Ich bin etwas verwirrt über die in PyTorch durchgeführte Datenerweiterung. Soweit ich weiß, behalten wir jetzt, wenn wir eine Datenerweiterung durchführen, unseren ursprünglichen Datensatz bei und fügen dann andere Versionen hinzu (Spiegeln, Beschneiden ... usw.). Dies scheint jedoch nicht in PyTorch zu geschehen. Soweit ich aus den Referenzen verstanden habe, verwenden wir data.transforms
in PyTorch, dann werden sie einzeln angewendet. Also zum Beispiel:
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])
]),
}
Für das Training beschneiden wir das Bild zunächst nach dem Zufallsprinzip und passen es in der Größe an (224,224)
. Dann nehmen wir diese (224,224)
Bilder und spiegeln sie horizontal. Daher enthält unser Datensatz jetzt NUR die horizontal gespiegelten Bilder, sodass unsere Originalbilder in diesem Fall verloren gehen.
Habe ich recht? Ist dieses Verständnis richtig? Wenn nicht, wo können wir PyTorch in diesem obigen Code (aus der offiziellen Dokumentation entnommen) anweisen, die Originalbilder beizubehalten und die Größe auf die erwartete Form zu ändern (224,224)
?
Vielen Dank
Die Vorgänge transforms
werden bei jeder Stapelgenerierung auf Ihre Originalbilder angewendet. Damit Ihr Datensatz unverändert bleibt, werden bei jeder Iteration nur die Stapelbilder kopiert und transformiert.
Die Verwirrung kann von der Tatsache herrühren, dass transforms
häufig, wie in Ihrem Beispiel, sowohl für die Datenaufbereitung (Größenänderung/Zuschneiden auf erwartete Abmessungen, Normalisierung von Werten usw.) als auch für die Datenerweiterung (Randomisierung der Größenänderung/Zuschneiden, zufälliges Spiegeln der Bilder usw.).
Was Ihr data_transforms['train']
Tut, ist:
(224, 224)
Zu erhaltenTensor
Tensor
unter Berücksichtigung der von Ihnen angegebenen Mittel- und AbweichungswerteWas Ihr data_transforms['val']
Tut, ist:
(256, 256)
(224, 224)
Zu erhaltenTensor
Tensor
unter Berücksichtigung der von Ihnen angegebenen Mittel- und Abweichungswerte(d. h. die zufällige Größenänderung/Zuschneidung für die Trainingsdaten wird durch eine feste Operation für die Validierungsoperation ersetzt, um zuverlässige Validierungsergebnisse zu erhalten)
Wenn Sie nicht möchten, dass Ihre Trainingsbilder mit einer Chance von 50/50 horizontal gespiegelt werden, entfernen Sie einfach die Zeile transforms.RandomHorizontalFlip()
.
Wenn Sie möchten, dass Ihre Bilder immer in der Mitte beschnitten werden, ersetzen Sie transforms.RandomResizedCrop
Durch transforms.Resize
Und transforms.CenterCrop
, Wie für data_transforms['val']
.
Ich gehe davon aus, dass Sie fragen, ob diese Datenerweiterungstransformationen (z. B. RandomHorizontalFlip) tatsächlich Vergrößerung des Datensatzes oder werden sie nacheinander auf jedes Element im Datensatz angewendet und nicht) Hinzufügen zur Größe des Datensatzes.
Beim Ausführen des folgenden einfachen Code-Snippets konnten wir beobachten, dass letzteres ist wahr, dh wenn Sie einen Datensatz mit 8 Bildern haben, und ein PyTorch-Datensatzobjekt für diesen Datensatz erstellen, wenn Sie den Datensatz und die Transformationen durchlaufen werden für jeden Datenpunkt aufgerufen und der transformierte Datenpunkt wird zurückgegeben. Wenn Sie beispielsweise zufälliges Spiegeln haben, werden einige der Datenpunkte als Original zurückgegeben, andere als gespiegelt (z. B. 4 gespiegelt und 4 Original). Mit anderen Worten, durch eine Iteration durch die Datensatzelemente erhalten Sie 8 Datenpunkte (einige umgedreht und andere nicht). [Dies steht im Widerspruch zum herkömmlichen Verständnis der Erweiterung des Datensatzes (z. B. in diesem Fall mit 16 Datenpunkten im erweiterten Datensatz)]
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)
Ergebnisse: (Die kleinen Unterschiede bei den Fließkommawerten werden durch die Transformation in pil-Bild und zurück verursacht.)
Ursprünglicher Dummy-Datensatz:
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]]]])
transformierter Datensatz:
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]]])