为什么TensorFlow模型总是预测相同的类?

3

我的TensorFlow模型总是以100%的置信度预测相同的类别。

首先简要介绍我的环境:任务是使用7个类别进行图像分类并从网络摄像头读取图像。对于模型的训练、验证和测试,我使用数据生成器来使用TensorFlow。

model = tf.keras.models.Sequential()
model.add(tf.keras.layers.Conv2D(32,(3,3), activation='elu',input_shape=(image_heigth,image_width,3)))
model.add(tf.keras.layers.Conv2D(64,(3,3), activation='elu'))
model.add(tf.keras.layers.MaxPooling2D((2,2)))
model.add(tf.keras.layers.Conv2D(128,(3,3), activation='elu'))
model.add(tf.keras.layers.MaxPooling2D((2,2)))
model.add(tf.keras.layers.Conv2D(256,(3,3), activation='elu'))
model.add(tf.keras.layers.Conv2D(256,(3,3), activation='elu'))
model.add(tf.keras.layers.MaxPooling2D((2,2)))
model.add(tf.keras.layers.Conv2D(512,(3,3), activation='elu'))
model.add(tf.keras.layers.MaxPooling2D((2,2)))
model.add(tf.keras.layers.Dropout(0.3))
model.add(tf.keras.layers.Flatten())
model.add(tf.keras.layers.Dense(512, activation='elu'))
model.add(tf.keras.layers.Dense(7, activation='softmax'))

model.summary()

model.compile(loss='categorical_crossentropy', optimizer=tf.keras.optimizers.RMSprop(lr=1e-4), metrics=['acc'])

仅供参考,这是我的模型。使用此代码进行训练、验证和测试:

train_datagen = tf.keras.preprocessing.image.ImageDataGenerator(rescale=1./255, rotation_range=40, shear_range=0.2,zoom_range=0.2, horizontal_flip=True)
validation_datagen = tf.keras.preprocessing.image.ImageDataGenerator(rescale=1./255)
test_datagen = tf.keras.preprocessing.image.ImageDataGenerator(rescale=1./255)
train_generator = train_datagen.flow_from_directory(train_dir, target_size=(image_heigth,image_width),batch_size=batch_size, class_mode='categorical', shuffle=True)
validation_generator = validation_datagen.flow_from_directory(validation_dir, target_size=(image_heigth,image_width), batch_size=5, class_mode='categorical')

for data_batch, labels_batch in train_generator:
    print('Shape des Datenstapels:', data_batch.shape)
    print('Shape des Klassenbzeichnungsstabels:', labels_batch.shape)
    break

history = model.fit(train_generator,steps_per_epoch=steps_per_epoch, epochs=epochs, validation_data=validation_generator,validation_steps=10, callbacks=callback_list)

# Testing the Model
test_generator = test_datagen.flow_from_directory(test_dir, target_size=(image_heigth,image_width), batch_size=5, class_mode='categorical')
test_loss, test_acc = model.evaluate(test_generator, steps=5)
predictions = model.predict(test_generator)
image_batch, label_batch = next (test_generator) 

我已经成功地将分类准确率提高到了90%。我的损失函数已经降至约0.3左右。 调试测试并观察预测结果,如[0.08;0.06;0.56;0.04;0.10;0.09;0.07],这些值符合预期。
最后,我使用TensorFlow方法将模型保存为h5文件。
在另一个Python程序中,我加载此h5文件并想要预测网络摄像头图像。但是现在的输出总是[1.0;0.0;0.0;0.0;0.0;0.0;0.0]。以下是我的代码:
 import numpy as np
import cv2
import tensorflow as tf

model = tf.keras.models.load_model('/home/poppe/Dokumente/Models/Proto2.h5')

classes = ['One', 'two', 'three', 'four', 'five', 'six', 'seven']

model.summary()

cap = cv2.VideoCapture(0)

while(True):
    # Capture frame-by-frame
    ret, frame = cap.read()
    # Our operations on the frame come here
    frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
    rezised = cv2.resize(frame, (150, 150))
    expandArrayImage = np.expand_dims(rezised, axis=0)


    prediction = model.predict(expandArrayImage)

    print (np.max(prediction))
    print(classes[np.argmax(prediction)])

    # Display the resulting frame
    cv2.imshow('frame',frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

# When everything is done, release the capture
cap.release()
cv2.destroyAllWindows()

如您所见,我正在使用OpenCV从网络摄像头读取图像。
为了解决问题,我尝试了以下方法:
1. 将模型简化到最小 --> 没有效果
2. 将问题简化为二元分类 --> 没有效果(始终以100%预测其中一个类)
3. 加载并预测单个图像 --> 没有效果
4. 直接在测试代码后加载和预测单个图像(不必保存和加载模型) --> 没有效果,该图像是我的测试图像之一......通过将此图像进行测试,可以正确地对其进行分类。但是,当将其作为单个图像进行加载并使用预测方法时,我遇到了与以前相同的错误。
因此,由于测试正常运行,我不认为我的数据或模型存在问题。是否有任何问题将OpenCV中的网络摄像头图像转换为TensorFlow模型?
您有其他想法可以尝试解决我的问题吗?
非常感谢! :)

你的训练集是否与你的网络接收到的摄像头视频完全相似(例如采集条件)? - Thomas Schillaci
似乎您没有对网络摄像头输入进行归一化处理,而您对训练集进行了归一化处理。 - Thomas Schillaci
是的...训练集是可能用于分类的照片。因此条件是相同的。我用已知和未知条件测试了我的网络,但总是得到100%的相同预测结果。这个值始终保持不变,即使相机移动一小段时间也不会改变。 - Patrick Poppe
1个回答

1
"

cv2.VideoCapture().read()将返回一个数值范围在(0,255)之间的numpy数组,但您的模型希望它们在范围(0,1)内。

您可以传递一个符合预期范围的图像,例如:

"
rezised = cv2.resize(frame, (150, 150)) / 255
expandArrayImage = np.expand_dims(rezised, axis=0)
# rest of the code

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接