scikit-learn - 初学者也能快速掌握的深度学习库



- 作者: SwiftCafe


提起人工智能和深度学习,算得上是这两年最热的话题,跟朋友交流的时候大家或多或少都有关注。作为一个开发者,如果你也像开发基于深度学习的应用而暂时不具备相关的基础只是的话,scikit-learn 就是非常适合你的敲门砖。

scikit-learn

scikit-learn 是基于 Python 环境的深度学习库,为我们封装了深度学习模型训练等一系列的功能, 我们只需要直接针对特定的问题给出训练数据,就可以实现自己的人工智能应用了。

scikit-learn 的项目主页: http://scikit-learn.org

在使用 scikit-learn 之前,最好对人工智能的基本概念有个大概的了解, 可以参考咱们之前的一个入门文章: 人工智能初体验

安装

安装 scikit-learn 之前, 你首先要安装 Python 环境, 可以到 https://www.python.org 下载安装包。 Python分为 2.x 和 3.x ,这两个版本的差异比较大, 2.x 兼容老代码好一些, 3.x 提供的特性优化比较多。 scikit-learn 同时支持 2.x 和 3.x 的 Python, 所以选择哪个版本就看你自己的喜好了。 我自己使用的是 2.x。

安装好 python 后, 还需要安装一些依赖组件, NumPy 和 SciPy, 可以通过 pip 命令来安装:

1
pip install --user numpy scipy

依赖库安装好后, 再通过 pip 命令来安装 scikit-learn:

1
pip install -U scikit-learn

到这里,准备工作就完成了。 这里再多说一句, 为什么很多深度学习库都使用 Python 呢,我查询到的信息是这样,Python 对于大规模的数值计算支持的比较好, 并且语言特性使用起来也比较简单。

开始前行

准备工作做好了,咱们就开始进行下面的旅程吧。 首先咱们要选择一个要解决的问题, 人工智能领域有很多经典的问题集,以后有时间可以和大家更多的探讨。
这里帮大家选择一个经典的 “20 Newsgroups” 问题。

听起来很高大上, 其实这个问题就是对新闻做归类。 它把所有的新闻分为 20 个类别,并且通过深度学习,可以将任何一个新闻内容归到这 20 个类别中的一个。

选择这个问题,一个是它相对简单,并且它还有一定的实用性。 比如对于信息流类型的 APP,我们可以使用它来做推荐系统, 邮箱系统可以通过同样的原理来清理垃圾邮件。

“20 Newsgroups” 问题的完整描述大家可以参看这里 http://qwone.com/~jason/20Newsgroups

它将新闻定义为 20 个类别如下:

比如 sci.space 代表关于科技类的太空探索相关, talk.politics 表示政治类话题等等。

准备数据集

在开始之前, 我们先要准备训练数据集。庆幸的是,scikit-learn 已经为我们预制了这些经典的数据集,那么就可以开始写代码了:

1
2
3
4
from sklearn.datasets import fetch_20newsgroups
categories = ['alt.atheism', 'soc.religion.christian','comp.graphics', 'sci.med']
twenty_train = fetch_20newsgroups(subset='train', categories=categories, shuffle=True, random_state=42)

即便你从来没接触过 Python 也没关系,咱们一行一行的讲解。

首先 from sklearn.datasets import fetch_20newsgroups 相当于一个 import 导入。从 sklearn.datasets 这个库中导入 fetch_20newsgroups 模块。

因为 fetch_20newsgroups 的原始数据集比较大,我们这个示例中不用加载全部的数据。 所以我们定义了一个数组 categories = ['alt.atheism', 'soc.religion.christian','comp.graphics', 'sci.med'] 说明了我们要加载的数据类别。

最后调用 fetch_20newsgroups 方法获取最终的数据集。

如果数据读取成功的话,可以通过这个语句会输出数据集的数量:

1
2
print(len(twenty_train.data))
// 输出: 2257

我们这里使用的是 Supervised learning 也叫作受控的学习。 这种深度学习算法是预先将正确的原始数据和结果预期输入到我们的模型中, 然后我们的模型通过这些训练数据不断调整自己的内部结构,再以后遇到新的数据的时候,就能通过以前的这些经验得出最接近的结果了。

我们可以通过 print 语句看看原始数据中都包含了什么:

1
print(twenty_train.data[0])

会输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
From: sd345@city.ac.uk (Michael Collier)
Subject: Converting images to HP LaserJet III?
Nntp-Posting-Host: hampton
Organization: The City University
Lines: 14
Does anyone know of a good way (standard PC application/PD utility) to
convert tif/img/tga files into LaserJet III format. We would also like to
do the same, converting to HPGL (HP plotter) files.
Please email any response.
Is this the correct group?
Thanks in advance. Michael.
--
Michael Collier (Programmer) The Computer Unit,
Email: M.P.Collier@uk.ac.city The City University,
Tel: 071 477-8000 x3769 London,
Fax: 071 477-8565 EC1V 0HB.

结合我们前面通过 print(len(twenty_train.data)) 得到的信息, 整个数据集包含了 2257 个这样的文档。 我们需要用这 2257 条数据来训练我们的模型, 让它变得智能起来。

那么具体怎么做呢? 对于 “20 Newsgroups” 使用的方法是先要将文本信息进行数字化。也就是将每个单词在这篇文章中的出现频次构建成一个数组, 比如我们上面这篇文章进行转换后就是类似这样的形式:

1
2
3
4
5
[
{"email" : 2},
{"tel" : 1},
....
]

这样统计了每个单词在这篇文章中的出现次数。 但直接将单词内容放到数据中比较占用空间,因为深度学习的模型数据都是超大规模的,所以我们需要尽可能的减少数据的空间占用。每个单词应该以数字的方式存放的模型中,并且通过一个映射表来对应:

1
2
map = ["email", "tel", ...]
data = [2,1, ...]

data 数组的第一个元素对应 “email” 的出现次数, 第二个元素对应 tel 的出现次数,等等。 data 的数据规模下降了一个维度。

我们需要将这个数据集的 2257 篇文章都转换成这样的数据集。 假设英文单词的数量有 10万个左右, 那么我们对于每篇文章都要存放这样一个10万条记录的数组。 这样的数据规模还是很大。

但大家可能很容易想到,不是每篇文章都会包含所有的单词, 一般情况是这 10 万个单词中只有一小部分会被包含在一篇文章中。 这就是一个典型的稀疏矩阵。大多数元素的计数都是 0。 对于这样的矩阵 scikit-learn 也提供了相应的处理方法。

咱们上面说的一大段流程,将文本信息映射到字符计数表,以及优化稀疏矩阵等, scikit-learn 都已经帮我们封装好了,这一系列的细节不需要我们来处理, 来看看代码吧:

1
2
3
4
5
from sklearn.feature_extraction.text import CountVectorizer
count_vect = CountVectorizer()
X_train_counts = count_vect.fit_transform(twenty_train.data)
print(X_train_counts.shape)
// 输出: (2257, 35788)

首先我们导入了 CountVectorizer。 用于将我们的文本信息进行我们前面说的一系列转换。 调用它的 fit_transform 方法并传入我们的数据集就完成了。 是不是很简单?

最后用 print 语句输出 X_train_counts 的维度, 包含了 2257 个条目, 每个条目包含了 35788 的字符计数。

这样我们就得到了每篇文章中的字符计数信息。可以根据文章中各个单词出现的频度来训练我们的模型将文章进行分类。

但还有一个问题,一篇较长的文章相应的单词计数肯定会比一篇比较短的文章要多。所以我们用字符计数的绝对值作为模型还不够准确。 可以将单词的绝对计数转换为这个单词在文章中出现的比例。

同样,scikit-learn 依然给我们提供了方便的封装:

1
2
3
from sklearn.feature_extraction.text import TfidfTransformer
tf_transformer = TfidfTransformer(use_idf=False).fit(X_train_counts)
X_train_tf = tf_transformer.transform(X_train_counts)

TfidfTransformer 这个类可以将我们的数据集进行这样的转换。 关于 TfidfTransformer 的原理我们这里不过多介绍,可以参看 tf-idf 的相关文档 https://en.wikipedia.org/wiki/Tf%E2%80%93idf

训练数据模型

基本的数据集我们准备好了,深度学习就是要用我们这些数据集来训练我们的模型,让它变得智能:

1
2
from sklearn.naive_bayes import MultinomialNB
>>> clf = MultinomialNB().fit(X_train_tfidf, twenty_train.target)

MultinomialNB 是我们的训练模型,通过 fit 方法传入我们刚刚处理过的数据 X_train_tfidf 以及每条记录对应的期望结果 twenty_train.target

通常这个操作会执行几秒钟,当训练完成后, 我们的模型就有了对任意文章的归类判断能力了。 当然归类的准确度跟我们训练数据的程度有关。

我们可以这样来进行一个实际验证:

1
2
3
4
5
6
7
8
9
10
11
docs_new = ['God is love', 'OpenGL on the GPU is fast']
X_new_counts = count_vect.transform(docs_new)
X_new_tfidf = tfidf_transformer.transform(X_new_counts)
predicted = clf.predict(X_new_tfidf)
for doc, category in zip(docs_new, predicted):
print('%r => %s' % (doc, twenty_train.target_names[category]))
// 输出: 'God is love' => soc.religion.christian
// 输出: 'OpenGL on the GPU is fast' => comp.graphics

我们这里定义了一个 docs_new, 里面放了两条记录,每条记录都是一段话。 同样也需要将它们转换成单词计数的数组格式,然后调用 cls.predict 来对这两段话进行分析。

从我们输出的结果来看,我们训练后的模型已经有了初步的分析能力了, 比如正确的将 ‘God is love’ 归类为宗教类, ‘OpenGL on the GPU is fast’ 归类为计算机图形学。

是不是很有意思? 通过 sklearn 我们只需要设计好我们的数据模型, 并利用好 sklearn 为我们封装的处理类, 即可实现我们自己的深度学习应用了。 如果感兴趣的话,可以自己试试运行这个例子,并输入任意的内容,看看这个模型是否能正确的归类呢。

结尾

深度学习这两年的发展非常迅猛,早已脱离了理论层面了。 随着 scikit-learn 这样的第三方库的出现,相信它的开发难度和成本会变得越来越低。当然,如果要开发一个实际的应用,肯定还是要比我们这个例子复杂很多。但 scikit-learn 这些库可以让你不用去过多处理深度学习底层逻辑,更专注于模型的设计。人工智能未来的应用相信会越来越多。

如果你觉得这篇文章有帮助,还可以关注微信公众号 swift-cafe,会有更多我的原创内容分享给你~

本站文章均为原创内容,如需转载请注明出处,谢谢。




微信公众平台
更多精彩内容,请关注微信公众号


公众号:swift-cafe
邮件订阅
请输入您的邮箱,我们会把最新的内容推送给您: