Ghost卷积
1. Ghost卷积的思想
在标准卷积操作中,大量的卷积核会生成丰富的特征,但许多特征之间存在高度的冗余性。也就是说,可以通过更少的计算生成具有相似表达能力的特征。它的关键思想是:使用较少的基础卷积生成一些特征图,然后使用简单的线性操作(如逐像素点乘)生成额外的特征图,最终将这些特征图组合成输出。这种方法保留了大部分的特征信息,同时减少了计算成本。
- 基础特征生成:首先使用标准卷积生成一部分核心特征图,但数量远小于传统卷积核生成的特征图数量。
- 稀疏特征扩展:通过一系列的线性变换(例如点卷积)生成这些核心特征的“Ghost特征”,从而生成更多的特征图。这些“Ghost特征”与原始特征共享较多信息。
2. Ghost卷积的计算过程
***假设传统卷积层会生成 n
张特征图,而Ghost卷积则会生成少于 n
的特征图(例如 m
张,其中 m < n
)。然后,它会将这 m
张基础特征图通过线性变换生成余下的特征图,使得总数达到 n
。***果然又是唬人的东西。
1. 输入图像
假设我们有一个5×5的灰度图像:
Image = [ 1 2 3 4 5 5 4 3 2 1 1 2 3 4 5 5 4 3 2 1 1 2 3 4 5 ] \text{Image} = \begin{bmatrix} 1 & 2 & 3 & 4 & 5 \\ 5 & 4 & 3 & 2 & 1 \\ 1 & 2 & 3 & 4 & 5 \\ 5 & 4 & 3 & 2 & 1 \\ 1 & 2 & 3 & 4 & 5 \\ \end{bmatrix} Image= 1515124242333334242451515
2. 基础卷积
假设我们只使用一个3×3的基础卷积核来生成少量的初始特征图。卷积核为:
Kernel = [ 1 0 − 1 1 0 − 1 1 0 − 1 ] \text{Kernel} = \begin{bmatrix} 1 & 0 & -1 \\ 1 & 0 & -1 \\ 1 & 0 & -1 \\ \end{bmatrix} Kernel= 111000−1−1−1
对图像进行基础卷积(步幅为1),我们会得到一个3×3的初始特征图。为了简化,假设我们仅生成一张初始特征图:
基础卷积结果(假设只有一张初始特征图)//玛德,GPT的卷积结果是错的,GPT连最基本的四则运算都是算错的,一定小心
Initial Feature Map = [ 2 0 − 2 0 0 0 2 0 − 2 ] \text{Initial Feature Map} = \begin{bmatrix} 2 & 0 & -2 \\ 0 & 0 & 0 \\ 2 & 0 & -2 \\ \end{bmatrix} Initial Feature Map= 202000−20−2
3. Ghost特征生成
在Ghost卷积中,我们使用一些简单的操作(如逐像素点乘或加法)生成额外的特征图。比如,可以将上述初始特征图按位置加上或乘以一个固定系数。
假设我们生成2张额外特征图,每一张特征图通过在初始特征图上加上不同的常数生成:
Ghost特征图1
Ghost Feature Map 1 = Initial Feature Map + 1 = [ 3 1 − 1 1 1 1 3 1 − 1 ] \text{Ghost Feature Map 1} = \text{Initial Feature Map} + 1 = \begin{bmatrix} 3 & 1 & -1 \\ 1 & 1 & 1 \\ 3 & 1 & -1 \\ \end{bmatrix} Ghost Feature Map 1=Initial Feature Map+1= 313111−11−1
Ghost特征图2
Ghost Feature Map 2 = Initial Feature Map − 1 = [ 1 − 1 − 3 − 1 − 1 − 1 1 − 1 − 3 ] \text{Ghost Feature Map 2} = \text{Initial Feature Map} - 1 = \begin{bmatrix} 1 & -1 & -3 \\ -1 & -1 & -1 \\ 1 & -1 & -3 \\ \end{bmatrix} Ghost Feature Map 2=Initial Feature Map−1= 1−11−1−1−1−3−1−3
4. 输出组合
最后,将初始特征图和Ghost特征图组合,形成最终的输出特征图。可以选择将它们进行平均、求和或其他组合方式。这里我们简单地将三张特征图按通道维度进行堆叠。
最终结果
最终的输出特征图可能是:
Output = [ [ 2 0 − 2 0 0 0 2 0 − 2 ] , [ 3 1 − 1 1 1 1 3 1 − 1 ] , [ 1 − 1 − 3 − 1 − 1 − 1 1 − 1 − 3 ] ] \text{Output} = \begin{bmatrix} \begin{bmatrix} 2 & 0 & -2 \\ 0 & 0 & 0 \\ 2 & 0 & -2 \end{bmatrix}, \begin{bmatrix} 3 & 1 & -1 \\ 1 & 1 & 1 \\ 3 & 1 & -1 \end{bmatrix}, \begin{bmatrix} 1 & -1 & -3 \\ -1 & -1 & -1 \\ 1 & -1 & -3 \end{bmatrix} \end{bmatrix} Output= 202000−20−2 , 313111−11−1 , 1−11−1−1−1−3−1−3
3. Ghost卷积的优点
- 减少计算量:只需使用较少的卷积核生成少量基础特征图,其他特征图通过线性操作生成,因此显著减少了卷积计算的 FLOPs。
- 更少的参数:通过减少实际卷积的核数,减少了模型的参数量,有利于模型在资源受限的设备上运行。
4. 代码示例
以下是Ghost卷积的一个简单实现示例(使用PyTorch):
import torch
import torch.nn as nnclass GhostModule(nn.Module):def __init__(self, in_channels, out_channels, kernel_size=1, ratio=2, dw_size=3, stride=1, padding=0):super(GhostModule, self).__init__()self.out_channels = out_channelsself.init_channels = int(out_channels / ratio)self.cheap_channels = out_channels - self.init_channels# 基础特征生成self.primary_conv = nn.Conv2d(in_channels, self.init_channels, kernel_size, stride, padding, bias=False)# 生成Ghost特征的线性变换self.cheap_operation = nn.Conv2d(self.init_channels, self.cheap_channels, dw_size, 1, dw_size//2, groups=self.init_channels, bias=False)def forward(self, x):# 基础特征primary_output = self.primary_conv(x)# Ghost特征cheap_output = self.cheap_operation(primary_output)# 合并特征output = torch.cat([primary_output, cheap_output], dim=1)return output[:, :self.out_channels, :, :]# 示例用法
ghost_layer = GhostModule(in_channels=32, out_channels=64, kernel_size=1, ratio=2, dw_size=3)
input_data = torch.randn(1, 32, 64, 64) # (batch_size, in_channels, height, width)
output_data = ghost_layer(input_data)
print(output_data.shape) # 输出形状
软池化
又一个吓人的词,其实没啥用,本质上其实就是综合最大池化和平均池化。
软池化(Soft Pooling)是一种改进传统池化方法的技术,通常用于神经网络中的特征下采样。与常用的最大池化(Max Pooling)和平均池化(Average Pooling)不同,软池化引入了软化权重或概率的概念,使池化过程更加平滑和信息保留更好。软池化可以在卷积神经网络(CNN)中更好地保留特征信息,尤其适用于处理不规则或变化较大的数据。
常见的软池化方法
-
Log-Sum-Exp Pooling(LSE Pooling)
LSE 池化是一种软化的最大池化,它通过对池化区域内的值进行指数和对数变换,使得最终的池化值受到整个池化窗口内所有值的影响,而不是仅取最大值。LSE 池化的公式为:
y = 1 α log ( ∑ i e α x i ) y = \frac{1}{\alpha} \log \left( \sum_{i} e^{\alpha x_i} \right) y=α1log(i∑eαxi)
其中 α \alpha α 是一个参数,用于调节软化程度。当 α → + ∞ \alpha \to +\infty α→+∞ 时,LSE 池化接近最大池化;当 α → 0 \alpha \to 0 α→0 时,LSE 池化接近平均池化。证明也挺简单,就是最简单的求极限。 -
加权平均池化(Weighted Average Pooling)
加权平均池化通过对池化窗口内的值赋予不同的权重来计算加权平均值。有点类似高斯滤波 -
自适应软池化(Adaptive Soft Pooling)
自适应软池化会根据特征图的内容来动态调整池化权重,通常使用学习的方式来决定各像素点的贡献。它适合于复杂任务或要求高细节保留的应用,比如语义分割。 -
混合池化(Mix Pooling)
混合池化结合了最大池化和平均池化的优点,通常通过引入一个混合系数 λ \lambda λ 来对两者进行加权:
y = λ ⋅ MaxPooling ( x ) + ( 1 − λ ) ⋅ AvgPooling ( x ) y = \lambda \cdot \text{MaxPooling}(x) + (1 - \lambda) \cdot \text{AvgPooling}(x) y=λ⋅MaxPooling(x)+(1−λ)⋅AvgPooling(x)
这样可以兼顾特征的显著性(来自最大池化)和特征的整体信息(来自平均池化)。
软池化的优点
- 信息保留:相比最大池化,软池化保留了更多的信息,而不仅仅是局部最大值。
- 平滑特征图:软池化避免了池化过程中的过度突变,使特征图更加平滑。
- 更高的鲁棒性:在一些不规则或嘈杂的输入数据中,软池化表现得更为稳定,不易受到极值影响。
注意力机制
看了很多视频,觉得还是这个视频讲的最好。跟着流程走走,还是能学的差不多,大家可以学学
注意力机制(Attention Mechanism)是深度学习中一种非常重要的技术,尤其在自然语言处理、图像处理和时序数据分析领域中有着广泛的应用。其核心思想是让模型关注输入数据中的重要部分,而忽略不太重要的部分,从而更有效地提取信息。以下是注意力机制的基本概念和实现方式。相似和点积很类似,所以通过点积计算相似性,俩向量越相似,那么他们大的点积就会越大。
1. 注意力机制的核心概念
假设在处理一个数据序列时,通常每一个输入都对模型输出产生影响。但这些影响的大小是不同的,例如在翻译一个句子时,某些词对当前词的翻译更加重要。注意力机制通过计算每个输入对当前输出的“权重”来确定每个输入的重要程度。
这些权重可以被称为注意力权重(Attention Weights),权重值越大表示该输入对当前输出的贡献越大。
2. 注意力机制的实现步骤
以下是基本的注意力机制实现流程:
-
应用Softmax函数:将所有的注意力分数通过Softmax函数归一化,使得这些分数的和为1,便于解释为概率。
α i , j = exp ( score ( q i , k j ) ) ∑ k = 1 n exp ( score ( q i , k k ) ) \alpha_{i,j} = \frac{\exp(\text{score}(q_i, k_j))}{\sum_{k=1}^{n} \exp(\text{score}(q_i, k_k))} αi,j=∑k=1nexp(score(qi,kk))exp(score(qi,kj))
-
加权求和:
在图像处理中,自注意力机制可以帮助模型理解图像中不同区域之间的关联。比如,图像中某些像素区域的特征可能和其他区域具有相似的模式或相关性,自注意力机制能帮助模型自动识别这些关系,从而提升理解和处理图像的能力。
示例:图像中的自注意力
假设我们有一张图片,其中包含一只狗站在草地上,周围是一些背景。我们可以利用自注意力机制帮助模型聚焦于狗和草地等重要区域,而不是被背景分散注意力。这是自注意力机制在图像中应用的简化示例:
-
输入特征表示:
首先,模型会将图像分割成小块(patches),比如每个块大小为 3 × 3 3 \times 3 3×3 像素。对于每个块,模型会提取出特征向量,用于表示该块的信息。假设我们将图像分割成 N N N 个块,并得到每个块的特征向量。 -
计算注意力权重:对于给定的查询(query)和键(key)向量,通过内积或其他相似性度量计算注意力分数(attention score)。
Q是你要查询的值,K相当于字典,V相当于结果,dk是K的维度,开根号是为了保证梯度稳定
score ( q , k ) = q ⋅ k T \text{score}(q, k) = q \cdot k^T score(q,k)=q⋅kT -
计算查询(Q)、键(K)和值(V)向量:
- 通过三个不同的权重矩阵,将每个块的特征向量映射为查询向量 Q Q Q、键向量 K K K 和值向量 V V V。
- 这些向量表示了每个块在图像中的重要性和特征。
-
计算注意力权重:
- 通过点积计算每个块的查询向量 Q Q Q 与其他所有块的键向量 K K K 的相似性,得到注意力分数。可以使用公式计算:
Attention Score i , j = Q i ⋅ K j T d k \text{Attention Score}_{i,j} = \frac{Q_i \cdot K_j^T}{\sqrt{d_k}} Attention Scorei,j=dkQi⋅KjT - 其中 d k d_k dk 是键向量的维度,用于缩放, Q i Q_i Qi 是第 i i i 个块的查询向量, K j K_j Kj 是第 j j j 个块的键向量。分数越高,表示块 i i i 对块 j j j 的注意力越大。
- 通过点积计算每个块的查询向量 Q Q Q 与其他所有块的键向量 K K K 的相似性,得到注意力分数。可以使用公式计算:
-
计算加权和(自注意力输出):
- 使用 Softmax 将注意力分数转换成概率分布,并计算每个块的值向量 V V V 的加权和。这给出了每个块在全局图像上下文中的自注意力表示。使用注意力权重对值(value)向量进行加权求和,
具体来说,块 i i i 的自注意力输出可以表示为:
Attention Output i = ∑ j = 1 N Softmax ( Attention Score i , j ) ⋅ V j \text{Attention Output}_i = \sum_{j=1}^N \text{Softmax}(\text{Attention Score}_{i,j}) \cdot V_j Attention Outputi=j=1∑NSoftmax(Attention Scorei,j)⋅Vj
- 使用 Softmax 将注意力分数转换成概率分布,并计算每个块的值向量 V V V 的加权和。这给出了每个块在全局图像上下文中的自注意力表示。使用注意力权重对值(value)向量进行加权求和,
自注意力在图像处理中的应用场景
在图像处理任务中,自注意力机制非常适用于以下场景:
- 图像分割:帮助模型识别同类区域的边界,自动聚焦于同类像素区域。
- 物体检测:提高模型对复杂背景下目标物体的检测能力。
- 图像生成:生成更加真实的图像,自动平衡整体和局部特征。
通过自注意力机制,模型能够自动捕捉图像中不同区域之间的关联关系,大幅提升处理效果。
3. 常见的注意力机制类型
-
自注意力(Self-Attention):即查询、键和值都来源于同一个序列,例如在Transformer模型中使用的自注意力机制。
-
多头注意力(Multi-Head Attention):通过多个不同的线性变换获取多个注意力头,让模型可以从不同的表示空间进行学习。相当于多找几个老师去问问结果
4. 通道注意力机制
通道注意力机制属于空间注意力机制的一种应用。其目的在于让模型能够在不同的特征通道上关注重要的信息,从而提高模型的特征表示能力,全局感知的能力
超参数化卷积
又是一个唬人的词语,本质上就是多种方法进行卷积,提高复杂程度。深度超参数化卷积是一种通过引入超参数来增加网络的表达能力和灵活性的方法。深度超参数化卷积使得卷积核在训练过程中可以适应更复杂的模式,达到更优的性能。它的核心思想是引入多个卷积核或不同的卷积参数,训练中对这些卷积核或参数进行学习和组合,以获得更丰富的特征表示。
核心概念
-
超参数化:引入额外的超参数,比如不同的卷积核大小、不同的激活函数组合等,来提高模型的表达能力。超参数化并不是直接增加参数,而是通过增加模型的配置自由度来提升表现。
-
深度超参数化卷积核:在卷积层中引入多个不同的卷积核(例如 3 × 3 3 \times 3 3×3、 5 × 5 5 \times 5 5×5 或 7 × 7 7 \times 7 7×7),在训练时选择或组合这些不同的核。这样,卷积层可以在不同尺度上提取特征,使模型更具鲁棒性。
-
混合卷积层:使用不同超参数配置的卷积核进行并行卷积操作,并对结果加权求和。例如,一个卷积层可以并行使用多个 3 × 3 3 \times 3 3×3 卷积核,而每个卷积核使用不同的超参数(如不同的偏置、不同的激活函数),从而增强模型对不同特征的敏感性。
优点
- 提高网络的表达能力:通过使用不同配置的卷积核来捕获多尺度特征,模型能够更加准确地表达图像中的复杂模式。
- 减少过拟合风险:通过引入超参数化的卷积核,模型在一定程度上增加了多样性,从而有助于降低过拟合风险。
- 提高计算效率:尽管增加了卷积核的数量,但超参数化策略可以通过共享参数和组合方式实现,通常不增加计算量。
实例
在深度学习框架(如 PyTorch)中,可以通过定义多个卷积层并将其输出组合来实现深度超参数化卷积。以下是一个简单示例:
import torch
import torch.nn as nn
#超参数卷积
class HyperConv(nn.Module):def __init__(self, in_channels, out_channels):super(HyperConv, self).__init__()# 使用不同的卷积核配置,3*3,5*5,7*7self.conv3x3 = nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1)self.conv5x5 = nn.Conv2d(in_channels, out_channels, kernel_size=5, padding=2)self.conv7x7 = nn.Conv2d(in_channels, out_channels, kernel_size=7, padding=3)# 定义可学习的组合权重self.weight3x3 = nn.Parameter(torch.tensor(0.33))#创建了一个初始化为 0.33 的可学习参数。这种参数在训练过程中可以通过反向传播进行更新self.weight5x5 = nn.Parameter(torch.tensor(0.33))self.weight7x7 = nn.Parameter(torch.tensor(0.34))def forward(self, x):# 分别应用不同的卷积核out3x3 = self.conv3x3(x)out5x5 = self.conv5x5(x)out7x7 = self.conv7x7(x)# 组合加权输出out = self.weight3x3 * out3x3 + self.weight5x5 * out5x5 + self.weight7x7 * out7x7return out# 测试示例
model = HyperConv(in_channels=3, out_channels=16)
input_tensor = torch.randn(1, 3, 64, 64) # 示例输入
output = model(input_tensor)
print(output.shape) # 输出形状
Dice系数
Dice 系数(Dice Coefficient),又称为 Dice 相似系数(Dice Similarity Coefficient, DSC),是一种常用于衡量两个集合相似度的指标。特别是在图像分割任务中,Dice 系数常用来评估模型分割结果与真实标注的吻合程度。
Dice 系数定义
对于两个集合 A A A 和 B B B,Dice 系数定义为:
Dice ( A , B ) = 2 ∣ A ∩ B ∣ ∣ A ∣ + ∣ B ∣ \text{Dice}(A, B) = \frac{2 |A \cap B|}{|A| + |B|} Dice(A,B)=∣A∣+∣B∣2∣A∩B∣
和交并比几乎一样,乘以二是因为,交的一定小于和的一半。
在图像分割任务中:
- A A A 表示模型分割得到的前景区域(预测结果)。
- B B B 表示真实的前景区域(标注数据)。
Dice 系数的值范围在 [ 0 , 1 ] [0, 1] [0,1] 之间:
- 当 Dice 系数为 1 时,说明预测结果与真实标注完全吻合。
- 当 Dice 系数为 0 时,表示预测和真实标注完全不重合。
Dice 系数的计算方式
对于二值分割图像 P P P 和 G G G,分别表示预测结果和真实标注,其中每个像素要么属于前景(用1表示),要么属于背景(用0表示)。Dice 系数可以写为:
Dice = 2 × ∣ P ∩ G ∣ ∣ P ∣ + ∣ G ∣ = 2 × T P 2 × T P + F P + F N \text{Dice} = \frac{2 \times |P \cap G|}{|P| + |G|} = \frac{2 \times TP}{2 \times TP + FP + FN} Dice=∣P∣+∣G∣2×∣P∩G∣=2×TP+FP+FN2×TP
其中:
- T P TP TP 表示真正例数(预测为前景且真实为前景的像素数)。
- F P FP FP 表示假正例数(预测为前景但真实为背景的像素数)。
- F N FN FN 表示假负例数(预测为背景但真实为前景的像素数)。
Dice 系数的优缺点
优点:
- Dice 系数特别适合用于不平衡的数据集,比如在医学影像中,前景(目标区域)通常占比很小,但 Dice 系数对小目标也能保持较好的敏感性。
缺点:
- Dice 系数通常对边界更敏感,因此在存在边界模糊的情况下,可能不够稳健。
示例代码
以下是一个基于 PyTorch 的简单示例代码,用于计算 Dice 系数:
import torchdef dice_coefficient(pred, target):smooth = 1e-6 # 避免分母为0,防止除零intersection = (pred * target).sum()dice = (2. * intersection + smooth) / (pred.sum() + target.sum() + smooth)return dice# 示例
pred = torch.tensor([[0, 1, 1], [0, 1, 0], [1, 1, 0]], dtype=torch.float32)
target = torch.tensor([[0, 1, 1], [1, 1, 0], [1, 0, 0]], dtype=torch.float32)dice_score = dice_coefficient(pred, target)
print(f'Dice coefficient: {dice_score:.4f}')
CSP
CSP(Cross Stage Partial) 是一种用于深度学习模型,尤其是在卷积神经网络(CNN)中,用以提高特征提取效率和模型性能的架构设计。CSP 的设计思想主要是在网络的不同阶段之间进行特征的部分交叉,旨在减少计算复杂度的同时保持高效的特征学习。
CSP 的主要概念
-
特征部分交叉:在 CSP 结构中,输入特征图被分成两个部分,然后对其中一部分进行处理。经过处理的特征图与未处理的部分进行拼接或融合,这样可以保留原始信息并增强特征表达能力。
-
阶段分离:CSP 设计将网络划分为多个阶段,每个阶段的输入特征可以通过不同的路径进行处理。这种分离有助于提高模型的灵活性和表达能力。
-
减少计算量:通过部分交叉,CSP 减少了需要处理的特征图数量,从而降低了计算复杂度。这样不仅能加快模型的训练和推理速度,还能减轻显存压力。
CSP 的工作原理
又是一个唬人的单词,本质上就是对图像一半进行处理,另一半进行
CSP 的基本工作原理:
- 输入一个特征图,将其划分为两个部分(例如, A A A 和 B B B)。
- 对部分 A A A 应用某种变换(例如,卷积层、激活函数等)。
- 将变换后的特征与未变换的部分 B B B 进行拼接或相加。
- 将融合后的特征图传递到下一个网络层。
示例
假设我们有一个输入特征图 X
,它的尺寸为 C × H × W C \times H \times W C×H×W(通道数、高度、宽度)。我们可以将其分成两个部分:
-
分割特征图:
- A = X [ : , : C / 2 , : , : ] A = X[:, :C/2, :, :] A=X[:,:C/2,:,:] (第一部分)
- B = X [ : , C / 2 : , : , : ] B = X[:, C/2:, :, :] B=X[:,C/2:,:,:] (第二部分)
-
对 A A A 进行卷积:
- A ′ = Conv ( A ) A' = \text{Conv}(A) A′=Conv(A)
-
拼接:
- Y = concat ( A ′ , B ) Y = \text{concat}(A', B) Y=concat(A′,B)
应用场景
CSP 通常应用于以下场景:
-
目标检测:在 YOLOv4 和 YOLOv5 等检测模型中,通过 CSP 提高了特征提取能力和检测精度。
-
图像分割:在语义分割任务中,CSP 结构有助于保留细节信息,提高分割结果的精度。
-
图像分类:在图像分类任务中,CSP 提高了分类模型的鲁棒性和泛化能力。
CSP 的优缺点
优点
- 高效的特征利用:通过交叉特征增强信息流动,使得网络能够更好地学习特征。
- 减少计算量:由于对特征图进行了部分处理,CSP 减少了不必要的计算,提升了推理速度。
缺点
- 设计复杂性:CSP 结构可能会增加模型的设计和调试复杂性,需要精心设计和调优。
代码示例(PyTorch)
以下是一个简单的 CSP 层的实现示例:
import torch
import torch.nn as nnclass CSPBlock(nn.Module):def __init__(self, in_channels, out_channels):super(CSPBlock, self).__init__()self.split_channels = in_channels // 2#分成两部分self.conv1 = nn.Conv2d(self.split_channels, self.split_channels, kernel_size=3, padding=1)self.conv2 = nn.Conv2d(self.split_channels, self.split_channels, kernel_size=3, padding=1)self.concat_conv = nn.Conv2d(in_channels, out_channels, kernel_size=1)def forward(self, x):# 分割输入特征图A, B = x.split(self.split_channels, dim=1)# 对 A 进行卷积A = self.conv1(A)# 将处理过的 A 和未处理的 B 拼接out = torch.cat((A, B), dim=1)# 通过卷积调整通道数out = self.concat_conv(out)return out# 示例使用
csp_block = CSPBlock(64, 128)
input_tensor = torch.randn(1, 64, 32, 32) # batch size 1, 64 channels, 32x32
output_tensor = csp_block(input_tensor)
print(output_tensor.shape) # 应该是 (1, 128, 32, 32)
在这个例子中,CSPBlock
是一个简单的 CSP 模块,输入特征图被分成两部分,部分特征经过卷积处理后与未处理的部分进行拼接,然后通过一层卷积调整输出的通道数。
letterBox
又是一个唬人的词,本质上是为了确定图像的宽高比,将图像周围进行填充,来提调整图像尺寸。
“Letterbox” 是一种图像处理技术,通常用于调整图像的尺寸,同时保持图像的宽高比,避免失真。
1. Letterbox 的定义
Letterbox 指的是在图像或视频的上下或左右添加黑边,以保持其原始的宽高比。通过这种方式,图像不会被拉伸或裁剪,从而避免失真。
2. 使用场景
- 视频播放:在不同宽高比的显示设备上播放视频时,如果视频的宽高比与屏幕不匹配,系统会在视频的上下或左右添加黑边。
- 图像处理:在深度学习或计算机视觉中,输入图像的大小可能需要调整为特定的尺寸,而使用 letterbox 方法可以在调整大小时保持图像的原始比例。
3. 具体实现
假设我们有一张图像,其尺寸为 400x300(宽x高),而我们希望将其调整为 640x480 的框架。这是一个16:9的宽高比,而原图是4:3的宽高比。使用 letterbox 方法可以将图像调整为新的大小,同时保持其宽高比。
4. 实现示例
以下是一个使用 PyTorch 和 OpenCV 的示例,展示如何实现 letterbox:整体上感觉思路还是比较简单的。
import cv2
import numpy as npdef letterbox(image, target_size):h, w = image.shape[:2]target_w, target_h = target_size# 计算缩放比例scale = min(target_w / w, target_h / h)new_w = int(w * scale)new_h = int(h * scale)# 重新调整图像大小resized_image = cv2.resize(image, (new_w, new_h))# 创建黑色背景letterboxed_image = np.zeros((target_h, target_w, 3), dtype=np.uint8)# 计算填充的偏移量pad_x = (target_w - new_w) // 2pad_y = (target_h - new_h) // 2# 将调整后的图像放到黑色背景中letterboxed_image[pad_y:pad_y + new_h, pad_x:pad_x + new_w] = resized_imagereturn letterboxed_image# 示例使用
image = cv2.imread('path_to_image.jpg') # 读取图像
target_size = (640, 480) # 目标尺寸
result_image = letterbox(image, target_size)# 显示结果
cv2.imshow('Letterboxed Image', result_image)
cv2.waitKey(0)
cv2.destroyAllWindows()