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中@Lazy注解的使用技巧与实例解析

《Spring中@Lazy注解的使用技巧与实例解析》@Lazy注解在Spring框架中用于延迟Bean的初始化,优化应用启动性能,它不仅适用于@Bean和@Component,还可以用于注入点,通过将... 目录一、@Lazy注解的作用(一)延迟Bean的初始化(二)与@Autowired结合使用二、实例解

Java中有什么工具可以进行代码反编译详解

《Java中有什么工具可以进行代码反编译详解》:本文主要介绍Java中有什么工具可以进行代码反编译的相关资,料,包括JD-GUI、CFR、Procyon、Fernflower、Javap、Byte... 目录1.JD-GUI2.CFR3.Procyon Decompiler4.Fernflower5.Jav

Python与DeepSeek的深度融合实战

《Python与DeepSeek的深度融合实战》Python作为最受欢迎的编程语言之一,以其简洁易读的语法、丰富的库和广泛的应用场景,成为了无数开发者的首选,而DeepSeek,作为人工智能领域的新星... 目录一、python与DeepSeek的结合优势二、模型训练1. 数据准备2. 模型架构与参数设置3

javaScript在表单提交时获取表单数据的示例代码

《javaScript在表单提交时获取表单数据的示例代码》本文介绍了五种在JavaScript中获取表单数据的方法:使用FormData对象、手动提取表单数据、使用querySelector获取单个字... 方法 1:使用 FormData 对象FormData 是一个方便的内置对象,用于获取表单中的键值

Vue ElementUI中Upload组件批量上传的实现代码

《VueElementUI中Upload组件批量上传的实现代码》ElementUI中Upload组件批量上传通过获取upload组件的DOM、文件、上传地址和数据,封装uploadFiles方法,使... ElementUI中Upload组件如何批量上传首先就是upload组件 <el-upl

Node.js net模块的使用示例

《Node.jsnet模块的使用示例》本文主要介绍了Node.jsnet模块的使用示例,net模块支持TCP通信,处理TCP连接和数据传输,具有一定的参考价值,感兴趣的可以了解一下... 目录简介引入 net 模块核心概念TCP (传输控制协议)Socket服务器TCP 服务器创建基本服务器服务器配置选项服

SpringBoot中整合RabbitMQ(测试+部署上线最新完整)的过程

《SpringBoot中整合RabbitMQ(测试+部署上线最新完整)的过程》本文详细介绍了如何在虚拟机和宝塔面板中安装RabbitMQ,并使用Java代码实现消息的发送和接收,通过异步通讯,可以优化... 目录一、RabbitMQ安装二、启动RabbitMQ三、javascript编写Java代码1、引入

C++使用栈实现括号匹配的代码详解

《C++使用栈实现括号匹配的代码详解》在编程中,括号匹配是一个常见问题,尤其是在处理数学表达式、编译器解析等任务时,栈是一种非常适合处理此类问题的数据结构,能够精确地管理括号的匹配问题,本文将通过C+... 目录引言问题描述代码讲解代码解析栈的状态表示测试总结引言在编程中,括号匹配是一个常见问题,尤其是在

Java调用DeepSeek API的最佳实践及详细代码示例

《Java调用DeepSeekAPI的最佳实践及详细代码示例》:本文主要介绍如何使用Java调用DeepSeekAPI,包括获取API密钥、添加HTTP客户端依赖、创建HTTP请求、处理响应、... 目录1. 获取API密钥2. 添加HTTP客户端依赖3. 创建HTTP请求4. 处理响应5. 错误处理6.

Python如何实现PDF隐私信息检测

《Python如何实现PDF隐私信息检测》随着越来越多的个人信息以电子形式存储和传输,确保这些信息的安全至关重要,本文将介绍如何使用Python检测PDF文件中的隐私信息,需要的可以参考下... 目录项目背景技术栈代码解析功能说明运行结php果在当今,数据隐私保护变得尤为重要。随着越来越多的个人信息以电子形