要懂 transformer 大模型(如 LLM)的基本构造 +关键组件(Attention, FFN, embedding 等)
作为一个顶级部署工程师,我们看 Transformer 的视角和算法研究员是完全不一样的。
研究员视角:数学公式、梯度传播、语义理解能力。
工程师视角:显存占用(Memory)、计算密度(FLOPS)、IO 瓶颈(Bandwidth)、并行切分点。
如果你不懂 Transformer 的内部构造,你在做极致优化(Kernel Fusion)、故障排查(NaN Debugging)、长文本扩展(Long Context)时就会束手无策。
下面我把 Transformer 的关键组件拆解开,告诉你它们在实际工程项目中是怎么用的。
1. Attention (注意力机制) ->显存杀手与优化核心
原理你肯定懂:。
但在工程中,Attention 是最让人头疼的IO 瓶颈和显存瓶颈。
实际应用场景:
1)FlashAttention (算子融合):
痛点:标准 Attention 会产生一个巨大的矩阵(Attention Matrix)。比如 100k 上下文,这个矩阵大到任何显卡都存不下。而且它需要频繁读写显存(HBM),速度受限于带宽,而不是计算能力。
应用:我们在部署时,必须强制开启 FlashAttention-2 或 3。
原理应用:它利用了 GPU 的 SRAM(极快的小缓存),把 Q/K/V 切块运算,坚决不把那个巨大的矩阵写回显存。如果你不懂 Attention 内部在算什么,你就不知道为什么用了 FlashAttn 显存瞬间降了,速度快了 5 倍。
2)KV Cache (PagedAttention / vLLM):
痛点:每次生成下一个 Token,都需要前面所有 Token 的 K 和 V 矩阵。如果每次都重算,慢死;如果存下来,显存爆炸。
应用:这就是vLLM的核心。
原理应用:我们知道 K 和 V 是按层存储的张量。vLLM 把这些连续的张量打散,像操作系统管理内存页一样(PagedAttention)存放在显存的不连续空间里。不懂 Attention 需要缓存 K/V,你就看不懂 vLLM 的代码。
3)GQA / MQA (分组查询注意力):
场景:为什么 Llama-2-70B 推理那么慢,而 Llama-3 或 Yi-34B 那么快?
原理应用:传统的 MHA(多头注意力)是 Q, K, V 头的数量一样多(1:1:1)。这导致 KV Cache 巨大。
工程决策:在选型模型时,如果是高并发场景,我们会优先选支持GQA (Grouped Query Attention)的模型(如 Llama-3)。因为它让几组 Q 共享一组 K, V,直接把KV Cache 的显存占用砍掉了 8 倍甚至更多,意味着你能支持的并发量(Batch Size)大了 8 倍。
2. FFN (前馈神经网络 / MLP) ->参数大户与并行切分
Transformer 结构里,Attention 层通常参数不多,2/3 的参数量其实都在 FFN 里(就是那是两个大的线性层 UpProj, DownProj + 激活函数)。
实际应用场景:
1)张量并行 (Tensor Parallelism, TP) 的切分:
痛点:单卡放不下 72B 模型,怎么切?
原理应用:
- 对于 FFN 的第一个矩阵
(扩维):我们将它按列切分(Column Parallel)。
- 对于 FFN 的第二个矩阵
(降维):我们将它按行切分(Row Parallel)。
- 工程意义:这种切法使得两个 GPU 计算完后,结果可以直接相加(All-Reduce),数学上是等价的。如果你不懂 FFN 是两个矩阵相乘,你就没法写 TP 的通信代码,也不知道为什么要在那里插入 All-Reduce 算子。
2)MoE (混合专家模型) - 如 DeepSeek-V2/Mixtral:
原理应用:MoE 本质上就是把 FFN 拆成了 8 个或 64 个小的 FFN(专家)。
工程坑点:部署 MoE 时,显存通信会变得极其复杂(All-to-All 通信)。因为不同的 Token 要去不同的卡上找专家。懂了 FFN 的结构,你才能优化 MoE 的路由策略,防止某些专家负载过高(Load Balancing)。
3. Embedding (嵌入层) & Tokenizer ->多语言适配与微调坑
实际应用场景:
1)词表扩充 (Vocabulary Expansion):
场景:Llama-3 原生中文能力一般,你想让它更懂中文。
应用:它的 Embedding 层大小原本是128256 x Hidden_Size。我们需要把这个矩阵“拉长”,往里面塞入几千个新的中文字符的向量。
工程操作:修改模型结构的 Embedding 层权重,并重新训练这一层。不懂 Embedding 只是一个查表操作(Lookup Table),你就不知道怎么无损地扩充词表。
2)多模态对齐 (Multimodal Projector):
场景:也就是像 GPT-4o 或 LLaVA 那样能看图。
原理应用:图片经过 Vision Encoder 后出来的向量,和文本 Embedding 的维度不一样(比如图片是 1024维,文本是 4096维)。
工程:我们需要在这中间加一个简单的Linear Projector (也是个 FFN),把图片向量“强行”映射到文本 Embedding 的空间里,伪装成文本 Token 喂给 Transformer。
4. Positional Encoding (位置编码 / RoPE) ->长文本外推
实际应用场景:
1)长文本扩展 (Long Context Scaling):
场景:模型训练时只看了 4k 长度,用户非要传 20k 的文档,模型直接胡说八道。
原因:旋转位置编码(RoPE)没见过那么大的位置索引。
工程 Hack:我们不需要重新训练模型!
- 线性插值 (Linear Scaling):骗模型说“现在的第 20 步其实是第 10 步”。
- NTK-Aware Scaled RoPE:修改推理配置文件(config.json),调整 RoPE 的
base参数。
这完全依赖于你对位置编码数学原理的理解。改一个参数,模型就能从支持 4k 变成支持 32k(虽然精度略降),这是部署工程师的高光时刻。
5. Layer Norm / RMS Norm ->精度溢出的罪魁祸首
实际应用场景:
1)FP16 vs BF16 的炸裂问题 (NaN):
现象:训练好的模型,用 FP16 推理时突然输出全屏乱码(NaN),改用 BF16 就好了。
原理:很多大模型现在用RMS Norm。在深层网络中,激活值可能会变得非常大(超过 65504),导致 FP16 溢出(Overflow)。
工程排查:如果你懂结构,你会去检查 Norm 层的输出。解决方案通常是强制把 Norm 层保留为 FP32 计算,或者全链路切 BF16。
总结:这些知识如何变现?
当你遇到下面这些实际问题时,原理知识就是你的武器:
1、老板问:“为什么这个 7B 模型显存只要 14G,那个 7B 模型要 20G?”
原理回答:“因为那个模型没用 GQA,KV Cache 太大,或者是词表(Embedding)特别大。”
2、客户问:“为什么输入长了之后,速度慢得像蜗牛?”
原理回答:“因为 Attention 是 O(N2)O(N^2)O(N2) 复杂度,我们需要开启 FlashAttention 来优化 IO。”
3、运维问:“怎么把两个 GPU 利用率跑满?”
原理回答:“按照 FFN 列切行切 + Attention 头切分的逻辑(TP),重写 Docker 启动参数。”
一句话:不懂结构,你只能当“API 调用工程师”;懂了结构,你才是能修改模型手术刀的“模型架构师”。
好!这才是做工程的态度。打破砂锅问到底,把那些故弄玄虚的数学符号扒光,看看到底是什么。
我用最通俗的大白话,配合咱们的实际工作场景,把这些概念一个个拆开。
1. Q, K, V 和
到底是啥?
别被数学符号吓到,这其实就是一个“查字典”或者“搜索引擎”的过程。
假设你输入一句话:“我爱吃苹果”(这里有 5 个字)。
在模型眼里,就是 5(输入的字数/Token数)。
- Q (Query - 查询):手里的拿着的字。比如“我”。
- K (Key - 索引):字典里的目录。比如“我”、“爱”、“吃”、“苹果”。
- V (Value - 内容):这些字背后的真正含义(向量)。
过程 ():
模型想知道:“我”这个字,和句子里其他的字有什么关系?
1、拿“我”(Q) 去跟“我”(K) 对一下 -> 关系很大 (Score高)。
2、拿“我”(Q) 去跟“吃”(K) 对一下 -> 我是主语,跟动作有关,关系也不错。
3、拿“我”(Q) 去跟“苹果”(K) 对一下 -> 关系一般。
(注意力矩阵):
每个人都要跟所有人比一次。
如果有 5 个字,就要比 5×5=255 \times 5 = 255×5=25 次。
如果有1000 个字(),就要比 1000×1000=100万次。
如果有10万 个字(长文本),那就是100亿次计算。
这就解释了“为什么输入长了之后,速度慢得像蜗牛(O(N^2))”:
因为输入长度翻倍(2倍),计算量不是翻2倍,而是翻4倍(2的平方)。输入翻10倍,计算量翻100倍。这就是的噩梦。
2. FlashAttention 怎么开启?
必须开启 FlashAttention 的原因:那个的矩阵 太大了,大到显存塞不下,而且读写很慢。FlashAttention 的绝招是:不把这个巨大的矩阵写到显存里,切成小块在计算核心(SRAM)里偷偷算完。
怎么开启?(实战篇)
通常不需要你写代码,而是在启动命令或安装环境时搞定。
场景 A:用 vLLM 部署(最常见)
vLLM 默认自动开启。只要你安装了库。
# 1. 安装 (环境准备) pip install flash-attn # 2. 启动 vLLM python -m vllm.entrypoints.openai.api_server --model /models/Qwen-72B # vLLM 启动日志会显示: "Model uses FlashAttention-2: True"如果没装这个库,vLLM 会退化到慢速模式,你会发现推理速度慢了 5 倍。
场景 B:用 HuggingFace Transformers 代码加载
from transformers import AutoModelForCausalLM # 显式指定使用 flash_attention_2 model = AutoModelForCausalLM.from_pretrained( "/models/Qwen-72B", device_map="auto", attn_implementation="flash_attention_2" # <--- 关键就是这一行参数 )3. FFN、TP、All-Reduce 是怎么回事?
FFN (Feed-Forward Network) 是啥?
它是模型的“大脑皮层”,用来存储知识的。结构很简单:输入 -> 变宽 (扩维) -> 激活 -> 变窄 (降维) -> 输出。
你可以把它想象成一个汉堡包:两片面包(两个矩阵)夹着肉(激活函数)。
TP (张量并行) 是自动的吗?要写代码吗?
- 不用你写底层 C++ 通信代码(那是 NVIDIA 工程师干的事)。
- 但是!你需要通过配置参数来“遥控”它。
什么是扩维、降维?
假设输入向量长度是 10。
- 扩维 (Up-Proj):乘以一个大矩阵,把它变成长度 40。
- 降维 (Down-Proj):乘以另一个矩阵,把它变回长度 10。
为什么要这么折腾?为了让数据在更高维度里“混合”一下,产生智能。
TP 是怎么切分工作的?(通俗版)
假设我们要算这个巨大的汉堡包,只有两张显卡 (GPU A 和 GPU B)。
切第一刀 (列切):汉堡的上半部分,A 做左边一半,B 做右边一半。大家各干各的,不用交流。
切第二刀 (行切):汉堡的下半部分,A 接着处理它的那份,B 接着处理它的。
All-Reduce (关键时刻):
最后一步,A 和 B 手里各有一部分结果。
All-Reduce就是 A 对 B 喊:“把你算的给我!”,B 对 A 喊:“把你算的给我!”
两人把对方的数据拿过来,加在一起,得到最终完整结果。
这就是为什么需要 NVLink!因为这一步大家要疯狂交换数据,没有高速通道就卡死了。
运维问:“怎么把两个 GPU 利用率跑满?”
你的回答翻译成人话:
“不用你写代码。你在启动 Docker 或者 vLLM 的时候,加上一个参数--tensor-parallel-size 2(简称 TP=2)。这就告诉程序,要把模型切成两半,让两个 GPU 一起通过 All-Reduce 协作干活。如果不加这个参数,它默认只用一张卡,另一张卡就在旁边看戏(利用率 0)。”
4. MoE (混合专家模型) 和 路由
什么是 MoE?
以前的模型(Dense)是全科医生,不管是感冒还是骨折,所有神经元都要参与计算。
MoE (Mixture of Experts) 是专科医院。模型里住了 64 个专家(Expert)。
这个 Token 是“感冒”,路由(Router)把它发给专家 A 和 B。
那个 Token 是“骨折”,路由把它发给专家 C 和 D。
好处:模型参数巨大(几千亿),但每次计算只用一小部分,速度极快。
我需要写路由策略吗?
不需要。路由策略是模型训练时定好的(写在模型权重里的)。
作为部署工程师,你只需要:
1、下载支持 MoE 的推理引擎(现在的 vLLM, TensorRT-LLM 都支持)。
2、加载模型(如 DeepSeek-V2, Mixtral-8x7B)。
3、引擎会自动读取模型里的路由权重,自己把数据分发给不同的专家。
5. 那些“不懂的技术”:部署工程师到底该懂啥?
第三四五条(Embedding, Positional, LayerNorm),你不需要懂公式,但你需要懂故障现象:
1. Embedding (词表) -> 解决“乱码”和“不识字”
现象:你的模型虽然很牛,但如果你让它处理某些特殊的中文行业术语,它拆得稀碎。
工程应用:有时候需要修改tokenizer.json或者微调 Embedding 层,把你们公司的专业术语加进去。这个叫“扩充词表”。
2. Positional Encoding (RoPE) -> 解决“长文本傻掉”
现象:Llama-2 说它支持 4096 长度。用户输入了 5000 字,模型最后生成的全是胡言乱语或者重复的话。
工程应用:你去改配置文件config.json,把rope_scaling这个参数改一下(比如改成linear或dynamic)。不需要重新训练,模型就能勉强支持更长的文本。这就是“改个参数就能跑”的奥秘。
3. Layer Norm / BF16 -> 解决“NaN 炸裂”
现象:你买不起 A100,用了便宜的 P40 或者 V100 (只支持 FP16)。结果模型跑着跑着报错output is NaN(输出不是数)。
工程应用:你得知道这是因为 FP16 的数字范围太小,溢出了。解决办法是强制把模型的某些层转成 FP32 跑,或者劝老板买支持BF16的新显卡(A10, 3090, 4090, A800)。BF16 不容易溢出,是大模型时代的标配。
1. 实战 TP (Tensor Parallelism):手把手配置 vLLM
你说“遥控太抽象”,那我们就来一次真实的部署操作。
项目背景:
老板给了你一台服务器,里面插了4 张 RTX 4090 (24G)。
任务是部署Qwen1.5-72B-Chat-Int4(通义千问 72B 的量化版)。
算账:
72B 的 Int4 模型权重大概占用 40GB+ 显存。
但是推理时还需要 KV Cache(为了存上下文),如果想支持长文本,还需要几十 GB 空间。
单张 4090 只有 24G ->绝对装不下。
两张 4090 有 48G -> 勉强装下权重,但没空间跑上下文了,一跑就 OOM(Out of Memory)。
决策:必须用 TP=4,把模型切分到 4 张卡上。这样总显存 96G,权重占 40G,还有 50G+ 可以跑很长的上下文。
操作步骤(这就是“遥控”):
我们不写 C++ 代码,我们写 Docker Compose 或者命令行。
# 这是一个真实的启动命令 python -m vllm.entrypoints.openai.api_server \ --model /data/models/Qwen1.5-72B-Chat-Int4 \ --tensor-parallel-size 4 \ # <--- 核心参数!TP=4 --gpu-memory-utilization 0.95 \ # 榨干 95% 的显存 --max-model-len 32768 \ # 支持 32k 上下文 --port 8000当你按下回车后,vLLM 内部发生了什么?
1、vLLM 读取--tensor-parallel-size 4。
2、它启动 4 个进程,分别控制 GPU 0, 1, 2, 3。
3、它加载 Qwen 模型权重。遇到 FFN 层(那个大汉堡)时,它自动把矩阵切成 4 份。
- GPU 0 拿第 1 份,GPU 1 拿第 2 份…
4、它在 4 张卡之间建立 NCCL 通信环(All-Reduce 通道)。
5、成功启动。此时你可以看到 4 张卡的显存都被占用了约 12GB(权重平分了)。
如果没有这个参数?
vLLM 默认 TP=1。它试图把 40GB 模型塞进 GPU 0 (24G)。
结果:CUDA out of memory。程序崩溃。
这就是 TP 在项目 中的实际应用:用多张小卡拼凑出大显存,通过配置参数让框架自动切分模型。
2. 现在主流大模型都是 MoE 吗?
不是。现在的江湖是Dense(稠密模型)和MoE(混合专家)分庭抗礼。
Dense 模型 (传统派):
- 代表:Llama-3 (70B),Qwen1.5/2 (72B),Yi-34B。
- 特点:结构简单,全是实打实的参数。推理比较慢(因为每个字都要算几百亿参数),但很稳,微调生态好。很多企业私有化部署首选这个,因为好维护。
MoE 模型 (新贵派):
- 代表:DeepSeek-V2,Mixtral-8x7B,Qwen1.5-MoE-A2.7B。
- 特点:参数量贼大(比如 DeepSeek 有 236B),但推理时激活参数少(只有 21B)。推理速度快,也更聪明。
- 趋势:今年(2024)MoE 越来越火,因为它的性价比极高(同样的智能水平,推理成本更低)。但它的显存需求通常比较大(因为虽然计算少,但所有专家的权重得先加载进显存)。
项目经验:如果你的显存够大(比如有 A100/H800),且追求高并发低延迟,首选 MoE。如果显存捉襟见肘,或者要搞复杂的微调,Dense可能更省心。
3. RoPE 与 config.json:为什么改个参数就能跑 5000 字?
为什么输入 5000 字就胡言乱语?
模型训练时,就像在操场上跑步。训练数据大多只有 4096 步长(4k)。
位置编码(RoPE)负责告诉模型:“这是第 1 步,那是第 100 步”。
RoPE 用了三角函数(正弦/余弦)来表示位置。训练时,它只见过频率范围在一定区间内的数值。
当你输入第 5000 个字时,位置索引变成了 5000。这个数字超出了 RoPE 在训练时见过的“相位”范围。
模型一脸懵逼:“没见过这个位置啊?这到底是第 5000 步,还是第 1 步?”(周期性函数的混叠效应)。
于是注意力机制失效,模型开始乱猜,输出乱码。
config.json 哪来的?
在你下载的模型文件夹里!
比如/models/Llama-2-7b-chat-hf/config.json。这是模型的“身份证”和“说明书”。
为啥改个参数就能勉强支持?(Linear Scaling 原理)
我们用一个欺骗战术。
假设模型只认识 0 到 4096 的位置。
现在来了个 8192 的位置。
我们修改配置:
"rope_scaling": {"type": "linear", "factor": 2.0}原理:推理时,把真实位置 pospospos 除以 2。
- 当位置是 8000 时,我们骗模型说:“嘿,其实这是位置 4000。”
- 当位置是 4000 时,我们骗模型说:“这是位置 2000。”
结果:所有输入位置都被压缩回了 0-4096 的区间内。模型觉得:“哦,这些位置我都认识!” 于是它就能正常处理了。
代价:虽然能跑了,但分辨率变低了(有点像把高清图压缩了),所以精度会稍微下降一点点,但比起直接乱码,这简直是神技。
4. P40 / V100 这种老卡,强制转 FP32 可行吗?
可行,但是有代价。
硬件支持:P40 和 V100 绝对支持 FP32(单精度)。实际上,P40 的 FP32 算力非常强(它就是为 FP32 设计的)。
为什么这么做?
- P40 的 FP16 支持很烂(甚至可以说是残废),它是 Pascal 架构的老古董。如果你强行用 FP16 跑 Llama,大概率溢出 NaN。
- V100 支持 FP16 很好,但不支持 BF16。如果模型训练时用了 BF16 且数值范围很大,转成 FP16 可能会溢出。
怎么操作?(解决方案)
如果是 P40 跑 Llama-3:
全量 FP32:显存占用直接翻倍。
- FP16 下 7B 模型占 14G。
- FP32 下 7B 模型占 28G -> P40 只有 24G ->爆显存,跑不了。
混合精度(Layer-wise Cast):这是高手的做法。
- 我们不把整个模型转 FP32。
- 我们只把最容易溢出的那一层(通常是最后的 Norm 层或者 Softmax 前的层)强制转成 FP32 计算。
- 其他的 FFN、Attention 还是跑 FP16。
- 结果:显存增加很少,速度稍微慢一点点,但 NaN 消失了,模型能用了。
项目经验:
现在国内有很多公司买退役的P40 (24G)做推理,因为只要 800 块钱一张,性价比无敌。
如果你要用 P40,你必须学会这种 FP32/FP16 混合或者量化的技巧,否则这卡就是废铁。但对于V100,通常 FP16 就能跑得不错,不需要强转 FP32,除非遇到极端 NaN 情况。
来,我们继续死磕这些细节,这对你上战场非常有帮助。
1.--gpu-memory-utilization 0.95到底是啥意思?
大白话解释:
这是 vLLM 的一个**“圈地”指令**。它的意思是:“vLLM 启动时,请直接把 GPU 上95%的显存一口气全部申请走,占为己有。”
为什么要这么霸道?
普通的程序是用多少申请多少。但大模型推理不一样:
权重 (Weights)是死的,占多少是固定的(比如 40GB)。
KV Cache (上下文缓存)是活的。
- 刚开始没用户时,它是空的。
- 用户发来 1 万字,它瞬间膨胀。
- 如果有 100 个用户同时发,它膨胀得更厉害。
vLLM 的逻辑是:
- 我不等到用户来了再去申请显存(那样容易碎片化,也慢)。
- 我先预先霸占95% 的显存。
- 扣除掉权重占用的那部分(比如 40%),剩下的所有空间(55%)全部划分为一个个小格子(Block)。
- 这些小格子就构成了KV Cache 内存池。
- 以后用户请求来了,我就从这个内存池里发牌。池子发完了,我就让后面的请求排队。
如果你不设这个参数(或者设太小,比如 0.5):
- vLLM 只占 50%。权重占去 40%,只剩下 10% 给 KV Cache。
- 结果:只要并发稍微高一点,或者文章稍微长一点,vLLM 就报错说“没内存池了”,尽管显卡上还有一大半空闲显存(因为你没让它用)。
如果你设太大(比如 1.0):
- vLLM 试图占 100%。
- 结果:显卡驱动、桌面环境、PyTorch 运行时本身也需要一点点显存(几百 MB)。vLLM 一点余地不留,直接导致OOM(Out of Memory)启动失败。
- 经验值:0.9 或 0.95 是最安全的最佳实践。
2. 32k 上下文是多少字?
简单换算公式:
在中文语境下,1 个 Token ≈ 1.5 到 1.8 个汉字(取决于模型的分词器 Tokenizer)。
但在英文语境下,1 个 Token ≈ 0.75 个单词。
所以,32k (32,768) Tokens大概对应:
- 纯英文:约 2.4 万个单词。
- 纯中文:约5 万 到 6 万个汉字。
实战感知:
- 一部中篇小说。
- 一份非常详尽的几十页财报 PDF。
- 半小时的会议录音转写文本。
这些都可以在 32k 窗口内一次性塞给模型处理。
3. V100 显卡支持 FP32 吗?既然只支持 FP16,怎么还能转?
这里有个误区,我们需要澄清一下显卡的**“支持”**到底指什么。
事实:V100 完美支持 FP32。
实际上,V100 的 FP32 计算速度非常快(15.7 TFLOPS)。
那为什么大家说“V100 适合 FP16”?或者“V100 不支持 BF16”?
FP32 (单精度 32-bit):
- V100支持。速度快,精度高。
- 缺点:占显存大(一个数 4 字节),算力比 Tensor Core 慢。
FP16 (半精度 16-bit):
- V100支持且极其强悍。
- V100 里面有专门的Tensor Core电路,专门加速 FP16 的矩阵运算。用 FP16 跑,速度是 FP32 的8 倍(125 TFLOPS)。
- 所以大家都在 V100 上用 FP16,是为了快。
BF16 (BFloat16):
- V100不支持(硬件层面不支持)。
- 这是 V100 最大的痛点。A100 才开始支持 BF16。
回到你的问题:
“有的转成 FP32,它支持嘛?”
答案:绝对支持,而且很稳。
场景复现:
你在 V100 上跑一个模型,绝大部分层(FFN, Attention)走FP16(利用 Tensor Core 加速)。
突然,到了LayerNorm这一层,数值波动很大,FP16 可能会溢出。
代码里写了一行:layer_norm.float()(意思是把这层转 FP32)。
V100 会怎么做?
- 前面的计算用 Tensor Core 飞快地算完 FP16。
- 到了 LayerNorm,CUDA 核心接手,无缝切换到 FP32 模式,精准地算出结果(虽然比 Tensor Core 慢一点点,但因为 LayerNorm 计算量很小,整体影响忽略不计)。
- 算完后,再转回 FP16,交给下一层。
结论:
混合精度(Mixed Precision)就是这么玩的。V100 完全有能力处理 FP32 的部分,这甚至是解决 V100 溢出问题的标准手段。
转自:https://blog.csdn.net/qq_41834780/article/details/155570268
