机器学习和深度学习_算法测评 | 机器学习VS深度学习

本文通过比较机器学习的朴素贝叶斯算法和深度学习的简单神经网络,分析在鸢尾花数据集上的表现。在未进行特征工程时,朴素贝叶斯预测准确率为80%,经过特征工程后达到90%。手工实现的单层神经网络在500轮训练后,准确率达到93.33%,调整参数后可达96.66%。深度学习虽然准确率高,但计算时间更长。
摘要由CSDN通过智能技术生成
28e8a1f5017dba6c7e769d3a0f8e4e32.gif

OLDER BROTHER

 大家好,我是你们的机房老哥! 

d1c1396fe309c5ec3887bdc8ee46def0.png

“机器学习进阶”

「前言

机器学习和深度学习是很早前就埋下的坑,最近决定整合写一篇,利用机器学习的经典算法朴素贝叶斯和深度学习的经典算法神经网络对鸢尾花数据集进行测试,综合对比两种经典算法的异同。后台回复6月24日获得完整代码。

相关入门教程:

  • 深度学习:Tensorflow 2.0简明入门

  • 人工智能 | 最简单的语言理解神经网络

  • 10分钟:开启你的机器学习&可视化之路

01

二者关系

AI

器学习是人工智能的重要子领域,它聚焦于如何构建随着经验而自动改进的算法,可以从数据中提取模式、规律和趋势。为什么叫做「学习」呢?一般编程语言的做法是人类给予指令,机器负责执行。而机器学习则相反,先定义好输出,然后程序自动「学习」出达到目标的「步骤」。机器学习最常见的应用领域:

  • 分类(新闻分类)

  • 预测(股票预测)

  • 聚类(自动分组)

  • 规则提取(数据挖掘)

然而机器学习却并非那么智能,数据和特征决定了机器学习的上限,需要人工不停的调整输入特征,使算法不断逼近该上限,这个过程叫特征工程。在算法一致的情况下,特征工程会极大的影响结果,因此准确率很难达到很高。

深度学习是机器学习的子类,通过模拟人脑的神经元,实现自动提取要素的复杂特征,减去了人工调整的烦恼。

43c2fcf1983b8ebd1ef7c7fd6ee2c4f6.png

机器学习与深度学习的关系

02

机器学习

Machine Learning,ML

哥先用sklearn测试机器学习经典算法之朴素贝叶斯。朴素贝叶斯是一个分类算法,通俗地讲分类算法就是把大量已知特征及类别的样本对象输入计算机,让计算机根据这些已知的类别与特征归纳出类别与特征之间的规律,最终目的是运用得到的分类模型对新输入的对象判断出该对象所属分类。

「朴素」的涵义是假设各特征之间相互独立,这意味着该算法很简单,但是会牺牲一定的准确性。其本质思想是判断输入的条件参数对结果影响的概率,相关公式在10分钟:开启你的机器学习&可视化之路一文中已经阐释,这里不再赘述。

from sklearn.datasets import load_irisimport pandas as pdx_data = load_iris().datay_data = load_iris().targetx_data = pd.DataFrame(x_data, columns = ['花萼长','花萼宽','花瓣长','花瓣宽'])x_data['标签'] = y_datapd.set_option('display.unicode.east_asian_width',True)print(x_data)

先从sklearn的datasets中导入iris数据集。load_iris().data可以得到数据集的特征项,load_iris().target可以得到标签项。老哥用pandas的DataFrame将数据集变成表格输出,可视化相关参数。pd.set_option()的作用是美化DataFrame的打印效果,使列名与数据对齐。

e6a78d764199b5e0d5abd3710bcc6c2f.png

iris数据集

数据共150个,有4个特征,标签有3类,代表鸢尾花的种类。目标是希望利用朴素贝叶斯算法,实现输入数据后,机器自动判断鸢尾花的种类。

from sklearn.model_selection import train_test_splitx_train, x_test, y_train, y_test = train_test_split(x_data,y_data,test_size=30, random_state=25)

利用train_test_split工具将数据集划分为训练集和测试集。输入特征项x_data、标签项y_data,该工具会自动随机划分数据集。test_size即划分比例,如果是小数,指测试集的百分比,如果是大于1的整数,则指测试集的数据个数,我们这里选择30个数据作为测试集。random_state是随机种子,种子一样,则每次的随机划分结果都一致,否则每一次对数据集的划分都是随机的。

本次为了对比机器学习和深度学习算法,设定随机种子,保证两算法用的数据集划分结果一致。

from sklearn.model_selection import train_test_splitfrom sklearn.naive_bayes import MultinomialNBfrom sklearn.datasets import load_irisimport timedef naviebayes(x_train, x_test, y_train, y_test):    """    朴素贝叶斯进行鸢尾花分类    """    mlt = MultinomialNB(alpha=1)    mltStart = time.time()    mlt.fit(x_train, y_train)    mltCostTime = time.time() - mltStart    print("朴素贝叶斯建模%.2f秒" % mltCostTime)    y_score_test = mlt.score(x_test, y_test)    print(y_score_test)if __name__ == "__main__":    x_data = load_iris().data    y_data = load_iris().target    x_train, x_test, y_train, y_test = train_test_split(x_data, y_data, test_size=30, random_state=25)    naviebayes(x_train, x_test, y_train, y_test)

完整代码如上,为测试特征工程对机器学习结果的影响,先不进行特征工程,直接对数据集进行训练。训练的方法也非常简单,从sklearn.naive_bayes中导入MultinomialNB算法,这里也可以导入GaussianNB(先验为高斯分布的朴素贝叶斯)和BernoulliNB(先验为伯努利分布的朴素贝叶斯),单纯的改个名字即可,大家可以自己测试。

首先将MultinomialNB(alpha=1)实例化为mlt,方便后续调用,参数alpha为拉普拉斯平滑参数,该参数为1代表默认每个特征至少出现一次(避免大量出现0概率的情况)。然后将训练集的x和y传入mlt.fit()中计算,得到模型。将测试集的x和y传入mlt.score()函数中,自动进行预测,并输出准确率。利用time模块计算算法运行时间。

ca6540373a3cf382d1f4b605879b189d.png

结果可知,在未进行特征工程的情况下,预测准确率为80%。接下来我们测试加入数据预处理后的预测准确率,代码如下:

from sklearn.model_selection import train_test_splitfrom sklearn.preprocessing import Normalizerfrom sklearn.preprocessing import PolynomialFeaturesfrom sklearn.preprocessing import MinMaxScalerfrom sklearn.preprocessing import StandardScalerfrom sklearn.preprocessing import OneHotEncoderfrom sklearn.preprocessing import Binarizerfrom sklearn.naive_bayes import MultinomialNBfrom sklearn.datasets import load_irisimport timedef naviebayes(x_train, x_test, y_train, y_test):    for preprocessing_method in [Normalizer(),PolynomialFeatures(),MinMaxScaler(),StandardScaler(),Binarizer(),OneHotEncoder()]:        try:            method = preprocessing_method            method.fit(x_train)            x_train = method.transform(x_train)            x_test = method.transform(x_test)            print('特征工程算法:',str(preprocessing_method).split('(')[0])            mlt = MultinomialNB(alpha=1)            mltStart = time.time()            mlt.fit(x_train, y_train)            mltCostTime = time.time() - mltStart            print("建模时长%.2f秒" % mltCostTime)            y_score_test = mlt.score(x_test, y_test)            print(y_score_test)        except:            print(str(preprocessing_method).split('(')[0],'算法无法在本例使用')if __name__ == "__main__":    x_data = load_iris().data    y_data = load_iris().target    x_train, x_test, y_train, y_test = train_test_split(x_data, y_data, test_size=30, random_state=25)    naviebayes(x_train, x_test, y_train, y_test)

sklearn将所有预处理算法都封装到了preprocessing函数中,如上述代码所示,老哥用for循环分别测试了六个算法的训练准确率。算法如下:

预处理算法

功能

Normalizer()

正则化

将每个样本缩放到单位范数

4e2fef17e6f0bfb4d95ac7df5f3d4fb7.png

PolynomialFeatures()

多项式转换

构造特征值,例如有 a、b 两个特征,那么它的 2 次多项式为 

[1,a,b,a2,ab,b2]

MinMaxScaler()

区间缩放

将属性缩放到指定的极值(通常是1-0)之间

2ca62713ae0129a15248878850fd3dba.png

StandardScaler()

中心化

令所有数据的中心为(0,0)

651a303f3cd5eee73a5d3041b5ab2d8f.png

Binarizer()

二值化

设定一个阈值,大于阈值的赋值为1,小于等于阈值的赋值为0

d3210aa1ffe0a52345137f9b96e75769.png

OneHotEncoder()

向量化

对离散特征进行独热编码

测试结果如下:

  • 正则化和多项式转换降低了预测准确率

  • 区间缩放提高了准确率

  • 中心化因为会生成负数,所以无法在朴素贝叶斯中使用

  • 二值化和独热编码未改变准确率

c95f810bf14cab3eadfd8841f4767335.png

至此朴素贝叶斯算法的准确率最高为90%,接下来看看神经网络模型。

03

深度学习

Deep Learning, DL

下来老哥搭建一个最最简单的,只有一层的神经网络模型,相关介绍请参考人工智能 | 最简单的语言理解神经网络。TensorFlow将深度学习算法很好的封装进了Keras,该函数被工业界和学术界广泛使用,仅需20行代码即可搭建一个简单的神经网络。但是这种方法会失去对神经网络的深入理解。因此本案例中,老哥将纯手工实现神经网络所有的数学公式。

如果你能完整的从头到尾跟完本次教程,那么你已经对神经网络有了入门级的理解。老哥会尽可能详细的逐步讲解,那我们开始吧!

import tensorflow as tffrom matplotlib import pyplot as plt

首先导入tensorflow和matplotlib库完成公式搭建和绘图。

x_train = tf.cast(x_train, dtype=tf.float32)x_test = tf.cast(x_test, dtype=tf.float32)

转换x的数据类型,否则后面矩阵相乘时会因数据类型不一致报错。

train_db = tf.data.Dataset.from_tensor_slices((x_train, y_train)).batch(30)test_db = tf.data.Dataset.from_tensor_slices((x_test, y_test)).batch(30)

分别将测试集和训练集分批次(Batch),每一批次为32个数据。测试集有120个数据,所以测试集会被分为4批。这4批数据会分批次喂入神经网络结构。分Batch的好处是减少内存的损耗,增加迭代次数有助于实现参数的修正,提高收敛效果。Batch的选择可能影响最终的结果。

w1 = tf.Variable(tf.random.truncated_normal([4, 3], stddev=0.1, seed=1))b1 = tf.Variable(tf.random.truncated_normal([3], stddev=0.1, seed=1))

生成神经网络的参数,因为有4个输入特征,故输入层为4个输入节点;因为y为3分类,故输出层为3个神经元。用tf.Variable()标记参数可训练,只有标记的数据才会在梯度下降中反向传播。使用truncated_normal随机生成符合截断正态分布随机初始参数w和b。使用seed使每次生成的随机数相同(方便教学,使大家结果和老哥一致,可以不写seed)。打印生成的随机初始值w和b如下:

1a20cc70a4cdbfa08f6550a1f37682ae.png

现在老哥已经搭建出了如下图所示的神经网络结构了。

494edf2349968b72a7039671bc75f1c6.png
lr = 0.05 train_loss_results = [] test_acc = [] epoch = 500 loss_all = 0

接下来初始化梯度循环所需的参数。设定学习率lr为0.05;构造空列表train_loss_results,记录每轮的loss损失函数值,为后续画loss曲线提供数据;test_acc同理;循环500轮;因为分了Batch,数据集被划分为4批,因此会生成4个loss,用loss_all记录这4批生成的4个loss的和。

for epoch in range(epoch):     for step, (x_train, y_train) in enumerate(train_db):         with tf.GradientTape() as tape:             y = tf.matmul(x_train, w1) + b1             y = tf.nn.softmax(y)            y_ = tf.one_hot(y_train, depth=3)             loss = tf.reduce_mean(tf.square(y_ - y))            loss_all += loss.numpy()         grads = tape.gradient(loss, [w1, b1])        w1 = w1 - lr * w1_grad    b = b - lr * b_grad        w1.assign_sub(lr * grads[0])        b1.assign_sub(lr * grads[1])    print("Epoch {}, loss: {}".format(epoch, loss_all/4))    train_loss_results.append(loss_all / 4)     loss_all = 0

接下来这段代码用来构造梯度下降,是参数自更新的核心。最外层是数据集级别的循环,每个epoch循环一次数据集,一共循环500轮;第二层是batch级别的循环 ,每个step循环一个batch,一共循环4个batch。循环的内部则是用with结构记录梯度信息,整个神经网络的计算过程图如下:

1c80ef6c4157822aa250484429655ba6.png

接下来重点解释神经网络公式的实现。

首先实现公式的前半部分,w和b的乘加运算。tf.matmul()函数可以实现两个矩阵相乘,生成两个矩阵的乘积。

9b1693ca2396bd7e24551fc2aabb7732.png

为方便理解,我们将生成的y打印,可以看到我们生成了30行3列的y值,这就是根据上述公式计算出的结果:

cd2c592c0faed95e2aa6597ab22eba8d.png

接下来用tf.nn.softmax(y)函数使输出得y符合概率分布。运算结果如下所示,每一行的y值相加为1,体现了预测值中每个类别所占的比例。

2c0c0d92bea5391f99c1b05e7cd6b689.png

将标准答案y_train转化为独热编码,方便计算loss和accuracy。

6c76f32939b8f2e5aac2e8c2e5e8e827.png

根据均方误差公式,计算标准答案y_train与预测答案y之间的差距,即为loss值。均方误差公式如下,先对每个差距平方,然后求和,最后除以总个数。在代码中,先用tf.square()函数求解y与y_的差的平方,然后用tf.reduce_mean()求解均值。

c858bc13d1263e361f601d020d702044.png

loss值计算如下:

e129e2a63335ad50d729326f5ed9fd03.png

现在我们得到了每一个预测值与标准值之间的均方差,接下来通过梯度下降的方式,找到使loss值最小的w和b参数。梯度下降公式如下。我们先利用tape.gradient()函数计算每一个tape中的loss对各个参数的梯度(导数)。然后用assign_sub()函数实现w和b参数的自减,从而实现参数的自更新:w1 = w1 - lr * w1_grad    b = b - lr * b_grad。

36a2a5975958d2615c8bdc7c93099b79.png 9c60e986b354e1182c3c22efae3cfdb4.png

公式写完后,将将4个step的loss求平均记录在train_loss_results中,并将loss_all归零,为记录下一个epoch的loss做准备。

通过上述操作,我们已经纯手工写完了所有神经网络的计算公式。接下来,我们用测试集来测试该训练结果的准确度。

total_correct, total_number = 0, 0for x_test, y_test in test_db:    y = tf.matmul(x_test, w1) + b1    y = tf.nn.softmax(y)    pred = tf.argmax(y, axis=1)    pred = tf.cast(pred, dtype=y_test.dtype)    correct = tf.cast(tf.equal(pred, y_test), dtype=tf.int32)    correct = tf.reduce_sum(correct)    total_correct += int(correct)    total_number += x_test.shape[0]    acc = total_correct / total_number    test_acc.append(acc)    print("Test_acc:", acc)

total_correct为预测对的样本个数, total_number为测试的总样本数,将这两个变量都初始化为0。使用更新后的w,b参数对测试集进行预测。最开始两步的计算和softmax刚才已经解释过了。这样我们得到了预测结果y。tf.argmax()函数可以得到预测结果中得分最高的结果的索引值,而索引值等同于分类结果。预测的分类结果如下图所示:

aa97b3d2e60438b09112ef1e3505e290.png

将预测结果pred转换为y_test的数据类型。用tf.equal()函数判断预测值与标准答案是否一致,一致则输出True,不一致则为False。利用tf.cast()函数将布尔值转化为0,1的整数形式。因为分了batch,所以要将每一个batch的判断正确的数量相加,得到总的正确数量。则总的准确率等于total_correct / total_number。这样我们就可以得到预测准确率了。

至此,整个神经网络模型的代码就写完了。

plt.title('Loss Function Curve')  # 图片标题plt.xlabel('Epoch')  # x轴变量名称plt.ylabel('Loss')  # y轴变量名称plt.plot(train_loss_results, label="$Loss$")  # 逐点画出trian_loss_results值并连线,连线图标是Lossplt.legend()  # 画出曲线图标plt.show()  # 画出图像plt.title('Acc Curve')  # 图片标题plt.xlabel('Epoch')  # x轴变量名称plt.ylabel('Acc')  # y轴变量名称plt.plot(test_acc, label="$Accuracy$")  # 逐点画出test_acc值并连线,连线图标是Accuracyplt.legend()plt.show()

最后我们用折线图将损失函数和准确率绘制出来,进行可视化。如下所示,loss函数稳定减小,acc准确率稳步上升,最后达到了93.333%的准确率。

a2c882a65aede89291c42cfc89fccc48.png f3b53140c0e6d3cbf76be3ff0a0ffa11.png

调整学习率和迭代次数,将学习率改为0.04,迭代次数增加到1000,改进后准确率达到了96.66%。

a90d4cbe34f106641754c2c40035a338.png

综上所述,本次对比了机器学习与深度学习计算的整个过程,可以看出深度学习的准确率相对更高,但是耗时较长。如果数据量更大,深度学习的效果会更好。本次测评到此结束,完整代码回复6月24日即可获得。

- END -

关注老哥,一起充电!

4350147910c4289d07eecdbfbe7da5c9.gif

机房老哥

欢迎扫码关注!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值