GPT实战系列-P-Tuning本地化训练ChatGLM2等LLM模型,到底做了什么?(二)

GPT实战系列-如何使用P-Tuning本地化训练ChatGLM2等LLM模型?(二)

文章目录

  • GPT实战系列-
    • 1.训练参数配置传递
    • 2.训练前准备
    • 3.训练参数配置
    • 4.训练对象,seq2seq训练
    • 5.执行训练
    • 6.训练模型评估
    • 依赖
    • 数据集的预处理

P-Tuning v2 将 ChatGLM2-6B 模型需要微调的参数量,减少到原来的 0.1%,再通过模型量化、Gradient Checkpoint 等方法,最低只需要 7GB 显存即可运行。

本文试图分析程序结构和代码,解释序列转换生成模型的微调训练。为了篇幅不要过长,分两篇文章解读,本文解读训练代码。框架概述请看前篇文章:GPT实战系列-P-Tuning本地化训练ChatGLM2等LLM模型,到底做了什么?(一)

对相关的内容感兴趣,也可以到GPT专栏里的文章看看。如果没有你感兴趣的,请留言,后续一起讨论。
GPT专栏:https://blog.csdn.net/alex_starsky/category_12467518.html

下面解读ptuning目录下的main.py代码。

1.训练参数配置传递

训练环节中,通过命令行配置参数(sh脚本),然后通过HfArgumentParser方法,把配置参数指定到模型,数据和训练的参数类中。通过参数解析器parser,进一步分类为模型参数,数据参数和训练超参数。

# 新版本的transformers中的ner没有采用传统的parser模块,利用HfArgumentParser方法,将参数类转化为argparse参数,以便于在命令行中指定他们。
# ModelArguments类为model/config/tokenizer涉及的参数。ModelArguments类 中包含的是关于模型的属性,如model_name,config_name,tokenizer_name等,类在run.py文件中定义;
# DataTrainingArguments类 为训练、测试数据集操作涉及到的参数。DataTrainingArguments类 中包含的是关于微调数据的属性,如task_name,data_dir等,类在transformers/data/datasets/glue.py文件中定义;
# TrainingArguments中包含的是关于微调过程的参数,如batch_size,learning_rate等参数,类在transformers/training_args.py中定义。parser = HfArgumentParser((ModelArguments, DataTrainingArguments, Seq2SeqTrainingArguments))
# 通过参数解析器parser,进一步分类为模型参数,数据参数和训练超参数。    
# 训练时输入python run_ner.py *******.json,即从.json中读取参数。
# 当sys.argv参数为2时,此时sys.argv[0]为自己本身,即"run_ner.py",sys.argv[1]为json文件
if len(sys.argv) == 2 and sys.argv[1].endswith(".json"):model_args, data_args, training_args = parser.parse_json_file(json_file=os.path.abspath(sys.argv[1]))
else:model_args, data_args, training_args = parser.parse_args_into_dataclasses()

如果参数过多,或者需要保存参数,采用json文件格式,比如:

{"do_train": true,"train_file": "dataset/AdvertiseGen/train.json","validation_file": "dataset/AdvertiseGen/dev.json","preprocessing_num_workers": 10,"prompt_column": "content","response_column": "summary","overwrite_cache": true,"model_name_or_path": "/Users/andy/Desktop/LLM/model/chatglm2-6b","output_dir": "output/adgen-chatglm2-6b-lora_version","overwrite_output_dir": true,"max_source_length": 64,"max_target_length": 128,"per_device_train_batch_size": 1,"per_device_eval_batch_size": 1,"gradient_accumulation_steps": 16,"predict_with_generate": true,"max_steps": 3000,"logging_steps": 10,"save_steps": 100,"learning_rate": 2e-5,"lora_r": 32,"model_parallel_mode": true,"output_dir": "output"
}

训练过程的日志排版,打印信息等相关设置

#设置日志相关,排版格式,日期格式
# Setup logging
logging.basicConfig(format="%(asctime)s - %(levelname)s - %(name)s - %(message)s",datefmt="%m/%d/%Y %H:%M:%S",handlers=[logging.StreamHandler(sys.stdout)],
)
#设置打印信息
if training_args.should_log:# The default of training_args.log_level is passive, so we set log level at info here to have that default.transformers.utils.logging.set_verbosity_info()#设置日志信息等级,transformer日志配置
log_level = training_args.get_process_log_level()
logger.setLevel(log_level)
# datasets.utils.logging.set_verbosity(log_level)
transformers.utils.logging.set_verbosity(log_level)
transformers.utils.logging.enable_default_handler()
transformers.utils.logging.enable_explicit_format()

2.训练前准备

训练前的准备工作,包括预处理,训练数据集、验证数据集、测试数据集等参数配置

训练数据准备

# 加载数据集,训练文件,验证文件,测试文件,文件名,文件类型(扩展名)# Load datasetdata_files = {}if data_args.train_file is not None:data_files["train"] = data_args.train_fileextension = data_args.train_file.split(".")[-1]if data_args.validation_file is not None:data_files["validation"] = data_args.validation_fileextension = data_args.validation_file.split(".")[-1]if data_args.test_file is not None:data_files["test"] = data_args.test_fileextension = data_args.test_file.split(".")[-1]# 加载训练、验证、测试数据文件,cache目录raw_datasets = load_dataset(extension,data_files=data_files,cache_dir=model_args.cache_dir,use_auth_token=True if model_args.use_auth_token else None,)

训练模型的配置

预训练模型加载,序列长度,序列前缀处理

# 加载模型配置(模型架构),预训练模型
# Load pretrained model and tokenizer
config = AutoConfig.from_pretrained(model_args.model_name_or_path, trust_remote_code=True)
config.pre_seq_len = model_args.pre_seq_len
config.prefix_projection = model_args.prefix_projection

加载分词器,对自然语言序列进行分解,分词处理

# 分词器
tokenizer = AutoTokenizer.from_pretrained(model_args.model_name_or_path, trust_remote_code=True)

预训练模型的加载,有两种方式,一种是把过程加载方式,checkpoint,另一种是整合为一个模型bin格式,然后直接加载。

# 含有训练过程信息的checkpoint模型的加载模式,如ptuning训练中间结果,需要从pytorch_model.bin加载字典,
# 或者直接加载模型
if model_args.ptuning_checkpoint is not None:# Evaluation# Loading extra state dict of prefix encodermodel = AutoModel.from_pretrained(model_args.model_name_or_path, config=config, trust_remote_code=True)prefix_state_dict = torch.load(os.path.join(model_args.ptuning_checkpoint, "pytorch_model.bin"))new_prefix_state_dict = {}for k, v in prefix_state_dict.items():if k.startswith("transformer.prefix_encoder."):new_prefix_state_dict[k[len("transformer.prefix_encoder."):]] = vmodel.transformer.prefix_encoder.load_state_dict(new_prefix_state_dict)
else:model = AutoModel.from_pretrained(model_args.model_name_or_path, config=config, trust_remote_code=True)

训练量化精度配置
加载模型后,考虑到模型大小,占用显存大小,以及训练速度,需要配置模型数据精度,一般分为float32为浮点,f16半浮点精度,bf16半浮点精度,及int8,int4等整型8,4位精度。

# 量化处理,f16半浮点精度,即将pytorch默认的32位浮点型都改成16位浮点型。
if model_args.quantization_bit is not None:print(f"Quantized to {model_args.quantization_bit} bit")model = model.quantize(model_args.quantization_bit)
if model_args.pre_seq_len is not None:# P-tuning v2model = model.half()model.transformer.prefix_encoder.float() #前缀编码器
else:# Finetunemodel = model.float()

数据预处理
数据集预处理,包括训练数据集,验证数据集,测试数据集。

prefix = data_args.source_prefix if data_args.source_prefix is not None else ""# 数据集预处理,分词处理# Preprocessing the datasets.# We need to tokenize inputs and targets.if training_args.do_train:column_names = raw_datasets["train"].column_nameselif training_args.do_eval:column_names = raw_datasets["validation"].column_nameselif training_args.do_predict:column_names = raw_datasets["test"].column_nameselse:logger.info("There is nothing to do. Please pass `do_train`, `do_eval` and/or `do_predict`.")return# 输入数据(prompt),标注目标数据(response),上下文历史会话(history)# Get the column names for input/target.prompt_column = data_args.prompt_columnresponse_column = data_args.response_columnhistory_column = data_args.history_column# 最大模板长度# Temporarily set max_target_length for training.max_target_length = data_args.max_target_length

3.训练参数配置

训练数据集参数配置,最大训练样本数,数据预处理函数,GPU显卡数,批处理,cache处理等配置

# 训练前配置和数据集处理,训练,训练数据,最大训练样本数,if training_args.do_train:if "train" not in raw_datasets:raise ValueError("--do_train requires a train dataset")train_dataset = raw_datasets["train"]if data_args.max_train_samples is not None:max_train_samples = min(len(train_dataset), data_args.max_train_samples)train_dataset = train_dataset.select(range(max_train_samples))with training_args.main_process_first(desc="train dataset map pre-processing"):train_dataset = train_dataset.map(preprocess_function_train,batched=True,num_proc=data_args.preprocessing_num_workers,remove_columns=column_names,load_from_cache_file=not data_args.overwrite_cache,desc="Running tokenizer on train dataset",)print_dataset_example(train_dataset[0])

同样方式,配置验证数据集,测试数据集参数。

    # 训练前验证评价的配置和数据集处理,验证评价if training_args.do_eval:max_target_length = data_args.val_max_target_lengthif "validation" not in raw_datasets:raise ValueError("--do_eval requires a validation dataset")eval_dataset = raw_datasets["validation"]#最大验证样本数if data_args.max_eval_samples is not None:max_eval_samples = min(len(eval_dataset), data_args.max_eval_samples)eval_dataset = eval_dataset.select(range(max_eval_samples))#with training_args.main_process_first(desc="validation dataset map pre-processing"):eval_dataset = eval_dataset.map(preprocess_function_eval,batched=True,num_proc=data_args.preprocessing_num_workers,remove_columns=column_names,load_from_cache_file=not data_args.overwrite_cache,desc="Running tokenizer on validation dataset",)print_dataset_example(eval_dataset[0])# 训练前预测的配置和数据集处理,预测if training_args.do_predict:max_target_length = data_args.val_max_target_lengthif "test" not in raw_datasets:raise ValueError("--do_predict requires a test dataset")predict_dataset = raw_datasets["test"]#最大预测样本if data_args.max_predict_samples is not None:max_predict_samples = min(len(predict_dataset), data_args.max_predict_samples)predict_dataset = predict_dataset.select(range(max_predict_samples))#数据集重映射with training_args.main_process_first(desc="prediction dataset map pre-processing"):predict_dataset = predict_dataset.map(preprocess_function_eval,batched=True,num_proc=data_args.preprocessing_num_workers,remove_columns=column_names,load_from_cache_file=not data_args.overwrite_cache,desc="Running tokenizer on prediction dataset",)print_dataset_example(predict_dataset[0])

数据分词,类型转换,pad等数据预处理操作

#训练准备,模型,数据加载# Data collatorlabel_pad_token_id = -100 if data_args.ignore_pad_token_for_loss else tokenizer.pad_token_iddata_collator = DataCollatorForSeq2Seq(tokenizer,model=model,label_pad_token_id=label_pad_token_id,pad_to_multiple_of=None,padding=False)

4.训练对象,seq2seq训练

序列训练参数配置,生成的length,beams配置,

# 序列训练参数配置,如有配置则重置解码参数# Override the decoding parameters of Seq2SeqTrainertraining_args.generation_max_length = (training_args.generation_max_lengthif training_args.generation_max_length is not Noneelse data_args.val_max_target_length)training_args.generation_num_beams = (data_args.num_beams if data_args.num_beams is not None else training_args.generation_num_beams)

训练器参数配置,预训练模型,训练超参数,相关数据集。分词器,训练度量器等过程参数配置。

#初始化训练参数,配置模型,训练参数,训练数据,分词器,数据加载工具,过程度量# Initialize our Trainertrainer = Seq2SeqTrainer(model=model,args=training_args,train_dataset=train_dataset if training_args.do_train else None,eval_dataset=eval_dataset if training_args.do_eval else None,tokenizer=tokenizer,data_collator=data_collator,compute_metrics=compute_metrics if training_args.predict_with_generate else None,save_changed=model_args.pre_seq_len is not None)

5.执行训练

执行训练过程,模型保存方式,过程度量及状态保存。

# 训练执行过程# Trainingif training_args.do_train:checkpoint = Noneif training_args.resume_from_checkpoint is not None:checkpoint = training_args.resume_from_checkpoint# elif last_checkpoint is not None:#     checkpoint = last_checkpointmodel.gradient_checkpointing_enable()model.enable_input_require_grads()train_result = trainer.train(resume_from_checkpoint=checkpoint)# trainer.save_model()  # Saves the tokenizer too for easy uploadmetrics = train_result.metricsmax_train_samples = (data_args.max_train_samples if data_args.max_train_samples is not None else len(train_dataset))metrics["train_samples"] = min(max_train_samples, len(train_dataset))trainer.log_metrics("train", metrics)trainer.save_metrics("train", metrics)trainer.save_state()

6.训练模型评估

训练后,数据集评估模型效果,预测处理。

#训练结束后评估# Evaluationresults = {}max_seq_length = data_args.max_source_length + data_args.max_target_length + 1# 训练评估if training_args.do_eval:logger.info("*** Evaluate ***")metrics = trainer.evaluate(metric_key_prefix="eval", do_sample=True, top_p=0.7, max_length=max_seq_length, temperature=0.95)max_eval_samples = data_args.max_eval_samples if data_args.max_eval_samples is not None else len(eval_dataset)metrics["eval_samples"] = min(max_eval_samples, len(eval_dataset))trainer.log_metrics("eval", metrics)trainer.save_metrics("eval", metrics)# 训练预测if training_args.do_predict:logger.info("*** Predict ***")predict_results = trainer.predict(predict_dataset, metric_key_prefix="predict", max_length=max_seq_length, do_sample=True, top_p=0.7, temperature=0.95)metrics = predict_results.metricsmax_predict_samples = (data_args.max_predict_samples if data_args.max_predict_samples is not None else len(predict_dataset))metrics["predict_samples"] = min(max_predict_samples, len(predict_dataset))trainer.log_metrics("predict", metrics)trainer.save_metrics("predict", metrics)if trainer.is_world_process_zero():if training_args.predict_with_generate:predictions = tokenizer.batch_decode(predict_results.predictions, skip_special_tokens=True, clean_up_tokenization_spaces=True)predictions = [pred.strip() for pred in predictions]labels = tokenizer.batch_decode(predict_results.label_ids, skip_special_tokens=True, clean_up_tokenization_spaces=True)labels = [label.strip() for label in labels]output_prediction_file = os.path.join(training_args.output_dir, "generated_predictions.txt")with open(output_prediction_file, "w", encoding="utf-8") as writer:for p, l in zip(predictions, labels):res = json.dumps({"labels": l, "predict": p}, ensure_ascii=False)writer.write(f"{res}\n")

依赖

中文分词器,中文评价指标,数据集管理

pip install rouge_chinese nltk jieba datasets

依赖模块解读

transformers提供数千个预先训练好的模型来执行不同模式的任务,如文本、视觉和音频。

transformer提供api,可以快速下载,并在给定文本上使用这些预训练的模型,在您自己的数据集上对它们进行微调,然后在Huggingface的模型中心上与社区共享。同时,每个定义架构的python模块都是完全独立的,可以进行修改以进行快速研究实验。

  • AutoConfig模块,模型的配置类是指定模型的构建方式。配置指定模型的属性,如隐藏层或注意力头的数量。当从自定义配置类初始化模型时,将从头开始。模型属性是随机初始化的,在使用模型得到有意义的结果之前,需要对模型进行训练。导入AutoConfig,然后加载要修改的预训练模型。在AutoConfig.from_pretrained()中,可以指定要更改的属性,例如注意力头的数量。
  • AutoModel加载一个预训练模型,Transformers提供简单统一的方法来加载。
  • AutoTokenizer加载的一个自动分词器。
  • DataCollatorForSeq2Seq 是在进行序列生成任务时(QA、文本概括等)使用的数据收集器,需要模型的输出是一个序列。该数据收集器不仅会动态的填充数据的数据,而且也会填充数据对应的标签。
  • HfArgumentParser可以将类对象中的实例属性转换成转换为解析参数。必须注意的是,这里的类对象必须是通过@dataclass()创建的类对象。并且通过HfArgumentParser创建的解析参数,都是可选参数。
# Transformers 工具已经帮我们封装了用于训练文本生成模型的 Seq2SeqTrainer 类,无需我们自己再去定义损失函数与优化方法了。
import transformers
from transformers import (AutoConfig,AutoModel,AutoTokenizer,DataCollatorForSeq2Seq,HfArgumentParser,Seq2SeqTrainingArguments,set_seed,
)

Trainer 所有模型都是标准的torch.nn.Module,因此可以在任何典型的训练循环中使用它们。虽然您可以编写自己的训练迭代器,但Transformers为PyTorch提供了Trainer类,其中包含基本的训练循环,并添加了额外的功能,如分布式训练、混合精度等。

  • Seq2SeqTrainingArguments 设置训练参数。
  • Seq2SeqTrainer 序列类的训练迭代器
# Seq2SeqTrainingArguments 设置训练参数。
# 例如,下面设置训练参数,配置学习率为2e-5,训练时batch大小为8,验证时为batch大小32,训练轮数为5,权重衰减大小为0.01,输出文件夹为model_for_seq2seqlm,日志记录的步长为10,即10个batch记录一次;评估策略为训练完一个epoch之后进行评估,模型保存策略同上,设置训练完成后加载最优模型,并指定最优模型的评估指标为rougeL,最后,需要指定predict_with_generate参数值为True。
# training_args = Seq2SeqTrainingArguments(
#     learning_rate=3e-5,
#     per_device_train_batch_size=8,
#     per_device_eval_batch_size=32,
#     num_train_epochs=5,
#     weight_decay=0.01,
#     output_dir="model_for_seq2seqlm",
#     logging_steps=10,
#     evaluation_strategy = "epoch",
#     save_strategy = "epoch",
#     load_best_model_at_end=True,
#     metric_for_best_model="rougeL",
#     predict_with_generate=True   # 训练最后会调用generate方法进行生成
# )from trainer_seq2seq import Seq2SeqTrainer
  • ModelArguments模型参数,
  • DataTrainingArguments数据集操作涉及的参数
#ModelArguments类为model/config/tokenizer涉及的参数
#DataTrainingArguments类为数据涉及到的参数
from arguments import ModelArguments, DataTrainingArguments

数据集的预处理

ADGEN数据集任务的数据形式,输入(content),生成输出(summary)

{"content": "类型#上衣*版型#宽松*版型#显瘦*图案#线条*衣样式#衬衫*衣袖型#泡泡袖*衣款式#抽绳","summary": "这件衬衫的款式非常的宽松,利落的线条可以很好的隐藏身材上的小缺点,穿在身上有着很好的显瘦效果。领口装饰了一个可爱的抽绳,漂亮的绳结展现出了十足的个性,配合时尚的泡泡袖型,尽显女性甜美可爱的气息。"
}

觉得有用 点个赞 + 收藏 吧

End


GPT专栏文章:
GPT实战系列-P-Tuning本地化训练ChatGLM2等LLM模型,到底做了什么?(一)

GPT实战系列-ChatGLM3本地部署CUDA11+1080Ti+显卡24G实战方案

GPT实战系列-ChatGLM2模型的微调训练参数解读

GPT实战系列-如何用自己数据微调ChatGLM2模型训练

GPT实战系列-ChatGLM2部署Ubuntu+Cuda11+显存24G实战方案

GPT实战系列-Baichuan2本地化部署实战方案

决策引擎专栏:
Falcon构建轻量级的REST API服务

决策引擎-利用Drools实现简单防火墙策略

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

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

相关文章

MATLAB 嵌套switch语句||MATLAB while循环

MATLAB 嵌套switch语句 在 MATLAB 中嵌套 switch 语句是可能的,可以在 switch 一部分外嵌套 switch 语句序列。即使 case 常量的内部和外部的 switch 含有共同的值,也不算冲突出现。 MATLAB嵌套switch语句语法 嵌套switch语句的语法如下: s…

012 C++ AVL_tree

前言 本文将会向你介绍AVL平衡二叉搜索树的实现 引入AVL树 二叉搜索树虽可以缩短查找的效率,但如果数据有序或接近有序普通的二叉搜索树将退化为单支树,查找元素相当于在顺序表中搜索元素,效率低下。因此,两位俄罗斯的数学家G.M…

学习模拟简明教程【Learning to simulate】

深度神经网络是一项令人惊叹的技术。 有了足够的标记数据,他们可以学习为图像和声音等高维输入生成非常准确的分类器。 近年来,机器学习社区已经能够成功解决诸如对象分类、图像中对象检测和图像分割等问题。 上述声明中的加黑字体警告是有足够的标记数…

OpenHarmony源码下载

OpenHarmony源码下载 现在的 OpenHarmony 4.0 源码已经有了,在 https://gitee.com/openharmony 地址中,描述了源码获取的方式,但那是基于 ubuntu 或者说是 Linux 的下载方式。在 windows 平台下的下载方式没有做出介绍。 我自己尝试了 wind…

PCIe协议加持,SD卡9.1规范达到媲美SSD的速度4GB/s

近日,SD协会(SDA)宣布了最新的SD Express存储卡的进化,将microSD Express存储卡的速度提高了一倍,达到2GB/s,并引入了4个新的SD Express速度等级,以确保新的SD 9.1规范中最低的顺序性能水平。这…

【Qt开发流程】之HelloWorld程序

【Qt开发流程】之HelloWorld程序 目的编写程序新建项目文件说明及界面设计 程序运行及发布程序运行程序发布手动构建使用windeployqt进行构建 设置应用程序图标修改快捷键类型列表命令行编译程序命令行编译.ui文件自定义类项目模式及项目文件介绍项目模式项目文件 目的 从Hell…

【Linux 源码阅读记录】设备树解析 of 相关代码

前言 最近移植接触 Linux 的设备树解析相关的代码,对 Linux of (open firmware)设备树解析代码比较感兴趣。 可以通过阅读Linux 大量的优秀代码,增强一些编程与编码的技巧与经验 切入点 of_device_is_available :设…

通过bat脚本控制Oracle服务启动停止

1、将Oracle服务全部设置为手动启动 初始安装Oracle之后服务启动状态: 2、服务功能介绍 3、构建服务启动/停止bat脚本 注意:编码选择ANSI(如果编码不是ANSI运行脚本会显示乱码) echo off :main cls echo 注:请保证该脚本是使用管理员权限…

Iceberg学习笔记(1)—— 基础知识

Iceberg是一个面向海量数据分析场景的开放表格式(Table Format),其设计的目的是解决数据存储和计算引擎之间的适配的问题 表格式(Table Format)可以理解为元数据以及数据文件的一种组织方式,处于计算框架&…

c++ binary_semaphore 使用详解

c binary_semaphore 使用详解 std::binary_semaphore c20 头文件 #include <semaphore>。作用&#xff1a;二进制信号量&#xff0c;轻量同步元件&#xff0c;能控制对共享资源的互斥访问。 std::binary_semaphore 成员函数 release&#xff1a;增加内部计数器并解除…

Java —— 抽象类和接口

目录 1. 抽象类 1.1 抽象类概念 1.2 抽象类语法与特性 1.3 抽象类的作用 2. 接口 2.1 接口的概念 2.2 接口的语法规则与特性 2.3 实现多个接口(解决多继承的问题) 2.4 接口间的继承 2.5 抽象类和接口的区别 2.6 接口的使用实例 2.7 Clonable 接口和深拷贝 2.7.1 Cloneable接口 …

探索arkui(2)--- 布局(列表)--- 1(列表数据的展示)

前端开发布局是指前端开发人员宣布他们开发的新网站或应用程序正式上线的活动。在前端开发布局中&#xff0c;开发人员通常会展示新网站或应用程序的设计、功能和用户体验&#xff0c;并向公众宣传新产品的特点和优势。前端开发布局通常是前端开发领域的重要事件&#xff0c;吸…

Apache Airflow (八) :DAG任务依赖设置

&#x1f3e1; 个人主页&#xff1a;IT贫道_大数据OLAP体系技术栈,Apache Doris,Clickhouse 技术-CSDN博客 &#x1f6a9; 私聊博主&#xff1a;加入大数据技术讨论群聊&#xff0c;获取更多大数据资料。 &#x1f514; 博主个人B栈地址&#xff1a;豹哥教你大数据的个人空间-豹…

44、echarts图形自动轮播tooltip提示,并显示高亮

自动轮播方法 参数myChart代表echarts的实例名称, options指定图表的配置项和数据, num类目数量(原因&#xff1a;循环时达到最大值后&#xff0c;使其从头开始循环), time轮播间隔时长 //自动轮播显示高亮--tooltip提示 export function autoHover(myChart, option, num, ti…

【漏洞复现】IP-guard WebServer 远程命令执行

漏洞描述 IP-guard是一款终端安全管理软件,旨在帮助企业保护终端设备安全、数据安全、管理网络使用和简化IT系统管理。互联网上披露IP-guard WebServer远程命令执行漏洞情报。攻击者可利用该漏洞执行任意命令,获取服务器控制权限。 免责声明 技术文章仅供参考,任何个人和…

leetcode字符串必刷题——反转字符串、反转字符串 II、反转字符串中的单词、找出字符串中第一个匹配项的下标、重复的子字符串

文章目录 反转字符串反转字符串 II反转字符串中的单词找出字符串中第一个匹配项的下标重复的子字符串 反转字符串 题目链接 编写一个函数&#xff0c;其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。 不要给另外的数组分配额外的空间&#xff0c;你必…

前端语言报错

1. 语法错误&#xff08;Syntax Errors&#xff09; 这是由于代码不符合语法规则而引起的错误&#xff0c;通常在代码编译阶段发生。示例&#xff1a; javascriptCopy code if (x 10 { // 缺少了右括号 // 代码逻辑 } 2. 类型错误&#xff08;Type Errors&#xff09; 这…

2024年软件测试面试必看系列,看完去面试你会感谢我的!!

朋友圈点赞的测试用例 功能测试 1点赞后是否显示结果 2.点赞后是否可以取消; 3.点赞取消后是否可以重复点赞; 4.共同好友点赞后&#xff0c;是否有消息提醒; 5.非共同好友点赞后&#xff0c;是否有消息提醒; 6.点击点赞人昵称&#xff0c;是否可以跳转到他/她的主页; 7.自己能…

Spring IOC/DI和MVC及若依对应介绍

文章目录 一、Spring IOC、DI注解1.介绍2.使用 二、Spring MVC注解1.介绍2.使用 一、Spring IOC、DI注解 1.介绍 什么是Spring IOC/DI&#xff1f; IOC(Inversion of Control&#xff1a;控制反转)是面向对象编程中的一种设计原则。其中最常见的方式叫做依赖注入&#xff08;…

【佳学基因检测】在LARAVEL中如何使用和设置路由组

【佳学基因检测】在LARAVEL中如何使用和设置路由组 在设计面向基因检测客户的动态网页和API中&#xff0c;基因检测人工智能常常使用LARAVEL网站框架。Laravel中&#xff0c;路由组&#xff08;Route Groups&#xff09;是一种用于组织和管理路由的方法。通过使用路由组&#…