尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

百度AI异构计算工程师笔试题解析:从体系结构到性能优化

百度AI异构计算工程师笔试题解析:从体系结构到性能优化 这阵子好几个学弟学妹在准备校招跑来问我百度2018年那批AI异构计算工程师的笔试题该怎么看。说实话这套题放在今天看依然很能打它不像普通软件岗那样考刷题套路而是实打实地在筛“懂硬件、懂并行、懂AI计算”的人。当年我做完这套题的最大感受是它是在用考题画一份AI异构计算工程师的能力地图从体系结构、并行编程模型到AI计算场景下的访存与算子优化再到系统调度和工程落地全都覆盖到了。这篇文章我不想只贴题目答案而是把整套题的考察逻辑、核心知识点、答题思路和准备方法拆开揉碎讲一遍。无论你是正在准备校招的应届生还是想从纯软件转异构计算方向的工程师这份梳理应该都能帮你少走不少弯路。1. 这套笔试题到底在考什么异构计算工程师的能力画像1.1 从职位JD反推考点为什么百度要给AI异构计算工程师出这些题先聊一个很多人忽略的问题一套笔试题的设计背后一定是对应岗位的能力模型。百度这个岗位标题里有两个关键词一个是“AI”一个是“异构计算”。前者决定了计算场景后者决定了技术栈。AI场景下的异构计算跟传统HPC高性能计算里的异构计算虽然共享很多底层技术但侧重点不太一样。AI异构计算工程师日常面对的问题通常有三个第一把训练或推理算子高效地映射到GPU、FPGA、ASIC上第二在有限的显存和带宽约束下把访存和计算比例调到最优第三在集群和单卡两个层面做性能调优同时兼顾易用性和可维护性。这意味着笔试题必须覆盖三个层次底层硬件原理比如GPU线程调度、内存层级、缓存一致性、中间编程模型CUDA、OpenCL的线程组织与同步机制、上层AI计算负载特征卷积、矩阵乘、注意力机制的访存密度。2018年的试卷结构也确实是按这个逻辑铺开的既有概念辨析也有计算推导还有综合设计题少说也有四五种题型。1.2 能力模型与题目映射把考点分成四层我当时把整套题的考点归纳成了四个层级后来准备面试时发现这个框架依然好用能力层级考察内容典型题目方向体系结构层CPU/GPU/FPGA/ASIC的原理差异访存层级缓存一致性PCIe/总线带宽计算、加速比推导、缓存命中率影响编程模型层CUDA/OpenCL线程模型、并行模式、同步机制、内存模型线程组织、死锁/竞态分析、并行化改写算法与优化层矩阵乘、卷积、规约、扫描等算子的并行化与访存优化算法复杂度、tiling、向量化、计算访存比系统工程层任务调度、流水线、负载均衡、多设备协同系统设计题、多卡训练架构题这套框架不只是用来拆题也是一个学习路线图。你做题时如果发现自己某一层特别吃力基本就能定位到知识短板了。2. 核心考点拆解体系结构与内存模型2.1 CPU/GPU/FPGA/ASIC的差异为什么AI计算常常选GPU而不是CPU笔试题里几乎必考的一个点是CPU和GPU的架构差异以及为什么深度学习训练偏爱GPU。这道题表面上是送分题但想拿高分必须答到指令流和数据流层面不能只说“GPU核心多”。CPU是典型的延迟优化设计核心数量少但单核性能强拥有大规模乱序执行、分支预测、超深流水线和大容量缓存目的是让单条线程跑得更快。GPU则是吞吐量优化设计核心多、频率相对低、缓存小但上下文切换极快通过大量线程并行来隐藏访存延迟。两者的本质区别在于CPU用复杂的控制逻辑换取低延迟GPU用简单的控制逻辑和超多线程换取高吞吐。做题时要注意一个细节GPU的线程调度采用SIMT单指令多线程模型调度单位是warpNVIDIA GPU上一个warp通常是32个线程。它的特点是一个warp内的所有线程在同一个周期执行同一条指令。如果遇到分支发散同一warp内不同线程走了不同分支这些路径会被串行执行。这个知识点经常用来出判断题问你“GPU的每个线程都是独立执行指令、互不干扰”这其实是错的。2.2 访存层级与带宽为什么带宽经常成为瓶颈AI异构计算里有一句话叫“凡是能算的问题最终都卡在访存上”。这个观点在笔试里会以多种方式出现比如让你算理论峰值和实际算力之间的差距或者问为什么GPU的利用率上不去。你需要记住一条关键规律现代处理器的计算能力增长速度远快于内存带宽的增长速度。于是计算密度越高的算子越容易被打满算力而元素级操作比如逐元素乘法、ReLU激活则几乎都是带宽瓶颈。这类算子的理论耗时瓶颈不在FLOPS每秒浮点运算次数而在数据搬运量。笔试中常见的一道计算题是这么出的假设一个矩阵A大小为MN一个矩阵B大小为NK要在GPU上做矩阵乘法。已知GPU的峰值算力为P TFLOPS显存带宽为B GB/s让你估算最小耗时。很多人上来就按FLOPs除以峰值算力来算这就是个坑。实际要考虑分块tiling之后每个block内数据复用情况还有输入矩阵需要从全局内存搬到共享内存的开销。只要算力没有被完全打满最终耗时往往由数据搬运主导。我建议复习时把“算力上限”和“带宽上限”这两个公式刻在脑子里计算下限 总浮点运算量 / 峰值算力访存下限 总字节搬运量 / 内存带宽。实际系统性能只能在这两个值之间取较大者再乘以一个效率系数。任何声称能超过这个下限的分析都是没有物理依据的。2.3 缓存一致性、Pinned Memory与PCIe传输隐含的工程题考点2018年的试卷里还有一类题不直接考缓存一致性名字但会用具体编程场景来考察比如cudaMemcpy的耗时分析、零拷贝zero-copy内存的使用条件。这里有个技术点要理清楚主机端内存默认是pageable memoryGPU访问它需要操作系统先把数据锁页并建立DMA映射。所以CUDA编程里有一种专门的内存叫pinned memory锁页内存它能显著提升Host到Device的传输带宽。但代价是锁页内存会占用物理内存且不能被换页用多了可能影响系统整体性能。笔试里如果给你一张表格列了普通内存和pinned memory的传输时间差让你解释原因答案一定要落到DMA和页映射上不要笼统说“更快”。多设备场景下还有一种常考的点同一台机器上两张GPU之间通信不经过CPU主存走的是NVLink或PCIe P2P。笔试会问你为什么训练时数据并行要分成“梯度聚合通信”和“参数更新”两个阶段这背后正是考虑到跨设备通信带宽有限需要尽量压缩通信频率和通信量。3. 编程模型与并行机制CUDA/OpenCL背后的思想3.1 一个程序怎么从CPU跑到GPUhost-device执行模型异构编程模型的起点就是host-device这种主从执行模型。CPU作为host负责逻辑控制、数据准备和任务下发GPU作为device负责大规模并行计算。笔试里常见的基础题是问你kernel内核函数的启动方式以及为什么kernel启动是异步的。这里有一个容易踩坑的细节kernel启动的异步性意味着如果你在kernel执行完之前就在host端读取device内存里的结果会拿到错误数据。面试官特别喜欢把这个点包装成一个“程序崩溃/结果不对”的场景题让你排查。答案是必须显式同步或者用cudaMemcpy这种隐式同步操作。这个“隐式同步”的概念值得好好理解cudaMemcpy本身是同步的它从设备拷贝数据到主机时会等待之前的kernel完成。跟执行模型相伴的另一个高频考点是线程层次结构。CUDA里线程被组织成grid网格、block线程块、thread线程三级block内的线程可以通过共享内存通信和同步block之间则不行。这个设计不是拍脑袋出来的它对应的是GPU硬件的执行单元划分一个block会被调度到一个SM流式多处理器上block内线程的同步才可能在硬件上高效实现。题目里如果让你判断“不同block内的线程可以通过__syncthreads同步”这肯定是错的。3.2 并行性从哪来数据并行、任务并行与流水线笔试的主观题里经常有一道“请将某个算法并行化”。做这类题第一步不是看能不能拆线程而是分析算法里有哪些可并行性有哪些不可并行的依赖关系。可并行性通常有三大类数据并行同一操作作用在不同数据上互不依赖最容易规模化也是GPU最擅长处理的。任务并行不同功能模块同时执行比如一个网络层做卷积另一个层做池化两者数据独立时就可以并行。流水线并行把一个大任务拆成多个阶段不同阶段之间按数据流传递适用于层间高度耦合但层内可切分的场景。做题时给你一个for循环你要能看出每次迭代之间是否有写-读依赖。如果没有依赖直接改成并行循环如果有依赖就要考虑用原子操作、局部私有副本加最终合并或者改变数据布局。这几个方案对应了不同的性能特性笔试里经常让你比较优劣。3.3 加速比的计算Amdahl定律的实战用法另一类计算题跟Amdahl定律有关。题目一般会给一个场景某个算法中80%的部分可以并行化20%的部分必须是串行的并行部分在GPU上理论上能做到无限加速。问最大能获得的加速比是多少。套公式最大加速比 1 / ((1 - P) P / N)其中P是可并行比例N是并行度。当N趋向无穷大时加速比趋近于1 / (1 - P)。题目里P0.8时最高加速比只有5倍。这个结果很反直觉很多人第一次算都觉得“80%能并行已经很高了怎么才加速5倍”但这就是串行部分的硬约束。做题时记得先算不可并行比例再讨论并行度趋向无穷的极限。有经验的工程师还会补充一点Amdahl定律给出的是上限但现实中还有一个Gustafson定律强调规模可扩展性说的是随着问题规模增大可并行部分占比会越来越大加速比可以更乐观。笔试里如果能写出Amdahl定律后再补一句“在固定问题规模下成立若问题规模随并行资源增长更适用Gustafson模型”会显得你理解得比较立体。4. 性能优化与AI计算场景的实战分析4.1 矩阵乘法这道“老熟人”为什么它总是被拿来当考题AI异构计算笔试里矩阵乘法GEMM出现的频率高到可以单独立一个专题。原因很简单全连接层、卷积、注意力机制的核心运算本质上都是矩阵乘它是AI计算的最小分母也是性能优化每招都能用上的完美载体。最简单的矩阵乘实现就是三层循环i、j、k各一层。这个实现在CPU上可能还能跑一跑挪到GPU上基本是灾难因为全局内存访问次数太多了。每计算一个输出元素就要读取一整行A和一整列B完全没有利用数据的相邻性。优化思路有一个经典路线先做block级分块让一个block负责一个输出子矩阵再把块内需要用到的A和B小片加载到共享内存把重复的全局内存访问变成共享内存访问最后在寄存器级别再做一次微分块减少对共享内存的重复读取。这套方法从CUDA一开始就在用到现在依然是几乎所有AI算子库比如cuBLAS、CUTLASS的基础。笔试里如果给出一个朴素的矩阵乘实现让你优化你就按这个阶梯思路来答基本能覆盖大部分得分点。4.2 卷积计算的访存瓶颈im2col、Winograd与算子融合2018年时候AI异构计算笔试已经开始考卷积的加速策略了。卷积的实现方式有好几种直接卷积、im2col加矩阵乘、Winograd、FFT。笔试里一般不会让你手写所有实现但会出题考察你对它们特点和适用场景的理解。im2col的思路是把卷积操作转换成一个大矩阵乘法借助已经高度优化的GEMM库来跑。它的优点是简单、通用、硬件利用率高缺点是会产生大量数据重复导致显存占用和访存开销暴涨。Winograd则通过变换减少乘法次数在卷积核尺寸较小时比如3x3能获得明显的加速比但它对数据的额外transform也有开销且数值精度可能受影响。这两者在今天依然是推理引擎里的核心选项。比如NVIDIA TensorRT里就集成了多种卷积tactic会自动根据输入尺寸、精度和硬件型号挑选最优实现。笔试中如果给你一组数据让你分析某卷积层该用im2col还是Winograd你的分析框架应该是先看卷积核尺寸和stride再看输入输出通道数最后看有没有可用库和硬件算子。一般结论是小卷积核、深层特征图适合Winograd大卷积核、随机形状适合im2col或直接卷积。4.3 规约、扫描与原子操作并发编程里的那些坑除了矩阵乘和卷积笔试里还有一类高频题叫“让结构化的并行算法跑起来”典型代表就是规约reduction和扫描scan。规约就是把一个数组求和/最大值/最小值聚合成一个标量扫描则是计算前缀和。这两个算法在softmax、BatchNorm、注意力分数归一化里都会用到。规约题最经典的考点是“并发求和要怎么保证正确性”。新手最容易犯的错误是让所有线程直接往同一个全局变量里累加然后发现结果偶尔正确偶尔错误。原因是多个线程同时读写同一地址发生了数据竞争。解决方法有两种思路一是每个线程算完自己的部分后先存到共享内存再做树形规约二是用原子操作。这里要强调一下原子操作和共享内存树形规约的性能差异。原子操作简单但冲突开销大尤其在并发度高时相当于把并行又串行化了。共享内存树形规约则是利用同步机制把多线程合拢成层级合并能更充分利用并行资源。笔试时如果让你设计规约kernel比较好的答案是先每个thread处理stride个元素得到局部结果再用block内共享内存树形归约最后再用原子操作或二次kernel把各个block的结果加起来。这个方案既减少了原子操作次数又控制了同步粒度。4.4 AI计算场景里的经典考察CNN训练与推理的算子特征整套卷子的“区分度大户”通常是一道AI场景综合题比如让你分析CNN训练和推理在异构设备上的性能差异。这类题需要你综合前面所有知识点来答。训练过程的特征是两个阶段前向传播和反向传播。反向传播需要保存中间激活值以便计算梯度所以对显存的需求远高于纯推理。训练还涉及梯度更新每一步都会更新权重权重如果是多GPU数据并行还涉及all-reduce通信。推理的特征则正好相反没有反向计算激活值可以边算边丢显存占用小。更重要的是推理对时延有严格要求经常做批处理batch时只能取很小的batch size因为用户请求是实时到达的。这导致推理时想要打满GPU算力更难反而是访存和kernel launch开销会在总耗时里占大头。笔试里如果问“为什么推理时GPU利用率低”你要答出几个因素batch size小导致并行度不足、单条样本时延敏感使kernel启动开销占比大、框架运行时和调度器本身有额外开销。多答一条就多一个得分点。5. 笔试答题策略与常见坑站在出题人角度想问题5.1 时间分配与答题顺序这套题的题量不小既有一批快速判断的概念题也有需要静心推导的计算题还有开放性的设计题。我的经验是先把会做的、短平快的题拿稳再攻需要推导的题最后用剩余时间写综合设计题。具体来说我建议的顺序是第一步扫一遍所有选择题和判断题这类题通常覆盖基础知识能答就答不要恋战。第二步做计算推导题比如加速比、访存带宽、kernel执行时间该类题目分值稳、容易拿。第三步做优化和设计题这类题没有严格唯一答案关键看你有没有完整的分析框架。还有一个小小的策略如果一道题让你“分析原因”或“给出方案”即使没有十足把握也要把分析框架写出来。比如问为什么某程序GPU加速比不理想哪怕不知道具体答案你写上“可能原因包括数据搬运开销过大、kernel启动次数过多、线程配置不合理”都会部分得分。出题人看的不只是结果更是思路。5.2 常见“送命题”与避坑清单结合我做题和辅导别人做这套题的经验以下这些错误出现的频率非常高列成清单供你复盘时对照忽略访存带宽把所有计算时间都按峰值算力估算。这是被问最多、错也最多的点。把GPU线程模型与CPU线程模型混为一谈。GPU线程极轻量且硬件调度CPU线程由操作系统调度且切换开销大。不清楚同步粒度。block内的__syncthreads()只同步一个block内的线程不是全局同步。以为kernel启动是同步的导致在kernel完成前就去读结果。计算并行化时忽略数据依赖直接把有依赖的循环并行化答案看似合理实际是错的。把CPU和GPU之间的传输时间忽略掉。实际上PCIe传输在中小规模数据下经常是整个任务的瓶颈。卷积题只知道im2col而不知道Winograd/算子融合答题缺乏层次感。5.3 结合项目经验答题让笔试答案“活”起来还有一类失分点不在知识本身而在表达方式。这套笔试题里的设计题往往不是简单考你知道某个概念而是让你用工程经验去解决问题。比如有一类题会给出一个实际场景某模型训练速度慢GPU利用率只有30%让你给出诊断和优化方案。正确答案不应该只列优化技术而是按“先分析瓶颈再对症下药”的流程来答先用profiler查看时间分布确认瓶颈在kernel计算、数据加载、还是通信同步再针对不同瓶颈提出不同策略。如果瓶颈是数据加载那优化方向是使用DataLoader并行、预取、pinned memory如果瓶颈是小kernel启动过多那考虑算子融合或CUDA Graph如果瓶颈是计算密度不够那考虑调大batch或重排算子。这种答题方式一方面能展示你用过性能分析工具另一方面也能证明你具备系统层面的抽象能力而不仅仅是知道零散知识点。想培养这种能力平时在项目里不要只写“能跑”的代码要多用ncu、nsys、perf这类工具看看程序的时间到底花在哪慢慢就会形成直觉。6. 备考路线与学习建议从校招笔试题到真实工程能力6.1 必备的图书、文档与实验平台如果你现在离笔试还有一两个月我认为最高效的路线是“教材搭骨架、文档补细节、实验出真知”。教材方面首推《Computer Architecture: A Quantitative Approach》计算机体系结构量化研究方法这本书关于内存层级和并行计算模型的内容非常扎实并行编程方面可以看《CUDA C Programming Guide》和黄铠的《多处理器编程的艺术》部分章节后者对并发控制讲得特别清楚。《CUDA C Programming Guide》是NVIDIA官方免费文档里面线程层次、内存层次、同步机制讲得非常细我建议直接把相关章节读两遍。如果想做题练手CUDA官方也提供很多GPU Computing Samples比如矩阵乘、reduce、scan这些经典样例每个样例都值得跑一遍然后尝试修改。跑环境和调kernel不要求你有顶级的显卡NVIDIA官网的免费云环境或者旧款显卡都够用重点是理解结构而不是追求算力。6.2 十个值得亲手实现的小实验光看不练等于白学这里列十个可以循序渐进的实验你在准备笔试的阶段如果能亲手完成其中七八个整套题的知识点基本就全覆盖了实现最朴素的vector add kernel对比CPU和GPU耗时。给vector add改成使用共享内存分块观察对耗时的影响。实现一个block内多线程规约求和确保结果正确再用ncu看bank conflict。用原子操作算全局求和对比原子操作版和树形版的性能。实现一个分块矩阵乘法从朴素版开始一步步加tiling和register reuse。用shared memory实现一个简单的卷积算子对比直接卷积的性能。实现一个softmax算子计算最大值和总和时都用规约。用pinned memory复制大数据对比与pageable memory的带宽差异。写一个简单的算子融合把卷积后面接的ReLU融合进卷积kernel。用NVML或nvidia-smi监测训练程序观察功率、显存和SM占用率的变化。6.3 从2018到当下异构计算工程师的考点依然在但场景更丰富最后想说一个备考心态上的事。很多人看到2018年的题目会觉得“过时了”其实不是。异构计算的核心硬件原理和优化方法论没有变但AI应用场景确实丰富了很多。当年的考题里还没有Transformer训练优化、MoE负载调度、Chiplet集群运行这些话题而这些年它们逐渐成了面试官的新宠。不过你回头对照会发现就算题目变化了底层能力要求还是那几条你能不能在并行计算模型里写出高效且正确的kernel能不能看清访存和计算的矛盾能不能在分布式环境下做通信和计算的重叠优化。这恰好就是那套2018笔试最核心的考察思路。所以备考时别只盯着具体题目的答案而是把考点当成能力坐标逐个补齐。按照我个人经验复习这套题最佳的方式不是刷题而是“做一个算子分析它的性能再回头改进它”的循环。每走完一个循环你就能更踏实一点。校招笔试只是门槛真正区分你未来能走多远的是你有没有形成“系统层面看性能”的直觉。这套题给得很好的一个提醒就是别只当调包侠把底层算清楚你才真正算这门领域里入了门。
返回列表