web-dev-qa-db-ja.com

PyTorchでのデータ増強

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にどこに指示しますか?

ありがとう

24
H.S

transforms操作は、バッチ生成のたびに元の画像に適用されます。したがって、データセットは変更されずに残され、反復ごとにバッチイメージのみがコピーおよび変換されます。

混乱は、あなたの例のように、多くの場合、transformsがデータの準備(予想されるディメンションへのサイズ変更/トリミング、値の正規化など)とデータの増強(サイズ変更/トリミングのランダム化)の両方に使用されるという事実から生じる場合があります、画像のランダムな反転など)。


あなたのdata_transforms['train']がすることは:

  • 提供された画像のサイズをランダムに変更し、ランダムにトリミングして(224, 224)パッチを取得します
  • 50/50の確率で、このパッチにランダムな水平反転を適用するかどうか
  • Tensorに変換します
  • 指定した平均値と偏差値を指定して、結果のTensorを正規化します

あなたのdata_transforms['val']がすることは:

  • 画像のサイズを(256, 256)に変更します
  • (224, 224)パッチを取得するには、サイズ変更された画像を中央で切り取ります
  • Tensorに変換します
  • 指定した平均値と偏差値を指定して、結果のTensorを正規化します

(つまり、トレーニングデータのランダムなサイズ変更/トリミングは、信頼できる検証結果を得るために、検証用の固定操作に置き換えられます)


50/50の機会でトレーニング画像を水平に反転させたくない場合は、transforms.RandomHorizontalFlip()行を削除してください。

同様に、画像を常に中央でトリミングする場合は、transforms.RandomResizedCropの場合と同様に、transforms.Resizetransforms.CenterCropおよびdata_transforms['val']に置き換えます。

15
benjaminplanche

これらのデータ拡張変換(RandomHorizo​​ntalFlipなど)が実際にデータセットのサイズを増やすであるか、またはデータセット内の各アイテムに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]]])
27
Ashkan372