参考《深度学习与图像识别原理与实践》一书P95,代码有所改动 这本书真的好多错误啊!!
小案例–利用梯度下降改善网络
输入一个X(人工识别这个X的图像为狗),让机器自动判断该图像的分类,其中,图像为三分类(类别分别为鸡、猫、狗),真实标签分类为y=[0,0,1](标签已经转化为one-hot类型,代表是狗)。假设我们有一个数据集X,X赋值为[[0.6,0.9]](已经将肉眼识别的狗的图片转化为矩阵, 从代码中可以看到X的形状为(1,2),代表的是1行2列
首先,根据题意,我们有
X = np.array([0.6,0.9])
y = np.array([0,0,1])
其中X代表的是狗的数据,Y表示正确的分类
建立简单网络类
class simpleNet:
def __init__(self):
np.random.seed(0)
self.W = np.random.randn(2,3)
def forward(self,x):
return np.dot(x,self.W)
def loss(self,x,y):
z = self.forward(x)
p = self._softmax(z)
loss = self.cross_entropy_error(p,y)
return loss
def predict(self,x):
x = self.forward(x)
return self._softmax(x)
def cross_entropy_error(self,p,y):
return np.sum(-y*np.log(p))
def _softmax(self,x):
exp_x = np.exp(x)
return exp_x / np.sum(exp_x)
构造函数
随机生成符合高斯分布且大小为(2,3)的矩阵,作为网络结点权重,如
网络结点图
损失函数
使用的是cross_entropy_error,即交叉熵误差
其公式为:
L
o
s
s
=
?
∑
j
=
1
C
=
3
y
j
log
?
(
y
_
p
r
e
d
i
c
t
j
)
Loss=-\sum^{C=3}_{j=1}y_j\log(y\_predict_j)
Loss=?j=1∑C=3?yj?log(y_predictj?) 其中C为类别数量,y代表对应目标值,y_predict代表本次的预测值。
激活函数
使用的是Softmax分类器,主要用于解决多分类问题。Softmax函数的定义如下所示:
S
i
=
e
V
i
∑
j
C
e
V
j
S_i=\frac{e^{V_i}}{\sum^C_je^{V_j}}
Si?=∑jC?eVj?eVi?? 其中,Vi表示的是分类器前级单元的输出。i表示类别索引,总的类别个数为C。Si表示当前元素的指数与所有元素指数和的比值。
例如:
V
=
(
?
3
2
?
1
0
)
V=\begin{pmatrix} -3 \\ 2 \\ -1 \\ 0 \end{pmatrix}
V=??????32?10?????? 经过Softmax处理后,数值转化为如下所示的相对概率:
S
=
(
0.0057
0.8390
0.0418
0.1135
)
S=\begin{pmatrix} 0.0057 \\ 0.8390 \\ 0.0418 \\ 0.1135 \end{pmatrix}
S=?????0.00570.83900.04180.1135?????? 可以清楚的看出不同类别之间的相对概率
接下来我们来看网络预测是否正确
p = net.predict(X)
print('预测值为:',p)
print('预测的类别为(0:鸡、1:猫、2:狗):',np.argmax(p))
print('损失值为:',net.loss(X,y))
损失值为3.66,且预测类别为鸡(我们要的是狗,即2),需要改善!
利用梯度下降改善网络
我们利用损失函数作为函数,不断计算其导数,利用导数不断向正确值逼近。(这里只是一维的函数而已,求导即可),即利用公式
d
f
(
x
)
d
x
=
lim
?
h
→
0
f
(
x
+
h
)
?
f
(
x
?
h
)
2
h
\frac{df(x)}{dx}=\lim_{h\rightarrow0}\frac{f(x+h)-f(x-h)}{2h}
dxdf(x)?=h→0lim?2hf(x+h)?f(x?h)? 下面为梯度下降详细代码
def numerical_gradient(f,x):
h = 1e-4
grad = np.zeros_like(x)
it = np.nditer(x,flags=['multi_index'],op_flags=['readwrite'])
while not it.finished:
idx = it.multi_index
temp_val = x[idx]
x[idx] = temp_val + h
fxh1 = f(X)
x[idx] = temp_val - h
fxh2 = f(X)
grad[idx] = (fxh1 - fxh2) / (2*h)
x[idx] = temp_val
it.iternext()
return grad
def gradient_descent(f,init_x,lr=0.01,step_num=1000):
x = init_x
for i in range(step_num):
grad = numerical_gradient(f,x)
x -= lr*grad
return x
f = lambda x:net.loss(x,y)
dw = gradient_descent(f,net.W)
np.nditer迭代数组
multi_index可以获取当前的索引值 readwrite表示可读可写
np.nditer的详情操作请参考https://blog.csdn.net/weixin_44901453/article/details/99562341
numerical_gradient
要注意区分,x为传进去的网络W,X为我们要预测的(狗)
这里书籍中后面所有的X都写成了x,导致我在这里卡了很久。
gradient_descent
lr为超参数,即学习率learning rate,一般选择较小的数
step_num为梯度下降迭代次数,这里为1000
改善网络后结果
print('经过梯度下降后,网络的权值变为:\n',dw)
print('损失值变为::',net.loss(X,y))
print('预测值为:',net.predict(X))
print('预测类别为:(0:鸡、1:猫、2:狗)',np.argmax(net.predict(X)))
下面为完整代码
import numpy as np
class simpleNet:
def __init__(self):
np.random.seed(0)
self.W = np.random.randn(2,3)
def forward(self,x):
return np.dot(x,self.W)
def loss(self,x,y):
z = self.forward(x)
p = self._softmax(z)
loss = self.cross_entropy_error(p,y)
return loss
def predict(self,x):
x = self.forward(x)
return self._softmax(x)
def cross_entropy_error(self,p,y):
return np.sum(-y*np.log(p))
def _softmax(self,x):
exp_x = np.exp(x)
return exp_x / np.sum(exp_x)
net = simpleNet()
print('随机初始化的网络参数为\n',net.W)
X = np.array([0.6,0.9])
print('我们输入张量为X,人眼识别为狗, X=',X)
p = net.predict(X)
print('预测值为:',p)
print('预测的类别为(0:鸡、1:猫、2:狗):',np.argmax(p))
y = np.array([0,0,1])
print('损失值为:',net.loss(X,y))
print()
def numerical_gradient(f,x):
h = 1e-4
grad = np.zeros_like(x)
it = np.nditer(x,flags=['multi_index'],op_flags=['readwrite'])
while not it.finished:
idx = it.multi_index
temp_val = x[idx]
x[idx] = temp_val + h
fxh1 = f(X)
x[idx] = temp_val - h
fxh2 = f(X)
grad[idx] = (fxh1 - fxh2) / (2*h)
x[idx] = temp_val
it.iternext()
return grad
def gradient_descent(f,init_x,lr=0.01,step_num=1000):
x = init_x
for i in range(step_num):
grad = numerical_gradient(f,x)
x -= lr*grad
return x
f = lambda x:net.loss(x,y)
dw = gradient_descent(f,net.W)
print('经过梯度下降后,网络的权值变为:\n',dw)
print('损失值变为::',net.loss(X,y))
print('预测值为:',net.predict(X))
print('预测类别为:(0:鸡、1:猫、2:狗)',np.argmax(net.predict(X)))
|