神经网络的编程基础(Basics of Neural Network programming)
作者:互联网
一、 二分类(Binary Classification)
在神经网络中,如何处理训练集。在这里将使用逻辑回归(logistic regression)来传达这些想法,以使大家能够更加容易地理解这些概念。即使你之前了解过逻辑回归,我认为这里还是有些新的、有趣的东西等着你去发现和了解,所以现在开始进入正题。
逻辑回归是一个用于二分类(binary classification)的算法。首先我们从一个问题开始说起,这里有一个二分类问题的例子,假如你有一张图片作为输入,比如这只猫,如果识别这张图片为猫,则输出标签1作为结果;如果识别出不是猫,那么输出标签0作为结果。现在我们可以用字母来 表示输出的结果标签,所以在二分类问题中,我们的目标就是习得一个分类器,它以图片的特征向量作为输入,然后预测输出结果为1还是0,也就是预测图片中是否有猫。
符号定义 :
x
:
x:
x: 表示一个
n
x
n_{x}
nx 维数据, 为输入数据, 维度为
(
n
x
,
1
)
;
\left(n_{x}, 1\right) ;
(nx,1);
y
:
y:
y: 表示输出结果, 取值为 (0,1)
;
;
;
(
x
(
i
)
,
y
(
i
)
)
:
\left(x^{(i)}, y^{(i)}\right):
(x(i),y(i)): 表示第i组数据, 可能是训练数据, 也可能是测试数据, 此处默认为训练数据;
X
=
[
x
(
1
)
,
x
(
2
)
,
…
,
x
(
m
)
]
:
X=\left[x^{(1)}, x^{(2)}, \ldots, x^{(m)}\right]:
X=[x(1),x(2),…,x(m)]: 表示所有的训练数据集的输入值, 放在一个
n
x
×
m
n_{x} \times m
nx×m 的矩阵中, 其中
m
m
m 表示样本数目;
Y
=
[
y
(
1
)
,
y
(
2
)
,
…
,
y
(
m
)
]
:
Y=\left[y^{(1)}, y^{(2)}, \ldots, y^{(m)}\right]:
Y=[y(1),y(2),…,y(m)]: 对应表示所有训练数据集的输出值, 维度为
1
×
m
∘
1 \times m_{\circ}
1×m∘
用一对
(
x
,
y
)
(x, y)
(x,y) 来表示一个单独的样本,
x
x
x 代表
n
x
n_{x}
nx 维的特征向量,
y
y
y 表示标签(输出结果)只能为0或1。 而训练集将由
m
m
m 个训练样本组成, 其中
(
x
(
1
)
,
y
(
1
)
)
\left(x^{(1)}, y^{(1)}\right)
(x(1),y(1)) 表示第一个样本的输入和输出,
(
x
(
2
)
,
y
(
2
)
)
\left(x^{(2)}, y^{(2)}\right)
(x(2),y(2)) 表示第二个样本的输入和输出, 直 到最后一个样本
(
x
(
m
)
,
y
(
m
)
)
,
\left(x^{(m)}, y^{(m)}\right),
(x(m),y(m)), 然后所有的这些一起表示整个训练集。有时候为了强调这是训练样本的个数, 会写 作
M
train
,
M_{\text {train }},
Mtrain , 当涉及到测试集的时候, 我们会使用
M
test
M_{\text {test }}
Mtest 来表示测试集的样本数。
二、逻辑回归(Logistic Regression)
1.逻辑回归的Hypothesis Function(假设函数)
重温逻辑回归学习算法,该算法适用于二分类问题,本节将主要介绍逻辑回归的Hypothesis Function(假设函数)
对于二元分类问题来讲,给定一个输入特征向量
X
,
X,
X, 它可能对应一张图片,你想识别这张图片识别看它是否是一只 猫或者不是一只猫的图片,你想要一个算法能够输出预测,你只能称之为
y
^
,
\hat{y},
y^, 也就是你对实际值
y
y
y 的估计。更正式 地来说, 你想让
y
^
\hat{y}
y^ 表示
y
y
y 等于1的一种可能性或者是机会, 前提条件是给定了输入特征
X
∘
X_{\circ}
X∘ 换句话来说, 如果
X
X
X 是 我们在上个视频看到的图片,你想让
y
^
\hat{y}
y^ 来告诉你这是一只猫的图片的机率有多大。在之前的视频中所说的,
X
X
X 是 一个
n
x
n_{x}
nx 维的向量(相当于有
n
x
n_{x}
nx 个特征的特征向量
)
)
) 。我们用
w
w
w 来表示逻辑回归的参数, 这也是一个
n
x
n_{x}
nx 维向量 (因 为
w
w
w 实际上是特征权重, 维度与特征向量相同
)
,
) ,
), 参数里面还有b,这是一个实数 (表示偏差) 。所以给出输入x以 及参数
w
w
w 和b之后,我们怎样产生输出预测值
y
^
,
\hat{y},
y^, 一件你可以尝试却不可行的事是让
y
^
=
w
T
x
+
b
∘
\hat{y}=w^{T} x+b_{\circ}
y^=wTx+b∘
这时候我们得到的是一个关于输入x的线性函数, 实际上这是你在做线性回归时所用到的, 但是这对于二元分类问决的问题, 因为
w
T
x
+
b
w^{T} x+b
wTx+b 可能比1要大得多,或者其至为一个负值。对于你想要的在0和1之间的概率来说它是没有 意义的, 因此在逻辑回归中,我们的输出应该是畴于由上面得到的线性函数式子作为自变量的sigmoid函数中, 将线性函数转换为非线性函数。
2.sigmoid函数的公式
关于sigmoid函数的公式是这样的,
σ
(
z
)
=
1
1
+
e
8
\sigma(z)=\frac{1}{1+e^{8}}
σ(z)=1+e81,在这里
z
z
z 是一个实数, 这里要说明一些要注意的事情,如果
z
z
z 非 常大那么
e
−
z
e^{-z}
e−z 将会接近于0,关于z的sigmoid函数将会近似等于1除以1加上某个非常接近于0的项, 因为e 的指数 如果是个绝对值很大的负数的话, 这项将会接近于0,所以如果
z
z
z 很大的话那么关于
z
z
z 的sigmoid函数会非常接近 1。相反地, 如果
z
z
z 非常小或者说是一个绝对值很大的负数,那么关于
e
−
z
e^{-z}
e−z 这项会变成一个很大的数, 你可以认为这 是1除以1加上一个非常非常大的数, 所以这个就接近于0。实际上你看到当z变成一个绝对值很大的负数,关于z的 sigmoid函数就会非常接近于0, 因此当你实现逻辑回归时,你的工作就是去让机器学习参数
w
w
w 以及b这样才使得
y
^
\hat{y}
y^ 成为对
y
=
1
y=1
y=1 这一情况的概率的一个很好的估计。
三,逻辑回归的代价函数(Logistic Regression Cost Function)
1.为什么需要代价函数
为了训练逻辑回归模型的参数参数w和参数b我们, 需要一个代价函数, 通过训练代价函数来得到参数 w和参数b。 先看一下逻辑回归的输出函数:
y
^
(
i
)
=
σ
(
w
T
x
(
i
)
+
b
)
,
where
σ
(
z
)
=
1
1
+
e
−
z
Given
{
(
x
(
1
)
,
y
(
1
)
)
,
…
,
(
x
(
m
)
,
y
(
m
)
)
}
,
want
y
^
(
i
)
≈
y
(
i
)
\begin{array}{l} \hat{y}^{(i)}=\sigma\left(w^{T} x^{(i)}+b\right), \text { where } \sigma(z)=\frac{1}{1+e^{-z}} \\ \text { Given }\left\{\left(x^{(1)}, y^{(1)}\right), \ldots,\left(x^{(m)}, y^{(m)}\right)\right\}, \text { want } \hat{y}^{(i)} \approx y^{(i)} \end{array}
y^(i)=σ(wTx(i)+b), where σ(z)=1+e−z1 Given {(x(1),y(1)),…,(x(m),y(m))}, want y^(i)≈y(i)
为了让模型通过学习调整参数, 你需要给予一个
m
m
m 样本的训练集, 这会让你在训练集上找到参数
w
w
w 和参数
b
,
b,
b, 来得 到你的输出。
对训练集的预测值, 我们将它写成子, 我们更希望它会接近于训练集中的
y
y
y 值, 为了对上面的公式更详细的介绍, 我们需要说明上面的定义是对一个训练样本来说的, 这种形式也使用于每个训练样本, 我们使用这些带有圆括号的 上标来区分索引和样本, 训练样本
i
i
i 所对应的预测值是
y
(
i
)
y^{(i)}
y(i),是用训练样本的
w
T
x
(
i
)
+
b
w^{T} x^{(i)}+b
wTx(i)+b 然后通过sigmoid函数来得 到, 也可以把
z
z
z 定义为
z
(
i
)
=
w
T
x
(
i
)
+
b
z^{(i)}=w^{T} x^{(i)}+b
z(i)=wTx(i)+b,我们将使用这个符号
(
i
)
(i)
(i) 注解, 上标
(
i
)
(i)
(i) 来指明数据表示
x
x
x 或者
y
y
y 或者
z
z
z 或者其 他数据的第i个训练样本, 这就是上标
(
i
)
(i)
(i) 的含义。
2.损失函数
损失函数又叫做误差函数,用来衡量算法的运行情况, Loss function: L ( y ^ , y ) L(\hat{y}, y) L(y^,y).我们通过这个 L L L 称为的损失函数,来衡量预测输出值和实际值有多接近。一般我们用预测值和实际值的平方差或者 它们平方差的一半,但是通常在逻辑回归中我们不这么做, 因为当我们在学习逻辑回归参数的时候, 会发现我们的 优化目标不是凸优化, 只能找到多个局部最优值,梯度下降法很可能找不到全局最优值, 虽然平方差是一个不错的 损失函数, 但是我们在逻辑回归模型中会定义另外一个损失函数。
- 我们在逻辑回归中用到的损失函数是:L ( y ^ , y ) = − y log ( y ^ ) − ( 1 − y ) log ( 1 − y ^ ) (\hat{y}, y)=-y \log (\hat{y})-(1-y) \log (1-\hat{y}) (y^,y)=−ylog(y^)−(1−y)log(1−y^)为什么要用这个函数作为逻辑损失函数?当我们使用平方误差作为损失函数的时候, 你会想要让这个误差尽可能地 小,对于这个逻辑回归损失函数,我们也想让它尽可能地小,为了更好地理解这个损失函数怎么起作用, 我们举两 个例子:值 [ 0 , 1 ] , [0,1], [0,1], 所以 y ^ \hat{y} y^ 会无限接近于1。当 y = 0 y=0 y=0 时损失函数 L = − log ( 1 − y ^ ) , L=-\log (1-\hat{y}), L=−log(1−y^), 如果想要损失函数 L L L 尽可能得小,那么鱼就要尽可能小, 因为sigmoid函 数取值 [ 0 , 1 ] , [0,1], [0,1], 所以子会无限接近于0。在这门课中有很多的函数效果和现在这个类似, 就是如果 y y y 等于1,我们就尽可能让令变大,如果 y y y 等于0,我们就尽 可能让 y ^ \hat{y} y^ 变小。 损失函数是在单个训练样本中定义的, 它衡量的是算法在单个训练样本中表现如何,为了衡量算和然后除以 m : 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 ) ) ) m: 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) m:J(w,b)=m1∑i=1mL(y^(i),y(i))=m1∑i=1m(−y(i)logy^(i)−(1−y(i))log(1−y^(i))) 损失函数只适用于像这样的单个训练样本,而代价函数是参数的总代价, 所以在训练逻辑回归模型时候,我们需要找到合适的 w w w 和b,来让代价函数 J J J 的总代价降到最低。 根据我们对逻辑回归算法的推导及对单个样本的损失函数的推导和针对 算法所选用参数的总代价函数的推导,结果表明逻辑回归可以看做是一个非常小的神经网络。
四.梯度下降法(Gradient Descent)
在你测试集上,通过最小化代价函数 (成本函数)
J
(
w
,
b
)
J(w, b)
J(w,b) 来训练的参数
w
w
w 和
b
b
b,如图,在第二行给出和之前一样的逻辑回归算法的代价函数(成本函数).
在这个图中,横轴表示你的空间参数
w
w
w 和b,在实践中,
w
w
w 可以是更高的维度, 但是为了更好地绘图,我们定义
w
w
w 和
b
,
b,
b, 都是单一实数, 代价函数 (成本函数)
J
(
w
,
b
)
J(w, b)
J(w,b) 是在水平轴
w
w
w 和b上的曲面, 因此曲面的高度就是
J
(
w
,
b
)
J(w, b)
J(w,b) 在某一 点的函数值。我们所做的就是找到使得代价函数 (成本函数)
J
(
w
,
b
)
J(w, b)
J(w,b) 函数值是最小值, 对应的参数
w
w
w 和b。
如图,代价函数(成本函数)
J
(
w
,
b
)
J(w, b)
J(w,b) 是一个凸函数(convex function), 像一个大碗一样。朝最陡的下坡方向走一步,不断地迭代,我们朝最陡的下坡方向走一步,如图,走到了如图中第二个小红点处,直到走到全局最优解或者接近全局最优解的地方,通过以上的三个步骤我们可以找到全局最优解, 也就是代价函数 (成本函数)
J
(
w
,
b
)
J(w, b)
J(w,b) 这个凸函数的最小值点。
1.梯度下降法的细节化说明(仅有一个参数)
假定代价函数(成本函数)
J
(
w
)
J(w)
J(w) 只有一个参数
w
w
w, 即用一维曲线代替多维曲线, 这样可以更好画出图像。
迭代就是不断重复做如图的公式:
:=表示更新参数,
a
a
a 表示学习率 (learning rate) , 用来控制步长 (step) , 即向下走一步的长度
d
J
(
w
)
d
w
\frac{d J(w)}{d w}
dwdJ(w) 就是函数
J
(
w
)
J(w)
J(w) 对
w
w
w 求早 (derivative),在代码中我们会使用
d
w
d w
dw 表示这个结果。
对于导数更加形象化的理解就是斜率 (slope) , 如图该点的导数就是这个点相切于
J
(
w
)
J(w)
J(w) 的小三角形的高除宽。 假设我们以如图点为初始化点, 该点处的斜率的符号是正的, 即
d
J
(
w
)
d
w
>
0
,
\frac{d J(w)}{d w}>0,
dwdJ(w)>0, 所以接下来会向左走一步。整个梯度下降法的迭代过程就是不断地向左走,直至逼近最小值点。小于0则是相反的过程。
2.梯度下降法的细节化说明(两个参数)
逻辑回归的代价函数(成本函数)
J
(
w
,
b
)
J(w, b)
J(w,b) 是含有两个参数的。
w
:
=
w
−
α
∂
J
(
w
,
b
)
∂
w
w:=w-\alpha \frac{\partial J(w, b)}{\partial w}
w:=w−α∂w∂J(w,b)
b
:
=
b
−
α
∂
J
(
w
,
b
)
∂
b
b:=b-\alpha \frac{\partial J(w, b)}{\partial b}
b:=b−α∂b∂J(w,b)
∂
\partial
∂ 表示求偏导符号, 可以读作round,
∂
J
(
w
,
b
)
∂
w
\frac{\partial J(w, b)}{\partial w}
∂w∂J(w,b) 就是函数
J
(
w
,
b
)
J(w, b)
J(w,b) 对
w
w
w 求偏导, 在代码中我们会使用
d
w
d w
dw 表示这个结果,
∂
J
(
w
,
b
)
∂
b
\quad \frac{\partial J(w, b)}{\partial b}
∂b∂J(w,b) 就是函数
J
(
w
,
b
)
J(w, b)
J(w,b) 对
b
b
b 求偏导,在代码中我们会使用
d
b
d b
db 表示这个结果, 小 写字母
d
d
d 用在求导数(derivative
)
)
) ,即函数只有一个参数, 偏导数符号
∂
\partial
∂ 用在求偏导(partial derivative), 即函数含有两个以上的参数。
五.导数
- 第一点, 导数就是斜率, 而函数的斜率, 在不同的点是不同的。在第一个例子中 f ( a ) = 3 a , f(a)=3 a, f(a)=3a, 这是一条直线,在任 何点它的斜率都是相同的, 均为3。但是对于函数 f ( a ) = a 2 , f(a)=\mathrm{a}^{2}, f(a)=a2, 或者 f ( a ) = log a , f(a)=\log a, f(a)=loga, 它们的斜率是变化的, 所以它 们的导数或者斜率,在曲线上不同的点处是不同的。
- 第二点, 如果你想知道一个函数的导数, 你可参考你的微积分课本或者维基百科, 然后你应该就能找到这些函数的 导数公式。
六.计算图(Computation Graph)
一个神经网络的计算,都是按照前向或反向传播过程组织的。首先我们计算出一个新的网络的输出(前向过程),紧接着进行一个反向传输操作。后者我们用来计算出对应的梯度或导数。计算图解释了为什么我们用这种方式组织这些计算过程。
从这个小例子中我们可以看出,通过一个从左向右 的过程, 你可以计算出J的值。为了计算导数, 从右到左(红色箭头, 和蓝色箭头的过程相反) 的过程是用于计算 导数最自然的方式。概括一下:计算图组织计算的形式是用蓝色箭头从左到右的计算, 让我们看看下一个视频中 如何进行反向红色箭头(也就是从右到左)的导数计算。
七.使用计算图求导数(Derivatives with a Computation Graph)
前面我们看了一个例子使用流程计算图来计算函数
。
。
。 现在我们清理一下流程图的描述,看看你如何 利用它计算出函数J的导数。下面用到的公式:
d
J
d
u
=
d
J
d
v
d
v
d
u
,
d
J
d
b
=
d
J
d
u
d
u
d
b
,
d
J
d
a
=
d
J
d
u
d
u
d
a
\frac{d J}{d u}=\frac{d J}{d v} \frac{d v}{d u}, \quad \frac{d J}{d b}=\frac{d J}{d u} \frac{d u}{d b}, \quad \frac{d J}{d a}=\frac{d J}{d u} \frac{d u}{d a}
dudJ=dvdJdudv,dbdJ=dudJdbdu,dadJ=dudJdadu
这是一个流程图:
八.逻辑回归中的梯度下降(Logistic Regression Gradient Descent)
讨论怎样通过计算偏导数来实现逻辑回归的梯度下降算法。它的关键点是几个重要公式, 其作用是用来实现逻辑回归中梯度下降算法。但是在本节中,我将使用计算图对梯度下降算法进行计算。我必须要承认的是, 使用计算图来计算逻辑回归的梯度下降算法有点大材小用了。但是, 我认为以这个例子作为开始来讲解,可以使你更好的理解背后的思想。从而在讨论神经网络时,你可以更深刻而全面地理解神经网络。接下来让我们开始学习逻辑回归的梯度下降算法。
- 假设样本只有两个特征 x 1 x_{1} x1 和 x 2 , x_{2}, x2, 为了计算 z , z, z, 我们需要输入参数 w 1 , w 2 w_{1}, w_{2} w1,w2 和 b , b, b, 除此之外还有特征值 x 1 x_{1} x1 和 x 2 x_{2} x2 。因此 z z z 的计算公式为: z = w 1 x 1 + w 2 x 2 + b z=w_{1} x_{1}+w_{2} x_{2}+b z=w1x1+w2x2+b 回想一下逻辑回归的公式定义如下: y ^ = a = σ ( z ) \hat{y}=a=\sigma(z) y^=a=σ(z) 其中 z = w T x + b z=w^{T} x+b z=wTx+b σ ( z ) = 1 1 + e z \sigma(z)=\frac{1}{1+e^{z}} σ(z)=1+ez1
- 损失函数: L ( y ^ ( i ) , y ( i ) ) = − y ( i ) log y ^ ( i ) − ( 1 − y ( i ) ) log ( 1 − y ^ ( i ) ) L\left(\hat{y}^{(i)}, y^{(i)}\right)=-y^{(i)} \log \hat{y}^{(i)}-\left(1-y^{(i)}\right) \log \left(1-\hat{y}^{(i)}\right) L(y^(i),y(i))=−y(i)logy^(i)−(1−y(i))log(1−y^(i))
- 代价函数:
J
(
w
,
b
)
=
1
m
∑
i
m
L
(
y
^
(
i
)
,
y
(
i
)
)
J(w, b)=\frac{1}{m} \sum_{i}^{m} L\left(\hat{y}^{(i)}, y^{(i)}\right)
J(w,b)=m1∑imL(y^(i),y(i))
假设现在只考虑单个样本的情况,单个样本的代价函数定义如下: L ( a , y ) = − ( y log ( a ) + ( 1 − y ) log ( 1 − a ) ) L(a, y)=-(y \log (a)+(1-y) \log (1-a)) L(a,y)=−(ylog(a)+(1−y)log(1−a)) 其中 a a a 是逻辑回归的输出, y y y 是样本的标签值。
现在让我们画出表示 这个计算的计算图。 这里先复习下梯度下降法, w w w 和b的修正量可以表达如下:
w : = w − a ∂ J ( w , b ) ∂ w , b : = b − a ∂ J ( w , b ) ∂ b w:=w-a \frac{\partial J(w, b)}{\partial w}, b:=b-a \frac{\partial J(w, b)}{\partial b} w:=w−a∂w∂J(w,b),b:=b−a∂b∂J(w,b)
进行最后一步反向推时,也就是计算 w w w 和 b b b 变化对代价函数 L L L 的影响,特别地, 可以用: -
d
w
1
=
1
m
∑
i
m
x
1
(
i
)
(
a
(
i
)
−
y
(
i
)
)
d
w
2
=
1
m
∑
i
m
x
2
(
i
)
(
a
(
i
)
−
y
(
i
)
)
d
b
=
1
m
∑
i
m
(
a
(
i
)
−
y
(
i
)
)
d w_{1}=\frac{1}{m} \sum_{i}^{m} x_{1}^{(i)}\left(a^{(i)}-y^{(i)}\right) d w_{2}=\frac{1}{m} \sum_{i}^{m} x_{2}^{(i)}\left(a^{(i)}-y^{(i)}\right) d b=\frac{1}{m} \sum_{i}^{m}\left(a^{(i)}-y^{(i)}\right)
dw1=m1∑imx1(i)(a(i)−y(i))dw2=m1∑imx2(i)(a(i)−y(i))db=m1∑im(a(i)−y(i))
视频中,表示 ∂ L ∂ w 1 = x 1 ⋅ d z , d w 2 \frac{\partial L}{\partial w_{1}}=x_{1} \cdot d z, \quad d w_{2} ∂w1∂L=x1⋅dz,dw2 表示 ∂ L ∂ w 2 = x 2 ⋅ d z , d b = d z ∘ \frac{\partial L}{\partial w_{2}}=x_{2} \cdot d z, \quad d b=d z_{\circ} \quad ∂w2∂L=x2⋅dz,db=dz∘ - 因此, 关于单个样本的梯度下降算法, 你所需要做的就是如下的事情:使用公式 d z = ( a − y ) d z=(a-y) dz=(a−y) 计算 d z , d z, dz, 使用 d w 1 = x 1 ⋅ d z d w_{1}=x_{1} \cdot d z dw1=x1⋅dz 计算 d w 1 , d w 2 = x 2 ⋅ d z d w_{1}, \quad d w_{2}=x_{2} \cdot d z dw1,dw2=x2⋅dz 计算 d w 2 , d b = d z d w_{2}, \quad d b=d z dw2,db=dz 来计算 d b , d b, \quad db, 然后: 更新 w 1 = w 1 − a d w 1 , w_{1}=w_{1}-a d w_{1}, \quad w1=w1−adw1, 更新 w 2 = w 2 − a d w 2 , w_{2}=w_{2}-a d w_{2}, \quad w2=w2−adw2, 更新 b = b − α d b 。 b=b-\alpha d b_{\text {。 }} b=b−αdb。 这就是关于单个样本实例的梯度下降算法中参数更新一次的步骤。
九.m 个样本的梯度下降(Gradient Descent on m Examples)
你已经看到如何计算导数,以及应用梯度下降在逻辑回归的一个训练样本上。现在我们想要把它应用在M个训练样本上。 首先, 让我们时刻记住有关于损失函数
J
(
w
,
b
)
J(w, b)
J(w,b) 的定义。
J
(
w
,
b
)
=
1
m
∑
i
=
1
m
L
(
a
(
i
)
,
y
(
i
)
)
J(w, b)=\frac{1}{m} \sum_{i=1}^{m} L\left(a^{(i)}, y^{(i)}\right)
J(w,b)=m1i=1∑mL(a(i),y(i))
当你的算法输出关于样本
y
y
y 的
a
(
i
)
,
a
(
i
)
a^{(i)}, a^{(i)}
a(i),a(i) 是训练样本的预测值, 即:
σ
(
z
(
i
)
)
=
σ
(
w
T
x
(
i
)
+
b
)
\sigma\left(z^{(i)}\right)=\sigma\left(w^{T} x^{(i)}+b\right)
σ(z(i))=σ(wTx(i)+b) 。 所以我们在前面的幻 灯中展示的是对于任意单个训练样本,如何计算微分当你只有一个训练样本。因此
d
w
1
,
d
w
2
d w_{1}, d w_{2}
dw1,dw2 和
d
b
d b
db 添上上标i表示 你求得的相应的值。如果你面对的是我们在之前的幻灯中演示的那种情况,但只使用了一个训练样本
(
x
(
i
)
,
y
(
i
)
)
\left(x^{(i)}, y^{(i)}\right)
(x(i),y(i)) 。 现在你知道带有求和的全局代价函数,实际上是1到m项各个损失的平均。所以它表明全局代价函数对
w
1
w_{1}
w1 的微 分,对
w
1
w_{1}
w1 的微分也同样是各项损失对
w
1
w_{1}
w1 微分的平均。
十. 向量化(Vectorization)
向量化是非常基础的去除代码中for循环的艺术,在深度学习安全领域、深度学习实践中,你会经常发现自己训练你的代码可能花费很长时间去运行,你将要等待非常长的时间去得到结果。所以在深度学习领域, 运行向量化是一 个关键的技巧, 让我们举个栗子说明什么是向量化。
在逻辑回归中你需要去计算
z
=
w
T
x
+
b
,
w
、
x
z=w^{T} x+b, \quad w 、 x
z=wTx+b,w、x 都是列向量。如果你有很多的特征那么就会有一个非常大的向 量, 所以
w
∈
R
n
∗
,
x
∈
R
n
∗
,
w \in \mathbb{R}^{n_{*}}, x \in \mathbb{R}^{n_{*}},
w∈Rn∗,x∈Rn∗, 所以如果你想使用非向量化方法去计算
w
T
x
,
w^{T} x,
wTx, 你需要用如下方式(python
)
)
)
xxxxxxxxxx
import numpy as np #导入numpy库
a = np.array([1,2,3,4]) #创建一个数据a
print(a)
# [1 2 3 4]
import time #导入时间库
a = np.random.rand(1000000)
b = np.random.rand(1000000) #通过round随机得到两个一百万维度的数组
tic = time.time() #现在测量一下当前时间
#向量化的版本
c = np.dot(a,b)
toc = time.time()
print(“Vectorized version:” + 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)
print(“For loop:” + str(1000*(toc-tic)) + “ms”)#打印for循环的版本的时间
在两个方法中, 向量化和非向量化计算了相同的值, 如你所见, 向量化版本花费了1.5毫秒, 非向量化版本的for循 环花费了大约几乎500毫秒, 非向量化版本多花费了300倍时间。所以在这个例子中,仅仅是向量化你的代码, 就 会运行300倍快。这意味着如果向量化方法需要花费一分钟去运行的数据, for循环将会花费5个小时去运行。一句话总结, 以上都是再说和for循环相比, 向量化可以快速得到结果。
十一.向量化的更多例子(More Examples of Vectorization)
经验提醒我, 当我们在写神经网络程序时,或者在写逻辑(logistic)回归, 或者其他神经网络模型时, 应该避免写 循环(loop)语句。盟然有时写循环(Ioop)是不可避免的, 但是我们可以使用比如numpy的内置函数或者其他办法 去计算。当你这样使用后,程序效率总是快于循环(Ioop)。
让我们看一个例子。如果你想计算向量
u
=
A
v
,
u=A v,
u=Av, 这时矩阵乘法定义为,矩阵乘法的定义就是:
u
i
=
∑
j
A
i
j
v
i
,
u_{i}=\sum_{j} A_{\mathrm{ij}} v_{i},
ui=∑jAijvi, 这取决于你怎么定义
u
i
u_{i}
ui 值。同样使用非向量化实现,
u
=
n
p
.
u=n p .
u=np. zeros
(
n
,
1
)
,
(n, 1),
(n,1), 并且通过两层循环
for
(
i
)
:
for
(
j
)
:
,
\operatorname{for}(i): \operatorname{for}(j):,
for(i):for(j):, 得到
u
[
i
]
=
u
[
i
]
+
A
[
i
]
[
j
]
∗
v
[
j
]
u[i]=u[i]+A[i][j] * v[j]
u[i]=u[i]+A[i][j]∗v[j] 。现在就有了
i
i
i 和
j
j
j 的两层循环,这就是非向量化。向量化方 式就可以用
u
=
n
p
.
dot
(
A
,
v
)
,
u=n p . \operatorname{dot}(A, v),
u=np.dot(A,v), 右边这种向量化实现方式, 消除了两层循环使得代码运行速度更快。
下面通过另一个例子继续了解向量化。如果你已经有一个向量v,并且想要对向量v的每个元素做指数操作,得到 向量u等于e的
v
1
,
e
v_{1}, e
v1,e 的
v
2
v_{2}
v2, 一直到
e
e
e 的
v
n
v_{n}
vn 次方。这里是非向量化的实现方式, 首先你初始化了向量
u
=
n
p
.
u=n p .
u=np. zeros
(
n
,
1
)
,
(n, 1),
(n,1), 并且通过循环依次计算每个元素。但事实证明可以通过python的numpy内置函数,帮助 你计算这样的单个函数。所以我会引入 import numpy as np,执行
u
=
n
p
.
exp
(
v
)
u=n p . \exp (v)
u=np.exp(v) 命令。注意到, 在之前有循 环的代码中,这里仅用了一行代码, 向量v作为输入,
u
u
u 作为输出。你已经知道为什么需要循环,并且通过右边代 码实现,效率会明显的快于循环方式。
事实上, numpy库有很多向量函数。比如
u
=
u=
u= np.
log
\log
log 是计算对数函数(log)、
\quad
np.abs () 是计算数据的绝对值. np.maximum() 计算元素
y
y
y 中的最大值, 你也可以 np.maximum
(
v
,
0
)
(\mathrm{v}, 0)
(v,0) 、
v
∗
∗
2
v * * 2
v∗∗2 代表获得元素
y
y
y 每个值得平方、
1
v
\frac{1}{v}
v1 获取元素
y
y
y 的倒数等等。所以当你想写循环时候, 检查numpy是否存在类似的内置函数, 从而避免使用循环 (loop)方式。
接下来将进一步的讲解逻辑回归,将会看到更好的监督学习结果。在训练中不需要使用任何 for 循环,你也可以写出代码去运行整个训练集。
十二.向量化逻辑回归(Vectorizing Logistic Regression)
首先我们回顾一下逻辑回归的前向传播步骤。所以, 如果你有
m
m
m 个训练样本,然后对第一个样本 进行预测,你需要这样计算。计算
z
,
z,
z, 我正在使用这个熟悉的公式
z
(
1
)
=
w
T
x
(
1
)
+
b
z^{(1)}=w^{T} x^{(1)}+b
z(1)=wTx(1)+b 。然后计算激活函数
a
(
1
)
=
σ
(
z
(
1
)
)
,
a^{(1)}=\sigma\left(z^{(1)}\right),
a(1)=σ(z(1)), 计算第一个样本的预测值
y
∘
y_{\circ}
y∘
然后对第二个样本进行预测, 你需要计算
z
(
2
)
=
w
T
x
(
2
)
+
b
,
a
(
2
)
=
σ
(
z
(
2
)
)
z^{(2)}=w^{T} x^{(2)}+b, a^{(2)}=\sigma\left(z^{(2)}\right)
z(2)=wTx(2)+b,a(2)=σ(z(2)) 。然后对第三个样本进行预测, 你 需要计算
z
(
3
)
=
w
T
x
(
3
)
+
b
,
a
(
3
)
=
σ
(
z
(
3
)
)
,
z^{(3)}=w^{T} x^{(3)}+b, a^{(3)}=\sigma\left(z^{(3)}\right),
z(3)=wTx(3)+b,a(3)=σ(z(3)), 依次类推。如果你有
m
m
m 个训练样本, 你可能需要这样做
m
m
m 次, 可以看出, 为了完成前向传播步骤, 即对我们的
m
m
m 个样本都计算出预测值。有一个办法可以并且不需要任何一个 明确的for循环。
让我们来看一下你该怎样做。首先, 回忆一下我们曾经定义了一个矩阵
X
X
X 作为你的训练输入,(如下图中蓝色
X
X
X )像这样在不同的列中堆积在一起。这是一个
n
x
n_{x}
nx 行
m
m
m 列的矩阵。我现在将它写为Python numpy的形式
(
n
x
,
m
)
,
\left(n_{x}, m\right),
(nx,m), 这只是表示
X
X
X 是一个
n
x
n_{x}
nx 乘 以
m
m
m 的矩阵
R
n
⋆
×
m
R^{n_{\star} \times m}
Rn⋆×m.
总结一下,在这张幻灯片中我们已经看到, 不需要for循环,利用
m
m
m 个训练样本一次性计算出小写
z
z
z 和小写
a
,
a,
a, 用 一行代码即可完成。
z
=
n
p
⋅
dot
(
w
⋅
T
,
x
)
+
b
z=n p \cdot \operatorname{dot}(w \cdot T, x)+b
z=np⋅dot(w⋅T,x)+b 这一行代码:
A
=
[
a
(
1
)
a
(
2
)
…
a
(
m
)
]
=
σ
(
Z
)
,
A=\left[a^{(1)} a^{(2)} \ldots a^{(m)}\right]=\sigma(Z),
A=[a(1)a(2)…a(m)]=σ(Z), 通过恰当地运用
σ
\sigma
σ 一次性计算所有
a
∘
a_{\circ}
a∘ 这就是在同一时间内你如何 完成一个所有
m
m
m 个训练样本的前向传播向量化计算。概括一下,你刚刚看到如何利用向量化在同一时间内高效地计算所有的激活函数的所有
a
a
a 值。接下来,可以证明, 你也可以利用向量化高效地计算反向传播并以此来计算梯度。让我们在下一个视频中看该如何实现。
十三.向量化 logistic 回归的梯度输出(Vectorizing Logistic Regression’s Gradient)
注:本节中大写字母代表向量,小写字母代表元素
首先我们来看
d
b
,
d b,
db, 不难发现
d
b
=
1
m
∑
i
=
1
m
d
z
(
i
)
,
d b=\frac{1}{m} \sum_{i=1}^{m} d z^{(i)}, \quad
db=m1∑i=1mdz(i), 之前的讲解中,我们知道所有的
d
z
i
d z^{i}
dzi 已经组成一个行向量
d
Z
d Z
dZ 了, 所以在Python中,我们很容易地想到
d
b
=
1
m
∗
n
p
.
sum
(
d
Z
)
;
d b=\frac{1}{m} * n p . \operatorname{sum}(d Z) ;
db=m1∗np.sum(dZ); 接下来看
d
w
,
d w,
dw, 我们先写出它的公式
d
w
=
1
m
∗
X
∗
d
z
T
d w=\frac{1}{m} * X * d z^{T}
dw=m1∗X∗dzT 其中,
X
X
X 是一个行向量。因此展开启
d
w
=
1
m
∗
(
x
(
1
)
d
z
(
1
)
+
x
(
2
)
d
z
(
2
)
+
…
+
x
m
d
z
m
)
d w=\frac{1}{m} *\left(x^{(1)} d z^{(1)}+x^{(2)} d z^{(2)}+\ldots+x^{m} d z^{m}\right)
dw=m1∗(x(1)dz(1)+x(2)dz(2)+…+xmdzm) 。因此我们可以仅用两行代码进行计算:
d
b
=
1
m
∗
n
p
.
sum
(
d
Z
)
,
d
w
=
1
m
∗
X
∗
d
z
T
d b=\frac{1}{m} * n p . \operatorname{sum}(d Z), \quad d w=\frac{1}{m} * X * d z^{T}
db=m1∗np.sum(dZ),dw=m1∗X∗dzT 。这样,我们就避免了在训练集上使用for循环。
现在,让我们回顾一下,看看我们之前怎么实现的逻辑回归,可以发现,没有向量化是非常低效的,如下图所示代码:
我们的目标是不使用for循环,而是向量,我们可以这么做:
Z
=
w
T
X
+
b
=
n
p
.
d
o
t
(
w
.
T
,
X
)
+
b
A
=
σ
(
Z
)
d
Z
=
A
−
Y
\begin{array}{l} Z=w^{T} X+b=n p . d o t(w . T, X)+b \\ A=\sigma(Z) \\ d Z=A-Y \end{array}
Z=wTX+b=np.dot(w.T,X)+bA=σ(Z)dZ=A−Y
d
w
=
1
m
∗
X
∗
d
z
T
d w=\frac{1}{m} * X * d z^{T}
dw=m1∗X∗dzT
d
b
=
1
m
∗
n
p
.
sum
(
d
Z
)
d b=\frac{1}{m} * n p . \operatorname{sum}(d Z)
db=m1∗np.sum(dZ)
w
:
=
w
−
a
∗
d
w
w:=w-a * d w
w:=w−a∗dw
b
:
=
b
−
a
∗
d
b
b:=b-a * d b
b:=b−a∗db
现在我们利用前五个公式完成了前向和启向传播, 也实现了对所有训练样本进行预测和求导,再利用后两个公式, 梯度下降更新参数。我们的目的是不使用for循环, 所以我们就通过一次迭代实现一次梯度下降, 但如果你希望多 次迭代进行梯度下降,那么仍然需要for循环,放在最外层。不过我们还是觉得一次迭代就进行一次梯度下降, 避免使用任何循环比较舒服一些。最后,我们得到了一个高度向量化的、非常高效的逻辑回归的梯度下降算法。
参考链接:
机器学习笔记:http://www.ai-start.com/ml2014/
深度学习笔记:http://www.ai-start.com/dl2017/
标签:Basics,frac,函数,Neural,Network,right,log,计算,left 来源: https://blog.csdn.net/qq_33043295/article/details/112731757