背景
Iterabledatasetと出会った!困った゜゜(´□`。)°゜。
GeneratorとIteratorの違い
Iteratorの中にGeneratorがいるイメージ
Generator | Iterator | |
---|---|---|
説明文 | generator iteratorを返す関数 | 反復可能オブジェクト =1つずつ要素を返せる |
共通点 | 反復処理を行える | 反復処理を行える |
異なる点 | 必要な時にのみ値を生成なのでメモリが少なくてもよい Generatorは中身が分からない generate関数がよばれたときにしか次の要素は分からない |
一度に全ての値をメモリに読み込む 最初から長さと中身が分かっている |
実装の方法 | yieldを持つ関数 | 自身を戻り値とする__iter__ メソッド、次の要素を返す__next__ メソッドを持つ。クラスで定義されがち |
generator iterator:Generatorによって生成されたIteratorのこと (__iter__
メソッドにyieldを使用しているとき、Iteratorであり、かつgenerator iterator)
Iterabledataset
-
__getitem__
が定義されていない -
__iter__
の定義のみで成り立っている -
毎回同じ順番で呼び出す(シャッフルは基本ない)
-
大規模データセットでよく使用されている
-
ストリーミングで呼び出す時などに使用
困ったこと:インデックスで呼び出しができない、len()
が使用できないなど
map-style dataset:基本的にDatasetには__getitem__
が定義されているので、indexを使用してアクセスが可能。ただし、データセット全体をメモリにのせる必要があるので、ディスクより大きいデータセットにはアクセスできない!!鬼強いPCが必要!
Iterabledataset:データセットを反復処理しながら徐々にデータを必要な分のみ読み込むので、サンプルのほんの一部だけがメモリにロードされ、ディスクには何も書き込まれません。便利!!
Iterabledatasetでデータローダーを作りたい
__getitem__
の代わりにgenerate
を定義
yield
yield:関数を一時的に止める役割。その時点で値を返し、また続きから再開する
return:値を返し、終了する
class ElsaDataset
# generateが呼ばれたときにおこること
# generateが1回目によばれたとき, indexは0, yieldがある行でforが一時的に止まって、imgとtargetがreturnされる
# generateが2回目によばれたとき, indexは1, yieldがある行でforが一時的に止まって、imgとtargetがreturnされる
# generateが3回目によばれたとき, indexは2, yieldがある行でforが一時的に止まって、imgとtargetがreturnされる
# generateが4回目によばれたとき, indexは3, yieldがある行でforが一時的に止まって、imgとtargetがreturnされる
# ....
#
# もしyeildがreturnだったらおこること
# generateが1回目によばれたとき, indexは0, returnがある行でimgとtargetがreturnされる
# generateが2回目によばれたとき, indexは0, returnがある行でimgとtargetがreturnされる
# generateが3回目によばれたとき, indexは0, returnがある行でimgとtargetがreturnされる
# generateが4回目によばれたとき, indexは0, returnがある行でimgとtargetがreturnされる
# ....
def generate(self):
"""データを生成するジェネレータ."""
# generateが呼ばれたときにおこること
# 1回目によばれたとき, 外側のindexは0, 内側のindexは0(REAL) yieldがある行で一時的に止まって、imgとtargetが返却される
# 2回目によばれたとき, 外側のindexは0, 内側のindexは1(FAKE) yieldがある行で一時的に止まって、imgとtargetが返却される
# 3回目によばれたとき, 外側のindexは1, 内側のindexは0(REAL) yieldがある行で一時的に止まって、imgとtargetが返却される
# 4回目によばれたとき, 外側のindexは1, 内側のindexは1(FAKE) yieldがある行で一時的に止まって、imgとtargetが返却される
# ...
for sample in self.elsa_data: # 1つのデータに対して2つの画像があるため
for label in range(2):
if label == DeepFakeDetectionLabel.REAL:
url_real_image = sample.pop("url_real_image")
response = requests.get(url_real_image, timeout=5)
img = Image.open(BytesIO(response.content))
target = DeepFakeDetectionLabel.REAL
else:
img = sample.pop("image")
target = DeepFakeDetectionLabel.FAKE
yield img, target
def __iter__(self):
"""データを生成するイテレータ."""
return iter(self.generate())
公式
datasetが無限にある場合
haggingface
今回使用したデータセット