transforms.Normalize()

这篇具有很好参考价值的文章主要介绍了transforms.Normalize()。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1、定义:数据标准化处理:transforms.Normalize():transforms.Normalize:数据标准化,即均值为0,标准差为1。

简单来说就是将数据按通道进行计算,将每一个通道的数据先计算出其方差与均值,然后再将其每一个通道内的每一个数据减去均值,再除以方差,得到归一化后的结果。
在深度学习图像处理中,标准化处理之后,可以使数据更好的响应激活函数,提高数据的表现力,减少梯度爆炸和梯度消失的出现。

Normalize a tensor image with mean and standard deviation. this transform will normalize each channel of the input torch.*Tensor i.e., output[channel] = (input[channel] - mean[channel]) / std[channel]
先看示例代码:

import torchvision.transforms as transforms
train_transforms = transforms.Compose(
        [transforms.RandomResizedCrop(size=256, scale=(0.8, 1.0)),  # 随机裁剪到256*256
         transforms.RandomRotation(degrees=15),  # 随机旋转
         transforms.RandomHorizontalFlip(),  # 随机水平翻转
         transforms.CenterCrop(size=224),  # 中心裁剪到224*224
         # 转化成张量,#归一化[0,1](是将数据除以255),
         # transforms.ToTensor()会把HWC会变成C *H *W(拓展:格式为(h,w,c),像素顺序为RGB)
         transforms.ToTensor(),
         transforms.Normalize([0.485, 0.456, 0.406],
                              [0.229, 0.224, 0.225])  # 标准化
         ])

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

Imagenet数据集的均值和方差为:mean=(0.485, 0.456, 0.406),std=(0.229, 0.224, 0.225),因为这是在百万张图像上计算而得的,所以我们通常见到在训练过程中使用它们做标准化。而对于特定的数据集,选择这个值的结果可能并不理想。接下来给出计算特定数据集的均值和方差的方法。

import torch
from torchvision.datasets import ImageFolder


def getStat(train_data):
    '''
    Compute mean and variance for training data
    :param train_data: 自定义类Dataset(或ImageFolder即可)
    :return: (mean, std)
    '''
    print('Compute mean and variance for training data.')
    print(len(train_data))
    train_loader = torch.utils.data.DataLoader(
        train_data, batch_size=1, shuffle=False, num_workers=0,
        pin_memory=True)
    mean = torch.zeros(3)
    std = torch.zeros(3)
    for X, _ in train_loader:
        for d in range(3):
            mean[d] += X[:, d, :, :].mean()
            std[d] += X[:, d, :, :].std()
    mean.div_(len(train_data))
    std.div_(len(train_data))
    return list(mean.numpy()), list(std.numpy())


if __name__ == '__main__':
    train_dataset = ImageFolder(root=r'./data/food/', transform=None)
    print(getStat(train_dataset))

2. 图像预处理Transforms(主要讲解数据标准化)
2.1 理解torchvision
transforms属于torchvision模块的方法,它是常见的图像预处理的方法
在这里贴上别人整理的transforms运行机制:
transforms.Normalize()

 可以看出torchvision工具包中包含三个主要模块,主要讲解学习transforms

torchvision.transforms:常用的数据预处理方法,提升泛化能力
包括:数据中心化、数据标准化、缩放、裁剪、旋转、翻转、填充、噪声添加、灰度变换、线性变换、仿射变换、亮度、饱和度及对比度变换等

2.2 数据标准化——transforms.normalize()
功能:逐channel的对图像进行标准化(均值变为0,标准差变为1),可以加快模型的收敛
output = (input - mean) / std
mean:各通道的均值
std:各通道的标准差
inplace:是否原地操作
思考:
(1)据我所知,归一化就是要把图片3个通道中的数据整理到[-1, 1]区间。
x = (x - mean(x))/std(x)
只要输入数据集x确定了,mean(x)和std(x)也就是确定的数值了,为什么Normalize()函数还需要输入mean和std的数值呢????

(2)RGB单个通道的值是[0, 255],所以一个通道的均值应该在127附近才对。
如果Normalize()函数去计算 x = (x - mean)/std ,因为RGB是[0, 255],算出来的x就不可能落在[-1, 1]区间了。

(3)在我看的了论文代码里面是这样的:
torchvision.transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
为什么就确定了这一组数值,这一组数值是怎么来的? 为什么这三个通道的均值都是小于1的值呢?
理解:
(1)针对第一个问题,mean 和 std 肯定要在normalize()之前自己先算好再传进去的,不然每次normalize()就得把所有的图片都读取一遍算这两个
(2)针对第二个问题,有两种情况
(a )如果是imagenet数据集,那么ImageNet的数据在加载的时候就已经转换成了[0, 1].
(b) 应用了torchvision.transforms.ToTensor,其作用是将数据归一化到[0,1](是将数据除以255),transforms.ToTensor()会把HWC会变成C *H *W(拓展:格式为(h,w,c),像素顺序为RGB)
(3)针对第三个问题:[0.485, 0.456, 0.406]这一组平均值是从imagenet训练集中抽样算出来的。
继续有疑问:
ToTensor 已经[0,1]为什么还要[0.485, 0.456, 0.406]?那么归一化后为什么还要接一个Normalize()呢?Normalize()是对数据按通道进行标准化,即减去均值,再除以方差
解答:
别人的解答:数据如果分布在(0,1)之间,可能实际的bias,就是神经网络的输入b会比较大,而模型初始化时b=0的,这样会导致神经网络收敛比较慢,经过Normalize后,可以加快模型的收敛速度。
因为对RGB图片而言,数据范围是[0-255]的,需要先经过ToTensor除以255归一化到[0,1]之后,再通过Normalize计算过后,将数据归一化到[-1,1]。
是否可以这样理解:
[0,1]只是范围改变了, 并没有改变分布,mean和std处理后可以让数据正态分布😂
参考:
pytorch torchvision.transforms.Normalize()中的mean和std参数—解惑
pytorch的transform中ToTensor接着Normalize
另外这篇包含数据增强部分:
Pytorch框架学习(6)——transforms与normalize
拓展:
数据增强又称为数据增广,数据扩增,它是对训练集进行变换,使训练集更丰富,从而让模型更具泛化能力。

3、通过例子解读:

问题:

transform.ToTensor(),
transform.Normalize((0.5,0.5,0.5),(0.5,0.5,0.5))

究竟是什么意思?(0.5,0.5,0.5),(0.5,0.5,0.5)又是怎么来的呢?

transform.ToTensor()

  1. 是将输入的数据shape W,H,C ——> C,W,H
  2. 将所有数除以255,将数据归一化到【0,1】

ToTensor的作用是将导入的图片转换为Tensor的格式,导入的图片为PIL image 或者 numpy.nadrry格式的图片,其shape为(H x W x C)数值范围在[0,255],转换之后shape为(C x H x W),数值范围在[0,1]。
 

代码示例

import torch
import numpy as np
from torchvision import transforms
import cv2
#自定义图片数组,数据类型一定要转为‘uint8’,不然transforms.ToTensor()不会归一化
data = np.array([
                [[1,1,1],[1,1,1],[1,1,1],[1,1,1],[1,1,1]],
                [[2,2,2],[2,2,2],[2,2,2],[2,2,2],[2,2,2]],
                [[3,3,3],[3,3,3],[3,3,3],[3,3,3],[3,3,3]],
                [[4,4,4],[4,4,4],[4,4,4],[4,4,4],[4,4,4]],
                [[5,5,5],[5,5,5],[5,5,5],[5,5,5],[5,5,5]]
        ],dtype='uint8')
print(data)
print(data.shape)   #(5,5,3)
data = transforms.ToTensor()(data)
print(data)
print(data.shape)	#(3,5,5)

输出:
tensor([[[0.0039, 0.0039, 0.0039, 0.0039, 0.0039],
         [0.0078, 0.0078, 0.0078, 0.0078, 0.0078],
         [0.0118, 0.0118, 0.0118, 0.0118, 0.0118],
         [0.0157, 0.0157, 0.0157, 0.0157, 0.0157],
         [0.0196, 0.0196, 0.0196, 0.0196, 0.0196]],

        [[0.0039, 0.0039, 0.0039, 0.0039, 0.0039],
         [0.0078, 0.0078, 0.0078, 0.0078, 0.0078],
         [0.0118, 0.0118, 0.0118, 0.0118, 0.0118],
         [0.0157, 0.0157, 0.0157, 0.0157, 0.0157],
         [0.0196, 0.0196, 0.0196, 0.0196, 0.0196]],

        [[0.0039, 0.0039, 0.0039, 0.0039, 0.0039],
         [0.0078, 0.0078, 0.0078, 0.0078, 0.0078],
         [0.0118, 0.0118, 0.0118, 0.0118, 0.0118],
         [0.0157, 0.0157, 0.0157, 0.0157, 0.0157],
         [0.0196, 0.0196, 0.0196, 0.0196, 0.0196]]])

transforms.Normalize()

看了许多文章,都是说:transform.Normalize()通过公式

x = (x - mean) / std

即同一纬度的数据减去这一维度的平均值,再除以标准差,将归一化后的数据变换到【-1,1】之间。可真是这样吗??

求解mean和std

我们需要求得一批数据的mean和std,代码如下:

import torch
import numpy as np
import torchvision.transforms as transforms
# 这里以上述创建的单数据为例子
data = np.array([
    [[1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1]],
    [[2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2]],
    [[3, 3, 3], [3, 3, 3], [3, 3, 3], [3, 3, 3], [3, 3, 3]],
    [[4, 4, 4], [4, 4, 4], [4, 4, 4], [4, 4, 4], [4, 4, 4]],
    [[5, 5, 5], [5, 5, 5], [5, 5, 5], [5, 5, 5], [5, 5, 5]]
], dtype='uint8')
# 将数据转为C,W,H,并归一化到[0,1]
data = transforms.ToTensor()(data)
# 需要对数据进行扩维,增加batch维度
data = torch.unsqueeze(data, 0) # tensor([1, 3, 5, 5])
nb_samples = 0.
# 创建3维的空列表
channel_mean = torch.zeros(3) # tensor([0., 0., 0.])
channel_std = torch.zeros(3) # tensor([0., 0., 0.])
print(data.shape) # torch.Size([1, 3, 5, 5])
N, C, H, W = data.shape[:4] # shape是一个列表, N:1 C:3 H:5 W:5
data = data.view(N, C, -1)  # 将w,h维度的数据展平,为batch,channel,data,然后对三个维度上的数分别求和和标准差
print(data.shape) # tensor([1, 3, 25])
# 展平后,w,h属于第二维度,对他们求平均,sum(0)为将同一纬度的数据累加
channel_mean += data.mean(2).sum(0)
# 展平后,w,h属于第二维度,对他们求标准差,sum(0)为将同一纬度的数据累加
channel_std += data.std(2).sum(0)
# 获取所有batch的数据,这里为1
nb_samples += N
# 获取同一batch的均值和标准差
channel_mean /= nb_samples
channel_std /= nb_samples
print(channel_mean, channel_std)
# tensor([0.0118, 0.0118, 0.0118]) tensor([0.0057, 0.0057, 0.0057])



以此便可求得均值和标准差。我们再带入公式:

x = (x - mean) / std

自己实现

data = np.array([
                [[1,1,1],[1,1,1],[1,1,1],[1,1,1],[1,1,1]],
                [[2,2,2],[2,2,2],[2,2,2],[2,2,2],[2,2,2]],
                [[3,3,3],[3,3,3],[3,3,3],[3,3,3],[3,3,3]],
                [[4,4,4],[4,4,4],[4,4,4],[4,4,4],[4,4,4]],
                [[5,5,5],[5,5,5],[5,5,5],[5,5,5],[5,5,5]]
        ],dtype='uint8')
data = transforms.ToTensor()(data)
for i in range(3):
    data[i,:,:] = (data[i,:,:] - channel_mean[i]) / channel_std[i]
print(data)

输出:
tensor([[[-1.3856, -1.3856, -1.3856, -1.3856, -1.3856],
         [-0.6928, -0.6928, -0.6928, -0.6928, -0.6928],
         [ 0.0000,  0.0000,  0.0000,  0.0000,  0.0000],
         [ 0.6928,  0.6928,  0.6928,  0.6928,  0.6928],
         [ 1.3856,  1.3856,  1.3856,  1.3856,  1.3856]],

        [[-1.3856, -1.3856, -1.3856, -1.3856, -1.3856],
         [-0.6928, -0.6928, -0.6928, -0.6928, -0.6928],
         [ 0.0000,  0.0000,  0.0000,  0.0000,  0.0000],
         [ 0.6928,  0.6928,  0.6928,  0.6928,  0.6928],
         [ 1.3856,  1.3856,  1.3856,  1.3856,  1.3856]],

        [[-1.3856, -1.3856, -1.3856, -1.3856, -1.3856],
         [-0.6928, -0.6928, -0.6928, -0.6928, -0.6928],
         [ 0.0000,  0.0000,  0.0000,  0.0000,  0.0000],
         [ 0.6928,  0.6928,  0.6928,  0.6928,  0.6928],
         [ 1.3856,  1.3856,  1.3856,  1.3856,  1.3856]]])

官方实现

data = np.array([
                [[1,1,1],[1,1,1],[1,1,1],[1,1,1],[1,1,1]],
                [[2,2,2],[2,2,2],[2,2,2],[2,2,2],[2,2,2]],
                [[3,3,3],[3,3,3],[3,3,3],[3,3,3],[3,3,3]],
                [[4,4,4],[4,4,4],[4,4,4],[4,4,4],[4,4,4]],
                [[5,5,5],[5,5,5],[5,5,5],[5,5,5],[5,5,5]]
        ],dtype='uint8')
data = transforms.ToTensor()(data)
data = transforms.Normalize(channel_mean, channel_std)(data)
print(data)

输出:
tensor([[[-1.3856, -1.3856, -1.3856, -1.3856, -1.3856],
         [-0.6928, -0.6928, -0.6928, -0.6928, -0.6928],
         [ 0.0000,  0.0000,  0.0000,  0.0000,  0.0000],
         [ 0.6928,  0.6928,  0.6928,  0.6928,  0.6928],
         [ 1.3856,  1.3856,  1.3856,  1.3856,  1.3856]],

        [[-1.3856, -1.3856, -1.3856, -1.3856, -1.3856],
         [-0.6928, -0.6928, -0.6928, -0.6928, -0.6928],
         [ 0.0000,  0.0000,  0.0000,  0.0000,  0.0000],
         [ 0.6928,  0.6928,  0.6928,  0.6928,  0.6928],
         [ 1.3856,  1.3856,  1.3856,  1.3856,  1.3856]],

        [[-1.3856, -1.3856, -1.3856, -1.3856, -1.3856],
         [-0.6928, -0.6928, -0.6928, -0.6928, -0.6928],
         [ 0.0000,  0.0000,  0.0000,  0.0000,  0.0000],
         [ 0.6928,  0.6928,  0.6928,  0.6928,  0.6928],
         [ 1.3856,  1.3856,  1.3856,  1.3856,  1.3856]]])

我们观察数据发现,通过求解的均值和标准差,求得的标准化的值,并非在【-1,1】,( 借此谴责部分博客 )。

结论
经过这样处理后将数据标准化,即均值为0,标准差为1。使模型更容易收敛。并非是归于【-1,1】!!

很多人纠结经过transforms.Normalize数据是否服从正态分布。
我这里简单的说一下经过transforms.Normalize数据不一定服从正态分布!
这里减去均值,除以标准差只是将数据进行标准化处理,并不会改变原始数据的分布!
另外是每一个channels上所有batch的数据服从均值为0,标准差为1。
如有疑问,请及时留言。
————————————————
参考文章:
1、pytorch中归一化transforms.Normalize的真正计算过程_月光下的小趴菜的博客-CSDN博客
2、数据归一化处理transforms.Normalize()_幼稚园的扛把子~的博客-CSDN博客_transforms.normalize文章来源地址https://www.toymoban.com/news/detail-448786.html

到了这里,关于transforms.Normalize()的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • torch.nn.functional.normalize参数说明

    公式为 v max ⁡ ( ∥ v ∥ p , ϵ ) frac{v}{max(lVert v rVert_p, epsilon)} max (∥ v ∥ p ​ , ϵ ) v ​ F.normalize(data, p=2/1, dim=0/1/-1) 将某一个维度除以那个维度对应的范数(默认是2范数) input:输入的数据(tensor) p:L2/L1_norm运算,(默认是2范数) dim:0表示按列操作,则每列都是除以该列下平方

    2024年02月05日
    浏览(38)
  • MATLAB——数据归一化处理(normalize函数)

    数据归一化: 数据的归一化是特征缩放(feature scaling)的方法,是数据预处理的关键步骤。不同评价指标往往具有不同的量纲和量纲单位,这样的情况会影响到数据分析的结果,为了消除指标之间的量纲影响,需要进行数据归一化处理,以解决数据指标之间的可比性。原始数据

    2024年02月22日
    浏览(40)
  • 【知识---如何进行图像数据的归一化呢(normalize)】

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 在做基于图像的目标检测遇到了图像的归一化操作,为此展开了一定的探讨: 图像归一化是指对图像进行了一系列标准的处理变换,使之变换为一固定标准形式的过程,该标准图像称作归一化图像。 这

    2024年01月19日
    浏览(54)
  • OpenCV-Python学习(17)—— OpenCV 图像像素类型转换与归一化(cv.normalize)

    1. 学习目标 学习 OpenCV 图像像素的类型转换; 学习 OpenCV 归一化函数。 2. OpenCV 图像像素的类型转换 由于【在 OpenCV-Python 中一切图像数据皆 numpy.array】,因此像素的类型转换可以直接使用 numpy 的类型转换方法。 2.1 将像素转换为 float32 2.2 数据输出结果 2.3 图像输出结果 3. 归一

    2024年02月05日
    浏览(68)
  • new THREE.Vector3(1, 1, 1).normalize();mesh.translateOnAxis(axis, 100);两个方法介绍,

    `new THREE.Vector3(1, 1, 1).normalize()` 是一个使用Three.js库中`Vector3`对象的方法,用于将一个三维向量归一化(normalize)。具体说明如下: 在Three.js中,`Vector3`是一个表示三维向量的对象。使用`new THREE.Vector3(x, y, z)`构造一个新的向量对象,其中`x`、`y`、`z`分别表示向量在X轴、Y轴和

    2024年02月12日
    浏览(46)
  • OpenCV的函数normalize()的两个作用:调整矩阵的值范围(归一化处理)、规范化矩阵的范数为某个值

    OpenCV的函数normalize()的两个作用:调整矩阵的值范围(归一化处理)、规范化矩阵的范数为某个值 函数normalize()有两个原型: 原型一: 原型二: 原型一的适用对象是密集矩阵,通常我们的矩阵都是密集矩阵。 原型二的适用对象是稀疏矩阵,在这篇博文中暂不作介绍。 在介绍各参

    2024年02月06日
    浏览(43)
  • OpenCV中的normalize函数以及NORM_MINMAX、NORM_INF、NORM_L1、NORM_L2具体应用介绍

    在OpenCV中,normalize函数用于将图像或矩阵的值规范化到一个特定的范围内。这在图像处理中非常有用,比如在调整图像的对比度、准备数据进行机器学习处理时。规范化可以提高不同图像之间的可比性,或是为了满足特定算法对数据范围的要求。 src:输入数组(可以是图像)

    2024年02月22日
    浏览(47)
  • Transformer---ViT:vision transformer

    记录一下对transformer方法在计算机视觉任务中的应用方法的理解 参考博客:https://blog.csdn.net/weixin_42392454/article/details/122667271 参考代码:https://gitcode.net/mirrors/Runist/torch_vision_transformer?utm_source=csdn_github_accelerator 模型网络图 假设输入维度为[B, C, H, W],假设其中C=3,H=224,W=224 假设patch_s

    2024年02月12日
    浏览(40)
  • FLatten Transformer 简化版Transformer

    今天在找论文时,看到一篇比较新奇的论文,在这里跟大家分享一下,希望可以给一些人提供一些思路。虽然现在Transformer 比较火,在分割上面也应用的比较多,但是我一直不喜欢用,其中一个原因是结构太复杂了,平时我主要用一个sel-attention 感觉都有点复杂了,如果用多

    2024年02月13日
    浏览(38)
  • Transformer [全网最详细的Transformer讲解]

    先看 Transformer 的整体框架: 可能看起来很复杂,但其实还是 Encoder 和 Decoder {seq2seq}的框架。默认NX=6 ,6层 Encoder 和 6层 Decoder 嵌套中嵌套了上次讲的 Self-Attention ,再进行多次非线性变换。 上图的框架很复杂,由于 Transformer 最初是作为翻译模型,我们举例先带大家理解用

    2024年02月12日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包