机器学习周报-ModernTCN文献阅读
文章目录
- 摘要
- Abstract
- 0 提升有效感受野(ERF)
- 1 相关知识
- 1.1 标准卷积
- 1.2 深度分离卷积(Depthwise Convolution,DWConv)
- 1.3 逐点卷积(Pointwise Convolution,PWConv)
- 1.4 组卷积(Group Convolution)
- 2 ModernTCN
- 2.1 Modern convolution block
- 2.2 相关修改
- 2.2.1 保留变量维度
- 2.2.2 DWConv
- 2.2.3 ConvFFN
- 2.3 最终结构
- 2.4 Modern TCN代码
- 总结
摘要
本周阅读了ModernTCN:一种时间序列分析的现代纯卷积结构,其在多个主流时间序列分析任务上取得了与最先进的基于Transformer和MLP的模型相媲美的性能,同时保持了卷积模型的效率优势。ModernTCN借鉴了Transformer中的架构设计,采用了深度卷积和逐点卷积的组合,以提高模型的表示能力。同时,为了更好地处理时间序列数据,ModernTCN引入了变量独立嵌入和跨变量依赖捕获机制。ModernTCN通过使用大核心尺寸而不是堆叠更多小核心,ModernTCN显著扩大了ERF,这有助于更好地捕捉时间序列数据中的长期依赖性。
Abstract
This week, I read ModernTCN: a modern pure convolutional structure for time series analysis that has achieved performance comparable to state-of-the-art Transformer and MLP based models on multiple mainstream time series analysis tasks, while maintaining the efficiency advantage of convolutional models. ModernTCN draws inspiration from the architecture design of Transformer and adopts a combination of deep convolution and pointwise convolution to enhance the model’s representation capability. Meanwhile, in order to better handle time series data, ModernTCN introduces variable independent embedding and cross variable dependency capture mechanisms. ModernTCN significantly expands ERF by using larger core sizes instead of stacking more small cores, which helps better capture long-term dependencies in time series data.
0 提升有效感受野(ERF)
基于Transformer的模型和基于MLP的模型具有全局有效感受野(ERF),因此可以更好地捕获长期时间(跨时间)依赖性,从而显著优于传统的TCN。而SCINet和MICN主要关注的是设计更复杂的结构来处理传统的卷积,而忽略了更新卷积本身的重要性,下图给出了这两种模型的感受野对比。
其中,ModernTCN通常采用大核,来有效地提高ERF。
SCINet 和 MICN 是两个基于 TCN 的预测模型,它们的感受野都很小。作者发现 ModernTCN 中采用大的卷积核所对应的感受野要大很多。其次是充分利用卷积可以捕获跨变量依赖性,也就是多变量时间序列中变量之间的关系
1 相关知识
1.1 标准卷积
标准卷积,利用若干个多通道卷积核对输入的多通道图像进行处理,输出的feature map既提取了通道特征,又提取了空间特征。
如图所示:假设输入层为一个大小为5×5像素,3通道色彩的输入图片(shape为5×5×3),经过3×3卷积核的卷积层(假设输出通道为4,则卷积核shape为3×3×3×4),最终输出4个Feature Map。其中卷积层的参数量为:3×3×3×4=108
1.2 深度分离卷积(Depthwise Convolution,DWConv)
DWConv就是深度(channel)维度不变,改变H/W。
DWConv的一个卷积核负责一个通道,一个通道只被一个卷积核卷积。而常规卷积每个卷积核是同时操作输入图片的每个通道,这样就不会混合通道,只会混合token。
DWConv的核为单通道模式,需要对输入的每一个通道进行卷积,这样就会得到和输入特征图通道数一致的输出特征图。即有输入特征图通道数=卷积核个数=输出特征图个数。
如下图所示:同样是对于一张5×5像素、三通道彩色输入图片(shape为5×5×3),Depthwise Convolution首先经过第一次卷积运算,不同于上面的常规卷积,DW完全是在二维平面内进行。卷积核的数量与上一层的通道数相同(通道和卷积核一一对应)。所以一个三通道的图像经过运算后生成了3个Feature map(如果有same padding则尺寸与输入层相同为5×5)。
卷积层的参数量为:3×3×3=27
DWConv完成后的Feature map数量与输入层的通道数相同,无法扩展Feature map。而且这种运算对输入层的每个通道独立进行卷积运算,没有有效的利用不同通道在相同空间位置上的feature信息。因此需要PWConv来将这些Feature map进行组合生成新的Feature map。
1.3 逐点卷积(Pointwise Convolution,PWConv)
PWConv就是W/H维度不变,改变channel
由于DWConv输入特征图通道数=卷积核个数=输出特征图个数,这样会导致输出的特征图个数过少(或者说输出特征图的通道数过少,可看成是输出特征图个数为1,通道数为3),从而可能影响信息的有效性。此时,就需要进行逐点卷积。
逐点卷积实质上是用1x1的卷积核进行升维
PWConv的运算与常规卷积运算非常相似,它的卷积核的尺寸为 1×1×M(M为上一层的通道数)。所以这里的卷积运算会将上一步的map在深度方向上进行加权组合,生成新的Feature map。有几个卷积核就有几个输出Feature map。
如下图所示:从DWConv得到的3个单通道特征图,经过4个大小为:1×1×3的卷积核的卷积计算后,输出4个特征图;而输出特征图的个数取决于Filter的个数。卷积层的参数量为:1×1×3×4=12
1.4 组卷积(Group Convolution)
将输入特征图的通道分成若干组,并在每组内单独进行卷积操作,从而减少计算复杂度和参数量,同时有效利用模型的结构特性。
如下图:输入数据shape: H i n × W i n × C i n H_{in}×W_{in}×C_{in} Hin×Win×Cin,假设将输入数据的通道分为G组,即每组数据的通道数为 C i n G \frac{C_{in}}{G} GCin,对这G组数据进行单独设计卷积核,最终的输出结果将这G组的卷积结果进行拼接;其中每个卷积核shape为:k×k
卷积层的参数量为: k × k × C i n G × C o u t G × G k×k×\frac{C_{in}}{G}×\frac{C_{out}}{G}×G k×k×GCin×GCout×G
= k × k × C i n × C o u t G \frac{k×k×C_{in}×C_{out}}{G} Gk×k×Cin×Cout
而标准卷积的卷积层的参数量为: k × k × C i n × C o u t k×k×C_{in}×C_{out} k×k×Cin×Cout
即分组卷积可将参数量减小为原来的1/G。
分组卷积的用途:
- 减少参数量,分成𝐺组,则该层的参数量减少为原来的1/𝐺
- Group Convolution可以看成是structured sparse,每个卷积核的尺寸由𝐶∗𝐾∗𝐾变为𝐶/𝐺∗𝐾∗𝐾,可以将其余(𝐶−𝐶 / 𝐺)∗𝐾∗𝐾的参数视为0,有时甚至可以在减少参数量的同时获得更好的效果(相当于正则)
- 当分组数量等于输入map数量,输出map数量也等于输入map数量,即𝐺=𝑁=𝐶,𝑁个卷积核每个尺寸为1∗𝐾∗𝐾时,Group Convolution就成了DWConv
2 ModernTCN
ModernTCN采用了现代化的卷积块设计,借鉴了Transformer中的架构设计,使用了深度卷积和逐点卷积的组合,以提高模型的表示能力。
论文贡献:
- 作者深入研究了如何更好地利用卷积在时间序列中的问题,并提出了一种新的解决方案。实验结果表明所提方法在时间序列分析中比现有的基于卷积的模型更能发挥卷积的潜力。
- ModernTCN在多个主流时间序列分析任务上实现了一致的最先进性能,展示了出色的任务泛化能力。
- ModernTCN提供了效率和性能的更好平衡。它保持了基于卷积的模型的效率优势,同时在性能方面与最先进的基于Transformer的模型竞争,甚至更好。
2.1 Modern convolution block
ModernTCN模块设计,其中M,N,D分别是变量维度、时间维度和特征维度的大小
DWConv
负责在每个特征的基础上学习token之间(不同时间步之间)的时间信息,其作用与Transformer中的自关注模块相同。
ConvFFN
类似于Transformer中的FFN
模块(结果等价)。它由两个PWConv
组成,采用倒瓶颈结构(先升维后降维),其中ConvFFN
块的隐藏通道比输入通道宽 r rr 倍。该模块独立学习每个 token 新的 feature representation。
上述设计实现了时间信息和特征信息混合的分离。DWConv
和ConvFFN
中的每一个都只混合一个时间或特征维度的信息。与传统的卷积不同,传统的卷积将两个维度的信息混合在一起。这种解耦设计使对象任务更容易学习,降低了计算复杂度
但作者发现,简单地以与CV相同的方式对卷积进行现代化改造,在时间序列任务中几乎没有带来性能改进。作者注意到时间序列除了特征维和时间维之外,时间序列还有一个变量维。**其中ConvFFN可以建模通道间关系,但无法建模变量间关系。为了使现代1D卷积更适合于时间序列分析,还需要更多与时间序列相关的修改
2.2 相关修改
2.2.1 保留变量维度
时间序列变量之间存在复杂的依赖关系,简单的嵌入层,忽略了变量的维度,无法学习这种依赖性,甚至可能因为不考虑变量的不同行为而丢失变量的独立特性。
作者提出了一种“patchify variable-independent embedding”(分块变量独立嵌入)的方法。
提出了一种新的时间序列数据嵌入方法,通过分块和全卷积的方式,更好地适应时间序列数据的特性,同时保留了变量维度,为进一步的分析和建模提供了基础。
输入表示: X i n ∈ R M × L X_{in}\in R^{M×L} Xin∈RM×L 表示输入的时间序列,其长度为L,其特征数量为M。
Patchify Variable-Independent Embedding 步骤:
- 将输入 X i n ∈ R M × L X_{in}\in R^{M×L} Xin∈RM×L 解压缩为 X i n ∈ R M × 1 × L X_{in}\in R^{M×1×L} Xin∈RM×1×L
- padding operation:对原始序列 X i n X_{in} Xin采用padding操作,确保N=L//S(L为序列长度,S为步长,)(具体来说,我们重复Xin的最后一个值(P-S)次,然后将它们填充回Xin的末尾。)
- 将填充好的 X i n X_{in} Xin通过1D卷积层进行patching和embedding
其中卷积层的核大小为P,步长为S,将1个输入通道映射到D个输出通道。在这个过程中,每个单变量时间序列被独立嵌入,从而保留了变量维度。
其中分块处理:将输入的时间序列在适当的填充后,将时间序列分成N个大小为P的块,分块过程中的步长为S,S也是两个连续块之间不重叠区域的长度。
嵌入变量将这些块嵌入到D维的嵌入向量中, X e m b = E m b e d d i n g ( X i n ) X_{emb}=Embedding(X_{in}) Xemb=Embedding(Xin)得到 X e m b ∈ R M × D × L X_{emb}\in R^{M×D×L} Xemb∈RM×D×L
这里将原始的变量的隐藏维度(等于1)计入输入变量 X i n ∈ R M × L X_{in}\in R^{M×L} Xin∈RM×L ,调整为 X i n ∈ R M × 1 × L X_{in}\in R^{M×1×L} Xin∈RM×1×L,然后对每个变量单独进行 embedding ,将每个变量映射为指定的隐藏维度D,得到嵌入 X e m b ∈ R M × D × L X_{emb}\in R^{M×D×L} Xemb∈RM×D×L;
优势:
- 保留变量维度:通过独立嵌入,可以保留时间序列的变量维度,这对于捕捉时间序列数据的复杂特性至关重要。
- 信息捕获:后续的修改将使结构能够从额外的变量维度中捕获信息。
2.2.2 DWConv
DWConv最初是为学习时间信息而设计的。由于单独使用DWConv来共同学习跨时间和跨变量的依赖关系比较困难,所以不适合让DWConv同时负责跨变量维度的信息混合。因此,作者将原来的DWConv从仅特征独立修改为特征和变量独立,使其独立学习每个单变量时间序列的时间依赖性。同时,在DWConv中采用大核来增加ERF,提高时间建模能力。
2.2.3 ConvFFN
由于DWConv是特征和变量独立的,ConvFFN作为补充,应该混合跨特征和变量维度的信息。一种简单的方法是通过单个ConvFFN共同学习特征和变量之间的依赖关系。但这种方法的计算复杂度较高,性能较差。因此,我们进一步将单个ConvFFN解耦为ConvFFN1和ConvFFN2,方法是将PWConvs替换为grouped PWConvs ,并设置不同的组数。ConvFFN1负责学习每个变量的特征信息,ConvFFN2负责捕获每个特征的交叉变量依赖性。
2.3 最终结构
最终修改得到的ModernTCN block如下
其中DWConv、ConvFFN1和ConvFFN2中的每一个只在时间、特征或可变维度中的一个上混合信息,这保持了现代卷积中解耦设计的思想。现(深度可分离卷积其实也是组数等于深度数的组卷积),既简单又有效。
上图中 shape 在每一个模块的前后变化,首先,用 DWConv 来建模时间上的关系,但又不希望它参与到通道间和变量间的建模上。因此,作者将M和D这两个表示变量通道的维度 reshape 在一起,再进行深度可分离卷积。其次,希望独立建模通道和变量。因此,作者采用了两个组卷积,其中一个组卷积的 Group 数为 M(表示每 D 个通道构成一个组,因此用来建模通道间关系),另一个组卷积的 Group 数为 D(表示每 M 个变量构成一个组,因此用来建模变量间关系)。注意,两个组卷积之间存在着 reshape 和 permute 操作,这是为了正确的分组,最后会再 reshape 和 permute 回去。最后,整体再用一个残差连接,即可得到最终的 ModernTCN block。堆叠多个 block 即可得到 ModernTCN 模型。综上所述,作者将时间上、通道上、变量上的三种关系解耦建模,用三种组卷积来巧妙地进行实现(深度可分离卷积其实也是组数等于深度数的组卷积),既简单又有效。
2.4 Modern TCN代码
ModernTCN_Layer.py
import torch
from torch import nn
import math
# decompositionclass moving_avg(nn.Module):"""Moving average block to highlight the trend of time series"""def __init__(self, kernel_size, stride):super(moving_avg, self).__init__()self.kernel_size = kernel_sizeself.avg = nn.AvgPool1d(kernel_size=kernel_size, stride=stride, padding=0)def forward(self, x):# padding on the both ends of time seriesfront = x[:, 0:1, :].repeat(1, (self.kernel_size - 1) // 2, 1)end = x[:, -1:, :].repeat(1, (self.kernel_size - 1) // 2, 1)x = torch.cat([front, x, end], dim=1)x = self.avg(x.permute(0, 2, 1))x = x.permute(0, 2, 1)return xclass series_decomp(nn.Module):"""Series decomposition block"""def __init__(self, kernel_size):super(series_decomp, self).__init__()self.moving_avg = moving_avg(kernel_size, stride=1)def forward(self, x):moving_mean = self.moving_avg(x)res = x - moving_meanreturn res, moving_mean# forecast task head
class Flatten_Head(nn.Module):def __init__(self, individual, n_vars, nf, target_window, head_dropout=0):super(Flatten_Head, self).__init__()self.individual = individualself.n_vars = n_varsif self.individual:self.linears = nn.ModuleList()self.dropouts = nn.ModuleList()self.flattens = nn.ModuleList()for i in range(self.n_vars):self.flattens.append(nn.Flatten(start_dim=-2))self.linears.append(nn.Linear(nf, target_window))self.dropouts.append(nn.Dropout(head_dropout))else:self.flatten = nn.Flatten(start_dim=-2)self.linear = nn.Linear(nf, target_window)self.dropout = nn.Dropout(head_dropout)def forward(self, x): # x: [bs x nvars x d_model x patch_num]if self.individual:x_out = []for i in range(self.n_vars):z = self.flattens[i](x[:, i, :, :]) # z: [bs x d_model * patch_num]z = self.linears[i](z) # z: [bs x target_window]z = self.dropouts[i](z)x_out.append(z)x = torch.stack(x_out, dim=1) # x: [bs x nvars x target_window]else:x = self.flatten(x)x = self.linear(x)x = self.dropout(x)return x
moving_avg模块
:移动平均块,用于突出时间序列的趋势,通过在时间序列两端进行填充,然后应用一维平均池化操作实现.series_decomp模块
:序列分解块,将时间序列分解为残差和趋势两部分,其中趋势部分通过moving_avg
模块计算得到.Flatten_Head模块
:预测任务头部模块,用于将特征进行展平和线性变换,以输出预测结果.支持个体化和非个体化两种模式,个体化模式为每个变量分别进行操作,非个体化模式则对所有变量统一操作.
ModernTCN.py
文件定义了基于时间卷积网络(TCN)的现代时间序列预测模型ModernTCN及其相关组件,包括模型的构建、前向传播过程以及模型的结构重参数化等.
import torch
from torch import nn
import torch.nn.functional as F
import math
from layers.RevIN import RevIN
from models.ModernTCN_Layer import series_decomp, Flatten_Headclass LayerNorm(nn.Module):def __init__(self, channels, eps=1e-6, data_format="channels_last"):super(LayerNorm, self).__init__()self.norm = nn.Layernorm(channels)def forward(self, x):B, M, D, N = x.shapex = x.permute(0, 1, 3, 2)x = x.reshape(B * M, N, D)x = self.norm(x)x = x.reshape(B, M, N, D)x = x.permute(0, 1, 3, 2)return xdef get_conv1d(in_channels, out_channels, kernel_size, stride, padding, dilation, groups, bias):return nn.Conv1d(in_channels=in_channels, out_channels=out_channels, kernel_size=kernel_size, stride=stride,padding=padding, dilation=dilation, groups=groups, bias=bias)def get_bn(channels):return nn.BatchNorm1d(channels)def conv_bn(in_channels, out_channels, kernel_size, stride, padding, groups, dilation=1,bias=False):if padding is None:padding = kernel_size // 2result = nn.Sequential()result.add_module('conv', get_conv1d(in_channels=in_channels, out_channels=out_channels, kernel_size=kernel_size,stride=stride, padding=padding, dilation=dilation, groups=groups, bias=bias))result.add_module('bn', get_bn(out_channels))return resultdef fuse_bn(conv, bn):kernel = conv.weightrunning_mean = bn.running_meanrunning_var = bn.running_vargamma = bn.weightbeta = bn.biaseps = bn.epsstd = (running_var + eps).sqrt()t = (gamma / std).reshape(-1, 1, 1)return kernel * t, beta - running_mean * gamma / stdclass ReparamLargeKernelConv(nn.Module):def __init__(self, in_channels, out_channels, kernel_size,stride, groups,small_kernel,small_kernel_merged=False, nvars=7):super(ReparamLargeKernelConv, self).__init__()self.kernel_size = kernel_sizeself.small_kernel = small_kernel# We assume the conv does not change the feature map size, so padding = k//2. Otherwise, you may configure padding as you wish, and change the padding of small_conv accordingly.padding = kernel_size // 2if small_kernel_merged:self.lkb_reparam = nn.Conv1d(in_channels=in_channels, out_channels=out_channels, kernel_size=kernel_size,stride=stride, padding=padding, dilation=1, groups=groups, bias=True)else:self.lkb_origin = conv_bn(in_channels=in_channels, out_channels=out_channels, kernel_size=kernel_size,stride=stride, padding=padding, dilation=1, groups=groups,bias=False)if small_kernel is not None:assert small_kernel <= kernel_size, 'The kernel size for re-param cannot be larger than the large kernel!'self.small_conv = conv_bn(in_channels=in_channels, out_channels=out_channels,kernel_size=small_kernel,stride=stride, padding=small_kernel // 2, groups=groups, dilation=1,bias=False)def forward(self, inputs):if hasattr(self, 'lkb_reparam'):out = self.lkb_reparam(inputs)else:out = self.lkb_origin(inputs)if hasattr(self, 'small_conv'):out += self.small_conv(inputs)return outdef PaddingTwoEdge1d(self,x,pad_length_left,pad_length_right,pad_values=0):D_out,D_in,ks=x.shapeif pad_values ==0:pad_left = torch.zeros(D_out,D_in,pad_length_left)pad_right = torch.zeros(D_out,D_in,pad_length_right)else:pad_left = torch.ones(D_out, D_in, pad_length_left) * pad_valuespad_right = torch.ones(D_out, D_in, pad_length_right) * pad_valuesx = torch.cat([pad_left,x],dims=-1)x = torch.cat([x,pad_right],dims=-1)return xdef get_equivalent_kernel_bias(self):eq_k, eq_b = fuse_bn(self.lkb_origin.conv, self.lkb_origin.bn)if hasattr(self, 'small_conv'):small_k, small_b = fuse_bn(self.small_conv.conv, self.small_conv.bn)eq_b += small_beq_k += self.PaddingTwoEdge1d(small_k, (self.kernel_size - self.small_kernel) // 2,(self.kernel_size - self.small_kernel) // 2, 0)return eq_k, eq_bdef merge_kernel(self):eq_k, eq_b = self.get_equivalent_kernel_bias()self.lkb_reparam = nn.Conv1d(in_channels=self.lkb_origin.conv.in_channels,out_channels=self.lkb_origin.conv.out_channels,kernel_size=self.lkb_origin.conv.kernel_size, stride=self.lkb_origin.conv.stride,padding=self.lkb_origin.conv.padding, dilation=self.lkb_origin.conv.dilation,groups=self.lkb_origin.conv.groups, bias=True)self.lkb_reparam.weight.data = eq_kself.lkb_reparam.bias.data = eq_bself.__delattr__('lkb_origin')if hasattr(self, 'small_conv'):self.__delattr__('small_conv')class Block(nn.Module):def __init__(self, large_size, small_size, dmodel, dff, nvars, small_kernel_merged=False, drop=0.1):super(Block, self).__init__()self.dw = ReparamLargeKernelConv(in_channels=nvars * dmodel, out_channels=nvars * dmodel,kernel_size=large_size, stride=1, groups=nvars * dmodel,small_kernel=small_size, small_kernel_merged=small_kernel_merged, nvars=nvars)self.norm = nn.BatchNorm1d(dmodel)#convffn1self.ffn1pw1 = nn.Conv1d(in_channels=nvars * dmodel, out_channels=nvars * dff, kernel_size=1, stride=1,padding=0, dilation=1, groups=nvars)self.ffn1act = nn.GELU()self.ffn1pw2 = nn.Conv1d(in_channels=nvars * dff, out_channels=nvars * dmodel, kernel_size=1, stride=1,padding=0, dilation=1, groups=nvars)self.ffn1drop1 = nn.Dropout(drop)self.ffn1drop2 = nn.Dropout(drop)#convffn2self.ffn2pw1 = nn.Conv1d(in_channels=nvars * dmodel, out_channels=nvars * dff, kernel_size=1, stride=1,padding=0, dilation=1, groups=dmodel)self.ffn2act = nn.GELU()self.ffn2pw2 = nn.Conv1d(in_channels=nvars * dff, out_channels=nvars * dmodel, kernel_size=1, stride=1,padding=0, dilation=1, groups=dmodel)self.ffn2drop1 = nn.Dropout(drop)self.ffn2drop2 = nn.Dropout(drop)self.ffn_ratio = dff//dmodeldef forward(self,x):input = xB, M, D, N = x.shapex = x.reshape(B,M*D,N)x = self.dw(x)x = x.reshape(B,M,D,N)x = x.reshape(B*M,D,N)x = self.norm(x)x = x.reshape(B, M, D, N)x = x.reshape(B, M * D, N)x = self.ffn1drop1(self.ffn1pw1(x))x = self.ffn1act(x)x = self.ffn1drop2(self.ffn1pw2(x))x = x.reshape(B, M, D, N)x = x.permute(0, 2, 1, 3)x = x.reshape(B, D * M, N)x = self.ffn2drop1(self.ffn2pw1(x))x = self.ffn2act(x)x = self.ffn2drop2(self.ffn2pw2(x))x = x.reshape(B, D, M, N)x = x.permute(0, 2, 1, 3)x = input + xreturn xclass Stage(nn.Module):def __init__(self, ffn_ratio, num_blocks, large_size, small_size, dmodel, dw_model, nvars,small_kernel_merged=False, drop=0.1):super(Stage, self).__init__()d_ffn = dmodel * ffn_ratioblks = []for i in range(num_blocks):blk = Block(large_size=large_size, small_size=small_size, dmodel=dmodel, dff=d_ffn, nvars=nvars, small_kernel_merged=small_kernel_merged, drop=drop)blks.append(blk)self.blocks = nn.ModuleList(blks)def forward(self, x):for blk in self.blocks:x = blk(x)return xclass ModernTCN(nn.Module):def __init__(self,patch_size,patch_stride, stem_ratio, downsample_ratio, ffn_ratio, num_blocks, large_size, small_size, dims, dw_dims,nvars, small_kernel_merged=False, backbone_dropout=0.1, head_dropout=0.1, use_multi_scale=True, revin=True, affine=True,subtract_last=False, freq=None, seq_len=512, c_in=7, individual=False, target_window=96):super(ModernTCN, self).__init__()# RevINself.revin = revinif self.revin:self.revin_layer = RevIN(c_in, affine=affine, subtract_last=subtract_last)# stem layer & down sampling layers(if needed)self.downsample_layers = nn.ModuleList()stem = nn.Sequential(nn.Conv1d(1, dims[0], kernel_size=patch_size, stride=patch_stride),nn.BatchNorm1d(dims[0]))self.downsample_layers.append(stem)for i in range(3):downsample_layer = nn.Sequential(nn.BatchNorm1d(dims[i]),nn.Conv1d(dims[i], dims[i + 1], kernel_size=downsample_ratio, stride=downsample_ratio),)self.downsample_layers.append(downsample_layer)self.patch_size = patch_sizeself.patch_stride = patch_strideself.downsample_ratio = downsample_ratioif freq == 'h':time_feature_num = 4elif freq == 't':time_feature_num = 5else:raise NotImplementedError("time_feature_num should be 4 or 5")self.te_patch = nn.Sequential(nn.Conv1d(time_feature_num, time_feature_num, kernel_size=patch_size, stride=patch_stride,groups=time_feature_num),nn.Conv1d(time_feature_num, dims[0], kernel_size=1, stride=1, groups=1),nn.BatchNorm1d(dims[0]))# backboneself.num_stage = len(num_blocks)self.stages = nn.ModuleList()for stage_idx in range(self.num_stage):layer = Stage(ffn_ratio, num_blocks[stage_idx], large_size[stage_idx], small_size[stage_idx], dmodel=dims[stage_idx],dw_model=dw_dims[stage_idx], nvars=nvars, small_kernel_merged=small_kernel_merged, drop=backbone_dropout)self.stages.append(layer)# Multi scale fusing (if needed)self.use_multi_scale = use_multi_scaleself.up_sample_ratio = downsample_ratioself.lat_layer = nn.ModuleList()self.smooth_layer = nn.ModuleList()self.up_sample_conv = nn.ModuleList()for i in range(self.num_stage):align_dim = dims[-1]lat = nn.Conv1d(dims[i], align_dim, kernel_size=1,stride=1)self.lat_layer.append(lat)smooth = nn.Conv1d(align_dim, align_dim, kernel_size=3, stride=1, padding=1)self.smooth_layer.append(smooth)up_conv = nn.Sequential(nn.ConvTranspose1d(align_dim, align_dim, kernel_size=self.up_sample_ratio, stride=self.up_sample_ratio),nn.BatchNorm1d(align_dim))self.up_sample_conv.append(up_conv)# headpatch_num = seq_len // patch_strideself.n_vars = c_inself.individual = individuald_model = dims[-1]if use_multi_scale:self.head_nf = d_model * patch_numself.head = Flatten_Head(self.individual, self.n_vars, self.head_nf, target_window,head_dropout=head_dropout)else:if patch_num % pow(downsample_ratio,(self.num_stage - 1)) == 0:self.head_nf = d_model * patch_num // pow(downsample_ratio,(self.num_stage - 1))else:self.head_nf = d_model * (patch_num // pow(downsample_ratio, (self.num_stage - 1))+1)self.head = Flatten_Head(self.individual, self.n_vars, self.head_nf, target_window,head_dropout=head_dropout)def up_sample(self, x, upsample_ratio):_, _, _, N = x.shapereturn F.upsample(x, size=N, scale_factor=upsample_ratio, mode='bilinear')def forward_feature(self, x, te=None):B,M,L=x.shapex = x.unsqueeze(-2)for i in range(self.num_stage):B, M, D, N = x.shapex = x.reshape(B * M, D, N)if i==0:if self.patch_size != self.patch_stride:# stem layer paddingpad_len = self.patch_size - self.patch_stridepad = x[:,:,-1:].repeat(1,1,pad_len)x = torch.cat([x,pad],dim=-1)else:if N % self.downsample_ratio != 0:pad_len = self.downsample_ratio - (N % self.downsample_ratio)x = torch.cat([x, x[:, :, -pad_len:]],dim=-1)x = self.downsample_layers[i](x)_, D_, N_ = x.shapex = x.reshape(B, M, D_, N_)x = self.stages[i](x)return xdef forward(self, x, te=None):# instance normif self.revin:x = x.permute(0, 2, 1)x = self.revin_layer(x, 'norm')x = x.permute(0, 2, 1)x = self.forward_feature(x,te)x = self.head(x)# de-instance normif self.revin:x = x.permute(0, 2, 1)x = self.revin_layer(x, 'denorm')x = x.permute(0, 2, 1)return xdef structural_reparam(self):for m in self.modules():if hasattr(m, 'merge_kernel'):m.merge_kernel()class Model(nn.Module):def __init__(self, configs):super(Model, self).__init__()# hyper paramself.stem_ratio = configs.stem_ratioself.downsample_ratio = configs.downsample_ratioself.ffn_ratio = configs.ffn_ratioself.num_blocks = configs.num_blocksself.large_size = configs.large_sizeself.small_size = configs.small_sizeself.dims = configs.dimsself.dw_dims = configs.dw_dimsself.nvars = configs.enc_inself.small_kernel_merged = configs.small_kernel_mergedself.drop_backbone = configs.dropoutself.drop_head = configs.head_dropoutself.use_multi_scale = configs.use_multi_scaleself.revin = configs.revinself.affine = configs.affineself.subtract_last = configs.subtract_lastself.freq = configs.freqself.seq_len = configs.seq_lenself.c_in = self.nvars,self.individual = configs.individualself.target_window = configs.pred_lenself.kernel_size = configs.kernel_sizeself.patch_size = configs.patch_sizeself.patch_stride = configs.patch_stride# decompself.decomposition = configs.decompositionif self.decomposition:self.decomp_module = series_decomp(self.kernel_size)self.model_res = ModernTCN(patch_size=self.patch_size,patch_stride=self.patch_stride,stem_ratio=self.stem_ratio, downsample_ratio=self.downsample_ratio, ffn_ratio=self.ffn_ratio, num_blocks=self.num_blocks, large_size=self.large_size, small_size=self.small_size, dims=self.dims, dw_dims=self.dw_dims,nvars=self.nvars, small_kernel_merged=self.small_kernel_merged, backbone_dropout=self.drop_backbone, head_dropout=self.drop_head, use_multi_scale=self.use_multi_scale, revin=self.revin, affine=self.affine,subtract_last=self.subtract_last, freq=self.freq, seq_len=self.seq_len, c_in=self.c_in, individual=self.individual, target_window=self.target_window)self.model_trend = ModernTCN(patch_size=self.patch_size,patch_stride=self.patch_stride,stem_ratio=self.stem_ratio, downsample_ratio=self.downsample_ratio, ffn_ratio=self.ffn_ratio, num_blocks=self.num_blocks, large_size=self.large_size, small_size=self.small_size, dims=self.dims, dw_dims=self.dw_dims,nvars=self.nvars, small_kernel_merged=self.small_kernel_merged, backbone_dropout=self.drop_backbone, head_dropout=self.drop_head, use_multi_scale=self.use_multi_scale, revin=self.revin, affine=self.affine,subtract_last=self.subtract_last, freq=self.freq, seq_len=self.seq_len, c_in=self.c_in, individual=self.individual, target_window=self.target_window)else:self.model = ModernTCN(patch_size=self.patch_size,patch_stride=self.patch_stride,stem_ratio=self.stem_ratio, downsample_ratio=self.downsample_ratio, ffn_ratio=self.ffn_ratio, num_blocks=self.num_blocks, large_size=self.large_size, small_size=self.small_size, dims=self.dims, dw_dims=self.dw_dims,nvars=self.nvars, small_kernel_merged=self.small_kernel_merged, backbone_dropout=self.drop_backbone, head_dropout=self.drop_head, use_multi_scale=self.use_multi_scale, revin=self.revin, affine=self.affine,subtract_last=self.subtract_last, freq=self.freq, seq_len=self.seq_len, c_in=self.c_in, individual=self.individual, target_window=self.target_window)def forward(self, x, te=None):if self.decomposition:res_init, trend_init = self.decomp_module(x)res_init, trend_init = res_init.permute(0, 2, 1), trend_init.permute(0, 2, 1)if te is not None:te = te.permute(0, 2, 1)res = self.model_res(res_init, te)trend = self.model_trend(trend_init, te)x = res + trendx = x.permute(0, 2, 1)else:x = x.permute(0, 2, 1)if te is not None:te = te.permute(0, 2, 1)x = self.model(x, te)x = x.permute(0, 2, 1)return x
- LayerNorm:层归一化模块,对输入特征进行归一化处理,支持不同的数据格式.
- get_conv1d、get_bn、conv_bn、fuse_bn:卷积层、批量归一化层、卷积+批量归一化组合模块以及批量归一化融合函数,用于构建和优化卷积神经网络.
- ReparamLargeKernelConv:可重参数化的大核卷积模块,通过将大核卷积分解为小核卷积和大核卷积的组合,实现模型的结构重参数化,以提高模型的表达能力和效率.
- Block:模型的基本构建块,包含深度可分离卷积、归一化、前馈网络等组件,用于提取特征和进行特征变换.
- Stage:由多个Block组成的一个阶段,用于构建模型的不同层次结构.
- ModernTCN:主模型类,定义了模型的整体架构和前向传播过程,包括RevIN(可逆归一化)层、茎层、下采样层、多尺度融合层以及预测头部等组件.
总结
ModernTCN是一种现代化的纯卷积结构,它通过以下几个关键创新点,成功地将卷积技术重新带回时间序列分析的舞台:
- 现代化的卷积块设计:借鉴了Transformer中的架构设计,ModernTCN采用了深度卷积和逐点卷积的组合,以提高模型的表示能力。
- 时间序列相关的修改:为了更好地处理时间序列数据,ModernTCN引入了变量独立嵌入和跨变量依赖捕获机制。
- 扩大有效感受野(ERF):通过使用大核心尺寸而不是堆叠更多小核心,ModernTCN显著扩大了ERF,这有助于更好地捕捉时间序列数据中的长期依赖性。
相关文章:
机器学习周报-ModernTCN文献阅读
文章目录 摘要Abstract 0 提升有效感受野(ERF)1 相关知识1.1 标准卷积1.2 深度分离卷积(Depthwise Convolution,DWConv)1.3 逐点卷积(Pointwise Convolution,PWConv)1.4 组卷积(Grou…...
QT RC_FILE 应用程序图标设置
1.先做一个app.ico 文件,并将文件放入资源文件夹中 2.打开QT项目的.pro文件在最下面增加 RC_FILE $$PWD/res/app.rc 3.在资源文件夹中创建一个app.rc文件。在QT开发工具中编辑并输入下在内容 IDI_ICON1 ICON "app.ico" 4.测试效果...
5G学习笔记之SNPN系列之网络选择
目录 0. NPN系列 1. 概述 2. 自动网络选择 3. 手动网络选择 0. NPN系列 1. NPN概述 2. NPN R18 3. 【SNPN系列】SNPN ID和广播消息 4. 【SNPN系列】UE入网和远程配置 5. 【SNPN系列】SNPN选择 6. PNI-NPN 1. 概述 对于某个特定的UE,可以仅支持SNPN接入模式&#x…...
k8s helm部署kafka集群(KRaft模式)——筑梦之路
添加helm仓库 helm repo add bitnami "https://helm-charts.itboon.top/bitnami" --force-update helm repo add grafana "https://helm-charts.itboon.top/grafana" --force-update helm repo add prometheus-community "https://helm-charts.itboo…...
Redis学习笔记
目录 Nosql概述 为什么用Nosql 什么是Nosql Nosql四大分类 Redis入门 概述 Windows安装 Linux安装 测试性能 基础知识 五大数据类型 Redis-Key String(字符串) List(列表) Set(集合) Hash(哈希) Zset(有…...
mysql递归查询语法WITH RECURSIVE
WITH RECURSIVE 是 SQL 中用于执行递归查询的语法,特别适合于处理层级结构或递归数据(如树形结构、图结构)。递归查询可以反复引用自己来查询多层次的数据,而无需写多个嵌套查询。 基本语法结构: WITH RECURSIVE CTE…...
Go语言之十条命令(The Ten Commands of Go Language)
Go语言之十条命令 Go语言简介 Go语言(又称Golang)是由Google开发的一种开源编程语言,首次公开发布于2009年。Go语言旨在提供简洁、高效、可靠的软件开发解决方案,特别强调并发编程和系统编程。 Go语言的基本特征 静态强类…...
Visual Studio 2022 C++ gRPC 环境搭建
文章目录 1、gRPC 安装2、创建项目2.1、创建 “空的解决方案”2.2、新建 gRPCServer 和 gRPCClient 项目2.3、创建 proto 文件 2、为 gRPC 服务端和客服端项目配置 protobuf 编译2.1、protobuf 配置2.2、gRPCServer 项目配置2.3、gRPCClient 项目配置 3、测试3.1、启动服务端程…...
2024AAAI SCTNet论文阅读笔记
文章目录 SCTNet: Single-Branch CNN with Transformer Semantic Information for Real-Time Segmentation摘要背景创新点方法Conv-Former Block卷积注意力机制前馈网络FFN 语义信息对齐模块主干特征对齐共享解码头对齐 总体架构backbone解码器头 对齐损失 实验SOTA效果对比Cit…...
【Java从入门到放弃 之 final 关键字】
final 关键字 final 关键字final 字段final 函数列表中的参数final 方法final 类 final 关键字 Java中里面有final这个关键字,这个关键字总体上是用来表达” 不能被改变“ 这个意思的。我们使用这个关键字表达不能被改变,有两种使用场景,有三…...
【U8+】用友U8软件中,出入库流水输出excel的时候提示报表输出引擎错误。
【问题现象】 通过天联高级版客户端登录拥有U8后, 将出入库流水输出excel的时候,提示报表输出引擎错误。 进行报表输出时出现错误,错误信息:找不到“fd6eea8b-fb40-4ce4-8ab4-cddbd9462981.htm”。 如果您正试图从最近使用的文件列…...
文本区域提取和分析——Python版本
目录 1. 图像预处理 2. 文本区域提取 3. 文本行分割 4. 文本区域分析 5. 应用举例 总结 文本区域提取和分析是计算机视觉中的重要任务,尤其在光学字符识别(OCR)系统、文档分析、自动化数据录入等应用中有广泛的应用。其目标是从图像中提…...
数据库介绍(不同数据库比较)
文章目录 **一、关系型数据库(RDBMS)****1. MySQL****优点**:**缺点**:**适用场景**: **2. PostgreSQL****优点**:**缺点**:**适用场景**: **3. Oracle Database****优点**ÿ…...
注意力的简单理解,有哪些注意力(Attention)
注意力(Attention) 目录 注意力(Attention)掩码注意力机制自注意力、交叉注意力、掩码注意力的不同点适应场景及举例多头注意分层注意力(Hierarchical Attention)协同注意力(Co - Attention)自注意力(Self - Attention) 简单理解:自注意力就像是一个句子(或序列)内…...
基于Python的投资组合收益率与波动率的数据分析
基于Python的投资组合收益率与波动率的数据分析 摘要:該文通过研究马科维茨的投资组合模型,并将投资组合模型应用到包含6只金融股票的金融行业基金中。首先通过开源的财经接口Tushare获取股票原始数据,接着利用数据分析的黄金组合库…...
《Opencv》图像的旋转
一、使用numpy库实现 np.rot90(img,-1) 后面的参数为-1时事顺时针旋转,为1时是逆时针旋转。 import cv2 import numpy as np img cv2.imread(./images/kele.png) """方法一""" # 顺时针90度 rot_1 np.rot90(img,-1) # 逆时针90度…...
Python 22:注释
1. 定义: 用熟悉的语言对代码进行解释说明。注释不会被执行。 2. 注释分类 单行注释:只能对一行代码进行注释。放在要注释的代码后面,用#进行分隔,中间至少空2个空格,保证代码规范。 print("hello world10"…...
python:利用神经网络技术确定大量离散点中纵坐标可信度的最高集中区间
当我们有许多离散点并想要确定纵坐标在某个区间内的可信度时,我们可以使用神经网络模型来解决这个问题。下面是一个使用Python编写的示例代码,展示了如何使用神经网络来确定大量离散点中纵坐标可信度的最高集中区间。 import numpy as np from sklearn.…...
计算机软件保护条例
(2001年12月20日中华人民共和国国务院令第339号公布 根据2011年1月8日《国务院关于废止和修改部分行政法规的决定》第一次修订 根据2013年1月30日《国务院关于修改〈计算机软件保护条例〉的决定》第二次修订) 第一章 总则 第一条 为了保护计算机软件著作权人的权益&#…...
CM3/4启动流程
CM3/4启动流程 1. 启动模式2. 启动流程 1. 启动模式 复位方式有三种:上电复位,硬件复位和软件复位。 当产生复位,并且离开复位状态后,CM3/4 内核做的第一件事就是读取下列两个 32 位整数的值: 从地址 0x0000 0000 处取…...
gaussdb中怎么查询一个表有多少GB
在 GaussDB 中,你可以通过多种方法查询一个表的大小,包括使用系统视图和内置函数。以下是几种常见的方法: 1. 使用 pg_total_relation_size 函数 pg_total_relation_size 函数返回一个表及其所有索引和 TOAST 数据的总大小。 示例查询 SE…...
2025-01-06 Unity 使用 Tip2 —— Windows、Android、WebGL 打包记录
文章目录 1 Windows2 Android2.1 横版 / 竖版游戏2.2 API 最低版本2.3 目标帧率2.3.1 targetFrameRate2.3.2 vSyncCount2.3.3 Unity 默认设置以及推荐设置2.3.4 Unity 帧率托管 3 WebGL3.1 平台限制3.2 打包报错记录 13.3 打包报错记录 2 最近尝试将写的小游戏打包ÿ…...
OP-TEE环境飞腾密码引擎编程指南
【写在前面】 飞腾开发者平台是基于飞腾自身强大的技术基础和开放能力,聚合行业内优秀资源而打造的。该平台覆盖了操作系统、算法、数据库、安全、平台工具、虚拟化、存储、网络、固件等多个前沿技术领域,包含了应用使能套件、软件仓库、软件支持、软件适…...
解密Navicat密码(Java)
最近从Navicat换到了DBeaver,导出配置文件发现配置文件里的密码都是加密的,看网上的都是给的PHP代码,因为环境问题,就算是在线上运行的PHP代码也会报错,所以就把这段代码改成Java了。 package com.unicdata.system.con…...
apex安装
安装过程复杂曲折,网上说的很多办法,貌似成功了,实际还是没起作用。 先说成功过程,执行下面命令,安装成功(当然,前提是你要先配置好编译环境): (我的环境&a…...
常见的开源网络操作系统
常见的开源网络操作系统有很多,它们通常用于路由器、交换机、网络设备和服务器等场景,具有灵活、可定制、易于扩展的特点。以下是一些常见的开源网络操作系统: OpenWRT 用途:主要用于路由器、无线接入点和网络设备。提供了广泛的定制选项和高级功能,如防火墙配置、VPN 支持…...
2024年6月英语六级CET6听力原文与解析
目录 0 序言 1.Long Conversation(长对话) 1.1 Blender 搅拌机 1.2 村庄的改造变化 2.Passage 2.1 micro robots 微型机器人 2.2 elite sleeper 睡眠精英 3.Lecture 3.1 对自身观念变化的低察觉度及相关研究发现 3.2 美国母亲群体数量变化及母亲节消费趋势分析 3.3 …...
力扣2-回文数
一.题目 给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false 。 回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。 例如,121 是回文&…...
基于springboot的网上商城购物系统
作者:学姐 开发技术:SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等 文末获取“源码数据库万字文档PPT”,支持远程部署调试、运行安装。 目录 项目包含: 开发说明: 系统功能: 项目截图…...
业务日志设计
当一个项目足够大的时候,我们需要将统计系统完全独立出去,那么就无法避免数据采集的问题,我们可以在业务触发处增加log日志来记录当前变化的原始数据,提供统计系统进行采集 设计一个统计系统的日志记录机制时,主要需要…...
梯度下降方法
2.5 梯度下降方法介绍 学习目标 掌握梯度下降法的推导过程知道全梯度下降算法的原理知道随机梯度下降算法的原理知道随机平均梯度下降算法的原理知道小批量梯度下降算法的原理 上一节中给大家介绍了最基本的梯度下降法实现流程,本节我们将进一步介绍梯度下降法的详细…...
javascript
引入方式 JavaScript 程序不能独立运行,它需要被嵌入 HTML 中,然后浏览器才能执行 JavaScript 代码。通过 script 标签将 JavaScript 代码引入到 HTML 中,有两种方式: 内部方式 通过 script 标签包裹 JavaScript 代码 <!DO…...
大语言模型训练所需的最低显存,联邦大语言模型训练的传输优化技术
联邦大语言模型训练的传输优化技术 目录 联邦大语言模型训练的传输优化技术大语言模型训练所需的最低显存大语言模型训练所需的最低显存 基于模型微调、压缩和分布式并行处理的方法,介绍了相关开源模型及技术应用 核心创新点 多维度优化策略:综合运用基于模型微调、模型压缩和…...
二叉树的二叉链表和三叉链表
在二叉树的数据结构中,通常有两种链表存储方式:二叉链表和三叉链表。这里,我们先澄清一下概念,通常我们讨论的是二叉链表,它用于存储二叉树的节点。而“三叉链表”这个术语在二叉树的上下文中不常见,可能是…...
api开发如何在代码中使用京东商品详情接口的参数?
选择编程语言和相关工具 以 Python 为例,你可以使用requests库来发送 HTTP 请求获取接口数据。如果是 Java,可以使用OkHttp等库。 Python 示例 假设你已经安装了requests库,以下是一个简单的代码示例来获取和使用京东商品详情接口参数&#…...
Quartz如何实现分布式调度
系列文章目录 任务调度管理——Quartz入门 Quartz如何实现分布式控制 系列文章目录一、持久化二、分布式调度1. 表信息2. 调度器的竞争3. 触发器的分配 三、 总结 我们都说Quartz是个分布式调度框架,那么在分布式环境上,如何使得各个服务器上的定时任务…...
JUC--线程池
线程池 七、线程池7.1线程池的概述7.2线程池的构建与参数ThreadPoolExecutor 的构造方法核心参数线程池的工作原理 Executors构造方法newFixedThreadPoolnewCachedThreadPoolnewSingleThreadExecutornewScheduledThreadPool(int corePoolSize) 为什么不推荐使用内置线程池&…...
以柔资讯-D-Security终端文件保护系统 logFileName 任意文件读取漏洞复现
0x01 产品简介 D-Security终端文件保护系统是一套专注于企业文件管理效率与安全的解决方案,统对文件进行全文加密,而非仅在文件表头或特定部分进行加密,从而大大提高了文件的安全性,降低了被破解的风险。D-Security终端文件保护系统是被政府和国安局等情报单位唯一认定的安…...
【JavaScript】Set,Map,Weakmap
以下来源:九剑科技。 weakmap WeakMap是 ES6 中新增的一种集合类型,叫做“弱映射”,由于他的键引用的对象是弱引用,键所指向的对象可以被垃圾回收,可以防止内存泄露。 map ①Map是键值对的集合,键值不限…...
idea小操作
idea 所边定位到你目前阅读的代码 AltF1 或者 选择定位图标...
[tesseract]Deserialize header failed: FIRC.lstmf
tesseract5.0训练时候会提示 [INFO]cd /d D:\program\tesseract-ocr-lstm-train\data [INFO]D:\program\tesseract-ocr-lstm-train\Tesseract-OCR\tesseract.exe xiangjiao.tif xiangjiao -l eng --psm 7 lstm.train [INFO]Page 1 [INFO]Page 2 [INFO]Deserialize header fail…...
深度学习知识点:RNN
文章目录 1.简单介绍2.网络结构3.应对梯度消失 1.简单介绍 循环神经网络(RNN,Recurrent Neural Network)是一类用于处理序列数据的神经网络。与传统网络相比,变化不是特别大,不如CNN的变化那么大。 为什么要有循环神经…...
【数据可视化-11】全国大学数据可视化分析
🧑 博主简介:曾任某智慧城市类企业算法总监,目前在美国市场的物流公司从事高级算法工程师一职,深耕人工智能领域,精通python数据挖掘、可视化、机器学习等,发表过AI相关的专利并多次在AI类比赛中获奖。CSDN…...
CSS:背景样式、盒子模型与文本样式
背景样式 背景样式用于设置网页元素的背景,包括颜色、图片等。 背景颜色 使用 background-color 属性设置背景颜色,支持多种格式(颜色英文、十六进制、RGB等)。 div {background-color: lightblue; }格式示例十六进制#ff5733R…...
学英语学压测:02jmeter组件-测试计划和线程组ramp-up参数的作用
📢📢📢:先看关键单词,再看英文,最后看中文总结,再回头看一遍英文原文,效果更佳!! 关键词 Functional Testing功能测试[ˈfʌŋkʃənəl ˈtɛstɪŋ]Sample样…...
环动科技平均售价波动下滑:大客户依赖明显,应收账款周转率骤降
《港湾商业观察》施子夫 2024年12月18日,浙江环动机器人关节科技股份有限公司(以下简称,环动科技)的上市审核状态变更为“已问询”,公司在11月25日科创板IPO获上交所受理,独家保荐机构为广发证券。 此次环…...
数据结构:LinkedList与链表—无头双向链表(二)
目录 一、什么是LinkedList? 二、LinkedList的模拟实现 1、display()方法 2、addFirst(int data)方法 3、addLast(int data)方法 4、addIndex(int index,int data)方法 5、contains(int key)方法 6、remove(int key)方法 7、removeAllKey(int key)方法 8、…...
『SQLite』解释执行(Explain)
摘要:本节主要讲解SQL的解释执行:Explain。 在 sqlite 语句之前,可以使用 “EXPLAIN” 关键字或 “EXPLAIN QUERY PLAN” 短语,用于描述表查询的细节。 基本语法 EXPLAIN 语法: EXPLAIN [SQLite Query]EXPLAIN QUER…...
计算机网络之---物理层的基本概念
物理层简介 物理层(Physical Layer) 是 OSI(开放系统互联)模型 中的第 1 层,它主要负责数据在物理媒介上的传输,确保原始比特(0 和 1)的传输不受干扰地从一个设备传送到另一个设备。…...
Elasticsearch:优化的标量量化 - 更好的二进制量化
作者:来自 Elastic Benjamin Trent 在这里,我们解释了 Elasticsearch 中的优化标量量化以及如何使用它来改进更好的二进制量化 (Better Binary Quantization - BBQ)。 我们的全新改进版二进制量化 (Better Binary Quantization - BBQ) 索引现在变得更强大…...