Keras快速上手 ——学习笔记(二)利用VGG16网络进行字体识别

利用VGG16网络进行字体识别

接下来使用迁移学习的思想,以VGG16作为模板搭建模型,训练识别手写字体。
VGG16模型是基于K.Simonyan和A.Zisserman写的Very Deep Convolutional Networks for Large-Scale Image Recognition,arXiv:1409.1556。

1、导入数据

from keras.applications.vgg16 import VGG16  # VGG16模型
from keras.layers import Input, Flatten, Dense, Dropout  # 搭建卷积神经网络需要的模块,分别为全展开方法,输出层方法,随机失活方法
from keras.models import Model  加载模型类
from keras.optimizers import SGD  # 加载SGD优化函数
from keras.datasets import mnist  # 加载数据集
import cv2  # 加载opencv,用于后期对图像的处理,比如尺寸变换和Channel变换。这些变换是为了使图像满足VGG16所需要的输入格式。
import h5py as h5py  # 数据储存和导出类
import numpy as np  # 必要的东西!

2、创建迁移网络

1、创建不包含权重的VGG_16迁移网络

model_vgg = VGG16(include_top=False, weights='imagenet', input_shape=(224, 224, 3))
model = Flatten(name = 'flatten')(model_vgg.output)
model = Dense(10, activation = "softmax")(model)
model_vgg_mnist = Model(model_vgg.input, model, name='vgg16')

VGG_16()中,include_top=False表示去除VGG16顶层(输出层),weights=’imagenet’表示使用图片网络的权重,input_shape=(224, 224, 3)表示输入的图片维度为224x224,图层为3(RBG)
model = Flatten(name = ‘flatten’)(model_vgg.output)表示在model_vgg模型的输出层再加上一层flatten(全展开)层,并把这层命名为flatten,把合起来的模型返回给model
model = Dense(10, activation = “softmax”)(model)表示在model上再加一层输出层,分类数为10个,激活函数使用softmax
model_vgg_mnist = Model(model_vgg.input, model, name=’vgg16’)表示创建一个新的模型,命名为vgg16,在keras的开发文档中查到Model(input=X, output=Y)
推测是以model_vgg的input层作为输入层,model作为输出层来构建新的网络

在这里可以看到,所有1496万个网络权重(VGG16网络权重加上我们搭建的权重)都需要训练,这是因为我们迁移了网络结构,但是没有迁移VGG16网络权重。迁移网络权重的好处在于网络权重不用重新训练,只需要训练最上层搭建的部分就行了。坏处是,新的数据不一定适用已训练好的权重,因为已训练好的权重是基于其他数据训练的,数据分布和我们关心的问题可能完全不一样。这里虽然引进了VGG在ImageNet中的结构,但是具体模型仍需要在VGG16的框架上加工。
另外,本地机器很有可能不能把整个模型和数据放入内存进行训练,出现Kill:9的内存不够的错误。如果想要训练,则建议用较少样本,或者把样本批量减小至比如32。有条件的话可以用AWS里的EC2 GPU Instance g2.2xlarge/g2.8xlarge进行训练。
作为对比,我们建立另外一个模型,这个模型的特点是把VGG16网络的结构和权重同时迁移。这里的关键点是把不需要重新训练的权重“冷冻”起来。这里使用trainable=false这个选项。注意,这里我们定义输入的维度为(224,224,3),因此需要较大的内存,除非读者使用数据生成器迭代对象。如果内存较小,那么可以将维度降为(112,112,3),这样在32GB内存的机器上也能顺利运行。
2、创建包含权重的迁移网络

ishape=224
model_vgg = VGG16(include_top=False, weights='imagenet', input_shape=(ishape, ishape, 3))
for layer in model_vgg.layers:
    layer.trainable = False
model = Flatten()(model_vgg.output)
model = Dense(10, activation="softmax")(model)
model_vgg_mnist_pretrain = Model(model_vgg.input, model, name='vgg_16_pretrain')
model_vgg_mnist_pretrain.summary()

运行结果如下:

·····
block5_conv2 (Conv2D)        (None, 14, 14, 512)       2359808   
_________________________________________________________________
block5_conv3 (Conv2D)        (None, 14, 14, 512)       2359808   
_________________________________________________________________
block5_pool (MaxPooling2D)   (None, 7, 7, 512)         0         
_________________________________________________________________
flatten_1 (Flatten)          (None, 25088)             0         
_________________________________________________________________
dense_2 (Dense)              (None, 10)                250890    
=================================================================
Total params: 14,965,578
Trainable params: 250,890
Non-trainable params: 14,714,688
_________________________________________________________________

我们只需要训练25万个参数,比之前整整少了60倍!

3、构建神经网络

(1)输入损失函数

sgd = SGD(lr = 0.05, decay = 1e-5)
model_vgg_mnist_pretrain.compile(loss='categorical_crossentropy', optimizer=sgd, metrics = ['accuracy'])

(2)数据预处理
因为VGG16网络对输入层的要求,我们用OpenCV把图像从32×32变成224×224(cv2.resize的命令),把黑白图像转换为RGB图像(cv2.COLOR_GRAY2BGR),并且把训练数据转化成张量形式,供Keras输入。

(X_train, Y_train), (X_test, Y_test) = mnist.load_data()
X_train = [cv2.cvtColor(cv2.resize(i, (ishape, ishape)), cv2.COLOR_GRAY2BGR) for i in X_train[:20000]]
X_train = np.concatenate([arr[np.newaxis] for arr in X_train]).astype("float32")

X_test = [cv2.cvtColor(cv2.resize(i, (ishape, ishape)), cv2.COLOR_GRAY2BGR) for i in X_test[:2000]]
X_test = np.concatenate([arr[np.newaxis] for arr in X_test]).astype("float32")

print("训练集的张量是",X_train.shape)
print("测试集的张量是",X_test.shape)

训练集原本有6w,但是因为笔者内存不足将测试集数量修改为10000,测试集数据量修改为1000

X_train /= 255
X_test /= 255
np.where(X_train[0] != 0)

def tran_y(y):
    y_ohe = np.zeros(10)
    y_ohe[y] = 1
    return y_ohe

Y_train_ohe = np.array([tran_y(Y_train[i]) for i in range(len(Y_train[:20000]))])
Y_test_ohe = np.array([tran_y(Y_test[i]) for i in range(len(Y_test[:2000]))])

运行模型

model_vgg_mnist_pretrain.fit(X_train, Y_train_ohe, validation_data = (X_test, Y_test_ohe), epochs = 200, batch_size = 128

笔者内存不足!等我以后再来补充!

你可能感兴趣的:(keras学习)