Я не понимаю размеры входов pytorch conv1d, conv2d - PullRequest
1 голос
/ 08 марта 2020

У меня есть данные 2 временных рядов по 18 баллов каждый. Поэтому я организовал матрицу из 18 строк и 2 столбцов (с 180 выборками для классификации по 2 классам - активированным и не активированным).

Итак, я хочу сделать CNN с этими данными, мое ядро ​​ходит в одном направлении, вдоль линий (временных). Примеры рисунка прилагаются.

Мои данные 18x2

В моем коде я не знаю, какие у меня есть каналы, по сравнению с RGB с 3 каналами. И не знаете входные размеры слоев, и как рассчитать, чтобы узнать полностью связанный слой.

Мне нужно использовать conv1d? conv2d? обыватель? Основываясь на Поймите, что лучше 1D 2D 3D , у меня есть 2D входы, и я хочу сделать 1D свертку (потому что я двигаю свое ядро ​​в одном направлении), это правильно?

Как мне пройти например, размер ядра (3,2)?

Мои данные в этой форме, после использования DataLoader с batch_size = 4:

print(data.shape, label.shape)

torch.Size ([4, 2, 18 ]) torch.Size ([4, 1])

Моя сверточная модель:

OBS: я просто поставил любое количество входного / выходного размера.

# Creating our CNN Model -> 1D convolutional with 2D input (HbO, HbR)

class ConvModel(nn.Module):
    def __init__(self):
        super(ConvModel, self).__init__()
        self.conv1 = nn.Conv1d(in_channels=1,  out_channels= 18, kernel_size=3, stride = 1)
# I dont know the in/out channels of the first conv
        self.maxpool = nn.MaxPool1d(kernel_size=3, stride=3)
        self.conv2 = nn.Conv1d(18, 32, kernel_size=3)
        self.fc1 = nn.Linear(200, 100)  #What I put in/out here ?
        self.fc2 = nn.Linear(100, 50)
        self.fc3 = nn.Linear(50, 2)

    def forward(self, x):
        x = F.relu(self.mp(self.conv1(x)))
        x = self.maxpool(x)

        x = F.relu(self.mp(self.conv2(x)))
        x = self.maxpool(x)

        x = x.view(-1, ??)  # flatten the tensor, which number here ?

        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)

        return x

1 Ответ

0 голосов
/ 08 марта 2020

Позже вы захотите использовать двухканальный conv1d в качестве первого свертка. Т.е. он примет тензор формы [Б, 2, 18]. Наличие двухканального ввода с размером ядра 3 будет определять ядра формы [2, 3], где ядро ​​скользит по последнему измерению ввода. Количество каналов C1 в вашей выходной карте зависит от вас. C1 определяет, сколько независимых [2, 3] ядер вы изучаете. Каждая свертка с ядром [2, 3] создает выходной канал.

Обратите внимание, что если вы не определите заполнение нулями во время conv1d, то вывод для ядра размера 3 будет уменьшен на 2, т.е. получит [B, C1, 16]. Если вы добавите заполнение 1 (которое эффективно дополняет обе стороны ввода столбцом нулей до свертки), то результат будет [B, C1, 18].

Максимальное объединение не меняет количество каналов. Если вы используете размер ядра 3, шаг 3 и отсутствие заполнения, то последнее измерение будет уменьшено до floor(x.size(2) / 3), где x - входной тензор для слоя максимального пула. Если ввод не кратен 3, то значения в конце x карты объектов будут игнорироваться (AKA проблема выравнивания ядра / окна).

Я рекомендую взглянуть на документацию для nn.Conv1d и nn.MaxPool1d, поскольку он предоставляет уравнения для вычисления выходной формы.


Давайте рассмотрим два примера. Вы можете определить C1, C2, F1, F2 так, как вам нравится. Оптимальные значения будут зависеть от ваших данных.

Без заполнения мы получим

class ConvModel(nn.Module):
    def __init__(self):
        # input [B, 2, 18]
        self.conv1 = nn.Conv1d(in_channels=2, out_channels=C1, kernel_size=3)
        # [B, C1, 16]
        self.maxpool = nn.MaxPool1d(kernel_size=3, stride=3)
        # [B, C1, 5]    (WARNING last column of activations in previous layer are ignored b/c of kernel alignment)
        self.conv2 = nn.Conv1d(C1, C2, kernel_size=3)
        # [B, C2, 3]
        self.fc1 = nn.Linear(C2*3, F1)
        # [B, F1]
        self.fc2 = nn.Linear(F1, F2)
        # [B, F2]
        self.fc2 = nn.Linear(F2, 2)
        # [B, 2]

    def forward(x):
        x = F.relu(self.mp(self.conv1(x)))
        x = self.maxpool(x)

        x = F.relu(self.mp(self.conv2(x)))
        x = self.maxpool(x)

        x = x.flatten(1) # flatten the tensor starting at dimension 1

        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)

        return x

Обратите внимание на проблему выравнивания ядра со слоем max-pooling. Это происходит потому, что входные данные для max-pooling не кратны 3. Чтобы избежать проблемы с выравниванием ядра и сделать размеры выходных данных более согласованными, я рекомендую включить дополнительный отступ 1 для обоих слоев свертки. Тогда у вас будет

class ConvModel(nn.Module):
    def __init__(self):
        # input [B, 2, 18]
        self.conv1 = nn.Conv1d(in_channels=2, out_channels=C1, kernel_size=3, padding=1)
        # [B, C1, 18]
        self.maxpool = nn.MaxPool1d(kernel_size=3, stride=3)
        # [B, C1, 6]    (no alignment issue b/c 18 is a multiple of 3)
        self.conv2 = nn.Conv1d(C1, C2, kernel_size=3, padding=1)
        # [B, C2, 6]
        self.fc1 = nn.Linear(C2*6, F1)
        # [B, F1]
        self.fc2 = nn.Linear(F1, F2)
        # [B, F2]
        self.fc2 = nn.Linear(F2, 2)
        # [B, 2]

    def forward(x):
        x = F.relu(self.mp(self.conv1(x)))
        x = self.maxpool(x)

        x = F.relu(self.mp(self.conv2(x)))
        x = self.maxpool(x)

        x = x.flatten(1) # flatten the tensor starting at dimension 1

        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)

        return x
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...