前段时间,有个朋友和我提到,自己最近正打算用机器来判别图片中的场景是古镇还是园林,所以我这一期特地写了一篇文章,来描述图像的分类算法。由于最近工作略忙,所以文章断断续续写了好久,终于在自己生日前夕完成,希望可以有所帮助,这样我就可以安心回家吃蛋糕了。
用机器来做图片分类简单来讲就是给机器输入一张图片,机器会输出这幅图片里面的内容。机器学习中提供了很多对数据分类的算法,像KNN(最近邻)、Adaboost、Naive Bayes(朴素贝叶斯)、SVM(支持向量机)、ANN(人工神经网络)等以及最近几年兴起的CNN(卷积神经网络)。
在这篇文章的实作部分,我会挑出KNN、SVM、ANN来实现,使用的是使用经典的scikit-learn(sklearn)库,CNN则使用Keras来实现。
编程的环境需求:
系统:windows / linux
解释器:python 3.6
依赖库:numpy、opencv-python 3、tensorflow、keras、scikit-learn
数据集选择:
由于这几天无法穿越到苏州去采集大量园林和古镇的图片,而且本文还会去实验多分类的情况,但是既然同是图片的分类问题,我决定去网上搜集一些和风景相关的数据集。
突然有一天,在我逛GitHub的时候,它就这样出现了,
在我的世界里
带给我惊喜
情不自已
为此,我给作者写了一份信:
作者在我晚上吃饭的时候给了回复:
这。。。。。。。
看来这条路没走顺,不如去看看一些知名的数据集里有没有自己需要的东西吧,不过有承诺在先,我还是会标注上数据集作者的GitHub地址:(https://github.com/yuweiming70/Landscape-Dataset),毕竟他送了我这么多精美壁纸。
牛津大学的17 Category Flower Dataset
(http://www.robots.ox.ac.uk/~vgg/data/flowers/17/index.html)很漂亮,看起来就是我在寻找的数据集(没错,我判断一个东西是不是自己需要的标准就是漂不漂亮)。这个数据集总共17种花,每种花有80张图片,整个数据集有1360张图片,为了既达到实验的目的又不在训练上耗费太多的时间,我在同一种算法上选取了前两种花和前四种花做对比实验:
由于SVM和ANN的原理会占用太多的篇幅,并且这篇文章的主要目的是为了讲解代码实现,所以这里只介绍下机器学习中最简单的KNN分类器:
KNN是数据挖掘分类技术中最简单的方法之一,k最近邻,从名字大致就可以看出它的含义,就是找出K个离自己最近(相似)的数据,在这K个找到的数据中,看看那个类别最多,那么就认为自己是属于哪一个类别。
关于相似度度量的方法有很多,常见的有欧氏距离、曼哈顿距离、切比雪夫距离(切比雪夫兄跨界实在太多)、汉明距离、余弦相似度(夹角余弦值)等等。
KNN用到的是:欧氏距离(L2):
在数据(向量)只有二维的情况下,两个数据之间的欧氏距离就是两个点在二维坐标系下的直线距离,用初中一年级的数学公式就可以算出来:
当数据推广到多维的时候,两个数据之间的欧式距离就变成了:
距离越小表示两个向量相似度越大。
KNN有着实现方法简单、无需训练的优点,但是由于每次分类都要计算和所有数据之间的相似度,所以当数据维度很大或者数据数量很大的时候,计算会很耗时。
实验(KNN、SVM、ANN):
现在我要使用sklearn中的KNeighborsClassifier( KNN )、SVC( SVM )、MLPClassifier( 多层感知机分类器:ANN ),来实现这三个算法,由于sklearn中的算法模型高度统一化,所以三个程序可以写在同一个例子中,只是在创建分类器模型的时候略有不同:
引入KNeighborsClassifier、SVC、MLPClassifier模块:
引入训练样本分割函数:
引入numpy 和 opencv:
读取图像函数,返回图像列表和标签列表:
由于这三种分类器只接受一维向量的输入,所以将图片拍扁:
分割训练集和测试集(训练集:测试集 = 8 : 2):
图片数据归一化:
创建分类器模型:
训练:
计算准确率:
实验了几次,计算准确率平均值大致得到:
KNN: 73.8%
SVM: 78.5%
ANN: 78.9%
上面只是2分类的情况,现在取4种花来训练,得到准确率:
KNN: 40.1%
SVM: 40.6%
ANN: 41.5%
并且ANN在训练集上的正确率表现为100%, 很明显,已经过拟合,即模型已经呈现了记忆效应。
实验(CNN):
现在来试下卷积神经网络(由于上篇文章已经讲解过卷积神经网络的构建过程,这篇文章就不再赘述):
引入相关模块:
读取图像函数,返回图像列表和标签列表:
One-Hot编码:
分割训练集和测试集(训练集:测试集 = 8 : 2):
图片数据归一化:
构建CNN:
采用了VGG19结构的CNN:
深度很深,训练时间很长,特别耗内存和处理器(训练的时候记得在电脑下面垫冰块):
如果想要快速训练,也可以使用下面的简化模型,效果也还不错:
设置SGD优化器并编译模型:
训练,这里只训练30次:
看看这个模型在测试集上的表现:
准确率96.88%
再试下四种花的情况,在测试集上正确率为 70%,在训练集上正确率为 99.6%,虽然也过拟合,但是比三种经典分类器效果要好很多。
这种感觉就好像CNN把经典机器学习分类器的脸按在地上疯狂的摩擦,不放润滑油的那种。
不过反思一下,如果在进SVM、KNN、ANN之前,可以做一些特征提取,效果应该会更好一些。毕竟CNN训练和运行起来实在是太耗硬件了。
领取专属 10元无门槛券
私享最新 技术干货