pytorch:基本操作
阿新 • • 發佈:2019-02-02
import torch
import numpy as np
%matplotlib inline
import matplotlib.pyplot as plt
pytorch中有兩種變數型別,一個是Tensor,一個是Variable。
- Tensor: 就像ndarray一樣,一維Tensor叫Vector,二維Tensor叫Matrix,三維及以上稱為Tensor
- Variable:是Tensor的一個wrapper,不僅儲存了值,而且儲存了這個值的creator,需要BP的網路都是Variable參與運算
# torch.Tensor(shape) 創建出一個未初始化的Tensor,但是還是可以打印出值的,這個應該是這塊記憶體之前的資料
x = torch.Tensor(2,3,4)
# 這種方式創建出來的Tensor更多是用來接受其他資料的計算值的
x
(0 ,.,.) = 2.8404e+29 6.7111e+22 1.3556e-19 1.3563e-19 1.3563e-19 1.3563e-19 1.3563e-19 4.4591e+30 3.9173e-02 3.0386e+29 1.2134e+19 1.1625e+27 (1 ,.,.) = 4.5435e+30 7.1429e+31 1.8467e+20 7.1220e+28 1.3556e-19 1.3563e-19 1.3563e-19 1.3563e-19 1.3563e-19 1.3563e-19 1.3563e-19 1.3563e-19 [torch.FloatTensor of size 2x3x4]
x.size()
torch.Size([2, 3, 4])
a = torch.rand(2,3,4)
b = torch.rand(2,3,4)
# 使用Tensor()方法創建出來的Tensor用來接收計算結果,當然torch.add(..)也會返回計算結果的
_=torch.add(a,b,out=x)
x
(0 ,.,.) = 1.2776 1.5515 1.6725 1.5813 1.8088 1.0150 0.4805 0.7575 1.4111 1.1892 1.4516 1.4634 (1 ,.,.) = 1.5148 1.5504 1.2196 1.8959 0.7730 1.4018 0.9021 1.6071 1.4863 0.6581 0.8338 0.8901 [torch.FloatTensor of size 2x3x4]
"""所有帶 _ 的operation,都會更改呼叫物件的值,"""
a.add_(b)
#例如 a=1;b=2;a就是3了,沒有 _ 的operation就沒有這種效果,只會返回運算結果
(0 ,.,.) =
1.2776 1.5515 1.6725 1.5813
1.8088 1.0150 0.4805 0.7575
1.4111 1.1892 1.4516 1.4634
(1 ,.,.) =
1.5148 1.5504 1.2196 1.8959
0.7730 1.4018 0.9021 1.6071
1.4863 0.6581 0.8338 0.8901
[torch.FloatTensor of size 2x3x4]
a
(0 ,.,.) =
1.2776 1.5515 1.6725 1.5813
1.8088 1.0150 0.4805 0.7575
1.4111 1.1892 1.4516 1.4634
(1 ,.,.) =
1.5148 1.5504 1.2196 1.8959
0.7730 1.4018 0.9021 1.6071
1.4863 0.6581 0.8338 0.8901
[torch.FloatTensor of size 2x3x4]
torch.cuda.is_available()
False
自動求導
- pytorch的自動求導工具包在torch.autograd中
from torch.autograd import Variable
x = torch.rand(5)
x = Variable(x, requires_grad = True)
y = x * 2
#如果y是scalar的話,那麼直接y.backward(),然後通過x.grad方式,就可以得到var的梯度
#如果y不是scalar,那麼只能通過傳參的方式給x指定梯度
grads = torch.FloatTensor([1,2,3,4,5])
y.backward(grads)
x.grad
Variable containing:
2
4
6
8
10
[torch.FloatTensor of size 5]
numpy array 和 torch tensor可以自由的轉換
import torch
import numpy as np
np_data = np.arange(6).reshape((2,3))
torch_data = torch.from_numpy(np_data)
tensor2array = torch_data.numpy()
print(
'\nnumpy array:', np_data,
'\ntorch tensor:', torch_data,
'\ntensor to array:', tensor2array,
)
numpy array: [[0 1 2]
[3 4 5]]
torch tensor:
0 1 2
3 4 5
[torch.IntTensor of size 2x3]
tensor to array: [[0 1 2]
[3 4 5]]
# abs 絕對值計算
data = [-1, -2, 1, 2]
tensor = torch.FloatTensor(data) # 轉換成32位浮點 tensor
print(
'\nabs',
'\nnumpy: ', np.abs(data), # [1 2 1 2]
'\ntorch: ', torch.abs(tensor) # [1 2 1 2]
)
abs
numpy: [1 2 1 2]
torch:
1
2
1
2
[torch.FloatTensor of size 4]
# sin 三角函式 sin
print(
'\nsin',
'\nnumpy: ', np.sin(data), # [-0.84147098 -0.90929743 0.84147098 0.90929743]
'\ntorch: ', torch.sin(tensor) # [-0.8415 -0.9093 0.8415 0.9093]
)
sin
numpy: [-0.84147098 -0.90929743 0.84147098 0.90929743]
torch:
-0.8415
-0.9093
0.8415
0.9093
[torch.FloatTensor of size 4]
# mean 均值
print(
'\nmean',
'\nnumpy: ', np.mean(data), # 0.0
'\ntorch: ', torch.mean(tensor) # 0.0
)
mean
numpy: 0.0
torch: 0.0
矩陣的乘法
# matrix multiplication 矩陣點乘
data = [[1,2], [3,4]]
tensor = torch.FloatTensor(data) # 轉換成32位浮點 tensor
# correct method
print(
'\nmatrix multiplication (matmul)',
'\nnumpy: ', np.matmul(data, data), # [[7, 10], [15, 22]]
'\ntorch: ', torch.mm(tensor, tensor) # [[7, 10], [15, 22]]
)
# !!!! 下面是錯誤的方法 !!!!
data = np.array(data)
print(
'\nmatrix multiplication (dot)',
'\nnumpy: ', data.dot(data), # [[7, 10], [15, 22]] 在numpy 中可行
'\ntorch: ', tensor.dot(tensor) # torch 會轉換成 [1,2,3,4].dot([1,2,3,4) = 30.0
)
#新版本中(>=0.3.0), 關於 tensor.dot() 有了新的改變, 它只能針對於一維的陣列. 所以上面的有所改變.
matrix multiplication (matmul)
numpy: [[ 7 10]
[15 22]]
torch:
7 10
15 22
[torch.FloatTensor of size 2x2]
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
<ipython-input-44-e307c2bb5181> in <module>()
14 '\nmatrix multiplication (dot)',
15 '\nnumpy: ', data.dot(data), # [[7, 10], [15, 22]] 在numpy 中可行
---> 16 '\ntorch: ', tensor.dot(tensor) # torch 會轉換成 [1,2,3,4].dot([1,2,3,4) = 30.0
17 )
18 #新版本中(>=0.3.0), 關於 tensor.dot() 有了新的改變, 它只能針對於一維的陣列. 所以上面的有所改變.
RuntimeError: Expected argument self to have 1 dimension(s), but has 2 at c:\miniconda2\conda-bld\pytorch-cpu_1519449358620\work\torch\csrc\generic\TensorMethods.cpp:25700
變數
- Variable:裝雞蛋的籃子,雞蛋數目不停變動
- Tensor:雞蛋
import torch
# torch中Variable模組
from torch.autograd import Variable
#先生雞蛋
tensor = torch.FloatTensor([[1,2],[3,4]])
#把雞蛋放到籃子裡, requires_grad是要不要計算梯度
variable = Variable(tensor, requires_grad=True)
print(tensor,variable)
1 2
3 4
[torch.FloatTensor of size 2x2]
Variable containing:
1 2
3 4
[torch.FloatTensor of size 2x2]
variable計算梯度
t_out = torch.mean(tensor*tensor) #x^2
v_out = torch.mean(variable*variable)
print(t_out,v_out)
7.5 Variable containing:
7.5000
[torch.FloatTensor of size 1]
v_out.backward() # 模擬 v_out 的誤差反向傳遞
# 下面兩步看不懂沒關係, 只要知道 Variable 是計算圖的一部分, 可以用來傳遞誤差就好.
# v_out = 1/4 * sum(variable*variable) 這是計算圖中的 v_out 計算步驟
# 針對於 v_out 的梯度就是, d(v_out)/d(variable) = 1/4*2*variable = variable/2
# 初始 Variable 的梯度
print(variable.grad)
0.5000 1.0000
1.5000 2.0000
[torch.FloatTensor of size 2x2]
獲取 Variable 裡面的資料
- 直接print(variable)只會輸出 Variable 形式的資料, 在很多時候是用不了的
- (比如想要用 plt 畫圖), 所以我們要轉換一下, 將它變成 tensor 形式.
#Variable形式
print(variable)
#tensor形式
print(variable.data)
#numpy形式
print(variable.data.numpy())
Variable containing:
1 2
3 4
[torch.FloatTensor of size 2x2]
1 2
3 4
[torch.FloatTensor of size 2x2]
[[1. 2.]
[3. 4.]]
Torch 中的激勵函式
import torch
import torch.nn.functional as F #啟用函式都在這
from torch.autograd import Variable
# 做一些假資料來觀看影象
x = torch.linspace(-5, 5, 200) # x data (tensor), shape=(100, 1)
x = Variable(x)
x_np = x.data.numpy() #
#幾種常用的啟用函式
y_relu = F.relu(x).data.numpy()
y_sigmoid =F.sigmoid(x).data.numpy()
y_tanh = F.tanh(x).data.numpy()
y_softplus = F.softplus(x).data.numpy()
# y_softmax = F.softmax(x) softmax 比較特殊, 不能直接顯示, 不過他是關於概率的, 用於分類
plt.figure(1, figsize=(8, 6))
plt.subplot(221)
plt.plot(x_np, y_relu, c='red', label='relu')
plt.ylim((-1, 5))
plt.legend(loc='best')
plt.subplot(222)
plt.plot(x_np, y_sigmoid, c='red', label='sigmoid')
plt.ylim((-0.2, 1.2))
plt.legend(loc='best')
plt.subplot(223)
plt.plot(x_np, y_tanh, c='red', label='tanh')
plt.ylim((-1.2, 1.2))
plt.legend(loc='best')
plt.subplot(224)
plt.plot(x_np, y_softplus, c='red', label='softplus')
plt.ylim((-0.2, 6))
plt.legend(loc='best')
<matplotlib.legend.Legend at 0x164816efe48>
關係擬合 (迴歸)
我們建立一些假資料來模擬真實的情況. 比如一個一元二次函式: y = a * x^2 + b, 我們給 y 資料加上一點噪聲來更加真實的展示它.
建立資料集
x = torch.unsqueeze(torch.linspace(-1,1,100),dim=1) #x data (tensor), shape=(100, 1)
y = x.pow(2) + 0.2*torch.rand(x.size()) # noisy y data (tensor), shape=(100, 1)
#用variable來修飾這些資料tensor
x, y = Variable(x),Variable(y)
#畫圖
plt.scatter(x.data.numpy(), y.data.numpy())
plt.show()
- 建立神經網路
class Net(torch.nn.Module): # 繼承 torch 的 Module
def __init__(self,n_feature,n_hidden,n_output):
super(Net,self).__init__() #繼承__init__功能
#定義每層用什麼樣的形式
self.hidden = torch.nn.Linear(n_feature, n_hidden) #隱藏層
self.predict = torch.nn.Linear(n_hidden, n_output) #輸出層
def forward(self, x): # Module中的forward功能
#正向傳播輸入值,神經網路分析出輸出值
x = F.relu(self.hidden(x))# 激勵函式(隱藏層的線性值)
x = self.predict(x)# 輸出值
return x
net = Net(n_feature=1,n_hidden=10,n_output=1)
print(net)
Net(
(hidden): Linear(in_features=1, out_features=10, bias=True)
(predict): Linear(in_features=10, out_features=1, bias=True)
)
訓練網路
#optimizer 是訓練工具
optimizer = torch.optim.SGD(net.parameters(),lr=0.5) #傳入net的所有引數,學習率
loss_func = torch.nn.MSELoss() #預測值和真實值的誤差計算公式(均方差)
for i in range(100):
prediction = net(x) #餵給net訓練資料x,輸出預測值
loss = loss_func(prediction, y) #計算兩者的誤差
optimizer.zero_grad() #清空上一步的殘餘更新引數值
loss.backward() #誤差反向傳播,計算引數更新值
optimizer.step() # 將引數更新值施加到net的parameters上
視覺化訓練過程
plt.ion()
plt.show()
for t in range(100):
prediction = net(x) #餵給net訓練資料x,輸出預測值
loss = loss_func(prediction, y) #計算兩者的誤差
optimizer.zero_grad() #清空上一步的殘餘更新引數值
loss.backward() #誤差反向傳播,計算引數更新值
optimizer.step() # 將引數更新值施加到net的parameters上
if t % 5 == 0:
# plt and show learning process
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[0], fontdict={'size': 20, 'color': 'red'})
plt.pause(0.1)
分類
- 建立資料集
# 假資料
n_data = torch.ones(100, 2) # 資料的基本形態
n_data.numpy().shape
(100, 2)
x0 = torch.normal(2*n_data, 1) # 型別0 x data (tensor), shape=(100, 2)
y0 = torch.zeros(100) # 型別0 y data (tensor), shape=(100, 1)
x1 = torch.normal(-2*n_data, 1) # 型別1 x data (tensor), shape=(100, 2)
y1 = torch.ones(100) # 型別1 y data (tensor), shape=(100, 1)
# 注意 x, y 資料的資料形式是一定要像下面一樣 (torch.cat 是在合併資料)
x = torch.cat((x0, x1), 0).type(torch.FloatTensor) # FloatTensor = 32-bit floating
y = torch.cat((y0, y1), ).type(torch.LongTensor) # LongTensor = 64-bit integer
# torch 只能在 Variable 上訓練, 所以把它們變成 Variable
x, y = Variable(x), Variable(y)
# 畫圖
plt.scatter(x.data.numpy()[:, 0], x.data.numpy()[:, 1], c=y.data.numpy(), s=100, lw=0, cmap='RdYlGn')
plt.show()
建立神經網路
- 建立一個神經網路我們可以直接運用 torch 中的體系. 先定義所有的層屬性(init()),
- 然後再一層層搭建(forward(x))層於層的關係連結. 這個和我們在前面 regression 的時候的神經網路基本沒差.
import torch
import torch.nn.functional as F
class Net(torch.nn.Module):
def __init__(self,n_feature, n_hidden,n_output):
super(Net,self).__init__() #繼承__init__功能
self.hidden = torch.nn.Linear(n_feature, n_hidden) #隱藏層線性輸出
self.out = torch.nn.Linear(n_hidden,n_output)
def forward(self,x):
x = F.relu(self.hidden(x))
x = self.out(x)
return x
net = Net(n_feature=2, n_hidden=10, n_output=2) #幾個類別就幾個output
print(net)
Net(
(hidden): Linear(in_features=2, out_features=10, bias=True)
(out): Linear(in_features=10, out_features=2, bias=True)
)
訓練網路
optimizer = torch.optim.SGD(net.parameters(), lr=0.02)
# 算誤差的時候, 注意真實值!不是! one-hot 形式的, 而是1D Tensor, (batch,)
# 但是預測值是2D tensor (batch, n_classes)
loss_func = torch.nn.CrossEntropyLoss()
for t in range(100):
out =net(x)
loss = loss_func(out, y)
optimizer.zero_grad()
loss.backward()
optimizer.step() #將引數更新值施加到net的parameter上
# 接著上面來
if t % 2 == 0:
plt.cla()
# 過了一道 softmax 的激勵函式後的最大概率才是預測值
prediction = torch.max(F.softmax(out), 1)[1]
pred_y = prediction.data.numpy().squeeze()
target_y = y.data.numpy()
plt.scatter(x.data.numpy()[:, 0], x.data.numpy()[:, 1], c=pred_y, s=100, lw=0, cmap='RdYlGn')
accuracy = sum(pred_y == target_y)/200 # 預測中有多少和真實值一樣
plt.text(1.5, -4, 'Accuracy=%.2f' % accuracy, fontdict={'size': 20, 'color': 'red'})
plt.pause(0.1)
plt.ioff() # 停止畫圖
plt.show()
C:\Users\dell\Anaconda3\lib\site-packages\ipykernel_launcher.py:18: UserWarning: Implicit dimension choice for softmax has been deprecated. Change the call to include dim=X as an argument.
快速搭建
#我們用 class 繼承了一個 torch 中的神經網路結構, 然後對其進行了修改, 不過還有更快的一招,
#用一句話就概括了上面所有的內容!
net2 = torch.nn.Sequential(
torch.nn.Linear(1, 10),
torch.nn.ReLU(),
torch.nn.Linear(10, 1)
)
print(net2)
Sequential(
(0): Linear(in_features=1, out_features=10, bias=True)
(1): ReLU()
(2): Linear(in_features=10, out_features=1, bias=True)
)
儲存
torch.manual_seed(1) #reproducible
#假資料
x = torch.unsqueeze(torch.linspace(-1, 1, 100), dim=1) # x data(tensor)
y = x.pow(2) + 0.2 * torch.rand(x.size()) #noisy y data(tensor)
x, y = Variable(x, requires_grad=False),Variable(y,requires_grad=False)
def save():
net1 = torch.nn.Sequential(
torch.nn.Linear(1, 10),
torch.nn.ReLU(),
torch.nn.Linear(10, 1)
)
optimizer = torch.optim.SGD(net1.parameters(),lr=0.5)
loss_func = torch.nn.MSELoss()
#訓練
for t in range(100):
prediction = net1(x)
loss = loss_func(prediction, y)
optimizer.zero_grad()
loss.backward()
optimizer.step()
torch.save(net1, 'net.pkl') # 儲存整個網路
torch.save(net1.state_dict(), 'net_params.pkl') # 只儲存網路中的引數 (速度快, 佔記憶體少)
save()
torch.unsqueeze?
提取網路
def restore_net():
#restore entire net1 to net2
net2 = torch.load('net.pkl')
prediction = net2(x)
只提取網路引數:這種方式將會提取所有的引數, 然後再放到你的新建網路中.
def restore_params():
#新建 net3
net3 = torch.nn.Sequential(
torch.nn.Linear(1, 10),
torch.nn.ReLU(),
torch.nn.Linear(10, 1)
)
"""得建立一個和之前訓練相同的model"""
#將儲存的引數複製到net3
net3.load_state_dict(torch.load('net_params.pkl'))
prediction = net3(x)
批訓練
import torch
import torch.utils.data as Data
torch.manual_seed(1) #reproducible
BATCH_SIZE = 5 #批訓練的資料個數
x = torch.linspace(1, 10 ,10)
y = torch.linspace(1, 10, 10)
#先轉換torch能識別的Dataset
torch_dataset = Data.TensorDataset(data_tensor=x,target_tensor=y)
#把dataset放入DataLoader
loader = Data.DataLoader(
dataset = torch_dataset,#torch TensorDateset format
batch_size = BATCH_SIZE, #mini batch size
shuffle = True, #是否打亂資料
num_workers = 2 , # 多執行緒來讀資料
)
for epoch in range(3): #訓練所有!整套資料3次
for step, (batch_x, batch_y) in enumerate(loader): #每次loader釋放一小批資料用來學習
# 假設這裡就是你訓練的地方...
# 打出來一些資料
print('Epoch: ', epoch, '| Step: ', step, '| batch x: ',
batch_x.numpy(), '| batch y: ', batch_y.numpy())
Epoch: 0 | Step: 0 | batch x: [ 4. 3. 6. 9. 10.] | batch y: [ 4. 3. 6. 9. 10.]
Epoch: 0 | Step: 1 | batch x: [8. 7. 2. 1. 5.] | batch y: [8. 7. 2. 1. 5.]
Epoch: 1 | Step: 0 | batch x: [1. 5. 4. 8. 9.] | batch y: [1. 5. 4. 8. 9.]
Epoch: 1 | Step: 1 | batch x: [ 6. 3. 10. 2. 7.] | batch y: [ 6. 3. 10. 2. 7.]
Epoch: 2 | Step: 0 | batch x: [ 5. 10. 8. 9. 7.] | batch y: [ 5. 10. 8. 9. 7.]
Epoch: 2 | Step: 1 | batch x: [1. 2. 3. 6. 4.] | batch y: [1. 2. 3. 6. 4.]
加速神經網路訓練 (Speed Up Training)
import torch
import torch.utils.data as Data
import torch.nn.functional as F
from torch.autograd import Variable
import matplotlib.pyplot as plt
torch.manual_seed(1) # reproducible
LR = 0.01
BATCH_SIZE = 32
EPOCH = 12
# fake dataset
x = torch.unsqueeze(torch.linspace(-1, 1, 1000), dim=1)
y = x.pow(2) + 0.1*torch.normal(torch.zeros(*x.size()))
# plot dataset
plt.scatter(x.numpy(), y.numpy())
plt.show()
# 使用上節內容提到的 data loader
torch_dataset = Data.TensorDataset(data_tensor=x, target_tensor=y)
loader = Data.DataLoader(dataset=torch_dataset, batch_size=BATCH_SIZE, shuffle=True, num_workers=2,)
#每個優化器優化一個神經網路
# 預設的 network 形式
class Net(torch.nn.Module):
def __init__(self):
super(Net, self).__init__()
self.hidden = torch.nn.Linear(1, 20) # hidden layer
self.predict = torch.nn.Linear(20, 1) # output layer
def forward(self, x):
x = F.relu(self.hidden(x)) # activation function for hidden layer
x = self.predict(x) # linear output
return x
# 為每個優化器建立一個 net
net_SGD = Net()
net_Momentum = Net()
net_RMSprop = Net()
net_Adam = Net()
nets = [net_SGD, net_Momentum, net_RMSprop, net_Adam]
# different optimizers
opt_SGD = torch.optim.SGD(net_SGD.parameters(), lr=LR)
opt_Momentum = torch.optim.SGD(net_Momentum.parameters(), lr=LR, momentum=0.8)
opt_RMSprop = torch.optim.RMSprop(net_RMSprop.parameters(), lr=LR, alpha=0.9)
opt_Adam = torch.optim.Adam(net_Adam.parameters(), lr=LR, betas=(0.9, 0.99))
optimizers = [opt_SGD, opt_Momentum, opt_RMSprop, opt_Adam]
loss_func = torch.nn.MSELoss()
losses_his = [[], [], [], []] # 記錄 training 時不同神經網路的 loss
for epoch in range(EPOCH):
print('Epoch: ', epoch)
for step, (batch_x, batch_y) in enumerate(loader):
b_x = Variable(batch_x) # 務必要用 Variable 包一下
b_y = Variable(batch_y)
# 對每個優化器, 優化屬於他的神經網路
for net, opt, l_his in zip(nets, optimizers, losses_his):
output = net(b_x) # get output for every net
loss = loss_func(output, b_y) # compute loss for every net
opt.zero_grad() # clear gradients for next train
loss.backward() # backpropagation, compute gradients
opt.step() # apply gradients
l_his.append(loss.data[0]) # loss recoder
Epoch: 0
Epoch: 1
Epoch: 2
Epoch: 3
Epoch: 4
Epoch: 5
Epoch: 6
Epoch: 7
Epoch: 8
Epoch: 9
Epoch: 10
Epoch: 11
參考:莫煩python