基于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.hqwc.cn/news/652258.html

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

相关文章

Visual Studio 对 C++ 头文件和模块的支持

在 C 编程领域,头文件和模块的管理有时候确实比较令人头疼。但是,有许多工具和功能可以简化此过程,提高效率并减少出错的可能性。下面是我们为 C 头文件和模块提供的几种工具的介绍。 构建明细 通过菜单栏 Build > Run Build Insights&a…

k8s学习(三十七)centos下离线部署kubernetes1.30(高可用)

文章目录 准备工作1、升级操作系统内核1.1、查看操作系统和内核版本1.2、下载内核离线升级包1.3、升级内核1.4、确认内核版本 2、修改主机名/hosts文件2.1、修改主机名2.2、修改hosts文件 3、关闭防火墙4、关闭SELINUX配置5、时间同步5.1、下载NTP5.2、卸载5.3、安装5.4、配置5…

43. UE5 RPG 实现敌人血量显示条

在上一篇文章中,我们实现了火球术伤害功能,在火球击中敌方目标,可以降低敌人20的血量,这个值现在是固定的,后面我们会修改火球的伤害设置。接着,我们也测试了功能是实现的,但是在正常的游玩过程…

tomcat 配置支持 ssl 附效果图

1、修改tomcat配置文件server.xml: vim ./conf/server.xml 把配置文件&#xff1a; <Connector port"8088" Server" " protocol"HTTP/1.1"connectionTimeout"20000"redirectPort"8443" URIEncoding"UTF-8" …

【办公类-22-14】周计划系列(5-6)“周计划-06 19周的周计划教案合并打印PDF(最终打印版))

背景需求&#xff1a; 花了十周&#xff0c;终于把周计划教案的文字都写满、加粗、节日替换了。为了便于打印&#xff0c;我把19周的周计划教案全部合并在一起PDF。制作打印用PDF 思路 1、周计划是单独打印一张&#xff0c;因此要在第2页插入空白页&#xff0c; 2、教案有3页…

数据库和表创建练习

一丶要求 1.创建一个数据库db_classes 2 创建一行表db_hero 3. 将四大名著中的常见人物插入这个英雄表 二丶创建db_classes一个数据库, 使用数据库默认的字符集 create database db_classes; 三丶创建一行表db_hero 1.先切换到我们创建的db_classes;数据库中 use db_class…

按现价和不变价计算与公布的统计指标主要有哪些

在经济统计和分析工作中 , 有些指标可以直接用实物量表示 , 如粮食和工业品产量等&#xff1b;而有些指标则是用价值量表示的 , 如全国居民人均可支配收入、社会消费品零售总额、商品房销售额等。在计算价值量指标时&#xff0c;一般均要考虑采用什么价格来计算。统计上常用的价…

【HTML图片压缩网页制作】

HTML图片压缩网页制作 效果图源码下期更新预报 效果图 源码 index.html <!doctype html> <html> <head> <meta charset"utf-8"> <title>图片压缩</title> <meta name"viewport" content"widthdevice-width,…

虚拟机VMware下ROS Neotic(Ubuntu 20.04)下安装OpenCV

一、ROS安装 ROS的官方安装步骤&#xff1a; 1、noetic / Ubuntu 20.04 &#xff1a; http://wiki.ros.org/noetic/Installation/Ubuntu 2、melodic / Ubuntu 18.04&#xff1a; http://wiki.ros.org/melodic/Installation/Ubuntu 3、kinetic / Ubuntu 16.04&#xff1a; http:…

Flutter基础语法

Flutter概要 Flutter目录结构 文件夹 作用 android android 平台相关代码 ios ios平台相关代码 lib flutter相关代码&#xff0c;我们主要编写的代码就在这个文件夹中 test 用于存放测试的代码 pubspec.yaml 配置文件&#xff0c;一般存放一些第三方库的依赖 Flutt…

SpringCloud系列(17)--将服务消费者Consumer注册进Zookeeper

前言&#xff1a;在上一章节中我们把服务提供者Provider注册进了Zookeeper&#xff0c;而本章节则是关于如何将服务消费者Consumer注册进Zookeeper 1、再次创建一个服务提供者模块&#xff0c;命名为consumerzk-order80 (1)在父工程下新建模块 (2)选择模块的项目类型为Maven并…

go基础(flag、json)

go基础 基础main函数数据类型类型转换switch函数计算效率go中实现工厂模式switch flag 解析命令行参数json结构体序列化map序列化struct 反序列化 基础 main函数 package main import "log" func main() {log.Println("hello world") }cd 到 main 文件夹下…