【pytorch閱讀筆記】pytorch基礎知識

本部分共分爲5部分:

  • 基本數據
  • Autograd與計算圖
  • 神經網絡工具箱:torch.nn
  • 模型處理 torchvision.model
  • 數據處理

pytorch最大的優勢是可以使用tensor代替numpy進行對應的矩陣操作並且支持對應的GPU加速。

1.pytorch基本數據: tensor

tensor的使用類似於numpy

  • tensor創建與維度的查看

    • torch.tensor()
    • torch.zeros()
    • torch.ones()
    • torch.randn()
    • torch.arrange()
    • a.shape
    • a.size()
  • tensor的組合與分塊

    • torch.cat()
    • torch.stack()
    • torch.chunk()
    • torch.split()
  • tensor索引與變形

    • torch.view()
    • torch.resize()
    • torch.reshape()
      (上述三者功能一致,自由變形)
    • torch.transpose()
    • torch.permute()
      (各維度之間變換)
    • torch.squeeze()
    • torch.unsqueeze()
      (增加某全1維度,或刪除全1維度)
  • tensor的排序與取極值

    • a.sort( 0, true) [0]
      (按0維排序,true爲降序,[0] 表示值,[1]表示索引)
    • a.max(0)
      (按0維度選取最大值,將每列最大值選出)
  • 自動廣播機制與向量化
    自動廣播:表示不同形狀的tensor(向量)能自動擴展到較大的形狀,並進行相應的計算

廣播機制前提:

  1. 任一tensor至少有一個維度
    2.從尾部開始遍歷(非從頭對應),兩者維度必須相等,要不其中爲1,要不不存在
a = torch.one (3,1,2)
b = torch.one(2,1)
c = torch.one(2,3)
a + b 雖形狀不同但可以相加
a + c 不行,尾部爲23
  • tensor的內存共享
    即當原始數據改變時,拷貝得到的tensor也會進行相應的改變
  • tensor直接初始化另一個: a = b , c = a.view
  • 原地運算操作符 :a = b.add_()
  • tensor與numpy可以互相轉換: a.numpy() | b.from_numpy(a)

2.Autograd與計算圖

默認爲不求導,需要參數

a = torch.randn(2,2, requires_grad = True)

即可進行求導

3.神經網絡工具箱 torch.nn

nn.model

  • nn.parameter 函數默認需要求導,即requires_grad = True
  • nn.Model自動利用反向傳播,Autograd機制。
  • nn.functional :也提供網絡層和函數,但區別於nn.model,不可自動學習參數,需要用nn.parameter封裝。
    • nn.functional : 設計初衷針對不需要自動求導的網絡層,如BN, 激活等
    • nn.Model: 設計針對需要自動求導的網絡層,如池化,卷積,全連接等
  • nn.Sequential :不考慮中間結果的線性無腦搭建,類似keras

損失函數

主要的損失函數在nn 和nn.functional 庫中
舉例:
loss_functional = F.cross_entropy(output, label)

實踐舉例

用我基友的一個例子

import torch
from torch.autograd import Variable #自動求導
import torch.nn.functional as F 
import matplotlib.pyplot as plt

x = torch.unsqueeze(torch.linspace(-1,1,100),dim=1) 
#linspace : 線性生成器,從-1 到1,一共平均生成100個數,
#dim = 1 以第二維度,行維度,全部增加1 (0無法進行求導,大部分情況自動補1,作爲可學習參數的初始化,這裏指二分類的初始化)
y = x.pow(2) + 0.2*torch.rand(x.size()) 
# 以x的維度尺寸,隨機數和x平方相加

x,y = Variable(x),Variable(y)
#打印圖片
plt.scatter(x.data.numpy(),y.data.numpy())
plt.show()


#建立網絡模型類
class Net(torch.nn.Module):
    def __init__(self,n_features,n_hidden,n_output): 
        super(Net,self).__init__() 
        # 繼承nn.module的構造函數初始化
        
        self.hidden=torch.nn.Linear(n_features,n_hidden)
        #建立線性層,輸入,輸出(隱藏層)
        self.predit=torch.nn.Linear(n_hidden,n_output)

    #建立向前傳播的圖(由於pytorch動態生成前向圖的緣故)
    def forward(self,x):  
        x = F.relu(self.hidden(x))
        x = self.predit(x)  
        return x

optimizer = torch.optim.SGD(net.parameters(),lr=0.5)
loss_func = torch.nn.MSELoss()
#定義對應的優化器和損失函數




net = Net(1,10,1)
#構建對應的網絡類,內部參數 n_features =1,n_hidden= 10 ,n_output =1
#故爲二分類問題,隱藏層有10個

for t in range(100):
#迭代100次進行訓練
    prediction =net(x)
    loss = loss_func(prediction,y) 
    # 損失函數參數: prediction 前向值,y 標籤值
    optimizer.zero_grad() #將所有參數的梯度全部降爲0,梯度值保留在這個裏面
    loss.backward()   
    #自動反向傳播過程
    optimizer.step()   
    #優化器更新


    if t%5==0:
    #每5次打印
        plt.cla()
        plt.scatter(x.data.numpy(),y.data.numpy())
        plt.plot(x.data.numpy(),prediction.data.numpy(),'r-',lw=5)
        plt.text(0.5,0,'Loss=%.4f' % loss.data,fontdict={'size':20,'color':'red'})
        plt.pause(0.1)

4.模型處理 torchvision.models

torchvision是一個獨立的庫,作用爲可以快速搭物體檢測網絡並含有大量封裝模型,例如:VGG.Resnet,Inception等等

加載自己的模型

加載模型,即加載對應的state_dict()
state_dict():記錄模型狀態的字典。由於在保存模型時不需要把所有代碼都進行保存,僅需要保存可學習的參數即可,(例如卷積層,全連接等),所以需要有存在保存模型可學習參數(狀態)的字典。

  • key:每個模型層名字
  • value: 該層對應的參數w,b等

每個模型都可以有自己的state_dict(),(優化器也有)

應用於模型加載的常用函數:
(1) torch.save(): 可保存模型,優化器等
(2) torch.load(‘你的模型路徑’): 加載模型
(3) torch.nn.Model.load_state_dict():通過去序列化的state_dict來加載模型權重(去掉鍵值關係的key value)

5.數據加載

pytorch提供了標準化的數據集處理框架

繼承Dataset 類 -------》增加數據變換 -------》繼承Dataloader

Dataset繼承

提供了torch.utils.data.Dataset 類 ,使用時需要重寫_len_( ) 和 _ getitem _( )

from torch.utils.data import Dataset
import torch
class MyDateset(Dataset):
    def __init__(self,num=10000,transform=None):  #這裏就可以寫你的參數了,比如文件夾什麼的。
        self.len=num
        self.transform=transform
    def __len__(self):
        return self.len
    def __getitem__(self,idx): #用於按照索引讀取每個元素的具體內容
        data=torch.rand(3,3,5)  #這裏就是你的數據圖像的話就是C*M*N的tensor,這裏創建了一個3*3*5的張量
        label=torch.LongTensor([1])   #label也是需要一個張量
        if self.transform:    #這裏就是數據預處理的部分 、
            data=self.transform(data)  #處理完必須要返回torch.Tensor類型
        return data,label

數據增強

提供了torchvision.transforms

dataloader

之前所說的Dataset類是讀入數據集數據並且對讀入的數據進行了索引。但是光有這個功能是不夠用的,在實際的加載數據集的過程中,我們的數據量往往都很大,對此我們還需要一下幾個功能:

  • 可以分批次讀取:batch-size
  • 可以對數據進行隨機讀取,可以對數據進行洗牌操作(shuffling),打亂數據集內數據分佈的順序
  • 可以並行加載數據(利用多核處理器加快載入數據的效率)

這時候就需要Dataloader類了,Dataloader這個類並不需要我們自己設計代碼,我們只需要利用DataLoader類讀取我們設計好的ShipDataset即可:

# 利用之前創建好的ShipDataset類去創建數據對象
ship_train_dataset = ShipDataset(data_path, augment=transform)
# 利用dataloader讀取我們的數據對象,並設定batch-size和工作現場
ship_train_loader = DataLoader(ship_train_dataset, batch_size=16, num_workers=4, shuffle=False, **kwargs)

完整代碼

dataset加載圖片和標籤,做成一個類,並完成迭代方法

from PIL import Image
import torch
 
class MyDataset(torch.utils.data.Dataset): #創建自己的類:MyDataset,這個類是繼承的torch.utils.data.Dataset
    def __init__(self,root, datatxt, transform=None, target_transform=None): #初始化一些需要傳入的參數
        super(MyDataset,self).__init__()
        fh = open(root + datatxt, 'r') #按照傳入的路徑和txt文本參數,打開這個文本,並讀取內容
        imgs = []                      #創建一個名爲img的空列表,一會兒用來裝東西
        for line in fh:                #按行循環txt文本中的內容
            line = line.rstrip()       # 刪除 本行string 字符串末尾的指定字符,這個方法的詳細介紹自己查詢python
            words = line.split()   #通過指定分隔符對字符串進行切片,默認爲所有的空字符,包括空格、換行、製表符等
            imgs.append((words[0],int(words[1]))) #把txt裏的內容讀入imgs列表保存,具體是words幾要看txt內容而定
                                        # 很顯然,根據我剛纔截圖所示txt的內容,words[0]是圖片信息,words[1]是lable
        self.imgs = imgs
        self.transform = transform
        self.target_transform = target_transform
 
    def __getitem__(self, index):    #這個方法是必須要有的,用於按照索引讀取每個元素的具體內容
        fn, label = self.imgs[index] #fn是圖片path #fn和label分別獲得imgs[index]也即是剛纔每行中word[0]和word[1]的信息
        img = Image.open(root+fn).convert('RGB') #按照path讀入圖片from PIL import Image # 按照路徑讀取圖片
 
        if self.transform is not None:
            img = self.transform(img) #是否進行transform
        return img,label  #return很關鍵,return回哪些內容,那麼我們在訓練時循環讀取每個batch時,就能獲得哪些內容
 
    def __len__(self): #這個函數也必須要寫,它返回的是數據集的長度,也就是多少張圖片,要和loader的長度作區分
        return len(self.imgs)
 
#根據自己定義的那個MyDataset來創建數據集!注意是數據集!而不是loader迭代器
train_data=MyDataset(txt=root+'train.txt', transform=transforms.ToTensor())
test_data=MyDataset(txt=root+'test.txt', transform=transforms.ToTensor())

使用Dataloader,進行對應的batch讀入,是否洗牌等

#然後就是調用DataLoader和剛剛創建的數據集,來創建dataloader,這裏提一句,loader的長度是有多少個batch,所以和batch_size有關
train_loader = DataLoader(dataset=train_data, batch_size=64, shuffle=True)
test_loader = DataLoader(dataset=test_data, batch_size=64)
 

使用數據集時:

for batch_index, data, target in test_loader:
        if use_cuda:
            data, target = data.cuda(), target.cuda()
        data, target = Variable(data, volatile=True), Variable(target)

_ getitem _( ) 作爲迭代器,能直接進行使用
python迭代器:

  • iter 創建對應迭代器
  • next 給出下一個數據

tips : 在用 for…in… 迭代對象時,如果對象沒有實現 __ iter __ , __ next __ 迭代器協議,Python的解釋器就會去尋找__getitem__ 來迭代對象.

6.GPU加速

  • torch.cuda.is_available() 判斷GPU是否可用
  • device = torch.device(“cuda : 1”) 指定轉移到哪塊GPU上
  • CUDA_VISIBLE_DEVICES = 2 全局指定使用哪塊GPU

碼字不易,如果對你有用,點個贊再走唄~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章