TensorFlow實現(xiàn)Batch Normalization
一、BN(Batch Normalization)算法
1. 對數(shù)據(jù)進行歸一化處理的重要性
神經(jīng)網(wǎng)絡學習過程的本質就是學習數(shù)據(jù)分布,在訓練數(shù)據(jù)與測試數(shù)據(jù)分布不同情況下,模型的泛化能力就大大降低;另一方面,若訓練過程中每批batch的數(shù)據(jù)分布也各不相同,那么網(wǎng)絡每批迭代學習過程也會出現(xiàn)較大波動,使之更難趨于收斂,降低訓練收斂速度。對于深層網(wǎng)絡,網(wǎng)絡前幾層的微小變化都會被網(wǎng)絡累積放大,則訓練數(shù)據(jù)的分布變化問題會被放大,更加影響訓練速度。
2. BN算法的強大之處
1)為了加速梯度下降算法的訓練,我們可以采取指數(shù)衰減學習率等方法在初期快速學習,后期緩慢進入全局最優(yōu)區(qū)域。使用BN算法后,就可以直接選擇比較大的學習率,且設置很大的學習率衰減速度,大大提高訓練速度。即使選擇了較小的學習率,也會比以前不使用BN情況下的收斂速度快??偨Y就是BN算法具有快速收斂的特性。
2)BN具有提高網(wǎng)絡泛化能力的特性。采用BN算法后,就可以移除針對過擬合問題而設置的dropout和L2正則化項,或者采用更小的L2正則化參數(shù)。
3)BN本身是一個歸一化網(wǎng)絡層,則局部響應歸一化層(Local Response Normalization,LRN層)則可不需要了(Alexnet網(wǎng)絡中使用到)。
3. BN算法概述
BN算法提出了變換重構,引入了可學習參數(shù)γ、β,這就是算法的關鍵之處:

引入這兩個參數(shù)后,我們的網(wǎng)絡便可以學習恢復出原是網(wǎng)絡所要學習的特征分布,BN層的錢箱傳到過程如下:

其中m為batchsize。BatchNormalization中所有的操作都是平滑可導,這使得back propagation可以有效運行并學到相應的參數(shù)γ,β。需要注意的一點是Batch Normalization在training和testing時行為有所差別。Training時μβ和σβ由當前batch計算得出;在Testing時μβ和σβ應使用Training時保存的均值或類似的經(jīng)過處理的值,而不是由當前batch計算。
二、TensorFlow相關函數(shù)
1.tf.nn.moments(x, axes, shift=None, name=None, keep_dims=False)
x是輸入張量,axes是在哪個維度上求解, 即想要 normalize的維度, [0] 代表 batch 維度,如果是圖像數(shù)據(jù),可以傳入 [0, 1, 2],相當于求[batch, height, width] 的均值/方差,注意不要加入channel 維度。該函數(shù)返回兩個張量,均值mean和方差variance。
2.tf.identity(input, name=None)
返回與輸入張量input形狀和內(nèi)容一致的張量。
3.tf.nn.batch_normalization(x, mean, variance, offset, scale, variance_epsilon,name=None)
計算公式為scale(x - mean)/ variance + offset。
這些參數(shù)中,tf.nn.moments可得到均值mean和方差variance,offset和scale是可訓練的,offset一般初始化為0,scale初始化為1,offset和scale的shape與mean相同,variance_epsilon參數(shù)設為一個很小的值如0.001。
三、TensorFlow代碼實現(xiàn)
1. 完整代碼
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
ACTIVITION = tf.nn.relu
N_LAYERS = 7 # 總共7層隱藏層
N_HIDDEN_UNITS = 30 # 每層包含30個神經(jīng)元
def fix_seed(seed=1): # 設置隨機數(shù)種子
np.random.seed(seed)
tf.set_random_seed(seed)
def plot_his(inputs, inputs_norm): # 繪制直方圖函數(shù)
for j, all_inputs in enumerate([inputs, inputs_norm]):
for i, input in enumerate(all_inputs):
plt.subplot(2, len(all_inputs), j*len(all_inputs)+(i+1))
plt.cla()
if i == 0:
the_range = (-7, 10)
else:
the_range = (-1, 1)
plt.hist(input.ravel(), bins=15, range=the_range, color='#FF5733')
plt.yticks(())
if j == 1:
plt.xticks(the_range)
else:
plt.xticks(())
ax = plt.gca()
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
plt.title("%s normalizing" % ("Without" if j == 0 else "With"))
plt.draw()
plt.pause(0.01)
def built_net(xs, ys, norm): # 搭建網(wǎng)絡函數(shù)
# 添加層
def add_layer(inputs, in_size, out_size, activation_function=None, norm=False):
Weights = tf.Variable(tf.random_normal([in_size, out_size],
mean=0.0, stddev=1.0))
biases = tf.Variable(tf.zeros([1, out_size]) + 0.1)
Wx_plus_b = tf.matmul(inputs, Weights) + biases
if norm: # 判斷是否是Batch Normalization層
# 計算均值和方差,axes參數(shù)0表示batch維度
fc_mean, fc_var = tf.nn.moments(Wx_plus_b, axes=[0])
scale = tf.Variable(tf.ones([out_size]))
shift = tf.Variable(tf.zeros([out_size]))
epsilon = 0.001
# 定義滑動平均模型對象
ema = tf.train.ExponentialMovingAverage(decay=0.5)
def mean_var_with_update():
ema_apply_op = ema.apply([fc_mean, fc_var])
with tf.control_dependencies([ema_apply_op]):
return tf.identity(fc_mean), tf.identity(fc_var)
mean, var = mean_var_with_update()
Wx_plus_b = tf.nn.batch_normalization(Wx_plus_b, mean, var,
shift, scale, epsilon)
if activation_function is None:
outputs = Wx_plus_b
else:
outputs = activation_function(Wx_plus_b)
return outputs
fix_seed(1)
if norm: # 為第一層進行BN
fc_mean, fc_var = tf.nn.moments(xs, axes=[0])
scale = tf.Variable(tf.ones([1]))
shift = tf.Variable(tf.zeros([1]))
epsilon = 0.001
ema = tf.train.ExponentialMovingAverage(decay=0.5)
def mean_var_with_update():
ema_apply_op = ema.apply([fc_mean, fc_var])
with tf.control_dependencies([ema_apply_op]):
return tf.identity(fc_mean), tf.identity(fc_var)
mean, var = mean_var_with_update()
xs = tf.nn.batch_normalization(xs, mean, var, shift, scale, epsilon)
layers_inputs = [xs] # 記錄每一層的輸入
for l_n in range(N_LAYERS): # 依次添加7層
layer_input = layers_inputs[l_n]
in_size = layers_inputs[l_n].get_shape()[1].value
output = add_layer(layer_input, in_size, N_HIDDEN_UNITS, ACTIVITION, norm)
layers_inputs.append(output)
prediction = add_layer(layers_inputs[-1], 30, 1, activation_function=None)
cost = tf.reduce_mean(tf.reduce_sum(tf.square(ys - prediction),
reduction_indices=[1]))
train_op = tf.train.GradientDescentOptimizer(0.001).minimize(cost)
return [train_op, cost, layers_inputs]
fix_seed(1)
x_data = np.linspace(-7, 10, 2500)[:, np.newaxis]
np.random.shuffle(x_data)
noise =np.random.normal(0, 8, x_data.shape)
y_data = np.square(x_data) - 5 + noise
plt.scatter(x_data, y_data)
plt.show()
xs = tf.placeholder(tf.float32, [None, 1])
ys = tf.placeholder(tf.float32, [None, 1])
train_op, cost, layers_inputs = built_net(xs, ys, norm=False)
train_op_norm, cost_norm, layers_inputs_norm = built_net(xs, ys, norm=True)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
cost_his = []
cost_his_norm = []
record_step = 5
plt.ion()
plt.figure(figsize=(7, 3))
for i in range(250):
if i % 50 == 0:
all_inputs, all_inputs_norm = sess.run([layers_inputs, layers_inputs_norm],
feed_dict={xs: x_data, ys: y_data})
plot_his(all_inputs, all_inputs_norm)
sess.run([train_op, train_op_norm],
feed_dict={xs: x_data[i*10:i*10+10], ys: y_data[i*10:i*10+10]})
if i % record_step == 0:
cost_his.append(sess.run(cost, feed_dict={xs: x_data, ys: y_data}))
cost_his_norm.append(sess.run(cost_norm,
feed_dict={xs: x_data, ys: y_data}))
plt.ioff()
plt.figure()
plt.plot(np.arange(len(cost_his))*record_step,
np.array(cost_his), label='Without BN') # no norm
plt.plot(np.arange(len(cost_his))*record_step,
np.array(cost_his_norm), label='With BN') # norm
plt.legend()
plt.show()
2. 實驗結果
輸入數(shù)據(jù)分布:

批標準化BN效果對比:

以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
python3.7+anaconda 安裝opencv和dlib的問題及解決方法
這篇文章主要介紹了python3.7+anaconda 安裝opencv和dlib的問題及解決方法,本文圖文并茂給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-08-08
Python解決兩個整數(shù)相除只得到整數(shù)部分的實例
今天小編就為大家分享一篇Python解決兩個整數(shù)相除只得到整數(shù)部分的實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-11-11
Python實戰(zhàn)之基于OpenCV的美顏掛件制作
在本文中,我們將學習如何創(chuàng)建有趣的基于Snapchat的增強現(xiàn)實,主要包括兩個實戰(zhàn)項目:在檢測到的人臉上的鼻子和嘴巴之間添加胡子掛件,在檢測到的人臉上添加眼鏡掛件。感興趣的童鞋可以看看哦2021-11-11
Perl中著名的Schwartzian轉換問題解決實現(xiàn)
這篇文章主要介紹了Perl中著名的Schwartzian轉換問題解決實現(xiàn),本文詳解講解了Schwartzian轉換涉及的排序問題,并同時給出實現(xiàn)代碼,需要的朋友可以參考下2015-06-06
win10系統(tǒng)配置GPU版本Pytorch的詳細教程
這篇文章主要介紹了win10系統(tǒng)配置GPU版本Pytorch,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-04-04

