TensorFlow2/Keras训练调用get/set_weights报图函数无法取值错误的解决方法
错误产生的根本原因
get_weights()、set_weights()是专门为eager模式设计的接口:
- 调用
get_weights()时,底层会执行.numpy()把权重张量转成Python可直接操作的numpy数组 - 调用
set_weights()时,会把传入的numpy数组转成张量,覆写对应层的权重值
而Keras运行fit()时,会自动把重写的train_step编译成带图执行的tf.function函数,静态图环境禁止直接读取张量的实际数值做numpy转换,因此就抛出了Cannot get value inside Tensorflow graph function的错误。
可正常运行的实现方式
核心逻辑是跳出“取numpy数组-算完再塞回去”的流程,全程留在TensorFlow张量计算体系里完成权重操作,完全适配静态图的执行规则:
- 不调用
get_weights()、set_weights(),直接通过模型的weights属性拿到对应编码器的权重张量列表——这个列表的顺序、形状和get_weights()返回的numpy数组列表完全一致,不会出现权重错位 - EMA的加权计算直接在张量层面完成,计算完通过权重自带的
assign()方法直接完成赋值,这个接口是原生支持静态图执行的,不会触发numpy取值的报错。
修正后的代码
只需要替换原来的update_ema方法,其余训练逻辑可以保留:
def update_ema(self, decay=0.999): # 直接拿权重张量,不触发numpy转换 online_weights = self.online_encoder.weights target_weights = self.target_encoder.weights # 逐权重计算EMA值并直接赋值 for online_w, target_w in zip(online_weights, target_weights): new_target_w = decay * target_w + (1 - decay) * online_w target_w.assign(new_target_w)
调试时的注意点
- 替换完逻辑后,可以先跑eager模式的单步训练验证:确认两个编码器的权重列表顺序完全匹配,不会出现因为层结构不同导致的权重错位赋值。
- 静态图包裹的所有方法里,都不要调用
.numpy()、get_weights()、set_weights()这类会触发跨环境取值的操作,一旦在图函数里调用,必然会触发同类报错。 - 初始化模型时要把
target_encoder的所有权重标记为non_trainable=True,避免优化器把它的权重纳入梯度更新范围,和后续的EMA赋值逻辑产生冲突。
内容的提问来源于stack exchange,提问作者MPA
相关产品推荐
相关产品推荐

