# 五、深度學習
在本章中,我們將介紹以下主題:
* 深度學習技巧
* 卷積神經網絡(CNN)
* CNN 架構
* CNN 的 TensorFlow 實現
* 循環神經網絡(RNN)
* RNN 架構
* 使用 TensorFlow 進行自然語言處理
# 深度學習技巧
深度學習技術是機器學習研究人員近幾十年來所邁出的關鍵一步,已提供了許多應用(如圖像識別和語音識別)中前所未有的成功成果。
有多種原因導致開發深度學習并將其置于機器學習范圍內的關注焦點。 這些原因之一是硬件的進步,以及新處理器的可用性,例如圖形處理單元(**GPU**),它們大大減少了訓練網絡所需的時間,降低了 10/20 的時間。
另一個原因肯定是*越來越容易找到*,要在其上訓練系統的*數據集*越多,這些數據集就需要訓練一定深度和輸入數據的高維結構。 深度學習包含一組方法,這些方法使系統可以在多個級別上獲取數據的*分層表示*。 這是通過組合簡單的單元(不是線性的)來實現的,每個簡單的單元從輸入級別開始將其自身級別的表示形式轉換為更高級別的表示形式*更抽象*。 通過足夠數量的這些轉換,可以學習相當復雜的輸入輸出函數。
關于分類問題,例如最高級別的表示,突出顯示與分類相關的輸入數據方面,從而抑制那些對分類目的沒有影響的方面。

圖像分類系統中的分層特征提取
前面的方案描述了圖像分類系統(人臉識別器)的特征:每個塊逐漸提取輸入圖像的特征,處理從先前塊中已經預處理過的數據,提取輸入圖像的日益復雜的特征, 從而構建表征基于深度學習的系統的分層數據表示。
層次結構特征的可能表示形式如下:
```py
pixel --> edge --> texture --> motif --> part --> object
```
但是,在文本識別問題中,可以將層次表示形式構造如下:
```py
character --> word --> word group --> clause --> sentence --> story
```
因此,深度學習架構是*多層架構*,它由簡單的單元組成,所有單元都受訓練,其中許多單元包含*非線性變換*。 每個單元都對其輸入進行轉換以改善其*屬性*,以僅出于分類目的選擇和放大相關方面,以及其*不變性*,即其傾向*忽略無關的方面*。
因此,通過多級非線性轉換,深度大約在 5 到 20 級之間,深度學習系統可以學習并實現極其復雜和復雜的特征,同時*對最小的相關細節非常敏感*,以及對輸入數據無關方面的大變化非常不敏感,在對象識別的情況下,這些變化可能是:圖像的背景,亮度或所表示對象的位置。
以下部分將借助 TensorFlow 說明兩種重要的深度神經網絡類型:**卷積神經網絡**(**CNN**),主要針對分類問題,然后針對**自然語言處理**(**NLP**)問題的**循環神經網絡**(**RNNs**)問題。
## 卷積神經網絡
**卷積神經網絡**(**CNN**)是面向神經網絡的一種特殊類型的深度學習,在許多實際應用中都取得了優異的成績,尤其是圖像中的*對象識別*。
實際上,CNN 被設計為處理以多個數組形式表示的數據,例如*彩色圖像*,可通過包含像素顏色強度的三個二維數組表示。 CNN 與普通神經網絡之間的實質區別在于,前者*在圖像上直接操作*,而后者在*從圖像中提取的特征上*。 因此,與普通神經網絡不同,CNN 的輸入將是*二維*,特征將是輸入圖像的像素。
CNN 是幾乎所有識別問題的主要方法。 這種類型的網絡所提供的出色表現實際上已經促使諸如 Google 和 Facebook 之類的最大的技術公司投資于此類網絡的研發項目,并開發和分發基于 CNN 的產品圖像識別。
### CNN 架構
CNN 使用三個基本概念:*局部感受野*,*卷積*和*合并*。
在卷積網絡中,我們認為輸入類似于下圖所示:

輸入神經元
CNN 背后的概念之一是*本地連接*。 實際上,CNN 利用輸入數據中可能存在的空間相關性。 第一后續層的每個神經元僅連接*某些輸入神經元。 該區域稱為**局部感受野**。 在下圖中,用*會聚*到隱藏的神經元的黑色`5x5`正方形表示:

從輸入到隱藏的神經元
*隱藏的神經元*當然只會處理其接受區域內的輸入數據,而不會實現其外部的變化。 但是,很容易看到,根據深度的基本原理,通過疊加多層本地連接的層,升級后,與輸入相比,您將擁有處理越來越多的*全局數據*的學習單元,以使表現達到不斷增長的抽象水平。
### 注意
本地連接的原因在于以下事實:在數組形式的數據(例如圖像)中,值通常高度相關,從而形成了易于識別的不同數據組。
每個連接都學習一個權重(因此它將得到`5x5 = 25`),而不是隱藏的神經元及其關聯的連接會學習一個總偏差,然后我們將通過不時執行移位來將區域連接到單個神經元,例如在以下圖中:

卷積運算
該操作稱為**卷積**。這樣,如果我們有一個`28x28`輸入和`5x5`區域的圖像,我們將在隱藏層中獲得`24x24`神經元。 我們說過,每個神經元都有一個偏差和與該區域相關的`5x5`權重:我們將對所有`24x24`神經元使用這些權重和偏差。 這意味著第一隱藏層中的所有神經元將識別相同的特征,只是在輸入圖像中放置的位置不同。 因此,從輸入層到隱藏特征圖的連接圖稱為*共享權重*,偏置稱為*共享偏置*,因為它們事實上是共享的。
顯然,我們需要識別的不僅僅是一個特征圖,因此,一個完整的卷積層是由*多個特征圖*組成的。

多個特征圖
在上圖中,我們看到了三個特征圖。 當然,實際上它的數量會增加,甚至可以使用具有 20 或 40 個特征圖的卷積層。 權重和偏差共享的一個巨大優勢是卷積網絡中涉及的參數的*顯著降低*。 考慮我們的示例,對于每個特征圖,我們需要 25 個權重(`5x5`)和一個偏差(共享)。 總共有 26 個參數。 假設我們有 20 個特征圖,我們將定義 520 個參數。 在具有 784 個輸入神經元和例如 30 個隱藏層神經元的完全連接的網絡中,我們需要 30 個以上的`784x30`偏差權重,以達到總共 23.550 個參數。
差異是顯而易見的。 卷積網絡還使用*池化層*,它們是緊接在卷積層之后的層。 這些簡化了前一層的輸出信息(*卷積*)。 它獲取從卷積層出來的輸入特征圖,并準備一個*壓縮的*特征圖。 例如,我們可以說池化層可以以其所有單元匯總在上一層神經元的`2x2`區域中。
該技術稱為池化,可以用以下方案概括:

池化操作有助于簡化從一層到下一層的信息
顯然,我們通常有更多的特征圖,并且我們將最大池分別應用于每個特征圖。

從輸入層到第二個隱藏層
因此,我們假設第一個隱藏層具有三個尺寸為`24x24`的特征圖,第二個隱藏層的尺寸將為 12x12,因為我們假設每個單元匯總一個`2x2`區域。
結合這三個思想,我們形成了一個完整的卷積網絡。 其架構可以顯示如下:

CNN 架構架構
讓我們總結一下:有`28x28`個輸入神經元,后跟一個*卷積層*,具有局部接收場`5x5`和 3 個特征圖。 作為*的結果,我們獲得了`3x24x24`神經元的隱藏層*。 然后在特征圖的 3 個區域上將最大池應用于`2x2`,從而獲得`3x12x12`的隱藏層。 最后一層是*完全連接的*:它將最大池化層的所有神經元連接到所有 10 個輸出神經元,有助于識別相應的輸出。
然后將通過梯度下降和反向傳播算法訓練該網絡。
### CNN 的 TensorFlow 實現
在以下示例中,我們將看到 CNN 在圖像分類問題中的作用。 我們想展示構建 CNN 網絡的過程:要執行哪些步驟以及需要執行哪些推理才能對整個網絡進行適當的尺寸標注,當然還要如何使用 TensorFlow 進行實現。
#### 初始化步驟
1. 加載并準備 MNIST 數據:
```py
import tensorflow as tf
import input_data
mnist = input_data.read_data_sets("/tmp/data/", one_hot=True)
```
2. 定義所有 CNN 參數:
```py
learning_rate = 0.001
training_iters = 100000
batch_size = 128
display_step = 10
```
3. MNIST 數據輸入(每個形狀為`28x28`數組像素):
```py
n_input = 784
```
4. MNIST 的總類別(0-9)
```py
n_classes = 10
```
5. 為了減少過擬合,我們應用了*丟棄*技術。 該術語是指在神經網絡中刪除單元(隱藏,輸入和輸出)。 確定要消除的神經元是隨機的; 一種方法是應用概率,正如我們將在代碼中看到的那樣。 因此,我們定義以下參數(待調整):
```py
dropout = 0.75
```
6. 定義輸入圖的占位符。 `x`占位符包含 MNIST 數據輸入(恰好 728 像素):
```py
x = tf.placeholder(tf.float32, [None, n_input])
```
7. 然后,我們使用 TensorFlow `reshape`運算符將 4D 輸入圖像的形式更改為張量:
```py
_X = tf.reshape(x, shape=[-1, 28, 28, 1])
```
第二和第三個尺寸對應于圖像的寬度和高度,而第二個尺寸是色彩通道的總數(在我們的情況下為 1)。
因此,我們可以將輸入圖像顯示為尺寸為`28x28`的二維張量:

我們問題的輸入張量
輸出張量將包含每個數字的*輸出概率*,以進行分類:
```py
y = tf.placeholder(tf.float32, [None, n_classes]).
```
#### 第一卷積層
隱藏層的每個神經元都連接到尺寸為`5x5`的輸入張量的一小部分。 這意味著隱藏層的大小為`24x24`。 我們還定義和初始化共享權重和共享偏差的張量:
```py
wc1 = tf.Variable(tf.random_normal([5, 5, 1, 32]))
bc1 = tf.Variable(tf.random_normal([32]))
```
回想一下,要識別圖像,我們需要的不僅僅是特征圖。 該數量僅是我們正在考慮的第一層特征圖的數量。 在我們的例子中,卷積層由 32 個特征圖組成。
下一步是*第一個卷積層*和`conv1`的構造:
```py
conv1 = conv2d(_X,wc1,bc1)
```
在此,`conv2d`是以下函數:
```py
def conv2d(img, w, b):
return tf.nn.relu(tf.nn.bias_add\
(tf.nn.conv2d(img, w,\
strides=[1, 1, 1, 1],\
padding='SAME'),b))
```
為此,我們使用了 TensorFlow `tf.nn.conv2d`函數。 它根據*輸入張量*和*共享權重*計算 2D 卷積。 然后,該操作的結果將被添加到偏置`bc1`矩陣。 為此,我們使用函數`tf.nn.conv2d`從輸入張量和共享權重的張量計算出二維卷積。 然后,該操作的結果將添加到偏置`bc1`矩陣中。 `tf.nn.relu`是 *Relu 函數*(整流線性單元),它是深層神經網絡隱藏層中的*常見激活函數*。
我們將這個激活函數應用于卷積函數的返回值。 填充值為`'SAME'`,它指示*輸出張量將具有與輸入張量*相同的大小。
表示卷積層的一種方法為`conv1`,如下所示:

第一隱藏層
卷積操作之后,我們強加了*池化*步驟,該步驟簡化了先前創建的卷積層的輸出信息。
在我們的示例中,讓我們采用卷積層的`2x2`區域,然后我們將匯總池層中每個點的信息。
```py
conv1 = max_pool(conv1, k=2)
```
在此,對于池操作,我們實現了以下函數:
```py
def max_pool(img, k):
return tf.nn.max_pool(img, \
ksize=[1, k, k, 1],\
strides=[1, k, k, 1],\
padding='SAME')
```
`tf.nn.max_pool`函數對輸入執行最大池化。 當然,我們將最大池化應用于每個卷積層,并且將有很多層池化和卷積。 在合并階段結束時,我們將具有`12x12x32`*卷積隱藏層*。
下圖顯示了池化和卷積操作后的 CNN 層:

第一次卷積和合并操作后的 CNN
最后的操作是通過在卷積層上應用`tf.nn.dropout` TensorFlow 運算符來減少過擬合。 為此,我們為占位符(`keep_prob`)在刪除期間保留神經元輸出的概率創建一個占位符:
```py
keep_prob = tf. placeholder(tf.float32)
conv1 = tf.nn.dropout(conv1,keep_prob)
```
#### 第二卷積層
對于*第二隱藏層*,我們必須應用與第一層相同的操作,因此我們定義并初始化*共享權重*和*共享偏置*的張量:
```py
wc2 = tf.Variable(tf.random_normal([5, 5, 32, 64]))
bc2 = tf.Variable(tf.random_normal([64]))
```
如您所注意到的,第二個隱藏層將具有`5x5`窗口的 64 個特征,而輸入層的數量將從第一個卷積獲得的層中給出。 接下來,我們將第二層應用于卷積`conv1`張量,但是這次我們將 64 組`5x5`過濾器分別應用于 32 個`conv1`層:
```py
conv2 = conv2d(conv1,wc2,bc2)
```
它為我們提供了 64 個`14x14`數組,通過最大池化將其減少到 64 個`7x7`數組:
```py
conv2 = max_pool(conv2, k=2)
```
最后,我們再次使用丟棄操作:
```py
conv2 = tf.nn.dropout(conv2, keep_prob)
```
生成的層是`7x7 x 64`卷積張量,因為我們從輸入張量`12x12`和`5x5`的滑動窗口開始,考慮到步幅為 1。

建立第二個隱藏層
#### 密集連接層
在此步驟中,我們將建立一個緊密連接的層,用于處理整個圖像。 權重和偏差張量如下:
```py
wd1 = tf.Variable(tf.random_normal([7*7*64, 1024]))
bd1 = tf.Variable(tf.random_normal([1024]))
```
如您所注意到的,該層將由`1024`神經元形成。
然后我們將來自第二個卷積層的張量整形為一批向量:
```py
dense1 = tf.reshape(conv2, [-1, wd1.get_shape().as_list()[0]])
```
將該張量乘以權重矩陣`wd1`,將張量偏差`bd1`相加,然后執行 RELU 操作:
```py
dense1 = tf.nn.relu(tf.add(tf.matmul(dense1, wd1),bd1))
```
我們再次使用丟棄運算符完成這一層:
```py
dense1 = tf.nn.dropout(dense1, keep_prob)
```
#### 輸出層
最后一層定義張量`wout`和`bout`:
```py
wout = tf.Variable(tf.random_normal([1024, n_classes]))
bout = tf.Variable(tf.random_normal([n_classes]))
```
在應用`softmax`函數之前,我們必須計算該圖像屬于某個類別的*證據*:
```py
pred = tf.add(tf.matmul(dense1, wout), bout)
```
#### 測試和訓練模型
必須將證據轉換為 10 種可能類別中每一種的概率(該方法與我們在第 4 章“神經網絡介紹”中看到的方法相同)。 因此,我們定義了成本函數,該函數通過應用`softmax`函數來評估模型的質量:
```py
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(pred, y))
```
使用 TensorFlow `AdamOptimizer`函數對其函數進行優化:
```py
optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost)
```
以下張量將在模型的評估階段使用:
```py
correct_pred = tf.equal(tf.argmax(pred,1), tf.argmax(y,1))
accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32))
```
#### 啟動會話
初始化變量:
```py
init = tf.initialize_all_variables()
```
建立求值圖:
```py
with tf.Session() as sess:
sess.run(init)
step = 1
```
讓我們訓練網絡直到`training_iters`:
```py
while step * batch_size < training_iters:
batch_xs, batch_ys = mnist.train.next_batch(batch_size)
```
使用`batch`數據進行健身訓練:
```py
sess.run(optimizer, feed_dict={x: batch_xs,\
y: batch_ys,\
keep_prob: dropout})
if step % display_step == 0:
```
計算`accuracy`:
```py
acc = sess.run(accuracy, feed_dict={x: batch_xs,\
y: batch_ys,\
keep_prob: 1.})
```
計算`loss`:
```py
loss = sess.run(cost, feed_dict={x: batch_xs,\
y: batch_ys,\
keep_prob: 1.})
print "Iter " + str(step*batch_size) +\
", Minibatch Loss= " + \
"{:.6f}".format(loss) + \
", Training Accuracy= " + \
"{:.5f}".format(acc)
step += 1
print "Optimization Finished!"
```
我們打印`256` MNIST 測試圖像的準確率:
```py
print "Testing Accuracy:",\
sess.run(accuracy,\
feed_dict={x: mnist.test.images[:256], \
y: mnist.test.labels[:256],\
keep_prob: 1.})
```
運行代碼,我們得到以下輸出:
```py
Extracting /tmp/data/train-images-idx3-ubyte.gz
Extracting /tmp/data/train-labels-idx1-ubyte.gz
Extracting /tmp/data/t10k-images-idx3-ubyte.gz
Extracting /tmp/data/t10k-labels-idx1-ubyte.gz
Iter 1280, Minibatch Loss= 27900.769531,
Training Accuracy= 0.17188
Iter 2560, Minibatch Loss= 17168.949219, Training Accuracy= 0.21094
Iter 3840, Minibatch Loss= 15000.724609, Training Accuracy= 0.41406
Iter 5120, Minibatch Loss= 8000.896484, Training Accuracy= 0.49219
Iter 6400, Minibatch Loss= 4587.275391, Training Accuracy= 0.61719
Iter 7680, Minibatch Loss= 5949.988281, Training Accuracy= 0.69531
Iter 8960, Minibatch Loss= 4932.690430, Training Accuracy= 0.70312
Iter 10240, Minibatch Loss= 5066.223633, Training Accuracy= 0.70312 . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
Iter 81920, Minibatch Loss= 442.895020, Training Accuracy= 0.93750
Iter 83200, Minibatch Loss= 273.936676, Training Accuracy= 0.93750
Iter 84480, Minibatch Loss= 1169.810303, Training Accuracy= 0.89062
Iter 85760, Minibatch Loss= 737.561157, Training Accuracy= 0.90625
Iter 87040, Minibatch Loss= 583.576965, Training Accuracy= 0.89844
Iter 88320, Minibatch Loss= 375.274475, Training Accuracy= 0.93750
Iter 89600, Minibatch Loss= 183.815613, Training Accuracy= 0.94531
Iter 90880, Minibatch Loss= 410.157867, Training Accuracy= 0.89844
Iter 92160, Minibatch Loss= 895.187683, Training Accuracy= 0.84375
Iter 93440, Minibatch Loss= 819.893555, Training Accuracy= 0.89062
Iter 94720, Minibatch Loss= 460.179779, Training Accuracy= 0.90625
Iter 96000, Minibatch Loss= 514.344482, Training Accuracy= 0.87500
Iter 97280, Minibatch Loss= 507.836975, Training Accuracy= 0.89844
Iter 98560, Minibatch Loss= 353.565735, Training Accuracy= 0.92188
Iter 99840, Minibatch Loss= 195.138626, Training Accuracy= 0.93750
Optimization Finished!
Testing Accuracy: 0.921875
```
它提供約 99.2% 的精度。 顯然,它不代表最新技術,因為該示例的目的只是看如何構建 CNN。 該模型可以進一步完善以提供更好的結果。
#### 源代碼
```py
# Import MINST data
import input_data
mnist = input_data.read_data_sets("/tmp/data/",one_hot=True)
import tensorflow as tf
# Parameters
learning_rate = 0.001
training_iters = 100000
batch_size = 128
display_step = 10
# Network Parameters
n_input = 784 # MNIST data input (img shape: 28*28)
n_classes = 10 # MNIST total classes (0-9 digits)
dropout = 0.75 # Dropout, probability to keep units
# tf Graph input
x = tf.placeholder(tf.float32, [None, n_input])
y = tf.placeholder(tf.float32, [None, n_classes])
#dropout (keep probability)
keep_prob = tf.placeholder(tf.float32)
# Create model
def conv2d(img, w, b):
return tf.nn.relu(tf.nn.bias_add\
(tf.nn.conv2d(img, w,\
strides=[1, 1, 1, 1],\
padding='SAME'),b))
def max_pool(img, k):
return tf.nn.max_pool(img, \
ksize=[1, k, k, 1],\
strides=[1, k, k, 1],\
padding='SAME')
# Store layers weight & bias
# 5x5 conv, 1 input, 32 outputs
wc1 = tf.Variable(tf.random_normal([5, 5, 1, 32]))
bc1 = tf.Variable(tf.random_normal([32]))
# 5x5 conv, 32 inputs, 64 outputs
wc2 = tf.Variable(tf.random_normal([5, 5, 32, 64]))
bc2 = tf.Variable(tf.random_normal([64]))
# fully connected, 7*7*64 inputs, 1024 outputs
wd1 = tf.Variable(tf.random_normal([7*7*64, 1024]))
# 1024 inputs, 10 outputs (class prediction)
wout = tf.Variable(tf.random_normal([1024, n_classes]))
bd1 = tf.Variable(tf.random_normal([1024]))
bout = tf.Variable(tf.random_normal([n_classes]))
# Construct model
_X = tf.reshape(x, shape=[-1, 28, 28, 1])
# Convolution Layer
conv1 = conv2d(_X,wc1,bc1)
# Max Pooling (down-sampling)
conv1 = max_pool(conv1, k=2)
# Apply Dropout
conv1 = tf.nn.dropout(conv1,keep_prob)
# Convolution Layer
conv2 = conv2d(conv1,wc2,bc2)
# Max Pooling (down-sampling)
conv2 = max_pool(conv2, k=2)
# Apply Dropout
conv2 = tf.nn.dropout(conv2, keep_prob)
# Fully connected layer
# Reshape conv2 output to fit dense layer input
dense1 = tf.reshape(conv2, [-1, wd1.get_shape().as_list()[0]])
# Relu activation
dense1 = tf.nn.relu(tf.add(tf.matmul(dense1, wd1),bd1))
# Apply Dropout
dense1 = tf.nn.dropout(dense1, keep_prob)
# Output, class prediction
pred = tf.add(tf.matmul(dense1, wout), bout)
# Define loss and optimizer
cost = tf.reduce_mean\
(tf.nn.softmax_cross_entropy_with_logits(pred, y))
optimizer =\
tf.train.AdamOptimizer\
(learning_rate=learning_rate).minimize(cost)
# Evaluate model
correct_pred = tf.equal(tf.argmax(pred,1), tf.argmax(y,1))
accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32))
# Initializing the variables
init = tf.initialize_all_variables()
# Launch the graph
with tf.Session() as sess:
sess.run(init)
step = 1
# Keep training until reach max iterations
while step * batch_size < training_iters:
batch_xs, batch_ys = mnist.train.next_batch(batch_size)
# Fit training using batch data
sess.run(optimizer, feed_dict={x: batch_xs,\
y: batch_ys,\
keep_prob: dropout})
if step % display_step == 0:
# Calculate batch accuracy
acc = sess.run(accuracy, feed_dict={x: batch_xs,\
y: batch_ys,\
keep_prob: 1.})
# Calculate batch loss
loss = sess.run(cost, feed_dict={x: batch_xs,\
y: batch_ys,\
keep_prob: 1.})
print "Iter " + str(step*batch_size) +\
", Minibatch Loss= " + \
"{:.6f}".format(loss) + \
", Training Accuracy= " + \
"{:.5f}".format(acc)
step += 1
print "Optimization Finished!"
# Calculate accuracy for 256 mnist test images
print "Testing Accuracy:",\
sess.run(accuracy,\
feed_dict={x: mnist.test.images[:256], \
y: mnist.test.labels[:256],\
keep_prob: 1.})
```
## 循環神經網絡
另一個面向深度學習的架構是所謂的**循環神經網絡**(**RNN**)的架構。 RNN 的基本思想是在輸入中使用*序列信息*類型。 在神經網絡中,我們通常假設每個輸入和輸出都獨立于所有其他輸入和輸出。 但是,對于許多類型的問題,此假設并不肯定。 例如,如果您想預測一個短語的下一個單詞,那么知道短語之前的單詞肯定很重要。 這些神經網絡稱為*循環*,因為它們對輸入序列的所有元素執行相同的計算,并且除當前輸入外,每個元素的輸出還取決于所有先前的計算。
### RNN 架構
RNN 一次處理一個順序輸入項,維護一種*更新狀態向量*,該向量包含有關*序列*的所有過去元素的信息。 通常,RNN 具有以下類型的形狀:

RNN 架構架構
上圖顯示了 RNN 的方面,其*展開*版本,解釋了在每個時間點的整個輸入序列的網絡結構。 很明顯,與典型的多級神經網絡不同,在*每個級別*中*使用多個*參數,RNN 始終使用*相同的參數*,命名為`U`,`V`和`W`(請參見上圖)。 此外,在相同輸入序列的多個時刻的每個,RNN 執行相同的計算。 共享相同的參數,可以大大減少網絡在訓練階段必須學習的參數數量,從而也可以縮短訓練時間。
顯然,您也可以訓練這種類型的網絡,因為參數是在每個時間共享的,所以為每個輸出計算的梯度不僅取決于當前計算,還取決于以前的。 例如,為了計算時間`t = 4`時的梯度,有必要使*向后傳播*之前三個時間點的梯度,然后求和所得的梯度。 同樣,*整個輸入序列*通常被認為是訓練集的*單元素*。
但是,這種類型的網絡的訓練會遇到所謂的梯度*消失/爆炸*問題; 計算得出的梯度和向后傳播的梯度在每個時間點傾向于使*增大*或*減小*,然后在一定時間間隔后,*趨于無窮大*或*收斂為零*。
現在讓我們檢查 RNN 的工作方式。`X[t]`; 是時間`t`上的網絡輸入,例如可以是代表句子的單詞,而`S[t]`的向量。 是網絡的*狀態向量*。 可以認為是系統的一種*記憶*,其中包含有關輸入序列的所有先前元素的信息。 從*當前輸入*(時間`t`)開始求值`t`時刻的狀態向量,并通過`U`和`W`參數的先前時刻(時間`t-1`)求值狀態:
```py
S[t] = f([U] * X[t] + [W] * S[t-1])
```
函數`f`是*非線性函數*,例如整流線性單元(ReLu),而`O[t]`; 是使用參數`V`計算的`t`時刻的輸出。
輸出將取決于網絡所使用的問題的類型。 例如,如果您要預測句子的下一個單詞,則它可能是系統詞匯表中每個單詞的*概率向量*。
### LSTM 網絡
**長短期記憶**(**LSTM**)網絡是 RNN 架構基本模型的擴展。 主要思想是改進網絡,為其提供顯式內存。 實際上,盡管 LSTM 網絡與 RNN 并沒有本質上的不同,但它們配備了特殊的隱藏單元,稱為存儲單元,其行為是長時間記住以前的輸入。

LSTM 單元
LSTM 單元具有三個門和四個輸入權重, `x[t]`(從數據到輸入和三個門),而`h[t]`是單元的輸出。
LSTM 塊包含確定輸入是否足夠重要以進行保存的門。 該塊由四個單元組成:
* **輸入門**:允許在結構中輸入值
* **遺忘門**:刪除結構中包含的值
* **輸出門**:確定設備何時輸出陷在結構中的值
* **單元**:啟用或禁用存儲單元
在下一個示例中,我們將在語言處理問題中看到 LSTM 網絡的 TensorFlow 實現。
### 使用 TensorFlow 的 NLP
RNN 已被證明在諸如預測文本中的下一個字符或類似地預測句子中的下一個順序詞等問題上具有出色的表現。 但是,它們也用于更復雜的問題,例如**機器翻譯**。 在這種情況下,網絡將輸入源語言中的單詞序列,而您想要輸出語言*目標*中的相應單詞序列。 最后,RNN 被廣泛使用的另一個非常重要的應用是*語音識別*。 在下文中,我們將開發一個計算模型,該模型可以根據前一個單詞的順序來預測文本中的下一個單詞。 為了測量模型的*精度*,我們將使用 **Penn 樹庫**(**PTB**)數據集,該數據集是衡量這些模型精度的基準 。
本示例引用您在 TensorFlow 發行版的`/rnn/ptb`目錄中找到的文件。 它包含以下兩個文件:
* `ptb_word_lm.py`:在 PTB 數據集上訓練語言模型的隊列
* `reader.py`:讀取數據集的代碼
與前面的示例不同,我們將僅介紹所實現過程的偽代碼,以便理解模型構建背后的主要思想,而不會陷入不必要的實現細節中。 源代碼很長,一行一行地解釋代碼太麻煩了。
### 注意
有關其他參考,請參見[這里](https://www.tensorflow.org/versions/r0.8/tutorials/recurrent/index.html)。
#### 下載數據
您可以從[網頁](http://www.fit.vutbr.cz/~imikolov/rnnlm/simple-examples.tgz)下載數據,然后提取數據文件夾。 數據集經過預處理,包含 10000 個不同的單詞,包括句子結尾標記和稀有單詞的特殊符號(`<unk>`)。 我們將`reader.py`中的所有參數都轉換為唯一的整數標識符,以使神經網絡更易于處理。
要使用`tar`解壓縮`.tgz`文件,您需要使用以下命令:
```py
tar -xvzf /path/to/yourfile.tgz
```
## 建立模型
該模型使用 LSTM 實現 RNN 的架構。 實際上,它計劃通過包括存儲單元來增加 RNN 的架構,該存儲單元允許保存有關長期時間依賴的信息。
TensorFlow 庫允許您通過以下命令創建 LSTM:
```py
lstm = rnn_cell.BasicLSTMCell(size)
```
這里`size`應該是 LSTM 要使用的單元數。 LSTM 內存初始化為零:
```py
state = tf.zeros([batch_size, lstm.state_size])
```
在計算過程中,用輸出值更新要檢查狀態值的每個單詞之后,以下是實現的步驟的偽代碼列表:
```py
loss = 0.0
for current_batch_of_words in words_in_dataset:
output, state = lstm(current_batch_of_words, state)
```
然后,`output`用于對下一個單詞的預測進行預測:
```py
logits = tf.matmul(output, softmax_w) + softmax_b
probabilities = tf.nn.softmax(logits)
loss += loss_function(probabilities, target_words)
```
`loss`函數將目標單詞的平均負對數概率最小化,它是 TensorFow 函數:
```py
tf.nn.seq2seq.sequence_loss_by_example
```
它計算平均每個單詞的*困惑度*,它的值衡量模型的準確率(值越小則表示最佳表現),并將在整個訓練過程中進行監控。
## 運行代碼
實現的模型支持三種類型的配置:`small`,`medium`和`large`。 它們之間的區別在于 LSTM 的大小和用于訓練的一組超參數。 模型越大,應獲得的結果越好。 `small`模型應該能夠在測試集上達到低于 120 的困惑度,而`large`模型則能夠達到低于 80 的困惑度,盡管可能需要花費幾個小時來訓練。
要執行模型,只需鍵入以下內容:
```py
python ptb_word_lm --data_path=/tmp/simple-examples/data/ --model small
```
在`/tmp/simple-examples/data/`中,您必須已經從 PTB 數據集中下載了數據。
以下列表顯示了訓練 8 個小時后的運行情況(對于*小型*配置,為 13 個周期):
```py
Epoch: 1 Learning rate: 1.000
0.004 perplexity: 5263.762 speed: 391 wps
0.104 perplexity: 837.607 speed: 429 wps
0.204 perplexity: 617.207 speed: 442 wps
0.304 perplexity: 498.160 speed: 438 wps
0.404 perplexity: 430.516 speed: 436 wps
0.504 perplexity: 386.339 speed: 427 wps
0.604 perplexity: 348.393 speed: 431 wps
0.703 perplexity: 322.351 speed: 432 wps
0.803 perplexity: 301.630 speed: 431 wps
0.903 perplexity: 282.417 speed: 434 wps
Epoch: 1 Train Perplexity: 268.124
Epoch: 1 Valid Perplexity: 180.210
Epoch: 2 Learning rate: 1.000
0.004 perplexity: 209.082 speed: 448 wps
0.104 perplexity: 150.589 speed: 437 wps
0.204 perplexity: 157.965 speed: 436 wps
0.304 perplexity: 152.896 speed: 453 wps
0.404 perplexity: 150.299 speed: 458 wps
0.504 perplexity: 147.984 speed: 462 wps
0.604 perplexity: 143.367 speed: 462 wps
0.703 perplexity: 141.246 speed: 446 wps
0.803 perplexity: 139.299 speed: 436 wps
0.903 perplexity: 135.632 speed: 435 wps
Epoch: 2 Train Perplexity: 133.576
Epoch: 2 Valid Perplexity: 143.072
............................................................
Epoch: 12 Learning rate: 0.008
0.004 perplexity: 57.011 speed: 347 wps
0.104 perplexity: 41.305 speed: 356 wps
0.204 perplexity: 45.136 speed: 356 wps
0.304 perplexity: 43.386 speed: 357 wps
0.404 perplexity: 42.624 speed: 358 wps
0.504 perplexity: 41.980 speed: 358 wps
0.604 perplexity: 40.549 speed: 357 wps
0.703 perplexity: 39.943 speed: 357 wps
0.803 perplexity: 39.287 speed: 358 wps
0.903 perplexity: 37.949 speed: 359 wps
Epoch: 12 Train Perplexity: 37.125
Epoch: 12 Valid Perplexity: 123.571
Epoch: 13 Learning rate: 0.004
0.004 perplexity: 56.576 speed: 365 wps
0.104 perplexity: 40.989 speed: 358 wps
0.204 perplexity: 44.809 speed: 358 wps
0.304 perplexity: 43.082 speed: 356 wps
0.404 perplexity: 42.332 speed: 356 wps
0.504 perplexity: 41.694 speed: 356 wps
0.604 perplexity: 40.275 speed: 357 wps
0.703 perplexity: 39.673 speed: 356 wps
0.803 perplexity: 39.021 speed: 356 wps
0.903 perplexity: 37.690 speed: 356 wps
Epoch: 13 Train Perplexity: 36.869
Epoch: 13 Valid Perplexity: 123.358
Test Perplexity: 117.171
```
如您所見,在每個周期之后,困惑變得更低了。
# 總結
在本章中,我們概述了深度學習技術,研究了使用中的兩種深度學習架構,即 CNN 和 RNN。 通過 TensorFlow 庫,我們開發了用于圖像分類問題的卷積神經網絡架構。 本章的最后一部分專門介紹 RNN,我們在其中描述了 TensorFlow 的 RNN 教程,其中建立了 LSTM 網絡以預測英語句子中的下一個單詞。
下一章介紹了用于 GPU 計算的 TensorFlow 功能,并介紹了 *TensorFlow 服務*,這是一種用于機器學習模型的高表現,開源服務系統,專為生產環境設計,并針對 [TensorFlow](https://www.tensorflow.org/) 進行了優化。
- TensorFlow 1.x 深度學習秘籍
- 零、前言
- 一、TensorFlow 簡介
- 二、回歸
- 三、神經網絡:感知器
- 四、卷積神經網絡
- 五、高級卷積神經網絡
- 六、循環神經網絡
- 七、無監督學習
- 八、自編碼器
- 九、強化學習
- 十、移動計算
- 十一、生成模型和 CapsNet
- 十二、分布式 TensorFlow 和云深度學習
- 十三、AutoML 和學習如何學習(元學習)
- 十四、TensorFlow 處理單元
- 使用 TensorFlow 構建機器學習項目中文版
- 一、探索和轉換數據
- 二、聚類
- 三、線性回歸
- 四、邏輯回歸
- 五、簡單的前饋神經網絡
- 六、卷積神經網絡
- 七、循環神經網絡和 LSTM
- 八、深度神經網絡
- 九、大規模運行模型 -- GPU 和服務
- 十、庫安裝和其他提示
- TensorFlow 深度學習中文第二版
- 一、人工神經網絡
- 二、TensorFlow v1.6 的新功能是什么?
- 三、實現前饋神經網絡
- 四、CNN 實戰
- 五、使用 TensorFlow 實現自編碼器
- 六、RNN 和梯度消失或爆炸問題
- 七、TensorFlow GPU 配置
- 八、TFLearn
- 九、使用協同過濾的電影推薦
- 十、OpenAI Gym
- TensorFlow 深度學習實戰指南中文版
- 一、入門
- 二、深度神經網絡
- 三、卷積神經網絡
- 四、循環神經網絡介紹
- 五、總結
- 精通 TensorFlow 1.x
- 一、TensorFlow 101
- 二、TensorFlow 的高級庫
- 三、Keras 101
- 四、TensorFlow 中的經典機器學習
- 五、TensorFlow 和 Keras 中的神經網絡和 MLP
- 六、TensorFlow 和 Keras 中的 RNN
- 七、TensorFlow 和 Keras 中的用于時間序列數據的 RNN
- 八、TensorFlow 和 Keras 中的用于文本數據的 RNN
- 九、TensorFlow 和 Keras 中的 CNN
- 十、TensorFlow 和 Keras 中的自編碼器
- 十一、TF 服務:生產中的 TensorFlow 模型
- 十二、遷移學習和預訓練模型
- 十三、深度強化學習
- 十四、生成對抗網絡
- 十五、TensorFlow 集群的分布式模型
- 十六、移動和嵌入式平臺上的 TensorFlow 模型
- 十七、R 中的 TensorFlow 和 Keras
- 十八、調試 TensorFlow 模型
- 十九、張量處理單元
- TensorFlow 機器學習秘籍中文第二版
- 一、TensorFlow 入門
- 二、TensorFlow 的方式
- 三、線性回歸
- 四、支持向量機
- 五、最近鄰方法
- 六、神經網絡
- 七、自然語言處理
- 八、卷積神經網絡
- 九、循環神經網絡
- 十、將 TensorFlow 投入生產
- 十一、更多 TensorFlow
- 與 TensorFlow 的初次接觸
- 前言
- 1.?TensorFlow 基礎知識
- 2. TensorFlow 中的線性回歸
- 3. TensorFlow 中的聚類
- 4. TensorFlow 中的單層神經網絡
- 5. TensorFlow 中的多層神經網絡
- 6. 并行
- 后記
- TensorFlow 學習指南
- 一、基礎
- 二、線性模型
- 三、學習
- 四、分布式
- TensorFlow Rager 教程
- 一、如何使用 TensorFlow Eager 構建簡單的神經網絡
- 二、在 Eager 模式中使用指標
- 三、如何保存和恢復訓練模型
- 四、文本序列到 TFRecords
- 五、如何將原始圖片數據轉換為 TFRecords
- 六、如何使用 TensorFlow Eager 從 TFRecords 批量讀取數據
- 七、使用 TensorFlow Eager 構建用于情感識別的卷積神經網絡(CNN)
- 八、用于 TensorFlow Eager 序列分類的動態循壞神經網絡
- 九、用于 TensorFlow Eager 時間序列回歸的遞歸神經網絡
- TensorFlow 高效編程
- 圖嵌入綜述:問題,技術與應用
- 一、引言
- 三、圖嵌入的問題設定
- 四、圖嵌入技術
- 基于邊重構的優化問題
- 應用
- 基于深度學習的推薦系統:綜述和新視角
- 引言
- 基于深度學習的推薦:最先進的技術
- 基于卷積神經網絡的推薦
- 關于卷積神經網絡我們理解了什么
- 第1章概論
- 第2章多層網絡
- 2.1.4生成對抗網絡
- 2.2.1最近ConvNets演變中的關鍵架構
- 2.2.2走向ConvNet不變性
- 2.3時空卷積網絡
- 第3章了解ConvNets構建塊
- 3.2整改
- 3.3規范化
- 3.4匯集
- 第四章現狀
- 4.2打開問題
- 參考
- 機器學習超級復習筆記
- Python 遷移學習實用指南
- 零、前言
- 一、機器學習基礎
- 二、深度學習基礎
- 三、了解深度學習架構
- 四、遷移學習基礎
- 五、釋放遷移學習的力量
- 六、圖像識別與分類
- 七、文本文件分類
- 八、音頻事件識別與分類
- 九、DeepDream
- 十、自動圖像字幕生成器
- 十一、圖像著色
- 面向計算機視覺的深度學習
- 零、前言
- 一、入門
- 二、圖像分類
- 三、圖像檢索
- 四、對象檢測
- 五、語義分割
- 六、相似性學習
- 七、圖像字幕
- 八、生成模型
- 九、視頻分類
- 十、部署
- 深度學習快速參考
- 零、前言
- 一、深度學習的基礎
- 二、使用深度學習解決回歸問題
- 三、使用 TensorBoard 監控網絡訓練
- 四、使用深度學習解決二分類問題
- 五、使用 Keras 解決多分類問題
- 六、超參數優化
- 七、從頭開始訓練 CNN
- 八、將預訓練的 CNN 用于遷移學習
- 九、從頭開始訓練 RNN
- 十、使用詞嵌入從頭開始訓練 LSTM
- 十一、訓練 Seq2Seq 模型
- 十二、深度強化學習
- 十三、生成對抗網絡
- TensorFlow 2.0 快速入門指南
- 零、前言
- 第 1 部分:TensorFlow 2.00 Alpha 簡介
- 一、TensorFlow 2 簡介
- 二、Keras:TensorFlow 2 的高級 API
- 三、TensorFlow 2 和 ANN 技術
- 第 2 部分:TensorFlow 2.00 Alpha 中的監督和無監督學習
- 四、TensorFlow 2 和監督機器學習
- 五、TensorFlow 2 和無監督學習
- 第 3 部分:TensorFlow 2.00 Alpha 的神經網絡應用
- 六、使用 TensorFlow 2 識別圖像
- 七、TensorFlow 2 和神經風格遷移
- 八、TensorFlow 2 和循環神經網絡
- 九、TensorFlow 估計器和 TensorFlow HUB
- 十、從 tf1.12 轉換為 tf2
- TensorFlow 入門
- 零、前言
- 一、TensorFlow 基本概念
- 二、TensorFlow 數學運算
- 三、機器學習入門
- 四、神經網絡簡介
- 五、深度學習
- 六、TensorFlow GPU 編程和服務
- TensorFlow 卷積神經網絡實用指南
- 零、前言
- 一、TensorFlow 的設置和介紹
- 二、深度學習和卷積神經網絡
- 三、TensorFlow 中的圖像分類
- 四、目標檢測與分割
- 五、VGG,Inception,ResNet 和 MobileNets
- 六、自編碼器,變分自編碼器和生成對抗網絡
- 七、遷移學習
- 八、機器學習最佳實踐和故障排除
- 九、大規模訓練
- 十、參考文獻