循环神经网络(RNN)+pytorch实现情感分析

news2025/2/2 2:04:03

目录

一、背景引入

二、网络介绍

2.1 输入层

2.2 循环层

2.3 输出层

2.4 举例

2.5 深层网络

三、网络的训练

3.1 训练过程举例

1)输出层

2)循环层

3.2 BPTT 算法

1)输出层

2)循环层

3)算法流程

四、循环神经网络实现情感分析 

4.1 实验介绍

4.2 数据集介绍

4.3 Embedding操作

4.4 pytorch实现 

1)数据处理

2)模型设计

3)训练配置

4)训练过程

5)测试模型


一、背景引入

全连接神经网络和卷积神经网络在运行时每次处理的都是独立的输入数据,没有记忆功能。

有些应用需要神经网络具有记忆能力, 典型的是输入数据为时间序列的问题, 时间序列可以抽象地表示为一个向量序列:x_1,x_2,...,x_t
其中, x_i是向量, 下标 i 为时刻。 各个时刻的向量之间存在相关。 例如, 在说话时当前要说的词和之前已经说出去的词之间存在关系, 依赖于上下文语境。算法需要根据输入序列来产生输出值, 这类问题称为序列预测问题, 需要注意的是输入序列的长度可能不固定。

语音识别和自然语言处理是序列预测问题的典型代表。 语音识别的输入是一个语音信号序列, 自然语言处理的输入是文字序列。 下面用一个实际例子来说明序列预测问题, 假设神经网络要用来完成汉语填空, 考虑下面这个句子:

                     现在已经下午 2 点了, 我们还没有吃饭, 非常饿, 赶快去餐馆_____ 。

根据上下文的理解, 这个空的最佳答案是“吃饭”, 如果没有上下文, 去参观可以喝咖啡或者歇一会, 但结合前面的饿了, 最佳答案显然是“吃饭”。 为了完成这个预测, 神经网络需要依次输入前面的每一个词, 最后输入“餐馆” 这个词时, 得到预测结果。

神经网络的每次输入为一个词, 最后要预测出这个空的内容, 这需要神经网络能够理解语义, 并记住之前输入的信息, 即语句上下文。 神经网络要根据之前的输入词序列计算出当前使用哪个词的概率最大。

二、网络介绍

循环神经网络(Recurrent Neural Network, 简称 RNN) 是一种能够处理序列数据的神经网络模型。 RNN 具有记忆功能, 它会记住网络在上一时刻运行时产生的状态值, 并将该值用于当前时刻输出值的生成。
 

RNN 由输入层、 循环层和输出层构成, 也有可能还包含全连接层。 输入层和输出层与前馈型神经网络类似, 唯一不同的是循环层。

2.1 输入层

输入值通常是一个时间序列。每个输入样本由一系列按时间顺序排列的数据点组成,每个数据点可以是向量、标量或其他形式的数据。例如,在自然语言处理中,一个句子可以被视为一个时间序列,其中每个单词或字符代表一个时间步的输入。

2.2 循环层

循环神经网络的输入为向量序列, 每个时刻接收一个输入x_i , 网络会产生一个输出h_i , 而这个输出是由之前时刻的输入序列x_1,x_2,...,x_i共同决定的。

假设 t 时刻的状态值为 h_t, 它由上一时刻的状态值h_{t-1} 以及当前时刻的输入值 x_t共同决定, 即:                               h_t = f(h_{t-1},x_t) = f(W_{xh}x_t+W_{hh}h_{t-1}+b_h)

  • W_{xh}是输入层到隐藏层的权重矩阵
  •  W_{hh}是隐藏层内的权重矩阵,可以看作状态转移权重。其并不会随着时间变化, 在每个时刻进行计算时使用的是同一个矩阵。 这样做的好处是一方面减少了模型参数, 另一方面也记住了之前的信息。
  •  b_h为偏置向量

一个神经元更形象的表示如下: 

循环神经网络中循环层可以只有一层, 也可以有多个循环层。 

2.3 输出层

输出层以循环层的输出值作为输入并产生循环神经网络最终的输出, 它不具有记忆功能。 输出层实现的变换为:y_t = g(W_oh_t+b_o)

  • W_o为权重矩阵
  •  b_o为偏置向量
  •  g 为激活函数。对于分类任务, g一般选用 softmax 函数, 输出各个类的概率。

2.4 举例

一个简单的循环神经网络, 这个网络有一个输入层、 一个循环层和一个输出层。其中输入层有 2 个神经元, 循环层有 3 个神经元, 输出层有 2 个神经元。

  • 循环层的输出h_t = f(W_{xh}x_t+W_{hh}h_{t-1}+b_h),其中输入向量是二维的, 输出向量是三维的
  • 输出层的输出y_t = g(W_oh_t+b_o) ,其中输入向量是三维的, 输出向量是二维的

递推:

按照时间轴进行展开, 当输入为 x_1时, 网络的输出为:

  • h_1 = f(W_{xh}x_1+b_h)
  • y_1 = g(W_oh_1+b_o)

当输入为 x_2时, 网络的输出为:

  • h_2 = f(W_{xh}x_2+W_{hh}h_{1}+b_h) = f(W_{xh}x_2+W_{hh}f(W_{xh}x_1+b_h) +b_h)
  • y_2 = g(W_oh_2+b_o)

输出值与x_1,x_2都有关。 依此类推, 可以得到x_3,x_4,...,x_t时网络的输出值,x_t时的输出值与 x_1,x_2,...,x_t都有关。

可以看出循环神经网络通过递推方式实现了记忆功能。

2.5 深层网络

可以构建含有多个隐藏层的网络,有3种方案

  1. Deep Input-to-Hidden Function:它在循环层之前加入多个全连接层, 将输入向量进行多层映射之后再送入循环层进行处理。
  2. Deep Hidden-to-Hidden Transition:它使用多个循环层, 这与前馈型神经网络类似, 唯一不同的是计算隐含层输出的时候需要利用本隐含层上一时刻的值。
  3. Deep Hidden-to-Output Function:它在循环层到输出层之间加入多个全连接层。

三、网络的训练

循环神经网络(RNN)处理序列数据,每个训练样本是一个时间序列,包含多个相同维度的向量。训练使用BPTT算法(Back Propagation Through Time 算法),先对序列中每个时刻的输入进行正向传播,再通过反向传播计算梯度并更新参数。每个训练样本的序列长度可以不同,前后时刻的输入值有关联。

3.1 训练过程举例

网络结构如下:

有一个训练样本, 其序列值为:(x_1,y_1)(x_2,y_2)(x_3,y_3)。其中, x_i为输入向量,y_i 为标签向量。 循环层状态的初始值设置为 0。

在 t=1 时刻, 网络的输出为:

  • u_1 = W_{xh} x_1 + b_h
  • h_1 = f(u_1)
  • v_1 = W_o h_1 + b_o
  • y_1^*= g(v_1)

在 t=2 时刻, 网络的输出为:

  • u_2 = W_{xh} x_2 + W_{hh} f(W_{xh} x_1 + b_h) + b_h
  • h_2 = f(u_2)
  • v_2 = W_o h_2 + b_o
  • y_2^* = g(v_2)

在 t=3 时刻, 网络的输出为:

  • u_3 = W_{xh} x_3 + W_{hh} f(W_{xh} x_2 + W_{hh} f(W_{xh} x_1 + b_h) + b_h)+ b_h
  • h_3 = f(u_3)
  • v_3 = W_o h_3 + b_o
  • y_3^* = g(v_3)

对单个样本的序列数据, 定义 t 时刻的损失函数为:L_t = L(y_t, y_t^*)

样本的总损失函数为各个时刻损失函数之和:L = \sum_{t=1}^{3} L(y_t, y_t^*)

1)输出层

如果输出层使用 softmax 变换, 则损失函数为 softmax 交叉熵:L_t = -y_t^T \ln y_t^*

梯度的计算公式为:\nabla_{v_t} L_t = y_t^* - y_t

根据之前全连接神经网络中的推论:\nabla_{W} L = \left(\nabla_{u^{(l)}} L\right) {z^{(l-1)}}^T\nabla_{​{z^{(l-1)}}} L = W^T\left(\nabla_{u^{(l)}} L\right)

可以得到 t 时刻

  • 损失函数对输出层权重的梯度:\nabla_{W_o} L_t = (\nabla_{v_t} L_t) h_t^T = (y_t^* - y_t) h_t^T
  • 损失函数对偏置项的梯度为:\nabla_{b_o} L_t = \nabla_{v_t} L_t = y_t^* - y_t

故得到总时刻

  • 总损失函数对权重的梯度为:\nabla_{W_o} L = \sum_{t=1}^{3} ((y_t^* - y_t) h_t^T)
  • 总损失函数对偏置项的梯度为:\nabla_{b_o} L = \sum_{t=1}^{3} (y_t^* - y_t)

2)循环层

按时间序列展开之后, 各个时刻在循环层的输出值是权重矩阵和偏置项的复合函数。

在 t=1 时刻u_1 = W_{xh} x_1 + b_h

根据全连接神经网络中的推论

\nabla_{W} L = \left(\nabla_{u^{(l)}} L\right) {z^{(l-1)}}^T

\delta^{(l)} = \nabla_{u^{(l)}} L = (W^{(l+1)})^T (\delta^{(l+1)}) \odot f'(u^{(l)})

\nabla_{​{z^{(l-1)}}} L = W^T\left(\nabla_{u^{(l)}} L\right)

可以得到损失函数对 W_{xh}的梯度:

由于 t=1 时循环层的输出值与 无关, 因此:\nabla_{W_{hh}} L_1 = 0

对偏置项的偏导为:\nabla_{b_h} L_1 = \nabla_{u_1} L_1 = (W_o^T (y_1^* - y_1)) \odot f'(u_1)

在 t=2 时刻u_2 = W_{xh} x_2 + W_{hh} f(W_{xh} x_1 + b_h) + b_h。当前式子中 W_{xh}出现了两次, 因此损失函数对 W_{xh}的梯度为:\nabla_{W_{xh}} L_2 = (\nabla_{u_2} L_2) x_2^T + (\nabla_{u_1} L_2) x_1^T

又由于:u_2 = W_{xh} x_2 + W_{hh} f(u_1) + b_h, h_1 = f(u_1),故有\nabla_{u_1} L_2 = \nabla_{h_1} L_2 \odot f'(u_1) = W_{hh}^T (\nabla_{u_2} L_2) \odot f'(u_1)

可以得到损失函数对 W_{xh}的梯度为:

损失函数对 W_{hh} 的梯度为:

在 t=3 时刻, u_3 = W_{xh} x_3 + W_{hh} f(W_{xh} x_2 + W_{hh} f(W_{xh} x_1 + b_h) + b_h) + b_h。当前式子中 W_{xh}出现了三次, 因此损失函数对 W_{xh}的梯度为:\nabla_{W_{xh}} L_3 = (\nabla_{u_3} L_3) x_3^T + (\nabla_{u_2} L_3) x_2^T + (\nabla_{u_1} L_3) x_1^T

类似地, 可以计算出:

\nabla_{u_2} L_3 = \nabla_{h_2} L_3 \odot f'(u_2) = W_{hh}^T (\nabla_{u_3} L_3) \odot f'(u_2)

由此可以计算出 \nabla_{W_{xh}} L_3 和 \nabla_{W_{hh}} L_3。 在计算出每个时刻的损失函数对各个参数的梯度之后, 把它们加起来得到总损失函数对各个参数的梯度:

  • \nabla_{W_{xh}} L = \sum_{t=1}^{3} \nabla_{W_{xh}} L_t
  • \nabla_{W_{hh}} L = \sum_{t=1}^{3} \nabla_{W_{hh}} L_t
  • \nabla_{b_h} L = \sum_{t=1}^{3} \nabla_{b_h} L_t

接下来用梯度下降法更新参数。

3.2 BPTT 算法

将上面的例子推广到一般情况, 得到通用的 BPTT 算法。

循环神经网络的反向传播是基于时间轴进行的, 我们需要计算所有时刻的总损失函数对所有参数的梯度, 然后用梯度下降法进行更新。 另外循环神经网络在各个时刻的权重、 偏置都是相同的。

设 t 时刻的损失函数为:L_t = L(y_t, y_t^*)

总损失函数为:L = \sum_{t=1}^{T} L_t

1)输出层

首先计算输出层偏置项的梯度\nabla_{b_o} L = \sum_{t=1}^{T} (\nabla_{b_o} L_t) = \sum_{t=1}^{T} (\nabla_{v_t} L_t) = \sum_{t=1}^{T} ((\nabla_{y_t^*} L_t) \odot g'(v_t))

如果选择 softmax 作为输出层的激活函数, 交叉熵作为损失函数, 则上面的梯度为:\nabla_{b_o} L = \sum_{t=1}^{T} (\nabla_{b_o} L_t) = \sum_{t=1}^{T} (\nabla_{v_t} L_t) = \sum_{t=1}^{T} (y_t^* - y_t)

输出层权重矩阵的梯度为:\nabla_{W_o} L = \sum_{t=1}^{T} \nabla_{W_o} L_t = \sum_{t=1}^{T} ((\nabla_{v_t} L_t) h_t^T) = \sum_{t=1}^{T} ((y_t^* - y_t) h_t^T)

2)循环层

u_t = W_{xh} x_t + W_{hh} h_{t-1} + b_h = W_{xh} x_t + W_{hh} f(u_{t-1}) + b_h

因此有:\nabla_{u_{t-1}} L_t = (\nabla_{h_{t-1}} L_t) \odot f'(u_{t-1}) = (W_{hh}^T (\nabla_{u_t} L_t)) \odot f'(u_{t-1})

由此建立了 \nabla_{u_{t-1}} L_t\nabla_{u_t} L_t 之间的递推关系。 定义误差项为:\delta_t = \nabla_{u_t} L

在总损失函数 L 中, 比 t 更早的时刻的损失函数不含有u_t , 因此与 \delta_t 无关。由于 L_tu_t决定, 因此 \delta_t 与 u_t 直接相关。 比 t 晚的时刻的 u_{t+1}u_{t+2} …,u_{T} 都与 u_t 有关, 因此有:\delta_t = \nabla_{u_t} L_t + (W_{hh}^T \delta_{t+1}) \odot f'(u_t)

存在

从而得到:\delta_t = (W_o^T ((\nabla_{y_t^*} L_t) \odot g'(v_t))) \odot f'(u_t) + (W_{hh}^T \delta_{t+1}) \odot f'(u_t)

由此建立了误差项沿时间轴的递推公式, 递推的起点是最后一个时刻的误差:\delta_T = (W_o^T ((\nabla_{y_T^*} L) \odot g'(v_T))) \odot f'(u_T)

根据误差项可以计算出损失函数对权重和偏置的梯度:

  • \nabla_{W_{xh}} L = \sum_{t=1}^{T} \nabla_{W_{xh}} L_t = \sum_{t=1}^{T} (\nabla_{u_t} L) x_t^T = \sum_{t=1}^{T} \delta_t x_t^T
  • \nabla_{W_{hh}} L = \sum_{t=1}^{T} \nabla_{W_{hh}} L_t = \sum_{t=1}^{T} (\nabla_{u_t} L) h_{t-1}^T = \sum_{t=1}^{T} \delta_t h_{t-1}^T
  • \nabla_{b_h} L = \sum_{t=1}^{T} \nabla_{b_h} L_t = \sum_{t=1}^{T} (\nabla_{u_t} L) = \sum_{t=1}^{T} \delta _t

3)算法流程

四、循环神经网络实现情感分析 

4.1 实验介绍

通过 RNN 模型对电影评论进行情感分类,判断评论是正面还是负面。 

4.2 数据集介绍

IMDB 数据集包含 50,000 条电影评论, 其中一半用于训练(25,000 条), 另一半用于测试(25,000 条)。 每条评论都附带一个标签, 要么是'pos'表示正面评价, 要么是'neg'表示负面评价。 这些评论通常以文本文件的形式存在, 每个文件中包含一条评论。

4.3 Embedding操作

Embedding 过程:计算机无法直接处理一个单词或者一个汉字, 需要把一个 token 转化成计算机可以识别的向量 。

Embedding 是一种将高维数据(如文本或图像) 转换为较低维度的向量表示的技术。 这种表示捕捉了数据的关键特征, 使得在处理、 分析和机器学习任务中更加高效。 通常用于将离散的、 非连续的数据转换为连续的向量表示, 以便于计算机进行处理。

Embedding 技术通常会捕获数据的语义信息。 在 NLP 中, 这意味着相似的单词或短语在嵌入空间中会更接近, 而不同的单词或短语会远离彼此。 这有助于模型理解语言的含义和语义关系。

Embedding 技术通常是上下文感知的, 它们可以捕获数据点与其周围数据点的关系。 在 NLP 中, 单词的嵌入会考虑其周围的单词, 以更好地表示语法和语义。

简单的说, Embedding 就是把一个东西映射到一个向量 X。 如果这个东西很像, 那么得到的向量 x1 和 x2 的欧式距离就很小。

4.4 pytorch实现 

1)数据处理

首先对数据集进行处理, 提取单词表, 单词表的最大尺寸是 10000。

# 加载数据
def load_data(data_dir):
    texts = []  # 存储文本数据
    labels = []  # 存储标签数据
    for label_type in ['neg', 'pos']:  # 遍历负面和正面评论目录
        dir_name = os.path.join(data_dir, label_type)  # 构建目录路径  /IMDB/train/neg/0_2.txt
        for fname in os.listdir(dir_name):  # 遍历目录中的文件
            if fname.endswith('.txt'):  # 只处理文本文件
                with open(os.path.join(dir_name, fname), encoding="utf-8") as f:
                    texts.append(f.read())  # 读取文本内容
                labels.append(0 if label_type == 'neg' else 1)  # 根据目录确定标签(负面:0,正面:1)
    return texts, labels  # 返回文本和标签


# 加载训练和测试数据
train_texts, train_labels = load_data('./IMDB/train')
test_texts, test_labels = load_data('./IMDB/test')

# 构建词汇表
max_features = 10000  # 词汇表大小,最多包含10000个单词
maxlen = 150  # 每个文本的最大长度为150

tokenizer = Counter(" ".join(train_texts).split())  # 统计词频
# print(tokenizer.most_common(100))
# [('the', 287032), ('a', 155096), ('and', 152664), ('of', 142972),
# ('to', 132568), ('is', 103229), ('in', 85580), ('I', 65973), ('that', 64560), ('this', 57199), ('it', 54439), ('/><br', 50935), ('was', 46698), ('as', 42510), ('with', 41721), ('for', 41070), ('but', 33790), ('The', 33762), ('on', 30767), ('movie', 30506), ('are', 28499), ('his', 27687), ('film', 27402), ('have', 27126), ('not', 26266), ('be', 25512), ('you', 25123), ('he', 21676), ('by', 21426), ('at', 21295), ('one', 20692), ('an', 20626), ('from', 19239), ('who', 18838), ('like', 18133), ('all', 18048), ('they', 17840), ('has', 16472), ('so', 16336), ('just', 16326), ('about', 16286), ('or', 16224), ('her', 15830), ('out', 14368), ('some', 14207), ('very', 13082), ('more', 12950), ('This', 12279), ('would', 11923), ('what', 11685), ('when', 11488), ('good', 11436), ('only', 11106), ('their', 11008), ('It', 10952), ('if', 10899), ('had', 10876), ('really', 10815), ("it's", 10727), ('up', 10658), ('which', 10658), ('even', 10607), ('can', 10560), ('were', 10460), ('my', 10166), ('see', 10155), ('no', 10062), ('she', 9933), ('than', 9772), ('-', 9355), ('been', 9050), ('there', 9036), ('into', 8950), ('get', 8777), ('will', 8558), ('story', 8527), ('much', 8507), ('because', 8357), ('other', 7917), ('most', 7859), ('we', 7808), ('time', 7765), ('me', 7540), ('make', 7485), ('could', 7462), ('also', 7422), ('do', 7408), ('how', 7403), ('first', 7339), ('people', 7335), ('its', 7323), ('/>The', 7243), ('any', 7232), ('great', 7191), ("don't", 7007), ('made', 6962), ('think', 6659), ('bad', 6506), ('him', 6347), ('being', 6202)]
vocab = [word for word, num in tokenizer.most_common(max_features)]  # 取出前10000个常用词
# print(vocab)
word_index = {word: idx + 1 for idx, word in enumerate(vocab)}  # 为每个词分配一个索引
# print(word_index)


# 将文本转换为序列
def texts_to_sequences(texts):
    return [[word_index.get(word, 0) for word in text.split()] for text in texts]


# 转换训练和测试文本为序列
x_train = texts_to_sequences(train_texts)#{}
x_test = texts_to_sequences(test_texts)

# 将序列填充到固定长度
x_train_padded = pad_sequence([torch.tensor(seq[:maxlen]) for seq in x_train], batch_first=True, padding_value=0)
x_test_padded = pad_sequence([torch.tensor(seq[:maxlen]) for seq in x_test], batch_first=True, padding_value=0)

y_train = torch.tensor(train_labels)  # 转换训练标签为张量
y_test = torch.tensor(test_labels)  # 转换测试标签为张量


# 创建 Dataset 和 DataLoader
class TextDataset(Dataset):
    def __init__(self, texts, labels):
        self.texts = texts  # 文本数据
        self.labels = labels  # 标签数据

    def __len__(self):
        return len(self.labels)  # 返回数据集大小

    def __getitem__(self, idx):
        return self.texts[idx], self.labels[idx]  # 返回指定索引的数据


train_dataset = TextDataset(x_train_padded, y_train)  # 创建训练数据集
test_dataset = TextDataset(x_test_padded, y_test)  # 创建测试数据集

train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)  # 创建训练数据加载器
test_loader = DataLoader(test_dataset, batch_size=32, shuffle=False)  # 创建测试数据加载器

2)模型设计

实现一个简单的循环神经网络, 第一层是 embedding 层, 词嵌入的大小是 100; 第二层是循环层, 循环层的输入尺寸是 100, 神经元数量是 256; 第三层是全连接层也就是输出层, 输入尺寸是 256, 输出是 1, 因为这是一个二分类问题, 所以输出尺寸是 1 即可。

class SimpleRNN(nn.Module):
    def __init__(self, vocab_size, embed_dim, hidden_dim, output_dim):
        super(SimpleRNN, self).__init__()
        self.embedding = nn.Embedding(vocab_size, embed_dim)  # 词嵌入层
        self.rnn = nn.RNN(embed_dim, hidden_dim, batch_first=True)
        self.fc = nn.Linear(hidden_dim, output_dim)

    def forward(self, text):
        embedded = self.embedding(text)
        output, hidden = self.rnn(embedded)
        out = self.fc(output[:, -1, :])
        return out

3)训练配置

设置损失函数和优化器。

model = SimpleRNN(max_features + 1, 100, 256, 1)  # 创建模型实例
# 编译模型
criterion = nn.CrossEntropyLoss()  # 使用交叉熵损失函数
optimizer = optim.Adam(model.parameters())  # 使用 SGD/Adam 优化器

4)训练过程

训练并保存模型

# 训练模型
def train(model, train_loader, optimizer, criterion, epochs):
    for epoch in range(epochs):  # 训练一个周期
        model.train()  # 设置模型为训练
        for texts, labels in train_loader:  # 遍历训练数据
            optimizer.zero_grad()  # 清零梯度
            outputs = model.forward(texts)  # 前向传播
            loss = criterion(outputs.squeeze(), labels.float())  # 计算损失
            loss.backward()  # 反向传播
            optimizer.step()  # 更新参数

# 训练并测试模型
train(model, train_loader, optimizer, criterion, epochs=1)
# 模型保存并测试
torch.save(model.state_dict(), 'rnn_state_dict.pth')

5)测试模型

评估模型性能

# 测试模型
def predict(model, test_loader):
    model.eval()  # 设置模型为评估模式
    correct = 0
    total = 0
    with torch.no_grad():  # 不计算梯度
        for texts, labels in test_loader:  # 遍历测试数据
            outputs = model.forward(texts)  # 前向传播
            predicted = (outputs.squeeze() > 0.5).int()  # 预测标签
            total += labels.size(0)  # 总样本数
            correct += (predicted == labels).sum().item()  # 正确预测数
    print(f'测试准确率: {correct / total}')

# 模型评估
model = SimpleRNN(max_features + 1, 100, 256, 1)
model.load_state_dict(torch.load('rnn_state_dict.pth'))
predict(model, test_loader)

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

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

相关文章

Linux网络 | 网络层IP报文解析、认识网段划分与IP地址

前言&#xff1a;本节内容为网络层。 主要讲解IP协议报文字段以及分离有效载荷。 另外&#xff0c; 本节也会带领友友认识一下IP地址的划分。 那么现在废话不多说&#xff0c; 开始我们的学习吧&#xff01;&#xff01; ps&#xff1a;本节正式进入网络层喽&#xff0c; 友友们…

2025年大年初一篇,C#调用GPU并行计算推荐

C#调用GPU库的主要目的是利用GPU的并行计算能力&#xff0c;加速计算密集型任务&#xff0c;提高程序性能&#xff0c;支持大规模数据处理&#xff0c;优化资源利用&#xff0c;满足特定应用场景的需求&#xff0c;并提升用户体验。在需要处理大量并行数据或进行复杂计算的场景…

python算法和数据结构刷题[2]:链表、队列、栈

链表 链表的节点定义&#xff1a; class Node():def __init__(self,item,nextNone):self.itemitemself.nextNone 删除节点&#xff1a; 删除节点前的节点的next指针指向删除节点的后一个节点 添加节点&#xff1a; 单链表 class Node():"""单链表的结点&quo…

Baklib解析内容中台与人工智能技术带来的价值与机遇

内容概要 在数字化转型的浪潮中&#xff0c;内容中台与人工智能技术的结合为企业提供了前所未有的发展机遇。内容中台作为一种新的内容管理和生产模式&#xff0c;通过统一管理和协调各种内容资源&#xff0c;帮助企业更高效地整合内外部数据。而人工智能技术则以其强大的数据…

Flask框架基础入门教程_ezflaskapp

pip install flaskFlask 快速入门小应用 学东西&#xff0c;得先知道我们用这个东西&#xff0c;能做出来一个什么东西。 一个最小的基于flask 的应用可能看上去像下面这个样子&#xff1a; from flask import Flask app Flask(__name__)app.route(/) def hello_world():ret…

黑马点评 - 商铺类型缓存练习题(Redis List实现)

首先明确返回值是一个 List<ShopType> 类型那么我们修改此函数并在 TypeService 中声明 queryTypeList 方法&#xff0c;并在其实现类中实现此方法 GetMapping("list")public Result queryTypeList() {return typeService.queryTypeList();}实现此方法首先需要…

洛谷P4057 [Code+#1] 晨跑

题目链接&#xff1a;P4057 [Code#1] 晨跑 - 洛谷 | 计算机科学教育新生态 题目难度&#xff1a;普及一 题目分析&#xff1a;这道题很明显是求最大公倍数&#xff0c;写题解是为了帮助自己复习。 下面用两种方法介绍如何求最大公倍数&#xff1a; 暴力破解 #include<bits…

讯飞绘镜(ai生成视频)技术浅析(四):图像生成

1. 技术架构概述 讯飞绘镜的图像生成技术可以分为以下几个核心模块: 文本理解与视觉元素提取:解析脚本中的场景描述,提取关键视觉元素(如人物、场景、物体等)。 视觉元素生成:根据文本描述生成具体的视觉元素(如人物、场景、物体等)。 分镜画面生成:将视觉元素组合成…

FreeRTOS从入门到精通 第十五章(事件标志组)

参考教程&#xff1a;【正点原子】手把手教你学FreeRTOS实时系统_哔哩哔哩_bilibili 一、事件标志组简介 1、概述 &#xff08;1&#xff09;事件标志位是一个“位”&#xff0c;用来表示事件是否发生。 &#xff08;2&#xff09;事件标志组是一组事件标志位的集合&#x…

使用Pygame制作“俄罗斯方块”游戏

1. 前言 俄罗斯方块&#xff08;Tetris&#xff09; 是一款由方块下落、行消除等核心规则构成的经典益智游戏&#xff1a; 每次从屏幕顶部出现一个随机的方块&#xff08;由若干小方格组成&#xff09;&#xff0c;玩家可以左右移动或旋转该方块&#xff0c;让它合适地堆叠在…

deepseek大模型本机部署

2024年1月20日晚&#xff0c;中国DeepSeek发布了最新推理模型DeepSeek-R1&#xff0c;引发广泛关注。这款模型不仅在性能上与OpenAI的GPT-4相媲美&#xff0c;更以开源和创新训练方法&#xff0c;为AI发展带来了新的可能性。 本文讲解如何在本地部署deepseek r1模型。deepseek官…

常见“栈“相关题目

找往期文章包括但不限于本期文章中不懂的知识点&#xff1a; 个人主页&#xff1a;我要学编程(ಥ_ಥ)-CSDN博客 所属专栏&#xff1a; 优选算法专题 目录 1047.删除字符串中的所有相邻重复项 844.比较含退格的字符串 227.基本计算器 II 394.字符串解码 946.验证栈序列 104…

QT实现有限元软件操作界面

本系列文章致力于实现“手搓有限元&#xff0c;干翻Ansys的目标”&#xff0c;基本框架为前端显示使用QT实现交互&#xff0c;后端计算采用Visual Studio C。 本篇将二维矩形截面梁单元&#xff08;Rect_Beam2D2Node&#xff09;组成的钢结构桥作为案例来展示软件功能。 也可以…

软件工程经济学-日常作业+大作业

目录 一、作业1 作业内容 解答 二、作业2 作业内容 解答 三、作业3 作业内容 解答 四、大作业 作业内容 解答 1.建立层次结构模型 (1)目标层 (2)准则层 (3)方案层 2.构造判断矩阵 (1)准则层判断矩阵 (2)方案层判断矩阵 3.层次单排序及其一致性检验 代码 …

Go学习:Go语言中if、switch、for语句与其他编程语言中相应语句的格式区别

Go语言中的流程控制语句逻辑结构与其他编程语言类似&#xff0c;格式有些不同。Go语言的流程控制中&#xff0c;包括if、switch、for、range、goto等语句&#xff0c;没有while循环。 目录 1. if 语句 2. switch语句 3. for语句 4. range语句 5. goto语句&#xff08;不常用…

14-8C++STL的queue容器

一、queue容器 (1)queue容器的简介 queue为队列容器&#xff0c;“先进先出”的容器 (2)queue对象的构造 queue<T>q; queue<int>que Int;//存放一个int的queue容器 queue<string>queString;//存放一个string的queue容器 (3)queue容器的push()与pop()方…

【B站保姆级视频教程:Jetson配置YOLOv11环境(四)cuda cudnn tensorrt配置】

Jetson配置YOLOv11环境&#xff08;4&#xff09;cuda cudnn tensorrt配置 文章目录 0. 简介1. cuda配置&#xff1a;添加cuda环境变量2. cudnn配置3. TensorRT Python环境配置3.1 系统自带Python环境中的TensorRT配置3.2 Conda 虚拟Python环境中的TensorRT配置 0. 简介 官方镜…

信号模块--simulink操作

位置simulink/sourses 常用的模块 功能&#xff1a;常数模块&#xff0c;提供一个常数 数据设置可以是一维或多维 一维数据设置 多维数据设置&#xff08;例三维数据设置&#xff09; 方波脉冲模块 模块用于按固定间隔生成方波脉冲信号 振幅就是方波的幅度&#xff0c;0到…

强化学习笔记(3)——基于值函数的方法和策略梯度方法

分为两大类方法&#xff1a; 基于值函数的方法&#xff08;Temporal Difference Methods, TD Methods&#xff09; 策略梯度方法&#xff08;Policy Gradient Methods&#xff09;。 二者不同之处&#xff1a; 通过值函数来间接表达隐式的策略&#xff0c;一个是直接迭代优化策…

新年新挑战:如何用LabVIEW开发跨平台应用

新的一年往往伴随着各种新的项目需求&#xff0c;而跨平台应用开发无疑是当前备受瞩目的发展趋势。在众多开发工具中&#xff0c;LabVIEW 以其独特的图形化编程方式和强大的功能&#xff0c;为开发跨平台应用提供了有效的途径。本文将深入探讨如何运用 LabVIEW 开发能够在不同操…