學習筆記TF033:實現ResNet
ResNet(Residual Neural Network),微軟研究院 Kaiming He等4名華人提出。通過Residual Unit訓練152層深神經網路,ILSVRC 2015比賽冠軍,3.57% top-5錯誤率,參數量比VGGNet低,效果非常突出。ResNet結構,極快加速超深神經網路訓練,模型準確率非常大提升。Inception V4,Inception Module、ResNet結合。ResNet推廣性好。
瑞十教授Schmidhuber(LSTM網路發明者,1997年)提出Highway Network。解決極深神經網路難訓練問題。修改每層激活函數,此前激活函數只是對輸入非線性變換y=H(x,WH),Highway NetWork保留一定比例原始輸入x,y=H(x,WH)·T(x,WT)+x·C(x,WC),T變換係數,C保留係數,令C=1-T。前面一層信息,一定比例不經過矩陣乘法和非線性變換,直接傳輸下一層。Highway Network,gating units學習控制網路信息流,學習原始信息應保留比例。gating機制,Schmidhuber教授早年LSTM循環神經網路gating。幾百上千層深Highway Network,直接梯度下降演算法訓練,配合多種非線性激活函數,學習極深神經網路。Highway Network允許訓練任意深度網路,優化方法與網路深度獨立。
ResNet 允許原始輸入信息直接傳輸到後層。Degradation問題,不斷加深神經網路深度,準確率先上升達到飽和,再下降。ResNet靈感,用全等映射直接將前層輸出傳到後層。神經網路輸入x,期望輸出H(x),輸入x直接傳到輸出作初始結果,學習目標F(x)=H(x)-x。ResNet殘差學習單元(Residual Unit),不再學習完整輸出H(x),只學習輸出輸入差別H(x)-x,殘差。
ResNet,很多旁路支線,輸入直接連到後層,後層直接學習殘差,shortcut或connections。直接將輸入信息繞道傳到輸出,保護信息完整性,整個網路只學習輸入、輸出差別,簡化學習目標、難度。
兩層殘新式學習單元包含兩個相同輸出通道數3x3卷積。三層殘差網路用Network In Network和Inception Net 1x1卷積。在中間3x3卷積前後都用1x1卷積,先降維再升維。如果輸入輸出維度不同,對輸入x線性映射變換維度,再接後層。
layername outputsize 18-layer 34-layer 50-layer 101-layer 152-layer
conv1 112x112 7x7,64,stride 2
conv2_x 56x56 3x3 max pool,stride 2
3x3,64x2 3x3,64x3 1x1,64x3 1x1,64x3 1x1,64x3
3x3,64 3x3,64 3x3,64 3x3,64 3x3,64
1x1,256 1x1,256 1x1,256
conv3_x 28x28 3x3,128x2 3x3,128x4 1x1,128x4 1x1,128x4 1x1,128x8
3x3,128 3x3,128 3x3,128 3x3,128 3x3,128
1x1,512 1x1,512 1x1,512
conv4_x 14x14 3x3,256x2 3x3,256x6 1x1,256x6 1x1,256x23 1x1,256x36
3x3,256 3x3,256 3x3,256 3x3,256 3x3,256
1x1,1024 1x1,1024 1x1,1024
conv5_x 7x7 3x3,512x2 3x3,512x3 1x1,512x3 1x1,512x3 1x1,512x3
3x3,512 3x3,512 3x3,512 3x3,512 3x3,512
1x1,2048 1x1,2048 1x1,2048
1x1 average pool,1000-d fc,softmax
FLOPs 1.8x10^9 3.6x10^9 3.8x10^9 7.6x10^9 11.3x10^9
ResNet結構,消除層數不斷加深訓練集誤差增大現象。ResNet網路訓練誤差隨層數增大逐漸減小,測試集表現變好。Google借鑒ResNet,提出Inception V4和Inception-ResNet-V2,ILSVRC錯誤率3.08%。《Identyty Mappings in Deep Residual Networks》提出ResNet V2。ResNet殘差學習單元傳播公式,前饋信息和反饋信號可直接傳輸。skip connection 非線性激活函數,替換Identity Mappings(y=x)。ResNet每層都用Batch Normalization。
Schmidhuber教授,ResNet,沒有gates LSTM網路,輸入x傳遞到後層過程一直發生。ResNet等價RNN,ResNet類似多層網路間集成方法(ensemble)。
《The Power of Depth for Feedforward Neural Networks》,理論證明加深網路比加寬網路更有效。
Tensorflow實現ResNet。contrib.slim庫,原生collections。collections.namedtuple設計ResNet基本Block模塊組named tuple,創建Block類,只有數據結構,沒有具體方法。典型Block,三個參數,scope、unit_fn、args。
Block(block1, bottleneck, [(256, 64, 1)] * 2 + [(256, 64, 2)]),block1是Block名稱(或scope),bottleneck是ResNet V2殘差學習單元。最後參數是Block args,args是列表,每個元素對應bottleneck殘差學習單元。前面兩個元素(256, 64, 1),第三元素(256, 64, 2),每個元素都是三元tuple(depth,depth_bottleneck,stride)。(256, 64, 3)代表bottleneck殘差學習單元(三個卷積層),第三層輸出通道數depth 256,前兩層輸出通道數depth_bottleneck 64,中間層步長stride 3。殘差學習單元結構[(1x1/s1,64),(3x3/s3,64),(1x1/s1,256)]。
降採樣subsample方法,參數inputs(輸入)、factor(採樣因子)、scope。fator1,不做修改直接返回inputsx,不為1,用slim.max_pool2d最大池化實現。1x1池化尺寸,stride步長,實現降採樣。
定義conv2d_same函數創建卷積層,如果stride為1,用slim.conv2d,padding模式SAME。stride不為1,顯式pad zero。pad zero總數kernel_size-1 pad_beg為pad//2,pad_end為餘下部分。tf.pad補零輸入變數。已經zero padding,只需padding模式VALID的slim.conv2d創建此卷積層。
定義堆疊Blocks函數,參數net輸入,blocks是Block class 列表。outputs_collections收集各end_points collections。兩層循環,逐個Block,逐個Residual Unit堆疊。用兩個tf.variable_scope命名殘差學習單元block/unit_1形式。第2層循環,每個Block每個Residual Unit args,展開depth、depth_bottleneck、stride。unit_fn殘差學習單元生成函數,順序創建連接所有殘差學習單元。slim.utils.collect_named_outputs函數,輸出net添加到collection。所有Block所有Residual Unit堆疊完,返回最後net作stack_blocks_dense函數結果。
創建ResNet通用arg_scope,定義函數參數默認值。定義訓練標記is_training默認True,權重衰減速度weight_decay默認0.001。BN衰減速率默認0.997,BN epsilon默認1e-5,BN scale默認True。先設置好BN各項參數,通過slim.arg_scope設置slim.conv2d默認參數,權重正則器設L2正則,權重初始化器設slim.variance_scaling_initializer(),激活函數設ReLU,標準化器設BN。最大池化padding模式默認設SAME(論文中用VALID),特徵對齊更簡單。多層嵌套arg_scope作結果返回。
定義核心bottleneck殘差學習單元。ResNet V2論文Full Preactivation Residual Unit 變種。每層前都用Batch Normalization,輸入preactivation,不在卷積進行激活函數處理。參數,inputs輸入,depth、depth_bottleneck、stride,outputs_collections收集end_points collection,scope是unit名稱。用slim.utils.last_dimension函數獲取輸入最後維度輸出通道數,參數min_rank=4限定最少4個維度。slim.batch_norm 輸入 Batch Normalization,用ReLU函數預激活Preactivate。
定義shorcut,直連x,如果殘差單元輸入通道數depth_in、輸出通道數depth一致,用subsample,步長stride,inputs空間降採樣,確保空間尺寸和殘差一致,殘差中間層卷積步長stride;如果不一致,用步長stride 1x1卷積改變通道數,變一致。
定義residual(殘差),3層,1x1尺寸、步長1?輸出通道數depth_bottleneck卷積,3x3尺寸、步長stride?輸出通道數depth_bottleneck卷積,1x1尺寸、步長1?輸出通道數depth卷積,得最終residual,最後層沒有正則項沒有激活函數。residual、shorcut相加,得最後結果output,用slim.utils.collect_named_outputs,結果添加collection,返回output函數結果。
定義生成ResNet V2主函數。參數,inputs輸入,blocks為Block類列表,num_classes最後輸出類數,global_pool標誌是否加最後一層全局平均池化,include_root_block標誌是否加ResNet網路最前面7x7卷積、最大池化,reuse標誌是否重用,scope整個網路名稱。定義variable_scope、end_points_collection,通過slim.arg_scope設slim.con2d、bottleneck、stack_block_dense函數的參數outputs_collections默認end_points_colletion。根據include_root_block標記,創建ResNet最前面64輸出通道步長2的7x7卷積,接步長2的3x3最大池化。兩個步長2層,圖片尺寸縮小為1/4。用stack_blocks_dense生成殘差學習模塊組,根據標記添加全局平均池化層,用tf.reduce_mean實現全局平均池化,效率比直接avg_pool高。根據是否有分類數,添加輸出通道num_classes1x1卷積(無激活函數無正則項),添加Softmax層輸出網路結果。用slim.utils.convert_to_dict 轉化collection為Python dict。最後返回net、end_points。
50層ResNet,4個殘差學習Blocks,units數量為3?4?6?3,總層數(3+4+6+3)x3+2=50。殘差學習模塊前,卷積、池化把尺寸縮小4倍,前3個Blocks包含步長2層,總尺寸縮小4x8=32倍。輸入圖片尺寸最後變224/32=7。ResNet不斷用步長2層縮減尺寸,輸出通道數持續增加,達到2048。
152層ResNet,第二Block units數8,第三Block units數36。
200層ResNet,第二Block units數23,第三Block units數36。
評測函數time_tensorflow_run測試152層ResNet forward性能。圖片尺寸224x224,batch size 32。is_training FLAG設False。resnet_v2_152創建網路,time_tensorflow_run評測forward性能。耗時增加50%,實用卷積神經網路結構,支持超深網路訓練,實際工業應用forward性能不差。
參考資料:
《TensorFlow實戰》
歡迎付費諮詢(150元每小時),我的微信:qingxingfengzi
推薦閱讀:
※乾貨 | TensorFlow的55個經典案例
※乾脆面君,你給我站住!你已經被TensorFlow盯上了
※請問batch_normalization做了normalization後為什麼要變回來?
※學習筆記TF049:TensorFlow 模型存儲載入、隊列線程、載入數據、自定義操作
TAG:TensorFlow | 机器学习 | 深度学习DeepLearning |