Attention显存统计与分析
Attention显存估计
简单的Attention函数
import torch
import torch.nn as nn
import einops
class Attention(nn.Module):def __init__(self, dim, num_heads=8, qkv_bias=False, qk_scale=None, attn_drop=0., proj_drop=0.):super().__init__()self.num_heads = num_headshead_dim = dim // num_headsself.scale = qk_scale or head_dim ** -0.5self.qkv = nn.Linear(dim, dim * 3, bias=qkv_bias)self.attn_drop = nn.Dropout(attn_drop)self.proj = nn.Linear(dim, dim)self.proj_drop = nn.Dropout(proj_drop)def forward(self, x):B, L, C = x.shapeqkv = self.qkv(x)if ATTENTION_MODE == 'flash':qkv = einops.rearrange(qkv, 'B L (K H D) -> K B H L D', K=3, H=self.num_heads).float()q, k, v = qkv[0], qkv[1], qkv[2] # B H L Dx = torch.nn.functional.scaled_dot_product_attention(q, k, v)x = einops.rearrange(x, 'B H L D -> B L (H D)')elif ATTENTION_MODE == 'xformers':qkv = einops.rearrange(qkv, 'B L (K H D) -> K B L H D', K=3, H=self.num_heads)q, k, v = qkv[0], qkv[1], qkv[2] # B L H Dx = xformers.ops.memory_efficient_attention(q, k, v)x = einops.rearrange(x, 'B L H D -> B L (H D)', H=self.num_heads)elif ATTENTION_MODE == 'math':qkv = einops.rearrange(qkv, 'B L (K H D) -> K B H L D', K=3, H=self.num_heads)q, k, v = qkv[0], qkv[1], qkv[2] # B H L Dattn = (q @ k.transpose(-2, -1)) * self.scaleattn = attn.softmax(dim=-1)attn = self.attn_drop(attn)x = (attn @ v).transpose(1, 2).reshape(B, L, C)else:raise NotImplementedx = self.proj(x)x = self.proj_drop(x)return x
# 设置注意力模式
ATTENTION_MODE = 'math'
# 参数设置
B = 64 # batch size
L = 32 # sequence length
C = 512 # embedding dimension
H = 8 # number of heads
# 创建模型和输入张量
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
initial_memory_1 = torch.cuda.memory_allocated(device)
attention = Attention(dim=C, num_heads=H).to(device)
x = torch.randn(B, L, C).to(device)
# 监控显存使用情况
torch.cuda.reset_peak_memory_stats(device)
initial_memory = torch.cuda.memory_allocated(device)
# 使用 autograd profiler 来记录显存使用情况
with torch.autograd.profiler.profile(profile_memory=True, record_shapes=True) as prof:output = attention(x)
# 计算显存占用ru
final_memory = torch.cuda.memory_allocated(device)
max_memory = torch.cuda.max_memory_allocated(device)
# 打印结果
print(f"Initial Memory_1: {initial_memory_1 / 1024**2:.2f} MB")
print(f"Initial Memory: {initial_memory / 1024**2:.2f} MB")
print(f"Final Memory: {final_memory / 1024**2:.2f} MB")
print(f"Max Memory: {max_memory / 1024**2:.2f} MB")
print(f"Activation Memory: {(final_memory - initial_memory) / 1024**2:.2f} MB")
# 打印详细的显存使用情况
print(prof.key_averages().table(sort_by="self_cuda_memory_usage", row_limit=10))
1 模型占用的显存
两个线性层,
一个是qkv
层
self.qkv = nn.Linear(dim, dim * 3, bias=qkv_bias)
假定嵌入为C,则参数量为
C×(3×C)+(3×C)(偏置项)
一层是线性层
self.proj = nn.Linear(dim, dim)
参数为
C×C+C(偏置项)
总共是 4 ∗ C 2 + 4 ∗ C 4*C^2+4*C 4∗C2+4∗C,需要乘以FP32的字节量即4
假定 C = 512,则为 ( 4 ∗ 51 2 2 + 4 ∗ 512 ) ∗ 4 / 1024 / 1024 = 4 M B (4*512^2+4*512)*4/1024/1024=4MB (4∗5122+4∗512)∗4/1024/1024=4MB
2 前向过程产生的最大峰值
import torch
import torch.nn as nn
import einops
class Attention(nn.Module):def __init__(self, dim, num_heads=8, qkv_bias=False, qk_scale=None, attn_drop=0., proj_drop=0.):super().__init__()self.num_heads = num_headshead_dim = dim // num_headsself.scale = qk_scale or head_dim ** -0.5self.qkv = nn.Linear(dim, dim * 3, bias=qkv_bias)self.attn_drop = nn.Dropout(attn_drop)self.proj = nn.Linear(dim, dim)self.proj_drop = nn.Dropout(proj_drop)def forward(self, x):B, L, C = x.shape# 记录显存使用print(f"Before qkv: {torch.cuda.memory_allocated() / 1024**2:.2f} MB")prev_memory = torch.cuda.memory_allocated()qkv = self.qkv(x)current_memory = torch.cuda.memory_allocated()memory_change = (current_memory - prev_memory) / 1024**2print(f"After qkv: {current_memory / 1024**2:.2f} MB, Change: {memory_change:.2f} MB")prev_memory = current_memory # 更新 prev_memoryif ATTENTION_MODE == 'flash':qkv = einops.rearrange(qkv, 'B L (K H D) -> K B H L D', K=3, H=self.num_heads).float()q, k, v = qkv[0], qkv[1], qkv[2] # B H L Dcurrent_memory = torch.cuda.memory_allocated()memory_change = (current_memory - prev_memory) / 1024**2print(f"After rearrange (flash): {current_memory / 1024**2:.2f} MB, Change: {memory_change:.2f} MB")prev_memory = current_memory # 更新 prev_memoryx = torch.nn.functional.scaled_dot_product_attention(q, k, v)current_memory = torch.cuda.memory_allocated()memory_change = (current_memory - prev_memory) / 1024**2print(f"After scaled_dot_product_attention (flash): {current_memory / 1024**2:.2f} MB, Change: {memory_change:.2f} MB")prev_memory = current_memory # 更新 prev_memoryx = einops.rearrange(x, 'B H L D -> B L (H D)')current_memory = torch.cuda.memory_allocated()memory_change = (current_memory - prev_memory) / 1024**2print(f"After rearrange (flash): {current_memory / 1024**2:.2f} MB, Change: {memory_change:.2f} MB")prev_memory = current_memory # 更新 prev_memoryelif ATTENTION_MODE == 'xformers':qkv = einops.rearrange(qkv, 'B L (K H D) -> K B L H D', K=3, H=self.num_heads)q, k, v = qkv[0], qkv[1], qkv[2] # B L H Dcurrent_memory = torch.cuda.memory_allocated()memory_change = (current_memory - prev_memory) / 1024**2print(f"After rearrange (xformers): {current_memory / 1024**2:.2f} MB, Change: {memory_change:.2f} MB")prev_memory = current_memory # 更新 prev_memoryx = xformers.ops.memory_efficient_attention(q, k, v)current_memory = torch.cuda.memory_allocated()memory_change = (current_memory - prev_memory) / 1024**2print(f"After memory_efficient_attention (xformers): {current_memory / 1024**2:.2f} MB, Change: {memory_change:.2f} MB")prev_memory = current_memory # 更新 prev_memoryx = einops.rearrange(x, 'B L H D -> B L (H D)', H=self.num_heads)current_memory = torch.cuda.memory_allocated()memory_change = (current_memory - prev_memory) / 1024**2print(f"After rearrange (xformers): {current_memory / 1024**2:.2f} MB, Change: {memory_change:.2f} MB")prev_memory = current_memory # 更新 prev_memoryelif ATTENTION_MODE == 'math':qkv = einops.rearrange(qkv, 'B L (K H D) -> K B H L D', K=3, H=self.num_heads)q, k, v = qkv[0], qkv[1], qkv[2] # B H L Dcurrent_memory = torch.cuda.memory_allocated()memory_change = (current_memory - prev_memory) / 1024**2print(f"After rearrange (math): {current_memory / 1024**2:.2f} MB, Change: {memory_change:.2f} MB")prev_memory = current_memory # 更新 prev_memoryattn = (q @ k.transpose(-2, -1)) * self.scalecurrent_memory = torch.cuda.memory_allocated()memory_change = (current_memory - prev_memory) / 1024**2print(f"After matmul (math): {current_memory / 1024**2:.2f} MB, Change: {memory_change:.2f} MB")prev_memory = current_memory # 更新 prev_memoryattn = attn.softmax(dim=-1)current_memory = torch.cuda.memory_allocated()memory_change = (current_memory - prev_memory) / 1024**2print(f"After softmax (math): {current_memory / 1024**2:.2f} MB, Change: {memory_change:.2f} MB")prev_memory = current_memory # 更新 prev_memoryattn = self.attn_drop(attn)current_memory = torch.cuda.memory_allocated()memory_change = (current_memory - prev_memory) / 1024**2print(f"After dropout (math): {current_memory / 1024**2:.2f} MB, Change: {memory_change:.2f} MB")prev_memory = current_memory # 更新 prev_memoryx = (attn @ v).transpose(1, 2).reshape(B, L, C)current_memory = torch.cuda.memory_allocated()memory_change = (current_memory - prev_memory) / 1024**2print(f"After final matmul and reshape (math): {current_memory / 1024**2:.2f} MB, Change: {memory_change:.2f} MB")prev_memory = current_memory # 更新 prev_memoryelse:raise NotImplementedprint(f"Before proj: {torch.cuda.memory_allocated() / 1024**2:.2f} MB")x = self.proj(x)current_memory = torch.cuda.memory_allocated()memory_change = (current_memory - prev_memory) / 1024**2print(f"After proj: {current_memory / 1024**2:.2f} MB, Change: {memory_change:.2f} MB")prev_memory = current_memory # 更新 prev_memoryprint(f"Before proj_drop: {torch.cuda.memory_allocated() / 1024**2:.2f} MB")x = self.proj_drop(x)current_memory = torch.cuda.memory_allocated()memory_change = (current_memory - prev_memory) / 1024**2print(f"After proj_drop: {current_memory / 1024**2:.2f} MB, Change: {memory_change:.2f} MB")return x
# 设置注意力模式
ATTENTION_MODE = 'math'
# 参数设置
B = 64 # batch size
L = 32 # sequence length
C = 512 # embedding dimension
H = 8 # number of heads
# 创建模型和输入张量
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
initial_memory_1 = torch.cuda.memory_allocated(device)
attention = Attention(dim=C, num_heads=H).to(device)
x = torch.randn(B, L, C).to(device)
# 监控显存使用情况
torch.cuda.reset_peak_memory_stats(device)
initial_memory = torch.cuda.memory_allocated(device)
# 前向传播
output = attention(x)
# 计算显存占用
final_memory = torch.cuda.memory_allocated(device)
max_memory = torch.cuda.max_memory_allocated(device)
# 打印结果
print(f"Initial Memory_1: {initial_memory_1 / 1024**2:.2f} MB")
print(f"Initial Memory: {initial_memory / 1024**2:.2f} MB")
print(f"Final Memory: {final_memory / 1024**2:.2f} MB")
print(f"Max Memory: {max_memory / 1024**2:.2f} MB")
print(f"Activation Memory: {(final_memory - initial_memory) / 1024**2:.2f} MB")
结果如下显示
Before qkv: 8.00 MB
After qkv: 21.00 MB, Change: 13.00 MB
After rearrange (math): 21.00 MB, Change: 0.00 MB
After matmul (math): 31.00 MB, Change: 10.00 MB
After softmax (math): 31.00 MB, Change: 0.00 MB
After dropout (math): 31.00 MB, Change: 0.00 MB
After final matmul and reshape (math): 39.00 MB, Change: 8.00 MB
Before proj: 39.00 MB
After proj: 43.00 MB, Change: 4.00 MB
Before proj_drop: 43.00 MB
After proj_drop: 43.00 MB, Change: 0.00 MB
Initial Memory_1: 0.00 MB
Initial Memory: 8.00 MB
Final Memory: 30.00 MB
Max Memory: 44.00 MB
Activation Memory: 22.00 MB
根据打印语句进行分析
import torch
import torch.nn as nn
import einops
class Attention(nn.Module):def __init__(self, dim, num_heads=8, qkv_bias=False, qk_scale=None, attn_drop=0., proj_drop=0.):super().__init__()self.num_heads = num_headshead_dim = dim // num_headsself.scale = qk_scale or head_dim ** -0.5self.qkv = nn.Linear(dim, dim * 3, bias=qkv_bias)self.attn_drop = nn.Dropout(attn_drop)self.proj = nn.Linear(dim, dim)self.proj_drop = nn.Dropout(proj_drop)def forward(self, x):B, L, C = x.shapeqkv = self.qkv(x) # qkv矩阵,此处增加BLC*3if ATTENTION_MODE == 'flash':qkv = einops.rearrange(qkv, 'B L (K H D) -> K B H L D', K=3, H=self.num_heads).float() q, k, v = qkv[0], qkv[1], qkv[2] # B H L D x = torch.nn.functional.scaled_dot_product_attention(q, k, v)x = einops.rearrange(x, 'B H L D -> B L (H D)')elif ATTENTION_MODE == 'xformers':qkv = einops.rearrange(qkv, 'B L (K H D) -> K B L H D', K=3, H=self.num_heads)q, k, v = qkv[0], qkv[1], qkv[2] # B L H Dx = xformers.ops.memory_efficient_attention(q, k, v)x = einops.rearrange(x, 'B L H D -> B L (H D)', H=self.num_heads)elif ATTENTION_MODE == 'math':qkv = einops.rearrange(qkv, 'B L (K H D) -> K B H L D', K=3, H=self.num_heads) #不变q, k, v = qkv[0], qkv[1], qkv[2] # B H L D # 不变,索引只是切片的操作attn = (q @ k.transpose(-2, -1)) * self.scale # 此处使用q和k,需要存储中间变量,因此产生 (B,H ,L D)*2的显存,存储结果,产生(B,H,L,L)的显存attn = attn.softmax(dim=-1) #显存不变attn = self.attn_drop(attn) #显存不变x = (attn @ v).transpose(1, 2).reshape(B, L, C) # 使用到v,存储变量,产生(BHLD)的显存,存储结果,产生BLC的显存else:raise NotImplementedx = self.proj(x) # 产生BLC的显存x = self.proj_drop(x)#不变return x
# 设置注意力模式
ATTENTION_MODE = 'math'
# 参数设置
B = 64 # batch size
L = 32 # sequence length
C = 512 # embedding dimension
H = 8 # number of heads
# 创建模型和输入张量
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
initial_memory_1 = torch.cuda.memory_allocated(device)
attention = Attention(dim=C, num_heads=H).to(device)
x = torch.randn(B, L, C).to(device)
# 监控显存使用情况
torch.cuda.reset_peak_memory_stats(device)
initial_memory = torch.cuda.memory_allocated(device)
# 使用 autograd profiler 来记录显存使用情况
with torch.autograd.profiler.profile(profile_memory=True, record_shapes=True) as prof:output = attention(x)
# 计算显存占用ru
final_memory = torch.cuda.memory_allocated(device)
max_memory = torch.cuda.max_memory_allocated(device)
# 打印结果
print(f"Initial Memory_1: {initial_memory_1 / 1024**2:.2f} MB")
print(f"Initial Memory: {initial_memory / 1024**2:.2f} MB")
print(f"Final Memory: {final_memory / 1024**2:.2f} MB")
print(f"Max Memory: {max_memory / 1024**2:.2f} MB")
print(f"Activation Memory: {(final_memory - initial_memory) / 1024**2:.2f} MB")
# 打印详细的显存使用情况
print(prof.key_averages().table(sort_by="self_cuda_memory_usage", row_limit=10))
因此,产生的总显存为
BLC*3(qkv) + BHLD*2(qk算点乘,属于中间变量)+BHLL(atten)+BHLD(v矩阵)+BLC(输出结果)+BLC(线性映射)=BLC*8+BHLL
和其余blog记录的差不多,只不过显存增加的时间点和之前想象的不同
线性层产生显存
1 x = self.proj(x)
产生显存的原因
在这里,self.proj(x)
是一个 线性投影 操作,通常是通过一个线性层(nn.Linear
)实现的。这个操作会执行以下几步:
- 矩阵乘法:假设
self.proj
是一个线性层(如nn.Linear
),它会对输入x
执行矩阵乘法,计算x @ W^T + b
,其中W
是权重矩阵,b
是偏置。 - 新张量的分配:线性变换会生成一个新的张量,并且这个张量的形状通常会与输入
x
不同(例如,x
可能是(B, L, D)
,而输出x
可能是(B, L, D')
)。这个新的张量需要分配新的内存,因此它会产生显存。
2 x = self.proj_drop(x)
不产生显存的原因
self.proj_drop
通常是一个 Dropout 操作。Dropout 是一种正则化技术,在训练时随机地丢弃一部分神经元,以防止过拟合。它不会创建新的张量,而是直接在原有的张量上进行操作。具体来说,Dropout
会在每次前向传播时,对输入张量的部分元素乘以零,但它 不会改变张量的形状或大小。
- 内存共享:
Dropout
操作不会创建新的张量副本,而是就地修改原始张量。因此,显存消耗不会增加。它只是改变了张量的值(通过乘以0),但并不需要额外的内存。 - 不产生新张量:
Dropout
仅仅是通过一个掩码(mask)将某些值屏蔽掉,操作是原地进行的,因此不需要为输出分配新的内存。
3 attn = attn.softmax(dim=-1)
和 attn = self.attn_drop(attn)
- Softmax 操作:
attn.softmax(dim=-1)
是对attn
张量沿着最后一个维度(通常是特征维度)进行 softmax 操作。这个操作是通过对原张量进行逐元素的数值变换(softmax 归一化)来完成的,但它 不需要额外的内存。实际上,它会直接在原始张量上进行操作,因此不会创建新的张量。 - Dropout 操作:
self.attn_drop(attn)
也是一个类似的 dropout 操作,它对attn
张量进行处理,但不会改变张量的形状。和前面的proj_drop
一样,dropout 不需要新的内存,它只在原始张量上执行修改(通过将一些值置为零)
3 执行结束后保留的激活值
可以看到前向激活值峰值和执行完前向保留的激活值大小不同,上述例子中峰值为34MB,而执行完前向后保留的激活值为22MB
分析哪些释放、哪些保存,需要结合模型的网络结构
总结:保存与释放的变量对比
变量名称 | 状态 | 原因 | |
---|---|---|---|
**一层后产生的激活(qkv ) ** | 保存 | 用于反向传播时计算 q , k , v 的梯度。 | |
重排后的 q , k , v | 释放 | 在计算 attn 和输出后不再需要。 | |
第二层产生的激活( x ) | 保存 | 用于回传梯度到上一层。 | |
最终输出张量 x | 保存 | 作为前向传播的输出,供后续层使用或反向传播。 | |
q @ k^T | 保存 | 用于计算梯度(链式法则的一部分)。 | |
所以为12+4+4+2 = 22MB |
1 为什么存储attn
q@ k^T
经过Softmax,所以需要存储,属于激活值中的一部分
2 为什么不存储分割后的qkv
属于中间变量,不需要存储
4 查看计算图
1 tensorboard查看计算图
import torch
import torch.nn as nn
import einops
from torch.utils.tensorboard import SummaryWriter
import osclass Attention(nn.Module):def __init__(self, dim, num_heads=8, qkv_bias=False, qk_scale=None, attn_drop=0., proj_drop=0.):super().__init__()self.num_heads = num_headshead_dim = dim // num_headsself.scale = qk_scale or head_dim ** -0.5self.qkv = nn.Linear(dim, dim * 3, bias=qkv_bias)self.attn_drop = nn.Dropout(attn_drop)self.proj = nn.Linear(dim, dim)self.proj_drop = nn.Dropout(proj_drop)def forward(self, x, writer=None, step=None):B, L, C = x.shapeqkv = self.qkv(x)qkv = einops.rearrange(qkv, 'B L (K H D) -> K B H L D', K=3, H=self.num_heads)q, k, v = qkv[0], qkv[1], qkv[2]attn = (q @ k.transpose(-2, -1)) * self.scaleattn = attn.softmax(dim=-1)attn = self.attn_drop(attn)x = (attn @ v).transpose(1, 2).reshape(B, L, C)x = self.proj(x)x = self.proj_drop(x)return x# 设置参数
B, L, C, H = 64, 32, 512, 8
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")# 确保路径存在
log_dir = "./tensorboard_writer"
if not os.path.exists(log_dir):os.makedirs(log_dir)# 初始化模型和输入张量
attention = Attention(dim=C, num_heads=H).to(device)
x = torch.randn(B, L, C).to(device)# 初始化 TensorBoard
writer = SummaryWriter(log_dir=log_dir)
print("TensorBoard writer initialized.")# 添加计算图和激活值
with torch.no_grad():writer.add_graph(attention, (x,)) # 修正计算图输入attention(x, writer=writer, step=0) # 记录激活值# 确保数据写入文件
writer.flush()
writer.close()
运行
tensorboard --logdir=./tensorboard_writer --port=6007
查看计算图
相关文章:
Attention显存统计与分析
Attention显存估计 简单的Attention函数 import torch import torch.nn as nn import einops class Attention(nn.Module):def __init__(self, dim, num_heads8, qkv_biasFalse, qk_scaleNone, attn_drop0., proj_drop0.):super().__init__()self.num_heads num_headshead_d…...
java反射
反射 Java 反射是 Java 提供的一种强大特性,它允许程序在运行时动态地获取类的信息,并操作类的属性和方法。这为编写灵活、可扩展的 Java 应用程序提供了强有力的支持 获取Class对象 package ref;public class Person {private String name ;private …...
Spring Boot入门
1、Spring Boot是什么 Spring Boot 帮我们简单、快速地创建一个独立的、生产级别的 Spring 应用(说明:Spring Boot底层是Spring) 大多数 Spring Boot 应用只需要编写少量配置即可快速整合 Spring 平台以及第三方技术 特性: 快速…...
Spring Web:深度解析与实战应用
概述 大家好,欢迎来到今天的技术分享。我是你们的老朋友,今天,我们要深入探讨的是Spring Web模块,这个模块为Java Web应用程序提供了全面的支持,不仅具备基本的面向Web的综合特性,还能与常见框架如Struts2无…...
学习日志019--初识PyQt
使用pyqt创建一个登录界面 from PyQt6.QtCore import Qt # 引入pyqt6包 from PyQt6.QtGui import QIcon, QMovie from PyQt6.QtWidgets import QApplication, QWidget, QPushButton, QLabel, QLineEdit import sysclass MyWidget(QWidget):# 构造函数,继承父类的构造…...
Swift 宏(Macro)入门趣谈(五)
概述 苹果在去年 WWDC 23 中就为 Swift 语言新增了“其利断金”的重要小伙伴 Swift 宏(Swift Macro)。为此,苹果特地用 2 段视频(入门和进阶)颇为隆重的介绍了它。 那么到底 Swift 宏是什么?有什么用&…...
Linux 35.6 + JetPack v5.1.4@DeepStream安装
Linux 35.6 JetPack v5.1.4DeepStream安装 1. 源由2. 步骤Step 1 安装Jetpack 5.1.4 L4T 35.6Step 2 安装依赖组件Step 3 安装librdkafkaStep 4 安装 DeepStream SDKStep 5 测试 deepstream-appStep 6 运行 deepstream-app 3. 总结3.1 版本问题3.2 二进制help 4. 参考资料 1. …...
C++基础:list的底层实现
文章目录 1.基本结构2.迭代器的实现2.1 尾插的实现2.2 迭代器的实现 3.打印函数(模版复用实例化)4.任意位置的插入删除1. 插入2. 删除 5.析构与拷贝构造5.1 析构函数5.2 拷贝构造5.3 赋值重载 1.基本结构 与vector和string不同list需要: 一个类来放入数据和指针也就是节点 一…...
Spring中@Transactional注解与事务传播机制
文章目录 事务传播机制事务失效的场景 事务传播机制 事务的传播特性指的是 当一个事务方法调用另一个事务方法时,事务方法应该如何执行。 事务传播行为类型外部不存在事务外部存在事务使用方式REQUIRED(默认)开启新的事务融合到外部事务中Transactional(propagati…...
实验七 用 MATLAB 设计 FIR 数字滤波器
实验目的 加深对窗函数法设计 FIR 数字滤波器的基本原理的理解。 学习用 Matlab 语言的窗函数法编写设计 FIR 数字滤波器的程序。 了解 Matlab 语言有关窗函数法设计 FIR 数字滤波器的常用函数用法。 掌握 FIR 滤波器的快速卷积实现原理。 不同滤波器的设计方法具有不同的优…...
Linux - selinux
七、selinux 1、说明 SELinux是Security-Enhanced Linux的缩写,意思是安全强化的linux。 SELinux是对程序、文件等权限设置依据的一个内核模块。由于启动网络服务的也是程序,因此刚好也 是能够控制网络服务能否访问系统资源的一道关卡。 传统的文件权…...
【STL】C++ vector类模板
文章目录 基本概念vector的使用定义和初始化构造函数赋值操作容量和大小插入和删除数据存取 互换容器vector的迭代器vector储存自定义数据类型 基本概念 vector是类型相同的对象的容器,vector的大小可以变化,可以向数组中增加元素。因此,vec…...
物联网——WatchDog(监听器)
看门狗简介 独立看门狗框图 看门狗原理:定时器溢出,产生系统复位信号;若定时‘喂狗’则不产生系统复位信号 定时中断基本结构(对比) IWDG键寄存器 独立看门狗超时时间 WWDG(窗口看门狗) WWDG特性 WWDG超时时间 由于…...
从零开始写游戏之斗地主-网络通信
在确定了数据结构后,原本是打算直接开始写斗地主的游戏运行逻辑的。但是突然想到我本地写出来之后,也测试不了啊,所以还是先写通信模块了。 基本框架 在Java语言中搞网络通信,那么就得请出Netty这个老演员了。 主要分为两个端&…...
【智能控制】实验,基于MATLAB的模糊推理系统设计,模糊控制系统设计
关注作者了解更多 我的其他CSDN专栏 过程控制系统 工程测试技术 虚拟仪器技术 可编程控制器 工业现场总线 数字图像处理 智能控制 传感器技术 嵌入式系统 复变函数与积分变换 单片机原理 线性代数 大学物理 热工与工程流体力学 数字信号处理 光电融合集成电路…...
Vega Editor 基于 Web 的图形编辑器
Vega Editor 是一个强大的基于 Web 的图形编辑器,专为 Vega 和 Vega-Lite 可视化语法设计。它提供了一个交互式的环境,用户可以在其中编写、预览和分享他们的 Vega 和 Vega-Lite 可视化作品。Vega 和 Vega-Lite 是用于声明性可视化的开源语法,…...
SQL 中SET @variable的使用
在 SQL 中,SET variable 用于声明和赋值用户定义的变量。具体来说, 符号用于表示一个局部变量,可以在 SQL 语句中存储和使用。它通常在存储过程、函数或简单的 SQL 查询中使用。 1. 声明并赋值给变量 你可以使用 SET 语句给一个变量赋值。例…...
基于 Vite 封装工具库实践
项目背景:公司在多个项目中频繁使用相同的工具函数。为了避免每次开发新项目时都重复复制代码,决定通过 Vite 封装一个时间函数组件库。该库将被发布到 Verdaccio 供团队其他项目使用。 项目介绍 本项目封装了一个时间函数工具库,使用 Momen…...
Oracle DataGuard 主备正常切换 (Switchover)
前言 众所周知,DataGuard 的切换分为两种情况: 系统正常情况下的切换:这种方式称为 switchover,是无损切换,不会丢失数据。灾难情况下的切换:这种情况下一般主库已经启动不起来了,称为 failov…...
[Redis#13] cpp-redis接口 | set | hash |zset
目录 Set 1. Sadd 和 Smembers 2. Sismember 3. Scard 4. Spop 5. Sinter 6. Sinter store Hash 1. Hset 和 Hget 2. Hexists 3. Hdel 4. Hkeys 和 Hvals 5. Hmget 和 Hmset Zset 1. Zadd 和 Zrange 2. Zcard 3. Zrem 4. Zscore cpp-redis 的学习 主要关注于…...
青海摇摇了3天,技术退步明显.......
最近快手上的青海摇招聘活动非常火热,我已经在思考是否备战张诗尧的秋招活动。开个玩笑正片开始: 先说一下自己的情况,大专生,20年通过校招进入杭州某软件公司,干了接近4年的功能测试,今年年初,…...
Flask+Minio实现断点续传技术教程
什么是MinIO MinIO是一个高性能的分布式对象存储服务,与Amazon S3 API兼容。它允许用户存储和检索任意规模的数据,非常适合于使用S3 API的应用程序。MinIO支持多租户存储,提供高可用性、高扩展性、强一致性和数据持久性。它还可以作为软件定义…...
Java中Logger定义的三种方式
在 Java 项目中,日志记录是开发中的一个重要部分,用于跟踪系统运行状态、排查问题以及记录重要事件。在定义日志记录器时,经常会遇到一些写法上的选择,比如 Logger 的作用域、是否使用静态变量,以及如何命名变量。本篇…...
模型压缩技术
目录 模型压缩技术 权重剪枝: 量化技术: 知识蒸馏: 低秩分解: 一、权重剪枝 二、量化技术 三、知识蒸馏 四、低秩分解 模型压缩技术 权重剪枝: 描述:通过删除模型中不重要的权重来减少参数数量和计算量。举例说明:假设我们有一个神经网络模型,其中某些神经元的…...
面试题整理
1 spring使用中有哪些设计模式 工厂模式-beanFactory,代理模式-aop,单例模式-每个bean默认都是单例的,原型模式-当将bean的作用域改为prototype时每次获取bean时使用了原型模式创建对象,责任链模式-dispatchServle查找url对应的处理器映射器时使用了,观察者模式-spring的…...
Linux
1、显示系统中所有进程 ps -ef运行效果: [rootredhat-9 ~]# ps -ef UID PID PPID C STIME TTY TIME CMD root 1 0 0 19:01 ? 00:00:01 /usr/lib/systemd/systemd rhgb --switched-r root 2 0 0…...
力扣_2389. 和有限的最长子序列
力扣_2389. 和有限的最长子序列 给你一个长度为 n 的整数数组 nums ,和一个长度为 m 的整数数组 queries 。 返回一个长度为 m 的数组 answer ,其中 answer[i] 是 nums 中 元素之和小于等于 queries[i] 的 子序列 的 最大 长度 。 子序列 是由一个数组…...
UI设计从入门到进阶,全能实战课
课程内容: ├── 【宣导片】从入门到进阶!你的第一门UI必修课!.mp4 ├── 第0课:UI知识体系梳理 学习路径.mp4 ├── 第1课:IOS设计规范——基础规范与切图.mp4 ├── 第2课:IOS新趋势解析——模块规范与设计原则(上).mp4…...
Formality:等价性检查的流程与模式(Guide、Setup、Preverify、Match与Verify)
相关阅读 Formalityhttps://blog.csdn.net/weixin_45791458/category_12841971.html?spm1001.2014.3001.5482 等价性检查的流程 图1概述了使用Formality进行等效性检查的具体步骤。 图1 等价性检查流程 启动Formality(Start Formality) 要启动Formality,请…...
【Linux】————(日志、线程池及死锁问题)
作者主页: 作者主页 本篇博客专栏:Linux 创作时间 :2024年11月29日 日志 关于日志,首先我们来说一下日志的作用, 作用: 问题追踪:通过日志不仅仅包括我们程序的一些bug,也可以在…...
【自动化】配置信息抽取
公共基本信息配置文件抽取 公共基本信息比如卖家、买家、管理员,验证码等基本信息,再比如数据库、redis、各个服务的域名,这些目前是写死在代码之中的,为了能够更好的维护他们,我们将他们放入配置文件进行管理 公共的…...
Python毕业设计选题:基于django+vue的校园影院售票系统
开发语言:Python框架:djangoPython版本:python3.7.7数据库:mysql 5.7数据库工具:Navicat11开发软件:PyCharm 系统展示 管理员登录 管理员功能界面 用户管理 影院信息管理 电影类型管理 电影信息管理 系统…...
Docker化部署Flask:轻量级Web应用的快速部署方案
Flask是一个用Python编写的轻量级Web应用框架,以其简洁性和灵活性而受到开发者的喜爱。Docker作为一种流行的容器化技术,为应用的部署和管理提供了极大的便利。本文将探讨Flask的优点、Docker部署的好处,并详细介绍如何将Flask应用Docker化部…...
centos怎么通过docker安装一个gitlab
在CentOS上通过Docker安装GitLab的步骤如下: 安装Docker引擎: 首先,需要在你的CentOS系统上安装Docker。可以通过以下命令来安装Docker:yum install -y yum-utils yum-config-manager --add-repo https://download.docker.com/lin…...
docker 运行my-redis命令
CREATE TABLE orders ( order_id bigint NOT NULL COMMENT "订单ID", dt date NOT NULL COMMENT "日期", merchant_id int NOT NULL COMMENT "商家ID", user_id int NOT NULL COMMENT "用户ID", good_id int NOT NULL COMMENT "商…...
qt6.4.0+visual studio2022+opencv
qt6.4.0visual studio2022opencv 补充:在安装完Qt后还需要配置环境变量...
23种设计模式之适配器模式
目录 1. 简介1.1 定义1.2 结构和组成部分 2. 代码2.1 MediaPlayer2.2 AdvanceMediaPlayer2.3 VicPlayer2.4 Mp4Player2.5 MediaPlayerAdapter2.6 AudioPlayer2.7 Test 3. 适用场景4. 优点和缺点5. 总结 1. 简介 1.1 定义 适配器模式(Adapter Pattern)是…...
剖析go协程池实现原理
go协程池实现 在go语言编程中有一种池肯定避免不了,那就是-协程池,无论你是日常工作还是面试中面试官都无法避免协程池,掌握协程池你也就算是入门go的并发编程了,打一波广告后面会有专门的文章来介绍如何在go中进行并发编程。 协…...
渗透测试--Linux上获取凭证
在测试过程中我们也会发现一些Linux主机加域的情况,虽然不多见,但它确实存在。正所谓技多不压身,这样能够触类旁通的知识,我们怎能错过,所以在此我们将会主要探讨从Linux主机上获取域凭证的方法。主要有以下内容&#…...
【笔记】自动驾驶预测与决策规划_Part9_数据驱动前沿算法与发展趋势
文章目录 数据驱动前沿算法与发展趋势0. 前言1. 端到端自动驾驶引言2. 端到端自动驾驶2.1 端到端自动驾驶早期尝试 ALVINN2.2 基于模仿学习的端到端系统 NVIDIA-E2E2.3 基于强化学习的端到端系统2.4 多模态融合的自动驾驶 Transfuser2.5 模块化端到端 UniAD2.6 模块化端到端 VA…...
工业公辅车间数智化节能头部企业,蘑菇物联选择 TDengine 升级 AI 云智控
小T导读:在工业节能和智能化转型的浪潮中,蘑菇物联凭借其自研的灵知 AI 大模型走在行业前沿,为高能耗设备和公辅能源车间提供先进的 AI 解决方案。此次采访聚焦于蘑菇物联与 TDengine 的合作项目,通过 AI 云智控平台的建设&#x…...
【Linux】开启你的Linux之旅:初学者指令指南
Linux相关知识点可以通过点击以下链接进行学习一起加油! 在 Linux 开发中,GDB 调试器和 Git 版本控制工具是开发者必备的利器。GDB 帮助快速定位代码问题,Git 则提供高效的版本管理与协作支持。本指南将简明介绍两者的核心功能与使用技巧&…...
Vite 6.0 发布:引领现代前端开发新方向
Vite 6.0 带来了大量更新与优化,旨在简化开发流程、提升性能,并解决现代 Web 开发中的诸多挑战。本次更新引入了 实验性环境 API 和现代化的工具链,进一步巩固了 Vite 作为开发者首选工具的地位。以下是关于新特性、生态发展以及重要更新的全…...
深入了解阿里云 OSS:强大的云存储解决方案
在现代互联网应用中,数据存储是一个不可忽视的环节。随着数据量的不断增长,传统的存储方式已经无法满足高速、低成本、大容量的需求。阿里云 OSS(对象存储服务)作为一种高性能、低成本且具备高度扩展性的云存储服务,已…...
canvas绘制网络地址图片
canvas在绘制网络地址图片时,需要先下载成临时路径 export function downLoadBgImg (url) {return new Promise((r,j) > {uni.downloadFile({url,success : res > {if (res.statusCode 200) {r(res.tempFilePath);return;};j(依赖文件下载失败);},fail : er…...
《DSL-FIQA》论文翻译
《DSL-FIQA: Assessing Facial Image Quality Via Dual-Set Degradation Learning and Landmark-Guided Transformer》 原文链接:DSL-FIQA: Assessing Facial Image Quality via Dual-Set Degradation Learning and Landmark-Guided Transformer | IEEE Conference…...
【Linux网络编程】第四弹---构建UDP服务器与字典翻译系统:源码结构与关键组件解析
✨个人主页: 熬夜学编程的小林 💗系列专栏: 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】【Linux网络编程】 目录 1、UdpServer.hpp 1.1、函数对象声明 1.2、Server类基本结构 1.3、构造函数 1.4、Start() 2、Dict.hpp…...
【人工智能】人工智能,深度学习与人工神经网络
人工智能 人工智能一、定义与核心要素二、主要方法与技术三、应用领域四、发展前景与挑战五、分类六、研究目标与价值 深度学习定义与核心思想网络结构工作原理关键技术与模型应用领域发展与挑战 人工神经网络一、定义与原理二、基本特性三、网络结构四、工作原理五、应用领域六…...
嵌入式系统应用-LVGL的应用-平衡球游戏 part2
平衡球游戏 part2 4 mpu60504.1 mpu6050 介绍4.2 电路图4.3 驱动代码编写 5 游戏界面移植5.1 移植源文件5.2 添加头文件 6 参数移植6.1 4 mpu6050 4.1 mpu6050 介绍 MPU6050是一款由InvenSense公司生产的加速度计和陀螺仪传感器,广泛应用于消费电子、机器人等领域…...
Linux网络编程之---多线程实现并发服务器
下面我们来使用tcp集合多线程实现并发服务器 一.服务端 #include <stdio.h> #include <arpa/inet.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <pthread.h>typedef struct sockinfo {char ip[16];unsigne…...