You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

tf.function内调用Optimizer.apply_gradients触发变量创建报错

问题根因

你的判断是对的,隐式创建tf.Variable触发报错的是定义在tf.function内部的Adam优化器,和apply_gradients的参数包装形式没有关系:

  • Keras优化器第一次执行apply_gradients时,会自动为每个待更新参数创建持久化的内部状态变量:比如Adam需要存储一阶动量、二阶动量的滑动平均结果,这些状态本质都是tf.Variable类型,会在优化器生命周期内持续更新。
  • 你当前代码把优化器实例化逻辑写在了@tf.function装饰的训练函数内部,每次函数执行时都会生成全新的优化器实例,第一次函数trace时创建的优化器内部变量无法复用到后续调用,直接违反了tf.function的变量创建规则:仅允许在函数第一次调用trace时创建单例tf.Variable,禁止后续调用重复新建变量。
  • 报错栈指向optimizer.apply_gradients行,只是因为这行是优化器实际触发内部变量初始化的执行节点,不是传参格式错误导致的,你之前调整参数列表、元组、zip包装形式的操作自然无法解决问题。
修复方案

核心原则是:所有带持久化状态的对象(模型、优化器等),都不要放在tf.function内部重复实例化,保证其只初始化一次即可。
修正后的可运行代码如下:

import tensorflow as tf
import numpy as np
from PIL import Image

# 读取并预处理图像
image = np.array(Image.open("frame7766.jpg")).reshape(1, 720, 1280, 3)/255
content_image = tf.convert_to_tensor(image, dtype = tf.float32)
generated_image = tf.Variable(np.random.rand(1, 720, 1280, 3)/2 + content_image/2, dtype = tf.float32)

# 优化器移到tf.function外部,全局只初始化一次
optimizer = tf.keras.optimizers.Adam(learning_rate = 0.01)

def clip_0_1(image):
    return tf.clip_by_value(image, clip_value_min=0, clip_value_max=1)

@tf.function
def train_step(generated_image, content_image):
    with tf.GradientTape() as tape:
        cost = tf.reduce_sum(tf.square(generated_image - content_image))
    grad = tape.gradient(cost, generated_image) 
    optimizer.apply_gradients([(grad, generated_image)])
    generated_image.assign(clip_0_1(generated_image))
    return generated_image

# 训练循环示例:generated_image为引用类型的Variable,assign操作是原地更新,不需要每次调用后重新赋值
for _ in range(100):
    train_step(generated_image, content_image)
补充说明

如果有特殊场景需要把优化器定义在tf.function内部,可以通过继承tf.Module将优化器设为模块的属性,依托Module的变量追踪机制保证变量只创建一次,但对于常规训练任务,直接将模型、优化器这类带状态的对象初始化在tf.function外部是最简单、符合官方最佳实践的写法,不会触发这类变量创建报错。

内容的提问来源于stack exchange,提问作者floatingtrees

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 05:30:47