動手學深度學習 | 多層感知機+程式碼實現 | 08
感知機
1960年的“物理感知機”。
感知機是人工智慧最早最早的一個模型。
感知機就是線性迴歸套了一層啟用函式。
因為感知機的輸出只有一個元素,所以只能做為一個二分類的問題。
可以理解為感知機使用了\(l(y,x,w)=max(0,-y<w,x>)\)這個損失函式。(只預測正確的)
多層感知機
多層感知機如何解決XOR問題呢?
假設一次做不了,那麼先學一個簡單的函式,再學一個簡單的函式,再用一個函式將兩部分進行組合,那麼就從一層變成了多層,這就是多層感知機乾的事情。
為什麼隱藏層大小是超引數?因為inputs是不能改的,outputs基本也是固定的,那麼可以進行修改的就是隱藏層。
如果不是非線性的啟用函式,其實也沒有意義,因為如果是線性的啟用函式,基本加了和沒加是一樣的。
ReLU的唯一好處就是算的特別快,前面的sigmoid和tanh都要進行指數運算,指數運算是一件很貴的事情,一次指數運算可以抵得上100次乘法運算的計算開銷。
其實如果沒有中間這個隱層的話,實際上和softmax迴歸是沒有差別的。
這裡只是把單個輸出變成了k個輸出。
多層感知機是可以把層數做深的。
在隱層中,每一層的啟用函式都不能少,如果少了,就相當於層數減一。輸出是不用啟用函式的。
超引數:
- 隱藏層數
- 每層隱藏層的大小
怎麼設定隱藏層的數量和每層的大小呢?其實是有工程經驗的。
從有種角度來說,深度學習就是在做壓縮,把輸入很多的資料,最後輸出成幾個簡單的類別,這個本質上就是對資料進行壓縮。所以其實第一隱層是可以適當大一些的,比如輸入是128,那麼可以先擴充套件到256,然後後面再進行加深,進行資料的壓縮。所以隱層一般都是“先肥後窄”
常用的啟用函式,如果沒有想法,使用ReLU就可以了,因為ReLU簡單,算的快。
多層感知機從零開始實現
操作總結
# 匯入資料 batch_size = 256 train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size) # 設定層數的數目 num_inputs, num_outputs, num_hiddens = 784, 10, 256 # nn.Parameter() 套不套這個都是可以的 W1 = nn.Parameter( torch.randn(num_inputs, num_hiddens, requires_grad=True) * 0.01) b1 = nn.Parameter(torch.zeros(num_hiddens, requires_grad=True)) W2 = nn.Parameter( torch.randn(num_hiddens, num_outputs, requires_grad=True) * 0.01) b2 = nn.Parameter(torch.zeros(num_outputs, requires_grad=True)) params = [W1, b1, W2, b2] # 實現ReLU的啟用函式 def relu(X): a = torch.zeros_like(X) return torch.max(X, a) def net(X): # 先將X拉成一個矩陣 X = X.reshape((-1, num_inputs)) # @表示矩陣乘法 H = relu(X @ W1 + b1) return (H @ W2 + b2) loss = nn.CrossEntropyLoss() # 訓練過程 num_epochs, lr = 10, 0.1 updater = torch.optim.SGD(params, lr=lr) d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, updater)
多層感知機簡潔實現
操作總結
# 這樣就構建了一個具有單層 256個隱藏單元的,並使用ReLU啟用函式的多層感知機模型了
net = nn.Sequential(nn.Flatten(), nn.Linear(784, 256), nn.ReLU(),nn.Linear(256, 10))
# 初始化權重
def init_weights(m):
if type(m) == nn.Linear:
nn.init.normal_(m.weight, std=0.01)
net.apply(init_weights);
# 訓練過程
batch_size, lr, num_epochs = 256, 0.1, 10
loss = nn.CrossEntropyLoss()
trainer = torch.optim.SGD(net.parameters(), lr=lr)
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer)
QA
- 多層感知機和純softmax模型相比,loss是下降了,但是精度並沒有提升。
可以解釋為因為模型更大了,所以資料擬合性更好,所以loss在下降。
- MLP和SVM
現在基本都是使用的MLP,因為MLP要改動的程式碼其實不多,輸入和輸出基本都不用變,只要把中間部分進行更換即可。
但是SVM就不是了,需要調整的東西會比較多。
- 神經網路中一層是怎麼看的?
一層主要只可以學習的引數,比如下圖,就是有兩層(輸入層不算做一層)
有幾層引數需要學習,就可以認為是幾層,當然在隱層之間可以認為啟用函式是一個分界。
- 為什麼神經網路要增加隱藏層的層數,而不是神經元的個數?
其實增加深度效果會更好,如果只是增加寬度的話,因為神經元是並行的,並不能很好的進行特徵的提取。如果是深層的話,可以第一層先提取一點,第二層再提取其他的....
其實增加網路的寬度和深度都是有用的,但是增加網路的深度效果會更好。
(可以認為2014年之前,深度學習基本都是沒有什麼突破的東西,和20,30年前做的東西是一樣的,只是把網路做的更深)
- 不同任務下的啟用函式是不是都不一樣?也是通過實驗來確認的嗎?
啟用函式遠遠沒有選擇隱藏層那些大小和數量來的重要,所以就用ReLU吧...就是你可以選,但是本質上沒有太多的區別。