ResNet详解:网络结构解读与PyTorch实现教程
目录
- 一、深度残差网络(Deep Residual Networks)简介
- 深度学习与网络深度的挑战
- 残差学习的提出
- 为什么ResNet有效?
- 二、深度学习与梯度消失问题
- 梯度消失问题定义
- 为什么会出现梯度消失?
- 激活函数
- 初始化方法
- 网络深度
- 如何解决梯度消失问题
- 三、残差块(Residual Blocks)基础
- 残差块的核心思想
- 结构组成
- 残差块的变体
- 四、ResNet架构
- 架构组成
- 4.1 初始卷积层
- 功能和作用
- 结构详解
- 为何不使用多个小卷积核?
- 小结
- 4.2 残差块组(Residual Block Groups)
- 功能和作用
- 结构详解
- 残差块组与特征图大小
- 小结
- 4.3 全局平均池化(Global Average Pooling)
- 功能和作用
- 结构详解
- 与全连接层的比较
- 小结
- 4.4 全连接层(Fully Connected Layer)
- 功能和作用
- 结构详解
- 激活函数与Dropout
- 小结
- 五、实战:使用PyTorch构建ResNet模型
- 5.1 构建ResNet模型
- 前置条件
- 构建Residual Block
- 构建ResNet-18
- 模型测试
- 5.2 训练与评估
- 数据预处理与加载
- 模型训练
- 模型评估
- 六、总结
本文深入探讨了深度残差网络(ResNet)的核心概念和架构组成。我们从深度学习和梯度消失问题入手,逐一解析了残差块、初始卷积层、残差块组、全局平均池化和全连接层的作用和优点。文章还包含使用PyTorch构建和训练ResNet模型的实战部分,带有详细的代码和解释。
关注TechLead,分享AI与云服务技术的全维度知识。作者拥有10+年互联网服务架构、AI产品研发经验、团队管理经验,同济本复旦硕,复旦机器人智能实验室成员,阿里云认证的资深架构师,项目管理专业人士,上亿营收AI产品研发负责人。
一、深度残差网络(Deep Residual Networks)简介
深度残差网络(Deep Residual Networks,简称ResNet)自从2015年首次提出以来,就在深度学习领域产生了深远影响。通过一种创新的“残差学习”机制,ResNet成功地训练了比以往模型更深的神经网络,从而显著提高了多个任务的性能。深度残差网络通过引入残差学习和特殊的网络结构,解决了传统深度神经网络中的梯度消失问题,并实现了高效、可扩展的深层模型。
深度学习与网络深度的挑战
在深度学习中,网络的“深度”(即层数)通常与模型的能力成正比。然而,随着网络深度的增加,一些问题也随之出现,最突出的是梯度消失/爆炸问题。这使得深层网络难以训练。
残差学习的提出
传统的深度神经网络试图学习目标函数 ( H(x) ),但是在ResNet中,每个网络层实际上学习的是一个残差函数 ( F(x) = H(x) - x )。然后,这个残差结果与输入 ( x ) 相加,形成 ( H(x) = F(x) + x )。这一机制使得网络更容易学习身份映射,进而缓解了梯度消失问题。
# PyTorch中的残差块实现
import torch
import torch.nn as nnclass ResidualBlock(nn.Module):def __init__(self, in_channels, out_channels, stride=1):super(ResidualBlock, self).__init__()self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=stride, padding=1)self.bn1 = nn.BatchNorm2d(out_channels)self.relu = nn.ReLU(inplace=True)self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3, stride=1, padding=1)self.bn2 = nn.BatchNorm2d(out_channels)self.shortcut = nn.Sequential()if stride != 1 or in_channels != out_channels:self.shortcut = nn.Sequential(nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=stride),nn.BatchNorm2d(out_channels))def forward(self, x):out = self.relu(self.bn1(self.conv1(x)))out = self.bn2(self.conv2(out))out += self.shortcut(x)out = self.relu(out)return out# 输出示例
x = torch.randn(64, 3, 32, 32)
block = ResidualBlock(3, 64)
out = block(x)
print(out.shape) # 输出:torch.Size([64, 64, 32, 32])
为什么ResNet有效?
- 解决梯度消失问题:通过残差连接,梯度能够更容易地反向传播。
- 参数效率:与传统的深层网络相比,ResNet能以更少的参数实现更好的性能。
二、深度学习与梯度消失问题
在深入研究深度残差网络(ResNet)之前,理解梯度消失问题是至关重要的。该问题长期以来一直是训练深层神经网络的主要难点。本节将讲解梯度消失问题的基本原理,以及这一问题如何影响深度学习模型的训练。
梯度消失问题定义
梯度消失问题发生在神经网络的反向传播过程中,具体表现为网络中某些权重的梯度接近或变为零。这导致这些权重几乎不会更新,从而阻碍了网络的训练。
数学上,假设我们有一个误差函数 ( E ),对于网络中的某个权重 ( w ),如果 ( \frac{\partial E}{\partial w} ) 趋近于零,则表明出现了梯度消失问题。
为什么会出现梯度消失?
激活函数
使用Sigmoid或者Tanh等饱和激活函数时,其导数在两端极小,这很容易导致梯度消失。
初始化方法
权重初始化不当也可能导致梯度消失。例如,如果初始化权重过小,那么激活函数的输出和梯度都可能非常小。
网络深度
网络越深,梯度在反向传播过程中经过的层就越多,导致梯度消失问题更加严重。
如何解决梯度消失问题
- 使用ReLU激活函数:ReLU(Rectified Linear Unit)激活函数能够缓解梯度消失。
- 合适的权重初始化:如He初始化或Glorot初始化。
- 使用短接结构(Skip Connections):这是ResNet解决梯度消失问题的核心机制。
# 使用ReLU和He初始化的简单示例
import torch.nn as nnclass SimpleNetwork(nn.Module):def __init__(self):super(SimpleNetwork, self).__init__()self.layer1 = nn.Linear(10, 50)nn.init.kaiming_normal_(self.layer1.weight, nonlinearity='relu') # He初始化self.relu = nn.ReLU()def forward(self, x):x = self.layer1(x)x = self.relu(x)return x# 输出示例
x = torch.randn(32, 10)
model = SimpleNetwork()
out = model(x)
print(out.shape) # 输出:torch.Size([32, 50])
三、残差块(Residual Blocks)基础
残差块(Residual Blocks)是深度残差网络(Deep Residual Networks,或ResNet)中的基本构建单元。通过使用残差块,ResNet有效地解决了梯度消失问题,并能训练极深的网络。本节将深入探讨残差块的基础概念、设计与实现。残差块作为ResNet的基础组成部分,其设计充分考虑了训练稳定性和模型性能。通过引入残差学习和短接连接,ResNet能够有效地训练深度网络,从而在多个任务上达到先进的性能。
残差块的核心思想
在传统的卷积神经网络(CNN)中,每个卷积层试图学习输入与输出之间的映射。残差块则采用了不同的策略:它们试图学习输入与输出之间的残差映射,即:
[
F(x) = H(x) - x
]
其中,( F(x) ) 是残差函数,( H(x) ) 是目标映射函数,( x ) 是输入。然后,( F(x) ) 与输入 ( x ) 相加,得到最终输出:
[
H(x) = F(x) + x
]
结构组成
一个基础的残差块通常包含以下几个部分:
- 卷积层:用于特征提取。
- 批量归一化(Batch Normalization):用于加速训练和改善模型泛化。
- 激活函数:通常使用ReLU。
- 短接连接(Skip Connection):直接连接输入和输出。
# 残差块的PyTorch实现
import torch
import torch.nn as nnclass ResidualBlock(nn.Module):def __init__(self, in_channels, out_channels, stride=1):super(ResidualBlock, self).__init__()self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=stride, padding=1)self.bn1 = nn.BatchNorm2d(out_channels)self.relu = nn.ReLU(inplace=True)self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3, stride=1, padding=1)self.bn2 = nn.BatchNorm2d(out_channels)self.shortcut = nn.Sequential()if stride != 1 or in_channels != out_channels:self.shortcut = nn.Sequential(nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=stride),nn.BatchNorm2d(out_channels))def forward(self, x):out = self.relu(self.bn1(self.conv1(x)))out = self.bn2(self.conv2(out))out += self.shortcut(x)out = self.relu(out)return out# 输出示例
x = torch.randn(64, 3, 32, 32)
block = ResidualBlock(3, 64)
out = block(x)
print(out.shape) # 输出:torch.Size([64, 64, 32, 32])
残差块的变体
- Bottleneck Blocks:在更深的ResNet(如ResNet-152)中,为了减少计算量,通常使用“瓶颈”结构,即先通过一个小的卷积核(如1x1)降维,再进行3x3卷积,最后通过1x1卷积恢复维度。
四、ResNet架构
本节将介绍ResNet(深度残差网络)的整体架构,以及它在计算机视觉和其他领域的应用。一个标准的ResNet模型由多个残差块组成,通常开始于一个普通的卷积层和池化层,用于进行初步的特征提取。接下来是一系列的残差块,最后是全局平均池化层和全连接层。
架构组成
- 初始卷积层:用于初步特征提取。
- 残差块组(Residual Blocks Group):包含多个残差块。
- 全局平均池化(Global Average Pooling):减小维度。
- 全连接层:用于分类或其他任务。
4.1 初始卷积层
在进入深度残差网络的主体结构之前,第一层通常是一个初始卷积层。这个卷积层的主要任务是对输入图像进行一定程度的空间下采样(Spatial Downsampling)和特征抽取。
功能和作用
- 空间下采样(Spatial Downsampling): 初始卷积层通常具有较大的卷积核和步长(stride),用于减少后续层需要处理的空间维度,从而降低计算复杂度。
- 特征抽取: 初始卷积层能够抓取图像的基础特征,如边缘、纹理等,为后续的特征抽取工作打下基础。
结构详解
在ResNet-18和ResNet-34中,这一初始卷积层通常由一个7x7
大小的卷积核、步长(stride)为2
和填充(padding)为3
组成。这个层后面通常还会跟随一个批量归一化(Batch Normalization)层和ReLU激活函数。
self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3)
self.bn1 = nn.BatchNorm2d(64)
self.relu = nn.ReLU(inplace=True)
为何不使用多个小卷积核?
在一些其他网络架构中,初始层可能由多个小卷积核(如3x3
)组成,那么为什么ResNet要使用一个较大的7x7
卷积核呢?主要原因是,一个大的卷积核可以在相同数量的参数下,提供更大的感受野(Receptive Field),从而更有效地捕获图像的全局信息。
小结
初始卷积层在整个ResNet架构中扮演着非常重要的角色。它不仅完成了对输入图像的基础特征抽取,还通过空间下采样减轻了后续计算的负担。这些设计细节共同使得ResNet能在保持高性能的同时,具有更低的计算复杂度。
4.2 残差块组(Residual Block Groups)
在初始卷积层之后,紧接着就是ResNet的核心组成部分,也就是残差块组(Residual Block Groups)。这些残差块组成了ResNet架构中的主体,负责高级特征的抽取和传递。
功能和作用
- 特征抽取: 每个残差块组负责从其前一组中提取的特征中提取更高级的特征。
- 非线性性能增强: 通过残差链接,每个残差块组能够学习输入与输出之间的复杂非线性映射。
- 避免梯度消失和爆炸: 残差块组内的Skip Connection(跳过连接)能够更好地传递梯度,有助于训练更深的网络。
结构详解
在标准的ResNet-18或ResNet-34模型中,通常会包括几组残差块。每一组都有一定数量的残差块,这些块的数量和组的深度有关。
- 第一组可能包括2个残差块,用64个输出通道。
- 第二组可能包括2个残差块,用128个输出通道。
- 第三组可能包括2个残差块,用256个输出通道。
- 第四组可能包括2个残差块,用512个输出通道。
# 示例代码,表示第一组残差块
self.layer1 = nn.Sequential(ResidualBlock(64, 64),ResidualBlock(64, 64)
)
残差块组与特征图大小
每一组的第一个残差块通常会减小特征图的尺寸(即进行下采样),而增加输出通道数。这样做可以保证模型的计算效率,同时能抓住更多层次的特征。
小结
残差块组是ResNet架构中最核心的部分,通过逐层抽取更高级的特征并通过残差连接优化梯度流动,这些设计使得ResNet模型能够有效并且准确地进行图像分类以及其他计算机视觉任务。
4.3 全局平均池化(Global Average Pooling)
在通过一系列残差块组进行特征抽取和非线性映射之后,ResNet通常使用全局平均池化层(Global Average Pooling,简称GAP)作为网络的最后一个卷积层。与传统的全连接层相比,全局平均池化有几个显著优点。
功能和作用
- 降维: 全局平均池化层将每个特征图(Feature Map)缩减为一个单一的数值,从而显著减小模型参数和计算量。
- 防止过拟合: 由于其简单性和少量的参数,全局平均池化有助于防止模型过拟合。
- 改善泛化能力: 简化的网络结构能更好地泛化到未见过的数据。
结构详解
全局平均池化层简单地计算每个特征图的平均值。假设我们有一个形状为(batch_size, num_channels, height, width)
的特征图,全局平均池化将输出一个形状为(batch_size, num_channels)
的张量。
# PyTorch中的全局平均池化
self.global_avg_pooling = nn.AdaptiveAvgPool2d((1, 1))
与全连接层的比较
在许多传统的卷积神经网络(如AlexNet)中,网络的末端通常包括几个全连接层。然而,全连接层往往包含大量的参数,从而增加了过拟合的风险。与之相比,全局平均池化由于其参数更少、计算更简单,因此更受现代深度学习架构的青睐。
小结
全局平均池化是ResNet架构的一个重要组成部分,它不仅显著减小了模型的参数数量,还有助于提高模型的泛化能力。这些优点使得全局平均池化在许多现代卷积神经网络中都有广泛的应用。
4.4 全连接层(Fully Connected Layer)
在全局平均池化(GAP)之后,ResNet架构通常包含一个或多个全连接层(Fully Connected Layer)。全连接层在ResNet中的主要目的是为了进行分类或者回归任务。
功能和作用
- 分类或回归: 全连接层的主要任务是根据前层特征进行分类或回归。
- 增加模型复杂度: 相比GAP,全连接层可以增加模型的复杂度,从而拟合更复杂的函数。
- 特征整合: 全连接层能够整合前面各层的信息,输出一个固定大小的特征向量。
结构详解
全连接层通常接收全局平均池化层输出的平坦化(flattened)向量,并通过一系列线性变换与激活函数生成输出。例如,在分类问题中,全连接层通常输出一个与类别数相等的节点。
# PyTorch中的全连接层示例
self.fc = nn.Linear(512, num_classes) # 假设全局平均池化后有512个通道,num_classes为分类数量
激活函数与Dropout
全连接层之后通常会接一个激活函数,如ReLU或者Softmax,以引入非线性。有时也会使用Dropout层来防止过拟合,尤其是在全连接层的节点数较多时。
小结
虽然全连接层相对简单,但它在ResNet以及其他深度学习模型中占据重要地位。全连接层是进行分类或回归的关键,同时也为模型提供了最后的机会进行特征整合和学习复杂映射。
五、实战:使用PyTorch构建ResNet模型
5.1 构建ResNet模型
在这一部分中,我们将使用PyTorch框架来实现一个简化版的ResNet-18模型。我们的目标是构建一个可以在CIFAR-10数据集上进行分类任务的模型。
前置条件
确保您已经安装了PyTorch和其他必要的库。
pip install torch torchvision
构建Residual Block
首先,让我们实现一个残差块。这是前面章节已经介绍过的内容。
import torch
import torch.nn as nnclass ResidualBlock(nn.Module):def __init__(self, in_channels, out_channels, stride=1):super(ResidualBlock, self).__init__()self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=stride, padding=1)self.bn1 = nn.BatchNorm2d(out_channels)self.relu = nn.ReLU(inplace=True)self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3, stride=1, padding=1)self.bn2 = nn.BatchNorm2d(out_channels)self.shortcut = nn.Sequential()if stride != 1 or in_channels != out_channels:self.shortcut = nn.Sequential(nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=stride),nn.BatchNorm2d(out_channels))
构建ResNet-18
接下来,我们使用残差块来构建完整的ResNet-18模型。
class ResNet18(nn.Module):def __init__(self, num_classes=10):super(ResNet18, self).__init__()self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1)self.bn1 = nn.BatchNorm2d(64)self.relu = nn.ReLU(inplace=True)self.layer1 = self._make_layer(64, 64, 2)self.layer2 = self._make_layer(64, 128, 2, stride=2)self.layer3 = self._make_layer(128, 256, 2, stride=2)self.layer4 = self._make_layer(256, 512, 2, stride=2)self.avgpool = nn.AdaptiveAvgPool2d((1, 1))self.fc = nn.Linear(512, num_classes)def _make_layer(self, in_channels, out_channels, blocks, stride=1):layers = []layers.append(ResidualBlock(in_channels, out_channels, stride))for _ in range(1, blocks):layers.append(ResidualBlock(out_channels, out_channels))return nn.Sequential(*layers)def forward(self, x):x = self.conv1(x)x = self.bn1(x)x = self.relu(x)x = self.layer1(x)x = self.layer2(x)x = self.layer3(x)x = self.layer4(x)x = self.avgpool(x)x = torch.flatten(x, 1)x = self.fc(x)return x
以上代码定义了一个用于CIFAR-10分类任务的ResNet-18模型。在这个模型中,我们使用了前面定义的ResidualBlock
类,并通过_make_layer
函数来堆叠多个残差块。
模型测试
接下来,我们可以测试这个模型以确保其结构是正确的。
# 创建一个模拟输入
x = torch.randn(64, 3, 32, 32)# 实例化模型
model = ResNet18(num_classes=10)# 前向传播
output = model(x)# 输出形状应为(64, 10),因为我们有64个样本和10个类别
print(output.shape) # 输出:torch.Size([64, 10])
5.2 训练与评估
在成功构建了ResNet-18模型之后,下一步就是进行模型的训练和评估。在这一部分,我们将介绍如何在CIFAR-10数据集上完成这两个步骤。
数据预处理与加载
首先,我们需要准备数据。使用PyTorch的torchvision
库,我们可以非常方便地下载和预处理CIFAR-10数据集。
import torch
import torchvision
import torchvision.transforms as transforms# 数据预处理
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)),
])# 加载数据集
trainset = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=128, shuffle=True)testset = torchvision.datasets.CIFAR10(root='./data', train=False, download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=128, shuffle=False)
模型训练
训练模型通常需要指定损失函数和优化器,并反复进行前向传播、计算损失、反向传播和参数更新。
import torch.optim as optim# 实例化模型并移至GPU
model = ResNet18(num_classes=10).cuda()# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.1, momentum=0.9, weight_decay=5e-4)# 训练模型
for epoch in range(10): # 运行10个周期for i, data in enumerate(trainloader, 0):inputs, labels = datainputs, labels = inputs.cuda(), labels.cuda()# 清零梯度缓存optimizer.zero_grad()# 前向传播,计算损失,反向传播outputs = model(inputs)loss = criterion(outputs, labels)loss.backward()# 更新参数optimizer.step()
模型评估
训练完成后,我们需要评估模型的性能。这通常通过在测试集上计算模型的准确率来完成。
# 切换模型为评估模式
model.eval()correct = 0
total = 0
with torch.no_grad():for data in testloader:images, labels = dataimages, labels = images.cuda(), labels.cuda()outputs = model(images)_, predicted = torch.max(outputs.data, 1)total += labels.size(0)correct += (predicted == labels).sum().item()print(f'Accuracy of the network on the 10000 test images: {100 * correct / total}%')
六、总结
通过深入探讨ResNet的关键组成部分,包括深度残差网络、梯度消失问题、残差块、初始卷积层、残差块组、全局平均池化以及全连接层,我们不仅理解了其背后的设计思想和优势,还通过PyTorch实现了一个完整的ResNet模型并进行了训练与评估。ResNet通过其独特的残差连接有效地解决了深度网络中的梯度消失问题,并且在多项视觉任务中实现了突破性的性能。这些优点使得ResNet成为现代深度学习架构中不可或缺的一部分。
关注TechLead,分享AI与云服务技术的全维度知识。作者拥有10+年互联网服务架构、AI产品研发经验、团队管理经验,同济本复旦硕,复旦机器人智能实验室成员,阿里云认证的资深架构师,项目管理专业人士,上亿营收AI产品研发负责人。
相关文章:

ResNet详解:网络结构解读与PyTorch实现教程
目录 一、深度残差网络(Deep Residual Networks)简介深度学习与网络深度的挑战残差学习的提出为什么ResNet有效? 二、深度学习与梯度消失问题梯度消失问题定义为什么会出现梯度消失?激活函数初始化方法网络深度 如何解决梯度消失问…...

ChatGPT 随机动态可视化图表分析
动态可视化图表分析实例如下图: 这样的动态可视化图表可以使用ChatGPT OpenAI 来实现。 给ChatGPT发送指令: 你现在是一个数据分析师,请使用HTML,JS,Echarts,来完成一个动态条形图,条形图方向横向,数据可以随机生成,并且随机生成10个不同的商品名称,每个类别分别用…...

国标视频融合云平台EasyCVR视频汇聚平台的应用场景及其功能说明
一、平台简介 EasyCVR国标视频融合云平台是一款基于端-边-云一体化架构的视频融合AI智能分析网关平台。EasyCVR平台支持视频汇聚、融合管理,兼容多类型设备、多协议接入。其提供的视频功能包括:视频监控、无插件直播录像、云存储、检索回放、智能告警、…...

后端面试话术集锦第三篇:spring cloud 面试话术
🚗后端面试集锦目录 💖后端面试话术集锦第 1 篇:spring面试话术💖 💖后端面试话术集锦第 2 篇:spring boot面试话术💖 💖后端面试话术集锦第 3 篇:spring cloud面试话术💖 💖后端面试话术集锦第 4 篇:ElasticSearch面试话术💖 💖后端面试话术集锦第 5 …...

React 18 选择 State 结构
参考文章 选择 State 结构 构建良好的 state 可以让组件变得易于修改和调试,而不会经常出错。以下是在构建 state 时应该考虑的一些建议。 构建 state 的原则 当编写一个存有 state 的组件时,需要选择使用多少个 state 变量以及它们都是怎样的数据格…...

LNMT与动静分离
目录 一、LNMT 一、部署tomcat 二、部署nginx 三、部署mariadb 四、配置nginx 二、操作流程及步骤 一、在第一台机器上进入 vim /etc/nginx/nginx.conf 更改配置文件 二、并查看端口是否成功启动 三、验证 四、再次来到网页验证 五、动静分离(修改配置…...

【java】LinkedList 和 ArrayList的简介与对比
Java LinkedList和 ArrayList 在使用上,几乎是一样的。由于LinkedList是基于双向链表的,会多出list.getFirst();获取头部元素等方法 链表(Linked list)是一种常见的基础数据结构,是一种线性表,但是并不会按…...

机器学习基础14-算法调参(基于印第安糖尿病Pima数据集)
机器学习的模型都是参数化的,可以通过调参来提高模型的准确度。 模型有很多参数,如何找到最佳的参数组合,可以把它当作一个查询问题来处理,但是调整参数到何时为止呢?应该遵循偏差和方差协调的原则。 接下来将介绍在 s…...

ASUS华硕天选4笔记本电脑FA507XV原厂Windows11系统22H2
天选四FA507X原装系统自带所有驱动、出厂主题壁纸LOGO、Office办公软件 华硕电脑管家、奥创控制中心等预装程序,恢复出厂状态W11 链接:https://pan.baidu.com/s/1SPoFW7wR5KawGu-yMckNzg?pwdayxd 提取码:ayxd...

IET独立出版 | EI检索 | 2023年第三届机械、航空航天与汽车工程国际会议
会议简介 Brief Introduction 2023年第三届机械、航空航天与汽车工程国际会议(CMAAE 2023) 会议时间:2023年12月8 -10日 召开地点:中国南京 大会官网:www.cmaae.org 航天是当今世界最具挑战性和广泛带动性的高技术领域…...

【Pytorch】CUDA error: no kernel image is available for execution on the device
记录一下pytorch安装的cuda版本和GPU cuda不一致的解决。 RuntimeError: CUDA error: no kernel image is available for execution on the device 一般就是pytorch和cuda安装的不匹配。 如果我安装的torch配的cuda信息如下, torch.__version__: 1.8.1cu102 tor…...

dolphinschedule配置企微告警服务(WeChat群组)
一、前置说明 ds配置好工作流后,比较重要的一个就是上线后的监控报警服务,如果你是基于企微作为协同办公的,WeChat群组预警必须是要安排上的,文章基于自建应用配合群组方式构建预警群,接入后,任务成功或者…...

Git中smart Checkout与force checkout
Git中smart Checkout与force checkout 使用git进行代码版本管理,当我们切换分支有时会遇到这样的问题: 这是因为在当前分支修改了代码,但是没有commit,所以在切换到其他分支的时候会弹出这个窗口, 提示你选force checkout或者smart checko…...

Java“牵手”1688商品跨境属性数据,1688API接口申请指南
1688平台商品详情跨境属性数据接口是开放平台提供的一种API接口,通过调用API接口,开发者可以获取1688商品的标题、价格、库存、月销量、总销量、库存、详情描述、图片,重量,详情描述等详细信息 。 获取商品详情接口API是一种用于…...

Win解答 | 解决键盘中 字母+空格 导致的输入法弹窗导致的一系列问题
近三个月来,一直都有一个键盘组合键的问题影响我的电脑使用,不管是打字还是打游戏,都会出现按键盘的 字母空格 弹出一个特殊符号的候选框,如下图所示 图片中为 S空格 所出现的弹窗 一个看似方便,实则难受的功能 其实打…...

WPF读取dicom序列:实现上一帧、下一帧、自动播放、暂停
一、整体设计概况 创建WPF程序使用.Net Framework4.8定义Image控件展示图像增加标签展示dcm文件信息规划按钮触发对应的事件:上一帧、下一帧、自动播放、暂停、缩放、播放速率二、页面展示 三、代码逻辑分析 Windows窗体加载Loaded事件:生成初始图像信息Windows窗体加载Mous…...

homeassistant ubuntu自启动 网络设置
命令行安装virtualbox 或者安装包 hass官网下载 haos_ova-10.4.vdi virtualbox 装hass 最少2G内存 其他省略 自启动: gnome-session-properties 添加 VBoxManage startvm hass --type headless hass为自己的虚拟机名字 网络配置如下: 要全部打开...

生成式AI背景下编程工作者的技术和高级软考理论的演进融合之路
思考背景 近两次软考,我都参与了,2022年11月参加的是系统架构师的考试,2023年5月参加的是系统分析师的考试,去年参加系统架构是考试是完全的裸考和第一次考,成绩是选择题39,综合题46和论文48分,…...

RabbitMQ的镜像队列
镜像队列 如果 RabbitMQ 集群中只有一个 Broker 节点,那么该节点的失效将导致整体服务的临时性不可用,并且也可能会导致消息的丢失。可以将所有消息都设置为持久化,并且对应队列的durable 属性也设置为 true ,但是这样仍然无法…...

【Spring Boot】数据库持久层框架MyBatis — Spring Boot构建MyBatis应用程序
Spring Boot构建MyBatis应用程序 Spring Boot是用于快速构建Spring应用程序的框架。MyBatis是一种Java持久化框架,可以帮助开发人员轻松地管理数据库。将Spring Boot与MyBatis结合使用可以使开发人员更容易地创建和管理数据库应用程序。 以下是使用Spring Boot构建…...

【校招VIP】专业课考点之session cookie
考点介绍: 测试工作中我们经常会听到这两个词,作为测试一定要理解这两个概念,对于测试应用的接口、业务理解很有帮助。需要了解Cookie和Session的作用、原理和两者的区别。 『专业课考点之session cookie』相关题目及解析内容可点击文章末尾…...

IDEA集成Git相关操作知识(pull、push、clone)
一:集成git 1:初始化git(新版本默认初始化) 老版本若没有,点击VCS,选中import into Version Controller中的Create git Repository(创建git仓库),同理即可出现git符号。 也可查看源文件夹有没有…...

Springboot 整合 Redis配置
RedisService接口 import java.util.List; import java.util.Map; import java.util.Set;/*** Redis操作Service* Created by macro on 2020/3/3.*/ public interface RedisService {/*** 保存属性*/void set(String key, Object value, long time);/*** 保存属性*/void set(St…...

Spark 启动时,报JAVA_HOME is not set
文章目录 1、报错内容2、解决方式3、再次启动Spark集群 1、报错内容 Spark启动时报错: hadoop104: JAVA_HOME is not set2、解决方式 解决方式: 打开启动配置文件 cd /opt/module/spark-standalone/sbin/ vim spark-config.sh配置Java的环境变量 …...

运用Python解析HTML页面获取资料
在网络爬虫的应用中,我们经常需要从HTML页面中提取图片、音频和文字资源。本文将介绍如何使用Python的requests库和BeautifulSoup解析HTML页面,获取这些资源。 一、环境准备 首先,确保您已经安装了Python环境。接下来,我们需要安…...

硬件名词--单片机,开发板和芯片
这里写自定义目录标题 初学硬件,一脸懵逼。整理了半天还是没太懂。只能说我不学习,我是知识点的搬运工。 1.半导体(semiconductor)指常温下导电性能介于导体与绝缘体之间的材料,常见材料有硅,锗、砷化镓等。…...

Ubuntu20.04下安装搜狗输入法Linux版
Ubuntu20.04下安装搜狗输入法Linux版 参考搜狗输入法的官网安装指南; 第一步:打开搜狗输入法官网; https://shurufa.sogou.com/ 点击X86_64后将会自动跳转到搜狗输入法的安装指南中; 安装指南 Ubuntu搜狗输入法安装指南 搜狗…...

springboot RabbitMQ客户端连接故障恢复
最近做RabbitMQ故障演练发现RabbitMQ服务器停止后,基于springboot的消费端不可以自动的恢复,队列的消费者消失,消息一直积压到队列中,这种情况肯定是不可接收的;通过研究源代码找到了解决方案。 一、添加自动恢复配置a…...

centos下配置SFTP且限制用户访问目录
一、SFTP使用场景 ftp是大多数网站的文件传输选择工具,但ftp并不是非常安全,并且在centos上搭建的vsftpd也非常的不稳定,偶尔会出现权限问题,例如500、或是账号密码不正确等等。 而SFTP是基于默认的22端口,是ssh内含…...

A - 最短路径
给出一张包含 n 个节点、 m 条边的无向图,请你求出图上两点 s,t 间的最短路径长度。 (请大家自行处理重边和自环) Input 第一行两个数 n,m ,分别表示节点数和边数,以空格隔开,其中1≤n≤500,1≤m≤50000 ; 之后 m 行…...