我一直強調作深度學習,最好是結合實際的數據上手,參照理論,對知識的掌握纔會更加全面。先了解原理,而後找一匹數據來驗證,這樣會不斷加深對理論的理解。html
歡迎留言與交流!python
數據來源: cifar10 (其餘相關的圖片的開源數據集下載見 : https://yq.aliyun.com/articles/576274 ) 文末有所有代碼web
PS:神經網絡系列多用於圖像,文字的生成,解析,識別。所以須要掌握充足的開源數據集來驗證所學的算法理論。算法
首先下載好數據後解壓。數據的樣子以下: data_batch1-5是訓練集數據,test_batch是驗證集, batches.meta是10個標籤的含義網絡
接下來分兩個大步驟:session
一是數據處理,使其符合模型的輸入接口。app
二是模型搭建,爲了訓練出準確有效的模型。框架
在python環境下導入須要的庫ide
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()#必要-用以解決重複調用時會話應結束