常数整数乘法优化

news2024/11/19 17:50:23

常数整数乘法优化

文章目录


嵌入式机器学习或深度学习算法中很大一部分运算涉及常数乘法:

  • 神经网络的卷积层和全连接层将来自前一层的数据和固定的权重矩阵相乘计算输出,SVM算法中通过固定的矩阵和向量乘法计算判决函数
  • 图像处理中各种滤波器算法也需要计算图像数据和固定的滤波器核的二维卷积

基于正则有符号数的常数整数乘法优化

就是通过移位加减法实现常数乘法的优化

常数乘法分为:

  1. 单常数乘法 SCM —— Single Contant Multipilication
  2. 多常数乘法 MCM —— Multiple Constants Multiplication

Example 1: 20 x 20x 20x

20 = ( 10100 ) 2 = ( 10000 ) 2 + ( 100 ) 2 = 2 4 + 2 2 20=(1 0100)_2=(10000)_2+(100)_2=2^4+2^2 20=101002=(10000)2+(100)2=24+22

因此 20 x 20x 20x乘积可表示为
20 x = ( 2 4 + 2 2 ) x = 2 4 x + 2 2 x 20x=(2^4+2^2)x=2^4x+2^2x 20x=(24+22)x=24x+22x
对于整数 x ,上述运算进一步表示为
20 x = ( x ≪ 4 ) + ( x ≪ 2 ) 20x = (x≪4)+(x≪2) 20x=(x4)+(x2)
不难发现:加法次数和二进制形式中的1的个数有关

Example 2: 153 x 153x 153x

153 x = ( 10011001 ) 2 x 153x = (1001 1001)_2 x 153x=(10011001)2x

153 x = ( x ≪ 7 ) + ( x ≪ 4 ) + ( x ≪ 3 ) + x 153x=(x≪7)+(x≪4)+(x≪3)+x 153x=(x7)+(x4)+(x3)+x

需要进行3次加法,还能简化吗?

可以的。
153 = ( 10011001 ) 2 153=(1001 1001)_2 153=(10011001)2

= > 153 x = 10010000 x + 1001 x => 153x = 10010000x + 1001x =>153x=10010000x+1001x

令 y = x × ( 1001 ) 2 令 y=x×(1001)_2 y=x×(1001)2

153 x = y + y ≪ 4 153x = y + y ≪ 4 153x=y+y4
仅需要2次加法

Example 3: 15 x 15x 15x

15 = ( 1111 ) 2 15=(1111)_2 15=11112

15 x = x ≪ 3 + x ≪ 2 + x ≪ 1 + x 15x=x≪3+x≪2+x≪1+x 15x=x3+x2+x1+x

这还不是最优的,重新分解15
15 = ( 10000 ) 2 − ( 1 ) 2 15=(10000)_2−(1)_2 15=(10000)2(1)2

15 x = x ≪ 4 − x 15x=x≪4−x 15x=x4x
因此,定义新的“有符号二进制形式”:
15 = ( 1000 1 ˉ ) 2 = 2 4 − 2 0 15=(1 000\bar{1})_2=2^4−2^0 15=10001ˉ2=2420

正则有符号数编码 CSD

将有符号整数转换为非0位最少的“有符号二进制序列”,这一序列成为 CSD:Canonical Signed Digit

为了尽可能降低常数乘法的运算量,我们希望找出非 0 位尽可能少的有符号二进制序列表示给定的常数。

对于无符号整数的二进制形式,从低位开始扫描,把所有长度大于2的连续1位串替换成 100 ⋅ ⋅ ⋅ 0 1 ˉ 100···0\bar{1} 100⋅⋅⋅01ˉ

例如 十进制 15 599,二进制为11 1100 1110 1111,可以转换为 $ 1000\bar{1}01000\bar{1}000\bar{1}$

因此,可以实现乘法优化:
x × ( 11110011101111 ) 2 = x × ( 1000 1 ˉ 01000 1 ˉ 000 1 ˉ ) 2 x×(11110011101111)_2=x×(1000\bar{1}01000\bar{1}000\bar{1})_2 x×(11110011101111)2=x×(10001ˉ010001ˉ0001ˉ)2

= x ≪ ( 14 − x ) ≪ ( 10 + x ) ≪ ( 8 − x ) ≪ ( 4 − x ) =x≪(14−x)≪(10+x)≪(8−x)≪(4−x) =x(14x)(10+x)(8x)(4x)

二进制序列转CSD编码算法流程

  1. 设置
    { b − 1 = 0 b N = b N − 1 γ − 1 = 0 \begin{cases} b_{-1} = 0 \\ b_N = b_{N-1} \\ \gamma_{-1} = 0 \end{cases} b1=0bN=bN1γ1=0

执行下面的循环 伪代码
f o r ( i = 1   t o   N − 1 ) for (i =1 \ to \ N-1) for(i=1 to N1)
{ \{ {

θ i = b i   ⨁ b i − 1 \theta_i = b_i \ \bigoplus b_{i-1} θi=bi bi1

$$
\gamma_i = (1 - \gamma_{i-1})\theta_{i}

$$

a i = ( 1 − 2 b i + 1 ) γ i a_i = (1-2b_{i+1})\gamma_i ai=(12bi+1)γi

} \} }

代码实现

import numpy as np

####################
# 生成二进制数的CSD表示
####################

## 将二进制字串(整数,无'0b'前缀)转成字典
# 代码清单 4-20
def bin_str_to_dict(bv): return {n:int(v=='1') for n,v in enumerate(bv[::-1])}

## 将二进制字串(整数)转成CSD表示
def bin_str_to_csd(bv):    
    w=len(bv)
    b=bin_str_to_dict(bv)
    b[-1]=0
    b[w]=b[w-1]
    gamma={-1:0}
    a={}
    theta={}
    for i in range(w):
        theta[i]=b[i]^b[i-1]
        gamma[i]=(1-gamma[i-1])*theta[i]
        a[i]=(1-2*b[i+1])*gamma[i]
    return a

## 将16-bit整数表示为二进制字串,用补码表示负数
def int16_to_bin_str(v):
    if v<0: v+=65536
    bv=bin(v)[2:]
    return '0'*(16-len(bv))+bv

## 将16-bit有符号整数转成CSD表示
def int16_to_csd(v):
    bv=int16_to_bin_str(v)
    csd=bin_str_to_csd(bv)
    return csd

## 将字典转回16-bit整数
def dict_to_int16(d): 
    v=sum([(2**k)*v for k,v in d.items()])
    if v>32767: v-=65536
    return v 

## 将字典内容打印成二进制字串
def dict_to_str(d):
    s=''
    for n in range(max(d.keys())+1):
        if n in d:
            s={-1:'n',0:'0',1:'1'}[d[n]]+s
        else:
            s='x'+x
    return s[::-1]

## 将CSD内容转成移位运算指令字符串
# 代码清单 4-21
def csd_to_code(csd):
    s=''
    for n,v in csd.items():
        if v==0: 
            continue
        elif n==0:
            s+='+x' if v>0 else '-x'
        else:
            s+='+(x<<%d)'%n if v>0 else '-(x<<%d)'%n
    return  s[1:] if s[0]=='+' else s

## 将16-bit有符号整数转成移位运算指令字符串
def int16_to_code(v):
    return csd_to_code(bin_str_to_csd(int16_to_bin_str(v)))
    
####################
# 单元测试
####################
if __name__=='__main__':
    print('\n[Randy] ---- test 1 ----')
    bv=int16_to_bin_str(-141)
    print('[Randy] bv:\n    ',bv)

    d=bin_str_to_dict(bv)
    print('[Randy] d=bin_str_to_dict(bv):\n    ',d)

    v=dict_to_int16(d)
    print('[Randy] v=dict_to_int16(d):\n    ',v)

    csd=bin_str_to_csd(bv)
    print('[Randy] csd                :\n    ',csd                )
    print('[Randy] dict_to_str(csd)   :\n    ',dict_to_str(csd)   )
    print('[Randy] dict_to_int16(csd) :\n    ',dict_to_int16(csd) )
    print('[Randy] csd_to_code(csd)   :\n    ',csd_to_code(csd)   )
    print('[Randy] int16_to_code(-141):\n    ',int16_to_code(-141))
    

    # test2
    print('\n[Randy] ---- test 2 ----')
    bv=int16_to_bin_str(141)
    print('[Randy] bv:\n    ',bv)

    d=bin_str_to_dict(bv)
    print('[Randy] d=bin_str_to_dict(bv):\n    ',d)

    v=dict_to_int16(d)
    print('[Randy] v=dict_to_int16(d):\n    ',v)

    csd=bin_str_to_csd(bv)
    print('[Randy] csd               :\n    ',csd               )
    print('[Randy] dict_to_str(csd)  :\n    ',dict_to_str(csd)  )
    print('[Randy] dict_to_int16(csd):\n    ',dict_to_int16(csd))
    print('[Randy] csd_to_code(csd)  :\n    ',csd_to_code(csd)  )
    print('[Randy] int16_to_code(141):\n    ',int16_to_code(141))

    # test3
    print('\n[Randy] ---- test 3 ----')
    for v in range(-32768,32768):
        csd=int16_to_csd(v)
        v1=dict_to_int16(csd)
        if v%10000==0:
            print('[Randy] %d'%v)
        if v!=v1: 
            print('[ERR] %d,%d'%(v,v1))
            print('[ERR]    ',bv)
            print('[ERR]    ',dict_to_str(csd))

结果:

[Randy] ---- test 1 ----
[Randy] bv:
     1111111101110011
[Randy] d=bin_str_to_dict(bv):
     {0: 1, 1: 1, 2: 0, 3: 0, 4: 1, 5: 1, 6: 1, 7: 0, 8: 1, 9: 1, 10: 1, 11: 1, 12: 1, 13: 1, 14: 1, 15: 1}
[Randy] v=dict_to_int16(d):
     -141
[Randy] csd                :
     {0: -1, 1: 0, 2: 1, 3: 0, 4: -1, 5: 0, 6: 0, 7: -1, 8: 0, 9: 0, 10: 0, 11: 0, 12: 0, 13: 0, 14: 0, 15: 0}
[Randy] dict_to_str(csd)   :
     n010n00n00000000
[Randy] dict_to_int16(csd) :
     -141
[Randy] csd_to_code(csd)   :
     -x+(x<<2)-(x<<4)-(x<<7)
[Randy] int16_to_code(-141):
     -x+(x<<2)-(x<<4)-(x<<7)

[Randy] ---- test 2 ----
[Randy] bv:
     0000000010001101
[Randy] d=bin_str_to_dict(bv):
     {0: 1, 1: 0, 2: 1, 3: 1, 4: 0, 5: 0, 6: 0, 7: 1, 8: 0, 9: 0, 10: 0, 11: 0, 12: 0, 13: 0, 14: 0, 15: 0}
[Randy] v=dict_to_int16(d):
     141
[Randy] csd               :
     {0: 1, 1: 0, 2: -1, 3: 0, 4: 1, 5: 0, 6: 0, 7: 1, 8: 0, 9: 0, 10: 0, 11: 0, 12: 0, 13: 0, 14: 0, 15: 0}
[Randy] dict_to_str(csd)  :
     10n0100100000000
[Randy] dict_to_int16(csd):
     141
[Randy] csd_to_code(csd)  :
     x-(x<<2)+(x<<4)+(x<<7)
[Randy] int16_to_code(141):
     x-(x<<2)+(x<<4)+(x<<7)

[Randy] ---- test 3 ----
[Randy] -30000
[Randy] -20000
[Randy] -10000
[Randy] 0
[Randy] 10000
[Randy] 20000
[Randy] 30000

欢迎关注公众号【三戒纪元】

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/543039.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

人工智能的机器人技术为啥那么强,对于未来意味着什么?

前言 人工智能技术的发展&#xff0c;推动了机器人技术的不断进步。机器人技术在工业、医疗、服务等领域发挥着越来越重要的作用。本文将详细介绍人工智能的机器人技术。 机器人技术的发展历程 机器人技术的发展可以追溯到20世纪50年代。当时&#xff0c;机器人主要用于工业生…

怎么给移动硬盘查错?移动硬盘查错能恢复数据吗

移动硬盘在长期使用或使用不当的情况下&#xff0c;可能会出现硬盘文件损坏或者出现坏道等问题&#xff0c;影响数据安全和文件操作。这时候&#xff0c;移动硬盘查错工具就派上用场了。它可以帮助用户发现移动硬盘中的问题&#xff0c;并且还可以对移动硬盘进行修复。 但是&a…

chatgpt赋能Python-python3_7怎么改颜色

Python3.7中如何改变颜色的方法 Python是一门广泛应用于各种领域的编程语言&#xff0c;其强大的数据分析能力和简单易用的语法得到了越来越多的开发者的青睐。在Python中&#xff0c;要想使文本在输出时带有颜色&#xff0c;可以使用ANSI转义序列进行操作。 什么是ANSI转义序…

国考省考行测:数量关系,消三法,比,分数,百分数,n倍

国考省考行测&#xff1a; 2022找工作是学历、能力和运气的超强结合体! 公务员特招重点就是专业技能&#xff0c;附带行测和申论&#xff0c;而常规国考省考最重要的还是申论和行测&#xff0c;所以大家认真准备吧&#xff0c;我讲一起屡屡申论和行测的重要知识点 遇到寒冬&am…

spring数据校验:Validation

目录 Spring Validation概述 通过Validator接口实现 Bean Validation注解实现 基于方法实现校验 实现自定义校验 Spring Validation概述 在开发中&#xff0c;我们经常遇到参数校验的需求&#xff0c;比如用户注册的时候&#xff0c;要校验用户名不能为空、用户名长度不超…

从眼中窥视:Google AI 模型如何通过眼睛预测你的年龄

新的模型可以通过分析眼部照片揭示衰老的秘密 近年来&#xff0c;谷歌一直在研究各种人工智能模型&#xff0c;可以分析眼睛&#xff08;内部和外部&#xff09;的图像并监测某些参数。正如之前提到的&#xff0c;开发能够从眼睛中提取信息的 AI 模型意味着能够以经济高效和无创…

Array-Deque-Queue等的区别

&#x1f50e;Deque&#xff08;双端队列&#xff09;: Deque 是 “double-ended queue” 的缩写&#xff0c;表示双端队列。它是一种可以在两端进行插入和删除操作的数据结构。你可以在队列的头部和尾部同时进行插入和删除操作。Deque 接口定义了这些操作的方法&#xff0c;如…

国际博物馆日|科技与文化的碰撞:大势智慧助力博物馆赋能美好生活

近年来&#xff0c;我国博物馆事业蓬勃发展&#xff0c;而科技与文博领域的深度融合&#xff0c;将继续成为博物馆事业高质量发展的助推器。作为连接过去、现在、未来的桥梁和新时代文化交流与传播的窗口&#xff0c;博物馆不仅是保护和传承人类文明的重要殿堂&#xff0c;也是…

网络优化干扰培训讲解

一、系统外干扰 1、信号放大器 1、特征&#xff1a;RB尖峰突起(类似于互调干扰&#xff0c;极少数会形成宽频干扰。信号放大器为目前FDD频段主要干扰源 2、影响范围&#xff1a;周边站点 3、干扰来源&#xff1a;用户私装信号放大器、黑直放站. 4、原因分析&#xff1a;放…

javaIO流之字节流

目录 1、字节输出流&#xff08;OutputStream&#xff09;2、FileOutputStream类2.1FileOutputStrea 的构造方法2.2FileOutputStream 写入字节数据2.3FileOutputStream实现数据追加、换行 3、字节流入流&#xff08;InputStream&#xff09;4、FileInputStream类4.1FileInputSt…

介绍自己的产品时,常犯的那些错

最近的一个轻咨询客户&#xff0c;在“全面提升组织产品能力”的项目中&#xff0c;正处于内部自学的“读书会”环节。 为了“用以致学”&#xff0c;而不是“学以致用”地读书&#xff0c;我给他们出了一道看起来很简单的题——介绍一下自己手头正在负责的产品。 前几天&#…

Java枚举

Java枚举 &#x1f37a;1 背景及定义&#x1f37a;&#x1f9c3;2 使用&#x1f9c3;&#x1f964;3 枚举优点缺点&#x1f964;&#x1f375;4 枚举和反射&#x1f375;&#x1f377;4.1 枚举是否可以通过反射&#xff0c;拿到实例对象呢&#xff1f;&#x1f377; ☕️5 总结…

正负压力精密控制在隐形牙齿矫正器成型机中的应用

摘要&#xff1a;真空压力热成型技术作为一种精密成型工艺在诸如隐形牙套等制作领域得到越来越多的重视&#xff0c;其主要特点是要求采用高精度的正负压力控制手段来抵消重力对软化膜变形的影响以及精密控制成型膜厚度。本文提出了相应的改进解决方案&#xff0c;通过可编程的…

Greenplum数据库系统架构

Greenplum数据库系统架构 Greenplum是一个纯软件的MPP数据库服务器&#xff0c;其系统架构专门用于管理大规模分析型数据仓库或商业智能工作负载。从技术上讲&#xff0c;MPP无共享架构是指具有多个节点的系统&#xff0c;每个节点都有自己的内存、操作系统和磁盘&#xff0c;…

【天线专题】天线(Antenna)的理解

天线,英文名称是(Antenna),本义是指像蚂蚁、蜜蜂这样的小动物头顶上的触角。天线的作用就是将调制到射频频率的数字信号或模拟信号发射到空间无线信道,或从空间无线信道接收调制在射频频率上的数字或模拟信号。简单来说就是有发射和接收电磁波的功能。 所以两只蚂…

chatgpt赋能Python-python3_5怎么用

Python 3.5是什么? Python是一种高级编程语言&#xff0c;非常流行并广泛使用。Python3.5是Python编程语言的一个较新的版本&#xff0c;它具有许多新的功能和改进。Python 3.5已包含许多流行的Python框架。它可以用于各种任务&#xff0c;例如web开发&#xff0c;数据科学&a…

StableDiffusion模型发展历史

参考资料&#xff1a; 相应的github和huggingface LDM [github] StableDiffusion v1.1 ~ v1.4 [github] [huggingface] StableDiffusion v1.5 [huggingface] [github] StableDiffusion v2 v2.1 [github] [huggingface]   首先说一下&#xff0c;这篇文章的目的是让你清晰地了…

Django SQL注入漏洞 CVE-2022-28347

漏洞简介 在Django 2.2 的 2.2.28 之前版本、3.2 的 3.2.13 之前版本和 4.0 的 4.0.4 之前版本中的 QuerySet.deexplain() 中发现了SQL注入问题。这是通过传递一个精心编制的字典&#xff08;带有字典扩展&#xff09;作为**options参数来实现的&#xff0c;并将注入负载放置在…

[golang gin框架] 36.Gin 商城项目-RESTful API 设计指南,允许Cros跨域 ,提供api接口实现前后端分离,以及JWT的使用

一.RESTful API 设计指南 请看:Restful API 的接口规范 二.Gin 中配置服务器端允许跨域 github官方地址: https://github.com/gin-contrib/cors 在 main.go文件中配置跨域请求 代码如下: 在使用cors时,需要 引入该插件,先: import ( "github.com/gin-contrib/cors" )…

Cocos CreatorXR 1.2.0 今日发布,正式支持 WebXR ,并开启 MR 之路

去年九月&#xff0c;Cocos CreatorXR v1.0.1 版本支持了 VR 内容创作&#xff0c;成为率先支持 XR 的国产引擎&#xff0c;今年三月&#xff0c;Cocos CreatorXR v1.1.0 版本实现了对 AR 内容开发的支持。在完成基本功能的建设后&#xff0c;更多开发者开始尝试使用 Cocos Cre…