官网实例详解4.8(cifar10_resnet.py)-keras学习笔记四

基于CIFAR10(小批量图片)数据集训练ResNet(残差网络)

Keras实例目录

代码注释

"""Trains a ResNet on the CIFAR10 dataset.
基于CIFAR10(小批量图片)数据集训练ResNet(残差网络)
ResNet v1
[a] Deep Residual Learning for Image Recognition
残差学习在图像识别中的应用
https://arxiv.org/pdf/1512.03385.pdf

ResNet v2
[b] Identity Mappings in Deep Residual Networks
基于ResNet的恒等映射
https://arxiv.org/pdf/1603.05027.pdf
"""

from __future__ import print_function
import keras
from keras.layers import Dense, Conv2D, BatchNormalization, Activation
from keras.layers import AveragePooling2D, Input, Flatten
from keras.optimizers import Adam
from keras.callbacks import ModelCheckpoint, LearningRateScheduler
from keras.callbacks import ReduceLROnPlateau
from keras.preprocessing.image import ImageDataGenerator
from keras.regularizers import l2
from keras import backend as K
from keras.models import Model
from keras.datasets import cifar10
import numpy as np
import os

# Training parameters
# 训练参数
batch_size = 32  # orig paper trained all networks with batch_size=128  原论文batch_size=128
epochs = 200
data_augmentation = True
num_classes = 10

# Subtracting pixel mean improves accuracy
subtract_pixel_mean = True

# Model parameter  模型参数
# ----------------------------------------------------------------------------
#           |      | 200-epoch | Orig Paper| 200-epoch | Orig Paper| sec/epoch
# Model     |  n   | ResNet v1 | ResNet v1 | ResNet v2 | ResNet v2 | GTX1080Ti
#           |v1(v2)| %Accuracy | %Accuracy | %Accuracy | %Accuracy | v1 (v2)
# ----------------------------------------------------------------------------
# ResNet20  | 3 (2)| 92.16     | 91.25     | -----     | -----     | 35 (---)
# ResNet32  | 5(NA)| 92.46     | 92.49     | NA        | NA        | 50 ( NA)
# ResNet44  | 7(NA)| 92.50     | 92.83     | NA        | NA        | 70 ( NA)
# ResNet56  | 9 (6)| 92.71     | 93.03     | 93.01     | NA        | 90 (100)
# ResNet110 |18(12)| 92.65     | 93.39+-.16| 93.15     | 93.63     | 165(180)
# ResNet164 |27(18)| -----     | 94.07     | -----     | 94.54     | ---(---)
# ResNet1001| (111)| -----     | 92.39     | -----     | 95.08+-.14| ---(---)
# ---------------------------------------------------------------------------
n = 3

# Model version
# 模型版本
# Orig paper: version = 1 (ResNet v1), Improved ResNet: version = 2 (ResNet v2)
# 原论文:版本 = 1 (ResNet v1),升级 ResNet:版本 =2 (ResNet v2)

version = 1

# Computed depth from supplied model parameter n
# 根据模型参数n计算深度
if version == 1:
    depth = n * 6 + 2
elif version == 2:
    depth = n * 9 + 2

# Model name, depth and version
# 模型名称,深度和版本
model_type = 'ResNet%dv%d' % (depth, version)

# Load the CIFAR10 data.
# 加载CIFAR10数据集
(x_train, y_train), (x_test, y_test) = cifar10.load_data()

# Input image dimensions.
# 输入图片维度
input_shape = x_train.shape[1:]

# Normalize data.
# 归一化数据
x_train = x_train.astype('float32') / 255
x_test = x_test.astype('float32') / 255

# If subtract pixel mean is enabled
# 如果启用像素均值
if subtract_pixel_mean:
    x_train_mean = np.mean(x_train, axis=0)
    x_train -= x_train_mean
    x_test -= x_train_mean

print('x_train shape:', x_train.shape)
print(x_train.shape[0], 'train samples')
print(x_test.shape[0], 'test samples')
print('y_train shape:', y_train.shape)

# Convert class vectors to binary class matrices.
# 转换类向量为多分类矩阵
y_train = keras.utils.to_categorical(y_train, num_classes)
y_test = keras.utils.to_categorical(y_test, num_classes)


def lr_schedule(epoch):
    """Learning Rate Schedule
    学习速率表

    Learning rate is scheduled to be reduced after 80, 120, 160, 180 epochs.
    Called automatically every epoch as part of callbacks during training.
    在80, 120, 160、180个时期后,学习率降低。在训练期间自动调用每个时期作为回调的一部分。

    # Arguments
    参数
        epoch (int): The number of epochs
        epoch(int,整型):(训练)周期数

    # Returns
    返回
        lr (float32): learning rate
        lr(float32,浮点型):学习率
    """
    lr = 1e-3 # 1e-3:1乘以10的-3次方
    if epoch > 180:
        lr *= 0.5e-3
    elif epoch > 160:
        lr *= 1e-3
    elif epoch > 120:
        lr *= 1e-2
    elif epoch > 80:
        lr *= 1e-1
    print('Learning rate: ', lr)
    return lr


def resnet_layer(inputs,
                 num_filters=16,
                 kernel_size=3,
                 strides=1,
                 activation='relu',
                 batch_normalization=True,
                 conv_first=True):
    """2D Convolution-Batch Normalization-Activation stack builder
    2D卷积批处理归一化激活堆栈生成器

    # Arguments
    参数
        inputs (tensor): input tensor from input image or previous layer
        inputs(tensor,张量):来自输入图片或前一层输入的张量
        num_filters (int): Conv2D number of filters
        num_filters (int): 2维卷积过滤器数
        kernel_size (int): Conv2D square kernel dimensions
        kernel_size (int): 2维卷积过滤器平方核维度
        strides (int): Conv2D square stride dimensions
        strides (int):2维卷积平方步长维度
        activation (string): activation name
        activation (string): 激活函数名称
        batch_normalization (bool): whether to include batch normalization
        batch_normalization (bool): 是否包含批次归一化
        conv_first (bool): conv-bn-activation (True) or
            activation-bn-conv (False)
        conv_first (bool): 卷积-批次归一化-激活 (True) or
           激活-批次归一化-卷积 (False)

    # Returns
    # 返回
        x (tensor): tensor as input to the next layer
        x (tensor): 张量作为下一层的输入
    """
    conv = Conv2D(num_filters,
                  kernel_size=kernel_size,
                  strides=strides,
                  padding='same',
                  kernel_initializer='he_normal',
                  kernel_regularizer=l2(1e-4))

    x = inputs
    if conv_first:
        x = conv(x)
        if batch_normalization:
            x = BatchNormalization()(x)
        if activation is not None:
            x = Activation(activation)(x)
    else:
        if batch_normalization:
            x = BatchNormalization()(x)
        if activation is not None:
            x = Activation(activation)(x)
        x = conv(x)
    return x


def resnet_v1(input_shape, depth, num_classes=10):
    """ResNet Version 1 Model builder [a]
    ResNet版本1模型构建 [a]

    Stacks of 2 x (3 x 3) Conv2D-BN-ReLU
    Last ReLU is after the shortcut connection.
    最后一个Relu是在快捷连接之后。
    At the beginning of each stage, the feature map size is halved (downsampled)
    by a convolutional layer with strides=2, while the number of filters is
    doubled. Within each stage, the layers have the same number filters and the
    same number of filters.
    在每个阶段的开始,特征映射的大小被步幅为2的卷积层减半(下采样),而滤波器的数量增加了一倍。
    在每个阶段,这些层具有相同数量的过滤器和相同数量的过滤器。
    Features maps sizes:
    特征映射大小:
    stage 0: 32x32, 16
    stage 1: 16x16, 32
    stage 2:  8x8,  64
    The Number of parameters is approx the same as Table 6 of [a]:
    参数的数量与[a]表6大致相同:
    ResNet20 0.27M
    ResNet32 0.46M
    ResNet44 0.66M
    ResNet56 0.85M
    ResNet110 1.7M

    # Arguments
    参数
        input_shape (tensor): shape of input image tensor
        input_shape (tensor): 输入图像张量形状
        depth (int): number of core convolutional layers
        depth (int):核卷积层的数量
        num_classes (int): number of classes (CIFAR10 has 10)
        num_classes (int): 类别数量 (CIFAR10(数据集)有10个)

    # Returns
    返回
        model (Model): Keras model instance
        模型(Model):Keras模型实例
    """
    if (depth - 2) % 6 != 0:
        raise ValueError('depth should be 6n+2 (eg 20, 32, 44 in [a])')
    # Start model definition.
    # 开始模型定义
    num_filters = 16
    num_res_blocks = int((depth - 2) / 6)

    inputs = Input(shape=input_shape)
    x = resnet_layer(inputs=inputs)
    # Instantiate the stack of residual units
    # 实例化残差单元堆栈
    for stack in range(3):
        for res_block in range(num_res_blocks):
            strides = 1
            if stack > 0 and res_block == 0:  # first layer but not first stack 第一层而不是第一堆栈
                strides = 2  # downsample 降低采样
            y = resnet_layer(inputs=x,
                             num_filters=num_filters,
                             strides=strides)
            y = resnet_layer(inputs=y,
                             num_filters=num_filters,
                             activation=None)
            if stack > 0 and res_block == 0:  # first layer but not first stack 第一层而不是第一堆栈
                # linear projection residual shortcut connection to match
                # 线性投影残差捷径连接匹配
                # changed dims
                # 改变维度
                x = resnet_layer(inputs=x,
                                 num_filters=num_filters,
                                 kernel_size=1,
                                 strides=strides,
                                 activation=None,
                                 batch_normalization=False)
            x = keras.layers.add([x, y])
            x = Activation('relu')(x)
        num_filters *= 2

    # Add classifier on top.
    # 在顶部添加分类器。
    # v1 does not use BN after last shortcut connection-ReLU
    # V1 没有使用 批次归一化处理,在上一个连接ReLU激活后。
    x = AveragePooling2D(pool_size=8)(x)
    y = Flatten()(x)
    outputs = Dense(num_classes,
                    activation='softmax',
                    kernel_initializer='he_normal')(y)

    # Instantiate model.
    # 初始化模型
    model = Model(inputs=inputs, outputs=outputs)
    return model


def resnet_v2(input_shape, depth, num_classes=10):
    """ResNet Version 2 Model builder [b]
    ResNet版本2模型构建 [b]

    Stacks of (1 x 1)-(3 x 3)-(1 x 1) BN-ReLU-Conv2D or also known as
    bottleneck layer
    First shortcut connection per layer is 1 x 1 Conv2D.
    第一个短连接每层是 1 x 1 的2维卷积
    Second and onwards shortcut connection is identity.
    第二个和前一个短连接是一致的。
    At the beginning of each stage, the feature map size is halved (downsampled)
    by a convolutional layer with strides=2, while the number of filter maps is
    doubled. Within each stage, the layers have the same number filters and the
    same filter map sizes.
    在每个阶段的开始,特征映射的大小被步幅为2的卷积层减半(下采样),而滤波器的数量增加了一倍。
    在每个阶段,这些层具有相同数量的过滤器和相同数量的过滤器。
    Features maps sizes:
    特征映射的大小:
    conv1  : 32x32,  16
    stage 0: 32x32,  64
    stage 1: 16x16, 128
    stage 2:  8x8,  256

    # Arguments
    参数
        input_shape (tensor): shape of input image tensor
        input_shape (tensor): 输入图像张量形状
        depth (int): number of core convolutional layers
        depth (int): 核卷积层数量
        num_classes (int): number of classes (CIFAR10 has 10)
        num_classes (int): 类别数量 (CIFAR10(数据集)有10个)

    # Returns
    返回
        model (Model): Keras model instance
        模型(Model):Keras模型实例
    """
    if (depth - 2) % 9 != 0:
        raise ValueError('depth should be 9n+2 (eg 56 or 110 in [b])')
    # Start model definition.
    # 模型定义
    num_filters_in = 16
    num_res_blocks = int((depth - 2) / 9)

    inputs = Input(shape=input_shape)
    # v2 performs Conv2D with BN-ReLU on input before splitting into 2 paths
    # V2在分裂成2条路径之前用BN-ReLU在输入端执行Conv2D
    x = resnet_layer(inputs=inputs,
                     num_filters=num_filters_in,
                     conv_first=True)

    # Instantiate the stack of residual units
    # 实例化残差单元堆栈
    for stage in range(3):
        for res_block in range(num_res_blocks):
            activation = 'relu'
            batch_normalization = True
            strides = 1
            if stage == 0:
                num_filters_out = num_filters_in * 4
                if res_block == 0:  # first layer and first stage 第一层、第一步
                    activation = None
                    batch_normalization = False
            else:
                num_filters_out = num_filters_in * 2
                if res_block == 0:  # first layer but not first stage 第一层非第一步
                    strides = 2    # downsample 降低采样

            # bottleneck residual unit
            # 瓶颈残差单元
            y = resnet_layer(inputs=x,
                             num_filters=num_filters_in,
                             kernel_size=1,
                             strides=strides,
                             activation=activation,
                             batch_normalization=batch_normalization,
                             conv_first=False)
            y = resnet_layer(inputs=y,
                             num_filters=num_filters_in,
                             conv_first=False)
            y = resnet_layer(inputs=y,
                             num_filters=num_filters_out,
                             kernel_size=1,
                             conv_first=False)
            if res_block == 0:
                # linear projection residual shortcut connection to match
                # changed dims
                x = resnet_layer(inputs=x,
                                 num_filters=num_filters_out,
                                 kernel_size=1,
                                 strides=strides,
                                 activation=None,
                                 batch_normalization=False)
            x = keras.layers.add([x, y])

        num_filters_in = num_filters_out

    # Add classifier on top.
    # 在顶部添加分类器。
    # v2 has BN-ReLU before Pooling
    # v2 在池化前用BN-ReLU激活处理
    x = BatchNormalization()(x)
    x = Activation('relu')(x)
    x = AveragePooling2D(pool_size=8)(x)
    y = Flatten()(x)
    outputs = Dense(num_classes,
                    activation='softmax',
                    kernel_initializer='he_normal')(y)

    # Instantiate model.
    # 初始化模型
    model = Model(inputs=inputs, outputs=outputs)
    return model


if version == 2:
    model = resnet_v2(input_shape=input_shape, depth=depth)
else:
    model = resnet_v1(input_shape=input_shape, depth=depth)

model.compile(loss='categorical_crossentropy',
              optimizer=Adam(lr=lr_schedule(0)),
              metrics=['accuracy'])
model.summary()
print(model_type)

# Prepare model model saving directory.
# 模型保存目录
save_dir = os.path.join(os.getcwd(), 'saved_models')
model_name = 'cifar10_%s_model.{epoch:03d}.h5' % model_type
if not os.path.isdir(save_dir):
    os.makedirs(save_dir)
filepath = os.path.join(save_dir, model_name)

# Prepare callbacks for model saving and for learning rate adjustment.
# 保存模型和学习率调整回调
checkpoint = ModelCheckpoint(filepath=filepath,
                             monitor='val_acc',
                             verbose=1,
                             save_best_only=True)

lr_scheduler = LearningRateScheduler(lr_schedule)

lr_reducer = ReduceLROnPlateau(factor=np.sqrt(0.1),
                               cooldown=0,
                               patience=5,
                               min_lr=0.5e-6)

callbacks = [checkpoint, lr_reducer, lr_scheduler]

# Run training, with or without data augmentation.
# 运行训练,有或没有数据扩大(增加数据集样本数量)
if not data_augmentation:
    print('Not using data augmentation.')
    model.fit(x_train, y_train,
              batch_size=batch_size,
              epochs=epochs,
              validation_data=(x_test, y_test),
              shuffle=True,
              callbacks=callbacks)
else:
    print('Using real-time data augmentation.')
    # This will do preprocessing and realtime data augmentation:
    # 处理和实时数据(集)扩大
    datagen = ImageDataGenerator(
        # set input mean to 0 over the dataset
        # 在数据集上设置输入平均值为0
        featurewise_center=False,
        # set each sample mean to 0
        # 设置样本均值为0
        samplewise_center=False,
        # divide inputs by std of dataset
        # 用数据集的std划分输入
        featurewise_std_normalization=False,
        # divide each input by its std
        # 根据标准划分每个输入
        samplewise_std_normalization=False,
        # apply ZCA whitening # 应用ZCA白化处理
        zca_whitening=False,
        # randomly rotate images in the range (deg 0 to 180)  # 在0到180度范围内,随机旋转图像
        rotation_range=0,
        # randomly shift images horizontally # 随机水平移动图像
        width_shift_range=0.1,
        # randomly shift images vertically # 随机垂直移动图像
        height_shift_range=0.1,
        # randomly flip images # 随机翻转图像
        horizontal_flip=True,
        # randomly flip images # 随机翻转图像
        vertical_flip=False)

    # Compute quantities required for featurewise normalization
    # (std, mean, and principal components if ZCA whitening is applied).
    # 特征归一化所需的计算量
    # (标准均值,主ZCA白化应用)。
    datagen.fit(x_train)

    # Fit the model on the batches generated by datagen.flow().
    # 拟合模型,该模型由datagen.flow()(函数)批量生成
    model.fit_generator(datagen.flow(x_train, y_train, batch_size=batch_size),
                        validation_data=(x_test, y_test),
                        epochs=epochs, verbose=1, workers=4,
                        callbacks=callbacks)

# Score trained model.
# 评估训练模型
scores = model.evaluate(x_test, y_test, verbose=1)
print('Test loss:', scores[0])
print('Test accuracy:', scores[1])

代码执行


Keras详细介绍

英文:https://keras.io/

中文:http://keras-cn.readthedocs.io/en/latest/

实例下载

https://github.com/keras-team/keras

https://github.com/keras-team/keras/tree/master/examples

完整项目下载

方便没积分童鞋,请加企鹅452205574,共享文件夹。

包括:代码、数据集合(图片)、已生成model、安装库文件等。


猜你喜欢

转载自blog.csdn.net/wyx100/article/details/80786280
今日推荐