Pytorch學習筆記(一)——簡介


一、Tensor

Tensor是Pytorch中重要的數據結構,可以認為是一個高維數組。Tensor可以是一個標量、一維數組(向量)、二維數組(矩陣)或者高維數組等。Tensor和numpy的ndarrays相似。

import torch as t

構建矩陣:x = t.Tensor(m, n)

注意這種情況下只分配了空間,並沒有初始化。

使用[0,1]均勻分布隨機初始化矩陣:x = t.rand(m, n)

查看x的形狀:x.size()

加法:

(1)x + y

(2)t.add(x, y)

(3)t.add(x, y, out = res)

(4)y.add(x) #不改變y的內容

(5)y.add_(x) #改變y的內容

注意,函數名后面帶下划線_的函數會修改Tensor本身,而x.add(y)等則會返回一個新的Tensor,而x不變。

Tensor可以進行數學運算、線性代數、選擇、切片等。而且Tensor與numpy的數組間互操作十分方便。對於Tensor不支持的操作可以先轉為numpy處理,再轉為Tensor。

a = t.ones(5)
b = a.numpy()  # Tensor -> Numpy

a = np.ones(5)
b = t.from_numpy(a)  # Numpy -> Tensor

Tensor和numpy的對象是共享內存的,如果其中一個改變,那么另一個也會隨之改變。

Tensor可以通過.cuda方法轉為GPU的Tensor。GPU加速:

if t.cuda.is_available():
    x = x.cuda()
    y = y.cuda()
    x + y

二、Autograd:自動微分

Pytorch的Autograd模塊實現了求導功能,在Tensor上的所有操作,Autograd都能自動為它們提供微分。

autograd.Variable是Autograd的核心類,簡單封裝了Tensor,並幾乎支持所有的Tensor操作。當Tensor被封裝為Variable后,可以通過調用.backward實現反向傳播,自動計算所有的梯度。

Variable包括三個屬性:

(1)data:保存Variable包含的Tensor;

(2)grad:保存data對應的梯度,grad也是個Variable;

(3)grad_fn:指向一個Function對象,該Function用於反向傳播計算輸入的梯度。

from torch.autograd import Variable
x = Variable(t.ones(2, 2), requires_grad = True)
y = x.sum()
print(y.grad_fn)
y.backward()
print(x.grad)
y.backward()
print(x.grad)

注意,grad在反向傳播中是累加的,也就是說每次運行反向傳播時梯度都會累加之前的梯度,因此需要反向傳播之前要把梯度清零。

x.grad.data.zero_()  # inplace操作,把x的data對應的梯度值清零

Variable和Tensor的轉換:
x = Variable(t.ones(4, 5))
y = t.cos(x)
x_tensor_cos = t.cos(x.data)   # Variable x的data的cosine對應的Tensor

三、神經網絡

torch.nn是專門為神經網絡設計的模塊化接口。nn.Module可以看做是一個網絡的封裝,包括網絡各層的定義以及forward方法,調用forward(input)方法,可返回前向傳播的結果。

LeNet網絡結構如下圖:

 

定義網絡時,要繼承nn.Module,並實現它的forward方法,把網絡中具有可學習參數的層放在構造函數__init__中。如果某層不具有可學習的參數,則既可以放在構造函數中,也可以不放。

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

class Net(nn.Module):
    def __init__(self):
        # nn.Module子類的函數必須在構造函數中執行父類的構造函數
        # 下式等價於nn.Module.__init__(self)
        super(Net, self).__init__()
        # '1'表示輸入圖像為單通道,'6'表示輸出通道數
        # '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'表示自適應
        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)

運行結果:

 

只要在nn.Module的子類中定義了forward函數,backward函數就會被自動實現。網絡的可學習參數通過net.parameters()返回,而net.named_parameters可同時返回可學習的參數及名稱。

params = list(net.parameters())
print(len(params))

for name, parameters in net.named_parameters():
    print(name, ':', parameters.size())

運行結果:

 

注意,輸入和輸出都必須是Variable。

torch.nn只支持mini-batches,不支持一次只輸入一個樣本,也就是說一次必須是一個batch。如果只想輸入一個樣本,那么要用input.unsqueeze(0)將batch_size設為1。

損失函數:

(1)nn.MSELoss用於計算均方誤差

(2)nn.CrossEntropyLoss用於計算交叉熵損失

output = net(input)
target = Variable(t.arange(0, 10))
target = target.float()
criterion = nn.MSELoss()
loss = criterion(output, target)

在反向傳播計算所有參數的梯度后,還需要使用優化方法更新網絡的權重和參數,如SGD:

weight = weight - lr * gradient

手工實現如下:

lr = 0.01
for f in net.parameters():
    f.data.sub_(f.grad.data * lr)
torch.optim中實現了深度學習中的絕大多數優化方法,如RMSProp、Adam、SGD等。

# 新建一個優化器,指定要調整的參數和學習率
optimizer = optim.SGD(net.parameters(), lr = 0.01)

# 訓練過程中,先梯度清零
optimizer.zero_grad()

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

# 反向傳播
loss.backward()
optimizer.step()

torchvision實現了常用的圖像數據加載功能。

四、CIFAR-10 分類

import torch.nn as nn
import torch as t
from torch.autograd import Variable
import torch.nn.functional as F
import torch.optim as optim
import torchvision as tv
import torchvision.transforms as transforms
from torchvision.transforms import ToPILImage

show = ToPILImage() # 把Tensor轉換成Image,方便可視化

# 數據預處理
transform = transforms.Compose([transforms.ToTensor(), # 轉為Tensor
            transforms.Normalize((0.5, 0.5, 0.5), (0.5,0.5, 0.5)),])

# 訓練集
trainset = tv.datasets.CIFAR10(root = 'F:/PycharmProjects/', train = True, download =
            True, transform = transform)
trainloader = t.utils.data.DataLoader(trainset, batch_size = 4, shuffle = True, num_workers = 2)

# 測試集
testset = tv.datasets.CIFAR10(root = 'F:/PycharmProjects/', train = False, download =
            True, transform = transform)
testloader = t.utils.data.DataLoader(testset, batch_size = 4, shuffle = False, num_workers = 2)

classes = ('plane', 'car', 'bird', 'cat',
           'deer', 'dog', 'frog', 'horse', 'ship', 'truck')

(data, label) = trainset[100]
print(classes[label])

show((data + 1) / 2).resize(100, 100)

# 將dataset返回的每一條數據樣本拼接成一個batch
dataiter = iter(trainloader)
images, labels = dataiter.next()
print(' '.join('%11s' % classes[labels[j]] for j in range(4)))
show(tv.utils.make_grid((images + 1) / 2)).resize((400, 100))

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(3, 6, 5)
        self.conv2 = nn.Conv2d(6, 16, 5)
        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)
        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()
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr = 0.001, momentum = 0.9)

for epoch in range(2):
    running_loss = 0.0
    for i, data in enumerate(trainloader, 0):
        inputs, labels = data
        inputs, labels = Variable(inputs), Variable(labels)

        optimizer.zero_grad()

        outputs = net(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        # 參數更新
        optimizer.step()

        running_loss += loss.data[0]
        if i % 2000 == 1999:
            print('[%d, %5d] loss: %.3f' % (epoch + 1, i + 1, running_loss / 2000))
            running_loss = 0.0
print('Finished Training')

dataiter = iter(testloader)
images, labels = dataiter.next()
outputs = net(Variable(images))
_, predicted = t.max(outputs.data, 1)
print('predicted result', ' '.join('%5s' % classes[predicted[j]] for j in range(4)))

correct = 0
total = 0
for data in testloader:
    images, labels = data
    outputs = net(Variable(images))
    _, predicted = t.max(outputs.data, 1)
    total += labels.size(0)
    correct += (predicted ==labels).sum

print('The accuracy is: %d %%' % (100 * correct / total))

#GPU加速操作:
if t.cuda.is_available():
    net.cuda()
    images = images.cuda()
    labels = labels.cuda()
    output = net(Variable(images))
    loss = criterion(output, Variable(labels))

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM