From 2edfb76f7a56da5c6362fe11495fbb1e228b78dc Mon Sep 17 00:00:00 2001 From: KMnO4-zx <1021385881@qq.com> Date: Mon, 9 Dec 2024 17:43:53 +0800 Subject: [PATCH] Add reward model --- docs/chapter7/7.1 强化学习的目标.md | 2 ++ docs/chapter7/7.2 奖励模型.md | 45 ++++++++++++++++++++++++++++ docs/chapter7/data/preference.json | 42 ++++++++++++++++++++++++++ docs/chapter7/images/7.1-1.png | Bin 0 -> 21783 bytes 4 files changed, 89 insertions(+) create mode 100644 docs/chapter7/7.2 奖励模型.md create mode 100644 docs/chapter7/data/preference.json create mode 100644 docs/chapter7/images/7.1-1.png diff --git a/docs/chapter7/7.1 强化学习的目标.md b/docs/chapter7/7.1 强化学习的目标.md index e7afe6f..9ce73c0 100644 --- a/docs/chapter7/7.1 强化学习的目标.md +++ b/docs/chapter7/7.1 强化学习的目标.md @@ -15,6 +15,8 @@ - 价值函数(Value Function) :这是一种对策略的评估工具,旨在预测从当前状态出发,长期来看能够获得的总奖励。值函数帮助智能体不仅考虑当前步骤的奖励,而且能更好地权衡短期和长期的收益。 - 模型(Model) :在有些强化学习系统中,我们会建立一个环境模型,帮助智能体预见其动作的结果。这在很多复杂计算情况下非常有用。 +![Reinforcement Learning](./images/7.1-1.png) + 这些元素共同作用,帮助智能体通过不断地在虚拟环境中试错来学习最佳的行动策略。在强化学习中,智能体是学习和决策的主体。它通过以下步骤与环境进行交互: 1. 观察状态 :智能体首先观察当前的状态(State)。 diff --git a/docs/chapter7/7.2 奖励模型.md b/docs/chapter7/7.2 奖励模型.md new file mode 100644 index 0000000..785efe8 --- /dev/null +++ b/docs/chapter7/7.2 奖励模型.md @@ -0,0 +1,45 @@ +# 7.2 奖励模型 + +在自然语言处理领域,大语言模型(如Llama 系列、Qwen系列等)已经展现了强大的文本理解和生成能力。然而,这些预训练模型并不总是能直接满足特定的业务需求和人类价值观。为此,人们通常需要对预训练模型进行“指令微调”(Instruction Tuning),即向模型提供特定的指令(prompts)和示例,使其在对话、问答、文本生成等任务中表现得更符合人类期望。 + +在完成初步的指令微调后,我们还想要使模型的回答不仅正确,还能最大程度上满足人类的审美、价值观和安全标准。为此,引入了强化学习与人类反馈(Reinforcement Learning from Human Feedback, RLHF)的概念。在 RLHF 中,我们会先从人类标注者那里获得对模型回答的偏好(例如,给出多个模型回答,让人类标注者对它们进行排名),然后通过这些反馈来指导模型学习,从而不断提高模型生成内容与人类偏好的契合度。 + +为了在 RLHF 流程中自动对模型的回答进行“打分”(赋予奖励),我们需要构建一个专门的奖励模型(Reward Model)。这个奖励模型会根据人类标注的数据进行训练,并在实际部署中独立对模型输出进行自动评分,从而减少持续人工参与的成本和延迟。 + +## 7.2.1 数据集构建 + +在构建奖励模型(Reward Model)之前,我们首先需要准备高质量的人类反馈数据集。此数据集的核心目标是为每条给定的提示(prompt)提供多个候选回答(completion),并由人类标注者对这些回答进行细致的评定与排序。通过对回答的对比和筛选,我们得以为机器模型提供明确的参考标准,帮助其进一步学习在给定任务下如何生成更符合人类期望的输出。 + +可以按照以下步骤进行数据收集: + +1. 收集初始回答:首先,我们需要从一个已经过基本微调的“大模型”(往往是具有一定指令理解和生成能力的预训练模型)中,为一组精心设计的提示生成多条回答。这些回答将作为后续人类标注工作的基础。 + + +2. 人工标注与评估:拥有多条候选回答后,我们邀请专业标注人员或众包标注者对每条回答的质量进行评价。这些评估通常会基于一系列预先设计的评价标准,如回答的准确性、完整性、上下文相关性、语言流畅度以及是否遵循道德与安全准则。对不同回答的比较与排序帮助我们识别最佳和最差的回答,从而形成有价值的训练数据。 + +3. 数据格式化与整理:标注完成后,我们将数据进行整理与格式化,通常采用 JSON、CSV 或其他便于计算机处理的结构化数据格式。数据集中需明确标识每个问题(prompt)、其对应的多个回答(completions),以及人类标注者对这些回答的选择(如标记为 "chosen" 的最佳答案与 "rejected" 的较差答案)。这些标记信息可直接作为奖励模型学习的监督信号,使其在训练中自动倾向于生成高质量回答。 + +下面是一个简单的数据示例,其中展示了两个问题(question)及其对应的回答和人类评价结果。通过 "chosen" 与 "rejected" 字段的对比,我们可以直观地看出哪条回答更为优质。 + +```json +[ + { + "question": "Python中的列表是什么?", + "chosen": "Python中的列表是一种有序的可变容器,允许存储多个元素,并且可以通过索引访问。", + "rejected": "Python中的列表用于存储数据。" + }, + { + "question": "Python中的元组是什么?", + "chosen": "Python中的元组是一种有序的不可变容器,允许存储多个元素,并且一旦创建就不能修改。", + "rejected": "Python中的元组用于存储数据。" + } +] +``` + +在上述示例中,人类标注者认为 "chosen" 字段下的回答相对于对应的 "rejected" 回答在描述、准确性和信息量等方面都更为优质。例如,对于列表的定义,"chosen" 答复更清晰地解释了列表的特征(有序、可变、支持索引访问),而非仅仅停留在“用于存储数据”这种笼统描述。 + + +## 7.2.2 奖励模型训练 + +我们可以借助大模型强化学习框架 TRL(Transformer Reinforcement Learning)来训练奖励模型。TRL 是一个基于强化学习的训练框架,旨在通过人类反馈指导模型生成更符合人类期望的回答。在 TRL 中,我们会将奖励模型作为一个独立的组件,用于评估模型生成的回答,并根据评估结果给予奖励或惩罚。 + diff --git a/docs/chapter7/data/preference.json b/docs/chapter7/data/preference.json new file mode 100644 index 0000000..ed14b5b --- /dev/null +++ b/docs/chapter7/data/preference.json @@ -0,0 +1,42 @@ +[ + {"question":"什么是神经网络?", "chosen":"神经网络是一种模拟人脑神经结构的计算模型,通常用于处理复杂的模式识别和分类任务。","rejected":"神经网络用于处理数据。"}, + {"question":"如何选择合适的机器学习模型?", "chosen":"选择合适的机器学习模型可以通过考虑问题的特性、数据量和模型的复杂性来实现。","rejected":"选择合适的模型是很重要的。"}, + {"question":"什么是特征工程?", "chosen":"特征工程是机器学习中准备数据的一步,包括选择、提取和转换输入特征。","rejected":"特征工程是机器学习的一部分。"}, + {"question":"Python适合初学者吗?", "chosen":"Python非常适合初学者,因为其代码简洁易读,并且拥有广泛的社区支持。","rejected":"Python适合初学者。"}, + {"question":"什么是监督学习?", "chosen":"监督学习是一种机器学习方法,其中模型通过已知的输入输出对进行训练,以预测未知数据的结果。","rejected":"监督学习是机器学习的一种方法。"}, + {"question":"如何实现数据可视化?", "chosen":"数据可视化可以通过使用Matplotlib、Seaborn或其他可视化库来生成图表和图形。","rejected":"数据可以用图形展示。"}, + {"question":"Python有哪些常用的库?", "chosen":"Python常用的库包括NumPy用于数值计算,Pandas用于数据处理,以及Matplotlib用于可视化。","rejected":"Python有很多库。"}, + {"question":"什么是无监督学习?", "chosen":"无监督学习是一种机器学习方法,通过分析数据的内在结构进行模式识别和聚类,而无需已标记的数据。","rejected":"无监督学习不需要标签。"}, + {"question":"如何处理数据的缺失值?", "chosen":"处理缺失值的方法包括删除含有缺失值的记录、用均值填充缺失值或使用预测模型进行插补。","rejected":"缺失值需要被处理。"}, + {"question":"什么是支持向量机?", "chosen":"支持向量机是一种用于分类和回归分析的监督学习算法,通过在高维空间中寻找最佳分隔超平面实现。","rejected":"支持向量机是一种算法。"}, + {"question":"深度学习中的反向传播是什么?", "chosen":"反向传播是一种用于训练神经网络的算法,通过计算损失函数的梯度调整权重。","rejected":"反向传播用于训练网络。"}, + {"question":"如何评价机器学习模型的性能?", "chosen":"模型的性能可以通过准确率、精确率、召回率和F1分数等指标进行评价。","rejected":"模型性能需要被评估。"}, + {"question":"Python如何管理包和依赖?", "chosen":"Python使用工具如pip或conda来管理包和依赖,方便安装和更新。","rejected":"Python用pip管理包。"}, + {"question":"如何提升深度学习模型的性能?", "chosen":"提升深度学习模型的性能可以通过架构调整、数据扩增和优化算法调整等实现。","rejected":"模型性能可以被提高。"}, + {"question":"什么是数据标准化?", "chosen":"数据标准化是调整数据尺度的方法,将特征调整到同一范围以提高模型训练效果。","rejected":"标准化用于调整数据。"}, + {"question":"机器学习中的过拟合是什么?", "chosen":"过拟合是指模型在训练集上表现良好,但在未见数据上效果不佳,通常由于模型过于复杂。","rejected":"过拟合影响模型性能。"}, + {"question":"什么是逻辑回归?", "chosen":"逻辑回归是一种用于分类问题的回归分析方法,通过逻辑函数将输入映射到一个概率。","rejected":"逻辑回归用于分类。"}, + {"question":"如何处理数据中的异常值?", "chosen":"处理异常值的方法包括删除异常值、替换或对其进行数据转换。","rejected":"异常值需要被处理。"}, + {"question":"Python的面向对象编程特性怎么样?", "chosen":"Python支持面向对象编程,允许定义类和对象并支持继承和多态。","rejected":"Python支持OOP。"}, + {"question":"有什么方法可以提高机器学习模型的泛化能力?", "chosen":"可以通过降低模型复杂度、使用正则化、以及增加训练数据等方法来提高模型的泛化能力。","rejected":"泛化能力需要被提高。"}, + {"question":"什么是卷积神经网络(CNN)?", "chosen":"卷积神经网络是一种专门用于处理具有网格数据的深度学习算法,广泛应用于图像和视频识别。","rejected":"卷积神经网络用于图像处理。"}, + {"question":"如何评估回归模型的性能?", "chosen":"回归模型的性能可以通过均方误差(MSE)、均方根误差(RMSE)和R^2分数等指标进行评估。","rejected":"回归模型需要性能评估。"}, + {"question":"什么是特征选择?", "chosen":"特征选择是在训练模型之前选择最具信息量的特征,以提高模型的性能并减少复杂度。","rejected":"特征选择能提升性能。"}, + {"question":"如何使用Python进行文本分析?", "chosen":"可以使用Python的NLTK或spaCy库进行文本分析,处理自然语言数据。","rejected":"Python用于文本分析。"}, + {"question":"机器学习中的泛化是什么?", "chosen":"泛化是指模型在处理未见数据时的表现,是评价模型性能的重要标准。","rejected":"泛化影响模型性能。"}, + {"question":"什么是随机森林?", "chosen":"随机森林是一种集成学习方法,通过构建多棵决策树来提高分类或回归性能。","rejected":"随机森林是集成方法。"}, + {"question":"如何处理数据中的类别变量?", "chosen":"处理类别变量可以采用编码方法如独热编码或标签编码,将类别转换为数值形式。","rejected":"类别变量需要编码。"}, + {"question":"什么是梯度下降算法?", "chosen":"梯度下降是一种优化算法,用于通过不断调整参数以最小化损失函数。","rejected":"梯度下降用于优化。"}, + {"question":"为什么使用正则化技术?", "chosen":"正则化用于减少模型的过拟合,通过在损失函数中增加惩罚项限制权重的大小。","rejected":"正则化减少过拟合。"}, + {"question":"如何处理时间序列数据?", "chosen":"处理时间序列数据时,通常需要考虑时间依赖性,可能使用平滑、差分等技术来提高分析效果。","rejected":"时间序列需要特殊处理。"}, + {"question":"什么是集成学习?", "chosen":"集成学习是一种将多个学习器结合以提高整体预测性能的机器学习方法。","rejected":"集成学习结合多模型。"}, + {"question":"如何通过Python实现自动化测试?", "chosen":"可以使用Python的unittest或pytest库实现自动化测试,以保证代码质量。","rejected":"Python可以测试代码。"}, + {"question":"什么是主成分分析(PCA)?", "chosen":"主成分分析是一种降维技术,通过对数据进行线性变换来提取主要特征。","rejected":"PCA用于降维。"}, + {"question":"如何提升算法的计算效率?", "chosen":"可以通过优化算法实现、利用并行计算、以及高效的数据结构来提升计算效率。","rejected":"计算效率需要提升。"}, + {"question":"什么是生物信息学?", "chosen":"生物信息学是结合生物学和信息技术来处理生物数据的学科,涉及基因组、蛋白质组等领域的研究。","rejected":"生物信息学处理生物数据。"}, + {"question":"如何实现数据采样?", "chosen":"数据采样可以通过随机采样、分层采样等方法来从数据集中选择部分样本进行分析。","rejected":"数据采样用于选择样本。"}, + {"question":"金融科技的关键技术有哪些?", "chosen":"金融科技的关键技术包括区块链、人工智能、大数据分析和云计算。","rejected":"金融科技涉及技术。"}, + {"question":"Python的垃圾回收机制是什么?", "chosen":"Python的垃圾回收机制通过引用计数和垃圾回收器(GC)来管理内存释放。","rejected":"Python自动管理内存。"}, + {"question":"如何使用随机搜索调优超参数?", "chosen":"随机搜索通过在参数空间中随机选择一组参数组合来找到较优的模型配置。","rejected":"随机搜索优化参数。"}, + {"question":"什么是过采样和下采样?", "chosen":"过采样和下采样是处理不平衡数据集的方法,通过增加少数类样本或减少多数类样本来平衡类别分布。","rejected":"采样处理不平衡数据。"} +] \ No newline at end of file diff --git a/docs/chapter7/images/7.1-1.png b/docs/chapter7/images/7.1-1.png new file mode 100644 index 0000000000000000000000000000000000000000..e00be4256a135f58e984bccd563c2fceb7543564 GIT binary patch literal 21783 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

%K5}(!puTO{3mEd}= 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 WUM){bbMH%J00K`}KbLh*2~7Z1i$P=n literal 0 HcmV?d00001