关于LeNet5结构,前面已经专门写过一篇文章做了详细分析,如果有小伙伴不太清楚具体结构或想要加深一下对LeNet5结构的理解,可参见https://blog.csdn.net/fencecat/article/details/123529738
这里就不再赘述了,直接上代码!!!
#!/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]))#将预测结果打印出来
在训练模型之前,需要通过compile来对学习过程进行配置。compile接收三个参数:
我们的测试图片就是十张写有0~9十个数字的图片
根据运行结果我们可以看出模型预测的结果,它是用概率来表示所属类别的可能性的。输出结果是一个含有10个元素的列表,每个元素一次对应分类结果是0~9的概率,概率最大的就是分类的结果。以图片0为例,输出的列表中第一个值最大为9.9996674e-01,即表明预测的分类结果为手写体“0”。
可以看出10张图片都识别对了,模型的损失为: 0.032327234745025635,
模型的准确率 为0.9890999794006348。
#模型预测结果
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]
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
注:……处填你的用户名
AttributeError: ‘Sequential’ object has no attribute ‘predict_classes’
解决方法:
将 'predict_classes'改为 'predict'
因为Sequential虽然没有predict_classes属性,但是有predict属性。
No module named ‘skimage‘
解决方法:
命令行中使用pip install scikit-image命令安装模块,
如果你直接使用命令pip install skimage是不行的。
pip install scikit-image