Как Pytorch Dataloader обрабатывает данные переменного размера? - PullRequest
3 голосов
/ 07 марта 2019

У меня есть набор данных, который выглядит как ниже. То есть первым элементом является идентификатор пользователя, за которым следует набор элементов, по которым пользователь щелкает.

0   24104   27359   6684
0   24104   27359
1   16742   31529   31485
1   16742   31529
2   6579    19316   13091   7181    6579    19316   13091
2   6579    19316   13091   7181    6579    19316
2   6579    19316   13091   7181    6579    19316   13091   6579
2   6579    19316   13091   7181    6579
4   19577   21608
4   19577   21608
4   19577   21608   18373
5   3541    9529
5   3541    9529
6   6832    19218   14144
6   6832    19218
7   9751    23424   25067   12606   26245   23083   12606

Я определяю пользовательский набор данных для обработки моих данных журнала кликов.

import torch.utils.data as data
class ClickLogDataset(data.Dataset):
    def __init__(self, data_path):
        self.data_path = data_path
        self.uids = []
        self.streams = []

        with open(self.data_path, 'r') as fdata:
            for row in fdata:
                row = row.strip('\n').split('\t')
                self.uids.append(int(row[0]))
                self.streams.append(list(map(int, row[1:])))

    def __len__(self):
        return len(self.uids)

    def __getitem__(self, idx):
        uid, stream = self.uids[idx], self.streams[idx]
        return uid, stream

Затем я использую DataLoader для извлечения мини-пакетов из данных для обучения.

from torch.utils.data.dataloader import DataLoader
clicklog_dataset = ClickLogDataset(data_path)
clicklog_data_loader = DataLoader(dataset=clicklog_dataset, batch_size=16)

for uid_batch, stream_batch in stream_data_loader:
    print(uid_batch)
    print(stream_batch)

Приведенный выше код возвращается не так, как я ожидал, я хочу, чтобы stream_batch был двумерным тензором типа integer длины 16. Тем не менее, я получаю список 1D-тензора длины 16, и этот список содержит только один элемент, как показано ниже. Почему это?

#stream_batch
[tensor([24104, 24104, 16742, 16742,  6579,  6579,  6579,  6579, 19577, 19577,
        19577,  3541,  3541,  6832,  6832,  9751])]

Ответы [ 2 ]

1 голос
/ 08 марта 2019

Как предложил @Jatentaki, я написал свою собственную функцию сортировки, и она работала нормально.

def get_max_length(x):
    return len(max(x, key=len))

def pad_sequence(seq):
    def _pad(_it, _max_len):
        return [0] * (_max_len - len(_it)) + _it
    return [_pad(it, get_max_length(seq)) for it in seq]

def custom_collate(batch):
    transposed = zip(*batch)
    lst = []
    for samples in transposed:
        if isinstance(samples[0], int):
            lst.append(torch.LongTensor(samples))
        elif isinstance(samples[0], float):
            lst.append(torch.DoubleTensor(samples))
        elif isinstance(samples[0], collections.Sequence):
            lst.append(torch.LongTensor(pad_sequence(samples)))
    return lst

stream_dataset = StreamDataset(data_path)
stream_data_loader = torch.utils.data.dataloader.DataLoader(dataset=stream_dataset,                                                         
                                                            batch_size=batch_size,                                            
                                                        collate_fn=custom_collate,
                                                        shuffle=False)
1 голос
/ 07 марта 2019

Итак, как вы справляетесь с тем, что ваши образцы имеют разную длину? torch.utils.data.DataLoader имеет параметр collate_fn, который используется для преобразования списка выборок в пакет. По по умолчанию это делает это для списков. Вы можете написать свой собственный collate_fn, который, например, 0 - дополняет ввод, усекает его до некоторой предопределенной длины или применяет любую другую операцию по вашему выбору.

...