目录
  • 什么是AlexNet模型
  • 训练前准备
    • 1、数据集处理
    • 2、创建Keras的AlexNet模型
  • 开始训练
    • 1、训练的主函数
    • 2、Keras数据生成器
    • 3、主训练函数全部代码
  • 训练结果

    最近在做实验室的工作,要用到分类模型,老板一星期催20次,我也是无语了,上有对策下有政策,在下先找个猫猫狗狗的数据集练练手,快乐极了

    什么是AlexNet模型

    AlexNet是2012年ImageNet竞赛冠军获得者Hinton和他的学生Alex Krizhevsky设计的。也是在那年之后,更多的更深的神经网络被提出,比如优秀的vgg,GoogLeNet。 这对于传统的机器学习分类算法而言,已经相当的出色。如下是其网络的结构,现在看来还是比较简单的。

    python神经网络AlexNet分类模型训练猫狗数据集

    python神经网络AlexNet分类模型训练猫狗数据集

    这是一个AlexNet的网络结构图,其实并不复杂,很好的反应了AlexNet的结构:

    1、一张原始图片被resize到(224,224,3);

    2、使用步长为4×4,大小为11的卷积核对图像进行卷积,输出的特征层为96层,输出的shape为(55,55,96);

    3、使用步长为2的最大池化层进行池化,此时输出的shape为(27,27,96)

    4、使用步长为1×1,大小为5的卷积核对图像进行卷积,输出的特征层为256层,输出的shape为(27,27,256);

    5、使用步长为2的最大池化层进行池化,此时输出的shape为(13,13,256);

    6、使用步长为1×1,大小为3的卷积核对图像进行卷积,输出的特征层为384层,输出的shape为(13,13,384);

    7、使用步长为1×1,大小为3的卷积核对图像进行卷积,输出的特征层为384层,输出的shape为(13,13,384);

    8、使用步长为1×1,大小为3的卷积核对图像进行卷积,输出的特征层为256层,输出的shape为(13,13,256);

    9、使用步长为2的最大池化层进行池化,此时输出的shape为(6,6,256);

    10、两个全连接层,最后输出为1000类

    最后输出的就是每个类的预测。

    从上面的图也可以看出,其实最大的内存与计算消耗在于第一个全连接层的实现,它的参数有37M之多(这一点与VGG很类似,第一个全连接层参数巨多。),

    训练前准备

    1、数据集处理

    在数据集处理之前,首先要下载猫狗数据集,地址如下。

    链接:https://pan.baidu.com/s/1IfN8Cvt60n64bbC2gF4Ung

    提取码:he9i

    顺便直接下载我的源代码吧。

    这里的源代码包括了所有的代码部分,训练集需要自己下载,大概训练2个小时就可以进行预测了。

    本次教程准备使用model.fit_generator来训练模型,在训练模型之前,需要将数据集的内容保存到一个TXT文件中,便于读取。

    txt文件的保存格式如下:

    文件名;种类

    python神经网络AlexNet分类模型训练猫狗数据集

    具体操作步骤如下:

    1、将训练文件存到"./data/image/train/"目录下。

    python神经网络AlexNet分类模型训练猫狗数据集

    2、调用如下代码:

    import os
    photos = os.listdir("./data/image/train/")
    # 该部分用于将
    with open("data/dataset.txt","w") as f:
        for photo in photos:
            name = photo.split(".")[0]
            if name=="cat":
                f.write(photo + ";0\n")
            elif name=="dog":
                f.write(photo + ";1\n")
    f.close()
    

    就可以得到训练数据集的文本文件。

    python神经网络AlexNet分类模型训练猫狗数据集

    2、创建Keras的AlexNet模型

    该步就是按照AlexNet的结构创建AlexNet的模型。我试了原大小的模型,发现根本呢不收敛,可能是模型太复杂而且猫狗的特征太少了(也许是我打开方式不对)……于是我就缩减了模型,每个卷积层的filter减半,全连接层减为1024.

    from keras.models import Sequential
    from keras.layers import Dense,Activation,Conv2D,MaxPooling2D,Flatten,Dropout,BatchNormalization
    from keras.datasets import mnist
    from keras.utils import np_utils
    from keras.optimizers import Adam
    def AlexNet(input_shape=(224,224,3),output_shape=2):
        # AlexNet
        model = Sequential()
        # 使用步长为4x4,大小为11的卷积核对图像进行卷积,输出的特征层为96层,输出的shape为(55,55,96);
        # 所建模型后输出为48特征层
        model.add(
            Conv2D(
                filters=48, 
                kernel_size=(11,11),
                strides=(4,4),
                padding='valid',
                input_shape=input_shape,
                activation='relu'
            )
        )
        model.add(BatchNormalization())
        # 使用步长为2的最大池化层进行池化,此时输出的shape为(27,27,96)
        model.add(
            MaxPooling2D(
                pool_size=(3,3), 
                strides=(2,2), 
                padding='valid'
            )
        )
        # 使用步长为1x1,大小为5的卷积核对图像进行卷积,输出的特征层为256层,输出的shape为(27,27,256);
        # 所建模型后输出为128特征层
        model.add(
            Conv2D(
                filters=128, 
                kernel_size=(5,5), 
                strides=(1,1), 
                padding='same',
                activation='relu'
            )
        )
        model.add(BatchNormalization())
        # 使用步长为2的最大池化层进行池化,此时输出的shape为(13,13,256);
        model.add(
            MaxPooling2D(
                pool_size=(3,3),
                strides=(2,2),
                padding='valid'
            )
        )
        # 使用步长为1x1,大小为3的卷积核对图像进行卷积,输出的特征层为384层,输出的shape为(13,13,384);
        # 所建模型后输出为192特征层
        model.add(
            Conv2D(
                filters=192, 
                kernel_size=(3,3),
                strides=(1,1), 
                padding='same', 
                activation='relu'
            )
        ) 
        # 使用步长为1x1,大小为3的卷积核对图像进行卷积,输出的特征层为384层,输出的shape为(13,13,384);
        # 所建模型后输出为192特征层
        model.add(
            Conv2D(
                filters=192, 
                kernel_size=(3,3), 
                strides=(1,1), 
                padding='same', 
                activation='relu'
            )
        )
        # 使用步长为1x1,大小为3的卷积核对图像进行卷积,输出的特征层为256层,输出的shape为(13,13,256);
        # 所建模型后输出为128特征层
        model.add(
            Conv2D(
                filters=128, 
                kernel_size=(3,3), 
                strides=(1,1), 
                padding='same', 
                activation='relu'
            )
        )
        # 使用步长为2的最大池化层进行池化,此时输出的shape为(6,6,256);
        model.add(
            MaxPooling2D(
                pool_size=(3,3), 
                strides=(2,2), 
                padding='valid'
            )
        )
        # 两个全连接层,最后输出为1000类,这里改为2类
        # 缩减为1024
        model.add(Flatten())
        model.add(Dense(1024, activation='relu'))
        model.add(Dropout(0.25))
        model.add(Dense(1024, activation='relu'))
        model.add(Dropout(0.25))
        model.add(Dense(output_shape, activation='softmax'))
        return model
    

    开始训练

    1、训练的主函数

    训练的主函数主要包括如下部分:

    1、读取训练用txt,并打乱,利用该txt进行训练集和测试集的划分。

    2、建立AlexNet模型

    3、设定模型保存的方式、学习率下降的方式、是否需要早停。

    4、利用model.fit_generator训练模型。

    具体代码如下:

    if __name__ == "__main__":
        # 模型保存的位置
        log_dir = "./logs/"
        # 打开数据集的txt
        with open(r".\data\dataset.txt","r") as f:
            lines = f.readlines()
        # 打乱行,这个txt主要用于帮助读取数据来训练
        # 打乱的数据更有利于训练
        np.random.seed(10101)
        np.random.shuffle(lines)
        np.random.seed(None)
        # 90%用于训练,10%用于估计。
        num_val = int(len(lines)*0.1)
        num_train = len(lines) - num_val
        # 建立AlexNet模型
        model = AlexNet()
        # 保存的方式,3世代保存一次
        checkpoint_period1 = ModelCheckpoint(
                                        log_dir + 'ep{epoch:03d}-loss{loss:.3f}-val_loss{val_loss:.3f}.h5',
                                        monitor='acc', 
                                        save_weights_only=False, 
                                        save_best_only=True, 
                                        period=3
                                    )
        # 学习率下降的方式,acc三次不下降就下降学习率继续训练
        reduce_lr = ReduceLROnPlateau(
                                monitor='acc', 
                                factor=0.5, 
                                patience=3, 
                                verbose=1
                            )
        # 是否需要早停,当val_loss一直不下降的时候意味着模型基本训练完毕,可以停止
        early_stopping = EarlyStopping(
                                monitor='val_loss', 
                                min_delta=0, 
                                patience=10, 
                                verbose=1
                            )
        # 交叉熵
        model.compile(loss = 'categorical_crossentropy',
                optimizer = Adam(lr=1e-3),
                metrics = ['accuracy'])
        # 一次的训练集大小
        batch_size = 64
        print('Train on {} samples, val on {} samples, with batch size {}.'.format(num_train, num_val, batch_size))
        # 开始训练
        model.fit_generator(generate_arrays_from_file(lines[:num_train], batch_size),
                steps_per_epoch=max(1, num_train//batch_size),
                validation_data=generate_arrays_from_file(lines[num_train:], batch_size),
                validation_steps=max(1, num_val//batch_size),
                epochs=150,
                initial_epoch=0,
                callbacks=[checkpoint_period1, reduce_lr])
        model.save_weights(log_dir+'last1.h5')
    

    model.fit_generator需要用到python的生成器来滚动读取数据,具体方法看第二步。

    2、Keras数据生成器

    Keras的数据生成器就是在一个while 1的无限循环中不断生成batch大小的数据集。

    def generate_arrays_from_file(lines,batch_size):
        # 获取总长度
        n = len(lines)
        i = 0
        while 1:
            X_train = []
            Y_train = []
            # 获取一个batch_size大小的数据
            for b in range(batch_size):
                if i==0:
                    np.random.shuffle(lines)
                name = lines[i].split(';')[0]
                # 从文件中读取图像
                img = cv2.imread(r".\data\image\train" + '/' + name)
                img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
                img = img/255
                X_train.append(img)
                Y_train.append(lines[i].split(';')[1])
                # 读完一个周期后重新开始
                i = (i+1) % n
            # 处理图像
            X_train = utils.resize_image(X_train,(224,224))
            X_train = X_train.reshape(-1,224,224,3)
            Y_train = np_utils.to_categorical(np.array(Y_train),num_classes= 2)   
            yield (X_train, Y_train)
    

    在其中用到了一些处理函数,我存在了utils.py工具人文件中。

    import matplotlib.image as mpimg
    import numpy as np
    import cv2
    import tensorflow as tf
    from tensorflow.python.ops import array_ops
    def load_image(path):
        # 读取图片,rgb
        img = mpimg.imread(path)
        # 将图片修剪成中心的正方形
        short_edge = min(img.shape[:2])
        yy = int((img.shape[0] - short_edge) / 2)
        xx = int((img.shape[1] - short_edge) / 2)
        crop_img = img[yy: yy + short_edge, xx: xx + short_edge]
        return crop_img
    def resize_image(image, size):
        with tf.name_scope('resize_image'):
            images = []
            for i in image:
                i = cv2.resize(i, size)
                images.append(i)
            images = np.array(images)
            return images
    def print_answer(argmax):
        with open("./data/model/index_word.txt","r",encoding='utf-8') as f:
            synset = [l.split(";")[1][:-1] for l in f.readlines()]
        print(synset[argmax])
        return synset[argmax]
    

    3、主训练函数全部代码

    大家可以整体看看哈:

    from keras.callbacks import TensorBoard, ModelCheckpoint, ReduceLROnPlateau, EarlyStopping
    from keras.utils import np_utils
    from keras.optimizers import Adam
    from model.AlexNet import AlexNet
    import numpy as np
    import utils
    import cv2
    from keras import backend as K
    K.set_image_dim_ordering('tf')
    def generate_arrays_from_file(lines,batch_size):
        # 获取总长度
        n = len(lines)
        i = 0
        while 1:
            X_train = []
            Y_train = []
            # 获取一个batch_size大小的数据
            for b in range(batch_size):
                if i==0:
                    np.random.shuffle(lines)
                name = lines[i].split(';')[0]
                # 从文件中读取图像
                img = cv2.imread(r".\data\image\train" + '/' + name)
                img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
                img = img/255
                X_train.append(img)
                Y_train.append(lines[i].split(';')[1])
                # 读完一个周期后重新开始
                i = (i+1) % n
            # 处理图像
            X_train = utils.resize_image(X_train,(224,224))
            X_train = X_train.reshape(-1,224,224,3)
            Y_train = np_utils.to_categorical(np.array(Y_train),num_classes= 2)   
            yield (X_train, Y_train)
    if __name__ == "__main__":
        # 模型保存的位置
        log_dir = "./logs/"
        # 打开数据集的txt
        with open(r".\data\dataset.txt","r") as f:
            lines = f.readlines()
        # 打乱行,这个txt主要用于帮助读取数据来训练
        # 打乱的数据更有利于训练
        np.random.seed(10101)
        np.random.shuffle(lines)
        np.random.seed(None)
        # 90%用于训练,10%用于估计。
        num_val = int(len(lines)*0.1)
        num_train = len(lines) - num_val
        # 建立AlexNet模型
        model = AlexNet()
        # 保存的方式,3世代保存一次
        checkpoint_period1 = ModelCheckpoint(
                                        log_dir + 'ep{epoch:03d}-loss{loss:.3f}-val_loss{val_loss:.3f}.h5',
                                        monitor='acc', 
                                        save_weights_only=False, 
                                        save_best_only=True, 
                                        period=3
                                    )
        # 学习率下降的方式,acc三次不下降就下降学习率继续训练
        reduce_lr = ReduceLROnPlateau(
                                monitor='acc', 
                                factor=0.5, 
                                patience=3, 
                                verbose=1
                            )
        # 是否需要早停,当val_loss一直不下降的时候意味着模型基本训练完毕,可以停止
        early_stopping = EarlyStopping(
                                monitor='val_loss', 
                                min_delta=0, 
                                patience=10, 
                                verbose=1
                            )
        # 交叉熵
        model.compile(loss = 'categorical_crossentropy',
                optimizer = Adam(lr=1e-3),
                metrics = ['accuracy'])
        # 一次的训练集大小
        batch_size = 64
        print('Train on {} samples, val on {} samples, with batch size {}.'.format(num_train, num_val, batch_size))
        # 开始训练
        model.fit_generator(generate_arrays_from_file(lines[:num_train], batch_size),
                steps_per_epoch=max(1, num_train//batch_size),
                validation_data=generate_arrays_from_file(lines[num_train:], batch_size),
                validation_steps=max(1, num_val//batch_size),
                epochs=150,
                initial_epoch=0,
                callbacks=[checkpoint_period1, reduce_lr, early_stopping ])
        model.save_weights(log_dir+'last1.h5')
    

    训练结果

    在完成上述的一大堆内容的配置后就可以开始训练了,所有文件的构架如下:

    python神经网络AlexNet分类模型训练猫狗数据集

    ……训练是真的慢

    ……
    Epoch 36/50
    175/175 [==============================] - 219s 1s/step - loss: 0.0124 - acc: 0.9962 - val_loss: 0.5256 - val_acc: 0.9034
    Epoch 37/50
    175/175 [==============================] - 178s 1s/step - loss: 0.0028 - acc: 0.9991 - val_loss: 0.7911 - val_acc: 0.9034
    Epoch 38/50
    175/175 [==============================] - 174s 992ms/step - loss: 0.0047 - acc: 0.9987 - val_loss: 0.6690 - val_acc: 0.8910
    Epoch 39/50
    175/175 [==============================] - 241s 1s/step - loss: 0.0044 - acc: 0.9986 - val_loss: 0.6518 - val_acc: 0.9001
    Epoch 40/50
    142/175 [=======================>......] - ETA: 1:07 - loss: 0.0074 - acc: 0.9976
    

    差不多是这样,在测试集上有90的准确度呢!我们拿一个模型预测一下看看。

    import numpy as np
    import utils
    import cv2
    from keras import backend as K
    from model.AlexNet import AlexNet
    K.set_image_dim_ordering('tf')
    if __name__ == "__main__":
        model = AlexNet()
        # 载入模型
        model.load_weights("./logs/ep039-loss0.004-val_loss0.652.h5")
        # 载入图片,并处理
        img = cv2.imread("./Test.jpg")
        img_RGB = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
        img_nor = img_RGB/255
        img_nor = np.expand_dims(img_nor,axis = 0)
        img_resize = utils.resize_image(img_nor,(224,224))
    	# 预测~!
        #utils.print_answer(np.argmax(model.predict(img)))
        print(utils.print_answer(np.argmax(model.predict(img_resize))))
        cv2.imshow("ooo",img)
        cv2.waitKey(0)
    

    预测结果为:

    猫猫

    python神经网络AlexNet分类模型训练猫狗数据集

    大功告成。

    以上就是python神经网络AlexNet分类模型训练猫狗数据集的详细内容,更多关于AlexNet分类模型训练猫狗数据集的资料请关注其它相关文章!

    声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。