项目05:CIFAR-10图像识别

CIFAR-10是由Alex Krizhevsky、Vinod Nair与Geoffreff Hinton收集的一个用于图像识别的数据集。共有10个分类:飞机、汽车、鸟、猫、鹿、狗、青蛙、马、船、卡车。与之前MNIST数据集相比,它的色彩和颜色噪点会比较多,其中分类如卡车,大小不一,角度不同,颜色不同。所以识别难度是要比之前的MNIST和Fashion MNIST大很多。

1. 准备工作

在指定的磁盘路径创建存放当前项目的目录,linux或macos可使用mkdir命令创建文件夹目录,Windows直接使用图形化界面右键新建文件夹即可,例如我们的存放项目的目录名为project05:

    (dlwork) jingyudeMacBook-Pro:~ jingyuyan$ mkdir project05

我们将之前几个项目所用到的一些函数进行收集,统一编写成simple_utils.py文件下,这样可在接下去的实验中更加方便的去调用,既节省时间也使代码更加简洁。将simple_utils.py和中文字体文件fz.ttf放入到project05当中。

# 这是simple_utils.py文件内从函数,导入即可
# %load simple_utils.py
import numpy as np
import matplotlib.pyplot as plt
from keras.models import Model
from matplotlib.font_manager import FontProperties

# 显示训练过程的函数
def show_train_history(train_history,train,validation):
    plt.plot(train_history.history[train])
    plt.plot(train_history.history[validation])
    plt.title('Train histoty')
    plt.ylabel(train)
    plt.xlabel('Epoch')
    plt.legend(['train','validation',],loc = 'upper left')
    plt.show()

# 获取某一层中预测的结果函数
def get_layer_output(model, layer_name, data_set):
    try:
        out = model.get_layer(layer_name).output
    except:
        raise Exception('Error layer named {}!'.format(layer_name))

    conv1_layer = Model(inputs=model.inputs, outputs=out)
    res = conv1_layer.predict(data_set)
    return res


# 中文字体可以选择下载或从本书提供云盘下载放置项目目录中
font_zh = FontProperties(fname='./fz.ttf')
# 可输出图片和标签的函数
def show_image(images, labels, idx, alias=[]):
    fig = plt.gcf()
    plt.imshow(images[idx], cmap='binary')
    if alias:
        plt.xlabel(str(CLASSES_NAME[labels[idx]]), fontproperties = font_zh, fontsize = 15)
    else:
        plt.xlabel('label:'+str(labels[idx]), fontsize = 15)
    plt.show()

# 可输多个图片和数字的函数
def show_images_set(images,labels,prediction,idx,num=15, alias=[]):
    fig = plt.gcf()
    fig.set_size_inches(14, 14)
    for i in range(0,num):
        color = 'black'
        tag = ''
        ax = plt.subplot(5,5,1+i)
        ax.imshow(images[idx],cmap='binary')
        if len(alias)>0:
            title = str(alias[labels[idx]])
        else:
            title = "label:"+str(labels[idx])
        if len(prediction)>0:
            if prediction[idx] != labels[idx]:
                color = 'red'
                tag = '×'
            if alias:
                title +="("+str(alias[prediction[idx]])+")" + tag
            else:
                title +=",predict="+str(prediction[idx])
        ax.set_title(title, fontproperties = font_zh, fontsize = 13, color=color)
        ax.set_xticks([])
        ax.set_yticks([])
        idx+=1
    plt.show()

    def show_images_set_cifar(images,labels,prediction,idx,num=15, alias=[]):
    fig = plt.gcf()
    fig.set_size_inches(14, 14)
    for i in range(0,num):
        color = 'black'
        tag = ''
        ax = plt.subplot(5,5,1+i)
        ax.imshow(images[idx],cmap='binary')
        if len(alias)>0:
            title = str(alias[labels[idx][0]])
        else:
            title = "label:"+str(labels[idx][0])
        if len(prediction)>0:
            if prediction[idx] != labels[idx][0]:
                color = 'red'
                tag = '×'
            if alias:
                title +="("+str(alias[prediction[idx]])+")" + tag
            else:
                title +=",predict="+str(prediction[idx])
        ax.set_title(title, fontproperties = font_zh, fontsize = 13, color=color)
        ax.set_xticks([])
        ax.set_yticks([])
        idx+=1
    plt.show()
  File "<ipython-input-2-7e0efde43ee8>", line 69
    fig = plt.gcf()
      ^
IndentationError: expected an indented block

进入到project04后开始我们的实验吧

    cd project01
    jupyter notebook

2. CIFAR-10数据集下载与分析

CIFAR-10共有10个分类:飞机、汽车、鸟、猫、鹿、狗、青蛙、马、船、卡车。数据集中有60000个32×32的彩色图像,分别划分为50000个训练图像和10000个测试图像。

label分别是0~9的十个数字分别对应着各个分类

标签 0 1 2 3 4 5 6 7 8 9
分类 飞机 汽车 鹿 青蛙 卡车

我们可以登录官网查看CIFAR-10图像的说明。http://www.cs.toronto.edu/~kriz/cifar.html

cifar-10.png

2.1 CIFAR-10数据的下载

2.1.1 使用Keras自动下载

可以从上面的图中发现CIFAR-10的官网是提供数据的下载的,这里我们使用的keras的databasets可以直接导入,如果是第一次使用keras会自动为我们下载好数据集,所以不需要手动下载。

from keras.datasets import cifar10
import numpy as np

# 这里如果是第一次使用。需要下载一段时间
(x_img_train,y_label_train),(x_img_test,y_label_test) = cifar10.load_data()
Using TensorFlow backend.

2.1.2 手动下载

如果下载失败或者下载速度比较缓慢的,本书有提供其他下载的方式(详情见附录),下载的文件名为cifar-10-batches-py.tar.gz或cifar-10-batches-py.tar。

  • Windows放置数据集:

在Windows环境下,将cifar-10-batches-py.tar.gz文件放置C:\Users\xxxx.keras\datasets目录下即可

  • Linux或MacOS放置数据集:

在Linux或MacOS环境下,将cifar-10-batches-py.tar.gz文件放置 ~/Users/xxxx/.keras/目录下即可

注:xxxx是当前用户名

2.2 查看训练数据

CIFAR-10和MNIST相同的是,数据集同样是由images和label组成的10个分类。CIFAR-10共有60000项数据,分别划分为训练集50000和测试集10000。

from keras.datasets import cifar10
import numpy as np
(x_img_train,y_label_train),(x_img_test,y_label_test) = cifar10.load_data()
print('train:',len(x_img_train))
print('test:',len(x_img_test))
train: 50000
test: 10000

查看数据的维度

x_img_train.shape
(50000, 32, 32, 3)

可以看到这次所使用的CIFAR-10数据集中的图像是32 × 32 × 3的图像。3代表的是3通道的RGB彩色图像。

从当前目录下导入simple_utils.py模块中的函数,使用show_images_set函数查看训练集图像。

from simple_utils import *

# 分别定义中英文的标签字典,主要是用于方便查看当前标签属性
classes_name={
0:"airplane", 1:"automobile", 2:"bird", 3:"cat", 4:"deer", 5:"dog", 6:"frog", 7:"horse", 8:"ship", 9:"truck"
}
classes_name_ch={
0:"飞机", 1:"汽车", 2:"鸟", 3:"猫", 4:"鹿", 5:"狗", 6:"青蛙", 7:"马", 8:"船", 9:"卡车"
}
show_images_set_cifar(images=x_img_train, labels=y_label_train, prediction=[], idx=0, alias=classes_name_ch)
<Figure size 1400x1400 with 15 Axes>

3. 处理数据集与训练模型

3.1 处理数据集

我们需要对数据集进行处理才能开始训练。

(x_img_train,y_label_train),(x_img_test,y_label_test) = cifar10.load_data()
# 查看第一个图像的第一个点的像素组合
x_img_train[0][0][0]
array([59, 62, 63], dtype=uint8)

可以看到片[59, 62, 63]三个点分别代表着[R-G-B]颜色的组合。为了提高模型的精确度,我们将数据进行标准化。

# 将数据集进行数字标准化
x_img_train_normalize = x_img_train.astype('float32') / 255.0
x_img_test_normalize = x_img_test.astype('float32') / 255.0
# 查看处理后的第一个点的像素组合
x_img_train_normalize[0][0][0]
array([0.23137255, 0.24313726, 0.24705882], dtype=float32)

接下来需要处理label的数据。

# 查看前4项label
y_label_train[:4]
array([[6],
       [9],
       [9],
       [4]], dtype=uint8)
# 使用One-HotEncoding编码来处理label数据
from keras.utils import np_utils
y_label_train_OneHot = np_utils.to_categorical(y_label_train)
y_label_test_OneHot = np_utils.to_categorical(y_label_test)
# 查看处理完后的OneHot编码
y_label_train_OneHot[:4]
array([[0., 0., 0., 0., 0., 0., 1., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 1.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 1.],
       [0., 0., 0., 0., 1., 0., 0., 0., 0., 0.]], dtype=float32)

3.2 模型的搭建

开始建立模型,CIFAR-10数据集的识别会比MNIST难度更高很多,所以我们直接采用更多的卷积层来提高识别的准确率。

from keras.models import Sequential
from keras.layers import Dense,Dropout,Activation,Flatten
from keras.layers import Conv2D,MaxPool2D,ZeroPadding2D

# 设置模型参数和训练参数
# 分类的类别
CLASSES_NB = 10
# 模型输入层数量
INPUT_SHAPE = (32, 32, 3)
# 验证集划分比例
VALIDATION_SPLIT = 0.2
# 训练周期,这边设置10个周期即可
EPOCH = 10
# 单批次数据量
BATCH_SIZE = 128
# 训练LOG打印形式
VERBOSE = 1
# 损失函数
LOSS = 'categorical_crossentropy'
# 优化函数
OPTIMIZER = 'adam'
# 训练指标
METRICS = ['accuracy']
model = Sequential()

# 建立卷积层
model.add(Conv2D(filters=32, kernel_size=(3,3),
         input_shape=INPUT_SHAPE,
         padding='same'))
model.add(Activation('relu'))
model.add(Dropout(rate=0.25))
model.add(MaxPool2D(pool_size=(2,2)))

# 建立卷积层
model.add(Conv2D(filters=64, kernel_size=(3,3), padding='same'))
model.add(Activation('relu'))
model.add(Dropout(rate=0.25))
model.add(MaxPool2D(pool_size=(2,2)))

# 建立平坦层
model.add(Flatten())
model.add(Dropout(rate=0.25))

# 建立隐藏层,共1024个神经元
model.add(Dense(1024))
model.add(Dropout(rate=0.25))

# 建立输出层
model.add(Dense(CLASSES_NB))
model.add(Activation('softmax'))

# 查看摘要
print(model.summary())
WARNING: Logging before flag parsing goes to stderr.
W0115 00:57:27.912718 4579980736 deprecation_wrapper.py:119] From /Users/jingyuyan/anaconda3/envs/dlwork/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py:4070: The name tf.nn.max_pool is deprecated. Please use tf.nn.max_pool2d instead.



Model: "sequential_1"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_1 (Conv2D)            (None, 32, 32, 32)        896       
_________________________________________________________________
activation_1 (Activation)    (None, 32, 32, 32)        0         
_________________________________________________________________
dropout_1 (Dropout)          (None, 32, 32, 32)        0         
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 16, 16, 32)        0         
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 16, 16, 64)        18496     
_________________________________________________________________
activation_2 (Activation)    (None, 16, 16, 64)        0         
_________________________________________________________________
dropout_2 (Dropout)          (None, 16, 16, 64)        0         
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 8, 8, 64)          0         
_________________________________________________________________
flatten_1 (Flatten)          (None, 4096)              0         
_________________________________________________________________
dropout_3 (Dropout)          (None, 4096)              0         
_________________________________________________________________
dense_1 (Dense)              (None, 1024)              4195328   
_________________________________________________________________
dropout_4 (Dropout)          (None, 1024)              0         
_________________________________________________________________
dense_2 (Dense)              (None, 10)                10250     
_________________________________________________________________
activation_3 (Activation)    (None, 10)                0         
=================================================================
Total params: 4,224,970
Trainable params: 4,224,970
Non-trainable params: 0
_________________________________________________________________
None

搭建好的模型结构如下

1

3.3 模型的训练

利用上述定义好的模型以及训练参数,定义训练方式,并且传入数据利用反向传播算法开始训练模型。

# 定义训练方式
model.compile(loss=LOSS, optimizer=OPTIMIZER, metrics=METRICS)
# 开始训练
train_history = model.fit(x_img_train_normalize, 
                          y_label_train_OneHot, 
                          validation_split=VALIDATION_SPLIT, 
                          epochs=EPOCH, 
                          batch_size=BATCH_SIZE, 
                          verbose=VERBOSE)
Train on 40000 samples, validate on 10000 samples
Epoch 1/10
40000/40000 [==============================] - 102s 3ms/step - loss: 1.6239 - acc: 0.4218 - val_loss: 1.3960 - val_acc: 0.5494
Epoch 2/10
40000/40000 [==============================] - 101s 3ms/step - loss: 1.2571 - acc: 0.5518 - val_loss: 1.2493 - val_acc: 0.5804
Epoch 3/10
40000/40000 [==============================] - 100s 3ms/step - loss: 1.1369 - acc: 0.6015 - val_loss: 1.1856 - val_acc: 0.6236
Epoch 4/10
40000/40000 [==============================] - 104s 3ms/step - loss: 1.0627 - acc: 0.6283 - val_loss: 1.1186 - val_acc: 0.6316
Epoch 5/10
40000/40000 [==============================] - 107s 3ms/step - loss: 1.0122 - acc: 0.6439 - val_loss: 1.0450 - val_acc: 0.6572
Epoch 6/10
40000/40000 [==============================] - 117s 3ms/step - loss: 0.9665 - acc: 0.6619 - val_loss: 0.9852 - val_acc: 0.6778
Epoch 7/10
40000/40000 [==============================] - 125s 3ms/step - loss: 0.9319 - acc: 0.6750 - val_loss: 0.9740 - val_acc: 0.6650
Epoch 8/10
40000/40000 [==============================] - 116s 3ms/step - loss: 0.8947 - acc: 0.6906 - val_loss: 1.0128 - val_acc: 0.6569
Epoch 9/10
40000/40000 [==============================] - 102s 3ms/step - loss: 0.8777 - acc: 0.6935 - val_loss: 1.0472 - val_acc: 0.6377
Epoch 10/10
40000/40000 [==============================] - 101s 3ms/step - loss: 0.8509 - acc: 0.7028 - val_loss: 0.9522 - val_acc: 0.6786

训练时间会比较长,因为到目前为止所有实验均采用CPU进行训练,诺有条件的情况下,建议采用GPU进行训练可缩短训练时长。

为了防止操作在jupyter notebook下的失误导致模型丢失,我们把训练好的模型权重进行保存

from keras.models import load_model

# 保存训练的好的model权重
model.save('cifar_10_weights_v1.h5')

3.4 测试训练结果

先绘制出训练过程中的准确率和误差率的图像。

# 显示训练准确率
show_train_history(train_history,'acc','val_acc')

png

# 显示误差率图
show_train_history(train_history,'loss','val_loss')

png

使用测试集对训练好的模型进行评估

# # 读取刚刚保存好的权重
# model = load_model('cifar_10_weights_v1.h5')
# 评估模型准确率
scores = model.evaluate(x_img_test_normalize, y_label_test_OneHot, verbose=1)
scores[1]
10000/10000 [==============================] - 8s 803us/step





0.6762

可以看到,本次训练结果的模型,在测试集下进行预测,可达到0.67的准确率。

为了更加直观查看测试情况,我们对将测试集进行预测,并绘制出部分预测结果

# 执行分类预测,该函数可直接得出预测的分类结果
result_predicition = model.predict_classes(x_img_test_normalize)
# 执行分类的概率预测,该函数执行结果为各个样本在各个分类的概率分布
result_Predicted_Probability = model.predict(x_img_test_normalize)

查看两种预测结果的数据形式。

# 查看predict_classes下出来的前五项结果
result_predicition[:5]
array([3, 8, 8, 8, 6])
# 查看predict下出来的前五项结果
result_Predicted_Probability[:5]
array([[5.34182461e-03, 8.43905087e-04, 2.47942265e-02, 6.79585218e-01,
        1.15932385e-02, 1.57841340e-01, 7.67891034e-02, 1.13944465e-03,
        3.67129333e-02, 5.35872672e-03],
       [1.79930497e-02, 1.50872976e-01, 1.14271745e-04, 1.70455955e-04,
        3.50254413e-05, 6.06207213e-05, 1.00560393e-03, 9.40183145e-06,
        8.04287553e-01, 2.54510436e-02],
       [2.03795120e-01, 8.24226364e-02, 3.03464085e-02, 4.04787622e-02,
        4.85980920e-02, 1.76508557e-02, 1.41626010e-02, 2.07500905e-02,
        4.57205743e-01, 8.45896080e-02],
       [3.24155211e-01, 9.89760160e-02, 2.32543647e-02, 4.33047023e-03,
        1.53712267e-02, 8.68870527e-04, 6.41026767e-03, 1.86687789e-03,
        5.20241618e-01, 4.52505238e-03],
       [4.31240587e-05, 1.93625048e-03, 2.40663663e-02, 3.37878950e-02,
        4.20266427e-02, 3.51430639e-03, 8.92321646e-01, 1.03993967e-04,
        1.98488263e-03, 2.14810600e-04]], dtype=float32)

利用predict_classes下出来的结果进行可视化结果绘制

# 随机查看15个结果
show_images_set_cifar(x_img_test, y_label_test, result_predicition, idx=40, alias=classes_name_ch)

png

可以发现部分结果存在了错误的情况

定义查看概率分布的函数,可以更加清楚的看到图像在预测过程中,对每一个分类的概率情况。该函数已经在simpl_utils.py当中。并且运行函数,查看第21项数据的预测结果。

# 建立show_Predicted_Probability()函数
def show_Predicted_Probability(y, prediction ,x_img,Predicted_Probability, label_dict, i):
    print('真实结果:',label_dict[y[i][0]])
    print('预测结果:',label_dict[prediction[i]])
    plt.figure(figsize=(2,2))
    plt.imshow(np.reshape(x_img_test[i],(32,32,3)))
    plt.show()
    for j in range(10):
        print(label_dict[j]+' 概率:%1.9f'%(Predicted_Probability[i][j]))
# 查看第29项数据的概率
show_Predicted_Probability(y_label_test, result_predicition, x_img_test, result_Predicted_Probability, classes_name_ch, 28)
真实结果: 卡车
预测结果: 卡车

png

飞机 概率:0.002581297
汽车 概率:0.054180630
 概率:0.002744253
 概率:0.008493958
鹿 概率:0.004325509
 概率:0.005801335
青蛙 概率:0.001365718
 概率:0.006288551
 概率:0.000617654
卡车 概率:0.913601160

可以清晰的看见,任意一个结果都是由10项分类的概率分布所组成,其中当前第28项的数据的结果中,概率最高的分类是卡车,达到了0.91的概率,其余类别的概率都非常之低,所以我们选取概率最大的分类作为当前数据项的预测结果。

我们再举一个例子,查看第39项的数据预测结果。

# 查看第42项数据的概率
show_Predicted_Probability(y_label_test, result_predicition, x_img_test, result_Predicted_Probability, classes_name_ch, 42)
真实结果: 
预测结果: 

png

飞机 概率:0.000712479
汽车 概率:0.001275811
 概率:0.016505195
 概率:0.577500820
鹿 概率:0.033857882
 概率:0.277522773
青蛙 概率:0.001494592
 概率:0.043435745
 概率:0.003604528
卡车 概率:0.044090137

可以看到第62项的预测出现了错误,真实的结果为狗,但是预测结果却为猫。猫分类的概率达到0.57,而真实结果的狗分类概率只达到0.27左右。所以该项结果预测是失败的。

建立混淆矩阵,更清晰的查看哪些分类直接存在较大的混淆。在此之前,我们需要对y_label_test进行一个转换,因为y_label_test的shape为(10000, 1)。

# 对比需要做混淆的两个数组的形状
y_label_test.shape, result_predicition.shape
((10000, 1), (10000,))
# 将y_label_test转为一纬数组的操作
y_label_test.reshape(-1).shape
(10000,)
# 建立混淆矩阵
import pandas as pd
print(classes_name_ch)
pd.crosstab(y_label_test.reshape(-1), predicition, rownames=['label'], colnames=['predict'])
{0: '飞机', 1: '汽车', 2: '鸟', 3: '猫', 4: '鹿', 5: '狗', 6: '青蛙', 7: '马', 8: '船', 9: '卡车'}
predict 0 1 2 3 4 5 6 7 8 9
label
0 815 18 32 20 10 4 3 16 42 40
1 9 911 3 5 0 5 1 3 6 57
2 70 3 641 74 64 64 36 36 8 4
3 16 5 54 593 34 200 34 51 3 10
4 21 2 62 91 646 53 28 90 5 2
5 12 1 35 157 24 705 9 52 2 3
6 10 4 36 87 47 63 738 4 6 5
7 9 2 22 46 27 44 2 844 2 2
8 77 33 10 14 4 8 5 4 821 24
9 21 56 6 13 2 2 1 15 14 870

通过混淆矩阵可以看出,3(猫)和5(狗)的最容易混淆,测试的混淆次数达到200次。其余的分类之间也存在着较高的混淆,比如3(猫)和4(鹿)91次、4(鹿)和7(马)90次

4. 加深网络结构

上一个训练的模型在测试集下的准确率只达到了0.67,这次我们加深网络中的卷积层结构,并且加大epoch,尝试提升模型的准确率。

from keras.models import Sequential
from keras.layers import Dense,Dropout,Activation,Flatten
from keras.layers import Conv2D,MaxPool2D,ZeroPadding2D

# 设置模型参数和训练参数
# 分类的类别
CLASSES_NB = 10
# 模型输入层数量
INPUT_SHAPE = (32, 32, 3)
# 验证集划分比例
VALIDATION_SPLIT = 0.2
# 训练周期,这边设置10个周期即可
EPOCH = 15
# 单批次数据量
BATCH_SIZE = 128
# 训练LOG打印形式
VERBOSE = 1
# 损失函数
LOSS = 'categorical_crossentropy'
# 优化函数
OPTIMIZER = 'adam'
# 训练指标
METRICS = ['accuracy']
model_v2 = Sequential()

# 建立卷积层
model_v2.add(Conv2D(filters=32, kernel_size=(3,3),
         input_shape=INPUT_SHAPE,
         padding='same'))
model_v2.add(Activation('relu'))
model_v2.add(Dropout(rate=0.3))

# 建立卷积层
model_v2.add(Conv2D(filters=32, kernel_size=(3,3), padding='same'))
model_v2.add(Activation('relu'))
model_v2.add(MaxPool2D(pool_size=(2,2)))

# 建立卷积层
model_v2.add(Conv2D(filters=64, kernel_size=(3,3), padding='same'))
model_v2.add(Activation('relu'))
model_v2.add(Dropout(rate=0.25))

# 建立卷积层
model_v2.add(Conv2D(filters=64, kernel_size=(3,3), padding='same'))
model_v2.add(Activation('relu'))
model_v2.add(MaxPool2D(pool_size=(2,2)))

# 追加卷积层和池化层
model_v2.add(Conv2D(filters=128, kernel_size=(3,3), padding='same'))
model_v2.add(Activation('relu'))
model_v2.add(Dropout(rate=0.3))
model_v2.add(Conv2D(filters=128, kernel_size=(3,3), padding='same'))
model_v2.add(Activation('relu'))
model_v2.add(MaxPool2D(pool_size=(2,2)))

# 建立平坦层
model_v2.add(Flatten())
model_v2.add(Dropout(rate=0.3))

# 建立隐藏层,共2500个神经元,并且加入Dropout(0.3)随机丢弃30%的神经元
model_v2.add(Dense(2500))
model_v2.add(Activation('relu'))
model_v2.add(Dropout(rate=0.3))

# 追加隐藏层
model_v2.add(Dense(1500))
model_v2.add(Activation('relu'))
model_v2.add(Dropout(rate=0.3))

# 建立输出层
model_v2.add(Dense(CLASSES_NB,))
model_v2.add(Activation('softmax'))

# 查看摘要
print(model.summary())
Model: "sequential_1"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_1 (Conv2D)            (None, 32, 32, 32)        896       
_________________________________________________________________
activation_1 (Activation)    (None, 32, 32, 32)        0         
_________________________________________________________________
dropout_1 (Dropout)          (None, 32, 32, 32)        0         
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 16, 16, 32)        0         
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 16, 16, 64)        18496     
_________________________________________________________________
activation_2 (Activation)    (None, 16, 16, 64)        0         
_________________________________________________________________
dropout_2 (Dropout)          (None, 16, 16, 64)        0         
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 8, 8, 64)          0         
_________________________________________________________________
flatten_1 (Flatten)          (None, 4096)              0         
_________________________________________________________________
dropout_3 (Dropout)          (None, 4096)              0         
_________________________________________________________________
dense_1 (Dense)              (None, 1024)              4195328   
_________________________________________________________________
dropout_4 (Dropout)          (None, 1024)              0         
_________________________________________________________________
dense_2 (Dense)              (None, 10)                10250     
_________________________________________________________________
activation_3 (Activation)    (None, 10)                0         
=================================================================
Total params: 4,224,970
Trainable params: 4,224,970
Non-trainable params: 0
_________________________________________________________________
None

搭建好的深度学习模型网络结构图如下

2

可以看到,这次我们将网络加深后,随之而来的参数量也加大了许多,这会使我们训练时间更加的长。如果有条件请在GPU环境下进行训练。

# 定义训练方式
model_v2.compile(loss=LOSS, optimizer=OPTIMIZER, metrics=METRICS)
# 开始训练
train_history = model_v2.fit(x_img_train_normalize,y_label_train_OneHot,validation_split=VALIDATION_SPLIT,epochs=EPOCH,batch_size=BATCH_SIZE,verbose=VERBOSE)
Train on 40000 samples, validate on 10000 samples
Epoch 1/15
40000/40000 [==============================] - 323s 8ms/step - loss: 1.8240 - acc: 0.3173 - val_loss: 1.6007 - val_acc: 0.4350
Epoch 2/15
40000/40000 [==============================] - 310s 8ms/step - loss: 1.3652 - acc: 0.5012 - val_loss: 1.2410 - val_acc: 0.5547
Epoch 3/15
40000/40000 [==============================] - 322s 8ms/step - loss: 1.1669 - acc: 0.5780 - val_loss: 1.1147 - val_acc: 0.6090
Epoch 4/15
40000/40000 [==============================] - 321s 8ms/step - loss: 1.0481 - acc: 0.6260 - val_loss: 1.0512 - val_acc: 0.6336
Epoch 5/15
40000/40000 [==============================] - 318s 8ms/step - loss: 0.9653 - acc: 0.6553 - val_loss: 0.9266 - val_acc: 0.6732
Epoch 6/15
40000/40000 [==============================] - 321s 8ms/step - loss: 0.8854 - acc: 0.6875 - val_loss: 0.9523 - val_acc: 0.6718
Epoch 7/15
40000/40000 [==============================] - 321s 8ms/step - loss: 0.8329 - acc: 0.7023 - val_loss: 0.7918 - val_acc: 0.7244
Epoch 8/15
40000/40000 [==============================] - 325s 8ms/step - loss: 0.7771 - acc: 0.7247 - val_loss: 0.7985 - val_acc: 0.7190
Epoch 9/15
40000/40000 [==============================] - 325s 8ms/step - loss: 0.7297 - acc: 0.7417 - val_loss: 0.7254 - val_acc: 0.7461
Epoch 10/15
40000/40000 [==============================] - 327s 8ms/step - loss: 0.6855 - acc: 0.7583 - val_loss: 0.7374 - val_acc: 0.7418
Epoch 11/15
40000/40000 [==============================] - 328s 8ms/step - loss: 0.6544 - acc: 0.7691 - val_loss: 0.7118 - val_acc: 0.7575
Epoch 12/15
40000/40000 [==============================] - 328s 8ms/step - loss: 0.6188 - acc: 0.7791 - val_loss: 0.7016 - val_acc: 0.7602
Epoch 13/15
40000/40000 [==============================] - 333s 8ms/step - loss: 0.5894 - acc: 0.7898 - val_loss: 0.6871 - val_acc: 0.7597
Epoch 14/15
40000/40000 [==============================] - 315s 8ms/step - loss: 0.5654 - acc: 0.7983 - val_loss: 0.7036 - val_acc: 0.7609
Epoch 15/15
40000/40000 [==============================] - 374s 9ms/step - loss: 0.5410 - acc: 0.8065 - val_loss: 0.6971 - val_acc: 0.7678
scores = model_v2.evaluate(x_img_test_normalize, y_label_test_OneHot, verbose=1)
scores[1]
10000/10000 [==============================] - 26s 3ms/step





0.7574

可以看到,在同一个测试集的准确率达到了0.75左右,比上次训练的0.67提升了不少。

from keras.models import load_model

# 保存训练的好的model权重
model_v2.save('cifar_10_weights_v2.h5')

结论

本章主要讲述如何使用卷积神经网络搭建模型识别CIFAR-10图像中的十个分类,大家可以自行对ImageNet深入了解,尝试搭建更加有效的模型识别难度更高的图片。


版权声明:如无特殊说明,文章均为本站原创,转载请注明出处

本文链接:http://tunm.top/article/learning_05/