1. 均值、方差

在进行网络训练时经常会看到这样的代码:

  1. self.image_transform=transforms.Compose([
  2. transforms.Resize((self.size,self.size)),
  3. transforms.ToTensor(),
  4. transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
  5. ])

其中transforms.Normalize()是对数据进行归一化,第一个参数[0.485, 0.456, 0.406]是均值(mean),第二个参数[0.229, 0.224, 0.225]是方差(std)。
这两个参数([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])在Pytorch官方教程中经常出现,它其实是对ImageNet数据集抽样计算出来的。

2. 计算均值、方差

如果要对自己的数据集计算均值和方差,那么就需要自己使用代码去计算。
搜索了网上计算mean和std的代码,大致分为以下两种:
1)手动累加计算

  1. import os
  2. from PIL import Image
  3. import numpy as np
  4. def cal_mean_std_2():
  5. filepath = 'D:\\Dataset\\OIP\\test_images'
  6. pathDir = os.listdir(filepath)
  7. R_channel = 0
  8. G_channel = 0
  9. B_channel = 0
  10. for idx in range(len(pathDir)):
  11. filename = pathDir[idx]
  12. with open(os.path.join(filepath, filename),'rb') as f:
  13. img=Image.open(f).convert('RGB')
  14. img=np.asarray(img)/255.
  15. R_channel = R_channel + np.sum(img[:, :, 0])
  16. G_channel = G_channel + np.sum(img[:, :, 1])
  17. B_channel = B_channel + np.sum(img[:, :, 2])
  18. num = len(pathDir) * 256 * 256
  19. R_mean = R_channel / num
  20. G_mean = G_channel / num
  21. B_mean = B_channel / num
  22. R_channel = 0
  23. G_channel = 0
  24. B_channel = 0
  25. for idx in range(len(pathDir)):
  26. filename = pathDir[idx]
  27. with open(os.path.join(filepath, filename),'rb') as f:
  28. img=Image.open(f).convert('RGB')
  29. img=np.asarray(img)/255.
  30. R_channel = R_channel + np.sum((img[:, :, 0] - R_mean) ** 2)
  31. G_channel = G_channel + np.sum((img[:, :, 1] - G_mean) ** 2)
  32. B_channel = B_channel + np.sum((img[:, :, 2] - B_mean) ** 2)
  33. R_var = np.sqrt(R_channel / num)
  34. G_var = np.sqrt(G_channel / num)
  35. B_var = np.sqrt(B_channel / num)
  36. print("R_mean is %f, G_mean is %f, B_mean is %f" % (R_mean, G_mean, B_mean))
  37. print("R_var is %f, G_var is %f, B_var is %f" % (R_var, G_var, B_var))

2)内置函数计算
  1. import os
  2. from PIL import Image
  3. import numpy as np
  4. def cal_mean_std():
  5. image_path='D:\\Dataset\\OIP\\test_images'
  6. image_list=[]
  7. file_names=os.listdir(image_path)
  8. means = [0, 0, 0]
  9. stdevs = [0, 0, 0]
  10. for name in file_names:
  11. if name.endswith('.jpg'):
  12. image_list.append(os.path.join(image_path,name))
  13. for image in image_list:
  14. with open(image,'rb') as f:
  15. img=Image.open(f).convert('RGB')
  16. img=np.asarray(img)/255.
  17. # print(img.dtype)
  18. for i in range(3):
  19. means[i] += img[:, :, i].mean()
  20. stdevs[i] += img[:, :, i].std()
  21. # means.reverse()
  22. # stdevs.reverse()
  23. mean = np.asarray(means) / len(image_list)
  24. std = np.asarray(stdevs) / len(image_list)
  25. print("mean:{},std:{}".format(mean,std))

3)计算结果对比

image.png
第一行是方法2的结果,第二和三行是方法1的结果
观看结果可以看出:

  • 两种方法均值计算结果大致相同,结果的精确度有差异
  • 方差计算结果差异较大

个人分析原因是mean的精度不同,两者产生一定的误差。因此在计算std的过程中,误差被平方计算扩大了。
因此,最终选择方法2作为计算mean和std的方法。