[英]Correct way of normalizing and scaling the MNIST dataset
我到處都看過,但找不到我想要的東西。 基本上,MNIST 數據集的圖像像素值在[0, 255]
范圍內。 人們說,一般來說,做以下事情是好的:
[0,1]
范圍。(data - mean) / std
。 不幸的是,沒有人展示如何做這兩件事。 它們都減去平均值0.1307
並除以標准差0.3081
。 這些值基本上是數據集的平均值和標准差除以 255:
from torchvision.datasets import MNIST
import torchvision.transforms as transforms
trainset = torchvision.datasets.MNIST(root='./data', train=True, download=True)
print('Min Pixel Value: {} \nMax Pixel Value: {}'.format(trainset.data.min(), trainset.data.max()))
print('Mean Pixel Value {} \nPixel Values Std: {}'.format(trainset.data.float().mean(), trainset.data.float().std()))
print('Scaled Mean Pixel Value {} \nScaled Pixel Values Std: {}'.format(trainset.data.float().mean() / 255, trainset.data.float().std() / 255))
這將輸出以下內容
Min Pixel Value: 0
Max Pixel Value: 255
Mean Pixel Value 33.31002426147461
Pixel Values Std: 78.56748962402344
Scaled Mean: 0.13062754273414612
Scaled Std: 0.30810779333114624
但是很明顯,以上都不是! 結果數據 1) 不會介於[0, 1]
之間,也不會具有 mean 0
或 std 1
。 事實上,這就是我們正在做的:
[data - (mean / 255)] / (std / 255)
這和這個很不一樣
[(scaled_data) - (mean/255)] / (std/255)
其中scaled_data
只是data / 255
。
我認為您誤解了一個關鍵概念:這是兩種不同且不一致的擴展操作。 您只能擁有以下兩者之一:
想想看,考慮到 [0,1] 范圍:如果數據都是小的正值,min=0 和 max=1,那么數據的總和必須是正的,給出一個正的非零均值。 類似地,當沒有任何數據可能與平均值相差 1.0 時,stdev不能為1
。
相反,如果您的均值 = 0,則某些數據必須為負。
您只使用了兩個轉變的一個。 使用哪種方法取決於您的數據集的特點,和-最終-這一件作品更好地為您的模型。
對於 [0,1] 縮放,您只需除以 255。
對於 mean=0, stdev=1 縮放,您執行您已經知道的簡單線性變換:
new_val = (old_val - old_mean) / old_stdev
這是否為您澄清,還是我完全錯過了您的困惑點?
Euler_Salter
我可能偶然發現這個有點太晚了,但希望我能幫上一點忙。
假設您正在使用 torchvision.Transform,以下代碼可用於規范化 MNIST 數據集。
train_loader = torch.utils.data.DataLoader(
datasets.MNIST('./data', train=True
transform=transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))
])),
通常,'transforms.ToTensor()' 用於將 [0,255] 范圍內的輸入數據轉換為 3 維 Tensor。 該函數自動將輸入數據縮放到 [0,1] 的范圍內。 (這相當於將數據縮小到 0,1)
因此,'transforms.Normalize(...)' 中使用的均值和標准差分別為 0.1307 和 0.3081 是有道理的。 (這等效於歸一化零均值和單位標准差。)
請參閱下面的鏈接以獲得更好的解釋。
特征縮放的兩個最重要的原因是:
示例:
具有兩個特征的數據集:年齡和體重。 以年為單位的年齡和以克為單位的重量! 現在,一個 20 歲、體重只有 60Kg 的家伙將轉換為向量 = [20 yrs, 60000g],對整個數據集依此類推。 在訓練過程中,權重屬性將占主導地位。 這是怎么回事,取決於您使用的算法的類型 - 有些比其他算法更敏感:例如,梯度下降的學習率受神經網絡 Thetas(即權重)大小影響的神經網絡,以及后者在訓練過程中與輸入(即特征)的相關性不同; 特征縮放也提高了收斂性。 另一個例子是 K 均值聚類算法需要相同量級的特征,因為它在空間的所有方向上都是各向同性的。 有趣的名單。
這很簡單:與非常大的數字相比,所有這些矩陣乘法和參數求和在小數字下會更快(或通過將特征乘以其他參數而產生的非常大的數字......等)
最流行的特征縮放器類型可以總結如下:
StandardScaler
:通常是您的第一個選項,它非常常用。 它通過標准化數據(即使它們居中)來工作,即使它們達到STD=1
和Mean=0
。 它會受到 outliers 的影響,並且只有在您的數據具有Gaussian-Like Distribution時才應該使用。MinMaxScaler
:通常用於將所有數據點置於特定范圍內(例如 [0-1] )。 僅僅因為它使用Range ,它就會受到異常值的嚴重影響。RobustScaler
:它對異常值具有“穩健性”,因為它根據分位數范圍縮放數據。 但是,您應該知道,縮放后的數據中仍會存在異常值。MaxAbsScaler
:主要用於稀疏數據。Unit Normalization
:它基本上將每個樣本的向量縮放為具有單位范數,與樣本的分布無關。您需要先了解您的數據集。 如上所述,您需要先查看一些內容,例如:數據的分布、異常值的存在以及正在使用的算法。
無論如何,除非有特定要求,否則每個數據集都需要一個定標器,例如,如果存在一種算法,該算法僅在數據在特定范圍內並且具有零均值和標准差為 1 的情況下才有效 - 全部在一起。 盡管如此,我從未遇到過這種情況。
根據上面提到的一些經驗法則,可以使用不同類型的特征縮放器。
您可以根據要求選擇一個 Scaler,而不是隨機選擇。
您出於某種目的縮放數據,例如, 在隨機森林算法中,您通常不需要縮放。
好吧,使用 torchvision.transforms.ToTensor() 將數據縮放到 [0,1],然后應用歸一化 (0.1306,0.3081)。 您可以在 Pytorch 文檔中查看它: https://pytorch.org/vision/stable/transforms.html 。
希望這能回答你的問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.