1. AI芯片概述:从GPU到NPU,AI芯片的演进之路与算力调度的重要性

大家好,我是你们这堂课的主讲人。在芯片行业摸爬滚打了十几年,从最早的DSP到后来的GPU,再到现在的NPU,我算是亲眼见证了AI芯片的整个演变过程。今天这第一课,咱们不聊虚的,直接切入正题:AI芯片到底是怎么从“通用”走向“专用”的?以及,为什么算力调度成了现在最头疼、也最值钱的问题。

1.1 为什么通用芯片“跑不动”AI了?

先问大家一个问题:2012年之前,深度学习还没火的时候,大家用什么做科学计算?答案是CPU和GPU。CPU是“万金油”,什么都能干,但并行度低。GPU呢,天生为图形渲染设计,有上千个核心,特别适合做矩阵乘法。

我记得2014年我刚接触第一个深度学习项目,用的是NVIDIA的K80。那时候大家觉得GPU真快,训练一个AlexNet从几天缩短到几小时。但很快问题就来了——GPU的架构是为图形渲染优化的,不是为神经网络优化的。

举个例子,GPU里有很多用于处理纹理和光照的硬件单元,这些在AI计算中完全用不上。说白了,你花大价钱买来的芯片,有30%的面积在“摸鱼”。

核心矛盾: AI计算的特点是“高并行、低精度、大吞吐”,而通用芯片的设计哲学是“高精度、低延迟、通用性”。这两者天然不匹配。

1.2 从GPU到NPU:一场“减负”运动

既然GPU有冗余,那能不能专门为AI设计一款芯片?这就是NPU(神经网络处理器)的由来。我参与过一款NPU的架构设计,当时团队争论最激烈的一个问题是:到底要不要保留FP32精度?

最后我们决定:砍掉FP64,只保留FP32和INT8。为什么?因为实际项目中我们发现,90%的推理任务用INT8就够了,精度损失不到1%。你想想看,INT8的乘法器面积只有FP32的1/4,功耗更是只有1/10。这笔账,怎么算都划算。

下面这张图是我自己画的,展示了从CPU到NPU的演进路径:

AI芯片演进路线图 CPU 通用计算 GPU 并行加速 FPGA 可重构 NPU 专用架构 各芯片特性对比 特性 CPU GPU NPU 并行度 低 高 极高 能效比 1x 3-5x 10-20x 精度支持 FP64/32 FP32/16 INT8/4 灵活性 极高 中等 低

1.3 NPU的核心架构:数据流才是王道

NPU和GPU最大的区别在哪?我个人的理解是:GPU是“计算中心”架构,NPU是“数据流”架构。

什么意思呢?GPU里,数据要从显存搬到寄存器,再搬到ALU,算完再存回去。每一步都有延迟。而NPU呢,它把计算单元和存储单元紧密耦合在一起,数据像流水一样流过计算阵列。

我参与过的一个项目里,我们设计了一个2D脉动阵列(Systolic Array)。每个PE(处理单元)只和相邻的PE通信。这样做的好处是:数据复用率极高,带宽需求大幅降低。

一个小技巧: 判断一个NPU架构好不好,看它的“数据复用率”就行。如果数据从DRAM到PE的搬运次数太多,那这个架构基本废了。我习惯用Roofline模型来评估,后面会详细讲。

1.4 算力调度:为什么它比算力本身更重要?

好,芯片有了,算力有了,然后呢?你发现实际跑起来,利用率只有30%。为什么?因为调度没做好。

我见过太多团队,花大价钱买了AI芯片,结果跑模型时,计算单元在空等数据,内存带宽成了瓶颈。说白了,算力是“纸面实力”,调度才是“实战能力”。

算力调度要解决三个核心问题:

  1. 任务切分: 一个大的神经网络,怎么切成小块,分配到不同的计算单元上?
  2. 数据搬运: 什么时候搬数据?搬多少?搬到哪里?
  3. 同步与依赖: 不同层之间有依赖关系,怎么保证数据一致性?

我曾经在一个项目中,因为调度策略没选好,导致芯片的利用率从理论上的80%掉到了实际的25%。后来我们改用了“流水线并行+数据并行”的混合策略,才把利用率拉回到65%。嗯,这里面的坑,后面几节课我会一个一个拆开来讲。

1.5 一个简单的调度示例

为了让大家有个直观感受,我写一个伪代码,展示最基本的调度逻辑:

// 假设有4个PE,处理一个4层网络
// 调度策略:层间流水线,层内数据并行

void schedule_network() {
    // 第1步:将网络切分为4个stage
    stage[0] = conv1 + relu1;   // PE0
    stage[1] = pool1 + conv2;   // PE1
    stage[2] = relu2 + fc1;     // PE2
    stage[3] = fc2 + softmax;   // PE3
    
    // 第2步:启动流水线
    for (int batch = 0; batch < BATCH_SIZE; batch++) {
        // 每个PE处理自己的stage
        pe_run(0, stage[0], input[batch]);
        pe_run(1, stage[1], pe0_output);
        pe_run(2, stage[2], pe1_output);
        pe_run(3, stage[3], pe2_output);
        
        // 等待所有PE完成
        sync_all();
    }
}
注意: 上面的代码只是演示逻辑。实际项目中,你还要考虑负载均衡、内存冲突、DMA传输重叠等问题。我曾经因为没处理好DMA和计算的overlap,导致芯片利用率直接腰斩。

1.6 本章小结

好了,第一课的内容就到这里。我们回顾一下:

  • GPU为什么不适合AI?因为架构冗余,能效比低。
  • NPU怎么解决?通过专用数据流架构,砍掉无用功能,提升能效。
  • 算力调度为什么重要?因为再强的芯片,调度不好也是白搭。

下一节课,我会带大家深入算力调度的核心——任务切分策略。到时候我会拿一个真实的Transformer模型来拆解,看看怎么把一个大模型切成小块,让NPU吃得饱、跑得快。

想要更多资料,联系可可