[InternLM训练营第二期笔记]4. XTuner 微调 LLM:1.8B、多模态、Agent


该系列是上海AI Lab举行的书生 浦语大模型训练营的相关笔记部分。
该笔记是第四节课,学习大语言模型微调的基本概念,以及利用XTuner工具进行微调。


0. 什么是LLM中的微调

0.1 两种Finetune范式

微调的目的是为了让foundation模型在特定的领域更好地发挥作用。目前Finetune的范式主要有两种:增量预训练指令跟随

其中,增量预训练的意思是继续训练,加入领域内的一些特定的知识。这个过程是无监督的,不需要人为制造高质量对话。

而指令跟随微调,是让模型学会对话模板,因此是有监督的,数据是高质量的问答数据。

在这里插入图片描述

0.2 一条数据的一生

那么数据从开始到结束,是怎么运作的呢?

首先,获得原始数据之后,需要将其转换成标准格式数据,这个标准格式数据是训练框架能够识别的,例如下面:

在这里插入图片描述
其中,system字段相当于一个前置条件,后面的User和Assistant也规定了问答的角色。在InternLM的用户定义中,是如下的json文件:

在这里插入图片描述

第三步,是需要添加对话模板,也就是让LLM区分出System,User和Assistant:

在这里插入图片描述
以上的代码模板是来自于用户定义的json文件的,当然不同的LLM有不同的格式。

此外,为了让LLM知道什么时候开始一段话,以及结束一段话,一般还有起始符和结束符<s>和</s>.

当然在计算loss的时候,只对模型的output计算。例如,InternLM中一条数据的input和output就是这样的:

在这里插入图片描述

0.3 微调的具体方案:LoRA与QLoRA

如果我们重新训练LLM是非常昂贵的。LoRA的核心思想就是,每一个线性层可以通过低秩分解的方式来提取最主要的信息,从而大大减小参数量,也就是 M ∈ R M × N = M 1 M 2 , M 1 = R M × k , M 2 ∈ R k × N , k < < M , N M\in \mathbb{R}^{M \times N} = M_1M_2, M_1=\mathbb{R}^{M\times k}, M_2 \in \mathbb{R}^{k \times N}, k << M, N MRM×N=M1M2,M1=RM×k,M2Rk×N,k<<M,N

在这里插入图片描述
下图是LoRA和QLoRA(量化版)的具体区别:

在这里插入图片描述

1. 实战环节:XTuner微调个人小助手

这个环节的目的是体验从用户自定义数据到微调模型的过程(微调方式是前面讲到的指令微调),然后看看模型是否能给出我们想要的答案。

1.1 准备工作

在InternLM中创建开发机,选择10% * A100即可,cuda版本选择11.7.

首先直接运行

studio-conda xtuner0.1.17
conda activate xtuner0.1.17

安装环境. 随后创建文件夹以及拉取XTuner代码:

cd ~
mkdir -p /root/xtuner0117 && cd /root/xtuner0117
git clone -b v0.1.17  https://github.com/InternLM/xtuner
cd /root/xtuner0117/xtuner
pip install -e '.[all]'

随后,我们需要构造并转换数据集格式:

# 前半部分是创建一个文件夹,后半部分是进入该文件夹。
mkdir -p /root/ft && cd /root/ft

# 在ft这个文件夹里再创建一个存放数据的data文件夹
mkdir -p /root/ft/data && cd /root/ft/data

然后,复制以下生成数据集的代码:

vim /root/ft/data/generate_data.py
import json

# 设置用户的名字
name = 'wjp'
# 设置需要重复添加的数据次数
n =  10000

# 初始化OpenAI格式的数据结构
data = [
    {
        "messages": [
            {
                "role": "user",
                "content": "请做一下自我介绍"
            },
            {
                "role": "assistant",
                "content": "我是{}的小助手,内在是上海AI实验室书生·浦语的1.8B大模型哦".format(name)
            }
        ]
    }
]

# 通过循环,将初始化的对话数据重复添加到data列表中
for i in range(n):
    data.append(data[0])

# 将data列表中的数据写入到一个名为'personal_assistant.json'的文件中
with open('personal_assistant.json', 'w', encoding='utf-8') as f:
    # 使用json.dump方法将数据以JSON格式写入文件
    # ensure_ascii=False 确保中文字符正常显示
    # indent=4 使得文件内容格式化,便于阅读
    json.dump(data, f, ensure_ascii=False, indent=4)

随后运行:

cd /root/ft/data && python /root/ft/data/generate_data.py

打开生成的json文件,可以发现成功生成了n组我们想要的对话~

在这里插入图片描述
然后,从share文件夹中搞出来1.8B的模型,在此为了省空间,就直接创建软链接:

ln -s /root/share/new_models/Shanghai_AI_Laboratory/internlm2-chat-1_8b /root/ft/model

然后,我们在所有的配置文件中,查找跟internlm2 1.8b有关的,运行以下命令,其中-p表示pattern,名称匹配模式的意思

xtuner list-cfg -p internlm2_1_8b

在这里插入图片描述

所以我们找到了两个相关的配置文件,从文件名称可以看出,第一个是全参数微调的,第二个是用QLoRA微调的,数据集名称是alpaca, epoch为3. 由于我们显存有限,当然选择QLoRA微调,接下来复制config文件:

mkdir -p /root/ft/config
xtuner copy-cfg internlm2_1_8b_qlora_alpaca_e3 /root/ft/config

1.2 配置文件修改

我们需要对权重路径、训练轮数等参数进行修改,修改后的config如下:

# Copyright (c) OpenMMLab. All rights reserved.
import torch
from datasets import load_dataset
from mmengine.dataset import DefaultSampler
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 (AutoModelForCausalLM, AutoTokenizer,
                          BitsAndBytesConfig)

from xtuner.dataset import process_hf_dataset
from xtuner.dataset.collate_fns import default_collate_fn
# 由于我们的数据集不再是原本的 aplaca 数据集,因此我们也要进入 PART 3 的部分对相关的内容进行修改。包括说我们数据集输入的不是一个文件夹而是一个单纯的 json 文件以及我们的数据集格式要求改为我们最通用的 OpenAI 数据集格式。

from xtuner.dataset.map_fns import openai_map_fn, template_map_fn_factory
# from xtuner.dataset.map_fns import alpaca_map_fn, template_map_fn_factory
from xtuner.engine.hooks import (DatasetInfoHook, EvaluateChatHook,
                                 VarlenAttnArgsToMessageHubHook)
from xtuner.engine.runner import TrainLoop
from xtuner.model import SupervisedFinetune
from xtuner.parallel.sequence import SequenceParallelSampler
from xtuner.utils import PROMPT_TEMPLATE, SYSTEM_TEMPLATE

#######################################################################
#                          PART 1  Settings                           #
#######################################################################
# Model
pretrained_model_name_or_path = '/root/ft/model'  # 模型地址修改
use_varlen_attn = False

# Data
alpaca_en_path = '/root/ft/data/personal_assistant.json'  # 数据集地址修改
prompt_template = PROMPT_TEMPLATE.default
max_length = 1024  # 单条数据的token数 其实绰绰有余
pack_to_max_length = True

# parallel
sequence_parallel_size = 1

# Scheduler & Optimizer
batch_size = 1  # per_device
accumulative_counts = 16
accumulative_counts *= sequence_parallel_size
dataloader_num_workers = 0
max_epochs = 2 # 降低一些轮数
optim_type = AdamW
lr = 2e-4
betas = (0.9, 0.999)
weight_decay = 0
max_norm = 1  # grad clip
warmup_ratio = 0.03

# Save
save_steps = 500
save_total_limit = 2  # Maximum checkpoints to keep (-1 means unlimited)

# Evaluate the generation performance during the training
evaluation_freq = 100  # 修改评估频率
SYSTEM = SYSTEM_TEMPLATE.alpaca
evaluation_inputs = ['请你介绍一下你自己', '你是谁', '你是我的小助手吗']  # 对我们关心的问题进行评估

#######################################################################
#                      PART 2  Model & Tokenizer                      #
#######################################################################
tokenizer = dict(
    type=AutoTokenizer.from_pretrained,
    pretrained_model_name_or_path=pretrained_model_name_or_path,
    trust_remote_code=True,
    padding_side='right')

model = dict(
    type=SupervisedFinetune,
    use_varlen_attn=use_varlen_attn,
    llm=dict(
        type=AutoModelForCausalLM.from_pretrained,
        pretrained_model_name_or_path=pretrained_model_name_or_path,
        trust_remote_code=True,
        torch_dtype=torch.float16,
        quantization_config=dict(
            type=BitsAndBytesConfig,
            load_in_4bit=True,
            load_in_8bit=False,
            llm_int8_threshold=6.0,
            llm_int8_has_fp16_weight=False,
            bnb_4bit_compute_dtype=torch.float16,
            bnb_4bit_use_double_quant=True,
            bnb_4bit_quant_type='nf4')),
    lora=dict(
        type=LoraConfig,
        r=64,
        lora_alpha=16,
        lora_dropout=0.1,
        bias='none',
        task_type='CAUSAL_LM'))

#######################################################################
#                      PART 3  Dataset & Dataloader                   #
#######################################################################
# 这部分也需要修改 改成openai格式
alpaca_en = dict(
    type=process_hf_dataset,
    dataset=dict(type=load_dataset, path='json', data_files=dict(train=alpaca_en_path)),
    tokenizer=tokenizer,
    max_length=max_length,
    dataset_map_fn=openai_map_fn,
    template_map_fn=dict(
        type=template_map_fn_factory, template=prompt_template),
    remove_unused_columns=True,
    shuffle_before_pack=True,
    pack_to_max_length=pack_to_max_length,
    use_varlen_attn=use_varlen_attn)

sampler = SequenceParallelSampler \
    if sequence_parallel_size > 1 else DefaultSampler
train_dataloader = dict(
    batch_size=batch_size,
    num_workers=dataloader_num_workers,
    dataset=alpaca_en,
    sampler=dict(type=sampler, shuffle=True),
    collate_fn=dict(type=default_collate_fn, use_varlen_attn=use_varlen_attn))

#######################################################################
#                    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
custom_hooks = [
    dict(type=DatasetInfoHook, tokenizer=tokenizer),
    dict(
        type=EvaluateChatHook,
        tokenizer=tokenizer,
        every_n_iters=evaluation_freq,
        evaluation_inputs=evaluation_inputs,
        system=SYSTEM,
        prompt_template=prompt_template)
]

if use_varlen_attn:
    custom_hooks += [dict(type=VarlenAttnArgsToMessageHubHook)]

# 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,
        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 benchmark
    cudnn_benchmark=False,
    # set multi process parameters
    mp_cfg=dict(mp_start_method='fork', opencv_num_threads=0),
    # set distributed parameters
    dist_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)

1.3 训练

直接运行

# 使用 deepspeed 来加速训练
xtuner train /root/ft/config/internlm2_1_8b_qlora_alpaca_e3_copy.py --work-dir /root/ft/train_deepspeed --deepspeed deepspeed_zero2

命令中的deepspeed_zero2是加速训练的工具。

训练过程中,刚开始效果一般

在这里插入图片描述

在第300次迭代以后,效果就不错了
在这里插入图片描述
第600次以后,就有点过拟合了
在这里插入图片描述

1.4 模型转换与模型整合

模型转换的目的就是将pth文件转换成通用的huggingface文件:

mkdir -p /root/ft/huggingface

xtuner convert pth_to_hf /root/ft/config/internlm2_1_8b_qlora_alpaca_e3_copy.py /root/ft/train_deepspeed/iter_600.pth /root/ft/huggingface

这就是转换后的huggingface格式的模型:

在这里插入图片描述

对于 LoRA 或者 QLoRA 微调出来的模型其实并不是一个完整的模型,而是一个额外的层(adapter)。那么训练完的这个层最终还是要与原模型进行组合才能被正常的使用。

而对于全量微调的模型(full)其实是不需要进行整合这一步的,因为全量微调修改的是原模型的权重而非微调一个新的 adapter ,因此是不需要进行模型整合的。

直接运行以下命令:

mkdir -p /root/ft/final_model

export MKL_SERVICE_FORCE_INTEL=1
xtuner convert merge /root/ft/model /root/ft/huggingface /root/ft/final_model

最后,我们进行合并后模型的对话测试:

在这里插入图片描述

2. 进阶作业1——将模型上传到OpenXLab

首先在OpenXLab网站中更改自己的用户名,比如我改成jackwoo

然后运行

apt-get install git-lfs
git lfs install

git config --global user.name "jackwoo"
git config --global user.email "XXXX@163.com"

在OpenXLav中点击创建——创建模型

然后将仓库拉取到本地:

git clone https://code.openxlab.org.cn/jackwoo/XTunerTest.git

然后将前面训练出来的模型复制到仓库里:

cp -r ~/ft/final_model ~/XTunerTest/

因为这里面有大文件,因此我们要用lfs标记他们:

git lfs track "*.bin"
git lfs track "*.model"

这里科普一下git lfs的作用

在这里插入图片描述

在上传更改之前,与GitHub一样,需要获取令牌:

点击用户头像——密钥管理——令牌 选择可写权限

在这里插入图片描述

然后上传更改

git add -A
git commit -m "upload model"
git push

然而事实证明,我在开发机中push之后提示输入密码而不是token,密码输入为token后也失败。因此直接

git push https://$TOKEN的值@code.openxlab.org.cn/jackwoo/XTunerTest.git

这次输入密码,直接输入token就对了。

在这里插入图片描述

3. 进阶作业2——微调多模态大模型LLaVA

多模态大模型微调的原理基本是,在已有LLM的基础上,训练一个image encoder,每次将文本和image encoder编码出的图像特征向量一同输入大模型,就可以协同理解的。

下面直接上实战步骤。

本实验需要30% * A100. 官方文档见https://github.com/InternLM/Tutorial/blob/camp2/xtuner/llava/xtuner_llava.md.

为了方便,官方已经提供预训练好的image encoder(用的ViT),这样我们直接把官方的仓库git clone下来,就不用自己手动搞了。

cd ~

git clone https://github.com/InternLM/tutorial -b camp2

我们看到官方对图片已经做了问答的标注:

在这里插入图片描述
现在我们把这个标注重复若干次,变成多组标注:

cd tutorial/

python /root/tutorial/xtuner/llava/llava_data/repeat.py \
  -i /root/tutorial/xtuner/llava/llava_data/unique_data.json \
  -o /root/tutorial/xtuner/llava/llava_data/repeated_data.json \  # 输出文件
  -n 200  # 重复200次

我们使用xtuner命令查一下对于llava的相关config:

xtuner list-cfg -p llava_internlm2_chat_1_8b

在这里插入图片描述

哦我们选择第二个:

xtuner copy-cfg \
  llava_internlm2_chat_1_8b_qlora_clip_vit_large_p14_336_lora_e1_gpu8_finetune \
  /root/tutorial/xtuner/llava

跟上面一样,我们需要修改一些路径信息:

# Model
llm_name_or_path = '/root/share/new_models/Shanghai_AI_Laboratory/internlm2-chat-1_8b'
visual_encoder_name_or_path = '/root/share/new_models/openai/clip-vit-large-patch14-336'
# Specify the pretrained pth
pretrained_pth = '/root/tutorial/xtuner/llava/iter_2181.pth'  # noqa: E501

# Data
data_root = '/root/tutorial/xtuner/llava/llava_data/'
data_path = data_root + 'repeated_data.json'
image_folder = data_root
prompt_template = PROMPT_TEMPLATE.internlm2_chat
max_length = int(2048 - (336 / 14)**2)

# Scheduler & Optimizer
batch_size = 1  # per_device
accumulative_counts = 1
dataloader_num_workers = 0
max_epochs = 1
optim_type = AdamW
lr = 2e-4
betas = (0.9, 0.999)
weight_decay = 0
max_norm = 1  # grad clip
warmup_ratio = 0.03

# Save
save_steps = 500
save_total_limit = 2  # Maximum checkpoints to keep (-1 means unlimited)

# Evaluate the generation performance during the training
evaluation_freq = 500
SYSTEM = ''
evaluation_images = 'https://llava-vl.github.io/static/images/view.jpg'
evaluation_inputs = ['Please describe this picture','What is the equipment in the image?']

然后开始训练:

cd /root/tutorial/xtuner/llava/

xtuner train /root/tutorial/xtuner/llava/llava_internlm2_chat_1_8b_qlora_clip_vit_large_p14_336_lora_e1_gpu8_finetune_copy.py --deepspeed deepspeed_zero2

训练完毕后,进行性能对比:

训练前的:

# 解决小bug
export MKL_SERVICE_FORCE_INTEL=1
export MKL_THREADING_LAYER=GNU

# pth转huggingface
xtuner convert pth_to_hf \
  llava_internlm2_chat_1_8b_clip_vit_large_p14_336_e1_gpu8_pretrain \
  /root/tutorial/xtuner/llava/iter_2181.pth \
  /root/tutorial/xtuner/llava/llava_data/iter_2181_hf

# 启动!
xtuner chat /root/share/new_models/Shanghai_AI_Laboratory/internlm2-chat-1_8b \
  --visual-encoder /root/share/new_models/openai/clip-vit-large-patch14-336 \
  --llava /root/tutorial/xtuner/llava/llava_data/iter_2181_hf \
  --prompt-template internlm2_chat \
  --image /root/tutorial/xtuner/llava/llava_data/test_img/oph.jpg

在这里插入图片描述
可以看到 效果不太像,只能复述图片标题

训练后的:

# 解决小bug
export MKL_SERVICE_FORCE_INTEL=1
export MKL_THREADING_LAYER=GNU

# pth转huggingface
xtuner convert pth_to_hf \
  /root/tutorial/xtuner/llava/llava_internlm2_chat_1_8b_qlora_clip_vit_large_p14_336_lora_e1_gpu8_finetune_copy.py \
  /root/tutorial/xtuner/llava/work_dirs/llava_internlm2_chat_1_8b_qlora_clip_vit_large_p14_336_lora_e1_gpu8_finetune_copy/iter_1200.pth \
  /root/tutorial/xtuner/llava/llava_data/iter_1200_hf

# 启动!
xtuner chat /root/share/new_models/Shanghai_AI_Laboratory/internlm2-chat-1_8b \
  --visual-encoder /root/share/new_models/openai/clip-vit-large-patch14-336 \
  --llava /root/tutorial/xtuner/llava/llava_data/iter_1200_hf \
  --prompt-template internlm2_chat \
  --image /root/tutorial/xtuner/llava/llava_data/test_img/oph.jpg

在这里插入图片描述
可以看到 微调后模型可以更细致地描述图片的内容。

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

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

相关文章

力扣练习题(2024/4/18)

1不相交的线 在两条独立的水平线上按给定的顺序写下 nums1 和 nums2 中的整数。 现在&#xff0c;可以绘制一些连接两个数字 nums1[i] 和 nums2[j] 的直线&#xff0c;这些直线需要同时满足&#xff1a; nums1[i] nums2[j]且绘制的直线不与任何其他连线&#xff08;非水平线…

mysql按季度统计数据

最近遇到按表里得交付时间换成季度取统计&#xff0c;如下&#xff1a; select sp.Id,sp.title,QUARTER(sp.expected_delivery_time) dateStr,CONCAT(DATE(MIN(sp.expected_delivery_time)),至,DATE(MAX(sp.expected_delivery_time))) dateStr2,sp.DemandType,sp.IndustryGrou…

【人工智能基础】状态空间搜索

状态空间法 状态空间&#xff1a;一个问题全部可能的状态以及其关系的集合。 状态空间图&#xff1a;以图的形式表示问题的状态空间&#xff0c;节点对应状态&#xff0c;边对应状态转移算子&#xff0c;边上的权对应转移所需的代价 问题的解&#xff1a;是从最开始状态到目…

BP使用和弱口令漏洞

目录 一、BP使用 1.BP设置 2.Proxy 3.Reapter 4.Decord 5.Intruder 二、弱口令爆破 1.服务弱口令爆破 2.验证码绕过 一、BP使用 1.BP设置 设置代理的监听端口: 这里设置为本机的9090端口 2.Proxy 浏览器要挂代理&#xff0c;设置为本机的9090端口 打开拦截功能 当浏览…

Youtube DNN

目录 1. 挑战 2. 系统整体结构 3.召回 4. 排序 5. 训练和测试样本的处理 1. 挑战 &#xff08;1&#xff09;规模。很多现有的推荐算法在小规模上效果好&#xff0c;但Youtobe规模很大。 &#xff08;2&#xff09;新颖度。Youtobe语料库是动态的&#xff0c;每秒都会有…

Windows如何安装JDK

JDK和JRE简介 JDK&#xff1a;Java Development ToolKit java开发工具包&#xff0c;包含JRE针对java程序开发者 JRE&#xff1a;Java Runtime Environment java程序的运行环境针对java使用者来说 下载JDK&#xff0c;进入官网下载 Oracle官网 双击下载好之后的exe文件&#…

关于Python中install edge_tts记录

如下代码&#xff1a; #!/usr/bin/env python3""" Basic audio streaming example.This example shows how to stream the audio data from the TTS engine, and how to get the WordBoundary events from the engine (which could be ignored if not needed).…

分保、等保、关保、密评之间联系与区别

分保、等保、关保、密评之间联系与区别 什么是“三保一评”分保等保关保密评 相关的法律法规依据分保等保关保密评 分保工作简介分保工作流程分级保护技术要求 等保工作简介关保工作简介密评工作简介三保一评联系与区别 什么是“三保一评” 分保 涉密信息系统分级保护 指涉密信…

vivado 存储器校准调试

存储器校准调试 Vivado 中的存储器接口 IP 支持校准调试。其中存储有实用的核配置、校准和数据窗口信息 &#xff0c; 可在 Vivado 硬件管理器 中访问这些信息。“存储器校准调试 (Memory Calibration Debug) ”可随时用于读取此信息 &#xff0c; 并从存储器接口 IP 中获…

Linux命令学习—Iptables 防火墙(上)

1.1、防火墙 1、防火墙的定义 所谓防火墙指的是一个由软件和硬件设备组合而成、在内部网和外部网之间、专用网与公共网之间的界面上 构造的保护屏障.是一种获取安全性方法的形象说法&#xff0c;它是一种计算机硬件和软件的结合&#xff0c;使 Internet 与 Intranet 之间建立起…

LeetCode216:组合总和Ⅲ

题目描述 找出所有相加之和为 n 的 k 个数的组合&#xff0c;且满足下列条件&#xff1a; 只使用数字1到9 每个数字 最多使用一次 返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次&#xff0c;组合可以以任何顺序返回。 解题思想 使用回溯算法 代码 class So…

代理IP对网络爬虫有什么影响?

代理IP对网络爬虫的影响深远且多方面&#xff0c;主要体现在以下几个方面&#xff1a; 第一点&#xff0c;代理IP能有效防止爬虫IP被封禁&#xff1a;在爬虫工作过程中&#xff0c;如果频繁访问同一目标网站&#xff0c;很容易被该网站的服务器识别为恶意行为&#xff0c;导致…

【大数据】Apache Knox 概述

Apache Knox 概述 1.概述1.1 Kerberos 封装1.2 简化客户端证书的管理1.3 Apache Ranger 集成1.4 Hadoop URLs VS Knox URLs 2.自定义 Apache Knox2.1 Topology2.2 Provider2.3 Services2.4 Personalized services 3.Tips3.1 Setting up SSL3.2 常见问题3.2.1 Bulky answer3.2.2…

【JavaSE】JDK17的一些特性

前言 从springboot3.0开始&#xff0c;已经不⽀持JDK8了 选⽤Java17&#xff0c;概括起来主要有下⾯⼏个主要原因 JDK17是LTS(⻓期⽀持版)&#xff0c;可以免费商⽤到2029年。⽽且将前⾯⼏个过渡版&#xff08;JDK9-JDK16&#xff09; 去其糟粕&#xff0c;取其精华的版本JDK17…

hbase基础(二)

HBase第二天 名称空间 namespace&#xff1a;名称空间默认hbase有两个名称空间&#xff0c;default、hbasedefault名称空间是默认创建表的位置&#xff0c;hbase是专门存放系统表的名称空间&#xff08;namespace、meta&#xff09;管理命名空间指令 create_namespace 命名空…

qt tcp 连接 秒断连,求助

问题&#xff1a; tcp连接总是秒成功后断连 debug会出现下面这些 onecore\net\netprofiles\service\src\nsp\dll\namespaceserviceprovider.cpp(550)\nlansp_c.dll!00007FFDA2A1D93D: (caller: 00007FFDD8BEACF6) LogHr(1) tid(336c) 8007277C ¡£¡£ one…

小型企业网络优化加速方案

随着数字化经济蓬勃发展&#xff0c;小型企业的网络基础设施变得尤为重要。在这一浪潮中&#xff0c;建立一个稳定、高效的企业网络成为支撑业务发展的关键。本文将深入研究针对小型企业设计的网络优化加速方案&#xff0c;助力企业主了解如何规划和实施适合自身业务需求的网络…

Spring Boot 统一功能处理(三)

本篇主要介绍Spring Boot的统一异常处理。 目录 一、统一异常处理的使用 二、测试统一异常处理效果 三、浅析原理 ControllerAdvice简析 统一处理异常简析 一、统一异常处理的使用 在前面介绍统一数据返回时&#xff0c;我们在程序发生异常时会把整个报错信息都封装在da…

BRC20铭文铭刻解析

BRC20铭文铭刻的出现对于智能制造无疑是一个重要的里程碑。随着科技的飞速发展&#xff0c;智能制造已经成为制造业发展的必然趋势&#xff01;智能制造是指通过运用人工智能、物联网、大数据等先进技术&#xff0c;实现生产过程的自动化、智能化和高效化。 1. BRC20铭文的概念…

Docker了解及命令行使用

一、了解Docker 1、什么是Docker Docker为应用程序的开发、发布和运行提供了一个基于容器的标准化平台。容器运行的是应用程序&#xff0c;Docker平台用来管理容器的整个生命周期 2、虚拟机与容器 2.1、虚拟机是什么 虚拟机&#xff08;Virtual Machine&#xff09;是一种软…