pytorch深度学习—RNN-循环神经网络

结合生活实例,先简单认识一下什么是循环神经网络

先想个问题:为什么需要 “循环”?

你平时看句子、听语音、看视频,都是 “按顺序” 来的吧?比如 “我吃苹果” 和 “苹果吃我”,字一样但顺序不同,意思天差地别。

传统的神经网络像个 “健忘症患者”—— 处理每个字的时候,只看当前这个字,记不住前面的。比如看 “苹果吃我”,它看到 “苹果” 时,等下看到 “吃我”,早忘了 “苹果” 是啥了,自然分不清意思。

而 RNN 就像个 “有记性的人”—— 处理每个字时,会偷偷记住前面看过的内容。比如看 “苹果吃我”,它看到 “苹果” 时记下来,看到 “吃” 时,结合前面的 “苹果”,再看到 “我” 时,就知道是 “苹果吃我”(虽然不合逻辑,但能记住顺序)。

RNN 到底怎么 “记” 东西?

把 RNN 想象成一个 “复读机 + 记事本” 的结合体,处理序列数据(比如一句话)时,它会按顺序一个字一个字地 “读”,边读边记。

举个例子:用 RNN 理解句子 “我爱吃西瓜”。

  • 第一步(看 “我”)
    它先看到 “我”,心里默默记下来(这就是 “记忆”,专业名叫 “隐藏状态”),记的内容是 “现在看到了‘我’”。

  • 第二步(看 “爱”)
    它不会忘了刚才的 “我”,而是把 “爱” 和之前记的 “我” 放一起,更新记忆:“现在是‘我’+‘爱’”。

  • 第三步(看 “吃”)
    继续带着之前的记忆(“我 + 爱”),加上 “吃”,记忆变成:“我 + 爱 + 吃”。

  • 第四步(看 “西瓜”)
    带着 “我 + 爱 + 吃” 的记忆,加上 “西瓜”,最终记忆变成整个句子的信息:“我爱吃西瓜”。

你看,它每一步都把新内容和 “之前的记忆” 混在一起,更新记忆 —— 这就是 “循环” 的意思:后一步依赖前一步的记忆,一步步传递下去

为什么说 “权重共享”?

还是刚才的例子,RNN 处理 “我”“爱”“吃”“西瓜” 这四个字时,用的是同一套 “记东西的规则”。

就像你记日记,不管今天记开心事还是难过事,都是用同样的方式写在本子上(不会今天用中文,明天用英文)。RNN 也一样,处理每个字的逻辑完全相同,这样既能少学很多规则,又能适应不同长度的句子(比如一句话 3 个字或 10 个字,都能用同一套方法处理)。

RNN 能干啥?

说白了,就是处理 “有顺序” 的事儿:

  • 看一句话猜情绪(“这部电影太烂了” 是负面,得记住每个词的顺序才能判断);
  • 听语音转文字(声音是按时间顺序来的,前面的音和后面的音有关联);
  • 预测明天的天气(今天、昨天的天气会影响明天,得按时间顺序记下来)。

它的毛病在哪?

RNN 的 “记性” 不好,记不住太久远的事。比如一句话特别长:“今天早上出门时忘了带伞,结果……(中间 100 个字)…… 所以全身湿透了”。

RNN 处理到 “全身湿透了” 时,可能早就忘了 “早上没带伞” 这回事了 —— 这就是 “长时记忆差”,专业叫 “梯度消失”,后面的 LSTM、GRU 就是给它加了 “备忘录”,帮它记久一点。

总结一下:
RNN 就像一个 “有短期记忆的复读机”,处理按顺序来的数据时,会把新信息和之前的记忆混在一起,一步步传递下去,所以能理解顺序的重要性。但记性不算太好,长句子容易忘事儿~

专业术语解释 

循环神经网络(Recurrent Neural Network, RNN)是一类专门处理序列数据(如文本、语音、时间序列等)的神经网络,其核心是通过隐藏状态的循环传递捕捉数据中的时序依赖关系。以下从专业角度解析其基本结构与机制:

1. 核心目标

传统前馈神经网络(如 CNN、全连接网络)的输入是固定维度的非序列数据,且各层神经元间无反馈连接,无法处理时序依赖(如 “苹果吃我” 与 “我吃苹果” 的语义差异由词序决定)。 RNN 的核心设计是:让网络在处理序列的第 t 步时,能利用第 t-1 步的信息,从而建模序列中 “前因后果” 的关联。

2. 基本结构与循环机制

RNN 的结构可简化为 “输入层 - 隐藏层 - 输出层”,但其核心特征是隐藏层存在自循环连接,即隐藏层的输出会作为自身的输入参与下一时间步的计算。

关键变量定义:

核心计算公式:
  • 隐藏状态更新(循环的核心):

  • 输出计算

3. 权重共享机制

RNN 的关键特性是所有时间步共享同一套参数(\(W_{hx}, W_{hh}, W_{ho}, b_h, b_o\))。 这意味着:处理序列中不同位置的元素(如第 1 个词与第 t 个词)时,使用相同的权重矩阵与偏置。

  • 优势:极大减少参数数量(与序列长度 T 无关),使模型能适应任意长度的序列输入;
  • 本质:建模 “序列中通用的时序规律”(如语言中 “主谓宾” 的语法规则对所有句子通用)。

4. 序列处理模式

根据输入序列与输出序列的长度关系,RNN 的应用模式可分为 4 类:

  • 一对一:输入输出均为单元素(如固定长度的时序数据分类,如 “用前 3 天天气预测第 4 天”);
  • 一对多:单输入生成序列(如输入 “晴天” 生成 “出门带伞?否;适合野餐?是”);
  • 多对一:序列输入生成单输出(如文本情感分类,输入句子输出 “正面 / 负面”);
  • 多对多:序列输入生成等长 / 不等长序列(如机器翻译,输入 “我爱你” 输出 “I love you”)。

5. 局限性

标准 RNN 的隐藏状态更新依赖线性变换与简单激活函数(如 tanh),在处理长序列(如 T>100)时会出现梯度消失 / 爆炸问题

  • 反向传播时,梯度需通过 \(W_{hh}\) 的多次矩阵乘法传递,当 时梯度会指数级衰减(消失),导致模型无法学习长距离依赖(如 “早上忘带伞...(100 词后)... 淋湿了” 的关联);
  • 这一缺陷推动了 LSTM(长短期记忆网络)、GRU(门控循环单元)等改进模型的提出,通过 “门控机制” 动态控制信息的保留与遗忘。

总结:RNN 通过隐藏状态的循环传递与权重共享,实现了对序列时序依赖的建模,是处理时序数据的基础模型;其核心是公式 所体现的 “当前状态依赖历史状态” 的循环逻辑。

简易代码实战(最后附带完整代码)

1. 序列数据的表

# 生成正弦波时序数据
time = np.linspace(0, 2 * np.pi * n_samples / 10, n_samples + seq_length)
data = np.sin(time)# 创建输入序列X和目标值y
for i in range(n_samples):X.append(data[i:i+seq_length])  # 前seq_length个点作为输入y.append(data[i+seq_length])    # 下一个点作为预测目标

  • 概念对应
    • 序列数据:正弦波是典型的时序数据,每个点依赖于前面的点。
    • 输入序列长度seq_length=20表示用前 20 个时间步预测第 21 个!!!!!
    • 时间步(time step):每个时间步对应序列中的一个点(如t=1对应data[0])。

2. RNN 模型结构

class SimpleRNN(nn.Module):def __init__(self, input_size, hidden_size, output_size, num_layers=1):super(SimpleRNN, self).__init__()self.hidden_size = hidden_sizeself.num_layers = num_layers# 定义RNN层(核心组件)self.rnn = nn.RNN(input_size, hidden_size, num_layers, batch_first=True, nonlinearity='tanh')# 全连接层:将RNN的输出映射到预测值self.fc = nn.Linear(hidden_size, output_size)def forward(self, x):# 初始化隐藏状态h0(形状:[层数, 批量大小, 隐藏维度])h0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(x.device)# 前向传播RNN# out形状:[批量大小, 序列长度, 隐藏维度]# hn形状:[层数, 批量大小, 隐藏维度]out, hn = self.rnn(x, h0)# 只取最后一个时间步的输出(用于预测下一个值)out = out[:, -1, :]  # 形状:[批量大小, 隐藏维度]# 通过全连接层得到预测值out = self.fc(out)  # 形状:[批量大小, 输出维度]return out

一、模型初始化(__init__方法)

1. 参数含义
def __init__(self, input_size, hidden_size, output_size, num_layers=1):

  • input_size:每个时间步的输入特征数(本例中为 1,因为只输入正弦波的当前值)。
  • hidden_size:隐藏状态的维度(记忆容量),数值越大,模型能记住的信息越多(本例为 64)。
  • output_size:输出的维度(本例中为 1,因为只预测下一个正弦波值)。
  • num_layers:RNN 的层数(默认 1 层,可堆叠多层增强表达能力)。
2. RNN 层的定义
self.rnn = nn.RNN(input_size, hidden_size, num_layers, batch_first=True, nonlinearity='tanh')

  • batch_first=True:输入张量的第 1 维是批量大小([batch, seq_len, feature])。
  • nonlinearity='tanh':使用 tanh 激活函数(将输出值压缩到 [-1, 1] 区间)。
3. 全连接层的作用
self.fc = nn.Linear(hidden_size, output_size)

  • 将 RNN 的隐藏状态(hidden_size维)映射到最终输出(output_size维)。
  • 相当于做一个线性变换:y = W*h + b

二、前向传播(forward方法)

1. 初始化隐藏状态
h0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(x.device)

  • h0是序列开始时的初始隐藏状态,形状为[层数, 批量大小, 隐藏维度]
  • 初始化为全零向量,表示序列开始时模型没有任何先验记忆。
2. RNN 层的计算
out, hn = self.rnn(x, h0)

  • 输入

    • x:输入序列,形状为[batch, seq_len, input_size](本例中为[32, 20, 1])。
    • h0:初始隐藏状态,形状为[num_layers, batch, hidden_size]
  • 输出

    • out:所有时间步的隐藏状态,形状为[batch, seq_len, hidden_size]
    • hn:最后一个时间步的隐藏状态(即out的最后一个时间步),形状为[num_layers, batch, hidden_size]
3. 提取最后时间步的输出
out = out[:, -1, :]  # 取每个样本的最后一个时间步

  • out的原始形状:[batch, seq_len, hidden_size](例如[32, 20, 64])。
  • 提取后形状:[batch, hidden_size](例如[32, 64])。
  • 为什么只取最后一个时间步?因为我们的任务是预测序列的下一个值,最后一个时间步的隐藏状态包含了整个序列的信息。
4. 通过全连接层生成预测
out = self.fc(out)  # 将64维隐藏状态映射到1维输出

  • 最终输出形状:[batch, output_size](本例中为[32, 1])。

三、用具体例子理解数据流动

假设:

  • 批量大小batch_size=2(同时处理 2 个序列)。
  • 序列长度seq_length=3(每个序列有 3 个时间步)。
  • 输入维度input_size=1(每个时间步 1 个特征)。
  • 隐藏维度hidden_size=2(简化计算)。
1. 输入 x 的形状
x.shape = [2, 3, 1]
# 示例数据:
x = [[[0.1], [0.2], [0.3]],  # 第1个序列[[0.4], [0.5], [0.6]]   # 第2个序列
]
2. 初始隐藏状态 h0 的形状

h0.shape = [1, 2, 2]  # [层数, 批量, 隐藏维度]
# 初始化为全零:
h0 = [[[0, 0], [0, 0]]  # 第1层(唯一层)的两个批量的初始隐藏状态
]
3. RNN 计算过程(简化版)

对第 1 个序列的第 1 个时间步x[0, 0] = [0.1]

h_1 = tanh(W_hx * [0.1] + W_hh * [0, 0] + b_h)
# 假设W_hx = [[0.5], [0.3]], W_hh = [[0.2, 0.1], [0.4, 0.3]]
h_1 = tanh([0.5*0.1 + 0.2*0 + 0.1*0, 0.3*0.1 + 0.4*0 + 0.3*0])= tanh([0.05, 0.03])≈ [0.05, 0.03]  # 经过tanh激活后的结果

类似地,计算后续时间步和其他序列,最终得到:

out.shape = [2, 3, 2]
out = [[[0.05, 0.03], [0.12, 0.08], [0.20, 0.15]],  # 第1个序列的3个时间步[[0.25, 0.18], [0.35, 0.25], [0.45, 0.32]]   # 第2个序列的3个时间步
]
4. 提取最后时间步并通过全连接层

out[:, -1, :] = [[0.20, 0.15], [0.45, 0.32]]  # 形状:[2, 2]# 假设全连接层权重W_fc = [[0.6], [0.7]],偏置b_fc = [0.1]
final_output = [[0.20*0.6 + 0.15*0.7 + 0.1], [0.45*0.6 + 0.32*0.7 + 0.1]]≈ [[0.295], [0.584]]  # 形状:[2, 1]

四、关键概念总结

  1. 隐藏状态

    • RNN 的核心是隐藏状态h_t,它整合了当前输入和历史信息。
    • 每个时间步的计算都依赖上一步的隐藏状态,形成 “记忆链”。
  2. 权重共享

    • W_hxW_hh在所有时间步中保持不变,减少了参数量。
  3. 输入输出形状

    • 输入:[batch, seq_len, input_size]
    • 输出:[batch, seq_len, hidden_size](所有时间步)或[batch, hidden_size](最后时间步)。
  4. 序列建模能力

    • 通过隐藏状态的传递,RNN 能捕捉序列中的时序依赖关系(如正弦波的周期性)。

3. 前向传播与隐藏状态传递

def forward(self, x):h0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(x.device)out, hn = self.rnn(x, h0)out = out[:, -1, :]  # 取最后一个时间步的输出

  • 概念对应
    • 初始隐藏状态(h0):序列开始时的记忆(全零向量)。
    • 隐藏状态更新

      h_t = tanh(W_hx * x_t + W_hh * h_{t-1})
      

      每个时间步的隐藏状态h_t整合当前输入x_t和上一步记忆h_{t-1}
    • 输出形状out是所有时间步的隐藏状态,形状为[batch, seq_len, hidden_size]
    • 最终输出:只取最后一个时间步的隐藏状态(out[:, -1, :]),用于预测下一个值。

4. 批处理与并行计算

train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)

  • 概念对应
    • 批处理(batch):每次训练同时处理 32 个序列,加速计算。
    • 输入形状[batch_size, seq_length, input_size] = [32, 20, 1]
    • 并行计算:GPU 同时处理 32 个序列的前向 / 反向传播。

5. 训练过程与损失函数

criterion = nn.MSELoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)for epoch in range(epochs):for X_batch, y_batch in train_loader:outputs = model(X_batch)loss = criterion(outputs, y_batch)  # 计算预测值与真实值的MSEoptimizer.zero_grad()loss.backward()  # 反向传播计算梯度optimizer.step()  # 更新参数

  • 概念对应
    • 损失函数(MSE)

      Loss = 1/N * Σ(y_pred - y_true)²
      

      衡量预测值与真实值的差异。
    • 反向传播:通过链式法则计算每个参数的梯度(如dLoss/dW_hh)。
    • 梯度消失:标准 RNN 在长序列中梯度会指数衰减(这里序列较短,问题不明显)。

6. 长距离依赖的挑战

# 序列长度seq_length=20,RNN可较好处理
# 若seq_length很大(如100),标准RNN性能会下降

  • 概念对应
    • 梯度消失 / 爆炸:RNN 通过tanh激活函数传递梯度,当序列很长时,梯度会趋近于 0 或无穷大。
    • 改进方案:LSTM/GRU 通过门控机制解决这一问题(后续可尝试替换nn.RNNnn.LSTM)。

7. 预测与可视化

plt.plot(targets, label='True Values')
plt.plot(predictions, label='Predictions')

  • 概念对应
    • 预测能力:模型学习到正弦波的周期性,能用前 20 个点预测下一个点。
    • 泛化验证:测试集上的预测效果验证模型是否真正理解序列规律。

8.完整代码

import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset
import numpy as np
import matplotlib.pyplot as plt# --------------训练 RNN 预测下一个时间步的值------------#
# 设置随机种子以确保结果可复现
torch.manual_seed(42)
np.random.seed(42)# 设置设备
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
print(f'Using device: {device}')# 生成简单的时序数据用于演示
n_samples = 1000
seq_length = 20
time = np.linspace(0, 2 * np.pi * n_samples / 10, n_samples + seq_length)
data = np.sin(time)
X = []
y = []
for i in range(n_samples):X.append(data[i:i + seq_length])y.append(data[i + seq_length])
X = np.array(X)
y = np.array(y)# 转换为PyTorch张量
X = torch.FloatTensor(X).view(n_samples, seq_length, 1)  # [batch, seq_len, feature_dim]
y = torch.FloatTensor(y).view(n_samples, 1)  # [batch, output_dim]# 划分训练集和测试集
train_size = int(0.8 * n_samples)
train_X, test_X = X[:train_size], X[train_size:]
train_y, test_y = y[:train_size], y[train_size:]# 创建数据加载器
batch_size = 32
train_dataset = TensorDataset(train_X, train_y)
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)test_dataset = TensorDataset(test_X, test_y)
test_loader = DataLoader(test_dataset, batch_size=batch_size)# 定义RNN模型
class SimpleRNN(nn.Module):def __init__(self, input_size, hidden_size, output_size, num_layers=1):super(SimpleRNN, self).__init__()self.hidden_size = hidden_sizeself.num_layers = num_layers# PyTorch内置的RNN层# batch_first=True表示输入的形状为[batch, seq_len, feature_dim]self.rnn = nn.RNN(input_size, hidden_size, num_layers, batch_first=True, nonlinearity='tanh')# 全连接层:将RNN的输出映射到预测值self.fc = nn.Linear(hidden_size, output_size)def forward(self, x):# 初始化隐藏状态# 形状为[num_layers, batch_size, hidden_size]h0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(x.device)# 前向传播RNN# out形状为[batch_size, seq_len, hidden_size]# hn形状为[num_layers, batch_size, hidden_size]out, hn = self.rnn(x, h0)# 我们只需要最后一个时间步的输出# 形状变为[batch_size, hidden_size]out = out[:, -1, :]# 通过全连接层得到预测值# 形状变为[batch_size, output_size]out = self.fc(out)return out# 模型参数
input_size = 1  # 输入特征维度(每个时间步的特征数)
hidden_size = 64  # 隐藏层维度
output_size = 1  # 输出维度(预测值的维度)
num_layers = 1  # RNN层数# 初始化模型
model = SimpleRNN(input_size, hidden_size, output_size, num_layers).to(device)# 定义损失函数和优化器
criterion = nn.MSELoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)# 训练模型
epochs = 50
train_losses = []print("开始训练模型...")
for epoch in range(epochs):total_loss = 0for X_batch, y_batch in train_loader:X_batch, y_batch = X_batch.to(device), y_batch.to(device)# 前向传播outputs = model(X_batch)loss = criterion(outputs, y_batch)# 反向传播和优化optimizer.zero_grad()loss.backward()optimizer.step()total_loss += loss.item()# 计算平均损失avg_loss = total_loss / len(train_loader)train_losses.append(avg_loss)if (epoch + 1) % 10 == 0:print(f'Epoch [{epoch + 1}/{epochs}], Loss: {avg_loss:.4f}')# 评估模型
model.eval()
predictions = []
targets = []with torch.no_grad():for X_batch, y_batch in test_loader:X_batch, y_batch = X_batch.to(device), y_batch.to(device)# 前向传播outputs = model(X_batch)predictions.extend(outputs.cpu().numpy())targets.extend(y_batch.cpu().numpy())predictions = np.array(predictions)
targets = np.array(targets)# 可视化结果
plt.figure(figsize=(12, 5))plt.subplot(1, 2, 1)
plt.plot(train_losses)
plt.title('Training Loss')
plt.xlabel('Epoch')
plt.ylabel('Loss')plt.subplot(1, 2, 2)
plt.plot(targets, label='True Values')
plt.plot(predictions, label='Predictions')
plt.title('Time Series Prediction')
plt.xlabel('Time Step')
plt.ylabel('Value')
plt.legend()plt.tight_layout()
plt.show()# 保存模型
torch.save(model.state_dict(), '1-0-rnn_model.pth')
print('Model saved as rnn_model.pth')

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

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

相关文章

深度学习常见名词解释、评价指标

目录 一、鲁棒性(robustness) 二、泛化能力(Generalization Ability) 核心含义: 如何衡量泛化能力? 三、先验信息(Prior Information) 四、mIoU (Mean Intersection over Union&#xff0…

docker-compose安装常用中间件

分为3大部分:数据库:mysql,redis,mongodb,elasticsearch,neo4j,minio,influxdb,canal-server应用中间件:nacos,apollo,zookeeper&…

基于无人机 RTK 和 yolov8 的目标定位算法

目录 背景 算法思路 代码实现 验证 背景 在城市交通巡检中如何进行车辆违停判断很重要,一个方法是通过精确坐标判断车辆中心是否位于违停框中,我们假设无人机坐标已知,并且无人机云台镜头垂直地面朝下,可根据图像分辨率、无人机参…

go入门 - day1 - 环境搭建

0. 介绍 go语言可以做什么? a. 区块链 b. 分布式/微服务/云原生 c. 服务器/游戏软件go的优势 a. 代码量比C和Java少 b. 编译速度比Java或者C快上5到6倍,比Scale块10被 c. 性能比C慢20%,但是比Java、python等快上5到10倍 d. 内存管理和C媲美&a…

【华为OD】MVP争夺战(C++、Java、Python)

文章目录题目描述输入描述输出描述示例解题思路算法思路核心步骤代码实现C实现Java实现Python实现算法要点复杂度分析解题总结题目描述 在星球争霸篮球赛对抗赛中,最大的宇宙战队希望每个人都能拿到MVP,MVP的条件是单场最高分得分获得者。可以并列所以宇…

Datawhale 2025 AI夏令营 MCP Server Task2

魔搭MCP &Agent赛事(MCP Server开发)/夏令营:动手开发MCP Server学习链接:魔搭MCP &Agent赛事(MCP Server开发) - Datawhale Task1回顾 1.task1应用功能 luner_info每日黄历 这是一个可以获取某天…

敏捷开发方法全景解析

核心理念:敏捷开发是以快速响应变化为核心的项目管理方法论,通过迭代式交付、自组织团队和持续反馈,实现高质量软件的高效交付。其本质是拥抱变化优于遵循计划,强调"可工作的软件高于详尽的文档"。 一、敏捷核心思想体系 #mermaid-svg-y7iyWsQGVWn3IpEi {font-fa…

Socket到底是什么(简单来说)

简单来说: Socket 抽象了网络通信的复杂底层细节,让应用程序开发者可以专注于发送和接收数据,而不用去操心数据在网络上是如何传输的。 它就像一个“黑盒子”,你只需要把数据扔进去,或者从里面取数据,至于数…

linux系统mysql性能优化

1、系统最大打开文件描述符数查看限制 ulimit -n更改配置 # 第一步 sudo vim /etc/security/limits.conf* soft nofile 1048576 * hard nofile 1048576# 第二步 sudo vim /etc/sysctl.conffs.file-max 1048576# 第三步(重启系统) sudo reboot验证生效 u…

免费的需要尝试claude code的API安利,截至今天可用(7月13号)

安装方法放最后(很简单,但是你得搞定网络) 注册如下: 链接如下(有详细说明): 🚀 AnyRouter|Claude Code 免费共享平台 安装(windows用户特殊点&#xff0…

Java 属性配置文件读取方法详解

Java 属性配置文件读取方法详解 一、配置文件基础概念 1. 配置文件类型对比类型格式优点缺点适用场景Propertieskeyvalue简单易读,Java原生支持不支持层级结构简单配置,JDBC参数XML标签层级结构结构化强,支持复杂数据类型冗余,解析…

NW728NW733美光固态闪存NW745NW746

美光NW系列固态闪存深度解析:NW728、NW733、NW745与NW746的全方位评测技术架构与核心创新美光NW系列固态闪存(包括NW728、NW733、NW745、NW746)的技术根基源于其先进的G9 NAND架构。该架构通过5纳米制程工艺和多层3D堆叠技术,在单…

【面试八股文】2025最新软件测试面试

一、测试基础 1、测试策略或测试包括哪些,测试要覆盖哪些方面 UI、功能、性能、可靠性、易用性、兼容性、安全性、安装卸载 2、设计测试用例的办法 等价类、边界值、错误推测法、场景法等设计方法来编写测试用例的 (1)等价类分为有效等价…

AI软件出海SEO教程

一、出海SEO核心思路 本地化:内容、技术、用户体验全面适应目标市场。关键词策略:围绕目标用户的真实搜索习惯做关键词挖掘和布局。内容为王:持续输出高质量、解决用户痛点的内容。技术优化:保证网站速度、结构、移动端体验及安全…

PyVision:基于动态工具的具身智能体

论文地址: [2507.07998v1] PyVision: Agentic Vision with Dynamic Tooling 1. 背景 现有的智能体一般都是通过大模型规划调用已经预定义好的一些工具(具体来说也就是一些函数)来解决问题。这样就会导致在针对特征的任务上Agent去解决问题…

Higress 上架 KubeSphere Marketplace,助力企业构建云原生流量入口

随着企业数字化转型持续深化,云原生架构正逐渐成为构建现代应用的主流选择。而服务治理作为云原生落地的核心能力之一,急需更灵活、高效的解决方案。近日,AI 原生的 API 网关 Higress 正式上架 KubeSphere Marketplace,助力用户轻…

在LC480T上部署xapp1052

实验环境:LC480T加速卡 开发环境:windows11vivado2020 运行环境:ubuntu22.04 硬件电路:LC480T加速卡(xc7k480tffg1156-2) vivado工程文件下载:https://download.csdn.net/download/xiaolangyangyang/91349686 驱动及应…

TCP的socket编程

TCP客户端逻辑void Usage(const std::string & process) {std::cout << "Usage: " << process << " server_ip server_port" <<std::endl; } // ./tcp_client serverip serverport int main(int argc, char * argv[]) {if (ar…

【理念●体系】模板规范篇:打造可标准化复用的 AI 项目骨架

【理念●体系】从零打造 Windows WSL Docker Anaconda PyCharm 的 AI 全链路开发体系-CSDN博客 【理念●体系】Windows AI 开发环境搭建实录&#xff1a;六层架构的逐步实现与路径治理指南-CSDN博客 【理念●体系】路径治理篇&#xff1a;打造可控、可迁移、可复现的 AI 开…

Skia---渐变色着色器

今天介绍的是实际工作中最常用到的着色器&#xff1a;渐变色着色器。 渐变色着色器是一个从一种颜色平滑的过渡到另一种颜色的效果&#xff0c;渐变色着色器的作用主要是增强图形的视觉吸引力。 线性渐变 Skia 里的线性渐变色着色器是最简单的渐变色着色器&#xff0c;它用于…