0%

Neural Network

解释性差,不可复现,数据存储量大是人工智能的瓶颈。

他们在NeuralNetwork中体现的淋漓尽致,入坑需谨慎。

👆神经网络示例图

神经元数学模型

由三部分组成:

①加权求和

②线性动态系统

③非线性函数映射

神经元接收来自n个其他神经元传递过来的输入信号,这些输入信号通过带权重的连接进行传递,神经元接收到的总输入值将与阈值进行比较,然后通过激活函数处理,产生神经元的输出。

理想的激活函数是阶跃函数,但是其不连续、不光滑,因此常常使用Sigmoid函数作为激活函数,把可能在较大范围内变化的输入值挤压到(0,1)范围内,因此有时也称为“挤压函数”

对于每一个最简单的神经元,我们有如下式子对权重进行调整:

如果预测正确,即,不用调整权值。

神经网络就是多个这样的神经元相互嵌套代入而得。

神经网络种类

⏩前馈型

第i层只与第i-1层输出相连,eg:BP神经网络,卷积神经网络

⏪反馈型

输出反馈到输入

类似模电反馈电路

BP神经网络

是有监督学习,学习能力很强,由定理,一个三层的BP神经网络就能够以任意精度逼近一个任意给定的连续函数

下面对BP神经网络进行推导:

假设我们有这样一个神经网络👇

给定训练集{} 即:输入由d个属性描述;输出维实值向量。假设隐层和输出层神经元都是用函数。

对于训练例,假定神经网络输出为,即,则网络在上的均方误差为:

BP神经网络是一个迭代学习算法,迭代的每一轮中采用广义的感知器规则对参数进行更新评估

任意参数的更新估计式为

下面以隐层到输出层的连接权为例进行推导。

BP神经网络基于梯度下降策略,以目标负梯度方向对参数进行调整(调整权值原则是使误差不断减小),对于,给定学习率,有

注意✍先影响第个输出层神经元的输入值,然后影响输出值,再然后是影响

根据的定义,有

函数有一个很好的性质

代入式得到

同理得到以下结论

其中(就这样定义的)

对于学习率,控制着每一轮迭代中的更新步长,若太大则振荡,若太小则收敛速度过慢,常规我们选择

BP神经网络实现

MATLAB也可以做BP神经网络,但是用哪个好呢?

知乎:神经网络研究与应用这块用python好还是matlab?

一般的讲,如果只是做做仿真,matlab更好,无他,现成的模块,大量的参考代码,以及简单爆了的语法规则,面向过程的程序设计。尽管python也有大量模块代码,但要用好还是有学习梯度的。

但是一旦有研究需要,包含大量自设计的模型,就会明白python是多么方便省事了。语言自身的灵活性给自行设计模型提供了极大的方便,这一点matlab能做到,但是很费事。而且做大工程,多人协作等,python比matlab有更多优势。

作者:Coldwings
链接:https://www.zhihu.com/question/28606380/answer/41478976
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

python实现神经网络

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
'''
BP神经网络Python实现,作为参考
实际使用时调sklearn的包就行
'''

import random
import numpy as np;


def sigmoid(x):
'''
激活函数
'''
return 1.0 / (1.0 + np.exp(-x))

def sigmoid_prime(x):
return sigmoid(x) * (1 - sigmoid(x))

class BPNNRegression:
'''
神经网络回归与分类的差别在于:
1. 输出层不需要再经过激活函数
2. 输出层的 w 和 b 更新量计算相应更改
'''
def __init__(self, sizes):

# 神经网络结构
self.num_layers = len(sizes)
self.sizes = sizes

# 初始化偏差,除输入层外, 其它每层每个节点都生成一个 biase 值(0-1)
self.biases = [np.random.randn(n, 1) for n in sizes[1:]]
# 随机生成每条神经元连接的 weight 值(0-1)
self.weights = [np.random.randn(r, c)
for c, r in zip(sizes[:-1], sizes[1:])]

def feed_forward(self, a):
'''
前向传输计算输出神经元的值
'''
for i, b, w in zip(range(len(self.biases)), self.biases, self.weights):
# 输出神经元不需要经过激励函数
if i == len(self.biases) - 1:
a = np.dot(w, a) + b
break
a = sigmoid(np.dot(w, a) + b)
return a

def MSGD(self, training_data, epochs, mini_batch_size, eta, error = 0.01):
'''
小批量随机梯度下降法
'''
n = len(training_data)
for j in range(epochs):
# 随机打乱训练集顺序
random.shuffle(training_data)
# 根据小样本大小划分子训练集集合
mini_batchs = [training_data[k:k+mini_batch_size]
for k in range(0, n, mini_batch_size)]
# 利用每一个小样本训练集更新 w 和 b
for mini_batch in mini_batchs:
self.updata_WB_by_mini_batch(mini_batch, eta)

#迭代一次后结果
err_epoch = self.evaluate(training_data)
print("Epoch {0} Error {1}".format(j, err_epoch))
if err_epoch < error:
break;
# if test_data:
# print("Epoch {0}: {1} / {2}".format(j, self.evaluate(test_data), n_test))
# else:
# print("Epoch {0}".format(j))
return err_epoch

def updata_WB_by_mini_batch(self, mini_batch, eta):
'''
利用小样本训练集更新 w 和 b
mini_batch: 小样本训练集
eta: 学习率
'''
# 创建存储迭代小样本得到的 b 和 w 偏导数空矩阵,大小与 biases 和 weights 一致,初始值为 0
batch_par_b = [np.zeros(b.shape) for b in self.biases]
batch_par_w = [np.zeros(w.shape) for w in self.weights]

for x, y in mini_batch:
# 根据小样本中每个样本的输入 x, 输出 y, 计算 w 和 b 的偏导
delta_b, delta_w = self.back_propagation(x, y)
# 累加偏导 delta_b, delta_w
batch_par_b = [bb + dbb for bb, dbb in zip(batch_par_b, delta_b)]
batch_par_w = [bw + dbw for bw, dbw in zip(batch_par_w, delta_w)]
# 根据累加的偏导值 delta_b, delta_w 更新 b, w
# 由于用了小样本,因此 eta 需除以小样本长度
self.weights = [w - (eta / len(mini_batch)) * dw
for w, dw in zip(self.weights, batch_par_w)]
self.biases = [b - (eta / len(mini_batch)) * db
for b, db in zip(self.biases, batch_par_b)]

def back_propagation(self, x, y):
'''
利用误差后向传播算法对每个样本求解其 w 和 b 的更新量
x: 输入神经元,行向量
y: 输出神经元,行向量

'''
delta_b = [np.zeros(b.shape) for b in self.biases]
delta_w = [np.zeros(w.shape) for w in self.weights]

# 前向传播,求得输出神经元的值
a = x # 神经元输出值
# 存储每个神经元输出
activations = [x]
# 存储经过 sigmoid 函数计算的神经元的输入值,输入神经元除外
zs = []
for b, w in zip(self.biases, self.weights):
z = np.dot(w, a) + b
zs.append(z)
a = sigmoid(z) # 输出神经元
activations.append(a)
#-------------
activations[-1] = zs[-1] # 更改神经元输出结果
#-------------
# 求解输出层δ
# 与分类问题不同,Delta计算不需要乘以神经元输入的倒数
#delta = self.cost_function(activations[-1], y) * sigmoid_prime(zs[-1])
delta = self.cost_function(activations[-1], y) #更改后
#-------------
delta_b[-1] = delta
delta_w[-1] = np.dot(delta, activations[-2].T)
for lev in range(2, self.num_layers):
# 从倒数第1层开始更新,因此需要采用-lev
# 利用 lev + 1 层的 δ 计算 l 层的 δ
z = zs[-lev]
zp = sigmoid_prime(z)
delta = np.dot(self.weights[-lev+1].T, delta) * zp
delta_b[-lev] = delta
delta_w[-lev] = np.dot(delta, activations[-lev-1].T)
return (delta_b, delta_w)

def evaluate(self, train_data):
test_result = [[self.feed_forward(x), y]
for x, y in train_data]
return np.sum([0.5 * (x - y) ** 2 for (x, y) in test_result])

def predict(self, test_input):
test_result = [self.feed_forward(x)
for x in test_input]
return test_result

def cost_function(self, output_a, y):
'''
损失函数
'''
return (output_a - y)
pass

这里用Sklearn实现一个神经网络回归例子

代码前置技能

①MLPRegressor()

语法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class sklearn.neural_network.MLPRegressor
(hidden_layer_sizes=(100, ),
activation='relu',
*,
solver='adam',
alpha=0.0001,
batch_size='auto',
learning_rate='constant',
learning_rate_init=0.001,
power_t=0.5,
max_iter=200,
shuffle=True,
random_state=None,
tol=0.0001,
verbose=False,
warm_start=False,
momentum=0.9,
nesterovs_momentum=True,
early_stopping=False,
validation_fraction=0.1,
beta_1=0.9,
beta_2=0.999,
epsilon=1e-08,
n_iter_no_change=10,
max_fun=15000)
参数 说明
hidden_layer_sizes tuple, length = n_layers - 2, default=(100,) 第i个元素代表第i个隐藏层中的神经元数量。
activation {‘identity’, ‘logistic’, ‘tanh’, ‘relu’}, default=’relu’ 隐藏层的激活函数。 - ‘identity’,无操作激活,用于实现线性瓶颈,返回f(x)= x - ‘logistic’,logistic Sigmoid函数,返回f(x)= 1 / (1 + exp(x))。 - ‘tanh’,双曲tan函数,返回f(x)= tanh(x)。 - ‘relu’,整流线性单位函数,返回f(x)= max(0,x)
solver {‘lbfgs’, ‘sgd’, ‘adam’}, default=’adam’ 权重优化的求解器。 - “ lbfgs”是quasi-Newton方法族的优化程序。 - “ sgd”是指随机梯度下降。 - “ adam”是指Kingma,Diederik和Jimmy Ba提出的基于随机梯度的优化器 注意:就训练时间和验证准确率而言,默认求解器“ adam”在相对较大的数据集(具有数千个训练样本或更多)上的效果很好。但是,对于小型数据集,“ lbfgs”可以收敛得更快并且性能更好。
alpha float, default=0.0001 L2惩罚(正则项)参数。
batch_size int, default=’auto’ 随机优化器的小批次的大小。如果求解器为“ lbfgs”,则分类器将不使用小批次处理。设为“自动”时,batch_size=min(200, n_samples)
learning_rate {‘constant’, ‘invscaling’, ‘adaptive’}, default=’constant’ 权重更新的学习速率表。 - ‘ constant ‘是一个恒定的学习速率,由’ learningrate_init ‘给出。 - “invscaling”通过使用“power_t”的缩放逆指数,逐步降低在每个时间步长“t”上的学习率`learning_rate。effective_learning_rate = learning_rate_init / pow(t, power_t) - 只要训练损失持续减少,‘adaptive’将学习率保持在‘learning_rate_init’不变。每次连续两个epoch不能减少至少tol的训练损失,或者如果“early_stop”开启,不能增加至少tol的验证分数,则当前学习率要除以5。 仅在solver=’sgd’`时使用。
learning_rate_init double, default=0.001 使用的初始学习率。它控制更新权重的步长。仅在Solver =’sgd’或’adam’时使用。
power_t double, default=0.5 反比例学习率的指数。当learning_rate设置为“ invscaling”时,它用于更新有效学习率。仅在Solver =’sgd’时使用。
max_iter int, default=200 最大迭代次数。求解器迭代直到收敛(由“ tol”决定)或这个迭代次数。对于随机求解器(“ sgd”,“ adam”),请注意,这决定时期数(每个数据点将使用多少次),而不是梯度步数。
shuffle bool, default=True 是否在每次迭代中对样本进行打乱。仅在Solver =’sgd’或’adam’时使用。
random_state int, RandomState instance, default=None 决定用于权重和偏差初始化的随机数生成,如果使用了提前停止,则切分测试集和训练集,并在solver =’sgd’或’adam’时批量采样。在多个函数调用之间传递一个int值以获得可重复的结果。请参阅词汇表
tol float, default=1e-4 优化公差。当n_iter_no_change连续迭代的损失或分数没有通过至少tol得到改善时,除非将learning_rate设置为‘adaptive’,否则将认为达到收敛并停止训练。
verbose bool, default=False 是否将进度消息打印到标准输出。
warm_start bool, default=False 设置为True时,请重用上一个调用的解决方案以拟合初始化,否则,只需擦除以前的解决方案即可。请参阅词汇表
momentum float, default=0.9 梯度下降更新的动量。应该在0到1之间。仅在solver =’sgd’时使用。
nesterovs_momentum boolean, default=True 是否使用内Nesterov的动量。仅在Solver =’sgd’且momentum> 0时使用。
early_stopping bool, default=False 当验证准确率没有提高时,是否使用提前停止来终止训练。如果设置为true,它将自动预留10%的训练数据作为验证,并在n_iter_no_change连续几个时期,验证准确率没有提高至少tol时终止训练 。除多标签设置外,这个切分是分层的。仅在Solver =’sgd’或’adam’时有效
validation_fraction float, default=0.1 预留的训练数据比例作为提前停止的验证集。必须在0到1之间。仅当early_stopping为True时使用
beta_1 float, default=0.9 第一矩向量估计的指数衰减率,应在[0,1)范围内。仅在solver =’adam’时使用
beta_2 float, default=0.999 第二矩向量估计的指数衰减率,应在[0,1)范围内。仅在solver =’adam’时使用
epsilon float, default=1e-8 adam中数值稳定性的值。仅在solver =’adam’时使用
n_iter_no_change int, default=10 不满足tol改进的最大时期数。仅在Solver =’sgd’或’adam’时有效 0.20版中的新功能。
max_fun int, default=15000 仅在Solver =’lbfgs’时使用。损失函数调用的最大次数。求解器迭代直到收敛(由“ tol”确定),迭代次数达到max_iter或这个损失函数调用的次数。请注意,损失函数调用的次数将大于或等于MLPClassifier的迭代次数。 0.22版中的新功能。
属性 说明
loss_ float 用损失函数计算的当前损失。
coefs_ list, length n_layers - 1 列表中的第i个元素表示与第i层相对应的权重矩阵。
intercepts_ list, length n_layers - 1 列表中的第i个元素表示与层i + 1对应的偏差向量。
niter int, 求解程序已运行的迭代次数。
nlayers int 层数。
noutputs int 输出数量。
outactivation string 输出激活函数的名称。

②评价回归模型

方法名称 最优值 sklearn函数
平均绝对误差 0.0 sklearn.metrics.mean_absolute_error
均方误差 0.0 sklearn.metrics.mean_squared_error
中值绝对误差 0.0 sklearn.metrics.median_absolute_error
可解释方差 1.0 sklearn.metrics.explained_variance_score
1.0 sklearn.metrics.r2_score

③transform与fit_tranform

训练集用fit_transform(),其实就找到了均值和方差,即找到了数据归一化的转换规则,于是我们把这个规则用在训练集上。这个规则同样可以将其运用到测试集上,但是注意👋测试集只需要标准化数据即可,不用再拟合数据,所以测试集使用transform()✍(也可以这样理解:如果测试集也拟合数据的话,得到的均值和方差就是测试集本身的,不能和训练集的规则联系起来

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#1.导入数据
from sklearn.datasets import load_boston
boston = load_boston()
data = boston['data']
target = boston['target']
#2.数据切片制作训练集和测试集
from sklearn.model_selection import train_test_split
train_data,test_data,train_target,test_target = train_test_split(data,target,test_size=0.2,random_state=42)
#3.数据预处理
from sklearn.preprocessing import StandardScaler
std = StandardScaler()
train_data_std = std.fit_transform(train_data)#先拟合数据,然后将其转化为标准形式
test_data_std = std.transform(test_data)
#4.MLP回归
from sklearn.neural_network import MLPRegressor
regr = MLPRegressor(solver='adam',hidden_layer_sizes=(50,50),activation='tanh',max_iter=5000).fit(train_data_std,train_target)
y_pred = regr.predict(test_data_std)
#5.评价回归模型
from sklearn.metrics import mean_absolute_error
#平均绝对误差作为评价指标
error = mean_absolute_error(test_target, y_pred)
print(error)
#6.绘图
import matplotlib.pyplot as plt
plt.figure()
plt.plot(range(len(y_pred)), y_pred, color='blue')
plt.plot(range(len(y_pred)), test_target, color='red')
plt.show()

红色的是回归值。

BP神经网络评价

Advantages:

①泛化能力强

②非线性映射能力强

③容错能力强

Disadvantages:

先天性缺陷来自梯度下降法:

①目标函数必须可微

②如果一片区域比较平坦会花费较多时间进行训练

③可能会陷入局部极小值,而没有到达全局最小值(求全局最小值的目的是为了实现误差的最小值)

BP神经网络缺陷:

①如何设置隐层神经元的个数是没有解决的问题,实际中我们通过调参来尝试

②权值是随机给定的,具有不可复现性

③属于监督学习,对于样本有较大依赖性。如果样本集合代表性差,样本矛盾多,存在冗余样本,网络就很难达到预期的性能

-------------本文结束感谢您的阅读-------------
请作者喝一杯蜜雪冰城吧!