函数定义神经网络与循环内直接定义的结果差异及问题解析
两种Keras模型定义方式的差异与问题分析
我尝试将神经网络模型定义为函数后在for循环中调用,但发现与直接在for循环内定义模型的运行结果不同。以下是两种实现案例:
第一种案例:模型定义为函数,循环内调用
def model_1(): model_1 = keras.Sequential() model_1.add(Dense(4, input_dim=5, activation='tanh')) model_1.add(Dropout(0.3)) model_1.add(Dense(2, activation='sigmoid')) model_1.compile(loss= 'binary_crossentropy', optimizer='adam', metrics=['accuracy']) return model_1
随后执行:
for train_index_1, test_index_1 in kfold_1.split(x1, y1): [X_train_1, X_test_1] = x1[train_index_1], x1[test_index_1] [y_train_1, y_test_1] = y1[train_index_1], y1[test_index_1] history_1 = model_1().fit(X_train_1, y_train_1, validation_data=(X_test_1, y_test_1), batch_size=64, verbose=0, epochs=500)
第二种案例:循环内直接定义模型
for train_index_1, test_index_1 in kfold_1.split(x1, y1): [X_train_1, X_test_1] = x1[train_index_1], x1[test_index_1] [y_train_1, y_test_1] = y1[train_index_1], y1[test_index_1] model_1 = keras.Sequential() model_1.add(Dense(4, input_dim=5, activation='tanh')) model_1.add(Dropout(0.3)) model_1.add(Dense(2, activation='sigmoid')) model_1.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy']) history_1 = model_1.fit(X_train_1, y_train_1, validation_data=(X_test_1, y_test_1), batch_size=64, verbose=0, epochs=500)
二者的差异与问题解析
- 核心逻辑等价性
两种写法本质上是完全等价的:每次循环都会创建一个全新的Sequential模型实例,初始化全新的层权重、Dropout随机状态和Adam优化器,不存在模型参数继承或复用的情况。 - 结果差异的根源:随机因素
训练结果不同并非写法本身的问题,而是Keras中多个环节的随机性导致的:- Dense层的权重初始化是随机的
- Dropout层每次迭代的失活神经元选择是随机的
- Adam优化器的初始状态包含随机成分
如果没有手动固定全局随机种子(如np.random.seed(42)、tf.random.set_seed(42)),每次模型创建和训练的随机状态都会有细微差异,最终导致结果波动。
- 函数写法的代码风格问题
第一种写法中,函数名和内部模型变量名均为model_1,虽然Python语法允许,但会降低代码可读性,容易混淆函数对象与模型实例,属于不规范的命名习惯,建议修改内部变量名(比如改为model)。 - 显存占用与资源回收
两种写法在资源占用上没有差异:每次循环创建的新模型会覆盖旧变量引用,旧模型会被Python垃圾回收机制自动清理,不会出现额外的显存泄漏问题。
内容的提问来源于stack exchange,提问作者Dua'a Hamdan
相关产品推荐
相关产品推荐

