入门神经网络-搭建自己的网络结构之网络搭建(二)
入门神经网络二
网络搭建
使用哪种深度学习框架
目前主流的神经网络框架有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%以上。也可以在这个网站查看我的网络结构示例如下图:
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语言实现输入参数预测结果。
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。