PyTorch快速使用介绍–实现分类

王 茂南 2018年7月25日09:07:1124 13220字阅读44分4秒
摘要这一篇文章会介绍一个不同激活函数在分类这个网络中的效果,具体来说就是ReLU和Sigmoid两者的效果,并且还会分析一下网络层数的深浅对模型的影响,最后会讲一个扩充数据集的办法。本文会使用PyTorch框架进行实现。

前言

上一篇文章讲了三种框架来实现线性回归,TensorFlow,Keras,PyTorch框架了解–实现线性回归,这一篇文章会详细介绍一下PyTorch的使用,会使用一个分类的例子来进行介绍。

马上就要是文艺数学君一周年的周年纪念了,到时候看看会有些什么。希望文艺数学君越做越好。

下面就开始正式讲关于PyTorch的内容,我们这次来讲一下分类,上次讲了线性回归,我们的神经网络还是就使用全连接层和激活层来搭建。

这一次介绍的四个模型分别是会比较两种激活函数,ReLU和Sigmoid,模型二和模型三;同时会比较不同层数的区别,模型一与模型二;同时会看一种数据增维的方法,模型四。下面就开始来讲吧。

实现分类

数据准备

我们首先使用sklearn中的datasets生成我们需要的数据;

  1. import numpy as np
  2. from sklearn import datasets
  3. from matplotlib import pyplot as plt
  4. # 生成样例数据
  5. noisy_moons, labels = datasets.make_moons(n_samples=1000, noise=.05, random_state=10) # 生成 1000 个样本并添加噪声
  6. # 其中800个作为训练数据,200个作为测试数据
  7. X_train,Y_train,X_test,Y_test = noisy_moons[:-200],labels[:-200],noisy_moons[-200:],labels[-200:]
  8. print(len(X_train),len(Y_train),len(X_test),len(Y_test))
  9. >> 800 800 200 200

我们可以画图看一下数据的样子:

  1. plt.figure(figsize=(8,6))
  2. plt.scatter(X_test[:,0],X_test[:,1],c=Y_test)
PyTorch快速使用介绍–实现分类

从上面的图像可以看到,我们的数据呈现月牙的形状,这种形状的数据直接使用k-means聚类是不能区分的,下面我们来搭建神经网络来实现以下数据的分类;

我们首先把要使用到的库进行导入:

  1. import torch as t
  2. from torch import nn
  3. from torch import optim
  4. from torch.autograd import Variable
  5. import torch.utils.data as Data
  6. from IPython import display

网络一(使用ReLU作为激活函数、三层)

下面开始介绍第一个模型,由于后面每个模型的代码内容基本差不多,即定义优化器,损失函数,训练绘图那里,就网络定义的地方有点区别,我们就着重先讲网络的结构,后面就贴一下全部的代码:

  1. # ---------
  2. # 网络的定义
  3. # ---------
  4. class classifer(nn.Module):
  5.     def __init__(self):
  6.         super(classifer, self).__init__()
  7.         self.class_col = nn.Sequential(
  8.             nn.Linear(2,16),
  9.             nn.ReLU(),
  10.             nn.Linear(16,16),
  11.             nn.ReLU(),
  12.             nn.Linear(16,2),
  13.         )
  14.     def forward(self, x):
  15.         out = self.class_col(x)
  16.         return out

上面是我们这里使用的网络的结构,输入是2是因为数据有x和y,最后输出也是2是因为分为两类,整个网络一共有三层,下面贴一下完整的代码,注释已经写得很详细了,可以复制下来仔细看一下;

  1. # ----------
  2. # 生成样例数据
  3. # ----------
  4. noisy_moons, labels = datasets.make_moons(n_samples=1000, noise=.05, random_state=10) # 生成 1000 个样本并添加噪声
  5. # 其中800个作为训练数据,200个作为测试数据
  6. X_train,Y_train,X_test,Y_test = noisy_moons[:-200],labels[:-200],noisy_moons[-200:],labels[-200:]
  7. # print(len(X_train),len(Y_train),len(X_test),len(Y_test))
  8. # ---------
  9. # 网络的定义
  10. # ---------
  11. class classifer(nn.Module):
  12.     def __init__(self):
  13.         super(classifer, self).__init__()
  14.         self.class_col = nn.Sequential(
  15.             nn.Linear(2,16),
  16.             nn.ReLU(),
  17.             nn.Linear(16,16),
  18.             nn.ReLU(),
  19.             nn.Linear(16,2),
  20.         )
  21.     def forward(self, x):
  22.         out = self.class_col(x)
  23.         return out
  24. # ----------------
  25. # 定义优化器及损失函数
  26. # ----------------
  27. from torch import optim
  28. model = classifer() # 实例化模型
  29. loss_fn = nn.CrossEntropyLoss() # 定义损失函数
  30. optimiser = optim.SGD(params=model.parameters(), lr=0.05) # 定义优化器
  31. # ------
  32. # 定义变量
  33. # ------
  34. from torch.autograd import Variable
  35. import torch.utils.data as Data
  36. X_train = t.Tensor(X_train) # 输入 x 张量
  37. X_test = t.Tensor(X_test)
  38. Y_train = t.Tensor(Y_train).long() # 输入 y 张量
  39. Y_test = t.Tensor(Y_test).long()
  40. # 使用batch训练
  41. torch_dataset = Data.TensorDataset(X_train, Y_train) # 合并训练数据和目标数据
  42. MINIBATCH_SIZE = 25
  43. loader = Data.DataLoader(
  44.     dataset=torch_dataset,
  45.     batch_size=MINIBATCH_SIZE,
  46.     shuffle=True,
  47.     num_workers=2           # set multi-work num read data
  48. )
  49. # ---------
  50. # 进行训练
  51. # ---------
  52. loss_list = []
  53. plt.style.use('ggplot')
  54. for epoch in range(70):
  55.     for step, (batch_x, batch_y) in enumerate(loader):
  56.         optimiser.zero_grad() # 梯度清零
  57.         out = model(batch_x) # 前向传播
  58.         loss = loss_fn(out, batch_y) # 计算损失
  59.         loss.backward() # 反向传播
  60.         optimiser.step() # 随机梯度下降
  61.     loss_list.append(loss)
  62.     if epoch%10==0:
  63.         outputs_train = model(X_train)
  64.         _, predicted_train = t.max(outputs_train, 1)
  65.         outputs_test = model(X_test)
  66.         _, predicted_test = t.max(outputs_test, 1)
  67.         # 同时画出训练集和测试的效果
  68.         display.clear_output(wait=True)
  69.         fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(13,7))
  70.         axes[0].scatter(X_train[:,0].numpy(),X_train[:,1].numpy(),c=predicted_train)
  71.         axes[0].set_xlabel('train')
  72.         axes[1].scatter(X_test[:,0].numpy(),X_test[:,1].numpy(),c=predicted_test)
  73.         axes[1].set_xlabel('test')
  74.         display.display(fig)

我们来看一下上面代码的输出,左边是训练集上的结果,右边是测试集上的结果:

PyTorch快速使用介绍–实现分类

可以看到最终可以全部分开,我们再看一下loss的情况:

PyTorch快速使用介绍–实现分类

网络二(使用ReLU作为激活函数、五层)

这个网络和上面的区别在于网络层数变深了,我们看一下这时候的情况,还是先看一下网络的定义:

  1. class classifer(nn.Module):
  2.     def __init__(self):
  3.         super(classifer, self).__init__()
  4.         self.class_col = nn.Sequential(
  5.             nn.Linear(2,16),
  6.             nn.ReLU(),
  7.             nn.Linear(16,32),
  8.             nn.ReLU(),
  9.             nn.Linear(32,32),
  10.             nn.ReLU(),
  11.             nn.Linear(32,32),
  12.             nn.ReLU(),
  13.             nn.Linear(32,2),
  14.         )
  15.     def forward(self, x):
  16.         out = self.class_col(x)
  17.         return out

和上面的差不多,就是变深了,看一下完整的代码:

  1. # 网路变深
  2. # ----------
  3. # 生成样例数据
  4. # ----------
  5. noisy_moons, labels = datasets.make_moons(n_samples=1000, noise=.05, random_state=10) # 生成 1000 个样本并添加噪声
  6. # 其中800个作为训练数据,200个作为测试数据
  7. X_train,Y_train,X_test,Y_test = noisy_moons[:-200],labels[:-200],noisy_moons[-200:],labels[-200:]
  8. # print(len(X_train),len(Y_train),len(X_test),len(Y_test))
  9. # ---------
  10. # 网络的定义
  11. # ---------
  12. class classifer(nn.Module):
  13.     def __init__(self):
  14.         super(classifer, self).__init__()
  15.         self.class_col = nn.Sequential(
  16.             nn.Linear(2,16),
  17.             nn.ReLU(),
  18.             nn.Linear(16,32),
  19.             nn.ReLU(),
  20.             nn.Linear(32,32),
  21.             nn.ReLU(),
  22.             nn.Linear(32,32),
  23.             nn.ReLU(),
  24.             nn.Linear(32,2),
  25.         )
  26.     def forward(self, x):
  27.         out = self.class_col(x)
  28.         return out
  29. # ----------------
  30. # 定义优化器及损失函数
  31. # ----------------
  32. from torch import optim
  33. model = classifer() # 实例化模型
  34. loss_fn = nn.CrossEntropyLoss() # 定义损失函数
  35. optimiser = optim.SGD(params=model.parameters(), lr=0.05) # 定义优化器
  36. # ------
  37. # 定义变量
  38. # ------
  39. from torch.autograd import Variable
  40. import torch.utils.data as Data
  41. X_train = t.Tensor(X_train) # 输入 x 张量
  42. X_test = t.Tensor(X_test)
  43. Y_train = t.Tensor(Y_train).long() # 输入 y 张量
  44. Y_test = t.Tensor(Y_test).long()
  45. # 使用batch训练
  46. torch_dataset = Data.TensorDataset(X_train, Y_train) # 合并训练数据和目标数据
  47. MINIBATCH_SIZE = 25
  48. loader = Data.DataLoader(
  49.     dataset=torch_dataset,
  50.     batch_size=MINIBATCH_SIZE,
  51.     shuffle=True,
  52.     num_workers=2           # set multi-work num read data
  53. )
  54. # ---------
  55. # 进行训练
  56. # ---------
  57. loss_list = []
  58. for epoch in range(200):
  59.     for step, (batch_x, batch_y) in enumerate(loader):
  60.         optimiser.zero_grad() # 梯度清零
  61.         out = model(batch_x) # 前向传播
  62.         loss = loss_fn(out, batch_y) # 计算损失
  63.         loss.backward() # 反向传播
  64.         optimiser.step() # 随机梯度下降
  65.     loss_list.append(loss)
  66.     if epoch%10==0:
  67.         outputs = model(X_test)
  68.         _, predicted = t.max(outputs, 1)
  69.         display.clear_output(wait=True)
  70.         plt.style.use('ggplot')
  71.         plt.figure(figsize=(12, 8))
  72.         plt.scatter(X_test[:,0].numpy(),X_test[:,1].numpy(),c=predicted)
  73.         plt.title("epoch: {}, loss:{}".format(epoch+1, loss))
  74.         plt.show()

还是看一下训练过程中结果的变化,可以看到收敛还是很快的

PyTorch快速使用介绍–实现分类

接下来可以看一下loss的变化情况,和上面的模型比起来,loss下降更加快了。

PyTorch快速使用介绍–实现分类

网络三(使用Sigmoid作为激活函数、五层)

这个网络我们使用Sigmoid作为激活函数来尝试一下,其他的不变。我们还是先把网络结构打印出来:

  1. # ---------
  2. # 网络的定义
  3. # ---------
  4. class classifer(nn.Module):
  5.     def __init__(self):
  6.         super(classifer, self).__init__()
  7.         self.class_col = nn.Sequential(
  8.             nn.Linear(2,16),
  9.             nn.Sigmoid(),
  10.             nn.Linear(16,32),
  11.             nn.Sigmoid(),
  12.             nn.Linear(32,32),
  13.             nn.Sigmoid(),
  14.             nn.Linear(32,32),
  15.             nn.Sigmoid(),
  16.             nn.Linear(32,2),
  17.         )
  18.     def forward(self, x):
  19.         out = self.class_col(x)
  20.         return out

接下来看一下完整的代码:

  1. # 调节网络获得更好的结果
  2. # ----------
  3. # 生成样例数据
  4. # ----------
  5. noisy_moons, labels = datasets.make_moons(n_samples=1000, noise=.05, random_state=10) # 生成 1000 个样本并添加噪声
  6. # 其中800个作为训练数据,200个作为测试数据
  7. X_train,Y_train,X_test,Y_test = noisy_moons[:-200],labels[:-200],noisy_moons[-200:],labels[-200:]
  8. # print(len(X_train),len(Y_train),len(X_test),len(Y_test))
  9. # ---------
  10. # 网络的定义
  11. # ---------
  12. class classifer(nn.Module):
  13.     def __init__(self):
  14.         super(classifer, self).__init__()
  15.         self.class_col = nn.Sequential(
  16.             nn.Linear(2,16),
  17.             nn.Sigmoid(),
  18.             nn.Linear(16,32),
  19.             nn.Sigmoid(),
  20.             nn.Linear(32,32),
  21.             nn.Sigmoid(),
  22.             nn.Linear(32,32),
  23.             nn.Sigmoid(),
  24.             nn.Linear(32,2),
  25.         )
  26.     def forward(self, x):
  27.         out = self.class_col(x)
  28.         return out
  29. # ----------------
  30. # 定义优化器及损失函数
  31. # ----------------
  32. from torch import optim
  33. model = classifer() # 实例化模型
  34. loss_fn = nn.CrossEntropyLoss() # 定义损失函数
  35. optimiser = optim.SGD(params=model.parameters(), lr=0.1) # 定义优化器
  36. # ------
  37. # 定义变量
  38. # ------
  39. from torch.autograd import Variable
  40. import torch.utils.data as Data
  41. X_train = t.Tensor(X_train) # 输入 x 张量
  42. X_test = t.Tensor(X_test)
  43. Y_train = t.Tensor(Y_train).long() # 输入 y 张量
  44. Y_test = t.Tensor(Y_test).long()
  45. # 使用batch训练
  46. torch_dataset = Data.TensorDataset(X_train, Y_train) # 合并训练数据和目标数据
  47. MINIBATCH_SIZE = 25
  48. loader = Data.DataLoader(
  49.     dataset=torch_dataset,
  50.     batch_size=MINIBATCH_SIZE,
  51.     shuffle=True,
  52.     num_workers=2           # set multi-work num read data
  53. )
  54. # ---------
  55. # 进行训练
  56. # ---------
  57. loss_list = []
  58. for epoch in range(500):
  59.     for step, (batch_x, batch_y) in enumerate(loader):
  60.         optimiser.zero_grad() # 梯度清零
  61.         out = model(batch_x) # 前向传播
  62.         loss = loss_fn(out, batch_y) # 计算损失
  63.         loss.backward() # 反向传播
  64.         optimiser.step() # 随机梯度下降
  65.     loss_list.append(loss)
  66.     if epoch%10==0:
  67.         outputs = model(X_test)
  68.         _, predicted = t.max(outputs, 1)
  69.         display.clear_output(wait=True)
  70.         plt.style.use('ggplot')
  71.         plt.figure(figsize=(12, 8))
  72.         plt.scatter(X_test[:,0].numpy(),X_test[:,1].numpy(),c=predicted)
  73.         plt.title("epoch: {}, loss:{}".format(epoch+1, loss))
  74.         plt.show()

看一下这个训练的动图,可以看到epoch是一直在变化的,前面模型收敛的比较慢:

PyTorch快速使用介绍–实现分类

下面我们看一下loss的图,来看一下上面的想法是否正确:

PyTorch快速使用介绍–实现分类

可以看到使用Sigmoid作为激活函数确实会收敛的慢一些,但是也不是所有的都适合用ReLU,有很多情况我也不确定,具体用的时候可以看一下别人写的论文之类的。

网络四(使用Sigmoid作为激活函数、五层、扩充数据集)

这个模型我们会重点介绍一下数据集扩展的方式,我们之前使用的数据集只有两个维度,可以认为是x1和x2,但是有的时候只有这两个数据是不够的,我们可以通过扩充数据集的方式使得模型更快的收敛:

  1. import math
  2. noisy_moons, labels = datasets.make_moons(n_samples=1000, noise=.05, random_state=10) # 生成 1000 个样本并添加噪声
  3. # 增加特征
  4. features1 = (noisy_moons[:,0] * noisy_moons[:,0]).reshape(-1,1)
  5. features2 = (noisy_moons[:,1] * noisy_moons[:,1]).reshape(-1,1)
  6. features3 = (noisy_moons[:,0] * noisy_moons[:,1]).reshape(-1,1)
  7. features4 = np.array([math.sin(i) for i in noisy_moons[:,0]]).reshape(-1,1)
  8. features5 = np.array([math.sin(i) for i in noisy_moons[:,1]]).reshape(-1,1)
  9. noisy_moons = np.hstack((noisy_moons,features1,features2,features3,features4,features5))

可以看到上面的代码,我们增加了五个特征,x1^2, x2^2, x1*x2, sin(x1)和sin(x1) ,其余的我们不变,还是使用上面的网络结构进行训练,只不过输入要改成7。

我们来看一下上面数据合并的方法,使用一个简单的例子进行查看:

PyTorch快速使用介绍–实现分类

接下来我们来看一下代码:

  1. # 增加特征获得更好的结果
  2. import math
  3. # ----------
  4. # 生成样例数据
  5. # ----------
  6. noisy_moons, labels = datasets.make_moons(n_samples=1000, noise=.05, random_state=10) # 生成 1000 个样本并添加噪声
  7. # 增加特征
  8. features1 = (noisy_moons[:,0] * noisy_moons[:,0]).reshape(-1,1)
  9. features2 = (noisy_moons[:,1] * noisy_moons[:,1]).reshape(-1,1)
  10. features3 = (noisy_moons[:,0] * noisy_moons[:,1]).reshape(-1,1)
  11. features4 = np.array([math.sin(i) for i in noisy_moons[:,0]]).reshape(-1,1)
  12. features5 = np.array([math.sin(i) for i in noisy_moons[:,1]]).reshape(-1,1)
  13. noisy_moons = np.hstack((noisy_moons,features1,features2,features3,features4,features5))
  14. # 其中800个作为训练数据,200个作为测试数据
  15. X_train,Y_train,X_test,Y_test = noisy_moons[:-200],labels[:-200],noisy_moons[-200:],labels[-200:]
  16. # print(len(X_train),len(Y_train),len(X_test),len(Y_test))
  17. # ---------
  18. # 网络的定义
  19. # ---------
  20. class classifer(nn.Module):
  21.     def __init__(self):
  22.         super(classifer, self).__init__()
  23.         self.class_col = nn.Sequential(
  24.             nn.Linear(7,32),
  25.             nn.Sigmoid(),
  26.             nn.Linear(32,32),
  27.             nn.Sigmoid(),
  28.             nn.Linear(32,32),
  29.             nn.Sigmoid(),
  30.             nn.Linear(32,32),
  31.             nn.Sigmoid(),
  32.             nn.Linear(32,2),
  33.         )
  34.     def forward(self, x):
  35.         out = self.class_col(x)
  36.         return out
  37. # ----------------
  38. # 定义优化器及损失函数
  39. # ----------------
  40. from torch import optim
  41. model = classifer() # 实例化模型
  42. loss_fn = nn.CrossEntropyLoss() # 定义损失函数
  43. optimiser = optim.SGD(params=model.parameters(), lr=0.1) # 定义优化器
  44. # ------
  45. # 定义变量
  46. # ------
  47. from torch.autograd import Variable
  48. import torch.utils.data as Data
  49. X_train = t.Tensor(X_train) # 输入 x 张量
  50. X_test = t.Tensor(X_test)
  51. Y_train = t.Tensor(Y_train).long() # 输入 y 张量
  52. Y_test = t.Tensor(Y_test).long()
  53. # 使用batch训练
  54. torch_dataset = Data.TensorDataset(X_train, Y_train) # 合并训练数据和目标数据
  55. MINIBATCH_SIZE = 25
  56. loader = Data.DataLoader(
  57.     dataset=torch_dataset,
  58.     batch_size=MINIBATCH_SIZE,
  59.     shuffle=True,
  60.     num_workers=2           # set multi-work num read data
  61. )
  62. # ---------
  63. # 进行训练
  64. # ---------
  65. loss_list = []
  66. for epoch in range(500):
  67.     for step, (batch_x, batch_y) in enumerate(loader):
  68.         optimiser.zero_grad() # 梯度清零
  69.         out = model(batch_x) # 前向传播
  70.         loss = loss_fn(out, batch_y) # 计算损失
  71.         loss.backward() # 反向传播
  72.         optimiser.step() # 随机梯度下降
  73.     loss_list.append(loss)
  74.     if epoch%10==0:
  75.         outputs = model(X_test)
  76.         _, predicted = t.max(outputs, 1)
  77.         display.clear_output(wait=True)
  78.         plt.style.use('ggplot')
  79.         plt.figure(figsize=(12, 8))
  80.         plt.scatter(X_test[:,0].numpy(),X_test[:,1].numpy(),c=predicted)
  81.         plt.title("epoch: {}, loss:{}".format(epoch+1, loss))
  82.         plt.show()

我们就直接看一下loss变化趋势的图像,可以看到这次的收敛会比上面做数据扩展之前快一些。

PyTorch快速使用介绍–实现分类

结语

关于上面四个模型的比较,我们可以看到当模型层数较深,且使用ReLU作为激活函数时效果会比较好,同时我们还学习了一种数据增维的方式。

这次的关于PyTorch的介绍到这里为止,其实内容也不是很多,很多代码片段都是重复的,我就只是多写了几次,方便之后直接复制来进行运行。

之后的话会继续更新关于深度学习的内容(写一篇文章挺久的,慢慢写)。

  • 微信公众号
  • 关注微信公众号
  • weinxin
  • QQ群
  • 我们的QQ群号
  • weinxin
王 茂南
  • 本文由 发表于 2018年7月25日09:07:11
  • 转载请务必保留本文链接:https://mathpretty.com/9469.html
匿名

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

评论:2   其中:访客  1   博主  1
    • 马掌头
      马掌头

      写的非常好,对我帮我很大