J'essaie de mettre en place un réseau siamois qui prend en deux images. Je charge ces images et crée deux chargeurs de données distincts.
Dans ma boucle, je veux passer simultanément par les deux chargeurs de données afin de pouvoir entraîner le réseau sur les deux images.
for i, data in enumerate(Zip(dataloaders1, dataloaders2)):
# get the inputs
inputs1 = data[0][0].cuda(async=True);
labels1 = data[0][1].cuda(async=True);
inputs2 = data[1][0].cuda(async=True);
labels2 = data[1][1].cuda(async=True);
labels1 = labels1.view(batchSize,1)
labels2 = labels2.view(batchSize,1)
# zero the parameter gradients
optimizer.zero_grad()
# forward + backward + optimize
outputs1 = alexnet(inputs1)
outputs2 = alexnet(inputs2)
La valeur de retour du chargeur de données est un tuple. Cependant, lorsque j'essaie d'utiliser Zip
pour les parcourir, j'obtiens l'erreur suivante:
OSError: [Errno 24] Too many open files
Exception NameError: "global name 'FileNotFoundError' is not defined" in <bound method _DataLoaderIter.__del__ of <torch.utils.data.dataloader._DataLoaderIter object at 0x7f2d3c00c190>> ignored
Le Zip ne devrait-il pas fonctionner sur tous les éléments itérables? Mais il semble qu'ici, je ne puisse pas l'utiliser sur des chargeurs de données.
Y a-t-il une autre façon de poursuivre cela? Ou est-ce que j'aborde la mise en place d'un réseau siamois de manière incorrecte?
Je vois que vous avez du mal à faire une bonne fonction de capteur de données. je ferais:
class Siamese(Dataset):
def __init__(self, transform=None):
#init data here
def __len__(self):
return #length of the data
def __getitem__(self, idx):
#get images and labels here
#returned images must be tensor
#labels should be int
return img1, img2 , label1, label2
Pour compléter la réponse de @ ManojAcharya:
L'erreur que vous obtenez ne provient ni de Zip()
ni DataLoader()
directement. Python essaie de vous dire qu'il n'a pas pu trouver l'un des fichiers de données que vous demandez (cf FileNotFoundError
dans la trace d'exception), probablement dans votre Dataset
.
Trouvez ci-dessous un exemple de travail utilisant DataLoader
et Zip
ensemble. Notez que si vous souhaitez mélanger vos données, il devient difficile de conserver les correspondances entre les 2 jeux de données. Cela justifie la solution de @ ManojAcharya.
import torch
from torch.utils.data import DataLoader, Dataset
class DummyDataset(Dataset):
"""
Dataset of numbers in [a,b] inclusive
"""
def __init__(self, a=0, b=100):
super(DummyDataset, self).__init__()
self.a = a
self.b = b
def __len__(self):
return self.b - self.a + 1
def __getitem__(self, index):
return index, "label_{}".format(index)
dataloaders1 = DataLoader(DummyDataset(0, 9), batch_size=2, shuffle=True)
dataloaders2 = DataLoader(DummyDataset(0, 9), batch_size=2, shuffle=True)
for i, data in enumerate(Zip(dataloaders1, dataloaders2)):
print(data)
# ([tensor([ 4, 7]), ('label_4', 'label_7')], [tensor([ 8, 5]), ('label_8', 'label_5')])
# ([tensor([ 1, 9]), ('label_1', 'label_9')], [tensor([ 6, 9]), ('label_6', 'label_9')])
# ([tensor([ 6, 5]), ('label_6', 'label_5')], [tensor([ 0, 4]), ('label_0', 'label_4')])
# ([tensor([ 8, 2]), ('label_8', 'label_2')], [tensor([ 2, 7]), ('label_2', 'label_7')])
# ([tensor([ 0, 3]), ('label_0', 'label_3')], [tensor([ 3, 1]), ('label_3', 'label_1')])
En ajoutant la solution de @ Aldream pour le cas où nous avons une longueur variable de l'ensemble de données et si nous voulons les parcourir tous à la même époque, nous pourrions utiliser la cycle()
de itertools
, a = Python Bibliothèque standard. En utilisant l'extrait de code de @Aldrem, le code mis à jour ressemblera à:
from torch.utils.data import DataLoader, Dataset
from itertools import cycle
class DummyDataset(Dataset):
"""
Dataset of numbers in [a,b] inclusive
"""
def __init__(self, a=0, b=100):
super(DummyDataset, self).__init__()
self.a = a
self.b = b
def __len__(self):
return self.b - self.a + 1
def __getitem__(self, index):
return index
dataloaders1 = DataLoader(DummyDataset(0, 100), batch_size=10, shuffle=True)
dataloaders2 = DataLoader(DummyDataset(0, 200), batch_size=10, shuffle=True)
num_epochs = 10
for Epoch in range(num_epochs):
for i, data in enumerate(Zip(cycle(dataloaders1), dataloaders2)):
print(data)
Avec seulement Zip()
l'itérateur sera épuisé lorsque la longueur est égale à celle du plus petit ensemble de données (ici 100). Mais avec l'utilisation de cycle()
, nous répéterons le plus petit ensemble de données à moins que notre itérateur ne regarde tous les échantillons du plus grand ensemble de données (ici 200).
P.S. On peut toujours affirmer que cette approche peut ne pas être nécessaire pour atteindre la convergence tant que l'on fait des échantillons au hasard, mais avec cette approche, l'évaluation pourrait être plus facile.
En plus de ce qui est déjà mentionné, cycle()
et Zip()
peut créer un problème de fuite de mémoire - surtout lorsque en utilisant des ensembles de données d'image! Pour résoudre cela, au lieu d'itérer comme ceci:
dataloaders1 = DataLoader(DummyDataset(0, 100), batch_size=10, shuffle=True)
dataloaders2 = DataLoader(DummyDataset(0, 200), batch_size=10, shuffle=True)
num_epochs = 10
for Epoch in range(num_epochs):
for i, (data1, data2) in enumerate(Zip(cycle(dataloaders1), dataloaders2)):
do_cool_things()
vous pourriez utiliser:
dataloaders1 = DataLoader(DummyDataset(0, 100), batch_size=10, shuffle=True)
dataloaders2 = DataLoader(DummyDataset(0, 200), batch_size=10, shuffle=True)
num_epochs = 10
for Epoch in range(num_epochs):
dataloader_iterator = iter(dataloaders1)
for i, data1 in enumerate(dataloaders2)):
try:
data2 = next(dataloader_iterator)
except StopIteration:
dataloader_iterator = iter(dataloaders1)
data2 = next(dataloader_iterator)
do_cool_things()
Gardez à l'esprit que si vous utilisez également des étiquettes, vous devez remplacer dans cet exemple data1
avec (inputs1,targets1)
et data2
avec inputs2,targets2
, comme l'a dit @Sajad Norouzi.
KUDOS à celui-ci: https://github.com/pytorch/pytorch/issues/1917#issuecomment-433698337
Si vous souhaitez parcourir plusieurs jeux de données simultanément, il n'est pas nécessaire de définir votre propre classe de jeu de données, utilisez simplement TensorDataset comme ci-dessous:
dataset = torch.utils.data.TensorDataset(dataset1, dataset2)
dataloader = DataLoader(dataset, batch_size=128, shuffle=True)
for index, data in enumerate(dataloader):
xb1, xb2 = data
....
Si vous souhaitez que les étiquettes ou l'itération sur plus de deux jeux de données, alimentez-les simplement en tant qu'argument au TensorDataset après le jeu de données2.