06_快速上手tf.keras第二部分:手写数字识别


本篇分别使用深度神经网络和卷积神经网络来实现对手写数字的识别。

本部分使用到的主要相关API:

  • tensorflow.keras.utils.to_categorical
  • tensorflow.keras.models.Sequential
  • tensorflow.keras.layers.Dropout
  • tensorflow.keras.regularizers.l2

Mnist数据集简介:

  • 1.对0~9这9个手写数字的灰度图像进行分类。
  • 2.数据集有训练图片60000张,测试图片10000张,每个图片大小是28x28的。
  • 3.在DNN模型中需要将每个图片从28x28的矩阵拉成1x784的向量,用来作为全连接网络的输入。
  • 4.在CNN模型中则不用做上面的拉伸。

1.使用深度神经网络实现对手写数字的识别

1.1 首先导入需要的包和函数

import tensorflow as tf
import numpy as np
from tensorflow.keras.utils import to_categorical
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense,Dropout
from tensorflow.keras.optimizers import SGD
from tensorflow.keras.regularizers import l2

与前面的需求不同,这里使用L2正则化以及Dropout,分别从regularizers以及layers中导入。

1.2读取mnist数据集

def load_mnist_func(path):
    f = np.load(path)
    x_train, y_train = f['x_train'], f['y_train']
    x_test, y_test = f['x_test'], f['y_test']
    f.close()
    return (x_train, y_train), (x_test, y_test)
(x_train_data,y_train_data),(x_test_data,y_test_data) = load_mnist_func(path='./data/mnist.npz')

由于原来的代码从网上下实在太慢,因此这里选择自己下载了从本地加载。

1.3 数据加工成合适的输入格式

#60000x28x28 ==>60000x784 并且归一化
x_train_data = x_train_data.reshape(x_train_data.shape[0],-1)/255.0
x_test_data = x_test_data.reshape(x_test_data.shape[0],-1)/255.0

# ==>onehot
y_train_data = to_categorical(y_train_data,num_classes=10)
y_test_data = to_categorical(y_test_data,num_classes=10)

前面两句将数据从60000x28x28转换成60000x784的格式,并且将其中的数据归一化到0~1的范围内。后面两句代码将训练集进行onehot独热编码。

1.4 搭建模型

#model 784==>200==>100=>10
model = Sequential([
    Dense(units=200,input_dim=784,bias_initializer='one',kernel_regularizer=l2(0.0003),activation='tanh'),
    Dropout(0.4),
    Dense(units=100,input_dim=200,bias_initializer='one',kernel_regularizer=l2(0.0003),activation='tanh'),
    Dropout(0.4),
    Dense(units=10,input_dim=100,bias_initializer='one',kernel_regularizer=l2(0.0003),activation='softmax'),
])
sgd = SGD(lr=0.1)
model.compile(
    optimizer=sgd,
    loss='categorical_crossentropy',
    metrics=['accuracy'])

这里可以看到搭建模型除了使用model.add方法,也可以直接在实例化模型对象时直接将各层输进去的方法,当然后面也是可以继续使用add方法来增加新的层。Dropout添加的方法同添加其他普通层一样,里面的值是该层处的参数丢弃率。

1.4 训练和保存模型

model.fit(x_train_data,y_train_data,batch_size=32,epochs=5)
model_path="./weights/mnist_dnn.h5"
model.save_weights(model_path)

#evaluate of test data
loss,accuracy = model.evaluate(x_test_data,y_test_data)
print("test loss: ",loss)
print("test acc: ",accuracy)

#evaluate of train data
loss,accuracy = model.evaluate(x_train_data,y_train_data)
print("train loss:",loss)
print("train loss:",accuracy)

这里模型的训练调用了fit方法,在该方法里可以指定训练数据以及batchsizeepoch等信息。保存模型则使用了save_weights方法,evaluate方法可以使用训练好的参数对数据进行评估。DNN的准确率在95%左右,但是其实这个模型是很不通用的,下面用CNN来重新训练一个泛化能力较好的模型。

本部分完整代码:
03_mnist_dnn.py

2.使用卷积神经网络实现对手写数字的识别

2.1 首先导入需要的包和函数

import tensorflow as tf
import numpy as np
from tensorflow.keras.utils import to_categorical
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense,Dropout,Conv2D,MaxPooling2D,Flatten
from tensorflow.keras.optimizers import SGD

卷积神经网络相关的API包括Dense,Dropout,Convolution2D,MaxPooling2D,Flatten,使用方法见下面搭建网络部分。

2.2读取并处理mnist数据集

def load_mnist_func(path):
    f = np.load(path)
    x_train, y_train = f['x_train'], f['y_train']
    x_test, y_test = f['x_test'], f['y_test']
    f.close()
    return (x_train, y_train), (x_test, y_test)
(x_train_data,y_train_data),(x_test_data,y_test_data) = load_mnist_func(path='./data/mnist.npz')

#60000x28x28 ==>60000x784 并且归一化
x_train_data = x_train_data.reshape(x_train_data.shape[0],-1)/255.0
x_test_data = x_test_data.reshape(x_test_data.shape[0],-1)/255.0

# ==>onehot
y_train_data = to_categorical(y_train_data,num_classes=10)
y_test_data = to_categorical(y_test_data,num_classes=10)

2.3搭建卷积神经网络

model = Sequential()
model.add(Conv2D(input_shape = (28,28,1),filters = 32,kernel_size = 3,
    strides = 1,padding = 'same',activation = 'relu'))
model.add(MaxPooling2D(pool_size = 2,strides =2,padding = 'same',))
model.add(Conv2D(64,3,strides=2,padding='same',activation = 'relu'))
model.add(MaxPooling2D(2,2,'same'))

#把第二个池化层的输出扁平化为1维
model.add(Flatten())
model.add(Dense(1024,activation = 'relu'))
model.add(Dropout(0.25))
model.add(Dense(10,activation='softmax'))

# 定义优化器,loss function,训练过程中计算准确率
sgd = SGD(lr=0.01)
model.compile(optimizer=sgd,loss='categorical_crossentropy',metrics=['accuracy'])
model.fit(x_train_data,y_train_data,batch_size=64,epochs=100)

# 评估模型
loss,accuracy = model.evaluate(x_test_data,y_test_data)
print('test loss',loss)
print('test accuracy',accuracy)

# 保存权重和网络
model_path="./weights/mnist_cnn.h5"
model.save(model_path)

经过100次的迭代之后,准且率已经很好了,达到了99.8%,下一篇来总结一下前几篇使用到的API并制作一些随意的手写字符样本来测试训练好的模型效果。

本部分完整代码:
04_mnist_cnn.py

3.Mnist测试

3.1 首先导入需要的包

import cv2 as cv
import numpy as np
from tensorflow.keras.models import load_model

model = load_model("./weights/mnist_cnn.h5")

加载模型使用的是load_model方法,该方法可以直接加载前面save方法保存下来的h5文件,里面包含了网络结构和训练好的参数。这里使用opencv来读取磁盘上绘制好的图片,图片内容如下:在这里插入图片描述

3.2 读取图片并进行预测

def pred(file_name):
    img = cv.imread(file_name,0)
    #cv.imshow("input",img)
    img = cv.resize(img,(28,28),interpolation = 0)
    img = 255-img
    img = img.reshape(-1,28,28,1)/255.0
    result = model.predict(img)
    print("predict result:",np.argmax(result,axis=1))
    #cv.waitKey(0)
    return np.argmax(result,axis=1)

pred函数首先根据参数里给出的图片路径来以灰度图方式读取图片。然后使用numpy的数据处理方法来将读入的图片转换成原先模型的输入格式,然后直接调用模型的predict方法就可以接收到预测的结果。由于是个十分类的模型,给出的结果是一个十维度的向量,即每个类别的概率分布,里面是每个类别的得分,得分最高的可以通过np.argmax方法提出来,该方法返回最大值的位置,即它的类别。

3.3 测试每一张图片得到准确率

count = 0
right = 0
for img in os.listdir("./data/test_numbers/"):
    label = img[0]
    result = pred("./data/test_numbers/"+img)
    if str(result[0]) == label:
        right += 1
    count += 1

print("CNN accuracy:",right/count)

最终准且率为90%:

CNN accuracy: 0.9

本部分完整代码:
05_mnist_app.py

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值