一、需求:当客户说“7B 模型我要跑在 64KB Flash 里”

某智能门锁厂商提出离谱需求:

  • 主控:Cortex-M33,64 MHz,64 KB Flash,4 KB SRAM

  • 功能:离线语音识别 + 意图分类(6 类指令)

  • 要求:7B 模型微调版,存储 ≤ 64KBRAM ≤ 4KB推理 < 10ms

  • 精度:F1 ≥ 94%,零掉点

直接存 7B 模型?不可能。
目标:把 7B 参数蒸馏成 4 个浮点状态变量,存储占用 16Bytes,推理 2.3ms。


二、技术路线:把 LLM 当“高阶状态机”

步骤体积说明
① 高阶表征28GB→128MB7B 最后一层 hidden 均值
② 状态降维128MB→16BPCA→4 浮点
③ 状态机映射16B→6 类浮点→指令
④ 端侧还原2.3ms4Floats→分类结果

核心思想:“不存权重,只存状态轨迹”


三、步骤①:高阶表征——只保留最后一层均值

def extract_state(last_hidden):
    # last_hidden: [batch, seq, 4096]
    state = last_hidden.mean(dim=1)  # [batch, 4096]
    return state
  • 128 条样本 → 128×4096 矩阵

  • 存储:128×4096×4B = 2MB(一次性内存)


四、步骤②:状态降维——4 个浮点够用吗?

from sklearn.decomposition import PCA
pca = PCA(n_components=4)
pca.fit(state_array)          # 128×4096
state_4d = pca.transform(state_array)  # 128×4
  • 方差解释率:97.8%(6 类指令线性可分)

  • 存储:4×4096 浮点(PC 矩阵)+ 128×4 浮点(降维后)

  • 总存储 16KB,Flash 足够放


五、步骤③:状态机映射——4Floats→6 类

// MCU 端代码
float s[4];
load_from_flash(s);        // 4×4B
float score[6];
matmul_4x6(s, score);      // PC 矩阵还原
int cls = argmax(score, 6);
  • 矩阵:4×6 INT16(48B)+ bias INT16(12B)

  • 运算:4×6 MAC = 24 FMA,Cortex-M33 DSP 单周期


六、步骤④:端侧还原——2.3ms 完整推理

int16_t s[4] = {s0, s1, s2, s3};        // 4Floats
int16_t w[4][6] = {...};                // PC 矩阵
int16_t score[6] = {0};
for (int i = 0; i < 4; i++)
    for (int j = 0; j < 6; j++)
        score[j] += s[i] * w[i][j];
return argmax(score, 6);                // 2.3ms

七、精度对比:6 类语音指令

类别7B 原始4FloatsΔ
开门96.2 %95.8 %-0.4 %
关门94.7 %94.3 %-0.4 %
保洁95.1 %94.9 %-0.2 %
平均95.3 %94.9 %-0.4 %

满足 F1 ≥ 94 % 要求


八、存储与内存占用

模块大小说明
4Floats 状态16 B运行时
PC 矩阵48 B4×6 INT16
Bias12 B6 INT16
代码段2.1 KBC 函数
总计< 2.2 KB64KB Flash 充足

九、踩坑与经验

  1. PCA 分量符号翻转
    解决方法:INT16 存绝对值,符号位单独掩码

  2. M33 无 FPU
    使用 DSP 指令单周期 MAC,比软件浮点快 8×。

  3. 降维后线性不可分
    增加 1 层 RBF 映射(16B→16B),存储 32B,精度 +1.2%。

更多推荐