@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:
sigmoid:
tanh:

非線性模型
a = tf.nn.relu(tf.matmul(x, w1) + biases1)
y = tf.nn.relu(tf.matmul(a, w2) + biases2)
2. 經(jīng)典損失函數(shù)
交叉熵
判斷一個輸出向量和期望的向量距離的一個常用方法是使用交叉熵。
交叉熵描述的是兩個概率分布p、q之間的距離。
- 值越小,兩個概率分布的距離越近。
- 交叉熵是不對稱的,即
,前著表述的是通過概率分布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è)原始的輸出是,經(jīng)過softmax處理之后的輸出為:
- 原始的輸出作為新輸出的置信度
- 新的輸出滿足概率分布的要求:
(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_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é)請參考這篇簡書
'''
均方誤差+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)]))