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

news2025/1/11 16:59:51
  • 🍨 本文为🔗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.coloradmin.cn/o/2061121.html

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

相关文章

《Cloud Native Data Center Networking》(云原生数据中心网络设计)读书笔记 -- 05网络虚拟化

本章帮助网络工程师或架构师回答如下问题&#xff1a; 什么是网络虚拟化?网络虚拟化有哪些用途?网络虚拟化领域内有哪些不同的技术方向?网络虚拟化的控制面有哪些选择?当使用 VXLAN 时如何进行桥接和路由&#xff1f; 什么是网络虚拟化&#xff1f; 网络虚拟化可以让网络…

揭秘!格行如何成为随身WiFi界的‘比亚迪’!如何成为随身WiFi热销第一名?

比亚迪把续航超过2000km的油车打入了10万元以内&#xff01;创造历史&#xff01; 为什么这么说&#xff1f;还不是因为这两辆车都搭载了比亚迪最新研发的第五代 Dmi 混动技术。这项技术有多“逆天”&#xff1f;直接创下了三项全球之最——全球最高发动机热效率、百公里最低油…

CUDA C++ 最佳实践指南

CUDA C 最佳实践指南 (nvidia.com)https://docs.nvidia.com/cuda/cuda-c-best-practices-guide/index.html#getting-started2. 异构计算 CUDA 编程涉及在两个不同的平台上同时运行代码&#xff1a;具有一个或多个 CPU 的主机系统和一个或多个支持 CUDA 的 NVIDIA GPU 设备。 …

Hermite 三次插值可编辑样条

欢迎关注更多精彩 关注我&#xff0c;学习常用算法与数据结构&#xff0c;一题多解&#xff0c;降维打击。 问题描述 利用三次样条和Hermite插值制作一个类似于ppt里的曲线工作。 基本思路 对于给定点&#xff0c;初始生成时用参数化三次函数插值的方式生成。三次样条函数插…

【Py/Java/C++三种语言详解】LeetCode743、网络延迟时间【单源最短路问题Djikstra算法】

可上 欧弟OJ系统 练习华子OD、大厂真题 绿色聊天软件戳 od1441了解算法冲刺训练&#xff08;备注【CSDN】否则不通过&#xff09; 文章目录 相关推荐阅读一、题目描述二、题目解析三、参考代码PythonJavaC 时空复杂度 华为OD算法/大厂面试高频题算法练习冲刺训练 相关推荐阅读 …

Java入门:06.Java中的方法--进阶01

1 JVM中方法的执行过程 1.1 JVM内存模型 在java程序的执行过程中会产生一些数据&#xff0c;这些数据将会存在jvm内存中。 JVM将内存分成了不同的逻辑区域&#xff0c;存储不同含义&#xff08;类别&#xff09;的数据 JVM内存模型有5种 方法区 &#xff1a; 存储类信息 堆…

初识redis:Set类型

Set有很多种含义&#xff0c;比如集合&#xff0c;比如设置&#xff08;和get相对应&#xff09;。 在这里我们说的set是指的redis中的集合&#xff0c;并且这里的集合是无序的&#xff0c;和之前的list是对应的。 List &#xff1a; [1,2,3] 和 [2,1,3] 是两个不同的listSe…

hbase-manager图形化界面的安装与配置

相关资料下载 夸克网盘分享 1、上传项目到linux上 解压&#xff1a; 切换到conf目录下&#xff1a;/opt/installs/hbase-manager-2.0.8-hbase-2.x/conf/ 2、修改数据库配置信息 application-druid.yml 3、创建hbase-manager数据库(注意字符集编码)&#xff0c;导入数据库脚本…

飞鸟物联平台数字化解决方案:全方位提升OEM厂商销售、售后服务能力

自从OEM厂商把设备销售给终端客户&#xff0c;这笔交易就到此为止了。一旦目标行业出现下行趋势&#xff0c;订单和利润往往难以为继&#xff0c;OEM厂商往往遭受着其特有的三重考验&#xff1a;设备状况不透明、设备维保成本高、终端客户粘性低。这些挑战如同“三害”压得OEM厂…

AI搜索产品:秘塔、天工、perplexity、felo、360AI搜索

1、秘塔 https://metaso.cn/ 2、天工 https://www.tiangong.cn/ 3、perplexity https://www.perplexity.ai/ 4、Felo https://felo.ai/search 5、360ai搜索 https://www.sou.com/

洛谷P3865.ST表

洛谷P3865.ST表 i的取值为[1,n−2j1]从而推出j的取值为 j < lg[n]找区间最值时&#xff1a; 要找一段起始点L的可覆盖[L,R]的区间&#xff0c;即L 2k - 1 < R –> k < lg[R-L1] (区间长度)同时起点为 D R - 2k 1 (起始点)即f[D][k] #include <bits/stdc.…

12.1.案例专题-数据流图

文章目录 数据流图结构化语言描述示例 练习题2020年真题2021年上真题 数据流图 数据流图DFD基本图形元素&#xff1a;外部实体、加工、数据存储、数据流。 数据流&#xff1a;由一组固定成分的数据组成&#xff0c;表示数据的流向。在DFD中&#xff0c;数据流的流向必须经过…

IP进程间的通信方式以及不同主机间的通信方式

一&#xff0c;IP进程间的通信方式 共享内存&#xff08;最高效&#xff09; 1.是一块内核的预留空间 2.避免了用户空间到内核空间的数据拷贝 1.产生key:ftok函数 功能&#xff1a;将pathname和pid_id转化为key 参数&#xff1a;(路径名&#xff0c;A) 返回值&#xff1…

Java并发类API——ExecutorService

1.ExecutorService概述 ExecutorService 是 Java 并发库中一个非常重要的接口&#xff0c;它提供了一种管理和控制线程执行的方法。ExecutorService 是 Executor 接口的扩展&#xff0c;除了 Executor 提供的基础任务执行功能之外&#xff0c;ExecutorService 提供了更强大的功…

如何用Python构建高校爬虫与k-means算法实现专业评分可视化分析

&#x1f34a;作者&#xff1a;计算机毕设匠心工作室 &#x1f34a;简介&#xff1a;毕业后就一直专业从事计算机软件程序开发&#xff0c;至今也有8年工作经验。擅长Java、Python、微信小程序、安卓、大数据、PHP、.NET|C#、Golang等。 擅长&#xff1a;按照需求定制化开发项目…

工业互联网与大数据实训室解决方案

一、引言 1.1 工业互联网与大数据的重要性 工业互联网作为新一代信息技术与制造业深度融合的产物&#xff0c;正在全球范围内推动着制造业的数字化、网络化、智能化转型。它通过连接机器、物料、人和信息系统&#xff0c;实现数据的全面感知、动态传输和智能分析&#xff0c;…

白酒与素食:健康与美味的双重享受

在美食的世界里&#xff0c;白酒与素食的搭配仿佛是一场跨界的盛宴。豪迈白酒&#xff08;HOMANLISM&#xff09;的醇香与精致素食的清新&#xff0c;在不经意间交织出了一幅美妙的画卷&#xff0c;让人在品味中感受到健康与美味的双重享受。 素食&#xff0c;以其清淡、自然的…

Verilog刷题笔记54

题目&#xff1a; Fsm serialdp See also: Serial receiver and datapath We want to add parity checking to the serial receiver. Parity checking adds one extra bit after each data byte. We will use odd parity, where the number of 1s in the 9 bits received must…

如何在 FastReport .NET 中构建和安装 Postgres 插件

FastReport .NET 是一款全功能的Windows Forms、ASP.NET和MVC报表分析解决方案。 功能非常丰富&#xff0c;功能广泛。今天我们将介绍如何使用报表设计器的 FastReport 插件连接数据库。 FastReport .NET 是适用于.NET Core 3&#xff0c;ASP.NET&#xff0c;MVC和Windows窗体…

LlamaIndex 介绍

LlamaIndex 是什么&#xff1f; 从字面上理解&#xff0c;是 Llama Index&#xff0c;Llama 是大语言模型&#xff0c;Index 是索引&#xff0c;Index for Llama 就是为大语言模型做索引&#xff0c;那么大语言模型为什么需要索引&#xff0c;索引的作用是什么&#xff1f; …