Keras中Conv1D层手动numpy计算输出形状不匹配问题咨询
Conv1D计算逻辑及手动复现方法
1. 直接使用np.dot出错的原因
你当前的用法混淆了卷积计算和全连接层的矩阵乘法逻辑:
- 普通全连接层的权重是对输入所有特征做全局映射,所以可以直接做矩阵乘法;
- Conv1D是滑动卷积核在时序维度上做局部加权求和,参数中的3是卷积核的窗口大小,代表每次会覆盖输入时序维度上连续的3个位置再做计算。
你直接调用np.dot(x, weight)的时候,numpy会把输入的最后一个维度和权重的第一个维度做乘积,自然会多出3这个维度,输出形状不符合预期。
2. padding='same'的Conv1D正确计算逻辑
针对你给出的参数,计算流程如下:
- 首先因为
padding='same',会先对输入x的时序维度(也就是196的维度)左右各补1个0,补完之后时序维度变成196+2=198,保证滑动之后输出时序长度和输入一致; - 大小为3的卷积核从补0后的输入的第0位开始滑动,默认步长为1,总共有196个滑动位置,刚好对应输出的196个时序位置;
- 每个滑动位置的计算逻辑:取出当前窗口覆盖的
(3, 512)的输入片段,和权重(3,512,256)做对应位置相乘后求和,得到(256,)的向量,加上偏置之后就是该位置的输出值; - 所有batch、所有滑动位置都做上述计算,最后得到的输出形状就是
(batch_size, 196, 256)。
3. Numpy手动复现代码参考
你可以用np.lib.stride_tricks.as_strided先把输入转换成滑动窗口的视图,再做计算,示例代码如下:
import numpy as np # 初始化参数 batch_size = 32 in_len = 196 in_dim = 512 kernel_size = 3 out_dim = 256 x = np.ones((batch_size, in_len, in_dim)) weight = np.ones((kernel_size, in_dim, out_dim)) bias = np.ones(out_dim) # 1. 做same padding,时序维度左右各补pad个0 pad = kernel_size // 2 x_pad = np.pad(x, ((0,0), (pad,pad), (0,0)), mode='constant') # 2. 生成滑动窗口视图,形状为 (batch_size, in_len, kernel_size, in_dim) strides = x_pad.strides x_windows = np.lib.stride_tricks.as_strided( x_pad, shape=(batch_size, in_len, kernel_size, in_dim), strides=(strides[0], strides[1], strides[1], strides[2]) ) # 3. 做卷积计算:对应位置乘加,最后加偏置 y = np.einsum('k d o, b t k d -> b t o', weight, x_windows) + bias print(y.shape) # 输出为 (32, 196, 256) 符合预期
内容的提问来源于stack exchange,提问作者Vishak Raj
相关产品推荐
相关产品推荐

