Вопрос:

Conv1D с kernel_size = 1 интерпретация

python conv-neural-network pytorch

280 просмотра

3 ответа

712 Репутация автора

Я работаю над очень разреженными векторами в качестве входных данных. Я начал работать с простыми Linear(плотными / полностью связанными слоями), и моя сеть дала довольно хорошие результаты (давайте возьмем точность в качестве моей метрики здесь, 95,8%).

Позже я попытался использовать a Conv1dс a kernel_size=1и a MaxPool1d, и эта сеть работает немного лучше (точность 96,4%).

Вопрос : Чем эти две реализации отличаются? Разве не должен Conv1dс юнитом kernel_sizeделать то же самое, что и линейный слой?

Я пробовал несколько прогонов, CNN всегда дает немного лучшие результаты.

Автор: RobinFrcd Источник Размещён: 08.04.2019 02:58

Ответы (3)


1 плюс

2366 Репутация автора

Я не согласен с ответом @ user2255757 в комментариях, что это должно дать тот же ответ.
TL; DR : Полностью связанные слои имеют индивидуальные веса для отдельных каналов, в то время как сверточные уровни разделяют веса только своих ядер.

Позволь мне объяснить:

Ради этого аргумента я предполагаю, что мы имеем дело с каким-то результатом промежуточного слоя h, который является вектором измерений 1 x N(в противном случае весь элемент полностью связанного слоя не будет иметь места для начала, а также ваше использование из Conv1d).

Из вашего описания я также прочитал, что вы хотите иметь один целевой выход, потенциально ограниченный [0,1]. Соответствующий полностью связанный слой будет иметь структуру, аналогичную соединениям между вторым скрытым слоем и выходным слоем на изображении ниже.
Как вы можете видеть, это содержит ровно четыре соединения, каждое из которых имеет свой собственный вес. Это означает, что вы можете выразить вычисление, которое происходит в этом слое, умножением матрицы, где матрица весов имеет форму [output dimension, input dimension], i.e. in our case this would be aN x 1` «матрицы». Результирующее значение тогда уже в правильном формате вывода (1 значение).

структура нейронной сети

С другой стороны, сверточный слой Conv1dсостоит из одного или нескольких фильтров . Ради аргумента, мы будем смотреть на PyTorch'sConv1d .
Здесь мы видим, что мы можем указать in_channelsи out_channels, но пока будем их игнорировать, поскольку в обоих случаях нам нужен только один канал.

Более интересными являются следующие параметры: как вы уже упоминали в своем вопросе, kernel_sizeбудет равен 1 для вашего примера. Это означает, что мы берем «коробку» размера 1 x 1(вторичное измерение - просто фиктивная фигура для сравнения с полностью подключенным слоем), а затем «сдвигаем» ее по входу, снова сравниваем изображение ниже, которое имеет размер ядра 2.

Именно здесь и происходит настоящая разница!
Вместо того, чтобы иметь Nразные веса для каждого отдельного входа предыдущего слоя, свертка делит один вес между всеми входами. Это означает, что выходное значение на самом деле просто сумма Conv1d_weight * input[i].

Конечно, MaxPool1d снова избавится от дополнительных измерений, но он делает это только путем выбора максимума, который не обязательно коррелирует с тем, что имеет полностью связанный слой.

введите описание изображения здесь

Автор: dennlinger Размещён: 09.04.2019 07:55

0 плюса

333 Репутация автора

Я не согласен с ответом @dennlinger. nn.Conv1dс размером ядра 1 и nn.Linearдают точно такие же результаты. Единственными отличиями являются процедура инициализации и способ применения операций (что оказывает некоторое влияние на скорость). Обратите внимание, что использование линейного слоя должно быть быстрее, поскольку оно реализовано в виде простого умножения матриц (+ добавление широковещательного вектора смещения)

@RobinFrcd Ваши ответы либо различны из-за MaxPool1dили из-за другой процедуры инициализации.

Вот несколько экспериментов, чтобы доказать мои утверждения:

def count_parameters(model):
    """Count the number of parameters in a model."""
    return sum([p.numel() for p in model.parameters()])

conv = torch.nn.Conv1d(8,32,1)
print(count_parameters(conv))
# 288

linear = torch.nn.Linear(8,32)
print(count_parameters(linear))
# 288

print(conv.weight.shape)
# torch.Size([32, 8, 1])
print(linear.weight.shape)
# torch.Size([32, 8])

# use same initialization
linear.weight = torch.nn.Parameter(conv.weight.squeeze(2))
linear.bias = torch.nn.Parameter(conv.bias)

tensor = torch.randn(128,256,8)
permuted_tensor = tensor.permute(0,2,1).clone().contiguous()

out_linear = linear(tensor)
print(out_linear.mean())
# tensor(0.0067, grad_fn=<MeanBackward0>)

out_conv = conv(permuted_tensor)
print(out_conv.mean())
# tensor(0.0067, grad_fn=<MeanBackward0>)

Тест скорости:

%%timeit
_ = linear(tensor)
# 151 µs ± 297 ns per loop

%%timeit
_ = conv(permuted_tensor)
# 1.43 ms ± 6.33 µs per loop
Автор: Yann Dubois Размещён: 20.06.2019 11:58

0 плюса

1 Репутация автора

Да, они разные. Я предполагаю, что вы используете Pytorch API, и, пожалуйста, прочитайте Conv1d Pytorch . Если честно, если вы возьмете оператор за матричный продукт, Conv1d с размером ядра = 1 выдаст те же результаты, что и линейный слой. Однако следует отметить, что оператор, используемый в Conv1d, является 2D -оператором взаимной корреляции, который измеряет сходство двух рядов. Я думаю, что ваш набор данных выигрывает от этого механизма.

Автор: Charles Ying Размещён: 11.08.2019 08:24
Вопросы из категории :
32x32