ResNet: 在训练过程中达到100%的准确率,但在相同数据上的预测准确率却只有33%

我尝试使用ResNet进行实验。我尝试在少量数据(3张不同的图片)上过拟合,看看能否达到几乎0的损失和1.0的准确率——我做到了。

问题在于对训练图片(即用于训练的相同3张图片)的预测并不正确..

训练图片

image 1 image 2image 3

图片标签

[1,0,0], [0,1,0], [0,0,1]

我的Python代码

# 加载3张图片并调整大小
imgs = np.array([np.array(Image.open("./Images/train/" + fname)
                          .resize((197, 197), Image.ANTIALIAS)) for fname in
                 os.listdir("./Images/train/")]).reshape(-1,197,197,1)
# 创建标签
y = np.array([[1,0,0],[0,1,0],[0,0,1]])
# 创建ResNet模型
model = ResNet50(input_shape=(197, 197,1),classes=3,weights=None)
# 编译和拟合模型
model.compile(loss='categorical_crossentropy', optimizer='adam',metrics=['acc'])
model.fit(imgs,y,epochs=5,shuffle=True)
# 在训练数据上进行预测
print(model.predict(imgs))

模型确实过拟合了数据:

3/3 [==============================] - 22s - loss: 1.3229 - acc: 0.0000e+00
Epoch 2/5
3/3 [==============================] - 0s - loss: 0.1474 - acc: 1.0000
Epoch 3/5
3/3 [==============================] - 0s - loss: 0.0057 - acc: 1.0000
Epoch 4/5
3/3 [==============================] - 0s - loss: 0.0107 - acc: 1.0000
Epoch 5/5
3/3 [==============================] - 0s - loss: 1.3815e-04 - acc: 1.0000

但预测结果是:

 [[  1.05677405e-08   9.99999642e-01   3.95520459e-07]
 [  1.11955103e-08   9.99999642e-01   4.14905685e-07]
 [  1.02637095e-07   9.99997497e-01   2.43751242e-06]]

这意味着所有图片都被预测为label=[0,1,0]

为什么会这样?这是怎么发生的?


回答:

这是因为批量归一化层的原因。

在训练阶段,批量是根据其均值和方差进行归一化的。然而,在测试阶段,批量是根据之前观察到的均值和方差的移动平均值进行归一化的。

当观察到的批量数量较少时(例如,你的例子中的5批),这就会成为一个问题,因为在BatchNormalization层中,默认情况下moving_mean初始化为0,moving_variance初始化为1。

考虑到默认的momentum是0.99,你需要更新移动平均值很多次,才能使它们收敛到“真实”的均值和方差。

这就是为什么在早期阶段预测不正确,但在1000个epoch之后预测正确的原因。


你可以通过强制BatchNormalization层在“训练模式”下运行来验证这一点。

在训练过程中,准确率为1,损失接近于零:

model.fit(imgs,y,epochs=5,shuffle=True)
Epoch 1/5
3/3 [==============================] - 19s 6s/step - loss: 1.4624 - acc: 0.3333
Epoch 2/5
3/3 [==============================] - 0s 63ms/step - loss: 0.6051 - acc: 0.6667
Epoch 3/5
3/3 [==============================] - 0s 57ms/step - loss: 0.2168 - acc: 1.0000
Epoch 4/5
3/3 [==============================] - 0s 56ms/step - loss: 1.1921e-07 - acc: 1.0000
Epoch 5/5
3/3 [==============================] - 0s 53ms/step - loss: 1.1921e-07 - acc: 1.0000

现在如果我们评估模型,我们会观察到高损失和低准确率,因为在5次更新后,移动平均值仍然非常接近初始值:

model.evaluate(imgs,y)
3/3 [==============================] - 3s 890ms/step
[10.745396614074707, 0.3333333432674408]

然而,如果我们手动指定“学习阶段”变量,让BatchNormalization层使用“真实”的批量均值和方差,结果将与在fit()中观察到的一样。

sample_weights = np.ones(3)
learning_phase = 1  # 1表示“训练”
ins = [imgs, y, sample_weights, learning_phase]
model.test_function(ins)
[1.192093e-07, 1.0]

还可以通过将动量值改为较小的值来验证这一点。

例如,通过在ResNet50中的所有批量归一化层中添加momentum=0.01,在20个epoch后的预测结果是:

model.predict(imgs)
array([[  1.00000000e+00,   1.34882026e-08,   3.92139575e-22],
       [  0.00000000e+00,   1.00000000e+00,   0.00000000e+00],
       [  8.70998792e-06,   5.31159838e-10,   9.99991298e-01]], dtype=float32)

Related Posts

使用LSTM在Python中预测未来值

这段代码可以预测指定股票的当前日期之前的值,但不能预测…

如何在gensim的word2vec模型中查找双词组的相似性

我有一个word2vec模型,假设我使用的是googl…

dask_xgboost.predict 可以工作但无法显示 – 数据必须是一维的

我试图使用 XGBoost 创建模型。 看起来我成功地…

ML Tuning – Cross Validation in Spark

我在https://spark.apache.org/…

如何在React JS中使用fetch从REST API获取预测

我正在开发一个应用程序,其中Flask REST AP…

如何分析ML.NET中多类分类预测得分数组?

我在ML.NET中创建了一个多类分类项目。该项目可以对…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注