【AI大模型】深入Transformer架构:编码器部分的实现与解析(上)

news2024/11/18 15:39:01

 

目录

🍔 编码器介绍

🍔 掩码张量

2.1 掩码张量介绍

2.2 掩码张量的作用

2.3 生成掩码张量的代码分析

2.4 掩码张量的可视化

2.5 掩码张量总结

🍔 注意力机制

3.1 注意力计算规则的代码分析

3.2 带有mask的输入参数:

3.3 注意力机制总结

🍔 多头注意力机制

4.1 多头注意力机制概念

4.2 多头注意力机制结构图

4.3 多头注意力机制的作用

4.4 多头注意力机制的代码实现

4.5 多头注意力机制总结


学习目标

🍀 了解编码器中各个组成部分的作用.

🍀 掌握编码器中各个组成部分的实现过程.

🍔 编码器介绍

编码器部分: * 由N个编码器层堆叠而成 * 每个编码器层由两个子层连接结构组成 * 第一个子层连接结构包括一个多头自注意力子层和规范化层以及一个残差连接 * 第二个子层连接结构包括一个前馈全连接子层和规范化层以及一个残差连接


🍔 掩码张量

2.1 掩码张量介绍

  • 掩代表遮掩,码就是我们张量中的数值,它的尺寸不定,里面一般只有1和0的元素,代表位置被遮掩或者不被遮掩,至于是0位置被遮掩还是1位置被遮掩可以自定义,因此它的作用就是让另外一个张量中的一些数值被遮掩,也可以说被替换, 它的表现形式是一个张量.

2.2 掩码张量的作用

  • 在transformer中, 掩码张量的主要作用在应用attention(将在下一小节讲解)时,有一些生成的attention张量中的值计算有可能已知了未来信息而得到的,未来信息被看到是因为训练时会把整个输出结果都一次性进行Embedding,但是理论上解码器的的输出却不是一次就能产生最终结果的,而是一次次通过上一次结果综合得出的,因此,未来的信息可能被提前利用. 所以,我们会进行遮掩. 关于解码器的有关知识将在后面的章节中讲解.

2.3 生成掩码张量的代码分析

def subsequent_mask(size):
    """生成向后遮掩的掩码张量, 参数size是掩码张量最后两个维度的大小, 它的最后两维形成一个方阵"""
    # 在函数中, 首先定义掩码张量的形状
    attn_shape = (1, size, size)

    # 然后使用np.ones方法向这个形状中添加1元素,形成上三角阵, 最后为了节约空间, 
    # 再使其中的数据类型变为无符号8位整形unit8 
    subsequent_mask = np.triu(np.ones(attn_shape), k=1).astype('uint8')

    # 最后将numpy类型转化为torch中的tensor, 内部做一个1 - 的操作, 
    # 在这个其实是做了一个三角阵的反转, subsequent_mask中的每个元素都会被1减, 
    # 如果是0, subsequent_mask中的该位置由0变成1
    # 如果是1, subsequent_mask中的该位置由1变成0 
    return torch.from_numpy(1 - subsequent_mask)
  • np.triu演示:
>>> np.triu([[1,2,3],[4,5,6],[7,8,9],[10,11,12]], k=-1)
array([[ 1,  2,  3],
       [ 4,  5,  6],
       [ 0,  8,  9],
       [ 0,  0, 12]])


>>> np.triu([[1,2,3],[4,5,6],[7,8,9],[10,11,12]], k=0)
array([[ 1,  2,  3],
       [ 0,  5,  6],
       [ 0,  0,  9],
       [ 0,  0, 0]])


>>> np.triu([[1,2,3],[4,5,6],[7,8,9],[10,11,12]], k=1)
array([[ 0,  2,  3],
       [ 0,  0,  6],
       [ 0,  0,  0],
       [ 0,  0, 0]])
  • 输入实例:
# 生成的掩码张量的最后两维的大小
size = 5
  • 调用:
sm = subsequent_mask(size)
print("sm:", sm)
  • 输出效果:
# 最后两维形成一个下三角阵
sm: (0 ,.,.) = 
  1  0  0  0  0
  1  1  0  0  0
  1  1  1  0  0
  1  1  1  1  0
  1  1  1  1  1
[torch.ByteTensor of size 1x5x5]

2.4 掩码张量的可视化

plt.figure(figsize=(5,5))
plt.imshow(subsequent_mask(20)[0])
  • 输出效果:


  • 效果分析:
  • 通过观察可视化方阵, 黄色是1的部分, 这里代表被遮掩, 紫色代表没有被遮掩的信息, 横坐标代表目标词汇的位置, 纵坐标代表可查看的位置;
  • 我们看到, 在0的位置我们一看望过去都是黄色的, 都被遮住了,1的位置一眼望过去还是黄色, 说明第一次词还没有产生, 从第二个位置看过去, 就能看到位置1的词, 其他位置看不到, 以此类推.

2.5 掩码张量总结

  • 学习了什么是掩码张量:

    • 掩代表遮掩,码就是我们张量中的数值,它的尺寸不定,里面一般只有1和0的元素,代表位置被遮掩或者不被遮掩,至于是0位置被遮掩还是1位置被遮掩可以自定义,因此它的作用就是让另外一个张量中的一些数值被遮掩, 也可以说被替换, 它的表现形式是一个张量.
  • 学习了掩码张量的作用:

    • 在transformer中, 掩码张量的主要作用在应用attention(将在下一小节讲解)时,有一些生成的attetion张量中的值计算有可能已知量未来信息而得到的,未来信息被看到是因为训练时会把整个输出结果都一次性进行Embedding,但是理论上解码器的的输出却不是一次就能产生最终结果的,而是一次次通过上一次结果综合得出的,因此,未来的信息可能被提前利用. 所以,我们会进行遮掩. 关于解码器的有关知识将在后面的章节中讲解.
  • 学习并实现了生成向后遮掩的掩码张量函数: subsequent_mask

    • 它的输入是size, 代表掩码张量的大小.
    • 它的输出是一个最后两维形成1方阵的下三角阵.
    • 最后对生成的掩码张量进行了可视化分析, 更深一步理解了它的用途.

🍔 注意力机制

我们这里使用的注意力的计算规则:

3.1 注意力计算规则的代码分析

import torch.nn.functional as F

def attention(query, key, value, mask=None, dropout=None):
    """注意力机制的实现, 输入分别是query, key, value, mask: 掩码张量, 
       dropout是nn.Dropout层的实例化对象, 默认为None"""
    # 在函数中, 首先取query的最后一维的大小, 一般情况下就等同于我们的词嵌入维度, 命名为d_k
    d_k = query.size(-1)
    # 按照注意力公式, 将query与key的转置相乘, 这里面key是将最后两个维度进行转置, 再除以缩放系数根号下d_k, 这种计算方法也称为缩放点积注意力计算.
    # 得到注意力得分张量scores
    scores = torch.matmul(query, key.transpose(-2, -1)) / math.sqrt(d_k)

    # 接着判断是否使用掩码张量
    if mask is not None:
        # 使用tensor的masked_fill方法, 将掩码张量和scores张量每个位置一一比较, 如果掩码张量处为0
        # 则对应的scores张量用-1e9这个值来替换, 如下演示
        scores = scores.masked_fill(mask == 0, -1e9)

    # 对scores的最后一维进行softmax操作, 使用F.softmax方法, 第一个参数是softmax对象, 第二个是目标维度.
    # 这样获得最终的注意力张量
    p_attn = F.softmax(scores, dim = -1)

    # 之后判断是否使用dropout进行随机置0
    if dropout is not None:
        # 将p_attn传入dropout对象中进行'丢弃'处理
        p_attn = dropout(p_attn)

    # 最后, 根据公式将p_attn与value张量相乘获得最终的query注意力表示, 同时返回注意力张量
    return torch.matmul(p_attn, value), p_attn
  • tensor.masked_fill演示:
>>> input = Variable(torch.randn(5, 5))
>>> input 
Variable containing:
 2.0344 -0.5450  0.3365 -0.1888 -2.1803
 1.5221 -0.3823  0.8414  0.7836 -0.8481
-0.0345 -0.8643  0.6476 -0.2713  1.5645
 0.8788 -2.2142  0.4022  0.1997  0.1474
 2.9109  0.6006 -0.6745 -1.7262  0.6977
[torch.FloatTensor of size 5x5]

>>> mask = Variable(torch.zeros(5, 5))
>>> mask
Variable containing:
 0  0  0  0  0
 0  0  0  0  0
 0  0  0  0  0
 0  0  0  0  0
 0  0  0  0  0
[torch.FloatTensor of size 5x5]

>>> input.masked_fill(mask == 0, -1e9)
Variable containing:
-1.0000e+09 -1.0000e+09 -1.0000e+09 -1.0000e+09 -1.0000e+09
-1.0000e+09 -1.0000e+09 -1.0000e+09 -1.0000e+09 -1.0000e+09
-1.0000e+09 -1.0000e+09 -1.0000e+09 -1.0000e+09 -1.0000e+09
-1.0000e+09 -1.0000e+09 -1.0000e+09 -1.0000e+09 -1.0000e+09
-1.0000e+09 -1.0000e+09 -1.0000e+09 -1.0000e+09 -1.0000e+09
[torch.FloatTensor of size 5x5]
  • 输入参数:
# 我们令输入的query, key, value都相同, 位置编码的输出
query = key = value = pe_result
Variable containing:
( 0 ,.,.) = 
  46.5196  16.2057 -41.5581  ...  -16.0242 -17.8929 -43.0405
 -32.6040  16.1096 -29.5228  ...    4.2721  20.6034  -1.2747
 -18.6235  14.5076  -2.0105  ...   15.6462 -24.6081 -30.3391
   0.0000 -66.1486 -11.5123  ...   20.1519  -4.6823   0.4916

( 1 ,.,.) = 
 -24.8681   7.5495  -5.0765  ...   -7.5992 -26.6630  40.9517
  13.1581  -3.1918 -30.9001  ...   25.1187 -26.4621   2.9542
 -49.7690 -42.5019   8.0198  ...   -5.4809  25.9403 -27.4931
 -52.2775  10.4006   0.0000  ...   -1.9985   7.0106  -0.5189
[torch.FloatTensor of size 2x4x512]
  • 调用:
attn, p_attn = attention(query, key, value)
print("attn:", attn)
print("p_attn:", p_attn)
  • 输出效果:
# 将得到两个结果
# query的注意力表示:
attn: Variable containing:
( 0 ,.,.) = 
   12.8269    7.7403   41.2225  ...     1.4603   27.8559  -12.2600
   12.4904    0.0000   24.1575  ...     0.0000    2.5838   18.0647
  -32.5959   -4.6252  -29.1050  ...     0.0000  -22.6409  -11.8341
    8.9921  -33.0114   -0.7393  ...     4.7871   -5.7735    8.3374

( 1 ,.,.) = 
  -25.6705   -4.0860  -36.8226  ...    37.2346  -27.3576    2.5497
  -16.6674   73.9788  -33.3296  ...    28.5028   -5.5488  -13.7564
    0.0000  -29.9039   -3.0405  ...     0.0000   14.4408   14.8579
   30.7819    0.0000   21.3908  ...   -29.0746    0.0000   -5.8475
[torch.FloatTensor of size 2x4x512]

# 注意力张量:
p_attn: Variable containing:
(0 ,.,.) = 
  1  0  0  0
  0  1  0  0
  0  0  1  0
  0  0  0  1

(1 ,.,.) = 
  1  0  0  0
  0  1  0  0
  0  0  1  0
  0  0  0  1
[torch.FloatTensor of size 2x4x4]

3.2 带有mask的输入参数:

query = key = value = pe_result

# 令mask为一个2x4x4的零张量
mask = Variable(torch.zeros(2, 4, 4))
  • 调用:
attn, p_attn = attention(query, key, value, mask=mask)
print("attn:", attn)
print("p_attn:", p_attn)
  • 带有mask的输出效果:
# query的注意力表示:
attn: Variable containing:
( 0 ,.,.) = 
   0.4284  -7.4741   8.8839  ...    1.5618   0.5063   0.5770
   0.4284  -7.4741   8.8839  ...    1.5618   0.5063   0.5770
   0.4284  -7.4741   8.8839  ...    1.5618   0.5063   0.5770
   0.4284  -7.4741   8.8839  ...    1.5618   0.5063   0.5770

( 1 ,.,.) = 
  -2.8890   9.9972 -12.9505  ...    9.1657  -4.6164  -0.5491
  -2.8890   9.9972 -12.9505  ...    9.1657  -4.6164  -0.5491
  -2.8890   9.9972 -12.9505  ...    9.1657  -4.6164  -0.5491
  -2.8890   9.9972 -12.9505  ...    9.1657  -4.6164  -0.5491
[torch.FloatTensor of size 2x4x512]

# 注意力张量:
p_attn: Variable containing:
(0 ,.,.) = 
  0.2500  0.2500  0.2500  0.2500
  0.2500  0.2500  0.2500  0.2500
  0.2500  0.2500  0.2500  0.2500
  0.2500  0.2500  0.2500  0.2500

(1 ,.,.) = 
  0.2500  0.2500  0.2500  0.2500
  0.2500  0.2500  0.2500  0.2500
  0.2500  0.2500  0.2500  0.2500
  0.2500  0.2500  0.2500  0.2500
[torch.FloatTensor of size 2x4x4]

3.3 注意力机制总结

  • 学习并实现了注意力计算规则的函数: attention
    • 它的输入就是Q,K,V以及mask和dropout, mask用于掩码, dropout用于随机置0.
    • 它的输出有两个, query的注意力表示以及注意力张量.

🍔 多头注意力机制

4.1 多头注意力机制概念

  • 从多头注意力的结构图中,貌似这个所谓的多个头就是指多组线性变换层,其实并不是,我只有使用了一组线性变化层,即三个变换张量对Q,K,V分别进行线性变换,这些变换不会改变原有张量的尺寸,因此每个变换矩阵都是方阵,得到输出结果后,多头的作用才开始显现,每个头开始从词义层面分割输出的张量,也就是每个头都想获得一组Q,K,V进行注意力机制的计算,但是句子中的每个词的表示只获得一部分,也就是只分割了最后一维的词嵌入向量. 这就是所谓的多头,将每个头的获得的输入送到注意力机制中, 就形成多头注意力机制.

4.2 多头注意力机制结构图


4.3 多头注意力机制的作用

  • 这种结构设计能让每个注意力机制去优化每个词汇的不同特征部分,从而均衡同一种注意力机制可能产生的偏差,让词义拥有来自更多元的表达,实验表明可以从而提升模型效果.

4.4 多头注意力机制的代码实现

# 用于深度拷贝的copy工具包
import copy

# 首先需要定义克隆函数, 因为在多头注意力机制的实现中, 用到多个结构相同的线性层.
# 我们将使用clone函数将他们一同初始化在一个网络层列表对象中. 之后的结构中也会用到该函数.
def clones(module, N):
    """用于生成相同网络层的克隆函数, 它的参数module表示要克隆的目标网络层, N代表需要克隆的数量"""
    # 在函数中, 我们通过for循环对module进行N次深度拷贝, 使其每个module成为独立的层,
    # 然后将其放在nn.ModuleList类型的列表中存放.
    return nn.ModuleList([copy.deepcopy(module) for _ in range(N)])


# 我们使用一个类来实现多头注意力机制的处理
class MultiHeadedAttention(nn.Module):
    def __init__(self, head, embedding_dim, dropout=0.1):
        """在类的初始化时, 会传入三个参数,head代表头数,embedding_dim代表词嵌入的维度, 
           dropout代表进行dropout操作时置0比率,默认是0.1."""
        super(MultiHeadedAttention, self).__init__()

        # 在函数中,首先使用了一个测试中常用的assert语句,判断h是否能被d_model整除,
        # 这是因为我们之后要给每个头分配等量的词特征.也就是embedding_dim/head个.
        assert embedding_dim % head == 0

        # 得到每个头获得的分割词向量维度d_k
        self.d_k = embedding_dim // head

        # 传入头数h
        self.head = head

        # 然后获得线性层对象,通过nn的Linear实例化,它的内部变换矩阵是embedding_dim x embedding_dim,然后使用clones函数克隆四个,
        # 为什么是四个呢,这是因为在多头注意力中,Q,K,V各需要一个,最后拼接的矩阵还需要一个,因此一共是四个.
        self.linears = clones(nn.Linear(embedding_dim, embedding_dim), 4)

        # self.attn为None,它代表最后得到的注意力张量,现在还没有结果所以为None.
        self.attn = None

        # 最后就是一个self.dropout对象,它通过nn中的Dropout实例化而来,置0比率为传进来的参数dropout.
        self.dropout = nn.Dropout(p=dropout)

    def forward(self, query, key, value, mask=None):
        """前向逻辑函数, 它的输入参数有四个,前三个就是注意力机制需要的Q, K, V,
           最后一个是注意力机制中可能需要的mask掩码张量,默认是None. """

        # 如果存在掩码张量mask
        if mask is not None:
            # 使用unsqueeze拓展维度
            mask = mask.unsqueeze(0)

        # 接着,我们获得一个batch_size的变量,他是query尺寸的第1个数字,代表有多少条样本.
        batch_size = query.size(0)

        # 之后就进入多头处理环节
        # 首先利用zip将输入QKV与三个线性层组到一起,然后使用for循环,将输入QKV分别传到线性层中,
        # 做完线性变换后,开始为每个头分割输入,这里使用view方法对线性变换的结果进行维度重塑,多加了一个维度h,代表头数,
        # 这样就意味着每个头可以获得一部分词特征组成的句子,其中的-1代表自适应维度,
        # 计算机会根据这种变换自动计算这里的值.然后对第二维和第三维进行转置操作,
        # 为了让代表句子长度维度和词向量维度能够相邻,这样注意力机制才能找到词义与句子位置的关系,
        # 从attention函数中可以看到,利用的是原始输入的倒数第一和第二维.这样我们就得到了每个头的输入.
        query, key, value = \
           [model(x).view(batch_size, -1, self.head, self.d_k).transpose(1, 2)
            for model, x in zip(self.linears, (query, key, value))]

        # 得到每个头的输入后,接下来就是将他们传入到attention中,
        # 这里直接调用我们之前实现的attention函数.同时也将mask和dropout传入其中.
        x, self.attn = attention(query, key, value, mask=mask, dropout=self.dropout)

        # 通过多头注意力计算后,我们就得到了每个头计算结果组成的4维张量,我们需要将其转换为输入的形状以方便后续的计算,
        # 因此这里开始进行第一步处理环节的逆操作,先对第二和第三维进行转置,然后使用contiguous方法,
        # 这个方法的作用就是能够让转置后的张量应用view方法,否则将无法直接使用,
        # 所以,下一步就是使用view重塑形状,变成和输入形状相同.
        x = x.transpose(1, 2).contiguous().view(batch_size, -1, self.head * self.d_k)

        # 最后使用线性层列表中的最后一个线性层对输入进行线性变换得到最终的多头注意力结构的输出.
        return self.linears[-1](x)
  • tensor.view演示:
>>> x = torch.randn(4, 4)
>>> x.size()
torch.Size([4, 4])
>>> y = x.view(16)
>>> y.size()
torch.Size([16])
>>> z = x.view(-1, 8)  # the size -1 is inferred from other dimensions
>>> z.size()
torch.Size([2, 8])

>>> a = torch.randn(1, 2, 3, 4)
>>> a.size()
torch.Size([1, 2, 3, 4])
>>> b = a.transpose(1, 2)  # Swaps 2nd and 3rd dimension
>>> b.size()
torch.Size([1, 3, 2, 4])
>>> c = a.view(1, 3, 2, 4)  # Does not change tensor layout in memory
>>> c.size()
torch.Size([1, 3, 2, 4])
>>> torch.equal(b, c)
False
  • torch.transpose演示:
>>> x = torch.randn(2, 3)
>>> x
tensor([[ 1.0028, -0.9893,  0.5809],
        [-0.1669,  0.7299,  0.4942]])
>>> torch.transpose(x, 0, 1)
tensor([[ 1.0028, -0.1669],
        [-0.9893,  0.7299],
        [ 0.5809,  0.4942]])
  • 实例化参数:
# 头数head
head = 8

# 词嵌入维度embedding_dim
embedding_dim = 512

# 置零比率dropout
dropout = 0.2
  • 输入参数:
# 假设输入的Q,K,V仍然相等
query = value = key = pe_result

# 输入的掩码张量mask
mask = Variable(torch.zeros(8, 4, 4))
  • 调用:
mha = MultiHeadedAttention(head, embedding_dim, dropout)
mha_result = mha(query, key, value, mask)
print(mha_result)
  • 输出效果:
tensor([[[-0.3075,  1.5687, -2.5693,  ..., -1.1098,  0.0878, -3.3609],
         [ 3.8065, -2.4538, -0.3708,  ..., -1.5205, -1.1488, -1.3984],
         [ 2.4190,  0.5376, -2.8475,  ...,  1.4218, -0.4488, -0.2984],
         [ 2.9356,  0.3620, -3.8722,  ..., -0.7996,  0.1468,  1.0345]],

        [[ 1.1423,  0.6038,  0.0954,  ...,  2.2679, -5.7749,  1.4132],
         [ 2.4066, -0.2777,  2.8102,  ...,  0.1137, -3.9517, -2.9246],
         [ 5.8201,  1.1534, -1.9191,  ...,  0.1410, -7.6110,  1.0046],
         [ 3.1209,  1.0008, -0.5317,  ...,  2.8619, -6.3204, -1.3435]]],
       grad_fn=<AddBackward0>)
torch.Size([2, 4, 512])

4.5 多头注意力机制总结

  • 学习了什么是多头注意力机制:

    • 每个头开始从词义层面分割输出的张量,也就是每个头都想获得一组Q,K,V进行注意力机制的计算,但是句子中的每个词的表示只获得一部分,也就是只分割了最后一维的词嵌入向量. 这就是所谓的多头.将每个头的获得的输入送到注意力机制中, 就形成了多头注意力机制.
  • 学习了多头注意力机制的作用:

    • 这种结构设计能让每个注意力机制去优化每个词汇的不同特征部分,从而均衡同一种注意力机制可能产生的偏差,让词义拥有来自更多元的表达,实验表明可以从而提升模型效果.
  • 学习并实现了多头注意力机制的类: MultiHeadedAttention

    • 因为多头注意力机制中需要使用多个相同的线性层, 首先实现了克隆函数clones.
    • clones函数的输入是module,N,分别代表克隆的目标层,和克隆个数.
    • clones函数的输出是装有N个克隆层的Module列表.
    • 接着实现MultiHeadedAttention类, 它的初始化函数输入是h, d_model, dropout分别代表头数,词嵌入维度和置零比率.
    • 它的实例化对象输入是Q, K, V以及掩码张量mask.
    • 它的实例化对象输出是通过多头注意力机制处理的Q的注意力表示.

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

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

相关文章

华为开源自研AI框架昇思MindSpore应用案例:计算高效的卷积模型ShuffleNet

如果你对MindSpore感兴趣&#xff0c;可以关注昇思MindSpore社区 ShuffleNet ShuffleNet网络介绍 ShuffleNetV1是旷视科技提出的一种计算高效的CNN模型&#xff0c;和MobileNet, SqueezeNet等一样主要应用在移动端&#xff0c;所以模型的设计目标就是利用有限的计算资源来达到…

文章解读与仿真程序复现思路——电网技术EI\CSCD\北大核心《基于节点碳势响应的新型电力系统鲁棒优化调度 》

本专栏栏目提供文章与程序复现思路&#xff0c;具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源…

生信初学者教程(二十二):Boruta+RF筛选候选标记物

文章目录 介绍加载R包导入数据准备数据机器学习特征筛选数据分割基础模型Boruta特征筛选调参最终分类模型测试集验证标记基因输出结果总结介绍 采用了Boruta结合 RF(Random Forest) 的方法,对差异基因(参考 @sec-different-limma) 进行了特征筛选。通过这种方法,能够从大…

你以为瀑布流布局很复杂?Vue-Waterfall让你秒变前端高手

你以为瀑布流布局很复杂&#xff1f;Vue-Waterfall让你秒变前端高手 Vue-Waterfall 是一个轻量级的 Vue.js 组件&#xff0c;专为实现灵活的瀑布流布局设计。如果你需要在页面上呈现动态、响应式的布局&#xff0c;那这个组件绝对能帮到你&#xff01;本文将带你快速了解这个组…

推荐 uniapp 相对好用的海报生成插件

插件地址&#xff1a;自定义canvas样式海报 - DCloud 插件市场 兼容性也是不错的&#xff1a;

微软准备了 Windows 11 24H2 ISO “OOBE/BypassNRO“命令依然可用

Windows 11 24H2 可能在未来几周内开始推出。 微软已经要求 OEM 遵循新的指南准备好 Windows 11 24H2 就绪的驱动程序&#xff0c;并且现在已经开始准备媒体文件 (.ISO)。 OEM ISO 的链接已在微软服务器上发布。 一个标有"X23-81971_26100.1742.240906-0331.ge_release_sv…

[Python学习日记-35] Python 中的内置函数(上)

[Python学习日记-35] Python 中的内置函数&#xff08;上&#xff09; 简介 内置函数详解&#xff08;A-E&#xff09; 简介 在 Python 中有很多内置函数&#xff0c;例如 len()&#xff0c;这些函数是 Python 解释器自带的&#xff0c;可以直接使用。本篇将介绍 A-H 的内置函…

基于Springboot+Vue的《计算机基础》网上考试系统(含源码数据库)

1.开发环境 开发系统:Windows10/11 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql5.7或8.0 数据库可视化工具: navicat 服务器: SpringBoot自带 apache tomcat 主要技术: Java,Springboot,mybatis,mysql,vue 2.视频演示地址 3.功能 系统中…

YOLOv11:重新定义实时目标检测的未来

YOLO 版本发布历史回顾 YOLO (You Only Look Once), a popular object detection and image segmentation model, was developed by Joseph Redmon and Ali Farhadi at the University of Washington. Launched in 2015, YOLO quickly gained popularity for its high speed a…

vulnhub-mrRobot靶机的测试报告

目录 一、测试环境 1、系统环境 2、使用工具/软件 二、测试目的 三、操作过程 1、信息搜集 2、渗透网页 3、Getshell 4、提权 四、结论 一、测试环境 1、系统环境 渗透机&#xff1a;kali2021.1(192.168.202.134) 靶 机&#xff1a;linux 3.13.0-55-generic #94-…

复习HTML(基础)

目录 HTML含义 HTML作用 HTML的常用元素 元素的特点 元素的分类 1 是否嵌套关系 2 是否独占一行 块元素&#xff1a;独占一行 行内元素&#xff1a;共享一行 行内元素与块级元素的转换 3是否有结束标签 常用标签 1 标题标签&#xff1a;有六级 我们用h1 ~h6 表…

国产化系统/鸿蒙开发足浴店收银源码-收缩左侧———未来之窗行业应用跨平台架构

一、左侧展开后 二、代码 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head><title></title><meta http-equiv"Content-Type" content"text/html; charsetUTF-8"><style t…

PHP安装后Apache无法运行的问题

问题 按照网上教程php安装点击跳转教程&#xff0c;然后修改Apache的httpd.conf文件&#xff0c;本来可以运行的Apache&#xff0c;无法运行了 然后在"C:\httpd-2.4.62-240904-win64-VS17\Apache24\logs\error.log"&#xff08;就是我下载Apache的目录下的logs中&am…

查看 git log的过程中看到 :说明日志输出可能超出屏幕大小,系统进入了分页模式

在命令行提示符中&#xff0c;通常 : 表示系统等待进一步的输入。如果你在查看 git log 的过程中看到 :&#xff0c;说明日志输出可能超出屏幕大小&#xff0c;系统进入了分页模式&#xff0c;默认使用 less 命令查看内容。 此时你可以&#xff1a; 按 q 退出日志查看。按 En…

通信工程学习:什么是NFS网络文件系统

NFS&#xff1a;网络文件系统 NFS&#xff08;Network File System&#xff09;&#xff0c;即网络文件系统&#xff0c;是一种用于在计算机网络上共享文件的协议。它允许一个计算机系统通过网络将其文件和存储设备共享给其他计算机系统&#xff0c;使得这些系统可以像访问本地…

deepin 无线网络搜不到信号

搜索不到wifi信号和无法连接wifi&#xff0d;论坛&#xff0d;深度科技 (deepin.org)https://bbs.deepin.org/zh/post/218198

【含文档】基于Springboot+Vue的果蔬种植销售一体化服务平台(含源码+数据库+lw)

1.开发环境 开发系统:Windows10/11 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql5.7或8.0 数据库可视化工具: navicat 服务器: SpringBoot自带 apache tomcat 主要技术: Java,Springboot,mybatis,mysql,vue 2.视频演示地址 3.功能 系统定…

前端工程化17-邂逅原生的ajax、跨域、JSONP

5、邂逅原生的ajax 5.1、什么是ajax AJAX 全称为Asynchronous Javascript And XML&#xff0c;就是异步的 JS 和 XML。通过AJAX可以在浏览器中向服务器发送异步请求&#xff0c;最大的优势&#xff1a;页面无刷新获取数据。AJAX 不是新的编程语言&#xff0c;而是一种将现有的…

将脚本编译为pyd文件

Python虽然作为一种解释性语言&#xff0c;通常是使用解释器处理脚本的方式完成工作&#xff0c;但是也具有和很多其他诸如C、C#语言等类似的方式&#xff0c;可以将.py文件编译为*.pyd文件&#xff0c;即Python动态链接库文件。 关于动态链接库的优缺点这里就不展开细说了&…

Android Studio Dolphin 中Gradle下载慢的解决方法

我用的版本Android Studio Dolphin | 2021.3.1 Patch 1 1.Gradle自身的版本下载慢 解决办法&#xff1a;修改gradle\wrapper\gradle-wrapper.properties中的distributionUrl 将https\://services.gradle.org/distributions为https\://mirrors.cloud.tencent.com/gradle dis…