今日份学习目标
- 掌握激活函数
- 学习激活函数的意义
- 激活函数和线性变化之间能产生的作用
- 链式求导
- 反向传播
- 传播的顺序由拓扑排序来决定
- 拓扑排序的原理和实现过程
激活函数
世界中的很多真实关系都不是简单的线性关系,我们是否可以构建一些基本的模块,然后来组成复杂的函数
其实早期的神经网络 只有线性变化+激活函数 深度网路最重要的是多了一个CNN
理论上所有的函数都可以用多层的线性函数+非线性变化来进行拟合。但是我们之所以又有了CNN,RNN这些模型,就是因为一个问题维数灾难,就是当参数每上升一个维度,我们所需要的数据就要10倍增长,所以我们不能无节制的使用多层线性函数,因为会增加参数,这也是我们为什么使用CNN,RNN因为会减少参数。
常用的激活函数:sigmoid,relu,tanh
def sigmoid(x): # basic sub-model : Transfer :Activation Function : 激活函数
return 1 / (1 + np.exp(-x))
def relu(x):
return x * (x > 0)
def tanh(x):
# return np.tanh(x)
return (np.exp(x)-np.exp(-x))/(np.exp(x)+np.exp(-x))
def leaky_relu(x):
return 0.1*x*(x<0)+x*(x>0)
x=np.linspace(-10,10,100)
plt.plot(tanh(x))
构建神经网络拓扑图
首先我们要构建神经网络拓扑图,可视化需要用到一个工具包networkx
NetworkX是一款Python的软件包,用于创造、操作复杂网络,以及学习复杂网络的结构、动力学及其功能。
有了NetworkX你就可以用标准或者不标准的数据格式加载或者存储网络,它可以产生许多种类的随机网络或经典网络,也可以分析网络结构,建立网络模型,设计新的网络算法,绘制网络等等。
#搭建神经网络
import networkx as nx
#代表着网络的结构
computing_graph = {
'x1': ['linear-01'],
'k1': ['linear-01'],
'b1': ['linear-01'],
'linear-01': ['sigmoid'],
'sigmoid': ['linear_2'],
'k2': ['linear_2'],
'b2': ['linear_2'],
'linear_2': ['loss']
}
#此处直接输入字典表示节点和边,当然可以使用其他的形式
graph=nx.DiGraph(computing_graph)#建立一个有向图
# nx.draw(graph,with_labels=True)
layout=nx.layout.spring_layout(graph)# 一种布局方式,用Fruchterman-Reingold算法排列节点(这个算法我不了解,样子类似多中心放射状)
nx.draw(graph,layout,with_labels=True,node_color='green')#显示标签,并设置颜色
显示图如下,还是比较清晰的
以上就是一个简单的展示,接下来,我们就正式开始
第一步:需要进行拓扑排序,确定节点遍历的顺序
第二步:前向传播
第三步:反向传播
首先进行第一步代码展示:
import random
#拓扑排序,来决定节点前向传播和反向传播的顺序
def topologic(graph):
sorted_node=[]
while len(graph)>0:
all_inputs=[]
all_outputs=[]
for n in graph:
all_inputs+=graph[n]
all_outputs.append(n)
all_inputs=set(all_inputs)
all_outputs=set(all_outputs)
need_remove=all_outputs-all_inputs#需要删除的节点,也就是只有输出没有输入的点
if len(need_remove)>0:
node=random.choice(list(need_remove))
visited_next=[node]
#如果是最后一个节点,比如linear2-loss
if len(graph)==1:
visited_next+=graph[node]
graph.pop(node)
sorted_node+=visited_next
else:
break
return sorted_node
#图中的所有节点
computing_graph = {
'x1': ['linear-01'],
'k1': ['linear-01'],
'b1': ['linear-01'],
'linear-01': ['sigmoid'],
'sigmoid': ['linear_2'],
'k2': ['linear_2'],
'b2': ['linear_2'],
'linear_2': ['loss']
}
visit_order_by_algorithm=topologic(computing_graph)
第二步,前向传播如下:
#首先建立图
import networkx as nx
computing_graph = {
'x1': ['linear-01'],
'k1': ['linear-01'],
'b1': ['linear-01'],
'linear-01': ['sigmoid'],
'sigmoid': ['linear_2'],
'k2': ['linear_2'],
'b2': ['linear_2'],
'linear_2': ['loss']
}
graph=nx.DiGraph(computing_graph)
layout=nx.layout.spring_layout(graph)
#该函数用来给每一步前向传播画图
def visited_procedure(graph, postion, visited_order, step, sub_plot_index=None, colors=('red', 'green')):
changed = visited_order[:step] if step is not None else visited_order
before, after = colors
color_map = [after if c in changed else before for c in graph]
nx.draw(graph, postion, node_color=color_map, with_labels=True, ax=sub_plot_index)
#构建前向传播
import matplotlib.pyplot as plt
import numpy as np
dimension = int(len(visit_order_by_algorithm)**0.5)
fig, ax = plt.subplots(dimension, dimension+1, figsize=(15,15))
for i in range(len(visit_order_by_algorithm)+1):
ix = np.unravel_index(i, ax.shape)#索引按照ax.shape进行排序
plt.sca(ax[ix])#选择(0,0)这个曲线,开始绘制
ax[ix].title.set_text('Feed Forward Step: {}'.format(i))
visited_procedure(graph, layout, visit_order_by_algorithm, step=i, sub_plot_index=ax[ix])
第三步,反向传播:
#反向传播代码基本一样,只需将,遍历顺序颠倒即可
dimension = int(len(visit_order_by_algorithm)**0.5)
fig, ax = plt.subplots(dimension, dimension+1, figsize=(15,15))
for i in range(len(visit_order_by_algorithm)+1):
ix = np.unravel_index(i, ax.shape)#索引按照ax.shape进行排序
plt.sca(ax[ix])#选择(0,0)这个曲线,开始绘制
ax[ix].title.set_text('Feed Forward Step: {}'.format(i))
visited_procedure(graph, layout, visit_order_by_algorithm[::-1], step=i, sub_plot_index=ax[ix],colors=['green','red'])
很感谢大家的观看,有什么问题欢迎随时留言交流。