Pytorch: 整合复杂的张量

创建于 2017-02-16  ·  128评论  ·  资料来源: pytorch/pytorch

@ezyang的新描述:

https://github.com/Roger-luo/pytorch-complex的工作正在进行中

组织原则

  • 复杂张量支持对 PyTorch 很重要,我们将接受内核补丁,这些补丁添加少量代码以添加复杂支持。
  • 添加复杂性涉及编写大量新内核和代码:我们希望这些代码最初不存在于 repo 中,因此人们可以更轻松地快速迭代它们,而无需经历 PyTorch 主要代码审查过程。 我们不会承诺在短期内审查大型新内核,但最终我们希望所有内核都回到 PyTorch。
  • 外部库将可与 PyTorch 分开构建,因此您将能够将其作为单独的存储库进行维护,而无需与 PyTorch 合并(并处理大量合并冲突)。

    • PyTorch 可能偶尔会对 C++ API 进行重大更改; 如果您提请我们注意这些问题,我们将尽最大努力帮助解决这些问题。

  • PyTorch 1.0 不会附带为此所需的钩子,但它们将在不久的将来随 PyTorch 的发布版本一起提供。

我将如何处理复杂的内核?

这是工作流程在稳定状态下的样子。

PyTorch 将本机包含用于引用复杂 dtype 的 API,但默认情况下它们不会做任何事情。 PyTorch 定义了 torch.complex64 和 torch.complex128 指的是复数张量。 但是,如果您尝试以这种方式构造张量,默认情况下,PyTorch 会出错:

>>> torch.zeros({2,2}, dtype=torch.complex64)
RuntimeError: complex64 not supported by PyTorch

@ezyang提供了一个补丁,将这些数据类型添加到 PyTorch。 https://github.com/pytorch/pytorch/pull/11173

在中期,我们将合并对 PyTorch 原生支持的基本功能(如分配零张量)的支持。 什么是“基本”支持的合理代理是 PyTorch 对 CPU 半张量的本机支持(非常贫乏)。

PyTorch 发布了一个用于注册复杂张量实现的接口。 该实现继承自 TypeDefault 类(https://github.com/pytorch/pytorch/pull/11013),并将覆盖此类上的方法以定义我们具有复杂实现的函数的实现。 它看起来像这样:

struct CPUComplexFloatType final : public TypeDefault {
  virtual Tensor add(const Tensor & self, const Tensor & other, Scalar alpha=1) const override {
    // Your implementation of add for complex tensors
  }
  // ...
}

此类将完全覆盖复杂的类型; 所有其他实现由 TypeDefault 提供,默认情况下会出错。

将有一个 Type (整体接口)支持的方法的规范列表,作为一个自动生成的文件,该文件被检入 PyTorch 源存储库; 我们将通过差异将 API 更改传达给此文件。 通常,这些方法与其在 PyTorch 前端中的相应名称一一对应。

一般来说,当您使用尚未实现的操作时,

警告:我们打算将 Type away 重构到一个新系统中,该系统还支持新操作的开放注册(如果您有一个定义了您可能想要支持的所有方法的单个超类,这显然不起作用)。 因此,尽量不要太拘泥于将 Type 编写为子类的特定实现策略。

要发布新的、仅复杂的操作,您将使用 C++ 扩展 API。 C++ 扩展 API 记录在https://pytorch.org/tutorials/advanced/cpp_extension.html本质上,您可以编写如下 C++ 函数:

at::Tensor imag(at::Tensor z) {
  ...
}

然后 C++ 扩展 API 将生成一个 Python 绑定,以便您从 Python 调用此函数。

一些操作将“容易”集成到目前存在的 PyTorch 中。 例如,对于二进制操作的实现,扩展 BinaryOpsKernel.cpp 中的 add_kernel 可能更有意义,以便它在复杂类型上分派(然后你可以免费获得它,因为 std::complex 实现了加法)。 只要这些补丁很小且独立,我们承诺会及时合并它们。

它应该总是可以解除阻塞,只需在 Type 上编写覆盖而不是使用现有的基础设施,并进行自由复制粘贴。 但是,当它很容易时,让我们避免它!

自动毕业。 只要您正在处理已经为它们定义了派生公式的操作,您将“自动”获得 autograd 支持,只要您为从衍生品.yaml 向后实现中调用的所有组成函数实现复杂的支持.

在某些情况下,我们可能需要调整 autograd 公式以使其适用于复数; 例如, 'abs' 的梯度不是 'grad 。 self.sign()'。 在这些情况下,我们需要做的就是上游修复将“abs”的 autograd 公式更改为“abs_backward”,这是一个可以被覆盖的函数。

对于一般的复值反向传播,有一些参考资料:

  1. Akira 的“复值神经网络”。
  2. https://giggleliu.github.io/2018/02/01/complex_bp.html

通常,我们不需要修改 autograd,因为在大多数情况下,我们只计算实值函数的导数(损失)。

工作计划

许多必要的部分今天已经到位,但它们并没有以端到端的方式组合在一起。 这是需要做的事情。

短期整合计划。 这些操作“容易”实现,因此我们应该尽快将它们纳入 PyTorch。

  • [X] 基本张量工厂:torch.empty、torch.zeros、torch.ones
  • [] CPU 二进制操作:add、sub、mul、div #11641
  • [ ] 傅立叶变换
  • [] ???

内核实现:

TODO:根据https://github.com/Roger-luo/TH/blob/master/ChangeLog.md生成列表

其他复杂的相关任务:

  • [ ] 找出复杂张量的类型提升规则,并在promoteTypes中实现#11641

历史问题内容

@PhilippPelz的原始评论

我想知道是否有兴趣将复杂的张量合并到 pytorch 中。
对于 CPU 支持,有 ztorch,我不久前写过 z-cutorch ( https://github.com/PhilippPelz/z-cutorch )。 这是 CudaHalfTensor 重构之前的一个分支(还没有硬件)。
如果不是工作量太大,我想慢慢和pytorch集成。 我正在使用 matplotlib 通过 fb.ptyhon 进行绘图,每次重新安装我的系统(编译所有依赖项)时都会产生巨大的痛苦,而且 pytorch 似乎很快就会在 Windows 下运行,我的一台实验 PC 运行在 Windows 上。
我还需要复杂的渐变,所以我迟早也会接触 autograd。
虽然 tf 本身支持复杂的张量,但似乎许多操作还不支持它(https://github.com/tensorflow/tensorflow/issues/2255),而且对于我的目的来说它似乎有点重量级。

如果这是一个受欢迎的想法,也许有人可以说几句话如何以及从哪里开始。

feature complex triaged

最有用的评论

@sunilkpai@boeddeker@兰德尔

感谢关于复杂衍生品的报告。 我将尝试遵循这一点,我将在下周继续讨论。 我想我会在这里添加一些链接并描述项目状态。

复数的状态是非官方支持的,必须通过 PyTorch 扩展添加:

每个扩展包含两件事:

  • 包含任何必要的数学内核注册的.cpp
  • test/文件夹,其中包含非常简化的 pytorch 测试脚本版本。
    查看测试脚本以了解支持哪些内核(以及为什么不支持其他内核)。

为什么我不能将复杂的张量打印到控制台?

  • Tensor python 对象有一些漂亮的打印格式,可以调用一些不受支持的函数。

    • 您可以修改tensor.py的内容以绕过打印格式。

    • 或者,您可以简单地将 Pytorch 张量转换为 Numpy 数组,然后打印。

当前项目状态:

  • CPU覆盖率相当不错。

    • 内核在 PyTorch 中的 'aten/src/ATen/native/cpu/ </li> <li>Complex number specific code is under 'aten/src/ATen/native/cpu/zmath.h下实现

    • Intel AVX256 加速在 'aten/src/ATen/cpu/vec256/'



      • @sunilkpai :我不知道 exp 的优化。 这是您添加它的文件夹。


      • 让我知道你是否愿意做出改变。



  • GPU 覆盖范围仅限于二元和一元操作:

    • 内核在 PyTorch 中的 'aten/src/ATen/native/cuda/* </li> <li>Complex number specific code is under 'aten/src/ATen/native/cuda/zmath.cuh下实现

    • 使用thrust::complex<T>数据类型,它们包括优化的内核。

目前的发展:

  • 等待基于 C 的 TH 内核被移植到 C++ ATen 文件夹。

    • 需要 rand() 函数将测试用例移植到 pytorch 的内部测试。

    • 某些索引操作当前未移植。

    • 目前有 168/1300 个数学内核(低于 10 月份的 230 个)需要从 TH 移植到 ATen。

  • 随着这些内核在 ATen 中可用,我将尝试添加复数支持。

--

所有128条评论

我认为我们有兴趣添加对复杂张量的可选支持。 最好的方法是在torch/lib中分叉和处理 C 库。 这应该和master没有冲突,所以你可以这样做很长时间。 一旦您将库设置为可用状态,您就可以开始编写绑定,我们可以在此提供一些指导,说明当时如何避免冲突。

我有复杂类型编译的 TH。 我需要为 python 集成添加什么?

@PhilippPelz你的意思是: https ://github.com/facebook/ztorch/tree/master/lib/THZ? 或者您是否构建了自己的 TH 分支来支持复杂类型?

@killeent有一些关于 TH 如何绑定到 Python 的注释,他可以分享这些。

一般来说,为了获得复杂的张量,我更喜欢 THZ,因为它有测试等。

不过,为复杂的张量构建 CUDA 后端是一项相当大的工作,我们甚至还没有开始。

我之前写过 z-cutorch ( https://github.com/PhilippPelz/z-cutorch )。 这是 CudaHalfTensor 重构之前的一个分支(还没有硬件)。

这很棒。 我猜你已经朝着那个方向付出了巨大的努力:)

@sumith我做了一个复杂类型的 TH 分支。 基本上一个 THGenerateComplexTypes.h + 添加了 BLAS + LAPACK 例程,其余的几乎是免费的。 这对我来说似乎比检查 THZ 的哪些部分兼容然后复制粘贴要少得多。

我现在一直在编译 THPP,找出编译器消息,例如

/home/philipp/projects/pytorch/torch/lib/tmp_install/include/TH/generic/THBlas.h:6:40: 错误:在 '*' 标记之前需要 ',' 或 '...'
TH_API void THBlas_(swap)(long n, real *, long incx, real *, long incy);

有点棘手。

我很感激有关如何启用 python 集成的帮助。 CUDA 后端应该主要是从 z-cutorch 复制粘贴。

@PhilippPelz这里有一些关于 PyTorch 包装 TH 的说明: https ://gist.github.com/killeent/4675635b40b61a45cac2f95a285ce3c0

@killeent谢谢,看起来很有帮助。 lib/build_all.sh 现在正在编译,我觉得可以看一下csrc目录。

现在运行:

导入torch作为th
将 numpy 导入为 np

a = np.array([1+1j,2+2j])
b = np.array([3+3j,4+4j])
ath = th.from_numpy(a)
bth = th.from_numpy(b)
ath_cuda = ath.cuda()
ath_cuda += bth.cuda()
ath = ath_cuda.cpu()
打印(ath.numpy())

出局:[ 4.+4.j 6.+6.j]

以及大多数数学函数。
我将在接下来的几周内添加便利功能和 ffts。 我想在合并之前需要对所有内容进行测试。 如果您认识其他对复杂张量感兴趣并愿意为编写测试做出贡献的人,那就太好了。 突然想到这篇论文: Deep Complex Networks ,也许那些人会感兴趣。
我没有时间自己编写所有测试。

@PhilippPelz感谢您的评论。 我正在检查您的执行情况。 首先,我不确定您的ger实施。 一些复杂的 blas 函数不包含在您的 THBlas.c 中,例如您在生成标头中将 GER 定义为zger_cger_ ,但是在 generic/THBlas.c 中没有带有 cger_ 的 blas 函数. 不过,我可以使用您的 gemv 和其他一些功能。 IMO 也许您应该将 .gch 添加到 .gitignore? 您是否已将所有扩展推送到您的 fork 中? 我可以先根据您的实现向您的主人提出一些拉动请求。

而对于DOT我想也许对于复杂的向量, dotc的 dot 例程更常见?

是的,如果只使用real会更容易实现,当real实际上是一个复杂的时候,我感到很奇怪......

对于测试,我没有看到任何以前的 TH 测试。 我应该在哪里写这些测试? 或者我们只写一些 python 测试

是的,对不起,我看到我可能没有推送所有需要的东西。 我会在星期一再检查一次。 缺少一些声明,例如。 zger 和 cger

对于 DOT,我使用的是 cdotc 和 zdotc,它们似乎不见了,我将在下周更新。

与 pytorch 维护人员核实他们真正喜欢的命名方式。 我更喜欢你的版本,只是还没有努力。

是的,python 测试数学的东西。 大多数功能应该很容易更改,还包括复杂的数字检查。

很酷,你也在调查这个!

好的,我推送了一些更改。 TH blas 例程现在可以用于复杂的

@PhilippPelz我刚刚向您的仓库提出了拉取请求。 对于复杂的线性层和其他一些运算符。 可能有很多厄米特运算(例如复杂线性层的 bp)。 也许为张量添加一些功能? 你检查过 THNN 部分吗?

是的,hermitian 很有用。 cuda fft 现在正在工作。 cpu fft 可以从 numpy. 我还没有接触过 THNN 或 THCUNN。

@PhilippPelz我在 PR 中添加了一个简单的 Hermitian。 你能回顾一下吗? 因此,我们可以查看这些更改是否合适并进入下一步。 谢谢! PS。 看来您错过了一些标题,我也更正了该标题和其他一些警告。 对于具有实数输出的复数函数,我们应该返回实数张量而不是复数张量吗? 我已经实现了复杂类型和真实类型之间的复制方法,所以这是可能的。

在您审核后,我将重新调整所有提交。

@PhilippPelz嗨,我对您实施的THPP部分感到很困惑。 为什么它依赖于Traits.hpp的推力? 这将在没有 cuda 的情况下编译时导致错误。 是否可以只使用like要么Traits.hpp ? 我还没弄清楚。 也许你可以提供一些线索?

@Roger-luo 是的,我在其他地方也遇到了一些问题。 我们使用的复杂类型应该来自 complex.h 或 std::complex。 由于 THPP 是 C++ 包装器,因此 std::complex 可能更合适。 你能改变一下吗?

在尝试构建 cffi 扩展时,推力也会因为完全相同的原因而导致问题。 现在我正在做一个解决方法,但正确的方法是将复杂类型更改为 THC 中的 cuFloatComplex/cuDoubleComplex。 这样 cffi 编译器就不会抱怨。 我现在只想继续研究,这占用了我太多时间:(。如果你有时间,请去做。

此外,使用自定义内核调用构建 cffi 扩展非常麻烦,因为总是需要创建一个使用 nvcc 编译的额外库,然后将其链接到 cffi 包装器。 我想没有别的办法了。 可以在 ABI 模式下使用 cffi,但该网站称“API 模式改为编译直接调用目标函数的 CPython C 包装器。相对而言,它的速度要快得多(并且比 libffi 运行得更好)。”

@PhilippPelz也许reinterpret_cast可能是一个解决方案? 我想它应该改为cuComplex ,并在 THPP 中使用reinterpret_cast 。 我先试一试...

是的,我想如果你想在没有安装 cuda 的情况下构建 THPP,除了 reinterpret_cast 之外别无他法。

@PhilippPelz我想帮忙。 任何地方都有待办事项列表吗?

复杂类型需要启用 THNN 和 THCUNN。 你能和@roger-luo 协调吗? 此外,如果我们的目标是与 master 集成,则需要为所有复杂方法编写单元测试。

@elbamos THNN中的大部分工作将是为每个现有层实现新的复杂反向传播方法。 Philipp 的分叉中有一个 WIP PR。 我列出了一些参考资料。

@apaszke @soumith @PhilippPelz还有两个问题:

  • 有谁知道为什么 $ THS中还有另一个GenerateXXXTypes.h文件? 它看起来与TH中的相同。

  • byte_order.cpp中的以下代码是什么?

void THP_decodeFloatBuffer(float* dst, const uint8_t* src, THPByteOrder order, size_t len)
{
  for (size_t i = 0; i < len; i++) {
    union { uint32_t x; float f; };
    x = (order == THP_BIG_ENDIAN ? decodeUInt32BE(src) : decodeUInt32LE(src));
    dst[i] = f;
    src += sizeof(float);
  }
}

void THP_decodeDoubleBuffer(double* dst, const uint8_t* src, THPByteOrder order, size_t len)
{
  for (size_t i = 0; i < len; i++) {
    union { uint64_t x; double d; };
    x = (order == THP_BIG_ENDIAN ? decodeUInt64BE(src) : decodeUInt64LE(src));
    dst[i] = d;
    src += sizeof(double);
  }
}

关于实施其相关的复杂版本有什么建议吗? 我不确定以下实现是否正确......

void THP_decodeZFloatBuffer(std::complex<float>* dst, const uint8_t* src, THPByteOrder order, size_t len)
{
  for (size_t i = 0; i < len; i++) {
    union { uint64_t x; std::complex<float> cf;};
    x = (order == THP_BIG_ENDIAN ? decodeUInt64BE(src) : decodeUInt64LE(src));
    dst[i] = cf;
    src += sizeof(std::complex<float>);
  }
}

void THP_decodeDoubleBuffer(std::complex<double>* dst, const uint8_t* src, THPByteOrder order, size_t len)
{
  for (size_t i = 0; i < len; i++) {
    union { uint128_t x; std::complex<double> df;};
    x = (order == THP_BIG_ENDIAN ? decodeUInt128BE(src) : decodeUInt128LE(src));
    dst[i] = df;
    src += sizeof(std::complex<double>);
  }
}

以前的decodeUInt128XE被声明为

static inline uint128_t decodeUInt128LE(const uint8_t *data) {
  return (((uint128_t)data[ 0])<<  0) | (((uint128_t)data[ 1])<<  8)|
         (((uint128_t)data[ 2])<< 16) | (((uint128_t)data[ 3])<< 24)|
         (((uint128_t)data[ 4])<< 32) | (((uint128_t)data[ 5])<< 40)|
         (((uint128_t)data[ 6])<< 48) | (((uint128_t)data[ 7])<< 56)|
         (((uint128_t)data[ 8])<< 64) | (((uint128_t)data[ 9])<< 72)|
         (((uint128_t)data[10])<< 80) | (((uint128_t)data[11])<< 88)|
         (((uint128_t)data[12])<< 96) | (((uint128_t)data[13])<<104)|
         (((uint128_t)data[14])<<112) | (((uint128_t)data[15])<<120);
}

static inline uint128_t decodeUInt128BE(const uint8_t *data) {
  return (((uint128_t)data[15])<<  0) | (((uint128_t)data[14])<<  8)|
         (((uint128_t)data[13])<< 16) | (((uint128_t)data[12])<< 24)|
         (((uint128_t)data[11])<< 32) | (((uint128_t)data[10])<< 40)|
         (((uint128_t)data[ 9])<< 48) | (((uint128_t)data[ 8])<< 56)|
         (((uint128_t)data[ 7])<< 64) | (((uint128_t)data[ 6])<< 72)|
         (((uint128_t)data[ 5])<< 80) | (((uint128_t)data[ 4])<< 88)|
         (((uint128_t)data[ 3])<< 96) | (((uint128_t)data[ 2])<<104)|
         (((uint128_t)data[ 1])<<112) | (((uint128_t)data[ 0])<<120);
}

我目前在THPP中使用std::complex<T>而不是T _Complex #$ 。 我不确定这是否可以被 Python 使用。 或者只有 c 类型T _Complex可用于 python。 所以这里 dst 的类型是std::complex<T>

如果我对这个实现是正确的,可能我们需要一个uint128_t实现,比如https://github.com/calccrypto/uint128_t ? 因为似乎并非所有编译器都支持 128 位整数(gcc 有一个 int128_t 和 uint128_t)。

@PhilippPelz我注意到您的分叉没有启用问题-您的项目的状态如何? 我有点沮丧,复杂的张量不在 pytorch 的路线图上

@el3ment我已经为 CPU 添加了一个复杂的后端https://github.com/pytorch/pytorch/pull/4899但它还没有经过审查......而且我还没有收到任何关于我的 PR 的评论,因此我转而使用Julia 编程语言最近...

我上次给@PhilippPelz发了邮件,我猜他的repo 还在v0.1 下,他一直忙于论文直到9 月? 虽然我正在开发 v0.3 的新 CUDA 后端,但我没有时间单独完成所有这些绑定。 map/reduce 函数与 v0.1 不同,有一些优化,但它们不能简单地转换为支持复数。 如果有人愿意帮忙,我会很高兴...

我愿意提供帮助。

2018 年 4 月 10 日晚上 10:52,Rogerluo [email protected]写道:

@el3ment我为 CPU #4899 添加了一个复杂的后端

我上次给@PhilippPelz发了邮件,我猜他的repo 还在v0.1 下,他一直忙于论文直到9 月? 虽然我正在开发 v0.3 的新 CUDA 后端,但我没有时间单独完成所有这些绑定。 map/reduce 函数与 v0.1 不同,有一些优化,但它们不能简单地转换为支持复数。 如果有人愿意帮忙,我会很高兴...


你收到这个是因为你被提到了。
直接回复此电子邮件,在 GitHub 上查看它,或将线程静音。

@elbamos很酷,pytorch 团队似乎更喜欢单独的实现。 稍后我会为其他部分更新我的叉子。 但我真的没有时间做这件事,我想我们应该在 pytorch 团队有计划时开始着手,因为这将是 pytorch 的一个重要扩展。

嗨,我的代码在 v0.2 之后进行了一些提交

我已经看到有一个相当大的重构将所有张量代码移动到 Aten。 这意味着不能轻易地将我的 fork 合并到当前版本中,并且可能涉及更多工作。

我还在写我的博士论文,但无论如何我都打算等到 0.4 版本,直到变量和张量的合并发布。 我担心如果提前进行重构,可能会有太多的重构赶不上它。

@elbamos如果你愿意,你可以开始向我的 fork 添加东西,我会将它合并。在你的位置,我会为你正在做的任何项目实现你需要的东西。 TH(CU)NN 是一个相当大的接口,工作量很大。

@el3ment我没有时间处理其他问题。 但是,如果您需要实现一些不存在的东西,我会合并一些东西。

如果您只想要开箱即用的复数,我强烈推荐 tensorflow。

如果有编译问题,我也会提供帮助。

如果我继续做博士后,我会在某个时候将所有这些东西移植到当前版本。 脸书不想支持这一点,真是令人难过。 :((

@PhilippPelz同意,这真的很可悲,实际上 tensorflow 并不支持量子物理学中的所有运算符......我已经开始使用 Julia 并放弃了 python。

@Roger-luo 很有趣,您使用的是特定的 julia 包还是全部是自己编写的代码?

@PhilippPelz我正在 Julia 中开发一个量子多体工具包(从 PyTorch PR 开始),它包括一个基于以前一些关于复杂神经网络的论文的复杂/真实神经网络实现,我发现使用 Julia 开发它非常容易元编程。 我目前只是把它放在QMTK.jl中,它仍在进行中,我还没有完成我想要的一切。 PyTorch 确实给了我很多启发,但对于复杂的支持真的很抱歉......

但我确实有计划在未来将它分离到一个神经网络单个包中(只是现在不想维护几个 repos)。 并且会有更多的人从中国科学院物理研究所加入进来。 我会在第一个标记版本之后接受 PR(几周后)。

如果您对它的发展感兴趣,可以观看它。

如果 PyTorch 团队未来仍有复杂支持的计划,我愿意提供帮助。

不错,我会关注的!

嘿伙计们,很抱歉,自从这个问题开放以来,我们还没有对它做出回应。

这里有两个事实:

  1. 我们绝对同意 PyTorch 需要复杂的支持,并且
  2. 我们没有足够的人力来充分填补所有复杂行动所需的长尾。 (为了证明这一点,请查看稀疏支持,它在 master 中并且一直在跛行。)

自从这个问题在 2017 年被打开以来,一些重要的事情已经发生了变化,这可能会使实现复杂的支持变得更简单一些。 首先是我们现在有了 ATen,这是一个用于操纵张量的符合人体工程学的 C++ 库。 这意味着您不必复制粘贴大量 TH/THC 代码,并希望您已正确掌握所有手动引用计数,您可以编写 C++ 代码,就好像它是 Python 一样,它会运行得很快。 其次是我们正在开发一个新版本的 ATen,称为 C10,它在开放后端方面比 ATen(这是一个封闭的东西)更加认真,这应该更容易处理复杂的支持,因为它不会' t 实际上需要分叉 PyTorch,只需添加一个新的代码目录。

所以,@Roger-luo 和@PhilippPelz ,我们很乐意得到您的帮助,使复杂的后端成为现实,但我们真的很想找到一种方法来帮助我们在未来可持续地维护它。 让我们知道您的想法。

@ezyang如果你人手不够,我可以尝试在未来保持复杂的张量部分,我刚开始读博士(实际上这是我的间隔年),因此我不会有写论文的问题至少最近几年。 但是如果没有 pytorch 团队的任何反馈,我真的无法继续贡献。 我确实认为这个大扩展应该有一个路线图。 我们可以顺利添加复杂的支持,这样您的人就不需要审查大型 PR,这将减轻开发人员跟踪 master 分支的工作量。

首先,我认为复杂支持的主要问题是 CUDA 部分。 使用 ATen 或任何其他库支持 CPU 部分非常容易,如果有任何反馈,我可以在几天内重写 CPU 部分。 对于 CUDA 部分,我可能会担心一些问题,我认为这可能会导致两种不同的方法:

  1. 使用float2等来模拟单个复杂值,例如cuComplex在 CUDA 部分中执行的操作。
  2. 使用现有的FloatTensorDoubleTensor来模拟 ATen 的 C++ 部分中的复杂张量。

第二种方法的原因是因为在THC中,pytorch 使用了一些技巧来加速 map/reduce 操作,它不适合cuComplex琐碎,因为cuComplex实际上是float2 ,但__shfl_xxx函数本身不支持float2 。 目前我不确定如何有效地为float2模拟这样的功能。

第二种方法会更容易,因为我们现在不需要关心硬件,我们可以让我们的新复杂扩展在旧设备上工作更容易。 但是,由于内存地址不连续,这可能会导致一些开销。

此外,我发现要将复数集成到 ATen 中,我们可能必须处理四种在硬件上实际上相同的不同类型: std::complexthrust::complexcuComplexfloat2有时可能很危险。 (其实我去年就遇到过这个问题, reinterpreter_cast就是解决方案)。

不过,我个人更愿意写出更原生的东西。

而且我认为我们可能需要一个时间表或路线图,我们可以拾起每个小部分并一起工作,这样我就不需要自己跟踪大师了,这完全不可能......

在我尝试实现CPU后端时有一个ChangeLog ,我分类功能需要修改日志中的复数。 我们可以根据此日志编写路线图。

此外,由于我的签证刚刚被(澳大利亚)拒绝,我必须开始一个gap year,如果你需要有人继续工作,我可以申请实习。

在过去的一天里,我想了很多。 我们无法按原样合并罗杰的努力,这有点令人难过,但我心想

“我们如何构建复杂的张量支持,同时保持低维护开销?”

这就是我根据上述目标制定的有效计划:

  • 复杂张量不应该是基本的新张量类型,如sparse张量。 添加基本​​类型会导致大量维护开销和横切更改。 维护开销不是关于“谁维护复杂位?”,而是更多“现在所有核心开发人员在进行任何基本更改、任何 ATen 更改等时都应该意识到这种复杂类型”。

    • 相反,它们应该始终是 [Tensor Shape x 2] 或 [2 x TensorShape],即张量应该有一个大小为 2 的额外维度。

  • 复杂张量应该是一个包含约 2k 行简单 C++ 的小文件/文件夹,它们构建在 ATen Tensor API 之上。

    • 例如,正如https://github.com/pytorch/pytorch/issues/6514所建议的,复数乘法应该实现为torch.stack([real1 * real2 - imag1 * imag2, real1 * imag2 + imag1 * real2], dim = -1)其中real1 = input1[:, :, :, ..., 0]

    • 这会损害性能:是的,我们不会像内联所有内容那样获得那么多性能。 然而,问题是:“多少?”。 我认为我们应该以降低 20% 的性能为目标,以换取健康且功能齐全的 + 维护的复杂支持。

    • 最常用的复杂函数可以开始获得专用内核,这样当性能对常用函数的影响超过 20% 时,我们就会介入。

它必须是 [Tensor Shape x 2],因为 BLAS、cublas 和 MAGMA 都期望它们自己的复杂类型与 float2 字节兼容。 此外,无法在 python 级别处理 blas、cublas 和 magma 调用。
我认为复数乘法不会只有 20%,除了实数和图像部分的计算之外,您不是有 4 个完整的复制操作吗?
无论如何,如果我不必不断地合并来自 master 的更改,我仍然会很高兴。

同意@PhilippPelz ,我们可能会损失很多性能,因为我们将失去 BLAS、cublas 和 MAGMA 的复杂支持。 但我不确定。 然而,需要明确的是,复张量与稀疏张量完全不同,大多数库如scipy.sparse和 Julia 的SparseArrays将稀疏数组视为基本多维数组的组合。 但是没有人通过复合两个实数数组来处理具有复杂类型的多维数组......(这里没有人指的是 tensorflow、arrayfire、numpy 和 Julia)。 虽然在 MXNet 中,FFT 确实是由两个真实张量的组合完成的,但它们不支持复杂的......似乎 tensorflow 实现了一个 DataType 作为不同类型的包装器,包括complex64complex128types.proto

关于性能损失

首先,逐元素函数(函数调用 map/reduce)不会有很大的性能损失(至少,这些操作的内存是连续的)。 但是我认为我们应该首先尝试对一些 BLAS 函数进行基准测试,看看FloatTensor的组合在 GPU 上是否具有与Complex64Tensor相似的性能,以及我们将在性能上损失多少实施草案,例如:

  • gemm
  • gemv

复合复数张量看起来像(或仅使用shared_ptr ):

class ComplexTensor {
    FloatTensor *real;
    FloatTensor *imag;
};

然而,正如我在第一种方法的缺点中提到的那样,如果我们想要更原生地做到这一点,像__shfl_xxx这样的函数看起来也是一个障碍。

当前torch.fft返回一个形状[dim1, ..., dimN, 2]的浮点张量

@ezyang C10 发布的时间表是什么? 这听起来像是在 master 分支中开始支持 complex 的一个非常合理的点。

@PhilippPelz绝对不是 0.4。 我们的内部目标是 6 月,希望等待时间不会太长。

@ezyang你在六月提到过,你是否设法为 PyTorch 添加了对复数的支持?

我认为他的意思是 C10,而不是复杂的支持。 C10 将使添加复杂性变得更容易。 我就是这么理解的。

是的,C10 将开放注册张量类型和功能。 因此,将复杂类型添加为单独的包会容易得多。

复数是否有预计到达时间? “更容易”是否意味着“可能会很快完成”?

@themightyoarfish更容易,我的意思是我们不会被什么可以推送到 pytorch master 所阻止。 我们还没有设定预计到达时间。 一旦我们开放注册到 PyTorch,我将确定工作范围。

@sumith你还需要人来处理这个(复数)吗? PyTorch 团队会支持复数吗? 如果你愿意,我可以在 9 月份花一些时间来处理这个问题,因为我会维护QuCumber (它会大量使用复数)

@Roger-luo 是的。 一旦我们在 PyTorch 后端开放注册,我想与您联系,我们可以制定详细信息。
@ezyang我们会在 9 月之前进行开放式注册吗?

@sumith Cool,随时为您服务。

我们可以实现它。 (我们不会有“完整”的新系统,但只要我们设置它以使其可重构,我们就可以随着新的发展继续移动它。这将是新开放的一个很好的测试用例注册。我可以确保发生这种情况。)

@ezyang现在有什么笔记吗? 在开始工作之前,我可以阅读它。 与上次相比,情况似乎发生了很大变化。

@Roger-luo @PhilippPelz我还想帮助您实现复杂的张量。 我的博士研究也需要它..

@alexgomezalanis也许我们可以有一个频道来讨论 slack,我刚刚创建了一个频道调用#complex-numbers 。 但我要到 9 月才开始研究它(仍然需要处理我的一些 Julia 代码......)

顺便说一句,与上次相比,它似乎发生了很大变化。 我会花一些时间赶上我的手之前。

@alexgomezalanis我不能。 您必须先在 slack 上加入 pytorch 的工作区。 我找不到你。 请发送电子邮件至地址: [email protected]以获得邀请。

@Roger-luo @alexgomezalanis很高兴在复杂的张量问题上再次看到生活。 我也可以提议参与,但实际上这要到 9 月底/10 月初才会发生。 对于这个问题的相当多的评论者,复杂的张量支持对我的博士项目非常有帮助。

去年我还试图挽救我的研究 😏……但现在我只想让我的旧 1w+ loc 代码重新焕发生机。 🤣 让我们在 slack 上聊天吧!

:) 是的,让我们闲聊。 刚刚在邮件文件夹中找到了邀请。

正在进行的插件(仅在短期内用于 CPU)在这里: https ://github.com/Roger-luo/pytorch-complex

请随时给我问题和公关。

我已经在本期的顶部发布了有关如何执行复杂实施的说明。

我最近开始使用 PyTorch,我非常喜欢它——它比 TensorFlow 好用得多。 然而,复杂的张量支持对我的研究(光学神经网络)非常重要。 这是否仍在积极进行中? 如果是这样,是否有人知道复杂张量支持的(松散)时间表?

我很乐意尽我所能帮助解决这个问题,但我对 PyTorch 还比较陌生,所以我还不知道这个功能有多大。 我的一些实验室成员也表达了对复杂张量支持的浓厚兴趣(在物理学中,添加这可能使 Torch 几乎成为 NumPy 的 GPU 加速替代品)并且如果这意味着在不远的将来。

@bencbartlett

我还在努力慢慢地工作......但我目前也只是一名学生(情况相当不稳定),这意味着我不能全职工作,只能在业余时间工作。 (我从去年开始在 Julia 中实现我的研究相关代码,这意味着只有我们的遗留包需要来自 torch 的更好的复数支持。)。

如果复数对你来说很重要,并且在火炬中迫切需要,我建议试试这个:

https://github.com/PIQuIL/QuCumber/blob/master/qucumber/utils/cplx.py

它超级慢......但它至少可以工作。 或者我有一个旧 TH 风格的 C 版本。

这不会是一个几天就能完成的小项目。 因此,我无法保证在 CPU 或 CUDA 上具有复杂价值的完整功能支持的任何特定时间范围。

不过,我很乐意帮助您与我一起工作。 我建议您首先尝试解决我在扩展存储库中发布的问题。 如果您有任何问题,请随时通过 slack 或电子邮件或问题向我提问(因为还没有太多文档)。

不幸的是,我还无法访问 PyTorch Slack。 (我发了两次电子邮件请求邀请,但没有收到回音。)有人可以邀请我吗? ([email protected]

@Roger-luo 我一定会看看你的叉子,但我不能保证我会提供很多帮助——我的 C++ 生锈了,正如你所指出的,很难找到时间来解决这个问题学生。 QuCumber 实用程序很好,但不幸的是它们对我没有太大帮助:在复杂张量得到 GPU 支持或被 autograd 和 torch.nn 支持之前,它们提供的实用程序不能超过 NumPy 所能提供的。

@soumith @ezyang如果能得到 PyTorch 团队的更多关注,那就太好了! 复杂的支持似乎是通用张量库的一个重要特性,它在物理学中几乎是必不可少的,特别是在过去几年中,在 ML 中,人们对复值模型的兴趣迅速增长。

@bencbartlett QuCumber 的方法可以在带有 AD 的 GPU 上使用......它只是超级慢......我的意思是如果你只想要那个 AD,你也许可以使用它。

是的,坦率地说,我正在使用https://github.com/FluxML/Flux.jl的略微修改版本和我自己在 Julia 中的一些包进行研究(在某些情况下,我需要在 GPU 上使用张量的复杂 AD )。 source2source AD 包 Zygote.jl 可以在复杂的张量上做 AD,但它处于非常早期的阶段,可能有段错误。 与torch相比,生态系统还不是那么稳定,有时我不得不稍微修改一下这些实现以供自用......但它基本上可以满足我研究量子物理学的需要。 我也可以在 GPU 上使用复杂的张量。

我认为不需要对torch.nn的复杂值支持,一旦复杂张量起作用,我们可能只需要为autograd添加一些定义,因为像线性层这样的东西可以保持不变. 并且某些激活函数在希尔伯特空间中可能没有标准扩展......(您可以查看我的合作者@GiggleLiu的博客文章)

对于 pytorch-complex 扩展,我不确定我们什么时候才能在 GPU 上获得对 AD 的全面支持……这对我来说似乎还很遥远。 我想说 CPU 实现将经历一些需要在主树中打补丁的时期(例如类型提升、simd 支持等),这也可能与即将在 C++ 中实现 ATen 并摆脱 TH 等有关,然后我们将能够更快地为复杂张量添加运算符。

我可以在春季申请实习(我刚刚问过@ezyang )。 因此,在我开始攻读博士学位之前,我也许可以全职工作几个月。 让我们来看看。

同时,我实现了我自己的复数乘法版本。 但是,当我对其进行分析时,会发现大量时间用于:torch._C_._cuda_isDriverSufficient

image

你知道为什么吗? 如果您知道复数乘法的更好实现,请告诉我。 不知何故,我的版本(即使针对乘法数进行了优化:3 而不是 4)似乎相对较慢,例如输出张量的 irfft 比我的元素乘法快 10 倍。 PyTorch 的 C++ 级别是否支持复数乘法?

def complex_mul(x, y, out):
    uavc = x[..., 0] * (y[..., 0] + y[..., 1])
    out[..., 0] = uavc - (x[..., 0] + x[..., 1]) * y[..., 1]
    out[..., 1] = (x[..., 1] - x[..., 0]) * y[..., 0] + uavc
def test_complex_mul_out_tensor(self):
        N, C, H, W, I = 128, 3, 32, 32, 2
        K = 16  # number of filter banks
        repetitions = 1000
        dtype = torch.float
        if torch.cuda.is_available():
            device = torch.device("cuda")
        else:
            device = torch.device("cpu")
        x = torch.randn(N, 1, C, H, W, I, dtype=dtype, device=device)
        y = torch.randn(K, C, H, W, I, dtype=dtype, device=device)
        start_mul_time = time.time()
        out = torch.empty(N, K, C, H, W, I, dtype=dtype, device=device)
        for _ in range(repetitions):
            complex_mul(x, y, out)
        print("multiplication time: ", time.time() - start_mul_time)

我们正在尝试从 C++ 中支持它。 见顶帖。 如果你可以编译扩展,它至少现在应该适用于标量乘法......

您的实现类似于我们在 QuCumber 中的实现。 如果您没有为复数调用正确的 cuda 内核,它可能会调用更多额外的 GPU 线程。 如果你没有 C++ 后端作为 Python 的支持,你可能会失去 SIMD。

我建议您运行nvprof以获取更多详细信息。

@Roger-luo @apaszke @soumith感谢这个线程顺便说一句。 我实现了一个从继承 torch.Tensor 的基础复杂张量。

我将前半部分视为真实,后半部分视为虚构,并实现了我自己的基本算术运算以及我研究所需的其他一些运算。

我针对 TensorFlow 和 numpy 进行了验证。 我实现的渐变和所有操作都与它们的输出相匹配!

它只是作为一种保留,直到 PT 完全支持复杂的张量。

特征:

  1. 已实施测试。
  2. 支持 Pypi(即:pip install)
pip install pytorch-complex-tensor

https://github.com/williamFalcon/pytorch-complex-tensor

谢谢@williamFalcon

这个有更新吗? 只是想知道是否有计划将复杂类型支持集成到 pytorch 中。

嗨, @whmrtm

@ezyang正在研究https://github.com/Roger-luo/pytorch-complex/issues/4或者任何对此感兴趣的人都可以帮助我们使其运行。 此问题将解决一些基本的广播问题(解决此问题后您可以使用很多功能)。 请随时进行任何 PR 或让我将您添加为合作者。

直到夏天我才能做任何事情,必须为我们自己的包完成一个新版本。

嗨,@whmrtm

@ezyang正在研究Roger-luo/pytorch-complex#4或者任何对此感兴趣的人都可以帮助我们让它运行。 此问题将解决一些基本的广播问题(解决此问题后您可以使用很多功能)。 请随时进行任何 PR 或让我将您添加为合作者。

直到夏天我才能做任何事情,必须为我们自己的包完成一个新版本。

感谢您的更新,我会看看我能做些什么。

嗨@Roger-luo

我可以访问与复杂张量支持主题([email protected])相关的松弛频道吗? 我通过电子邮件发送了邀请,但还没有发生任何事情。 现在我正试图找出从哪里开始为这个问题做出贡献。 我猜https://github.com/Roger-luo/pytorch-complex/issues/4现在是当前的切入点?

@beconstant是的,这是起点,这应该使一些广播功能起作用,但我不知道为什么它会在 cuda 上引发类型提升错误,它正在 CPU 上工作。 (虽然我们一开始并不打算支持 cuda,但这会导致构建失败)

我无法向您发送邀请电子邮件(我无权访问)。 我认为你应该按照 pytorch 官方指南加入 slack。 但我们总是可以在问题/公关中讨论。

@Roger-luo 好的,知道了:)

让我知道你们是否需要任何帮助。 我将从构建指定的 pytorch 版本开始。 pytorch-complex/issues/4 有什么进展吗?

让我知道你们是否需要任何帮助。 我将从构建指定的 pytorch 版本开始。 pytorch-complex/issues/4 有什么进展吗?

@dylanbespalko嗨,我迫切需要在复值版本中实现的 pytorch。
非常感谢您的贡献。

最好的祝福,
Zellar209

@Zellar209

我感觉@ezyang正在努力解决一个更大的问题( pytorch-complex/issues/4 )。 我现在有一个 AMD 系统和 3 周后的 Nvidia 系统,我可以用它来增加对 GPU 的支持。

我想问题只是原始类型提升更改破坏了 CUDA,只要解决了 PR,至少有一些运算符在 CPU 上工作,我们还没有 CUDA 支持......

恕我直言,我认为我们应该先关注 CPU 并让事情正常工作,然后再考虑 GPU。

仅支持 CPU 即可。 这种类型的提升问题( pytorch-complex/issues/4是否由 fb 内部处理?可以在外部处理吗?

嗨@dylanbespalko; 我确实告诉@Roger-luo 我会调查它(因为我可能最适合找出问题所在),但我还没有时间看它。 如果您确实想了解如何解决问题,我很乐意提供建议。

@Zellar209

我感觉@ezyang正在努力解决一个更大的问题( pytorch-complex/issues/4 )。 我现在有一个 AMD 系统和 3 周后的 Nvidia 系统,我可以用它来增加对 GPU 的支持。

是的,我现在不需要任何 GPU,我使用的是 MAC 系统。 但是我在构建这个项目时遇到了一些错误。

@Zellar209 ,你能发布你在pytorch-complex 的问题中得到的东西吗? 我认为 Mac 的新 Xcode 有问题,这使得构建变得困难。 但是人们需要更多的错误信息来找出原因。

我询问了操作系统和错误消息,但您没有回复...

嗨@dylanbespalko; 我确实告诉@Roger-luo 我会调查它(因为我可能最适合找出问题所在),但我还没有时间看它。 如果您确实想了解如何解决问题,我很乐意提供建议。

感谢您早日回复。

1. 当我使用 gcc(默认)运行“python setup.py install”时,出现如下错误:

构建“torch_complex.cpp”扩展
gcc -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -I/anaconda3/include -arch x86_64 -I/anaconda3/include -arch x86_64 -I/ anaconda3/lib/python3.6/site-packages/torch/include -I/anaconda3/lib/python3.6/site-packages/torch/include/torch/csrc/api/include -I/anaconda3/lib/python3。 6/site-packages/torch/include/TH -I/anaconda3/lib/python3.6/site-packages/torch/include/THC -I/anaconda3/include/python3.6m -c src/module.cpp -o build/temp.macosx-10.7-x86_64-3.6/src/module.o -g -stdlib=libc++ -std=c++11 -DTORCH_API_INCLUDE_EXTENSION_H -DTORCH_EXTENSION_NAME=cpp
gcc:错误:无法识别的命令行选项“-stdlib=libc++”

错误:命令“gcc”失败,退出状态为 1

2.我用clang编译的时候报错:

在 src/module 中包含的文件中。 cpp:2
在 src/CPUComplexType.h:60 包含的文件中:
src/CPUComplexTypeImpl.h:102:105: 警告: 'IntList' 已弃用 [-Wdeprecated-declarations]
Tensor & CPUComplexType::set_(Tensor & self, Storage source, int64_t storage_offset, IntList sizes, IntList strides) const {
^
/anaconda3/lib/python3.6/site-packages/torch/include/c10/util/ArrayRef.h:273:7:注意:“IntList”已在此处明确标记为弃用
使用 IntList C10_DEPRECATED_USING = ArrayRef;
^
在 src/module 中包含的文件中。 cpp:2
在 src/CPUComplexType.h:60 包含的文件中:
src/CPUComplexTypeImpl.h:105:76:错误:命名空间“at”中没有名为“scalarTypeToDataType”的成员
auto source_ = checked_storage(source,"source",2, DeviceType::CPU, at::scalarTypeToDataType(CPUComplexTypeInfo::scalar_type));
~~~~^
生成 7 个警告和 2 个错误。

错误:命令“clang”失败,退出状态为 1

我无法修复它。 我真的希望你能帮助我!

大家好,

感谢您的反馈意见。 我想我可以花一周的时间来研究这个。 到目前为止,我已经编译了 @Roger-luo 的 pytorch-complex 如下:

@Zellar209 :我附加了在 macOS 10.13 上运行的环境变量。

  1. 删除现有的pytorch分布如下
    conda 卸载 pytorch
    pip 卸载火炬
    pip uninstall torch # 运行此命令两次
    python setup.py 清理
    删除 python site-packages 文件夹中的 torch 文件夹(如果存在)。
    重命名(或删除)以前的 pytorch 源文件夹(引用它的东西)。

  2. 安装 PyTorch 修订版 6cb593b88cb0c411690b4957850058329526d87b。

    git clone [email protected]:pytorch/pytorch.git
    git checkout 6cb593b88cb0c411690b4957850058329526d87b
    git submodule update --init —recursive
    export CMAKE_PREFIX_PATH=${CONDA_PREFIX:-"$(dirname $(which conda))/../“}
    MACOSX_DEPLOYMENT_TARGET=10.13 CC=clang CXX=clang++ python setup.py develop
    python
>>> import torch
  1. 安装 pytorch-complex
    python setup.py install
    python setup.py build
    python setup.py test
    # ERROR: test (unittest.loader._FailedTest)
    # ERROR: test_scalar_binary_op (tests.test_tensor.TestComplexTensor)
  1. 创建一个复杂的张量
   from torch_complex import torch
   a = torch.ones(3, dtype=torch.complex128)
   a*a  
   RuntimeError: promoteTypes with complex numbers is not handled yet; figure out what the correct rules should be

@ ezyang ,@罗杰罗:

张量操作的类型提升的一切似乎都在c10/core/ScalarType.h中完成
我发现了错误AT_ERROR("promoteTypes with complex numbers is not handled yet; figure out what the correct rules should be”);
看来我必须在此表中添加 c8 和 c16 的条目。
这和9515有关系吗? 我认为这只是为了调用 numpy 函数。
这是一个很好的起点吗?

9515 无关。 但是,在 ScalarType.h 中修复此代码路径是一个不错的起点。

我在 ScalarType.h 中修复了代码路径
BinaryOps (add, sub, mul, div) 有效,但前提是两个参数都是张量。
其他一些奇怪的问题,但我需要多看一些。

@dylanbespalko我在这里添加了类型促销: https ://github.com/pytorch/pytorch/pull/11641

你可以复制它,但问题是这会以某种方式破坏 CUDA。

IIRC,由于 gcc 版本,存在线路错误。 我在那里有一些解决方法。

啊,谢谢@Roger-luo。 我在看#11641的评论。 明天我会更好地复制代码。

当我没有 CUDA 设备时,我如何知道我何时损坏了 CUDA? 我假设CI会告诉我?

是的,只要你提交 PR,它就会告诉你哪个坏了。 如果一切都过去了,那么我们就可以合并它并使事情正常进行。

好的,那么我将开始提交 PR,以便我知道它何时发生。

@dylanbespalko嗨,您的环境中似乎还有一些错误?
如果你修复它,请与我们分享。 非常感谢。

大家好,

在复制了几个 @Roger-luo 的提交后,我尝试了几个 PR。 不幸的是,我现在没有 CUDA GPU,带有 CUDA 的 CI 机器也没有初始化。 我现在无法重新创建 CUDA 测试失败,所以我会在几周后在该 GPU 上本地运行时回到这个问题。 至少看起来很有希望。

@ ezyang ,@罗杰罗

我看过 Roger 的 PR #11641

  • 它在我的 CUDA 9.0 机器上构建和运行
  • 它无法在运行 CUDA 9.0 的 CI 机器上构建

我还查看了 PyTorch 最近的一些发展:

  • @ezyang演示文稿描述了如何编写可以定义自定义device/layout/ dtype 的 C++/CUDA 扩展。

    • 最近的 PR #21964 “删除了 ComplexHooksInterface”,但定义了一个复数 C++ 扩展,位于 pytorch/test/cpp_extensions/complex_registration_extension.cpp

在我看来,正在开发一种新的“树外”扩展功能,这将使我能够在不破坏其余 pytorch 的情况下研究复数支持。 我的目标是:

  1. 定义没有 AVX 的复杂 CPU 支持。
  2. 使用 Thrust 定义复杂的 CUDA 支持。

@ezyang
您能否为您展示的这种树外设备/布局/dtype扩展提供预期的时间表? 我们可以在未来 3 个月内期待这个功能吗?

@ezyang

您能否在没有 AVX/SSE 支持的情况下合并 CPU 上的复数支持? 我计划在单独的合并请求中提交以下内容:

  • [ ] 添加了对 CPU BinaryOp 内核的复杂支持
  • [] 添加了对 CPU TensorFactories 的复杂支持
  • [ ] 添加了对 CPU FillKernels 的复杂支持
  • [ ] 添加了对 CPU Range 内核的复杂支持
  • [ ] 添加了对 CPU 一元内核的复杂支持
  • [ ] 添加了对 CPU 比较内核的复杂支持
  • [ ] 添加了对 CPU TensorCompare 内核的复杂支持
  • [ ] 添加了对 CPU ReduceOp 内核的复杂支持
  • [ ] 添加了对 CPU PointwiseOps 内核的复杂支持
  • [ ] 添加了对 CPU learpOps 内核的复杂支持
  • [ ] 添加了对 CPU LinearAlgebraOps 内核的复杂支持
  • [ ] 添加了对 CPU SpectralOps 内核的复杂支持

我计划在接下来的几天内在 intel/arm cpus 上对此进行测试。

@ezyang

我正在研究像fft()var()这样的操作,其中复数实现必须将张量数据转换为形状的双张量: (complex_shape, 2) 。 这不适用于任何现有的张量方法:

  1. 'tensor.to(torch.float64): 只保留实部,并返回一个形状相同的张量。
  2. 'tensor.view(new_shape): 新形状必须有相同数量的元素。

显然我可以做一些低效的事情,比如:

def to_float(tensor):
    return th.stack((tensor.real().type(th.float64), tensor.imag().type(th.float64)), -1)

def to_complex(tensor):
    tensor = tensor.type(th.complex128) 
    return tensor[..., 0] + 1j*tensor[..., 1]

显然,这是创建副本,而我只需要static_cast<double>并将张量的形状更改为(old_shape, 2) 。 你对如何做到这一点有什么建议吗?

此外,numpy 中有一个 hack 允许您执行此操作:

a = np.array([1 + 1j], dtype=np.complex128)
a.dtype = np.float64  ## This works

a = torch.tensor([1 + 1j], dtype=torch.complex128)
a.dtype = torch.float64  ## This does not work

设置 dtype 的能力在这种情况下确实有效,但是它可能是不可预测的。

有关将复数解释为长度为 2 的实数数组的一些附加信息。 以下在 C++11 中有效。

对于任何指向复数数组元素 p 和任何有效数组索引 i 的指针,reinterpret_cast(p)[2 i] 是复数 p[i] 的实部,reinterpret_cast(p)[2 i + 1] 是复数 p[i] 的虚部。 (C++11 起)

我认为这意味着可以将 complex_tensor 转换为具有形状 (complex_shape, 2) 的 real_tensor,然后执行操作而无需调用分配新内存的real()imag()

@dylanbespalko当你问这个问题时我很害怕 :) std::complex保证意味着如果你有数据指针std::complex<float>* ,你可以安全地将它转换成float* (喃喃自语严格混叠),然后将其传递给您正在使用的任何 fft 东西。 如果您只需要实现 fft/var 即可传递此低级代表,那将是最简单的。

但是,如果您需要从字面上将复杂张量重新视为浮点张量,我们就有点麻烦了,因为今天 PyTorch 中没有这方面的先例。 Storage dtype 一直与 Tensor dtype 一致。 因此,如果您制作复杂的存储,则无法将其视为浮动存储。

我的一个想法是也许我们应该放松这个不变量。 这个想法是:

  1. 我们总是将存储分配为有问题的“未矢量化”类型。 所以对于一个复杂的我们分配一个浮点张量。
  2. 允许张量 dtype 与 storage dtype 不一致,但只能作为基础类型的矢量化变体

我不确定我们必须更改多少代码才能使这个不变量发生。

@ezyang

是的,这是不可避免的……

如果您只需要实现 fft/var 即可传递此低级代表,那将是最简单的。

是的,这在很多情况下都是可能的。 您是否能够提供如何将张量数据解释为 std::vector 的代码片段?

但是,如果您需要从字面上重新查看复杂张量作为浮点张量,....

我想很少使用另一种 dtype 来查看张量。 我为Tensor实现了set_dtype()方法,但出现了一些错误。 我也没有更新步幅以反映形状的变化。 我不确定为什么设置 dtype 在 numpy 中起作用(这是巧合吗?),但是当您将数据上传到数模转换器 (DAC) 时,它通常期望实数/虚数数据是交错的。 正如您所建议的那样,也许这会激发将 tensor dtype 与 storage dtype 分离的需要。

我暂时避免这样做。 我确信对我来说还有其他性能瓶颈。

是的,这在很多情况下都是可能的。 您是否能够提供如何将张量数据解释为 std::vector 的代码片段?

不完全是 std::vector,但我在想象这样的事情:

Tensor complex_tensor;
assert(complex_tensor.is_contiguous());
std::complex<float>* cp = complex_tensor.data_ptr<std::complex<float>>();
float* fp = reinterpret_cast<float*>(cp);
auto num_floats = complex_tensor.numel() * 2;

我为 Tensor 实现了 set_dtype() 方法,但出现了一些错误。 我也没有更新步幅以反映形状的变化。

是的,如果您不修复跨步,这可能是个坏主意。 此外,我不是张量转化为其他 dtype 的忠实粉丝; 最好只是不合时宜地做这一切:)

但是,当您将数据上传到数模转换器 (DAC) 时,它通常期望实数/虚数数据是交错的。 正如您所建议的那样,也许这会激发将 tensor dtype 与 storage dtype 分离的需要。

是的,最终这是正确的做法,但我同意现在不这样做更容易。

@ezyang

我开始搞乱复数 CUDA 支持。

有两个二进制兼容选项:

  1. cuComplex : 非常基本的 add、sub、mul、div、real、imag 支持。
  2. 推力::复杂:替代支持主机和设备内存分配的std::complex

推力::复杂容器似乎是要走的路。 Thrust::Complex API建议thrust::complex<T>容器可以分配在主机和设备内存上,而std::complex<T>只能分配在主机内存上:

__host__ __device__     thrust::complex< T >::complex (const complex< T > &z)  //thrust container
__host__    thrust::complex< T >::complex (const std::complex< T > &z) //stl container.
  1. 这是否暗示 AT_DISPATCH_COMPLEX_TYPES 应该设置using scalar_t = thrust::complex<double>而不是using scalar_t = std::complex<double>

  2. Pytorch 如何为真实数据类型自动调用std::log的 CUDA 等效项? 我怎么知道有一个相当于数学内核的 CUDA?

  1. 我认为将thrust::complex<double>普遍用于 CPU 和 CUDA 的困难在于,如果您只构建 CPU,我们实际上并没有针对推力进行构建。 我想有很多选择; 我们可以滚动我们自己的复杂类型(类似于我们滚动自己的半类型),或者您可以重新解释 cast your way to win,因为std::complex<>被定义为具有特定的二进制布局。 这取决于你,但现在重新解释类型之间的转换似乎更容易。
  2. 我们在 THCNumerics.cuh 中有数学重载,这能回答你的问题吗?

@iotamudelta在 #29547 中提出了 C++11 合规性问题

std::real 只是 C++14 中的 constexpr

如果我理解正确, std::real()需要是constexpr以便 hcc 编译器可以编译__device__的指令。

可能的解决方案:

  1. 找到另一种方法或函数将complex<double>转换为double
  1. 找到一种包装函数的方法:

    • 大多数对 std::real 的调用都是在aten/src/ATen/native/cpu/zmath.h中进行的。 示例:将inline替换为constexpr

      inline VALUE_TYPE real_impl (SCALAR_TYPE z) ->
      constexpr VALUE_TYPE real_impl (SCALAR_TYPE z)

      inline std::complex<float> real_impl <std::complex<float>> (std::complex<float> z) -> constexpr std::complex<float> real_impl <std::complex<float>> (std::complex<float> z)

      inline std::complex<float> real_impl <std::complex<double>> (std::complex<float> z) -> constexpr std::complex<float> real_impl <std::complex<double>> (std::complex<float> z)

这不会编译,因为仍然存在对std::real()的嵌套调用,这不是constexpr

3. 如果我使用 std::complex::real() 而不是 std::real() 这似乎符合 C++11。

  1. 我想你是说无论我做什么,这段代码在 C++14 之前都是 UB。 有没有其他方法可以将std::complex<double>转换为double以满足您的要求?

@iotamudelta@bddppq@ezyang

我在 CUDA Thrust::complex API 上添加了对复杂 UnaryOps 和 BinaryOps 的支持,但在提交之前我需要问几个问题。

我定义了一个模板函数,允许您在处理复数时使用thrust::complex 数据类型。
aten/src/ATen/native/cuda/zmath.cuh

#pragma once

#include <complex>
#include <thrust/complex.h>

namespace at { namespace native {
namespace {

template <typename TYPE>
struct ztype_cuda {
  using value_t = TYPE; // Complex template type
  using thrust_t = TYPE; // Equivalent thrust type
};

template <>
struct ztype_cuda<std::complex<float>> {
  using value_t = float;
  using thrust_t = thrust::complex<float>;
};

template <>
struct ztype_cuda<std::complex<double>> {
  using value_t = double;
  using thrust_t = thrust::complex<double>;
};

} // end namespace
}} //end at::native

然后在aten/src/ATen/native/cuda/BinaryOpsKernel.cu
代替:

void add_kernel_cuda(TensorIterator& iter, Scalar alpha_scalar) {
  AT_DISPATCH_ALL_TYPES_AND2(kHalf, kBool, iter.common_dtype(), "add_cuda/sub_cuda", [&]() {
    auto alpha = alpha_scalar.to<scalar_t>();
    gpu_kernel_with_scalars(iter, [alpha]GPU_LAMBDA(scalar_t a, scalar_t b) -> scalar_t {
      return a + alpha * b;
    });
  });
}

和:

void add_kernel_cuda(TensorIterator& iter, Scalar alpha_scalar) {
  AT_DISPATCH_ALL_TYPES_AND_COMPLEX_AND2(kHalf, kBool, iter.dtype(), "add_cuda/sub_cuda", [&]() {
    using thrust_t = typename ztype_cuda<scalar_t>::thrust_t;
    auto alpha = thrust_t(alpha_scalar.to<scalar_t>());
    gpu_kernel_with_scalars(iter, [alpha]GPU_LAMBDA(thrust_t a, thrust_t b) -> thrust_t {
      return a + alpha * b;
    });
  });
}

问题

  1. @ezyang :对于非复数,scalar_t 和thrust_t 是同一类型。 也许我可以将变量名称thrust_t替换为对非复杂数字更友好的名称,例如scalar_t_c
  2. 推力库似乎在代码中被广泛引用:
    a) @bddppq :有什么理由我应该使用cuComplex而不是thrust::complex吗?
    b) @iotamudelta :ROCm2.7 中已删除臀部推力。 我应该改用hip_complex吗?
    推力::complex 似乎支持比cuComplex更多的功能。

请让我知道你在想什么。

@iotamudelta

我更新了关于 std::real() 的讨论。 你能确认 std::complex::real() 将解决问题。

@dylanbespalko

我猜@iotamudelta抱怨的是复杂类型的cast_and_store缺少C10_HOST_DEVICE ,如果该代码路径曾经在 GPU 上执行,这将是一个 UB。

目前,该动态转换工具仅在 GPU TensorIterator 中使用,并且仅在有类型提升时使用。 由于目前 GPU 不支持 complex ,现在复杂类型的cast_and_store没有C10_HOST_DEVICE限定符,并且使用std::real这对于主机来说是完全可以的-唯一的功能。 这里没有UB,因为它没有被使用,没有什么你需要担心的。

但是由于您想向 GPU 添加对复杂的支持,并且类型提升支持复杂,正如我们在https://github.com/pytorch/pytorch/blob/master/c10/core/ScalarType.h#L398中看到的那样 - L420,您需要在此代码路径上非常小心,您可能需要进行一些修改才能使其正常工作:

当然,您需要像@iotamudeltahttps://github.com/pytorch/pytorch/pull/29547中所做的那样添加C10_HOST_DEVICE ,但这还不够,因为只需添加C10_HOST_DEVICE@iotamudelta所述,没有其他更改仍然是 C++11 上的 UB,一个好的解决方案可能就是您提到的:使用std::complex::real()替换std::real

但除此之外,如果您查看文件https://github.com/pytorch/pytorch/blob/master/c10/util/TypeCast.h ,您会在fetch_and_cast中看到类似的内容:

#ifndef C10_HOST_DEVICE
    AT_FORALL_COMPLEX_TYPES(FETCH_AND_CAST_COMPLEX_CASE)
#endif

此代码路径在 GPU 上已禁用。 您需要启用它并使其工作。

此外,我在fetch_and_castcast_and_store中没有看到complex<float>complex<double>之间的任何转换。 您可能还需要为此添加转换。 确保对所有 dtype 的这些功能的覆盖范围进行彻底测试。

抄送: @ezyang@bddppq

还有@dylanbespalko ,如果您在 PR 中对TypeCast.h进行任何更改,请抄送我。

好的,我在 ARM 上用torch.real()torch.imag()修复了一些小问题,所以我会在处理时修复TypeCast.h和其他一些问题。 我会在 PR 上抄送你们。

评论驱动: @smessmer正在将我们转移到 C++14,此时它不会是 UB。 由于这即将到来,如果 UB 没有引起真正的问题,我不会太担心。

@ezyang :很高兴知道。 大多数像 Eigen 这样的第三方东西仍然非常自由地调用std::real()

对于非复数,scalar_t 和thrust_t 是同一类型。 也许我可以用对非复数更友好的名称替换变量名thrust_t,例如scalar_t_c?

我不太确定,但scalar_t_c似乎比thrust_t不太清楚( c到底是什么意思?)这里有问题的类型似乎非常具体,所以最好使用直接谈论意图的名称。

好的,我会坚持使用thrust_t 。 如果有人深入研究ztype_cuda<>() ,他们应该立即发现scalar_t thrust_t

大家好! 看起来在向 pytorch 添加复杂支持方面取得了良好进展! 感谢@dylanbespalko采取主动并添加了 CUDA 支持! 从高层次上看,我很想知道复杂支持的当前进展是什么? 我最感兴趣的是让 CUDA 支持添加和相乘复杂张量(二进制操作)的粗略时间表。 谢谢!

@sunilkpai

我有一个开放的 PR,应该支持 CUDA 上的二元和一元操作:#30295。

另一个问题是反向传播。 我认为复数abs()的导数的定义与实数不同。 不知道该怎么做,但衍生品在tools/autograd/derivatives.yaml中定义

我认为对于复数/dz abs(z) = z/abs(z) 。 这也可以用于实数,但可能会比sgn(z)

@dylanbespalko也许我的报告https://arxiv.org/pdf/1701.00392.pdf中的表 4.1、4.2 和 4.3 可以帮助您定义衍生品。

对于复数导数(wirtinger 演算),有两种选择。
计算 z 或 z 共轭的导数。
我个人更喜欢 wrt z 共轭的导数。
矩阵运算感觉更自然,梯度更新不需要共轭。
它们的定义是:

  • z = x + jy的衍生 wrt z $ : dJ/dz = dJ/dx -j dJ/dy
  • z = x + jy 的衍生 wrt z.conj z = x + jy : dJ/dz.conj = dJ/dx + j dJ/dy

根据您的评论,我的假设是,您现在计算z的导数。
在这种情况下,导数是d abs(z) / d z = z.conj / abs(z) 。 当您采用其他定义时,您可以遵循@Randl 的建议。

让我知道我是否应该解释更多。 对于复杂的导数,我也有一些 numpy 实现。

另一个有用的操作(特别是对于需要复数支持的物理空间中的项目)是exp()操作符的处理程序。 在张量流中,我们有tf.exp(x + iy) = tf.exp(x) * (tf.cos(y) + 1j * tf.sin(y)) 。 这在pytorch中也很容易实现吗?

@sunilkpai@boeddeker@兰德尔

感谢关于复杂衍生品的报告。 我将尝试遵循这一点,我将在下周继续讨论。 我想我会在这里添加一些链接并描述项目状态。

复数的状态是非官方支持的,必须通过 PyTorch 扩展添加:

每个扩展包含两件事:

  • 包含任何必要的数学内核注册的.cpp
  • test/文件夹,其中包含非常简化的 pytorch 测试脚本版本。
    查看测试脚本以了解支持哪些内核(以及为什么不支持其他内核)。

为什么我不能将复杂的张量打印到控制台?

  • Tensor python 对象有一些漂亮的打印格式,可以调用一些不受支持的函数。

    • 您可以修改tensor.py的内容以绕过打印格式。

    • 或者,您可以简单地将 Pytorch 张量转换为 Numpy 数组,然后打印。

当前项目状态:

  • CPU覆盖率相当不错。

    • 内核在 PyTorch 中的 'aten/src/ATen/native/cpu/ </li> <li>Complex number specific code is under 'aten/src/ATen/native/cpu/zmath.h下实现

    • Intel AVX256 加速在 'aten/src/ATen/cpu/vec256/'



      • @sunilkpai :我不知道 exp 的优化。 这是您添加它的文件夹。


      • 让我知道你是否愿意做出改变。



  • GPU 覆盖范围仅限于二元和一元操作:

    • 内核在 PyTorch 中的 'aten/src/ATen/native/cuda/* </li> <li>Complex number specific code is under 'aten/src/ATen/native/cuda/zmath.cuh下实现

    • 使用thrust::complex<T>数据类型,它们包括优化的内核。

目前的发展:

  • 等待基于 C 的 TH 内核被移植到 C++ ATen 文件夹。

    • 需要 rand() 函数将测试用例移植到 pytorch 的内部测试。

    • 某些索引操作当前未移植。

    • 目前有 168/1300 个数学内核(低于 10 月份的 230 个)需要从 TH 移植到 ATen。

  • 随着这些内核在 ATen 中可用,我将尝试添加复数支持。

--

供参考。 关于复杂的衍生品,我们在 Julia 中进行了长时间的讨论,现在它的实现在ChainRules (另见:http://www.juliadiff.org/ChainRules.jl/dev/api.html#ChainRulesCore.Wirtinger)和Zygote . 一般人只需要
\partial L/\partial adjoint(z)作为梯度(根据定义它是下降最快的方向),但是导数与\partial L/\partial z不同,如果我们想要完全支持复数AD,应该添加一个额外的接口. 详细规则可以查看ChainRulesZygote/lib中实现的内容(由于只有通用规则,因此大多数运算符没有单独的复数规则,事物的后向传递像matmul是用通用定义编写的,例如adjoint(A) * B )

为什么我不能将复杂的张量打印到控制台?
Tensor python 对象有一些漂亮的打印格式,可以调用一些不受支持的函数。
您可以修改 tensor.py 的内容以绕过打印格式。
或者,您可以简单地将 Pytorch 张量转换为 Numpy 数组,然后打印。

我想我首先修复了https://github.com/Roger-luo/pytorch-complex中的至少部分打印以进行调试等,不确定这是否会有所帮助,因为主人过去发生了很大变化年。 有帮助的可以采纳,我不做这个了。

@dylanbespalko虽然我已经开始学习,但我对 pytorch 的内部结构相对缺乏经验! 我可以想象尝试这种改变,但根据我在aten/src/ATen/cpu/vec256/*中看到的内容,我不确定是否有必要考虑到 std::exp(std::complex) 的默认行为正是我提到的在我之前的评论中:请参阅https://en.cppreference.com/w/cpp/numeric/complex/exp的注释。 我也不确定这如何转化为在 CUDA 中实现这些操作(目前似乎仅限于 real、imag、conj 和 angle?)。

@sunilkpai

我使用提供的公式添加了对exp()的 AVX 支持。

我还注意到由于 PyTorch 最近的一些变化,有些东西被破坏了。 我已在 #30871 中修复了这些问题。

@dylanbespalko

从 TH 移植到 ATen 是否有时间表?
考虑到我不熟悉 pytorch 的内部工作原理,我有什么办法可以做出贡献吗?

在 arxiv 上找到了一个复杂 svd 反向传播的公式,并且可以实现它,如果你告诉我在哪里

感谢您的工作!

@Jakob-Unfried

https://github.com/pytorch/pytorch/wiki/TH-to-ATen-porting-guide

TH 内核是用 C 实现的,由于所有固有的引用计数问题,人们对在那里添加复杂的支持几乎没有兴趣。 您可以在每个内核注册的aten/src/ATen/native/native_functions.yaml中跟踪进度:

搜索legacy::cpu::_th并将该数字除以 3 以获得旧 TH 内核的数量。
搜索legacy::cpu::_thnn并将该数字除以 3 以获得旧 TH 神经网络内核的数量。

每个内核通常以 3 种不同的方式注册:
1. 正则内核 y = add(a, b)
2. 就地内核 a = add_(a, b)
3. 输出内核add_out(a, b, out=y)
实际的实现总是在输出内核中,另外两个调用该函数。

nn 内核往往更容易移植,因为它们的依赖内核较少。 因此,如果您可以按照与实现方式相反的顺序移植内核,那么您将完成更少的整体工作。

检查移植跟踪问题https://github.com/pytorch/pytorch/issues/24507 ,也抄送@VitalyFedyunin

这是 #32437 中要求的复数支持的状态更新。 我今天回来从事与 CPU 相关的支持工作。

Autograd 支持

  • 我没有太多时间做这件事。
  • angle()real()imag()conj()都已实施。
  • abs()将需要一个单独的复数实现。 (参见上面@boeddeker@Randl的注释)

硬件支持

复数支持目前是在树外实现的。 这是什么意思:

树内代码

  • 数学运算实际上是在树中实现的(在 PyTorch 源代码中)。
  • 没有任何树内 Pytorch 测试验证复数支持(所以事情往往会中断)。
  • PyTorch 正在从 TH 迁移到 ATen (#24507)。
    - 在 TH 中实现的数学内核不支持复数。
    - 只有在 ATen 中实现的内核才能支持复数。
  • 您需要安装 PyTorch 扩展才能启用复杂的 dtype。

树外代码

  • 实现了几个 PyTorch 扩展,并且可以在未来轻松内化:
  • 每个扩展都有四个重要的文件:

    • setup.py:构建和安装 pytorch 扩展。

    • [CPU/CUDA/FPGA]ComplexType.cpp:类似于CPUType.cpp或CUDAType.cpp的数学内核注册

    • test/test_torch.py​​:非常丑陋的测试用例,指示哪些内核正在工作,受 ATen 支持的限制。

    • test/test_autograd.py:测试 autograd 功能。

树外 PyTorch 扩展

  1. cpu_strided_complex
    - [x] 复制内核
    - [] TensorFactories (th_random, th_uniform, th_normal)
    - [x] 范围工厂
    - [x] BinaryOpKernals
    - [x] UnaryOpKernels
    - [x] 比较操作内核
    - [x] PowKernels
    - [x] ReduceOpKernels (th_min, th_max, 一些范数不计算复共轭)
    - [] IndexOpKernels (th_masked_select_bool, th_set, th_gather, th_cat)
    - [x] PointwiseOps
    - [x] Lerp Ops
    - [] BlasOps (th_mv, th_mm, th_fmod, th_eig)
    - [] LinpackOps(使用 Blas)
    - [] SpectralOps(支持,但需要工作)

    1. cuda_strided_complex



      • [x] 复制内核


      • [ ] TensorFactories(参见 cpu 问题)


      • [x] BinaryOpKernals


      • [x] UnaryOpKernels (Todo: add angle, real, imag, conj)


      • []比较OpKernels(待办事项)


      • [] ReduceOpKernels(关于 WARP_SIZE 的错误消息)


      • GPU 变得难以超越逐点计算,但可以支持其他功能



  2. vitis_​​strided_complex

    • Xilinx Vitis 是一个支持服务器和嵌入式设备的 FPGA 高级综合平台。

    • 于 2019 年 10 月发布(可能对设备的支持有限)。

    • 将 SDAccel(服务器)与 VIvado HLS(嵌入式)相结合。

    • [] BinaryOpKernals(一月底)

    • [] UnaryOpKernels(一月底)

    • [ ] ReduceOpKernels(2 月底)。

    • FPGA 最近添加的矢量化对象支持类似于 Vec256 PyTorch 模板类

    • Vec256 是向 CPU 添加复杂支持的方式,它似乎是实现 $C$ 或 $R^N$ 张量空间的更自然方式

关于这个问题的更多更新: https ://github.com/pytorch/pytorch/issues/33152

这可能值得或可能不值得一个单独的问题,但我希望看到并认为在文档中包含一些解释“pytorch 现在如何处理复数”的内容实际上更重要。 aka 可以做加法、乘法、某种规范,不能有复杂的权重等等。所有这些都可以通过几行文档来总结,解释什么是高级预期的当前行为。

这可能值得或可能不值得一个单独的问题,但我希望看到并认为在文档中包含一些解释“pytorch 现在如何处理复数”的内容实际上更重要。 aka 可以做加法、乘法、某种规范,不能有复杂的权重等等。所有这些都可以通过几行文档来总结,解释什么是高级预期的当前行为。

@redwrasse感谢您的反馈! 我们目前有一个关于复数的注释,其中讨论了一些 Torch 基础知识和复杂张量支持的复杂函数
(其中大部分包含在 1.6 版本中) https://pytorch.org/docs/master/complex_numbers.html?highlight=complex。 你能分享你感兴趣的其他功能吗? 很高兴更多地谈论我们当前的支持以及即将发布的版本的计划。

这可能值得或可能不值得一个单独的问题,但我希望看到并认为在文档中包含一些解释“pytorch 现在如何处理复数”的内容实际上更重要。 aka 可以做加法、乘法、某种规范,不能有复杂的权重等等。所有这些都可以通过几行文档来总结,解释什么是高级预期的当前行为。

@redwrasse感谢您的反馈! 我们目前有一个关于复数的注释,其中讨论了一些 Torch 基础知识和复杂张量支持的复杂函数
(其中大部分包含在 1.6 版本中) https://pytorch.org/docs/master/complex_numbers.html?highlight=complex。 你能分享你感兴趣的其他功能吗? 很高兴更多地谈论我们当前的支持以及即将发布的版本的计划。

谢谢@anjali411 ,很高兴看到这个文档,我以前不知道。 我认为需要的是前面和中心几行“对复杂神经网络的支持的当前状态”,但让我来看看它......

对复杂的 autograd 感兴趣的人,您可能对https://github.com/pytorch/pytorch/issues/41857感兴趣,它涉及 PyTorch 将遵循的约定(JAX 或 TF)。

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

miguelvr picture miguelvr  ·  3评论

Coderx7 picture Coderx7  ·  3评论

SeparateReality picture SeparateReality  ·  3评论

soumith picture soumith  ·  3评论

bartolsthoorn picture bartolsthoorn  ·  3评论