二元分类Binary classification与逻辑回归logistic regression
逻辑回归即是一个二元分类模型,例如给定一定数量的猫的样本图片,经过模型训练后,随意给定一张图片,判断是否是猫,这里把结果设为y,输入的数据为x,若图片是64x64的大小,且为RGB色彩模式,则x为一个64x64x3的矩阵,即n=12288,用n(x) = 12288 来表示输入特征向量x的维度,为了简化,直接用小写n 来表示输入特征向量的维度 所以,在此二元分类问题中 我们的目标是学习到这样的一个分类器: 我们输入一幅以特征向量x表示的图像 然后预测对应的输出y是1还是0 即,这幅图上是猫还是不是猫。
首先,先罗列出一些变量与符号,这些变量与符号将在后续用到
单个样本由一对(x,y):表示x是一个n(x)维的特征向量 ,y是标签,取值为0或1 训练集包含m个训练样本 所以训练集将被写成
(
x
(
1
)
,
y
(
1
)
)
(x^{(1)}, y^{(1)})
(x(1),y(1))表示第一个样本的输入和输出,
(
x
(
2
)
,
y
(
2
)
)
(x^{(2)}, y^{(2)})
(x(2),y(2))代表第二个样本的输入和输出 直到
(
x
(
m
)
,
y
(
m
)
)
(x^{(m)}, y^{(m)})
(x(m),y(m)),表示最后一个样本输入和输出
Cost function and Grandient
对于逻辑回归学习算法会得到的输出标签y,y在监督学习问题中全是0或者1,因此这是一种针对二分类问题的算法,给定的输入特征向量 x 和一幅图片对应,识别这是否是一张猫的图片 因此我们想要一种算法能够输出一个预测值 我们称之为
y
^
\hat{y}
y^这代表对真实标签 Y 的估计,事实上讲
y
^
\hat{y}
y^是当给定输入特征x时,预测标签 y 为1的概率 换种说法就是当x是一张图片,
y
^
\hat{y}
y^告诉你这是一张猫图的概率:
即:
y
^
=
P
{
y
=
1
∣
x
}
\hat{y} = P\{y=1|x\}
y^=P{y=1∣x}
那么如何产生
y
^
\hat{y}
y^呢,如果是线性回归,则有如下的假设,
y
^
=
w
T
x
+
b
\hat{y} = w^Tx+b
y^=wTx+b
而在二元分类算法中,
y
^
\hat{y}
y^的取值范围必须为(0,1),那么可以带入sigmoid函数:
g
(
z
)
=
1
1
+
e
−
z
g(z) = \frac{1}{1+e^{-z}}
g(z)=1+e−z1
其函数图像为:
在构建好逻辑回归的假设函数后的目标即是优化参数W和b,使得预测的标签
y
^
\hat{y}
y^能够尽可能接近真实的输出y,因此需要计算代价函数以优化参数,若按照线性回归的损失函数(error function),即
L
(
y
^
,
y
)
=
1
2
(
y
^
−
y
)
2
L(\hat{y},y)=\frac1{2}(\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)=−ylog(y^)−(1−y)log(1−y^)
代价函数为:
J
(
w
,
b
)
=
−
1
m
∑
i
=
0
m
L
(
y
^
,
y
)
=
−
1
m
∑
i
=
0
m
(
y
l
o
g
(
y
^
)
+
(
1
−
y
)
l
o
g
(
1
−
y
^
)
)
J(w, b) = -\frac1{m}\sum_{i=0}^{m}L(\hat{y},y) = -\frac1{m}\sum_{i=0}^{m}(ylog(\hat{y})+(1-y)log(1-\hat{y}))
J(w,b)=−m1i=0∑mL(y^,y)=−m1i=0∑m(ylog(y^)+(1−y)log(1−y^))
这样所得到得代价函数图像为:
根据不断地迭代w和b的值即可得到使代价最小的最优化的参数:
w
:
=
w
−
α
∂
J
∂
w
w:=w-\alpha\frac{\partial{J}}{\partial{w}}
w:=w−α∂w∂J
b
:
=
b
−
α
∂
J
∂
b
b:=b-\alpha\frac{\partial{J}}{\partial{b}}
b:=b−α∂b∂J
计算图(compute graph)
根据上文,对逻辑回归作以下概要,首先根据输入的标签X(vectorizing)与初始的参数,带入线性回归假设函数得到z,再带入sigmoid函数得到
y
^
\hat{y}
y^标签;
z
=
w
T
x
+
b
z = w^Tx +b
z=wTx+b
y
^
=
a
=
σ
(
z
)
\hat{y} = a = \sigma(z)
y^=a=σ(z)
L
(
a
,
y
)
=
−
y
l
o
g
(
a
)
−
(
1
−
y
)
l
o
g
(
1
−
a
)
L(a,y)=-ylog(a)-(1-y)log(1-a)
L(a,y)=−ylog(a)−(1−y)log(1−a)
得到如图逻辑回归的前向传播计算图:
再从计算图末端(即损失函数)向后递推求到损失函数关于a、z、wj以及b的偏导数,如图:
称为其反向传播算法(其实就是向后依次求复合函数的偏微分)
由此对于代价函数,即有公式:
∂
J
∂
w
=
1
m
X
(
A
−
Y
)
T
\frac{\partial J}{\partial w} = \frac{1}{m}X(A-Y)^T
∂w∂J=m1X(A−Y)T
∂
J
∂
b
=
1
m
∑
i
=
1
m
(
a
(
i
)
−
y
(
i
)
)
\frac{\partial J}{\partial b} = \frac{1}{m} \sum_{i=1}^m (a^{(i)}-y^{(i)})
∂b∂J=m1i=1∑m(a(i)−y(i))
上图即位文首所谈到的区分图片是否是猫的用于逻辑回归的计算图,也是最简单的神经网络,下面即介绍对该神经网络模型搭建的算法实现
算法实现
导入模块
import numpy
import matplotlib.pyplot as plt
train_set_x_orig:训练集的x数据(m_train个样本)
train_set_y:训练集的y数据
test_set_x_orig:测试集的x数据(m_test个样本)
test_set_y:训练集的y数据
m_train = train_set_x_orig.shape[0]
m_test = test_set_x_orig.shape[0]
num_px = train_set_x_orig.shape[1]#每个样本的特征数
实现sigmoid函数
def sigmoid(z):
"""
Compute the sigmoid of z
Arguments:
z -- 标量或任意大小的numpy数组
Return:
s -- sigmoid(z)
"""
s = 1/(1+np.exp(-z))
return s
初始化神经网络参数:
def initialize_with_zeros(dim):
w = np.zeros((dim, 1))#由于逻辑回归是单个神经元,故可以将w参数初始化为0,在后续的深度神经网络中,若w均初始化为0,则所有结点都会做相同的运算,无法破坏其对称性
b = 0
assert(w.shape == (dim, 1))
assert(isinstance(b, float) or isinstance(b, int))
return w, b
根据上述计算图的前向后向传播算法计算对参数的导数:
def propagate(w, b, X, Y):
m = X.shape[1]#样本数
# 前向传播算法(From X to Cost)
A = sigmoid(np.dot(w.T, X)+b) # 计算激活函数
cost = (-1/m)*np.sum(Y*np.log(A)+(1-Y)*np.log(1-A)).sum() #计算代价函数
# 反向传播算法 (TO FIND GRAD)
dw = np.dot(X, (A-Y).T)/m
db = np.sum(A-Y).sum()/m
assert(dw.shape == w.shape)
assert(db.dtype == float)
cost = np.squeeze(cost)#把[[[17]]]变为17
assert(cost.shape == ())
grads = {"dw": dw,
"db": db}
return grads, cost
反复迭代,优化参数
def optimize(w, b, X, Y, num_iterations, learning_rate, print_cost = False):
costs = []
for i in range(num_iterations):
#代价和梯度计算
grads, cost = propagate(w, b, X, Y)
print_cost = True
dw = grads["dw"]
db = grads["db"]
# 更新梯度
w = w - learning_rate*dw
b = b - learning_rate*db
#每100次迭代输出一次代价
if i % 100 == 0:
costs.append(cost)
if print_cost and i % 100 == 0:
print ("Cost after iteration %i: %f" %(i, cost))
params = {"w": w,
"b": b}
grads = {"dw": dw,
"db": db}
return params, grads, costs
利用优化好的参数进行预测:
def predict(w, b, X):
m = X.shape[1]
Y_prediction = np.zeros((1,m))#初始化预测值
w = w.reshape(X.shape[0], 1)
A = sigmoid(np.dot(w.T, X)+b)#通过训练好的参数计算A
for i in range(A.shape[1]):
if A[0,i] > 0.5:(当概率大于0.5时视预测值为1)
Y_prediction[0,i] = 1
assert(Y_prediction.shape == (1, m))
return Y_prediction
整合上述函数构建训练模型:
def model(X_train, Y_train, X_test, Y_test, num_iterations = 2000, learning_rate = 0.5, print_cost = False):
# 初始化参数
w, b = initialize_with_zeros(X_train.shape[0])
# 梯度下降算法优化参数
parameters, grads, costs = optimize(w, b, X_train, Y_train, num_iterations, learning_rate, print_cost = False)
# 提取迭代优化后的的参数
w = parameters["w"]
b = parameters["b"]
# 预测给定的样本
Y_prediction_test = predict(w, b, X_test)
Y_prediction_train = predict(w, b, X_train)
print("train accuracy: {} %".format(100 - np.mean(np.abs(Y_prediction_train - Y_train)) * 100))
print("test accuracy: {} %".format(100 - np.mean(np.abs(Y_prediction_test - Y_test)) * 100))
d = {"costs": costs,
"Y_prediction_test": Y_prediction_test,
"Y_prediction_train" : Y_prediction_train,
"w" : w,
"b" : b,
"learning_rate" : learning_rate,
"num_iterations": num_iterations}
return d