TensorFlow模型无法训练实现简单乘法预测问题求助
问题描述
我计划先构建一个能预测简单乘法的神经网络,后续再替换成其他公式。原以为实现起来很简单,代码也不复杂,但模型完全无法训练,几乎学不到任何东西,预测结果毫无合理性。
我生成-100到100之间的两个数作为输入,将它们的乘积作为正确结果。程序能正常运行并完成训练轮次,但无法得到有效的预测结果。我猜测是模型搭建存在问题,当前使用两个含1024个神经元的全连接层,尝试调整层数和神经元数量后,仅改变了训练时长,问题仍未解决。
以下是我的代码:
import tensorflow as tf import numpy as np import random import os.path def compileModel(): model = tf.keras.Sequential() model.add( tf.keras.layers.InputLayer(shape=(2,)) ) model.add( tf.keras.layers.Dense(1024) ) model.add( tf.keras.layers.Dense(1024) ) model.add( tf.keras.layers.Dense(units=1) ) model.compile(loss="mean_squared_error", optimizer="adam", metrics=["mse"]) return model def generateData(num): vals = np.zeros((num, 2)) res = np.zeros(num) for i in range(num): a = random.uniform(-100,100) b = random.uniform(-100,100) c = a*b vals[i][0] = a vals[i][1] = b res[i] = c return (vals, res) modelFilename = 'saved_model.keras' runTraining = False if not runTraining and not os.path.isfile(modelFilename): runTraining = True if runTraining: trainData, trainRes = generateData(100000) model = compileModel() model.fit(x=trainData, y=trainRes, epochs=12, batch_size=100) model.save(filepath=modelFilename) else: model = tf.keras.models.load_model(modelFilename) testData, testRes = generateData(1000) model.evaluate(x=testData, y=testRes) print(testData.shape) res = model.predict(testData[0:1]) print(testData[0:1]) print(testRes[0:1]) print(res)
问题分析与解决方案
你的模型无法学习乘法的核心原因有几个,逐个解决就能改善效果:
1. 缺少激活函数导致模型表达能力受限
当前的全连接层没有添加激活函数,相当于所有层都是线性变换。而乘法是非线性任务,线性模型的组合依然是线性的,根本无法拟合乘法这种非线性关系。
解决办法:在两个隐藏的Dense层后添加非线性激活函数,比如ReLU,或者更适合回归任务的Swish:
def compileModel(): model = tf.keras.Sequential() model.add( tf.keras.layers.InputLayer(shape=(2,)) ) model.add( tf.keras.layers.Dense(1024, activation='relu') ) # 添加激活函数 model.add( tf.keras.layers.Dense(1024, activation='relu') ) # 添加激活函数 model.add( tf.keras.layers.Dense(units=1) ) model.compile(loss="mean_squared_error", optimizer="adam", metrics=["mse"]) return model
2. 输入输出的数值范围差异过大
输入是-100到100的数,乘积的范围是-10000到10000,数值跨度太大,会导致梯度更新不稳定,模型难以收敛。
解决办法:对输入和输出做归一化处理,把数值压缩到0-1或-1-1的区间:
- 修改
generateData函数,对输入和输出做标准化:
def generateData(num): vals = np.zeros((num, 2)) res = np.zeros(num) for i in range(num): a = random.uniform(-100,100) b = random.uniform(-100,100) c = a*b # 归一化输入到[-1, 1] vals[i][0] = a / 100.0 vals[i][1] = b / 100.0 # 归一化输出到[-1, 1] res[i] = c / 10000.0 return (vals, res)
- 预测时记得反归一化,把结果还原成实际乘积:
res = model.predict(testData[0:1]) # 反归一化 actual_pred = res * 10000.0 print(testData[0:1] * 100.0) # 还原输入的原始值 print(testRes[0:1] * 10000.0) # 还原真实结果 print(actual_pred)
3. 训练参数可以微调
- 可以把学习率调小一点,比如
optimizer=tf.keras.optimizers.Adam(learning_rate=0.0001),避免梯度震荡。 - 增加训练轮次到20-30轮,或者添加
EarlyStopping回调,防止过拟合同时确保模型收敛:
from tensorflow.keras.callbacks import EarlyStopping # 训练时添加回调 early_stop = EarlyStopping(monitor='val_loss', patience=3, restore_best_weights=True) model.fit(x=trainData, y=trainRes, epochs=30, batch_size=100, validation_split=0.1, callbacks=[early_stop])
4. 模型结构可以简化
不需要1024这么多神经元,过多的神经元反而容易导致过拟合或训练效率低下。可以尝试调整为:
def compileModel(): model = tf.keras.Sequential() model.add( tf.keras.layers.InputLayer(shape=(2,)) ) model.add( tf.keras.layers.Dense(64, activation='relu') ) model.add( tf.keras.layers.Dense(32, activation='relu') ) model.add( tf.keras.layers.Dense(units=1) ) model.compile(loss="mean_squared_error", optimizer=tf.keras.optimizers.Adam(learning_rate=0.0001), metrics=["mse"]) return model
按照以上修改后,模型应该能有效学习乘法关系,预测结果会接近真实值。
内容的提问来源于stack exchange,提问作者v010dya
相关产品推荐
相关产品推荐

