rubix / har
使用在手机传感器数据上训练的Softmax分类器,识别六种人类活动之一,如站立、坐着和行走。
Requires
- php: >=7.4
- rubix/ml: ^2.0
README
这是一个示例项目,展示了使用手机内部惯性测量单元(IMU)记录的传感器数据来演示人类活动识别(HAR)的问题。训练数据是30名志愿者在进行各种任务(如坐着、站立、行走和躺下)时的人工标注的传感器读数。每个样本包含一个561特征的窗口,但我们通过称为随机投影的技术证明,我们可以减少维度而不损失任何精度。我们将训练一个Softmax分类器来完成这个任务,它是二元分类器逻辑回归的多类泛化。
- 难度:中等
- 训练时间:分钟
安装
使用 Composer 在本地克隆项目
$ composer create-project rubix/har
要求
- PHP 7.4或更高版本
推荐
- Tensor扩展 以实现更快的训练和推理
- 1G的系统内存或更多
教程
介绍
实验是在19-48岁年龄段的30名志愿者组中进行的。每个人穿着腰部的智能手机执行了六项活动(行走、上楼梯行走、下楼梯行走、坐着、站立和躺下)。使用其内置加速度计和陀螺仪,以50Hz的恒定速率记录了3轴线性加速度和3轴角速度。传感器信号通过应用噪声滤波器进行预处理,然后以2.56秒的固定宽度滑动窗口进行采样。我们的目标是构建一个分类器,根据一些未见数据识别用户正在执行的活动。
注意:此示例的源代码可以在项目根目录中的train.php文件中找到。
提取数据
数据以两个NDJSON(换行分隔的JSON)文件的形式提供,位于项目根目录中。一个文件包含训练样本,另一个用于测试。我们将使用Rubix ML提供的NDJSON提取器将训练数据导入新的Labeled数据集对象。由于提取器是迭代器,我们可以直接将提取器传递给fromIterator()
工厂方法。
use Rubix\ML\Datasets\Labeled; use Rubix\ML\Extractors\NDJSON; $dataset = Labeled::fromIterator(new NDJSON('train.ndjson'));
数据集准备
在机器学习中,降维常用于压缩输入样本,以保留大部分或全部信息。通过减少输入特征的数量,我们可以加快训练过程。《随机投影》(Random Projection)是一种基于《Johnson-Lindenstrauss引理》(Johnson-Lindenstrauss lemma)的、计算效率高的无监督降维技术,该引理表明,高维空间中的一组点可以嵌入到较低维度的空间中,使得点之间的距离几乎保持不变。《高斯随机投影器》(Gaussian Random Projector)将作为我们流程的一部分,应用于HAR数据集的降维。高斯随机投影器将对样本矩阵应用从高斯分布中抽取的随机线性变换。我们将目标维度数设置为110,这比原始输入维度的20%还少。
最后,我们将使用《Z Scale 标准化器》(Z Scale Standardizer)对数据集进行居中和缩放,使特征值具有0均值和单位方差。这一步将有助于学习者在训练过程中更快地收敛。
我们将这些转换封装在一个《流程》(Pipeline)中,以便将它们的拟合与模型一起持久化。
实例化学习器
现在,我们将关注设置学习器的超参数。《Softmax分类器》(Softmax Classifier)是一种单层神经网络,具有《Softmax》输出层。训练是迭代进行的,使用小批量梯度下降,在每个epoch中,模型参数沿着由用户定义的成本函数(如《交叉熵》(Cross Entropy))产生的误差梯度的最小值方向迈出一步。
Softmax分类器的第一个超参数是《批量大小》(batch size),它控制一次被送入网络的样本数量。批量大小在训练速度和梯度估计的平滑性之间进行权衡。对于这个例子,256个批量大大小比较合适,因此我们将选择这个值,但也欢迎您在自己的设置中尝试其他批量大小。
下一个超参数是梯度下降的《优化器》(optimizer)和相关的《学习率》(learning rate)。《动量优化器》(Momentum optimizer)是一种自适应优化器,它将动量力添加到每个参数更新中。动量有助于通过更快地遍历梯度来加速训练。它使用用户可以设置的全球学习率,通常在0.1到0.0001之间。对于这个例子,默认设置0.001效果很好,因此我们将保持这个设置。
use Rubix\ML\PersistentModel; use Rubix\ML\Pipeline; use Rubix\ML\Transformers\GaussianRandomProjector; use Rubix\ML\Transformers\ZScaleStandardizer; use Rubix\ML\Classifiers\SoftmaxClassifier; use Rubix\ML\NeuralNet\Optimizers\Momentum; use Rubix\ML\Persisters\Filesystem; $estimator = new PersistentModel( new Pipeline([ new GaussianRandomProjector(110), new ZScaleStandardizer(), ], new SoftmaxClassifier(256, new Momentum(0.001))), new Filesystem('har.rbx') );
我们将整个流程封装在一个《持久化模型》(Persistent Model)元估计器中,该估计器为基本估计器添加了《save()`》和《load()`》方法。《持久化模型》需要一个《持久化器》(Persister)对象来告诉它在哪里存储序列化的模型数据。《文件系统持久化器》(Filesystem persister)将模型数据保存和加载到存储中用户指定的路径上的文件中。
设置日志记录器
由于Softmax分类器实现了详细输出接口,我们可以实时记录训练进度。要设置记录器,请将兼容PSR-3的记录器实例传递给学习实例上的setLogger()
方法。如果只需要将简单信息输出到控制台,Rubix ML内置的Screen记录器是一个不错的选择。
use Rubix\ML\Loggers\Screen; $estimator->setLogger(new Screen());
训练
要开始训练学习器,请使用训练数据集作为参数,在实例上调用train()
方法。
$estimator->train($dataset);
训练损失
在训练过程中,学习器会记录每个epoch的训练损失,我们可以绘制出来以可视化训练进度。训练损失是每个epoch的成本函数值,可以解释为模型在更新步骤后剩余的错误量。要返回每个epoch的成本函数值数组,请在学习器上调用steps()
方法。然后我们将损失保存到CSV文件中,使用可写的CSV提取器。
use Rubix\ML\Extractors\CSV; $extractor = new CSV('progress.csv', true); $extractor->export($estimator->steps());
这是从一次训练会话中得到的交叉熵成本函数的线图示例。如图所示,模型在早期epoch快速学习,接近最终阶段时,学习器调整模型参数,训练速度变慢。
保存
由于我们将估算器包装在持久模型包装器中,我们可以通过在估算器实例上调用save()
方法来保存模型。
$estimator->save();
要运行训练脚本,请在命令行中像这样调用它。
$ php train.php
交叉验证
数据集的作者提供了额外的2,947个标记的测试样本,我们将使用这些样本来测试模型。我们一直将这些样本保留到現在,因为我们想能够在学习器从未见过的样本上测试模型。首先从test.ndjson
文件中提取测试样本和真实标签。
注意:该示例的源代码可以在项目根目录下的validate.php文件中找到。
use Rubix\ML\Datasets\Labeled; use Rubix\ML\Extractors\NDJSON; $dataset = Labeled::fromIterator(new NDJSON('test.ndjson'));
从存储中加载模型
要加载之前实例化的估算器/转换器管道,请使用指向存储中模型的持久化实例的Persister实例,在持久模型类上调用静态load()
方法。
use Rubix\ML\PersistentModel; use Rubix\ML\Persisters\Filesystem; $estimator = PersistentModel::load(new Filesystem('har.rbx'));
进行预测
要从模型中获得预测,请将测试集传递给估算器实例上的predict()
方法。
$predictions = $estimator->predict($dataset);
生成报告
交叉验证报告提供了有关模型性能的详细统计信息。一个多分类分解报告将模型的性能分解到类别级别,并输出诸如准确性、精确度、召回率等指标。一个混淆矩阵是一个表格,比较预测标签与实际标签,以显示模型在预测某些类别时是否有困难。我们将这两个报告包装在一个汇总报告中,这样我们就可以同时生成这两个报告。
use Rubix\ML\CrossValidation\Reports\AggregateReport; use Rubix\ML\CrossValidation\Reports\MulticlassBreakdown; use Rubix\ML\CrossValidation\Reports\ConfusionMatrix; $report = new AggregateReport([ new MulticlassBreakdown(), new ConfusionMatrix(), ]);
现在,使用测试集中的预测和标签生成报告。此外,我们还将报告输出到控制台,并将结果保存到JSON文件以供以后参考。
use Rubix\ML\Persisters\Filesystem; $results = $report->generate($predictions, $dataset->labels()); echo $results; $results->toJSON()->saveTo(new Filesystem('report.json'));
要执行验证脚本,请在命令提示符中输入以下命令。
$ php validate.php
报告的输出应该类似于下面的输出。做得好!如您所见,我们的估算器大约有97%的准确性,并且具有非常好的特异性和负预测值。
[ { "overall": { "accuracy": 0.9674308943546821, "precision": 0.9063809316861989, "recall": 0.9048187793615003, "specificity": 0.9802554195397294, "negative_predictive_value": 0.9803712249716344, "false_discovery_rate": 0.09361906831380108, "miss_rate": 0.09518122063849947, "fall_out": 0.019744580460270538, "false_omission_rate": 0.01962877502836563, "f1_score": 0.905257137386163, "mcc": 0.8858111380161123, "informedness": 0.8850741989012301, "markedness": 0.8867521566578332, "true_positives": 2675, "true_negatives": 13375, "false_positives": 272, "false_negatives": 272, "cardinality": 2947 }, } ]
下一步
完成本教程关于使用Softmax分类器对人进行活动分类后,尝试通过微调一些超参数来获得更好的结果。通过从管道中移除高斯随机投影器,看看维度降低对估计器最终准确率的影响有多大。还有哪些维度降低技术效果更好吗?
原始数据集
联系人:Jorge L. Reyes-Ortiz(1,2),Davide Anguita(1),Alessandro Ghio(1),Luca Oneto(1)和Xavier Parra(2) 机构:1 - Smartlab - 非线性复杂系统实验室 DITEN - 热那亚大学,热那亚(I-16145),意大利。 2 - CETpD - 护理依赖性和自主生活技术研究中心 加泰罗尼亚理工大学(BarcelonaTech)。Vilanova i la Geltrú(08800),西班牙 activityrecognition '@' smartlab.ws
参考文献
- Davide Anguita,Alessandro Ghio,Luca Oneto,Xavier Parra和Jorge L. Reyes-Ortiz。用于智能手机人体活动识别的公共领域数据集。第21届欧洲人工神经网络、计算智能和机器学习研讨会,ESANN 2013,布鲁日,比利时,2013年4月24-26日。
许可协议
代码遵循MIT许可协议,教程遵循CC BY-NC 4.0许可协议。