chinese_llama_aplaca训练和代码分析

训练细节 · ymcui/Chinese-LLaMA-Alpaca Wiki · GitHub中文LLaMA&Alpaca大语言模型+本地CPU/GPU训练部署 (Chinese LLaMA & Alpaca LLMs) - 训练细节 · ymcui/Chinese-LLaMA-Alpaca Wikiicon-default.png?t=N7T8https://github.com/ymcui/Chinese-LLaMA-Alpaca/wiki/%E8%AE%AD%E7%BB%83%E7%BB%86%E8%8A%82中文LLaMA&Alpaca大语言模型词表扩充+预训练+指令精调 - 知乎在 大模型词表扩充必备工具SentencePiece一文中,我们提到了在目前开源大模型中,LLaMA无疑是最闪亮的星。但是,与 ChatGLM-6B 和 Bloom 原生支持中文不同。 LLaMA 原生仅支持 Latin 或 Cyrillic 语系,对于中文支…icon-default.png?t=N7T8https://zhuanlan.zhihu.com/p/631360711GitHub - liguodongiot/llm-action: 本项目旨在分享大模型相关技术原理以及实战经验。本项目旨在分享大模型相关技术原理以及实战经验。. Contribute to liguodongiot/llm-action development by creating an account on GitHub.icon-default.png?t=N7T8https://github.com/liguodongiot/llm-action大模型词表扩充必备工具SentencePiece - 知乎背景随着ChatGPT迅速出圈,最近几个月开源的大模型也是遍地开花。目前,开源的大语言模型主要有三大类:ChatGLM衍生的大模型(wenda、 ChatSQL等)、LLaMA衍生的大模型(Alpaca、Vicuna、BELLE、Phoenix、Chimera…icon-default.png?t=N7T8https://zhuanlan.zhihu.com/p/630696264经过了一次预训练和一次指令精调,预训练使用扩充后的tokenizer,精调使用chinese_llama_aplaca的tokenizer。

1.词表扩充

为什么要扩充词表?直接在原版llama上用中文预训练不行吗?

原版LLaMA模型的词表大小是32K,其主要针对英语进行训练(具体详见LLaMA论文),对多语种支持不是特别理想(可以对比一下多语言经典模型XLM-R的词表大小为250K)。通过初步统计发现,LLaMA词表中仅包含很少的中文字符,所以在切词时会把中文切地更碎,需要多个byte token才能拼成一个完整的汉字,进而导致信息密度降低。比如,在扩展词表后的模型中,单个汉字倾向于被切成1个token,而在原版LLaMA中可能就需要2-3个才能组合成一个汉字,显著降低编解码的效率。

Chinese-LLaMA-Alpaca是在通用中文语料上训练了基于 sentencepiece 的20K中文词表并与原版LLaMA模型的32K词表进行合并,排除重复的token后,得到的最终中文LLaMA词表大小为49953。在模型精调(fine-tune)阶段 Alpaca 比 LLaMA 多一个 pad token,所以中文Alpaca的词表大小为49954。合并中文扩充词表并与原版LLaMA模型的32K词表,这里直接使用官方训练好的词表chinese_sp.model

1.1 sentencepiece训练:

spm_train --input=/workspace/data/book/hongluomeng_clean.txt --model_prefix=/workspace/model/book/hongluomeng-tokenizer --vocab_size=4000 --character_coverage=0.9995 --model_type=bpe

  • --input: 训练语料文件,可以传递以逗号分隔的文件列表。文件格式为每行一个句子。 无需运行tokenizer、normalizer或preprocessor。 默认情况下,SentencePiece 使用 Unicode NFKC 规范化输入。
  • --model_prefix:输出模型名称前缀。 训练完成后将生成 <model_name>.model 和 <model_name>.vocab 文件。
  • --vocab_size:训练后的词表大小,例如:8000、16000 或 32000
  • --character_coverage:模型覆盖的字符数量,对于字符集丰富的语言(如日语或中文)推荐默认值为 0.9995,对于其他字符集较小的语言推荐默认值为 1.0。
  • --model_type:模型类型。 可选值:unigram(默认)、bpe、char 或 word 。 使用word类型时,必须对输入句子进行pretokenized。

1.2 训练得到的model和原词表进行合并

转换格式
```
python convert_llama_weights_to_hf.py --input_dir /home/image_team/image_team_docker_home/lgd/e_commerce_llm/weights/LLaMA-7B-Base/ --model_size 7B --output_dir /home/image_team/image_team_docker_home/lgd/e_commerce_llm/weights/LLaMA-7B-Base-hf/
```

词表合并
```
python merge_tokenizers.py   --llama_tokenizer_dir /home/image_team/image_team_docker_home/lgd/e_commerce_llm/weights/LLaMA-7B-Base-hf/   --chinese_sp_model_file /home/image_team/image_team_docker_home/lgd/common/Chinese-LLaMA-Alpaca-main/scripts/merge_tokenizer/chinese_sp.model
```
merged_tokenizer_sp:为训练好的词表模型
merged_tokenizer_hf:HF格式训练好的词表模型

2.训练:

训练分三个阶段,第一和第二阶段属于预训练阶段,第三阶段属于指令精调。

2.1 第一阶段

冻结transformer参数,仅训练embedding,在尽量不干扰元模型的情况下适配新增的中文词向量。收敛速度较慢,如果不是有特别充裕的时间和计算资源,官方建议跳过该阶段,同时,官网并没有提供该阶段的代码,如果需要进行该阶段预训练,需要自行修改。

第一步:在训练之前,将除了Embedding之外的层设置为param.requires_grad = False,如下所示:

for name, param in model.named_parameters():
    if "model.embed_tokens" not in name:
        param.requires_grad = False

第二步:在训练的时候,在优化器中添加过滤器filter把requires_grad = False的参数过滤掉,这样在训练的时候,不会更新这些参数,如下所示:

optimizer = AdamW(filter(lambda p: p.requires_grad, model.parameters()))

2.2 第二阶段

使用lora,为模型添加lora权重,训练embedding的同时更新lora权重

lr=2e-4
lora_rank=8
lora_alpha=32
lora_trainable="q_proj,v_proj,k_proj,o_proj,gate_proj,down_proj,up_proj"
modules_to_save="embed_tokens,lm_head"
lora_dropout=0.05

pretrained_model=/home/image_team/image_team_docker_home/lgd/e_commerce_llm/weights/LLaMA-7B-Base-hf/
chinese_tokenizer_path=/home/image_team/image_team_docker_home/lgd/common/Chinese-LLaMA-Alpaca-main/scripts/merge_tokenizer/merged_tokenizer_hf/
dataset_dir=/home/image_team/image_team_docker_home/lgd/common/Chinese-LLaMA-Alpaca-main/data/
data_cache=/home/image_team/image_team_docker_home/lgd/common/Chinese-LLaMA-Alpaca-main/data_cache/
per_device_train_batch_size=1
per_device_eval_batch_size=1
gradient_accumulation_steps=1
training_step=100
output_dir=/home/image_team/image_team_docker_home/lgd/common/Chinese-LLaMA-Alpaca-main/output_dir/

deepspeed_config_file=ds_zero2_no_offload.json

torchrun --nnodes 1 --nproc_per_node 3 run_clm_pt_with_peft.py \
    --deepspeed ${deepspeed_config_file} \
    --model_name_or_path ${pretrained_model} \
    --tokenizer_name_or_path ${chinese_tokenizer_path} \
    --dataset_dir ${dataset_dir} \
    --data_cache_dir ${data_cache} \
    --validation_split_percentage 0.001 \
    --per_device_train_batch_size ${per_device_train_batch_size} \
    --per_device_eval_batch_size ${per_device_eval_batch_size} \
    --do_train \
    --seed $RANDOM \
    --fp16 \
    --num_train_epochs 1 \
    --lr_scheduler_type cosine \
    --learning_rate ${lr} \
    --warmup_ratio 0.05 \
    --weight_decay 0.01 \
    --logging_strategy steps \
    --logging_steps 10 \
    --save_strategy steps \
    --save_total_limit 3 \
    --save_steps 200 \
    --gradient_accumulation_steps ${gradient_accumulation_steps} \
    --preprocessing_num_workers 8 \
    --block_size 512 \
    --output_dir ${output_dir} \
    --overwrite_output_dir \
    --ddp_timeout 30000 \
    --logging_first_step True \
    --lora_rank ${lora_rank} \
    --lora_alpha ${lora_alpha} \
    --trainable ${lora_trainable} \
    --modules_to_save ${modules_to_save} \
    --lora_dropout ${lora_dropout} \
    --torch_dtype float16 \
    --gradient_checkpointing \
    --ddp_find_unused_parameters False

2.3 将lora模型合并到基础模型中

python merge_llama_with_chinese_lora.py     --base_model /home/image_team/image_team_docker_home/lgd/e_commerce_llm/weights/LLaMA-7B-Base-hf/      --lora_model /home/image_team/image_team_docker_home/lgd/common/Chinese-LLaMA-Alpaca-main/output_dir/pt_lora_model/     --output_type huggingface     --output_dir /home/image_team/image_team_docker_home/lgd/common/Chinese-LLaMA-Alpaca-main/output_dir/

 2.4 第三阶段:指令精调

训练数据是alpaca_data_zh_51k.json,词表扩充阶段得到的词表是49953,但是sft阶段,alpaca的词表比llama多一个pad token,所以是49954,注意这个chinese_llama_alpaca的词表直接从作者的项目中拉取。

lr=1e-4
lora_rank=8
lora_alpha=32
lora_trainable="q_proj,v_proj,k_proj,o_proj,gate_proj,down_proj,up_proj"
modules_to_save="embed_tokens,lm_head"
lora_dropout=0.05

pretrained_model=/home/image_team/image_team_docker_home/lgd/common/Chinese-LLaMA-Alpaca-main/output_dir/
chinese_tokenizer_path=/home/image_team/image_team_docker_home/lgd/common/Chinese-LLaMA-Alpaca-main/chinese_alpaca_tokenizer/
dataset_dir=/home/image_team/image_team_docker_home/lgd/common/Chinese-LLaMA-Alpaca-main/data/
per_device_train_batch_size=1
per_device_eval_batch_size=1
gradient_accumulation_steps=8
output_dir=/home/image_team/image_team_docker_home/lgd/common/Chinese-LLaMA-Alpaca-main/output_dir_sft/
#peft_model=/home/image_team/image_team_docker_home/lgd/common/Chinese-LLaMA-Alpaca-main/output_dir_sft/
validation_file=/home/image_team/image_team_docker_home/lgd/common/Chinese-LLaMA-Alpaca-main/data/alpaca_valid.json

deepspeed_config_file=ds_zero2_no_offload.json

torchrun --nnodes 1 --nproc_per_node 3 run_clm_sft_with_peft.py \
    --deepspeed ${deepspeed_config_file} \
    --model_name_or_path ${pretrained_model} \
    --tokenizer_name_or_path ${chinese_tokenizer_path} \
    --dataset_dir ${dataset_dir} \
    --validation_split_percentage 0.001 \
    --per_device_train_batch_size ${per_device_train_batch_size} \
    --per_device_eval_batch_size ${per_device_eval_batch_size} \
    --do_train \
    --do_eval \
    --seed $RANDOM \
    --fp16 \
    --num_train_epochs 1 \
    --lr_scheduler_type cosine \
    --learning_rate ${lr} \
    --warmup_ratio 0.03 \
    --weight_decay 0 \
    --logging_strategy steps \
    --logging_steps 10 \
    --save_strategy steps \
    --save_total_limit 3 \
    --evaluation_strategy steps \
    --eval_steps 100 \
    --save_steps 2000 \
    --gradient_accumulation_steps ${gradient_accumulation_steps} \
    --preprocessing_num_workers 8 \
    --max_seq_length 512 \
    --output_dir ${output_dir} \
    --overwrite_output_dir \
    --ddp_timeout 30000 \
    --logging_first_step True \
    --lora_rank ${lora_rank} \
    --lora_alpha ${lora_alpha} \
    --trainable ${lora_trainable} \
    --modules_to_save ${modules_to_save} \
    --lora_dropout ${lora_dropout} \
    --torch_dtype float16 \
    --validation_file ${validation_file} \
    --gradient_checkpointing \
    --ddp_find_unused_parameters False  
#    --peft_path ${peft_model} 

2.5 将预训练权重lora和精调lora合并到基础模型上

python merge_llama_with_chinese_lora.py     --base_model /home/image_team/image_team_docker_home/lgd/e_commerce_llm/weights/LLaMA-7B-Base-hf/   --lora_model /home/image_team/image_team_docker_home/lgd/common/Chinese-LLaMA-Alpaca-main/output_dir/pt_lora_model/,"/home/image_team/image_team_docker_home/lgd/common/Chinese-LLaMA-Alpaca-main/output_dir_sft/sft_lora_model/"     --output_type huggingface     --output_dir /home/image_team/image_team_docker_home/lgd/common/Chinese-LLaMA-Alpaca-main/output_dir_all/

2.6 前向推理

python inference_hf.py      --base_model /home/image_team/image_team_docker_home/lgd/common/Chinese-LLaMA-Alpaca-main/output_dir_all/     --with_prompt    --interactive

transformer==4.31.0 

3.代码分析

3.1 预训练代码

parser = HfArgumentParser((ModelArgument,DataTrainArguments,MyTrainingArgument))
model_args, data_args, training_args = parser.parse_args_into_dataclasses()

set_seed(training_args.seed)
config = AutoConfig.from_pretrained(model_args.model_name_or_path,...)
tokenizer = LlamaTokenizer.from_pretrained(model_args.tokenizer_name_or_path,...)

block_size = tokenizer.model_max_length

with training_args.main_process_first():
    files = [file.name for file in path.glob("*.txt")]
    for idx,file in enumerate(files):
        raw_dataset = load_dataset("text",data_file,cache_dir,keep_in_memory=False)
        tokenized_dataset = raw_dataset.map(tokenize_function,...)
        grouped_dataset = tokenized_dataset.map(group_texts,...)
- tokenize_function->output = tokenizer(examples["text"])
        processed_dataset.save_to_disk(cache_path)
    lm_datasets = concatenate_datasets([lm_datasets,processed_dataset['train']])
    lm_datasets = lm_datasets.train_test_split(data_args.validation_split_percentage) 
   
train_dataset = lm_datasets['train']
model = LlamaForCausalLM.from_pretrained(model_args.model_name_or_path,..)
model_vocab_size = model.get_output_embeddings().weight.size(0)
model.resize_token_embeddings(len(tokenizer))

target_modules = training_args.trainable.split(',')
modules_to_save = training_args.module_to_save
lora_rank = training_args.lora_rank
lora_dropout = training_args.lora_dropout
lora_alpha = training_args.lora_alpha
peft_config = LoraConfig(TasskType.CAUSAL_LM,target_modules,lora_rank,lora_alpha,lora_dropout,lora_dropout,modules_to_save)
model = get_peft_model(model,peft_config)
old_state_dict = model.state_dict()
model.state_dict = (
        lambda self, *_, **__: get_peft_model_state_dict(self, old_state_dict())
).__get__(model, type(model))

trainer = Trainer(
        model,
        training_args,
        train_dataset,
        eval_dataset,
        tokenizer,
        fault_tolerance_data_collator,
        compute_metrics,preprocess_logits_for_metrics)
trainer.add_callback(SavePeftModelCallback)

checkpoint = training_args.resume_from_checkpoint
train_result = trainer.train(checkpoint)
metrics = train_result.metrics
trainer.log_metrics("train",metrics)
trainer.save_metrics("train",metrics)
trainer.save_state()

3.2 指令精调代码

parser = HfArgumentParser((ModelArguments, DataTrainingArguments, MyTrainingArguments))
model_args, data_args, training_args = parser.parse_args_into_dataclasses()

set_seed(training_args.seed)
config = AutoConfig.from_pretrained(model_args.model_name_or_path,...)
tokenizer = LlamaTokenizer.from_pretrained(model_args.tokenizer_name_or_path,...)

tokenizer.add_special_tokens(dict(pad_token="[PAD]"))
data_collator = DataCollatorForSupervisedDataset(tokenizer)
- input_ids,labels = tuple([instance[key] for instance in instances] for key in ("input_ids","labels"))
- input_ids = torch.nn.utils.rnn.pad_sequence(input_ids,batch_first=True,padding_value=self.tokenizer.pad_token_id)
- labels = torch.nn.utils.rnn.pad_sequence(labels,batch_first=True,padding_values=-100)

with training_args.main_process_first():
    files = [os.path.join(path,filename) for file in path.glob("*.json")]
    train_dataset = build_instruction_dataset(files,tokenizer,data,max_seq_length,...)
- for file in data_path:
      raw_dataset = load_dataset("json",data_file=file,..)
      tokenized_dataset = raw_dataset.map(tokenization,...)
-- for instruction,input,output in zip(examples['instruction'],examples['input'],examples['output']):
       if input is not None and input != "":
           instruction = instruction+"\n"+input
       source = prompt.format_map({'instruction':instruction})
       target = f"{output}{tokenizer.eos_token}"
    tokenized_sources = tokenizer(sources,return_attention_mask=False)
    tokenized_targets = tokenizer(targets,return_attention_mask=False,add_special_tokens=False)
    for s,t in zip(tokenized_sources['input_ids'],tokenized_targets['input_ids']):
        input_ids = torch.LongTensor(s+t)[:max_seq_length]
        labels = torch.LongTensor([IGNORE_INDEX]*len(s) + t)[:max_seq_length]
    return results = {'input_ids':all_input_ids,'labels':all_labels}

model = LlamaForCausalLM.from_pretrained(model_args.model_name_or_path,config,...)    
embedding_size = model.get_input_embeddings().weight.shape[0]
model.resize_token_embeddings(len(tokenizers))

target_modules = training_args.trainable.split(',')
modules_to_save = training_args.modules_to_save
if modules_to_save is not None:
   modules_to_save = modules_to_save.split(',')
lora_rank = training_args.lora_rank
lora_dropout = training_args.lora_dropout
lora_alpha = training_args.lora_alpha
peft_config = LoraConfig(
            task_type=TaskType.CAUSAL_LM,
            target_modules=target_modules,
            inference_mode=False,
            r=lora_rank, lora_alpha=lora_alpha,
            lora_dropout=lora_dropout,
            modules_to_save=modules_to_save)
model = get_peft_model(model, peft_config)

old_state_dict = model.state_dict
model.state_dict = (
        lambda self, *_, **__: get_peft_model_state_dict(self, old_state_dict())
    ).__get__(model, type(model))
trainer = Trainer(
        model=model,
        args=training_args,
        train_dataset=train_dataset,
        eval_dataset=eval_dataset,
        tokenizer=tokenizer,
        data_collator=data_collator,
    )
trainer.add_callback(SavePeftModelCallback) 

train_result = trainer.train(resume_from_checkpoint=checkpoint)
metrics = train_result.metrics
trainer.log_metrics("train", metrics)
trainer.save_metrics("train", metrics)
trainer.save_state()

3.3 推理代码

apply_attention_patch(use_memory_efficient_attention=True)
apply_ntk_scaling_path(args.alpha)

generation_config = dict(
temperature=0.2,
topk=40,
top_p=0.9,
do_sample=True,
num_beams=1,
repetition_penalty=1.1,
max_new_tokens=400)

tokenizer = LlamaTokenizer.from_pretrained(args.tokenizer_path)
base_model = LlamaForCausalLM.from_pretrained(args.base_model,load_in_8bit,torch.float16,low_cpu_mem_usage=True)
model_vocab_size = base_model.get_input_embeddings().weight.size(0)
base_model.resize_token_embeddings(tokenzier_vocab_size)
model = base_model
model.eval()

with torch.no_grad():
    while True:
        raw_input_text = input("Input:")
        input_text = generate_prompt(instruction=raw_input_text)
        inputs = tokenizer(input_text,return_tensors="pt")
        generation_output = model.generate(
                    input_ids=inputs["input_ids"].to(device),
                    attention_mask=inputs['attention_mask'].to(device),
                    eos_token_id=tokenizer.eos_token_id,
                    pad_token_id=tokenizer.pad_token_id,
                    **generation_config)
        s = generate_output[0]
        output = tokenizer.decode(s,skip_special_tokens=True)
        response = output.split("### Response:")[1].strip()

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【实战Flask API项目指南】之一 概述

实战Flask API项目指南之 概述 本系列文章将带你深入探索实战Flask API项目指南&#xff0c;通过跟随小菜的学习之旅&#xff0c;你将逐步掌握Flask在实际项目中的应用。让我们一起踏上这个精彩的学习之旅吧&#xff01; 前言 小菜是一个Python编程爱好者&#xff0c;他目前…

华为OD机试 - 高效的任务规划 - 逻辑分析(Java 2023 B卷 200分)

目录 专栏导读一、题目描述二、输入描述三、输出描述四、解题思路五、Java算法源码六、效果展示1、输入2、输出3、说明 华为OD机试 2023B卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;A卷B卷&#…

挑战100天 AI In LeetCode Day02(1)

挑战100天 AI In LeetCode Day02&#xff08;1&#xff09; 一、LeetCode介绍二、LeetCode 热题 HOT 100-32.1 题目2.2 题解 三、面试经典 150 题-33.1 题目3.2 题解 一、LeetCode介绍 LeetCode是一个在线编程网站&#xff0c;提供各种算法和数据结构的题目&#xff0c;面向程序…

Linux中的高级IO

文章目录 1.IO1.1基本介绍1.2基础io的低效性1.3如何提高IO效率1.4五种IO模型1.5非阻塞模式的设置 2.IO多路转接之Select2.1函数的基本了解2.2fd_set理解2.3完整例子代码&#xff08;会在代码中进行讲解&#xff09;2.4优缺点 3.多路转接之poll3.1poll函数的介绍3.2poll服务器3.…

4.网络之TCP

TCP协议(传输层) 文章目录 TCP协议(传输层)1. TCP报文格式2. TCP相关机制2.1 确认应答机制2.2 超时重传机制2.3 连接管理机制&#xff08;重点&#xff09;2.3.1 三次握手2.3.2 四次挥手 2.4 滑动窗口机制2.5 流量控制机制2.6 拥塞控制机制2.7 延迟应答机制2.8 捎带应答机制 3.…

Linux工具git版本控制器介绍

git介绍 ​ git就是一个版本控制器&#xff0c;是由Linux之父写的开源软件&#xff0c;功能就是保存每个版本的内容。将被管理的内容&#xff08;文本&#xff09;&#xff0c;按照变化来进行管理的软件&#xff0c;你需要哪一个变化的版本都可以找到。 git是一个软件&#x…

ATE新能源汽车充电桩自动负载测试系统

随着新能源汽车的普及&#xff0c;充电桩的需求也在不断增加&#xff0c;为了确保充电桩的性能和安全性&#xff0c;对其进行负载测试是非常重要的。ATE新能源汽车充电桩自动负载测试系统是一种专门用于检测充电桩性能的设备&#xff0c;它可以模拟各种实际使用场景&#xff0c…

打造高效运营底座,极智嘉一体化软件系统彰显科技威能

在仓储成本和物流需求日益增加的今天&#xff0c;创新且高效的物流机器人解决方案能够显著提升物流运营效率&#xff0c;降低物流成本&#xff0c;实现智能化、精益化、一体化的物流管理。全球仓储机器人引领者极智嘉(Geek)以「一套系统&#xff0c;天生全能」为准则&#xff0…

数据集:机器人理解世界的关键

原创 | 文 BFT机器人 传统的机器人和工业自动化解决方案已经颇有成效。在工厂中入驻自动化机器人可以快速地帮助工人们完成长时间重复劳动的任务。随着用工成本上涨、技能人才短缺、工作环境恶劣等问题的凸显&#xff0c;社会更迫切地需要采用自动化设备代替人工来完成该类操作…

又要报销了,还在手动下载整理发票吗?

大多数公司都是每个月定期提交报销&#xff0c;一般报销用的发票都是电子发票发到邮箱&#xff0c;每次要报销时都需要登录邮箱&#xff0c;点开邮件&#xff0c;一个个下载整理&#xff0c;工作量不大&#xff0c;但是发票多了也着实很烦。这个月终于下决心把这个过程自动化一…

《005.SpringBoot+vue之学生选课管理系统01》

《005.SpringBootvue之学生选课管理系统01》 项目简介 [1]本系统涉及到的技术主要如下&#xff1a; 推荐环境配置&#xff1a;DEA jdk1.8 Maven MySQL 前后端分离; 后台&#xff1a;SpringBootMybatis; 前台&#xff1a;vueElementUI; [2]功能模块展示&#xff1a; 管理端 1…

BO(Business Object)是一种用于表示业务对象的设计模式

1、Service层 BO 1.1、FruitService接口 package com.csdn.fruit.service; import com.csdn.fruit.dto.PageInfo; import com.csdn.fruit.dto.PageQueryParam; import com.csdn.fruit.pojo.Fruit; public interface FruitService {PageInfo<Fruit> getFruitPageInfo(Page…

C++性能优化笔记-6-C++元素的效率差异-7-类型转换

C元素的效率差异 类型转换signed与unsigned转换整数大小转换浮点精度转换整数到浮点转换浮点到整数转换指针类型转换重新解释对象的类型const_caststatic_castreinterpret_castdynamic_cast转换类对象 类型转换 在C语法中&#xff0c;有几种方式进行类型转换&#xff1a; // …

unity【动画】脚本_角色动画控制器 c#

首先创建一个代码文件夹Scripts 从人物角色Player的基类开始 创建IPlayer类 首先我们考虑到如果不挂载MonoBehaviour需要将角色设置成预制体实例化到场景上十分麻烦&#xff0c; 所以我们采用继承MonoBehaviour类的角色基类方法写代码 也就是说这个脚本直接绑定在角色物体…

VBA之正则表达式(44)-- 拆分商品和规格

实例需求&#xff1a;商品组清单保存在A列中&#xff0c;现需要将其拆分为商品名称&#xff0c;保存在从B列开始的后续单元格中&#xff0c;部分商品包含规格&#xff0c;并且多种规格属性使用了逗号分隔&#xff0c;因此无法直接使用Excel分列功能完成数据拆分。 示例代码如下…

“第六十一天”

这三个也算一类的&#xff0c;减和加的处理差不多&#xff0c;不过这个题多了限制是被减数大于减数&#xff0c;要是想再完整一点&#xff0c;可以把小于的情况也考虑进去&#xff0c;不过这个我是如果被减数小于减数的话&#xff0c;我就用减数加被减数&#xff0c;然后最后打…

【MySQL数据库】 四

本文主要介绍了mysql数据库的几种常见的约束. 一.数据库约束 我们希望存储的数据是靠谱的,mysql提供一些机制来辅助我们自动的依赖程序对数据进行检查 . 这类查数据的机制,就是约束 一旦约束好了,后续在进行增 删 改的时候,mysql就会自动的对修改的数据做出检查,如果不符合…

wscat

wscat 是一个用于 WebSocket 通信测试的命令行工具 安装wscat flynnsinflynnsin:~$ sudo npm install -g wscat loadDep:ws → afterAdd ▄ ╢████████████████████████████████████░░░░░░░░░░░░░░░░░░░░░░░…

爱上C语言:函数递归,青蛙跳台阶图文详解

&#x1f680; 作者&#xff1a;阿辉不一般 &#x1f680; 你说呢&#xff1a;生活本来沉闷&#xff0c;但跑起来就有风 &#x1f680; 专栏&#xff1a;爱上C语言 &#x1f680;作图工具&#xff1a;draw.io(免费开源的作图网站) 如果觉得文章对你有帮助的话&#xff0c;还请…

大数据毕业设计选题推荐-旅游景点游客数据分析-Hadoop-Spark-Hive

✨作者主页&#xff1a;IT毕设梦工厂✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Py…