- 前言
- 三、神经网络
- 3.2 激活函数
- 3.2.1 阶跃函数
- 3.2.2 sigmoid函数
- 3.2.3 ReLU函数
- 3.3 多维数组
- 3.3.1 多维数组的维度和形状
- 3.3.2 多维数组的点乘
- 3.4 三层神经网络的实现
- 3.4.1 一步一步进行
- 3.4.2 合起来实现
- 3.5 输出层的设计
- 3.5.1 Softmax函数
- 3.5.2 Softmax函数的特征:输出值求和为1,符合概率分布问题
- 四、神经网络的学习
- 4.2 损失函数
- 4.2.1 均方误差MSE
- 4.2.2 交叉熵误差CEE
- 4.2.3 mini-batch上的交叉熵的实现
- 4.3 数值微分
- 4.3.1 导数
- 4.3.2 偏导数
- 4.4 梯度
- 4.4.1 梯度法
- 4.4.2 神经网络的梯度
- 4.5 学习算法的实现
- 五、误差反向传播法
- 5.4 简单层的实现
- 5.5 激活函数层的实现
- 5.5.1 Relu层
- 5.5.2 Sigmoid
- 5.6 Affine/Softmax层的实现
- 5.6.1 Affine层数
- 5.6.2 Softmax-with-Loss层
- 总结
前言
终于从头到尾把鱼书看完啦,真的是非常入门,非常查漏补缺,对新手很友好,对有一定基础的人也非常不错。看完不复习等于没看,所以今天开始复盘,顺便写这篇读书笔记。希望分享给没看过这本书或者看过这本书的同僚们参考,欢迎大家指教。我将从第三章神经网络开始复习,前两章内容书里已经非常基础and清楚了。(会持续更新滴)
三、神经网络 3.2 激活函数
这一小节学习的概念是神经网络学习中非常重要的激活函数,它们都是一些非线性函数,至于为何是非线性函数,因为非线性函数组合才能实现复杂网络的构建。以下将实现三个激活函数,它们分别是阶跃函数、sigmoid函数和relu函数
3.2.1 阶跃函数def step_function(x):
# if x > 0:
# y = 1
# else:
# y = 0
y = x > 0
y = y.astype(np.int)
return y
这就是阶跃函数的代码实现,可以了解到阶跃函数就是当自变量大于零的时候等于1,小于零的时候等于0的函数,注释上面的改写成下面的原因是,为了numpy数组更方便进行后续操作。
x = np.array([1.5,-2,5.0]) step_function(x)
输出为array([1, 0, 1])
x1 = np.arange(-6,7,1) y1 = step_function(x1) plt.plot(x1,y1) plt.show()
输出的图像为
3.2.2 sigmoid函数def sigmoid(x):
y = 1/(1+np.exp(-x))
return y
sigmoid函数是1/(+exp(-x))的形式,当输入是numpy数组的时候,用上面的代码就可实现了。
sigmoid(x):
输出为array([0.81757448, 0.11920292, 0.99330715])
x1 = np.arange(-6,7,1) y2 = sigmoid(x1) plt.plot(x1,y2) plt.show()
输出的图像为
3.2.3 ReLU函数def ReLU(x):
y = np.maximum(0,x)
return y
ReLU函数相当于在自变量小于0的时候为0,大于零的时候和自变量相等,也就是在自变量和0中取最大值,如上代码即可实现。
ReLU(x)
输出为array([1.5, 0. , 5. ])
x1 = np.arange(-6,7,1) y3 = ReLU(x1) plt.plot(x1,y3) plt.show()
输出图像为
以上小节激活函数,为什么激活函数不能是线性函数呢?如果使用线性函数,加深神经网络的层数就没有意义了。
numpy多维数组的相关运算对于神经网络的实现是基本操作。
3.3.1 多维数组的维度和形状a = np.array([[2,4,5],[2,3,9]]) a.ndim #维度 将会输出2 a.shape #形状 将会输出(2,3) b = np.array([[2,2,1],[2,2,4],[5,4,4]]) b.ndim #维度 将会输出2 b.shape #形状 将会输出(3,3)3.3.2 多维数组的点乘
np.dot(a,b) #维度要符合矩阵乘法,左列等于右行;不然就要符合广播机制
输出为array([[37, 32, 38],
[55, 46, 50]])
第一层,大概逻辑是输入×权重加偏置,然后激活函数
X = np.array([1.0,0.5]) W1 = np.array([[0.1,0.3,0.5],[0.2,0.4,0.6]]) B1 = np.array([0.1,0.2,0.3]) print(X.shape) print(W1.shape) print(B1.shape)
输出为(2,)
(2, 3)
(3,)
A1 = np.dot(X,W1) + B1 print(A1)
输出为[0.3 0.7 1.1]
Z1 = sigmoid(A1) print(Z1)
输出为[0.57444252 0.66818777 0.75026011]
第二层,和第一层的逻辑
W2 = np.array([[0.1,0.4],[0.2,0.5],[0.3,0.6]]) B2 = np.array([0.1,0.2]) A2 = np.dot(A1,W2) + B2 print(A2)
输出为[0.6 1.33]
Z2 = sigmoid(A2) print(Z2)
输出为[0.64565631 0.79084063]
第三层,前面逻辑一样,激活函数那里用的恒等函数,回归用恒等,分类下一节介绍
W3 = np.array([[0.1,0.3],[0.2,0.4]]) B3 = np.array([0.1,0.2]) A3 = np.dot(A2,W3) + B3 print(A3)
输出为[0.426 0.912]
def identity_function(x):
y = x
return y
Z3=identity_function(A3)
print(Z3)
输出为[0.426 0.912]
回归问题的输出层的激活函数为恒等函数,下一节详细介绍
先构建一个初始化参数的函数,如下:
def init_network():
network = {}
network['W1'] = np.array([[0.1,0.3,0.5],[0.2,0.4,0.6]])
network['W2'] = np.array([[0.1,0.4],[0.2,0.5],[0.3,0.6]])
network['W3'] = np.array([[0.1,0.3],[0.2,0.4]])
network['B1'] = np.array([0.1,0.2,0.3])
network['B2'] = np.array([0.1,0.2])
network['B3'] = np.array([0.1,0.2])
return network
然后构建一个前进函数,如下:
def forward(network,x):
W1,W2,W3 = network['W1'],network['W2'],network['W3']
B1,B2,B3 = network['B1'],network['B2'],network['B3']
A1 = np.dot(x,W1) + B1
Z1 = sigmoid(A1)
A2 = np.dot(Z1,W2) + B2
Z2 = sigmoid(A2)
A3 = np.dot(Z2,W3) + B3
Z3 = identity_function(A3)
return Z3
接着传入输入,观察参数通过网络的情况
network=init_network() x=np.array([1.0,0.5]) y=forward(network,x) print(y)
输出为[0.31682708 0.69627909]
3.5 输出层的设计 3.5.1 Softmax函数激活函数的使用,回归问题用恒等函数,分类问题用softmax函数
def softmax(x):
exp_x = np.exp(x)
sum_exp_x = np.sum(exp_x)
y = exp_x / sum_exp_x
return y
softmax函数的函数形式相当于是自然指数除以自然之数求和
x = np.array([0.3,2.9,4.0]) y = softmax(x) print(y)
输出为[0.01821127 0.24519181 0.73659691]
x = np.array([1010,1000,990]) y = softmax(x) print(y)
输出为[nan nan nan]
为了解决数组中的大数的输入无法处理的问题,将softmax函数优化为下面这样,在传入自然指数的时候减去数组中的最大值,得到的函数定义代码如下:
def softmax(x):
c = np.max(x)
exp_x = np.exp(x-c)
sum_exp_x = np.sum(exp_x)
y = exp_x / sum_exp_x
return y
x = np.array([1010,1000,990]) y = softmax(x) print(y)
输出为[9.99954600e-01 4.53978686e-05 2.06106005e-09],至此解决了softmax函数的大数输入问题
3.5.2 Softmax函数的特征:输出值求和为1,符合概率分布问题sum_y = np.sum(y) print(sum_y)
输出为1.0,因此对于分类问题的输出都是需要进行这样的softmax操作,规范输出的求和符合1.0
四、神经网络的学习 4.2 损失函数这一小节中的y为输出的预测值,t为标签
4.2.1 均方误差MSE均方误差的公式相当于相减的平方求和然后×0.5,如下:
def mean_standard_erro(y,t):
return 0.5*np.sum((y-t)**2)
t=[0,0,1,0,0,0,0,0,0,0]
y=[0.1,0.05,0.6,0.0,0.05,0.1,0.0,0.1,0.0,0.0]
mean_standard_erro(np.array(y),np.array(t))
输出为0.09750000000000003
y=[0.1,0.05,0.1,0.0,0.05,0.1,0.0,0.6,0.0,0.0] mean_standard_erro(np.array(y),np.array(t))
输出为0.5975
一般回归问题使用的损失函数是方均误差这种形式的
交叉熵误差相当于计算一个和另一个的lg相乘的相反数,其中lg里需要加上一个小数,避免定义域出现0的问题,这是一种保护机制,交叉熵误差的值是由正确解标签所对应的输出结果决定的,代码如下:
def cross_entropy_error(y,t):
delta=1e-7
return -np.sum(t*np.log(y+delta))
t=[0,0,1,0,0,0,0,0,0,0]
y=[0.1,0.05,0.6,0.0,0.05,0.1,0.0,0.1,0.0,0.0]
cross_entropy_error(np.array(y),np.array(t))
输出为0.510825457099338
y=[0.1,0.05,0.1,0.0,0.05,0.1,0.0,0.6,0.0,0.0] cross_entropy_error(np.array(y),np.array(t))
输出为2.302584092994546
一般分类问题使用的损失函数是交叉熵误差这种形式的
mini-batch用的是部分计算计算近似整体的一个思路,类似于电视台求收视率,mini-batch上的交叉熵求解的代码如下:
def cross_entropy_error(y,t):
if y.ndim==1:
t=t.reshape(1,t.size)
y=y.reshape(1,y.size)
batch_size=y.shape[0]
return -np.sum(np.log(y[np.arange(batch_size),t]+1e-7))/batch_size
np.arange(batch_size)会生成一个从0到batch_size-1的numpy数组,y[np.arange(batch_size),t]能抽出各个数据的正确解标签对应的神经网络输出
关于为何设定损失函数,不直接把精度作为标准,原因是以精度为标准的话会使得绝大多数地方的导数为0,连续、平滑才能使导数不为0,才能继续更新神经网络参数,这也是激活函数不能选择阶跃函数这样不连续光滑的函数,而是选择了sigmoid这样的函数的原因
4.3.2 偏导数
4.4 梯度
4.4.1 梯度法
4.4.2 神经网络的梯度
4.5 学习算法的实现
五、误差反向传播法 5.4 简单层的实现 5.5 激活函数层的实现 5.5.1 Relu层
5.5.2 Sigmoid
5.6 Affine/Softmax层的实现 5.6.1 Affine层数
5.6.2 Softmax-with-Loss层
总结
第三章到第七章将会以书上的基础内容总结为主,第八章争取找一些新东西(那些没有代码示例,但似乎很有趣的概念和算法)加进读书笔记里。
希望这一次的读书笔记不要半途而废,每天总结一小部分,积少成多,希望早日完结撒花~



