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

如何在TensorFlow中使用或自定义实现Nadam优化器?

嘿,别担心,我来帮你把Nadam优化器在TensorFlow里的用法讲明白,不管是用官方现成的API,还是自己手动实现,都给你梳理清楚~

一、使用官方tf.keras.optimizers.Nadam API的完整流程

官方已经封装好了Nadam,直接用就行,主要分两种常见场景:

1. 配合Keras高阶API(model.fit)快速上手

这是最常用的方式,只需要在模型编译阶段指定optimizer为Nadam实例就好,甚至可以直接传字符串'nadam'让Keras自动初始化。

举个简单的示例,比如训练一个手写数字识别的CNN:

import tensorflow as tf
from tensorflow.keras import layers, models

# 构建简单模型
model = models.Sequential([
    layers.Conv2D(32, (3,3), activation='relu', input_shape=(28,28,1)),
    layers.MaxPooling2D((2,2)),
    layers.Flatten(),
    layers.Dense(10, activation='softmax')
])

# 初始化Nadam优化器,可自定义参数(比如学习率、动量系数)
nadam_optimizer = tf.keras.optimizers.Nadam(
    learning_rate=0.001,
    beta_1=0.9,
    beta_2=0.999,
    epsilon=1e-7
)

# 编译模型,指定优化器、损失函数和评估指标
model.compile(
    optimizer=nadam_optimizer,
    loss=tf.keras.losses.SparseCategoricalCrossentropy(),
    metrics=['accuracy']
)

# 加载MNIST数据并训练
(x_train, y_train), _ = tf.keras.datasets.mnist.load_data()
x_train = x_train.reshape(-1,28,28,1).astype('float32') / 255.0

model.fit(x_train, y_train, epochs=5, batch_size=32)

这里的核心参数简单解释下:

  • learning_rate:控制权重更新的步长,默认0.001
  • beta_1:一阶矩估计的指数衰减率,影响动量的保留程度,默认0.9
  • beta_2:二阶矩估计的指数衰减率,影响自适应学习率的调整,默认0.999
  • epsilon:防止计算时分母为0的小常数,默认1e-7

如果你不想手动初始化,直接写optimizer='nadam'也可以,Keras会用默认参数创建Nadam实例。

2. 自定义训练循环(更精细控制)

如果你的训练逻辑比较复杂(比如需要自定义梯度裁剪、多任务训练等),可以用TensorFlow的GradientTape来手动计算梯度,然后用Nadam的apply_gradients方法更新权重。

示例代码:

# 复用刚才的模型结构和数据
model = models.Sequential([...])  # 同上的CNN结构
nadam_optimizer = tf.keras.optimizers.Nadam()
loss_fn = tf.keras.losses.SparseCategoricalCrossentropy()

# 自定义训练循环
epochs = 5
batch_size = 32
train_dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train)).shuffle(10000).batch(batch_size)

for epoch in range(epochs):
    print(f"Epoch {epoch+1}/{epochs}")
    for step, (x_batch, y_batch) in enumerate(train_dataset):
        with tf.GradientTape() as tape:
            # 前向传播计算预测值和损失
            y_pred = model(x_batch, training=True)
            loss = loss_fn(y_batch, y_pred)
        
        # 计算梯度
        gradients = tape.gradient(loss, model.trainable_variables)
        # 用Nadam优化器更新权重
        nadam_optimizer.apply_gradients(zip(gradients, model.trainable_variables))
        
        # 每100步打印一次损失
        if step % 100 == 0:
            print(f"Step {step}, Loss: {loss.numpy():.4f}")

这样就能完全控制训练的每一步,适合复杂的定制化场景。

二、自定义实现Nadam优化器

如果你想深入理解Nadam的原理,或者需要做一些个性化修改,可以继承tf.keras.optimizers.Optimizer来自己实现。

Nadam的核心是结合了Nesterov动量和Adam的自适应学习率,大致步骤是:

  1. 计算权重的一阶矩(动量)和二阶矩(自适应学习率的分母)
  2. 对一阶矩和二阶矩做偏差修正
  3. 应用Nesterov动量的修正,最终更新权重

下面是一个简化的自定义实现示例:

class CustomNadam(tf.keras.optimizers.Optimizer):
    def __init__(self, learning_rate=0.001, beta_1=0.9, beta_2=0.999, epsilon=1e-7, name="CustomNadam", **kwargs):
        super().__init__(name, **kwargs)
        self._set_hyper("learning_rate", kwargs.get("lr", learning_rate))
        self._set_hyper("beta_1", beta_1)
        self._set_hyper("beta_2", beta_2)
        self._set_hyper("epsilon", epsilon)
    
    def _create_slots(self, var_list):
        # 为每个可训练变量创建一阶矩(m)和二阶矩(v)的缓存
        for var in var_list:
            self.add_slot(var, "m")
            self.add_slot(var, "v")
    
    def _resource_apply_dense(self, grad, var):
        # 获取超参数
        lr = self._get_hyper("learning_rate", tf.float32)
        beta_1 = self._get_hyper("beta_1", tf.float32)
        beta_2 = self._get_hyper("beta_2", tf.float32)
        epsilon = self._get_hyper("epsilon", tf.float32)
        
        # 获取当前的m和v缓存
        m = self.get_slot(var, "m")
        v = self.get_slot(var, "v")
        
        # 更新步骤数(内置的self.iterations会自动递增)
        t = tf.cast(self.iterations + 1, tf.float32)
        
        # 更新一阶矩和二阶矩
        m_t = beta_1 * m + (1 - beta_1) * grad
        v_t = beta_2 * v + (1 - beta_2) * tf.square(grad)
        
        # 偏差修正(消除初始阶段的偏差)
        m_hat = m_t / (1 - tf.pow(beta_1, t))
        v_hat = v_t / (1 - tf.pow(beta_2, t))
        
        # Nadam核心:应用Nesterov动量修正
        m_hat_nesterov = beta_1 * m_hat + (1 - beta_1) * grad
        
        # 更新权重
        var_update = var - lr * m_hat_nesterov / (tf.sqrt(v_hat) + epsilon)
        
        # 赋值更新后的缓存和权重
        m.assign(m_t)
        v.assign(v_t)
        var.assign(var_update)
        
        return tf.group(*[var_update, m_t, v_t])
    
    def get_config(self):
        config = super().get_config()
        config.update({
            "learning_rate": self._serialize_hyperparameter("learning_rate"),
            "beta_1": self._serialize_hyperparameter("beta_1"),
            "beta_2": self._serialize_hyperparameter("beta_2"),
            "epsilon": self._serialize_hyperparameter("epsilon"),
        })
        return config

之后你就可以像用官方Nadam一样使用这个自定义版本了:

custom_nadam = CustomNadam(learning_rate=0.001)
model.compile(optimizer=custom_nadam, loss=tf.keras.losses.SparseCategoricalCrossentropy(), metrics=['accuracy'])

这个实现保留了Nadam的核心逻辑,你可以根据自己的需求修改,比如添加梯度裁剪、调整动量计算方式等。


内容的提问来源于stack exchange,提问作者CQ is not hot

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:42:15