当前位置:   article > 正文

吴恩达deeplearning.ai神经网络和深度学习(Ⅰ)(第二周-神经网络基础)_2.8z.z .dz z.z.

2.8z.z .dz z.z.

神经网络和深度学习课程(第二周-神经网络基础)

2.1 二分类

1.二分类定义
  二分类就是输出y只有{0,1}两个离散值(也有{-1,1}的情况)。我们以一个图像识别问题为例,判断图片中是否有猫存在,0代表non cat,1代表cat。
在这里插入图片描述
  如上图所示,这是一个典型的二分类问题。一般来说,彩色图片包含RGB三个通道。例如该cat图片的尺寸为(64,64,3),在神经网络模型中,我们首先要将图片输入x(维度是(64,64,3))转化为一维的特征向量(feature vector)。方法是每个通道拉成一列,再连接起来。由于64x64x3=12288,则转化后的输入特征向量维度为(12288,1)。特征向量x是列向量,维度一般记为 n x n _x nx
  如果训练样本共有m张图片,那么整个训练样本X组成了矩阵,维度是( n x n_x nx,m)。注意,这里矩阵X的行 n x n_x nx代表了每个样本 x ( i ) x^{(i)} x(i)特征个数,列m代表了样本个数(说白了就是一列一个样本)。一列一个样本的原因是为了之后矩阵运算的方便。而所有训练样本的输出Y也组成了一维的行向量,写成矩阵的形式后,它的维度就是(1,m)(一列一个样本)。

2.2 逻辑回归

接下来介绍如何使用逻辑回归来解决二分类问题

1.逻辑回归的定义
  逻辑回归与二分类模型不同,它的输出,取值范围在[0,1]之间,而二分类模型的输出要么是0,要么是1。
  假设只有一张图片,使用线性模型,引入参数w和b。权重w的维度是( n x n_x nx,1),b是一个常数项。这样,逻辑回归的线性预测输出可以写成: y ^ = w T x + b \hat{y}=w^Tx+b y^=wTx+b
  上式的线性输出区间为整个实数范围,而逻辑回归要求输出范围在[0,1]之间,所以还需要对上式的线性函数输出进行处理。方法是引入Sigmoid函数(激活函数),让输出限定在[0,1]之间。这样,逻辑回归的预测输出 y ^ \hat{y} y^就可以完整写成:
y ^ = s i g m o i d ( w T x + b ) \hat{y}=sigmoid(w^Tx+b) y^=sigmoid(wTx+b)

2.3 逻辑回归的代价函数

1.损失函数(Loss function)
  损失函数又叫做误差函数,描述了样本的预测值 y ^ \hat{y} y^与真实值之间的差距,用来衡量算法的运行情况。
  根据以往经验,通常使用平方误差(squared error)来衡量: L ( y ^ , y ) = 1 2 ( y ^ − y ) 2 L(\hat{y},y)=\frac12(\hat{y}-y)^2 L(y^,y)=21(y^y)2
  但在逻辑回归中,优化的参数不是凸优化,使用上面的损失函数,利用梯度下降法时可能找不到全局最优解,因此定义另一种损失函数:
L ( y ^ , y ) = − ( y l o g y ^ + ( 1 − y ) l o g ( 1 − y ^ ) ) L(\hat{y},y)=-(ylog\hat{y}+(1-y)log(1-\hat{y})) L(y^,y)=(ylogy^+(1y)log(1y^))
  当y=1时, L ( y ^ , y ) = − l o g y ^ L(\hat{y},y)=-log\hat{y} L(y^,y)=logy^,如果想让 L ( y ^ , y ) L(\hat{y},y) L(y^,y)尽可能的小,那 y ^ \hat{y} y^的值就要尽可能的大,因为sigmoid函数的取值是[0,1],因此 y ^ \hat{y} y^会无限趋近于1。
  当y=0时, L ( y ^ , y ) = − l o g ( 1 − y ^ ) L(\hat{y},y)=-log(1-\hat{y}) L(y^,y)=log(1y^),如果想让 L ( y ^ , y ) L(\hat{y},y) L(y^,y)尽可能的小(L趋于0),那 y ^ \hat{y} y^的值就要尽可能的小,因为sigmoid函数的取值是[0,1],因此 y ^ \hat{y} y^会无限趋近于0。

2.代价函数(Cost function)
  上面介绍的Loss function是针对单个样本的,对于m个样本,我们定义Cost function,Cost function是m个样本的Loss function的平均值,反映了m个样本的预测输出 y ^ \hat{y} y^与真实样本输出y的平均接近程度:
J ( w , b ) = 1 m ∑ i = 1 m L ( y ^ ( i ) , y ( i ) ) = 1 m ∑ i = 1 m − y ( i ) l o g y ^ ( i ) − ( 1 − y ( i ) ) l o g ( y ^ ( i ) ) J(w,b)=\frac1m\sum_{i=1}^mL(\hat{y}^{(i)},y^{(i)})=\frac1m\sum_{i=1}^m -y^{(i)}log\hat{y}^{(i)}-(1-y^{(i)}) log(\hat{y}^{(i)}) J(w,b)=m1i=1mL(y^(i),y(i))=m1i=1my(i)logy^(i)(1y(i))log(y^(i))
  损失函数只适用单个训练样本,而代价函数是参数的总代价,所以在训练逻辑回归模型时候,我们需要找到合适的w和b,来让代价函数的总代价降到最低。逻辑回归可以看做是一个非常小的神经网络。

2.4 梯度下降法

  使用梯度下降(Gradient Descent)算法来计算出合适的w和b值,从而最小化m个训练样本的Cost function

1.梯度下降法的定义
  梯度下降算法是先随机选择一组参数w和b值,然后每次迭代的过程中分别沿着w和b的梯度(偏导数)下降的方向前进一小步,不断修正w和b。每次迭代更新w和b后,都能让J(w,b)更接近全局最小值,梯度下降的过程如图所示:
在这里插入图片描述  每次迭代更新,w和b的修正表达式为:
w : = w − α ∂ J ( w , b ) ∂ w w:=w-\alpha {\partial J(w,b)\over \partial w} w:=wαwJ(w,b)
b : = b − α ∂ J ( w , b ) ∂ b b:=b-\alpha {\partial J(w,b)\over \partial b} b:=bαbJ(w,b)

  • :=表示更新参数
  • α \alpha α表示学习率,即每次梯度下降的步进长度。 α \alpha α越大,w和b每次更新的“步伐”越大。
  • python程序中常用dw表示 ∂ J ( w , b ) ∂ w \partial J(w,b)\over \partial w wJ(w,b),用db表示 ∂ J ( w , b ) ∂ b \partial J(w,b)\over \partial b bJ(w,b)

2.梯度下降法的细节说明
  假设只有一个参数w,寻找w的最小值:
在这里插入图片描述
  假设我们以如图点为初始化点,该点的斜率 d J ( w ) d w {d J(w)\over dw} dwdJ(w)大于0,为了到达最小点,由下面公式可知,接下来向左走一步。 w : = w − α d J ( w ) d w w:=w-\alpha {d J(w)\over dw} w:=wαdwdJ(w)
在这里插入图片描述
  反之,以下图的点为初始点,斜率小于0,接下走应该向右走一步。
在这里插入图片描述

2.5&2.6 关于导数

  不再过多赘述!!

2.7 计算图正向传播&2.8计算图的反向传播

  神经网络的训练过程实际上包含了两个过程:正向传播(Forward Propagation)和反向传播(Back Propagation)。正向传播是从输入到输出,由神经网络计算得到预测输出的过程;反向传播是从输出到输入,对参数w和b计算梯度的过程。

1.正向传播
在这里插入图片描述
  计算图中,这种从左到右,从输入到输出的过程就对应着神经网络或者逻辑回归中输入与权重经过运算计算得到Cost function的正向过程。

2.反向传播
  反向传播(Back Propagation),即计算输出对输入的偏导数
在这里插入图片描述

  计算 ∂ J ( a , b , c ) ∂ a {\partial J(a,b,c)\over \partial a} aJ(a,b,c),由于a→v→J,求导数从输出到输入,即:
∂ J ( a , b , c ) ∂ a = ∂ J ( a , b , c ) ∂ v ⋅ ∂ v ∂ a = 3 ⋅ 1 = 3 {\partial J(a,b,c)\over \partial a}={\partial J(a,b,c)\over \partial v} \cdot {\partial v\over \partial a}=3 \cdot 1=3 aJ(a,b,c)=vJ(a,b,c)av=31=3
  计算 ∂ J ( a , b , c ) ∂ b {\partial J(a,b,c)\over \partial b} bJ(a,b,c),由于b→u→v→J,求导数从输出到输入,即:
∂ J ( a , b , c ) ∂ b = ∂ J ( a , b , c ) ∂ v ⋅ ∂ v ∂ u ⋅ ∂ u ∂ b = 3 ⋅ 1 ⋅ 2 = 6 {\partial J(a,b,c)\over \partial b}={\partial J(a,b,c)\over \partial v} \cdot {\partial v\over \partial u} \cdot {\partial u\over \partial b}=3 \cdot 1 \cdot 2=6 bJ(a,b,c)=vJ(a,b,c)uvbu=312=6
  计算 ∂ J ( a , b , c ) ∂ c {\partial J(a,b,c)\over \partial c} cJ(a,b,c),由于c→u→v→J,求导数从输出到输入,即:
∂ J ( a , b , c ) ∂ c = ∂ J ( a , b , c ) ∂ v ⋅ ∂ v ∂ u ⋅ ∂ u ∂ c = 3 ⋅ 1 ⋅ 3 = 9 {\partial J(a,b,c)\over \partial c}={\partial J(a,b,c)\over \partial v} \cdot {\partial v\over \partial u} \cdot {\partial u\over \partial c}=3 \cdot 1 \cdot 3=9 cJ(a,b,c)=vJ(a,b,c)uvcu=313=9

2.9 逻辑回归中的梯度下降

  逻辑回归的损失函数可以表示为:
z = w T x + b y ^ = a = σ ( z ) L ( a , y ) = − ( y log ⁡ ( a ) + ( 1 − y ) log ⁡ ( 1 − a ) )

z=wTx+by^=a=σ(z)L(a,y)=(ylog(a)+(1y)log(1a))
z=wTx+by^=a=σ(z)L(a,y)=(ylog(a)+(1y)log(1a))
  假设一个样本有两个特征 x 1 x_1 x1 x 2 x_2 x2,相应的权重w维度也是2,即 w 1 w_1 w1 w 2 w_2 w2,此时 z = w 1 x 1 + w 2 x 2 + b z=w_1x_1+w_2x_2+b z=w1x1+w2x2+b,正向传播的过程即计算损失函数的过程为:在这里插入图片描述
  反向传播(Back Propagation),即计算输出对输入的偏导数:{ w 1 w_1 w1 w 2 w_2 w2、b}→z→a→L

在这里插入图片描述

d a = ∂ L ∂ a = − y a + 1 − y 1 − a d a=\frac{\partial L}{\partial a}=-\frac{y}{a}+\frac{1-y}{1-a} da=aL=ay+1a1y d z = ∂ L ∂ z = ∂ L ∂ a ⋅ ∂ a ∂ z = ( − y a + 1 − y 1 − a ) ⋅ a ( 1 − a ) = a − y d z=\frac{\partial L}{\partial z}=\frac{\partial L}{\partial a} \cdot \frac{\partial a}{\partial z}=\left(-\frac{y}{a}+\frac{1-y}{1-a}\right) \cdot a(1-a)=a-y dz=zL=aLza=(ay+1a1y)a(1a)=ay
  损失函数L关于w和b的偏导数:
d w 1 = ∂ L ∂ w 1 = ∂ L ∂ z ⋅ ∂ z ∂ w 1 = x 1 ⋅ d z = x 1 ( a − y ) d w 2 = ∂ L ∂ w 2 = ∂ L ∂ z ⋅ ∂ z ∂ w 2 = x 2 ⋅ d z = x 2 ( a − y ) d b = ∂ L ∂ b = ∂ L ∂ z ⋅ ∂ z ∂ b = 1 ⋅ d z = a − y

dw1=Lw1=Lzzw1=x1dz=x1(ay)dw2=Lw2=Lzzw2=x2dz=x2(ay)db=Lb=Lzzb=1dz=ay
dw1dw2=w1L=zLw1z=x1dz=x1(ay)=w2L=zLw2z=x2dz=x2(ay)db=bL=zLbz=1dz=ay
  梯度下降法可以表示为:
w 1 : = w 1 − α d w 1 w 2 : = w 2 − α d w 2 b : = b − α d b
w1:=w1αdw1w2:=w2αdw2b:=bαdb
w1w2b:=w1αdw1:=w2αdw2:=bαdb

2.10 m个样本的梯度下降(此处假设每个样本两个特征)

  假设有m个样本,每个样本两个特征,则代价函数(2.8是单个样本的损失函数,单个样本损失函数=代价函数)表达式为:
z ( i ) = w T x ( i ) + b z^{(i)}=w^{T} x^{(i)}+b z(i)=wTx(i)+b y ^ ( i ) = a ( i ) = σ ( z ( i ) ) \hat{y}^{(i)}=a^{(i)}=\sigma\left(z^{(i)}\right) y^(i)=a(i)=σ(z(i)) J ( w , b ) = 1 m ∑ i = 1 m L ( y ^ ( i ) , y ( i ) ) = − 1 m ∑ i = 1 m [ y ( i ) log ⁡ y ^ ( i ) + ( 1 − y ( i ) ) log ⁡ ( 1 − y ^ ( i ) ) ] J(w, b)=\frac{1}{m} \sum_{i=1}^{m} L\left(\hat{y}^{(i)}, y^{(i)}\right)=-\frac{1}{m} \sum_{i=1}^{m}\left[y^{(i)} \log \hat{y}^{(i)}+\left(1-y^{(i)}\right) \log \left(1-\hat{y}^{(i)}\right)\right] J(w,b)=m1i=1mL(y^(i),y(i))=m1i=1m[y(i)logy^(i)+(1y(i))log(1y^(i))]
  其中,i表示第i个样本。
  代价函数Cost function关于w和b的偏导数可以写成和平均的形式:
d w 1 = ∂ J ( w , b ) ∂ w 1 = 1 m ∑ i = 1 m x 1 ( i ) ( a ( i ) − y ( i ) ) d w 2 = ∂ J ( w , b ) ∂ w 2 = 1 m ∑ i = 1 m x 2 ( i ) ( a ( i ) − y ( i ) ) d b = ∂ J ( w , b ) ∂ b = 1 m ∑ i = 1 m ( a ( i ) − y ( i ) )

dw1=J(w,b)w1=1mi=1mx1(i)(a(i)y(i))dw2=J(w,b)w2=1mi=1mx2(i)(a(i)y(i))db=J(w,b)b=1mi=1m(a(i)y(i))
dw1dw2db=w1J(w,b)=m1i=1mx1(i)(a(i)y(i))=w2J(w,b)=m1i=1mx2(i)(a(i)y(i))=bJ(w,b)=m1i=1m(a(i)y(i))
  对上式进行分析,代价函数是m个损失函数的平均值,例如损失函数对 w 1 w_1 w1的偏导数为 x 1 ( a − y ) x_{1}(a-y) x1(ay),因此代价函数对 w 1 w_1 w1的偏导数为m个损失函数对 w 1 w_1 w1偏导数的平均值, d w 1 = ∂ J ( w , b ) ∂ w 1 = 1 m ∑ i = 1 m x 1 ( i ) ( a ( i ) − y ( i ) ) d w_{1}=\frac{\partial J(w, b)}{\partial w_{1}}=\frac{1}{m} \sum_{i=1}^{m} x_{1}^{(i)}\left(a^{(i)}-y^{(i)}\right) dw1=w1J(w,b)=m1i=1mx1(i)(a(i)y(i))

  梯度下降法可以表示为:
w 1 : = w 1 − α d w 1 w 2 : = w 2 − α d w 2 b : = b − α d b

w1:=w1αdw1w2:=w2αdw2b:=bαdb
w1w2b:=w1αdw1:=w2αdw2:=bαdb
  经过n次迭代后,整个梯度下降算法就完成了。值得一提的是,在上述的梯度下降算法中,我们是利用for循环对每个样本进行 d w 1 dw_1 dw1 d w 2 dw_2 dw2和db的累加计算最后再求平均数的。在深度学习中,样本数量m通常很大,使用for循环会让神经网络程序运行得很慢。所以,我们应该尽量避免使用for循环操作,而使用矩阵运算,能够大大提高程序运行速度。因此提出向量化

2.11&2.12 向量化(Vectorization)

  向量化(Vectorization)就是利用矩阵运算的思想,减少使用loop循环语句,从而大大提高运算速度。
举一个简单的例子,采用向量化和非向量化计算sum(a*b)

import numpy as np
import time

a = np.random.rand(1000000)
b = np.random.rand(1000000)

tic = time.time()
# 向量中对应元素相乘,再相加
c = np.dot(a, b)
toc = time.time()

print(c)
# time.time()以秒为单位
print("Vectorized:" + str(1000 * (toc - tic)) + "ms")

c = 0
tic = time.time()
for i in range(1000000):
    c += a[i] * b[i]
toc = time.time()

print(c)
# time.time()以秒为单位
print("Non Vectorized:" + str(1000 * (toc - tic)) + "ms")
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
249657.11697603075
Vectorized:1.9545555114746094ms
249657.11697603532
Non Vectorized:449.5701789855957ms
  • 1
  • 2
  • 3
  • 4

  从程序运行结果上来看,该例子使用for循环运行时间是使用向量运算运行时间的很多倍。因此,深度学习算法中,使用向量化矩阵运算的效率要高得多。

2.13&2.14 向量化在logistics中的应用

1.正向传播
  输入矩阵X的维度是( n x n_x nx,m)。注意,这里矩阵X的行数 n x n_x nx代表了每个样本 x ( i ) x^{(i)} x(i)特征个数,列m代表了样本个数(说白了就是一列一个样本)。权重矩阵w的维度是( n x n_x nx,1),b是一个常数值,输出矩阵Y的维度为(1,m)。
z = w T x + b y ^ = A = σ ( z )

z=wTx+by^=A=σ(z)
z=wTx+by^=A=σ(z)   在python中可以表示为:

# w.T表示w的转置
Z= np.dot(w.T,X) + b
A = sigmoid(Z)
  • 1
  • 2
  • 3

2.反向传播
d z ( i ) = a ( i ) − y ( i ) dz^{(i)} = a^{(i)}-y^{(i)} dz(i)=a(i)y(i) d w 1 = ∂ J ( w , b ) ∂ w 1 = 1 m ∑ i = 1 m x 1 ( i ) ( a ( i ) − y ( i ) ) = 1 m ∑ i = 1 m x 1 ( i ) d z ( i ) d w 2 = ∂ J ( w , b ) ∂ w 2 = 1 m ∑ i = 1 m x 2 ( i ) ( a ( i ) − y ( i ) ) = 1 m ∑ i = 1 m x 2 ( i ) d z ( i ) d b = ∂ J ( w , b ) ∂ b = 1 m ∑ i = 1 m ( a ( i ) − y ( i ) ) = 1 m ∑ i = 1 m d z ( i )

dw1=J(w,b)w1=1mi=1mx1(i)(a(i)y(i))=1mi=1mx1(i)dz(i)dw2=J(w,b)w2=1mi=1mx2(i)(a(i)y(i))=1mi=1mx2(i)dz(i)db=J(w,b)b=1mi=1m(a(i)y(i))=1mi=1mdz(i)
dw1dw2db=w1J(w,b)=m1i=1mx1(i)(a(i)y(i))=m1i=1mx1(i)dz(i)=w2J(w,b)=m1i=1mx2(i)(a(i)y(i))=m1i=1mx2(i)dz(i)=bJ(w,b)=m1i=1m(a(i)y(i))=m1i=1mdz(i)
将上述变量写成矩阵形式:

A = [ a ( 1 ) , a ( 2 ) , … … , a ( m ) ] A=[a^{(1)},a^{(2)},……,a^{(m)}] A=[a(1),a(2),……a(m)]

Y = [ y ( 1 ) , y ( 2 ) , … … , y ( m ) ] Y=[y^{(1)},y^{(2)},……,y^{(m)}] Y=[y(1),y(2),……y(m)]

X = [ x 1 ( 1 ) x 1 ( 2 ) ⋯ x 1 ( m ) x 2 ( 1 ) x 2 ( 2 ) ⋯ x 2 ( m ) ⋮ ⋮ ⋯ ⋮ x n x ( 1 ) x n x ( 2 ) ⋯ x n x ( m ) ] X=\left[

x1(1)x1(2)x1(m)x2(1)x2(2)x2(m)xnx(1)xnx(2)xnx(m)
\right] X= x1(1)x2(1)xnx(1)x1(2)x2(2)xnx(2)x1(m)x2(m)xnx(m)

d Z = A − Y = [ z ( 1 ) , z ( 2 ) , … … , z ( m ) ] dZ=A-Y=[z^{(1)},z^{(2)},……,z^{(m)}] dZ=AY=[z(1),z(2),……z(m)]

则由此可得

d W = [ d w 1 , d w 2 , … … , d w n x ] = 1 m X ⋅ ( d Z ) T = 1 m [ x 1 ( 1 ) x 1 ( 2 ) ⋯ x 1 ( m ) x 2 ( 1 ) x 2 ( 2 ) ⋯ x 2 ( m ) ⋮ ⋮ ⋯ ⋮ x n x ( 1 ) x n x ( 2 ) ⋯ x n x ( m ) ] ⋅ [ z ( 1 ) z ( 2 ) ⋮ z ( m ) ] dW=[dw_1,dw_2,……,dw_{n_x}]=\frac{1}{m}X·(dZ)^T=\frac{1}{m}\left[

x1(1)x1(2)x1(m)x2(1)x2(2)x2(m)xnx(1)xnx(2)xnx(m)
\right]·\left[
z(1)z(2)z(m)
\right] dW=[dw1,dw2,……dwnx]=m1X(dZ)T=m1 x1(1)x2(1)xnx(1)x1(2)x2(2)xnx(2)x1(m)x2(m)xnx(m) z(1)z(2)z(m)

d b = ∂ J ( w , b ) ∂ b = 1 m ∑ i = 1 m ( a ( i ) − y ( i ) ) = 1 m ∑ i = 1 m d z ( i ) d b =\frac{\partial J(w,b)}{\partial b}=\frac{1}{m} \sum_{i=1}^{m}\left(a^{(i)}-y^{(i)}\right)=\frac{1}{m} \sum_{i=1}^{m}dz^{(i)} db=bJ(w,b)=m1i=1m(a(i)y(i))=m1i=1mdz(i)

综上,整个逻辑回归的python程序为:

Z = np.dot(w.T,X) + b
A = sigmoid(Z)
dZ = A-Y
dw = 1/m*np.dot(X,dZ.T)
db = 1/m*np.sum(dZ)

w = w - alpha*dw
b = b - alpha*db
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

2.15 python中的Broadcasting

两张图足以解释Broadcasting:
图1:
在这里插入图片描述
图2:
在这里插入图片描述

2.16 关于python numpy向量的说明

a=np.random.randn(5)
  • 1

  该语句生成5个高斯随机变量,它的shape为(5,),它既不是行向量也不是列向量,这在python中被称为秩为1的数组,这导致一些不直观的效果,例如a的转置还是a本身。
  因此要定义行向量或者列向量,选择使用以下语句:

a=np.random.randn(51)
a=np.random.randn(1,5)
  • 1
  • 2

  除此之外,我们还可以使用assert语句对向量或数组的维度进行判断,例如:

assert(a.shape == (5,1))
  • 1

  assert会对内嵌语句进行判断,即判断a的维度是不是(5,1)的。如果不是,则程序在此处停止。
  另外,还可以使用reshape函数对数组设定所需的维度:

a.reshape((5,1))
  • 1

Summary

  首先,介绍了二分类问题,以图片为例,将多维输入x转化为特征向量,输出y只有{0,1}两个离散值。接着,我们介绍了逻辑回归及其对应的损失函数和代价函数。然后,介绍了梯度下降算法,并使用计算图的方式来讲述神经网络的正向传播和反向传播两个过程。接下来,在逻辑回归中使用梯度下降算法,总结出最优化参数w和b的算法流程。
  在深度学习程序中,使用向量化和矩阵运算的方法能够大大提高运行速度,节省时间。以逻辑回归为例,我们将其算法流程包括梯度下降转换为向量化的形式。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/78026
推荐阅读
相关标签
  

闽ICP备14008679号