第R2周:LSTM-火灾温度预测

  • 🍨 本文为🔗365天深度学习训练营 中的学习记录博客
  • 🍖 原作者:K同学啊

一、什么是LSTM

1.LSTM的本质

长短时记忆网络(Long Short-Term Memory, LSTM)的本质是一种特殊的循环神经网络(Recurrent Neural Network, RNN),它被设计来解决标准RNN在处理长序列数据时遇到的梯度消失或梯度爆炸问题,这些问题限制了RNN在处理长距离依赖关系时的能力。
LSTM的核心创新在于它引入了所谓的“门控机制”(gates),这些门控机制允许网络学习何时让信息进入或离开网络,以及何时保留或更新长期状态。LSTM包含三个主要门控结构:

  1. 遗忘门(Forget Gate):决定哪些信息应该从单元状态(cell state)中丢弃。它通过查看前一个隐藏状态和当前输入,输出一个介于0和1之间的值给每个在单元状态中的数。1表示“完全保留这个信息”,而0表示“完全丢弃这个信息”。
  2. 输入门(Input Gate):决定哪些新的信息将被存储在单元状态中。它由两个部分组成:一个sigmoid函数决定哪些值将要更新,一个tanh函数创建一个新的候选值向量,可以被加到状态中。
  3. 输出门(Output Gate):决定下一个隐藏状态应该是什么。隐藏状态包含关于过去的输入的信息,输出门通过决定哪些信息应该被输出,来控制这些信息的流动。
    LSTM的单元状态可以在长序列中保持相对稳定的信息流,这使得LSTM特别适合于处理需要记忆长期依赖信息的任务,如语音识别、机器翻译、时间序列预测等。
    此外,LSTM还通过引入“细胞状态”(cell state)的概念,使得信息可以在网络中流动而不被干扰,从而解决了标准RNN在长序列学习中的稳定性问题。细胞状态在LSTM单元中贯穿始终,只有通过门控结构才能对其进行修改,这使得LSTM能够有效地学习长期依赖关系。

RNN的缺点以及LSTM如何解决这些问题的对比:

RNN的缺点:

  1. 梯度消失/梯度爆炸:在训练过程中,RNN的权重更新依赖于梯度,而梯度在反向传播过程中可能会指数级减小(消失)或增大(爆炸),这使得网络难以学习长期依赖关系。
  2. 难以捕捉长期依赖:由于梯度消失的问题,RNN在处理长序列时,很难保留早期信息对当前时刻的影响,导致网络性能下降。
  3. 状态更新不灵活:在标准的RNN中,状态更新是固定的,即前一个隐藏状态直接加到当前输入上,没有机制来选择性地保留或遗忘信息。

LSTM的提升:

  1. 门控机制:LSTM通过引入输入门、遗忘门和输出门,提供了更灵活的状态更新机制。这些门控结构可以控制信息的流入、保留和流出,从而有效避免梯度消失/梯度爆炸问题。
  2. 细胞状态(Cell State):LSTM有一个单独的细胞状态,它贯穿于整个序列,允许信息在长序列中流动而不被干扰。细胞状态可以通过门控结构进行选择性的更新,使得网络能够学习长期依赖关系。
  3. 长期依赖学习:由于上述机制,LSTM能够更好地捕捉和表示长期依赖关系,这使得它在处理需要记忆长期信息的任务上表现出色。
    总的来说,LSTM通过其特殊的网络结构和门控机制,解决了标准RNN在处理长序列数据时的主要问题,提升了网络在处理长期依赖关系时的性能。

2.LSTM的原理

从隐藏状态的产生、传递和计算角度来解释LSTM(长短时记忆网络)的原理,可以分为以下几个步骤:

隐藏状态的产生

  1. 初始化:在序列的开始,LSTM的隐藏状态通常被初始化为全零向量。
  2. 遗忘门:在处理序列的每个时间步时,LSTM首先通过遗忘门决定哪些信息应该从细胞状态中丢弃。遗忘门的输出是一个介于0和1之间的向量,表示每个在细胞状态中的信息应该被保留的程度。
  3. 输入门和候选状态:接着,LSTM通过输入门决定哪些新的信息将被存储在细胞状态中。输入门输出一个介于0和1之间的向量,表示每个候选值应该被添加到细胞状态中的程度。同时,LSTM会生成一个候选值向量,它包含了可能被添加到细胞状态中的新信息。
  4. 更新细胞状态:细胞状态在当前时间步被更新。LSTM会根据遗忘门的输出和候选值向量来更新细胞状态。
  5. 输出门:最后,LSTM通过输出门决定细胞状态中的哪些信息应该被输出。输出门的输出是一个介于0和1之间的向量,表示细胞状态中哪些信息应该影响当前时间步的隐藏状态。

隐藏状态的传递

隐藏状态在LSTM中起到了传递序列历史信息的作用。在每个时间步,隐藏状态会根据细胞状态和输入门的输出生成。这个隐藏状态包含了在当前时间步需要传递给后续层的信息,并且会作为下一个时间步的输入的一部分。

隐藏状态的计算

隐藏状态的计算是通过将细胞状态通过一个tanh函数(将值压缩到-1和1之间)然后乘以输出门的输出来生成的。这个计算过程确保了隐藏状态包含了当前时间步的细胞状态中的相关信息,并且可以传递给后续层或下一个时间步。
通过这种方式,LSTM能够有效地处理序列数据,并学习到序列中的长期依赖关系。隐藏状态的产生、传递和计算是LSTM实现这一目标的关键步骤。

二、pytorch实现

1.前期准备工作

import torch.nn.functional as F  
import numpy as np  
import pandas as pd  
import torch  
from torch    import nn

(1)导入数据

data = pd.read_csv("woodpine2.csv")  
print(data)

输出
在这里插入图片描述

(2)数据集可视化

snsseaborn 库的简称,这是一个在 Python 中用于数据可视化的库,它基于 matplotlib 库构建,提供了更为美观和高级的绘图样式。seaborn 专门针对统计图表进行了优化,使得创建具有吸引力的、信息丰富的图表变得简单。
下面是这段代码中使用的 seaborn 库的函数及其作用和参数的含义:

  1. sns.lineplot
    • 作用:这个函数用于绘制线形图,非常适合展示数据随时间或其他连续变量的变化趋势。
    • 参数:
      • data:这个参数接受一个 pandas Series、DataFrame 或数组。在这个例子中,它接受的是 data["Tem1"]data["CO 1"]data["Soot 1"],它们应该是 DataFrame 中的列,表示不同的数据集。
      • ax:这个参数允许你指定一个轴(matplotlib Axes 对象),在这个轴上绘制图形。在提供的代码中,ax=ax[0]ax=ax[1]ax=ax[2] 分别指定了三个子图中的一个来绘制对应的线形图。
import matplotlib.pyplot as plt
import seaborn as sns
plt.rcParams['savefig.dpi'] = 500 # 图片像素
plt.rcParams['figure.dpi'] = 500 # 分辨率
fig, ax = plt.subplots(1,3,constrained_layout=True, figsize=(14,3))
sns.lineplot(data=data["Tem1"], ax=ax[0])
sns.lineplot(data=data["CO 1"], ax=ax[1])
sns.lineplot(data=data["Soot 1"], ax=ax[2])
plt.show()

输出
在这里插入图片描述

这行代码的作用是选择 data 这个 pandas DataFrame 中的所有行和除了第一列之外的所有列。
下面是代码的详细解释:

  • datadata 是一个 pandas DataFrame 对象,它包含了原始数据集。
  • .iloc:这是 pandas DataFrame 提供的一个索引器,用于通过行和列的索引位置进行数据选择。与 .loc 不同,.loc 是基于标签的索引器,.iloc 是基于整数位置的索引器。
  • ::这表示选择所有行。在 Python 中,单独的冒号 : 通常用作范围操作符,在这里它表示从起始位置到结束位置的全部范围。由于没有指定起始和结束,所以默认选择所有行。
  • ,1:]:这表示选择除了第一列之外的所有列。在 Python 中,切片操作 1: 表示从索引 1 开始,一直到最后一个元素。由于列的索引是从 0 开始的,所以 1: 实际上是从第二列开始,直到最后一列。

综上所述,data.iloc[:,1:] 这行代码会选择 data DataFrame 的所有行和从第二列开始到最后一列的所有列。如果你有一个具有多列的 DataFrame,并且想要排除第一列(比如排除一个索引列或者分类列),这行代码就非常有用。

dataFrame = data.iloc[:,1:]
dataFrame

输出
在这里插入图片描述

2、构建数据集

(1)数据集预处理

from sklearn.preprocessing import MinMaxScaler
  • from sklearn.preprocessing import MinMaxScaler:这行代码从 sklearn.preprocessing 模块中导入 MinMaxScaler 类。MinMaxScaler 是一个用于数据归一化的工具,它可以将每个特征缩放到一个指定的范围,通常是0到1。
dataFrame = data.iloc[:,1:].copy()
  • data.iloc[:,1:]:这部分选择 data DataFrame 的所有行和从第二列开始到最后一列的所有列。
  • .copy():这个方法创建了一个新的 DataFrame,它是原始 DataFrame 的一个副本。这是为了防止后续的操作影响到原始的 data DataFrame。
sc = MinMaxScaler(feature_range=(0,1))
  • sc = MinMaxScaler(feature_range=(0,1)):创建一个 MinMaxScaler 对象,名为 scfeature_range=(0,1) 参数指定了归一化的范围,即每个特征的值将被缩放到0到1之间。
for i in ['CO 1', 'Soot 1', 'Tem1']:
  • 这行代码开始一个循环,循环变量 i 将遍历列表 ['CO 1', 'Soot 1', 'Tem1'] 中的每个元素。这个列表包含了要归一化的列名。
    dataFrame[i] = sc.fit_transform(dataFrame[i].values.reshape(-1,1))
  • dataFrame[i]:选择 DataFrame 中名为 i 的列。
  • .values:这个属性返回列中的值,作为 NumPy 数组。
  • .reshape(-1,1):这个方法改变数组的形状,使其成为一个二维数组,其中 -1 表示自动计算行数,1 表示列数。MinMaxScaler 需要二维数组作为输入。
  • sc.fit_transform():这是一个组合方法,fit 方法计算数据的转换参数(例如,每个特征的最大值和最小值),然后 transform 方法使用这些参数来转换数据。这里,它将 dataFrame[i] 的值缩放到0到1之间。
dataFrame.shape
  • dataFrame.shape:这个属性返回 DataFrame 的形状,即行数和列数。这个操作没有改变 DataFrame,只是返回其维度信息,通常用于确认数据操作后 DataFrame 的结构是否正确。
    总结来说,这段代码的作用是创建一个新的 DataFrame,然后对其中的特定列(‘CO 1’, ‘Soot 1’, ‘Tem1’)进行归一化处理,使其值在0到1之间。最后,打印出归一化后 DataFrame 的形状。
from sklearn.preprocessing import MinMaxScaler

dataFrame = data.iloc[:,1:].copy()
sc = MinMaxScaler(feature_range=(0,1)) #将数据归一化,范围是0到1

for i in ['CO 1', 'Soot 1', 'Tem1']:
    dataFrame[i] = sc.fit_transform(dataFrame[i].values.reshape(-1,1))

dataFrame.shape

输出
(5948, 3)

(2)设置x,y

width_x=8
width_y=1
  • width_x=8:定义变量 width_x,表示输入特征的时间段宽度,这里设置为8。
  • width_y=1:定义变量 width_y,表示预测目标的时间段宽度,这里设置为1。
x=[]
y=[]
  • x=[]y=[]:初始化两个空列表 xy,用于存储输入特征和目标值。
in_start =0
  • in_start =0:定义变量 in_start,它是循环中用来追踪输入数据开始索引的变量,初始值设为0。
for _, _ in data.iterrows():
  • for _, _ in data.iterrows():开始一个循环,遍历 data DataFrame 的每一行。iterrows() 方法返回每一行的索引和内容,但这里我们不需要使用这些值,所以使用 _ 来忽略它们。
    in_end = in_start + width_x
    out_end = in_end + width_y
  • in_end = in_start + width_x:计算当前输入特征的结束索引。
  • out_end = in_end + width_y:计算当前目标值的结束索引。
    if out_end < len(dataFrame):
  • if out_end < len(dataFrame):检查是否还有足够的数据来形成一个完整的输入-输出对。如果 out_end 超出了 DataFrame 的长度,则不执行下面的代码。
        x_ = np.array(dataFrame.iloc[in_start:in_end,])
        y_ = np.array(dataFrame.iloc[in_end:out_end,0])
  • x_ = np.array(dataFrame.iloc[in_start:in_end,]):从 DataFrame 中提取从 in_startin_end 的行,并转换为 NumPy 数组,存储在变量 x_ 中。
  • y_ = np.array(dataFrame.iloc[in_end:out_end,0]):从 DataFrame 中提取从 in_endout_end 的第一列(‘Tem1’),并转换为 NumPy 数组,存储在变量 y_ 中。
        x.append(x_)
        y.append(y_)
  • x.append(x_)y.append(y_):将 x_y_ 分别添加到列表 xy 中。
    in_start += 1
  • in_start += 1:将 in_start 的值增加1,以便在下一次循环时移动到下一个输入窗口的开始位置。
x = np.array(x)
y = np.array(y).reshape(-1,1,1)
  • x = np.array(x):将列表 x 转换为 NumPy 数组。
  • y = np.array(y).reshape(-1,1,1):将列表 y 转换为 NumPy 数组,并重新调整其形状,以适应模型输入的要求。-1 表示自动计算行数,1 表示有两个维度,每个维度大小为1。
x.shape, y.shape
  • x.shape, y.shape:打印数组 xy 的形状。这是为了确认数据的维度是否符合预期。
    总结来说,这段代码的作用是从 dataFrame 中提取时间序列数据,形成输入特征 x 和目标值 y。输入特征 x 是连续的8个时间段的 ‘Tem1’、‘CO 1’、‘Soot 1’ 数据,而目标值 y 是紧接着的第9个时间段的 ‘Tem1’ 数据。最终,这些数据被转换为 NumPy 数组,并调整形状以供后续使用,如机器学习模型的训练。
width_x=8
width_y=1

##取前8个时间段的Tem1、CO1、Soot1为x,第9个时间段的Tem1为y。
x=[]
y=[]
in_start =0

for _, _ in data.iterrows():
    in_end = in_start + width_x
    out_end = in_end + width_y
    
    if out_end < len(dataFrame):
        x_ = np.array(dataFrame.iloc[in_start:in_end,])
        y_ = np.array(dataFrame.iloc[in_end:out_end,0])
        
        x.append(x_)
        y.append(y_)
        
    in_start += 1
    
x = np.array(x)
y = np.array(y).reshape(-1,1,1)

x.shape, y.shape

输出
((5939, 8, 3), (5939, 1, 1))

print(np.any(np.isnan(x)))
  • np.isnan(x)np.isnan 是 NumPy 库中的一个函数,用于检测数组 x 中的元素是否为 NaN(Not a Number),即非数字值。它返回一个布尔数组,其中 True 表示相应的元素是 NaN。
  • np.any()np.any 是 NumPy 库中的一个函数,用于测试数组中是否至少有一个元素为 True。如果数组中至少有一个 True,则返回 True,否则返回 False
  • print(np.any(np.isnan(x))):这行代码首先检查数组 x 中是否有任何 NaN 值,然后打印结果。如果 x 中至少有一个 NaN 值,将打印 True,否则打印 False
print(np.any(np.isnan(x)))
print(np.any(np.isnan(y)))

输出
print(np.any(np.isnan(x)))
print(np.any(np.isnan(y)))

(3)划分数据集

x_train = torch.tensor(np.array(x[:5000]), dtype=torch.float32)
y_train = torch.tensor(np.array(y[:5000]), dtype=torch.float32)

x_test = torch.tensor(np.array(x[5000:]), dtype=torch.float32)
y_test = torch.tensor(np.array(y[5000:]), dtype=torch.float32)
x_train.shape, y_train.shape

输出
(torch.Size([5000, 8, 3]), torch.Size([5000, 1, 1]))

from torch.utils.data import TensorDataset, DataLoader

train_dl = DataLoader(TensorDataset(x_train, y_train), batch_size=64, shuffle=False)

test_dl = DataLoader(TensorDataset(x_test, y_test), batch_size=64, shuffle=False)

3、模型训练

(1)构建模型

这段代码定义了一个名为 model_lstm 的 PyTorch 模型类,它继承自 nn.Module

class model_lstm(nn.Module):
  • 这行代码定义了一个名为 model_lstm 的类,该类继承自 nn.Modulenn.Module 是 PyTorch 中所有神经网络模块的基类。
    def __init__(self):
        super(model_lstm, self).__init__()
  • def __init__(self)::这是类的构造函数,用于初始化类的实例。
  • super(model_lstm, self).__init__():这行代码调用父类 nn.Module 的构造函数,这是 PyTorch 中初始化模块的标准做法。
        self.lstmθ = nn.LSTM(input_size=3, hidden_size=320, num_layers=1, batch_first=True)
  • self.lstmθ = nn.LSTM(...):这行代码创建一个 LSTM 层,并将其赋值给实例变量 self.lstmθ
    • input_size=3:指定输入特征的维度,这里为3,意味着每个时间步有3个特征。
    • hidden_size=320:指定 LSTM 层的隐藏层大小,这里为320。
    • num_layers=1:指定 LSTM 层的层数,这里为1。
    • batch_first=True:指定输入数据的格式,如果为 True,则输入数据的形状应该是 [batch_size, sequence_length, input_size]
        self.lstm1 = nn.LSTM(input_size=320, hidden_size=320, num_layers=1, batch_first=True)
  • self.lstm1 = nn.LSTM(...):与上面类似,这行代码创建另一个 LSTM 层,并将其赋值给实例变量 self.lstm1
        self.fcθ = nn.Linear(320, 1)
  • self.fcθ = nn.Linear(320, 1):这行代码创建一个全连接层(线性层),并将其赋值给实例变量 self.fcθ
    • 320:指定输入特征的数量,与 LSTM 层的隐藏层大小相同。
    • 1:指定输出特征的数量,这里为1,因为我们要预测一个值。
    def forward(self, x):
  • def forward(self, x)::定义 forward 方法,这是神经网络模型的前向传播函数。
        out, hidden1 = self.lstmθ(x)
  • out, hidden1 = self.lstmθ(x):这行代码对输入 x 应用第一个 LSTM 层,并返回输出 out 和最后一个时间步的隐藏状态 hidden1
        out, _ = self.lstm1(out, hidden1)
  • out, _ = self.lstm1(out, hidden1):这行代码对前一个 LSTM 层的输出 out 和隐藏状态 hidden1 应用第二个 LSTM 层,并返回输出 out。下划线 _ 用于忽略返回的隐藏状态。
        out = self.fcθ(out)
  • out = self.fcθ(out):这行代码将第二个 LSTM 层的输出 out 传递给全连接层 self.fcθ,得到最终的输出。
        return out[::,-1:] #取2个预测值,否则经过lstm会得到8*2个预测
  • return out[::,-1:]:这行代码返回最终的预测结果。这里使用切片操作 [::,-1:] 来选择每个序列的最后一个时间步的输出,因为我们的目标是预测每个序列的最后一个值。
model = model_lstm()
  • model = model_lstm():这行代码创建 model_lstm 类的一个实例,并将其赋值给变量 model
model
  • model:这行代码打印模型的结构,它会显示模型中的层和它们的参数。
    总结来说,这段代码定义了一个具有两个 LSTM 层和一个全连接层的 PyTorch 模型,用于时间序列预测。模型接受维度为 [batch_size, sequence_length, input_size] 的输入,并输出每个序列的最后一个预测值。
class model_lstm(nn.Module):
    def __init__(self):
        super(model_lstm, self).__init__()
        self.lstmθ = nn.LSTM(input_size=3, hidden_size=320, num_layers=1, batch_first=True)
        self.lstm1 = nn.LSTM(input_size=320, hidden_size=320, num_layers=1, batch_first=True)
        self.fcθ = nn.Linear(320, 1)
    def forward(self, x):
        out, hidden1 = self.lstmθ(x)
        out, _ = self.lstm1(out, hidden1)
        out = self.fcθ(out)
        return out[::,-1:] #取2个预测值,否则经过lstm会得到8*2个预测
model = model_lstm()
model

输出
在这里插入图片描述
检验模型输出数据集的格式

model(torch.rand(30,8,3)).shape

输出
torch.Size([30, 1, 1])

(2)定义训练函数

这段代码定义了一个名为 train 的函数,用于训练一个 PyTorch 模型。以下是代码的逐行解释,包括每个函数的作用和参数的含义:

import copy
  • 这行代码导入 Python 标准库中的 copy 模块,该模块提供了一些用于复制对象的函数。尽管在这段代码中没有直接使用 copy 模块,但它可能用于其他部分的代码中。
def train(train_dl, model, loss_fn, opt, lr_scheduler=None):
  • 这行代码定义了 train 函数,它接受以下参数:
    • train_dl:训练数据的数据加载器(DataLoader),它负责批处理和打乱数据。
    • model:要训练的 PyTorch 模型。
    • loss_fn:用于计算损失的损失函数。
    • opt:优化器,用于更新模型的权重。
    • lr_scheduler:学习率调度器,它是可选的,用于在训练过程中调整学习率。
    size = len(train_dl.dataset)
  • 这行代码获取训练数据集的总大小。
    num_batches = len(train_dl)
  • 这行代码计算训练数据加载器中的批次数。
    train_loss = 0 #初始化训练损失和正确率
  • 这行代码初始化 train_loss 变量,用于累积训练过程中的总损失。
    for x, y in train_dl:
  • 这行代码开始一个循环,遍历 train_dl 中的每个批次的数据。xy 分别是批次中的输入数据和标签。
        x, y = x.to(device), y.to(device)
  • 这行代码将输入数据和标签移动到计算设备上(通常是 GPU)。
        pred = model(x)
  • 这行代码通过模型 model 前向传播输入数据 x,得到预测结果 pred
        loss = loss_fn(pred, y)
  • 这行代码使用损失函数 loss_fn 计算预测结果 pred 和真实标签 y 之间的损失。
        opt.zero_grad()
  • 这行代码清除优化器 opt 中所有参数的梯度,为下一次反向传播做准备。
        loss.backward()
  • 这行代码执行反向传播,计算损失关于模型参数的梯度。
        opt.step()
  • 这行代码根据计算出的梯度更新模型参数。
        train_loss += loss.item()
  • 这行代码累加当前批次的损失到 train_loss 变量中。
    if lr_scheduler is not None:
        lr_scheduler.step()
        print("learning rate = {:.5f}".format(opt.param_groups[0]['lr']))
  • 这行代码检查是否提供了学习率调度器 lr_scheduler。如果是,则在每个训练周期后更新学习率,并打印当前学习率。
    train_loss /= num_batches
  • 这行代码计算平均训练损失,通过将累积的损失除以批次数。
    return train_loss
  • 这行代码返回计算出的平均训练损失。
    总结来说,train 函数负责执行一个训练周期,包括前向传播、计算损失、反向传播、更新模型参数,以及计算和返回平均训练损失。如果提供了学习率调度器,它还会在每个周期后更新学习率。
import copy
def train(train_dl, model, loss_fn, opt, lr_scheduler=None):
    size = len(train_dl.dataset)
    num_batches = len(train_dl)
    train_loss = 0 #初始化训练损失和正确率
    
    for x, y in train_dl:
        x, y = x.to(device), y.to(device)
        
        #计算预测误差
        pred = model(x)
        
        #网络输出
        loss = loss_fn(pred, y) #计算网络输出和真实值之间的差距
        
        #反向传播
        opt.zero_grad() # grad属性归零
        loss.backward() #反向传播
        opt.step() #每一步自动更新
        #记录loss
        train_loss += loss.item()
        
    if lr_scheduler is not None:
        lr_scheduler.step()
        print("learning rate = {:.5f}".format(opt.param_groups[0]['lr']))
    train_loss /= num_batches
    return train_loss

(3)定义测试函数

这段代码定义了一个名为 test 的函数,用于评估一个 PyTorch 模型在测试数据集上的性能。以下是代码的逐行解释,包括每个函数的作用和参数的含义:

def test(dataloader, model, loss_fn):
  • 这行代码定义了 test 函数,它接受以下参数:
    • dataloader:测试数据的数据加载器(DataLoader),它负责批处理数据。
    • model:要评估的 PyTorch 模型。
    • loss_fn:用于计算损失的损失函数。
    size = len(dataloader.dataset)
  • 这行代码获取测试数据集的总大小。
    num_batches = len(dataloader)
  • 这行代码计算测试数据加载器中的批次数。
    test_loss = 0
  • 这行代码初始化 test_loss 变量,用于累积测试过程中的总损失。
    with torch.no_grad():
  • 这行代码开始一个上下文管理器 with torch.no_grad(),它告诉 PyTorch 在接下来的代码块中不需要计算或存储梯度。这是因为在测试阶段,我们不需要进行梯度更新。
        for x, y in dataloader:
  • 这行代码开始一个循环,遍历 dataloader 中的每个批次的数据。xy 分别是批次中的输入数据和标签。
            x, y = x.to(device), y.to(device)
  • 这行代码将输入数据和标签移动到计算设备上(通常是 GPU)。
            y_pred = model(x)
  • 这行代码通过模型 model 前向传播输入数据 x,得到预测结果 y_pred
            loss = loss_fn(y_pred, y)
  • 这行代码使用损失函数 loss_fn 计算预测结果 y_pred 和真实标签 y 之间的损失。
            test_loss += loss.item()
  • 这行代码累加当前批次的损失到 test_loss 变量中。
    test_loss /= num_batches
  • 这行代码计算平均测试损失,通过将累积的损失除以批次数。
    return test_loss
  • 这行代码返回计算出的平均测试损失。
    总结来说,test 函数负责执行模型的测试阶段,计算模型在测试数据集上的平均损失。它通过前向传播来获取预测结果,然后计算预测结果与真实标签之间的损失,并最终返回平均损失值。在测试过程中,由于不需要进行梯度更新,所以使用了 torch.no_grad() 来节省计算资源。
def test(dataloader, model, loss_fn):
    size = len(dataloader.dataset) # 测试集的大小
    num_batches = len(dataloader)  # 批次数目
    test_loss = 0
    
    # 当不进行训练时,停止梯度更新,节省计算内存消耗
    with torch.no_grad():
        for x, y in dataloader:
            x, y = x.to(device), y.to(device)
            y_pred = model(x)
            loss = loss_fn(y_pred, y)
            test_loss += loss.item()
    test_loss /= num_batches
    return test_loss

(4)正式训练模型

这里可能会道导致输入数据和参数数据不在同一个设备上的报错。这里教案上的带代码是

device=torch.device("cuda" if torch.cuda.is_available() else "cpu")  
device

但是后面训练后在调用模型进行微调那一步会出现报错如下
在这里插入图片描述
这里我是把参数张量也转移到cpu上了
可以参考这篇文章
Pytorch 如何解决在 pytorch 中的 ‘Input and hidden tensors are not at the same device’ 错误

device=torch.device("cpu")  
device

输出
device(type=‘cpu’)
这段代码是用于训练和评估一个LSTM模型的Python脚本的一部分。以下是代码的逐行解释,包括每个函数的作用和参数的含义:

# 训练模型
model = model_lstm()
model = model.to(device)
  • model = model_lstm():这行代码创建了一个model_lstm类的实例。
  • model = model.to(device):这行代码将模型model移动到指定的计算设备上,通常是GPU。
loss_fn = nn.MSELoss() # 创建损失函数
  • loss_fn = nn.MSELoss():这行代码创建一个均方误差(Mean Squared Error, MSE)损失函数,用于评估模型的预测与真实值之间的差异。
learn_rate = 1e-1 # 学习率
  • learn_rate = 1e-1:这行代码设置学习率为0.1。
opt = torch.optim.SGD(model.parameters(), lr=learn_rate, weight_decay=1e-4)
  • opt = torch.optim.SGD(...):这行代码创建一个Stochastic Gradient Descent (SGD)优化器,用于更新模型的权重。
    • model.parameters():这行代码指定优化器将更新model的所有参数。
    • lr=learn_rate:这行代码指定学习率为learn_rate
    • weight_decay=1e-4:这行代码指定权重衰减系数为0.0001,用于防止过拟合。
epochs = 50
  • epochs = 50:这行代码设置训练周期数为50。
train_loss = []
test_loss = []
  • train_loss = []test_loss = []:这行代码分别初始化两个列表train_losstest_loss,用于存储训练和测试过程中的损失值。
lr_scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(opt, epochs, last_epoch=-1)
  • lr_scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(...):这行代码创建一个余弦退火学习率调度器。
    • opt:这行代码指定优化器,学习率调度器将应用于该优化器。
    • epochs:这行代码指定训练周期数,学习率调度器将在每个周期结束时调整学习率。
    • last_epoch=-1:这行代码指定学习率调度器的起始周期为-1,意味着它将从第一个周期开始调整学习率。
for epoch in range(epochs):
  • 这行代码开始一个循环,循环变量 epoch 将在 0epochs-1 之间遍历。epochs 是训练周期的总数。
    model.train()
  • 这行代码将模型设置为训练模式。在训练模式下,模型的某些部分(如批标准化层)会根据训练数据进行调整。
    epoch_train_loss = train(train_dl, model, loss_fn, opt, lr_scheduler)
  • 这行代码调用 train 函数,将模型在训练数据集 train_dl 上进行训练。train 函数计算当前训练周期的损失,并返回这个损失值。
    • train_dl:训练数据的数据加载器。
    • model:要训练的PyTorch模型。
    • loss_fn:用于计算损失的损失函数。
    • opt:优化器,用于更新模型的权重。
    • lr_scheduler:学习率调度器,用于在训练过程中调整学习率。
    model.eval()
  • 这行代码将模型设置为评估模式。在评估模式下,模型的某些部分(如批标准化层)不会根据训练数据进行调整。
    epoch_test_loss = test(test_dl, model, loss_fn)
  • 这行代码调用 test 函数,将模型在测试数据集 test_dl 上进行评估。test 函数计算当前评估周期的损失,并返回这个损失值。
    • test_dl:测试数据的数据加载器。
    • model:要评估的PyTorch模型。
    • loss_fn:用于计算损失的损失函数。
    train_loss.append(epoch_train_loss)
  • 这行代码将当前训练周期的损失值 epoch_train_loss 添加到列表 train_loss 中。
    test_loss.append(epoch_test_loss)
  • 这行代码将当前评估周期的损失值 epoch_test_loss 添加到列表 test_loss 中。
    template = ('Epoch:{:2d}, Train_loss:{:.5f}, Test_loss:{:.5f}')
  • 这行代码定义了一个格式化字符串模板,用于打印当前周期的训练和测试损失。
    • 'Epoch:{:2d}':格式化字符串,用于打印周期的编号,格式为两位数字。
    • 'Train_loss:{:.5f}':格式化字符串,用于打印训练损失,格式为五位小数。
    • 'Test_loss:{:.5f}':格式化字符串,用于打印测试损失,格式为五位小数。
    print(template.format(epoch+1, epoch_train_loss, epoch_test_loss))
  • 这行代码使用格式化字符串模板打印当前周期的训练和测试损失。epoch+1 是因为循环是从 0 开始的,而打印时通常从 1 开始。
#训练模型
model = model_lstm()
model = model.to(device)
loss_fn = nn.MSELoss() #创建损失函数
learn_rate = 1e-1 #学习率
opt = torch.optim.SGD(model.parameters(),lr=learn_rate,weight_decay=1e-4)
epochs = 50
train_loss = []
test_loss = []
lr_scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(opt, epochs, last_epoch=-1)

for epoch in range(epochs):
    model.train()
    epoch_train_loss = train(train_dl, model, loss_fn, opt, lr_scheduler)
    model.eval()
    epoch_test_loss = test(test_dl, model, loss_fn)
    train_loss.append(epoch_train_loss)
    test_loss.append(epoch_test_loss)
    template = ('Epoch:{:2d}, Train_loss:{:.5f}, Test_loss:{:.5f}')
    print(template.format(epoch+1, epoch_train_loss, epoch_test_loss))
    
print("="*20, 'Done', "="*20)

输出
learning rate = 0.09990
Epoch: 1, Train_loss:0.00125, Test_loss:0.01216
learning rate = 0.09961
Epoch: 2, Train_loss:0.01388, Test_loss:0.01182
learning rate = 0.09911
Epoch: 3, Train_loss:0.01361, Test_loss:0.01145
learning rate = 0.09843
Epoch: 4, Train_loss:0.01330, Test_loss:0.01106
learning rate = 0.09755
Epoch: 5, Train_loss:0.01294, Test_loss:0.01063
learning rate = 0.09649
Epoch: 6, Train_loss:0.01252, Test_loss:0.01014
learning rate = 0.09524
Epoch: 7, Train_loss:0.01201, Test_loss:0.00960
learning rate = 0.09382
Epoch: 8, Train_loss:0.01141, Test_loss:0.00899
learning rate = 0.09222
Epoch: 9, Train_loss:0.01071, Test_loss:0.00832
learning rate = 0.09045
Epoch:10, Train_loss:0.00989, Test_loss:0.00758
learning rate = 0.08853
Epoch:11, Train_loss:0.00897, Test_loss:0.00680
learning rate = 0.08645
Epoch:12, Train_loss:0.00797, Test_loss:0.00599
learning rate = 0.08423
Epoch:13, Train_loss:0.00691, Test_loss:0.00518
learning rate = 0.08187
Epoch:14, Train_loss:0.00583, Test_loss:0.00439
learning rate = 0.07939
Epoch:15, Train_loss:0.00479, Test_loss:0.00366
learning rate = 0.07679
Epoch:16, Train_loss:0.00382, Test_loss:0.00302
learning rate = 0.07409
Epoch:17, Train_loss:0.00296, Test_loss:0.00246
learning rate = 0.07129
Epoch:18, Train_loss:0.00224, Test_loss:0.00200
learning rate = 0.06841
Epoch:19, Train_loss:0.00166, Test_loss:0.00164
learning rate = 0.06545
Epoch:20, Train_loss:0.00122, Test_loss:0.00136
learning rate = 0.06243
Epoch:21, Train_loss:0.00088, Test_loss:0.00115
learning rate = 0.05937
Epoch:22, Train_loss:0.00064, Test_loss:0.00099
learning rate = 0.05627
Epoch:23, Train_loss:0.00047, Test_loss:0.00087
learning rate = 0.05314
Epoch:24, Train_loss:0.00036, Test_loss:0.00079
learning rate = 0.05000
Epoch:25, Train_loss:0.00028, Test_loss:0.00073
learning rate = 0.04686
Epoch:26, Train_loss:0.00022, Test_loss:0.00068
learning rate = 0.04373
Epoch:27, Train_loss:0.00018, Test_loss:0.00065
learning rate = 0.04063
Epoch:28, Train_loss:0.00016, Test_loss:0.00062
learning rate = 0.03757
Epoch:29, Train_loss:0.00014, Test_loss:0.00060
learning rate = 0.03455
Epoch:30, Train_loss:0.00013, Test_loss:0.00058
learning rate = 0.03159
Epoch:31, Train_loss:0.00012, Test_loss:0.00057
learning rate = 0.02871
Epoch:32, Train_loss:0.00012, Test_loss:0.00056
learning rate = 0.02591
Epoch:33, Train_loss:0.00011, Test_loss:0.00055
learning rate = 0.02321
Epoch:34, Train_loss:0.00011, Test_loss:0.00055
learning rate = 0.02061
Epoch:35, Train_loss:0.00011, Test_loss:0.00055
learning rate = 0.01813
Epoch:36, Train_loss:0.00011, Test_loss:0.00055
learning rate = 0.01577
Epoch:37, Train_loss:0.00012, Test_loss:0.00055
learning rate = 0.01355
Epoch:38, Train_loss:0.00012, Test_loss:0.00055
learning rate = 0.01147
Epoch:39, Train_loss:0.00012, Test_loss:0.00056
learning rate = 0.00955
Epoch:40, Train_loss:0.00012, Test_loss:0.00057
learning rate = 0.00778
Epoch:41, Train_loss:0.00013, Test_loss:0.00058
learning rate = 0.00618
Epoch:42, Train_loss:0.00013, Test_loss:0.00058
learning rate = 0.00476
Epoch:43, Train_loss:0.00013, Test_loss:0.00059
learning rate = 0.00351
Epoch:44, Train_loss:0.00014, Test_loss:0.00060
learning rate = 0.00245
Epoch:45, Train_loss:0.00014, Test_loss:0.00060
learning rate = 0.00157
Epoch:46, Train_loss:0.00014, Test_loss:0.00060
learning rate = 0.00089
Epoch:47, Train_loss:0.00014, Test_loss:0.00060
learning rate = 0.00039
Epoch:48, Train_loss:0.00014, Test_loss:0.00060
learning rate = 0.00010
Epoch:49, Train_loss:0.00014, Test_loss:0.00060
learning rate = 0.00000
Epoch:50, Train_loss:0.00014, Test_loss:0.00060
==================== Done ====================

4.模型评估

(1)Loss图

import matplotlib.pyplot as plt

plt.figure(figsize=(5,3),dpi=120)

plt.plot(train_loss, label='LSTM Training Loss')
plt.plot(test_loss, label='LSTM Validation Loss')

plt.title('Training and Validation Loss')
plt.legend()
plt.show()

输出
在这里插入图片描述

(2)调用模型进行预测

这段代码是用于绘制时间序列预测模型的真实值和预测值对比曲线的Python脚本的一部分。以下是代码的逐行解释,包括每个函数的作用和参数的含义:

predicted_y_lstm = sc.inverse_transform(model(x_test).detach().numpy().reshape(-1,1))
  • predicted_y_lstm = sc.inverse_transform(...):这行代码使用 sc 对象(可能是 scikit-learn 库中的 MinMaxScaler 对象)对模型 model 在测试数据 x_test 上的预测结果进行反归一化处理。
    • model(x_test):这行代码通过模型 model 前向传播输入数据 x_test,得到预测结果。
    • .detach():这行代码将预测结果从计算图中分离出来,使其变为一个不依赖于任何计算图的 Tensor。
    • .numpy():这行代码将 Tensor 转换为 NumPy 数组。
    • .reshape(-1,1):这行代码将数组重塑为二维数组,其中 -1 表示自动计算行数,1 表示列数。
    • sc.inverse_transform(...):这行代码使用 sc 对象对数组进行反归一化处理,恢复其原始范围。
y_test_1 = sc.inverse_transform(y_test.reshape(-1,1))
  • y_test_1 = sc.inverse_transform(...):这行代码使用 sc 对象对测试数据集的真实标签 y_test 进行反归一化处理。
    • y_test.reshape(-1,1):这行代码将真实标签 y_test 重塑为二维数组,以便与预测结果进行比较。
    • sc.inverse_transform(...):这行代码使用 sc 对象对数组进行反归一化处理,恢复其原始范围。
y_test_one = [i[0] for i in y_test_1]
  • y_test_one = [i[0] for i in y_test_1]:这行代码将反归一化后的真实标签 y_test_1 转换为一个列表,其中每个元素是列表 y_test_1 中的一行。
predicted_y_lstm_one = [i[0] for i in predicted_y_lstm]
  • predicted_y_lstm_one = [i[0] for i in predicted_y_lstm]:这行代码将反归一化后的预测结果 predicted_y_lstm 转换为一个列表,其中每个元素是列表 predicted_y_lstm 中的一行。
plt.figure(figsize=(5,3),dpi=120)
  • plt.figure(...):这行代码创建一个新的 Matplotlib 图形,并设置其大小和分辨率。
    • figsize=(5,3):这行代码指定图形的大小为 5 英寸宽和 3 英寸高。
    • dpi=120:这行代码指定图形分辨率为 120 像素/英寸。
# 画出真实数据和预测数据的对比曲线
  • 这一行是注释,说明接下来将绘制真实数据和预测数据的对比曲线。
plt.plot(y_test_one[:2000], color='red', label='real_temp')
  • plt.plot(...):这行代码在当前图形中绘制真实标签 y_test_one 的前2000个值。
    • y_test_one[:2000]:这行代码指定要绘制的真实标签的范围,即前2000个值。
    • color='red':这行代码指定真实标签的线条颜色为红色。
    • label='real_temp':这行代码指定真实标签的图例标签为 ‘real_temp’。
predicted_y_lstm = sc.inverse_transform(model(x_test).detach().numpy().reshape(-1,1))
y_test_1 = sc.inverse_transform(y_test.reshape(-1,1))
y_test_one = [i[0] for i in y_test_1]
predicted_y_lstm_one = [i[0] for i in predicted_y_lstm]

plt.figure(figsize=(5,3),dpi=120)
# 画出真实数据和预测数据的对比曲线

plt.plot(y_test_one[:2000], color='red', label='real_temp')
plt.plot(predicted_y_lstm_one[:2000], color='blue', label='prediction')

plt.title('Title')
plt.xlabel('X')
plt.ylabel('Y')
plt.legend()
plt.show()

输出
在这里插入图片描述

(3)R2值评估

from sklearn import metrics
RMSE_lstm = metrics.mean_squared_error(predicted_y_lstm_one, y_test_1)*0.5
R2_lstm = metrics.r2_score(predicted_y_lstm_one, y_test_1)
print('均方根误差:%.5f'% RMSE_lstm)
print('R2:%.5f'% R2_lstm)

输出
均方根误差:24.17460
R2:0.82963

三、nn.LSTM( )函数详解

nn.LSTM() 是 PyTorch 库中用于创建 LSTM(长短期记忆)层的函数。LSTM 是一种特殊类型的循环神经网络(RNN),它特别擅长处理和预测时间序列数据。以下是 nn.LSTM() 函数的详细解释,包括每个参数的含义和用法:

nn.LSTM(input_size, hidden_size, num_layers, batch_first=False, dropout=0, bidirectional=False)
  1. input_size
    • 类型:int
    • 含义:输入数据的特征维度。
    • 用法:指定每个时间步输入数据的特征数量。对于二维输入([batch_size, time_steps, input_size]),input_size 就是 time_steps 维度上的大小。
  2. hidden_size
    • 类型:int
    • 含义:LSTM 层的隐藏单元数量。
    • 用法:指定每个时间步的 LSTM 层能够处理的数据量。这个值越大,模型可以处理的数据范围越广,但也会增加模型的复杂度。
  3. num_layers
    • 类型:int
    • 含义:LSTM 层的层数。
    • 用法:指定 LSTM 层的堆叠次数。例如,num_layers=2 表示有两个 LSTM 层堆叠在一起。
  4. batch_first
    • 类型:bool
    • 含义:输入数据的格式。
    • 用法:指定输入数据的格式。如果为 True,则输入数据的形状应该是 [batch_size, time_steps, input_size];如果为 False(默认值),则输入数据的形状应该是 [time_steps, batch_size, input_size]
  5. dropout
    • 类型:float
    • 含义:LSTM 层的 dropout 比率。
    • 用法:指定在 LSTM 层之间应用 dropout 的比率。这有助于防止过拟合。
  6. bidirectional
    • 类型:bool
    • 含义:LSTM 层的方向性。
    • 用法:指定是否使用双向 LSTM。如果为 True,则 LSTM 层会同时处理输入序列的前向和后向信息。这会增加模型的容量,但也会增加计算量。
      当创建一个 LSTM 层时,你可以根据你的具体需求调整这些参数。例如,如果你的输入数据是二维的,并且每个时间步有 32 个特征,你可以创建一个有 2 个隐藏单元、2 个 LSTM 层堆叠、不使用 dropout 和双向的 LSTM 层,如下所示:
lstm = nn.LSTM(input_size=32, hidden_size=2, num_layers=2, batch_first=False)

如果你的输入数据是三维的,并且每个时间步有 32 个特征,你可以创建一个有 2 个隐藏单元、2 个 LSTM 层堆叠、不使用 dropout 和双向的 LSTM 层,如下所示:

lstm = nn.LSTM(input_size=32, hidden_size=2, num_layers=2, batch_first=True)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

大模型构建合作性的Agent,多代理框架MetaGpt

大模型构建合作性的Agent,多代理框架MetaGpt 前言 MetaGPT 框架将标准的操作程序(SOP)与基于大模型的多智能体相结合,使用标准操作程序来编码提示,确保协调结构化和模块化输出。 MetaGPT 允许 Agent 在类似流水线的范式中扮演多中角色,通过结构化的 Agent 协作和强化领…

香橙派列出附近所有的WiFi

使用 nmcli nmcli 是 NetworkManager 的命令行工具&#xff0c;它可以用来检索和管理网络连接。 nmcli device wifi list这个命令会列出所有周围的WiFi网络。

Vitis AI 进阶认知(pybind11)

目录 1. 简介 2. 代码分析 2.1 pybind11 介绍 2.2 writefile 魔法命令 2.3 快速编译和加载 2.3.1 语法主体 2.3.2 查看模块位置 2.3.3 中间文件 2.4 编译器链接器标志 3. pybind11 语法 3.1 基础示例 3.1.1 example.cpp 3.1.2 编译 3.1.3 关键字参数 3.1.4 帮助…

java 设计模式-代理模式

目录 概述 一. 什么是代理模式 1. 举例说明 二. 代理模式作用 1. 保护代理 2. 增强功能 3. 代理交互 4. 远程代理&#xff1a; 三. 代理模式3个角色 四. 静态代理 1. 代码示例&#xff1a; 五. JDK动态代理 1. 代码示例&#xff1a; 六. CGLIB 动态代理 1.代码示…

P1.8COB小间距成本下降,增大COB超微小间距LED显示屏市场份额

随着P1.8 COB&#xff08;Chip On Board&#xff09;小间距技术的不断成熟与成本的有效控制&#xff0c;其在LED显示屏市场中的竞争力日益凸显。这一趋势不仅激发了行业内对超微小间距LED显示屏的浓厚兴趣&#xff0c;更推动了市场的快速扩张。 随着成本的进一步下降&#xff…

支持图片和视频分割,SAM2最新分割一切大模型分享

Segment Anything Model 2&#xff08;简称SAM 2&#xff09;是由Meta&#xff08;Facebook AI&#xff09;开发的最新一代图像和视频分割模型。 SAM2能够实现对静态图像和动态视频中的对象进行实时、可提示的分割&#xff0c;将图像与视频分割功能整合到了同一个系统中。 SA…

在Centos中的mysql的备份与恢复

1.物理备份 冷备份&#xff1a;关闭数据库时进行热备份&#xff1a;数据库运行时进行&#xff0c;依赖于数据库日志文件温备份&#xff1a;数据库不可写入但可读的状态下进行 2.逻辑备份 对数据库的表或者对象进行备份 3.备份策略 完全备份&#xff1a;每次都备份完整的数…

【运维监控】influxdb 2.0+telegraf 监控tomcat 8.5运行情况(1)

关于java应用的监控本系列有文章如下&#xff1a; 【运维监控】influxdb 2.0telegraf 监控tomcat 8.5运行情况 【运维监控】influxdb 2.0grafana 监控java 虚拟机以及方法耗时情况 【运维监控】Prometheusgrafana监控tomcat运行情况 【运维监控】Prometheusgrafana监控spring b…

数学建模强化宝典(13)M-K检验法

前言 M-K检验法&#xff0c;全称为Mann-Kendall检验法&#xff0c;是一种非参数的假设检验方法&#xff0c;广泛应用于时间序列数据的趋势性变化检验&#xff0c;特别是气候序列中的趋势分析和突变点检测。以下是对M-K检验法的详细介绍&#xff1a; 一、定义与背景 M-K检验法由…

Leetcode面试经典150题-83.删除链表中的重复元素

解法都在代码里&#xff0c;不懂就留言或者私信 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val val; }* ListNode(int val, ListNode next) { this.val …

服务器监控工具都是监控服务器的哪些性能和指标

服务器监控工具通常用于确保服务器及其相关服务的正常运行。这些工具可以帮助管理员快速识别并解决问题&#xff0c;从而减少停机时间和性能下降的风险。以下是服务器监控工具通常会监控的一些主要内容&#xff1a; 系统健康状态&#xff1a; CPU使用率 内存&#xff08;RAM&…

油猴插件录制请求,封装接口自动化参数

参考&#xff1a;如何使用油猴插件提高测试工作效率 一、背景 在酷家乐设计工具测试中&#xff0c;总会有许多高频且较繁琐的工作&#xff0c;比如&#xff1a; 查询插件版本&#xff1a;需要打开Chrome控制台&#xff0c;输入好几个命令然后过滤出版本信息。 查询模型商品&…

JAVA—单元测试

单元测试&#xff1a;就是针对最小的功能单元&#xff08;方法&#xff09;&#xff0c;编写测试代码对其进行正确性测试 之前是使用main函数调用来进行检测&#xff0c;无法实现自动化测试 也会影响其他方法的测试 目录 1.junit框架概述 2.junit框架的常见注解 1.junit框架…

基于C++实现(MFC界面)家谱管理系统

一、题目&#xff1a;家谱管理系统 二、内容&#xff1a; 2.1 概述 2.1.1 选题原因 做此题的原因是因为可以比较方便的记录家族历代成员的情况与关系&#xff0c;能很好的保存家族每一代的信息&#xff0c;而不用人工纸质的方式来存取家谱&#xff0c;更便于人们保存和使用…

基于STELLA系统动态模拟技术及在农业、生态环境等科学领域中的实践应用

STELLA是一种用户友好的计算机软件。通过绘画出一个系统的形象图形&#xff0c;并给这个系统提供数学公式和输入数据&#xff0c;从而建立模型。依据专业兴趣&#xff0c;STELLA可以用来建立各种各样的农业、生态、环境等方面的系统动态模型&#xff0c;为科研、教学、管理服务…

Day16_0.1基础学习MATLAB学习小技巧总结(16)——元胞数组

利用空闲时间把碎片化的MATLAB知识重新系统的学习一遍&#xff0c;为了在这个过程中加深印象&#xff0c;也为了能够有所足迹&#xff0c;我会把自己的学习总结发在专栏中&#xff0c;以便学习交流。 素材来源“数学建模清风” 特此说明&#xff1a;本博客的内容只在于总结在…

linux top命令介绍以及使用

文章目录 介绍 top 命令1. top 的基本功能2. 如何启动 top3. top 的输出解释系统概况任务和 CPU 使用情况内存和交换空间进程信息 4. 常用操作 总结查看逻辑CPU的个数查看系统运行时间 介绍 top 命令 top 是一个在类 Unix 系统中广泛使用的命令行工具&#xff0c;用于实时显示…

pikachu文件包含漏洞靶场攻略

1.File inclusion(local)&#xff08;本地文件包含&#xff09; 提交一个球员信息 filename后面输入../../../../../1.php访问php文件 2.File Inclusion(remote)&#xff08;远程文件包含&#xff09; 修改配置 远程包含漏洞的前提&#xff1a;需要php.ini配置如下&#…

深入理解 Babel - 微内核架构与 ECMAScript 标准化|得物技术

随着浏览器版本的持续更新&#xff0c;浏览器对JavaScript的支持越来越强大&#xff0c;Babel的重要性显得较低了。但Babel的设计思路、背后依赖的ECMAScript标准化思想仍然值得借鉴。 本文涉及的Babel版本主要是V7.16及以下&#xff0c;截至发文时&#xff0c;Babel最新发布的…

利用SSH加密实现的HTTP隧道分析与检测

1.隧道介绍 Chisel是一个快速稳定的TCP/UDP隧道工具&#xff0c;该工具基于HTTP实现&#xff0c;并通过SSH加密保证通信安全。Chisel可以进行端口转发、反向端口转发以及SOCKS流量代理&#xff0c;使用GO语言编写&#xff0c;具备较好的跨平台特性。该工具的主要用于绕过防火墙…