如果你一直关注数据科学或者机器学习等领域,你肯定不会错过深度学习和神经网络的热潮。许多组织都正在寻找深度学习人才,将深度学习运用于各个领域。从参与竞赛到运用于开源项目,并愿意为之付出高额的奖励,他们正尽一切可能挖掘这个目前十分有限的人才库为自己所用。
如果你对深度学习的前景感到兴奋,但是还没有开始你深度学习的旅程,这篇文章的目的就是扶你上马,再送你一程。
在这篇文章中,我将介绍TensorFlow。通过本文,你将理解神经网络的应用,并能够使用TensorFlow解决现实生活中的问题。本文需要你了解神经网络的基础知识并熟悉编程。尽管本文中的代码是用Python编写的,但我会把重心集中在概念上,并尽可能保持语言无关。
现在就让我们开始吧!
何时需要使用神经网络
近来,神经网络一直备受关注。有关神经网络和深度学习的更详细的解释, 请看这里。相比我们今天讨论的神经网络,更复杂,深奥的神经网络在图像识别,语音和自然语言处理等诸多领域 正在取得巨大的突破。
现在的主要问题变成了何时使用,而何时不使用神经网络。现在这个领域就像金矿,每天都有许多发现。想要参与到神经网络的“淘金热”,你必须记住以下几点:
神经网络是一种特殊的机器学习(ML)算法。因此,与每个机器学习算法一样,它遵循数据预处理,模型构建和模型评估等常规的机器学习工作流程。简明起见,我列出了一个如何处理神经网络问题的待办事项清单。
对于本文,我将重点关注图像数据。让我们先了解一些图像的知识,然后再研究TensorFlow。
图像大多可以视为一个三维数组,三个维度分别是指高度,宽度和颜色。比如说,如果你这会截取了你的电脑屏幕,截图会首先被转换为三维数组,然后被压缩为PNG或JPG文件格式。
虽然图像对于人类来说是相当容易理解的,但计算机很难理解它们。这种现象被称为语义鸿沟。我们的大脑可以通过观察图像,并在几秒钟内了解整个图像的意义。但是计算机只会将图像视为一组数字。所以问题是,我们使机器了解图像的意义?
在早期,人们试图把图像分解成“计算机可理解的”格式,好比各种模板。比如,人脸总是具有特定的结构,这个结构在每个人身上都有所体现,比如眼睛和鼻子的位置,或者我们脸的形状。但是这种方法比较单一,当要识别的对象的数量增加时,“模板”的方法就很难继续奏效。
时间来到2012年,深度神经网络架构赢得了那年的 ImageNet 挑战,ImageNet 是一种从自然场景中识别物体的知名比赛。并且,深度神经网络架构继续统治了此后进行的 ImageNet 挑战,证明了深度神经网络架构在解决图像问题方面的实际作用。
那么人们通常使用哪种库/编程语言来解决图像识别问题?一项最近的一项调查 发现,大多数流行的深度学习库都提供Python接口,其次第二多的是Lua,随后是Java和Matlab。而最流行的深度学习库,仅举几例:
我们已经了解了图像是如何储存的以及有哪些常用的图像处理库,现在让我们来看看TensorFlow提供了哪些功能。
我们从官方定义开始:
TensorFlow™ 是一个采用数据流图(data flow graphs),用于数值计算的开源软件库。节点(Nodes)在图中表示数学操作,图中的线(edges)则表示在节点间相互联系的多维数据数组,即张量(tensor)。它灵活的架构让你可以在多种平台上展开计算,例如台式计算机中的一个或多个CPU(或GPU),服务器,移动设备等等。
(官方中文定义)
如果对你来说,这些概念听上去就很可怕,也请不要担心。我会给TensorFlow一个简单的定义。TensorFlow不过是对numpy(一个广为使用的Python数学运算库)做了一些变形而已。如果你之前曾经有使用numpy的经历,那么了解TensorFlow的原理不过是小菜一碟!numpy和TensorFlow之间的主要区别在于,TensorFlow遵循一个惰性编程范例。它首先建立一张包含所有需要完成的操作的图( graph ),然后当调用某个“会话”(session),c程序会“运行”该图形(译者注:数据开始在图中流动)。通过将内部数据表示更改为张量(也就是多维数组),张量具有可扩展性。构建一个计算图可以被认为是TensorFlow的主要内容。要了解更多关于计算图的数学原理,请阅读 这篇文章。
TensorFlow一般被分类为神经网络库,但其并不仅限于神经网络。TensorFlow设计的初衷是建立一个强大的神经网络库,这没错。但它其实有能力做到更多。你可以在其上构建其他机器学习算法,如决策树或k最近邻算法。你完全可以在TensorFlow上做你通常会在numpy中做的一切!它被恰当地称为“强化numpy”。
使用TensorFlow的优点是:
每个库都有自己的“实现细节”,即按照其编程范式编写程序的一种方法。例如,在scikit-learn的实现中,首先创建所需算法的对象,然后在训练集上构建一个模型,使用训练的模型对测试集进行评估 - 例如:
# define hyperparamters of ML algorithm
clf = svm.SVC(gamma=0.001, C=100.)
# train
clf.fit(X, y)
# test
clf.predict(X_test)
正如我刚才所说,TensorFlow遵循一个惰性方法。在TensorFlow中运行程序的通常工作流程如下所示:
TensorFlow中用到的一些术语:
placeholder: A way to feed data into the graphs
# 一种数据输入的方式(原意为占位符,即在构建图时使用占位符,因为此时数据尚未输入)
feed_dict: A dictionary to pass numeric values to computational graph
# 相当于一个key-value key:placeholder value:data
接下来写一个输入两个数据的小程序
# import tensorflow
import tensorflow as tf
# build computational graph
a = tf.placeholder(tf.int16)
b = tf.placeholder(tf.int16)
addition = tf.add(a, b)
# initialize variables
init = tf.initialize_all_variables()
# create session and run the graph
with tf.Session() as sess:
sess.run(init)
print "Addition: %i" % sess.run(addition, feed_dict={a: 2, b: 3})
# close session
sess.close()
注意:我们可以使用不同的神经网络体系结构来解决这个问题,但是为了简单起见,我们基于深度多层前向感知器实现。
让我们首先回忆下我们通过这篇文章对神经网络的了解。
神经网络的典型实现如下:
在这里,我们通过一个手写数字识别的小例子来进行一次深度学习的实践。首先让我们看看我们的问题描述。
我们的问题是识别出所给的28x28图像中的数字。我们将一部分图像用于训练,剩下的则用于测试我们的模型。所以首先下载训练和测试文件。数据集包含一个数据集中所有图像的压缩文件,train.csv
和test.csv
包含相应训练和测试图像。数据集不提供任何附加功能,只是以“.png”的格式提供原始图像。
正如本文的主题,我们将使用TensorFlow来建立一个神经网络模型。所以你应该先在你的系统中安装TensorFlow。 根据你的系统情况,参阅 官方安装指南进行安装。
我们将按照上文的模板进行操作。用Python 2.7内核创建一个Jupyter notebook,步骤如下所示。
导入所有必需的模块:
%pylab inline
import os
import numpy as np
import pandas as pd
from scipy.misc import imread
from sklearn.metrics import accuracy_score
import tensorflow as tf
# To stop potential randomness
seed = 128
rng = np.random.RandomState(seed)
第一步是设置数据的目录路径
root_dir = os.path.abspath('../..')
data_dir = os.path.join(root_dir, 'data')
sub_dir = os.path.join(root_dir, 'sub')
# check for existence
os.path.exists(root_dir)
os.path.exists(data_dir)
os.path.exists(sub_dir)
读取我们的数据集。数据集的格式为CSV,并且具有对应标签的文件名:
train = pd.read_csv(os.path.join(data_dir, 'Train', 'train.csv'))
test = pd.read_csv(os.path.join(data_dir, 'Test.csv'))
sample_submission = pd.read_csv(os.path.join(data_dir, 'Sample_Submission.csv'))
train.head()
让我们看看我们的数据是什么样的!我们查看我们的图像并显示它。
img_name = rng.choice(train.filename)
filepath = os.path.join(data_dir, 'Train', 'Images', 'train', img_name)
img = imread(filepath, flatten=True)
pylab.imshow(img, cmap='gray')
pylab.axis('off')
pylab.show()
上图可以表示为numpy数组,如下所示“
为了使数据处理更简单,让我们将所有的图像存储为numpy数组:
temp = []
for img_name in train.filename:
image_path = os.path.join(data_dir, 'Train', 'Images', 'train', img_name)
img = imread(image_path, flatten=True)
img = img.astype('float32')
temp.append(img)
train_x = np.stack(temp)
temp = []
for img_name in test.filename:
image_path = os.path.join(data_dir, 'Train', 'Images', 'test', img_name)
img = imread(image_path, flatten=True)
img = img.astype('float32')
temp.append(img)
test_x = np.stack(temp)
#由于这是一个典型的ML问题,为了测试我们模型的正确功能,我们创建了一个验证集。我们以70:30的分组大小对比验证集:
split_size = int(train_x.shape[0]*0.7)
train_x, val_x = train_x[:split_size], train_x[split_size:]
train_y, val_y = train.label.values[:split_size], train.label.values[split_size:]
#现在定义一些之后会用到的帮助函数
def dense_to_one_hot(labels_dense, num_classes=10):
"""Convert class labels from scalars to one-hot vectors"""
num_labels = labels_dense.shape[0]
index_offset = np.arange(num_labels) * num_classes
labels_one_hot = np.zeros((num_labels, num_classes))
labels_one_hot.flat[index_offset + labels_dense.ravel()] = 1
return labels_one_hot
def preproc(unclean_batch_x):
"""Convert values to range 0-1"""
temp_batch = unclean_batch_x / unclean_batch_x.max()
return temp_batch
def batch_creator(batch_size, dataset_length, dataset_name):
"""Create batch with random samples and return appropriate format"""
batch_mask = rng.choice(dataset_length, batch_size)
batch_x = eval(dataset_name + '_x')[[batch_mask]].reshape(-1, input_num_units)
batch_x = preproc(batch_x)
if dataset_name == 'train':
batch_y = eval(dataset_name).ix[batch_mask, 'label'].values
batch_y = dense_to_one_hot(batch_y)
return batch_x, batch_y
现在来到了主要部分!我们会定义我们的神经网络架构。我们在这里定义了一个三层神经网络:输入层,隐藏层和输出层。输入层和输出层中神经单元的数量是固定的,因为输入是我们的28x28图像,输出是代表数字的10x1向量(0-9)。我们在隐藏层中设置500个神经元。这个数字可以根据你的需要而有所不同。我们再为剩下的变量赋值。阅读 文章以获得完整的代码,并深入了解它的工作原理。