TensorFlow 學習指南 一、基礎
TensorFlow 學習指南 一、基礎
原文:ofollow,noindex">LearningTensorFlow.com
譯者:飛龍
自豪地採用谷歌翻譯
變數
TensorFlow 是一種表示計算的方式,直到請求時才實際執行。 從這個意義上講,它是一種延遲計算形式,它能夠極大改善程式碼的執行:
- 更快地計算複雜變數
- 跨多個系統的分散式計算,包括 GPU。
- 減少了某些計算中的冗餘
我們來看看實際情況。 首先,一個非常基本的 python 指令碼:
x = 35 y = x + 5 print(y)
這個指令碼基本上只是“建立一個值為35
的變數x
,將新變數y
的值設定為它加上5
,當前為40
,並將其打印出來”。 執行此程式時將打印出值40
。 如果你不熟悉 python,請建立一個名為basic_script.py
的新文字檔案,並將該程式碼複製到該檔案中。將其儲存在你的計算機上並執行它:
python basic_script.py
請注意,路徑(即basic_script.py
)必須指向該檔案,因此如果它位於Code
資料夾中,則使用:
python Code/basic_script.py
此外,請確保已啟用 Anaconda 虛擬環境。 在 Linux 上,這將使你的提示符看起來像:
(tensorenv)username@computername:~$
如果起作用,讓我們將其轉換為 TensorFlow 等價形式。
import tensorflow as tf x = tf.constant(35, name='x') y = tf.Variable(x + 5, name='y') print(y)
執行之後,你會得到一個非常有趣的輸出,類似於<tensorflow.python.ops.variables.Variable object at 0x7f074bfd9ef0>
。 這顯然不是40
的值。
原因在於,我們的程式實際上與前一個程式完全不同。 這裡的程式碼執行以下操作:
-
匯入
tensorflow
模組並將其命名為tf
-
建立一個名為
x
的常量值,併為其賦值35
-
建立一個名為
y
的變數,並將其定義為等式x + 5
-
列印
y
的等式物件
微妙的區別是,y
沒有像我們之前的程式那樣,給出x + 5
的當前值”。 相反,它實際上是一個等式,意思是“當計算這個變數時,取x
的值(就像那樣)並將它加上5
”。y
值的計算在上述程式中從未實際執行。
我們來解決這個問題:
import tensorflow as tf x = tf.constant(35, name='x') y = tf.Variable(x + 5, name='y') model = tf.global_variables_initializer() with tf.Session() as session: session.run(model) print(session.run(y))
我們刪除了print(y)
語句,而是建立了一個會話,並實際計算了y
的值。這裡有相當多的樣板,但它的工作原理如下:
-
匯入
tensorflow
模組並將其命名為tf
-
建立一個名為
x
的常量值,併為其賦值35
-
建立一個名為
y
的變數,並將其定義為等式x + 5
-
使用
tf.global_variables_initializer()
初始化變數(我們將在此詳細介紹) - 建立用於計算值的會話
- 執行第四步中建立的模型
-
僅執行變數
y
並打印出其當前值
上面的第四步是一些魔術發生的地方。在此步驟中,將建立變數之間的依賴關係的圖。在這種情況下,變數y
取決於變數x
,並且通過向其新增5
來轉換它的值。請記住,直到第七步才計算該值,在此之前,僅計算等式和關係。
1)常量也可以是陣列。預測此程式碼將執行的操作,然後執行它來確認:
import tensorflow as tf x = tf.constant([35, 40, 45], name='x') y = tf.Variable(x + 5, name='y') model = tf.global_variables_initializer() with tf.Session() as session: session.run(model) print(session.run(y))
生成包含 10,000 個隨機數的 NumPy 陣列(稱為x
),並建立一個儲存等式的變數。

image
你可以使用以下程式碼生成 NumPy 陣列:
import numpy as np data = np.random.randint(1000, size=10000)
然後可以使用data
變數代替上面問題 1 中的列表。 作為一般規則,NumPy 應該用於更大的列表/數字陣列,因為它具有比列表更高的記憶體效率和更快的計算速度。 它還提供了大量的函式(例如計算均值),通常不可用於列表。
3)你還可以在迴圈更新的變數,稍後我們將這些變數用於機器學習。 看看這段程式碼,預測它會做什麼(然後執行它來檢查):
import tensorflow as tf x = tf.Variable(0, name='x') model = tf.global_variables_initializer() with tf.Session() as session: session.run(model) for i in range(5): x = x + 1 print(session.run(x))
4)使用上面(2)和(3)中的程式碼,建立一個程式,計算以下程式碼行的“滑動”平均值:np.random.randint(1000)
。 換句話說,保持迴圈,並在每個迴圈中,呼叫np.random.randint(1000)
一次,並將當前平均值儲存在在每個迴圈中不斷更新變數中。
5)使用 TensorBoard 視覺化其中一些示例的圖。 要執行 TensorBoard,請使用以下命令:tensorboard --logdir=path/to/log-directory
。
import tensorflow as tf x = tf.constant(35, name='x') print(x) y = tf.Variable(x + 5, name='y') with tf.Session() as session: merged = tf.summary.merge_all() writer = tf.summary.FileWriter("/tmp/basic", session.graph) model =tf.global_variables_initializer() session.run(model) print(session.run(y))
要了解 Tensorboard 的更多資訊,請訪問我們的視覺化課程 。
陣列
在本教程中,我們將處理影象,以便視覺化陣列的更改。 陣列是強大的結構,我們在前面的教程中簡要介紹了它。 生成有趣的陣列可能很困難,但影象提供了很好的選擇。
首先,下載此影象到你的計算機(右鍵單擊,並尋找選項“圖片另存為”)。
[圖片上傳失敗...(image-98f5bd-1538558671775)]
此圖片來自維基共享的使用者 Uoaei1 。
要處理影象,我們需要matplotlib
。 我們還需要pillow
庫,它會覆蓋已棄用的 PIL 庫來處理影象。 你可以使用 Anaconda 的安裝方法在你的環境中安裝它們:
conda install matplotlib pillow
要載入影象,我們使用matplotlib
的影象模組:
import matplotlib.image as mpimg import os # 首先載入影象 dir_path = os.path.dirname(os.path.realpath(__file__)) filename = dir_path + "/MarshOrchid.jpg" # 載入影象 image = mpimg.imread(filename) # 列印它的形狀 print(image.shape)
上面的程式碼將影象作為 NumPy 陣列讀入,並打印出大小。 請注意,檔名必須是下載的影象檔案的完整路徑(絕對路徑或相對路徑)。
你會看到輸出,即(5528, 3685, 3)
。 這意味著影象高 5528 畫素,寬 3685 畫素,3 種顏色“深”。
你可以使用pyplot
檢視當前影象,如下所示:
import matplotlib.pyplot as plt plt.imshow(image) plt.show()
現在我們有了影象,讓我們使用 TensorFlow 對它進行一些更改。
幾何操作
我們將要執行的第一個轉換是轉置,將影象逆時針旋轉 90 度。 完整的程式如下,其中大部分是你見過的。
import tensorflow as tf import matplotlib.image as mpimg import matplotlib.pyplot as plt import os # 再次載入影象 dir_path = os.path.dirname(os.path.realpath(__file__)) filename = dir_path + "/MarshOrchid.jpg" image = mpimg.imread(filename) # 建立 TF 變數 x = tf.Variable(image, name='x') model = tf.global_variables_initializer() with tf.Session() as session: x = tf.transpose(x, perm=[1, 0, 2]) session.run(model) result = session.run(x) plt.imshow(result) plt.show()
轉置操作的結果:

image
新東西是這一行:
x = tf.transpose(x, perm=[1, 0, 2])
該行使用 TensorFlow 的transpose
方法,使用perm
引數交換軸 0 和 1(軸 2 保持原樣)。
我們將要做的下一個操作是(左右)翻轉,將畫素從一側交換到另一側。 TensorFlow 有一個稱為reverse_sequence
的方法,但簽名有點奇怪。 這是文件所說的內容(來自該頁面
):
tf.reverse_sequence( input, seq_lengths, seq_axis=None, batch_axis=None, name=None, seq_dim=None, batch_dim=None )
反轉可變長度切片。
這個操作首先沿著維度batch_axis
對input
卻偏,並且對於每個切片i
,沿著維度seq_axis
反轉第一個seq_lengths [i]
元素。
seq_lengths
的元素必須滿足seq_lengths [i] <= input.dims [seq_dim]
,而seq_lengths
必須是長度為input.dims [batch_dim]
的向量。
然後,輸入切片i
給出了沿維度batch_axis
的輸出切片i
,其中第一個seq_lengths [i]
切片沿著維度seq_axis
被反轉。
對於這個函式,最好將其視為:
-
根據
batch_dim
迭代陣列。 設定batch_dim = 0
意味著我們遍歷行(從上到下)。 -
對於迭代中的每個專案
-
對第二維切片,用
seq_dim
表示。 設定seq_dim = 1
意味著我們遍歷列(從左到右)。 -
迭代中第
n
項的切片由seq_lengths
中的第n
項表示
-
對第二維切片,用
讓我們實際看看它:
import numpy as np import tensorflow as tf import matplotlib.image as mpimg import matplotlib.pyplot as plt import os # First, load the image again dir_path = os.path.dirname(os.path.realpath(__file__)) filename = dir_path + "/MarshOrchid.jpg" image = mpimg.imread(filename) height, width, depth = image.shape # Create a TensorFlow Variable x = tf.Variable(image, name='x') model = tf.global_variables_initializer() with tf.Session() as session: x = tf.reverse_sequence(x, [width] * height, 1, batch_dim=0) session.run(model) result = session.run(x) print(result.shape) plt.imshow(result) plt.show()
新東西是這一行:
x = tf.reverse_sequence(x, np.ones((height,)) * width, 1, batch_dim=0)
它從上到下(沿著它的高度)迭代影象,並從左到右(沿著它的寬度)切片。 從這裡開始,它選取大小為width
的切片,其中width
是影象的寬度。
譯者注:
還有兩個函式用於實現切片操作。一個是
tf.reverse
,另一個是張量的下標和切片運算子(和 NumPy 用法一樣)。
程式碼np.ones((height,)) * width
建立一個填充值width
的 NumPy 陣列。 這不是很有效! 不幸的是,在編寫本文時,似乎此函式不允許你僅指定單個值。
“翻轉”操作的結果:

image
1)將轉置與翻轉程式碼組合來順時針旋轉。
2)目前,翻轉程式碼(使用reverse_sequence
)需要預先計算寬度。 檢視tf.shape
函式的文件,並使用它在會話中計算x
變數的寬度。
3)執行“翻轉”,從上到下翻轉影象。
4)計算“映象”,複製影象的前半部分,(左右)翻轉然後複製到後半部分。
佔位符
到目前為止,我們已經使用Variables
來管理我們的資料,但是有一個更基本的結構,即佔位符。 佔位符只是一個變數,我們將在以後向它分配資料。 它允許我們建立我們的操作,並構建我們的計算圖,而不需要資料。 在 TensorFlow 術語中,我們隨後通過這些佔位符,將資料提供給圖。
import tensorflow as tf x = tf.placeholder("float", None) y = x * 2 with tf.Session() as session: result = session.run(y, feed_dict={x: [1, 2, 3]}) print(result)
這個例子與我們之前的例子略有不同,讓我們分解它。
首先,我們正常匯入tensorflow
。然後我們建立一個名為x
的placeholder
,即我們稍後將儲存值的記憶體中的位置。
然後,我們建立一個Tensor
,它是x
乘以 2 的運算。注意我們還沒有為x
定義任何初始值。
我們現在定義了一個操作(y
),現在可以在會話中執行它。我們建立一個會話物件,然後只執行y
變數。請注意,這意味著,如果我們定義了更大的操作圖,我們只能執行圖的一小部分。這個子圖求值實際上是 TensorFlow 的一個賣點,而且許多其他類似的東西都沒有。
執行y
需要了解x
的值。我們在feed_dict
引數中定義這些來執行。我們在這裡宣告x
的值是[1,2,3]
。我們執行y
,給了我們結果[2,4,6]
。
佔位符不需要靜態大小。讓我們更新我們的程式,讓x
可以接受任何長度。將x
的定義更改為:
x = tf.placeholder("float", None)
現在,當我們在feed_dict
中定義x
的值時,我們可以有任意維度的值。 程式碼應該仍然有效,並給出相同的答案,但現在它也可以處理feed_dict
中的任意維度的值。
佔位符也可以有多個維度,允許儲存陣列。 在下面的示例中,我們建立一個 3 乘 2 的矩陣,並在其中儲存一些數字。 然後,我們使用與以前相同的操作,來逐元素加倍數字。
import tensorflow as tf x = tf.placeholder("float", [None, 3]) y = x * 2 with tf.Session() as session: x_data = [[1, 2, 3], [4, 5, 6],] result = session.run(y, feed_dict={x: x_data}) print(result)
佔位符的第一個維度是None
,這意味著我們可以有任意數量的行。 第二個維度固定為 3,這意味著每行需要有三列資料。
我們可以擴充套件它來接受任意數量的None
維度。 在此示例中,我們載入來自上一課的影象,然後建立一個儲存該影象切片的佔位符。 切片是影象的 2D 片段,但每個“畫素”具有三個分量(紅色,綠色,藍色)。 因此,對於前兩個維度,我們需要None
,但是對於最後一個維度,需要 3(或None
也能用)。 然後,我們使用 TensorFlow 的切片方法從影象中取出一個子片段來操作。
import tensorflow as tf import matplotlib.image as mpimg import matplotlib.pyplot as plt import os # First, load the image again dir_path = os.path.dirname(os.path.realpath(__file__)) filename = dir_path + "/MarshOrchid.jpg" raw_image_data = mpimg.imread(filename) image = tf.placeholder("uint8", [None, None, 3]) slice = tf.slice(image, [1000, 0, 0], [3000, -1, -1]) with tf.Session() as session: result = session.run(slice, feed_dict={image: raw_image_data}) print(result.shape) plt.imshow(result) plt.show()
譯者注:使用下標和切片運算子也可以實現切片。
結果是影象的子片段:

image
1)在官方文件中檢視 TensorFlow 中的其他陣列函式 。
2)將影象分成四個“角”,然後再將它拼在一起。
3)將影象轉換為灰度。 一種方法是隻採用一個顏色通道並顯示。 另一種方法是將三個通道的平均值作為灰色。
互動式會話
現在我們有了一些例子,讓我們更仔細地看看發生了什麼。
正如我們之前已經確定的那樣,TensorFlow 允許我們建立操作和變數圖。這些變數稱為張量,表示資料,無論是單個數字,字串,矩陣還是其他內容。張量通過操作來組合,整個過程以圖來建模。
首先,確保激活了tensorenv
虛擬環境,一旦啟用,請輸入conda install jupyter
來安裝jupter books
。
然後,執行jupyter notebook
以啟動 Jupyter Notebook(以前稱為 IPython Notebook)的瀏覽器會話。 (如果你的瀏覽器沒有開啟,請開啟它並在瀏覽器的位址列中輸入localhost:8888
。)
單擊New
(新建),然後單擊Notebooks
(筆記本)下的Python 3
(Python 3)。這將啟動一個新的瀏覽器選項卡。通過單擊頂部的Untitled
(無標題)為該筆記本命名,併為其命名(我使用Interactive TensorFlow
)。
如果你以前從未使用過 Jupyter 筆記本(或 IPython 筆記本),請檢視此站點 來獲得簡介。
接下來,和以前一樣,讓我們建立一個基本的 TensorFlow 程式。 一個主要的變化是使用InteractiveSession
,它允許我們執行變數,而不需要經常引用會話物件(減少輸入!)。 下面的程式碼塊分為不同的單元格。 如果你看到程式碼中斷,則需要先執行上一個單元格。 此外,如果你不自信,請確保在執行之前將給定塊中的所有程式碼鍵入單元格。
import tensorflow as tf session = tf.InteractiveSession() x = tf.constant(list(range(10)))
在這段程式碼中,我們建立了一個InteractiveSession
,然後定義一個常量值,就像一個佔位符,但具有設定的值(不會改變)。 在下一個單元格中,我們可以求解此常量並列印結果。
print(x.eval())
下面我們關閉開啟的會話。
session.close()
關閉會話非常重要,並且很容易忘記。 出於這個原因,我們在之前的教程中使用with
關鍵字來處理這個問題。 當with
塊完成執行時,會話將被關閉(如果發生錯誤也會發生這種情況 - 會話仍然關閉)。
現在讓我們來看更大的例子。 在這個例子中,我們將使用一個非常大的矩陣並對其進行計算,跟蹤何時使用記憶體。 首先,讓我們看看我們的 Python 會話當前使用了多少記憶體:
import resource print("{} Kb".format(resource.getrusage(resource.RUSAGE_SELF).ru_maxrss))
在我的系統上,執行上面的程式碼之後,使用了 78496 千位元組。 現在,建立一個新會話,並定義兩個矩陣:
import numpy as np session = tf.InteractiveSession() X = tf.constant(np.eye(10000)) Y = tf.constant(np.random.randn(10000, 300))
讓我們再看一下我們的記憶體使用情況:
print("{} Kb".format(resource.getrusage(resource.RUSAGE_SELF).ru_maxrss))
在我的系統上,記憶體使用率躍升至 885,220 Kb - 那些矩陣很大!
現在,讓我們使用matmul
將這些矩陣相乘:
Z = tf.matmul(X, Y)
如果我們現在檢查我們的記憶體使用情況,我們發現沒有使用更多的記憶體 - 沒有實際的Z
的計算。 只有當我們求解操作時,我們才真正計算。 對於互動式會話,你可以使用Z.eval()
,而不是執行session.run(Z)
。 請注意,你不能總是依賴.eval()
,因為這是使用“預設”會話的快捷方式,不一定是你要使用的會話。
如果你的計算機比較低階(例如,ram 低於 3Gb),那麼不要執行此程式碼 - 相信我!
Z.eval()
你的計算機會考慮很長一段時間,因為現在它才實際執行這些矩陣相乘。 之後檢查記憶體使用情況會發現此計算已經發生,因為它現在使用了接近 3Gb!
print("{} Kb".format(resource.getrusage(resource.RUSAGE_SELF).ru_maxrss))
別忘了關閉你的會話!
session.close()
注意:我建議使用新的 Jupyter Notebook,因為上面的示例程式碼可能會被意外再次執行,可能導致計算機崩潰!
1)建立一個整數值的大矩陣(至少 10,000,000)(例如,使用 NumPy 的randint
函式)。 建立矩陣後檢查記憶體使用情況。 然後,使用 TensorFlow 的to_float
函式將矩陣轉換為浮點值。 再次檢查記憶體使用情況,看到記憶體使用量增加超過兩倍。 “加倍”是由建立矩陣的副本引起的,但是“額外增加”的原因是什麼? 執行此實驗後,你可以使用此程式碼顯示影象。
from PIL import Image from io import BytesIO # 從字串讀取資料 im = Image.open(BytesIO(result)) im
提示:確保在每一步之後仔細測量記憶體使用情況,因為只是匯入 TensorFlow 就會使用相當多的記憶體。
2)使用 TensorFlow 的影象函式將上一個教程中的影象(或其他影象)轉換為 JPEG 並記錄記憶體使用情況。
視覺化
在本課中,我們將介紹如何使用 TensorBoard 建立和視覺化圖。 我們在第一課變數中簡要地瀏覽了 TensorBoard
那麼什麼是 TensorBoard 以及我們為什麼要使用它呢?
TensorBoard 是一套 Web 應用程式,用於檢查和理解你的 TensorFlow 執行和圖。 TensorBoard 目前支援五種視覺化:標量,影象,音訊,直方圖和圖。 你將在 TensorFlow 中的計算用於訓練大型深度神經網路,可能相當複雜且令人困惑,TensorBoard 將使你更容易理解,除錯和優化 TensorFlow 程式。
要實際檢視 TensorBoard,請單擊此處 。
這就是 TensorBoard 圖的樣子:
[圖片上傳失敗...(image-42df2c-1538558671775)]
基本的指令碼
下面我們有了構建 TensorBoard 圖的基本指令碼。 現在,如果你在 python 直譯器中執行它,會返回 63。
import tensorflow as tf a = tf.add(1, 2,) b = tf.multiply(a, 3) c = tf.add(4, 5,) d = tf.multiply(c, 6,) e = tf.multiply(4, 5,) f = tf.div(c, 6,) g = tf.add(b, d) h = tf.multiply(g, f) with tf.Session() as sess: print(sess.run(h))
現在我們在程式碼末尾新增一個SummaryWriter
,這將在給定目錄中建立一個資料夾,其中包含 TensorBoard 用於構建圖的資訊。
with tf.Session() as sess: writer = tf.summary.FileWriter("output", sess.graph) print(sess.run(h)) writer.close()
如果你現在執行 TensorBoard,使用tensorboard --logdir=path/to/logs/directory
,你會看到在你給定的目錄中,你得到一個名為output
的資料夾。 如果你在終端中訪問 IP 地址,它將帶你到 TensorBoard,然後如果你點選圖,你將看到你的圖。

image
在這一點上,圖遍佈各處,並且相當難以閱讀。 因此,請命名一些部分來其更更加可讀。

image
新增名稱
在下面的程式碼中,我們只添加了parameter
幾次。name=[something]
。 這個parameter
將接受所選區域並在圖形上為其命名。
a = tf.add(1, 2, name="Add_these_numbers") b = tf.multiply(a, 3) c = tf.add(4, 5, name="And_These_ones") d = tf.multiply(c, 6, name="Multiply_these_numbers") e = tf.multiply(4, 5, name="B_add") f = tf.div(c, 6, name="B_mul") g = tf.add(b, d) h = tf.multiply(g, f)
現在,如果你重新執行 python 檔案,然後再次執行tensorboard --logdir=path/to/logs/directory
,你現在將看到,在你命名的特定部分上,你的圖有了一些名稱。 然而,它仍然非常混亂,如果這是一個巨大的神經網路,它幾乎是不可讀的。

image
建立作用域
如果我們通過鍵入tf.name_scope("MyOperationGroup"):
給圖命名:並使用with tf.name_scope("Scope_A"):
給圖這樣的作用域,當你重新執行你的 TensorBoard 時,你會看到一些非常不同的東西。 圖現在更容易閱讀,你可以看到它都在圖的標題下,這裡是MyOperationGroup
,然後你有你的作用域A
和B
,其中有操作。
# 這裡我們定義圖的名稱,作用域 A,B 和 C。 with tf.name_scope("MyOperationGroup"): with tf.name_scope("Scope_A"): a = tf.add(1, 2, name="Add_these_numbers") b = tf.multiply(a, 3) with tf.name_scope("Scope_B"): c = tf.add(4, 5, name="And_These_ones") d = tf.multiply(c, 6, name="Multiply_these_numbers") with tf.name_scope("Scope_C"): e = tf.multiply(4, 5, name="B_add") f = tf.div(c, 6, name="B_mul") g = tf.add(b, d) h = tf.multiply(g, f)
如你所見,圖現在更容易閱讀。

image
TensorBoard 具有廣泛的功能,其中一些我們將在未來的課程中介紹。 如果你想深入瞭解,請先觀看2017 年 TensorFlow 開發者大會的視訊 。
在本課中,我們研究了:
- TensorBoard 圖的基本佈局
- 新增摘要編寫器來構建 TensorBoard
- 將名稱新增到 TensorBoard 圖
- 將名稱和作用域新增到 TensorBoard
有一個很棒的第三方工具叫做 TensorDebugger(TDB),TBD 就像它所謂的偵錯程式一樣。 但是與 TensorBoard 中內建的標準偵錯程式不同,TBD 直接與 TensorFlow 圖的執行互動,並允許一次執行一個節點。 由於標準 TensorBoard 偵錯程式不能在執行 TensorFlow 圖時同時使用,因此必須先寫日誌檔案。
- 從這裡 安裝 TBD 並閱讀材料(試試 Demo!)。
- 將 TBD 與此梯度下降程式碼一起使用,繪製一個圖表,通過結果顯示偵錯程式的工作,並列印預測模型。 (注意:這僅僅與 2.7 相容)
import tensorflow as tf import numpy as np # x 和 y 是我們的訓練資料的佔位符 x = tf.placeholder("float") y = tf.placeholder("float") # w 是儲存我們的值的變數。 它使用“猜測”來初始化 # w[0] 是我們方程中的“a”,w[1] 是“b” w = tf.Variable([1.0, 2.0], name="w") # 我們的模型是 y = a*x + b y_model = tf.multiply(x, w[0]) + w[1] # 我們的誤差定義為差異的平方 error = tf.square(y - y_model) # GradientDescentOptimizer 完成繁重的工作 train_op = tf.train.GradientDescentOptimizer(0.01).minimize(error) # TensorFlow 常規 - 初始化值,建立會話並執行模型 model = tf.global_variables_initializer() with tf.Session() as session: session.run(model) for i in range(1000): x_value = np.random.rand() y_value = x_value * 2 + 6 session.run(train_op, feed_dict={x: x_value, y: y_value}) w_value = session.run(w) print("Predicted model: {a:.3f}x + {b:.3f}".format(a=w_value[0], b=w_value[1]))
這些特殊圖示用於常量和摘要節點。

image
讀取檔案
TensorFlow 支援讀取更大的資料集,特別是這樣,資料永遠不能一次全部儲存在記憶體中(如果有這個限制則不會非常有用)。 你可以使用一些函式和選項,從標準 Python 一直到特定的操作。
TensorFlow 還支援編寫自定義資料處理程式,如果你有一個包含大量資料的非常大的專案,這是值得研究的。 編寫自定義資料載入是前期的一點努力,但以後可以節省大量時間。 此主題的更多資訊,請檢視此處 的官方文件。
在本課程中,我們將介紹使用 TensorFlow 讀取 CSV 檔案,以及在圖中使用資料的基礎知識。
佔位符
讀取資料的最基本方法是使用標準 python 程式碼讀取它。 讓我們來看一個基本的例子,從這個2016 年奧運會獎牌統計資料 中讀取資料。
首先,我們建立我們的圖,它接受一行資料,並累計總獎牌。
import tensorflow as tf import os dir_path = os.path.dirname(os.path.realpath(__file__)) filename = dir_path + "/olympics2016.csv" features = tf.placeholder(tf.int32, shape=[3], name='features') country = tf.placeholder(tf.string, name='country') total = tf.reduce_sum(features, name='total')
接下來,我將介紹一個名為Print
的新操作,它打印出圖形上某些節點的當前值。 它是一個單位元素,這意味著它將操作作為輸入,只返回與輸出相同的值。
printerop = tf.Print(total, [country, features, total], name='printer')
當你求解列印操作時會發生什麼? 它基本上將當前值記錄在第二個引數中(在本例中為列表[country, features, total]
)並返回第一個值(total
)。 但它被認為是一個變數,因此我們需要在啟動會話時初始化所有變數。
接下來,我們啟動會話,然後開啟檔案來讀取。 請注意,檔案讀取完全是在 python 中完成的 - 我們只是在執行圖形的同時讀取它。
with tf.Session() as sess: sess.run( tf.global_variables_initializer()) with open(filename) as inf: # 跳過標題 next(inf) for line in inf: # 使用 python 將資料讀入我們的特徵 country_name, code, gold, silver, bronze, total = line.strip().split(",") gold = int(gold) silver = int(silver) bronze = int(bronze) # 執行列印操作 total = sess.run(printerop, feed_dict={features: [gold, silver, bronze], country:country_name}) print(country_name, total)
在迴圈的內部部分,我們讀取檔案的一行,用逗號分割,將值轉換為整數,然後將資料作為佔位符值提供給feed_dict
。 如果你不確定這裡發生了什麼,請檢視之前的佔位符教程。
當你執行它時,你會在每一行看到兩個輸出。 第一個輸出將是列印操作的結果,看起來有點像這樣:
I tensorflow/core/kernels/logging_ops.cc:79] [\"France\"][10 18 14][42]
下一個輸出將是print(country_name, total)
行的結果,該行列印當前國家/地區名稱(python 變數)和執行列印操作的結果。 由於列印操作是一個單位函式,因此呼叫它的結果只是求值total
的結果,這會將金,銀和銅的數量相加。
它通常以類似的方式工作得很好。 建立佔位符,將一些資料載入到記憶體中,計算它,然後迴圈使用新資料。 畢竟,這是佔位符的用途。
讀取 CSV
TensorFlow 支援將資料直接讀入張量,但格式有點笨重。 我將通過一種方式逐步完成此操作,但我選擇了一種特殊的通用方法,我希望你可以將它用於你自己的專案。
步驟是建立要讀取的檔名的佇列(列表),然後建立稍後將執行讀取的讀取器操作。 從這個閱讀器操作中,建立在圖執行階段執行時用實際值替換的變數。
讓我們來看看該過程的最後幾個步驟:
def create_file_reader_ops(filename_queue): reader = tf.TextLineReader(skip_header_lines=1) _, csv_row = reader.read(filename_queue) record_defaults = [[""], [""], [0], [0], [0], [0]] country, code, gold, silver, bronze, total = tf.decode_csv(csv_row, record_defaults=record_defaults) features = tf.pack([gold, silver, bronze]) return features, country
這裡的讀取器在技術上採用佇列物件,而不是普通的 Python 列表,所以我們需要在將它傳遞給函式之前構建一個:
filename_queue = tf.train.string_input_producer(filenames, num_epochs=1, shuffle=False) example, country = create_file_reader_ops(filename_queue)
由該函式呼叫產生的那些操作,稍後將表示來自我們的資料集的單個條目。 執行這些需要比平常更多的工作。 原因是佇列本身不像正常操作那樣位於圖上,因此我們需要一個Coordinator
來管理佇列中的執行。 每次求值示例和標籤時,此協調器將在資料集中遞增,因為它們有效地從檔案中提取資料。
with tf.Session() as sess: tf.global_variables_initializer().run() coord = tf.train.Coordinator() threads = tf.train.start_queue_runners(coord=coord) while True: try: example_data, country_name = sess.run([example, country]) print(example_data, country_name) except tf.errors.OutOfRangeError: break
內部while
迴圈保持迴圈,直到我們遇到OutOfRangeError
,表明沒有更多資料要還原。
有了這段程式碼,我們現在從資料集中一次得到一行,直接載入到我們的圖形中。 還有其他用於建立批量和打亂的功能 - 如果你想了解這些引數的更多資訊,請檢視tf.train.string_input_producer
和tf.train.shuffle_batch
中的一些引數。
在本課中,我們研究了:
- 在執行 TensorFlow 圖時使用 Python 讀取資料
-
tf.Print
操作 - 將資料直接讀入 TensorFlow 圖/變數
- 佇列物件
-
更新第二個示例的程式碼(直接將檔案讀入 TensorFlow),使用與 python-version 相同的方式輸出總和(即打印出來並使用
tf.Print
) -
在
create_file_reader_ops
中解包特徵操作,即不執行tf.pack
行。 更改程式碼的其餘部分來滿足一下情況,特徵作為三個單獨的特徵返回,而不是單個打包的特徵。 需要改變什麼? - 將資料檔案拆分為幾個不同的檔案(可以使用文字編輯器完成)並更新佇列來全部讀取它們。
-
使用
tf.train.shuffle_batch
將多行合成一個變數。 這對於較大的資料集比逐行讀取更有用。
對於問題4,一個好的目標是在一個批量中載入儘可能多的資料,但不要太多以至於它會使計算機的 RAM 過載。 這對於這個資料集無關緊要,但以後請記住。
另外,使用批量時不會返回所有資料 - 如果批量未滿,則不會返回。
遷移到 AWS
在很多情況下,執行程式碼可能非常耗時,特別是如果你正在執行機器學習或神經網路。除非你在計算機上花費了大量資金,否則轉向基於雲的服務可能是最好的方法。
在本教程中,我們將採用一些 Tensorflow 程式碼並將其移至 Amazon Web 服務(AWS)彈性計算雲實例(EC2)。
亞馬遜網路服務(AWS)是一個安全的雲服務平臺,提供計算能力,資料庫儲存,內容交付和其他功能,來幫助企業擴充套件和發展。此外,亞馬遜彈性計算雲(Amazon EC2)是一種 Web 服務,可在雲中提供可調整大小的計算能力。它旨在使 Web 級雲端計算對開發人員更輕鬆。
這樣做的好處是,亞馬遜擁有大量基於雲的伺服器,其背後有很多功能。這將允許你在網路上執行程式碼的時間,只有你能夠從本地計算機執行程式碼的一半。這也意味著如果它是一個需要 5-8 個小時才能完成的大型檔案,你可以在 EC2 例項上執行它,並將其保留在後臺而不使用你的整個計算機資源。
建立一個 EC2 環境會花費你的錢,但它是一個非常少,8 小時可能大約 4.00 美元。 一旦你停止使用它,將不會收取你的費用。請訪問此連結 來檢視價格。
建立 EC2 例項
首先,訪問AWS 控制檯 。
使用你的亞馬遜帳戶登入。如果你沒有,則會提示你建立一個,你需要執行此操作才能繼續。
接下來,請訪問EC2 服務控制檯 。
單擊Launch Instance
並在右上角的下拉選單中選擇你的地區(例如sydney, N california
)作為你的位置。
接下來轉到社群 AMI 並搜尋 Ubuntu x64 AMI 和 TensorFlow(GPU),它已準備好通過 GPU 執行程式碼,但它也足以在其上執行基本或大型 Tensorflow 指令碼,而且優勢是 Tensorflow 已安裝。
此時,將向你收取費用,因此請務必在完成後關閉機器。 你可以轉到 EC2 服務,選擇機器並停止它。 你不需要為未執行的機器付費。
系統將提示你如何連線到例項的一些資訊。 如果你之前未使用過 AWS,則可能需要建立一個新金鑰對才能安全地連線到你的例項。 在這種情況下,為你的金鑰對命名,下載 pemfile,並將其儲存在安全的地方 - 如果丟失,你將無法再次連線到你的例項!
單擊“連線”來獲取使用 pem 檔案連線到例項的資訊。 最可能的情況是你將使用以下命令來使用ssh
:
ssh -i <certificante_name>.pem ubuntu@<server_ip_address>
將你的程式碼移動到 AWS EC2
我們將使用以下示例繼續我們的 EC2 例項,這來自前面的章節:
import tensorflow as tf import numpy as np # x 和 y 是我們的訓練資料的佔位符 x = tf.placeholder("float") y = tf.placeholder("float") # w 是儲存我們的值的變數。 它使用“猜測”來初始化 # w[0] 是我們方程中的“a”,w[1] 是“b” w = tf.Variable([1.0, 2.0], name="w") # 我們的模型是 y = a*x + b y_model = tf.multiply(x, w[0]) + w[1] # 我們的誤差定義為差異的平方 error = tf.square(y - y_model) # GradientDescentOptimizer 完成繁重的工作 train_op = tf.train.GradientDescentOptimizer(0.01).minimize(error) # TensorFlow 常規 - 初始化值,建立會話並執行模型 model = tf.global_variables_initializer() with tf.Session() as session: session.run(model) for i in range(1000): x_value = np.random.rand() y_value = x_value * 2 + 6 session.run(train_op, feed_dict={x: x_value, y: y_value}) w_value = session.run(w) print("Predicted model: {a:.3f}x + {b:.3f}".format(a=w_value[0], b=w_value[1]))
有很多方法可以將此檔案放到EC2例項上,但最簡單的方法之一就是複製並貼上內容。
首先,按Ctrl + A
高亮以上所有程式碼,然後使用Ctrl + C
複製所有程式碼
在 Amazon 虛擬機器上,移動到主目錄並使用新檔名開啟nano
,我們將在此示例中呼叫basic.py
(以下是終端命令):
$ cd~/ $ nano <nameofscript>.py
nano
程式將開啟,這是一個命令列文字編輯器。
開啟此程式後,將剪貼簿的內容貼上到此檔案中。 在某些系統上,你可能需要使用ssh
程式的檔案選項,而不是按Ctrl + V
進行貼上。 在nano
中,按Ctrl + O
將檔案儲存在磁碟上,我們將其命名為basic.py
,然後按Ctrl + X
退出程式。
一旦你退出nano
,輸入python basic.py
就可以了!
你現在應該看到終端中彈出程式碼的結果,因為你很可能會發現,這可能是一種執行大型資料程式的更好方法。
Facenet 是一款利用 Tensorflow 的人臉識別程式,它提供了預先訓練的模型,供你下載和執行來檢視其工作原理。
1)訪問此連結並下載預先訓練的人臉識別模型
2)使用上面的教程,將程式碼上傳到 EC2 例項並使其執行。