卷积神经网络之LeNet5手写识别及代码中一些常见问题的解决

LeNet5手写识别

关于LeNet5结构,前面已经专门写过一篇文章做了详细分析,如果有小伙伴不太清楚具体结构或想要加深一下对LeNet5结构的理解,可参见https://blog.csdn.net/fencecat/article/details/123529738
这里就不再赘述了,直接上代码!!!

1.LeNet5手写识别代码与注释

#!/usr/bin/env python3

import numpy as np
#import keras
from keras.datasets import mnist
from keras.utils import np_utils
from keras.models import Sequential
from keras.layers import Dense, Activation, Conv2D, MaxPooling2D, Flatten
#from keras.optimizers import adam
from keras.callbacks import ModelCheckpoint
import skimage.io as io

(X_train, y_train), (X_test, y_test) = mnist.load_data()#调用mnist数据集


X_train = X_train.reshape(-1, 28, 28, 1)  # normalize
X_test = X_test.reshape(-1, 28, 28, 1)      # normalize
X_train = X_train / 255
X_test = X_test / 255   #归一化
y_train = np_utils.to_categorical(y_train, num_classes=10)#categorical类别属性,label的编码可能不是字符型的数据,因为是做分类的,所以我们希望把结果转换成类别
y_test = np_utils.to_categorical(y_test, num_classes=10)#categorical就是类别,一共分成10类

model_checkpoint = ModelCheckpoint('lenet5_membrane.hdf5', monitor='loss',verbose=1, save_best_only=True)
#模型训练好后,把权重,阈值存到一个.hdf5的文件中,保存的时候只存最好的一次,
#网络结构的设计
model = Sequential()
model.add(Conv2D(input_shape=(28, 28, 1), kernel_size=(5, 5), filters=20, activation='relu'))#第一层卷积层:输入是28×28的灰度图,filter指的是20个通道,激活函数用的是relu,当然也可以用其他的激活函数,如sigmoid,tanh等
model.add(MaxPooling2D(pool_size=(2,2), strides=2, padding='same'))#第二层池化层,用的最大池化,same 可以简单理解为输入和输出图像的大小相同,为了达到这个目的一般需要padding

model.add(Conv2D(kernel_size=(5, 5), filters=50,  activation='relu', padding='same'))#第三层卷积层
model.add(MaxPooling2D(pool_size=(2,2), strides=2, padding='same'))#第四层池化层

model.add(Flatten())#Flatten“拉直”,将上一层池化层的输出结果拉直成一个向量
model.add(Dense(500, activation='relu'))#全连接隐层,500个节点
model.add(Dense(10, activation='softmax'))#输出层10类10个节点,激活函数使用的是softmax

model.compile(optimizer='rmsprop', loss='categorical_crossentropy', metrics=['accuracy'])


print('Training')
model.fit(X_train, y_train, epochs=2, batch_size=32,callbacks=[model_checkpoint])#模型训练
#将切分好的训练样本,做2个epoch,分批次的训练,每32个样本为1组,训练好以后,把刚才的模型fit拟合一下
#就是前向计算反向传播
print('\nTesting')
model.load_weights('lenet5_membrane.hdf5')#把训练好的保存的最好的模型的权重加载进来
loss, accuracy = model.evaluate(X_test, y_test)#模型的评价,看模型预测的分类结果与真实的结果是否一样

print('\ntest loss: ', loss)
print('\ntest accuracy: ', accuracy)#打印模型的损失与准确度



#测试程序,0~9十个手写数字图像,大小就是28×28的
#load_data是用来读取样本的
def load_data(address):
    im = io.imread(address)
    image_list = []#用一个列表,把10个测试数据读进来
    for item in im:
        row = []
        for i in item:
            row.append([i[0]])
        image_list.append(row)
    array = np.array(image_list)
    array = array/255#分别做归一化
    image = np.expand_dims(array, axis=0)
    return image

address_list = ['0.jpg','1.jpg','2.jpg','3.jpg','4.jpg','5.jpg','6.jpg','7.jpg','8.jpg','9.jpg']


for address in address_list:
    image = load_data(address)#使用自定义函数load_data将图片读进来
    predictions = model.predict_classes(image)#调用predict做预测,这里predict_classes里边有fit,有评估
    print('图片预测结果:'+str(predictions[0]))#将预测结果打印出来

2.关于compile

在训练模型之前,需要通过compile来对学习过程进行配置。compile接收三个参数:

  • 优化器optimizer:指定为已预定义的优化器名,如rmsprop、adagrad,或一个Optimizer类的对象
    #损失函数loss:最小化的目标函数,为预定义的损失函数名,如categorical_crossentropy、mse,也可以为一个损失函数
  • 指标列表metrics:对分类问题,一般设置为metrics=[‘accuracy’]。指标可以是一个预定义指标的名字,也可以是一个用户定制的函数.指标函数应该返回单个张量,或一个完成metric_name - > metric_value映射的字典.
  • 如果只是载入模型并利用其predict,可以不用进行compile。在Keras中,compile主要完成损失函数和优化器的一些配置,是为训练服务的。predict会在内部进行符号函数的编译工作(通过调用_make_predict_function生成函数)

3.运行结果卷积神经网络之LeNet5手写识别及代码中一些常见问题的解决_第1张图片

我们的测试图片就是十张写有0~9十个数字的图片
根据运行结果我们可以看出模型预测的结果,它是用概率来表示所属类别的可能性的。输出结果是一个含有10个元素的列表,每个元素一次对应分类结果是0~9的概率,概率最大的就是分类的结果。以图片0为例,输出的列表中第一个值最大为9.9996674e-01,即表明预测的分类结果为手写体“0”。
可以看出10张图片都识别对了,模型的损失为: 0.032327234745025635,
模型的准确率 为0.9890999794006348。
卷积神经网络之LeNet5手写识别及代码中一些常见问题的解决_第2张图片

#模型预测结果
test loss:  0.032327234745025635

test accuracy:  0.9890999794006348
图片预测结果:[9.9996674e-01 1.4531780e-09 3.6541067e-08 2.3892710e-07 8.0564977e-10
 2.1735028e-05 5.0758335e-06 7.5194259e-07 2.5847055e-06 2.7731057e-06]
图片预测结果:[1.6777943e-08 9.9940062e-01 4.7675867e-04 6.7097149e-05 1.7910816e-05
 2.5193499e-06 1.3442985e-07 2.5095436e-05 6.0522575e-06 3.8941007e-06]
图片预测结果:[1.2141053e-10 9.4990736e-01 5.0068785e-02 1.2220319e-05 8.9143998e-07
 1.6966968e-08 4.1489009e-10 1.0333614e-05 4.0532541e-07 2.9848351e-08]
图片预测结果:[2.0645930e-15 6.0836253e-11 4.5220752e-09 9.9999952e-01 1.5850897e-12
 4.1950503e-07 5.2519745e-13 5.0554507e-09 1.3183955e-09 4.9834348e-10]
图片预测结果:[3.06091952e-09 4.69441694e-08 3.69757231e-07 7.11042249e-12
 9.99998927e-01 2.96041969e-09 6.11938503e-07 1.08300666e-08
 1.07891085e-10 4.60915395e-08]
图片预测结果:[9.5183388e-13 1.4112284e-09 1.8609682e-12 3.9296650e-05 1.0219015e-08
 9.9995780e-01 9.4438901e-09 1.0756977e-07 1.0569416e-08 2.7594053e-06]
图片预测结果:[1.4176695e-06 1.6748903e-05 9.2335415e-07 2.7700067e-09 1.5665944e-04
 5.3242047e-04 9.9929094e-01 2.3881627e-10 8.0925338e-07 2.5435987e-09]
图片预测结果:[1.1376241e-11 6.6254070e-05 4.7511628e-04 4.2667158e-05 2.0856714e-09
 2.3252527e-09 2.2043253e-12 9.9941587e-01 4.1451024e-08 2.8455176e-08]
图片预测结果:[7.6020033e-13 1.8679576e-09 8.3119521e-06 2.4773360e-07 4.6920401e-10
 9.8522442e-08 5.2838236e-09 1.0951308e-09 9.9999130e-01 8.2217406e-11]
图片预测结果:[7.8212171e-13 5.7768826e-08 1.3405849e-08 1.3201839e-06 5.0993433e-04
 1.0229867e-05 2.1776499e-11 4.9842776e-05 1.5813828e-03 9.9784720e-01]

4.模型训练过程遇到的问题

(1)找不到URL路径无法加载mnist数据集

URL fetch failure on https://storage.googleapis.com/tensorflow/tf-keras-datasets/mnist.npz: None – unknown url type: https
解决方法
浏览器直接访问链接下载mnist.npz并将下载好的文件存放在以下目录

 C:\Users\……\.keras\datasets

注:……处填你的用户名

(2)Sequential没有predict_classes属性

AttributeError: ‘Sequential’ object has no attribute ‘predict_classes’

解决方法

'predict_classes'改为 'predict'

因为Sequential虽然没有predict_classes属性,但是有predict属性。

(3)没有skimage模块

No module named ‘skimage‘
解决方法
命令行中使用pip install scikit-image命令安装模块,
如果你直接使用命令pip install skimage是不行的。

pip install scikit-image

你可能感兴趣的:(图像识别,学习中遇到的问题,LeNet5手写体识别,python,深度学习)