深度學習框架集成平臺C++ Guide指南

深度學習框架集成平臺C++ Guide指南

這個指南詳細地介紹了神經網絡C++的API,並介紹了許多不同的方法來處理模型。

提示

所有框架運行時接口都是相同的,因此本指南適用於所有受支持框架(包括TensorFlow、PyTorch、Keras和TorchScript)中的模型。

導入神經網絡

最簡單的導入方法如下:

#include “neuropod/neuropod.hh”

Neuropod neuropod(PATH_TO_MY_MODEL);

其中PATH_TO_MY_MODEL是使用其中一個打包程序導出的模型的路徑。

選項

您還可以在加載模型時提供運行時選項。

要選擇運行模型的設備,可以指定“visible_device”選項:

neuropod::RuntimeOptions opts;

// Set the
visible device to the first GPU

opts.visible_device = Device::GPU0;

Neuropod neuropod(PATH_TO_MY_MODEL, opts);

默認爲GPU0。如果沒有可用的GPU,將嘗試退回到CPU。

設置opts.visible_device = Device::CPU將強制模型在CPU上運行。

獲取模型的輸入和輸出

要獲取模型的輸入和輸出,可以執行以下操作:

Neuropod neuropod(PATH_TO_MY_MODEL);

// Both of these
are std::vector<TensorSpec>

const auto &inputs = neuropod.get_inputs();

const auto &outputs = neuropod.get_outputs();

for (const auto &item : inputs)

{

// A `TensorSpec` is a struct with a `name`, `dims` and `type`

std::cout << "Tensor name: " << item.name << std::endl;

}

Tensor張量類型

支持以下Tensor張量類型:

·
float

·
double

·
string

·
int8

·
int16

·
int32

·
int64

·
uint8

·
uint16

·
uint32

·
uint64

提示

PyTorch或TorchScript不支持uint16、uint32和uint64。請參閱PyTorch文檔中支持的類型列表。

TorchScript不支持字符串Tensor張量,因此我們將它們表示爲字符串列表。因此,TorchScript-Neuropod模型只支持一維字符串“Tensor張量”。請參見此處的用法示例。

創建Tensor張量

提示

有關最適合您的用例的方法的指南,請參見高效張量創建頁面。

有很多不同的方法來創建神經網絡Tensor張量,但是所有的方法都是從分配器開始的。
要獲取加載模型的分配器,可以執行以下操作:

Neuropod neuropod(PATH_TO_MY_MODEL);

auto allocator = neuropod.get_tensor_allocator();

對於未加載模型的場景(例如單元測試),可以使用通用張量分配器:

#include “neuropod/core/generic_tensor.hh”

auto allocator = neuropod::get_generic_tensor_allocator();

分配新內存

爲此,我們只需要我們想要分配的張量的維數和類型。

auto tensor = allocator->allocate_tensor({1, 2, 3});

也可以在不使用模板函數的情況下手動指定類型

auto tensor = allocator->allocate_tensor({1, 2, 3}, neuropod::FLOAT_TENSOR);

要對這些張量做一些有用的事情,請參閱下面的“與張量的交互”部分。

從現有內存

提供了一種包裝現有記憶並以零拷貝方式使用它的方法。

要做到這一點,需要四件事:

要創建的張量的維數

要創建的張量類型

指向要包裝的數據的指針

注意:這應該是64字節對齊的

deleter函數

使用此數據完成底層庫後,將調用此deleter函數。在調用此函數之前,釋放數據是不安全的。

傳遞正確的刪除程序以確保內存不會過早釋放,這一點非常重要。下面是一些例子。

cv::Mat

cv::Mat image = … // An image from somewhere

auto tensor = allocator->tensor_from_memory<uint8_t>(

// Dimensions

{1, image.rows, image.cols, image.channels()},



// Data

image.data,



// Deleter

[image](void * unused) {

    // By capturing `image` in this deleter, we ensure

    // that the underlying data does not get deallocated

    // before we're done with the tensor.

}

);

提示

也可以在不使用模板函數的情況下指定類型

cv::Mat image = … // An image from somewhere

auto tensor = allocator->tensor_from_memory(

// Dimensions

{1, image.rows, image.cols, image.channels()},



// Tensor Type

get_tensor_type_from_cv_mat(image),



// Data

image.data,



// Deleter

[image](void * unused) {}

);

將來的版本中將添加用於包裝來自公共庫的類型的實用程序。

特徵Eigen

#include “neuropod/conversions/eigen.hh”

auto tensor = allocator->allocate_tensor({1, 2, 3});

// Returns an
Eigen::Map

auto eigen_map = neuropod::as_eigen(*tensor);

提示

如果您不使用eign的特性,只需要簡單的元素接入,請使用接入設備。

工廠函數

這些函數對於創建測試數據非常有用。

0

返回T類型的張量,input_dims輸入爲0。

auto zeros = allocator->zeros(input_dims);

1

返回T類型的張量和input_dims輸入爲1。

auto ones = allocator->ones(input_dims);

full滿的

返回T類型的張量和輸入input_dims = fill_value。

auto full = allocator->full(input_dims, fill_value);

隨機數randn

返回一個T型張量和形狀輸入維度,用正態分佈中的隨機數填充,平均值和標準偏差爲stddev。

auto full = allocator->randn(input_dims, mean = 0, stddev = 1);

序列分配

返回T類型的1D張量,其中包含從步長爲步長的開始處開始的一系列數字。

auto range1 = allocator->arange(end);

auto range2 = allocator->arange(start, end, step = 1);

示例:

// 0, 1, 2, 3, 4

auto range1 = allocator->arange(5);

// 2, 3, 4, 5

auto range2 = allocator->arange(2, 6);

// 0, 2, 4, 6, 8

auto range3 = allocator->arange(0, 10, 2);

關注eye

返回T類型和形狀(M,N)的標識矩陣。這個矩陣的對角線上爲1,其餘元素都有0。

auto eye1 = allocator->eye(M, N);

示例:

// 1, 0, 0, 0,

// 0, 1, 0, 0,

// 0, 0, 1, 0,

// 0, 0, 0, 1

auto eye1 = allocator->eye(4, 4);

// 1, 0, 0, 0,
0, 0, 0,

// 0, 1, 0, 0,
0, 0, 0,

// 0, 0, 1, 0,
0, 0, 0

auto eye2 = allocator->eye(3, 7);

與張量相互作用

本節將介紹與現有張量交互的各種方式。

張量類型

神經網絡集成軟件有幾種不同的表示張力的方法:神經網絡集成軟件值、神經網絡集成軟件張力和類型的神經網絡集成軟件張力

神經網絡值value是基類型,表示庫可以存儲和傳遞的任何值。

神經網絡張量tensor是一個神經odvalue,它是一個張量。這將添加元數據功能(維度、類型、num元素等),但不允許數據訪問。

dneuropodtensor是一種特殊類型的神經網絡張量tensor。此層次結構級別添加類型安全數據訪問。

這就是類層次結構的表示:
在這裏插入圖片描述
要從neuromodvalue轉換爲neuromodtensor,可以使用as_tensor()。

auto my_value = …

auto my_tensor = my_value->as_tensor();

要從一個NeuropodValue或NeuropodTensor轉換爲一個特定類型的TypedNeuropodTensor,可以使用as_typed_tensor)。這將對請求的類型進行類型檢查,如果請求的類型與張量的實際類型不匹配,則拋出錯誤。

auto my_value = …

auto my_float_tensor = my_value->as_typed_tensor();

// This will
throw an error

auto my_uint_tensor = my_value->as_typed_tensor<uint8_t>();

下面的部分將介紹更多的用法和示例。

提示

大多數用例不需要使用這些方法(因爲工廠和模板分配器已經返回TypedNeuropodTensors)。

通常,數據訪問需要一個TypedNeuropodTensor類型,而元數據訪問至少需要一個NeuropodTensor。

將數據copy到Tensor張量

Requires
TypedNeuropodTensor

如果要複製數據(並且無法使用上面的tensor_from_memory API包裝數據),可以執行以下操作:

float * my_data = …;

size_t num_elements = …;

tensor->copy_from(my_data, num_elements);

可用向量vectorcopy數據

std::vector my_data;

tensor->copy_from(my_data);

直接設置/獲取數據

Requires
TypedNeuropodTensor

您可以使用訪問器接口來實現這一點,該接口與PyTorch的訪問器接口非常相似。

auto tensor = allocator->allocate_tensor({6, 6});

// 2 is the
number of dimensions of this tensor

auto accessor = tensor->accessor<2>();

accessor[5][3] = 1.0;

基於範圍的for循環也適用於訪問器:

auto tensor = allocator->allocate_tensor({3, 5});

// 2 is the
number of dimensions of this tensor

auto accessor = tensor->accessor<2>();

for (const auto &row : accessor)

{

for (const auto &item : row)

{

    // Do something

}

}

張量Tensor字符示例:

auto tensor = allocator->allocate_tensorstd::string({3, 5});

// 2 is the
number of dimensions of this tensor

auto accessor = tensor->accessor<2>();

for (int i = 0; i < 3; i++)

{

for (int j = 0; j < 5; j++)

{

    accessor[i][j] = std::to_string(i * 5 + j);

}

}

使用訪問器的單個元素訪問非常高效,與優化生成期間的原始指針操作相當。

提示

有關最適合您的用例的方法的指南,請參見高效張量創建頁面。使用

獲取張量Tensor維數

Requires
NeuropodTensor

const auto &dims = tensor->get_dims();

獲取張量Tensor中元素數目

Requires
NeuropodTensor

auto num_elements = tensor->get_num_elements();

獲取張量Tensor類型

Requires
NeuropodTensor

auto tensor_type = tensor->get_tensor_type();

獲取指向基礎數據的原始指針

Requires
TypedNeuropodTensor

auto data = tensor->get_raw_data_ptr();

提示

此方法不適用於字符串張量。改用訪問器。

獲取向量vector的數據

Requires
TypedNeuropodTensor

auto data = tensor->get_data_as_vector();

warning

此方法執行復制。

推論

基本推斷方法如下:

std::unique_ptr infer(const NeuropodValueMap &inputs);

neuromodvaluemap只是從std::string到 std::shared_ptr

與它的交互等同於與std::unordered_map的交互。

示例

// Get an
allocator

auto alloctor = neuropod.get_tensor_allocator();

// Create some
tensors

auto x = allocator->randn({5, 5});

auto y = allocator->ones({5, 5});

// Run inference

const auto output_data = neuropod.infer({

{"x", x},

{"y", y}

});

// Get the
outputs

auto z = output_data->at(“z”)->as_typed_tensor();

還可以通過提供請求的輸出列表來獲取模型輸出的子集:

std::unique_ptr infer(const NeuropodValueMap &inputs, const std:: vectorstd::string requested_outputs);

例如,如果要返回僅包含張量“z”的映射,可以執行以下操作:

const auto output_data = neuropod.infer(input_data, {“z”});

序列化

所有內置的神經網絡Value類型都是可序列化的。此外,NeuropodValueMap也是可序列化的。

// A stream to
serialize to. Any ostream is allowed, but we use a

// stringstream
in this example

std::stringstream ss;

neuropod::NeuropodValueMap data = …;

neuropod::serialize(my_stream, data);

同樣,反序列化也同樣容易。

auto deserialized = neuropod::deserializeneuropod::NeuropodValueMap(ss, allocator);

提示

序列化和反序列化工作在Python和C++之間。有關更多信息,請參見Python綁定文檔。

Warning

這個API的目標是支持臨時序列化。不能保證向後兼容,因此此API不應用於數據的長期存儲。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章