【自然语言处理】【大模型】极低资源微调大模型方法LoRA以及BLOOM-LORA实现代码

news2024/10/6 20:39:25
极低资源微调大模型方法LoRA以及BLOOM-LORA实现代码

相关博客
【自然语言处理】【大模型】极低资源微调大模型方法LoRA以及BLOOM-LORA实现代码
【自然语言处理】【大模型】DeepMind的大模型Gopher
【自然语言处理】【大模型】Chinchilla:训练计算利用率最优的大语言模型
【自然语言处理】【大模型】大语言模型BLOOM推理工具测试
【自然语言处理】【大模型】GLM-130B:一个开源双语预训练语言模型
【自然语言处理】【大模型】用于大型Transformer的8-bit矩阵乘法介绍
【自然语言处理】【大模型】BLOOM:一个176B参数且可开放获取的多语言模型
【自然语言处理】【大模型】PaLM:基于Pathways的大语言模型
【自然语言处理】【chatGPT系列】大语言模型可以自我改进

一、LoRA的原理

​ LoRA是一种以极低资源微调大模型的方法,其来自于论文LoRA: Low-Rank Adaptation of Large Language Models。

1. 大模型微调的困境

​ 随着模型规模的不断扩大,模型会"涌现"出各种能力。特别是对大语言模型(LLM)来说,随着规模的扩大其在zero-shot、常识推理等能力上会有大幅度的提高。相比于规模较小的模型,大模型的微调成本和部署成本都非常高。例如,GPT-3 175B模型微调需要1.2TB的显存。此外,若针对不同下游任务微调多个模型,那么就需要为每个下游任务保存一份模型权重,成本非常高。在某些场景下,甚至可能需要针对不同的用户微调不同的模型,那么模型微调和部署的成本将不可接受

因此,如何降低大模型微调和部署成本,将是大模型商用的重要一环

2. LoRA之前的方法

​ 在LoRA方法提出之前,也有很多方法尝试解决大模型微调困境的方法。其中有两个主要的方向:(1) 添加adapter层;(2) 由于某种形式的输入层激活。但是这两种方法都有局限性:

2.1 Adapter层会引入推理时延

在这里插入图片描述

​ 简单来说,adapter就是固定原有的参数,并添加一些额外参数用于微调。上图中会在原始的transformer block中添加2个adapter,一个在多头注意力后面,另一个这是FFN后面。

​ 显然,adapter会在模型中添加额外的层,这些层会导致大模型在推理时需要更多的GPU通信,而且也会约束模型并行。这些问题都将导致模型推理变慢

2.2 prefix-tuning难以优化

在这里插入图片描述

​ prefix-tuning方法是受语言模型in-context learning能力的启发,只要有合适的上下文则语言模型可以很好的解决自然语言任务。但是,针对特定的任务找到离散token的前缀需要花费很长时间,prefix-tuning提出使用连续的virtual token embedding来替换离散token。

​ 具体来说,对于transformer中的每一层,都在句子表征前面插入可训练的virtual token embedding。对于自回归模型(GPT系列),在句子前添加连续前缀,即 z = [ PREFIX ; x ; y ] z=[\text{PREFIX};x;y] z=[PREFIX;x;y]。对于Encoder-Decoder模型(T5),则在Ecoder和Decoder前都添加连续前缀 z = [ PREFIX ; x ∣ PREFIX ′ ; y ] z=[\text{PREFIX};x|\text{PREFIX}';y] z=[PREFIX;xPREFIX;y]添加前缀的过程如上图所示

虽然,prefix-tuning并没有添加太多的额外参数。但是,prefix-tuning难以优化,且会减少下游任务的序列长度。

3. 问题的正式表述

术语与约定。由于LoRA原理的介绍,会使用Transformer架构。因此,这里先给出一些术语约定。一个Transformer层的输入和输出维度尺寸为 d m o d e l d_{model} dmodel,使用 W q W_q Wq W k W_k Wk W v W_v Wv W o W_o Wo表示自注意力模块中的query/key/value/output投影矩阵。 W W W W 0 W_0 W0表示预训练模型的权重矩阵, Δ W \Delta W ΔW表示模型在适配过程中的梯度更新。 r r r来表示LoRA模块的秩。使用Adam作为模型优化器,Transformer MLP前馈层的维度为 d f f n = 4 × d m o d e l d_{ffn}=4\times d_{model} dffn=4×dmodel

问题表述。LoRA虽然与训练目标无关,这里还是以语言建模为例。假设给定一个预训练的自回归语言模型 P Φ ( y ∣ x ) P_{\Phi}(y|x) PΦ(yx) Φ \Phi Φ是模型参数。目标是使该语言模型适应下游的摘要、机器阅读理解等任务。每个下游任务都有context-target样本对组成的训练集: Z = { ( x i , y i ) } i = 1 , … , N \mathcal{Z}=\{(x_i,y_i)\}_{i=1,\dots,N} Z={(xi,yi)}i=1,,N,其中 x i x_i xi y i y_i yi都是token序列。例如,对于摘要任务, x i x_i xi是文章内容, y i y_i yi是摘要。

​ 在完整微调的过程中,模型使用预训练好的权重 Φ 0 \Phi_0 Φ0来初始化模型,然后通过最大化条件语言模型来更新参数 Φ 0 + Δ Φ \Phi_0+\Delta\Phi Φ0+ΔΦ
max ⁡ Φ ∑ ( x , y ) ∈ Z ∑ t = 1 ∣ y ∣ log ⁡ ( P Φ ( y t ∣ x , y < t ) ) (1) \max_{\Phi}\sum_{(x,y)\in \mathcal{Z}}\sum_{t=1}^{|y|}\log (P_\Phi(y_t|x,y_{<t})) \tag{1} Φmax(x,y)Zt=1ylog(PΦ(ytx,y<t))(1)
完整微调的主要缺点:对于每个下游任务,都需要学习不同的参数更新 Δ Φ \Delta\Phi ΔΦ,其中维度 ∣ Δ Φ ∣ = ∣ Φ 0 ∣ |\Delta\Phi|=|\Phi_0| ∣ΔΦ∣=Φ0。因此,如果预训练模型很大,存储和部署许多独立的微调模型实例非常有挑战。

​ LoRA为了更加的参数高效,使用相对非常小的参数 Θ \Theta Θ来表示任务相关的参数增量 Δ Φ = Δ Φ ( Θ ) \Delta\Phi=\Delta\Phi(\Theta) ΔΦ=ΔΦ(Θ),其中 ∣ Θ ∣ ≪ ∣ Φ 0 ∣ |\Theta|\ll |\Phi_0| ∣Θ∣Φ0。寻找 Δ Φ \Delta\Phi ΔΦ的任务就变成对 Θ \Theta Θ的优化
max ⁡ Θ ∑ ( x , y ) ∈ Z ∑ t = 1 ∣ y ∣ log ⁡ ( p Φ 0 + Δ Φ ( Θ ) ( y t ∣ x , y < t ) ) (2) \max_{\Theta}\sum_{(x,y)\in\mathcal{Z}}\sum_{t=1}^{|y|}\log(p_{\Phi_0+\Delta\Phi(\Theta)}(y_t|x,y_{<t})) \tag{2} Θmax(x,y)Zt=1ylog(pΦ0+ΔΦ(Θ)(ytx,y<t))(2)
LoRA将会使用低秩表示来编码 Δ Φ \Delta\Phi ΔΦ,同时实现计算高效和存储高效。当预训练模型是175B GPT-3,可训练参数 ∣ Θ ∣ |\Theta| ∣Θ∣可以小至 ∣ Φ 0 ∣ |\Phi_0| Φ0 0.01 % 0.01\% 0.01%

4. LoRA

在这里插入图片描述

​ 通常,神经网络中会包含许多进行矩阵乘法的稠密层,这些层通常是满秩的。Adgajanyan et al.等人的研究表示预训练语言模型具有低的"内在维度"。受该工作的启发,在模型适配下游任务的过程中,权重更新也应该具有低的“内在秩”。对于预训练权重矩阵 W 0 ∈ R d × k W_0\in\mathbb{R}^{d\times k} W0Rd×k,可以通过低秩分解来表示其更新 W 0 + Δ W = W 0 + B A W_0+\Delta W=W_0+BA W0+ΔW=W0+BA B ∈ R d × r , A ∈ R r × k B\in\mathbb{R}^{d\times r},A\in\mathbb{R}^{r\times k} BRd×r,ARr×k且秩 r ≪ min ⁡ ( d , k ) r\ll\min(d,k) rmin(d,k)。在训练过程中, W 0 W_0 W0被冻结且不接受梯度更新, A A A B B B则是可训练参数。注意, W 0 W_0 W0 Δ W = B A \Delta W=BA ΔW=BA都会乘以相同的输入。对于 h = W 0 x h=W_0x h=W0x,前向传播变为:
h = W 0 x + Δ W x = W 0 x + B A x (3) h=W_0x+\Delta Wx=W_0x+BAx \tag{3} h=W0x+ΔWx=W0x+BAx(3)

对矩阵 A A A使用随机高斯初始化,对矩阵 B B B使用0进行初始化,因此 Δ W = B A \Delta W=BA ΔW=BA在训练的开始为0。使用 α r \frac{\alpha}{r} rα来缩放 Δ W x \Delta Wx ΔWx,其中 α \alpha α是小于 r r r的常数。当使用Adam优化时,经过适当的缩放初始化,调优 α \alpha α与调优学习率大致相同。

​ 当进行部署时,以显式的计算和存储 W = W 0 + B A W=W_0+BA W=W0+BA,并正常执行推理。 W 0 W_0 W0 B A BA BA都是 R d × k \mathbb{R}^{d\times k} Rd×k。当需要转换至另一个下游任务,可以通过减去 B A BA BA来恢复 W 0 W_0 W0,然后添加不同的 B ′ A ′ B'A' BA。至关重要的是,这保证不会引人任何额外的推理时延。

5. LoRA应用于Transformer

​ 理论上,LoRA可以应用于任何神经网络的权重矩阵,从而减少可训练参数的数量。Transformer架构中的自注意力模块有4个权重矩阵: W q , W k , W v , W o W_q,W_k,W_v,W_o Wq,Wk,Wv,Wo,以及两个MLP模型的权重矩阵。将 W q W_q Wq(或者 W k , W v W_k,W_v Wk,Wv)作为一个维度为 d m o d e l × d m o d e l d_{model}\times d_{model} dmodel×dmodel的单个矩阵。为了简单和参数高效,本研究仅限于适配下游任务的注意力权重,并冻结MLP模块。

优点。最显著的优点是显存和存储空间的减少。对于使用Adam训练的大型Transformer,若 r ≪ d m o d e l r\ll d_{model} rdmodel,由于不需要存储被冻结参数的优化器状态,VRAM使用量减少2/3。对于GPT-3 175B,训练中的显存消耗从1.2TB减少自350GB。当 r = 4 r=4 r=4并且仅调整query矩阵和value矩阵时,checkpoint大小减少10000倍(从350GB减少自35MB)。另一个优点是,可以在部署时以更低的成本切换任务,仅需要交换LoRA权重即可。此外,与完全微调相比,GPT-3 175B训练速度提高了25%,因为不需要计算绝大多数参数的梯度。

二、代码:实现BLOOM-LoRA

​ 本小节展示如何使用LoRA微调大语言模型bloom。

  • 数据:使用BELLE提供的100万指令微调数据;

  • 模型:使用bloomz-7b1-mt,该版本的bloomz也是经过指令微调后的模型。BLOOM原理见:

    【自然语言处理】【大模型】BLOOM:一个176B参数且可开放获取的多语言模型

  • 依赖包:使用transformers提供模型加载和训练;使用peft提供LoRA实现;使用DeepSpeed提供训练假设。

​ 注意:peft包目前还处于快速迭代当中,后续接口可能会有大的变动,也可能存在一些bug。关键依赖包版本:

transformers==4.26.1
torch==1.13.1
deepspeed==0.8.2
peft==0.2.0

1. 训练代码

​ 为了简洁,假设训练代码位于train.py。

1.1 导入依赖包

import os
import torch
import random
import datasets
import numpy as np

from tqdm import tqdm
from typing import Dict
from torch.utils.data import DataLoader
from transformers import (
    AutoModelForCausalLM,
    AutoTokenizer,
    DataCollatorForSeq2Seq,
    TrainingArguments,
    Trainer
)
from peft import (
    LoraConfig,
    TaskType,
    get_peft_model,
    get_peft_model_state_dict,
    set_peft_model_state_dict
)

def set_random_seed(seed):
    if seed is not None and seed > 0:
        random.seed(seed)
        np.random.seed(seed)
        torch.manual_seed(seed)
        torch.random.manual_seed(seed)
        torch.cuda.manual_seed(seed)
        torch.cuda.manual_seed_all(seed)
        torch.backends.cudnn.deterministic = True

set_random_seed(1234)

1.2 设置参数

# LoRA参数
LORA_R = 8
LORA_ALPHA = 32
LORA_DROPOUT = 0.1
# 训练参数
EPOCHS=3
LEARNING_RATE=5e-5
OUTPUT_DIR="./checkpoints"
BATCH_SIZE=4 # 2
GRADIENT_ACCUMULATION_STEPS=3
# 其他参数
MODEL_PATH = "bigscience/bloomz-7b1-mt"
DATA_PATH = "./data/belle_open_source_1M.train.json"
MAX_LENGTH = 512
PATTERN = "{}\n{}"
DS_CONFIG = "ds_zero2_config.json"
tokenizer = AutoTokenizer.from_pretrained(MODEL_PATH) # 加载tokenizer

1.3 加载数据

dataset = datasets.load_dataset("json", data_files=DATA_PATH)
# print(dataset["train"][0])

1.4 tokenize

def tokenize(text: str, add_eos_token=True):
    result = tokenizer(
        text,
        truncation=True,
        max_length=MAX_LENGTH,
        padding=False,
        return_tensors=None)
    # 判断是否要添加eos_token
    if (result["input_ids"][-1] != tokenizer.eos_token_id
        and len(result["input_ids"]) < MAX_LENGTH
        and add_eos_token):
        result["input_ids"].append(tokenizer.eos_token_id)
        result["attention_mask"].append(1)
    result["labels"] = result["input_ids"].copy()
    return result

def preprocess(example: Dict, train_on_inputs: bool = False):
    prompt = example["input"]
    response = example["target"]
    text = PATTERN.format(prompt, response)
    tokenized_inp = tokenize(text)
    # 若train_on_inputs为False,则将label中与input相关的token替换为-100
    if not train_on_inputs:
        tokenized_prompt = tokenize(prompt,add_eos_token=False)
        prompt_tokens_len = len(tokenized_prompt["input_ids"])
        tokenized_inp["labels"] = [-100]*prompt_tokens_len + tokenized_inp["labels"][prompt_tokens_len:]
    return tokenized_inp

train_data = dataset["train"].shuffle().map(preprocess, remove_columns=["id", "input", "target"])
print(train_data[0])

1.5 collate_fn

# pad_to_multiple_of=8表示padding的长度是8的倍数
collate_fn = DataCollatorForSeq2Seq(tokenizer, pad_to_multiple_of=8, return_tensors="pt", padding=True)

1.6 加载模型

device_map = {"": int(os.environ.get("LOCAL_RANK") or 0)}
# device_map指定模型加载的GPU;troch_dtype=torch.float16表示半精度加载模型
model = AutoModelForCausalLM.from_pretrained(MODEL_PATH, torch_dtype=torch.float16, device_map=device_map)

1.7 LoRA相关

# 转换模型
model = get_peft_model(model, lora_config)
model.config.use_cache = False
old_state_dict = model.state_dict
model.state_dict = (
    lambda self, *_, **__: get_peft_model_state_dict(self, old_state_dict())
).__get__(model, type(model))
# 打印模型中的可训练参数
model.print_trainable_parameters()

1.8 训练参数

args = TrainingArguments(
    output_dir=OUTPUT_DIR, # checkpoint的存储目录
    per_device_train_batch_size=BATCH_SIZE, # 单设备上的batch size
    gradient_accumulation_steps=GRADIENT_ACCUMULATION_STEPS, # 梯度累加的step数
    warmup_steps=100,
    num_train_epochs=EPOCHS,
    learning_rate=LEARNING_RATE,
    fp16=True, # 使用混合精度训练
    logging_steps=50,
    evaluation_strategy="no", # 不进行评估
    save_strategy="steps",
    save_steps=2000, # 保存checkpoint的step数
    save_total_limit=5, # 最多保存5个checkpoint
    deepspeed=DS_CONFIG
)

1.9 模型训练

trainer = Trainer(
    model=model,
    train_dataset=train_data,
    eval_dataset=None,
    args=args,
    data_collator=collate_fn
)
trainer.train()
model.save_pretrained("best_model")

2. DeepSpeed配置文件

​ DeepSpeed配置文件名为ds_zero2_config.json。

{
  "train_micro_batch_size_per_gpu": "auto",
  "gradient_accumulation_steps": "auto",
  "steps_per_print": 50,
  "gradient_clipping": 1.0,
  "zero_optimization": {
    "stage": 2,
    "offload_optimizer": {
            "device": "cpu"
    },
    "contiguous_gradients": true,
    "overlap_comm": true
  },
  "zero_allow_untested_optimizer": true,
  "fp16": {
    "enabled": true,
    "loss_scale": 0,
    "loss_scale_window": 1000,
    "hysteresis": 2,
    "min_loss_scale": 1
  },
  "optimizer": {
    "type": "Adam",
    "params": {
      "lr": "auto",
      "betas": "auto",
      "eps": "auto",
      "weight_decay": "auto"
    }
  },
  "activation_checkpointing": {
    "partition_activations": true,
    "contiguous_memory_optimization": true
  },
  "wall_clock_breakdown": false
}

3. 启动

deepspeed --include=localhost:0,1,2,3 train.py

4. 推理

​ 推理文件名为inference.py

import torch
  
from peft import PeftModel
from transformers import AutoModelForCausalLM, AutoTokenizer

BASE_MODEL = "bigscience/bloomz-7b1-mt"
LORA_WEIGHTS = "best_model"
tokenizer = AutoTokenizer.from_pretrained(BASE_MODEL)
model = AutoModelForCausalLM.from_pretrained(
        BASE_MODEL,
        torch_dtype=torch.float16, # 加载半精度
        device_map={"":0}, # 指定GPU 0
    )
model.eval()
# 加载LoRA权重
model = PeftModel.from_pretrained(model, LORA_WEIGHTS, torch_dtype=torch.float16)
model.half()
prompt = ""
inp = tokenizer(prompt, max_length=512, return_tensors="pt").to("cuda")
outputs = model.generate(input_ids=inp["input_ids"], max_new_tokens=256)
print(tokenizer.decode(outputs[0]))

参考资料

https://arxiv.org/pdf/2106.09685.pdf

https://zhuanlan.zhihu.com/p/615235322

https://github.com/tloen/alpaca-lora/blob/main/finetune.py

https://github.com/huggingface/peft/blob/main/examples/conditional_generation/peft_lora_seq2seq_accelerate_ds_zero3_offload.py

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

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

相关文章

Froala V4.0.18 Crack Froala 编辑器

Froala V4.0.18&#xff1a;复制和粘贴图像变得更好&#xff0c;还有更多&#xff01; 2023 年 3 月 25 日最忠实用户编辑器&#xff0c;新版本发表评论 Froala Editor团队很高兴地宣布发布Froala Editor 4.0.18。这个新版本在质量和稳定性方面有很多改进&#xff0c;并修复了…

优雅的处理sping项目全局异常

全局异常处理 为了达到系统的各个模块中都能够共用同一个异常处理逻辑&#xff0c;避免代码重复和错误。在Spring框架中&#xff0c;可以通过全局异常处理来捕获应用程序中抛出的异常&#xff0c;并根据需要进行处理。 ControllerAdvice ControllerAdvice是Spring MVC框架中…

TCP CUBIC 动力学

曾陪经理一起面试&#xff0c;问过一个问题&#xff1a; CUBIC 的公式&#xff1a; W ( x ) C ( x − K ) 3 W m a x W(x)C(x−K)^3W_{max} W(x)C(x−K)3Wmax​ 其中 x 是什么意思&#xff1f; 本意是想候选人回答 “x 是绝对时间”&#xff0c;然后我会接着问 “这个 x …

[SWPUCTF] 2021新生赛之(NSSCTF)刷题记录 ②

[SWPUCTF] 2021 新生赛&#xff08;NSSCTF刷题记录wp&#xff09; [SWPUCTF 2021 新生赛]no_wakeup[鹤城杯 2021]easy_crypto[suctf 2019]EasySQL[ZJCTF 2019]NiZhuanSiWei[强网拟态 2021]拟态签到题[BJDCTF 2020]easy_md5[SWPUCTF 2021 新生赛]easyupload3.0[SWPUCTF 2021 新生…

Python解决微软Microsoft的登录机器人验证

前言 本文是该专栏的第8篇,结合优质项目案例,让你精通使用Pyppeteer,后面会持续分享Pyppeteer的干货知识,记得关注。 在注册微软Microsoft账号或者注册outlook邮箱账号的时候,会遇到如下机器人验证: 是的,你可能第一眼看到这个验证页面,首先会想到是定位它的页面元素N…

数据结构各结构特点(数组、链表、栈、队列、树)

目录 一、数组 二、链表 三、栈 四、队列 五、树 1.二叉树 2.二叉查找树 3.平衡二叉树&#xff08;AVL树&#xff09; 4.红黑树 六、总结&#xff1a; 1.红黑树和平衡二叉树的区别&#xff1a; 2.为什么有了数组和链表还要引入二叉树&#xff1f; 3.为什么有了二叉树…

【Linux】从机I/O线程报错

一、报错问题 I/O线程报错 查看/var/log/mysqld.d日志&#xff0c;查看报错&#xff1b; 在从机&#xff0c;telnet主机的3306端口显示拒绝连接&#xff1b; 并且从机mysql登录用户密码问题&#xff0c;密码输入正确但是报错【ERROR 1045 (28000): Access denied for user root…

软件开发中的DevOps实践

一、引言 在软件开发领域&#xff0c;为了满足用户需求、提升产品质量、缩短产品上线时间&#xff0c;DevOps已经成为一种流行的开发实践方式。本文将从什么是DevOps、DevOps的理念、DevOps的价值、DevOps的实践等方面详细介绍DevOps在软件开发中的实践。 二、什么是DevOps …

python爬虫原理及源码解析(入门)

目录 一、爬虫是什么&#xff1f;二、爬虫的基本原理三、HTTP协议与响应4、爬虫实现源码 一、爬虫是什么&#xff1f; ​ 如果将互联网比作一张大的蜘蛛网&#xff0c;数据便是存放在蜘蛛网的各个节点&#xff0c;而爬虫就是一只小蜘蛛&#xff0c;沿着网络抓取自己的猎物(数据…

用spring-boot-starter实现事务的统一配置

一、前言 微服务架构下&#xff0c;多个微服务都需要事务操作&#xff0c;如果在每个微服务下都从头配置事务&#xff0c;将非常繁锁。事务配置具有高度的一致性&#xff0c;可以抽取出来&#xff0c;制作starter&#xff0c;在需要配置事务的服务中引入starter依赖即可。 采用…

NFS(UOS)

appsrv 172.16.146.11 strogesrv 172.16.146.53 共享/data/share目录 用于存储app主机的web数据 仅允许stora访问该共享 安装nfs apt install nfs-common nfs-kernel-server -y mkdir /data/share /data/share 172.16.146.50(rw,sync,no_root_squash,insecure) 重启服…

志特转债上市价格预测

志特转债 基本信息 转债名称&#xff1a;志特转债&#xff0c;评级&#xff1a;A&#xff0c;发行规模&#xff1a;6.14033亿元。 正股名称&#xff1a;志特新材&#xff0c;今日收盘价&#xff1a;35.6元&#xff0c;转股价格&#xff1a;41.08元。 当前转股价值 转债面值 / …

微服务学习高级篇【5】之服务异步通信(rabbitmq的高级特性)

文章目录 环境准备&#xff1a;MQ部署【docker环境】消息可靠性生产者消息确认项目配置定义Return回调和ConfirmCallback 消息持久化交换机持久化队列持久化消息持久化 消费者消息确认none模式演示 消费失败重试机制本地重试失败策略 总结 死信交换机初识死信交换机死信交换机接…

【DHCP原理与配置】

目录 一、了解DHCP服务使用DHCP的好处DHCP的分配方式 二、DHCP的租约过程传输协议端口DHCP的IP地址自动获取工作原理 三、配置DHCP服务器安装dhcp查看配置文件根据配置文件提示查看相关文档 四、模拟外网和内网互通进入主机1的设置进入主机2的设置复制dhcp文件&#xff0c;修改…

Nginx 优化与防盗链

Ngnix优化主要有两种&#xff0c;一种是配置上的优化&#xff0c;一种是内核上的优化 实验准备&#xff1a;安装好一台Nginx服务器&#xff0c;IP&#xff1a;192.168.126.22&#xff0c;域名&#xff1a;www.accp.com 浏览器访问nginx服务器此时F12查看网页信息&#xff0c;可…

MySQL之表的约束

目录 一 空属性 定义 如何设置 示例 影响&#xff1a; 二 默认值 定义 示例 影响&#xff1a; 三 列描述 定义 示例 影响&#xff1a; 四 zerofill 定义&#xff1a; 示例&#xff1a; 影响&#xff1a; 五 主键 定义 主键的性质是什么&#xff1a; 为什么要…

C++——一种特殊的二叉搜索树之红黑树

目录 1 红黑树的概念2 红黑树的性质3 红黑树节点的定义4 红黑树的插入操作情况一: cur为红&#xff0c;p为红&#xff0c;g为黑&#xff0c;u存在且为红。情况二: cur为红&#xff0c;p为红&#xff0c;g为黑&#xff08;不存在连续的红结点&#xff09;&#xff0c;u不存在/u存…

设计模式 -- 适配器模式

前言 月是一轮明镜,晶莹剔透,代表着一张白纸(啥也不懂) 央是一片海洋,海乃百川,代表着一块海绵(吸纳万物) 泽是一柄利剑,千锤百炼,代表着千百锤炼(输入输出) 月央泽,学习的一种过程,从白纸->吸收各种知识->不断输入输出变成自己的内容 希望大家一起坚持这个过程,也同…

第五篇 Spring 集合注入、作用域

《Spring》篇章整体栏目 ————————————————————————————— 【第一章】spring 概念与体系结构 【第二章】spring IoC 的工作原理 【第三章】spring IOC与Bean环境搭建与应用 【第四章】spring bean定义 【第五章】Spring 集合注入、作用域 【第六章】…

时间序列分析卫星重力梯度观测值

阚昊宇 1 时间序列图 导入数据&#xff0c;共2880历元&#xff08;86370 s&#xff09;数据&#xff0c;取前2400历元&#xff08;72000 s&#xff09;数据作为训练集&#xff0c;后480历元作为测试集。将训练集绘制时间序列图如下图 1红色线所示&#xff0c;可见明显的自相关…