AdamW Optimizer:为什么要把权重衰减与梯度更新解耦
在上一篇 Adam Optimizer 文章中,我们知道 Adam 会同时维护梯度的一阶矩和二阶矩,并根据历史梯度为不同参数调整有效步长。 当模型出现过拟合时,我们还希望限制参数变得过大,于是经常会为优化器设置 weight_decay: optimizer = torch.optim.AdamW( model.parameters(), lr=1e-3, weight_decay=1e-2, ) 这里为什么常用 AdamW,而不是简单地给 Adam 加一个 L2 正则项?AdamW 中的字母 W 又代表什么? 一句话概括: AdamW 把权重衰减从 Adam 的梯度与矩估计中分离出来,让“根据损失优化参数”和“按比例缩小参数”成为两件独立的事。 1. 先回顾 AdamAdam 对当前梯度 $g_t$ 维护两种状态。 一阶矩: $$m_t=\beta_1m_{t-1}+(1-\beta_1)g_t$$ 二阶矩: $$v_t=\beta_2v_{t-1}+(1-\beta_2)g_t^2$$ 经过偏差修正后: $$\hat{m...
Adam Optimizer:从梯度下降到自适应学习率
训练神经网络时,我们经常会看到下面这行代码: optimizer = torch.optim.Adam(model.parameters(), lr=0.001) 它很短,却承担着一个关键任务:根据反向传播得到的梯度,不断更新模型中的权重和偏置。 Adam 的全称是 Adaptive Moment Estimation,可以翻译为“自适应矩估计”。它同时利用梯度的移动平均和梯度平方的移动平均,为不同参数自动调整更新方向与步长。 一句话概括: Adam 在动量方法的基础上记录梯度方向,又根据历史梯度大小为每个参数调整学习率,因此通常比普通 SGD 更容易上手。 1. 优化器到底负责什么神经网络训练通常包含三个核心步骤: optimizer.zero_grad() loss.backward() optimizer.step() 它们的职责并不相同: 代码 作用 optimizer.zero_grad() 清空上一轮保存在参数上的梯度 loss.backward() 根据计算图和链式法则计算梯度 optimizer.step() 根据梯度和优化算法更...
Word2Vec:从词向量训练到神经网络分类器
前面学习文本处理时,我们已经知道:自然语言不能直接送进模型,必须先变成数字。 最朴素的方法是 One-hot。比如词表里有 10000 个词,每个词就用一个长度为 10000 的向量表示,属于自己的位置为 1,其他位置为 0。 但 One-hot 有两个明显问题: 向量太稀疏,绝大多数位置都是 0。 词和词之间没有语义关系,“国王”和“王后”在 One-hot 空间里并不比“国王”和“香蕉”更接近。 word2vec 要解决的就是这个问题: 把词表示成低维、稠密、带有语义关系的向量。 例如: 国王 -> [0.32, -0.18, 0.71, ...] 王后 -> [0.29, -0.15, 0.69, ...] 香蕉 -> [-0.44, 0.83, 0.12, ...] 如果训练得好,“国王”和“王后”的向量会更接近,而“国王”和“香蕉”的向量会更远。 这篇文章就从 word2vec 出发,理解词向量是怎么训练出来的、怎么改进和评价词向量,并进一步过渡到神经网络文本分类器。 1. 词向量到底是什么词向量,也叫 word embedding,本质上就是给每个词分...
深度学习入门:从神经网络到学习路线
学习深度学习时,很多人一上来就会被一堆名词淹没:神经网络、反向传播、CNN、RNN、Transformer、Embedding、优化器、损失函数、过拟合、预训练、微调…… 这些概念当然重要,但如果一开始没有一张地图,就很容易出现一种感觉:每个词好像都看过,但不知道它们之间到底是什么关系。 所以这篇文章不急着推公式,也不急着写复杂代码,而是先回答几个更基础的问题: 深度学习到底在学什么? 神经网络为什么可以拟合复杂关系? 一个模型是如何被训练出来的? 入门之后应该按什么顺序继续学? 一句话概括: 深度学习就是用多层神经网络从数据中自动学习特征表示,再用这些表示完成分类、回归、生成、推荐、预测等任务。 1. 深度学习是什么在传统机器学习中,我们经常需要手动设计特征。 比如要判断一封邮件是不是垃圾邮件,可能会人工提取这些特征: 是否包含“免费”“中奖”“限时”等关键词。 邮件长度是多少。 是否包含很多链接。 发件人是否陌生。 这些特征再送入逻辑回归、决策树、随机森林、GBDT 等模型中进行预测。 深度学习的思路稍微不一样。它希望模型自己从原始数据中逐层学习特征。 以图...
MLP多层感知机:从原理到PyTorch实现
MLP(Multilayer Perceptron,多层感知机)是最基础也最重要的神经网络之一。 如果说线性回归、逻辑回归只有一层线性变换,那么 MLP 就是在多层线性变换之间加入非线性激活函数,让模型能够拟合更复杂的关系。 它的结构并不神秘: 输入特征 -> 隐藏层 -> 激活函数 -> 隐藏层 -> 激活函数 -> 输出层 一句话概括: MLP 用多个全连接层和非线性激活函数,把输入特征一步步变换成适合分类或回归的输出。 1. 为什么需要 MLP前面学习线性回归时,模型大致是: $$\hat{y}=wx+b$$ 对于多维输入,可以写成: $$\hat{y}=xW+b$$ 这类模型只能表达线性关系。 例如下面这种问题,线性模型就比较吃力: 两个特征单独看都不能决定类别, 但它们组合起来以后才有意义。 经典例子是 XOR: $x_1$ $x_2$ 标签 0 0 0 0 1 1 1 0 1 1 1 0 这四个点无法用一条直线完美分开。 MLP 的作用就是:先通过隐藏层把原始特征映射到新的空间,再在新空间里完成分类或回归。...
图神经网络GNN:让模型学会理解关系数据
前面学习线性回归、逻辑回归、决策树、GBDT 这类模型时,我们面对的数据通常是表格、向量或图片。每个样本大多可以单独看待。 但现实中还有很多数据天然带有“关系”: 社交网络中,用户之间有好友关系。 推荐系统中,用户、商品、点击、购买构成交互图。 分子结构中,原子是节点,化学键是边。 交通网络中,路口是节点,道路是边。 知识图谱中,实体和实体之间有语义关系。 这些数据的重点不只在于“单个对象有什么特征”,还在于“对象之间如何连接”。图神经网络(Graph Neural Network,GNN)就是专门用来处理这类图结构数据的神经网络。 一句话概括: GNN 让每个节点不断接收邻居的信息,更新自己的表示,从而把节点特征和图结构一起编码进向量里。 1. 为什么普通神经网络不够用假设我们要判断一个社交网络用户是否可能对某个话题感兴趣。 如果只看用户自己的特征,例如年龄、地区、历史点击,当然能得到一些信息。 但在社交网络里,用户的邻居也很重要: 他的朋友是否都关注这个话题? 他是否处在某个兴趣社区中? 他和哪些关键用户有连接? 他在网络中的位置是否特殊? 普通全连接神经网...
PPO算法:从策略梯度到裁剪目标函数
PPO(Proximal Policy Optimization,近端策略优化)是深度强化学习中非常常用的一类策略优化算法。 如果前面已经理解了 MDP、奖励、价值函数和策略,那么 PPO 要解决的问题可以这样理解: 智能体已经有一个策略了。 现在我们根据新采样到的经验,让这个策略变得更好。 但每次更新不能太激进,否则好不容易学到的行为可能被一下子破坏。 这也是 PPO 名字里 “Proximal” 的含义:更新策略时,希望新策略离旧策略近一点。 一句话概括: PPO 是一种策略梯度算法,它通过裁剪新旧策略概率比值,限制单次策略更新幅度,从而在实现简单和训练稳定之间取得平衡。 1. 为什么需要 PPO在强化学习中,我们最终想学到一个策略: $$\pi_\theta(a|s)$$ 它表示在状态 $s$ 下选择动作 $a$ 的概率。这里的 $\theta$ 是神经网络参数。 如果某个动作带来了更高的长期回报,我们就希望以后在类似状态下更倾向于选择它;如果某个动作表现很差,就希望降低它被选中的概率。 这就是策略梯度的基本思想: 好动作的概率提高 坏动作的概率降低 但普通策...
HEFT算法:异构计算中的任务调度方法
在并行计算、云计算、边缘计算和异构芯片中,我们经常会遇到这样的问题:一个应用不是一个单独任务,而是一组有依赖关系的子任务;这些子任务可以运行在不同处理器上,但每个处理器的速度并不一样。 例如: 图像处理流水线中,解码、滤波、特征提取、分类之间有先后依赖。 科学计算工作流中,某些矩阵运算必须等前面的数据准备完成。 CPU、GPU、FPGA 同时存在时,不同任务适合的执行设备不同。 边缘计算中,任务可以放在本地设备、边缘服务器或云端执行。 这类问题的核心是: 哪些任务先执行? 每个任务放到哪个处理器上执行? 怎样让整个工作流尽快完成? HEFT(Heterogeneous Earliest Finish Time,异构最早完成时间)就是一个经典的异构任务调度启发式算法。它不保证一定得到全局最优解,但因为思想清晰、计算复杂度相对较低、效果通常不错,所以经常作为异构计算调度问题中的基线算法。 一句话概括: HEFT 先根据任务到出口任务的“平均关键路径长度”给任务排序,再按照这个顺序把每个任务放到能最早完成它的处理器上。 1. 为什么需要 HEFT假设我们有 4 个任务:...
强化学习:从状态、动作到马尔可夫决策过程
强化学习(Reinforcement Learning,RL)研究的是:一个智能体如何在环境中不断尝试,通过奖励信号学会更好的决策。 和监督学习不同,强化学习通常没有现成的标准答案。智能体每一步都要自己选择动作,然后环境会返回新的状态和奖励。 例如: 游戏角色向左走、向右走、攻击或防御。 机器人选择前进、转弯、抓取物体。 推荐系统选择给用户展示哪一个内容。 自动驾驶系统根据路况选择加速、刹车或转向。 这些问题都有一个共同点:当前的选择不只影响当前结果,还会影响以后能走到哪里、以后能拿到多少奖励。 马尔可夫决策过程(Markov Decision Process,MDP)就是强化学习中描述这种“连续决策问题”的基础数学框架。 一句话概括: MDP 描述的是:智能体在某个状态下选择动作,环境按照一定概率转移到下一个状态,并给出奖励;智能体的目标是在长期上获得尽可能多的累计奖励。 1. 为什么需要 MDP前面学习线性回归、逻辑回归、决策树时,我们面对的问题通常是这样的: 输入一个样本 -> 模型给出一个预测 例如: 房屋面积 -> 房价 学习时长 -> 是否通过考试 花...
文本处理:让自然语言变成模型能理解的数字
学习 Transformer 之前,有一个非常重要的前置问题: 机器学习模型只能处理数字,那自然语言文本应该怎样变成数字? 比如一句话: 我喜欢自然语言处理 人可以直接理解它的意思,但模型不能直接处理汉字、单词和标点。我们需要先把文本拆成一个个 token,再把 token 映射成编号或向量,最后才能送进模型。 这篇文章就来系统梳理 NLP 中最基础的文本处理流程。 1. 文本处理在 NLP 中的位置在前面的机器学习文章中,我们处理的大多是结构化数据,例如: 学习时长、睡眠时长、房屋面积、历史成绩 这些特征天然就是数字,或者很容易转成数字。 但 NLP 处理的是文本,例如: 这部电影很好看 这个商品质量一般 今天天气不错 模型不能直接理解这些句子,所以需要一个转换流程: 原始文本 -> 清洗与规范化 -> 分词 / tokenization -> 构建词表 -> token 转 id -> id 转向量 -> 输入模型 传统机器学习中,文本常被转成词袋、TF-IDF 这样的稀疏向量;深度学习和 Transformer 中,文本通常先转成 ...
正则化与过拟合:让模型不只记住训练集
前面学习线性回归、逻辑回归、决策树、集成学习和 GBDT 时,我们一直在训练模型,让模型尽可能学到数据里的规律。 但机器学习里有一个很重要的问题: 模型在训练集上表现很好,不代表它在新数据上也表现很好。 如果模型把训练数据里的噪声、偶然样本、特殊细节都记住了,就会出现过拟合(Overfitting)。正则化(Regularization)就是用来控制模型复杂度、提升泛化能力的一类方法。 1. 什么是泛化能力机器学习真正关心的不是训练集分数,而是模型面对新数据时的表现。 例如我们训练一个模型预测学生是否通过考试。训练集中有 100 个学生,模型全部预测正确,训练准确率达到 $100%$。 这听起来很好,但如果换一批新学生,准确率只有 $65%$,说明模型可能只是记住了训练集,而没有学到稳定规律。 这种“面对新数据仍然表现好”的能力,叫泛化能力。 可以简单记住: 训练集表现好:说明模型会做旧题 测试集表现好:说明模型学到了规律 在交叉验证那篇文章里,我们已经讲过:不能只看一次训练/测试划分,更稳妥的方式是用验证集或交叉验证评估模型。正则化则是进一步解决“模型太复...
GBDT:从残差到梯度提升树的完整理解
GBDT(Gradient Boosting Decision Tree,梯度提升决策树)是机器学习中非常常用的一类模型,尤其适合表格数据任务。 它的名字看起来很长,但拆开以后并不神秘: Gradient:沿着损失函数下降的方向修正模型。 Boosting:一轮一轮训练模型,后面的模型修正前面的错误。 Decision Tree:每一轮加入的基模型通常是一棵回归树。 一句话概括: GBDT 不是一次训练一棵很大的树,而是一棵树接一棵树地补前面模型的错误。 1. 为什么需要 GBDT单棵决策树有两个明显问题: 树太浅,模型表达能力不够,容易欠拟合。 树太深,容易把训练数据记得太死,导致过拟合。 GBDT 的思路不是训练一棵特别复杂的树,而是训练很多棵相对简单的树。 每一棵树只做一件事: 修正当前模型还没预测好的部分 这样模型可以逐步变强,同时通过学习率、树深度、树数量等参数控制复杂度。 2. 从一个房价例子理解 GBDT假设我们要预测 3 套房子的价格: 房子 面积 房龄 真实价格 A 70 平 15 年 100 万 B 100 平 8 年 16...
