TensorFlow自定义层实现时递归深度超出错误求助
问题描述
我照着TensorFlow官方文档写了自定义全连接层的代码,在Spyder里用TensorFlow 2.17.0运行时,却遇到了RecursionError: maximum recursion depth exceeded in comparison的错误,实在摸不着头脑,麻烦各位帮忙看看问题出在哪?
我的代码如下:
import tensorflow as tf class MyDenseLayer(tf.keras.layers.Layer): def __init__(self, num_outputs): super(MyDenseLayer, self).__init__() self.num_outputs = num_outputs def build(self, input_shape): self.kernel = self.add_weight("kernel", shape=[int(input_shape[-1]), self.num_outputs]) def call(self, inputs): return tf.matmul(inputs, self.kernel) layer = MyDenseLayer(10) _ = layer(tf.zeros([10, 5])) # Calling the layer `.builds` it. print([var.name for var in layer.trainable_variables])
错误回溯信息:
Traceback (most recent call last):
File "/Users/xoxo/Documents/test.py", ...
我的解答
这种递归错误通常是某个方法被无限调用导致的,结合TensorFlow 2.17.0的版本特性和Spyder环境,给你几个排查和解决的方向:
修正
super调用的写法
在Python 3中,虽然super(MyDenseLayer, self).__init__()是合法写法,但新版本的TensorFlow可能在处理这种显式指定类名的调用时出现兼容性问题。建议改成Python 3推荐的简化写法:def __init__(self, num_outputs): super().__init__() self.num_outputs = num_outputs这种写法更简洁,也能避免一些潜在的继承链问题。
排查Spyder环境的变量冲突
Spyder的交互式环境经常会保留之前运行的变量,如果你之前已经定义过layer或者MyDenseLayer同名对象/类,可能会导致新旧定义冲突,触发无限递归。解决办法:- 点击Spyder工具栏的“重启内核”按钮,清空环境后重新运行代码
- 或者在代码开头添加
%reset -f(IPython魔法命令)强制清除所有变量
显式完成层的构建流程
有时候新版本TensorFlow对自定义层的构建流程要求更严格,你可以尝试在build方法中显式调用父类的build方法,确保层的初始化流程完整:def build(self, input_shape): super().build(input_shape) # 调用父类的build方法 self.kernel = self.add_weight("kernel", shape=[int(input_shape[-1]), self.num_outputs])定位递归触发点
如果上面的方法都没用,建议在关键方法里加打印语句,看看哪个方法被反复调用:def __init__(self, num_outputs): print("进入__init__方法") super().__init__() self.num_outputs = num_outputs def build(self, input_shape): print(f"进入build方法,输入形状:{input_shape}") super().build(input_shape) self.kernel = self.add_weight("kernel", shape=[int(input_shape[-1]), self.num_outputs]) def call(self, inputs): print("进入call方法") return tf.matmul(inputs, self.kernel)运行后如果看到某条打印信息重复输出,那就是递归的源头,再针对性解决。
一般来说,第一种或者第二种方法就能解决你遇到的问题,先试试重启Spyder内核再运行修改后的代码吧!
备注:内容来源于stack exchange,提问作者tew_evolving

