# Menggunakan Datasets dengan TensorFlow

Dokumen ini adalah pengantar singkat tentang penggunaan `datasets` dengan TensorFlow, dengan fokus khusus pada cara mendapatkan objek `tf.Tensor` dari dataset kami, dan cara mengalirkan data dari objek `Dataset` Hugging Face ke metode Keras seperti `model.fit()`.

## Format dataset

Secara default, dataset mengembalikan objek Python biasa: bilangan bulat, bilangan desimal, string, daftar, dan sebagainya.

Untuk mendapatkan tensor TensorFlow, Anda dapat mengatur format dataset menjadi `tf`:

```py
>>> from datasets import Dataset
>>> data = [[1, 2],[3, 4]]
>>> ds = Dataset.from_dict({"data": data})
>>> ds = ds.with_format("tf")
>>> ds[0]
{'data': <tf.Tensor: shape=(2,), dtype=int64, numpy=array([1, 2])>}
>>> ds[:2]
{'data': <tf.Tensor: shape=(2, 2), dtype=int64, numpy=
array([[1, 2],
       [3, 4]])>}
```

> [!TIP]
> Objek [Dataset](/docs/datasets/main/id/package_reference/main_classes#datasets.Dataset) adalah pembungkus dari tabel Arrow, yang memungkinkan pembacaan cepat dari array dalam dataset ke tensor TensorFlow.

Hal ini dapat berguna untuk mengonversi dataset Anda menjadi dict dari objek `Tensor`, atau untuk menulis generator guna memuat sampel TF darinya. Jika Anda ingin mengonversi seluruh dataset menjadi `Tensor`, cukup kueri dataset penuh:

```py
>>> ds[:]
{'data': <tf.Tensor: shape=(2, 2), dtype=int64, numpy=
array([[1, 2],
       [3, 4]])>}
```

### Array N-dimensi

Jika dataset Anda terdiri dari array N-dimensi, Anda akan melihat bahwa secara default mereka dianggap sebagai tensor yang sama jika bentuknya tetap:

```py
>>> from datasets import Dataset
>>> data = [[[1, 2],[3, 4]],[[5, 6],[7, 8]]]  # fixed shape
>>> ds = Dataset.from_dict({"data": data})
>>> ds = ds.with_format("tf")
>>> ds[0]
{'data': <tf.Tensor: shape=(2, 2), dtype=int64, numpy=
 array([[1, 2],
        [3, 4]])>}
```

Jika tidak, dataset berformat TensorFlow akan mengoutputkan `RaggedTensor` alih-alih satu tensor:

```py
>>> from datasets import Dataset
>>> data = [[[1, 2],[3]],[[4, 5, 6],[7, 8]]]  # varying shape
>>> ds = Dataset.from_dict({"data": data})
>>> ds = ds.with_format("torch")
>>> ds[0]
{'data': <tf.RaggedTensor [[1, 2], [3]]>}
```

Namun logika ini sering kali memerlukan perbandingan bentuk (shape) dan penyalinan data yang lambat. Untuk menghindarinya, Anda harus secara eksplisit menggunakan tipe fitur `Array` dan menentukan bentuk tensor Anda:

```py
>>> from datasets import Dataset, Features, Array2D
>>> data = [[[1, 2],[3, 4]],[[5, 6],[7, 8]]]
>>> features = Features({"data": Array2D(shape=(2, 2), dtype='int32')})
>>> ds = Dataset.from_dict({"data": data}, features=features)
>>> ds = ds.with_format("tf")
>>> ds[0]
{'data': <tf.Tensor: shape=(2, 2), dtype=int64, numpy=
 array([[1, 2],
        [3, 4]])>}
>>> ds[:2]
{'data': <tf.Tensor: shape=(2, 2, 2), dtype=int64, numpy=
 array([[[1, 2],
         [3, 4]],
 
        [[5, 6],
         [7, 8]]])>}
```

### Jenis fitur lainnya

Data [ClassLabel](/docs/datasets/main/id/package_reference/main_classes#datasets.ClassLabel) dikonversi dengan benar menjadi tensor:

```py
>>> from datasets import Dataset, Features, ClassLabel
>>> labels = [0, 0, 1]
>>> features = Features({"label": ClassLabel(names=["negative", "positive"])})
>>> ds = Dataset.from_dict({"label": labels}, features=features) 
>>> ds = ds.with_format("tf")  
>>> ds[:3]
{'label': <tf.Tensor: shape=(3,), dtype=int64, numpy=array([0, 0, 1])>}
```

String dan objek biner juga didukung:

```py
>>> from datasets import Dataset, Features 
>>> text = ["foo", "bar"]
>>> data = [0, 1] 
>>> ds = Dataset.from_dict({"text": text, "data": data})  
>>> ds = ds.with_format("tf") 
>>> ds[:2]
{'text': <tf.Tensor: shape=(2,), dtype=string, numpy=array([b'foo', b'bar'], dtype=object)>,
 'data': <tf.Tensor: shape=(2,), dtype=int64, numpy=array([0, 1])>}
```

Anda juga dapat secara eksplisit memformat kolom tertentu dan membiarkan kolom lainnya tidak diformat:

```py
>>> ds = ds.with_format("tf", columns=["data"], output_all_columns=True)
>>> ds[:2]
{'data': <tf.Tensor: shape=(2,), dtype=int64, numpy=array([0, 1])>,
 'text': ['foo', 'bar']}
```

Objek string dan biner tidak berubah, karena PyTorch hanya mendukung angka.

Jenis fitur [Image](/docs/datasets/main/id/package_reference/main_classes#datasets.Image) dan [Audio](/docs/datasets/main/id/package_reference/main_classes#datasets.Audio) juga didukung.

> [!TIP]
> Untuk menggunakan tipe fitur [Image](/docs/datasets/main/id/package_reference/main_classes#datasets.Image), Anda perlu menginstal ekstra `vision` sebagai `pip install datasets[vision]`.

```py
>>> from datasets import Dataset, Features, Audio, Image
>>> images = ["path/to/image.png"] * 10
>>> features = Features({"image": Image()})
>>> ds = Dataset.from_dict({"image": images}, features=features) 
>>> ds = ds.with_format("tf")  
>>> ds[0]
{'image': <tf.Tensor: shape=(512, 512, 4), dtype=uint8, numpy=
 array([[[255, 215, 106, 255],
         [255, 215, 106, 255],
         ...,
         [255, 255, 255, 255],
         [255, 255, 255, 255]]], dtype=uint8)>}
>>> ds[:2]
{'image': <tf.Tensor: shape=(2, 512, 512, 4), dtype=uint8, numpy=
 array([[[[255, 215, 106, 255],
          [255, 215, 106, 255],
          ...,
          [255, 255, 255, 255],
          [255, 255, 255, 255]]]], dtype=uint8)>}
```

> [!TIP]
> Untuk menggunakan tipe fitur [Audio](/docs/datasets/main/id/package_reference/main_classes#datasets.Audio), Anda perlu menginstal ekstra `audio` sebagai `pip install datasets[audio]`.

```py
>>> from datasets import Dataset, Features, Audio, Image
>>> audio = ["path/to/audio.wav"] * 10
>>> features = Features({"audio": Audio()})
>>> ds = Dataset.from_dict({"audio": audio}, features=features) 
>>> ds = ds.with_format("tf")  
>>> ds[0]["audio"]["array"]
<tf.Tensor: shape=(202311,), dtype=float32, numpy=
array([ 6.1035156e-05,  1.5258789e-05,  1.6784668e-04, ...,
       -1.5258789e-05, -1.5258789e-05,  1.5258789e-05], dtype=float32)>
>>> ds[0]["audio"]["sampling_rate"]
<tf.Tensor: shape=(), dtype=int32, numpy=44100>
```

## Memuat data

Meskipun Anda dapat memuat sampel dan batch individual hanya dengan mengindeks dataset Anda, hal ini tidak akan berfungsi jika Anda ingin menggunakan metode Keras seperti `fit()` dan `predict()`. Anda bisa menulis fungsi generator yang mengacak dan memuat batch dari dataset Anda lalu `fit()` pada generator tersebut, tetapi itu terdengar seperti banyak pekerjaan yang tidak perlu. Sebagai gantinya, jika Anda ingin mengalirkan data dari dataset Anda secara langsung, kami merekomendasikan untuk mengonversi dataset Anda menjadi `tf.data.Dataset` menggunakan metode `to_tf_dataset()`.

The `tf.data.Dataset` class covers a wide range of use-cases - it is often created from Tensors in memory, or using a load function to read files on disc or external storage. The dataset can be transformed arbitrarily with the `map()` method, or methods like `batch()` and `shuffle()` can be used to create a dataset that's ready for training. These methods do not modify the stored data in any way - instead, the methods build a data pipeline graph that will be executed when the dataset is iterated over, usually during model training or inference. This is different from the `map()` method of Hugging Face `Dataset` objects, which runs the map function immediately and saves the new or changed columns.

Karena seluruh pipeline pra-pemrosesan data dapat dikompilasi dalam `tf.data.Dataset`, pendekatan ini memungkinkan pemuatan data dan pelatihan yang paralel secara masif serta asinkron. Namun, persyaratan kompilasi graf dapat menjadi keterbatasan, khususnya untuk tokenizer Hugging Face, yang biasanya belum (belum!) dapat dikompilasi sebagai bagian dari graf TF. Akibatnya, kami biasanya menyarankan untuk memproses dataset terlebih dahulu sebagai dataset Hugging Face, di mana fungsi Python apa pun dapat digunakan, dan kemudian mengonversinya menjadi `tf.data.Dataset` setelahnya menggunakan `to_tf_dataset()` untuk mendapatkan dataset yang sudah di-batch dan siap untuk pelatihan. Untuk melihat contoh pendekatan ini, silakan lihat [contoh](https://github.com/huggingface/transformers/tree/main/examples) atau [notebook](https://huggingface.co/docs/transformers/notebooks) untuk `transformers`.

### Menggunakan `to_tf_dataset()`

Menggunakan `to_tf_dataset()` sangat mudah. Setelah dataset Anda dipreprocess dan siap, cukup panggil seperti ini:

```py
>>> from datasets import Dataset
>>> data = {"inputs": [[1, 2],[3, 4]], "labels": [0, 1]}
>>> ds = Dataset.from_dict(data)
>>> tf_ds = ds.to_tf_dataset(
            columns=["inputs"],
            label_cols=["labels"],
            batch_size=2,
            shuffle=True
            )
```

Objek `tf_ds` yang dikembalikan di sini kini sepenuhnya siap untuk dilatih, dan dapat langsung diteruskan ke `model.fit()`. Perhatikan bahwa Anda mengatur ukuran batch saat membuat dataset, sehingga Anda tidak perlu menentukannya saat memanggil `fit()`:

```py
>>> model.fit(tf_ds, epochs=2)
```

Untuk deskripsi lengkap argumen, silakan lihat dokumentasi [to_tf_dataset()](/docs/datasets/main/id/package_reference/main_classes#datasets.Dataset.to_tf_dataset). Dalam banyak kasus, Anda juga perlu menambahkan `collate_fn` ke pemanggilan Anda. Ini adalah fungsi yang mengambil beberapa elemen dari dataset dan menggabungkannya menjadi satu batch. Ketika semua elemen memiliki panjang yang sama, collator bawaan default akan cukup, tetapi untuk tugas yang lebih kompleks, collator kustom mungkin diperlukan. Secara khusus, banyak tugas memiliki sampel dengan panjang sekuens yang bervariasi, yang akan memerlukan [data collator](https://huggingface.co/docs/transformers/main/en/main_classes/data_collator) yang dapat melakukan padding batch dengan benar. Anda dapat melihat contoh hal ini di `transformers` NLP [examples](https://github.com/huggingface/transformers/tree/main/examples) dan [notebooks](https://huggingface.co/docs/transformers/notebooks), di mana panjang sekuens yang bervariasi sangat umum.

Jika Anda menemukan bahwa pemuatan dengan `to_tf_dataset` lambat, Anda juga dapat menggunakan argumen `num_workers`. Argumen ini menjalankan beberapa proses anak untuk memuat data secara paralel. Fitur ini baru dan masih agak eksperimental - silakan laporkan masalah jika Anda menemukan bug saat menggunakannya!

### Kapan menggunakan to_tf_dataset

Pembaca yang cermat mungkin telah menyadari pada titik ini bahwa kami telah menawarkan dua pendekatan untuk mencapai tujuan yang sama - jika Anda ingin meneruskan dataset Anda ke model TensorFlow, Anda dapat mengonversi dataset menjadi `Tensor` atau `dict` dari `Tensors` menggunakan `.with_format('tf')`, atau Anda dapat mengonversi dataset menjadi `tf.data.Dataset` dengan `to_tf_dataset()`. Keduanya dapat diteruskan ke `model.fit()`, jadi mana yang harus Anda pilih?

Hal penting yang perlu dipahami adalah bahwa ketika Anda mengonversi seluruh dataset menjadi `Tensor`, data tersebut bersifat statis dan dimuat sepenuhnya ke RAM. Pendekatan ini sederhana dan praktis, tetapi jika salah satu kondisi berikut berlaku, sebaiknya gunakan `to_tf_dataset()` sebagai gantinya:

- Dataset Anda terlalu besar untuk muat di RAM. `to_tf_dataset()` hanya mengalirkan satu batch pada satu waktu, sehingga bahkan dataset yang sangat besar pun dapat ditangani dengan metode ini.
- Anda ingin menerapkan transformasi acak menggunakan `dataset.with_transform()` atau `collate_fn`. Hal ini umum terjadi pada beberapa modalitas, seperti augmentasi gambar saat melatih model visi, atau masking acak saat melatih masked language models. Menggunakan `to_tf_dataset()` akan menerapkan transformasi tersebut pada saat batch dimuat, yang berarti sampel yang sama akan mendapatkan augmentasi yang berbeda setiap kali dimuat. Ini biasanya yang Anda inginkan.
- Data Anda memiliki dimensi yang bervariasi, seperti teks input dalam NLP yang terdiri dari jumlah token yang berbeda-beda. Saat Anda membuat batch dengan sampel yang memiliki dimensi bervariasi, solusi standar adalah mengisi (padding) sampel yang lebih pendek hingga panjang sampel terpanjang. Saat Anda mengalirkan sampel dari dataset dengan `to_tf_dataset`, Anda dapat menerapkan padding ini ke setiap batch melalui `collate_fn` Anda. Namun, jika Anda ingin mengonversi dataset seperti itu menjadi `Tensor` padat, Anda harus mengisi sampel hingga panjang sampel terpanjang di *seluruh dataset!* Hal ini dapat menghasilkan jumlah padding yang sangat besar, yang membuang-buang memori dan mengurangi kecepatan model Anda.

### Catatan dan batasan

Saat ini, `to_tf_dataset()` selalu mengembalikan dataset yang sudah di-batch - kami akan segera menambahkan dukungan untuk dataset yang tidak di-batch!

