import numpy
as np
"""
在01中讲到了计算节点的反向传播的计算方式,下面来说说激活函数节点的反向传播计算方式
对于ReLU函数(x大于0时输出x,小于0时输出0),我们对其求导数可以很容易得到当大于0时导数值为1,小于等于0时导数值为0
所以当上游传过来导数时,若这个节点正向传播时的x大于0,那么导数原封不动向下游传过去,反之为0
x大于0 x小于0
x-------》 -------》y x-------》 -------》0
relu relu
d《------ 《------ 导数值d 0《------ 《------ 导数值d
"""
class Relu:
"""Relu的反向传播和正向传播实现"""
def __init__(self
):
self
.mask
= None
def forward(self
, x
):
self
.mask
= (x
<= 0)
out
= x
.copy
()
out
[self
.mask
] = 0
return out
def backward(self
, dout
):
dout
[self
.mask
] = 0
dx
= dout
return dx
"""
sigmoid函数的反向传播
x-------》 -------》y
sigmoid
d*y*(1-y)《------ 《------ 导数值d
"""
def sigmoid(x
):
return 1 / (1 + np
.exp
(-x
))
class Sigmoid:
def __init__(self
):
self
.out
= None
def forward(self
, x
):
out
= sigmoid
(x
)
self
.out
= out
return out
def backward(self
, dout
):
dx
= dout
* (1.0 - self
.out
) * self
.out
return dx
"""
Affine层实现反向传播
对于矩阵乘法顺便加上偏置的节点
"""
class Affine:
def __init__(self
, W
, b
):
"""
初始化矩阵
:param W: 权值
:param b: 偏置
"""
self
.W
= W
self
.b
= b
self
.x
= None
self
.dW
= None
self
.db
= None
def forward(self
, x
):
"""
前项传播
:param x: 输入,矩阵
:return: 矩阵乘法和偏置相加后结果
"""
x
= x
.reshape
(x
.shape
[0], -1)
self
.x
= x
out
= np
.dot
(self
.x
, self
.W
) + self
.b
return out
def backward(self
, dout
):
dx
= np
.dot
(dout
, self
.W
.T
)
self
.dW
= np
.dot
(self
.x
.T
, dout
)
self
.db
= np
.sum(dout
, axis
=0)
return dx
"""
实现soft-with-loss层
"""
def softmax(x
):
x
= x
- np
.max(x
, axis
=-1, keepdims
=True)
return np
.exp
(x
) / np
.sum(np
.exp
(x
), axis
=-1, keepdims
=True)
def cross_entropy_error(y
, t
):
if y
.ndim
== 1:
t
= t
.reshape
(1, t
.size
)
y
= y
.reshape
(1, y
.size
)
if t
.size
== y
.size
:
t
= t
.argmax
(axis
=1)
batch_size
= y
.shape
[0]
return -np
.sum(np
.log
(y
[np
.arange
(batch_size
), t
] + 1e-7)) / batch_size
class SoftmaxWithLoss:
def __init__(self
):
self
.loss
= None
self
.y
= None
self
.t
= None
def forward(self
, x
, t
):
self
.t
= t
self
.y
= softmax
(x
)
self
.loss
= cross_entropy_error
(self
.y
, self
.t
)
return self
.loss
def backward(self
, dout
=1):
batch_size
= self
.t
.shape
[0]
if self
.t
.size
== self
.y
.size
:
dx
= (self
.y
- self
.t
) / batch_size
else:
dx
= self
.y
.copy
()
dx
[np
.arange
(batch_size
), self
.t
] -= 1
dx
= dx
/ batch_size
return dx
转载请注明原文地址:https://tech.qufami.com/read-5703.html