Pytoch计算数据集的均值和方差

1.前言

        图像预处理时,通常使用transforms.Normalize(mean, std)对图像按通道进行标准化,即减去均值,再除以方差。这样做可以加快模型的收敛速度。其中参数mean和std分别表示图像每个通道的均值和方差序列。

2.具体代码

import os
import torch
from torchvision import datasets, transforms


def calculate_mean_std(dataset):
    """
    计算数据集的均值和方差
    :param dataset: 数据集
    :return: mean, std
    """
    # init mean and std
    mean = 0.
    std = 0.
    total_samples = len(dataset)
    print("tran dataset len:", total_samples)
    
    # Traversing the dataset calculates the mean and std
    for data, _ in dataset:
        """
        data张量是一个代表图像的张量,通常具有三个维度:(通道, 高度, 宽度)。
        dim=(1, 2)参数指定了要在高度和宽度维度上进行求均值的操作。
        计算每个通道上的像素值的平均值,得到的结果是一个包含每个通道上的平均值的张量。
        """
        mean += torch.mean(data, dim=(1, 2))
        std += torch.std(data, dim=(1, 2))
    
    # Calculate the population mean and std
    mean /= total_samples
    std /= total_samples
    
    return mean, std


if __name__ == "__main__":
    # 定义数据转换
    transform = transforms.Compose([transforms.ToTensor()])
    # get data root path
    data_root = os.path.abspath(os.path.join(os.getcwd(), "../"))
    # flower data set path
    image_path = os.path.join(data_root, "data_set", "flower_data")
    # 加载数据集
    dataset = datasets.ImageFolder(root=os.path.join(image_path, "train"), transform=transform)
    # calculate mean and std
    mean, std = calculate_mean_std(dataset)
    print("Mean:", mean)
    print("Std:", std)

3.问题层层解析

(1)怎样加速收敛数度?

        通过标准化,模型在训练期间更容易学习到数据的分布,从而提高了梯度下降的效率。

(2)为什么可以提高梯度下降的效率?

        1.更快的收敛速度

        在神经网络训练中,如果输入数据的尺度相差很大,可能会导致梯度更新不平衡,进而影响训练速度。通过标准化,可以确保输入数据的尺度基本一致,有助于更快地找到全局最优解或局部最优解。

        2.更好的数值稳定性

        标准化可以使得输入数据的均值接近于零,从而使得激活函数的输入更接近于线性变换的范围,有助于避免梯度消失或梯度爆炸等数值问题,提高了梯度下降算法的稳定性。

        3.减少训练时的振荡

        在梯度下降的过程中,如果数据的尺度不一致,可能会导致训练过程中的振荡现象,即在损失函数表面上来回跳动。通过标准化,可以减少这种振荡,使得训练过程更加稳定。

        4.更好的收敛路径

        标准化后的数据使得损失函数的形状更加规则,更接近于一个圆形或球形,而不是一个细长的椭圆形。这样可以使得梯度下降更容易找到最优解,从而提高了训练的效率。

(3) 什么叫数据的尺度一致?为什么激活函数的输入要近于线性变换的范围?为什么损失函数表面上来回跳动?为什么损失函数的形状是一个圆形或球形?

        1.数据的尺度一致

        数据的尺度一致意味着不同特征之间的取值范围差异较小。在机器学习中,不同特征可能具有不同的量纲和尺度。如果不同特征之间的尺度相差很大,比如一个特征的取值范围在 0 到 1 之间,另一个特征的取值范围在 100 到 1000 之间,这种情况下模型可能会因为不同尺度的影响而训练不稳定,收敛速度慢。

        2.激活函数的输入近于线性变换的范围

        大多数深度学习模型使用的激活函数(如ReLU、Sigmoid、Tanh等)在输入较大或较小的时候,会表现出较小的梯度,这可能导致梯度消失或梯度爆炸的问题。如果输入数据被标准化,使得输入的均值接近于零,标准差接近于1,那么激活函数的输入就会落在接近线性变换的范围内,这有助于避免梯度消失或梯度爆炸。

        3.损失函数表面上来回跳动

        这种现象通常出现在损失函数表面非常不规则、有很多局部最小值和鞍点的情况下。当学习率过高时,梯度下降算法可能会在损失函数表面上来回跳动,而不是朝着收敛方向移动。这种情况下,模型的训练过程会变得不稳定,收敛速度变慢。

        4.损失函数的形状是一个圆形或球形

        当数据经过标准化处理后,不同特征之间的尺度一致,且取值范围较小,这会使得损失函数的形状更加规则。在高维空间中,这样的数据点分布形成的超球面(hypersphere)形状,通常会使得损失函数的形状更接近于一个圆形或球形。这种形状对于优化算法来说更容易处理,因为它没有像椭圆形那样的突起或陡峭区域,从而减少了算法在搜索最优解时的困难程度。

        (4)激活函数的作用

        1.什么是激活函数,为什么需要激活函数?

        激活函数是在神经网络层间输入与输出之间的一种函数变换,目的是为了加入非线性因素,增强模型的表达能力。

2.了解那些激活函数以及应用?

        主要分两类(饱和/非饱和),以及应用场景等。有时候可能特定到具体经典模型,

        比如LSTM用到Tanh,Transfromer中用到的ReLU,Bert中的GeLU,YOLO的Leaky ReLU等。

3.梯度消失与梯度爆炸现象与原因以及解决办法?

        梯度消失是指在反向传播过程中,梯度值逐层减小,最终变得非常接近于零。

    1. 使用更合适的激活函数:ReLU 和其变种(如 Leaky ReLU、ELU)在输入较大时具有较大的梯度,可以一定程度上缓解梯度消失问题。
    2. 使用 Batch Normalization:Batch Normalization 在每一层的输出进行标准化处理,有助于缓解梯度消失问题。
    3. 使用残差连接(Residual Connections):在深度神经网络中使用残差连接可以使得梯度更容易地传播,从而减轻梯度消失的影响。
    4. 使用梯度裁剪(Gradient Clipping):设置梯度的阈值,防止梯度爆炸。

        梯度爆炸是指在反向传播过程中,梯度值逐层增大,最终变得非常大。这通常发生在模型中存在梯度值异常增大的情况,例如网络权重初始化不合适、学习率过高等

    1. 使用梯度裁剪(Gradient Clipping):设置梯度的阈值,当梯度超过阈值时进行裁剪,以避免梯度爆炸。
    2. 使用更小的学习率:减小学习率可以减缓梯度的增长速度,从而降低梯度爆炸的可能性。
    3. 使用合适的权重初始化方法:合适的权重初始化可以避免初始时梯度爆炸的发生。例如,使用 Xavier 初始化或 He 初始化。
    4. 使用稳定的优化器:一些优化器(如 Adam、RMSProp)具有自适应学习率的特性,可以更好地处理梯度爆炸问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

呆呆珝

您的打赏是我的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值