1. 程式人生 > 程式設計 >基於TensorBoard中graph模組圖結構分析

基於TensorBoard中graph模組圖結構分析

在上一篇文章中,我們介紹瞭如何使用原始碼對TensorBoard進行編譯教程,沒有定製需求的可以直接使用pip進行安裝。

TensorBoard中的graph是一種計算圖,裡面的點用於表示Tensor本身或者運算子,圖中的邊則代表Tensor的流動或者控制關係。

基於TensorBoard中graph模組圖結構分析

本文主要從程式碼的層面,分析graph的資料來源與結構。

一般來說,我們在啟動TensorBoard的時候會使用--logdir引數配置檔案路徑(或者設定資料庫位置),這些日誌檔案為TensorBoard提供了資料。於是我們開啟一個日誌檔案,檢視裡面的內容

基於TensorBoard中graph模組圖結構分析

我們看到,檔案是通過二進位制展示的,因此無法直接讀取檔案的內容。

回到瀏覽器中,進入graph頁面,通過開發者工具發現,構造圖的時候呼叫了一個介面

http://localhost:6006/data/plugin/graphs/graph?large_attrs_key=_too_large_attrs&limit_attr_size=1024&run=task1

用瀏覽器開啟這個地址,看到以下內容

node {
 name: "Input/X"
 op: "Placeholder"
 attr {
 key: "_output_shapes"
 value {
  list {
  shape {
   unknown_rank: true
  }
  }
 }
 }
 attr {
 key: "dtype"
 value {
  type: DT_FLOAT
 }
 }
 attr {
 key: "shape"
 value {
  shape {
  unknown_rank: true
  }
 }
 }
}
...

每個node都能夠與圖中的一個節點相對應,因此我們可以確定,這個接口裡返回的node,就是構成圖所需要的資料結構。

那麼,TensorBoard是如何將日誌檔案轉化為圖的呢?

TesnorBoard中的每個模組都是以plugin存在的,我們進入tensorboard/plugin/graph/graphs_plungin.py,在這個檔案中定義了graph相關的介面

def get_plugin_apps(self):
 return {
  '/graph': self.graph_route,'/runs': self.runs_route,'/run_metadata': self.run_metadata_route,'/run_metadata_tags': self.run_metadata_tags_route,}

我們可以看到,‘/graph'這個介面返回值為self.graph_route,在這個檔案中搜索graph_route方法

 @wrappers.Request.application
 def graph_route(self,request):
 """Given a single run,return the graph definition in protobuf format."""
 run = request.args.get('run')
 if run is None:
  return http_util.Respond(
   request,'query parameter "run" is required','text/plain',400)
 
 limit_attr_size = request.args.get('limit_attr_size',None)
 if limit_attr_size is not None:
  try:
  limit_attr_size = int(limit_attr_size)
  except ValueError:
  return http_util.Respond(
   request,'query parameter `limit_attr_size` must be an integer',400)
 
 large_attrs_key = request.args.get('large_attrs_key',None)
 
 try:
  result = self.graph_impl(run,limit_attr_size,large_attrs_key)
 except ValueError as e:
  return http_util.Respond(request,e.message,code=400)
 else:
  if result is not None:
  (body,mime_type) = result # pylint: disable=unpacking-non-sequence
  return http_util.Respond(request,body,mime_type)
  else:
  return http_util.Respond(request,'404 Not Found',code=404)

在這個方法中,分別取了“run”,”limit_attr_size“和“large_attrs_key”三個引數,和前面url所呼叫的引數一致,說明這個是我們要找的方法。在方法的最後,呼叫了self.graph_impl生成了圖,我們繼續檢視這個方法

def graph_impl(self,run,limit_attr_size=None,large_attrs_key=None):
 """Result of the form `(body,mime_type)`,or `None` if no graph exists."""
 try:
  graph = self._multiplexer.Graph(run)
 except ValueError:
  return None
 # This next line might raise a ValueError if the limit parameters
 # are invalid (size is negative,size present but key absent,etc.).
 process_graph.prepare_graph_for_ui(graph,large_attrs_key)
 return (str(graph),'text/x-protobuf') # pbtxt

這個方法呼叫了self._multiplexer.Graph(run)生成圖。_multiplexer是一個event_multiplexer例項,在graph_plugln初始化時通過base_plaugin.TBContext獲得。

 def __init__(self,context):
 """Instantiates GraphsPlugin via TensorBoard core.
 Args:
  context: A base_plugin.TBContext instance.
 """
 self._multiplexer = context.multiplexer

進入tensorboard/backend/event_processing/event_multiplexer,找到Graph方法

def Graph(self,run):
 """Retrieve the graph associated with the provided run.
 Args:
  run: A string name of a run to load the graph for.
 Raises:
  KeyError: If the run is not found.
  ValueError: If the run does not have an associated graph.
 Returns:
  The `GraphDef` protobuf data structure.
 """
 accumulator = self.GetAccumulator(run)
 return accumulator.Graph()
 
 def GetAccumulator(self,run):
 """Returns EventAccumulator for a given run.
 Args:
  run: String name of run.
 Returns:
  An EventAccumulator object.
 Raises:
  KeyError: If run does not exist.
 """
 with self._accumulators_mutex:
  return self._accumulators[run]

Graph方法獲取了run對應的accumulator例項,並返回了這個例項的Graph方法的返回值。我們進入tensorboard/backend/event_processing/event_accumulator,找到Graph()方法

 def Graph(self):
 """Return the graph definition,if there is one.
 If the graph is stored directly,return that. If no graph is stored
 directly but a metagraph is stored containing a graph,return that.
 Raises:
  ValueError: If there is no graph for this run.
 Returns:
  The `graph_def` proto.
 """
 graph = tf.GraphDef()
 if self._graph is not None:
  graph.ParseFromString(self._graph)
  return graph
 raise ValueError('There is no graph in this EventAccumulator')

事實上,它返回了一個GraphDef圖,因此我們也可以通過將日誌轉換為GraphDef的方式讀取日誌。

# 匯入要用到的基本模組。為了在python2、python3 中可以使用E侶相容的 print 函式
from __future__ import print_function
import numpy as np
import tensorflow as tf
 
# 建立圖和Session
graph = tf.Graph()
sess = tf.InteractiveSession(graph=graph)
 
#日誌路徑
model_fn = '/log/events.out.tfevents.1535957014.ubuntu'
 
for e in tf.train.summary_iterator(model_fn):
 if e.HasField('graph_def'):
  graph = e.graph_def;
  graph_def = tf.GraphDef()
  graph_def.ParseFromString(graph)
  print(graph_def)

我們新建一個python檔案,修改日誌路徑為自己的日誌位置,便可以得到與TensorBoard相同的內容。

以上這篇基於TensorBoard中graph模組圖結構分析就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支援我們。