现代 C++ 实战(11):Concepts 与模板进阶
模板很强大,但约束不足时编译错误像天书——SFINAE、enable_if 能解决问题,却难写难读。C++20 Concepts 把「类型必须满足什么」写进签名,错误从 100 行模板展开变成 3 行人话。 这一篇从 SFINAE 回顾到 Concepts 语法,并配合 type_traits 与 demo:ref/cpp_demo/basics/type_traits_demo/。 这是「现代 C++ 实战」系列的第 11 篇。建议先读 第 10 篇:Ranges。 一、模板的问题:约束写在哪?12345template<typename T>T add(T a, T b) { return a + b; }add(1, 2); // OKadd("hello", "world"); // 可能编译过,但语义不对(指针相加) 我们希望:在模板实例化前就拒绝不合法的类型,并给出清晰错误——而不是在深层实例化里爆炸。 历史上三条路线: 时代 手段 C++11 SFINA...
大模型数学速成(07):RoPE——用旋转编码位置
Self-Attention 本身不包含位置信息——打乱 token 顺序,只要 Q/K/V 一起打乱,注意力分数不变。但语言有语序:「狗咬人」≠「人咬狗」。位置编码告诉模型每个 token 在序列中的位置;现代 LLM 广泛使用的 RoPE(Rotary Position Embedding,旋转位置编码) 通过「旋转」Q/K 向量来注入相对位置。 这一篇搞懂:为什么需要 RoPE、旋转在算什么、为何只改 Q/K、以及绝对位置与相对位置的关系。 这是「大模型数学速成」系列的第 7 篇。建议先读 第 06 篇:FFN。下一篇 ViT 层 vs LLM 层对照总表。 一、顺序问题:Attention 是「置换等变」的第 05 篇 的注意力只看点积相似度。若把 token 列整体重排(Q、K、V 同步重排),每个 token 关注谁不变——模型不知道谁在前谁在后。 早期做法: 方法 思路 代表 绝对位置嵌入 给每个位置 $i$ 学一个向量 $p_i$,$x + p_i$ 原始 Transformer RoPE 按位置旋转...
现代 C++ 实战(10):Ranges 与函数式风格
传统 STL 算法要传 begin/end,中间步骤常要临时容器;C++20 Ranges 用「范围 + 视图管道」把数据处理写成 Unix 管道风格——filter | transform | take,且惰性求值,少分配、可读性高。 这一篇对应 demo:ref/cpp_demo/basics/ranges_demo/。 这是「现代 C++ 实战」系列的第 10 篇。建议先读 第 09 篇:C++20 格式化与编译期计算。 一、传统算法的局限12345678910std::vector<int> nums = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};// 传统写法:多步 + 中间容器std::vector<int> evens;std::copy_if(nums.begin(), nums.end(), std::back_inserter(evens), [](int n) { return n % 2 == 0; });std::vector<in...
大模型数学速成(06):前馈网络 FFN——GELU 与 SwiGLU
上一篇里,每个 token 通过注意力「看过」其他 token。但注意力只做加权混合——线性组合 V,表达能力有限。Transformer 块的另一半是 FFN(Feed-Forward Network,前馈网络):对每个 token 独立做「升维 → 非线性 → 降维」,注入更强的逐 token 变换能力。 这一篇搞懂 FFN 在算什么、GELU / SwiGLU 是什么、以及 ViT 与 LLM 的常见差异。 这是「大模型数学速成」系列的第 6 篇。建议先读 第 05 篇:注意力与 Softmax。下一篇讲 RoPE 位置编码。 一、注意力 vs FFN:分工不同 Self-Attention FFN 跨 token ✅ token 之间交换信息 ❌ 每个 token 独立处理 主要操作 加权求和(线性) 矩阵乘 + 非线性激活 类比 开会对齐信息 会后各自消化、深度加工 形状 [d, S] → [d, S] [d, S] → [d, S] 完整 Transformer 子层(Pre-LN)典型顺序: 1x → Norm → At...
现代 C++ 实战(09):C++20 格式化与编译期计算
printf 类型不安全,iostream 又冗又慢;C++20 的 std::format 把 {fmt} 收进标准库,Python 风格占位符 + 编译期类型检查。同一时代还有 constexpr 进阶、consteval、std::span——把格式化与计算都推向「更安全、更编译期」。 这一篇对应三个 demo:format_demo、constexpr_demo、span_demo。 这是「现代 C++ 实战」系列的第 9 篇。建议先读 第 08 篇:错误处理策略。 一、格式化三时代 方式 类型安全 语法 性能 printf ❌ 格式与参数不匹配 → UB C 风格 %d 快 iostream ✅ cout << x << y 冗长 较慢 std::format ✅ "{} + {} = {}" 简洁 接近 printf C++23 再加 std::print / std::println——直接输出,不必先拼 string 再 cout。 编译器要求:GCC 13+ / Cla...
大模型数学速成(05):注意力机制与 Softmax
上一篇我们有了 Norm 与残差;第 03 篇我们算出了 Q、K、V。现在进入 Transformer 的核心:每个 token 用 Q 去「查询」全序列的 K,按匹配度加权混合 V。 这一篇把 注意力分数、Softmax、输出混合 的公式与手算例子讲清楚,并区分 Self-Attention 与 Cross-Attention。 这是「大模型数学速成」系列的第 5 篇。建议先读 第 04 篇:LayerNorm 与残差。下一篇讲 前馈网络 FFN。 一、图书馆检索三步把 第 03 篇 的图书馆类比补全: 步骤 数学 生活类比 1. 匹配 $Q$ 与每个 $K$ 算相似度 → scores 你的检索便签与每本书脊标签比对 2. 归一化 Softmax → 权重(和为 1) 把分数变成「借哪几本、各占多少比例」 3. 混合 按权重对 $V$ 加权求和 → 输出 把选中书的正文按比例拼成一份摘要 三步走完,每个 token 的输出不再只是「自己长什么样」,而是融入了它选择关注的其他 token 的信息。 二、符号与形状(列 = token)沿...
现代 C++ 实战(08):错误处理策略
C++ 没有统一的「错误处理方式」——return -1、throw、std::optional、std::expected 各有战场。选错方式要么性能吃亏,要么错误被静默忽略,要么 API 语义含糊。 这一篇用同一个「解析配置文件」场景,对比 四种主流错误处理策略,并给出选型指南。对应 demo:ref/cpp_demo/basics/error_handling_demo/。 这是「现代 C++ 实战」系列的第 8 篇。建议先读 第 07 篇:C++17 工具箱。 一、为什么错误处理值得单独讲?现代 C++ 项目里,错误处理往往比算法更影响可维护性: 调用方会不会忘记检查返回值? 失败时资源会不会泄漏(文件句柄、锁、内存)? API 语义是否清晰:「找不到」和「出错了」是一回事吗? demo 用解析 host=...、port=... 的配置文件贯穿全文——同一功能,四种写法。 二、C 风格错误码:return -1 + 输出参数12345678enum class CErrorCode { SUCCESS = 0, FILE_NOT_FOUND = -...
大模型数学速成(04):LayerNorm、RMS Norm 与残差连接
上一篇我们算出 Q、K、V——但在乘 $W_q$ 之前,输入通常先过 LayerNorm 或 RMS Norm。算完注意力或 FFN 之后,还要加一条 残差连接 把原输入「抄送」回来。 这一篇搞懂:为什么要归一化、两种 Norm 差在哪、Pre-LN 与 Post-LN 怎么排、残差为什么能训深网络。 这是「大模型数学速成」系列的第 4 篇。建议先读 第 03 篇:Q/K/V 投影。下一篇讲 注意力机制与 Softmax。 一、为什么需要归一化?深度网络堆叠几十层后,中间激活的数值尺度容易漂移:某些维爆炸、某些维趋近 0,梯度不稳定,训练变慢甚至发散。 归一化(Normalization) 对每个 token 的特征向量做「拉回标准尺度」——让均值为 0、方差为 1(或类似效果),再交给下一层矩阵乘法。 生活类比:音响均衡器——不管输入音量忽大忽小,先归一化到合适响度,再进功放。 在本系列约定下(第 01 篇): 输入形状 [n_embd, n_tokens],每一列是一个 token 的 $n_embd$ 维向量 Norm 按列操作:对每个 tok...
现代 C++ 实战(07):C++17 工具箱
C++17 不像 C++11 / C++20 那样「改天换地」,却塞进了大量日常极好用的工具:std::any、std::filesystem、结构化绑定、if constexpr、折叠表达式、并行算法……写业务代码时经常伸手就能摸到。 这一篇把 C++17 工具箱里最常用的一批串起来,对应三个 demo:any_demo、filesystem_demo、parallel_algo_demo。 这是「现代 C++ 实战」系列的第 7 篇。建议先读 第 06 篇:Lambda 与类型推导。 一、std::any:运行期存任意类型C++17 的 std::any 是类型擦除容器——运行期可以换成 int、string、vector……类型信息保存在内部,取出时用 std::any_cast。 123456789#include <any>#include <string>std::any value = 42;value = std::string("hello"); // 可以改存别的类型value....
x86 汇编入门(06):文件读写
程序不能只跟终端打交道。配置文件、日志、数据文件——都离不开文件 I/O。这一篇用 06_file_io.asm 完成「写入 → 关闭 → 重新打开 → 读取 → 输出」全流程,也是本系列的收官之作。 这是「x86 汇编入门」系列的第 6 篇,也是最后一篇。前五篇覆盖了输出、输入、算术、循环和函数。这一篇综合运用文件相关系统调用,并回顾整个系列的学习路径。 一、文件相关系统调用 调用号 名称 作用 2 sys_open 打开或创建文件 0 sys_read 从 fd 读取 1 sys_write 向 fd 写入 3 sys_close 关闭 fd sys_open 参数: 寄存器 含义 rdi 文件路径(以 \0 结尾的 C 字符串) rsi 打开标志 flags rdx 权限 mode(创建文件时有效) 返回值 rax 文件描述符;失败时为负数 常用 flags(可位或组合): 标志 值 含义 O_RDONLY 0 只读 O_WRONLY 1 只写 O_CREAT 0x40 不存在则创建...















