动手学深度学习9.1. 门控循环单元(GRU)-笔记练习(PyTorch)

news2024/11/16 9:18:31

本节课程地址:门控循环单元(GRU)_哔哩哔哩_bilibili

本节教材地址:9.1. 门控循环单元(GRU) — 动手学深度学习 2.0.0 documentation (d2l.ai)

本节开源代码:...>d2l-zh>pytorch>chapter_multilayer-perceptrons>gru.ipynb


门控循环单元(GRU)

在 8.7节 中, 我们讨论了如何在循环神经网络中计算梯度, 以及矩阵连续乘积可以导致梯度消失或梯度爆炸的问题。 下面我们简单思考一下这种梯度异常在实践中的意义:

  • 我们可能会遇到这样的情况:早期观测值对预测所有未来观测值具有非常重要的意义。 考虑一个极端情况,其中第一个观测值包含一个校验和, 目标是在序列的末尾辨别校验和是否正确。 在这种情况下,第一个词元的影响至关重要。 我们希望有某些机制能够在一个记忆元里存储重要的早期信息。 如果没有这样的机制,我们将不得不给这个观测值指定一个非常大的梯度, 因为它会影响所有后续的观测值。
  • 我们可能会遇到这样的情况:一些词元没有相关的观测值。 例如,在对网页内容进行情感分析时, 可能有一些辅助HTML代码与网页传达的情绪无关。 我们希望有一些机制来跳过隐状态表示中的此类词元。
  • 我们可能会遇到这样的情况:序列的各个部分之间存在逻辑中断。 例如,书的章节之间可能会有过渡存在, 或者证券的熊市和牛市之间可能会有过渡存在。 在这种情况下,最好有一种方法来重置我们的内部状态表示。

在学术界已经提出了许多方法来解决这类问题。 其中最早的方法是"长短期记忆"(long-short-term memory,LSTM) (Hochreiter and Schmidhuber, 1997), 我们将在 9.2节 中讨论。 门控循环单元(gated recurrent unit,GRU) (href="https://zh.d2l.ai/chapter_references/zreferences.html#id23">Choet al., 2014) 是一个稍微简化的变体,通常能够提供同等的效果, 并且计算 (ef="https://zh.d2l.ai/chapter_references/zreferences.html#id26">Chunget al., 2014) 的速度明显更快。 由于门控循环单元更简单,我们从它开始解读。

门控隐状态

门控循环单元与普通的循环神经网络之间的关键区别在于: 前者支持隐状态的门控。 这意味着模型有专门的机制来确定应该何时更新隐状态, 以及应该何时重置隐状态。 这些机制是可学习的,并且能够解决了上面列出的问题。 例如,如果第一个词元非常重要, 模型将学会在第一次观测之后不更新隐状态。 同样,模型也可以学会跳过不相关的临时观测。 最后,模型还将学会在需要的时候重置隐状态。 下面我们将详细讨论各类门控。

重置门和更新门

我们首先介绍重置门(reset gate)和更新门(update gate)。 我们把它们设计成$(0, 1)$区间中的向量, 这样我们就可以进行凸组合。 重置门允许我们控制“可能还想记住”的过去状态的数量(能遗忘的机制); 更新门将允许我们控制新状态中有多少个是旧状态的副本(能关注的机制)。

我们从构造这些门控开始。 图9.1.1 描述了门控循环单元中的重置门和更新门的输入, 输入是由当前时间步的输入和前一时间步的隐状态给出。 两个门的输出是由使用sigmoid激活函数的两个全连接层给出。

我们来看一下门控循环单元的数学表达。 对于给定的时间步 t ,假设输入是一个小批量 \mathbf{X}_t \in \mathbb{R}^{n \times d}(样本个数 n ,输入个数 d ), 上一个时间步的隐状态是 \mathbf{X}_t \in \mathbb{R}^{n \times d} (隐藏单元个数 h )。 那么,重置门 \mathbf{R}_t \in \mathbb{R}^{n \times h} 和 更新门 \mathbf{Z}_t \in \mathbb{R}^{n \times h} 的计算如下所示:

\begin{aligned} \mathbf{R}_t = \sigma(\mathbf{X}_t \mathbf{W}_{xr} + \mathbf{H}_{t-1} \mathbf{W}_{hr} + \mathbf{b}_r),\\ \mathbf{Z}_t = \sigma(\mathbf{X}_t \mathbf{W}_{xz} + \mathbf{H}_{t-1} \mathbf{W}_{hz} + \mathbf{b}_z), \end{aligned}

其中 \mathbf{W}_{xr}, \mathbf{W}_{xz} \in \mathbb{R}^{d \times h} 和 \mathbf{W}_{hr}, \mathbf{W}_{hz} \in \mathbb{R}^{h \times h} 是权重参数, \mathbf{b}_r, \mathbf{b}_z \in \mathbb{R}^{1 \times h} 是偏置参数。 请注意,在求和过程中会触发广播机制 (请参阅 2.1.3节)。 我们使用sigmoid函数(如 4.1节 中介绍的) 将输入值转换到区间 (0, 1) 。

候选隐状态

接下来,让我们将重置门 \mathbf{R}_t 与 (8.4.5) 中的常规隐状态更新机制集成, 得到在时间步 t 的候选隐状态(candidate hidden state) \tilde{\mathbf{H}}_t \in \mathbb{R}^{n \times h} 。

\tilde{\mathbf{H}}_t = \tanh(\mathbf{X}_t \mathbf{W}_{xh} + \left(\mathbf{R}_t \odot \mathbf{H}_{t-1}\right) \mathbf{W}_{hh} + \mathbf{b}_h),(9.1.2)

其中 \mathbf{W}_{xh} \in \mathbb{R}^{d \times h}  \mathbf{W}_{hh} \in \mathbb{R}^{h \times h} 是权重参数, \mathbf{b}_h \in \mathbb{R}^{1 \times h} 是偏置项, 符号 \odot 是Hadamard积(按元素乘积)运算符。 在这里,我们使用tanh非线性激活函数来确保候选隐状态中的值保持在区间 (-1, 1) 中。

与 (8.4.5) 相比, (9.1.2)中的 \mathbf{R}_t  \mathbf{H}_{t-1} 的元素相乘可以减少以往状态的影响。 每当重置门 \mathbf{R}_t 中的项接近 1 时, 我们恢复一个如 (8.4.5)中的普通的循环神经网络。 对于重置门 \mathbf{R}_t 中所有接近 0 的项, 候选隐状态是以 \mathbf{X}_t 作为输入的多层感知机的结果。 因此,任何预先存在的隐状态都会被重置为默认值。

图9.1.2 说明了应用重置门之后的计算流程。

隐状态

上述的计算结果只是候选隐状态,我们仍然需要结合更新门 \mathbf{Z}_t 的效果。 这一步确定新的隐状态 \mathbf{H}_t \in \mathbb{R}^{n \times h} 在多大程度上来自旧的状态 \mathbf{H}_{t-1} 和 新的候选状态 \tilde{\mathbf{H}}_t 。 更新门 \mathbf{Z}_t 仅需要在 \mathbf{H}_{t-1} 和 \tilde{\mathbf{H}}_t 之间进行按元素的凸组合就可以实现这个目标。 这就得出了门控循环单元的最终更新公式:

\mathbf{H}_t = \mathbf{Z}_t \odot \mathbf{H}_{t-1} + (1 - \mathbf{Z}_t) \odot \tilde{\mathbf{H}}_t. (9.1.3)

每当更新门 \mathbf{Z}_t 接近 1 时,模型就倾向只保留旧状态。 此时,来自 \mathbf{X}_t 的信息基本上被忽略, 从而有效地跳过了依赖链条中的时间步 t 。 相反,当 \mathbf{Z}_t 接近 0 时, 新的隐状态 Ht 就会接近候选隐状态 \tilde{\mathbf{H}}_t 。 这些设计可以帮助我们处理循环神经网络中的梯度消失问题, 并更好地捕获时间步距离很长的序列的依赖关系。 例如,如果整个子序列的所有时间步的更新门都接近于 1 , 则无论序列的长度如何,在序列起始时间步的旧隐状态都将很容易保留并传递到序列结束。

图9.1.3 说明了更新门起作用后的计算流。

总之,门控循环单元具有以下两个显著特征:

  • 重置门有助于捕获序列中的短期依赖关系;
  • 更新门有助于捕获序列中的长期依赖关系。

极端情况,当 \mathbf{R}_t 为 1 且 \mathbf{Z}_t 为 0 时,GRU相当于RNN。

从零开始实现

为了更好地理解门控循环单元模型,我们从零开始实现它。 首先,我们读取 8.5节 中使用的时间机器数据集:

import torch
from torch import nn
from d2l import torch as d2l

batch_size, num_steps = 32, 35
train_iter, vocab = d2l.load_data_time_machine(batch_size, num_steps)

[初始化模型参数]

下一步是初始化模型参数。 我们从标准差为0.01的高斯分布中提取权重, 并将偏置项设为0,超参数num_hiddens定义隐藏单元的数量, 实例化与更新门、重置门、候选隐状态和输出层相关的所有权重和偏置。

def get_params(vocab_size, num_hiddens, device):
    num_inputs = num_outputs = vocab_size

    def normal(shape):
        return torch.randn(size=shape, device=device)*0.01

    def three():
        return (normal((num_inputs, num_hiddens)),
                normal((num_hiddens, num_hiddens)),
                torch.zeros(num_hiddens, device=device))

    W_xz, W_hz, b_z = three()  # 更新门参数
    W_xr, W_hr, b_r = three()  # 重置门参数
    W_xh, W_hh, b_h = three()  # 候选隐状态参数
    # 输出层参数
    W_hq = normal((num_hiddens, num_outputs))
    b_q = torch.zeros(num_outputs, device=device)
    # 附加梯度
    params = [W_xz, W_hz, b_z, W_xr, W_hr, b_r, W_xh, W_hh, b_h, W_hq, b_q]
    for param in params:
        param.requires_grad_(True)
    return params

定义模型

现在我们将[定义隐状态的初始化函数]init_gru_state。 与 8.5节 中定义的init_rnn_state函数一样, 此函数返回一个形状为(批量大小,隐藏单元个数)的张量,张量的值全部为零。

def init_gru_state(batch_size, num_hiddens, device):
    return (torch.zeros((batch_size, num_hiddens), device=device), )

现在我们准备[定义门控循环单元模型], 模型的架构与基本的循环神经网络单元是相同的, 只是权重更新公式更为复杂。

def gru(inputs, state, params):
    W_xz, W_hz, b_z, W_xr, W_hr, b_r, W_xh, W_hh, b_h, W_hq, b_q = params
    H, = state
    outputs = []
    for X in inputs:
        Z = torch.sigmoid((X @ W_xz) + (H @ W_hz) + b_z)
        R = torch.sigmoid((X @ W_xr) + (H @ W_hr) + b_r)
        H_tilda = torch.tanh((X @ W_xh) + ((R * H) @ W_hh) + b_h)
        H = Z * H + (1 - Z) * H_tilda
        Y = H @ W_hq + b_q
        outputs.append(Y)
    return torch.cat(outputs, dim=0), (H,)

[训练]与预测

训练和预测的工作方式与 8.5节 完全相同。 训练结束后,我们分别打印输出训练集的困惑度, 以及前缀“time traveler”和“traveler”的预测序列上的困惑度。

vocab_size, num_hiddens, device = len(vocab), 256, d2l.try_gpu()
num_epochs, lr = 500, 1
model = d2l.RNNModelScratch(len(vocab), num_hiddens, device, get_params,
                            init_gru_state, gru)
d2l.train_ch8(model, train_iter, vocab, lr, num_epochs, device)

输出结果:
perplexity 1.1, 23537.9 tokens/sec on cpu
time traveller for so it will be convenient to speak of himwas e
travelleryou can show black is white by argument said filby

[简洁实现]

高级API包含了前文介绍的所有配置细节, 所以我们可以直接实例化门控循环单元模型。 这段代码的运行速度要快得多, 因为它使用的是编译好的运算符而不是Python来处理之前阐述的许多细节。

num_inputs = vocab_size
gru_layer = nn.GRU(num_inputs, num_hiddens)
model = d2l.RNNModel(gru_layer, len(vocab))
model = model.to(device)
d2l.train_ch8(model, train_iter, vocab, lr, num_epochs, device)

输出结果:
perplexity 1.0, 39868.2 tokens/sec on cpu
time traveller for so it will be convenient to speak of himwas e
travelleryou can show black is white by argument said filby

小结

  • 门控循环神经网络可以更好地捕获时间步距离很长的序列上的依赖关系。
  • 重置门有助于捕获序列中的短期依赖关系。
  • 更新门有助于捕获序列中的长期依赖关系。
  • 重置门打开(R=1)时,门控循环单元包含基本循环神经网络;更新门打开(Z=1)时,门控循环单元可以跳过子序列。

练习

  1. 假设我们只想使用时间步 t' 的输入来预测时间步 t > t' 的输出。对于每个时间步,重置门和更新门的最佳值是什么?
    解:
    对于重置门 
    \mathbf{R}_t 中所有接近0的项,候选隐状态是以 \mathbf{X}_t 作为输入的多层感知机的结果。
    当 
    \mathbf{Z}_t 接近0时,新的隐状态 \mathbf{H}_t 就会接近候选隐状态 \tilde{\mathbf{H}}_t
    因此,当只想使用时间步
    t′的输入来预测时间步 t > t' 的输出时,\mathbf{R}_t 和 \mathbf{Z}_t 的最佳值均为0。
  2. 调整和分析超参数对运行时间、困惑度和输出顺序的影响。
    解:
    超参数包括:
  • 批量大小 batch_size,由下面代码试验结果0和1比较可以看出:batch_size增加会增加运行时间,并大大增加困惑度。
  • 批量步长 num_steps,由下面代码试验结果0和2比较可以看出:num_steps降低会略增加运行时间,但困惑度降为最低。
  • 隐藏层数 num_hiddens,由下面代码试验结果0和3比较可以看出:num_hiddens增加会大大增加运行时间,但困惑度同样能将为最低。
  • 迭代次数 num_epochs,这个可以从运行结果图中直接看出:epochs越大,运行时间越长;如果epochs过低,则模型无法完成收敛,困惑度不能有效降低,因此,需要保证足够的epochs。下面代码不做epochs的调整。
  • 学习率 lr,由下面代码试验结果0和4比较可以看出:learning rate降低会导致模型无法完成收敛,困惑度很高。

代码如下:

import time

# 单一变量依次调整 batch_size, num_steps, num_hiddens, lr
hyper_0 = [32, 35, 256, 1] # 初始值
hyper_1 = [64, 35, 256, 1]
hyper_2 = [32, 10, 256, 1]
hyper_3 = [32, 35, 512, 1]
hyper_4 = [32, 35, 256, 0.1]
hyper_params = [hyper_0, hyper_1, hyper_2, hyper_3, hyper_4]

def train_ch9_1(net, train_iter, vocab, lr, num_epochs, device,
              use_random_iter=False):
    loss = nn.CrossEntropyLoss()
    # 初始化
    if isinstance(net, nn.Module):
        updater = torch.optim.SGD(net.parameters(), lr)
    else:
        updater = lambda batch_size: d2l.sgd(net.params, lr, batch_size)
    predict = lambda prefix: d2l.predict_ch8(prefix, 50, net, vocab, device)
    # 训练和预测
    for epoch in range(num_epochs):
        ppl, _ = d2l.train_epoch_ch8(
            net, train_iter, loss, updater, device, use_random_iter)
    print(predict('time traveller'))
    print(predict('traveller'))
    return ppl 

ppls = []
run_times = []

for i, hyper in enumerate(hyper_params):
    num_epochs = 500
    batch_size, num_steps, num_hiddens, lr = hyper
    train_iter, vocab = d2l.load_data_time_machine(batch_size, num_steps)
    vocab_size, device = len(vocab), d2l.try_gpu()
    model = d2l.RNNModelScratch(len(vocab), num_hiddens, device, get_params,
                            init_gru_state, gru)
    print(f'hyper_{i}:')
    print(f'When batch_size = {hyper[0]}, num_steps = {hyper[1]}, num_hiddens = {hyper[2]}, lr = {hyper[3]}:')
    start = time.time()
    ppl = train_ch9_1(model, train_iter, vocab, lr, num_epochs, device)
    end = time.time()
    run_time = end - start
    print(f'困惑度 {ppl:.1f}, {run_time:.1f} 秒')

    ppls.append(ppl)
    run_times.append(run_time)

输出结果:
hyper_0:
When batch_size = 32, num_steps = 35, num_hiddens = 256, lr = 1:
time travelleryou can show black is white by argument said filby
traveller with a slight accession ofcheerfulness really thi
困惑度 1.1, 206.8 秒
hyper_1:
When batch_size = 64, num_steps = 35, num_hiddens = 256, lr = 1:
time traveller that is and the pald the per and and the pald the
traveller that is and the pald the per and and the pald the
困惑度 4.8, 336.2 秒
hyper_2:
When batch_size = 32, num_steps = 10, num_hiddens = 256, lr = 1:
time travelleryou can show black is white by argument said filby
travelleryou can show black is white by argument said filby
困惑度 1.0, 242.9 秒
hyper_3:
When batch_size = 32, num_steps = 35, num_hiddens = 512, lr = 1:
time traveller for so it will be convenient to speak of himwas e
travelleryou can show black is white by argument said filby
困惑度 1.0, 749.2 秒
hyper_4:
When batch_size = 32, num_steps = 35, num_hiddens = 256, lr = 0.1:
time travellere the the the the the the the the the the the the
travellere the the the the the the the the the the the the
困惑度 10.3, 208.9 秒

import matplotlib.pyplot as plt

fig, ax1 = plt.subplots(figsize=(8, 6))
ax2 = ax1.twinx()
ax1.bar([0, 1, 2, 3, 4], ppls, alpha=0.8)
ax1.set_ylim()
ax1.set_xlabel('No. hyper_params')
ax1.set_ylabel('Perplexity')
ax2.plot([0, 1, 2, 3, 4], run_times, linewidth='2', color = 'darkred')
ax2.set_ylabel('Run_time')
ax2.set_ylim()
plt.plot(0, 0, linewidth='2', color = 'darkred', label="Run_time")
plt.bar(0, 0, alpha=0.8, label="Perplexity")
plt.legend(loc='upper left', frameon=False)
plt.show()

3. 比较rnn.RNNrnn.GRU的不同实现对运行时间、困惑度和输出字符串的影响。
解:
8.6节应用RNN的运行结果为:
perplexity 1.3, 79579.9 tokens/sec
time traveller after the pauserequired for the prathere for anou
traveller bat no sime soc ans have a dimentab incane round ;
本节应用GRU的运行结果为:
perplexity 1.0, 39699.2 tokens/sec
time travelleryou can show black is white by argument said filby
traveller with a slight accession ofcheerfulness really thi;
由上可见,GRU由于增加了权重更新的参数和计算量,运行时间变慢,但同时GRU的网络结构优化也降低了困惑度(从1.3降到最佳的1.0),输出的字符串也更加准确合理。

4. 如果仅仅实现门控循环单元的一部分,例如,只有一个重置门或一个更新门会怎样?
解:
重置门赋予了GRU的遗忘机制,其作用是确定当前输入对单元状态的影响程度,允许网络忽略与当前任务无关的过去信息,也即重置前一时刻的隐状态H_{t-1}。只有重置门,网络会无法有效地处理长期依赖关系,因为单元状态可能会在不适当的时间被重置,或者无法适应新的输入。
更新门赋予了GRU的关注机制,其作用是控制单元状态的更新程度,决定了网络如何结合新的输入信息和保留的旧信息。只有更新门,网络会无法有效地处理短期依赖关系,因为更新门无法决定忽略哪些过去信息。
比较代码如下:

# 只有一个重置门
def get_params_reset(vocab_size, num_hiddens, device):
    num_inputs = num_outputs = vocab_size

    def normal(shape):
        return torch.randn(size=shape, device=device)*0.01

    def two():
        return (normal((num_inputs, num_hiddens)),
                normal((num_hiddens, num_hiddens)),
                torch.zeros(num_hiddens, device=device))

    W_xr, W_hr, b_r = two()  # 重置门参数
    W_xh, W_hh, b_h = two()  # 候选隐状态参数
    # 输出层参数
    W_hq = normal((num_hiddens, num_outputs))
    b_q = torch.zeros(num_outputs, device=device)
    # 附加梯度
    params = [W_xr, W_hr, b_r, W_xh, W_hh, b_h, W_hq, b_q]
    for param in params:
        param.requires_grad_(True)
    return params

def gru_only_reset(inputs, state, params):
    W_xr, W_hr, b_r, W_xh, W_hh, b_h, W_hq, b_q = params
    H, = state
    outputs = []
    for X in inputs:
        R = torch.sigmoid((X @ W_xr) + (H @ W_hr) + b_r)
        H = torch.tanh((X @ W_xh) + ((R * H) @ W_hh) + b_h)
        Y = H @ W_hq + b_q
        outputs.append(Y)
    return torch.cat(outputs, dim=0), (H,)

vocab_size, num_hiddens, device = len(vocab), 256, d2l.try_gpu()
num_epochs, lr = 500, 1
model = d2l.RNNModelScratch(len(vocab), num_hiddens, device, get_params_reset,
                            init_gru_state, gru_only_reset)
d2l.train_ch8(model, train_iter, vocab, lr, num_epochs, device)

输出结果:
perplexity 1.0, 28502.0 tokens/sec on cpu
time travelleryou can show black is white by argument said filby
travelleryou can show black is white by argument said filby

# 只有一个更新门
def get_params_Z(vocab_size, num_hiddens, device):
    num_inputs = num_outputs = vocab_size

    def normal(shape):
        return torch.randn(size=shape, device=device)*0.01

    def two():
        return (normal((num_inputs, num_hiddens)),
                normal((num_hiddens, num_hiddens)),
                torch.zeros(num_hiddens, device=device))

    W_xz, W_hz, b_z = two()  # 更新门参数
    W_xh, W_hh, b_h = two()  # 候选隐状态参数
    # 输出层参数
    W_hq = normal((num_hiddens, num_outputs))
    b_q = torch.zeros(num_outputs, device=device)
    # 附加梯度
    params = [W_xz, W_hz, b_z, W_xh, W_hh, b_h, W_hq, b_q]
    for param in params:
        param.requires_grad_(True)
    return params

def gru_only_Z(inputs, state, params):
    W_xz, W_hz, b_z, W_xh, W_hh, b_h, W_hq, b_q = params
    H, = state
    outputs = []
    for X in inputs:
        Z = torch.sigmoid((X @ W_xz) + (H @ W_hz) + b_z)
        H_tilda = torch.tanh((X @ W_xh) + (H @ W_hh) + b_h)
        H = Z * H + (1 - Z) * H_tilda
        Y = H @ W_hq + b_q
        outputs.append(Y)
    return torch.cat(outputs, dim=0), (H,)

vocab_size, num_hiddens, device = len(vocab), 256, d2l.try_gpu()
num_epochs, lr = 500, 1
model = d2l.RNNModelScratch(len(vocab), num_hiddens, device, get_params_Z,
                            init_gru_state, gru_only_Z)
d2l.train_ch8(model, train_iter, vocab, lr, num_epochs, device)

输出结果:

perplexity 1.0, 32176.4 tokens/sec on cpu
time traveller for so it will be convenient to speak of himwas e
traveller with a slight accession ofcheerfulness really thi

 

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

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

相关文章

K8S服务发布

一 、服务发布方式对比 二者主要区别在于: 1. 部署复杂性:传统的服务发布方式通常涉及手动配置 和管理服务器、网络设置、负载均衡等,过程相对复 杂且容易出错。相比之下,Kubernetes服务发布方式 通过使用容器编排和自动化部署工…

高灵敏度电容式触摸IC在弹簧触控按键中的应用

电容式触摸IC-弹簧触控按键-是通过检测人体与传感器之间的电容变化来实现触摸控制。这种技术具有高灵敏度、稳定性好、防水性强等优点,广泛应用于家用电器、消费电子、工业控制等领域。 弹簧触控按键的特点: 1. 高灵敏度:即使隔着绝缘材料&a…

Java语言的Springboot框架+云快充协议1.5+充电桩系统+新能源汽车充电桩系统源码

介绍 云快充协议云快充1.5协议云快充协议开源代码云快充底层协议云快充桩直连桩直连协议充电桩系统桩直连协议 有需者咨询,非诚勿扰; 软件架构 1、提供云快充底层桩直连协议,版本为云快充1.5,对于没有对接过充电桩系统的开发者…

[vulnhub] Jarbas-Jenkins

靶机链接 https://www.vulnhub.com/entry/jarbas-1,232/ 主机发现端口扫描 扫描网段存活主机,因为主机是我最后添加的,所以靶机地址是135的 nmap -sP 192.168.75.0/24 // Starting Nmap 7.93 ( https://nmap.org ) at 2024-09-21 14:03 CST Nmap scan…

求职Leetcode题目(11)

1.最长连续序列 解题思路: 方法一: • 首先对数组进行排序,这样我们可以直接比较相邻的元素是否连续。• 使用一个变量 cur_cnt 来记录当前的连续序列长度。• 遍历排序后的数组: 如果当前元素与前一个元素相等,则跳过&#xf…

文档矫正算法:DocTr++

文档弯曲矫正(Document Image Rectification)的主要作用是在图像处理领域中,对由于拍摄、扫描或打印过程中产生的弯曲、扭曲文档进行校正,使其恢复为平整、易读的形态。 一. 论文和代码 论文地址:https://arxiv.org/…

AI辅助编码工具如何影响着程序员开发群体

AI辅助编码工具的出现对程序员开发群体产生了深远的影响,有一些初步基础的程序员,可以借助AI工具的加持,生产效率大大提升,达到中高级程序员的水平。 这些影响可以从多个角度来分析: 提高开发效率: AI工具…

跳蚤市场小程序|基于微信小程序的跳蚤市场(源码+数据库+文档)

跳蚤市场小程序目录 基于微信小程序的饮品点单系统的设计与实现 一、前言 二、系统功能设计 三、系统实现 管理员功能实现 商品信息管理 商品订单管理 论坛管理 用户管理 5.1.5 新闻信息管理 用户功能实现 四、数据库设计 1、实体ER图 2、具体的表设计如下所示&a…

毕业设计选题:基于ssm+vue+uniapp的英语学习激励系统小程序

开发语言:Java框架:ssmuniappJDK版本:JDK1.8服务器:tomcat7数据库:mysql 5.7(一定要5.7版本)数据库工具:Navicat11开发软件:eclipse/myeclipse/ideaMaven包:M…

STM32引脚输入

文章目录 前言一、看原理图二、开始编程1.开启时钟2.配置GPIOA.0 上拉输入3.读取 GPIOA.0 引脚 GPIOA_IDR 0位上是1(按键松开),输入就是高电平,否则就是低电平(按键按下) 三、完整程序四 测试效果总结 前言…

Spring MVC的应用

目录 1、创建项目与maven坐标配置 2、核心配置 3、启动项目测试 4、不同请求参数在controller的配置 4.1 servlet API 4.2 简单类型 4.3 pojo类型 4.4 日期类型 4.5 restful风格4种操作类型 4.5.1 GET:获取资源 4.5.2 POST:新建资源 4.5.3 P…

【Godot4.3】自定义数列类NumList

概述 数列是一种特殊数组。之前写过等比、等差数列、斐波那契等数列的求取函数。今天就汇总到一起,并添加其他的一些数列,比如平方数、立方数、三角形数等。 这里我首先采用以前比较喜欢的静态函数库的写法,然后在其基础上改进为基于类继承…

基于飞腾平台的OpenCV的编译与安装

【写在前面】 飞腾开发者平台是基于飞腾自身强大的技术基础和开放能力,聚合行业内优秀资源而打造的。该平台覆盖了操作系统、算法、数据库、安全、平台工具、虚拟化、存储、网络、固件等多个前沿技术领域,包含了应用使能套件、软件仓库、软件支持、软件适…

ChatGPT 推出“Auto”自动模式:智能匹配你的需求

OpenAI 最近为 ChatGPT 带来了一项新功能——“Auto”自动模式,这一更新让所有用户无论使用哪种设备都能享受到更加个性化的体验。简单来说,当你选择 Auto 模式后,ChatGPT 会根据你输入的提示词复杂程度,自动为你挑选最适合的AI模…

解密 Python 的 staticmethod 函数:静态方法的全面解析!

更多Python学习内容:ipengtao.com 在 Python 中,staticmethod 函数是一种装饰器,用于将函数转换为静态方法。静态方法与实例方法和类方法不同,它们不需要类实例作为第一个参数,也不需要类作为第一个参数,因…

只用几行代码,不依赖任何框架?SMTFlow 轻松实现前端流程图

只用几行代码,不依赖任何框架?SMTFlow 轻松实现前端流程图! 在前端开发中,如果你需要一个简单好用的流程图设计工具,SMTFlow 绝对是你的不二之选!本文将介绍 SMTFlow 的核心功能、特点以及如何快速上手。 工…

C++中set和map的使用

1.关联式容器 序列式容器里存储的是元素本身&#xff0c;如vector、list、deque 关联式容器即&#xff0c;容器中存储<key&#xff0c;value>的键值对&#xff0c;树型结 构的关联式容器主要有四种&#xff1a;map、set、multimap、multiset。他们都使用平衡搜索树(即红…

项目实战:lngress搭建Nginx+WP论坛+MariaDB

1. 网站架构 本次部署形式完全舍弃 Docker&#xff0c;将所有应用都置于Kubernetes&#xff0c;采用 Deployment 而非单 Pod 部署&#xff0c;稳定性得到升级。 2. 部署 MariaDB [rootk8s-master ~]# mkdir tdr [rootk8s-master ~]# cd tdr/ &#xff08;1&#xff09;定义 …

Flowable7.0.1框架严重bug,流程跳转到指定节点导致流程中断

一、Bug描述 使用7.0.1版本的 moveActivityIdsToSingleActivityId 或 moveExecutionsToSingleActivityId实现节点跳转&#xff0c;程序不会报错&#xff0c;但是act_ru_task 没有生成新的任务&#xff0c;导致流程中断&#xff0c;这是相当严重的bug。 经过多次测试&#xff…

【LLM多模态】文生视频综述From Sora What We Can See: A Survey of Text-to-Video Generation

note 现在很多主流的文生视频应该还是Diffusion-based 基于扩散模型的方法这篇综述将现有研究按照三个维度进行分类&#xff1a;进化生成器&#xff08;Evolutionary Generators&#xff09;、卓越追求&#xff08;Excellent Pursuit&#xff09;、现实全景&#xff08;Realis…