點選關注我哦
歡迎關注 “小白玩轉Python”,發現更多 “有趣”
“A little learning is a dangerous thing; drink deep or taste not Pierian Spring” (Alexander Pope)
在昨天的文章中,我們已經建構了一個非常簡單和“幼稚”的神經網絡,它不知道将輸入映射到輸出的函數。為了使網絡更加智能化,我們将以“真實資料”為例對網絡進行訓練,然後調整網絡參數(權重和偏差)。簡而言之,我們通過疊代一個訓練資料集,同時調整模型的參數(權重和偏差)來提高準确性。
為了找到這些參數,我們需要知道我們的網絡對真實輸出的預測有多差。為此,我們将計算cost,也稱為loss function。
Cost
cost或loss function是我們預測誤差的度量。通過最小化網絡參數方面的loss,我們可以找到loss最小的狀态,使得網絡能夠高精度地預測正确的标簽。我們通過一個叫做Gradient Descent(梯度下降法)的過程找到loss的最小值。
Gradient Descent
梯度下降法需要一個 cost 函數。我們需要這個 cost 函數,因為我們需要最小化這個以獲得高的預測精度。GD 的全部意義在于使 cost 函數最小化。該算法的目标是獲得最低 error value 的過程。為了得到 cost 函數中的最低 error value (相對于一個權重) ,我們需要調整模型的參數。那麼,我們需要調整多少參數呢?我們可以用微積分 calculus 進行計算。利用 calculus,我們可以知道函數的斜率 slope 是函數對值的導數。梯度是損失函數的斜率,指向變化最快的方向。
Backpropagation
對于單層網絡,梯度下降算法的實作比較簡單,而對于多層網絡,則更為複雜和深入。訓練多層網絡是通過反向傳播完成的,反向傳播實際上是微積分鍊式規則的一個應用。如果我們把一個兩層的網絡轉換成一個圖形表示,這是最容易了解的。
forward pass 前向傳播
在前向傳播中,資料和操作從底部到頂部。
步驟1: 我們将輸入 x 輸入一個帶權重 W1和偏差 b 1的線性映射 L1中;
步驟2: 将步驟1中的輸出經過 Sigmod 函數和另一個線性映射 L2 中;
步驟3:最後我們計算損失 l。
我們可以用損失來衡量網絡的預測結果有多糟糕。是以,我們的目标是調整權重和偏差,以最大限度地減少損失。
Backward 向後傳播
為了用梯度下降法來訓練權重,我們通過網絡向後傳播計算梯度損失。
每個操作在輸入和輸出之間都有一定的梯度。
當我們向後傳遞梯度時,我們将輸入的梯度與操作的梯度相乘。
數學上,這實際上隻是使用鍊式法則,計算損失相對于權重的梯度。
我們可以調整梯度下降過程中的學習率 α 來更新我們的權重。
學習速率 α 的設定使得權重更新步驟足夠小,以至于疊代法最小化。
PyTorch 的損失
PyTorch 提供了很多損失函數,例如交叉熵損失函數 nn.CrossEntropyLoss。對于類似 MNIST 這樣的分類問題,我們使用Softmax 函數模型來預測類别機率。
為了計算損失,我們首先定義criterion ,然後傳入我們的網絡輸出和正确的标簽。
CrossEntropyLoss 标準将 nn. LogSoftmax ()和 nn.NLLLoss ()組合在一個類中。
輸入應該包含每個類的得分。
Autograd
Torch 提供了一個名為 autograd 的子產品來自動計算張量的梯度。這是一種計算導數的引擎。在設定計算梯度可用時,它是一個可以記錄張量上所有操作的圖,并建立一個稱為動态計算圖的無向圖。這個圖的葉子是輸入張量,根是輸出張量。
Autograd 的工作原理是跟蹤張量上執行的操作,然後通過這些操作向後傳播,沿着這條“路”計算梯度。
為了確定 PyTorch 跟蹤一個張量的操作并計算我們需要設定requires_ grad = True。我們也可以在計算過程中使用torch.no_grad()關閉梯度計算。
訓練網絡
最後,我們将需要一個優化器,以使用梯度來更新權重。我們從 PyTorch 的optim庫中得到這些。例如,我們可以在 optim.SGD 中使用随機梯度下降。
訓練神經網絡的過程:
通過網絡向前傳遞
使用網絡輸出來計算損失
使用loss.backward()在網絡中執行向後傳播來計算梯度
與優化器一起執行更新權重的步驟
我們将為訓練準備資料:
import torchfrom torch import nnimport torch.nn.functional as Ffrom torchvision import datasets, transforms# Define a transform to normalize the datatransform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,)), ])# Download and load the training datatrainset = datasets.MNIST('~/.pytorch/MNIST_data/', download=True, train=True, transform=transform)trainloader = torch.utils.data.DataLoader(trainset, batch_size=64, shuffle=True)
使用真實資料進行訓練:
在某些術語中,周遊整個資料集的過程稱為 epoch。是以在這裡我們将通過 trainloader 循環獲得我們的訓練批次。對于每一批資料,我們将做一個訓練傳遞,計算損失,做一個向後傳遞,并更新權重。
model = nn.Sequential(nn.Linear(784, 128), nn.ReLU(), nn.Linear(128, 64), nn.ReLU(), nn.Linear(64, 10), nn.LogSoftmax(dim=1))# Define the losscriterion = nn.NLLLoss()# Optimizers require the parameters to optimize and a learning rateoptimizer = optim.SGD(model.parameters(), lr=0.003)epochs = 5for e in range(epochs): running_loss = 0 for images, labels in trainloader: # Flatten MNIST images into a 784 long vector images = images.view(images.shape[0], -1) # Training pass optimizer.zero_grad() output = model(images) loss = criterion(output, labels) loss.backward() optimizer.step() running_loss += loss.item() else: print(f"Training loss: {running_loss/len(trainloader)}")
注意: optimizer.zero _ grad () : 當我們使用相同的參數進行多次向後傳遞時,梯度是累積的。這意味着我們需要在每次訓練通過時将梯度歸零,否則我們将保留之前訓練批次的梯度。
通過訓練網絡,我們可以檢查它的預測。
現在我們的網絡是輝煌的! 它可以準确地預測我們的圖像中的數字。
· END ·
HAPPY LIFE