task06--批量归一化

批量归一化(BatchNormalization)

BN算法(Batch Normalization)其强大之处如下:

(1)、你可以选择比较大的初始学习率,让你的训练速度飙涨。以前还需要慢慢调整学习率,甚至在网络训练到一半的时候,还需要想着学习率进一步调小的比例选择多少比较合适,现在我们可以采用初始很大的学习率,然后学习率的衰减速度也很大,因为这个算法收敛很快。当然这个算法即使你选择了较小的学习率,也比以前的收敛速度快,因为它具有快速训练收敛的特性;

(2)、你再也不用去理会过拟合中drop out、L2正则项参数的选择问题,采用BN算法后,你可以移除这两项了参数,或者可以选择更小的L2正则约束参数了,因为BN具有提高网络泛化能力的特性;

(3)、再也不需要使用使用局部响应归一化层了(局部响应归一化是Alexnet网络用到的方法,搞视觉的估计比较熟悉),因为BN本身就是一个归一化网络层;

(4)、可以把训练数据彻底打乱(防止每批训练的时候,某一个样本都经常被挑选到,文献说这个可以提高1%的精度,这句话我也是百思不得其解啊)。

开始讲解算法前,先来思考一个问题:我们知道在神经网络训练开始前,都要对输入数据做一个归一化处理,那么具体为什么需要归一化呢?归一化后有什么好处呢?原因在于神经网络学习过程本质就是为了学习数据分布,一旦训练数据与测试数据的分布不同,那么网络的泛化能力也大大降低;另外一方面,一旦每批训练数据的分布各不相同(batch 梯度下降),那么网络就要在每次迭代都去学习适应不同的分布,这样将会大大降低网络的训练速度,这也正是为什么我们需要对数据都要做一个归一化预处理的原因。

对于深度网络的训练是一个复杂的过程,只要网络的前面几层发生微小的改变,那么后面几层就会被累积放大下去。一旦网络某一层的输入数据的分布发生改变,那么这一层网络就需要去适应学习这个新的数据分布,所以如果训练过程中,训练数据的分布一直在发生变化,那么将会影响网络的训练速度。

我们知道网络一旦train起来,那么参数就要发生更新,除了输入层的数据外(因为输入层数据,我们已经人为的为每个样本归一化),后面网络每一层的输入数据分布是一直在发生变化的,因为在训练的时候,前面层训练参数的更新将导致后面层输入数据分布的变化。以网络第二层为例:网络的第二层输入,是由第一层的参数和input计算得到的,而第一层的参数在整个训练过程中一直在变化,因此必然会引起后面每一层输入数据分布的改变。我们把网络中间层在训练过程中,数据分布的改变称之为:“Internal Covariate Shift”。

原文链接:https://blog.youkuaiyun.com/hjimce/article/details/50866313

对输入的标准化(浅层模型)

处理后的任意一个特征在数据集中所有样本上的均值为0、标准差为1。
标准化处理输入数据使各个特征的分布相近

批量归一化(深度模型)

利用小批量上的均值和标准差,不断调整神经网络中间输出,从而使整个神经网络在各层的中间输出的数值更稳定。

1.对全连接层做批量归一化

位置:全连接层中的仿射变换和激活函数之间。
全连接:
x = W u + b o u t p u t = ϕ ( x ) \boldsymbol{x} = \boldsymbol{W\boldsymbol{u} + \boldsymbol{b}} \\ output =\phi(\boldsymbol{x}) x=Wu+boutput=ϕ(x)

批量归一化:
o u t p u t = ϕ ( BN ( x ) ) output=\phi(\text{BN}(\boldsymbol{x})) output=ϕ(BN(x))

y ( i ) = BN ( x ( i ) ) \boldsymbol{y}^{(i)} = \text{BN}(\boldsymbol{x}^{(i)}) y(i)=BN(x(i))
输入是d维的(i=1…d),这里要对每一维度进行归一化
m是批量大小
μ B ← 1 m ∑ i = 1 m x ( i ) , \boldsymbol{\mu}_\mathcal{B} \leftarrow \frac{1}{m}\sum_{i = 1}^{m} \boldsymbol{x}^{(i)}, μBm1i=1mx(i),
σ B 2 ← 1 m ∑ i = 1 m ( x ( i ) − μ B ) 2 , \boldsymbol{\sigma}_\mathcal{B}^2 \leftarrow \frac{1}{m} \sum_{i=1}^{m}(\boldsymbol{x}^{(i)} - \boldsymbol{\mu}_\mathcal{B})^2, σB2m1i=1m(x(i)μB)2,
x ^ ( i ) ← x ( i ) − μ B σ B 2 + ϵ , \hat{\boldsymbol{x}}^{(i)} \leftarrow \frac{\boldsymbol{x}^{(i)} - \boldsymbol{\mu}_\mathcal{B}}{\sqrt{\boldsymbol{\sigma}_\mathcal{B}^2 + \epsilon}}, x^(i)σB2+ϵ x(i)μB,

这⾥ϵ > 0是个很小的常数,保证分母大于0
这篇博客里有一个计算图

如果是仅仅使用上面的归一化公式,对网络某一层A的输出数据做归一化,然后送入网络下一层B,这样是会影响到本层网络A所学习到的特征的。比如我网络中间某一层学习到特征数据本身就分布在S型激活函数的两侧,你强制把它给我归一化处理、标准差也限制在了1,把数据变换成分布于s函数的中间部分,这样就相当于我这一层网络所学习到的特征分布被你搞坏了,这可怎么办?于是文献使出了一招式:变换重构,引入了可学习参数γ、β,这就是算法关键之处:

y ( i ) ← γ ⊙ x ^ ( i ) + β . {\boldsymbol{y}}^{(i)} \leftarrow \boldsymbol{\gamma} \odot \hat{\boldsymbol{x}}^{(i)} + \boldsymbol{\beta}. y(i)γx^(i)+β.

引入可学习参数:拉伸参数γ和偏移参数β。若 γ = σ B 2 + ϵ \boldsymbol{\gamma} = \sqrt{\boldsymbol{\sigma}_\mathcal{B}^2 + \epsilon} γ=σB2+ϵ β = μ B \boldsymbol{\beta} = \boldsymbol{\mu}_\mathcal{B} β=μB,批量归一化无效。

2.对卷积层做批量归⼀化

  • BN层是对于每个神经元做归一化处理,甚至只需要对某一个神经元进行归一化,而不是对一整层网络的神经元进行归一化。既然BN是对单个神经元的运算,那么在CNN中卷积层上要怎么搞?假如某一层卷积层有6个特征图,每个特征图的大小是100100,这样就相当于这一层网络有6100100个神经元,如果采用BN,就会有6100*100个参数γ、β,这样岂不是太恐怖了。因此卷积层上的BN使用,其实也是使用了类似权值共享的策略,把一整张特征图当做一个神经元进行处理。

  • 卷积神经网络经过卷积后得到的是一系列的特征图,如果min-batch sizes为m,那么网络某一层输入数据可以表示为四维矩阵(m,f,w,h),m为min-batch sizes,f为特征图个数,w、h分别为特征图的宽高。在CNN中我们可以把每个特征图看成是一个特征处理(一个神经元),因此在使用Batch Normalization,mini-batch size 的大小就是:mw*h,于是对于每个特征图都只有一对可学习参数:γ、β。说白了吧,这就是相当于求取所有样本所对应的一个特征图的所有神经元的平均值、方差,然后对这个特征图神经元做归一化。
    参考的文章

位置:卷积计算之后、应⽤激活函数之前。
如果卷积计算输出多个通道,我们需要对这些通道的输出分别做批量归一化,且每个通道都拥有独立的拉伸和偏移参数。
计算:对单通道,batchsize=m,卷积计算输出=pxq
对该通道中m×p×q个元素同时做批量归一化,使用相同的均值和方差。

3.预测时的批量归⼀化

训练:以batch为单位,对每个batch计算均值和方差。
预测:用移动平均估算整个训练数据集的样本均值和方差。

从零实现

import time
import torch
from torch import nn, optim
import torch.nn.functional as F
import torchvision
import sys
sys.path.append("/home/kesci/input/") 
import d2lzh1981 as d2l
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

def batch_norm(is_training, X, gamma, beta, moving_mean, moving_var, eps, momentum):
    # 判断当前模式是训练模式还是预测模式
    if not is_training:
        # 如果是在预测模式下,直接使用传入的移动平均所得的均值和方差
        X_hat = (X - moving_mean) / torch.sqrt(moving_var + eps)
    else:
        assert len(X.shape) in (2, 4)
        if len(X.shape) == 2:
            # 使用全连接层的情况,计算特征维上的均值和方差
            mean = X.mean(dim=0)
            var = ((X - mean) ** 2).mean(dim=0)
        else:
            # 使用二维卷积层的情况,计算通道维上(axis=1)的均值和方差。这里我们需要保持
            # X的形状以便后面可以做广播运算
            mean = X.mean(dim=0, keepdim=True).mean(dim=2, keepdim=True).mean(dim=3, keepdim=True)
            var = ((X - mean) ** 2).mean(dim=0, keepdim=True).mean(dim=2, keepdim=True).mean(dim=3, keepdim=True)
        # 训练模式下用当前的均值和方差做标准化
        X_hat = (X - mean) / torch.sqrt(var + eps)
        # 更新移动平均的均值和方差
        moving_mean = momentum * moving_mean + (1.0 - momentum) * mean
        moving_var = momentum * moving_var + (1.0 - momentum) * var
    Y = gamma * X_hat + beta  # 拉伸和偏移
    return Y, moving_mean, moving_var
class BatchNorm(nn.Module):
    def __init__(self, num_features, num_dims):
        super(BatchNorm, self).__init__()
        if num_dims == 2:
            shape = (1, num_features) #全连接层输出神经元
        else:
            shape = (1, num_features, 1, 1)  #通道数
        # 参与求梯度和迭代的拉伸和偏移参数,分别初始化成0和1
        self.gamma = nn.Parameter(torch.ones(shape))
        self.beta = nn.Parameter(torch.zeros(shape))
        # 不参与求梯度和迭代的变量,全在内存上初始化成0
        self.moving_mean = torch.zeros(shape)
        self.moving_var = torch.zeros(shape)

    def forward(self, X):
        # 如果X不在内存上,将moving_mean和moving_var复制到X所在显存上
        if self.moving_mean.device != X.device:
            self.moving_mean = self.moving_mean.to(X.device)
            self.moving_var = self.moving_var.to(X.device)
        # 保存更新过的moving_mean和moving_var, Module实例的traning属性默认为true, 调用.eval()后设成false
        Y, self.moving_mean, self.moving_var = batch_norm(self.training, 
            X, self.gamma, self.beta, self.moving_mean,
            self.moving_var, eps=1e-5, momentum=0.9)
        return Y

残差网络(ResNet)

深度学习的问题:深度CNN网络达到一定深度后再一味地增加层数并不能带来进一步地分类性能提高,反而会招致网络收敛变得更慢,准确率也变得更差。

残差块(Residual Block)

恒等映射:
左边:f(x)=x
右边:f(x)-x=0 (易于捕捉恒等映射的细微波动)

Image Name

在残差块中,输⼊可通过跨层的数据线路更快 地向前传播。

<think>好的,我现在需要帮助用户解决在ENVI中对多波段影像进行批量归一化处理的问题。首先,我得理解用户的需求。用户提到的是多波段影像的批量归一化,可能他们有很多影像需要处理,手动一个个处理效率太低,所以想要批量处理的方法。 接下来,我应该回忆一下ENVI的相关功能。根据之前的引用内容,ENVI有波段运算、内置函数Spectral Indices运算以及内置工具如NDVI计算。用户提到的归一化处理,可能需要通过波段运算来实现,因为归一化通常是自定义的数学运算,比如每个波段的像元值除以总和或其他统计值。 用户提供的引用中,引用[2]提到了波段比和波段运算,指出比值增强可以用于归一化处理,压制亮度差异或大气影响。这可能和用户的需求相关。此外,引用[3]提到了ENVI计算NDVI的几种方法,包括波段运算,这说明波段运算是ENVI中处理这类任务的主要工具之一。 那如何批量处理呢?ENVI的波段运算是否支持批量处理多个文件?我记得ENVI可以通过编写脚本或者使用任务批处理功能来执行批量操作。用户可能需要使用ENVI的Band Math工具,逐个处理每个波段,但如果是多影像文件,就需要结合批处理功能。 可能的步骤是:首先,打开波段运算工具,输入归一化公式,比如(b1)/(b1+b2+...+bn),其中b1到bn是各个波段的像元值。然后,对每个影像文件应用这个公式。但如何批量处理多个文件呢?可能需要使用ENVI的API或者编写IDL脚本,或者利用ENVI的Task模式进行批处理。 另外,用户可能需要考虑每个影像的各个波段归一化后的结果保存到新文件。例如,对于每个输入影像,生成一个归一化后的输出影像,并自动保存到指定目录。这可能需要循环处理每个文件,应用相同的波段运算公式。 需要注意的是,ENVI的默认波段运算可能不支持直接处理多文件,所以可能需要结合ENVI的编程接口,或者使用ENVI Modeler创建处理流程,然后批量应用。例如,使用ENVI的Batch Processing工具,或者编写IDL代码调用ENVI的功能。 另外,引用[1]提到使用GDAL进行批量波段运算,但用户明确询问的是ENVI的方法,所以可能不需要涉及GDAL,除非用户愿意考虑其他工具。但根据问题描述,用户希望使用ENVI处理。 总结步骤可能包括: 1. 确定归一化公式,比如每个波段除以所有波段之和。 2. 使用ENVI的波段运算工具输入公式。 3. 对每个影像文件应用该公式,并保存结果。 4. 使用ENVI的批处理功能自动化处理多个文件。 但如何具体操作呢?例如,假设用户有多个影像文件,每个文件有多个波段,如何对每个文件的每个波段进行归一化处理?可能需要针对每个影像,逐个波段应用公式,或者一次性计算所有波段的归一化值。 另外,归一化方法可能有多种,比如最大值最小值归一化,或者总和归一化。用户需要明确具体需求,但问题中没有说明具体归一化方法,所以可能需要给出一般性的方法,并说明如何自定义公式。 此外,引用[3]提到ENVI的不同方法计算NDVI的结果差异,所以归一化的方法也需要确保公式正确,避免误差。 可能的解决方案是: - 使用波段运算,编写归一化公式。 - 使用ENVI的Task API或者Batch Processing工具进行批量处理。 - 或者编写IDL脚本自动化处理。 需要详细步骤,可能还需要考虑如何获取所有波段的数值总和,比如在波段运算中如何引用多个波段。例如,如果影像有n个波段,公式可能是b1/(b1+b2+...+bn),但需要知道波段数量。对于不同的影像,波段数量可能不同,所以可能需要动态处理。 或者,用户可能需要逐波段归一化,比如每个波段的值除以整个影像的最大值,或者其他统计值。这需要更复杂的处理,可能需要先计算统计信息,再应用公式。 不过,用户的问题是多波段影像的归一化,可能指的是将每个像元的各个波段值归一化为总和为1,或者每个波段独立归一化到0-1范围。需要明确。 假设用户是指每个像元的各个波段值之和为1,即每个波段的值为该像元各个波段值的比例。这种情况下,公式为每个波段除以所有波段之和。例如,对于波段i,公式为bi / (b1 + b2 + ... + bn)。这在ENVI的波段运算中如何实现? ENVI的波段运算允许使用波段变量,如b1到bn。例如,如果有3个波段,表达式可以是b1/(b1+b2+b3),然后应用到每个波段。但如果是多个波段,比如10个,手动输入会很麻烦。这时候可能需要使用IDL编写循环来处理每个波段,或者使用更高级的表达式。 另外,ENVI的波段运算是否支持数组操作?例如,计算所有波段的总和,然后每个波段除以总和。例如,总和可以表示为total = sum(b1, b2, ..., bn),然后每个波段为bi / total。但如何动态引用所有波段呢? 可能需要用到ENVI的数组变量。例如,使用float(b1)将每个波段转换为浮点数,然后计算总和。例如,总和可以通过b1 + b2 + b3 + ... + bn,但手动输入所有波段变量可能不现实,尤其是当波段数量较多时。 或者,可以使用ENVI的API,例如,通过IDL脚本获取影像的波段数,然后动态生成表达式。例如,如果影像有5个波段,表达式会是b1/(b1+b2+b3+b4+b5)。这样,对于不同数量的波段,需要不同的表达式。 因此,批量处理多波段影像的归一化可能需要针对每个影像单独处理,根据其波段数量生成相应的表达式。这可能比较复杂,特别是当不同影像的波段数不同时。 另一个可能性是,用户希望每个波段独立进行归一化,比如将每个波段的值线性拉伸到0-1范围。这需要计算每个波段的最小值和最大值,然后进行归一化。这种情况下,可以使用ENVI的波段运算结合统计信息。例如,对于波段i,公式为(float(bi) - min) / (max - min),其中min和max是该波段的最小和最大值。ENVI是否支持在波段运算中动态获取波段的统计信息? 或者,用户可能需要使用ENVI的Routine Normalization工具,如果有的话。但我不太确定ENVI是否有内置的归一化工具。如果没有,可能需要手动处理。 综合以上分析,可能的解决步骤是: 1. 确定归一化方法,例如每个像元的各波段值之和为1。 2. 使用波段运算工具输入表达式,例如b1/(b1+b2+b3)(假设3个波段)。 3. 对于不同波段数量的影像,需要调整表达式中的波段数。 4. 使用ENVI的批处理功能或IDL脚本批量处理多个影像文件。 或者,使用IDL脚本自动获取每个影像的波段数,动态生成表达式,并循环处理所有影像。 如果用户不具备编程能力,可能需要手动逐个处理,或者寻找其他方法。例如,使用ENVI Modeler创建处理链,然后应用批量处理。 此外,引用[2]提到波段运算可以用于归一化处理,所以可能需要具体指导用户如何在波段运算中设置公式,并如何批量应用。 因此,回答的结构应该是: 1. 介绍ENVI中批量归一化处理的两种主要方法:波段运算结合批处理工具,或者IDL脚本。 2. 详细步骤:使用波段运算输入公式,然后使用任务批处理功能。 3. 示例公式,比如总和归一化或最大值最小值归一化。 4. 注意事项,如波段数不同时的处理,以及如何自动保存结果。 可能需要参考引用[2]和[3]来说明波段运算的应用和不同方法的差异。</think>### ENVI多波段影像批量归一化处理方法 在ENVI中对多波段影像进行批量归一化处理,可通过**波段运算**结合**任务批处理功能**实现。以下是具体操作步骤: --- #### **方法一:波段运算+手动批处理** 1. **确定归一化公式** 假设需将每个像元的各波段值归一化为总和为1,表达式为: $$ \text{归一化值} = \frac{b_i}{b_1 + b_2 + \dots + b_n} $$ 其中$b_i$为当前波段值,$b_1$到$b_n$为所有波段值。 2. **单文件处理流程** - 打开影像文件后,选择`Band Math`工具(`工具箱 > Band Algebra > Band Math`)。 - 输入公式(以3波段为例): ```b1/(b1+b2+b3)``` 为每个波段重复此步骤,修改`b1`为当前波段变量[^2]。 - 输出结果保存为新文件。 3. **批量处理多文件** - 使用`Task Manager`(`文件 > 任务管理器`)记录上述操作。 - 通过`Batch Processing`功能加载多个文件并自动应用任务[^3]。 --- #### **方法二:IDL脚本自动化** 若需处理波段数量动态变化的影像,可编写IDL脚本动态生成表达式: ```idl pro batch_normalize ; 选择输入文件目录 input_dir = dialog_pickfile(/directory) files = file_search(input_dir + '*.dat') foreach file, files do begin ; 打开影像并获取波段数 envi_open_file, file, r_fid=fid if fid eq -1 then continue envi_file_query, fid, nb=nb ; 动态生成表达式 sum_bands = strjoin(strarr(nb)+'b'+string(1+nb_indgen(nb)), '+') expression = 'b1/(' + sum_bands + ')' ; 执行波段运算并保存 for i=0, nb-1 do begin envi_doit, 'band_math', fid=fid, dims=dims, exp=expression, out_name=file+'_normalized' endfor endforeach end ``` --- #### **注意事项** 1. **归一化类型选择** - 若需最大值归一化(如NDVI标准化),公式为: $$ \text{归一化值} = \frac{b_i - \text{min}(b_i)}{\text{max}(b_i) - \text{min}(b_i)} $$ 需提前通过`Statistics`工具计算各波段统计值[^3]。 2. **数据格式转换** 归一化可能导致小数结果,建议输出为浮点型(如`float`)避免精度损失。 3. **结果验证** 使用`Pixel Inspector`工具检查归一化后像元值是否符合预期范围(如0-1)。 --- 相关问题
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值