Keras / TensorFlow相当于PyTorch Conv1d

问题描述

我目前正在将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,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)

我无法再现在TensorFlow中的PyTorch中获得的相同输出。即用于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,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,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,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,L]
    norm_coef = tf.keras.backend.sqrt(tf.keras.backend.sum(mixture ** 2,axis=2,keepdims=True) + 1e-8)  # [B,1]
    norm_mixture = mixture / norm_coef  # [B,L]
    norm_mixture = tf.keras.backend.expand_dims(tf.keras.backend.reshape(norm_mixture,[-1,128]),axis=2)  # [B*K,1]
    conv = tf.keras.layers.Conv1D(filters=64,activation='relu',use_bias=False,name='conv')(norm_mixture)  # [B*K,1]
    mixture_w = tf.keras.backend.reshape(conv,[4,-1,64])  # [B,N]
    return tf.keras.models.Model(inputs=mixture,outputs=mixture_w)

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

在两种情况下,比较Conv1d操作与TensorFlow(Keras)的权重尺寸时,应该如何更改TF代码以反映相同的操作?

解决方法

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,1]
    norm_mixture = mixture / norm_coef  # [B,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,N]
    mixture_w = tf.keras.backend.reshape(conv,[4,-1,64])  # [B,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)