基于LSTM算法实现交通流量预测(Pytorch版)

算法介绍

LSTM(Long Short-Term Memory)算法是一种特殊设计的循环神经网络(RNN, Recurrent Neural Network),专为有效地处理和建模序列数据中的长期依赖关系而开发。由于传统RNN在处理长序列时容易遇到梯度消失和梯度爆炸问题,导致模型难以捕捉到远距离输入之间的关联,LSTM通过引入独特的细胞状态(cell state)和多层门控机制解决了这些问题,从而在各种序列学习任务中展现出强大的性能。

LSTM模型的结构如下:
在这里插入图片描述
LSTM的关键组件如下:

遗忘门

LSTM(Long Short-Term Memory)网络的遗忘门(Forget Gate)是其门控机制的关键部分之一,负责决定在给定时间步 t t t 时,上一时刻的细胞状态 C t − 1 C_{t-1} Ct1 中哪些信息应该被保留,哪些应该被遗忘。遗忘门的工作流程如下:

遗忘门计算
  1. 输入合并
    遗忘门接收前一时刻隐藏状态 h t − 1 h_{t-1} ht1 和当前时间步输入 x t x_t xt。这两个向量被拼接(concatenate)或通过某种形式的线性变换(如全连接层)组合在一起,形成一个综合的输入向量,表示当前时间步的全部可用信息。

  2. 门控值计算
    综合输入向量经过一个带有sigmoid激活函数的全连接层(或称线性层),计算出遗忘门的输出值 f t f_t ft。sigmoid函数将这个综合输入向量映射到一个介于0和1之间的值,其中:

    • 值接近0:表示对应的信息维度应该几乎完全被遗忘,即在更新细胞状态时,该维度的值将被显著减小。
    • 值接近1:表示对应的信息维度应该几乎完全被保留,即在更新细胞状态时,该维度的值将基本保持不变。

    数学表达式为:

f t = σ ( W f ⋅ [ h t − 1 , x t ] + b f ) f_t = \sigma(W_f \cdot [h_{t-1}, x_t] + b_f) ft=σ(Wf[ht1,xt]+bf)

其中:

  • f t f_t ft 是遗忘门在时间步 t t t 的输出向量,每个元素值都在 [ 0 , 1 ] [0, 1] [0,1] 范围内。
  • σ \sigma σ 是sigmoid激活函数,它将输入值压缩到 ( 0 , 1 ) (0, 1) (0,1) 区间内,确保输出的是一个概率值。
  • W f W_f Wf 是遗忘门对应的权重矩阵,用于将拼接后的输入向量映射到一个新的特征空间。
  • b f b_f bf 是遗忘门的偏置项。
  • [ h t − 1 , x t ] [h_{t-1}, x_t] [ht1,xt] 表示将前一时刻隐藏状态和当前输入按维度拼接成一个单一向量。
细胞状态更新

遗忘门输出 f t f_t ft 与上一时刻细胞状态 C t − 1 C_{t-1} Ct1 进行逐元素(element-wise)乘法,得到更新后的细胞状态 C t C_t Ct。乘积操作相当于对每个维度上的信息进行“筛选”,遗忘门输出值为0的部分会被有效遗忘(置零),为1的部分则完全保留。

C t = f t ⊙ C t − 1 C_t = f_t \odot C_{t-1} Ct=ftCt1

这里的 ⊙ \odot 表示逐元素乘法(Hadamard product)。通过这种方式,遗忘门能够有选择地决定哪些历史信息应当保留在细胞状态中,以便在后续时间步中继续影响模型的计算,而哪些信息应当被舍弃,从而避免无关或过时信息对当前决策产生干扰。

综上所述,LSTM的遗忘门通过计算sigmoid激活函数的输出来决定细胞状态中各维度信息的遗忘程度,并通过逐元素乘法更新细胞状态,实现了对长期依赖关系的灵活控制。这一机制使得LSTM能够在处理长序列数据时有效地避免梯度消失问题,同时保持对关键时间点信息的长期记忆能力。

输入门

LSTM(Long Short-Term Memory)网络的输入门(Input Gate)负责决定在给定时间步 t t t 时,当前输入 x t x_t xt 中哪些新信息应当被添加到细胞状态 C t C_t Ct 中。输入门的工作流程如下:

输入门计算
  1. 输入合并
    输入门同样接收前一时刻隐藏状态 h t − 1 h_{t-1} ht1 和当前时间步输入 x t x_t xt,这两个向量通常被拼接(concatenate)或通过某种形式的线性变换(如全连接层)组合在一起,形成一个综合的输入向量,表示当前时间步的全部可用信息。

  2. 门控值计算
    综合输入向量经过两个不同的全连接层,分别生成两部分输出:

    • 输入门sigmoid部分:这部分输出经过sigmoid激活函数,生成一个介于0和1之间的向量 i t i_t it,表示新信息被添加到细胞状态中的比例。值接近0表示不添加,接近1表示完全添加。

    i t = σ ( W i ⋅ [ h t − 1 , x t ] + b i ) i_t = \sigma(W_i \cdot [h_{t-1}, x_t] + b_i) it=σ(Wi[ht1,xt]+bi)

    其中 W i W_i Wi 是输入门sigmoid部分的权重矩阵, b i b_i bi 是对应的偏置项, σ \sigma σ 是sigmoid激活函数。

    • 候选细胞状态(Candidate Cell State):这部分输出经过tanh激活函数,生成一个新的向量 C ~ t \tilde{C}_t C~t,表示可能被添加到细胞状态中的新信息。tanh函数将输出限制在 [ − 1 , 1 ] [-1, 1] [1,1] 范围内。

    C ~ t = tanh ⁡ ( W C ⋅ [ h t − 1 , x t ] + b C ) \tilde{C}_t = \tanh(W_C \cdot [h_{t-1}, x_t] + b_C) C~t=tanh(WC[ht1,xt]+bC)

    其中 W C W_C WC 是候选细胞状态的权重矩阵, b C b_C bC 是对应的偏置项。

细胞状态更新

基于输入门的sigmoid输出 i t i_t it 和候选细胞状态 C ~ t \tilde{C}_t C~t,通过逐元素乘法将两者结合起来,生成新信息的实际贡献值,然后将其添加到由遗忘门处理过的细胞状态 C t − 1 C_{t-1} Ct1 中,得到更新后的细胞状态 C t C_t Ct

C t = f t ⊙ C t − 1 + i t ⊙ C ~ t C_t = f_t \odot C_{t-1} + i_t \odot \tilde{C}_t Ct=ftCt1+itC~t

这里的 ⊙ \odot 表示逐元素乘法(Hadamard product)。通过输入门sigmoid输出 i t i_t it 与候选细胞状态 C ~ t \tilde{C}_t C~t 的乘积,模型仅允许那些被判定为重要的新信息(即 i t i_t it 中接近1的维度)进入细胞状态,并且这些新信息是以 C ~ t \tilde{C}_t C~t 中相应维度的值来更新细胞状态的。

综上所述,LSTM的输入门通过计算sigmoid激活函数的输出来决定当前输入信息中各维度应当被添加到细胞状态中的程度,并通过tanh激活函数生成候选细胞状态。然后,这两部分通过逐元素乘法结合,更新细胞状态。这样,输入门既控制了新信息的流入量,又确保了新添加的信息经过了适当的非线性变换,有助于模型捕获复杂的时间序列特征。

输出门

LSTM(Long Short-Term Memory)网络的输出门(Output Gate)负责控制在给定时间步 t t t 时,细胞状态 C t C_t Ct 中哪些信息应当被输出到当前时刻的隐藏状态 h t h_t ht 并进一步影响模型的最终输出。输出门的工作流程如下:

输出门计算
  1. 输入合并
    类似于输入门,输出门也接收前一时刻隐藏状态 h t − 1 h_{t-1} ht1 和当前时间步输入 x t x_t xt,这两个向量通常通过拼接或线性变换组合成一个综合输入向量,表示当前时间步的全部可用信息。

  2. 门控值计算
    综合输入向量经过一个全连接层,然后使用sigmoid激活函数生成一个介于0和1之间的向量 o t o_t ot,它表示细胞状态 C t C_t Ct 中哪些信息应当被输出到隐藏状态的比例。值接近0表示不输出,接近1表示完全输出。

o t = σ ( W o ⋅ [ h t − 1 , x t ] + b o ) o_t = \sigma(W_o \cdot [h_{t-1}, x_t] + b_o) ot=σ(Wo[ht1,xt]+bo)

其中 W o W_o Wo 是输出门的权重矩阵, b o b_o bo 是对应的偏置项, σ \sigma σ 是sigmoid激活函数。

隐藏状态计算

输出门 o t o_t ot 与细胞状态 C t C_t Ct 经过tanh激活函数后的结果进行逐元素乘法,生成当前时刻的隐藏状态 h t h_t ht。tanh函数将细胞状态压缩至 [ − 1 , 1 ] [-1, 1] [1,1] 范围内,而输出门则控制了哪些信息应当被保留并传递到后续层或作为模型的最终输出。

h t = o t ⊙ tanh ⁡ ( C t ) h_t = o_t \odot \tanh(C_t) ht=ottanh(Ct)

这里 ⊙ \odot 仍然表示逐元素乘法。输出门 o t o_t ot 中接近1的维度对应于细胞状态 C t C_t Ct 中被选择输出的信息,接近0的维度则对应于被抑制输出的信息。通过这样的乘法操作,模型只允许那些被输出门判定为重要且应当传递给后续时间步或作为模型输出的信息,从细胞状态中流向隐藏状态。

综上所述,LSTM的输出门通过计算sigmoid激活函数的输出来决定细胞状态中各维度应当被输出到隐藏状态及后续模型计算的程度。它与经过tanh激活函数的细胞状态进行逐元素乘法,生成当前时刻的隐藏状态。这样,输出门不仅控制了细胞状态信息的流出量,还确保了输出的信息经过了适当的非线性变换,使得模型能够灵活地选择性地表达记忆细胞中的相关信息,适应不同任务的需求,如分类、回归或者生成等。

模型构建

输入

时序预测场景中,每次前向传播的input一般为[batch, input_len, node, input_channel]。

input张量的具体含义如下:

  • Batch: 这个维度表示一批样本的数量。在训练或推断过程中,模型通常会一次性处理多个样本以利用并行计算的优势。

  • Input Length: 这个维度通常表示时间步长、序列长度或类似的概念,即每个样本内部包含了一段连续的时间序列、事件序列或其它具有顺序关系的数据。对于每个样本,模型将在这些连续的步骤中依次处理其包含的信息。

  • Node: 这个维度表示每个样本内部的节点(或称为元素、位置)数量。这里的“节点”概念通常出现在与图结构相关的数据或具有内在空间结构(如网格、点云)的数据中。每个时间步长(或序列位置)下,样本包含一组节点,每个节点都有自己的特征。

  • Input Channel: 这个维度表示特征维度,即每个节点在每个时间步长(或序列位置)下具有 input_channel 个特征值。这些特征可以是数值型、类别型或其他类型的特征,共同描述了节点在当前时间步长(或序列位置)的状态。

综合来看,[batch, input_len, node, input_channel] 形状的输入表示:

  • 批处理的一组样本(batch 个),每个样本包含一段具有 input_len 个时间步长(或序列位置)的数据。
  • 在每个时间步长(或序列位置)下,样本内部由 node 个节点组成,每个节点具有 input_channel 个特征值。

输出

对应的output为output为[batch, output_len, node, output_channel]。

输出形状为 [batch, output_len, node, output_channel] 的四维张量表示模型对输入数据进行前向传播后的输出结果,其具体含义如下:

  • Batch: 与输入相同,这个维度仍然表示一批样本的数量。模型对同一批次的样本同时进行处理,并生成对应的输出。

  • Output Length: 这个维度对应于输入中的 input_len,表示模型生成的输出序列长度或时间步长。通常情况下,output_leninput_len 相同,意味着模型对每个输入时间步长都有相应的输出;但在某些模型(如自回归模型、循环解码器等)中,output_len 可能小于等于 input_len,尤其是当模型进行序列生成任务时,可能逐步生成输出序列。

  • Node: 与输入相同,此维度表示每个样本内部的节点(或称为元素、位置)数量。模型在输出阶段同样关注这些节点,并为每个节点生成一组特征。

  • Output Channel: 这个维度表示模型为每个节点在每个输出时间步长(或序列位置)生成的特征维度。每个输出特征通道可能对应于某种特定的预测结果、概率分布、注意力权重、状态变量等,具体取决于模型的设计和应用任务。

综上所述,形状为 [batch, output_len, node, output_channel] 的输出张量表示:

  • 批处理的一组样本(batch 个),每个样本生成一段具有 output_len 个时间步长(或序列位置)的输出数据。
  • 在每个输出时间步长(或序列位置)下,样本内部的每个节点都有 output_channel 个特征值,这些特征值反映了模型对节点在该时刻状态的预测、解释或生成结果。

模型适配

要基于PyTorch构建一个能够处理输入形状为 [batch, input_len, node, input_channel] 并产生输出形状为 [batch, output_len, node, output_channel] 的LSTM模型,首先需要明确LSTM层本身并不直接支持这种四维输入/输出。LSTM通常处理的是三维张量,即 [batch_size, sequence_length, input_features] 的输入以及 [batch_size, sequence_length, hidden_size] 或 [batch_size, sequence_length, num_directions * hidden_size](双向LSTM)的输出。因此,需要适当调整模型结构或对数据进行预处理,以适应LSTM的要求。

以下是常用的处理方式:

  • 展平节点和通道信息

    如果输入数据中每个节点在每个时间步长有多个特征(即input_channel),那么可以先将这些特征展平到一维,使得每个时间步长每个节点只有一个值。类似地,对于输出,也需要将output_channel展平。这样处理后,输入和输出的形状分别变为 [batch, input_len, node * input_channel][batch, output_len, node * output_channel]

如果本身的输入和输出的channel均为1,比如基于最近12个时间窗的流量预测未来3个时间窗的流量,则直接可将[batch, input_len, node, 1]通过squeeze函数直接变为[batch, input_len, node],即:

input = input.squeeze(-1)

模型开发

基于上述内容,构建模型如下:

class LSTM(nn.Module):def __init__(self, node_num, input_len, input_channel, hidden_sizes, output_len, output_channel):super(LSTM, self).__init__()self.node_num = node_numself.input_len = input_lenself.input_channel = input_channelself.hidden_sizes = hidden_sizesself.output_len = output_lenself.layers = nn.ModuleList()self.output_channel = output_channelprev_size = node_num * input_channelfor hidden_size in hidden_sizes:self.layers.append(nn.LSTM(input_size=prev_size, hidden_size=hidden_size))prev_size = hidden_sizeself.layers.append(nn.LSTM(input_size=prev_size, hidden_size=node_num * output_channel))self.mlp = nn.Linear(input_len, output_len)def forward(self, x):# [Batch, Input_len, Node, Input_channel] --> [Batch, Input_len, Node*Input_channel]x = x.reshape(x.shape[0], x.shape[1], -1)# [Batch, Input_len, Node*Input_channel] --> [Input_len, Batch, Node*Input_channel]x = x.permute(1, 0, 2)prev_output = xfor layer in self.layers:output, (ht, ct) = layer(prev_output)prev_output = output# [Input_len, Batch, Node * Output_channel] --> [Batch, Node * Output_channel, Input_len]y = output.permute(1, 2, 0)# [Batch, Node * Output_channel, Input_len] --> [Batch, Node * Output_channel, Output_len]y = self.mlp(y)# [Batch, Node * Output_channel, Output_len] --> [Batch, Output_len, Node * Output_channel]y = y.permute(0, 2, 1)y = y.reshape(y.shape[0], y.shape[1], -1, self.output_channel)return y

上述代码定义了一个名为 LSTM 的 PyTorch 模块类,继承自 nn.Module。该类旨在处理形状为 [Batch, Input_len, Node, Input_channel] 的输入数据,并生成形状为 [Batch, Output_len, Node, Output_channel] 的输出。

初始化方法 (__init__):

  • 类接收6个参数:node_num(节点数)、input_len(输入序列长度)、input_channel(输入通道数)、hidden_sizes(隐藏层大小列表)、output_len(输出序列长度)和 output_channel(输出通道数)。

  • 初始化父类 nn.Module

  • 将传入的参数存储为类属性。

  • 定义一个可迭代的模块列表 self.layers,用于存放多层 LSTM 单元。

  • 初始化一个 prev_size 变量,其初始值为 node_num * input_channel,表示展平后的节点特征总维度。

  • 遍历 hidden_sizes 列表,为每层 LSTM 定义一个 nn.LSTM 单元,其中 input_size 设置为当前 prev_sizehidden_size 设置为当前遍历到的隐藏层大小。每次迭代后,更新 prev_size 为当前隐藏层大小,以便下一层 LSTM 使用。

  • 添加最后一层 LSTM,其 input_size 为上一层 LSTM 的输出维度(即最后一个 hidden_size),hidden_sizenode_num * output_channel。这样最后一层 LSTM 的输出可以直接映射到所需形状的输出。

  • 定义一个全连接层(MLP)self.mlp,其输入维度为 input_len,输出维度为 output_len。该层用于将 LSTM 的输出时间步长调整为所需的 output_len

前向传播方法 (forward):

  • 输入 x 形状为 [Batch, Input_len, Node, Input_channel]

  • 展平节点和通道信息:将输入 reshape 为 [Batch, Input_len, Node * Input_channel],将节点和通道特征合并为一维。

  • 调整输入顺序:将输入 permute 为 [Input_len, Batch, Node * Input_channel],使时间步长成为第一维,便于 LSTM 处理。

  • 初始化 prev_output 为经过调整顺序后的输入 x,用于存储当前层的输出,供下一层 LSTM 使用。

  • 逐层处理:遍历 self.layers 中的所有 LSTM 单元,对 prev_output 进行前向传播,得到当前层的输出和隐含状态(output, (ht, ct))。将当前输出赋值给 prev_output,准备传递给下一层。

  • 调整输出顺序:将最后一层 LSTM 的输出 permute 回 [Batch, Node * Output_channel, Input_len],恢复到原始的批次和节点特征维度顺序,时间步长为第三维。

  • 调整时间步长:使用全连接层 self.mlp 对 LSTM 输出进行前向传播,将时间步长从 Input_len 调整为 Output_len,得到形状为 [Batch, Node * Output_channel, Output_len] 的中间结果。

  • 重新排列维度:将中间结果 permute 为 [Batch, Output_len, Node * Output_channel],使得输出序列长度成为第二维。

  • 重塑为所需输出形状:最后,将结果 reshape 为 [Batch, Output_len, Node, Output_channel],满足预期输出形状。

  • 返回处理后的输出。

总结来说,上述LSTM 类实现了对形状为 [Batch, Input_len, Node, Input_channel] 的输入数据进行多层 LSTM 处理,并通过全连接层调整时间步长,最终生成形状为 [Batch, Output_len, Node, Output_channel] 的输出。在处理过程中,节点特征被展平并与通道特征合并,以适应 LSTM 的输入要求。

训练、验证、测试

训练、验证、测试的代码可直接参见基于MLP算法实现交通流量预测(Pytorch版)。

代码基本一致,只需要修改Exp_LSTM_PEMS的_build_model即可:

def _build_model(self):if self.args.dataset == 'PEMS03':self.input_dim = 358elif self.args.dataset == 'PEMS04':self.input_dim = 307elif self.args.dataset == 'PEMS07':self.input_dim = 883elif self.args.dataset == 'PEMS08':self.input_dim = 170model = LSTM(node_num=self.input_dim, input_len=args.window_size, input_channel=1, hidden_sizes=args.hidden_sizes,output_len=args.horizon, output_channel=1)print(model)return model

上述模型,输入仅使用了流量这1个特征,然后来预测流量这1个特征,所以input_channeloutput_channel均为1,若使用多变量预测单变量,或者多变量预测多变量,读者可自行调整配置,此处不再赘述。

模型效果

最后,将我们构建好的MLP网络在PEMS数据集进行了准确性测试,算法测试的相关配置如下:

torch.manual_seed(4321)  # reproducible
parser = argparse.ArgumentParser(description='LSTM on pems datasets')
### -------  dataset settings --------------
parser.add_argument('--dataset', type=str, default='PEMS08',choices=['PEMS03', 'PEMS04', 'PEMS07', 'PEMS08'])  # sometimes use: PeMS08
parser.add_argument('--norm_method', type=str, default='z_score')
parser.add_argument('--normtype', type=int, default=0)
### -------  input/output length settings --------------
parser.add_argument('--window_size', type=int, default=12)
parser.add_argument('--horizon', type=int, default=12)
parser.add_argument('--train_length', type=float, default=6)
parser.add_argument('--valid_length', type=float, default=2)
parser.add_argument('--test_length', type=float, default=2)
### -------  training settings --------------
parser.add_argument('--use_gpu', type=bool, default=False)
parser.add_argument('--train', type=bool, default=True)
parser.add_argument('--resume', type=bool, default=False)
parser.add_argument('--evaluate', type=bool, default=False)
parser.add_argument('--finetune', type=bool, default=False)
parser.add_argument('--validate_freq', type=int, default=1)
parser.add_argument('--epoch', type=int, default=80)
parser.add_argument('--lr', type=float, default=0.001)
parser.add_argument('--batch_size', type=int, default=8)
parser.add_argument('--optimizer', type=str, default='N')  #
parser.add_argument('--early_stop', type=bool, default=True)
parser.add_argument('--early_stop_step', type=int, default=5)
parser.add_argument('--exponential_decay_step', type=int, default=5)
parser.add_argument('--decay_rate', type=float, default=0.5)
parser.add_argument('--lradj', type=int, default=1, help='adjust learning rate')
parser.add_argument('--weight_decay', type=float, default=1e-5)
parser.add_argument('--model_name', type=str, default='LSTM')
### -------  model settings --------------
parser.add_argument('--hidden_sizes', type=list, default=[64, 36, 64])
args = parser.parse_args()
Exp=Exp_LSTM_PEMS
exp=Exp(args)

可以看到,我们定义了4层LSTM,以PEMS03为例,因为PEMS03的节点数为358,所以4层LSTM的维度变化如下:

第1个LSTM: [batch, input_len, 358] --> [batch, input_len, 64]
第2个LSTM: [batch, input_len, 64] --> [batch, input_len, 36]
第3个LSTM: [batch, input_len, 36] --> [batch, input_len, 64]
第4个LSTM: [batch, input_len, 64] --> [batch, input_len, 358]

结果如下:

DatasetMAEMAPERMSE
PEMS0319.19570.18180432.8948
PEMS0423.24340.15568937.2810
PEMS0729.73810.12907747.9241
PEMS0820.46710.12773933.2526

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

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

相关文章

Linux驱动开发——(七)Linux阻塞和非阻塞IO

目录 一、阻塞和非阻塞IO简介 二、等待队列 2.1 等待队列头 2.2 等待队列项 2.3 将队列项添加/移除等待队列头 2.4 等待唤醒 2.5 等待事件 三、轮询 四、驱动代码 4.1 阻塞IO 4.2 非阻塞IO 一、阻塞和非阻塞IO简介 IO指的是Input/Output,也就是输入/输…

如何解决冲突性需求,看看TRIZ怎么做

​本田公司的产品经理(本田的产品经理被称为是大型产品领导人,large product leader)在设计第三代雅阁的时候,面临的需求主要集中在三个方面:1、视野要好;2、空间要大;3、发动机要强劲。 每一个…

TCP关闭连接时的一些思考

TCP协议是TCP/IP栈中最复杂的协议,它最大的优点是传输的可靠性,这通过面向连接、按序传输、超时重传、流量控制等机制保证其传输的可靠性。但这并不是我们今天要讨论的重点! TCP通信的过程分别是三个阶段:建立连接、传输数据、关…

图论基础知识 深度优先(Depth First Search, 简称DFS),广度优先(Breathe First Search, 简称DFS)

图论基础知识 学习记录自代码随想录 dfs 与 bfs 区别 dfs是沿着一个方向去搜,不到黄河不回头,直到搜不下去了,再换方向(换方向的过程就涉及到了回溯)。 bfs是先把本节点所连接的所有节点遍历一遍,走到下…

从单按键状态机思维扫描引申到4*4矩阵按键全键无冲扫描,一步一步教,超好理解,超好复现(STM32程序例子HAL库)

目前大部分代码存在的问题 ​ 单次只能对单个按键产生反应;多个按键按下就难以修改;并且代码耦合度较高,逻辑难以修改,对于添加长按,短按,双击的需求修改困难。 解决 16个按键按下无冲,并且代…

如何在CentOS本地搭建DataEase数据分析服务并实现远程查看数据分析

文章目录 前言1. 安装DataEase2. 本地访问测试3. 安装 cpolar内网穿透软件4. 配置DataEase公网访问地址5. 公网远程访问Data Ease6. 固定Data Ease公网地址 前言 DataEase 是开源的数据可视化分析工具,帮助用户快速分析数据并洞察业务趋势,从而实现业务…

【项目分享】用 Python 写一个桌面倒计日程序!

事情是这样的,我们班主任想委托我做一个程序,能显示还有几天考试。我立即理解了这个意思,接下了这个项目。 话不多说,来看看这个项目吧—— 项目简介 仓库地址:https://gitee.com/yaoqx/desktop-countdown-day 这是 …

幻兽帕鲁中文怎么设置 游戏中文修改方法 《幻兽帕鲁》宠物指定配种显示英文解决方法 幻兽帕鲁Steam游戏解说合集 Mac玩Windows游戏

在广阔的世界中收集神奇的生物“帕鲁”,派他们进行战斗、建造、做农活,工业生产等,这是一款支持多人游戏模式的全新开放世界生存制作游戏。幻兽帕鲁支持多人在线捕捉“帕鲁”,展开丰富的冒险玩法;不同的关卡具有不同的…

Bellman Ford算法:解决负权边图的最短路径问题

Bellman Ford算法的介绍 在计算机科学的世界中,Bellman Ford算法是一种解决单源最短路径问题的算法,它可以处理有负权边的图。这个算法的名字来源于两位科学家Richard Bellman和Lester Randolph Ford,他们是这个算法的发明者。 这个算法的主…

AI图书推荐:2024年ChatGPT副业搞钱指南

本书《2024年ChatGPT副业搞钱指南》(ChatGPT Side Hustles 2024)由Alec Rowe撰写,旨在指导读者如何利用ChatGPT技术来提升被动收入、创造新的现金流,并在数字化时代保持领先。 本书是深入了解被动收入未来的综合指南。本书揭示了超…

【算法基础实验】图论-基于DFS的连通性检测

基于DFS的连通性检测 理论基础 在图论中,连通分量是无向图的一个重要概念,特别是在处理图的结构和解析图的组成时。连通分组件表示图中的一个子图,在这个子图中任意两个顶点都是连通的,即存在一条路径可以从一个顶点到达另一个顶…

Flutter应用下拉菜单设计DropdownButtonFormField控件介绍

文章目录 DropdownButtonFormField介绍使用方法重点代码说明属性解释 注意事项 DropdownButtonFormField介绍 Flutter 中的 DropdownButtonFormField 是一个用于在表单中选择下拉菜单的控件。它是 DropdownButton 和 TextFormField 的组合,允许用户从一组选项中选择…

井字棋游戏

1. 游戏创建 1.1导包 from tkinter import * import numpy as np import math import tkinter.messagebox 1.2 窗口内容 1.2.1创建一个窗口 root Tk() # 窗口名称 root.title("井字棋 from Sun") 1.2.2 创建一个框架,将其放置在窗口中 Frame1 F…

汽车底盘域的学习笔记

前言:底盘域分为传统车型底盘域和新能源车型底盘域(新能源系统又可以分为纯电和混动车型,有时间可以再研究一下) 1:传统车型底盘域 细分的话可以分为四个子系统 传动系统 行驶系统 转向系统 制动系统 1.1传动系…

什么样的内外网文档摆渡,可以实现安全高效传输?

内外网文档摆渡通常指的是在内网(公司或组织的内部网络)和外网(如互联网)之间安全地传输文件的过程。这个过程需要特别注意安全性,因为内网往往包含敏感数据,直接连接内网和外网可能会带来安全风险。因此会…

设计模式——终止模式之两阶段终止模式

文章目录 1. 错误思路2. 两阶段终止模式2.1 利用 isInterrupted2.2 利用停止标记interrupt-打断park Two Phase Termination 在一个线程 T1 中如何“优雅”终止线程 T2?这里的【优雅】指的是给 T2 一个料理后事的机会。 1. 错误思路 使用线程对象的 stop() 方法停…

GEM TSU Interface Details and IEEE 1588 Support

摘要:Xilinx ZNYQ ULTRASCALE MPSOC的GEM和1588的使用 对于FPGA来说,只需要勾选一些znyq的配置就行了,其余的都是软件的工作; 所有配置都勾选之后,最终会露出来的接口如下: GEM需要勾选的配置如下&#xf…

15.Blender Eevee和Cycles渲染引擎对比

初步介绍 Eevee是实时渲染的引擎,会省略一些解算方式,尤其对光线和阴影 Cycles会考虑这些因素,所以会对光线和阴影的表达更加真实,有一个实时光线追踪的功能 Cycles渲染完之后,每移动一次画面,都会重新渲染…

政安晨:【Keras机器学习示例演绎】(十九)—— 可视化网络学习内容

目录 简介 设置 建立特征提取模型 设置梯度上升过程 设置端到端滤波器可视化回路 可视化目标层中的前 64 个滤波器 政安晨的个人主页:政安晨 欢迎 👍点赞✍评论⭐收藏 收录专栏: TensorFlow与Keras机器学习实战 希望政安晨的博客能够对您有所裨益&…

基于Rust的多线程 Web 服务器

构建多线程 Web 服务器 在 socket 上监听 TCP 连接解析少量的 HTTP 请求创建一个合适的 HTTP 响应使用线程池改进服务器的吞吐量优雅的停机和清理注意:并不是最佳实践 创建项目 ~/rust ➜ cargo new helloCreated binary (application) hello package~/rust ➜ma…