人体动作识别(Human activity recognition)是健康领域一个热点问题,它通过加速度计,陀螺仪等传感器记录人体运动数据,对人体动作进行识别。最近用微信小程序做了一个动作识别的项目,同时尝试部署了单片机。首先奉上b站的视频链接,里面详细介绍了项目的思路和代码:https://b23.tv/4VRvff
下面我将这个过程分成以下几部分给大家进行讲解:
1.数据收集
人体动作的数据是通过手机内部自带的六轴传感器收集的,借助于微信小程序的API可以直接调用。
其中蹲起的数据采集页面如下图所示:
右手持手机,点击“开始读取”后,开始做深蹲,加速度轴和陀螺仪的实时数据会在数据框内显示。做完动作后点击存储,会将采集的数据上传到微信自带的云数据库,并且关闭加速度计和陀螺仪。
我们将每个动作分为不同的document,每个实验者作为一个record,在数据库中进行存储。每条record由六个轴的六个数组、时间戳数组和用户的其他信息组成,数组长度约为采样频率f*采样总时间,大约是700。
将数据导出成JSON或csv文件之后便可以开始信号处理了。
2.信号处理
2.1滤波
本部分中的信号处理是通过python中的signal包来完成。
将csv文件导入到python中,将数组长度统一为700。首先我们可以先直观地感受一下数据:
plt
展示出六个轴的数据,可以看出某些轴的数据是有明显的周期性的,但是噪声较多,需要进行滤波处理。
首先使用中值滤波器,这可以通过signal包中的medfilt函数来完成:
#中值滤波
然后是巴特沃斯滤波器,同样是使用signal包中的函数来完成:
# butterworth滤波器
2.2数据切割
数据经过滤波之后在图像上的体现是变得更加平滑,滤掉了高频的噪音,此时我们将数据进行切割:设定一个时间窗口,以及一个overlap的比例,将数据切分成许多小段。这样就增加了样本的数量,满足机器学习需要的数据量。
2.3特征提取
注意,通过微信小程序提取的数据为时间序列,本身不能作为输入直接喂给机器学习模型,而是需要从中提取一些特征,作为输入向量。此处我们首先将数据进行了快速傅里叶变换,计算功率谱密度、自相关函数,在此基础上得到了时间序列的特征向量。将以上功能封装到一个函数中:
def
当我们将时域数据转换到频域数据上之后,便可以提取特征,使用分类器进行建模。提取特征的常用方法可以是信号的频率分量以及在此分量上的振幅。
3.模型构建
数据的处理工作完成之后就要开始机器学习的核心部分:模型训练了。此处我们用python强大的机器学习第三方包:sklearn来完成这一部分的工作。
3.1模型选择
机器学习模型众多,如何选择一个适合自己的呢?在此我们选择了一些常用的机器学习模型,查看它们在此数据集上的表现。
首先构建一个装有模型的字典:
dict_classifiers
然后,我们可以在此字典和每个分类器上迭代:
- 训练分类器.fit(X_train, Y_train)
- 评估分类器在训练集中的性能.score(X_train, Y_train)
- 评估分类器在测试集上的性能.score(X_test, Y_test)
- 记录训练分类器所需的时间。
- 将训练模型、训练分数、测试分数和训练时间保存到字典中。如有必要,此字典可以使用 Python 的pickle模块保存。
def
最终结果如下所示:
可以发现,Gradient Boosting算法效果是最好的,同时训练时间也最长,高达88秒;表现最不好的是SVM;训练时间最短的是Native Bayes。
通过模型的训练与对比,结合我们自身的需求,选择最为合适的模型进行参数调优。考虑到本项目后期需要部署JS,因此需要在算法的复杂程度和准确率之间取舍,此处我选择MLP(多层神经网络)作为最终的模型。
3.2超参数调优
当选择好合适的模型之后,我们就需要调整模型的参数,使其表现的最好,这就是超参数调优。MLP模型的参数主要有:激活函数、学习率
MLP_params
可以看出,当激活函数relu,alpha=1,隐藏层神经元个数为100时,MLP模型表现是最好的;同时relu函数运算较快,100个神经元大小适中,用来部署JS较为合适。
模型训练好后,用sklearn自带的函数输出权重矩阵和偏置向量,保存到csv文件中,便于后续模型的部署。
对于大部分的机器学习教程而言,模型训练完之后就算是万事大吉了,但我们的目标是最终做出一个能用于实际生活的小程序,因此还需要进行模型的部署。
4.模型部署
4.1小程序部署
我们将上面保存好的csv文件复制到小程序的js里,对六轴到的数据进行计算。通过几次实验发现,由于安卓系统传感器采集数据的频率较低,因此滤波对本数据集的影响不大。同时因为时间前后的相关性,不对序列进行特征提取,直接将序列喂给模型也能达到同样的准确率。
每隔2秒钟对数据进行一次分类,js代码就是根据MLP的原理进行矩阵的乘法,此处不再赘述。
4.2单片机部署
由于近些年来手环的兴起,因此我也尝试部署了单片机。这里模型比较庞大,即便是功能强大的STC8A8K系列的单片机也只有64KB的内存,是远远不够的,需要进行内存扩展。此处给出我的老师提供的一种方案:
按照上述方案,我使用了洞洞板+单片机的方式进行了连接,洞洞板上是内存扩展芯片,另一块板子是做其他项目时用到的,这里只用到了它的单片机:
十分凌乱,大家实验没问题之后还是用PCB打样吧。。。
最终我通过离线的方式,测试准确率达到了70%,实现了单片机的部署。
写在最后
本文从零开始实现了一个能够落地的人工智能项目,同时部署到小程序端可以实现离线识别,摆脱了对网络的依赖。
非常感谢大家的耐心阅读,我也是一名正在学习中的大二学生,所写内容如有不当之处欢迎大家批评指正。