pytorch::Dataloaderの反復およびジェネレータアプリケーション
5362 ワード
pytorchトレーニングモデルを使用すると、多くのピクチャデータをロードする必要があることが多いため、pytorchは使いやすいデータロードツールDataloaderを提供します.大規模なデータセットの小ロットループ読み出しを実現するために、Dataloaderクラスの具体的な実装では、反復器とジェネレータが使用されます.この応用シーンはpythonにおける反復器モードの意味であるため,本稿ではDataloaderにおけるコードを解読し,pythonにおける反復器と生成器の概念をよりよく理解できる.
本文の内容は主に以下の通りである.
pythonの反復器とジェネレータの概念を説明pytorchのDataloaderコードを解読します.反復器とジェネレータを使用してデータロードpython反復を実現する方法pythonには、反復の周りに次の概念があります.
反復可能オブジェクトiterables反復器iteratorジェネレータgeneratorの3つの概念は互いに関連しており、孤立しているわけではありません.反復可能なオブジェクトに基づいて反復器を開発し,反復器に基づいて生成器を開発した.これらの概念を学ぶ名詞の解釈にはあまり意味がない.プログラミングの中の多くの抽象概念は、いくつかの機能をよりよく実現するために、人為的に創造されたプロトコルとモードを行う.そのため、それらを理解するには、概念の背後にある論理を探究する必要があります.なぜこのように設計されていますか.解決すべき本当の問題は何ですか.どのシーンで適用するのが一番いいですか?
反復モードがまず解決すべき基礎的な問題は,リストをループするなど,集合内部データを一定の順序で取得する必要があることである.データが小さい場合、問題はありません.しかし、大量のデータを読み取る場合、一度に読み取るとメモリの制限を超えてしまうので、以下の方法を考えます.
大きなデータをいくつかの小さなブロックに分けて、不活性な値の取り方をバッチで処理し、必要に応じて値を取ってデータを繰り返し読むことで、コンテナ(反復可能なオブジェクト)、反復器、ジェネレータの3つの応用シーンに分けることができます.
for x in container:python内部シーケンスコンテナ(listなど)を巡回するために、これらのタイプの内部実装は_getitem__()メソッドでは、シーケンスコンテナ内の要素を0から順に巡回できます.for x in iterator:ユーザーがカスタマイズした反復器をループするには_iter__および_next__メソッド、_iter__反復プロトコルであり、各反復の実行ロジックは_next__またはnextメソッドにfor x in generator:サイクルのメモリを節約し、加速するためにジェネレータを使用して不活性なロードを実現し、反復器にyield文を加え、最も簡単な例はrange(5)コードの例です.
通常サイクルfor x in list
numbers = [1, 2, 3,] for n in numbers: print(n) # 1,2,3
for実際にやったことを繰り返す
iter反復可能なオブジェクトlistを入力し、反復器を返します.
nextメソッドによるデータの取得
my_iterator = iter(numbers) next(my_iterator) # 1 next(my_iterator) # 2 next(my_iterator) # 3 next(my_iterator) # StopIteration exception
反復器サイクルfor x in iterator
for i,n in enumerate(numbers): print(i,n) # 0,1/1,3/2,3
ジェネレータサイクルfor x in generator
for i in range(3):print(i)#0,1,2上の例のコードでpython内蔵関数iterとnextの使い方:
iter関数、呼び出し_iter__,反復器next関数を返し、反復器を入力し、呼び出し_next__,データを取り出して混同しやすいのは_iter__および_next__二つの方法.違いは次のとおりです.
__iter__反復可能にするために、実際にデータを取得する論理は__です.next__メソッドで実装され、実際の呼び出しはnext(iterator)によって完了する_iter__自身(return self)に戻り、実際にデータを読み取る実装を__に置くことができます.next__メソッド_iter__yieldと組み合わせて、ジェネレータオブジェクトに戻ることができます.iter__自分のやり方を返すのはpythonのタイプのシステムに似ています.一貫性を保つためにpythonのすべてのオブジェクトをオブジェクト化します.各オブジェクトが作成されると、タイプポインタがあり、タイプオブジェクトのポインタはメタオブジェクトを指し、メタオブジェクトのポインタは自身を指します.
ジェネレータは、__iter__メソッドにyield文を追加するメリットは、次のとおりです.
サイクル判定ロジックの複雑さを減らし、メモリと時間を節約する.
代替関数のreturn文は、前回のサイクル反復器の内部要素の位置の3つのサイクルモードの一般的な関数for x in containerメソッドを覚えます.
list,deque,...set,frozensets,...dict,defaultdict,OrderedDict,Counter,...tuple,namedtuple,...str for x in iteratorメソッド:
Enumerate()#listのindex sorted()#ソートlist reversed()#逆シーケンスlist zip()#マージlist for x in generatorメソッド:
range()map()filter()reduce()[x for x in list(...)]Dataloderソース分析pytorchはfor x in iteratorモードを採用し、Dataloaderクラスからデータを読み出す.
この反復モードを実現するために、Dataloader内部で__を実現するiter__メソッド、実際に返されるのは_DataLoaderIterクラス._DataLoaderIterクラスで、実現しました_iter__メソッド、自身を返して、具体的にデータを読むロジックを実行して、_next__メソッド内.次のコードは、単一スレッドでのデータ読み出しのみを切り取ります.
class DataLoader(object): r"""Data loader. Combines a dataset and a sampler, and provides single- or multi-process iterators over the dataset. “”"def init(self, dataset, batch_size=1, shuffle=False, …): self.dataset = dataset self.batch_sampler = batch_sampler …
class _DataLoaderIter(object): r""“Iterates once over the DataLoader’s dataset, as specified by the sampler”""def init(self, loader): self.sample_iter = iter(self.batch_sampler) …
DataloaderクラスでデータIndexを読み込む方法は、for x in generator方式を採用していますが、呼び出しはiterとnext関数を採用しています
ランダムサンプリングクラスRandomSamplerを構築し、内部で__を実現iter__メソッド_iter__メソッドの内部にyieldを使用し、batch_に達するとデータセットをループします.sizeが大きくなると、ランダムサンプリングクラスがインスタンス化され、iter関数が入力され、反復器nextがランダムサンプリングクラスのジェネレータを呼び出し、対応するindexデータclass RandomSampler(object):「"random sampler to yield a mini-batch of indices."""def init(self, batch_size, dataset, drop_last=False): self.dataset = dataset self.batch_size = batch_size self.num_imgs = len(dataset) self.drop_last = drop_last
batch_sampler = RandomSampler(batch_size. dataset) sample_iter=iter(batch_sampler)indices=next(sample_iter)pythonにおけるサイクルの3つのパターンをまとめた.
for x in container反復可能オブジェクトfor x in iterator反復器for x in generatorジェネレータpytorchのデータロードモジュールDataloaderは、ジェネレータを使用してデータのインデックスを返し、反復器を使用して必要なテンソルデータを返し、大量のデータの場合、小ロットの循環反復式の読み取りを実現し、メモリ不足の問題を回避することができます.
本文の内容は主に以下の通りである.
pythonの反復器とジェネレータの概念を説明pytorchのDataloaderコードを解読します.反復器とジェネレータを使用してデータロードpython反復を実現する方法pythonには、反復の周りに次の概念があります.
反復可能オブジェクトiterables反復器iteratorジェネレータgeneratorの3つの概念は互いに関連しており、孤立しているわけではありません.反復可能なオブジェクトに基づいて反復器を開発し,反復器に基づいて生成器を開発した.これらの概念を学ぶ名詞の解釈にはあまり意味がない.プログラミングの中の多くの抽象概念は、いくつかの機能をよりよく実現するために、人為的に創造されたプロトコルとモードを行う.そのため、それらを理解するには、概念の背後にある論理を探究する必要があります.なぜこのように設計されていますか.解決すべき本当の問題は何ですか.どのシーンで適用するのが一番いいですか?
反復モードがまず解決すべき基礎的な問題は,リストをループするなど,集合内部データを一定の順序で取得する必要があることである.データが小さい場合、問題はありません.しかし、大量のデータを読み取る場合、一度に読み取るとメモリの制限を超えてしまうので、以下の方法を考えます.
大きなデータをいくつかの小さなブロックに分けて、不活性な値の取り方をバッチで処理し、必要に応じて値を取ってデータを繰り返し読むことで、コンテナ(反復可能なオブジェクト)、反復器、ジェネレータの3つの応用シーンに分けることができます.
for x in container:python内部シーケンスコンテナ(listなど)を巡回するために、これらのタイプの内部実装は_getitem__()メソッドでは、シーケンスコンテナ内の要素を0から順に巡回できます.for x in iterator:ユーザーがカスタマイズした反復器をループするには_iter__および_next__メソッド、_iter__反復プロトコルであり、各反復の実行ロジックは_next__またはnextメソッドにfor x in generator:サイクルのメモリを節約し、加速するためにジェネレータを使用して不活性なロードを実現し、反復器にyield文を加え、最も簡単な例はrange(5)コードの例です.
通常サイクルfor x in list
numbers = [1, 2, 3,] for n in numbers: print(n) # 1,2,3
for実際にやったことを繰り返す
iter反復可能なオブジェクトlistを入力し、反復器を返します.
nextメソッドによるデータの取得
my_iterator = iter(numbers) next(my_iterator) # 1 next(my_iterator) # 2 next(my_iterator) # 3 next(my_iterator) # StopIteration exception
反復器サイクルfor x in iterator
for i,n in enumerate(numbers): print(i,n) # 0,1/1,3/2,3
ジェネレータサイクルfor x in generator
for i in range(3):print(i)#0,1,2上の例のコードでpython内蔵関数iterとnextの使い方:
iter関数、呼び出し_iter__,反復器next関数を返し、反復器を入力し、呼び出し_next__,データを取り出して混同しやすいのは_iter__および_next__二つの方法.違いは次のとおりです.
__iter__反復可能にするために、実際にデータを取得する論理は__です.next__メソッドで実装され、実際の呼び出しはnext(iterator)によって完了する_iter__自身(return self)に戻り、実際にデータを読み取る実装を__に置くことができます.next__メソッド_iter__yieldと組み合わせて、ジェネレータオブジェクトに戻ることができます.iter__自分のやり方を返すのはpythonのタイプのシステムに似ています.一貫性を保つためにpythonのすべてのオブジェクトをオブジェクト化します.各オブジェクトが作成されると、タイプポインタがあり、タイプオブジェクトのポインタはメタオブジェクトを指し、メタオブジェクトのポインタは自身を指します.
ジェネレータは、__iter__メソッドにyield文を追加するメリットは、次のとおりです.
サイクル判定ロジックの複雑さを減らし、メモリと時間を節約する.
代替関数のreturn文は、前回のサイクル反復器の内部要素の位置の3つのサイクルモードの一般的な関数for x in containerメソッドを覚えます.
list,deque,...set,frozensets,...dict,defaultdict,OrderedDict,Counter,...tuple,namedtuple,...str for x in iteratorメソッド:
Enumerate()#listのindex sorted()#ソートlist reversed()#逆シーケンスlist zip()#マージlist for x in generatorメソッド:
range()map()filter()reduce()[x for x in list(...)]Dataloderソース分析pytorchはfor x in iteratorモードを採用し、Dataloaderクラスからデータを読み出す.
この反復モードを実現するために、Dataloader内部で__を実現するiter__メソッド、実際に返されるのは_DataLoaderIterクラス._DataLoaderIterクラスで、実現しました_iter__メソッド、自身を返して、具体的にデータを読むロジックを実行して、_next__メソッド内.次のコードは、単一スレッドでのデータ読み出しのみを切り取ります.
class DataLoader(object): r"""Data loader. Combines a dataset and a sampler, and provides single- or multi-process iterators over the dataset. “”"def init(self, dataset, batch_size=1, shuffle=False, …): self.dataset = dataset self.batch_sampler = batch_sampler …
def __iter__(self):
return _DataLoaderIter(self)
def __len__(self):
return len(self.batch_sampler)
class _DataLoaderIter(object): r""“Iterates once over the DataLoader’s dataset, as specified by the sampler”""def init(self, loader): self.sample_iter = iter(self.batch_sampler) …
def __next__(self):
if self.num_workers == 0: # same-process loading
indices = next(self.sample_iter) # may raise StopIteration
batch = self.collate_fn([self.dataset[i] for i in indices])
if self.pin_memory:
batch = pin_memory_batch(batch)
return batch
...
def __iter__(self):
return self
DataloaderクラスでデータIndexを読み込む方法は、for x in generator方式を採用していますが、呼び出しはiterとnext関数を採用しています
ランダムサンプリングクラスRandomSamplerを構築し、内部で__を実現iter__メソッド_iter__メソッドの内部にyieldを使用し、batch_に達するとデータセットをループします.sizeが大きくなると、ランダムサンプリングクラスがインスタンス化され、iter関数が入力され、反復器nextがランダムサンプリングクラスのジェネレータを呼び出し、対応するindexデータclass RandomSampler(object):「"random sampler to yield a mini-batch of indices."""def init(self, batch_size, dataset, drop_last=False): self.dataset = dataset self.batch_size = batch_size self.num_imgs = len(dataset) self.drop_last = drop_last
def __iter__(self):
indices = np.random.permutation(self.num_imgs)
batch = []
for i in indices:
batch.append(i)
if len(batch) == self.batch_size:
yield batch
batch = []
## if images not to yield a batch
if len(batch)>0 and not self.drop_last:
yield batch
def __len__(self):
if self.drop_last:
return self.num_imgs // self.batch_size
else:
return (self.num_imgs + self.batch_size - 1) // self.batch_size
batch_sampler = RandomSampler(batch_size. dataset) sample_iter=iter(batch_sampler)indices=next(sample_iter)pythonにおけるサイクルの3つのパターンをまとめた.
for x in container反復可能オブジェクトfor x in iterator反復器for x in generatorジェネレータpytorchのデータロードモジュールDataloaderは、ジェネレータを使用してデータのインデックスを返し、反復器を使用して必要なテンソルデータを返し、大量のデータの場合、小ロットの循環反復式の読み取りを実現し、メモリ不足の問題を回避することができます.