我已经在带有TensorFlow后端(v 1.12.0)的scikit-learn(v 0.20.0)和Keras(v 2.2.4)中构建了一个完全连接的神经网络。一个隐藏层中有10个单位。在这两种情况下,我都通过调用scikit-learn的train_test_split函数(random_state
设置为0)来选择训练和测试数据。然后都使用scikit-learn的StandardScaler
对其进行缩放。实际上,到目前为止,每种情况的代码实际上是相同的。
在scikit-learn中,我使用MLPRegressor定义了神经网络。该函数调用的输出为
MLPRegressor(activation='logistic', alpha=1.0, batch_size='auto', beta_1=0.9,
beta_2=0.999, early_stopping=False, epsilon=1e-08,
hidden_layer_sizes=(10,), learning_rate='constant',
learning_rate_init=0.001, max_iter=200, momentum=0.9,
n_iter_no_change=10, nesterovs_momentum=True, power_t=0.5,
random_state=None, shuffle=True, solver='sgd', tol=0.0001,
validation_fraction=0.2, verbose=False, warm_start=False)
这些参数中的大多数参数未使用,但其中一些相关参数是有200次迭代,没有提前停止,学习率恒定,求解器为SGD,nesterovs_momentum=True
和{{1} }。
Keras中的定义是(称为Keras 1)
momentum=0.9
我对Keras的理解是,该网络应该与scikit-learn相同,但可能会有一个例外,scikit-learn应该对层之间的所有权重进行正则化,而此Keras网络仅对进入权重的权重进行正则化。输入层的隐藏层。我可以通过以下方式将权重的正则化从隐藏层添加到输出层(称为Keras 2)
mlp = Sequential() # create a sequential neural network using Keras
mlp.add(Dense(units=10,activation='sigmoid',input_dim=X.shape[1],
kernel_regularizer=skl_norm))
mlp.add(Dense(units=1,activation='linear'))
opt = optimizers.SGD(lr=0.001,momentum=0.9,decay=0.0,nesterov=True)
mlp.compile(optimizer=opt,loss='mean_squared_error')
mlp.fit(X_train,y_train,batch_size=200,epochs=200,verbose=0)
为了确保Keras中的正则化与scikit-learn中的正则化相匹配,我在Keras中实现了自定义正则化功能:
mlp = Sequential() # create a sequential neural network using Keras
mlp.add(Dense(units=10,activation='sigmoid',input_dim=X.shape[1],
kernel_regularizer=skl_norm))
mlp.add(Dense(units=1,activation='linear',kernel_regularizer=skl_norm))
opt = optimizers.SGD(lr=0.001,momentum=0.9,decay=0.0,nesterov=True)
mlp.compile(optimizer=opt,loss='mean_squared_error')
mlp.fit(X_train,y_train,batch_size=200,epochs=200,verbose=0)
其中的alpha参数应该与scikit-learn中显示的相同。遵循这些定义的代码仅在每个API使用的方法的名称上有所不同。
我的结果表明,这两个API中的正则化并不相同,或者更有可能的是,我在Keras中的实现并非我所认为的那样。这是神经网络输出之间的比较:
顶行为alpha = 0,底行为alpha = 1.0。左列是scikit-learn,中列是Keras 1,右列是Keras2。与其讨论各个图之间的所有差异,不如立即跳出我的是,当正则化被“关闭”(alpha = 0)时,适合度非常相似。当“打开”正则化(alpha = 1)时,当隐藏层的输出被正则化时,scikit-learn的性能优于Keras,尤其是Keras 2。
在不同的运行中,R ^ 2值略有变化,但不足以解决底行中的差异。那么,这两种网络实现之间有什么区别?
更新:
此后,我发现,如果我在Keras中使用“无限”激活函数,则对于所有预测,训练将完全失败,而返回nan,而在scikit-learn中就可以了。 “无界”是指一种激活,允许无穷大的输出值,例如线性/同一性,softplus或relu。
当我打开TensorBoard回调时,我收到一个以结尾的错误(已编辑以省去无关的潜在敏感信息):
InvalidArgumentError(请参阅上面的回溯):汇总直方图中的Nan为:density_2 / bias_0 [[node density_2 / bias_0(在/Users/.../python2.7/site-packages/keras/callbacks.py:796上定义= HistogramSummary [T = DT_FLOAT,_device =“ / job:localhost / replica:0 / task:0 / device:CPU:0“](dense_2 / bias_0 / tag,density_2 / bias / read)]] p
基于此错误,我猜想第二层的偏置单位会变得非常大,但我不知道为什么这会在Keras / TF中发生,而不是在scikit-learn中发生。
由于softplus在x = 0时不具有f(x)= 0的属性,因此我认为问题不在于输入几乎为零。此外,tanh激活非常有效。因此,我认为输入群集接近零时不会出现问题。当x->-infinity和Sigmoid / logistic工作良好而softplus失败时,Sigmoid / logistic和softplus都具有f(x)= 0属性。因此,我认为输入到-infinity不会有问题。