1. 程式人生 > >Tensorflow框架(二)

Tensorflow框架(二)

《TensorFlow 實戰Google深度學習框架》一書中比較簡單的部分就不做過多介紹。由於本書對滑動平均模型介紹個人感覺有點過簡,所以詳細介紹這一節知識點。

一、啟用函式

tensorflow提供了多種啟用函式,常用的有:

x = tf.constant([1.,2.])
y1 = tf.sigmoid(x)
y2 = tf.tanh(x)
y3 = tf.nn.relu(x)
y4 = tf.nn.leaky_relu(x)
y5 = tf.nn.softmax(x)
with tf.Session() as sess:
    print(sess.run(y4))

 

二、損失函式定義

損失函式常用函式

tf.log:對張量求對數

tf.matmul:矩陣乘法

tf.clip_by_value:將張量數值限制在一個範圍之內(在第一篇中已做詳述)

v = tf.constant([[1.1,2.2,3.3], [4.1,5.2,6.3]])
with tf.Session() as sess:
    print(tf.clip_by_value(v, 2.5, 4.5).eval())

tf.reduce_mean:對矩陣做平均

v = tf.constant([[1.1,2.2,3.3], [4.1,5.2,6.3]])
with tf.Session() as sess:
    print(tf.reduce_mean(v).eval())

tf.reduce_sum:對矩陣求和

tf.nn.softmax_cross_entropy_with_logits:softmax迴歸的交叉熵損失函式

# y是真實樣本標籤,y_hat是預測標籤
loss = tf.nn.softmax_cross_entropy_with_logits(
labels = y, logits = y_hat)

均方誤差損失函式:

mse = tf.reduce_mean(tf.square(y - y_hat))

自定義損失函式

tf.greater:比較兩個輸入張量中的每一個元素大小,返回比較結果

tf.where:當第一個引數即選擇條件為True,tf.where選擇第二個引數,反之選擇第三個引數

# tf.greater
loss = tf.reduce_sum(tf.where(tf.greater(v1, v2),
                              (v1 - v2) * a, (v2 - v1) * b))

 

三、神經網路優化演算法

1.優化學習率

為了能解決學習率過大和過小的問題,使用指數衰減法能有效解決問題。

tf.train.exponential_decay函式實現了指數衰減學習率

decayed_learning_rate = \
learning_rate * decay_rate ^ (global_step / decay_steps)

decayed_learning_rate:表示每一輪優化時使用的學習率

learning_rate:為事先設定的初始學習率

decay_rate:衰減係數

decay_steps:衰減速度

同時衰減方式有階梯狀衰減學習率和連續衰減學習率,通過staircase設定,當為True時是階梯函式,反之為連續衰減

global_step = tf.Variable(0)

# 使用exponential_decay生成新的學習率
learning_rate = tf.train.exponential_decay(
    0.1, global_step, 100, 0.96, staircase = True)

learning_step = tf.train.GradientDescentOptimizer(learning_rate).minize(...,global_step = global_step)

 

2.正則化

L1和L2正則化

weights = tf.constant([[1.0, -2.0], [-3.0, 4.0]])
with tf.Session() as sess:
    # L1正則化的使用
    print(sess.run(tf.contrib.layers.l1_regularizer(0.5)(weights)))
    # L2正則化的使用
    print(sess.run(tf.contrib.layers.l2_regularizer(0.5)(weights)))

  實際應用中,常使用L2正則化

w = tf.Variable(tf.random_normal([2, 1], stddev = 1, seed = 1))
y = tf.matmul(x, w)
loss = tf.reduce_mean(tf.square(y - y_hat)) + tf.contrib.layers.l2_regularizer(lambd)(w)

當網路結構較為複雜的時候,使用上述定義正則化的方式會導致程式碼的可讀性較差,因此常使用下述定義方法:

def get_weight(shape, lambd):
    # 生成變數
    var = tf.Variable(tf.random_normal(shape), dtype = tf.float32)  
    # 將新生成的變數L2正則化損失項加入集合中
    tf.add_to_collection('losses', tf.contrib.layers.l2_regularizer(lambd)(var))
    return var

x = tf.placeholder(tf.float32, shape = [None, 2])
y = tf.placeholder(tf.float32, shape = [None, 1])

batch_size = 8
lambd = 0.001

# 定義每層網路中的節點數
layer_dimension = [2, 10, 10, 10, 1]
# 神經網路的層數
n_layers = len(layer_dimension)

# 當前傳播至最深層的節點
cur_layer = x
in_dimension = layer_dimension[0]

# 迴圈建立五層全連線神經網路
for i in range(1, n_layers):
    out_dimension = layer_dimension[i]
    weight = get_weight((in_dimension, out_dimension), lambd)
    bias = tf.Variable(tf.zeros([out_dimension]))
    cur_layer = tf.nn.relu(tf.matmul(cur_layer, weight) + bias)
    in_dimension = layer_dimension[i]
    
# 定義損失函式
mse_loss = tf.reduce_mean(tf.square(y - y_hat))

# 將均方誤差損失函式加入損失集合
tf.add_to_collection("losses", mse_loss)

# tf.get_collection以列表的形式返回losses集合中所有元素
# 由正則化損失函式的形式我們可以知道,將這些元素部分加在一起得到最終損失函式
loss = tf.add_n(tf.get_collection('losses'))

 

四、滑動平均模型

因為在深度學習演算法理論中,由於本人才疏學淺,剛看到這個模型的時候也是一臉懵逼,不曾瞭解過滑動平均模型,經過多方查閱後得知,滑動平均模型機制即在更新引數的時候防止引數更新發生突變情況,因此會有一個影子變數的概念,這個影子變數與原變數之間的對應關係可以有效的防止引數發生不正常的更新現象,能有效增加模型的健壯性。

Tensorflow中提供tf.train.ExponentialMovingAverage來實現滑動平均模型。

該函式為每個變數維護一個影子變數,影子變數的初始值就是相應變數的初始值。影子變數根據下式更新:

shadow\_variable = decay \times shadow\_variable + (1-decay) \times variable

shadow_variable:影子變數

variable:待更新變數

decay:衰減率

觀察上式可以知道,衰減率decay決定模型更新速度,decay越大,shadow_variable(此時代表原來舊的影子變數)佔比就越大,對新的影子變數更新幅度就更小。同時為了能使模型在訓練前期更新得更快,ExponentialMovingAverage初始化提供了num_updates引數,由此定義:

decay = min\{decay, \frac{1+num\_updates}{10+num\_updates} \}

上述式子就表示了當迭代次數num_updates,可以發現隨著迭代次數的增加,decay也逐漸趨向於1,這樣在迭代後期,此時模型可能已經收斂到最有點附近,卻保證了模型不會出現非正常的引數更新情況。

# 定義變數用於計算滑動平均
v1 = tf.Variable(0, dtype = tf.float32)

# step表示之前提到的num_updates,初始沒有訓練,自然也就是0.
# 隨著step增加,控制衰減率decay
step = tf.Variable(0, trainable = False)

# 定義滑動視窗類,衰減率被初始化成0.99,控制衰減率是之前
ema = tf.train.ExponentialMovingAverage(0.99, step)

# 定義一個更新變數滑動平均的操作。通過給定一個列表,列表內的所有變數都會被更新
maintain_averages_op = ema.apply([v1])

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    
    # 因為初始化都為0,所以輸出為0
    print(sess.run([v1, ema.average(v1)]))
    
    # 把5賦值給v1,計算得到滑動平均更新為4.5
    sess.run(tf.assign(v1, 5))
    sess.run(maintain_averages_op)
    print(sess.run([v1, ema.average(v1)]))
    
    # step = 1000
    sess.run(tf.assign(step, 10000))
    sess.run(tf.assign(v1, 10))
    sess.run(maintain_averages_op)
    print(sess.run([v1, ema.average(v1)]))
    
    sess.run(maintain_averages_op)
    print(sess.run([v1, ema.average(v1)]))