机器学习周报(9.23-9.29)

文章目录

  • 摘要
  • Abstract
  • 1 自监督学习(Self-Supervised Learning)
    • 1.1 BERT
      • 1.1.1 Masking Input
      • 1.1.2 Next Sentence Prediction
      • 1.1.3 BERT的使用方式
    • 1.2 Why does BERT work?
    • 1.3 Multi-lingual BERT
  • 2 pytorch中tensor相关函数学习使用
    • 2.1 张量拼接与拆分
      • 2.1.1 tensor.cat张量合并
        • 两个二维张量拼接
        • 两个三维张量拼接
      • 2.1.2 tensor.stack张量合并
      • 2.1.3 tensor.split张量分割
      • 2.1.4 tensor.chunk张量分割
    • 总结

摘要

主要学习了自监督学习的相关知识,了解了 BERT 是如何实现自监督学习以及 BERT 为什么能够有效地完成任务。通过 BERT 的四个例子来理解怎样使用 BERT 。最后了解了 Multi-lingual BERT 的基本知识。补充学习了pytorch中有关tensor的拼接与拆分

Abstract

I mainly learned the relevant knowledge of self-supervised learning, and understood how BERT realized self-supervised learning and why BERT could effectively complete tasks. Take a look at four examples of BERT to understand how to use BERT. Finally, I have understood the basic knowledge of Multi-lingual BERT. I also learned the splicing and splitting of tensor in pytorch

1 自监督学习(Self-Supervised Learning)

在这里插入图片描述

对于Supervised Learning(监督式学习),我们需要一组带有 label 的训练资料,当我们把 x 输入模型之后将输出的 y 和对应的 label 作对比来训练模型。
而Self-Supervised Learning(自监督学习)属于非监督式学习的一种,我们把训练资料 x 分为两部分,把其中一部分输入到模型中,再把另一部分作为 label 来训练这个模型。

1.1 BERT

BERT 模型是自监督学习的经典模型,BERT 是一个 Transformer 的编
码器,BERT 的架构与 Transformer 的编码器完全相同,里面有很多自注意力和残差连接、归一化等等. BERT 可以输入一行向量,输出另一行向量. 输出的长度与输入的长度相同

在这里插入图片描述

1.1.1 Masking Input

BERT 的输入是一段文字. 接下来需要随机掩码一些输入文字,被掩码的部分是随机决定的,有两种方法来实现掩码:

  1. 用特殊符号替换句子中的单词,使用“MASK”词元来表示特殊符号,可以将其看成一个新的汉字
  2. 用另一个字随机替换一个字. 本来是“度”字,可以随机选择另一个汉字来替换它

这两种方法都可以使用,使用哪种方法也是随机确定的

在这里插入图片描述
掩码后,向 BERT 输入了一个序列,BERT 的相应输出就是另一个序列,接下来,查看输入序列中掩码部分的对应输出,仍然在掩码部分输入汉字,它可能是“MASK”词元或随机单词,它仍然输出一个向量,对这个向量使用线性变换然后做 softmax 并输出一个分布. 输出是一个很长的向量,包含要处理的每个汉字. 每个字对应一个分数,它是通过 softmax 函数生成的分布.

我们知道被掩码字符是哪个字符,而 BERT 不知道. 因为把句子交给BERT 时,该字符被掩码了,所以 BERT 不知道该字符,但我们知道掩码字“深度”一词中的“度”. 因此,训练的目标是输出一个尽可能接近真实答案的字符,即“度”字符. 独热编码可以用来表示字符,并最小化输出和独热向量之间的交叉熵损失

1.1.2 Next Sentence Prediction

训练 BERT 时,除了掩码之外,还有另一种方法:下一句预测(next sentence prediction)

给定一个很长的序列,其中包括两个句子,中间有个 [SEP] 词元(表示两个句子分割),前面有一个 [CLS]词元

在这里插入图片描述

我们只取与 [CLS] 对应的输出,忽略其他输出,并将 [CLS]的输出乘以线性变换. 现在它做一个二元分类问题,它有两个可能的输出:是或否。这种方法称为Next Sentence Prediction

即需要预测第二句是否是第一句的后一句(这两个句子是不是相接的). 如果第二句确实是后续句子(这两个句子是相接的),就要训练 BERT 输出“是”. 当第二句不是后一句时(这两个句子不是相接的),BERT 需要输出“否”作为预测.

1.1.3 BERT的使用方式

在训练时,让BERT学习了两个任务:

  1. 把一些字符掩盖起来,让它做填空题,补充掩码的字符.
  2. 预测两个句子是否有顺序关系(两个句子是否应该接在一起)

通过这两个任务,BERT 学会了如何填空。在训练模型填空后,也可以用于其他任务

在这里插入图片描述

  • downstream task(下游任务)

这些任务不一定与填空有关,它可能是完全不同的东西. 尽管如此,BERT 仍然可以用于这些任务. 这些任务是真正使用 BERT 的任务,称为**下游任务(downstream task)**下游任务就是我们实际关心的任务. 但当 BERT 学习完成这些任务时,仍然需要一些标注的数据

在这里插入图片描述

给 BERT 一些有标注的数据,它可以学习各种任务,将 BERT 分化并用于各种任务称为微调(fine-tuning),让它可以做某种任务。

在微调之前产生此 BERT 的过程称为Pre-train(预训练), 所以产生 BERT 的过程就是自监督学习,也可以将其称为预训练。

case1

假设下游任务是输入一个序列并输出一个类别. 这是一个分类问题,输入是一个序列

例如:情感分析,给机器一个句子,并让它判断句子是正面的还是负面的

其中 BERT 需要先经过预训练来初始化参数,而 Linear部分仅需随机初始化。BERT 的部分输入非监督式学习,而在下游任务的环节需要一部分标注的资料,这属于监督式学习。因此,整个环节应该属于半监督式学习。

在这里插入图片描述

case2:

对于词性标注问题也一样,BERT 参数不是随机初始化,而是在Pre-train 阶段就找到一组比较好的初始化参数了。

在这里插入图片描述

case3:

在这里插入图片描述

NLI(Natural Language Inference,自然语言推理)是一项重要的自然语言处理(NLP)任务,它涉及到判断两个句子之间的逻辑关系。NLI任务的核心在于理解两个句子之间的逻辑联系,并根据这种联系做出合理的推断。具体来说,NLI任务通常包含两个句子:前提句(premise)和假设句(hypothesis),任务是确定假设句相对于前提句的逻辑关系。

在这里插入图片描述

将两个句子输入 BERT 产生一组新的向量,将 CLS 产生的向量丢到 Linear transform 就可以得到相应的类别了。其中,BERT 的参数也是预先训练好的。

case4:

基于提取的问答(extraction-based question answering):给机器读一篇文章,问它一个问题,它就会回答一个答案(但是这个答案必须出现在文章里面)

在这里插入图片描述

首先计算橙色向量和文档对应的输出向量的内积(inner product).由于有 3 个词元代表文章,因此它将输出 3 个向量. 计算这 3 个向量与橙色向量的内积可以得到 3 个值. 然后将它们传递给 softmax 函数,将得到另外 3 个值(这种内积与注意力非常相似,把橙色部分可以视为查询,把黄色部分视为键,这就是一种注意力)

在这里插入图片描述
注意:蓝色和橙色向量是随机初始化的,而 BERT 是由其预训练的权重
初始化的

1.2 Why does BERT work?

在这里插入图片描述

将文字序列通过 BERT 之后产生的向量蕴含着文字本身的含义。例如“果”和“草”、“鸟”和“鱼”由于意思比较相近,所以在向量空间中的分布相近。但是 BERT 会考虑上下文的因素,比如“吃苹果”中的“果”和“苹果手机”的“果”距离较远。

在这里插入图片描述

我们可以验证一下对于一个同样的字在两句不同的语句的向量相似度。

在这里插入图片描述

图中颜色越鲜艳代表相似度越高,可以看到前五句话互相之间相似度较高,而前五句话和后五句话相似度就比较低了。

从语言学的观点来看,一个词语的意思和它的上下文有关。
在这里插入图片描述
BERT 正是从它的上下文抽取资讯来预测缺失的向量。

1.3 Multi-lingual BERT

在这里插入图片描述
Multi-lingual BERT(mBERT)是BERT的一个多语言版本,旨在支持多种语言的自然语言处理任务。mBERT 在设计上与单语言的BERT非常相似,但其预训练数据集包含了104种不同语言的文本,这使得 mBERT 能够理解和生成多种语言的文本表示。

在这里插入图片描述
用英文的 QA 资料集训练,然后在中文上测试,正确率居然表现也还不错。将中文和英文一起训练后正确率甚至快接近人类的正确率了

为什么在英文的训练集里训练 BERT 之后在中文测试里依旧有效呢?

在这里插入图片描述
原因就是不同语言描述同一事物或者相似事物的 embedding 很接近。

在这里插入图片描述

在英文资料上 BERT 可以做英文的填空题,而在中文资料上 BERT 可以做中文的填空题。如果说两种不同的语言本质上没有区别,那 BERT 怎么会知道它应该要做中文还是英文的填空题?

在这里插入图片描述
我们将所有英文的平均 embedding 求出来,再将所有中文的平均 embedding 求出来,最后将两者相减得到图上这个蓝色向量。这个向量就代表了中文和英文之间的差距。我们将 “there is a cat” 输入 BERT 后得到的向量加上这个蓝色向量,最后很神奇的就可以得到“那有一猫”。

在这里插入图片描述

2 pytorch中tensor相关函数学习使用

  • range arange

arange:返回一个长度为: e n d − s t a r t s t e p \frac{end-start}{step} stependstart的一维张量,start默认为0,step默认为1

range:返回一个长度为: e n d − s t a r t s t e p + 1 \frac{end-start}{step}+1 stependstart+1的一维张量,start默认为0,step默认为1

# arange
a = torch.arange(end=5)
print(a)    # tensor([0, 1, 2, 3, 4])
print(a.dtype)   # torch.int64# range
b = torch.range(start=0, end=5)
print(b)    # tensor([0., 1., 2., 3., 4., 5.])
print(b.dtype)  # torch.float32c = torch.range(start=1, end=6)
print(c)    # tensor([1., 2., 3., 4., 5., 6.])
  • reshape
    改变张量的维度,修改的维度的乘积跟修改之前的维度乘积相同即可。a = torch.reshape(a, (-1,))将张量修改为一行
a = torch.rand([2, 3])
'''
tensor([[0.3855, 0.8812, 0.7528],[0.9095, 0.4733, 0.1893]])
'''
a = torch.reshape(a, [3, 2])
'''
tensor([[0.3855, 0.8812],[0.7528, 0.9095],[0.4733, 0.1893]])
'''
a = torch.reshape(a, (-1,))
# tensor([0.3855, 0.8812, 0.7528, 0.9095, 0.4733, 0.1893])

2.1 张量拼接与拆分

方法作用区别
cat合并保持原有维度的数量
stack合并原有维度数量加1
split分割按照长度去分割
chunk分割等分

2.1.1 tensor.cat张量合并

两个二维张量拼接

定义两个二维张量:

# 定义两个二维张量
a = torch.tensor([[1, 2, 3],[4, 5, 6]])b = torch.tensor([[7, 8, 9],[10, 11, 12]])print(a.shape)  # torch.Size([2, 3])
print(b.shape)  # torch.Size([2, 3])
  • dim=0维度(在第一个维度进行合并,二维张量中,第一个维度为行)
cat_0 = torch.cat((a, b), dim=0)
print(cat_0)
print(cat_0.shape)  # torch.Size([4, 3])

合并结果:

tensor([[ 1,  2,  3],[ 4,  5,  6],[ 7,  8,  9],[10, 11, 12]])
  • dim=1维度(在第二个维度进行合并,二维张量中,第二个维度为列)
cat_1 = torch.cat((a, b), dim=1)
print(cat_1)
print(cat_1.shape)  # torch.Size([2, 6])

合并结果:

tensor([[ 1,  2,  3,  7,  8,  9],[ 4,  5,  6, 10, 11, 12]])

注意:dim=-1 是对最后一个维度进行拼接,故二维张量中,dim=-1拼接和dim=1拼接相同

两个三维张量拼接

定义两个三维张量

# 定义两个三维张量
a = torch.tensor([[[1, 2, 3],[4, 5, 6],[7, 8, 9]],[[10, 11, 12],[13, 14, 15],[16, 17, 18]]])
b = torch.tensor([[[20, 21, 22],[23, 24, 25],[26, 27, 28]],[[29, 30, 31],[32, 33, 34],[35, 36, 37]]])
print(a.shape)  # torch.Size([2, 3, 3])
print(b.shape)  # torch.Size([2, 3, 3])
  • dim=0维度(在第一个维度进行合并)
cat_0 = torch.cat((a, b), dim=0)
print(cat_0)
print(cat_0.shape)  # torch.Size([4, 3, 3])

合并结果为:

tensor([[[ 1,  2,  3],[ 4,  5,  6],[ 7,  8,  9]],[[10, 11, 12],[13, 14, 15],[16, 17, 18]],[[20, 21, 22],[23, 24, 25],[26, 27, 28]],[[29, 30, 31],[32, 33, 34],[35, 36, 37]]])
  • dim=1维度(在第二个维度进行合并,三维张量中,第二个维度为行)
cat_1 = torch.cat((a, b), dim=1)
print(cat_1)
print(cat_1.shape)  # torch.Size([2, 6, 3])

合并结果:

tensor([[[ 1,  2,  3],[ 4,  5,  6],[ 7,  8,  9],[20, 21, 22],[23, 24, 25],[26, 27, 28]],[[10, 11, 12],[13, 14, 15],[16, 17, 18],[29, 30, 31],[32, 33, 34],[35, 36, 37]]])
  • dim=2维度(在第三个维度进行合并,三维张量中,第三个维度为列)
cat_2 = torch.cat((a, b), dim=2)
print(cat_2)
print(cat_2.shape)  # torch.Size([2, 3, 6])

合并结果:

tensor([[[ 1,  2,  3, 20, 21, 22],[ 4,  5,  6, 23, 24, 25],[ 7,  8,  9, 26, 27, 28]],[[10, 11, 12, 29, 30, 31],[13, 14, 15, 32, 33, 34],[16, 17, 18, 35, 36, 37]]])

注意:dim=-1 是对最后一个维度进行拼接,故三维张量中,dim=-1拼接和dim=2拼接相同

2.1.2 tensor.stack张量合并

定义两个二维张量

# stack
a = torch.tensor([[1, 2, 3],[4, 5, 6],[7, 8, 9]])b = torch.tensor([[10, 11, 12],[13, 14, 15],[16, 17, 18]])
print(a.shape)  # torch.Size([3, 3])
print(b.shape)  # torch.Size([3, 3])

对于stack和cat关于关键字dim的理解:

  • cat方法中可以理解为原tensor的维度,dim=0,就是沿着原来的0轴进行拼接,dim=1,就是沿着原来的1轴进行拼接。
  • stack方法中的dim则是指向新增维度的位置,dim=0,就是在新形成的tensor的维度的第0个位置新插入维度

dim=0,在第一个维度上,新增加一个维度

stack_0 = torch.stack((a, b), dim=0)
print(stack_0)
print(stack_0.shape)    # torch.Size([2, 3, 3])
tensor([[[ 1,  2,  3],[ 4,  5,  6],[ 7,  8,  9]],[[10, 11, 12],[13, 14, 15],[16, 17, 18]]])

dim=1,在第二个维度上,新增加一个维度

stack_1 = torch.stack((a, b), dim=1)
print(stack_1)
print(stack_1.shape)   # torch.Size([3, 2, 3])
tensor([[[ 1,  2,  3],[10, 11, 12]],[[ 4,  5,  6],[13, 14, 15]],[[ 7,  8,  9],[16, 17, 18]]])

dim=2,在第三个维度上,新增加一个维度

stack_2 = torch.stack((a, b), dim=2)
print(stack_2)
print(stack_2.shape)   # torch.Size([3, 3, 2])
tensor([[[ 1, 10],[ 2, 11],[ 3, 12]],[[ 4, 13],[ 5, 14],[ 6, 15]],[[ 7, 16],[ 8, 17],[ 9, 18]]])
torch.Size([3, 3, 2])

2.1.3 tensor.split张量分割

split 可以指定将张量分成几份,并且指定每一份张量的长度
同理,dim=0为对第一维度进行分割,dim=1为对第二维度进行分割

a = torch.arange(start=0, end=10).reshape([5, 2])
# print(a)
'''
tensor([[0, 1],[2, 3],[4, 5],[6, 7],[8, 9]])
'''
  • split_size_or_sections参数传入一个整数:将张量分割成长度为该整数长度,无法整除,最后一个取余
split_00, split_01 = torch.split(a, 3, dim=0)
print(split_00)
print(split_01)
print(split_00.shape)   # torch.Size([3, 2])
print(split_01.shape)   # torch.Size([2, 2])
tensor([[0, 1],[2, 3],[4, 5]])tensor([[6, 7],[8, 9]])
  • split_size_or_sections参数传入一个数组:张量分割个数为数组长度,数组中数字代表分割成每个张量的长度
s1, s2, s3 = torch.split(a, [1, 2, 2], dim=0)
print(s1)
print(s2)
print(s3)
print(s1.shape) # torch.Size([1, 2])
print(s2.shape) # torch.Size([2, 2])
print(s3.shape) # torch.Size([2, 2])
tensor([[0, 1]])tensor([[2, 3],[4, 5]])tensor([[6, 7],[8, 9]])

2.1.4 tensor.chunk张量分割

chunk可以理解为均等分的split,但是当维度长度不能被等分份数整除时,虽然不会报错,但可能结果与预期的不一样,建议只在可以被整除的情况下运用

将张量拆分成指定数量的块

a = torch.arange(start=0, end=10).reshape([5, 2])
print(a)
'''
tensor([[0, 1],[2, 3],[4, 5],[6, 7],[8, 9]])
'''
  • dim=0,在第一个维度进行分割
chunk_00, chunk_01 = torch.chunk(a, chunks=2, dim=0)
print(chunk_00)
print(chunk_01)
print(chunk_00.shape)   # torch.Size([3, 2])
print(chunk_01.shape)   # torch.Size([2, 2])

chunk_00:

tensor([[0, 1],[2, 3],[4, 5]])

chunk_01:

tensor([[6, 7],[8, 9]])
  • dim=1,在第二个维度进行分割
chunk_10, chunk_11 = torch.chunk(a, chunks=2, dim=1)
print(chunk_10)
print(chunk_11)
print(chunk_10.shape)   # torch.Size([5, 1])
print(chunk_11.shape)   # torch.Size([5, 1])

chunk_10:

tensor([[0],[2],[4],[6],[8]])

chunk_11:

tensor([[1],[3],[5],[7],[9]])

总结

BERT(Bidirectional Encoder Representations from Transformers)是一种基于Transformer架构的语言理解模型,它通过双向上下文来捕捉句子中的语义关系。BERT的最终目标是提升自然语言处理任务的效果,如问答系统和文本分类。通过在大规模文本上预训练并进行微调,BERT能够有效理解复杂的语言特征,推动了NLP领域的重大进展。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

4G模组SIM卡电路很简单,但也要注意这些坑

上次水SIM卡相关的文章,还是上一次; 上一篇文章里吹牛说,跟SIM卡相关的问题还有很多,目的是为下一篇文章埋下伏笔;伏笔埋是埋下了,但如果债老是不还,心里的石头就总悬着,搞不好老板…

MAC的几个常见的快捷方式

1.mac 查看图片好的方式 默认查看图片的方式无法直接切换上一张下一张 解决方法: 1.(最好的方法)选中图片直接按空格,进入快速预览图片 2.就是全部选中然后打开,但是说实话有点奇怪,而且很占内存 3.直接显示…

Linux 信号捕捉

我们知道信号的处理不是即时的,进程在合适的时机才会处理信号,而这个时机就比如从内核态返回用户态。 1. 用户态与内核态 在操作系统中,用户态(User Mode)和内核态(Kernel Mode)是两种不同的C…

安卓主板_MTK4G/5G音视频记录仪整机及方案定制

音视频记录仪方案,采用联发科MT6877平台八核2* A78 6* A55主频高达2.4GHz, 具有高能低耗特性,搭载Android 12.0智能操作系统,可选4GB32GB/6GB128GB内存,运行流畅。主板集成NFC、双摄像头、防抖以及多种无线数据连接,支…

如何在 Kubernetes 上部署和配置开源数据集成平台 Airbyte?

在 Kubernetes 上部署和配置 Airbyte 是一个复杂但非常有价值的过程,特别是对于需要强大数据集成和数据处理能力的企业或团队。Airbyte 是一个开源的数据集成平台,允许用户从各种来源提取数据并加载到目标存储中。其强大的插件系统支持多种数据源与目标&…

新能源汽车储充机器人:能源高效与智能调度

新能源汽车储充机器人:开启能源高效利用与智能调度的未来之门 随着全球能源危机的日益加剧和环境污染问题的不断恶化,新能源汽车成为了未来交通领域的重要发展方向。然而,新能源汽车的普及不仅需要解决电池技术的瓶颈,还需要构建一…

labview更换操作系统后打开原VI闪退

labview更换操作系统后打开原VI闪退 问题描述: Windows11由家庭版更换为专业版后,重新安装labview2021,打开原来的项目,项目管理器可以正常打开,但是打开VI却闪退,并报错如下 出现这种原因主要是labview在…

通信工程学习:什么是LAN局域网、MAN城域网、WAN广域网

LAN局域网、MAN城域网、WAN广域网 LAN(Local Area Network,局域网)、MAN(Metropolitan Area Network,城域网)和WAN(Wide Area Network,广域网)是计算机网络中根据覆盖范围…

vue组合式api

一、ref(基本类型数据,对象类型数据) 1.作用:定义响应式变量 2.语法:let xxx ref(初始值) 3.返回值:一个RefImpl的实例对象,简称ref对象,ref对象的value属性是响应式的。 4.注意…

【MySQL】视图、用户和权限管理

目录 视图创建视图数据修改影响删除视图视图优点 用户和权限管理查看当前的数据库拥有用户信息创建用户修改密码删除用户权限授权回收权限 视图 视图就是相当于创建一个表,将查询到的结果集给存储起来。像使用复杂的多表查询查询到的结果集就不可以对结果集操作。而…

2024/9/29周报

文章目录 摘要Abstract污水处理工艺流程整体介绍粗格栅细格栅曝气沉砂池提升泵房峰谷平策略 初沉池(一级处理)工作原理运行管理 氧化沟生化池(二级处理)二沉池工作原理运行参数 高效沉淀池功能与特点工作原理 深度处理&#xff08…

Coursera_ Algorithms I 学习笔记:Module_3_Analysis_of_Algorithm_Introduction

Coursera_ Algorithms I 学习笔记:Module_3_Analysis_of_Algorithm_Introduction scientific method applied to analysis of algorithms data analysis log-log plot doubling hypothesis experimental alogrithmics System independent effectsSystem dependen…

Electron 主进程与渲染进程、预加载preload.js

在 Electron 中,主要控制两类进程: 主进程 、 渲染进程 。 Electron 应⽤的结构如下图: 如果需要更深入的了解electron进程,可以访问官网 流程模型 文档。 主进程 每个 Electron 应用都有一个单一的主进程,作为应用…

ubuntu20.04系统下,c++图形库Matplot++配置

linux下安装c图形库Matplot,使得c可以可视化编程;安装Matplot之前,需要先安装一个gnuplot,因为Matplot是依赖于此库 gnuplot下载链接: http://www.gnuplot.info/ 一、gnuplot下载与安装(可以跳过,下面源码…

业务调度 -- OTN集群

传输网络Mesh化客观上导致了单节点的业务维度增多以及调度需求增大,通过组建OTN集群可实现业务跨子架调度,容量按需扩展,高效疏导网络节点流量。 什么是OTN集群 OTN集群是OTN设备的一种组合应用形式,多个OTN子架通过集群交叉板互…

启动hadoop集群出现there is no HDFS_NAMENODE_USER defined.Aborting operation

解决方案 在hadoop-env.sh中添加 export HDFS_DATANODE_USERroot export HDFS_NAMENODE_USERroot export HDFS_SECONDARYNAMENODE_USERroot export YARN_RESOURCEMANAGER_USERroot export YARN_NODEMANAGER_USERroot 再次运行即可。

Android 安卓内存安全漏洞数量大幅下降的原因

谷歌决定使用内存安全的编程语言 Rust 向 Android 代码库中写入新代码,尽管旧代码(用 C/C 编写)没有被重写,但内存安全漏洞却大幅减少。 Android 代码库中每年发现的内存安全漏洞数量(来源:谷歌&#xff09…

Python办公自动化案例:实现XMind文件转换成Excel文件

案例:实现XMind文件转换成Excel文件 将XMind文件转换为Excel文件的过程可以通过几个步骤来实现,主要涉及到读取XMind文件,解析其内容,然后创建一个Excel文件并将解析的内容写入。以下是一个简化的Python脚本,展示了如何使用xmindparser库来解析XMind文件,并使用pandas库…

初识Linux · 进程终止

目录 前言: 进程终止在干什么 进程终止的3种情况 进程如何终止 前言: 由上文的地址空间的学习,我们已经知道了进程不是单纯的等于PCB 自己的代码和数据,进程实际上是等于PCB mm_struct(地址空间) 页表 自己的代码和数据。…

PCL 法线空间采样

目录 一、概述 1.1原理 1.2实现步骤 1.3应用场景 二、代码实现 2.1关键函数 2.1.1 法线计算 2.1.2 基于法线进行采样 2.1.3 可视化原始点云和采样后的点云 2.2完整代码 三、实现效果 PCL点云算法汇总及实战案例汇总的目录地址链接: PCL点云算法与项目实…