美文网首页机器学习机器学习笔记
利用keras从实例掌握深度学习图像分类

利用keras从实例掌握深度学习图像分类

作者: Spytensor | 来源:发表于2018-07-19 20:04 被阅读3475次

    目的:帮助那些学习过机器学习、深度学习算法、了解keras框架以及熟悉python用 法却对实际应用无从下手的同学,
    从简单交通标志识别入手,彻底掌握深度学习算法在图像识别领域的应用。
    项目完整地址Github:ImageClassification

    注:目前已经支持的网络结构有 :

    • LeNet
    • AlexNet
    • VGGNet
    • ZFNet
    • GoogLeNet
    • ResNet_18/34/50/101/152
    • DenseNet_161

    1.项目准备工作

    数据集下载地址交通标志数据集

    1.1 完整目录

    创建一下三个文件夹,其中data用来存放待训练的数据以及测试数据,log用来存放keras训练好的模型,便于后续预测图像类别时对训练好的模型进行加载,src用来存放所有的python文件。


    完整目录
    1.2 data文件夹

    结构如下,其中待识别的图像直接放到test文件夹下面
    ├─data
    │ ├─test
    │ └─train

    1.3 train文件夹

    结构如下,每个文件夹的名称代表一个类别(在代码中会有所体现),每个文件夹存放了一定数量的对应类别的图像
    └─train
       ├─00000
       ├─00001
       ├─00002
       ├─00003
       ├─00004
       ├─00005
       ├─00006
       ├─00007
       ├─00008
       └─00009

    2. 使用keras搭建网络结构

    在完成项目文件夹以及数据准备后,开始创建网络结构,在完成该步骤后,可以修改参数实现选择不同的网络结构对数据进行训练

    2.1 创建src/config.py,用来定以所需要的一些列参数
    class DefaultConfigs(object):
        """docstring for DefaultConfig"""
        train_data_path = "../data/train/"     #训练数据所在路径
        test_data_path = "../data/test/"       #要识别的图像存储路径
        weights_path = "../log/"               #模型保存路径
        normal_size = 64                        #图像输入网络之前需要被resize的大小
        channels = 3                           #RGB通道数
        epochs = 60                            #训练的epoch次数
        batch_size = 64                         #训练的batch 数
        classes = 10                            #要识别的类数
        data_augmentation = True               #是否使用keras的数据增强模块
        model_name = "ResNet_18"                 #选择所要使用的网络结构名称
    
    config = DefaultConfigs()
    
    2.2 创建src/utils.py 包括数据读取和不同网络模型的加载
    from keras.preprocessing.image import img_to_array
    from keras.utils import to_categorical
    from models import AlexNet,resnet
    import cv2
    import os
    import numpy as np
    
    np.random.seed(42)
    
    def load_data(config):
        labels = []                                                         #存放标签信息
        images_data = []                                                    #存放图片信息
        print("loading dataset......")
        data_path = config. train_data_path                                  #也即是train文件夹
        category_paths = os.listdir(data_path)                              #每个类别所在的文件夹,返回list格式
        category_paths = list(map(lambda x:data_path+x,category_paths))     #组合成合法的路径,如../data/train/00000
        np.random.shuffle(category_paths)
        for category_path in category_paths:
            images_files_list = os.listdir(category_path)                   #获取每个类别下的图像名称
            print(category_path)
            for image_file in images_files_list:
                file_name = category_path + "/"+image_file                  #每张图片的路径,便于读取
                label = int(category_path[-2:])                                  #提取类别信息
                labels.append(label)
    
                image = cv2.imread(file_name)                               #使用opencv读取图像
                image = cv2.resize(image,(config.normal_size,config.normal_size))
                image = img_to_array(image)                                 #将图像转换成array形式
                images_data.append(image)
    
        #缩放图像数据
        images_data = np.array(images_data,dtype="float") / 255.0
        labels = np.array(labels)                                           #将label转换成np.array格式
        labels = to_categorical(labels, num_classes=config.classes)
    
        return images_data,labels
    
    def build_model(config):
        #根据选择的网络模型构建
        if config.model_name == "AlexNet":
            model = AlexNet.AlexNet(config)
        elif config.model_name == "ResNet_18":
            model = resnet.ResnetBuilder.build_resnet_18(config)
        elif config.model_name == "ResNet_34":
            model = resnet.ResnetBuilder.build_resnet_34(config)
        elif config.model_name == "ResNet_50":
            model = resnet.ResnetBuilder.build_resnet_50(config)
        elif config.model_name == "ResNet_101":
            model = resnet.ResnetBuilder.build_resnet_101(config)
        elif config.model_name == "ResNet_152":
            model = resnet.ResnetBuilder.build_resnet_152(config)
        else:
            print("The model you have selected doesn't exists!")
        return model
    
    2.3 创建src/train.py,进行训练参数设置的主文件
    from utils import build_model,load_data
    from sklearn.model_selection import train_test_split
    from keras.callbacks import ReduceLROnPlateau, CSVLogger, EarlyStopping, ModelCheckpoint
    from keras.preprocessing.image import ImageDataGenerator
    from sklearn.metrics import accuracy_score
    from config import config
    
    def train(config,train_x,train_y,dev_x,dev_y):
        model = build_model(config)
        lr_reducer = ReduceLROnPlateau(factor=0.005, cooldown=0, patience=5, min_lr=0.5e-6,verbose=1)      #设置学习率衰减
        early_stopper = EarlyStopping(min_delta=0.001, patience=10,verbose=1)                                     #设置早停参数
        checkpoint = ModelCheckpoint(config.weights_path + config.model_name + "_model.h5",
                                     monitor="val_acc", verbose=1,
                                     save_best_only=True, save_weights_only=True,mode="max")            #保存训练过程中,在验证集上效果最好的模型
        #使用数据增强
        if config.data_augmentation:
            print("using data augmentation method")
            data_aug = ImageDataGenerator(
                rotation_range=90,              #图像旋转的角度
                width_shift_range=0.2,          #左右平移参数
                height_shift_range=0.2,         #上下平移参数
                zoom_range=0.3,                 #随机放大或者缩小
                horizontal_flip=True,           #随机翻转
            )
            data_aug.fit(train_x)
            model.fit_generator(
                data_aug.flow(train_x,train_y,batch_size=config.batch_size),
                steps_per_epoch=train_x.shape[0] // config.batch_size,
                validation_data=(dev_x,dev_y),
                shuffle=True,
                epochs=config.epochs,verbose=1,max_queue_size=100,
                callbacks=[lr_reducer,early_stopper,checkpoint]
            )
        else:
            print("don't use data augmentation method")
            model.fit(train_x,train_y,batch_size = config.batch_size,
                      nb_epoch=config.epochs,
                      validation_data=(dev_x, dev_y),
                      shuffle=True,
                      callbacks=[lr_reducer, early_stopper, checkpoint]
                      )
    
    if __name__ == "__main__":
        images_data, labels = load_data(config)
        train_x,dev_x,train_y,dev_y = train_test_split(images_data,labels,test_size=0.25) #随机切分数据集,分为训练和验证集
        train(config,train_x,train_y,dev_x,dev_y)
    
    
    2.4 创建src/models/AlexNet.py,搭建AlexNet网络结构,其他网络结构不再一一列出
    from keras.models import Sequential
    from keras.layers.core import Flatten, Dense
    from keras.layers.convolutional import Convolution2D
    from keras.layers.pooling import MaxPooling2D
    from keras.layers import Dropout
    
    def AlexNet(config):
        model = Sequential()
        input_shape = (config.normal_size,config.normal_size,config.channels)
        model.add(Convolution2D(96, (11, 11), strides=(4, 4), input_shape=input_shape, padding='valid', activation='relu',
                         kernel_initializer='uniform'))
        model.add(MaxPooling2D(pool_size=(3, 3), strides=(2, 2)))
        model.add(Convolution2D(256, (5, 5), strides=(1, 1), padding='same', activation='relu', kernel_initializer='uniform'))
        model.add(MaxPooling2D(pool_size=(3, 3), strides=(2, 2)))
        model.add(Convolution2D(384, (3, 3), strides=(1, 1), padding='same', activation='relu', kernel_initializer='uniform'))
        model.add(Convolution2D(384, (3, 3), strides=(1, 1), padding='same', activation='relu', kernel_initializer='uniform'))
        model.add(Convolution2D(256, (3, 3), strides=(1, 1), padding='same', activation='relu', kernel_initializer='uniform'))
        model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))
        model.add(Flatten())
        model.add(Dense(4096, activation='relu'))
        model.add(Dropout(0.5))
        model.add(Dense(4096, activation='relu'))
        model.add(Dropout(0.5))
        model.add(Dense(config.classes, activation='softmax'))
        model.compile(loss="categorical_crossentropy", optimizer="adam",metrics=["accuracy"])
    
        return model
    

    注1:之所以数据的存储文件格式要按照前文的要求,是因为在代码utils.py中的load_data()函数在读取文件是,按照层级结构,根据os.listdir()寻找文件夹和文件。
    ps:当你很熟练的时候,当然不用根据代码去调整文件夹了,而是根据数据去调整代码~

    3.训练日志

    Epoch 00019: val_acc improved from 0.96401 to 0.96429, saving model to ../log/ResNet_18_model.h5
    Epoch 20/60
      1/171 [..............................] - ETA: 16s - loss: 0.3963 - acc: 0.9531
      2/171 [..............................] - ETA: 15s - loss: 0.4064 - acc: 0.9453
      3/171 [..............................] - ETA: 15s - loss: 0.4375 - acc: 0.9323
    

    选择的是resnet18,后续还有提升,没有继续训练,有兴趣的可以尝试不同的网络结构~

    4.TODO

    希望能够添加更多的网络模型进去,目前该项目只支持图像识别任务,后续做一个检测类的项目。

    5.项目完整地址

    Github:ImageClassification

    6.参考文献

    [1] Lécun Y, Bottou L, Bengio Y, et al. Gradient-based learning applied to document recognition[J]. Proceedings of the IEEE, 1998, 86(11):2278-2324.
    [2] Krizhevsky A, Sutskever I, Hinton G E. ImageNet classification with deep convolutional neural networks[C]// International Conference on Neural Information Processing Systems. Curran Associates Inc. 2012:1097-1105.
    [3] Simonyan K, Zisserman A. Very Deep Convolutional Networks for Large-Scale Image Recognition[J]. Computer Science, 2014.
    [4] Zeiler M D, Fergus R. Visualizing and Understanding Convolutional Networks[J]. 2014, 8689:818-833.
    [5] He K, Zhang X, Ren S, et al. Deep Residual Learning for Image Recognition[C]// IEEE Conference on Computer Vision and Pattern Recognition. IEEE Computer Society, 2016:770-778.
    [6] Szegedy C, Liu W, Jia Y, et al. Going deeper with convolutions[C]// IEEE Conference on Computer Vision and Pattern Recognition. IEEE, 2015:1-9.
    [7] Huang G, Liu Z, Laurens V D M, et al. Densely Connected Convolutional Networks[J]. 2016:2261-2269.
    [8] Introduce the cnns from LeNet to DensNet
    [9] DenseNet-Keras
    [10] keras-resnet

    相关文章

      网友评论

        本文标题:利用keras从实例掌握深度学习图像分类

        本文链接:https://www.haomeiwen.com/subject/fxdtmftx.html