参数高效微调PEFT(二)快速入门P-Tuning、P-Tuning V2

参数高效微调PEFT(二)快速入门P-Tuning、P-Tuning V2

参数高效微调PEFT(一)快速入门BitFit、Prompt Tuning、Prefix Tuning

  • 今天,我们继续了解下来自清华大学发布的两种参数高效微调方法P-Tuning和P-Tuning v2。
  • 可以简单的将P-Tuning是认为针对Prompt Tuning的改进,P-Tuning v2认为是针对Prefix Tuning的改进。
  • 不过,P-Tuning是21年3月份发布的,而Prompt Tuning是21年4月发布的。

1 P-Tuning

1.1 P-Tuning概述

  • 论文链接:GPT Understands, Too (202103)

  • Prompt Tuning原理如下图所示:冻结主模型全部参数,在训练数据前加入一小段Prompt,只训练Prompt的表示层,即一个Embedding模块。论文实验表明,只要模型规模够大,简单加入 Prompt tokens 进行微调,就能取得很好的效果。

在这里插入图片描述

  • P Tuning原理如下图所示:在Prompt-Tuning的基础上,对Prompt部分进行进一步的编码计算,加速收敛。具体来说,PEFT中支持两种编码方式,一种是LSTM,一种是MLP。与Prompt-Tuning不同的是,Prompt的形式只有Soft Prompt。

在这里插入图片描述

  • P Tuning将Prompt转换为可以学习的Embedding层,并用MLP+LSTM的方式来对Prompt Embedding进行一层处理

    • 相比Prefix Tuning,P Tuning仅限于输入层,没有在每一层都加virtual token
    • 经过预训练的LM的词嵌入已经变得高度离散,如果随机初始化virtual token,容易优化到局部最优值,而这些virtual token理论是应该有相关关联的。因此,作者通过实验发现用一个prompt encoder来编码会收敛更快,效果更好。即用一个LSTM+MLP去编码这些virtual token以后,再输入到模型
    • 作者在实验中发现,相同参数规模,如果进行全参数微调,Bert的在NLU(自然语言理解)任务上的效果,超过GPT很多;但是在P-Tuning下,GPT可以取得超越Bert的效果。

    在这里插入图片描述

1.2 P-Tuning轻量微调bloom模型

1.2.1 peft中的P-Tuning

我们来看下peft\tuners\p_tuning.py中的内容:

  • 可以看到,peft支持两种编码方式,即MLP和LSTM。
# peft\tuners\p_tuning.py
class PromptEncoderReparameterizationType(str, enum.Enum):
    MLP = "MLP"
    LSTM = "LSTM"
  • P-Tuning在peft中默认的编码方式为MLP。
# peft\tuners\p_tuning.py
@dataclass
class PromptEncoderConfig(PromptLearningConfig):
    encoder_reparameterization_type: Union[str, PromptEncoderReparameterizationType] = field(
        default=PromptEncoderReparameterizationType.MLP,
        metadata={"help": "How to reparameterize the prompt encoder"},
    )
    encoder_hidden_size: int = field(
        default=None,
        metadata={"help": "The hidden size of the prompt encoder"},
    )
    encoder_num_layers: int = field(
        default=2,
        metadata={"help": "The number of layers of the prompt encoder"},
    )
    encoder_dropout: float = field(
        default=0.0,
        metadata={"help": "The dropout of the prompt encoder"},
    )

    def __post_init__(self):
        self.peft_type = PeftType.P_TUNING
  • 如下代码所示,经过LSTM或MLP去编码virtual token以后,再输入到模型。
class PromptEncoder(torch.nn.Module):
    """
    Input shape: (`batch_size`, `total_virtual_tokens`)
    Output shape: (`batch_size`, `total_virtual_tokens`, `token_dim`)
    """
    def __init__(self, config):
        super().__init__()
        self.token_dim = config.token_dim
        self.input_size = self.token_dim
        self.output_size = self.token_dim
        self.hidden_size = config.encoder_hidden_size
        self.total_virtual_tokens = config.num_virtual_tokens * config.num_transformer_submodules
        self.encoder_type = config.encoder_reparameterization_type

        # embedding
        self.embedding = torch.nn.Embedding(self.total_virtual_tokens, self.token_dim)
        if not config.inference_mode:
            if self.encoder_type == PromptEncoderReparameterizationType.LSTM:
                lstm_dropout = config.encoder_dropout
                num_layers = config.encoder_num_layers
                # LSTM
                self.lstm_head = torch.nn.LSTM(
                    input_size=self.input_size,
                    hidden_size=self.hidden_size,
                    num_layers=num_layers,   # 深层LSTM
                    dropout=lstm_dropout,   
                    bidirectional=True,      # 双向
                    batch_first=True,        # batch_size在第一维
                )

                self.mlp_head = torch.nn.Sequential(
                    torch.nn.Linear(self.hidden_size * 2, self.hidden_size * 2),
                    torch.nn.ReLU(),
                    torch.nn.Linear(self.hidden_size * 2, self.output_size),
                )

            elif self.encoder_type == PromptEncoderReparameterizationType.MLP:
                encoder_num_layers_default = PromptEncoderConfig.encoder_num_layers
                layers = [
                    torch.nn.Linear(self.input_size, self.hidden_size),
                    torch.nn.ReLU(),
                    torch.nn.Linear(self.hidden_size, self.hidden_size),
                    torch.nn.ReLU(),
                    torch.nn.Linear(self.hidden_size, self.output_size),
                ]
                self.mlp_head = torch.nn.Sequential(*layers)

            else:
                raise ValueError("Prompt encoder type not recognized. Please use one of MLP (recommended) or LSTM.")

    def forward(self, indices):
        # 1、先进行embedding
        input_embeds = self.embedding(indices)
        # 2、embedding后,再进行编码
        if self.encoder_type == PromptEncoderReparameterizationType.LSTM:
            output_embeds = self.mlp_head(self.lstm_head(input_embeds)[0])
        elif self.encoder_type == PromptEncoderReparameterizationType.MLP:
            output_embeds = self.mlp_head(input_embeds)
        else:
            raise ValueError("Prompt encoder type not recognized. Please use one of MLP (recommended) or LSTM.")

        return output_embeds
  • peft\peft_model.py中PeftModelForCausalLM代码如下,通过配置文件的类型来判断PEFT方法到底是PrefixTuning/PTuningV2,还是PromptTuning/PTuningV1。
    • 如果是Prompt Tuning/P-TuningV1,则将虚拟token的embedding直接concat到原始输入序列的前面,送入base model模型进行推理。
    • 如果是Prefix Tuning/P-TuningV2,需要给每一个transformer block的key和value添加虚拟token的embedding。
        # peft\peft_model.py
    	if peft_config.peft_type == PeftType.PREFIX_TUNING:
            #  如果为PREFIX_TUNING,需要给每一个transformer block的key和value添加虚拟token的embedding
            ......
        else:
            # PromptTuning/PTuningV1 分支
            if inputs_embeds is None:
                # 计算prompt以外输入内容的embedding
                inputs_embeds = self.word_embeddings(input_ids)
            # concat prompt labels
            if labels is not None:
                prefix_labels = torch.full((batch_size, peft_config.num_virtual_tokens), -100).to(labels.device)
                kwargs["labels"] = torch.cat((prefix_labels, labels), dim=1)
            # prompt内容的embedding    
            prompts = self.get_prompt(batch_size=batch_size)
            prompts = prompts.to(inputs_embeds.dtype)
            # 将prompt embedding 和原始的embedding 一起送到base model进行推理计算
            inputs_embeds = torch.cat((prompts, inputs_embeds), dim=1)
            return self.base_model(inputs_embeds=inputs_embeds, **kwargs)

1.2.2 轻量微调bloom模型

我们只需要在加载原模型后、配置训练器前加peft的代码即可。

from peft import PromptEncoderConfig, TaskType, get_peft_model, PromptEncoderReparameterizationType

config = PromptEncoderConfig(task_type=TaskType.CAUSAL_LM, 
                             num_virtual_tokens=10,
                 encoder_reparameterization_type=PromptEncoderReparameterizationType.MLP,
                             encoder_dropout=0.1, 
                             encoder_num_layers=5, 
                             encoder_hidden_size=1024)


model = get_peft_model(model, config)

# 打印可训练参数信息
model.print_trainable_parameters()

trainable params: 3,159,040 || all params: 348,928,000 || trainable%: 0.9053558327219369
  • 配置训练器、模型训练及推理和参数高效微调PEFT(一)快速入门BitFit、Prompt Tuning、Prefix Tuning中2.1一样。
  • 显存消耗情况:
(base) root@autodl-container-adbc11ae52-f2ebff02:~# nvidia-smi 
Tue May 28 15:15:53 2024       
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 525.89.02    Driver Version: 525.89.02    CUDA Version: 12.0     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|                               |                      |               MIG M. |
|===============================+======================+======================|
|   0  NVIDIA GeForce ...  On   | 00000000:B1:00.0 Off |                  N/A |
| 33%   59C    P2   168W / 250W |   2870MiB / 11264MiB |     45%      Default |
|                               |                      |                  N/A |
+-------------------------------+----------------------+----------------------+
                                                                               
+-----------------------------------------------------------------------------+
| Processes:                                                                  |
|  GPU   GI   CI        PID   Type   Process name                  GPU Memory |
|        ID   ID                                                   Usage      |
|=============================================================================|
+-----------------------------------------------------------------------------+

2 P-Tuning V2

Prompt Tuning和P-Tuning等方法存在两个主要的问题:

  • 第一,缺乏模型参数规模和任务通用性。

    • 缺乏规模通用性:Prompt Tuning论文中表明当模型规模超过100亿个参数时,提示优化可以与全量微调相媲美。但是对于那些较小的模型(从100M到1B),提示优化和全量微调的表现有很大差异,这大大限制了提示优化的适用性。
    • 缺乏任务普遍性:尽管Prompt Tuning和P-tuning在一些 NLU 基准测试中表现出优势,但对硬序列标记任务(即序列标注)的有效性尚未得到验证。
  • 第二,缺少深度提示优化。我们知道在Prompt Tuning和P-tuning中,只被插入transformer第一层的输入embedding序列中,在接下来的transformer层中,插入Prompt的位置的embedding是由之前的transformer层计算出来的。

    • 由于序列长度的限制,可调参数的数量是有限的。
    • 输入embedding对模型预测只有相对间接的影响。

考虑到这些问题,作者提出了P-Tuning v2。

2.1 P-Tuning V2概述

  • 论文地址:P-Tuning v2: Prompt Tuning Can Be Comparable to Fine-tuning Universally Across Scales and Tasks(2110)
  • Prefix Tuning原理如下图所示:相较于Prompt-Tuning和P-tuning,Prefix-Tuning不再将Prompt加在输入的Embedding层,而是将其作为可学习的前缀,放置在Transformer模型中的每一层中,具体表现形式为past_key_values。

在这里插入图片描述

  • P-Tuning V2和Prefix Tuning的区别主要在于:移除重参数化的编码器,即没有MLP。我们之前分析Prefix Tuning源码时,也看到了在peft库中将P-Tuning V2和Prefix Tuning进行了集成:
# peft/tuners/prefix_tuning.py

# Based on https://github.com/THUDM/P-tuning-v2/blob/main/model/prefix_encoder.py
# with some refactor
class PrefixEncoder(torch.nn.Module):
    def __init__(self, config):
        super().__init__()
        self.prefix_projection = config.prefix_projection
        token_dim = config.token_dim
        num_layers = config.num_layers
        encoder_hidden_size = config.encoder_hidden_size
        num_virtual_tokens = config.num_virtual_tokens
        if self.prefix_projection and not config.inference_mode:
            # Use a two-layer MLP to encode the prefix
            # Prefix Tuning 进行重新参数化编码(通过MLP)
            self.embedding = torch.nn.Embedding(num_virtual_tokens, token_dim)
            self.transform = torch.nn.Sequential(
                torch.nn.Linear(token_dim, encoder_hidden_size),
                torch.nn.Tanh(),
                torch.nn.Linear(encoder_hidden_size, num_layers * 2 * token_dim),
            )
        else:
            # P-Tuning v2 
            self.embedding = torch.nn.Embedding(num_virtual_tokens, num_layers * 2 * token_dim)

    def forward(self, prefix: torch.Tensor):
        if self.prefix_projection:
            # Prefix Tuning
            # 先进行Embedding 此时shape为:(batch_size, num_virtual_tokens)
            # 再进行重新参数化编码,此时shape为:(batch_size, num_virtual_tokens, 2*layers*hidden)
            prefix_tokens = self.embedding(prefix)
            past_key_values = self.transform(prefix_tokens)
        else:
            # P-Tuning v2, 没有进行重参数化编码
            past_key_values = self.embedding(prefix)
        return past_key_values

P-Tuning V2具体做法基本同Prefix Tuning,可以看作是将文本生成的Prefix Tuning技术适配到NLU任务中,然后做了一些改进:

  • 1、移除重参数化的编码器。以前的方法利用重参数化功能来提高训练速度和鲁棒性(如:Prefix Tuning中的MLP、P-Tuning中的LSTM)。在作者发现重参数化的改进很小,尤其是对于较小的模型,同时还会影响模型的表现。
  • 2、针对不同任务采用不同的提示长度
    • 提示长度在提示优化方法的超参数搜索中起着核心作用。在实验中,作者发现不同的理解任务通常用不同的提示长度来实现其最佳性能。
    • 从图3中,可以观察到,针对简单任务:较短的Prompt(20)即可取得不错的效果。针对复杂任务:如阅读理解,需要更长的Prompt(100)。
    • 重参数化与最佳提示长度有密切关联。例如,在RTE、CoNLL04和BoolQ中,MLP重参数化比嵌入更早达到最佳结果。

在这里插入图片描述

  • 3、引入多任务学习(MPT-2)。先在多任务的Prompt上进行预训练,然后再适配下游任务。

2.2 论文部分实验

  • 对于简单的NLU任务,如SST-2(单句分类),Prompt Tuning和P-Tuning在较小的规模下没有显示出明显的劣势。但是当涉及到复杂的挑战时,如:自然语言推理(RTE)和多选题回答(BoolQ),它们的性能会非常差。
  • 相反,P-Tuning v2在较小规模的所有任务中都与微调的性能相匹配。并且,P-tuning v2在RTE中的表现明显优于微调,特别是在BERT中。

在这里插入图片描述

  • P-Tuning v2在一些困难的NLU任务中,作者选择了三个典型的序列标注任务(名称实体识别(NER)、抽取式问答(QA)和语义角色标签(SRL)),共八个数据集。作者发现P-Tuning v2在所有任务上都能与全量微调相媲美,下图只展示了NER任务的实验结果。

在这里插入图片描述

  • P-Tuning v2是一种在不同规模和任务中都可与微调相媲美的提示方法。P-Tuning v2对从330M到10B的模型显示出一致的改进,并在序列标注等困难的序列任务上以很大的幅度超过了Prompt Tuning和P-Tuning。

2.3 轻量微调bloom模型

我们只需要在加载原模型后、配置训练器前加peft的代码即可。

from peft import PrefixTuningConfig, get_peft_model, TaskType

# 和Prefix Tuning不同的是设置prefix_projection=False
config = PrefixTuningConfig(task_type=TaskType.CAUSAL_LM, num_virtual_tokens=10, prefix_projection=False)


model = get_peft_model(model, config)

# 打印可训练参数信息
model.print_trainable_parameters()

trainable params: 491,520 || all params: 346,260,480 || trainable%: 0.1419509382069822
  • 配置训练器、模型训练及推理和参数高效微调PEFT(一)快速入门BitFit、Prompt Tuning、Prefix Tuning中2.1一样。
  • 显存消耗情况:
(base) root@autodl-container-adbc11ae52-f2ebff02:~# nvidia-smi 
Tue May 28 15:18:39 2024       
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 525.89.02    Driver Version: 525.89.02    CUDA Version: 12.0     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|                               |                      |               MIG M. |
|===============================+======================+======================|
|   0  NVIDIA GeForce ...  On   | 00000000:B1:00.0 Off |                  N/A |
| 33%   56C    P2   189W / 250W |   2826MiB / 11264MiB |     45%      Default |
|                               |                      |                  N/A |
+-------------------------------+----------------------+----------------------+
                                                                               
+-----------------------------------------------------------------------------+
| Processes:                                                                  |
|  GPU   GI   CI        PID   Type   Process name                  GPU Memory |
|        ID   ID                                                   Usage      |
|=============================================================================|
+-----------------------------------------------------------------------------+

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

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

相关文章

用大模型理解爆火的KAN网络

五一假期的时候,KAN突然成为了热门话题。虽然最初我并没有计划弄懂它,但在老板的要求下,我还是探索了一下。 一、KAN是什么? Kolmogorov-Arnold 定理是数学领域的一个里程碑,它揭示了多元函数能够通过一组更简单的函…

希尔排序法

希尔排序为插入排序的优化,即将数组分组,将每一组进行插入排序,每一组排成有序后,最后整体就变有序了。 上面gap2,即5,14,18,27,68为一组;13,20&a…

小程序自动化辅助渗透脚本(2024)

简介 1.还在一个个反编译小程序吗? 2.还在自己一个个注入hook吗? 3.还在一个个查看找接口、查找泄露吗? 现在有自动化辅助渗透脚本了,自动化辅助反编译、自动化注入hook、自动化查看泄露 注:本工具仅用于学习交流&…

【Qt秘籍】[002]-开始你的Qt之旅-下载

一、Qt的开发工具有哪些? Qt的开发工具概述Qt支持多种开发工具,其中最常见的开发工具是 1.QtCreator 【易上手/有少量bug/适合新手】 2.VisualStudio 【功能强大/易出错/需要更多额外配置】 3.Eclipse 【清朝老兵IDE/不建议使用】 【注意&#xff1…

Java | Leetcode Java题解之第118题杨辉三角

题目&#xff1a; 题解&#xff1a; class Solution {public List<List<Integer>> generate(int numRows) {List<List<Integer>> ret new ArrayList<List<Integer>>();for (int i 0; i < numRows; i) {List<Integer> row new…

vxe-form-design 表单设计器的使用

vxe-form-design 在 vue3 中表单设计器的使用 查看官网 https://vxeui.com 安装 npm install vxe-pc-ui // ... import VxeUI from vxe-pc-ui import vxe-pc-ui/lib/style.css // ...// ... createApp(App).use(VxeUI).mount(#app) // ...使用 github vxe-form-design 用…

【MySQL事务(下)(重点)】

文章目录 再次理解MySQL事务一、MVCC机制数据库并发的场景有三种&#xff1a;3个记录隐藏列字段undo日志——由mysql维护的一段内存空间再次理解隔离性和隔离级别 Read View 理论部分RR 和 RC 的本质区别 再次理解MySQL事务 1.每个事务都有自己的事务ID&#xff0c;根据事务的…

蒙特卡洛法求解机械臂工作空间(以IRB4600型工业机械臂为例)

1. 概念 工作空间是衡量机器人工作能力的一个重要的运动学指标&#xff0c;蒙特卡洛法是一种随机模拟方法&#xff0c;用于在计算机上估计某些统计量&#xff0c;对于要估计的统计量&#xff0c;通过模拟大量的随机抽样&#xff0c;并计算这些样本的随机值来估算这个统计量的值…

释放 OSINT 的力量:在线调查综合指南

开源情报 (OSINT) 是从公开信息中提取有价值见解的艺术。无论您是网络安全专业人士、道德黑客还是情报分析师&#xff0c;OSINT 都能为您提供先进的技术&#xff0c;帮助您筛选海量的数字数据&#xff0c;发现隐藏的真相。 在本文中&#xff0c;我们将深入研究大量的OSINT 资源…

【LeetCode刷题】滑动窗口解决问题:串联所有单词的子串(困难)、最小覆盖子串(困难)

【LeetCode刷题】Day 10 题目1&#xff1a;30. 串联所有单词的子串&#xff08;困难&#xff09;思路分析&#xff1a;思路1&#xff1a;滑动窗口哈希map 题目2&#xff1a;LCR 017.最小覆盖子串思路分析思路1&#xff1a;滑动窗口哈希表 题目1&#xff1a;30. 串联所有单词的子…

【论文阅读|cryoET】DeepETPicker:使用弱监督深度学习的快速准确cryoET三维颗粒挑选算法

题目 DeepETPicker: Fast and accurate 3D particle picking for cryo-electron tomography using weakly supervised deep learning 发表期刊&#xff1a; Nature Communications 发表时间&#xff1a;2024.02 Accepted 作者&#xff1a;Guole Liu, Tongxin Niu 中科院自动化…

43-2 Linux入侵排查实验

环境准备: 老规则,我没有靶场就自己搭建了类似, 这里准备一台CentOS 7虚拟机作为受害者,然后使用CS制作木马并在受害者主机上线,具体过程可以看我之前写的一篇文章: 黑客必备利器:如何在系统上安装和使用 CobaltStrike(简称:CS)_cobalt strike-CSDN博客 最终的效果…

FPGA——eMMC验证

一.FPGA基础 1.FPGA烧录流程 (1) 加载流文件 —— bitfile (2) 烧录文件 —— cmm 二.MMC 1.基础知识 (1)jz4740、mmc、emmc、sd之间的关系&#xff1f; jz4740——处理器 mmc——存储卡标准 emmc——mmc基础上发展的高效存储解决方案 sd—— 三.eMMC和SD case验证 1.ca…

【一竞技DOTA2】RAMZES666替补参加裂变联赛

1、根据主办方文件,RAMZES666将继续作为Tundra战队替补参加裂变联赛。该比赛为欧洲线上赛,于5月27日-30日举行,总奖金8万美元。 除此之外,Nigma战队在上个月宣布四号位Matthew离队后,也选择启用老队员GH参赛。而在本月初让ah fu转回教练、携替补Thiolicor出战PGL瓦拉几亚的Secr…

浏览器提示网站不安全怎么办?有什么解决办法吗?

当你在浏览器中访问一个网站时&#xff0c;如果看到提示说该网站不安全&#xff0c;这通常是由于网站没有使用SSL证书或者SSL证书存在问题。SSL证书在这里扮演着非常关键的角色&#xff0c;下面我会详细解释它的作用以及如何解决这类不安全提示。 SSL证书的作用&#xff1a; 1…

JAVA基础----线程池

①什么是线程池&#xff1f; 线程池是对所有线程进行统一的管理和控制&#xff0c;从而提高系统的运行效率。当我们要使用线程的时候可以直接从线程池中拿&#xff0c;用完也不用自己去销毁&#xff0c;省去创建和销毁的时间&#xff0c;提升系统的响应时间。 ②线程池的七大核…

Apache、Nginx、IIS文件解析漏洞

目录 1、文件解析漏洞介绍 2、Apache相关的解析漏洞 &#xff08;1&#xff09;多后缀解析漏洞 &#xff08;2&#xff09;Apache配置问题 &#xff08;3&#xff09;换行符解析漏洞 &#xff08;4&#xff09;罕见后缀解析 3、Nginx相关的解析漏洞 &#xff08;1&…

【安装笔记-20240528-Linux-在 Vultr 云服务器上安装 OpenWRT】

安装笔记-系列文章目录 安装笔记-20240528-Linux-在 Vultr 云服务器上安装测试 OpenWRT 文章目录 安装笔记-系列文章目录安装笔记-20240528-Linux-在 Vultr 云服务器上安装测试 OpenWRT 前言一、软件介绍名称&#xff1a;OpenWRT主页官方介绍 二、安装步骤测试版本&#xff1a…

【SCAU操作系统】实验二页面置换算法的模拟实现及命中率对比python源代码及实验报告参考

一、课程设计目的 通过请求页式管理方式中页面置换算法的模拟设计&#xff0c;了解虚拟存储技术的特点&#xff0c;掌握请 求页式存储管理中的页面置换算法。 二、课程设计内容 模拟实现 OPT &#xff08;最佳置换&#xff09;、 FIFO 和 LRU 算法&#xff0c;并计算缺页…

Linux快速定位日志 排查bug技巧和常用命令

1. 快速根据关键字定位错误信息 grep 在 Linux 系统中&#xff0c;可以使用 grep 命令来查找日志文件中包含特定关键字的行。假设你的日志文件路径为 /var/log/myapp.log&#xff0c;你想要查找包含关键字 "abc" 的日志内容&#xff0c;可以按照以下步骤操作&#…