Camp4-L2:InternVL 多模态模型部署微调实践

书生浦语大模型实战营第四期:InternVL 多模态模型部署微调实践

  • 教程链接:https://github.com/InternLM/Tutorial/tree/camp4/docs/L2/InternVL
  • 视频链接:https://www.bilibili.com/video/BV1nESCYWEnN/
  • 任务链接:https://github.com/InternLM/Tutorial/blob/camp4/docs/L2/InternVL/task.md
  • 提交链接:https://aicarrier.feishu.cn/share/base/form/shrcnUqshYPt7MdtYRTRpkiOFJd

任务说明

基础任务(完成此任务即完成闯关)

  • 理解多模态大模型的常见设计模式,可以大概讲出多模态大模型的工作原理。
  • 了解InternVL2的设计模式,可以大概描述InternVL2的模型架构和训练流程。
  • 了解LMDeploy部署多模态大模型的核心代码,并运行提供的gradio代码,在UI界面体验与InternVL2的对话。
  • 了解XTuner,并利用给定数据集微调InternVL2-2B后,再次启动UI界面,体验模型美食鉴赏能力的变化。

基础1:多模态大模型常见设计模式&工作原理

视频内容

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
举例:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

简单总结

多模态大语言模型MLLM是指能够处理和融合多种不同类型数据(如文本、图像、音频、视频等)的大型人工智能模型,这些模型通常基于
深度学习技术,能够理解和生成多种模态的数据,从而在各种复杂的应用场景中表现出强大的能力。

多模态大模型研究的重点是不同模态特征空间的对齐,常见设计模式主要有:

  • 以Blip2,Mini-GPT4为代表的Q-Former路线
  • 以LLaVA, LLaVA-NEXT为代表的Linear Projector/MLP路线

Q-Former由两个transformer子模块组成,一个是query encoder(可学习的查询编码器),另一个是text encoder & decoder(文本编码器和解码器)。这两个子模块通过cross attention(交叉注意力)机制进行交互,以实现视觉和文本信息的对齐和融合。Q-Former旨在通过一组可学习的query tokens来压缩和提取视觉特征,这些特征能够被大语言模型所解释和利用。它使用了一个轻量级的transformer结构,包含一个可学习的query向量集,用于从冻结的视觉模型中提取视觉特征。Q-Former由两个transformer子模块组成,一个是query encoder(可学习的查询编码器),另一个是text encoder & decoder(文本编码器和解码器)。这两个子模块通过cross attention(交叉注意力)机制进行交互,以实现视觉和文本信息的对齐和融合。由于参数量大、收敛速度慢以及信息损失等问题,Q-Former在某些任务上可能受到限制。此外,Q-Former的训练过程也相对复杂,需要较高的计算资源。

LLaVA的架构包括视觉编码器、语言模型和线性投影三个核心组件。视觉编码器用于处理输入图像以提取特征,语言模型用于理解和生成语言响应,线性投影则作为视觉特征和语言模型嵌入空间之间的桥梁。LaVA 的对齐方式相对来说比较简单,只有简单的线性层。Linear Projector 没有视觉信息损失、训练收敛快、表现也好。

基础2:InternVL2设计模式,模型架构&训练流程

InternVL2的设计基本上都在这个图里了,包括InternViT、Pixel Shuffle、动态处理高分辨率图片、基于InternLM2的Tokenizer
在这里插入图片描述
下面是各个部件的细节说明:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述训练是分阶段的,先训MLP Projector部分,第二阶段是联合训练,主要是视觉文本指令
在这里插入图片描述
在这里插入图片描述

大概有这些知识点,先动手操作一下,后面慢慢看~

LMDeploy部署多模态大模型

回顾了一下LMDeploy的优点
在这里插入图片描述
在这里插入图片描述
LMdeploy的环境配置之前基础岛都搞过了,可以回去翻翻,这里直接部署:
改下教程提供的demo.py中的模型路径即可。
PS:本人也遇到了教程中所说的这个问题:
在这里插入图片描述
这个直接按照教程搞下就ok了,可能异步并发的时候也会有bug,遇到再说~

import os
import random
import numpy as np
import torch
import torch.backends.cudnn as cudnn
import gradio as grfrom utils import load_json, init_logger
from demo import ConversationalAgent, CustomThemeFOOD_EXAMPLES = "demo/food_for_demo.json"
# MODEL_PATH = "/root/share/new_models/OpenGVLab/InternVL2-2B"
MODEL_PATH = '../InternVL2-2B'
# MODEL_PATH = "/root/xtuner/work_dirs/internvl_v2_internlm2_2b_lora_finetune_food/lr35_ep10"
OUTPUT_PATH = "./outputs"def setup_seeds():seed = 42random.seed(seed)np.random.seed(seed)torch.manual_seed(seed)cudnn.benchmark = Falsecudnn.deterministic = Truedef main():setup_seeds()# logginginit_logger(OUTPUT_PATH)# food examplesfood_examples = load_json(FOOD_EXAMPLES)agent = ConversationalAgent(model_path=MODEL_PATH,outputs_dir=OUTPUT_PATH)theme = CustomTheme()titles = ["""<center><B><font face="Comic Sans MS" size=10>书生大模型实战营</font></B></center>"""  ## Kalam:wght@700"""<center><B><font face="Courier" size=5>「进阶岛」InternVL 多模态模型部署微调实践</font></B></center>"""]language = """Language: 中文 and English"""with gr.Blocks(theme) as demo_chatbot:for title in titles:gr.Markdown(title)# gr.Markdown(article)gr.Markdown(language)with gr.Row():with gr.Column(scale=3):start_btn = gr.Button("Start Chat", variant="primary", interactive=True)clear_btn = gr.Button("Clear Context", interactive=False)image = gr.Image(type="pil", interactive=False)upload_btn = gr.Button("🖼️ Upload Image", interactive=False)with gr.Accordion("Generation Settings"):                    top_p = gr.Slider(minimum=0, maximum=1, step=0.1,value=0.8,interactive=True,label='top-p value',visible=True)temperature = gr.Slider(minimum=0, maximum=1.5, step=0.1,value=0.8,interactive=True,label='temperature',visible=True)with gr.Column(scale=7):chat_state = gr.State()chatbot = gr.Chatbot(label='InternVL2', height=800, avatar_images=((os.path.join(os.path.dirname(__file__), 'demo/user.png')), (os.path.join(os.path.dirname(__file__), "demo/bot.png"))))text_input = gr.Textbox(label='User', placeholder="Please click the <Start Chat> button to start chat!", interactive=False)gr.Markdown("### 输入示例")def on_text_change(text):return gr.update(interactive=True)text_input.change(fn=on_text_change, inputs=text_input, outputs=text_input)gr.Examples(examples=[["图片中的食物通常属于哪个菜系?"],["如果让你简单形容一下品尝图片中的食物的滋味,你会描述它"],["去哪个地方游玩时应该品尝当地的特色美食图片中的食物?"],["食用图片中的食物时,一般它上菜或摆盘时的特点是?"]],inputs=[text_input])with gr.Row():gr.Markdown("### 食物快捷栏")with gr.Row():example_xinjiang_food = gr.Examples(examples=food_examples["新疆菜"], inputs=image, label="新疆菜")example_sichuan_food = gr.Examples(examples=food_examples["川菜(四川,重庆)"], inputs=image, label="川菜(四川,重庆)")example_xibei_food = gr.Examples(examples=food_examples["西北菜 (陕西,甘肃等地)"], inputs=image, label="西北菜 (陕西,甘肃等地)")with gr.Row():example_guizhou_food = gr.Examples(examples=food_examples["黔菜 (贵州)"], inputs=image, label="黔菜 (贵州)")example_jiangsu_food = gr.Examples(examples=food_examples["苏菜(江苏)"], inputs=image, label="苏菜(江苏)")example_guangdong_food = gr.Examples(examples=food_examples["粤菜(广东等地)"], inputs=image, label="粤菜(广东等地)")with gr.Row():example_hunan_food = gr.Examples(examples=food_examples["湘菜(湖南)"], inputs=image, label="湘菜(湖南)")example_fujian_food = gr.Examples(examples=food_examples["闽菜(福建)"], inputs=image, label="闽菜(福建)")example_zhejiang_food = gr.Examples(examples=food_examples["浙菜(浙江)"], inputs=image, label="浙菜(浙江)")with gr.Row():example_dongbei_food = gr.Examples(examples=food_examples["东北菜 (黑龙江等地)"], inputs=image, label="东北菜 (黑龙江等地)")start_btn.click(agent.start_chat, [chat_state], [text_input, start_btn, clear_btn, image, upload_btn, chat_state])clear_btn.click(agent.restart_chat, [chat_state], [chatbot, text_input, start_btn, clear_btn, image, upload_btn, chat_state], queue=False)upload_btn.click(agent.upload_image, [image, chatbot, chat_state], [image, chatbot, chat_state])text_input.submit(agent.respond,inputs=[text_input, image, chatbot, top_p, temperature, chat_state], outputs=[text_input, image, chatbot, chat_state])demo_chatbot.launch(share=True, server_name="127.0.0.1", server_port=1096, allowed_paths=['./'])demo_chatbot.queue()if __name__ == "__main__":main()

把实战营的宣传照片贴过来提问一下,哈哈,效果貌似还可以:
在这里插入图片描述
试下领域的就不太行了:
在这里插入图片描述
这个需要后面着手微调~

XTuner微调InternVL2-2B

回顾了一下xtuner的优点:
在这里插入图片描述

环境

这里根据教程即可,建议先安装torch,不然可能会有奇奇怪怪的版本冲突:

conda create --name xtuner python=3.10 -y
conda activate xtuner
pip install torch==2.4.1 torchvision==0.19.1 torchaudio==2.4.1 --index-url https://download.pytorch.org/whl/cu121
pip install -U 'xtuner[deepspeed]' timm==1.0.9
pip install transformers==4.39.0

数据

在这里插入图片描述
原始数据需要从huggingface上下载,到官网申请下数据,然后生成一个read的token,然后使用下面命令下载,记得改下自己的保存路径,改那个--local-dir即可

huggingface-cli login
huggingface-cli download --repo-type dataset --resume-download lyan62/FoodieQA --local-dir ./huggingface/FoodieQA --local-dir-use-symlinks False

下载示例:
在这里插入图片描述
原始数据是这个样子:

    {"question": "图片中的食物通常属于哪个菜系?","choices": ["京菜","徽菜","新疆菜","桂菜"],"answer": "2","question_type": "cuisine_type","food_name": "烤羊肉串","question_id": "vqa-0","food_meta": {"main_ingredient": ["肉","羊"],"id": 217,"food_name": "烤羊肉串","food_type": "新疆菜","food_location": "餐馆","food_file": "images/14456664_217_IMG_3854.jpeg"},"question_en": "The food in the picture usually belongs to which cuisine?","choices_en": ["Beijing cuisine","Anhui cuisine","Xinjiang cuisine","Guizhou cuisine"]}

需要根据教程,将数据处理为XTuner所需格式,脚本如下:

import json
input_path = "./huggingface/FoodieQA/FoodieQA/sivqa_tidy.json"  # sivqa_tidy.json所在位置
output_path = "./huggingface/FoodieQA/FoodieQA/sivqa_llava.json"  # 输出文件位置with open(input_path, 'r', encoding='utf-8') as f:foodqa = json.load(f)llava_format = []
for data in foodqa:llava_format.append({"image": data['food_meta']['food_file'],"conversations": [{"from": "human","value": data['question']+"\n<image>"},{"from": "gpt","value": data['choices'][int(data['answer'])] + ",图中的菜是"+ data['food_meta']['food_name']}]})with open(output_path, 'w', encoding='utf-8') as f:json.dump(llava_format, f, indent=4, ensure_ascii=False)

处理完大概这个样子:

    {"image": "images/14456664_217_IMG_3854.jpeg","conversations": [{"from": "human","value": "图片中的食物通常属于哪个菜系?\n<image>"},{"from": "gpt","value": "新疆菜,图中的菜是烤羊肉串"}]}

配置文件

数据准备好, 然后就可以开始微调了,主要就是改配置文件,其他的交给xtuner:
在这里插入图片描述
主要配置说明

- `path`: 需要微调的模型路径,在InternStudio环境下,无需修改。
- `data_root`: 数据集所在路径。
- `data_path`: 训练数据文件路径。
- `image_folder`: 训练图像根路径。
- `prompt_temple`: 配置模型训练时使用的聊天模板、系统提示等。使用与模型对应的即可,此处无需修改。
- `max_length`: 训练数据每一条最大token数。
- `batch_size`: 训练批次大小,可以根据显存大小调整。
- `accumulative_counts`: 梯度累积的步数,用于模拟较大的batch_size,在显存有限的情况下,提高训练稳定性。
- `dataloader_num_workers`: 指定数据集加载时子进程的个数。
- `max_epochs`:训练轮次。
- `optim_type`:优化器类型。
-  `lr`: 学习率
- `betas`: Adam优化器的beta1, beta2
- `weight_decay`: 权重衰减,防止训练过拟合用
- `max_norm`: 梯度裁剪时的梯度最大值
- `warmup_ratio`: 预热比例,前多少的数据训练时,学习率将会逐步增加。
- `save_steps`: 多少步存一次checkpoint
- `save_total_limit`: 最多保存几个checkpoint,设为-1即无限制

LoRA相关参数:

- `r`: 低秩矩阵的秩,决定了低秩矩阵的维度。
- `lora_alpha` 缩放因子,用于调整低秩矩阵的权重。
- `lora_dropout`  dropout 概率,以防止过拟合。

输入xtuner list-cfg,看下目前支持微调的配置文件,找到参考的配置文件:
在这里插入图片描述
复制一份过来:

xtuner copy-cfg internvl_v2_internlm2_2b_lora_finetune ./

主要修改下模型和数据路径,根据自己的gpu大小调节下batch_size和学习率即可,如果在开发机里面基本不用怎么改:

# Copyright (c) OpenMMLab. All rights reserved.
from mmengine.hooks import (CheckpointHook, DistSamplerSeedHook, IterTimerHook,LoggerHook, ParamSchedulerHook)
from mmengine.optim import AmpOptimWrapper, CosineAnnealingLR, LinearLR
from peft import LoraConfig
from torch.optim import AdamW
from transformers import AutoTokenizerfrom xtuner.dataset import InternVL_V1_5_Dataset
from xtuner.dataset.collate_fns import default_collate_fn
from xtuner.dataset.samplers import LengthGroupedSampler
from xtuner.engine.hooks import DatasetInfoHook
from xtuner.engine.runner import TrainLoop
from xtuner.model import InternVL_V1_5
from xtuner.utils import PROMPT_TEMPLATE#######################################################################
#                          PART 1  Settings                           #
#######################################################################
# Model
path = '/root/share/new_models/OpenGVLab/InternVL2-2B'# Data
data_root = '/root/share/datasets/FoodieQA/'  # your data path
data_path = data_root + 'sivqa_llava.json'
image_folder = data_root  # your image folder path
prompt_template = PROMPT_TEMPLATE.internlm2_chat
max_length = 8192# Scheduler & Optimizer
batch_size = 4  # per_device
accumulative_counts = 2
dataloader_num_workers = 4
max_epochs = 10
optim_type = AdamW
# official 1024 -> 4e-5
# lr = 1e-6
lr = 3e-5
betas = (0.9, 0.999)
weight_decay = 0.05
max_norm = 1  # grad clip
warmup_ratio = 0.03# Save
save_steps = 64
save_total_limit = -1  # Maximum checkpoints to keep (-1 means unlimited)#######################################################################
#            PART 2  Model & Tokenizer & Image Processor              #
#######################################################################
model = dict(type=InternVL_V1_5,model_path=path,freeze_llm=True,freeze_visual_encoder=True,# comment the following lines if you don't want to use Lora in llmllm_lora=dict(type=LoraConfig,r=128,lora_alpha=256,lora_dropout=0.05,target_modules=None,task_type='CAUSAL_LM'),# uncomment the following lines if you don't want to use Lora in visual encoder # noqa# visual_encoder_lora=dict(#     type=LoraConfig, r=64, lora_alpha=16, lora_dropout=0.05,#     target_modules=['attn.qkv', 'attn.proj', 'mlp.fc1', 'mlp.fc2'])
)#######################################################################
#                      PART 3  Dataset & Dataloader                   #
#######################################################################
llava_dataset = dict(type=InternVL_V1_5_Dataset,model_path=path,data_paths=data_path,image_folders=image_folder,template=prompt_template,max_length=max_length)train_dataloader = dict(batch_size=batch_size,num_workers=dataloader_num_workers,dataset=llava_dataset,sampler=dict(type=LengthGroupedSampler,length_property='modality_length',per_device_batch_size=batch_size * accumulative_counts),collate_fn=dict(type=default_collate_fn))#######################################################################
#                    PART 4  Scheduler & Optimizer                    #
#######################################################################
# optimizer
optim_wrapper = dict(type=AmpOptimWrapper,optimizer=dict(type=optim_type, lr=lr, betas=betas, weight_decay=weight_decay),clip_grad=dict(max_norm=max_norm, error_if_nonfinite=False),accumulative_counts=accumulative_counts,loss_scale='dynamic',dtype='float16')# learning policy
# More information: https://github.com/open-mmlab/mmengine/blob/main/docs/en/tutorials/param_scheduler.md  # noqa: E501
param_scheduler = [dict(type=LinearLR,start_factor=1e-5,by_epoch=True,begin=0,end=warmup_ratio * max_epochs,convert_to_iter_based=True),dict(type=CosineAnnealingLR,eta_min=0.0,by_epoch=True,begin=warmup_ratio * max_epochs,end=max_epochs,convert_to_iter_based=True)
]# train, val, test setting
train_cfg = dict(type=TrainLoop, max_epochs=max_epochs)#######################################################################
#                           PART 5  Runtime                           #
#######################################################################
# Log the dialogue periodically during the training process, optional
tokenizer = dict(type=AutoTokenizer.from_pretrained,pretrained_model_name_or_path=path,trust_remote_code=True)custom_hooks = [dict(type=DatasetInfoHook, tokenizer=tokenizer),
]# configure default hooks
default_hooks = dict(# record the time of every iteration.timer=dict(type=IterTimerHook),# print log every 10 iterations.logger=dict(type=LoggerHook, log_metric_by_epoch=False, interval=10),# enable the parameter scheduler.param_scheduler=dict(type=ParamSchedulerHook),# save checkpoint per `save_steps`.checkpoint=dict(type=CheckpointHook,save_optimizer=False,by_epoch=False,interval=save_steps,max_keep_ckpts=save_total_limit),# set sampler seed in distributed evrionment.sampler_seed=dict(type=DistSamplerSeedHook),
)# configure environment
env_cfg = dict(# whether to enable cudnn benchmarkcudnn_benchmark=False,# set multi process parametersmp_cfg=dict(mp_start_method='fork', opencv_num_threads=0),# set distributed parametersdist_cfg=dict(backend='nccl'),
)# set visualizer
visualizer = None# set log level
log_level = 'INFO'# load from which checkpoint
load_from = None# whether to resume training from the loaded checkpoint
resume = False# Defaults to use random seed and disable `deterministic`
randomness = dict(seed=None, deterministic=False)# set log processor
log_processor = dict(by_epoch=False)

训练&debug

一开始是打算在自己机器搞事情,后来碰到一个bug,死活解决不了:
在这里插入图片描述

RuntimeError: "_amp_foreach_non_finite_check_and_unscale_cuda" not implemented for 'BFloat16'

网上倒是有一些方案,例如:

  • https://github.com/pytorch/pytorch/issues/127176,不过行不通

办法总是有的,于是开始尝试以下两个解决方案:

  • 利用docker重新在服务器构建个干干净净的容器,看看是不是因为乱七八糟的环境配置导致的
  • 使用书生浦语大模型实战营提供的开发机,这个已经完成基础岛了,解锁了50%的A100权限,嘿嘿

果然,上述两个方案都是行的通的,哈哈,第一个方案用的A30,只能设置batch_size=2,第二个用的50%的A100,可以设置batch_size=4,果断选择第二个~

训练命令(开发机一个卡这么搞ok):

xtuner train /root/homework/L2_internVL/InternVL2-Tutorial/xtuner_config/internvl_v2_internlm2_2b_lora_finetune_food.py --deepspeed deepspeed_zero2

如果多个卡可以这么指定(本地配的环境一个卡那个命令提示有问题,两个卡就没问题,奇奇怪怪的):

CUDA_VISIBLE_DEVICES=0,1 NPROC_PER_NODE=2 xtuner train /root/homework/L2_internVL/InternVL2-Tutorial/xtuner_config/internvl_v2_internlm2_2b_lora_finetune_food.py --deepspeed deepspeed_zero2

对了,之前本地调还遇到了这个错误:

RuntimeError: The server socket has failed to listen on any local network address. The server socket has failed to bind to [::]:29500 (errno: 98 - Address already in use). The server socket has failed to bind to 0.0.0.0:29500 (errno: 98 - Address already in use).

去github查了下issues,有类似问题,居然需要通过改源码来解决,而不能命令行手动改master port,后面可能会改吧,暂时的解决方案请参考:https://github.com/InternLM/xtuner/issues/467
在这里插入图片描述
搞完之后开始训练:
在这里插入图片描述
记得提前开screen,看eta还得好久,看下开发机目前资源占用

在这里插入图片描述

模型转换和合并

主要命令:

python xtuner/configs/internvl/v1_5/convert_to_official.py xtuner/configs/internvl/v2/internvl_v2_internlm2_2b_lora_finetune_food.py ./work_dirs/internvl_v2_internlm2_2b_lora_finetune_food/iter_640.pth ./work_dirs/internvl_v2_internlm2_2b_lora_finetune_food/lr35_ep10/

这是转换后的模型文件:
在这里插入图片描述

模型测试

回到lmdeploy部分,对比使用微调前的模型以及微调后的模型,主要在demo.py里面修改下模型路径即可,效果对比如下,微调前:
在这里插入图片描述
属实在胡说八道了,这是宫保鸡丁呀,嘿嘿~

微调后:
在这里插入图片描述

效果还是不错的呢,后面就可以自己制作感兴趣的数据集,测试下垂直领域的其他案例了~

恭喜我完成了本课程!

参考文献

教程里的参考文献放这里,备用~
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

Unity内置渲染管线升级URP,使用ShaderGraph

问题描述 在内置渲染管线的工程中&#xff0c;导入之前通过ShaderGraph制作的Shader。 文件不可打开&#xff0c;我们需要升级成URP 过程记录 当前Unity版本 2022.3.49 安装Package 创建配置文件 Assets -> Rendering -> URP Asset 创建成功 修改配置 Edit->P…

MYSQL 修改表的结构

在项目的实际开发中&#xff0c;随着版本的迭代和需求的变更&#xff0c;经常会对表结构进行调整&#xff0c;比如向现有表中添加列&#xff0c;删除列&#xff0c;或者修改某列的列名、数据类型或长度&#xff0c;这时就需要对表进行修改操作。 修改表结构语法 ALTER TABLE t…

夹耳开放式耳机好用吗?夹耳开放式耳机推荐

夹耳式耳机作为开放式耳机的一种&#xff0c;在最近几年里深受大家欢迎。它能够受到大家欢迎的原因主要是其不入耳的特性&#xff0c;既有助于保护听力健康&#xff0c;又能让人尽情享受极致的音乐体验。不过&#xff0c;很多小伙伴不知道夹耳式耳机到底好不好用&#xff1f;夹…

React--》掌握openapi-typescript-codegen快速生成API客户端代码

今天深入探索一个神奇的工具——openapi-typescript-codegen。它不仅能够帮助你快速生成TS代码&#xff0c;还能让你的API请求更加高效、类型安全&#xff0c;让开发者摆脱手动编写冗长请求代码的困扰&#xff0c;专注于实现业务逻辑。接下来让我们一起来了解它的强大功能和使用…

【C++】类中的“默认成员函数“--构造函数、析构函数、拷贝构造、赋值运算符重载

目录 "默认"成员函数 概念引入&#xff1a; 一、构造函数 问题引入&#xff1a; 1&#xff09;构造函数的概念 2&#xff09;构造函数实例 3&#xff09;构造函数的特性 4)关于默认生成的构造函数 (默认构造函数) 默认构造函数未完成初始化工作实例: 二…

中仕公考怎么样?事业编面试不去有影响吗?

事业编考试笔试已经通过&#xff0c;但是面试不去参加会有影响吗&#xff1f; 1. 自动放弃面试资格&#xff1a;未能按时出席事业单位的面试将被视为主动放弃该岗位的竞争机会。 2. 个人信誉问题&#xff1a;面试作为招聘流程的关键步骤&#xff0c;无故缺席可能被解释为诚信…

websocket初始化

websocket初始化 前言 上一集我们HTTP的ping操作就可以跑通了&#xff0c;那么我们还有一个协议---websocket&#xff0c;我们在这一集就要去完成我们websocket的初始化。 分析 我们在初始化websocket的之前&#xff0c;我们考虑一下&#xff0c;我们什么时候就要初始化我们…

Unity中HDRP设置抗锯齿

一、以前抗锯齿的设置方式 【Edit】——>【Project Settings】——>【Quality】——>【Anti-aliasing】 二、HDRP项目中抗锯齿的设置方式 在Hierarchy中——>找到Camera对象——>在Inspector面板上——>【Camera组件】——>【Rendering】——>【Pos…

Linux系统任务管理

文章目录 系统任务管理atcron &#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f916;Linux专栏&#xff1a;点击&#xff01; ⏰️创作时间&#xff1a;2024年11月14日11点20分 系统任务管理 任务管理 计划执行&#xff1a;特定时间运行一次&#xff1a;at 定期执…

(附项目源码)Java开发语言,springboot 民宿管理系统的设计与实现 57,计算机毕设程序开发+文案(LW+PPT)

目 录 摘 要 1 绪论 1.1 研究背景 1.2 研究意义 1.3 主要研究内容 1.4 论文章节安排 2 相关技术介绍 2.1 Java编程语言 2.2 MySQL数据库 2.3 springboot框架 3 系统分析 3.1 可行性分析 3.1.1 技术可行性分析 3.1.2 经济可行性分析 3.1.3 操作可行性分析 3.2 …

IDEA热部署(简单死了!)

真的很简单很简单&#xff0c;我之前看别的博主&#xff0c;很多都讲的很复杂&#xff0c;我哭 步骤一&#xff1a; 步骤二&#xff1a; 步骤三&#xff1a; 步骤四&#xff1a; 到这里就结束啦~ 最后很重的是&#xff1a; 1.启动项目时候&#xff0c;必须使用debug方式启…

基于java+springboot+layui的流浪动物交流信息平台设计实现

基于javaspringbootlayui的流浪动物交流信息平台设计实现 &#x1f345; 作者主页 网顺技术团队 &#x1f345; 欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; &#x1f345; 文末获取源码联系方式 &#x1f4dd; &#x1f345; 查看下方微信号获取联系方式 承接各种定制系…

Spring Boot框架:构建可扩展的网上商城

4 系统设计 网上商城系统的设计方案比如功能框架的设计&#xff0c;比如数据库的设计的好坏也就决定了该系统在开发层面是否高效&#xff0c;以及在系统维护层面是否容易维护和升级&#xff0c;因为在系统实现阶段是需要考虑用户的所有需求&#xff0c;要是在设计阶段没有经过全…

「Py」模块篇 之 PyAutoGUI库自动化图形用户界面库

✨博客主页何曾参静谧的博客&#x1f4cc;文章专栏「Py」Python程序设计&#x1f4da;全部专栏「Win」Windows程序设计「IDE」集成开发环境「UG/NX」BlockUI集合「C/C」C/C程序设计「DSA」数据结构与算法「UG/NX」NX二次开发「QT」QT5程序设计「File」数据文件格式「UG/NX」NX定…

打造透明、高效的分布式系统:通过 EMQX ECP 集成实现链路追踪功能

链路追踪作为一种用于监控和观察分布式系统中请求流动和性能的技术&#xff0c;在现代微服务架构中扮演着重要角色。 在复杂的分布式环境中&#xff0c;它可以记录并可视化跨多个服务与组件的完整请求路径&#xff0c;并提供每个服务节点上的执行时间&#xff0c;帮助开发人员…

sql数据库-聚合函数-DQL(类似Excel函数)

目录 聚合函数介绍 语法 举例 统计表中的所有女性员工 统计表中工作地点在北京的员工 聚合函数介绍 常用的聚合函数 函数功能count统计字段数量max最大值min最小值avg平均值sum求和 语法 SELECT 聚合函数(字段列表) FROM 表名; 举例 统计表中的所有女性员工 sele…

【C语言刷力扣】58.最后一个单词的长度

题目&#xff1a; 解题思路; 倒序遍历&#xff0c;先将末尾的空格过滤&#xff0c;再统计至第一个空格。 条件i > 0 放在前面先判断&#xff0c;条件s[i] ! 放后面&#xff0c;反之遇到单字符会溢出。 时间复杂度&#xff1a; 空间复杂度&#xff1a; int lengthOfLas…

【数据运营】数据资产私域运营:探索并实现数据价值变现的新途径

随着数字化浪潮的席卷&#xff0c;数据已成为现代企业的核心竞争力之一。然而&#xff0c;仅仅拥有数据并不足以在激烈的市场竞争中脱颖而出&#xff0c;关键在于如何有效地管理和运营这些数据资产&#xff0c;将其转化为实实在在的商业价值。本文将从数据资产私域运营的定义、…

360天擎终端安全管理 远程控制客户端终端进行的安全防护/终端管理:病毒查杀/插件管理/系统修复/漏洞管理等操作

文章目录 目录 文章目录 使用流程 小结 概要使用流程技术细节小结 概要 如果首页上出现只有5台。但是公司实际上有20台电脑。还有很多未进行安装360天擎的用户主机。我们下发指示通告内容。这个的话需要一个一个排查才能知道谁没有安装。可以查看终端管理页面看到主机IP知道已…

数字人直播骗局大起底!源码部署究竟有哪些优势?

随着数字人直播的应用频率不断上升&#xff0c;越来越多的人开始关注到了它所蕴含着的广阔前景和巨大收益潜力&#xff0c;于是&#xff0c;纷纷打听起了入局相关的事宜。而这也就让许多不法分子盯上了这一项目&#xff0c;并炮制出了各式各样的数字人直播骗局来收割韭菜。 其中…