【参考视频网址:】https://space.bilibili.com/45151802/video
(老师讲的特别好,良心推荐)
【mnist数据集下载:】https://download.csdn.net/download/weixin_41874898/11434107
【github代码下载:】https://github.com/Seasea77/keras_small_project_19_07_26
文章目录
1. 实现功能:使用keras实现全连接神经网络手写数字的识别
2. 准备工作
2.1文章目录
2.2 BatchNormalization
BN的基本思想其实相当直观:因为深层神经网络在做非线性变换前的激活输入值(就是那个x=WU+B,U是输入)随着网络深度加深或者在训练过程中,其分布逐渐发生偏移或者变动,之所以训练收敛慢,一般是整体分布逐渐往非线性函数的取值区间的上下限两端靠近(对于Sigmoid函数来说,意味着激活输入值WU+B是大的负值或正值),所以这导致反向传播时低层神经网络的梯度消失,这是训练深层神经网络收敛越来越慢的本质原因,而BN就是通过一定的规范化手段,把每层神经网络任意神经元这个输入值的分布强行拉回到均值为0方差为1的标准正态分布,其实就是把越来越偏的分布强制拉回比较标准的分布,这样使得激活输入值落在非线性函数对输入比较敏感的区域,这样输入的小变化就会导致损失函数较大的变化,意思是这样让梯度变大,避免梯度消失问题产生,而且梯度变大意味着学习收敛速度快,能大大加快训练速度。
THAT’S
IT。其实一句话就是:对于每个隐层神经元,把逐渐向非线性函数映射后,向取值区间极限饱和区靠拢的输入分布强制拉回到均值为0方差为1的比较标准的正态分布,使得非线性变换函数的输入值落入对输入比较敏感的区域,以此避免梯度消失问题。因为梯度一直都能保持比较大的状态,所以很明显对神经网络的参数调整效率比较高,就是变动大,就是说向损失函数最优值迈动的步子大,也就是说收敛地快。BN说到底就是这么个机制,方法很简单,道理很深刻。
3. keras_mnist_fc.py
3.1 代码如下
# coding:utf-8
from keras.datasets import mnist
from keras.utils import np_utils
from keras.models import Sequential, Model
from keras.layers.core import Dense, Activation, Dropout
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimage
from PIL import Image
"""1设置基本参数"""
batch_size = 1024 # 一次训练需要给神经网络注入多少个数据,即神经网络跑一次,能跑1024个数据。这个值取的太大效果不好
num_class = 10 # 训练分类的个数
num_epochs = 2 # 训练的次数(所有60000个数据用一次叫做1个epoch)
"""2加载原始数据"""
(X_train, Y_train), (X_test, Y_test) = mnist.load_data() # 加载进来的二值图就是矩阵
# (1)mnist数据集的加载
# ——问题:
# # 使用(X_train, Y_train), (X_test, Y_test) = mnist.load_data()下载失败,所以无法加载成功。
# ——解决:
# # 加载失败会提示下载地址,通过下载,通过翻墙,下载速度很快。
# # 在执行上述指令时,mnist.load_data(),会在home(C:/Users/61052)目下的.keras目录下生成datasets文件夹,
# 因为下载失败,所以文件夹为空。
# # cmd打开终端,在home目录下,cd .keras、cd datasets、start .(打开当前文件夹),执行将下载好的mnist
# 数据集放入到文件夹再运行就不会报错。
#
# # X_train.shape=(60000, 28, 28)
# Y_train.shape=(60000,)
# X_test.shape=(10000, 28, 28)
# Y_test.shape=(10000,)
# # 加载进来的二值图就是矩阵
"""3处理数据集,归一化"""
X_train = X_train.reshape(60000, 784)
X_test = X_test.reshape(10000, 784)
# 转换成小数,进行归一化(相当于是BN)
# X_train = X_train.astype("float32")
X_train = X_train / 255. # 255加小数点;print(X_train[9999]) #打印其中任意一行,看一下
# 将整型标签转为onehot
Y_train = np_utils.to_categorical(Y_train, num_class) # Y_train必须为数组
Y_test = np_utils.to_categorical(Y_test, num_class) # 可以print(Y_test[99])看其中一个标签的形式
"""4设置网络结构"""
model = Sequential() # 开始keras的序列模型
# 第一层
model.add(Dense(512, input_shape=(784,)))
# 只用写一张图片的形状就行,784既可以表示行又可以表示列,此处表示一行
# 第一层必须告诉系统你的输入是多少,默认1行784列,输入是(*,784),输出是(*,512)
# (784, )逗号不能少,(784,1)或者写成这样
model.add(Activation("relu"))
model.add(Dropout(0.2)) # 随机失活一部分
# 第二层
model.add(Dense(256))
model.add(Activation("relu"))
model.add(Dropout(0.2))
# 第三层
model.add(Dense(10))
model.add(Activation("softmax")) # softmax针对10个进行分类
"""5编译"""
# 用什么函数来处理
model.compile(
loss="categorical_crossentropy", # 损失函数
optimizer="rmsprop", # 优化函数,SGD、adam不同优化函数不同的路径向最优点推进,adam最新
metrics=["accuracy"] # 达到的目标
)
# model.save("./mine.h5") # 模型的保存
"""6启动网络--训练网络"""
Trainning = model.fit(
X_train, Y_train,
batch_size=batch_size,
epochs=num_epochs,
validation_data=(X_test, Y_test), # 可加可不加,输出多一条数据
# - 3s - loss: 0.5421 - acc: 0.8313 - val_loss: 1.2277 - val_acc: 0.9230
verbose=2
# 默认为1,输出显示进度条,显示每个Epoch
# 2,输出不显示进度条,显示每个Epoch
# 0,输出什么都不显示
)
"""7把Training实例化"""
print("_________________________________________________________________")
print(Trainning.history) #
print(Trainning.params) # 网络的设置
"""8测试test数据"""
testpic = X_test[9998].reshape(1, 784)
testlabel = np.argmax(Y_test[9998])
testpic = testpic.reshape(28, 28)
print("标签结果:", testlabel)
plt.imshow(testpic)
plt.show()
# 模型预测结果
testpic = testpic.reshape(1, 784)
pred = model.predict(testpic)
print("预测结果:", np.argmax(pred))
"""9测试自己的照片"""
# # 方法1:变成灰度图
# def rgb2gray(rgb):
# return np.dot(rgb[..., :3], [0.299, 0.587, 0.144])
# mine_img = mpimage.imread("./test.jpg")
# mine_img_L = rgb2gray(mine_img)
# print(mine_img_L.shape)
# 方法2:变成灰度图
mine_img = Image.open("./test.png") # open和imread的区别
mine_img_L = mine_img.convert("L")
mine_img_L = mine_img_L.resize((28, 28), Image.ANTIALIAS) # 调整图片大小为(28, 28)
mine_img_L = np.array(mine_img_L) # mine_img_L的shape为(28, 28)
# np.savetxt('4.csv', mine_img_L, delimiter=',') # 把矩阵存放到csv文件里面
plt.imshow(mine_img_L) # mine_img_L.show(),使用电脑自带的照片显示软件。plt.imshow(mine_img_L),使用plt来显示图片。
plt.show()
print(mine_img_L.shape)
# 模型预测结果
mine_img_L = mine_img_L.reshape(1, 784)
mine_img_L = mine_img_L / 255.
pred = model.predict(mine_img_L)
print(np.argmax(pred)) # 预测不准和背景色有关,与训练模板背景色相同
3.2 思路总结
- 数据集加载及处理
- 此处用的是mnist数据集,使用mnist.load_data()获取数据集,(X_train, Y_train), (X_test, Y_test) = mnist.load_data() ,加载进来的二值图就是矩阵
- 数据集最后为两类:X_train,Y_train(X_test,Y_test),其中X_train为(-1, 784)且除以255.归一化矩阵,Y_train(-1,10)为one-hot类型矩阵
网络结构设置
model = Sequential()
model.add()
网络编译
model.compile(loss, optimizer, metrics=[“accuracy”])
网络训练
Trainning = model.fit()
测试自己的照片
3.3 问题解决
mnist.load_data()下载失败**
(1)在执行该指令时,mnist.load_data(),会在home(C:/Users/61052)目下的.keras目录下生成datasets文件夹,因为下载失败,所以文件夹为空。
(2)加载失败会提示下载地址,通过下载,通过翻墙,下载速度很快。
(3)cmd打开终端,在home目录下,cd .keras、cd datasets、start .(打开当前文件夹),执行将下载好的mnist;数据集放入到文件夹再运行就不会报错。
4. test.png(灰度图)文件生成
(1)打开ps,操作三步骤如下:
(测试图片大小不用28*28也可以,代码中会统一)
(2)ALT+鼠标滚轮调整新建图片大小;选中画笔,切换成英文输入法,中括号调节画笔大小; Ctrl+Alt+z撤销操作(此步可能需要退出下qq,要不老是跳出qq);使用快捷键Ctrl+Shift+Alt+w保存图片,保存格式为png,test.png
5. 测试结果
(1)test.png测试图
(2)测试结果为: