Tensorflow中的tensor Dimension问题

本文记录了一次在合并代码过程中因忽视Keras的数据格式设置(data_format)而导致的bug排查经历。在将代码B的部分内容移植到代码A时,未注意到全局设置K.set_image_data_format('channels_first')的影响,导致Dense层报错。通过调整代码结构,仅在必要层手动设置data_format,最终解决了问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

记录一个耗时一天多才排除的bug

起因: 在一份代码(A)上添加了另外一份代码(B)的部分内容

原代码(A)在python脚本开始时做了如下声明

K.set_image_data_format('channels_first')

将全局所有含有data_format参数的keras.layer都设置了data_format='channels_first'

而实际上keras.layer默认data_format='channels_last'

data_format='channels_first'data_format='channels_last的区别是指定这一层的输入哪一个维度是channel

而待移植代码(B)没有做声明, 就保持了默认的data_format='channels_last.

结果: 移植代码(B)的过程中忽视了data_format这个全局参数

将另一份代码(B)的部分移植到原来的代码(A)上时, Dense层一直报错. 报错如下

ValueError: Dimensions must be equal, but are 32 and 256 for 'dense_1/add' (op: 'Add') with input shapes: [?,32,256], [1,256,1].

原因在于, 当设置了全局K.set_image_data_format('channels_first')之后, 前面的网络层生成都按照第一维为通道数的逻辑, 到Dense层, 也就是全连接层再进行相乘时就无法继续正常完成矩阵相乘了.

解决

  1. 尝试将代码A向代码B上移植, 在这个过程中, 由于没有设置K.set_image_data_format('channels_first'), 所以全局默认data_format='channels_last, Dense层不再报错.
  2. 在Dense层不再报错的情况下, 发现步骤1获得的代码输出与预计不一样, 主要表现在输出不一致, 执行同样一段代码, 进行卷积操作结果却不一样.
spec_x = Conv2D(filters=_cnn_nb_filt, kernel_size=(3, 3), padding='same')(spec_x)

在这里插入图片描述
上图左侧是实际结果(代码B) 2,256,40 卷积之后变成了 2,256,128 以最后一维为channel(错误结果).
上图右侧是目标输出结果(代码A), 2,256,40 卷积之后变成了 128, 256,40 以第一维为channel(正确结果).

由于K.set_image_data_format('channels_first')是在文件最开始, 浪费了很多时间都没有发现, 最终通过仔细阅读文档中Conv2D的部分, 才发现可能是data_format这个参数的问题. 最终取消全局设置K.set_image_data_format('channels_first'), 只在特殊层手动设置data_format='channels_first'的方法实现了输出维度的可控, 至此解决了这问题.

教训

  1. 进行代码合并融合时, 一定要多关注诸如K.set_image_data_format('channels_first')这样的公共设置.
  2. 当发现直接将B的部分代码移植到A之上有报错但B单独运行就能正常运行的时候, 尝试新开一个文件夹, 将A的部分代码移植到B上, 看看还能不能正常运行.
  3. 如果出现像上述情况, 执行一样的代码spec_x = Conv2D(filters=_cnn_nb_filt, kernel_size=(3, 3), padding='same')(spec_x), 输入维度一样却出现不一样的输出, 千万不要懵逼, 记得使用pycharm等ide, 打上断点, 看看两边执行到这里之后, 除了filterskernel_size这种显式声眀的参数以外其他参数是否有区别, 这样就能较快的发现是哪一个参数的区别导致了输出的变化. 如果IDE无法确认参数, 就仔细看文档, 确认区别.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值