携程 大模型算法开发 一面

1. 介绍一下你做过的一个项目

2. LoRA 的原理以及初始化方法是什么

LoRA 的核心是低秩适配。对于原始权重矩阵 (W \in \mathbb{R}^{d \times k}),全参数微调直接更新整个 (W),成本高、显存占用大。LoRA 认为下游任务需要的更新往往落在一个低秩子空间里,所以把增量写成:

W' = W + \Delta W = W + BA

其中,并且r≪min⁡(d,k)r≪min(d,k)训练时冻结原始参数 (W),只训练 (A) 和 (B),这样参数量和优化器状态都能显著下降。

初始化时通常让 (A) 随机初始化,(B) 初始化为 0,或者相反。这样一开始 (\Delta W = BA = 0),模型初始前向和原模型完全一致,不会一接入 LoRA 就把预训练能力扰乱。训练开始后,低秩更新逐步学出来。缩放项通常写成:

这里的 (\alpha) 用来控制更新幅度。

import torch
import torch.nn as nn

class LoRALinear(nn.Module):
    def __init__(self, in_features, out_features, r=8, alpha=16):
        super().__init__()
        self.weight = nn.Parameter(torch.randn(out_features, in_features))
        self.weight.requires_grad = False

        self.A = nn.Parameter(torch.randn(r, in_features) * 0.02)
        self.B = nn.Parameter(torch.zeros(out_features, r))
        self.scale = alpha / r

    def forward(self, x):
        delta_w = self.B @ self.A
        return x @ (self.weight + self.scale * delta_w).t()

3. LoRA 里的几个关键参数分别是什么意思

r 是低秩分解的秩,决定更新子空间维度。r 越大,表达能力越强,但参数量、显存和训练成本也会上升。alpha 是缩放系数,实际作用是调节低秩更新的有效幅度,通常和 r 一起考虑,因为真正起作用的是α/rdropout 是 LoRA 分支上的 dropout,用来防止小数据集微调时过拟合。

还有一个关键点是插入位置。LoRA 不一定每一层都加,也不一定只加在 attention 上。最常见的是加在 q_projv_proj,有些任务会加在 k_projo_proj,甚至 MLP 的 up/down projection。插在哪里,决定了微调的能力边界和训练成本。一般生成类任务对 attention 层更敏感,领域迁移较大的任务有时会连 MLP 一起加。

4. QLoRA 和 LoRA 的区别是什么

LoRA 是冻结原权重、训练低秩增量。QLoRA 则是在这个基础上,把基座模型权重量化到 4 bit 存储,同时仍然在高精度上训练 LoRA 参数。它的目标是进一步降低显存占用,让更大的模型也能在有限显存下微调。

QLoRA 的关键点有三个。第一,基座权重用 NF4 这类更适合正态分布权重的量化格式存储。第二,计算时会把量化权重反量化到更高精度参与前向。第三,优化器只更新 LoRA 参数,不更新量化后的底座。这样训练开销比普通 LoRA 更低,但如果任务非常依赖底层分布调整,QLoRA 的上限有时会稍逊于全精度 LoRA 或全参微调。

5. DeepSpeed 的 ZeRO 三个阶段分别做了什么

ZeRO 的核心是把传统数据并行里每张卡都完整保存一份模型状态的做法拆开。模型训练时主要有三类大块内存:优化器状态、梯度、参数。ZeRO 就是按阶段逐步把它们分片。

ZeRO-1 只切优化器状态。也就是 Adam 里的 momentum 和 variance 不再每卡完整保留,而是分散到不同设备上。ZeRO-2 在此基础上继续切梯度,反向传播后每张卡只保留自己那份梯度。ZeRO-3 更进一步,把模型参数本身也切开,前向和反向按需 gather。这样显存节省最大,但通信和调度复杂度也最高。

它本质上解决的是“参数冗余复制”问题,不是直接让单卡算得更快,而是让更大模型能训练起来。实际选型时,如果模型不算特别大,ZeRO-2 通常是比较稳的折中;模型继续变大时,ZeRO-3 才更有必要。

6. FSDP 和 DeepSpeed ZeRO-3 的差别是什么

FSDP 和 ZeRO-3 的目标很像,都是把参数、梯度和优化器状态做分片,降低单卡显存压力。但实现方式和工程生态上有一些差异。FSDP 属于 PyTorch 原生体系,更偏框架级封装;ZeRO-3 则来自 DeepSpeed,围绕大模型训练场景做了很多额外优化。

FSDP 通常按 module 为粒度做参数分片和 gather,配合 auto wrap policy 可以比较灵活地控制切分边界。ZeRO-3 更强调状态分片和训练系统整体管理,在配合 CPU offload、NVMe offload、pipeline parallel 时工程能力更完整。实际落地时,如果团队偏 PyTorch 原生、希望代码侵入小一些,FSDP 更自然;如果是超大模型训练、要叠加很多并行策略,DeepSpeed 生态通常更成熟。

7. 强化学习在大模型对齐里一般是什么框架

大模型对齐里最常见的是 RLHF,也就是先监督微调,再偏好建模,再强化学习优化。典型链路是 SFT 得到一个可用策略模型,然后收集偏好数据训练奖励模型,最后用 PPO 之类的算法让策略模型朝高奖励方向更新。

这套框架本质上不是让模型在环境里探索动作,而是把文本生成视作一个序列决策过程,每生成一个 token 都是在做动作选择。奖励信号通常不是即时给每个 token,而是对整段回答或者回答片段打分,所以要把最终奖励回传到生成轨迹里。难点在于奖励稀疏、训练不稳定、模型容易为了讨好奖励模型而偏离原分布,因此实际训练时都会加 KL 约束,把策略模型限制在参考模型附近。

8. PPO、DPO、GRPO 的区别是什么

PPO 是强化学习方法,依赖策略模型、参考模型、奖励模型,训练时还会引入 value/critic 去估计回报。它的好处是灵活,可以接复杂奖励,但工程链路长、训练不稳、成本高。PPO 的典型目标会带一个裁剪项,避免新旧策略差太远。

DPO 不显式训练奖励模型再跑 RL,而是直接利用 chosen/rejected 偏好对优化策略模型。它把偏好学习转成一个分类式目标,本质上在提升 chosen 相对 rejected 的概率,同时参考模型提供锚点。相比 PPO,它更简单、更稳定,代价是适用前提更依赖高质量偏好对。

GRPO 更强调组内相对比较。不是只比较一个 chosen 和一个 rejected,而是在一组候选里根据相对优劣优化策略。它适合推理、数学、代码这类可以对多候选进行相对打分的场景,尤其是当绝对奖励难定义,但组内排序信号比较可靠时更有优势。

9. PPO 里的 critic model 起什么作用

critic 的作用是估计 value,也就是当前状态下未来预期回报。因为直接用整段回答的最终奖励更新每个 token,方差会非常大,训练不稳定。critic 提供一个 baseline,用来计算 advantage:

这样策略梯度更新的信号会更稳。简单理解,critic 不是告诉模型“什么答案更好”,而是在告诉模型“当前这一步的实际收益,相对预期来说是超了还是没达到”。如果没有 critic,PPO 仍然能做,但方差会高很多,尤其在长序列生成里更明显。

10. 如果 PPO 训练里 KL 发散了,通常怎么处理

KL 发散说明当前策略偏离参考模型太快,常见原因是学习率过大、奖励尺度过强、采样温度过高、reward hacking,或者优势估计不稳。处理上通常先从最直接的地方下手:降学习率、增大 KL 系数、做 reward

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

AI-Agent面试实战专栏 文章被收录于专栏

本专栏聚焦 AI-Agent 面试高频考点,内容来自真实面试与项目实践。系统覆盖大模型基础、Prompt工程、RAG、Agent架构、工具调用、多Agent协作、记忆机制、评测、安全与部署优化等核心模块。以“原理+场景+实战”为主线,提供高频题解析、标准答题思路与工程落地方法,帮助你高效查漏补缺.

全部评论
佬 考虑我司么 考虑的话 可以看我主页帖子
点赞 回复 分享
发布于 04-08 10:49 上海

相关推荐

05-22 00:29
浙江大学 C++
很多设计题聊到最后,都会慢慢绕回“稳定性”这件事。一开始还没那么强烈的意识。觉得 Agent 设计题重点应该是架构怎么拆、工具怎么接、Memory 怎么存、RAG 怎么做,或者 Multi-Agent 怎么协作。结果面多了之后发现,这些东西聊着聊着,最后几乎都会被问到同一个方向:如果它出错了怎么办,如果它一直跑不回来怎么办,如果线上真的来很多请求怎么办。后来想想其实也挺正常。因为 Agent 这类系统和传统那种很固定的后端流程不太一样,它天然就更“不稳”。传统系统很多时候是你把规则写死,输入和输出路径都比较确定;但 Agent 不是,它中间有模型决策、有工具调用、有外部数据、有多轮上下文,链路一长,变量就会变得很多。只要中间任何一层开始飘,整个结果都可能跟着飘。所以面试官前面问你架构、问你 Tool Calling、问你 Memory,看起来像是在听方案,实际上很快就会往后问:这个方案怎么稳住。比如你说模型自己判断该调哪个工具,那下一句就可能是,如果它调错了呢;你说用了 Multi-Agent 去拆任务,那后面可能就会接,如果其中一个 Agent 输出错了,下游怎么处理;你说接了知识库做 RAG,那也很容易继续问,检索到了不相关内容怎么办,知识库更新不及时怎么办。Agent 设计题里最容易被忽略的一点就是,很多人会默认自己是在讲“理想链路”,但面试官其实更关心“非理想链路”。也就是说,你当然可以先讲正常情况下系统怎么跑,但如果你只会讲 happy path,后面大概率就会被一直追问。因为真正难的地方,本来就不是“它能不能工作一次”,而是“它能不能在复杂场景里别太失控”。而且这种稳定性,还不是只指服务别挂这么简单。它其实分很多层。最表层的是接口别报错、调用别超时,再往里一点是模型别乱调工具、别死循环、别把参数填错;再往后一点,是上下文别越跑越脏,Memory 别把旧信息带偏,多个 Agent 之间别互相污染;再工程一点,还会涉及监控、降级、重试、回滚、权限控制这些。现在再被问这种题,我会更有意识地去想两条线:一条是系统怎么工作,另一条是系统怎么出问题。很多时候后者反而更重要,因为 Agent 这类东西你只要真的做过一点,就会知道它最麻烦的从来不是第一轮跑通,而是后面怎么别失控。
点赞 评论 收藏
分享
评论
点赞
5
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务