一、Pytorch介紹
1)Pytorch介紹
PyTorch 是 Torch 在 Python 上的衍生. 因為 Torch 是一個使用 Lua 語言的神經網絡庫, Torch 很好用, 但是 Lua 又不是特别流行, 所有開發團隊将 Lua 的 Torch 移植到了更流行的語言 Python 上.
2)Pytorch和Tensorflow
Pyrtoch最大的優點就是建立的神經網絡是動态的,對比靜态的TensorFlow,它能更加有效地去處理一些問題,Tensorflow 的靜态計算圖使得他在 RNN 上有一點點被動 (雖然它用其他途徑解決了), 不過用 PyTorch 的時候, 你會對這種動态的 RNN 有更好的了解.而且 Tensorflow 的高度工業化, 它的底層代碼… 你是看不懂的. PyTorch 好那麼一點點, 如果你深入 API, 你至少能比看 Tensorflow 多看懂一點點 PyTorch 的底層在幹嘛.
動态圖:建構BP算法,首先要建構一個計算圖,即網絡的結構拓撲圖。如建構一個三層結構,前項計算的時候把網絡加到計算圖裡去,前項結束的時候,結構圖就有了,反向傳播的時候,從圖的最後一層倒推,一層一層計算每一層的梯度,然後更新參數。
Tensorflow是先建構一個結構圖,再對參數進行更新,不夠靈活。但能分布式訓練。
3)Numpy 還是Pytorch
Torch自稱為神經網絡界的Numpy,它能将torch産生的tensor放在GPU中加速運算,就想Numpy會把array放在CPU中加速運算。是以在神經網絡中,用Torch的tensor形式更優。
import torch
import torch.nn as nn
import torch.nn.functional as F
import numpy as np
# 聲明一個tensor張量
a = torch.tensor(3)# 标量
print(a)
a = torch.tensor([3]) #向量
print(a)
print(type(a))
b = torch.tensor([1,2,3], dtype=torch.float32)
print(b)
a = torch.Tensor([1,2])#浮點型
print(a)
a = torch.tensor([1,2])
print(a)
a = torch.tensor([[1,2,3],[4,5,6]])
b = torch.tensor([[1,2,3],[4,5,6]])
print(a * b)
print(a + b)
print(a - b)
print(a / b)
print(torch.mm(a,b.t()))#矩陣乘法
print(torch.dot(a[0],b[0]))#求内積(torch.dot求向量的内積)
out:
tensor(3)
tensor([3])
<class ‘torch.Tensor’>
tensor([1., 2., 3.])
tensor([1., 2.])
tensor([1, 2])
tensor([[ 1, 4, 9],
[16, 25, 36]])
tensor([[ 2, 4, 6],
[ 8, 10, 12]])
tensor([[0, 0, 0],
[0, 0, 0]])
tensor([[1, 1, 1],
[1, 1, 1]])
tensor([[14, 32],
[32, 77]])
tensor(14)
4)Pytorch是什麼?
Pytorch是一個基于Python的科學計算工具包,它主要面向兩種場景:
用于替代Numpy,可以使用GPU的計算力
一種深度學習研究平台,可以提供最大的靈活性和速度
x = torch.tensor([1,2])
#x.to(device="cuda")
y = torch.tensor([3,4])
if torch.cuda.is_available():
x = x.cuda() # 把x放在GPU裡面計算
y = y.cuda() # cpu convert cuda
y = y.cpu() # cuda convert cpu
else:
print(x, y)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(type(device))
x = x.to(device)
print(x)
x.cpu()
out:
tensor([1, 2]) tensor([3, 4])
<class ‘torch.device’>
tensor([1, 2])
# numpy轉torch
a = np.array([1,2,3])
b = torch.tensor([1,2,3])
c = (torch.from_numpy(a))
print(type(c))
print(type(b.numpy()))
a[0] = 5
print(c)#用的是同一套記憶體空間
print(torch.tensor(a))#直接轉Tensor
out:
<class ‘torch.Tensor’>
<class ‘numpy.ndarray’>
tensor([5, 2, 3], dtype=torch.int32)
tensor([5, 2, 3], dtype=torch.int32)
二、Pytorch的使用方法
1)Autograd:自動求導(automatic differentiation)
Pytorch中所有神經網絡的核心是autograd包。
autograd包為張量上的所有操作提供了自動求導,它是一個運作時定義的架構,這意味着反向傳播是根據你的代碼如何運作來定義,并且每次疊代可以不同。
2)變量(Variable)
autograd.Variable是autograd包的核心類,它包裝了張量,支援幾乎所有的張量上的操作,一旦你完成前向計算,可以通過.backward()方法來自動計算所有的梯度,可以通過.data屬性來通路變量中的原始張量,關于這個變量的梯度被計算放入.grad屬性中
import torch
from torch.autograd import Variable
x = torch.tensor([1.,2,3], requires_grad=True)
# x = Variable(x, requires_grad=True) # 需要計算梯度
y = x.mean() # y = 1/3*(x1+x2+x3)# 隻能對标量進行求導
z = y**2
w = 3*z
w.backward()
print(w)
print(z)
print(y)
print(x.grad)# 求的x的導數
print(x.data)
out:
tensor(12., grad_fn=<MulBackward0>)
tensor(4., grad_fn=<PowBackward0>)
tensor(2., grad_fn=<MeanBackward0>)
tensor([4., 4., 4.])
tensor([1., 2., 3.])
#自動求導機制
_x = [i/100 for i in range(100)]
_y = [5*i + 3 for i in _x]
w = torch.rand(1,requires_grad=True)
b = torch.rand(1,requires_grad=True)
optimizer= torch.optim.SGD([w,b],lr=0.1)
for i in range(100):
for x,y in zip(_x, _y):
z = w*x + b
loss = torch.pow((z-y),2)
optimizer.zero_grad()
loss.backward()
optimizer.step()
print(w,b)
out:
40次以上得到
tensor([5.0000], requires_grad=True) tensor([3.0000], requires_grad=True)
四、Pytorch實作CNN
計算MNIST圖檔的均值和方差
import torch
from torchvision import datasets, transforms
if __name__ == '__main__':
train_dataset = datasets.MNIST("datasets/", train=True, download=True, transform=transforms.ToTensor())
testdataset = datasets.MNIST("datasets/", train=False, download=True, transform=transforms.ToTensor())
dataset = train_dataset+testdataset
dataloader = torch.utils.data.DataLoader(dataset, batch_size=70000, shuffle=True)
data = next(iter(dataloader))[0]#通過疊代器疊代,取出來隻有一個值,索引用0取出來
mean = torch.mean(data,dim=(0,2,3))
std = torch.std(data,dim=(0,2,3))
print(mean)
print(std)
out:
tensor([0.1309])
tensor([0.3084])
from torchvision import datasets, transforms
import numpy as np
if __name__ == '__main__':
train_dataset = datasets.MNIST("datasets/", train=True, download=True, transform=transforms.ToTensor())
testdataset = datasets.MNIST("datasets/", train=False, download=True, transform=transforms.ToTensor())
mnist_data = train_dataset + testdataset
_data = [d[0].data.cpu().numpy() for d in mnist_data]
print(np.mean(_data))
print(np.std(_data))
out:
tensor([0.1309])
tensor([0.3084])
五、Pytorch實作MNIST(OOP實作)
MyNet.py
import torch
class MLPNet(torch.nn.Module):
def __init__(self):
super().__init__()
self.layer1 = torch.nn.Linear(784,128)
self.layer2 = torch.nn.Linear(128,256)
self.layer3 = torch.nn.Linear(256,512)
self.layer4 = torch.nn.Linear(512,256)
self.layer5 = torch.nn.Linear(256,128)
self.layer6 = torch.nn.Linear(128,10)
def forward(self, x):
x = torch.reshape(x, (-1,784))
x = torch.relu(self.layer1(x))
x = torch.relu(self.layer2(x))
x = torch.relu(self.layer3(x))
x = torch.relu(self.layer4(x))
x = torch.relu(self.layer5(x))
x = self.layer6(x)#用均方差就不要用softmax
return x
Train.py
術語:
輪次 10
疊代次數 120
batch_size
mini_batch:一個樣本的泛型不廣
from MyNet import MLPNet
import torch
import torch.nn.functional as F
from torchvision.datasets import MNIST
import torchvision.transforms as trans
from torch.utils.data import DataLoader
import matplotlib.pyplot as plt
from PIL import Image
import numpy as np
class Trainer:
def __init__(self):
self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
self.net = MLPNet().to(self.device)
self.loss_func = torch.nn.MSELoss()
self.opt = torch.optim.Adam(self.net.parameters())
self.trainset, self.testset = self.get_dataset()
def get_dataset(self):
transformer = trans.Compose([
trans.ToTensor(),
trans.Normalize((0.1309,), (0.3084,))
])
trianData = MNIST(root="datasets/", train=True, download=False, transform=transformer)
testData = MNIST(root="datasets/", train=False, download=False, transform=transformer)
return trianData, testData
def loader_data(self):
trainloader = DataLoader(dataset=self.trainset, batch_size=512, shuffle=True)
testloader = DataLoader(dataset=self.testset, batch_size=512, shuffle=True)
return trainloader, testloader
def train(self):
trainloader, testloader = self.loader_data()
losses = []
for i in range(10):
print("epochs:{}".format(i))
for j, (x, y) in enumerate(trainloader):
x = x.to(self.device)
y = F.one_hot(y.long()).float().to(self.device)#(500,10)
#y = torch.zeros(y.size(0),10).scatter_(1, y.view(-1, 1), 1).to(self.device)
out = self.net(x)
loss = self.loss_func(out, y)
if j % 10 == 0:
print("{}/{},loss{}".format(j, len(trainloader), loss.float()))
losses.append(loss.float())
plt.clf()
plt.plot(losses)
plt.pause(0.01)
self.opt.zero_grad()
loss.backward()
self.opt.step()
torch.save(self.net, "models/net.pth")
self.test(testloader)#每輪結束都測試一下
def test(self, testloader):
total = 0
for x ,y in testloader:
x = x.to(self.device)
y = y.to(self.device)
out = self.net(x)
predict = torch.argmax(out, dim=1)
total += (predict == y).sum()
print("精确度:{}".format(total.item() / len(self.testset) * 100))
def testPic(self):
net = torch.load("models/net.pth")
img = Image.open("8.jpg")
img = trans.Resize(28)(img)
img = trans.Grayscale()(img)
img = trans.ToTensor()(img)
img = 1. - img
img = trans.Normalize((0.1309,),(0.3084,))(img)
img = img.unsqueeze(0)
# print(img)
"""
但均值标準差不是0.5,歸一化後不再是[-1,1],是以
測試圖檔255 - 0 歸一化後是 1 - 0,訓練的圖檔是 0 - 1
我們要測試的圖檔變成0 - 1,用1-img即可
"""
out = net(img.to(self.device))
print("AI的預測是:{}".format(out.argmax(dim=1)))
# img.show()
def testPic2(self):
net = torch.load("models/net.pth")
transformer = trans.Compose([
trans.Resize(28),
trans.CenterCrop(28),
trans.Grayscale(),
trans.ToTensor(),
trans.Normalize((0.5,),(0.5,))
])
"""
訓練:-1黑 1 白
測試:也要這麼變,測試圖檔是白底黑字,訓練圖檔是黑底白字,
即測試圖檔255 - 0 歸一化後是 1,-1
訓練圖檔0 - 255,歸一化後是-1,1,是以給img.unsqueeze(0)*-1可以轉化
"""
img = transformer(Image.open("8.jpg")).unsqueeze(0)*-1
output = net(img.to(self.device))
print("AI的預測是:{}".format(output.argmax(dim=1)))
def test2(self, testloader):#檢視資料集
net = torch.load("models/net.pth")
for x ,y in testloader:
x = x.to(self.device)
datas = (x * 0.3084 + 0.1309) * 255
datas = datas.cpu().numpy().astype(np.uint8)
for i in range(x.shape[0]):
data = datas[i].squeeze()
out = net(x[i])
predict = out.argmax(1)
plt.clf()
plt.subplot(1,2,1)
plt.imshow(data)
plt.subplot(1,2,2)
plt.ylim(20)
plt.xlim(20)
plt.text(15,10, s="Result is :{}".format(predict.item()), color="r", fontsize=20)
plt.pause(1)
if __name__ == '__main__':
t = Trainer()
train,test = t.loader_data()
t.test2(test)
"""
self, dim, index ,value
torch.scatter()把value按照index根據dim的方向填入self中
"""
index = torch.tensor([0,2,4,1])
src = torch.zeros(4,5)
src = torch.scatter(src, dim=1, index=index.view(-1,1), value=1)
print(src)
a = F.one_hot(index)#要轉long()
print(a)
out:
tensor([[1., 0., 0., 0., 0.],
[0., 0., 1., 0., 0.],
[0., 0., 0., 0., 1.],
[0., 1., 0., 0., 0.]])
tensor([[1, 0, 0, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 0, 0, 1],
[0, 1, 0, 0, 0]])