2024/3/24周报

文章目录

  • 摘要
  • Abstract
  • 文献阅读
    • 题目
    • 引言
    • 创新点
    • 数据处理
      • 研究区域和数据
      • 缺失值处理
      • 水质相关分析
    • 方法和模型
      • LSTM
      • Attention机制
      • AT-LSTM模型
    • 实验结果
  • 深度学习transformer代码实现
    • 1 模型输入
      • 1.1 Embedding层
      • 1.2 位置编码
    • 2 Encoder
      • 2.1 编码器
      • 2.2 编码器层
      • 2.3注意力机制
      • 2.4多头注意力机制
    • 3 Decoder
      • 3.1 解码器整体结构
      • 3.2 解码器层
  • 总结

摘要

本周阅读了一篇基于LSTM和注意机制的水质预测的文章,以澳大利亚Burnett河为研究对象。本文利用LSTM和AT-LSTM模型对伯内特河溶解氧进行了一步预报和多步预报,并对预报结果进行了比较。研究结果表明,包含注意力机制提高了LSTM模型的预测性能。此外,还对自注意力机制等相关内容进行补充学习。

Abstract

This week, an article on water quality prediction based on LSTM and attention mechanism is readed. The author takes Burnett River in Australia as the research object. In this paper, LSTM and AT-LSTM models are used to make one-step and multi-step predictions of dissolved oxygen in Burnett River, and the prediction results are compared. The results show that including attention mechanism improves the prediction performance of LSTM model. In addition, self-attention mechanism and other related contents are supplemented.

文献阅读

题目

Water Quality Prediction Based on LSTM and Attention Mechanism: A Case Study of the Burnett River, Australia

引言

水质预测是指利用长期收集的水质数据,预测未来一段时间内可能出现的水质趋势。为提前评价水环境状况,预防水污染问题的大规模发生提供科学的决策依据。本研究以水质评价的关键参数溶解氧作为建模和预测评价的目标,在LSTM模型的基础上开发了一个AT-LSTM模型,重点是更好地捕捉水质变量。利用水质监测原始数据对澳大利亚伯内特河的溶解氧浓度进行了预测。

创新点

1) 本研究开发的模型在Burnett河断面水质数据特征提取后引入注意机制,考虑不同时刻序列对预测结果的影响,增强关键特征对预测结果的影响。
2) 本文利用LSTM和AT-LSTM模型对伯内特河溶解氧进行了一步预报和多步预测,并对预测结果进行了比较。

数据处理

研究区域和数据

本研究使用的数据是伯内特河自动监测站的水质数据,其位置和集水区边界如下图:
在这里插入图片描述

研究使用了2015年1月至2020年1月收集的伯内特河水质监测数据。数据每半小时收集一次,包括五个特征:水温(Temp)、pH值、溶解氧(DO)、电导率(EC)、叶绿素a(Chl-a)和浊度(NTU)。本文以39,752个特征的逐时水质数据和溶解氧作为输出变量:
在这里插入图片描述

溶解氧DO的变化如下所示:
在这里插入图片描述

缺失值处理

如果一次监测中只有一个指标缺失,则采用线性插值的方法进行数据填充。通过线性插值后,数据集成为等时间间隔的连续时间序列。

线性插值描述:假设在坐标(x0,y0)和坐标(x1,y1)之间存在缺失值(x,y),使用如下等式(1):
在这里插入图片描述

其中x是已知的,并且y的值如下等式(2)中获得:
在这里插入图片描述

如果连续缺失一个监测值,则删除监测时刻的数据,避免人为填充造成较大误差。

水质相关分析

使用皮尔逊相关系数描述变量之间的线性相关程度,如等式(3)所示:
在这里插入图片描述

本研究通过皮尔逊相关性检验,得出与水质预测指标DO相关的主要元素特征为pH、Chl-a和Temp。水质预测将把这些因子作为输入特征。

方法和模型

LSTM

LSTM网络适用于处理和预测时间序列中具有很长间隔和延迟的时间序列特征,在解决传统递归神经网络中容易出现的梯度消失和梯度爆炸问题方面也很有效。LSTM模型有一个输入门、一个输出门和一个遗忘门。
在这里插入图片描述
在这里插入图片描述

输入门和输出门主要用于控制输入特性和输出内容,而遗忘门主要用于决定存储单元中哪些存储器应该保留,哪些存储器可以遗忘。

Attention机制

在这里插入图片描述

注意力机制的本质是对于给定的目标,生成权重系数并与输入相乘,以识别输入中的哪些特征对目标重要,哪些特征不重要。

注意力的计算有三个步骤:第一步是计算Query和key之间的相似度以获得权重,常见的相似度函数有点积,拼接和感知器,第二步是使用softmax函数将这些权重归一化,第三步是将权重乘以相应的键值以获得最终的注意力。
计算权重系数W的公式如式(10)所示:
在这里插入图片描述

等式(11)将注意力权重系数W乘以值以获得包含注意力的输出a:
在这里插入图片描述

AT-LSTM模型

该模型的主要思想是通过对神经网络隐层元素进行自适应加权,减少无关因素对预测结果的影响,突出相关因素的影响,从而提高预测精度。模型框架如下图所示,主要组件是LSTM层和attention层。
在这里插入图片描述

模型结构和主要参数见下表:
在这里插入图片描述

实验结果

从下图中,可以看到AT-LSTM模型在Burnett River测试集的水质预测方面优于LSTM模型:
在这里插入图片描述

在图(b)中,蓝色曲线表示实际值,橙色曲线表示建模的预测值。虽然LSTM可以预测水质变化,但AT-LSTM的预测与实际值的差异较小,表明AT-LSTM的泛化能力比LSTM更强。
在这里插入图片描述

下表总结了LSTM和AT-LSTM模型在监测段中预测溶解氧DO任务的性能:
在这里插入图片描述

以下是两种模型多步预测结果的比较:
在这里插入图片描述

从这些表中可以看出,本文提出的方法在MAE,RMSE和R²等方面比起LSTM都有显著改善。

深度学习transformer代码实现

1 模型输入

输入部分包含两个模块,Embedding和Positional Encoding。

1.1 Embedding层

Embedding层的作用是将某种格式的输入数据,例如文本,转变为模型可以处理的向量表示,来描述原始数据所包含的信息。Embedding层输出的可以理解为当前时间步的特征,如果是文本任务,这里就可以是Word Embedding,如果是其他任务,就可以是任何合理方法所提取的特征。构建Embedding层的代码很简单,核心是借助torch提供的nn.Embedding,如下:

class Embeddings(nn.Module):def __init__(self, d_model, vocab):"""类的初始化函数d_model:指词嵌入的维度vocab:指词表的大小"""super(Embeddings, self).__init__()#之后就是调用nn中的预定义层Embedding,获得一个词嵌入对象self.lutself.lut = nn.Embedding(vocab, d_model)#最后就是将d_model传入类中self.d_model =d_modeldef forward(self, x):"""Embedding层的前向传播逻辑参数x:这里代表输入给模型的单词文本通过词表映射后的one-hot向量将x传给self.lut并与根号下self.d_model相乘作为结果返回"""embedds = self.lut(x)return embedds * math.sqrt(self.d_model)

1.2 位置编码

Positional Encodding位置编码的作用是为模型提供当前时间步的前后出现顺序的信息。

class PositionalEncoding(nn.Module):def __init__(self, d_model, dropout, max_len=5000):"""位置编码器类的初始化函数共有三个参数,分别是d_model:词嵌入维度dropout: dropout触发比率max_len:每个句子的最大长度"""super(PositionalEncoding, self).__init__()self.dropout = nn.Dropout(p=dropout)# Compute the positional encodings# 注意下面代码的计算方式与公式中给出的是不同的,但是是等价的,你可以尝试简单推导证明一下。# 这样计算是为了避免中间的数值计算结果超出float的范围,pe = torch.zeros(max_len, d_model)position = torch.arange(0, max_len).unsqueeze(1)div_term = torch.exp(torch.arange(0, d_model, 2) *-(math.log(10000.0) / d_model))pe[:, 0::2] = torch.sin(position * div_term)pe[:, 1::2] = torch.cos(position * div_term)pe = pe.unsqueeze(0)self.register_buffer('pe', pe)def forward(self, x):x = x + Variable(self.pe[:, :x.size(1)], requires_grad=False)return self.dropout(x)

2 Encoder

2.1 编码器

编码器作用是用于对输入进行特征提取,为解码环节提供有效的语义信息整体来看编码器由N个编码器层简单堆叠而成,因此实现非常简单,代码如下:

# 定义一个clones函数,来更方便的将某个结构复制若干份
def clones(module, N):"Produce N identical layers."return nn.ModuleList([copy.deepcopy(module) for _ in range(N)])class Encoder(nn.Module):"""EncoderThe encoder is composed of a stack of N=6 identical layers."""def __init__(self, layer, N):super(Encoder, self).__init__()# 调用时会将编码器层传进来,我们简单克隆N分,叠加在一起,组成完整的Encoderself.layers = clones(layer, N)self.norm = LayerNorm(layer.size)def forward(self, x, mask):"Pass the input (and mask) through each layer in turn."for layer in self.layers:x = layer(x, mask)return self.norm(x)

2.2 编码器层

class EncoderLayer(nn.Module):"EncoderLayer is made up of two sublayer: self-attn and feed forward"                                                                                                         def __init__(self, size, self_attn, feed_forward, dropout):super(EncoderLayer, self).__init__()self.self_attn = self_attnself.feed_forward = feed_forwardself.sublayer = clones(SublayerConnection(size, dropout), 2)self.size = size   # embedding's dimention of model, 默认512def forward(self, x, mask):# attention sub layerx = self.sublayer[0](x, lambda x: self.self_attn(x, x, x, mask))# feed forward sub layerz = self.sublayer[1](x, self.feed_forward)return z

2.3注意力机制

def attention(query, key, value, mask=None, dropout=None):"Compute 'Scaled Dot Product Attention'"#首先取query的最后一维的大小,对应词嵌入维度d_k = query.size(-1)#按照注意力公式,将query与key的转置相乘,这里面key是将最后两个维度进行转置,再除以缩放系数得到注意力得分张量scoresscores = torch.matmul(query, key.transpose(-2, -1)) / math.sqrt(d_k)#接着判断是否使用掩码张量if mask is not None:#使用tensor的masked_fill方法,将掩码张量和scores张量每个位置一一比较,如果掩码张量则对应的scores张量用-1e9这个置来替换scores = scores.masked_fill(mask == 0, -1e9)#对scores的最后一维进行softmax操作,使用F.softmax方法,这样获得最终的注意力张量p_attn = F.softmax(scores, dim = -1)#之后判断是否使用dropout进行随机置0if dropout is not None:p_attn = dropout(p_attn)#最后,根据公式将p_attn与value张量相乘获得最终的query注意力表示,同时返回注意力张量return torch.matmul(p_attn, value), p_attn

2.4多头注意力机制

class MultiHeadedAttention(nn.Module):def __init__(self, h, d_model, dropout=0.1):#在类的初始化时,会传入三个参数,h代表头数,d_model代表词嵌入的维度,dropout代表进行dropout操作时置0比率,默认是0.1super(MultiHeadedAttention, self).__init__()#在函数中,首先使用了一个测试中常用的assert语句,判断h是否能被d_model整除,这是因为我们之后要给每个头分配等量的词特征,也就是embedding_dim/head个assert d_model % h == 0#得到每个头获得的分割词向量维度d_kself.d_k = d_model // h#传入头数hself.h = h#创建linear层,通过nn的Linear实例化,它的内部变换矩阵是embedding_dim x embedding_dim,然后使用,为什么是四个呢,这是因为在多头注意力中,Q,K,V各需要一个,最后拼接的矩阵还需要一个,因此一共是四个self.linears = clones(nn.Linear(d_model, d_model), 4)#self.attn为None,它代表最后得到的注意力张量,现在还没有结果所以为Noneself.attn = Noneself.dropout = nn.Dropout(p=dropout)def forward(self, query, key, value, mask=None):#前向逻辑函数,它输入参数有四个,前三个就是注意力机制需要的Q,K,V,最后一个是注意力机制中可能需要的mask掩码张量,默认是Noneif mask is not None:# Same mask applied to all h heads.#使用unsqueeze扩展维度,代表多头中的第n头mask = mask.unsqueeze(1)#接着,我们获得一个batch_size的变量,他是query尺寸的第1个数字,代表有多少条样本nbatches = query.size(0)# 1) Do all the linear projections in batch from d_model => h x d_k # 首先利用zip将输入QKV与三个线性层组到一起,然后利用for循环,将输入QKV分别传到线性层中,做完线性变换后,开始为每个头分割输入,这里使用view方法对线性变换的结构进行维度重塑,多加了一个维度h代表头,这样就意味着每个头可以获得一部分词特征组成的句子,其中的-1代表自适应维度,计算机会根据这种变换自动计算这里的值,然后对第二维和第三维进行转置操作,为了让代表句子长度维度和词向量维度能够相邻,这样注意力机制才能找到词义与句子位置的关系,从attention函数中可以看到,利用的是原始输入的倒数第一和第二维,这样我们就得到了每个头的输入query, key, value = \[l(x).view(nbatches, -1, self.h, self.d_k).transpose(1, 2)for l, x in zip(self.linears, (query, key, value))]# 2) Apply attention on all the projected vectors in batch. # 得到每个头的输入后,接下来就是将他们传入到attention中,这里直接调用我们之前实现的attention函数,同时也将mask和dropout传入其中x, self.attn = attention(query, key, value, mask=mask, dropout=self.dropout)# 3) "Concat" using a view and apply a final linear. # 通过多头注意力计算后,我们就得到了每个头计算结果组成的4维张量,我们需要将其转换为输入的形状以方便后续的计算,因此这里开始进行第一步处理环节的逆操作,先对第二和第三维进行转置,然后使用contiguous方法。这个方法的作用就是能够让转置后的张量应用view方法,否则将无法直接使用,所以,下一步就是使用view重塑形状,变成和输入形状相同。  x = x.transpose(1, 2).contiguous() \.view(nbatches, -1, self.h * self.d_k)#最后使用线性层列表中的最后一个线性变换得到最终的多头注意力结构的输出return self.linears[-1](x)

3 Decoder

3.1 解码器整体结构

#使用类Decoder来实现解码器
class Decoder(nn.Module):"Generic N layer decoder with masking."def __init__(self, layer, N):#初始化函数的参数有两个,第一个就是解码器层layer,第二个是解码器层的个数Nsuper(Decoder, self).__init__()#首先使用clones方法克隆了N个layer,然后实例化一个规范化层,因为数据走过了所有的解码器层后最后要做规范化处理。self.layers = clones(layer, N)self.norm = LayerNorm(layer.size)def forward(self, x, memory, src_mask, tgt_mask):#forward函数中的参数有4个,x代表目标数据的嵌入表示,memory是编码器层的输出,source_mask,target_mask代表源数据和目标数据的掩码张量,然后就是对每个层进行循环,当然这个循环就是变量x通过每一个层的处理,得出最后的结果,再进行一次规范化返回即可。for layer in self.layers:x = layer(x, memory, src_mask, tgt_mask)return self.norm(x)

3.2 解码器层

每个解码器层由三个子层连接结构组成,第一个子层连接结构包括一个多头自注意力子层和规范化层以及一个残差连接,第二个子层连接结构包括一个多头注意力子层和规范化层以及一个残差连接,第三个子层连接结构包括一个前馈全连接子层和规范化层以及一个残差连接。

#使用DecoderLayer的类实现解码器层
class DecoderLayer(nn.Module):"Decoder is made of self-attn, src-attn, and feed forward (defined below)"def __init__(self, size, self_attn, src_attn, feed_forward, dropout):#初始化函数的参数有5个,分别是size,代表词嵌入的维度大小,同时也代表解码器的尺寸,第二个是self_attn,多头自注意力对象,也就是说这个注意力机制需要Q=K=V,第三个是src_attn,多头注意力对象,这里Q!=K=V,第四个是前馈全连接层对象,最后就是dropout置0比率super(DecoderLayer, self).__init__()self.size = sizeself.self_attn = self_attnself.src_attn = src_attnself.feed_forward = feed_forward#按照结构图使用clones函数克隆三个子层连接对象self.sublayer = clones(SublayerConnection(size, dropout), 3)def forward(self, x, memory, src_mask, tgt_mask):#forward函数中的参数有4个,分别是来自上一层的输入x,来自编码器层的语义存储变量memory,以及源数据掩码张量和目标数据掩码张量,将memory表示成m之后方便使用。"Follow Figure 1 (right) for connections."m = memory#将x传入第一个子层结构,第一个子层结构的输入分别是x和self-attn函数,因为是自注意力机制,所以Q,K,V都是x,最后一个参数时目标数据掩码张量,这时要对目标数据进行遮掩,因为此时模型可能还没有生成任何目标数据。#比如在解码器准备生成第一个字符或词汇时,我们其实已经传入了第一个字符以便计算损失,但是我们不希望在生成第一个字符时模型能利用这个信息,因此我们会将其遮掩,同样生成第二个字符或词汇时,模型只能使用第一个字符或词汇信息,第二个字符以及之后的信息都不允许被模型使用。x = self.sublayer[0](x, lambda x: self.self_attn(x, x, x, tgt_mask))#接着进入第二个子层,这个子层中常规的注意力机制,q是输入x;k,v是编码层输出memory,同样也传入source_mask,但是进行源数据遮掩的原因并非是抑制信息泄露,而是遮蔽掉对结果没有意义的padding。x = self.sublayer[1](x, lambda x: self.src_attn(x, m, m, src_mask))#最后一个子层就是前馈全连接子层,经过它的处理后就可以返回结果,这就是我们的解码器结构return self.sublayer[2](x, self.feed_forward)

以下搭建出整个网络的结构:

# Model Architecture
#使用EncoderDecoder类来实现编码器-解码器结构
class EncoderDecoder(nn.Module):"""A standard Encoder-Decoder architecture. Base for this and many other models."""def __init__(self, encoder, decoder, src_embed, tgt_embed, generator):#初始化函数中有5个参数,分别是编码器对象,解码器对象,源数据嵌入函数,目标数据嵌入函数,以及输出部分的类别生成器对象.super(EncoderDecoder, self).__init__()self.encoder = encoderself.decoder = decoderself.src_embed = src_embed    # input embedding module(input embedding + positional encode)self.tgt_embed = tgt_embed    # ouput embedding moduleself.generator = generator    # output generation moduledef forward(self, src, tgt, src_mask, tgt_mask):"Take in and process masked src and target sequences."#在forward函数中,有四个参数,source代表源数据,target代表目标数据,source_mask和target_mask代表对应的掩码张量,在函数中,将source source_mask传入编码函数,得到结果后与source_mask target 和target_mask一同传给解码函数memory = self.encode(src, src_mask)res = self.decode(memory, src_mask, tgt, tgt_mask)return resdef encode(self, src, src_mask):#编码函数,以source和source_mask为参数,使用src_embed对source做处理,然后和source_mask一起传给self.encodersrc_embedds = self.src_embed(src)return self.encoder(src_embedds, src_mask)def decode(self, memory, src_mask, tgt, tgt_mask):#解码函数,以memory即编码器的输出,source_mask target target_mask为参数,使用tgt_embed对target做处理,然后和source_mask,target_mask,memory一起传给self.decodertarget_embedds = self.tgt_embed(tgt)return self.decoder(target_embedds, memory, src_mask, tgt_mask)# Full Model
def make_model(src_vocab, tgt_vocab, N=6, d_model=512, d_ff=2048, h=8, dropout=0.1):"""构建模型params:src_vocab:tgt_vocab:N: 编码器和解码器堆叠基础模块的个数d_model: 模型中embedding的size,默认512d_ff: FeedForward Layer层中embedding的size,默认2048h: MultiHeadAttention中多头的个数,必须被d_model整除dropout:"""c = copy.deepcopyattn = MultiHeadedAttention(h, d_model)ff = PositionwiseFeedForward(d_model, d_ff, dropout)position = PositionalEncoding(d_model, dropout)model = EncoderDecoder(Encoder(EncoderLayer(d_model, c(attn), c(ff), dropout), N),Decoder(DecoderLayer(d_model, c(attn), c(attn), c(ff), dropout), N),nn.Sequential(Embeddings(d_model, src_vocab), c(position)),nn.Sequential(Embeddings(d_model, tgt_vocab), c(position)),Generator(d_model, tgt_vocab))# This was important from their code. # Initialize parameters with Glorot / fan_avg.for p in model.parameters():if p.dim() > 1:nn.init.xavier_uniform_(p)return model

下面用一个人造的玩具级的小任务,来实战体验下Transformer的训练,加深理解,并且验证代码是否work。任务描述:针对数字序列进行学习,学习的最终目标是使模型学会输出与输入的序列删除第一个字符之后的相同的序列,如输入[1,2,3,4,5],尝试让模型学会输出[2,3,4,5]:
训练大致流程如下:

# Train the simple copy task.
device = "cuda"
nrof_epochs = 20
batch_size = 32
V = 11    # 词典的数量
sequence_len = 15  # 生成的序列数据的长度
nrof_batch_train_epoch = 30    # 训练时每个epoch多少个batch                                                                                                                       
nrof_batch_valid_epoch = 10    # 验证时每个epoch多少个batch
criterion = LabelSmoothing(size=V, padding_idx=0, smoothing=0.0)
model = make_model(V, V, N=2)
optimizer = torch.optim.Adam(model.parameters(), lr=0, betas=(0.9, 0.98), eps=1e-9)
model_opt = NoamOpt(model.src_embed[0].d_model, 1, 400, optimizer)
if device == "cuda":model.cuda()for epoch in range(nrof_epochs):print(f"\nepoch {epoch}")print("train...")model.train()data_iter = data_gen(V, sequence_len, batch_size, nrof_batch_train_epoch, device)   loss_compute = SimpleLossCompute(model.generator, criterion, model_opt)train_mean_loss = run_epoch(data_iter, model, loss_compute, device)print("valid...")model.eval()valid_data_iter = data_gen(V, sequence_len, batch_size, nrof_batch_valid_epoch, device)valid_loss_compute = SimpleLossCompute(model.generator, criterion, None)valid_mean_loss = run_epoch(valid_data_iter, model, valid_loss_compute, device)print(f"valid loss: {valid_mean_loss}")

训好模型后,使用贪心解码的策略,进行预测。
运行训练脚本,训练过程与预测结果打印如下:
在这里插入图片描述
测试用例[1,2,3,4,5,6,7,8,9,10] 的预测结果为[2,3,4,5,6,7,8,9,10],符合预期。

总结

Transformer 突破了 RNN 模型不能并行计算的限制,CNN需要增加卷积层数来扩大视野,RNN需要从1到n逐个进行计算,而self-attention只需要一步矩阵计算就可以。所以也可以看出,self-attention可以比rnn更好地解决长时依赖问题。自注意力可以产生更具可解释性的模型,self-attention模型更可解释,attention结果的分布表明了该模型学习到了一些语法和语义信息,我们可以从模型中检查注意力分布,各个注意头(attention head)可以学会执行不同的任务,有更强的建模能力。Transformer 通过验证的哲学来建立图节点之间的关系,具有较好的通用性:无论节点多么异构,它们之间的关系都可以通过投影到一个可以比较的空间里计算相似度来建立,在大模型和大数据方面展示了强大的可扩展性。

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

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

相关文章

第五讲 哈希表

我们在前面讲了存储层,以及从次磁盘中将页面加载到缓冲池【Buffer Pool】中,现在我们继续往上,来讨论如何支持 DBMS 的执行引擎从页面中读取/写入数据。这部分是访问方法层的功能,它负责通过索引或者表本身,设置是其他…

生物信息学文章中常见的图应该怎么看?

目录 火山图 热图 箱线图 森林图 LASSO回归可视化图(套索图) 交叉验证图 PCA图 ROC曲线图 这篇文章只介绍这些图应该怎么解读,具体怎么绘制,需要什么参数,怎么处理数据,会在下一篇文章里面给出 火山…

python之jsonpath的使用

文章目录 介绍安装语法语法规则举例说明 在 python 中使用获取所有结构所有子节点的作者获取所有子孙节点获取所有价格取出第三本书的所有信息取出价格大于70块的所有书本从mongodb 中取数据的示例 介绍 JSONPath能在复杂的JSON数据中 查找和提取所需的信息,它是一…

Java设计模式之单例模式(多种实现方式)

虽然写了很多年代码,但是说真的对设计模式不是很熟练,虽然平时也会用到一些,但是都没有深入研究过,所以趁现在有空练下手 这章主要讲单例模式,也是最简单的一种模式,但是因为spring中bean的广泛应用&#…

YoloV8改进策略:BackBone改进|PKINet

摘要 PKINet是面向遥感旋转框的主干,网络包含了CAA、PKI等模块,给我们改进卷积结构的模型带来了很多启发。本文,使用PKINet替代YoloV8的主干网络,实现涨点。PKINet是我在作者的模型基础上,重新修改了底层的模块,方便大家轻松移植到YoloV8上。 论文:《Poly Kernel Ince…

计算机三级网络技术 选择+大题234笔记

上周停去准备计算机三级的考试啦,在考场上看到题目就知道这次稳了!只有一周的时间,背熟笔记,也能稳稳考过计算机三级网络技术!

鸿蒙开发学习:【华为支付服务客户端案例】

简介 华为应用内支付服务(HUAWEI In-App Purchases)支持3种商品,包括消耗型商品、非消耗型商品和订阅型商品。 消耗商品:仅能使用一次,消耗使用后即刻失效,需再次购买。非消耗商品:一次性购买…

计算机常见的知识点(3)

计算机系统 系统的构成 一个完整的计算机系统是由硬件和软件组成 硬件是由运算器、控制器、存储器、输入设备、输出设备五部分组成 其中:中央处理器(简称CPU)运算器控制器 主机中央处理器主存储器 计算机软件包括计算机本身运行所需要的系统软件和用户完成任务…

Mybatis中显示插入数据成功,但在数据库中却没有显示插入的数据

1、在mybatis-config.xml中查看是否添加了JDBC,并引入了映射文件 2、在测试文件中,结尾是否添加提交事务:sqlSession.commit() 添加了这一步就能够将数据提交到数据库中,最后再关闭事务:sqlSession.close() * 如果运…

JWT原理分析

为什么会有JWT的出现? 首先不得不提到一个知识叫做跨域身份验证,JWT的出现就是为了更好的解决这个问题,但是在没有JWT的时候,我们一般怎么做呢?一般使用Cookie和Session,流程大体如下所示: 用…

手撕算法-买卖股票的最佳时机 II(买卖多次)

描述 分析 使用动态规划。dp[i][0] 代表 第i天没有股票的最大利润dp[i][1] 代表 第i天持有股票的最大利润 状态转移方程为:dp[i][0] max(dp[i-1][0], dp[i-1][1] prices[i]); // 前一天没有股票,和前一天有股票今天卖掉的最大值dp[i][1] max(dp[i-1…

Linux查看磁盘空间

查看磁盘空间 df -h 查看目录所占空间 du -sh [目录] 查看当前目录下, 所有目录所占空间 (一级目录) find . -maxdepth 1 -type d -exec du -sh {} \;-maxdepth 1 查看的目录深度是1级, 2则是2级

FOCUS-AND-DETECT: A SMALL OBJECTDETECTION FRAMEWORK FOR AERIAL IMAGES

摘要 为了解决小对象检测问题,提出了一个叫做 Focus-and Detect 的检测框架,它是一个两阶段的框架。 第 一阶段包括由高斯混合模型监督的对象检测器网络,生成构成聚焦区域的对象簇 。 第二阶段 也是一个物体探测器网络,预测聚焦…

【云开发笔记No.6】腾讯CODING平台

腾讯云很酷的一个应用,现在对于研发一体化,全流程管理,各种工具层出不穷。 云时代用云原生,再加上AI,编码方式真是发生了质的变化。 从前,一个人可以写一个很酷的软件,后来,这变得…

<商务世界>《第16课 餐桌礼仪之座次》

1 简要 我国自古以来就很重视座位礼仪,非讲究,分君臣、分宾主、分方位等等而今座位礼仪已经简化为: 以“中”为尊: 中心为尊,突出主位。 以“右”为尊: 从历史上到国际上都是以右为尊。 以“内”为尊&…

故障诊断模型 | 基于图卷积网络的轴承故障诊断

文章目录 文章概述模型描述模型描述参考资料文章概述 故障诊断模型 | 基于图卷积网络的轴承故障诊断 模型描述 针对基于图卷积网络(GCN)的故障诊断方法大多默认节点间的权重相同、导致诊断精度较低与鲁棒性较差的问题,提出了一种基于欧式距离和余弦距离的 GCN 故障诊断方法…

力扣热门算法题 62. 不同路径,66. 加一,67. 二进制求和

62. 不同路径,66. 加一,67. 二进制求和,每题做详细思路梳理,配套Python&Java双语代码, 2024.03.21 可通过leetcode所有测试用例。 目录 62. 不同路径 解题思路 完整代码 Python Java 66. 加一 解题思路 …

29-goto语句

29-1 goto语句介绍 C语言中提供了可以随意滥用的goto语句和标记跳转的标号。 从理论上goto语句是没有必要的,实践中没有goto语句也可以很容易的写出代码。 但是某些场合下goto语句还是用得着的,最常见的用法就是终止程序在某些深度嵌套的结构的处理过程…

第十一届蓝桥杯大赛第二场省赛试题 CC++ 研究生组-回文日期

solution1&#xff08;通过50%&#xff09; #include<stdio.h> void f(int a){int t a;while(a){printf("%d", a % 10);a / 10;}if(t < 10) printf("0"); } int isLeap(int n){if(n % 400 0 || (n % 4 0 && n % 100 ! 0)) return 1;r…

抖音IP属地怎么更改

抖音是一个非常受欢迎的短视频平台&#xff0c;吸引了无数用户在上面分享自己的生活和才艺。然而&#xff0c;随着快手的火爆&#xff0c;一些用户开始担心自己的IP地址会被他人获取&#xff0c;引起个人隐私风险。那么&#xff0c;抖音用户又该如何更改到别的地方呢&#xff1…