Dense / 全连接层 / GEMM 解决的是"把前面提取出来的局部特征综合起来,做最终判断"的问题。
卷积层:发现局部特征,比如边缘、纹理、局部形状
Flatten:把这些特征摊平
Dense:把所有特征放在一起综合分析,最后输出分类结果
比如前面卷积已经知道:
左上角像眼睛
中间像鼻子
下方像嘴巴
那 Dense 层做的就是:
把这些零散特征拼起来,判断这是不是一张脸
Dense / 全连接层的作用,就是把前面提取到的全部特征做全局整合,输出最终结果。
所以这几个层你现在可以这样记:
-
Conv:提局部特征
-
ReLU:加非线性
-
Flatten:摊平数据
-
Dense:综合全局特征做判断
这套链条,你总算开始摸到 CNN 的骨架了。
cpp
/* Dense1: 960 → 48 */
float input[960]; // Flatten 的输出
float output[48];
float weight[48][960]; // 权重矩阵(46,080 个参数)
float bias[48];
for (int j = 0; j < 48; j++) { // 48 个输出神经元
float sum = bias[j];
for (int i = 0; i < 960; i++) { // 与 960 个输入全连接
sum += weight[j][i] * input[i]; // ← 1 次 MAC
}
output[j] = sum;
}
// Dense1 总计: 960 × 48 = 46,080 次 MAC
/* Dense2: 48 → 4 */
float input2[48]; // Dense1+ReLU 的输出
float output2[4]; // 最终输出 [Fx, Fy, Fz, Fn]
float weight2[4][48];
float bias2[4];
for (int j = 0; j < 4; j++) {
float sum = bias2[j];
for (int i = 0; i < 48; i++) {
sum += weight2[j][i] * input2[i];
}
output2[j] = sum; // → 接 Sigmoid 后变成 [0,1] 范围
}
// Dense2 总计: 48 × 4 = 192 次 MAC
权重和 MACs 占比
权重占比:
Conv1-3 合计: 66 KB(26.8%)
Dense1: 180 KB(~73%) ← 绝对大头
Dense2: 0.8 KB(<1%)
总计: 247 KB
MACs 占比:
Conv1-3 合计: 725,760(93.5%) ← 绝对大头
Dense1: 46,080(5.9%)
Dense2: 192(<0.1%)
总计: 776,032
- 想减权重/Flash → 压缩 Dense1(比如 960→24 只用 90KB)
- 想减计算量/推理时间 → 优化 Conv 层(比如 DepthwiseConv)