8. 尝试微调LLM大型语言模型,让它会写唐诗

这篇文章与03. 进阶指南:自定义 Prompt 提升大模型解题能力一样,本质上是专注于“用”而非“写”,你可以像之前一样,对整体的流程有了一个了解,尝试调整超参数部分来查看对微调的影响。

这里同样是生成式人工智能导论:HW5 Fine-tuning 的中文镜像。

代码文件下载

文章目录

    • 环境配置与库安装
    • 导入库
    • 下载微调所需的数据集
    • 定义辅助函数
      • 数据预处理函数
      • 模型评估函数
    • 下载模型并在微调前进行推理
      • 选择预训练模型
      • 微调前的推理
        • 加载模型
        • 初始表现
    • 设置用于微调的超参数
    • 开始微调
    • 测试微调后的模型
      • 选取要加载的微调后的模型
      • 释放显存
      • 加载模型和分词器
      • 生成测试结果
    • 微调前后的对比

环境配置与库安装

首先,我们需要安装一些必要的库,以便简化微调过程。

pip install bitsandbytes==0.43.0
pip install datasets==2.10.1
pip install transformers==4.38.2
pip install peft==0.9.0
pip install sentencepiece==0.1.99
pip install -U accelerate==0.28.0
pip install colorama==0.4.6
pip install fsspec==2023.9.2

库说明(实际上在这里不需要深究)

  • bitsandbytes:用于低精度计算,加速训练过程。
  • datasets:用于加载和处理数据集。
  • transformers:Hugging Face 提供的库,包含预训练的模型和 Tokenizer。
  • peft:Parameter-Efficient Fine-Tuning,参数高效微调库。
  • sentencepiece:用于处理分词。
  • accelerate:用于加速训练过程。
  • colorama:用于在终端中打印彩色文本。
  • fsspec:文件系统规范库。

导入库

安装完库后,导入我们需要的模块。

import os
import sys
import argparse
import json
import warnings
import logging
warnings.filterwarnings("ignore")import torch
import torch.nn as nn
import bitsandbytes as bnb
from datasets import load_dataset, load_from_disk
import transformers
from peft import PeftModel
from colorama import Fore, Stylefrom tqdm import tqdm
from transformers import (AutoTokenizer,AutoConfig,AutoModelForCausalLM,BitsAndBytesConfig,GenerationConfig
)
from peft import (prepare_model_for_int8_training,LoraConfig,get_peft_model,get_peft_model_state_dict,prepare_model_for_kbit_training
)

下载微调所需的数据集

我们将使用一个唐诗的数据集来微调模型,这个数据集实际上来自于全唐诗 - Github。

git clone https://github.com/CheeEn-Yu/GenAI-Hw5.git

克隆完成后,数据集会存储在 GenAI-Hw5 目录下。

定义辅助函数

在微调过程中,我们需要一些辅助函数来处理数据和评估模型。

数据预处理函数

def generate_training_data(data_point):"""将输入和输出文本转换为模型可读取的 tokens。参数:- data_point: 包含 "instruction"、"input" 和 "output" 字段的字典。返回:- 包含模型输入 IDs、标签和注意力掩码的字典。示例:- 如果你构建了一个字典 data_point_1,并包含字段 "instruction"、"input" 和 "output",你可以像这样使用函数:generate_training_data(data_point_1)"""# 构建完整的输入提示词prompt = f"""\
[INST] <<SYS>>
You are a helpful assistant and good at writing Tang poem. 你是一個樂於助人的助手且擅長寫唐詩。
<</SYS>>{data_point["instruction"]}
{data_point["input"]}
[/INST]"""# 计算用户提示词的 token 数量len_user_prompt_tokens = (len(tokenizer(prompt,truncation=True,max_length=CUTOFF_LEN + 1,padding="max_length",)["input_ids"]) - 1)# 将完整的输入和输出转换为 tokensfull_tokens = tokenizer(prompt + " " + data_point["output"] + "</s>",truncation=True,max_length=CUTOFF_LEN + 1,padding="max_length",)["input_ids"][:-1]return {"input_ids": full_tokens,"labels": [-100] * len_user_prompt_tokens + full_tokens[len_user_prompt_tokens:],"attention_mask": [1] * len(full_tokens),}

函数解释

  • 目的:将原始数据转换为模型可以处理的输入格式。
  • 处理步骤
    • 构建提示词 prompt,包括系统信息和用户的指令。
    • 使用 tokenizerprompt 转换为 token,并计算其长度。
    • 将完整的输入(提示词和输出)转换为 tokens。
    • 构建 labels,对于提示词部分的 tokens,使用 -100(在计算损失时会被忽略),对于输出部分的 tokens,保留实际的 token ID。

模型评估函数

def evaluate(instruction, generation_config, max_len, input_text="", verbose=True):"""获取模型在给定输入下的生成结果。参数:- instruction: 描述任务的字符串。- generation_config: 模型生成配置。- max_len: 最大生成长度。- input_text: 输入文本,默认为空字符串。- verbose: 是否打印生成结果。返回:- output: 模型生成的文本。"""# 构建完整的输入提示词prompt = f"""\
[INST] <<SYS>>
You are a helpful assistant and good at writing Tang poem. 你是一個樂於助人的助手且擅長寫唐詩。
<</SYS>>{instruction}
{input_text}
[/INST]"""# 将提示词转换为模型所需的 token 格式inputs = tokenizer(prompt, return_tensors="pt")input_ids = inputs["input_ids"].cuda()# 使用模型生成回复generation_output = model.generate(input_ids=input_ids,generation_config=generation_config,return_dict_in_generate=True,output_scores=True,max_new_tokens=max_len,)# 解码并打印生成的回复for s in generation_output.sequences:output = tokenizer.decode(s)output = output.split("[/INST]")[1].replace("</s>", "").replace("<s>", "").replace("Assistant:", "").replace("Assistant", "").strip()if verbose:print(output)return output

函数解释

  • 目的:给定一个指令,使用模型生成对应的回复。
  • 处理步骤
    • 构建提示词 prompt,包括系统信息和用户的指令。
    • 使用 tokenizerprompt 转换为模型的输入格式。
    • 调用 model.generate 生成文本。
    • 对生成的序列进行解码,提取模型的输出部分。

下载模型并在微调前进行推理

选择预训练模型

我们将默认选择 MediaTek Breeze 7B 模型,因为 TAIDE 模型可能遇到下载次数过多无法访问。实际上换其他的开源大模型一样可以,并不影响学习的目的。

""" 你可以(但不一定需要)更改 LLM 模型 """model_name = "MediaTek-Research/Breeze-7B-Instruct-v0_1"# model_name = "/content/TAIDE-LX-7B-Chat"
# 如果你想使用 TAIDE 模型,请先查看 TAIDE L Models Community License Agreement (https://drive.google.com/file/d/1FcUZjbUH6jr4xoCyAronN_slLgcdhEUd/view)。
# 一旦使用,即表示你同意协议条款。
# !wget -O taide_7b.zip "https://www.dropbox.com/scl/fi/harnetdwx2ttq1xt94rin/TAIDE-LX-7B-Chat.zip?rlkey=yzyf5nxztw6farpwyyildx5s3&st=s22mz5ao&dl=0"
# !unzip taide_7b.zip

微调前的推理

让我们先看看在未进行微调的情况下,模型的表现如何。

加载模型

会占用大概 5.2G 的显存。

cache_dir = "./cache"nf4_config = BitsAndBytesConfig(load_in_4bit=True,bnb_4bit_quant_type="nf4",bnb_4bit_use_double_quant=True,bnb_4bit_compute_dtype=torch.bfloat16
)# 从指定模型名称或路径加载预训练语言模型
model = AutoModelForCausalLM.from_pretrained(model_name,cache_dir=cache_dir,quantization_config=nf4_config,low_cpu_mem_usage=True
)# 创建 tokenizer 并设置结束符号 (eos_token)
logging.getLogger('transformers').setLevel(logging.ERROR)
tokenizer = AutoTokenizer.from_pretrained(model_name,add_eos_token=True,cache_dir=cache_dir,quantization_config=nf4_config
)
tokenizer.pad_token = tokenizer.eos_token# 设置模型推理时的解码参数
max_len = 128
generation_config = GenerationConfig(do_sample=True,temperature=0.1,num_beams=1,top_p=0.3,no_repeat_ngram_size=3,pad_token_id=2,
)

主要函数解释

  • BitsAndBytesConfig:配置模型的量化设置,使用 4 位精度以节省显存。
  • AutoModelForCausalLM:加载预训练的语言模型。
  • AutoTokenizer:加载对应的分词器。
  • GenerationConfig:设置文本生成时的参数,如温度、采样策略等。

这个代码块会下载对应的预训练模型。
预训练模型下载

初始表现
""" 样例和 Prompt 都保持繁体 """# 测试样例
test_tang_list = ['相見時難別亦難,東風無力百花殘。','重帷深下莫愁堂,臥後清宵細細長。','芳辰追逸趣,禁苑信多奇。'
]# 获取每个样例的模型输出
demo_before_finetune = []
for tang in test_tang_list:demo_before_finetune.append(f'模型輸入:\n以下是一首唐詩的第一句話,請用你的知識判斷並完成整首詩。{tang}\n\n模型輸出:\n' +evaluate('以下是一首唐詩的第一句話,請用你的知識判斷並完成整首詩。', generation_config, max_len, tang, verbose=False))# 打印并将输出存储到文本文件
for idx in range(len(demo_before_finetune)):print(f"Example {idx + 1}:")print(demo_before_finetune[idx])print("-" * 80)

可以看到回答多数是在重复输入的第一句话。

image-20240913153551684

设置用于微调的超参数

""" 强烈建议你尝试调整这个参数 """num_train_data = 1040  # 设置用于训练的数据量,最大值为5000。通常,训练数据越多越好,模型会见到更多样化的诗句,从而提高生成质量,但也会增加训练时间。# 使用默认参数(1040):微调大约需要25分钟,完整运行所有单元大约需要50分钟。# 使用最大值(5000):微调大约需要100分钟,完整运行所有单元大约需要120分钟。""" 你可以(但不一定需要)更改这些超参数 """output_dir = "./output"  # 设置作业结果输出目录。
ckpt_dir = "./exp1"  # 设置 model checkpoint 保存目录(如果想将 model checkpoints 保存到其他目录下,可以修改这里)。
num_epoch = 1  # 设置训练的总 Epoch 数(数值越高,训练时间越长,若使用免费版的 Colab 需要注意时间太长可能会断线,本地运行不需要担心)。
LEARNING_RATE = 3e-4  # 设置学习率""" 建议不要更改此单元格中的代码 """cache_dir = "./cache"  # 设置缓存目录路径
from_ckpt = False  # 是否从 checkpoint 加载模型权重,默认值为否
ckpt_name = None  # 加载特定 checkpoint 时使用的文件名,默认值为无
dataset_dir = "./GenAI-Hw5/Tang_training_data.json"  # 设置数据集目录或文件路径
logging_steps = 20  # 定义训练过程中每隔多少步骤输出一次日志
save_steps = 65  # 定义训练过程中每隔多少步骤保存一次模型
save_total_limit = 3  # 控制最多保留多少个模型 checkpoint
report_to = None  # 设置上报实验指标的目标,默认值为无
MICRO_BATCH_SIZE = 4  # 定义微批次大小
BATCH_SIZE = 16  # 定义一个批次的大小
GRADIENT_ACCUMULATION_STEPS = BATCH_SIZE // MICRO_BATCH_SIZE  # 计算每个微批次累积的梯度步骤
CUTOFF_LEN = 256  # 设置文本截断的最大长度
LORA_R = 8  # 设置 LORA(Layer-wise Random Attention)的 R 值
LORA_ALPHA = 16  # 设置 LORA 的 Alpha 值
LORA_DROPOUT = 0.05  # 设置 LORA 的 Dropout 率
VAL_SET_SIZE = 0  # 设置验证集的大小,默认值为无
TARGET_MODULES = ["q_proj", "up_proj", "o_proj", "k_proj", "down_proj", "gate_proj", "v_proj"]  # 设置目标模块,这些模块的权重将被保存为 checkpoint。
device_map = "auto"  # 设置设备映射,默认值为 "auto"
world_size = int(os.environ.get("WORLD_SIZE", 1))  # 获取环境变量 "WORLD_SIZE" 的值,若未设置则默认为 1
ddp = world_size != 1  # 根据 world_size 判断是否使用分布式数据处理(DDP),若 world_size 为 1 则不使用 DDP
if ddp:device_map = {"": int(os.environ.get("LOCAL_RANK") or 0)}GRADIENT_ACCUMULATION_STEPS = GRADIENT_ACCUMULATION_STEPS // world_size

开始微调

# 创建指定的输出目录
os.makedirs(output_dir, exist_ok=True)
os.makedirs(ckpt_dir, exist_ok=True)# 根据 from_ckpt 标志,从 checkpoint 加载模型权重
if from_ckpt:model = PeftModel.from_pretrained(model, ckpt_name)# 准备模型以使用 INT8 进行训练
model = prepare_model_for_int8_training(model)# 使用 LoraConfig 配置 LORA 模型
config = LoraConfig(r=LORA_R,lora_alpha=LORA_ALPHA,target_modules=TARGET_MODULES,lora_dropout=LORA_DROPOUT,bias="none",task_type="CAUSAL_LM",
)
model = get_peft_model(model, config)# 将 tokenizer 的填充 token 设置为 0
tokenizer.pad_token_id = 0# 加载并处理训练数据
with open(dataset_dir, "r", encoding="utf-8") as f:data_json = json.load(f)
with open("tmp_dataset.json", "w", encoding="utf-8") as f:json.dump(data_json[:num_train_data], f, indent=2, ensure_ascii=False)data = load_dataset('json', data_files="tmp_dataset.json", download_mode="force_redownload")# 将训练数据分为训练集和验证集(若 VAL_SET_SIZE 大于 0)
if VAL_SET_SIZE > 0:train_val = data["train"].train_test_split(test_size=VAL_SET_SIZE, shuffle=True, seed=42)train_data = train_val["train"].shuffle().map(generate_training_data)val_data = train_val["test"].shuffle().map(generate_training_data)
else:train_data = data['train'].shuffle().map(generate_training_data)val_data = None# 使用 Transformers Trainer 进行模型训练
trainer = transformers.Trainer(model=model,train_dataset=train_data,eval_dataset=val_data,args=transformers.TrainingArguments(per_device_train_batch_size=MICRO_BATCH_SIZE,gradient_accumulation_steps=GRADIENT_ACCUMULATION_STEPS,warmup_steps=50,num_train_epochs=num_epoch,learning_rate=LEARNING_RATE,fp16=True,  # 使用混合精度训练logging_steps=logging_steps,save_strategy="steps",save_steps=save_steps,output_dir=ckpt_dir,save_total_limit=save_total_limit,ddp_find_unused_parameters=False if ddp else None,  # 是否使用 DDP,控制梯度更新策略report_to=report_to,),data_collator=transformers.DataCollatorForLanguageModeling(tokenizer, mlm=False),
)# 禁用模型的缓存功能
model.config.use_cache = False# 若使用 PyTorch 2.0 以上版本且非 Windows 系统,编译模型
if torch.__version__ >= "2" and sys.platform != 'win32':model = torch.compile(model)# 开始模型训练
trainer.train()# 将训练好的模型保存到指定目录
model.save_pretrained(ckpt_dir)# 打印训练过程中可能出现的缺失权重警告信息
print("\n 如果上方有关于缺少键的警告,请忽略 :)")

输出:

image-20240913155243608

测试微调后的模型

选取要加载的微调后的模型

# 查找所有可用的 checkpoints
ckpts = []
for ckpt in os.listdir(ckpt_dir):if ckpt.startswith("checkpoint-"):ckpts.append(ckpt)# 列出所有的 checkpoints
ckpts = sorted(ckpts, key=lambda ckpt: int(ckpt.split("-")[-1]))
print("所有可用的 checkpoints:")
print(" id: checkpoint 名称")
for (i, ckpt) in enumerate(ckpts):print(f"{i:>3}: {ckpt}")
""" 你可以(但不一定需要)更改 checkpoint """id_of_ckpt_to_use = -1  # 要用于推理的 checkpoint 的 id(对应上一单元格的输出结果)。# 默认值 -1 表示使用列出的最后一个 checkpoint。# 如果你想选择其他 checkpoint,可以将 -1 更改为列出的 checkpoint id 中的某一个。ckpt_name = os.path.join(ckpt_dir, ckpts[id_of_ckpt_to_use])""" 你可以(但不一定需要)更改解码参数 """
# 你可以在此处调整解码参数,解码参数的详细解释请见作业幻灯片。
max_len = 128  # 生成回复的最大长度
temperature = 0.1  # 设置生成回复的随机度,值越小生成的回复越稳定。
top_p = 0.3  # Top-p (nucleus) 采样的概率阈值,用于控制生成回复的多样性。
# top_k = 5  # 调整 Top-k 值,以增加生成回复的多样性并避免生成重复的词汇。

释放显存

为防止显存不足,我们先释放之前占用的显存。

import gc# 删除模型和 tokenizer 对象
del model
del tokenizer# 调用垃圾回收机制,强制释放未使用的内存
gc.collect()# 清理 GPU 缓存
torch.cuda.empty_cache()

加载模型和分词器

test_data_path = "GenAI-Hw5/Tang_testing_data.json"  # 测试数据集的路径
output_path = os.path.join(output_dir, "results.txt")  # 生成结果的输出路径cache_dir = "./cache"
seed = 42
no_repeat_ngram_size = 3# 配置模型的量化设置
nf4_config = BitsAndBytesConfig(load_in_4bit=True,bnb_4bit_quant_type="nf4",bnb_4bit_use_double_quant=True,bnb_4bit_compute_dtype=torch.bfloat16
)# 加载 tokenizer
tokenizer = AutoTokenizer.from_pretrained(model_name,cache_dir=cache_dir,quantization_config=nf4_config
)# 加载模型
model = AutoModelForCausalLM.from_pretrained(model_name,quantization_config=nf4_config,device_map={'': 0},cache_dir=cache_dir
)# 加载微调后的权重
model = PeftModel.from_pretrained(model, ckpt_name, device_map={'': 0})

生成测试结果

""" 建议不要更改此单元格中的代码 """results = []generation_config = GenerationConfig(do_sample=True,temperature=temperature,num_beams=1,top_p=top_p,no_repeat_ngram_size=no_repeat_ngram_size,pad_token_id=2
)# 读取测试数据集
with open(test_data_path, "r", encoding="utf-8") as f:test_datas = json.load(f)# 对每个测试样例生成预测,并保存结果
with open(output_path, "w", encoding="utf-8") as f:for (i, test_data) in enumerate(test_datas):predict = evaluate(test_data["instruction"], generation_config, max_len, test_data["input"], verbose=False)f.write(f"{i+1}. " + test_data["input"] + predict + "\n")print(f"{i+1}. " + test_data["input"] + predict)

输出:

image-20240913161131722

微调前后的对比

# 使用之前的测试例子
test_tang_list = ['相見時難別亦難,東風無力百花殘。','重帷深下莫愁堂,臥後清宵細細長。','芳辰追逸趣,禁苑信多奇。'
]# 使用微调后的模型进行推理
demo_after_finetune = []
for tang in test_tang_list:demo_after_finetune.append(f'模型輸入:\n以下是一首唐詩的第一句話,請用你的知識判斷並完成整首詩。{tang}\n\n模型輸出:\n' +evaluate('以下是一首唐詩的第一句話,請用你的知識判斷並完成整首詩。', generation_config, max_len, tang, verbose=False))# 打印输出结果
for idx in range(len(demo_after_finetune)):print(f"Example {idx + 1}:")print(demo_after_finetune[idx])print("-" * 80)

输出:

image-20240913161214578

“月明人不归,风起鸟不飞。”

可以看到和最开始有着很大的差别,最起码不是复读机了。

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

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

相关文章

13年计算机考研408-数据结构

解析&#xff1a; 这个降序链表不影响时间复杂度&#xff0c;因为是链表&#xff0c;所以你想要升序就使用头插法&#xff0c;你想要降序就使用尾插法。 然后我们来分析一下最坏的情况是什么样的。 因为m和n都是两个有序的升序序列。 如果刚好m的最大值小于n的最小值&#xff0…

消息中间件---Kafka

一、什么是Kafka&#xff1f; Kafka是一个分布式流处理平台,类似于消息队列或企业消息传递系统&#xff1b; 流处理事什么呢&#xff1f; 流处理就是数据处理工作流&#xff0c;本质上是一种计算机编程范例。流处理是对接收到的新数据事件的连续处理。‌它涉及对从生产者到消…

10年408考研真题-数据结构

23.[2010统考真题]若元素 a,b,c,d,e,f 依次进栈&#xff0c;允许进栈、退栈操作交替进行&#xff0c;但不允许连续3次进行退栈操作&#xff0c;不可能得到的出栈序列是(D)。 A.dcebfa B.cbdaef C.bcaefd D.afedcb 解析&#xff1a; 直接看D选项&#xff0…

Python | Leetcode Python题解之第420题强密码检验器

题目&#xff1a; 题解&#xff1a; class Solution:def strongPasswordChecker(self, password: str) -> int:n len(password)has_lower has_upper has_digit Falsefor ch in password:if ch.islower():has_lower Trueelif ch.isupper():has_upper Trueelif ch.isdi…

微服务保护之熔断降级

在微服务架构中&#xff0c;服务之间的调用是通过网络进行的&#xff0c;网络的不确定性和依赖服务的不可控性&#xff0c;可能导致某个服务出现异常或性能问题&#xff0c;进而引发整个系统的故障&#xff0c;这被称为 微服务雪崩。为了防止这种情况发生&#xff0c;常用的一些…

pytorch实现RNN网络

目录 1.导包 2. 加载本地文本数据 3.构建循环神经网络层 4.初始化隐藏状态state 5.创建随机的数据&#xff0c;检测一下代码是否能正常运行 6. 构建一个完整的循环神经网络 7.模型训练 8.个人知识点理解 1.导包 import torch from torch import nn from torch.nn imp…

Python画笔案例-057 绘制蜘蛛网

1、绘制蜘蛛网 通过 python 的turtle 库绘制 蜘蛛网,如下图: 2、实现代码 绘制蜘蛛网,以下为实现代码: """蜘蛛网.py """ import turtledef draw_circle(pos,r):"""p

实时数据的处理一致性

实时数据一致性的定义以及面临的挑战‍‍‍‍‍ 数据一致性通常指的是数据在整个系统或多个系统中保持准确、可靠和同步的状态。在实时数据处理中&#xff0c;一致性包括但不限于数据的准确性、完整性、时效性和顺序性。 下图是典型的实时/流式数据处理的流程&#xff1a; 1、…

Infineon——TC397 Multicore简介

文章目录 前言一、TC397简介二、命名规则三、多核开发建议 前言 AURIX™ TC3xx微控制器架构具有多达6个独立的处理器内核CPU0…CPU5, 可在一个统一平台上无缝托管多个应用程序和操作系统. 由于实现了具有独立读取接口的多个程序Flash模块, 该架构支持进一步的实时处理. AURIX™…

毕业设计选题:基于ssm+vue+uniapp的驾校预约管理系统小程序

开发语言&#xff1a;Java框架&#xff1a;ssmuniappJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;M…

iPhone16,超先进摄像头系统?丝滑的相机控制

iPhone 16将于9月20号正式开售&#xff0c;这篇文章我们来看下iPhone 16 在影像方面&#xff0c;有哪些升级和新feature。 芯片&#xff1a;采用第二代 3纳米芯片&#xff0c;A18。 摄像头配置&#xff1a; iPhone 16 前置&#xff1a;索尼 IMX714 &#xff0c;1200 万像素&am…

Red Hat 和 Debian Linux 对比

原图的作者(https://bbs.deepin.org/post/209759) Red Hat Enterprise Linux https://www.redhat.com/ CentOS Linux https://www.centos.org/ Fedora Linux https://fedoraproject.org/ Debian https://www.debian.org/ Ubuntu https://cn.ubuntu.com/ https://ubuntu.c…

harbor私有镜像仓库,搭建及管理

私有镜像仓库 docker-distribution docker的镜像仓库&#xff0c;默认端口号5000 做个仓库&#xff0c;把镜像放里头&#xff0c;用什么服务&#xff0c;起什么容器 vmware公司在docker私有仓库的基础上做了一个web页面&#xff0c;是harbor docker可以把仓库的镜像下载到本地&…

Matlab 的.m 文件批量转成py文件

在工作中碰到了一个问题&#xff0c;需要将原来用matlab gui做出来的程序改为python程序&#xff0c;因为涉及到很多文件&#xff0c;所以在网上搜了搜有没有直接能转化的库。参考了【Matlab】一键Matlab代码转python代码详细教程_matlab2python-CSDN博客 这位博主提到的matla…

Lanterns (dp 紫 线段树 二分 维护dp)

Lanterns - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 让所有点被覆盖&#xff0c;那么状态可以设计成覆盖一段前缀&#xff0c;并且中间不允许出现断点 由于CF崩了&#xff0c;所以暂时没提交代码。 记f(i) 为前 i 个灯笼点亮的最长前缀。 由于答案具有保留性&#xff…

自闭症孩子送寄宿学校,给他们成长的机会

在自闭症儿童的教育与康复之路上&#xff0c;选择一种合适的寄宿方式对于孩子的成长至关重要。这不仅关乎到孩子能否获得专业的训练与关怀&#xff0c;还直接影响到他们未来的社交能力、独立生活能力以及心理健康。今天&#xff0c;我们将以广州的星贝育园自闭症儿童寄宿制学校…

SOI 刻蚀气体

Liu, Yingjie, et al. "Very sharp adiabatic bends based on an inverse design." Optics letters 43.11 (2018): 2482-2485.

yolov8模型在手部关键点检测识别中的应用【代码+数据集+python环境+GUI系统】

yolov8模型在手部关键点检测识别中的应用【代码数据集python环境GUI系统】 背景意义 在手势识别、虚拟现实&#xff08;VR&#xff09;、增强现实&#xff08;AR&#xff09;等领域&#xff0c;手部关键点检测为用户提供了更加自然、直观的交互方式。通过检测手部关键点&#…

FreeSWITCH 简单图形化界面29 - 使用mod_xml_curl 动态获取配置、用户、网关数据

FreeSWITCH 简单图形化界面29 - 使用mod_xml_curl 动态获取配置、用户、网关数据 FreeSWITCH GUI界面预览安装FreeSWITCH GUI先看使用手册1、简介2、安装mod_xml_curl模块3、配置mod_xml_curl模块3、编写API接口4、测试一下5、其他注意的地方 FreeSWITCH GUI界面预览 http://m…

鸿蒙开发(NEXT/API 12)【跨设备互通特性简介】协同服务

跨设备互通提供跨设备的相机、扫描、图库访问能力&#xff0c;平板或2in1设备可以调用手机的相机、扫描、图库等功能。 说明 本章节以拍照为例展开介绍&#xff0c;扫描、图库功能的使用与拍照类似。 用户在平板或2in1设备上使用富文本类编辑应用&#xff08;如&#xff1a;…