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

一、RLHF微调三阶段

参考:https://huggingface.co/blog/rlhf

1)使用监督数据微调语言模型,和fine-tuning一致。

2)训练奖励模型

奖励模型是输入一个文本序列,模型给出符合人类偏好的奖励数值,这个奖励数值对于后面的强化学习训练非常重要。构建奖励模型的训练数据一般是同一个数据用不同的语言模型生成结果,然后人工打分。如果是训练自己领域的RLHF模型,也可以尝试用chatgpt打分,效果也不错。

3)训练RL模型

在训练强化学习模型时,需要搞清楚状态空间、动作空间、策略函数、价值函数这些东西,动作空间就是所有的token,状态空间就是输入的序列的分布,价值函数由第二步的奖励模型和策略约束结合,策略函数就是微调的大模型。

从上图可以看出,给定一个输入xx,会生成两个文本y1y1和y2y2,一个来自于初始的模型,另一个来自于微调的模型,微调的模型生成的文本还会进入到奖励模型中打分输出rθrθ,而初始模型和微调的模型生成的结果会用KL散度约束它们的分布,确保模型不会太偏离原来的模型,并且能输出高质量的回复。

值得注意的是三个阶段的训练数据尽量是分布一致的,否则后面的训练会很不稳定。所以在第一步微调时不要一味地使用大量的训练数据(这一步的数据比较容易获得),尽量和后面两步的数据分布保持一致。

二:RLHF代码理解

以DeepSpeed-Chat的代码去理解RLHF的过程。https://github.com/microsoft/DeepSpeedExamples/tree/master/applications/DeepSpeed-Chat

DeepSpeed-Chat提供了RLHF三个阶段的训练代码,可以很方便地训练三个阶段,现在我们来一个一个阶段地来看。

1)数据集处理

首先从数据集的处理出发,去理解三个阶段的输入是什么样的数据?在training/utils/data/raw_datasets.py提供了多种开源数据集的读取方式,可以看到每个数据集都包含prompt(提问),chosen(正向回答),rejected(负向回答)。以其中某一个为例:

class DahoasRmstaticDataset(PromptRawDataset):def __init__(self, output_path, seed, local_rank, dataset_name):super().__init__(output_path, seed, local_rank, dataset_name)self.dataset_name = "Dahoas/rm-static"self.dataset_name_clean = "Dahoas_rm_static"def get_train_data(self):return self.raw_datasets["train"]def get_eval_data(self):return self.raw_datasets["test"]def get_prompt(self, sample):return sample['prompt']def get_chosen(self, sample):return sample['chosen']def get_rejected(self, sample):return sample['rejected']def get_prompt_and_chosen(self, sample):return sample['prompt'] + sample['chosen']def get_prompt_and_rejected(self, sample):return sample['prompt'] + sample['rejected']

具体的数据处理在training/utils/data/data_utils.py中,下面的代码展示了三个阶段使用的输入是什么?在第一步,即监督微调大模型,使用prompt + chosen;在第二步,即训练奖励模型时,需要使用prompt + chosen 和 prompt + rejected;在第三步,即训练RL模型,只使用prompt。

if train_phase == 1:for i, tmp_data in enumerate(current_dataset):# tokenize the textchosen_sentence = raw_dataset.get_prompt_and_chosen(tmp_data)  # the accept responseif chosen_sentence is not None:chosen_sentence += end_of_conversation_tokenchosen_token = tokenizer(chosen_sentence,max_length=max_seq_len,padding="max_length",truncation=True,return_tensors="pt")chosen_token["input_ids"] = chosen_token["input_ids"].squeeze(0)chosen_token["attention_mask"] = chosen_token["attention_mask"].squeeze(0)chosen_dataset.append(chosen_token)elif train_phase == 2:for i, tmp_data in enumerate(current_dataset):# tokenize the textchosen_sentence = raw_dataset.get_prompt_and_chosen(tmp_data)  # the accept responsereject_sentence = raw_dataset.get_prompt_and_rejected(tmp_data)  # the accept responseif chosen_sentence is not None and reject_sentence is not None:chosen_sentence += end_of_conversation_token  # the accept responsereject_sentence += end_of_conversation_tokenchosen_token = tokenizer(chosen_sentence,max_length=max_seq_len,padding="max_length",truncation=True,return_tensors="pt")reject_token = tokenizer(reject_sentence,max_length=max_seq_len,padding="max_length",truncation=True,return_tensors="pt")chosen_token["input_ids"] = chosen_token["input_ids"]chosen_token["attention_mask"] = chosen_token["attention_mask"]chosen_dataset.append(chosen_token)reject_token["input_ids"] = reject_token["input_ids"]reject_token["attention_mask"] = reject_token["attention_mask"]reject_dataset.append(reject_token)elif train_phase == 3:for i, tmp_data in enumerate(current_dataset):# tokenize the textprompt = raw_dataset.get_prompt(tmp_data)if prompt is not None:prompt_token = tokenizer(prompt, return_tensors="pt")prompt_token["input_ids"] = prompt_token["input_ids"]prompt_token["attention_mask"] = prompt_token["attention_mask"]for key_word in ["input_ids", "attention_mask"]:length = prompt_token[key_word].size()[-1]if length > max_seq_len:y = prompt_token[key_word].squeeze(0)[length -(max_seq_len -1):].flip(0)else:y = prompt_token[key_word].squeeze(0).flip(0)prompt_token[key_word] = yprompt_dataset.append(prompt_token)

2)监督数据微调大模型

代码在training/step1_supervised_finetuning文件夹下,文件夹下的traning_scripts提供了单GPU,多GPU,多机器的训练脚本。监督数据微调没有什么值得说的,和我们常用的微调方式一致,可以选择一个开源的模型,比如facebook/opt-1.3b,微调时可以选择lora和offload微调。

3)训练奖励模型

代码在training/step2_reward_model_finetuning文件夹下,奖励模型可以选择一个较小的模型,如opt-350M,在chosen和rejected这种样本对上训练。奖励模型的代码实现在training/utils/model/reward_model.py中。reward model的输出类似于回归任务,将大模型的输出,然后经过N ✖️ 1 的线性层,得到一个batch size ✖️ seq len ✖️ 1的输出。在训练过程中,使用到的loss是二元交叉熵,确保每个prompt 的 chosen分数都是要大于rejected。

loss += -torch.log(torch.sigmoid(c_truncated_reward - r_truncated_reward)).mean()

上面的代码中c_truncated_reward 和 r_truncated_reward 即给定一个prompt,对应的chosen和rejected获得的分数,而且是chosen 和 rejected所有token的分数差值。注意在这里因为chosen和rejected的长度不一致,而且还有padding的部分,所以c_truncated_reward和r_truncated_reward要做阶段,主要是截取chosen_id和rejected_id不等的部分出来,去除共同padding的部分。

4)训练强化学习模型

代码在training/step3_rlhf_finetuning文件夹下,在第三步我们需要两个模型,一个是第一步训练好的SFT模型,另一个是第二步训练好的reward模型。接下来看下强化学习模型训练的步骤:

1)初始化rlhf engine,在代码training/step3_rlhf_finetuning/main.py中

rlhf_engine = DeepSpeedRLHFEngine(actor_model_name_or_path=args.actor_model_name_or_path,critic_model_name_or_path=args.critic_model_name_or_path,tokenizer=tokenizer,num_total_iters=num_total_iters,args=args)

rlhf_engine中会包含4个模型对象:self.actor: sft模型,可训练,作为策略模型;self.ref: sft模型,不可训练,只做前向推断,用于约束self.actor生成结果的向量分布;self.critic:reward模型,可训练,价值模型,用于对生成的每个动作打分;self.reward:reward 模型,不可训练,用于计算整个序列的奖励值。

2)初始化ppo训练器,在代码training/step3_rlhf_finetuning/main.py中

ppo_trainer = DeepSpeedPPOTrainerUnsupervised if unsupervised_training_enabled else DeepSpeedPPOTrainer
trainer = ppo_trainer(rlhf_engine, args)

3)生成PPO的训练样本,在代码training/step3_rlhf_finetuning/main.py中

out = trainer.generate_experience(prompts)
exp_dataset = exp_mini_dataset.add(out)

4)训练PPO模型,在代码training/step3_rlhf_finetuning/main.py中

for ppo_ep in range(args.ppo_epochs):for i, (exp_data, unsup_data) in enumerate(zip(exp_dataset, unsup_dataset)):actor_loss, critic_loss = trainer.train_rlhf(exp_data)                                

回过头来再看rlhf_engine和ppo_trainer的实现逻辑。

rlhf_engine的实现在training/step3_rlhf_finetuning/rlhf_engine.py中,主要是初始化了几个模型对象

self.actor = self._init_actor(actor_model_name_or_path=actor_model_name_or_path)
self.ref = self._init_ref(actor_model_name_or_path=actor_model_name_or_path)
self.actor_ema = None
if self.args.enable_ema:self.actor_ema = self._init_ema(actor_model_name_or_path=actor_model_name_or_path)self.critic = self._init_critic(critic_model_name_or_path=critic_model_name_or_path)
self.reward = self._init_reward(critic_model_name_or_path=critic_model_name_or_path)

ppo_trainer的具体代码在training/step3_rlhf_finetuning/ppo_trainer.py中,由于对强化学习不是很熟悉,只能简单地描述下整个逻辑:

1)输入prompt,使用self.actor生成对应的answer,并拼接成一个完整的seq,这其实是一个采样的过程,类似于强化学习中生成一条完整的状态-动作序列。动作即生成的token,状态时生成token的前缀输入。

with torch.no_grad():seq = self.actor_model.module.generate(prompts,max_length=max_min_length,min_length=max_min_length)

2)基于当前 T 时刻的网络参数,生成完整的状态-动作序列,奖励值。

with torch.no_grad():output = self.actor_model(seq, attention_mask=attention_mask)output_ref = self.ref_model(seq, attention_mask=attention_mask)reward_score = self.reward_model.forward_value(seq, attention_mask,prompt_length=self.prompt_length)['chosen_end_scores'].detach()values = self.critic_model.forward_value(seq, attention_mask, return_value_only=True).detach()[:, :-1]logits = output.logits
logits_ref = output_ref.logitsreturn {'prompts': prompts,'logprobs': gather_log_probs(logits[:, :-1, :], seq[:, 1:]),'ref_logprobs': gather_log_probs(logits_ref[:, :-1, :], seq[:,1:]),'value': values,'rewards': reward_score,'input_ids': seq,"attention_mask": attention_mask
}

3)训练PPO模型,所有的核心训练逻辑都在这里。

def train_rlhf(self, inputs):# train the rlhf mode here### process the old outputsprompts = inputs['prompts']log_probs = inputs['logprobs']ref_log_probs = inputs['ref_logprobs']reward_score = inputs['rewards']values = inputs['value']attention_mask = inputs['attention_mask']seq = inputs['input_ids']start = prompts.size()[-1] - 1action_mask = attention_mask[:, 1:]old_values = valueswith torch.no_grad():# 1、计算生成的每个token的奖励值old_rewards = self.compute_rewards(prompts, log_probs,ref_log_probs, reward_score,action_mask)# 2、计算价值,价值不等于奖励值,价值是考虑到未来的,奖励值只考虑当下advantages, returns = self.get_advantages_and_returns(old_values, old_rewards, start)### process the new outputsbatch = {'input_ids': seq, "attention_mask": attention_mask}actor_prob = self.actor_model(**batch, use_cache=False).logitsactor_log_prob = gather_log_probs(actor_prob[:, :-1, :], seq[:, 1:])# 3、计算actor网络的loss,并更新网络参数actor_loss = self.actor_loss_fn(actor_log_prob[:, start:],log_probs[:, start:], advantages,action_mask[:, start:])self.actor_model.backward(actor_loss)self.actor_model.step()value = self.critic_model.forward_value(**batch,return_value_only=True,use_cache=False)[:, :-1]# 4、计算critic网络的loss,并更新网络参数critic_loss = self.critic_loss_fn(value[:, start:], old_values[:,start:],returns, action_mask[:, start:])self.critic_model.backward(critic_loss)self.critic_model.step()return actor_loss, critic_loss

因为这一部分的内容比较多,我们再细分来描述:

3.1)计算每个时刻(沿着序列的方向定义时刻)的奖励值,即给定前缀输入,生成当前token时对应的奖励值,奖励值由两部分组成,一是完整的序列奖励,由self.reward输出的,二是self.actor和self.ref输出的token向量的KL散度值。具体的代码:

def compute_rewards(self, prompts, log_probs, ref_log_probs, reward_score,action_mask):kl_divergence_estimate = -self.kl_ctl * (log_probs - ref_log_probs)rewards = kl_divergence_estimatestart = prompts.shape[1] - 1ends = start + action_mask[:, start:].sum(1)reward_clip = torch.clamp(reward_score, -self.clip_reward_value,self.clip_reward_value)batch_size = log_probs.shape[0]for j in range(batch_size):rewards[j, start:ends[j]][-1] += reward_clip[j]return rewards

3.2)计算每个时刻的价值,actor的价值采用TD误差。在这里要指明价值不等于奖励值,奖励值只取决于当前时刻的状态和动作,而价值是考虑到了未来的情况的。所以价值的计算如下:核心是下面的delta的计算,除了考虑到当前的时刻的奖励值,还考虑到了未来时刻的输出的奖励值nextvalues(只不过这里的奖励值是由critic网络直接输出的每个token对应的分数)。下面的函数输出了两个值,一个是advantages,用于更新actor。二是returns,这是我们的目标Q值,用于后面更新critic。

def get_advantages_and_returns(self, values, rewards, start):# Adopted from https://github.com/CarperAI/trlx/blob/main/trlx/models/modeling_ppo.py#L134lastgaelam = 0advantages_reversed = []length = rewards.size()[-1]for t in reversed(range(start, length)):nextvalues = values[:, t + 1] if t < length - 1 else 0.0delta = rewards[:, t] + self.gamma * nextvalues - values[:, t]  # TD误差lastgaelam = delta + self.gamma * self.lam * lastgaelamadvantages_reversed.append(lastgaelam)advantages = torch.stack(advantages_reversed[::-1], dim=1)returns = advantages + values[:, start:]  # Q值return advantages.detach(), returns

3.3)计算actor的loss,其实在这里有一个目标actor和当前actor的概念,下面函数中old_logprobs是由目标actor输出的,logprobs是由当前actor输出的,ppo算法中actor的loss是使用当前actor输出的概率和目标actor输出的概率的比值来约束的,转换成log后就是logprobs - old_logprobs。

def actor_loss_fn(self, logprobs, old_logprobs, advantages, mask):## policy gradient losslog_ratio = (logprobs - old_logprobs) * mask  # 当前策略和上一策略的比值ratio = torch.exp(log_ratio)pg_loss1 = -advantages * ratiopg_loss2 = -advantages * torch.clamp(ratio, 1.0 - self.cliprange,1.0 + self.cliprange)pg_loss = torch.sum(torch.max(pg_loss1, pg_loss2) * mask) / mask.sum()return pg_loss

3.4)计算critic的loss,在这里一样有一个目标critic和当前cirtic的概念,用当前cirtic输出的value减去目标Q值(也就是上面计算得到的returns)再求平方,所以是使用了当前critic的Q值和目标critic的Q值的均方误差作为critic的loss。

def critic_loss_fn(self, values, old_values, returns, mask):## value lossvalues_clipped = torch.clamp(values,old_values - self.cliprange_value,old_values + self.cliprange_value,)vf_loss1 = (values - returns)**2  # 当前critic和目标critic的Q值的均方误差vf_loss2 = (values_clipped - returns)**2vf_loss = 0.5 * torch.sum(torch.max(vf_loss1, vf_loss2) * mask) / mask.sum()return vf_loss

在上面3.3)和3.4)提到了目标actor和目标critic,但在代码里并没有创建这两个变量,这里其实和PPO的训练方式有关,首先是利用T时刻的actor和critic生成状态-动作序列和价值,奖励等并存储下来。在训练PPO时会使用生成的状态-动作去重新输出价值、奖励等值并更新actor和critic参数,所以并没有显示构造目标actor和目标critic,但是存储了它们产生的结果。存储的这部分数据会不断地更新,保证目标actor和critic和当前的actor和critic的参数不会有太大的差别,更新的逻辑在training/utils/data/data_utils.py中的MiniDataset类中。

所以强化学习模型的训练流程就是两步,一是先生成目标actor和critic的值作为对比的数据,二是训练actor和critic模型,将代码简化,其实就是training/step3_rlhf_finetuning/main.py中下面的代码段:

for epoch in range(args.num_train_epochs):....for step, (batch_prompt, batch_unsupervised) in enumerate(zip(prompt_train_dataloader, unsupervised_train_dataloader)):...# 生成训练强化学习模型的数据out = trainer.generate_experience(prompts)exp_dataset = exp_mini_dataset.add(out)if exp_dataset is not None:...# 训练强化学习模型for ppo_ep in range(args.ppo_epochs):for i, (exp_data, unsup_data) in enumerate(zip(exp_dataset, unsup_dataset)):actor_loss, critic_loss = trainer.train_rlhf(exp_data)actor_loss_sum += actor_loss.item()critic_loss_sum += critic_loss.item()average_reward += exp_data["rewards"].mean()

如何学习大模型 AI ?

由于新岗位的生产效率,要优于被取代岗位的生产效率,所以实际上整个社会的生产效率是提升的。

但是具体到个人,只能说是:

“最先掌握AI的人,将会比较晚掌握AI的人有竞争优势”。

这句话,放在计算机、互联网、移动互联网的开局时期,都是一样的道理。

我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。

我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在人工智能学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限,很多互联网行业朋友无法获得正确的资料得到学习提升,故此将并将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。

😝有需要的小伙伴,可以点击下方链接免费领取或者V扫描下方二维码免费领取🆓

在这里插入图片描述

在这里插入图片描述

第一阶段(10天):初阶应用

该阶段让大家对大模型 AI有一个最前沿的认识,对大模型 AI 的理解超过 95% 的人,可以在相关讨论时发表高级、不跟风、又接地气的见解,别人只会和 AI 聊天,而你能调教 AI,并能用代码将大模型和业务衔接。

  • 大模型 AI 能干什么?
  • 大模型是怎样获得「智能」的?
  • 用好 AI 的核心心法
  • 大模型应用业务架构
  • 大模型应用技术架构
  • 代码示例:向 GPT-3.5 灌入新知识
  • 提示工程的意义和核心思想
  • Prompt 典型构成
  • 指令调优方法论
  • 思维链和思维树
  • Prompt 攻击和防范

第二阶段(30天):高阶应用

该阶段我们正式进入大模型 AI 进阶实战学习,学会构造私有知识库,扩展 AI 的能力。快速开发一个完整的基于 agent 对话机器人。掌握功能最强的大模型开发框架,抓住最新的技术进展,适合 Python 和 JavaScript 程序员。

  • 为什么要做 RAG
  • 搭建一个简单的 ChatPDF
  • 检索的基础概念
  • 什么是向量表示(Embeddings)
  • 向量数据库与向量检索
  • 基于向量检索的 RAG
  • 搭建 RAG 系统的扩展知识
  • 混合检索与 RAG-Fusion 简介
  • 向量模型本地部署

第三阶段(30天):模型训练

恭喜你,如果学到这里,你基本可以找到一份大模型 AI相关的工作,自己也能训练 GPT 了!通过微调,训练自己的垂直大模型,能独立训练开源多模态大模型,掌握更多技术方案。

到此为止,大概2个月的时间。你已经成为了一名“AI小子”。那么你还想往下探索吗?

  • 为什么要做 RAG
  • 什么是模型
  • 什么是模型训练
  • 求解器 & 损失函数简介
  • 小实验2:手写一个简单的神经网络并训练它
  • 什么是训练/预训练/微调/轻量化微调
  • Transformer结构简介
  • 轻量化微调
  • 实验数据集的构建

第四阶段(20天):商业闭环

对全球大模型从性能、吞吐量、成本等方面有一定的认知,可以在云端和本地等多种环境下部署大模型,找到适合自己的项目/创业方向,做一名被 AI 武装的产品经理。

  • 硬件选型
  • 带你了解全球大模型
  • 使用国产大模型服务
  • 搭建 OpenAI 代理
  • 热身:基于阿里云 PAI 部署 Stable Diffusion
  • 在本地计算机运行大模型
  • 大模型的私有化部署
  • 基于 vLLM 部署大模型
  • 案例:如何优雅地在阿里云私有部署开源大模型
  • 部署一套开源 LLM 项目
  • 内容安全
  • 互联网信息服务算法备案

学习是一个过程,只要学习就会有挑战。天道酬勤,你越努力,就会成为越优秀的自己。

如果你能在15天内完成所有的任务,那你堪称天才。然而,如果你能完成 60-70% 的内容,你就已经开始具备成为一名大模型 AI 的正确特征了。

这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

😝有需要的小伙伴,可以Vx扫描下方二维码免费领取==🆓

在这里插入图片描述

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

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

相关文章

未来编码探索:揭秘Java的进化之旅与技术革新!

Java是一种广泛使用的编程语言&#xff0c;自1995年问世以来&#xff0c;它在企业级应用、移动应用开发、大数据处理等领域都有着广泛的应用。随着时间的推移&#xff0c;Java也在不断发展和进化&#xff0c;以满足不断变化的技术需求和市场趋势。本文将全面详细地探讨Java的未…

MyBatis(该篇足已)

目录 一.MyBatis是什么&#xff1f; 二.为什么学习MyBatis呢&#xff1f; 三.MyBatis的学习 3.1MyBatis的开发流程 3.2MyBatis项目 四.MyBatis的增删改操作 五.参数占位符 #{} 和 ${} 六.映射返回 七.映射失败 八.数据库连接池 九.动态SQL 9.1<if>标签 9.2&…

LeetCode63:不同路径Ⅱ

题目描述 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “Finish”&#xff09;。 现在考虑网格中有障碍物。那么从左上角…

5.07 Pneumonia Detection in Chest X-Rays using Neural Networks

肺炎诊断是一个耗时的过程&#xff0c;需要高技能的专业人员分析胸部X光片chest X-ray (CXR)&#xff0c;并通过临床病史、生命体征和实验室检查确认诊断。 它可以帮助医生确定肺部感染的程度和位置。呼吸道疾病在 X 光片上表现为一处膨胀的不透明区域。然而&#xff0c;由于不…

力扣HOT100 - 155. 最小栈

解题思路&#xff1a; 辅助栈 class MinStack {private Stack<Integer> stack;private Stack<Integer> min_stack;public MinStack() {stack new Stack<>();min_stack new Stack<>();}public void push(int val) {stack.push(val);if (min_stack.i…

LeetCode 404.左叶子之和

LeetCode 404.左叶子之和 1、题目 题目链接&#xff1a;404. 左叶子之和 给定二叉树的根节点 root &#xff0c;返回所有左叶子之和。 示例 1&#xff1a; 输入: root [3,9,20,null,null,15,7] 输出: 24 解释: 在这个二叉树中&#xff0c;有两个左叶子&#xff0c;分别…

SaToken框架实现在Rpc上下文的login处理逻辑

最近在工作中遇到一个需求&#xff0c;需要在项目A中实现一个rpc接口供其他项目调用&#xff0c;接口返回登录token&#xff0c;从而实现其他项目的用户能免密登录到项目A。 项目A是用了SaToken来做的鉴权&#xff0c;原本我的打算是直接在rpc中调用StpUtil.login()方法来实现登…

在Flask中使用Celery完成异步和定时任务(Flask、Celery、Redis)

编程目标 通过使用Flask和Celery&#xff0c;实现一个简单的Web应用程序&#xff0c;能够接收HTTP POST请求&#xff0c;并异步发送电子邮件。 说明 使用Flask创建一个简单的Web应用程序&#xff0c;包含一个HTTP POST路由&#xff0c;用于接收发送电子邮件的请求。使用Cele…

基于Spring Boot的酒店管理系统设计与实现

基于Spring Boot的酒店管理系统设计与实现 开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclipse/idea 系统部分展示 系统首页界面图&#xff0c;在系统首页可以查看首页…

java io包

InputStream InputStream 是 Java I/O 中所有输入流的抽象基类&#xff0c;它定义了读取字节流的基本方法。InputStream 类提供了许多子类&#xff0c;用于从不同的数据源读取数据&#xff0c;如文件、网络连接、内存等。 InputStream 提供了以下常用的方法&#xff1a; int…

【数学建模】天然肠衣搭配问题衍生问题/线性规划限制条件建立问题

线性规划限制条件建立问题 前景回顾/提出问题回顾1回顾2/问题提出解决前提 解决方法坐标轴(区间)法总结 前景回顾/提出问题 回顾1 首先回顾一下DVD在线租赁问题 在 question2中&#xff0c;需要保证每个人都不会收到自己不喜欢的DVD&#xff0c;即客户在线订单数为0时候&…

umi6.x + react + antd的项目增加403(无权限页面拦截),404,错误处理页面

首先在src/pages下创建403&#xff0c;404&#xff0c;ErrorBoundary 403 import { Button, Result } from antd; import { history } from umijs/max;const UnAccessible () > (<Resultstatus"403"title"403"subTitle"抱歉&#xff0c;您无权…

HarmonyOS开发之ArkTS使用:新建活动页面

目录 目录 引言 关于ArkTS 开发环境准备 新建项目 新建活动页面 编写ArkTS代码 注册页面 运行应用 最后 引言 随着HarmonyOS&#xff08;鸿蒙操作系统&#xff09;的不断发展&#xff0c;越来越多的前端开发者投入到这个全新的生态系统中。而在HarmonyOS的开发中&…

线上副业新选择:宅家工作,4个项目助力增收!

在这个繁华世界&#xff0c;财富与智慧并驾齐驱。越来越多的人意识到&#xff0c;除了主业外&#xff0c;开拓一份副业是实现财富增长的重要途径。在此&#xff0c;我为大家精心挑选了几个值得一试的网上赚钱副业。 1&#xff0c;参与网络调查与问卷填写 随着大数据时代的到来…

kkkkkkkkkkkk564

欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起探讨和分享Linux C/C/Python/Shell编程、机器人技术、机器学习、机器视觉、嵌入式AI相关领域的知识和技术。 人工智能与机器学习 &#x1f4dd;人工智能相关概念☞什么是人工智能、机器学习、深度学习☞人工智能发…

YOLOv8 Tensorrt Python/C++部署详解

按照大佬的方法进行部署&#xff0c;但是中间出现了很多问题&#xff0c;这里进行一下总结。 YOLOv8 Tensorrt Python/C部署教程_yolo 安装tensorrt-CSDN博客https://blog.csdn.net/weixin_45747759/article/details/130341118 Monday-Leo/Yolov5_Tensorrt_Win10: A simple i…

Kafka从0到消费者开发

安装ZK Index of /zookeeper/zookeeper-3.9.2 下载安装包 一定要下载-bin的&#xff0c;不带bin的是源码&#xff0c;没有编译的&#xff0c;无法执行。-bin的才可以执行。 解压 tar -zxvf apache-zookeeper-3.9.2-bin.tar.gz 备份配置 cp zoo_sample.cfg zoo_sample.cfg-b…

物流集成商巨头-员工薪酬PK:今天国际、音飞存储,诺力股份

语 大家好&#xff0c;我是智能仓储物流技术研习社的社长&#xff0c;老K。专注分享智能仓储物流技术、智能制造等内容。 新书《智能物流系统构成与技术实践》 以下内容为根据上市财报和公开数据整理&#xff0c;若有偏差&#xff0c;请联系小编修改。注意&#xff1a;各公司员…

ZYNQ实验--裸机程序固化

参考资料 正点原子《领航者 ZYNQ 之嵌入式 SDK 开发指南》详细的配置资料中都有介绍&#xff0c;本文只针对个人实验需求进行简要说明 固化流程 调试阶段是通过 JTAG 接口将 FPGA 配置文件和应用程序下载到 ZYNQ 器件中。但在实际应用中需要程序在上电或者复位时让程序自动运…

Adversarial Synthesis of Human Pose From Text # 论文阅读

URL https://arxiv.org/pdf/2005.00340 TD;DR 20 年 5 月来自高校的一篇论文&#xff0c;任务是用 GAN 生成 pose&#xff0c;目前 7 引用。 Model & Method 输入的是描述动作的 text&#xff0c;通过 text encoder&#xff08;本文用的是叫做 fastText 的方法&#…