我尝试使用 Resnet。我尝试过拟合小数据(3 个不同图像),看看是否可以获得几乎 0 损失和 1.0 准确率 - 我做到了。
问题是对训练图像(即用于训练的相同3张图像)的预测不正确..
训练图像
图像标签
[1,0,0]
、[0,1,0]
、[0,0,1]
我的Python代码
#loading 3 images and resizing them
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)
# creating labels
y = np.array([[1,0,0],[0,1,0],[0,0,1]])
# create resnet model
model = ResNet50(input_shape=(197, 197,1),classes=3,weights=None)
# compile & fit model
model.compile(loss='categorical_crossentropy', optimizer='adam',metrics=['acc'])
model.fit(imgs,y,epochs=5,shuffle=True)
# predict on training data
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,损失接近于0:
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 means "training"
ins = [imgs, y, sample_weights, learning_phase]
model.test_function(ins)
[1.192093e-07, 1.0]
也可以通过将动量改为更小的值来验证。
例如,通过将
momentum=0.01
添加到 ResNet50
中的所有批量归一化层,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)
ResNet50V2(第二版)在预测给定图像(例如经典埃及猫)方面比 ResNet50 具有更高的准确度。
预测:[[('n02124075', 'Egyptian_cat', 0.8233388), ('n02123159', 'tiger_cat', 0.103765756), ('n02123045', '虎斑猫', 0.07267675), ('n03958227' , '塑料袋', 3.6531426e-05), ('n02127052', '山猫', 3.647774e-05)]]
与 EfficientNet(90% 准确率)相比,ResNet50/101/152 在采用 Francios Cholett 提供的给定权重时预测结果相当糟糕(15~50% 准确率)。它与权重无关,而是与上述模型固有的复杂性有关。换句话说,需要重新训练上述模型来预测给定的图像。但 EfficientNet 不需要这样的训练来预测图像。
例如,给定一个经典的猫图像,它显示的最终结果如下。
1。采用decode_predictions
from keras.applications.imagenet_utils import decode_predictions
预测:[[('n01930112', '线虫', 0.122968934), ('n03041632', '菜刀', 0.04236396), ('n03838899', '双簧管', 0.03846453), ('n02783161', '球点', 0.027445247), ('n04270147', '抹刀', 0.024508419)]]
2。采用 CV2
img = cv2.resize(cv2.imread('/home/mike/Documents/keras_resnet_common/images/cat.jpg'), (224, 224)).astype(np.float32)
# Remove the train image mean
img[:,:,0] -= 103.939
img[:,:,1] -= 116.779
img[:,:,2] -= 123.68
预测:[[('n04065272', 'recreational_vehicle', 0.46529356), ('n01819313', 'sulfur-crested_cockatoo', 0.31684962), ('n04074963', 'remote_control', 0.051597465), (' n02111889', '萨摩耶犬', 0.040776145), ('n04548362', '钱包', 0.029898684)]]
因此,ResNet50/101/152 模型不适合在没有训练的情况下预测图像,即使提供了权重。但经过 100~1000 epoch 的预测训练后,用户可以感受到它的价值,因为它有助于获得更好的移动平均值。如果用户想要简单的预测,在给定权重的情况下,EfficientNet 是一个不错的选择。
在 Keras 中,使用一批图像进行预测似乎无法正常工作。最好对每张图像单独进行预测,然后手动计算准确性。 举个例子,在下面的代码中,我不使用批量预测,而是使用单个图像预测。
import os
from PIL import Image
import keras
import numpy
###
# I am not including code to load models or train model
###
print("Prediction result:")
dir = "/path/to/test/images"
files = os.listdir(dir)
correct = 0
total = 0
#dictionary to label all traffic signs class.
classes = {
0:'This is Cat',
1:'This is Dog',
}
for file_name in files:
total += 1
image = Image.open(dir + "/" + file_name).convert('RGB')
image = image.resize((100,100))
image = numpy.expand_dims(image, axis=0)
image = numpy.array(image)
image = image/255
pred = model.predict_classes([image])[0]
sign = classes[pred]
if ("cat" in file_name) and ("cat" in sign):
print(correct,". ", file_name, sign)
correct+=1
elif ("dog" in file_name) and ("dog" in sign):
print(correct,". ", file_name, sign)
correct+=1
print("accuracy: ", (correct/total))
发生的事情基本上是 keras.fit() 即你的
model.fit()
在具有最佳拟合的同时,精度会丢失。由于精度丢失,模型拟合会出现问题并产生不同的结果。keras.fit 仅具有良好的拟合效果,而没有达到所需的精度