保存TensorFlow图像分类模型时触发AttributeError: 'CustomAugment'对象无'__name__'属性的问题咨询
问题原因与解决方法
嘿,这个问题我之前在调试TensorFlow数据增强的时候也碰到过!咱们先搞清楚为啥会报错,再一步步解决。
为什么会出现 AttributeError: 'CustomAugment' object has no attribute '__name__'?
Keras的Lambda层设计初衷是用来包装函数的,而不是类的实例。当你保存模型时,Keras需要序列化所有层的配置,对于Lambda层来说,它会依赖传入的可调用对象的__name__属性来完成序列化。
但你这里传的是CustomAugment()——这是一个类的实例,不是函数。类本身有__name__属性(比如CustomAugment.__name__会返回字符串"CustomAugment"),但类的实例是没有这个属性的,所以保存时就触发了这个错误。
另外顺便提一句,你的_color_drop函数里有个小bug:转灰度后得到的是image,但你用tf.tile的却是原输入x,等于没做颜色丢弃,后面我会在代码示例里修复这个问题。
两种解决方法
方法一:把自定义增强改成函数(最简单)
既然Lambda层适合包装函数,那我们直接把CustomAugment的逻辑改成函数形式:
def CustomAugment(image): def _random_apply(func, x, p): return tf.cond( tf.less(tf.random.uniform([], minval=0, maxval=1, dtype=tf.float32), tf.cast(p, tf.float32)), lambda: func(x), lambda: x) def _color_drop(x): # 修复bug:转灰度后tile处理后的图像,而不是原x gray_image = tf.image.rgb_to_grayscale(x) return tf.tile(gray_image, [1, 1, 3]) img = _random_apply(tf.image.flip_left_right, image, p=0.6) img = _random_apply(_color_drop, img, p=0.9) return img # Lambda层直接传入函数本身,不要实例化 data_augmentation = keras.Sequential( [ tf.keras.layers.Lambda(CustomAugment), layers.experimental.preprocessing.RandomRotation(0.1), ] )
方法二:把CustomAugment改成自定义Keras层(更规范)
如果你的增强逻辑比较复杂,或者需要保存一些参数,更推荐把它改成继承tf.keras.layers.Layer的自定义层,这样天然支持Keras的序列化和保存:
class CustomAugment(tf.keras.layers.Layer): def __init__(self, flip_prob=0.6, color_drop_prob=0.9, **kwargs): super().__init__(**kwargs) self.flip_prob = flip_prob self.color_drop_prob = color_drop_prob def call(self, image, training=None): # 可选:只在训练阶段应用增强,推理阶段返回原图 if not training: return image img = self._random_apply(tf.image.flip_left_right, image, p=self.flip_prob) img = self._random_apply(self._color_drop, img, p=self.color_drop_prob) return img def _color_drop(self, x): gray_image = tf.image.rgb_to_grayscale(x) return tf.tile(gray_image, [1, 1, 3]) # 修复之前的bug def _random_apply(self, func, x, p): return tf.cond( tf.less(tf.random.uniform([], minval=0, maxval=1, dtype=tf.float32), tf.cast(p, tf.float32)), lambda: func(x), lambda: x) # 必须实现这个方法,让Keras能序列化层的参数 def get_config(self): config = super().get_config() config.update({ 'flip_prob': self.flip_prob, 'color_drop_prob': self.color_drop_prob }) return config # 现在直接用这个层,不需要Lambda包装 data_augmentation = keras.Sequential( [ CustomAugment(), layers.experimental.preprocessing.RandomRotation(0.1), ] )
这两种方法都能解决模型保存时的错误,第二种方法更适合长期维护的项目,因为自定义层的扩展性更好,也符合Keras的最佳实践。
内容的提问来源于stack exchange,提问作者Adi
相关产品推荐
相关产品推荐

