如何将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()