Datasets 文件

在TensorFlow中使用資料集

Hugging Face's logo
加入 Hugging Face 社群

並獲得增強的文件體驗

開始使用

在TensorFlow中使用資料集

本文件是關於如何在TensorFlow中使用 `datasets` 的快速入門,特別側重於如何從我們的資料集中獲取 `tf.Tensor` 物件,以及如何將資料從 Hugging Face `Dataset` 物件流式傳輸到 Keras 方法(如 `model.fit()`)。

資料集格式

預設情況下,資料集返回常規的Python物件:整數、浮點數、字串、列表等。

要獲取TensorFlow張量,您可以將資料集的格式設定為 `tf`

>>> 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]])>}

一個Dataset物件是Arrow表的封裝,它允許從資料集中的陣列快速讀取到TensorFlow張量。

這對於將資料集轉換為 `Tensor` 物件的字典,或者編寫生成器以從中載入TF樣本很有用。如果您希望將整個資料集轉換為 `Tensor`,只需查詢完整的資料集

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

N維陣列

如果您的資料集由N維陣列組成,您會發現如果形狀固定,它們預設被視為相同的張量

>>> 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]])>}

否則,TensorFlow格式的資料集會輸出一個 `RaggedTensor` 而不是單個張量

>>> 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]]>}

然而,這種邏輯通常需要慢速的形狀比較和資料複製。為了避免這種情況,您必須明確使用 `Array` 特徵型別並指定張量的形狀

>>> 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]]])>}

其他特徵型別

ClassLabel 資料正確轉換為張量

>>> 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])>}

還支援字串和二進位制物件

>>> 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])>}

您還可以顯式格式化某些列,而其他列則不進行格式化

>>> 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']}

字串和二進位制物件保持不變,因為PyTorch只支援數字。

ImageAudio 特徵型別也支援。

要使用 Image 特徵型別,您需要安裝 `vision` 額外依賴:`pip install datasets[vision]`。

>>> 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)>}

要使用 Audio 特徵型別,您需要安裝 `audio` 額外依賴:`pip install datasets[audio]`。

>>> 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>

資料載入

儘管您可以透過對資料集進行索引來載入單個樣本和批次,但這在您想使用 Keras 方法(例如 `fit()` 和 `predict()`)時不起作用。您可以編寫一個生成器函式,從資料集中洗牌並載入批次,然後使用 `fit()`,但這聽起來像是不必要的重複工作。相反,如果您想即時地從資料集中流式傳輸資料,我們建議使用 `to_tf_dataset()` 方法將資料集轉換為 `tf.data.Dataset`。

`tf.data.Dataset` 類涵蓋了廣泛的用例——它通常從記憶體中的 Tensor 建立,或者使用載入函式從磁碟或外部儲存讀取檔案。資料集可以使用 `map()` 方法進行任意轉換,或者可以使用 `batch()` 和 `shuffle()` 等方法建立用於訓練的資料集。這些方法不會以任何方式修改儲存的資料——相反,這些方法構建了一個數據管道圖,該圖將在資料集迭代時執行,通常在模型訓練或推理期間。這與 Hugging Face `Dataset` 物件的 `map()` 方法不同,後者立即執行 map 函式並儲存新的或更改的列。

由於整個資料預處理管道可以在 `tf.data.Dataset` 中編譯,因此這種方法可以實現大規模並行、非同步資料載入和訓練。然而,圖編譯的要求可能是一個限制,特別是對於 Hugging Face tokenizer,它們通常還沒有(!)作為 TF 圖的一部分進行編譯。因此,我們通常建議先將資料集作為 Hugging Face 資料集進行預處理,其中可以使用任意 Python 函式,然後使用 `to_tf_dataset()` 轉換為 `tf.data.Dataset`,以獲得可用於訓練的批處理資料集。要檢視此方法的示例,請參閱 `transformers` 的示例notebooks

使用 to_tf_dataset()

使用 `to_tf_dataset()` 非常簡單。一旦您的資料集經過預處理並準備就緒,只需像這樣呼叫它即可

>>> 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
            )

此處返回的 `tf_ds` 物件現在已完全準備好進行訓練,可以直接傳遞給 `model.fit()`。請注意,您在建立資料集時設定了批處理大小,因此在呼叫 `fit()` 時無需指定它

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

有關引數的完整說明,請參閱 to_tf_dataset() 文件。在許多情況下,您還需要在呼叫中新增 `collate_fn`。這是一個接受資料集的多個元素並將它們組合成單個批處理的函式。當所有元素長度相同時,內建的預設 collator 就足夠了,但對於更復雜的任務,可能需要自定義 collator。特別是,許多工的樣本序列長度不同,這將需要一個可以正確填充批處理的資料 collator。您可以在 `transformers` NLP 示例notebooks 中看到此方法的示例,其中可變序列長度非常常見。

如果您發現使用 `to_tf_dataset` 載入速度較慢,您還可以使用 `num_workers` 引數。這將啟動多個子程序以並行載入資料。此功能是最近推出的,仍處於實驗階段——如果您在使用時遇到任何錯誤,請提交問題!

何時使用 to_tf_dataset

敏銳的讀者可能已經注意到,我們提供了兩種方法來實現相同的目標——如果您想將資料集傳遞給TensorFlow模型,您可以將資料集轉換為 `Tensor` 或 `Tensors` 的 `dict`(使用 `.with_format('tf')`),或者您可以使用 `to_tf_dataset()` 將資料集轉換為 `tf.data.Dataset`。兩者都可以傳遞給 `model.fit()`,那麼您應該選擇哪種方法呢?

關鍵是要認識到,當您將整個資料集轉換為 `Tensor` 時,它是靜態的並且完全載入到RAM中。這很簡單方便,但如果以下任何情況適用,您可能應該使用 `to_tf_dataset()`:

  • 您的資料集太大,無法完全載入到RAM中。`to_tf_dataset()` 一次只流式傳輸一個批次,因此即使是非常大的資料集也可以透過此方法處理。
  • 您希望使用 `dataset.with_transform()` 或 `collate_fn` 應用隨機轉換。這在多種模式中很常見,例如訓練視覺模型時的影像增強,或訓練掩碼語言模型時的隨機掩碼。使用 `to_tf_dataset()` 將在載入批次時應用這些轉換,這意味著每次載入相同的樣本時都會得到不同的增強。這通常是您想要的。
  • 您的資料具有可變維度,例如自然語言處理中由不同數量的 token 組成的輸入文字。當您建立具有可變維度的樣本批次時,標準解決方案是將較短的樣本填充到最長樣本的長度。當您使用 `to_tf_dataset` 從資料集中流式傳輸樣本時,可以透過 `collate_fn` 將此填充應用於每個批次。但是,如果您想將此類資料集轉換為密集的 `Tensor`,那麼您將不得不將樣本填充到**整個資料集**中最長樣本的長度!這可能會導致大量的填充,從而浪費記憶體並降低模型的速度。

注意事項和限制

目前,`to_tf_dataset()` 總是返回一個批處理資料集——我們很快將新增對非批處理資料集的支援!

< > 在 GitHub 上更新

© . This site is unofficial and not affiliated with Hugging Face, Inc.