读书笔记:多Transformer的双向编码器表示法(Bert)-1

多Transformer的双向编码器表示法

Bidirectional Encoder Representations from Transformers,即Bert;

在这里插入图片描述

本笔记主要是对谷歌Bert架构的入门学习:

  • 介绍Transformer架构,理解编码器和解码器的工作原理;
  • 掌握Bert模型架构的各个部分,了解如何进行模型的预训练、模型微调(将预训练的结果用于下游任务);
  • 学习Bert的不同变体、基于知识蒸馏的变体;
  • 一些其他模型架构;
  • 用于获取句子特征的Sentence-Bert模型以及一些用于特定领域的Bert模型(医学or生物学);
  • VideoBert模型;

目标是熟练掌握Bert及其变体来执行实际的自然语言处理任务;利用Bert模型超强的理解能力来简化自然语言处理任务;

章节目录

  • 第1章 Transformer概览
  • 第2章 了解Bert模型(掩码语言模型构建和下句预测)
  • 第3章 Bert实战
  • 第4章 Bert变体:ALBERT、RoBERTa、ELECTRA和SpanBERT
  • 第5章 Bert变体:基于知识蒸馏
  • 第6章 用于文本摘要任务的BERTSUM模型
  • 第7章 将Bert模型应用于其他语言
  • 第8章 Sentence-Bert模型和特定领域的Bert模型
  • 第9章 VideoBERT模型和BART模型

要求环境 Python3

第一部分 开始使用BERT

  • 第1章 Transformer概览
  • 第2章 了解Bert模型(掩码语言模型构建和下句预测)
  • 第3章 Bert实战

第1章 Transformer概览

自注意力机制

Transformer完全依赖于注意力机制,并摒弃了循环;使用了一种特殊的注意力机制,称为自注意力(self-attention)

实例:文本翻译(从英文翻译为法文)

  • 向编码器输入一句话(原句)
  • 让其学习到这句话的特征1;
  • 在将特征作为输入传输给解码器;
  • 最后通过解码器生成输出句(目标句);

N个编码器:

Transformer中的编码器不止一个,而是由一组N个编码器串联而成,一个编码器的输出作为下一个编码器的输入;

原句的特征会由最后一个编码器输出,编码器的作用就是提取原句中的特征;

Transformer原论文中“Attention is all your need”中,作者使用的N=6;

关于Transformer的学习可以参考之前总结的blog:

  • 《Transformer应用实践(学习篇)》
  • 《Transformer应用实践(补充)》

每个编码器的组成:

I am good -> 【多头注意力层 -> 前馈网络层 】-> …

每一个编码器的构造都是相同的,并且包含两个部分:

  • 多头注意力层
  • 前馈网络层

首先我们要了解“自注意力机制”:

以一句话为例:“A dog ate the food beacause it was hungry”,计算机模型要理解it的意思是dog还是food,自注意力机制有助解决该问题;

模型会一次计算每个单词的特征值,当计算每个词的特征值时,模型都需要遍历每个词与句子中其他词的关系;模型可以通过词与词之间的关系来更好的理解当前词的意思;

  • it的特征值 由它本身与句子中其他词的关系计算所得;
  • 关系越紧密,相应的注意力表示权重也就也大;

我们以一个简单的句子“I am good”为例:

  • 首先,需要将词转化为其他对应的词嵌入向量;需要注意的是,嵌入只是的特征向量,这个特征向量也是需要通过训练获得的;
  • 这个句子的词嵌入向量,可以表示为矩阵X = [x1, x2, x3];矩阵X的维度是[句子的长度 x 词嵌入向量维度],可以是512;
  • 现在,通过X创建3个新的矩阵:
    • 查询query矩阵Q:相当于问题提示
    • 键key矩阵K:类似问题的标准答案
    • 值value矩阵V:相当于我们期待的答案

关于三个新的矩阵QKV我们来具体看下:

  • 要创建这三个矩阵,需要先创建另外三个权重矩阵,分别为WQ/WK/W^V,用矩阵X分别乘以权重矩阵,就会得到Q、K、V三个矩阵;
  • 值得注意的是:三个权重矩阵的初始值是随机的,其最优值需要通过训练获得;
  • 这些权重矩阵的值越优,通过计算所得的查询矩阵、键矩阵、值矩阵也会越精确;

Q、K、V三个矩阵的行数与X一致,它们的每一行分别表示一个单词的q、k、v向量;向量的维度由参与计算的权重矩阵决定,可以是64;

那么,为什么要使用Q、K、V三个矩阵?如何才能用自注意力模型?我民额继续;

理解注意力机制:

已经计算得到Q、K、V矩阵,是要应用于注意力机制的;我们知道,要计算一个词的特征值,自注意力机制会使该词与给定句子中所有词联系起来;了解一个词与句子中所有词相关程度有助于更精确地计算特征值;

自注意力机制的4个步骤:

  • 1.计算Q与K^T的点积:
    • Q和K的shape一致,KT表示K矩阵的转置;Q的每一行代表一个词的查询向量q,KT的每一列表示相应词的键向量k,那么点积的结果是一个 词数x词数的矩阵,它的每一行计算的是 q1和k1、k2、k3的点积;
    • 通过计算两个向量的点积可以知道它们之间的相似度;这样通过计算q1和k1、k2、k3的点积,就可以了解单词“I”与句子“I am good”中所有单词的相似度,显然q1与k1的点积值最大,因为“I”这个词与自己的关系要比与其他词的关系更紧密;
    • 综上,计算Q和K^T的点积,得到了句子中每个词与所有其他词的相似度分数矩阵,即Q·K^T
  • 2.将Q·K^T 矩阵除以键向量维度的平方根:
    • 这样做的目的,主要是为了获得稳定的梯度;
    • 如果用dk 表示键向量维度(这里使用64),那么它的平方根就是8;
  • 3.使用softmax函数对目前所得相似度分数进行归一化处理:
    • 应用softmax函数可以将数值分布在0~1的范围内,且每一行(向量)的所有数之和等于1(即百分之百);
    • 然后得到的矩阵,成为“分数矩阵”,通过这些分数,可以了解到句子中每个词与所有词的相关程度,softmax(Q·K^T/√dk)
  • 4.计算注意力矩阵Z:
    • 注意力矩阵要包含的是句子中每个单词的注意力值,通过将分数矩阵乘以值矩阵V得到;
    • 注意力矩阵Z就是值分量(WordNum x 64)与分数(WordNum x WordNum)加权之后求和的结果,即“分数加权的值向量之和”,Z = softmax(Q·K^T/√dk)V (WordNum x 1);
import numpy as np
test_a = np.array([[1,2,3],[4,5,6],[4,5,6]])
test_b = np.array([[1,4,5,6],[2,7,8,9],[3,10,11,12]])
print(test_a.shape,test_b.shape)
# 点积计算
np.matmul(test_a, test_b)
(3, 3) (3, 4)array([[ 14,  48,  54,  60],[ 32, 111, 126, 141],[ 32, 111, 126, 141]])
# 求和
np.matmul(test_a, test_b).sum(axis=1)
array([176, 410, 410])

单词“I”的自注意力值:假设“I”的分数向量是[0.9, 0.07, 0.03],那么其自注意力值就包含了90%的值向量v1(I)、7%的值向量v2(am)、3%的值向量v3(good);

再看之前的例子,“A dog ate the food beacause it was hungry”,计算机模型要理解it的意思是dog还是food,可以计算it这个词的自注意力值,它对dog词的值分量的权重会更大;

这也说明了:通过自注意力机制,我们可以了解一个词与句子中所有词的相关程度;

注意力矩阵Z由句子中所有单词的自注意力值组成,公式为Z = softmax(Q·K^T/√dk)V

自注意力机制也被称为“缩放点积注意力机制”;

多头注意力层:

  • 指我们使用多个注意力头,而不只是一个,使用的计算注意力矩阵方法,同求Z;
  • 以之前it指代的例子来说,它实际上是由其他词(这里是dog)的值向量控制(假设权重是100%),由于这个词的含义是模糊的,此时这种控制关系是有用的,但为了确保结果准确,不能依赖单一的注意力矩阵,应该设计多个,并将其结果串联起来;

使用多头注意力的逻辑为:使用多个注意力矩阵,可以提高注意力矩阵的准确性;

我们知道:为了计算注意力矩阵,需要创建三个新的矩阵QKV,为此还要引入三个新的权重矩阵;要计算多个注意力矩阵,就需要这样的多组数据;

假设我们有8个注意力矩阵,Z1到Z8,将所有的注意力头(就是注意力矩阵)串联起来,并将结果乘以一个新的权重矩阵W0,从而得到最终的注意力矩阵;

Multi-head attention = Concatenate(Z1,Z2...,Z8) W0

位置编码

位置编码:(position encoding)

指词在句子中的位置编码;仍以“I am good”为例,在循环神经网络RNN中,句子是逐字送入学习网络,最终完全理解整个句子;但在Transformer网络则是将句子中所有词并行输入到神经网络(并行有助于缩短训练时间,同时有利于学习长期依赖);

既然是并行输入,那么就无法保留词序,而词序有很重要,因此也要为Transformer输入一些关于词序的信息;

对于给定的句子:

  • 首先计算每个单词在句子中的嵌入值,词嵌入维度可以表示为dmodel,那么输入矩阵的维度就是[句子长度 x 嵌入维度],如3 x 512;
  • 如果把输入矩阵直接传给Transformer,模型就无法理解词序,因此需要给输入矩阵添加一些表明词序的信息,以便神经网络可以理解句子含义,这里要用到的技术就是“位置编码”技术;

位置编码矩阵P,其shape与X相同,只需将P添加到X中,再输入神经网络,就可以让输入矩阵既包含词的嵌入,也包含词在句子中的位置信息,X = X + P

一种计算位置编码矩阵P的方式——“使用正弦函数来计算位置编码”

  • pos表示词在句子中的位置,i表示在输入矩阵中的位置;
  • 当i是偶数时,使用sin函数,i为奇数时,使用cos函数(示意图中10000^0,表示10000的0次幂);
  • I的pos=0,am的pos=1,。。。
  • 最后将输入矩阵X与计算所得位置编码矩阵P进行逐元素相加即可输入到编码器模块;

在这里插入图片描述

  • I am good
  • 词嵌入矩阵 + 位置编码矩阵
  • 输入编码器,提取特征值

而一个编码器模块是由 多头注意力层 和前馈网络层 两部分组成,而此前我们已经了解了多头注意力层,接下来看下前馈网络层;

理解编码器

前馈网络层:

在编码器模块中,前馈网络层 接在 多头注意力层后;它由两个有ReLU激活函数的全连接层组成,前馈网络的参数在句子的不同位置是相同的,但在不同的编码器模块上是不同的;

编码器的“叠加和归一组件”:

  • 它同时连接一个子层的输入和输出,示意如下:
输入矩阵 编码器模块编码器模块编码器模块编码器模块编码器模块
输入多头注意力层→叠加和归一组件前馈网络层→叠加和归一组件
   
 
  • 叠加和归一化组件实际上包含了一个残差连接与层的归一化;层的归一化可以防止每层的值剧烈变化,从而提高模型训练速度;

现在回顾下编码器及前后的部分:

  • 输入值的嵌入:将输入转换为嵌入矩阵(即输入矩阵);
  • 位置编码:将位置编码嵌入输入矩阵;
  • 编码器1 … 编码器N:使用输入矩阵作为编码器输入;
  • 编码器接受输入,在内部:
    • 首先将其送入多头注意力层,该子层运算后输出注意力矩阵;
    • 将注意力矩阵输入到下一子层,即前馈网络层,输出特征值;
  • 后续编码器的输入是前一编码器的输出;

N个叠加的编码器的输出特征值记为R,再把R作为输入传给解码器,解码器将基于这个输入生成目标句;

理解解码器

I am good => 通过编码器学习原句,并计算特征值 => 解码器将特征值作为输入,生成目标句”我很好“;

类似编码器叠加N个,解码器也可以有N个叠加,一个解码器的输入会作为输入传给下一个解码器;值得注意的是:编码器输出的特征值,将作为输入传给所有解码器,因此一个解码器有两个输入,一个是来自前一解码器的输出,另一个是编码器输出的特征值;

生成目标句的过程:

  • 使用t表示时间步,当t=1时,解码器输入<sos>表示句子开始,生成目标句的第一个词”我“;
  • t=2时,解码器使用当前的输入和上一步(t-1)生成的单词,预测句子中的下一个单词,即将<sos>和”我“作为输入,并试图生成目标句中的下一个词;
  • 在每一步中,解码器都将上一步新生成的单词与输入的词结合起来,并预测下一个单词;
  • 在最后一步t=4时,解码器的输入是<sos>、我、很、好作为输入,试图生成下一个词,如果生成的标记为<eos>则表示句子结束;就意味着解码器已经完成了对目标句的生成;

对于解码器的输入,实际同样需要将其转换为嵌入矩阵,为其添加位置编码

解码器模块:

 解码器模块解码器模块解码器模块 
带掩码的多头注意力层→多头注意力层→前馈网络层

内部包含三个子层:

  • 带掩码的多头注意力层
  • 多头注意力层
  • 前馈网络层

相比编码器模块,多了带掩码的多头注意力层;

带掩码的多头注意力层:

  • 以翻译任务为例,参与训练的样本需要包含两部分,即原句和目标句;
  • 解码器可以直接将整个目标句稍作修改作为输入,将<sos>标记添加到目标句的开头,并在每一步将下一个预测词与输入结合起来,以预测目标句;

过程举例说明如下:

  • <sos>我很好输入解码器(实际输入是添加了位置编码的嵌入矩阵X),预测输出为我很好<eos>
  • 解码器中的第一层 带掩码的多头注意力层,与编码器中的多头注意力层有一点不同:
    • 为了运行自注意力机制,我们需要创建三个新矩阵Q K V,由于是多头,因此Q K V一共创建h组;每组中的Q K V可通过X分别乘以权重矩阵W^Q W^K W^V而得;
    • 而自注意力机制会将一个单词与句子中的所有单词联系起来,从而提取每个词的更多信息,但是,在测试期间,解码器只将上一步生成的词作为输入
    • 如t=2时,解码器的输入应只有[<sos>, "我"],并没有其他词;我也也需要实现这样的方式来训练模型:模型的注意力机制应该只与该词之前的单词有关;
    • 要做到这一点,可以掩盖后边所有还没有被模型预测的词,如当预测<sos>相邻的词,模型应只看见<sos>,那么就应该掩盖<sos>后边的词;
<sos>    掩码    掩码    掩码    
<sos>    我      掩码    掩码  
<sos>    我      很      掩码
<sos>    我      很      好

这样的掩码有助于自注意力机制只注意模型在测试期间可以使用的词;

我们知道:

  • 计算注意力矩阵的第一步是计算 查询矩阵Q与键矩阵转置的点积,第二步除以键向量维度的平方根以缩放,第三步应用softmax函数,将分值归一化;
  • 我们需要在应用softmax前,完成对数值的掩码转换;可以使用负无穷大来掩盖,测试代码如下;
  • 最后将softmax函数的结果与V相乘,得到注意力矩阵Z,h个注意力矩阵串联,结果乘以新的权重矩阵W,即可得到最终的注意力矩阵M;
import numpy as np
test_a = np.array([[1,2,3],[4,5,6],[4,5,6]], dtype=np.float32)
matrix = np.triu(np.ones(test_a.shape) * -np.inf, 1)  
test_a = test_a + matrix
test_a 
array([[  1., -inf, -inf],[  4.,   5., -inf],[  4.,   5.,   6.]])
def softmax(x):e_x = np.exp(x - np.max(x))return e_x / e_x.sum(axis=0)# 使用-inf掩盖的向量,在计算softmax时,不会分摊权重
test_a[0],softmax(test_a[0])
(array([  1., -inf, -inf]), array([1., 0., 0.]))

带掩码的多头注意力层输出的注意力矩阵M,送到解码器的下一个子层,这是一个多头注意力层;

多头注意力层:

我们之前提到过:编码器输出的特征值,将作为输入传给所有解码器,更准确的描述是:将作为输入传给所有解码器的多头注意力子层;即解码器中的多头注意力层有两个输入:一个来自带掩码的多头注意力层,另一个是编码器输出的特征值;

由于涉及编码器与解码器的交互,解码器的这一子层也被称为编码器-解码器注意力层

我们用R来表示编码器输出的特征值(每个词都对应一个特征向量,因此这里的R实际是一个矩阵),用M表示由带掩码的多头注意力层输出的注意力矩阵;我们知道多头注意力机制第1步就是创建Q K V三个矩阵(通过将输入矩阵乘以权重矩阵),但是R和M两个输入,究竟用谁?

答案是:我们使用M作为输入矩阵来创建查询矩阵Q,使用R作为输入矩阵创建K和V矩阵;

  • 这里查询矩阵Q是从M求得,所以本质上包含了目标句的特征;
  • 键矩阵和值矩阵用R计算,则包含了原句的特征;

细节的:

  • Q·K^T:其第一行是查询向量q1(<sos>)与所有键向量k1(I)、k2(am)、k3(good)的点积,因此第1行表示目标词<sos>与原句中所有词的相似度;最终得到的所有行对应 查询矩阵(目标句特征)与键矩阵(原句特征)的相似度;
  • 经过维度平方根的缩放,和softmax函数,得到分数矩阵,再乘以值矩阵V,即注意力矩阵Z,目标句的注意力矩阵Zi是通过分数加权的值向量之和计算的(每一个目标句词都对应了一个注意力向量),实际的可能是这样:Z2的注意力向量包含了0.98个值向量v1(I)、0.02个值向量v2(am)、0.00的值向量v3(good),这个结果可以帮助模型理解目标词我指代原词I;

计算h个注意力矩阵后,将它们串联起来,乘以一个新的权重矩阵,得到最终的注意力矩阵;将其输入解码器的下一个子层,即前馈网络层;

前馈网络层:

  • 其工作原理与解码器中一致;
  • 解码器的前馈网络层中的叠加和归一化组件同样连接子层的输入和输出,而且需要注意的是:解码器的三个子层都使用了叠加和归一化组件连接了子层的输入和输出;
  • 前馈网络层输出解码后的特征(最后一个解码器输出将是目标句的特征);

关于线性层和softmax层:

  • 解码器学习了目标句特征之后,需要将顶层(叠加的最后一个)解码器的输出送入线性层和softmax层;
  • 线性层将生成一个logit3(是一种概率分布)向量,其大小等于原句中的词汇量(这个应该是指词源量,而不是原句的词量,输出的词的索引值,也是要对应到总词汇表的);
  • 接下来,再使用softmax函数将logit向量转换成概率,然后将输出具有高概率值的词的索引值,即通过概率得到预测的词;

整合编码器和解码器

即Transformer架构;

  • 编码器学习原句特征并将其发送给解码器;
  • 解码器又会生成目标句;

训练Transformer

可以通过最小化损失函数来训练Transformer网络,解码器预测的是词汇的概率分布,并选择概率最高的词作为输出,因此损失函数的选择,需要让预测的概率分布和实际的概率分布之间的差异最小化,这样可以将损失函数定义为交叉熵损失函数,并使用Adam算法来优化训练过程;

需要注意的是,为了防止过拟合,可以将dropout方法应用于每个子层的输出,以及嵌入和位置编码的总和(这里说的可能是输入矩阵);

小结

了解了Transformer 编码器-解码器架构,了解使用的不同子层;我们了解到自注意力机制将一个词与句子中的所有词联系起来,以便更好的理解这个词;使用Q K V三个矩阵计算自注意力值;如何计算位置编码,以及如何用它来捕捉词序;

下一章,我们将学习Bert,以及它如何使用Transformer来对上下文嵌入进行学习。

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

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

相关文章

2023.9.7 关于 TCP / IP 的基本认知

目录 网络协议分层 TCP/IP 五层&#xff08;四层&#xff09;模型 应用层 传输层 网络层&#xff08;互联网层&#xff09; 数据链路层&#xff08;网络接口层&#xff09; 物理层 网络数据传输的基本流程 网络协议分层 为什么需要分层&#xff1f; 分层之后&#xff0c…

MATLAB实现数据插值

目录 一.理论知识 二.一维插值实例 三.二维插值实例 一.理论知识 所谓插值&#xff0c;顾名思义&#xff0c;插入数值。很多时候&#xff0c;我们仅有离散点上的数据&#xff0c;这时如果我们想要分析变量之间的函数关系&#xff0c;则无法实现。但如果通过插值处理&#xf…

PCL入门(四):kdtree简单介绍和使用

目录 1. kd树的意义2. kd树的使用 参考博客《欧式聚类&#xff08;KD-Tree&#xff09;详解&#xff0c;保姆级教程》和《(三分钟)学会kd-tree 激光SLAM点云搜索常见》 1. kd树的意义 kd树是什么&#xff1f; kd树是一种空间划分的数据结构&#xff0c;对于多个维度的数据&a…

电商(淘宝1688京东拼多多等)API接口服务:提升商业效率和用户体验的关键

电商API接口服务&#xff1a;提升商业效率和用户体验的关键 随着电子商务的飞速发展&#xff0c;电商企业需要不断提升自身的业务能力和服务质量&#xff0c;以应对日益激烈的市场竞争。为了更好地满足商家和消费者的需求&#xff0c;电商API接口服务应运而生。本文将探讨电商…

计算机毕设 大数据商城人流数据分析与可视化 - python 大数据分析

文章目录 0 前言课题背景分析方法与过程初步分析&#xff1a;总体流程&#xff1a;1.数据探索分析2.数据预处理3.构建模型 总结 最后 0 前言 &#x1f525; 这两年开始毕业设计和毕业答辩的要求和难度不断提升&#xff0c;传统的毕设题目缺少创新和亮点&#xff0c;往往达不到…

jmeter调试错误大全

一、前言 在使用jmeter做接口测试的过程中大家是不是经常会遇到很多问题&#xff0c;但是无从下手&#xff0c;不知道从哪里开始找起&#xff0c;对于初学者而言这是一个非常头痛的事情。这里结合笔者的经验&#xff0c;总结出以下方法。 二、通过查看运行日志调试问题 写好…

【常用代码14】el-input输入框内判断正则,只能输入数字,过滤汉字+字母。

问题描述&#xff1a; el-input输入框&#xff0c;只能输入数字&#xff0c;但是不能显示输入框最右边的上下箭头&#xff0c; <el-input v-model"input" type"number" placeholder"请输入内容" style"width: 200px;margin: 50px 0;&…

两种解法解决LCR 008. 长度最小的子数组【C++】

文章目录 [LCR 008. 长度最小的子数组](https://leetcode.cn/problems/2VG8Kg/description/)解法暴力解法滑动窗口&#xff08;双指针法&#xff09; LCR 008. 长度最小的子数组 解法 暴力解法 //暴力解法&#xff1a; //使用双for循环依次遍历数组&#xff0c;罗列出所有情况…

华为云 异构数据迁移

数据库和应用迁移 UGO&#xff08;Database and Application Migration UGO&#xff0c;以下简称为UGO&#xff09;是专注于异构数据库结构迁移的专业服务。可将源数据库中的DDL、DML和DCL一键自动转换为华为云GaussDB/RDS的SQL语法&#xff0c;通过数据库评估、对象迁移两大核…

计算机竞赛 基于深度学习的植物识别算法 - cnn opencv python

文章目录 0 前言1 课题背景2 具体实现3 数据收集和处理3 MobileNetV2网络4 损失函数softmax 交叉熵4.1 softmax函数4.2 交叉熵损失函数 5 优化器SGD6 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; **基于深度学习的植物识别算法 ** …

Vue3,Typescript中引用组件路径无法找到模块报错

是这么个事&#xff0c;我在vue3新创建的项目里&#xff0c;写了个组件叫headerIndex.vue&#xff0c;放到app.vue中import就会报错 路径肯定没写错&#xff0c;找到了解决方法&#xff0c;但是也没想明白为什么 解决方法如下 在vite-env.d.ts文件中加入 declare module &qu…

AJAX学习笔记6 JQuery对AJAX进行封装

AJAX学习笔记5同步与异步理解_biubiubiu0706的博客-CSDN博客 AJAX请求相关的代码都是类似的&#xff0c;有很多重复的代码&#xff0c;这些重复的代码能不能不写&#xff0c;能不能封装一个工具类。要发送ajax请求的话&#xff0c;就直接调用这个工具类中的相关函数即可。 用J…

springboot web 增加不存在的url返回200状态码 vue 打包设置

spring boot项目增加 html web页面访问 1. 首先 application.properties 文件中增加配置&#xff0c;指定静态资源目录&#xff08;包括html的存放&#xff09; spring.resources.static-locationsclasspath:/webapp/,classpath:/webapp/static/ 2. 项目目录 3. 如果有实现 …

Arm 架构 Ubuntu 使用 Docker 安装 Gitlab 并使用

官方 gitlab 文档 我的系统是 arm 架构的 ubuntu 官网没有提供 arm 架构的 docker 的 gitlab 的安装方式&#xff0c;直接安装的也是后来加的&#xff0c;文档也是随笔带过&#xff0c;&#xff0c;&#xff0c;我用到了&#xff0c;记录一下 默认已经安装了 docker 在 docker …

爬虫逆向实战(31)-某花顺行情中心(cookie、补环境)

一、数据接口分析 主页地址&#xff1a;某花顺 1、抓包 通过抓包可以发现数据接口是/page/2/ajax/1/ 2、判断是否有加密参数 请求参数是否加密&#xff1f; 无请求头是否加密&#xff1f; 通过查看“标头”可以发现有一个Hexin-V加密参数&#xff0c;但是这个参数的值与c…

初学Python记

Python这个编程语言的大名当然听说过了呀&#xff0c;这几年特别火&#xff0c;火的一塌涂地。大家可以回忆一下&#xff1a;朋友圈推荐的广告里经常可以看见python的网课广告。 本学期&#xff0c;学校开设了python课程&#xff0c;这几天学习了一下入了一下门&#xff0c;感…

SpringMVC笔记

文章目录 一、SpringMVC简介1、什么是MVC2、什么是SpringMVC3、SpringMVC的特点 二、HelloWorld1、开发环境2、创建maven工程a>添加web模块b>打包方式&#xff1a;warc>引入依赖 3、配置web.xmla>默认配置方式b>扩展配置方式 4、创建请求控制器5、创建springMVC…

selenium的Chrome116版驱动下载

这里写自定义目录标题 下载地址https://googlechromelabs.github.io/chrome-for-testing/#stable 选择chromedriver 对应的平台和版本 国内下载地址 https://download.csdn.net/download/dongtest/88314387

探索Apache Hive:融合专业性、趣味性和吸引力的数据库操作奇幻之旅

文章目录 版权声明一 数据库操作二 Hive数据表操作2.1 表操作语法和数据类型2.2 Hive表分类2.3 内部表Vs外部表2.4 内部表操作2.4.1 创建内部表2.4.2 其他创建内部表的形式2.4.3 数据分隔符2.4.4 自定义分隔符2.4.5 删除内部表 2.5 外部表操作2.5.1 创建外部表2.5.2 操作演示2.…

MNIST手写数字辨识-cnn网路 (机器学习中的hello world,加油)

用PyTorch实现MNIST手写数字识别(非常详细) - 知乎 (zhihu.com) 参考来源&#xff08;这篇文章非常适合入门来看&#xff0c;每个细节都讲解得很到位&#xff09; 一、模块函数用法-查漏补缺&#xff1a; 1.关于torch.nn.functional.max_pool2d()的用法&#xff1a; 上述示例…