神经网络-一个案例的研究

在完成的了神经网络的编程后,下面进行一个案例研究。具体的,下面会查看神经网络对于分类高度重合数据的效果,并对其结果进行讨论。

数据生成

这里使用的数据是三维的各维服从高斯分布并分别属于4个类别的数据。下面是生成数据的代码。

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
import numpy as np
import matplotlib.pyplot as plt
# 各类别分布的参数
mu1, cov1 = [0, 0, 0], [[1, 0, 0], [0, 1, 0], [0, 0, 1]]
mu2, cov2 = [0, 1, 0], [[1, 0, 1], [0, 2, 2], [1, 2, 5]]
mu3, cov3 = [-1, 0, 1], [[2, 0, 0], [0, 6, 0], [0, 0, 1]]
mu4, cov4 = [0, 0.5, 1], [[2, 0, 0], [0, 1, 0], [0, 0, 3]]
def gen_data(mu, cov, num):
return np.random.multivariate_normal(mu, cov, num)
num = 1000
np.random.seed(0)
X = np.vstack((gen_data(mu1, cov1, num), \
gen_data(mu2, cov2, num), \
gen_data(mu3, cov3, num), \
gen_data(mu4, cov4, num)))
y = np.append(0 * np.ones(num, dtype=np.int),\
[1 * np.ones(num, dtype=np.int),\
2 * np.ones(num, dtype=np.int),\
3 * np.ones(num, dtype=np.int)])
print X.shape, y.shape

先来直观看下数据分布。使用ployly进行可视化。

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
import plotly.plotly as py
import plotly.graph_objs as go
#plot graph
def create_trace(x, y, z, color):
trace = go.Scatter3d(
x=x,
y=y,
z=z,
mode='markers',
marker=dict(
# color='rgb(127, 127, 127)',
size=5,
symbol='circle',
line=dict(
color=color
),
opacity=0.6
)
)
return trace
layout = go.Layout(
margin=dict(
l=0,
r=0,
b=0,
t=0
)
)
trace1 = create_trace(X[y==0, 0], X[y==0, 1], X[y==0, 2], 'rgb(228, 46, 93)')
trace2 = create_trace(X[y==1, 0], X[y==1, 1], X[y==1, 2], 'rgb(255, 127, 14)')
trace3 = create_trace(X[y==2, 0], X[y==2, 1], X[y==2, 2], 'rgb(14, 71, 255)')
trace4 = create_trace(X[y==3, 0], X[y==3, 1], X[y==3, 2], 'rgb(46, 76, 228)')
# # create_trace(x, y, z, 'rgba(217, 217, 217, 0.14)')
data = [trace1, trace2, trace3, trace4]
fig = go.Figure(data=data, layout=layout)
py.iplot(fig, filename='normal-3d-scatter')

可以看出4各类别的数据重叠在一起。对于这样分布的数据分类准确率会有一定的上限。

神经网络学习与分类

下面使用上次编写的神经网络代码进行分类。

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
# 初始化数据
# init input data for NN
nsample = num * 4
nfeature = 3
nclass = 4
tX = X
ty = np.zeros((nsample, nclass))
for i in range(len(ty)):
ty[i][int(y[i])] = 1
# ty = ty
print tX.shape, ty.shape
# Logistic-Sigmoid
# f = lambda x: 1.0 / (1 + np.exp(-x)) #apply to net
# df = lambda x: x * (1 - x) #apply to z
# # Tanh-Sigmoid
f = lambda x: np.tanh(x)
df = lambda x: 1 - x*x
nn = ANN()
nn.train(tX, ty, hide_n = [3], f=f, df=df, \
eta = 0.01, epochs=5000, _lambda = 0.001, \
momentum_alpha = 0.1, decay_r = 0.001, print_loss=500, seed=0)

测试一个网络结构为3 X 3 X 4的神经网络,经过5000次迭代后分类的准确率达到51.52%。

下面查看在个别样本点下预测概率值与真实概率值的区别。

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
# 生成4个样本点
target = np.array([[0, 0, 0],
[-1, 0, 1],
[0.5, -0.5, 0],
[-1, 0, 0],
[0, 0, -1]])
# 获取神经网络的预测概率值
pre_p = nn.get_p(target)
# 获取真实分布概率值
# 多元高斯概率值函数
def multivariate_gaussian(x, mu, cov):
k = len(mu)
cov_det = np.linalg.det(cov)
cov_inv = np.linalg.inv(cov)
sub = x - mu
up = np.exp(-1.0 / 2 * sum(sub.dot(cov_inv) * sub))
down = np.sqrt((2*np.pi)**k * cov_det)
return up / down
# 条件概率
def get_multip_class_true_p(x):
return [multivariate_gaussian(x, mu=mu1, cov=cov1),
multivariate_gaussian(x, mu=mu2, cov=cov2),
multivariate_gaussian(x, mu=mu3, cov=cov3),
multivariate_gaussian(x, mu=mu4, cov=cov4)]
all_true_p = np.array([get_multip_class_true_p(target[i]) for i in range(5)]).T
# 真实概率值
target_p = all_true_p / all_true_p.sum(0)

得到的概率值数值为

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
# NN预测概率, 其中每一行代表一个数据点,每一列对应每个类别的概率值
[[ 0.43965423 0.2412433 0.07974024 0.23936223]
[ 0.2807295 0.03333006 0.26068414 0.4252563 ]
[ 0.4733875 0.2553482 0.07037593 0.20088837]
[ 0.41485988 0.13125879 0.17941225 0.27446907]
[ 0.44024963 0.33186004 0.06392216 0.16396817]]
# 真实后验概率
[[ 0.57319913 0.17383142 0.07816171 0.17480774]
[ 0.38239803 0.02587597 0.30006788 0.29165812]
[ 0.61360936 0.15427108 0.07698202 0.15513754]
[ 0.54839143 0.07855839 0.15830697 0.21474321]
[ 0.50071463 0.32146516 0.02511796 0.15270225]]
# 画热图
plt.figure(figsize=(16, 32))
plt.subplot(1, 2, 1)
plt.title('True probability')
plt.imshow(target_p, cmap='hot')
plt.xlabel('sample')
plt.ylabel('class')
plt.subplot(1, 2, 2)
plt.title('NN predict probability')
plt.imshow(pre_p, cmap='hot')
plt.xlabel('sample')
plt.ylabel('class')
plt.show()

pro_heatmap

上图左图为5个样本属于4个类别的真实概率值,右图表示该[3X3X4]神经网络预测概率值。颜色越浅表示概率值越大,横轴对应不同的样本,纵轴对应4个类别。从图中可见该5个样本点在第一类有最高的概率值。可以看出预测概率值和真实概率大小关系大致相同,但其中第二个样本点分类错误。

多层神经网络

从前面的测试看出使用[3 X 3 X 4]的神经网络学习的准确率只有51%左右,下面改变网络隐藏层的节点数和结构学习新的神经网络看学习准确率的改变。

分别使用上面的代码新生成3个神经网络,分别是nn1(结构为[3 X 10 X 4], lambda=0.0001,迭代10000次),nn2(结构为[3 X 10 X 10 X 4], lambda=0.0001,迭代10000次),nn3(结构为[3 X 50 X 50 X 4], lambda=0.0001,迭代10000次)。它们学习准确率分别为 nn1 分类正确了57.57%训练样本,nn2分类正确58.5%, nn3 分类正确60.65%。

下面是在5个样本点中,这4个分类器得到的概率值热图。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
the_nn = [nn, nn1, nn2, nn3]
plt.figure(figsize=(15, 30))
plt.subplot(5, 2, 1)
plt.title('True probability')
plt.imshow(target_p, cmap='hot', interpolation='nearest')
plt.xlabel('sample')
plt.ylabel('class')
for i, nn_i in enumerate(the_nn):
plt.subplot(5, 2, i+2)
plt.title('NN%s preict probability' % (i))
pre_tmp = nn_i.get_p(target)
plt.imshow(pre_tmp, cmap='hot', interpolation='nearest')
plt.xlabel('sample')
plt.ylabel('class')
plt.show()

pro_heatmap_all

虽然随着隐藏层节点数和层数的增加,学习的准确率得到提升(51% -> 57% -> 58% -> 60%),但是从概率预测值的如图来看,概率预测值和真实值相比并没变得更加贴近。其中藏层层数为[3]和[10X10]的神经网络得到的预测概率值与真实概率相似。从这些热图图也可以看出较复杂的神经网络并没有比最简单[3 X 3 X 4]的神经网络得到更优的概率值预测结果。

预测

下面生成一组测试样本集(400个样本,每个类别100个),计算识别率。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 生成测试数据
test_num = 100
test_X = np.vstack((gen_data(mu1, cov1, test_num), \
gen_data(mu2, cov2, test_num), \
gen_data(mu3, cov3, test_num), \
gen_data(mu4, cov4, test_num)))
test_y = np.append(0 * np.ones(test_num, dtype=np.int),\
[1 * np.ones(test_num, dtype=np.int),\
2 * np.ones(test_num, dtype=np.int),\
3 * np.ones(test_num, dtype=np.int)])
print test_X.shape, test_y.shape
nsample = test_num * 4
nfeature = 3
nclass = 4
test_tX = test_X
test_ty = np.zeros((nsample, nclass))
for i in range(len(test_ty)):
test_ty[i][int(test_y[i])] = 1
print test_tX.shape, test_ty.shape

进行测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 分别对4个分类器进行测试
the_nn = [nn, nn1, nn2, nn3]
# 测试得到预测准确率
all_pre_nn = [t.calculate_match_rate(test_tX, test_ty) for t in the_nn]
# 画图
from matplotlib import pyplot
pyplot.plot([0, 1, 2, 3], all_pre_nn)
for a,b in zip([0, 1, 2, 3], all_pre_nn):
pyplot.text(a, b, str(b))
pyplot.title('all NN test preict rate')
my_xticks = ['nn [3]','nn1[10]','nn2[10X10]','nn3[50X50]']
pyplot.xticks([0, 1, 2, 3], my_xticks)
pyplot.ylabel('test predict rate')
pyplot.show()

test_predict_rate

可以看出神经网络测试的准确率在0.54到0.58左右,其中[3 X 3 X 4]的准确率为54.75%,[3 X 10 X 10 X 4]网络的准确率为最大的58.5%。此后增加网络的节点并没有提升测试的性能。可以说明随着神经网络的复杂度增加(隐藏节点数增加,层数增加),网络学习的准确率能增加,但泛化的能力在过了一定数值后会减少,此即为学习的过拟合。

总结

本文通过对一个不同类别紧密结合的数据集进行神经网络分类学习和预测。得到的结果可以看出神经网络的性能有一定上限,即和样本的真实分布相关。从以上实验可以直观体会“天下没有免费的午餐”,对于该由正态分布生成的“简单”分类问题,神经网络亦不能得到很好的预测效果。对于实际问题,某些模型并不一定能得到很好的效果。总的来说,实际模式识别问题还是需要一定的先验(能不能分类、怎么分类)以及需要进行多种测试(不同得算法、参数等)。