為什么我們需要了解Logistic regression邏輯回歸?
因為神經網絡的一個神經元就是Logistic regression邏輯回歸。
Logistic regression(LR)邏輯回歸是什么?
它就是套一個概率分布模型上去。什么是模型?模型就是一個函數比如:f(x)=ax+b。至於邏輯回歸套的那個概率分布模型是什么稍后再說,先說套概率分布模型上去有什么用?假如需要判斷樣本x是屬於A類還是屬於B類。在前面提到了模型就是一個函數,概率分布模型就是輸入一個樣本數據x,函數輸出它屬於A類的概率。邏輯回歸只能分出兩種類。x屬於A類的概率大於0.5那就我們可以認為當前樣本屬於A類,如果概率小於0.5那就認為它屬於B類。
那么邏輯回歸套的是什么函數呢?答:
。其中
是待求解的參數,不同的數據是不一樣的。那我們怎么根據當前已有的數據調整得到最優的參數
?答:用梯度下降。
如果你對梯度下降不理解可以參考這兩篇文章:
易懂的神經網絡理論到實踐(1):單個神經元+隨機梯度下降學習邏輯與規則
{高中生能看懂的}梯度下降是個啥?
pytorch編程實踐
本文的實踐會先介紹使用的數據是什么。然后介紹如何檢驗自己程序是否正確。然后介紹如何用pytorch的反向傳播求導(求導結果是否正確可以我們自己手動計算下來檢驗),並用這個導數實現梯度下降。然后介紹如何我們自己求導實現梯度下降(我們自己寫的導數是否計算正確檢驗方法1是可以用前面反向傳播求導結果檢驗2是我們自己手動計算看程序運行結果是否正確)。
使用pytorch自帶的自動求導工具求導,然后實現梯度下降
大家一定要注意機器學習必備下面那幾個步驟。寫程序一定要對這些步驟爛熟於心。
- 加載數據
- 輸入樣本計算模型的輸出
- 計算損失函數對參數w的導數(梯度)
- 梯度下降調節參數w
- 重復2-4
1.加載數據
首先我們需要加載數據,這次我們想實現的是讓邏輯回歸識別邏輯異或(兩個數字相同那就是0,兩個數字不同那就是1)。
所以數據(前面兩個數字)與標簽(最后那個數字)是:
1 1 0
1 0 1
0 1 0
0 0 1
現在我們用代碼實現加載數據
# -*- coding:utf-8 -*-
import torch
import numpy as np
''' 用邏輯回歸實現異或功能 '''
# 加載數據
data = torch.tensor([[1,1],[1,0],[0,1],[0,0]],dtype=torch.float)
label = torch.tensor([[0,1,1,0]],dtype=torch.float).t()
計算模型的輸出
前面提到了邏輯回歸的模型是 。我們首先需要先初始化參數w。然后輸入一個樣本x,然后根據公式 計算模型輸出。接下來我們用代碼實現它。很多同學不知道自己代碼寫的對不對,大家只需要自己算一下結果,然后看看程序輸出是否符合自己計算結果。
# -*- coding:utf-8 -*-
import torch
import numpy as np
''' 用邏輯回歸實現異或功能 '''
# 加載數據
data = torch.tensor([[1,1],[1,0],[0,1],[0,0]],dtype=torch.float)
label = torch.tensor([[0,1,1,0]],dtype=torch.float).t()
w = torch.tensor([1,1],dtype=torch.float, requires_grad=True)
# 加載一個數據,代入到公式中
i = 0
x = data[i]
#f = 1/[1+e^(-wx)]
f = 1/(1+torch.pow(np.e,-x.dot(w)))
print(f) # 輸出tensor(0.8808)
利用pytorch反向傳播自動求導工具計算損失函數對參數w的導數
我們需要告訴pytorch損失函數,然后讓它根據損失函數對參數w求導。接下來我們用代碼實現。()
# -*- coding:utf-8 -*-
import torch
import numpy as np
''' 用邏輯回歸實現異或功能 '''
# 加載數據
data = torch.tensor([[1,1],[1,0],[0,1],[0,0]],dtype=torch.float)
label = torch.tensor([[0,1,1,0]],dtype=torch.float).t()
w = torch.tensor([1,1],dtype=torch.float,requires_grad=True)
# 加載一個數據,代入到公式中
i = 0
x = data[i]
#f = 1/[1+e^(-wx)]
f = 1/(1+torch.pow(np.e,-x.dot(w)))
print(f) # 輸出tensor(0.8808)
loss = (f-label[i])**2
print(loss)# 輸出:tensor([0.7758])
loss.backward() # 使用反向傳播求損失函數對參數w的導數值
print(w.grad) # 損失函數對w的導數值tensor([0.1850, 0.1850])
利用反向傳播的導數實現梯度下降
# -*- coding:utf-8 -*-
import torch
import numpy as np
''' 用邏輯回歸實現異或功能 '''
# 加載數據
data = torch.tensor([[1,1],[1,0],[0,1],[0,0]],dtype=torch.float)
label = torch.tensor([[0,1,1,0]],dtype=torch.float).t()
w = torch.tensor([1,1],dtype=torch.float,requires_grad=True)
# 加載一個數據,代入到公式中
i = 0
x = data[i]
#f = 1/[1+e^(-wx)]
f = 1/(1+torch.pow(np.e,-x.dot(w)))
print(f) # 輸出tensor(0.8808)
loss = (f-label[i])**2
print(loss)# 輸出:tensor([0.7758])
loss.backward() # 使用反向傳播求損失函數對參數w的導數值
print(w.grad) # 損失函數對w的導數值tensor([0.1850, 0.1850])
learning_rate = 1e-2
w = w - learning_rate*w.grad
print('更新后的參數w',w)#更新后的參數w tensor([0.9982, 0.9982])
我們自己手動計算導數,並實現梯度下降
# -*- coding:utf-8 -*-
import torch
import numpy as np
''' 用邏輯回歸實現異或功能 '''
# 加載數據
data = torch.tensor([[1,1],[1,0],[0,1],[0,0]],dtype=torch.float)
label = torch.tensor([[0,1,1,0]],dtype=torch.float).t()
w = torch.tensor([1,1],dtype=torch.float,requires_grad=True)
# 加載一個數據,代入到公式中
i = 0
x = data[i]
#f = 1/[1+e^(-wx)]
f = 1/(1+torch.pow(np.e,-x.dot(w)))
print(f) # 輸出tensor(0.8808)
#loss = (f-label[i])**2
# 計算損失函數loss對w的導數
# 我們把e^(-wx)這部分先存到一個變量里面
e_wx = torch.pow(np.e,-x.dot(w))
dloss_dw = 2*(f-label[i])*x*e_wx/(1+e_wx)**2
print(dloss_dw)
learning_rate = 1e-2
w = w - learning_rate*dloss_dw
print('更新后的參數w',w)#更新后的參數w tensor([0.9982, 0.9982])