ILSVRC(ImageNet Large Scale Visual Recognition Challenge)分類比賽。AlexNet 2012年冠軍(top-5錯誤率16.4%,額外數據15.3%,8層神經網路)。VGGNet 2014年亞軍(top-5錯誤率7.3%,19層神經網路)。Goo ...
ILSVRC(ImageNet Large Scale Visual Recognition Challenge)分類比賽。AlexNet 2012年冠軍(top-5錯誤率16.4%,額外數據15.3%,8層神經網路)。VGGNet 2014年亞軍(top-5錯誤率7.3%,19層神經網路)。Google Inception 2014年冠軍(top-5錯誤率6.7%,22層神經網路)。ResNet 2015年冠軍(top-5錯誤率3.57%,152層神經網路)。人眼錯誤率5.1%。捲積神經網路基本解決ImageNet數據集圖片分類問題。
ImageNet,2007年斯坦福大學李飛飛教授創辦,收集大量帶標註信息圖片數據供電腦視覺模型訓練。1500萬張標註高清圖片,22000類,100萬張標註圖片主要物體定位邊框。眼睛生物照相機,每200ms拍一張,3歲已經上億張。ImageNet下載互聯網10億張圖片,亞馬遜土耳其機器人平臺眾包標註過程,167個國家5萬名工作者篩選標註。每年ILSVRC比賽數據120萬張圖片,1000類標註。top-5、top-1分類錯誤率模型性能評測指標。
2012年,Hinton學生Alex Krizhevsky提出LeNet更深更寬版深度神經網路模型AlexNet。首次在CNN用ReLU、Dropout、LRN等Trick。GPU運算加速。開源GPU訓紅捲積神經網路CUDA代碼。6億3000萬連接,6000萬參數,65萬神經元,5個捲積層,3個捲積層後連最大池化層,3個全連接層。top-5錯誤率16.4%。第二名26.2%。神經網路低谷期後第一次發聲,確立深度學習(深度捲積網路)電腦視覺統治地位,推動深度學習語音識別、自然語言處理、強化學習領域拓展。
成功使用ReLU CNN激活函數,驗證較深網路效果超過Sigmoid,解決梯度彌散問題。訓練用Dropout隨機忽略部分神經元,避免模型過擬合。CNN用重疊最大池化,避免平均池化模糊化效果,步長比池化核尺寸小,池化層輸出重疊覆蓋,提升特征豐富性。LRN層,創建局部神經元活動競爭機制,響應較大值變更大,抑制其他反饋較小神經元,增強模型泛化能力。CUDA加速深度捲積網路訓練,並行計算大量矩陣,GPU通信方便,互相訪問顯存,只在網路某些層進行,控制通信性能損耗。數據增強,隨機從256x256原始圖像截取224x224區域,水平翻轉鏡像,增加(256-224)^2x2=2048倍數據量,減輕過擬合,提升泛化能力,預測取圖片四角加中間5個位置,左右翻轉,10張圖片,10次預測結果求均值,圖像RGB數據PCA處理,主成分標準差0.1高斯擾動,增加雜訊,錯誤率下降1%。
8個參數訓練層(不包括池化層、LRN層),前5捲積層,後3全連接層。最後一層1000類輸出Softmax層分類。LRN層在第1、2捲積層後,最大池化層在LRN層、最後捲積層後。ReLU激活函數在每個參數層後。
AlexNet超參數:
params AlexNext FLOPs
4M FC1000 4M
16M FC4096/ReLU 4M
37M FC4096/ReLU 37M
Max Pool 3x3s2
442K Conv 3x3s1,256/ReLU 74M
1.3M Conv 3x3s1,384/ReLU 112M
884K Conv 3x3s1,384/ReLU 149M
Max Pool 3x3s2
Local Response Norm
307K Conv 5x5s1,256/ReLU 223M
Max Pool 3x3s2
Local Response Norm
35K Conv 11x11s4,96/ReLU 105M
輸入圖片尺寸224x224,第一卷積層捲積核尺寸11x11,步長4,96個捲積核。LRN層。3x3 最大池化層,步長2。後續捲積核5x5或3x3,步長2。通過較小參數提取有效特征。
導入系統庫datetime、math、time,載入TensorFlow。
batch_size 32,num_batches 100,共測試100個batch數據。
定義網路結構顯示函數print_actications,捲積層或池化層輸出tensor尺寸。接受tensor輸入,顯示名稱(t.op.name)、tensor尺寸(t.get_shape.as_list())。
網路結構。定義inference函數,接受images輸入,返回最後一層pool5(第5個池化層)及parameters(模型參數)。多個捲積層、池化層。
第一卷積層conv1,TensorFlow name_scope,with tf.name_scope('conv1') as scope,scope內生成Variable自動命名為conv1/xxx,區分不同捲積層組件。定義第一卷積層,tf.truncated_normal截斷正態分佈函數(標準差0.1),初始化捲積核參數kernel。捲積核尺寸11x11,顏色通道3,捲積核64。tf.nn.conv2d捲積images,strides步長4x4(圖片每4x4區域只取樣一次,橫向間隔4,縱向間隔4,取樣捲積核尺寸11x11),padding模式SAME。捲積層biases全初始化0。tf.nn.bias_add,conv、biases加。用激活函數tf.nn.relu結果非線性。print_activations 列印最後輸出tensor conv1結構。可訓練參數kernel、biases添加parameters。
第一卷積層後添加LRN層、最大池化層。tf.nn.lrn LRN處理前面輸出tensor conv1,depth_radius 4,bias 1,alpha 0.001/9,beta 0.75。其他經典捲積神經網路放充LRN。LRN讓前饋、反饋速度下降到1/3。tf.nn.max_pool 最大池化處理前面輸出lrn1,尺寸 3x3,3x3像素塊降為1x1像素,取樣步長2x2,padding模式VALID,取樣不超過邊框,不填充邊界外點(SAME)。列印輸出結果pool1結構。
第二捲積層,捲積核尺寸5x5,輸入通道數 64(上一層輸出通道數,上一層捲積核數量),捲積核192,步長1,掃描全圖像素。
處理第二捲積層輸出conv2,先LRN處理,再最大池化。
第三捲積層,捲積核尺寸3x3,輸入通道數 192,捲積核 384,步長1。
第四捲積層,捲積核尺寸3x3,輸入通道數 384,捲積核 256,步長1。
第五捲積層,捲積核尺寸3x3,輸入通道數 256,捲積核 256,步長1。
最大池化層,返回池化層輸出pool5。捲積結束。
3個全連接層,隱含節點4096、4096、1000,計算量很小。
評估AlexNet每輪計算時間函數time_tensorflow_run。第一輸入TensorFlow Session,第二變數評測運算運算元,第三變數測試名稱。定義預熱輪數num_steps_burn_in=10,給程式熱身,頭幾輪迭代顯存載入、cache命中問題跳過,10輪迭代後計算時間。記錄總時間total_duration、平方和total_duration_squared,計算方差。
num_batches+num_steps_burn_in次迭代計算,time.time()記錄時間,session.run(target)執行每次迭代。初始熱身num_steps_burn_in次迭代後,每10輪迭代顯示當前迭代時間。每輪total_duration、total_duration_squared累加。
迴圈結束,計算每輪耗時均值mn、標準差sd,顯示結果。
主函數run_benchmark。with tf.Graph().as_default()定義預設Graph。tf.random_nomal函數構造正態頒上(標準差 0.1)隨機tensor,第一維度batch_size,每輪迭代樣本數,第二、三維度圖片尺寸image_size 224,第四維度圖片顏色通道數。inference函數構建整個AlexNet網路,最後池化層輸出pool5,訓練參數集合parameters。tf.Session()創建新Session,tf.global_variables_initializer()初始化所有參數。
AlexNet forward計算評測,time_tensorflow_run 統計運算時間,傳入target pool5,捲積網路最後池化層輸出。backward 訓練過程評測,最後輸出pool5設置優化目標loss。tf.nn.l2_loss計算,tf.gradients求loss所有模型參數梯度,模擬訓練過程,根據梯度更新參數。time_tensorflow_run統計backward運算時間,target求整個網路梯度gard。
執行主函數。
程式顯示三段結果。AlexNet網路結構、輸出tensor尺寸。forward計算時間,有LRN層每輪迭代時間0.026s,去除LRN層0.007s,對最終準確率影響不大。backward運算時間,有LRN層每輪迭代時間0.078s,去除LRN層0.025s。backward運算耗時約forward三倍。
CNN訓練過程(backward計算)比較耗時,過很多遍數據,大量迭代。CNN瓶勁在訓練。TensorFlow已經支持iOS、Android,手機CPU做人臉識別、圖片分類非常方便、響應速度很快。
傳統機器學習模型適合學習小型數據集,大型數據集需要更大學習容量(Learning Capacity)模型,深度學習模型。捲積層參數量少,抽取特征能力非常強。
from datetime import datetime import math import time import tensorflow as tf batch_size=32 num_batches=100 def print_activations(t): print(t.op.name, ' ', t.get_shape().as_list()) def inference(images): parameters = [] # conv1 with tf.name_scope('conv1') as scope: kernel = tf.Variable(tf.truncated_normal([11, 11, 3, 64], dtype=tf.float32, stddev=1e-1), name='weights') conv = tf.nn.conv2d(images, kernel, [1, 4, 4, 1], padding='SAME') biases = tf.Variable(tf.constant(0.0, shape=[64], dtype=tf.float32), trainable=True, name='biases') bias = tf.nn.bias_add(conv, biases) conv1 = tf.nn.relu(bias, name=scope) print_activations(conv1) parameters += [kernel, biases] # pool1 lrn1 = tf.nn.lrn(conv1, 4, bias=1.0, alpha=0.001 / 9.0, beta=0.75, name='lrn1') pool1 = tf.nn.max_pool(lrn1, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1], padding='VALID', name='pool1') print_activations(pool1) # conv2 with tf.name_scope('conv2') as scope: kernel = tf.Variable(tf.truncated_normal([5, 5, 64, 192], dtype=tf.float32, stddev=1e-1), name='weights') conv = tf.nn.conv2d(pool1, kernel, [1, 1, 1, 1], padding='SAME') biases = tf.Variable(tf.constant(0.0, shape=[192], dtype=tf.float32), trainable=True, name='biases') bias = tf.nn.bias_add(conv, biases) conv2 = tf.nn.relu(bias, name=scope) parameters += [kernel, biases] print_activations(conv2) # pool2 lrn2 = tf.nn.lrn(conv2, 4, bias=1.0, alpha=0.001 / 9.0, beta=0.75, name='lrn2') pool2 = tf.nn.max_pool(lrn2, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1], padding='VALID', name='pool2') print_activations(pool2) # conv3 with tf.name_scope('conv3') as scope: kernel = tf.Variable(tf.truncated_normal([3, 3, 192, 384], dtype=tf.float32, stddev=1e-1), name='weights') conv = tf.nn.conv2d(pool2, kernel, [1, 1, 1, 1], padding='SAME') biases = tf.Variable(tf.constant(0.0, shape=[384], dtype=tf.float32), trainable=True, name='biases') bias = tf.nn.bias_add(conv, biases) conv3 = tf.nn.relu(bias, name=scope) parameters += [kernel, biases] print_activations(conv3) # conv4 with tf.name_scope('conv4') as scope: kernel = tf.Variable(tf.truncated_normal([3, 3, 384, 256], dtype=tf.float32, stddev=1e-1), name='weights') conv = tf.nn.conv2d(conv3, kernel, [1, 1, 1, 1], padding='SAME') biases = tf.Variable(tf.constant(0.0, shape=[256], dtype=tf.float32), trainable=True, name='biases') bias = tf.nn.bias_add(conv, biases) conv4 = tf.nn.relu(bias, name=scope) parameters += [kernel, biases] print_activations(conv4) # conv5 with tf.name_scope('conv5') as scope: kernel = tf.Variable(tf.truncated_normal([3, 3, 256, 256], dtype=tf.float32, stddev=1e-1), name='weights') conv = tf.nn.conv2d(conv4, kernel, [1, 1, 1, 1], padding='SAME') biases = tf.Variable(tf.constant(0.0, shape=[256], dtype=tf.float32), trainable=True, name='biases') bias = tf.nn.bias_add(conv, biases) conv5 = tf.nn.relu(bias, name=scope) parameters += [kernel, biases] print_activations(conv5) # pool5 pool5 = tf.nn.max_pool(conv5, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1], padding='VALID', name='pool5') print_activations(pool5) return pool5, parameters def time_tensorflow_run(session, target, info_string): num_steps_burn_in = 10 total_duration = 0.0 total_duration_squared = 0.0 for i in range(num_batches + num_steps_burn_in): start_time = time.time() _ = session.run(target) duration = time.time() - start_time if i >= num_steps_burn_in: if not i % 10: print ('%s: step %d, duration = %.3f' % (datetime.now(), i - num_steps_burn_in, duration)) total_duration += duration total_duration_squared += duration * duration mn = total_duration / num_batches vr = total_duration_squared / num_batches - mn * mn sd = math.sqrt(vr) print ('%s: %s across %d steps, %.3f +/- %.3f sec / batch' % (datetime.now(), info_string, num_batches, mn, sd)) def run_benchmark(): with tf.Graph().as_default(): image_size = 224 images = tf.Variable(tf.random_normal([batch_size, image_size, image_size, 3], dtype=tf.float32, stddev=1e-1)) pool5, parameters = inference(images) init = tf.global_variables_initializer() config = tf.ConfigProto() config.gpu_options.allocator_type = 'BFC' sess = tf.Session(config=config) sess.run(init) time_tensorflow_run(sess, pool5, "Forward") objective = tf.nn.l2_loss(pool5) grad = tf.gradients(objective, parameters) time_tensorflow_run(sess, grad, "Forward-backward") run_benchmark()
參考資料:
《TensorFlow實踐》
歡迎付費咨詢(150元每小時),我的微信:qingxingfengzi