多种方式实现Sigmoid函数导数的仿真(含代码)

本文详细介绍了四种Sigmoid函数导数的仿真方法,包括基于与或非门的方法、迭代直线逼近法、直接计算法以及简单的移位法。作者通过比较性能和误差,最终提出了改进的128段线方法,适用于CNN硬件实现。
摘要由CSDN通过智能技术生成

综述

这一周所有的空闲时间就是完成了Sigmoid函数的导数的仿真,用了总共四种方法,并对他们的性能进行了对比。并最后找到了自己的方法,想用于将来的CNN硬件代码当中。基本所有的方法都比较简单,原理我就只是大概得说一说,文章的最末尾会提供相关的参考文献(有代码了还需要其他的吗?)

方法一

在我的上面的一篇博文中介绍了一种只是用与或非门的仿真sigmoid函数的方法,下面提供了我上一篇文章的链接:[http://blog.csdn.net/xjtu_noc_wei/article/details/52886727]
这种方法可以非常快速的知道sigmoid函数的输出,然后我们可以利用sigmoid函数的特有关系即:y’=y(1-y)即可算出结果,怎么样是不是很简单呢?但是这种方法不好的地方是最后的时候使用了乘法器,然后老师就把我这个工作pass了,其实已经挺快了。直接写代码吧,二进制转换成十进制的代码我上个博文已经给出,这里直接给出核心代码:

function sig3_3_6p()
%%因为是一个小数点后面三位的二进制数
%那么000.000到111.111可以用一个十进制的最小值为0最大值为7.875,步长为0.125的数组进行表示
%v=-7.875:0.125:7.875
x=0:0.125:7.875;
m=0:-0.125:-7.875;
%fx= 1 ./ (1 + exp(- x));
fx=exp(-x)./(1+exp(-x)).^2;
%画出理想的sig函数图片
n=cell(1,size(x,2));%建立大小和x相同的胞元将数组或者数存到胞元里面
t=cell(1,size(x,2));
y=zeros(1,size(x,2));
for i=1:1:64
    [~,n{i},t{i}]=change(x(i),3);
    %如果直接进行取值的话得到的结果是有问题的,因为char类型中间有两个空的字符
    %只需要将char类型转化为一个新的类型就可以了
    n{i}=str2num(n{i});
    t{i}=str2num(t{i});
     x0=t{i}(3);
     x1=logical(t{i}(2));
     x2=logical(t{i}(1));
     x3=logical(n{i}(3));
     x4=logical(n{i}(2));
     x5=logical(n{i}(1));
     x_0=~x0;
     x_1=~x1;
     x_2=~x2;
     x_3=~x3;
     x_4=~x4;
     x_5=~x5;
    p1=x5&&x2;
    p2=x5&&x4;
    p3=x5&&1;
    p4=x5&&x3;
    p5=x4&&x_3&&x_2&&x_1&&x_0;
    p6=x_4&&x3&&x_2&&x_1&&x_0;
    p7=x_4&&x_3&&x2&&x1&&x_0;
    p8=x3&&x_2&&x1&&x_0;
    p9=x4&&x3&&x1&&x0;
    p10=x4&&x_3&&x1&&x0;
    p11=x4&&x2&&x1;
    p12=x_4&&x3&&x1&&x0;
    p13=x3&&x2&&x1;
    p14=x3&&x_1&&x0;
    p15=x4&&x2&&x0;
    p16=x4&&x_3&&x_2&&x1;
    p17=x_4&&x_3&&x_2&&x1;
    p18=x_4&&x3&&x2;
    p19=x4&&x3&&x2;
    p20=x_3&&x2;
    p21=x_4&&x2&&x1&&x0;
    p22=x_4&&x2&&x_1&&x0;
    p23=x4&&x_3&&x2&&x_1;
    p24=x4&&x_2&&x_1&&x0;
    p25=x_4&&x_3&&x_2&&x0;
    p26=x4&&x3;
    p27=x4&&x3&&x_2&&x_0;
    y6=1;
    y5=p3|p5|p8|p10|p11|p12|p13|p14|p15|p16|p18|p23|p24|p26;
    y4=p3|p5|p6|p10|p11|p15|p16|p20|p24|p26;
    y3=p3|p6|p11|p13|p17|p18|p21|p26;
    y2=p3|p6|p7|p9|p12|p13|p16|p19|p23|p25;
    y1=p3|p6|p7|p8|p12|p21|p22|p23|p24|p27;
    y0=p1|p2|p4|p5|p7|p8|p10|p13|p14|p15|p18|p22;
    y(i)=1/2*y6+1/4*y5+1/8*y4+1/16*y3+1/32*y2+1/64*y1+1/128*y0;
    b(i)=1-y(i);
    m(i)=y(i)*b(i);
    j=0;
    L(i)=abs(fx(i)-y(i));
    P(i)=abs(fx(i)-m(i));
    j=j+L(i);
end
   Eave=mean(P)
   Emax=max(P)
%plot(x,y,'b');
%hold on;
%plot(m,b,'b')
%hold on;
plot(x,fx,'b');
hold on;
plot(x,m,'r');
end

下面给出得出的仿真图像,还有得出的最大误差和平均误差:
这里写图片描述
这里写图片描述

方法二

这种方法怎么说呢,也就能在软件上面用用。因为用了好多乘法器还迭代了很多次,timing什么的惨不忍睹。写出来就是让大家看看,笑话笑话我。下面说一下核心算法,简单的说就是把几条直线通过迭代掰弯了。
这里写图片描述
这里面的第四行g(x)应该改成dg(x),只是觉得真的好坑,我改了好久才改出来的!
代码如下:

function SIGD()
m=0.096225;
n=0.293391;
deta1=0.0868;
deta2=0.09634;
x=-8:0.01:8;
h=0;
dg=m.*x+n;
l=(-1)*m;
h1=l.*x+n;
fx=exp(-x)./(1+exp(-x)).^2;
q=4;
for i=0:1:q
    dg1=min(dg,h1);
    h1=0.5*(dg+h1-deta1);
    dg=max(dg1,h);
    h=0.5*(dg1+h+deta2);
    deta1=deta1/4;
    deta2=deta2/4;
end
dg1=min(dg,h1);
dg=max(dg1,h);
l=abs(dg-fx);
Emax=max(l)
Emean=mean(l)
plot(x,dg,'red');
hold on;
plot(x,fx,'b')
end

同样的,仿真图像和最大平均误差也给出了(可以看到红色的线有四条,那是q=1,2,3,4四种情形,q表示迭代次数):
这里写图片描述
这里写图片描述
怎么样,很简单吧。

方法三

算法图如下,输入输出非常明了:
这里写图片描述
代码:

function threhold()
x1=0:0.01:1;
f1=0.25;
x2=1:0.01:2;
f2=0.125;
x3=2:0.01:3;
f3=0.0625;
x4=3:0.01:4;
f4=0.03125;
x5=4:0.01:5;
f5=0.015625;
x6=5:0.01:6;
f6=0.0078125;
x7=6:0.01:7;
f7=0.00390625;
x8=7:0.01:8;
f8=0.001953125;
plot(x1,f1,'r');hold on;
plot(x2,f2,'r');hold on;
plot(x3,f3,'r');hold on;
plot(x4,f4,'r');hold on;
plot(x5,f5,'r');hold on;
plot(x6,f6,'r');hold on;
plot(x7,f7,'r');hold on;
plot(x8,f8,'r');hold on;
end

这里写图片描述
这个误差真是有点恐怖了,不在考虑范围之内。

方法四

算法:
这里写图片描述
仿真图像:
这里写图片描述
代码:

function
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值