添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

作為一個開源的類神經網路模型交換格式,能夠以定義一組通用的運算元集合,並運用該集合建照計算圖是很重要的。今天的文章就先來看看要怎麼用 ONNX 提供的 Python API 來建立一個計算圖,同時我們也會提到 ONNX 以 protobuf 定義圖形,節點和模型等的規格。

如何建造一個 ONNX Graph

我們可以依照 ONNX 定義的 protobuf 檔案 來建立一個計算圖。建立的方法會由葉節點,連接葉節點作為運算元輸入的中間節點,最後到根節點。

  • 葉節點:代表的是運算元節點的輸入。可以依據 ValueInfoProto protobuf 定義建立輸入和輸出。使用者呼叫 helper.make_tensor_value_info 函式,並依序傳入名稱,資料型態,和一個 list,list 裡的每一個元素都表示一個維度。原始碼如下:
  • # 建立輸入 (ValueInfoProto)
    X = helper.make_tensor_value_info('X', TensorProto.FLOAT, [1, 2])
    # 建立輸出 (ValueInfoProto)
    Y = helper.make_tensor_value_info('Y', TensorProto.FLOAT, [1, 4])
    print(X)
    #=>name: "X"
    #type {
    #  tensor_type {
    #    elem_type: 1
    #    shape {
    #      dim {
    #        dim_value: 1
    #      }
    #      dim {
    #        dim_value: 2
    #      }
    #    }
    
  • 中間節點:根據 onnx 的 NodeProto protobuf 定義,使用者可以呼叫 helper.make_node函式,並依序傳入 op_type,輸入,輸出和額外的屬性。在 NodeProto 的定義上,name 和 op_type 都是用來當作節點的 id ,只不過 name 是用在計算圖中,而 op_type 則是在執行檔中可讓 IR 辨識的符號。有關 NodeProto 的幾個重要欄位,可以見下表:
  • AttributeType 定義在 AttributeProto 內的一個 enum list。定義的型別總共有 13 種,除了上列的 10 種外,還包括了 UNDEFINED (未定義),SPARSE_TENSOR 和 SPARSE_TENSORS(稀疏張量和稀疏張量陣列)。原始碼如下:

    #建立一個節點(NodeProto)
    node_def = helper.make_node(
        'Pad', # op_type
        ['X'], # 輸入
        ['Y'], # 輸出
        # 額外的屬性
        mode='constant', #名為 mode 的屬性,資料型別(AttributeType)為 STRING
        value=1.5, #名為 value 的屬性,資料型別(AttributeType)為 FLOAT
        pads=[0, 1, 0, 1], #名為 pads 的屬性,資料型別(AttributeType)為 INTS 
    print(node_def)
    # => input: "X"
    #output: "Y"
    #op_type: "Pad"
    #attribute {
    #  name: "mode"
    #  s: "constant"
    #  type: STRING
    #attribute {
    #  name: "pads"
    #  ints: 0
    #  ints: 1
    #  ints: 0
    #  ints: 1
    #  type: INTS
    #attribute {
    #  name: "value"
    #  f: 1.5
    #  type: FLOAT
    
  • 依據 GraphProto protobuf 建立計算圖,使用者可以呼叫 helper.make_graph 函式並依序傳入,一個 內裝一到多個 NodeProto 物件的 python list,名稱,一個內裝一到多個輸入的 python list 和一個內裝一到多個輸出的 python list。關於 GraphProto 的部分欄位定義如下:
  • 如何做型別與維度臆測

    在執行期間做維度臆測:在下面的原始碼中,我們將會建構一個簡單的 ModelProto 物件,使用 onnx.shape_inference 模組函式 infer_shapes 來做輸出張量的維度臆測。這次建立的計算圖,會用 make_node 建立兩個運算元 Transpose 的計算節點,關鍵值引數 perm 則是第一個輸入張量 Transpose 的維度。在計算圖中的輸入 X 和最終的輸出 Z 都在建立圖時用 make_tensor_value_info 方法來建立,所以無需做維度臆測。然而中繼變數 Y,則可以透過計算而得知,或由 X 和 Z 的維度進行臆測。下面的程式碼,即是使用後者:

    from onnx import shape_inference
    from onnx import TensorProto
    # 前處理,建立兩個計算節點,其中 Y 的維度是未知的
    node1 = helper.make_node('Transpose', ['X'], ['Y'], perm=[1, 0, 2])
    node2 = helper.make_node('Transpose', ['Y'], ['Z'], perm=[1, 0, 2])
    graph = helper.make_graph(
        [node1, node2],
        'two-transposes',
        [helper.make_tensor_value_info('X', TensorProto.FLOAT, (2, 3, 4))],
        [helper.make_tensor_value_info('Z', TensorProto.FLOAT, (2, 3, 4))],
    original_model = helper.make_model(graph, producer_name='onnx-examples')
    # 尚未應用維度臆測前,Y 的維度是未知
    print('Before shape inference, the shape info of Y is:\n{}'.format(original_model.graph.value_info))
    # => Before shape inference, the shape info of Y is:
    inferred_model = shape_inference.infer_shapes(original_model)
    # 未應用維度臆測後,Y 的維度可被推測
    print('After shape inference, the shape info of Y is:\n{}'.format(inferred_model.graph.value_info))
    # => After shape inference, the shape info of Y is:
    #[name: "Y"
    #type {
    #  tensor_type {
    #    elem_type: 1
    #    shape {
    #      dim {
    #        dim_value: 3
    #      }
    #      dim {
    #        dim_value: 2
    #      }
    #      dim {
    #        dim_value: 4
    #      }
    #    }