pytorch快速入門

Tensor

Tensor是PyTorch中重要的數(shù)據(jù)結(jié)構(gòu),可認(rèn)為是一個(gè)高維數(shù)組。它可以是一個(gè)數(shù)(標(biāo)量)、一維數(shù)組(向量)、二維數(shù)組(矩陣)以及更高維的數(shù)組。Tensor和Numpy的ndarrays類似,但Tensor可以使用GPU進(jìn)行加速。Tensor的使用和Numpy及Matlab的接口十分相似,下面通過幾個(gè)例子來(lái)看看Tensor的基本使用。
0.查看版本:
import torch as t
t.__version__
1.創(chuàng)建矩陣,只分配空間不初始化:
x=t.Tensor(5,3)
2.創(chuàng)建矩陣并初始化:
x=t.Tensor([[1,2],[3,4]])
x=t.rand(5,3) //使用[0,1]均勻分布隨機(jī)初始化二維數(shù)組
y=x.clone() //進(jìn)行數(shù)據(jù)拷貝,不在共用內(nèi)存
y=x.detach() //新建一個(gè)tensor,二者共用內(nèi)存
3.查看形狀:
print(x.size()),這兩種寫法等價(jià)x.size()[1] ,x.size(1)
4.加法
寫法1:
y=t.rand(5,3)
x+y
寫法2:
t.add(x,y)
寫法3:指定加法結(jié)果的輸出目標(biāo)為result
result = t.Tensor(5, 3) # 預(yù)先分配空間
t.add(x, y, out=result) # 輸入到result
寫法4:y不變
z=y.add(x)
寫法5:y改變,函數(shù)名后面帶下劃線_ 的函數(shù)會(huì)修改Tensor本身
z=y.add_(x)
5.Tensor和numpy數(shù)組互轉(zhuǎn)
Tensor和Numpy的數(shù)組之間的互操作非常容易且快速。對(duì)于Tensor不支持的操作,可以先轉(zhuǎn)為Numpy數(shù)組處理,之后再轉(zhuǎn)回Tensor.Tensor和numpy對(duì)象共享內(nèi)存,所以他們之間的轉(zhuǎn)換很快,而且?guī)缀醪粫?huì)消耗什么資源。但這也意味著,如果其中一個(gè)變了,另外一個(gè)也會(huì)隨之改變。
b = a.numpy() # Tensor -> Numpy
b = t.from_numpy(a) # Numpy->Tensor
6.Tensor取值
Tensor的取值不能直接用下標(biāo),下標(biāo)取出來(lái)的還是Tensor,所以需要先用下標(biāo)獲取一個(gè)scalar再用scalar.item()。一個(gè)0-dim 的tensor,一般稱為scalar。
z=y[0][0].item()
7.Tensor轉(zhuǎn)為GPU的tensor
Tensor可通過.cuda 方法轉(zhuǎn)為GPU的Tensor,從而享受GPU帶來(lái)的加速運(yùn)算.
在不支持CUDA的機(jī)器下,下一步還是在CPU上運(yùn)行
device = t.device("cuda:0" if t.cuda.is_available() else "cpu")
x = x.to(device)
y = y.to(x.device)
z = x+y

torch.nn

torch.nn是專門為神經(jīng)網(wǎng)絡(luò)設(shè)計(jì)的模塊化接口。nn構(gòu)建于 Autograd之上,可用來(lái)定義和運(yùn)行神經(jīng)網(wǎng)絡(luò)。nn.Module是nn中最重要的類,可把它看成是一個(gè)網(wǎng)絡(luò)的封裝,包含網(wǎng)絡(luò)各層定義以及forward方法,調(diào)用forward(input)方法,可返回前向傳播的結(jié)果。下面就以最早的卷積神經(jīng)網(wǎng)絡(luò):LeNet為例,來(lái)看看如何用nn.Module實(shí)現(xiàn)。


1、定義網(wǎng)絡(luò)
定義網(wǎng)絡(luò)時(shí),需要繼承nn.Module,并實(shí)現(xiàn)它的forward方法,把網(wǎng)絡(luò)中具有可學(xué)習(xí)參數(shù)的層放在構(gòu)造函數(shù)init中。如果某一層(如ReLU)不具有可學(xué)習(xí)的參數(shù),則既可以放在構(gòu)造函數(shù)中,也可以不放,但建議不放在其中,而在forward中使用nn.functional代替。

import torch.nn as nn
import torch.nn.functional as F

class Net(nn.Module):
    def __init__(self):
        # nn.Module子類的函數(shù)必須在構(gòu)造函數(shù)中執(zhí)行父類的構(gòu)造函數(shù)
        # 下式等價(jià)于nn.Module.__init__(self)
        super(Net, self).__init__()
        
        # 卷積層 '1'表示輸入圖片為單通道, '6'表示輸出通道數(shù),'5'表示卷積核為5*5
        self.conv1 = nn.Conv2d(1, 6, 5) 
        # 卷積層
        self.conv2 = nn.Conv2d(6, 16, 5) 
        # 仿射層/全連接層,y = Wx + b
        self.fc1   = nn.Linear(16*5*5, 120) 
        self.fc2   = nn.Linear(120, 84)
        self.fc3   = nn.Linear(84, 10)

    def forward(self, x): 
        # 卷積 -> 激活 -> 池化 
        x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2))
        x = F.max_pool2d(F.relu(self.conv2(x)), 2) 
        # reshape,‘-1’表示自適應(yīng)
        x = x.view(x.size()[0], -1) 
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)        
        return x

net = Net()
print(net)
#網(wǎng)絡(luò)的可學(xué)習(xí)參數(shù)通過net.parameters()返回,net.named_parameters可同時(shí)返回可學(xué)習(xí)的參數(shù)及名稱。
params = list(net.parameters())
print(len(params))
for name,parameters in net.named_parameters():
    print(name,':',parameters.size())

2.損失函數(shù)
nn實(shí)現(xiàn)了神經(jīng)網(wǎng)絡(luò)中大多數(shù)的損失函數(shù),例如nn.MSELoss用來(lái)計(jì)算均方誤差,nn.CrossEntropyLoss用來(lái)計(jì)算交叉熵?fù)p失。

output = net(input)
target = t.arange(0,10).view(1,10).float() 
criterion = nn.MSELoss()
loss = criterion(output, target)
loss # loss是個(gè)scalar
#反向傳播
net.zero_grad() # 把net中所有可學(xué)習(xí)參數(shù)的梯度清零
loss.backward()

3.優(yōu)化器
在反向傳播計(jì)算完所有參數(shù)的梯度后,還需要使用優(yōu)化方法來(lái)更新網(wǎng)絡(luò)的權(quán)重和參數(shù),例如隨機(jī)梯度下降法(SGD)的更新策略如下:
weight = weight - learning_rate * gradient
手動(dòng)實(shí)現(xiàn)如下:
learning_rate = 0.01
for f in net.parameters():
f.data.sub_(f.grad.data * learning_rate)# inplace 減法
torch.optim中實(shí)現(xiàn)了深度學(xué)習(xí)中絕大多數(shù)的優(yōu)化方法,例如RMSProp、Adam、SGD等,更便于使用,因此大多數(shù)時(shí)候并不需要手動(dòng)寫上述代碼。

import torch.optim as optim
#新建一個(gè)優(yōu)化器,指定要調(diào)整的參數(shù)和學(xué)習(xí)率
optimizer = optim.SGD(net.parameters(), lr = 0.01)

# 在訓(xùn)練過程中
# 先梯度清零(與net.zero_grad()效果一樣)
optimizer.zero_grad() 

# 計(jì)算損失
output = net(input)
loss = criterion(output, target)

#反向傳播
loss.backward()

#更新參數(shù)
optimizer.step()

基本套路

1、加載數(shù)據(jù)集
2、定義網(wǎng)絡(luò)
3、定義損失函數(shù)和優(yōu)化器
4、訓(xùn)練網(wǎng)絡(luò)并更新網(wǎng)絡(luò)參數(shù)
所有網(wǎng)絡(luò)的訓(xùn)練流程都是類似的,不斷地執(zhí)行如下流程:
輸入數(shù)據(jù),前向傳播+反向傳播,更新參數(shù)。

t.set_num_threads(8)
for epoch in range(2):  
    
    running_loss = 0.0
    for i, data in enumerate(trainloader, 0):
        
        # 輸入數(shù)據(jù)
        inputs, labels = data
        
        # 梯度清零
        optimizer.zero_grad()
        
        # forward + backward 
        outputs = net(inputs)
        loss = criterion(outputs, labels)
        loss.backward()   
        
        # 更新參數(shù) 
        optimizer.step()
        
        # 打印log信息
        # loss 是一個(gè)scalar,需要使用loss.item()來(lái)獲取數(shù)值,不能使用loss[0]
        running_loss += loss.item()
        if i % 2000 == 1999: # 每2000個(gè)batch打印一下訓(xùn)練狀態(tài)
            print('[%d, %5d] loss: %.3f' \
                  % (epoch+1, i+1, running_loss / 2000))
            running_loss = 0.0
print('Finished Training')

5、測(cè)試網(wǎng)絡(luò)

在GPU上訓(xùn)練

就像把Tensor從CPU轉(zhuǎn)到GPU一樣,模型也可以類似地從CPU轉(zhuǎn)到GPU。

device = t.device("cuda:0" if t.cuda.is_available() else "cpu")

net.to(device)
images = images.to(device)
labels = labels.to(device)
output = net(images)
loss= criterion(output,labels)

loss
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容