LLM面面观之RLHF平替算法DPO

【LLM第三篇】名词解释:RLHF——chatgpt的功臣 RLHF (Reinforcement Learning from Human Feedback) ,直译为:“来自人类反馈的强化学习”。RLHF是一种结合了强化学习和人类反馈的机器学习方法,主要用于训练大模型以执行复杂的任务,尤其是当这些任务难以通过传统的奖励函数来精确定义时。 阅读详情

1. 背景

最近本qiang~老看到一些关于大语言模型的DPO、RLHF算法,但都有些云里雾里,因此静下心来收集资料、研读论文,并执行了下开源代码,以便加深印象。

此文是本qiang~针对大语言模型的DPO算法的整理,包括原理、流程及部分源码。

2. DPO vs RLHF

上图左边是RLHF算法,右边为DPO算法,两图的差异对比即可体现出DPO的改进之处。

1. RLHF算法包含奖励模型(reward model)和策略模型(policy model,也称为演员模型,actor model),基于偏好数据以及强化学习不断迭代优化策略模型的过程。

2. DPO算法不包含奖励模型和强化学习过程,直接通过偏好数据进行微调,将强化学习过程直接转换为SFT过程,因此整个训练过程简单、高效,主要的改进之处体现在于损失函数。

PS:

1. 偏好数据,可以表示为三元组(提示语prompt, 良好回答chosen, 一般回答rejected)。论文中的chosen表示为下标w(即win),rejected表示为下标l(即lose)

2. RLHF常使用PPO作为基础算法,整体流程包含了4个模型,且通常训练过程中需要针对训练的actor model进行采样,因此训练起来,稳定性、效率、效果不易控制。

1) actor model/policy model: 待训练的模型,通常是SFT训练后的模型作为初始化

2) reference model: 参考模型,也是经SFT训练后的模型进行初始化,且通常与actor model是同一个模型,且模型冻结,不参与训练,其作用是在强化学习过程中,保障actor model与reference model的分布差异不宜过大。

3) reward model: 奖励模型,用于提供每个状态或状态动作对的即时奖励信号。

4) Critic model: 作用是估计状态或状态动作对的长期价值,也称为状态值函数或动作值函数。

3. DPO算法仅包含RLHF中的两个模型,即演员模型(actor model)以及参考(reference model),且训练过程中不需要进行数据采样。

4. RLHF可以参考附件中的引文

3. DPO的损失函数

如何将RLHF的Reward model过程简化为上式,作者花了大量篇幅进行了推导,感兴趣的读者可以参考附件DPO的论文。

DPO算法的目的是最大化奖励模型(此处的奖励模型即为训练的策略),使得奖励模型对chosen和rejected数据的差值最大,进而学到人类偏好。

上式的后半部分通过对数函数运算规则,可以进行如下转化。

转化后的公式和源代码中的计算函数中的公式是一致的。

其中左半部分是训练的policy模型选择chosen优先于rejected,右半部分是冻结的reference模型选择chosen优先于rejected,二者的差值可类似于KL散度,保障actor模型的分布与reference模型的分布不会有较大的差异。

4. 微调流程

上图展示了DPO微调的大致流程,其中Trained LM即为策略模型,Frozen LM即为参考模型,二者均是先进行SFT微调得到的模型进行初始化,其中Trained LM需要进行训练,Frozen LM不参与训练。

两个模型分别针对chosen和rejected进行预测获取对应的得分,再通过DPO的损失函数进行损失计算,进而不断的迭代优化。

5. 源码

源码参考代码:https://github.com/eric-mitchell/direct-preference-optimization

5.1 DPO损失函数

def preference_loss(policy_chosen_logps: torch.FloatTensor,
                    policy_rejected_logps: torch.FloatTensor,
                    reference_chosen_logps: torch.FloatTensor,
                    reference_rejected_logps: torch.FloatTensor,
                    beta: float,
                    label_smoothing: float = 0.0,
                    ipo: bool = False,
                    reference_free: bool = False) -> Tuple[torch.FloatTensor, torch.FloatTensor, torch.FloatTensor]:
    # policy_chosen_logps: 训练模型对于chosen经过log后logits
	# policy_rejected_logps: 训练模型对于rejected经过log后logits
	# reference_chosen_logps: 训练模型对于chosen经过log后logits
	# reference_rejected_logps: 训练模型对于rejected经过log后logits
	# beta: policy和reference的差异性控制参数
	
	# actor模型选择chosen优先于rejected
    pi_logratios = policy_chosen_logps - policy_rejected_logps
	# reference模型选择chosen优先于rejected
    ref_logratios = reference_chosen_logps - reference_rejected_logps

    if reference_free:
        ref_logratios = 0
	
	# 差值可类似于KL散度,保障actor模型的分布与reference模型的分布不会有较大的差异
    logits = pi_logratios - ref_logratios  # also known as h_{\pi_\theta}^{y_w,y_l}

    if ipo:
        losses = (logits - 1/(2 * beta)) ** 2  # Eq. 17 of https://arxiv.org/pdf/2310.12036v2.pdf
    else:
        # Eq. 3 https://ericmitchell.ai/cdpo.pdf; label_smoothing=0 gives original DPO (Eq. 7 of https://arxiv.org/pdf/2305.18290.pdf)
		# label_smoothing为0,对应的DPO论文的算法
        losses = -F.logsigmoid(beta * logits) * (1 - label_smoothing) - F.logsigmoid(-beta * logits) * label_smoothing
	
	# chosen和rejected的奖励
    chosen_rewards = beta * (policy_chosen_logps - reference_chosen_logps).detach()
    rejected_rewards = beta * (policy_rejected_logps - reference_rejected_logps).detach()

    return losses, chosen_rewards, rejected_rewards

5.2 批次训练过程

def get_batch_metrics(self, batch: Dict[str, Union[List, torch.LongTensor]], loss_config: DictConfig, train=True):
	"""Compute the SFT or DPO loss and other metrics for the given batch of inputs."""

	if loss_config.name in {'dpo', 'ipo'}:
		# policy模型针对chosen和rejected进行预测
		policy_chosen_logps, policy_rejected_logps = self.concatenated_forward(self.policy, batch)
		with torch.no_grad():
			# reference模型针对chosen和rejected进行预测
			reference_chosen_logps, reference_rejected_logps = self.concatenated_forward(self.reference_model, batch)

		if loss_config.name == 'dpo':
			loss_kwargs = {'beta': loss_config.beta, 'reference_free': loss_config.reference_free, 'label_smoothing': loss_config.label_smoothing, 'ipo': False}
		elif loss_config.name == 'ipo':
			loss_kwargs = {'beta': loss_config.beta, 'ipo': True}
		else:
			raise ValueError(f'unknown loss {loss_config.name}')
		# 损失计算
		losses, chosen_rewards, rejected_rewards = preference_loss(
			policy_chosen_logps, policy_rejected_logps, reference_chosen_logps, reference_rejected_logps, **loss_kwargs)

		reward_accuracies = (chosen_rewards > rejected_rewards).float()

	elif loss_config.name == 'sft':
		policy_chosen_logits = self.policy(batch['chosen_input_ids'], attention_mask=batch['chosen_attention_mask']).logits.to(torch.float32)
		policy_chosen_logps = _get_batch_logps(policy_chosen_logits, batch['chosen_labels'], average_log_prob=False)

		losses = -policy_chosen_logps

	return losses.mean()

5.3 LM的交叉熵计算

def _get_batch_logps(logits: torch.FloatTensor, labels: torch.LongTensor, average_log_prob: bool = False) -> torch.FloatTensor:
    # 经模型后的logits进行批量计算logps
	
    assert logits.shape[:-1] == labels.shape
	
	# 基于先前的token预测下一个token
    labels = labels[:, 1:].clone()
    logits = logits[:, :-1, :]
    loss_mask = (labels != -100)

    # dummy token; we'll ignore the losses on these tokens later
    labels[labels == -100] = 0
	
	# 交叉熵函数
    per_token_logps = torch.gather(logits.log_softmax(-1), dim=2, index=labels.unsqueeze(2)).squeeze(2)

    if average_log_prob:
        return (per_token_logps * loss_mask).sum(-1) / loss_mask.sum(-1)
    else:
        return (per_token_logps * loss_mask).sum(-1)

5.4 其他注意

1. hugging face设置代理

源码会从hugging face中下载英文语料和模型,由于网络限制,因此设置代理映射,将HF_ENDPOINT设置为https://hf-mirror.com,即设置: os.environ['HF_ENDPOINT'] = 'https://hf-mirror.com'

2. 如果仅想要熟悉DPO整体流程,可以下载较小的生成式模型,如BLOOM 560M,GPT2等

6. 总结

一句话足矣~

本文主要针对大语言模型的DPO算法的整理,包括原理、流程及部分源码。

此外,建议大家可以针对源码进行运行,源码的欢迎大家一块交流。

7. 参考

(1) RLHF:ChatGPT技术原理解析:从RL之PPO算法、RLHF到GPT4、instructGPT-优快云博客

(2) DPO论文: https://arxiv.org/pdf/2305.18290v2.pdf

(3) DPO代码: https://github.com/eric-mitchell/direct-preference-optimization

(4) DPO理解1:https://medium.com/@joaolages/direct-preference-optimization-dpo-622fc1f18707

(5) DPO理解2: https://zhuanlan.zhihu.com/p/669825918

 

RLHF(从人类反馈中进行强化学习)详解(一) RLHF,即Reinforcement Learning from Human Feedback(从人类反馈中进行强化学习),是一种结合了机器学习中的强化学习算法与人类主观判断的训练技术。这种方法旨在利用人类的直觉和判断力来指导人工智能系统学习更复杂、更贴近人类期望的行为模式,尤其是在自然语言处理(NLP)和决策制定等领域。 阅读详情

相关推荐

基于人类反馈的强化学习(RLHF)入门指南

基于人类反馈的强化学习(RLHF)入门指南

安静的软件工程师 2497

什么是RLHF

*字面翻译:**RLHF (Reinforcement Learning from Human Feedback) ,即以强化学习方式依据人类反馈优化语言模型。强化学习从人类反馈(RLHF)是一种先进的AI系统训练方法,它将强化学习与人类反馈相结合。它是一种通过将人类训练师的智慧和经验纳入模型训练过程中,创建更健壮的学习过程的方法。该技术涉及使用人类反馈创建奖励信号,然后通过强化学习来改善模型的行为。

盖瑞理的智汇说 1万+

一文读懂「RLHF」基于人类反馈的进行强化学习

RLHF就是基于人类反馈(Human Feedback)对语言模型进行强化学习(Reinforcement Learning),和一般的fine-tune过程乃至prompt tuning自然也不同。多种策略产生样本并收集人类反馈训练奖励模型训练强化学习策略,微调 LM首先需要一个预训练语言模型,通过大量的语料去训练出基础模型,对于ChatGPT来说就是GPT-3。还有一个可选的Human Augmented Text,又叫Fine-tune。

女王の专属领地 5万+

SFT、RLHF、DPO、IFT —— LLM 微调的进化之路

• SFT、RLHF 和 DPO 都是先估计 LLMs 本身的偏好,再与人类的偏好进行对齐;• SFT 只通过 LLMs 生成的下一个单词进行估计,而 RLHF 和 DPO 通过 LLMs 生成的完整句子进行估计,显然后者的估计会更准确;• 虽然 RLHF 和 DPO 取得比 SFT 好的结果,但代价是高昂的数据构造和计算资源开销;

mama19971023的博客 1355

RLHF:人类反馈强化学习的核心原理

1. 背景介绍 1.1 人工智能的发展 随着计算机技术的飞速发展,人工智能(AI)已经成为了当今科技领域的热门话题。从早期的基于规则的专家系统,到现在的深度学习和强化学习,人工智能技术不断地突破自身的局限,为人类带来了前所未有的便利。 1.2 强化学习的

AI天才研究院 909

STM32F407硬件SPI驱动ADS1220避坑指南:从寄存器读不到数据到采样值异常的完整解决流程

本文详细解析了STM32F407硬件SPI驱动ADS1220的常见问题与解决方案,包括SPI配置、寄存器读取异常、采样值优化等关键环节。通过CubeMX配置技巧和Keil调试经验,帮助开发者快速排查从通信失败到数据异常的各种问题,实现高精度数据采集系统的稳定运行。

weixin_26878995的博客 157

大模型 | 通俗理解RLHF基础知识以及完整流程

AI大模型作为人工智能领域的重要技术突破,正成为推动各行各业创新和转型的关键力量。抓住AI大模型的风口,掌握AI大模型的知识和技能将变得越来越重要。学习AI大模型是一个系统的过程,需要从基础开始,逐步深入到更高级的技术。这里给大家精心整理了一份全面的AI大模型学习资源,包括:AI大模型全套学习路线图(从入门到实战)、精品AI大模型学习书籍手册、视频教程、实战学习、面试题等,资料免费分享!

老皮的博客 5802

保姆级教程:彻底清理Win11更新缓存并解除外设,一次搞定0xc1900101更新错误

本文提供了一套完整的Win11更新报错0xc1900101解决方案,涵盖软件环境净化和硬件设备隔离。通过终止干扰进程、重置更新组件、清理临时文件以及断开外设等步骤,有效提升更新成功率。特别强调外设驱动兼容性对解决0xc1900101错误的关键作用。

weixin_33483304的博客 417

使用DPO将LLM与人类偏好对齐

预训练为理解语言奠定了基础。监督微调/指令微调教会模型对特定指令做出适当的响应。RHFL将模型的响应与道德和以人为中心的标准对齐,增强了模型在实际应用中的可靠性和安全性。端到端LLM训练流程(图片来源在另一个摘要任务中,他们以Reddit的论坛帖子作为输入 X*,然后策略必须生成帖子主要观点的摘要 Y*。他们在这个实验中使用了Reddit TL;DR摘要数据集以及已经收集到的人类偏好。同样地,首先对Reddit的回复进行监督微调,以学习生成摘要。

数智笔记 3413

揭秘 Chat Template 如何驱动 AI Agent?以Qwen3为例详解LLM的聊天模板

bos_token: null (没有使用特殊的文档开始符)eos_token<|im_end|>(作为每个对话回合的结束符)pad_token: 对话回合开始<|im_end|>: 对话回合结束非特殊但关键的控制 Token (在词汇表中定义): 包裹模型生成的工具调用请求。: 包裹外部工具返回的执行结果。<think></think>: 包裹模型的内部思考或推理过程。

ljp1919的专栏 1352

一文读懂AI协同办公领域发展和趋势

协同办公,又称OA,是指企业内部或外部各类人员之间利用信息技术来进行协作工作的一种形式。这种协作工作既可以由直接员工进行,也可以来自外部的咨询机构、合作伙伴或联营企业。协同办公的优势在于可以对资源进行有效管理和配置,各部门之间可以建立良好的协作关系,跨部门更好地实现资源共享。

女王の专属领地 2357

RLHF 和 DPO:简化和增强语言模型的微调

人类反馈强化学习 (RLHF) 是人工智能领域的一种前沿方法,它利用人类偏好和指导来训练和改进机器学习模型。RLHF的核心是一种机器学习范式,它结合了强化学习和监督学习的元素,使人工智能系统能够以更加人性化的方式学习和做出决策。RLHF的重要性在于它有可能解决人工智能中的一些基本挑战,例如需要模型来理解和尊重人类的价值观和偏好。传统的强化学习模型通过与环境交互产生的奖励来学习,而 RLHF 则不同,它引入了人类反馈作为宝贵的指导来源。

yanqianglifei的专栏 3852

YOLOv12改进策略【Neck】| arXiv 2024 MAFPN:多分支辅助特征金字塔网络 | 通过双向辅助融合与异构卷积机制,解决传统PAFPN多尺度特征融合不充分与小目标检测不足问题

本文记录的是利用MAFPN颈部结构改进YOLOv12的目标检测网络模型。通过引入双向辅助融合机制优化特征处理流程,在自底向上路径利用 SAF 模块融合主干浅层特征与颈部输出,并保留浅层空间信息,为小目标检测提供更丰富细节;自顶向下路径通过 AAF 模块建立密集连接,聚合浅层高 / 低分辨率层、同级层及前层特征,均衡各层通道数后实现多向梯度信息交互,增强中 / 大目标特征表达。将其应用到中,解决传统特征金字塔在多尺度信息整合中的不足,提升多尺度目标检测的精度与特征表达的丰富性。Multi-Branch Aux

Limiiiing的博客 1254

详解DPO过程及其损失的计算

数据集构建:首先,通过对同一问题的不同回复进行标注,生成“chosen”(选择的)和“rejected”(拒绝的)样本,以反映人类偏好。模型训练使用预训练语言模型进行监督微调。生成成对响应,并由人类标注偏好。利用标注好的偏好数据集优化策略模型。迭代更新:通过不断的迭代和更新,得到与人类偏好一致的最优策略模型。DPO通过直接利用人类偏好数据来优化策略模型,简化了传统强化学习中的复杂过程。其损失函数基于简单而有效的数学原理,不仅提高了训练效率,还确保了模型能够稳定地学习到符合人类偏好的策略。

具身机器人和通用AI 3208

用Obsidian搭建个人知识库:AI时代如何构建你的第二大脑

AI 时代,真正有价值的不只是获取知识,而是沉淀属于自己的知识体系。本文从 Obsidian 安装、目录设计、双向链接、插件推荐到 AI 联动、多端同步,手把手教你打造高效、可持续进化的个人知识库,让知识真正为你所用。🧠

XiaoqiangClub的博客 466

Python图像处理之光斑分析

光斑是工程中经常出现的图像数据,其特点是目标明确,分布清晰。对光斑图像的分析,主要包括质心定位、目标截取以及半径拟合等。

微小冷的学习笔记 2857

RLHF的替代之DPO原理解析:从RLHF、Claude的RAILF到DPO、Zephyr

今年5月份,斯坦福的一些研究者提出了RLHF的替代算法:直接偏好优化(Direct Preference Optimization,简称DPO),其对应论文为《那其与ChatGPT所用的RLHF有何本质区别呢,简言之RLHF将奖励模型拟合到人类偏好数据集上,然后使用RL方法比如PPO算法优化语言模型的策略,以输出可以获得高奖励的responses(同时不会偏离原始SFT模型太远)

结构之法 算法之道 2万+

【OpenClaw从入门到精通】第09篇:企业级实践——将OpenClaw接入钉钉,打造7×24小时数字员工(2026实测版)

本文聚焦OpenClaw的企业级落地实践,以“招聘数字专员”为核心场景,完整演示从钉钉接入到全流程自动化的实现路径。内容涵盖企业级部署架构设计、前置环境搭建、核心技能开发、流程串联、安全权限管控及运维监控六大模块,详解简历解析、岗位匹配、外呼集成、CRM同步、日历提醒等关键技能的构建逻辑与代码实现。借鉴中关村科金、网易智企的企业级实践经验,重点突破企业知识融合、安全权限管控、业务系统连接三大核心门槛,提供可直接参考的配置示例与操作步骤。所有技术方案均基于公开文档与实测验证,兼顾新手入门与进阶实操。

专注于人工智能、软件开发、工控自动化、工厂数字化及智能化等领域,希望和大家共同进步! 1169

【LLM】大模型之RLHF和替代方法(DPO、RAILF、ReST等)

SFT使用交叉熵损失函数,目标是调整参数使模型输出与标准答案一致,不能从整体把控output质量,RLHF(分为奖励模型训练、近端策略优化两个步骤)则是将output作为一个整体考虑,优化目标是使模型生成高质量回复。 启发1:像可以用6b、66b依次得到差一点、好一点的target构造排序数据集,进行DPO直接偏好学习或者其他RLHF替代方法(RAILF、ReST等),比直接RLHF更方便训练 启发2:为了减少幻觉(如拒绝回答),可以构造排序数据集(如good response为拒绝话术,bad respo

发现问题,并解决问题,批判性思维 1万+

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

DPO讲解

PPO算法的pipeline冗长,涉及模型多,资源消耗大,且训练极其不稳定。DPO是斯坦福团队基于PPO推导出的优化算法,去掉了RW训练和RL环节,只需要加载一个推理模型和一个训练模型,直接在偏好数据上进行训练即可:[外链图片转存中…(img-zz2PfNyG-1702835338094)]moreLDPO​πθ​;

Swift's Blog 3241

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

别再栽跟头了!腾讯二面DPO算法把我问懵了,现在一文详解,赶紧补课!

摘要:DPO(直接偏好优化)是一种高效的语言模型训练方法,通过最小化特殊损失函数使模型输出更符合人类偏好。相比PPO、RLHF等方法,DPO具有计算效率高、训练简单、开销小等优势。其核心原理结合了KL散度(衡量概率分布差异)和Bradley-Terry模型(处理配对比较数据),通过数学推导形成最终损失函数。该函数可在单次前向传播中计算,适用于大规模偏好数据训练。文章详细解析了损失函数的推导过程,包括KL散度约束和奖励值计算,并介绍β超参数对模型优化的调节作用。

2401_85375151的博客 1523

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

大模型入门(六)—— RLHF微调大模型

所以价值的计算如下:核心是下面的delta的计算,除了考虑到当前的时刻的奖励值,还考虑到了未来时刻的输出的奖励值nextvalues(只不过这里的奖励值是由critic网络直接输出的每个token对应的分数)。从上图可以看出,给定一个输入x,会生成两个文本y11和y22,一个来自于初始的模型,另一个来自于微调的模型,微调的模型生成的文本还会进入到奖励模型中打分输出rθ,而初始模型和微调的模型生成的结果会用KL散度约束它们的分布,确保模型不会太偏离原来的模型,并且能输出高质量的回复。

chaishen10000的专栏 6853

深入浅出讲 RLHF(RL with human feedback)

RLHF 是一种基于强化学习的算法,通过结合人类专家的知识和经验来优化智能体的学习效果。与传统的强化学习算法相比,RLHF 不仅考虑到了智能体的行为奖励,还融合了人类专家的反馈信息,使得模型能够更快地学习到有效的策略。RLHF 是一种创新的强化学习算法,能够结合智能体自主学习和人类专家反馈两种不同的策略,加速模型的训练并提高模型的性能。与传统的强化学习算法相比,RLHF 具有更快的训练速度、更高的性能和更强的可解释性,为实际应用带来更多可能性。

m0_72410588的博客 4182

速通LLM——SFT、RLHF、对齐、RAG、微调大扫盲

LLM(large language model)技术发展到今天,已经有许多代码和权重都开源的模型(如llama2等)供开发者下载使用。语言模型的本质是通过算法预测下一个位置上出现概率最高的字或词,LLM的预训练阶段通常是无监督或自监督的,例如通过bert模型完成类似于完型填空的任务,数据通常来源于互联网上的大量预料。预训练后的LLM已经具备了基础的语言理解或预测能力,但可能存在输出不符合人类表达习惯或道德准则,或在特定场景或垂直领域(比如数学计算,推理等)中的表现不尽人意等问题。这就需要对预训练后的大模

2401_85379281的博客 5597

RLHF知识

然而,对生成结果的评估是主观和依赖上下文的,这些结果难以用现有的基于规则的文本生成指标 (如 BLUE 和 ROUGE) 来衡量。除了评估指标,现有的模型通常以预测下一个单词的方式和简单的损失函数 (如交叉熵) 来建模,没有显式地引入人的偏好和主观意见。因此,训练阶段,如果直接用人的偏好(或者说人的反馈)来对模型整体的输出结果计算reward或loss,显然是要比上面传统的“给定上下文,预测下一个词”的损失函数合理的多。:即使用强化学习的方法,利用人类反馈信号直接优化语言模型。

bbbeoy的专栏 1298

小学生也能听得懂的大模型 - Transformer 1

参考 [小学生也能听得懂的大模型 Transformer 1]

2401_85325557的博客 1737
上一篇: LLM面面观之LLM上下文扩展方案
下一篇: LLM面面观之MoE
mengrennwpu
博客等级 码龄15年 262粉丝 87原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mengrennwpu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值