从零开始:使用 PyTorch 构建深度学习网络
从零开始:使用 PyTorch 构建深度学习网络
目录
- PyTorch 简介
- 环境配置
- PyTorch 基础
- 构建神经网络
- 训练模型
- 评估与测试
- 案例实战:手写数字识别
- 进阶技巧
- 常见问题解答
PyTorch 简介
PyTorch 是一个开源的深度学习框架,由 Facebook(现在的 Meta)的人工智能研究团队开发。它以其动态计算图和简洁的 API 而受到广泛欢迎,尤其在学术研究领域。与其他深度学习框架相比,PyTorch 的特点是直观、灵活且易于调试。
为什么选择 PyTorch?
- Python 友好:PyTorch 的设计理念非常符合 Python 的编程风格,如果你熟悉 NumPy,学习 PyTorch 将会非常顺利。
- 动态计算图:不同于 TensorFlow 1.x 的静态图,PyTorch 使用动态计算图,这意味着你可以在运行时修改网络结构,使调试和实验更加方便。
- 强大的社区支持:庞大的用户基础和丰富的学习资源。
- 良好的生态系统:包括计算机视觉(torchvision)、自然语言处理(transformers)、音频处理(torchaudio)等领域的专用库。
- 现代化 API:PyTorch 2.0+ 提供了编译器优化、更好的性能和更简洁的 API。
环境配置
开始使用 PyTorch 前,需要先配置环境。以下是基本步骤:
安装 PyTorch
推荐使用 Anaconda 或 Miniconda 创建虚拟环境:
# 创建虚拟环境
conda create -n pytorch_env python=3.11
# 激活环境
conda activate pytorch_env
# 安装 PyTorch(CPU 版本)
conda install pytorch torchvision torchaudio cpuonly -c pytorch
如果你有 NVIDIA GPU,可以安装支持 CUDA 的版本:
# 安装支持 CUDA 的 PyTorch
conda install pytorch torchvision torchaudio pytorch-cuda=12.1 -c pytorch -c nvidia
你也可以使用 pip 安装最新版本:
# CPU 版本
pip install torch torchvision torchaudio# GPU 版本 (CUDA 12.1)
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121
验证安装
创建一个简单的 Python 脚本来验证 PyTorch 是否正确安装:
import torch# 打印 PyTorch 版本
print(f"PyTorch 版本: {torch.__version__}")# 检查 GPU 是否可用
print(f"GPU 是否可用: {torch.cuda.is_available()}")
if torch.cuda.is_available():print(f"GPU 名称: {torch.cuda.get_device_name(0)}")# 检查 MPS(适用于 Apple Silicon)
print(f"MPS 是否可用: {getattr(torch, 'has_mps', False)}")
PyTorch 基础
在构建神经网络前,先了解 PyTorch 的核心概念。
张量(Tensor)
张量是 PyTorch 中的基本数据结构,类似于 NumPy 的多维数组,但可以在 GPU 上运行计算。
import torch# 创建张量
x = torch.tensor([[1, 2], [3, 4]])
print(x)
print(f"Shape: {x.shape}")
print(f"Data type: {x.dtype}")# 创建特定类型的张量
x_float = torch.tensor([[1, 2], [3, 4]], dtype=torch.float32)
print(x_float)# 常用的张量创建函数
zeros = torch.zeros(2, 3)
ones = torch.ones(2, 3)
rand = torch.rand(2, 3) # 均匀分布 [0,1)
randn = torch.randn(2, 3) # 标准正态分布print(f"Zeros:\n{zeros}")
print(f"Ones:\n{ones}")
print(f"Random (uniform):\n{rand}")
print(f"Random (normal):\n{randn}")
张量运算
PyTorch 提供了丰富的张量运算函数:
import torch# 创建两个张量
a = torch.tensor([[1, 2], [3, 4]], dtype=torch.float32)
b = torch.tensor([[5, 6], [7, 8]], dtype=torch.float32)# 基本算术运算
print(f"a + b = \n{a + b}")
print(f"a - b = \n{a - b}")
print(f"a * b = \n{a * b}") # 元素级乘法
print(f"a / b = \n{a / b}")# 矩阵乘法
print(f"矩阵乘法 a @ b = \n{a @ b}")
# 或使用 torch.matmul
print(f"torch.matmul(a, b) = \n{torch.matmul(a, b)}")# 其他常用运算
print(f"Sum: {a.sum()}")
print(f"Mean: {a.mean()}")
print(f"Max: {a.max()}")
print(f"Min: {a.min()}")
自动微分
PyTorch 的核心功能之一是自动计算梯度,这是深度学习训练的基础:
import torch# 创建需要梯度的张量
x = torch.tensor([[1., 2.], [3., 4.]], requires_grad=True)
print(x)# 进行一些操作
y = x * 2
z = y.sum()
print(f"z = {z}")# 反向传播计算梯度
z.backward()# 查看 x 的梯度
print(f"梯度 dz/dx = \n{x.grad}") # 应该全是 2
构建神经网络
PyTorch 提供了 nn
模块,包含构建神经网络所需的各种组件。
线性层与激活函数
最基本的神经网络由线性层和激活函数组成:
import torch
import torch.nn as nn# 定义一个简单的全连接层
linear = nn.Linear(in_features=10, out_features=5)# 创建输入数据(批量大小为3,每个样本有10个特征)
x = torch.randn(3, 10)# 前向传播
output = linear(x)
print(f"输入形状: {x.shape}")
print(f"输出形状: {output.shape}")# 激活函数
relu = nn.ReLU()
sigmoid = nn.Sigmoid()
tanh = nn.Tanh()# 应用激活函数
print(f"ReLU: {relu(output)}")
print(f"Sigmoid: {sigmoid(output)}")
print(f"Tanh: {tanh(output)}")
定义神经网络类
在 PyTorch 中,神经网络通常通过继承 nn.Module
类来定义:
import torch
import torch.nn as nnclass SimpleNN(nn.Module):def __init__(self, input_size, hidden_size, output_size):super(SimpleNN, self).__init__()# 第一个全连接层self.fc1 = nn.Linear(input_size, hidden_size)# 激活函数self.relu = nn.ReLU()# 第二个全连接层self.fc2 = nn.Linear(hidden_size, output_size)def forward(self, x):# 定义前向传播过程x = self.fc1(x)x = self.relu(x)x = self.fc2(x)return x# 创建网络实例
input_size = 10
hidden_size = 20
output_size = 5
model = SimpleNN(input_size, hidden_size, output_size)# 打印模型结构
print(model)# 创建一个输入样本
x = torch.randn(1, input_size)
# 前向传播
output = model(x)
print(f"输出: {output}")
使用 PyTorch 2.x 的新特性
PyTorch 2.x 引入了一些强大的新特性,比如 torch.compile
,可以显著提高模型性能:
import torch
import torch.nn as nnclass ModernNN(nn.Module):def __init__(self, input_size, hidden_size, output_size):super().__init__()# 使用 Sequential 简化网络定义self.network = nn.Sequential(nn.Linear(input_size, hidden_size),nn.ReLU(),nn.Linear(hidden_size, hidden_size // 2),nn.ReLU(),nn.Linear(hidden_size // 2, output_size))def forward(self, x):return self.network(x)# 创建网络实例
model = ModernNN(input_size=10, hidden_size=32, output_size=5)# 使用 torch.compile 加速模型(PyTorch 2.0+ 新特性)
# 在生产环境运行速度提升可达 2x 或更多
if hasattr(torch, 'compile'):model = torch.compile(model)# 输入数据
x = torch.randn(100, 10) # 批量大小为100的输入# 使用 @torch.inference_mode 可以在推理时降低内存使用
@torch.inference_mode()
def predict(model, x):return model(x)# 调用推理函数
outputs = predict(model, x)
print(f"输出形状: {outputs.shape}")
训练模型
训练神经网络涉及多个步骤:数据准备、定义损失函数、优化器配置和训练循环。
数据加载与预处理
PyTorch 提供了 Dataset
和 DataLoader
类来简化数据处理:
import torch
from torch.utils.data import Dataset, DataLoader
import numpy as np# 创建一个简单的数据集类
class SimpleDataset(Dataset):def __init__(self, size, input_dim, output_dim):# 生成随机数据self.x = torch.randn(size, input_dim)# 生成随机标签(分类问题)self.y = torch.randint(0, output_dim, (size,))def __len__(self):return len(self.x)def __getitem__(self, idx):return self.x[idx], self.y[idx]# 创建数据集实例
dataset = SimpleDataset(size=1000, input_dim=10, output_dim=5)# 创建数据加载器
dataloader = DataLoader(dataset, batch_size=32, shuffle=True)# 查看一个批次的数据
for inputs, labels in dataloader:print(f"Inputs shape: {inputs.shape}")print(f"Labels shape: {labels.shape}")break # 只查看第一个批次
损失函数与优化器
选择合适的损失函数和优化器对模型训练至关重要:
import torch
import torch.nn as nn
import torch.optim as optim# 假设我们已经定义了模型
model = SimpleNN(input_size=10, hidden_size=20, output_size=5)# 定义损失函数(交叉熵损失,适用于分类问题)
criterion = nn.CrossEntropyLoss()# 定义优化器(随机梯度下降)
optimizer = optim.SGD(model.parameters(), lr=0.01)# 其他常用优化器
# Adam 优化器
optimizer_adam = optim.Adam(model.parameters(), lr=0.001)
# RMSprop 优化器
optimizer_rmsprop = optim.RMSprop(model.parameters(), lr=0.001)
训练循环
下面是一个完整的训练循环示例:
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader# 假设我们已经定义了模型、数据集和数据加载器
model = SimpleNN(input_size=10, hidden_size=20, output_size=5)
dataloader = DataLoader(dataset, batch_size=32, shuffle=True)# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)# 训练参数
num_epochs = 10
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model.to(device)# 训练循环
for epoch in range(num_epochs):running_loss = 0.0for inputs, labels in dataloader:# 将数据移到设备(CPU/GPU)inputs, labels = inputs.to(device), labels.to(device)# 清零梯度optimizer.zero_grad()# 前向传播outputs = model(inputs)# 计算损失loss = criterion(outputs, labels)# 反向传播loss.backward()# 更新参数optimizer.step()# 累加损失running_loss += loss.item()# 打印每个 epoch 的平均损失epoch_loss = running_loss / len(dataloader)print(f"Epoch {epoch+1}/{num_epochs}, Loss: {epoch_loss:.4f}")print("训练完成!")
评估与测试
训练后,需要评估模型在测试数据上的性能:
import torch# 切换到评估模式
model.eval()# 创建测试数据集和数据加载器
test_dataset = SimpleDataset(size=200, input_dim=10, output_dim=5)
test_loader = DataLoader(test_dataset, batch_size=32)# 在测试数据上评估
correct = 0
total = 0# 不计算梯度
with torch.no_grad():for inputs, labels in test_loader:inputs, labels = inputs.to(device), labels.to(device)# 前向传播outputs = model(inputs)# 获取预测结果_, predicted = torch.max(outputs.data, 1)# 统计正确预测的数量total += labels.size(0)correct += (predicted == labels).sum().item()# 计算准确率
accuracy = 100 * correct / total
print(f"测试集准确率: {accuracy:.2f}%")# 返回训练模式
model.train()
案例实战:手写数字识别
下面将使用 MNIST 数据集实现一个完整的手写数字识别模型,并应用 PyTorch 的现代特性。
导入必要的库
import torch
import torch.nn as nn
import torch.optim as optim
import torchvision
import torchvision.transforms as transforms
from torch.utils.data import DataLoader
import torch.nn.functional as F
from torch.cuda.amp import GradScaler, autocast # 用于混合精度训练
准备数据
# 数据预处理
transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.1307,), (0.3081,))
])# 下载 MNIST 数据集
train_dataset = torchvision.datasets.MNIST(root='./data', train=True, transform=transform,download=True
)test_dataset = torchvision.datasets.MNIST(root='./data', train=False, transform=transform,download=True
)# 创建数据加载器,使用新的 PyTorch 2.x 的 persistent workers 特性提高数据加载效率
train_loader = DataLoader(train_dataset, batch_size=128, # 更大的批次大小shuffle=True,num_workers=4, # 多进程加载persistent_workers=True, # 保持工作进程活跃,减少启动开销pin_memory=True # 使用固定内存提高GPU传输速度
)test_loader = DataLoader(test_dataset, batch_size=1000, shuffle=False,num_workers=4,persistent_workers=True,pin_memory=True
)
定义现代化的 CNN 模型
class ModernMNISTModel(nn.Module):def __init__(self):super().__init__()# 使用更现代的网络架构self.features = nn.Sequential(nn.Conv2d(1, 32, kernel_size=3, padding=1),nn.BatchNorm2d(32),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=2, stride=2),nn.Conv2d(32, 64, kernel_size=3, padding=1),nn.BatchNorm2d(64),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=2, stride=2),nn.Conv2d(64, 128, kernel_size=3, padding=1),nn.BatchNorm2d(128),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=2, stride=2, padding=1) # 确保尺寸正确)self.classifier = nn.Sequential(nn.AdaptiveAvgPool2d((1, 1)), # 自适应池化到固定尺寸nn.Flatten(),nn.Linear(128, 64),nn.ReLU(inplace=True),nn.Dropout(0.5),nn.Linear(64, 10))def forward(self, x):x = self.features(x)x = self.classifier(x)return x# 创建模型实例
model = ModernMNISTModel()# 使用 torch.compile 编译模型(PyTorch 2.0+)
if hasattr(torch, 'compile'):model = torch.compile(model)
训练与评估完整流程(带混合精度训练)
# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.AdamW(model.parameters(), lr=0.001, weight_decay=1e-4) # 使用 AdamW 替代 Adam
scheduler = torch.optim.lr_scheduler.OneCycleLR( # 使用 OneCycleLR 调度器optimizer, max_lr=0.005, epochs=10, steps_per_epoch=len(train_loader)
)# 设备配置
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model.to(device)# 混合精度训练
scaler = GradScaler()# 训练参数
num_epochs = 10# 训练循环
for epoch in range(num_epochs):model.train() # 设置为训练模式running_loss = 0.0for i, (images, labels) in enumerate(train_loader):images, labels = images.to(device), labels.to(device)# 清零梯度optimizer.zero_grad()# 使用混合精度训练with autocast():# 前向传播outputs = model(images)loss = criterion(outputs, labels)# 反向传播和优化scaler.scale(loss).backward()scaler.step(optimizer)scaler.update()# 更新学习率scheduler.step()running_loss += loss.item()# 每100批次打印统计信息if (i+1) % 100 == 0:print(f'Epoch [{epoch+1}/{num_epochs}], Step [{i+1}/{len(train_loader)}], Loss: {loss.item():.4f}, LR: {scheduler.get_last_lr()[0]:.6f}')# 测试模型model.eval() # 设置为评估模式with torch.no_grad():correct = 0total = 0for images, labels in test_loader:images, labels = images.to(device), labels.to(device)# 使用 torch.inference_mode() 优化推理with torch.inference_mode():outputs = model(images)_, predicted = torch.max(outputs.data, 1)total += labels.size(0)correct += (predicted == labels).sum().item()print(f'Epoch [{epoch+1}/{num_epochs}], 测试准确率: {100 * correct / total:.2f}%')# 保存模型
torch.save({'model_state_dict': model.state_dict(),'optimizer_state_dict': optimizer.state_dict(),'epoch': num_epochs
}, 'mnist_model_modern.pth')print("模型已保存!")# 测试推理性能
import timemodel.eval()
test_images, test_labels = next(iter(test_loader))
test_images = test_images.to(device)# 预热
with torch.inference_mode():for _ in range(10):_ = model(test_images[:10])# 计时
start_time = time.time()
with torch.inference_mode():for _ in range(50):_ = model(test_images)
end_time = time.time()print(f"推理性能: {50 * len(test_images) / (end_time - start_time):.2f} 图像/秒")
进阶技巧
掌握了基础知识后,这里介绍一些提高模型性能的进阶技巧和 PyTorch 的现代特性。
学习率调整
随着训练的进行,适当调整学习率可以帮助模型更好地收敛:
from torch.optim.lr_scheduler import StepLR, ReduceLROnPlateau, CosineAnnealingLR# 每10个 epoch 将学习率乘以 gamma
scheduler = StepLR(optimizer, step_size=10, gamma=0.1)# 当验证损失不再下降时减小学习率
scheduler = ReduceLROnPlateau(optimizer, mode='min', factor=0.1, patience=5)# 余弦退火学习率(在深度学习中表现优异)
scheduler = CosineAnnealingLR(optimizer, T_max=10)# 在训练循环中使用
for epoch in range(num_epochs):# 训练代码...# 更新学习率(取决于scheduler类型)if isinstance(scheduler, ReduceLROnPlateau):scheduler.step(val_loss)else:scheduler.step()
早停法(Early Stopping)
当模型在验证集上的性能不再提升时,停止训练可以防止过拟合:
best_val_loss = float('inf')
patience = 5
counter = 0
best_model_path = 'best_model.pth'for epoch in range(num_epochs):# 训练代码...# 计算验证损失val_loss = validate(model, val_loader, criterion)# 更新最佳损失和检查早停if val_loss < best_val_loss:best_val_loss = val_losscounter = 0# 保存最佳模型torch.save({'model_state_dict': model.state_dict(),'optimizer_state_dict': optimizer.state_dict(),'epoch': epoch,'loss': val_loss,}, best_model_path)print(f"保存最佳模型,验证损失: {val_loss:.4f}")else:counter += 1if counter >= patience:print(f"Early stopping at epoch {epoch+1}")break
使用预训练模型与迁移学习
对于复杂任务,使用预训练模型可以大幅提高性能,PyTorch 2.x 提供了更简洁的 API:
import torch
import torchvision.models as models# 使用新的 API 加载预训练模型
# weights 参数代替了旧的 pretrained=True
resnet = models.resnet50(weights=models.ResNet50_Weights.IMAGENET1K_V2)# 冻结预训练层
for param in resnet.parameters():param.requires_grad = False# 替换最后的全连接层,适应新任务
num_features = resnet.fc.in_features
resnet.fc = torch.nn.Linear(num_features, num_classes) # 只训练这一层# 也可以使用 HuggingFace 获取最新的预训练模型
# pip install transformers
from transformers import AutoImageProcessor, AutoModelForImageClassification# 加载预训练的视觉模型
processor = AutoImageProcessor.from_pretrained("microsoft/resnet-50")
model = AutoModelForImageClassification.from_pretrained("microsoft/resnet-50")# 加载并预处理图像
from PIL import Image
import requestsurl = "http://images.cocodataset.org/val2017/000000039769.jpg"
image = Image.open(requests.get(url, stream=True).raw)
inputs = processor(images=image, return_tensors="pt")# 使用模型进行推理
with torch.no_grad():outputs = model(**inputs)logits = outputs.logits# 获取预测结果
predicted_class_idx = logits.argmax(-1).item()
print("预测类别:", model.config.id2label[predicted_class_idx])
PyTorch 2.x 的模型加速与部署
PyTorch 2.x 提供了多种模型优化和部署技术:
使用 TorchScript 和 torch.compile
import torch# 定义模型
model = YourModel()
model.eval()# 使用 torch.compile 加速(PyTorch 2.0+)
optimized_model = torch.compile(model, mode='reduce-overhead', # 可选模式: 'default', 'reduce-overhead', 'max-autotune'fullgraph=True
)# 或使用 TorchScript 导出模型
example_input = torch.randn(1, 3, 224, 224)
scripted_model = torch.jit.script(model)
# 或 traced_model = torch.jit.trace(model, example_input)# 保存模型用于部署
scripted_model.save("model_scripted.pt")
量化模型以减小尺寸和加速推理
import torch.quantization# 准备量化
model.eval()
model.qconfig = torch.quantization.get_default_qconfig('fbgemm')
torch.quantization.prepare(model, inplace=True)# 校准模型(需要代表性数据)
with torch.no_grad():for data, _ in calibration_dataloader:model(data)# 转换到量化模型
torch.quantization.convert(model, inplace=True)# 保存量化模型
torch.jit.save(torch.jit.script(model), "quantized_model.pt")
分布式训练
PyTorch 提供了多种分布式训练方法,包括数据并行和模型并行:
import torch.distributed as dist
import torch.multiprocessing as mp
from torch.nn.parallel import DistributedDataParallel as DDPdef setup(rank, world_size):# 初始化进程组dist.init_process_group("nccl", rank=rank, world_size=world_size)def train(rank, world_size):setup(rank, world_size)# 创建模型model = YourModel().to(rank)# 将模型包装为分布式模型ddp_model = DDP(model, device_ids=[rank])# 数据加载器需要修改为分布式sampler = torch.utils.data.distributed.DistributedSampler(dataset,num_replicas=world_size,rank=rank)dataloader = DataLoader(dataset, sampler=sampler, ...)# 训练循环for epoch in range(num_epochs):sampler.set_epoch(epoch) # 确保不同进程看到不同数据for data, target in dataloader:# 常规训练步骤...# 启动多进程训练
world_size = torch.cuda.device_count()
mp.spawn(train, args=(world_size,), nprocs=world_size, join=True)
使用现代 PyTorch 特性进行移动设备部署
PyTorch 提供了 TorchMobile 功能,可以将模型部署到移动设备:
import torch# 准备模型
model = YourModel()
model.eval()# 转换为 TorchScript
example_input = torch.rand(1, 3, 224, 224)
traced_model = torch.jit.trace(model, example_input)# 优化移动设备部署
traced_model_optimized = torch.utils.mobile_optimizer.optimize_for_mobile(traced_model)# 保存为移动格式
traced_model_optimized.save("model_mobile.pt")# 可以进一步转换为适用于更多平台的格式,如 ONNX
torch.onnx.export(model,example_input,"model.onnx",export_params=True,opset_version=12,do_constant_folding=True,input_names=['input'],output_names=['output'],dynamic_axes={'input': {0: 'batch_size'},'output': {0: 'batch_size'}}
)
常见问题解答
如何处理过拟合?
过拟合是指模型在训练数据上表现良好,但在测试数据上表现不佳。解决方法包括:
- 增加数据量:更多样本通常会降低过拟合风险
- 数据增强:通过旋转、缩放等变换增加训练数据的多样性
- 正则化:使用 L1、L2 正则化或 Dropout
- 简化模型:减少模型的复杂度(层数或参数数量)
示例代码(添加 Dropout 和 权重衰减):
# 添加 Dropout
self.dropout = nn.Dropout(0.5) # 在网络中间层添加# 添加权重衰减(L2正则化)
optimizer = optim.Adam(model.parameters(), lr=0.001, weight_decay=1e-4)
GPU 内存不足怎么办?
当模型或数据集过大,GPU 内存不足时:
- 减小批量大小:这是最直接的方法
- 使用梯度累积:累积多个小批量的梯度后再更新参数
- 混合精度训练:使用 float16 代替 float32 进行部分计算
梯度累积示例:
accumulation_steps = 4 # 累积4个批次
optimizer.zero_grad()for i, (inputs, labels) in enumerate(dataloader):outputs = model(inputs)loss = criterion(outputs, labels) / accumulation_steps # 缩小损失loss.backward()if (i + 1) % accumulation_steps == 0:optimizer.step()optimizer.zero_grad()
如何解决梯度消失/爆炸问题?
- 使用 ReLU 等现代激活函数:避免 Sigmoid 和 Tanh 在饱和区的梯度消失
- 批量归一化(Batch Normalization):稳定各层的输入分布
- 梯度裁剪:防止梯度爆炸
- 合理的权重初始化:如 Xavier 或 He 初始化
梯度裁剪示例:
torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
以上就是 PyTorch 深度学习入门的完整指南。
相关文章:
从零开始:使用 PyTorch 构建深度学习网络
从零开始:使用 PyTorch 构建深度学习网络 目录 PyTorch 简介环境配置PyTorch 基础构建神经网络训练模型评估与测试案例实战:手写数字识别进阶技巧常见问题解答 PyTorch 简介 PyTorch 是一个开源的深度学习框架,由 Facebook(现…...
应用层自定义协议与序列化
应用层自定义协议与序列化 应用层协议网络版计算器序列化和反序列化序列化反序列化 重新理解read、write、recv、send和TCP为什么支持全双工代码结构Jsoncpp特性安装序列化使用Json::Value的toStyledString方法使用Json::StreamWriter使用Json::FastWriter 反序列化使用Json::R…...
2025春训第二十场
问题 B: 狗是啥呀 题目描述 在神秘的地狱深处,有着一种神秘的犬类生物,据传这种生物长了x个脑袋,并且具有强大的生命力。由于见过它的人全都下落不明,至今没有人知道它的真面目。 一位勇士为了斩杀这奇怪的生物,来到地…...
分糖果--思维+while判断
1.从左到右只考虑右边一遍,再从右到左考虑左边一遍,相当于左右考虑了 2.然后关键是1遍不一定行,while循环直到成功 https://www.luogu.com.cn/problem/B4091 #include<bits/stdc.h> using namespace std; #define N 100011 typedef …...
[system-design] ByteByteGo_Note Summary
目录 通信协议 REST API 与 GraphQL gRPC 如何工作? 什么是Webhook? 如何提高应用程序接口的性能? HTTP 1.0 -> HTTP 1.1 -> HTTP 2.0 -> HTTP 3.0 (QUIC) SOAP vs REST vs GraphQL vs RPC 代码优先与应用程序接口优先 HTT…...
Flask项目实践:构建功能完善的博客系统(含评论与标签功能)
引言 在Python Web开发领域,Flask以其轻量级、灵活性和易用性赢得了众多开发者的青睐。本文将带您从零开始构建一个功能完善的博客系统,包含文章发布、评论互动和标签分类等核心功能。通过这个实战项目,您不仅能掌握Flask的核心技术…...
Python爬虫实战:获取1688商品信息
在电商领域,获取1688商品信息对于市场分析、竞品研究、用户体验优化等至关重要。1688作为国内领先的B2B电商平台,提供了丰富的商品资源。通过Python爬虫技术,我们可以高效地获取1688商品的详细信息,包括商品名称、价格、图片、描述…...
Canva 推出自有应用生成器以与 Bolt 和 Lovable 竞争
AI 目前是一个巨大的市场,每个人都想从中分一杯羹。 即使是 Canva,这个以拖放图形设计而闻名的流行设计平台,也在其 Canva Create 2025 活动中发布了自己版本的代码生成器,加入了 AI 竞赛。 但为什么一个以设计为先的平台会提供代码生成工具呢? 乍看之下,这似乎有些不…...
多平台屏幕江湖生存指南
UniApp 屏幕适配大师:多平台屏幕江湖生存指南 屏幕江湖:尺寸混战 屏幕适配就像是应对不同体型的客人:从迷你的手机屏,到标准的平板,再到巨大的电视屏幕,你的应用必须有如武林高手般的适应力。 ┌──────────────────────────────────…...
BootCDN介绍(Bootstrap主导的前端开源项目免费CDN加速服务)
文章目录 BootCDN前端开源项目CDN加速服务全解析什么是BootCDN技术原理与架构CDN技术基础BootCDN架构特点1. 全球分布式节点网络2. 智能DNS解析系统3. 高效缓存管理机制4. 自动同步更新机制5. HTTPS和HTTP/2协议支持 BootCDN的核心优势速度与稳定性开源免费资源丰富度技术规范遵…...
LeetCode 153. 寻找旋转排序数组中的最小值:二分查找法详解及高频疑问解析
文章目录 问题描述算法思路:二分查找法关键步骤 代码实现代码解释高频疑问解答1. 为什么循环条件是 left < right 而不是 left < right?2. 为什么比较 nums[mid] > nums[right] 而不是 nums[left] < nums[mid]?3. 为什么 right …...
刷leetcodehot100返航版--二叉树
二叉树理论基础 二叉树的种类 满二叉树和完全二叉树,二叉树搜索树 满二叉树 如果一棵二叉树只有度为0的结点和度为2的结点,并且度为0的结点在同一层上,则这棵二叉树为满二叉树。 节点个数2^n-1【n为树的深度】 完全二叉树 在完全二叉树…...
「Mac畅玩AIGC与多模态41」开发篇36 - 用 ArkTS 构建聚合搜索前端页面
一、概述 本篇基于上一节 Python 实现的双通道搜索服务(聚合 SearxNG 本地知识库),构建一个完整的 HarmonyOS ArkTS 前端页面。用户可在输入框中输入关键词,实时查询本地服务 http://localhost:5001/search?q...,返…...
【LINUX操作系统】生产者消费者模型(下):封装、信号量与环形队列
1.封装、完善基于阻塞队列的productor-consumer module 前文中我们封装了自己的Mutex 【LINUX操作系统】线程同步与互斥-CSDN博客 按照老规矩,现在我们对同步与互斥的理解更进一步了,现在把这种面向过程的语言封装成面向对象的写法 1.1 封装条件变量 #p…...
项目管理学习-CSPM-4考试总结
前言 经过两个月左右时间的学习,今天(2025年5月17日)参加了CSPM-4的考试,仿佛回到了2011年参加软考高项的时候。中午12点考完出来后,手都是酸酸的。不过整体感觉还可以,和预想的差不多。CSPM-4的考试一共有…...
自己手写tomcat项目
一:Servlet的原理 在Servlet(接口中)有: 1.init():初始化servlet 2.getServletConfig():获取当前servlet的配置信息 3.service():服务器(在HttpServlet中实现,目的是为了更好的匹配http的请求方式) 4.g…...
C语言—再学习(结构体)
一、建立结构体 用户自己建立由不同类型数据组成的组合型的数据结构,它称为结构体。 struct Student { int num; //学号char name[20]; //名字为字符串char sex; //性别int age; //年纪float score; //分数char addr[30]; 地址为字符…...
SpringBoot--自动配置原理详解
为什么要学习自动配置原理? 原因:在实际开发中,我们经常会定义一些公共的组件,提供各个团队来使用,为了使用方便,我们经常会将公共的组件自定义成starter,如果想自定义starter,必须…...
MiInsertPageInFreeList函数分析和MmFreePagesByColor数组的关系
第一部分: Color MI_GET_COLOR_FROM_LIST_ENTRY(PageFrameIndex, Pfn1); ColorHead &MmFreePagesByColor[ListName][Color]; 第二部分: #define MI_GET_COLOR_FROM_LIST_ENTRY(index,pfn) \ ((ULONG)(((pfn)->…...
Windows/MacOS WebStorm/IDEA 中开发 Uni-App 配置
文章目录 前言1. 安装 HBuilder X2. WebStorm/IDEA 安装 Uniapp Tool 插件3. 配置 Uniapp Tool 插件4. 运行 Uni-App 项目 前言 前端开发人员对 WebStorm 一定不陌生,但有时需要开发 Uni-App 的需求,就必须要采用 HBuilder X,如果不习惯 HBu…...
redisson分布式锁实现原理归纳总结
Redisson 分布式锁的实现原理主要依赖于 Redis 的 Hash 数据结构、Lua 脚本、发布订阅机制以及看门狗(Watchdog)机制,以下是核心要点总结: 1. 核心原理 • 互斥性与可重入性: 通过 Redis 的 Hash 数据结构保存锁的持…...
Ubuntu 添加系统调用
实验内容 通过内核编译法添加一个不用传递参数的系统调用,其功能可自定义。 (1)添加系统调用号,系统会根据这个号找到syscall_table中的相应表项。具体做法是在syscall_64.tbl文件中添加系统调用号和调用函数的对应关系。 &#…...
Olib 2.2.0 | 免费开源软件,无需注册登录即可从ZLibrary下载多语言电子书
Olib是一款专为书籍爱好者设计的免费开源软件,它允许用户无需注册或登录即可从ZLibrary高速下载各种语言的电子书。该软件支持上百种语言的电子书下载,非常适合需要多语言资源的读者和研究人员使用。Olib的操作界面非常直观,使得书籍的搜索与…...
c++动态链接库
1. 生成动态链接库 首先实现一个动态链接库的代码 // example.cpp #include <iostream> void sayHello() {std::cout << "Hello from shared library!" << std::endl; }int add(int a, int b) {return a b; }// example.h #pragma once void sa…...
HelloWorld
HelloWorld 新建一个java文件 文件后缀名为 .javahello.java【注意】系统可能没有显示文件后缀名,我们需要手动打开 编写代码 public class hello {public static void main(String[] args) {System.out.print(Hello,World)} }编译 javac java文件,会生…...
SVGPlay:一次 CodeBuddy 主动构建的动画工具之旅
我正在参加CodeBuddy「首席试玩官」内容创作大赛,本文所使用的 CodeBuddy 免费下载链接:腾讯云代码助手 CodeBuddy - AI 时代的智能编程伙伴 背景与想法 我一直对 SVG 图标的动画处理有浓厚兴趣,特别是描边、渐变、交互等效果能为图标增添许…...
SLAM定位常用地图对比示例
序号 地图类型 概述 1 格栅地图 将现实环境栅格化,每一个栅格用 0 和 1 分别表示空闲和占据状态,初始化为未知状态 0.5 2 特征地图 以点、线、面等几何特征来描绘周围环境,将采集的信息进行筛选和提取得到关键几何特征 3 拓扑地图 将重要部分抽象为地图,使用简单的图形表示…...
强化学习中,frames(帧)和 episodes(回合)
在强化学习中,frames(帧)和 episodes(回合)是两个不同的概念: 1. 定义差异 Frame(帧): 表示智能体与环境交互的单个时间步(step),例如…...
HCIP第六次作业
一、拓扑图 二、需求 1、使用PreVal策略,确保R4通过R2到达192.168.10.0/24 2、使用AS_Path策略,确保R4通过R3到达192.168.11.0/24 3、配置MED策略,确保R4通过R3到达192.168.12.0/24 4、使用Local Preference策略,确保R1通过R2…...
高频面试题(含笔试高频算法整理)基本总结回顾110
干货分享,感谢您的阅读! (暂存篇---后续会删除,完整版和持续更新见高频面试题基本总结回顾(含笔试高频算法整理)) 备注:引用请标注出处,同时存在的问题请在相关博客留言…...
数据湖与数据仓库融合:Hudi、Iceberg、Delta Lake 实践对比
在实时与离线一体化的今天,数据湖与数据仓库边界不断融合,越来越多企业选用如 Hudi、Iceberg、Delta Lake 等开源方案实现统一的数据存储、计算、分析平台。本篇将围绕以下关键点,展开实战对比与解决方案分享: ✅ 实时写入能力 ✅ ACID 保证 ✅ 增量数据处理能力 ✅ 流批一…...
OGG 更新表频繁导致进程中断,见鬼了?非也!
大家好,这里是 DBA学习之路,专注于提升数据库运维效率。 目录 前言问题描述问题分析解决方案后续 前言 最近几周一直遇到一个 OGG 问题,有一张表已更新就会中断 OGG 同步进程,本文记录一下分析过程以及解决方案。 问题描述 昨天…...
C++学习-入门到精通-【7】类的深入剖析
C学习-入门到精通-【7】类的深入剖析 类的深入剖析 C学习-入门到精通-【7】类的深入剖析一、Time类的实例研究二、组成和继承三、类的作用域和类成员的访问类作用域和块作用域圆点成员选择运算符(.)和箭头成员选择运算符(->)访问函数和工具函数 四、具有默认实参的构造函数重…...
非易失性存储技术综合对比:EEPROM、NVRAM、NOR Flash、NAND Flash和SD卡
非易失性存储技术综合对比:EEPROM、NVRAM、NOR Flash、NAND Flash和SD卡 读写性能对比 存储类型读取速度写入速度随机访问能力最小操作单位NVRAM极快(~10ns)极快(~10ns)极优(字节级)字节EEPROM中等(~100ns)慢(~5ms/字节)优(字节级)字节NOR Flash快(~50ns)慢(~5ms/…...
数字化转型- 数字化转型路线和推进
数字化转型三个阶段 百度百科给出的企业的数字化转型包括信息化、数字化、数智化三个阶段 信息化是将企业在生产经营过程中产生的业务信息进行记录、储存和管理,通过电子终端呈现,便于信息的传播与沟通。数字化通过打通各个系统的互联互通,…...
ARM (Attention Refinement Module)
ARM模块【来源于BiSeNet】:细化特征图的注意力,增强重要特征并抑制不重要的特征。 Attention Refinement Module (ARM) 详解 ARM (Attention Refinement Module) 是 BiSeNet 中用于增强特征表示的关键模块,它通过注意力机制来细化特征图&…...
符合Python风格的对象(对象表示形式)
对象表示形式 每门面向对象的语言至少都有一种获取对象的字符串表示形式的标准方 式。Python 提供了两种方式。 repr() 以便于开发者理解的方式返回对象的字符串表示形式。str() 以便于用户理解的方式返回对象的字符串表示形式。 正如你所知,我们要实现_…...
AtCoder AT_abc406_c [ABC406C] ~
前言 除了 A 题,唯一一道一遍过的题。 题目大意 我们定义满足以下所有条件的一个长度为 N N N 的序列 A ( A 1 , A 2 , … , A N ) A(A_1,A_2,\dots,A_N) A(A1,A2,…,AN) 为波浪序列: N ≥ 4 N\ge4 N≥4(其实满足后面就必须满足这…...
多指标组合策略
该策略(MultiConditionStrategy)是一种基于多种技术指标和市场条件的交易策略。它通过综合考虑多个条件来生成交易信号,从而决定买入或卖出的时机。 以下是对该策略的详细分析: 交易逻辑思路 1. 条件1:星期几和价格变化判断 - 该条件根据当前日期是星期几以及价格的变化…...
系统架构-大数据架构设计
基础介绍 三大挑战: 如何处理非结构化和半结构化数据如何探索大数据复杂性、不确定性特征描述的刻画方法及大数据的系统建模数据异构性与决策异构性的关系对大数据知识发现与管理决策的影响 架构特征: 鲁棒性(稳定性)和容错性…...
R语言空间数据处理入门教程
我的课程《R语言空间数据处理入门教程》已重新恢复课程售卖,有需要的读者可以学习。 👇点击下方链接(文末“阅读原文”可直达),立即开启你的空间数据之旅: https://www.bilibili.com/cheese/play/ss13775…...
QT+EtherCAT 主站协议库—SOEM主站
SOEM 是 Simple Open EtherCAT Master Library 的缩写,是瑞典 rt-lab 提供 的一个开源 EtherCAT 主站协议库 。 SOEM 库使用 C 语言编写,可以在 windows 以及 Linux 平台上运行,并也可以方便地移植到嵌入式平台上。 SOEM 支持 CoE ࿰…...
Java-反射(Reflection)
一:概述 (1)出现背景 (2)解决方案 (3)使用场景 业务开发用的少,框架使用的多,业务反射被认为是动态语言的关键 (4)与原方法对比 (5…...
第一次经历项目上线
这几天没写csdn,因为忙着项目上线的问题,我这阶段改了非常多的前端bug哈哈哈哈,说几个比较好的bug思想! 这个页面算是我遇到的比较大的bug,因为我一开始的逻辑都写好了,询价就是在点击快递公司弹出弹框的时…...
基于C#的MQTT通信实战:从EMQX搭建到发布订阅全解析
MQTT(Message Queueing Telemetry Transport) 消息队列遥测传输,在物联网领域应用的很广泛,它是基于Publish/Subscribe模式,具有简单易用,支持QoS,传输效率高的特点。 它被设计用于低带宽,不稳定或高延迟的…...
DeepSeek超大模型的高效训练策略
算力挑战 训练DeepSeek此类千亿乃至万亿级别参数模型,对算力资源提出了极高要求。以DeepSeek-V3为例,其基础模型参数量为67亿,采用专家混合(MoE)架构后实际激活参数可达几百亿。如此规模的模型远超单张GPU显存容量极限,必须借助分布式并行才能加载和训练。具体挑战主要包…...
【论文阅读】人脸修复(face restoration ) 不同先验代表算法整理
转眼做人脸复原(face restoration)算法也一段时间了,根据自己的记忆整理一下自己的一些看法,算作个人记录,当然如果有人愿意分享自己的看法也是极好的。先挂下文章链接,下一篇在写总结。 一、前述 人脸修复(face restoration)任…...
最小二乘法拟合平面(线性回归法、梯度下降、PCA法)
参考笔记: Open3D 最小二乘拟合平面(直接求解法)【2025最新版】_python open3d已知平面方程绘制平面-CSDN博客 目录 1.前言 2.线性回归法 2.1 模型假设 2.2 定义误差函数 2.3 求偏导并解方程 2.4 解方程 2.5 案例演示 2.5.1 手工计…...
数组名既可作为指针也可作为变量名
在C语言中,数组名在不同的上下文中既可以作为指向数组首个元素的指针,也可以代表整个数组,这是由C语言的设计和语法规则决定的,下面我来详细解释一下。 1. 数组名作为指向首元素的指针 在大多数情况下,当数组名出现在…...
MySQL相关
1.多表查询关键点在哪 📖 1️⃣ 明确关联关系 先搞清楚多表之间的关联关系: 一对一(1:1) 一对多(1:N) 多对多(M:N) 比如: 一个课程对应一个教室(1:1&am…...