原文鏈接:https://blog.csdn.net/weixin_37251044/article/details/81157344
### 1.什么是均值?對於每幀圖像來說,均值分為兩種:image mean 和 pixel mean。
image mean:
簡單的說,讀入一張彩色圖像,假設是(NN3),這時候,求出image mean的話,就也是\(N*N*3\),相當於把所有訓練集在同一個空間位置上的像素的對應通道求了均值,也就是caffe里生成的mean.binaryproto文件。
pixel mean:
而pixel mean的話,其實是把訓練集里面所有圖片的所有R通道像素,求了均值,G,B通道類似,也就是不考慮空間位置了。所以求出來就是三個數值(R_mean,G_mean,B_mean),所以其實就是把image mean再求了一次均值。
2.為什么要去均值?
2.1.從主成分分析(PCA)入手解釋
說白了就是數據特征標准化。
特征標准化指的是(獨立地)使得數據的每一個維度具有零均值和單位方差。這是歸一化中最常見的方法並被廣泛地使用(例如,在使用支持向量機(SVM)時,特征標准化常被建議用作預處理的一部分)。在實際應用中,特征標准化的具體做法是:首先計算每一個維度上數據的均值(使用全體數據計算),之后在每一個維度上都減去該均值。下一步便是在數據的每一維度上除以該維度上數據的標准差。
對於自然圖像,更多的是做圖像零均值化,並不需要估計樣本的方差。這是因為在自然圖像上進行訓練時,對每一個像素單獨估計均值和方差意義不大,因為(理論上)圖像任一部分的統計性質都應該和其它部分相同,圖像的這種特性被稱作平穩性(stationarity)。
對於圖像,這種歸一化可以移除圖像的平均亮度值 (intensity)。很多情況下我們對圖像的照度並不感興趣,而更多地關注其內容,比如在對象識別任務中,圖像的整體明亮程度並不會影響圖像中存在的是什么物體。這時對每個數據點移除像素的均值是有意義的。
2.2.從深度學習反向傳播計算入手
了解到基本在deep learning中只要你是使用gradient descent來訓練模型的話都要在數據預處理步驟進行數據歸一化。當然這也是有一定原因的。
根據公式$$ \frac{\alpha E}{\alpha W_{11}^2} = x_1 \delta_1^2 $$
如果輸入層 \(x\) 很大,在反向傳播時候傳遞到輸入層的梯度就會變得很大。梯度大,學習率就得非常小,否則會越過最優。在這種情況下,學習率的選擇需要參考輸入層數值大小,而直接將數據歸一化操作,能很方便的選擇學習率。而且受 \(x\) 和 \(w\) 的影響,各個梯度的數量級不相同,因此,它們需要的學習率數量級也就不相同。對 \(w_1\) 適合的學習率,可能相對於 \(w_2\) 來說會太小,如果仍使用適合 \(w_1\) 的學習率,會導致在 \(w_2\) 方向上走的非常慢,會消耗非常多的時間,而使用適合 \(w_2\) 的學習率,對 \({w_1}\) 來說又太大,搜索不到適合 \({w_1}\) 的解。
3.代碼
3.1 圖像去均值(image mean)
# Normalize the data: subtract the mean image
X_train = sum_img
print ("減去均值之前,X_train的第一幅圖像的RGB通道的第一個通道的圖像數值32*32:")
print (X_train[0][0])
mean_image = np.mean(X_train, axis=0)
#shape=(3,32, 32) 這里axis=0表示按照列算均值,在這里是將所有圖像的R圖上的每個像素點的數值取平均,G,B通道同理,這里是image mean。
X_train_m = X_train - mean_image
print ("-----------------------------------------------")
print ("mean_image的形狀以及數值")
print (mean_image.shape)
print (mean_image[0])
print ("-----------------------------------------------")
print ("減去均值之后,X_train的第一幅圖像的RGB通道的第一個通道的圖像數值32*32:")
print (X_train_m[0][0])
輸出:
減去均值之前,X_train的第一幅圖像的RGB通道的第一個通道的圖像數值32*32:
[[ 62 61 60 ..., 64 82 62]
[ 62 63 61 ..., 77 114 64]
[ 67 78 115 ..., 100 119 63]
...,
[161 159 159 ..., 152 157 156]
[163 161 162 ..., 162 161 161]
[169 167 167 ..., 167 167 167]]
-----------------------------------------------
mean_image的形狀以及數值
(3, 32, 32)
[[ 121.33333333 114.66666667 113.83333333 ..., 134. 135.5
130.66666667]
[ 112.33333333 111.5 110.33333333 ..., 134.16666667
136.16666667 125.16666667]
[ 113.33333333 112.66666667 119.83333333 ..., 134.16666667 137.5
123.66666667]
...,
[ 135.66666667 131.66666667 129.66666667 ..., 99.33333333 84. 86. ]
[ 129.16666667 125.5 128.5 ..., 112.16666667
99.66666667 101. ]
[ 129.83333333 125.66666667 127.66666667 ..., 122.16666667
112.33333333 109.66666667]]
-----------------------------------------------
減去均值之后,X_train的第一幅圖像的RGB通道的第一個通道的圖像數值32*32:
[[-59.33333333 -53.66666667 -53.83333333 ..., -70. -53.5
-68.66666667]
[-50.33333333 -48.5 -49.33333333 ..., -57.16666667 -22.16666667
-61.16666667]
[-46.33333333 -34.66666667 -4.83333333 ..., -34.16666667 -18.5
-60.66666667]
...,
[ 25.33333333 27.33333333 29.33333333 ..., 52.66666667 73. 70. ]
[ 33.83333333 35.5 33.5 ..., 49.83333333 61.33333333
60. ]
[ 39.16666667 41.33333333 39.33333333 ..., 44.83333333 54.66666667
57.33333333]]
3.2 像素均值(pixel mean)
import os
import cv2
from numpy import *
img_dir='.\img'
img_list=os.listdir(img_dir)
img_size=224
sum_r=0
sum_g=0
sum_b=0
count=0
for img_name in img_list:
img_path=os.path.join(img_dir,img_name)
img=cv2.imread(img_path)
img=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
img=cv2.resize(img,(img_size,img_size))
sum_r=sum_r+img[:,:,0].mean()
sum_g=sum_g+img[:,:,1].mean()
sum_b=sum_b+img[:,:,2].mean()
count=count+1
sum_r=sum_r/count
sum_g=sum_g/count
sum_b=sum_b/count
img_mean=[sum_r,sum_g,sum_b]
print (img_mean)
輸出:
[122.30835127019559, 115.90339671024662, 99.094251567814624]
4.參考鏈接:
caffe訓練的時候減去pixel-mean和image-mean的區別
Caffe學習系列——工具篇:計算數據集的圖像均值
深度學習歷程之圖片的預處理為什么要減去圖片的平均值
計算圖像均值