MNIST是一个手写数字的数据集(包含数字0-9),它包含60000个训练数据和10000个测试数据。这些数字已经经过尺寸标准化并位于图像中心,图像像素固定为28x28,每个像素值为0到255,每张图片有一个通道数。
keras
内置了mnist数据集我们第一次导入会进行下载
from keras.datasets import mnist
(x_train, y_train), (x_test, y_test) = mnist.load_data()
print(len(y_train))
print(y_train)
print(len(y_test))
60000
[5 0 4 ... 5 6 8]
10000
对标签进行独热编码
from keras.utils.np_utils import to_categorical
y_test = to_categorical(y_test)
y_train = to_categorical(y_train)
查看一张图片
import matplotlib.pyplot as plt
%matplotlib inline
plt.imshow(x_train[255])
由于下面我们训练使用的是fit_generator,它和fit的区别是,fit是将全部的数据直接加载到内存中,而fit_generator会一边训练一边生成数据,节省了内存,fit_generator传入的是一个生成器。
为了让大家理解到生成器对内存的节约,下面用一个小例子来作说明
import sys
#a是一个生成器
a = (i for i in range(10000))
#b是一个列表
b = [i for i in range(10000)]
print("a的类型为:",type(a))
print("b的类型为:",type(b))
print("a所占内存大小为:",sys.getsizeof(a))
print("b所占内存大小为:",sys.getsizeof(b))
print("=============")
print("a取出一个元素",next(a))
print("现在a所占内存的大小为:",sys.getsizeof(a))
执行结果如下:
a的类型为: <class 'generator'>
b的类型为: <class 'list'>
a所占内存大小为: 128
b所占内存大小为: 87632
=============
a取出一个元素 0
现在a所占内存的大小为: 128
可以看到生成器比列表节省了大量的内存,我们需要元素时只需要next()
取出即可,取出元素后生成器所占的内存不变。
keras
提供了用于fit_generator的类模板,我们需要重写一下
from keras.utils import Sequence
import math
class Generator(Sequence):
def __init__(self, x, y, b_size):
self.x, self.y = x, y
self.batch_size = b_size
def __len__(self):
return math.ceil(len(self.y)/self.batch_size)
def __getitem__(self, idx):
batch_x = self.x[idx * self.batch_size:(idx + 1) *
self.batch_size]
batch_y = self.y[idx * self.batch_size:(idx + 1) *
self.batch_size]
batch_x = batch_x/255.0
batch_x = batch_x.reshape(*batch_x.shape,1)
return batch_x,batch_y
def on_epoch_end(self):
pass
以RGB图片为例,一张图片有三个通道,分别是R(red),G(green),B(blue),我们的每一个卷积核都会对三个通道进行运算,每一个通道的运算如下图所示(下图为3×3卷积核)
每一个卷积核对三个通道进行运算后得到了三张3×3的图片,然后再把对应位置相加得到了一张3×3的图片,如下图所示
输出的通道数等于卷积核的个数。
二维卷积能够捕获到图片的局部特征,并且这种捕获不受局部特征在图片上位置的影响。通过这些特征可以让神经网络进行分类和识别从而达到一个较高的精度。
from keras.models import Sequential
from keras.losses import CategoricalCrossentropy
from keras import layers
import numpy as np
model = Sequential([
layers.Conv2D(64,(3,3),padding='same',activation='relu',input_shape=(28,28,1)),
layers.MaxPool2D(2,2),
layers.Conv2D(128,(3,3),padding='same',activation='relu'),
layers.MaxPool2D(2,2),
layers.Conv2D(64,(3,3),activation='relu'),
layers.Conv2D(32,(3,3),padding='same',activation='relu'),
layers.Flatten(),
layers.Dense(10,activation='softmax'),
])
model.compile(loss=CategoricalCrossentropy(),optimizer="adam",metrics=["acc"])
model.summary()
from keras.callbacks import EarlyStopping,ModelCheckpoint
callbacks_list = [
EarlyStopping(
monitor = 'val_acc', #监控验证精度
patience = 2, #如果精度多于两轮不改善则中断训练
),
ModelCheckpoint(
filepath = 'my_model_conv2d.h5', #模型保存路径
monitor = 'val_acc', #
save_best_only = True, #如果val_loss没有改善则不需要覆盖模型
)
]
history = model.fit_generator(Generator(x_train,y_train,200),epochs=5,validation_data=Generator(x_test,y_test,200),callbacks=callbacks_list)
训练结果:
Epoch 1/5
300/300 [==============================] - 264s 880ms/step - loss: 0.2648 - acc: 0.9221 - val_loss: 0.0755 - val_acc: 0.9825
Epoch 2/5
300/300 [==============================] - 257s 857ms/step - loss: 0.0561 - acc: 0.9825 - val_loss: 0.0232 - val_acc: 0.9878
Epoch 3/5
300/300 [==============================] - 260s 867ms/step - loss: 0.0399 - acc: 0.9874 - val_loss: 0.0226 - val_acc: 0.9909
Epoch 4/5
300/300 [==============================] - 257s 856ms/step - loss: 0.0284 - acc: 0.9914 - val_loss: 0.0101 - val_acc: 0.9901
Epoch 5/5
300/300 [==============================] - 262s 874ms/step - loss: 0.0244 - acc: 0.9920 - val_loss: 0.0202 - val_acc: 0.9909
很快验证精度便达到了0.99,可以看到模型的效果还是很不错的,神经网络对于手写数字的识别率还是蛮高的。
今天的分享就到这里了,希望大家能够有所收获,欢迎关注,一起进步~