循环神经网络(RNN)是一种专门用于处理序列数据的神经网络架构。与处理空间数据的卷积神经网络(Conv2D)不同,RNN通过引入循环连接使网络具有"记忆"能力,能够利用之前的信息来影响当前的输出,非常适合处理音频波形、频谱。

一、RNN介绍

1.1 结构

  • 输入层:序列数据,通常为形状为(batch_size, seq_len, input_size)的张量
示例:音频频谱处理:将音频转换为频谱图后,seq_len对应时间帧数,input_size对应每个时间帧的频率维度(如梅尔频带数),梅尔频谱图特征形状为 (batch_size, 128, 100) 表示:
-128个时间帧(seq_len=128-每个时间帧有100个梅尔频带特征(input_size=100)原始波形处理:直接处理音频波形时,seq_len对应采样点数,input_size对应特征维度(如单声道为1,立体声为2),16kHz音频的2秒片段形状为 (batch_size, 32000, 1) 表示:
-32000个采样点(seq_len=32000-单声道音频(input_size=1
  • RNN层

    • 循环单元:包含一个或多个RNN单元,每个单元包含以下可学习参数:
      • 输入到隐藏的权重WxhW_{xh}Wxh,形状:(hidden_size, input_size)
      • 隐藏到隐藏的权重WhhW_{hh}Whh,形状:(hidden_size, hidden_size)
      • 偏置bhb_hbh,形状:(hidden_size,)
    • 隐藏状态hth_tht,形状:(batch_size, hidden_size):存储网络的状态信息,在时间步之间传递
  • 激活函数

    • 隐藏层激活:通常使用TanhReLUtanh将输出压缩到[-1,1]范围,有助于缓解梯度爆炸;ReLU计算高效,但可能导致梯度消失。
    • 输出层激活:根据任务选择(Softmax用于分类,线性激活用于回归)

1.2 参数

  • input_size:每个时间步输入的特征数量。对于音频频谱,通常是频率维度(如梅尔频带数)
  • hidden_size:隐藏状态的维度,决定RNN的记忆容量和表征能力
  • num_layers:堆叠的RNN层数,增加层数可提高模型复杂度但也会增加计算量
  • nonlinearity:激活函数选择,Tanh适合大多数情况,RELU在某些场景可能表现更好
  • bias:是否在计算中添加可学习的偏置项
  • batch_first:输入张量的维度顺序。True: (batch, seq, feature)False: (seq, batch, feature)
  • dropout:在多层RNN中应用dropout防止过拟合,0表示不使用dropout
  • bidirectional:是否使用双向RNN,True时会同时考虑前向和后向序列信息

1.3 输入输出维度

  • 输入数据维度(batch_size, seq_len, input_size)(当 batch_first=True 时)
  • 输出序列维度(batch_size, seq_len, hidden_size * num_directions)(当 batch_first=True 时)
  • 最终隐藏状态(num_layers * num_directions, batch_size, hidden_size)

1.4 计算过程

ht=tanh⁡(Wxh×xt+Whh×ht−1+bh)h_t = \tanh(W_{xh} \times x_t + W_{hh} \times h_{t-1} + b_h)ht=tanh(Wxh×xt+Whh×ht1+bh)

其中:

  • hth_tht:当前时间步的隐藏状态(也是该时间步的输出)
  • ht−1h_{t-1}ht1:上一时间步的隐藏状态
  • xtx_txt:当前时间步的输入
  • WxhW_{xh}Wxh:输入到隐藏的权重矩阵
  • WhhW_{hh}Whh:隐藏到隐藏的权重矩阵
  • bhb_hbh:偏置项
  • tanh⁡\tanhtanh:激活函数

对于多层RNN(num_layers > 1):
ht(l)=tanh⁡(Wxh(l)ht(l−1)+Whh(l)ht−1(l)+bh(l))h_t^{(l)} = \tanh(W_{xh}^{(l)} h_t^{(l-1)} + W_{hh}^{(l)} h_{t-1}^{(l)} + b_h^{(l)})ht(l)=tanh(Wxh(l)ht(l1)+Whh(l)ht1(l)+bh(l))

其中
ht(0)=xth_t^{(0)} = x_tht(0)=xt

1.5 计算过程可视化

import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from matplotlib.patches import Circle, Arrow# 创建画布
fig, ax = plt.subplots(figsize=(12, 6))
ax.set_xlim(0, 10)
ax.set_ylim(0, 5)
ax.axis('off')
plt.title('RNN Computation Process', fontsize=16, pad=20)# 颜色定义
input_color = '#FFD700'  # 金色
hidden_color = '#1E90FF'  # 道奇蓝
active_color = '#FF4500'  # 橙红色
arrow_color = '#8B0000'  # 深红色# 初始化节点
time_steps = 3
input_nodes = []
hidden_nodes = []
input_texts = []
hidden_texts = []# 初始隐藏状态
h_init = Circle((0.5, 2.5), 0.3, facecolor='lightgray', edgecolor='black')
ax.add_patch(h_init)
ax.text(0.5, 2.5, 'h_{-1}', ha='center', va='center', fontsize=10)# 创建节点
for t in range(time_steps):# 输入节点input_circle = Circle((2.5 + t * 2.5, 4), 0.3, facecolor=input_color, edgecolor='black', alpha=0.7)ax.add_patch(input_circle)input_nodes.append(input_circle)input_text = ax.text(2.5 + t * 2.5, 4, f'x_{t}', ha='center', va='center', fontsize=10)input_texts.append(input_text)# 隐藏状态节点hidden_circle = Circle((2.5 + t * 2.5, 2.5), 0.3, facecolor=hidden_color, edgecolor='black', alpha=0.7)ax.add_patch(hidden_circle)hidden_nodes.append(hidden_circle)hidden_text = ax.text(2.5 + t * 2.5, 2.5, f'h_{t}', ha='center', va='center', fontsize=10)hidden_texts.append(hidden_text)# 时间步标签ax.text(2.5 + t * 2.5, 4.8, f'Time Step {t}', ha='center', fontsize=10)# 绘制连接线
arrows = []
arrow_labels = []# 输入到隐藏的连接
for t in range(time_steps):arrow = Arrow(2.5 + t * 2.5, 3.7, 0, -0.9, width=0.1, color='gray', alpha=0.3)ax.add_patch(arrow)arrows.append(arrow)label = ax.text(2.7 + t * 2.5, 3.2, '$W_{xh}$', fontsize=10, alpha=0.3)arrow_labels.append(label)# 隐藏到隐藏的连接
for t in range(time_steps):if t == 0:# 初始隐藏状态到第一个隐藏状态arrow = Arrow(0.8, 2.5, 1.5, 0, width=0.1, color='gray', alpha=0.3)ax.add_patch(arrow)arrows.append(arrow)label = ax.text(1.5, 2.7, '$W_{hh}$', fontsize=10, alpha=0.3)arrow_labels.append(label)else:# 隐藏状态之间的连接arrow = Arrow(2.5 + (t - 1) * 2.5, 2.5, 2.5, 0, width=0.1, color='gray', alpha=0.3)ax.add_patch(arrow)arrows.append(arrow)label = ax.text(2.5 + (t - 1) * 2.5 + 1.25, 2.7, '$W_{hh}$', fontsize=10, alpha=0.3)arrow_labels.append(label)# 添加公式
formula_text = ax.text(5, 1, '', fontsize=14, ha='center')# 动画更新函数
def update(frame):# 重置所有颜色for node in input_nodes + hidden_nodes:node.set_alpha(0.7)if node.get_facecolor() != active_color:node.set_facecolor(input_color if node in input_nodes else hidden_color)for arrow in arrows:arrow.set_alpha(0.3)arrow.set_color('gray')for label in arrow_labels:label.set_alpha(0.3)# 根据帧数更新if frame == 0:# 初始状态formula_text.set_text('Initialization: $h_{-1} = 0$')h_init.set_facecolor(active_color)h_init.set_alpha(1.0)elif frame <= time_steps:t = frame - 1# 激活当前输入input_nodes[t].set_facecolor(active_color)input_nodes[t].set_alpha(1.0)# 激活输入到隐藏的连接arrows[t].set_alpha(1.0)arrows[t].set_color(arrow_color)arrow_labels[t].set_alpha(1.0)# 激活隐藏状态hidden_nodes[t].set_facecolor(active_color)hidden_nodes[t].set_alpha(1.0)# 激活隐藏到隐藏的连接if t == 0:arrows[time_steps].set_alpha(1.0)arrows[time_steps].set_color(arrow_color)arrow_labels[time_steps].set_alpha(1.0)else:arrows[time_steps + t].set_alpha(1.0)arrows[time_steps + t].set_color(arrow_color)arrow_labels[time_steps + t].set_alpha(1.0)# 显示公式formula_text.set_text(f'Compute $h_{t}$: $h_{t} = \\tanh(W_{{xh}} x_{t} + W_{{hh}} h_{t - 1} + b_h)$')return input_nodes + hidden_nodes + arrows + arrow_labels + [formula_text, h_init]# 创建动画
animation = FuncAnimation(fig, update, frames=range(time_steps + 1),interval=1500, blit=True)plt.tight_layout()
animation.save('rnn_core_animation.gif', writer='pillow', fps=1, dpi=100)
plt.show()

在这里插入图片描述

二、代码示例

通过两层RNN处理一段音频频谱,打印每层的输出形状、参数形状,并可视化特征图。

import torch
import torch.nn as nn
import matplotlib.pyplot as plt
import librosa
import numpy as np# 定义 RNN 模型
class RNNModel(nn.Module):def __init__(self, input_size):super(RNNModel, self).__init__()self.rnn1 = nn.RNN(input_size, 128, batch_first=True)self.rnn2 = nn.RNN(128, 64, batch_first=True)def forward(self, x):h_out1, _ = self.rnn1(x)h_out2, _ = self.rnn2(h_out1)return h_out1, h_out2  # 返回两层的输出# 读取音频文件并处理
file_path = 'test.wav'
waveform, sample_rate = librosa.load(file_path, sr=16000, mono=True)# 选取 3 秒的数据
start_sample = int(1.5 * sample_rate)
end_sample = int(4.5 * sample_rate)
audio_segment = waveform[start_sample:end_sample]# 转换为频谱
n_fft = 512
hop_length = 256
spectrogram = librosa.stft(audio_segment, n_fft=n_fft, hop_length=hop_length)
spectrogram_db = librosa.amplitude_to_db(np.abs(spectrogram))
spectrogram_tensor = torch.tensor(spectrogram_db, dtype=torch.float32).unsqueeze(0)
spectrogram_tensor = spectrogram_tensor.permute(0, 2, 1)  # 调整为 (batch_size, seq_len, input_size)
print(f"Spectrogram tensor shape: {spectrogram_tensor.shape}")# 创建 RNN 模型实例
input_size = spectrogram_tensor.shape[2]
model = RNNModel(input_size)# 前向传播
rnn_output1, rnn_output2 = model(spectrogram_tensor)
print(f"RNN Layer 1 output shape: {rnn_output1.shape}")
print(f"RNN Layer 2 output shape: {rnn_output2.shape}")# 打印每层的参数形状
print(f"RNN Layer 1 weights shape: {model.rnn1.weight_ih_l0.shape}")
print(f"RNN Layer 1 hidden weights shape: {model.rnn1.weight_hh_l0.shape}")
print(f"RNN Layer 1 bias shape: {model.rnn1.bias_ih_l0.shape}")print(f"RNN Layer 2 weights shape: {model.rnn2.weight_ih_l0.shape}")
print(f"RNN Layer 2 hidden weights shape: {model.rnn2.weight_hh_l0.shape}")
print(f"RNN Layer 2 bias shape: {model.rnn2.bias_ih_l0.shape}")# 可视化原始频谱
plt.figure(figsize=(10, 4))
plt.imshow(spectrogram_db, aspect='auto', origin='lower', cmap='inferno')
plt.title("Original Spectrogram")
plt.xlabel("Time Frames")
plt.ylabel("Frequency Bins")
plt.colorbar(format='%+2.0f dB')
plt.tight_layout()# 可视化 RNN 输出的特征图
plt.figure(figsize=(10, 4))# 绘制第一层 RNN 输出的特征图
plt.subplot(2, 1, 1)
plt.imshow(rnn_output1[0].detach().numpy().T, aspect='auto', origin='lower', cmap='inferno')  # 转置
plt.title("RNN Layer 1 Output Feature Map")
plt.xlabel("Time Steps")
plt.ylabel("Hidden State Dimensions")
plt.colorbar(label='Hidden State Value')# 绘制第二层 RNN 输出的特征图
plt.subplot(2, 1, 2)
plt.imshow(rnn_output2[0].detach().numpy().T, aspect='auto', origin='lower', cmap='inferno')  # 转置
plt.title("RNN Layer 2 Output Feature Map")
plt.xlabel("Time Steps")
plt.ylabel("Hidden State Dimensions")
plt.colorbar(label='Hidden State Value')plt.tight_layout()
plt.show()
Spectrogram tensor shape: torch.Size([1, 188, 257])
RNN Layer 1 output shape: torch.Size([1, 188, 128])
RNN Layer 2 output shape: torch.Size([1, 188, 64])
RNN Layer 1 weights shape: torch.Size([128, 257])
RNN Layer 1 hidden weights shape: torch.Size([128, 128])
RNN Layer 1 bias shape: torch.Size([128])
RNN Layer 2 weights shape: torch.Size([64, 128])
RNN Layer 2 hidden weights shape: torch.Size([64, 64])
RNN Layer 2 bias shape: torch.Size([64])

在这里插入图片描述
在这里插入图片描述

三、RNN的梯度消失与长期依赖问题

循环神经网络(RNN)在处理序列数据时面临两个核心问题:梯度消失问题和长期依赖问题。这些问题的根源在于RNN的结构和训练机制。

3.1 梯度消失问题

RNN通过时间反向传播(BPTT)算法进行训练,梯度需要沿着时间步反向传播。当序列较长时,梯度在反向传播过程中会指数级地减小或增大。

考虑RNN的计算公式:
ht=tanh⁡(Wxhxt+Whhht−1+bh)h_t = \tanh(W_{xh}x_t + W_{hh}h_{t-1} + b_h)ht=tanh(Wxhxt+Whhht1+bh)

在反向传播时,需要计算损失函数LLL对参数WhhW_{hh}Whh的梯度:
∂L∂Whh=∑t=1T∂L∂hT∂hT∂ht∂ht∂Whh\frac{\partial L}{\partial W_{hh}} = \sum_{t=1}^T \frac{\partial L}{\partial h_T} \frac{\partial h_T}{\partial h_t} \frac{\partial h_t}{\partial W_{hh}}WhhL=t=1ThTLhthTWhhht

关键项是∂hT∂ht\frac{\partial h_T}{\partial h_t}hthT,它可以通过链式法则展开:
∂hT∂ht=∏k=tT−1∂hk+1∂hk=∏k=tT−1Whh⊤⋅diag(tanh⁡′(zk))\frac{\partial h_T}{\partial h_t} = \prod_{k=t}^{T-1} \frac{\partial h_{k+1}}{\partial h_k} = \prod_{k=t}^{T-1} W_{hh}^\top \cdot \text{diag}(\tanh'(z_k))hthT=k=tT1hkhk+1=k=tT1Whhdiag(tanh(zk))

其中
zk=Wxhxk+Whhhk−1+bhz_k = W_{xh}x_k + W_{hh}h_{k-1} + b_hzk=Wxhxk+Whhhk1+bh

由于tanh⁡\tanhtanh的导数tanh⁡′(z)=1−tanh⁡2(z)\tanh'(z) = 1 - \tanh^2(z)tanh(z)=1tanh2(z)的值域为(0,1](0, 1](0,1],且WhhW_{hh}Whh通常初始化为小随机数,这个连乘积会指数级衰减:
∣∏k=tT−1∂hk+1∂hk∣≤∣Whh∣T−t⋅(max⁡tanh⁡′)T−t\left| \prod_{k=t}^{T-1} \frac{\partial h_{k+1}}{\partial h_k} \right| \leq \left| W_{hh} \right|^{T-t} \cdot (\max \tanh')^{T-t}k=tT1hkhk+1WhhTt(maxtanh)Tt
T−tT-tTt很大时,这个值趋近于0,导致早期时间步的梯度消失。

影响

  • 早期时间步的参数无法有效更新:网络难以学习长序列中早期时间步的重要信息
  • 训练过程缓慢且不稳定:梯度太小导致参数更新幅度极小
  • 模型无法捕捉长期模式:只能记住短期信息,难以学习长序列中的依赖关系

3.2 长期依赖问题

即使没有梯度消失问题,RNN也难以有效利用序列中相距较远的信息。这是因为隐藏状态的表示能力有限,信息在多次变换中逐渐"稀释"。

考虑信息从时间步t传递到时间步T的过程:
hT=f(hT−1,xT)=f(f(hT−2,xT−1),xT)=⋯=f(⋯f(ht,xt+1)⋯ ,xT)h_T = f(h_{T-1}, x_T) = f(f(h_{T-2}, x_{T-1}), x_T) = \cdots = f(\cdots f(h_t, x_{t+1}) \cdots, x_T)hT=f(hT1,xT)=f(f(hT2,xT1),xT)==f(f(ht,xt+1),xT)

每次变换fff都会对信息进行非线性转换和压缩,经过多次变换后,早期信息hth_ththTh_ThT的影响变得微弱且难以区分。

示例在语言建模中,考虑句子:"The clouds in the sky are [...] color." 要预测最后一个词"blue",需要记住开头的"clouds"信息。标准RNN很难保持这种长距离依赖。

3.3 梯度爆炸问题

与梯度消失相反,当权重矩阵WhhW_{hh}Whh的特征值大于 1 时,梯度在反向传播过程中会指数级增长。这种现象被称为梯度爆炸。

在 RNN 的反向传播过程中,梯度的计算可以表示为:
∣∏k=tT−1∂hk+1∂hk∣≤∣Whh∣T−t\left| \prod_{k=t}^{T-1} \frac{\partial h_{k+1}}{\partial h_k} \right| \leq \left| W_{hh} \right|^{T-t}k=tT1hkhk+1WhhTt

如果∥Whh∥>1\| W_{hh} \| > 1Whh>1,则梯度的范数会指数增长,导致以下问题:

  • 参数更新过大:由于梯度过大,参数更新可能会超出合理范围,导致模型无法收敛。
  • 训练不稳定:模型的训练过程可能变得不稳定,导致损失函数波动较大。
  • 可能产生 NaN 值:在极端情况下,过大的参数更新可能导致数值溢出,从而产生 NaN 值。

为了解决梯度爆炸问题,可以采取以下措施:

  • 梯度裁剪:通过限制梯度的大小,确保参数更新不会过大。常用的方法是将梯度的 L2 范数限制在一个预设的阈值之内。例如,如果梯度的范数超过阈值,则按比例缩放梯度。
    torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm)
    
  • 权重正则化:通过约束权重矩阵的范数,防止权重过大。常见的正则化方法包括 L2 正则化(权重衰减)和 L1 正则化。

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

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

相关文章

React18学习笔记(二) React的状态管理工具--Redux,案例--移动端外卖平台

文章目录一.Redux的基础用法1.示例:普通网页中的Redux计步器2.Redux管理数据的流程3.配套工具和环境准备3.1.配套工具3.2.环境准备4.示例:React项目中的Redux计步器思路步骤step1:创建子模块step2:导入子模块step3:注入store实例step4:React组件内使用store中的数据step5:在组件…

34.Socket编程(UDP)(上)

点分十进制字符串IP 转 32位网络序列IP 分析&#xff1a;1&#xff09;IP转成4字节 2&#xff09;4字节转成网络序列 思路&#xff1a; "192.168.1.1" 进行字符串划分&#xff0c;以 "." 为分割符&#xff0c;分割出"192"&#xff0c;&qu…

Redis的持久化工具包—RDB AOF

文章目录 前言 一、RDB 持久化&#xff08;快照持久化&#xff09; 1. 定义 2. RDB 触发机制 &#xff08;1&#xff09;手动触发 &#xff08;2&#xff09;自动触发 3. RDB 持久化流程 4. RDB 核心配置 5. RDB 优缺点 二、AOF 持久化&#xff08;日志持久化&#xff09; 1. 定…

【Web安全】XXL-JOB框架SRC高频漏洞分析总结

文章目录前言一、核心漏洞分类与技术细节二、漏洞关联利用与攻击路径三、版本演进与修复策略四、安全运维建议五、典型漏洞复现环境搭建六、总结前言 XXL-JOB是国内主流的开源分布式任务调度框架&#xff0c;由徐雪里开发维护&#xff0c;以轻量易用、高可用、适配分布式场景等…

Capacitor 打包后接口访问不到的排查经历

我最近在用 Quasar Capacitor 6 做一个 Android App&#xff0c;前端用的是 Vue3 Quasar&#xff0c;打包交给 Capacitor 去跑在手机的 WebView 里&#xff0c;后端是 FastAPI 提供接口。开发模式下一切顺利&#xff0c;浏览器里访问接口没有任何问题&#xff0c;我甚至觉得打…

【正点原子】Linux应用编程入门~概念及环境介绍

应用编程概念 应用编程&#xff08;也可称为系统编程&#xff09;与驱动编程、裸机编程有何不同&#xff1f;系统调用&#xff1b;何为库函数&#xff1b;应用程序的 main()函数&#xff1b;应用程序开发环境的介绍&#xff1b;系统调用 定义系统调用&#xff08;system call&a…

一、HTML 完全指南:从零开始构建网页

文章目录前言一、 HTML 结构认识 HTML 标签HTML 文件基本结构标签层次结构快速生成代码框架二、 HTML 常见标签详解2.1 注释标签2.2 标题标签 (h1 - h6)2.3 段落标签 (p)2.4 换行标签 (br)2.5 格式化标签2.6 图片标签 (img)2.7 超链接标签 (a)2.8 表格标签基本使用合并单元格2.…

基于POI-TL实现动态Word模板的数据填充:【散点图】特殊处理方案

基于POI-TL实现动态Word模板的数据填充:散点图特殊处理方案 在使用POI-TL进行Word模板动态数据填充时,图表生成是一个常见需求。最近在项目中使用POI-TL处理散点图时遇到了一个特殊问题,经过研究后找到了解决方案,特此记录分享。 问题背景 POI-TL作为一款优秀的Java Wor…

使用node-Express框架写一个学校宿舍管理系统练习项目-前后端分离

今天继续分享一个新的练习项目&#xff0c;是使用node做为后端语言&#xff0c;来写的一个前后端分离项目&#xff1a;学校宿舍管理系统。我们如果想掌握一门编程语言&#xff0c;就是需要大量的练习。所以当我们学习到了一些知识&#xff0c;自己想一下 可以拿学到的知识&…

Kafka 运维实战基本操作含命令与最佳实践

1. 基础概览与工具入口 Kafka 发行包的所有 CLI 工具均在 bin/ 目录下。任何工具不带参数运行都会显示所有可用选项。本文命令默认&#xff1a;--bootstrap-server localhost:9092&#xff1b;生产请替换为你的控制面或内网 VIP。 2. 主题管理&#xff08;创建 / 修改 / 删除 /…

贪心算法应用:航班起降问题详解

Java中的贪心算法应用&#xff1a;航班起降问题详解 贪心算法是一种在每一步选择中都采取当前状态下最优的选择&#xff0c;从而希望导致全局最优解的算法策略。在航班起降问题中&#xff0c;贪心算法可以有效地解决机场跑道调度问题&#xff0c;即如何安排航班的起降顺序以最大…

uniapp scroll-view 设置scrollTop无效

当我们使用 scroll-view的scroll-top的时候 默认想让它回到顶部&#xff0c;当我们设置值为0的时候会不生效&#xff0c;在实际运用过程中&#xff0c;发现设置了scroll-top无效&#xff0c;滚动条位置并没有发生变化&#xff0c;是因为微信小程序的官方框架处于性能考虑&#…

网络与通信

1.TCP协议与UDP协议TCP&#xff08;Transmission Control Protocol&#xff0c;传输控制协议&#xff09;和 UDP&#xff08;User Datagram Protocol&#xff0c;用户数据报协议&#xff09;是 TCP/IP 协议族中两种核心的传输层协议&#xff0c;它们在数据传输方式、可靠性、适…

Node.js中package.json详解

1. name&#xff08;名称&#xff09; 如果你计划发布你的包&#xff0c;package.json 中最重要的字段是 name 和 version&#xff0c;因为它们是必需的。name 和 version 共同组成一个假定完全唯一的标识符。包的更改应伴随版本号的更新。如果你不打算发布包&#xff0c;那么…

代码随想录第14天| 翻转、对称与深度

226.翻转二叉树 &#xff08;优先掌握递归&#xff09; 题目链接/文章讲解/视频讲解&#xff1a;翻转二叉树 交换的是指针&#xff0c;而不是数值&#xff0c;如果用数值做交换&#xff0c;需要交换的节点下面无法很好的操作。 使用递归来实现&#xff0c;但要提前清除是什么顺…

DNS-Windows上使用DNS

DNS-Windows上使用DNS一、查看与修改DNS配置1.1、查看当前DNS服务器设置1.2、临时修改 DNS 服务器&#xff08;命令行&#xff09;二、DNS缓存相关操作2.1、查看DNS缓存内容2.2、 刷新 DNS 缓存&#xff08;清除过期记录&#xff09;三、测试域名解析&#xff08;nslookup 工具…

3dsMax 2026 .NET Core 8 转型下的Maxscript脚本开发:动态编译模块的重构策略与兼容性升级路径

3ds Max 长期以来一直提供出色的 .NET 集成,使 Maxscript 能够无缝利用任何 .NET 库的强大功能。部分开发者在工具中广泛使用了 .NET 功能。 之前,3ds Max 依赖于 .NET Framework 4.8 并且最近更新到了 4.8.1,用于 2025 版本的发布。然而,随着 3ds Max 2026 的推出,Autod…

golang 做webrtc开发核心

在Golang中进行WebRTC开发&#xff0c;核心在于理解WebRTC协议的工作原理以及如何利用Go生态中的库来实现关键功能。以下是Golang WebRTC开发的核心要点&#xff1a; WebRTC基础概念 了解ICE&#xff08;Interactive Connectivity Establishment&#xff09;协议用于NAT穿越掌握…

RabbitMQ 异步化抗洪实战

说明&#xff1a;本文仅展示架构思路与安全片段&#xff0c;所有敏感字段已用占位符&#xff1b;不含可直接复刻的生产细节。数据与接口均为演示/虚拟。0. 背景与目标长耗时/不确定接口&#xff08;如对接第三方机器人平台&#xff09;的同步阻塞&#xff0c;容易造成请求堆积与…

接口返回 2 万条数据,easy-trans导致多了20s耗时排查过程

内网访问排版核料详情功能&#xff0c;用户反馈要等十几秒排查 sql&#xff1a;sql 比较简单排查内存计算&#xff1a;arthus trace 类名 方法名 总耗时2s排查页面渲染是否缓慢&#xff1a;F12 查看接口 等待服务器响应 20s 下载时间 30s, 故不考虑渲染问题排查请求响应日志打…