# 四、循環神經網絡介紹
在上一章中,您了解了卷積網絡。 現在,該介紹一種新型的模型和問題了-循環神經網絡(RNN)。 在本章中,我們將解釋 RNN 的工作原理,并在 TensorFlow 中實現一個。 我們的示例問題將是具有天氣信息的簡單季節預報器。 我們還將看一下`skflow`,它是 TensorFlow 的簡化接口。 這將使我們能夠快速重新實現舊的圖像分類模型和新的 RNN。 在本章的最后,您將對以下概念有很好的理解:
* 探索 RNN
* TensorFlow Learn
* 密集神經網絡(DNN)
# 探索 RNN
在本節中,我們將探索 RNN。 一些背景信息將使我們開始工作,然后我們將探討一個激發性的天氣建模問題。 我們還將在 TensorFlow 中實現和訓練 RNN。

在典型模型中,您要預測一些`X`輸入特征和一些`Y`輸出。 我們通常將不同的訓練樣本視為獨立的觀察結果。 因此,數據點 1 的特征不應影響數據點 2 的預測。 但是,如果我們的數據點相互關聯怎么辦? 最常見的示例是每個數據點`Xt`代表在時間`t`收集的特征。 自然地假設時間`t`和時間`t+1`的特征對于時間`t+1`的預測都將很重要。 換句話說,歷史很重要。
現在,在建模時,您可以只包含兩倍的輸入特征,將前一個時間步長添加到當前特征中,并計算兩倍的輸入權重。 但是,如果您正在努力構建神經網絡來計算變換特征,那么可以在當前時間步網絡中使用上一個時間步的中間特征就很好了。
RNN 正是這樣做的。 像往常一樣考慮您的輸入`Xt`,但在某些狀態下添加來自上一個時間步的`St-1`作為附加特征。 現在,您可以像往常一樣計算權重以預測`Yt`,并產生一個新的內部狀態`St`,以供下一步使用。 對于第一步,通常使用默認或零初始狀態。 經典的 RNN 實際上就是這么簡單,但是當今文學中有更高級的結構,例如門控循環單元和長短期存儲電路。 這些不在本書的討論范圍之內,但是它們遵循相同的原理,并且通常適用于相同類型的問題。
## 模型權重
您可能想知道我們如何根據上一個時間步長計算所有這些相關性的權重。 計算梯度確實涉及到時間計算的遞歸,但不要擔心,TensorFlow 處理乏味的東西,讓我們進行建模:
```py
# read in data
filename = 'weather.npz'
data = np.load(filename)
daily = data['daily']
weekly = data['weekly']
num_weeks = len(weekly)
dates = np.array([datetime.datetime.strptime(str(int(d)),
'%Y%m%d') for d in weekly[:,0]])
```
要使用 RNN,我們需要一個帶有時間成分的數據建模問題。
字體分類問題在這里并不是很合適。 因此,讓我們看一些天氣數據。 `weather.npz`文件是幾十年來來自美國一個城市的氣象站數據的集合。 `daily`數組包含一年中每一天的測量值。 數據有六列,從日期開始。 接下來是降雨量,以英寸為單位測量當日的降雨量。 之后,出現兩列降雪-第一列是當前地面上的實測雪,而第二列是當天的降雪,單位是英寸。 最后,我們有一些溫度信息,以華氏度為單位的每日最高和最低每日溫度。
我們將使用的`weekly`數組是每日信息的每周摘要。 我們將使用中間日期來表示一周,然后,我們將匯總一周中的所有降雨量。 但是,對于降雪,我們將平均降雪量,因為從一個寒冷的天氣到第二天坐在地上的積雪都沒有意義。 雖然降雪,但我們總共要一周,就像下雨一樣。 最后,我們將平均一周的高溫和低溫。 現在您已經掌握了數據集,我們該如何處理? 一個有趣的基于時間的建模問題是,嘗試使用天氣信息和前幾周的歷史來預測特定一周的季節。
在美國的北半球,6 月至 8 月的氣溫較高,而 12 月至 2 月的氣溫較低,兩者之間有過渡。 春季通常是多雨的,冬季通常包括雪。 盡管一周的變化很大,但一周的歷史應該可以提供一定的預測能力。
## 了解 RNN
首先,讓我們從壓縮的 NumPy 數組中讀取數據。 如果您想探索自己的模型,`weather.npz`文件也包括每日數據。 `np.load`將兩個數組都讀入字典,并將每周設置為我們感興趣的數據; `num_weeks`自然就是我們擁有多少個數據點,在這里,幾十年的信息的值:
```py
num_weeks = len(weekly)
```
為了格式化星期,我們使用 Python `datetime.datetime`對象以年月日格式讀取存儲字符串:
```py
dates = np.array([datetime.datetime.strptime(str(int(d)),
'%Y%m%d') for d in weekly[:,0]])
```
我們可以使用每周的日期來指定其季節。 對于此模型,因為我們正在查看天氣數據,所以我們使用氣象季節而不是普通的天文季節。 幸運的是,這很容易通過 Python 函數實現。 從`datetime`對象中獲取月份,我們可以直接計算出該季節。 春季,零季節是 3 月至 5 月,夏季是 6 月至 8 月,秋天是 9 月至 11 月,最后是冬季 12 月至 2 月。 以下是簡單的函數,它僅求值月份并實現該月份:
```py
def assign_season(date):
''' Assign season based on meteorological season.
Spring - from Mar 1 to May 31
Summer - from Jun 1 to Aug 31
Autumn - from Sep 1 to Nov 30
Winter - from Dec 1 to Feb 28 (Feb 29 in a leap year)
'''
month = date.month
# spring = 0
if 3 <= month < 6:
season = 0
# summer = 1
elif 6 <= month < 9:
season = 1
# autumn = 2
elif 9 <= month < 12:
season = 2
# winter = 3
elif month == 12 or month < 3:
season = 3
return season
```
讓我們注意一下,我們有四個季節和五個輸入變量,例如歷史狀態中的 11 個值:
```py
# There are 4 seasons
num_classes = 4
# and 5 variables
num_inputs = 5
# And a state of 11 numbers
state_size = 11
```
現在您可以計算標簽了:
```py
labels = np.zeros([num_weeks,num_classes])
# read and convert to one-hot
for i,d in enumerate(dates):
labels[i,assign_season(d)] = 1
```
通過制作全零數組并在分配季節的位置放置一個全零,我們直接以一鍵式格式執行此操作。
涼! 您僅用幾個命令就總結了幾十年的時間。
由于這些輸入特征在非常不同的尺度上測量非常不同的事物,即降雨,降雪和溫度,因此我們應注意將它們全部置于相同的尺度上。 在下面的代碼中,我們抓住了輸入特征,當然跳過了日期列,并減去平均值以將所有特征居中為零:
```py
# extract and scale training data
train = weekly[:,1:]
train = train - np.average(train,axis=0)
train = train / train.std(axis=0)
```
然后,我們將每個特征除以其標準偏差來縮放。 這說明溫度范圍大約為 0 到 100,而降雨量僅在大約 0 到 10 之間變化。數據準備工作不錯! 它并不總是很有趣,但這是機器學習和 TensorFlow 的關鍵部分。
現在進入 TensorFlow 模型:
```py
# These will be inputs
x = tf.placeholder("float", [None, num_inputs])
# TF likes a funky input to RNN
x_ = tf.reshape(x, [1, num_weeks, num_inputs])
```
我們使用占位符變量正常輸入數據,但是隨后您會看到將整個數據集奇怪地重塑為一個大張量。 不用擔心,這是因為從技術上講,我們有一個漫長而連續的觀測序列。 `y_`變量只是我們的輸出:
```py
y_ = tf.placeholder("float", [None,num_classes])
```
我們將計算每個季節每周的概率。
`cell`變量是循環神經網絡的關鍵:
```py
cell = tf.nn.rnn_cell.BasicRNNCell(state_size)
```
這告訴 TensorFlow 當前時間步長如何取決于前一個時間步長。 在這種情況下,我們將使用基本的 RNN 單元。 因此,我們一次只回首一周。 假設它具有狀態大小或 11 個值。 隨意嘗試使用更多奇異的單元和不同的狀態大小。
要使用該單元格,我們將使用`tf.nn.dynamic_rnn`:
```py
outputs, states = tf.nn.dynamic_rnn(cell,x_,
dtype=tf.nn.dtypes.float32, initial_state=None)
```
這可以智能地處理遞歸,而不是簡單地將所有時間步長展開成一個巨大的計算圖。 因為我們在一個序列中有成千上萬的觀測值,所以這對于獲得合理的速度至關重要。 在單元格之后,我們指定輸入`x_`,然后指定`dtype`以使用 32 位將十進制數字存儲在浮點數中,然后指定空的`initial_state`。 我們使用此輸出建立一個簡單的模型。 從這一點開始,該模型幾乎完全符合您對任何神經網絡的期望:
我們將 RNN 單元的輸出,一些權重相乘,并添加一個偏差以獲得該周每個類的分數:
```py
W1 = tf.Variable(tf.truncated_normal([state_size,num_classes],
stddev=1./math.sqrt(num_inputs)))
b1 = tf.Variable(tf.constant(0.1,shape=[num_classes]))
# reshape the output for traditional usage
h1 = tf.reshape(outputs,[-1,state_size])
```
### 注意
請注意,由于我們有一個長序列,因此我們確實需要進行此重塑操作以再次獲得合適的大小。
您應該非常熟悉我們的分類`cross_entropy`損失函數和訓練優化器:
```py
# Climb on cross-entropy
cross_entropy = tf.reduce_mean(
tf.nn.softmax_cross_entropy_with_logits(y + 1e-50, y_))
# How we train
train_step = tf.train.GradientDescentOptimizer(0.01
).minimize(cross_entropy)
# Define accuracy
correct_prediction = tf.equal(tf.argmax(y,1),tf.argmax(y_,1))
accuracy=tf.reduce_mean(tf.cast(correct_prediction, "float"))
```
搭建 TensorFlow 模型的出色工作! 為了訓練這一點,我們將使用一個熟悉的循環:
```py
# Actually train
epochs = 100
train_acc = np.zeros(epochs//10)
for i in tqdm(range(epochs), ascii=True):
if i % 10 == 0:
# Record summary data, and the accuracy
# Check accuracy on train set
A = accuracy.eval(feed_dict={x: train, y_: labels})
train_acc[i//10] = A
train_step.run(feed_dict={x: train, y_: labels})
```
由于這是一個虛擬的問題,因此我們不必擔心模型的實際準確率。 這里的目的只是看 RNN 的工作原理。 您可以看到它像任何 TensorFlow 模型一樣運行:

如果您確實看過準確率,您會發現它做得很好。 比 25% 的隨機猜測要好得多,但仍有很多東西需要學習。
# TensorFlowLearn
正如 Scikit-Learn 是傳統機器學習算法的便捷接口一樣,[`tf.contrib.learn`](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/contrib/learn/python/learn)(以前稱為`skflow`),它是構建和訓練 DNN 的簡化接口。 現在,隨 TensorFlow 的每次安裝免費提供!
即使您不喜歡該語法,也值得將 TensorFlow Learn 作為 TensorFlow 的高級 API。 這是因為它是當前唯一受官方支持的版本。 但是,您應該知道,有許多替代的高級 API 可能具有更直觀的接口。 如果有興趣,請參閱 [Keras](https://keras.io/),`tf.slim`(包含在 TF 中)或 [TFLearn](http://tflearn.org/)。為了了解有關 TensorFlow-Slim 的更多信息,請參閱[此鏈接](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/contrib/slim)。
## 起步
要開始使用 TensorFlow Learn,您只需導入它即可。 我們還將導入`estimators`函數,這將幫助我們制作常規模型:
```py
# TF made EZ
import tensorflow.contrib.learn as learn
from tensorflow.contrib.learn.python.learn.estimators import estimator
```
我們還希望導入一些用于基本操作的庫 -- 抓取 NumPy,`math`和 Matplotlib(可選)。 這里值得注意的是`sklearn`,這是一個通用的機器學習庫,它試圖簡化模型的創建,訓練和使用。 我們主要將其用于方便的指標,但是您會發現它具有與 Learn 類似的主接口:
```py
# Some basics
import numpy as np
import math
import matplotlib.pyplot as plt
plt.ion()
# Learn more sklearn
# scikit-learn.org
import sklearn
from sklearn import metrics
```
接下來,我們將讀取一些數據進行處理。 由于您熟悉字體分類問題,因此讓我們繼續對其建模。 為了重現性,您可以使用自己喜歡的數字為 NumPy 播種:
```py
# Seed the data
np.random.seed(42)
# Load data
data = np.load('data_with_labels.npz')
train = data['arr_0']/255.
labels = data['arr_1']
```
對于本練習,將您的數據分為訓練和驗證集; `np.random.permutation`對于為您的輸入數據生成隨機順序很有用,所以讓我們像在以前的模塊中那樣使用它:
```py
# Split data into training and validation
indices = np.random.permutation(train.shape[0])
valid_cnt = int(train.shape[0] * 0.1)
test_idx, training_idx = indices[:valid_cnt],\
indices[valid_cnt:]
test, train = train[test_idx,:],\
train[training_idx,:]
test_labels, train_labels = labels[test_idx],\
labels[training_idx]
```
在這里,`tf.contrib.learn`可以對其接收的數據類型有所變幻。 為了發揮出色,我們需要重鑄數據。 圖像輸入將是`np.float32`,而不是默認的 64 位。 同樣,我們的標簽將是`np.int32`而不是`np.uint8`,即使這只會占用更多內存:
```py
train = np.array(train,dtype=np.float32)
test = np.array(test,dtype=np.float32)
train_labels = np.array(train_labels,dtype=np.int32)
test_labels = np.array(test_labels,dtype=np.int32)
```
## 邏輯回歸
讓我們做一個簡單的邏輯回歸示例。 這將非常迅速,并顯示`learn`如何使簡單的模型變得異常簡單。 首先,我們必須創建模型期望輸入的變量列表。 您可能希望可以使用一個簡單的參數來設置它,但實際上是這個不直觀的`learn.infer_real_valued_columns_from_input`函數。 基本上,如果將輸入數據提供給該函數,它將推斷出您擁有多少個特征列以及其應處于的形狀。在我們的線性模型中,我們希望將圖像展平為一維,因此我們對其執行整形推斷函數時:
```py
# Convert features to learn style
feature_columns = learn.infer_real_valued_columns_from_input(train.reshape([-1,36*36]))
```
現在創建一個名為`classifier`的新變量,并為其分配`estimator.SKCompat`結構。 這是一個 Scikit-Learn 兼容性層,允許您在 TensorFlow 模型中使用某些 Scikit-Learn 模塊。
無論如何,這僅僅是敷料,真正創建模型的是`learn.LinearClassifier`。 這樣就建立了模型,但是沒有訓練。 因此,它只需要幾個參數。 首先是那個時髦的`feature_columns`對象,只是讓您的模型知道期望輸入什么。 第二個也是最后一個必需的參數是它的反函數,模型應具有多少個輸出值? 我們有五種字體,因此設置`n_classes = 5`。 這就是整個模型規格!
```py
# Logistic Regression
classifier = estimator.SKCompat(learn.LinearClassifier(
feature_columns = feature_columns,
n_classes=5))
```
要進行訓練,只需要一行。 調用`classifier.fit`并輸入數據(當然是經過調整的形狀),輸出標簽(請注意,這些標簽不必是一字不漏的格式)以及其他一些參數。 `steps`參數確定模型將查看多少批次,即優化算法要采取的步驟。 `batch_size`參數通常是優化步驟中要使用的數據點數。 因此,您可以將步數乘以批次大小除以訓練集中的數據點數來計算周期數。 這似乎有點違反直覺,但至少是一個快速的說明,您可以輕松編寫幫助函數以在步驟和周期之間進行轉換:
```py
# One line training
# steps is number of total batches
# steps*batch_size/len(train) = num_epochs
classifier.fit(train.reshape([-1,36*36]),
train_labels,
steps=1024,
batch_size=32)
```
為了評估我們的模型,我們將照常使用`sklearn`的`metrics`。 但是,基本學習模型預測的輸出現在是字典,其中包含預先計算的類標簽以及概率和對數。 要提取類標簽,請使用鍵`classes`:
```py
# sklearn compatible accuracy
test_probs = classifier.predict(test.reshape([-1,36*36]))
sklearn.metrics.accuracy_score(test_labels,
test_probs['classes'])
```
# DNN
盡管有更好的方法來實現純線性模型,但 TensorFlow 和`learn`真正的亮點在于簡化具有不同層數的 DNN。
我們將使用相同的輸入特征,但現在我們將構建一個具有兩個隱藏層的 DNN,首先是`10`神經元,然后是`5`。 創建此模型僅需一行 Python 代碼; 這再簡單不過了。
規格類似于我們的線性模型。 我們仍然需要`SKCompat`,但現在是`learn.DNNClassifier`。 對于參數,還有一個額外的要求:每個隱藏層上的神經元數量,以列表的形式傳遞。 這個簡單的參數真正抓住了 DNN 模型的本質,使深度學習的力量觸手可及。
也有一些可選的參數,但是我們只提及`optimizer`。 這樣,您就可以在不同的常見優化器例程之間進行選擇,例如隨機梯度下降(SGD)或 Adam。 很方便!
```py
# Dense neural net
classifier = estimator.SKCompat(learn.DNNClassifier(
feature_columns = feature_columns,
hidden_units=[10,5],
n_classes=5,
optimizer='Adam'))
```
訓練和評估與線性模型完全一樣。 僅出于演示目的,我們還可以查看此模型創建的混淆矩陣。 請注意,我們訓練不多,因此該模型可能無法與使用純 TensorFlow 的早期作品競爭:
```py
# Same training call
classifier.fit(train.reshape([-1,36*36]),
train_labels,
steps=1024,
batch_size=32)
# simple accuracy
test_probs = classifier.predict(test.reshape([-1,36*36]))
sklearn.metrics.accuracy_score(test_labels,
test_probs['classes'])
# confusion is easy
train_probs = classifier.predict(train.reshape([-1,36*36]))
conf = metrics.confusion_matrix(train_labels,
train_probs['classes'])
print(conf)
```
## TFLearn 中的卷積神經網絡(CNN)
CNN 支持一些最成功的機器學習模型,因此我們希望`learn`支持它們。 實際上,該庫支持使用任意 TensorFlow 代碼! 您會發現這是一種祝福和詛咒。 擁有任意可用的代碼意味著您可以使用`learn`來執行幾乎可以使用純 TensorFlow 進行的所有操作,從而提供最大的靈活性。 但是通用接口往往會使代碼更難以讀寫。
如果您發現自己在`learn`中使用接口使某些復雜的模型起作用,那么可能是時候使用純 TensorFlow 或切換到另一個 API 了。
為了證明這種通用性,我們將構建一個簡單的 CNN 來解決字體分類問題。 它將具有一個帶有四個過濾器的卷積層,然后將其展平為具有五個神經元的隱藏密集層,最后以密集連接的輸出邏輯回歸結束。
首先,讓我們再進行幾個導入。 我們想要訪問通用的 TensorFlow,但是我們還需要`layers`模塊以`learn`期望的方式調用 TensorFlow `layers`:
```py
# Access general TF functions
import tensorflow as tf
import tensorflow.contrib.layers as layers
```
通用接口迫使我們編寫為模型創建操作的函數。 您可能會發現這很乏味,但這就是靈活性的代價。
用三個參數啟動一個名為`conv_learn`的新函數。 `X`將作為輸入數據,`y`將作為輸出標簽(尚未進行一次熱編碼),`mode`確定您是訓練還是預測。 請注意,您永遠不會直接與此特征交互; 您只需將其傳遞給需要這些參數的構造器。 因此,如果您想改變層的數量或類型,則需要編寫一個新的模型函數(或另一個會生成這種模型函數的函數):
```py
def conv_learn(X, y, mode):
```
由于這是卷積模型,因此我們需要確保數據格式正確。 特別是,這意味著將輸入重塑為不僅具有正確的二維形狀(`36x36`),而且具有 1 個顏色通道(最后一個尺寸)。 這是 TensorFlow 計算圖的一部分,因此我們使用`tf.reshape`而不是`np.reshape`。 同樣,由于這是通用圖,因此我們希望將輸出進行一次熱編碼,`tf.one_hot`提供了該功能。 請注意,我們必須描述有多少類(`5`),應設置的值(`1`)和未設置的值(`0`):
```py
# Ensure our images are 2d
X = tf.reshape(X, [-1, 36, 36, 1])
# We'll need these in one-hot format
y = tf.one_hot(tf.cast(y, tf.int32), 5, 1, 0)
```
現在,真正的樂趣開始了。 為了指定卷積層,讓我們初始化一個新的作用域`conv_layer`。 這只會確保我們不會破壞任何變量。 `layers.convolutional`提供了基本的機制。 它接受我們的輸入(一個 TensorFlow 張量),多個輸出(實際上是內核或過濾器的數量)以及內核的大小,這里是`5x5`的窗口。 對于激活函數,讓我們使用整流線性,可以從主 TensorFlow 模塊調用它。 這給了我們基本的卷積輸出`h1`。
實際上,最大池化的發生與常規 TensorFlow 中的發生完全相同,既不容易也不難。 具有通常的內核大小和步幅的`tf.nn.max_pool`函數可以正常工作。 保存到`p1`中:
```py
# conv layer will compute 4 kernels for each 5x5 patch
with tf.variable_scope('conv_layer'):
# 5x5 convolution, pad with zeros on edges
h1 = layers.convolution2d(X, num_outputs=4,
kernel_size=[5, 5],
activation_fn=tf.nn.relu)
# 2x2 Max pooling, no padding on edges
p1 = tf.nn.max_pool(h1, ksize=[1, 2, 2, 1],
strides=[1, 2, 2, 1], padding='VALID')
```
現在,要在此時展平張量,我們需要計算將要成為一維張量的元素數量。 一種方法是將所有尺寸值(`batch_size`除外,它占據第一個位置)相乘。 此特定操作可以在計算圖之外進行,因此我們使用`np.product`。 一旦提供了總大小,我們就可以將其傳遞給`tf.reshape`以重新劃分圖中的中間張量:
```py
# Need to flatten conv output for use in dense layer
p1_size = np.product(
[s.value for s in p1.get_shape()[1:]])
p1f = tf.reshape(p1, [-1, p1_size ])
```
現在是時候建立緊密連接的層了。 `layers`模塊再次出現,這一次具有`fully_connected`函數(致密層的另一個名稱)。 這需要上一層,神經元的數量和激活函數,它們又由通用 TensorFlow 提供。
為了演示的目的,我們也在此處添加一個`dropout`對象。 `layers.dropout`提供了接口。 不出所料,它需要上一層以及保持給定節點輸出的概率。 但是它也需要我們傳遞給原始`conv_learn`函數的`mode`參數。 所有這些復雜的接口只不過是在訓練期間丟棄節點。 如果您能解決這個問題,那么我們幾乎可以遍歷整個模型!
```py
# densely connected layer with 32 neurons and dropout
h_fc1 = layers.fully_connected(p1f,
5,
activation_fn=tf.nn.relu)
drop = layers.dropout(h_fc1, keep_prob=0.5,
is_training=mode == tf.contrib.learn.ModeKeys.TRAIN)
```
現在有一些壞消息。 我們需要手動寫出最終的線性模型,損失函數和優化參數。 這可能會因版本而異,因為在某些情況下,以前對用戶來說更容易,但對后端的維護則更困難。 但是,讓我們堅持下去; 確實不是很繁瑣。
另一個`layers.fully_connected`層創建最終的邏輯回歸。 請注意,此處的激活應為`None`,因為它是線性的。 處理方程邏輯方面的是損失函數。 值得慶幸的是,TensorFlow 提供了`softmax_cross_entropy`函數,因此我們無需手動將其寫出。 給定輸入,輸出和損失函數,我們可以應用優化例程。 同樣,`layers.optimize_loss`以及相關函數可以最大程度地減少痛苦。 將您的損失節點,優化器(作為字符串)和學習率傳遞給它。 此外,為其提供此`get_global_step()`參數,以確保優化程序正確處理衰減。
最后,我們的函數需要返回一些東西。 第一,它應該報告預測的類別。 接下來,它必須自己提供損失節點輸出。 最后,訓練節點必須可用于外部例程以實際執行所有操作:
```py
logits = layers.fully_connected(drop, 5, activation_fn=None)
loss = tf.losses.softmax_cross_entropy(y, logits)
# Setup the training function manually
train_op = layers.optimize_loss(
loss,
tf.contrib.framework.get_global_step(),
optimizer='Adam',
learning_rate=0.01)
return tf.argmax(logits, 1), loss, train_op
```
雖然指定模型可能很麻煩,但使用它就像以前一樣容易。 現在,使用最通用的例程`learn.Estimator`,并將模型函數傳遞給`model_fn`。 并且不要忘記`SKCompat`!
訓練的工作原理與以前完全相同,只是請注意,我們不需要在此處重塑輸入內容,因為這是在函數內部處理的。
要使用模型進行預測,您可以簡單地調用`classifier.predict`,但是請注意,您會獲得函數返回的第一個參數作為輸出。 我們選擇返回該類,但也可以從`softmax`函數中返回概率。 這就是`tf.contrib.learn`模型的基礎!
```py
# Use generic estimator with our function
classifier = estimator.SKCompat(
learn.Estimator(
model_fn=conv_learn))
classifier.fit(train,train_labels,
steps=1024,
batch_size=32)
# simple accuracy
metrics.accuracy_score(test_labels,classifier.predict(test))
```
## 提取權重
雖然訓練和預測是模型的核心用途,但也必須研究模型的內部也很重要。 不幸的是,此 API 使得提取參數權重變得困難。 值得慶幸的是,本節提供了一些文獻記載較弱的功能的簡單示例,以使權重從`tf.contrib.learn`模型中消失。
為了拉出模型的權重,我們確實需要從基礎 TensorFlow 計算圖中的某些點獲取值。 TensorFlow 提供了許多方法來執行此操作,但是第一個問題只是弄清楚您感興趣的變量被稱為什么。
可以使用`learn`圖中的變量名列表,但該變量名已隱藏在`_estimator`隱藏屬性下。 調用`classifier._estimator.get_variable_names()`將返回您各種名稱的字符串列表。 其中許多將是無趣的,例如`OptimizeLoss`條目。 在我們的情況下,我們正在尋找`conv_layer`和`fully_connected`元素:
```py
# See layer names
print(classifier._estimator.get_variable_names())
['OptimizeLoss/beta1_power',
'OptimizeLoss/beta2_power',
'OptimizeLoss/conv_layer/Conv/biases/Adam',
'OptimizeLoss/conv_layer/Conv/biases/Adam_1',
'OptimizeLoss/conv_layer/Conv/weights/Adam',
'OptimizeLoss/conv_layer/Conv/weights/Adam_1',
'OptimizeLoss/fully_connected/biases/Adam',
'OptimizeLoss/fully_connected/biases/Adam_1',
'OptimizeLoss/fully_connected/weights/Adam',
'OptimizeLoss/fully_connected/weights/Adam_1',
'OptimizeLoss/fully_connected_1/biases/Adam',
'OptimizeLoss/fully_connected_1/biases/Adam_1',
'OptimizeLoss/fully_connected_1/weights/Adam',
'OptimizeLoss/fully_connected_1/weights/Adam_1',
'OptimizeLoss/learning_rate',
'conv_layer/Conv/biases',
'conv_layer/Conv/weights',
'fully_connected/biases',
'fully_connected/weights',
'fully_connected_1/biases',
'fully_connected_1/weights',
'global_step']
```
找出哪個條目是您要查找的層可能是一個挑戰。 在這里,`conv_layer`顯然來自我們的卷積層。 但是,您看到兩個`fully_connected`元素,一個是展平時的密集層,另一個是輸出權重。 事實證明,它們是按指定的順序命名的。 我們首先創建了密集的隱藏層,所以它獲得了基本的`fully_connected`名稱,而輸出層位于最后,因此在其上面加上了`_1`。 如果不確定,可以隨時查看權重數組的形狀,具體取決于模型的形狀。
要真正發揮作用,這是另一個不可思議的要求。 這次,`classifier._estimator.get_variable_value`(帶有變量名字符串)提供了具有相關權重的 NumPy 數組。 試用卷積權重和偏差以及密集層:
```py
# Convolutional Layer Weights
print(classifier._estimator.get_variable_value(
'conv_layer/Conv/weights'))
print(classifier._estimator.get_variable_value(
'conv_layer/Conv/biases'))
# Dense Layer
print(classifier._estimator.get_variable_value(
'fully_connected/weights'))
# Logistic weights
print(classifier._estimator.get_variable_value(
'fully_connected_1/weights'))
```
現在,掌握了如何在`tf.contrib.learn`神經網絡內部進行交流的深奧知識,您將可以使用此高級 API 擁有更多的能力。 盡管在許多情況下很方便,但在其他情況下卻很麻煩。 永遠不要害怕暫停并考慮切換到另一個庫; 為正確的機器學習工作使用正確的機器學習工具。
# 總結
從簡單理解 RNN 到在新的 TensorFlow 模型中實現它們,您在本章中學到了很多東西。 我們還查看了 TensorFlow 的一個簡單接口,稱為 TensorFlow Learn。 我們還遍歷了 DNN,并了解了 CNN 和詳細提取權重。
在下一章中,我們將對 TensorFlow 進行總結,看看我們已經走了多遠,以及從這里可以去哪里。
- 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
- 六、自編碼器,變分自編碼器和生成對抗網絡
- 七、遷移學習
- 八、機器學習最佳實踐和故障排除
- 九、大規模訓練
- 十、參考文獻