tensorflow2.0 CNN fashion MNIST图像分类



fashion MNIST图像分类

数据集简介

  在 2017年8月份,德国研究机构Zalando Research在GitHub上推出了一个全新的数据集——fashion MNIST数据集,其中训练集包含60000个样例,测试集包含 10000个样例,分为10类,每一类的样本训练样本数量和测试样本数量相同。该数据集是一个替代 MNIST手写数据集的图像数据,比 MNIST数据复杂一些。该数据集的数据量较小,适用于用来验证某个算法可否正常运行和机器学习的入门。数据集的样本都来自日常穿着的衣裤鞋包,每个都是 28× 28的灰度图像,其中总共有10类标签,每张图像都有各自的标签,分别是T-shirt/top(T恤)、Trouser(裤子)、Pullover(套衫)、Dress(裙子)、Coat(外套)等10个服装类型,值得注意的是该数据集在我对数据集预处理时,发现其中有一些数据标签错误,这导致了数据在训练之后得不到很高的准确率。

数据的预处理

  在进行分类之前,需要对数据进行归一化。归一化可以加快训练网络的收敛性,归纳统一样本的统计分布特性,这里将数据归一化到0-1之间,使之符合概率分布,也能够加速梯度下降求解除最优解。归一化也可以使用其他的归一算法。归一化代码如下:
x_train, x_test = x_train / 255.0, x_test / 255.0

  本实验采用交叉验证的方法,交叉验证可以缓解单独测试结果的片面性和训练数据不足的问题。在数据预处理之后,需要对数据进行切分,切分为训练集和验证集以及测试集。将50000张测试集的数据中切割48000张图片进行训练,将2000张图片进行测试,最后将10000张图进行测试。具体的宿数据集切分代码如下所示:
#数据集切分
x_valid,x_train=x_train[:2000],x_train[2000:]
y_valid,y_train=y_train[:2000],y_train[2000:]

import tensorflow as tf
import os
from tensorflow import keras
import numpy as np
from matplotlib import pyplot as plt
import time
import math
import random
import numpy
from tqdm import tqdm_notebook as tqdm
from tensorflow.keras.utils import plot_model

#数据预处理
def pretreatment():
    
    '''
    @introduction:数据预处理,将数据归一化,如果必要,可以进行数据混洗;其次将数据分割               
    @return : 
               x_train 训练数据
               y_train 训练数据标签
               x_valid 验证数据
               y_valid 验证数据标签
               x_test 测试数据
               y_test 测试数据标签
    '''
    np.set_printoptions(threshold=np.inf)#控制台输出所有的值,不需要省略号
    fashion = tf.keras.datasets.fashion_mnist
    (x_train, y_train), (x_test, y_test) = fashion.load_data()
    x_train = x_train.reshape([-1,28,28,1])/255.0
    x_test = x_test.reshape([-1,28,28,1])/255.0

    #数据集切分
    x_valid,x_train=x_train[:2000],x_train[2000:]
    y_valid,y_train=y_train[:2000],y_train[2000:]
    return x_valid,x_train,y_valid,y_train,x_test,y_test

CNN简介和构建

  卷积神经网络(CNN)是1998年纽约大学的Yann Lecun在基于感受野和神经认知机的基础上提出的,这个神经网络模型在图像处理的领域取得了巨大成功。该网络相对于传统的神经网络的优势在于它能够通过卷积等一系列操作提取出图像的特征,使具有这些特征的网络能够很好的泛化能力和抽象表达能力。最为关键的是,卷积神经网络为了缓解过拟合和网络参数过多得导致的训练困难,这个模型引入了局部连接,权值共享等非常高明的策略。CNN比较关键在卷积和池化以及非线性映射。卷积层能够有效的提取出图像集的特征,这是提供系统准确率的关键。池化能够有效的减少数据量,并且缓解模型的过拟合问题,池化采用的具体方式则是降采样。非线性映射能够从概率统计的角度提升系统的非线性能力,因为在实际的应用中,线性系统的情况适用性不够宽泛。本实验模型图如下
在这里插入图片描述

模型部分代码

#模型训练
def model_train(x_train,y_train,x_valid,y_valid,choice=False):
    '''
    @introduction:训练模型,根据需求保存模型
    @parameter:   
               x_train 训练数据
               y_train 训练数据标签
               x_valid 验证数据
               y_valid 验证标签
               choice 选择是否读取保存的模型,默认值为不读取
               
    @return : model和history
    '''
    
    #模型处理
    def model_read(model):
        
        save_path = "CNN_new_model.h5"
        if os.path.exists(save_path):#判断文件是否存在
            print('\n')
            print('-------------------******模型读入*****----------------------')
            model=tf.keras.models.load_model(save_path)  
        else:
            print('文件不存在')
        return model
    def model_save(model):
        save_path = "CNN_new_model.h5"
        model.save(save_path)
    
    #模型定义
    model = keras.Sequential([   
        #(-1,28,28,1)->(-1,28,28,32)    
        keras.layers.Conv2D(input_shape=(28, 28, 1),filters=32,kernel_size=5,strides=1,padding='same'),     # Padding method),    
        #(-1,28,28,32)->(-1,14,14,32)    
        keras.layers.MaxPool2D(pool_size=2,strides=2,padding='same'),    
        #(-1,14,14,32)->(-1,14,14,64)    
        keras.layers.Conv2D(filters=64,kernel_size=3,strides=1,padding='same'),     # Padding method),    #(-1,14,14,64)->(-1,7,7,64)   
        keras.layers.MaxPool2D(pool_size=2,strides=2,padding='same'),    
        #(-1,7,7,64)->(-1,7*7*64)    
        keras.layers.Flatten(),    
        #(-1,7*7*64)->(-1,256)    
        keras.layers.Dense(256, activation=tf.nn.relu),    
        #(-1,256)->(-1,10)    
        keras.layers.Dense(10, activation=tf.nn.softmax)])
    model.summary()
  
    
    #配置参数
    #引入指数衰减学习率或不引入
    ad1 = tf.keras.optimizers.Adam(lr=0.0001, beta_1=0.9, beta_2=0.999, epsilon=1e-08)
    ad2 = 'adam'
    model.compile(optimizer=ad2,
              loss='sparse_categorical_crossentropy',
              metrics=['sparse_categorical_accuracy'])
    
    if choice:
        model=model_read(model)
        history = model.fit(x_train, y_train , batch_size=128, epochs=2, validation_data=(x_valid, y_valid), validation_freq=1)
        #history = model.fit(x_train, y_train, epochs=2, validation_data=(x_valid, y_valid))
        model_save(model)
    else:
        history = model.fit(x_train, y_train,epochs=5, validation_data=(x_valid, y_valid))
        model_save(model)
    return history,model

def model_get():
    '''
    @introduction: 模型读取
    @return: model 已经训练好的模型
    '''
    save_path = "CNN_model.h5"
    if os.path.exists(save_path):#判断文件是否存在
        print('\n>>>>>>>>>>>>模型读入>>>>>>>>>>>>>>>>>>>\n')
        model=tf.keras.models.load_model(save_path)  
        plot_model(model, to_file='CNN_model.jpg',show_shapes=True)
        for i in tqdm(range(100)):
            if(i==99):
                print('模型读入成功!')
    else:
        print('文件不存在')
    return model

#数据可视化
def figshow(history):
    '''
    introductoin:  数据可视化,画出训练损失函数和验证集上的准确率
    '''
    # 显示训练集和验证集的acc和loss曲线
    print('\n\n\n')
    print('----------------------------------------------图像绘制-------------------------------------')
    acc = history.history['sparse_categorical_accuracy']
    val_acc = history.history['val_sparse_categorical_accuracy']
    loss = history.history['loss']
    val_loss = history.history['val_loss']

    plt.subplots(figsize=(8,6))
    plt.plot(acc, label='Training Accuracy')
    plt.plot(val_acc, label='Validation Accuracy')
    plt.title('Training and Validation Accuracy')
    plt.legend()
    plt.show()

    plt.subplots(figsize=(8,6))
    plt.plot(loss, label='Training Loss')
    plt.plot(val_loss, label='Validation Loss')
    plt.title('Training and Validation Loss')
    plt.legend()
    plt.show()

#测试集测试
def data_test(x_test,y_test,model):
    '''
    @introduction :输出模型在测试集上的top1准确率和top2准确率
    @parameter :
               x_test  测试集数据
               y_test  测试数据标签
               model   训练好的模型
    @return :
              top1_acc   top1标准下的准确率
              top2_acc   top2标准下的准确率
    
    '''
    print('****************************test******************************')
    loss, acc = model.evaluate(x_test, y_test)
    top1_acc = acc
    
    #print("test_accuracy:{:5.2f}%".format(100 * acc))
    y_pred = model.predict(x_test)
    k_b = tf.math.top_k(y_pred,2).indices
    idx=0
    acc=0.0
    for i in k_b:
        if y_test[idx] in i.numpy():
            acc=acc+1
        idx=idx+1
    top2_acc=acc/y_test.shape[0] 
    print('top1准确率:{0}\ntop2准确率:{1}'.format(top1_acc,top2_acc))
    return top1_acc,top2_acc

#随机测试20张图片
def random_test(x_test,y_test,model):
    '''
    @introduction: 产生20个不同整数作为下标索引,输出预测值与真实值,两者比较
    @parameter : x_test  测试集数据
                 y_test  测试集标签
                 model  训练好的模型
    
    '''
    def randomNums(a, b, n):#产生n个不同的随机整数
        all_num = list(range(a, b))
        res = []

        while n:
            numpy.random.seed(0)
            index = math.floor(numpy.random.uniform() * len(all_num))
            res.append(all_num[index])
            del all_num[index]
            n -= 1
        return res
    
    test_idx = randomNums(0, 10000,20)  #测试集大小为10000,索引范围是[0,10000)
    
    pred_img=[]  #预测的图片
    d_label=[]   #预测图片的标签
    for i in test_idx:
        pred_img.append(x_test[i])
        d_label.append(y_test[i])
    pred_img = numpy.array(pred_img)#转换为ndarray格式
    pred_prob = model.predict(pred_img)  #预测概率
    pred_label = numpy.argmax(pred_prob,1)  #索引
    
    labels = ['T恤','裤子','套头衫','连衣裙','外套','凉鞋','衬衫','运动鞋','包','靴子']
    plt.figure(figsize=(14,14)) 
    #显示前10张图像,并在图像上显示类别
    for i in range(20):   
        plt.subplot(4,5,i+1)
        plt.grid(False)
        plt.imshow(pred_img[i,:,:,0],cmap=plt.cm.binary)
        plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
        t = labels[pred_label[i]]+'('+labels[d_label[i]]+')'
        plt.title(t) 
    plt.show()


if __name__ == '__main__':

    x_valid,x_train,y_valid,y_train,x_test,y_test = pretreatment()
    #model = model_get()
    history,model = model_train(x_train,y_train,x_valid,y_valid,True)
    #history,model = model_train(x_train,y_train,x_valid,y_valid)
    figshow(history)
    #data_test(x_test,y_test,model)
    
    #random_test(x_test,y_test,model)

CNN实验结果

 模型采用分步进行训练能够尽可能的让神经网络学习到更多特征,所以实验分为两步,第一步先使用默认的学习率进行训练,神经网络迭代5次得到初步的模型。模型在训练集和测试集上的准确率在不断的提升,且系统的损失函数都呈现下降趋势。Top1和Top准确率分别为90.83%和97.74%,神经网络的预测准确率有所上升。
1.初步训练和验证准确率
初步训练和验证准确率
2.初步训练和验证的损失函数
在这里插入图片描述
3.初步Top1和Top2准确率
在这里插入图片描述
 实验进行第二次训练,能够有效的提高预测准确率。首先,将第一次训练的模型读出,再较小的学习率的基础上进行学习,能够尽可能的求得系统的最优值。具体实验操作是将学习率降低为0.001,再将第一步的模型迭代2次后得到最后的模型。最终再训练完成之后,模型的Top1和Top2准确率分别为92.44%和98.21%,此时的Top2也提高了,说明数据更加集中于准确值,模型的预测准确率进一步提高。在测试集上随机输入20个数据进行预测,实验显示的20张图片中,第一张图片预测错误,其他20张图片预测准确。这说明,模型在一定程度上能够较为准确的对数据集进行fashion_MNIST进行分类处理。
1.最终模型准确率在这里插入图片描述
2.最终模型Top1和Top2准确率
在这里插入图片描述
3.随机输出模型预测
在这里插入图片描述

致谢

感谢诸君观看,如果感觉有用的话,点个赞吧!🎉



  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值