美文网首页大数据 爬虫Python AI SqlPython小哥哥
从头构建恶性肿瘤检测网络 | 100行Python代码理解深度学

从头构建恶性肿瘤检测网络 | 100行Python代码理解深度学

作者: 14e61d025165 | 来源:发表于2019-04-16 15:56 被阅读0次
    <tt-image data-tteditor-tag="tteditorTag" contenteditable="false" class="syl1555401272636 ql-align-center" data-render-status="finished" data-syl-blot="image" style="box-sizing: border-box; cursor: text; text-align: left; color: rgb(34, 34, 34); font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial; display: block;"> image

    <input class="pgc-img-caption-ipt" placeholder="图片描述(最多50字)" value="" style="box-sizing: border-box; outline: 0px; color: rgb(102, 102, 102); position: absolute; left: 187.5px; transform: translateX(-50%); padding: 6px 7px; max-width: 100%; width: 375px; text-align: center; cursor: text; font-size: 12px; line-height: 1.5; background-color: rgb(255, 255, 255); background-image: none; border: 0px solid rgb(217, 217, 217); border-radius: 4px; transition: all 0.2s cubic-bezier(0.645, 0.045, 0.355, 1) 0s;"></tt-image>

    在构建乳腺癌预测神经网络过程中,我们主要分为3大部分:

    1.用Python从零开始创建一个神经网络,并使用梯度下降算法训练模型。

    2.在该神经网络中使用威斯康星乳腺癌数据集,根据9种不同的特征,预测肿瘤是良性还是恶性的。

    3.探索反向传播和梯度下降算法的工作原理。

    在这个领域中,有很多大牛都通过视频和博文分享了自己掌握的专业知识,如fast.ai的Jeremy Howard、吴恩达、Andrej Karpathy、Yann Lecun等等。

    他们一致认为,深度学习的关键之一就是,尽快亲自动手编写一个深度学习的模型。当前,深度学习领域中有很多强大的库可供我们使用,如Tensorflow、 PyTorch、 Fast.ai、 Keras、 Mxnett、Nctk、DL4J 等。如果仅仅直接使用这些强大的库,我们可能会错过很多关键的东西,因此,我们需要进一步思考这些进程中最重要的那部分。

    如果能自己亲自动手编码创建一个神经网络,我们就不得不面对创建过程中出现的一些问题和障碍,挖掘深度学习背后隐藏的那些令人惊叹的知识。

    当前,深度学习领域中有各种各样的架构和开发:卷积神经网络、循环神经网络和生成对抗网络等等。在这些不同种类的网络背后,都包含了两个相同的算法:反向传播算法和梯度下降算法。

    探索神秘的函数

    如果你在学习Python的过程当中有遇见任何问题,可以加入我的python交流学习qq群:683380553,多多交流问题,互帮互助,群里有不错的学习教程和开发工具。学习python有任何问题(学习方法,学习效率,如何就业),可以随时来咨询我,如果你准备学习大数据,也欢迎加入大数据学习交流qq群683380553,每天与大家分享学习资源哦。

    宇宙中的很多事物都可以用函数表示。本质上来说,函数是一种数学结构,接受一个输入并产生一个输出,表示因果关系、输入输出关系。

    当我们审视周围的世界时,会接收到很多信息,我们将这些信息转化为数据,就可以从这些数据中学到很多知识。在利用这些数据进行学习的时候,会有很多不同的种类。通常来说,深度学习中有三种最常见的类型:

    1.监督学习:从一组有标签(已分类)的训练数据中学习函数,输入和输出是成对的数据集。

    2.非监督学习:从没有任何标签或分类的数据中学习到函数。

    3.强化学习:代理人会在特定环境中做出相应的动作,通过最大化代理人得到的奖励得到函数。

    监督学习

    本文中,我们主要关注监督学习。现在,我们有一个数据集,包含输入及对应的输出。下面,我们想了解这些输入和输出是如何通过一个神秘的函数联系起来的。

    当数据集达到一定的复杂度时,寻找这个函数的难度就相当大。因此,我们就需要使用神经网络和深度学习,来探索这个神秘的函数。

    本质上来说,神经网络通过一系列的中间“权重”连接我们的输入和期望输出数据。这些权重实际上就是一些数字。

    <tt-image data-tteditor-tag="tteditorTag" contenteditable="false" class="syl1555401272656 ql-align-center" data-render-status="finished" data-syl-blot="image" style="box-sizing: border-box; cursor: text; text-align: left; color: rgb(34, 34, 34); font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial; display: block;"> image

    <input class="pgc-img-caption-ipt" placeholder="图片描述(最多50字)" value="" style="box-sizing: border-box; outline: 0px; color: rgb(102, 102, 102); position: absolute; left: 187.5px; transform: translateX(-50%); padding: 6px 7px; max-width: 100%; width: 375px; text-align: center; cursor: text; font-size: 12px; line-height: 1.5; background-color: rgb(255, 255, 255); background-image: none; border: 0px solid rgb(217, 217, 217); border-radius: 4px; transition: all 0.2s cubic-bezier(0.645, 0.045, 0.355, 1) 0s;"></tt-image>

    当我们使用正确的架构和参数,通过神经网络的结构和优化算法,我们可将神经网络近似成一个通用函数近似器,将输入和输出数据联系起来。

    创建一个神经网络

    一般来说,简单的神经网络包括两层(输入不计入层数):

    1.输入:神经网络的输入包含了我们的源数据。并且,神经元的数量与源数据的特征数量相匹配。下图中有4个输入,当我们使用威斯康星乳腺癌数据集创建神经网络的时候,就会使用9个输入。

    2.第一层:隐藏层,包含一些隐藏层神经元,这些神经元将会与周围层中的所有单元相连接。

    3.第二层:有一个单元,为神经网络的输出。

    在实际的神经网络构建过程中,我们可以使用更多的层,比如10个或20个层的网络。为了简单起见,在这里,我们使用2个层。千万不要小看这2个层,它能够实现很多功能。

    <tt-image data-tteditor-tag="tteditorTag" contenteditable="false" class="syl1555401272661 ql-align-center" data-render-status="finished" data-syl-blot="image" style="box-sizing: border-box; cursor: text; text-align: left; color: rgb(34, 34, 34); font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial; display: block;"> image

    <input class="pgc-img-caption-ipt" placeholder="图片描述(最多50字)" value="" style="box-sizing: border-box; outline: 0px; color: rgb(102, 102, 102); position: absolute; left: 187.5px; transform: translateX(-50%); padding: 6px 7px; max-width: 100%; width: 375px; text-align: center; cursor: text; font-size: 12px; line-height: 1.5; background-color: rgb(255, 255, 255); background-image: none; border: 0px solid rgb(217, 217, 217); border-radius: 4px; transition: all 0.2s cubic-bezier(0.645, 0.045, 0.355, 1) 0s;"></tt-image>

    神经网络如何进行学习

    问题来了:在这个神经网络中,学习将在哪个部分进行?

    我们来回顾一下,我们在神经网络的输入层放置了一些数据,并向网络展示某个输入应该对应什么输出,也就是说,神经网络的输出(第2层)应该是什么结果。

    在神经网络中,每个神经元都有一个相关的权重以及一个偏差。这些权重只是神经网络在开始学习时候初始化的一些随机数字。

    神经网络根据输入数据和这些权重值进行计算,通过神经网络传播,直到输出产生最终的结果。

    这些计算的结果就是一个将输入映射到输出的函数。

    我们需要的就是,这些神经网络能够计算出一个最佳权重值。因为网络通过计算,不同的权重和不同的层结合起来,会近似出不同类型的函数。

    现在,我们来进一步探索正在探寻的函数。为了方便阅读,我们需要解释下这些变量的名称:

    1.X表示输入层,即提供给网络的数据集。

    2.Y表示与输入x对应的目标输出,由输入经过网络进行一系列的计算得到的输出。

    3.Yh(y hat)表示预测函数,即我们像网络提供输入数据集x后,经过神经网络一系列的计算产生的输出。因此,Y是理想的输出,Yh是神经网络接收到输入数据后产生的实际输出。

    4.W表示网络各层的权重。

    我们首先看第一层——隐藏层,它执行了一个运算W*X(即W和X的乘积)。

    <tt-image data-tteditor-tag="tteditorTag" contenteditable="false" class="syl1555401272671 ql-align-center" data-render-status="finished" data-syl-blot="image" style="box-sizing: border-box; cursor: text; text-align: left; color: rgb(34, 34, 34); font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial; display: block;"> image

    <input class="pgc-img-caption-ipt" placeholder="图片描述(最多50字)" value="" style="box-sizing: border-box; outline: 0px; color: rgb(102, 102, 102); position: absolute; left: 187.5px; transform: translateX(-50%); padding: 6px 7px; max-width: 100%; width: 375px; text-align: center; cursor: text; font-size: 12px; line-height: 1.5; background-color: rgb(255, 255, 255); background-image: none; border: 0px solid rgb(217, 217, 217); border-radius: 4px; transition: all 0.2s cubic-bezier(0.645, 0.045, 0.355, 1) 0s;"></tt-image>

    然后进行一个加权和:

    1.这一层中的每个单元都和前一层中的每个单元相连接。

    2.权重值存在于每个连接中。

    3.该层中每个单元的值都是由前一个层中每个单元的值*权重的总和,而该权重则是1中所得到的权重。

    从某种程度上来说,权重表示连接的强度,即:不同层之间单元连接的强度。

    现在,我们要在这个架构中添加一个额外的量——偏差:W*X+b。

    这个偏差能够给神经网络带来更多的灵活性,偏差允许网络“移动”单位的线性计算,加强网络学习这些函数的能力。

    b代表单位偏差项。

    我们看到,W*X+b就是一个线性方程,通过乘积与和运算表示输入和输出的线性关系。

    现在,我们的神经网络只有2层,但是请记住,一个神经网络可以有很多层,比如20个甚至200个。因此,我们用数字表述这些变量属于哪一层。这样一来,定义隐藏层(第1层)的线性方程则为:W1*X+b1,并为其输出命名为Z,表示某一层计算的输出。因此,我们得到如下方程:

    Z1=W1*X+b1

    注意,这个计算应该针对每个层的每个单元进行。当我们为神经网络编写代码的时候,我们将使用向量化编程,也就是说,利用矩阵将某一层的所有计算放在一个单一的数学运算中。

    上面所讲述的是只有一个层的神经网络。现在,我们考虑一个有很多层的神经网络,每个层执都执行一个类似上面的线性运算,当所有的线性运算连接在一起时,这个神经网络就能够计算复杂的函数了。

    激活函数

    然而,现在就有一个问题:线性函数——太简单了吧。

    这个世界是复杂的,因此,线性函数远远满足不了实际需求。一般来说,复杂的函数往往都是非线性的。而且,如果神经网络的架构仅仅由线性函数计算,那么就很难计算非线性行为。这就是为什么我们要在神经网络的每一层末尾加上一个额外的量:激活函数。现在,我们介绍4个最典型的例子。

    为了方便我们后续对激活函数进行深入探索,首先需要介绍梯度这一概念。一个函数在某一点上的梯度也称为函数的导数,表示该函数在该点输出值的变化率。

    我们来思考这样一个问题:当特定输入发生变化时,函数的输出会发生怎样的变化?

    当梯度(导数)非常小,即函数的输出变化非常平坦时,我们称之为梯度消失。在后边的反向传播算法中,我们可以通过梯度了解网络中每个参数将会如何影响网络的输出,从而就能够决定如何调整网络的权值,也就是说了解这个参数的变化将会使网络的输出增加还是减少?

    梯度消失是我们所面临的一个问题,因为如果某一点的梯度变化很小或趋于0,我们就很难确定该神经网络在该点的输出方向。

    当然,我们也会遇到相反的情况——梯度爆炸。当梯度值非常大时,神经网络可能就会变得非常不稳定。

    不同的激活函数有各自的优点,但是都会面临梯度消失和梯度爆炸这两大问题。

    <tt-image data-tteditor-tag="tteditorTag" contenteditable="false" class="syl1555401272682 ql-align-center" data-render-status="finished" data-syl-blot="image" style="box-sizing: border-box; cursor: text; text-align: left; color: rgb(34, 34, 34); font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial; display: block;"> image

    <input class="pgc-img-caption-ipt" placeholder="图片描述(最多50字)" value="" style="box-sizing: border-box; outline: 0px; color: rgb(102, 102, 102); position: absolute; left: 187.5px; transform: translateX(-50%); padding: 6px 7px; max-width: 100%; width: 375px; text-align: center; cursor: text; font-size: 12px; line-height: 1.5; background-color: rgb(255, 255, 255); background-image: none; border: 0px solid rgb(217, 217, 217); border-radius: 4px; transition: all 0.2s cubic-bezier(0.645, 0.045, 0.355, 1) 0s;"></tt-image>

    左上:Sigmoid激活函数;右上:Tanh激活函数;

    左下:Relu激活函数;右下:Leaky Relu激活函数

    (1)Sigmoid激活函数——1/(1+e-x)**

    1.输出范围:[0,1]。

    2.非线性,输出为两个极端变量0和1。适用于二分类问题。

    3.曲线变化温和,因此,梯度(导数)比较容易控制。

    4.该激活函数的主要缺点为:在极端情况下,函数的输出曲线变得非常平坦,也就是说,函数的导数(变化率)将变得非常小,在这种情况下,Sigmoid激活函数的计算效率和速度将会非常低,甚至会完全没效率。

    5.当Sigmoid激活函数出现在神经网络的最后一层时,将会特别有用,因为Sigmoid激活函数有助于将输出变为0或1(即二分类问题)。如果将Sigmoid激活函数放在神经网络的其他层,就会出现梯度消失问题。

    (2)Tanh激活函数——(2/(1+e-2x))-1**

    1.输出范围:[-1,1]。

    2.曲线和Sigmoid激活函数的曲线类似,是Sigmoid激活函数曲线的缩小版。

    3.Tanh激活函数曲线较为陡峭,因此,该激活函数的导数(变化率)比较大。

    4.Tanh激活函数的缺点与Sigmoid激活函数类似。

    (3)Relu激活函数——max (0,x)

    1.如果输入大于0,那么,输出值等于输入值;否则,输出为0。

    2.Relu激活函数的范围是[0,+∞),这就意味着输出可能是+∞,可能会存在梯度爆炸问题。

    3.优点:使神经网络轻量化,因为一些神经元可能输出为0,防止所有的神经元被同时激活。

    4.Relu激活函数存在一个问题,即输入为0的时候,输出全部为0,这将会导致梯度为0,会让我们忽视某些神经元的一些有用的计算。

    5.Relu激活函数计算简单,成本低廉。

    6.当前,Relu激活函数是神经网络内层最经常使用的激活函数。

    ï¼�4ï¼�   Leaky Relu激活函数——ex / Sum(ex)

    1.输出范围:[0,1]

    2.Leaky Relu激活函数将输入进行标准化处理为一个概率分布。

    3.通常用于多分类场景中的输出层。

    在这里,我们在输出层使用Sigmoid激活函数,在隐藏层使用Relu激活函数。

    好了,现在我们已经理解了激活函数,那么,就需要对其进行命名!

    A:表示激活函数的输出。

    因此,在神经网络的隐藏层中,将会进行如下计算:

    A1=Relu(Z1)

    Z1=W1*X+b1

    在第二层的输出层中,将会进行如下计算:

    A2=Sigmoid(Z2)

    Z2=W2*A1+b2

    请注意,第二层(输出层)的输入为第一层的输出,即A1。

    第二层的输出就是网络的最终输出。将上面的计算归纳一下,就得到2层神经网络所执行的全部计算:

    Yh = A2 = Sigmoid(W2ReLU (W1X+ b1) + b2 )

    <tt-image data-tteditor-tag="tteditorTag" contenteditable="false" class="syl1555401272696 ql-align-center" data-render-status="finished" data-syl-blot="image" style="box-sizing: border-box; cursor: text; text-align: left; color: rgb(34, 34, 34); font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial; display: block;"> image

    <input class="pgc-img-caption-ipt" placeholder="图片描述(最多50字)" value="" style="box-sizing: border-box; outline: 0px; color: rgb(102, 102, 102); position: absolute; left: 187.5px; transform: translateX(-50%); padding: 6px 7px; max-width: 100%; width: 375px; text-align: center; cursor: text; font-size: 12px; line-height: 1.5; background-color: rgb(255, 255, 255); background-image: none; border: 0px solid rgb(217, 217, 217); border-radius: 4px; transition: all 0.2s cubic-bezier(0.645, 0.045, 0.355, 1) 0s;"></tt-image>

    因此,本质上来说,神经网络是一连串的函数,有些是线性函数,有些是非线性函数,它们共同组成了一个复杂的函数,将我们的输入数据和想要的输出数据连接了起来。

    现在,我们注意到,在这个方程的所有变量中,W和b是两个未知数,这就是神经网络需要学习的地方。也就是说,神经网络必须进行不断的学习,找到W和b的正确值,才能计算出正确的函数。

    因此,我们训练神经网络的目的也变得明了了,即寻找W1,b1,W2,b2的正确值。但是,在开始训练神经网络之前,我们必须首先对这些值进行初始化,即用随机函数对其进行初始化处理。

    初始化以后,我们就可以对神经网络进行编码,我们使用Python构建一个类,对这些主要的参数进行初始化处理。

    我们将如何进行实战编码呢?请继续阅读我们的第二部分:用Python构建一个神经网络。

    相关文章

      网友评论

        本文标题:从头构建恶性肿瘤检测网络 | 100行Python代码理解深度学

        本文链接:https://www.haomeiwen.com/subject/yvibwqtx.html