机器学习周记(第四十三周:MCformer)2024.6.10~2024.6.16

news2024/11/26 1:26:18

目录

  • 摘要
  • ABSTRACT
  • 1 论文信息
    • 1.1 论文标题
    • 1.2 论文摘要
    • 1.3 论文引言
    • 1.4 论文贡献
  • 2 论文模型
    • 2.1 问题定义
    • 2.2 可逆实例归一化(Reversible Instance Normalization)
    • 2.3 混合通道块 (Mixed-Channels Block)
    • 2.4 编码器(Decoder)
  • 3 相关代码

摘要

本周阅读了一篇关于多变量时间序列的论文。论文模型 MCformer 结合了 CI 策略的数据扩展优势,同时减轻了通道间相关性遗忘的问题。MCformer 使用了一种称为混合通道模块的方法,以增强多变量时间序列数据集的表示能力,同时使用原生的 Transformer 编码器来建模序列的长期和跨变量特征。实验结果表明,在多变量时间序列预测任务中,混合通道策略优于纯 CI 策略。

ABSTRACT

This week, We read a paper on multivariate time series. The paper’s model, MCformer, combines the data expansion advantages of the CI strategy while alleviating the issue of inter-channel correlation forgetting. MCformer employs a method called the Mixed Channels module to enhance the representational capacity of multivariate time series datasets, and it uses a native Transformer encoder to model both long-term and cross-variable features of the sequence. Experimental results demonstrate that the Mixed Channels strategy outperforms the pure CI strategy in multivariate time series forecasting tasks.

1 论文信息

1.1 论文标题

MCformer: Multivariate Time Series Forecasting with Mixed-Channels Transformer

1.2 论文摘要

大规模物联网(IoT)设备会生成大量时间序列数据,迫使人们探索更有效的多变量时间序列预测模型。在以前的模型中,主要采用的是通道依赖(CD)策略(其中每个通道代表一个单变量序列)。当前最先进的(SOTA)模型主要依赖于通道独立(CI)策略。CI 策略将多通道序列视为独立的单通道序列,从而扩展数据集以提高泛化性能,并避免了破坏长期特征的通道间相关性。然而,CI 策略面临着通道间相关性遗忘的问题。为了解决这个问题,我们提出了一种创新的混合通道策略,该策略结合了 CI 策略的数据扩展优势,同时减轻了通道间相关性遗忘的问题。基于这种策略,论文引入了 MCformer,这是一种具有混合通道特征的多变量时间序列预测模型。该模型融合了特定数量的通道,利用注意力机制在建模长期特征时有效捕捉通道间的相关信息。实验结果表明,在多变量时间序列预测任务中,混合通道策略优于纯 CI 策略。

1.3 论文引言

随着 IoT 设备在气象学、交通和电力等领域的广泛应用,设备数量的增加也导致大量时间序列数据的生成。这些数据可以用于决策、资源分配以及预测未来趋势,从而提高物联网系统的效率和可靠性。源自 IoT 设备的时间序列预测任务旨在根据历史数据预测未来状态。鉴于物联网数据通常具有非线性、快速采样和多通道等特性,这一任务存在一定的挑战。

由于物联网设备生成的时间序列数据通常具有较长的采样间隔和多采样通道,在处理这些设备的多变量时间序列时,必须考虑长序列建模和多个通道之间的复杂相互关系。鉴于 Transformer 在自然语言处理领域中展示的长序列建模的杰出能力,这种能力在时间序列预测任务中也至关重要,促使了诸如 LogTransInformerReformerAutoformerFEDformerScaleFormerPyraformerFPPformer等模型的出现。这些模型在长时间序列建模方面取得了显著进展。

近年来,一些研究将重点转向多变量时间序列的挑战,例如 CrossformerSageFormer 等模型。这些模型在所有通道上进行学习,特别关注捕捉多个变量之间的依赖关系。所有这些模型都可以被视为通道依赖(CD)策略模型,其中将单变量序列视为一个通道。这种方法将多变量数据视为一个整体输入,并允许模型学习通道之间的相关性,如下图1所示。

然而,这些 CD 策略模型也存在局限性。DLinear 以其简单的架构超过了现有模型。PatchTST 引入了一种通道独立(CI)策略模型,进一步提升了最先进的水平(SOTA)。CI 策略将多变量时间序列数据视为独立的单变量序列,如下图1所示。CI策略的成功引起了人们对 CD 和 CI 策略对模型影响的关注,可见于 PRRegPETformerCSformeritransformer 等模型。随后,TiDE(一种基于MLP的CI模型) 不仅表现与PatchTST相似,而且在时空效率上表现出色。PETformer 的研究发现,通道独立优于通道依赖,可能是因为多变量特征会干扰长序列特征的提取。这一结果与直觉相悖,因为在深度学习中,更多的信息通常会提高模型的泛化能力。

总的来说,现有 SOTA 模型主要依赖 CI 策略有两个主要原因:首先,CI 策略可以扩展数据集以提高模型的泛化性能;其次,CI 策略可以避免因通道间相关信息而破坏长期特征信息,正如PETformer 所展示的。然而,CI 策略也有缺点,因为它倾向于忽略通道间的特征信息。在通道数量较多的情况下,可能会出现通道间相关性遗忘的问题,类似于 RNN 中的长期信息遗忘。在这种背景下,论文提出了一种混合通道策略。该策略保留了 CI 策略在数据集扩展方面的优势,同时通过选择性地混合有限数量的通道,有效地缓解了长期特征信息的破坏和过拟合问题,也解决了通道间相关性遗忘的问题。
在这里插入图片描述
上图1展示了 混合通道策略通道独立(CI)通道依赖(CD) 策略的区别。CD 策略通过考虑所有通道的历史数据来预测未来值,而 CI 策略则在预测未来值时不考虑其他通道的历史数据,且所有通道共享模型参数。与通道依赖策略和通道独立策略相比,混合通道策略保持了通道独立策略的优势,同时混合了有限数量的随机选择的通道,以增强模型捕捉通道间相关信息的能力。

基于上述策略,论文提出了一种具有混合通道特征的多通道时间序列预测模型。图2提供了该模型的概述。具体来说,论文的模型首先使用 CI 策略扩展数据,然后混合特定数量的通道,并允许注意力机制在建模长期特征信息时有效捕捉通道间的相关信息。最后,将编码器的结果还原以获得所有通道的预测值。
在这里插入图片描述

1.4 论文贡献

① 提出了一种混合通道策略,旨在最小化通道特征在 CD 策略下破坏长期信息的缺点,同时保留CI 策略下扩展数据集的优势。这使模型能够更有效地学习通道间的依赖信息。

② 基于混合通道策略,提出了一种具有混合通道特征的多变量时间序列预测模型。通过使用混合通道块,模型扩展了数据集,并通过混合方法整合了通道间的依赖信息。

2 论文模型

2.1 问题定义

在多变量时间序列预测任务中,历史观测值表示为 X = x 1 , x 2 , . . . , x t ∈ R t × M X={x_{1}, x_{2}, ..., x_{t}} \in \R^{t \times M} X=x1,x2,...,xtRt×M,其中 t 是时间步,M 是变量的数量。每个时间步 t 的观测值表示为一个 M 维向量: x t = [ x t 1 , x t 2 , . . . , x t M ] ⊤ x_{t}=[x_{t}^{1},x_{t}^{2},...,x_{t}^{M}]^{\top} xt=[xt1,xt2,...,xtM]。论文的目标是基于过去的观测值预测未来时间步的多变量观测值。这个问题可以形式化为:给定时间步 t 之前的观测序列 { x 1 , x 2 , . . . , x t } \{x_{1},x_{2},...,x_{t}\} {x1,x2,...,xt},预测时间步 t+1 到 t+h 的多变量观测序列 { x t + 1 , . . . , x t + h } \{x_{t+1},...,x_{t+h}\} {xt+1,...,xt+h},其中 h 是要预测的时间步数。论文将混合通道模块 (Mixed-Channels Block) 集成到基础 Transformer 编码器中,以扩展数据集并融合通道间的依赖信息。论文的 MCformer 模型的架构如下图3所示。
在这里插入图片描述

2.2 可逆实例归一化(Reversible Instance Normalization)

引入 可逆实例归一化(Reversible Instance Normalization,RevIN) 旨在解决训练和测试数据之间非均匀时间分布的问题,这通常被称为分布偏移。在混合通道模块之前,应用实例归一化来归一化每个通道的数据。对于每个实例 x t i x_{t}^{i} xti 的单个通道 x i = [ x 1 i , x 2 i , . . . , x t i ] x^{i}=[x_{1}^{i},x_{2}^{i},...,x_{t}^{i}] xi=[x1i,x2i,...,xti],计算其均值和标准差。在获得预测结果后,这些非平稳性信息组件会被加回到预测值中。

R e v I N ( x i ) = { γ i x i − M e a n ( x i ) V a r ( x i ) + ε } , i = 1 , 2 , . . . , M        ( 1 ) RevIN(x^{i})=\{\gamma_{i} \frac {x^{i}-Mean(x^{i}) }{\sqrt{Var}(x^{i})+\varepsilon} \}, i=1,2,...,M\ \ \ \ \ \ (1) RevIN(xi)={γiVar (xi)+εxiMean(xi)},i=1,2,...,M      (1)

2.3 混合通道块 (Mixed-Channels Block)

论文引入了一种称为混合通道模块的方法,以增强多变量时间序列数据集的表示能力。

Flatten: 论文采用通道独立(CI)策略,将来自 M 个通道的数据展平。对于给定的样本 X,展平后得到 X F = F l a t t e n ( X ) ∈ R t M × 1 X_F=Flatten(X) \in \R ^{tM \times1} XF=Flatten(X)RtM×1。然后将展平后的 X F X_F XF 视为M个独立的样本。

Mixed Channels: Mixed-Channels Block是在 Flatten 之后将不同通道的数据进行组合,通过以下步骤执行混合通道操作:

  1. 计算区间大小: 首先计算区间大小 ⌊ M m ⌋ \lfloor \frac M m \rfloor mM,其中 m 是要混合的通道数。

  2. 混合通道操作: 对于给定的时间步 t,从目标通道开始,以区间步长堆叠其他所有通道来形成 U i ∈ R t × m U^i \in \R^{t \times m} UiRt×m。具体而言,混合通道模块的输出定义为:

U i = M i x e d C h a n n e l s ( x i , m ) = [ s t a c k ( x i , C 1 , C 2 , . . . , C m ) ]        ( 2 ) U^{i}=MixedChannels(x^{i},m)=[stack(x^{i},C^{1},C^{2},...,C^{m})]\ \ \ \ \ \ (2) Ui=MixedChannels(xi,m)=[stack(xi,C1,C2,...,Cm)]      (2)

其中, C i C^{i} Ci 表示在第 i 个间隔处获取的第 i 个通道,1 ≤ i ≤ m。通过引入混合通道模块,其目的是增加输入数据的表示能力,加入多通道信息,以更好地捕捉时间序列数据的特征。

补丁和投影: 在当前的研究中,已经观察到,相比于使用时间点数据作为输入,使用补丁可以更好地捕捉局部信息,并且捕捉到更丰富的变量间依赖关系。因此,利用补丁在混合通道后聚合序列,并采用单层 MLP 来投影通道依赖性以及相邻的时间依赖性。表示为:

P i = P r o j e c t i o n ( P a t c h ( U i ) )        ( 3 ) P^{i}=Projection(Patch(U^{i}))\ \ \ \ \ \ (3) Pi=Projection(Patch(Ui))      (3)

这里 P i ∈ R P × N P^{i}\in\R^{P \times N} PiRP×N ,其中P表示投影后的长度,补丁的数量为 N, N = ⌊ ( L − p ) S ⌋ + 2 N=\lfloor \frac{(L-p)}{S} \rfloor+ 2 N=S(Lp)+2,p 表示补丁的长度,S 表示步长。使用补丁的方法可以保留时间依赖性和通道间依赖性。它不仅保留了 Transformer 输入的标记,还进一步增加了预测窗口的大小,同时保持了时间依赖性。图 4 说明了在时间序列任务中使用补丁的方法。
在这里插入图片描述
在这里插入图片描述

2.4 编码器(Decoder)

论文采用原生的 Transformer 编码器来建模序列的长期和跨变量特征,这类似于 PatchTST 中使用的方法。由于 Transformer 没有明确建模序列的顺序,为了提供位置信息,论文使用了可学习的加权位置编码 W p o s ∈ R P × N W_{pos} \in \R^{P \times N} WposRP×N。位置编码被添加到输入序列的嵌入表示 x i n i = P i + W p o s x_{in}^{i}=P^{i}+W_{pos} xini=Pi+Wpos 上。通过这种方式,模型可以区分不同位置的元素。

编码器由多个具有相同结构的层组成,每一层包括两个子层:多头自注意力层和前馈神经网络层。多头自注意力层是编码器的第一个子层。在这个层中,输入序列中的每个元素都可以与其他所有元素进行交互,而不仅仅是与其相邻的元素。这里使用三个权重矩阵 W Q W^{Q} WQ W K W^{K} WK W V W^{V} WV 来计算 Q i = ( x i n i ) T W Q Q^{i}=(x_{in}^{i})^{T}W^{Q} Qi=(xini)TWQ K i = ( x i n i ) T W K K^{i}=(x_{in}^{i})^{T}W^{K} Ki=(xini)TWK V i = ( x i n i ) T W V V^{i}=(x_{in}^{i})^{T}W^{V} Vi=(xini)TWV。这是通过计算注意力分数实现的,每个元素会接收到一组权重,指示其对其他元素的重要性。通过使用多头注意力机制,模型可以学习不同方面的注意力,从而更好地捕捉序列中的信息:

A t t e n t i o n ( Q i , K i , V i ) = s o f t m a x ( Q i ( K i ) T d k ) V i        ( 4 ) Attention(Q^{i},K^{i},V^{i})=softmax(\frac{Q^{i}(K^{i})^{T}}{\sqrt {d_{k}}})V^{i}\ \ \ \ \ \ (4) Attention(Qi,Ki,Vi)=softmax(dk Qi(Ki)T)Vi      (4)

在多头自注意力层之后是前馈神经网络层。每个位置的表示通过一个全连接的前馈神经网络进一步处理。这个网络通常包括两个全连接层,其输出被添加到输入中,形成一个残差连接。这有助于在训练过程中缓解梯度消失问题。

在每个子层的输入和输出之间,使用残差连接和层归一化。残差连接的引入使得模型更容易学习恒等映射,从而有助于深度网络的训练。此外,每个子层的输出还经过层归一化,以稳定训练过程。

3 相关代码

Transformer:

class PositionalEncoding(nn.Module):
    def __init__(self, outfea, max_len):
        super(PositionalEncoding, self).__init__()

        # 计算位置编码
        pe = torch.zeros(max_len, outfea)
        position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1)
        div_term = torch.exp(torch.arange(0, outfea, 2).float() * (-torch.log(
            torch.tensor(10000.0)) / outfea))
        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 + x + self.pe[:, :x.size(1)]
        return x


class MultiHeadAttention(nn.Module):
    def __init__(self, outfea, num_heads):
        super(MultiHeadAttention, self).__init__()
        self.num_heads = num_heads
        self.outfea = outfea
        assert outfea % num_heads == 0
        self.depth = outfea // num_heads

        # 查询、键和值的线性投影
        self.query_linear = nn.Linear(outfea, outfea)
        self.key_linear = nn.Linear(outfea, outfea)
        self.value_linear = nn.Linear(outfea, outfea)

        # 输出线性投影
        self.output_linear = nn.Linear(outfea, outfea)

    def split_heads(self, x):
        batch_size, seq_length, outfea = x.size()
        return x.view(batch_size, seq_length, self.num_heads, self.depth).transpose(1, 2)

    def forward(self, query, key, value, mask=None):
        # 线性投影
        query = self.query_linear(query)  # [batch_size, seq_length, outfea]
        key = self.key_linear(key)
        value = self.value_linear(value)

        # 分割头部
        query = self.split_heads(query)  # [batch_size, num_heads, seq_length, depth]
        key = self.split_heads(key)
        value = self.split_heads(value)

        # 缩放点积注意力
        scores = torch.matmul(query, key.transpose(-2, -1)) / math.sqrt(
            self.depth)  # [batch_size, num_heads, seq_length, seq_length]

        # 如果提供了掩码,则应用掩码
        if mask is not None:
            scores += scores.masked_fill(mask == 0, -1e9)

        # 计算注意力权重并应用softmax
        attention_weights = torch.softmax(scores, dim=-1)

        # 应用注意力到值
        attention_output = torch.matmul(attention_weights, value)

        # 合并头部
        batch_size, _, seq_length, d_k = attention_output.size()
        attention_output = attention_output.transpose(1, 2).contiguous().view(batch_size,
                                                                              seq_length, self.outfea)

        # 线性投影
        attention_output = self.output_linear(attention_output)

        return attention_output


class FeedForward(nn.Module):
    def __init__(self, outfea, hiddenfea):
        super(FeedForward, self).__init__()
        self.linear1 = nn.Linear(outfea, hiddenfea)
        self.linear2 = nn.Linear(hiddenfea, outfea)
        self.relu = nn.ReLU()

    def forward(self, x):
        # 线性变换1
        x = self.linear1(x)
        # 非线性激活
        x = self.relu(x)
        # 线性变换2
        x = self.linear2(x)

        return x


class EncoderLayer(nn.Module):
    def __init__(self, outfea, num_heads, hiddenfea, dropout):
        super(EncoderLayer, self).__init__()
        self.self_attention = MultiHeadAttention(outfea, num_heads)
        self.feed_forward = FeedForward(outfea, hiddenfea)
        self.norm1 = nn.LayerNorm(outfea)
        self.norm2 = nn.LayerNorm(outfea)
        self.dropout = nn.Dropout(dropout)

    def forward(self, x, mask):
        # 自注意力层
        attention_output = self.self_attention(x, x,
                                               x, mask)
        attention_output = self.dropout(attention_output)
        x = x + attention_output
        x = self.norm1(x)

        # 前馈层
        feed_forward_output = self.feed_forward(x)
        feed_forward_output = self.dropout(feed_forward_output)
        x = x + feed_forward_output
        x = self.norm2(x)

        return x


class DecoderLayer(nn.Module):
    def __init__(self, outfea, num_heads, hiddenfea, dropout):
        super(DecoderLayer, self).__init__()
        self.masked_self_attention = MultiHeadAttention(outfea, num_heads)
        self.enc_dec_attention = MultiHeadAttention(outfea, num_heads)
        self.feed_forward = FeedForward(outfea, hiddenfea)
        self.norm1 = nn.LayerNorm(outfea)
        self.norm2 = nn.LayerNorm(outfea)
        self.norm3 = nn.LayerNorm(outfea)
        self.dropout = nn.Dropout(dropout)

    def forward(self, x, encoder_output, src_mask, tgt_mask):
        # 掩码的自注意力层
        self_attention_output = self.masked_self_attention(x, x, x, tgt_mask)
        self_attention_output = self.dropout(self_attention_output)
        x = x + self_attention_output
        x = self.norm1(x)

        # 编码器-解码器注意力层
        enc_dec_attention_output = self.enc_dec_attention(x, encoder_output,
                                                          encoder_output, src_mask)
        enc_dec_attention_output = self.dropout(enc_dec_attention_output)
        x = x + enc_dec_attention_output
        x = self.norm2(x)

        # 前馈层
        feed_forward_output = self.feed_forward(x)
        feed_forward_output = self.dropout(feed_forward_output)
        x = x + feed_forward_output
        x = self.norm3(x)

        return x


class Transformer(nn.Module):
    def __init__(self, outfea, num_heads, num_layers, hiddenfea,
                 max_len, dropout):
        super(Transformer, self).__init__()

        # 定义位置编码层
        self.positional_encoding = PositionalEncoding(outfea, max_len)

        # 定义编码器和解码器的多层堆叠
        self.encoder_layers = nn.ModuleList([EncoderLayer(outfea, num_heads, hiddenfea, dropout)
                                             for i in range(num_layers)])
        self.decoder_layers = nn.ModuleList([DecoderLayer(outfea, num_heads, hiddenfea, dropout)
                                             for i in range(num_layers)])

        # 定义线性层
        self.linear = nn.Linear(outfea, outfea)
        self.dropout = nn.Dropout(dropout)

    # 生成掩码
    def generate_mask(self, src, tgt):
        src_mask = (src != 0).unsqueeze(1).unsqueeze(2)
        tgt_mask = (tgt != 0).unsqueeze(1).unsqueeze(3)
        seq_length = tgt.size(1)
        nopeak_mask = (1 - torch.triu(torch.ones(1, seq_length, seq_length), diagonal=1)).bool()
        tgt_mask = tgt_mask & nopeak_mask
        return src_mask, tgt_mask

    # 前向传播
    def forward(self, src, tgt):
        src_mask, tgt_mask = self.generate_mask(src, tgt)

        # 编码器输入的词嵌入和位置编码
        encoder_embedding = self.encoder_embedding(src)
        en_positional_encoding = self.positional_encoding(encoder_embedding)
        src_embedded = self.dropout(en_positional_encoding)

        # 解码器输入的词嵌入和位置编码
        decoder_embedding = self.decoder_embedding(tgt)
        de_positional_encoding = self.positional_encoding(decoder_embedding)
        tgt_embedded = self.dropout(de_positional_encoding)

        enc_output = src_embedded
        for enc_layer in self.encoder_layers:
            enc_output = enc_layer(enc_output, src_mask)

        dec_output = tgt_embedded
        for dec_layer in self.decoder_layers:
            dec_output = dec_layer(dec_output, enc_output, src_mask, tgt_mask)

        output = self.linear(dec_output)
        return output

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

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

相关文章

MPLS VPN一

R1为客户,现在进行一些基本配置,来确保可以通路由 先启动OSPF跑通 在R3上 等一会 现在启动MPLS 对R3 对R4 然后在R2上 再把接口划到空间里面 原来的IP在公网里面,被清除了 然后再配置接口 查看 对R1(相当于客户) …

CrossOver和PD虚拟机谁更强大?CrossOver和PD虚拟机应该怎么选择

在当前的虚拟化技术和应用程序兼容性解决方案中,CrossOver和PD虚拟机(Parallels Desktop)都是备受用户喜爱的选择。对于需要在非原生系统上运行应用程序的用户而言,选择合适的工具尤为重要。那么,CrossOver和PD虚拟机谁…

虚表-在成员函数前面加上virtual后发生了什么事情???

从上图得出: 子类继承的父类的虚表指针吗? 答:是的。 子类和父类是同一个虚表还是不同的虚表? 答:不同的虚表,倘若是同一个当子类进行覆盖的时候,父类的虚表会丢失。 下面有一些方法来观察类…

【linux】认识“文件”的本质,理解“文件系统”的设计逻辑,体会linux优雅的设计理念

⭐⭐⭐个人主页⭐⭐⭐ ~~~~~~~~~~~~~~~~~~ C站最❤❤❤萌❤❤❤博主 ~~~~~~~~~~~~~~~~~~~ ​♥东洛的克莱斯韦克-CSDN博客♥ ~~~~~~~~~~~~~~~~~~~~ 嗷呜~ ✌✌✌✌ 萌妹统治世界~ 🎉🎉🎉🎉 ✈✈✈✈相关文章✈✈✈✈ &#x1f4a…

虚函数表共享和生成

每个类有不同的虚表,相同的类使用相同的虚表 模拟动态绑定的一个过程

【Apache Doris】周FAQ集锦:第 6 期

【Apache Doris】周FAQ集锦:第 6 期 SQL问题数据操作问题运维常见问题其它问题关于社区 欢迎查阅本周的 Apache Doris 社区 FAQ 栏目! 在这个栏目中,每周将筛选社区反馈的热门问题和话题,重点回答并进行深入探讨。旨在为广大用户和…

C++11左值、右值

知识回顾,详解引用 简单概括,引用就是给已存在对象取别名,引用变量与其引用实体共用同一块内存空间 左右值区分 注意:不一定左边的都是左值,右边的都是右值 左边的也可能是右值,等号右边的也可能是左值 …

大数据工程师如何做到数据可视化?

好的数据可视化作品都是通过不断的数据对比分析实战出来的。 今天给大家带来一篇大数据工程师干货,从多角度解析做数据可视化的重要性,并解读一些适用的应用场景。大数据工程师们刷到这篇文章时一定要进来看看,满满的干货。 目录 1. 什么是数…

中望CAD 2025 (ZW3D2025) 简体中文修改版

名称:中望CAD 2025 (ZW3D2025) 简体中文修改版 描述:一款三维CAD设计工具,运行破解补丁ZW3D2025-2024-Patch执行修补。 链接:夸克网盘分享 📁 大小:3.2GB 🏷 标签:#PC软件 #CAD #设…

为什么笔记本电脑触控板不工作?这里有你想要的答案和解决办法

序言 你的笔记本电脑触控板停止工作了吗?值得庆幸的是,这个令人沮丧的问题通常很容易解决。以下是笔记本电脑触控板问题的最常见原因和修复方法。 触控板被功能键禁用 大多数(如果不是全部的话)Windows笔记本电脑都将其中一个功能键用于禁用和启用笔记本电脑触控板。按键…

【Arthas案例】某应用依赖两个GAV不同但包含两个相同全限定类名StaticLoggerBinder,引起log4j.Level类找不到异常

3分钟内解决问题 两个不同的GAV依赖冲突,包含相同全限定类名,引起ClassNotFoundException Maven依赖的三坐标体系GAV(G-groupId,A-artifactId,V-version) 【案例1】某应用依赖两个GAV不同的jar,但包含两个相同全限定类…

Jmeter多个请求按照比例并发压测的几种方式

🍅 视频学习:文末有免费的配套视频可观看 🍅 点击文末小卡片 ,免费获取软件测试全套资料,资料在手,涨薪更快 一、需求 在压测的过程中,为了能够压测整个链路,通常需要多个接口进行并…

OpenAI Assistants API:如何使用代码或无需代码创建您自己的AI助手

Its now easier than ever to create your own AI Assistant that can handle a lot of computing tasks for you. See how you can get started with the OpenAI AI Assistant API. 现在比以往任何时候都更容易创建您自己的AI助手,它可以为您处理许多计算任务。了…

微信公众号打通与登录的实现

今天实现一下与微信公众号进行对接,通过扫描二维码的方式来进行注册与登录,获取用户的微信唯一标识作为用户的username,下面我们开始编写。 骨架建立: 建包: 第一步还是先将骨架建好,与网关骨架差不多&a…

树莓派4B_OpenCv学习笔记9:图片的腐蚀与膨胀

今日继续学习树莓派4B 4G:(Raspberry Pi,简称RPi或RasPi) 本人所用树莓派4B 装载的系统与版本如下: 版本可用命令 (lsb_release -a) 查询: Opencv 版本是4.5.1: 图像的膨胀与腐蚀一般用于灰度图或者二值图,今日便来学习…

基于python-CNN卷积网络训练识别牛油果和猕猴桃-含数据集+pyqt界面

代码下载地址: https://download.csdn.net/download/qq_34904125/89383066 本代码是基于python pytorch环境安装的。 下载本代码后,有个requirement.txt文本,里面介绍了如何安装环境,环境需要自行配置。 或可直接参考下面博文…

目前市面上DIY高端空心耳机壳使用的透明原材料是什么?

目前市面上DIY高端空心耳机壳使用的透明原材料是什么? DIY制作耳机壳的UV树脂胶是一种单组份、通过紫外线光固化的胶粘剂,具有低能量固化、收缩低、发热量低、高透明、耐盐酸、耐黄变好、高硬度、韧性好、成型好等特点。这种胶粘剂非常适合用于制作耳机壳…

Redis 主从集群 哨兵原理

一. Redis 主从集群 1.1 基本概念 主从架构:Redis主从集群采用“一主多从”的架构模式,其中主节点(Master)负责处理客户端的读写请求,而从节点(Slave)则负责处理读请求。这种读写分离的设计使…

Pytest 读取excel文件参数化应用

本文是基于Pytest框架,读取excel中的文件,传入页面表单中,并做相应的断言实现。 1、编辑媒体需求 首先明确一下需求,我们需要对媒体的表单数据进行编辑,步骤如下: 具体表单如下图所示 1、登录 2、点击我…

618洗地机全网热门推荐,跟着买错不了

步入酷热夏天,家中的清洁工作也迎来了新的挑战。天气炎热,细菌、异味滋生的困扰让日常打扫变得不再轻松,这时一台高性能的洗地机就成了提升生活品质的必备良品。不同于洗地机的技术与类别繁多,洗地机虽原理不复杂,但在…