当前位置: 首页 > news >正文

EAGLE代码研读+模型复现

要对代码下手了,加油(ง •_•)ง

作者在他们自己的设备上展现了推理的评估结果,受第三方评估认证,EAGLE为目前最快的投机方法(虽然加速度是评估投机解码方法的主要指标,但其他点也值得关注。比如PLD和Lookahead无需额外参数,更容易和许多模型进行集成),所有用来评估的方法都和Spec-Bench对齐。

设备:一台NVIDIA GeForce RTX 3090 GPU(24GB) ,带12个CPU核

测试环境:Pytorch 2.0.1,CUDA 11.8

环境设置:Vicuna-7B-v1.3,贪心解码,FP16精度,批量大小为1

EAGLE-2会利用草稿模型打出的信心分数去近似接受率,动态调整草稿的树形架构,进一步提升性能。EAGLE-2在两块RTX 3060 GPU上的推理速度,比原始的投机解码在一块A100 GPU上的推理速度要快。

设备:一台NVIDIA A100 GPU(80GB) ,带64个CPU核(比V100提升20倍的AI计算性能,实验室没有-_-,相较于RTX 4090、A40,更适合大模型AI训练)(看人家怎么说的,在8张RTX 3090 GPU上也能训练,1-2天完事儿,“so even the GPU poor can afford it”)(下面3张图看着乐呵一下,俺只有3090(≧∀≦)ゞ)

测试环境:Pytorch 2.0.1,CUDA 11.4

实验设置:贪心解码,FP16精度,批量大小为1

 

 


EAGLE已被集成到许多主流的LLM服务框架中了,比如Intel Extension for Transformers、vLLM、SGLang等等。

相应GitHub库的更新如下:2023.12.8发布EAGLE v1.0,2024.1.17起支持Mixtral-8x7B-Instruct、2024.2.25经第三方评估认证为最快的投机方法、2024.6.27发布EAGLE-2、2024.8.8起支持QWen-2(阿里巴巴集团QWen团队开发的第二代LLM系列,旨在提升自然语言处理和生成任务的性能)。不久的将来将发布EAGLE-3(2025.3.19更新:太牛了,我代码还没复现完它就出了)。


我选用的基础模型主要是Llama-2-chat-7B,该模型是由Meta(原Facebook)基于Transformer架构开发的开源LLM,有70亿参数,属于Llama-2系列中的较小版本,专为对话任务微调,适合交互式应用。


 配置并安装

git clone https://github.com/SafeAILab/EAGLE.git
cd EAGLE
pip install -r requirements.txt

在安装requirements.txt中的包时,要使用合适的python版本,比如我试过python3.11报错说没有“python3.11/site-packages/torch/include/torch/目录”,而3.9可以丝滑安装。

而且需要提前设置一下pip镜像,参考博客,不然慢不慢另说,还可能找不到某些版本的包而发生报错。

为什么要cd到这个目录呢?其实后面可以发现,许多文件里到处都是相对路径(🤯)也不是说一定要在这个目录吧,只是要改成对应的正确路径。

下载EAGLE权重

作者提供了各式目标模型对应的EAGLE参数的Hugging Face网址。对于在上面托管的模型,点开hugging face界面的“Use this model”-》Transformers库,一般可以看到两种使用transformer库的加载方法(下图microsoft/DialoGPT-small对应的界面这样)

一种使用高级封装pipeline,自动处理tokenization(文本切分)、模型推理、解码这些步骤,简单不灵活;一种手动加载模型和分词器,可自由调整参数,可扩展性强,代码复杂。 


1. 使用pipeline作为高级封装

# Use a pipeline as a high-level helper
from transformers import pipelinepipe = pipeline("text-generation", model="yuhuili/EAGLE-Vicuna-7B-v1.3")

pipeline是transformer库提供的一个高级封装,可自动处理tokenization(文本切分)、模型推理、解码这些步骤;"text-generation"任务代表使用自回归文本生成模型,比如GPT类模型(Vicuna也在其中);model="yuhuili/EAGLE-Vicuna-7B-v1.3"告诉pipeline下载该模型。加载后使用方法就是

result=pipe("Hello, how are you?")
print(result)

pipe()直接输入文本,返回生成的文本结果,通常是一个包含文本输出的列表。简单易用,适用于对性能要求不高时的快速部署。但缺乏灵活性,无法自定义tokenizer或model的参数,例如温度、最大长度等,且pipeline默认会尝试自动优化加载方式,可能消耗额外显存。

2. 手动加载模型和分词器

# Load model directly
from transformers import AutoTokenizer, AutoModelForCausalLMtokenizer = AutoTokenizer.from_pretrained("yuhuili/EAGLE-Vicuna-7B-v1.3")
model = AutoModelForCausalLM.from_pretrained("yuhuili/EAGLE-Vicuna-7B-v1.3")

tokenizer分词器负责将输入的文本转换为token,用于模型计算,并将模型的输出转换回人类可读的文本。从Hugging Face服务器下载该模型的权重和架构时,AutoModelForCausalLM适用于因果语言模型,如GPT、Vicuna这类基于自回归生成的Transformer模型。使用时需要手动处理输入输出

input_text = "Hello, how are you?"
input_ids = tokenizer(input_text, return_tensors="pt").input_ids  # 将文本转换为 token ID(张量格式)
output = model.generate(input_ids, max_length=50)  # 让模型生成文本,指定最大生成长度为50
result = tokenizer.decode(output[0], skip_special_tokens=True)  # 将生成的 token ID序列转换成字符串
print(result)

优点是高度可控,可以自由调整generate()里的参数,如温度、top_k、top_p等,提高生成质量,可以优化显存占用(如启用torch_dtype=torch.float16或device_map="auto"),适合大规模任务,可扩展性强,可与LoRA、DeepSpeed、FSDP等优化技术结合,可扩展性强。但代码复杂度高,默认不会自动优化显存占用,加载大模型时可能会超出GPU负载。 


但是,要真直接运行这代码,常会报错(≧∀≦)ゞ,比如EAGLE系列模型的就说没分词器啦~聊天小模型microsoft/DialoGPT-small就说输入内容格式不对啦~因为这代码是网站自动生成的,适用于通常情况。就以yuhuili/EAGLE-Vicuna-7B-v1.3的情况来说吧,点开“Files and versions”,下面确实没有分词器(可以拿上图比对一下)

咱就下载一下EAGLE weight🙄,直接运行下边这个得了,下载条拉满即可。

git lfs clone https://huggingface.co/yuhuili/EAGLE-llama2-chat-7B

 另外作者说了一下,目标模型是QWen时,应采用bf16而非fp16以避免数字溢出,两者都是16位浮点数格式,但指数和位数分布分配不同,BF16为8位指数7位尾数,数值范围接近FP32,FP16为5位指数10位尾数。草稿模型的训练数据集为ShareGPT,数据全英文,如果想要将其用在非英文,比如中文的数据上,需要用相应的数据进行训练。在EAGLE的基础上,EAGLE-2无需额外的训练,直接使用相同的权重。仓库提供的推理代码会自动分配模型权重,在多个GPU上加载模型,使得超出单个GPU内存的模型也能跑起来。(自动分布式吗?还挺牛的!看代码咋实现)

用UI体验

作者提供了网络端口,运行下列命令即可启动(damn!还得事先下载llama2-chat-7B)。等模型被完全加载,终端就会输出网址,点进去就跳到浏览器体验啦。(好好好显存不够,换台新的服务器。每当俺在一台新服务器上注册账号后,需要设置免密登录,安装Miniconda、pip,禁止自动激活base环境、安装扩展,scp文件,有时还得加速这个加速内个🙄)(还得小心代码中给你指定设备的情况)

python -m eagle.application.webui --ea-model-path [path of EAGLE weight]\ --base-model-path [path of the original model]\--model-type ["llama-2-chat","vicuna","mixtral","llama-3-instruct"]\--total-token [int]

total-token这个选项代表草稿token的数量,如果用的是较小的模型或先进的GPUs(没有:p)的话这个值可以大点。反正就根据具体的硬件和模型做调整,以达更好的性能吧。设成-1的话EAGLE-2会自动配置的(😭模型啥都能自动了而本菜鸡怎么活)。

3090GPU的服务器挂掉了,我换了台A40 GPU的服务器,这时仓库提供的requirement.txt中,torch和accelerate版本(2.0.1和0.21.0)会出现“设备映射”的问题,代码里有的地方又用的旧版本,而且轻易更换版本容易冲突,总之各种问题!再换台服务器吧😭

代码运行报错说让你安装什么包、什么版本,就照着报错提示去安装得了。

TODO: 怪我写的太慢,eagle3都出来了我还在这磨蹭!注意到eagle3中添加了一个参数”draft_vocab_size“,这难道可以控制草稿长度?后面看看!然后在eagle3版本的webui.py中有下面这么句代码,光从字面意思上看也很迷惑啊!加个“not”吧。

use_eagle3=args.no_eagle3,

特别解释一下-m选项,用于以模块方式运行Python脚本,告诉python查找eagle.application.webui这个模块并运行它(会去哪找eagle模块呢?当前目录以及PYTHON中),而无需手动cd进入目录再执行python webui.py,更灵活(吗?)

所以直接运行可能会遇到一个问题,如果你不是正处于EAGLE这一级目录(谁知道经历了前面一堆乱七八糟的时候跑到了哪个鬼目录),又在PYTHONPATH找不到eagle.application.webui这个模块的话,就会报错“Error while finding module specification for 'eagle.application.webui' (ModuleNotFoundError: No module named 'eagle')”。要么执行“cd xxx/EAGLE”回到正确目录,要么执行下列指令

export PYTHONPATH=xxx/EAGLE:$PYTHONPATH

(哪个办法好我也是反复横跳,最后结论是觉得前者麻烦,限死了终端执行目录,脚本文件存放位置。我倾向于后者,直接在终端执行的话,就临时添加一下,换个终端便没了,写到~/.bashrc文件里,source一下永久生效吧也行,下次换别的哪个模块的话改一下)

用第一种办法就每次在终端打那么老长的指令,也累,可以直接去改 eagle/application/webui.py下解析参数的代码,设成默认值,指令在“webui”后截断即可

python -m eagle.application.webui --ea-model-path ../EAGLE-llama2-chat-7B/ --base-model-path ../Llama-2-7b-chat-hf/ --model-type llama-2-chat --total-token 2

 感谢!下面看看弹出来的界面(两张图才截全,说真的,作者的界面都做得好好看இ௰இ)

我问这个负责任有道德的模型,为啥它有的字体显示橙色,它说它只会生成文本,没能力调颜色或用视觉特效,可能是设备、浏览器、平台或什么别的的锅。作者用gradio包做的网页,只需看上面的勾选框和解释即可知,橙色高亮部分是EAGLE-2正确猜测的token,上图便是将total-token设成2的结果。

这个纷繁复杂的交互式网页,是作者通过“ea_generate”流式返回模型每次前向的结果,以快速响应用户请求的。其中每次前向的结果output_ids的形状为(batch_size, sequence_length),都存到text里,其中第一个token由原始模型生成,存到naive_text里,剩下的token便是EAGLE-2的功劳。所以高亮哪些token呢?找text中naive_text里没有的。代码简陋一点看就是

for output_ids in model.ea_generate(input_ids, ...):...# decode_ids是截至本轮所有新生的tokendecode_ids = output_ids[0, input_len:].tolist() # 去掉输入部分decode_ids = truncate_list(decode_ids, model.tokenizer.eos_token_id) # 截断终止符后面的部分...text = model.tokenizer.decode(decode_ids, skip_special_tokens=True,spaces_between_special_tokens=False,clean_up_tokenization_spaces=True, )naive_text.append(model.tokenizer.decode(output_ids[0, cu_len], # 本轮首个tokenskip_special_tokens=True,spaces_between_special_tokens=False,clean_up_tokenization_spaces=True, ))cu_len = output_ids.shape[1]# 将text中naive_token里没有的内容高亮colored_text = highlight_text(text, naive_text, "orange")...

用代码体验

下面用“eagenerate”,一次性返回完整的token序列(体验感不如上面的好,有时会怀疑它卡了或者又要报错),就像用Hugging Face的“generate”那样,如下

from eagle.model.ea_model import EaModel
# EaModel,来自eagle.model.ea_model模块,一个用于NLP任务的模型类,支持从预训练模型加载权重
from fastchat.model import get_conversation_template
# get_conversation_template,来自fastchat.model,用于获取对话模板(如vicuna)
import torchdef warmup(model):# 按照目标模型类型创建对话模板conv = get_conversation_template(args.model_type)if args.model_type == "llama-2-chat":# Llama 2 Chat版本需要一个系统提示词,确保其回答安全无偏见符合道德,其他模型可能就无需这种额外约束了sys_p = "You are a helpful, respectful and honest assistant. Always answer as helpfully as possible, while being safe.  Your answers should not include any harmful, unethical, racist, sexist, toxic, dangerous, or illegal content. Please ensure that your responses are socially unbiased and positive in nature.\n\nIf a question does not make any sense, or is not factually coherent, explain why instead of answering something not correct. If you don't know the answer to a question, please don't share false information."conv.system_message = sys_pelif args.model_type == "mixtral":conv = get_conversation_template("llama-2-chat")conv.system_message = ''conv.sep2 = "</s>" # 特定结束符your_message="who are you?"# 将用户输入“hello”作为第一个角色(通常是用户)的话加入对话conv.append_message(conv.roles[0], your_message)# 给第二个角色(通常是AI模型)留一个空的响应位置,等待模型生成conv.append_message(conv.roles[1], None)# get_prompt()负责将对话格式化成适合EaModel处理的输入文本prompt = conv.get_prompt()if args.model_type == "llama-2-chat":prompt += " "# 分词器将prompt转换成token idinput_ids=model.tokenizer([prompt]).input_ids# 再转换成PyTorch张量,并转移到GPU提高推理效率input_ids = torch.as_tensor(input_ids).cuda()# 进行文本生成output_ids = model.eagenerate(input_ids,temperature=0.5,max_new_tokens=512) # eagenerate一次性返回完整的token序列output=model.tokenizer.decode(output_ids[0])print(output)# 使用命令行参数,添加参数解析(包已内置于python中)
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--ea_model_path",type=str,default="EAGLE-llama2-chat-7B",help="The path of EAGLE weight. This can be a local folder or a Hugging Face repo ID(<组织名或用户名>/<模型名>)."
)
parser.add_argument("--base_model_path",type=str,default="Llama-2-7b-chat-hf",help="path of the original model. a local folder or a Hugging Face repo ID"
)
parser.add_argument("--load_in_8bit",action="store_true", # 如果提供该参数,则值为True,否则默认为Falsehelp="use 8-bit quantization"
)
parser.add_argument("--load_in_4bit",action="store_true",help="use 4-bit quantization"
)
parser.add_argument("--model_type",type=str,default="llama-2-chat",choices=["llama-2-chat","vicuna","mixtral","llama-3-instruct"]
)
parser.add_argument("--total_token",type=int,default=-1,help=" the number of draft tokens"
)
parser.add_argument("--max_new_token",type=int,default=512,help="the maximum number of new generated tokens",
)
args = parser.parse_args()model = EaModel.from_pretrained(base_model_path=args.base_model_path,ea_model_path=args.ea_model_path,total_token=args.total_token,torch_dtype=torch.float16,low_cpu_mem_usage=True,load_in_4bit=args.load_in_4bit,load_in_8bit=args.load_in_8bit,device_map="auto",
)# 让模型进入推理模式,防止dropout等影响推理
model.eval()warmup(model)

eagle.application.webui里有解析参数的代码,但eagle.model.ea_model里没有,得在作者提供的调用代码里再额外填上,另外Vicuna、LLaMA2-Chat、LLaMA3-Instruct都是聊天模型,咱需要使用对应正确的聊天模板,不然会从模型里产生异常输出,影响EAGLE性能。我仿照webui.py的代码改了改。(不要两种体验同时用,一旦内存不够了它就给你报奇奇怪怪的错误)(一个来回的对话,而且比较久才回你)

训练

生成训练数据

先说一下文件调用结构,在原项目中,allocation.py将待处理的数据平均分配,各GPU执行各自任务,并行调用ge_data_all_llama2chat.py,使用llama2-chat-7B进行数据预处理、加载数据集、推理并保存结果。数据集的存储格式如下

new_examples = {"conversation": [], # 存储对话文本"input_ids": [], # 输入token ID"loss_mask": [] # 标记哪些token需要计算loss
}

预测结果被存储成.ckpt(checkpoint)文件,存储内容如下:

input_ids: Tensor, shape=torch.Size([151]), dtype=torch.int64
hidden_state: Tensor, shape=torch.Size([151, 4096]), dtype=torch.float16
loss_mask: Tensor, shape=torch.Size([151]), dtype=torch.int64

其中最重要的信息就是

hidden_state_big = outs_big.hidden_states[-1] # 提取最后一层隐藏状态

作者没有提供原数据集,咱去hugging face上随便找了个——shareGPT/computer_en_26k.jsonl。检查了一下,总共20692条数据,单拎第一条出来看看

{"conversation_id": "vtu3ZfW", "category": "Program and Code", "conversation": [{"human": "Give Landing page HTML and CSS with bootstrap framework that takes email address and phone number in the lead generation form", "assistant": "Here is an example of a basic landing page HTML structure using the Bootstrap framework:\n...server."}]
}

得据此修改ge_data_all_llama2chat.py中用到的键名,另外这个数据集没有清理的好,“category”的值存在字符串和列表混用的现象,得自己检查一遍,检查代码如下:

import pandas as pd
original_file = '/home/xxx/EAGLE_test/original_data/computer_en_26k.jsonl'
cleaned_file = '/home/xxx/EAGLE_test/original_data/computer_en_26k_cleaned.jsonl'try:df = pd.read_json(original_file, lines=True)print(df.head())
except Exception as e:print(f"Error loading JSON: {e}")# 检查 'category' 列是否存在类型不一致
print(df['category'].apply(type).value_counts())# 遍历 'category' 列并查找出现 list 的位置
for index, value in enumerate(df['category']):if isinstance(value, list):print(f"First occurrence of list in 'category' at row {index}")print(value)def clean_category(value):if isinstance(value, list):return ' '.join(value)elif isinstance(value, str):return valueelse:return str(value)df['category'] = df['category'].apply(clean_category)
df.to_json(cleaned_file, orient='records', lines=True)

用原代码中读取json文件的方式读取jsonl文件也行得通。额外说一下,jsonl文件的每行都是一个JSON(JavaScript Object Notation)格式数据。JSON是一种轻量级的数据交换格式,使用键值对存储数据,类似于Python的dict或JavaScipt的对象(Object)。.json文件通常是配置文件、模型索引、数据存储或API响应。


我摘取了前68条数据,在一台服务器的4张GPU上进行处理,运行指令(参数同样可以在文件中设置默认值)

python -m eagle.ge_data.allocation --outdir [path of data]

得到的训练数据如下

4个进程并行时的输出、文件命名方式都没有太大更改,原代码还是蛮清晰的,但有些逻辑错误,到后面就会发现他妈的loss_mask全零🤯!主要是修改ge_data_all_llama2chat.py中的映射代码

def preprocess_function(examples):new_examples = {"conversation":[], # 存储对话文本"input_ids": [], # token ID"loss_mask": [] # 标记哪些token需要计算loss}# 获取LLaMA-2对话模板conv = get_conversation_template("llama-2-chat")# 设定AI助手的形为准则sys_p="You are a helpful, respectful and honest assistant. Always answer as helpfully as possible, while being safe. " \"Your answers should not include any harmful, unethical, racist, sexist, toxic, dangerous, or illegal content. " \"Please ensure that your responses are socially unbiased and positive in nature.\n\n" \"If a question does not make any sense, or is not factually coherent, explain why instead of answering something not correct. " \"If you don't know the answer to a question, please don't share false information."conv.system_message=sys_p# 遍历数据集中的所有对话num_of_examples = len(examples['conversation_id'])for i in range(num_of_examples):source= examples['conversation'][i]conv.messages = []# 处理human和assistant的每轮对话for j, sentence in enumerate(source):if "human" in sentence and "assistant" in sentence:conv.append_message(conv.roles[0], sentence["human"])conv.append_message(conv.roles[1], " " + sentence["assistant"])else:print(f"Warning: Invalid or incomplete dialogue at index {j}: {sentence}")# 获取最终格式化后的对话文本conversation=conv.get_prompt()# 将对话转成token IDinput_ids = tokenizer(conversation,return_tensors="pt", # 结果返回PyTorch张量max_length=2048,truncation=True,).input_ids[0]# 创建一个形同input_ids的张量loss_mask,初始值全为1,默认所有token都会计算lossloss_mask=torch.ones_like(input_ids)# AI回复前的分隔符:“[/INST] ”sep = conv.sep + conv.roles[1] + " "# 将对话拆分为不同轮次,conv.sep2:“ </s><s>”turns = conversation.split(conv.sep2)# 忽略开始符<s>的loss计算cur_len = 1loss_mask[: cur_len] = 0# 处理每轮对话for j, turn in enumerate(turns):# print(f"本轮内容:{turn}") # 两轮对话三个turnif turn == "":breakturn_len = len(tokenizer(turn).input_ids) # 当前轮对话的token长度parts = turn.split(sep) # 拆分成用户输入和AI回复if len(parts) != 2:breakparts[0] += sepinst_len = len(tokenizer(parts[0]).input_ids) - 2 # 去掉开始符和结尾空格# 忽略(第一轮对话还额外有提示词部分)用户输入部分的loss计算loss_mask[cur_len : cur_len + inst_len] = 0cur_len += (turn_len + 2)if j != 0 and not tokenizer.legacy:# print("是新版,</s><s>只占2个token")cur_len -= 1# print(tokenizer.decode(input_ids[cur_len-2:cur_len]))# 忽略padding位置的loss计算(实际上似乎没有填充)loss_mask[cur_len:] = 0# 把格式化后的对话、token ID、loss_mask存入new_examplesnew_examples["conversation"].append(conversation)new_examples["input_ids"].append(input_ids[None,:])new_examples["loss_mask"].append(loss_mask[None,:])# print(f"loss_mask是什么类型啊现在?{type(new_examples['loss_mask'])}") # listreturn new_examples

而且用这么点数据训练肯定是不够的,后面会出现在训练集上的准确率嘎嘎提高,而在测试集上表现平平的情况,也就是过拟合了。干脆将jsonl文件中所有数据一并处理了,总20692条样本

wc -l path/to/file

好的,显存不够了😭原本我想换一台更加空闲的服务器,但已经换了几次服务器了,深知要想转到一台全新服务器有多麻烦,然后就想用docker把实验依赖的所有环境之类的一起打包,获取镜像、实例化容器,在新服务器上拉取巴拉巴拉……但是家人们,我这条菜狗又困在网络这一关了😭docker学习进程再次搁置。


更换策略,启用4-bit NF4量化,节省显存,如下更改代码

'''启用4-bit NF4量化,最节省显存'''
quantization_config = BitsAndBytesConfig(load_in_4bit=True,bnb_4bit_compute_dtype=torch.bfloat16, # 若GPU不支持bfloat16,改用torch.float16bnb_4bit_use_double_quant=True,bnb_4bit_quant_type="nf4", # Normalized Float 4
)
bigmodel = AutoModelForCausalLM.from_pretrained(bigname,quantization_config=quantization_config,device_map="auto"
)# "auto"会自动将模型的不同层分配到可用的GPU上,以实现模型并行
# bigmodel = AutoModelForCausalLM.from_pretrained(bigname, device_map="auto", torch_dtype=torch.float16)

 额外说一下,在AutoModelForCausalLM.from_pretrained中,device_map参数用于控制模型在多个GPU上的分配方式。“auto”和“balanced”是两种不同的分配策略,核心区别在于显存分配的智能程度和均匀性。

device_map="auto"时按层顺序分配,模型从第一层开始依次分配到当前显存最充足的GPU,直到占满该GPU的显存,再切换到下一个GPU,实现简单分配快,但可能导致现存利用率不均衡,某些GPU显存剩余较多,对显存碎片化较敏感。适用于模型层之间显存占用差异较小(如大部分Transformer模型)和GPU显存容量相同(下图我用的服务器的显存情况可能就不太符合?)的场景。(“gpustat -i 1”每隔1s刷新一次GPU使用信息)

device_map="balanced"时则是显存均匀分配,尽可能让每个GPU的显存占用接近均等,计算所有层的显存需求后,动态规划最优分配方案。其现存利用率高,可减少OOM风险,但分配计算开销稍大(首次加载略慢),适合模型层显存需求差异大(如MoE)和GPU显存容量不同的场景,对模型结构的适应性要求较高了。

建议就是优先尝试“balanced”,尤其是面对OOM时,若仍失败,就结合量化(4-bit)或手动分配,超大模型还可考虑offload_to_cpu(如accelerate库的device_map="auto"就支持CPU卸载)


(每个进程处理5173条数据)(如果还是OOM运行失败,但输出文件下的东西看着有模有样的,不要被骗啦!像我的,OOM时输出文件大小71G)(文件夹大小查看指令如下)

du -sh /path/to/directory

 allocation分配不同GPU并行,每个GPU上运行ge_data_all_llama2chat,让多个CPU进行数据处理,ctrl+z暂停指令(c才是终止)时,显存不一定释放,可用如下指令筛选一下自己的进程

ps aux | grep "$USER"  # 筛选属于当前用户的所有进程

或直接批量终止

ps aux | grep "my_ge_data_all_llama2chat.py" | grep -v "grep" | awk '{print $2}' | xargs kill -9

 记得在代码中常加入下列指令:

torch.cuda.empty_cache()

为什么需要这个PyTorch提供的函数?

《PyTorch的显存管理机制》:PyTorch会使用CUDA内存缓存机制来加速张量分配和计算,当释放张量时(如del tensor或变量超出作用域)时,PyTorch不会立即将显存归还给系统,而是保留在内部的缓存池中,当后续需要重新分配新张量时,优先从缓存中复用显存,而非重新向CUDA申请,以便快速重用,减少显存分配的开销。具体地,PyTorch使用分块内存池(Block-based Memory Pool)管理显存,显存被划分为不同大小的块,分配张量时PyTorch会寻找大小最匹配的块,减少碎片化,释放张量时,块会被标记为空闲,供后续使用。但这种缓存机制就可能会导致显存占用看起来比实际需求更高。 

《显存碎片化问题》若频繁分配和释放不同大小的张量,显存可能变得碎片化,即剩余显存被分割为小块,无法满足大块请求,此时即使显存总量足够,PyTorch也可能因找不到足够大的连续显存块而报CUDA out of memory错误。PyTorch的显存管理机制正是通过块复用、合并相邻空闲块、按大小分类管理等方式减少碎片化。

empty_cache()的作用就在于强制释放PyTorch缓存的未使用显存,使其归还给系统,减少显存碎片化,提高显存利用率。

另外进一步优化显存管理的方法还有复用张量(避免在循环中反复创建临时张量),还有按照报错“torch.cuda.OutOfMemoryError: CUDA out of memory. Tried to allocate 20.00 MiB (GPU 0; 23.68 GiB total capacity; 1.06 GiB already allocated; 12.06 MiB free; 1.13 GiB reserved in total by PyTorch) If reserved memory is >> allocated memory try setting max_split_size_mb to avoid fragmentation.  See documentation for Memory Management and PYTORCH_CUDA_ALLOC_CONF”提示的那样,如下调整分配策略,减少每次分配的内存块最大大小,减少碎片化:

os.environ["PYTORCH_CUDA_ALLOC_CONF"] = "max_split_size_mb:32"

可以通过如下代码监控显存使用

'''检查显存占用情况'''
def print_memory():allocated = torch.cuda.memory_allocated() / 1024**3reserved = torch.cuda.memory_reserved() / 1024**3print(f"Allocated: {allocated:.2f}GB | Reserved: {reserved:.2f}GB")

 终于不报错了,可能在1h的推理等待后,成功输出文件的大小在138G,友友们可以帮我检查一下!

训练自回归头

接下来用前面获取的checkpoint训练自回归头。训练代码和设置可参考eagle/train/


期间有几点说明,.safetensors是一种专门用于存储神经网络权重的二进制文件格式(不能直接用文本编辑器打开,需用safetensors库解析),由Hugging Face团队开发,作为PyTorch的.pt或.bin文件更安全高效的替代方案。具体地,

1.更安全。其仅支持张量数据的存储,即使部分文件损坏,仍可加载其他部分,存储结构固定,而.bin(通常是torch.save生成的PyTorch权重文件)可以包含任意Python对象,若加载不受信任的.bin文件,可能导致代码执行漏洞(Pickle反序列化攻击),若文件损坏,可能整个模型都无法加载,若PyTorch版本不同,可能导致序列化格式变化,影响兼容性。

2. 更快。其支持按需加载(lazy loading),避免不必要数据传输,而.bin必须一次性全部加载

3. 更节约内存。其通过零拷贝(zero-copy)方式映射到内存,而.bin需要将数据从磁盘拷贝到内存,增加了额外开销

存储权重数据的二进制.safetensors文件通常有索引文件.index.json,内容如下:(本节在预训练模型上较关心的正是它的语言建模头lm_head)

{"metadata": {"total_size": 13476835328},"weight_map": {"lm_head.weight": "model-00002-of-00002.safetensors","model.embed_tokens.weight": "model-00001-of-00002.safetensors","model.layers.0.input_layernorm.weight": "model-00001-of-00002.safetensors","model.layers.0.mlp.down_proj.weight": "model-00001-of-00002.safetensors",...}
}

这些文件在原先下载的预训练模型下都配好了👌 

将上图高亮的.safetensors文件中部分张量的键名和形状输出,有如下图


再简要介绍一下W&B(这种工具本菜狗才发现இ௰இ)。它是一个机器学习实验管理平台,提供了强大的工具来追踪、可视化和优化模型训练过程,允许用户记录和管理实验的超参数、损失函数、评估指标等,支持实现可视化训练曲线,并为团队提供协作和版本控制功能。通过与常见机器学习框架(如TensorFlow、PyTorch)无缝集成,W&B可帮助开发者更高效地管理实验、提高模型性能,并加速团队的研究与开发进程。!!!想用它得用点魔法访问网站!!!

1. 在Python环境中安装W&B

pip install wandb

2. 在W&B官网注册一个账号,并登录

wandb login <API key>
# 然后终端会输出:wandb: Appending key for api.wandb.ai to your netrc file: /xx/xx/.netrc

3. 在代码中导入wandb库并初始化一个新的实验

import wandb
wandb.init(project="your_project_name")

4. 记录实验参数(config)

wandb.config.batch_size = 32
wandb.config.epochs = 10
wandb.config.learning_rate = 0.001

 5. 记录训练过程中的数据(log追踪)

# 假设在训练过程中记录每个epoch的损失和准确率
for epoch in range(10):loss = train_one_epoch()accuracy = evaluate_model()wandb.log({"epoch": epoch, "loss": loss, "accuracy": accuracy})

6. 若想在训练结束后保存模型,也可将其与W&B关联,进行版本控制

wandb.save('path_to_your_model.h5')

 7. 结束实验

wandb.finish()

每次运行完wandb.init()后,W&B会自动创建一个新页面,记录该实验的所有信息 。


关于BF16:Bfloat16是一种16-bit浮点数格式,主要由Google提出,并在其TPU和一些NVIDIA A100等加速器中得到了广泛使用。与FP16相比,其在数值范围和精度表示上做了不同的权衡,FP16使用5位指数位,10位尾数位;BF16使用8位指数位,7位尾数位,其指数范围和FP32相当,使其能表示更广泛的数值范围,于神经网络训练中的梯度计算和大数值表示非常有用。


面对OOM问题时还可以用一个PyTorch的梯度检查点(gradient checkpointing)技术,以显著减少显存占用(↓50%~70%),但会略增加计算时间(↑20%~30%)。

问题背景:训练深度神经网络时,前向传播计算的中间结果需要保存,以便在反向传播时计算梯度,这些中间结果就会占用大量GPU显存,尤其是大模型(如Llama-2-7B)。

解决方法:只保留部分关键中间结果,其余的在反向传播时重新计算,用计算时间换显存。

from torch.utils.checkpoint import checkpoint # 导入检查点功能def _forward(self, x):return self.layer2(self.layer1(x)) # 模型的计算逻辑(如Transformer层的堆叠)def forward(self, x):return checkpoint(self._forward, x) # 使用检查点包装前向计算'''关键点解释:
1. checkpoint(func, *args)func:要优化的前向计算函数(如self._forward)*args:传给func的输入(如x)作用:PyTorch不会保存func的中间激活值,而是在反向传播时重新计算它们
2. self._forward(x)是你模型的实际前向计算逻辑(如nn.Module的forward方法)
'''''' 进阶操作如下 '''# 只对显存占用高的部分使用检查点
def forward(self, x):x = checkpoint(self.layer1, x)x = self.layer2(x)    # layer2正常计算return x# 调整检查点频率
def forward(self, x):if self.training: # 仅在训练时使用检查点return checkpoint(self._forward, x)else:    # 推理时不使用,避免额外计算return self._forward(x)

 事先说一下我们将要处理的数据,原始数据集shareGPT/computer_en_26k.jsonl有20692条对话样本,把里面的“category”类处理一下,清洗后的数据集文件cleaned.jsonl文件中样本数是一样的(.jsonl文件每行是一个JSON样本,可用wc -l file_path进行查看),处理成20692个ckpt文件,从中抽取0.95用作训练的话,训练样本数就是19657。然后accelerator检测到服务器上有3块GPU,咱为了避免OOM设置了较小的批处理大小,为2,故每个训练epoch的进度条显示有“/3277”,测试时显示“/173”。

为什么说OOM时老说要减少批处理大小?(原先通过LLM推理获取数据集时批处理大小就是1了)加载模型本身需要固定显存,例如LLaMA-2-7B的4-bit量化后,7B参数,每个0.5个字节,再加些七七八八的,实际推理时的经验值为6-8GB;然后每增加一个样本,前向传播的中间结果就会线性增加显存占用,故总显存≈模型参数+批处理大小×单样本激活值显存。

好不容易准备好数据集,运行下列代码进行训练(我和网络和OOM问题不共戴天!)

accelerate launch -m --mixed_precision=bf16 eagle.train.main --tmpdir [path of data]\
--cpdir [path of checkpoints] --configpath [path of config file]

 跑了超4h,约10min/训练epoch(明白为啥原代码只20个epoch了),可以将代码放到后台开始运行,即使电脑关闭也不影响服务器继续当牛做马。首先创建一个新会话,运行下列指令后便会进入一个新终端,此时再打开另一个终端窗口,输入tmux ls便能看到包含它在内的会话列表。

tmux new -s <会话名>

在tmux会话中输入要在后台运行的指令。如果想滚动查看窗口内容,可以配置一下鼠标支持,即在~/.tmux.conf中添加如下配置后重载(tmux source-file ~/.tmux.conf)

set -g mouse on  # 允许鼠标滚动和选择面板

 创建会话后键入Ctrl+B, 松手,再按D就能从前台分离会话,通过如下指令又能重新连接

tmux attach -t <会话名>

创建会话后键入Ctrl+B,松手,再按C就能新建又一个窗口,执行exit就能退出当前窗口,当最后一个窗口也被关闭时,整个会话会被自动删除。

利用tmux就能方向地关闭电脑了吗?No,还记得前面提到的,为了使用W&B,做了到本地代理的端口映射吗?这个Clash还不能关!或者说我设置了透明代理,代理IP就是本机的IPv4地址,那本机就不能关!我们的确将程序放在服务器上由tmux托管,一般本机关闭并不影响程序本体的继续运行,但这里一旦关机,目标代理IP无法连接,网络请求就会失败。W&B还挺好用的,又自动给你画图,又记录日志的,我们的服务器又不能科学上网,自己的这破电脑就一直开着呗。


 区分一下几个指标 

交叉熵损失:(plogp是 目标概率分布 与 模型预测的对数概率 的乘积,loss_mask用于忽略无效位置的损失)用于衡量模型预测的token分布和真实token分布的差异,适用于分类任务

out_head = head(predict)
out_logp = nn.LogSoftmax(dim=2)(out_head)
plogp = target_p * out_logp
cross_entropy_loss = -torch.sum(torch.sum(loss_mask * plogp, 2)) / (loss_mask.sum() + 1e-5)

平滑L1损失:计算模型预测的隐藏状态predict与目标隐藏状态target之间的差异

# 平滑L1损失(又称Huber损失)(介于绝对误差损失和均方误差之间的损失函数)
criterion = nn.SmoothL1Loss(reduction="none")
...
smooth_L1_loss = criterion(predict, target)
smooth_L1_loss = torch.sum(torch.mean(loss_mask * smooth_L1_loss, 2)) / (loss_mask.sum() + 1e-5)

Top-k准确率:top-1即标准准确率,指示预测的最高概率token是否正确,top-2/3表示前2/3个token是否包含正确答案,用于评估语言模型的预测能力

def top_kaccuracy(output, target, topk=(1, 2, 3)):
'''
预测头输出output的形状为(bs, num_classes)
目标输出target的形状为(bs,)
'''with torch.no_grad():maxk = max(topk) # 3_, pred = output.topk(maxk, 1, True, True) # 取预测分数前3名,分数忽略,索引保留pred = pred.t() # pred形状转置为(maxk, bs)correct = pred.eq(target.view(1, -1).expend_as(pred)

 关于deepspeed:它是由Microsoft开发的深度学习优化库,旨在通过高效的内存管理、分布式训练和混合精度训练等技术,显著提高大规模模型的训练效率。利用零冗余优化器(ZeRO)减少显存占用,支持训练数十亿参数的超大模型(如GPT-3),还支持数据并行、模型并行和多机多卡训练,能在有限的硬件资源上加速训练过程,并广泛用于NLP、CV等领域的大规模深度学习任务。

很抱歉写到这里我打算放弃了,有点戛然而止的感觉,而且前面写的也乱七八糟。主要是在完成主线任务的时候本人太菜了会遇到很多支线问题,而且原论文提供的代码里也存在一些很明显的错误,会让人不禁怀疑这是否是一篇high level的论文,然后实验室挂了两台有3090的服务器成了“最后一根稻草”,我想过换另一台显存很局限的3090服务器,或一台有A40的服务器、或拿师兄买的4090服务器,但停下来审视一番后还是算了,其实也算走完了训练这一步,最后也是在整理和修改原作者的代码。我想再去探索一下别的科研方向,很感谢eagle的作者🙇‍,研究了代码之后我对论文的理解会更加深刻,也会感慨现在的论文能被接收很不容易,同时在和代码搏斗的这个月里俺也学到了很多东西,这就够了。最后最后,谢谢友友们能看到这里🌼

相关文章:

EAGLE代码研读+模型复现

要对代码下手了&#xff0c;加油(ง •_•)ง 作者在他们自己的设备上展现了推理的评估结果&#xff0c;受第三方评估认证&#xff0c;EAGLE为目前最快的投机方法&#xff08;虽然加速度是评估投机解码方法的主要指标&#xff0c;但其他点也值得关注。比如PLD和Lookahead无需额…...

多线程使用——线程安全、线程同步

一、线程安全 &#xff08;一&#xff09;什么是线程安全问题 多个线程&#xff0c;同时操作同一个共享资源的时候&#xff0c;可能会出现业务安全的问题。 &#xff08;二&#xff09;用程序摹拟线程安全问题 二、线程同步 &#xff08;一&#xff09;同步思想概述 解决线…...

基于 Linux 环境的办公系统开发方案

基于 Linux 环境的办公系统开发方案 一、项目概述 1.1 项目背景 在当今数字化办公的时代&#xff0c;高效、稳定且功能丰富的办公系统对于企业和组织的日常运营至关重要。Linux 作为一种开源、稳定且高度可定制的操作系统&#xff0c;拥有庞大的开发者社区和丰富的软件资源&…...

mysql8.0.17以下驱动导致mybatis blob映射String乱码问题分析与解决

mysql8.0.17以下驱动导致blob映射String乱码问题分析与解决 一、问题复现二、问题深究三、解决方法方法1方法2 一、问题复现 1、docker安装mysql8.0&#xff0c;并创建测试数据库及测试数据表 CREATE DATABASE test DEFAULT CHARACTER SET utf8mb4; use test; CREATE TABLE t…...

Unity Nav Mesh导航系统的简单使用

标题 1.下载。2.面板位置3.object面板4.Area面板5.Bake面板6.Agent面板7.Nav Mesh Agent组件8.Nav Mesh Obstacle组件9.简单使用 1.下载。 unity2022以上版本要去packageManager中下载。 2.面板位置 3.object面板 Navigation Static&#xff1a;设置该物体是否被列入静态寻路…...

从零开始学A2A五:A2A 协议的安全性与多模态支持

A2A 协议的安全性与多模态支持 一、A2A 协议安全机制 1. 认证机制 A2A 协议采用多层次认证机制&#xff0c;确保智能体身份的真实性和通信的安全性。 基于 Agent Card 的身份认证&#xff1a; {"agent_id": "secure_agent_001","authentication&…...

PyTorch源码编译报错“fatal error: numpy/arrayobject.h: No such file or directory”

记录一下这个bug的fix过程 一开始以为是版本问题&#xff0c;尝试了几个不同版本都不可以&#xff0c;遂排除版本问题的可能 定位 首先 pip list 看到确实安装了这个库 接着 pip show 查看 numpy 库的安装路径 numpy/arrayobject.h 是 NumPy 的 C-API 头文件&#xff0c;其…...

[Java EE] Spring AOP 和 事务

目录 1. AOP 1.1 AOP 概念 1.2 AOP 核心概念 1.3 AOP 作用 2. AOP 详解 2.1 切点(Pointcut) 2.2 连接点(Join Point) 2.3 通知(Advice) 2.4 切面(Aspect) 2.5 通知类型 2.5.1 Around 环绕通知 2.5.2 Before 前置通知 2.5.3 After 后置通知 2.5.4 AfterReturning …...

2025年KBS SCI1区TOP:增强天鹰算法EBAO,深度解析+性能实测

目录 1.摘要2.天鹰算法AO原理3.改进策略4.结果展示5.参考文献6.代码获取 1.摘要 本文提出了增强二进制天鹰算法&#xff08;EBAO&#xff09;&#xff0c;针对无线传感器网络&#xff08;WSNs&#xff09;中的入侵检测系统&#xff08;IDSs&#xff09;。由于WSNs的特点是规模…...

适合IIS部署网页应用的编程语言

直接部署在 IIS 上的语言/技术 PHP 使用 FastCGI 模块直接集成安装 PHP Manager for IIS 可简化配置示例配置&#xff1a;在 web.config 中添加处理程序映射指向 php-cgi.exe Node.js 使用 iisnode 模块实现直接集成允许 Node.js 应用在 IIS 进程中运行支持进程管理、负载均衡…...

43.[前端开发-JavaScript高级]Day08-ES6-模板字符串-展开运算符-ES7~ES11

ES6~ES13新特性&#xff08;二&#xff09; 1 模板字符串的详解 字符串模板基本使用 标签模板字符串使用 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content…...

边生成边训练:构建合成数据驱动的在线训练系统设计实战

目录 边生成边训练&#xff1a;构建合成数据驱动的在线训练系统设计实战 一、系统目标与能力总览 ✅ 核心目标&#xff1a; 二、系统架构图&#xff08;推荐用于PPT展示&#xff09; 三、关键模块设计解析 ✅ 1. 合成数据生成器模块 ✅ 2. 质量评分器模块 ✅ 3. 在线训…...

AF3 create_alignment_db_sharded脚本main函数解读

AlphaFold3 create_alignment_db_sharded 脚本在源代码的scripts/alignment_db_scripts文件夹下。 该脚本中的 main 函数是整个对齐数据库生成脚本的核心入口,它 orchestrates(编排)了所有流程,从读取链目录到生成 .db 文件、构建索引、处理重复链、写入最终索引文件。 ma…...

52. Java 类和对象 - 什么是隐藏字段?

文章目录 52. Java 类和对象 - 什么是隐藏字段&#xff1f;&#x1f3af; 参数名称的作用与规则✅ 参数名称的命名规则 &#x1f3af; 什么是隐藏字段&#xff1f;&#x1f6a8; 问题定义✅ 解决办法&#xff1a;使用 this 关键字 &#x1f3af; 如何避免隐藏字段带来的困扰&am…...

IntelliJ IDEA右键快捷方式设置方法

IntelliJ IDEA右键快捷方式设置方法 在 IntelliJ IDEA 中设置右键快捷方式快速打开项目或文件&#xff08;Windows 系统&#xff09;&#xff0c;可以通过以下方法实现&#xff1a; 方法 1&#xff1a;通过注册表添加右键菜单&#xff08;推荐&#xff09; 打开注册表编辑器 按…...

深入剖析JavaScript内存泄漏:识别、定位与实战解决

在JavaScript的世界里&#xff0c;开发者通常不必像使用C那样手动管理内存的分配和释放&#xff0c;这得益于JavaScript引擎内置的垃圾回收&#xff08;Garbage Collection, GC&#xff09;机制。然而&#xff0c;这并不意味着我们可以完全忽视内存管理。“自动"不等于&qu…...

JVM原理与实战

一、Java虚拟机概述 java程序通过虚拟机实现了java代码的跨平台。 二、java虚拟机运行过程&#xff1a; 类编译器编译java代码为class文件&#xff0c; 类加载器将class文件加载到jvm&#xff0c; 程序计数器控制程序的执行&#xff0c; 虚拟机栈存放局部变量&#xff0c;方法名…...

MCP协议用到的Node.js 和 npm npx

一、Node.js 与 npm、npx 的介绍 Node.js&#xff1a;是一个基于 Chrome V8 引擎的 JavaScript 运行时环境&#xff0c;使您能够在服务器端运行 JavaScript 代码。它广泛用于构建服务器端应用程序和工具。 npm&#xff08;Node Package Manager&#xff09;&#xff1a;是 Nod…...

如何写 commit message?

前言 每次写 commit message 时&#xff0c;都会纠结用什么动词&#xff0c;格式应该什么样&#xff0c;所以决定总结一下。 查了一下&#xff0c;还是挺复杂的。因为只面向我个人日常使用&#xff0c;所以只进行一些简单的、适合我的总结。 正文 message 分为两部分&#…...

【厦门大学】DeepSeek大模型赋能高校教学和科研

DeepSeek赋能高校教学和科研 引言人工智能发展简史&#xff1a;从图灵测试到大模型时代大模型核心技术解析&#xff1a;构筑智能金字塔DeepSeek赋能高校&#xff1a;打造智能校园生态本地部署方案&#xff1a;安全、高效与定制化兼得教学革新&#xff1a;重塑知识传授与学习体验…...

【专刷】滑动窗口(一)

&#x1f4dd;前言说明&#xff1a; 本专栏主要记录本人的基础算法学习以及LeetCode刷题记录&#xff0c;按专题划分每题主要记录&#xff1a;&#xff08;1&#xff09;本人解法 本人屎山代码&#xff1b;&#xff08;2&#xff09;优质解法 优质代码&#xff1b;&#xff…...

cJSON_Print 和 cJSON_PrintUnformatted的区别

cJSON_Print 和 cJSON_PrintUnformatted 是 cJSON 库中用于将 cJSON 对象转换为 JSON 字符串的两个函数&#xff0c;它们的区别主要在于输出的格式&#xff1a; 1. cJSON_Print 功能&#xff1a;将 cJSON 对象转换为格式化的 JSON 字符串。 特点&#xff1a; 输出的 JSON 字符…...

C 语 言 --- 指 针 4(习 题)

C 语 言 --- 指 针 4&#xff08;习 题&#xff09; sizeofstrlen整 型 数 组 - - - int a[ ]字 符 数 组 - - - char arr[ ]字 符 数 组 - - - char arr1[ ]字 符 串 常 量 指 针 - - - char arr[ ]二 维 数 组 - - - char arr[3][4]总结 &#x1f4bb;作 者 简 介&#xff1a…...

可发1区的超级创新思路(python 、MATLAB实现):基于区域注意力双通道MABMA的时间序列预测模型

首先声明,该模型为原创!原创!原创!且该思路还未有成果发表,感兴趣的小伙伴可以借鉴! 应用领域:功率预测、故障诊断、流量预测等领域! 目录 首先声明,该模型为原创!原创!原创!且该思路还未有成果发表,感兴趣的小伙伴可以借鉴! 应用领域:功率预测、故障诊断、流…...

可发1区的超级创新思路(python 、MATLAB实现):基于多尺度注意力TCN-KAN与小波变换的时间序列预测模型

一、数学模型与原理 1.1 小波变换多尺度分解 输入功率序列 x(t) 经小波变换分解为近似系数 Aj​ 与细节系数 Dj​: 1.2 多尺度TCN特征提取 对每个尺度子序列 {A3​,D3​,D2​,D1​} 采用独立TCN: 式中 ∗d​ 为扩张率 d=2l 的扩张卷积,Wd​ 为可学习参数。 1.3 多尺度注…...

PyTorch `flatten()` 和 `squeeze()` 区别

PyTorch flatten() 和 squeeze() 区别 在 PyTorch 里,flatten() 和 squeeze(0) 是两个不同的张量操作, 1. flatten() 方法 flatten() 方法用于把一个多维张量展开成一维张量。它会将张量里的所有元素按顺序排列成一个一维序列。 语法 torch.flatten(input, start_dim=...

使用Java基于Geotools的SLD文件编程式创建与磁盘生成实战

前言 在地理信息系统&#xff08;GIS&#xff09;领域&#xff0c;地图的可视化呈现至关重要&#xff0c;而样式定义语言&#xff08;SLD&#xff09;文件为地图元素的样式配置提供了强大的支持。SLD 能够精确地定义地图图层中各类要素&#xff08;如点、线、面、文本等&#x…...

opencv练习

1.创建一个 PyQt 应用程序&#xff0c;该应用程序能够&#xff1a; &#xff08;1&#xff09;使用 OpenCV 加载一张图像。 &#xff08;2&#xff09;在 PyQt 的窗口中显示这张图像。 &#xff08;3&#xff09;提供四个按钮&#xff08;QPushButton&#xff09;&#xff1…...

opencv--基础

opencv OpenCV是一个实现数字图像处理和计算机视觉通用算法的开源跨平台库。 链接 opencv中的cv是什么意思 在OpenCV中&#xff0c;"cv" 是 "Computer Vision"&#xff08;计算机视觉&#xff09; 的缩写。 opencv的实现语言 opencv的底层实现代码是使…...

基于模板匹配的信用卡号码识别系统

本项目实现了一个基于模板匹配的信用卡号码识别系统。 1. 导入库和设置参数 # -*- coding: utf-8 -*- # 导入工具包 from imutils import contours import numpy as np import argparse import cv2 import myutils import os# 设置参数 ap argparse.ArgumentParser() # 替换…...

Spring Boot中Excel处理完全指南

文章目录 1. Excel处理基础知识1.1 为什么需要在应用中处理Excel文件?1.2 Java中的Excel处理库介绍1.2.1 Apache POI1.2.2 EasyExcel1.2.3 JExcel1.2.4 Apache POI SXSSF1.3 Spring Boot中集成Excel处理2. 在Spring Boot中集成Excel处理库2.1 集成Apache POI2.1.1 添加依赖2.1…...

洛谷P1312 [NOIP 2011 提高组] Mayan 游戏

题目 #算法/进阶搜索 思路: 根据题意,我们可以知道,这题只能枚举,剪枝,因此,我们考虑如何枚举,剪枝. 首先,我们要定义下降函数down(),使得小木块右移时,能够下降到最低处,其次,我们还需要写出判断函数,判断矩阵内是否有小木块没被消除.另外,我们还需要消除函数,将矩阵内三个相连…...

c++ (异常)

1.异常的概念及使用 1.1异常的概念 异常处理机制允许程序中独立开发的部分能够在运行时就出现的问题进行通信并做出相应的处理&#xff0c; 异常使得我们能够将问题的检测与解决问题的过程分开&#xff0c;程序的一部分负责检测问题的出现&#xff0c;然后 解决问题的任务传…...

MySQL如何实现行行比较

概述 在MySQL中实现行行比较通常涉及比较同一表或不同表中不同行的数据。以下是几种常见的方法及示例&#xff1a; 1. 自连接&#xff08;Self-Join&#xff09; 通过将表与自身连接&#xff0c;比较不同行的数据。 场景示例&#xff1a;比较同一用户相邻订单的金额差异。 …...

springboot2.X创建maven多模块工程

因为需要&#xff0c;所以付出。 好长时间没有搭建新的框架了&#xff0c;最近在搭建微服务的多模块maven工程&#xff0c;现在就将创建的过程记录下来&#xff0c;方便自学的小伙伴找寻资料&#xff0c;少走弯路。好了下面直接开干。 开发工具 &#xff1a;idea 、springboo…...

八股文---Redis(1)

目录 1.Redis-使用场景 1.我看你做的项目中&#xff0c;都用到了redis&#xff0c;你在最近的项目中哪些场景使用了redis呢&#xff1f; 2.缓存三兄弟可以我看我另一个文章&#xff08;穿透&#xff0c;雪崩&#xff0c;击穿&#xff09; 3.redis做为缓存&#xff0c;mysql…...

QT聊天项目DAY06

1.从git上同步项目 编译测试&#xff0c;编译通过 Post请求测试 测试成功 2. email is 打印有问题&#xff0c;检查 解析结果是存储在jsonResult中的&#xff0c;修改 3. 客户端实现Post验证码请求 3.1 同步Qt客户端项目 检查QT版本&#xff0c;由于我在公司用的还是QT5.12.9…...

python(八)-数据类型转换

#数据类型转换 #转换为整型int #字符串str--》整数int #纯数字的字符串可以转换&#xff0c;否则会报错 s 2025 n int(s) print(type(s),type(n)) print(n)#浮点数float--》整数int s1 2.23 print(int(s1))#bool-->整数int s2,s3 True,False print(int(s2),int(s3))#转…...

JavaScript 变量命名规范

在编写JavaScript代码时&#xff0c;遵循良好的变量命名规范对于提高代码的可读性、可维护性和协作效率至关重要。一个清晰且一致的命名习惯不仅有助于开发者自己理解代码&#xff0c;也能让其他团队成员更容易上手和维护项目。本文将详细介绍JavaScript中常见的变量命名规则和…...

2025年渗透测试面试题总结-拷打题库05(题目+回答)

网络安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。 目录 2025年渗透测试面试题总结-拷打题库05 1. 病毒和蠕虫的区别 2. DNS欺骗&#xff08;DNS Spoofing&…...

【排队论】Probabilistic Forecasts of Bike-Sharing Systems for Journey Planning

Probabilistic Forecasts of Bike-Sharing Systems forJourney Planning abstract 我们研究了对共享单车系统&#xff08;BSS&#xff09;车站未来自行车可用性进行预测的问题。这是相关的&#xff0c;以便提出建议&#xff0c;保证用户能够进行旅行的概率足够高。为此&#x…...

Redis 的持久化机制(RDB, AOF)对微服务的数据一致性和恢复性有何影响?如何选择?

Redis 的持久化机制&#xff08;RDB 和 AOF&#xff09;对于保证 Redis 服务重启或崩溃后数据的恢复至关重要&#xff0c;这直接影响到依赖 Redis 的微服务的数据一致性和恢复能力。 1. RDB (Redis Database Backup) 机制: 在指定的时间间隔内&#xff0c;将 Redis 在内存中的…...

手撕LLM(四):从源码出发,探索大模型的预训练(pretrain)过程

前面我们基于Minimind项目介绍了大模型的推理、LoRa加载、Moe结构&#xff0c; 大家对大模型的整体结构应该有一个比较清晰的认识&#xff1b;从该篇博客开始&#xff0c;我们通过代码剖析大模型的训练过程&#xff0c;今天的主题是大模型的预训练。 那大模型的预训练是一个什么…...

Linux系统:进程终止的概念与相关接口函数(_exit,exit,atexit)

本节目标 理解进程终止的概念理解退出状态码的概念以及使用方法掌握_exit与exit函数的用法以及区别atexit函数注册终止时执行的函数相关宏 一、进程终止 进程终止&#xff08;Process Termination&#xff09;是指操作系统结束一个进程的执行&#xff0c;回收其占用的资源&a…...

keil5 µVision 升级为V5.40.0.0:增加了对STM32CubeMX作为全局生成器的支持,主要有哪些好处?

在Keil5 μVision V5.40.0.0版本中,增加了对STM32CubeMX作为全局生成器的支持,这一更新主要带来了以下三方面的提升: 开发流程整合STM32CubeMX原本就支持生成Keil项目代码,但新版本将这一集成升级为“全局生成器”级别,意味着STM32CubeMX生成的代码能直接成为Keil项目的核…...

C 语言联合与枚举:自定义类型的核心解析

上篇博客中&#xff0c;我们通过学习了解了C语言中一种自定义类型结构体的相关知识&#xff0c;那么该语言中是否还拥有相似的自定义类型呢&#xff1f;这将是我们今天学习的目标。 1.联合体 联合体其实跟结构体类似&#xff0c;也是由一个或多个成员构成&#xff0c;这些成员…...

P1113 杂务-拓扑排序

拓扑排序 P1113 杂务 题目来源-洛谷 题意 求出完成所有任务的最短时间 思路 要求完成所有任务的最短时间&#xff0c;即每个任务尽可能最短&#xff0c;所以再求完成所有任务中的最大值&#xff08;需要最长时间的任务都完成了才叫全部完成&#xff09; 问题化解&#xf…...

Flink介绍——实时计算核心论文之Kafka论文总结

引入 大数据系统中的数据来源 在开始深入探讨Kafka之前&#xff0c;我们得先搞清楚一个问题&#xff1a;大数据系统中的数据究竟是从哪里来的呢&#xff1f;其实&#xff0c;这些数据大部分都是由各种应用系统或者业务系统产生的“日志”。 比如&#xff0c;互联网公司的广告…...

模拟投资大师思维:AI对冲基金开源项目详解

这里写目录标题 引言项目概述核心功能详解多样化的AI投资智能体灵活的运行模式透明的决策过程 安装和使用教程环境要求安装步骤基本使用方法运行对冲基金模式运行回测模式 应用场景和实际价值教育和研究价值潜在的商业应用与现有解决方案的对比局限性与发展方向 结论 引言 随着…...

DAY4:数据库对象与高级查询深度解析:从视图到多表关联实战

一、数据库对象精要指南 1.1 视图&#xff08;View&#xff09;的进阶应用 视图是存储在数据库中的虚拟表&#xff0c;本质是预编译的SQL查询语句。通过视图可以简化复杂查询、实现数据安全隔离、保持业务逻辑一致性。 创建语法示例&#xff1a; CREATE VIEW sales_summary…...