深度学习框架集成平台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<float>({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<float>({1, 2, 3});

// Returns an `Eigen::Map`

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

提示

如果您不使用eign的特性,只需要简单的元素接入,请使用接入设备。

工厂函数

这些函数对于创建测试数据非常有用。

0

返回T类型的张量,input_dims输入为0。

auto zeros = allocator->zeros<T>(input_dims);

1

返回T类型的张量和input_dims输入为1。

auto ones = allocator->ones<T>(input_dims);

full满的

返回T类型的张量和输入input_dims = fill_value。

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

随机数randn

返回一个T型张量和形状输入维度,用正态分布中的随机数填充,平均值和标准偏差为stddev。

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

序列分配

返回T类型的1D张量,其中包含从步长为步长的开始处开始的一系列数字。

auto range1 = allocator->arange<T>(end);

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

示例:

// 0, 1, 2, 3, 4

auto range1 = allocator->arange<float>(5);

// 2, 3, 4, 5

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

// 0, 2, 4, 6, 8

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

关注eye

返回T类型和形状(M,N)的标识矩阵。这个矩阵的对角线上为1,其余元素都有0。

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

示例:

// 1, 0, 0, 0,

// 0, 1, 0, 0,

// 0, 0, 1, 0,

// 0, 0, 0, 1

auto eye1 = allocator->eye<float>(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<float>(3, 7);

与张量相互作用

本节将介绍与现有张量交互的各种方式。

张量类型

神经网络集成软件有几种不同的表示张力的方法:神经网络集成软件值、神经网络集成软件张力和类型的神经网络集成软件张力<T>

神经网络值value是基类型,表示库可以存储和传递的任何值。

神经网络张量tensor是一个神经odvalue,它是一个张量。这将添加元数据功能(维度、类型、num元素等),但不允许数据访问。

dneuropodtensor<T>是一种特殊类型的神经网络张量tensor。此层次结构级别添加类型安全数据访问。

这就是类层次结构的表示:

要从neuromodvalue转换为neuromodtensor,可以使用as_tensor()。

auto my_value = ...

auto my_tensor = my_value->as_tensor();

要从一个NeuropodValue或NeuropodTensor转换为一个特定类型的TypedNeuropodTensor,可以使用as_typed_tensor<T>)。这将对请求的类型进行类型检查,如果请求的类型与张量的实际类型不匹配,则抛出错误。

auto my_value = ...

auto my_float_tensor = my_value->as_typed_tensor<float>();

// This will throw an error

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

下面的部分将介绍更多的用法和示例。

提示

大多数用例不需要使用这些方法(因为工厂和模板分配器已经返回TypedNeuropodTensors)。

通常,数据访问需要一个TypedNeuropodTensor<T>类型,而元数据访问至少需要一个NeuropodTensor。

将数据copy到Tensor张量

Requires TypedNeuropodTensor<T>

如果要复制数据(并且无法使用上面的tensor_from_memory API包装数据),可以执行以下操作:

float * my_data = ...;

size_t num_elements = ...;

tensor->copy_from(my_data, num_elements);

可用向量vectorcopy数据

std::vector<float> my_data;

tensor->copy_from(my_data);

直接设置/获取数据

Requires TypedNeuropodTensor<T>

您可以使用访问器接口来实现这一点,该接口与PyTorch的访问器接口非常相似。

auto tensor = allocator->allocate_tensor<float>({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<float>({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_tensor<std::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<T>

auto data = tensor->get_raw_data_ptr();

提示

此方法不适用于字符串张量。改用访问器。

获取向量vector的数据

Requires TypedNeuropodTensor<T>

auto data = tensor->get_data_as_vector();

warning

此方法执行复制。

推论

基本推断方法如下:

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

neuromodvaluemap只是从std::stringstd::shared_ptr<NeuropodValue>

与它的交互等同于与std::unordered_map的交互。

示例

// Get an allocator

auto alloctor = neuropod.get_tensor_allocator();

// Create some tensors

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

auto y = allocator->ones<float>({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<float>();

还可以通过提供请求的输出列表来获取模型输出的子集:

std::unique_ptr<NeuropodValueMap> infer(const NeuropodValueMap &inputs, const std:: vector<std::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::deserialize<neuropod::NeuropodValueMap>(ss, allocator);

提示

序列化和反序列化工作在Python和C++之间。有关更多信息,请参见Python绑定文档。

Warning

这个API的目标是支持临时序列化。不能保证向后兼容,因此此API不应用于数据的长期存储。

深度学习框架集成平台C++ Guide指南的更多相关文章

  1. 金玉良缘易配而木石前盟难得|M1 Mac os(Apple Silicon)天生一对Python3开发环境搭建(集成深度学习框架Tensorflow/Pytorch)

    原文转载自「刘悦的技术博客」https://v3u.cn/a_id_189 笔者投入M1的怀抱已经有一段时间了,俗话说得好,但闻新人笑,不见旧人哭,Intel mac早已被束之高阁,而M1 mac已经 ...

  2. 28款GitHub最流行的开源机器学习项目,推荐GitHub上10 个开源深度学习框架

    20 个顶尖的 Python 机器学习开源项目 机器学习 2015-06-08 22:44:30 发布 您的评价: 0.0 收藏 1收藏 我们在Github上的贡献者和提交者之中检查了用Python语 ...

  3. 从TensorFlow 到 Caffe2:盘点深度学习框架

    机器之心报道 本文首先介绍GitHub中最受欢迎的开源深度学习框架排名,然后再对其进行系统地对比 下图总结了在GitHub中最受欢迎的开源深度学习框架排名,该排名是基于各大框架在GitHub里的收藏数 ...

  4. 转:TensorFlow和Caffe、MXNet、Keras等其他深度学习框架的对比

    http://geek.csdn.net/news/detail/138968 Google近日发布了TensorFlow 1.0候选版,这第一个稳定版将是深度学习框架发展中的里程碑的一步.自Tens ...

  5. 开源脉冲神经网络深度学习框架——惊蛰(SpikingJelly)

    开源脉冲神经网络深度学习框架--惊蛰(SpikingJelly) 背景 近年来神经形态计算芯片发展迅速,大量高校企业团队跟进,这样的芯片运行SNN的能效比与速度都超越了传统的通用计算设备.相应的,神经 ...

  6. 深度学习与CV教程(8) | 常见深度学习框架介绍

    作者:韩信子@ShowMeAI 教程地址:http://www.showmeai.tech/tutorials/37 本文地址:http://www.showmeai.tech/article-det ...

  7. 推荐GitHub上10 个开源深度学习框架

    推荐GitHub上10 个开源深度学习框架   日前,Google 开源了 TensorFlow(GitHub),此举在深度学习领域影响巨大,因为 Google 在人工智能领域的研发成绩斐然,有着雄厚 ...

  8. 贾扬清分享_深度学习框架caffe

    Caffe是一个清晰而高效的深度学习框架,其作者是博士毕业于UC Berkeley的 贾扬清,目前在Google工作.本文是根据机器学习研究会组织的online分享的交流内容,简单的整理了一下. 目录 ...

  9. TensorFlow与主流深度学习框架对比

    引言:AlphaGo在2017年年初化身Master,在弈城和野狐等平台上横扫中日韩围棋高手,取得60连胜,未尝败绩.AlphaGo背后神秘的推动力就是TensorFlow--Google于2015年 ...

随机推荐

  1. hdu3472 混合欧拉

    题意:       给你一些字符串,有的字符串反过来也有意义,题目问给的这n个字符串是否可以首尾相连,组成一个串. 思路:       算是混合欧拉的基础题目了,混合欧拉就是专门处理这类问题的,先说下 ...

  2. CTFHub-技能树-SSRF

    SSRF 目录 SSRF 1.内网访问 2.伪协议读取文件 3.端口扫描 4.POST请求 5.上传文件 6.FastCGI协议 7.Redis 8.URL Bypass 9.数字IP Bypass ...

  3. controller通过map返回减少dto类的创建

    更多精彩关注公众号 不要把实体类对象直接返给前端 ,首先想到的是创建DTO,但是这样就造成大量的DTO,显得很臃肿,为了减少dto的数量,像一些比较少的参数避免创建不必要的DTO,通过本次优化达到业务 ...

  4. PHP 读取文件夹(比如某共享文件夹)中的图片并显示

    1.获取文件夹下图片public function albumList(){ $share_url = input('path'); $files = getImgList($share_url); ...

  5. 变分贝叶斯学习(variational bayesian learning)及重参数技巧(reparameterization trick)

    摘要:常规的神经网络权重是一个确定的值,贝叶斯神经网络(BNN)中,将权重视为一个概率分布.BNN的优化常常依赖于重参数技巧(reparameterization trick),本文对该优化方法进行概 ...

  6. CAS指令

    原文链接:https://www.jianshu.com/p/00edb3d74a33   CAS是CPU的一条指令,其具有原子性,原子性是由CPU硬件层面保证的.   CAS原语有三个操作数--内存 ...

  7. python工业互联网应用实战14——单元测试覆盖率

    前面的章节我们完成了任务管理主要功能的开发及单元测试编写,可如何知道单元测试效果怎么样呢?测试充分吗?还有没有没有测到的地方呢? 本章节我们介绍一个统计测试代码覆盖率的利器Coverage,Cover ...

  8. Java 给Word添加数字签名

    本文以Java程序代码为例,介绍如何给Word文档添加数字签名. 程序运行环境 IntedliJ IDEA JDK 1.8.0 Jar包:spire.doc.jar 4.5.1 Word文档:.doc ...

  9. .NET Worker Service 如何优雅退出

    上一篇文章中我们了解了 .NET Worker Service 的入门知识[1],今天我们接着介绍一下如何优雅地关闭和退出 Worker Service. Worker 类 从上一篇文章中,我们已经知 ...

  10. MySQL如何快速插入数据

    前言: 日常学习和工作中,经常会遇到导数据的需求.比如数据迁移.数据恢复.新建从库等,这些操作可能都会涉及大量数据的导入.有时候导入进度慢,电脑风扇狂转真的很让人崩溃,其实有些小技巧是可以让导入更快速 ...