diff --git "a/docs/dl/CNN\345\216\237\347\220\206.md" "b/docs/dl/CNN\345\216\237\347\220\206.md" index ac54361fa..bcce2dde8 100644 --- "a/docs/dl/CNN\345\216\237\347\220\206.md" +++ "b/docs/dl/CNN\345\216\237\347\220\206.md" @@ -50,7 +50,7 @@   前面说到在图像领域,用传统的神经网络并不合适。我们知道,图像是由一个个像素点构成,每个像素点有三个通道,分别代表RGB颜色,那么,如果一个图像的尺寸是(28,28,1),即代表这个图像的是一个长宽均为28,channel为1的图像(channel也叫depth,此处1代表灰色图像)。如果使用全连接的网络结构,即,网络中的神经与与相邻层上的每个神经元均连接,那就意味着我们的网络有 `28 * 28 =784` 个神经元,hidden层采用了15个神经元,那么简单计算一下,我们需要的参数个数(w和b)就有: `784*15*10+15+10=117625` 个,这个参数太多了,随便进行一次反向传播计算量都是巨大的,从计算资源和调参的角度都不建议用传统的神经网络。(评论中有同学对这个参数计算不太理解,我简单说一下:图片是由像素点组成的,用矩阵表示的, `28*28` 的矩阵,肯定是没法直接放到神经元里的,我们得把它“拍平”,变成一个`28*28=784` 的一列向量,这一列向量和隐含层的15个神经元连接,就有 `784*15=11760` 个权重w,隐含层和最后的输出层的10个神经元连接,就有 `11760*10=117600` 个权重w,再加上隐含层的偏置项15个和输出层的偏置项10个,就是:117625个参数了) -![](/img/dl/CNN原理/853467-20171031123650574-11330636.png) +![](../../img/dl/CNN原理/853467-20171031123650574-11330636.png)                                     图1 三层神经网络识别手写数字 @@ -62,7 +62,7 @@   上文提到我们用传统的三层神经网络需要大量的参数,原因在于每个神经元都和相邻层的神经元相连接,但是思考一下,这种连接方式是必须的吗?全连接层的方式对于图像数据来说似乎显得不这么友好,因为图像本身具有“二维空间特征”,通俗点说就是局部特性。譬如我们看一张猫的图片,可能看到猫的眼镜或者嘴巴就知道这是张猫片,而不需要说每个部分都看完了才知道,啊,原来这个是猫啊。所以如果我们可以用某种方式对一张图片的某个典型特征识别,那么这张图片的类别也就知道了。这个时候就产生了卷积的概念。举个例子,现在有一个4*4的图像,我们设计两个卷积核,看看运用卷积核后图片会变成什么样。 -![](/img/dl/CNN原理/853467-20171104142033154-1330878114.png) +![](../../img/dl/CNN原理/853467-20171104142033154-1330878114.png)  图2 4*4 image与两个2*2的卷积核操作结果 @@ -532,7 +532,7 @@ class LayerHelper(object):   通过上一层2*2的卷积核操作后,我们将原始图像由4*4的尺寸变为了3*3的一个新的图片。池化层的主要目的是通过降采样的方式,在不影响图像质量的情况下,压缩图片,减少参数。简单来说,假设现在设定池化层采用MaxPooling,大小为2*2,步长为1,取每个窗口最大的数值重新,那么图片的尺寸就会由3*3变为2*2:(3-2)+1=2。从上例来看,会有如下变换: -![](/img/dl/CNN原理/853467-20171104142056685-2048616836.png) +![](../../img/dl/CNN原理/853467-20171104142056685-2048616836.png)        图3 Max Pooling结果 @@ -553,7 +553,7 @@ class LayerHelper(object):       所以到现在为止,我们的图片由4*4,通过卷积层变为3*3,再通过池化层变化2*2,如果我们再添加层,那么图片岂不是会越变越小?这个时候我们就会引出“Zero Padding”(补零),它可以帮助我们保证每次经过卷积或池化输出后图片的大小不变,如,上述例子我们如果加入Zero Padding,再采用3*3的卷积核,那么变换后的图片尺寸与原图片尺寸相同,如下图所示: -![](/img/dl/CNN原理/853467-20171031215017701-495180034.png) +![](../../img/dl/CNN原理/853467-20171031215017701-495180034.png)   图4 zero padding结果 @@ -565,7 +565,7 @@ class LayerHelper(object): 到这一步,其实我们的一个完整的“卷积部分”就算完成了,如果想要叠加层数,一般也是叠加“Conv-MaxPooing",通过不断的设计卷积核的尺寸,数量,提取更多的特征,最后识别不同类别的物体。做完Max Pooling后,我们就会把这些数据“拍平”,丢到Flatten层,然后把Flatten层的output放到full connected Layer里,采用softmax对其进行分类。 -![](/img/dl/CNN原理/853467-20171104142200763-1912037434.png) +![](../../img/dl/CNN原理/853467-20171104142200763-1912037434.png)     图5 Flatten过程 @@ -586,7 +586,7 @@ class LayerHelper(object):   1.卷积核的尺寸不一定非得为正方形。长方形也可以,只不过通常情况下为正方形。如果要设置为长方形,那么首先得保证这层的输出形状是整数,不能是小数。如果你的图像是边长为 28 的正方形。那么卷积层的输出就满足 [ (28 - kernel_size)/ stride ] + 1 ,这个数值得是整数才行,否则没有物理意义。譬如,你算得一个边长为 3.6 的 feature map 是没有物理意义的。 pooling 层同理。FC 层的输出形状总是满足整数,其唯一的要求就是整个训练过程中 FC 层的输入得是定长的。如果你的图像不是正方形。那么在制作数据时,可以缩放到统一大小(非正方形),再使用非正方形的 kernel_size 来使得卷积层的输出依然是整数。总之,撇开网络结果设定的好坏不谈,其本质上就是在做算术应用题:如何使得各层的输出是整数。 -  2.由经验确定。通常情况下,靠近输入的卷积层,譬如第一层卷积层,会找出一些共性的特征,如手写数字识别中第一层我们设定卷积核个数为5个,一般是找出诸如"横线"、“竖线”、“斜线”等共性特征,我们称之为basic feature,经过max pooling后,在第二层卷积层,设定卷积核个数为20个,可以找出一些相对复杂的特征,如“横折”、“左半圆”、“右半圆”等特征,越往后,卷积核设定的数目越多,越能体现label的特征就越细致,就越容易分类出来,打个比方,如果你想分类出“0”的数字,你看到![](/img/dl/CNN原理/853467-20171031231438107-1902818098.png)这个特征,能推测是什么数字呢?只有越往后,检测识别的特征越多,试过能识别![](/img/dl/CNN原理/853467-20171101085737623-1572944193.png)这几个特征,那么我就能够确定这个数字是“0”。 +  2.由经验确定。通常情况下,靠近输入的卷积层,譬如第一层卷积层,会找出一些共性的特征,如手写数字识别中第一层我们设定卷积核个数为5个,一般是找出诸如"横线"、“竖线”、“斜线”等共性特征,我们称之为basic feature,经过max pooling后,在第二层卷积层,设定卷积核个数为20个,可以找出一些相对复杂的特征,如“横折”、“左半圆”、“右半圆”等特征,越往后,卷积核设定的数目越多,越能体现label的特征就越细致,就越容易分类出来,打个比方,如果你想分类出“0”的数字,你看到![](../../img/dl/CNN原理/853467-20171031231438107-1902818098.png)这个特征,能推测是什么数字呢?只有越往后,检测识别的特征越多,试过能识别![](../../img/dl/CNN原理/853467-20171101085737623-1572944193.png)这几个特征,那么我就能够确定这个数字是“0”。   3.有stride_w和stride_h,后者表示的就是上下步长。如果用stride,则表示stride_h=stride_w=stride。 @@ -632,7 +632,7 @@ def convolutional_neural_network_org(img):   那么这个时候我考虑的问题是,既然上面我们已经了解了卷积核,改变卷积核的大小是否会对我的结果造成影响?增多卷积核的数目能够提高准确率?于是我做了个实验: -![](/img/dl/CNN原理/853467-20171031232805748-157396975.png) +![](../../img/dl/CNN原理/853467-20171031232805748-157396975.png) * 第一次改进:仅改变第一层与第二层的卷积核数目的大小,其他保持不变。可以看到结果提升了0.06% *  第二次改进:保持3*3的卷积核大小,仅改变第二层的卷积核数目,其他保持不变,可以看到结果相较于原始参数提升了0.08% diff --git "a/docs/dl/LSTM\345\216\237\347\220\206.md" "b/docs/dl/LSTM\345\216\237\347\220\206.md" index d43813f5a..26ac295ac 100644 --- "a/docs/dl/LSTM\345\216\237\347\220\206.md" +++ "b/docs/dl/LSTM\345\216\237\347\220\206.md" @@ -4,35 +4,35 @@ **LSTM**(Long Short-Term Memory)长短期记忆网络,是一种时间递归神经网络,**适合于处理和预测时间序列中间隔和延迟相对较长的重要事件**。LSTM是解决循环神经网络RNN结构中存在的“梯度消失”问题而提出的,是一种特殊的循环神经网络。最常见的一个例子就是:当我们要预测“the clouds are in the (...)"的时候, 这种情况下,相关的信息和预测的词位置之间的间隔很小,RNN会使用先前的信息预测出词是”sky“。但是如果想要预测”I grew up in France ... I speak fluent (...)”,语言模型推测下一个词可能是一种语言的名字,但是具体是什么语言,需要用到间隔很长的前文中France,在这种情况下,RNN因为“梯度消失”的问题,并不能利用间隔很长的信息,然而,LSTM在设计上明确避免了长期依赖的问题,这主要归功于LSTM精心设计的“门”结构(输入门、遗忘门和输出门)消除或者增加信息到细胞状态的能力,使得LSTM能够记住长期的信息。 -![](/img/dl/LSTM原理/20180704173253439.jpg)  vs   ![](/img/dl/LSTM原理/20180704173230785.jpg)   +![](../../img/dl/LSTM原理/20180704173253439.jpg)  vs   ![](../../img/dl/LSTM原理/20180704173230785.jpg)   标准的RNN结构都具有一种重复神经网络模块的链式形式,一般是一个tanh层进行重复的学习(如上图左边图),而在LSTM中(上图右边图),重复的模块中有四个特殊的结构。**贯穿在图上方的水平线为细胞状态(cell),黄色的矩阵是学习得到的神经网络层,粉色的圆圈表示运算操作,黑色的箭头表示向量的传输**,整体看来,不仅仅是h在随着时间流动,细胞状态c也在随着时间流动,细胞状态c代表着长期记忆。 -上面我们提到LSTM之所以能够记住长期的信息,在于设计的“门”结构,“门”结构是一种让信息选择式通过的方法,包括一个sigmoid神经网络层和一个pointwise乘法操作,如下图所示结构。复习一下sigmoid函数,![](/img/dl/LSTM原理/20180705153027598.jpg),sigmoid输出为0到1之间的数组,一般用在二分类问题,输出值接近0代表“不允许通过”,趋向1代表“允许通过”。 +上面我们提到LSTM之所以能够记住长期的信息,在于设计的“门”结构,“门”结构是一种让信息选择式通过的方法,包括一个sigmoid神经网络层和一个pointwise乘法操作,如下图所示结构。复习一下sigmoid函数,![](../../img/dl/LSTM原理/20180705153027598.jpg),sigmoid输出为0到1之间的数组,一般用在二分类问题,输出值接近0代表“不允许通过”,趋向1代表“允许通过”。 -![](/img/dl/LSTM原理/20180705152515679.jpg) +![](../../img/dl/LSTM原理/20180705152515679.jpg) **在LSTM中,第一阶段是遗忘门,遗忘层决定哪些信息需要从细胞状态中被遗忘,下一阶段是输入门,输入门确定哪些新信息能够被存放到细胞状态中,最后一个阶段是输出门,输出门确定输出什么值**。下面我们把LSTM就着各个门的子结构和数学表达式进行分析。 -* 遗忘门:遗忘门是以上一层的输出![](/img/dl/LSTM原理/20180705154943659.jpg)和本层要输入的序列数据![](/img/dl/LSTM原理/20180705155022656.jpg)作为输入,通过一个激活函数sigmoid,得到输出为![](/img/dl/LSTM原理/201807051551130.jpg)。![](/img/dl/LSTM原理/20180705155135748.jpg)的输出取值在[0,1]区间,表示上一层细胞状态被遗忘的概率,1是“完全保留”,0是“完全舍弃” +* 遗忘门:遗忘门是以上一层的输出![](../../img/dl/LSTM原理/20180705154943659.jpg)和本层要输入的序列数据![](../../img/dl/LSTM原理/20180705155022656.jpg)作为输入,通过一个激活函数sigmoid,得到输出为![](../../img/dl/LSTM原理/201807051551130.jpg)。![](../../img/dl/LSTM原理/20180705155135748.jpg)的输出取值在[0,1]区间,表示上一层细胞状态被遗忘的概率,1是“完全保留”,0是“完全舍弃” -![](/img/dl/LSTM原理/20180705154117297.jpg) +![](../../img/dl/LSTM原理/20180705154117297.jpg) -* 输入门:输入门包含两个部分,第一部分使用sigmoid激活函数,输出为![](/img/dl/LSTM原理/20180705160829424.jpg),第二部分使用tanh激活函数,输出为![](/img/dl/LSTM原理/20180705161911316.jpg)。**【个人通俗理解:![](/img/dl/LSTM原理/20180705162106120.jpg)在RNN网络中就是本层的输出,![](/img/dl/LSTM原理/20180705162239540.jpg)是在[0,1]区间取值,表示![](/img/dl/LSTM原理/20180705162835994.jpg)中的信息被保留的程度,![](/img/dl/LSTM原理/20180705162518689.jpg)表示该层被保留的新信息】** +* 输入门:输入门包含两个部分,第一部分使用sigmoid激活函数,输出为![](../../img/dl/LSTM原理/20180705160829424.jpg),第二部分使用tanh激活函数,输出为![](../../img/dl/LSTM原理/20180705161911316.jpg)。**【个人通俗理解:![](../../img/dl/LSTM原理/20180705162106120.jpg)在RNN网络中就是本层的输出,![](../../img/dl/LSTM原理/20180705162239540.jpg)是在[0,1]区间取值,表示![](../../img/dl/LSTM原理/20180705162835994.jpg)中的信息被保留的程度,![](../../img/dl/LSTM原理/20180705162518689.jpg)表示该层被保留的新信息】** -![](/img/dl/LSTM原理/20180705154140100.jpg) +![](../../img/dl/LSTM原理/20180705154140100.jpg) -到目前为止,![](/img/dl/LSTM原理/20180705162951402.jpg)是遗忘门的输出,控制着上一层细胞状态![](/img/dl/LSTM原理/20180705163019968.jpg)被遗忘的程度,![](/img/dl/LSTM原理/20180705163047274.jpg)为输入门的两个输出乘法运算,表示有多少新信息被保留,基于此,我们就可以把新信息更新这一层的细胞状态![](/img/dl/LSTM原理/20180705163146715.jpg)。 +到目前为止,![](../../img/dl/LSTM原理/20180705162951402.jpg)是遗忘门的输出,控制着上一层细胞状态![](../../img/dl/LSTM原理/20180705163019968.jpg)被遗忘的程度,![](../../img/dl/LSTM原理/20180705163047274.jpg)为输入门的两个输出乘法运算,表示有多少新信息被保留,基于此,我们就可以把新信息更新这一层的细胞状态![](../../img/dl/LSTM原理/20180705163146715.jpg)。 -![](/img/dl/LSTM原理/20180705154157781.jpg) +![](../../img/dl/LSTM原理/20180705154157781.jpg) -* 输出门:输出门用来控制该层的细胞状态有多少被过滤。首先使用sigmoid激活函数得到一个[0,1]区间取值的![](/img/dl/LSTM原理/20180705163549770.jpg),接着将细胞状态![](/img/dl/LSTM原理/20180705164009353.jpg)通过tanh激活函数处理后与![](/img/dl/LSTM原理/20180705164029948.jpg)相乘,即是本层的输出![](/img/dl/LSTM原理/20180705164102617.jpg)。 +* 输出门:输出门用来控制该层的细胞状态有多少被过滤。首先使用sigmoid激活函数得到一个[0,1]区间取值的![](../../img/dl/LSTM原理/20180705163549770.jpg),接着将细胞状态![](../../img/dl/LSTM原理/20180705164009353.jpg)通过tanh激活函数处理后与![](../../img/dl/LSTM原理/20180705164029948.jpg)相乘,即是本层的输出![](../../img/dl/LSTM原理/20180705164102617.jpg)。 -![](/img/dl/LSTM原理/20180705154210768.jpg) +![](../../img/dl/LSTM原理/20180705154210768.jpg) 至此,终于将LSTM的结构理解了,现在有很多LSTM结构的变形,只要把这个母体结构理解了,再去理解变形的结构应该不会再有多麻烦了。 @@ -41,21 +41,21 @@ 双向RNN由两个普通的RNN所组成,一个正向的RNN,利用过去的信息,一个逆序的RNN,利用未来的信息,这样在时刻t,既能够使用t-1时刻的信息,又能够利用到t+1时刻的信息。一般来说,由于双向LSTM能够同时利用过去时刻和未来时刻的信息,会比单向LSTM最终的预测更加准确。下图为双向LSTM的结构。 -![](/img/dl/LSTM原理/20180713200802779.jpg) +![](../../img/dl/LSTM原理/20180713200802779.jpg) -* ![](/img/dl/LSTM原理/20180713204707320.jpg)为正向的RNN,参与正向计算,t时刻的输入为t时刻的序列数据![](/img/dl/LSTM原理/20180713204850377.jpg)和t-1时刻的输出![](/img/dl/LSTM原理/20180713204838867.jpg) -* ![](/img/dl/LSTM原理/20180713204802532.jpg)为逆向的RNN,参与反向计算,t时刻的输入为t时刻的序列数据![](/img/dl/LSTM原理/20180713204852425.jpg)和t+1时刻的输出![](/img/dl/LSTM原理/20180713204825347.jpg) -* t时刻的最终输出值取决于![](/img/dl/LSTM原理/20180713204838867.jpg)和![](/img/dl/LSTM原理/20180713204913638.jpg) +* ![](../../img/dl/LSTM原理/20180713204707320.jpg)为正向的RNN,参与正向计算,t时刻的输入为t时刻的序列数据![](../../img/dl/LSTM原理/20180713204850377.jpg)和t-1时刻的输出![](../../img/dl/LSTM原理/20180713204838867.jpg) +* ![](../../img/dl/LSTM原理/20180713204802532.jpg)为逆向的RNN,参与反向计算,t时刻的输入为t时刻的序列数据![](../../img/dl/LSTM原理/20180713204852425.jpg)和t+1时刻的输出![](../../img/dl/LSTM原理/20180713204825347.jpg) +* t时刻的最终输出值取决于![](../../img/dl/LSTM原理/20180713204838867.jpg)和![](../../img/dl/LSTM原理/20180713204913638.jpg) **GRU(Gated Recurrent Unit)**是LSTM最流行的一个变体,比LSTM模型要简单 -![](/img/dl/LSTM原理/20180713200829571.jpg) +![](../../img/dl/LSTM原理/20180713200829571.jpg) -GRU包括两个门,一个重置门![](/img/dl/LSTM原理/20180713205653854.jpg)和更新门![](/img/dl/LSTM原理/20180713205710503.jpg)。这两个门的激活函数为sigmoid函数,在[0,1]区间取值。 +GRU包括两个门,一个重置门![](../../img/dl/LSTM原理/20180713205653854.jpg)和更新门![](../../img/dl/LSTM原理/20180713205710503.jpg)。这两个门的激活函数为sigmoid函数,在[0,1]区间取值。 -候选隐含状态![](/img/dl/LSTM原理/20180713210203944.jpg)使用重置门![](/img/dl/LSTM原理/20180713205653854.jpg)来控制t-1时刻信息的输入,如果![](/img/dl/LSTM原理/20180713205653854.jpg)结果为0,那么上一个隐含状态的输出信息![](/img/dl/LSTM原理/20180713211322965.jpg)将被丢弃。也就是说,**重置门决定过去有多少信息被遗忘,有助于捕捉时序数据中短期的依赖关系**。 +候选隐含状态![](../../img/dl/LSTM原理/20180713210203944.jpg)使用重置门![](../../img/dl/LSTM原理/20180713205653854.jpg)来控制t-1时刻信息的输入,如果![](../../img/dl/LSTM原理/20180713205653854.jpg)结果为0,那么上一个隐含状态的输出信息![](../../img/dl/LSTM原理/20180713211322965.jpg)将被丢弃。也就是说,**重置门决定过去有多少信息被遗忘,有助于捕捉时序数据中短期的依赖关系**。 -隐含状态使用更新门![](/img/dl/LSTM原理/20180713205710503.jpg)对上一时刻隐含状态![](/img/dl/LSTM原理/20180713210738834.jpg)和候选隐含状态![](/img/dl/LSTM原理/20180713210203944.jpg)进行更新。更新门控制过去的隐含状态在当前时刻的重要性,**如果更新门一直趋近于1,t时刻之前的隐含状态将一直保存下来并全传递到t时刻,****更新门有助于捕捉时序数据中中长期的依赖关系**。 +隐含状态使用更新门![](../../img/dl/LSTM原理/20180713205710503.jpg)对上一时刻隐含状态![](../../img/dl/LSTM原理/20180713210738834.jpg)和候选隐含状态![](../../img/dl/LSTM原理/20180713210203944.jpg)进行更新。更新门控制过去的隐含状态在当前时刻的重要性,**如果更新门一直趋近于1,t时刻之前的隐含状态将一直保存下来并全传递到t时刻,****更新门有助于捕捉时序数据中中长期的依赖关系**。 diff --git "a/docs/dl/RNN\345\216\237\347\220\206.md" "b/docs/dl/RNN\345\216\237\347\220\206.md" index 57630f250..0e15e5af9 100644 --- "a/docs/dl/RNN\345\216\237\347\220\206.md" +++ "b/docs/dl/RNN\345\216\237\347\220\206.md" @@ -7,7 +7,7 @@ 循环神经网络的应用场景比较多,比如暂时能写论文,写程序,写诗,但是,(总是会有但是的),但是他们现在还不能正常使用,学习出来的东西没有逻辑,所以要想真正让它更有用,路还很远。 这是一般的神经网络应该有的结构:  -![这里写图片描述](/img/dl/RNN原理/20171119130251741.jpg) +![这里写图片描述](../../img/dl/RNN原理/20171119130251741.jpg) 既然我们已经有了人工神经网络和卷积神经网络,为什么还要循环神经网络?  原因很简单,无论是卷积神经网络,还是人工神经网络,他们的前提假设都是:元素之间是相互独立的,**输入与输出也是独立的**,比如猫和狗。  @@ -16,18 +16,18 @@ ## 2.RNN的网络结构及原理 它的网络结构如下:  -![这里写图片描述](/img/dl/RNN原理/20171129184524844.jpg) +![这里写图片描述](../../img/dl/RNN原理/20171129184524844.jpg) 其中每个圆圈可以看作是一个单元,而且每个单元做的事情也是一样的,因此可以折叠呈左半图的样子。用一句话解释RNN,就是**一个单元结构重复使用**。 -RNN是一个序列到序列的模型,假设![-w88](/img/dl/RNN原理/15570321772488.jpg)是一个输入:“我是中国“,那么![-w54](/img/dl/RNN原理/15570322195709.jpg)就应该对应”是”,”中国”这两个,预测下一个词最有可能是什么?就是![-w31](/img/dl/RNN原理/15570322451341.jpg)应该是”人”的概率比较大。 +RNN是一个序列到序列的模型,假设![-w88](../../img/dl/RNN原理/15570321772488.jpg)是一个输入:“我是中国“,那么![-w54](../../img/dl/RNN原理/15570322195709.jpg)就应该对应”是”,”中国”这两个,预测下一个词最有可能是什么?就是![-w31](../../img/dl/RNN原理/15570322451341.jpg)应该是”人”的概率比较大。 因此,我们可以做这样的定义: -![-w416](/img/dl/RNN原理/15570322822857.jpg) +![-w416](../../img/dl/RNN原理/15570322822857.jpg) 。因为我们当前时刻的输出是由记忆和当前时刻的输入决定的,就像你现在大四,你的知识是由大四学到的知识(当前输入)和大三以及大三以前学到的东西的(记忆)的结合,RNN在这点上也类似,神经网络最擅长做的就是通过一系列参数把很多内容整合到一起,然后学习这个参数,因此就定义了RNN的基础: -![-w200](/img/dl/RNN原理/15570322981095.jpg) +![-w200](../../img/dl/RNN原理/15570322981095.jpg) 大家可能会很好奇,为什么还要加一个f()函数,其实这个函数是神经网络中的激活函数,但为什么要加上它呢?  举个例子,假如你在大学学了非常好的解题方法,那你初中那时候的解题方法还要用吗?显然是不用了的。RNN的想法也一样,既然我能记忆了,那我当然是只记重要的信息啦,其他不重要的,就肯定会忘记,是吧。但是在神经网络中什么最适合过滤信息呀?肯定是激活函数嘛,因此在这里就套用一个激活函数,来做一个非线性映射,来过滤信息,这个激活函数可能为tanh,也可为其他。 @@ -35,10 +35,10 @@ RNN是一个序列到序列的模型,假设![-w88](/img/dl/RNN原理/155703217 假设你大四快毕业了,要参加考研,请问你参加考研是不是先记住你学过的内容然后去考研,还是直接带几本书去参加考研呢?很显然嘛,那RNN的想法就是预测的时候带着当前时刻的记忆 去预测。假如你要预测“我是中国“的下一个词出现的概率,这里已经很显然了,运用softmax来预测每个词出现的概率再合适不过了,但预测不能直接带用一个矩阵来预测呀,所有预测的时候还要带一个权重矩阵V,用公式表示为: -![-w160](/img/dl/RNN原理/15570323546017.jpg) +![-w160](../../img/dl/RNN原理/15570323546017.jpg) -其中![-w21](/img/dl/RNN原理/15570323768890.jpg)就表示时刻t的输出。 +其中![-w21](../../img/dl/RNN原理/15570323768890.jpg)就表示时刻t的输出。 RNN中的结构细节:  1.可以把St当作隐状态,捕捉了之前时间点上的信息。就像你去考研一样,考的时候记住了你能记住的所有信息。  @@ -50,10 +50,10 @@ RNN中的结构细节:  ## 3.RNN的改进1:双向RNN 在有些情况,比如有一部电视剧,在第三集的时候才出现的人物,现在让预测一下在第三集中出现的人物名字,你用前面两集的内容是预测不出来的,所以你需要用到第四,第五集的内容来预测第三集的内容,这就是双向RNN的想法。如图是双向RNN的图解:  -![这里写图片描述](/img/dl/RNN原理/bi-directional-rnn.png)  -![-w347](/img/dl/RNN原理/15570324711246.jpg) +![这里写图片描述](../../img/dl/RNN原理/bi-directional-rnn.png)  +![-w347](../../img/dl/RNN原理/15570324711246.jpg) -这里的![-w50](/img/dl/RNN原理/15570324937386.jpg)做的是一个拼接,如果他们都是1000x1维的,拼接在一起就是1000x2维的了。 +这里的![-w50](../../img/dl/RNN原理/15570324937386.jpg)做的是一个拼接,如果他们都是1000x1维的,拼接在一起就是1000x2维的了。 双向RNN需要的内存是单向RNN的两倍,因为在同一时间点,双向RNN需要保存两个方向上的权重参数,在分类的时候,需要同时输入两个隐藏层输出的信息。 @@ -61,18 +61,18 @@ RNN中的结构细节:  深层双向RNN 与双向RNN相比,多了几个隐藏层,因为他的想法是很多信息记一次记不下来,比如你去考研,复习考研英语的时候,背英语单词一定不会就看一次就记住了所有要考的考研单词吧,你应该也是带着先前几次背过的单词,然后选择那些背过,但不熟的内容,或者没背过的单词来背吧。 -深层双向RNN就是基于这么一个想法,他的输入有两方面,第一就是前一时刻的隐藏层传过来的信息![-w41](/img/dl/RNN原理/15570325271812.jpg),和当前时刻上一隐藏层传过来的信息![-w167](/img/dl/RNN原理/15570325458791.jpg),包括前向和后向的。  -![这里写图片描述](/img/dl/RNN原理/deep-bi-directional-rnn.png) +深层双向RNN就是基于这么一个想法,他的输入有两方面,第一就是前一时刻的隐藏层传过来的信息![-w41](../../img/dl/RNN原理/15570325271812.jpg),和当前时刻上一隐藏层传过来的信息![-w167](../../img/dl/RNN原理/15570325458791.jpg),包括前向和后向的。  +![这里写图片描述](../../img/dl/RNN原理/deep-bi-directional-rnn.png) 我们用公式来表示是这样的:  -![这里写图片描述](/img/dl/RNN原理/deep-bi-directional-rnn-hidden-layer.png)  +![这里写图片描述](../../img/dl/RNN原理/deep-bi-directional-rnn-hidden-layer.png)  然后再利用最后一层来进行分类,分类公式如下:  -![这里写图片描述](/img/dl/RNN原理/deep-bi-directional-rnn-classification.png) +![这里写图片描述](../../img/dl/RNN原理/deep-bi-directional-rnn-classification.png) ### 4.1 Pyramidal RNN 其他类似的网络还有Pyramidal RNN:  -![这里写图片描述](/img/dl/RNN原理/20171221152506461.jpg) +![这里写图片描述](../../img/dl/RNN原理/20171221152506461.jpg) 我们现在有一个很长的输入序列,可以看到这是一个双向的RNN,上图是谷歌的W.Chan做的一个测试,它原先要做的是语音识别,他要用序列到序列的模型做语音识别,序列到序列就是说,输入一个序列然后就输出一个序列。 由图我们发现,上一层的两个输出,作为当前层的输入,如果是非常长的序列的话,这样做的话,每一层的序列都比上一层要短,但当前层的输入f(x)也会随之增多,貌似看一起相互抵消,运算量并没有什么改进。 @@ -84,55 +84,55 @@ RNN中的结构细节:  如前面我们讲的,如果要预测t时刻的输出,我们必须先利用上一时刻(t-1)的记忆和当前时刻的输入,得到t时刻的记忆: -![-w202](/img/dl/RNN原理/15570325921406.jpg) +![-w202](../../img/dl/RNN原理/15570325921406.jpg) 然后利用当前时刻的记忆,通过softmax分类器输出每个词出现的概率: -![-w144](/img/dl/RNN原理/15570326059642.jpg) +![-w144](../../img/dl/RNN原理/15570326059642.jpg) 为了找出模型最好的参数,U,W,V,我们就要知道当前参数得到的结果怎么样,因此就要定义我们的损失函数,用交叉熵损失函数: -![-w252](/img/dl/RNN原理/15570326336949.jpg) +![-w252](../../img/dl/RNN原理/15570326336949.jpg) -其中![-w14](/img/dl/RNN原理/15570326853547.jpg) - t时刻的标准答案,是一个只有一个是1,其他都是0的向量; ![-w19](/img/dl/RNN原理/15570326727679.jpg)是我们预测出来的结果,与![-w14](/img/dl/RNN原理/15570327422935.jpg) +其中![-w14](../../img/dl/RNN原理/15570326853547.jpg) + t时刻的标准答案,是一个只有一个是1,其他都是0的向量; ![-w19](../../img/dl/RNN原理/15570326727679.jpg)是我们预测出来的结果,与![-w14](../../img/dl/RNN原理/15570327422935.jpg) 的维度一样,但它是一个概率向量,里面是每个词出现的概率。因为对结果的影响,肯定不止一个时刻,因此需要把所有时刻的造成的损失都加起来: -![-w300](/img/dl/RNN原理/15570327570018.jpg) +![-w300](../../img/dl/RNN原理/15570327570018.jpg) -![](/img/dl/RNN原理/20171130091040277.jpg) +![](../../img/dl/RNN原理/20171130091040277.jpg) 如图所示,你会发现每个cell都会有一个损失,我们已经定义好了损失函数,接下来就是熟悉的一步了,那就是根据损失函数利用SGD来求解最优参数,在CNN中使用反向传播BP算法来求解最优参数,但在RNN就要用到BPTT,它和BP算法的本质区别,也是CNN和RNN的本质区别:CNN没有记忆功能,它的输出仅依赖与输入,但RNN有记忆功能,它的输出不仅依赖与当前输入,还依赖与当前的记忆。这个记忆是序列到序列的,也就是当前时刻收到上一时刻的影响,比如股市的变化。 因此,在对参数求偏导的时候,对当前时刻求偏导,一定会涉及前一时刻,我们用例子看一下: -![](/img/dl/RNN原理/20171130091956686.jpg) +![](../../img/dl/RNN原理/20171130091956686.jpg) -假设我们对E3的W求偏导:它的损失首先来源于预测的输出![-w19](/img/dl/RNN原理/15570327881131.jpg) -,预测的输出又是来源于当前时刻的记忆s3,当前的记忆又是来源于当前的输出和截止到上一时刻的记忆:![-w170](/img/dl/RNN原理/15570328132196.jpg) +假设我们对E3的W求偏导:它的损失首先来源于预测的输出![-w19](../../img/dl/RNN原理/15570327881131.jpg) +,预测的输出又是来源于当前时刻的记忆s3,当前的记忆又是来源于当前的输出和截止到上一时刻的记忆:![-w170](../../img/dl/RNN原理/15570328132196.jpg) 因此,根据链式法则可以有: -![-w172](/img/dl/RNN原理/15570328255432.jpg) +![-w172](../../img/dl/RNN原理/15570328255432.jpg) -但是,你会发现,![-w145](/img/dl/RNN原理/15570328436386.jpg) +但是,你会发现,![-w145](../../img/dl/RNN原理/15570328436386.jpg) ,也就是s2里面的函数还包含了W,因此,这个链式法则还没到底,就像图上画的那样,所以真正的链式法则是这样的:  -![这里写图片描述](/img/dl/RNN原理/20171130094236429.jpg)  +![这里写图片描述](../../img/dl/RNN原理/20171130094236429.jpg)  我们要把当前时刻造成的损失,和以往每个时刻造成的损失加起来,因为我们每一个时刻都用到了权重参数W。和以往的网络不同,一般的网络,比如人工神经网络,参数是不同享的,但在循环神经网络,和CNN一样,设立了参数共享机制,来降低模型的计算量。 ## 6.RNN与CNN的结合应用:看图说话 在图像处理中,目前做的最好的是CNN,而自然语言处理中,表现比较好的是RNN,因此,我们能否把他们结合起来,一起用呢?那就是看图说话了,这个原理也比较简单,举个小栗子:假设我们有CNN的模型训练了一个网络结构,比如是这个 -![](/img/dl/RNN原理/20171129213601819.jpg) +![](../../img/dl/RNN原理/20171129213601819.jpg) 最后我们不是要分类嘛,那在分类前,是不是已经拿到了图像的特征呀,那我们能不能把图像的特征拿出来,放到RNN的输入里,让他学习呢? 之前的RNN是这样的: -![-w238](/img/dl/RNN原理/15570328705596.jpg) +![-w238](../../img/dl/RNN原理/15570328705596.jpg) 我们把图像的特征加在里面,可以得到: -![-w266](/img/dl/RNN原理/15570328817086.jpg) +![-w266](../../img/dl/RNN原理/15570328817086.jpg) 其中的X就是图像的特征。如果用的是上面的CNN网络,X应该是一个4096X1的向量。 diff --git "a/docs/dl/\345\217\215\345\220\221\344\274\240\351\200\222.md" "b/docs/dl/\345\217\215\345\220\221\344\274\240\351\200\222.md" index 5648828e5..a6207e22b 100644 --- "a/docs/dl/\345\217\215\345\220\221\344\274\240\351\200\222.md" +++ "b/docs/dl/\345\217\215\345\220\221\344\274\240\351\200\222.md" @@ -8,7 +8,7 @@   说到神经网络,大家看到这个图应该不陌生: -![](/img/dl/反向传递/853467-20160630140644406-409859737.png) +![](../../img/dl/反向传递/853467-20160630140644406-409859737.png)   这是典型的三层神经网络的基本构成,Layer L1是输入层,Layer L2是隐含层,Layer L3是隐含层,我们现在手里有一堆数据{x1,x2,x3,...,xn},输出也是一堆数据{y1,y2,y3,...,yn},现在要他们在隐含层做某种变换,让你把数据灌进去后得到你期望的输出。如果你希望你的输出和原始输入一样,那么就是最常见的自编码模型(Auto-Encoder)。可能有人会问,为什么要输入输出都一样呢?有什么用啊?其实应用挺广的,在图像识别,文本分类等等都会用到,我会专门再写一篇Auto-Encoder的文章来说明,包括一些变种之类的。如果你的输出和原始输入不一样,那么就是很常见的人工神经网络了,相当于让原始数据通过一个映射来得到我们想要的输出数据,也就是我们今天要讲的话题。 @@ -16,13 +16,13 @@   假设,你有这样一个网络层: -![](/img/dl/反向传递/853467-20160630141449671-1058672778.png) +![](../../img/dl/反向传递/853467-20160630141449671-1058672778.png)   第一层是输入层,包含两个神经元i1,i2,和截距项b1;第二层是隐含层,包含两个神经元h1,h2和截距项b2,第三层是输出o1,o2,每条线上标的wi是层与层之间连接的权重,激活函数我们默认为sigmoid函数。   现在对他们赋上初值,如下图: -![](/img/dl/反向传递/853467-20160630142019140-402363317.png) +![](../../img/dl/反向传递/853467-20160630142019140-402363317.png)   其中,输入数据  i1=0.05,i2=0.10; @@ -40,23 +40,23 @@   计算神经元h1的输入加权和: -![](/img/dl/反向传递/853467-20160630142915359-294460310.png) +![](../../img/dl/反向传递/853467-20160630142915359-294460310.png) 神经元h1的输出o1:(此处用到激活函数为sigmoid函数): -![](/img/dl/反向传递/853467-20160630150115390-1035378028.png) +![](../../img/dl/反向传递/853467-20160630150115390-1035378028.png)   同理,可计算出神经元h2的输出o2: -  ![](/img/dl/反向传递/853467-20160630150244265-1128303244.png) +  ![](../../img/dl/反向传递/853467-20160630150244265-1128303244.png)   2.隐含层---->输出层:   计算输出层神经元o1和o2的值: -  ![](/img/dl/反向传递/853467-20160630150517109-389457135.png) +  ![](../../img/dl/反向传递/853467-20160630150517109-389457135.png) -![](/img/dl/反向传递/853467-20160630150638390-1210364296.png) +![](../../img/dl/反向传递/853467-20160630150638390-1210364296.png) 这样前向传播的过程就结束了,我们得到输出值为[0.75136079 , 0.772928465],与实际值[0.01 , 0.99]相差还很远,现在我们对误差进行反向传播,更新权值,重新计算输出。 @@ -66,125 +66,125 @@ 总误差:(square error) -![](/img/dl/反向传递/853467-20160630151201812-1014280864.png) +![](../../img/dl/反向传递/853467-20160630151201812-1014280864.png) 但是有两个输出,所以分别计算o1和o2的误差,总误差为两者之和: -![](/img/dl/反向传递/853467-20160630151457593-1250510503.png) +![](../../img/dl/反向传递/853467-20160630151457593-1250510503.png) -![](/img/dl/反向传递/853467-20160630151508999-1967746600.png) +![](../../img/dl/反向传递/853467-20160630151508999-1967746600.png) -![](/img/dl/反向传递/853467-20160630151516093-1257166735.png) +![](../../img/dl/反向传递/853467-20160630151516093-1257166735.png) 2.隐含层---->输出层的权值更新: 以权重参数w5为例,如果我们想知道w5对整体误差产生了多少影响,可以用整体误差对w5求偏导求出:(链式法则) -![](/img/dl/反向传递/853467-20160630151916796-1001638091.png) +![](../../img/dl/反向传递/853467-20160630151916796-1001638091.png) 下面的图可以更直观的看清楚误差是怎样反向传播的: -![](/img/dl/反向传递/853467-20160630152018906-1524325812.png) +![](../../img/dl/反向传递/853467-20160630152018906-1524325812.png) 现在我们来分别计算每个式子的值: -计算![](/img/dl/反向传递/853467-20160630152206781-7976168.png): +计算![](../../img/dl/反向传递/853467-20160630152206781-7976168.png): -![](/img/dl/反向传递/853467-20160630152258437-1960839452.png) +![](../../img/dl/反向传递/853467-20160630152258437-1960839452.png) -计算![](/img/dl/反向传递/853467-20160630152417109-711077078.png): +计算![](../../img/dl/反向传递/853467-20160630152417109-711077078.png): -![](/img/dl/反向传递/853467-20160630152511937-1667481051.png) +![](../../img/dl/反向传递/853467-20160630152511937-1667481051.png) (这一步实际上就是对sigmoid函数求导,比较简单,可以自己推导一下) -计算![](/img/dl/反向传递/853467-20160630152625593-2083321635.png): +计算![](../../img/dl/反向传递/853467-20160630152625593-2083321635.png): -![](/img/dl/反向传递/853467-20160630152658109-214239362.png) +![](../../img/dl/反向传递/853467-20160630152658109-214239362.png) 最后三者相乘: -![](/img/dl/反向传递/853467-20160630152811640-888140287.png) +![](../../img/dl/反向传递/853467-20160630152811640-888140287.png) 这样我们就计算出整体误差E(total)对w5的偏导值。 回过头来再看看上面的公式,我们发现: -![](/img/dl/反向传递/853467-20160630153103187-515052589.png) +![](../../img/dl/反向传递/853467-20160630153103187-515052589.png) -为了表达方便,用![](/img/dl/反向传递/853467-20160630153202812-585186566.png)来表示输出层的误差: +为了表达方便,用![](../../img/dl/反向传递/853467-20160630153202812-585186566.png)来表示输出层的误差: -![](/img/dl/反向传递/853467-20160630153251234-1144531293.png) +![](../../img/dl/反向传递/853467-20160630153251234-1144531293.png) 因此,整体误差E(total)对w5的偏导公式可以写成: -![](/img/dl/反向传递/853467-20160630153405296-436656179.png) +![](../../img/dl/反向传递/853467-20160630153405296-436656179.png) 如果输出层误差计为负的话,也可以写成: -![](/img/dl/反向传递/853467-20160630153514734-1544628024.png) +![](../../img/dl/反向传递/853467-20160630153514734-1544628024.png) 最后我们来更新w5的值: -![](/img/dl/反向传递/853467-20160630153614374-1624035276.png) +![](../../img/dl/反向传递/853467-20160630153614374-1624035276.png) -(其中,![](/img/dl/反向传递/853467-20160630153700093-743859667.png)是学习速率,这里我们取0.5) +(其中,![](../../img/dl/反向传递/853467-20160630153700093-743859667.png)是学习速率,这里我们取0.5) 同理,可更新w6,w7,w8: -![](/img/dl/反向传递/853467-20160630153807624-1231975059.png) +![](../../img/dl/反向传递/853467-20160630153807624-1231975059.png) 3.隐含层---->隐含层的权值更新:  方法其实与上面说的差不多,但是有个地方需要变一下,在上文计算总误差对w5的偏导时,是从out(o1)---->net(o1)---->w5,但是在隐含层之间的权值更新时,是out(h1)---->net(h1)---->w1,而out(h1)会接受E(o1)和E(o2)两个地方传来的误差,所以这个地方两个都要计算。 -![](/img/dl/反向传递/853467-20160630154317562-311369571.png) +![](../../img/dl/反向传递/853467-20160630154317562-311369571.png) -计算![](/img/dl/反向传递/853467-20160630154712202-1906007645.png): +计算![](../../img/dl/反向传递/853467-20160630154712202-1906007645.png): -![](/img/dl/反向传递/853467-20160630154758531-934861299.png) +![](../../img/dl/反向传递/853467-20160630154758531-934861299.png) -先计算![](/img/dl/反向传递/853467-20160630154958296-1922097086.png): +先计算![](../../img/dl/反向传递/853467-20160630154958296-1922097086.png): -![](/img/dl/反向传递/853467-20160630155015546-1106216279.png) +![](../../img/dl/反向传递/853467-20160630155015546-1106216279.png) -![](/img/dl/反向传递/853467-20160630155036406-964647962.png) +![](../../img/dl/反向传递/853467-20160630155036406-964647962.png) -![](/img/dl/反向传递/853467-20160630155117656-1905928379.png) +![](../../img/dl/反向传递/853467-20160630155117656-1905928379.png) -![](/img/dl/反向传递/853467-20160630155158468-157032005.png) +![](../../img/dl/反向传递/853467-20160630155158468-157032005.png) 同理,计算出: -          ![](/img/dl/反向传递/853467-20160630155310937-2103938446.png) +          ![](../../img/dl/反向传递/853467-20160630155310937-2103938446.png) 两者相加得到总值: -![](/img/dl/反向传递/853467-20160630155435218-396769942.png) +![](../../img/dl/反向传递/853467-20160630155435218-396769942.png) -再计算![](/img/dl/反向传递/853467-20160630155555562-1422254830.png): +再计算![](../../img/dl/反向传递/853467-20160630155555562-1422254830.png): -![](/img/dl/反向传递/853467-20160630155628046-229505495.png) +![](../../img/dl/反向传递/853467-20160630155628046-229505495.png) -再计算![](/img/dl/反向传递/853467-20160630155731421-239852713.png): +再计算![](../../img/dl/反向传递/853467-20160630155731421-239852713.png): -![](/img/dl/反向传递/853467-20160630155706437-964861747.png) +![](../../img/dl/反向传递/853467-20160630155706437-964861747.png) 最后,三者相乘: -![](/img/dl/反向传递/853467-20160630155827718-189457408.png) +![](../../img/dl/反向传递/853467-20160630155827718-189457408.png)  为了简化公式,用sigma(h1)表示隐含层单元h1的误差: -![](/img/dl/反向传递/853467-20160630160345281-679307550.png) +![](../../img/dl/反向传递/853467-20160630160345281-679307550.png) 最后,更新w1的权值: -![](/img/dl/反向传递/853467-20160630160523437-1906004593.png) +![](../../img/dl/反向传递/853467-20160630160523437-1906004593.png) 同理,额可更新w2,w3,w4的权值: -![](/img/dl/反向传递/853467-20160630160603484-1471434475.png) +![](../../img/dl/反向传递/853467-20160630160603484-1471434475.png)   这样误差反向传播法就完成了,最后我们再把更新的权值重新计算,不停地迭代,在这个例子中第一次迭代之后,总误差E(total)由0.298371109下降至0.291027924。迭代10000次后,总误差为0.000035085,输出为[0.015912196,0.984065734](原输入为[0.01,0.99]),证明效果还是不错的。 diff --git "a/docs/ml/1.\346\234\272\345\231\250\345\255\246\344\271\240\345\237\272\347\241\200.md" "b/docs/ml/1.\346\234\272\345\231\250\345\255\246\344\271\240\345\237\272\347\241\200.md" index ac425776c..6f35a45d8 100644 --- "a/docs/ml/1.\346\234\272\345\231\250\345\255\246\344\271\240\345\237\272\347\241\200.md" +++ "b/docs/ml/1.\346\234\272\345\231\250\345\255\246\344\271\240\345\237\272\347\241\200.md" @@ -1,6 +1,6 @@ # 第1章 机器学习基础 -![机器学习基础_首页](/img/ml/1.MLFoundation/机器学习基础-首页.jpg) +![机器学习基础_首页](../../img/ml/1.MLFoundation/机器学习基础-首页.jpg) ## 机器学习 概述 @@ -86,11 +86,11 @@ 这个算法可以训练程序做出某一决定。程序在某一情况下尝试所有的可能行动,记录不同行动的结果并试着找出最好的一次尝试来做决定。 属于这一类算法的有马尔可夫决策过程。 ### 训练过程 -![机器学习训练过程图](/img/ml/1.MLFoundation/机器学习基础训练过程.jpg) +![机器学习训练过程图](../../img/ml/1.MLFoundation/机器学习基础训练过程.jpg) ### 算法汇总 -![算法汇总](/img/ml/1.MLFoundation/ml_algorithm.jpg) +![算法汇总](../../img/ml/1.MLFoundation/ml_algorithm.jpg) ## 机器学习 使用 @@ -104,7 +104,7 @@ > 举例 -![选择算法图](/img/ml/1.MLFoundation/机器学习基础-选择算法.jpg) +![选择算法图](../../img/ml/1.MLFoundation/机器学习基础-选择算法.jpg) > 机器学习 开发流程 @@ -215,7 +215,7 @@ F 值 = 70% * 50% * 2 / (70% + 50%) = 58.3% 下面这个图可以比较直观地展示出来: -![](/img/ml/1.MLFoundation/ml_add_1.jpg) +![](../../img/ml/1.MLFoundation/ml_add_1.jpg) ### 特征工程的一些小东西 @@ -225,7 +225,7 @@ F 值 = 70% * 50% * 2 / (70% + 50%) = 58.3% 下面给出一个特征工程的图: -![](/img/ml/1.MLFoundation/ml_add_2.jpg) +![](../../img/ml/1.MLFoundation/ml_add_2.jpg) ### 其他 diff --git "a/docs/ml/10.k-means\350\201\232\347\261\273.md" "b/docs/ml/10.k-means\350\201\232\347\261\273.md" index e2bbd5b39..b09ac1dd7 100644 --- "a/docs/ml/10.k-means\350\201\232\347\261\273.md" +++ "b/docs/ml/10.k-means\350\201\232\347\261\273.md" @@ -1,7 +1,7 @@ # 第 10 章 K-Means(K-均值)聚类算法 -![K-Means(K-均值)聚类算法_首页](/img/ml/10.KMeans/K-Means_首页.jpg) +![K-Means(K-均值)聚类算法_首页](../../img/ml/10.KMeans/K-Means_首页.jpg) ## 聚类 聚类,简单来说,就是将一个庞杂数据集中具有相似特征的数据自动归类到一起,称为一个簇,簇内的对象越相似,聚类的效果越好。它是一种无监督的学习(Unsupervised Learning)方法,不需要预先标注好的训练集。聚类与分类最大的区别就是分类的目标事先已知,例如猫狗识别,你在分类之前已经预先知道要将它分为猫、狗两个种类;而在你聚类之前,你对你的目标是未知的,同样以动物为例,对于一个动物集来说,你并不清楚这个数据集内部有多少种类的动物,你能做的只是利用聚类方法将它自动按照特征分为多类,然后人为给出这个聚类结果的定义(即簇识别)。例如,你将一个动物集分为了三簇(类),然后通过观察这三类动物的特征,你为每一个簇起一个名字,如大象、狗、猫等,这就是聚类的基本思想。 @@ -48,7 +48,7 @@ kmeans,如前所述,用于数据集内种类属性不明晰,希望能够 有关 `簇` 和 `质心` 术语更形象的介绍, 请参考下图: -![K-Means 术语图](/img/ml/10.KMeans/apachecn-k-means-term-1.jpg) +![K-Means 术语图](../../img/ml/10.KMeans/apachecn-k-means-term-1.jpg) ### K-Means 工作流程 1. 首先, 随机确定 K 个初始点作为质心(**不必是数据中的点**)。 @@ -151,7 +151,7 @@ def kMeans(dataSet, k, distMeas=distEclud, createCent=randCent): 2. 测试一下 kMeans 函数是否可以如预期运行, 请看: 参考运行结果如下: -![K-Means 运行结果1](/img/ml/10.KMeans/apachecn-k-means-run-result-1.jpg) +![K-Means 运行结果1](../../img/ml/10.KMeans/apachecn-k-means-run-result-1.jpg) @@ -159,7 +159,7 @@ def kMeans(dataSet, k, distMeas=distEclud, createCent=randCent): > 在 kMeans 的函数测试中,可能偶尔会陷入局部最小值(局部最优的结果,但不是全局最优的结果). 局部最小值的的情况如下: -![K-Means 局部最小值1](/img/ml/10.KMeans/apachecn-kmeans-partial-best-result-1.jpg) +![K-Means 局部最小值1](../../img/ml/10.KMeans/apachecn-kmeans-partial-best-result-1.jpg) 出现这个问题有很多原因,可能是k值取的不合适,可能是距离函数不合适,可能是最初随机选取的质心靠的太近,也可能是数据本身分布的问题。 为了解决这个问题,我们可以对生成的簇进行后处理,一种方法是将具有最大**SSE**值的簇划分成两个簇。具体实现时可以将最大簇包含的点过滤出来并在这些点上运行K-均值算法,令k设为2。 @@ -228,7 +228,7 @@ def biKMeans(dataSet, k, distMeas=distEclud): 上述函数可以运行多次,聚类会收敛到全局最小值,而原始的 kMeans() 函数偶尔会陷入局部最小值。 运行参考结果如下: -![二分 K-Means 运行结果1](/img/ml/10.KMeans/apachecn-bikmeans-run-result-1.jpg) +![二分 K-Means 运行结果1](../../img/ml/10.KMeans/apachecn-bikmeans-run-result-1.jpg) * **作者:[那伊抹微笑](http://www.apache.wiki/display/~xuxin), [清都江水郎](http://cwiki.apachecn.org/display/~xuzhaoqing)** * [GitHub地址](https://github.com/apachecn/AiLearning): diff --git "a/docs/ml/11.\344\275\277\347\224\250Apriori\347\256\227\346\263\225\350\277\233\350\241\214\345\205\263\350\201\224\345\210\206\346\236\220.md" "b/docs/ml/11.\344\275\277\347\224\250Apriori\347\256\227\346\263\225\350\277\233\350\241\214\345\205\263\350\201\224\345\210\206\346\236\220.md" index 49821cfad..64ec19ea9 100644 --- "a/docs/ml/11.\344\275\277\347\224\250Apriori\347\256\227\346\263\225\350\277\233\350\241\214\345\205\263\350\201\224\345\210\206\346\236\220.md" +++ "b/docs/ml/11.\344\275\277\347\224\250Apriori\347\256\227\346\263\225\350\277\233\350\241\214\345\205\263\350\201\224\345\210\206\346\236\220.md" @@ -1,7 +1,7 @@ # 第 11 章 使用 Apriori 算法进行关联分析 -![](/img/ml/11.Apriori/apachecn_apriori_homepage.jpg) +![](../../img/ml/11.Apriori/apachecn_apriori_homepage.jpg) ## 关联分析 关联分析是一种在大规模数据集中寻找有趣关系的任务。 @@ -12,7 +12,7 @@ ## 相关术语 * 关联分析(关联规则学习): 从大规模数据集中寻找物品间的隐含关系被称作 `关联分析(associati analysis)` 或者 `关联规则学习(association rule learning)` 。 下面是用一个 `杂货店` 例子来说明这两个概念,如下图所示: -![关联分析示例1](/img/ml/11.Apriori/apachecn_apriori_association_demo_1.jpg) +![关联分析示例1](../../img/ml/11.Apriori/apachecn_apriori_association_demo_1.jpg) * 频繁项集: {葡萄酒, 尿布, 豆奶} 就是一个频繁项集的例子。 * 关联规则: 尿布 -> 葡萄酒 就是一个关联规则。这意味着如果顾客买了尿布,那么他很可能会买葡萄酒。 @@ -31,14 +31,14 @@ 假设我们一共有 4 个商品: 商品0, 商品1, 商品2, 商品3。 所有可能的情况如下: -![4种商品的所有组合](/img/ml/11.Apriori/apachecn_apriori_goods_all_1.jpg) +![4种商品的所有组合](../../img/ml/11.Apriori/apachecn_apriori_goods_all_1.jpg) 如果我们计算所有组合的支持度,也需要计算 15 次。即 2^N - 1 = 2^4 - 1 = 15。 随着物品的增加,计算的次数呈指数的形式增长 ... 为了降低计算次数和时间,研究人员发现了一种所谓的 Apriori 原理,即某个项集是频繁的,那么它的所有子集也是频繁的。 例如,如果 {0, 1} 是频繁的,那么 {0}, {1} 也是频繁的。 该原理直观上没有什么帮助,但是如果反过来看就有用了,也就是说如果一个项集是 `非频繁项集`,那么它的所有超集也是非频繁项集,如下图所示: -![非频繁项集](/img/ml/11.Apriori/非频繁项集.png) +![非频繁项集](../../img/ml/11.Apriori/非频繁项集.png) 在图中我们可以看到,已知灰色部分 {2,3} 是 `非频繁项集`,那么利用上面的知识,我们就可以知道 {0,2,3} {1,2,3} {0,1,2,3} 都是 `非频繁的`。 也就是说,计算出 {2,3} 的支持度,知道它是 `非频繁` 的之后,就不需要再计算 {0,2,3} {1,2,3} {0,1,2,3} 的支持度,因为我们知道这些集合不会满足我们的要求。 @@ -272,7 +272,7 @@ def apriori(dataSet, minSupport=0.5): ### 一个频繁项集可以产生多少条关联规则呢? 如下图所示,给出的是项集 {0,1,2,3} 产生的所有关联规则: -![关联规则网格示意图](/img/ml/11.Apriori/apachecn_association_rule_demo_1.jpg) +![关联规则网格示意图](../../img/ml/11.Apriori/apachecn_association_rule_demo_1.jpg) 与我们前面的 `频繁项集` 生成一样,我们可以为每个频繁项集产生许多关联规则。 如果能减少规则的数目来确保问题的可解析,那么计算起来就会好很多。 通过观察,我们可以知道,如果某条规则并不满足 `最小可信度` 要求,那么该规则的所有子集也不会满足 `最小可信度` 的要求。 @@ -386,7 +386,7 @@ def generateRules(L, supportData, minConf=0.7): * 1.首先从一个频繁项集开始,接着创建一个规则列表,其中规则右部分只包含一个元素,然后对这个规则进行测试。 * 2.接下来合并所有剩余规则来创建一个新的规则列表,其中规则右部包含两个元素。 * 如下图: - * ![所有可能的项集组合](/img/ml/11.Apriori/所有可能的项集组合.png) + * ![所有可能的项集组合](../../img/ml/11.Apriori/所有可能的项集组合.png) * 最后: 每次增加频繁项集的大小,Apriori 算法都会重新扫描整个数据集,是否有优化空间呢? 下一章:FP-growth算法等着你的到来 * * * diff --git "a/docs/ml/12.\344\275\277\347\224\250FP-growth\347\256\227\346\263\225\346\235\245\351\253\230\346\225\210\345\217\221\347\216\260\351\242\221\347\271\201\351\241\271\351\233\206.md" "b/docs/ml/12.\344\275\277\347\224\250FP-growth\347\256\227\346\263\225\346\235\245\351\253\230\346\225\210\345\217\221\347\216\260\351\242\221\347\271\201\351\241\271\351\233\206.md" index 08f6c361d..921ae98be 100644 --- "a/docs/ml/12.\344\275\277\347\224\250FP-growth\347\256\227\346\263\225\346\235\245\351\253\230\346\225\210\345\217\221\347\216\260\351\242\221\347\271\201\351\241\271\351\233\206.md" +++ "b/docs/ml/12.\344\275\277\347\224\250FP-growth\347\256\227\346\263\225\346\235\245\351\253\230\346\225\210\345\217\221\347\216\260\351\242\221\347\271\201\351\241\271\351\233\206.md" @@ -1,7 +1,7 @@ # 第12章 使用FP-growth算法来高效发现频繁项集 -![](/img/ml/12.FP-growth/apachecn_fp_growth_homepage.png) +![](../../img/ml/12.FP-growth/apachecn_fp_growth_homepage.png) ## 前言 在 [第11章]() 时我们已经介绍了用 `Apriori` 算法发现 `频繁项集` 与 `关联规则`。 @@ -37,16 +37,16 @@ class treeNode: 1. 遍历所有的数据集合,计算所有项的支持度。 2. 丢弃非频繁的项。 3. 基于 支持度 降序排序所有的项。 - ![](/img/ml/12.FP-growth/步骤1-3.png) + ![](../../img/ml/12.FP-growth/步骤1-3.png) 4. 所有数据集合按照得到的顺序重新整理。 5. 重新整理完成后,丢弃每个集合末尾非频繁的项。 - ![](/img/ml/12.FP-growth/步骤4-5.png) + ![](../../img/ml/12.FP-growth/步骤4-5.png) 步骤2: 6. 读取每个集合插入FP树中,同时用一个头部链表数据结构维护不同集合的相同项。 - ![](/img/ml/12.FP-growth/步骤6-1.png) + ![](../../img/ml/12.FP-growth/步骤6-1.png) 最终得到下面这样一棵FP树 - ![](/img/ml/12.FP-growth/步骤6-2.png) + ![](../../img/ml/12.FP-growth/步骤6-2.png) 从FP树中挖掘出频繁项集 @@ -54,14 +54,14 @@ class treeNode: 步骤3: 1. 对头部链表进行降序排序 2. 对头部链表节点从小到大遍历,得到条件模式基,同时获得一个频繁项集。 - ![](/img/ml/12.FP-growth/步骤6-2.png) + ![](../../img/ml/12.FP-growth/步骤6-2.png) 如上图,从头部链表 t 节点开始遍历,t 节点加入到频繁项集。找到以 t 节点为结尾的路径如下: - ![](/img/ml/12.FP-growth/步骤7-1.png) + ![](../../img/ml/12.FP-growth/步骤7-1.png) 去掉FP树中的t节点,得到条件模式基<左边路径,左边是值>[z,x,y,s,t]:2,[z,x,y,r,t]:1 。条件模式基的值取决于末尾节点 t ,因为 t 的出现次数最小,一个频繁项集的支持度由支持度最小的项决定。所以 t 节点的条件模式基的值可以理解为对于以 t 节点为末尾的前缀路径出现次数。 3. 条件模式基继续构造条件 FP树, 得到频繁项集,和之前的频繁项组合起来,这是一个递归遍历头部链表生成FP树的过程,递归截止条件是生成的FP树的头部链表为空。 根据步骤 2 得到的条件模式基 [z,x,y,s,t]:2,[z,x,y,r,t]:1 作为数据集继续构造出一棵FP树,计算支持度,去除非频繁项,集合按照支持度降序排序,重复上面构造FP树的步骤。最后得到下面 t-条件FP树 : - ![](/img/ml/12.FP-growth/步骤7-2.png) + ![](../../img/ml/12.FP-growth/步骤7-2.png) 然后根据 t-条件FP树 的头部链表进行遍历,从 y 开始。得到频繁项集 ty 。然后又得到 y 的条件模式基,构造出 ty的条件FP树,即 ty-条件FP树。继续遍历ty-条件FP树的头部链表,得到频繁项集 tyx,然后又得到频繁项集 tyxz. 然后得到构造tyxz-条件FP树的头部链表是空的,终止遍历。我们得到的频繁项集有 t->ty->tyz->tyzx,这只是一小部分。 * 条件模式基:头部链表中的某一点的前缀路径组合就是条件模式基,条件模式基的值取决于末尾节点的值。 * 条件FP树:以条件模式基为数据集构造的FP树叫做条件FP树。 diff --git "a/docs/ml/13.\345\210\251\347\224\250PCA\346\235\245\347\256\200\345\214\226\346\225\260\346\215\256.md" "b/docs/ml/13.\345\210\251\347\224\250PCA\346\235\245\347\256\200\345\214\226\346\225\260\346\215\256.md" index 67b7b42f0..c22cc64a9 100644 --- "a/docs/ml/13.\345\210\251\347\224\250PCA\346\235\245\347\256\200\345\214\226\346\225\260\346\215\256.md" +++ "b/docs/ml/13.\345\210\251\347\224\250PCA\346\235\245\347\256\200\345\214\226\346\225\260\346\215\256.md" @@ -1,6 +1,6 @@ # 第13章 利用 PCA 来简化数据 -![利用PCA简化数据_首页](/img/ml/13.PCA/利用PCA简化数据_首页.jpg) +![利用PCA简化数据_首页](../../img/ml/13.PCA/利用PCA简化数据_首页.jpg) ## 降维技术 @@ -70,7 +70,7 @@ 例如下图: -![应用PCA降维](/img/ml/13.PCA/应用PCA降维.png) +![应用PCA降维](../../img/ml/13.PCA/应用PCA降维.png) > PCA 优缺点 @@ -128,7 +128,7 @@ def replaceNanWithMean(): > 分析数据:统计分析 N 的阈值 -![PCA分析数据过程](/img/ml/13.PCA/PCA分析数据过程.jpg) +![PCA分析数据过程](../../img/ml/13.PCA/PCA分析数据过程.jpg) > PCA 数据降维 diff --git "a/docs/ml/14.\345\210\251\347\224\250SVD\347\256\200\345\214\226\346\225\260\346\215\256.md" "b/docs/ml/14.\345\210\251\347\224\250SVD\347\256\200\345\214\226\346\225\260\346\215\256.md" index e20461c35..92a464fca 100644 --- "a/docs/ml/14.\345\210\251\347\224\250SVD\347\256\200\345\214\226\346\225\260\346\215\256.md" +++ "b/docs/ml/14.\345\210\251\347\224\250SVD\347\256\200\345\214\226\346\225\260\346\215\256.md" @@ -1,7 +1,7 @@ # 第14章 利用SVD简化数据 -![利用SVD简化数据首页](/img/ml/14.SVD/svd_headPage.jpg "利用SVD简化数据首页") +![利用SVD简化数据首页](../../img/ml/14.SVD/svd_headPage.jpg "利用SVD简化数据首页") ## SVD 概述 @@ -17,14 +17,14 @@ 隐性语义索引:矩阵 = 文档 + 词语 * 是最早的 SVD 应用之一,我们称利用 SVD 的方法为隐性语义索引(LSI)或隐性语义分析(LSA)。 -![LSA举例](/img/ml/14.SVD/使用SVD简化数据-LSI举例.png) +![LSA举例](../../img/ml/14.SVD/使用SVD简化数据-LSI举例.png) > 推荐系统 1. 利用 SVD 从数据中构建一个主题空间。 2. 再在该空间下计算其相似度。(从高维-低维空间的转化,在低维空间来计算相似度,SVD 提升了推荐系统的效率。) -![主题空间案例1](/img/ml/14.SVD/SVD_推荐系统_主题空间案例1.jpg) +![主题空间案例1](../../img/ml/14.SVD/SVD_推荐系统_主题空间案例1.jpg) * 上图右边标注的为一组共同特征,表示美式 BBQ 空间;另一组在上图右边未标注的为日式食品 空间。 @@ -32,7 +32,7 @@ 例如:`32*32=1024 => 32*2+2*1+32*2=130`(2*1表示去掉了除对角线的0), 几乎获得了10倍的压缩比。 -![SVD公式](/img/ml/14.SVD/使用SVD简化数据-SVD公式.jpg) +![SVD公式](../../img/ml/14.SVD/使用SVD简化数据-SVD公式.jpg) ## SVD 原理 @@ -54,11 +54,11 @@ \\(Data_{m*n} = U_{m\*k} \* ∑_{k\*k} \* V_{k\*n}\\) -![SVD公式](/img/ml/14.SVD/使用SVD简化数据-SVD公式.jpg) +![SVD公式](../../img/ml/14.SVD/使用SVD简化数据-SVD公式.jpg) 具体的案例:(大家可以试着推导一下:https://wenku.baidu.com/view/b7641217866fb84ae45c8d17.html ) -![SVD公式](/img/ml/14.SVD/SVD公式的测试案例.jpg) +![SVD公式](../../img/ml/14.SVD/SVD公式的测试案例.jpg) * 上述分解中会构建出一个矩阵∑,该矩阵只有对角元素,其他元素均为0(近似于0)。另一个惯例就是,∑的对角元素是从大到小排列的。这些对角元素称为奇异值。 * 奇异值与特征值(PCA 数据中重要特征)是有关系的。这里的奇异值就是矩阵 \\(Data * Data^T\\) 特征值的平方根。 @@ -97,12 +97,12 @@ * 基于物品的相似度:计算物品之间的距离。【耗时会随物品数量的增加而增加】 * 由于物品A和物品C 相似度(相关度)很高,所以给买A的人推荐C。 -![SVD公式](/img/ml/14.SVD/使用SVD简化数据-基于物品相似度.png) +![SVD公式](../../img/ml/14.SVD/使用SVD简化数据-基于物品相似度.png) * 基于用户的相似度:计算用户之间的距离。【耗时会随用户数量的增加而增加】 * 由于用户A和用户C 相似度(相关度)很高,所以A和C是兴趣相投的人,对于C买的物品就会推荐给A。 -![SVD公式](/img/ml/14.SVD/使用SVD简化数据-基于用户相似度.png) +![SVD公式](../../img/ml/14.SVD/使用SVD简化数据-基于用户相似度.png) > 相似度计算 @@ -146,7 +146,7 @@ > 收集 并 准备数据 -![SVD 矩阵](/img/ml/14.SVD/项目数据导入.jpg) +![SVD 矩阵](../../img/ml/14.SVD/项目数据导入.jpg) ```python def loadExData3(): @@ -177,9 +177,9 @@ recommend() 会调用 基于物品相似度 或者是 基于SVD,得到推荐 * 1.基于物品相似度 -![基于物品相似度](/img/ml/14.SVD/基于物品相似度.jpg) +![基于物品相似度](../../img/ml/14.SVD/基于物品相似度.jpg) -![欧式距离的计算方式](/img/ml/14.SVD/欧式距离的计算方式.jpg) +![欧式距离的计算方式](../../img/ml/14.SVD/欧式距离的计算方式.jpg) ```python # 基于物品相似度的推荐引擎 @@ -229,7 +229,7 @@ def standEst(dataMat, user, simMeas, item): * 2.基于SVD(参考地址:http://www.codeweblog.com/svd-%E7%AC%94%E8%AE%B0/) -![基于SVD.png](/img/ml/14.SVD/基于SVD.png) +![基于SVD.png](../../img/ml/14.SVD/基于SVD.png) ```python # 基于SVD的评分估计 diff --git "a/docs/ml/15.\345\244\247\346\225\260\346\215\256\344\270\216MapReduce.md" "b/docs/ml/15.\345\244\247\346\225\260\346\215\256\344\270\216MapReduce.md" index 6d43e3e45..dc1390858 100644 --- "a/docs/ml/15.\345\244\247\346\225\260\346\215\256\344\270\216MapReduce.md" +++ "b/docs/ml/15.\345\244\247\346\225\260\346\215\256\344\270\216MapReduce.md" @@ -1,6 +1,6 @@ # 第15章 大数据与MapReduce -![大数据与MapReduce首页](/img/ml/15.BigData_MapReduce/mr_headPage.jpg "大数据与MapReduce首页") +![大数据与MapReduce首页](../../img/ml/15.BigData_MapReduce/mr_headPage.jpg "大数据与MapReduce首页") ## 大数据 概述 @@ -37,7 +37,7 @@ MapReduce: 分布式的计算框架,可以将单个计算作业分配给多台 * 数据被重复存放在不同的机器上,以防止某个机器失效 * mapper 和 reducer 传输的数据形式为 key/value对 -![MapReduce框架的示意图](/img/ml/15.BigData_MapReduce/mr_1_cluster.jpg "MapReduce框架的示意图") +![MapReduce框架的示意图](../../img/ml/15.BigData_MapReduce/mr_1_cluster.jpg "MapReduce框架的示意图") > MapRedece 特点 diff --git "a/docs/ml/16.\346\216\250\350\215\220\347\263\273\347\273\237.md" "b/docs/ml/16.\346\216\250\350\215\220\347\263\273\347\273\237.md" index 436fafda8..ef9a6a288 100644 --- "a/docs/ml/16.\346\216\250\350\215\220\347\263\273\347\273\237.md" +++ "b/docs/ml/16.\346\216\250\350\215\220\347\263\273\347\273\237.md" @@ -46,13 +46,13 @@ | 基于知识推荐 | | | 组合推荐 | | -![推荐方法对比](/img/ml/16.RecommendedSystem/推荐方法对比.png) +![推荐方法对比](../../img/ml/16.RecommendedSystem/推荐方法对比.png) ### 基于知识推荐 基于知识的推荐(Knowledge-based Recommendation)在某种程度是可以看成是一种推理(Inference)技术,它不是建立在用户需要和偏好基础上推荐的。基于知识的方法因它们所用的功能知识不同而有明显区别。效用知识(Functional Knowledge)是一种关于一个项目如何满足某一特定用户的知识,因此能解释需要和推荐的关系,所以用户资料可以是任何能支持推理的知识结构,它可以是用户已经规范化的查询,也可以是一个更详细的用户需要的表示。 -![基于知识的推荐](/img/ml/16.RecommendedSystem/基于知识的推荐.jpg) +![基于知识的推荐](../../img/ml/16.RecommendedSystem/基于知识的推荐.jpg) ### 协同过滤推荐 diff --git "a/docs/ml/2.k-\350\277\221\351\202\273\347\256\227\346\263\225.md" "b/docs/ml/2.k-\350\277\221\351\202\273\347\256\227\346\263\225.md" index a9791d9ca..cd2235794 100644 --- "a/docs/ml/2.k-\350\277\221\351\202\273\347\256\227\346\263\225.md" +++ "b/docs/ml/2.k-\350\277\221\351\202\273\347\256\227\346\263\225.md" @@ -1,7 +1,7 @@ # 第2章 k-近邻算法 -![k-近邻算法_首页](/img/ml/2.KNN/knn_headPage_xy.png "k-近邻算法首页") +![k-近邻算法_首页](../../img/ml/2.KNN/knn_headPage_xy.png "k-近邻算法首页") ## KNN 概述 @@ -21,7 +21,7 @@ 基于电影中的亲吻、打斗出现的次数,使用 k-近邻算法构造程序,就可以自动划分电影的题材类型。 -![电影视频案例](/img/ml/2.KNN/knn-1-movie.png "电影视频案例") +![电影视频案例](../../img/ml/2.KNN/knn-1-movie.png "电影视频案例") ``` 现在根据上面我们得到的样本集中所有电影与未知电影的距离,按照距离递增排序,可以找到 k 个距离最近的电影。 @@ -162,7 +162,7 @@ plt.show() 下图中采用矩阵的第一和第二列属性得到很好的展示效果,清晰地标识了三个不同的样本分类区域,具有不同爱好的人其类别区域也不同。 -![Matplotlib 散点图](/img/ml/2.KNN/knn_matplotlib_2.png) +![Matplotlib 散点图](../../img/ml/2.KNN/knn_matplotlib_2.png) * 归一化数据 (归一化是一个让权重变为统一的过程,更多细节请参考: https://www.zhihu.com/question/19951858 ) @@ -194,7 +194,7 @@ $$\sqrt{(0-67)^2 + (20000-32000)^2 + (1.1-0.1)^2 }$$ 如图: - ![对数函数图像](/img/ml/2.KNN/knn_1.png) + ![对数函数图像](../../img/ml/2.KNN/knn_1.png) 3) 反余切函数转换,表达式如下: @@ -202,7 +202,7 @@ $$\sqrt{(0-67)^2 + (20000-32000)^2 + (1.1-0.1)^2 }$$ 如图: - ![反余切函数图像](/img/ml/2.KNN/arctan_arccot.gif) + ![反余切函数图像](../../img/ml/2.KNN/arctan_arccot.gif) 4) 式(1)将输入值换算为[-1,1]区间的值,在输出层用式(2)换算回初始值,其中和分别表示训练样本集中负荷的最大值和最小值。  @@ -363,7 +363,7 @@ You will probably like this person: in small doses 目录 [trainingDigits](/data/2.KNN/trainingDigits) 中包含了大约 2000 个例子,每个例子内容如下图所示,每个数字大约有 200 个样本;目录 [testDigits](/data/2.KNN/testDigits) 中包含了大约 900 个测试数据。 -![手写数字数据集的例子](/img/ml/2.KNN/knn_2_handWriting.png) +![手写数字数据集的例子](../../img/ml/2.KNN/knn_2_handWriting.png) > 准备数据: 编写函数 img2vector(), 将图像文本数据转换为分类器使用的向量 diff --git "a/docs/ml/3.\345\206\263\347\255\226\346\240\221.md" "b/docs/ml/3.\345\206\263\347\255\226\346\240\221.md" index 3343e4813..b13753c98 100644 --- "a/docs/ml/3.\345\206\263\347\255\226\346\240\221.md" +++ "b/docs/ml/3.\345\206\263\347\255\226\346\240\221.md" @@ -2,7 +2,7 @@ # 第3章 决策树 -![决策树_首页](/img/ml/3.DecisionTree/DecisionTree_headPage_xy.png "决策树首页") +![决策树_首页](../../img/ml/3.DecisionTree/DecisionTree_headPage_xy.png "决策树首页") ## 决策树 概述 @@ -18,7 +18,7 @@ 一个邮件分类系统,大致工作流程如下: -![决策树-流程图](/img/ml/3.DecisionTree/决策树-流程图.jpg "决策树示例流程图") +![决策树-流程图](../../img/ml/3.DecisionTree/决策树-流程图.jpg "决策树示例流程图") ``` 首先检测发送邮件域名地址。如果地址为 myEmployer.com, 则将其放在分类 "无聊时需要阅读的邮件"中。 @@ -114,7 +114,7 @@ def createBranch(): > 收集数据:可以使用任何方法 -![海洋生物数据](/img/ml/3.DecisionTree/DT_海洋生物数据.png) +![海洋生物数据](../../img/ml/3.DecisionTree/DT_海洋生物数据.png) 我们利用 createDataSet() 函数输入数据 @@ -134,7 +134,7 @@ def createDataSet(): > 分析数据:可以使用任何方法,构造树完成之后,我们可以将树画出来。 -![熵的计算公式](/img/ml/3.DecisionTree/熵的计算公式.jpg) +![熵的计算公式](../../img/ml/3.DecisionTree/熵的计算公式.jpg) 计算给定数据集的香农熵的函数 diff --git "a/docs/ml/4.\346\234\264\347\264\240\350\264\235\345\217\266\346\226\257.md" "b/docs/ml/4.\346\234\264\347\264\240\350\264\235\345\217\266\346\226\257.md" index c5196224b..2cf772e5e 100644 --- "a/docs/ml/4.\346\234\264\347\264\240\350\264\235\345\217\266\346\226\257.md" +++ "b/docs/ml/4.\346\234\264\347\264\240\350\264\235\345\217\266\346\226\257.md" @@ -2,7 +2,7 @@ # 第4章 基于概率论的分类方法:朴素贝叶斯 -![朴素贝叶斯_首页](/img/ml/4.NaiveBayesian/NavieBayesian_headPage_xy.png "朴素贝叶斯首页") +![朴素贝叶斯_首页](../../img/ml/4.NaiveBayesian/NavieBayesian_headPage_xy.png "朴素贝叶斯首页") ## 朴素贝叶斯 概述 @@ -14,7 +14,7 @@ 我们现在有一个数据集,它由两类数据组成,数据分布如下图所示: -![朴素贝叶斯示例数据分布](/img/ml/4.NaiveBayesian/朴素贝叶斯示例数据分布.png "参数已知的概率分布") +![朴素贝叶斯示例数据分布](../../img/ml/4.NaiveBayesian/朴素贝叶斯示例数据分布.png "参数已知的概率分布") 我们现在用 p1(x,y) 表示数据点 (x,y) 属于类别 1(图中用圆点表示的类别)的概率,用 p2(x,y) 表示数据点 (x,y) 属于类别 2(图中三角形表示的类别)的概率,那么对于一个新数据点 (x,y),可以用下面的规则来判断它的类别: * 如果 p1(x,y) > p2(x,y) ,那么类别为1 @@ -28,11 +28,11 @@ 有一个装了 7 块石头的罐子,其中 3 块是白色的,4 块是黑色的。如果从罐子中随机取出一块石头,那么是白色石头的可能性是多少?由于取石头有 7 种可能,其中 3 种为白色,所以取出白色石头的概率为 3/7 。那么取到黑色石头的概率又是多少呢?很显然,是 4/7 。我们使用 P(white) 来表示取到白色石头的概率,其概率值可以通过白色石头数目除以总的石头数目来得到。 -![包含 7 块石头的集合](/img/ml/4.NaiveBayesian/NB_2.png) +![包含 7 块石头的集合](../../img/ml/4.NaiveBayesian/NB_2.png) 如果这 7 块石头如下图所示,放在两个桶中,那么上述概率应该如何计算? -![7块石头放入两个桶中](/img/ml/4.NaiveBayesian/NB_3.png) +![7块石头放入两个桶中](../../img/ml/4.NaiveBayesian/NB_3.png) 计算 P(white) 或者 P(black) ,如果事先我们知道石头所在桶的信息是会改变结果的。这就是所谓的条件概率(conditional probablity)。假定计算的是从 B 桶取到白色石头的概率,这个概率可以记作 P(white|bucketB) ,我们称之为“在已知石头出自 B 桶的条件下,取出白色石头的概率”。很容易得到,P(white|bucketA) 值为 2/4 ,P(white|bucketB) 的值为 1/3 。 @@ -44,7 +44,7 @@ P(white|bucketB) = P(white and bucketB) / P(bucketB) 另外一种有效计算条件概率的方法称为贝叶斯准则。贝叶斯准则告诉我们如何交换条件概率中的条件与结果,即如果已知 P(x|c),要求 P(c|x),那么可以使用下面的计算方法: -![计算p(c|x)的方法](/img/ml/4.NaiveBayesian/NB_4.png) +![计算p(c|x)的方法](../../img/ml/4.NaiveBayesian/NB_4.png) ### 使用条件概率来分类 @@ -54,7 +54,7 @@ P(white|bucketB) = P(white and bucketB) / P(bucketB) 这并不是贝叶斯决策理论的所有内容。使用 p1() 和 p2() 只是为了尽可能简化描述,而真正需要计算和比较的是 p(c1|x, y) 和 p(c2|x, y) .这些符号所代表的具体意义是: 给定某个由 x、y 表示的数据点,那么该数据点来自类别 c1 的概率是多少?数据点来自类别 c2 的概率又是多少?注意这些概率与概率 p(x, y|c1) 并不一样,不过可以使用贝叶斯准则来交换概率中条件与结果。具体地,应用贝叶斯准则得到: -![应用贝叶斯准则](/img/ml/4.NaiveBayesian/NB_5.png) +![应用贝叶斯准则](../../img/ml/4.NaiveBayesian/NB_5.png) 使用上面这些定义,可以定义贝叶斯分类准则为: * 如果 P(c1|x, y) > P(c2|x, y), 那么属于类别 c1; @@ -213,7 +213,7 @@ def setOfWords2Vec(vocabList, inputSet): 现在已经知道了一个词是否出现在一篇文档中,也知道该文档所属的类别。接下来我们重写贝叶斯准则,将之前的 x, y 替换为 w. 粗体的 w 表示这是一个向量,即它由多个值组成。在这个例子中,数值个数与词汇表中的词个数相同。 -![重写贝叶斯准则](/img/ml/4.NaiveBayesian/NB_6.png ) +![重写贝叶斯准则](../../img/ml/4.NaiveBayesian/NB_6.png ) 我们使用上述公式,对每个类计算该值,然后比较这两个概率值的大小。 @@ -274,7 +274,7 @@ def _trainNB0(trainMatrix, trainCategory): 下图给出了函数 f(x) 与 ln(f(x)) 的曲线。可以看出,它们在相同区域内同时增加或者减少,并且在相同点上取到极值。它们的取值虽然不同,但不影响最终结果。 -![函数图像](/img/ml/4.NaiveBayesian/NB_7.png ) +![函数图像](../../img/ml/4.NaiveBayesian/NB_7.png ) ```python def trainNB0(trainMatrix, trainCategory): diff --git "a/docs/ml/5.Logistic\345\233\236\345\275\222.md" "b/docs/ml/5.Logistic\345\233\236\345\275\222.md" index 32776da03..0e88dbe7a 100644 --- "a/docs/ml/5.Logistic\345\233\236\345\275\222.md" +++ "b/docs/ml/5.Logistic\345\233\236\345\275\222.md" @@ -1,7 +1,7 @@ # 第5章 Logistic回归 -![朴素贝叶斯_首页](/img/ml/5.Logistic/LogisticRegression_headPage_xy.png "Logistic回归首页") +![朴素贝叶斯_首页](../../img/ml/5.Logistic/LogisticRegression_headPage_xy.png "Logistic回归首页") ## Logistic 回归 概述 @@ -19,11 +19,11 @@ 我们想要的函数应该是: 能接受所有的输入然后预测出类别。例如,在两个类的情况下,上述函数输出 0 或 1.或许你之前接触过具有这种性质的函数,该函数称为 `海维塞得阶跃函数(Heaviside step function)`,或者直接称为 `单位阶跃函数`。然而,海维塞得阶跃函数的问题在于: 该函数在跳跃点上从 0 瞬间跳跃到 1,这个瞬间跳跃过程有时很难处理。幸好,另一个函数也有类似的性质(可以输出 0 或者 1 的性质),且数学上更易处理,这就是 Sigmoid 函数。 Sigmoid 函数具体的计算公式如下: -![Sigmoid 函数计算公式](/img/ml/5.Logistic/LR_1.png) +![Sigmoid 函数计算公式](../../img/ml/5.Logistic/LR_1.png) 下图给出了 Sigmoid 函数在不同坐标尺度下的两条曲线图。当 x 为 0 时,Sigmoid 函数值为 0.5 。随着 x 的增大,对应的 Sigmoid 值将逼近于 1 ; 而随着 x 的减小, Sigmoid 值将逼近于 0 。如果横坐标刻度足够大, Sigmoid 函数看起来很像一个阶跃函数。 -![Sigmoid 函数在不同坐标下的图片](/img/ml/5.Logistic/LR_3.png) +![Sigmoid 函数在不同坐标下的图片](../../img/ml/5.Logistic/LR_3.png) 因此,为了实现 Logistic 回归分类器,我们可以在每个特征上都乘以一个回归系数(如下公式所示),然后把所有结果值相加,将这个总和代入 Sigmoid 函数中,进而得到一个范围在 0~1 之间的数值。任何大于 0.5 的数据被分入 1 类,小于 0.5 即被归入 0 类。所以,Logistic 回归也是一种概率估计,比如这里Sigmoid 函数得出的值为0.5,可以理解为给定数据和参数,数据被分入 1 类的概率为0.5。想对Sigmoid 函数有更多了解,可以点开[此链接](https://www.desmos.com/calculator/bgontvxotm)跟此函数互动。 @@ -31,9 +31,9 @@ Sigmoid 函数的输入记为 z ,由下面公式得到: -![Sigmoid 函数计算公式](/img/ml/5.Logistic/LR_2.png) +![Sigmoid 函数计算公式](../../img/ml/5.Logistic/LR_2.png) -如果采用向量的写法,上述公式可以写成 ![Sigmoid 函数计算公式向量形式](/img/ml/5.Logistic/LR_4.png) ,它表示将这两个数值向量对应元素相乘然后全部加起来即得到 z 值。其中的向量 x 是分类器的输入数据,向量 w 也就是我们要找到的最佳参数(系数),从而使得分类器尽可能地精确。为了寻找该最佳参数,需要用到最优化理论的一些知识。我们这里使用的是——梯度上升法(Gradient Ascent)。 +如果采用向量的写法,上述公式可以写成 ![Sigmoid 函数计算公式向量形式](../../img/ml/5.Logistic/LR_4.png) ,它表示将这两个数值向量对应元素相乘然后全部加起来即得到 z 值。其中的向量 x 是分类器的输入数据,向量 w 也就是我们要找到的最佳参数(系数),从而使得分类器尽可能地精确。为了寻找该最佳参数,需要用到最优化理论的一些知识。我们这里使用的是——梯度上升法(Gradient Ascent)。 ### 梯度上升法 @@ -50,17 +50,17 @@ Sigmoid 函数的输入记为 z ,由下面公式得到: #### 梯度上升法的思想 要找到某函数的最大值,最好的方法是沿着该函数的梯度方向探寻。如果梯度记为 ▽ ,则函数 f(x, y) 的梯度由下式表示: -![梯度上升计算公式](/img/ml/5.Logistic/LR_5.png) +![梯度上升计算公式](../../img/ml/5.Logistic/LR_5.png) -这个梯度意味着要沿 x 的方向移动 ![f(x, y)对x求偏导](/img/ml/5.Logistic/LR_6.png) ,沿 y 的方向移动 ![f(x, y)对y求偏导](/img/ml/5.Logistic/LR_7.png) 。其中,函数f(x, y) 必须要在待计算的点上有定义并且可微。下图是一个具体的例子。 +这个梯度意味着要沿 x 的方向移动 ![f(x, y)对x求偏导](../../img/ml/5.Logistic/LR_6.png) ,沿 y 的方向移动 ![f(x, y)对y求偏导](../../img/ml/5.Logistic/LR_7.png) 。其中,函数f(x, y) 必须要在待计算的点上有定义并且可微。下图是一个具体的例子。 -![梯度上升](/img/ml/5.Logistic/LR_8.png) +![梯度上升](../../img/ml/5.Logistic/LR_8.png) 上图展示的,梯度上升算法到达每个点后都会重新估计移动的方向。从 P0 开始,计算完该点的梯度,函数就根据梯度移动到下一点 P1。在 P1 点,梯度再次被重新计算,并沿着新的梯度方向移动到 P2 。如此循环迭代,直到满足停止条件。迭代过程中,梯度算子总是保证我们能选取到最佳的移动方向。 上图中的梯度上升算法沿梯度方向移动了一步。可以看到,梯度算子总是指向函数值增长最快的方向。这里所说的是移动方向,而未提到移动量的大小。该量值称为步长,记作 α 。用向量来表示的话,梯度上升算法的迭代公式如下: -![梯度上升迭代公式](/img/ml/5.Logistic/LR_9.png) +![梯度上升迭代公式](../../img/ml/5.Logistic/LR_9.png) 该公式将一直被迭代执行,直至达到某个停止条件为止,比如迭代次数达到某个指定值或者算法达到某个可以允许的误差范围。 @@ -80,12 +80,12 @@ Sigmoid 函数的输入记为 z ,由下面公式得到: 只需要在迭代公式中的加法变成减法。因此,对应的公式可以写成 -![梯度下降迭代公式](/img/ml/5.Logistic/LR_10.png) +![梯度下降迭代公式](../../img/ml/5.Logistic/LR_10.png) **局部最优现象 (Local Optima)** -![梯度下降图_4](/img/ml/5.Logistic/LR_20.png) +![梯度下降图_4](../../img/ml/5.Logistic/LR_20.png) 上图表示参数 θ 与误差函数 J(θ) 的关系图 (这里的误差函数是损失函数,所以我们要最小化损失函数),红色的部分是表示 J(θ) 有着比较高的取值,我们需要的是,能够让 J(θ) 的值尽量的低。也就是深蓝色的部分。θ0,θ1 表示 θ 向量的两个维度(此处的θ0,θ1是x0和x1的系数,也对应的是上文w0和w1)。 @@ -126,7 +126,7 @@ Sigmoid 函数的输入记为 z ,由下面公式得到: ### 附加 方向导数与梯度 -![方向导数与梯度](/img/ml/5.Logistic/方向导数和梯度.png) +![方向导数与梯度](../../img/ml/5.Logistic/方向导数和梯度.png) ## Logistic 回归 项目案例 @@ -163,7 +163,7 @@ Sigmoid 函数的输入记为 z ,由下面公式得到: 绘制在图中,如下图所示: -![简单数据集绘制在图上](/img/ml/5.Logistic/LR_11.png) +![简单数据集绘制在图上](../../img/ml/5.Logistic/LR_11.png) > 准备数据: 由于需要进行距离计算,因此要求数据类型为数值型。另外,结构化数据格式则最佳 @@ -247,7 +247,7 @@ def gradAscent(dataMatIn, classLabels): 大家看到这儿可能会有一些疑惑,就是,我们在迭代中更新我们的回归系数,后边的部分是怎么计算出来的?为什么会是 alpha * dataMatrix.transpose() * error ?因为这就是我们所求的梯度,也就是对 f(w) 对 w 求一阶导数。具体推导如下: -![f(w)对w求一阶导数](/img/ml/5.Logistic/LR_21.png) +![f(w)对w求一阶导数](../../img/ml/5.Logistic/LR_21.png) 可参考http://blog.csdn.net/achuo/article/details/51160101 画出数据集和 Logistic 回归最佳拟合直线的函数 @@ -357,7 +357,7 @@ def stocGradAscent0(dataMatrix, classLabels): 判断优化算法优劣的可靠方法是看它是否收敛,也就是说参数是否达到了稳定值,是否还会不断地变化?下图展示了随机梯度上升算法在 200 次迭代过程中回归系数的变化情况。其中的系数2,也就是 X2 只经过了 50 次迭代就达到了稳定值,但系数 1 和 0 则需要更多次的迭代。如下图所示: -![回归系数与迭代次数的关系图](/img/ml/5.Logistic/LR_12.png) +![回归系数与迭代次数的关系图](../../img/ml/5.Logistic/LR_12.png) 针对这个问题,我们改进了之前的随机梯度上升算法,如下: @@ -393,7 +393,7 @@ def stocGradAscent1(dataMatrix, classLabels, numIter=150): 程序运行之后能看到类似于下图的结果图。 -![改进随机梯度下降结果图](/img/ml/5.Logistic/LR_13.png) +![改进随机梯度下降结果图](../../img/ml/5.Logistic/LR_13.png) ### 项目案例2: 从疝气病症预测病马的死亡率 diff --git "a/docs/ml/6.1.\346\224\257\346\214\201\345\220\221\351\207\217\346\234\272\347\232\204\345\207\240\344\270\252\351\200\232\344\277\227\347\220\206\350\247\243.md" "b/docs/ml/6.1.\346\224\257\346\214\201\345\220\221\351\207\217\346\234\272\347\232\204\345\207\240\344\270\252\351\200\232\344\277\227\347\220\206\350\247\243.md" index 7c202798b..629861c93 100644 --- "a/docs/ml/6.1.\346\224\257\346\214\201\345\220\221\351\207\217\346\234\272\347\232\204\345\207\240\344\270\252\351\200\232\344\277\227\347\220\206\350\247\243.md" +++ "b/docs/ml/6.1.\346\224\257\346\214\201\345\220\221\351\207\217\346\234\272\347\232\204\345\207\240\344\270\252\351\200\232\344\277\227\347\220\206\350\247\243.md" @@ -44,13 +44,13 @@ support vector (支持向量)的意思就是 数据集中的某些点 不通俗的理解: 在 maximum margin (最大间隔)上的这些点就叫 “支持向量”,我想补充的是为啥这些点就叫 “支持向量” ,因为最后的 classification machine (分类器)的表达式里只含有这些 “支持向量” 的信息,而与其他数据点无关: -![支持向量机公式](/img/ml/6.SVM/supportVector公式.jpg "supportVector公式") +![支持向量机公式](../../img/ml/6.SVM/supportVector公式.jpg "supportVector公式") -在这个表达式中,只有支持向量的系数 ![alphai](/img/ml/6.SVM/alpha.png "alphai") 不等于 0 。 +在这个表达式中,只有支持向量的系数 ![alphai](../../img/ml/6.SVM/alpha.png "alphai") 不等于 0 。 如果还是不怎么理解,不要紧,看下图: -![supportVector](/img/ml/6.SVM/supportVector.png "supportVector") +![supportVector](../../img/ml/6.SVM/supportVector.png "supportVector") “支持向量” 就是图中用紫色框框圈出来的点... @@ -59,7 +59,7 @@ support vector (支持向量)的意思就是 数据集中的某些点 我们先看一张图 -![supportVectorMachine](/img/ml/6.SVM/svm_2.png "supportVectorMachine") +![supportVectorMachine](../../img/ml/6.SVM/svm_2.png "supportVectorMachine") `linearly separable (线性可分)`: 如上图中的两组数据,它们之间已经分的足够开了,因此很容易就可以在图中画出一条直线将两组数据点分开。在这种情况下,这组数据就被称为线性可分数据。 @@ -87,35 +87,35 @@ support vector (支持向量)的意思就是 数据集中的某些点 魔鬼在桌子上似乎有规律放了两种颜色的球,说:“你用一根棍分开它们?要求:尽量在放更多球之后,仍然适用。” -![story_1](/img/ml/6.SVM/story_1.png "story_1") +![story_1](../../img/ml/6.SVM/story_1.png "story_1") 于是大侠这样放,干的不错? -![story_2](/img/ml/6.SVM/story_2.png "story_2") +![story_2](../../img/ml/6.SVM/story_2.png "story_2") 然后魔鬼,又在桌上放了更多的球,似乎有一个球站错了阵营。 -![story_3](/img/ml/6.SVM/story_3.png "story_3") +![story_3](../../img/ml/6.SVM/story_3.png "story_3") SVM 就是试图把棍放在最佳位置,好让在棍的两边有尽可能大的间隙。 -![story_4](/img/ml/6.SVM/story_4.png "story_4") +![story_4](../../img/ml/6.SVM/story_4.png "story_4") 现在即使魔鬼放了更多的球,棍仍然是一个好的分界线。 -![story_5](/img/ml/6.SVM/story_5.png "story_5") +![story_5](../../img/ml/6.SVM/story_5.png "story_5") 然后,在 SVM 工具箱中有另一个更加重要的 trick。 魔鬼看到大侠已经学会了一个 trick ,于是魔鬼给了大侠一个新的挑战。 -![story_6](/img/ml/6.SVM/story_6.png "story_6") +![story_6](../../img/ml/6.SVM/story_6.png "story_6") 现在,大侠没有棍可以很好帮他分开两种球了,现在怎么办呢?当然像所有武侠片中一样大侠桌子一拍,球飞到空中。然后,凭借大侠的轻功,大侠抓起一张纸,插到了两种球的中间。 -![story_7](/img/ml/6.SVM/story_7.png "story_7") +![story_7](../../img/ml/6.SVM/story_7.png "story_7") 现在,从魔鬼的角度看这些球,这些球看起来像是被一条曲线分开了。 -![story_8](/img/ml/6.SVM/story_8.png "story_8") +![story_8](../../img/ml/6.SVM/story_8.png "story_8") 再之后,无聊的大人们,把这些球叫做 「data」,把棍子叫做 「classifier」, 最大间隙 trick 叫做「optimization」, 拍桌子叫做「kernelling」, 那张纸叫做「hyperplane」 。 @@ -162,11 +162,11 @@ d什么是 SVM ? Support Vector Machine, 一个普通的 SVM 就是一条直线罢了,用来完美划分 linearly separable 的两类。但这又不是一条普通的直线,这是无数条可以分类的直线当中最完美的,因为它恰好在两个类的中间,距离两个类的点都一样远。而所谓的 Support vector 就是这些离分界线最近的『点』。如果去掉这些点,直线多半是要改变位置的。可以说是这些 vectors (主,点点) support (谓,定义)了 machine (宾,分类器)... -![k_2](/img/ml/6.SVM/k_2.jpg "k_2") +![k_2](../../img/ml/6.SVM/k_2.jpg "k_2") 所以谜底就在谜面上啊朋友们,只要找到了这些最靠近的点不就找到了 SVM 了嘛。 @@ -223,45 +223,45 @@ Support Vector Machine, 一个普通的 SVM 就是一条直线罢了,用来完 于是自然而然可以得到重要表达 I. direct representation -![k_7](/img/ml/6.SVM/k_7.png "k_7") +![k_7](../../img/ml/6.SVM/k_7.png "k_7") (可以把 margin 看作是 boundary 的函数,并且想要找到使得是使得 margin 最大化的boundary,而 margin(*) 这个函数是:输入一个 boundary ,计算(正确分类的)所有苹果和香蕉中,到 boundary 的最小距离。) 又有最大又有最小看起来好矛盾。实际上『最大』是对这个整体使用不同 boundary 层面的最大,『最小』是在比较『点』的层面上的最小。外层在比较 boundary 找最大的 margin ,内层在比较点点找最小的距离。 -其中距离,说白了就是点到直线的距离;只要定义带正负号的距离,是 {苹果+1} 面为正 {香蕉-1} 面为负的距离,互相乘上各自的 label ![k_8](/img/ml/6.SVM/k_8.png "k_8") ,就和谐统一民主富强了。 +其中距离,说白了就是点到直线的距离;只要定义带正负号的距离,是 {苹果+1} 面为正 {香蕉-1} 面为负的距离,互相乘上各自的 label ![k_8](../../img/ml/6.SVM/k_8.png "k_8") ,就和谐统一民主富强了。 -![k_9](/img/ml/6.SVM/k_9.png "k_9") +![k_9](../../img/ml/6.SVM/k_9.png "k_9") 到这里为止已经说完了所有关于SVM的直观了解,如果不想看求解,可以跳过下面一大段直接到 objective function 。 直接表达虽然清楚但是求解无从下手。做一些简单地等价变换(分母倒上来)可以得到 II. canonical representation (敲黑板) -![k_10](/img/ml/6.SVM/k_10.png "k_10") +![k_10](../../img/ml/6.SVM/k_10.png "k_10") 要得到 III. dual representation 之前需要大概知道一下拉格朗日乘子法 (method of lagrange multiplier),它是用在有各种约束条件(各种 "subject to" )下的目标函数,也就是直接可以求导可以引出 dual representation(怎么还没完摔) -![k_11](/img/ml/6.SVM/k_11.png "k_11") +![k_11](../../img/ml/6.SVM/k_11.png "k_11") 稍微借用刚刚数学表达里面的内容看个有趣的东西: 还记得我们怎么预测一个新的水果是苹果还是香蕉吗?我们代入到分界的直线里,然后通过符号来判断。 -刚刚w已经被表达出来了也就是说这个直线现在变成了: ![k_12](/img/ml/6.SVM/k_12.png "k_12") +刚刚w已经被表达出来了也就是说这个直线现在变成了: ![k_12](../../img/ml/6.SVM/k_12.png "k_12") -看似仿佛用到了所有的训练水果,但是其中 ![k_13](/img/ml/6.SVM/k_13.png "k_13") 的水果都没有起到作用,剩下的就是小部分靠边边的 Support vectors 呀。 +看似仿佛用到了所有的训练水果,但是其中 ![k_13](../../img/ml/6.SVM/k_13.png "k_13") 的水果都没有起到作用,剩下的就是小部分靠边边的 Support vectors 呀。 III. dual representation -![k_14](/img/ml/6.SVM/k_14.png "k_14") +![k_14](../../img/ml/6.SVM/k_14.png "k_14") 如果香蕉和苹果不能用直线分割呢? -![k_3](/img/ml/6.SVM/k_3.jpg "k_3") +![k_3](../../img/ml/6.SVM/k_3.jpg "k_3") Kernel trick. -其实用直线分割的时候我们已经使用了 kernel ,那就是线性 kernel , ![k_15](/img/ml/6.SVM/k_15.png "k_15") +其实用直线分割的时候我们已经使用了 kernel ,那就是线性 kernel , ![k_15](../../img/ml/6.SVM/k_15.png "k_15") 如果要替换 kernel 那么把目标函数里面的内积全部替换成新的 kernel function 就好了,就是这么简单。 @@ -269,13 +269,13 @@ Kernel trick. 如果香蕉和苹果有交集呢? -![k_4](/img/ml/6.SVM/k_4.jpg "k_4") +![k_4](../../img/ml/6.SVM/k_4.jpg "k_4") -![k_16](/img/ml/6.SVM/k_16.png "k_16") +![k_16](../../img/ml/6.SVM/k_16.png "k_16") 如果还有梨呢? -![k_5](/img/ml/6.SVM/k_5.jpg "k_5") +![k_5](../../img/ml/6.SVM/k_5.jpg "k_5") 可以每个类别做一次 SVM:是苹果还是不是苹果?是香蕉还是不是香蕉?是梨子还是不是梨子?从中选出可能性最大的。这是 one-versus-the-rest approach。 @@ -289,7 +289,7 @@ Kernel trick.

最后送一张图我好爱哈哈哈 (Credit: Burr Settles)

-![k_6](/img/ml/6.SVM/k_6.png "k_6") +![k_6](../../img/ml/6.SVM/k_6.png "k_6")

[1] Bishop C M. Pattern recognition[J]. Machine Learning, 2006, 128.

[2] Friedman J, Hastie T, Tibshirani R. The elements of statistical learning[M]. Springer, Berlin: Springer series in statistics, 2001.

@@ -311,7 +311,7 @@ Kernel trick. SVM 的基本原理基本上已经说的差不多了,下面咱们就来看看 SVM 在实际应用该如何使用了。幸运的是,在 python 下面,sklearn 提供了一个非常好用的机器学习算法,我们调用相关的包就好啦。 -![sklearn_map](/img/ml/6.SVM/ml_map.png "sklearn") +![sklearn_map](../../img/ml/6.SVM/ml_map.png "sklearn") ## 小结 diff --git "a/docs/ml/6.\346\224\257\346\214\201\345\220\221\351\207\217\346\234\272.md" "b/docs/ml/6.\346\224\257\346\214\201\345\220\221\351\207\217\346\234\272.md" index 28690f530..2cfb263f3 100644 --- "a/docs/ml/6.\346\224\257\346\214\201\345\220\221\351\207\217\346\234\272.md" +++ "b/docs/ml/6.\346\224\257\346\214\201\345\220\221\351\207\217\346\234\272.md" @@ -1,7 +1,7 @@ # 第6章 支持向量机 -![支持向量机_首页](/img/ml/6.SVM/SVM_1.jpg) +![支持向量机_首页](../../img/ml/6.SVM/SVM_1.jpg) ## 支持向量机 概述 @@ -14,14 +14,14 @@ * 要给左右两边的点进行分类 * 明显发现:选择D会比B、C分隔的效果要好很多。 -![线性可分](/img/ml/6.SVM/SVM_3_linearly-separable.jpg) +![线性可分](../../img/ml/6.SVM/SVM_3_linearly-separable.jpg) ## 支持向量机 原理 ### SVM 工作原理 -![k_2](/img/ml/6.SVM/k_2.jpg "k_2") +![k_2](../../img/ml/6.SVM/k_2.jpg "k_2") 对于上述的苹果和香蕉,我们想象为2种水果类型的炸弹。(保证距离最近的炸弹,距离它们最远) @@ -32,7 +32,7 @@ * 数据可以通过画一条直线就可以将它们完全分开,这组数据叫`线性可分(linearly separable)`数据,而这条分隔直线称为`分隔超平面(separating hyperplane)`。 * 如果数据集上升到1024维呢?那么需要1023维来分隔数据集,也就说需要N-1维的对象来分隔,这个对象叫做`超平面(hyperlane)`,也就是分类的决策边界。 -![分隔超平面](/img/ml/6.SVM/SVM_2_separating-hyperplane.jpg) +![分隔超平面](../../img/ml/6.SVM/SVM_2_separating-hyperplane.jpg) ### 寻找最大间隔 @@ -65,7 +65,7 @@ Support Vector Machines: Slide 12 Copyright © 2001, 2003, Andrew W. Moore Why M * 分类的结果: \\(f(x)=sign(w^Tx+b)\\) (sign表示>0为1,<0为-1,=0为0) * 点到超平面的`几何间距`: \\(d(x)=(w^Tx+b)/||w||\\) (||w||表示w矩阵的二范数=> \\(\sqrt{w^T*w}\\), 点到超平面的距离也是类似的) -![点到直线的几何距离](/img/ml/6.SVM/SVM_4_point2line-distance.jpg) +![点到直线的几何距离](../../img/ml/6.SVM/SVM_4_point2line-distance.jpg) > 拉格朗日乘子法 @@ -96,7 +96,7 @@ Support Vector Machines: Slide 12 Copyright © 2001, 2003, Andrew W. Moore Why M * 先求: \\(min_{关于w, b} L(w,b,\alpha)=\frac{1}{2} * ||w||^2 + \sum_{i=1}^{n} \alpha_i * [1 - label * (w^Tx+b)]\\) * 就是求`L(w,b,a)`关于[w, b]的偏导数, 得到`w和b的值`,并化简为:`L和a的方程`。 * 参考: 如果公式推导还是不懂,也可以参考《统计学习方法》李航-P103<学习的对偶算法> - ![计算拉格朗日函数的对偶函数](/img/ml/6.SVM/SVM_5_Lagrangemultiplier.png) + ![计算拉格朗日函数的对偶函数](../../img/ml/6.SVM/SVM_5_Lagrangemultiplier.png) * 终于得到课本上的公式: \\(max_{关于\alpha} \left( \sum_{i=1}^{m} \alpha_i - \frac{1}{2} \sum_{i, j=1}^{m} label_i·label_j·\alpha_i·\alpha_j· \right) \\) * 约束条件: \\(a>=0\\) 并且 \\(\sum_{i=1}^{m} a_i·label_i=0\\) @@ -104,12 +104,12 @@ Support Vector Machines: Slide 12 Copyright © 2001, 2003, Andrew W. Moore Why M 参考地址:http://blog.csdn.net/wusecaiyun/article/details/49659183 -![松弛变量公式](/img/ml/6.SVM/SVM_松弛变量.jpg) +![松弛变量公式](../../img/ml/6.SVM/SVM_松弛变量.jpg) * 我们知道几乎所有的数据都不那么干净, 通过引入松弛变量来 `允许数据点可以处于分隔面错误的一侧`。 * 约束条件: \\(C>=a>=0\\) 并且 \\(\sum_{i=1}^{m} a_i·label_i=0\\) * 总的来说: - * ![松弛变量](/img/ml/6.SVM/松弛变量.png) 表示 `松弛变量` + * ![松弛变量](../../img/ml/6.SVM/松弛变量.png) 表示 `松弛变量` * 常量C是 `惩罚因子`, 表示离群点的权重(用于控制“最大化间隔”和“保证大部分点的函数间隔小于1.0” ) * \\(label*(w^Tx+b) > 1\\) and alpha = 0 (在边界外,就是非支持向量) * \\(label*(w^Tx+b) = 1\\) and 0< alpha < C (在分割超平面上,就支持向量) @@ -351,7 +351,7 @@ def smoSimple(dataMatIn, classLabels, C, toler, maxIter): * 核函数并不仅仅应用于支持向量机,很多其他的机器学习算法也都用到核函数。最流行的核函数:径向基函数(radial basis function) * 径向基函数的高斯版本,其具体的公式为: -![径向基函数的高斯版本](/img/ml/6.SVM/SVM_6_radial-basis-function.jpg) +![径向基函数的高斯版本](../../img/ml/6.SVM/SVM_6_radial-basis-function.jpg) ### 项目案例: 手写数字识别的优化(有核函数) diff --git "a/docs/ml/7.\351\233\206\346\210\220\346\226\271\346\263\225-\351\232\217\346\234\272\346\243\256\346\236\227\345\222\214AdaBoost.md" "b/docs/ml/7.\351\233\206\346\210\220\346\226\271\346\263\225-\351\232\217\346\234\272\346\243\256\346\236\227\345\222\214AdaBoost.md" index cd6df82ff..870f39aed 100644 --- "a/docs/ml/7.\351\233\206\346\210\220\346\226\271\346\263\225-\351\232\217\346\234\272\346\243\256\346\236\227\345\222\214AdaBoost.md" +++ "b/docs/ml/7.\351\233\206\346\210\220\346\226\271\346\263\225-\351\232\217\346\234\272\346\243\256\346\236\227\345\222\214AdaBoost.md" @@ -1,6 +1,6 @@ # 第7章 集成方法 ensemble method -![利用AdaBoost元算法提高分类](/img/ml/7.AdaBoost/adaboost_headPage.jpg "利用AdaBoost元算法提高分类") +![利用AdaBoost元算法提高分类](../../img/ml/7.AdaBoost/adaboost_headPage.jpg "利用AdaBoost元算法提高分类") ## 集成方法: ensemble method(元算法: meta algorithm) 概述 @@ -52,7 +52,7 @@ 3. 然后统计子决策树的投票结果,得到最终的分类 就是 随机森林的输出结果。 4. 如下图,假设随机森林中有3棵子决策树,2棵子树的分类结果是A类,1棵子树的分类结果是B类,那么随机森林的分类结果就是A类。 -![数据重抽样](/img/ml/7.RandomForest/数据重抽样.jpg) +![数据重抽样](../../img/ml/7.RandomForest/数据重抽样.jpg) > 待选特征的随机化 @@ -63,7 +63,7 @@ 左边是一棵决策树的特征选取过程,通过在待选特征中选取最优的分裂特征(别忘了前文提到的ID3算法,C4.5算法,CART算法等等),完成分裂。
右边是一个随机森林中的子树的特征选取过程。
-![特征重抽样](/img/ml/7.RandomForest/特征重抽样.jpg) +![特征重抽样](../../img/ml/7.RandomForest/特征重抽样.jpg) > 随机森林 开发流程 @@ -317,7 +317,7 @@ def evaluate_algorithm(dataset, algorithm, n_folds, *args): > AdaBoost 工作原理 -![AdaBoost 工作原理](/img/ml/7.AdaBoost/adaboost_illustration.png "AdaBoost 工作原理") +![AdaBoost 工作原理](../../img/ml/7.AdaBoost/adaboost_illustration.png "AdaBoost 工作原理") > AdaBoost 开发流程 @@ -344,7 +344,7 @@ def evaluate_algorithm(dataset, algorithm, n_folds, *args): > 项目流程图 -![AdaBoost代码流程图](/img/ml/7.AdaBoost/adaboost_code-flow-chart.jpg "AdaBoost代码流程图") +![AdaBoost代码流程图](../../img/ml/7.AdaBoost/adaboost_code-flow-chart.jpg "AdaBoost代码流程图") 基于单层决策树构建弱分类器 * 单层决策树(decision stump, 也称决策树桩)是一种简单的决策树。 @@ -399,11 +399,11 @@ def loadDataSet(fileName): 过拟合(overfitting, 也称为过学习) * 发现测试错误率在达到一个最小值之后有开始上升,这种现象称为过拟合。 -![过拟合](/img/ml/7.AdaBoost/过拟合.png) +![过拟合](../../img/ml/7.AdaBoost/过拟合.png) * 通俗来说:就是把一些噪音数据也拟合进去的,如下图。 -![过拟合](/img/ml/7.AdaBoost/过拟合图解.png) +![过拟合](../../img/ml/7.AdaBoost/过拟合图解.png) > 训练算法:在数据上,利用 adaBoostTrainDS() 函数训练出一系列的分类器 @@ -466,7 +466,7 @@ D (样本权重)的目的是为了计算错误概率: weightedError = D.T* 样本的权重值:如果一个值误判的几率越小,那么 D 的样本权重越小 ``` -![AdaBoost算法权重计算公式](/img/ml/7.AdaBoost/adaboost_alpha.png "AdaBoost算法权重计算公式") +![AdaBoost算法权重计算公式](../../img/ml/7.AdaBoost/adaboost_alpha.png "AdaBoost算法权重计算公式") > 测试算法:我们拥有两个数据集。在不采用随机抽样的方法下,我们就会对 AdaBoost 和 Logistic 回归的结果进行完全对等的比较。 @@ -556,7 +556,7 @@ ROC Curves * ROC 曲线: 最佳的分类器应该尽可能地处于左上角 -![ROC曲线](/img/ml/7.AdaBoost/ROC曲线.png) +![ROC曲线](../../img/ml/7.AdaBoost/ROC曲线.png) * 对不同的 ROC 曲线进行比较的一个指标是曲线下的面积(Area Unser the Curve, AUC). @@ -615,7 +615,7 @@ python实现可以查阅[UnbalancedDataset](https://github.com/scikit-learn-cont * 基于代价函数的分类器决策控制:`TP*(-5)+FN*1+FP*50+TN*0` -![代价函数](/img/ml/7.AdaBoost/代价函数.png) +![代价函数](../../img/ml/7.AdaBoost/代价函数.png) 这种方式叫做 cost sensitive learning,Weka 中相应的框架可以实现叫[CostSensitiveClassifier](http://weka.sourceforge.net/doc.dev/weka/classifiers/meta/CostSensitiveClassifier.html) diff --git "a/docs/ml/8.\345\233\236\345\275\222.md" "b/docs/ml/8.\345\233\236\345\275\222.md" index 876e1a427..5714455ce 100644 --- "a/docs/ml/8.\345\233\236\345\275\222.md" +++ "b/docs/ml/8.\345\233\236\345\275\222.md" @@ -1,7 +1,7 @@ # 第8章 预测数值型数据:回归 -![预测数值型数据回归首页](/img/ml/8.Regression/预测数值型数据回归首页.png "回归Regression首页") +![预测数值型数据回归首页](../../img/ml/8.Regression/预测数值型数据回归首页.png "回归Regression首页") ## 回归(Regression) 概述 @@ -30,11 +30,11 @@ HorsePower = 0.0015 * annualSalary - 0.99 * hoursListeningToPublicRadio 平方误差可以写做(其实我们是使用这个函数作为 loss function): -![平方误差](/img/ml/8.Regression/LinearR_18.png) +![平方误差](../../img/ml/8.Regression/LinearR_18.png) -用矩阵表示还可以写做 ![平方误差_2](/img/ml/8.Regression/LinearR_19.png) 。如果对 w 求导,得到 ![平方误差_3](/img/ml/8.Regression/LinearR_20.png) ,令其等于零,解出 w 如下(具体求导过程为: http://blog.csdn.net/nomadlx53/article/details/50849941 ): +用矩阵表示还可以写做 ![平方误差_2](../../img/ml/8.Regression/LinearR_19.png) 。如果对 w 求导,得到 ![平方误差_3](../../img/ml/8.Regression/LinearR_20.png) ,令其等于零,解出 w 如下(具体求导过程为: http://blog.csdn.net/nomadlx53/article/details/50849941 ): -![回归系数的最佳估计计算公式](/img/ml/8.Regression/LinearR_1.png) +![回归系数的最佳估计计算公式](../../img/ml/8.Regression/LinearR_1.png) #### 1.1、线性回归 须知概念 @@ -42,7 +42,7 @@ HorsePower = 0.0015 * annualSalary - 0.99 * hoursListeningToPublicRadio 因为我们在计算回归方程的回归系数时,用到的计算公式如下: -![回归系数的最佳估计计算公式](/img/ml/8.Regression/LinearR_1.png) +![回归系数的最佳估计计算公式](../../img/ml/8.Regression/LinearR_1.png) 需要对矩阵求逆,因此这个方程只在逆矩阵存在的时候适用,我们在程序代码中对此作出判断。 判断矩阵是否可逆的一个可选方案是: @@ -88,7 +88,7 @@ HorsePower = 0.0015 * annualSalary - 0.99 * hoursListeningToPublicRadio 根据下图中的点,找出该数据的最佳拟合直线。 -![线性回归数据示例图](/img/ml/8.Regression/LinearR_2.png "线性回归数据示例图") +![线性回归数据示例图](../../img/ml/8.Regression/LinearR_2.png "线性回归数据示例图") 数据格式为: @@ -178,7 +178,7 @@ def regression1(): ##### 1.5.3、线性回归 拟合效果 -![线性回归数据效果图](/img/ml/8.Regression/LinearR_3.png "线性回归数据效果图") +![线性回归数据效果图](../../img/ml/8.Regression/LinearR_3.png "线性回归数据效果图") ### 2、局部加权线性回归 @@ -187,21 +187,21 @@ def regression1(): 一个方法是局部加权线性回归(Locally Weighted Linear Regression,LWLR)。在这个算法中,我们给预测点附近的每个点赋予一定的权重,然后与 线性回归 类似,在这个子集上基于最小均方误差来进行普通的回归。我们需要最小化的目标函数大致为: -![局部加权线性回归回归系数公式](/img/ml/8.Regression/LinearR_21.png) +![局部加权线性回归回归系数公式](../../img/ml/8.Regression/LinearR_21.png) 目标函数中 w 为权重,不是回归系数。与 kNN 一样,这种算法每次预测均需要事先选取出对应的数据子集。该算法解出回归系数 w 的形式如下: -![局部加权线性回归回归系数公式](/img/ml/8.Regression/LinearR_4.png) +![局部加权线性回归回归系数公式](../../img/ml/8.Regression/LinearR_4.png) 其中 W 是一个矩阵,用来给每个数据点赋予权重。$\hat{w}$ 则为回归系数。 这两个是不同的概念,请勿混用。 LWLR 使用 “核”(与支持向量机中的核类似)来对附近的点赋予更高的权重。核的类型可以自由选择,最常用的核就是高斯核,高斯核对应的权重如下: -![局部加权线性回归高斯核](/img/ml/8.Regression/LinearR_23.png) +![局部加权线性回归高斯核](../../img/ml/8.Regression/LinearR_23.png) 这样就构建了一个只含对角元素的权重矩阵 **w**,并且点 x 与 x(i) 越近,w(i) 将会越大。上述公式中包含一个需要用户指定的参数 k ,它决定了对附近的点赋予多大的权重,这也是使用 LWLR 时唯一需要考虑的参数,下面的图给出了参数 k 与权重的关系。 -![参数k与权重的关系](/img/ml/8.Regression/LinearR_6.png) +![参数k与权重的关系](../../img/ml/8.Regression/LinearR_6.png) 上面的图是 每个点的权重图(假定我们正预测的点是 x = 0.5),最上面的图是原始数据集,第二个图显示了当 k = 0.5 时,大部分的数据都用于训练回归模型;而最下面的图显示当 k=0.01 时,仅有很少的局部点被用于训练回归模型。 @@ -222,7 +222,7 @@ LWLR 使用 “核”(与支持向量机中的核类似)来对附近的点 我们仍然使用上面 线性回归 的数据集,对这些点进行一个 局部加权线性回归 的拟合。 -![局部加权线性回归数据示例图](/img/ml/8.Regression/LinearR_2.png) +![局部加权线性回归数据示例图](../../img/ml/8.Regression/LinearR_2.png) 数据格式为: @@ -340,7 +340,7 @@ def regression2(): ##### 2.2.3、局部加权线性回归 拟合效果 -![局部加权线性回归数据效果图](/img/ml/8.Regression/LinearR_7.png) +![局部加权线性回归数据效果图](../../img/ml/8.Regression/LinearR_7.png) 上图使用了 3 种不同平滑值绘出的局部加权线性回归的结果。上图中的平滑系数 k =1.0,中图 k = 0.01,下图 k = 0.003 。可以看到,k = 1.0 时的使所有数据等比重,其模型效果与基本的线性回归相同,k=0.01时该模型可以挖出数据的潜在规律,而 k=0.003时则考虑了太多的噪声,进而导致了过拟合现象。 @@ -452,7 +452,7 @@ def abaloneTest(): ### 4、缩减系数来 “理解” 数据 -如果数据的特征比样本点还多应该怎么办?是否还可以使用线性回归和之前的方法来做预测?答案是否定的,即我们不能再使用前面介绍的方法。这是因为在计算 ![矩阵求逆](/img/ml/8.Regression/LinearR_8.png) 的时候会出错。 +如果数据的特征比样本点还多应该怎么办?是否还可以使用线性回归和之前的方法来做预测?答案是否定的,即我们不能再使用前面介绍的方法。这是因为在计算 ![矩阵求逆](../../img/ml/8.Regression/LinearR_8.png) 的时候会出错。 如果特征比样本点还多(n > m),也就是说输入数据的矩阵 x 不是满秩矩阵。非满秩矩阵求逆时会出现问题。 @@ -460,14 +460,14 @@ def abaloneTest(): #### 4.1、岭回归 -简单来说,岭回归就是在矩阵 ![矩阵_1](/img/ml/8.Regression/LinearR_9.png) 上加一个 λI 从而使得矩阵非奇异,进而能对 ![矩阵_2](/img/ml/8.Regression/LinearR_10.png ) 求逆。其中矩阵I是一个 n * n (等于列数) 的单位矩阵, +简单来说,岭回归就是在矩阵 ![矩阵_1](../../img/ml/8.Regression/LinearR_9.png) 上加一个 λI 从而使得矩阵非奇异,进而能对 ![矩阵_2](../../img/ml/8.Regression/LinearR_10.png ) 求逆。其中矩阵I是一个 n * n (等于列数) 的单位矩阵, 对角线上元素全为1,其他元素全为0。而λ是一个用户定义的数值,后面会做介绍。在这种情况下,回归系数的计算公式将变成: -![岭回归的回归系数计算](/img/ml/8.Regression/LinearR_11.png ) +![岭回归的回归系数计算](../../img/ml/8.Regression/LinearR_11.png ) 岭回归最先用来处理特征数多于样本数的情况,现在也用于在估计中加入偏差,从而得到更好的估计。这里通过引入 λ 来限制了所有 w 之和,通过引入该惩罚项,能够减少不重要的参数,这个技术在统计学中也叫作 `缩减(shrinkage)`。 -![岭回归](/img/ml/8.Regression/LinearR_22.png) +![岭回归](../../img/ml/8.Regression/LinearR_22.png) 缩减方法可以去掉不重要的参数,因此能更好地理解数据。此外,与简单的线性回归相比,缩减法能取得更好的预测效果。 @@ -551,7 +551,7 @@ def regression3(): ##### 4.1.2、岭回归在鲍鱼数据集上的运行效果 -![岭回归的运行效果](/img/ml/8.Regression/LinearR_12.png) +![岭回归的运行效果](../../img/ml/8.Regression/LinearR_12.png) 上图绘制出了回归系数与 log(λ) 的关系。在最左边,即 λ 最小时,可以得到所有系数的原始值(与线性回归一致);而在右边,系数全部缩减为0;在中间部分的某值将可以取得最好的预测效果。为了定量地找到最佳参数值,还需要进行交叉验证。另外,要判断哪些变量对结果预测最具有影响力,在上图中观察它们对应的系数大小就可以了。 @@ -560,13 +560,13 @@ def regression3(): 在增加如下约束时,普通的最小二乘法回归会得到与岭回归一样的公式: -![lasso_1](/img/ml/8.Regression/LinearR_13.png) +![lasso_1](../../img/ml/8.Regression/LinearR_13.png) 上式限定了所有回归系数的平方和不能大于 λ 。使用普通的最小二乘法回归在当两个或更多的特征相关时,可能会得到一个很大的正系数和一个很大的负系数。正是因为上述限制条件的存在,使用岭回归可以避免这个问题。 与岭回归类似,另一个缩减方法lasso也对回归系数做了限定,对应的约束条件如下: -![lasso_2](/img/ml/8.Regression/LinearR_14.png) +![lasso_2](../../img/ml/8.Regression/LinearR_14.png) 唯一的不同点在于,这个约束条件使用绝对值取代了平方和。虽然约束形式只是稍作变化,结果却大相径庭: 在 λ 足够小的时候,一些系数会因此被迫缩减到 0.这个特性可以帮助我们更好地理解数据。 @@ -633,7 +633,7 @@ def regression4(): ##### 4.3.2、逐步线性回归在鲍鱼数据集上的运行效果 -![逐步线性回归运行效果](/img/ml/8.Regression/LinearR_15.png) +![逐步线性回归运行效果](../../img/ml/8.Regression/LinearR_15.png) 逐步线性回归算法的主要优点在于它可以帮助人们理解现有的模型并作出改进。当构建了一个模型后,可以运行该算法找出重要的特征,这样就有可能及时停止对那些不重要特征的收集。最后,如果用于测试,该算法每100次迭代后就可以构建出一个模型,可以使用类似于10折交叉验证的方法比较这些模型,最终选择使误差最小的模型。 @@ -646,13 +646,13 @@ def regression4(): 任何时候,一旦发现模型和测量值之间存在差异,就说出现了误差。当考虑模型中的 “噪声” 或者说误差时,必须考虑其来源。你可能会对复杂的过程进行简化,这将导致在模型和测量值之间出现 “噪声” 或误差,若无法理解数据的真实生成过程,也会导致差异的产生。另外,测量过程本身也可能产生 “噪声” 或者问题。下面我们举一个例子,我们使用 `线性回归` 和 `局部加权线性回归` 处理过一个从文件导入的二维数据。 -![生成公式](/img/ml/8.Regression/LinearR_16.png) +![生成公式](../../img/ml/8.Regression/LinearR_16.png) 其中的 N(0, 1) 是一个均值为 0、方差为 1 的正态分布。我们尝试过仅用一条直线来拟合上述数据。不难想到,直线所能得到的最佳拟合应该是 3.0+1.7x 这一部分。这样的话,误差部分就是 0.1sin(30x)+0.06N(0, 1) 。在上面,我们使用了局部加权线性回归来试图捕捉数据背后的结构。该结构拟合起来有一定的难度,因此我们测试了多组不同的局部权重来找到具有最小测试误差的解。 下图给出了训练误差和测试误差的曲线图,上面的曲面就是测试误差,下面的曲线是训练误差。我们根据 预测鲍鱼年龄 的实验知道: 如果降低核的大小,那么训练误差将变小。从下图开看,从左到右就表示了核逐渐减小的过程。 -![偏差方差图](/img/ml/8.Regression/LinearR_17.png) +![偏差方差图](../../img/ml/8.Regression/LinearR_17.png) 一般认为,上述两种误差由三个部分组成: 偏差、测量误差和随机噪声。局部加权线性回归 和 预测鲍鱼年龄 中,我们通过引入了三个越来越小的核来不断增大模型的方差。 diff --git "a/docs/ml/9.\346\240\221\345\233\236\345\275\222.md" "b/docs/ml/9.\346\240\221\345\233\236\345\275\222.md" index ea5fe0f26..2b0fe7dc7 100644 --- "a/docs/ml/9.\346\240\221\345\233\236\345\275\222.md" +++ "b/docs/ml/9.\346\240\221\345\233\236\345\275\222.md" @@ -1,7 +1,7 @@ # 第9章 树回归 -![预测数值型数据回归首页](/img/ml/9.TreeRegression/TreeRegression_headPage_xy.png "树回归首页") +![预测数值型数据回归首页](../../img/ml/9.TreeRegression/TreeRegression_headPage_xy.png "树回归首页") ## 树回归 概述 @@ -124,10 +124,10 @@ data1.txt 文件中存储的数据格式如下: > 分析数据:绘出数据的二维可视化显示结果,以字典方式生成树 基于 CART 算法构建回归树的简单数据集 -![基于 CART 算法构建回归树的简单数据集](/img/ml/9.TreeRegression/RegTree_1.png) +![基于 CART 算法构建回归树的简单数据集](../../img/ml/9.TreeRegression/RegTree_1.png) 用于测试回归树的分段常数数据集 -![用于测试回归树的分段常数数据集](/img/ml/9.TreeRegression/RegTree_2.png) +![用于测试回归树的分段常数数据集](../../img/ml/9.TreeRegression/RegTree_2.png) > 训练算法: 构造树的数据结构 @@ -376,7 +376,7 @@ def prune(tree, testData): 决策树相比于其他机器学习算法的优势之一在于结果更易理解。很显然,两条直线比很多节点组成一棵大树更容易解释。模型树的可解释性是它优于回归树的特点之一。另外,模型树也具有更高的预测准确度。 -![分段线性数据](/img/ml/9.TreeRegression/RegTree_3.png) +![分段线性数据](../../img/ml/9.TreeRegression/RegTree_3.png) 将之前的回归树的代码稍作修改,就可以在叶节点生成线性模型而不是常数值。下面将利用树生成算法对数据进行划分,且每份切分数据都能很容易被线性模型所表示。这个算法的关键在于误差的计算。 @@ -451,7 +451,7 @@ def linearSolve(dataSet): ### 3.3、模型树 运行结果 -![模型树运行结果](/img/ml/9.TreeRegression/RegTree_4.png) +![模型树运行结果](../../img/ml/9.TreeRegression/RegTree_4.png) ## 4、树回归 项目案例 @@ -490,7 +490,7 @@ def linearSolve(dataSet): > 分析数据:绘出数据的二维可视化显示结果,以字典方式生成树 -![骑自行车速度和智商之间的关系](/img/ml/9.TreeRegression/RegTree_5.png) +![骑自行车速度和智商之间的关系](../../img/ml/9.TreeRegression/RegTree_5.png) > 训练算法:模型树的构建 @@ -598,7 +598,7 @@ R^2 判定系数就是拟合优度判定系数,它体现了回归模型中自 如果能让用户不需要任何指令就可以按照他们自己的方式来分析数据,就不需要对数据做出过多解释。其中一个能同时支持数据呈现和用户交互的方式就是构建一个图形用户界面(GUI,Graphical User Interface),如图9-7所示。 -![GUI示例图](/img/ml/9.TreeRegression/GUI示例图.png "GUI示例图") +![GUI示例图](../../img/ml/9.TreeRegression/GUI示例图.png "GUI示例图") ### 5.2、用 Tkinter 创建 GUI @@ -613,7 +613,7 @@ MatPlotlib 的构建程序包含一个前端,也就是面向用户的一些代 ### 5.4、用treeExplore 的GUI构建的模型树示例图 -![取得更好预测效果的GUI示例图](/img/ml/9.TreeRegression/GUI更好的示例图.png "取得更好预测效果的GUI示例图") +![取得更好预测效果的GUI示例图](../../img/ml/9.TreeRegression/GUI更好的示例图.png "取得更好预测效果的GUI示例图") [完整代码地址](https://github.com/apachecn/AiLearning/blob/master/src/py2.x/ml/9.RegTrees/treeExplore.py): diff --git "a/faq/1.\346\234\272\345\231\250\345\255\246\344\271\240\345\256\236\346\210\230-\345\244\215\344\271\240\347\211\210.md" "b/faq/1.\346\234\272\345\231\250\345\255\246\344\271\240\345\256\236\346\210\230-\345\244\215\344\271\240\347\211\210.md" index 07f8036a8..efdf2c365 100644 --- "a/faq/1.\346\234\272\345\231\250\345\255\246\344\271\240\345\256\236\346\210\230-\345\244\215\344\271\240\347\211\210.md" +++ "b/faq/1.\346\234\272\345\231\250\345\255\246\344\271\240\345\256\236\346\210\230-\345\244\215\344\271\240\347\211\210.md" @@ -30,7 +30,7 @@ 如下图:用于评估模型的效果。(测试样本的预测类别 和 测试样本的实际类别 的diff,就是我们的错误率) -![机器学习训练过程图](/img/ml/1.MLFoundation/机器学习基础训练过程.jpg) +![机器学习训练过程图](../../img/ml/1.MLFoundation/机器学习基础训练过程.jpg) > 5.监督学习和无监督学习的区别:是否有目标变量(也就是:是否存在分类结果) diff --git "a/faq/\347\233\264\346\222\255\351\227\256\351\242\230\346\261\207\346\200\273.md" "b/faq/\347\233\264\346\222\255\351\227\256\351\242\230\346\261\207\346\200\273.md" index df655cb59..cebd686c0 100644 --- "a/faq/\347\233\264\346\222\255\351\227\256\351\242\230\346\261\207\346\200\273.md" +++ "b/faq/\347\233\264\346\222\255\351\227\256\351\242\230\346\261\207\346\200\273.md" @@ -42,7 +42,7 @@ 1. 谷德 2017-11-21 20:39:38 问:求距离还有其他的算法吗? - 答:k 近邻模型的特征空间一般是 n 维实数向量空间 ![向量空间](/img/ml/2.KNN/knn_3.png) ,使用的距离是欧式距离。当然,我们还可以选择其他距离,比如更加一般的 ![Lp距离](/img/ml/2.KNN/knn_4.png) 距离(Lp distance),或者 Minkowski 距离(Minkowski distance),曼哈顿距离(Manhattan Distance),切比雪夫距离(Chebyshev Distance)。 + 答:k 近邻模型的特征空间一般是 n 维实数向量空间 ![向量空间](../../img/ml/2.KNN/knn_3.png) ,使用的距离是欧式距离。当然,我们还可以选择其他距离,比如更加一般的 ![Lp距离](../../img/ml/2.KNN/knn_4.png) 距离(Lp distance),或者 Minkowski 距离(Minkowski distance),曼哈顿距离(Manhattan Distance),切比雪夫距离(Chebyshev Distance)。 更多参见链接:http://liyonghui160com.iteye.com/blog/2084557 @@ -51,7 +51,7 @@ 答:如果大佬你说的是下面这种: - ![距离计算](/img/ml/faq/faq_1.png) + ![距离计算](../../img/ml/faq/faq_1.png) 那么求电影距离的 x 是对应的电影中的 打斗镜头数 ,而 y 对应的是接吻镜头数,都是指的数据的特征,可能这里写的不清楚,你可以把这里的 y 当成 x2 属性,而把之前的 x 当成 x1 属性,这样就容易理解多了。都是特征,只不过是对应的不同的特征。注意,这里的 y 代表的不是相应的分类。 diff --git "a/report/2017-04-08_\347\254\254\344\270\200\346\234\237\347\232\204\346\200\273\347\273\223.md" "b/report/2017-04-08_\347\254\254\344\270\200\346\234\237\347\232\204\346\200\273\347\273\223.md" index 1c006a222..5d9c14cb2 100644 --- "a/report/2017-04-08_\347\254\254\344\270\200\346\234\237\347\232\204\346\200\273\347\273\223.md" +++ "b/report/2017-04-08_\347\254\254\344\270\200\346\234\237\347\232\204\346\200\273\347\273\223.md" @@ -1,15 +1,15 @@ # 2017-04-08 第一期的总结 -![2017-04-08_第一期的总结_1](/img/report_20170408/2017-04-08_第一期的总结_1.jpg) -![2017-04-08_第一期的总结_2](/img/report_20170408/2017-04-08_第一期的总结_2.jpg) -![2017-04-08_第一期的总结_3](/img/report_20170408/2017-04-08_第一期的总结_3.jpg) -![2017-04-08_第一期的总结_4](/img/report_20170408/2017-04-08_第一期的总结_4.jpg) -![2017-04-08_第一期的总结_5](/img/report_20170408/2017-04-08_第一期的总结_5.jpg) -![2017-04-08_第一期的总结_6](/img/report_20170408/2017-04-08_第一期的总结_6.jpg) -![2017-04-08_第一期的总结_7](/img/report_20170408/2017-04-08_第一期的总结_7.jpg) -![2017-04-08_第一期的总结_8](/img/report_20170408/2017-04-08_第一期的总结_8.jpg) -![2017-04-08_第一期的总结_9](/img/report_20170408/2017-04-08_第一期的总结_9.jpg) -![2017-04-08_第一期的总结_10](/img/report_20170408/2017-04-08_第一期的总结_10.jpg) -![2017-04-08_第一期的总结_11](/img/report_20170408/2017-04-08_第一期的总结_11.jpg) -![2017-04-08_第一期的总结_12](/img/report_20170408/2017-04-08_第一期的总结_12.jpg) -![2017-04-08_第一期的总结_13](/img/report_20170408/2017-04-08_第一期的总结_13.jpg) +![2017-04-08_第一期的总结_1](../img/report_20170408/2017-04-08_第一期的总结_1.jpg) +![2017-04-08_第一期的总结_2](../img/report_20170408/2017-04-08_第一期的总结_2.jpg) +![2017-04-08_第一期的总结_3](../img/report_20170408/2017-04-08_第一期的总结_3.jpg) +![2017-04-08_第一期的总结_4](../img/report_20170408/2017-04-08_第一期的总结_4.jpg) +![2017-04-08_第一期的总结_5](../img/report_20170408/2017-04-08_第一期的总结_5.jpg) +![2017-04-08_第一期的总结_6](../img/report_20170408/2017-04-08_第一期的总结_6.jpg) +![2017-04-08_第一期的总结_7](../img/report_20170408/2017-04-08_第一期的总结_7.jpg) +![2017-04-08_第一期的总结_8](../img/report_20170408/2017-04-08_第一期的总结_8.jpg) +![2017-04-08_第一期的总结_9](../img/report_20170408/2017-04-08_第一期的总结_9.jpg) +![2017-04-08_第一期的总结_10](../img/report_20170408/2017-04-08_第一期的总结_10.jpg) +![2017-04-08_第一期的总结_11](../img/report_20170408/2017-04-08_第一期的总结_11.jpg) +![2017-04-08_第一期的总结_12](../img/report_20170408/2017-04-08_第一期的总结_12.jpg) +![2017-04-08_第一期的总结_13](../img/report_20170408/2017-04-08_第一期的总结_13.jpg)