[程序員指南4]圖表和會話

圖表和會話

TensorFlow使用數據流圖來表示您的計算,這取決於各個操做之間的相關性。這致使了一個低級編程模型,您首先定義數據流圖,而後建立一個TensorFlow 會話,以便跨一組本地和遠程設備運行部分圖形。html

若是您打算直接使用低級編程模型,本指南將很是有用。更高級別的API(如tf.estimator.EstimatorKeras)會隱藏最終用戶的圖形和會話細節,可是若是您想了解這些API是如何實現的,本指南也可能頗有用。python

 

爲何要數據流圖?

 

數據流是並行計算的通用編程模型。在數據流圖中,節點表示計算單位,邊緣表示計算消耗或產生的數據。例如,在TensorFlow圖中,該tf.matmul 操做將對應於具備兩個輸入邊(要被乘法的矩陣)和一個輸出邊(乘法的結果)的單個節點。算法

數據流在執行程序時能夠利用TensorFlow的幾個優勢:編程

  • 並行。經過使用顯式邊來表示操做之間的依賴關係,系統很容易識別並行執行的操做。api

  • 分佈式執行。經過使用顯式邊來表示在操做之間流動的值,TensorFlow能夠跨越鏈接到不一樣機器的多個設備(CPU,GPU和TPU)對程序進行分區。TensorFlow在設備之間插入必要的通訊和協調。
  • 彙編。TensorFlow的XLA編譯器可使用數據流圖中的信息來生成更快的代碼,例如經過將相鄰操做融合在一塊兒。
  • 可移植性。數據流圖是模型中代碼的語言無關表示。您能夠在Python中構建數據流圖,將其存儲在SavedModel中,並在C ++程序中將其還原爲低延遲推斷。

什麼是tf.Graph

tf.Graph包含兩種相關信息:數組

  • 圖形結構。圖形的節點和邊緣,指示單個操做如何組合在一塊兒,但不規定如何使用它們。圖形結構就像彙編代碼:檢查它能夠傳達一些有用的信息,但不包含源代碼傳達的全部有用的上下文。瀏覽器

  • 圖形集合。TensorFlow提供了一種用於存儲元數據集合的通用機制tf.Graphtf.add_to_collection功能使您可以將對象列表與鍵(其中tf.GraphKeys 定義了一些標準鍵)tf.get_collection相關聯,並使您可以查找與鍵相關聯的全部對象。TensorFlow庫的許多部分都使用此功能:例如,當您建立時tf.Variable,默認狀況下將其添加到表示「全局變量」和「可培訓變量」的集合中。當你之後來建立一個tf.train.Saver或者 tf.train.Optimizer,這些集合中的變量被用做默認參數。

建一個 tf.Graph

大多數TensorFlow程序從數據流圖構建階段開始。在此階段,您調用構造新tf.Operation (節點)和tf.Tensor(邊)對象的TensorFlow API函數,並將它們添加到tf.Graph 實例中。TensorFlow提供了一個默認圖形,它是同一上下文中全部API函數的隱式參數。例如:緩存

  • 調用tf.constant(42.0)建立一個tf.Operation生成該值的單個42.0,將其添加到默認圖形,並返回一個tf.Tensor表示常量的值。服務器

  • 呼叫tf.matmul(x, y)建立一個tf.Operation相乘的值tf.Tensor對象xy,把它添加到默認的圖形,並返回一個tf.Tensor表示相乘的結果。網絡

  • 執行v = tf.Variable(0)會添加圖形tf.Operation,它將存儲在tf.Session.run調用之間持續的可寫張量值tf.Variable對象包裝該操做,而且可使用像的張量,這將讀出的存儲值的當前值。tf.Variable對象也有例如方法 assignassign_add用於建立tf.Operation對象在被執行時,更新所存儲的值。(有關變量的更多信息,請參見變量。)

  • 調用tf.train.Optimizer.minimize將會將運算和張量添加到計算梯度的默認圖形上,並返回一個tf.Operation運行時,將這些漸變應用於一組變量。

大多數程序只依賴於默認圖形。可是,有關更多高級用例,請參閱處理多個圖表高級API(如tf.estimator.EstimatorAPI)表明您管理默認圖表,例如 - 能夠爲培訓和評估建立不一樣的圖表。

注意:調用TensorFlow API中的大多數函數僅將操做和張量添加到默認圖形,但執行實際計算。相反,您組合這些函數,直到您有tf.Tensor 或tf.Operation表明總體計算(例如執行梯度降低的一步),而後將該對象傳遞給a tf.Session執行計算。有關tf.Session詳細信息,請參見「執行圖中的」 一節。

命名操做

tf.Graph對象定義一個命名空間tf.Operation它包含的對象。TensorFlow會自動爲圖形中的每一個操做選擇惟一的名稱,但給出操做描述性名稱可使程序更容易閱讀和調試。TensorFlow API提供了兩種覆蓋操做名稱的方法:

  • 建立新的tf.Operation或返回新的 API函數tf.Tensor接受可選name參數。例如, tf.constant(42.0, name="answer")建立一個新的tf.Operationnamed "answer"並返回一個tf.Tensornamed "answer:0"若是默認圖形已經包含一個名爲的操做"answer",那麼TensorFlow將附加 "_1""_2"等等到名稱,以使其惟一。

  • tf.name_scope功能能夠爲在特定上下文中建立的全部操做添加名稱範圍前綴。當前名稱範圍前綴是"/"全部活動tf.name_scope 上下文管理器的名稱的不相關列表若是在當前上下文中已經使用了名稱範圍,則TensorFlow會附加"_1""_2"等等。例如:

c_0 = tf.constant(0, name="c")  # => operation named "c"

# Already-used names will be "uniquified".
c_1 = tf.constant(2, name="c")  # => operation named "c_1"

# Name scopes add a prefix to all operations created in the same context.
with tf.name_scope("outer"):
  c_2 = tf.constant(2, name="c")  # => operation named "outer/c"

  # Name scopes nest like paths in a hierarchical file system.
  with tf.name_scope("inner"):
    c_3 = tf.constant(3, name="c")  # => operation named "outer/inner/c"

  # Exiting a name scope context will return to the previous prefix.
  c_4 = tf.constant(4, name="c")  # => operation named "outer/c_1"

  # Already-used name scopes will be "uniquified".
  with tf.name_scope("inner"):
    c_5 = tf.constant(5, name="c")  # => operation named "outer/inner_1/c"

圖形可視化器使用名稱範圍來對操做進行分組,並減小圖形的視覺複雜性。有關詳細信息,請參閱可視化圖形

 

請注意,tf.Tensor對象是以tf.Operation 產生張量做爲輸出的隱式命名的張量名稱的格式"<OP_NAME>:<i>" 以下:

  • "<OP_NAME>" 是產生它的操做的名稱。
  • "<i>" 是表示操做輸出中該張量的索引的整數。

將操做放置在不一樣的設備上

若是您但願TensorFlow程序使用多個不一樣的設備,該 tf.device功能提供了一種方便的方式來請求在特定上下文中建立的全部操做都放置在同一設備(或設備類型)上。

設備規範具備如下形式:

/job:<JOB_NAME>/task:<TASK_INDEX>/device:<DEVICE_TYPE>:<DEVICE_INDEX>

哪裏:

  • <JOB_NAME> 是一個不以數字開頭的字母數字字符串。
  • <DEVICE_TYPE>是註冊的設備類型(如GPUCPU)。
  • <TASK_INDEX>是表示做業中任務的索引的非負整數<JOB_NAME>查看tf.train.ClusterSpec工做和任務的解釋。
  • <DEVICE_INDEX> 是表示設備索引的非負整數,例如,區分在同一進程中使用的不一樣GPU設備。

您不須要指定設備規範的每一個部分。例如,若是您使用單個GPU進行單機配置,則能夠tf.device將一些操做用於CPU和GPU:

# Operations created outside either context will run on the "best possible"
# device. For example, if you have a GPU and a CPU available, and the operation
# has a GPU implementation, TensorFlow will choose the GPU.
weights = tf.random_normal(...)

with tf.device("/device:CPU:0"):
  # Operations created in this context will be pinned to the CPU.
  img = tf.decode_jpeg(tf.read_file("img.jpg"))

with tf.device("/device:GPU:0"):
  # Operations created in this context will be pinned to the GPU.
  result = tf.matmul(weights, img)

若是要在典型的分佈式配置中部署TensorFlow ,則能夠指定做業名稱和任務ID,以將變量放置在參數服務器做業("/job:ps")中的任務上,以及在worker做業("/job:worker"中的任務上的其餘操做

with tf.device("/job:ps/task:0"):
  weights_1 = tf.Variable(tf.truncated_normal([784, 100]))
  biases_1 = tf.Variable(tf.zeroes([100]))

with tf.device("/job:ps/task:1"):
  weights_2 = tf.Variable(tf.truncated_normal([100, 10]))
  biases_2 = tf.Variable(tf.zeroes([10]))

with tf.device("/job:worker"):
  layer_1 = tf.matmul(train_batch, weights_1) + biases_1
  layer_2 = tf.matmul(train_batch, weights_2) + biases_2

tf.device爲您選擇TensorFlow圖的各個操做或普遍區域的展現位置提供了很大的靈活性。在許多狀況下,有一些簡單的啓發式工做很好。例如, tf.train.replica_device_setterAPI可用於tf.device進行數據並行分佈式培訓的操做例如,如下代碼片斷顯示瞭如何tf.train.replica_device_setter將不一樣的佈局策略應用於tf.Variable對象和其餘操做:

with tf.device(tf.train.replica_device_setter(ps_tasks=3)):
  # tf.Variable objects are, by default, placed on tasks in "/job:ps" in a
  # round-robin fashion.
  w_0 = tf.Variable(...)  # placed on "/job:ps/task:0"
  b_0 = tf.Variable(...)  # placed on "/job:ps/task:1"
  w_1 = tf.Variable(...)  # placed on "/job:ps/task:2"
  b_1 = tf.Variable(...)  # placed on "/job:ps/task:0"

  input_data = tf.placeholder(tf.float32)     # placed on "/job:worker"
  layer_0 = tf.matmul(input_data, w_0) + b_0  # placed on "/job:worker"
  layer_1 = tf.matmul(layer_0, w_1) + b_1     # placed on "/job:worker"

相似Tensor的物體

許多TensorFlow操做將一個或多個tf.Tensor對象做爲參數。例如,tf.matmul須要兩個tf.Tensor對象,並tf.add_n獲取一個n tf.Tensor對象列表爲了方便起見,這些函數將接受一個相似張量的對象代替a tf.Tensor,並將其隱式轉換爲tf.Tensor使用該tf.convert_to_tensor方法。相似Tensor的對象包括如下類型的元素:

您可使用註冊附加的張量類型 tf.register_tensor_conversion_function

注意:默認狀況下,TensorFlow將在tf.Tensor每次使用相同的張量對象時建立一個新的若是張量類物體較大(例如 numpy.ndarray包含一組訓練樣本),而且屢次使用,則可能會耗盡內存。爲了不這種狀況,請手動調用tf.convert_to_tensor相似張量的對象,並使用返回值 tf.Tensor

在a中執行圖形 tf.Session

TensorFlow使用tf.Session該類來表示客戶端程序之間的鏈接 - 一般是Python程序,儘管相似的接口可用於其餘語言---和C ++運行時。一個tf.Session對象提供對本地機器中的設備和使用分佈式TensorFlow運行時的遠程設備的訪問。它還緩存有關您的信息, tf.Graph以便您能夠屢次有效地運行相同的計算。

建立一個 tf.Session

若是您使用低級TensorFlow API,則能夠按照tf.Session 如下方式爲當前默認圖形建立一個

# Create a default in-process session.
with tf.Session() as sess:
  # ...

# Create a remote session.
with tf.Session("grpc://example.org:2222"):
  # ...

因爲tf.Session擁有物理資源(如GPU和網絡鏈接),所以一般將其用做在with 退出塊時自動關閉會話的上下文管理器(在塊中)。也能夠在不使用with塊的狀況下建立會話,可是tf.Session.close當您完成它以釋放資源時,應該顯式調用它。

注意:更高級別的API,例如tf.train.MonitoredTrainingSession或 tf.estimator.Estimator將爲您建立和管理一個tf.Session這些API接受可選targetconfig參數(直接或做爲的一部分tf.estimator.RunConfig,以下所述對象),具備相同的含義。

tf.Session.__init__ 接受三個可選參數:

  • target若是此參數爲空(默認值),則會話將僅使用本地計算機中的設備。可是,您還能夠指定一個grpc://URL來指定TensorFlow服務器的地址,該服務器將會話訪問該服務器所控制的計算機上的全部設備。請參閱 tf.train.Server如何建立TensorFlow服務器的詳細信息。例如,在常見的圖形間複製 配置中,tf.Session鏈接到tf.train.Server與客戶端相同的進程。分佈式TensorFlow 部署指南介紹了其餘常見的場景。

  • graph默認狀況下,一個新的tf.Session綁定到---而且只能在---當前的默認圖中運行。若是您在程序中使用多個圖形(有關更多詳細信息,請參閱使用多個圖形編程),您能夠tf.Graph在構建會話時指定一個顯式

  • config此參數容許您指定tf.ConfigProto控制會話的行爲。例如,一些配置選項包括:

  • allow_soft_placement將其設置True爲啓用「軟」設備佈局算法,該算法忽略tf.device嘗試在GPU設備上放置僅CPU操做的註釋,並將其放置在CPU上。

  • cluster_def當使用分佈式TensorFlow時,此選項容許您指定計算中要使用的計算機,並提供做業名稱,任務索引和網絡地址之間的映射。看 tf.train.ClusterSpec.as_cluster_def詳情。

  • graph_options.optimizer_options在執行TensorFlow在圖形上執行的優化控制。

  • gpu_options.allow_growth將其設置True爲更改GPU內存分配器,以便逐漸增長分配的內存量,而不是在啓動時分配大部份內存。

使用tf.Session.run執行操做

tf.Session.run方法是運行tf.Operation 或評估a 的主要機制tf.Tensor你能夠經過一個或多個tf.Operation或 tf.Tensor對象tf.Session.run,並TensorFlow將執行所需計算結果的操做。

tf.Session.run要求您指定的列表,它決定了返回值,也能夠是一個tf.Operation,一個tf.Tensor,或張樣型tf.Variable這些提取肯定必須執行總體的子圖tf.Graph才能產生結果:這是包含在提取列表中命名的全部操做的子圖,以及其輸出用於計算提取值的全部操做。例如,如下代碼片斷顯示了不一樣的參數如何tf.Session.run致使執行不一樣的子圖:

x = tf.constant([[37.0, -23.0], [1.0, 4.0]])
w = tf.Variable(tf.random_uniform([2, 2]))
y = tf.matmul(x, w)
output = tf.nn.softmax(y)
init_op = w.initializer

with tf.Session() as sess:
  # Run the initializer on `w`.
  sess.run(init_op)

  # Evaluate `output`. `sess.run(output)` will return a NumPy array containing
  # the result of the computation.
  print(sess.run(output))

  # Evaluate `y` and `output`. Note that `y` will only be computed once, and its
  # result used both to return `y_val` and as an input to the `tf.nn.softmax()`
  # op. Both `y_val` and `output_val` will be NumPy arrays.
  y_val, output_val = sess.run([y, output])

tf.Session.run還能夠選擇一個Feed的字典,它是從tf.Tensor對象(一般是tf.placeholder張量)到值(一般是Python標量,列表或NumPy數組)的映射,將代替執行中的那些張量。例如:

# Define a placeholder that expects a vector of three floating-point values,
# and a computation that depends on it.
x = tf.placeholder(tf.float32, shape=[3])
y = tf.square(x)

with tf.Session() as sess:
  # Feeding a value changes the result that is returned when you evaluate `y`.
  print(sess.run(y, {x: [1.0, 2.0, 3.0]})  # => "[1.0, 4.0, 9.0]"
  print(sess.run(y, {x: [0.0, 0.0, 5.0]})  # => "[0.0, 0.0, 25.0]"

  # Raises `tf.errors.InvalidArgumentError`, because you must feed a value for
  # a `tf.placeholder()` when evaluating a tensor that depends on it.
  sess.run(y)

  # Raises `ValueError`, because the shape of `37.0` does not match the shape
  # of placeholder `x`.
  sess.run(y, {x: 37.0})

tf.Session.run還接受一個可選options參數,使您可以指定關於調用的選項,以及可選run_metadata參數,使您可以收集有關執行的元數據。例如,您能夠一塊兒使用這些選項來收集有關執行的跟蹤信息:

y = tf.matmul([[37.0, -23.0], [1.0, 4.0]], tf.random_uniform([2, 2]))

with tf.Session() as sess:
  # Define options for the `sess.run()` call.
  options = tf.RunOptions()
  options.output_partition_graphs = True
  options.trace_level = tf.RunOptions.FULL_TRACE

  # Define a container for the returned metadata.
  metadata = tf.RunMetadata()

  sess.run(y, options=options, run_metadata=metadata)

  # Print the subgraphs that executed on each device.
  print(metadata.partition_graphs)

  # Print the timings of each operation that executed.
  print(metadata.step_stats)

可視化圖形

TensorFlow包括能夠幫助您瞭解圖形中的代碼的工具。曲線圖可視化是在視覺上呈現您圖的結構在瀏覽器TensorBoard的組分。建立可視化的最簡單方法是在建立可視化tf.Graph時 傳遞tf.summary.FileWriter

# Build your graph.
x = tf.constant([[37.0, -23.0], [1.0, 4.0]])
w = tf.Variable(tf.random_uniform([2, 2]))
y = tf.matmul(x, w)
# ...
loss = ...
train_op = tf.train.AdagradOptimizer(0.01).minimize(loss)

with tf.Session() as sess:
  # `sess.graph` provides access to the graph used in a `tf.Session`.
  writer = tf.summary.FileWriter("/tmp/log/...", sess.graph)

  # Perform your computation...
  for i in range(1000):
    sess.run(train_op)
    # ...

  writer.close()

注意:若是使用a tf.estimator.Estimator,則圖形(和任何摘要)將自動記錄到model_dir建立估計器時指定的圖形

而後,您能夠打開登陸tensorboard,導航到「圖形」選項卡,並查看圖形結構的高級可視化。請注意,典型的TensorFlow圖 - 特別是具備自動計算梯度的訓練圖 - 具備太多的節點能夠當即可視化。圖形可視化器利用名稱範圍將相關操做分組爲「超級」節點。您能夠點擊任何這些超級節點上的橙色「+」按鈕,將子圖擴展到裏面。

有關使用TensorBoard可視化TensorFlow應用程序的更多信息,請參閱TensorBoard教程

用多個圖表編程

注意:訓練模型時,組織代碼的常見方式是使用一個圖形來訓練模型,以及用於評估或執行訓練模型推理的單獨圖形。在許多狀況下,推理圖將與訓練圖不一樣:例如,在各類狀況下,技術(如退出和批量歸一化)都使用不一樣的操做。此外,默認實用程序tf.train.Saver使用tf.Variable對象的名稱(其名稱基於底層tf.Operation)來標識保存的檢查點中的每一個變量。編程時,您可使用徹底獨立的Python進程構建和執行圖形,也能夠在同一過程當中使用多個圖形。本節介紹如何在同一過程當中使用多個圖。

如上所述,TensorFlow提供了在相同上下文中隱式傳遞給全部API函數的「默認圖」。對於許多應用程序,單個圖形就足夠了。可是,TensorFlow還提供了操做默認圖形的方法,這在更先進的用例中可使用。例如:

  • tf.Graph定義tf.Operation對象的命名空間:單個圖中的每一個操做必須具備惟一的名稱。若是已經使用了請求的名稱,TensorFlow將經過附加"_1""_2"等等將其命名爲「惟一」 使用多個顯式建立的圖形能夠更好地控制每一個操做的名稱。

  • 默認圖形存儲有關每一個tf.Operation和 tf.Tensor以前添加的信息若是您的程序建立大量未鏈接的子圖,使用其餘子圖可能會更有效 tf.Graph,以便無關的狀態能夠被垃圾回收

您能夠tf.Graph使用tf.Graph.as_default上下文管理器安裝不一樣的默認圖形 

g_1 = tf.Graph()
with g_1.as_default():
  # Operations created in this scope will be added to `g_1`.
  c = tf.constant("Node in g_1")

  # Sessions created in this scope will run operations from `g_1`.
  sess_1 = tf.Session()

g_2 = tf.Graph()
with g_2.as_default():
  # Operations created in this scope will be added to `g_2`.
  d = tf.constant("Node in g_2")

# Alternatively, you can pass a graph when constructing a `tf.Session`:
# `sess_2` will run operations from `g_2`.
sess_2 = tf.Session(graph=g_2)

assert c.graph is g_1
assert sess_1.graph is g_1

assert d.graph is g_2
assert sess_2.graph is g_2

要檢查當前的默認圖形,調用tf.get_default_graph,返回一個tf.Graph對象:

# Print all of the operations in the default graph.
g = tf.get_default_graph()
print(g.get_operations())
相關文章
相關標籤/搜索