【问题标题】:Why does keras neural network predicts the same number for all different images?为什么 keras 神经网络为所有不同的图像预测相同的数字?
【发布时间】:2021-05-14 07:21:50
【问题描述】:

我正在尝试使用 TensorFlow 的 keras 神经网络来识别手写数字。但是我知道为什么当我调用predict() 时,它会为所有输入图像返回相同的结果。

代码如下:

  ### Train dataset ###
  mnist = tf.keras.datasets.mnist
  (x_train, y_train), (x_test, y_test) = mnist.load_data()
  x_train = x_train/255
  x_test = x_test/255

  model = tf.keras.models.Sequential()
  model.add(tf.keras.layers.Flatten(input_shape=(28,28)))
  model.add(tf.keras.layers.Dense(units=128,activation=tf.nn.relu))
  model.add(tf.keras.layers.Dense(units=10,activation=tf.nn.softmax))

  model.compile(optimizer="adam", loss="sparse_categorical_crossentropy", metrics=["accuracy"])

  model.fit(x_train, y_train, epochs=5)

结果如下:

Epoch 1/5
1875/1875 [==============================] - 2s 672us/step - loss: 0.2620 - accuracy: 0.9248
Epoch 2/5
1875/1875 [==============================] - 1s 567us/step - loss: 0.1148 - accuracy: 0.9658
Epoch 3/5
1875/1875 [==============================] - 1s 559us/step - loss: 0.0784 - accuracy: 0.9764
Epoch 4/5
1875/1875 [==============================] - 1s 564us/step - loss: 0.0596 - accuracy: 0.9817
Epoch 5/5
1875/1875 [==============================] - 1s 567us/step - loss: 0.0462 - accuracy: 0.9859

那么使用图像进行测试的代码如下:

  img = cv.imread('path/to/1.png')
  img = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
  img = cv.resize(img,(28,28))
  img = np.array([img])
    
  if cv.countNonZero((255-image)) == 0:
     print('')
  img = np.invert(img)
    
  plt.imshow(img[0])
  plt.show()
    
  prediction = model.predict(img)
  result = np.argmax(prediction)
  print(prediction)
  print(f'Result: {result}')

结果是:

plt 显示:

[[0. 0. 0. 1. 0. 0. 0. 0. 0. 0.]]
Result: 3

plt 显示

[[0. 0. 0. 1. 0. 0. 0. 0. 0. 0.]]
Result: 3

【问题讨论】:

  • 在预测img = np.invert(img) 时,您正在反转您的图像,而原始数据集的数字值较高(因此黑色背景(0)上的白色数字(1))。同样img/255。在测试图像上/在预测时执行与训练图像相同的处理。
  • 我看到如果我删除第二个img = np.invert(img),它会返回准确百分比的预测,但是如果删除所有img = np.invert(img),它会给出所有错误
  • 你在说什么第二个np.invert(img)?只有一个。 cv.countNonZero((255-image)) 不会反转您所说的实际图像
  • 我再次检查了我的代码并看到了第二个np.invert(img),但cv.countNonZero((255-image)) 仅用于检查图像是否为空白背景。 :D
  • @HungDang 你能就给定的答案(更新部分)提供一些反馈吗?

标签: python tensorflow keras neural-network handwriting-recognition


【解决方案1】:

在推理时间内标准化您的数据,就像您在训练集上所做的那样

img = np.array([img]) / 255

查看this answer (Inference)了解更多详情。


根据您的第三条评论,这里有一些详细信息。

def input_prepare(img):            
    img = cv2.resize(img, (28, 28))   
    img = cv2.bitwise_not(img)   

    img = tf.cast(tf.divide(img, 255) , tf.float64)              
    img = tf.expand_dims(img, axis=0)   
    return img 

img = cv2.imread('/content/1.png')
orig = img.copy() # save for plotting later on 

img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # gray scaling 
img = input_prepare(img)

plt.imshow(tf.reshape(img, shape=[28, 28]))

plt.imshow(cv2.cvtColor(orig, cv2.COLOR_BGR2RGB))
plt.title(np.argmax(model.predict(img)))
plt.show()

它按预期工作。但是由于调整图像大小,数字会损坏并丢失其空间信息。这对模型来说似乎没问题,但如果情况变得更糟,那么模型将预测错误。一个案例

而模型对此的预测是错误的。

plt.imshow(cv2.cvtColor(orig, cv2.COLOR_BGR2RGB))
plt.title(np.argmax(model.predict(img)))
plt.show()

为了解决这个问题,我们可以应用cv2.erode 在调整大小后添加一些像素,例如

def input_prepare(img):            
    img = cv2.resize(img, (28, 28))   
    img = cv2.erode(img, np.ones((2, 2)))
    img = cv2.bitwise_not(img)   

    img = tf.cast(tf.divide(img, 255) , tf.float64)              
    img = tf.expand_dims(img, axis=0)   
    return img 

也许不是最好的方法,但现在模型会更好地理解。

plt.imshow(cv2.cvtColor(orig, cv2.COLOR_BGR2RGB))
plt.title(np.argmax(model.predict(img)))
plt.show()

【讨论】:

  • 所以img = np.invert(img) 没有帮助,对吧?
  • 通常在mnist中,背景为黑色,前景(或数字本身)为白色。您只需要在测试(推理集)时确保相同的视图即可。
  • 图像包含的数字有白色背景和黑色前景,所以我使用np.invert(img) 来反转背景和前景。我还检查了我的代码,我不小心调用了np.invert(img) 两次,所以要预测的最终图像具有白色背景,我清除了第二个,它工作正常,但数字 1 仍然不正确...:(
  • 您是否按照我上面提到的那样在推理时间内对数据进行了标准化?另外,您也可以发布您的原始图片吗?
  • 我试过了,但没有任何变化,我已经在主题中发布了原始图像
猜你喜欢
  • 1970-01-01
  • 2021-01-07
  • 1970-01-01
  • 2013-05-12
  • 2017-05-14
  • 1970-01-01
  • 2017-09-01
  • 2021-07-22
  • 1970-01-01
相关资源
最近更新 更多