为什么Pytorch官方使用均值=[0.485,0.456,0.406]和标准差=[0.229,0.224,0.225]来归一化图像?

neekobn8  于 2023-01-30  发布在  其他
关注(0)|答案(4)|浏览(159)

在此页面(https://pytorch.org/vision/stable/models.html)中,它指出“所有预训练模型都希望输入图像以相同的方式归一化,即形状为(3 x H x W)的3通道RGB图像的小型批处理,其中H和W预计至少为224。图像必须加载到范围[0,1]中,然后使用mean = [0.485, 0.456, 0.406]std = [0.229, 0.224, 0.225]归一化“。
正常化的meanstd不应该是[0.5, 0.5, 0.5][0.5, 0.5, 0.5]吗,为什么设置这么奇怪的值?

3z6pesqy

3z6pesqy1#

使用Imagenet的平均值和标准差是一种常见做法。它们是基于数百万张图像计算的。如果要在自己的数据集上从头开始训练,可以计算新的平均值和标准差。否则,建议使用具有自己的平均值和标准差的Imagenet预训练模型。

lpwwtiir

lpwwtiir2#

在这个例子中,他们使用ImageNet的mean和stddev,但是如果您看一下他们的MNIST例子,mean和stddev是一维的(因为输入是灰度的--没有RGB通道)。
是否使用ImageNet's均值和标准差取决于您的数据。假设您的数据是“自然场景”的普通照片†(人物、建筑物、动物、各种照明/Angular /背景等),并假设您的数据集与ImageNet的偏差方式相同(就类别平衡而言),那么就可以使用ImageNet的场景统计数据进行归一化。(颜色过滤、对比度调整、不常见的照明等)或“非自然主题”(医学图像、卫星图像、手绘等),那么我建议在模型训练之前正确地归一化数据集!*
下面是一些示例代码,可以帮助您入门:

import os
import torch
from torchvision import datasets, transforms
from torch.utils.data.dataset import Dataset
from tqdm.notebook import tqdm
from time import time

N_CHANNELS = 1

dataset = datasets.MNIST("data", download=True,
                 train=True, transform=transforms.ToTensor())
full_loader = torch.utils.data.DataLoader(dataset, shuffle=False, num_workers=os.cpu_count())

before = time()
mean = torch.zeros(1)
std = torch.zeros(1)
print('==> Computing mean and std..')
for inputs, _labels in tqdm(full_loader):
    for i in range(N_CHANNELS):
        mean[i] += inputs[:,i,:,:].mean()
        std[i] += inputs[:,i,:,:].std()
mean.div_(len(dataset))
std.div_(len(dataset))
print(mean, std)

print("time elapsed: ", time()-before)

†在计算机视觉中,“自然场景”有一个特定的含义,与自然和人造无关,参见https://en.wikipedia.org/wiki/Natural_scene_perception

  • 否则,由于损失函数的延长,您将遇到优化问题--参见my answer here
7cwmlq89

7cwmlq893#

我无法按计划计算标准差,但使用了下面的代码。灰度imagenet的训练数据集均值和标准差是(四舍五入到你喜欢的程度):
平均值:0.44531356896770125
标准偏差:0.2692461874154524

def calcSTD(d):
    meanValue = 0.44531356896770125
    squaredError = 0
    numberOfPixels = 0
    for f in os.listdir("/home/imagenet/ILSVRC/Data/CLS-LOC/train/"+str(d)+"/"): 
        if f.endswith(".JPEG"):
            
            image = imread("/home/imagenet/ILSVRC/Data/CLS-LOC/train/"+str(d)+"/"+str(f))
                
            ###Transform to gray if not already gray anyways  
            if  np.array(image).ndim == 3:
                matrix = np.array(image)
                blue = matrix[:,:,0]/255
                green = matrix[:,:,1]/255
                red = matrix[:,:,2]/255
                gray = (0.2989 * red + 0.587 * green + 0.114 * blue)
            else:
                gray = np.array(image)/255
            ###----------------------------------------------------       
                    
            for line in gray:
                for pixel in line:

                    squaredError += (pixel-meanValue)**2
                    numberOfPixels += 1
    
    return (squaredError, numberOfPixels)

a_pool = multiprocessing.Pool()
folders = []
[folders.append(f.name) for f in os.scandir("/home/imagenet/ILSVRC/Data/CLS-LOC/train") if f.is_dir()]
resultStD = a_pool.map(calcSTD, folders)

StD = (sum([intensity[0] for intensity in resultStD])/sum([pixels[1] for pixels in resultStD]))**0.5
print(StD)

来源:https://stackoverflow.com/a/65717887/7156266

qyzbxkaa

qyzbxkaa4#

靶区; DR

我相信原因是,就像(深度)机器学习中的许多事情一样,它碰巧工作得很好。

详情

统计中的"标准化"一词可以应用于不同的转换。例如:for all x in X: x->(x - min(x))/(max(x)-min(x)将X的值归一化并拉伸至[0..1]范围。
另一个例子:for all x in X: x->(x - mean(X))/stdv(x)将图像变换为平均值= 0,标准差= 1。此变换称为标准得分,有时称为标准化。如果将结果乘以sigma,并加上mu,则将结果设置为平均值= mu且stdv = sigma
PyTorch不做任何这些--相反,它应用标准分数,但不是X(要规范化的图像)的平均值和标准差,而是在一个大的Imagenet图像集上的平均值和平均标准差,但不将平均值和标准差 * 设置 * 为这些值。
如果图像恰好具有与Imagenet集合的平均值相同的平均值和标准差,则它将被转换为平均值0和标准差1。否则,它将转换为其平均值和标准差以及所述平均值的函数。
对我来说,不清楚这严格地意味着什么(为什么是标准差的平均值?,为什么对平均值应用标准分?)。
也许有人能澄清这一点?
然而,就像深度机器学习中的许多事情一样,这个理论还没有完全建立起来。我的猜测是,人们已经尝试了不同的归一化,而这一种只是碰巧表现良好。
这并不意味着这是最好的归一化,只是一个不错的归一化。当然,如果你使用的是通过这个特定的归一化学习到的预训练值,那么你可能更好地使用与训练中使用的相同的归一化来进行推理或派生模型。

相关问题