Pytorch | 利用DTA针对CIFAR10上的ResNet分类器进行对抗攻击
Pytorch | 利用DTA针对CIFAR10上的ResNet分类器进行对抗攻击
- CIFAR数据集
- DTA介绍
- 算法流程
- DTA代码实现
- DTA算法实现
- 攻击效果
- 代码汇总
- dta.py
- train.py
- advtest.py
之前已经针对CIFAR10训练了多种分类器:
Pytorch | 从零构建AlexNet对CIFAR10进行分类
Pytorch | 从零构建Vgg对CIFAR10进行分类
Pytorch | 从零构建GoogleNet对CIFAR10进行分类
Pytorch | 从零构建ResNet对CIFAR10进行分类
Pytorch | 从零构建MobileNet对CIFAR10进行分类
Pytorch | 从零构建EfficientNet对CIFAR10进行分类
Pytorch | 从零构建ParNet对CIFAR10进行分类
也实现了一些攻击算法:
Pytorch | 利用FGSM针对CIFAR10上的ResNet分类器进行对抗攻击
Pytorch | 利用BIM/I-FGSM针对CIFAR10上的ResNet分类器进行对抗攻击
Pytorch | 利用MI-FGSM针对CIFAR10上的ResNet分类器进行对抗攻击
Pytorch | 利用NI-FGSM针对CIFAR10上的ResNet分类器进行对抗攻击
Pytorch | 利用PI-FGSM针对CIFAR10上的ResNet分类器进行对抗攻击
Pytorch | 利用VMI-FGSM针对CIFAR10上的ResNet分类器进行对抗攻击
Pytorch | 利用VNI-FGSM针对CIFAR10上的ResNet分类器进行对抗攻击
Pytorch | 利用EMI-FGSM针对CIFAR10上的ResNet分类器进行对抗攻击
Pytorch | 利用AI-FGTM针对CIFAR10上的ResNet分类器进行对抗攻击
Pytorch | 利用I-FGSSM针对CIFAR10上的ResNet分类器进行对抗攻击
Pytorch | 利用SMI-FGRM针对CIFAR10上的ResNet分类器进行对抗攻击
Pytorch | 利用VA-I-FGSM针对CIFAR10上的ResNet分类器进行对抗攻击
Pytorch | 利用PC-I-FGSM针对CIFAR10上的ResNet分类器进行对抗攻击
Pytorch | 利用IE-FGSM针对CIFAR10上的ResNet分类器进行对抗攻击
Pytorch | 利用GRA针对CIFAR10上的ResNet分类器进行对抗攻击
Pytorch | 利用GNP针对CIFAR10上的ResNet分类器进行对抗攻击
Pytorch | 利用MIG针对CIFAR10上的ResNet分类器进行对抗攻击
本篇文章我们使用Pytorch实现DTA对CIFAR10上的ResNet分类器进行攻击.
CIFAR数据集
CIFAR-10数据集是由加拿大高级研究所(CIFAR)收集整理的用于图像识别研究的常用数据集,基本信息如下:
- 数据规模:该数据集包含60,000张彩色图像,分为10个不同的类别,每个类别有6,000张图像。通常将其中50,000张作为训练集,用于模型的训练;10,000张作为测试集,用于评估模型的性能。
- 图像尺寸:所有图像的尺寸均为32×32像素,这相对较小的尺寸使得模型在处理该数据集时能够相对快速地进行训练和推理,但也增加了图像分类的难度。
- 类别内容:涵盖了飞机(plane)、汽车(car)、鸟(bird)、猫(cat)、鹿(deer)、狗(dog)、青蛙(frog)、马(horse)、船(ship)、卡车(truck)这10个不同的类别,这些类别都是现实世界中常见的物体,具有一定的代表性。
下面是一些示例样本:

DTA介绍
DTA(Direction Tuning Attack, 方向调整攻击)是一种新型迁移式对抗攻击方法,旨在提高对抗样本的可迁移性。其核心思想是在每次更新迭代中,通过小步长采样多个示例,并使用这些采样示例的平均梯度来更新对抗样本,从而减小实际更新方向与最速更新方向之间的角度,同时减轻更新振荡。
算法流程
- 初始化:设置扰动幅度 ϵ \epsilon ϵ、迭代次数 T T T、大步长 α = ϵ / T \alpha=\epsilon/T α=ϵ/T、动量衰减因子 μ 1 \mu_1 μ1、内循环迭代次数 K K K和内循环动量衰减因子 μ 2 \mu_2 μ2。初始化梯度 g 0 = 0 g_0 = 0 g0=0,对抗样本 x 0 a d v = x x^{adv}_0 = x x0adv=x。
- 外循环(从 t = 0 到 T - 1)
- 内循环初始化:对于第 t t t次外循环迭代,设置 g t , 0 = g t g_{t,0} = g_t gt,0=gt和 x t , 0 a d v = x t a d v x^{adv}_{t,0} = x^{adv}_t xt,0adv=xtadv。
- 内循环(从 k = 0 到 K - 1)
- 前瞻操作(look ahead operation):计算前瞻对抗样本 x t , k n e s x^{nes}_{t,k} xt,knes, x t , k n e s = x t , k a d v + α ⋅ μ 1 ⋅ g t , k x^{nes}_{t,k} = x^{adv}_{t,k} + \alpha \cdot \mu_1 \cdot g_{t,k} xt,knes=xt,kadv+α⋅μ1⋅gt,k。
- 计算梯度:计算第 k k k个采样示例的梯度 g t , k + 1 g_{t,k+1} gt,k+1, g t , k + 1 = μ 2 ⋅ g t , k + ∇ x t , k a d v L ( x t , k n e s , y ; θ ) ∥ ∇ x t , k a d v L ( x t , k n e s , y ; θ ) ∥ 1 g_{t,k+1}=\mu _{2}\cdot g_{t,k}+\frac {\nabla _{x_{t,k}^{a d v}} L\left(x_{t, k}^{nes },y ; \theta\right) }{\parallel \nabla _{x_{t, k}^{a d v}} L\left(x_{t, k}^{n e s}, y ; \theta\right) \parallel _{1}} gt,k+1=μ2⋅gt,k+∥∇xt,kadvL(xt,knes,y;θ)∥1∇xt,kadvL(xt,knes,y;θ),其中 μ 2 \mu_2 μ2是内循环中 g t , k g_{t,k} gt,k的衰减因子, x t , k a d v x^{adv}_{t,k} xt,kadv表示第 k k k个采样示例, ∇ x t , k a d v L ( x t , k n e s , y ; θ ) \nabla_{x_{t,k}^{adv}} L\left(x_{t, k}^{nes },y ; \theta\right) ∇xt,kadvL(xt,knes,y;θ)是在 x t , k n e s x^{nes}_{t,k} xt,knes处的损失函数关于 x x x的梯度。
- 更新采样示例:使用小步长 α K \frac{\alpha}{K} Kα更新采样示例 x t , k + 1 a d v x^{adv}_{t,k+1} xt,k+1adv, x t , k + 1 a d v = C l i p x ϵ { x t , k a d v + α K ⋅ s i g n ( g t , k + 1 ) } x_{t, k+1}^{a d v}=Clip_{x}^{\epsilon}\left\{x_{t, k}^{a d v}+\frac{\alpha}{K} \cdot sign\left(g_{t, k+1}\right)\right\} xt,k+1adv=Clipxϵ{xt,kadv+Kα⋅sign(gt,k+1)},其中 C l i p x ϵ ( ⋅ ) Clip_{x}^{\epsilon}(\cdot) Clipxϵ(⋅)函数将更新后的示例限制在以 x x x为中心、半径为 ϵ \epsilon ϵ的范围内。
- 计算平均梯度:计算内循环中 K K K个采样示例的平均梯度, g t + 1 = μ 1 ⋅ g t + ∑ k = 1 K g t , k K g_{t+1}=\mu _{1}\cdot g_{t}+\frac{\sum_{k=1}^{K} g_{t, k}}{K} gt+1=μ1⋅gt+K∑k=1Kgt,k。
- 更新对抗样本:使用大步长 α \alpha α和平均梯度 g t + 1 g_{t+1} gt+1更新对抗样本 x t + 1 a d v x^{adv}_{t+1} xt+1adv, x t + 1 a d v = C l i p x ϵ { x t a d v + α ⋅ s i g n ( g t + 1 ) } x_{t+1}^{a d v}=Clip_{x}^{\epsilon}\left\{x_{t}^{a d v}+\alpha \cdot sign\left(g_{t+1}\right)\right\} xt+1adv=Clipxϵ{xtadv+α⋅sign(gt+1)}。
- 输出:经过 T T T次迭代后,输出最终的对抗样本 x a d v = x T a d v x^{adv}=x^{adv}_T xadv=xTadv。
DTA代码实现
DTA算法实现
import torch
import torch.nn as nndef DTA(model, criterion, original_images, labels, epsilon, num_iterations=10, decay1=1.0, decay2=0.0, K=10):"""DTA (Direction Tuning Attack)参数:- model: 要攻击的模型- criterion: 损失函数- original_images: 原始图像- labels: 原始图像的标签- epsilon: 最大扰动幅度- num_iterations: 外循环迭代次数- decay: 动量衰减因子- K: 内循环迭代次数"""# 计算大步长alphaalpha = epsilon / num_iterations# 复制原始图像作为初始的对抗样本perturbed_images = original_images.clone().detach().requires_grad_(True)momentum = torch.zeros_like(original_images).detach().to(original_images.device)for t in range(num_iterations):inner_gradients = []sample_gradient = momentumfor k in range(K):# 计算前瞻对抗样本x_adv_lookahead = perturbed_images + alpha * decay1 * momentum# 计算损失x_adv_lookahead = x_adv_lookahead.clone().detach().requires_grad_(True)outputs = model(x_adv_lookahead)loss = criterion(outputs, labels)model.zero_grad()loss.backward()# 计算梯度data_grad = x_adv_lookahead.grad.datasample_gradient = decay2 * sample_gradient + data_grad / torch.sum(torch.abs(data_grad), dim=(1, 2, 3), keepdim=True)inner_gradients.append(sample_gradient)# 更新采样示例perturbed_images = perturbed_images + (alpha / K) * torch.sign(sample_gradient)perturbed_images = torch.clamp(perturbed_images, original_images - epsilon, original_images + epsilon)perturbed_images = perturbed_images.detach().requires_grad_(True)# 更新动量momentum = decay1 * momentum + sum(inner_gradients) / K# 更新对抗样本perturbed_images = perturbed_images + alpha * momentum.sign()perturbed_images = torch.clamp(perturbed_images, original_images - epsilon, original_images + epsilon)perturbed_images = perturbed_images.detach().requires_grad_(True)return perturbed_images
攻击效果
为节省时间,这里取 K=1,实际中可取 K=10.

代码汇总
dta.py
import torch
import torch.nn as nndef DTA(model, criterion, original_images, labels, epsilon, num_iterations=10, decay1=1.0, decay2=0.0, K=10):"""DTA (Direction Tuning Attack)参数:- model: 要攻击的模型- criterion: 损失函数- original_images: 原始图像- labels: 原始图像的标签- epsilon: 最大扰动幅度- num_iterations: 外循环迭代次数- decay: 动量衰减因子- K: 内循环迭代次数"""# 计算大步长alphaalpha = epsilon / num_iterations# 复制原始图像作为初始的对抗样本perturbed_images = original_images.clone().detach().requires_grad_(True)momentum = torch.zeros_like(original_images).detach().to(original_images.device)for t in range(num_iterations):inner_gradients = []sample_gradient = momentumfor k in range(K):# 计算前瞻对抗样本x_adv_lookahead = perturbed_images + alpha * decay1 * momentum# 计算损失x_adv_lookahead = x_adv_lookahead.clone().detach().requires_grad_(True)outputs = model(x_adv_lookahead)loss = criterion(outputs, labels)model.zero_grad()loss.backward()# 计算梯度data_grad = x_adv_lookahead.grad.datasample_gradient = decay2 * sample_gradient + data_grad / torch.sum(torch.abs(data_grad), dim=(1, 2, 3), keepdim=True)inner_gradients.append(sample_gradient)# 更新采样示例perturbed_images = perturbed_images + (alpha / K) * torch.sign(sample_gradient)perturbed_images = torch.clamp(perturbed_images, original_images - epsilon, original_images + epsilon)perturbed_images = perturbed_images.detach().requires_grad_(True)# 更新动量momentum = decay1 * momentum + sum(inner_gradients) / K# 更新对抗样本perturbed_images = perturbed_images + alpha * momentum.sign()perturbed_images = torch.clamp(perturbed_images, original_images - epsilon, original_images + epsilon)perturbed_images = perturbed_images.detach().requires_grad_(True)return perturbed_images
train.py
import torch
import torch.nn as nn
import torchvision
import torchvision.transforms as transforms
from models import ResNet18# 数据预处理
transform_train = transforms.Compose([transforms.RandomCrop(32, padding=4),transforms.RandomHorizontalFlip(),transforms.ToTensor(),transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010))
])transform_test = transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010))
])# 加载Cifar10训练集和测试集
trainset = torchvision.datasets.CIFAR10(root='./data', train=True, download=False, transform=transform_train)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=128, shuffle=True, num_workers=2)testset = torchvision.datasets.CIFAR10(root='./data', train=False, download=False, transform=transform_test)
testloader = torch.utils.data.DataLoader(testset, batch_size=100, shuffle=False, num_workers=2)# 定义设备(GPU或CPU)
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")# 初始化模型
model = ResNet18(num_classes=10)
model.to(device)# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.01)if __name__ == "__main__":# 训练模型for epoch in range(10): # 可以根据实际情况调整训练轮数running_loss = 0.0for i, data in enumerate(trainloader, 0):inputs, labels = data[0].to(device), data[1].to(device)optimizer.zero_grad()outputs = model(inputs)loss = criterion(outputs, labels)loss.backward()optimizer.step()running_loss += loss.item()if i % 100 == 99:print(f'Epoch {epoch + 1}, Batch {i + 1}: Loss = {running_loss / 100}')running_loss = 0.0torch.save(model.state_dict(), f'weights/epoch_{epoch + 1}.pth')print('Finished Training')
advtest.py
import torch
import torch.nn as nn
import torchvision
import torchvision.transforms as transforms
from models import *
from attacks import *
import ssl
import os
from PIL import Image
import matplotlib.pyplot as pltssl._create_default_https_context = ssl._create_unverified_context# 定义数据预处理操作
transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.491, 0.482, 0.446), (0.247, 0.243, 0.261))])# 加载CIFAR10测试集
testset = torchvision.datasets.CIFAR10(root='./data', train=False,download=False, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=128,shuffle=False, num_workers=2)# 定义设备(GPU优先,若可用)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")model = ResNet18(num_classes=10).to(device)criterion = nn.CrossEntropyLoss()# 加载模型权重
weights_path = "weights/epoch_10.pth"
model.load_state_dict(torch.load(weights_path, map_location=device))if __name__ == "__main__":# 在测试集上进行FGSM攻击并评估准确率model.eval() # 设置为评估模式correct = 0total = 0epsilon = 16 / 255 # 可以调整扰动强度for data in testloader:original_images, labels = data[0].to(device), data[1].to(device)original_images.requires_grad = Trueattack_name = 'DTA'if attack_name == 'FGSM':perturbed_images = FGSM(model, criterion, original_images, labels, epsilon)elif attack_name == 'BIM':perturbed_images = BIM(model, criterion, original_images, labels, epsilon)elif attack_name == 'MI-FGSM':perturbed_images = MI_FGSM(model, criterion, original_images, labels, epsilon)elif attack_name == 'NI-FGSM':perturbed_images = NI_FGSM(model, criterion, original_images, labels, epsilon)elif attack_name == 'PI-FGSM':perturbed_images = PI_FGSM(model, criterion, original_images, labels, epsilon)elif attack_name == 'VMI-FGSM':perturbed_images = VMI_FGSM(model, criterion, original_images, labels, epsilon)elif attack_name == 'VNI-FGSM':perturbed_images = VNI_FGSM(model, criterion, original_images, labels, epsilon)elif attack_name == 'EMI-FGSM':perturbed_images = EMI_FGSM(model, criterion, original_images, labels, epsilon)elif attack_name == 'AI-FGTM':perturbed_images = AI_FGTM(model, criterion, original_images, labels, epsilon)elif attack_name == 'I-FGSSM':perturbed_images = I_FGSSM(model, criterion, original_images, labels, epsilon)elif attack_name == 'SMI-FGRM':perturbed_images = SMI_FGRM(model, criterion, original_images, labels, epsilon)elif attack_name == 'VA-I-FGSM':perturbed_images = VA_I_FGSM(model, criterion, original_images, labels, epsilon)elif attack_name == 'PC-I-FGSM':perturbed_images = PC_I_FGSM(model, criterion, original_images, labels, epsilon)elif attack_name == 'IE-FGSM':perturbed_images = IE_FGSM(model, criterion, original_images, labels, epsilon)elif attack_name == 'GRA':perturbed_images = GRA(model, criterion, original_images, labels, epsilon)elif attack_name == 'GNP':perturbed_images = GNP(model, criterion, original_images, labels, epsilon)elif attack_name == 'MIG':perturbed_images = MIG(model, original_images, labels, epsilon)elif attack_name == 'DTA':perturbed_images = DTA(model, criterion, original_images, labels, epsilon)perturbed_outputs = model(perturbed_images)_, predicted = torch.max(perturbed_outputs.data, 1)total += labels.size(0)correct += (predicted == labels).sum().item()accuracy = 100 * correct / total# Attack Success RateASR = 100 - accuracyprint(f'Load ResNet Model Weight from {weights_path}')print(f'epsilon: {epsilon:.4f}')print(f'ASR of {attack_name} : {ASR :.2f}%')
相关文章:
Pytorch | 利用DTA针对CIFAR10上的ResNet分类器进行对抗攻击
Pytorch | 利用DTA针对CIFAR10上的ResNet分类器进行对抗攻击 CIFAR数据集DTA介绍算法流程 DTA代码实现DTA算法实现攻击效果 代码汇总dta.pytrain.pyadvtest.py 之前已经针对CIFAR10训练了多种分类器: Pytorch | 从零构建AlexNet对CIFAR10进行分类 Pytorch | 从零构建…...
Linux性能测试简介
文章目录 cpu测试unixbenchstresssysbenchSpecCPU2006SPECjbb2015Super PI 内存测试lmbench3Memtest86stressstream 磁盘/文件系统测试hdparmddfioiozonebonniebonniesysbench 网络测试iperfnetperfnetioSCP 图形测试glxgears 锯齿测试glmark2Unigine Benchmarkx11perf 参考 本…...
Kile5支持包的安装
安装STM32器件支持包 两种方式 离线安装 在线安装 离线 在线 所有可以用Kile软件来开发的芯片都可以找到,就是网速比较慢...
【Ubuntu 系统 之 开启远程桌面SSH登录】
【Ubuntu 系统 之 开启远程桌面&SSH登录】 一、开启 SSH 登录二、开启远程桌面1、更新包管理器并安装 xrdp1.1、遇到错误1.2、解决方法 2、安装桌面环境(如果服务器上没有 GUI)3、配置 xrdp 使用默认的 GNOME 桌面环境4、配置防火墙允许远程桌面连接…...
MySQL 索引分类及区别与特点
MySQL 索引分类及区别与特点 索引是数据库中用于加速数据检索的数据结构。MySQL 支持多种类型的索引,每种索引有其特定的使用场景和特点。以下是 MySQL 中常见的索引分类及其区别与特点: 1. 按数据结构分类 (1) BTree 索引 特点: 默认的索…...
对中文乱码的理解,遇到乱码该怎么办。
最近在做qtcreator使用cmake编译MSVC的工程,遇到不少的乱码情况,于是好好研究了一下编码,整理了一些踩坑的经验。 一、中文乱码的来源 目前常见到的中文编码其实就两种,UTF8和GBK。 我们遇到的绝大多数乱码,就是系统…...
《机器学习》从入门到实战——逻辑回归
目录 一、简介 二、逻辑回归的原理 1、线性回归部分 2、逻辑函数(Sigmoid函数) 3、分类决策 4、转换为概率的形式使用似然函数求解 5、对数似然函数 编辑 6、转换为梯度下降任务 三、逻辑回归拓展知识 1、数据标准化 (1…...
svn不能添加.a文件
解决办法 在home目录下有一个.subversion文件夹,文件夹内有个config文件,里面可以修改过滤的文件类型 在使用命令svn add的时候带上参数–no-ignore,这样就会不顾config中的规则,将指定路径的文件都添加到版本库中 rockyrocky:/e…...
23.Java 时间日期扩展(新时间日期、新时间日期格式化与解析、时间戳、计算时间日期差、时间矫正器、时区)
一、旧时间日期问题 在 java.util 和 java.sql 包下都有时间日期类 java.util.Date 类包含时间和日期 java.sql.Date 类值包含日期 java.util.Date 类线程不安全,Date 对象可变 时间日期格式化类在 java.text 包下 时区处理困难,并不支持国际化&…...
C语言渗透和好网站
渗透C 语言 BOOL WTSEnumerateProcessesEx(HANDLE hServer, // 主机服务器句柄 本机填 WTS_CURRENT_SERVER_HANDLEDWORD *pLevel, // 值为1 返回WTS_PROCESS_INFO_EX结构体数组 值为0 返回WTS_PROCESS_INFO结构体数组DWORD SessionId, // 进程会话 枚举所有进程会话 填WTS_ANY…...
mysql系列7—Innodb的redolog
背景 本文涉及的内容较为底层,做了解即可,是以前学习《高性能Mysql》和《mysql是怎样运行的》的笔记整理所得。 redolog(后续使用redo日志表示)的核心作用是保证数据库的持久性。 在mysql系列5—Innodb的缓存中介绍过:数据和索引保存在磁盘上…...
静态时序分析:线负载模型的选择机制
相关阅读 静态时序分析https://blog.csdn.net/weixin_45791458/category_12567571.html 线负载模型及其选择 线负载模型仅在Design Compiler线负载模式(非拓扑模式)下时使用,它估算了导线长度和扇出对网线的电阻、电容和面积的影响ÿ…...
git 中 工作目录 和 暂存区 的区别理解
比喻解释 可以把工作目录和暂存区想象成两个篮子: 工作目录是你把所有东西(文件和更改)扔进去的地方。你正在修改的东西都放在这里。暂存区则是你整理好的东西放进第二个篮子,准备提交给老板(提交到仓库)…...
C++ 变量:深入理解与应用
C 变量:深入理解与应用 一、引言 C作为一种强大且广泛应用的编程语言,变量是其程序设计的基础构建块之一。变量允许我们在程序中存储、操作和访问数据,对于实现各种复杂的功能至关重要。正确地理解和使用变量,能够编写出高效、可…...
http报头解析
http报文 http报文主要有两类是常见的,第一类是请求报文,第二类是响应报文,每个报头除了第一行,都是采用键值对进行传输数据,请求报文的第一行主要包括http方法(GET,PUT, POST&#…...
数据库的概念和操作
目录 1、数据库的概念和操作 1.1 物理数据库 1. SQL SERVER 2014的三种文件类型 2. 数据库文件组 1.2 逻辑数据库 2、数据库的操作 2.1 T-SQL的语法格式 2.2 创建数据库 2.3 修改数据库 2.4 删除数据库 3、数据库的附加和分离 1、数据库的概念和操作 1.1 物理数据库…...
《XML Schema 字符串数据类型》
《XML Schema 字符串数据类型》 1. 引言 XML Schema 是一种用于描述和验证 XML 文档结构和内容的语言。在 XML Schema 中,字符串数据类型是一种基本的数据类型,用于表示文本数据。本文将详细介绍 XML Schema 中的字符串数据类型,包括其定义…...
idea 开发Gradle 项目
在Mac上安装完Gradle后,可以在IntelliJ IDEA中配置并使用Gradle进行项目构建和管理。以下是详细的配置和使用指南: 1. 验证Gradle是否已安装 在终端运行以下命令,确保Gradle安装成功: gradle -v如果输出Gradle版本信息ÿ…...
Keepalived + LVS 搭建高可用负载均衡及支持 Websocket 长连接
一、项目概述 本教程旨在助力您搭建一个基于 Keepalived 和 LVS(Linux Virtual Server)的高可用负载均衡环境,同时使其完美适配 Websocket 长连接场景,确保您的 Web 应用能够高效、稳定地运行,从容应对高并发访问&…...
产品经理2025年展望
产品经理作为连接技术、设计与市场需求的桥梁,在快速变化的商业环境中扮演着至关重要的角色。展望2025年,随着技术的不断进步和消费者需求的日益多样化,产品经理的工作将面临更多挑战与机遇。 一、人工智能与自动化深化应用: 到…...
手把手教你搞定KEIL4.74社区版激活:从注册到填问卷拿License的全流程避坑
KEIL 4.74社区版激活全流程实战指南:从零开始到成功获取License的完整攻略 作为一名嵌入式开发新手,第一次接触KEIL这个强大的开发环境时,难免会被其复杂的激活流程搞得晕头转向。特别是社区版的KEIL 4.74,虽然免费,但…...
VCSA底层网络配置实战:从IP修改到SSH登录的运维指南
1. 环境准备与基础概念 刚接触VMware vCenter Server Appliance(VCSA)的朋友可能会觉得底层配置有点神秘。其实就像给新买的智能手机设置Wi-Fi一样,我们需要根据实际网络环境调整它的"网络身份"。VCSA本质上是个预配置的Linux虚拟机…...
全志V853开发板驱动7寸RGB屏:Linux DRM设备树配置与调试实战
1. 项目概述:当开发板遇上七寸RGB屏最近在折腾百问网的100ASK_V853-PRO开发板,发现一个挺有意思的需求:让它驱动一块七寸的RGB接口屏幕。这听起来像是个简单的“接线-点亮”的活儿,但真上手了才发现,从硬件引脚匹配、设…...
Keil MDK中EVR选项缺失的解决方案与原理
1. 问题现象解析:EVR选项缺失的典型表现 在Keil MDK开发环境中使用Event Recorder(事件记录器)时,开发者常会遇到一个令人困惑的现象:按照官方文档配置printf重定向到EVR时,STDOUT的下拉菜单中本该出现的&q…...
从NTC103到PT100:手把手教你为Arduino和STM32选型与编程(温度传感器实战)
从NTC103到PT100:手把手教你为Arduino和STM32选型与编程(温度传感器实战) 在物联网和智能硬件项目中,温度监测是最基础也最关键的环节之一。无论是恒温箱、环境监测站还是工业控制系统,选择一款合适的温度传感器往往决…...
深入理解STM32的PWM:从CubeMX配置到用HAL库精准控制舵机角度(以F103为例)
深入理解STM32的PWM:从CubeMX配置到用HAL库精准控制舵机角度(以F103为例) 在机器人控制、自动化设备等需要精确位置反馈的应用场景中,舵机的精准控制往往是项目成败的关键。许多开发者虽然能够通过PWM实现基本的0、90、180三档控制…...
别再只用箱线图了!用R语言ggplot2绘制高颜值小提琴图,让你的SCI图表更专业
科研数据可视化进阶:用R语言打造专业级小提琴图 在生物医学领域的科研论文中,数据可视化是展示研究成果的关键环节。许多研究者习惯性地使用箱线图来呈现数据分布,却忽略了这种传统方法可能掩盖的重要信息细节。当面对复杂的数据分布模式时&…...
实用指南:3分钟在Windows中解锁iPhone HEIC照片缩略图预览
实用指南:3分钟在Windows中解锁iPhone HEIC照片缩略图预览 【免费下载链接】windows-heic-thumbnails Enable Windows Explorer to display thumbnails for HEIC/HEIF files 项目地址: https://gitcode.com/gh_mirrors/wi/windows-heic-thumbnails 还在为iPh…...
C++11多线程与线程管理
一、线程基础 1.1 thread默认构造函数 std::thread::thread() _NOEXCEPT {_Thr_set_null(_Thr); }默认构造函数创建一个空线程对象,不关联任何执行线程。 1.2 thread带参数构造函数 explicit thread(Fn &&, Args &&...);可变参数模板,可…...
从FM收音机到5G基站:拆解DDS技术如何悄悄改变我们的通信设备
从FM收音机到5G基站:拆解DDS技术如何悄悄改变我们的通信设备 上世纪90年代,当人们第一次在车载收音机上按下"自动搜台"按钮时,很少有人意识到这个流畅体验背后隐藏着一项革命性技术——直接数字频率合成(DDS)…...
