美文网首页
cifar 图像分类

cifar 图像分类

作者: 此间不留白 | 来源:发表于2020-01-05 20:14 被阅读0次

    前言

    cifar-9 分类图像数据集是从cifar10图像数据集中提取出的包含9个分类的图像数据集,cifar图像官网提供了cifar10图像数据集和cifar100图像数据集的下载。本次竞赛中,官方给定的数据集是从cifar10图像数据集中剔除掉“青蛙”这个类别的数据集。所有的图像都是32×32×3的RGB彩色图像。

    数据预处理

    比赛方提供的包含训练数据集和测试数据集的压缩包,每个目录的名称代表目录中数据的标签。在整个任务之前,首先,需要对数据集进行预处理。
    数据的文件结构如下所示:



    对原始的图像数据进行处理,主要分为以下几个步骤:

    原始图像写入csv表格中

    为了方便对数据进行操作,采用将图像数据以矩阵的方式写入csv中的方法,csv中,第一列表示图像的标签,用0-8这几个数字依次表示9个分类,1-3073类表示32×32×3的像素值。具体代码如下所示:

    • 解压图像数据
    with zipfile.ZipFile("cifarData.zip") as zf:
        zf.extractall()
    
    • 获得训练集和测试集的所有标签
      按照文件目录,图像的标签即是当前图像所在文件夹(目录)的名称,则有如下代码:
    #获得所有标签
    train_label = [] #训练集标签
    test_label = [] #测试集标签
    for i in os.listdir('data/train'):
        train_label.append(i)
    for i in os.listdir('data/test'):
        test_label.append(i)
        
    
    • 将图像数据写入csv文件中
      参数mode代表了写入数据集的类别,即训练集数据还是测试集数据
    
    import cv
    import csv
    label_num = 0
    def writeDataAsCsv(mode,fileName):
        with open(fileName,"w",newline="") as f:
            column_name=["lable"]
            for i in range(3072):
                column_name.extend(["pix"+str(i)])
            write = csv.writer(f)
            write.writerow(column_name)
           if mode==”test“:
            for i in test_label:
                for j in os.walk('data/'+str(mode)+'/'+str(i)):
                    #print(i,j[2])
                    #print(train_label.index(i))
                    for k in j[2]:
                        img = cv2.imread("./data/"+str(mode)+"/"+str(i)+'/'+str(k))
                    
                        row_data = [test_label.index(i)]
                        row_data.extend(img.flatten())
                        write.writerow(row_data)
    
    
    • 对数据集归一化和one-hot编码
      对数据集进行归一化和one-hot编码之前,首先需要加载csv格式的数据,为了加快加载数据的速度,可以采用dask.dataframe替代常用的pandas.DataFrame,并且需要对csv中数据的顺序随机调整(类似于洗牌操作)具体代码如下所示:
    import dask.dataframe as dd
    import numpy as np
    import pandas as pd
    train_data = dd.read_csv("train.csv",engine='python')
    train_data = train_data.sample(frac=1)
    test_data = dd.read_csv("test.csv",engine='python')
    test_data = test_data.sample(frac=1)
    
    #标签数据和图像数据进行划分
    train_y = train_data['lable']
    train_x = train_data.drop('lable',axis=1)
    test_y = test_data['lable']
    test_x = test_data.drop('lable',axis=1)
    
    train_x = np.array(train_x).astype('float32')/255
    test_x = np.array(test_x).astype('float32')/255
    
    train_x = train_x.reshape(train_x.shape[0],32,32,3)
    test_x = test_x.reshape((test_x.shape[0],32,32,3))
    from keras.utils import np_utils
    train_y = np_utils.to_categorical(train_y,9)
    test_y = np_utils.to_categorical(test_y,9)
    

    搭建模型

    模型的结构是一个20层resnet的模型,每6层之间用一个shortcut路径进行连接,模型结构的代码如下所示:

    # 残差模块
    def resnet_block(inputs,num_filters=16, kernel_size=3,strides=1, activation='relu'):
        x = Conv2D(num_filters,kernel_size=kernel_size,strides=strides,padding='same',
               kernel_initializer='he_normal',kernel_regularizer=l2(1e-4))(inputs)
        x = BatchNormalization()(x)
        if(activation):
            x = Activation('relu')(x)
        return x
    def resnet_v1(input_shape):
        inputs = Input(shape=input_shape)# Input层,用来当做占位使用
    
        #第一层
        x = resnet_block(inputs)
        print('layer1,xshape:',x.shape)
        # 第2~7层
        for i in range(6):
            a = resnet_block(inputs = x)
            b = resnet_block(inputs=a,activation=None)
            x = keras.layers.add([x,b])
            x = Activation('relu')(x)
        # out:32*32*16
        # 第8~13层
        for i in range(6):
            if i == 0:
                a = resnet_block(inputs = x,strides=2,num_filters=32)
            else:
                a = resnet_block(inputs = x,num_filters=32)
            b = resnet_block(inputs=a,activation=None,num_filters=32)
            if i==0:
                x = Conv2D(32,kernel_size=3,strides=2,padding='same',
                           kernel_initializer='he_normal',kernel_regularizer=l2(1e-4))(x)
            x = keras.layers.add([x,b])
            x = Activation('relu')(x)
        # out:16*16*32
        # 第14~19层
        for i in range(6):
            if i ==0 :
                a = resnet_block(inputs = x,strides=2,num_filters=64)
            else:
                a = resnet_block(inputs = x,num_filters=64)
    
            b = resnet_block(inputs=a,activation=None,num_filters=64)
            if i == 0:
                x = Conv2D(64,kernel_size=3,strides=2,padding='same',
                           kernel_initializer='he_normal',kernel_regularizer=l2(1e-4))(x)
            x = keras.layers.add([x,b])# 相加操作,要求x、b shape完全一致
            x = Activation('relu')(x)
        # out:8*8*64
        # 第20层 
        x = AveragePooling2D(pool_size=2)(x)
        # out:4*4*64
        y = Flatten()(x)
        # out:1024
        outputs = Dense(9,activation='softmax',
                        kernel_initializer='he_normal')(y)
    
        #初始化模型
        #之前的操作只是将多个神经网络层进行了相连,通过下面这一句的初始化操作,才算真正完成了一个模型的结构初始化
        model = Model(inputs=inputs,outputs=outputs)
        return model
    

    拟合模型

    模型实现之后,在拟合之前,可以实现数据增强增加模型的泛化能力,利用学习率衰减获得损失函数最优解,利用checkpoint保存模型的最佳的权重参数,具体如下代码所示:

    checkpoint = ModelCheckpoint(filepath='./cifar10_resnet_ckpt.h5',monitor='val_acc',
                                 verbose=1,save_best_only=True)
    def lr_sch(epoch):
        #200 total
        if epoch <50:
            return 1e-3
        if 50<=epoch<100:
            return 1e-4
        if epoch>=100:
            return 1e-5
    lr_scheduler = LearningRateScheduler(lr_sch)
    lr_reducer = ReduceLROnPlateau(monitor='val_acc',factor=0.2,patience=5,
                                   mode='max',min_lr=1e-3)
    callbacks = [checkpoint,lr_scheduler,lr_reducer]
    
    batch_size = 64
    data_generator = tf.keras.preprocessing.image.ImageDataGenerator(width_shift_range=0.1, height_shift_range=0.1, horizontal_flip=True)
    train_generator = data_generator.flow(train_x, train_y, batch_size)
    steps_per_epoch = train_x.shape[0] // batch_size
    model.fit_generator(train_generator, validation_data=(test_x, test_y), steps_per_epoch=steps_per_epoch, epochs=200,callbacks=callbacks)
    

    做出预测

    训练完成之后,利用保存好的模型权重参数进行预测,如下代码所示

    
    from keras.models import load_model
    load_model = load_model("./cifar9_resnet_ckpt.h5")
    pred = load_model.predict(test_x)
    

    模型预测的输出是one-hot形式的编码,对one-hot编码的形式进行整理,并将预测结果与对应图片名写入csv文件中,如下所示:

    label = np.argmax(pred,axis=1)
    data_row_img=[]
    data_row_label=[]
    path = "./data/test/"
    for i in test_label:
        for j in os.walk(path+i+"/"):
            for k in j[2]:
                data_row_img.append(k)
            
    for j in label:
        data_row_label.append(test_label[j])
    pred_data = pd.DataFrame({"Img_file":data_row_img,"Label":data_row_label})
    
    pred_data.to_csv("submission.csv",index=False)
    
    

    参考:http://www.voidcn.com/article/p-cguqgdal-brn.html
    https://arxiv.org/pdf/1512.03385.pdf

    相关文章

      网友评论

          本文标题:cifar 图像分类

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