PyTorch 深度学习实战(34):神经架构搜索(NAS)实战
在上一篇文章中,我们探讨了联邦学习与隐私保护技术。本文将深入介绍神经架构搜索(Neural Architecture Search, NAS)这一自动化机器学习方法,它能够自动设计高性能的神经网络架构。我们将使用PyTorch实现基于梯度优化的DARTS方法,并在CIFAR-10数据集上进行验证。
一、神经架构搜索基础
神经架构搜索是AutoML的核心技术之一,旨在自动化神经网络设计过程。
1. NAS的核心组件
组件 | 描述 | 典型实现 |
---|---|---|
搜索空间 | 定义可能架构的集合 | 细胞结构、宏架构 |
搜索策略 | 探索搜索空间的方法 | 强化学习、进化算法、梯度优化 |
性能评估 | 评估架构质量的方式 | 代理指标、权重共享 |
2. 主流NAS方法对比
class NASMethod(Enum):RL_BASED = "基于强化学习" # Google早期方案EVOLUTIONARY = "进化算法" # Google Brain提出GRADIENT_BASED = "梯度优化" # DARTS为代表ONESHOT = "权重共享" # ENAS、ProxylessNAS
3. DARTS数学原理
DARTS(Differentiable ARchiTecture Search)将离散架构搜索转化为连续优化问题:
二、DARTS实战:CIFAR-10图像分类
1. 环境配置
pip install torch torchvision matplotlib graphviz
2. 实现可微分架构搜索
2.1 搜索空间定义
import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.utils.data import DataLoader
from torchvision import datasets, transforms
import numpy as np
from matplotlib import pyplot as plt
import copy
from graphviz import Digraph
# 设备配置
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f"使用设备: {device}")
# 操作类型集合
OPS = {'none': lambda C, stride: Zero(stride),'skip_connect': lambda C, stride: Identity() if stride == 1 else FactorizedReduce(C, C),'conv_3x3': lambda C, stride: ConvBNReLU(C, C, 3, stride, 1),'conv_5x5': lambda C, stride: ConvBNReLU(C, C, 5, stride, 2),'dil_conv_3x3': lambda C, stride: DilConv(C, C, 3, stride, 2, 2),'dil_conv_5x5': lambda C, stride: DilConv(C, C, 5, stride, 4, 2),'max_pool_3x3': lambda C, stride: PoolBN('max', C, 3, stride, 1),'avg_pool_3x3': lambda C, stride: PoolBN('avg', C, 3, stride, 1)
}
# 基础操作模块
class ConvBNReLU(nn.Module):def __init__(self, C_in, C_out, kernel_size, stride, padding):super().__init__()self.op = nn.Sequential(nn.Conv2d(C_in, C_out, kernel_size, stride, padding, bias=False),nn.BatchNorm2d(C_out),nn.ReLU(inplace=False))
def forward(self, x):return self.op(x)
class DilConv(nn.Module):def __init__(self, C_in, C_out, kernel_size, stride, padding, dilation):super().__init__()self.op = nn.Sequential(nn.Conv2d(C_in, C_in, kernel_size, stride, padding, dilation, groups=C_in, bias=False),nn.Conv2d(C_in, C_out, 1, padding=0, bias=False),nn.BatchNorm2d(C_out),nn.ReLU(inplace=False))
def forward(self, x):return self.op(x)
class PoolBN(nn.Module):def __init__(self, pool_type, C, kernel_size, stride, padding):super().__init__()if pool_type == 'max':self.pool = nn.MaxPool2d(kernel_size, stride, padding)elif pool_type == 'avg':self.pool = nn.AvgPool2d(kernel_size, stride, padding)else:raise ValueError()self.bn = nn.BatchNorm2d(C)
def forward(self, x):return self.bn(self.pool(x))
class Identity(nn.Module):def __init__(self):super().__init__()
def forward(self, x):return x
class Zero(nn.Module):def __init__(self, stride):super().__init__()self.stride = stride
def forward(self, x):if self.stride == 1:return x.mul(0.)return x[:, :, ::self.stride, ::self.stride].mul(0.)
class FactorizedReduce(nn.Module):def __init__(self, C_in, C_out):super().__init__()self.conv1 = nn.Conv2d(C_in, C_out // 2, 1, stride=2, padding=0, bias=False)self.conv2 = nn.Conv2d(C_in, C_out // 2, 1, stride=2, padding=0, bias=False)self.bn = nn.BatchNorm2d(C_out)
def forward(self, x):return self.bn(torch.cat([self.conv1(x), self.conv2(x[:, :, 1:, 1:])], dim=1))
2.2 可微分细胞结构实现
class MixedOp(nn.Module):"""混合操作实现"""
def __init__(self, C, stride):super().__init__()self._ops = nn.ModuleList()for primitive in OPS.keys():op = OPS[primitive](C, stride)self._ops.append(op)
def forward(self, x, weights):return sum(w * op(x) for w, op in zip(weights, self._ops))
class Cell(nn.Module):"""可微分细胞结构"""
def __init__(self, steps, multiplier, C_prev_prev, C_prev, C, reduction, reduction_prev):super().__init__()self.reduction = reductionself.steps = stepsself.multiplier = multiplier
# 预处理节点if reduction_prev:self.preprocess0 = FactorizedReduce(C_prev_prev, C)else:self.preprocess0 = ConvBNReLU(C_prev_prev, C, 1, 1, 0)self.preprocess1 = ConvBNReLU(C_prev, C, 1, 1, 0)
# 构建DAG结构self._ops = nn.ModuleList()self._bns = nn.ModuleList()for i in range(self.steps):for j in range(2 + i):stride = 2 if reduction and j < 2 else 1op = MixedOp(C, stride)self._ops.append(op)
def forward(self, s0, s1, weights):s0 = self.preprocess0(s0)s1 = self.preprocess1(s1)
states = [s0, s1]offset = 0for i in range(self.steps):s = sum(self._ops[offset + j](h, weights[offset + j]) for j, h in enumerate(states))offset += len(states)states.append(s)
return torch.cat(states[-self.multiplier:], dim=1)
2.3 完整搜索网络
class Network(nn.Module):"""可微分架构搜索网络"""
def __init__(self, C, num_classes, layers, criterion, steps=4, multiplier=4, stem_multiplier=3):super().__init__()self._C = Cself._num_classes = num_classesself._layers = layersself._criterion = criterionself._steps = stepsself._multiplier = multiplier
C_curr = stem_multiplier * Cself.stem = nn.Sequential(nn.Conv2d(3, C_curr, 3, padding=1, bias=False),nn.BatchNorm2d(C_curr))
C_prev_prev, C_prev, C_curr = C_curr, C_curr, Cself.cells = nn.ModuleList()reduction_prev = Falsefor i in range(layers):if i in [layers // 3, 2 * layers // 3]:C_curr *= 2reduction = Trueelse:reduction = Falsecell = Cell(steps, multiplier, C_prev_prev, C_prev, C_curr, reduction, reduction_prev)reduction_prev = reductionself.cells.append(cell)C_prev_prev, C_prev = C_prev, multiplier * C_curr
self.global_pooling = nn.AdaptiveAvgPool2d(1)self.classifier = nn.Linear(C_prev, num_classes)
# 架构参数k = sum(2 + i for i in range(steps))num_ops = len(OPS)self._alphas = nn.Parameter(1e-3 * torch.randn(k, num_ops)) # 使用随机初始化
# 修正优化器初始化self._arch_optimizer = torch.optim.Adam([self._alphas], lr=6e-4, betas=(0.5, 0.999))
def forward(self, x):s0 = s1 = self.stem(x)weights = F.softmax(self._alphas, dim=-1)
for cell in self.cells:s0, s1 = s1, cell(s0, s1, weights)
out = self.global_pooling(s1)logits = self.classifier(out.view(out.size(0), -1))return logits
def _loss(self, input, target):logits = self(input)# 添加L1正则化reg_loss = 0.01 * torch.sum(torch.exp(-self._alphas))return self._criterion(logits, target) + reg_loss
def arch_parameters(self):return [self._alphas]
def genotype(self):"""从架构参数导出离散架构"""
def _parse(weights):gene = []start = 0for i in range(self._steps):end = start + i + 2W = weights[start:end].copy()edges = []for j in range(2 + i):k_best = Nonefor k in range(len(W[j])):if k_best is None or W[j][k] > W[j][k_best]:k_best = kedges.append((list(OPS.keys())[k_best], j)) # 修正OPS.keys()索引gene.append(edges)start = endreturn gene
gene_normal = _parse(F.softmax(self._alphas, dim=-1).data.cpu().numpy())return gene_normal
def plot_genotype(self, filename):"""可视化基因型"""dot = Digraph(format='png')
for i, edges in enumerate(self.genotype()):for op, j in edges:dot.edge(str(j), str(i + 2), label=op)
dot.node("0", fillcolor='lightblue', style='filled')dot.node("1", fillcolor='lightblue', style='filled')
dot.render(filename, view=True)
3. 搜索算法实现
class DARTS:def __init__(self, model, train_loader, val_loader, epochs=50):self.model = model.to(device)self.train_loader = train_loaderself.val_loader = val_loaderself.epochs = epochs
# 优化器self.optimizer = torch.optim.SGD(model.parameters(), lr=0.025, momentum=0.9, weight_decay=3e-4)self.scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(self.optimizer, epochs, eta_min=0.001)
# 架构搜索参数self.arch_optimizer = torch.optim.Adam(model.arch_parameters(), lr=3e-4, betas=(0.5, 0.999))
def _train(self):self.model.train()train_loss = 0correct = 0total = 0
for inputs, targets in self.train_loader:inputs, targets = inputs.to(device), targets.to(device)
# 更新架构参数self.arch_optimizer.zero_grad()arch_loss = self.model._loss(inputs, targets)arch_loss.backward()self.arch_optimizer.step()
# 更新模型权重self.optimizer.zero_grad()loss = self.model._loss(inputs, targets)loss.backward()nn.utils.clip_grad_norm_(self.model.parameters(), 5.0)self.optimizer.step()
train_loss += loss.item()_, predicted = self.model(inputs).max(1)total += targets.size(0)correct += predicted.eq(targets).sum().item()
return train_loss / len(self.train_loader), 100. * correct / total
def _validate(self):self.model.eval()val_loss = 0correct = 0total = 0
with torch.no_grad():for inputs, targets in self.val_loader:inputs, targets = inputs.to(device), targets.to(device)outputs = self.model(inputs)loss = self.model._loss(inputs, targets)
val_loss += loss.item()_, predicted = outputs.max(1)total += targets.size(0)correct += predicted.eq(targets).sum().item()
return val_loss / len(self.val_loader), 100. * correct / total
def search(self):best_acc = 0history = {'train_loss': [], 'val_loss': [], 'train_acc': [], 'val_acc': []}
for epoch in range(self.epochs):train_loss, train_acc = self._train()val_loss, val_acc = self._validate()self.scheduler.step()
history['train_loss'].append(train_loss)history['val_loss'].append(val_loss)history['train_acc'].append(train_acc)history['val_acc'].append(val_acc)
if val_acc > best_acc:best_acc = val_accbest_genotype = copy.deepcopy(self.model.genotype())
print(f"Epoch: {epoch + 1}/{self.epochs} | "f"Train Loss: {train_loss:.4f} | Val Loss: {val_loss:.4f} | "f"Train Acc: {train_acc:.2f}% | Val Acc: {val_acc:.2f}%")
return best_genotype, history
4. 完整训练流程
# 数据准备
def prepare_data(batch_size=64, val_ratio=0.1):transform = 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))])
full_dataset = datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)val_size = int(val_ratio * len(full_dataset))train_size = len(full_dataset) - val_size
train_dataset, val_dataset = torch.utils.data.random_split(full_dataset, [train_size, val_size])
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True, num_workers=2)val_loader = DataLoader(val_dataset, batch_size=batch_size, shuffle=False, num_workers=2)
return train_loader, val_loader
# 主函数
def main():train_loader, val_loader = prepare_data()
# 初始化模型criterion = nn.CrossEntropyLoss().to(device)model = Network(C=16, num_classes=10, layers=8, criterion=criterion)
# 开始搜索darts = DARTS(model, train_loader, val_loader, epochs=50)best_genotype, history = darts.search()
# 保存结果print("Best Genotype:", best_genotype)model.plot_genotype("best_architecture")
# 绘制训练曲线plt.figure(figsize=(12, 4))plt.subplot(1, 2, 1)plt.plot(history['train_loss'], label='Train')plt.plot(history['val_loss'], label='Validation')plt.title('Loss Curve')plt.legend()
plt.subplot(1, 2, 2)plt.plot(history['train_acc'], label='Train')plt.plot(history['val_acc'], label='Validation')plt.title('Accuracy Curve')plt.legend()
plt.savefig('search_progress.png')plt.show()
if __name__ == "__main__":main()
输出为:
使用设备: cuda
Files already downloaded and verified
Epoch: 1/50 | Train Loss: 2.3124 | Val Loss: 2.1910 | Train Acc: 46.93% | Val Acc: 55.88%
Epoch: 2/50 | Train Loss: 1.3163 | Val Loss: 1.1209 | Train Acc: 67.39% | Val Acc: 68.60%
Epoch: 3/50 | Train Loss: 1.0027 | Val Loss: 0.8909 | Train Acc: 75.54% | Val Acc: 75.54%
Epoch: 4/50 | Train Loss: 0.8162 | Val Loss: 0.7608 | Train Acc: 80.52% | Val Acc: 79.12%
Epoch: 5/50 | Train Loss: 0.7098 | Val Loss: 0.7313 | Train Acc: 83.37% | Val Acc: 79.44%
Epoch: 6/50 | Train Loss: 0.6268 | Val Loss: 0.6517 | Train Acc: 85.73% | Val Acc: 82.10%
Epoch: 7/50 | Train Loss: 0.5662 | Val Loss: 0.6084 | Train Acc: 87.38% | Val Acc: 83.04%
Epoch: 8/50 | Train Loss: 0.5164 | Val Loss: 0.5669 | Train Acc: 88.96% | Val Acc: 84.56%
Epoch: 9/50 | Train Loss: 0.4790 | Val Loss: 0.5206 | Train Acc: 90.14% | Val Acc: 85.66%
Epoch: 10/50 | Train Loss: 0.4447 | Val Loss: 0.5097 | Train Acc: 91.23% | Val Acc: 85.64%
Epoch: 11/50 | Train Loss: 0.4135 | Val Loss: 0.5081 | Train Acc: 92.16% | Val Acc: 85.78%
Epoch: 12/50 | Train Loss: 0.3887 | Val Loss: 0.5135 | Train Acc: 92.81% | Val Acc: 85.76%
Epoch: 13/50 | Train Loss: 0.3687 | Val Loss: 0.4952 | Train Acc: 93.40% | Val Acc: 86.02%
Epoch: 14/50 | Train Loss: 0.3490 | Val Loss: 0.4915 | Train Acc: 94.02% | Val Acc: 86.72%
Epoch: 15/50 | Train Loss: 0.3323 | Val Loss: 0.5027 | Train Acc: 94.69% | Val Acc: 86.20%
Epoch: 16/50 | Train Loss: 0.3109 | Val Loss: 0.4722 | Train Acc: 95.34% | Val Acc: 87.44%
Epoch: 17/50 | Train Loss: 0.2952 | Val Loss: 0.4687 | Train Acc: 95.74% | Val Acc: 87.14%
Epoch: 18/50 | Train Loss: 0.2780 | Val Loss: 0.4605 | Train Acc: 96.38% | Val Acc: 87.92%
Epoch: 19/50 | Train Loss: 0.2591 | Val Loss: 0.4469 | Train Acc: 96.82% | Val Acc: 88.26%
Epoch: 20/50 | Train Loss: 0.2474 | Val Loss: 0.4479 | Train Acc: 97.22% | Val Acc: 88.04%
Epoch: 21/50 | Train Loss: 0.2371 | Val Loss: 0.4765 | Train Acc: 97.46% | Val Acc: 87.90%
Epoch: 22/50 | Train Loss: 0.2257 | Val Loss: 0.4213 | Train Acc: 97.78% | Val Acc: 89.00%
Epoch: 23/50 | Train Loss: 0.2100 | Val Loss: 0.4625 | Train Acc: 98.21% | Val Acc: 88.38%
Epoch: 24/50 | Train Loss: 0.2045 | Val Loss: 0.4474 | Train Acc: 98.24% | Val Acc: 88.74%
Epoch: 25/50 | Train Loss: 0.1859 | Val Loss: 0.4511 | Train Acc: 98.60% | Val Acc: 88.48%
Epoch: 26/50 | Train Loss: 0.1790 | Val Loss: 0.4307 | Train Acc: 98.81% | Val Acc: 89.54%
Epoch: 27/50 | Train Loss: 0.1644 | Val Loss: 0.4390 | Train Acc: 99.08% | Val Acc: 89.80%
Epoch: 28/50 | Train Loss: 0.1541 | Val Loss: 0.4344 | Train Acc: 99.17% | Val Acc: 89.60%
Epoch: 29/50 | Train Loss: 0.1449 | Val Loss: 0.4176 | Train Acc: 99.32% | Val Acc: 90.34%
Epoch: 30/50 | Train Loss: 0.1352 | Val Loss: 0.3915 | Train Acc: 99.47% | Val Acc: 90.64%
Epoch: 31/50 | Train Loss: 0.1261 | Val Loss: 0.4300 | Train Acc: 99.58% | Val Acc: 90.20%
Epoch: 32/50 | Train Loss: 0.1183 | Val Loss: 0.3936 | Train Acc: 99.67% | Val Acc: 91.10%
Epoch: 33/50 | Train Loss: 0.1056 | Val Loss: 0.3889 | Train Acc: 99.77% | Val Acc: 91.00%
Epoch: 34/50 | Train Loss: 0.0990 | Val Loss: 0.3937 | Train Acc: 99.81% | Val Acc: 91.00%
Epoch: 35/50 | Train Loss: 0.0949 | Val Loss: 0.3694 | Train Acc: 99.77% | Val Acc: 92.16%
Epoch: 36/50 | Train Loss: 0.0862 | Val Loss: 0.3788 | Train Acc: 99.89% | Val Acc: 91.72%
Epoch: 37/50 | Train Loss: 0.0815 | Val Loss: 0.3893 | Train Acc: 99.90% | Val Acc: 91.52%
Epoch: 38/50 | Train Loss: 0.0768 | Val Loss: 0.3847 | Train Acc: 99.92% | Val Acc: 91.92%
Epoch: 39/50 | Train Loss: 0.0729 | Val Loss: 0.3602 | Train Acc: 99.95% | Val Acc: 91.90%
Epoch: 40/50 | Train Loss: 0.0689 | Val Loss: 0.3846 | Train Acc: 99.94% | Val Acc: 91.68%
Epoch: 41/50 | Train Loss: 0.0656 | Val Loss: 0.3361 | Train Acc: 99.95% | Val Acc: 92.62%
Epoch: 42/50 | Train Loss: 0.0625 | Val Loss: 0.3563 | Train Acc: 99.96% | Val Acc: 92.18%
Epoch: 43/50 | Train Loss: 0.0598 | Val Loss: 0.3475 | Train Acc: 99.96% | Val Acc: 92.28%
Epoch: 44/50 | Train Loss: 0.0579 | Val Loss: 0.3468 | Train Acc: 99.94% | Val Acc: 92.22%
Epoch: 45/50 | Train Loss: 0.0561 | Val Loss: 0.3680 | Train Acc: 99.94% | Val Acc: 91.64%
Epoch: 46/50 | Train Loss: 0.0532 | Val Loss: 0.3334 | Train Acc: 99.95% | Val Acc: 92.40%
Epoch: 47/50 | Train Loss: 0.0509 | Val Loss: 0.3381 | Train Acc: 99.96% | Val Acc: 92.50%
Epoch: 48/50 | Train Loss: 0.0493 | Val Loss: 0.3517 | Train Acc: 99.95% | Val Acc: 92.16%
Epoch: 49/50 | Train Loss: 0.0474 | Val Loss: 0.3305 | Train Acc: 99.95% | Val Acc: 92.30%
Epoch: 50/50 | Train Loss: 0.0458 | Val Loss: 0.3305 | Train Acc: 99.94% | Val Acc: 92.84%
Best Genotype: [[('conv_5x5', 0), ('conv_5x5', 1)], [('none', 0), ('conv_5x5', 1), ('conv_5x5', 2)], [('conv_5x5', 0), ('conv_5x5', 1), ('conv_5x5', 2), ('conv_5x5', 3)], [('conv_5x5', 0), ('conv_5x5', 1), ('conv_5x5', 2), ('conv_5x5', 3), ('conv_5x5', 4)]]
perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:LANGUAGE = (unset),LC_ALL = (unset),LC_CTYPE = "C.UTF-8",LANG = "en_US.UTF-8"are supported and installed on your system.
perl: warning: Falling back to the standard locale ("C").
Error: no "view" mailcap rules found for type "image/png"
/usr/bin/xdg-open: 869: www-browser: not found
/usr/bin/xdg-open: 869: links2: not found
/usr/bin/xdg-open: 869: elinks: not found
/usr/bin/xdg-open: 869: links: not found
/usr/bin/xdg-open: 869: lynx: not found
/usr/bin/xdg-open: 869: w3m: not found
xdg-open: no method available for opening 'best_architecture.png'
错误提示 Error: no "view" mailcap rules found for type "image/png" 是因为系统缺少图片查看工具(如浏览器)
不影响结果:文件 best_architecture.png 仍会生成,但无法自动弹出预览。
三、进阶话题
1. 搜索空间设计技巧
class MacroSearchSpace:"""宏架构搜索空间示例"""def __init__(self):self.resolutions = [224, 192, 160, 128] # 输入分辨率self.depths = [3, 4, 5, 6] # 网络深度self.widths = [32, 64, 96, 128] # 初始通道数self.ops = OPS.keys() # 操作类型
2. 多目标NAS实现
class MultiObjectiveNAS:"""同时优化精度和延迟"""def __init__(self, model, latency_predictor):self.model = modelself.latency_predictor = latency_predictordef evaluate(self, genotype):# 预测延迟latency = self.latency_predictor(genotype)# 评估精度accuracy = evaluate_accuracy(genotype)return {'accuracy': accuracy,'latency': latency,'score': accuracy * (latency ** -0.07) # 平衡因子}
3. 实际应用建议
场景 | 推荐方法 | 理由 |
---|---|---|
移动端部署 | ProxylessNAS | 直接优化目标设备指标 |
研究探索 | DARTS | 灵活可扩展 |
工业级应用 | ENAS | 搜索效率高 |
四、总结与展望
本文实现了基于DARTS的神经架构搜索系统,主要亮点包括:
-
完整实现了可微分架构搜索:包括混合操作、细胞结构和双层优化
-
可视化搜索过程:支持架构基因型的图形化展示
-
实用训练技巧:采用余弦退火学习率等优化策略
在下一篇文章中,我们将探讨图生成模型与分子设计,介绍如何利用深度生成模型设计新型分子结构。
相关文章:
PyTorch 深度学习实战(34):神经架构搜索(NAS)实战
在上一篇文章中,我们探讨了联邦学习与隐私保护技术。本文将深入介绍神经架构搜索(Neural Architecture Search, NAS)这一自动化机器学习方法,它能够自动设计高性能的神经网络架构。我们将使用PyTorch实现基于梯度优化的DARTS方法&…...
【python】速通笔记
Python学习路径 - 从零基础到入门 环境搭建 安装Python Windows: 从官网下载安装包 https://www.python.org/downloads/Mac/Linux: 通常已预装,可通过终端输入python3 --version检查 配置开发环境 推荐使用VS Code或PyCharm作为代码编辑器安装Python扩展插件创建第…...
简易Minecraft python
废话多说 以下是一个基于Python和ModernGL的简化版3D沙盒游戏框架。由于代码长度限制,这里提供一个核心实现(约500行),您可以通过添加更多功能和内容来扩展它: python import pygame import moderngl import numpy a…...
Linux信号处理解析:从入门到实战
Linux信号处理全解析:从入门到实战 一、初识Linux信号:系统级的"紧急电话" 信号是什么? 信号是Linux系统中进程间通信的"紧急通知",如同现实中的交通信号灯。当用户按下CtrlC(产生SIGINT信号&…...
2025-04-04 Unity 网络基础5——TCP分包与黏包
文章目录 1 分包与黏包2 解决方案2.1 数据接口2.2 定义消息2.3 NetManager2.4 分包、黏包处理 3 测试3.1 服务端3.2 客户端3.3 直接发送3.4 黏包发送3.5 分包发送3.6 分包、黏包发送3.7 其他 1 分包与黏包 分包、黏包指在网络通信中由于各种因素(网络环境、API …...
Ubuntu 安装 JMeter:为你的服务器配置做好准备
Apache JMeter 是一个开源的负载测试工具,可以用于测试静态和动态资源,确定服务器的性能和稳定性。在本文中,我们将讨论如何下载和安装 JMeter。 安装 Java(已安装 Java 的此步骤可跳过) 要下载 Java,请遵…...
swift-oc和swift block和代理
一、闭包或block 1.1、swift 闭包表达式作为参数的形式 一、闭包的定义 func exec(v1: Int, v2: Int, fn: (Int, Int) -> Int) { print(fn(v1, v2)) } 二、调用 exec(v1: 10, v2: 20, fn: { (v1: Int, v2: Int) -> Int in return v1 v2 }) 1.2、swift 闭包表达式作为…...
【数据结构】_队列
hello 友友们~ 今天我们要开始学习队列啦~ 话不多说,让我们开始吧!GO! 1.队列的概念及结构 队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表。 队列具有先进先出FIFO(First In First Out) 入队列&#x…...
【软考中级软件设计师】数据表示:原码、反码、补码、移码、浮点数
数据表示 一、数据表示1、整数的表示(1) 原码(2) 反码(3) 补码:(4) 移码 2、浮点数的表示(IEEE 754标准) 一、数据表示 计算机使用的是二进制,也就是0和1的组合。所有的数据,无论是数字、文字还是图片、声音ÿ…...
Linux(十二)信号
今天我们就要来一起学习信号啦!!!还记得小编在之前的文章中说过的ctrlc吗?之前小编没有详细介绍过,现在我们就要来学习啦!!! 一、信号的基本介绍 首先,小编带领大家先一…...
迪杰斯特拉+二分+优先队列+拓扑+堆优化(奶牛航线Cowroute、架设电话线dd、路障Roadblocks、奶牛交通Traffic)
原文地址 https://fmcraft.top/index.php/Programming/2025040402.html 主要算法 迪杰斯特拉Dijkstra 题目列表 P1:奶牛航线Cowroute 题目描述 题目描述 Bessie已经厌倦了农场冬天的寒冷气候,她决定坐飞机去更温暖的地方去度假。不幸的是…...
【数据结构】树的介绍
目录 一、树1.1什么是树?1.2 树的概念与结构1.3树的相关术语1.4 树形结构实际运用场景 二、二叉树2.1 概念与结构2.2 特殊的二叉树2.2.1 满二叉树2.2.2 完全二叉树 个人主页,点击这里~ 数据结构专栏,点击这里~ 一、树 1.1什么是树࿱…...
【CF】Day24——Codeforces Round 994 (Div. 2) D
D. Shift Esc 题目: 思路: 典DP的变种 如果这一题没有这个变换操作,那么是一个很典型的二维dp,每一个格子我们都选择上面和左边中的最小值即可 而这题由于可以变换,那我们就要考虑变换操作,首先一个显然…...
Python 字典
Python 字典 字典的介绍 字典不仅可以保存值,还能对值进行描述使用大括号来表示一个字典,不仅有值 value ,还有值的描述 key字典里的数据都是以键值对 key-value 的形式来保留的key 和 value 之间用冒号 : 来连接多个键值对之间用逗号 , 来…...
yolov12检测 聚类轨迹运动速度
目录 分割算法api版: 分割算法: yolo_kmean.py 优化版: 第1步,检测生成json 第2步骤聚类: 分割算法api版: import json import os from glob import globimport cv2 import imageio import numpy as np from scipy.ndimage import gaussian_filter1d from scipy.s…...
【Lua】pcall使用详解
目录 基本语法核心作用基础示例示例 1:捕获一个简单错误示例 2:调用不存在的函数 高级用法1. 传递多个参数和接收多个返回值2. 捕获带 error 主动抛出的错误3. 匿名函数与 pcall 使用场景注意事项总结 在 Lua 中,pcall(Protected …...
Floyd 算法 Java
图论算法实践:使用 Floyd 求任意两点最短路(Java 实现) 在图论算法中,Floyd-Warshall 算法是一个经典的动态规划算法,用于在一个加权图中寻找所有点对之间的最短路径。 场景描述 假设我们有一个包含 n 个点的无向图&…...
List结构之非实时榜单实战
像京东、淘宝等电商系统一般都会有热销的商品榜单,比如热销手机榜单,热销电脑榜单,这些都是非实时的榜单。为什么是非实时的呢?因为完全实时的计算和排序对于资源消耗较大,尤其是当涉及大量交易数据时。 一般来说&…...
OCR的备份与恢复
1.简介 在Oracle RAC环境中,ASM(Automatic Storage Management)管理的OCR(Oracle Cluster Registry)是集群的关键组件,存储集群配置和状态信息。 OCR的备份一般指物理备份,系统默认每4个小时自…...
算法思想之双指针(一)
欢迎拜访:雾里看山-CSDN博客 本篇主题:算法思想之双指针(一) 发布时间:2025.4.4 隶属专栏:算法 目录 双指针算法介绍对撞指针:快慢指针: 例题移动零题目链接题目描述算法思路代码实现 复写零题目链接题目描…...
Pascal语言的设备管理
Pascal语言的设备管理 引言 在计算机科学中,设备管理是操作系统的重要组成部分之一。设备管理指的是操作系统对外部设备的控制和协调,实现对各种设备的有效利用。Pascal语言作为一种教育性编程语言,虽然最初并不是为了直接进行设备管理而设…...
【MySQL】DML:添加-修改-删除数据 (数据操作语言) 学习笔记
DML (数据操作语言) 学习笔记 1. 数据表结构 首先创建员工表 employee: CREATE TABLE employee (id int unsigned NOT NULL AUTO_INCREMENT COMMENT ID,username varchar(20) NOT NULL COMMENT 用户名,password varchar(32) DEFAULT 123456 COMMENT 密码,name va…...
React编程高级主题:背压(Backpressure)处理
文章目录 **5.1 背压(Backpressure)概述****5.1.1 缓冲(Buffer)****1. 基本概念****2. 缓冲的实现方式****3. 适用场景****4. 潜在问题** **5.1.2 丢弃(Drop)****1. 基本概念****2. 丢弃的实现方式****3. 适…...
Spring IoCDI
IoC容器 前⾯我们提到IoC控制反转, 就是将对象的控制权交给Spring的IOC容器 ,由IOC容器创建及管理对 象。 也就是bean的存储. 在类上⾯添加 RestController 和 Controller 注解, 就是把这个对象交给Spring管理 , Spring 框架启动时就会加载该类. 把对象…...
COBOL语言的数据库交互
COBOL语言的数据库交互 引言 随着信息技术的不断发展,数据库管理系统(DBMS)已经成为现代应用程序中不可或缺的组成部分。在众多编程语言中,COBOL(Common Business-Oriented Language)以其在商业应用中的稳…...
【C++11(中)】—— 我与C++的不解之缘(三十一)
一、可变参数模版 基本语法: C11支持可变参数模版,简单来说就是支持可变数量参数的函数模版或者类模版; 可变数目的参数被称为参数包,存在两种参数包:模版参数包(表示0个或者多个模版参数),函数参数包(表示…...
JavaScript学习19-事件类型之鼠标事件
1. 2. 3....
文件或目录损坏且无法读取:数据恢复的实战指南
在数字化时代,数据的重要性不言而喻。然而,在日常使用电脑、移动硬盘、U盘等存储设备时,我们难免会遇到“文件或目录损坏且无法读取”的提示。这一提示如同晴天霹雳,让无数用户心急如焚,尤其是当这些文件中存储着重要的…...
python爬虫:小程序逆向实战教程
根据我之前发表的文章,我们进行延伸实战https://blog.csdn.net/weixin_64809364/article/details/146981598?spm1001.2014.3001.5501 1. 想要爬取什么小程序,我们进行搜索 2. 找到我们vx小程序的文件地址,我们就可以进行破解 破解步骤强看…...
第二十节课:python实例五:身体质量指数BMI计算
python实例五:身体质量指数BMI计算 一、问题分析 BMI计算公式: BMI 体重(kg) / 身高(m)^2国际与国内标准对比 分类国际标准国内标准偏瘦<18.5<18.5正常18.5-2518.5-24偏胖25-3024-28肥胖≥30≥28 二、实现要点 输入处理 # 同时接收身高体重…...
八、重学C++—动态多态(运行期)
上一章节: 七、重学C—静态多态(编译期)-CSDN博客https://blog.csdn.net/weixin_36323170/article/details/146999362?spm1001.2014.3001.5502 本章节代码: cpp/dynamicPolymorphic.cpp CuiQingCheng/cppstudy - 码云 - 开源中…...
思维链 Chain-of-Thought(COT)
思维链 Chain-of-Thought(COT):思维链的启蒙 3. 思维链 Chain-of-Thought(COT)存在问题?2. 思维链 Chain-of-Thought(COT)是思路是什么?1. 什么是 思维链 Chain-of-Thoug…...
React框架的Fiber架构
以下是关于 Fiber 架构 的系统梳理: 一、Fiber 架构的出现背景 React 15 及之前的问题 同步递归渲染:虚拟DOM的diff过程不可中断,导致主线程长时间阻塞。掉帧问题:复杂组件树渲染时,用户交互无法及时响应。无法实现增量渲染:无法拆分任务优先级,无法利用浏览器空闲时间。…...
PCI与PCIe接口的通信架构是主从模式吗?
PCI(Peripheral Component Interconnect)总线在通信架构上本质是主从模式,但其具体实现和角色分配在不同版本(如传统PCI与PCI Express)中存在差异。以下是详细分析: 传统PCI总线的主从模式 (1) 基本架构 主…...
【2011】【论文笔记】THz保护文化遗产——
前言 类型 太赫兹 + 文化保护 太赫兹 + 文化保护 太赫兹+文化保护 期刊 I E E E T R A N S A C T I O N S O N T E R A H E R...
状态机思想编程练习
状态机实现LED流水灯 本次实验,我们将利用状态机的思想来进行Verilog编程实现一个LED流水灯,并通过Modelsim来进行模拟仿真,再到DE2-115开发板上进行验证。 首先进行主要代码的编写。 module led (input sys_clk,input sys_…...
三部门新政力推智能家居 居然智家数智化转型迎利好东风
2025年3月,工业和信息化部、教育部、市场监管总局联合印发《轻工业数字化转型实施方案》,明确提出重点培育智能家居、智能穿戴、智能骑行、智慧养老等消费端场景,深化人工智能技术在家电、家具等领域的应用,推动产业链供应链智能化…...
CCF GESP C++编程 七级认证真题 2025年3月
C 七级 2025 年 03 月 题号 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 答案 B A B C B B B A D D A C B B D 一、单选题 第 1 题 下列哪个选项是C中的关键字? A. function B. class C. method D. object 第 2 题 下面代码输出的是() int main()…...
【MySQL】navicat16 result字段识别不了
在mysql里面使用result字段 打印出来为空 之后换了个字段命名 使用outcome 成功能打印出来了。。 不知道是不是版本的问题...
【教学类-102-02】自制剪纸图案(留白边、沿线剪)02——Python+PS自动化添加虚线边框
背景需求: 01版本实现了对透明背景png图案边界线的扩展,黑线实线描边 【教学类-102-01】自制剪纸图案(留白边、沿线剪)01-CSDN博客文章浏览阅读974次,点赞15次,收藏7次。【教学类-102-01】自制剪纸图案(留白边、沿线剪)01https://blog.csdn.net/reasonsummer/article…...
CExercise_05_1函数_1.1素数(要对键盘录入的数据做参数校验)
题目: 编写函数实现以下功能: 键盘录入一个正整数,请判断它是否是一个素数,然后控制台输出对应的结果。要对键盘录入的数据做参数校验,素数是一个大于1的自然数,它仅能被1和自身整除。 关键点 分析…...
运算放大器(五)电压比较器
比较器在最常用的简单集成电路中排名第二,仅次于排名第一的运算放大器。 电压比较器是一种用来比较输入信号电压与参考电压大小,并将比较结果以高电平或低电平形式输出的一种信号处理电路,广泛应用于各种非正弦波的产生和变换电路中…...
蓝桥杯_PCF8591
目录 一 前言 二 引言 三 PCF8591介绍 (1)I2C通信 (2)原理图中的8591 四 代码层面 (1)根据题目所给的示范代码,实现ADC 1 为什么需要返回值,同时返回值是unsigned char&#x…...
Windows修改hosts文件让向日癸软件联网
Windows修改hosts文件让向日癸软件联网 前言一、查看向日葵软件使用的网址及IP1.清除dns记录2.打开向日葵软件并将dns记录导出txt 二、修改Windows服务器的hosts文件1.winx选择Windows PowerShell(管理员)2.在Windows PowerShell中输入如下内容:3.在hosts文件最后添…...
[MySQL初阶]MySQL数据类型
MySQL数据类型 1. 数据类型分类2. 数值类型2.1 tinyint类型2.2 bit类型2.3 float类型2.4 decimal类型3. 字符串类型3.1 char3.2 varchar3.3 日期和时间类型3.4 enum和set1. 数据类型分类 数据库中的类型决定了在存储位置中,占据的空间大小以及如何识别的问题。 2. 数值类型 2…...
JS用ES6和ES5分别实现:8字节长整数和字节数组的互转
🧑 博主简介:CSDN博客专家,历代文学网(PC端可以访问:https://literature.sinhy.com/#/?__c1000,移动端可微信小程序搜索“历代文学”)总架构师,15年工作经验,精通Java编…...
【学Rust写CAD】29 Alpha256结构体(alpha256.rs)
源码 #[derive(Clone, Copy)] pub struct Alpha256(u32);impl Alpha256{#[inline]pub fn from(alpha:u32)->Alpha256{Alpha256(alpha1)}// Calculates 256 - (value * alpha256) / 255 in range [0,256],// for [0,255] value and [0,256] alpha256.#[inline]fn alpha_mul_…...
Titanic - Machine Learning from Disaster
数据集 通过网盘分享的文件: 链接: https://pan.baidu.com/s/17TLeF8PW2GSWTbAIJC69-A?pwd4dak 提取码: 4dak 准备工作 # 导入必要的库 import numpy as np # 用于数值计算(如矩阵运算、数学函数等) import pandas as pd # 用于数据…...
GoFrame框架中Prometheus Metric组件监控的优势与实践
文章摘要 GoFrame 是一款轻量、高效且模块化的 Go 语言全能型框架,在 Go 生态中以其企业级应用能力和简洁设计受到开发者青睐。随着微服务架构的普及,性能监控成为开发中不可或缺的一环,而 Prometheus 凭借其强大的时间序列数据处理能力和灵…...
SQL语言的物联网
以SQL语言的物联网 引言 物联网(IoT,Internet of Things)作为一个新兴的技术领域,正迅速改变着我们的生活方式和工作模式。它通过将各种物体连接到互联网,实现了设备之间的智能通信与数据交换。随着物联网的普及&…...