web-dev-qa-db-ja.com

pytorchを使用して2つのデータローダーを同時に反復する方法は?

2つの画像を取り込むシャムネットワークを実装しようとしています。これらのイメージをロードして、2つの個別のデータローダーを作成します。

私のループでは、両方のデータローダーを同時に通過させて、両方のイメージでネットワークをトレーニングできるようにします。

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)

データローダーの戻り値はタプルです。ただし、Zipを使用してそれらを反復しようとすると、次のエラーが発生します。

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                           

Zipはすべての反復可能なアイテムで機能しないのですか?しかし、ここではデータローダーでは使用できないようです。

これを追求する他の方法はありますか?または、シャムのネットワークの実装に間違ってアプローチしていますか?

7
ce1

適切なデータローダー機能を作成するのに苦労しているようです。私はやります:

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 
4
Manoj Acharya

@ManojAcharyaの回答を完了するには:

発生しているエラーは、Zip()またはDataLoader()のどちらからも直接発生しません。 Pythonは、要求しているデータファイル(例外トレースのFileNotFoundErrorを参照)の1つがおそらくDataset

DataLoaderZipを一緒に使用した実用的な例を以下に示します。データをシャッフルしたい場合、2つのデータセット間の対応を維持することが難しくなることに注意してください。これは@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')])
6
benjaminplanche

データセットの長さがさまざまで、すべてを同じエポックで通過させたい場合の@Aldreamのソリューションを追加すると、itertoolsからcycle()を使用できます。a= Python標準ライブラリ。@ Aldremのコードスニペットを使用すると、更新されたコードは次のようになります。

_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)
_

Zip()のみでは、長さが最小のデータセット(ここでは100)と等しい場合、イテレータが使い果たされます。ただし、cycle()を使用すると、イテレータが最大のデータセット(ここでは200)のすべてのサンプルを調べない限り、最小のデータセットを再度繰り返します。

追伸ランダムにサンプルを抽出する限り、収束を達成するためにこのアプローチは必要ないかもしれないと常に主張することができますが、このアプローチを使用すると、評価がより簡単になるかもしれません。

2
user3901687

それがすでに述べられていることに加えて、cycle()およびZip()は、メモリリークの問題を引き起こす可能性があります-特に画像データセットを使用して!それを解決するには、次のように繰り返す代わりに:

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()

あなたは使うことができます:

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()

ラベルも使用する場合は、この例ではdata1(inputs1,targets1)およびdata2inputs2,targets2、@ Sajad Norouziが言ったように。

これにKUDOS: https://github.com/pytorch/pytorch/issues/1917#issuecomment-433698337

1
afroditi

2つのデータセットを同時に反復処理する場合は、以下のようにTensorDatasetを使用するだけで、独自のデータセットクラスを定義する必要はありません。

dataset = torch.utils.data.TensorDataset(dataset1, dataset2)
dataloader = DataLoader(dataset, batch_size=128, shuffle=True)
for index, data in enumerate(dataloader):
    xb1, xb2 = data
    ....

ラベルが必要な場合、または3つ以上のデータセットを反復処理する場合は、dataset2の後にTensorDatasetへの引数としてそれらをフィードします。

1
Sajad Norouzi