Эквивалент Keras / TensorFlow для PyTorch Conv1d

#python #tensorflow #keras #pytorch

#python #tensorflow #keras #pytorch

Вопрос:

В настоящее время я нахожусь в процессе преобразования кода PyTorch в TensorFlow (Keras). Одним из используемых слоев является Conv1d, и описание того, как его использовать в PyTorch, приведено в виде

 torch.nn.Conv1d(in_channels: int, out_channels: int, kernel_size: Union[T, Tuple[T]], stride: Union[T, Tuple[T]] = 1, padding: Union[T, Tuple[T]] = 0, dilation: Union[T, Tuple[T]] = 1, groups: int = 1, bias: bool = True, padding_mode: str = 'zeros')
  

где, как и в Keras (TF1.15), описание дается как

 tf.keras.layers.Conv1D(filters, kernel_size, strides=1, padding='valid', data_format='channels_last', dilation_rate=1, activation=None, use_bias=True, kernel_initializer='glorot_uniform', bias_initializer='zeros', kernel_regularizer=None, bias_regularizer=None, activity_regularizer=None, kernel_constraint=None, bias_constraint=None, **kwargs)
  

Я не смог воспроизвести тот же результат, который я получаю в PyTorch в TensorFlow. т.е. для примера кода в PyTorch

 import torch
import torch.nn as nn
import torch.nn.functional as F
import numpy as np

B, K, L, N = 4, 10, 128, 64
mixture = torch.randint(3, (B, K, L), dtype=torch.float32)
# L2 Norm along L axis
EPS = 1e-8
norm_coef = torch.norm(mixture, p=2, dim=2, keepdim=True)  # B x K x 1
norm_mixture = mixture / (norm_coef   EPS)  # B x K x L
# 1-D gated conv
norm_mixture = torch.unsqueeze(norm_mixture.view(-1, L), 2)  # B*K x L x 1
conv1d_U = nn.Conv1d(L, N, kernel_size=1, stride=1, bias=False)
conv_out = conv1d_U(norm_mixture)
conv_out = F.relu(conv_out)  # B*K x N x 1
mixture_w = conv_out.view(B, K, N)  # B x K x N

weights = conv1d_U.weight.data
  

В TensorFlow для получения аналогичных размеров для вывода код можно найти ниже

 import tensorflow as tf
import numpy as np

def build_net():
    # Encoder
    mixture = tf.keras.layers.Input(shape=(10, 128), name='mixture', batch_size=4)  # [B,K,L]
    norm_coef = tf.keras.backend.sqrt(tf.keras.backend.sum(mixture ** 2, axis=2, keepdims=True)   1e-8)  # [B,K,1]
    norm_mixture = mixture / norm_coef  # [B, K, L]
    norm_mixture = tf.keras.backend.expand_dims(tf.keras.backend.reshape(norm_mixture, [-1, 128]), axis=2)  # [B*K,L,1]
    conv = tf.keras.layers.Conv1D(filters=64, kernel_size=1, activation='relu', use_bias=False, name='conv')(norm_mixture)  # [B*K,N,1]
    mixture_w = tf.keras.backend.reshape(conv, [4, -1, 64])  # [B, K, N]
    return tf.keras.models.Model(inputs=mixture, outputs=mixture_w)

model = build_net()
weights = model.get_weights()
inp = np.random.randn(4, 10, 128)
out = model.predict(inp)
  

Сравнивая размеры весов в любом случае, операция Conv1d явно отличается от TensorFlow (Keras), как следует изменить код TF, чтобы отразить ту же операцию?

Комментарии:

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

2. Я не ожидаю, что веса будут одинаковыми, я бы хотел, чтобы операция была воспроизведена. Размеры весов — это прокси для проверки, приведут ли ядра Conv1d к аналогичной операции. Я изменил формулировку вопроса, чтобы отразить это

3. Количество каналов in не указано в Conv1D в keras (оно получено из предыдущего уровня, в данном случае входного уровня). filters это количество выходных каналов: conv = tf.keras.layers.Conv1D(filters=64, kernel_size=1, activation='relu', use_bias=False, name='conv')(norm_mixture)

4. @Max это то, что я думал, что должен сделать из документации, однако размер вывода операции Conv1D равен (40,128,64), но в PyTorch мы получаем вывод размерности (40,64,1). Итак, снова операция, выполняемая с данными, не совпадает.

5. Я понимаю. Дело в том, что keras использует формат «последний канал», то есть последнее измерение всегда является количеством каналов / фильтров / карт объектов в сверточных слоях. Предыдущее измерение — это измерение последовательности в 1D-сверточных слоях. Пожалуйста, проверьте мое предложение ниже, на самом деле необходимо изменить только ось expand_dims.

Ответ №1:

 import tensorflow as tf
import numpy as np

def build_net():
    # Encoder
    mixture = tf.keras.layers.Input(shape=(10, 128), name='mixture', batch_size=4)  # [B,K,L]
    norm_coef = tf.keras.backend.sqrt(tf.keras.backend.sum(mixture ** 2, axis=2, keepdims=True)   1e-8)  # [B,K,1]
    norm_mixture = mixture / norm_coef  # [B, K, L]
    norm_mixture = tf.keras.backend.expand_dims(tf.keras.backend.reshape(norm_mixture, [-1, 128]), axis=1)  # [B*K,1,L]
    conv = tf.keras.layers.Conv1D(filters=64, kernel_size=1, activation='relu', use_bias=False, name='conv')(norm_mixture)  # [B*K,1,N]
    mixture_w = tf.keras.backend.reshape(conv, [4, -1, 64])  # [B, K, N]
    return tf.keras.models.Model(inputs=mixture, outputs=mixture_w)

model = build_net()
print(model.summary())
weights = model.get_weights()
inp = np.random.randn(4, 10, 128)
out = model.predict(inp)