找回密码
 立即注册

QQ登录

只需一步,快速开始

机器学习资料整理【内有福利】 加入本站QQ交流群 本站落实实名发帖政策的通知
大家在训练模型时相信
从20世纪60年代,由MIT的计算机教授组织了第一个面向本科生的Summer Project,经历了20世纪50年代初到90年代,尝试用创建
毕业设计中,修改论文格式是一件极其耗费精力的事情,标题,字体,目录,表格等
近几年,人工智能应用范围在不断扩大。其中,合同审查的智能化应用在影响现在的法务市场,合
TensorFlow官方文档—中文版 链接:https://pan.ba
该教程将通过知识点讲解+答疑指导相结合的方式,让大家循序渐进的了解深度学习模型并通过实操演示掌握相关框架及TensorFlow工
本帖最后由 周天 于 2018-1-2
最最经典的凸
lhh.163@163.com
机器学习算法需要作用于数据,而数据的本质则决定了应
总体而言,这本书从基础到研究前沿介绍了深度学习的核心概念与理论。我们不仅能了解到全连接、卷积和循环等基本深度神经网络网络,同时还
【主讲嘉宾】 https://bbs.byr.cn/att/BBSOpenAPI/0/1560/41488 宋 宇 纵目科技无人驾驶事业部首席科学
近年来,随着全球自动化生产需求的持续释放,以及人力成本的不断上升,以互联网、大数据、人工智能
1011
知识图谱技术作为一门新兴的技术,是
“N+”大会是面向全球 AR、VR、AI 等互联网新技术领域的行业领袖及从业者的盛会。 旨在推动全球
优达学院面试技能三件套,包括找工作策略、模拟面试、拓展人脉三门课程
编者按:2017年是不平凡的一年(当然,事实上,每一年都是;P)
查看: 394|回复: 1

仅需六步,从零实现机器学习算法!

[复制链接]

8

主题

19

帖子

399

积分

初级会员

积分
399
发表于 2018-11-16 15:37:27 | 显示全部楼层 |阅读模式
悄悄告诉你,文末有资料哟~

本文以感知器为例,介绍了从零实现机器学习方法的具体步骤以及重要性。


从头开始写机器学习算法能够获得很多经验。当你最终完成时,你会惊喜万分,而且你明白这背后究竟发生了什么。

有些算法比较复杂,我们不从简单的算法开始,而是要从非常简单的算法开始,比如单层感知器。

本文以感知器为例,通过以下 6 个步骤引导你从头开始写算法:

  • 对算法有基本的了解
  • 找到不同的学习资源
  • 将算法分解成块
  • 从简单的例子开始
  • 用可信的实现进行验证
  • 写下你的过程


基本了解

不了解基础知识,就无法从头开始处理算法。至少,你要能回答下列问题:

  • 它是什么?
  • 它一般用在什么地方?
  • 什么时候不能用它?


就感知器而言,这些问题的答案如下:

  • 单层感知器是最基础的神经网络,一般用于二分类问题(1 或 0,「是」或「否」)。
  • 它可以应用在一些简单的地方,比如情感分析(积极反应或消极反应)、贷款违约预测(「会违约」,「不会违约」)。在这两种情况中,决策边界都是线性的。


  • 当决策边界是非线性的时候不能使用感知器,要用不同的方法。



借助不同的学习资源

在对模型有了基本了解之后,就可以开始研究了。有人用教科书学得更好,而有人用视频学得更好。就我而言,我喜欢到处转转,用各种各样的资源学习。

如果是学数学细节的话,书的效果很好(参见:https://www.dataoptimal.com/data-science-books-2018/),但对于更实际的例子,我更推荐博客和 YouTube 视频。

以下列举了一些关于感知器不错的资源:



博客


视频


将算法分解成块

现在我们已经收集好了资料,是时候开始学习了。与其从头读一个章节或者一篇博客,不如先浏览章节标题和其他重要信息。写下要点,并试着概述算法。

在看过这些资料之后,我将感知器分成下列 5 个模块:

  • 初始化权重
  • 将输入和权重相乘之后再求和
  • 比较上述结果和阈值,计算输出(1 或 0)
  • 更新权重
  • 重复


接下来我们详细叙述每一个模块的内容。

1. 初始化权重

首先,我们要初始化权重向量。

权重数量要和特征数量相同。假设我们有三个特征,权重向量如下图所示。权重向量一般会初始化为 0,此例中将一直采用该初始化值。


2. 输入和权重相乘再求和

接下来,我们就要将输入和权重相乘,再对其求和。为了更易于理解,我给第一行中的权重及其对应特征涂上了颜色。


在我们将特征和权重相乘之后,对乘积求和。一般将其称为点积。


最终结果是 0,此时用「f」表示这个暂时的结果。

3. 和阈值比较

计算出点积后,我们要将它和阈值进行比较。我将阈值定为 0,你可以用这个阈值,也可以试一下其他值。

由于之前计算出的点积「f」为 0,不比阈值 0 大,因此估计值也等于 0。

将估计值标记为「y hat」,y hat 的下标 0 对应的是第一行。当然你也可以用 1 表示第一行,这无关紧要,我选择从 0 开始。

如果将这个结果和真值比较的话,可以看出我们当前的权重没有正确地预测出真实的输出。

由于我们的预测错了,因此要更新权重,这就要进行下一步了。

4. 更新权重

我们要用到下面的等式:

基本思想是在迭代「n」时调整当前权重,这样我们将在下一次迭代「n+1」时得到新权重。

为了调整权重,我们需要设定「学习率」,用希腊字母「eta(η)」标记。我将学习率设为 0.1,当然就像阈值一样,你也可以用不同的数值。

目前本教程主要介绍了:


现在我们要继续计算迭代 n=2 时的新权重了。

我们成功完成了感知器算法的第一次迭代。

5. 重复

由于我们的算法没能计算出正确的输出,因此还要继续。

一般需要进行大量的迭代。遍历数据集中的每一行,每一次迭代都要更新权重。一般将完整遍历一次数据集称为一个「epoch」。

我们的数据集有 3 行,因此如果要完成 1 个 epoch 需要经历 3 次迭代。我们也可以设置迭代总数或 epoch 数来执行算法,比如指定 30 次迭代(或 10 个 epoch)。与阈值和学习率一样,epoch 也是可以随意使用的参数。

在下一次迭代中,我们将使用第二行特征。


此处不再重复计算过程,下图给出了下一个点积的计算:

接着就可以比较该点积和阈值来计算新的估计值、更新权重,然后再继续。如果我们的数据是线性可分的,那么感知器最终将会收敛。

从简单的例子开始

我们已经将算法分解成块了,接下来就可以开始用代码实现它了。

简单起见,我一般会以非常小的「玩具数据集」开始。对这类问题而言,有一个很好的小型线性可分数据集,它就是与非门(NAND gate)。这是数字电路中一种常见的逻辑门。


由于这个数据集很小,我们可以手动将其输入到 Python 中。我添加了一列值为 1 的虚拟特征(dummy feature)「x0」,这样模型就可以计算偏置项了。你可以将偏置项视为可以促使模型正确分类的截距项。

以下是输入数据的代码:

# Importing libraries
# NAND Gate
# Note: x0 is a dummy variable for the bias term
#     x0  x1  x2
x = [[1., 0., 0.],
     [1., 0., 1.],
     [1., 1., 0.],
     [1., 1., 1.]]

y =[1.,
    1.,
    1.,
    0.]

与前面的章节一样,我将逐步完成算法、编写代码并对其进行测试。

1. 初始化权重

第一步是初始化权重。

# Initialize the weights
import numpy as np
w = np.zeros(len(x[0]))

Out:
[ 0.  0.  0.]
注意权重向量的长度要和特征长度相匹配。以 NAND 门为例,它的长度是 3。

2. 将权重和输入相乘并对其求和

我们可以用 Numpy 轻松执行该运算,要用的方法是 .dot()。

从权重向量和第一行特征的点积开始。

# Dot Product
f = np.dot(w, x[0])
print f

Out:
0.0
如我们所料,结果是 0。为了与前面的笔记保持连贯性,设点积为变量「f」。

3. 与阈值相比较

为了与前文保持连贯,将阈值「z」设为 0。若点积「f」大于 0,则预测值为 1,否则,预测值为 0。将预测值设为变量 yhat。

# Activation Function
z = 0.0
if f > z:
    yhat = 1.
else:
    yhat = 0.

print yhat

Out:
0.0

正如我们所料,预测值是 0。

你可能注意到了在上文代码的注释中,这一步被称为「激活函数」。这是对这部分内容的更正式的描述。

从 NAND 输出的第一行可以看到实际值是 1。由于预测值是错的,因此需要继续更新权重。

4. 更新权重

现在已经做出了预测,我们准备更新权重。

# Update the weights
eta = 0.1
w[0] = w[0] + eta*(y[0] - yhat)*x[0][0]
w[1] = w[1] + eta*(y[0] - yhat)*x[0][1]
w[2] = w[2] + eta*(y[0] - yhat)*x[0][2]

print w

Out:
[ 0.1  0.   0. ]

要像前文那样设置学习率。为与前文保持一致,将学习率 η 的值设为 0.1。为了便于阅读,我将对每次权重的更新进行硬编码。

权重更新完成。

5. 重复

现在我们完成了每一个步骤,接下来就可以把它们组合在一起了。

我们尚未讨论的最后一步是损失函数,我们需要将其最小化,它在本例中是误差项平方和。


我们要用它来计算误差,然后看模型的性能。

把它们都放在一起,就是完整的函数:

import numpy as np


# Perceptron function
def perceptron(x, y, z, eta, t):
    '''
    Input Parameters:
        x: data set of input features
        y: actual outputs
        z: activation function threshold
        eta: learning rate
        t: number of iterations
    '''


    # initializing the weights
    w = np.zeros(len(x[0]))      
    n = 0                        

    # initializing additional parameters to compute sum-of-squared errors
    yhat_vec = np.ones(len(y))     # vector for predictions
    errors = np.ones(len(y))       # vector for errors (actual - predictions)
    J = []                         # vector for the SSE cost function

    while n < t: for i in xrange(0, len(x)): # dot product f = np.dot(x, w) # activation function if f >= z:                              
                yhat = 1.                              
            else:                                   
                yhat = 0.
            yhat_vec = yhat

            # updating the weights
            for j in xrange(0, len(w)):            
                w[j] = w[j] + eta*(y-yhat)*x[j]

        n += 1
        # computing the sum-of-squared errors
        for i in xrange(0,len(y)):     
           errors = (y-yhat_vec)**2
        J.append(0.5*np.sum(errors))

    return w, J

现在已经编写了完整的感知器代码,接着是运行代码:

#     x0  x1  x2
x = [[1., 0., 0.],
     [1., 0., 1.],
     [1., 1., 0.],
     [1., 1., 1.]]

y =[1.,
    1.,
    1.,
    0.]

z = 0.0
eta = 0.1
t = 50

print "The weights are:"
print perceptron(x, y, z, eta, t)[0]

print "The errors are:"
print perceptron(x, y, z, eta, t)[0]

Out:
The weights are:
[ 0.2 -0.2 -0.1]
The errors are:
[0.5, 1.5, 1.5, 1.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]

我们可以看到,第 6 次迭代时误差趋近于 0,且在剩余迭代中误差一直是 0。当误差趋近于 0 并保持为 0 时,模型就收敛了。这告诉我们模型已经正确「学习」了适当的权重。

下一部分,我们将用计算好的权重在更大的数据集上进行预测。

用可信的实现进行验证

到目前为止,我们已经找到了不同的学习资源、手动完成了算法,并用简单的例子测试了算法。

现在要用可信的实现和我们的模型进行比较了。我们使用的是 scikit-learn 中的感知器(http://scikit-learn.org/stable/m ... del.Perceptron.html)。

我们将按照以下几步进行比较:

  • 导入数据
  • 将数据分割为训练集和测试集
  • 训练感知器
  • 测试感知器
  • 和 scikit-learn 感知器进行比较


1. 导入数据

首先导入数据。你可以在这里(https://github.com/dataoptimal/posts/blob/master/algorithms from scratch/dataset.csv)得到数据集的副本。这是我创建的线性可分数据集,确保感知器可以起作用。为了确认,我们还将数据绘制成图。

从图中很容易看出来,我们可以用一条直线将数据分开。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

df = pd.read_csv("dataset.csv")
plt.scatter(df.values[:,1], df.values[:,2], c = df['3'], alpha=0.8)

text


在继续之前,我先解释一下绘图的代码。我用 Pandas 导入 csv,它可以自动将数据放入 DataFrame 中。为了绘制数据,我要将值从 DataFrame 中取出来,因此我用了 .values 方法。特征在第一列和第二列,因此我在散点图函数中用了这些特征。第 0 列是值为 1 的虚拟特征,这样就能计算截距。这与上一节中的 NAND 门操作相似。最后,在散点图函数中令 c = df['3'], alpha = 0.8 为两个类着色。输出是第三列数据(0 或 1),所以我告诉函数用列「3」给这两个类着色。

关注“人工智能前沿”公众号,查看完整文章。还有免费资料领取
回复“AI”、“PGM”、“深度学习”、“人脸识别”、“Python入门”、“AI技术架构”、“3D视觉”、“PyTorch1.0”等关键词,领取最新研究报告或技术资料

回复 论坛版权

使用道具 举报

0

主题

62

帖子

847

积分

中级会员

积分
847
发表于 2018-12-4 17:42:12 | 显示全部楼层
了解一下
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

宸ュ晢钀ヤ笟鎵х収鐢靛瓙璁稿彲璇 | QQ|申请友链|小黑屋|手机版|人工智能A7论坛(aqinet.cn) ( 沪ICP备15039134号-1 ) 人工智能A7论坛坛友会

GMT+8, 2019-9-18 21:51 , Processed in 0.085185 second(s), 47 queries .

Powered by Discuz! X3.4 Licensed

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表