优达学城《DeepLearning》2-3:权重初始化
目錄
初始重量并觀察訓練損失
數據集和模型
導入庫并加載數據
可視化一些訓練數據
定義模型結構
初始化權重
全部為0或1
比較模型行為
均勻分布
統一初始化,基線
設置權重的一般規則
正態分布(Normal Distribution)
自動初始化
在本課中,您將學習如何為神經網絡找到好的初始權重。權重初始化只發生一次,即在創建模型時和訓練之前。具有良好的初始權值可以使神經網絡接近最優解。這使得神經網絡能夠更快地得到最佳解。
初始重量并觀察訓練損失
為了了解不同權重的性能,我們將在相同的數據集和神經網絡上進行測試。
我們將用不同的初始權重實例化至少兩個相同的模型,并查看訓練損失如何隨著時間的推移而減少,如下面的示例所示。
有時訓練損失的差異隨著時間的推移,會很大,而其他時候,某些權重只提供小的改善。
數據集和模型
我們將訓練一個MLP來對Fashion-MNIST database?中的圖像進行分類,以演示不同初始權重的效果。作為提醒,FashionMNIST數據集包含服裝類型的圖像:classes = ['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat', 'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot']。對圖像進行歸一化,使其像素值在[0.0 - 1.0]范圍內。運行下面的單元格下載并加載數據集。
導入庫并加載數據
import torch
import numpy as np
from torchvision import datasets
import torchvision.transforms as transforms
from torch.utils.data.sampler import SubsetRandomSampler# number of subprocesses to use for data loading
num_workers = 0
# how many samples per batch to load
batch_size = 100
# percentage of training set to use as validation
valid_size = 0.2# convert data to torch.FloatTensor
transform = transforms.ToTensor()# choose the training and test datasets
train_data = datasets.FashionMNIST(root='data', train=True,download=True, transform=transform)
test_data = datasets.FashionMNIST(root='data', train=False,download=True, transform=transform)# obtain training indices that will be used for validation
num_train = len(train_data)
indices = list(range(num_train))
np.random.shuffle(indices)
split = int(np.floor(valid_size * num_train))
train_idx, valid_idx = indices[split:], indices[:split]# define samplers for obtaining training and validation batches
train_sampler = SubsetRandomSampler(train_idx)
valid_sampler = SubsetRandomSampler(valid_idx)# prepare data loaders (combine dataset and sampler)
train_loader = torch.utils.data.DataLoader(train_data, batch_size=batch_size,sampler=train_sampler, num_workers=num_workers)
valid_loader = torch.utils.data.DataLoader(train_data, batch_size=batch_size, sampler=valid_sampler, num_workers=num_workers)
test_loader = torch.utils.data.DataLoader(test_data, batch_size=batch_size, num_workers=num_workers)# specify the image classes
classes = ['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat', 'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot']
可視化一些訓練數據
定義模型結構
我們已經定義了用于對數據集進行分類的MLP。
一個3層MLP,隱藏層單元數為256和128。
該MLP接受一個扁平圖像(784個值的長向量)作為輸入,并產生10個類分數作為輸出。
我們將用ReLU激活和Adam優化器測試不同初始權重對這3層神經網絡的影響。
你學到的經驗教訓適用于其他神經網絡,包括不同的激活和優化。
初始化權重
讓我們開始看一些初始權重。
全部為0或1
如果你遵循Occam剃須刀原理,你可能會認為將所有的權重設置為0或1是最好的解決方案。事實并非如此。
在權重都相同的情況下,每一層的所有神經元都產生相同的輸出。這使得很難決定要調整哪些權重。
讓我們通過定義兩個具有這些恒定權重的模型來比較所有1和所有0權重的損失。
下面,我們使用PyTorch的nn.init初始化每個線性層,使其具有恒定的權重。init庫提供了許多權重初始化函數,使您能夠根據層類型初始化每個層的權重。
在下面的例子中,我們查看模型中的每個層/模塊。如果它是一個線性層(因為這三個層都是針對MLP的),那么我們使用以下代碼將這些層權重初始化為constant_weight,偏差為0:
constant_weight是在實例化模型時可以傳入的值。
import torch.nn as nn
import torch.nn.functional as F# define the NN architecture
class Net(nn.Module):def __init__(self, hidden_1=256, hidden_2=128, constant_weight=None):super(Net, self).__init__()# linear layer (784 -> hidden_1)self.fc1 = nn.Linear(28 * 28, hidden_1)# linear layer (hidden_1 -> hidden_2)self.fc2 = nn.Linear(hidden_1, hidden_2)# linear layer (hidden_2 -> 10)self.fc3 = nn.Linear(hidden_2, 10)# dropout layer (p=0.2)self.dropout = nn.Dropout(0.2)# initialize the weights to a specified, constant valueif(constant_weight is not None):for m in self.modules():if isinstance(m, nn.Linear):nn.init.constant_(m.weight, constant_weight)nn.init.constant_(m.bias, 0)def forward(self, x):# flatten image inputx = x.view(-1, 28 * 28)# add hidden layer, with relu activation functionx = F.relu(self.fc1(x))# add dropout layerx = self.dropout(x)# add hidden layer, with relu activation functionx = F.relu(self.fc2(x))# add dropout layerx = self.dropout(x)# add output layerx = self.fc3(x)return x
比較模型行為
下面,我們使用?helpers.compare_init_weights?來比較上面定義的兩個模型(model_0和model_1)的訓練和驗證損失。此函數接收模型列表(每個模型具有不同的初始權重)、要生成的繪圖的名稱以及訓練和驗證數據集加載器。對于每個給定的模型,它將繪制前100批的訓練損失,并打印出兩個訓練epoch后的驗證精度。注意:如果您使用的是小批量的,您可能需要增加這里的epoch數,以便更好地比較模型在看到幾百張圖像后的行為。
我們繪制前100批的損失圖,以便更好地判斷哪些模型權重在訓練開始時表現更好。我建議您查看helpers.py中的代碼,以了解模型是如何訓練、驗證和比較的。
運行下面的單元格,查看權重全為0與權重全為1之間的差異。
helpers.py內如如下:
import numpy as np
import matplotlib.pyplot as pltimport torch
import torch.nn as nn
import torch.optimdef _get_loss_acc(model, train_loader, valid_loader):"""Get losses and validation accuracy of example neural network"""n_epochs = 2learning_rate = 0.001# Training losscriterion = nn.CrossEntropyLoss()# Optimizeroptimizer = optimizer = torch.optim.Adam(model.parameters(), learning_rate)# Measurements used for graphing lossloss_batch = []for epoch in range(1, n_epochs+1):# initialize var to monitor training losstrain_loss = 0.0#################### train the model ####################for data, target in train_loader:# clear the gradients of all optimized variablesoptimizer.zero_grad()# forward pass: compute predicted outputs by passing inputs to the modeloutput = model(data)# calculate the batch lossloss = criterion(output, target)# backward pass: compute gradient of the loss with respect to model parametersloss.backward()# perform a single optimization step (parameter update)optimizer.step()# record average batch loss loss_batch.append(loss.item())# after training for 2 epochs, check validation accuracy correct = 0total = 0for data, target in valid_loader:# forward pass: compute predicted outputs by passing inputs to the modeloutput = model(data)# get the predicted class from the maximum class score_, predicted = torch.max(output.data, 1)# count up total number of correct labels# for which the predicted and true labels are equaltotal += target.size(0)correct += (predicted == target).sum()# calculate the accuracy# to convert `correct` from a Tensor into a scalar, use .item()valid_acc = correct.item() / total# return model statsreturn loss_batch, valid_accdef compare_init_weights(model_list,plot_title,train_loader,valid_loader,plot_n_batches=100):"""Plot loss and print stats of weights using an example neural network"""colors = ['r', 'b', 'g', 'c', 'y', 'k']label_accs = []label_loss = []assert len(model_list) <= len(colors), 'Too many initial weights to plot'for i, (model, label) in enumerate(model_list):loss, val_acc = _get_loss_acc(model, train_loader, valid_loader)plt.plot(loss[:plot_n_batches], colors[i], label=label)label_accs.append((label, val_acc))label_loss.append((label, loss[-1]))plt.title(plot_title)plt.xlabel('Batches')plt.ylabel('Loss')plt.legend(bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.)plt.show()print('After 2 Epochs:')print('Validation Accuracy')for label, val_acc in label_accs:print(' {:7.3f}% -- {}'.format(val_acc*100, label))print('Training Loss')for label, loss in label_loss:print(' {:7.3f} -- {}'.format(loss, label))def hist_dist(title, distribution_tensor, hist_range=(-4, 4)):"""Display histogram of values in a given distribution tensor"""plt.title(title)plt.hist(distribution_tensor, np.linspace(*hist_range, num=len(distribution_tensor)//2))plt.show()
正如你所看到的,對于全0和1的權重初始化,準確率都接近于猜測,大約10%。
神經網絡很難確定哪些權值需要改變,因為神經元對每一層都有相同的輸出。為了避免神經元輸出相同,讓我們使用唯一的權重。我們還可以隨機選擇這些權重,以避免每次運行都陷入局部最小值。
獲得這些隨機權重的一個好辦法是從均勻分布中取樣。
均勻分布
均勻分布從一組數中選取任意數的概率相等。我們將從連續分布中挑選,因此挑選相同值的可能性很低。我們將使用NumPy的np.random.uniform函數從均勻分布中選取隨機數。
np.random_uniform(low=0.0, high=1.0, size=None)- 從均勻分布輸出隨機值。
- 生成的值在[低,高]范圍內遵循均勻分布。下限值包含在可選范圍中,而上限值被排除在外。
- low:要生成的隨機值范圍的下限。默認為0。
- high:要生成的隨機值范圍的上限。默認為1。
- size:指定輸出數組形狀的整數或整數元組。
我們可以用直方圖來顯示均勻分布。讓我們使用helper.hist_dist函數將值np.random_uniform(-3, 3, [1000])映射到直方圖。這將是1000個從-3到3的隨機浮點值,不包括值3。
直方圖使用500個柱子來表示1000個值。因為任何一個柱子的概率都是相同的,所以每個柱子應該有2個左右的值。這正是我們看到的直方圖。有些柱子有更多的,有些柱子有更少的,但他們的趨勢是2左右。
現在您已經了解了統一函數,讓我們使用PyTorch的nn.init將其應用于模型的初始權重。
統一初始化,基線
讓我們看看神經網絡如何使用均勻權重初始化進行訓練,其中low=0.0,high=1.0。下面,我將向您展示另一種初始化網絡權重的方法(除了在Net類代碼中)。要在模型定義之外定義權重,你可以:
- 定義一個按網絡層類型分配權重的函數,然后
- 使用model.Apply(fn)將這些權重應用于初始化的模型,該函數將函數應用于每個模型層。
這次,我們將使用weight.data.uniform直接初始化模型的權重。
損失圖顯示了神經網絡正在學習,而不是全零或全一。我們正朝著正確的方向前進!
設置權重的一般規則
在神經網絡中設置權重的一般規則是將它們設置為接近于零而不太小。
讓我們看看這是否成立;讓我們創建一個基線來比較,并通過將其移動0.5,使我們的統一范圍居中于零之上。這將給出范圍[-0.5,0.5)。
然后讓我們創建一個數據分布和模型,使用一般規則進行權重初始化;使用range?, where?。
最后,我們將比較這兩種模型。
這種行為真的很有希望!不僅損失在減少,而且對于遵循一般規則的統一權重,似乎也很快地減少了損失;在僅僅經歷了兩個epoch之后,我們得到了相當高的驗證準確性,這應該給你一些直覺,為什么從正確的初始權重開始,真的可以幫助你的訓練!
由于均勻分布有相同的機會選擇一個范圍內的任何值,如果我們使用的分布有更高的機會選擇接近0的數字呢?讓我們看看正態分布。
正態分布(Normal Distribution)
與均勻分布不同,正態分布挑選的數據具有更高接近整體均值的可能性。為了可視化,讓我們將NumPy的np.random.normal函數的值繪制為直方圖。
讓我們將正態分布與以前基于規則的均勻分布進行比較。
TODO:定義一個權重初始化函數,該函數從正態分布中獲取權重
在這種情況下,正態分布給出了與均勻分布非常相似的行為。這可能是因為我們的網絡太小了;一個較大的神經網絡將從每個分布中選取更多的權值,從而放大兩種初始化方式的效果。一般來說,正態分布會使模型具有更好的性能。
自動初始化
讓我們快速看看在沒有任何顯式權重初始化的情況下會發生什么。
完成此練習時,請記住以下問題:
- 哪種初始化策略在兩個階段后訓練損失最小?最高的驗證準確度呢?
- 在測試了所有這些初始權重選項之后,您決定在最終的分類模型中使用哪一個?
?
?
?
?
?
總結
以上是生活随笔為你收集整理的优达学城《DeepLearning》2-3:权重初始化的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 优达学城《DeepLearning》2-
- 下一篇: 优达学城《DeepLearning》2-