Reward Modelling(RM)and Reinfo

Reward Modelling(RM)and Reinfo

文章标签数据语言模型强化学习文章分类jQuery前端开发阅读数254

Reward Modelling(RM)and Reinforcement Learning from Human Feedback(RLHF)for Large language models(LLM)技术初探

一、RLHF 技术的背景

OpenAI 推出的 ChatGPT 对话模型掀起了新的 AI 热潮,它面对多种多样的问题对答如流,似乎已经打破了机器和人的边界。这一工作的背后是大型语言模型 (Large Language Model,LLM) 生成领域的新训练范式:RLHF (Reinforcement Learning from Human Feedback) ,即以强化学习方式依据人类反馈优化语言模型。

过去几年里各种 LLM 根据人类输入提示 (prompt) 生成多样化文本的能力令人印象深刻。然而,对生成结果的评估是主观和依赖上下文,例如,

  • 我们希望模型生成一个有创意的故事
  • 一段真实的信息性文本
  • 可执行的代码片段

这些结果难以用现有的基于规则的文本生成指标 (如  BLEU 和  ROUGE) 来衡量

除了评估指标,现有的模型通常以预测下一个单词的方式和简单的损失函数 (如交叉熵) 来建模,没有显式地引入人的偏好和主观意见

为了解决上述问题,如果我们 用生成文本的人工反馈作为性能衡量标准,或者更进一步用该反馈作为损失来优化模型,那不是更好吗?这就是 RLHF 的思想:使用强化学习的方式直接优化带有人类反馈的语言模型

RLHF 使得在一般文本数据语料库上训练的语言模型能和复杂的人类价值观对齐。

二、RLHF 技术分解 

RLHF 是一项涉及多个模型和不同训练阶段的复杂概念,根据OpenAI的思路,RLHF分为三步:

  1. 收集人类反馈,并根据人工标注数据(prompt-completions pairs),预训练/微调一个语言模型
  2. 用多个模型(可以是初始模型、finetune模型、人工等等)给出同一个问题的多个回答,然后人工给这些问答对按一些标准(可读性、无害、正确性blabla)进行排序,聚合问答数据并训练一个奖励模型(Reward Model,RM)来进行打分
  1. 问题一,为什么不人工直接打分?因为打分是主观的需要归一化,而排序一般大家会有共同的结论:对同一个问题,A和B哪个回答更好。人类反馈的不是标准答案,而是对更好的答案的偏好,这种偏好以排序的形式展现。事实上多数问题没有标准最好的答案。
  2. 问题二,有了一组一组的偏序(A>B, A>C, C>B)怎么得到每个回答的奖励分数?这一步在Hug的博客里用了Elo排名系统,打网游排位赛、看足球篮球比赛的可能都知道。把每个偏序当作比赛,把奖励分数看作排位分,这里我们是用Elo得到一个完整排序后,经过归一化得到了奖励分数。
  3. 问题三,这个RM用什么模型?只要用Elo系统打分后归一化,然后直接上个LM做回归就行,可以从零训练也可以用老LM做finetune。这里有个有趣的事情在于,做问答和做评分都需要输入所有的文本,实际上两个模型的容量(或者说理解能力)应该是差不多的,而现有的RLHF模型都使用了两个不同大小的模型。
  4. 问题四,有没有其他方式训练打分的模型?张俊林老师指出对偏序直接用pairwise learning to rank做打分,大概更符合常规的思路,具体效果如何就需要看实践。
  1. 用强化学习 (RL) 方式微调 Pretrain LM,得到一个SFT-LM

参考链接:

https://zhuanlan.zhihu.com/p/591474085
https://zhuanlan.zhihu.com/p/613315873?utm_id=0

三、收集人类反馈,并根据人工标注数据(prompt-completions pairs by human feedback),预训练/微调一个语言模型(SFT LLM)

可用于收集人类反馈的模型主要有两类:

  • 预训练模型(Base LLM),即只经过预料库训练而不经过 fine-tune 的模型
  • 监督基线模型(SFT LLM),即在预训练模型基础上使用测试数据集 fine-tune 的模型

对于上述模型产生的结果,由专门的研究人员 labeler 去进行相对好坏的的评价,最终得到”prompt-completions pairs by human feedback“。接下来可以使用经典的微调方法训练一个sft语言模型。对这一步的模型,

  • OpenAI 在其第一个流行的 RLHF 模型  InstructGPT 中使用了较小版本的 GPT-3
  • Anthropic 使用了 1000 万 ~ 520 亿参数的 Transformer 模型进行训练
  • DeepMind 使用了自家的 2800 亿参数模型  Gopher

这里可以用额外的文本或者条件对这个 LM 进行微调,例如

  • OpenAI 对 “更可取” (preferable) 的人工生成文本进行了微调
  • Anthropic 按 “有用、诚实和无害” 的标准在上下文线索上蒸馏了原始的 LM

注意,这个sft-llm的训练只是一个起点,之后我们要训练一个 RM奖励模型,然后用RM奖励模型继续训练这个sft-llm。

当RM奖励模型参与到SFT训练中,会将RM中包含的人类倾向经验注入到SFT反馈中,最终我们得目标是得到一个高质量的 RLHF-LLM。

四、训练奖励模型(Reward Model)

接下来,我们会基于 sft-llm 来生成训练 奖励模型 (RM,也叫偏好模型) 的数据(prompt对应的completions),并在这一步引入人类的偏好信息(打分和排名)。 

0x1:我们为什么需要 reward model?

下图展示当前GPT技术面向特定任务应用的开发范式,

在一般情况下,SFT已经可以满足大多数场景下的需求(我们要做的主要是数据提纯和数据蒸馏),但如果对模型生成质量有更高的需求,则需要采用基于人类反馈的强化学习(RLHF)。

当SFT Model已经可以较好地生成多种不同风格的响应回答,但出于法律、道德、人类价值观、特定领域任务要求等原因,我们需要引导SFT Model选择某种特定风格的回答。因此,我们需要一种向 LLM 提供反馈的方法,以帮助他们了解什么是有用的,什么是无用的,以便我们可以将其输出与公认的人类价值观(例如诚实、乐于助人和无害)保持一致。

综上,出于以下几种原因,我们需要训练一个RM Model:

  • 基础SFT-LLM虽然满足基本质量要求,但是依然不完全符合人类对特定任务、价值观、道德、法律相关的约束的倾向
  • 出于工作量原因,在训练期间由人类直接提供此类反馈是不切实际的,因此我们需要一个可以模仿人类偏好的模型,以便在训练对齐 LLM 时提供奖励。
  • 不管是在模型调优还是模型上线后的日常性能监控中,我们都需要一个自动化的评测标准和评测流程,以此持续监控模型的泛化和衰退情况。

以上正是 LLM 对齐中奖励模型的目标。

0x2:构建 reward model 的挑战

  • Amount of feedback data(反馈数据量):生成足够准确的奖励模型所需的数量和种类的人类反馈数据具有挑战性。
  • Feedback distribution(反馈分布):理想情况下,我们希望奖励模型不仅能准确预测模型所见数据的奖励,还能准确预测训练数据分布 (OOD) 之外的数据的奖励。
  • Reward gaming(奖励博弈):如果奖励函数中存在多个循环黑洞,在 RL 期间,代理可以利用它们获得更多奖励,而不会收敛到预期值。

0x3:Reward Modeling

RM 的训练是 RLHF 区别于旧范式的开端。这一模型接收一系列文本(prompt-completions pairs)并返回一个标量奖励(scores),数值上对应人的偏好。

  • 我们可以用端到端的方式用 LM 建模
  • 或者用模块化的系统建模(比如对输出进行排名,再将排名转换为奖励),这一奖励数值将对后续无缝接入现有的 RL 算法至关重要。

关于模型选择方面,

  • RM 可以是另一个经过微调的 LM
  • 也可以是根据偏好数据从头开始训练的 LM

例如 Anthropic 提出了一种特殊的预训练方式,即用偏好模型预训练 (Preference Model Pretraining,PMP) 来替换一般预训练后的微调过程。因为前者被认为对样本数据的利用率更高。但对于哪种 RM 更好尚无定论。

关于训练文本方面,RM 的提示(prompt) - 生成(completions)对(prompt-completions pairs)文本是经过人工打标后的包含completions打分或者completions pair排序的增强文。例如下图所示

关于训练奖励数值方面,这里需要人工对 SFT-LM 生成的回答进行打分,

  • 一种想法是直接对文本标注分数来训练 RM,但是由于标注者的价值观不同导致这些分数未经过校准并且充满噪音。
  • 另一种想法是通过排名,比较多个模型对同一个prompt的completions输出并,然后使用  Elo 系统建立一个完整的排名。这些不同的排名结果将被归一化为用于训练的标量奖励值。

关于刻画文本质量的标量数字,用公式表示如下:

  • x 表示 prompt
  • y 表示 completions
  • rθ 表示参数为 θ 的奖励模型的打分值scores
  • σ 表示sigmoid函数

奖励模型接收一系列文本(good or bad prompt-completions pair)并返回一个标量奖励(scores),数值上对应人的偏好。

这个过程中一个有趣的产物是目前成功的 RLHF 系统使用了和生成模型具有 不同 大小的 LM,例如

  • OpenAI 使用了 175B 的 LM 和 6B 的 RM
  • Anthropic 使用的 LM 和 RM 从 10B 到 52B 大小不等
  • DeepMind 使用了 70B 的 Chinchilla 模型分别作为 LM 和 RM

一种直觉是,偏好模型和生成模型需要具有类似的能力来理解提供给它们的文本,即裁判的能力和运动员要大差不差,才能准确无误地对运动员的表现进行评判。

0x4:策略模型训练

首先将初始语言模型的微调任务建模为强化学习(RL)问题,因此需要定义策略(policy)、动作空间(action space)和奖励函数(reward function)等基本要素。

  • 策略就是基于该语言模型,接收prompt作为输入,然后输出一系列文本(或文本的概率分布)
  • 动作空间就是词表所有token在所有输出位置的排列组合(单个位置通常有50k左右的token候选)
  • 观察空间则是可能的输入token序列(即prompt),显然也相当大,为词表所有token在所有输入位置的排列组合
  • 奖励函数(reward)则是基于之前我们训好的RM模型计算得到初始reward,再叠加上一个约束项来

整个过程如下所示: 

而对于强化学习的算法,常见的可行方案是使用策略梯度强化学习 (Policy Gradient RL) 算法、近端策略优化 (Proximal Policy Optimization,PPO) 微调初始 LM 的部分或全部参数。 

1、语言模型的强化学习建模

设词表为

,语言模型为,那么对于长度为 n 的序列的概率分布可表示为

  • 输入空间
  • 输出空间

对于输入

可能长度为1000的prompt

可能是长度为100的completions。

那么由prompt x 生成completions y 的的概率可表示为:

初始化策略

,然后使用PPO算法更新策略π,奖励函数定义为 r,则奖励的期望值可表示为:

接下来,PPO 算法优化奖励函数计算步骤如下:

  • 将prompt x输入初始 LM 和当前微调的 LM,分别得到了输出文本 y1,y2,将来自当前策略的文本传递给 RM 得到一个标量的奖励 rθ
  • 将两个模型的生成文本进行比较,计算差异的惩罚项,通常设计为输出词分布序列之间的Kullback–Leibler (KL) 散度的缩放,即,其中
  • 这一项被用于惩罚 RL 策略在每个训练批次中生成大幅偏离初始模型,以确保模型输出合理连贯的文本。如果去掉这一惩罚项可能导致模型在优化中生成乱码文本来愚弄奖励模型提供高奖励值。 

最后根据 PPO 算法,我们按当前批次数据的奖励指标进行优化 (来自 PPO 算法 on-policy 的特性) 。PPO 算法是一种信赖域优化 (Trust Region Optimization,TRO) 算法,它使用梯度约束确保更新步骤不会破坏学习过程的稳定性,另外也可以使用 A2C (synchronous advantage actor-critic) 算法来优化梯度。 

0x5:RM & 策略模型训练整体流程

  1. 从Base LLM(例如GTP-3.5、LLaMA、通义千问)开始,收集提示(prompts)和响应回答(completions)
  2. 通过人工反馈,给每个prompt的不同completions进行两两比较排名,表明人类人对不同响应回答(completions)的偏好,并通过ELO等算法将两两排序转化为不同completions对应的score分值
  3. 训练一个RM模型(一般情况下也是一个LLM),输入”prompt-completions pair with score labels数据集“继续训练,训练得到的RM模型,具备输出给定prompt-completions pair的score分值的能力
  4. 策略模型训练
  1. 让我们首先将微调任务表述为 RL 问题。首先,该 策略 (policy) 是一个接受提示并返回一系列文本 (或文本的概率分布) 的 LM。这个策略的 行动空间 (action space) 是 LM 的词表对应的所有词元 (一般在 50k 数量级) ,观察空间 (observation space) 是可能的输入词元序列,也比较大 (词汇量 ^ 输入标记的数量) 。奖励函数 是偏好模型和策略转变约束 (Policy shift constraint) 的结合。
  2. PPO 算法确定的奖励函数具体计算如下:
  1. 将提示 x 输入初始 LM 和当前微调的 LM,分别得到了输出文本 y1, yw
  2. 将来自当前策略的文本传递给 RM 得到一个标量的奖励 
  1. 最后根据 PPO 算法,我们按当前批次数据的奖励指标进行优化 (来自 PPO 算法 on-policy 的特性) 。PPO 算法是一种信赖域优化 (Trust Region Optimization,TRO) 算法,它使用梯度约束确保更新步骤不会破坏学习过程的稳定性。DeepMind 对 Gopher 使用了类似的奖励设置,但是使用 A2C ( synchronous advantage actor-critic) 算法来优化梯度
  1. 最后得到一个符合人类偏好的RM神经网络,接下去就可以利用 RM 输出的奖励(对不同completions的打分),自动化筛选出更符合人类偏好的completions,以此不断微调优化 SFT-LM

参考链接:

https://karpathy.ai/stateofgpt.pdf
https://zhuanlan.zhihu.com/p/616708590
https://openreview.net/forum?id=10uNUgI5Kl
https://huggingface.co/blog/zh/rlhf
https://huggingface.co/datasets/CarperAI/openai_summarize_comparisons/viewer/CarperAI--openai_summarize_comparisons/train?row=0
https://zhuanlan.zhihu.com/p/450690041

  

五、训练一个简单的Reward Model

选择WebGPT数据集作为reward model的语料集,如下所示,每一个prompt都对应了一个completions列表。

('The USA entered World War I because Germany attempted to enlist Mexico as an ally, and for what other reason?',["The United States entered World War I because of Germany's use of submarine warfare against ships in the Atlantic Ocean, which was hurting American exports to Europe. Additionally, Germany tried to enlist Mexico as an ally against the United States, an event which convinced American businessmen and industrialists that the United States should enter the war.",'The USA entered World War I because Germany attempted to enlist Mexico as an ally and for the Zimmerman Telegram.']
)
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

人类反馈强化后的数据集如下:

从数据集中选出人类反馈的最佳回答的 处理逻辑如下:

class WebGPT:name = "openai/webgpt_comparisons"def __init__(self, split: str = "train"):super().__init__()self.split = splitdataset = load_dataset(self.name, split=self.split)self.dataset_dict = defaultdict(dict)for item in dataset:post_id = item["question"]["id"]if post_id not in self.dataset_dict.keys():self.dataset_dict[post_id] = {"full_text": item["question"]["full_text"],"answers": [],}if item["score_0"] > 0:answers = [item["answer_0"], item["answer_1"]]elif item["score_0"] < 0:answers = [item["answer_1"], item["answer_0"]]else:answers = []answers = [re.sub(r"\[\d+\]", "", answer) for answer in answers]answers = [".".join([sent.strip() for sent in answer.split(".")])for answer in answers]if answers:self.dataset_dict[post_id]["answers"].extend(answers)else:_ = self.dataset_dict.pop(post_id)self.post_ids = list(self.dataset_dict.keys())def __len__(self):return len(self.post_ids)def __getitem__(self, idx):question, answers = self.dataset_dict[self.post_ids[idx]].values()return question, answers
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.

然后,在将数据输入模型之前,使用整理功能进行额外的数据准备,例如标记化和填充。 根据数据集,每个提示的完成次数可能会有所不同,因此我将维护一个额外的变量 batch_k_lens 以指示批次中每个提示的可用完成次数。 这将帮助我们计算损失。

@dataclass
class RMDataCollator:tokenizer: PreTrainedTokenizermax_length: int = 512def format_example(self, example, eos, prompt=False):sp_token = SPECIAL_TOKENS["prompter"] if prompt else SPECIAL_TOKENS["assistant"]return "{}{}{}".format(sp_token, example, eos)def process_example(self, example):trunc_len = 0eos = self.tokenizer.eos_tokenprefix, outputs = exampleprefix = self.format_example(example, eos, prompt=True)outputs = [self.format_example(output, eos) for output in outputs]prefix_tokens = self.tokenizer.encode(prefix)input_ids, attention_masks = [], []for output in outputs:out_tokens = self.tokenizer.encode(output,)if len(prefix_tokens) + len(out_tokens) > self.max_length:trunc_len = max(0, len(prefix_tokens) + len(out_tokens) - self.max_length)prefix_tokens = prefix_tokens[trunc_len:]out_tokens = prefix_tokens + out_tokensout_tokens = out_tokens[: self.max_length]pad_len = self.max_length - len(out_tokens)attn_masks = [1] * len(out_tokens) + [0] * pad_lenout_tokens += [self.tokenizer.pad_token_id] * pad_leninput_ids.append(out_tokens)attention_masks.append(attn_masks)return input_ids, attention_masksdef __call__(self, examples):batch_k_lens = [0]input_ids, attention_masks = [], []for i, example in enumerate(examples):inp_ids, attn_masks = self.process_example(example)input_ids.extend(inp_ids)attention_masks.extend(attn_masks)batch_k_lens.append(batch_k_lens[i] + len(inp_ids))return {"input_ids": torch.tensor(input_ids),"attention_mask": torch.tensor(attention_masks),"k_lens": batch_k_lens,}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.

对于reward model模型架构,有两种选择:

  • 使用 BERT、Roberta 等纯编码器模型,并在顶部添加一个线性层。 任何支持 AutoModelForSequenceClassification 的模型都可以。
  • 使用像 GPT 这样的纯解码器架构,并在顶部添加一个自定义线性层。 仅解码器模型更具可扩展性。 任何支持 AutoModelForCausalLM 的模型都可以。

我现在选择 GPTNeoXModel,我将对最后一个隐藏层进行平均池化,并添加顶部的自定义头部以生成标量输出。 

@dataclass
class GPTNeoxRMOuptput(ModelOutput):"""Reward Model Output"""logits: torch.FloatTensor = Noneclass GPTNeoXRM(GPTNeoXPreTrainedModel):""" """def __init__(self,config,):super().__init__(config)self.gpt_neox = GPTNeoXModel(config)self.out_layer = nn.Linear(config.hidden_size, 1)def forward(self,input_ids,attention_mask,**kwargs,):return_dict = (kwargs.get("return_dict")if kwargs.get("return_dict") is not Noneelse self.config.use_return_dict)outputs = self.gpt_neox(input_ids,attention_mask,return_dict=return_dict,**kwargs,)hidden_states = outputs[0]if attention_mask is None:hidden_states = hidden_states.mean(dim=1)else:hidden_states = (hidden_states * attention_mask.unsqueeze(-1)).sum(dim=1) / attention_mask.sum(dim=1).unsqueeze(-1)lm_logits = self.out_layer(hidden_states)if not return_dict:return (lm_logits,) + outputs[1:]return GPTNeoxRMOuptput(logits=lm_logits)
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.

对于损失函数,我将使用额外的 L2 归一化因子,以防止过度拟合。 对于每个提示prompt的k个响应回答completions,存在

个两两比较。

损失是针对每个提示单独计算的,并取平均值以获得批量平均损失。

class RMLoss(nn.Module):""" """def __init__(self,reduction=None,beta=0.001,):super().__init__()self.reduction = reductionself.beta = betadef forward(self,logits,k_lens=None,):total_loss = []indices = list(zip(k_lens[:-1], k_lens[1:]))for start, end in indices:combinations = torch.combinations(torch.arange(start, end, device=logits.device), 2)positive = logits[combinations[:, 0]]negative = logits[combinations[:, 1]]l2 = 0.5 * (positive**2 + negative**2)loss = (-1 * nn.functional.logsigmoid(positive - negative) + self.beta * l2).mean()total_loss.append(loss)total_loss = torch.stack(total_loss)if self.reduction == "mean":total_loss = total_loss.mean()return total_loss
view raw
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.

最后,我们会将所有这些连同训练参数一起传递给自定义训练器来训练和评估我们的模型。

记住!我们最终的目标是训练出一个”裁判“,这个”裁判“代表了人类反馈的倾向,它可以对prompt的completions进行打分和排序(本质上是实现训练集蒸馏)。

一旦训练出一个好的”裁判“,LLM SFT的开发就可以进入一个正向循环,一个整体的开发流程如下:

  1. 基于Base LLM进行prompt engining,生成一批初始数据集data_v1
  2. 基于初始数据集对Base LLM进行SFT,得到一个sft-llm_v1
  3. 引入领域业务专家,对初始数据集进行倾向打标和排序,得到一份强化数据集data_v2
  4. 基于强化数据集data_v2,训练一个reward model,reward_v1
  5. 基于sft-llm_v1进行prompt engining,得到一份新的prompt-completions数据集data_v3
  6. 基于reward_v1对data_v3进行打标和排序,得到data_v4
  7. 引入领域业务专家,对data_v4进行倾向打标和排序,得到一份强化数据集data_v5
  8. 基于强化数据集data_v5,训练一个reward model,reward_v2
  9. 基于data_v5对sft-llm_v1进行SFT,得到一个sft-llm_v2
  10. .....
  11. 反复循环上述步骤,通过领域业务专家的反馈,不断优化reward model和sft llm
  12. 当reward model的性能和人工专家基本齐平时,后续的训练将不再需要人工的介入,可以让reward model自动对sft llm的completions进行打分和排序,整个训练优化过程进入全自动化 

参考链接:

https://explodinggradients.com/reward-modeling-for-large-language-models-with-code
https://huggingface.co/datasets/openai/summarize_from_feedback/viewer/axis/test?row=0
  • 1.
  • 2.

六、通过trlx的rlhf案例学习一个完整的RLHF开发流程

以trlx的  rlhf案例 为例,深入了解整个过程。

0x1:零样本冷启动

对于大多数特定领域任务LLM的开发来说,项目的初期基本都是从零样本冷启动开始的。因此,task-LLM的第一步就是数据准备工作。

我们分两种情况讨论零样本启动流程。

1、基础大模型能力相对目标任务领域有泛化能力较差  

  • 已经具备至少一种基础大模型,可以输入prompt生成completions
  • 基础大模型对于目标任务领域的泛化能力相对较弱,生成的completions不太符合目标任务领域的需求

当处于这种情况时,我们需要分别采取prompt engining、样本提纯蒸馏等过程,循环迭代不断扩展我们的基础样本。

  1. 步骤一:prompt engining(prompt工程):
  1. 用Base LLM,对种子样本进行prompt,人工对打标结果进行挑选修改
  2. 持续子步骤a,不断筛选出高质量的prompt指令集
  3. 用最优的prompt指令集,输入通义千问基模型,得到”基础prompt-completions数据集“
  1. 步骤二:sample distillation(样本蒸馏/提纯)
  1. 人工从基础prompt-completions数据集中,挑选出符合最低质量要求的good case样本,进行样本提纯
  2. 人工对不符合要求的bad case样本进行completions修正,使其符合最低质量要求,以保证总体样本数量基本不变
  3. 样本蒸馏/提纯过程可以分批,不断增量扩展,不断给模型注入泛化能力。每轮迭代不断累计,得到一批数量不断扩大的”提纯prompt-completions数据集“
  1. 步骤三:sft train(微调自监督训练)
  1. 基于”提纯prompt-completions数据集“,基于Base-LLM进行微调,得到微调后模型sft-llm
  1. 步骤四:rm奖励模型开发 & RLHF人工反馈训练
  1. 开发评测网页版,人可以通过看模型的输出给模型打分,
  2. 基于sft-llm微调模型打标新样本,对同一个prompt生成2条以上completions,生成“sft-prompt-completions数据集”
  3. 人工选取good case、bad case,对“sft-prompt-completions数据集”进行排序rank,通过elo转换为不同completions的分数,喂给rm模型进行学习,得到一个奖励模型
  4. 通过ppo train,对sft-llm进行fine-tune,最终得到RLHF-llm
  1. 步骤五:循环进行prompt engining和RLHF过程
  1. 基于RLHF-llm充当步骤一的基础模型
  2. 重新循环进行新一轮的prompt engining(prompt工程)
  3. 重新循环进行新一轮的sample distillation(样本蒸馏/提纯)
  4. 重新循环进行新一轮的sft train(微调自监督训练)
  5. 重新循环进行新一轮的rm奖励模型开发 & RLHF人工反馈训练
  1. 步骤六:auto RLHF
  1. 奖励模型可作为模型上线后的自动化评估机制和反馈机制
  2. 当rm性能只够好时(已经充分拟合人工的倾向经验),人工介入程度可以减少,让奖励模型rm来辅助sft-model不断循环微调,最终得到SOTA-RLHF model

2、基础大模型能力能够生成基本符合相对目标任务领域的样本

  • 已经具备至少一种基础大模型,可以输入prompt生成completions
  • 基础大模型对于目标任务领域的泛化能力表现优异,生成的completions对于目标领域任务质量很高

当处于这种情况时,sample distillation(样本蒸馏/提纯)这一步可以基本省略,其他步骤保持不变。

基础大模型生成的completions基本都满足目标任务领域的最低质量要求,重点的工作就要放在强化奖励模型的开发和RLHF微调训练上。

0x2:训练基础SFT模型

我们使用” CarperAI/openai_summarize_tldr“,基于” EleutherAI/gpt-j-6B“进行SFT,

# 单GPU
cd sft/ && CUDA_VISIBLE_DEVICES=0 python3 train_gptj_summarize.py
# 多GPU
cd sft/ && deepspeed train_gptj_summarize.py
  • 1.
  • 2.
  • 3.
  • 4.

通过sft,得到了一个和summarize任务对齐了的sft-llm。

0x3:奖励模型(Reward Model)的训练

1、数据集准备工作(completions打分、排名)

在一般的项目开发中,我们需要雇佣数据承包商或者外包人员,对base-llm、sft-llm、人工等方式生成的completions进行排序(rank)。这一步非常消耗时间,但对最终模型的效果来说又非常重要。

这里我们使用hugeface上开源的” CarperAI/openai_summarize_comparisons“进行演示。

2、hugface数据集(已完成rank排序的completions数据集)加载与预处理

使用开源 数据集,创建一个由字典的组成的列表,每一个字典有3个key,

  • prompt:原始prompt
  • chosen:该prompt对应的summary被人工打标为”接受“,即代表rank更高
  • rejected:该prompt对应的summary被人工打标为”拒绝“,即代表rank更低 

def create_comparison_dataset(path="CarperAI/openai_summarize_comparisons", split="train"):dataset = load_dataset(path, split=split)pairs = []for sample in tqdm(dataset):pair = {}prompt = sample["prompt"]chosen_summary = sample["chosen"]rejected_summary = sample["rejected"]if chosen_summary == rejected_summary:continueif len(chosen_summary.split()) < 5 or len(rejected_summary.split()) < 5:continuepair["chosen"] = prompt + "\n" + chosen_summarypair["rejected"] = prompt + "\n" + rejected_summarypairs.append(pair)return pairs
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.

拼接prompt-completions pair对,

  • prompt+chosen
  • prompt+rejected

针对处理完的 pair 对,进行分词处理,并构造成可供训练的数据集形式

class PairwiseDataset(Dataset):def __init__(self, pairs, tokenizer, max_length):self.chosen_input_ids = []self.chosen_attn_masks = []self.rejected_input_ids = []self.rejected_attn_masks = []for pair in tqdm(pairs):chosen, rejected = pair["chosen"], pair["rejected"]chosen_encodings_dict = tokenizer("<|startoftext|>" + chosen + "<|endoftext|>",truncation=True,max_length=max_length,padding="max_length",return_tensors="pt",)rejected_encodings_dict = tokenizer("<|startoftext|>" + rejected + "<|endoftext|>",truncation=True,max_length=max_length,padding="max_length",return_tensors="pt",)self.chosen_input_ids.append(chosen_encodings_dict["input_ids"])self.chosen_attn_masks.append(chosen_encodings_dict["attention_mask"])self.rejected_input_ids.append(rejected_encodings_dict["input_ids"])self.rejected_attn_masks.append(rejected_encodings_dict["attention_mask"])def __len__(self):return len(self.chosen_input_ids)def __getitem__(self, idx):return (self.chosen_input_ids[idx],self.chosen_attn_masks[idx],self.rejected_input_ids[idx],self.rejected_attn_masks[idx],)
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.

上述数据不便于同时输入模型进行训练,需要进一步整理数据,构造成如下形式:

  • input_ids: 将 input_ids 的 chosen 和 rejected 在0维度上 concat
  • attention_mask: 将 attention_mask 的 chosen 和 rejected 在0维度上 concat
  • labels: 将 chosen 部分置0,rejected 部分置1,并在0维度上concat。这一步完成stirng label的数字向量化。

需要说明的是,经过上述处理,batch size 变为原来的2倍

class DataCollatorReward:def __call__(self, data):batch = {}batch["input_ids"] = torch.cat([f[0] for f in data] + [f[2] for f in data])batch["attention_mask"] = torch.cat([f[1] for f in data] + [f[3] for f in data])batch["labels"] = torch.tensor([0] * len(data) + [1] * len(data))return batch
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

3、构建奖励模型

RM 的结构相对简单,即 transformer 结构+线性分类头。

  • transformer使用” CarperAI/openai_summarize_tldr_sft“预训练llm模型,并freeze 70%的神经元不进行参数微调,即保留原始sft-llm对文本的理解能力
  • Linear线性分类器,用于输出dim=1的score分数,用于对completions进行打分

定义loss公式,

  • RM模型对prompt-completions pair预测为chose,则返回0;RM模型对prompt-completions pair预测为rejected,则返回1
  • loss优化函数的目标是让RM输出的0/1,和训练数据的0/1,尽量多的符合接近,符合地越多,loss越小

class GPTRewardModel(nn.Module):def __init__(self, model_path):super().__init__()model = AutoModelForCausalLM.from_pretrained(model_path)self.config = model.config# `gpt-neo(x)` models use `hidden_size` attribute names instead of `n_embd``self.config.n_embd = self.config.hidden_size if hasattr(self.config, "hidden_size") else self.config.n_embdself.transformer = model.transformerself.v_head = nn.Linear(self.config.n_embd, 1, bias=False)self.tokenizer = AutoTokenizer.from_pretrained("EleutherAI/gpt-j-6B")self.tokenizer.pad_token = self.tokenizer.eos_tokenself.PAD_ID = self.tokenizer(self.tokenizer.pad_token)["input_ids"][0]def forward(self,input_ids=None,past_key_values=None,attention_mask=None,token_type_ids=None,position_ids=None,head_mask=None,inputs_embeds=None,mc_token_ids=None,labels=None,return_dict=False,output_attentions=False,output_hidden_states=False,):loss = Nonetransformer_outputs = self.transformer(input_ids,past_key_values=past_key_values,attention_mask=attention_mask,token_type_ids=token_type_ids,position_ids=position_ids,head_mask=head_mask,inputs_embeds=inputs_embeds,)hidden_states = transformer_outputs[0]rewards = self.v_head(hidden_states).squeeze(-1)chosen_end_scores = []rejected_end_scores = []# Split the inputs and rewards into two parts, chosen and rejectedassert len(input_ids.shape) == 2bs = input_ids.shape[0] // 2chosen = input_ids[:bs]rejected = input_ids[bs:]chosen_rewards = rewards[:bs]rejected_rewards = rewards[bs:]loss = 0inference = Falsefor i in range(bs):if torch.all(torch.eq(chosen[i], rejected[i])).item():c_inds = (chosen[i] == self.PAD_ID).nonzero()c_ind = c_inds[0].item() if len(c_inds) > 0 else chosen.shape[1]chosen_end_scores.append(chosen_rewards[i, c_ind - 1])inference = Truecontinue# Check if there is any padding otherwise take length of sequencec_inds = (chosen[i] == self.PAD_ID).nonzero()c_ind = c_inds[0].item() if len(c_inds) > 0 else chosen.shape[1]r_inds = (rejected[i] == self.PAD_ID).nonzero()r_ind = r_inds[0].item() if len(r_inds) > 0 else rejected.shape[1]end_ind = max(c_ind, r_ind)# Retrieve first index where trajectories divergedivergence_ind = (chosen[i] != rejected[i]).nonzero()[0]assert divergence_ind > 0# Index into the correct rewardsc_truncated_reward = chosen_rewards[i][divergence_ind:end_ind]r_truncated_reward = rejected_rewards[i][divergence_ind:end_ind]# Append the last rewards to the list of end scoreschosen_end_scores.append(c_truncated_reward[-1])rejected_end_scores.append(r_truncated_reward[-1])# Compute loss based on truncated rewards (ignore padding)loss += -torch.log(torch.sigmoid(c_truncated_reward - r_truncated_reward)).mean()loss = loss / bsif not inference:chosen_end_scores = torch.stack(chosen_end_scores)rejected_end_scores = torch.stack(rejected_end_scores)if inference:chosen_end_scores = torch.stack(chosen_end_scores)return {"chosen_end_scores": chosen_end_scores}return {"loss": loss,"chosen_end_scores": chosen_end_scores,"rejected_end_scores": rejected_end_scores,}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.

将以上部分组合起来,即可以训练RM

# Initialize the reward model from the (supervised) fine-tuned GPT-Jmodel = GPTRewardModel("CarperAI/openai_summarize_tldr_sft")# Freeze the first 70% of the hidden layers of the reward model backbonelayers = model.transformer.hnum_layers = len(layers)num_unfrozen = int(0.3 * num_layers)for layer in layers[:-num_unfrozen]:layer.requires_grad_(False)# Create the comparisons datasetsdata_path = "CarperAI/openai_summarize_comparisons"train_pairs = create_comparison_dataset(data_path, "train")val_pairs = create_comparison_dataset(data_path, "test")# Make pairwise datasets for trainingmax_length = 550train_dataset = PairwiseDataset(train_pairs, tokenizer, max_length=max_length)val_dataset = PairwiseDataset(val_pairs, tokenizer, max_length=max_length)# Create the collator to gather batches of pairwise comparisonsdata_collator = DataCollatorReward()Trainer(model=model,args=training_args,train_dataset=train_dataset,compute_metrics=compute_metrics,eval_dataset=val_dataset,data_collator=data_collator,).train()
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.

4、启动BP训练

cd reward_model/ && deepspeed train_reward_model_gptj.py
  • 1.

如果想要加快时间,也可以直接下载hugeface上已经开源的训练好的reward model,

mkdir reward_model/rm_checkpoint
wget https://huggingface.co/CarperAI/openai_summarize_tldr_rm_checkpoint/resolve/main/pytorch_model.bin -O reward_model/rm_checkpoint/pytorch_model.bin
  • 1.
  • 2.

0x4:策略模型(PPO)的训练

由于PPO算法的值函数可以是一个深度学习模型,在本例中则是一个 transformer 模型,策略梯度方法的基本思想将值函数表示为策略参数的某个函数,然后可以根据RM的反馈值进行更新。

1、标准化(Normalization)

由于 reward scores 方差较大,因此需要根据人为结果做差以实现标准化,即

其中

分别表示模型得分和人为得分。代码实现如下:

def reward_fn(samples: List[str]):# get humans summarizesposts = [sample.split('TL;DR')] for sample in samples]ref_samples = [post + 'TL;DR' + post_summ_dict[post] for post in post]samples_encodings = reward_tokenizer(samples)samples_scores = reward_model(**samples_encodings) # get scores from reward model for samplesref_samples_encodings = reward_tokenizer(ref_samples) # get scores from reward model corresponding references samplesref_samples_scores = reward_model(**ref_samples_encodings)norms_rewards = samples_scores - ref_samples_scoresreturn norms_rewards

2、KL 散度(KL Divergence)

当使用 PPO 做 fine-tuning 的时候,summary 由策略(LLM)生成。生成的 summary传到奖励模型生成奖励分,进而更新策略。 由于上述操作是 batch-wise 的,同时由于 RL 训练的噪声很大,特别是在初始阶段,这些可能会导致策略偏移过大。为防止这个问题,引进KL散度作为惩罚项,以避免策略模型偏差过大。

其中

表示奖励模型的输出分数,

表示系数,

表示策略模型,

表示监督模型。

3、启动PPO训练

accelerate launch --config_file configs/default_accelerate_config.yaml trlx_gptj_text_summarization.py
  • 1.

0x5:Results

SFT vs PPO

Model

Rouge-1

Rouge-2

Rouge-L

Average

SFT

0.334

0.125

0.261

0.240

PPO

0.323

0.109

0.238

0.223

ROUGE scores 

Model

Average Reward

Reward Δ

SFT

2.729

-0.181

PPO

3.291

+0.411

Reward scores 

参考链接:

https://huggingface.co/datasets/CarperAI/openai_summarize_comparisons/viewer/CarperAI--openai_summarize_comparisons/train?row=0
https://link.zhihu.com/?target=https%3A//github.com/CarperAI/trlx/tree/main/examples/summarize_rlhf
https://github.com/CarperAI/trlx 
https://github.com/CarperAI/trlx/tree/main/examples/summarize_rlhf

七、RL4LMs - A modular RL library to fine-tune language models to human preferences

参考资料:

https://github.com/allenai/RL4LMs

八、RLHF的局限和未来工作

  • RLHF 范式训练出来的这些模型虽然效果更好,但仍然可能输出有害或事实上不准确的文本。这种不完美则是 RLHF 的长期挑战和优化目标。
  • 在基于 RLHF 范式训练模型时,人工标注的成本是非常高昂的,而 RLHF 性能最终仅能达到标注人员的知识水平。此外,这里的人工标注主要是为RM模型标注输出文本的排序结果,而若想要用人工去撰写答案的方式来训练模型,那成本更是不可想象的,而实际上,对SFT-LLM或者RLHF-LLM来说,真正有价值和重要的信息是人工撰写的completions输出结果。
  • RLHF的流程还有很多值得改进的地方,其中,改进 RL 优化器显得尤为重要PPO 是一种基于信赖域优化的相对较旧的RL算法,但没有其他更好的算法来优化 RLHF 了。

九、Reward Model开发的另一种范式

RM总共有两种作用场景:

  1. 接收prompt-completions pair,给出一个数值评分(或者一个多维度数值向量,由人类专家定义)
  2. 辅助SFT-LLM进行强化学习训练

如果场景1,其实还可以有另一种范式,即通过构造prompt template实现一个“prompt-completions pair文本质量推理链”,prompt template包含如下几个元素:

  • prompt-completions pair输
  • 问题定义
  • 评价标准定义
  • 评价结果输出(可以设计成格式化)

一个例如如下:

登录后复制 

You are a fair AI assistant for checking the quality of the answers of other two AI assistants. [Question] {data['query']}[The Start of Assistant 1's Answer]llama chains: {data['llama_chains']}llama answer: {data['llama_answer']}[The End of Assistant 1's Answer][The Start of Assistant 2's Answer]chatgpt chains: {data['chatgpt_chains']}chatgpt answer: {data['chatgpt_answer']}[The End of Assistant 2's Answer] We would like to request your feedback on the performance of two AI assistants in response to the user question displayed above. Please first judge if the answer is correct based on the question, if an assistant gives a wrong answer, the score should be low.Please rate the quality, correctness, helpfulness of their responses based on the question.Each assistant receives an overall score on a scale of 1 to 10, where a higher score indicates better overall performance, your scores should be supported by reasonable reasons. Please first output a single line containing only two values indicating the scores for Assistant 1 and 2, respectively. The two scores are separated by a space. In the subsequent line, please provide a comprehensive explanation of your evaluation, avoiding any potential bias, and the order in which the responses were presented does not affect your judgement.If the two assistants perform equally well, please output the same score for both of them.

回放中丨2023北京智源大会
https://2023.baai.ac.cn/schedule

智源「悟道3.0」大模型系列问世
https://baai.org/l/27398

Hinton:放弃永生的凡人计算 (附视频)
https://baai.org/l/27397

Yann LeCun:LLM推理能力有限,需要被重新训练
https://baai.org/l/27396

Sam Altman:AI 安全始于足下
https://baai.org/l/27385

David Holz:AI将彻底改变学习、创意和组织
https://baai.org/l/27399

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/30287.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用 RLHF 训练 LLaMA 的实践指南:StackLLaMA

由于LLaMA没有使用RLHF&#xff0c;后来有一个初创公司 Nebuly AI使用LangChain agent生成的数据集对LLaMA模型使用了RLHF进行学习&#xff0c;得到了ChatLLaMA模型&#xff0c;详情请参考&#xff1a;Meta开源的LLaMA性能真如论文所述吗&#xff1f;如果增加RLHF&#xff0c;效…

基于人类反馈的强化学习(RLHF) 理论

gpt 进程 GPT-1 用的是无监督预训练 有监督微调&#xff0c;只有简单的单向语言模型任务&#xff1b;GPT-2用的是纯无监督预训练&#xff0c;使用更多的数据&#xff0c;更大的模型&#xff0c;又新增了几个辅助的训练任务&#xff1b;GPT-3 沿用了 GPT-2 的纯无监督预训练&a…

【疑难杂症】overleaf公式显示异常并且被重复添加至正文内,正文内$符号消失,编译报错Missing $ inserted.inserted text。

问题描述 此问题困扰本人许久&#xff0c;搜索了许多相关情况都没有我这样的。每次编译后&#xff0c;overleaf中的公式会编译错误&#xff0c;并且被莫名其妙地添加到正文中&#xff0c;而且原来引用公式的dollar符号$$也异常消失。 问题举例 原始文本&#xff1a; 编译后…

【ChatGPT】从人类反馈 (RLHF) 中进行强化学习 | Illustrating Reinforcement Learning from Human Feedback (RLHF)

从人类反馈 (RLHF) 中进行强化学习 | Illustrating Reinforcement Learning from Human Feedback (RLHF) 目录

python 用 xlwings 处理 Excel 中的重复数据

xlwings 简介 xlwings 是一个 Python 库。简化了 Python 和 Excel 通信。 xlwings - 让Excel跑得飞快! 本文写作背景 & 需求 & 方案 因前几个月帮在医院工作的朋友现学现卖用VBA写了段程序&#xff0c;处理2个excel文档的数据到第3个Excel文档上&#xff0c;有模板数据…

解决Chrome网页编码显示乱码的问题

解决Chrome网页编码显示乱码的问题 记得在没多久以前&#xff0c;Google Chrome上面出现编码显示问题时&#xff0c;可以手动来调整网页编码问题&#xff0c;可是好像在Chrome 55.0版以后就不再提供手动调整编码&#xff0c;所以如果现在遇到big 5被误判为UTF8的网页问题时&…

全网最详细中英文ChatGPT-GPT-4示例文档-从0到1快速入门语法纠正应用——官网推荐的48种最佳应用场景(附python/node.js/curl命令源代码,小白也能学)

从0到1快速入门语法纠正应用场景 Introduce 简介setting 设置Prompt 提示Sample response 回复样本API request 接口请求python接口请求示例node.js接口请求示例curl命令示例json格式示例 其它资料下载 ChatGPT是目前最先进的AI聊天机器人&#xff0c;它能够理解图片和文字&…

ChatGPT其实无法获得法学保研资格

ChatGPT通过了美国明尼苏达大学法学院4门课程的考试&#xff0c;95个选择题、12个论述题&#xff0c;平均分为C&#xff1b;也通过了宾夕法尼亚大学沃顿商学院的考试&#xff0c;成绩也不错。但是在当下内卷的情形下&#xff0c;ChatGPT的考试成绩不会获得保研资格&#xff0c;…

chatgpt赋能python:Python摄像头运用介绍

Python摄像头运用介绍 Python是一种广泛应用于各种领域的高级编程语言。其中&#xff0c;Python摄像头应用越来越受欢迎&#xff0c;尤其是在计算机视觉和机器学习领域。本文将介绍Python摄像头运用的相关知识。 什么是Python摄像头运用&#xff1f; Python摄像头运用是使用…

NAT技术之NAT server

技术背景&#xff1a; 在很多场景中&#xff0c;比如企业、学校、甚至家里都有一些对外访问的业务提供&#xff0c;比如门户网址、NAS、ERP等&#xff0c;在实际部署中&#xff0c;这些提供访问的服务器都属于内网内&#xff0c;配置的是内网地址&#xff0c;导致的情况是公网…

在群晖NAS上搭建导航页_通过Web Station搭建

一、业务需求 1.1、需求说明 我们在使用群晖NAS的过程中&#xff0c;随着时间的推移会安装各种各样的软件内容和管理工具&#xff0c;而这些内容又都是一些网页界面&#xff08;特别是一些在Docker中搭建的工具&#xff09;时间久了我们也记不住那么多工具的Web界面地址&#…

[NAS] QNAP/威联通 常用设置和操作

&#x1f341;简介 QNap 产品是一种可扩展的数据存储解决方案。它们包括具有 1 到 30 个驱动器托架的设备&#xff0c;并提供 HDMI、Thunderbolt 2 和 USB 3.1 等连接选项&#xff0c;以及 802.11ac/a/n Wi-Fi 和高达每秒 40 Gb 的以太网。内置软件提供基本服务&#xff0c;例如…

详解央行数字货币和数字票据交易平台架构(多图)

独家披露&#xff1a;详解央行数字货币和数字票据交易平台架构(多图) 暴走时评&#xff1a;央行推动的基于区块链的数字票据交易平台已测试成功&#xff0c;由央行发行的法定数字货币已在该平台试运行。作为一种创新的货币和全新的支付体系架构&#xff0c;央行数字货币具有长远…

国家队入场,中国数字资产交易市场或将迎来新一轮“洗牌”

‍ ‍数据智能产业创新服务媒体 ——聚焦数智 改变商业 数字化已经成为中国文化产业的催化剂&#xff0c;一大批文化资源在数字技术的赋能下焕发了崭新的生机。 随着数字化的升级与科技进步&#xff0c;数字经济正在成为改变全球竞争格局的关键力量&#xff0c;各国家都争先出…

浅谈数字人民币什么时候正式推出DCEP钱包在哪里下载

11月23日,澎湃新闻从苏州一位知情人士处独家获悉,继深圳后,苏州将于双十二推出数字人民币红包测试。 上述知情人士告诉澎湃新闻记者,目前苏州相城区已有很多商家已经安装NFC(Near Field Communication,近场通信)二维码,只是支付载体还在测试员中,目前已有测试员体验过数字人民币…

Facebook 数字货币:缘起、意义和后果

来源 | 孟岩的区块链思考 作者 | 孟岩、邵青 出品 | 区块链大本营&#xff08;blockchain_camp&#xff09; 6 月 18日&#xff0c;Facebook 位于瑞士的子公司 Libra Network (天秤座网络&#xff09;将发布其加密数字货币项目白皮书。此前 BBC 报道说这个数字货币叫做 GlobalC…

数字货币钱包基础

我在前面3篇文章讲了区块链基础知识、普通人如何购买以及如何在imtoken里参与ICO。一个核心的问题其实是没有讲到的&#xff0c;我们这些数字货币到底怎么保存&#xff0c;因为之前讲的都是在交易市场上购买比特币、以太币&#xff0c;这些货币被保存在交易市场&#xff0c;本质…

大家知道微信个人收款码限额多少吗

大家知道微信个人收款码限额多少吗 随着移动支付的普及&#xff0c;微信、支付宝等平台已经成为了人们日常生活中不可或缺的支付工具。二维码收款作为这些平台的重要功能之一&#xff0c;可以方便快捷地完成转账和付款操作&#xff0c;受到了越来越多用户的广泛关注和使用。 对…

用户授信额度管理中,会运用到哪些策略?

关注“金科应用研院”&#xff0c;回复“CSDN” 领取风控资料合集 01、授信额度与贷款额度 授信额度是指金融机构能够为借款人提供的最大贷款金额。贷款额度一般是指借款人在金融机构给予的最大贷款金额范围内&#xff0c;实际借贷的金额。 授信额度和贷款额度的主要区别是授…

ChatGPT在做什么?为什么它有效?

2023 年 2 月 14 日 它只是一次添加一个词 ChatGPT可以自动生成一些表面上看起来像人类书写文本的东西&#xff0c;这是非常了不起的&#xff0c;也是出乎意料的。但是它是怎么做到的呢&#xff1f;为什么它有效&#xff1f;我在这里的目的是粗略概述 ChatGPT 内部发生的事情&…