1 神經(jīng)元
神經(jīng)元是構成神經(jīng)網(wǎng)絡的基本單元,接受一組輸入信號并產(chǎn)生輸出
1.1 基本機制
接收一個列向量輸入嘁扼,通過下列表達式產(chǎn)生凈輸出
- 行向量為權重向量
- 為偏置
凈輸入通過激活函數(shù)杉适,得到輸入為時該神經(jīng)元的活性值
圖示
1.2 激活函數(shù)
1.2.1 為什么需要激活函數(shù)蕊玷?
神經(jīng)網(wǎng)絡屬于非線性分類氓英。當輸入與權重及偏置經(jīng)過線性組合之后得到凈輸出馋吗,如果沒有激活函數(shù)對凈輸出的處理镊折,那么不管有多少神經(jīng)元最后得到的輸出仍然是線性輸出胯府,這也就是為什么感知機無法處理XOR(異或)問題的原因。而經(jīng)非線性的激活函數(shù)的處理之后恨胚,神經(jīng)網(wǎng)絡得以解決這一問題骂因。
1.2.2 激活函數(shù)的特征
- 連續(xù)并可導的非線性函數(shù),連續(xù):每一個凈輸入則產(chǎn)生對應的活性值赃泡;可導:只有有限個點不可導寒波,則可以使用數(shù)值優(yōu)化的方法(如梯度下降)訓練網(wǎng)絡。
- 激活函數(shù)的導數(shù)的值域要處于一個合適的區(qū)間升熊,因為這將影響訓練的效率及穩(wěn)定性俄烁。
1.2.3 兩種典型的激活函數(shù)
Logistic函數(shù)
- 輸入越小,越接近于级野;輸入越大页屠,越接近
- 輸出值直接可以視作概率分布
ReLU函數(shù)
- 當時辰企,導數(shù)為,有利于加速梯度下降的收斂
- 一定程度上緩解了神經(jīng)網(wǎng)絡的梯度消失問題
2 網(wǎng)絡結構
網(wǎng)絡中各個神經(jīng)元根據(jù)接受信息的先后分為不同的組別况鸣,每一組視為一個神經(jīng)層牢贸。每一層的神經(jīng)元接受前一層神經(jīng)元的輸出,并輸出到下一層神經(jīng)元镐捧。整個網(wǎng)絡的信息從輸入端朝輸出端傳播潜索,不存在反向的信息傳播臭增。網(wǎng)絡結構可使用一個有向無環(huán)圖表示,整個網(wǎng)絡可以視作一個非線性函數(shù)帮辟,實現(xiàn)從輸入到輸出的復雜映射。
2.1 結構組成
共分為三大層玩焰,第0層:輸入層由驹;最后一層:輸出層;其他中間層:隱藏層
- :神經(jīng)網(wǎng)絡的層數(shù)
- :第層神經(jīng)元的個數(shù)
- :第層神經(jīng)元的激活函數(shù)
- : 層到第 層的權重矩陣
- : 層神經(jīng)元的凈輸入
- :表示 層神經(jīng)元的輸出(活性值)
3 反向傳播算法
為了訓練參數(shù)蔓榄,最小化損失函數(shù)∧眨可采用梯度下降(通過計算損失函數(shù)對參數(shù)的偏導數(shù)甥郑,不斷迭代使得損失函數(shù)最小化)等算法。而梯度下降需要對每一個參數(shù)求解偏導荤西,效率低下澜搅。故誕生了反向傳播算法
3.1 算法思路
- 前饋計算每一層的凈輸入與輸出(活性值)
- 反向傳播計算每一層的誤差項(表示第層的神經(jīng)元對損失函數(shù)的影響)
- 計算每一層關于參數(shù)的偏導數(shù),并更新參數(shù)
3.2 數(shù)學原理
根據(jù)鏈式求導法則邪锌,可令損失函數(shù)對權重及偏置的偏導數(shù)分別如下
- 其中
由上列表達式可只饵溅,想要求損失函數(shù)對于第層的神經(jīng)元的偏導可以通過求解和可一次性求得妇萄。
而
即
關于第 層權重 的梯度為
關于第 層權重 的梯度為
其中(代表點積)
4 自動微分
在以計算機中轻掩,一種求解導數(shù)的精確且方便的計算方式。通過鏈式法則將復雜的表達式拆分成更簡單而精確的形式懦底。
例
求解過程:
- 令
- 求得上述表達式偏導數(shù)
- 故
5 優(yōu)化
在訓練神經(jīng)網(wǎng)絡時放典,有兩大問題難以解決:
- 非凸優(yōu)化(容易陷入局部最優(yōu)解)
- 梯度消失(參數(shù)學習停止)
6 兩層ReLU網(wǎng)絡的Pytorch實現(xiàn)
6.1 Code
導入Pytorch框架
import torch
import torch.nn as nn
import torch.nn.functional as F
from matplotlib import pyplot as plt
網(wǎng)絡實現(xiàn)
class Net(nn.Module):
def __init__(self, n_input, n_hidden, n_output):
super(Net, self).__init__()
# 定義層的形式
self.hidden = torch.nn.Linear(n_input, n_hidden)
self.output = torch.nn.Linear(n_hidden, n_output)
def forward(self, x):
# 隱藏層輸出
hidden = F.relu(self.hidden(x))
# 輸出層
y_predict = self.output(hidden)
return y_predict
def train(self, x, y, learning_rate, train_num):
# 優(yōu)化器
optimizer = torch.optim.SGD(self.parameters(), learning_rate)
# 損失函數(shù),均方差
loss_func = torch.nn.MSELoss()
# 迭代訓練
for i in range(train_num):
# 預測
y_predict = self(x)
# 計算誤差
loss = loss_func(y_predict, y)
# 情況上一次參與更新值
optimizer.zero_grad()
# 計算反向傳播
loss.backward()
# 更新參數(shù)
optimizer.step()
print(str(i) + "----->" + "loss:" + str(loss.data.numpy()))