TensorFlow 深度學(xué)習(xí)基本概念

@Deprecated讓我們擁抱tensorflow2.0吧

1. 深度學(xué)習(xí)

特性:

  • 多層:單層神經(jīng)網(wǎng)絡(luò)其實就是感知機(jī)(1958年由Frank Rosenblatt提出),感知機(jī)的最大問題在于無法解決異或問題。
  • 非線性:線性模型不管有多少層,其實和單層沒有區(qū)別,本質(zhì)還是線性模型,因為線性模型的最大特點是任意線性模型的組合任然是線性模型。節(jié)點的激活函數(shù)(在線性函數(shù)外面又包了一層的函數(shù))決定了模型是否是線性的。常用的非線性模型有ReLU、sigmoid、tanh。
    ReLU: f(x) = max(x, 0)
    sigmoid: f(x) = \frac{1}{1+e^{-x}}
    tanh: f(x) = \frac{1-e^{-2x}}{1+e^{-2x}}
非線性模型
a = tf.nn.relu(tf.matmul(x, w1) + biases1)
y = tf.nn.relu(tf.matmul(a, w2) + biases2)

2. 經(jīng)典損失函數(shù)

交叉熵

判斷一個輸出向量和期望的向量距離的一個常用方法是使用交叉熵。
交叉熵描述的是兩個概率分布p、q之間的距離。

H(p,q)=-\sum_{x}p(x)log \cdot q(x)

  • 值越小,兩個概率分布的距離越近。
  • 交叉熵是不對稱的,即H(p, q)\neq H(q , p),前著表述的是通過概率分布q來表達(dá)p的困難程度。當(dāng)用于神經(jīng)網(wǎng)絡(luò)的損失函數(shù)時,p代表正確值,q表示預(yù)測值。
# 二值輸出的交叉熵樣例
cross_entropy = -tf.reduce_mean(y_ * tf.log(tf.clip_by_value(y, 1e-10, 1.0))
                                + (1 - y_) * tf.log(tf.clip_by_value(1 - y, 1e-10, 1.0)))
'''
y_是正確值, y是預(yù)測值。
tf.clip_by_value(y, 1e-10, 1.0) 將 y的值限定在1e-10, 1.0之間(大于1的統(tǒng)統(tǒng)為1,小于等于0的統(tǒng)統(tǒng)為1e-10)。保證不會出現(xiàn)log0的情況。
* 是各元素相乘,不是矩陣相乘。
tf.reduce_mean計算矩陣所有元素的平均值。
'''

但是神經(jīng)網(wǎng)絡(luò)的輸出卻不一定是一個概率分布,那么如何將神經(jīng)網(wǎng)絡(luò)向前傳播得到的結(jié)果也變成概率分布呢?

Softmax回歸

假設(shè)原始的輸出是y_i,經(jīng)過softmax處理之后的輸出為:
softmax(y)_i = y_{i}^{'} = \frac{e^{y_i}}{\sum_{j=1}^{n}e^{y_i}}

  • 原始的輸出作為新輸出的置信度
  • 新的輸出滿足概率分布的要求:
    (1)任意事件發(fā)生的概率在0到1之間 。
    (2)所有事件的概率之和為1。
  • 新的輸出可以理解成一個樣例為不同類別的概率分別為多大。
# 使用了softmax回歸之后的交叉損失函數(shù)
cross_entropy = tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=y)

# 針對只有一個正確值的加速版本
cross_entropy_for_only_one_class = tf.nn.sparse_softmax_cross_entropy_with_logits(labels=y_, logits=y)

均方誤差

對于回歸問題,一般只有一個輸出節(jié)點,即預(yù)測值,最常用的損失函數(shù)是均方誤差。

MSE(y, {y}')=\frac{\sum_{i=1}^{n}(y_i-y_i^{'})^2}{n}

mse_loss = tf.reduce_mean(tf.square(y_ - y))

3. 神經(jīng)網(wǎng)絡(luò)優(yōu)化算法

梯度下降算法

用于優(yōu)化單個參數(shù)的取值。算法細(xì)節(jié)參考這篇簡書

反向傳播算法

給出了一個高效的方式,在所有參數(shù)上使用梯度下降算法。算法細(xì)節(jié)參閱這篇簡書
論文Learning-Representations-by-back-propagating-errors

4. 神經(jīng)網(wǎng)絡(luò)算法優(yōu)化

學(xué)習(xí)率

'''
指數(shù)衰減發(fā)
'''
import tensorflow as tf

global_step = tf.Variable(0)
learning_rate = tf.train.exponential_decay(     #生成學(xué)習(xí)率
    learning_rate=0.1,        #初始學(xué)習(xí)率
    global_step=global_step,  #當(dāng)前迭代次數(shù)
    decay_steps=100,          #衰減速度 (在迭代到該次數(shù)時學(xué)習(xí)率衰減為learning_rate * decay_rate)
    decay_rate=0.96,          #衰減系數(shù)
    staircase=True,           #True 表示 global_step/decay_steps會轉(zhuǎn)化成整數(shù),使得學(xué)習(xí)率的變化成一個階梯函數(shù),這樣
    name=None
)
'''
學(xué)習(xí)率的變化: decayed_learning_rate = learning_rate * decay_rate ^ (global_step / decay_steps)
'''
train_op = tf.train.AdamOptimizer(learning_rate).minimize(any_loss, global_step=global_step)


'''
其他衰減方法:
tf.train.exponential_decay
tf.train.inverse_time_decay
tf.train.natural_exp_decay
tf.train.piecewise_constant
tf.train.polynomial_decay
'''

過擬合

解決過擬合的常用方法是正則化,正則化的細(xì)節(jié)請參考這篇簡書
J(\theta)+\lambda R(w)

'''
均方誤差+L2正則化的損失函數(shù)
'''
import tensorflow as tf

v_lambda = 0.001
w = tf.Variable(tf.random_normal([2, 1], stddev=1, seed=1))
y = tf.matmul(x, w)
mse_loss = tf.reduce_mean(tf.square(y_ - y) + tf.contrib.layers.l2_regularizer(v_lambda)(w))
實例
import tensorflow as tf
import matplotlib.pyplot as plt
import numpy as np
'''
1. 生成模擬數(shù)據(jù)集。
'''
dataset_size = 200
data = []
label = []
np.random.seed(0)

# 以原點為圓心,半徑為1的圓把散點劃分成紅藍(lán)兩部分,并加入隨機(jī)噪音。
for i in range(dataset_size):
    x1 = np.random.uniform(-1,1)
    x2 = np.random.uniform(0,2)
    if x1**2 + x2**2 <= 1:
        data.append([np.random.normal(x1, 0.1),np.random.normal(x2,0.1)])
        label.append(0)
    else:
        data.append([np.random.normal(x1, 0.1), np.random.normal(x2, 0.1)])
        label.append(1)
        
data = np.hstack(data).reshape(-1,2)
label = np.hstack(label).reshape(-1, 1)
plt.scatter(data[:,0], data[:,1], c=np.squeeze(label),  # np.squeeze: 從數(shù)組的形狀中刪除單維度條目,即把shape中為1的維度去掉
           cmap="RdBu", vmin=-.2, vmax=1.2, edgecolor="white")
plt.show()
測試數(shù)據(jù)
'''
2. 定義一個獲取權(quán)重,并自動加入正則項到損失的函數(shù)。一般tf.Variable都是需要訓(xùn)練的權(quán)重參數(shù)
'''
def get_weight(shape, var_lambda):
    w = tf.Variable(tf.random_normal(shape), dtype=tf.float32)
    tf.add_to_collection('losses', tf.contrib.layers.l2_regularizer(var_lambda)(w))
    return w

'''
3. 定義神經(jīng)網(wǎng)絡(luò)。
'''
x = tf.placeholder(tf.float32, shape=(None, 2))
y_ = tf.placeholder(tf.float32, shape=(None, 1))

# 每層節(jié)點的個數(shù)
layer_dimension = [2,10,5,3,1]

n_layers = len(layer_dimension)

cur_layer = x
in_dimension = layer_dimension[0]

# 循環(huán)生成網(wǎng)絡(luò)結(jié)構(gòu),輸入層X[None, 2],隱藏層W1[2, 10]、W2[10, 5]、W3[5, 3],輸出層Y[None, 1]
for i in range(1, n_layers):
    out_dimension = layer_dimension[i]
    weight = get_weight([in_dimension, out_dimension], 0.003)
    bias = tf.Variable(tf.constant(0.1, shape=[out_dimension]))
    cur_layer = tf.nn.elu(tf.matmul(cur_layer, weight) + bias)
    in_dimension = layer_dimension[i]

y= cur_layer

# 損失函數(shù)的定義。
mse_loss = tf.reduce_sum(tf.pow(y_ - y, 2)) / dataset_size
tf.add_to_collection('losses', mse_loss)
loss = tf.add_n(tf.get_collection('losses'))

'''
4. 訓(xùn)練不帶正則項的損失函數(shù)mse_loss。
'''

# 定義訓(xùn)練的目標(biāo)函數(shù)mse_loss,訓(xùn)練次數(shù)及訓(xùn)練模型
train_op = tf.train.AdamOptimizer(0.001).minimize(mse_loss)
TRAINING_STEPS = 10000

with tf.Session() as sess:
    tf.global_variables_initializer().run()
    for i in range(TRAINING_STEPS):
        sess.run(train_op, feed_dict={x: data, y_: label})
        if i % 1000 == 1000 - 1:
            print("After %d steps, mse_loss: %f" % (i,sess.run(mse_loss, feed_dict={x: data, y_: label})))

    # 畫出訓(xùn)練后的分割曲線       
    xx, yy = np.mgrid[-1.2:1.2:.01, -0.2:2.2:.01]
    grid = np.c_[xx.ravel(), yy.ravel()]
    probs = sess.run(y, feed_dict={x:grid})
    probs = probs.reshape(xx.shape)

plt.scatter(data[:,0], data[:,1], c=np.squeeze(label),
           cmap="RdBu", vmin=-.2, vmax=1.2, edgecolor="white")
plt.contour(xx, yy, probs, levels=[.5], cmap="Greys", vmin=0, vmax=.1)
plt.show()
不帶正則項的分類結(jié)果
'''
5. 訓(xùn)練帶正則項的損失函數(shù)loss
'''
# 定義訓(xùn)練的目標(biāo)函數(shù)loss,訓(xùn)練次數(shù)及訓(xùn)練模型
train_op = tf.train.AdamOptimizer(0.001).minimize(loss)
TRAINING_STEPS = 10000

with tf.Session() as sess:
    tf.global_variables_initializer().run()
    for i in range(TRAINING_STEPS):
        sess.run(train_op, feed_dict={x: data, y_: label})
        if i % 1000 == 1000 - 1:
            print("After %d steps, loss: %f" % (i, sess.run(loss, feed_dict={x: data, y_: label})))

    # 畫出訓(xùn)練后的分割曲線       
    xx, yy = np.mgrid[-1:1:.01, 0:2:.01]
    grid = np.c_[xx.ravel(), yy.ravel()]
    probs = sess.run(y, feed_dict={x:grid})
    probs = probs.reshape(xx.shape)

plt.scatter(data[:,0], data[:,1], c=np.squeeze(label),
           cmap="RdBu", vmin=-.2, vmax=1.2, edgecolor="white")
plt.contour(xx, yy, probs, levels=[.5], cmap="Greys", vmin=0, vmax=.1)
plt.show()
帶正則項的分類結(jié)果

滑動平均模型

v1 = tf.Variable(0, dtype=tf.float32)
step = tf.Variable(0, trainable=False)
ema = tf.train.ExponentialMovingAverage(decay=0.99, num_updates=step)
# 每一次操作的時候,列表變量[v1]都會被更新
maintain_averages_op = ema.apply([v1])

with tf.Session() as sess:
    
    # 初始化
    init_op = tf.global_variables_initializer()
    sess.run(init_op)
    print(sess.run([v1, ema.average(v1)]))
    
    # 更新變量v1的取值
    sess.run(tf.assign(v1, 5))
    sess.run(maintain_averages_op)
    print(sess.run([v1, ema.average(v1)]))
    
    # 更新step和v1的取值
    sess.run(tf.assign(step, 10000))  
    sess.run(tf.assign(v1, 10))
    sess.run(maintain_averages_op)
    print(sess.run([v1, ema.average(v1)]))
    
    # 更新一次v1的滑動平均值
    sess.run(maintain_averages_op)
    print(sess.run([v1, ema.average(v1)]))
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容