【第二十周】U-Net:用于生物图像分割的卷积神经网络
文章目录
- 摘要
- Abstract
- 文章信息
- 研究动机
- U-Net网络结构
- U-Net网络搭建
- 数据增强
- 损失函数
- 转置卷积
- 创新性与不足
- 创新性:
- 不足:
- 总结
摘要
U-Net(Convolutional Networks for Biomedical Image Segmentation)是一种用于图像分割的深度学习网络,最初设计用于医学图像分割任务。其核心结构由对称的编码器-解码器组成:编码器通过卷积和池化操作逐步提取图像的抽象特征并降低分辨率,从而捕捉目标的全局语义信息;解码器通过上采样和卷积操作逐步恢复分辨率,并结合编码器提供的低层特征图(通过跳跃连接)重建目标的细节信息,从而实现精确的分割。为了解决深层网络中的细节丢失问题,U-Net 引入了跳跃连接,将编码器的低层特征图与解码器的高层特征图拼接,从而保留细节信息并提升分割精度。针对医学图像标注数据有限的问题,U-Net 采用了弹性形变的数据增强技术,增强了模型在少量数据上的泛化能力。然而,U-Net 也存在一些局限性:如对小目标的检测能力有限,对多尺度目标的适应性不足,以及对数据增强的依赖较强。为了解决这些问题,许多方法被提出,例如引入注意力机制(如 CBAM、SE Block)增强特征表达能力,使用多尺度特征融合(如空洞卷积、金字塔池化)提升对多尺度目标的适应性,以及通过自监督学习减少对标注数据的依赖。这些改不仅提升了U-Net的性能,也进一步扩大了其应用范围。
Abstract
U-Net (Convolutional Networks for Biomedical Image Segmentation) is a deep learning network designed for image segmentation, initially developed for medical image segmentation tasks. Its core structure consists of a symmetric encoder-decoder architecture: the encoder gradually extracts abstract features from the image and reduces resolution through convolutional and pooling operations, capturing the global semantic information of the target; the decoder gradually restores resolution through upsampling and convolutional operations, combining low-level feature maps from the encoder (via skip connections) to reconstruct detailed information of the target, thereby achieving precise segmentation. To address the issue of detail loss in deep networks, U-Net introduces skip connections, which concatenate low-level feature maps from the encoder with high-level feature maps from the decoder, preserving detail information and improving segmentation accuracy. To tackle the limited availability of annotated medical image data, U-Net employs data augmentation techniques such as elastic deformation, enhancing the model’s generalization ability with small datasets. However, U-Net also has some limitations: for example, its ability to detect small targets is limited, its adaptability to multi-scale targets is insufficient, and it heavily relies on data augmentation. To address these issues, many methods have been proposed, such as introducing attention mechanisms (e.g., CBAM, SE Block) to enhance feature representation, using multi-scale feature fusion (e.g., dilated convolution, pyramid pooling) to improve adaptability to multi-scale targets, and leveraging self-supervised learning to reduce dependence on annotated data. These improvements not only enhance the performance of U-Net but also further expand its application scope.
文章信息
Title:U-Net: Convolutional Networks for Biomedical Image Segmentation
Author:Olaf Ronneberger, Philipp Fischer, and Thomas Brox
Source:https://arxiv.org/abs/1505.04597
研究动机
从2012年Alexnet的提出以来,卷积神经网络已经广泛运用于计算机视觉任务。卷积网络的典型用途是分类任务,其中图像的输出是单个类别标签。然而,在许多视觉任务中,尤其是在生物医学图像处理中,期望的输出应当包括定位,即,假设将类标签分配给每个像素。此外,在生物医学任务中,用于训练的数据很少。所以,本文构建了一种全卷积网络用来分割图像,这种网络需要的训练图像很少,却能产生精确的分割结果。
U-Net网络结构
U-Net网络是一个全卷积网络,是一个编码-解码的结构,有基本的对称性。

U-Net的网络架构如上图所示,U-Net 可以分为三部分:
第一部分是主干特征提取部分,遵循经典的卷积网络架构,是卷积和最大池化的堆叠,利用主干特征提取部分我们可以获得五个初步有效特征层。
第二部分是加强特征提取部分,对主干特征提取部分得到的五个初步有效特征层进行逐步的上采样和拼接融合,得到与第一个初步有效特征层有相同通道数的特征层。
第三部分是预测部分,对第二部分得到的特征层进行卷积操作,对每一个像素点分类,得到图像分割结果图。
下面对具体的卷积层和上采样层进行说明:
- conv 3 × 3 3\times 3 3×3,ReLU:此结构中所有的卷积都是 s t r i d e = 1 stride = 1 stride=1, p a d d i n g = 0 padding = 0 padding=0,此结构在主干特征提取部分使用,除连接输入的卷积层用的第一个卷积核通道是64外,其他卷积层的通道数都是输入通道数的2倍(通道数加倍以弥补下采样带来的损失)。
- copy and crop:对主干特征提取部分得到的前四个初步有效特征层进行裁剪,以便与上采样得来的特征层进行拼接。
- max pool 2 × 2 2\times 2 2×2:做 2 × 2 2\times 2 2×2的最大池化操作(下采样), s t r i d e = 2 stride = 2 stride=2, p a d d i n g = 0 padding = 0 padding=0,池化前后的通道数不变,宽高减半。
- up-conv 2 × 2 2\times 2 2×2:上采样,可用转置卷积或双线性插值等,转置卷积前后宽高加倍,通道数减半。
- conv 1 × 1 1\times 1 1×1:卷积核为 1 × 1 1\times 1 1×1的卷积操作, s t r i d e = 1 stride = 1 stride=1, p a d d i n g = 0 padding = 0 padding=0,用在预测部分,卷积后,通道数变为类别数(包括背景类别)。
U-Net 还是一个编码-解码的结构,编码器就是下采样路径,通过卷积和池化操作提取特征。解码器就是上采样路径,通过上采样和跳跃连接恢复分辨率。
U-Net网络搭建
首先,为了方便搭建网络,可以定义一个标准的卷积块。另外吗,本网络不是严格按中文中的网络设置进行搭建的。在实现中,实际上可以在下采样的卷积操作时设置 padding = 1 ,以保持卷积前后的宽高不变,这样在与上采样的结果进行拼接时就不需要裁剪(文中的上采样后宽高加倍),最终得到的分割结果也是和输入图像的尺寸一样,而不是输入图像中间的一部分。
def _block(in_channels, features, name):"""定义一个标准的卷积块。参数:in_channels (int): 输入通道数。features (int): 输出通道数。name (str): 块的名称(用于调试)。返回:nn.Sequential: 包含两个卷积层、两个批归一化层和两个 ReLU 激活函数的序列模块。"""return nn.Sequential(nn.Conv2d(in_channels=in_channels,out_channels=features,kernel_size=3,padding=1, #不同于原文,设置 padding=1 使卷积前后的宽高保持不变bias=False,),nn.BatchNorm2d(num_features=features), # 批归一化层nn.ReLU(inplace=True), # ReLU 激活函数nn.Conv2d(in_channels=features,out_channels=features,kernel_size=3,padding=1,bias=False,),nn.BatchNorm2d(num_features=features), # 批归一化层nn.ReLU(inplace=True), # ReLU 激活函数)
标准卷积块的参数信息:
in_channels:是卷积块的输入通道数,int型;
features:是卷积块的输出通道数,int型;
name:是块的名称,方便调试,string型。
本函数返回的是经过两组卷积、Batchnormal、ReLu操作后的结果。
接下来搭建编码器部分:
先说明网络中的参数:
in_channels : 输入图像的通道数(例如,灰度图为 1,RGB 图为 3),int型。
out_channels : 输出图像的通道数(例如,二分类任务为 1,多分类任务为类别数),int型。
init_features : 初始特征通道数(决定网络的宽度),int型。
features = init_features #定义编码器的通道数# 编码器部分(下采样路径)# 第一个编码器块self.encoder1 = UNet._block(in_channels, features, name="enc1") # 最大池化层self.pool1 = nn.MaxPool2d(kernel_size=2, stride=2) # 第二个编码器块self.encoder2 = UNet._block(features, features * 2, name="enc2") # 最大池化层self.pool2 = nn.MaxPool2d(kernel_size=2, stride=2) # 第三个编码器块self.encoder3 = UNet._block(features * 2, features * 4, name="enc3") # 最大池化层self.pool3 = nn.MaxPool2d(kernel_size=2, stride=2) # 第四个编码器块self.encoder4 = UNet._block(features * 4, features * 8, name="enc4") # 最大池化层self.pool4 = nn.MaxPool2d(kernel_size=2, stride=2)
编码器和解码器之间还有一个连接的部分:
# 底部(最深层)self.bottleneck = UNet._block(features * 8, features * 16, name="bottleneck")
下面搭建解码器部分:
# 上采样层self.upconv4 = nn.ConvTranspose2d(features * 16, features * 8, kernel_size=2, stride=2) # 第四个解码器块self.decoder4 = UNet._block(features * 16, features * 8, name="dec4")# 上采样层 self.upconv3 = nn.ConvTranspose2d(features * 8, features * 4, kernel_size=2, stride=2) # 第三个解码器块self.decoder3 = UNet._block(features * 8, features * 4, name="dec3") # 上采样层self.upconv2 = nn.ConvTranspose2d(features * 4, features * 2, kernel_size=2, stride=2) # 第二个解码器块self.decoder2 = UNet._block(features * 4, features * 2, name="dec2") # 上采样层self.upconv1 = nn.ConvTranspose2d(features * 2, features, kernel_size=2, stride=2) # 第一个解码器块self.decoder1 = UNet._block(features * 2, features, name="dec1")
下面是输出层(预测层):
# 输出层self.conv = nn.Conv2d(in_channels=features, out_channels=out_channels, kernel_size=1) # 1x1 卷积层
整体网络搭建:
import torch
import torch.nn as nn
import torch.nn.functional as Fclass UNet(nn.Module):def __init__(self, in_channels=1, out_channels=1, init_features=32):"""U-Net 初始化函数。参数:in_channels (int): 输入图像的通道数(例如,灰度图为 1,RGB 图为 3)。out_channels (int): 输出图像的通道数(例如,二分类任务为 1,多分类任务为类别数)。init_features (int): 初始特征通道数(决定网络的宽度)。"""super(UNet, self).__init__()# 定义编码器的特征通道数features = init_features# 编码器部分(下采样路径)self.encoder1 = UNet._block(in_channels, features, name="enc1") # 第一个编码器块self.pool1 = nn.MaxPool2d(kernel_size=2, stride=2) # 最大池化层self.encoder2 = UNet._block(features, features * 2, name="enc2") # 第二个编码器块self.pool2 = nn.MaxPool2d(kernel_size=2, stride=2) # 最大池化层self.encoder3 = UNet._block(features * 2, features * 4, name="enc3") # 第三个编码器块self.pool3 = nn.MaxPool2d(kernel_size=2, stride=2) # 最大池化层self.encoder4 = UNet._block(features * 4, features * 8, name="enc4") # 第四个编码器块self.pool4 = nn.MaxPool2d(kernel_size=2, stride=2) # 最大池化层# 底部(最深层)self.bottleneck = UNet._block(features * 8, features * 16, name="bottleneck") # 瓶颈层# 解码器部分(上采样路径)self.upconv4 = nn.ConvTranspose2d(features * 16, features * 8, kernel_size=2, stride=2) # 上采样层self.decoder4 = UNet._block(features * 16, features * 8, name="dec4") # 第四个解码器块self.upconv3 = nn.ConvTranspose2d(features * 8, features * 4, kernel_size=2, stride=2) # 上采样层self.decoder3 = UNet._block(features * 8, features * 4, name="dec3") # 第三个解码器块self.upconv2 = nn.ConvTranspose2d(features * 4, features * 2, kernel_size=2, stride=2) # 上采样层self.decoder2 = UNet._block(features * 4, features * 2, name="dec2") # 第二个解码器块self.upconv1 = nn.ConvTranspose2d(features * 2, features, kernel_size=2, stride=2) # 上采样层self.decoder1 = UNet._block(features * 2, features, name="dec1") # 第一个解码器块# 输出层self.conv = nn.Conv2d(in_channels=features, out_channels=out_channels, kernel_size=1) # 1x1 卷积层def forward(self, x):"""前向传播函数。参数:x (torch.Tensor): 输入图像张量,形状为 (batch_size, in_channels, height, width)。返回:torch.Tensor: 输出分割结果,形状为 (batch_size, out_channels, height, width)。"""# 编码器部分enc1 = self.encoder1(x) # 第一个编码器块enc2 = self.encoder2(self.pool1(enc1)) # 第二个编码器块enc3 = self.encoder3(self.pool2(enc2)) # 第三个编码器块enc4 = self.encoder4(self.pool3(enc3)) # 第四个编码器块# 底部(最深层)bottleneck = self.bottleneck(self.pool4(enc4)) # 瓶颈层# 解码器部分dec4 = self.upconv4(bottleneck) # 上采样dec4 = torch.cat((dec4, enc4), dim=1) # 跳跃连接(拼接编码器的特征图)dec4 = self.decoder4(dec4) # 第四个解码器块dec3 = self.upconv3(dec4) # 上采样dec3 = torch.cat((dec3, enc3), dim=1) # 跳跃连接dec3 = self.decoder3(dec3) # 第三个解码器块dec2 = self.upconv2(dec3) # 上采样dec2 = torch.cat((dec2, enc2), dim=1) # 跳跃连接dec2 = self.decoder2(dec2) # 第二个解码器块dec1 = self.upconv1(dec2) # 上采样dec1 = torch.cat((dec1, enc1), dim=1) # 跳跃连接dec1 = self.decoder1(dec1) # 第一个解码器块# 输出层return torch.sigmoid(self.conv(dec1)) # 1x1 卷积 + Sigmoid 激活函数@staticmethoddef _block(in_channels, features, name):"""定义一个标准的卷积块。参数:in_channels (int): 输入通道数。features (int): 输出通道数。name (str): 块的名称(用于调试)。返回:nn.Sequential: 包含两个卷积层、两个批归一化层和两个 ReLU 激活函数的序列模块。"""return nn.Sequential(nn.Conv2d(in_channels=in_channels,out_channels=features,kernel_size=3,padding=1,bias=False,),nn.BatchNorm2d(num_features=features), # 批归一化层nn.ReLU(inplace=True), # ReLU 激活函数nn.Conv2d(in_channels=features,out_channels=features,kernel_size=3,padding=1,bias=False,),nn.BatchNorm2d(num_features=features), # 批归一化层nn.ReLU(inplace=True), # ReLU 激活函数)
下面对模型进行实例化,测试是否正常:
model = UNet(in_channels=1, out_channels=1, init_features=32)
print(model)
运行的部分结果如下:


可见输出与输入的宽高尺寸一致,各部分也都正常。
数据增强
作者使用弹性形变来进行数据增强,由于数据集的不足,并且数据集是细胞组织的图像,细胞组织的边界每时每刻都会发生不规则的畸变,所以这种弹性形变非常有必要。弹性形变可以让网络学习更稳定的图像特征。
使用随机位移矢量在粗糙的3*3网格上(random displacement vectors on a coarse 3 by 3 grid)产生平滑形变(smooth deformations)。 位移是从10像素标准偏差的高斯分布中采样的。然后使用双三次插值计算每个像素的位移。在contracting path的末尾采用drop-out 层更进一步增加数据。
损失函数
文中使用的损失函数为:pixel-wise softmax + cross_entropy
softmax函数为:

其中 K K K 代表类别数量, x x x 代表像素位置, a k ( x ) a_k(x) ak(x) 表示像素 x x x 预测为 K K K 的概率。
交叉熵损失函数:

ι:Ω→(1,2,3…K)代表true label, w 是权重
对于细胞的分割,细胞间的间隙需要设置较大的损失权重,而大片的背景区域需要设置相对较小的损失权重,下图是文中的权重热力图。

文中对损失权重的定义为:

其中, W c ( x ) W_c(x) Wc(x)是用于平衡类别频率的权重函数, d 1 d_1 d1是与最近细胞的距离, d 2 d_2 d2是与第二近的细胞的距离。
转置卷积
转置卷积(Transposed Convolution)在语义分割和对抗神经网络(GAN)中较为常见,其主要作用就是上采样。
转置卷积也是一种卷积操作,但不是卷积的逆运算。
卷积操作直观上理解就是卷积核在输入上进行滑动卷积

等效矩阵:每次一个卷积核在一个位置上的卷积操作可以等效为矩阵的乘法:

输入转换成一个向量,每一个等效矩阵转化为一个列向量,然后拼接在一起形成矩阵。

通过输入向量和卷积核矩阵的相乘获得输出向量。输出的向量经过整形便可得到我们的二维输出特征。
将输入记为 I I I,向量化的卷积向量记为 C C C,输出向量记为 O O O,则有: I T ∗ C = O T I^T*C=O^T IT∗C=OT

转置卷积就是按照此思想还原出输出的形状,注意,转置卷积不是卷积的逆运算,而只是形状上的相反关系:
O T ∗ C T = I T O^T*C^T=I^T OT∗CT=IT

转置卷积的操作:
- 在输入特征图元素间填充s-1行、列0(其中s表示转置卷积的步距)
- 在输入特征图四周填充k-p-1行、列0(其中k表示转置卷积的kernel_size大小,p为转置卷积的padding,注意这里的padding和卷积操作中有些不同)
- 将卷积核参数上下、左右翻转
- 做正常卷积运算(填充0,步距1)

下面是 s = 2 , p = 1 , k = 3 s=2,p=1,k=3 s=2,p=1,k=3的计算例子:

转置卷积后特征图的大小计算如下:

其中stride[0]表示高度方向的stride,padding[0]表示高度方向的padding,kernel_size[0]表示高度方向的kernel_size,索引[1]都表示宽度方向上的。通过上面公式可看出padding越大,输出的特征矩阵高、宽越小,你可以理解为正向卷积过程中进行了padding然后得到了特征图,现在使用转置卷积还原到原来高、宽后要把之前的padding减掉。
pytorch中给出的转置卷积函数信息如下:

输出特征图宽高计算如下:

下面对转置卷积进行实验:
import torch
import torch.nn as nndef transposed_conv_official():feature_map = torch.as_tensor([[1, 0],[2, 1]], dtype=torch.float32).reshape([1, 1, 2, 2])print(feature_map)trans_conv = nn.ConvTranspose2d(in_channels=1, out_channels=1,kernel_size=3, stride=1, bias=False)trans_conv.load_state_dict({"weight": torch.as_tensor([[1, 0, 1],[0, 1, 1],[1, 0, 0]], dtype=torch.float32).reshape([1, 1, 3, 3])})print(trans_conv.weight)output = trans_conv(feature_map)print(output)def transposed_conv_self():feature_map = torch.as_tensor([[0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0],[0, 0, 1, 0, 0, 0],[0, 0, 2, 1, 0, 0],[0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0]], dtype=torch.float32).reshape([1, 1, 6, 6])print(feature_map)conv = nn.Conv2d(in_channels=1, out_channels=1,kernel_size=3, stride=1, bias=False)conv.load_state_dict({"weight": torch.as_tensor([[0, 0, 1],[1, 1, 0],[1, 0, 1]], dtype=torch.float32).reshape([1, 1, 3, 3])})print(conv.weight)output = conv(feature_map)print(output)def main():transposed_conv_official()print("---------------")transposed_conv_self()if __name__ == '__main__':main()
transposed_conv_official函数是使用官方的转置卷积进行计算,transposed_conv_self函数是按照上面讲的步骤自己对输入特征图进行填充并通过卷积得到的结果。
终端输出为:
tensor([[[[1., 0.],[2., 1.]]]])
Parameter containing:
tensor([[[[1., 0., 1.],[0., 1., 1.],[1., 0., 0.]]]], requires_grad=True)
tensor([[[[1., 0., 1., 0.],[2., 2., 3., 1.],[1., 2., 3., 1.],[2., 1., 0., 0.]]]], grad_fn=<SlowConvTranspose2DBackward>)
---------------
tensor([[[[0., 0., 0., 0., 0., 0.],[0., 0., 0., 0., 0., 0.],[0., 0., 1., 0., 0., 0.],[0., 0., 2., 1., 0., 0.],[0., 0., 0., 0., 0., 0.],[0., 0., 0., 0., 0., 0.]]]])
Parameter containing:
tensor([[[[0., 0., 1.],[1., 1., 0.],[1., 0., 1.]]]], requires_grad=True)
tensor([[[[1., 0., 1., 0.],[2., 2., 3., 1.],[1., 2., 3., 1.],[2., 1., 0., 0.]]]], grad_fn=<ThnnConv2DBackward>)Process finished with exit code 0
根据输出可知,官方的转置卷积函数与通过以上的步骤实现的转置卷积的结果一致。
创新性与不足
创新性:
- 编码器-解码器结构:编码器通过卷积和池化操作逐步提取特征,降低分辨率。解码器通过上采样和卷积操作逐步恢复分辨率。这种结构能够有效地捕捉图像的全局信息和局部细节。
- 跳跃连接:在编码器和解码器之间引入了跳跃连接,将低层特征图与高层特征图拼接。保留了低层特征的细节信息,有助于精确分割目标边界。
- 数据增强策略:训练过程中使用了弹性形变等数据增强技术。提高了模型在少量标注数据上的泛化能力。
不足:
- 对小目标的检测能力有限:尽管 U-Net 通过跳跃连接保留了低层特征,但其低层特征的语义信息不足,在处理极小目标时仍可能丢失细节信息。
- 对遮挡目标的处理能力有限: 此模型难以区分重叠目标的边界。
- 长距离依赖性不足:UNet捕捉全局上下文的能力有限,虽然跳连接保留了部分空间信息,但在处理更大范围内的上下文关系时,传统卷积操作仍然难以有效捕捉远距离的依赖性。
总结
U-NetU-Net 采用对称的编码器-解码器设计,编码器通过卷积和池化操作提取特征,解码器通过上采样和卷积操作恢复分辨率。这种架构允许U-Net进行端到端训练,并有效地从有限的数据集中学习。U-Net 最初用于医学图像分割(如细胞分割、肿瘤检测),但其高效的架构和强大的性能使其迅速扩展到其他领域,包括:卫星图像分析、工业检测、自然图像处理等。尽管存在一些局限性,但通过不断的改进和优化,U-Net 及其变体在图像分割任务中仍然具有广泛的应用前景。
相关文章:
【第二十周】U-Net:用于生物图像分割的卷积神经网络
文章目录 摘要Abstract文章信息研究动机U-Net网络结构U-Net网络搭建数据增强损失函数转置卷积创新性与不足创新性:不足: 总结 摘要 U-Net(Convolutional Networks for Biomedical Image Segmentation)是一种用于图像分割的深度学…...
部署Metricbeat监测ES
官方参考文档 安装Metricbeat curl -L -O https://artifacts.elastic.co/downloads/beats/metricbeat/metricbeat-7.17.27-linux-x86_64.tar.gztar xzvf metricbeat-7.17.27-linux-x86_64.tar.gz设置 Metricbeat连接到 Elasticsearch 进入metricbeat目录配置metricbeat.yml …...
Pytorch|YOLO
🍨 本文为🔗365天深度学习训练营中的学习记录博客🍖 原作者:K同学啊 一、 前期准备 1. 设置GPU 如果设备上支持GPU就使用GPU,否则使用CPU import torch import torch.nn as nn import torchvision.transforms as transforms im…...
云计算与物联网技术的融合应用(在工业、农业、家居、医疗、环境、城市等整理较全)
摘要 为生产领域带来更加全面和深入的变革。通过云计算平台对物联网数据进行处理和分析,企业可以实现对生产过程的更加精细化的管理和控制。 1. 智能生产调度 通过云计算和物联网技术的融合应用,企业可以实现对生产线上各个环节的实时监控和数据分析。…...
基于python+Django+mysql鲜花水果销售商城网站系统设计与实现
博主介绍:黄菊华老师《Vue.js入门与商城开发实战》《微信小程序商城开发》图书作者,CSDN博客专家,在线教育专家,CSDN钻石讲师;专注大学生毕业设计教育、辅导。 所有项目都配有从入门到精通的基础知识视频课程ÿ…...
Golang:报错no required module provides package github.com/xx的解决方法
报错 问题重现可能的原因及解决方法1. 未初始化 Go 模块解决方法: 2. 没有添加依赖解决方法: 3. 网络问题解决方法: 4. 依赖版本问题解决方法: 5. 包未发布或路径拼写错误解决方法: 6. go mod tidy 未运行解决方法&…...
数据结构与算法(2):顺序表与链表
1.前言 哈喽大家好喔,今天博主继续进行数据结构的分享与学习,今天的主要内容是顺序表与链表,是最简单但又相当重要的数据结构,为以后的学习有重要的铺垫,希望大家一起交流学习,互相进步,让我们…...
华为OD机试E卷 --过滤组合字符串--24年OD统一考试(Java JS Python C C++)
文章目录 题目描述输入描述输出描述用例题目解析JS算法源码Java算法源码python算法源码c算法源码c++算法源码题目描述 数字 0、1、2、3、4、5、6、7、8、9 分别关联 a~z 26 个英文字母。 0 关联“a”"b”"c1 关联“d”"e”"f2 关联“g"“h”“i”3 关…...
QT跨平台应用程序开发框架(3)—— 信号和槽
目录 一,基本概念 二,connect函数使用 2.1 connect 2.2 Qt内置信号和槽 2.3 一些细节 三,自定义信号和槽 3.1 自定义槽函数 3.2 自定义信号 3.3 带参数的信号槽 四,信号和槽的意义 五,信号和槽断开连接 六&…...
从 0 开始实现一个 SpringBoot + Vue 项目
从 0 开始实现一个 SpringBoot Vue 项目 从 0 开始实现一个 SpringBoot Vue 项目 软件和工具创建 SpringBoot 后端项目创建 MySQL 数据库配置文件实现增删改查接口 Model 层mapper 层service 层controller 层测试 实现项目功能接口 代码测试 创建 Vue 前端 安装 Node.js配置…...
【无标题】微调是迁移学习吗?
是的,微调(Fine-Tuning)可以被视为一种迁移学习(Transfer Learning)的形式。迁移学习是一种机器学习方法,其核心思想是利用在一个任务上学到的知识来改进另一个相关任务的性能。微调正是通过在预训练模型的…...
虚幻基础1:hello world
能帮到你的话,就给个赞吧 😘 文章目录 hello world创建项目创建关卡创建蓝图将蓝图插入关卡中运行 hello world 本文引擎为5.5.1 创建项目 如图 创建后如图。 创建关卡 如图 创建蓝图 如图 选择actor 双击进入蓝图节点 选择事件图表 创…...
C链表的一些基础知识
一、链表的基本概念 链表是一种常见的线性数据结构,它由一系列节点组成,每个节点包含数据部分和指向下一个节点的指针(单链表情况)。通过指针将各个节点连接起来,与数组不同,链表在内存中的存储不是连续的…...
JDK长期支持版本(LTS)
https://blogs.oracle.com/java/post/the-arrival-of-java-23 jdk长期支持版本(LTS):JDK 8、11、17、21:...
【超详细】Python datetime(当前日期、时间戳转换、前一天日期等)【附:时区原理详解】
文章目录 相关文献当前时间前一天日期、后一天日期东八区(北京)时间时间戳转换datetime -> strstr -> datetimedatetime -> timestamp(时间戳)timestamp -> datetime 获取日期中的年、季度、月、周、日、小时、分、秒等时区原理时区问题复杂…...
【Excel】【VBA】双列排序:坐标从Y从大到小排列之后相同Y坐标的行再对X从小到大排列
Excel VBA 双列排序 功能概述 这段VBA代码实现了Excel中的双列排序功能,具体是: 跳过前3行表头先按C列数据从大到小排序在C列值相同的情况下,按B列从大到小排序排序时保持整行数据的完整性 流程图 #mermaid-svg-XJERemQluZlM4K8l {font-fa…...
为什么相关性不是因果关系?人工智能中的因果推理探秘
目录 一、背景 (一)聚焦当下人工智能 (二)基于关联框架的人工智能 (三)基于因果框架的人工智能 二、因果推理的基本理论 (一)因果推理基本范式:因果模型࿰…...
Nginx调优
Nginx 是一个高性能的反向代理服务器和负载均衡器,在处理大量并发请求时表现出色。但是,随着系统负载的增加,Nginx 的性能可能受到多方面的影响,因此进行适当的调优至关重要。以下是 Nginx 调优的几个方向和关键点: 1…...
联德胜w801开发板(四)实现腾讯云mqtt的订阅和发布
一、开发准备 在设备开发这里我们就能看到物模型的topic,跟之前用stm32esp8266一样 附上之前的链接: STM32ESP8266连接腾讯IOT上传数据(四)_stm32通过esp8266上传数据到云平台-CSDN博客https://blog.csdn.net/Try1harder/article/details/134914027?…...
LLM框架对比选择:MaxKB、Dify、FastGPT、RagFlow【RAG+AI工作流+Agent]
1.MaxKB MaxKB Max Knowledge Base,是一款基于 LLM 大语言模型的开源知识库问答系统,旨在成为企业的最强大脑。它能够帮助企业高效地管理知识,并提供智能问答功能。想象一下,你有一个虚拟助手,可以回答各种关于公司内…...
使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式
一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明:假设每台服务器已…...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...
连锁超市冷库节能解决方案:如何实现超市降本增效
在连锁超市冷库运营中,高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术,实现年省电费15%-60%,且不改动原有装备、安装快捷、…...
测试markdown--肇兴
day1: 1、去程:7:04 --11:32高铁 高铁右转上售票大厅2楼,穿过候车厅下一楼,上大巴车 ¥10/人 **2、到达:**12点多到达寨子,买门票,美团/抖音:¥78人 3、中饭&a…...
涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战
“🤖手搓TuyaAI语音指令 😍秒变表情包大师,让萌系Otto机器人🔥玩出智能新花样!开整!” 🤖 Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制(TuyaAI…...
自然语言处理——循环神经网络
自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元(GRU)长短期记忆神经网络(LSTM)…...
MySQL用户和授权
开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务: test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...
python执行测试用例,allure报乱码且未成功生成报告
allure执行测试用例时显示乱码:‘allure’ �����ڲ����ⲿ���Ҳ���ǿ�&am…...
【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习
禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...
C++.OpenGL (14/64)多光源(Multiple Lights)
多光源(Multiple Lights) 多光源渲染技术概览 #mermaid-svg-3L5e5gGn76TNh7Lq {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-3L5e5gGn76TNh7Lq .error-icon{fill:#552222;}#mermaid-svg-3L5e5gGn76TNh7Lq .erro…...
