Pytorch入門與實踐——快速入門

import torch as t
import numpy as np
import torch.nn as nn
import torch.nn.functional as F

from torch.autograd import Variable
import torch.optim as optim
import matplotlib.pyplot as plt

x = t.Tensor(3, 2)
y = t.rand(5, 3)
z = t.rand(5, 3)
# print(x, y, z)\
# result = t.Tensor(5, 3)  #使用t.add(x,y,out=z)時,這裏需要預先分配空間, 注意是t.Tensor 而不是t.tensor
# t.add(y,z, out=result)
# # print(x.size(), z+y, z.add(y), t.add(y,z))
# print(result)

# print(y)
# y.add(z) #普通加法,不改變y的內容;會返回一個新的Tensor,而y不變
# print(y)
#
# y.add_(z) #inplace加法,改變y的內容;函數名後面帶下劃線_的函數會修改Tensor本身
# print(y)

#Tensor的選取操作與numpy類似
# print(x, x[:,1])

#Tensor和numpy的數組之間的互操作
# a = t.ones(5)  #新建一個全是1的Tensor
# print(a)
# b = a.numpy() #Tensor -> Numpy
# print(b)

# a = np.ones(5)
# b = t.from_numpy(a) #Numpy -> Tensor
# print (a , b)
# #Tensor 和Numpy對象共享內存,一個改變,另外一個隨之改變
# b.add_(1)
# print(a, b) #Tensor和Numpy共享內存,一變俱變

# #Tensor可通過.cuda方法轉爲GPU的Tensor
# if t.cuda.is_available():
#     x = x.cuda()
#     y = y.cuda()
#     print(x+y)
#
# #=======================================================
# #Autograde:自動微分
# #Tensor在被封裝爲Variable之後,可以調用它的.backward實現反向傳播,自動計算所有梯度
# from torch.autograd import Variable
# x = Variable(t.ones(2, 2), requires_grad = True)
# y = x.sum()
# print(y.grad_fn)  #grad_fn指向一個Function對象,其用來反向傳播計算輸入的梯度
# y.backward()
# x.grad.data.zero_()  #grad在反向傳播過程中是累加的,所以反向傳播之前需要把梯度清零
# y.backward()
# print(x.grad)
#
# #Variable和Tensor具有近乎一致的接口,在實際使用中可以無縫切換
# y = t.cos(x)
# x_tensor_cos = t.cos(x.data)
# print(y, x_tensor_cos)

#2.2.3 神經網絡
#定義網絡,需要繼承nn.Module,並實現它的forward方法,把網絡中具有可學習參數的層數放在構造函數__init__中
# import torch.nn as nn
# import torch.nn.functional as F
class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()   # 等價於nn.Module.__init__(self)
        #'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)  #16個5x5變成一維,
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, 10)

    def forward(self, x):  #override nn.Module中的forward方法;只要在nn.Module的子類中定義了fprward函數,backward函數就會自動實現(利用Autograd)
        #卷積 激活 池化
        x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2))
        x = F.max_pool2d(F.relu(self.conv2(x)), (2, 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)

# 網絡的可學習參數通過net.parameters()返回,net.named_parameters可同時返回可學習的參數及名稱
# params = list(net.parameters())
# print(len(params))
# for name,parameters in net.named_parameters():
#     print(name, ':', parameters.size())

#forward函數的輸入和輸出都是Variable,只有Variable才具有自動求導的功能,Tensor是沒有的,所以輸入時,需要把Tensor封裝成Variable
# input = Variable(t.randn(1, 1, 32, 32))  #torch.nn只支持mini-batchs,即一次必須是一個batch
# out = net(input)
# print(out.size())
# net.zero_grad()
# out.backward(Variable(t.ones(1, 10)))


# #損失函數
# output = net(input)
# target = Variable(t.arange(0, 10))
# print(target)
# criterion = nn.MSELoss()
# loss = criterion(output, target.float())  #這裏需要類型轉換.float(),.long(),.int(),.double(),.byte();Variable.data獲得Tensor變量
# print(loss)
# #運行.backward,觀察調用之前和調用之後的grad
# net.zero_grad()
# print('反向傳播之前conv1.bias的梯度:', net.conv1.bias.grad)
# loss.backward()
# print('之後:', net.conv1.bias.grad)

#SGD的更新策略: weight = weight - learning_rate * gradient
#手動實現如下:
# learing_rate = 0.01
# for f in net.parameters():
#     f.data.sub_(f.grad.data * learing_rate) # inplace 減法

##################################################################################################
# #torch.optim中實現了做大多數的優化方法,例如RMSProp、Adam、SGD等
# # import torch.optim as optim
# #新建一個優化器,指定要調整的參數和學習率
# optimizer = optim.SGD(net.parameters(), lr = 0.01)
#
# #在訓練過程中,先梯度清零
# optimizer.zero_grad()
#
# input = Variable(t.randn(1, 1, 32, 32))  #torch.nn只支持mini-batchs,即一次必須是一個batch
# target = Variable(t.arange(0, 10))
# criterion = nn.MSELoss()
#
# #計算損失
# output = net(input)
# loss = criterion(output, target.float())
#
# #反向傳播
# loss.backward()
# print(net.conv1.bias)
#
# #更新參數
# optimizer.step()
#
# print(net.conv1.bias.data)

############################################################################
#CIFAR-10分類
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 = '\D\Python相關\數據集\cy\data',
    train = True,
    download = True,   #若沒有下載好的數據集,則爲True
    transform = transform,
)

trainloader = t.utils.data.DataLoader(
    trainset,
    batch_size = 4,
    shuffle = True,
    num_workers = 0 #未使用if __name__ == '__main__',使用多線程會報錯
)

#測試集
testset = tv.datasets.CIFAR10(
    r'\D\Python相關\數據集\cy\data',
    train = False,
    download = True,
    transform = transform,
)

testloader = t.utils.data.DataLoader(
    testset,
    batch_size = 4,
    shuffle = False,
    num_workers = 0
)

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

(data, label) = trainset[100]   #Dataset對象是一個數據集,可以按下標訪問,返回形如(data,label)的數據
print(classes[label], '\n--------')
# plt.imshow(show((data+1)/2).resize((100, 100)))
# plt.show()  #顯示圖像plt.imshow(); plt.show()

dataiter = iter(trainloader)
images, labels = dataiter.next()    #返回4張圖片及標籤
print(' '.join('%11s'%classes[labels[j]] for j in range(4)))
picture = show(tv.utils.make_grid((images+1)/2)).resize((400, 100))   #將一個batch的圖片顯示在一張圖片上,(400,100)是寬和高?
# plt.imshow(picture)
# plt.show()

#定義網絡
import torch.nn as nn
import  torch.nn.functional as F

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)
        # 仿射層/全連接層, y = Wx + b
        self.fc1 = nn.Linear(16 * 5 * 5, 120)  # 16個5x5變成一維,
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, 10)

    def forward(self, x):  #override nn.Module中的forward方法;只要在nn.Module的子類中定義了fprward函數,backward函數就會自動實現(利用Autograd)
        #卷積 激活 池化
        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()

#定義損失函數和優化器(loss和optimizer)
from torch import optim
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()
#
#         #forward + backward
#         outputs = net(inputs)
#         loss = criterion(outputs, labels)
#         loss.backward()
#
#         #更新參數
#         optimizer.step()
#
#         #打印log信息
#         running_loss += loss.data
#         if i%2000 == 1999:  #每2000個batch打印一次訓練狀態
#             print('[%d, %5d] loss:  %.3f'%(epoch+1, i+1, running_loss/2000))
#             running_loss = 0.0
# t.save(net.state_dict(), 'test.pth')      # Module對象的保存
# print('Finished Training.')
#
# dataiter = iter(testloader)
# images, labels = dataiter.next()
# print('實際的label:', ''.join('%08s'%classes[labels[j]] for j in range(4)))
# show(tv.utils.make_grid(images/2-0.5)).resize((400,100))
#
# #計算圖片在每個類別上的分數
# outputs = net(Variable(images))
# #得分最高的那個類
# _, predicted = t.max(outputs.data, 1)
# print('預測結果:', ''.join('%08s'%classes[predicted[j]] for j in range(4)))

#整個測試集上的效果
correct = 0
total = 0
net.load_state_dict(t.load('test.pth'))     # Module對象的加載
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('準確率爲:%d %%'%(100*correct/total))     #因爲沒有保存參數值,所以此次結果爲隨機猜測10%

#在GPU上訓練
if t.cuda.is_available():
    net.cuda()
    images = images.cuda()
    labels = labels.cuda()
    outputs = net(Variable(images))
    loss = criterion(outputs, Variable(labels))
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章