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