深度神经网络中的局部响应归一化LRN简介及实现

article/2025/9/16 1:28:31

Alex、Hinton等人在2012年的NIPS论文《ImageNet Classification with Deep Convolutional Neural Networks》中将LRN应用于深度神经网络中(AlexNet)。论文见:http://www.cs.toronto.edu/~hinton/absps/imagenet.pdf ,截图如下:

公式解释:

a_{x,y}^{i}:ReLU处理后的神经元,作为LRN的输入;

b_{x,y}^{i}:LRN的输出,LRN处理后的神经元;

N:kernal总数或通道数;

k、n、\alpha\beta:为常量,是超参数,k类似于bias,n对应于Caffe中的local_size,在论文中这几个值分别为2、5、10^{-4}、0.75。

LRN(Local Response Normalization):局部响应归一化,此层实现了” lateral inhibition”(侧抑制),通过对局部输入区域进行归一化来执行一种”侧抑制”。在AlexNet中,处理ReLU神经元时,LRN很有用,因为ReLU的响应结果是无界的,可以非常大,所以需要归一化。当处理具有无限激活(unbounded activation)的神经元时(如ReLU),可以通过LRN对其归一化(normalize),因为它允许检测具有大神经元响应的高频特征(high-frequency features),同时衰减局部周围(local neighborhood)均匀大(uniformly large)的响应。它是一种正则化类型。一般应用在激活、池化后进行的一种处理方法。该层的输出维数始终等于输入维数。

在神经生物学有一个概念叫做侧抑制(lateral inhibition),指的是被激活的神经元抑制相邻的神经元。归一化的目的是”抑制”,局部响应归一化就是借鉴侧抑制的思想来实现局部抑制。LRN层模仿生物神经系统的侧抑制机制,对局部神经元的活动创建竞争机制,使得其中响应比较大的值变得相对更大,并抑制其它反馈较小的神经元,增强了模型泛化能力。

后来研究者发现LRN起不到太大作用,LRN的作用已被正则化技术(regularization techniques,例如dropout and batch normalization)、更好的初始化和训练方法所取代。

在Caffe的caffe.proto中,LRN参数内容如下:分为通道间归一化(local_size*1*1)和通道内归一化(1*local_size*local_size)

// Message that stores parameters used by LRNLayer
message LRNParameter {optional uint32 local_size = 1 [default = 5];optional float alpha = 2 [default = 1.];optional float beta = 3 [default = 0.75];enum NormRegion {ACROSS_CHANNELS = 0;WITHIN_CHANNEL = 1;}optional NormRegion norm_region = 4 [default = ACROSS_CHANNELS];optional float k = 5 [default = 1.];enum Engine {DEFAULT = 0;CAFFE = 1;CUDNN = 2;}optional Engine engine = 6 [default = DEFAULT];
}

各参数介绍见:http://caffe.berkeleyvision.org/tutorial/layers/lrn.html

注:以上内容主要来自网络整理。

以下是实现的测试代码,仅实现通道间归一化,包括C++和tensorflow:

tensorflow的实现如下:

import tensorflow as tf
import numpy as np
x = np.array([i for i in range(1, 33)]).reshape([2, 2, 2, 4])
y = tf.nn.lrn(input=x, depth_radius=2, bias=1, alpha=1, beta=0.75)
print("input:\n", x)
print("output:\n", y)

C++代码实现如下:

lrn.hpp:

#ifndef FBC_NN_LRN_HPP_
#define FBC_NN_LRN_HPP_namespace ANN {enum class NormRegion {ACROSS_CHANNEL = 0,WITHIN_CHANNEL
};template<typename T = float>
class LRN {
public:LRN() = default;LRN(unsigned int local_size, T alpha, T beta, T bias, NormRegion norm_region) :local_size_(local_size), alpha_(alpha), beta_(beta), bias_(bias), norm_region_(norm_region) {}int run(const T* input, int batch, int channel, int height, int width, T* output) const;private:int across_channel(const T* input, int batch, int channel, int height, int width, T* output) const;int within_channel(const T* input, int batch, int channel, int height, int width, T* output) const;unsigned int local_size_ = 5; // nT alpha_ = 1.;T beta_ = 0.75;T bias_ = 1.; // kNormRegion norm_region_ = NormRegion::ACROSS_CHANNEL;
};} // namespace ANN#endif // FBC_NN_LRN_HPP_

lrn.cpp:

#include "lrn.hpp"
#include <algorithm>
#include <cmath>namespace ANN {template<typename T>
int LRN<T>::run(const T* input, int batch, int channel, int height, int width, T* output) const
{if (norm_region_ == NormRegion::ACROSS_CHANNEL)return across_channel(input, batch, channel, height, width, output);elsereturn within_channel(input, batch, channel, height, width, output);
}template<typename T>
int LRN<T>::across_channel(const T* input, int batch, int channel, int height, int width, T* output) const
{int size = channel * height * width;for (int p = 0; p < batch; ++p) {const T* in = input + size * p;T* out = output + size * p;// N = channel; n = local_size_; k = bias_for (int i = 0; i < channel; ++i) {for (int y = 0; y < height; ++y) {for (int x = 0; x < width; ++x) {T tmp = 0;for (int j = std::max(0, static_cast<int>(i - local_size_ / 2)); j <= std::min(channel - 1, static_cast<int>(i + local_size_ / 2)); ++j) {tmp += std::pow(in[j * height * width + width * y + x], 2);}out[i * height * width + width * y + x] = in[i * height * width + width * y + x] / std::pow(bias_ + alpha_ * tmp, beta_);}}}}return 0;
}template<typename T>
int LRN<T>::within_channel(const T* input, int batch, int channel, int height, int width, T* output) const
{fprintf(stderr, "not implemented\n");return -1;
}template class LRN<float>;} // namespace ANN

test_lrn.cpp:

int test_lrn()
{int batch = 2, channel = 4, height = 2, width = 2;std::vector<float> input{ 1., 5., 9., 13., 2., 6., 10., 14., 3., 7., 11., 15., 4., 8., 12., 16.,17., 21., 25., 29., 18., 22., 26., 30., 19., 23., 27., 31., 20., 24., 28., 32.};CHECK(batch * channel * height * width == input.size());std::unique_ptr<float[]> output(new float[input.size()]);ANN::LRN<> lrn;lrn.run(input.data(), batch, channel, height, width, output.get());auto print = [height, width](const float* data, int length) {int size = height * width;for (int i = 0; i < length / size; ++i) {const float* p = data + i * size;for (int j = 0; j < size; ++j) {fprintf(stdout, "  %f", p[j]);}fprintf(stdout, "\n");}};fprintf(stdout, "input:\n"); print(input.data(), input.size());fprintf(stdout, "output:\n"); print(output.get(), input.size());return 0;
}

执行结果如下图所示:由结果可知,C++实现与tensorflow一致

tensorflow执行结果如下:

C++执行结果如下:

GitHub:https://github.com/fengbingchun/NN_Test


http://chatgpt.dhexx.cn/article/DNYxhSK4.shtml

相关文章

LRN

发展时间点 局部响应归一化这个方法流行于2012年的 AlexNet网络&#xff0c;它将这种方法付诸实践&#xff0c;验证了它的可行性。在caffe框架和tensorflow框架中&#xff0c;这都是经常和卷积、池化配合使用的方法。 作用时间点&#xff1a;LRN一般是在激活、池化后进行的一中…

LRN (Local Response Normalization,即局部响应归一化层)

LRN (Local Response Normalization&#xff0c;即局部响应归一化层) &#xff08;一&#xff09;先看看归一化吧 什么是归一化&#xff1f; 归一化化是归纳统一样本的统计分布性。就是要把你需要处理的数据经过处理后&#xff08;通过某种算法&#xff09;限制在你需要的一定范…

详解LRN(local response normalization--局部响应标准化)缓解过拟合

局部响应归一化层&#xff08;Local Response Normalization&#xff09; LRN全称为Local Response Normalization&#xff0c;即局部响应归一化层&#xff0c;LRN函数类似Dropout和数据增强作为relu激活函数之后防止数据过拟合而提出的一种处理方法。这个函数很少使用&#xf…

局部响应归一化LRN (Local Response Normalization)

一、LRN技术介绍&#xff1a; LRN&#xff08;Local Response Normalization&#xff09; 是一种提高深度学习准确度的技术方法。 LRN 一般是在激活、 池化函数后的一种方法。在 ALexNet 中&#xff0c; 提出了 LRN 层&#xff0c; 对局部神经元的活动创建竞争机制&#xff0c…

深度学习饱受争议的局部响应归一化(LRN)详解

前言&#xff1a;Local Response Normalization(LRN)技术主要是深度学习训练时的一种提高准确度的技术方法。其中caffe、tensorflow等里面是很常见的方法&#xff0c;其跟激活函数是有区别的&#xff0c;LRN一般是在激活、池化后进行的一种处理方法。LRN归一化技术首次在AlexNe…

压缩算法之算术编码浅析与实现

压缩算法之算术编码浅析与实现 简介实现思路实现代码参考资料 简介 算术编码&#xff0c;属于熵编码的范畴&#xff0c;常用于各种信息压缩场合&#xff0c;如图像、视频、音频压缩领域。 基本原理&#xff1a; 核心原则&#xff1a;出现频率高的信息&#xff0c;分配少的比特…

算术编码(1)

序列a2a1的区间为&#xff08;0.2,0.22&#xff09; 算术解码步骤&#xff1a;

用分组编码解决算术编码的精度要求问题

这篇博客要介绍的是算术编码、译码。主要用分组编码的思路解决了当消息比较长时&#xff0c;小数位数太多&#xff0c;计算工具精度达不到的问题。 文末给出了matlab代码。题目的要求是&#xff1a;已知26个英文字母和空格的统计概率&#xff0c;对文本文档中的消息&#xff08…

算术编码 matlab程序,算术编码算法的matlab实现

算术编码算法的matlab实现 实验 1 算术编码算法的 Matlab 实现实验学时&#xff1a;2实验类型&#xff1a;(演示、验证、综合、√设计、研究)实验要求&#xff1a;(√必修、选修)一、实验目的掌握算数编码原理。二、实验内容利用 Matlab 编写程序实现算数编码&#xff0c;包括…

十六、算术编码_2、算术编码举例实现

基本原理 在一次算术编码的执行前,为简便起见,首先假设输入的信源为0/1的二进制信源,0和1的概率比为7:3。即二者的概率为: p(0) = 0.7; p(1) = 0.3;假设输入的待编码信息为[0, 0, 1],在编码每一个符号时,都需要对概率区间进行分割,并通过与编码区间进行比较,判断是否…

信息论基础:算术编码

1 引言 霍夫曼码是一种无损编码&#xff0c;而且是最优的符号码。但是&#xff0c;它有两个缺点&#xff1a;&#xff08;1&#xff09;每个符号至少需要一个比特&#xff1b;&#xff08;2&#xff09;当符号的概率分布变化时&#xff0c;使用不方便。 用一个例子来看看霍夫…

多媒体数据处理实验1:算术编码

1. 算法描述 功能&#xff1a; 给定概率字典以及待编码字符串&#xff0c;求出该字符串算术编码的结果&#xff08;最短二进制串&#xff09;&#xff0c;并能根据算数编码结果进行解码&#xff0c;得到原字符串。 2.算法流程&#xff1a; 算术编码流程&#xff1a; (1) 首先…

数字图像算术编码python_算术编码简介

上一篇讲了LZW编码&#xff0c;本篇讨论另一种不同的编码算法&#xff0c;算数编码。和哈夫曼编码一样&#xff0c;算数编码是熵编码的一种&#xff0c;是基于数据中字符出现的概率&#xff0c;给不同字符以不同的编码。本文也会对这两种编码方式的相似和不同点进行比较。 编码…

算术编码

文章首发于我的个人博客 前言 这篇博客主要总结大二下课程《信息论》实验的内容。主要包含固定模式的算数编码以及自适应模式的算术编码。我将首先介绍这两种算术编码的基本思想和实现思路&#xff0c;然后给出具体的python代码并对代码中的一些关键点进行解释说明。 固定模…

算术编码原理及其python实现

目录 1. 原理部分&#xff1a;2. 香农界理论分析&#xff1a;3. 代码实现&#xff1a;4.实验结果 1. 原理部分&#xff1a; 原理部分参考什么是算术编码 一个从信源序列到不可压缩二元序列的一个可逆映射&#xff0c;假设序列 { X 1 … X n } \{X_{1} \ldots X_{n}\} {X1​…X…

基本算术编码

1.基本思想 算术编码&#xff0c;就是用一个数编码一串字符串。它的思想是这样的:对一个需要编码的字符串&#xff0c;给出一个初始区间[0, 1),这个区间被分成n份&#xff0c;n是这串字符串中不同字符的个数&#xff0c;每一份占区间长度的比例与相应字符出现次数占整个字符串…

算术编码的基本概念

二、算术编码的基本概念 算术编码属于熵编码的一种重要的类型&#xff0c;其作用同变长编码等熵编码方法类似&#xff0c;用于压缩输入数据中的统计冗余&#xff0c;并且使用算术编码的压缩同样是无损压缩。 在本系列第1篇中讨论了典型的变长编码方法——哈夫曼编码。包括哈夫…

Otsu大津算法公式推导及python实现

目录 前言 一、类间平方差是什么&#xff1f; 二、公式推导及实现 1.求类间平方差 2.opencv-python编程实现 2.1 引入图像并灰度化 2.2 查看灰度值的分布情况 2.3 求全局平均阈值 2.4 求最大类间方差 3.算法的验证 总结 前言 OTSU&#xff08;大津算法&#xff09;是…

OTSU算法原理

OTSU算法原理及实现&#xff1a; 最大类间方差是由日本学者大津(Nobuyuki Otsu)于1979年提出&#xff0c;是一种自适应的阈值确定方法。算法假设图像像素能够根据阈值&#xff0c;被分成背景[background]和目标[objects]两部分。然后&#xff0c;计算该最佳阈值来区分这两类像素…

大津阈值分割算法(OTSU处理图像)

1.算法原理简述 对于图像I(x,y)&#xff0c;前景(即目标)和背景的分割阈值记作T&#xff0c;属于前景的像素点数占整幅图像的比例记为ω0&#xff0c;其平均灰度μ0&#xff1b;背景像素点数占整幅图像的比例为ω1&#xff0c;其平均灰度为μ1。图像的总平均灰度记为μ&#xf…