NVDLA专题12:具体模块介绍——LUT Programming

11 篇文章 2 订阅

LUT编程

LUT是NVDLA中SDP/CDP的实例,用于模拟神经网络中的非线性函数(Sigmoid/TanH/LRN等。)。我们知道,LUT精度高度依赖于LUT entry和曲线的斜率变化:LUT entry越多,精度越高。另一方面,曲线的斜率变化越大,越难模拟。

值得一提的是,SDP/CDP共享相同的LUT逻辑,它们之间的唯一区别是位深度,因为SDP管道是32位,而CDP管道是37位。

这里提出了一种创新的2级混合LUT架构,通过有限的LUT entry来保持非常高的精度:

该实施方案有两个亮点:

LUT中有两个表(X表\Y表)和两种模式(X表有两种工作模式),典型配置是将其中一个用作原始表以覆盖整个动态范围另一个用作密度表以覆盖一小部分动态范围。由于覆盖范围的差异,原始表具有较低的采样率,而密度表具有相对较高的采样率,这是受LRN/Sigmoid/TanH曲线属性的启发

从上面的图我们可以看出,对于这些函数,只有一小部分具有显著的斜率变化,而其他部分几乎没有太大的变化,因此2级LUT是模拟这些函数的经济选项。

由于密度表和原始表之间可能有重叠,我们有一个可编程的寄存器:“优先级”(pri),当一个样本适合两个表时,允许软件控制哪个LUT表输出应该作为最终输出。当然,建议是一直使用密度输出。

混合工作模式

我们注意到,对于LRN,输入动态范围非常高(0~10^8),但大多数样本都在一个小数据范围内:

上面的直方图是从GoogleNet的“pool1/norm1”层收集的,我们通过不同的x轴坐标系(线性和指数)查看了相同的数据。

我们可以看到,线性(均匀采样)视图将50%以上的样本合并到直方图中的一个点,而指数视图(不均匀采样)将这些样本区分到不同的直方图点,从而提供更好的分辨率。同样的策略可以用于LUT:如果LUT在指数模式下工作,我们对低范围值有很高的采样率,对高范围值有很低的采样率(这是公平的,因为它们在直方图中的频率很低)。这就是“指数”模式的思想。目前,只有X表能够在指数模式下工作,当该模式被启用时,覆盖范围被固定为2^{exp\_start} 2^{exp\_start+tlb\_entry}

下表总结了NVDLA的LUT属性(当映射到硬件时,X/Y用于表示不同的表,X对应于LE(Linear/Exponent,线性/指数),而Y对应于LO(Linear Only, 仅线性)):

典型使用场景的推荐LUT配置:

然而,这不是强制性的,软件可以将LUT编程为以下任何情况(X/Y可以颠倒,这意味着总共6种情况)运行:

如第一张图所示,LUT有几个参数,让我们讨论如何根据不同的模式来配置它们。

指数工作模式

如果LUT正在指数模式下工作,LUT存储有如下示例(实际上,exp_start是可编程的):

假定对于每一个LUT存储,LUT的输入是x{'}=(x-O_{in})*SF_{in{}'},那么索引应该是

这需要乘法器,为了使硬件更简单,我们要求:

然后,硬件只需要右/左移位器来获得正确的索引,然而,也就是:

这可以通过LUT之前的变换器来保证(cdp中的cdp _ in _ cvt;SDP中的X/X/Y乘数)。 上述符号与实际寄存器之间的映射是(X可以是LE/LO):

溢出范围控制

假设一个LUT覆盖范围在[min,max]之间,如果一个输入样本大于max或小于min,我们称之为超范围样本。 NVDLA支持对这些超范围样本进行线性插值。插值的数学公式为(x是输入样本值):

从硬件的角度来说,插值是

以下溢为例,给定(2^M是应用于LUT输入的缩放,SF是应用于LUT entry的缩放):

硬件输出为:

进而

上述公式中的符号与寄存器之间的映射为:

LUT存储编程

通常来说,为了对LUT entry进行编程,必须指定LUT entry地址及其值,这需要2次寄存器写操作。NVDLA通过引入硬件自动地址递增机制简化了这一过程,这意味着,当你需要对LUT表进行编程时,你只需编写如下代码(以LE表程序为例):

/* program raw table */
reg = (FIELD_ENUM(S_LUT_ACCESS_CFG, LUT_TABLE_ID, LE) << SHIFT(S_LUT_ACCESS_CFG, LUT_TABLE_ID)) |
      (FIELD_ENUM(S_LUT_ACCESS_CFG, LUT_ACCESS_TYPE, WRITE) << SHIFT(S_LUT_ACCESS_CFG, LUT_ACCESS_TYPE));
reg_write(S_LUT_ACCESS_CFG, reg);
for(i = 0; i < LUT_LE_TABLE_ENTRIES; i++) {
    reg_write(S_LUT_ACCESS_DATA, lut->le_table[i]);
}

如果地址超出了总的LUT entry(例如:上述伪代码中的LUT_RAW_TABLE_ENTRIES超出了实际的LUT entry),则硬件行为是未定义的。

NVDLA支持从任意入口读回已编程的LUT entry。LUT访问CFG只需要编程一次,地址就会自动增加。请注意,对于LUT读取的情况,S_LUT_ACCESS_CFG的编程必须是非后写的;

LUT编程有两个限制:

  • 确保总是从第一个entry开始写LUT,并更新整个表;
  • 对于两个寄存器组只有一个共享的LUT存储,确保当相应的子单元空闲时更新LUT;

命中/未命中行为

对于给定的输入样本,如果只命中一个表,最终输出将是命中表的输出;然而,X/Y表编程非常灵活,因此会导致不同的命中/未命中情况:

  1. 一个输入样本可能在两个表中都被命中;(case1)
  2. 由于溢出,一个输入样本可能在两个表中都丢失;(case1、2、3)
  3. 由于下溢,一个输入样本可能在两个表中都丢失;(case1、2、3)
  4. 由于一个表溢出而另一个表下溢,一个输入样本可能在两个表中都丢失(case3)

对于上述所有情况,硬件需要一种方法来选择如何获得最终输出,因此我们在下面公开了可编程寄存器,以允许软件对优先级进行编程:

LUT统计

当一个硬件层完成时,硬件将在下面报告统计数据,以帮助软件了解LUT表是否被合理编程。

对于每个寄存器组,我们在上面有专用的统计寄存器,当一个硬件完成时,这些计数器将可供读取(通过将生产者指针设置到该寄存器组)。在启用相应的寄存器组(op_en被置位)之前,这些统计数据不会被擦除。

end

  • 32
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值