深度学习系列 Part (1)
传统机器学习的回顾
近年来,深度学习的概念十分火热,人工智能也由于这一技术的兴起,在近几年吸引了越来越多的关注。我们这里,将结合一些基本的用例,简要的介绍一下这一新的技术。
我们首先需要明确人工智能、机器学习以及深度学习三者之间的关系。如NVIDIA官网所述,人工智能是一个非常大的概念,而机器学习只是人工智能的一种实现方法。深度学习是同样也是一种实现机器学习的方法,是在机器学习的基础上建立起来的。这体现在,首先从字面上看,二者都是在“学习”,因此在评价深度学习训练出的模型好坏时,同样直接来源于机器学习的评价方法。其次,深度学习最常见的形式,深度神经网络,直接脱胎于机器学习中的神经网络模型。
因此,本文主要将从评价方法以及模型实现这两个方面,基于传统机器学习的概念,谈一谈深度学习。
1. 机器学习的评价方法
我们首先讲一下评价方法问题。为了让本文看起来更加有趣,我们不妨把“机器”理解为“学生”。我们知道,学生有所谓的“好学生”,通常我们搞应试教育,学习成绩好的是“好学生”,不好的就不是“好学生”,但现在流行素质教育,从素质教育的角度看,可能有的学生学习成绩中等,但是团结同学、体育优秀、能歌善舞,这样也算是好学生。
这就涉及到了不同评价标准的问题——应试教育和素质教育。机器学习同样有这两种评价方式,应试教育、唯分数论的监督学习,和素质教育、综合考量并不明确打分的非监督学习。注意这里有一个误区,即可能现在认为素质教育优于应试教育,近期大牛们也一再强调非监督算法的重要意义。但实际上如果拿到一个学习任务,具体使用哪一种方式去分析,还是需要考虑应用场景。通常我们不了解这个学习任务的目的性、需要找线索时,会用非监督找线索,方法包括聚类、降维。而如果明确了学习的目的性,追求高准确率,这时候就需要使用监督学习的方法。
具体举一个鸢尾花分类的例子。我们使用 费雪鸢尾花卉数据集(Fisher's Iris data set),它最初是埃德加·安德森从加拿大加斯帕半岛上的鸢尾属花朵中提取的地理变异数据,包含了150个样本,都属于鸢尾属下的三个亚属,分别是山鸢尾(0)、变色鸢尾(1)和维吉尼亚鸢尾(2)。四个特征被用作样本的定量分析,它们分别是花萼(Sepal)和花瓣(Petal)的长度和宽度:
Sepal Length | Sepal Width | Petal Length | Petal Width | Species |
---|---|---|---|---|
5.1 | 3.5 | 1.4 | 0.2 | 0 |
4.9 | 3.0 | 1.4 | 0.2 | 0 |
4.7 | 3.2 | 1.3 | 0.2 | 0 |
... | ... | ... | ... | ... |
7.0 | 3.2 | 4.7 | 1.4 | 1 |
6.4 | 3.2 | 4.5 | 1.5 | 1 |
6.9 | 3.1 | 4.9 | 1.5 | 1 |
... | ... | ... | ... | ... |
6.5 | 3.0 | 5.2 | 2.0 | 2 |
6.2 | 3.4 | 5.4 | 2.3 | 2 |
5.9 | 3.0 | 5.1 | 1.8 | 2 |
于是,我们就想,是否可以用鸢尾花数据集里面包含的四个特征,去预测花的种类?如果要这么做,我们首先应该明确不同种类的鸢尾花,这四个特征是否真的有区别(非监督学习),如果确实有所区别,我们就可以在此基础上,用这几个特征去追求高的分类准确性(监督学习)。下面部分我们逐个执行这些步骤。
1.1 使用数据可视化、降维、聚类等非监督方法,探索数据特征
首先展示不同种类鸢尾花四个数据两两组合的情况,如下:
import matplotlib.pyplot as plt
from sklearn import datasets
import seaborn as sns
%matplotlib inline
data = datasets.load_iris()
X = data.data
color = data.target
sns.set_style("white")
# compatibility matplotlib < 1.0
df = sns.load_dataset("iris")
sns.pairplot(df, hue="species")
这些特征的两两组合,起来确实和花的种类有关。但实际上我们总共有四个维度,这里只能看见两个,我们能否将四个维度换成两个维度、展示在一个平面上呢?这里使用了多种非监督的降维方法,尝试去从非监督的角度,展示不同种类之间的区别:
import matplotlib.pyplot as plt
from sklearn import datasets
import seaborn as sns
%matplotlib inline
data = datasets.load_iris()
X = data.data
color = data.target
sns.set_style("white")
from sklearn import decomposition
from sklearn import manifold
from matplotlib.ticker import NullFormatter
from time import time
n_components = 2
n_neighbors = 10
data = datasets.load_iris()
X = data.data
color = data.target
fig = plt.figure(figsize=(15, 4))
t0 = time()
Y = manifold.Isomap(n_neighbors, n_components).fit_transform(X)
t1 = time()
print("Isomap: %.2g sec" % (t1 - t0))
ax = fig.add_subplot(151)
plt.scatter(Y[:, 0], Y[:, 1], c=color, cmap=plt.cm.Set1)
plt.title("Isomap (%.2g sec)" % (t1 - t0))
ax.xaxis.set_major_formatter(NullFormatter())
ax.yaxis.set_major_formatter(NullFormatter())
plt.axis('tight')
t0 = time()
mds = manifold.MDS(n_components, max_iter=100, n_init=1)
Y = mds.fit_transform(X)
t1 = time()
print("MDS: %.2g sec" % (t1 - t0))
ax = fig.add_subplot(152)
plt.scatter(Y[:, 0], Y[:, 1], c=color, cmap=plt.cm.Set1)
plt.title("MDS (%.2g sec)" % (t1 - t0))
ax.xaxis.set_major_formatter(NullFormatter())
ax.yaxis.set_major_formatter(NullFormatter())
plt.axis('tight')
t0 = time()
se = manifold.SpectralEmbedding(n_components=n_components,
n_neighbors=n_neighbors)
Y = se.fit_transform(X)
t1 = time()
print("SpectralEmbedding: %.2g sec" % (t1 - t0))
ax = fig.add_subplot(153)
plt.scatter(Y[:, 0], Y[:, 1], c=color, cmap=plt.cm.Set1)
plt.title("SpectralEmbedding (%.2g sec)" % (t1 - t0))
ax.xaxis.set_major_formatter(NullFormatter())
ax.yaxis.set_major_formatter(NullFormatter())
plt.axis('tight')
t0 = time()
pca = decomposition.PCA(n_components=n_components)
pca.fit(X)
Y = pca.transform(X)
t1 = time()
print("PCA: %.2g sec" % (t1 - t0))
ax = fig.add_subplot(154)
plt.scatter(Y[:, 0], Y[:, 1], c=color, cmap=plt.cm.Set1)
plt.title("PCA (%.2g sec)" % (t1 - t0))
ax.xaxis.set_major_formatter(NullFormatter())
ax.yaxis.set_major_formatter(NullFormatter())
plt.axis('tight')
t0 = time()
tsne = manifold.TSNE(n_components=n_components, init='pca', random_state=0, perplexity=40)
Y = tsne.fit_transform(X)
t1 = time()
print("t-SNE: %.2g sec" % (t1 - t0))
ax = fig.add_subplot(155)
plt.scatter(Y[:, 0], Y[:, 1], c=color, cmap=plt.cm.Set1)
plt.title("t-SNE (%.2g sec)" % (t1 - t0))
ax.xaxis.set_major_formatter(NullFormatter())
ax.yaxis.set_major_formatter(NullFormatter())
plt.axis('tight')
plt.show()
我们可以看到基于花萼(Sepal)和花瓣(Petal)的长度和宽度特征,可以通过非监督的数学方法,在降维后,将三种鸢尾花分开。由此,我们明确了学习的目的性(根据花萼和花瓣的长度和宽度特征,对三种鸢尾花分类)。其中第一类和其他两类可以很好区分,而第二类、第三类之间区分度并不好,这也是一个潜在的问题。
1.2 基于特征的监督模型预测
明确目的之后,我们就可以采用监督学习的方法,使用模型进行分类。监督学习有很多模型,包括深度学习中的神经网络模型。监督学习的基础,是我们已知一部分数据以及其对应的结果,对这些已知结果的数据进行建模,使模型预测的结果和已知的结果越接近越好。这种接近的程度用损失函数来表示,进而通过最小化这个损失函数,得到最优模型。
经典的机器学习方法,可以基于高斯过程:
也可以使用基于核方法的支持向量机:
更可以通过决策树的集成:
同时也可以使用 Tensorflow ,建立一个包含三个隐藏层深度神经网络。以下例子来自 Tensorflow 官网:
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import os
import urllib
import tensorflow as tf
import numpy as np
IRIS_TRAINING = "iris_training.csv"
IRIS_TEST = "iris_test.csv"
# 下载数据
for infile in [IRIS_TRAINING, IRIS_TEST]:
if not os.path.exists(infile):
raw = urllib.urlopen("http://download.tensorflow.org/data/%s" % IRIS_TRAINING_URL).read()
with open(infile,'w') as f:
f.write(raw)
training_set = tf.contrib.learn.datasets.base.load_csv_with_header(
filename=IRIS_TRAINING,
target_dtype=np.int,
features_dtype=np.float32)
test_set = tf.contrib.learn.datasets.base.load_csv_with_header(
filename=IRIS_TEST,
target_dtype=np.int,
features_dtype=np.float32)
# 使用花萼花瓣的长宽作为输入特征
feature_columns = [tf.contrib.layers.real_valued_column("", dimension=4)]
# 建立一个三层的神经网络,每层分别包含 10个、 20个、 10个隐藏单元。
classifier = tf.contrib.learn.DNNClassifier(feature_columns=feature_columns,
hidden_units=[10, 20, 10],
n_classes=3,
model_dir="/tmp/iris_model")
# 训练数据转化成 Tensorflow 格式
def get_train_inputs():
x = tf.constant(training_set.data)
y = tf.constant(training_set.target)
return x, y
# 训练模型
classifier.fit(input_fn=get_train_inputs, steps=2000)
# 测试数据转换成 Tensorflow 格式
def get_test_inputs():
x = tf.constant(test_set.data)
y = tf.constant(test_set.target)
return x, y
# 评价准确率
accuracy_score = classifier.evaluate(input_fn=get_test_inputs,
steps=1)["accuracy"]
print("\nTest Accuracy: {0:f}\n".format(accuracy_score))
最终这个简单的深度神经网络模型,会实现一个 96% 的分类准确率。
1.3 结果的评价指标以及潜在问题
注意这里最优模型拼准确率时,有一个很大的问题,就是数据分布不平均时,单纯的使用错误率作为标准,会有很大的问题。比如某一种罕见疾病的发病率是万分之一(0.01%) ,这时候如果一个模型什么都不管,直接认为这个人没有病,也能拿到一个 99.99%正确的模型。如何正确衡量这个问题?如果是经典的二分类问题,这种情况下我们需要综合考虑 灵敏度以及 假阳性率,用这两个指标计算ROC 曲线,继而计算 ROC 围成的面积——AUC 值 (详见这里)。 这种情况下,我们可以认为,AUC 值越高越好。
注意这里AUC 越高越好和最小化损失函数这两个概念,这里意味着,可能某个模型,损失函数已经最小化了,但是AUC 却并不高,造成模型在实际使用时,会引入很多错误——一个较低的 AUC 值,可能会在追求高灵敏度时引入了大量的假阳性,正如古话所言,“宁可错杀一万,不可放过一个”,后果就是可能医生通知了十位患者有患癌风险,最终可能只有一位真有问题,其他九人虚惊一场。这种情况,模型并未被很好的训练,可能存在着 欠拟合 的问题。同时,也可能损失函数最小化以后,测试数据 AUC 也很高,但是实际运用在真实案例中,却又有大量的错误,这种情况被称作 过拟合。
那么如何避免这两种问题呢?前面提到,监督学习如同“应试教育”,所以机器学习过程为了避免这两种常见问题,也使用了一种类似“题海战术”的策略,即老师手里有一堆题目,不会全都给学生,会分成三个部分,一部分作为 训练集(平时作业),一部分作为验证集(平时考试),最后还有 测试集(中考高考)。训练集有数据也有答案,验证集同样有数据有答案,但和平时课堂测试一样,答案是考完试才给看的。而用到测试集时,才会最终评价模型的优劣,如同学生平时作业得分第一,但高考没有考第一,那他也不是状元。
为了避免平时作业写得好、高考失误这种悲剧,合理的运用平时考试抓差补缺就十分必要。机器学习的过程中,这一条同样成立,具体而言,如果一个学生,作业全对,但是平时考试成绩不好,这种情况用机器学习术语就是 过拟合 了,可能的原因是,机器学习过程中使用了过多的参数去迎合数据,片面追求平时学习过程的准确率,造成知其然不知其所以然的结果,在实际运用过程中表现很差。还有种情况可能更加常见,就是一个学生,写作业错一堆,考试也一堆错,这种情况,就是 欠拟合,可能是学习不够、方法不对,需要更多的特征、更优化的模型。
2. 提高深度学习模型预测的准确性
回到鸢尾花的例子,我们写的最简单的深度学习模型,达到了 96% 的准确性。那么问题来了,如果我们追求的是 100%,如何提高模型的表现?
调整模型的参数,无疑是最简单最快速的方法,但调参并不能从根本上解决分类准确性的问题。如果是数据 欠拟合,则通常需要更多的特征、更优化的模型。
我们首先说 更多的特征,比如我们这里只用了四个特征,花瓣、花萼的长度和宽度。而植物分类学家使用的特征,可能就会包括诸如 “根部是否肥大呈纺锤形”、“外花被裂片附属物有无或附属物是须毛状还是鸡冠状”、“rbcL基因序列和3个限制性位点的比对” 这种更加专业的特征,这些特征可能只有专业人士才能得出结论,甚至需要借助专业的仪器、花费数天时间。
但实际上,植物分类,并不一定要按照植物分类学课本的定义进行,可能普通人看一眼也可以分的差不多。比如我们的三种鸢尾花,我们看起来确实是第一类和第二三类不同,然后二三类之间区别相对更小,但其形状、颜色、纹路等确实有所区别:
因此对于鸢尾花数据集,各种模型可能都并不足以达到100% 准确分类,其背后深层次的原因是,这个数据集可能并没有很好的表征花瓣的形状、颜色、纹路等特征。原因也很简单,数据收集者很难准确用几个数字描述出花瓣的形状,特别是形状极为相似的情况。同时,描述出深紫色、浅紫色的区别也十分困难。于是有一个想法,就是我们能不能直接给出图片,让计算机帮忙标注这些特征,用更多的特征,增加模型准确性?
想让计算机帮忙挖掘、标注这些更多的特征,这就离不开 更优化的模型 了。事实上,这几年深度学习领域的新进展,就是以这个想法为基础产生的。我们可以使用更复杂的深度学习网络,在图片中挖出数以百万计的特征。在这些数以百万计的特征中,可能就包括了我们想到的形状、纹路、颜色等信息,更多的则是我们也无法理解、描述的东西。如下图,使用 Alexnet 深度学习架构,后面的全连接部分(Fully Connection Part)与本节 1.2 部分相同,都是三层隐藏层,但是前面却接了一个卷积部分(Convolutionary Part),用来在图像中提取各种特征。
我们将在接下来的章节中,详细介绍如何通过深度学习技术,在图像中挖出更多的特征,达到一个更高的分类正确性。
深度学习系列 Part (1)的更多相关文章
- 【深度学习系列3】 Mariana CNN并行框架与图像识别
[深度学习系列3] Mariana CNN并行框架与图像识别 本文是腾讯深度学习系列文章的第三篇,聚焦于腾讯深度学习平台Mariana中深度卷积神经网络Deep CNNs的多GPU模型并行和数据并行框 ...
- 【深度学习系列2】Mariana DNN多GPU数据并行框架
[深度学习系列2]Mariana DNN多GPU数据并行框架 本文是腾讯深度学习系列文章的第二篇,聚焦于腾讯深度学习平台Mariana中深度神经网络DNN的多GPU数据并行框架. 深度神经网络( ...
- 深度学习系列 Part(3)
这是<GPU学习深度学习>系列文章的第三篇,主要是接着上一讲提到的如何自己构建深度神经网络框架中的功能模块,进一步详细介绍 Tensorflow 中 Keras 工具包提供的几种深度神经网 ...
- 【深度学习系列】关于PaddlePaddle的一些避“坑”技巧
最近除了工作以外,业余在参加Paddle的AI比赛,在用Paddle训练的过程中遇到了一些问题,并找到了解决方法,跟大家分享一下: PaddlePaddle的Anaconda的兼容问题 之前我是在服务 ...
- 【深度学习系列】PaddlePaddle垃圾邮件处理实战(二)
PaddlePaddle垃圾邮件处理实战(二) 前文回顾 在上篇文章中我们讲了如何用支持向量机对垃圾邮件进行分类,auc为73.3%,本篇讲继续讲如何用PaddlePaddle实现邮件分类,将深度 ...
- 基于TensorFlow的深度学习系列教程 2——常量Constant
前面介绍过了Tensorflow的基本概念,比如如何使用tensorboard查看计算图.本篇则着重介绍和整理下Constant相关的内容. 基于TensorFlow的深度学习系列教程 1--Hell ...
- 使用腾讯云 GPU 学习深度学习系列之二:Tensorflow 简明原理【转】
转自:https://www.qcloud.com/community/article/598765?fromSource=gwzcw.117333.117333.117333 这是<使用腾讯云 ...
- 【深度学习系列】PaddlePaddle之手写数字识别
上周在搜索关于深度学习分布式运行方式的资料时,无意间搜到了paddlepaddle,发现这个框架的分布式训练方案做的还挺不错的,想跟大家分享一下.不过呢,这块内容太复杂了,所以就简单的介绍一下padd ...
- 深度学习系列 Part (2)
1. 神经网络原理 神经网络模型,是上一章节提到的典型的监督学习问题,即我们有一组输入以及对应的目标输出,求最优模型.通过最优模型,当我们有新的输入时,可以得到一个近似真实的预测输出. 我们先看一下如 ...
- 【深度学习系列】一起来参加百度 PaddlePaddle AI 大赛吧!
写这个系列写了两个月了,对paddlepaddle的使用和越来越熟悉,不过一直没找到合适的应用场景.最近百度搞了个AI大赛,据说有四个赛题,现在是第一个----综艺节目精彩片段预测 ,大家可以去检测一 ...
随机推荐
- 我的Spring学习记录(二)
本篇就简单的说一下Bean的装配和AOP 本篇的项目是在上一篇我的Spring学习记录(一) 中项目的基础上进行开发的 1. 使用setter方法和构造方法装配Bean 1.1 前期准备 使用sett ...
- Python初识2
27.Python中没有{}括起来的代码块,使用pass来代替c语言中的{(无内容)}: 28.使用__name__来指示模块是如何加载的,如果是被导入的,那么__name__就是该模块的名字,如果是 ...
- 【Java】关于Java8 parallelStream并发安全的思考
背景 Java8的stream接口极大地减少了for循环写法的复杂性,stream提供了map/reduce/collect等一系列聚合接口,还支持并发操作:parallelStream. 在爬虫开发 ...
- 使用http -server 搭建本地简易文件服务器
安装 npm install http-server -g 使用 1. cd project . 2. hs [pwd] -o, 默认是当前路径 ./ 3. 其他选项 -p Port to use ( ...
- 打印ASCII码
总时间限制:1000ms内存限制:65536kB 描述 输入一个除空格以外的可见字符(保证在函数scanf中可使用格式说明符%c读入),输出其ASCII码. 输入 一个除空格以外的可见字符. 输出 一 ...
- 记一次Linux下JavaWeb环境的搭建
今天重装了腾讯云VPS的系统,那么几乎所有运行环境都要重新部署了.过程不难懂,但是也比较繁琐,这次就写下来,方便他人也方便自己日后参考参考. 我采用的是JDK+Tomcat的形式来进行JavaWeb初 ...
- bzoj1051(明星奶牛)
这道就是明星奶牛,A了一次又一次了,(⊙o⊙)-(⊙o⊙)- 去年pas就打了不下5次,就是强联通缩点,然后求出度为0的块 判断有多个的话就无解,一个就输出块的大小. #include<cstd ...
- S2_SQL_第二章
第二章:初始mySql 2.1:mySql简介 2.1.2:mysql的优势 运行速度块,体积小,命令执行的块 使用成本低,开源的 容易使用 可移植性强 2.2:mysql的配置 2.2.1:端口配置 ...
- Monit : 开源监控工具介绍
· Monit 简介 Monit是一个轻量级(500KB)跨平台的用来监控Unix/linux系统的开源工具.部署简单,并且不依赖任何第三方程序.插件或者库. Monit可以监控服务器进程.文件.文件 ...
- [js高手之路] html5 canvas动画教程 - 匀速运动
匀速运动:指的是物体在一条直线上运动,并且物体在任何相等时间间隔内通过的位移都是相等的.其实就是匀速直线运动,它的特点是加速度为0,从定义可知,在任何相等的时间间隔内,速度大小和方向是相同的. < ...