提交 4f3b0959 编写于 作者: ToTensor's avatar ToTensor

add code

上级 25d61c35
<h1 class="firstTitle"><a >尾声 如何实现机器学习中的知识迁移及持续性的学习</a></h1>
<p class="content">在课程的最后,我想和同学们谈一谈机器的自我学习以及知识的积累,也就是如何让机器在尽可能少的人工干预下,完成持续性的学习。这个议题很大,我只是抛砖引玉。</p>
<p class="content">所谓机器的自我学习,也是一个模糊的概念,我们讲过的无监督学习、半监督学习、自监督学习、强化学习等都可以算作机器的自我学习。这是一个非主流却很重要的领域。为什么这么说呢?因为人类和动物的学习模式绝大多数情况下都是自我学习模式,其中的自我探索的价值要远超过监督和指导。从知识积累的角度来说,自我学习所能够积累的知识也远超监督学习。通过自我学习可以学习更多关于世界结构的知识:数据是无限的,每个例子提供的反馈量都很大。</p>
<p class="content">这种学习模式在自然语言处理方面取得了巨大成功。例如,通过BERT(一种双向训练的语言模型)这样的半监督式的NLP模型,机器能预测文本中缺失的单词、自动补全程序代码,甚至生成新的代码,这都是近期机器学习领域的新趋势。</p>
<p class="content">可以说,机器的自我学习能力越强,我们离强AI就越近。</p>
<p class="content_166">在线学习</p>
<p class="content">比如在线学习,一个典型例子是通过对用户购物篮的分析,推荐相关的商品,这就是一种典型的监督学习和机器的自我学习的结合。</p>
<p class="content_101"><img alt="" class="h-pic" src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0344-0445.jpg">咖哥发言</p>
<p class="content">推荐算法的实现方式,一是基于商品内容的推荐,把用户所购的近似商品推荐给用户,前提是每个商品都得有若干个标签,才可以知道其近似度。二是基于用户相似度的推荐,就是根据不同用户的购买历史,将与目标用户兴趣相同的其他用户购买的商品推荐给目标用户。例如,小冰买过物品<span class="italic">A</span><span class="italic">B</span><span class="italic">C</span>,我买过了商品<span class="italic">A</span><span class="italic">B</span><span class="italic">D</span>,于是将商品<span class="italic">C</span>推荐给我,同时将商品<span class="italic">D</span>推荐给小冰。</p>
<p class="content">传统的训练方法基于固定的训练集,模型上线后,一般是静态的,不会与线上的数据流有任何互动。假设预测错了,或者推荐得不合适,只能等待进一步积累聚集,并在下次系统更新的时候完成修正。</p>
<p class="content">在线学习要求系统能够更加及时地反映线上变化,它是机器学习领域中常用的技术,也就是一边学着,一边让新数据进来。大型电商网站的机器学习都是在线学习。例如,在亚马逊上购书之后,马上就会有相关新书推荐给我们。这种学习的训练集是动态的、不断变化的,呈现出一种数据流的性质。因此,算法也需要动态适应数据中的新模式,在每个步骤中更新对未来数据的最佳预测,实时快速地进行模型调整,提高线上预测的准确率。尤其是与用户交互这一块,在将模型的预测结果展现给用户的同时收集用户的反馈数据,再用来继续训练模型,及时做出修正。</p>
<p class="content">例如某网上书店的推荐系统的实现,首先通过普通的机器学习模型,根据系统已有数据(如图书的特征信息)和用户的历史行为,向用户推荐其可能感兴趣的书,然后通过在线排序模型对书进行交互式排序。考虑到用户往往是使用移动端设备,每次看到的推荐条目很少,因此前面几个排序项的作用更突出。系统会在线监控用户的选择。假设用户单击了第<span class="italic">n</span>个条目,系统将只保留第<span class="italic">n</span>个条目前后几条数据作为训练数据,其他的就丢弃,以确保训练集中的数据是用户已经看到的。而且系统还将实时增加用户刚刚选择的书的权重。</p>
<p class="content_166">迁移学习</p>
<p class="content">另一个需要思索的机器学习发展方向是如何在机器学习过程中进行知识的积累。</p>
<p class="content">机器学习的经典模式是:在给定一个数据集上,运行一个机器学习算法,构建一个模型,然后将这个模型应用在实际的任务上。这种学习模式被称为<span class="bold">孤立学习</span>,因为它并未考虑任意其他相关的信息和过去学习的知识。孤立学习的缺点在于没有记忆,即它没有保留学到的知识,并应用于未来的学习。因此它需要大量的训练样例。</p>
<p class="content">然而,纵观人类发展的历史,之所以人类能够发展出如此辉煌的文化,筑成如此复杂的科学宫殿,其中语言和文字对于知识的保存和传续功不可没。人类是以完全不同的方式进行学习的。我们从不孤立地学习,而是不断地积累过去学习的知识,并无缝地利用它们学习更多的知识。随着时间的增长,人类将会学习越来越多的知识,而且越来越善于学习。</p>
<p class="content">机器学习中的迁移学习,意味着知识的积累,它存储已有问题的解决模型,并将其利用在其他不同但相关的问题上。这是一个很有意思的思路,因为这意味着我们将站在“巨人”肩上去学习。</p>
<p class="content">一个最典型的迁移学习的例子就是利用已经训练好的大型卷积网络,进行微调之后来实现自己的机器学习任务。</p>
<p class="content">这个知识迁移过程并没有我们想象的那么困难。现在就来试着运行一个实例。请看下面的代码:</p>
<div class="content_106">
<p class="content_105">from keras.applications import VGG19 # 基网络是VGG19</p>
<p class="content_105">from keras import models # 导入模块</p>
<p class="content_105">from keras import layers # 导入层</p>
<p class="content_105">from keras import optimizers # 导入优化器</p>
<p class="content_105"># 预训练的卷积基</p>
<p class="content_105">conv_base = VGG19(weights='imagenet', include_top=False,</p>
<p class="content_131">input_shape=(150, 150, 3))</p>
<p class="content_105">conv_base.trainable = True # 解冻卷积基</p>
<p class="content_105"># 冻结其他卷积层, 仅设置block5_conv1可训练</p>
<p class="content_105">set_trainable = False</p>
<p class="content_105">for layer in conv_base.layers:</p>
<p class="content_111">if layer.name == 'block5_conv1':</p>
<p class="content_139">set_trainable = True</p>
<p class="content_111">if set_trainable:</p>
<p class="content_105">layer.trainable = True</p>
<p class="content_111">else:</p>
<p class="content_139">layer.trainable = False</p>
<p class="content_105">model = models.Sequential()</p>
<p class="content_105">model.add(conv_base) # 基网络的迁移</p>
<p class="content_105">model.add(layers.Flatten()) # 展平层</p>
<p class="content_105">model.add(layers.Dense(128, activation='relu')) # 微调全连接层</p>
<p class="content_105">model.add(layers.Dense(10, activation='sigmoid')) # 微调分类输出层</p>
<p class="content_105">model.compile(loss='binary_crossentropy', # 交叉熵损失函数</p>
<p class="content_119"># 为优化器设置小的学习速率, 就是在微调第5卷积层的权重</p>
<p class="content_119">optimizer=optimizers.adam(lr=1e-4),</p>
<p class="content_119">metrics=['acc']) # 评估指标为准确率</p>
<p class="content_105">model.fit(X_train, y_train, epochs=2, validation_split=0.2) # 训练网络</p>
<p class="content_105">model.add(layers.Dense(10, activation='softmax'))</p>
</div>
<p class="content">这段简单的代码就实现了在有名的大型卷积网络VGG19基础之上的微调。我们可以拿这个新模型来训练我们的任何图像集。</p>
<p class="content">微调之后的属于我们的新模型如下图所示。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0346-0446.jpg">
<p class="imgtitle">基于VGG19网络的迁移学习模型</p>
</div>
<p class="content">新模型结构如下图所示。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0346-0447.jpg">
<p class="imgtitle">程序编译出来的基于VGG19迁移形成的新模型结构</p>
</div>
<p class="content">Keras中预置的成熟模型有很多,除了VGG外,你们也可以试试Res Net、Inception、Inception-ResNet、Xception等,这些已经在大型图像库如Image Net中“千锤百炼”过的大型卷积网络,都可以直接迁移至你们自己的机器学习模型。</p>
<p class="content">下面代码中给出了多种Keras提供的可迁移的基网络:</p>
<div class="content_167">
<p class="content_105">from keras.applications import ResNet50</p>
<p class="content_105">from keras.applications import Inception V3</p>
<p class="content_105">from keras.applications import Mobile Net V2</p>
<p class="content_105">from keras.applications import Xception</p>
<p class="content_105">from keras.applications import VGG16</p>
<p class="content_105">from keras.applications import VGG19</p>
</div>
<p class="content">迁移学习,不仅限于卷积网络,像BERT这样的NLP模型,也可以下载下来,进行微调后复用。</p>
<p class="content_166">终身学习</p>
<p class="content">通过迁移学习,我们在知识积累的路上迈出了一大步。迁移学习假设源领域有大量已经标注的训练数据,目标领域有很少或者根本没有标注的训练数据,但是有很多未标注的训练数据。迁移学习利用源领域已经标注的数据来帮助目标领域完成学习任务。</p>
<p class="content">然而,迁移学习还不能算是持续性地学习,它仅仅是利用源领域来帮助目标领域的单向学习过程。迁移学习在知识积累方面是有局限性的,因为<span class="bold">迁移学习假设源领域与目标领域是很相似的</span></p>
<p class="content">而终身学习(lifelong learning)没有这么强的假设,使用者通常也不参与决定任务的相似性。</p>
<p class="content">对于监督学习而言,大量的训练数据通常是手工标注得到的,这样既费时又费力。但是现实世界中存在很多的学习任务,为了学习一个机器学习模型,对每个任务都手工标注大量的训练数据是不可能的。</p>
<p class="content">而且,事情总是处在不断变化中的,因而需要不停地标注训练数据,这显然是无法完成的任务。对建立真正的智能系统而言,当前的孤立学习是不合适的,其仅可被用于解决具体领域的任务。</p>
<p class="content">机器的终身学习就是模仿人类的这种学习过程和能力。由于我们周围的事物都是紧密相关和相互联系的,因此这种学习方式更为自然。</p>
<p class="content">因为过去学习的概念和关系可以帮助我们更好地理解和学习一个新的任务,所以终身学习是一个持续学习过程,模型应该可以利用其知识库中的先验知识来帮助学习新任务。知识库中存储和维护过去的任务中学习和积累的知识。知识库也会根据新任务中学习的中间或最终结果进行更新。</p>
<p class="content">终身学习包括以下主要特征。</p>
<p class="content">■持续学习。</p>
<p class="content">■知识被积累到知识库。</p>
<p class="content">■利用过去学习的知识,来帮助解决未来的学习问题。</p>
<p class="content">当然,这里进行的只是理念上的探讨,对于自我学习、迁移学习、终身学习这些比较接近“强人工智能”领域的主题,目前仍处在刚刚起步探索的阶段,技术和实践上远远没有监督学习那么成熟。</p>
<p class="content_105">-----------------------------------------------------------------</p>
<p class="content_105">不知不觉间,到了真要说再见的时候。咖哥说会送给每位同学一本书,作为纪念。</p>
<p class="content_105">小冰看到,这是本非常有名的书—《高效能人士的七个习惯》。</p>
<p class="content_105">咖哥说:“这本书,是我很喜欢的一本书,也可以说陪伴了我的生活、工作和学习。我时常会把它赠送给同事和朋友们。不过,我肯定是没有时间给大家介绍每一个习惯了。但是,允许我说一下这七个习惯里面的最后一个习惯:<span class="bold">不断更新</span>。不断更新,其实也就是<span class="bold">终身学习</span>。说的是<span class="bold">如何在四个生活面向(生理、社会、情感、心智)中,不断更新自己</span>。这个习惯好比梯度提升机一样推着人持续成长。只有不断更新、不断完善自我,人才不致老化及呈现疲态,才总是能踏上新的路径,迎接新的天地。”</p>
<p class="content_105">“同学们,在AI来临的时代,机器尚且能够自我更新、自我学习,我们人类更应时时刻刻记住持续学习、不断成长的重要性。”</p>
<p class="content_105">“成长,不是负担,而是一种常态、一种快乐。”</p>
<p class="content_105">“再见喽,同学们。”</p>
<p class="content_105">小冰和其他同学有些恋恋不舍地往课堂外面走去。</p>
<p class="content_105">“哎,小冰,等一等!还有一件事!”咖哥叫住小冰,“你的新项目几个月做完?3个月?好!3个月之后,你回来给我上上课,分享经验。”</p>
<p class="content_105">小冰说:“啊?!不可能吧。”</p>
<p class="content_105">咖哥说:“怎么不可能,完全有可能。两千多年前的孔子都认为‘三人行,必有我师焉’,在现在这个时代,更是任何人都有可能成为我的老师。好了,再见!”</p>
<p class="content_105">-----------------------------------------------------------------</p>
\ No newline at end of file
<h1 class="firstTitle"><a >引子 AI菜鸟的挑战——100天上线智能预警系统</a></h1>
<p class="content_105">小冰,“90后”,研究生毕业,非资深程序员,目前在一家软件公司工作。工作虽忙但尚能应付,还和朋友合伙开了一个网店。她的生活风平浪静。</p>
<p class="content_105">故事从大老板今天早晨踏进她们项目组这一刻开始。</p>
<p class="content_105">她到公司比别人早,刚刚收拾了一下混乱的房间,正要打开电脑,大老板进来了。</p>
<p class="content_105">“小冰,你们经理呢?还没来吗?这都10点了!”老板似乎生气了。</p>
<p class="content_105">小冰说:“昨天经理带着我们赶进度,到晚上12点多才走,可能今天要晚到一会儿。”</p>
<p class="content_105">“唉,算了。不等他了。就你吧,你跟我过来一下。还有你们两个,”老板指着其他项目组的另外两个同事说,“也来一下。”</p>
<p class="content_105">到了会议室,老板开口了:“我这边有一个很紧急、也很重要的项目哈。合作方是老客户了,因为信任咱们,才直接交给咱们。但是时间非常非常紧,100天内必须上线。我琢磨着你们手头上的几个项目都在收尾阶段了,本来是准备跟你们经理商量,抽调一两个人做这个新项目。但是他们又都迟到,我这儿又着急。算了,我也不和他们商量了,就定你们几个吧!”说完,又补了一句:“叫他们带头迟到!”</p>
<p class="content_105">小冰和其他几位同事面面相觑。</p>
<p class="content_105">过了3秒,小冰弱弱地问:“请问是什么方面的项目?”</p>
<p class="content_105">老板答:“<span class="bold">人工智能!</span></p>
<p class="content_105">小冰他们吓了一跳。</p>
<p class="content_105">老板接着说:“不是让你们去研发一个会端茶倒水的机器人。具体讲,是<span class="bold">机器学习</span>方面的项目。机器学习,听说过吗?属于人工智能的一个分支领域,最近是热得很呢。这是一个银行客户,他们的信用卡申请系统是我们前年做的,现在也开始做大数据和机器学习的项目了。这次是请我们给他们做一个诈骗行为预警的应用,根据现有的数据智能化地判断哪些客户可能存在欺诈性的刷卡行为。这个项目如果完成得好,他们还会继续开发一个人脸识别应用,加入信用卡的申请验证过程,那就需要<span class="bold">深度学习</span>的技术了。深度学习也算是机器学习的分支吧。”</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0018-0005.jpg">
<p class="imgtitle">小冰被新项目吓了一跳</p>
</div>
<p class="content_105">老板一谈起项目,那是滔滔不绝啊!停都停不下来。但是几个听众有点觉得云山雾罩的。</p>
<p class="content_105">“可是……这些技术我们都不懂啊……”几人在同一时间表达了同一个意思。</p>
<p class="content_105"><span class="bold">学啊!</span>”老板说。</p>
<p class="content_105">“有那么容易吗?”一个比较大胆的同事问,“我看过一些机器学习的文档,也买过几本书,里面的数学公式、算法,难度可不低啊,我一个专业程序员都感觉看不大懂。”</p>
<p class="content_105">“嗯,这样啊……” 老板思索了一下,“我倒觉得这机器学习项目,门槛没有你们想象的那么高。以你们目前的编程背景和数学知识,如果学习路线正确,应该可以快速上手。不过,我其实也考虑到这点了,如果没有一个适当的培训来引导你们,完全自学的话应该还是挺艰苦的。我安排了一个短期培训,找的是专家,一个在大厂任资深数据科学家的朋友。让他带一带你们,先入门。据他说,他的第一个机器学习项目也是临危受命,同样是半年之内从不懂到懂,‘摸爬滚打’几个月之后,最终完成了。因此,几个月搞定这个项目不算是开玩笑。我们做IT的,哪个项目不是这样边学边做拼出来的?”</p>
<p class="content_105">紧接着老板大手一挥,斩钉截铁地说:“好,这事儿就这么定了!这是好事,别人想要做这机器学习项目还没机会呢。”</p>
<p class="content_105">“明天开始机器学习培训!”</p>
<p class="content_105">这样,小冰似乎不是很情愿,而又幸运地开启了她的机器学习之旅。</p>
\ No newline at end of file
<h1 class="firstTitle"><a >彩插</a></h1>
<div class="bodyPic_104">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0356-0449.jpg">
</div>
<div class="bodyPic_104">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0357-0450.jpg">
</div>
<div class="bodyPic_104">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0358-0451.jpg">
</div>
\ No newline at end of file
<p class="content_105">咖哥问:“刚才我们进行了一次简单的机器学习项目实战,并且介绍了几个Jupyter Notebook开发平台。现在考一考同学们已经学过的内容。谁能说说机器学习的定义是什么?”</p>
<p class="content_105">一位同学回答:“<span class="bold">机器学习,就是机器基于输入数据集中的信息来训练、确立模型,对以前从未见过的数据做出有用的预测</span>。”</p>
<p class="content_105">咖哥说:“总结得不错。下面给出机器学习中其他一些基本术语的定义,如表1-1所示。”</p>
<div class="pic_115">
<p class="imgtitle">表1-1 机器学习的基本术语</p>
<img alt="" src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0043-0040.jpg">
</div>
<p class="content">再稍微详细地说一说上表中最为重要的3个术语:特征、标签和模型。</p>
<h3 class="thirdTitle" id="bw16"><a >1.3.1 特征</a></h3>
<p class="content">特征是机器学习中的输入,原始的特征描述了数据的属性。它是有维度的。<span class="bold">特征的维度指的是特征的数目</span>(不是数据集里面样本的个数),不同的数据集中的数据特征的维度不同,有多有少。</p>
<p class="content">■少,可以少到仅有一个特征,也就是一维特征数据。比如房价(标签)仅依据房屋面积(特征)而定。</p>
<p class="content">■多,可以多到几万,几十万。比如一个100px×100px的RGB彩色图片输入,每一个像素都可以视为一个特征,也就是1万维,再乘以RGB 3个颜色通道,那么这个小小的图片数据的特征维度就可以达到3万维。</p>
<p class="content">举例来说,如果预测商品的销量,把商品的类别、价格和推荐级别这3个属性定义为商品的特征,那么这个数据集就是三维特征数据集。其中的一个样本的格式如下:</p>
<p class="content"><span class="italic">x</span><span class="sub">1</span><span class="italic">x</span><span class="sub">2</span><span class="italic">x</span><span class="sub">3</span></p>
<p class="content">然而,所谓三维特征,其实只是二维数据结构中的一个轴(另一个轴是样本轴)上的数据个数。为了避免混淆,我们以后会把向量、矩阵和其他张量的维度统称为<span class="bold"></span>,或者称为1D向量、2D矩阵、3D张量等。因此,以后<span class="bold">一提“维”,主要指的就是数据集中特征</span><span class="italic">X</span><span class="bold">的数目。</span>一般来说,<span class="bold">特征维度越高,数据集越复杂</span>。这里的“维”和“阶”有点绕,以后还会反复强调。</p>
<p class="content_101"><img alt="" class="h-pic" src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0044-0041.jpg">咖哥发言</p>
<p class="content">这里提到的<span class="bold">张量</span>是机器学习的数据结构,其实也就是程序中的数组。在第2课中,才会很详细地讲解各种张量的结构。向量、矩阵都是张量的一种。简单地理解,向量张量是一个1D数组,而矩阵张量是一个2D数组。</p>
<h3 class="thirdTitle" id="bw17"><a >1.3.2 标签</a></h3>
<p class="content">标签,也就是机器学习要输出的结果,是我们试图预测的目标。示例里面的标签是房价。实际上,机器学习要解决什么问题,标签就是什么。比如:未来的股票价格、图片中的内容(猫、狗或长颈鹿)、文本翻译结果、音频的输出内容、Alpha Go的下一步走棋位置、自动导购汽车的行驶方向等。</p>
<p class="content">下面是一个有标签数据样本的格式:</p>
<p class="content"><span class="italic">x</span><span class="sub">1</span><span class="italic">x</span><span class="sub">2</span><span class="italic">x</span><span class="sub">3</span><span class="italic">y</span></p>
<p class="content">标签有时候是随着样本一起来的,有时候是机器推断出来的,称作<span class="bold">预测标签</span><span class="italic">y'</span>(也叫y-hat,因为那一撇也可放在<span class="italic">y</span>的上方,就像是戴了一个帽子的<span class="italic">y</span>)。比较<span class="italic">y</span><span class="italic">y'</span>的差异,也就是在评判机器学习模型的效果。</p>
<p class="content">表1-2显示的是刚才实战案例中加州房价数据集中的部分特征和标签。</p>
<div class="pic_115">
<p class="imgtitle">表1-2 加州房价数据集中的特征和标签</p>
<img alt="" src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0044-0042.jpg">
</div>
<p class="content">并不是所有的样本都有标签。在无监督学习中,所有的样本都没有标签。</p>
<h3 class="thirdTitle" id="bw18"><a >1.3.3 模型</a></h3>
<p class="content">模型将样本映射到预测标签<span class="italic">y'</span>。其实模型就是函数,是执行预测的工具。函数由模型的内部参数定义,而这些内部参数通过从数据中学习规律而得到。</p>
<p class="content">在机器学习中,先确定模型的类型(也可以说是算法),比如是使用线性回归模型,还是逻辑回归模型,或者是神经网络模型;选定算法之后,再确定模型的参数,如果选择了线性回归模型,那么模型<span class="italic">f</span><span class="italic">x</span>) = 3<span class="italic">x</span> + 2中的3和2就是它的参数,而神经网络有神经网络的参数。类型和参数都确定了,机器学习的模型也就最终确定了。</p>
<p class="content">大家有没有想过,为什么Python不知不觉中成了最流行的机器学习语言之一?</p>
<h3 class="thirdTitle" id="bw20"><a >1.4.1 为什么选择用Python</a></h3>
<p class="content">Python像Java、C++、Basic一样,是程序员和计算机交互的方式。</p>
<p class="content">但是,为什么选择用Python。有句话大家可能都听过:人生苦短,Python是岸。</p>
<p class="content">这话什么意思呢?Python易学、易用、接地气。这就好比一个学编程的人,在程序设计的海洋里面遨游,游啊,游啊,总觉得这海实在太浩瀚了,找不着北。突然发现了Python这种语言,就上岸了……</p>
<p class="content">Python是一种很简洁的语言,容易写、容易读,而且在机器学习方面有独特的优势。</p>
<p class="content">机器学习的目的是解决实际问题,而不是开发出多强大的应用软件。因此,编写程序代码是工具而非目的,追求的是方便。搞数据科学和机器学习的人并不一定都是资深程序员,他们希望将自己头脑中的公式、逻辑和思路迅速转化到计算机语言。这个转化过程消耗的精力越少越好,而程序代码就不需要有多么高深、多么精致了。</p>
<p class="content">而Python正是为了解决一个个问题而生的,比如数据的读取、矩阵的点积,一个语句即可搞定,要是用传统的C++、Java,那还真的很费力气。还有切片、广播等操作,都是直接针对机器学习中的数据结构—张量而设计的。</p>
<p class="content">上面说的数据操作如此容易,很大程度上也是Num Py的功劳,我们以后还会反复提到Num Py这个数学函数库(扩展包)。因此,另外特别重要的一点就是Python的开发生态成熟,除Num Py外,还有非常多的库,这些库就是机器学习的开放框架。有很多库都是开源的,拿来就可以用。</p>
<p class="content">综上,便捷和实用性强似乎是Python的天然优势。我觉得Python和一些老牌语言相比,有点像口语和文言文的区别,文言文虽然高雅,但是不接地气。因为Python接地气,所以用户社群强大、活跃。机器学习圈的很多大咖们也隶属于这个Python社群,开发了很多优质的库。这样一来Python在AI时代,搭着数据科学和机器学习顺风车,弯道超车Java和C++,成了最流行的编程语言之一。</p>
<h3 class="thirdTitle" id="bw21"><a >1.4.2 机器学习和深度学习框架</a></h3>
<p class="content">大家可能听说过机器学习和深度学习“框架”这个名词,这个框架的作用可是很大的。想象一下,有一天老板说:“来,给你们一个任务,用机器学习的方法给咱们这些图片分类。”你们去Google查询了一下,发现这种图片分类任务用卷积神经网络来解决最好。但是你们很疑惑从头开始编写一个卷积神经网络是好做法吗?</p>
<p class="content">Python的机器学习框架,也就是各种Python库,里面包含定义好的数据结构以及很多库函数、方法、模型等(即API)。我们只需要选择一个适合的框架,通过调用其中的API,编写少量代码,就可以快速建立机器学习模型了。为什么刚才的机器学习实战中只用了不到20行代码就能够完成预测加州房价这么“艰巨”的任务?其中最大的秘密就是使用了框架中的API。</p>
<p class="content">良好的框架不仅易于理解,还支持并行化计算(即硬件加速),并能够自动计算微分、链式求导(“不明觉厉”是吧?不要紧,正因为框架把这些都做了,同学们就无须自己做这些不懂的东西)。</p>
<p class="content">下图中,给出了8个机器学习中常用的库。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0046-0043.jpg">
<p class="imgtitle">8个机器学习常用的库</p>
</div>
<p class="content">这8个库,可分为3大类:Pandas和Num Py提供数据结构,支持数学运算;Matplotlib和Seaborn用于数据可视化;后面4个库提供算法,其中的Scikit-learn是机器学习框架, Tesnsor Flow、Keras和Py Torch则是深度学习框架,可以选择一个来用。另有一些曾经有影响力的框架,如Theano、Caffe、CNTK等,随着“江山代有才人出”,使用率已经大大下降。而新的更方便的库呢?那也一定会继续涌现。</p>
<p class="content">下面分别简单说说它们。</p>
<p class="content_101">1.Pandas</p>
<p class="content">我们已经使用过Pandas了!请回头看一下第一个机器学习项目的第一行代码,如下段代码所示。通过这一行代码,就可以把整个Pandas中的所有函数、数据结构导入当前机器学习程序的运行环境。</p>
<p class="content_114">import pandas as pd #导入Pandas, 用于数据读取和处理</p>
<p class="content">Pandas是基于Num Py的数据分析工具,里面预置了大量库函数和标准数据结构,可以高效地操作大型数据集。Pandas,连同其下层的Num Py,是使Python成为强大而高效的数据分析工具的重要因素之一。</p>
<p class="content">Pandas中的预置数据结构有下面几种。</p>
<p class="content">■Series:1D数组,它与Num Py中的一维数组(array)类似。这两者与Python基本的数据结构列表(list)也很相似。</p>
<p class="content">■Time Series:以时间为索引的Series。</p>
<p class="content">■Data Frame:2D的表格型数据结构,Series的容器。</p>
<p class="content">■Panel:3D的数组,Data Frame的容器。</p>
<p class="content">我们这个课程里面Pandas数据结构用得不多,只用到了2D的数据结构Data Frame,这种数据结构用来存储表格式的数据非常方便,可以直接被机器学习模型所读取。比如,刚才的加州房价机器学习项目,就先把数据文件读入一个Data Frame,然后把Data Frame导入了线性回归模型进行学习。</p>
<p class="content_101">2.Num Py</p>
<p class="content">Num Py是Python进行科学计算的基础库,有人称它为Python的数学扩展包。它提供了一个强大的多维数组对象array,还提供了大量API支持数组运算。</p>
<p class="content_101">本课程中将重点使用的数据结构就是Num Py中的数组。</p>
<p class="content">Num Py所自带的向量化运算功能在机器学习中也属于不可或缺的技能。目前的CPU和GPU都有并行处理的处理器,能够无缝衔接Num Py的向量化运算,大幅度提升机器学习的效率。</p>
<p class="content">后面我们会专门讲Num Py的数组(在机器学习中称为张量)及其基本运算这部分内容。</p>
<p class="content_101">3.Matplotlib</p>
<p class="content">Matplotlib是Python及其数学扩展包Num Py的可视化操作界面,通过应用程序接口(API)向应用程序提供嵌入式绘图功能。其中还有面向其他图像处理库(如开放图形库Open GL)的接口。</p>
<p class="content">Matplotlib的设计与MATLAB的绘图功能非常相似(名字都很相似!),然而它是开源的、免费的。这自然令大家觉得物超所值。</p>
<p class="content">Matplotlib好用又强大。刚才的实战过程中导入Matplotlib的绘图工具后,通过短短几行代码,就把加州房价分布的散点图和机器学习到的模型呈现出来了。</p>
<p class="content_101">4.Seaborn</p>
<p class="content">Seaborn是在Matplotlib基础上设计出的绘图库,因此是更高级的视觉化工具,可以画出特别酷炫的数学统计图形。</p>
<p class="content_101">5.Scikit-learn</p>
<p class="content">Scikit-learn刚才也已经用过了,如下段代码所示。用于预测加州房价的机器学习模型Linear Regression就是直接从那儿“拎”出来的。</p>
<div class="content_106">
<p class="content_105">from sklearn.linear_model import Linear Regression #导入线性回归算法模型</p>
<p class="content_105">model = Linear Regression() #使用线性回归算法</p>
</div>
<p class="content">它简称Sklearn,是一个相当强大的Python机器学习库,也是简单有效的数据挖掘和数据分析工具。Sklearn基于Num Py、Sci Py和Matplotlib构建,其功能涵盖了从数据预处理到训练模型,再到性能评估的各个方面。</p>
<p class="content">Scikit-learn真的太好用了,它里面包含的大量可以直接使用的机器学习算法,这节省了很多时间。因为不必重复编写算法,更多的精力可以放在问题定义、数据分析、调整参数、模型性能优化等这些具体项目相关的工作上面。<span class="bold">本课程的机器学习模型,大多通过调用Scikit-learn库来实现。</span></p>
<p class="content_101">6.Tensor Flow</p>
<p class="content">Sklearn是机器学习的工具集,而Tensor Flow则是深度学习的设计利器。据说Google主要产品的开发过程都有Tensor Flow的参与,并且它以某种形式进行机器学习。很惊讶吧。</p>
<p class="content">但对于新手来说有个小小遗憾:Tensor Flow编程建立在“图”这个抽象的概念之上,据说其难度比起其他的深度学习框架更高,至少要研究几天才能搞清楚入门内容。这太耗时了!我们学机器学习和深度学习,目标是几个小时以内上手。因此,本课程的案例不采用Tensor Flow进行设计。</p>
<p class="content_105">小冰焦急地问:“你不是说Tensor Flow是很强大的深度学习工具吗?不用Tensor Flow,那你用什么讲课?”</p>
<p class="content_105">咖哥回答:“Keras!”</p>
<p class="content_101">7.Keras</p>
<p class="content">Keras建立在TensorFlow、CNTK或Theano这些后端框架之上。这也就是说,Keras比TensorFlow更高级。在计算机领域,高级是“<span class="bold">简单</span>”的代名词。高级意味着易学易用。</p>
<p class="content">Keras才出来没两年时,就已经大受欢迎,到现在已经是除Tensor Flow外最流行的、排行第二位的深度学习框架。</p>
<p class="content">搞机器学习的人,就喜欢简单易用的工具。</p>
<p class="content">其实,写Keras的时候是在对其后端进行调用,相当于还是在Tensor Flow上运行程序,只不过将程序经过Keras中转了一下变成Tensor Flow听得懂的语言,再交给Tensor Flow处理。</p>
<p class="content">鉴于Keras易用且高效的特点,<span class="bold">本课程的深度学习模型,都使用Keras来实现。</span></p>
<p class="content_101">8.Py Torch</p>
<p class="content">Py Torch是Tensor Flow的竞争对手,也是一个非常“优雅”的机器学习框架。相对Tensor Flow而言,Facebook开发的Py Torch上手相对简单一些,里面所有的算法都是用Python写的,源码也很简洁。近期Py Torch用户量的增长也是相当迅速的。</p>
<p class="content">同学们,祝贺大家终于学完了这最为基础的一课。万事开头难,本课中理论的东西有点多,目前大家理解起来应该是挺辛苦的。因为基于长期实践总结出来的东西,对于没有上过手的人来说,难免学起来是一头雾水。这是正常的现象。也许上完全部课程后,回过头来复习,你们会有更多的感悟。</p>
<p class="content">下面是本课中的重点内容。</p>
<p class="content">(1)首先是机器学习的内涵:机器学习的关键内涵在于从大量的数据中发现一个“模型”,并通过它来模拟现实世界事物间的关系,从而实现预测或判断的功能。</p>
<p class="content">■从这个定义出发,机器学习可以分为监督学习、无监督学习、半监督学习,以及深度学习、强化学习等类型。这些学习类型之间的界限是比较模糊的,彼此之间有交集,也可以相互组合。比如,深度学习和强化学习技术同时运用,可以形成深度强化学习模型。</p>
<p class="content">■我们也给出了最基本的机器学习术语,如特征、标签和模型等。</p>
<p class="content">(2)通过在线的Jupyter Notebook,可以方便快捷地进行机器学习实战。Colab和Kaggle,是两个提供免费Jupyter Notebook的平台,可以在其中通过Python编写机器学习源代码。</p>
<p class="content">机器学习是一个有很强共享精神的领域,不仅免费在线开发工具多,无论是数据集、算法,还是库函数和框架方面,都有很多开源的项目可供选择。</p>
<p class="content">■Scikit-learn是重点介绍的机器学习算法库。</p>
<p class="content">■Keras是重点介绍的深度学习算法库。</p>
<p class="content">(3)最后给出了机器学习项目实战流程中的5个环节,指导我们进行实战,具体包括问题定义、数据的收集和预处理、选择机器学习模型、训练机器,确定参数、超参数调试和性能优化,如下图所示。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0061-0056.jpg">
<p class="imgtitle">不断优化,找到最佳模型</p>
</div>
<p class="content">总而言之,机器学习实战的各个环节就像机器学习模型训练一样,是一个反复迭代的过程。只有不断优化,才能找到最完善的模型、达到最佳状态,这也是符合敏捷(agile)和Dev Ops那种快捷的、迭代式IT产品开发原则的。其秘密就是:迅速拿出一个可用产品的雏形,然后持续完善它。嗯,跑题了,下课吧。不过,别忘记完成课后的练习哦。</p>
<div class="content_120">
<p class="content">练习一 请同学们列举出机器学习的类型,并说明分类的标准。</p>
<p class="content">练习二 解释机器学习术语:什么是特征,什么是标签,什么是机器学习模型。</p>
<p class="content">练习三 我们已经见过了Google中的加州房价数据集和Keras自带的MNIST数据集,请同学们自己导入Keras的波士顿房价(boston_housing)数据集,并判断其中哪些是特征字段,哪些是标签字段。</p>
<p class="content">(提示:使用语句from keras.datasets import boston_housing导入波士顿房价数据集。)</p>
<p class="content">练习四 参考本课中的两个机器学习项目代码,使用Linear Regression线性回归算法对波士顿房价数据集进行建模。</p>
</div>
<hr>
<p class="noindent" id="annot2"><a >[1].</a>肖莱.Python深度学习[M].张亮,译.北京:人民邮电出版社,2018.</p>
<p class="noindent" id="annot3"><a >[2].</a>从本节开始,所有正文文字除小冰和同学们的提问之外,都是咖哥课程讲述内容,为保证真实课堂体验,将以咖哥为第一人称叙述。其中的“我”均指代咖哥。</p>
<p class="noindent" id="annot4"><a >[3].</a>Magnus Lie Hetland.Python基础教程(第3版)[M].袁国忠,译.北京:人民邮电出版社,2018.</p>
<p class="noindent" id="annot5"><a >[4].</a>HARRINGTON P.机器学习实战[M].李锐,李鹏,曲亚东等译.北京:人民邮电出版社:2013.</p>
<p class="noindent" id="annot6"><a >[5].</a>FLACH P.机器学习[M].段菲,译.北京:人民邮电出版社:2016.</p>
<p class="noindent" id="annot7"><a >[6].</a>肖莱.Python深度学习[M].张亮,译.北京:人民邮电出版社,2018.</p>
<p class="noindent" id="annot8"><a >[7].</a>肖莱.Python深度学习[M].张亮,译.北京:人民邮电出版社,2018.</p>
\ No newline at end of file
<h1 class="firstTitle"><a >第1课 机器学习快速上手路径——唯有实战</a></h1>
<p class="content_105">第二天清晨,小冰准时来到上课地点。</p>
<p class="content_105">出乎她的意料,等待他们的讲师—老板口中的“大厂资深数据科学家”竟然是她很久没见的高中同桌。这位哥从小喜欢编程,经常熬夜,年纪轻轻就养成了喝浓咖啡的习惯,因此人称“<span class="bold">咖哥</span>”。毕业时小冰只知道他考入了某校计算机系,之后就再也没联系过了。</p>
<p class="content_105">意外重逢,二人很是激动。不过,他们只能简单寒暄几句,咖哥迅速进入正题。</p>
<p class="content_105">“同学们好,”咖哥说,“你们可知道为什么来上这门课程?”</p>
<p class="content_105">“要做机器学习项目。”3人很默契地回答道。</p>
<p class="content_105">“好,既然是为了做项目而学,那么我们会非常强调实战。当然理论是基础,在开始应用具体技术之前,总要先厘清概念。机器学习,是属于人工智能领域的技术,小冰,你怎么理解‘人工智能’这个概念?”</p>
<p class="content_105">“啊,你还真问倒我了,”小冰说,“成天说人工智能,可是我还真说不清楚它到底是什么。”</p>
<p class="content_105">咖哥说:“好,我们就从人工智能究竟是什么说起。不过,先给出本课重点。”</p>
<div class="bodyPic_104">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0020-0006.jpg">
</div>
<p class="content">“四方上下曰宇,往古来今曰宙。”我们所生活的世界上至无限苍穹,下至微观粒子,瞬息万变。“仰观宇宙之大,俯察品类之盛。”想要把握其中的全部奥妙,难度极大。然而,人类一直在努力探寻事物之间的联系和规律,从而把复杂的现象简单化、抽象化,使之尽量变得有条理,变得可以预测。</p>
<p class="content">整个科学体系就试图整理出“宇宙的运行规则”。而函数,可以视为一种模型,这种模型是对客观世界复杂事物之间的关系的简单模拟。有了这种模拟,从已知到未知的运算、预测或判断,就成为可能。</p>
<h3 class="thirdTitle" id="bw31"><a >2.1.1 什么是函数</a></h3>
<p class="content">函数描述了输入与输出的关系。在函数中,一个事物(输出)随着另一个(或一组)事物(输入)的变化而变化,如下图所示。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0064-0059.jpg">
<p class="imgtitle">输入与输出的关系</p>
</div>
<p class="content">一般情况下,用<span class="italic">x</span>(或<span class="italic">x</span><span class="sub">1</span><span class="italic">x</span><span class="sub">2</span><span class="italic">x</span><span class="sub">3</span>,…)表示输入,用<span class="italic">y</span>表示输出,并把它们叫作变量,同时用<span class="italic">f</span><span class="italic">x</span>)来表示从<span class="italic">x</span><span class="italic">y</span>之间转换的过程,它也是函数的名字,如下图所示。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0064-0060.jpg">
<p class="imgtitle">用解析式表述函数</p>
</div>
<p class="content">上面这种表述函数的方法叫作解析式法,除此之外,还可以用列表法、图像法和语言叙述法等表述函数。其中,最直观的是通过图像来描述自变量和因变量之间的关系,如下图所示。但并不一定所有的函数都能够或者需要用图像来表述。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0064-0061.jpg">
<p class="imgtitle">用图像表述函数</p>
</div>
<p class="content">函数的输入和输出,很多情况下都是数字,但是也不完全如此。函数可以反映非数字之间的关系。比如,函数的输入可以是编号,输出可以是人名,关系就是“S1105560Z”→“黄先生”。在机器学习中,反映非数字之间的关系的函数就更常见了,比如,从狗的图片(输入)到狗的种类(输出)。</p>
<p class="content">因此需要用一个更强大的工具来帮助定义函数—集合。集合里面的每个东西(如“数字1”“狗的图片”或“黄先生”),不管是不是数字,都是集合成员或元素。所以,函数的输入是一个集中的元素,通过对应法则来输出另一个集中的元素。因此,大家可能还记得,初中的时候学过:定义域(也就是输入集)、值域(也就是输出集)和对应法则(也就是关系)被称为函数三要素。</p>
<p class="content">那么说到此处,函数的定义就完善了吗?还没有。<span class="bold">函数把一个集里的每一个元素联系到另一个集里一个独一的值</span>(该定义参考自“数学乐”网站的文章《函数是什么》)。这才算是较严谨的函数定义,如下图所示。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0065-0062.jpg">
<p class="imgtitle">函数反映了两个集合之间的对应关系</p>
</div>
<p class="content">有以下两点需要注意。</p>
<p class="content">(1)<span class="bold">输入</span>集中的<span class="bold">每一个元素</span><span class="italic">X</span>都要被“照顾”到(不过输出集<span class="italic">Y</span>并不一定需要完全覆盖。想象一下有一组狗的图片,全部鉴别完之后,发现其中缺少一个类型的狗,这是可能的)。</p>
<p class="content">(2)函数的<span class="bold">输出</span>值是<span class="bold">独一无二</span>的。一个输入绝对不能够对应多个输出。比如,一张狗的图片,鉴定后贴标签时,认为既是哈士奇,又是德国牧羊犬。这种结果令人困惑,这样的函数我们也不接受。</p>
<p class="content">如下面左图,是函数无疑;而右图,虽然也体现了从输入到输出之间的关系,但是有的<span class="italic">X</span>值同时对应了几个<span class="italic">Y</span>值,不满足函数的定义,所以它不是函数。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0065-0063.jpg">
<p class="imgtitle">左图满足函数定义,右图不满足函数定义</p>
</div>
<h3 class="thirdTitle" id="bw32"><a >2.1.2 机器学习中的函数</a></h3>
<p class="content">机器学习基本上等价于寻找函数的过程。机器学习的目的是进行预测、判断,实现某种功能。通过学习训练集中的数据,计算机得到一个从<span class="italic">x</span><span class="italic">y</span>的拟合结果,也就是函数。然后通过这个函数,计算机就能够从任意的<span class="italic">x</span>,推知任意的<span class="italic">y</span>。这里的自变量<span class="italic">x</span>,就是机器学习中数据集的特征,而特征的个数,通常会多于一个,记作<span class="italic">x</span><span class="sub">1</span>, <span class="italic">x</span><span class="sub">2</span>, …, <span class="italic">x</span><span class="span_108">n</span>。如下图中的示例:机器学习通过电影的成本、演员等特征数据,推测这部电影可能收获的票房。</p>
<div class="bodyPic_104">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0066-0064.jpg">
</div>
<p class="content">机器学习到的函数,实现了从特征到结果的一个特定推断。</p>
<p class="content">机器学习到的函数模型有时过于复杂,并不总是能通过集合、解析式或者图像描述出来。然而,不能直观描述,并不等于函数就不存在了,机器学习所得到的函数正是事物之间的关系的体现,并发挥着预测功能。换句话说,大数据时代的机器学习,不是注重特征到标签之间的因果<span class="bold">逻辑</span>,而是注重其间的相关<span class="bold">关系</span></p>
<p class="content">那么如何衡量通过机器学习所得到的函数是不是好的函数呢?在训练集和验证集上预测准确,而且能够泛化到测试集,就是好函数。对结果判断的准确性,是机器学习函数的衡量标准,在这个前提之下,我们把科学体系中原本的核心问题“<span class="bold">为什么</span>”,转移到了“<span class="bold">是什么</span>”这个更加实用的目标。</p>
<p class="content">Kaggle上面有一个很知名的竞赛,其训练集中包含泰坦尼克号登船乘客的详细信息(这是特征),以及生还与否的记录(这是标签),目标则是去预测测试集中的每一位乘客是存活还是死亡。这个竞赛数据集的说明如下图所示。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0066-0065.jpg">
<p class="imgtitle">存活或死亡?—泰坦尼克号机器学习竞赛数据集</p>
</div>
<p class="content">面对这样的数据集,如何去寻找一个好的函数呢?你们可能听说过,当时船长曾提议让女士和儿童优先离船,登上救生艇。因此,如果预测女性全部存活,准确率会超过预测男性全部存活。“登船女性全部存活,男性全部遇难”,这也是从特征到标签的简单映射关系,算是一个函数。而且应用这个函数大概可以得到60%的预测准确率。然而,这个函数过于简单了,没有含金量。</p>
<p class="content">通过机器学习,可以实现更准确的预测,能够更有效地找到数据特征以及标签之间错综复杂的联系。也就是说,机器通过学习发现了一个更为复杂的函数,能够从各种看似不相关的特征<span class="italic">x</span>中,预测或者推导出更加靠谱的<span class="italic">y</span>值。</p>
<p class="content">此时,从数据特征到生还与否的结果间的关系通过机器学习算法拟合到了极为细微的程度。比如,某个家庭的成员情况(如孩子的个数)、所住的舱位、所在的甲板,以及他们的生活习惯(如是否吸烟)等特征信息,都有可能在冥冥之中影响着乘客们的生命。这些很难用肉眼或者统计学方法去发现的关联性,竟能够通过机器学习算法的推演,得到相当准确的答案。可以说,<span class="bold">机器学习算法得到的函数,往往能看到数据背后隐藏着的、肉眼所不能发现的秘密</span></p>
<p class="content">就这个竞赛来说,“高手”的机器学习模型,甚至可达到99%以上的预测准确率。也就是说,如果能够穿越时空,带上机器交给我们的函数来到泰坦尼克号启航的码头,询问每一位乘客几个私人问题,根据他们的回答,就可以基本知晓他们的命运。</p>
<p class="content">传统的机器学习算法包括线性回归、逻辑回归、决策树、朴素贝叶斯等,通过应用这些算法可以得到不同的函数。而深度学习的函数具有复杂的神经网络拓扑结构,网络中的参数通过链式求导来求得,相当于一大堆线性函数的跨层堆叠。它们仿佛存在于一片混沌之中,虽然看不见摸不着,却真实地存在着。</p>
<p class="content">无论是传统的机器学习,还是深度学习,所得到的函数模型都是对样本集中特征到标签的关系的总结,是其相关性的一种函数化的表达。</p>
<p class="content">下面简单说说我们这次机器学习之旅中会见到的一些函数。</p>
<p class="content_101">1.线性函数</p>
<p class="content">线性函数是线性回归模型的基础,也是很多其他机器学习模型中最基本的结构单元。线性函数是只拥有一个变量的一阶多项式函数,函数图像是一条直线。下图给出了两个线性函数。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0067-0066.jpg">
<p class="imgtitle">两个线性函数</p>
</div>
<p class="content">线性函数适合模拟简单的关系,比如,同一个小区房屋的面积和其售价之间可能会呈现线性的关系。</p>
<p class="content_101">2.二次函数和多次函数</p>
<p class="content">函数中自变量<span class="italic">x</span>中最大的指数被称为函数的次数,比如<span class="italic">y</span>=<span class="italic">x</span><span class="super">2</span>就是二次函数。二次函数和多次函数的函数图像更加复杂,因而可以拟合出更为复杂的关系,如下图所示。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0068-0067.jpg">
<p class="imgtitle">二次函数和多次函数</p>
</div>
<p class="content_101">3.激活函数</p>
<p class="content">还有一组函数在机器学习中相当重要,它们是神经网络中的<span class="bold">激活函数</span>(activation function)。这组函数我们在数学课上也许没见过,但是它们都十分简单,如下图所示。它们的作用是在机器学习算法中实现非线性的、阶跃性质的变换。其中的Sigmoid函数在机器学习的逻辑回归模型中起着重要的作用。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0068-0068.jpg">
<p class="imgtitle">激活函数</p>
</div>
<p class="content_101"><img alt="" class="h-pic" src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0068-0069.jpg">咖哥发言</p>
<p class="content">Sigmoid函数中的e叫自然常数,是一个无理数,约等于2.72。</p>
<p class="content_101">4.对数函数</p>
<p class="content">对数函数是指数函数(求幂)的逆运算。原来的指数就是对数的底。从几何意义上说,对数是将数轴进行强力的缩放,再大的数字经对数缩放都会变小。对数函数图像如下图所示。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0069-0070.jpg">
<p class="imgtitle">对数函数图像</p>
</div>
<p class="content">下面给出对数函数的Python代码示例:</p>
<div class="content_106">
<p class="content_105">import math # 导入数学工具包</p>
<p class="content_105">y = math.log(100000000, 10)# 以10为底, 在x值等于一亿的情况下</p>
<p class="content_105">print("以10为底, 求一亿的对数:", y)# 求出y的值为8</p>
</div>
<p class="content_112">以10为底, 求一亿的对数:8.0</p>
<p class="content">如果不指定对数的底,则称log<span class="italic">x</span>为自然对数,是以自然常数e为底数的对数<span class="super" id="ref9"><a >[1]</a></span>。在逻辑回归算法中,我们会见到自然对数作为损失函数而出现。</p>
<p class="content">机器学习所关心的问题之一是捕捉函数的变化趋势,也就是研究<span class="italic">y</span>如何随着<span class="italic">x</span>而变,这个趋势是通过求导和微分来实现的。</p>
<h3 class="thirdTitle" id="bw34"><a >2.2.1 连续性是求导的前提条件</a></h3>
<p class="content">连续性是函数的性质之一,它是可以对函数求导的前提条件。</p>
<p class="content">具有连续性的函数,<span class="italic">y</span>值随<span class="italic">x</span>值的变化是连贯不间断的。并不是所有函数都具有连续性,像上面提到的阶跃函数从-1到1的跃迁明显就不具有连续性。</p>
<p class="content">然而,有连续性的函数对于机器学习来说至关重要。因为机器学习的过程总体来说是对趋势和函数的变化规律的学习。失去了连续性,趋势和变化的规律也就难以用下面所要介绍的方法寻找了。</p>
<h3 class="thirdTitle" id="bw35"><a >2.2.2 通过求导发现y如何随x而变</a></h3>
<p class="content"><span class="bold">导数</span>(derivative)是定义在连续函数的基础之上的。想要对函数求导,函数至少要有一段是连续的。导数的这个“导”字命名得好,导,是引导,是导航,它与函数上连续两个点之间的变化趋势,也就是与变化的方向相关。</p>
<p class="content">看下面这张图,在一段连续函数的两个点<span class="italic">A</span><span class="italic">B</span>之间,<span class="italic">y</span>值是怎么从<span class="italic">A</span>点逐渐过渡到<span class="italic">B</span>点的?是因为<span class="italic">x</span>的变化,<span class="italic">y</span>也随之发生了变化,这个变化记作d<span class="italic">x</span>,d<span class="italic">y</span></p>
<p class="content">为了演示得比较清楚,<span class="italic">A</span><span class="italic">B</span>两点离得比较远,通过一条割线,就可以把d<span class="italic">x</span>,d<span class="italic">y</span>割出来。这个割线给出的方向,就是从<span class="italic">A</span>点到<span class="italic">B</span>点的变化,也就是割线的斜率。初中数学讲过,直线的斜率就是它相对于横轴的倾斜程度,求法是d<span class="italic">y</span>/d<span class="italic">x</span>,也等价于从<span class="italic">A</span>点到<span class="italic">B</span>点的变化方向。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0070-0071.jpg">
<p class="imgtitle"><span class="italic">x</span>变化,导致<span class="italic">y</span>随之发生了变化</p>
</div>
<p class="content">那么当<span class="italic">A</span>点和<span class="italic">B</span>点的距离越来越小,两个点无限接近,逼近极限的时候,在即将重合而又未重合的一刹那,割线就变成切线了,如下图所示。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0070-0072.jpg">
<p class="imgtitle">对切点求导所得的值,就是切线的斜率</p>
</div>
<p class="content">而此时,对切点求导所得的值,就是切线的斜率。</p>
<p class="content">■当斜率为正的时候,说明函数目前变化趋势是在上升。</p>
<p class="content">■当斜率为负的时候,说明函数目前变化趋势是在下降。</p>
<p class="content">■当斜率为0的时候,说明函数正处于全局或者局部的最低点,趋势即将发生改变。</p>
<p class="content">总结一下:函数变化的趋势至少由两个点体现,即当<span class="italic">A</span>趋近于<span class="italic">B</span>的时候,求其变换的极限,这就是导数。导数的值和它附近的一小段连续函数有关。如果没有那么一段连续的函数,就无法计算其切线的斜率,函数在该点也就是不可导的。</p>
<p class="content">通过求导,实现了以直代曲,也发现了<span class="italic">y</span>值随<span class="italic">x</span>值而变化的方向。引申到机器学习领域,通过导数就可以得到标签<span class="italic">y</span>随特征<span class="italic">x</span>而变化的方向。</p>
<p class="content">导数是针对一个变量而言的函数变化趋向。而对于多元(即多变量)的函数,它关于其中一个变量的导数为偏导数,此时保持其他变量恒定。如果其中所有变量都允许变化,则称为全导数。</p>
<p class="content_101"><img alt="" class="h-pic" src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0071-0073.jpg">咖哥发言</p>
<p class="content">我们经常听说<span class="italic">n</span><span class="italic">n</span>次方程式,或者<span class="italic">n</span><span class="italic">n</span>次函数,其中的“元”,指的是自变量<span class="italic">x</span>的个数;其中的“次”,指的是<span class="italic">x</span>的指数的最大值。</p>
<p class="content">在微积分中,可微函数是指那些在定义域中所有点都存在导数的函数。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0071-0074.jpg">
<p class="imgtitle">一个可微的二元函数</p>
</div>
<p class="content">右图所示为一个可微的二元函数(对应机器学习中特征轴是二维的情况),这时候对函数求导,切线就变成了切面。</p>
<h3 class="thirdTitle" id="bw36"><a >2.2.3 凸函数有一个全局最低点</a></h3>
<p class="content">凹凸性也是函数的性质之一(函数还有很多其他性质,如奇偶性、单调性、周期性等),在这里只说说什么是凸函数。凸函数的定义比较抽象,这里只通过函数图形从直观上去理解。首先,函数形状必须是连续的,而不是断续的。其次,函数平滑,只存在一个最低点,整个函数呈现碗状。而非凸函数,可能呈现各种形状,有很多个底部(机器学习里面叫作局部最低点)。下图所示的函数<span class="italic">f</span><span class="sub">1</span>就是一个凸函数,而函数<span class="italic">f</span><span class="sub">2</span>就不是一个凸函数。</p>
<p class="content">在连续函数图像上的局部或者全局最低点对函数求导,导数值都为0。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0071-0075.jpg">
<p class="imgtitle">凸函数和非凸函数</p>
</div>
<p class="content">为什么要特别讲这个凸函数呢?因为在机器学习的梯度下降过程中,只有凸函数能够确保下降到全局最低点。你们可能注意到我在上面的图像里面画了一个小球,凸函数的小球不管初始位置放在哪里,都可以<span class="bold">沿着导数给出的方向滚到最低点</span>;而在其他非凸函数中,小球就可能卡在半路,也就是那个叫作局部最低点的地方。在机器学习中,无法达到全局最低点是很不理想的情况(这是后话,暂且不讲解)。</p>
<p class="content">经过前面两节内容的铺垫,我们可以开始讲一讲机器学习的动力之源:梯度下降。</p>
<p class="content">梯度下降并不是一个很复杂的数学工具,其历史已经有200多年了,但是人们可能不曾料到,这样一个相对简单的数学工具会成为诸多机器学习算法的基础,而且还配合着神经网络点燃了深度学习革命。</p>
<h3 class="thirdTitle" id="bw38"><a >2.3.1 什么是梯度</a></h3>
<p class="content">对多元函数的各参数求偏导数,然后把所求得的各个参数的偏导数以向量的形式写出来,就是梯度。</p>
<p class="content">具体来说,两个自变量的函数<span class="italic">f</span><span class="italic">x</span><span class="sub">1</span><span class="italic">x</span><span class="sub">2</span>),对应着机器学习数据集中的两个特征,如果分别对<span class="italic">x</span><span class="sub">1</span><span class="italic">x</span><span class="sub">2</span>求偏导数,那么求得的梯度向量就是(∂<span class="italic">f</span>/∂<span class="italic">x</span><span class="sub">1</span>,∂<span class="italic">f</span>/∂<span class="italic">x</span><span class="sub">2</span><span class="super">T</span>,在数学上可以表示成Δ<span class="italic">f</span><span class="italic">x</span><span class="sub">1</span><span class="italic">x</span><span class="sub">2</span>)。</p>
<p class="content">那么计算梯度向量的意义何在呢?其几何意义,就是函数变化的方向,而且是变化最快的方向。对于函数<span class="italic">f</span><span class="italic">x</span>),在点(<span class="italic">x</span><span class="sub">0</span><span class="italic">y</span><span class="sub">0</span>),梯度向量的方向也就是<span class="italic">y</span>值增加最快的方向。也就是说,沿着梯度向量的方向Δ<span class="italic">f</span><span class="italic">x</span><span class="sub">0</span>),能找到函数的最大值。反过来说,沿着梯度向量相反的方向,也就是 -Δ<span class="italic">f</span><span class="italic">x</span><span class="sub">0</span>)的方向,梯度减少最快,能找到函数的最小值。如果某一个点的梯度向量的值为0,那么也就是来到了导数为0的函数最低点(或局部最低点)了。</p>
<h3 class="thirdTitle" id="bw39"><a >2.3.2 梯度下降:下山的隐喻</a></h3>
<p class="content">在机器学习中用下山来比喻梯度下降是很常见的。想象你们站在一座大山上某个地方,看着远处的地形,一望无际,只知道远处的位置比此处低很多。你们想知道如何下山,但是只能一步一步往下走,那也就是在每走到一个位置的时候,求解当前位置的梯度。然后,沿着梯度的负方向,也就是往最陡峭的地方向下走一步,继续求解新位置的梯度,并在新位置继续沿着最陡峭的地方向下走一步。就这样一步步地走,直到山脚,如下图所示。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0072-0076.jpg">
<p class="imgtitle">梯度下降的隐喻和一个二元函数的立体图像</p>
</div>
<p class="content">从上面的解释中,就不难理解为何刚才我们要提到函数的凹凸性了。因为,在非凸函数中,有可能还没走到山脚,而是到了某一个山谷就停住了。也就是说,对应非凸函数梯度下降不一定总能够找到全局最优解,有可能得到的只是一个局部最优解。然而,如果函数是凸函数,那么梯度下降法理论上就能得到全局最优解。</p>
<h3 class="thirdTitle" id="bw40"><a >2.3.3 梯度下降有什么用</a></h3>
<p class="content">梯度下降在机器学习中非常有用。简单地说,可以注意以下几点。</p>
<p class="content">■机器学习的本质是找到最优的函数。</p>
<p class="content">■如何衡量函数是否最优?其方法是尽量减小预测值和真值间的误差(在机器学习中也叫损失值)。</p>
<p class="content">■可以建立误差和模型参数之间的函数(最好是凸函数)。</p>
<p class="content">■梯度下降能够引导我们走到凸函数的全局最低点,也就是找到误差最小时的参数。</p>
<p class="content">也许上面的说明还是挺抽象的,不要着急,在第3课线性回归的梯度下降实现部分,我将保证你们会完全理解梯度下降在机器学习中的意义。</p>
<p class="content">Python的语法介绍暂告一段落。接下来同学们思索一个较为抽象的问题:如何用几何(形状、大小、图形的相对位置等空间区域)的方式去表述机器学习的本质呢?这个题目很大,我在这里做一点点肤浅的尝试。</p>
<h3 class="thirdTitle" id="bw58"><a >2.6.1 机器学习的向量空间</a></h3>
<p class="content">张量,可以被解释为某种几何空间内点的坐标。这样,机器学习中特征向量就形成了<span class="bold">特征空间</span>,这个空间的维度和特征向量的维度相同。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0090-0094.jpg">
<p class="imgtitle">二维向量—平面上的点</p>
</div>
<p class="content">现在考虑这样一个二维向量:<span class="italic">A</span> = (0.5,1)。</p>
<p class="content">这个向量可以看作二维空间中的一个点,一般将它描绘成原点到这个点的箭头,如右图所示。那么更高维的向量呢?应该也可以想象为更高维空间的点。像这样把平面数字转换为空间坐标的思考方式其实是很有难度的。</p>
<p class="content">张量运算都有几何意义。举个例子,我们来看二维向量的加法,如下图所示。向量的加法在几何上体现为一个封闭的图形。两个向量的和形成一个平行四边形,结果向量就是起点到终点的对角线。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0090-0095.jpg">
<p class="imgtitle">二维向量的加法</p>
</div>
<p class="content_101"><img alt="" class="h-pic" src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0090-0096.jpg">咖哥发言</p>
<p class="content">不知道你们是否还记得初中物理中曾讲过的向量相加的效果:对于力、位移、速度、加速度等向量,其相加后的效果等于几个分向量的效果之和。</p>
<p class="content">而二维向量的点积的几何意义则是两个向量之间的夹角,以及在<span class="italic">b</span>向量和<span class="italic">a</span>向量方向上的投影(如右图所示):</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0090-0097.jpg">
<p class="imgtitle">向量的点积</p>
</div>
<p class="content_100"><span class="italic">a</span>·<span class="italic">b</span>=|<span class="italic">a</span>||<span class="italic">b</span>|cos<span class="italic">θ</span></p>
<p class="content">其中<span class="italic">θ</span><span class="italic">a</span>向量与<span class="italic">b</span>向量的夹角,点积结果则是<span class="italic">a</span>(或<span class="italic">b</span>)向量在<span class="italic">b</span>(或<span class="italic">a</span>)向量上的投影长度,是一个标量。</p>
<p class="content">这些例子展示了平面中一些二维向量操作的几何意义,推而广之:<span class="bold">机器学习模型是在更高维度的几何空间中对特征向量进行操作、变形,计算其间的距离,并寻找从特征向量到标签之间的函数拟合-这就是从几何角度所阐述的机器学习本质。</span></p>
<p class="content">几种常见的机器学习模型都可以通过特征空间进行几何描述,如下图所示。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0091-0098.jpg">
<p class="imgtitle">几种常见的机器学习模型</p>
</div>
<h3 class="thirdTitle" id="bw59"><a >2.6.2 深度学习和数据流形</a></h3>
<p class="content">下面继续介绍深度学习的几何意义。前面我们也提过,深度学习的过程,实际上也就是一个数据提纯的过程。数据从比较粗放的格式,到逐渐变得“计算机友好”。</p>
<p class="content">数据为什么需要提纯呢?主要还是因为特征维度过高,导致特征空间十分复杂,进而导致机器学习建模过程难度过大。有一种思路是通过<span class="bold">流形(manifold)</span>学习将高维特征空间中的样本分布群“平铺”至一个低维空间,同时能保存原高维空间中样本点之间的局部位置相关信息。</p>
<p class="content">原始数据特征空间中的样本分布可能极其扭曲,平铺之后将更有利于样本之间的距离度量,其距离将能更好地反映两个样本之间的相似性。原始空间中相邻较近的点可能不是同一类点,而相邻较远的点有可能是同一类,“平铺”至低维空间后就能解决这一问题。</p>
<p class="content_101"><img alt="" class="h-pic" src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0091-0099.jpg">咖哥发言</p>
<p class="content">流形,其概念相当的抽象,属于比较高端的数学。我查阅过资料,坦白说,不能完全理解。“流形”这个漂亮的翻译源自北大数学系老教授江泽涵,江教授的灵感则源自文天祥的名作《正气歌》中“天地有正气,杂然赋流形”。</p>
<p class="content">在传统的机器学习中,流形学习主要用于特征提取和数据降维,特征提取使特征变得更加友好,降维是因为高维数据通常有冗余。</p>
<p class="content">而在深度学习出现之后,有一种说法认为神经网络能够自动自发地将复杂的特征数据流形展开,从而减少了特征提取的需要。从直观上,这个展开过程可以用一团揉皱了的纸来解释,如下图所示。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0092-0100.jpg">
<p class="imgtitle">通过神经网络展开数据流形</p>
</div>
<p class="content">如果有好几张揉皱了的纸上写满了数字,要读取上面的信息是不可能的事。但把这样的纸展开,而又不损害纸,也挺麻烦。因此,现代的<span class="bold">深度神经网络(Deep Neural Networks,DNN)通过参数学习,展开了高维数据的流形—这可以说是深度学习的几何意义</span><span class="super" id="ref10"><a >[2]</a></span></p>
<p class="content">在本课的最后,我想用很短的篇幅复习一下概率和统计的基本知识。这些内容在机器学习领域时有出现,同学们需要简单了解。</p>
<h3 class="thirdTitle" id="bw61"><a >2.7.1 什么是概率</a></h3>
<p class="content">事件分为以下两种。</p>
<p class="content">■一种是<span class="bold">确定性事件</span>。确定性事件又分为以下两种。</p>
<p class="content">□必然事件:如太阳从东方升起,或者水在0℃会结冰。</p>
<p class="content">□不可能事件:如掷一个常规的六面骰子,得到的点数是7。</p>
<p class="content">■有大量事件在一定条件下能否发生,是无法确定的,它们是<span class="bold">随机事件</span>。比如,掷一枚硬币得到的是正面还是反面、明天大盘是涨还是跌等。</p>
<p class="content">因此,对于随机事件,我们很想知道“这件事情会发生吗?”,然而很多情况下,答案是不确定的。而概率则回答的是“我们有多确定这件事情会发生?”,然后试图用0~1的数字来表示事件的确定程度。</p>
<p class="content">表2-1给出了概率的定义和计算公式。</p>
<div class="pic_115">
<p class="imgtitle">表2-1 概率的定义和计算公式</p>
<img alt="" src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0092-0101.jpg">
</div>
<p class="content">表中公式都不难理解,简单解释一下最后一个公式<span class="italic">P</span><span class="italic">A</span>|<span class="italic">B</span>)的意义。公式中的<span class="italic">P</span><span class="italic">A</span>|<span class="italic">B</span>)叫作<span class="bold">条件概率</span>,也叫<span class="bold">后验概率</span>。也就是说已知事件<span class="italic">B</span>发生的时候,<span class="italic">A</span>的概率。</p>
<p class="content">举个例子来解释:某公司男生、女生各占50%,烟民占总人数的10%,而女烟民则占总人数的1%。那么问题来了:现在遇到了一个烟民,这个烟民是女生的可能性有多大?</p>
<p class="content">现在是已知3个概率后,能够算出来第4个概率,根据条件概率公式进行推导计算,需要注意以下几个地方。</p>
<p class="content">■事件<span class="italic">B</span>—烟民。</p>
<p class="content">■事件<span class="italic">A</span>—女生。</p>
<p class="content"><span class="italic">P</span><span class="italic">B</span>)—10%,随便遇到一个烟民的概率。</p>
<p class="content"><span class="italic">P</span><span class="italic">A</span>)—50%,随便遇到一个女生的概率。</p>
<p class="content"><span class="italic">P</span><span class="italic">B</span>|<span class="italic">A</span>)—1%,已知100个人里面才有一个女烟民。</p>
<p class="content"><span class="italic">P</span><span class="italic">A</span>|<span class="italic">B</span>)—现在遇到一个烟民(事件<span class="italic">B</span>发生了),是女生的可能性有多大?</p>
<p class="content">答案:(1%×50%)/10% = 5%。这个答案可以这样解释,随便在该公司遇到一个烟民, 95%的可能性都是男生,只有5%的可能性是女生。</p>
<p class="content">关于上面的例子,还有以下几点需要说明。</p>
<p class="content">(1)其实这个条件概率公式就是简化版的贝叶斯定理—一个很老牌的统计学习模型。</p>
<p class="content">(2)如果把<span class="italic">P</span><span class="italic">A</span>|<span class="italic">B</span>)中的<span class="italic">A</span>换成<span class="italic">Y</span>,把<span class="italic">B</span>换成<span class="italic">X</span>,那么这个公式就可以用作机器学习的模型, <span class="italic">X</span>就变成了特征,<span class="italic">Y</span>就变成要预测的标签—我们不就是要根据已有的特征(已发生事件),来预测目标吗?</p>
<p class="content">(3)<span class="italic">P</span><span class="italic">A</span>),也就是<span class="italic">P</span><span class="italic">Y</span>),叫作先验概率,是发生<span class="italic">B</span>事件之前观测到的发生<span class="italic">A</span>事件的可能性。</p>
<p class="content">(4)<span class="italic">P</span><span class="italic">B</span>),也就是<span class="italic">P</span><span class="italic">X</span>),是<span class="italic">B</span>发生的概率,也就是数据特征<span class="italic">X</span>出现的概率。它与<span class="italic">Y</span>是独立的存在,而且机器学习多数情况下可以忽略。</p>
<p class="content">(5)<span class="italic">P</span><span class="italic">B</span>|<span class="italic">A</span>),这个叫作<span class="bold">似然,</span><span class="bold">似然函数</span>。什么是似然?就是当事情<span class="italic">A</span>发生时(女生),<span class="italic">B</span>发生的概率。现在已经知道了标签(女生<span class="italic">Y</span>),回去查找特征(烟民<span class="italic">X</span>)出现的概率。训练集就可以提供这个似然。似然和后验概率,两者并不是一回事,它们之间可以通过贝叶斯定理相互转换。</p>
<p class="content_101"><img alt="" class="h-pic" src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0093-0102.jpg">咖哥发言</p>
<p class="content">几率和概率,这两个词的区别大家了解吗?它们在数学上可不是同义词。几率是该事件发生的概率和不发生概率的比值。因此,在上面的例子中,遇到烟民的几率是1∶9,而概率则是10%。</p>
<p class="content">关于概率,就先介绍这么多。在机器学习中,概率的概念常常出现(例如逻辑回归中的分类问题)。</p>
<h3 class="thirdTitle" id="bw62"><a >2.7.2 正态分布</a></h3>
<p class="content">正态分布(normal distribution)这个词你们肯定听起来很耳熟,但是也许不知道它的确切定义。其实,所谓分布就是一组概率的集合,是把一种常见的概率分布用连续的函数曲线显示出来的方式。而正态分布,又名高斯分布(Gaussian distribution),则是一个非常常见的连续概率分布。</p>
<p class="content">比如,显示一下全国学生的高考成绩,如果分数范围是0~100分,绘制一下概率,你们就会发现,60~70分的中间人数最多(得60~70分的概率大),考0分的少,考100分的也少(得100分的概率小)。绘制出的这种曲线,就符合正态分布,中间高,两边低。</p>
<p class="content">正态分布也叫概率分布的钟形曲线(bell curve),因为曲线的形状就像一口悬挂的大钟,如下图所示。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0094-0103.jpg">
<p class="imgtitle">正态分布的形状:就像一口悬挂的大钟</p>
</div>
<p class="content">但在某些情况下分布并不是正态的。比如,某个数学特长班的学生去做一套普通学校的试卷,全部学生都考了90分以上。这种分布画出来就不是很像钟形,其原因就在于这套试卷对于这批学生是没有什么鉴别力的。</p>
<h3 class="thirdTitle" id="bw63"><a >2.7.3 标准差和方差</a></h3>
<p class="content">上面正态分布示意图中出现了一个奇怪的符号<span class="italic">σ</span>,这个符号代表<span class="bold">标准差</span>(Standard Deviation,SD),读作sigma。标准差,也称均方差(mean square error),是反映研究总体内个体之间差异程度的一种统计指标。</p>
<p class="content">标准差是根据方差计算出来的。而<span class="bold">方差</span>(variance)是一组资料中各实际数值与其算术平均数(即<span class="bold">均值</span>(mean),也叫期望值)的差值做平方结果相加之后,再除以总数而得。标准差是方差的算术平方根。方差和标准差,描述的都是数据相对于其期望值的离散程度。</p>
<p class="content">标准差在机器学习中也经常出现,比如,当进行数据预处理时,常常要涉及数据标准化。在该步骤中,最常见的做法就是对样本特征减去其均值,然后除以其标准差来进行缩放。</p>
<p class="content">机器学习相关数学知识和Python语法的介绍就结束了。本课的内容很多,下面总结一些重点内容。</p>
<p class="content">(1)我们介绍函数的定义并给出几种类型的函数图像,目的是让大家从直观上去理解机器学习如何通过函数对特征和标签之间的关联性进行拟合。然后介绍的对函数进行求导、微分以及梯度下降方法则是机器学习进行参数优化的最基本原理。具体的细节在下一课中介绍。</p>
<p class="content">(2)机器学习中的数据结构称为张量,下面是几种重要的张量格式,用于处理不同类型的数据集。</p>
<p class="content">■普通向量数据集结构:2D张量,形状为(样本,标签)。</p>
<p class="content"> ■时间序列数据集或序列数据集:3D张量,形状为(样本,时戳,特征)。</p>
<p class="content"> ■图像数据集:4D张量,形状为(样本,图像高度,图像宽度,颜色深度)。</p>
<p class="content">(3)Python语句操作方面,Num Py数组的操作都是重点内容。</p>
<p class="content">■张量的切片操作。</p>
<p class="content">■用reshape进行张量变形。</p>
<p class="content">■Python的广播功能。</p>
<p class="content">■向量和矩阵的点积操作之异同,向量的点积得到的是一个数。</p>
<p class="content">■要记得不定时地检查张量的维度。</p>
<p class="content">在下一课中,我们就要开始讲真正的机器学习算法和项目的实战了。我曾经反复说过机器学习是非常接地气的技术,大家先思索一下你们生活中有没有什么具体的问题,是可以应用机器学习算法的,如果你们有数据,可以拿来共同探讨,甚至当成教学及实战的案例。</p>
<div class="content_120">
<p class="content">练习一 变量(<span class="italic">x</span><span class="italic">y</span>)的集合{(−5,1),(3,−3),(4,0),(3,0),(4,−3)}是否满足函数的定义?为什么?</p>
<p class="content">练习二 请同学们画出线性函数<span class="italic">y</span>=2<span class="italic">x</span>+1的函数图像,并在图中标出其斜率和<span class="italic">y</span>轴上的截距。</p>
<p class="content">练习三 在上一课中,我们曾使用语句from keras.datasets import boston_housing导入了波士顿房价数据集。请同学们输出这个房价数据集对应的数据张量,并说出这个张量的形状。</p>
<p class="content">练习四 对波士顿房价数据集的数据张量进行切片操作,输出其中第101~200个数据样本。</p>
<p class="content">(提示:注意Python的数据索引是从0开始的。)</p>
<p class="content">练习五 用Python生成形状如下的两个张量,确定其阶的个数,并进行点积操作,最后输出结果。</p>
<p class="content"><span class="italic">A</span> = [1,2,3,4,5]</p>
<p class="content"><span class="italic">B</span> = [[5],[4],[3],[2],[1]]</p>
</div>
<hr>
<p class="noindent" id="annot9"><a >[1].</a>此处及本书后续公式中log的底数为自然常数e,标准写法应该为ln。不过,很多程序语言中都用log()函数来实现ln(),所以程序设计教学过程中往往约定俗成,采用log()这一写法。</p>
<p class="noindent" id="annot10"><a >[2].</a>肖莱.Python深度学习[M].张亮,译.北京:人民邮电出版社,2018.</p>
\ No newline at end of file
<h1 class="firstTitle"><a >第2课 数学和Python基础知识——一天搞定</a></h1>
<p class="content_105">在第1课中,小冰学到了如何通过机器学习预测房价、如何实现手写数字识别。于是小冰信心满满地问咖哥:“今天咱们用机器学习解决什么新问题?”</p>
<p class="content_105">“先不要急,小冰。”咖哥说,“在系统地讲解各种机器学习算法之前,我们要先花一天的时间来看一下与机器学习密切相关的数学知识。所谓‘不积跬步,无以至千里’,机器学习的数学基础包括函数、线性代数、概率与统计、微积分,等等。”</p>
<p class="content_105">听到这里,小冰的嘴已经张得很大:“天啊,这些知识我几乎全还给老师了,你居然说只用一天时间看一下。”</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0063-0057.jpg">
<p class="imgtitle">小冰联想到一大堆的数学符号,开始皱眉头</p>
</div>
<p class="content_105">“别急!我们要说的数学内容,重在理解而不重在推导,重在领悟而不重在计算。目的是帮你们建立起机器学习的直觉。”</p>
<p class="content_105">“除了数学之外,机器学习的另一个基础就是Python语法,尤其是和Num Py数组操作相关的语句,也要介绍一下。同样地,还是先给出本课重点吧。”</p>
<div class="bodyPic_104">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0063-0058.jpg">
</div>
<p class="content_105">小冰已经准备好了她的问题。这些问题都与广告投放金额和商品销售额有关,她希望通过机器学习算法找出答案。</p>
<p class="content_105">(1)各种广告和商品销售额的相关度如何?</p>
<p class="content_105">(2)各种广告和商品销售额之间体现出一种什么关系?</p>
<p class="content_105">(3)哪一种广告对于商品销售额的影响最大?</p>
<p class="content_105">(4)分配特定的广告投放金额,预测出未来的商品销售额。</p>
<p class="content_105">咖哥说:“问题定义得不错。广告投放金额和商品销售额之间,明显呈现出一种相关性。”</p>
<p class="content">机器学习算法正是通过分析已有的数据,发现两者之间的关系,也就是发现一个能由“此”推知“彼”的函数。本课通过回归分析来寻找这个函数。所谓回归分析(regression analysis),是确定两种或两种以上变量间相互依赖的定量关系的一种统计分析方法,也就是研究当自变量<span class="italic">x</span>变化时,因变量<span class="italic">y</span>以何种形式在变化。在机器学习领域,回归应用于被预测对象具有连续值特征的情况(如客流量、降雨量、销售量等),所以用它来解决小冰的这几个问题非常合适。</p>
<p class="content">最基本的回归分析算法是<span class="bold">线性回归</span>,它是通过线性函数对变量间定量关系进行统计分析。比如,一个简单函数<span class="italic">y</span>=2<span class="italic">x</span>+1,就体现了一个一元(只有一个自变量)的线性回归,其中2是斜率,1是<span class="italic">y</span>轴上的截距。</p>
<p class="content">机器学习的初学者经常见到的第一个教学案例就是对房价的预测。不难理解,房屋的售价与某些因素呈现比较直接的线性关系,比如房屋面积越大,售价越高。如下图所示,线性函数对此例的拟合效果比较好。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0098-0107.jpg">
<p class="imgtitle">线性函数对某些问题的拟合效果比较好</p>
</div>
<p class="content">在机器学习的线性回归分析中,如果只包括一个自变量(特征<span class="italic">x</span>)和一个因变量(标签<span class="italic">y</span>),且两者的关系可用一条直线近似表示,这种回归分析就称为一元线性回归分析。如果回归分析中包括两个或两个以上的自变量,且因变量和自变量之间是线性关系,则称为多元线性回归分析。</p>
<p class="content">那么小冰带来的这个销售额预测问题是一元线性回归还是多元线性回归呢?我们先来看一看她收集的数据吧。</p>
<p class="content">下面继续通过Python代码实现回归模型并调试模型。</p>
<h3 class="thirdTitle" id="bw85"><a >3.5.1 权重和偏置的初始值</a></h3>
<p class="content">在线性回归中,权重和偏置的初始值的选择可以是随机的,这对结果的影响不大,因为我们知道无论怎么选择,梯度下降总会带领机器“走”到最优结果(差别只是步数的多少而已)。通过下面的代码设置初始参数值:</p>
<div class="content_106">
<p class="content_105"># 首先确定参数的初始值</p>
<p class="content_105">iterations = 100;# 迭代100次</p>
<p class="content_105">alpha = 1;# 初始学习速率设为1</p>
<p class="content_105">weight = -5 # 权重</p>
<p class="content_105">bias = 3 # 偏置</p>
<p class="content_105"># 计算一下初始权重和偏置值所带来的损失</p>
<p class="content_105">print ('当前损失:', loss_function(X_train, y_train, weight, bias))</p>
</div>
<p class="content">上面的代码设定各个参数的初始值并通过损失函数loss_function,求出初始损失:</p>
<p class="content_112">当前损失:1.343795534906634</p>
<p class="content">下面画出当前回归函数的图像:</p>
<div class="content_106">
<p class="content_105"># 绘制当前的函数模型</p>
<p class="content_105">plt.plot(X_train, y_train, 'r.', label='Training data') # 显示训练数据</p>
<p class="content_105">line_X = np.linspace(X_train.min(), X_train.max(), 500) # X值域</p>
<p class="content_105">line_y = [weight*xx + bias for xx in line_X] # 假设函数y_hat</p>
<p class="content_105">plt.plot(line_X, line_y, 'b--', label='Current hypothesis' ) #显示当前假设函数</p>
<p class="content_105">plt.xlabel('wechat') # x轴标签</p>
<p class="content_105">plt.ylabel('sales') # y轴标签</p>
<p class="content_105">plt.legend() # 显示图例</p>
<p class="content_105">plt.show() # 显示函数图像</p>
</div>
<p class="content">输出函数图像如下所示。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0117-0146.jpg">
<p class="imgtitle">还没有开始机器学习之前:随机选择初始参数时的函数图像</p>
</div>
<p class="content_105">“哇!”一位同学看了一愣,“咖哥,这个好像和刚才你手绘的<span class="italic">L</span>-<span class="italic">W</span>线有很大差异!”</p>
<p class="content_105">咖哥哈哈大笑,说:“因为初始权重和偏置的值都是随机选择的。而且我是故意让当前这个拟合结果显得很离谱,目的就是在后面的步骤中更好地显示出梯度下降的效果。”</p>
<h3 class="thirdTitle" id="bw86"><a >3.5.2 进行梯度下降</a></h3>
<p class="content">下面就基于这个平均损失比较大的初始参数值,进行梯度下降,也就是开始训练机器,拟合函数。调用刚才已经定义好的梯度下降函数gradient_descent,并迭代100次(在上一节参数初始化的代码中已设定),也就是下100级台阶:</p>
<div class="content_106">
<p class="content_105"># 根据初始参数值, 进行梯度下降, 也就是开始训练机器, 拟合函数</p>
<p class="content_105">loss_history, weight_history, bias_history = gradient_descent(</p>
<p class="content_119">X_train, y_train, weight, bias, alpha, iterations)</p>
</div>
<p class="content">在训练机器的过程中,已经通过变量loss_history记录了每一次迭代的损失值。下面把损失大小和迭代次数的关系通过函数图像显示出来,看看损失是不是如同所预期的那样,随着梯度下降而逐渐减小并趋近最佳状态。通过下面的代码绘制损失曲线:</p>
<div class="content_106">
<p class="content_105">plt.plot(loss_history, 'g--', label='Loss Curve') # 显示损失曲线</p>
<p class="content_105">plt.xlabel('Iterations') # x轴标签</p>
<p class="content_105">plt.ylabel('Loss') # y轴标签</p>
<p class="content_105">plt.legend() # 显示图例</p>
<p class="content_105">plt.show() # 显示损失曲线</p>
</div>
<p class="content">代码运行后,发现很奇怪的现象,图中(如下图所示)显示出来的损失竟随着梯度下降的迭代而变得越来越大,从很小的值开始,越来越大,后来达到好几万。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0118-0147.jpg">
<p class="imgtitle">损失值竟然越来越大</p>
</div>
<p class="content">如果在这时画出当前的线性函数图像,也会特别离谱,根本就没有与数据集形成拟合:</p>
<div class="content_106">
<p class="content_105"># 绘制当前的函数模型</p>
<p class="content_105">plt.plot(X_train, y_train, 'r.', label='Training data') # 显示训练数据</p>
<p class="content_105">line_X = np.linspace(X_train.min(), X_train.max(), 500) # X值域</p>
<p class="content_105"># 关于weight_history[-1], 这里的索引[-1], 就代表迭代500次后的最后一个W值</p>
<p class="content_105">line_y = [weight_history[-1]*xx + bias_history[-1] for xx in line_X] # 假设函数</p>
<p class="content_105">plt.plot(line_X, line_y, 'b--', label='Current hypothesis' ) # 显示当前假设函数</p>
<p class="content_105">plt.xlabel('wechat') # x轴标签</p>
<p class="content_105">plt.ylabel('sales') # y轴标签</p>
<p class="content_105">plt.legend() # 显示图例</p>
<p class="content_105">plt.show() # 显示函数图像</p>
</div>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0118-0148.jpg">
<p class="imgtitle">不成功的拟合</p>
</div>
<p class="content">梯度下降并没有得到我们所期望的结果。原因何在呢?</p>
<p class="content_105">咖哥说:“考验咱们的经验和解决问题的能力的时刻来了!同学们说一说自己的看法吧。”</p>
<p class="content_105">此时,同学们却都沉默了。</p>
<p class="content_105">咖哥说:“其实,根据刚刚讲过的内容,应该可以猜出问题大概出在哪里。这个数据集比较简单,没有什么潜在的数据问题。而且模型也比较简单,如果损失函数、梯度下降代码和求导过程都没有出现错误的话,那么此处基本上可以确定,<span class="bold">问题出在学习速率</span><span class="italic">α</span><span class="bold">的设定方面</span>。”</p>
<h3 class="thirdTitle" id="bw87"><a >3.5.3 调试学习速率</a></h3>
<p class="content">现在的<span class="italic">α</span>值,也就是梯度下降的速率在参数初始化时设定为1,这个值可能太大了。我们可以在0到1之间进行多次尝试,以找到最合适的<span class="italic">α</span>值。</p>
<p class="content">当把<span class="italic">α</span>从1调整为0.01后,损失开始随着迭代次数而下降,但是似乎下降的速度不是很快,迭代100次后没有出现明显的收敛现象,如下面左图所示。反复调整<span class="italic">α</span>,发现在<span class="italic">α</span>=0.5的情况下损失曲线在迭代80~100次之后开始出现比较好的收敛现象,如下面右图所示。此时梯度已经极为平缓,接近凸函数的底部最优解,对权重求导时斜率几乎为0,因此继续增加迭代次数,损失值也不会再发生什么大的变化。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0119-0149.jpg">
<p class="imgtitle">调整学习速率:<span class="italic">α</span> = 0.01,<span class="italic">α</span> = 0.5</p>
</div>
<p class="content"><span class="italic">α</span>设为0.5,迭代100次后,绘制新的线性函数图像,就呈现出了比较好的拟合状态,如下图所示。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0119-0150.jpg">
<p class="imgtitle">终于得到成功的拟合</p>
</div>
<p class="content_105">看到这条漂亮的虚线,同学们一颗颗原本悬着的小心脏都落了地。</p>
<h3 class="thirdTitle" id="bw88"><a >3.5.4 调试迭代次数</a></h3>
<p class="content">对迭代次数进行调试的主要目的是确认损失值已经收敛,因为收敛之后再继续迭代下去,损失值的变化已经微乎其微。</p>
<p class="content">确定损失值已经收敛的主要方法是观察不同迭代次数下形成的损失曲线。下图是<span class="italic">α</span> = 0.5时,迭代20次、100次、500次的损失曲线图像。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0120-0151.jpg">
<p class="imgtitle">将迭代次数从100次增加至500次后,损失并没有明显减小</p>
</div>
<p class="content">从图像显示可知,迭代20次显然太少了,损失值还在持续减少,训练不应停止。大概在迭代80~100次之后,损失已经达到了比较小的值,继续迭代下去没有太大意义,只是浪费资源,所以迭代500次没有什么必要。</p>
<p class="content">就此例而言,以0.5的学习速率来说,为了安全起见,我们迭代100~200次差不多就可以了,最后确定迭代200次吧。</p>
<p class="content">下面就输出<span class="italic">α</span>=0.5时,迭代200次之后的损失值,以及参数<span class="italic">w</span><span class="italic">b</span>的值:</p>
<div class="content_106">
<p class="content_105">print ('当前损失:', loss_function(X_train, y_train,</p>
<p class="content_124">weight_history[-1], bias_history[-1]))</p>
<p class="content_105">print ('当前权重:', weight_history[-1])</p>
<p class="content_105">print ('当前偏置:', bias_history[-1])</p>
</div>
<p class="content">这里的索引[-1],前面讲过,是相对索引,它代表迭代200次后的最后一次的<span class="italic">w</span><span class="italic">b</span>值,这两个值就是机器学习基于训练数据集得到的结果:</p>
<div class="content_113">
<p class="content_109">当前损失:0.00465780405531404</p>
<p class="content_109">当前权重:0.6552253409192808</p>
<p class="content_109">当前偏置:0.17690341009472488</p>
</div>
<h3 class="thirdTitle" id="bw89"><a >3.5.5 在测试集上进行预测</a></h3>
<p class="content">现在,在迭代200次之后,我们认为此时机器学习已经给出了足够好的结果,对于训练集的均方误差函数的损失值已经非常小,几乎接近0。那么,是不是在测试集上,这个函数模型效果也一样好呢?</p>
<p class="content">下面在测试集上进行预测和评估:</p>
<div class="content_106">
<p class="content_105">print ('测试集损失:', loss_function(X_test, y_test,</p>
<p class="content_124">weight_history[-1], bias_history[-1]))</p>
</div>
<p class="content">输出结果如下:</p>
<p class="content_112">测试集损失:0.00458180938024721</p>
<p class="content">结果显示当前的测试集的损失值约为0.00458,甚至还要好过训练集。测试集损失比训练集损失还低,这种情形并不是机器学习的常态,但在比较小的数据集上是有可能出现的。</p>
<p class="content">我们还可以同时描绘出训练集和测试集随着迭代次数而形成的损失曲线,如下图所示。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0121-0152.jpg">
<p class="imgtitle">同时显示测试集与训练集的损失曲线</p>
</div>
<p class="content">结果显示,测试集与训练集的损失随迭代次数的增加,呈现相同的下降趋势,说明我们的机器学习模型是成功的。在训练的初期,训练集上的损失明显小于测试集上的损失,但是这种差距会随着学习的过程而逐渐变小,这也是机器学习过程正确性的体现。</p>
<p class="content">因此,最终确定了一个适合预测小冰的网店销售额的最佳线性回归模型:</p>
<p class="content"><span class="italic">w</span> = 0.6608381748731955</p>
<p class="content"><span class="italic">b</span> = 0.17402747570052432</p>
<p class="content">函数模型:<span class="italic">y'</span>=0.66<span class="italic">x</span>+0.17</p>
<p class="content">而我们刚才所做的全部工作,就是<span class="bold">利用机器学习的原理,基于线性回归模型,通过梯度下降,找到了两个最佳的参数值而已</span></p>
<h3 class="thirdTitle" id="bw90"><a >3.5.6 用轮廓图描绘L、w和b的关系</a></h3>
<p class="content">至此,机器学习建模过程已经完成。这里我再多讲一个辅助性的工具,叫作<span class="bold">轮廓图</span>(contour plot)。损失曲线描绘的是损失和迭代次数之间的关系,而轮廓图则描绘的是<span class="italic">L</span><span class="italic">w</span><span class="italic">b</span>这3者之间的关系,这样才能够清楚地知道损失值是怎样随着<span class="italic">w</span><span class="italic">b</span>的变化而逐步下降的。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0121-0153.jpg">
<p class="imgtitle">从损失曲线到轮廓图</p>
</div>
<p class="content">这个轮廓图,其实大概就是等高线+地形图。</p>
<p class="content_105">小冰插嘴:“等高线和地形图地理课学过啊,我知道是怎么回事。”</p>
<p class="content_105">咖哥说:“那就比较容易理解了。”</p>
<p class="content">介绍梯度下降的时候,我们反复讲全局最低点,如果只有一个参数<span class="italic">w</span>,那么损失函数的图像就是二次函数曲线。</p>
<p class="content">如果考虑两个参数<span class="italic">w</span><span class="italic">b</span>,就是类似于右侧上图的一个三维立体图像,像一个碗。而轮廓图,就是这个三维的碗到二维平面的投影,如右侧下图所示。</p>
<p class="content">在轮廓图中,每一个圈圈上的各个点,损失值都相同,也就是说,这些点所对应的<span class="italic">w</span><span class="italic">b</span>,带来的<span class="italic">L</span>是等值的。而<span class="italic">L</span>的最小值,就投影到了同心椭圆的中心点,也就是全局最优解,此时只有一个最优的<span class="italic">w</span><span class="italic">b</span>的组合。</p>
<p class="content">因此,这个轮廓图可以方便、直观地观察损失函数和模型内部参数之间关系。</p>
<p class="content_105">小冰突然发问:“如果参数超过两个呢?又怎么画轮廓图?”</p>
<p class="content_105">咖哥“痛苦”地回答:“轮廓图,费了好大的力气,把三维的关系降到二维平面上进行显示,你又想再多加一维,那是又在挑战人类的极限了。这里请理解一下,不要钻牛角尖了。其实在纸面上是比较难画出更多个参数的轮廓图的。”</p>
<p class="content">针对这个案例,我在训练机器的过程中绘制出了轮廓图,代码比较长,基于篇幅,我就不进行展示了,你们可以去源码包里面看一看。代码显示了线性函数图像从初始状态到最优状态的渐变和损失在轮廓图中逐渐下降到最低点的轨迹,这把训练机器的过程描绘得非常直观,如下图所示。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0122-0154.jpg">
<p class="imgtitle">随着参数的拟合过程,损失越来越小,最终下降到轮廓图的中心点</p>
</div>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0123-0155.jpg">
<p class="imgtitle">随着参数的拟合过程,损失越来越小,最终下降到轮廓图的中心点(续)</p>
</div>
<p class="content">从图中可以分析出,当<span class="italic">w</span>在0.66附近,<span class="italic">b</span>在0.17附近时,<span class="italic">L</span>值接近轮廓图颜色最深的底部中心点,也就是最优解。</p>
<p class="content_105">“休息10分钟,”咖哥说,“之后讲如何实现多变量的线性回归。”</p>
<p class="content">多元,即多变量,也就是特征是多维的。我们用下标(例如<span class="italic">w</span><span class="sub">1</span><span class="italic">x</span><span class="sub">1</span>)代表特征的编号,即特征的维度。多个特征,可以用来表示更复杂的机器学习模型。同学们不要忘了,小冰给咱们带来的原始数据集,本来就是具有3个特征的模型。只是为了简化教学,才只选择了微信公众号广告投放金额作为唯一的特征,构建单变量线性回归模型。现在重新引入<span class="italic">x</span><span class="sub">2</span>代表微博广告投放金额, <span class="italic">x</span><span class="sub">3</span>代表其他类型广告投放金额,采用以下多元(多变量)的线性方程式来构造假设函数:</p>
<div class="bodyPic_104">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0123-0156.jpg">
</div>
<h3 class="thirdTitle" id="bw92"><a >3.6.1 向量化的点积运算</a></h3>
<p class="content">在机器学习的程序设计中,这个公式可以被向量化地实现,以表示任意维的特征:</p>
<div class="bodyPic_104">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0124-0157.jpg">
</div>
<p class="content">其中,<span class="italic">w</span> <span class="super">T</span>·<span class="italic">x</span>就是<img alt="" class="h-pic" src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0124-0158.jpg"></p>
<p class="content">点积前面讲过:如果<span class="italic">w</span>是一个向量,<span class="italic">x</span>也是一个向量,两个向量做乘法,会得到一个标量,也就是数值<span class="italic">y'</span>。两个向量,你点积我,我点积你,结果是相同的。因此<span class="italic">w</span><span class="super">T</span>·<span class="italic">x</span>等于<span class="italic">x</span>·<span class="italic">w</span><span class="super">T</span></p>
<p class="content">但是,为什么公式里面有一个矩阵转置符号T呢?这是因为<span class="italic">w</span><span class="italic">x</span>这两个张量的实际形状为(<span class="italic">N</span>,1)的矩阵,它们直接相乘是不行的。其中一个需要先转置为(1,<span class="italic">N</span>),才能进行点积操作,这就是为什么公式中特别强调用<span class="italic">w</span><span class="super">T</span></p>
<p class="content">而且,要注意以下几点。</p>
<p class="content">■张量形状(1,<span class="italic">N</span>)点积(<span class="italic">N</span>,1),就得到1×1的标量。</p>
<p class="content">■张量形状(<span class="italic">N</span>,1)点积(1,<span class="italic">N</span>),那就得到(<span class="italic">N</span><span class="italic">N</span>)的矩阵,就不是我们想要的<span class="italic">y'</span></p>
<p class="content">■张量形状(1,<span class="italic">N</span>)点积(1,<span class="italic">N</span>),或者(<span class="italic">N</span>,1)点积(<span class="italic">N</span>,1),就会出错。</p>
<p class="content_101"><img alt="" class="h-pic" src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0124-0159.jpg">咖哥发言</p>
<p class="content">要注意输入张量的维度和目标张量的维度,维度的错误会导致得不到想要的结果。公式里的<span class="italic">y'</span>是一个值,也就是标量。而在本例的程序代码中,因为整个数据集是一起进行向量化运算的,所以<span class="italic">y'</span>应该是一个形状为(200,1)的张量,里面包含200个值。调试程序时要记得多输出张量的形状。</p>
<p class="content">还可以把公式进一步简化,就是把<span class="italic">b</span>也看作权重<span class="italic">w</span><span class="sub">0</span>,那么需要引入<span class="italic">x</span><span class="sub">0</span>,这样公式就是:</p>
<div class="bodyPic_104">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0124-0160.jpg">
</div>
<p class="content">引入<span class="italic">x</span><span class="sub">0</span>,就是给数据集添加一个新的哑(dummy)特征,值为1,<span class="italic">b</span>和这个哑特征相乘,值不变:</p>
<p class="content_100"><span class="italic">w</span><span class="sub">0</span><span class="italic">x</span><span class="sub">0</span>=<span class="italic">b</span>×1=<span class="italic">b</span></p>
<p class="content">新的公式变为:</p>
<p class="content_100"><span class="italic">y'</span>=<span class="italic">h</span><span class="italic">x</span>)=<span class="italic">w</span><span class="super">T</span><span class="italic">x</span></p>
<p class="content">习惯上,对于多元参数,会把<span class="italic">W</span><span class="italic">X</span>大写,突出它们是一个数组,而非标量:</p>
<div class="bodyPic_104">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0124-0161.jpg">
</div>
<p class="content">上面的表述形式令多元回归的程序实现过程更为简洁。多元回归的代码实现和刚才的单变量回归非常相似,只有几个部分需要注意(下面只给出重点代码段,完整代码参阅代码包中的源代码)。</p>
<p class="content">首先,在构建特征数据集时,保留所有字段,包括wechat、weibo、others,然后用Num Py的delete方法删除标签字段:</p>
<div class="content_106">
<p class="content_105">X = np.array(df_ads) # 构建特征集, 包含全部特征</p>
<p class="content_105">X = np.delete(X, [3], axis = 1) # 删除标签</p>
<p class="content_105">y = np.array(df_ads.sales) #构建标签集, 销售额</p>
<p class="content_105">print ("张量X的阶:", X.ndim)</p>
<p class="content_105">print ("张量X的维度:", X.shape)</p>
<p class="content_105">print (X)</p>
</div>
<p class="content">输出结果如下:</p>
<div class="content_113">
<p class="content_109">张量X的阶: 2</p>
<p class="content_109">张量X的维度: (200, 3)</p>
<p class="content_109">[[ 304.4  93.6 294.4]</p>
</div>
<p class="content_133">[1011.9  34.4 398.4]</p>
<div class="content_113">
<p class="content_118">… …</p>
<p class="content_110">[ 343.5  86.4  48.]</p>
<p class="content_110">[ 796.7 180.  252.]]</p>
</div>
<p class="content">因为<span class="italic">X</span>特征集已经是2阶的,不需要再进行reshape操作,所以只需要把标签张量<span class="italic">y</span>进行reshape操作:</p>
<p class="content_114">y = y.reshape(-1, 1) #通过reshape方法把向量转换为矩阵, -1等价于len(y), 返回样本个数</p>
<p class="content">目前输入数据集是2D矩阵,包含两个轴,样本轴和特征轴,其中样本轴共200行数据,特征轴中有3个特征。</p>
<p class="content">多变量线性回归实现过程中的重点就是<span class="italic">W</span><span class="italic">X</span>点积运算的实现,因为<span class="italic">W</span>不再是一个标量,而是变成了一个1D向量[<span class="italic">w</span><span class="sub">0</span><span class="italic">w</span><span class="sub">1</span><span class="italic">w</span><span class="sub">2</span><span class="italic">w</span><span class="sub">3</span>]。此时,假设函数<span class="italic">f</span><span class="italic">x</span>)在程序中的实现就变成了一个循环,其伪代码如下:</p>
<div class="content_106">
<p class="content_105">for i in N: # N为特征的个数</p>
<p class="content_121">y_hat = y_hat + weight[i]*X[i]</p>
<p class="content_121">y_hat = y_hat + bias</p>
</div>
<p class="content">但是,我们已经知道,Num Py工具集中的点积运算可以避免类似的循环语句出现。</p>
<p class="content">而且,有以下两种实现思路。</p>
<p class="content">■一种是<span class="italic">W</span><span class="italic">X</span>点积,再加上偏置。</p>
<p class="content">■另一种是给<span class="italic">X</span>最前面加上一列(一个新的维度),这个维度所有数值全都是1,是一个哑特征,然后把偏置看作<span class="italic">w</span><span class="sub">0</span></p>
<p class="content">第二种实现的代码比较整齐。为<span class="italic">X</span>训练集添加<span class="italic">x</span><span class="sub">0</span>维特征的代码如下:</p>
<div class="content_106">
<p class="content_105">x0_train = np.ones((len(X_train), 1)) # 构造X长度的全1数组配合对偏置的点积</p>
<p class="content_105">X_train = np.append(x0_train, X_train, axis=1) #把X增加一系列的1</p>
<p class="content_105">print ("张量X的形状:", X_train.shape)</p>
<p class="content_105">print (X_train)</p>
</div>
<p class="content">输出结果如下:</p>
<p class="content_112">张量X的形状: (160, 4)</p>
<div class="content_106">
<p class="content_109">[[1.     0.39995488 0.1643002 0.42568162]</p>
<p class="content_110">[1.     0.72629521 0.83975659 0.34564644]</p>
<p class="content_110">[1.     0.22746071 0.31845842 0.35620053]</p>
<p class="content_110">--- ---</p>
<p class="content_110">[1.     0.31949771 0.14807302 0.06068602]]</p>
</div>
<p class="content">类似的x<span class="sub">0</span>维特征也需要添加至测试集。</p>
<h3 class="thirdTitle" id="bw93"><a >3.6.2 多变量的损失函数和梯度下降</a></h3>
<p class="content">损失函数也通过向量化来实现:</p>
<div class="content_106">
<p class="content_105">def loss_function(X, y, W): # 手工定义一个均方误差函数, W此时是一个向量</p>
<p class="content_121">y_hat = X.dot(W.T) # 点积运算h(x)=w<span class="sub">0</span>x<span class="sub">0</span>+w<span class="sub">1</span>x<span class="sub">1</span>+w<span class="sub">2</span>x<span class="sub">2</span>+w<span class="sub">3</span>x<span class="sub">3</span></p>
<p class="content_121">loss = y_hat.reshape((len(y_hat), 1))-y # 中间过程, 求出当前W和真值的差值</p>
<p class="content_121">cost = np.sum(loss**2)/(2*len(X)) # 这是平方求和过程, 均方误差函数的代码实现</p>
<p class="content_121">return cost # 返回当前模型的均方误差值</p>
</div>
<p class="content">梯度下降的公式仍然是:</p>
<div class="bodyPic_104">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0126-0162.jpg">
</div>
<p class="content">封装进一个梯度下降函数:</p>
<div class="content_106">
<p class="content_105">def gradient_descent(X, y, W, lr, iter): # 定义梯度下降函数</p>
<p class="content_121">l_history = np.zeros(iter) # 初始化记录梯度下降过程中损失的数组</p>
<p class="content_121">W_history = np.zeros((iter, len(W))) # 初始化记录梯度下降过程中权重的数组</p>
<p class="content_121">for i in range(iter): # 进行梯度下降的迭代, 就是下多少级台阶</p>
<p class="content_111">y_hat = X.dot(W) # 这是向量化运算实现的假设函数</p>
<p class="content_111">loss = y_hat.reshape((len(y_hat), 1))-y # 中间过程, 求出y_hat和y真值的差值</p>
<p class="content_111">derivative_W = X.T.dot(loss)/(2*len(X)) #求出多项式的梯度向量</p>
<p class="content_111">derivative_W = derivative_W.reshape(len(W))</p>
<p class="content_111">W = W - alpha*derivative_W # 结合学习速率更新权重</p>
<p class="content_111">l_history[i] = loss_function(X, y, W) # 梯度下降过程中损失的历史记录</p>
<p class="content_111">W_history[i] = W # 梯度下降过程中权重的历史记录</p>
<p class="content_121">return l_history, W_history # 返回梯度下降过程中的数据</p>
</div>
<h3 class="thirdTitle" id="bw94"><a >3.6.3 构建一个线性回归函数模型</a></h3>
<p class="content">在训练机器之前,构建一个线性回归函数,把梯度下降和训练过程封装至一个函数。这可以通过调用线性回归模型来训练机器,代码显得比较整齐:</p>
<div class="content_106">
<p class="content_105"># 定义线性回归模型</p>
<p class="content_105">def linear_regression(X, y, weight, alpha, iterations):</p>
<p class="content_121">loss_history, weight_history = gradient_descent(X, y,</p>
<p class="content_134">weight,</p>
<p class="content_134">alpha, iterations)</p>
<p class="content_121">print("训练最终损失:", loss_history[-1]) # 输出最终损失</p>
<p class="content_121">y_pred = X.dot(weight_history[-1]) # 进行预测</p>
<p class="content_121">traning_acc = 100 - np.mean(np.abs(y_pred - y))*100 # 计算准确率</p>
<p class="content_121">print("线性回归训练准确率: {:.2f}%".format(traning_acc)) # 输出准确率</p>
<p class="content_121">return loss_history, weight_history # 返回训练历史记录</p>
</div>
<p class="content">这个模型中调用了梯度下降函数来训练机器,同时计算了最终损失并基于训练集给出了在训练集上的预测准确率。</p>
<h3 class="thirdTitle" id="bw95"><a >3.6.4 初始化权重并训练机器</a></h3>
<p class="content">下面初始化权重,这时候weight变成了一个数组,bias变成了其中的w[0]:</p>
<div class="content_106">
<p class="content_105">#首先确定参数的初始值</p>
<p class="content_105">iterations = 300;# 迭代300次</p>
<p class="content_105">alpha = 0.15;#学习速率设为0.15</p>
<p class="content_105">weight = np.array([0.5, 1, 1, 1]) # 权重向量, w[0] = bias</p>
<p class="content_105">#计算一下初始值的损失</p>
<p class="content_105">print ('当前损失:', loss_function(X_train, y_train, weight))</p>
</div>
<p class="content">下面通过调用前面定义好的线性回归模型训练机器,并给出最终损失,以及基于训练集的预测准确率:</p>
<div class="content_106">
<p class="content_105"># 调用刚才定义的线性回归模型</p>
<p class="content_105">loss_history, weight_history = linear_regression(X_train, y_train,</p>
<p class="content_135">weight, alpha, iterations) #训练机器</p>
</div>
<p class="content">输出结果如下:</p>
<div class="content_113">
<p class="content_109">训练最终损失: 0.004334018335124016</p>
<p class="content_109">线性回归训练准确率: 74.52%</p>
</div>
<p class="content">还可以输出返回的权重历史记录以及损失历史记录:</p>
<div class="content_106">
<p class="content_105">print("权重历史记录:", weight_history)</p>
<p class="content_105">print("损失历史记录:", loss_history)</p>
</div>
<p class="content">损失历史记录显示,迭代200次之后,基本收敛。迭代300次之后,weight的值如下:</p>
<p class="content_136">[-0.04161205 0.6523009 0.24686767 0.37741512]</p>
<p class="content">这表示<span class="italic">w</span><span class="sub">0</span>约为 −0.004,<span class="italic">w</span><span class="sub">1</span>约为0.65,<span class="italic">w</span><span class="sub">2</span>约为0.25,<span class="italic">w</span><span class="sub">3</span>约为0.38。</p>
<p class="content">最后,回答本课开始时,小冰同学提出的问题:在未来的某周,当我将各种广告投放金额做一个分配(比如,我决定用250元、50元、50元)来进行一周的广告投放时,我将大概实现多少元的商品销售额?</p>
<div class="content_106">
<p class="content_105">X_plan = [250,50,50] # 要预测的X特征数据</p>
<p class="content_105">X_train,X_plan = scaler(X_train_original,X_plan) # 对预测数据也要归一化缩放</p>
<p class="content_105">X_plan = np.append([1], X_plan ) # 加一个哑特征X0 = 1</p>
<p class="content_105">y_plan = np.dot(weight_history[-1],X_plan) # [-1] 即模型收敛时的权重</p>
<p class="content_105"># 对预测结果要做反向缩放,才能得到与原始广告费用对应的预测值</p>
<p class="content_105">y_value = y_plan*23.8 + 3.2 #23.8是当前y_train中最大值和最小值的差,3.2是最小值</p>
<p class="content_105">print ("预计商品销售额:",y_value, "千元")</p>
</div>
<p class="content">通过上面的机器学习函数给出的预测参数向量,可以计算出预计商品销售额约为6千元:</p>
<p class="content_112">预计商品销售额:6.088909584694067千元</p>
<p class="content_105">同学们都转头去看小冰,眼神很诧异。咖哥也忍不住了,开口问道:“350元的广告费用,就能卖出6千多元的商品,你真的确定你需要学AI才能养家糊口吗?”小冰白了咖哥一眼:“咖哥,人家这个是商品销售额,不是利润。这6千元里面,大部分是成本。”</p>
<p class="content_105">小冰接着说:“再说,这个模型预测得就一定很准吗?”</p>
<p class="content">本课完成了第一个机器学习模型的项目设计,实现了整个机器学习流程。我们学到了以下内容。</p>
<p class="content">■数据的收集与分析。</p>
<p class="content">■机器学习模型的确定。</p>
<p class="content">■假设函数—<span class="italic">h</span><span class="italic">x</span>)=<span class="italic">wx</span>+<span class="italic">b</span>或写成<span class="italic">h</span><span class="italic">x</span>)=<span class="italic">w</span><span class="sub">0</span>+<span class="italic">w</span><span class="sub">1</span><span class="italic">x</span>,很多地方使用<span class="italic">h</span><span class="italic">x</span>)=<span class="italic">θ</span><span class="sub">0</span>+<span class="italic">θ</span><span class="sub">1</span><span class="italic">x</span></p>
<p class="content">■损失函数—<img alt="" class="ah-pic" src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0128-0163.jpg">,很多地方使用<span class="italic">J</span><span class="italic">θ</span><span class="sub">0</span><span class="italic">θ</span><span class="sub">1</span>)表示损失函数。</p>
<p class="content">■通过梯度下降训练机器,目标是最小化<span class="italic">L</span><span class="italic">w</span><span class="italic">b</span>),即<span class="italic">J</span><span class="italic">θ</span><span class="sub">0</span><span class="italic">θ</span><span class="sub">1</span>)。</p>
<p class="content">■权重和偏置的初始化。</p>
<p class="content">■参数的确定与调试:学习速率、迭代次数。</p>
<p class="content">■针对测试集应用机器学习的训练结果(即得到的模型)。</p>
<p class="content">下面回答本课初始时小冰提出的几个问题。</p>
<p class="content">(1)各种广告和商品销售额的相关度如何?答案:如相关性热力图所示。</p>
<p class="content">(2)各种广告和商品销售额之间体现出一种什么关系?答案:线性关系。</p>
<p class="content">(3)哪一种广告对于商品销售额的影响最大?答案:微信公众号广告。</p>
<p class="content">(4)在未来的某周,当我将各种广告投放金额做一个分配(比如我决定用250元、50元、50元)进行一周的广告投放,我将大概实现多少元的商品销售额?答案:根据机器学习得到的线性函数,可以预测出的销售额为6千元。</p>
<div class="content_120">
<p class="content">练习一 在这一课中,我们花费了一些力气自己从头构造了一个线性回归模型,并没有借助Sklearn库的线性回归函数。这里请大家用Sklearn库的线性回归函数完成同样的任务。怎么做呢?同学们回头看看第1课1.2.3节中的“用Google Colab开发第一个机器学习程序”的加州房价预测问题就会找到答案。</p>
<p class="content">(提示:学完本课内容之后,面对线性回归问题,有两个选择,要么自己构建模型,要么直接调用机器学习函数库里现成的模型,然后用fit方法训练机器,确定参数。)</p>
<p class="content">练习二 在Sklearn库中,除了前面介绍过的Linear Regression线性回归算法之外,还有Ridge Regression(岭回归)和Lasso Regression(套索回归)这两种变体。请大家尝试参考Sklearn在线文档,找到这两种线性回归算法的说明文档,并把它们应用于本课的数据集。</p>
<p class="content">Ridge Regression和Lasso Regression与普通的线性回归在细节上有何不同?下一课中会简单地介绍。</p>
<p class="content">练习三 导入第3课的练习数据集:Keras自带的波士顿房价数据集,并使用本课介绍的方法完成线性回归,实现对标签的预测。</p>
</div>
\ No newline at end of file
<h1 class="firstTitle"><a >第3课 线性回归——预测网店的销售额</a></h1>
<p class="content_105">咖哥让同学们思考一下自己的生活中有没有可以应用机器学习算法来解决的问题。小冰回家之后突然想起自己和朋友开的网店,这个店的基本情况是这样的:正式运营一年多,流量、订单数和销售额都显著增长。经过一段时间的观察,小冰发现网店商品的销量和广告推广的力度息息相关。她在微信公众号推广,也通过微博推广,还在一些其他网站上面投放广告。当然,投入推广的资金越多,则商品总销售额越多。</p>
<p class="content_105">小冰问咖哥:“能不能通过机器学习算法,根据过去记录下来的广告投放金额和商品销售额,来预测在未来的某个节点,一个特定的广告投放金额对应能实现的商品销售额?”</p>
<p class="content_105">咖哥说:“真是巧了,本课要讲的线性回归算法正适合对连续的数值进行预测。”咖哥说着,在白板上画起了图说:“你们看这个例子,假设你去年没有孩子,今年有一个孩子,根据这两个数据样本,通过线性回归预测,5年之后你就有5个孩子,10年之后就10个孩子……”</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0096-0104.jpg">
<p class="imgtitle">线性回归适合对连续的数值进行预测</p>
</div>
<p class="content_105">小冰说:“咖哥,你这个模型不可靠吧。”</p>
<p class="content_105">咖哥说:“哈哈,开个玩笑,这么少的数据量当然无法准确建模了。不过,线性回归是机器学习中一个非常基础,也十分重要的内容,本课要讲的内容不少,大家要集中精力、心无旁骛,才能跟上我讲解的思路。”</p>
<p class="content_105">从本课开始,我们会完整地讲解一个算法,并应用于机器学习实战。课程内容将完全按照第1课中所介绍的机器学习实战架构来规划,具体如下图所示。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0097-0105.jpg">
<p class="imgtitle">机器学习的实战架构</p>
</div>
<p class="content_105">(1)明确定义所要解决的问题—网店销售额的预测。</p>
<p class="content_105">(2)在数据的收集和预处理环节,分5个小节完成数据的预处理工作,分别如下。</p>
<p class="content">■收集数据—需要小冰提供网店的相关记录。</p>
<p class="content">■将收集到的数据可视化,显示出来看一看。</p>
<p class="content">■做特征工程,使数据更容易被机器处理。</p>
<p class="content">■拆分数据集为训练集和测试集。</p>
<p class="content">■做特征缩放,把数据值压缩到比较小的区间。</p>
<p class="content_105">(3)选择机器学习模型的环节,其中有3个主要内容。</p>
<p class="content">■确定机器学习的算法—这里也就是线性回归算法。</p>
<p class="content">■确定线性回归算法的假设函数。</p>
<p class="content">■确定线性回归算法的损失函数。</p>
<p class="content_105">(4)通过梯度下降训练机器,确定模型内部参数的过程。</p>
<p class="content_105">(5)进行超参数调试和性能优化。</p>
<p class="content_105">为了简化模型,上面的5个机器学习环节,将先用于实现单变量(仅有一个特征)的线性回归,在本课最后,还会扩展到多元线性回归。此处,先看看本课重点。</p>
<div class="bodyPic_104">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0097-0106.jpg">
</div>
<p class="content_105">咖哥说:“小冰,下面就由你来定义一下你要解决的具体问题吧。”</p>
<p class="content_105">小冰告诉咖哥,最近,因为她的网店做得有声有色,朋友们也纷纷找她来合作,其中一位朋友就请她帮着推销一种新型的血压计。为了使自己的推广更有针对性,小冰在自己的朋友圈发了1000份调查问卷,让朋友们完成心脏健康状况的一个测评,并收到了大概几百个结果。当然,这个调查问卷中的问题是她的朋友提供的专业内容,涉及医学知识,很多名词小冰也看不懂。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0130-0166.jpg">
<p class="imgtitle">心脏健康状况问卷调查结果</p>
</div>
<p class="content_101"><img alt="" class="h-pic" src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0130-0167.jpg">咖哥发言</p>
<p class="content">以下是测评中各列数值的中文含义。</p>
<p class="content">■age:年龄。</p>
<p class="content">■sex:性别。</p>
<p class="content">■cp:胸痛类型。</p>
<p class="content">■trestbps:休息时血压。</p>
<p class="content">■chol:胆固醇。</p>
<p class="content">■fbs:血糖。</p>
<p class="content">■restecg:心电图。</p>
<p class="content">■thalach:最大心率。</p>
<p class="content">■exang:运动后心绞痛。</p>
<p class="content">■oldpeak:运动后ST段压低。</p>
<p class="content">■slope:运动高峰期ST段的斜率。</p>
<p class="content">■ca:主动脉荧光造影染色数。</p>
<p class="content">■thal:缺陷种类。</p>
<p class="content">■target:0代表无心脏病,1代表有心脏病。</p>
<p class="content">在这个问卷中要注意以下两点。</p>
<p class="content">■从A栏到M栏,是调查的信息,包括年龄、性别、心脏功能的一些指标等,从机器学习的角度看就是特征字段。</p>
<p class="content">■问卷的最后一栏,第N栏的target字段,是调查的目标,也就是潜在客户患病还是未患病,这是标签字段。</p>
<p class="content">在收回的问卷中,有以下3种情况。</p>
<p class="content">■有一部分人已经是心脏病患者,这批人是我们的潜在客户群,则target = 1。</p>
<p class="content">■有一部分人确定自己没有心脏问题,那么目前他们可能就不大需要血压计这个产品,则target = 0。</p>
<p class="content">■还有一部分人只填好了调查表的前一部分,但是最后一个问题,是否有心脏病?他们没有填写答案,target字段是空白的。可能他们自己不知道,也可能他们不愿意提供这个答案给我们。<span class="bold">这些数据就是无标签的数据</span></p>
<p class="content_105">小冰问:“咖哥你看,现在我已经掌握了这么多<span class="bold">‘有标签’</span>的数据,那么能不能用刚才你所说的逻辑回归模型,对没有提供答案的人以及未来的潜在客户进行是否有心脏病的推测。如果能够推知这些潜在客户是否患心脏病,就等于知道这些潜在客户是否需要心脏保健相关产品(血压计)。这是多么精准的营销策略啊!”</p>
<p class="content_105">“当然可以。”咖哥回答,“只要你的数据是准确的,这个情况就很适合用逻辑回归来解决。你刚才说问卷中的很多专业性内容你不是很懂,那没有关系。<span class="bold">机器学习的一大优势,就是可以对我们本身并不是特别理解的数据,也产生精准的洞见</span>。”</p>
<p class="content_105">咖哥又说:“我看了一下,这几百张已收回的有标签(就是已经回答了最后一个问题:是否患心脏病?)的调查问卷,正是珍贵的机器学习‘训练集’和‘验证集’。下面就让逻辑回归算法来完成一个专业医生才能够做出的判断。”</p>
<p class="content_105">咖哥带着大家搞定了二元分类问题之后,马不停蹄地开始介绍多元分类。</p>
<p class="content_105">咖哥说:“还是老规矩,先介绍要解决的问题,然后讲方法。下面要解决一个经典机器学习教学案例:确定鸢尾花的种类。这也是一个典型的多分类问题。数据来自R.A.Fisher 1936年发表的论文,已开源供机器学习爱好者下载。同学们也可以从源代码包中找到这个数据集。”</p>
<p class="content">数据集中的鸢尾花(iris)共3类,分别是山鸢尾(iris-setosa)、杂色鸢尾(iris-versicolor)和维吉尼亚鸢尾(iris-virginica)。整个数据集中一共只有150个数据,已经按照标签类别排序,每类50个数据,其中有一类可以和其他两类进行线性的分割,但另外两类无法根据特征线性分割开。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0150-0206.jpg">
<p class="imgtitle">梵高名画:鸢尾花(请见339页彩色版插图)</p>
</div>
<p class="content">鸢尾花数据集的特征和标签字段如表4-1所示。</p>
<p class="content">■Id:序号。</p>
<p class="content">■Sepal Length Cm:花萼长度。</p>
<p class="content">■Sepal Width Cm:花萼宽度。</p>
<p class="content">■Petal Length Cm:花瓣长度。</p>
<p class="content">■Petal Width Cm:花瓣宽度。</p>
<p class="content">■Species:类别(这是标签)。</p>
<div class="pic_115">
<p class="imgtitle">表4-1 鸢尾花数据集中的特征和标签字段</p>
<img alt="" src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0151-0207.jpg">
</div>
<p class="content">复习一下刚才解决二元分类问题的基本思路:通过逻辑回归算法确定一个种类或者一种情况出现的概率。除了我们刚才举的例子客户是否患病之外,类似的应用还可以用来判断一种商品是否值得进货,结果大于等于0.5就进货(类别1),小于0.5就不进货(类别0),诸如此类,等等。</p>
<p class="content">然而,在实际生活中,分类并不总是二元的。多元分类就是多个类别,而且每一个类别和其他类别都是互斥的情况。也就是说,最终所预测的标签只能属于多个类别中的某一个。下图所示,同样是邮件分类问题,可以存在二元或多元的应用场景。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0151-0208.jpg">
<p class="imgtitle">从二元分类到多元分类</p>
</div>
<h3 class="thirdTitle" id="bw116"><a >4.5.1 以一对多</a></h3>
<p class="content_105">咖哥说:“用逻辑回归解决多元分类问题的思路是‘以一对多’,英文是one vs all或one vs rest。”</p>
<p class="content_105">小冰打断咖哥:“别说英文,说英文我更糊涂,还是用中文解释吧。”</p>
<p class="content_105">“唔……”咖哥说,“意思就是,有多个类别的情况下,如果确定一个数据样本属于某一个类(1),那么就把其他所有类看成另一类(0)。”</p>
<p class="content_105">小冰说:“还是不懂!”</p>
<p class="content_105">咖哥接着解释:“也就是说,有多少类别,就要训练多少二元分类器。每次选择一个类别作为正例,标签为1,其他所有类别都视为负例,标签为0,以此类推至所有的类别。训练好多个二元分类器之后,做预测时,将所有的二元分类器都运行一遍,然后对每一个输入样本,选择最高可能性的输出概率,即为该样本多元分类的类别。”</p>
<p class="content"></p>
<div class="bodyPic_104">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0152-0209.jpg">
</div>
<p class="content">下图就是多元分类示意。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0152-0210.jpg">
<p class="imgtitle">多元分类示意</p>
</div>
<p class="content">举例来说,如果对3个二元分类器分别做一次逻辑回归,机器的分类结果告诉我们,数据<span class="italic">A</span>是孔雀的可能性为0.5,是熊猫的可能性为0.1,是独角兽的可能性为0.4。那就会判断数据<span class="italic">A</span>是孔雀。尽管是独角兽的概率和是孔雀的概率相差不多,但它已经是孔雀了,就不可能同时是独角兽。</p>
<p class="content">这就是多分类问题的解决思路。</p>
<p class="content_101"><img alt="" class="h-pic" src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0152-0211.jpg">咖哥发言</p>
<p class="content">还有另外一种分类叫作“多标签分类”,指的是如果每种样本可以分配多个标签,就称为多标签分类。比如,一个图片标注任务,猫和狗同时出现在图片中,就需要同时标注“猫”“狗”。这是更为复杂的分类任务,但基本原理也是一样的。</p>
<h3 class="thirdTitle" id="bw117"><a >4.5.2 多元分类的损失函数</a></h3>
<p class="content">多元分类的损失函数的选择与输出编码,与标签的格式有关。</p>
<p class="content">多元分类的标签共有以下两种格式。</p>
<p class="content">■一种是one-hot格式的分类编码,比如,数字0~9分类中的数字8,格式为[0,0,0, 0,0,0,0,1,0]。</p>
<p class="content">■一种是直接转换为类别数字,如1、2、3、4。</p>
<p class="content">因此损失函数也有以下两种情况。</p>
<p class="content">■如果通过one-hot分类编码输出标签,则应使用分类交叉熵(categorical crossentropy)作为损失函数。</p>
<p class="content">■如果输出的标签编码为类别数字,则应使用稀疏分类交叉熵(sparse categorical crossentropy)作为损失函数。</p>
<p class="content">在开始解决鸢尾花的多元分类之前,先插播<span class="bold">正则化</span>(regularization)这个重要的机器学习概念,因为后面除了实现多元分类之外,还将特别聚焦于正则化相关的参数调整。</p>
<h3 class="thirdTitle" id="bw119"><a >4.6.1 正则化</a></h3>
<p class="content_105">温故而知新,先复习一下旧的概念。</p>
<p class="content_105">咖哥问:“小冰同学,数据的规范化和标准化,还记得吗?”</p>
<p class="content_105">小冰一愣,说:“好像都是特征缩放相关的技术,具体差别说不准。”</p>
<p class="content_105">咖哥说:“规范化一般是把数据限定在需要的范围,比如[0,1],从而消除了数据量纲对建模的影响。标准化一般是指将数据正态分布,使平均值为0,标准差为1。它们都是针对数据做手脚,消除过大的数值差异,以及离群数据所带来的偏见。经过规范化和标准化的数据,能加快训练速度,促进算法的收敛。”</p>
<p class="content_105">小冰说:“那正则化也是一种对数据做手脚的方法吗?”</p>
<p class="content_105">咖哥说:“不是。正则化不是对数据的操作。机器学习中的正则化是在损失函数里面加惩罚项,增加建模的模糊性,从而把捕捉到的趋势从局部细微趋势,调整到整体大概趋势。虽然一定程度上地放宽了建模要求,但是能有效防止过拟合的问题,增加模型准确性。它影响的是模型的权重。”</p>
<p class="content_101"><img alt="" class="h-pic" src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0153-0212.jpg">咖哥发言</p>
<p class="content">regularization、和normalization和standardization这3个英文单词因为看起来相似,常常混淆。标准化、规范化,以及归一化,是调整数据,特征缩放;而正则化,是调整模型,约束权重。</p>
<h3 class="thirdTitle" id="bw120"><a >4.6.2 欠拟合和过拟合</a></h3>
<p class="content">正则化技术所要解决的过拟合问题,连同欠拟合(underfit)一起,都是机器学习模型调优(找最佳模型)、参数调试(找模型中的最佳参数)过程中的主要阻碍。</p>
<p class="content">下面用图来描述欠拟合和过拟合。这是针对一个回归问题的3个机器学习模型,如下图所示。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0154-0213.jpg">
<p class="imgtitle">3个机器学习模型对数据集的拟合</p>
</div>
<p class="content">同学们可以想一想,这3个机器学习模型,哪一个的误差最小?</p>
<p class="content">正确答案是第3个。</p>
<p class="content">在开展一个机器学习项目的初期,会倾向于用比较简单的函数模型去拟合训练数据集,比如线性函数(上图第1个)。后来发现简单的函数模型不如复杂一点的模型拟合效果好,所以调整模型之后,有可能会得到更小的均方误差(上图第2个)。但是,计算机专业的总会有点小强迫症,这是我们的职业病啊。如果继续追求更完美的效果,甚至接近于0的损失,可能会得到类似于上图第3个函数图形。</p>
<p class="content">那么上图第3个函数好不好呢?</p>
<p class="content">好不好,不能单看训练集上的损失。或者说,不能主要看训练集上的损失,更重要的是看测试集上的损失。让我们画出机器学习模型优化过程中的误差图像,如下图所示。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0154-0214.jpg">
<p class="imgtitle">寻找模型优化和泛化的平衡点</p>
</div>
<p class="content">看得出来,一开始模型“很烂”的时候,训练集和测试集的误差都很大,这是<span class="bold">欠拟合</span>。随着模型的优化,训练集和测试集的误差都有所下降,其中训练集的误差值要比测试集的低。这很好理解,因为函数是根据训练集拟合的,泛化到测试集之后表现会稍弱一点。但是,如果此处继续增加模型对训练集的拟合程度,会发现测试集的误差将逐渐升高。这个过程就被称作<span class="bold">过拟合</span></p>
<p class="content_101"><img alt="" class="h-pic" src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0155-0215.jpg">咖哥发言</p>
<p class="content">注意,这里的模型的复杂度可以代表迭代次数的增加(内部参数的优化),也可以代表模型的优化(特征数量的增多、函数复杂度的提高,比如从线性函数到二次、多次函数,或者说决策树的深度增加,等等)。</p>
<p class="content">所以,过拟合就是机器学习的模型过于依附于训练集的特征,因而模型<span class="bold">泛化</span>能力降低的体现。泛化能力,就是模型从训练集移植到其他数据集仍然能够成功预测的能力。</p>
<p class="content">分类问题也会出现过拟合,如下图所示,过于细致的分类边界也造成了过拟合。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0155-0216.jpg">
<p class="imgtitle">3个分类器的分类边界</p>
</div>
<p class="content"><span class="bold">过拟合现象是机器学习过程中怎么甩都甩不掉的阴影</span>,影响着模型的泛化功能,因此我们几乎在每一次机器学习实战中都要和它作战!</p>
<p class="content">刚才用逻辑回归模型进行心脏病预测的时候,我们也遇见了过拟合问题。那么,有什么方法解决吗?</p>
<p class="content">降低过拟合现象通常有以下几种方法。</p>
<p class="content">■增加数据集的数据个数。数据量太小时,非常容易过拟合,因为小数据集很容易精确拟合。</p>
<p class="content">■找到模型优化时的平衡点,比如,选择迭代次数,或者选择相对简单的模型。</p>
<p class="content"><span class="bold">正则化</span>。为可能出现过拟合现象的模型增加正则项,通过降低模型在训练集上的精度来提高其泛化能力,这是非常重要的机器学习思想之一。</p>
<h3 class="thirdTitle" id="bw121"><a >4.6.3 正则化参数</a></h3>
<p class="content">机器学习中的正则化通过引入模型参数<span class="italic">λ</span>(lambda)来实现。</p>
<p class="content">加入了正则化参数之后的线性回归均方误差损失函数公式被更新成下面这样: </p>
<div class="bodyPic_104">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0155-0217.jpg">
</div>
<p class="content">加入了正则化参数之后的逻辑回归均方误差损失函数公式被更新成下面这样:</p>
<div class="bodyPic_104">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0155-0218.jpg">
</div>
<p class="content">现在的训练优化算法是一个由两项内容组成的函数:一个是<span class="bold">损失项</span>,用于衡量模型与数据的拟合度;另一个是<span class="bold">正则化项</span>,用于调解模型的复杂度。</p>
<p class="content">公式看起来有点小复杂,但也不用特别介意,因为正则化参数已经被嵌入Python的库函数内部。从直观上不难看出,将正则化机制引入损失函数之后,当权重大的时候,损失被加大,<span class="italic">λ</span>值越大,惩罚越大。这个公式引导着机器在进行拟合的时候不会随便增加权重。</p>
<p class="content">记住,正则化的目的是帮助我们减少过拟合的现象,而它的本质是约束(限制)要优化的参数。</p>
<p class="content">其实,正则化的本质,就是<span class="bold">崇尚简单化</span>。同时以最小化损失和复杂度为目标,这称为<span class="bold">结构风险最小化</span></p>
<p class="content_101"><img alt="" class="h-pic" src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0156-0219.jpg">咖哥发言</p>
<p class="content">奥卡姆的威廉是14世纪的修士和哲学家,是极简主义的早期代言人。他提出的<span class="bold">奥卡姆剃刀定律</span>认为科学家应该优先采用更简单的公式或理论。将该理论应用于机器学习,就意味着越简单的模型,有可能具有越强的泛化能力。</p>
<p class="content">选择<span class="italic">λ</span>值的目标是在简单化和训练集数据拟合之间达到适当的平衡。</p>
<p class="content">■如果<span class="italic">λ</span>值过大,则模型会非常简单,将面临数据欠拟合的风险。此时模型无法从训练数据中获得足够的信息来做出有用的预测。而且<span class="italic">λ</span>值越大,机器收敛越慢。</p>
<p class="content">■如果<span class="italic">λ</span>值过小,则模型会比较复杂,将面临数据过拟合的风险。此时模型由于获得了过多训练数据特点方面的信息而无法泛化到新数据。</p>
<p class="content">■将<span class="italic">λ</span>设为0可彻底取消正则化。在这种情况下,训练的唯一目的是最小化损失,此时过拟合的风险较高。</p>
<p class="content">正则化参数通常有L1正则化和L2正则化两种选择。</p>
<p class="content">■L1正则化,根据权重的绝对值的总和来惩罚权重。在依赖稀疏特征(后面会讲什么是稀疏特征)的模型中,L1正则化有助于使不相关或几乎不相关的特征的权重正好为0,从而将这些特征从模型中移除。</p>
<p class="content">■L2正则化,根据权重的平方和来惩罚权重。L2 正则化有助于使离群值(具有较大正值或较小负值)的权重接近于0,但又不会正好为0。在线性模型中,L2 正则化比较常用,而且在任何情况下都能够起到增强泛化能力的目的。</p>
<p class="content">同学们可能注意到了,刚才给出的正则化公式实际上是L2正则化,因为权重<span class="italic">w</span>正则化时做了平方。</p>
<p class="content_101"><img alt="" class="h-pic" src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0156-0220.jpg">咖哥发言</p>
<p class="content">正则化不仅可以应用于逻辑回归模型,也可以应用于线性回归和其他机器学习模型。应用L1正则化的回归又叫Lasso Regression(套索回归),应用L2正则化的回归又叫Ridge Regression(岭回归)。</p>
<p class="content">而最佳<span class="italic">λ</span>值则取决于具体数据集,需要手动或自动进行调整。下面就通过多元分类的一个案例来解释正则化参数的调整。</p>
<p class="content">下面就开始用逻辑回归来解决之前介绍过的鸢尾花的分类问题:根据花萼和花瓣的长度数据来判断其类别。</p>
<h3 class="thirdTitle" id="bw123"><a >4.7.1 数据的准备与分析</a></h3>
<p class="content">同学们可以在源码包中找到这个数据集,而且Sklearn也自带这个数据集。这个数据集中,有4个特征,为了方便可视化,我们将特征两两组合。我将主要使用花萼长度和花萼宽度这两个特征来判断其分类,剩下两个特征组成的花瓣特征集则留给同学们自己来尝试做类似的工作。</p>
<div class="content_106">
<p class="content_105">import numpy as np # 导入Num Py</p>
<p class="content_105">import pandas as pd # 导入Pandas</p>
<p class="content_105">from sklearn import datasets # 导入Sklearn的数据集</p>
<p class="content_105">iris=datasets.load_iris() # 导入iris</p>
<p class="content_105">X_sepal = iris.data[:, [0, 1]]</p>
<p class="content_142"># 花萼特征集:两个特征长度和宽度</p>
<p class="content_105">X_petal = iris.data[:, [2, 3]]</p>
<p class="content_142"># 花瓣特征集:两个特征长度和宽度</p>
<p class="content_105">y = iris.target # 标签集</p>
</div>
<p class="content">现在我们拥有两个独立的特征集,一个特征集包含花萼长度、花萼宽度,另一个包含花瓣长度、花瓣宽度。</p>
<p class="content">如果根据花萼长度、花萼宽度这两个特征将3种鸢尾花的分类可视化,会得到如下图所示的结果。此时每一个特征代表一个轴,类别(即标签)则通过圆点、叉、三角等不同的形状进行区分。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0157-0221.jpg">
<p class="imgtitle">3种鸢尾花样本的分布</p>
</div>
<p class="content">下面进行花萼数据集的分割和标准化,分成训练集和测试集:</p>
<div class="content_106">
<p class="content_105">from sklearn.model_selection import train_test_split # 导入拆分数据集工具</p>
<p class="content_105">from sklearn.preprocessing import Standard Scaler # 导入标准化工具</p>
<p class="content_105">X_train_sepal, X_test_sepal, y_train_sepal, y_test_sepal = \</p>
<p class="content_143">train_test_split(X_sepal, y, test_size=0.3, random_state=0) # 拆分数据集</p>
<p class="content_105">print("花瓣训练集样本数: ", len(X_train_sepal))</p>
<p class="content_105">print("花瓣测试集样本数: ", len(X_test_sepal))</p>
<p class="content_105">scaler = Standard Scaler() # 标准化工具</p>
<p class="content_105">X_train_sepal = scaler.fit_transform(X_train_sepal) # 训练集数据标准化</p>
<p class="content_105">X_test_sepal = scaler.transform(X_test_sepal) # 测试集数据标准化</p>
<p class="content_105"># 合并特征集和标签集, 留待以后数据展示之用</p>
<p class="content_105">X_combined_sepal = np.vstack((X_train_sepal, X_test_sepal)) # 合并特征集</p>
<p class="content_105">Y_combined_sepal = np.hstack((y_train_sepal, y_test_sepal)) # 合并标签集</p>
</div>
<h3 class="thirdTitle" id="bw124"><a >4.7.2  通过Sklearn实现逻辑回归的多元分类</a></h3>
<p class="content">下面直接通过Sklearn的Logistic Regression函数实现多元分类功能:</p>
<div class="content_106">
<p class="content_105">from sklearn.linear_model import Logistic Regression # 导入逻辑回归模型</p>
<p class="content_105">lr = Logistic Regression(penalty='l2', C = 0.1) # 设定L2正则化和C参数</p>
<p class="content_105">lr.fit(X_train_sepal, y_train_sepal) # 训练机器</p>
<p class="content_105">score = lr.score(X_test_sepal, y_test_sepal) # 验证集分数评估</p>
<p class="content_105">print("SKlearn逻辑回归测试准确率 {:.2f}%".format(score*100))</p>
</div>
<p class="content">得到的准确率:</p>
<p class="content_112">Sklearn逻辑回归测试准确率:66.67%</p>
<p class="content">这里采用了刚才介绍的L2正则化,这是通过penalty参数设定的。</p>
<p class="content">但是,另外一个参数<span class="italic">C</span>又是什么东西呢?</p>
<p class="content">L2正则化,只是选择了正则化的参数类别,但是用多大的力度进行呢?此时要引入另外一个配套用的正则化相关参数<span class="italic">C</span><span class="italic">C</span>表示正则化的力度,它与<span class="italic">λ</span>刚好成反比。<span class="italic">C</span>值越小,正则化的力度越大。</p>
<p class="content_101"><img alt="" class="h-pic" src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0158-0222.jpg">咖哥发言</p>
<p class="content">同学们,如果你们搜索“sklearn.linear_model”“Logistic Regression”这两个关键字,很容易找到Sklearn的官方文档(如下图所示),在那里可以学习库函数,了解各个参数的全面信息。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0158-0223.jpg">
<p class="imgtitle">Sklearn的官方文档,提供库函数和各个参数的全面信息</p>
</div>
<h3 class="thirdTitle" id="bw125"><a >4.7.3 正则化参数——C值的选择</a></h3>
<p class="content">下面就用绘图的方式显示出采用不同的<span class="italic">C</span>值,对于鸢尾花分类边界的具体影响。这样做的目的是进一步了解正则化背后的意义,以及对此问题采用什么样的正则化参数才是最优的选择。这也即是超参数调试的又一次实战。</p>
<p class="content">首先定义一个绘图的函数:</p>
<div class="content_106">
<p class="content_105">import matplotlib.pyplot as plt # 导入Matplotlib库</p>
<p class="content_105">from matplotlib.colors import Listed Colormap # 导入Listed Colormap</p>
<p class="content_105">def plot_decision_regions(X, y, classifier, test_idx=None, resolution=0.02):</p>
<p class="content_121">markers = ('o', 'x', 'v')</p>
<p class="content_121">colors = ('red', 'blue', 'lightgreen')</p>
<p class="content_121">color_Map = Listed Colormap(colors[:len(np.unique(y))])</p>
<p class="content_121">x1_min = X[:, 0].min() - 1</p>
<p class="content_121">x1_max = X[:, 0].max() + 1</p>
<p class="content_121">x2_min = X[:, 1].min() - 1</p>
<p class="content_121">x2_max = X[:, 1].max() + 1</p>
<p class="content_121">xx1, xx2 = np.meshgrid(np.arange(x1_min, x1_max, resolution),</p>
<p class="content_135">np.arange(x2_min, x2_max, resolution))</p>
<p class="content_121">Z = classifier.predict(np.array([xx1.ravel(), xx2.ravel()]).T)</p>
<p class="content_121">Z = Z.reshape(xx1.shape)</p>
<p class="content_121">plt.contour(xx1, xx2, Z, alpha=0.4, cmap = color_Map)</p>
<p class="content_121">plt.xlim(xx1.min(), xx1.max())</p>
<p class="content_121">plt.ylim(xx2.min(), xx2.max())</p>
<p class="content_121">X_test, Y_test = X[test_idx, :], y[test_idx]</p>
<p class="content_121">for idx, cl in enumerate(np.unique(y)):</p>
<p class="content_111">plt.scatter(x = X[y == cl, 0], y = X[y == cl, 1],</p>
<p class="content_124">alpha = 0.8, c = color_Map(idx),</p>
<p class="content_124">marker = markers[idx], label = cl)</p>
</div>
<p class="content">然后使用不同的<span class="italic">C</span>值进行逻辑回归分类,并绘制分类结果:</p>
<div class="content_106">
<p class="content_105">from sklearn.metrics import accuracy_score # 导入准确率指标</p>
<p class="content_105">C_param_range = [0.01, 0.1, 1, 10, 100, 1000]</p>
<p class="content_105">sepal_acc_table = pd.Data Frame(columns = ['C_parameter', 'Accuracy'])</p>
<p class="content_105">sepal_acc_table['C_parameter'] = C_param_range</p>
<p class="content_105">plt.figure(figsize=(10, 10))</p>
<p class="content_105">j = 0</p>
<p class="content_105">for i in C_param_range:</p>
<p class="content_121">lr = Logistic Regression(penalty = 'l2', C = i, random_state = 0)</p>
<p class="content_121">lr.fit(X_train_sepal, y_train_sepal)</p>
<p class="content_121">y_pred_sepal = lr.predict(X_test_sepal)</p>
<p class="content_121">sepal_acc_table.iloc[j, 1] = accuracy_score(y_test_sepal, y_pred_sepal)</p>
<p class="content_121">j += 1</p>
<p class="content_121">plt.subplot(3, 2, j)</p>
<p class="content_121">plt.subplots_adjust(hspace = 0.4)</p>
<p class="content_121">plot_decision_regions(X = X_combined_sepal, y = Y_combined_sepal,</p>
<p class="content_135">classifier = lr, test_idx = range(0, 150))</p>
<p class="content_121">plt.xlabel('Sepal length')</p>
<p class="content_121">plt.ylabel('Sepal width')</p>
<p class="content_121">plt.title('C = %s'%i)</p>
</div>
<p class="content">运行上面的代码段,绘制出各个不同<span class="italic">C</span>值情况下的分类边界,如下图所示。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0160-0224.jpg">
<p class="imgtitle">不同C值带来不同的分类边界</p>
</div>
<p class="content">上面图中不同的<span class="italic">C</span>值所展现出的分类边界线和分类的结果告诉了我们以下一些信息。</p>
<p class="content">(1)<span class="italic">C</span>取值越大,分类精度越大。注意,当<span class="italic">C</span>=1 000时图中左下方的圆点,本来按照其特征空间的位置来说,应该被放弃纳入圆点类,但是算法因为正则化的力度过小,过分追求训练集精度而将其划至山鸢尾集(圆点类),导致算法在这里过拟合。</p>
<p class="content">(2)而当<span class="italic">C</span>值取值过小时,正则化的力度过大,为了追求泛化效果,算法可能会失去区分度。</p>
<p class="content">还可以绘制出测试精度随着<span class="italic">C</span>参数的不同取值而变化的学习曲线(learning curve),如右图所示。这样,可以更清晰地看到<span class="italic">C</span>值是如何影响训练集以及测试集的精度的。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0160-0225.jpg">
<p class="imgtitle">不同<span class="italic">C</span>值来不同的分类准确率</p>
</div>
<p class="content">该如何选择<span class="italic">C</span>值呢?学者们认为应该有以下两点考量因素。</p>
<p class="content">(1)一个因素是应该观察比较高的测试集准确率。</p>
<p class="content">(2)另一个因素是训练集和测试集的准确率之差比较小,通常会暗示更强的泛化能力。</p>
<p class="content">如果选择<span class="italic">C</span>值为10重做逻辑回归:</p>
<div class="content_106">
<p class="content_105">lr = Logistic Regression(penalty='l2', C = 10) # 设定L2正则化和C参数</p>
<p class="content_105">lr.fit(X_train_sepal, y_train_sepal) # 训练机器</p>
<p class="content_105">score = lr.score(X_test_sepal, y_test_sepal) # 测试集分数评估</p>
<p class="content_105">print("Sklearn逻辑回归测试准确率 {:.2f}%".format(score*100))</p>
</div>
<p class="content">此时测试准确率会有所提高:</p>
<p class="content_112">Sklearn逻辑回归测试准确率:68.89%</p>
<p class="content_105">“本课内容就这么多,”咖哥说,“最重点的内容,是要记住逻辑回归只不过是在线性回归的基础上增加了一个Sigmoid逻辑函数,把目标值的输出限制在[0,1]区间而已。除此之外,整个流程即细节都和线性回归非常相似。当然其假设函数和损失函数和线性回归是不同的。”</p>
<p class="content">逻辑回归的假设函数如下:</p>
<div class="bodyPic_104">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0161-0226.jpg">
</div>
<p class="content">逻辑回归的损失函数如下:</p>
<div class="bodyPic_104">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0161-0227.jpg">
</div>
<p class="content">另外需要牢记的是,这两种基本的机器学习算法中,线性回归多用于解决回归问题(可简单理解为数值预测型问题),而逻辑回归多用于解决分类问题。</p>
<p class="content">大家不要以为线性回归和逻辑回归在深度学习时代过时了。2017年Kaggle的调查问卷显示(如下图所示),在目前数据科学家的工作中,线性回归和逻辑回归的使用率仍然高居榜首,因为这两种算法可以快速应用,作为其他解决方案的基准模型。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0161-0228.jpg">
<p class="imgtitle">别小看线性回归和逻辑回归</p>
</div>
<p class="content_105">咖哥正说着,突然问:“小冰,超参数的调试是否让你觉得有些麻烦,一个小小的<span class="italic">C</span>参数怎么花那么大力气画各种各样的图来观察?”</p>
<p class="content_105">小冰说:“就是啊,怎么这么麻烦?”</p>
<p class="content_105">咖哥说:“其实也是有自动调参的方法。”</p>
<p class="content_105">小冰说:“快说说。”</p>
<p class="content_105">咖哥说:“这个以后再讲吧。先记住已经学的基础知识。”</p>
<p class="content_105">机器学习解决现实问题的超强能力让小冰新奇而又兴奋,她真的觉得过瘾极了。机器学习的两个模型已经解决了困扰着她的两个非常实际的业务问题,那么下一课,咖哥又将介绍一些什么新的模型呢?她迫不及待地想要知道。</p>
<div class="content_120">
<p class="content">练习一 根据第4课的练习案例数据集:泰坦尼克数据集(见源码包),并使用本课介绍的方法完成逻辑回归分类。</p>
<p class="content">(提示:在进行拟合之前,需要将类别性质的字段进行类别到哑变量的转换。)</p>
<p class="content">练习二 在多元分类中,我们基于鸢尾花萼特征,进行了多元分类,请同学们用类似的方法,进行花瓣特征集的分类。</p>
<p class="content">练习三 请同学们基于花瓣特征集,进行正则化参数<span class="italic">C</span>值的调试。</p>
</div>
\ No newline at end of file
<h1 class="firstTitle"><a >第4课 逻辑回归——给病患和鸢尾花分类</a></h1>
<p class="content_105">我们已经通过线性回归模型成功解决了回归问题,本课就来处理分类问题。分类问题与回归问题,是机器学习两大主要应用。</p>
<p class="content_105">分类问题覆盖面很广泛:有二元分类,如根据考试成绩推断是否被录取、根据消费记录判断信用卡是否可以申请,以及预测某天是否将发生地震等;有多元分类,如消费群体的划分、个人信用的评级等;还有图像识别、语音识别等,在本质上也是很多个类别的分类问题。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0129-0164.jpg">
<p class="imgtitle">垃圾分类器帮助市民确定垃圾的类别</p>
</div>
<p class="content_105">本课要讲的专用于分类的机器学习算法,叫逻辑回归(logistic regression),简称Logreg。</p>
<p class="content_105">“等等,咖哥。”小冰问道,“你刚才说,机器学习两大主要应用是回归问题和分类问题,可你又说这个逻辑回归算法,专用于分类问题,这我就不明白了,专用于分类问题的算法,为什么叫逻辑回归,不叫‘逻辑分类’算法呢?”</p>
<p class="content_105">“哈哈。”咖哥说,“你这就有点咬文嚼字了。逻辑回归算法的本质其实仍然是回归。这个算法也是通过调整权重<span class="italic">w</span>和偏置<span class="italic">b</span>来找到线性函数来计算数据样本属于某一类的概率。比如二元分类,一个样本有60%的概率属于A类,有20%的概率属于B类,算法就会判断样本属于A类。”</p>
<p class="content_105">咖哥接着说:“不过,在介绍这些细节之前,还是先看本课重点吧。”</p>
<div class="bodyPic_104">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0130-0165.jpg">
</div>
<p class="content_105">“Stop!咖哥,”小冰听说了逻辑回归能解决各种分类问题之后,突然喊道,“我想到了我的一个朋友现在正在做的一个医疗产品,也许这个逻辑回归机器学习模型可以帮到他!”</p>
<p class="content_105">“好啊,那不妨先听一听你的具体需求吧。”咖哥回答。</p>
<p class="content">这次的实战,来看一个我最近接手的金融领域项目吧,我的团队正是用神经网络,也就是深度学习模型,解决了这个问题。</p>
<p class="content">该项目的具体需求是根据已知的一批客户数据(当然客户姓名我都进行了掩码),来预测某个银行的客户是否会流失。通过学习历史数据,如果机器能够判断出哪些客户很有可能在未来两年内结束在该银行的业务(这当然是银行所不希望看到的),那么银行的工作人员就可以采取相应的、有针对性的措施来挽留这些高流失风险的客户。其实这个问题和上一课的心脏病预测问题一样,本质上都是分类,我们看看用神经网络来解决这类问题有何优势。</p>
<p class="content">从第5课源码包的“教学用例 银行客户流失”目录中找到Bank Customer.csv文件之后,读入本机的Python环境,或者在Kaggle网站搜索Jacky Huang的“Bank Customer”数据集 (如下图所示)或根据源码包中的文件新建Dataset,然后创建Notebook。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0164-0231.jpg">
<p class="imgtitle">银行客户数据集</p>
</div>
<div class="content_120">
<p class="content">练习一 对本课示例继续进行参数调试和模型优化。</p>
<p class="content">(提示:可以考虑增加或者减少迭代次数、增加或者减少网络层数、添加Dropout层、引入正则项,以及选择其他优化器等。)</p>
<p class="content">练习二 第5课的练习数据集仍然是泰坦尼克数据集,使用本课介绍的方法构建神经网络处理该数据集。</p>
<p class="content">练习三 使用TensorBoard和回调函数显示训练过程中的信息。</p>
</div>
<hr>
<p class="noindent" id="annot11"><a >[1].</a>图片参考了李宏毅老师的机器学习教学视频</p>
<p class="noindent" id="annot12"><a >[2].</a>肖莱.Python深度学习[M].张亮,译.北京:人民邮电出版社,2018.</p>
\ No newline at end of file
<h3 class="thirdTitle" id="bw130"><a >5.2.1 神经网络极简史</a></h3>
<p class="content">神经网络其实有一段“悠久”的历史。早在1958年,计算机科学家罗森布拉特(Rosenblatt)就提出了一种具有单层网络特性的神经网络结构,称为“感知器”(perceptron)。感知器出现之后很受瞩目,大家对它的期望很高。然而好景不长—一段时间后,人们发现感知器的实用性很弱。1969年,AI的创始人之一马文·明斯基(Marvin Minsky)指出简单神经网络只能运用于线性问题的求解。这之后神经网络就逐渐被遗忘了。</p>
<p class="content">直到1985年,杰弗里·辛顿(Geoffrey Hinton,深度学习“三巨头”之一)和特伦斯·谢诺夫斯基(Terrence Sejnowski)提出了一种随机神经网络模型—受限玻尔兹曼机。紧接着, Rumelhart、Hinton、Williams提出了BP算法,即多层感知器的梯度反向传播算法。这也是神经网络的核心算法,人们以此为基础搭建起几乎现代所有的深度网络模型。因此,可以说神经网络的理论基础在20世纪60年代出现,并在80年代几乎完全形成。</p>
<p class="content">在工程界,当时神经网络也已经有了应用。杨立昆(Yann Le Cun,深度学习“三巨头”之一)于20世纪80年代末在贝尔实验室研发出了卷积神经网络,他将其应用到手写识别和OCR,并在美国广泛应用于手写邮编、支票的读取。然而后来,另一种理论相当完善的机器学习技术支持向量机(Support Vector Machine,SVM)被发明出来,成为了业界“新宠”,神经网络再一次被遗忘了。</p>
<p class="content">大约2009年,计算机最终有了足够的算力进行深度计算,神经网络开始在语音和图像识别方面战胜传统算法。杰弗里·辛顿、杨立昆和约书亚·本吉奥(Yoshua Bengio)3人联合提出<span class="bold">深度学习</span>的概念。这是新瓶装旧酒,名称变了,技术还是一样的技术。然而时代也已经改变,此时深度神经网络开始实证性地在工程界展示出绝对的优势。2012年年底,基于卷积神经网络模型的Inception结构在ImageNet图片分类竞赛中获胜。此后深度学习火山爆发式发展,科技“巨头”们开始在这个领域投资:计算机视觉、语音识别、自然语言处理、棋类竞赛和机器人技术,这些应用领域的突破一个接着一个出现……</p>
<p class="content">其实,从一开始就不是神经网络不行,而是原来的数据量和计算速度两方面都跟不上。在这个数据泛滥的时代,海量数据的获取不再是什么难事。可以预见,在5G时代,深度学习必然还会有更大发展的空间……</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0165-0232.jpg">
<p class="imgtitle">在大数据领域,神经网络的效能显著地领先于其他算法</p>
</div>
<p class="content">讲完历史,咖哥抛出了一个问题让大家去思索—机器学习应用领域,也就是回归和分类这两大块,既然有了线性回归和逻辑回归两大机器学习基础算法,这两类问题都可解了。那么,为什么还需要神经网络?它有什么特别的优势?</p>
<h3 class="thirdTitle" id="bw131"><a >5.2.2 传统机器学习算法的局限性</a></h3>
<p class="content">先说一说传统机器学习算法的局限性。首先,越简单的关系越容易拟合。比如,第3课中的广告投放金额和商品销售额的例子,一个线性函数就能轻松地搞定。然而对于一个非线性的问题(如下图所示),就需要通过更复杂的函数模型(如高阶多项式)去拟合。此时,单纯线性回归明显不给力,因而我们把特征重新组合,变化出新的特征。比如,一次函数不够用时,可以把<span class="italic">x</span><span class="sub">1</span>做平方变成<span class="italic">x</span><span class="sub">1</span>2,做立方变成<span class="italic">x</span><span class="sub">1</span>3,甚至可以和<span class="italic">x</span><span class="sub">2</span>做组合,变成<span class="italic">x</span><span class="sub">1</span><span class="italic">x</span><span class="sub">2</span><span class="italic">x</span><span class="sub">1</span>2<span class="italic">x</span><span class="sub">2</span>等,不断创造出新的特征,构造新的函数,直到把训练集的数据拟合好为止。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0165-0233.jpg">
<p class="imgtitle">复杂的关系需要复杂的函数去拟合</p>
</div>
<p class="content">这种对特征的变换、升阶,以及多个特征相互组合形成新特征的过程,就是机器学习过程中既耗时又耗力的<span class="bold">特征工程</span>的一个例子。</p>
<p class="content">当特征的维度越来越大时,特征之间相互组合的可能性将以几何级数递增,特征空间急剧膨胀,对应的假设空间也随之膨胀。此时,你们会惊奇地发现,单纯用线性回归和逻辑回归模型进行的机器学习会显得越来越力不从心,因为特征工程本身就已经把机器“累死”了。</p>
<p class="content_101"><img alt="" class="h-pic" src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0166-0234.jpg">咖哥发言</p>
<p class="content">特征空间是数据特征所形成的空间,特征维度越高,特征空间越复杂。而假设空间则是假设函数形成的空间,特征越多,特征和标签之间的对应的关系越难拟合,假设空间也就越复杂。</p>
<p class="content">此时,要进一步扩展机器学习的应用领域,我们就需要更强的系统去减少对特征工程的需求,去解决巨大特征量的问题,这就是……</p>
<p class="content_105">“等一下。”小冰发问,“有这样多特征的实际问题吗?前面介绍的房价预测、销售额预测、客户分类等,感觉特征的数量两只手都能比划出来,房屋面积、广告投放金额、胸痛类型、休息时血压等,也就这些东西,怎么就难了?”</p>
<p class="content_105">“啊,原来你是这么想的。”咖哥说,“那我再多解释一下。”</p>
<p class="content">前几课中咱们处理的问题,都是<span class="bold">结构化数据</span>。这种结构化数据有一个特点,就是人弄起来很费劲儿,但是计算机会很快搞定。比如一堆堆的血压、脉搏计数,让很有经验的医生去分析,如果数据量很大的话,他也得看一阵子。因为人脑在处理数字、运算时是有局限性的,和计算机比的话既不够快也不够准。</p>
<p class="content">那么什么是<span class="bold">非结构化数据</span>呢?就是没有什么预定义的数据结构,不方便用数据库存储,也不方便用Excel表格来表现的数据。比如,办公文档、文本、图片、网页、各种图像/音频/视频信息等,都是非结构化数据。你们可能看出来了,这些数据大都和人类的感觉、知觉相关。笼统地说,也可称为<span class="bold">感知类数据</span>。人脑理解和处理感知类数据在深度学习出现之前比计算机好使。比如一只猫的图片,我们不会根据一个个像素点去分析特征,哪个像素点是耳朵的一部分,哪个像素点是鼻子的一部分,哪个像素点应该是红色,哪个像素点应该是黑色。小孩子看了,也能轻而易举地知道图片里面的内容是猫。因为可能很多<span class="bold">“深度”的经验</span>已经集成在人脑的潜意识里面了。</p>
<p class="content">对于这种类型的问题,传统的机器学习模型比如线性回归或者逻辑回归,就不大好使。因为要训练一个分类器来判断图片是否为一只猫时,计算机实际上看到的是一个巨大的数字矩阵(如下图所示),矩阵中的每一个数字代表一个像素的强度(亮度、颜色)值,比如猫眼睛处像素值对应为黑色、猫的嘴处为红色等。我们会输入大量的猫图片样本集,希望经过学习之后,模型知道大概什么地方会出现什么样的像素,比如猫眼睛是什么样,或者是猫耳朵是什么样的,等等。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0166-0235.jpg">
<p class="imgtitle">人眼看猫,计算机看数字矩阵</p>
</div>
<p class="content">即使图片很小,长宽也各有50像素,也就是有2 500个特征 。如果是RGB彩色图像,那么特征的数目就是7 500了。如果特征之间还可以组合,特征空间可以达到上百万的级别。不仅是图片,其他感知类数据如文本、网页,都出现类似特征维度超大的现象。对于传统机器学习算法来说,计算成本太高了。而且,这些像素特征和分类结果之间的拟合过于复杂,如果通过手工特征工程来辅助机器学习的建模,这个特征工程本身的难度也将是巨大的。</p>
<p class="content_101"><img alt="" class="h-pic" src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0167-0236.jpg">咖哥发言</p>
<p class="content">机器学习中有个术语叫“维度灾难”,即高维度带来了超高的复杂度和超巨大的特征空间。比如,对于围棋来说,特征维度是19×19,但是它的有效状态数量超过了10<span class="super">170</span></p>
<p class="content">而神经网络就是专门为了解决这类超高特征维度的感知类问题而生的。数学上已经证明,浅层神经网络可以模拟任何连续函数。而深层神经网络更是可以用更少的参数来学到更好的拟合。特征数量越大,神经网络优势越明显。机器学习,学的就是对客观世界事物之间关系的拟合,谁的拟合能力更强,实现起来更简便,谁就是“王者”。因而,神经网络,尤其是深度神经网络,在大数据时代肩负着处理超高维特征问题以及减少特征工程两大重任,是处理感知类问题的一把利刃。</p>
<h3 class="thirdTitle" id="bw132"><a >5.2.3 神经网络的优势</a></h3>
<p class="content">还是借着刚才这个猫的例子,说说神经网络是怎么做到这种不惧巨大特征量的“深度学习”的。</p>
<p class="content">假设我们是在传统AI模型上弄一个猫识别器,首先需要花大量的时间来帮机器定义什么是“猫”—2个眼睛,4条腿,尖尖的耳朵,软软的毛…… 这些信息输入机器,组合起来构成了一只猫。然后对图片里面的特征进行分解,拆分成一小块一小块的元素,眼睛、毛发颜色、胡须、爪子,等等。最后将这些元素和机器记忆中的信息进行比对,如果大多数都吻合了,那么这就是一只猫。</p>
<p class="content">而现在用神经网络去识别猫可就省力多了。不必手工去编写猫的定义,它的定义只存在于网络中大量的“<span class="bold">分道器”</span>之中。这些分道器负责控制在网络的每一个分岔路口把图片往目的地输送。而神经网络就像一张无比庞大、带有大量分岔路的铁轨网,如右图所示。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0167-0237.jpg">
<p class="imgtitle">网络把猫全都输送到猫站,狗全都输送到狗站</p>
</div>
<p class="content">在这密密麻麻的铁轨的一边是输入的图片,另一边则是对应的输出结果,也就是道路的终点。网络会通过调整其中的每一个分道器来确保输入映射到正确的输出。训练数据越多,这个网络中的轨道越多,分岔路口越多,网络也就越复杂。一旦训练好了,我们就拥有了大量的预定轨道,对新图片也能做出可靠的预测,这就是神经网络的自我学习原理(本小节内容部分参考了《谷歌大脑养成记》,由公众号机器之心编译)。</p>
<p class="content_105">小冰插嘴:“咦?好像这个神经网络的原理和线性回归或者逻辑回归完全相同,不就是通过不断地训练寻找最佳的参数嘛!”</p>
<p class="content_105">咖哥答:“你说得简直太正确了!它们本来就是一回事,唯一的不同是,神经网络的参数多、层级深,需要的数据量也多。”</p>
<p class="content">那么为什么这个网络需要如此多的神经元和数据呢?</p>
<p class="content">因为这是训练机器的必需项。到底是猫是狗,由网络中成千上万个“分道器” 神经元决定。拿出一张猫图片问:这是什么?铁轨大网经过重重分叉,在第一次判断中把它输送到了狗站。</p>
<p class="content">机器告诉铁轨大网:不对,这是猫。你再弄一次。</p>
<p class="content">然后,网络中负责统计的人员回头检查各个神经元的分道情况。因为错误的回答,神经元的参数,也就是权重<span class="italic">w</span>,得到了惩罚。而下一次呢?正确的结果将使参数得到强化和肯定。这样不断地调整,直到这个网络能够对大多数的训练数据得到正确的答案。所以重要的不是单个分道器,而是整个轨道网络中集体意见的组合结果。因此<span class="bold">数据越多,投票者越多,就能获得越多的模式</span>。如果有数百万个投票者,就能获得数十亿种模式。每一种模式都可以对应一种结果,都代表着一种极为具体的从输入到输出的函数。这些不同的模式使网络拥有归类的能力。训练的数据越多,网络就越了解一种模式属于哪一个类别,就能在未来遇到没有标签的图片时做出更准确的分类。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0168-0238.jpg">
<p class="imgtitle">当得出错误结果时,神经元的权重会受惩罚</p>
</div>
<p class="content">因此,深度学习并不是去尝试定义到底什么是一只猫,而是通过大量的数据和大量的投票器,把网络里面的开关训练成“猫通路”“狗通路”。对数据量的需求远远胜过对具体“猫特征”定义的需求。所以,程序员所做的是源源不断地把数据输入神经网络,让它自己优化自己,而<span class="bold">不是</span>坚持不懈地告诉神经网络,猫这里有胡须,一般是8根,有时候是6根。<span class="bold">这些机械化的定义在神经网络面前变得不再有任何用处</span></p>
<p class="content">这里你们也看得出样本的重要性,数据样本才是网络中每个投票器参数值的决定者(而不是作为网络设计者的人类!)。如果这一批样本中,所有的猫都有8根胡须,那么这个特征—结果的线路,很可能被训练得很强。突然之间,样本中出现了一只有6根胡须的猫。由于神经网络里面什么先验知识也没有。神经网络本来就是一张白纸,没有人告诉它,有几根胡须的是猫。因此被这样的训练样本训练出来的网络也许会告诉我们有6根胡须的猫不是猫。</p>
<p class="content">所以,用精炼语言来总结一下神经网络,即深度学习的机理:它是用一串一串的函数,也就是层,堆叠起来,作用于输入数据,进行<span class="bold">从原始数据到分类结果的过滤与提纯</span>。这些层通过权重来参数化,通过损失函数来判断当前网络的效能,然后通过优化器来调整权重,寻找从输入到输出的最佳函数。注意以下两点。</p>
<p class="content">■学习:就是为神经网络的每个层中的每个神经元寻找最佳的权重。</p>
<p class="content">■知识:就是学到的权重。</p>
<p class="content_105">咖哥一下子讲了那么多原理,讲累了,喝了一口水,接着说:“神经网络由神经元组成,最简单的神经网络只有一个神经元,叫感知器。”</p>
<h3 class="thirdTitle" id="bw134"><a >5.3.1 感知器是最基本的神经元</a></h3>
<p class="content">所谓“道生一,一生二,二生三,三生万物”,万事万物都是从简单到复杂的演进。神经网络也是。前面说到,感知器是神经网络的雏形,最初的神经网络也就是只有一个神经元的感知器。</p>
<p class="content">右图中的圆圈就代表一个神经元,它可以接收输入,并根据输入提供一个输出。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0169-0239.jpg">
<p class="imgtitle">神经元</p>
</div>
<p class="content">这个简单的感知器可以做什么呢?</p>
<p class="content">首先它可以成为一个“与门”。与门我们很熟悉,它的逻辑就是只有当所有输入值都为1时,输出才为1,否则输出为0。这个与门逻辑通过感知器的实现如下图所示。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0169-0240.jpg">
<p class="imgtitle">设定了权重,感知器可以用来做“与”逻辑判断</p>
</div>
<p class="content_105">小冰说:“这个感知器看起来的确有点像是逻辑回归。”</p>
<p class="content_105">咖哥说:“小冰,你说得很对,这就是一个逻辑回归分类器。但它太简单了,只有两个特征(<span class="italic">x</span><span class="sub">1</span><span class="italic">x</span><span class="sub">2</span>),而且输入也简单,只有0、1两种可能,共4组数据。因为数据量太小,所以很容易拟合。很多权重值的组合都可以实现这个拟合,如果我们随意分配两个简单的权重(<span class="italic">w</span><span class="sub">1</span>=20, <span class="italic">w</span><span class="sub">2</span>=20)和一个偏置(<span class="italic">b</span>=−30)值,就能够通过一个线性函数(<span class="italic">y</span>=20<span class="italic">x</span><span class="sub">1</span>+20<span class="italic">x</span><span class="sub">2</span>−30)加一个激活函数(<span class="italic">Sigmiod</span><span class="italic">z</span>)),对4组数据进行简单的‘与’逻辑判断,其实也就是为一个小小的数据集进行分类。这些都是在逻辑回归里面讲过的内容。”</p>
<p class="content_101"><img alt="" class="h-pic" src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0170-0241.jpg">咖哥发言</p>
<p class="content">Sigmiod函数,在逻辑回归中叫逻辑函数,在神经网络中则称为激活函数,用以类比人类神经系统中神经元的“激活”过程。</p>
<p class="content">如果换其他数据,比如再给4组符合“或”规则的数据(只要输入中有一个值为1,输出就为1,否则输出为0),感知器能不能够完成这个新的逻辑判断呢?当然可以。通过调整感知器的权重和偏置,比如设置<span class="italic">w</span><span class="sub">1</span>=20,<span class="italic">w</span><span class="sub">2</span>=20,<span class="italic">b</span>=−10后,就成功地实现了新规则(如下图所示)。这样,根据不同的数据输入,感知器适当地调整权重,在不同的功能之间切换(也就是拟合),形成了一个简单的自适应系统,人们就说它拥有了“感知”事物的能力。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0170-0242.jpg">
<p class="imgtitle">通过调整权重,感知器从“与门”变成了“或门”</p>
</div>
<h3 class="thirdTitle" id="bw135"><a >5.3.2 假设空间要能覆盖特征空间</a></h3>
<p class="content">单神经元,也就是感知器,通过训练可以用作逻辑回归分类器,那么它是如何进化成更为复杂的多层神经网络呢?</p>
<p class="content">要理解从单层到多层这一“跃迁”的意义,我们需要重温几个概念。前面讲过,机器学习中数据的几何映射是空间;向量,也可以看作一个多维空间中的点。由此,对输入空间、输出空间、特征空间、假设空间进行如下的定义。</p>
<p class="content">■输入空间:<span class="italic">x</span>,输入值的集合。</p>
<p class="content">■输出空间:<span class="italic">y</span>,输出值的集合。通常,输出空间会小于输入空间。</p>
<p class="content">■特征空间:每一个样本被称作一个实例,通常由特征向量表示,所有特征向量存在的空间称为特征空间。特征空间有时候与输入空间相同,有时候不同。因为有时候经过特征工程之后,输入空间可通过某种映射生成新的特征空间。</p>
<p class="content">■假设空间:假设空间一般是对于学习到的模型(即函数)而言的。模型表达了输入到输出的一种映射集合,这个集合就是假设空间。假设空间代表着<span class="bold">模型学习过程中能够覆盖的最大范围</span></p>
<p class="content">因为模型本身就是对特征的一种函数化的表达,一个基本的原则是:<span class="bold">模型的假设空间,一定要大到能覆盖特征空间</span>,否则,模型就不可能精准地完成任务。某些回归问题,一定需要曲线模型进行拟合,如果坚持使用线性模型,就会因为其特征空间覆盖面有限,无论怎么调整权重和偏置都不可能达到理想效果。下面的示意图就描绘出函数的复杂度和其所能够覆盖的假设空间范围之间的关系:函数越复杂,假设空间的覆盖面越大,拟合能力就越强。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0171-0243.jpg">
<p class="imgtitle">模型的假设空间越大,拟合复杂数据集的能力就越强<span class="super" id="ref11"><a >[1]</a></span></p>
</div>
<h3 class="thirdTitle" id="bw136"><a >5.3.3 单神经元特征空间的局限性</a></h3>
<p class="content">其实,从拓扑结构来看,感知器,也就是说神经网络中的单个神经元所能够解决的问题是线性可分的。刚才我们成功拟合的“与”和“或”两个数据集,它们的输入空间都满足线性可分这个条件,如下图所示。因此,如果模型的假设空间能够覆盖输入空间,就可以搞定它们。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0171-0244.jpg">
<p class="imgtitle">“与”和“或”的线性分界平面</p>
</div>
<p class="content">但是,感知器没有办法拟合非线性的空间。再看看下图中这个符合“同或”(XOR)逻辑的数据集,也是只有2个特征,4组数据而已。两个输入值不同时,输出为0。反之,输出为1。数据集虽然简单,但“同或”逻辑是线性不可分的,我们再怎么画直线,也无法分割出一个平面来为其分界。因此,这个问题也就没有办法通过一个单节点感知器处理—<span class="bold">无论我们如何调整感知器的权重和偏置,都无法拟合“同或”数据集从特征到标签的逻辑</span></p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0172-0245.jpg">
<p class="imgtitle">无论怎么调整感知器的权重和偏置,都无法解决同或问题</p>
</div>
<p class="content">所以,感知器是有局限性的。它连同或这样简单的任务都完成不了,又如何去模拟现实世界中更为复杂的关系?难怪感知器当年“红火”一阵子后就消失在人们的视野了。</p>
<h3 class="thirdTitle" id="bw137"><a >5.3.4 分层:加入一个网络隐层</a></h3>
<p class="content">那么,机器学习如何解决这个问题?</p>
<p class="content">有以下两个思路。</p>
<p class="content">■第一个思路,进行手工特征工程,就是对<span class="italic">x</span><span class="sub">1</span><span class="italic">x</span><span class="sub">2</span>进行各种各样的组合变形,形成新的特征,比如<span class="italic">x</span><span class="sub">3</span><span class="italic">x</span><span class="sub">4</span>。然后对新特征<span class="italic">x</span><span class="sub">3</span><span class="italic">x</span><span class="sub">4</span>做线性回归。这种特征工程本质上改变了数据集原本的特征空间,目标是降低其维度,使其线性回归算法可解。</p>
<p class="content">■第二个思路,就是<span class="bold">将神经网络分层</span>。人们发现,如果在感知器的激活函数后面再多加入一个新的神经网络层,以上一层神经元激活后的输出作为下一层神经元的输入,此时模型的假设空间就会被扩展,神经网络就会从线性模型跃迁至非线性模型(如下图所示),从而将本来线性不可分的函数图像拟合成功!</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0172-0246.jpg">
<p class="imgtitle">同或问题的特征空间并不是线性可分的,需要引入非线性模型</p>
</div>
<p class="content">第二个思路较之于第一个思路的优势是什么?省去了特征工程。因为特征的变换,特征之间的组合的种种逻辑都是人工决定的,相当耗时耗力。所以,对特征量巨大,而且特征之间无明显关联的非结构化数据做特征工程是不实际的。</p>
<p class="content">神经网络隐层的出现把<span class="bold">手工的特征工程工作丢给了神经网络</span>,网络第一层的权重和偏置自己去学,网络第二层的权重和偏置自己去学,网络其他层的权重和偏置也是自己去学。我们除了提供数据以及一些网络的初始参数之外,剩下的事情全部都让网络自己完成。</p>
<p class="content">因此,神经网络的自我学习功能实在是懒人的福音。</p>
<p class="content">下图展示的就是神经网络解决这个非线性的“同或”问题的具体过程。这个网络不但多出一层,每层还可以有多个神经元,具有充分的灵活性。哪怕特征数量再大,特征空间再复杂,神经网络通过<span class="bold">多层架构</span>也可以将其搞定。</p>
<p class="content_101"><img alt="" class="h-pic" src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0173-0247.jpg">咖哥发言</p>
<p class="content"><span class="bold">注意神经网络的上下标符号规则。</span>神经网络中因为层数多,每层中节点(即神经元)数目也多,因此其中节点、权重的标号规则变得复杂起来。举例来说,此处,<img alt="" class="h-pic" src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0173-0248.jpg">中,中括号里面的上标的数字代表第几层;下标有两个,第一个代表权重属于哪一个特征,即特征的维度,第二个代表其所连接到的下层神经元的维度。</p>
<p class="content">还要注意的就是每层会有多个权重,但每层只有1个偏置。</p>
<p class="content">再多说一句,对于数据集的特征<span class="italic">x</span>来说,有时候也会出现这样比较复杂的标号<img alt="" class="h-pic" src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0173-0249.jpg">,这里的下标1代表特征的维度,1就是第1个特征;而圆括号里面的上标的数字代表的是样本的维度, 1也就是第1个样本。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0173-0250.jpg">
<p class="imgtitle">加入网络隐层之后,同或数据集变得可以拟合了</p>
</div>
<p class="content">理论内容讲了不少,同学们可能听得有点发懵。现在可以轻松一点了,接下来用更深的神经网络来处理那个银行客户流失案例。你们会发现搭建深层神经网络完全没有想象的那么难。因为神经网络模型的各种组件在Keras中都已经封装好了,我们拿过来组合一下就能用。</p>
<p class="content_101"><img alt="" class="h-pic" src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0203-0291.jpg">咖哥发言</p>
<p class="content">随着网络加深,参数增多,对硬件的要求提高,可以在Kaggle的Settings中把GPU选项设置为打开,如右图所示。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0203-0292.jpg">
<p class="imgtitle">打开GPU设置</p>
</div>
<h3 class="thirdTitle" id="bw157"><a >5.7.1 构建深度神经网络</a></h3>
<p class="content">搭建多层的神经网络,还是使用序贯模型。下面随意地添加几层看一看效果:</p>
<p class="content">ann = Sequential() # 创建一个序贯ANN模型</p>
<div class="content_106">
<p class="content_105">ann.add(Dense(units=12, input_dim=12, activation = 'relu')) # 添加输入层</p>
<p class="content_105">ann.add(Dense(units=24, activation = 'relu')) # 添加隐层</p>
<p class="content_105">ann.add(Dense(units=48, activation = 'relu')) # 添加隐层</p>
<p class="content_105">ann.add(Dense(units=96, activation = 'relu')) # 添加隐层</p>
<p class="content_105">ann.add(Dense(units=192, activation = 'relu')) # 添加隐层</p>
<p class="content_105">ann.add(Dense(units=1, activation = 'sigmoid')) # 添加输出层</p>
<p class="content_105"># 编译神经网络, 指定优化器、损失函数, 以及评估指标</p>
<p class="content_105">ann.compile(optimizer = 'rmsprop', # 此处我们先试试RMSP优化器</p>
<p class="content_111">loss = 'binary_crossentropy', # 损失函数</p>
<p class="content_111">metrics = ['acc']) # 评估指标</p>
</div>
<p class="content">不管是浅层网络,还是深层网络,构建起来真的很简单。因为深度学习背后的思想本来就很简单,那么它的实现过程又何必要那么痛苦呢?—这话可不是我说的,是Keras的发明者François Chollet说的。我表示很赞同。</p>
<p class="content">来看看这个网络的效果:</p>
<div class="content_106">
<p class="content_105">history = ann.fit(X_train, y_train, # 指定训练集</p>
<p class="content_119">epochs=30,    # 指定轮次</p>
<p class="content_119">batch_size=64,  # 指定批量大小</p>
<p class="content_119">validation_data=(X_test, y_test)) # 指定验证集</p>
</div>
<p class="content">训练结束之后,采用同样的方法对测试集进行预测,并显示损失曲线和准确率曲线,同时显示分类报告(这里就不重复展示相同的代码了)。</p>
<p class="content">观察训练及预测结果之后我们有一些发现。</p>
<p class="content">第一,发现较深的神经网络训练效率要高于小型网络,一两个轮次之后,准确率迅速提升到0.84以上,而单隐层神经网络需要好几轮才能达到这个准确率:</p>
<div class="content_106">
<p class="content_109">Train on 8000 samples, validate on 2000 samples</p>
<p class="content_109">Epoch 1/30</p>
<p class="content_109">8000/8000 [===================] - 3s 320us/step - loss: 0.4359 - acc: 0.8199</p>
<p class="content_156">- val_loss: 0.4229 - val_acc: 0.8290</p>
<p class="content_109">Epoch 2/30</p>
<p class="content_109">8000/8000 [===================] - 1s 180us/step - loss: 0.3780 - acc: 0.8475</p>
<p class="content_156">- val_loss: 0.3893 - val_acc: 0.8445</p>
<p class="content_109">Epoch 3/30</p>
<p class="content_109">8000/8000 [===================] - 1s 180us/step - loss: 0.3670 - acc: 0.8574</p>
<p class="content_156">- val_loss: 0.3818 - val_acc: 0.8445</p>
<p class="content_109">Epoch 4/30</p>
<p class="content_109">8000/8000 [===================] - 1s 182us/step - loss: 0.3599 - acc: 0.8581</p>
<p class="content_156">- val_loss: 0.3842 - val_acc: 0.8480</p>
</div>
<p class="content">第二,从准确率上看,没有什么提升;而从F1分数上看,目前这个比较深的神经网络反而不如简单的单隐层神经网络,从0.58下降到0.55:</p>
<div class="content_106">
<p class="content_117">precision  recall f1-score  support</p>
<p class="content_116">0    0.87   0.97   0.92    1583</p>
<p class="content_116">1    0.80   0.42   0.55     417</p>
</div>
<p class="content">第三,从损失函数图像上看(如下图所示),深度神经网络在几轮之后就开始出现过拟合的问题,而且验证集上损失的波动也很大。因为随着轮次的增加,训练集的误差值逐渐减小,但是验证集的误差反而越来越大了。也就是说,网络的参数逐渐地对训练集的数据形成了过高的适应性。这对于较大网络来说的确是常见情况。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0204-0293.jpg">
<p class="imgtitle">验证集上损失的波动很大</p>
</div>
<h3 class="thirdTitle" id="bw158"><a >5.7.2 换一换优化器试试</a></h3>
<p class="content_105">网络变深了,预测准确率和F1分数反而降低了。大家的心情十分沮丧。该如何是好呢?</p>
<p class="content_105">没有任何经验的同学们只好看着咖哥,希望他给出一些方向。</p>
<p class="content_105">咖哥咳嗽两声,说:“对于某些简单问题,本来小网络的效能就是要高于深的网络。网络参数多,有时并不是一件好事。当然,我们还是可以做一些尝试。第一步,先更换一下优化器,把它从RMSProp换成Adam,如下段代码所示。”</p>
<div class="content_106">
<p class="content_105">ann.compile(optimizer = 'adam', # 换一下优化器</p>
<p class="content_111">loss = 'binary_crossentropy', # 损失函数</p>
<p class="content_111">metrics = ['acc']) # 评估指标</p>
</div>
<p class="content">更换优化器之后,重新训练、测试网络。发现最为关心的F1分数有所上升,上升至0.56,如下输出结果所示。但这仍然低于单隐层神经网络的0.58:</p>
<div class="content_106">
<p class="content_117">precision  recall f1-score  support</p>
<p class="content_116">0    0.87   0.96   0.91   1583</p>
<p class="content_116">1    0.75   0.45   0.56    417</p>
</div>
<p class="content">损失曲线显示(如下图所示),过拟合现象仍然十分严重。也许这个过拟合问题就是深层神经网络效率低的症结所在。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0205-0294.jpg">
<p class="imgtitle">过拟合现象仍然存在</p>
</div>
<h3 class="thirdTitle" id="bw159"><a >5.7.3 神经网络正则化:添加Dropout层</a></h3>
<p class="content_105">咖哥说:“从损失曲线上判断,对于小数据而言,深度神经网络由于参数数量太多,已经出现了过拟合的风险。因此,我们决定针对过拟合问题来做一些事情,优化网络。在神经网络中,最常用的对抗过拟合的工具就是Dropout。在Keras中,Dropout也是神经网络中的层组件之一,其真正目的是实现网络正则化,避免过拟合。大家还记得正则化的原理吗?”</p>
<p class="content_105">有一位同学答道:“为了让模型粗犷一点儿,不要过分追求完美。”</p>
<p class="content_105">咖哥说:“意思基本正确。大家想一想,对于神经网络那么复杂的模型来说,要避免过拟合还挺难做到的。而Dropout就是专门对付神经网络过拟合的有效正则化方法之一。这个方法也是Hinton和他的学生开发的。”</p>
<p class="content">它的原理非常奇特:在某一层之后添加Dropout层,意思就是随机将该层的一部分神经元的输出特征丢掉(设为0),相当于随机消灭一部分神经元。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0205-0295.jpg">
<p class="imgtitle">Dropout示意</p>
</div>
<p class="content">假设在训练过程中,某一层对特定数据样本输出一个中间向量。</p>
<p class="content">■使用Dropout之前,中间向量为[0.5,0.2,3.1,2,5.9,4]。</p>
<p class="content">■使用Dropout之后,中间向量变为[0.5,0,0,2,5.9,0]。</p>
<p class="content">Dropout比率就是被设为0的输出特征所占的比例,通常为0.2~0.5。注意,Dropout只是对训练集起作用,在测试时没有神经元被丢掉。</p>
<p class="content">据Hinton 说,这个小窍门的灵感来自银行的防欺诈机制。他去银行办理业务时,发现柜员不停地换人。他就猜想,银行工作人员要想成功欺诈银行,他们之间要互相合作才行,因此一个柜员不能在同一个岗位待得过久。这让他意识到,在某些神经网络层中随机删除一部分神经元,可以阻止它们的阴谋,从而降低过拟合。</p>
<p class="content">下面就在刚才的深度神经网络中添加一些Dropout层,并重新训练它:</p>
<div class="content_106">
<p class="content_105">from keras.layers import Dropout # 导入Dropout</p>
<p class="content_105">ann = Sequential() # 创建一个序贯ANN模型</p>
<p class="content_105">ann.add(Dense(units=12, input_dim=12, activation = 'relu')) # 添加输入层</p>
<p class="content_105">ann.add(Dense(units=24, activation = 'relu')) # 添加隐层</p>
<p class="content_105">ann.add(Dropout(0.5)) # 添加Dropout层</p>
<p class="content_105">ann.add(Dense(units=48, activation = 'relu')) # 添加隐层</p>
<p class="content_105">ann.add(Dropout(0.5)) # 添加Dropout层</p>
<p class="content_105">ann.add(Dense(units=96, activation = 'relu')) # 添加隐层</p>
<p class="content_105">ann.add(Dropout(0.5)) # 添加Dropout层</p>
<p class="content_105">ann.add(Dense(units=192, activation = 'relu')) # 添加隐层</p>
<p class="content_105">ann.add(Dropout(0.5)) # 添加Dropout层</p>
<p class="content_105">ann.add(Dense(units=1, activation = 'sigmoid')) # 添加输出层</p>
<p class="content_105">ann.compile(optimizer = 'adam', # 优化器</p>
<p class="content_119">loss = 'binary_crossentropy', #损失函数</p>
<p class="content_119">metrics = ['acc']) # 评估指标</p>
</div>
<p class="content">损失曲线显示(如下图所示),添加Dropout层之后,过拟合现象被大幅度地抑制了。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0206-0296.jpg">
<p class="imgtitle">添加Dropout层之后,过拟合现象被大幅度地抑制了</p>
</div>
<p class="content">现在,针对客户流失样本的F1分数上升到了令人惊讶的0.62,如下输出结果所示。对于难以预测的客户流失现象来说,这是一个相当棒的成绩!这样说明对于这个问题,加深网络同时辅以Dropout正则化的策略比用单隐层神经网络更好。</p>
<div class="content_106">
<p class="content_117">precision  recall f1-score  support</p>
<p class="content_116">0    0.89   0.92   0.91   1583</p>
<p class="content_116">1    0.67   0.58   0.62    417</p>
</div>
<p class="content">新的混淆矩阵显示(如下图所示),400多个即将流失的客户中,我们成功地捕捉到了200多人。这是非常有价值的商业信息。</p>
<div class="pic">
<img src="http://csdn-ebook-resources.oss-cn-beijing.aliyuncs.com/images/b88b00f6ad14402ea66695d6809614da/figure-0207-0297.jpg">
<p class="imgtitle">新的混淆矩阵</p>
</div>
<p class="content_105">看到这样的效果,小冰和同学们都对咖哥竖起大拇指。咖哥说:“其实准确率或者F1分数本身的提升并不重要,更有价值的是网络优化过程中所做的各种尝试和背后的思路。”</p>
<p class="content">本课讲了挺多内容,具体包括:感知器的结构、单隐层神经网络的构建,以及深度神经网络的构建,并解决了一个预测银行客户是否会流失的案例。一个重点是如何优化神经网络的性能,并解决过拟合的问题。</p>
<p class="content">神经网络的优势在于它可以有很多层。如果输入输出是直接连接的,那么它和逻辑回归就没有什么区别。但是通过大量中间层的引入,它就能够捕捉很多输入特征之间的关系。此外,它还具有如下优势。</p>
<p class="content">■它利用了现代计算机的强大算力,提高了机器学习的精度。</p>
<p class="content">■它使特征工程不再显得那么重要,非结构化数据的处理变得简单。</p>
<p class="content">深度学习适合处理任何形式的数据,特别是非结构化的数据,如音频、文本、图像、时间序列,以及视频等。</p>
<p class="content">而深度学习的具体应用也实在是太多了,这里随便列出一些。</p>
<p class="content">■图像分类,人脸识别,如Facebook的人脸自动标签功能。</p>
<p class="content">■自然语言处理(Natural Language Processing,NLP),如语音识别、机器翻译、文本到语音转换、手写文字转录、情感分析以及自动回答人类用语言提出的问题等。</p>
<p class="content">■智能助理,比如苹果公司的Siri。</p>
<p class="content">■棋类游戏,以Deep Mind的Alpha Go为代表,它已经战胜世界围棋冠军。</p>
<p class="content">■推荐系统,如各大电商网站都在进行的广告定向投放,以及电影、书籍的推荐等。</p>
<p class="content">经过今天的学习,咖哥有一个愿望,就是希望我们从此对深度学习不再感到神秘。如果一个东西太神秘,那么会令人不敢接近、不敢使用。现在同学们了解了它的原理,使用Keras做了自己的深度网络,现在回头再看神经网络的实现架构,它和人类大脑的机理是没有太多相似度的。因此Keras之父肖莱认为,神经网络这个名词不如“分层学习”贴切。</p>
<p class="content">另外,尽管深度神经网络处理巨大数据集和复杂问题的优势已经毋庸置疑,但是不能直接得出结论认为网络越深越好。如果问题并不复杂,我们还是应该先尝试较为简单的模型。</p>
<p class="content_105">此时此刻,咖哥和同学们从大厦的窗口向外望去,天已经完全黑了,四环路上车流如水,头灯、尾灯联结起来,形成一条条长长的“光龙”,整个城市似乎正像是一张无限延展的大网,看不到尽头。</p>
<div class="content_120">
<p class="content">练习一 对本课示例继续进行参数调试和模型优化。</p>
<p class="content">(提示:可以考虑增加或者减少迭代次数、增加或者减少网络层数、添加Dropout层、引入正则项等。)</p>
<p class="content">练习二 在Kaggle网站搜索下载第6课的练习数据集“是什么花”,并使用本课介绍的方法新建卷积网络处理该数据集。</p>
<p class="content">练习三 保存卷积网络模型,并在新程序中导入保存好的模型。</p>
</div>
\ No newline at end of file
<p class="content">下面,我们总结一下卷积网络的特点。</p>
<p class="content">■局部连接,减少参数,提升效率。</p>
<p class="content">■通过特征提取把整体特征分解成小特征。</p>
<p class="content">■小特征具有平移不变性,因此出现的各个位置均能被识别。</p>
<p class="content">■通过空间层级将深度特征组合,形成整体特征。</p>
<p class="content">■卷积的原理:抠图,卷积核对抠下来的图进行运算,形成响应通道。</p>
<p class="content">■填充和步幅。</p>
<p class="content">■池化层的功能是对特征图进行下采样。</p>
<p class="content">卷积网络是计算机视觉处理的“利器”,在目前计算机视觉相关的项目实践中,绝大多数情况都可以看见卷积网络的身影。本课就通过一个小型的卷积网络,实现了对10种不同品种狗狗的图像进行分类。在这个过程中,我们用多种方式对网络进行了优化。</p>
<p class="content">在本课的最后,还介绍了一种将卷积网络特征通道可视化的方法,以及几种大型卷积网络模型。</p>
<div class="content_120">
<p class="content">练习一 重做本课中的聚类案例,使用年龄和消费分数这两个特征进行聚类(我们的例子中是选择了年收入和消费分数),并调整<span class="italic">K</span>值的大小。</p>
<p class="content">练习二 研究源码包中给出的变分自编码器的代码,试着自己用Keras神经网络生成变分自编码器。</p>
<p class="content">练习三 研究源码包中给出的GAN实现代码。</p>
</div>
\ No newline at end of file
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册