本港台开奖现场直播 j2开奖直播报码现场
当前位置: 新闻频道 > IT新闻 >

报码:PyTorch内部机制解析:如何通过PyTorch实现Tensor(3)

时间:2017-08-07 09:07来源:报码现场 作者:118开奖 点击:
这样做的目的是从通用 Tensor.cpp 文件引入代码,并使用后面的宏定义。例如,我们将 real 定义为一个浮点数,所以泛型 Tensor 实现中的任何代码将指向一个

这样做的目的是从通用 Tensor.cpp 文件引入代码,并使用后面的宏定义。例如,我们将 real 定义为一个浮点数,所以泛型 Tensor 实现中的任何代码将指向一个 real 对象,实际上 real 被替换为浮点数。在对应的文件 THGenerateIntType.h 中,atv,同样的宏定义将用 int 替换 real。

这些输出文件从 split_types 返回,并添加到源文件列表中,因此我们可以看到不同的类型的.cpp 代码是如何创建的。

这里需要注意以下几点:第一,split_types 函数不是必需的。我们可以将 Tensor.cpp 中的代码包装在一个文件中,然后为每个类型重复使用。我们将代码分割成单独文件的原因是这样可以加快编译速度。第二,当我们谈论类型替换(例如用浮点数代替 real)时,我们的意思是,C 预处理器将在编译期执行这些替换。并且在预处理之前这些嵌入源代码的宏定义都没有什么弊端。

通用构建(第二部分)

我们现在有所有的 Tensor 类型的源文件,我们需要考虑如何创建相应的头文件声明,以及如何将 THTensor_(方法)和 THPTensor_(方法)转化成 TH <Type> Tensor_method 和 THP <Type> Tensor_method。例如,csrc/generic/Tensor.h 具有如下声明:

THP_API PyObject * THPTensor_(New)(THTensor *ptr);

我们使用相同的策略在头文件的源文件中生成代码。在 csrc/Tensor.h 中,我们执行以下操作:

#include "generic/Tensor.h"#include <TH/THGenerateAllTypes.h>#include "generic/Tensor.h"#include <TH/THGenerateHalfType.h>

从通用的头文件中抽取代码和用相同的宏定义包装每个类型具有同样的效果。唯一的区别就是前者编译后的代码包含在同一个头文件中,而不是分为多个源文件。

最后,我们需要考虑如何「转换」或「替代」函数类型。如果我们查看相同的头文件,我们会看到一堆 #define 语句,其中包括:

#define THPTensor_(NAME) TH_CONCAT_4(THP,Real,Tensor_,NAME)

这个宏表示,源代码中的任何匹配形如 THPTensor_(NAME)的字符串都应该替换为 THPRealTensor_NAME,其中 Real 参数是从符号 Real 所在的 #define 定义的时候派生的。因为我们的头文件代码和源代码都包含所有上述类型的宏定义,所以在预处理器运行之后,生成的代码就是我们想要的。

TH 库中的代码为 THTensor_(NAME)定义了相同的宏,支持这些功能的转移。如此一来,我们最终就会得到带有专用代码的头文件和源文件。

#### 模块对象和类型方法,我们现在已经看到如何在 THP 中封装 TH 的 Tensor 定义,并生成了 THPFloatTensor_init(...)等 THP 方法。现在我们可以从我们创建的模块中了解上面的代码实际上做了什么。THPTensor_(init)中的关键行是:

# THPTensorBaseStr, THPTensorType are also macros that are specific # to each typePyModule_AddObject(module, THPTensorBaseStr, (PyObject *)&THPTensorType);

该函数将 Tensor 对象注册到扩展模块,因此我们可以在我们的 Python 代码中使用 THPFloatTensor,THPIntTensor 等。

只是单纯的创建 Tensors 不是很有用 - 我们需要能够调用 TH 定义的所有方法。以下是一个在 Tensor 上调用就地(in-place)zero_ 方法的简单例子。

x = torch.FloatTensor(10)x.zero_()

我们先看看如何向新定义的类型中添加方法。「类型对象」中的有一个字段 tp_methods。此字段包含方法定义数组(PyMethodDefs),用于将方法(及其底层 C / C ++实现)与类型相关联。假设我们想在我们的 PyFloatObject 上定义一个替换该值的新方法。我们可以按照下面的步骤来实现这一想法:

static PyObject * replace(PyFloatObject *self, PyObject *args) { double val; if (!PyArg_ParseTuple(args, "d", &val)) return NULL; self->ob_fval = val; Py_RETURN_NONE}

Python 版本的等价方法

def replace(self, val): self.ob_fval = fal

阅读更多的关于在 CPython 中如何定义方法颇具启发性。通常,方法将对象的实例作为第一个参数,以及可选的位置参数和关键字参数。这个静态函数是在我们的浮点数上注册为一个方法:

static PyMethodDef float_methods[] = { {"replace", (PyCFunction)replace, METH_VARARGS, "replace the value in the float" }, {NULL} /* Sentinel */}

这会注册一个名为 replace 的方法,该方法由同名的 C 函数实现。METH_VARARGS 标志表示该方法使用包含函数所有参数的参数元组。该元组设置为类型对象的 tp_methods 字段,然后我们可以对该类型的对象使用 replace 方法。

(责任编辑:本港台直播)
顶一下
(0)
0%
踩一下
(0)
0%
------分隔线----------------------------
栏目列表
推荐内容