首页 文章

TensorFlow和Keras的相同实现之间的不同行为

提问于
浏览
2

我的机器上有TensorFlow 1.9和Keras 2.0.8 . 在使用一些玩具数据训练神经网络时,TensorFlow和Keras之间产生的训练曲线非常不同,我不明白为什么 .

对于Keras实现,网络学习良好且损失继续减少,而对于TensorFlow实施,网络不学习任何东西,并且损失不会减少 . 我试图确保两个实现都使用相同的超参数 . Why is the behaviour so different?

网络本身有两个输入:图像和矢量 . 然后在连接之前将它们传递给它们自己的层 .

这是我的实现 .

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)

Keras:

# 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:

enter image description here

enter image description here

Keras:

enter image description here

enter image description here

2 回答

  • 2

    在仔细检查了您的实现后,我发现除了批量大小之外,所有超参数都匹配 . 我不同意@Ultraviolet的答案,因为 tf.layers.conv2d 的默认 kernel_initializer 也是Xavier(参见conv2d的TF实现) .

    由于以下两个原因,学习曲线不匹配:

    • 来自Keras实现(版本2)的参数接收的数据比TF实现(版本1)的更多 . 在版本1中,您将在每个时期将完整数据集同时馈送到网络中 . 这导致仅有30个adam更新 . 相比之下,版本2使用 batch_size=4 执行 30 * ceil(len(training_label_data)/batch_size) adam更新 .

    • 版本2的更新比版本1的更新更嘈杂,因为渐变是在较少的样本上取平均值 .

  • 1

    我没有注意到你的两个实现之间有任何区别 . 我想,假设没有,

    • 首先,他们从不同的 initial losses 开始 . 这表明图表的初始化是不同的 . 因为你没有提到任何初始化器 . 查看文档(tensorflow Conv2DKeras Conv2D)我发现默认初始值设定项不同 .

    另一方面 tensorflow 使用 no initializer Keras 使用 Xavier initializer .

    • 第二件事是(这是我的假设) tensorflow 损失最初急剧减少但后来并没有比 Keras 减少太多 . 由于设计的网络不是非常健壮而且不是很深,因为初始化不好会因为落入本地最小值而受到影响 .

    • 第三,两者之间可能存在一些差异,因为默认参数可能会有所不同 . 通常,包装器框架尝试处理一些默认参数,以便我们需要更少的调整来获得最佳权重 .
      我使用基于 pytorchKeras 框架的 FastAI 框架来解决使用相同VGG网络的特定分类问题 . 我在 FastAI 有了显着的进步 . 因为它的默认参数最近调整了最新的最佳实践 .

    编辑:

    我没注意到批量大小不同,这是这里最重要的超参数之一 . @rvinas 在答案中明确表示 .

相关问题