我的机器上装有TensorFlow 1.9和Keras 2.0.8。当使用一些玩具数据训练神经网络时,TensorFlow和Keras之间的训练曲线非常不同,我不明白为什么。
对于Keras实施,网络学习得很好,并且损失继续减少,而对于TensorFlow实施,网络没有学到任何东西,并且损失也没有减少。我试图确保两个实现都使用相同的超参数。 为什么行为如此不同?
网络本身有两个输入:和图像,以及一个向量。然后将它们通过各自的层,然后再进行连接。
这是我的实现。
Tensorflow:
# Create the placeholders
input1 = tf.placeholder("float", [None, 64, 64, 3])
input2 = tf.placeholder("float", [None, 4])
label = tf.placeholder("float", [None, 4])
# Build the TensorFlow network
# Input 1
x1 = tf.layers.conv2d(inputs=input1, filters=30, kernel_size=[5, 5], strides=(2, 2), padding='valid', activation=tf.nn.relu)
x1 = tf.layers.conv2d(inputs=x1, filters=30, kernel_size=[5, 5], strides=(2, 2), padding='valid', activation=tf.nn.relu)
x1 = tf.layers.flatten(x1)
x1 = tf.layers.dense(inputs=x1, units=30)
# Input 2
x2 = tf.layers.dense(inputs=input2, units=30, activation=tf.nn.relu)
# Output
x3 = tf.concat(values=[x1, x2], axis=1)
x3 = tf.layers.dense(inputs=x3, units=30)
prediction = tf.layers.dense(inputs=x3, units=4)
# Define the optimisation
loss = tf.reduce_mean(tf.square(label - prediction))
train_op = tf.train.AdamOptimizer(learning_rate=0.001).minimize(loss)
# Train the model
sess = tf.Session()
sess.run(tf.global_variables_initializer())
training_feed = {input1: training_input1_data, input2: training_input2_data, label: training_label_data}
validation_feed = {input1: validation_input1_data, input2: validation_input2_data, label: validation_label_data}
for epoch_num in range(30):
train_loss, _ = sess.run([loss, train_op], feed_dict=training_feed)
val_loss = sess.run(loss, feed_dict=validation_feed)
凯拉斯:
# Build the keras network
# Input 1
input1 = Input(shape=(64, 64, 3), name='input1')
x1 = Conv2D(filters=30, kernel_size=5, strides=(2, 2), padding='valid', activation='relu')(input1)
x1 = Conv2D(filters=30, kernel_size=5, strides=(2, 2), padding='valid', activation='relu')(x1)
x1 = Flatten()(x1)
x1 = Dense(units=30, activation='relu')(x1)
# Input 2
input2 = Input(shape=(4,), name='input2')
x2 = Dense(units=30, activation='relu')(input2)
# Output
x3 = keras.layers.concatenate([x1, x2])
x3 = Dense(units=30, activation='relu')(x3)
prediction = Dense(units=4, activation='linear', name='output')(x3)
# Define the optimisation
model = Model(inputs=[input1, input2], outputs=[prediction])
adam = optimizers.Adam(lr=0.001)
model.compile(optimizer=adam, loss='mse')
# Train the model
training_inputs = {'input1': training_input1_data, 'input2': training_input2_data}
training_labels = {'output': training_label_data}
validation_inputs = {'input1': validation_images, 'input2': validation_state_diffs}
validation_labels = {'output': validation_label_data}
callback = PlotCallback()
model.fit(x=training_inputs, y=training_labels, validation_data=(validation_inputs, validation_labels), batch_size=len(training_label_data[0]), epochs=30)
这是训练曲线(每个实现两次运行)。
Tensorflow:
凯拉斯:
答案 0 :(得分:2)
在仔细检查了您的实现之后,我发现除批大小外,所有超参数都匹配。我不同意@Ultraviolet的回答,因为kernel_initializer
的默认tf.layers.conv2d
也是Xavier(请参见conv2d的TF实现)。
学习曲线不匹配有以下两个原因:
与TF实现(版本1)相比,Keras实现(版本2)的参数收到的更新更多。在版本1中,您将在每个时期将整个数据集同时馈入网络。这样只会更新30个adam。相比之下,版本2正在执行30 * ceil(len(training_label_data)/batch_size)
的{{1}}亚当更新。
版本2的更新比版本1的噪声更大,因为梯度是在更少的样本上平均的。
答案 1 :(得分:1)
我没有注意到您的两个实现之间的任何区别。我认为如果没有,
第一件事是,它们以不同的初始损失开始。 这表明图的初始化是不同的。 正如您没有提到任何初始化程序。查看文档 (tensorflow Conv2D,Keras Conv2D)我发现 默认的初始值设定项不同。
tensorflow
使用不使用初始化程序,另一方面,Keras
使用
Xavier初始化程序。
第二件事是(这是我的假设)tensorflow
的损失起初急剧减少,但与Keras
相比损失没有太大的减少。由于所设计的网络不是很健壮,也不是很深,这是因为tensorflow
陷入了局部最小值所导致的初始化错误。
第三,两者之间可能会有一些小的差异,因为
默认参数可能有所不同。通常,包装器框架会尝试
处理一些默认参数,以便我们需要进行更少的调整
最佳重量。
我使用了基于的 FastAI 框架
pytorch
和 Keras 框架进行特定分类
使用同一VGG网络的问题。我在 FastAI 上有了明显的进步。因为
它的默认参数最近经过了最新的调整
实践。
我没有注意到批处理大小不同,这是这里最重要的超参数之一。 @rvinas 在他的回答中明确指出了这一点。