keras 多类别分类问题-识别手写数字
“识别手写数字”被称为“人工智能”中的“hello world”。
前置知识
- 图片数据形式
用shape()
查看数据形状。
第一个数字为数据项数。一项数据代表一张图片,称为一个样本。
第2、3个数字表示数据形式,是一个什么形状的矩阵。矩阵中的数字值代表了这张正方形图片中对应位置的像素值,像素值为 0~255 之间的数字,这块区域的颜色也随像素值的增大而变黑,从白色到黑色增强。
例如,像素值为 0,表示图片中这一块区域为白色,像素值为 255,表示图片中这一块区域为黑色,像素值为 125,表示图片中这一块区域为灰色
- reshape() 方法
第一个参数规定变形后的数据共有多少项,第二个参数是每一项数据的形状
- to_categorical 函数
将数据集中“1,2,3,4,5,6……”形式的标签值化为一个向量标签,便于计算机识别
- softmax 激活函数
用于处理多分类问题。输出是一个数组,其中元素索引代表一种类别、元素为样本属于该类别的可能性,该可能性用0-1来描述
- predict_classes 函数
参考:Get Class Labels from predict method in Keras
TensorFlow 2.6 版本中删除了 predict_classes 函数,需要用代替品
classes = model.predict_classes(x_test)
改为:
-
多分类问题(最后一层激活层是 softmax)
predict = model.predict(x_test) # 得到概率 classes = np.argmax(predict, axis=-1)
也就是
np.argmax(model.predict(x_test), axis=-1)
-
二分类问题(最后一层激活层是 sigmoid)
predict = model.predict(x_test) classes = np.where(y_pred > threshold, 1,0)
-
多标签分类问题(最后一层激活层是 softmax)
y_predict = model.predict(y_test) class_labels = [labels[i] for i, prob in enumerate(y_predict) if prob > 0.5]
代码
from tensorflow import keras
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Activation
from tensorflow.keras import optimizers
from tensorflow.keras.datasets import mnist
from tensorflow.python.keras.utils.np_utils import to_categorical
(x_train, y_train), (x_test, y_test) = mnist.load_data('mnist.pkl.gz') # 从 keras 官方下载数据集
print(x_train.shape) # 查看训练集x坐标形状
结果表明 x_train 中一共有60000项数据。一项数据代表一张图片,称为一个样本。这张图片的数据形式是一个28*28的数字矩阵,矩阵中的数字值代表了这张正方形图片中对应位置的像素值,取值范围为0~255之间的数字
# 可以先查看一下数据构成
print(x_train)
print(y_train)
print(y_test)
从结果可以看出,y 代表的标签值并不能代表分类。因为对计算机来说,0,1值才能代表分类
# 转变训练数据的形状:把数字矩阵平铺,即 将28*28二维矩阵变成长度为784(=28*28)的一维数组,便于神经网络接收和处理数据
# 为了方便处理数据,将数组中数字的类型转换为 float32
x_train = x_train.reshape(x_train.shape[0], x_train.shape[1]*x_train.shape[2]).astype('float32') # 第一个参数规定变形后的数据共有多少项。第二个参数为每一项数据的形状,即 一个由原矩阵展开的数组28*28
x_test = x_test.reshape(x_test.shape[0], x_test.shape[1]*x_test.shape[2]).astype('float32')
# 归一化:把矩阵中的每项数字都除以255,将里面的数字转换成0-1之间的数。这样神经网络更好地处理这些数据
x_train /= 255
x_test /= 255
# 将标签值转化成标签
y_train = to_categorical(y_train, num_classes=10)
y_test = to_categorical(y_test, num_classes=10)
# 构建模型
model = Sequential()
model.add(Dense(64, input_shape=(784,))) # 注意:输入层一定要传入input_shape参数
model.add(Activation('relu')) # 激活层,给上一层的输出叠加一个非线性激活函数relu。作用:给模型增加非线性,如果只使用线性函数模型对这种复杂问题的拟合性会不好
model.add(Dense(32))
model.add(Activation('relu'))
model.add(Dense(10)) # 将之前的结果汇总为10个输出,以此对应10个类别
model.add(Activation('softmax')) # 用于处理多分类问题的函数,它的输出是一个数组,其中元素索引代表一种类别、元素为样本属于该类别的可能性
# 编译训练
model.compile(optimizer='adadelta', loss='categorical_crossentropy', metrics=['accuracy'])
model.fit(x_train, y_train, batch_size=20, epochs=10)
# 测试
score = model.evaluate(x_test, y_test, batch_size=500)
# 测试对 x_test[5] 的分类。x_test[5]所代表的图片中数字为1,则分类应该为分类为class[1]
predict = model.predict(x_test[5].reshape(1,-1), batch_size=1)
classes = np.argmax(predict, axis=-1)
print(r'loss: ', score[0], r' accuracy: ', score[1])
print(r'class: ', classes)
结果为
Epoch 1/10
3000/3000 [==============================] - 10s 3ms/step - loss: 2.3030 - accuracy: 0.1228
Epoch 2/10
3000/3000 [==============================] - 8s 3ms/step - loss: 2.1898 - accuracy: 0.1626
Epoch 3/10
3000/3000 [==============================] - 9s 3ms/step - loss: 2.1019 - accuracy: 0.2089
Epoch 4/10
3000/3000 [==============================] - 8s 3ms/step - loss: 2.0175 - accuracy: 0.2681
Epoch 5/10
3000/3000 [==============================] - 8s 3ms/step - loss: 1.9330 - accuracy: 0.3305
Epoch 6/10
3000/3000 [==============================] - 8s 3ms/step - loss: 1.8498 - accuracy: 0.3933
Epoch 7/10
3000/3000 [==============================] - 8s 3ms/step - loss: 1.7689 - accuracy: 0.4483
Epoch 8/10
3000/3000 [==============================] - 8s 3ms/step - loss: 1.6909 - accuracy: 0.4982
Epoch 9/10
3000/3000 [==============================] - 9s 3ms/step - loss: 1.6162 - accuracy: 0.5396
Epoch 10/10
3000/3000 [==============================] - 10s 3ms/step - loss: 1.5444 - accuracy: 0.5770
---
20/20 [==============================] - 1s 7ms/step - loss: 1.4999 - accuracy: 0.6000
1/1 [==============================] - 1s 884ms/step
loss: 1.4999303817749023 accuracy: 0.6000000238418579
class: [1]