PyTorchで実行されるデータの増強について少し混乱しています。今、私が知る限り、データ拡張を実行しているときは、元のデータセットを保持し、それから他のバージョンを追加しています(フリッピング、トリミングなど)。しかし、それはPyTorchで起こっているようには見えません。参照から理解した限りでは、PyTorchでdata.transforms
を使用すると、それらを1つずつ適用します。たとえば、次のとおりです。
data_transforms = {
'train': transforms.Compose([
transforms.RandomResizedCrop(224),
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
]),
'val': transforms.Compose([
transforms.Resize(256),
transforms.CenterCrop(224),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
]),
}
ここでは、トレーニングのために、最初に画像をランダムに切り取り、(224,224)
の形状にサイズ変更します。次に、これらの(224,224)
画像を取得し、水平方向に反転させます。したがって、データセットには水平方向に反転した画像のみが含まれるようになり、この場合、元の画像は失われます。
私は正しいですか?この理解は正しいですか?そうでない場合、元の画像を保持し、それらを予想される形状(224,224)
にサイズ変更するために、上記のコード(公式ドキュメントから取得)でPyTorchにどこに指示しますか?
ありがとう
transforms
操作は、バッチ生成のたびに元の画像に適用されます。したがって、データセットは変更されずに残され、反復ごとにバッチイメージのみがコピーおよび変換されます。
混乱は、あなたの例のように、多くの場合、transforms
がデータの準備(予想されるディメンションへのサイズ変更/トリミング、値の正規化など)とデータの増強(サイズ変更/トリミングのランダム化)の両方に使用されるという事実から生じる場合があります、画像のランダムな反転など)。
あなたのdata_transforms['train']
がすることは:
(224, 224)
パッチを取得しますTensor
に変換しますTensor
を正規化しますあなたのdata_transforms['val']
がすることは:
(256, 256)
に変更します(224, 224)
パッチを取得するには、サイズ変更された画像を中央で切り取りますTensor
に変換しますTensor
を正規化します(つまり、トレーニングデータのランダムなサイズ変更/トリミングは、信頼できる検証結果を得るために、検証用の固定操作に置き換えられます)
50/50の機会でトレーニング画像を水平に反転させたくない場合は、transforms.RandomHorizontalFlip()
行を削除してください。
同様に、画像を常に中央でトリミングする場合は、transforms.RandomResizedCrop
の場合と同様に、transforms.Resize
をtransforms.CenterCrop
およびdata_transforms['val']
に置き換えます。
これらのデータ拡張変換(RandomHorizontalFlipなど)が実際にデータセットのサイズを増やすであるか、またはデータセット内の各アイテムに1つずつ適用されているかどうかを尋ねていると思いますデータセットのサイズに追加。
次の簡単なコードスニペットを実行すると、後者はtrueであることがわかります。つまり、8つの画像のデータセットがある場合、データセットを反復処理するときにこのデータセットのPyTorchデータセットオブジェクトを作成します。各データポイントで呼び出され、変換されたデータポイントが返されます。たとえば、ランダムな反転がある場合、一部のデータポイントは元として返され、一部は反転されて返されます(4つの反転と4つの元)。 つまり、データセットアイテムを1回繰り返すことで、8個のデータポイント(一部は反転され、一部は反転されない)になります。 [これは、データセットの拡張に関する従来の理解と矛盾しています(たとえば、この場合、拡張されたデータセットに16個のデータポイントがある)]
class experimental_dataset(Dataset):
def __init__(self, data, transform):
self.data = data
self.transform = transform
def __len__(self):
return len(self.data.shape[0])
def __getitem__(self, idx):
item = self.data[idx]
item = self.transform(item)
return item
transform = transforms.Compose([
transforms.ToPILImage(),
transforms.RandomHorizontalFlip(),
transforms.ToTensor()
])
x = torch.Rand(8, 1, 2, 2)
print(x)
dataset = experimental_dataset(x,transform)
for item in dataset:
print(item)
結果:(浮動小数点数のわずかな違いは、pilイメージへの変換とその逆によって引き起こされます)
元のダミーデータセット:
tensor([[[[0.1872, 0.5518],
[0.5733, 0.6593]]],
[[[0.6570, 0.6487],
[0.4415, 0.5883]]],
[[[0.5682, 0.3294],
[0.9346, 0.1243]]],
[[[0.1829, 0.5607],
[0.3661, 0.6277]]],
[[[0.1201, 0.1574],
[0.4224, 0.6146]]],
[[[0.9301, 0.3369],
[0.9210, 0.9616]]],
[[[0.8567, 0.2297],
[0.1789, 0.8954]]],
[[[0.0068, 0.8932],
[0.9971, 0.3548]]]])
変換されたデータセット:
tensor([[[0.1843, 0.5490],
[0.5725, 0.6588]]])
tensor([[[0.6549, 0.6471],
[0.4392, 0.5882]]])
tensor([[[0.5647, 0.3255],
[0.9333, 0.1216]]])
tensor([[[0.5569, 0.1804],
[0.6275, 0.3647]]])
tensor([[[0.1569, 0.1176],
[0.6118, 0.4196]]])
tensor([[[0.9294, 0.3333],
[0.9176, 0.9608]]])
tensor([[[0.8549, 0.2275],
[0.1765, 0.8941]]])
tensor([[[0.8902, 0.0039],
[0.3529, 0.9961]]])