【Nan‘s 吴恩达深度学习笔记】第一课 神经网络&逻辑回归
神经网络(Neural Networks)
提示
对于图像应用,我们经常在神经网络上使用卷积( Convolutional Neural Network),通常缩写为 CNN。
对于序列数据,例如音频,有一个时间组件,随着时间的推移,音频被播放出来,所以音频是最自然的表现。作为一维时间序列(两种英文说法 one-dimensional timeseries / temporal sequence).对于序列数据,经常使用 RNN,一种递归神经网络(Recurrent Neural Network),语言,英语和汉语字母表或单词都是逐个出现的,所以语言也是最自然的序列数据,因此更复杂的 RNNs 版本经常用于这些应用。
2.1 二分类(Binary Classification)
训练样本的个数,会写作
M
t
r
a
i
n
=
m
M_{train}=m
Mtrain=m,测试集的样本数
M
t
e
s
t
M_{test}
Mtest.
实现神经网络时,将训练集的输入值X 按照 列 堆叠起来,会让实现过程更加简单。
将标签y放在列中,会方便后续计算,训练集的输出值Y按照 行 堆叠起来。
Python代码实现:
X.shape=(n_x,m)
Y.shape=(1,m)
2.2 逻辑回归(Logistic Regression)
sigmoid 函数的公式,其中z为一个实数:
σ
(
z
)
=
1
1
+
e
−
z
σ(z) = \frac{1}{1+e^{-z}}
σ(z)=1+e−z1
当z非常大时,sigmoid函数会非常接近1;
当z非常小时,sigmoid函数会非常接近0;
因此当实现逻辑回归时,工作就是去让机器学习参数𝑤以及𝑏,这样才使得 y ^ \hat{y} y^成为对𝑦 = 1这一情况的概率的一个很好的估计。
y
^
\hat{y}
y^= 𝜎(
θ
T
θ^T
θT𝑥)的 sigmoid 函数:
有一个参数向量
θ
0
,
θ
1
,
θ
2
,
.
.
.
,
θ
n
x
θ_0, θ_1, θ_2,...,θ_{nx}
θ0,θ1,θ2,...,θnx
这样
θ
0
θ_0
θ0就充当了𝑏,而剩下的
θ
1
θ_1
θ1直到
θ
n
x
θ_{nx}
θnx充当了𝑤.
损失函数(Loss/Error Function)
损失函数又叫误差函数,用来衡量算法的运行情况(预测输出值和实际值有多接近)
L
o
s
s
F
u
n
c
t
i
o
n
:
L
(
y
^
,
y
)
.
Loss Function:L(\hat{y},y).
LossFunction:L(y^,y).
一般我们用预测值和实际值的平方差或者它们平方差的一半作为损失函数。
但在逻辑回归中我们不这么做,因为当我们在学习逻辑回归参数的时候,会发现我们的优化目标是非凸(non-convex)优化——只能找到多个局部最优值,梯度下降法很可能找不到全局最优值。
逻辑回归中用到的损失函数:
由于L描述的是真实值与预测值之间的差距,所以要使得L尽可能小!
如果𝑦等于 1,我们就尽可能让
y
^
\hat{y}
y^变大,如果𝑦等于 0,我们就尽可能让
y
^
\hat{y}
y^变小。
Cross Entropy Error Function(交叉熵损失函数):
学习过程:
交叉熵损失函数经常用于分类问题中,特别是在神经网络做分类问题时,也经常使用交叉熵作为损失函数。又由于交叉熵涉及到计算每个类别的概率,所以交叉熵几乎每次都和sigmoid(或softmax)函数一起出现。
函数性质:
凸函数,求导可得到全局最优值。
代价函数(Cost Function)
训练集的预测值写成
y
^
\hat{y}
y^,我们更希望它会接近于训练集中的𝑦值。
损失函数是在单个训练样本中定义的,它衡量的是算法在单个训练样本中表现如何。
为了衡量算法在全部训练样本上的表现如何,我们需要定义一个算法的代价函数,代价函数是参数的总代价。
逻辑回归的代价函数:
在训练逻辑回归模型时候,我们需要找到合适的𝑤和𝑏,来让代价函数 𝐽 的总代价降到最低。
梯度下降算法的应用
一般情况下,一次迭代就进行一次梯度下降。
关于单个样本:
应用链式法则!
d
w
1
=
∂
L
∂
w
1
=
∂
L
∂
z
∂
z
∂
w
1
=
d
z
⋅
x
1
d_{w_1}=\frac{∂L}{∂w_1}=\frac{∂L}{∂z}\frac{∂z}{∂w_1}=dz·x_1
dw1=∂w1∂L=∂z∂L∂w1∂z=dz⋅x1
d
w
2
=
∂
L
∂
w
2
=
∂
L
∂
z
∂
z
∂
w
2
=
d
z
⋅
x
2
d_{w_2}=\frac{∂L}{∂w_2}=\frac{∂L}{∂z}\frac{∂z}{∂w_2}=dz·x_2
dw2=∂w2∂L=∂z∂L∂w2∂z=dz⋅x2
d
b
=
∂
L
∂
b
=
∂
L
∂
z
∂
z
∂
b
=
d
z
⋅
1
d_{b}=\frac{∂L}{∂b}=\frac{∂L}{∂z}\frac{∂z}{∂b}=dz·1
db=∂b∂L=∂z∂L∂b∂z=dz⋅1
求导数和求偏导,区别可见下:
关于m个训练样本:
代价函数实际上是 1 到m项各个损失的平均。 所以它表
明全局代价函数对𝑤1的微分,对𝑤1的微分也同样是各项损失对𝑤1微分的平均。
J=0;dw1=0;dw2=0;db=0;
#对于m个样本的叠加 for循环(1) 遍历所有样本
for i = 1 to m
z(i) = wx(i)+b;
a(i) = sigmoid(z(i));
J += -[y(i)log(a(i))+(1-y(i)) log(1-a(i));
dz(i) = a(i)-y(i);
#for循环(2) 遍历所有特征xn
#显性for会使得代码低效,尽量不要用,可用 向量化vectorization解决!
dw1 += x1(i)dz(i);
dw2 += x2(i)dz(i);
db += dz(i);
#各项平均
J/= m;
dw1/= m;
dw2/= m;
db/= m;
#更新参数 alpha为学习率
w1=w1-alpha*dw1;
w2=w2-alpha*dw2;
b=b-alpha*db;
向量化
数据集越来越大,需要高效运行。
经验法则是,无论什么时候,避免使用明确的 for 循环。
向量化可以快速得到结果。
numpy 库有很多向量函数,比如 u=np.log 是计算对数函数(𝑙𝑜𝑔)、 np.abs()是 计 算 数 据 的 绝 对 值 、np.maximum() 计 算 元 素 𝑦 中 的 最 大 值 , 你 也 可 以
np.maximum(v,0) 、 𝑣 ∗∗ 2 代表获得元素 𝑦 每个值得平方、
1
v
\frac1v
v1获取元素 𝑦 的倒数等
等。
所以当你想写循环时候,检查 numpy 是否存在类似的内置函数,从而避免使用循环(loop)方式。
广播Broadcasting
为了计算
W
T
X
W^TX
WTX + [𝑏𝑏. . . 𝑏] , numpy 命令是𝑍 = 𝑛𝑝. 𝑑𝑜𝑡(𝑤. 𝑇, 𝑋) + 𝑏。
在 Python 中有巧妙的地方,这里 𝑏 是一个实数,但当你将这个向量加上这个实数时, Python 自动把这个实数 𝑏 扩展成一个 1 × 𝑚 的行向量。
一行代码计算出Z和A:
Z = np.dot(w.T,X)+b;
#𝐴 = [𝑎(1)𝑎(2). . . 𝑎(𝑚)] = 𝜎(𝑍)
𝑋 是一个行向量,仅用两行代码进行计算:
dZ = A-Y;
dw = 1/m*X*numpy.transpose(m).tolist();
db = 1/m*np.sum(dZ);
A.sum(axis = 0):sum()函数的参数axis 用来指明将要进行的运算是沿着哪个轴执行,axis=1表示按行相加 , axis=0表示按列相加。
cal.reshape(1,4)指令:将矩阵𝑐𝑎𝑙 reshape(重塑)成1 × 4。当我们写代码时不确定矩阵维度的时候,通常会对矩阵进行重塑来确保得到我们想要的列向量或行向量。该指令的时间复杂度是𝑂(1),调用代价极低。
numpy 广播机制:
如果两个数组的后缘维度的轴长度相符或其中一方的轴长度为 1,则认为它们是广播兼容的。广播会在缺失维度和轴长度为 1 的维度上进行。
(二维的shape是(4,3);向量b一维的,shape是(3)。可以看到最后一个维度,就是最后一个轴是相等的,都是3)
相关:https://my.oschina.net/u/4135288/blog/3056263
注: 矩阵和一维数组的差别
我经常会扔进一个断言语句(assertion statement)。像这样,去确保在这种情况下是一个(5,1)向量,或者说是一个列向量。