Skip to content

Commit

Permalink
Update docs, use ## instead of ##### and misc changes
Browse files Browse the repository at this point in the history
  • Loading branch information
daquexian committed Jun 4, 2019
1 parent a9b0a33 commit bda0bce
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 21 deletions.
10 changes: 4 additions & 6 deletions docs/bconv_CN.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
#### 二值卷积实现

##### Bit-packing
## Bit-packing
在执行二值卷积之前,网络需要手动插入一层`Binarize`。是指将 N 个 32 位的 float/integer,根据和 0 的大小关系,二值化为 N 个 bit (即 0 或 1),并打包成一个 N-bit 的整体,例如对 128 个浮点数进行 bit-packing 之后,就会产生一个 128-bit 的操作数。这一步叫做 bit-packing,做了这一步,后续才可以进行位运算 xnor/xor。

Bit-packing 的具体实现在
Expand All @@ -10,15 +8,15 @@ Bit-packing 的具体实现在

高优化版和低优化版的性能差距在 4 倍左右。在高优化版中,bit-packing 算法直接利用 IEEE 754 float 和 int32 的符号位,而不需要把每一个数都和 0 比较,并使用了 SIMD 指令加速这一算法。值得一提的是,使用 SIMD 指令进行 bit-packing 后,输出的 N-bit 操作数的 N 个 bit 和 N 个输入不是按顺序对应的,但只要 xnor/xor 的两个操作数的每个 bit 一一对应,就不会对运算产生任何影响,因此,在适用高优化 bit-packing 的场景下,我们会对 weight 进行重排,使它的每个 bit 和 input 的每个 bit 一一对应,这一步的具体代码在 https://github.com/JDAI-CV/dabnn/blob/master/dabnn/net.cpp#L82。

卷积实现有很多种办法,dabnn 提供了两种优化实现
卷积实现有很多种办法,dabnn 提供了如下两种优化实现

##### BGEMM
## BGEMM

GEMM 是实现浮点卷积的通用方法。它要求先用 [im2col](https://github.com/JDAI-CV/dabnn/blob/master/dabnn/im2col.h) 重排输入,经过 im2col 之后,卷积即可被表示为矩阵和矩阵的乘法,即 GEMM。GEMM 的加速方法在 CNN 火热起来之前,就已经得到了深入的研究。不过在二值卷积中,不能利用已有的 GEMM 库,因为它们是为 double、float 或 integer 准备的,因此 dabnn 实现了 BGEMM (Binary GEMM)。它的优点是性能不低,实现方便,一套 GEMM 代码即可处理所有的情况。

BGEMM 的具体实现在 https://github.com/JDAI-CV/dabnn/blob/master/dabnn/bgemm.h。

##### Binary Direct Convolution
## Binary Direct Convolution

然而 BGEMM 在 ARM 设备上并不高效,因为二值乘-加操作中,加法需要两步 - bitcount 和普通的加法。Bitcount 用来得到一个 N-bit 操作数中有多少 bit 是 1。在 ARMv8 设备上,bitcount 需要两条指令,ARMv7 设备上需要更多条指令。这大大限制了 BGEMM 的速度。因此 dabnn 提出了直接卷积的方法,称为 Binary Direct Convolution (BDC),它是指直接按照卷积的定义来计算卷积。在 BDC 中,通过一个简单的变换,大部分 bitcount 指令会被消除。它的优点是性能比 BGEMM 更高,但不能像 BGEMM 一样用一套代码覆盖所有的情况。

Expand Down
10 changes: 5 additions & 5 deletions docs/design_CN.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#### 背景和发展方向
## 背景和发展方向

二值网络比较年轻,最初的两篇文章是 2016 年的 [Binary Neural Networks](https://arxiv.org/abs/1602.02830)[XNOR-Net](https://arxiv.org/abs/1603.05279)。后续的工作中,[Bi-Real Net](https://arxiv.org/abs/1808.00278) 提出了一些精度提升方法,[BENN](https://arxiv.org/abs/1806.07550v2) 用 ensemble 方法进一步提升了 BNN 在分类任务上的表现,结果甚至超过单精度浮点模型。

Expand All @@ -12,9 +12,9 @@
卷积曾出现过很多变种,但是其中大部分已被历史淘汰。BNN 要想避免此命运,最简单的方法莫过于尽快落在某个产品或项目上,证明自己的价值。


#### 软件架构
## 软件架构
在使用流程和软件结构方面,dabnn 和已开源的推理库(如 [ncnn](https://github.com/Tencent/ncnn)[Tengine](https://github.com/OAID/Tengine)[FeatherCNN](https://github.com/Tencent/FeatherCNN) 等)差距不大:

1. 模型训练可使用任意一种可以导出 ONNX 模型的框架,但需要注意的是,二值卷积是自定义操作,为了让模型中二值卷积可以被 dabnn 正确识别,需要了解 [onnx2bnn 的几种识别模式]。一个 dabnn 官方提供的 PyTorch 实现在 [这里](https://gist.github.com/daquexian/7db1e7f1e0a92ab13ac1ad028233a9eb)
1. 部署模型前需要把 onnx 格式转换成 dabnn 内部格式。在转换过程中,会把二值卷积的权重转换为 1-bit (而不是默认的 32-bit),大大减小模型文件的体积。流程和**注意事项**可参照 [onnx2bnn_CN.md](onnx2bnn_CN.md)
3. 二值卷积实现请查阅 [bconv_CN.md](bconv_CN.md)
1. 模型训练可使用任意一种可以导出 ONNX 模型的框架,但需要注意的是,二值卷积是自定义操作,为了让模型中二值卷积可以被 dabnn 正确识别,请看 [onnx2bnn_CN.md](docs/onnx2bnn_CN.md)
1. 部署模型前需要把 onnx 格式转换成 dabnn 内部格式。在转换过程中,会把二值卷积的权重转换为 1-bit (而不是默认的 32-bit),大大减小模型文件的体积。流程和**注意事项**可参照 [onnx2bnn_CN.md](docs/onnx2bnn_CN.md)
3. 二值卷积实现请查阅 [bconv_CN.md](docs/bconv_CN.md)
20 changes: 10 additions & 10 deletions docs/onnx2bnn_CN.md
Original file line number Diff line number Diff line change
@@ -1,31 +1,31 @@
## 关于 ONNX

ONNX (Open Neural Network Exchange) 是一个独立于训练框架的模型格式,[众多框架和工具](http://onnx.ai/supported-tools) 支持 ONNX 格式。

#### 模型转换流程
## 模型转换流程

1. 识别二值卷积,对二值卷积的 weight 进行 bit-packing。dabnn 开发者给 onnx 增加了多个 optimizer,用来识别二值卷积,具体实现可参考 https://github.com/daquexian/onnx/tree/optimizer_for_bnn/onnx/optimizer/passes 中的 dabnn_*.h。关于 bit-packing 可以参考 [这篇文档](docs/bconv_CN.md);

1. 修改紧跟着二值卷积的 BN 层的权重。因为 bit 只有 1 和 0 两个值,所以二值卷积中的 -1 被用 0 表示,bitcount 可以得到一个 N-bit 操作数中,值为 1 的 bit 的数量,这忽略了 -1 的存在。具体来说,设 a 为一个 N-bit 操作数,b 为一个自然数,且

> b = bitcount(a)
1. 修改紧跟着二值卷积的 BN 层的权重。因为 bit 只有 1 和 0 两个值,所以二值卷积中的 -1 被用 0 表示,bitcount 可以得到一个 N-bit 操作数中,值为 1 的 bit 的数量,这忽略了 -1 的存在。具体来说,设 a 为一个 N-bit 操作数,b 是 a 中值为 1 的 bit 数量,c 是 a 中值为 0 的 bit 数量(即 -1 的数量)

实际上我们应该得到的值是
在计算卷积时,我们应该得到的值是

> c = bitcount(a) - (N - bitcount(a)) = 2 * bitcount(a) - N = 2 * b - N
> b - c = b - (N - b) = 2 * b - N = 2 * bitcount(a) - N
这个值可以经过一个对 b 的线性变换得到,因此我们将这个变换融合进二值卷积之后的 BN 层之中。
这个值可以经过一个对 bitcount(a) 的线性变换得到,因此我们将这个变换融合进二值卷积之后的 BN 层之中。

具体实现在 https://github.com/JDAI-CV/dabnn/blob/master/tools/onnx2bnn/OnnxConverter.cpp#L530。

1. 其他 Layer 正常处理。

#### 注意事项(必看)
## 注意事项(必看)

模型转换过程中有些规则或限制需要额外说明。

1. **二值卷积的输入 channel 暂时需要是 128 的倍数或 64**

1. 二值卷积是自定义操作,因此可能存在多种实现,网上存在的二值卷积的自定义实现几乎全部是错的,例如它们用 0 进行 pad,而忽略了二值卷积的输入只能有 +1 和 -1。dabnn 开发者提供了一个[标准的二值卷积 PyTorch 实现](https://gist.github.com/daquexian/7db1e7f1e0a92ab13ac1ad028233a9eb),我们建议所有二值网络的训练者使用这个实现,或是按照这个实现来在他们用的训练框架中自行实现二值卷积
1. 二值卷积是自定义操作,因此可能存在多种实现,网上存在的二值卷积的自定义实现几乎全部是错的,例如它们用 0 进行 pad,而忽略了二值卷积的输入只能有 +1 和 -1。dabnn 开发者提供了一个[标准的二值卷积 PyTorch 实现](https://gist.github.com/daquexian/7db1e7f1e0a92ab13ac1ad028233a9eb),我们建议所有二值网络的训练者使用这个实现,或是按照这个实现来在他们用的训练框架中自行实现二值卷积

1. onnx2bnn 有多种针对二值卷积的识别模式,例如会根据卷积的权重(是否为 +1/-1)识别、根据 Sign operator 识别,在用户选择 aggressive 模式时,甚至可以识别上一条所述的非正确的二值卷积(但在运算时仍会以 -1 而不是 0 来 pad,因此会导致结果不完全一致)。具体请看 [这篇文档](https://github.com/JDAI-CV/dabnn/wiki/Train,-export-and-convert-a-dabnn-model)
1. onnx2bnn 有多种针对二值卷积的识别模式,例如会根据卷积的权重(是否为 +1/-1)识别、根据 Sign operator 识别,在用户选择 aggressive 模式时,甚至可以识别上一条所述的非正确的二值卷积(但在运算时仍会以 -1 而不是 0 来 pad,因此会导致结果不完全一致)。具体请看 [这篇文档](https://github.com/JDAI-CV/dabnn/wiki/Train,-export-and-convert-a-dabnn-model)

1. 目前暂时不支持 `group` 参数。

0 comments on commit bda0bce

Please sign in to comment.