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 小米 华为 单反 装机 图拉丁
 
   -> 人工智能 -> 《动手学深度学习》之多层感知机 -> 正文阅读

[人工智能]《动手学深度学习》之多层感知机

多层感知机

我们可以通过在网络中加入一个或多个隐藏层来克服线性模型的限制,使其能处理更普遍的函数关系类型。要做到这一点,最简单的方法是将许多全连接层堆叠在一起。每一层都输出到上面的层,直到生成最后的输出。我们可以把前 L ? 1 L-1 L?1层看作表示,把最后一层看作线性预测器。这种架构通常称为多层感知机(multilayer perceptron),通常缩写为MLP。下面,我们以图的方式描述了多层感知机,有4个输入,3个输出,其隐藏层包含5个隐藏单元。。

从线性到非线性

矩阵 X ∈ R n × d \mathbf{X} \in \mathbb{R}^{n \times d} XRn×d来表示 n n n个样本的小批量,其中每个样本具有 d d d个输入(特征)。

对于具有 h h h个隐藏单元的单隐藏层多层感知机,用 H ∈ R n × h \mathbf{H} \in \mathbb{R}^{n \times h} HRn×h表示隐藏层的输出,称为隐藏表示(hidden representations)。在数学或代码中, H \mathbf{H} H也被称为隐藏层变量(hidden-layer variable)或隐藏变量(hidden variable)。

为了发挥多层结构的潜力,我们还需要一个额外的关键要素:在仿射变换之后对每个隐藏单元应用非线性的激活函数(activation function) σ \sigma σ。激活函数的输出(例如, σ ( ? ) \sigma(\cdot) σ(?))被称为激活值(activations)。一般来说,有了激活函数,就不可能再将我们的多层感知机退化成线性模型:

H = σ ( X W ( 1 ) + b ( 1 ) ) , O = H W ( 2 ) + b ( 2 ) . \begin{aligned} \mathbf{H} & = \sigma(\mathbf{X} \mathbf{W}^{(1)} + \mathbf{b}^{(1)}), \\ \mathbf{O} & = \mathbf{H}\mathbf{W}^{(2)} + \mathbf{b}^{(2)}.\\ \end{aligned} HO?=σ(XW(1)+b(1)),=HW(2)+b(2).?

为了构建更通用的多层感知机,我们可以继续堆叠这样的隐藏层,例如, H ( 1 ) = σ 1 ( X W ( 1 ) + b ( 1 ) ) \mathbf{H}^{(1)} = \sigma_1(\mathbf{X} \mathbf{W}^{(1)} + \mathbf{b}^{(1)}) H(1)=σ1?(XW(1)+b(1)) H ( 2 ) = σ 2 ( H ( 1 ) W ( 2 ) + b ( 2 ) ) \mathbf{H}^{(2)} = \sigma_2(\mathbf{H}^{(1)} \mathbf{W}^{(2)} + \mathbf{b}^{(2)}) H(2)=σ2?(H(1)W(2)+b(2)),一层叠一层,从而产生更有表达能力的模型。

激活函数

ReLU函数

最受欢迎的选择是线性整流单元(Rectified linear unit,ReLU),因为它实现简单,同时在各种预测任务中表现良好。[ReLU提供了一种非常简单的非线性变换]。
给定元素 x x x,ReLU函数被定义为该元素与 0 0 0的最大值:

ReLU ? ( x ) = max ? ( x , 0 ) . \operatorname{ReLU}(x) = \max(x, 0). ReLU(x)=max(x,0).

通俗地说,ReLU函数通过将相应的激活值设为0来仅保留正元素并丢弃所有负元素。

激活函数通过计算加权和并加上偏置来确定神经元是否应该被激活。它们是将输入信号转换为输出的可微运算。大多数激活函数都是非线性的。

使用ReLU的原因是,它求导表现得特别好:要么让参数消失,要么让参数通过。这使得优化表现得更好,并且ReLU减轻了困扰以往神经网络的梯度消失问题。

注意,ReLU函数有许多变体,包括参数化ReLU(Parameterized ReLU,pReLU)函数 。该变体为ReLU添加了一个线性项,因此即使参数是负的,某些信息仍然可以通过:

pReLU ? ( x ) = max ? ( 0 , x ) + α min ? ( 0 , x ) . \operatorname{pReLU}(x) = \max(0, x) + \alpha \min(0, x). pReLU(x)=max(0,x)+αmin(0,x).

sigmoid函数

[对于一个定义域在 R \mathbb{R} R中的输入,sigmoid函数将输入变换为区间(0, 1)上的输出]。因此,sigmoid通常称为挤压函数(squashing function):它将范围(-inf, inf)中的任意输入压缩到区间(0, 1)中的某个值:

sigmoid ? ( x ) = 1 1 + exp ? ( ? x ) . \operatorname{sigmoid}(x) = \frac{1}{1 + \exp(-x)}. sigmoid(x)=1+exp(?x)1?.

tanh函数

与sigmoid函数类似,[tanh(双曲正切)函数也能将其输入压缩转换到区间(-1, 1)上]。tanh函数的公式如下:

tanh ? ( x ) = 1 ? exp ? ( ? 2 x ) 1 + exp ? ( ? 2 x ) . \operatorname{tanh}(x) = \frac{1 - \exp(-2x)}{1 + \exp(-2x)}. tanh(x)=1+exp(?2x)1?exp(?2x)?.

注意,当输入在0附近时,tanh函数接近线性变换。函数的形状类似于sigmoid函数,不同的是tanh函数关于坐标系原点中心对称。

# 模型选择、欠拟合和过拟合

作为机器学习科学家,我们的目标是发现模式(pattern),这些模式捕捉到了我们训练集所来自的潜在总体的规律。

将模型在训练数据上拟合得比在潜在分布中更接近的现象称为过拟合(overfitting),用于对抗过拟合的技术称为正则化(regularization)。

模型选择、欠拟合和过拟合

训练误差和泛化误差

训练误差(training error)是指,我们的模型在训练数据集上计算得到的误差。泛化误差(generalization error)是指,当我们将模型应用在同样从原始样本的分布中抽取的无限多的数据样本时,我们模型误差的期望。

统计学习理论

我们假设训练数据和测试数据都是从相同的分布中独立提取的。这通常被称为独立同分布假设(i.i.d. assumption),这意味着对数据进行采样的过程没有进行“记忆”。

模型复杂性

我们将重点介绍几个倾向于影响模型泛化的因素:

  1. 可调整参数的数量。当可调整参数的数量(有时称为自由度)很大时,模型往往更容易过拟合。
  2. 参数采用的值。当权重的取值范围较大时,模型可能更容易过拟合。
  3. 训练样本的数量。即使你的模型很简单,也很容易过拟合只包含一两个样本的数据集。而过拟合一个有数百万个样本的数据集则需要一个极其灵活的模型。

模型选择

在机器学习中,我们通常在评估几个候选模型后选择最终的模型。这个过程叫做模型选择。有时,需要进行比较的模型在本质上是完全不同的(比如,决策树与线性模型)。又有时,我们需要比较不同的超参数设置下的同一类模型。

例如,训练多层感知机模型时,我们可能希望比较具有不同数量的隐藏层、不同数量的隐藏单元以及不同的的激活函数组合的模型。为了确定候选模型中的最佳模型,我们通常会使用验证集。

验证集

我们很少能有充足的数据来对每一轮实验采用全新测试集,解决此问题的常见做法是将我们的数据分成三份,除了训练和测试数据集之外,还增加一个验证数据集(validation dataset),也叫验证集(validation set)。。

K K K折交叉验证

当训练数据稀缺时,通常采用 K K K折交叉验证。这里,原始训练数据被分成 K K K个不重叠的子集。然后执行 K K K次模型训练和验证,每次在 K ? 1 K-1 K?1个子集上进行训练,并在剩余的一个子集(在该轮中没有用于训练的子集)上进行验证。最后,通过对 K K K次实验的结果取平均来估计训练和验证误差。

权重衰减

范数与权重衰减

在训练参数化机器学习模型时,权重衰减(通常称为 L 2 L_2 L2?正则化)是最广泛使用的正则化的技术之一。

线性回归的损失由下式给出:

L ( w , b ) = 1 n ∑ i = 1 n 1 2 ( w ? x ( i ) + b ? y ( i ) ) 2 . L(\mathbf{w}, b) = \frac{1}{n}\sum_{i=1}^n \frac{1}{2}\left(\mathbf{w}^\top \mathbf{x}^{(i)} + b - y^{(i)}\right)^2. L(w,b)=n1?i=1n?21?(w?x(i)+b?y(i))2.

我们通过正则化常数 λ \lambda λ来描述这种权衡,这是一个非负超参数,我们使用验证数据拟合:

L ( w , b ) + λ 2 ∥ w ∥ 2 , L(\mathbf{w}, b) + \frac{\lambda}{2} \|\mathbf{w}\|^2, L(w,b)+2λ?w2,

L 2 L_2 L2?正则化线性模型构成经典的岭回归(ridge regression)算法。
L 1 L_1 L1?正则化线性回归是统计学中类似的基本模型,通常被称为套索回归(lasso regression)。

使用 L 2 L_2 L2?范数的一个原因:

它对权重向量的大分量施加了巨大的惩罚。这使得我们的学习算法偏向于在大量特征上均匀分布权重的模型。在实中,这可能使它们对单个变量中的观测误差更为鲁棒。相比之下, L 1 L_1 L1?惩罚会导致模型将其他权重清除为零而将权重集中在一小部分特征上。这称为特征选择(feature selection)。

Dropout

Dropout可以作为训练深度神经网络的一种trick供选择。在每个训练批次中,通过忽略一半的特征检测器(让一半的隐层节点值为0),可以明显地减少过拟合现象。这种方式可以减少特征检测器(隐层节点)间的相互作用,检测器相互作用是指某些检测器依赖其他检测器才能发挥作用。

Dropout说的简单一点就是:我们在前向传播的时候,让某个神经元的激活值以一定的概率p停止工作,这样可以使模型泛化性更强,因为它不会太依赖某些局部的特征。

正向传播、反向传播和计算图

数值稳定性和模型初始化

梯度消失和梯度爆炸

梯度爆炸(gradient exploding)问题:参数更新过大,破坏了模型的稳定收敛;

梯度消失(gradient vanishing)问题:参数更新过小,在每次更新时几乎不会移动,导致无法学习。

参数初始化

默认初始化

在前面的部分中,我们使用正态分布来初始化权重值。如果我们不指定初始化方法,框架将使用默认的随机初始化方法,对于中等规模的问题,这种方法通常很有效。

Xavier初始化

:没怎么看懂!!!!!!!!

让我们看看某些没有非线性的全连接层输出(例如,隐藏变量) o i o_{i} oi?的尺度分布。
对于该层 n i n n_\mathrm{in} nin?输入 x j x_j xj?及其相关权重 w i j w_{ij} wij?,输出由下式给出

o i = ∑ j = 1 n i n w i j x j . o_{i} = \sum_{j=1}^{n_\mathrm{in}} w_{ij} x_j. oi?=j=1nin??wij?xj?.

权重 w i j w_{ij} wij?都是从同一分布中独立抽取的。此外,让我们假设该分布具有零均值和方差 σ 2 \sigma^2 σ2。请注意,这并不意味着分布必须是高斯的,只是均值和方差需要存在。现在,让我们假设层 x j x_j xj?的输入也具有零均值和方差 γ 2 \gamma^2 γ2,并且它们独立于 w i j w_{ij} wij?并且彼此独立。在这种情况下,我们可以按如下方式计算 o i o_i oi?的平均值和方差:

E [ o i ] = ∑ j = 1 n i n E [ w i j x j ] = ∑ j = 1 n i n E [ w i j ] E [ x j ] = 0 , V a r [ o i ] = E [ o i 2 ] ? ( E [ o i ] ) 2 = ∑ j = 1 n i n E [ w i j 2 x j 2 ] ? 0 = ∑ j = 1 n i n E [ w i j 2 ] E [ x j 2 ] = n i n σ 2 γ 2 . \begin{aligned} E[o_i] & = \sum_{j=1}^{n_\mathrm{in}} E[w_{ij} x_j] \\&= \sum_{j=1}^{n_\mathrm{in}} E[w_{ij}] E[x_j] \\&= 0, \\ \mathrm{Var}[o_i] & = E[o_i^2] - (E[o_i])^2 \\ & = \sum_{j=1}^{n_\mathrm{in}} E[w^2_{ij} x^2_j] - 0 \\ & = \sum_{j=1}^{n_\mathrm{in}} E[w^2_{ij}] E[x^2_j] \\ & = n_\mathrm{in} \sigma^2 \gamma^2. \end{aligned} E[oi?]Var[oi?]?=j=1nin??E[wij?xj?]=j=1nin??E[wij?]E[xj?]=0,=E[oi2?]?(E[oi?])2=j=1nin??E[wij2?xj2?]?0=j=1nin??E[wij2?]E[xj2?]=nin?σ2γ2.?

保持方差不变的一种方法是设置 n i n σ 2 = 1 n_\mathrm{in} \sigma^2 = 1 nin?σ2=1。现在考虑反向传播过程,我们面临着类似的问题,尽管梯度是从更靠近输出的层传播的。使用与正向传播相同的推理,我们可以看到,除非 n o u t σ 2 = 1 n_\mathrm{out} \sigma^2 = 1 nout?σ2=1,否则梯度的方差可能会增大,其中 n o u t n_\mathrm{out} nout?是该层的输出的数量。这使我们进退两难:我们不可能同时满足这两个条件。相反,我们只需满足:

1 2 ( n i n + n o u t ) σ 2 = 1 ?或等价于? σ = 2 n i n + n o u t . \begin{aligned} \frac{1}{2} (n_\mathrm{in} + n_\mathrm{out}) \sigma^2 = 1 \text{ 或等价于 } \sigma = \sqrt{\frac{2}{n_\mathrm{in} + n_\mathrm{out}}}. \end{aligned} 21?(nin?+nout?)σ2=1?或等价于?σ=nin?+nout?2? ?.?

这就是现在标准且实用的Xavier初始化的基础。通常,Xavier初始化从均值为零,方差 σ 2 = 2 n i n + n o u t \sigma^2 = \frac{2}{n_\mathrm{in} + n_\mathrm{out}} σ2=nin?+nout?2?的高斯分布中采样权重。我们也可以利用Xavier的直觉来选择从均匀分布中抽取权重时的方差。注意均匀分布 U ( ? a , a ) U(-a, a) U(?a,a)的方差为 a 2 3 \frac{a^2}{3} 3a2?。将 a 2 3 \frac{a^2}{3} 3a2?代入到 σ 2 \sigma^2 σ2的条件中,将得到初始化的建议:

U ( ? 6 n i n + n o u t , 6 n i n + n o u t ) . U\left(-\sqrt{\frac{6}{n_\mathrm{in} + n_\mathrm{out}}}, \sqrt{\frac{6}{n_\mathrm{in} + n_\mathrm{out}}}\right). U(?nin?+nout?6? ?,nin?+nout?6? ?).

尽管上述数学推理中,不存在非线性的假设在神经网络中很容易被违反,但Xavier初始化方法在实践中被证明是有效的。

注:上面的推理仅仅触及了现代参数初始化方法的皮毛。深度学习框架通常实现十几种不同的启发式方法。此外,参数初始化一直是深度学习基础研究的热点领域。其中包括专门用于参数绑定(共享)、超分辨率、序列模型和其他情况的启发式算法。

环境和分布偏移

:没怎么看懂!!!!!!!!!!!!

分布偏移的类型

首先,我们坚持使用被动预测设置,考虑到数据分布可能发生变化的各种方式,以及为挽救模型性能可能采取的措施。在一个经典的设置中,我们假设我们的训练数据是从某个分布 p S ( x , y ) p_S(\mathbf{x},y) pS?(x,y)中采样的,但是我们的测试数据将包含从不同分布 p T ( x , y ) p_T(\mathbf{x},y) pT?(x,y)中抽取的未标记样本。我们必须面对一个清醒的现实。如果没有任何关于 p S p_S pS? p T p_T pT?之间相互关系的假设,学习到一个鲁棒的分类器是不可能的。

考虑一个二元分类问题,我们希望区分狗和猫。如果分布可以以任意方式偏移,那么我们的设置允许病态的情况,即输入的分布保持不变: p S ( x ) = p T ( x ) p_S(\mathbf{x}) = p_T(\mathbf{x}) pS?(x)=pT?(x),但标签全部翻转: p S ( y ∣ x ) = 1 ? p T ( y ∣ x ) p_S(y | \mathbf{x}) = 1 - p_T(y | \mathbf{x}) pS?(yx)=1?pT?(yx)。换言之,如果上帝能突然决定,将来所有的“猫”现在都是狗,而我们以前所说的“狗”现在是猫。而此时输入 p ( x ) p(\mathbf{x}) p(x)的分布没有任何改变,那么我们就不可能将这种设置与分布完全没有变化的设置区分开。

幸运的是,在对未来我们的数据可能发生变化的一些限制性假设下,有原则的算法可以检测这种偏移,有时甚至动态调整,提高原始分类器的准确性。

协变量偏移

这里我们假设,虽然输入的分布可能随时间而改变,但标签函数(即条件分布 P ( y ∣ x ) P(y \mid \mathbf{x}) P(yx))没有改变。统计学家称之为协变量偏移(covariate shift),因为这个问题是由于协变量(特征)分布的变化而产生的。虽然有时我们可以在不引用因果关系的情况下对分布偏移进行推理,但我们注意到,在我们认为 x \mathbf{x} x导致 y y y的情况下,协变量偏移是一种自然假设。

标签偏移

标签偏移描述了与协变量偏移相反的问题。
这里,我们假设标签边缘概率 P ( y ) P(y) P(y)可以改变,但是类别条件分布 P ( x ∣ y ) P(\mathbf{x} \mid y) P(xy)在不同的领域之间保持不变。当我们认为 y y y导致 x \mathbf{x} x时,标签偏移是一个合理的假设。

例如,我们可能希望根据症状(或其他表现)来预测疾病,即使疾病的相对流行率随着时间的推移而变化。标签偏移在这里是恰当的假设,因为疾病会引起症状。在一些退化的情况下,标签偏移和协变量偏移假设可以同时成立。

概念偏移

我们也可能会遇到概念偏移的相关问题,当标签的定义发生变化时,就会出现这种问题。

事实证明,如果我们环游美国,根据所在的地理位置改变我们的数据来源,我们会发现关于“软饮”名称的分布发生了相当大的概念偏移。

分布偏移示例

在深入研究形式体系和算法之前,我们可以讨论一些协变量偏移或概念偏移可能并不明显的具体情况。

医学诊断

自动驾驶汽车

非平稳分布

典型非平稳分布(nonstationary distribution的情况。

  • 我们训练了一个计算广告模型,但却没有经常更新(例如,我们忘记了一个叫iPad的不知名新设备刚刚上市)。
  • 我们建立了一个垃圾邮件过滤器。它能很好地检测到我们目前看到的所有垃圾邮件。但是,垃圾邮件发送者们变得聪明起来,制造出新的信息,看起来不像我们以前见过的任何垃圾邮件。
  • 我们建立了一个产品推荐系统。它在整个冬天都有效,但圣诞节过后很久还会继续推荐圣诞帽。

更多轶事

  • 我们建立了一个人脸检测器。它在所有基准测试中都能很好地工作。不幸的是,它在测试数据上失败了——有问题的例子是人脸充满了整个图像的特写镜头(训练集中没有这样的数据)。
  • 我们为美国市场建立了一个网络搜索引擎,并希望将其部署到英国。
  • 我们通过在一个大的数据集来训练图像分类器,其中每一个大类的数量在数据集近乎是平均的,比如1000个类别,每个类别由1000个图像表示。然后我们将该系统部署到真实世界中,照片的实际标签分布显然是不均匀的。

分布偏移纠正

经验风险与真实风险

我们迭代训练数据 { ( x 1 , y 1 ) , … , ( x n , y n ) } \{(\mathbf{x}_1, y_1), \ldots, (\mathbf{x}_n, y_n)\} {(x1?,y1?),,(xn?,yn?)}的特征和相关的标签,并在每一个小批量之后更新模型 f f f的参数。

m i n i m i z e f 1 n ∑ i = 1 n l ( f ( x i ) , y i ) , \mathop{\mathrm{minimize}}_f \frac{1}{n} \sum_{i=1}^n l(f(\mathbf{x}_i), y_i), minimizef?n1?i=1n?l(f(xi?),yi?),

其中 l l l是损失函数,用来度量给定响应标签 y i y_i yi?,预测 f ( x i ) f(\mathbf{x}_i) f(xi?)的“糟糕程度”。统计学家称上述公式中的这一项为经验风险。
经验风险 (empirical risk)是
为了近似 真实风险(true risk),整个训练数据上的平均损失,即从其真实分布 p ( x , y ) p(\mathbf{x},y) p(x,y)中抽取的所有数据的总体损失的期望值:

E p ( x , y ) [ l ( f ( x ) , y ) ] = ∫ ∫ l ( f ( x ) , y ) p ( x , y ) ?? d x d y . E_{p(\mathbf{x}, y)} [l(f(\mathbf{x}), y)] = \int\int l(f(\mathbf{x}), y) p(\mathbf{x}, y) \;d\mathbf{x}dy. Ep(x,y)?[l(f(x),y)]=l(f(x),y)p(x,y)dxdy.

经验风险最小化即在第一个公式 中最小化经验风险,是一种实用的机器学习策略,希望能近似最小化真实风险。

协变量偏移纠正

标签偏移纠正

概念偏移纠正

总结

  • 梯度消失和爆炸是深度网络中常见的问题。在参数初始化时需要非常小心,以确保梯度和参数可以得到很好的控制。

  • 需要用启发式的初始化方法来确保初始梯度既不太大也不太小。

  • ReLU激活函数缓解了梯度消失问题,这样可以加速收敛。

  • 随机初始化是保证在进行优化前打破对称性的关键。

  • Xavier初始化表明,对于每一层,输出的方差不受输入数量的影响,任何梯度的方差不受输出数量的影响。

  • 在许多情况下,训练集和测试集并不来自同一个分布。这就是所谓的分布偏移。

  • 真实风险是从真实分布中抽取的所有数据的总体损失的预期。然而,这个数据总体通常是无法获得的。经验风险是训练数据的平均损失,用于近似真实风险。在实践中,我们进行经验风险最小化。

  • 在相应的假设条件下,可以在测试时检测并纠正协变量偏移和标签偏移。在测试时,不考虑这种偏移可能会成为问题。

  • 在某些情况下,环境可能会记住自动操作并以令人惊讶的方式做出响应。在构建模型时,我们必须考虑到这种可能性,并继续监控实时系统,并对我们的模型和环境以意想不到的方式纠缠在一起的可能性持开放态度。

  人工智能 最新文章
2022吴恩达机器学习课程——第二课(神经网
第十五章 规则学习
FixMatch: Simplifying Semi-Supervised Le
数据挖掘Java——Kmeans算法的实现
大脑皮层的分割方法
【翻译】GPT-3是如何工作的
论文笔记:TEACHTEXT: CrossModal Generaliz
python从零学(六)
详解Python 3.x 导入(import)
【答读者问27】backtrader不支持最新版本的
上一篇文章      下一篇文章      查看所有文章
加:2021-09-12 13:09:55  更:2021-09-12 13:11:11 
 
开发: 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/27 15:39:59-

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