LoginSignup
1
1

GeneratorとIteratorについて

Last updated at Posted at 2024-04-13

背景

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

今回使用したデータセット

1
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1