为啥 Pytorch 官方使用 mean=[0.485, 0.456, 0.406] 和 std=[0.229, 0.224, 0.225] 来规范化图像?
Posted
技术标签:
【中文标题】为啥 Pytorch 官方使用 mean=[0.485, 0.456, 0.406] 和 std=[0.229, 0.224, 0.225] 来规范化图像?【英文标题】:Why Pytorch officially use mean=[0.485, 0.456, 0.406] and std=[0.229, 0.224, 0.225] to normalize images?为什么 Pytorch 官方使用 mean=[0.485, 0.456, 0.406] 和 std=[0.229, 0.224, 0.225] 来规范化图像? 【发布时间】:2020-01-28 18:44:54 【问题描述】:在此页面 (https://pytorch.org/vision/stable/models.html) 中,它说“所有预训练模型都期望输入图像以相同方式归一化,即小批量 3 通道 RGB 图像的形状 (3 x H x W),其中 H 和 W 预计至少为 224。图像必须加载到 [0, 1] 的范围内,然后使用 mean = [0.485, 0.456, 0.406]
和 std = [0.229, 0.224, 0.225]
" 进行归一化。
通常的mean
和std
不应该是[0.5, 0.5, 0.5]
和[0.5, 0.5, 0.5]
吗?为什么会设置这么奇怪的值?
【问题讨论】:
***.com/questions/57532661/… 【参考方案1】:使用 Imagenet 的均值和标准差是一种常见的做法。它们是根据数百万张图像计算得出的。如果您想在自己的数据集上从头开始训练,可以计算新的均值和标准差。否则,建议使用具有自己的均值和标准差的 Imagenet 预测试模型。
【讨论】:
【参考方案2】:在该示例中,他们使用 ImageNet 的均值和标准差,但如果您查看他们的 MNIST 示例,均值和标准差是一维的(因为输入是灰度 - 没有 RGB 通道)。
是否使用ImageNet's mean 和 stddev 取决于您的数据。假设您的数据是“自然场景”的普通照片†(人物、建筑物、动物、不同的照明/角度/背景等),并假设您的数据集以与 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。
【讨论】:
【参考方案3】:我无法按计划计算标准偏差,但使用下面的代码进行了计算。灰度图像网络的训练数据集均值和标准差为(任意取整):
平均值: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://***.com/a/65717887/7156266
【讨论】:
【参考方案4】:TL;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,我们会将结果设置为 mean=mu 和 stdv=sigma
Pytorch 不做任何这些 - 相反,它应用标准分数,但不是使用 X 的平均值和 stdv 值(要归一化的图像),而是使用平均平均值和平均 stdv 的值。 Imagenet 图像集。但不将均值和标准差设置为这些值。
如果图像恰好与 Imagenet 集合的平均值具有相同的均值和标准差 - 它将被转换为均值 0 和标准偏差 1。 否则,它将转换为它的平均值和标准差以及所述平均值的函数。
对我来说,不清楚这严格意味着什么(为什么是标准差平均值?为什么要对平均值应用标准分数?)。
也许有人可以澄清这一点?
但是,与深度机器学习中的许多事情一样,该理论尚未完全确立。我的猜测是人们尝试了不同的标准化,而这个恰好表现良好。
这并不意味着这是最好的标准化,只是说它是一个不错的标准化。当然,如果您使用的是使用此特定归一化学习的预训练值,您可能最好使用与训练中使用的相同的归一化进行推理或派生模型。
【讨论】:
以上是关于为啥 Pytorch 官方使用 mean=[0.485, 0.456, 0.406] 和 std=[0.229, 0.224, 0.225] 来规范化图像?的主要内容,如果未能解决你的问题,请参考以下文章
不只是支持Windows, PyTorch 0.4新版本变动详解与升级指南
为啥这个 Pytorch 官方教程中没有 .train() 方法?