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

用TensorFlow原生API重构Keras模型训练异常求助

问题分析与解决方案

你遇到的问题主要来自两个关键细节遗漏,加上Keras在后台帮你处理了一些默认逻辑,而原生TensorFlow代码里没做这些步骤:

1. 训练数据未做epoch级打乱

Keras的model.fit()默认会在每个epoch开始前彻底打乱训练数据(你也显式设置了shuffle='true'),但你的原生TensorFlow代码是直接按meshgrid生成的原始顺序取batch训练。这种网格数据的样本是按x、y的顺序排列的,每个batch里的样本特征高度相似,会让SGD的更新方向极度单一,快速收敛到糟糕的局部最优解,完全学不到函数的真实模式。

2. 目标值与模型输出的形状不匹配

你的模型输出logits是(batch_size, 1)的二维张量,但目标placeholdery定义的是(None)的一维数组。虽然TensorFlow的广播机制能让减法运算运行,但这会导致损失计算的逻辑和Keras的MSE存在细微差异,甚至引入不必要的计算误差。

修复后的原生TensorFlow代码

针对以上问题,我调整了你的代码,保留核心逻辑的同时补上了关键步骤:

import tensorflow as tf
import numpy as np

# 生成训练数据
start = 0
end = 2*np.pi
samp = 1000
num_samp = samp**2
step = end / samp
x_train = np.arange(start, end, step)
y_train = np.arange(start, end, step)
data = np.array(np.meshgrid(x_train,y_train)).T.reshape(-1,2)
z_label = np.sin(data[:,0] + data[:,1])
# 转换标签为二维,完全匹配模型输出形状
z_label = z_label.reshape(-1, 1)

# 超参数
n_inputs = 2
n_hidden1 = 128
n_hidden2 = 64
n_outputs = 1
learning_rate = 0.01

# 构建阶段
X = tf.placeholder(tf.float32, shape=(None, n_inputs), name='input')
# 修改目标placeholder形状为(None,1),和输出严格对齐
y = tf.placeholder(tf.float32, shape=(None, 1), name="target")
hidden1 = tf.layers.dense(X, n_hidden1, name="hidden1", activation=tf.nn.sigmoid)
hidden2 = tf.layers.dense(hidden1, n_hidden2, name="hidden2", activation=tf.nn.sigmoid)
logits = tf.layers.dense(hidden2, n_outputs, activation='linear', name='output')
loss = tf.reduce_mean(tf.square(logits - y), name='loss')
optimizer = tf.train.GradientDescentOptimizer(learning_rate)
training_op = optimizer.minimize(loss, name='train')
init = tf.global_variables_initializer()
saver = tf.train.Saver()

# --- 执行阶段 ---
n_epochs = 40
batch_size = 32
# 计算完整batch数(包含最后一个不足batch_size的样本)
n_batches = int(np.ceil(num_samp / batch_size))

with tf.Session() as sess:
    init.run()
    for epoch in range(n_epochs):
        print("Epoch: ", epoch, " Running...")
        # 每个epoch开始前打乱数据顺序
        permutation = np.random.permutation(num_samp)
        data_shuffled = data[permutation]
        z_label_shuffled = z_label[permutation]
        
        loss_arr = []
        for iteration in range(n_batches):
            start = iteration * batch_size
            end = min(start + batch_size, num_samp)  # 处理最后一个不完整batch
            batch_X = data_shuffled[start:end]
            batch_y = z_label_shuffled[start:end]
            
            # 一次run同时获取训练操作和当前batch损失,避免重复计算
            _, batch_loss = sess.run([training_op, loss], feed_dict={X: batch_X, y: batch_y})
            loss_arr.append(batch_loss)
        
        mean_loss = np.mean(loss_arr)
        print(f"Epoch: {epoch} | Mean Loss: {mean_loss:.6f}")

Keras后台隐式处理的细节

除了上述的shuffle和形状对齐,Keras还帮你做了这些默认工作:

  • 自动处理最后一个不完整的batch,不会丢弃样本
  • 默认使用glorot_uniform初始化权重(和TensorFlowtf.layers.dense默认一致,但自定义初始化时需注意)
  • 自动管理会话、变量初始化等底层逻辑,不需要手动编写tf.Session()和init.run()
  • 内置回调的默认调度逻辑(比如你用的ModelCheckpoint和TensorBoard,原生TF需要手动实现部分细节)

按照修改后的代码训练,应该能得到和Keras模型相近的训练效果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 08:54:35