时间序列分类与音频唤醒词检测实战

时间序列分类

在时间序列分类中,数据标注是重要的初始步骤。之前章节的数据标注是自动完成的,而现在需要手动进行。这一过程可能会很繁琐,尤其是在处理大量数据时,但数据集的准备(收集和标注)通常都很耗时。不过,输入数据的质量越高,分类结果的质量也会越高。

数据标注操作步骤
  1. 加载时间序列数据 :使用 tinyml4all Python 包中的 TimeSeries 类读取 CSV 文件夹中的数据。
from tinyml4all.time.episodic.classification import TimeSeries
ts = TimeSeries.read_csv_folder("media-control")
  1. 运行标注 GUI :调用 label_gui() 方法打开浏览器窗口,在窗口中对时间序列进行标注。
ts.label_gui()
  1. 保存标注结果 :标注完成后,从页面底部的 Output 标签复制内容,粘贴到一个名为 labels.json 的新文件中,或者点击下载图标,然后将文件移动到 media-control 文件夹中。

需要注意的是,数据文件夹中可能会有 PKL 文件,这些文件是由 tinyml4all 库自动创建的,包含时间序列数据的紧凑表示,不要删除它们,因为它们可以加快代码的加载时间。

以下代码可以用来验证数据加载和标注结果:

from tinyml4all.time.episodic.classification import TimeSeries
ts = TimeSeries.read_csv_folder("media-control")
print(ts.events)
特征工程

特征工程是时间序列分类中的关键环节。在处理多维数据时,通常会对每个维度单独进行特征提取,最后将各维度的特征连接成一个特征向量。

以下是一些常用的特征:
1. 统计矩
- 均值(Mean) :数据集的平均值,反映数据的中心趋势。
- 标准差(Standard deviation) :衡量数据相对于均值的离散程度。
- 偏度(Skew) :衡量数据分布的不对称性。
- 峰度(Kurtosis) :衡量数据分布的尾部密度。
2. 自相关(Autocorrelation) :衡量时间序列在不同时间点的相似性,反映数据的短期模式。
3. 形状指标
- 峰值数量(Number of peaks) :序列中的峰值(最小值或最大值)数量。
- 高于/低于均值的样本数量(Count above/below mean) :值大于/小于均值的样本数量。

为了更全面地捕捉时间序列的模式,通常会使用窗口化方法将长输入序列分割成较短的重叠块。窗口化有两个重要参数:
- 长度(Length) :窗口内包含的样本数量。
- 偏移(Shift) :窗口满时,丢弃的样本数量,以容纳新的样本。

时间序列分类链

为了对时间序列输入数据进行预处理、窗口化、特征提取和分类,需要构建一个操作链。 Chain 类提供了一个结构化的格式,包含以下几个部分:
- pre(预处理) :对输入数据进行预处理的步骤列表,如缩放、归一化、分箱等,可选。
- chunk(分块) :定义子块的持续时间,可选。
- features(特征提取) :负责从每个窗口(或块)中提取特征的步骤(或步骤列表),必须。
- ovr(一对多分类) :在特征提取后对数据的二进制视图(感兴趣的类与非感兴趣的类)运行的步骤列表,必须。

以下是一个示例代码,展示了如何构建和使用时间序列分类链:

from tinyml4all.time.episodic.classification import TimeSeries, Chain
from tinyml4all.time.episodic.features import Window
from tinyml4all.time.features import Scale, Moments, Autocorrelation, Peaks, CountAboveMean, Select
from tinyml4all.time.models import RandomForest

ts = TimeSeries.read_csv_folder("media-control")
chain = Chain(
    pre=[Scale("minmax")],
    window=Window(chunk="250ms", features=[Moments(), Autocorrelation(), Peaks(), CountAboveMean()]),
    ovr=[
        Select(sequential="auto"),
        RandomForest()
    ]
)

tables = chain(ts)
for table in tables:
    print(table.classification_report())
True vs Predicted not volume-up volume-up
not volume-up 230 0
volume-up 0 26
部署到 Arduino

训练完成后,需要将分类链转换为 C++ 代码,以便在 Arduino 上运行。以下是具体的操作步骤:
1. 生成 C++ 代码 :使用 convert_to() 方法将分类链转换为 C++ 代码。

chain.convert_to("c++", class_name="MediaControlChain", save_to="MediaControlChain.h")
  1. 复制代码到项目文件夹 :将生成的 MediaControlChain.h 文件复制到 Arduino 项目的文件夹中。
  2. 上传 Arduino 代码 :上传以下代码到 Arduino 板,实现媒体控制手势的预测。
#include <Arduino_LSM9DS1.h>
#include <PluggableUSBHID.h>
#include <USBKeyboard.h>
#include <tinyml4all.h>
#include "./MediaControlChain.h"

tinyml4all::LSM9DS1 imu;
tinyml4all::MediaControlChain chain;
USBKeyboard keyboard;

void setup() {
  Serial.begin(115200);
  while (!Serial);
  Serial.println("Predict media control gestures");
  imu.begin();
}

void loop() {
  imu.readMagneticField();
  if (!chain(imu.mx, imu.my, imu.mz))
    return;
  if (chain.output.classification.label == "idle")
    return;
  Serial.print("Predicted ");
  Serial.print(chain.output.classification.label);
  Serial.print(" with confidence ");
  Serial.println(chain.output.classification.confidence);
  if (chain.label == "tap")
    keyboard.media_control(KEY_PLAY_PAUSE);
  else if (chain.label == "next")
    keyboard.media_control(KEY_NEXT_TRACK);
}

打开串口监视器,进行媒体控制手势操作,你会看到预测结果。该方法的预测时间约为 4 ms,比 Edge Impulse 模型快很多,但通常准确性较低。

音频唤醒词检测

在 TinyML 和音频处理领域,音频唤醒词检测(Keyword Spotting,KWS)对于实现设备的免提交互至关重要。从智能音箱到手机,KWS 系统不断监听特定的唤醒词或命令。然而,在资源受限的设备上实现这些系统面临着独特的挑战,特别是在高效处理原始音频数据方面。

硬件要求

要进行音频唤醒词检测,需要一个麦克风来捕获音频。以下是一些内置麦克风的 Arduino 板:
- PDM 接口 :Arduino Nano BLE Sense、Arduino RP2040 Connect 和 Nicla Vision。
- I2S 接口 :Seeed Studio Wio Terminal 和 LILYGO TTGO 变体。

如果没有这些板,可以购买外部麦克风,并根据其要求进行连接。常见的 Arduino 麦克风有两种类型:
- PDM(脉冲密度调制) :音频波形编码在数字脉冲的密度中,需要专门的软件进行解码,通常只处理单声道音频,每个样本 16 位。
- I2S(Inter-IC Sound) :音频输出已经编码,无需进一步处理,Arduino 生态系统中的 I2S 麦克风通常可以处理 32 位立体声音频。

在购买麦克风时,要确保其与所用的 Arduino 板兼容。后续的代码示例假设使用的是 Arduino Nano BLE Sense,你可以在代码仓库中找到不同设备的更多示例。

通过以上内容,我们介绍了时间序列分类和音频唤醒词检测的基本原理、操作步骤和代码实现,希望能帮助你在相关领域开展实践和研究。

时间序列分类与音频唤醒词检测实战(续)

音频唤醒词检测实战流程

在具备了合适的硬件之后,就可以开始音频唤醒词检测的实战操作了。这里以使用 Edge Impulse 低代码平台为例,构建一个类似常见语音助手激活机制的系统,用“Hey Arduino”语音命令来唤醒 Arduino 板。

数据采集

首先需要采集音频数据,这些数据将用于训练唤醒词检测模型。具体操作如下:
1. 连接硬件 :确保 Arduino 板和麦克风正常连接。若使用 Arduino Nano BLE Sense,其内置麦克风可直接使用。
2. 安装 Edge Impulse CLI :在本地环境中安装 Edge Impulse 的命令行工具,用于与 Edge Impulse 平台进行交互。
3. 初始化项目 :在命令行中使用 Edge Impulse CLI 初始化一个新的项目,并将其与 Arduino 板连接。
4. 采集数据 :在 Edge Impulse 平台上创建不同的标签,如“Hey Arduino”和“背景噪音”等。然后对着麦克风说出唤醒词和产生背景噪音,通过 CLI 工具将音频数据上传到 Edge Impulse 平台。

特征提取与模型训练

Edge Impulse 平台会自动对采集到的音频数据进行特征提取和模型训练。
- 特征提取 :平台会使用一些先进的音频特征描述符,如梅尔频率倒谱系数(MFCC)等,将音频数据转换为特征向量。
- 模型训练 :选择合适的机器学习模型,如神经网络,对特征向量进行训练。平台会自动划分训练集和验证集,以评估模型的性能。

以下是一个简单的 mermaid 流程图,展示了数据采集和模型训练的流程:

graph LR
    A[连接硬件] --> B[安装 Edge Impulse CLI]
    B --> C[初始化项目]
    C --> D[采集数据]
    D --> E[上传数据到平台]
    E --> F[特征提取]
    F --> G[模型训练]
模型部署

训练好模型后,需要将其部署到 Arduino 板上。
1. 生成代码 :在 Edge Impulse 平台上生成适用于 Arduino 的 C++ 代码。
2. 下载代码 :将生成的代码下载到本地,并复制到 Arduino 项目文件夹中。
3. 上传代码 :使用 Arduino IDE 将代码上传到 Arduino 板。

以下是一个简单的 Arduino 代码示例,用于运行唤醒词检测模型:

#include <Arduino_LSM9DS1.h>
#include <EdgeImpulse.h>

// 包含 Edge Impulse 生成的代码
#include "edge-impulse-sdk/classifier/ei_run_classifier.h"

// 定义麦克风采样率等参数
#define SAMPLE_RATE 16000
#define SAMPLE_LENGTH 1000

// 音频缓冲区
float audio_buffer[SAMPLE_LENGTH];

void setup() {
  Serial.begin(115200);
  // 初始化麦克风等硬件
  if (!IMU.begin()) {
    Serial.println("Failed to initialize IMU!");
    while (1);
  }
}

void loop() {
  // 采集音频数据
  for (int i = 0; i < SAMPLE_LENGTH; i++) {
    audio_buffer[i] = analogRead(A0);
    delayMicroseconds(1000000 / SAMPLE_RATE);
  }

  // 运行模型进行预测
  ei_impulse_result_t result;
  EI_IMPULSE_ERROR res = run_classifier(audio_buffer, &result, false);
  if (res != EI_IMPULSE_OK) {
    Serial.println("Failed to run classifier!");
    return;
  }

  // 输出预测结果
  for (size_t ix = 0; ix < result.classification.count; ix++) {
    Serial.print(result.classification[ix].label);
    Serial.print(": ");
    Serial.println(result.classification[ix].value);
  }

  // 判断是否检测到唤醒词
  if (result.classification[0].value > 0.8) {
    Serial.println("Hey Arduino detected!");
    // 可以在这里添加唤醒后的操作,如点亮 LED 等
  }

  delay(100);
}
模型评估与优化

在模型部署到 Arduino 板后,需要对其进行评估和优化。
- 评估指标 :使用准确率、召回率、F1 值等指标来评估模型的性能。
- 优化方法 :如果模型性能不理想,可以尝试增加训练数据、调整特征提取参数或更换模型结构等方法进行优化。

以下是一个简单的表格,展示了不同评估指标的含义:
| 评估指标 | 含义 |
| ---- | ---- |
| 准确率 | 模型正确预测的样本数占总样本数的比例 |
| 召回率 | 模型正确预测的正样本数占实际正样本数的比例 |
| F1 值 | 准确率和召回率的调和平均数,综合衡量模型的性能 |

总结

时间序列分类和音频唤醒词检测在 TinyML 领域都有着重要的应用。时间序列分类通过手动标注数据、特征工程和构建分类链等步骤,能够对时间序列数据进行有效的分类,并可以部署到 Arduino 等嵌入式设备上。而音频唤醒词检测则需要合适的硬件支持,借助 Edge Impulse 等低代码平台进行数据采集、特征提取、模型训练和部署,实现设备的免提交互。

虽然这两种技术都有各自的挑战,但通过合理的方法和实践,能够取得较好的效果。在实际应用中,可以根据具体需求对模型进行进一步的优化和调整,以满足不同场景的要求。未来,随着 TinyML 技术的不断发展,时间序列分类和音频唤醒词检测有望在更多的领域得到应用和拓展。

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐