【LLM】浅析chatglm的sft+p-tuning v2

news2024/11/17 22:02:24

note

  • GLM将针对不同类型下游任务的预训练目标统一为了自回归填空,结合了混合的注意力机制和新的二维位置编码。
  • 本文浅析sft,并基于GLM在广告描述数据集上进行sft+p-tuning代码的数据流讲解

文章目录

  • note
  • 零、ChatGLM2模型
  • 一、Supervised fine-tuning
    • 1. 数据样本的准备
    • 2. stanford_alpaca的dataset类
    • 3. 数据格式、计算loss的数据
  • 二、P-Tuning v2的数据流
    • 1. 数据准备
    • 2. P-Tuning v2微调
    • 3. 模型推理
  • 三、垂直领域训练注意事项
  • Reference

零、ChatGLM2模型

后面对chatglm2进行sft微调,这里顺带着先介绍下glm2:
在这里插入图片描述

  • chatglm-6b:https://github.com/THUDM/ChatGLM-6B
  • chatglm2-6b:https://github.com/THUDM/ChatGLM2-6B
  • chatglm130:https://github.com/THUDM/GLM-130B

在这里插入图片描述

  • 自回归空格填充任务:
    • 初始文本输入:x1, x2,x3,x4,x5,x6
    • 随机掩码mask
      • PartA 部分:x1,x2,M,x4,M ,其中M表示mask的跨度
      • PartB 部分: S,x5,x6,S,x3(刚才mask掉的那几坨,随机排序后,对起始位置加入token)
      • 拼接PartA和PartB
  • 自注意机制(chatglm在Q、K中加入了RoPE位置信息): Q = W q X K = W k X V = W v X Attention ⁡ ( Q , K , V , A ) = softmax ⁡ ( Q K T d k ) V \begin{aligned} Q & =W_q X \\ K & =W_k X \\ V & =W_v X \\ \operatorname{Attention}(Q, K, V, A) & =\operatorname{softmax}\left(\frac{Q K^T}{\sqrt{d_k}}\right) V \end{aligned} QKVAttention(Q,K,V,A)=WqX=WkX=WvX=softmax(dk QKT)V
  • mask:chatglm6b使用prefix-LM的mask,对于输入的前缀使用双向注意力,对于后续的生成部分则是causal mask
    • PartA部分内的各token可以互相注意到
    • PartB部分内的tokens可以注意到PartA和PartB中已经生成的token

在这里插入图片描述

    def get_masks(self, input_ids, past_key_values, padding_mask=None):
        batch_size, seq_length = input_ids.shape
        full_attention_mask = torch.ones(batch_size, seq_length, seq_length, device=input_ids.device)
        full_attention_mask.tril_()
        past_length = 0
        if past_key_values:
            past_length = past_key_values[0][0].shape[0]
        if past_length:
            full_attention_mask = torch.cat((torch.ones(batch_size, seq_length, past_length,
                                                        device=input_ids.device), full_attention_mask), dim=-1)
        if padding_mask is not None:
            full_attention_mask = full_attention_mask * padding_mask.unsqueeze(1)
        if not past_length and padding_mask is not None:
            full_attention_mask -= padding_mask.unsqueeze(-1) - 1
        full_attention_mask = (full_attention_mask < 0.5).bool()
        full_attention_mask.unsqueeze_(1)
        return full_attention_mask

一、Supervised fine-tuning

sft就是下面的第一个环节,使用指令数据做有监督精调 (supervised fine-tuning)。

在这里插入图片描述

1. 数据样本的准备

参考stanford_alpaca的sft:

  • 整理的数据有三列:instruction、input、output。
  • Instruction和input通过prompt组搞在一起,为sourse;output换为target
  • 把source和target和token.eos_token_id直接拼接在一起,这个时候暂时叫sentence。
  • 然后把sentence通过tokenizer转换成input_ids。
  • 最后一步,要把input_ids复制一份,叫labels。然后把labels前面的位置,即source对应的tokenid,全部变成-100。
  • 那么这个时候,一个面向sft任务的input_ids和labels就已经构造好了。

在这个任务里面,使用的就是transformers的DataCollatorForSeq2Seq。这个data_collator任务很简单:就是让每一个batch内的input_ids和labels都长度对齐。

def _tokenize_fn(strings: Sequence[str], tokenizer: transformers.PreTrainedTokenizer) -> Dict:
    """Tokenize a list of strings."""
    tokenized_list = [
        tokenizer(
            text,
            return_tensors="pt",
            padding="longest",
            max_length=tokenizer.model_max_length,
            truncation=True,
        )
        for text in strings
    ]
    input_ids = labels = [tokenized.input_ids[0] for tokenized in tokenized_list]
    input_ids_lens = labels_lens = [
        tokenized.input_ids.ne(tokenizer.pad_token_id).sum().item() for tokenized in tokenized_list
    ]
    return dict(
        input_ids=input_ids,
        labels=labels,
        input_ids_lens=input_ids_lens,
        labels_lens=labels_lens,
    )


def preprocess(
    sources: Sequence[str],
    targets: Sequence[str],
    tokenizer: transformers.PreTrainedTokenizer,
) -> Dict:
    """Preprocess the data by tokenizing."""
    examples = [s + t for s, t in zip(sources, targets)]
    examples_tokenized, sources_tokenized = [_tokenize_fn(strings, tokenizer) for strings in (examples, sources)]
    input_ids = examples_tokenized["input_ids"]
    labels = copy.deepcopy(input_ids)
    for label, source_len in zip(labels, sources_tokenized["input_ids_lens"]):
        label[:source_len] = IGNORE_INDEX
    return dict(input_ids=input_ids, labels=labels)

2. stanford_alpaca的dataset类

class SupervisedDataset(Dataset):
    """Dataset for supervised fine-tuning."""

    def __init__(self, data_path: str, tokenizer: transformers.PreTrainedTokenizer):
        super(SupervisedDataset, self).__init__()
        logging.warning("Loading data...")
        list_data_dict = utils.jload(data_path)

        logging.warning("Formatting inputs...")
        prompt_input, prompt_no_input = PROMPT_DICT["prompt_input"], PROMPT_DICT["prompt_no_input"]
        sources = [
            prompt_input.format_map(example) if example.get("input", "") != "" else prompt_no_input.format_map(example)
            for example in list_data_dict
        ]
        targets = [f"{example['output']}{tokenizer.eos_token}" for example in list_data_dict]

        logging.warning("Tokenizing inputs... This may take some time...")
        data_dict = preprocess(sources, targets, tokenizer)

        self.input_ids = data_dict["input_ids"]
        self.labels = data_dict["labels"]

    def __len__(self):
        return len(self.input_ids)

    def __getitem__(self, i) -> Dict[str, torch.Tensor]:
        return dict(input_ids=self.input_ids[i], labels=self.labels[i])

3. 数据格式、计算loss的数据

简单分析hf的trainer:hugggingface自带的trainer类中参数如下:

    def __init__(
        self,
        model: Union[PreTrainedModel, nn.Module] = None,
        args: TrainingArguments = None,
        data_collator: Optional[DataCollator] = None,
        train_dataset: Optional[Dataset] = None,
        eval_dataset: Optional[Union[Dataset, Dict[str, Dataset]]] = None,
        tokenizer: Optional[PreTrainedTokenizerBase] = None,
        model_init: Optional[Callable[[], PreTrainedModel]] = None,
        compute_metrics: Optional[Callable[[EvalPrediction], Dict]] = None,
        callbacks: Optional[List[TrainerCallback]] = None,
        optimizers: Tuple[torch.optim.Optimizer, torch.optim.lr_scheduler.LambdaLR] = (None, None),
        preprocess_logits_for_metrics: Optional[Callable[[torch.Tensor, torch.Tensor], torch.Tensor]] = None,
    )

hf自带的trainer中的compute_loss函数中,用到了标签平滑的正则化(将真实标签的概率分布进行平滑,减少模型过拟合):
在这里插入图片描述
对于上面trainer类的参数data_collator,对于encoder和decoder模型都是不同的:比如前者的bert模型,用于ner词性标注任务时:

BertForTokenClassification(
  (bert): BertModel(
    (embeddings): BertEmbeddings(
      (word_embeddings): Embedding(28996, 768, padding_idx=0)
      (position_embeddings): Embedding(512, 768)
      (token_type_embeddings): Embedding(2, 768)
      (LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
      (dropout): Dropout(p=0.1, inplace=False)
    )
    (encoder): BertEncoder(
      (layer): ModuleList(
        (0-11): 12 x BertLayer(
          (attention): BertAttention(
            (self): BertSelfAttention(
              (query): Linear(in_features=768, out_features=768, bias=True)
              (key): Linear(in_features=768, out_features=768, bias=True)
              (value): Linear(in_features=768, out_features=768, bias=True)
              (dropout): Dropout(p=0.1, inplace=False)
            )
            (output): BertSelfOutput(
              (dense): Linear(in_features=768, out_features=768, bias=True)
              (LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
              (dropout): Dropout(p=0.1, inplace=False)
            )
          )
          (intermediate): BertIntermediate(
            (dense): Linear(in_features=768, out_features=3072, bias=True)
            (intermediate_act_fn): GELUActivation()
          )
          (output): BertOutput(
            (dense): Linear(in_features=3072, out_features=768, bias=True)
            (LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
            (dropout): Dropout(p=0.1, inplace=False)
          )
        )
      )
    )
  )
  (dropout): Dropout(p=0.1, inplace=False)
  (classifier): Linear(in_features=768, out_features=9, bias=True)
)

对于上面这种encoder模型的data_collator定义如下(比如我们要做文本分类,每个数据样本即对应一个文本序列+一个label):

from transformers import BertTokenizer
from torch.utils.data import DataLoader

tokenizer = BertTokenizer.from_pretrained('bert-base-cased')

class TextClassificationDataset(Dataset):
    def __init__(self, texts, labels, max_length):
        self.texts = texts
        self.labels = labels
        self.max_length = max_length
    
    def __len__(self):
        return len(self.texts)
    
    def __getitem__(self, index):
        text = self.texts[index]
        label = self.labels[index]
        input_ids, attention_mask = self.encode_text(text)
        return {'input_ids': input_ids, 'attention_mask': attention_mask, 'label': label}
    
    def encode_text(self, text):
        input_ids = tokenizer.encode(text, add_special_tokens=True, max_length=self.max_length, truncation=True)
        attention_mask = [1] * len(input_ids)
        padding_length = self.max_length - len(input_ids)
        input_ids = input_ids + [0] * padding_length
        attention_mask = attention_mask + [0] * padding_length
        return input_ids, attention_mask

def collate_fn(batch):
    input_ids = [item['input_ids'] for item in batch]
    attention_mask = [item['attention_mask'] for item in batch]
    labels = [item['label'] for item in batch]
    label_map = {label: i for i, label in enumerate(set(labels))}
    encoded_labels = [label_map[label] for label in labels]
    return {'input_ids': input_ids, 'attention_mask': attention_mask, 'labels': encoded_labels}

train_dataset = TextClassificationDataset(texts=train_texts, labels=train_labels, max_length=128)
train_dataloader = DataLoader(train_dataset, batch_size=32, collate_fn=collate_fn)

后者的gpt是next token prediction,以chatglm为栗子,特点是加入了ROPE旋转位置编码、使用RMSNorm正则化等操作:

ChatGLMForConditionalGeneration(
  (transformer): ChatGLMModel(
    (embedding): Embedding(
      (word_embeddings): Embedding(65024, 4096)
    )
    (rotary_pos_emb): RotaryEmbedding()
    (encoder): GLMTransformer(
      (layers): ModuleList(
        (0-27): 28 x GLMBlock(
          (input_layernorm): RMSNorm()
          (self_attention): SelfAttention(
            (query_key_value): QuantizedLinear()
            (core_attention): CoreAttention(
              (attention_dropout): Dropout(p=0.0, inplace=False)
            )
            (dense): QuantizedLinear()
          )
          (post_attention_layernorm): RMSNorm()
          (mlp): MLP(
            (dense_h_to_4h): QuantizedLinear()
            (dense_4h_to_h): QuantizedLinear()
          )
        )
      )
      (final_layernorm): RMSNorm()
    )
    (output_layer): Linear(in_features=4096, out_features=65024, bias=False)
  )
)

对于上面这种decoder模型,我们的data_collator定义如下(TextGenerationDataset对输入文本进行编码,并且将目标序列往后移动一位以便预测,dataloader将数据集分为多个mini-batch,collate_fn函数对每个mini-batch数据进行自定义组合):

from transformers import GPT2Tokenizer
from torch.utils.data import Dataset, DataLoader
from torch.nn.utils.rnn import pad_sequence

tokenizer = GPT2Tokenizer.from_pretrained('gpt2')

class TextGenerationDataset(Dataset):
    def __init__(self, texts, max_length):
        self.texts = texts
        self.max_length = max_length
    
    def __len__(self):
        return len(self.texts)
    
    def __getitem__(self, index):
        text = self.texts[index]
        input_ids, attention_mask = self.encode_text(text)
        return {'input_ids': input_ids, 'attention_mask': attention_mask}
    
    def encode_text(self, text):
        input_ids = tokenizer.encode(text, add_special_tokens=True, max_length=self.max_length, truncation=True)
        attention_mask = [1] * len(input_ids)
        padding_length = self.max_length - len(input_ids)
        input_ids = input_ids + [tokenizer.pad_token_id] * padding_length
        attention_mask = attention_mask + [0] * padding_length
        return input_ids, attention_mask

def collate_fn(batch):
    input_ids = [torch.tensor(item['input_ids'], dtype=torch.long) for item in batch]
    attention_mask = [torch.tensor(item['attention_mask'], dtype=torch.long) for item in batch]
    input_ids = pad_sequence(input_ids, batch_first=True, padding_value=tokenizer.pad_token_id)
    attention_mask = pad_sequence(attention_mask, batch_first=True, padding_value=0)
    return {'input_ids': input_ids, 'attention_mask': attention_mask}

train_dataset = TextGenerationDataset(texts=train_texts, max_length=128)
train_dataloader = DataLoader(train_dataset, batch_size=32, collate_fn=collate_fn)

在计算loss时也会将input_id向后移动1位后作为label,比如下面chatglm2-6b的源码:

  • lm_logits:初始[batch_size, sequence_length, vocab_size],减1是将最后一个位置的预测结果去掉
  • labels:初始[batch_size, sequence_length],下面代码的labels[..., 1:]即第1个(0开始计算)维度从位置1开始取
  • 最后计算nll_losssmoothed_loss的加权和,作为loss值
    def __call__(self, model_output, labels, shift_labels=False):
        logits = model_output["logits"] if isinstance(model_output, dict) else model_output[0]
        if shift_labels:
            logits = logits[..., :-1, :].contiguous()
            labels = labels[..., 1:].contiguous()

        log_probs = -nn.functional.log_softmax(logits, dim=-1)
        if labels.dim() == log_probs.dim() - 1:
            labels = labels.unsqueeze(-1)

        padding_mask = labels.eq(self.ignore_index)
        # In case the ignore_index is -100, the gather will fail, so we replace labels by 0. The padding_mask
        # will ignore them in any case.
        labels = torch.clamp(labels, min=0)
        nll_loss = log_probs.gather(dim=-1, index=labels)
        # works for fp16 input tensor too, by internally upcasting it to fp32
        smoothed_loss = log_probs.sum(dim=-1, keepdim=True, dtype=torch.float32)

        nll_loss.masked_fill_(padding_mask, 0.0)
        smoothed_loss.masked_fill_(padding_mask, 0.0)

        # Take the mean over the label dimensions, then divide by the number of active elements (i.e. not-padded):
        num_active_elements = padding_mask.numel() - padding_mask.long().sum()
        nll_loss = nll_loss.sum() / num_active_elements
        smoothed_loss = smoothed_loss.sum() / (num_active_elements * log_probs.shape[-1])
        return (1 - self.epsilon) * nll_loss + self.epsilon * smoothed_loss

二、P-Tuning v2的数据流

项目:基于广告数据集,chatglm2的p-tuning v2微调
背景:sft指令微调时为了加快训练, Parameter-Efficient Model Adaptation,所以经常伴随着prompt tuning、lora tuning、p-tuning v2等peft操作。下面以chatglm2官方的p-tuning v2为例介绍。

1. 数据准备

ADGEN 数据集任务为根据输入(content)生成一段广告词(summary)。

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

2. P-Tuning v2微调

  • train.sh 中的 PRE_SEQ_LENLR 分别是 soft prompt 长度和训练的学习率,可以进行调节以取得最佳的效果。
  • P-Tuning-v2 方法会冻结全部的模型参数,可通过调整 quantization_bit 来被原始模型的量化等级,不加此选项则为 FP16 精度加载。
  • glm2源码中的data_collator使用了transformer的DataCollatorForSeq2Seq,其实很多时候直接用这个就行了,不用像上面1.1中的stanford_alpaca中一样去自定义:
from transformers import DataCollatorForSeq2Seq
    data_collator = DataCollatorForSeq2Seq(
        tokenizer,
        model=model,
        label_pad_token_id=label_pad_token_id,
        pad_to_multiple_of=None,
        padding=False
    )

3. 模型推理

在 P-tuning v2 训练时模型只保存 PrefixEncoder 部分的参数(继承了trainerPrefixTrainer类,重写了父类的_save函数),所以在推理时需要同时加载原 ChatGLM2-6B 模型以及 PrefixEncoder 的权重,因此需要指定 evaluate.sh 中的参数:

--model_name_or_path THUDM/chatglm2-6b
--ptuning_checkpoint $CHECKPOINT_PATH

如果是,只需要跟之前一样设定 model_name_or_path

--model_name_or_path $CHECKPOINT_PATH

评测指标为中文 Rouge score 和 BLEU-4。

三、垂直领域训练注意事项

如PowerLawGLM的训练。(怎么做法律条文的准确输出)

  • 对pretrained 进行法文垂直场景的增量微调。 收集大量的法文数据(网络,离线):对GLM130基座模型进行增量预训练,先把垂直场景的法律条文数据注入到pretrained 模型。
  • 对齐法律场景对齐:用监督数据做SFT微调(百万级真实法律条文的数据)。
  • 解决出现的幻觉问题(输出不存在的法律条文): (重点工程优化,比如做基于检索的条文输出)可参考Langchain+LLM的输出方式(外挂知识库)。

Reference

[1] GLM: General Language Model Pretraining with Autoregressive Blank Infilling ,ACL2022
[2] https://aclanthology.org/2022.acl-long.26.pdf
[3] GLM论文精读-自回归填空的通用语言模型

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

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

相关文章

位图和布隆过滤器+哈希切分思想

文章目录 一.位图(bitset)底层实现: 二.布隆过滤器(bloomFilter)底层实现: 三.哈希切分思想 一.位图(bitset) 位图是一种以一个比特位为数据记录单元的哈希表 ,以无符号整数为key值,采用直接定址法(不存在哈希冲突的问题),其哈希映射函数为 f ( k e y ) k e y ( k e y 的存在…

有关合泰BA45F5260中断的思考

最近看前辈写的代码&#xff0c;发现这样一段代码&#xff1a; #ifdef SUPPORT_RF_NET_FUNCTION if(UART_INT_is_L()) { TmrInsertTimer(eTmrHdlUartRxDelay,TMR_PERIOD(2000),NULL); break; } #endif 其中UART_INT_is_L&am…

【lesson6】Linux下:第一个小程序,进度条代码

文章目录 准备工作sleep问题fflush回车与换行的区别 进度条代码 准备工作 sleep问题 首先我们来看一段代码&#xff1a; 这时候有个 问题这个代码是输出“hello world”还是先sleep三秒&#xff1f; 再来一段代码 这个代码是先sleep三秒还是先输出“hello world”&#xff…

「乐天世界」NFT 作品集

进入「乐天世界」NFT 作品集的迷人世界&#xff0c;这里仿佛就是乐天世界探险主题公园里充满活力的礼品店。 准备好随着想象力的飞跃而沉浸其中吧&#xff0c;因为主题公园里的普通物品已经变得非凡。沉浸在游乐园美食的魔力中&#xff0c;如香脆的玉米热狗、令人垂涎的巧克力蛋…

立创EDA学习

学习树莓派3B的板子发现有个扩展板比较好&#xff0c;自己最好画一个&#xff0c;反正免费。 学习视频&#xff1a;立创EDA&#xff08;专业版&#xff09;电路设计与制作快速入门。 下载专业版&#xff0c;并激活。【分专业版和标准版&#xff0c;专业版也是免费的】 手机…

基于物联网技术的能耗在线监测平台的架构设计与应用

安科瑞 华楠 摘要&#xff1a;围绕工业生产等领域节能降耗实际需求&#xff0c;提出基于物联网的能耗在线监测平台总体方案&#xff0c;面向政府、行业、企业提供能耗管理信息化管理与服务;研究设计能耗监测终端&#xff0c;支持多种工业总线及工业协议&#xff0c;实现电表、…

jenkins执行jmeter时,报Begin size 1 is not equal to fixed size 5

jenkins执行jmeter脚本的时候一直提示如下错误&#xff1a; Tidying up ... Fri Jul 28 17:03:53 CST 2023 (1690535033178) Error generating the report: org.apache.jmeter.report.dashboard.GenerationException: Error while processing samples: Consumer failed wi…

this关键字和同步异步宏认为微任务理解

目录 js面试常见问题&#xff1a;1.this指向 2.闭包定义和作用 3.原型链 4.异步协程 this关键字 this主要有以下几个使用场合。 1&#xff09;全局环境 &#xff08;2&#xff09;构造函数 &#xff08;3&#xff09;对象的方法 避免多层this 避免数组处理方法中的 this 避免回…

RabbitMQ 教程 | RabbitMQ 入门

&#x1f468;&#x1f3fb;‍&#x1f4bb; 热爱摄影的程序员 &#x1f468;&#x1f3fb;‍&#x1f3a8; 喜欢编码的设计师 &#x1f9d5;&#x1f3fb; 擅长设计的剪辑师 &#x1f9d1;&#x1f3fb;‍&#x1f3eb; 一位高冷无情的编码爱好者 大家好&#xff0c;我是 DevO…

VS CODE 20230728

VSCode添加至右键菜单 2.Visual Studio Code(VS Code)中文显示乱码的解决方法 1.按 快捷键 ctrl, 在搜索栏中输入“files:auto Guess Encoding” 勾选 还是乱码

UG\NX二次开发 获取2D制图视图中可见的对象,并获取类型

文章作者:里海 来源网站:https://blog.csdn.net/WangPaiFeiXingYuan 简介: 使用UF_VIEW_ask_visible_objects获取2D制图视图中可见的对象,并获取类型。 下面是将一个六面体以不同的视图投影,获取视图对象和类型的效果。 效果: 1个部件事例,1个体,4条边 1个部件事…

C++,类和对象-多态,制作饮品

#include<iostream> using namespace std;//多态案例&#xff0c;制作饮品class AbstractDrinking { public://煮水virtual void Boil() 0;//冲泡virtual void Brew() 0;//倒入茶杯virtual void PourInCup() 0;//加入辅料virtual void PutSomething() 0;//制作饮品vo…

外文期刊影响因子去哪里查询,如何查询

期刊影响因子(Impact factor&#xff0c;IF)&#xff0c;是代表期刊影响大小的一项定量指标。也就是某刊平均每篇论文的被引用数&#xff0c;它实际上是某刊在某年被全部源刊物引证该刊前两年发表论文的次数&#xff0c;与该刊前两年所发表的全部源论文数之比。那么&#xff0c…

4.操作元素属性

4.1操作元素常用属性 ●通过 JS 设置/修改 标签元素属性&#xff0c;比如通过src更换图片 ●最常见的属性比如&#xff1a;href、 title、 src 等 ●语法: 对象.属性 值【示例】 // 1.获取元素 const pic document.querySelector( img ) // 2.操作元素 pic.src ./images/b…

vector使用

文章目录 vector的介绍vector的使用vector的初始化vector iterator迭代器的使用vector 空间增长问题vector的增删改查 迭代器失效总结 vector的介绍 文档介绍 vector是表示可变大小数组的序列容器。就像数组一样&#xff0c;vector也采用的连续存储空间来存储元素。也就是意味着…

分布式事务及解决方案

1、分布式事务 分布式事务就是在一个交易中各个服务之间的相互调用必须要同时成功或者同时失败&#xff0c;保持一致性和可靠性。在单体项目架构中&#xff0c;在多数据源的情况下也会发生 分布式事务问题。本质上来说&#xff0c;分布式事务就是为了保证不同数据库的数据一致性…

关于Docker的知识点

Docker是一个快速交付应用、运行应用的技术。 Docker基本操作--容器 示例&#xff1a;创建运行一个Nginx容器

【每日一题】—— B - Broken Rounding(AtCoder Beginner Contest 273)

&#x1f30f;博客主页&#xff1a;PH_modest的博客主页 &#x1f6a9;当前专栏&#xff1a;每日一题 &#x1f48c;其他专栏&#xff1a; &#x1f534; 每日反刍 &#x1f7e1; C跬步积累 &#x1f7e2; C语言跬步积累 &#x1f308;座右铭&#xff1a;广积粮&#xff0c;缓称…

【个人笔记】Linux命令之watch命令

1.命令简介 watch 以周期性方式执行给定的命令&#xff0c;并全屏显示执行结果&#xff0c;可以帮助监测一个命令的运行结果。 2.命令格式及参数选项说明 命令格式&#xff1a; watch [OPTIONS] COMMAND选项说明&#xff1a; -d, --differences [PERMANENT]高亮显示最近两…