zoukankan      html  css  js  c++  java
  • CNN实战篇-手把手教你利用开源数据进行图像识别(基于keras搭建)

    我一直强调做深度学习,最好是结合实际的数据上手,参照理论,对知识的掌握才会更加全面。先了解原理,然后找一匹数据来验证,这样会不断加深对理论的理解。

     欢迎留言与交流!

    数据来源: cifar10  (其他相关的图片的开源数据集下载见 : https://yq.aliyun.com/articles/576274 文末有全部代码

    PS:神经网络系列多用于图像,文字的生成,解析,识别。因此需要掌握充足的开源数据集来验证所学的算法理论。

    首先下载好数据后解压。数据的样子如下: data_batch1-5是训练集数据,test_batch是验证集, batches.meta是10个标签的含义

    接下来分两个大步骤:

    一是数据处理,使其符合模型的输入接口。

    二是模型搭建,为了训练出准确有效的模型。

    • 数据处理部分:

    在python环境下导入需要的库

    import numpy as np
    import pandas as pd
    import matplotlib.pyplot as plt
    import tensorflow as tf
    from tensorflow import keras
    from keras import backend as K
    K.set_image_dim_ordering('tf') 
    from keras.applications.imagenet_utils import preprocess_input, decode_predictions
    from keras.preprocessing import image

    之后我们先导入并观察数据,处理成keras 搭建的模型可使用的格式。

    导入代码:

    # 定义读取方法
    def unpickle(file):
        import pickle
        with open(file, 'rb') as fo:
            dict = pickle.load(fo, encoding='bytes')
        return dict
    
    # 读取CIFAR10数据
    cifar={}
    # 合并5个训练集
    for i in range(5):    
        cifar1=unpickle('data_batch_'+str(i+1))
        if i==0:
            cifar[b'data']=cifar1[b'data']
            cifar[b'labels']=cifar1[b'labels']
        else:
            cifar[b'data']=np.vstack([cifar1[b'data'],cifar[b'data']])
            cifar[b'labels']=np.hstack([cifar1[b'labels'],cifar[b'labels']])
    # label的含义 写在 batches.meta文件里
    target_name=unpickle('batches.meta')
    cifar[b'label_names']=target_name[b'label_names']    
    
    # 测试集读取
    cifar_test=unpickle('test_batch')
    cifar_test[b'labels']=np.array(cifar_test[b'labels'])

     合并之后,我们观察一下数据:

    发现是rgb三通道数据拉伸成一维的像素了,即原来为32x32x3的rgb图像,变成了3072个行像素。
    如下图:

     

    那么接下来要做的就是还原数据,并看一下打好标签的10类对应的图片长什么样子

    # 定义数据格式 将原三通道的一维数据还原至三通道的二维图片格式
    blank_image= np.zeros((len(cifar[b'data']),32,32,3), np.uint8) #定义一个rpb图的集合
    blank_image2= np.zeros((len(cifar[b'data']),32,32), np.uint8) #定义一个灰度图的集合 稍后写入
    for i in range(len(cifar[b'data'])):
        blank_image[i] = np.zeros((32,32,3), np.uint8) 
        blank_image[i][:,:,0]=cifar[b'data'][i][0:1024].reshape(32,32) #前1024个像素还原为32x32并写入到rgb的第一个red通道.
        blank_image[i][:,:,1]=cifar[b'data'][i][1024:1024*2].reshape(32,32) #中间1024个像素还原为32x32并写入到rgb的第二个green通道.
        blank_image[i][:,:,2]=cifar[b'data'][i][1024*2:1024*3].reshape(32,32) #后1024个像素还原为32x32并写入到rgb的第三个blue通道.
    cifar[b'data']=blank_image
    cifar[b'data2']=blank_image2

    至此测试集还原完毕,可以看到测试集cifar[b'data']变成:

     

    接着同理处理一下验证集,不做详述了:

    # 测试集图片数据还原
    blank_image= np.zeros((len(cifar_test[b'data']),32,32,3), np.uint8)
    blank_image2= np.zeros((len(cifar_test[b'data']),32,32), np.uint8) #定义一个灰度图的集合 稍后写入
    for i in range(len(cifar_test[b'data'])):
        blank_image[i] = np.zeros((32,32,3), np.uint8)
        blank_image[i][:,:,0]=cifar_test[b'data'][i][0:1024].reshape(32,32)
        blank_image[i][:,:,1]=cifar_test[b'data'][i][1024:1024*2].reshape(32,32)
        blank_image[i][:,:,2]=cifar_test[b'data'][i][1024*2:1024*3].reshape(32,32)
    
    # data2处理成黑白 data处理为彩色
    cifar_test[b'data']=blank_image
    cifar_test[b'data2']=blank_image2

    我们选10个种类 各画一张图观察一下:

    # 画图关闭
    target_list=pd.Series(cifar[b'labels']).drop_duplicates() # labels去重
    target_list=target_list.sort_values()  # labels排序
    target_list=list(target_list.index) # 提取后即为10个标签对应的测试集的位置,找出这些位置的图画出来即可
    target_figure=cifar[b'data'][target_list];
    
    for i in range(10):
        plt.subplot(2,5,1+i)
        plt.imshow(target_figure[i]),plt.axis('off') 

    数据集的10个label图:

     

    现在到了数据处理的最后一步,定义测试集和训练集,并归一化:

    # 训练数据集定义,训练集,测试集归一化
    x_train=cifar[b'data'] # 训练集数据
    y_train=cifar[b'labels'] # 训练集标签
    x_test=cifar_test[b'data'] # 验证集标签
    y_test=cifar_test[b'labels'] # 验证集标签
    
    x_train=x_train.reshape(-1,32,32,3) # 训练集格式确保为32x32的rgb三通道格式
    x_test=x_test.reshape(-1,32,32,3)  #  验证集同理
    class_names=cifar[b'label_names'];
    
    x_train = x_train.astype('float32') 
    x_test = x_test.astype('float32')
    x_train=x_train/255 #将像素的0到255 归一化至0-1
    x_test=x_test/255

    至此数据处理部分完毕,等待模型建立后调用即可。

    • 模型建立部分:
    # 由经典卷积神经模型 VGG16 简化而来
    model = tf.keras.models.Sequential([ #此处可简化,但须均维持keras格式或者tf格式
            
      tf.keras.layers.Conv2D(32,
                             kernel_size=(3, 3), 
                             padding='same',
                             activation='relu',
                             input_shape=(32,32,3)
                             ),      #第一层卷积 卷积核为3x3    
                             
      tf.keras.layers.Conv2D(32,
                             kernel_size=(3,3),
                             activation='relu',
                             padding='same',
                             data_format='channels_last',
                             ),     #第二层卷积 卷积核为3x3
    
      tf.keras.layers.MaxPooling2D(pool_size=(2, 2)), # 池化 缩小  
      tf.keras.layers.Dropout(0.25),  # 防止过拟合
                             
      tf.keras.layers.Conv2D(64,
                             kernel_size=(3, 3), 
                             padding='same',
                             activation='relu',
                             input_shape=(32,32,1)
                             ),          
                             
      tf.keras.layers.Conv2D(64,
                             kernel_size=(3,3),
                             activation='relu',
                             padding='same',
                             data_format='channels_last',
                             ),
    
      tf.keras.layers.MaxPooling2D(pool_size=(2, 2)), # 池化缩小  
      tf.keras.layers.Dropout(0.25),   # 防止过拟合
      
      tf.keras.layers.Flatten(),  # 将所有特征展平为一维
      
      tf.keras.layers.Dense(512,activation='relu'), # 与一个512节点全链接,激活条件 relu
      tf.keras.layers.Dropout(0.5),           
    
      tf.keras.layers.Dense(10,activation=tf.nn.softmax) # 分类专用激活函数 softmax
      ])

    CNN框架解析: 按照步骤来--->

      1. 输入rgb图片32x32x3:(一共有50000个,一个一个来)

      2. 经过第一次卷积变成了 32x32x32,

    (第一步卷积说明: 按照我们参数的设置建立了32个神经元,每个神经元由一个3x3x3的卷积核,也就是32个不同的卷积核卷积后形成了32个不同的特征,因此卷积后将32x32x3大小的图特征维度变成了32。其中每一个神经元有3x3x3+1(bias)个权重。 )

      3. 经过第二次卷积变成了 32x32x32,

      4. 再经过2x2的步长为2的池化(最大池化法),缩小一倍。

      5. 经过第三次卷积变成了 32x32x64,

      6. 经过第四次卷积变成了 32x32x64,

      7. 再经过2x2的步长为2的池化,缩小一倍

      8. 随后拉伸为一维和一个512节点进行全连接,

      9. 再与一个10个节点全连接)

     

     

    这一部分对应下图:

     

    模型搭建好以后就要开始使用它,即模型编译与开始训练:

    # 模型编译
    model.compile(optimizer='adam',# keras.optimizers.Adadelta()
                  loss='sparse_categorical_crossentropy',
                  metrics=['accuracy'])
    
    # 模型加载训练集  callbacks=tensorboard 监控
    model.fit(x_train, y_train,batch_size=32, epochs=10,verbose=1, validation_data=(x_test, y_test),
              callbacks=[keras.callbacks.TensorBoard(log_dir='./tmp/keras_log',write_images=1, histogram_freq=1),
                         ]) #verbos 输出日志 keras.callbacks.EarlyStopping(patience=10, monitor='val_acc')
        
    # epochs 数据集所有样本跑过一遍的次数 搭配 batch_size多少个一组进行训练 调整权重
    model.evaluate(x_test, y_test,verbose=0)

      这一部分的核心是需要了解 优化器,loss函数的不同种类和适用范围。即 model.compile中

    optimizer 和 loss 的定义


    待训练完毕后 可以加载tensorboard观察模型和训练过程:
    # tensorboard 加载监控
    import webbrowser
    url='http://a1414l039:6006'
    webbrowser.open(url, new=0, autoraise=True)
    import os
    cmd='cd /d '+os.getcwd()+'\tmp && tensorboard --logdir keras_log'
    os.system(cmd)
    keras.backend.clear_session()#必要-用以解决重复调用时会话应结束

    跑10轮后正确率在验证集和训练集基本维持在78%以上了。

    如果需要提高精确度可以适当将全连接层的节点数放大,比如512换成1000.

    如果图片大于32x32的话,根据情况拓展卷积的深度。

     整体代码附上:

    # -*- coding: utf-8 -*-
    """
    Created on Thu Jan 27 14:29:54 2019
    
    @author: wenzhe.tian
    """
    
    import numpy as np
    import pandas as pd
    import matplotlib.pyplot as plt
    import tensorflow as tf
    from tensorflow import keras
    from keras import backend as K
    K.set_image_dim_ordering('tf') 
    from keras.applications.imagenet_utils import preprocess_input, decode_predictions
    from keras.preprocessing import image
    
    
    # 定义读取方法
    def unpickle(file):
        import pickle
        with open(file, 'rb') as fo:
            dict = pickle.load(fo, encoding='bytes')
        return dict
    
    # 读取CIFAR10数据
    cifar={}
    # 合并给5个训练集
    for i in range(5):    
        cifar1=unpickle('data_batch_'+str(i+1))
        if i==0:
            cifar[b'data']=cifar1[b'data']
            cifar[b'labels']=cifar1[b'labels']
        else:
            cifar[b'data']=np.vstack([cifar1[b'data'],cifar[b'data']])
            cifar[b'labels']=np.hstack([cifar1[b'labels'],cifar[b'labels']])
    # label的含义 写在 batches.meta文件里
    target_name=unpickle('batches.meta')
    cifar[b'label_names']=target_name[b'label_names']    
    
    # 测试集读取
    cifar_test=unpickle('test_batch')
    cifar_test[b'labels']=np.array(cifar_test[b'labels'])
    
    
    # 定义数据格式 将原三通道的一维数据还原至三通道的二维图片格式
    blank_image= np.zeros((len(cifar[b'data']),32,32,3), np.uint8) #定义一个rpb图的集合
    blank_image2= np.zeros((len(cifar[b'data']),32,32), np.uint8) #定义一个灰度图的集合 稍后写入
    for i in range(len(cifar[b'data'])):
        blank_image[i] = np.zeros((32,32,3), np.uint8) 
        blank_image[i][:,:,0]=cifar[b'data'][i][0:1024].reshape(32,32) #前1024个像素还原为32x32并写入到rgb的第一个red通道.
        blank_image[i][:,:,1]=cifar[b'data'][i][1024:1024*2].reshape(32,32) #中间1024个像素还原为32x32并写入到rgb的第二个green通道.
        blank_image[i][:,:,2]=cifar[b'data'][i][1024*2:1024*3].reshape(32,32) #后1024个像素还原为32x32并写入到rgb的第三个blue通道.
    cifar[b'data']=blank_image
    cifar[b'data2']=blank_image2
    
    # 测试集图片数据还原
    blank_image= np.zeros((len(cifar_test[b'data']),32,32,3), np.uint8)
    blank_image2= np.zeros((len(cifar_test[b'data']),32,32), np.uint8) #定义一个灰度图的集合 稍后写入
    for i in range(len(cifar_test[b'data'])):
        blank_image[i] = np.zeros((32,32,3), np.uint8)
        blank_image[i][:,:,0]=cifar_test[b'data'][i][0:1024].reshape(32,32)
        blank_image[i][:,:,1]=cifar_test[b'data'][i][1024:1024*2].reshape(32,32)
        blank_image[i][:,:,2]=cifar_test[b'data'][i][1024*2:1024*3].reshape(32,32)
    
    # data2处理成黑白 data处理为彩色
    cifar_test[b'data']=blank_image
    cifar_test[b'data2']=blank_image2
    
    # 画图关闭
    #target_list=pd.Series(cifar[b'labels']).drop_duplicates() # labels去重
    #target_list=target_list.sort_values()  # labels排序
    #target_list=list(target_list.index) # 提取后即为10个标签对应的测试集的位置,找出这些位置的图画出来即可
    #target_figure=cifar[b'data'][target_list];
    #
    #for i in range(10):
    #    plt.subplot(2,5,1+i)
    #    plt.imshow(target_figure[i]),plt.axis('off') 
    
    
    # 转化为灰度预测    
    def rgb2gray(rgb):
        r, g, b = rgb[:,:,0], rgb[:,:,1], rgb[:,:,2]
        gray = 0.2989 * r + 0.5870 * g + 0.1140 * b
        return gray
    
    for i in range(len(cifar_test[b'data'])):
        temp=rgb2gray(cifar_test[b'data'][i])
        cifar_test[b'data2'][i]=temp
    
    for i in range(len(cifar[b'data'])):
        temp=rgb2gray(cifar[b'data'][i])
        cifar[b'data2'][i]=temp
    
    # 训练数据集定义,训练集,测试集归一化
    x_train=cifar[b'data'] # 训练集数据
    y_train=cifar[b'labels'] # 训练集标签
    x_test=cifar_test[b'data'] # 验证集标签
    y_test=cifar_test[b'labels'] # 验证集标签
    
    x_train=x_train.reshape(-1,32,32,3) # 训练集格式确保为32x32的rgb三通道格式
    x_test=x_test.reshape(-1,32,32,3)  #  验证集同理
    class_names=cifar[b'label_names'];
    
    x_train = x_train.astype('float32') 
    x_test = x_test.astype('float32')
    x_train=x_train/255 #将像素的0到255 归一化至0-1
    x_test=x_test/255
    
    # 由经典卷积神经模型 VGG16 简化而来
    model = tf.keras.models.Sequential([ #此处可简化,但须均维持keras格式或者tf格式
            
      tf.keras.layers.Conv2D(32,
                             kernel_size=(3, 3), 
                             padding='same',
                             activation='relu',
                             input_shape=(32,32,3)
                             ),      #第一层卷积 卷积核为3x3    
                             
      tf.keras.layers.Conv2D(32,
                             kernel_size=(3,3),
                             activation='relu',
                             padding='same',
                             data_format='channels_last',
                             ),     #第二层卷积 卷积核为3x3
    
      tf.keras.layers.MaxPooling2D(pool_size=(2, 2)), # 池化 缩小  
      tf.keras.layers.Dropout(0.25),  # 防止过拟合
                             
      tf.keras.layers.Conv2D(64,
                             kernel_size=(3, 3), 
                             padding='same',
                             activation='relu',
                             input_shape=(32,32,1)
                             ),          
                             
      tf.keras.layers.Conv2D(64,
                             kernel_size=(3,3),
                             activation='relu',
                             padding='same',
                             data_format='channels_last',
                             ),
    
      tf.keras.layers.MaxPooling2D(pool_size=(2, 2)), # 池化缩小  
      tf.keras.layers.Dropout(0.25),   # 防止过拟合
      
      tf.keras.layers.Flatten(),  # 将所有特征展平为一维
      
      tf.keras.layers.Dense(512,activation='relu'), # 与一个512节点全链接,激活条件 relu
      tf.keras.layers.Dropout(0.5),           
    
      tf.keras.layers.Dense(10,activation=tf.nn.softmax) # 分类专用激活函数 softmax
      ])
    
    
    # 模型编译
    model.compile(optimizer='adam',# keras.optimizers.Adadelta()
                  loss='sparse_categorical_crossentropy',#tf.keras.losses.categorical_crossentropy会造成单一种类标签
                  metrics=['accuracy'])
    
    # 模型加载训练集  callbacks=tensorboard 监控
    model.fit(x_train, y_train,batch_size=32, epochs=10,verbose=1, validation_data=(x_test, y_test),
              callbacks=[keras.callbacks.TensorBoard(log_dir='./tmp/keras_log',write_images=1, histogram_freq=1),
                         ]) #verbos 输出日志 keras.callbacks.EarlyStopping(patience=10, monitor='val_acc')
        
    # epochs 数据集所有样本跑过一遍的次数 搭配 batch_size多少个一组进行训练 调整权重
    model.evaluate(x_test, y_test,verbose=0)
    
    
    
    # tensorboard 加载监控
    import webbrowser
    url='http://a1414l039:6006'
    webbrowser.open(url, new=0, autoraise=True)
    import os
    cmd='cd /d '+os.getcwd()+'\tmp && tensorboard --logdir keras_log'
    os.system(cmd)
    
    
    
    # 经过图像处理后的手机图片预测结果
    #plt.figure(figsize=(10,10))
    #for i in range(6):
    #    plt.subplot(3,2,i+1)
    #    plt.xticks([])
    #    plt.yticks([])
    #    plt.grid(False)
    #    plt.imshow(temp_test_ori[i], cmap=plt.cm.binary)
    #    plt.xlabel(answer[i])
    
    '''
    保存模型 加载权重
    '''
    
    # Returns a short sequential model
    keras.backend.clear_session()#必要-用以解决重复调用时会话应结束
    View Code
  • 相关阅读:
    List of the best open source software applications
    Owin对Asp.net Web的扩展
    NSwag给api加上说明
    'workspace' in VS Code
    unable to find valid certification path to requested target
    JMeter的下载以及安装使用
    exception disappear when forgot to await an async method
    Filter execute order in asp.net web api
    记录web api的request以及response(即写log)
    asp.net web api的源码
  • 原文地址:https://www.cnblogs.com/techs-wenzhe/p/11102998.html
Copyright © 2011-2022 走看看