循环神经网络(Recurrent Neural Network,RNN)

简介:个人学习分享,如有错误,欢迎批评指正。

一. 核心理念

循环神经网络(Recurrent Neural Network,RNN)是一类专门用于处理序列数据的神经网络架构。其独特之处在于能够处理输入序列中元素的时序关系,通过在网络中引入循环连接,使得信息能够在时间步之间传递和积累。

时间序列数据是指在不同时间点上收集到的数据,这类数据反映了某一事物、现象等随时间的变化状态或程度。当然序列数据也可以不是时间,比如文字序列,但总归序列数据有一个特点——后面的数据跟前面的数据有关系

为什么要发明RNN

在这里插入图片描述

我们先来看一个NLP很常见的问题,命名实体识别,举个例子,现在有两句话:
第一句话:I like eating apple!(我喜欢吃苹果!)
第二句话:The Apple is a great company!(苹果真是一家很棒的公司!)
现在的任务是要给apple打Label,我们都知道第一个apple是一种水果,第二个apple是苹果公司,假设我们现在有大量的已经标记好的数据以供训练模型,当我们使用全连接的神经网络时,我们做法是把apple这个单词的特征向量输入到我们的模型中(如上图),在输出结果时,让我们的label里,正确的label概率最大,来训练模型,但我们的语料库中,有的apple的label是水果,有的label是公司,这将导致模型在训练的过程中,预测的准确程度,取决于训练集中哪个label多一些,这样的模型对于我们来说完全没有作用。问题就出在了我们没有结合上下文去训练模型,而是单独的在训练apple这个单词的label,这也是全连接神经网络模型所不能做到的,于是就有了我们的循环神经网络。

二. RNN的基本网络结构

1 网络组成

标准的RNN由以下几个主要部分组成:

  • 输入层 (Input Layer):接收序列数据的每一个时间步的输入向量
  • 隐藏层 (Hidden Layer):包含循环连接,用于储存和传递时间步之间的信息
  • 输出层 (Output Layer):生成每个时间步的输出。

2 RNN基础结构

单层网络结构如下图所示:

在这里插入图片描述
输入是 x x x,经过变换 W x + b Wx + b Wx+b激活函数 f f f,得到输出 y y y

假设这里的激活函数 f f f 是 sigmoid 函数:
f ( x ) = 1 1 + e − x f(x) = \frac{1}{1 + e^{-x}} f(x)=1+ex1
则进一步得到:
y = 1 1 + e − ( W x + b ) y = \frac{1}{1 + e^{-(Wx + b)}} y=1+e(Wx+b)1

在实际应用中,我们还会遇到很多序列形的数据。

为了建模序列问题,RNN 引入了 隐藏状态 h h h (hidden state) 的概念,隐藏状态 h h h 可以对序列形的数据提取特征,接着再转换为输出。

先从 h 1 h_1 h1 的计算开始看:
在这里插入图片描述

图示中记号的含义是:

a) 圆圈或方块表示的是向量。

b) 一个箭头就表示对该向量做一次变换。如上图中 h 0 h_0 h0 x 1 x_1 x1 分别有一个箭头连接,就表示对 h 0 h_0 h0 x 1 x_1 x1 各做了一次变换。

h 2 h_2 h2 的计算和 h 1 h_1 h1 类似,但有两点需要注意:

  1. 在计算时,每一步使用的参数 U , W , b U, W, b U,W,b 都是一样的,也就是说每个步骤的参数都是共享的,这是 RNN 的重要特点。(虽然说 X [ t − 1 ] , X [ t ] , X [ t + 1 ] X[t-1], X[t], X[t+1] X[t1],X[t],X[t+1] 是表示不同时间刻的输入,但是真正输入到 RNN 网络中的时候,并不是作为单独的向量一个一个输入,而是组合在一起形成一个矩阵输入,然后这个矩阵再通过权重矩阵 U U U 的变化。其实是同一时刻输入地,只是计算的先后顺序不同。因此同一个隐藏层中,不同时刻的输入他们的 W , V , U W, V, U W,V,U 参数是共享的。)

  2. LSTM 中的权值则不共享因为它是在两个不同的向量中。而 RNN 的权值为何共享呢?很简单,因为 RNN 的权值是在同一个向量中,只是不同时刻而已

在这里插入图片描述

依次计算剩下来的(使用相同的参数 U , W , b U, W, b U,W,b):

在这里插入图片描述

为了方便起见,只画出序列长度为4的情况,实际上,这个计算过程可以无限地持续下去。
我们目前的RNN还没有输出,得到输出值的方法就是直接通过 h h h 进行计算:
在这里插入图片描述

正如之前所说,一个箭头就表示对对应的向量做一次类似于 f ( W x + b ) f(Wx + b) f(Wx+b) 的变换,这里的这个箭头就表示对 h 1 h_1 h1 进行一次变换,得到输出 y 1 y_1 y1

剩下的输出类似进行(使用和 h 1 h_1 h1 同样的参数 V V V c c c):
在这里插入图片描述

这就是最经典的 RNN 结构,是 x 1 , x 2 , … , x n x_1, x_2, \dots, x_n x1,x2,,xn,输出为 y 1 , y 2 , … , y n y_1, y_2, \dots, y_n y1,y2,,yn。也就是说,输入和输出序列必须是等长的。

三. RNN的基本工作流程

1 序列数据的处理

RNN主要用于处理序列数据,如文本、语言、时间序列等。假设输入序列为 X = ( x 1 , x 2 , x 3 , … , x T ) X = (x_1, x_2, x_3, \ldots, x_T) X=(x1,x2,x3,,xT),RNN逐步处理序列中的每一个时间步 t = 1 , 2 , … , T t = 1, 2, \ldots, T t=1,2,,T

2 时间步之间的信息传递

在每一个时间步 t t t,RNN接收当前输入 x t x_t xt 和前一时间步的隐藏状态 h t − 1 h_{t-1} ht1,通过非线性变换计算当前时间步的隐藏状态 h t h_t ht,并根据 h t h_t ht 生成输出 y t y_t yt。这种机制允许网络在处理当前输入时,结合之前的历史信息

3 信息流动图示

四. 数学基础

1 隐藏状态的计算

每个时间步的隐藏状态 h t h_t ht 由当前输入 x t x_t xt 和前一隐藏状态 h t − 1 h_{t-1} ht1 共同决定,计算公式如下:
h t = tanh ⁡ ( W x h x t + W h h h t − 1 + b h ) h_t = \tanh(W_{xh}x_t + W_{hh}h_{t-1} + b_h) ht=tanh(Wxhxt+Whhht1+bh)

  • W x h W_{xh} Wxh:输入到隐藏层的权重矩阵
  • W h h W_{hh} Whh:隐藏层到隐藏层的权重矩阵(循环连接)
  • b h b_h bh:隐藏层的偏置向量
  • tanh ⁡ \tanh tanh:激活函数,常用双曲正切函数以引入非线性

2 输出的计算

基于当前隐藏状态 h t h_t ht,计算输出 y t y_t yt
y t = W h y h t + b y y_t = W_{hy}h_t + b_y yt=Whyht+by

  • W h y W_{hy} Why:隐藏层到输出层的权重矩阵
  • b y b_y by:输出层的偏置向量

3 参数共享

RNN在所有时间步之间共享权重矩阵 W x h W_{xh} Wxh W h h W_{hh} Whh W h y W_{hy} Why。这种参数共享不仅减少了模型的参数数量,还使得RNN能够处理可变长度的序列输入

五. 信息流动与记忆机制

1 前向传播

在前向传播过程中,RNN按时间步依次处理输入序列的每个元素。具体步骤如下:

  1. 初始化:设定初始隐藏状态 h 0 h_0 h0(通常为零向量)。

  2. 时间步 t t t

    • 接收当前输入 x t x_t xt 和前一隐藏状态 h t − 1 h_{t-1} ht1
    • 计算当前隐藏状态 h t h_t ht
    • 生成当前输出 y t y_t yt

整个过程可以表示为:
h t = tanh ⁡ ( W x h x t + W h h h t − 1 + b h ) y t = W h y h t + b y \begin{aligned} h_t &= \tanh(W_{xh}x_t + W_{hh}h_{t-1} + b_h) \\ y_t &= W_{hy}h_t + b_y \end{aligned} htyt=tanh(Wxhxt+Whhht1+bh)=Whyht+by

2 隐藏状态的记忆能力

通过循环连接,隐藏状态 h t h_t ht 不仅包含当前时间步的信息,还积累了前面时间步的历史信息。这使得RNN能够在处理当前输入时,参考和利用之前的信息,从而捕捉序列中的时序依赖关系

六. 学习机制:通过时间反向传播(BPTT)

1 损失函数

对于一个序列任务,通常定义一个整体损失函数,如对所有时间步的输出损失进行累加:
L = ∑ t = 1 T L ( y t , y ^ t ) L = \sum_{t=1}^{T} L(y_t, \hat{y}_t) L=t=1TL(yt,y^t)

其中, L ( y t , y ^ t ) L(y_t, \hat{y}_t) L(yt,y^t) 表示在时间步 t t t 的损失。

2 反向传播过程

由于RNN的隐藏状态在时间步之间共享传递,传统的反向传播方法无法直接应用。取而代之的是通过时间反向传播(Backpropagation Through Time,BPTT),其步骤如下:

  1. 展开网络:将RNN在时间维度上展开成一个深层网络,每个时间步对应网络中的一层

  2. 计算损失在每个时间步计算输出的损失,并累加得到整个序列的总损失

  3. 反向传播

    • 从最后一个时间步 T T T 开始,逐步向前计算每个时间步的梯度
    • 于隐藏状态在时间步之间共享,梯度会在时间步之间传播,影响每个时间步的权重更新
  4. 更新参数:根据损失的梯度,通过优化算法(如SGD, Adam)更新权重参数 W x h W_{xh} Wxh, W h h W_{hh} Whh, W h y W_{hy} Why 及偏置 b h b_h bh, b y b_y by

七. RNN的具体工作机制

1 初始化

在开始处理序列之前,RNN需要初始化隐藏状态 h 0 h_0 h0。通常, h 0 h_0 h0 被设定为零向量,但也可以根据具体任务进行初始化。

2 前向传播详细过程

对于每一个时间步 t t t,RNN执行以下操作:

  1. 输入获取:接收当前时间步的输入 x t x_t xt 和前一时间步的隐藏状态 h t − 1 h_{t-1} ht1
  2. 隐藏状态更新:计算当前隐藏状态 h t h_t ht,结合 x t x_t xt h t − 1 h_{t-1} ht1
  3. 输出生成:基于当前隐藏状态 h t h_t ht,生成输出 y t y_t yt

这种逐步处理的方式使得RNN能够在处理当前输入时,参考并利用之前的信息,实现对序列的动态建模。

3 反向传播详细过程

通过时间反向传播(BPTT)的步骤如下:

  1. 展开网络:将RNN在时间维度上展开为一个多层的前馈网络,每个时间步对应网络中的一层。
  2. 损失计算:在每个时间步计算输出的损失,并累加得到整体损失。
  3. 梯度计算
    • 从最后一个时间步开始,逐步向前计算每个时间步的梯度
    • 每个时间步的梯度不仅受当前时间步的损失影响,还受后续时间步梯度的影响,因为隐藏状态在时间步之间共享
  4. 权重更新:根据累积的梯度,通过优化算法更新权重参数。

4 参数更新

RNN的参数更新通常采用梯度下降法及其变种,如:

  • 随机梯度下降(SGD):逐步更新参数。
  • Adam优化:结合动量项和自适应学习率,提升收敛速度和稳定性。
  • RMSProp:适应性平滑动量,动态调整学习率。

八. RNN的优势与局限

1 优势

  • 序列建模能力强:能够捕捉和利用序列中的时序依赖关系,适用于多种序列任务。
  • 参数共享权重在时间步之间共享,减少了模型的参数数量,提高了泛化能力。
  • 处理可变长度序列:能够处理长短不同的输入和输出序列,具备高度的灵活性。

2 局限

  • 梯度消失与爆炸:在长序列训练中,在反向传播过程中,梯度容易消失或爆炸(因为RNN在时序上共享参数,梯度在反向传播过程中,不断连乘,数值不是越来越大就是越来越小),影响模型的学习效果。
  • 计算效率低:由于时间步之间存在依赖关系, 难以进行并行计算(RNN的计算过程具有依赖性,因此难以有效地并行化,无法充分利用GPU等硬件加速器的计算能力) ,训练速度较慢。
  • 难以捕捉长距离依赖:尽管LSTM和GRU在一定程度上缓解了这一问题,但对于非常长的序列,仍然存在挑战。

九. RNN的优化与改进

1 梯度裁剪(Gradient Clipping)

在训练过程中,当梯度的范数超过预设阈值时,将其缩放至阈值范围内,防止梯度爆炸。
if  ∥ ∇ ∥ > 阈值  ⇒ ∇ ← 阈值 ∥ ∇ ∥ × ∇ \text{if} \ \|\nabla\| > \text{阈值} \ \Rightarrow \ \nabla \leftarrow \frac{\text{阈值}}{\|\nabla\|} \times \nabla if ∥∇∥>阈值  ∥∇∥阈值×

2 正则化技术

  • Dropout:在RNN中应用Dropout需要特殊处理,如在每个时间步共享Dropout掩码,防止时间步之间的信息泄露。
  • L2正则化:通过在损失函数中添加权重的平方和,防止权重过大,减少过拟合。

3 优化算法

采用先进的优化算法,如Adam、RMSProp,提升训练的收敛速度和稳定性。

4 权重初始化

使用适当的权重初始化方法,如Xavier初始化He初始化,确保网络在开始训练时处于良好的状态,避免梯度消失或爆炸。

5 使用更稳定的激活函数

采用ReLU等更稳定的激活函数,替代传统的tanh或sigmoid,可以在一定程度上缓解梯度消失问题。

十. 高级RNN结构

1 双向RNN(Bidirectional RNN)

双向RNN通过同时考虑序列的正向和反向信息提升模型对上下文的理解能力。其结构包括两个独立的RNN,一个按时间正序处理输入,另一个按时间逆序处理输入,最终将两个方向的隐藏状态进行合并。

数学表示

h t f o r w a r d = RNN_Cell ( h t − 1 f o r w a r d , x t ) h t b a c k w a r d = RNN_Cell ( h t + 1 b a c k w a r d , x t ) h t = [ h t f o r w a r d , h t b a c k w a r d ] h_t^{forward} = \text{RNN\_Cell}(h_{t-1}^{forward}, x_t) \\ h_t^{backward} = \text{RNN\_Cell}(h_{t+1}^{backward}, x_t) \\ h_t = [h_t^{forward}, h_t^{backward}] htforward=RNN_Cell(ht1forward,xt)htbackward=RNN_Cell(ht+1backward,xt)ht=[htforward,htbackward]

2 深度RNN(Deep RNN)

深度RNN通过堆叠多个RNN层,增加网络的深度,从而提升模型的表达能力。每一层RNN的输出作为下一层RNN的输入。

结构示意

输入层 → RNN层1 → RNN层2... → RNN层L → 输出层

3 注意力机制RNN(Attention-based RNN)

注意力机制通过赋予输入序列中不同部分不同的权重,提升模型对重要信息的关注度。特别是在机器翻译等任务中,注意力机制显著提升了模型性能。

数学表示

在计算输出时,引入一个注意力权重 α t , i \alpha_{t,i} αt,i,用于加权输入序列中不同时间步的隐藏状态:
α t , i = exp ⁡ ( e t , i ) ∑ k = 1 T exp ⁡ ( e t , k ) \alpha_{t,i} = \frac{\exp(e_{t,i})}{\sum_{k=1}^{T} \exp(e_{t,k})} αt,i=k=1Texp(et,k)exp(et,i)
e t , i = score ( h t , h i encoder ) e_{t,i} = \text{score}(h_t, h_i^{\text{encoder}}) et,i=score(ht,hiencoder)
context t = ∑ i = 1 T α t , i h i encoder \text{context}_t = \sum_{i=1}^{T} \alpha_{t,i} h_i^{\text{encoder}} contextt=i=1Tαt,ihiencoder
y t = Output ( h t , context t ) y_t = \text{Output}(h_t, \text{context}_t) yt=Output(ht,contextt)

其中, e t , i e_{t,i} et,i 是一个评分函数,用于计算当前隐藏状态 h t h_t ht 与编码器隐藏状态 h i encoder h_i^{\text{encoder}} hiencoder 的相关性。

十一. RNN与其他模型的对比

1 RNN与前馈神经网络(FNN)

  • 序列处理能力:RNN适用于处理序列数据,而FNN主要处理固定大小的输入
  • 记忆能力:RNN具有记忆前一时间步信息的能力,FNN缺乏这种能力

2 RNN与卷积神经网络(CNN)

  • 结构差异:CNN主要用于处理具有局部特征的二维数据(如图像),而RNN用于处理一维序列数据
  • 应用领域:CNN广泛应用于计算机视觉,RNN则主要用于自然语言处理、语言识别等领域。

3 RNN与Transformer

  • 并行化能力:Transformer利用自注意力机制,能够更好地并行化计算,提升训练效率。
  • 捕捉依赖关系:Transformer在捕捉长距离依赖关系上表现优异,而RNN在这方面存在梯度消失问题
  • 应用趋势:近年来,Transformer逐渐取代RNN成为序列建模的主流架构,但RNN在资源受限或需要极长序列的场景中仍具有优势

十二. 案例和python代码

案例概述

任务:基于给定的文本数据(例如莎士比亚的作品),训练一个标准 RNN 模型,以生成具有相似风格的新文本。

模型架构

  1. 字符级编码:将每个字符转换为整数索引,并进行独热编码。
  2. 嵌入层(可选):将字符索引转换为密集向量表示。
  3. 多层标准 RNN (SimpleRNN):捕捉字符序列中的模式和依赖关系。
  4. 全连接层 (Dense Layer):预测下一个字符的概率分布。
  5. Dropout层:防止过拟合。
  6. 批归一化层(可选):加强训练并稳定模型。

所需库

首先,确保你已经安装了必要的库:

pip install tensorflow numpy

Python代码实现

以下是完整的Python代码,实现了字符级文本生成的标准RNN模型:

import tensorflow as tf
import numpy as np
import os
import sys
import requestsfrom tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, SimpleRNN, Dropout, Embedding, BatchNormalization
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.callbacks import ModelCheckpoint, EarlyStopping# 下载示例文本数据(莎士比亚的《哈姆雷特》)
def download_text():url = "https://www.gutenberg.org/files/2264/2264-0.txt"response = requests.get(url)text = response.textreturn text# 数据预处理
def preprocess_text(text, max_vocab=1000):# 保留前max_vocab个字符unique_chars = sorted(list(set(text)))if len(unique_chars) > max_vocab:unique_chars = unique_chars[:max_vocab]char_to_int = {c: i for i, c in enumerate(unique_chars)}int_to_char = {i: c for i, c in enumerate(unique_chars)}encoded_text = [char_to_int[c] for c in text if c in char_to_int]return encoded_text, char_to_int, int_to_char, len(unique_chars)# 创建数据集
def create_dataset(encoded_text, seq_length):X = []y = []for i in range(0, len(encoded_text) - seq_length):X.append(encoded_text[i:i + seq_length])y.append(encoded_text[i + seq_length])X = np.array(X)y = np.array(y)return X, y# 超参数
SEQ_LENGTH = 100      # 输入序列长度
BATCH_SIZE = 128
EPOCHS = 50
EMBEDDING_DIM = 64
RNN_UNITS = 256
DROPOUT_RATE = 0.2
LEARNING_RATE = 0.001
MAX_VOCAB = 1000      # 最大字符集大小# 下载并预处理文本数据
print("下载文本数据...")
text = download_text()
print(f"文本长度: {len(text)}")print("预处理文本数据...")
encoded_text, char_to_int, int_to_char, vocab_size = preprocess_text(text, max_vocab=MAX_VOCAB)
print(f"字符集大小: {vocab_size}")# 创建数据集
print("创建数据集...")
X, y = create_dataset(encoded_text, SEQ_LENGTH)
print(f"输入数据形状: {X.shape}")
print(f"目标数据形状: {y.shape}")# 分割训练和验证集
split = int(0.9 * len(X))
X_train, X_val = X[:split], X[split:]
y_train, y_val = y[:split], y[split:]# 构建模型
print("构建模型...")
model = Sequential()# 嵌入层
model.add(Embedding(input_dim=vocab_size, output_dim=EMBEDDING_DIM, input_length=SEQ_LENGTH))# 第一层SimpleRNN
model.add(SimpleRNN(RNN_UNITS, return_sequences=True))
model.add(Dropout(DROPOUT_RATE))
model.add(BatchNormalization())# 第二层SimpleRNN
model.add(SimpleRNN(RNN_UNITS))
model.add(Dropout(DROPOUT_RATE))
model.add(BatchNormalization())# 全连接层
model.add(Dense(256, activation='relu'))
model.add(Dropout(DROPOUT_RATE))# 输出层
model.add(Dense(vocab_size, activation='softmax'))# 编译模型
optimizer = Adam(learning_rate=LEARNING_RATE)
model.compile(loss='sparse_categorical_crossentropy', optimizer=optimizer, metrics=['accuracy'])# 模型概述
model.summary()# 设置回调
checkpoint_filepath = 'model_checkpoint.h5'
checkpoint = ModelCheckpoint(filepath=checkpoint_filepath, monitor='val_loss', save_best_only=True, verbose=1)
early_stopping = EarlyStopping(monitor='val_loss', patience=5, restore_best_weights=True, verbose=1)# 训练模型
print("开始训练模型...")
history = model.fit(X_train, y_train,validation_data=(X_val, y_val),epochs=EPOCHS,batch_size=BATCH_SIZE,callbacks=[checkpoint, early_stopping])# 加载最佳模型
model.load_weights(checkpoint_filepath)# 生成文本
def generate_text(model, int_to_char, char_to_int, seed_text, length=100):generated = seed_textencoded = [char_to_int[c] for c in seed_text if c in char_to_int]for _ in range(length):if len(encoded) < SEQ_LENGTH:input_seq = [0] * (SEQ_LENGTH - len(encoded)) + encodedelse:input_seq = encoded[-SEQ_LENGTH:]input_seq = np.array([input_seq])preds = model.predict(input_seq, verbose=0)[0]next_index = np.argmax(preds)next_char = int_to_char.get(next_index, '')generated += next_charencoded.append(next_index)return generated# 选择一个随机种子文本
start_index = np.random.randint(0, len(encoded_text) - SEQ_LENGTH - 1)
seed_encoded = encoded_text[start_index:start_index + SEQ_LENGTH]
seed_text = ''.join([int_to_char.get(i, '') for i in seed_encoded])
print("生成文本:")
print(generate_text(model, int_to_char, char_to_int, seed_text, length=1000))

总结
循环神经网络(RNN)通过其独特的循环连接和隐藏状态机制,能够有效处理和建模序列数据中的时序依赖关系。尽管标准RNN在训练过程中面临梯度消失和爆炸的挑战,但通过引入LSTM、GRU等变种,显著提升了其在捕捉长期依赖方面的能力。同时,RNN在多种实际应用中展现了强大的潜力。然而,随着Transformer等更高效模型的出现,RNN的应用场景逐渐被拓展和细化。未来,RNN与其他模型的结合,如混合神经网络,可能进一步推动其在人工智能领域的发展和应用。


参考文献:

如何从RNN起步,一步一步通俗理解LSTM_rnn lstm-CSDN博客

【精选】通俗易懂的RNN-CSDN博客

史上最小白之RNN详解-CSDN博客

结~~~

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

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

相关文章

STM32定时器

目录 STM32定时器概述 STM32基本定时器 基本定时器的功能 STM32基本定时器的寄存器 STM32通用定时器 STM32定时器HAL库函数 STM32定时器概述 从本质上讲定时器就是“数字电路”课程中学过的计数器&#xff08;Counter&#xff09;&#xff0c;它像“闹钟”一样忠实地为处…

41 C 语言共用体:共用体数据类型、共用体变量、访问共用体成员、与结构体的区别

目录 1 什么是共用体 2 共用体与结构体的区别 3 声明共用体类型 4 声明共用体变量 5 共用体内存分析 6 共用体成员的获取和赋值 7 综合案例 7.1 共同体特点演示 7.2 使用共用体存储学生和教师信息 1 什么是共用体 共用体&#xff08;Union&#xff09;是一种特殊的数据…

大型企业软件开发是什么样子的? - Web Dev Cody

引用自大型企业软件开发是什么样子的&#xff1f; - Web Dev Cody_哔哩哔哩_bilibili 一般来说 学技术的时候 我们会关注 开发语言特性 &#xff0c;各种高级语法糖&#xff0c;底层技术 但是很少有关注到企业里面的开发流程&#xff0c;本着以终为始&#xff08;以就业为导向…

OpenCV高级图形用户界面(8)在指定的窗口中显示一幅图像函数imshow()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 在指定的窗口中显示一幅图像。 函数 imshow 在指定的窗口中显示一幅图像。如果窗口是以 cv::WINDOW_AUTOSIZE 标志创建的&#xff0c;图像将以原…

An.如何在an中截取音频片段

如何在an中截取音频片段 在an动画制作过程中&#xff0c;部分片段需要插入音乐&#xff0c;如果想要插入一首歌曲的其中一小节&#xff0c;打开音频编辑软件操作就很麻烦&#xff0c;不妨直接在an中操作&#xff1a; 以这首节气歌为例&#xff0c;前奏太长需要剪掉前面的部分 …

TOGAF 9.2 与 TOGAF 10 的对比分析:架构演进之路

TOGAF 9.2 与 TOGAF 10 的对比分析&#xff1a;架构演进之路 前言 TOGAF&#xff08;The Open Group Architecture Framework&#xff09;自诞生以来&#xff0c;已成为企业架构&#xff08;EA&#xff09;领域的全球标准框架。随着时代的发展&#xff0c;TOGAF也在不断进化&…

基于SpringBoot+Vue+uniapp的在线招聘平台的详细设计和实现

详细视频演示 请联系我获取更详细的演示视频 项目运行截图 技术框架 后端采用SpringBoot框架 Spring Boot 是一个用于快速开发基于 Spring 框架的应用程序的开源框架。它采用约定大于配置的理念&#xff0c;提供了一套默认的配置&#xff0c;让开发者可以更专注于业务逻辑而不…

第二课:Python入门学习之开发工具的安装

今天我们进行Python开发工具的安装&#xff0c;其实网上的开发工具是很多的&#xff0c;每个人的习惯也都不一样&#xff0c;我们先去官网下载一个比较常用的吧。废话不多开始操作。 第一步&#xff1a;打开官网地址&#xff1a;https://www.jetbrains.com.cn/ 第二步&#xf…

面试题:Redis(三)

1. 面试题 背景 问题&#xff0c;上面业务逻辑你用java代码如何写&#xff1f; 2. 缓存双写一致性谈谈你的理解&#xff1f; 3. 双检加锁策略 多个线程同时去查询数据库的这条数据&#xff0c;那么我们可以在第一个查询数据的请求上使用一个 互斥锁来锁住它。 其他的线程走到这…

微知-Mellanox驱动中的iSCSI是什么?有哪三种网络存储有哪三种?iSER是什么?(iSCSI协议(总线),SAN 存储区域网络)

背景 本文根据Mellanox网卡驱动中关于iSCSI模块&#xff0c;来介绍iSCSI是什么&#xff1f;该技术发展演进背景&#xff1f; 关于iSCSI iSCSI是一种协议&#xff0c;SCSI是总线。比如常说的SAS&#xff08;Serial Attach SCSI&#xff09;存储盘对比与家用的SATA&#xff0…

Uiautomator2与weditor配置一直报错咋办

作者在配置这两个的时候绞尽脑汁了&#xff0c;u2的init总是报错并且无法自动在手机上安装atx&#xff0c;weditor可以打开但是只要对元素操作或者任意操作就会让你去重新init&#xff0c;搞得作者焦头烂额&#xff0c;而且网上各种各样的报错信息眼花缭乱&#xff0c;作者几乎…

NVIDIA NIM平台如何打造AI图表识别系统

NVIDIA NIM是一套易于使用的推理微服务&#xff0c;旨在加速企业中性能优化的生成式 AI 模型的部署。 NIM 推理微服务可以部署在任何地方&#xff0c;从工作站和本地到云&#xff0c;提供企业控制自己的部署选择并确保数据安全。它还提供行业领先的延迟和吞吐量&#xff0c;实现…

使用Windows创建一个MFC应用【带界面】

MFC使用教程【对初学者保姆型友好&#xff01;】 目录 前提条件 1&#xff1a;创建MFC应用程序 2. 项目结构解读 引用 外部依赖项 头文件 源文件 资源文件 文件功能详解 项目的主要流程 步骤2&#xff1a;配置OpenCV 安装OpenCV 包含目录与库文件 步骤3&#xff1…

云卓H30:引领科技与性能的完美融合!

在科技日新月异的今天&#xff0c;一款集高性能与便捷操作于一体的手持地面站成为了无人机、机器人等智能设备的得力助手。云卓H30手持地面站&#xff0c;凭借其搭载的高通骁龙660处理器&#xff0c;在多个适用场景中展现出了卓越的实力。 高通骁龙660&#xff0c;这款先进的移…

Python 如何处理大规模数据库表的迁移与数据迁移的高效执行

Python 如何处理大规模数据库表的迁移与数据迁移的高效执行 引言 在现代应用开发中&#xff0c;随着业务需求的增长&#xff0c;数据库表结构和数据往往需要进行迁移和更新。迁移&#xff08;Migration&#xff09;是指对数据库表的结构、数据类型、索引、约束等进行修改或更新…

Docker 安装sql server 登陆失败

错误&#xff1a; Sqlcmd: Error: Microsoft ODBC Driver 18 for SQL Server : SSL Provider: [error:0A000086:SSL routines::certificate verify failed:self-signed certificate]. Sqlcmd: Error: Microsoft ODBC Driver 18 for SQL Server : Client unable to establish co…

UE5 TimeLine入门

UE5 TimeLine入门 时间轴曲线 共计三个关键帧&#xff08;0,0&#xff09;(1.5,10) (3,0) 蓝图 1.按下空格键执行。 2.时间轴TimeLine函数。 3.动画播放结束后执行。 4.每一帧都执行。

单片机原理及应用笔记:单片机的结构原理与项目实践

作者介绍 李婷婷&#xff0c;女&#xff0c;银川科技学院计算机与人工智能学院&#xff0c;2022级计算机与科学技术9班本科生&#xff0c;单片机原理及应用课程第五组。 指导老师&#xff1a;王兴泽 电子邮箱&#xff1a;365349930qq.com 前言 本篇文章是参考《单片机原理…

rk3568 , rk3588 , rknpu2 sdk , rknn-toolkit2, rknn-toolkit2-lite 的了解

rknpu2 sdk 与 rknn-toolkit 的区别。 网上的截图&#xff1a; 总结&#xff1a; rknpu2 是针对 C接口的&#xff0c; rknn toolkit2 是针对 Python接口的。 至于 连不连板&#xff0c; 是不是 拷贝&#xff0c; 那不重要。 然后是 rknn rootlkit2 与 rknn toolkit2 li…

数据结构算法题:栈与队列的使用(一)

目录 用队列实现栈题目解题思路代码实现创建栈的结构体栈的初始化入栈出栈获取栈顶数据判断栈是否为空销毁栈 用队列实现栈 题目 题目描述&#xff1a; 示例&#xff1a; 解题思路 题目要求使用两个队列实现栈的入栈、出栈、获取栈顶元素、检查栈是否为空栈的基本操作。 …