
2018年百度校招AI异构计算工程师的笔试题第二批这个话题放在今天看依然很有嚼头。当时那场笔试结束后不少应届生在网上讨论题目难度吐槽“CPU、GPU、缓存、CUDA全覆盖”也有人感慨“面试造火箭工作拧螺丝”。但说句实在话这批题目考察的东西恰恰是今天AI基础设施方向最值钱的底层能力体系结构、并行编程、性能优化和系统设计思维。这篇文章不是去复盘某一道具体题目而是把这类笔试背后的考察逻辑、核心知识体系、做题思路以及这份岗位在真实工程中的样子完整拆开揉碎讲一遍。无论你是准备校招、想转AI底层加速方向还是单纯对“异构计算”这四个字好奇这篇内容应该都能帮你在脑子里搭起一张地图。1. 这次笔试到底在考什么岗位画像与出题逻辑1.1 AI异构计算工程师是做什么的先别急着刷题你得先搞清楚这个岗位的存在意义。所谓异构计算核心就是让不同架构的处理器各司其职CPU负责复杂逻辑和任务调度GPU、FPGA、ASIC这类加速器负责大规模并行计算。放在AI场景里就是你在训练一个深度模型时数据预处理、图调度、控制流逻辑跑在CPU上而矩阵乘法、卷积这类计算密集型的算子要放到GPU上跑如果更激进一点还会用FPGA做推理加速、用AI芯片做端侧部署。这个岗位不是“调包侠”而是要深入到框架底层写算子、优化内存、调内核、分析性能瓶颈。说白了你得同时懂三样东西计算机体系结构、并行编程模型、深度学习框架的运行机制。笔试就是围绕这三样东西设计的。1.2 出题逻辑为什么题目长这样从公司的角度看校招笔试要在短时间内筛掉大量候选人题目必须覆盖各段位的人。基础题考你有没有计算机系统功底进阶题考你有没有并行编程直觉附加题则看你面对开放问题有没有系统化思考能力。第二批的“批”字也有讲究。校招笔试分批次通常是因为报名量太大、考场安排不过来也可能是因为题库里有多个版本的试卷需要分散使用。从概率上讲第二批的题目会和第一批有知识点重叠但具体题目会换花样。所以准备这类笔试押题是没用的老老实实把底层原理吃透才是正路。我还注意到一个细节这类岗位的笔试很少考纯深度学习理论比如反向传播推导、损失函数调参反而更爱考C多线程、CUDA编程、访存优化、加速比计算。原因很简单AI异构计算工程师的日常不是做模型效果而是让模型跑得更快工程属性远大于算法属性。1.3 2018年前后的技术背景这批题为什么这么出聊这一节是为了让你理解出题方向的来源。2018年是深度学习框架百家争鸣的时期TensorFlow 1.x如日中天PyTorch正在快速崛起各家大厂都在自研训练框架和推理引擎。而GPU编程人才严重稀缺大部分算法工程师只会在Python层调用框架对底层kernel一无所知。这种情况下公司招聘AI异构计算工程师本质上是在抢“能写高性能CUDA代码”的人。笔试自然就侧重于你对GPU硬件了解多少、你写过多少并行程序、你能不能发现性能瓶颈。那几年也是AI芯片创业潮的高峰做AI加速器的公司遍地开花但做芯片的人可以不懂框架做框架加速的人必须懂硬件这种人才缺口直接决定了考题重心。2. 硬核考点体系结构与并行计算原理2.1 从CPU到GPU理解两种设计哲学笔试中反复出现的题目本质上都在考察你是否理解CPU和GPU的设计差异。CPU是“延迟优化”的产物它把大量晶体管用在分支预测、乱序执行、大容量缓存上目的是让单个程序跑得更快。GPU则是“吞吐优化”的产物它用大量简单计算核心堆出并行度单个线程很弱但一万个线程一起跑就能碾压CPU。一个经典类比是CPU就像几个博士生每个人都能解复杂数学题GPU像一万个小学生每个人只会做加减法但你把一万个小学生组织起来同时做一万道加减法速度就上来了。AI计算恰恰是“一万道加减法”的集合体矩阵乘法里每个输出点的计算彼此独立天然适合GPU。这类题目经常是选择题或简答题比如“GPU为什么不适合跑串行任务”“CPI、吞吐量、延迟之间什么关系”。回答的关键不在于背概念而在于你脑子里能浮现出这两种芯片的微架构图。2.2 Amdahl定律与并行效率笔试必考的加速比计算Amdahl定律是我反复强调必考的一个点因为它太适合出成计算题了。公式很简单加速比 ( S 1 / ((1 - P) P / N) )其中P是可并行部分占比N是处理器数量。但很多人算题没问题却忽略了这个公式背后的工程含义即使你有无限多核心加速比的上限也只有 ( 1 / (1 - P) )。举个例子一个程序中20%的代码无法并行哪怕你用1000个核心去跑最大加速比也只有 ( 1 / 0.2 5 ) 倍。这在工程里太常见了——你优化一个kernel优化得飞起结果数据加载、预处理、CPU和GPU之间的拷贝是串行的整体性能提升就被卡住了。笔试中这类题往往会给一串数字让你算加速比或者反过来问你“要达到某个加速比需要多少核心”。建议你把Amdahl定律和Gustafson定律都推一遍理解两种观察角度固定问题规模 vs 固定时间。前者是强扩展后者是弱扩展在性能分析里都有应用场景。2.3 存储层次与访存局部性性能题的核心异构计算工程师日常做的最多的事就是“搬数据”所以存储体系一定是笔试重灾区。从CPU角度看你需要理解L1/L2/L3缓存、寄存器、主存的关系从GPU角度看你要理解寄存器文件、共享内存、L2缓存、全局内存、常量内存、纹理内存这一整套层次。笔试常常考察的一个概念是局部性。时间局部性是指刚访问过的数据很快还会被访问空间局部性是指访问了一个地址后周围的地址也很快会被访问。在GPU编程里空间局部性对应的是“合并访问”coalesced memory access也就是一个warp里的32个线程最好访问连续的内存地址这样硬件能把这些访问合并成一次或少数几次内存事务。这一块我强烈建议你用实际数据去感受。你在CUDA里写一个数组求和如果线程按顺序访问连续地址带宽利用率可能达到80%以上如果每个线程跳着访问带宽可能直接掉到20%。笔试里不会让你跑实验但描述这种场景的判断题很常见能不能一眼看出“这里访存不连续”就是高分和低分的分水岭。2.4 笔试常考的并行模式map、reduce、scan、stencil我在带新人的时候发现很多人刷了不少CUDA题但遇到新问题还是懵因为他们没有抽象出并行模式。校招笔试其实特别偏爱四类模式Map映射每个输入对应一个输出互不依赖直接并行比如逐元素加和、图像像素调整。Reduce归约把一组数据规约为一个值比如求和、求最大值需要树形划分和线程同步。Scan扫描又叫前缀和每个输出是前面所有输入的累计结果比如 ( y[i] y[i-1] x[i] )这个在排序、稀疏矩阵处理里很常用。Stencil模板每个输出依赖周围邻居的输入典型代表是图像卷积、有限差分。笔试时看到一道编程题先别急着写代码问问自己这个计算属于哪类模式能不能拆成map和reduce的组合这个思维习惯能让你在考场上省下大量时间。我见过一道很有代表性的题目给一个二维矩阵要求把每个元素替换成它周围3×3网格的平均值。不会并行编程的人写个双重for循环就完事了稍微懂行的人会说这个适合stencil模式用共享内存存tile减少重复访存。这道题考的其实不是你会不会写图像处理而是你对数据复用和访存模式的理解。3. CUDA编程与优化实战思路3.1 CUDA线程模型grid、block、thread与warp如果笔试只允许出一个考点那大概率是CUDA线程模型。你需要清楚一件事GPU执行的最小单位是线程但真正调度执行的单位是warp一个warp通常是32个线程。你在写代码时指定block大小为128、256或512但硬件会把block切分成多个warp来调度。block的大小选择是有讲究的。太小比如32每个block只有1个warp调度开销大占用率可能不够太大比如1024一个block占用的资源太多可能限制同时驻留的block数量。实际工程里128到256是常见的默认选择但这绝不是死规矩得根据kernel的寄存器用量、共享内存用量、访存模式来调。笔试可能会让你分析“为什么block大小设为256而不是257”。本质是在考你warp对齐block大小最好是32的倍数这样每个block刚好是整数个warp不会产生尾部浪费。3.2 矩阵乘法从朴素实现到优化实现矩阵乘法是GPU编程的“hello world”笔试、面试、工作面试题都爱考它。朴素实现很简单每个线程算输出矩阵的一个元素三层循环。第一版代码能跑但性能极差因为每个线程都从全局内存重复读A和B的数据访存严重冗余。进阶思路是分块tiling把输出矩阵切分成小块每个block负责计算一个小块先把需要用到的A、B数据加载到共享内存然后反复从共享内存读。这一步优化能把全局内存访问量降低几个数量级是笔试考“共享内存作用”时的标准答案。再往后还有双缓冲double buffering隐藏共享内存加载延迟、避免bank conflict调整共享内存布局、使用向量化加载float4、用Tensor Core做混合精度计算。这些优化点笔试里经常会以“请列出你能想到的矩阵乘法优化手段”这样的开放性题目出现。你要做的是按层次来答基础分块、共享内存复用、避免bank conflict、提高计算访存比、使用特殊硬件单元。按这个顺序答出题人就知道你是真写过性能代码的人。3.3 归约与原子操作并行编程的经典陷阱归约问题是另一道高频题有一个长度为N的数组求所有元素的和。朴素并行思路是每个线程算一部分然后加到全局结果上。但这有个严重问题如果所有线程同时往一个全局变量上累加会发生竞争结果不确定。解法有两种一是用原子操作简单但原子操作在高竞争下会严重拖慢速度二是树形归约每轮把两个部分和合并用共享内存做缓存最后只做极少的原子操作或由单个线程写回。笔试考这个题往往是让你分析“为什么这段并行求和代码结果是错的”或者“如何改进”。答案里要有两个关键词竞争条件race condition和树形归约。另外还得注意一个细节块内用__syncthreads()做同步时如果让一个block里的多个warp都写同一个共享内存位置也可能产生竞争必须保证先写、同步、再读的顺序。这背后其实是一个更通用的问题并行程序里同步和通信是最大的敌人。原子操作是锁的替代品但有性能代价同步会带来barrier等待通信则产生数据搬移。笔试和工程里你得能判断什么时候该用哪种手段。3.4 访存优化与异步执行决定性能上限的关键很多人在性能优化上陷入一个误区只盯着计算量忽略了访存。实际上在AI kernel里绝大多数算子都是访存密集型性能瓶颈在内存带宽不在计算单元。衡量指标是算术强度arithmetic intensity也就是每字节数据对应多少次浮点运算。以向量加法为例每个元素需要读两个数、写一个数但只做一次加法。这种低算术强度的操作无论你怎么调kernel性能都受制于内存带宽。笔试如果让你评估一段代码的潜在性能你得学会先算算术强度再对比硬件平台的“计算峰值/内存带宽”比值判断这段代码是compute-bound还是memory-bound。这时候异步执行的作用就体现出来了。GPU有独立的DMA引擎可以做到数据拷贝和kernel执行重叠。使用pinned memory页锁定内存可以加速CPU和GPU之间的拷贝使用多个CUDA stream可以让不同kernel之间部分重叠执行。笔试里出现“如何让CPU和GPU通信不阻塞计算”这类题时标准答案就是pinned memory加stream异步。4. 深度学习框架与异构加速的交叉考点4.1 框架底层如何调度GPU从Python到Kernel笔试考深度学习框架的题不会真让你写一个张量库而是在概念层面考察你懂不懂框架的运行机制。一个典型的流程是你用Python定义了一个矩阵乘法PyTorch会把它封装成一个operation并加入计算图执行时调度器会把这个op派发给对应的GPU kernelkernel在GPU上启动执行完结果写回显存如果开启了自动微分还会记录反向传播所需的中间张量。框架层面有一个很重要的概念叫“op放到哪个设备上”。你写代码时用.cuda()把张量搬到GPU但这只是显式管理。框架内部还有显存缓存分配器它不会每次请求都向驱动申请内存而是预分配一大块显存然后自己管理分配和释放。2018年前后各家框架的显存管理策略差别很大笔试可能会问“为什么你监视显存占用时框架看起来把显存都吃了”这类题答案就是显存池机制。4.2 卷积计算的加速思路im2col与隐式GEMM卷积是深度学习计算的核心笔试题不会让你直接写出高性能卷积kernel但会问“卷积在GPU上怎么加速”。这时候你要知道大多数框架不是直接做卷积而是把卷积转化成矩阵乘法GEMM因为矩阵乘法有高度优化的cuBLAS库可以调用。最直观的转换是im2col把输入feature map按卷积窗口重新排列成一个大矩阵然后和权重矩阵做GEMM。这个方法实现简单但会引入大量显存冗余所以后来又有了隐式GEMM不真正展开数据直接在计算时按GEMM的索引方式取数据省掉了冗余存储。再高阶一点是Winograd和FFT。Winograd通过在频域里做变换减少乘法次数在3×3卷积上应用广泛FFT在超大卷积核上有效但在小卷积核上反而更慢。笔试如果让你比较这些方案的优劣你需要抓住两个维度计算量与额外内存开销。没有一种方案是万能的能做工程的人都明白这个道理。4.3 混合精度与推理优化从FP32到FP16/INT82018年那会儿Tensor Core已经出现在NVIDIA的Volta架构上FP16混合精度训练也逐渐成为趋势。笔试考混合精度的核心是让你理解为什么用低精度能加速一是FP16的存储带宽需求减半二是Tensor Core能大幅提升浮点吞吐率三是显存占用变少可以跑更大的batch。但混合精度不是把float换成half就完事。FP16的表示范围小容易溢出所以训练时要额外维护一个FP32的权重副本并用损失缩放loss scaling防止梯度下溢。推理场景下还有INT8量化需要考虑量化误差和校准方法。笔试的判断题往往考察你能不能意识到“低精度不是免费的需要损失精度风险与性能收益”。这一节的思想本质是性能优化的核心不是无脑堆算力而是找到计算精度要求和硬件特性之间的平衡点。这种判断力比背几个API值钱得多。5. 真实做题复盘如果坐在考场上5.1 拿到一份异构计算笔试题的答题顺序这篇帖子不是教人做某张卷子但我可以分享一套通用的答题策略。异构计算工程师的笔试题通常分三块客观题选择填空、代码题C或CUDA、系统题开放论述。很多人喜欢按顺序从头做到尾但我建议先花三分钟浏览全卷把题目按“会、模糊、不会”分类。先做会做的题保证基础分再做模糊题尽量写出推导过程和关键步骤说不定能拿部分分最后啃不会的题。特别是代码题一定要展示你的思考过程就算代码没完全写对也要把思路写清楚比如“这里应该开一个block网格每个block负责计算某一行”。在校招笔试里部分分和完整分差得很远但零分和一百分之间的差距往往就看你有没有写出关键的概念。5.2 一道典型C多线程题的思考过程异构计算工程师的笔试题里C多线程题不会缺席目的是考察你有没有多线程编程的底层直觉。想一道典型的题让两个线程交替打印奇数和偶数线程A打印1、3、5线程B打印2、4、6。这道题看着简单实际考察的是两件事条件变量condition variable的使用和锁的粒度控制。解题思路是维护一个共享变量表示当前轮到谁每个线程拿到锁之后检查是否轮到自己不是则等待是则打印并修改状态、通知对方。看似简单坑点在于初学者容易忘了把条件变量放在while循环里而不是if里因为可能存在“虚假唤醒”也就是线程被唤醒后发现条件其实不满足。这类题考察的不是你能不能写出正确代码而是你对并发编程里经典的“lost wakeup”陷阱是否敏感。如果是CUDA版本出题风格就变了比如“写一个kernel把数组所有元素乘以2”。这种题明显是考网格划分你要把block数算清楚确保覆盖N个元素且不越界。答案不唯一但好的答案会考虑N不是blockDim整数倍的情况用边界判断处理。5.3 系统设计题的答题框架性能优化的完整思路开放性的系统设计题是最拉分的一类通常长这样“某个AI推理服务延迟很高你怎么定位和优化”或者“请设计一个异构训练系统的框架”。这类题没有标准答案但阅卷人很清楚什么答案有工程经验。我推荐的答题框架是四步走第一明确系统边界和性能指标把“延迟很高”具体化为“P99延迟100毫秒目标降到30毫秒”。没有量化目标就无从优化。第二画出数据流和计算图标出哪些环节是CPU、哪些是GPU往往瓶颈一眼就能看出来比如CPU预处理太慢GPU在空转。第三逐层分析是该调框架参数、改kernel还是换硬件先做成本最低的改动比如增加Pipeline并行度让数据准备和计算重叠。第四给出验证方案怎么测量、怎么判断改有效果。这种结构化的思路比“我觉得应该用TensorRT做加速”这种单一答案要加分得多。因为面试官看到的是你有完整的优化方法论而不是只会套工具。6. 从笔试到工程异构计算工程师的真实日常6.1 笔试通过之后接下来会被考察什么如果你笔试顺利通过后面迎接你的是至少两轮技术面试和一轮代码面。到了这个环节笔试里考的那些知识都会被“追问”到更深一层。比如笔试写了矩阵乘法优化面试官就会问你为什么选128作为block大小你的kernel占用率是多少有没有用profiler量过带宽我亲眼见过一个候选人笔试里矩阵乘法优化写得很好但一问到“如何用Nsight Compute定位性能瓶颈”人就支支吾吾了。这说明他只刷过题没真正做过性能分析。我的建议是不要因为笔试刷题通过了就万事大吉你应该真的在本机上跑几个实验把NVIDIA Nsight或者AMD ROCm的性能分析工具用熟至少在简历上写项目经历时你能说出“我通过profile分析发现某个算子访存不连续然后我用共享内存分块把它优化了3倍”这种话。6.2 异构计算在今天的演进大模型时代反而更重要你可能觉得2018年的笔试已经过时恰恰相反异构计算在大模型时代的重要性不仅没降反而更高了。当年跑一个ResNet-50单卡V100基本够用现在训练千亿参数大模型动辄需要几千张GPU算力调度、显存管理、通信优化、故障恢复每个环节都是异构计算工程师的主场。以前笔试里考的显存管理现在对应的是大模型训练里的ZeRO、重计算activation checkpointing和显存碎片整理以前考的通信优化现在对应的是all-reduce、ring-AllReduce、NCCL调优以前考的混合精度现在对应的是FP8训练和推理量化。底层的知识体系没有变变的是规模和应用场景。所以如果你现在还在为这类笔试做准备看2018年的题是好事因为核心考点依然准确。但你更应该把目光放远在掌握CUDA优化后去了解分布式训练框架的显存规划去了解最新的AI加速芯片指令集。这些东西学得越深你在行业里的价值越大。6.3 给准备者的学习路径建议最后我给真心想投这个方向的人一条可行的学习路线。第一步补体系结构基础推荐读《计算机组成与设计》和《深入理解计算机系统》的前几章重点是缓存、虚拟内存、流水线。第二步上手CUDA编程不要只看书一定要把《CUDA C Programming Guide》前几章的例子在自己的显卡上跑一遍然后把矩阵乘法从朴素版一步步优化到使用共享内存和Tensor Core。第三步学工具链熟练使用Nsight Compute和Nsight Systems。前者看kernel内部的吞吐和延迟瓶颈后者看整个应用的时间线。第四步深入到推理引擎或训练框架的源码比如把TensorRT的onnx解析到执行的流程走一遍或者看DeepSpeed怎么管理显存碎片。每一步都在为笔试的“最后一类开放题”积累素材。记住一点笔试考的不是你背了多少而是你有没有形成“先从系统角度看问题、再深入到算子细节”的思维习惯。这种思维不是刷几周题能速成的但一旦建立了后面受益很久。我在实际带人的过程中发现很多同学对异构计算的第一反应是“高端、门槛高”其实它只是把计算机系统最朴素的原则用在了AI场景里知道数据放在哪里、知道哪些计算可以并行、知道瓶颈在计算还是访存、知道如何用硬件特性把潜力逼出来。2018年那批笔试题目虽然已经过去好几年了但把这套本事练好放到今天的大模型训练和推理优化里依然是一张硬通货。