Support custom feature types
MEMBER
Hi ! Interesting :) What kind of new types would you like to use ?

Note that you can already implement your own decoding by using `set_transform` that can decode data on-the-fly when rows are accessed
2023-04-21T15:32:52Z
https://github.com/huggingface/datasets/issues/5766#issuecomment-1518006628
https://api.github.com/repos/huggingface/datasets/issues/5766
IC_kwDODunzps5aevFk
https://api.github.com/repos/huggingface/datasets/issues/comments/1518006628/reactions
2023-04-21T15:32:52Z
https://api.github.com/repos/huggingface/datasets/issues/comments/1518006628
https://avatars.githubusercontent.com/u/42851186?v=4
https://api.github.com/users/lhoestq/events{/privacy}
https://api.github.com/users/lhoestq/followers
https://api.github.com/users/lhoestq/following{/other_user}
https://api.github.com/users/lhoestq/gists{/gist_id}
https://github.com/lhoestq
lhoestq
MDQ6VXNlcjQyODUxMTg2
https://api.github.com/users/lhoestq/orgs
https://api.github.com/users/lhoestq/received_events
https://api.github.com/users/lhoestq/repos
https://api.github.com/users/lhoestq/starred{/owner}{/repo}
https://api.github.com/users/lhoestq/subscriptions
User
https://api.github.com/users/lhoestq
public
COLLABORATOR
An interesting proposal indeed. 

Pandas and Polars have the "extension API", so doing something similar on our side could be useful, too. However, this requires defining a common interface for the existing feature types before discussing the API/workflow for defining/sharing custom feature types, and this could take some time.

It would also be nice if the datasets viewer could render these custom types.
2023-05-03T18:59:50Z
https://github.com/huggingface/datasets/issues/5766#issuecomment-1533548073
https://api.github.com/repos/huggingface/datasets/issues/5766
IC_kwDODunzps5baBYp
https://api.github.com/repos/huggingface/datasets/issues/comments/1533548073/reactions
2023-05-03T18:59:50Z
https://api.github.com/repos/huggingface/datasets/issues/comments/1533548073
https://avatars.githubusercontent.com/u/47462742?v=4
https://api.github.com/users/mariosasko/events{/privacy}
https://api.github.com/users/mariosasko/followers
https://api.github.com/users/mariosasko/following{/other_user}
https://api.github.com/users/mariosasko/gists{/gist_id}
https://github.com/mariosasko
mariosasko
MDQ6VXNlcjQ3NDYyNzQy
https://api.github.com/users/mariosasko/orgs
https://api.github.com/users/mariosasko/received_events
https://api.github.com/users/mariosasko/repos
https://api.github.com/users/mariosasko/starred{/owner}{/repo}
https://api.github.com/users/mariosasko/subscriptions
User
https://api.github.com/users/mariosasko
public
NONE
Thank you for your replies! @lhoestq I have a use case involving whole-slide images in digital pathology. These are very large images (potentially gigapixel scale), so standard image tools are not suitable. Essentially, encoding/decoding can be done from/to [`OpenSlide`](https://openslide.org/api/python/) objects. Though there may be interest in this use case from the digital pathology community, it may not be sufficiently useful to suggest adding the feature type, but there will likely be many other use cases for a generic custom feature type.

Thank you for pointing out `set_transform`! I will make sure to keep this in mind in the future.

@mariosasko An "extension API" sounds like a good idea, though I understand that this needs to be properly defined, and that you will need to discuss it internally. Support from the viewer would be awesome, too, though the generalization to arbitrary types sounds challenging.

For now, happy to know that you're considering the feature. Feel free to let me know if I can do anything to support the process.
2023-05-03T21:58:43Z
https://github.com/huggingface/datasets/issues/5766#issuecomment-1533806495
https://api.github.com/repos/huggingface/datasets/issues/5766
IC_kwDODunzps5bbAef
https://api.github.com/repos/huggingface/datasets/issues/comments/1533806495/reactions
2023-05-03T21:58:43Z
https://api.github.com/repos/huggingface/datasets/issues/comments/1533806495
https://avatars.githubusercontent.com/u/37540982?v=4
https://api.github.com/users/jmontalt/events{/privacy}
https://api.github.com/users/jmontalt/followers
https://api.github.com/users/jmontalt/following{/other_user}
https://api.github.com/users/jmontalt/gists{/gist_id}
https://github.com/jmontalt
jmontalt
MDQ6VXNlcjM3NTQwOTgy
https://api.github.com/users/jmontalt/orgs
https://api.github.com/users/jmontalt/received_events
https://api.github.com/users/jmontalt/repos
https://api.github.com/users/jmontalt/starred{/owner}{/repo}
https://api.github.com/users/jmontalt/subscriptions
User
https://api.github.com/users/jmontalt
public
NONE
Not a beautiful solution, but we use this for now


```
import datasets.features.features
old_decode_fn = datasets.features.features.decode_nested_example
def decode_ext_fn(schema, obj, token_per_repo_id = None):
        #Decode new type here

        return old_decode_fn(schema, obj, token_per_repo_id)
datasets.features.features.decode_nested_example = decode_ext_fn

```

2024-03-10T11:10:08Z
https://github.com/huggingface/datasets/issues/5766#issuecomment-1987188146
https://api.github.com/repos/huggingface/datasets/issues/5766
IC_kwDODunzps52chWy
https://api.github.com/repos/huggingface/datasets/issues/comments/1987188146/reactions
2024-03-10T11:11:22Z
https://api.github.com/repos/huggingface/datasets/issues/comments/1987188146
https://avatars.githubusercontent.com/u/82008173?v=4
https://api.github.com/users/zux-hidden/events{/privacy}
https://api.github.com/users/zux-hidden/followers
https://api.github.com/users/zux-hidden/following{/other_user}
https://api.github.com/users/zux-hidden/gists{/gist_id}
https://github.com/zux-hidden
zux-hidden
MDQ6VXNlcjgyMDA4MTcz
https://api.github.com/users/zux-hidden/orgs
https://api.github.com/users/zux-hidden/received_events
https://api.github.com/users/zux-hidden/repos
https://api.github.com/users/zux-hidden/starred{/owner}{/repo}
https://api.github.com/users/zux-hidden/subscriptions
User
https://api.github.com/users/zux-hidden
public
### Feature request

I think it would be nice to allow registering custom feature types with the 🤗 Datasets library. For example, allow to do something along the following lines:

```
from datasets.features import register_feature_type  # this would be a new function

@register_feature_type
class CustomFeatureType:
    def encode_example(self, value):
        """User-provided logic to encode an example of this feature."""
        pass

    def decode_example(self, value, token_per_repo_id=None):
        """User-provided logic to decode an example of this feature."""
        pass
```

### Motivation

Users of 🤗 Datasets, such as myself, may want to use the library to load datasets with unsupported feature types (i.e., beyond `ClassLabel`, `Image`, or `Audio`). This would be useful for prototyping new feature types and for feature types that aren't used widely enough to warrant inclusion in 🤗 Datasets.

At the moment, this is only possible by monkey-patching 🤗 Datasets, which obfuscates the code and is prone to breaking with library updates. It also requires the user to write some custom code which could be easily avoided.

### Your contribution

I would be happy to contribute this feature. My proposed solution would involve changing the following call to `globals()` to an explicit feature type registry, which a user-facing `register_feature_type` decorator could update.

https://github.com/huggingface/datasets/blob/fd893098627230cc734f6009ad04cf885c979ac4/src/datasets/features/features.py#L1329

I would also provide an abstract base class for custom feature types which users could inherit. This would have at least an `encode_example` method and a `decode_example` method, similar to `Image` or `Audio`.

The existing `encode_nested_example` and `decode_nested_example` functions would also need to be updated to correctly call the corresponding functions for the new type.