PytouchのData Loader、DataSet、Samplerの関係が分かります。


以下の内容はPytoch 1.0-1.1について紹介します。
多くの文章はDatasetなどの対象から下から上に紹介されていますが、初心者にとってはよく理解できないこともあります。知らず知らずのうちに細かいことに落ち込んでしまい、ポイントがつかめないこともあるので、ここではトップダウンでPytochデータの読み取り方法を紹介します。
上から下まで3つの関係を理解する。
まず、Data Loader.nextのソースコードの長さはどうですか?分かりやすいようにnum_だけを選びました。worksが0の場合(num_)ワードはデータを並列化して読み取ることができるという単純な理解である)。

class DataLoader(object):
	...
	
 def __next__(self):
  if self.num_workers == 0: 
   indices = next(self.sample_iter) # Sampler
   batch = self.collate_fn([self.dataset[i] for i in indices]) # Dataset
   if self.pin_memory:
    batch = _utils.pin_memory.pin_memory_batch(batch)
   return batch
上のコードを読む前に、私達は私達のデータが一つの画像であると仮定してもいいです。各画像は一つのindexに対応しています。データを読み込むには対応するindexだけが必要です。つまり、上のコードのindicesは、indexを選択する方式は多種あります。順番もあれば、順序もあります。今は具体的な詳細は必要ありません。後で紹介します。DataLoaderとSamplerはここで関係ができます。
DatasetとData Loaderはいつ関係がありますか?間違いなく次の行です。私たちはもうindicesを手に入れました。次はindexによってデータを読み取ります。
以下のSampler文の役割を簡単に理解すると、ifなら、Pytochは一連の操作でGPUにデータをコピーします。つまり、加速するためです。
以上より、Data Loader、SamplerとDatasetの3つの関係が分かります。

後の文を読んでいるうちに、上の関係をずっと心に留めておく必要があります。そうすれば、よりよく理解することができます。
Sampler
パラメータ転送
Samplerの原理をより詳細に理解するには、まずData Loaderのソースコードを読む必要があります。

class DataLoader(object):
 def __init__(self, dataset, batch_size=1, shuffle=False, sampler=None,
     batch_sampler=None, num_workers=0, collate_fn=default_collate,
     pin_memory=False, drop_last=False, timeout=0,
     worker_init_fn=None)
初期化パラメータには2つのsamplerがあります。pin_memory=Truesamplerとがデフォルトでbatch_samplerです。前者の役割は一連のindexを生成することであり、batch_samplerはsamplerで生成されたindicesをパケット化し、一つ又一つのbatchのindexを得る。例えば、Noneは、BatchSamplerによって生成されたindexを指定されたbatch sizeパケットに従う。

>>>in : list(BatchSampler(SequentialSampler(range(10)), batch_size=3, drop_last=False))
>>>out: [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]
Pytouchで実現されているSequentialSamplerには以下のような種類があります。
  • Sampler
  • SequentialSampler
  • RandomSampler
  • WeightedSampler
  • 注意したいのは、Data Loaderの部分初期化パラメータの間に相互反発関係があり、これは本を読むことによってソースをより深く理解でき、ここではまとめをするだけである。
  • batch_をカスタマイズしたらsamplerでは、これらのパラメータはすべて標準値を使用しなければなりません。size、shuffle、sampler、drop_last.
  • もしあなたがsamplerをカスタマイズしたら、shuffleはFalse
  • に設定する必要があります。
  • samplerとbatch_samplerは全部Noneです。それではbatch_samplerはPytouchを使用してすでにBatch Samplerを実現しましたが、samplerは2つの状況に分けられます。
  • shuffle=Trueの場合、sampler=RandomSampler
  • shuffle=Falseの場合、sampler=Sequential Sampler(dataset)
  • どのようにSamplerとBatch Samplerをカスタマイズしますか?
    ソースコードをよく見ると、すべての試料は実は同じ親類から継承されています。すなわちSubsetRandomSampler、そのコードの定義は以下の通りです。
    
    class Sampler(object):
     r"""Base class for all Samplers.
     Every Sampler subclass has to provide an :meth:`__iter__` method, providing a
     way to iterate over indices of dataset elements, and a :meth:`__len__` method
     that returns the length of the returned iterators.
     .. note:: The :meth:`__len__` method isn't strictly required by
        :class:`~torch.utils.data.DataLoader`, but is expected in any
        calculation involving the length of a :class:`~torch.utils.data.DataLoader`.
     """
    
     def __init__(self, data_source):
      pass
    
     def __iter__(self):
      raise NotImplementedError
    		
     def __len__(self):
      return len(self.data_source)
    したがって、Sampler関数を定義することですが、この関数の戻り値は反復可能である必要があります。__iter__(self)は、例えばSequentialSamplerによって返される。
    また、iter(range(len(self.data_source)))は、他のSamplerとの主な違いは、Samplerをパラメータとして包装する必要があり、さらに、繰り返しbatch sizeサイズのindexリストに戻る。つまり、後ろのデータの読み込み中に使用されるのは全部batch samplerです。
    Dataset
    Datasetの定義は以下の通りです。
    
    class Dataset(object):
    	def __init__(self):
    		...
    		
    	def __getitem__(self, index):
    		return ...
    	
    	def __len__(self):
    		return ...
    上記の3つの方法は最も基本的であり、BatchSamplerは最も主要な方法であり、データの読み取り方法を規定している。しかし、一般的な方法とは異なり、これはpython built-in方法であり、その主な役割は、クラスがリストのようにインデックス値を通してデータにアクセスできるようにすることである。datasetを定義したら、__getitem__を通じて直接最初のデータにアクセスできます。これまでは、dataset[0]がどのような役割を果たしているのか分かりませんでしたので、どうやってこの関数に入ればいいのか分かりませんでした。今__getitem__方法をデバッグしたいなら、フォーマットサイクルを書いてdatasetを巡回してデバッグしてもいいです。dataloaderなどの山のようなものを構築しなくてもいいです。__getitem__のライブラリを使うことをお勧めします。とても実用的です。後でipdbの使用教程を書く時間があります。また、実際には、前のDataloaderのipdb関数を通じて、Data Loaderのデータの読み取りが実はforループを使ってデータを巡回しています。上にひっくり返さなくてもいいです。直接コピーしました。
    
    class DataLoader(object): 
     ... 
      
     def __next__(self): 
      if self.num_workers == 0: 
       indices = next(self.sample_iter) 
       batch = self.collate_fn([self.dataset[i] for i in indices]) # this line 
       if self.pin_memory: 
        batch = _utils.pin_memory.pin_memory_batch(batch) 
       return batch
    私達はよく見ると、前にもう一つの__next__方法があります。これは何のために使いますか?紹介する前に各パラメータの意味を知る必要があります。
  • self.collate_fn:各iteration、samplerが返すindices、すなわちbatch sizeサイズを示すインデックスリスト
  • indices:前に紹介しましたが、ここではi番目のデータを読み取る動作です。一般的にはself.dataset[i]
  • これを見て、self.dataset[i]=(img, label)の役割は一つのバッtchのデータを統合することです。デフォルトのcollate_fnは、それぞれimgsとlabelを結合するので、collate_fn方法が__getitem__に戻るだけであれば、デフォルトのimg, label方法を使用してもいいですが、読むたびにcollate_fnなどがあれば、対応するデータをbatchデータに統合する必要があります。このように、後続のトレーニングステップが便利である。
    ここで、PytouchのDataLoader、DataSet、Samplerの関係についての文章を紹介します。Pytouch DataLoader DataSet Samplerの内容については、以前の文章を検索したり、次の関連記事を見たりしてください。これからもよろしくお願いします。