Изменение размерности встраивания из-за изменения заполнения в размере партии

Вопрос или проблема

Я хочу обучить простую нейронную сеть, у которой embedding_dim является параметром:

class BoolQNN(nn.Module):
    def __init__(self, embedding_dim):
        super(BoolQNN, self).__init__()
        self.fc1 = nn.Linear(embedding_dim, 64)
        self.relu = nn.ReLU()
        self.fc2 = nn.Linear(64, 1)

    def forward(self, question_emb, passage_emb):
        combined = torch.cat((question_emb, passage_emb), dim=1)
        x = self.fc1(combined)
        x = self.relu(x)
        x = self.fc2(x)
        return torch.sigmoid(x)

Для загрузки данных я использовал DataLoader из torch с пользовательской функцией collate_fn.

train_dataset = BoolQDataset(train_data, pretrained_embeddings)
train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=16, shuffle=True, collate_fn=collate_fn_padd)

model = BoolQNN(301)

Функция collate_fn_padd выглядит следующим образом:

def collate_fn_padd(batch):

  questions, passages, labels = zip(*batch)

  questions = [torch.tensor(q) for q in questions]
  passages = [torch.tensor(p) for p in passages]

  padded_questions = pad_sequence(questions, batch_first=True, padding_value=0)
  padded_passages = pad_sequence(passages, batch_first=True, padding_value=0)

  labels = torch.tensor(labels, dtype=torch.float32)
  
  return padded_questions, padded_passages, labels

Проблема: Для каждой партии, с которой я хочу обучать свою модель, встроенный текст заполняется разной длины (он принимает самую длинную последовательность текущей партии).

Это означает, что мой размер embedding dim/размер входа для линейного слоя в нейронной сети меняется от партии к партии, хотя я хочу, чтобы размер был одинаковым для каждой партии.

Из-за этого я получаю ошибки вроде: shapes mat1 и mat2 не могут быть перемножены (16×182 и 301×64)

Можно ли настроить функцию collate_fn_pad так, чтобы она заполняла последовательности одинакового размера, независимо от размера партии?

Ответ или решение

Ваш вопрос касается проблемы с изменением размера входных данных в нейронной сети из-за различной длины последовательности, полученной при использовании функции collate_fn. Действительно, при использовании pad_sequence, ваша нейронная сеть сталкивается с ошибкой, когда размер входа метки не совпадает с ожидаемым размером при каждом батче, что приводит к ошибке mat1 and mat2 shapes cannot be multiplied.

Проблема

Как вы отметили, размерность ваших векторов question_emb и passage_emb меняется в зависимости от самой длинной последовательности в каждом батче. Это значит, что количество элементов в padded_questions и padded_passages будет различным при различных батчах, что вызывает конфликт при попытке произведения матриц в слоях:

16x182 и 301x64

Решение

Для решения вашей проблемы, вам нужно убедиться, что размерность входных последовательностей остается фиксированной для всех батчей, независимо от их длины. Это можно сделать, предварительно задав фиксированную длину последовательности. Приведу пример, как можно адаптировать вашу функцию collate_fn_padd для достижения этой цели.

Шаги по внедрению

  1. Определите фиксированную длину последовательности. Это может быть максимальная длина, которую вы готовы поддерживать в вашей модели. Например, если вы хотите, чтобы все последовательности имели длину, равную MAX_SEQ_LEN, вы можете использовать эту длину для обоих видов эмбеддингов.

  2. Измените функцию collate_fn. При добавлении паддинга учитывайте не только длину текущего батча, но и фиксированное значение.

Пример кода

MAX_SEQ_LEN = 300  # или любое другое значение, которое вам подходит

def collate_fn_padd(batch):
    questions, passages, labels = zip(*batch)

    # Преобразуйте в тензоры
    questions = [torch.tensor(q) for q in questions]
    passages = [torch.tensor(p) for p in passages]

    # Паддинг до фиксированной длины
    padded_questions = pad_sequence([q[:MAX_SEQ_LEN] for q in questions], 
                                    batch_first=True, 
                                    padding_value=0)

    padded_questions = F.pad(padded_questions, (0, MAX_SEQ_LEN - padded_questions.size(1)), "constant", 0)

    padded_passages = pad_sequence([p[:MAX_SEQ_LEN] for p in passages], 
                                   batch_first=True, 
                                   padding_value=0)

    padded_passages = F.pad(padded_passages, (0, MAX_SEQ_LEN - padded_passages.size(1)), "constant", 0)

    labels = torch.tensor(labels, dtype=torch.float32)

    return padded_questions, padded_passages, labels

Объяснение

  • MAX_SEQ_LEN: Определяет фиксированную длину, до которой будут паддинговаться все последовательности. Если длина вашего вопроса или прохода превышает это значение, они будут обрезаны.
  • pad_sequence: Используется для паддинга последовательностей до указанной длины.
  • F.pad: Применяется для добавления паддинга до фиксированной длины (если требуется), чтобы гарантировать, что все батчи имеют одинаковую размерность.

Заключение

Теперь, благодаря внесенным изменениям, ваша модель будет принимать входы с фиксированной размерностью, что устраняет проблемы, связанные с несовпадением форматов входа. Подобный подход позволяет избежать ошибок и обеспечивает стабильность сети при обучении. Не забудьте протестировать модель с различными размерами входных данных, чтобы обеспечить ее корректную работу.

Оцените материал
Добавить комментарий

Капча загружается...