深度学习笔记(一):卷积变种(分组卷积、空洞卷积、深度可分离卷积、可形变卷积) 卷积中的不一样的操作

您所在的位置:网站首页 卷积计算的公式有哪些 深度学习笔记(一):卷积变种(分组卷积、空洞卷积、深度可分离卷积、可形变卷积) 卷积中的不一样的操作

深度学习笔记(一):卷积变种(分组卷积、空洞卷积、深度可分离卷积、可形变卷积) 卷积中的不一样的操作

2024-07-15 04:59| 来源: 网络整理| 查看: 265

文章目录 常规卷积(Convolution)分组卷积(Group Convolution)原理用途 空洞(扩张)卷积(Dilated/Atrous Convolution)深度可分离卷积(depthwise separable convolution)标准卷积与深度可分离卷积的不同深度可分离卷积的过程深度可分离卷积的优点 可变形卷积网络背景想法评价 卷积神经网络中十大拍案叫绝的操作一、卷积只能在同一组进行吗?-- Group convolution二、卷积核一定越大越好?-- 3×3卷积核三、每层卷积只能用一种尺寸的卷积核?-- Inception结构四、怎样才能减少卷积层参数量?-- Bottleneck五、越深的网络就越难训练吗?-- Resnet残差网络六、卷积操作时必须同时考虑通道和区域吗?-- DepthWise操作七、分组卷积能否对通道进行随机分组?-- ShuffleNet八、通道间的特征都是平等的吗? -- SEnet九、能否让固定大小的卷积核看到更大范围的区域?-- Dilated convolution十、卷积核形状一定是矩形吗?-- Deformable convolution 可变形卷积核**启发与思考**

常规卷积(Convolution)

如果输入feature map尺寸为 C ∗ H ∗ W C∗H∗W C∗H∗W,卷积核有 N N N个,输出feature map与卷积核的数量相同也是 N N N,每个卷积核的尺寸为 C ∗ K ∗ K C∗K∗K C∗K∗K, N N N个卷积核的总参数量为 N ∗ C ∗ K ∗ K N∗C∗K∗K N∗C∗K∗K,输入map与输出map的连接方式如下:

分组卷积(Group Convolution) 原理

最早见于AlexNet——2012年Imagenet的冠军方法,Group Convolution被用来切分网络,使其在2个GPU上并行运行,AlexNet网络结构如下:

AlexNet

Group Convolution顾名思义,则是对输入feature map进行分组,然后每组分别卷积。假设输入feature map的尺寸仍为 C ∗ H ∗ W C∗H∗W C∗H∗W,输出feature map的数量为 N N N个,如果设定要分成 G G G个groups,则每组的输入feature map数量为 C G \frac{C}{G} GC​,每组的输出feature map数量为 N G \frac{N}{G} GN​,每个卷积核的尺寸为 C G ∗ K ∗ K \frac{C}{G}*K*K GC​∗K∗K,卷积核的总数仍为 N N N个,每组的卷积核数量为 N G \frac{N}{G} GN​,卷积核只与其同组的输入map进行卷积,卷积核的总参数量为 N ∗ C G ∗ K ∗ K N*\frac{C}{G}*K*K N∗GC​∗K∗K,可见,总参数量减少为原来的 1 G \frac{1}{G} G1​,其连接方式如下图所示,group1输出map数为2,有2个卷积核,每个卷积核的channel数为4,与group1的输入map的channel数相同,卷积核只与同组的输入map卷积,而不与其他组的输入map卷积,group2与group3同理。

用途 减少参数量,分成 G G G组,则该层的参数量减少为原来的 1 G \frac{1}{G} G1​Group Convolution可以看成是structured sparse,每个卷积核的尺寸由 C ∗ K ∗ K C∗K∗K C∗K∗K变为 C G ∗ K ∗ K \frac{C}{G}*K*K GC​∗K∗K,可以将其余 ( C − C G ) ∗ K ∗ K (C-\frac{C}{G})*K*K (C−GC​)∗K∗K的参数视为0,有时甚至可以在减少参数量的同时获得更好的效果(相当于正则)。当分组数量等于输入map数量,输出map数量也等于输入map数量,即 G = N = C G=N=C G=N=C、 N N N个卷积核每个尺寸为 1 ∗ K ∗ K 1∗K∗K 1∗K∗K时,Group Convolution就成了Depthwise Convolution,参见MobileNet和Xception等,参数量进一步缩减,如下图所示 Depthwise Separable Convolution更进一步,如果分组数 G = N = C G=N=C G=N=C,同时卷积核的尺寸与输入map的尺寸相同,即 K = H = W K=H=W K=H=W,则输出map为 C ∗ 1 ∗ 1 C∗1∗1 C∗1∗1即长度为 C C C的向量,此时称之为Global Depthwise Convolution(GDC),见MobileFaceNet,可以看成是全局加权池化,与 Global Average Pooling(GAP) 的不同之处在于,GDC 给每个位置赋予了可学习的权重(对于已对齐的图像这很有效,比如人脸,中心位置和边界位置的权重自然应该不同),而GAP每个位置的权重相同,全局取个平均,如下图所示:

global average pooling

空洞(扩张)卷积(Dilated/Atrous Convolution)

空洞卷积(dilated convolution)是针对图像语义分割问题中下采样会降低图像分辨率、丢失信息而提出的一种卷积思路。利用添加空洞扩大感受野,让原本3 x3的卷积核,在相同参数量和计算量下拥有5x5(dilated rate =2)或者更大的感受野,从而无需下采样。扩张卷积(dilated convolutions)又名空洞卷积(atrous convolutions),向卷积层引入了一个称为 “扩张率(dilation rate)”的新参数,该参数定义了卷积核处理数据时各值的间距。换句话说,相比原来的标准卷积,扩张卷积(dilated convolution) 多了一个hyper-parameter(超参数)称之为dilation rate(扩张率),指的是kernel各点之前的间隔数量,(正常的convolution 的 dilatation rate为 1)。 (a)图对应3x3的1-dilated conv,和普通的卷积操作一样。 (b)图对应3x3的2-dilated conv,实际的卷积kernel size还是3x3,但是空洞为1,需要注意的是空洞的位置全填进去0,填入0之后再卷积即可。即为下图。 ©图是4-dilated conv操作。 在上图中扩张卷积的感受野可以由以下公式计算得到 F i + 1 = ( 2 i + 2 − 1 ) x ( 2 i + 2 − 1 ) F_{i+1}=(2^{i+2}-1)x(2^{i+2}-1) Fi+1​=(2i+2−1)x(2i+2−1);其中i+1表示dilated rate。 比如上图中(a),dilated=1,F(dilated) = 3×3;图(b)中,dilated=2,F(dilated)=7×7;图(c)中,dilated=4, F(dilated)=15×15。 dilated=2时具体的操作,即按照下图在空洞位置填入0之后,然后直接卷积就可以了。 上图是一个扩张率为2的3×3卷积核,感受野与5×5的卷积核相同,而且仅需要9个参数。你可以把它想象成一个5×5的卷积核,每隔一行或一列删除一行或一列。 在相同的计算条件下,空洞卷积提供了更大的感受野。空洞卷积经常用在实时图像分割中。当网络层需要较大的感受野,但计算资源有限而无法提高卷积核数量或大小时,可以考虑空洞卷积。

深度可分离卷积(depthwise separable convolution)

在可分离卷积(separable convolution)中,通常将卷积操作拆分成多个步骤。而在神经网络中通常使用的就是深度可分离卷积(depthwise separable convolution)。 举个例子,假设有一个3×3大小的卷积层,其输入通道为16、输出通道为32。 那么一般的操作就是用32个3×3的卷积核来分别同输入数据卷积,这样每个卷积核需要3×3×16个参数,得到的输出是只有一个通道的数据。之所以会得到一通道的数据,是因为刚开始3×3×16的卷积核的每个通道会在输入数据的每个对应通道上做卷积,然后叠加每一个通道对应位置的值,使之变成了单通道,那么32个卷积核一共需要(3×3×16)×32 =4068个参数。

标准卷积与深度可分离卷积的不同

用一张来解释深度可分离卷积,如下:

可以看到每一个通道用一个filter卷积之后得到对应一个通道的输出,然后再进行信息的融合。而以往标准的卷积过程可以用下面的图来表示:

深度可分离卷积的过程

而应用深度可分离卷积的过程是 ①用16个3×3大小的卷积核(1通道)分别与输入的16通道的数据做卷积(这里使用了16个1通道的卷积核,输入数据的每个通道用1个3×3的卷积核卷积),得到了16个通道的特征图,我们说该步操作是depthwise(逐层)的,在叠加16个特征图之前, ②接着用32个1×1大小的卷积核(16通道)在这16个特征图进行卷积运算,将16个通道的信息进行融合(用1×1的卷积进行不同通道间的信息融合),我们说该步操作是pointwise(逐像素)的。这样我们可以算出整个过程使用了3×3×16+(1×1×16)×32 =656个参数。

深度可分离卷积的优点

可以看出运用深度可分离卷积比普通卷积减少了所需要的参数。重要的是深度可分离卷积将以往普通卷积操作同时考虑通道和区域改变成,卷积先只考虑区域,然后再考虑通道。实现了通道和区域的分离。

可变形卷积网络 背景

由于同样的物体在图像中可能呈现出不同的大小、姿态、视角变化甚至非刚体形变,因此如何适应这些复杂的几何形变是物体识别的主要难点。 微软亚洲研究院视觉计算组的研究员在arXiv上公布了一篇题为“Deformable Convolutional Networks”(可变形卷积网络)的论文,首次在卷积神经网络(convolutional neutral networks,CNN)中引入了学习空间几何形变的能力,得到可变形卷积网络(deformable convolutional networks),从而更好地解决了具有空间形变的图像识别任务。

研究员们通过大量的实验结果验证了该方法在复杂的计算机视觉任务(如目标检测和语义分割)上的有效性,首次表明在深度卷积神经网络(deep CNN)中学习空间上密集的几何形变是可行的。该论文的源代码也于近期在GitHub上公布。

现有的网络模型对于物体几何形变的适应能力几乎完全来自于数据本身所具有的多样性,其模型内部并不具有适应几何形变的机制。究其根本,是因为卷积操作本身具有固定的几何结构,而由其层叠搭建而成的卷积网络的几何结构也是固定的,所以不具有对于几何形变建模的能力。

举个例子,想要识别出同一图像中不同大小的物体(比如远近不同的两个人),理想的结果是,在对应于每个物体的位置网络需要具有相应大小的感受野(receptive field)。直观的说,为了识别更大的物体网络需要看到更大的图像区域。然而,在现有的卷积网络架构中,图像中任何位置的感受野大小都是相同的,其取决于事先设定的网络参数(卷积核的大小、步长和网络深度等),无法根据图像内容自适应调整,从而限制了识别精度。

想法

微软亚洲研究院的研究员们发现,标准卷积中的规则格点采样是导致网络难以适应几何形变的“罪魁祸首”。为了削弱这个限制,研究员们对卷积核中每个采样点的位置都增加了一个偏移的变量。通过这些变量,卷积核就可以在当前位置附近随意的采样,而不再局限于之前的规则格点。这样扩展后的卷积操作被称为可变形卷积(deformable convolution)。标准卷积和可变形卷积在图1中有简要的展示。

上图显示可变形卷积可以提高模型对 scale, aspect ratio and rotation 等映射的泛化能力。

卷积该具体怎么deformable,这个可以通过一个卷积层来学习,如下图所示:

从公式层面来说:一般的卷积可以定义如下式:

对于可变形卷积定义如下:

这个 offset Δ p n \Delta p_n Δpn​通过卷积网络学习得到

事实上,可变形卷积单元中增加的偏移量是网络结构的一部分,通过另外一个平行的标准卷积单元计算得到,进而也可以通过梯度反向传播进行端到端的学习。加上该偏移量的学习之后,可变形卷积核的大小和位置可以根据当前需要识别的图像内容进行动态调整,其直观效果就是不同位置的卷积核采样点位置会根据图像内容发生自适应的变化,从而适应不同物体的形状、大小等几何形变,如图2、图3中所展示。

评价

可变形卷积单元具有诸多良好的性质。它不需要任何额外的监督信号,可以直接通过目标任务学习得到。它可以方便地取代任何已有视觉识别任务的卷积神经网络中的若干个标准卷积单元,并通过标准的反向传播进行端到端的训练。由此得到的网络则称为“可变形卷积网络”。

可变形卷积网络是对于传统卷积网络简明而又意义深远的结构革新,具有重要的学术和实践意义。它适用于所有待识别目标具有一定几何形变的任务(几乎所有重要的视觉识别任务都有此特点,人脸、行人、车辆、文字、动物等),可以直接由已有网络结构扩充而来,无需重新预训练。它仅增加了很少的模型复杂度和计算量,且显著提高了识别精度。例如,在用于自动驾驶的图像语义分割数据集(CityScapes)上,可变形卷积神经网络将准确率由70%提高到了75%。

此外,通过增加偏移量来学习几何形变的思想还可方便地扩展到其它计算单元中去。例如,目前业界最好的物体检测方法都使用了基于规则块采样的兴趣区域(region of interests, ROI)池化(pooling)。在该操作中,对于每个采样的规则块增加类似的偏移量,从而得到可变形兴趣区域池化 (deformable ROI pooling)。由此所获得的新的物体检测方法也取得了显著的性能提升。

卷积神经网络中十大拍案叫绝的操作 一、卷积只能在同一组进行吗?-- Group convolution

Group convolution 分组卷积,最早在AlexNet中出现,由于当时的硬件资源有限,训练AlexNet时卷积操作不能全部放在同一个GPU处理,因此作者把feature maps分给多个GPU分别进行处理,最后把多个GPU的结果进行融合。

img

alexnet结构

分组卷积的思想影响比较深远,当前一些轻量级的SOTA(State Of The Art)网络,都用到了分组卷积的操作,以节省计算量。但题主有个疑问是,如果分组卷积是分在不同GPU上的话,每个GPU的计算量就降低到 1/groups,但如果依然在同一个GPU上计算,最终整体的计算量是否不变?找了pytorch上有关组卷积操作的介绍,望读者解答我的疑问。

img

pytroch github

EDIT:

关于这个问题,知乎用户朋友

蔡冠羽

提出了他的见解:

我感觉group conv本身应该就大大减少了参数,比如当input channel为256,output channel也为256,kernel size为33,不做group conv参数为25633256,若group为8,每个group的input channel和output channel均为32,参数为8323332,是原来的八分之一。这是我的理解。

我的理解是分组卷积最后每一组输出的feature maps应该是以concatenate的方式组合,而不是element-wise add,所以每组输出的channel是 input channels / #groups,这样参数量就大大减少了。

二、卷积核一定越大越好?-- 3×3卷积核

AlexNet中用到了一些非常大的卷积核,比如11×11、5×5卷积核,之前人们的观念是,卷积核越大,receptive field(感受野)越大,看到的图片信息越多,因此获得的特征越好。虽说如此,但是大的卷积核会导致计算量的暴增,不利于模型深度的增加,计算性能也会降低。于是在VGG(最早使用)、Inception网络中,利用2个3×3卷积核的组合比1个5×5卷积核的效果更佳,同时参数量(3×3×2+1 VS 5×5×1+1)被降低,因此后来3×3卷积核被广泛应用在各种模型中。

img

三、每层卷积只能用一种尺寸的卷积核?-- Inception结构

传统的层叠式网络,基本上都是一个个卷积层的堆叠,每层只用一个尺寸的卷积核,例如VGG结构中使用了大量的3×3卷积层。事实上,同一层feature map可以分别使用多个不同尺寸的卷积核,以获得不同尺度的特征,再把这些特征结合起来,得到的特征往往比使用单一卷积核的要好,谷歌的GoogleNet,或者说Inception系列的网络,就使用了多个卷积核的结构:

img

最初版本的Inception结构

如上图所示,一个输入的feature map分别同时经过1×1、3×3、5×5的卷积核的处理,得出的特征再组合起来,获得更佳的特征。但这个结构会存在一个严重的问题:参数量比单个卷积核要多很多,如此庞大的计算量会使得模型效率低下。这就引出了一个新的结构:

四、怎样才能减少卷积层参数量?-- Bottleneck

发明GoogleNet的团队发现,如果仅仅引入多个尺寸的卷积核,会带来大量的额外的参数,受到Network In Network中1×1卷积核的启发,为了解决这个问题,他们往Inception结构中加入了一些1×1的卷积核,如图所示:

img

加入1×1卷积核的Inception结构

img

根据上图,我们来做个对比计算,假设输入feature map的维度为256维,要求输出维度也是256维。有以下两种操作:

256维的输入直接经过一个3×3×256的卷积层,输出一个256维的feature map,那么参数量为:256×3×3×256 = 589,824256维的输入先经过一个1×1×64的卷积层,再经过一个3×3×64的卷积层,最后经过一个1×1×256的卷积层,输出256维,参数量为:256×1×1×64 + 64×3×3×64 + 64×1×1×256 = 69,632。足足把第一种操作的参数量降低到九分之一!

1×1卷积核也被认为是影响深远的操作,往后大型的网络为了降低参数量都会应用上1×1卷积核。

五、越深的网络就越难训练吗?-- Resnet残差网络

img

ResNet skip connection

传统的卷积层层叠网络会遇到一个问题,当层数加深时,网络的表现越来越差,很大程度上的原因是因为当层数加深时,梯度消散得越来越严重,以至于反向传播很难训练到浅层的网络。为了解决这个问题,何凯明大神想出了一个“残差网络”,使得梯度更容易地流动到浅层的网络当中去,而且这种“skip connection”能带来更多的好处,这里可以参考一个PPT:极深网络(ResNet/DenseNet): Skip Connection为何有效及其它 ,以及我的一篇文章:为什么ResNet和DenseNet可以这么深?一文详解残差块为何能解决梯度弥散问题。 ,大家可以结合下面的评论进行思考。

六、卷积操作时必须同时考虑通道和区域吗?-- DepthWise操作

img

标准的卷积过程可以看上图,一个2×2的卷积核在卷积时,对应图像区域中的所有通道均被同时考虑,问题在于,为什么一定要同时考虑图像区域和通道?我们为什么不能把通道和空间区域分开考虑?

img

Xception网络就是基于以上的问题发明而来。我们首先对每一个通道进行各自的卷积操作,有多少个通道就有多少个过滤器。得到新的通道feature maps之后,这时再对这批新的通道feature maps进行标准的1×1跨通道卷积操作。这种操作被称为 “DepthWise convolution” ,缩写“DW”。

这种操作是相当有效的,在imagenet 1000类分类任务中已经超过了InceptionV3的表现,而且也同时减少了大量的参数,我们来算一算,假设输入通道数为3,要求输出通道数为256,两种做法:

1.直接接一个3×3×256的卷积核,参数量为:3×3×3×256 = 6,912

2.DW操作,分两步完成,参数量为:3×3×3 + 3×1×1×256 = 795,又把参数量降低到九分之一!

因此,一个depthwise操作比标准的卷积操作降低不少的参数量,同时论文中指出这个模型得到了更好的分类效果。

EDIT:2017.08.25

本文在发出12小时后,一位知乎用户私信了我,向我介绍了Depthwise和Pointwise的历史工作,而Xception和Mobilenet也引用了他们16年的工作,就是Min Wang et al 的Factorized Convolutional Neural Networks,这篇论文的Depthwise中,每一通道输出的feature map(称为“基层”)可以不止一个,而Xception中的Depthwise separable Convolution, 正是这篇工作中“单一基层”的情况。推荐有兴趣的读者关注下他们的工作,这里有篇介绍博文:【深度学习】卷积层提速Factorized Convolutional Neural Networks。而最早关于separable convolution的介绍,Xception作者提到,应该追溯到Lau- rent Sifre 2014年的工作 Rigid-Motion Scattering For Image Classification 6.2章节。

七、分组卷积能否对通道进行随机分组?-- ShuffleNet

在AlexNet的Group Convolution当中,特征的通道被平均分到不同组里面,最后再通过两个全连接层来融合特征,这样一来,就只能在最后时刻才融合不同组之间的特征,对模型的泛化性是相当不利的。为了解决这个问题,ShuffleNet在每一次层叠这种Group conv层前,都进行一次channel shuffle,shuffle过的通道被分配到不同组当中。进行完一次group conv之后,再一次channel shuffle,然后分到下一层组卷积当中,以此循环。

img

来自ShuffleNet论文

经过channel shuffle之后,Group conv输出的特征能考虑到更多通道,输出的特征自然代表性就更高。另外,AlexNet的分组卷积,实际上是标准卷积操作,而在ShuffleNet里面的分组卷积操作是depthwise卷积,因此结合了通道洗牌和分组depthwise卷积的ShuffleNet,能得到超少量的参数以及超越mobilenet、媲美AlexNet的准确率!

另外值得一提的是,微软亚洲研究院MSRA最近也有类似的工作,他们提出了一个IGC单元(Interleaved Group Convolution),即通用卷积神经网络交错组卷积,形式上类似进行了两次组卷积,Xception 模块可以看作交错组卷积的一个特例,特别推荐看看这篇文章:王井东详解ICCV 2017入选论文:通用卷积神经网络交错组卷积

要注意的是,Group conv是一种channel分组的方式,Depthwise +Pointwise是卷积的方式,只是ShuffleNet里面把两者应用起来了。因此Group conv和Depthwise +Pointwise并不能划等号。

八、通道间的特征都是平等的吗? – SEnet

无论是在Inception、DenseNet或者ShuffleNet里面,我们对所有通道产生的特征都是不分权重直接结合的,那为什么要认为所有通道的特征对模型的作用就是相等的呢? 这是一个好问题,于是,ImageNet2017 冠军SEnet就出来了。

img

SEnet 结构

一组特征在上一层被输出,这时候分两条路线,第一条直接通过,第二条首先进行Squeeze操作(Global Average Pooling),把每个通道2维的特征压缩成一个1维,从而得到一个特征通道向量(每个数字代表对应通道的特征)。然后进行Excitation操作,把这一列特征通道向量输入两个全连接层和sigmoid,建模出特征通道间的相关性,得到的输出其实就是每个通道对应的权重,把这些权重通过Scale乘法通道加权到原来的特征上(第一条路),这样就完成了特征通道的权重分配。作者详细解释可以看这篇文章:专栏 | Momenta详解ImageNet 2017夺冠架构SENet

九、能否让固定大小的卷积核看到更大范围的区域?-- Dilated convolution

标准的3×3卷积核只能看到对应区域3×3的大小,但是为了能让卷积核看到更大的范围,dilated conv使其成为了可能。dilated conv原论文中的结构如图所示:

img

上图b可以理解为卷积核大小依然是3×3,但是每个卷积点之间有1个空洞,也就是在绿色7×7区域里面,只有9个红色点位置作了卷积处理,其余点权重为0。这样即使卷积核大小不变,但它看到的区域变得更大了。详细解释可以看这个回答:如何理解空洞卷积(dilated convolution)?

十、卷积核形状一定是矩形吗?-- Deformable convolution 可变形卷积核

img

传统的卷积核一般都是长方形或正方形,但MSRA提出了一个相当反直觉的见解,认为卷积核的形状可以是变化的,变形的卷积核能让它只看感兴趣的图像区域 ,这样识别出来的特征更佳。

img

图来自微软亚洲研究院公众号要做到这个操作,可以直接在原来的过滤器前面再加一层过滤器,这层过滤器学习的是下一层卷积核的位置偏移量(offset),这样只是增加了一层过滤器,或者直接把原网络中的某一层过滤器当成学习offset的过滤器,这样实际增加的计算量是相当少的,但能实现可变形卷积核,识别特征的效果更好。详细MSRA的解读可以看这个链接:可变形卷积网络:计算机新“视”界。

启发与思考

现在越来越多的CNN模型从巨型网络到轻量化网络一步步演变,模型准确率也越来越高。现在工业界追求的重点已经不是准确率的提升(因为都已经很高了),都聚焦于速度与准确率的trade off,都希望模型又快又准。因此从原来AlexNet、VGGnet,到体积小一点的Inception、Resnet系列,到目前能移植到移动端的mobilenet、ShuffleNet(体积能降低到0.5mb!),我们可以看到这样一些趋势:

卷积核方面:

大卷积核用多个小卷积核代替;单一尺寸卷积核用多尺寸卷积核代替;固定形状卷积核趋于使用可变形卷积核;使用1×1卷积核(bottleneck结构)。

卷积层通道方面:

标准卷积用depthwise卷积代替;使用分组卷积;分组卷积前使用channel shuffle;通道加权计算。

卷积层连接方面:

使用skip connection,让模型更深;densely connection,使每一层都融合上其它层的特征输出(DenseNet)

启发

类比到通道加权操作,卷积层跨层连接能否也进行加权处理?bottleneck + Group conv + channel shuffle + depthwise的结合会不会成为以后降低参数量的标准配置?



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3