PyTrac 1跟踪JIT和LiBrand C++ API集成PyTorch into NodeJS

今天,在Pythort开发者大会上,PyTorch团队宣布了PyTorch 1.0预览版的计划和发布,该预览版具有许多不错的功能,例如模型图的JIT(有跟踪和无跟踪)以及竖笛,PyTrac C++接口,其中之一最重要的发布公告在我看来是今天做的。

考虑到人们对理解这种新的API的工作方式非常感兴趣,我决定写这篇文章,展示了很多机会,在发布PyTrac C++ API之后,现在是开放的。在这篇文章中,我将使用NoDEJS C++附加组件将PyTrar推断集成到本地NoDEJS中,作为使用C++ API现在可能的不同框架/语言之间的集成的一个例子。

下面您可以看到最终结果:

正如你所看到的,集成是无缝的,我可以使用一个跟踪的resnet作为计算图模型,并向它提供任何张量来获得输出预测。

介绍

简单地说,libtorch是pytorch的图书馆版本。它包含了Py火炬使用的基础,如阿滕(张量图书馆)它包含所有张量运算和方法。libtorch还包含自动格栅,它是把自动微分加到ATEN张量上的分量。

对于那些现在开始的人来说,要注意张量的使用,这些张量既可以用Aten生成,也可以用签名生成。不要混合它们,ATEN将返回普通张量(当使用命名空间)而签名函数(来自火炬命名空间)将返回变量,增加了自动微分机构。

关于PyTorch内部如何工作的更广泛的教程,请看一下我以前的教程Pythort内部架构.

libtorch可以从火炬火炬网站它只在一段时间内作为预览版提供。您还可以在本网站,它主要是一个由多行生成的文档。我发现图书馆很稳定,这是有道理的,因为它实际上是暴露了俾火炬稳定的基础,然而,在开始使用类库组织时,您可能会发现一些头部问题和一些与类库组织相关的小问题(希望很快就能解决)。

对NodeJS来说,我会用本地抽象库(南),它是最推荐的库(实际上基本上是一个头文件库)来创建NoDEJS C++附加组件和CJEW JS,因为libtorch已经提供了cmake文件,使我们的构建过程更加容易。然而,这里的重点将放在C++代码上,而不是在构建过程中。

发展的流程,追踪,序列化和加载模型可以在左侧的图中看到。

它从PyTrun(Python域)中的开发过程和跟踪开始,然后在C++域上加载和推理(在我们的例子中是NodeJS插件)。

包裹张量

在NodeJS,要创建一个对象作为JavaScript世界的一级公民,你需要继承ObjuttWRAP类,负责封装C++组件。

定义张量包括
          
           包括:
           
            命名空间torchjs class tensor:public nan::objectwarp public:static nan_module_init(init);void settensor(at::tensor tensor)this->mtensor=tensor;torch::tensor gettensor()返回这个->mtensor;静态V8::本地
            
             NeWistStand();private:显式张量();~张量();静态Nan_法(新);静态Nan_法(ToString);静态NaN::持久
             
              构造函数;private:torch::tensor mtensor;//命名空间torchjs endif
             
            
           
          

正如你所看到的,张量类定义的大多数代码只是样板文件。这里的关键是Trjjs::张量将包装一个火炬:张量我们添加了两种特殊的公共方法(设置张量获得张量)设置并获得内部焊炬张量。

我不会显示所有的实现细节,因为它的大部分是用于构造对象的nodejs样板代码,等。我将重点介绍接触libtorch API的部分,在下面的代码中,我们创建一个小的张量的文本表示,显示在javascript()上。弦线方法:

Nan_方法(Tensor::ToString)Tensor*Obj=ObjectWrap::Unwrap
          
           (info.holder());std::字符串流ss;at::intlist sizes=obj->mtensor.sizes();ss<“tensor[type=”<<obj->mtensor.type()<<“,“;ss<“size=”<<size<<std::endl;info.getReturnValue().set(nan::new(ss.str()).toLocalChecked());
          

我们在上面的代码中所做的,只是从包装的对象获取内部张量对象解缠它。之后,我们用张量大小(每个维度大小)及其类型(float,等)。

包装张量创建操作

现在让我们为火炬:函数,它负责创建由常量1填充的任何定义形状的张量。

nan_method(ones)//如果(info.length()<2)返回nan::throwerror(nan::new(“错误的参数数目”).toLocalChecked())参数的健全性检查;如果(!)信息[0]->isarray()!信息[1]->IsBoolean())返回Nan::ThrowerRor(Nan::New(“错误参数类型”).ToLocalChecked());//检索参数(需要_Grad和张量shape)const bool需要_Grad=info[1]->booleanvalue();const V8::本地
          
           数组=信息[0].as
           
            ();const uint32_t length=array->length();//从v8::array转换为std::vector std::vector
            
             迪姆斯;对于(int i=0);我
             
              V;int d=array->get(i)->numberValue();调光。向后推(d);//调用libtorch并创建一个新的torchjs::tensor对象//包装由torch::ones at::tensor v=torch::ones(dims,Torch::需要_Grad(需要_Grad));auto newinst=tensor::newInstance();张量*obj=nan::objectwarp::unwrap
              
               (NeWST);对象->设置传感器(V);info.getReturnValue().set(newinst);
              
             
            
           
          

所以,让我们看一下这个代码。我们首先检查函数的参数。对于这个功能,我们期望张量形状有一个元组(一个javascript数组)和一个布尔值,指示我们是否要为这个张量节点计算渐变。之后,我们将V8 JavaScript类型的参数转换为本机C++类型。一旦我们有了所需的参数,然后我们打电话给火炬:来自libtorch的函数,这个函数将在我们使用Trjjs::张量我们之前创建的用于包装它的类。

就是这样,我们只公开了一个可以用作本机JavaScript操作的火炬操作。

用于Pythort JIT的Intermezzo

引入的pytorch-jit围绕torch脚本的概念展开。Torch脚本是Python语言的一个子集,它自带编译器和转换过程(优化,等)。

这个脚本可以用两种不同的方式创建:使用跟踪JIT或提供脚本本身。在跟踪模式下,将访问您的计算图节点并记录操作以生成最终脚本,而脚本是一种模式,在这种模式下,考虑到Torch脚本的限制,您可以提供模型的描述。

注意,如果您的代码上有依赖于外部因素或数据的分支决策,跟踪不会像您期望的那样工作,因为它将记录图形的特定执行,因此提供脚本的替代选项。然而,在大多数情况下,追踪是我们需要的。

为了理解这些差异,让我们来看看由跟踪和脚本生成的脚本模块中的中间表示(IR)。

@torch.jit.scriptdef happy_函数_script(x):ret=torch.rand(0)if true==true:ret=torch.rand(1)else:ret=torch.rand(2)return retdef happy_函数_trace(x):ret=torch.rand(0)if true==true:ret=torch.rand(1)else:ret=torch.rand(2)return rettracked_=torch.jit.trace(happy_f功能追踪(火炬张量(0),),检查_trace=false)

在上面的代码中,我们提供两种功能,一个是使用@torch.jit.script.脚本装饰者,这是创建Torch脚本的脚本方式,当跟踪函数正在使用第二个函数时痕迹.我并不是有意在函数上添加了“true==true”决定(这永远都是真的)。

现在,如果我们检查这两种不同方法产生的红外线,我们将清楚地看到跟踪和脚本方法之间的区别:

1)来自脚本方法图的图(%x:dynamic)%16:int=prim::constant[value=2]()%10:int=prim::constant[value=1]()%7:int=prim::constant[value=1]()%8:int=prim::constant[value=1]()%9:int=aten::eq(%7,%8)%ret:dynamic=prim::if(%9)block0()%11:int[]=prim::listconstruct(%10)%12:int=prim::constant[value=6]()%13:int=prim::constant[value=0]()%14:int[]=prim::constant[value=[0,-1]()%ret.2:dynamic=aten::rand(%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)返回(%ret);2)来自跟踪方法图(%0:long())%7:int=prim::constant[值=1]()%8:int[]=prim::listconstruct(%7)%9:int=prim::constant[值=6]()%10:int=prim::constant[值=0]()%11:int[]=prim::constant[值=0,-1]()%12:浮点(1)=Aten::Rand(%8,% 9,% 10,%11)返回(%12);

正如我们所看到的,红外光谱与bepaly亚洲LLVM红外,注意,在跟踪方法中,记录的跟踪只包含来自代码的一条路径,真理之路,在脚本中,我们有两个分支替代方案。然而,即使在脚本编写方面,总是错误的分支可以通过死代码消除转换来优化和删除。

pytorch-jit有很多用于循环展开的转换过程,死代码消除,等。你可以找到这些通过这里.并不是说,到其他格式(如ONNX)的转换可以作为这个中间表示(IR)之上的传递来实现,这很方便。

跟踪Resnet

现在,在nodejs中实现脚本模块之前,让我们首先使用pytorch(仅使用python)跟踪resnet网络:

tracked_net=torch.jit.trace(torchvision.models.resnet18(),火炬兰德(1)三,224,224))跟踪的_net.save(“resnet18_trace.pt”)

从上面的代码中可以看到,我们只需要提供一个张量例子(在本例中,是一批3个通道的单图像,尺寸为224×224)。之后,我们将跟踪的网络保存到一个名为resnet18_跟踪.pt.

现在我们准备在nodejs中实现脚本模块,以便加载跟踪的文件。

包装脚本模块

这是nodejs中脚本模块的实现:

//类构造函数scriptmodule::scriptmodule(const std::string filename)//从文件中加载跟踪网络this->mmodule=torch::jit::load(filename);//javascript对象creationan_method(scriptmodule::new)if(info.isconstructcall())//获取文件名参数v8::string::utf8value param_filename(info[0]->toString());const std::string filename=std::string(*param_filename);//使用该文件名script module*obj=new script module(文件名)创建新的脚本模块;obj->wrap(info.this());info.getReturnValue().set(info.this());其他V8::本地
          
           cons=nan::new(构造函数);info.getReturnValue().set(nan::newInstance(cons.toLocalChecked());}
          

从上面的代码中可以看到,我们只是创建一个类来调用焊炬::jit::加载函数传递跟踪网络的文件名。我们还有javascript对象的实现,在这里,我们将参数转换为C++类型,然后创建一个新的torchjs::脚本模块.

向前传球的包装也很简单:

nan_方法(script module::forward)script module*script_module=objectwarp::unwrap
          
           (info.holder());楠:梅贝卡尔
           
            也许=南:
            
             (信息〔0〕);张量*张量=Nan::ObjectWrap::Unwrap
             
              (可能是.toLocalChecked());torch::tensor torch_tensor=tensor->gettensor();torch::tensor output=script_module->mmodule->forward(torch_tensor).totensor();auto newinst=tensor::newInstance();张量*obj=nan::objectwarp::unwrap
              
               (NeWST);obj->settensor(输出);info.getReturnValue().set(newinst);
              
             
            
           
          

正如你所看到的,在本代码中,我们只是收到一个张量作为论点,我们得到内部火炬:张量然后从脚本模块调用Forward方法,我们将输出包装在新的Trjjs::张量然后把它还给我。

就是这样,我们已经准备好在本机节点中使用我们的内置模块,如下例所示:

var torchjs=require(“/build/release/torchjs”);var script_module=new torchjs.script module(“resnet18_trace.pt”);var data=torchjs.ones([1,三,224,224,假);var输出=script_module.forward(数据);

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

—克里斯汀S.佩隆

介绍

集中不平等,或概率界限,是分析机bepaly亚洲器学习算法或随机算法的重要工具。在统计学习理论中,我们经常想证明随机变量,鉴于一些假设,接近预期,概率高。本文概述了这些集中度量分析中最基本的不等式。

马尔可夫不等式

马尔可夫不等式是最基本的边界之一,它几乎不假设随机变量。马尔可夫不等式的假设是,随机变量(x)是非负的(x>0),并且有一个有限的期望值(mathbb e left[x\right]<\infty)。马尔可夫不等式由以下公式给出:

$$\Underrace P(x\geq\alpha)\text大于常量\alpha \leq\Underrace \frac \mathbb \e \left[x\right]\alpha \text以上由常量\alpha$

这意味着随机变量\(x\)将被期望值\(x\)除以常数\(\alpha\)所限定的概率。这个界限有什么值得注意的,它适用于任何正值分布,不依赖于概率分布的任何特征,它只需要一些薄弱的假设和它的第一个时刻,期望。

例子:一家杂货店平均每天出售40瓶啤酒(现在是夏天!).明天能卖出80瓶或更多啤酒的可能性有多大?

$$
\开始{Al}}
P(x \geq \alpha)&\leq \frac \mathbb e \ left[x \ right]\ alpha \ \ leq \ frac \mathbb \ e \ left[x \ right
P(x\geq 80)&\leq\frac 40 80=0.5=50%
\{{Al}}
$$

马尔可夫不等式不依赖于随机变量概率分布的任何性质,所以很明显,如果有关于概率分布的信息,就有更好的使用界限。

切比雪夫不等式

当我们有关于随机变量基本分布的信息时,我们可以利用这个分布的性质来了解这个变量的浓度。让我们以下面的概率密度函数(pdf)给出的平均值为\(\mu=0\)和单位标准差为例:

$$F(X)=\frac 1 \sqrt 2\pi e ^-x^2/2美元

从-1到1:\(\int-1 ^ 1 \ frac 1 \ sqrt 2 \ pi e-x^2/2)的集成,我们知道68%的数据在平均值(mu)的(1-西格玛)范围内(一个标准差),95%在平均值的(2-西格玛)范围内。然而,当无法假定正常时,任何其他数量的数据都可以集中在\(1 \西格玛\)或\(2 \西格玛\)内。

切比雪夫的不等式为任何分布的集中度提供了一个约束。除了有限的均值和方差外,不假设任何潜在属性。切比雪夫也适用于任何随机变量,不仅对于非负变量,如马尔可夫不等式。

切比雪夫不等式由以下关系式给出:

$$
P(\mid x–\mu\mid\geq k\sigma)\leq\frac 1 k^2
$$

也可以改写为:

$$
P(\mid x–\mu\mid<k\sigma)\geq 1–\frac 1 k^2
$$

对于\(k=2\)的具体情况,切比雪夫告诉我们,至少75%的数据集中在平均值的2个标准偏差内。而这也适用于任何分发.

现在,当我们将这个结果与正态分布的95%浓度(2-西格玛)进行比较时,我们可以看到切比雪夫的界限有多保守。然而,我们不能忘记,这适用于任何分布,不仅适用于正态分布随机变量,切比雪夫所需要的一切,是数据的第一和第二个时刻。需要注意的一点是,在缺乏关于随机变量的更多信息的情况下,这是无法改善的。

切比雪夫不等式与弱大数定律

切比雪夫不等式也可以用来证明弱大数定律,也就是说,样本均值在概率上收敛于真实均值。

可以这样做:

  • 考虑I.I.D.序列。(独立和相同分布)随机变量\(x_1,XY2XY3具有平均值(mu)和方差(sigma^2)的\ldots;
  • 样本平均值为\(m_n=\frac x_1+\ldots+x_n n),实际平均值为\(\mu);
  • 对于样本平均值的期望值,我们有:$$
  • 对于样本的方差,我们有:$$var\left[m_n\right]=\frac var\left[x_1\right]+\ldots+var\left[x_n\right]n^2=\frac n\sigma^2 n^2=\frac \sigma^2 n美元。
  • 根据切比雪夫不等式的应用,我们得到:任意(固定)的$$P(\mid m_n–\mu \mid \geq \epsilon)\leq \frac \sigma^2 n \epsilon^2$(\epsilon>0\),随着(n)的增加,不等式的右边是零。直观地说,这意味着对于一个大的(n)浓度分布的\(m_n \)将在\(\mu \)左右。

切尔诺夫界对马尔可夫和切比雪夫的改进

在进入切尔诺夫区之前,让我们了解它背后的动机,以及如何改善切比雪夫的束缚。为了理解它,我们首先需要了解成对独立和相互独立之间的区别。为了两人独立,我们有以下内容:B和C:

$$
P(A \ Cap B)=P(A)P(B)P \
P(A \ Cap C)=P(A)P(C)P \
p(b \cap c)=p(b)p(c)
$$

这意味着任何一对(任意两个事件)都是独立的,但不一定是:

$$
P(A \Cap B \Cap C)=P(A)P(B)P(C)
$$

这就是所谓的“相互独立”,它是一种更强大的独立。根据定义,相互独立假定为成对独立,但事实并非总是相反的。这就是我们可以改进切比雪夫定界的情况,因为不做这些进一步的假设是不可能的(假设越强,界限越大)。

我们将在本教程的第二部分中讨论切尔诺夫边界!

NLP词汇表征与维特根斯坦语言哲学

我做了一个开场白关于过去的单词嵌入,这篇文章是关于单词向量后面的哲学思想部分的扩展版本。本文的目的是介绍路德维希·维特根斯坦关于语言学的主要观点,这些观点与通过设计分配(稍后我将讨论这意味着什么)的技术密切相关。如word2vec[Mikolov等人,2013,手套〔手套〕Pennington等人,二千零一十四,跳过思维向量[基罗斯等人,2015,在其他中。

维特根斯坦最有趣的方面之一可能是他在一生中发展了两种截然不同的哲学,bepaly亚洲每一个都有很大的影响。对于那些花了这么多时间研究这些想法,甚至在他们施加了重大影响之后又退缩的人来说,这是非常罕见的事情,尤其是在维也纳圈。一个真正的知识诚实的教训,在我看来,一个重要的遗产。

维特根斯坦是叔本华哲学的热心读者,与叔本华继承康德哲学一样,尤其是关于可试验物的划分(现象)与否本体)将事物对比为他们出现在我们面前从事物就像他们自己一样,维特根斯坦认为叔本华哲学从根本上是正确的。他相信在本体境界,我们没有概念上的理解,因此我们将永远无法说任何东西(而不是变得胡说八道)。相比之下现象我们的经验领域,在那里我们可以真正谈论并试图理解。通过增加安全基础,比如逻辑,对于现象世界,他能够解释世界是如何通过语言来描述的,从而描绘出语言或概念思维中如何表达和表达的极限。

维特根斯坦的第一个语言理论,在HIS中描述逻辑哲学,被称为语言图论(又名图像意义理论)。这个理论是以绘画为基础的。维特根斯坦意识到,绘画与自然景观截然不同,bepaly亚洲然而,一个熟练的画家仍然可以通过放置与自然景观现实相对应的补丁或笔画来表现真实的景观。维特根斯坦给出了这个名字逻辑形式“这一套绘画与自然景观之间的关系。这种逻辑形式,两种表示所共有的一组内部关系,这就是为什么画家能够表现现实,因为两种表现形式的逻辑形式是相同的(在这里,我称两者为“表征”,以与叔本华和康德的术语相一致,因为现实也是我们的表征。区分它和事物本身

这个理论很重要,尤其是在我们的语境中,因为维特根斯坦意识到语言也会发生同样的事情。我们能把句子中的单词组合起来,使之匹配逻辑形式我们想要描述的。逻辑形式是使我们能够谈论世界.然而,后来维特根斯坦意识到他只选择了一项任务,从语言所能完成的大量任务中,创造出一套完整的意义理论。

事实是,除了表现(想象)现实,语言还可以做许多其他的工作。用语言,正如维特根斯坦注意到的,我们可以下命令,我们不能说这是一张照片。一旦他意识到这些反例,维特根斯坦放弃了语言图论采用了一个更有力的比喻工具.在这里,我们将探讨语言意义的现代观点,以及许多现代机器学习技术背后的主要基础思想,这些技术可以很好地应用于单词/句子表示。一旦你意识到语言是一种工具,如果你想理解它的含义,你只需要理解你能用它做的所有可能的事情。如果你以一个孤立的词或概念为例,它的含义是它所有用途的总和,这个意思是流动的,可以有很多不同的面孔。这一重要的思想可以在下面的名言中总结:

一个词的意思是使用语言。

(…)

人们无法猜测一个词是如何运作的。我们必须看看它的用途,和从中学习.

——路德维希·维特根斯坦,哲学研究

事实上,这是完全有意义的,因为一旦你用尽了一个词的所有用法,上面什么都没有。现实也远比通常想象的更具流动性,因为:

我们的语言可以看作是一座古老的城市:迷宫般的小街和广场,新老房子,以及从不同时期增加的房屋(…)

——路德维希·维特根斯坦,哲学研究

约翰河弗思他是一位语言学家,也以普及意义的语境依赖性而闻名,他还利用维特根斯坦的哲学研究来强调语境在意义中的重要性,其中我引用如下:

将文本作为一个组成部分放在情境环境中有助于说明意义,因为情境是用来识别使用的。正如维特根斯坦所说,’词的意义在于其用法。“(菲尔)调查,80,109)。每天玩语言游戏的习惯和规则是公认的。因此,这样一个既定用法的文本可能包含诸如“别这么蠢”之类的句子。,“你这蠢驴!”,“他真是个混蛋!”在这些例子中,“ass”这个词在熟悉习惯的公司里,通常和你一起傻傻的-,他是个傻子,别这样。你应该知道它所保存的公司的一个字!“ass”的一个意思是它与上面提到的其他单词的习惯搭配。虽然维特根斯坦正在处理另一个问题,他还认识到普通的面额,文字的相貌。他们看着我们!“这个句子是由单词组成的,这就足够了。”

- John R.弗思

这个由公司学习一个词的意思的想法正是Word2VEC(以及基于共同发生的其他基于计数的方法)是通过数据和无监督学习的方式进行的,有监督的任务是通过设计来预测上下文的(反之亦然,取决于您使用的是skip-gram还是cbow)。这也是跳过思维向量.如今,这个想法也被称为分布假设“它也被用于语言学以外的领域。

现在,如果我们在Neelakantan等,二千零一十五,被称为“矢量空间中每个字多个嵌入的有效非参数估计“他们提到了word2vec中的一个重要缺陷,即每个单词类型只有一个向量表示,如果我们把它与维特根斯坦和弗斯的思想联系起来,你会发现它有深刻的哲学动机,因为,正如维特根斯坦注意到的,一个词的意思不太可能是一张脸,而word2vec似乎正在收敛到一个词的平均意思的近似值,而不是捕捉语言中固有的多义现象。

“证据”一词的例子中可以看到词的多方面本质的具体例子,其中的含义与历史学家完全不同,律师和物理学家。传闻在法庭上不能算作证据,而它是历史学家所拥有的唯一证据,而道听途说在物理学中甚至没有出现。最近的作品,如Elmo[彼得斯马修E等。2018,它使用了语言模型目标所训练的LSTM的不同层次的特性,这也是一个非常有趣的方向,在将上下文相关的语义合并到单词表示中,并打破了Word2vec中所看到的浅表示的传统方面取得了很好的效果。bepaly亚洲

我们正处在一个激动人心的时刻,看到有多少深刻的哲学基础实际上隐藏在机器学习技术中,真是令人惊讶。有趣的是,我们从机器学bepaly亚洲习实验中学习了很多语言课程,我们可以看到,这是发现的重要手段,正形成一个惊人的良性循环。bepaly亚洲我认为我们从来没有像过去几年那样自觉地关注语言。

我真的希望你喜欢读这个!

—克里斯汀S.佩隆

工具书类

麻吉布莱恩。哲学史。1998。

MikolovThomas等人矢量空间中单词表示的有效估计。2013年https://arxiv.org/abs/1301.3781

潘宁顿Jeffrey et al.Glove:单词表示的全局向量。2014。https://nlp.stanford.edu/projects/glove/

Kiros瑞安等。跳过思维向量。2015年https://arxiv.org/abs/1506.06726

NeelakantanArvind等人矢量空间中每个字多个嵌入的有效非参数估计。2015年https://arxiv.org/abs/1504.06654

莱昂杰奎琳。搭配的意思。语料库语言学的第一分支。2007。