基于FPGA的GoogleNet加速器-Local Response Normalization

局部归一化据说是没啥用,不过既然GNet里面有那还是要写的。
该层需要参数有:
norm_region: 选择对相邻通道间归一化还是通道内空间区域归一化,默认为ACROSS_CHANNELS,即通道间归一化;
local_size:两种表示(1)通道间归一化时表示求和的通道数;(2)通道内归一化时表示求和区间的边长;默认值为5;
alpha:缩放因子(详细见后面),默认值为1;
beta:指数项(详细见后面), 默认值为5;
在通道间归一化模式中,局部区域范围在相邻通道间,但没有空间扩展(即尺寸为 local_size x 1 x 1);
在通道内归一化模式中,局部区域在空间上扩展,但只针对独立通道进行(即尺寸为 1 x local_size x local_size);
每个输入值都除以
caffe的lrn.cpp文件中有将近200行代码,但是实际上我们用到的只有CrossChannelForward_cpu()这一个函数而已。Forward
意思是向前传播,也就是说还有backward反向传播,是用来算梯度的,我们现在用不上。
在这里将caffe的代码贴出来,一步一步拆解
  1.   const vector<Blob<Dtype>*>& bottom, vector<Blob<Dtype>*>* top) {  
  2.   const Dtype* bottom_data = bottom[0]->cpu_data();  
  3.   Dtype* top_data = (*top)[0]->mutable_cpu_data();  
  4.   Dtype* scale_data = scale_.mutable_cpu_data();//用指针获取每个Blob对象的内存地址,便于后面操作  
  5.   // start with the constant value  
  6.   for (int i = 0; i < scale_.count(); ++i) {//初始化值为1.0  
  7.     scale_data[i] = 1.;  
  8.   } 
虽然没学过C++,但是我们已经知道了这层的功能,所以大概猜出来这段代码是干什么的并不难。bottom是输入,top是输出,scale用来存放中间数据
大小在这里找不出来,但是根据后面的代码可以算出来scale的大小就是整个输入的大小,初始化为1。下面紫色的立方体就代表输入,画出来的是长6宽6高5

图1
  1.   Blob<Dtype> padded_square(1, channels_ + size_ - 1, height_, width_);//补零后的Blob,第三维尺寸比bottom大了size_ - 1;  
  2.   Dtype* padded_square_data = padded_square.mutable_cpu_data();  
  3.   caffe_set(padded_square.count(), Dtype(0), padded_square_data);//先清零  
padded_square 用来存储平方后的数据,高为 channels_ + size_ - 1,跟卷积时候添加的pad类似要上下各延伸一部分, 下图那些透明的部分始终为0,存放数据时候直接跳过。 最前面的1是长宽高以外的第四维度,我并不知道他是做什么的,但是并不影响,我们继续看。
  1.  Dtype alpha_over_size = alpha_ / size_;//预先计算公式中的alpha/n  
  2. // go through the images  
  3.   for (int n = 0; n < num_; ++n) {//bottom的第四维尺寸num_,需要分解为单个来做归一化 
  4. // compute the padded square  
  5.     caffe_sqr(channels_ * height_ * width_,  
  6.         bottom_data + bottom[0]->offset(n),  
  7.         padded_square_data + padded_square.offset(0, pre_pad_));//计算bottom的平方,放入padded_square矩阵中,前pre_pad_个位置依旧0  
for循环不用看,因为在这里num=1。难点在于理解caffe_sqr:在caffe下面的math_function.cpp文件里我们可以找到caffe_sqr的定义
caffe_sqr(int len,float* a,float* b) ,意思就是b[i]=a[i]*a[i],执行len次。关于offset(n),可以回想在卷积层我们每次执行计算都要找到现在计算的点
是所有输入中的第几个,在这里offset就是起到这个作用。offset(int num,int channel,int hight,int width)输入当前所在位置就可以得到当前算的点是第几个,放进什么地方。C++中如果传入参数数目可以小于声明时所定义的数目时取默认值。
那么这一段的意思就很好理解了,输入的每一个数都平方放进padded_Square中对应位置,比如in[0]放进padded_square第pad层的第一个位置,因为上下各延伸了pad层。在这里就是图1算完放进图2紫色的部分。

  1. for (int c = 0; c < size_; ++c) {//对n个通道平方求和并乘以预先算好的(alpha/n),累加至scale_中(实现计算 1 + sum_under_i(x_i^2))  
  2.       caffe_axpy<Dtype>(height_ * width_, alpha_over_size,  
  3.           padded_square_data + padded_square.offset(0, c),  
  4.           scale_data + scale_.offset(n, 0));  
  5.     } 
找到caffe_axpy()的定义:caffe_axpy(int len,float alpha,float* x,float* y){for(int i=0;i<len;i++)y[i]=alpha*x+y;}
在这里,len= height * width,意思就是每调用一次caffe_axpy这个函数算一层。所以下面以层为单位讲述,scale(0)表示
当c=0时,这段函数执行的是将scale(0)=alpha_over_size*padded_square(0),for循环执行完scale(0)=1+ alpha_over_size*[padded_square(0)+ padded_square(1)+ padded_square(2)+ padded_square(3)+ padded_square(4)]如图所示。到这儿你可能就看明白为什么scale要全部赋值为1了
到这里, 除了最后的指数项已经全部完成了。但是这只算完了scale(0),还剩下channel-1个没算呢

图3

  1.     for (int c = 1; c < channels_; ++c) {//这里使用了类似FIFO的形式计算其余scale_参数,每次向后移动一个单位,加头去尾,避免重复计算求和  
  2.       // copy previous scale  
  3.       caffe_copy<Dtype>(height_ * width_,  
  4.           scale_data + scale_.offset(n, c - 1),  
  5.           scale_data + scale_.offset(n, c));  
  6.       // add head  
  7.       caffe_axpy<Dtype>(height_ * width_, alpha_over_size,  
  8.           padded_square_data + padded_square.offset(0, c + size_ - 1),  
  9.           scale_data + scale_.offset(n, c));  
  10.       // subtract tail  
  11.       caffe_axpy<Dtype>(height_ * width_, -alpha_over_size,  
  12.           padded_square_data + padded_square.offset(0, c - 1),  
  13.           scale_data + scale_.offset(n, c));  
  14.     }  
  15.   }  
现在开始计算后面那些层:
首先scale(1)=scale(0)= scale(0)=1+ alpha_over_size*[padded_square(0)+ padded_square(1)+ padded_square(2)+ padded_square(3)+ padded_square(4)]
然后scale(1)=scale(1)+pad(5)= 1+ alpha_over_size*[pad(0)+ pad(1)+ pad(2)+ pad(3)+ pad(4)+pad(5)]
如图4所展示

图4
最后要把scale(1)多算的那一层pad(0)给去掉,scale(1)= 1+ alpha_over_size*[ pad(1)+ pad(2)+ pad(3)+ pad(4)+pad(5)]
------------------------------------------------------------------------------------------------------------------------------------------
  1. caffe_powx<Dtype>(scale_.count(), scale_data, -beta_, top_data);//计算求指数,将除法转换为乘法,故指数变负  
  2.   caffe_mul<Dtype>(scale_.count(), top_data, bottom_data, top_data);//bottom .* scale_-> top最后输出结果


傲盾网络加速器是目前最流行,使用人数最多的一款上网加速软件。傲盾网络加速器是由用户终端软件以及加速服务器构成,傲盾网络加速器具有高性能的网 络优化网关,透过改良 HTTP 协议与文字、影像压缩技术,大幅改善网页浏览速度和访问速度。傲盾网络加速器不等同于其他 网络加速软件通过修改注册表等方 法来做“提速”。软件终端运行后,通过1-3秒的身份验证便可连接至傲盾数据中心分布在全球各地的12组24台加速服务器的任意一台。傲盾网络加速器终端工作后将IE 所请求下载的文件将通过加速服务 器的优化后再下载到本地,优化后数据传输提高50%或更高(比如:不使用傲盾网络加速器打开搜狐的主页需要有500K的数据流量,而使用了傲盾网络加速器打开只需190K 左右的流量),这样如果你不使用本 软件访问下载完搜狐主页需要2分钟,而使用了本软件以后仅需30秒就可以下载完。 傲盾网络加速器自带优越的图像缓存功能,在您访问以前访问过的网页时仅仅下载网页源文件,再次访问几乎是即点即现。傲盾网络加速器将是加速软件的一场革命 !该软件适用于任何网络加速!同时这款软件还是一个突破内网限制和突破ISP限制的工具,只需运行该软件,无需对浏览器做任何改动即可平时无法访问的外部网站。 傲盾网络加速器在进行网页加速具有革命性的加速优势,它采取的WEBCACHE技术不单有助于各ISP间服务器的 网 页加速并且对其本身ISP的服务器也具备加速条件,先拿各ISP间服务器的网页加速来说明,比如用户是使用网通..... 更多>> 在针对网游加速方面,傲盾网络加速器也进行了成千上万次的计算,分别在全国各省市分布了数百台服务器 ,专门针对网游服务器进行速度跟踪,我们更针对主流的游戏服务器进行实时速度.....更多>> 在视频播放方面,我们在原有的技术层面上增加了P2P技术,专门针对视频流进行了更加完美解决方案,用户 在访问同一个视频源的时候,我们分别从各地的服务器上分别搜索该视频源然后汇聚到用户的计算机上。.....更多>> 小王是上海某公司的服务器运维人员,公司分别在天津铁通、河南教育网、福建电信以及江西网通放置了大 量的服务器,以往小王经常为对服务器的维护感到心力憔悴,因为公司是使用上海.....更多 >>
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值