不确定性估计深度学习(PyData里斯本/ 2019日)

只是分享一些幻灯片我在里斯本PyData提出了关于2019年7月有关谈话“在深学习不确定度评定“:

引用本文为:基督教S. Perone,“不确定性估计深度学习(PyData里斯本/ 2019年7月)”中亚洲金博宝未知领域,18/07/2019,//www.cpetem.com/2019/07/uncertainty-estimation-in-deep-learning-pydata-lisbon-july-2019/

PyData蒙特利尔幻灯片谈话:引擎盖下PyTorch

这些都是我在PyData蒙特利尔提出02月25日演讲的幻灯片。我也很高兴见到你们!由于很多玛丽亚and一个lexanderfor the invitation !

引用本文为:基督教S. Perone,“PyData蒙特利尔幻灯片谈话:PyTorch引擎盖下,”中亚洲金博宝未知领域,26/02/2019,//www.cpetem.com/2019/02/pydata-montreal-slides-for-the-talk-pytorch-under-the-hood/

188betiosapp

Update 28 Feb 2019:我添加了一个新的博客文章用幻灯片平台包括我做了PyData蒙特利尔的表现。

今天,在PyTorch开发者大会中,PyTorch队宣布计划与PyTorch 1.0预览有许多不错的释放如模型图一个JIT(有和没有跟踪)功能,以及在LibTorch,the PyTorch C++ API, one of the最重要的发行公告今天在我看来做。

Given the huge interest in understanding how this new API works, I decided to write this article showing an example of many opportunities that are now open after the release of the PyTorch C++ API. In this post, I’ll integrate PyTorch inference into native NodeJS using NodeJS C++ add-ons, just as an example of integration between different frameworks/languages that are now possible using the C++ API.

下面你可以看到最后的结果:

正如你所看到的,整合是无缝的,我可以用一个跟踪RESNET作为计算图模型和饲料任何张量它得到的输出预测。

Introduction

小号imply put, the libtorch is a library version of the PyTorch. It contains the underlying foundation that is used by PyTorch, such as theATEN(the tensor library), which contains all the tensor operations and methods. Libtorch also contains theautograd,这是增加了自动微分对Aten张量的分量。

谨慎为那些谁现在正在开始一个字是要小心使用,可以从ATEN和autograd创建两个张量,do not mix them中,ATEN将返回平原张量(当你使用它们创建namespace) while the autograd functions (from the火炬namespace) will return变量,by adding its automatic differentiation mechanism.

For a more extensive tutorial on how PyTorch internals work, please take a look on my previous tutorial on thePyTorch internal architecture

Libtorch can be downloaded from thePytorch网站and it is only available as a preview for a while. You can also find the documentation in本网站,这主要是一个Doxygen的渲染文档。我发现图书馆相当稳定,这是有道理的,因为它实际上是暴露PyTorch的稳定基础,但是,也有一些问题,标题和一些小问题,关于图书馆的组织,而开始使用它,你可能会发现(将希望尽快修复)。

对于的NodeJS,我将使用本土抽象库(楠),这是最值得推荐的库(实际上基本是仅标头库)来创建的NodeJS C ++的附加组件和cmake的-JS,因为libtorch已经提供cmake的文件,使我们的建设过程变得更加容易。然而,这里的重点将是C ++代码,而不是在建设过程中。

为发展方向,跟踪,序列化和加载模型,流程可以在左边的图中可以看出。

It starts with the development process and tracing being done in PyTorch (Python domain) and then the loading and inference on the C++ domain (in our case in NodeJS add-on).

结束语张量

In NodeJS, to create an object as a first-class citizen of the JavaScript world, you need to inherit from theObjectWrap类,这将负责用于包装C ++组件。

的#ifndef TENSOR_H的#define TENSOR_H的#include 的#include <炬/ torch.h>命名空间torchjs {类张量:公共楠:: ObjectWrap {公共:静态NAN_MODULE_INIT(初始化);空隙setTensor(在::张量张量){这个 - > mTensor =张量;}炬::张量getTensor(){返回这个 - > mTensor;}静态V8 ::本地 NewInstance方法();私人:明确的张量();张量〜();静态NAN_METHOD(新);静态NAN_METHOD(的toString);静态楠::持久构造;私人:火炬::张量mTensor; }; } // namespace torchjs #endif

正如你所看到的,最让我们张量类定义的代码仅仅是样板。这里的关键点是,torchjs ::张量将一个包裹火炬::张量and we added two special public methods (setTensorandgetTensor)来设置和得到这个内部火炬张量。

I won’t show all the implementation details because most parts of it are NodeJS boilerplate code to construct the object, etc. I’ll focus on the parts that touch the libtorch API, like in the code below where we are creating a small textual representation of the tensor to show on JavaScript (的toString方法):

NAN_METHOD(张量::的toString){张量* OBJ = ObjectWrap ::展开<张量>(info.Holder());的std :: stringstream的SS;在:: intList中尺寸= obj-> mTensor.sizes();SS << “张量[类型=” << obj-> mTensor.type()<< “”;SS << “大小=” <<尺寸<<的std :: ENDL;。info.GetReturnValue()设置(楠::新(ss.str())ToLocalChecked());}

我们在上面做代码,通过在刚刚起步的内部对象张从被包装的对象解缠it. After that, we build a string representation with the tensor size (each dimension sizes) and its type (float, etc).

包装张量创建操作

让我们创建一个现在包装代码为火炬::onesfunction which is responsible for creating a tensor of any defined shape filled with constant 1’s.

NAN_METHOD(个){//理智的参数检查,如果(info.Length()<2)返回楠:: ThrowError(楠::新( “错误的数目的参数”)ToLocalChecked());如果(!信息[0]  - > IsArray的()||信息[1]  - > IsBoolean()!)返回楠:: ThrowError(楠::新( “错误的参数类型”)ToLocalChecked());//检索参数(require_grad和张量形状)const的布尔require_grad =信息[1]  - > BooleanValue中();常量V8 ::本地阵列=信息[0]。如();常量uint32_t的长度=阵列 - >长度();//从V8 ::数组转换为标准::矢量的std ::矢量<长长>变暗;对于(中间体I = 0;我<长度;我++){V8 ::本地 V;INT d =阵列 - >获取(ⅰ) - > NumberValue();dims.push_back(d);} //调用libtorch并创建一个新torchjs ::张量对象//包装新火炬::张量,是由火炬创建::在::张量V =火炬::一(变暗,火炬:: requires_grad的人(require_grad)); auto newinst = Tensor::NewInstance(); Tensor* obj = Nan::ObjectWrap::Unwrap(newinst); obj->setTensor(v); info.GetReturnValue().Set(newinst); }

所以,让我们通过这个代码。我们首先检查函数的参数。对于这个功能,我们期待为张量形状和指示,如果我们要计算梯度或不是此张量节点的布尔元组(JavaScript数组)。在那之后,我们把从V8的JavaScript类型分为本地C ++类型的参数。一旦我们所需要的参数,我们再调用火炬::onesfunction from the libtorch, this function will create a new tensor where we use atorchjs ::张量Class that we created earlier to wrap it.

就是这样,我们刚刚曝光,可以用来作为本地JavaScript运行一个火炬操作。

间奏曲为PyTorch JIT

引进的PyTorch JIT围绕着火炬脚本的概念。火炬脚本是Python语言的有限子集,并配有自己的编译器和转换通行证(优化等)。

Ťhis script can be created in two different ways: by using a tracing JIT or by providing the script itself. In the tracing mode, your computational graph nodes will be visited and operations recorded to produce the final script, while the scripting is the mode where you provide this description of your model taking into account the restrictions of the Torch Script.

注意that if you have branching decisions on your code that depends on external factors or data, tracing won’t work as you expect because it will record that particular execution of the graph, hence the alternative option to provide the script. However, in most of the cases, the tracing is what we need.

Ťo understand the differences, let’s take a look at the Intermediate Representation (IR) from the script module generated both by tracing and by scripting.

@ torch.jit.script DEF happy_function_script(X):RET = torch.rand(0)如果真== TRUE:RET = torch.rand(1)否则:RET = torch.rand(2)返回RET DEF happy_function_trace(X):t RET = torch.rand(0)如果真== TRUE:RET = torch.rand(1)否则:RET = torch.rand(2)返回RET traced_fn = torch.jit.trace(happy_function_trace,(torch.tensor(0),),check_trace = FALSE)

在上面的代码中,我们提供两个功能,一个是使用@ torch.jit.script装饰,并且它是脚本的方式来创建一个火炬脚本,而第二个功能是正在使用的跟踪功能torch.jit.trace。这并不是说我故意增加了一个“真正的==真”的功能(这将永远是正确的)决定。

现在,如果我们考察这两个不同的方法所产生的IR,我们会清楚地看到跟踪和脚本方法之间的区别:

#1)格拉夫从编写脚本的方法图(%×:动态){%16:整数=拘谨::常数[值= 2]()%10:整数=拘谨::常数[值= 1]()%7:INT =拘谨::常数[值= 1]()%8:整数=拘谨::常数[值= 1]()%9:整数= ATEN ::当量(%7,%8)%保留:动态= ::拘谨如果(%9)BLOCK0(){%11:INT [] =拘谨:: ListConstruct(%10)%12:整数=拘谨::常数[值= 6]()%13:INT =拘谨::常数[值= 0]()%14:INT [] =拘谨::常数[值= [0,-1]()%ret.2:动态=阿坦::兰特(11%,12%,%13, %14) -> (%ret.2) } block1() { %17 : int[] = prim::ListConstruct(%16) %18 : int = prim::Constant[value=6]() %19 : int = prim::Constant[value=0]() %20 : int[] = prim::Constant[value=[0, -1]]() %ret.3 : Dynamic = aten::rand(%17, %18, %19, %20) -> (%ret.3) } return (%ret); } # 2) Graph from the tracing approach graph(%0 : Long()) { %7 : int = prim::Constant[value=1]() %8 : int[] = prim::ListConstruct(%7) %9 : int = prim::Constant[value=6]() %10 : int = prim::Constant[value=0]() %11 : int[] = prim::Constant[value=[0, -1]]() %12 : Float(1) = aten::rand(%8, %9, %10, %11) return (%12); }

一个s we can see, the IR is very similar to theLLVM IR应注意,在跟踪方法,跟踪记录包含的代码,真理的路径只有一条路径,而在脚本我们既有分支的替代品。然而,即使在脚本中,总是假的分支可以进行优化,并与死代码消除变换通过去除。

PyTorch JIT有很多被用来做循环展开改造通行证,死代码消除等。您可以找到这些的这里传递。不是转换成其它格式,例如ONNX可以被实施为在该中间表示(IR),这是相当方便的顶部一通。

追根RESNET

现在,在执行的NodeJS的脚本模块之前,让我们先跟踪使用PyTorch(只使用Python)的一个RESNET网络:

traced_net = torch.jit.trace(torchvision.models.resnet18(), torch.rand(1, 3, 224, 224)) traced_net.save("resnet18_trace.pt")

正如可以从上面的代码中看到的,我们只需要提供一个张量的例子(在此情况下一个批次的单个图像的与3个通道和尺寸224×224。之后,我们只需保存追踪网络到一个文件称为resnet18_trace.pt

现在,我们已经准备好执行脚本模块中的NodeJS以加载该文件被追踪。

Wrapping the Script Module

这是现在的脚本模块中的的NodeJS执行:

// Class构造ScriptModule :: ScriptModule(常量的std :: string文件名){//加载从文件这 - > mModule =炬:: JIT ::负载(文件名)所追踪的网络;} // JavaScript对象创建NAN_METHOD(ScriptModule ::新){如果(info.IsConstructCall()){//获取文件名参数V8 ::字符串:: Utf8Value param_filename(信息[0]  - >的ToString());常量的std :: string文件名=的std :: string(* param_filename);//使用该文件名ScriptModule * OBJ =新ScriptModule(文件名)创建一个新的脚本模块;obj->裹(info.This());。info.GetReturnValue()设置(info.This());}否则{V8 ::本地缺点=楠::新(构造);。info.GetReturnValue()设置(楠:: NewInstance方法(缺点).ToLocalChecked());}}

正如你可以从上面的代码中看到,我们只是创建一个类,将调用火炬:: JIT ::负荷function passing a file name of the traced network. We also have the implementation of the JavaScript object, where we convert parameters to C++ types and then create a new instance of thetorchjs :: ScriptModule

直传的包装也很简单:

NAN_METHOD(ScriptModule ::向前){ScriptModule * script_module = ObjectWrap ::展开(info.Holder());楠:: MaybeLocal 说不定=楠::要(信息[0]);张量*张量=楠:: ObjectWrap ::展开<张量>(maybe.ToLocalChecked());火炬::张量torch_tensor = tensor-> getTensor();火炬::张量输出= script_module-> mModule->向前({torch_tensor})toTensor();自动newinst中=张量:: NewInstance方法();张量* OBJ =楠:: ObjectWrap ::展开<张量>(newinst中);obj-> setTensor(输出);。info.GetReturnValue()设置(newinst中);}

正如你所看到的,在这段代码中,我们只收到张量作为参数,我们得到的内部火炬::张量从它,然后调用从脚本模块forward方法,我们总结了新的输出torchjs ::张量and then return it.

就是这样,我们就可以使用原生我们的NodeJS内置模块,如下面的例子:

VAR torchjs =需要( “./构建/释放/ torchjs”);VAR = script_module新torchjs.ScriptModule( “resnet18_trace.pt”);VAR数据= torchjs.ones([1,3,224,224],假);VAR输出= script_module.forward(数据);

我希望你喜欢!Libtorch打开了在许多不同的语言和框架的紧密集成PyTorch,这是非常令人兴奋,对生产部署代码的方向迈出了一大步门。

- 基督教S. Perone

引用本文为:基督教S. Perone, “PyTorch 1.0追踪JIT和LibTorch C ++ API来PyTorch融入的NodeJS,” 在亚洲金博宝未知领域,02/10/2018,188betiosapp

PyTorch - 内部建筑之旅

Update 28 Feb 2019:我添加了一个新的博客文章用幻灯片平台包括我做了PyData蒙特利尔的表现。

Introduction

这篇文章是围绕PyTorch代码库参观,它的目的是为PyTorch和其内部的建筑设计指导。我的主要目标是提供一些对于那些谁有兴趣了解发生什么事超出了面向用户的API,并展示一些新的东西超出了已经包含在其他的教程非常有用。

注意:PyTorch构建系统使用的代码生成广泛,所以我就不在这里重复了已经被别人描述。如果您有兴趣了解如何工作的,请阅读以下教程:

短介绍到Python扩展在C / C ++对象

正如你可能知道,你可以使用C和C的Python扩展++和发展所谓的“延伸”。所有PyTorch繁重的工作在C / C ++,而不是纯Python实现。在C / C定义一个新的Python对象类型++,可以定义像低于该一个例子的结构(其是用于autograd基变量类):

// Python对象即背torch.autograd.Variable结构THPVariable {PyObject_HEAD炬:: autograd ::可变CDATA;*的PyObject backward_hooks;};

正如你所看到的,有在定义的开始宏,叫PyObject_HEAD,该宏的目标是Python中的标准化的对象和将扩大到包含一个指向类型的对象(其限定初始化方法,分配器等),也与参考计数器的场另一种结构。

该[Re are two extra macros in the Python API calledPy_INCREF()andPy_DECREF(),这是用来递增和递减Python对象的引用计数器。多个实体可以借用或自己到其他对象的引用(引用计数器增加),只有当这个引用计数器达到零(当所有的引用被摧毁),Python将自动使用其垃圾回收对象中删除的记忆。

你可以阅读更多有关Python C / ++扩展这里

滑稽的事实:这是在许多应用亚洲金博宝中非常普遍使用小整数作为索引,计数器等为了提高效率,官方CPython的解释从-5高达256缓存整数出于这个原因,语句一个= 200;B = 200;A是B将会真正,而声明一个= 300;B = 300;A是B将会False

Zero-copy PyTorch Tensor to Numpy and vice-versa

PyTorch有它自己的张量表示,该解耦对外交涉PyTorch内部表示。然而,因为它是很常见的,尤其是当数据亚洲金博宝从多种来源,装载有numpy的阵列无处不在,所以我们真的需要作出与NumPy和PyTorch张量之间的转换。出于这个原因,PyTorch提供了两个方法叫from_numpy()andnumpy(),that converts a Numpy array to a PyTorch array and vice-versa, respectively. If we look the code that is being called to convert a Numpy array into a PyTorch tensor, we can get more insights on the PyTorch’s internal representation:

在::张量tensor_from_numpy(*的PyObject OBJ){如果(!PyArray_Check(OBJ)){抛出类型错误( “预期np.ndarray(得到的是%S)”,Py_TYPE(OBJ) - > tp_name);}自动阵列=(PyArrayObject *)OBJ;INT NDIM = PyArray_NDIM(数组);自动调整大小= to_aten_shape(NDIM,PyArray_DIMS(阵列));自动步幅= to_aten_shape(NDIM,PyArray_STRIDES(阵列));// NumPy的进步使用字节。火炬大步使用元素计数。自动element_size_in_bytes = PyArray_ITEMSIZE(数组);为(自动&步幅:步幅){步幅/ = element_size_in_bytes;} //(...) - 为了简洁省略无效* DATA_PTR = PyArray_DATA(数组); auto& type = CPU(dtype_to_aten(PyArray_TYPE(array))); Py_INCREF(obj); return type.tensorFromBlob(data_ptr, sizes, strides, [obj](void* data) { AutoGIL gil; Py_DECREF(obj); }); }

(代码从tensor_numpy.cpp

正如你可以从这个代码中看到,PyTorch是获得来自numpy的表示所有的信息(数组元数据),然后创建自己的。然而,如可以从标记线18注意,PyTorch是得到一个指针到内部numpy的阵列的原始数据而不是复制。这意味着PyTorch将创建该数据的参考,与用于原始数据张量的numpy的数组对象共享相同的存储器区域。

此外,还有一个重要的点这里:当numpy的数组对象超出范围了,并得到一个零引用计数,它会被垃圾收集和销毁,that’s why there is an increment in the reference counting of the Numpy array object at line 20.

在此之后,PyTorch将创建从该numpy的数据blob一个新的张量对象,并且在创建新张量的它与存储器的大小和进展以及稍后将被使用的功能通过借用存储数据指针,一起the Tensor Storage (we’ll discuss this in the next section) to release the data by decrementing the reference counting to the Numpy array object and let Python take care of this object life cycle.

tensorFromBlob()方法将创建一个新的张量,但只有创建一个新的“存储”这个张量之后。存储是其中实际数据指针将被存储(而不是在张量结构本身)。这需要我们去了解下部分张量存储s

张量存储

张量的实际原始数据不直接保存在张量结构,但在另一种结构称为存储,这又是张量结构的一部分。

一个s we saw in the previous code fromtensor_from_numpy(),有一个呼叫tensorFromBlob()将从原始数据blob创建一个张量。这最后一个功能将调用另外一个函数storageFromBlob(),这将反过来,对于这个数据根据其类型创建存储。在CPU浮点类型的情况下,它会返回一个新的CPUFloatStorage实例。

该CPUFloatStorage基本上是与各地实际的存储结构的效用函数的包装称为THFloatStorage我们下面显示:

typedef结构THStorage {真实*数据;ptrdiff_t的大小;INT引用计数;焦标志;THAllocator *分配器;无效* allocatorContext;STRUCT THStorage *图;} THStorage;

(代码从THStorage.h

正如你所看到的,THStorage具有指向原始数据,它的尺寸,标志和也是一个有趣的领域被称为分配器that we’ll soon discuss. It is also important to note that there is no metadata regarding on how to interpret the data inside theTHStorage,这是由于这样的事实,存储是“哑”关于它的内容,它是张量的责任要懂得“视图”或解释这个数据。

由此看来,你已经大概意识到,我们可以有指向同一个存储,但与此不同的数据视图多张量,这就是为什么有不同的形状观看张量(但保持相同数量的元素),效率非常高。此Python代码下面示出的是,在存储器中的数据指针被改变张量认为其数据的方式后共享:

>>> tensor_a = torch.ones((3,3))>>> tensor_b = tensor_a.view(9)>>> tensor_a.storage()。DATA_PTR()== tensor_b.storage()。DATA_PTR()真

正如我们可以在上面的例子中看到的,在两个张量的存储数据指针是相同的,但张量表示存储的数据的不同的解释。

现在,我们的7号线锯THFloatStorage结构中,存在一个指向TH一个llocator构建那里。而且因为它带来了关于可用亚洲金博宝于分配存储数据分配器的灵活性,这是非常重要的。这种结构通过下面的代码表示:

typedef结构THAllocator {无效*(* malloc的)(无效*,ptrdiff_t的);无效*(* realloc的)(无效*,无效*,ptrdiff_t的);空隙(*免费)(无效*,无效*);} THAllocator;

(代码从THAllocator.h

正如你所看到的,也有在这个结构中三个功能指针字段定义什么分配器手段:一个malloc,realloc的和免费的。对于CPU分配的内存,这些功能将,当然,涉及到传统的malloc / realloc的/自由POSIX的功能,但是,当我们要对我们最终会使用CUDA的GPU分配器,如分配的存储C乌达MallocHost(),就像我们可以在看THCudaHostAllocator下面malloc函数:

static void *THCudaHostAllocator_malloc(void* ctx, ptrdiff_t size) { void* ptr; if (size < 0) THError("Invalid memory size: %ld", size); if (size == 0) return NULL; THCudaCheck(cudaMallocHost(&ptr, size)); return ptr; }

(代码从THCAllocator.c

You probably noticed a pattern in the repository organization, but it is important to keep in mind these conventions when navigating the repository, as summarized here (taken from thePyTorch lib readme):

  • TH=Ť兽人H
  • THC=Ť兽人HC乌达
  • THC小号=Ť兽人HC乌达小号parse
  • THCUNN=Ť兽人HCUDAñeuralñetwork
  • THD=Ť兽人Hdistributed
  • THNN=Ť兽人Hñeuralñetwork
  • THS=Ť兽人H 2 Sparse

这种约定也存在于功能/类名和其他对象,所以它始终保持这些模式的一点是重要的。虽然你可以找到在TH代码CPU分配器,你会发现在THC代码CUDA分配器。

最后,我们可以看到主要的张量的组成THTensor结构体:

typedef struct THTensor { int64_t *size; int64_t *stride; int nDimension; THStorage *storage; ptrdiff_t storageOffset; int refcount; char flag; } THTensor;

(从代码THTensor。h

一个nd as you can see, the mainTHTensorstructure holds the size/strides/dimensions/offsets/etc as well as the storage (THStorage)for the Tensor data.

我们可以概括所有这种结构,我们在下图中看到:

现在,当我们有要求,如多处理,我们希望将多个不同进程之间共享数据的张,我们需要一个共享内存的方式来解决这个问题,否则,每次另一个进程需要一个张量,甚至当你想实现亚洲金博宝Hogwildtraining procedure where all different processes will write to the same memory region (where the parameters are), you’ll need to make copies between processes, and this is very inefficient. Therefore we’ll discuss in the next section a special kind of storage for Shared Memory.

小号hared Memory

共享内存可以根据平台支持多种不同的方式来实现。PyTorch支持其中的一些,但是为了简单起见,我会在这里讨论关于使用CPU(而非GPU)的MacOS会发生什么。由于PyTorch支持多种共享存储器方法,这部分是有点棘手把握成,因为它涉及间接在代码多个级别。

PyTorch周围提供了Python的包装模块,并且可以从被导入torch.multiprocessing。他们在各地官方Python多这个包装实施的变化做是为了确保每次张量放在一个队列或共享与另一个进程,PyTorch将确保只对共享内存的句柄将被共享,而不是亚洲金博宝张量的新的完整副本。

现在,很多人不知道从PyTorch张量方法称为share_memory_()然而,这个功能是什么触发了整个重建该特定张量的存储内存。什么这种方法确实是创建共享存储器的区域,可以不同的过程中被使用。该功能将在年底,拨打以下这个如下功能:

static THStorage* THPStorage_(newFilenameStorage)(ptrdiff_t size) { int flags = TH_ALLOCATOR_MAPPED_SHAREDMEM | TH_ALLOCATOR_MAPPED_EXCLUSIVE; std::string handle = THPStorage_(__newHandle)(); auto ctx = libshm_context_new(NULL, handle.c_str(), flags); return THStorage_(newWithAllocator)(size, &THManagedSharedAllocator, (void*)ctx); }

(从代码StorageSharing.cpp

一个nd as you can see, this function will create another storage using a special allocator calledTHManagedSharedAllocator。Ťhis function first defines some flags and then it creates a handle which is a string in the format/torch_[process id]_[random number],之后,它就会使用特殊创建一个新的存储THManagedSharedAllocator。该分配器具有函数指针称为内部PyTorch库libshm,将实施Unix域套接字通信共享所述共享存储器区域的把手。这是分配的实际情况特殊,它是一种“智能分配器”,因为它包含了通信控制逻辑以及它使用另一个名为分配器THRefcountedMapAllocator这将是负责创建实际的共享内存区域和呼叫mmap()的to map this region to the process virtual address space.

注意: when a method ends with a underscore in PyTorch, such as the method calledshare_memory_(),这意味着,该方法具有就地效果,它将改变当前对象,而不是创建一个新的与改进的。

我现在将展示使用来自张量,是由手动交换共享存储器手柄上的另一过程中分配的数据的一个处理的一个Python例如:

这是在处理A执行:

>>>进口炬>>> tensor_a = torch.ones((5,5))>>> tensor_a 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 [火炬。FloatTensor of size 5x5] >>> tensor_a.is_shared() False >>> tensor_a = tensor_a.share_memory_() >>> tensor_a.is_shared() True >>> tensor_a_storage = tensor_a.storage() >>> tensor_a_storage._share_filename_() (b'/var/tmp/tmp.0.yowqlr', b'/torch_31258_1218748506', 25)

In this code, executed in the进程A我们创建充满的人的5×5的一个新的张量。之后,我们让共享和打印与Unix域套接字地址元组以及手柄。现在,我们可以从另一个访问该存储区域进程B如下所示:

码的过程中B所执行:

>>> import torch >>> tensor_a = torch.Tensor() >>> tuple_info = (b'/var/tmp/tmp.0.yowqlr', b'/torch_31258_1218748506', 25) >>> storage = torch.Storage._new_shared_filename(*tuple_info) >>> tensor_a = torch.Tensor(storage).view((5, 5)) 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 [torch.FloatTensor of size 5x5]

正如你所看到的,使用关于Unix域套接字的地址和手柄的元组信息,我们能够从另一个访问的过程中张量存储。如果您更改此张量进程B,你也会看到它的反映进程A因为这些张量共享相同的存储区。

DLPack:对于深度学习一个希望构架巴贝尔

现在我想谈谈在PyTorch代码库的东西最近,被称为DLPack。DLPack是一个内存张量结构,其将允许交换张量数据的一个开放的标准化between frameworks,and what is quite interesting is that since this memory representation is standardized and very similar to the memory representation already in use by many frameworks, it will allow a框架之间的零拷贝数据共享,这是考虑到各种框架,我们今天有没有它们之间相互通信的相当惊人的举措。

这必将有助于克服“孤岛模式”,我们今天在MXNet,PyTorch,等张量表示之间,并且将允许开发者框架和标准化能够给框架的所有好处之间的混合架构的操作。

DLPack的核心操作系统被称为结构非常简单亚洲金博宝DLTensor,如下所示:

/ *!* \简短的纯C张量的对象,不管理内存。* / typedef结构{/ *!* \介绍不透明数据指针指向分配的数据。*这将在CUDA的OpenCL设备指针或cl_mem手柄。*这个指针始终对齐到256个字节的CUDA。* / void *的数据;/ *!\介绍张量* / DLContext CTX的设备上下文/ *! \brief Number of dimensions */ int ndim; /*! \brief The data type of the pointer*/ DLDataType dtype; /*! \brief The shape of the tensor */ int64_t* shape; /*! * \brief strides of the tensor, * can be NULL, indicating tensor is compact. */ int64_t* strides; /*! \brief The offset in bytes to the beginning pointer to data */ uint64_t byte_offset; } DLTensor;

(代码从dlpack.h

正如可以看到,对于原始数据的数据指示字,以及形状/步幅/偏移/ GPU VS CPU,和其它元数据的信息有关的数据,该DLTensor指向。

还有那个叫做张量的托管版本DLManagedTensor,where the frameworks can provide a context and also a “deleter” function that can be called by the framework who borrowed the Tensor to inform the other framework that the resources are no longer required.

In PyTorch, if you want to convert to or from a DLTensor format, you can find both C/C++ methods for doing that or even in Python you can do that as shown below:

import torch from torch.utils import dlpack t = torch.ones((5, 5)) dl = dlpack.to_dlpack(t)

Ťhis Python function will call thetoDLPack从宏正函数,如下所示:

DLManagedTensor* toDLPack(const Tensor& src) { ATenDLMTensor * atDLMTensor(new ATenDLMTensor); atDLMTensor->handle = src; atDLMTensor->tensor.manager_ctx = atDLMTensor; atDLMTensor->tensor.deleter = &deleter; atDLMTensor->tensor.dl_tensor.data = src.data_ptr(); int64_t device_id = 0; if (src.type().is_cuda()) { device_id = src.get_device(); } atDLMTensor->tensor.dl_tensor.ctx = getDLContext(src.type(), device_id); atDLMTensor->tensor.dl_tensor.ndim = src.dim(); atDLMTensor->tensor.dl_tensor.dtype = getDLDataType(src.type()); atDLMTensor->tensor.dl_tensor.shape = const_cast(src.sizes().data()); atDLMTensor->tensor.dl_tensor.strides = const_cast(src.strides().data()); atDLMTensor->tensor.dl_tensor.byte_offset = 0; return &(atDLMTensor->tensor); }

正如你所看到的,这是一个非常简单的转换,铸造从PyTorch格式的DLPack格式,元数据和分配的指针内部张量数据表示。

I really hope that more frameworks adopt this standard that will certainly give benefits to the ecosystem. It is also interesting to note that a potential integration with一个pache Arrow将是惊人的。

就是这样,我希望你喜欢这个长的帖子!

- 基督教S. Perone

Cite this article as: Christian S. Perone, "PyTorch – Internal Architecture Tour," in亚洲金博宝未知领域,12/03/2018,//www.cpetem.com/2018/03/pytorch-internal-architecture-tour/

Privacy-preserving sentence semantic similarity using InferSent embeddings and secure two-party computation

隐私保护计算

隐私保护计算或安全计算是加密的子场,其中两个(两方或2PC)或多个(多方,或MPC)当事人可以没有关于当事人私人输入数据揭示信息一起评估功能彼此。这个问题和第一个解决方案,它在1982年由安德鲁姚明在了后来被称为“做了一个惊人的突破进行了介绍姚氏百万富翁问题“。

在姚明的百万富翁问题是两个百万富翁,Alice和Bob,谁有兴趣知道其中哪些是更丰富,但without revealing对方自己的实际财富。换句话说,他们想要的东西可以概括为:Alice和Bob希望共同计算功能安全,不知道什么比对输入数据计算的结果等(这仍然是私有它们)。

为了使问题具体,Alice有量的,如$ 10和Bob拥有量B,如$ 50,他们想知道的是哪一个是较大的,没有鲍勃揭示量B给Alice或翘透露出什么量的给Bob。这是要注意同样重要的是,我们也不想在第三方信任,否则问题将只是向可信方信息交换的一个简单的协议。

在形式上,我们要的是共同评估以下功能:

[R=f(A, B)

小号uch as the private values一个andare held private to the sole owner of it and where the result[R将知道的只是一个或双方的。

这似乎很违反直觉的亚洲金博宝,象这样的问题可能永远不会得到解决,但对许多人惊讶的是,有可能解决这个问题的一些安全要求。由于在技术,如FHE最近的事态发展(全同态加密),不经意传输乱码电路,这样的问题开始变得实际[Real-life usage and they are being nowadays being used by many companies in applications such as information exchange, secure location, advertisement, satellite orbit collision avoidance, etc.

I’m not going to enter into details of these techniques, but if you’re interested in the intuition behind the OT (Oblivious Transfer), you should definitely read the amazing explanation done by Craig Gidney这里。该[Re are also, of course, many different protocols for doing 2PC or MPC, where each one of them assumes some security requirements (semi-honest, malicious, etc), I’m not going to enter into the details to keep the post focused on the goal, but you should be aware of that.

问题:句子相似度

What we want to achieve is to use privacy-preserving computation to calculate the similarity between sentences without disclosing the content of the sentences. Just to give a concrete example: Bob owns a company and has the description of many different projects in sentences such as: “Ťhis project is about building a deep learning sentiment analysis framework that will be used for tweets“爱丽丝谁拥有另一家竞争对手公司,拥有的也是类似的句子描述不同的项目。What they want to do is to jointly compute the similarity between projects in order to find if they should be doing partnership on a project or not, however, and this is the important point: Bob doesn’t want Alice to know the project descriptions and neither Alice wants Bob to be aware of their projects, they want to know the closest match between the different projects they run, but但不透露该项目的想法(项目说明)。

句子相似度比较

ñow, how can we exchange information about the Bob and Alice’s project sentences without disclosing information about the project descriptions ?

一种简单的方式来做到这一点是只计算句子的哈希值,然后只比较哈希值以检查它们是否匹配。然而,这假设的描述是完全一样的,再说,如果句子的熵是小(如小句),有人用合理的计算能力可以尝试恢复的句子。

对于这个问题的另一种方法(这是我们将要使用的方法),是句子中的句子的嵌入空间比较。我们只需要使用机器学习模型来创建句子的嵌入(我们将使用InferSent更高版本),然后比较句子的嵌入物。不过,这种做法也引起了另一个问题:如果什么鲍勃或翘火车一Seq2Seq模式,将从对方回项目的大致描述的嵌入物去?

认为可以收回他们给出的嵌入句子的大致描述这不是没有道理的。这就是为什么我们将使用两方安全计算用于计算嵌入物的相似性,在某种程度上Alice和Bob将计算的嵌入的相似性without revealing their embeddings,保持他们的项目的想法是安全的。

整个流程如下图,其中Alice和Bob共享相同的机器学习模型,之后,他们利用这个模型,从句子的嵌入进去描述,随后在嵌入空间相似的安全计算。

整个过程的框图概览。

生成文章的嵌入与InferSent

碧LSTM MAX-汇集网络。来源:自然语言推测数据万能句子陈述的监督学习。亚历克西斯Conneau等。

InferSentis an NLP technique for universal sentence representation developed by Facebook that uses supervised training to produce high transferable representations.

该ÿused a Bi-directional LSTM with attention that consistently surpassed many unsupervised training methods such as the SkipThought vectors. They also provide aPytorch实施that we’ll use to generate sentence embeddings.

注意:即使你没有GPU,你可以有几个句子合理的性能做的嵌入。

第一步,以产生句子的嵌入是下载和加载预训练InferSent模型:

进口numpy np进口火炬# fr训练模型om: https://github.com/facebookresearch/InferSent GLOVE_EMBS = '../dataset/GloVe/glove.840B.300d.txt' INFERSENT_MODEL = 'infersent.allnli.pickle' # Load trained InferSent model model = torch.load(INFERSENT_MODEL, map_location=lambda storage, loc: storage) model.set_glove_path(GLOVE_EMBS) model.build_vocab_k_words(K=100000)

现在,我们需要定义一个相似性度量来比较两个向量,并为实现这一目标,我会余弦相似性(188betcom网页版)since it’s pretty straightforward:

COS(\ PMB的x,\ PMB Y)= \压裂{\ PMB X \ CDOT \ PMB Y} {|| \ PMB X ||\ CDOT || \ PMBÿ||}

一个s you can see, if we have two unit vectors (vectors with norm 1), the two terms in the equation denominator will be 1 and we will be able to remove the entire denominator of the equation, leaving only:

COS(\帽子{X},\帽子{Y})= \帽子{X} \ CDOT \帽子{Y}

所以,如果我们规范我们的向量有一个单位范(这就是为什么向量都穿着上面公式中的帽子),我们可以使余弦相似变成只是一个简单的点积的计算。这将有助于我们很多在计算类似距离后,当我们用一个框架来做到这一点的点产品的安全计算。

因此,下一步是定义,将采取一些句子文本,并将其转发给模型生成的嵌入,然后将它们归到单位向量函数:

#该功能将转发文成模型和#得到的嵌入。在此之后,它会#正常化到一个单位向量。DEF编码(模型,文本):嵌入= model.encode([文本])[0]嵌入/ = np.linalg.norm(嵌入)返回嵌入

一个s you can see, this function is pretty simple, it feeds the text into the model, and then it will divide the embedding vector by the embedding norm.

现在,对于实际的原因,我将在以后使用整数运算计算的相似性,但是,通过InferSent产生的嵌入当然真正的价值。出于这个原因,你会在下面的代码中看到,我们创建另一个函数缩放浮点值并删除小数点and将它们转换为整数。还有另一个重要的问题,我们将在以后使用安全计算框架不允许有符号整数的,所以我们还需要在0.0和1.0之间剪辑的嵌入值。这当然会引起一些逼近误差,但是,我们仍然可以得到裁剪和缩放以有限的精度(我使用的是14位的过程中积计算比例,以避免溢出问题后)后很好的近似值:亚洲金博宝

# This function will scale the embedding in order to # remove the radix point. def scale(embedding): SCALE = 1 << 14 scale_embedding = np.clip(embedding, 0.0, 1.0) * SCALE return scale_embedding.astype(np.int32)

You can use floating-point in your secure computations and there are a lot of frameworks that support them, however, it is more tricky to do that, and for that reason, I used integer arithmetic to simplify the tutorial. The function above is just a hack to make it simple. It’s easy to see that we can recover this embedding later without too much loss of precision.

现在我们只需要创建一些句子的样品,我们将使用:

#爱丽丝句子alice_sentences =列表[“我的猫很喜欢我的键盘走了”,“我想爱抚我的猫”,]#鲍勃的句子bob_sentences名单= [“猫总是走在我的键盘”,]

一个nd convert them to embeddings:

#爱丽丝句子alice_sentence1 =编码(型号,alice_sentences [0])= alice_sentence2编码(型号,alice_sentences [1])#鲍勃句bob_sentence1 =编码(型号,bob_sentences [0])

因为我们现在的句子,每个句子也被标准化,我们只要通过执行向量之间的点积计算亚洲金博宝余弦相似性:

>>> np.dot(bob_sentence1, alice_sentence1) 0.8798542 >>> np.dot(bob_sentence1, alice_sentence2) 0.62976325

正如我们所看到的,鲍勃的第一句是不是爱丽丝第二句(〜0.62)最相似(〜0.87)与爱丽丝第一句话。

因为我们现在的嵌入物,我们只是需要把它们转换成比例整数:

#缩放alice_sentence1_scaled爱丽丝句子的嵌入=规模(alice_sentence1)alice_sentence2_scaled =规模(alice_sentence2)#量表鲍勃句子的嵌入bob_sentence1_scaled =规模(bob_sentence1)#这是单位矢量嵌入用于句子>>> alice_sentence1阵列([0.01698913, -0.0014404,0.0010993,...,0.00252409,0.00828147,0.00466533],D型细胞= FLOAT32)#这是经缩放的矢量作为整数>>> alice_sentence1_scaled阵列([278,0,18,...,41,135,76],D型细胞= INT32)

现在,这些嵌入物的比例整数,我们就可以进入第二部分,我们会做双方的安全计算。

两方安全计算

为了执行双方(Alice和Bob)之间的安全计算,我们将使用ABY框架。ABY实现了许多差异安全计算方案,并允许你描述你的计算像下面的图片,其中姚明的百万富翁的问题描述描绘的电路:

姚明的百万富翁问题。从ABY资料为准(https://github.com/encryptogr金宝博游戏网址oup/ABY)。

正如你可以看到,我们有两个输入一个GT GATE(大于门),然后输出输入。该电路具有的3为每个输入的比特长度,并且如果爱丽丝输入大于(GT GATE)鲍勃输入更大的将计算。然后,计算双方的秘密分享他们的私人数据,然后可以用算术共享,布尔共享或共享姚明能够安全地评估这些门。

偿是易于使用,因为你可以desC[Ribe your inputs, shares, gates and it will do the rest for you such as creating the socket communication channel, exchanging data when needed, etc. However, the implementation is entirely written in C++ and I’m not aware of any Python bindings for it (a great contribution opportunity).

幸运的是,对于一个ABY实现的示例可以为我们做点积计算,example is here。我不会在这里复制的例子,但只有一部分,我们必须改变读取嵌入矢量,我们之前创建的,而不是随机生成vectors and increasing the bit length to 32-bits.

在那之后,我们只需要在两台不同的机器上执行的应用程序(或通过模拟本地像下面):

#这将执行的服务器部分,所述-r 0指定的角色(服务器)#和载体的-n 4096只限定了尺寸(InferSent生成#4096维的嵌入)。〜#./innerproduct -r 0 -n 4096#而另一个进程相同(或另一台机器,但是对于另一个#机执行,你必须明明指定IP)。〜#./innerproduct -r 1 -n 4096

而我们得到如下结果:

alice_sentence1的内积和alice_sentence2的bob_sentence1 = 226691917内产品和bob_sentence1 = 171746521

Even in the integer representation, you can see that the inner product of the Alice’s first sentence and the Bob sentence is higher, meaning that the similarity is also higher. But let’s now convert this value back to float:

>>> SCALE = 1 << 14#这是点的产品,我们应该得到>>> np.dot(alice_sentence1,bob_sentence1)0.8798542#这是内部的产品,我们在安全计算>>> 226691917 / SCALE **了2.00.8444931#这是点的产品,我们应该得到>>> np.dot(alice_sentence2,bob_sentence1)0.6297632#这是内部的产品,我们在安全计算得到>>> 171746521 / SCALE ** 2.0 0.6398056

一个s you can see, we got very good approximations, even in presence of low-precision math and unsigned integer requirements. Of course that in real-life you won’t have the two values and vectors, because they’re supposed to be hidden, but the changes to accommodate that are trivial, you just need to adjust ABY code to load only the vector of the party that it is executing it and using the correct IP addresses/port of the both parties.

I hope you liked it !

- 基督教S. Perone

引用本文为:基督教S. Perone,“隐私保护使用InferSent的嵌入和安全两方计算句子的语义相似性,”在亚洲金博宝未知领域,22/01/2018,//www.cpetem.com/2018/01/privacy-preserving-infersent/

在细胞神经网络的有效感受野

鉴于“有趣的最近的一篇文章一个中央窝的同时学习到参加崛起“我决定让罗,文杰等人撰写的论文进行审查。所谓的“了解有效的感受野在深卷积神经网络”在那里,他们推出了‘的想法有效的感受野’(ERF),并与凹视觉上卷积神经网络自然会产生令人惊讶的关系。

在卷积神经网络的感受域(CNN)是影响网络的特定单元输入空间的区域中。注意,该输入区域可以是不仅在网络中的所述网络的输入,但也输出从其它单元,因此该感受域可以相对于我们考虑输入被计算并且也相对,我们考虑到为单位在此输入区域的“接收器”。通常,当提及感受野术语,它是考虑到网络的最终输出单元(在二元分类任务即,单一的单元)相对于所述网络输入(即,网络的输入图像)。

这是很容易看到,在CNN,感受域可以使用不同的方法,例如增加:堆叠多个层(深度),子采样(池,跨越),过滤器扩张(扩张卷积)等。在理论上,当你stack more layers you can increase your receptive field linearly, however, in practice, things aren’t simple as we thought, as shown by Luo, Wenjie et al.文章。在文章中,它们引入“有效感受野”,或ERF的概念;这一概念背后的直觉是,在感受野并不是所有的像素同样的输出单元的响应做出贡献。在做直传,我们可以看到,在中央感受野像素可以使用许多不同的路径,因为它们多输出单元的计算的一部分传播他们的信息输出。

In the figure below, we can see in left the input pixels, after that we have a feature map calculated from the input pixels using a 3×3 convolution filter and then finally the output after another 3×3 filtering. The numbers inside the pixels on the left image represent how many times this pixel was part of a convolution step (each sliding step of the filter). As we can see, some pixels like the central ones will have their information propagated through many different paths in the network, while the pixels on the borders are propagated along a single path.

感受域横跨使用3×3的过滤器3个不同的层。

通过看上面的图片,它并不奇怪,关于最终输出计算的有效感受野的影响会看起来更像是一个高斯分布代替均匀分布。什么是真正的甚至更有趣的是,这种感受野动态and changes during the training. The impact of this on the backpropagation is that the central pixels will have a larger gradient magnitude when compared to the border pixels.

在由洛,文杰等人写的文章,他们设计了一种方法,通过计算量量化在网络的每个输入像素的影响\压裂{\部分Y} {\局部X_ {I,J}}代表多少每个像素x_{i, j}有助于输出ÿ

In the,他们确实性实验使用多个不同的体系结构,激活,等我重复在这里,我发现最有趣的那些直观有效的感受野:

图1从纸“了解有效感受野在深卷积神经网络”,由罗,文杰等人。

一个s we can see from the图1of the,where they compare the effect of the number of layers, initialization schemes, and different activations, the results are amazing. We can clearly see the Gaussian and also the sparsity added by the ReLU activations.

也有一些比较图3的纸,其中CIFAR-10和CamVid数据集被用于训练网络。

纸“了解有效感受野在深卷积神经网络”,由罗,文杰等人的图3。

正如我们所看到的,有效的感受野的大小是非常动态的,它增加了训练,这意味着,由论文的作者指出后一大截,这更好的初始化方案可亚洲金博宝以用来增加感受野在训练的开始。他们实际上开发了不同的初始化方案,并能获得30%的培训加速,然而,这些结果并不一致。

Foveal vision on reading activity. Image from http://www.learning-systems.ch.

什么也很有趣,是有效的感受亚洲金博宝域具有与人眼的视网膜中央凹视力,如下面的图像中产生的急剧的中心视力,视锥细胞的高密度区域的效果(非常密切的关系)存在于眼底。

对人眼黄斑中心凹区。从http://eyetracking.me图像。

我们的中心以敏锐的眼光也迅速衰减,如有效的感受野,这是非常类似于高斯。亚洲金博宝令人吃惊的是,这种效果也自然出现在CNN的网络。

PS:只是为了好奇的缘故,有些鸟是做复杂的空中运动,如蜂鸟,有2个foveas而不是单一的一个,这意味着它们不仅对中部地区也对双方的尖锐眼光准确。

我希望你喜欢的文章!

- 基督教S. Perone

引用本文为:基督教S. Perone,“关于细胞神经网络的有效感受野,”在亚洲金博宝未知领域,12/11/2017,//www.cpetem.com/2017/11/the-effective-receptive-field-on-cnns/