YOLOv8改进 | 融合改进 | C2f融合Faster-GELU模块提升检测速度【完整代码 + 主要代码解析】

本文主要是介绍YOLOv8改进 | 融合改进 | C2f融合Faster-GELU模块提升检测速度【完整代码 + 主要代码解析】,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

秋招面试专栏推荐 :深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转


💡💡💡本专栏所有程序均经过测试,可成功执行💡💡💡


专栏目录 :《YOLOv8改进有效涨点》专栏介绍 & 专栏目录 | 目前已有100+篇内容,内含各种Head检测头、损失函数Loss、Backbone、Neck、NMS等创新点改进——点击即可跳转


本文介绍一种部分卷积(PConv)以高效提取特征,减少冗余计算和内存访问。基于PConv,构建了FasterNet神经网络,它在多种设备上运行更快,且机会不影响视觉任务的准确性。此外,卷积的机会函数将替换为GELU。文章在介绍主要的原理后,将手把手教学如何进行模块的代码添加和修改,并将修改后的完整代码放在文章的最后,方便大家一键运行,小白也可轻松上手实践。以帮助您更好地学习深度学习目标检测YOLO系列的挑战。 

专栏地址YOLOv8改进——更新各种有效涨点方法——点击即可跳转  

目录

1. 原理

2. 将C2f_Faster添加到yolov8网络中

2.1 C2f_Faster 代码实现

 2.2 Faster_Block_CGLU的神经网络模块代码解析

2.3 更改init.py文件

2.4 添加yaml文件

2.5 注册模块

2.6 执行程序

3. 完整代码分享

4. GFLOPs

5. 进阶

6. 总结


1. 原理

论文地址:GAUSSIAN ERROR LINEAR UNITS (GELUS)——点击即可跳转

官方代码:官方代码仓库——点击即可跳转

GELU(Gaussian Error Linear Unit)激活函数是一种用于神经网络的非线性激活函数。它的主要原理基于将输入按其值进行加权,而不是像ReLU那样通过输入的符号来控制输出。

GELU的主要原理:

  1. 数学表达式:GELU的表达式为\text{GELU}(x) = x \Phi(x),其中\Phi(x) 是标准高斯分布的累积分布函数(CDF)。这意味着GELU函数的输出是输入值与输入值在标准正态分布中小于等于它的概率的乘积。

  2. 输入值的加权:不同于ReLU(直接将输入小于零的部分置为零),GELU通过 \Phi(x) 平滑地控制输入的通过情况。对于较大的正输入,GELU近似为输入本身;对于负输入,GELU将其逐渐减小到接近零,而不是直接变为零。

  3. 近似计算:GELU函数可以近似为以下公式,以便提高计算效率:\text{GELU}(x) \approx 0.5x(1 + \tanh[\sqrt{2/\pi}(x + 0.044715x^3)]) 这种近似形式保留了GELU的核心特性,并在计算速度上有所提升。

  4. 与ReLU和ELU的比较:GELU的非线性特性在多个任务中表现出色,例如计算机视觉、自然语言处理和语音识别。相比于ReLU和ELU,GELU能够更好地处理输入噪声,并且在没有丢弃的情况下表现出更低的训练损失。

通过这种平滑的处理方式,GELU在确保非线性的同时,能够在一定程度上保留输入的特性,这有助于网络更好地拟合复杂的数据分布。

2. 将C2f_Faster添加到yolov8网络中

2.1 C2f_Faster 代码实现

关键步骤一将下面代码粘贴到在/ultralytics/ultralytics/nn/modules/block.py中,并在该文件的__all__中添加“C2f_Faster_CGLU”


from timm.models.layers import DropPath
class Partial_conv3(nn.Module):def __init__(self, dim, n_div=4, forward='split_cat'):super().__init__()self.dim_conv3 = dim // n_divself.dim_untouched = dim - self.dim_conv3self.partial_conv3 = nn.Conv2d(self.dim_conv3, self.dim_conv3, 3, 1, 1, bias=False)if forward == 'slicing':self.forward = self.forward_slicingelif forward == 'split_cat':self.forward = self.forward_split_catelse:raise NotImplementedErrordef forward_slicing(self, x):# only for inferencex = x.clone()   # !!! Keep the original input intact for the residual connection laterx[:, :self.dim_conv3, :, :] = self.partial_conv3(x[:, :self.dim_conv3, :, :])return xdef forward_split_cat(self, x):# for training/inferencex1, x2 = torch.split(x, [self.dim_conv3, self.dim_untouched], dim=1)x1 = self.partial_conv3(x1)x = torch.cat((x1, x2), 1)return xclass ConvolutionalGLU(nn.Module):def __init__(self, in_features, hidden_features=None, out_features=None, act_layer=nn.GELU, drop=0.) -> None:super().__init__()out_features = out_features or in_featureshidden_features = hidden_features or in_featureshidden_features = int(2 * hidden_features / 3)self.fc1 = nn.Conv2d(in_features, hidden_features * 2, 1)self.dwconv = nn.Sequential(nn.Conv2d(hidden_features, hidden_features, kernel_size=3, stride=1, padding=1, bias=True, groups=hidden_features),act_layer())self.fc2 = nn.Conv2d(hidden_features, out_features, 1)self.drop = nn.Dropout(drop)# def forward(self, x):#     x, v = self.fc1(x).chunk(2, dim=1)#     x = self.dwconv(x) * v#     x = self.drop(x)#     x = self.fc2(x)#     x = self.drop(x)#     return xdef forward(self, x):x_shortcut = xx, v = self.fc1(x).chunk(2, dim=1)x = self.dwconv(x) * vx = self.drop(x)x = self.fc2(x)x = self.drop(x)return x_shortcut + xclass Faster_Block_CGLU(nn.Module):def __init__(self,inc,dim,n_div=4,mlp_ratio=2,drop_path=0.1,layer_scale_init_value=0.0,pconv_fw_type='split_cat'):super().__init__()self.dim = dimself.mlp_ratio = mlp_ratioself.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity()self.n_div = n_divself.mlp = ConvolutionalGLU(dim)self.spatial_mixing = Partial_conv3(dim,n_div,pconv_fw_type)self.adjust_channel = Noneif inc != dim:self.adjust_channel = Conv(inc, dim, 1)if layer_scale_init_value > 0:self.layer_scale = nn.Parameter(layer_scale_init_value * torch.ones((dim)), requires_grad=True)self.forward = self.forward_layer_scaleelse:self.forward = self.forwarddef forward(self, x):if self.adjust_channel is not None:x = self.adjust_channel(x)shortcut = xx = self.spatial_mixing(x)x = shortcut + self.drop_path(self.mlp(x))return xdef forward_layer_scale(self, x):shortcut = xx = self.spatial_mixing(x)x = shortcut + self.drop_path(self.layer_scale.unsqueeze(-1).unsqueeze(-1) * self.mlp(x))return xclass C3_Faster_CGLU(C3):def __init__(self, c1, c2, n=1, shortcut=False, g=1, e=0.5):super().__init__(c1, c2, n, shortcut, g, e)c_ = int(c2 * e)  # hidden channelsself.m = nn.Sequential(*(Faster_Block_CGLU(c_, c_) for _ in range(n)))class C2f_Faster_CGLU(C2f):def __init__(self, c1, c2, n=1, shortcut=False, g=1, e=0.5):super().__init__(c1, c2, n, shortcut, g, e)self.m = nn.ModuleList(Faster_Block_CGLU(self.c, self.c) for _ in range(n))

 2.2 Faster_Block_CGLU的神经网络模块代码解析

这段代码定义一个名为Faster_Block_CGLU的神经网络模块,主要包括了卷积操作、空间混合操作以及层级缩放。卷积函数使用的是带有GELU激活函数的ConvolutionalGLU

代码结构和关键部分:

  1. 构造函数 (__init__):

    • inc: 输入通道数。

    • dim: 输出通道数。

    • n_div: 空间混合操作中使用的通道划分因子,默认值为4。

    • mlp_ratio: MLP(多层感知器)中通道的扩展比例。

    • drop_path: DropPath的概率,用于随机丢弃通道以增强模型的鲁棒性。

    • layer_scale_init_value: 用于层级缩放的初始化值。

    • pconv_fw_type: 部分卷积的前向传播类型(split_cat是默认值)。

  2. ConvolutionalGLU (Gated Linear Unit with Convolution):

    • self.mlp = ConvolutionalGLU(dim):这是一个使用GELU激活函数的卷积操作,通常用于引入非线性特性。

    • GELU在这里用作激活函数,可以帮助网络更有效地捕捉输入特征的细微变化。

  3. 空间混合 (Partial_conv3):

    • self.spatial_mixing = Partial_conv3(dim, n_div, pconv_fw_type):这部分处理输入特征的空间信息,通过部分卷积操作实现。

  4. 通道调整 (adjust_channel):

    • 如果输入通道数inc与输出通道数dim不匹配,会通过一个1x1卷积层调整通道数,以便匹配后续操作。

  5. 层级缩放 (layer_scale):

    • 如果layer_scale_init_value大于0,将初始化一个可训练的缩放参数self.layer_scale。这部分通过在前向传播时对特征进行缩放来增强模型的学习能力。

前向传播 (forward) 和带层级缩放的前向传播 (forward_layer_scale):

  • forward:

    • 如果通道数需要调整,首先会通过adjust_channel进行处理。

    • 然后通过spatial_mixing进行空间信息的混合。

    • 最后通过mlp(此处即使用了GELU激活函数的卷积层)处理,并加上shortcut连接(残差连接)后的结果返回。

  • forward_layer_scale:

    • 这一部分与forward类似,不同的是,mlp输出会先乘以layer_scale再进行残差连接。这样可以对特征进行更加精细的控制。

总结:

这段代码实现了一个基于卷积的模块Faster_Block_CGLU,其中卷积操作采用了GELU激活函数。GELU使得这个模块能够更灵活地处理输入特征,尤其是在处理具有复杂模式的数据时。

2.3 更改init.py文件

关键步骤二:修改modules文件夹下的__init__.py文件,先导入函数   

 然后在下面的__all__中声明函数 

2.4 添加yaml文件

关键步骤三:在/ultralytics/ultralytics/cfg/models/v8下面新建文件yolov8_Faster_Block_CGLU.yaml文件,粘贴下面的内容

  • OD【目标检测】
# Ultralytics YOLO 🚀, AGPL-3.0 license
# YOLOv8 object detection model with P3-P5 outputs. For Usage examples see https://docs.ultralytics.com/tasks/detect# Parameters
nc: 80  # number of classes
scales: # model compound scaling constants, i.e. 'model=yolov8n.yaml' will call yolov8.yaml with scale 'n'# [depth, width, max_channels]n: [0.33, 0.25, 1024]  # YOLOv8n summary: 225 layers,  3157200 parameters,  3157184 gradients,   8.9 GFLOPss: [0.33, 0.50, 1024]  # YOLOv8s summary: 225 layers, 11166560 parameters, 11166544 gradients,  28.8 GFLOPsm: [0.67, 0.75, 768]   # YOLOv8m summary: 295 layers, 25902640 parameters, 25902624 gradients,  79.3 GFLOPsl: [1.00, 1.00, 512]   # YOLOv8l summary: 365 layers, 43691520 parameters, 43691504 gradients, 165.7 GFLOPsx: [1.00, 1.25, 512]   # YOLOv8x summary: 365 layers, 68229648 parameters, 68229632 gradients, 258.5 GFLOPs# YOLOv8.0n backbone
backbone:# [from, repeats, module, args]- [-1, 1, Conv, [64, 3, 2]]  # 0-P1/2- [-1, 1, Conv, [128, 3, 2]]  # 1-P2/4- [-1, 3, C2f_Faster_CGLU, [128, True]]- [-1, 1, Conv, [256, 3, 2]]  # 3-P3/8- [-1, 6, C2f_Faster_CGLU, [256, True]]- [-1, 1, Conv, [512, 3, 2]]  # 5-P4/16- [-1, 6, C2f_Faster_CGLU, [512, True]]- [-1, 1, Conv, [1024, 3, 2]]  # 7-P5/32- [-1, 3, C2f_Faster_CGLU, [1024, True]]- [-1, 1, SPPF, [1024, 5]]  # 9# YOLOv8.0n head
head:- [-1, 1, nn.Upsample, [None, 2, 'nearest']]- [[-1, 6], 1, Concat, [1]]  # cat backbone P4- [-1, 3, C2f_Faster_CGLU, [512]]  # 12- [-1, 1, nn.Upsample, [None, 2, 'nearest']]- [[-1, 4], 1, Concat, [1]]  # cat backbone P3- [-1, 3, C2f_Faster_CGLU, [256]]  # 15 (P3/8-small)- [-1, 1, Conv, [256, 3, 2]]- [[-1, 12], 1, Concat, [1]]  # cat head P4- [-1, 3, C2f_Faster_CGLU, [512]]  # 18 (P4/16-medium)- [-1, 1, Conv, [512, 3, 2]]- [[-1, 9], 1, Concat, [1]]  # cat head P5- [-1, 3, C2f_Faster_CGLU, [1024]]  # 21 (P5/32-large)- [[15, 18, 21], 1, Detect, [nc]]  # Detect(P3, P4, P5)
  • Seg【语义分割】
# Ultralytics YOLO 🚀, AGPL-3.0 license
# YOLOv8 object detection model with P3-P5 outputs. For Usage examples see https://docs.ultralytics.com/tasks/detect# Parameters
nc: 80  # number of classes
scales: # model compound scaling constants, i.e. 'model=yolov8n.yaml' will call yolov8.yaml with scale 'n'# [depth, width, max_channels]n: [0.33, 0.25, 1024]  # YOLOv8n summary: 225 layers,  3157200 parameters,  3157184 gradients,   8.9 GFLOPss: [0.33, 0.50, 1024]  # YOLOv8s summary: 225 layers, 11166560 parameters, 11166544 gradients,  28.8 GFLOPsm: [0.67, 0.75, 768]   # YOLOv8m summary: 295 layers, 25902640 parameters, 25902624 gradients,  79.3 GFLOPsl: [1.00, 1.00, 512]   # YOLOv8l summary: 365 layers, 43691520 parameters, 43691504 gradients, 165.7 GFLOPsx: [1.00, 1.25, 512]   # YOLOv8x summary: 365 layers, 68229648 parameters, 68229632 gradients, 258.5 GFLOPs# YOLOv8.0n backbone
backbone:# [from, repeats, module, args]- [-1, 1, Conv, [64, 3, 2]]  # 0-P1/2- [-1, 1, Conv, [128, 3, 2]]  # 1-P2/4- [-1, 3, C2f_Faster_CGLU, [128, True]]- [-1, 1, Conv, [256, 3, 2]]  # 3-P3/8- [-1, 6, C2f_Faster_CGLU, [256, True]]- [-1, 1, Conv, [512, 3, 2]]  # 5-P4/16- [-1, 6, C2f_Faster_CGLU, [512, True]]- [-1, 1, Conv, [1024, 3, 2]]  # 7-P5/32- [-1, 3, C2f_Faster_CGLU, [1024, True]]- [-1, 1, SPPF, [1024, 5]]  # 9# YOLOv8.0n head
head:- [-1, 1, nn.Upsample, [None, 2, 'nearest']]- [[-1, 6], 1, Concat, [1]]  # cat backbone P4- [-1, 3, C2f_Faster_CGLU, [512]]  # 12- [-1, 1, nn.Upsample, [None, 2, 'nearest']]- [[-1, 4], 1, Concat, [1]]  # cat backbone P3- [-1, 3, C2f_Faster_CGLU, [256]]  # 15 (P3/8-small)- [-1, 1, Conv, [256, 3, 2]]- [[-1, 12], 1, Concat, [1]]  # cat head P4- [-1, 3, C2f_Faster_CGLU, [512]]  # 18 (P4/16-medium)- [-1, 1, Conv, [512, 3, 2]]- [[-1, 9], 1, Concat, [1]]  # cat head P5- [-1, 3, C2f_Faster_CGLU, [1024]]  # 21 (P5/32-large)- [[15, 18, 21], 1, Segment, [nc, 32, 256]] # Segment(P3, P4, P5)

温馨提示:因为本文只是对yolov8基础上添加模块,如果要对yolov8n/l/m/x进行添加则只需要指定对应的depth_multiple 和 width_multiple。不明白的同学可以看这篇文章: yolov8yaml文件解读——点击即可跳转  


2.5 注册模块

关键步骤四:在task.py的parse_model函数中注册

2.6 执行程序

在train.py中,将model的参数路径设置为yolov8_Faster_Block_CGLU.yaml的路径

建议大家写绝对路径,确保一定能找到

from ultralytics import YOLO
import warnings
warnings.filterwarnings('ignore')
from pathlib import Pathif __name__ == '__main__':# 加载模型model = YOLO("ultralytics/cfg/v8/yolov8.yaml")  # 你要选择的模型yaml文件地址# Use the modelresults = model.train(data=r"你的数据集的yaml文件地址",epochs=100, batch=16, imgsz=640, workers=4, name=Path(model.cfg).stem)  # 训练模型

 🚀运行程序,如果出现下面的内容则说明添加成功🚀 

                   from  n    params  module                                       arguments0                  -1  1       464  ultralytics.nn.modules.conv.Conv             [3, 16, 3, 2]1                  -1  1      4672  ultralytics.nn.modules.conv.Conv             [16, 32, 3, 2]2                  -1  1      3448  ultralytics.nn.modules.block.C2f_Faster_CGLU [32, 32, 1, True]3                  -1  1     18560  ultralytics.nn.modules.conv.Conv             [32, 64, 3, 2]4                  -1  2     18296  ultralytics.nn.modules.block.C2f_Faster_CGLU [64, 64, 2, True]5                  -1  1     73984  ultralytics.nn.modules.conv.Conv             [64, 128, 3, 2]6                  -1  2     71536  ultralytics.nn.modules.block.C2f_Faster_CGLU [128, 128, 2, True]7                  -1  1    295424  ultralytics.nn.modules.conv.Conv             [128, 256, 3, 2]8                  -1  1    207868  ultralytics.nn.modules.block.C2f_Faster_CGLU [256, 256, 1, True]9                  -1  1    164608  ultralytics.nn.modules.block.SPPF            [256, 256, 5]10                  -1  1         0  torch.nn.modules.upsampling.Upsample         [None, 2, 'nearest']11             [-1, 6]  1         0  ultralytics.nn.modules.conv.Concat           [1]12                  -1  1     85176  ultralytics.nn.modules.block.C2f_Faster_CGLU [384, 128, 1]13                  -1  1         0  torch.nn.modules.upsampling.Upsample         [None, 2, 'nearest']14             [-1, 4]  1         0  ultralytics.nn.modules.conv.Concat           [1]15                  -1  1     21564  ultralytics.nn.modules.block.C2f_Faster_CGLU [192, 64, 1]16                  -1  1     36992  ultralytics.nn.modules.conv.Conv             [64, 64, 3, 2]17            [-1, 12]  1         0  ultralytics.nn.modules.conv.Concat           [1]18                  -1  1     60600  ultralytics.nn.modules.block.C2f_Faster_CGLU [192, 128, 1]19                  -1  1    147712  ultralytics.nn.modules.conv.Conv             [128, 128, 3, 2]20             [-1, 9]  1         0  ultralytics.nn.modules.conv.Concat           [1]21                  -1  1    240636  ultralytics.nn.modules.block.C2f_Faster_CGLU [384, 256, 1]22        [15, 18, 21]  1    897664  ultralytics.nn.modules.head.Detect           [80, [64, 128, 256]]
YOLOv8_faster_CGLU summary: 265 layers, 2349204 parameters, 2349188 gradients, 6.8 GFLOPs

3. 完整代码分享

https://pan.baidu.com/s/1WKs66u904YmY2wZOlCdYDw?pwd=3kg6

 提取码: 3kg6 

4. GFLOPs

关于GFLOPs的计算方式可以查看百面算法工程师 | 卷积基础知识——Convolution

未改进的YOLOv8nGFLOPs

img

改进后的GFLOPs

5. 进阶

可以与其他的注意力机制或者损失函数等结合,进一步提升检测效果

6. 总结

Faster_Block_CGLU 是一个神经网络模块,结合了卷积、空间混合和层级缩放操作。它使用GELU激活函数来增强卷积层的非线性表达能力,能够灵活处理复杂输入特征。模块中的卷积操作由 `ConvolutionalGLU` 实现,并通过 `Partial_conv3` 进行空间信息的混合。当输入通道数与输出通道数不匹配时,使用 1x1 卷积进行调整。此外,通过残差连接和可选的层级缩放机制,模块能够在前向传播中更加精细地控制特征流,从而提高模型的学习能力。

这篇关于YOLOv8改进 | 融合改进 | C2f融合Faster-GELU模块提升检测速度【完整代码 + 主要代码解析】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1115506

相关文章

Spring Boot 3.4.3 基于 Spring WebFlux 实现 SSE 功能(代码示例)

《SpringBoot3.4.3基于SpringWebFlux实现SSE功能(代码示例)》SpringBoot3.4.3结合SpringWebFlux实现SSE功能,为实时数据推送提供... 目录1. SSE 简介1.1 什么是 SSE?1.2 SSE 的优点1.3 适用场景2. Spring WebFlu

java之Objects.nonNull用法代码解读

《java之Objects.nonNull用法代码解读》:本文主要介绍java之Objects.nonNull用法代码,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录Java之Objects.nonwww.chinasem.cnNull用法代码Objects.nonN

Java的IO模型、Netty原理解析

《Java的IO模型、Netty原理解析》Java的I/O是以流的方式进行数据输入输出的,Java的类库涉及很多领域的IO内容:标准的输入输出,文件的操作、网络上的数据传输流、字符串流、对象流等,这篇... 目录1.什么是IO2.同步与异步、阻塞与非阻塞3.三种IO模型BIO(blocking I/O)NI

SpringBoot实现MD5加盐算法的示例代码

《SpringBoot实现MD5加盐算法的示例代码》加盐算法是一种用于增强密码安全性的技术,本文主要介绍了SpringBoot实现MD5加盐算法的示例代码,文中通过示例代码介绍的非常详细,对大家的学习... 目录一、什么是加盐算法二、如何实现加盐算法2.1 加盐算法代码实现2.2 注册页面中进行密码加盐2.

python+opencv处理颜色之将目标颜色转换实例代码

《python+opencv处理颜色之将目标颜色转换实例代码》OpenCV是一个的跨平台计算机视觉库,可以运行在Linux、Windows和MacOS操作系统上,:本文主要介绍python+ope... 目录下面是代码+ 效果 + 解释转HSV: 关于颜色总是要转HSV的掩膜再标注总结 目标:将红色的部分滤

Python 中的异步与同步深度解析(实践记录)

《Python中的异步与同步深度解析(实践记录)》在Python编程世界里,异步和同步的概念是理解程序执行流程和性能优化的关键,这篇文章将带你深入了解它们的差异,以及阻塞和非阻塞的特性,同时通过实际... 目录python中的异步与同步:深度解析与实践异步与同步的定义异步同步阻塞与非阻塞的概念阻塞非阻塞同步

在C#中调用Python代码的两种实现方式

《在C#中调用Python代码的两种实现方式》:本文主要介绍在C#中调用Python代码的两种实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录C#调用python代码的方式1. 使用 Python.NET2. 使用外部进程调用 Python 脚本总结C#调

Java时间轮调度算法的代码实现

《Java时间轮调度算法的代码实现》时间轮是一种高效的定时调度算法,主要用于管理延时任务或周期性任务,它通过一个环形数组(时间轮)和指针来实现,将大量定时任务分摊到固定的时间槽中,极大地降低了时间复杂... 目录1、简述2、时间轮的原理3. 时间轮的实现步骤3.1 定义时间槽3.2 定义时间轮3.3 使用时

Python使用date模块进行日期处理的终极指南

《Python使用date模块进行日期处理的终极指南》在处理与时间相关的数据时,Python的date模块是开发者最趁手的工具之一,本文将用通俗的语言,结合真实案例,带您掌握date模块的六大核心功能... 目录引言一、date模块的核心功能1.1 日期表示1.2 日期计算1.3 日期比较二、六大常用方法详

Java中&和&&以及|和||的区别、应用场景和代码示例

《Java中&和&&以及|和||的区别、应用场景和代码示例》:本文主要介绍Java中的逻辑运算符&、&&、|和||的区别,包括它们在布尔和整数类型上的应用,文中通过代码介绍的非常详细,需要的朋友可... 目录前言1. & 和 &&代码示例2. | 和 ||代码示例3. 为什么要使用 & 和 | 而不是总是使