2.3 使用ANN对医疗数据分类
IBM在2015年5月宣布推出Watson Health服务,收集健康数据交给Watson超级计算机进行分析。目前IBM Waston Health最主要的应用便是在癌症的诊疗上,通过对医学影像的分析和学习,帮助医生做出对癌症患者的精准诊断。另外一方面,在每一个国家的医疗资源都是十分稀缺的,如何提高基层医生的诊疗水平显得至关重要。我们并不需要智能诊疗会取代医生,因为医疗也并不是简单的诊断,医生更重要的价值还在于对诊断结果的解释、说明和信用背书,但让智能诊疗系统辅助医生诊断,则无疑会大大提高普通医生的诊断水平和诊断效率,降低误诊率。
因此,人工智能对于辅助医生的工作来说,越显得非常重要。例如:医生可以根据人工智能给出女性最佳生育期的建议,不再仅仅基于她们的年龄,而是基于一系列相关的个人身体指标。
以现代医疗检测报告为例,很多时候我们去医院抽血、检查细胞病变等检查之后,检查室开出一张看不懂的表格如图2.3.1,上面有白细胞、链球菌、血小板的参数,医生通过检查这些参数值得大小和变化,可以预测判断该病人是否患有某种病原体。
下面我们将把类似的医疗数据作为背景:首先给出对的医疗检测数据进行数学模型的转换,然后通过构建一个三层的人工神经网络ANN对已有的医疗数据进行训练, 得到该医疗数据的分类模型,然后对新的数据进行预测其所属分类,因为人工神经网络的隐层对数据的分类存在较大影响,因此最后探讨隐层的神经元节点数对实际的数据有如何的影响。
2.3.1 准备数据:从医疗数据到数学模型
假设本次血液检测项目只有链球菌x1和葡萄球菌x2两种,对于不同的球菌组合,会出现不同的病原体(不同的病症)。假设有两个分类,分别是病原体I和病原体II,病原体I、病原体II分别用用蓝色、红色表达;x轴表示链球菌的值,y轴表示葡萄球菌的值。在本例程这里的数据已经归一化处理过后,因此数据的分布集中在[-2, 2]之间(想要了解更多关于归一化操作请参考机器学习实践[1])。
我们的目标是通过训练一个三层的人工神经网络ANN模型,对给出不同血液检测项目(x1、x2)的数据进行分类。值得注意的是,因为很多时候医疗数据是线性不可分的,因此我们并不能够简单地使用一条直线对数据进行划分。这意味着不能够用线性分类器来分类,例如Logistic分类器、贝叶斯分类器等,否则分类的数据精度和回召率过低,会对真实的医疗诊断结果造成巨大的影响。
使用神经网络的好处就是不需要去担心特征工程问题,隐层会自动地去寻找特征。
from sklearn import linear_model
from sklearn import datasets
import sklearn
import numpy as np
import matplotlib.pyplot as plt
# 在notebook内显示plt图
%matplotlib inline
def plot_decision_boundary(pred_func, data, labels):
'''绘制分类边界图'''
# 设置最大值和最小值并增加0.5的边界(0.5 padding)
x_min, x_max = data[:, 0].min() - 0.5, data[:, 0].max() + 0.5
y_min, y_max = data[:, 1].min() - 0.5, data[:, 1].max() + 0.5
h = 0.01
# 生成一个点阵网格,点阵间距离为h
xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
np.arange(y_min, y_max, h))
# 预测整个网格当中的函数值
z = pred_func(np.c_[xx.ravel(), yy.ravel()])
z = z.reshape(xx.shape)
# 绘制轮廓和训练样本
plt.contourf(xx, yy, z, cmap=plt.cm.Spectral)
plt.scatter(data[:, 0], data[:, 1], s=40, c=labels, cmap=plt.cm.Spectral)
np.random.seed(0)
X, y = datasets.make_moons(300, noise=0.25) # 300个数据点,噪声设定0.3
plt.scatter(X[:,0], X[:,1], s = 50, c = y, cmap=plt.cm.Spectral, edgecolors="Black")
plt.title('Data Example')
plt.show()
逻辑回归结果
下图显示了我们逻辑回归分类器的分类结果,逻辑回归算法直接用直线将数据分隔开两类,明显这样的分类结果是远远不能满足真实情况的。
# 使用scikit-learn的线性回归分类器
clf = sklearn.linear_model.LogisticRegressionCV()
clf.fit(X, y)
# 显示分类结果
plot_decision_boundary(lambda x: clf.predict(x), X, y)
plt.title("Logistic Regression")
<matplotlib.text.Text at 0x10d0de190>
2.3.2 建立人工神经网络模型
为了解决现实情况更多线性不可分的数据,我们需要建立一个三层神经网络,输入层、隐层、输出层。
其中输入层(第一层)中的神经节点数目由输入数据的维数决定,例子有链球菌x1和葡萄球菌x2,因此数据维度是2,输入有两个神经元节点。同理,输出层(第三层)中的节点数目由我们的分类数决定,例子里为病原体I(0)和病原体II(1),因此输出层有两个神经元。该神经网络如图2.3.4所示。
根据实际情况我们可以增加隐层数和每一隐层的节点数,当隐层越多、隐层节点越多,能够处理更加复杂数据模型,但是伴随着是更大的开销:
1.更多隐层意味着我们的网络模型越大,引入更多的权值参数,占用更多GPU显存;
2.参数数量越多,数据过度拟合的可能性就越大,网络就有可能不稳定,预测效果反而下降;
那么如何选择适当的隐层数呢?每层隐藏层的神经元数应该设置多少呢?这是一个工程问题,不同的数据会有不一样的结果,所以作者觉得神经网络的设计是一种工程艺术,我们需要去尝试、训练、预测、评估,才能最终决定整个网络模型的形态,感受深度学习的魅力所在。
在隐层我们需要一个激活函数,激活函数把输出层转换成为下一层的输入层。非线性的激活函数能够让我们去处理非线性的问题。常用的有tanh函数、sigmoid函数或者ReLUs函数。例子里我们选择使用tanh函数,你也可以尝试把tanh函数换成其他函数查看输出。
最后通过softmax分类器把激活函数的输出分数转换成为概率。
Softmax分类器
预测网络
人工神经网络的预测使用向前反馈操作,我们可以理解为激活函数和矩阵乘法的操作。假设输入x是二维,我们可以根据计算公式得到输出分类结果 ŷ :
z1=xW1+b1
a1=tanh(Z1)
z2=a1W2+b2
a2=ŷ =so