1. 程式人生 > >resNet_model—定義殘差網路模型

resNet_model—定義殘差網路模型

resnet_model.py

"""ResNet model.

Related papers:
https://arxiv.org/pdf/1603.05027v2.pdf
https://arxiv.org/pdf/1512.03385v1.pdf
https://arxiv.org/pdf/1605.07146v1.pdf
"""


import numpy as np
import tensorflow as tf
import six
from collections import namedtuple
from tensorflow.python.training import moving_averages


HParams =
namedtuple('HParams', 'batch_size, num_classes, min_lrn_rate, lrn_rate, ' 'num_residual_units, use_bottleneck, weight_decay_rate, ' 'relu_leakiness, optimizer') """ HParams = namedtuple('HParams', '一個batch內的圖片個數', '分類任務數目', '最小的學習率', '學習率', '一個殘差組內殘差單元數量', '是否使用bottleneck', 'relu洩漏', '優化策略') 定義resNet網路模型: | |----- __init__ (初始化) |----- build_graph (構建模型圖) |----- _build_model (構建模型) | |-----(殘差網路:bottleneck模組/標準模組 ) | |----- 第一組 | |----- 第二組 | |----- 第三組 | |----- 全域性池化 | |----- 全連線層 + Softmax | |----- 構建損失函式(交叉熵) | |----- _build_train_op(構建訓練操作)學習率/步長-->計算訓練引數的梯度-->設定優化方法 | 梯度優化操作-->合併BN更新操作-->建立優化操作組 | |----- _stride_arr(步長調整) |----- _residual(殘差單元模組) | |-------是否前置啟用(先 殘差直連、還是先 BN和ReLU) | |-------第一子層 | |-------第二子層 | |-------合併殘差層 | |----- bottleneck殘差單元模組 | |-------是否前置啟用(先 殘差直連、還是先 BN和ReLU) | |-------第一子層 | |-------第二子層 | |-------第三子層 | |-------合併殘差層 | |----- _batch_norm 批量歸一化:((x-mean)/var)*gamma+beta |----- _decay 權重衰減 L2正則loss |----- _conv 2D 卷積 |----- _relu : leaky ReLU啟用函式,洩漏引數leakiness為0就是標準ReLU |----- _fully_connected 全連線層,網路最後一層 |----- _global_avg_pool 全域性均值池化 """
class ResNet(object): """ResNet model.""" def __init__(self, hps, images, labels, mode): """ResNet constructor. Args: hps: Hyperparameters. images: Batches of images 圖片. [batch_size, image_size, image_size, 3] labels: Batches of labels 類別標籤. [batch_size, num_classes] mode: One of 'train' and 'eval'. """
self.hps = hps self._images = images self.labels = labels self.mode = mode self._extra_train_ops = [] def build_graph(self): # 構建模型圖 # 新建全域性step self.global_step = tf.contrib.framework.get_or_create_global_step() self._build_model() # 構建ResNet網路模型 if self.mode == 'train': # 構建優化訓練操作 self._build_train_op() self.summaries = tf.summary.merge_all() # 合併所有總結 def _build_model(self): # 構建模型 with tf.variable_scope('init'): x = self._images """第一層卷積(3,3x3/1,16)""" x = self._conv('init_conv', x, 3, 3, 16, self._stride_arr(1)) strides = [1, 2, 2] # 殘差網路引數 activate_before_residual = [True, False, False] # 啟用前置 if self.hps.use_bottleneck: res_func = self._bottleneck_residual # bottleneck殘差單元模組 filters = [16, 64, 128, 256] # 通道數量 else: res_func = self._residual # 標準殘差單元模組 filters = [16, 16, 32, 64] # 通道數量 # 第一組 with tf.variable_scope('unit_1_0'): x = res_func(x, filters[0], filters[1], self._stride_arr(strides[0]), activate_before_residual[0]) for i in six.moves.range(1, self.hps.num_residual_units): with tf.variable_scope('unit_1_%d' % i): x = res_func(x, filters[1], filters[1], self._stride_arr(1), False) # 第二組 with tf.variable_scope('unit_2_0'): x = res_func(x, filters[1], filters[2], self._stride_arr(strides[1]), activate_before_residual[1]) for i in six.moves.range(1, self.hps.num_residual_units): with tf.variable_scope('unit_2_%d' % i): x = res_func(x, filters[2], filters[2], self._stride_arr(1), False) # 第三組 with tf.variable_scope('unit_3_0'): x = res_func(x, filters[2], filters[3], self._stride_arr(strides[2]), activate_before_residual[2]) for i in six.moves.range(1, self.hps.num_residual_units): with tf.variable_scope('unit_3_%d' % i): x = res_func(x, filters[3], filters[3], self._stride_arr(1), False) # 全域性池化層 with tf.variable_scope('unit_last'): x = self._batch_norm('final_bn', x) x = self._relu(x, self.hps.relu_leakiness) x = self._global_avg_pool(x) # 全連線層 + Softmax with tf.variable_scope('logit'): logits = self._fully_connected(x, self.hps.num_classes) self.predictions = tf.nn.softmax(logits) # 構建損失函式 with tf.variable_scope('costs'): # 交叉熵 xent = tf.nn.softmax_cross_entropy_with_logits(logits=logits, labels=self.labels) self.cost = tf.reduce_mean(xent, name='xent') # 加和 self.cost += self._decay() # L2正則,權重衰減 tf.summary.scalar('cost', self.cost) # 新增cost總結,用於Tensorborad顯示 # 構建訓練操作 def _build_train_op(self): """ ( 學習率/步長-->計算訓練引數的梯度-->設定優化方法) """ self.lrn_rate = tf.constant(self.hps.lrn_rate, tf.float32) tf.summary.scalar('learning_rate', self.lrn_rate) trainable_variables = tf.trainable_variables() grads = tf.gradients(self.cost, trainable_variables) if self.hps.optimizer == 'sgd': optimizer = tf.train.GradientDescentOptimizer(self.lrn_rate) elif self.hps.optimizer == 'mom': optimizer = tf.train.MomentumOptimizer(self.lrn_rate, 0.9) # 梯度優化操作-->合併BN更新操作-->建立優化操作組 apply_op = optimizer.apply_gradients( zip(grads, trainable_variables), global_step=self.global_step, name='train_step') train_ops = [apply_op] + self._extra_train_ops self.train_op = tf.group(*train_ops) # 把步長值轉換成tf.nn.conv2d需要的步長陣列 def _stride_arr(self, stride): return [1, stride, stride, 1] # 殘差單元模組 def _residual(self, x, in_filter, out_filter, stride, activate_before_residual=False): if activate_before_residual: # 是否前置啟用(取殘差直連之前進行BN和ReLU) with tf.variable_scope('shared_activation'): # 先做BN和ReLU啟用 x = self._batch_norm('init_bn', x) x = self._relu(x, self.hps.relu_leakiness) orig_x = x # 獲取殘差直連 else: with tf.variable_scope('residual_only_activation'): orig_x = x # 獲取殘差直連 x = self._batch_norm('init_bn', x) # 後做BN和ReLU啟用 x = self._relu(x, self.hps.relu_leakiness) with tf.variable_scope('sub1'): # 第1子層 # 3x3卷積,通道數(in_filter -> out_filter,使用輸入步長,) x = self._conv('conv1', x, 3, in_filter, out_filter, stride) with tf.variable_scope('sub2'): # 第2子層 x = self._batch_norm('bn2', x) # BN和ReLU啟用 x = self._relu(x, self.hps.relu_leakiness) # 3x3卷積,步長為1,通道數不變(out_filter) x = self._conv('conv2', x, 3, out_filter, out_filter, [1, 1, 1, 1]) # 合併殘差層 with tf.variable_scope('sub_add'): if in_filter != out_filter: # 當通道數有變化時 orig_x = tf.nn.avg_pool(orig_x, stride, stride, 'VALID') # 均值池化,無補零 orig_x = tf.pad(orig_x, # 通道補零(第4維前後對稱補零) [[0, 0], [0, 0], [0, 0], [(out_filter-in_filter)//2, (out_filter-in_filter)//2] ]) x += orig_x # 合併殘差 tf.logging.debug('image after unit %s', x.get_shape()) return x # bottleneck殘差單元模組 def _bottleneck_residual(self, x, in_filter, out_filter, stride, activate_before_residual=False): if activate_before_residual: # 是否前置啟用(取殘差直連之前進行BN和ReLU) with tf.variable_scope('common_bn_relu'): x = self._batch_norm('init_bn', x) # 先做BN和ReLU啟用 x = self._relu(x, self.hps.relu_leakiness) orig_x = x # 獲取殘差直連 else: with tf.variable_scope('residual_bn_relu'): orig_x = x # 獲取殘差直連 x = self._batch_norm('init_bn', x) # 後做BN和ReLU啟用 x = self._relu(x, self.hps.relu_leakiness) # 第1子層 with tf.variable_scope('sub1'): # 1x1卷積,使用輸入步長,通道數(in_filter -> out_filter/4) x = self._conv('conv1', x, 1, in_filter, out_filter/4, stride) # 第2子層 with tf.variable_scope('sub2'): x = self._batch_norm('bn2', x) # BN和ReLU啟用 x = self._relu(x, self.hps.relu_leakiness) # 3x3卷積,步長為1,通道數不變(out_filter/4) x = self._conv('conv2', x, 3, out_filter/4, out_filter/4, [1, 1, 1, 1]) # 第3子層 with tf.variable_scope('sub3'): x = self._batch_norm('bn3', x) # BN和ReLU啟用 x = self._relu(x, self.hps.relu_leakiness) # 1x1卷積,步長為1,通道數不變(out_filter/4 -> out_filter) x = self._conv('conv3', x, 1, out_filter/4, out_filter, [1, 1, 1, 1]) # 合併殘差層 with tf.variable_scope('sub_add'): if in_filter != out_filter: # 當通道數有變化時 # 1x1卷積,使用輸入步長,通道數(in_filter -> out_filter) orig_x = self._conv('project', orig_x, 1, in_filter, out_filter, stride) x += orig_x # 合併殘差 tf.logging.info('image after unit %s', x.get_shape()) return x # Batch Normalization批歸一化 ((x-mean)/var)*gamma+beta def _batch_norm(self, name, x): with tf.variable_scope(name): params_shape = [x.get_shape()[-1]] # 輸入通道維數 beta = tf.get_variable('beta', # offset params_shape, tf.float32, initializer=tf.constant_initializer(0.0, tf.float32)) gamma = tf.get_variable('gamma', # scale params_shape, tf.float32, initializer=tf.constant_initializer(1.0, tf.float32)) if self.mode == 'train': # 為每個通道計算均值、標準差 mean, variance = tf.nn.moments(x, [0, 1, 2], name='moments') moving_mean = tf.get_variable('moving_mean', # 新建或建立測試階段使用的batch均值、標準差 params_shape, tf.float32, initializer=tf.constant_initializer(0.0, tf.float32), trainable=False) moving_variance = tf.get_variable('moving_variance', params_shape, tf.float32, initializer=tf.constant_initializer(1.0, tf.float32), trainable=False) """ 新增batch均值和標準差的更新操作(滑動平均) moving_mean = moving_mean * decay + mean * (1 - decay) moving_variance = moving_variance * decay + variance * (1 - decay) """ self._extra_train_ops.append(moving_averages.assign_moving_average( moving_mean, mean, 0.9)) self._extra_train_ops.append(moving_averages.assign_moving_average( moving_variance, variance, 0.9)) else: mean = tf.get_variable('moving_mean', # 獲取訓練中積累的batch均值、標準差 params_shape, tf.float32, initializer=tf.constant_initializer(0.0, tf.float32), trainable=False) variance = tf.get_variable('moving_variance', params_shape, tf.float32, initializer=tf.constant_initializer(1.0, tf.float32), trainable=False) tf.summary.histogram(mean.op.name, mean) # 新增到直方圖總結 tf.summary.histogram(variance.op.name, variance) # BN層:((x-mean)/var)*gamma+beta y = tf.nn.batch_normalization(x, mean, variance, beta, gamma, 0.001) y.set_shape(x.get_shape()) return y def _decay(self): # 權重衰減,L2正則loss costs = [] for var in tf.trainable_variables(): # 遍歷所有可訓練變數 if var.op.name.find(r'DW') > 0: #只計算標有“DW”的變數 costs.append(tf.nn.l2_loss(var)) # 加和,並乘以衰減因子 return tf.multiply(self.hps.weight_decay_rate, tf.add_n(costs)) # 2D卷積 def _conv(self, name, x, filter_size, in_filters, out_filters, strides): with tf.variable_scope(name): n = filter_size * filter_size * out_filters # 獲取或新建卷積核,正態隨機初始化 kernel = tf.get_variable( 'DW', [filter_size, filter_size, in_filters, out_filters], tf.float32, initializer=tf.random_normal_initializer(stddev=np.sqrt(2.0/n))) # 計算卷積 return tf.nn.conv2d(x, kernel, strides, padding='SAME') # leaky ReLU啟用函式,洩漏引數leakiness為0就是標準ReLU def _relu(self, x, leakiness=0.0): return tf.where(tf.less(x, 0.0), leakiness * x, x, name='leaky_relu'

相關推薦

resNet_model定義網路模型

resnet_model.py """ResNet model. Related papers: https://arxiv.org/pdf/1603.05027v2.pdf https://arxiv.org/pdf/1512.03385v1.pdf ht

PyTorch—torchvision.models匯入預訓練模型網路講解

文章目錄 torchvision.models 1. 模組呼叫 2. 原始碼解析 3. ResNet類 4. Bottlenect類 5. BasicB

[caffe]深度學習之MSRA影象分類模型Deep Residual Network(深度網路)解讀

一、簡介         MSRA的深度殘差網路在2015年ImageNet和COCO如下共5個領域取得第一名:ImageNet recognition, ImageNet detection, ImageNet localization, COCO detection,

使用keras實現深度網路

from keras.models import Model from keras.layers import Input, Dense, Dropout, BatchNormalization, Conv2D, MaxPooling2D, AveragePooling2D, concate

高速路神經網路(Highway Networks)與深度網路(ResNet)的原理和區別

高速路神經網路(Highway Networks): 我們知道,神經網路的深度是其成功的關鍵因素。然而,隨著深度的增加,網路訓練變得更加困難,並且容易出現梯度爆炸或梯度消失的問題。高速路神經網路(Highway Networks)就是為了解決深層網路訓練困難的問題而提出的。 在一般的神經

吳恩達深度學習4-Week2課後作業2-網路

一、Deeplearning-assignment 在本次作業中,我們將學習如何通過殘差網路(ResNets)建立更深的卷及網路。理論上,深層次的網路可以表示非常複雜的函式,但在實踐中,他們是很難建立和訓練的。殘差網路使得建立比以前更深層次的網路成為可能。對於殘差網路的詳細講解,具體可參考該

學習筆記之——基於pytorch的網路(deep residual network)

本博文為本人學習pytorch系列之——residual network。 前面的博文( 學習筆記之——基於深度學習的分類網路)也已經介紹過ResNet了。ResNet是2015年的ImageNet競賽的冠軍,由微軟研究院提出,通過引入residual block能夠成功地訓練高達

網路(Residual Networks, ResNets)

1. 什麼是殘差(residual)?   “殘差在數理統計中是指實際觀察值與估計值(擬合值)之間的差。”“如果迴歸模型正確的話, 我們可以將殘差看作誤差的觀測值。”   更準確地,假設我們想要找一個 $x$,使得 $f(x) = b$,給定一個 $x$ 的估計值 $x_0$,殘差(residual)就是 $

resnet,Resnet,網路

Resnet 這篇部落格主要介紹了提出Resnet的兩篇論文,我分析了兩篇論文的核心內容,歡迎大家閱讀! 相關論文 2016CVPR Deep Residual Learning for Image Recognition 2016ECCV Identity Mapp

大牛教你使用dlib中的深度網路(ResNet)實現實時人臉識別

opencv中提供的基於haar特徵級聯進行人臉檢測的方法效果非常不好,本文使用dlib中提供的人臉檢測方法(使用HOG特徵或卷積神經網方法),並使用提供的深度殘差網路(ResNet)實現實時人臉識別,不過本文的目的不是構建深度殘差網路,而是利用已經訓練好的模型進行實時人臉識

深度學習 --- 深度網路(ResNet)變體介紹

先說明,本文不是本人所寫,是本人翻譯得來,目的是系統整理一下,供以後深入研究時引用,如有侵權請聯絡本人刪除。 ResNet變體 寬剩餘網路(WRN):從“寬度”入手做提升: Wide Residual Network(WRN)由Sergey Zagoruyko和Nikos Komod

深度學習 --- 深度網路詳解ResNet

本來打算本節開始迴圈神經網路RNN,LSTM等,但是覺得還是應該把商用比較火的網路介紹一下,同時詳細介紹一下深度殘差網路,因為他是基於卷積的。而後面的迴圈神經網路更多偏向於序列問題,偏向語音識別,自然語言處理等的應用,而卷積神經網路更偏向於影象識別方面的應用,因此在本節就介紹幾種常用的神經網路,

網路(Residual Network)

一、背景 1)梯度消失問題 我們發現很深的網路層,由於引數初始化一般更靠近0,這樣在訓練的過程中更新淺層網路的引數時,很容易隨著網路的深入而導致梯度消失,淺層的引數無法更新。 可以看到,假設現在需要更新b1,w2,w3,w4引數因為隨機初始化偏向於0,通過鏈式求導我們會發現,w1w2w3相乘會得到更

網路的理解

網路深度是影響深度卷積神經網路效能的一大因素,但是研究者發現當網路不斷加深時,訓練的結果並不好。這不是因為過擬合,因為過擬合的話應該是訓練集上結果好,測試集不好,但深度網路出現的現象是訓練集上的效果就不好。而且這種現象還會隨著深度加深而變差。這並不符合邏輯,因為

深度學習之網路原理深度刨析

為什麼要加深網路? 深度卷積網路自然的整合了低中高不同層次的特徵,特徵的層次可以靠加深網路的層次來豐富。 從而,在構建卷積網路時,網路的深度越高,可抽取的特徵層次就越豐富。 所以一般我們會傾向於使用更深層次的網路結構,以便取得更高層次的特徵。 但是在使用深層次的網路結構時我們會遇到兩個問

【轉載】十分鐘一起學會ResNet網路

  深層次網路訓練瓶頸:梯度消失,網路退化 深度卷積網路自然的整合了低中高不同層次的特徵,特徵的層次可以靠加深網路的層次來豐富。從而,在構建卷積網路時,網路的深度越高,可抽取的特徵層次就越豐富。所以一般我們會傾向於使用更深層次的網路結構,以便取得更高層次的特徵。但是在使用深層次的網路結構時我們會

網路ResNet網路原理及實現

全文共1483字,5張圖,預計閱讀時間10分鐘。作者介紹:石曉文,中國人民大學資訊學院在讀研究生

深度學習: ResNet () 網路

Introduction 添加了一些直達通道,相當於加入了約束。使得某些原本就應為identity mapping的module,直接獲得identity mapping的能力。 起因 2015年之前,在層數不多的深度網路模型中,人們通過 設定 合理的

CNN入門講解:什麼是網路Resnet

微信公眾號:follow_bobo知乎:蔣竺波加公眾號,回覆殘差網路,可以得得到視訊所有高清PPT-----------------------------------------------------------------------------------------------大家好,我是第一行こん

網路實現手勢識別

ng深度學習第四課第二週程式設計作業2,用keras框架殘差網路(residual network)實現手勢識別:import numpy as np from keras.layers import Input, Add, Dense, Activation, ZeroPa