入门神经网络二

网络搭建

  • 使用哪种深度学习框架

    目前主流的神经网络框架有tensorflow、kears,国产的有百度的PaddlePaddle,但是我是从yolov5入坑的,yolov5官方代码使用的是pytorch框架,所以我使用torch,而且torch框架上手很简单,资源较多坑较少。

  • 建立一个怎样的网络结构

  • 网络层
    网络层很简单,只有一个卷积层和一个全连接层,一个卷积层包括卷积、激活、下采样。我是用5个卷积核进行卷积,网络结构非常简单,是因为模型训练出来后需要部署在C平台上,作为一个新手,我想网络尽量简单从而避免过量的参数带来的工作量。

      self.conv1 = torch.nn.Conv2d(in_channels=1, out_channels=5, kernel_size=3, stride=(3, 1))  # 只进行横向卷积
      self.pooling = torch.nn.MaxPool2d(kernel_size=(1, 2))
      self.fc1 = torch.nn.Linear(in_features=5*1*24, out_features = 3)
    
  • 构建损失函数
    损失函数(loss function)就是用来度量模型的预测值与真实值的差异程度的运算函数,它是一个非负实值函数,损失函数越小,模型的鲁棒性就越好。损失函数使用主要是在模型的训练阶段,每个批次的训练数据送入模型后,通过前向传播输出预测值,然后损失函数会计算出预测值和真实值之间的差异值,也就是损失值。得到损失值之后,模型通过反向传播去更新各个参数,来降低真实值与预测值之间的损失,使得模型生成的预测值往真实值方向靠拢,从而达到学习的目的。

    criterion = torch.nn.CrossEntropyLoss()
  • 构建优化器
    优化器就是需要根据网络反向传播的梯度信息来更新网络的参数,以起到降低loss函数计算值的作用,我在这里测试了torch的四种优化器,我暂时不了解四种优化器的原理,但是实际训练时差异较大(后面注释是在不同网络结构下的loss,可以看出RMSprop与Adam的优化器效果最好)。

    #optimizer = torch.optim.SGD(model.parameters(),lr = 0.001,momentum=0.8) #0.4741 conv2
    #optimizer = torch.optim.SGD(model.parameters(),lr = 0.001) #0.0037 conv2    0.4931 conv1
    #optimizer = torch.optim.RMSprop(model.parameters(),lr=0.001,alpha=0.9)#0.0000 conv2    0.0000 conv1
    optimizer = torch.optim.Adam(model.parameters(),lr=0.0001,betas=(0.9,0.99))#0.0000 conv2  0.0000 conv1
    
  • 开始训练

  • 读取数据
    上文中提到我们将采集到的样本保存为npy数据,本文来读取它

      rest_sample = np.load('sample/rest.npy')
      walk_sample = np.load('sample/walk.npy')
      run_sample = np.load('sample/run.npy')
      print(rest_sample.shape)
      print(walk_sample.shape)
      print(run_sample.shape)
    
  • 上文中提到我们采集到的每种姿态的样本数量是300帧,按照网络上传统的训练比重,我将训练样本与测试样本按照7:3分开,也就是210:90个样本比例,建立训练网络结构:

    class Net(torch.nn.Module):#这个网络结构只有一层卷积
      def __init__(self):
          super(Net, self).__init__()
          self.conv1 = torch.nn.Conv2d(
            in_channels=1, out_channels=5, kernel_size=3, stride=(3, 1))  # 只进行横向卷积
          self.pooling = torch.nn.MaxPool2d(kernel_size=(1, 2))
          self.fc1 = torch.nn.Linear(in_features=5*1*24, out_features = 3)
    
      def forward(self, x):
          x = self.conv1(x)
          x = F.relu(x)
          x = self.pooling(x)
          x = x.view(x.size(0), -1)
          x = self.fc1(x)
          return x
    
    model = Net()
    print(model)
    #构建损失
    criterion = torch.nn.CrossEntropyLoss()
    #构建优化器
    #optimizer = torch.optim.SGD(model.parameters(),lr = 0.001,momentum=0.8) #0.4741 conv2
    #optimizer = torch.optim.SGD(model.parameters(),lr = 0.001) #0.0037 conv2    0.4931 conv1
    #optimizer = torch.optim.RMSprop(model.parameters(),lr=0.001,alpha=0.9)#0.0000 conv2    0.0000 conv1
    optimizer = torch.optim.Adam(model.parameters(),lr=0.0001,betas=(0.9,0.99))#0.0000 conv2  0.0000 conv1
    
    def train():
      epoches = 100
      targets = torch.tensor([0,1,2])
      for epoch in range(epoches):
          for i in range(0,210):
              inputs= torch.Tensor(([rest_sample[i]],[walk_sample[i]],[run_sample[i]]))
              outputs = model(inputs)
              loss = criterion(outputs,targets)
              optimizer.zero_grad()
              loss.backward()
              optimizer.step()
              print('Epoch: ', epoch, '| train loss: %.10f' % loss.data.numpy())
    

    这个训练过程,我们每次同时训练三个样本(batch = 3),循环迭代100次,得到best_model.pth模型文件,并将其保存在本地。

  • 模型测试

    我们读取本地保存的模型,编写测试函数,其中pred_y为测试结果。实际测试中模型准确率在80%以上。也可以在这个网站查看我的网络结构示例如下图:
    best_model.pth.png

    def test(model):
      for i in range(210,300):
          test_output = model(torch.Tensor(([rest_sample[i]],[walk_sample[i]],[run_sample[i]])))
          pred_y = torch.max(test_output, 1)[1].data.numpy().squeeze()
          #print(test_output)
          print(pred_y)

    整体网络代码如下:

    import torch
    import torch.nn.functional as F
    import numpy as np
    
    rest_sample = np.load('sample/rest.npy')
    walk_sample = np.load('sample/walk.npy')
    run_sample = np.load('sample/run.npy')
    print(rest_sample.shape)
    print(walk_sample.shape)
    print(run_sample.shape)
    #构建CNN模型
    # class Net(torch.nn.Module):
    #     def __init__(self):
    #         super(Net, self).__init__()
    #         self.conv1 = torch.nn.Conv2d(
    #             in_channels=1, out_channels=5, kernel_size=3, stride=(3, 1), padding=1)  # 只进行横向卷积
    #         self.conv2 = torch.nn.Conv2d(
    #             in_channels=5, out_channels=10, kernel_size=3, stride=(3, 1), padding=1)  # 只进行横向卷积
    #         self.pooling = torch.nn.MaxPool2d(kernel_size=(1, 2))
    #         self.fc1 = torch.nn.Linear(in_features=10*1*12, out_features = 3)
    
    #     def forward(self, x):
    #         # 先做Relu在做pooling
    #         x = self.pooling(F.relu(self.conv1(x)))
    #         x = self.pooling(F.relu(self.conv2(x)))
    #         x = x.view(x.size(0), -1)
    #         x = self.fc1(x)
    #         return x
    
    class Net(torch.nn.Module):#这个网络结构只有一层卷积
      def __init__(self):
          super(Net, self).__init__()
          self.conv1 = torch.nn.Conv2d(
            in_channels=1, out_channels=5, kernel_size=3, stride=(3, 1))  # 只进行横向卷积
          self.pooling = torch.nn.MaxPool2d(kernel_size=(1, 2))
          self.fc1 = torch.nn.Linear(in_features=5*1*24, out_features = 3)
    
      def forward(self, x):
          x = self.conv1(x)
          x = F.relu(x)
          x = self.pooling(x)
          x = x.view(x.size(0), -1)
          x = self.fc1(x)
          return x
    
    model = Net()
    print(model)
    
    #构建损失
    criterion = torch.nn.CrossEntropyLoss()
    #构建优化器
    #optimizer = torch.optim.SGD(model.parameters(),lr = 0.001,momentum=0.8) #0.4741 conv2
    #optimizer = torch.optim.SGD(model.parameters(),lr = 0.001) #0.0037 conv2    0.4931 conv1
    #optimizer = torch.optim.RMSprop(model.parameters(),lr=0.001,alpha=0.9)#0.0000 conv2    0.0000 conv1
    optimizer = torch.optim.Adam(model.parameters(),lr=0.0001,betas=(0.9,0.99))#0.0000 conv2  0.0000 conv1
    
    def train():
      epoches = 100
      targets = torch.tensor([0,1,2])
      for epoch in range(epoches):
          for i in range(0,210):
              inputs= torch.Tensor(([rest_sample[i]],[walk_sample[i]],[run_sample[i]]))
              outputs = model(inputs)
              loss = criterion(outputs,targets)
              optimizer.zero_grad()
              loss.backward()
              optimizer.step()
              print('Epoch: ', epoch, '| train loss: %.10f' % loss.data.numpy())
    def test(model):
      for i in range(210,300):
          test_output = model(torch.Tensor(([rest_sample[i]],[walk_sample[i]],[run_sample[i]])))
          pred_y = torch.max(test_output, 1)[1].data.numpy().squeeze()
          #print(test_output)
          print(pred_y)
    if __name__ == '__main__':
      # train()
      # torch.save(model, 'best_model.pth')
      my_model = torch.load('best_model.pth')
      test(my_model)
    
      # print("parameters")
      # torch.set_printoptions(profile="full")
      # for parameters in my_model.parameters():
      #     print(parameters)
      # print("------------------------------------")
      # print("name,parameters")
      # for name,parameters in my_model.named_parameters():
      #     print(name,':',parameters.size())
    
    

    后记

    从代码中能看出来我曾经测试过两层的卷积网络,实际测试效果比单纯一层网络好很多,但是后续需要将其部署到C环境中,为了减少后续的工作量,只用了一层网络,并且这层的卷积核参数只有五个,所以说效果一般般。下一章讲一下如何将这个比较简单的网络结构:怎样读取模型数据,用C语言实现输入参数预测结果。

文章目录