コードを勉強してから追加します
データベースデータベース+データセット+サンプラー=ローダー
from torch.utils.data import *
IMDB
+ + || =Dataset
Sampler
BatchSampler
DataLoader
1データベース
Image DataBaseはIMDBと略され、ファイルに保存されているデータ情報を参照します。
ファイル形式は変更できます。xml、yaml、json、sqlなど。
VOCはxml形式、COCOはJSON形式です。
IMDBを構築するプロセスは、これらのファイルを解析してデータインデックスを確立するプロセスです。
通常、後続の反復で読みやすいようにPythonリストとして解析されます。
2データセットDataSet
データセット:データベースIMDBに基づいて、データへのシングルトンまたはスライスアクセス方法を提供します。
つまり、データベース内のオブジェクトのインデックス作成メカニズムと、シングルトンインデックスまたはスライスインデックスの実装方法を定義することです。
つまり、DataSetは__getitem__
、データセットを定義することにより、インデックス可能なオブジェクト、つまりインデックス可能なオブジェクトです。
つまり、特定のインデックスインデックスを渡した後、このインデックス、シングルトン、またはスライスに従ってシングルトンまたはスライスアクセスを実行する方法は、インデックスが単一の値であるかリストであるかによって異なります。
Pytorchのソースコードは次のとおりです。
class Dataset(object):
"""An abstract class representing a Dataset.
All other datasets should subclass it. All subclasses should override
``__len__``, that provides the size of the dataset, and ``__getitem__``,
supporting integer indexing in range from 0 to len(self) exclusive.
"""
# 定义单例/切片访问方法,即 dataItem = Dataset[index]
def __getitem__(self, index):
raise NotImplementedError
def __len__(self):
raise NotImplementedError
def __add__(self, other):
return ConcatDataset([self, other])
前述のデータセット基本クラスとIMDB基本クラスに基づいてデータセットをカスタマイズする方法は2つあります。
# 方法一: 单继承
class XxDataset(Dataset)
# 将IMDB作为参数传入,进行二次封装
imdb = IMDB()
pass
# 方法二: 双继承
class XxDataset(IMDB, Dataset):
pass
3サンプラー&バッチサンプラー
実際のアプリケーションでは、データは必ずしも通常の順序でアクセスされるとは限りませんが、ランダムな順序でランダムにアクセスする必要があります。そうでない場合は、ランダムな加重アクセスが必要です。
したがって、特定のルールに従ってデータを読み取ることはサンプリング操作であり、サンプラーを定義する必要があります:サンプラー。
また、データを1つずつ読み取ることはできませんが、バッチで読み取る必要があります。つまり、バッチサンプリング操作が必要です。バッチサンプラーを定義します:BatchSampler。
したがって、データセットのシングルトンアクセス方式だけでは不十分です。これに基づいて、バッチアクセス方式をさらに定義する必要があります。
つまり、サンプラーはインデックス生成ルールを定義し、指定されたルールに従ってインデックスを生成することで、データ読み取りメカニズムを制御します。
BatchSamplerは、サンプラーに基づいて構築されます: BatchSampler = Sampler + BatchSize
Pytorchのソースコードは次のとおりです。
class Sampler(object):
"""Base class for all Samplers.
采样器基类,可以基于此自定义采样器。
Every Sampler subclass has to provide an __iter__ method, providing a way
to iterate over indices of dataset elements, and a __len__ method that
returns the length of the returned iterators.
"""
def __init__(self, data_source):
pass
def __iter__(self):
raise NotImplementedError
def __len__(self):
raise NotImplementedError
# 序惯采样
class SequentialSampler(Sampler):
def __init__(self, data_source):
self.data_source = data_source
def __iter__(self):
return iter(range(len(self.data_source)))
def __len__(self):
return len(self.data_source)
# 随机采样
class RandomSampler(Sampler):
def __init__(self, data_source):
self.data_source = data_source
def __iter__(self):
return iter(torch.randperm(len(self.data_source)).long())
def __len__(self):
return len(self.data_source)
# 随机子采样
class SubsetRandomSampler(Sampler):
pass
# 加权随机采样
class WeightedRandomSampler(Sampler):
pass
class BatchSampler(object):
"""Wraps another sampler to yield a mini-batch of indices.
Args:
sampler (Sampler): Base sampler.
batch_size (int): Size of mini-batch.
drop_last (bool): If ``True``, the sampler will drop the last batch if
its size would be less than ``batch_size``
Example:
>>> list(BatchSampler(range(10), batch_size=3, drop_last=False))
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]
>>> list(BatchSampler(range(10), batch_size=3, drop_last=True))
[[0, 1, 2], [3, 4, 5], [6, 7, 8]]
"""
def __init__(self, sampler, batch_size, drop_last):
self.sampler = sampler # ******
self.batch_size = batch_size
self.drop_last = drop_last
def __iter__(self):
batch = []
for idx in self.sampler:
batch.append(idx)
if len(batch) == self.batch_size:
yield batch
batch = []
if len(batch) > 0 and not self.drop_last:
yield batch
def __len__(self):
if self.drop_last:
return len(self.sampler) // self.batch_size
else:
return (len(self.sampler) + self.batch_size - 1) // self.batch_size
上記から、Samplerは基本的に特定のルールを持つ反復可能なオブジェクトであることがわかりますが、反復できるのは1つのインスタンスのみです。
たとえば [x for x in range(10)]
、range(10)は最も基本的なサンプラーであり、各ループで取得できる値は1つだけです。
[x for x in range(10)]
Out[10]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
from torch.utils.data.sampler import SequentialSampler
[x for x in SequentialSampler(range(10))]
Out[14]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
from torch.utils.data.sampler import RandomSampler
[x for x in RandomSampler(range(10))]
Out[12]: [4, 9, 5, 0, 2, 8, 3, 1, 7, 6]
BatchSamplerは、サンプラーを2回カプセル化し、batchSizeパラメーターを導入してバッチ反復を実現します。
from torch.utils.data.sampler import BatchSampler
[x for x in BatchSampler(range(10), batch_size=3, drop_last=False)]
Out[9]: [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]
[x for x in BatchSampler(RandomSampler(range(10)), batch_size=3, drop_last=False)]
Out[15]: [[1, 3, 7], [9, 2, 0], [5, 4, 6], [8]]
4ローダーDataLoader
実際の計算では、メモリの制限とIO速度の低下を考慮して、データ量が多い場合、
したがって、一度にメモリにロードしたり、1つのスレッドだけでロードしたりすることはできません。
したがって、マルチスレッドと反復ロードが必要であるため、ローダーは具体的に定義されています:DataLoader。
DataLoaderは反復可能オブジェクトである反復可能オブジェクトであり、内部——iter——
にマジック関数が構成されており、それを呼び出すと反復子が返されます。
この関数はiter
、組み込み関数、つまりによって直接呼び出すことができます DataIteror = iter(DataLoader)
。
dataloader = DataLoader(dataset=Dataset(imdb=IMDB()), sampler=Sampler(), num_works, ...)
__init__
パラメータは2つの部分で構成され、前半はを指定するために使用され数据集 + 采样器
、後半はを指定するために使用されます多线程参数
。
class DataLoader(object):
"""
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, sampler=None, batch_sampler=None,
num_workers=0, collate_fn=default_collate, pin_memory=False, drop_last=False,
timeout=0, worker_init_fn=None):
self.dataset = dataset
self.batch_size = batch_size
self.num_workers = num_workers
self.collate_fn = collate_fn
self.pin_memory = pin_memory
self.drop_last = drop_last
self.timeout = timeout
self.worker_init_fn = worker_init_fn
if timeout < 0:
raise ValueError('timeout option should be non-negative')
# 检测是否存在参数冲突: 默认batchSampler vs 自定义BatchSampler
if batch_sampler is not None:
if batch_size > 1 or shuffle or sampler is not None or drop_last:
raise ValueError('batch_sampler is mutually exclusive with '
'batch_size, shuffle, sampler, and drop_last')
if sampler is not None and shuffle:
raise ValueError('sampler is mutually exclusive with shuffle')
if self.num_workers < 0:
raise ValueError('num_workers cannot be negative; '
'use num_workers=0 to disable multiprocessing.')
# 在此处会强行指定一个 BatchSampler
if batch_sampler is None:
# 在此处会强行指定一个 Sampler
if sampler is None:
if shuffle:
sampler = RandomSampler(dataset)
else:
sampler = SequentialSampler(dataset)
batch_sampler = BatchSampler(sampler, batch_size, drop_last)
# 使用自定义的采样器和批采样器
self.sampler = sampler
self.batch_sampler = batch_sampler
def __iter__(self):
# 调用Pytorch的多线程迭代器加载数据
return DataLoaderIter(self)
def __len__(self):
return len(self.batch_sampler)
5データイテレータDataLoaderIter
イテレータとイテレータオブジェクトには違いがあります。
反復可能オブジェクトとは、Iter
関数がそのオブジェクトで使用されるときに、イテレータを返すことができるため、継続的に反復的にアクセスできることを意味します。
イテレータオブジェクトには、内部に追加のマジック関数があり__next__
ます。組み込み関数を使用して操作するnext
と、次のデータを継続的に生成できます。生成ルールは、この関数によって決定されます。
反復可能オブジェクトは、オブジェクトが反復可能であることを示しますが、特定の反復ルールはイテレーターによって記述されます。このデカップリングの利点は、同じ反復可能オブジェクトを、異なるルールを持つ複数のイテレーターで構成できることです。
6データセット/コンテナトラバーサルの一般化されたプロセス:NILIS
NILIS规则
:data = next(iter(loader(DataSet [sampler])))data = next(iter(loader(DataSet [ sampler ])))
- サンプラー は、インデックスの生成ルールを定義し、インデックスリストを返し、後続のインデックスアクセスプロセスを制御します。
__item__
インデックスコンテナと、インデックス可能なオブジェクトとして使用できるコンテナによって定義されたルールに 基づくインデクサー[]操作。- ローダーは
__iter__
、コンテナーの反復可能性の定義に 基づいており、コンテナーをiter()で操作できる反復可能オブジェクトにするためにイテレーターを返すなど、ロード規則を記述します。 - 次にされた ベース
__next__
イテレータを定義する上で、容器の特定の反復ルールを記述し、そして容器を製造するイテレータオブジェクト(次によって操作することができます)。
## 初始化
sampler = Sampler()
dataSet = DataSet(sampler) # __getitem__
dataLoader = DataLoader(dataSet, sampler) / DataIterable() # __iter__()
dataIterator = DataLoaderIter(dataLoader) #__next__()
data_iter = iter(dataLoader)
## 遍历方法1
for _ in range(len(data_iter))
data = next(data_iter)
## 遍历方法2
for i, data in enumerate(dataLoader):
data = data