IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 人工智能 -> 机器学习(16)——卷积神经网络(一) -> 正文阅读

[人工智能]机器学习(16)——卷积神经网络(一)

1 简介

??卷积网络(convolutional network)(LeCun, 1989),也叫做 卷积神经网络(convolutional neural network, CNN),是一种专门用来处理具有类似网格结构的数据的神经网络。例如时间序列数据(可以认为是在时间轴上有规律地采样形成的一维网格)和图像数据(可以看作是二维的像素网格)。卷积网络在诸多应用领域都表现优异。“卷积神经网络’’ 一词表明该网络使用了 卷积(convolution)这种数学运算。卷积是一种特殊的线性运算。卷积网络是指那些至少在网络的一层中使用卷积运算来替代一般的矩阵乘法运算的神经网络。
??卷积网络为什么会出现?得先看看更早时期提出的 全连接网络(Fully Connected Neural Network,FC)在处理类似图片数据时会出现的问题:

  • 参数过多;
  • 破坏图像的空间分布和像素之间的距离关系;

针对上述问题,图像的主要特点:

  • 图像的关键特征可能只是图像的一小部分;
  • 相同的特征可能出现在不同位置;
  • 对一张图像进行抽样,不改变预测目标。

CNN 正是针对图像的特点来解决 FC 的缺点的。卷积神经网络通常由一个或多个卷积层和顶端的全连通层(对应经典的神经网络)组成,同时也包括 关联权重池化层(Pooling Layer)等。下图就是一个卷积神经网络架构。

在这里插入图片描述
与其他深度学习结构相比,卷积神经网络在图像和语音识别方面能够给出更好的结果。这一模型也可以使用反向传播算法进行训练。相比其他深度、前馈神经网络,卷积神经网络可以用更少的参数,却获得更高的性能。卷积神经网络的一般结构包括卷积神经网络的常用层, 如卷积层、池化层、全连接层和输出层;有些还包括其他层,如正则化层、 高级层等。

2 卷积层

??针对FC神经网络处理图片数据的两个缺点,CNN提出的解决方案是 权值共享卷积操作。首先要先理解一个概念:感受野,感受野表示当前特征图的 每个像素 表示 原始图像 的哪部分,看图说话:

在这里插入图片描述
输入图像 X \boldsymbol{X} X,维度为 5 × 5 \boldsymbol{5×5} 5×5Layer2 的输出特征维度是 3 × 3 \boldsymbol{3×3} 3×3,则其中的任一像素表征着 X \boldsymbol{X} X 的 9 个像素即 Layer1 中的绿色部分,则 Layer2 的感受野为 3,Layer3 的输出特征维度是 1 × 1 \boldsymbol{1×1} 1×1,只有一个像素,表征着 Layer2 整张特征图,对应到 X \boldsymbol{X} X 也是表征 X \boldsymbol{X} X 的整幅特征图,因此 Layer3 的感受野是 5。总结成一个规律就是,特征图越小,其感受野越大。

2.1 权值共享

??由我们上面介绍的感受野的概念,网络层的每个输出节点(输出像素)仅与感受野区域内 k × k \boldsymbol{k × k} k×k 个输入节点相连接,假如输出节点数为 J \boldsymbol{J} J,则当前层的参数量为 k × k × J \boldsymbol{k × k×J} k×k×J,相对于全连接层的 I × J \boldsymbol{I×J} I×J k \boldsymbol{k} k 一般取值较小,如 1、 3、5 等, k × k \boldsymbol{k×k} k×k 远小于 I \boldsymbol{I} I,因此成功地将参数量减少了很多。注: 上述假设以及在后面的示例中只有一层卷积层,这是为了用感受野容易表示卷积图像位置,如果是多层卷积,则不能随便使用感受野这个名词。
??通过权值共享的思想,对于每个输出节点 o j \boldsymbol{o_j} oj?,均使用相同的权值矩阵 W \boldsymbol{W} W,那么无论输出节点的数量 J \boldsymbol{J} J 是多少,网络层的参数量总是 k × k \boldsymbol{k × k} k×k。如下图所示,在计算左上角位置的输出像素时,使用权值矩阵 W \boldsymbol{W} W
[ w 00 w 01 w 02 w 10 w 11 w 12 w 020 w 21 w 22 ] \begin{bmatrix} w_{00} & w_{01} & w_{02} \\ w_{10} & w_{11} & w_{12}\\ w_{020} & w_{21} & w_{22} \end{bmatrix} ???w00?w10?w020??w01?w11?w21??w02?w12?w22?????
与对应感受野内部的像素相乘累加,作为左上角像素的输出值;在计算右下方感受野区域时,共享权值参数 W \boldsymbol{W} W,即使用相同的权值参数 W \boldsymbol{W} W相乘累加,得到右下角像素的输出值,此时网络层的参数量只有 3 × 3 = 9 \boldsymbol{3 × 3 = 9} 3×3=9 个,且与输入、输出节点数无关。

在这里插入图片描述
通过运用局部相关性和权值共享的思想,我们成功把全连接网络的参数量从 I × J \boldsymbol{I×J} I×J 减少到 𝑘 × 𝑘 \boldsymbol{𝑘 × 𝑘} k×k (准确地说,是在单输入通道、单卷积核的条件下)。这种共享权值的“局部连接层”网络其实就是卷积神经网络。

2.2 卷积操作

??卷积层是卷积神经网络的核心层,而卷积(Convolution)又是卷积层的核心。对卷积直观的理解,就是两个函数的一种运算,这种运算就称为卷积运算。下图就是一个简单的二维空间卷积运算示例,虽然简单,但却包含了卷积的核心内容。

在这里插入图片描述
上图中,输入和卷积核都是张量,卷积运算就是用卷积分别乘以输入张量中的每个元素,然后输出一个代表每个输入信息的张量。其中卷积核 (kernel)又称权重过滤器,简称为过滤器(filter)。我们可以将输入、卷积 核推广到更高维空间上,输入由 2 × 2 \boldsymbol{2×2} 2×2 矩阵,拓展为 5 × 5 \boldsymbol{5×5} 5×5 矩阵,卷积核由一个标量拓展为一个 3 × 3 \boldsymbol{3×3} 3×3 矩阵,卷积结果如下:

在这里插入图片描述
用卷积核中每个元素,乘以对应输入矩阵中的对应元素,这点还是一 样,但输入张量为 5 × 5 \boldsymbol{5×5} 5×5 矩阵,而卷积核为 3 × 3 \boldsymbol{3×3} 3×3 矩阵,所以这里首先就要解决 一个如何对应的问题,这个问题解决了,这个推广也就完成了。把卷积核作为在输入矩阵上的一个移动窗口,对应关系就迎刃而解了。了解上述的卷积方式之后,下面开始介绍的卷积是单通道输入、单卷积核的情况,然后推广至多通道输入、单卷积核,最后讨论最常用,也是最复杂的多通道输入、多个卷积核的卷积层实现。动图如下:
在这里插入图片描述
从数学上来讲,深度学习里面所谓的卷积运算,其实它被称为 互相关(cross-correlation)运算:将图像矩阵中,从左到右,由上到下,取与滤波器同等大小的一部分,每一部分中的值与滤波器中的值对应相乘后求和,最后的结果组成一个矩阵,其中没有对核进行翻转。

2.3 单通道输入和单卷积核

??首先讨论单通道输入 C i n = 1 \boldsymbol{C_{in} = 1} Cin?=1,如灰度图片只有灰度值一个通道,单个卷积核 C o u t = 1 \boldsymbol{C_{out} = 1} Cout?=1 的情况(卷积核的个数决定卷积层的输出通道数)。以输入 X \boldsymbol{X} X 5 × 5 \boldsymbol{5×5} 5×5 的矩阵,卷积核为 3 × 3 \boldsymbol{3×3} 3×3 的矩阵为例,如下图:

在这里插入图片描述
计算过程如下:与卷积核同大小的感受野(输入 X \boldsymbol{X} X 上方的绿色方框)首先移动至输入 X \boldsymbol{X} X 最左上方,选中输入 X \boldsymbol{X} X 3 × 3 \boldsymbol{3×3} 3×3 的感受野元素,与卷积核(图片中间 3 × 3 \boldsymbol{3×3} 3×3 方框)对应元素相乘:
[ 1 ? 1 0 ? 1 ? 2 2 1 2 ? 2 ] ? [ ? 1 1 2 1 ? 1 3 0 ? 1 ? 2 ] = [ ? 1 ? 1 0 ? 1 2 6 0 ? 2 4 ] \begin{bmatrix} 1 & -1 & 0\\ -1 & -2 & 2\\ 1 & 2 & -2 \\ \end{bmatrix}? \begin{bmatrix} -1 & 1 & 2\\ 1 & -1 & 3\\ 0 & -1 & -2 \\ \end{bmatrix}= \begin{bmatrix} -1 & -1 & 0\\ -1 & 2 & 6\\ 0 & -2 & 4 \\ \end{bmatrix} ???1?11??1?22?02?2?????????110?1?1?1?23?2????=????1?10??12?2?064????
? 符号表示哈达马积(Hadamard Product),即矩阵的对应元素相乘。运算后得到 3 × 3 \boldsymbol{3×3} 3×3 的矩阵,这 9 个数值全部相加:
? 1 ? 1 + 0 ? 1 + 2 + 6 + 0 ? 2 + 4 = 7 ? 1?1 + 0?1 + 2 +6 + 0? 2 + 4=7 ?1?1+0?1+2+6+0?2+4=7
得到标量 7,写入输出矩阵第一行、第一列的位置。完成第一个感受野区域的特征提取后,感受野窗口向右移动一个步长单位(Strides,记 为𝑠,默认为 1),选中下图中绿色方框中的 9 个感受野元素,按照同样的计算方法,与卷积核对应元素相乘累加,得到输出 10,写入第一行、第二列位置。

在这里插入图片描述
感受野窗口再次向右移动一个步长单位,选中下图中绿色方框中的元素,并与卷积核相乘累加,得到输出 3,并写入输出的第一行、第三列位置。

在这里插入图片描述
此时感受野已经移动至输入 X \boldsymbol{X} X 的有效像素的最右边,无法向右边继续移动(在不填充无效元素的情况下),因此感受野窗口向下移动一个步长单位(𝑠 = 1),并回到当前行的行首位置,继续选中新的感受野元素区域,与卷积核运算得到输出-1。此时的感受野由于经过向下移动一个步长单位,因此输出值 -1 写入第二行、第一列位置。

在这里插入图片描述
以此类推得到最终的结果:

在这里插入图片描述
最终输出我们得到一个 3 × 3 \boldsymbol{3×3} 3×3 的矩阵,比输入 5 × 5 \boldsymbol{5×5} 5×5 略小,这是因为感受野不能超出元素边界的缘故,由此我们也能知道,在没有扩展输入图像的情况下卷积,输出图像的维度一定会变小,我们将这种卷积方式称作 Vaild卷积。可以观察到,卷积运算的输出矩阵大小由卷积核的大小 k \boldsymbol{k} k ,输入 X \boldsymbol{X} X 的高宽,移动步长 s \boldsymbol{s} s,是否填充等因素共同决定。

2.4 多通道输入和单卷积核

??多通道输入的卷积层更为常见,比如彩色的图片包含了 R/G/B 三个通道,每个通道上
面的像素值表示 R/G/B 色彩的强度。下面我们以 3 通道输入、单个卷积核为例,将单通道输入的卷积运算方法推广到多通道的情况。在多通道输入的情况下,卷积核的通道数需要和输入 X \boldsymbol{X} X 的通道数量相匹配,卷积核的第𝑖个通道和 X \boldsymbol{X} X 的第 i \boldsymbol{i} i 个通道运算,得到第 i \boldsymbol{i} i 个中间矩阵,此时可以视为单通道输入与单卷积核的情况,所有通道的中间矩阵对应元素再次相加,作为最终输出。

在这里插入图片描述
上图中:每行的最左边 5 × 5 \boldsymbol{5×5} 5×5 的矩阵表示输入 X \boldsymbol{X} X1~3 通道,第 2 列的 3 × 3 \boldsymbol{3×3} 3×3 矩阵分别表示卷积核的 1~3 通道,第 3 列的矩阵表示当前通道上运算结果的中间矩阵,最右边一个矩阵表示卷积层运算的最终输出。在初始状态,每个通道上面的感受野窗口同步落在对应通道上面的最左边、最上方位置,每个通道上感受野区域元素与卷积核对应通道上面的矩阵相乘累加,分别得到三个通道上面的输出 7、-11、-1 的中间变量,这些中间
变量相加得到输出-5,写入对应位置。
??随后,感受野窗口同步在 X \boldsymbol{X} X 的每个通道上向右移动 s = 1 \boldsymbol{s = 1} s=1 个步长单位,此时感受野区域元素如下图所示,每个通道上面的感受野与卷积核对应通道上面的矩阵相乘累加,得到中间变量 10、20、20,全部相加得到输出 50,写入第一行、第二列元素位置。

在这里插入图片描述
以此方式同步移动感受野窗口,直至最右边、最下方位置,此时全部完成输入和卷积核的卷积运算,得到 3 × 3 \boldsymbol{3×3} 3×3 的输出矩阵。

在这里插入图片描述
输入的每个通道处的感受野均与卷积核的对应通道相乘累加,得到与通道数量相等的中间变量,这些中间变量全部相加即得到当前位置的输出值。输入通道的通道数量决定了卷积核的通道数。一个卷积核只能得到一个输出矩阵,无论输入 X \boldsymbol{X} X 的通道数量。

在这里插入图片描述
一般来说,一个卷积核只能完成某种逻辑的特征提取,当需要同时提取多种逻辑特征时,可以通过增加多个卷积核来得到多种特征,提高神经网络的表达能力,这就是多通道输入、多卷积核的情况。

2.5 多通道输入和多卷积核

??多通道输入、多卷积核是卷积神经网络中最为常见的形式,前面已经介绍了单卷积核的运算过程,每个卷积核和输入 X \boldsymbol{X} X 做卷积运算,得到一个输出矩阵。当出现多卷积核时,第 i \boldsymbol{i} i ( 𝑖 ∈ 𝑛 \boldsymbol{ 𝑖 ∈ 𝑛 } in,𝑛为卷积核个数)个卷积核与输入 X \boldsymbol{X} X 运算得到第𝑖个输出矩阵(也称为输出张量 O \boldsymbol{O} O 的通道 i \boldsymbol{i} i),最后全部的输出矩阵在通道维度上进行拼接(Stack 操作,创建输出通道数的新维度),产生输出张量 O \boldsymbol{O} O O \boldsymbol{O} O 包含了 n \boldsymbol{n} n 个通道数。
??以 3 通道输入、2 个卷积核的卷积层为例。第一个卷积核与输入 X \boldsymbol{X} X 运算得到输出 O \boldsymbol{O} O 的第一个通道,第二个卷积核与输入𝑿运算得到输出𝑶的第二个通道,输出的两个通道拼接在一起形成了最终输出 O \boldsymbol{O} O 。每个卷积核的大小 k \boldsymbol{k} k 、步长 s \boldsymbol{s} s 、填充设定等都是统一设置,这样才能保证输出的每个通道大小一致,从而满足拼接的条件。

在这里插入图片描述
在CNN中,通常我们会使用大小为奇数的卷积核,因为进行卷积操作时一般会以卷积核模块的一个位置为基准进行滑动,这个基准通常就是卷积核模块的中心。若卷积核为奇数,卷积锚点很好找,自然就是卷积模块中心,但如果卷积核是偶数,这时候就没有办法确定了,让谁是锚点似乎都不怎么好。

2.5 步长

??步长就是卷积核或过滤器在左边窗口中每次移动的格数 (无论是自左向右移动,或自上向下移动),对于 2D 输入来说,分为沿 x \boldsymbol{x} x (向右)方向和 y \boldsymbol{y} y (向下)方向的移动长度。下图中,绿色实线代表的卷积核的位置是当前位置,绿色虚线代表是上一次卷积核所在位置,从上一次位置移动到当前位置的移动长度即是步长的定义。下图中感受野沿 x \boldsymbol{x} x 方向的步长为 2,表达为步长 s = 2 \boldsymbol{s = 2} s=2

在这里插入图片描述
当感受野移动至输入 X \boldsymbol{X} X 右边的边界时,感受野向下移动一个步长 s = 2 \boldsymbol{s = 2} s=2,并回到行首。如下图,感受野向下移动 2 个单位,并回到行首位置,进行相乘累加运算。

在这里插入图片描述
循环往复移动,直至达到最下方、最右边边缘位置。然后得到 2 × 2 \boldsymbol{2×2} 2×2 的矩阵。

在这里插入图片描述
可以看到,通过设定步长𝑠,可以有效地控制信息密度的提取。当步长设计的较小时,卷积核以较小幅度移动窗口,有利于提取到更多的特征信息,输出张量的尺寸也更大;当步长设计的较大时,卷积核以较大幅度移动窗口,有利于减少计算代价,过滤冗余信息,输出张量的尺寸也更小。
??同时,在卷积核移动过程中,其值始终是不变的,都是卷积核的值。也可以说,卷积核的值在整个过程中都是共享的,所以又把卷积核的值称为共享变 量。卷积神经网络采用参数共享的方法大大降低了参数的数量。在下图中,卷积核如果继续往右移动2格,卷积核窗口部分将在输入矩 阵之外,这种情况该如何处理?具体处理方法就涉及下面的内容——填充(Padding)。

在这里插入图片描述

2.6 填充

??在前面我们提过,如果不对图片进行拓展的话,经过卷积运算后的输出 O \boldsymbol{O} O 的高宽会小于输入 X \boldsymbol{X} X 的高宽;且当卷积核的步长过大时,卷积核可能会超过图片边界。在实际的网络模型设计时,我们通常希望输出 O \boldsymbol{O} O 的高宽能够与输入 X \boldsymbol{X} X 的高宽相同,从而方便网络参数的设计、残差连接等。为了让输出 O \boldsymbol{O} O 的高宽能够与输入 X \boldsymbol{X} X 的相等,一般通过在原输入 X \boldsymbol{X} X 的高和宽维度上面进行填充(padding)若干无效元素操作,得到增大的输入 X ′ \boldsymbol{X'} X 。通过精心设计填充单元的数量,在 X ′ \boldsymbol{X'} X 上面进行卷积运算得到输出 O \boldsymbol{O} O 的高宽可以和原输入 X \boldsymbol{X} X 相等。这种输入与输出的特征图维度一样的卷积方式,我们称作 Same卷积,不填充称作 Vaild卷积
??如下图,在高/行方向的上(Top)、下(Bottom)方向,宽/列方向的左(Left)、 右(Right)均可以进行不定数量的填充操作,填充的数值一般默认为 0,也可以填充自定义的数据。上、下方向各填充 1 行,左、右方向各填充 2 列,得到新的输入 X ′ \boldsymbol{X'} X

在这里插入图片描述
那么添加填充后的卷积层运算同样,仅仅是把参与运算的输入从 X \boldsymbol{X} X 换成了填充后得到的新张量 X ′ \boldsymbol{X'} X 。如下图,感受野的初始位置在填充后的 X ′ \boldsymbol{X'} X 的左上方,完成相乘累加运算,得到输出 1,写入输出张量的对应位置。

在这里插入图片描述
循环往复,最终得到 5 × 5 \boldsymbol{5 × 5} 5×5 的输出张量。

在这里插入图片描述

2.7 卷积的计算公式

??经过上述对输入图像、卷积核、步长、填充、输出图像的分析,使用张量将它们表示如下:

  • 输入图片的尺寸:一般用 n × n \boldsymbol{n × n} n×n 表示输入的图像大小;
  • 卷积核的大小:一般用 f × f \boldsymbol{f × f} f×f 表示卷积核的大小;
  • 填充(padding):一般用 p \boldsymbol{p} p 来表示填充大小;
  • 步长(stride):一般用 s \boldsymbol{s} s 来表示步长大小;
  • 输出图片的尺寸:一般用 o \boldsymbol{o} o 来表示。

如果已知 n 、 f 、 s \boldsymbol{n、f、s} nfs,则 p = f ? 1 2 \boldsymbol{p = \frac{f - 1}{2}} p=2f?1? o = ? n + 2 p ? f s + 1 ? \boldsymbol{o = \lfloor \frac{n + 2p - f}{s} + 1\rfloor} o=?sn+2p?f?+1?。最后再来分析以下卷积核在 2.5 多通道输入和多卷积核 的末尾我分析过在实际中卷积核的大小 f \boldsymbol{f} f 常常使用奇数是为了找到一个好锚点。实际上选择奇数的卷积核也更容易(padding)。当我们使用 Same卷积 时,这时候我们就需要用到 padding。但是如果 f \boldsymbol{f} f 是偶数的话, p = f ? 1 2 \boldsymbol{p = \frac{f - 1}{2}} p=2f?1?就不是整数了。这意味着我们只需要在输入图像的一边或者两边进行填充。
??(这里可选看)在 PyTorch 中,假设 Input 维度为 ( N , C i n , H i n , W i n ) \boldsymbol{(N,C_{in},H_{in}, W_{in})} (N,Cin?,Hin?,Win?)Output 维度为 ( N , C o u t , H o u t , W o u t ) \boldsymbol{(N,C_{out},H_{out}, W_{out})} (N,Cout?,Hout?,Wout?),两维度关系如下:

  • H o u t = H i n + 2 × p a d d i n g [ 0 ] ? d i l a t i o n [ 0 ] × ( k e r n e l s i z e [ 0 ] ? 1 ) ? 1 s t r i d e [ 0 ] + 1 \boldsymbol{H_{out} = \frac{H_{in} + 2 × padding[0] - dilation[0] ×(kernel_size[0] - 1) - 1}{stride[0]} + 1} Hout?=stride[0]Hin?+2×padding[0]?dilation[0]×(kernels?ize[0]?1)?1?+1
  • W o u t = W i n + 2 × p a d d i n g [ 1 ] ? d i l a t i o n [ 1 ] × ( k e r n e l s i z e [ 1 ] ? 1 ) ? 1 s t r i d e [ 1 ] + 1 \boldsymbol{W_{out} = \frac{W_{in} + 2 × padding[1] - dilation[1] ×(kernel_size[1] - 1) - 1}{stride[1]} + 1} Wout?=stride[1]Win?+2×padding[1]?dilation[1]×(kernels?ize[1]?1)?1?+1

3 总结

??在本篇博客中,我跟大家分享了卷积神经网络中的基础结构——卷积层,并依次介绍了权值共享、卷积操作、卷积核,填充等内容。卷积神经网络的基础知识有很多,本篇博客介绍不完,剩下的我放到下一篇博客。期待您的访问!感恩!


下一篇:卷积神经网络之池化层、BN 层

  人工智能 最新文章
2022吴恩达机器学习课程——第二课(神经网
第十五章 规则学习
FixMatch: Simplifying Semi-Supervised Le
数据挖掘Java——Kmeans算法的实现
大脑皮层的分割方法
【翻译】GPT-3是如何工作的
论文笔记:TEACHTEXT: CrossModal Generaliz
python从零学(六)
详解Python 3.x 导入(import)
【答读者问27】backtrader不支持最新版本的
上一篇文章      下一篇文章      查看所有文章
加:2022-04-28 11:50:53  更:2022-04-28 11:51:12 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 8:19:05-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码