SMARTWATCH 学习手册有 C 基础 · 嵌入式从零开始
支线四 / 数据、训练与部署 / 06

为什么要让一个小窗口沿波形移动

全连接小模型跑通后,再看动作的局部变化怎样被重复利用。从一次小卷积手算起,逐步认识一维卷积、通道和池化。

接续上一篇:亲手训练第一个小模型

1 · 一个局部变化,可能出现在不同时间

走路中一个重复的加速度变化可能出现在窗口开头,也可能出现在后面。展平模型给每个位置不同权重,学习同一种局部模式可能需要重复安排参数。一维卷积让一个小计算规则沿时间轴复用。

普通 Python · 对照深度学习中常用的滑动相关计算

signal = [1, 2, 3, 2, 1]
kernel = [1, 0, -1]
result = []
for start in range(3):
    result.append(sum(signal[start+i]*kernel[i] for i in range(3)))
print(result)

每次只看相邻三点,乘以三个权重后求和,再往后移动。例子不是整套动作识别,只展示局部计算。框架通常把这个相关运算也叫卷积,不在入门时混入翻核的符号差异。

2 · 多个输入通道怎样共同参与

六轴输入的每个时间位置都有六个数,一个卷积核会在自己的时间范围内组合多个通道。使用多个卷积核,就得到多条不同的输出特征。它们的物理含义由训练形成,不能未经检查就把某一条命名为“走路特征”。

六输入通道,八输出通道,局部长度五

nn.Conv1d(6, 8, kernel_size=5, padding=2)

padding 在边界补值以控制长度,stride 控制每次移动距离。它们与训练数据的滑窗步长是不同层次:一个在网络内部移动,一个决定原始窗口何时重新取样。

3 · 池化和最后分类做什么

教学小卷积模型

model = nn.Sequential(
    nn.Conv1d(6, 8, 5, padding=2),
    nn.ReLU(),
    nn.AdaptiveAvgPool1d(1),
    nn.Flatten(),
    nn.Linear(8, classes),
)

卷积后仍有时间长度,平均池化把每条输出特征在时间上汇总成一个数,最后用这些数分类。这里汇总得到八个数,可以先把它们看成一份较紧凑的窗口描述。更复杂网络的特征维度可以不同。

4 · 用同一份划分比较两个小模型

和全连接实验使用相同人工数据规则;真实比较改用相同真实记录

python train_activity.py --demo --network cnn --out practice_cnn --epochs 8 --export

比较参数数量、验证结果和运行时间。卷积不保证在所有数据上更好;数据太少、标签错误或不合适的结构都可能导致表现下降。人工数据只检验计算流程,最终选择仍由独立真实记录决定。

5 · 接到项目的中间特征

当前活动网络提取 128 维中间特征,供原型分类使用。它是网络某个位置的输出,不是原始六轴简单拼接后的前 128 个数。重新导出网络后,节点编号、缓冲位置与数值分布都可能改变,必须重新核对。

动手观察

手算上面的三个局部输出;把卷积核改成 [1,1,1],描述它现在偏向计算什么。再检查框架中输入、卷积输出、池化输出的形状。

资料与代码