conv1d 一维卷积
tf.nn.conv1d(
value,
filters,
stride,
padding,
use_cudnn_on_gpu=None,
data_format=None,
name=None
)
- value的格式为:[batch, in_width, in_channels],batch为样本维,in_width为宽度维,表示样本的宽度,in_channels维通道维,表示样本有多少个通道,对应到本文输入[batch, sequence_length, hidden_size]
- [filter_width, in_channels, out_channels] filter_width可以看作每次与value进行卷积的行数,in_channels表示value一共有多少列(与value中的in_channels相对应)。out_channels表示输出通道,可以理解为一共有多少个卷积核,即卷积核的数目。
- stride:一个整数,表示步长,每次(向下)移动的距离。
- padding:‘SAME’或’VALID’
- use_cudnn_on_gpu:可选的bool,默认为True。
- data_format:一个可选的string,可以是"NWC"和"NCW";默认为"NWC",数据按[batch,in_width,in_channels]的顺序存储;"NCW"格式将数据存储为[batch, in_channels, in_width]。
- name:操作的名称(可选)。
我们来理解一下怎么运算的
一个conv2d [128,128,3] 卷积核[3,3,64] ==> [128,128,64] 计算改变了通道数,实际上是每一个通道的卷积核与输入所有通道做计算。
类比一下 conv1d 卷积核变为1维 也就是filter_width,每一个新通道与旧的所有通道相乘,然后多个卷积核相加,实际上是一个矩阵相乘,旧通道为行乘新通道列,看做两个矩阵运算就得出了所有的旧通道*所有的新通道。矩阵运算完再做卷积核的运算应该会简洁很多。
看个例子:
import keras
import keras.backend as K
x = K.variable([[[0.5,0.5,0.5], [1.0,1.0,1.0], [1.5,1.5,1.5], [2.0,2.0,2.0], [2.5,2.5,2.5]]]) # (1,5,3)
# 卷积核大小3 输出通道5
cnn = keras.layers.Conv1D(5, 3, activation='relu', padding='same', kernel_initializer=keras.initializers.Ones(), bias_initializer=keras.initializers.Zeros())(x)
print(K.eval(cnn)) # shape: (1, 5, 5)
# (1*0.5+1*0.5+1*0.5)*3 3:通道
array([[[ 4.5, 4.5, 4.5, 4.5, 4.5],
[ 9. , 9. , 9. , 9. , 9. ],
[13.5, 13.5, 13.5, 13.5, 13.5],
[18. , 18. , 18. , 18. , 18. ],
[13.5, 13.5, 13.5, 13.5, 13.5]]], dtype=float32)