1. 程式人生 > 實用技巧 >pytorch入門到專案(七)autograd與邏輯迴歸

pytorch入門到專案(七)autograd與邏輯迴歸

autograd與邏輯迴歸

自動求導系統中兩個常用的方法:

torch.autograd.backward and torch.autograd.grad

演示理解一階導數、二階導數的求導過程
理解自動求導系統,以及張量,前向傳播構建計算圖、計算圖求取梯度
演示邏輯迴歸訓練,學習五大模組:資料、模型、損失函式、優化器、迭代訓練過程

深度學習模型的訓練就是不斷更新權值,權值的更新需要求解梯度。梯度時關鍵重要的,Pytorch就有自動求導系統,只需要搭建前向傳播的計算圖,通過autograd就可以得到梯度

torch.autograd.backward

  1. autograd
    torch.autograd.backward(tensors,grad_tensors=None,retain_graph=None,create_graph=False)
    retain_graph用來儲存計算圖
    create_graph建立導數計算圖,用於高階求導
    grad_tensors多梯度權重
import torch
import numpy as np

x = torch.tensor([2.], requires_grad=True)
w = torch.tensor([1.], requires_grad=True)

a = torch.add(x,w)
# a.retain_grad()
b = torch.add(w,1)
y = torch.mul(a,b)
y.backward()# 在此行設定斷點

點選step into,此時發現呼叫的是tensor.py中的

torch.autograd.backward(self, gradient, retain_graph, create_graph)
import torch
import numpy as np

x = torch.tensor([2.], requires_grad=True)
w = torch.tensor([1.], requires_grad=True)

a = torch.add(x,w)
# a.retain_grad()
b = torch.add(w,1)
y = torch.mul(a,b)
y.backward()
y.backward()
RuntimeError: Trying to backward through the graph a second time, but the saved intermediate results have already been freed. Specify retain_graph=True when calling backward the first time.

報錯資訊表示我們想進行兩次的backward運算,但是儲存的結果已經釋放掉了,如果我們想要運算的話,應該指定retain_graph=True

y.backward(retain_graph=True)
y.backward()

grad_tensors

用於設定多個梯度之間的權重。

torch.autograd

torch.autograd.grad(outputs,inputs,grad_outputs=None,retain_grph=None,create_graph=False)
outputs:用於求導的張量,如loss
inputs:需要梯度的張量
create_graph:建立導數計算圖,用於高階求導
retain_graph:儲存計算圖
grad_outputs:多梯度權重

flag = True
# flag = False
if flag:
    x = torch.tensor([3.], requires_grad=True)
    y = torch.pow(x, 2)
    y1 = torch.autograd.grad(y,x,create_graph=True)
    y2 = torch.autograd.grad(y1[0],x)# 二次求導對元組裡的元素進行求導
    y.backward()
    print(x.grad)
    print(y1)
    print(y2)
tensor([6.])
(tensor([6.], grad_fn=<MulBackward0>),)
(tensor([2.]),)

tips

  1. 梯度不會自動清零
flag = True
# flag = False
if flag:
    x = torch.tensor([3.], requires_grad=True)
    y = torch.tensor([4.], requires_grad=True)
    for i in range(10):
        t = torch.mul(x,y)
        t.backward()
        x.grad.zero_()
        print(x.grad)
tensor([4.])
tensor([4.])
tensor([4.])
tensor([4.])
tensor([4.])
tensor([4.])
tensor([4.])
tensor([4.])
tensor([4.])
tensor([4.])
  1. 依賴於葉子結點的結點,requires_grad預設為True
flag = True
# flag = False
if flag:
    x = torch.tensor([3.], requires_grad=True)
    y = torch.tensor([4.], requires_grad=True)
    t = torch.mul(x,y)
    t.backward()
    print(t.requires_grad)
True
  1. 葉子結點不可執行in-place
    in_place操作即原位操作,類似於x.grad.zero_().其中_就是原位操作
    在查閱相關資料後,個人覺得可以直接當成覆蓋操作,是否進行覆蓋運算,pandas 中 inplace 引數在很多函式中都會有,它的作用是:是否在原物件基礎上進行修改。 inplace = True:不建立新的物件,直接對原始物件進行修改;inplace = False:對資料進行修改,建立並返回新的物件承載其修改結果。預設是False,即建立新的物件進行修改,原物件不變,和深複製和淺複製有些類似。
    inplace是在原始記憶體中改變這個資料,為什麼葉子結點不可以inplace

邏輯迴歸

邏輯迴歸模型是一個線性二分類模型
模型表示式:

\[y = f(WX+b)\\ f(x)=\frac{1}{1+e^-x} \]

f(x)成為Sigmoid函式,也成為logistic函式

\[class = \begin{cases} 0&,&{0.5>y}\\ 1&,&{0.5 \leq y} \end{cases} \]

線性迴歸模型是分析自變數x因變數y(標量)之間關係的方法
邏輯迴歸是分析自變數x因變數y(概率)之間關係的方法,也可以說是把線性迴歸的基礎上加上了sigmoid函式
邏輯迴歸=對數機率迴歸

\[ln\frac{y}{1-y}=WX+b \]

對數迴歸

\[ln y = WX+B \]

機器學習模型訓練五個步驟
資料、模型、損失函式、優化器、迭代訓練

import torch
import torch.nn as nn
import matplotlib.pyplot as plt
import numpy as np
import os

os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE"
torch.manual_seed(7)

ones = torch.ones(100, 2)
x0 = torch.normal(ones, 1) + 1
x1 = torch.normal(-ones, 1) - 0.4
# print(x0)
y0 = torch.zeros(100)
y1 = torch.ones(100)
train_x = torch.cat((x0, x1), 0)
train_y = torch.cat((y0, y1), 0)
print(train_x.shape)
print(train_y.shape)


class LR(nn.Module):
    def __init__(self):
        super(LR, self).__init__()
        self.features = nn.Linear(2, 1)
        self.sigmoid = nn.Sigmoid()

    def forward(self, x):
        x = self.features(x)
        x = self.sigmoid(x)
        return x

lr_net = LR()
loss_fn = nn.BCELoss()

lr = 0.01
optimizer = torch.optim.SGD(lr_net.parameters(),lr = lr,momentum= 0.9)


for i in range(1000):
    y_hats = lr_net(train_x)

    loss = loss_fn(y_hats.squeeze(), train_y)

    loss.backward()

    optimizer.step()

    optimizer.zero_grad()

    if i %10 == 0:

        mask = y_hats.ge(0.5).float().squeeze()
        masky = (mask==train_y).sum()
        # print(train_y.sum().data.numpy())
        # print(masky.data.numpy())
        print( masky.item(),train_y.size()[0])
        acc = masky.item()/train_y.size()[0]

        plt.scatter(x0.data.numpy()[:, 0], x0.data.numpy()[:, 1])
        plt.scatter(x1.data.numpy()[:, 0], x1.data.numpy()[:, 1])
        plt.xlim(-6,6)
        plt.ylim(-10,10)
        w0,w1 = lr_net.features.weight[0]
        w0,w1 = float(w0.item()),float(w1.item())
        b = float(lr_net.features.bias[0].item())
        xd = np.arange(-6,6,0.1)
        yd = w0*xd+b
        plt.plot(xd,yd)
        plt.title("the acc:{}".format(acc))

        # plt.show()

        # plt.ion()
        plt.pause(1)
        plt.clf()
        if acc > 0.95:
            break