欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

pytorch搭建模型的五大層次級別解讀(由淺入深)

 更新時間:2023年06月15日 08:57:02   作者:LoveMIss-Y  
這篇文章主要介紹了pytorch搭建模型的五大層次級別(由淺入深),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

前言

神經(jīng)網(wǎng)絡的搭建本身是一個較為復雜的過程,但是現(xiàn)在有非常多的、非常人性化的開源框架提供給我們使用,但是即便如此,網(wǎng)絡的搭建也是有多種方法可以選擇,本文以pytorch為例子加以說明。

神經(jīng)網(wǎng)絡的基本流程可以分為兩大步驟,即

網(wǎng)絡結(jié)構(gòu)搭建+參數(shù)的梯度更新(后者又包括  “前向傳播+計算參數(shù)的梯度+梯度更新”)

這其實也是后面pytorch搭建神經(jīng)網(wǎng)絡的一個基本思路

1 、原始搭建——使用numpy實現(xiàn)

# -*- coding: utf-8 -*-
import numpy as np
# N是訓練的batch size; D_in 是input輸入數(shù)據(jù)的維度;
# H是隱藏層的節(jié)點數(shù); D_out 輸出的維度,即輸出節(jié)點數(shù).
N, D_in, H, D_out = 64, 1000, 100, 10
# 創(chuàng)建輸入、輸出數(shù)據(jù)
x = np.random.randn(N, D_in)  #(64,1000)
y = np.random.randn(N, D_out) #(64,10)可以看成是一個10分類問題
# 權(quán)值初始化
w1 = np.random.randn(D_in, H)  #(1000,100),即輸入層到隱藏層的權(quán)重
w2 = np.random.randn(H, D_out) #(100,10),即隱藏層到輸出層的權(quán)重
learning_rate = 1e-6   #學習率
for t in range(500):
    # 第一步:數(shù)據(jù)的前向傳播,計算預測值p_pred
    h = x.dot(w1)
    h_relu = np.maximum(h, 0)
    y_pred = h_relu.dot(w2)
    # 第二步:計算計算預測值p_pred與真實值的誤差
    loss = np.square(y_pred - y).sum()
    print(t, loss)
    # 第三步:反向傳播誤差,更新兩個權(quán)值矩陣
    grad_y_pred = 2.0 * (y_pred - y)     #注意:這里的導函數(shù)也是自己求的,因為這個地方是很簡答的函數(shù)表達式
    grad_w2 = h_relu.T.dot(grad_y_pred)
    grad_h_relu = grad_y_pred.dot(w2.T)
    grad_h = grad_h_relu.copy()
    grad_h[h < 0] = 0
    grad_w1 = x.T.dot(grad_h)
    # 更新參數(shù)
    w1 -= learning_rate * grad_w1
    w2 -= learning_rate * grad_w2

缺點:

(1)沒辦法搭建復雜的網(wǎng)絡結(jié)構(gòu)(網(wǎng)絡的結(jié)構(gòu)搭建太底層);

(2)梯度需要自己求導函數(shù),如果函數(shù)太復雜,網(wǎng)絡太深就很難求了;

(3)沒有辦法使用GPU加速

2、使用torch的Tensor原始實現(xiàn)

import torch
dtype = torch.float
device = torch.device("cpu")
# device = torch.device("cuda:0") # 這里使用CPU,但實際上可以使用GPU
# N是訓練的batch size; D_in 是input輸入數(shù)據(jù)的維度;
# H是隱藏層的節(jié)點數(shù); D_out 輸出的維度,即輸出節(jié)點數(shù).
N, D_in, H, D_out = 64, 1000, 100, 10
# 創(chuàng)建輸入、輸出數(shù)據(jù)
x = torch.randn(N, D_in, device=device, dtype=dtype)  #(64,1000)
y = torch.randn(N, D_out, device=device, dtype=dtype) #(64,10)可以看成是一個10分類問題
# 權(quán)值初始化
w1 = torch.randn(D_in, H, device=device, dtype=dtype) #(1000,100),即輸入層到隱藏層的權(quán)重
w2 = torch.randn(H, D_out, device=device, dtype=dtype)#(100,10),即隱藏層到輸出層的權(quán)重
learning_rate = 1e-6
for t in range(500):
    # 第一步:數(shù)據(jù)的前向傳播,計算預測值p_pred
    h = x.mm(w1)
    h_relu = h.clamp(min=0)
    y_pred = h_relu.mm(w2)
    # 第二步:計算計算預測值p_pred與真實值的誤差
    loss = (y_pred - y).pow(2).sum().item()
    print(t, loss)
    # 第三步:反向傳播誤差,更新兩個權(quán)值矩陣
    grad_y_pred = 2.0 * (y_pred - y)    #注意:這里的導函數(shù)也是自己求的,因為這個地方是很簡答的函數(shù)表達式
    grad_w2 = h_relu.t().mm(grad_y_pred)
    grad_h_relu = grad_y_pred.mm(w2.t())
    grad_h = grad_h_relu.clone()
    grad_h[h < 0] = 0
    grad_w1 = x.t().mm(grad_h)
    # 參數(shù)更新(梯度下降法)
    w1 -= learning_rate * grad_w1
    w2 -= learning_rate * grad_w2

缺點:

(1)沒辦法搭建復雜的網(wǎng)絡結(jié)構(gòu)(網(wǎng)絡的結(jié)構(gòu)搭建太底層);

(2)梯度需要自己求導函數(shù),如果函數(shù)太復雜,網(wǎng)絡太深就很難求了;

解決了GPU計算問題、少了一個缺點。

3、torch的自動求導autograd

import torch
dtype = torch.float
device = torch.device("cpu")
# device = torch.device("cuda:0") # 這里使用CPU,但實際上可以使用GPU
# N是訓練的batch size; D_in 是input輸入數(shù)據(jù)的維度;
# H是隱藏層的節(jié)點數(shù); D_out 輸出的維度,即輸出節(jié)點數(shù).
N, D_in, H, D_out = 64, 1000, 100, 10
# 創(chuàng)建輸入、輸出數(shù)據(jù)
x = torch.randn(N, D_in, device=device, dtype=dtype)  #(64,1000)
y = torch.randn(N, D_out, device=device, dtype=dtype) #(64,10)可以看成是一個10分類問題
# 權(quán)值初始化
w1 = torch.randn(D_in, H, device=device, dtype=dtype) #(1000,100),即輸入層到隱藏層的權(quán)重
w2 = torch.randn(H, D_out, device=device, dtype=dtype)#(100,10),即隱藏層到輸出層的權(quán)重
learning_rate = 1e-6
for t in range(500):
    # 第一步:數(shù)據(jù)的前向傳播,計算預測值p_pred
    y_pred = x.mm(w1).clamp(min=0).mm(w2)
    # 第二步:計算計算預測值p_pred與真實值的誤差
    loss = (y_pred - y).pow(2).sum()
    print(t, loss.item())
    # 第三步:反向傳播誤差,更新兩個權(quán)值矩陣,這就是關鍵了,不再需要自己寫出導函數(shù),求導是自動完成的
    loss.backward()  #一步到位、自動求導
    # 參數(shù)梯度更新
    with torch.no_grad():
        w1 -= learning_rate * w1.grad  #grad屬性獲取梯度,其實這個地方就是相當于是梯度下降法,優(yōu)化的過程可以自己定義,因為這里參數(shù)很少
        w2 -= learning_rate * w2.grad
        求完一次之后將梯度歸零
        w1.grad.zero_()
        w2.grad.zero_()

缺點:

(1)沒辦法搭建復雜的網(wǎng)絡結(jié)構(gòu)(網(wǎng)絡的結(jié)構(gòu)搭建太底層);

解決了GPU計算問題、而且梯度導數(shù)也不用自己求了,少了兩個缺點。那現(xiàn)在就只剩一個問題沒解決了,那就是怎么快速搭建更復雜、更深層的網(wǎng)絡結(jié)構(gòu)。

(2)上面更新參數(shù)w1和w2的過程其實就是一個優(yōu)化過程,這里是用的就是簡單的頭下降法,這樣做有一個很大的缺點,那就是這里只有兩個參數(shù)需要優(yōu)化,所以可以自己寫,但是現(xiàn)在的網(wǎng)絡有很多的參數(shù)需要優(yōu)化,都自己寫的話實在是太麻煩了。于是就有了后面的方法,參見下面

4、使用pytorch.nn模塊

可以將它理解為一個較高層次的API封裝

# -*- coding: utf-8 -*-
import torch
# N是訓練的batch size; D_in 是input輸入數(shù)據(jù)的維度;
# H是隱藏層的節(jié)點數(shù); D_out 輸出的維度,即輸出節(jié)點數(shù).
N, D_in, H, D_out = 64, 1000, 100, 10
# 創(chuàng)建輸入、輸出數(shù)據(jù)
x = torch.randn(N, D_in)
y = torch.randn(N, D_out)
#模型搭建:這是與前面關鍵的區(qū)別,不再需要自己手動進行矩陣相乘,而是這種一步到位的方法
model = torch.nn.Sequential(
    torch.nn.Linear(D_in, H),
    torch.nn.ReLU(),
    torch.nn.Linear(H, D_out),
)
#定義損失函數(shù)
loss_fn = torch.nn.MSELoss(reduction='sum')
learning_rate = 1e-4
for t in range(500):
    # 第一步:數(shù)據(jù)的前向傳播,計算預測值p_pred
    y_pred = model(x)
    # 第二步:計算計算預測值p_pred與真實值的誤差
    loss = loss_fn(y_pred, y)
    print(t, loss.item())
    # 在反向傳播之前,將模型的梯度歸零
    model.zero_grad()
    # 第三步:反向傳播誤差,更新兩個權(quán)值矩陣,這就是關鍵了,不再需要自己寫出導函數(shù),求導是自動完成的
    loss.backward()
    #更新參數(shù)的梯度
    with torch.no_grad():
        for param in model.parameters():
            param -= learning_rate * param.grad #這其實就是梯度下降法,優(yōu)化參數(shù),通過循環(huán)自動實現(xiàn),不要再一個一個寫了,相較于上面的參數(shù)更新方法簡單了很多。但是還不夠

總結(jié):

到這一步,基本解決了前面的三個致命問題,即解決了GPU計算問題、而且梯度導數(shù)也不用自己求了,并且可以搭建復雜的網(wǎng)絡,不需要自己進行一個一個的矩陣相乘,少了三個缺點。

使用這里的層次,一些簡單的網(wǎng)絡類型就沒什么問題了,當然我們還可以進一步優(yōu)化,因為上面我們對loss進行自動求導之后,還需要通過一個循環(huán)來對模型的各個參數(shù)逐個進行參數(shù)的更新,所以下面提供了兩個層次方面的優(yōu)化措施:

5、使用torch.optim

來進一步簡化訓練過程——進一步省略手動的參數(shù)更新,更加一步到位

# -*- coding: utf-8 -*-
import torch
# N是訓練的batch size; D_in 是input輸入數(shù)據(jù)的維度;
# H是隱藏層的節(jié)點數(shù); D_out 輸出的維度,即輸出節(jié)點數(shù).
N, D_in, H, D_out = 64, 1000, 100, 10
# 創(chuàng)建輸入、輸出數(shù)據(jù)
x = torch.randn(N, D_in)
y = torch.randn(N, D_out)
#模型搭建:這是與前面關鍵的區(qū)別,不再需要自己手動進行矩陣相乘,而是這種一步到位的方法
model = torch.nn.Sequential(
    torch.nn.Linear(D_in, H),
    torch.nn.ReLU(),
    torch.nn.Linear(H, D_out),
)
#定義損失函數(shù)
loss_fn = torch.nn.MSELoss(reduction='sum')
learning_rate = 1e-4
#構(gòu)造一個optimizer對象
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)
for t in range(500):
    # 第一步:數(shù)據(jù)的前向傳播,計算預測值p_pred
    y_pred = model(x)
    # 第二步:計算計算預測值p_pred與真實值的誤差
    loss = loss_fn(y_pred, y)
    print(t, loss.item())
    # 在反向傳播之前,將模型的梯度歸零,這
    optimizer.zero_grad()
    # 第三步:反向傳播誤差
    loss.backward()
    # 直接通過梯度一步到位,更新完整個網(wǎng)絡的訓練參數(shù),一句話優(yōu)化所有的參數(shù),是不是很牛逼
    optimizer.step()

這是不是更加簡單了?

如果是使用過keras這樣高層次的API,所以到這里應該發(fā)現(xiàn),他們實在是太像了,現(xiàn)在來總結(jié)一下使用pytorch搭建神經(jīng)網(wǎng)路的一般步驟:

(1)第一步:搭建網(wǎng)絡的結(jié)構(gòu),得到一個model。網(wǎng)絡的結(jié)構(gòu)可以是上面這種最簡單的序貫模型,當然還可以是多輸入-單輸出模型、單輸入-多輸出模型、多輸入-多輸出模型、跨層連接的模型等,我們好可以自己定義模型,后面再講。

(2)第二步:定義損失函數(shù)。

loss?= torch.nn.MSELoss(reduction='sum')

(3)第二步:定義優(yōu)化方式。構(gòu)造一個optimizer對象

optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)

上面是模型以及模型相關的配置三步走,下面是訓練的五步走。

(1)第一步:計算y_pred;

(2)第二步:根據(jù)損失函數(shù)計算loss

(3)第三步:梯度歸零,

optimizer.zero_grad()

(4)第四步:反向傳播誤差

loss.backward()

(5)更新參數(shù),使用step()

optimizer.step()

個人觀點:

深度學習框架最大的地方在于兩個點,正是這兩個點大大簡化了我們自己的實現(xiàn)思路,當然這兩個點不在于一層一層的搭建,個人認為最重要的在于以下兩個:

(1)第一,自動求導。設想一下,如果一個如此復雜的“高維度”、“非線性”的函數(shù),需要自己寫出求導公式,在進行矩陣運算,這一項就很不現(xiàn)實了。

(2)第二,參數(shù)的優(yōu)化。即所謂的optimizer的作用,它是每一個參數(shù)的更新規(guī)則,由于模型參數(shù)眾多,不可能一個一個來更新,而且沒一個更新的原理是重復的,深度學習框架正好提供了一步到位的方法,不管是tensorflow還是pytorch。

總結(jié)

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關文章

  • Qt自定義Plot實現(xiàn)曲線繪制的詳細過程

    Qt自定義Plot實現(xiàn)曲線繪制的詳細過程

    這篇文章主要介紹了Qt自定義Plot實現(xiàn)曲線繪制,包含arm觸摸屏多點觸控縮放(只支持兩點),實時曲線繪制,數(shù)據(jù)點根據(jù)繪制寬度優(yōu)化,跟蹤點數(shù)據(jù)獲取,雙坐標等功能,需要的朋友可以參考下
    2021-11-11
  • pytorch torch.expand和torch.repeat的區(qū)別詳解

    pytorch torch.expand和torch.repeat的區(qū)別詳解

    這篇文章主要介紹了pytorch torch.expand和torch.repeat的區(qū)別詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-11-11
  • 詳解Python調(diào)試神器之PySnooper

    詳解Python調(diào)試神器之PySnooper

    在程序開發(fā)過程中,代碼的運行往往會和我們預期的結(jié)果有所差別。于是,我們需要清楚代碼運行過程中到底發(fā)生了什么?代碼哪些模塊運行了,哪些模塊沒有運行?輸出的局部變量是什么樣的?PySnooper,能夠大大減少調(diào)試過程中的工作量
    2021-11-11
  • 淺談python中的變量默認是什么類型

    淺談python中的變量默認是什么類型

    python中的變量默認是什么類型呢?還有很多新手不太明白。下面小編就為大家介紹一下python中的變量默認是什么類型。一起跟隨小編過來看看吧
    2016-09-09
  • 從基礎到高階探索Python中的文件操作

    從基礎到高階探索Python中的文件操作

    文件操作在Python編程中是不可或缺的一部分,在本篇博客中,我們將全面、深入地探討Python中的文件操作,感興趣的小伙伴可以跟隨小編一起學習學習
    2023-06-06
  • Python3.5 創(chuàng)建文件的簡單實例

    Python3.5 創(chuàng)建文件的簡單實例

    下面小編就為大家分享一篇Python3.5 創(chuàng)建文件的簡單實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-04-04
  • Python爬取網(wǎng)頁信息的示例

    Python爬取網(wǎng)頁信息的示例

    這篇文章主要介紹了Python爬取網(wǎng)頁信息的示例,幫助大家更好的理解和學習python 爬蟲,感興趣的朋友可以了解下
    2020-09-09
  • Python標準庫中隱藏的利器(示例詳解)

    Python標準庫中隱藏的利器(示例詳解)

    在命令行中直接使用Python標準庫的模塊,最大的好處就是就是不用寫代碼,就能使用其中的功能,當臨時需要一些某些功能的時候,用這種方式會快捷,方便很多,這篇文章主要介紹了Python標準庫中隱藏的利器,需要的朋友可以參考下
    2023-11-11
  • 使用python制作一個解壓縮軟件

    使用python制作一個解壓縮軟件

    這篇文章主要介紹了python制作一個解壓縮軟件的方法,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-11-11
  • Python?第三方庫?Pandas?數(shù)據(jù)分析教程

    Python?第三方庫?Pandas?數(shù)據(jù)分析教程

    這篇文章主要介紹了Python?第三方庫?Pandas?數(shù)據(jù)分析教程的相關資料,需要的朋友可以參考下
    2022-09-09

最新評論