pytorch入门(一):基本概念、模型训练与保存、优化器
什么是深度学习深度学习是机器学习中的神经网络的延伸,它将这门学问发扬光大!什么是神经网络计算机神经网络是模仿生物神经网络的一种运算模型。神经网络有输入层、隐藏层和输出层,通过输出层可以直观看到计算机的判断。我们需要许多张带有标签的数据,给他看数据,首先会给我们不成熟的答案,通过一张张辨识,错误答案会反向传播让神经元的激活函数的参数进行调整,使得部分神经元变得活跃或迟钝。黑盒其中,输入层可以是将原数
如何将list转为Tensor
torch.stack(myls, dim=1)
matplotlib显示mnist数据集图片
import torch
import torchvision
import torch.nn.functional as F
import matplotlib.pyplot as plt
import matplotlib;matplotlib.use('TKAgg') # 不加这一行的话pycharm不显示动态图
# Mnist digits dataset
train_data = torchvision.datasets.MNIST(
root='./mnist/',
train=True, # this is training data
transform=torchvision.transforms.ToTensor(), # Converts a PIL.Image or numpy.ndarray to
# torch.FloatTensor of shape (C x H x W) and normalize in the range [0.0, 1.0]
download=True, # download it if you don't have it
)
print(train_data.train_data.size())
print(train_data.train_labels.size())
plt.imshow(train_data.train_data[2].numpy(),cmap='gray')
plt.title('%d'%train_data.train_labels[2])
plt.show()
什么是深度学习
深度学习是机器学习中的神经网络的延伸,它将这门学问发扬光大!
什么是神经网络
计算机神经网络是模仿生物神经网络的一种运算模型。神经网络有输入层、隐藏层和输出层,通过输出层可以直观看到计算机的判断。
我们需要许多张带有标签的数据,给他看数据,首先会给我们不成熟的答案,通过一张张辨识,错误答案会反向传播让神经元的激活函数的参数进行调整,使得部分神经元变得活跃或迟钝。
黑盒
其中,输入层可以是将原数据进行处理之后的数据,称为特征,加工后的数据称为代表特征。
依次打开黑盒,就相当于黑盒不存在,与其说是黑盒对数据进行加工,不如说是由一种代表特征转化为了另一种代表特征。
我们可以试用神经网络得到的代表特征来进行迁移学习
什么是梯度下降
神经网络是梯度下降法的一个分支,得到误差函数,通过梯度下降的方式,得到误差最小(在运动就会上升)的参数,即极小值。下面是一个简化的误差曲线
但是,往往我们的得到的误差曲线不止有一个极小值。
不同的W初始化的位置会带来不同的下降区域,不同的下降区域会带来不同的W的解,我们可以得到全局最优解和局部最优解(通常会得到局部最优解),但是不用怕,因为计算机可以让我们的局部最优解变得足够优秀,可以用它很出色的完成手中的任务。
激励函数(activation funcations)
生活中很多模型都不是线性的,我们可以使用激励函数将我们的线性模型变为非线性模型
AF就是一个非线性方程,常见的分为三种,我们也可以自己定义激励函数,但必须是可以微分的,因为在进行误差反向传播的时候,只有可微分的激励函数才可以将误差反向传播回去。
当我们只有隐藏层只有一两层的时候,使用任意的激励函数随便掰弯都可以,影响不大,但是隐藏层很多的时候不能随意选择,可能会引起梯度爆炸,梯度消失等问题。
在少量层中使用激励函数推荐如下:
- 卷积神经网络:relu
- 循环神经网络:relu或tanh
回归(Regression)
我们的神经网络可以分为两种类型,一种叫做回归,一种叫做分类。
-
“回归”,大概的意思就是事物总是倾向于朝着某种“平均”发展,也可以说是回归于事物本来的面目。
-
“分类”,就是将数据进行分类。。。
下面我们做一个回归模型
先看看数据:
import torch
import torch.nn.functional as F
import matplotlib.pyplot as plt
# 生成二维数据
x = torch.unsqueeze(torch.linspace(-1,1,100),dim=1)
# 添加噪点
y = x.pow(2) + 0.2*torch.rand(x.size())
plt.scatter(x.data.numpy(),y.data.numpy())
plt.show()
构建模型(图):
class Net(torch.nn.Module):
def __init__(self,n_feature,n_hidden,n_output): # 搭建我们的层所需要的信息
super(Net,self).__init__()
self.hidden = torch.nn.Linear(n_feature,n_hidden) # 一个隐藏层。包含的信息是有多少个输入和输出
self.predict = torch.nn.Linear(n_hidden,n_output) # 因为我们是预测y的值,这里n_out可以直接写成1
def forward(self,x): # 神经网络前向传递的一个过程,搭建神经网络
x = F.relu(self.hidden(x)) # 使用hidden加工一下x,再使用激活函数进行激活。hidden输出了n_hidden个神经元
y = self.predict(x) # predict不用激励函数,因为得到的值一般为负无穷到正无穷,使用它的话会将值截掉
return y
训练、优化模型:
net = Net(1,10,1)
# print(net)
# 使用优化器优化我们的参数
optimizer = torch.optim.SGD(net.parameters(),lr=0.5) # 要优化参数,就要传入我们net的参数。lr:学习率,越高越不好,一般小于1
# 怎么计算误差的一种手段
loss_func = torch.nn.MSELoss() # MSE是均方差,用均方差来处理回归问题就足以应对了
# 开始训练,训练一百步
for t in range(100):
# 预测
prediction = net(x)
# 计算损失
loss = loss_func(prediction,y) # 计算预测值与真实值的误差,预测值在前,真实值在后
# 开始优化
optimizer.zero_grad() # 先将神经网络的参数的梯度降为0
loss.backward() # 反向传递,给每个节点计算梯度
optimizer.step()
# 可视化训练过程
if t%5 == 0:
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.item(),fontdict={'size':20,'color':'red'})
plt.pause(0.1)
plt.ioff()
plt.show()
代码汇总:
import torch
import torch.nn.functional as F
import matplotlib.pyplot as plt
import matplotlib;matplotlib.use('TKAgg') # 不加这一行的话pycharm不显示动态图
# 生成二维数据
x = torch.unsqueeze(torch.linspace(-1,1,100),dim=1)
# 添加噪点
y = x.pow(2) + 0.2*torch.rand(x.size())
plt.scatter(x.data.numpy(),y.data.numpy())
plt.show()
class Net(torch.nn.Module):
def __init__(self,n_feature,n_hidden,n_output): # 搭建我们的层所需要的信息
super(Net,self).__init__()
self.hidden = torch.nn.Linear(n_feature,n_hidden) # 一个隐藏层。包含的信息是有多少个输入和输出
self.predict = torch.nn.Linear(n_hidden,n_output) # 因为我们是预测y的值,这里n_out可以直接写成1
def forward(self,x): # 神经网络前向传递的一个过程,搭建神经网络
x = F.relu(self.hidden(x)) # 使用hidden加工一下x,再使用激活函数进行激活。hidden输出了n_hidden个神经元
y = self.predict(x) # predict不用激励函数,因为得到的值一般为负无穷到正无穷,使用它的话会将值截掉
return y
net = Net(1,10,1)
# print(net)
# 使用优化器优化我们的参数
optimizer = torch.optim.SGD(net.parameters(),lr=0.5) # 要优化参数,就要传入我们net的参数。lr:学习率,越高越不好,一般小于1
# 怎么计算误差的一种手段
loss_func = torch.nn.MSELoss() # MSE是均方差,用均方差来处理回归问题就足以应对了
# 开始训练,训练一百步
for t in range(100):
# 预测
prediction = net(x)
# 计算损失
loss = loss_func(prediction,y) # 计算预测值与真实值的误差,预测值在前,真实值在后
# 开始优化
optimizer.zero_grad() # 先将神经网络的参数的梯度降为0
loss.backward() # 反向传递,给每个节点计算梯度
optimizer.step()
# 可视化训练过程
if t%5 == 0:
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.item(),fontdict={'size':20,'color':'red'})
plt.pause(0.1)
plt.ioff()
plt.show()
分类(Classification)
多分类返回的数据格式:数字1在哪个位置,就被规定在哪一类了。
和回归模型差不多,多分类的损失函数换为CrossEntropyLoss,他计算的是概率误差
import torch
import torch.nn.functional as F
import matplotlib.pyplot as plt
import matplotlib;matplotlib.use('TKAgg')
n_data = torch.ones(100,2) # 二维数据。100个数字分开,得到50行
# print(n_data)
x0 = torch.normal(2*n_data,1)
y0 = torch.zeros(100)
x1 = torch.normal(-2*n_data,1)
y1 = torch.ones(100)
x = torch.cat((x0,x1),0).type(torch.FloatTensor) # 数据
y = torch.cat((y0,y1),).type(torch.LongTensor) # 标签
# plt.scatter(x.data.numpy()[:,0],x.data.numpy()[:,1],c=y.data.numpy(),s=100,lw=0,cmap=)
# plt.show()
class Net(torch.nn.Module):
def __init__(self,n_feature,n_hidden,n_output): # 搭建我们的层所需要的信息
super(Net,self).__init__()
self.hidden = torch.nn.Linear(n_feature,n_hidden) # 一个隐藏层。包含的信息是有多少个输入和输出
self.predict = torch.nn.Linear(n_hidden,n_output) # 因为我们是预测y的值,这里n_out可以直接写成1
def forward(self,x): # 神经网络前向传递的一个过程,搭建神经网络
x = F.relu(self.hidden(x)) # 使用hidden加工一下x,再使用激活函数进行激活。hidden输出了n_hidden个神经元
y = self.predict(x) # predict不用激励函数,因为得到的值一般为负无穷到正无穷,使用它的话会将值截掉
return y
net = Net(2,10,2) # 输入信息有xy两个特征,输出为2分类
# 使用优化器优化我们的参数
optimizer = torch.optim.SGD(net.parameters(),lr=0.5) # 要优化参数,就要传入我们net的参数。lr:学习率,越高越不好,一般小于1
# 怎么计算误差的一种手段
loss_func = torch.nn.CrossEntropyLoss() # MSE是均方差,用均方差来处理回归问题就足以应对了
# 开始训练,训练一百步
for t in range(100):
# 预测
out = net(x)
# 计算损失
loss = loss_func(out,y) # 计算预测值与真实值的误差,预测值在前,真实值在后
# 开始优化
optimizer.zero_grad() # 先将神经网络的参数的梯度降为0
loss.backward() # 反向传递,给每个节点计算梯度
optimizer.step()
if t%2 == 0:
plt.cla()
prediction = torch.max(F.softmax(out),1)[1] # 使用F.softmax(out)将输出层的值转化为概率,概率相加为1。索引为0返回的是最大值,为1是index
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)
accuracy = sum(pred_y == target_y)/200 # 准确率
plt.text(1.5,-4,'Accuracy=%.4f'%loss.item(),fontdict={'size':20,'color':'red'})
plt.pause(0.1)
plt.ioff()
plt.show()
使用Sequential快速搭建法
我们不用再手写class,可以使用Sequential快速搭建模型,下面是把上面回归模型修改了一下
import torch
import torch.nn.functional as F
import matplotlib.pyplot as plt
import matplotlib;matplotlib.use('TKAgg')
# 生成二维数据
x = torch.unsqueeze(torch.linspace(-1,1,100),dim=1)
y = x.pow(2) + 0.2*torch.rand(x.size())
# 搭建模型
net = torch.nn.Sequential(
torch.nn.Linear(1,10), # 线性模型
torch.nn.ReLU(), # 激励函数
torch.nn.Linear(10,1), # 线性模型
)
# 使用优化器优化我们的参数
optimizer = torch.optim.SGD(net.parameters(),lr=0.5) # 要优化参数,就要传入我们net的参数。lr:学习率,越高越不好,一般小于1
# 怎么计算误差的一种手段
loss_func = torch.nn.MSELoss() # MSE是均方差,用均方差来处理回归问题就足以应对了
# 开始训练,训练一百步
for t in range(100):
# 预测
prediction = net(x)
# 计算损失
loss = loss_func(prediction,y) # 计算预测值与真实值的误差,预测值在前,真实值在后
# 开始优化
optimizer.zero_grad() # 先将神经网络的参数的梯度降为0
loss.backward() # 反向传递,给每个节点计算梯度
optimizer.step()
if t%5 == 0:
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.item(),fontdict={'size':20,'color':'red'})
plt.pause(0.1)
plt.ioff()
plt.show()
保存提取神经网络
拟合线是平的的话就把lr改为0.4
import torch
import time
import matplotlib.pyplot as plt
import matplotlib;matplotlib.use('TKAgg')
torch.manual_seed(1)
# 生成二维数据
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)
def save(): # 保存模型
net = torch.nn.Sequential(
torch.nn.Linear(1, 10),
torch.nn.ReLU(), # 激励函数
torch.nn.Linear(10, 1),
)
# 使用优化器优化我们的参数
optimizer = torch.optim.SGD(net.parameters(), lr=0.4) # 要优化参数,就要传入我们net的参数。lr:学习率,越高越不好,一般小于1
# 怎么计算误差的一种手段
loss_func = torch.nn.MSELoss() # MSE是均方差,用均方差来处理回归问题就足以应对了
# 开始训练,训练一百步
for t in range(100):
# 预测
prediction = net(x)
# 计算损失
loss = loss_func(prediction, y) # 计算预测值与真实值的误差,预测值在前,真实值在后
# 开始优化
optimizer.zero_grad() # 先将神经网络的参数的梯度降为0
loss.backward() # 反向传递,给每个节点计算梯度
optimizer.step()
torch.save(net,'net.pkl') # 保存的格式为pkl。保存整个图
torch.save(net.state_dict(),'net_params.pkl') # 保存神经网络的参数,速度较快
plt.subplot(131)
plt.title('NET1')
plt.scatter(x.data.numpy(),y.data.numpy())
plt.plot(x.data.numpy(), prediction.data.numpy(),'r-',lw=5)
def restore_net(): # 引入整个模型
net2 = torch.load('net.pkl')
prediction = net2(x)
plt.subplot(132)
plt.title('NET2')
plt.scatter(x.data.numpy(),y.data.numpy())
plt.plot(x.data.numpy(), prediction.data.numpy(),'r-',lw=5)
def restore_params(): # 只提取参数,速度稍微快点
'''
建立和net一模一样的神经网络,然后将参数复制到网络中去
:return:
'''
net3 = torch.nn.Sequential(
torch.nn.Linear(1, 10),
torch.nn.ReLU(), # 激励函数
torch.nn.Linear(10, 1),
)
net3.load_state_dict(torch.load('net_params.pkl'))
prediction = net3(x)
plt.subplot(133)
plt.title('NET3')
plt.scatter(x.data.numpy(),y.data.numpy())
plt.plot(x.data.numpy(), prediction.data.numpy(),'r-',lw=5)
plt.show()
save()
restore_net()
restore_params()
批训练(minibatch training)
有时候数据非常大,我们不把所有的数据一起打包放到模型中去,通过拆分,每次都拿一小部分数据进行训练,提高训练速度。
注意,num_workers是多进程的意思,要在调用的时候放在main中,否则会一直递归。
import torch
import torch.utils.data as Data # 引入批训练的模块
BATCH_SIZE = 5 # 每次训练5个
x = torch.linspace(1,10,10)
y = torch.linspace(10,1,10)
torch_dataset = Data.TensorDataset(x,y)
loader = Data.DataLoader(
dataset=torch_dataset,
batch_size=BATCH_SIZE,
shuffle=True,
num_workers=2 # 进程数量
)
if __name__ == '__main__':
# 因为使用到了进程包,所以要在main中调用
# 训练三回
for epoch in range(3):
# 开始训练我们的数据
for step,(batch_x,batch_y) in enumerate(loader):
# 模型训练
print('Epoch: ', epoch, '| Step: ', step, '| batch x: ',
batch_x.numpy(), '| batch y: ', batch_y.numpy())
使用优化器加速神经网络训练
大多数的优化器是在更新神经网络的参数上动手脚,下图是常见的优化器。
我们可以使用SGD,将数据拆分,批量放入nn中训练。
Monentum意思是一直走下坡路,很快就能到最低点
AdaGrad是在学习率上动手脚,让他斜向前走。使得每一个参数更新,都会有不同的学习效率
Rmsprop是Monentum与AdaGrad的结合(实验证明,大多数情况下使用它可以又快又好的达到目标
)
四种optimizer优化器对比
import torch
import torch.utils.data as Data
import torch.nn.functional as F
import matplotlib.pyplot as plt
import matplotlib;matplotlib.use('TKAgg')
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(x, y)
loader = Data.DataLoader(
dataset=torch_dataset,
batch_size=BATCH_SIZE,
shuffle=True,
num_workers=2,
)
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
y = self.predict(x) # linear output
return y
# 为每个优化器创建一个 net
net_SGD = Net()
net_Momentum = Net()
net_RMSprop = Net()
net_Adam = Net()
nets = [net_SGD, net_Momentum, net_RMSprop, net_Adam]
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
if __name__ == '__main__':
for epoch in range(EPOCH):
print('Epoch: ', epoch)
for step, (b_x, b_y) in enumerate(loader):
# 对每个优化器, 优化属于他的神经网络
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.numpy()) # loss recoder
labels = ['SGD','Momentum','RMSprop','Adam']
for i,l_his in enumerate(losses_his):
plt.plot(l_his,label=labels[i])
plt.legend() # 放置图例
plt.xlabel('Steps')
plt.ylabel('Loss')
plt.ylim((0,0.2))
plt.show()
更多推荐
所有评论(0)