PyTorch
是 Torch
在 Python
上的衍生(Torch
是一个使用 Lua
语言的神经网络库)tensorflow
比较
PyTorch
建立的神经网络是动态的Tensorflow
是建立静态图Tensorflow
的高度工业化, 它的底层代码是很难看懂的.PyTorch
好那么一点点, 如果你深入 API
, 你至少能比看 Tensorflow
多看懂一点点 PyTorch
的底层在干嘛.PyTorch
PyTorch
会安装两个模块
torch
, 一个 torchvision
, torch
是主模块, 用来搭建神经网络的,torchvision
是辅模块,有数据库,还有一些已经训练好的神经网络等着你直接用, 比如 (VGG, AlexNet, ResNet
).ubuntu14
下自带的python2.7
安装没有问题,在CentOS6.5
下的python3.5
中安装可能报错
python3.5
时的配置:
1
2
3
|
./configure --enable-shared \
--prefix=/usr/local/python3.
5 \
LDFLAGS=
"-Wl,--rpath=/usr/local/lib"
|
python
可能报loading shared libraries: libpython3.5m.so.1.0: cannot open shared object file: No such file or directory
的错误,拷贝一份libpython3.5m.so.1.0
到/usr/lib64
目录下即可
1
|
cp /home/Python/Python-
3.5.
3/libpython3.
5m
.so.
1.0 /usr/lib64
|
Numpy
相似之处import torch
numpy
数据转为torch
数据
1
2
|
np_data = np.arange(
6).reshape((
2,
3))
torch_data = torch.from_numpy(np_data)
|
torch
数据转为numpy
数据
1
|
tensor2array = torch_data.numpy()
|
Torch
中的运算torch
中 tensor
的运算和 numpy array
运算很相似,比如
np.abs() --> torch.abs()
np.sin() --> torch.sin()
等data = [[1,2], [3,4]]
tensor = torch.FloatTensor(data) # 转换成32位浮点 tensor
torch.mm(tensor, tensor)
Variable
Variable
就是一个存放会变化的值的位置导入包
1
2
|
import torch
from torch.autograd import Variable # torch 中 Variable 模块
|
定义tensor
: tensor = torch.FloatTensor([[1,2],[3,4]])
tensor
放入Variable
: variable = Variable(tensor, requires_grad=True)
requires_grad
是参不参与误差反向传播, 要不要计算梯度print(variable)
会输出,(多出Variable containing:
,表明是Variable
)
1
2
3
4
|
Variable containing:
1
2
3
4
[torch
.FloatTensor of size
2x2]
|
v_out = torch.mean(variable*variable) # x^2
v_out.backward() # 模拟 v_out 的误差反向传递
print(variable.grad) # 显示 Variable 的梯度
torch.mean(variable*variable)
是1/4*x^2
,导数就是1/2x
1
2
|
0.5000
1.0000
1.5000
2.0000
|
print(variable)
只会输出 Variable
形式的数据, 在很多时候是用不了的(比如想要用 plt
画图), 所以我们要转换一下, 将它变成 tensor
形式.tensor
数据:print(variable.data) # tensor 形式
numpy
数据:print(variable.data.numpy()) # numpy 形式
Torch
中的激励函数import torch.nn.functional as F # 激励函数都在这
relu, sigmoid, tanh, softplus
x
是Variable
数据,F.relu(x)
也是返回Variable
数据,然后.data
获取 tensor
数据
1
2
3
4
|
# 做一些假数据来观看图像
x = torch.linspace(-5, 5, 200) # x data (tensor), shape=(100, 1)
x = Variable(x)
x_np = x.data.numpy() # 换成 numpy array, 出图时用
|
1
2
3
4
5
|
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 比较特殊, 不能直接显示, 不过他是关于概率的, 用于分类
|
softplus
的公式为:f(x)=ln(1+ex)
1
2
3
4
|
import torch
from torch
.autograd import Variable
import torch
.nn
.functional as F
import matplotlib
.pyplot as plt
|
制造假数据
torch.unsqueeze
是转成2维的数据[[]]
,加上一个假的维度
1
2
|
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
: x, y = torch.autograd.Variable(x), Variable(y)
使用类的方式class
torch.nn.Module
__init__
只是定义了几个层forward
进行传播,也就是整个网络的搭建,因为是预测,最后一层不需要激励函数
1
2
3
4
5
6
7
8
9
10
11
12
|
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)
,结果为
1
2
3
4
|
Net (
(hidden): Linear (
1 ->
10)
(predict): Linear (
10 ->
1)
)
|
optimizer = torch.optim.SGD(net.parameters(), lr=0.5) # 传入 net 的所有参数, 学习率lr
loss_func = torch.nn.MSELoss() # 预测值和真实值的误差计算公式 (均方差)
1
2
3
4
5
6
7
8
|
for t in range(100):
prediction = net(x) # 喂给 net 训练数据 x, 输出预测值
loss = loss_func(prediction, y) # 计算两者的误差
optimizer.zero_grad() # 清空上一步的残余更新参数值
loss.backward() # 误差反向传播, 计算参数更新值
optimizer.step() # 将参数更新值施加到 net 的 parameters 上
|
1
2
3
4
|
import torch
from torch.autograd import Variable
import torch.nn.functional as F # 激励函数都在这
import matplotlib.pyplot as plt
|
制造假数据
x0
是一个类别的x1,x2
y0
就是对应这个类别的 label
,这里是0
x0,x1
,y0,y1
合并在一起
1
2
3
4
5
6
7
8
9
|
# 假数据
n_data = torch.ones(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, 1)
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
|
定义Variable: x, y = Variable(x), Variable(y)
与上面回归的例子类似
relu
激励函数softmax
,因为下面使用了CrossEntropyLoss
,这个里面默认会调用log_softmax
函数(nll_loss(log_softmax(input), target, weight, size_average)
)F.softmax(x)
, 那么下面的损失函数就是loss = F.nll_loss(out, y)
1
2
3
4
5
6
7
8
9
10
11
|
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.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
optimizer = torch.optim.SGD(net.parameters(), lr=0.02) # 传入 net 的所有参数, 学习率
loss_func = torch.nn.CrossEntropyLoss()
1
2
3
4
5
6
7
8
|
for t in range(100):
out = net(x) # 喂给 net 训练数据 x, 输出分析值
loss = loss_func(out, y) # 计算两者的误差
optimizer.zero_grad() # 清空上一步的残余更新参数值
loss.backward() # 误差反向传播, 计算参数更新值
optimizer.step() # 将参数更新值施加到 net 的 parameters 上
|
1
2
|
# 过了一道 softmax 的激励函数后的最大概率才是预测值
prediction = torch.max(F.softmax(out), 1)[1]
|
torch.nn.Sequential
1
2
3
4
5
|
net2 = torch
.nn
.Sequential(
torch
.nn
.Linear(
1,
10),
torch
.nn
.ReLU(),
torch
.nn
.Linear(
10,
1)
)
|
print(net2)
1
2
3
4
5
|
Sequential (
(
0): Linear (
1 ->
10)
(
1): ReLU ()
(
2): Linear (
10 ->
1)
)
|
torch.save(net1, 'net.pkl')
# 保存整个网络,net1
就是定义的网络torch.save(net1.state_dict(), 'net_params.pkl')
# 只保存网络中的参数 (速度快, 占内存少) net2 = torch.load('net.pkl')
prediction = net2(x)
net3.load_state_dict(torch.load('net_params.pkl'))
prediction = net3(x)
torch.optim.SGD
进行优化,但是还是将所有数据放进去训练 torch
用来包装你的数据(tensor
)的工具import torch.utils.data as Data
将tensor数据转为torch
能识别的Dataset
1
|
torch_dataset = Data.TensorDataset(data_tensor=x, target_tensor=y)
|
把 dataset 放入 DataLoader
BATCH_SIZE
是我们定义的batch
大小
1
2
3
4
5
6
|
loader = Data.DataLoader(
dataset=torch_dataset, # torch TensorDataset format
batch_size=BATCH_SIZE, # mini batch size
shuffle=True, # 要不要打乱数据 (打乱比较好)
num_workers=2, # 多线程来读数据
)
|
就可以得到batch
数据了
1
2
3
4
5
6
7
8
|
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())
|
这里还是tensor
数据,真正训练时还要放到Variable
中
1
2
|
b_x = Variable(batch_x) # 务必要用 Variable 包一下
b_y = Variable(batch_y)
|
SGD
momentum
SGD
函数里指定momentum
的值即可RMSprop
alpha
Adam
betas=(0.9, 0.99)
1
2
3
4
|
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))
|
CNN
1
2
3
4
5
|
import torch
from torch
.autograd import Variable
import torch
.utils
.data as Data
import torchvision
from matplotlib import pyplot as plt
|
1
2
3
4
5
6
7
8
9
|
EPOCH = 10
BATCH_SIZE = 50
LR = 0.001
train_data = torchvision.datasets.MNIST(root='./mnist',
transform=torchvision.transforms.ToTensor(),
download=False) # first set True, then set False
print(train_data.train_data.size())
test_data = torchvision.datasets.MNIST(root='./mnist', train=False)
|
处理数据
DataLoader
进行batch
训练Variable
里,并加上一个维度(在第二维位置dim=1),因为下面训练时是(batch_size, 1, 28, 28)
1
2
3
4
5
|
train_loader = Data.DataLoader(dataset=train_data, batch_size=128, shuffle=True)
# shape from (total_size, 28, 28) to (total_size, 1, 28, 28)
test_x = Variable(torch.unsqueeze(test_data.test_data, dim=1), volatile=True).type(torch.FloatTensor)/255.0
test_y = test_data.test_labels
|
建立计算图模型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
class CNN(torch.nn.Module):
def __init__(self):
super(CNN, self).__init__()
self.conv1 = torch.nn.Sequential( # input shape (1, 28, 28)
torch.nn.Conv2d(in_channels=1,
out_channels=16,
kernel_size=5,
stride=1,
padding=2),
torch.nn.ReLU(),
torch.nn.MaxPool2d(kernel_size=2)
) # output shape (16, 14, 14)
self.conv2 = torch.nn.Sequential(
torch.nn.Conv2d(16, 32, 5, 1, 2),
torch.nn.ReLU(),
torch.nn.MaxPool2d(2)
) # output shape (32, 7, 7)
self.out = torch.nn.Linear(in_features=32*7*7, out_features=10)
def forward(self, x):
x = self.conv1(x)
x = self.conv2(x)
x = x.view(x.size(0), -1) # 展平多维的卷积图成 (batch_size, 32 * 7 * 7)
output = self.out(x)
return output
cnn = CNN()
|
optimizer
和损失
1
2
|
optimizer = torch
.optim
.Adam(cnn.parameters(), lr=LR)
loss_func = torch
.nn
.CrossEntropyLoss()
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
for epoch in range(EPOCH):
for i, (x, y) in enumerate(train_loader):
batch_x = Variable(x)
batch_y = Variable(y)
output = cnn(batch_x)
loss = loss_func(output, batch_y)
optimizer.zero_grad()
loss.backward()
optimizer.step()
if i % 50 == 0:
# 用 test 数据来验证准确率
test_output = cnn(test_x)
pred_y = torch.max(test_output, 1)[1].data.squeeze()
accuracy = sum(pred_y == test_y) / float(test_y.size(0))
print('Epoch: ', epoch, '| train loss: %.4f' % loss.data[0], '| test accuracy: %.2f' % accuracy)
|