如何使用TensorFlow实现神经网络

时间:2022-04-26
本文章向大家介绍如何使用TensorFlow实现神经网络,主要内容包括如何使用神经网络解决问题、了解图像数据和当下流行的图像处理库、什么是TensorFlow?、典型的TensorFlow“张量流图"、在TensorFlow中实现神经网络、基本概念、基础应用、原理机制和需要注意的事项等,并结合实例形式分析了其使用技巧,希望通过本文能帮助到大家理解应用这部分内容。

如果你一直关注数据科学或者机器学习等领域,你肯定不会错过深度学习和神经网络的热潮。许多组织都正在寻找深度学习人才,将深度学习运用于各个领域。从参与竞赛到运用于开源项目,并愿意为之付出高额的奖励,他们正尽一切可能挖掘这个目前十分有限的人才库为自己所用。

如果你对深度学习的前景感到兴奋,但是还没有开始你深度学习的旅程,这篇文章的目的就是扶你上马,再送你一程。

在这篇文章中,我将介绍TensorFlow。通过本文,你将理解神经网络的应用,并能够使用TensorFlow解决现实生活中的问题。本文需要你了解神经网络的基础知识并熟悉编程。尽管本文中的代码是用Python编写的,但我会把重心集中在概念上,并尽可能保持语言无关。

现在就让我们开始吧!

何时需要使用神经网络

近来,神经网络一直备受关注。有关神经网络和深度学习的更详细的解释, 请看这里。相比我们今天讨论的神经网络,更复杂,深奥的神经网络在图像识别,语音和自然语言处理等诸多领域 正在取得巨大的突破。

现在的主要问题变成了何时使用,而何时不使用神经网络。现在这个领域就像金矿,每天都有许多发现。想要参与到神经网络的“淘金热”,你必须记住以下几点:

  • 首先,神经网络需要清晰的,具有信息量的数据(主要是大数据)来训练。尝试将神经网络想象成一个孩子。他首先观察父母如何走路。然后试图独立行走,并且每走一步,孩子都会学习如何在特定情况下保持平衡。他可能会摔上几跤,但经过几次不成功的尝试,他最终会学会走路。如果你不让他走,他可能永远学不会如何走路。小孩尝试的次数越多,学习走路的效果就越好。
  • 神经网络适合应用于图像处理等复杂问题。神经网络属于表征学习算法的范畴。这些算法将复杂问题分解为更简单的形式,以使它们对于计算机变得可理解(或者说“可表示为计算机能处理的问题”)。好比先咀嚼食物,然后再咽下去。这对于传统(非表征学习)算法来说是很难做到的。
  • 使用适当类型的神经网络来解决问题。 每个问题都有自己的难点。数据决定了你解决问题的方式。例如,如果问题是序列生成型的,那么递归神经网络是解决这个问题的合适方法,而如果它是一个图像相关的问题,转而采取卷积神经网络可能更合适
  • 最后, 硬件性能对于运行深度神经网络模型是至关重要的。 神经网络很早以前就被“发现”了,但近些年来,主要是因为计算性能日益强大,才使神经网络开始大放异彩。如果你想运用神经网络解决现实生活中的问题,准备购买一些高端硬件吧!

如何使用神经网络解决问题

神经网络是一种特殊的机器学习(ML)算法。因此,与每个机器学习算法一样,它遵循数据预处理,模型构建和模型评估等常规的机器学习工作流程。简明起见,我列出了一个如何处理神经网络问题的待办事项清单。

  • 检查神经网络是否可以提升传统算法(请参考上部分提到的几点)。
  • 调查何种神经网络架构最适合解决当前的问题。
  • 根据你使用语言和函数库来定义神经网络架构。
  • 将数据转换为正确的格式,并将数据分批。
  • 根据你的需要预处理数据。
  • 通过增加数据量增加模型的规模,训练出更好的模型。
  • 将数据分批输入神经网络。
  • 训练并监测训练集和验证集的区别。
  • 测试你的模型,并保存以备将来使用。

对于本文,我将重点关注图像数据。让我们先了解一些图像的知识,然后再研究TensorFlow。

了解图像数据和当下流行的图像处理库

图像大多可以视为一个三维数组,三个维度分别是指高度,宽度和颜色。比如说,如果你这会截取了你的电脑屏幕,截图会首先被转换为三维数组,然后被压缩为PNG或JPG文件格式。

虽然图像对于人类来说是相当容易理解的,但计算机很难理解它们。这种现象被称为语义鸿沟。我们的大脑可以通过观察图像,并在几秒钟内了解整个图像的意义。但是计算机只会将图像视为一组数字。所以问题是,我们使机器了解图像的意义?

在早期,人们试图把图像分解成“计算机可理解的”格式,好比各种模板。比如,人脸总是具有特定的结构,这个结构在每个人身上都有所体现,比如眼睛和鼻子的位置,或者我们脸的形状。但是这种方法比较单一,当要识别的对象的数量增加时,“模板”的方法就很难继续奏效。

时间来到2012年,深度神经网络架构赢得了那年的 ImageNet 挑战,ImageNet 是一种从自然场景中识别物体的知名比赛。并且,深度神经网络架构继续统治了此后进行的 ImageNet 挑战,证明了深度神经网络架构在解决图像问题方面的实际作用。

那么人们通常使用哪种库/编程语言来解决图像识别问题?一项最近的一项调查 发现,大多数流行的深度学习库都提供Python接口,其次第二多的是Lua,随后是Java和Matlab。而最流行的深度学习库,仅举几例:

我们已经了解了图像是如何储存的以及有哪些常用的图像处理库,现在让我们来看看TensorFlow提供了哪些功能。

什么是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的优点是:

  • 它有一个直观的结构, 顾名思义,TensorFlow有一个“张量流图”。 你可以很容易地看到图的每一个部分。
  • 可以方便地在CPU / GPU上通过分布式计算训练模型
  • 平台灵活性。你可以在任何平台上运行模型,无论是移动设备,服务器还是PC。

典型的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支持的数学操作。
  • 初始化变量 以编译先前定义的变量
  • 创建会话 (Session) 这是魔法开始的地方!
  • 在会话中运行图形, 经过编译的图形传递给会话,开始执行会话。
  • 关闭会话 关闭会话。

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()

在TensorFlow中实现神经网络

注意:我们可以使用不同的神经网络体系结构来解决这个问题,但是为了简单起见,我们基于深度多层前向感知器实现。

让我们首先回忆下我们通过这篇文章对神经网络的了解。

神经网络的典型实现如下:

  • 确定要使用神经网络体系结构
  • 将数据传输到模型
  • 在模型中,数据首先被分批以便可以被分批提取。首先对数据进行预处理,然后将其分批加入神经网络进行训练。
  • 然后模型被逐渐训练成型。
  • 显示特定步长下的准确度。
  • 训练结束后保存模型以供将来使用。
  • 在新数据上测试模型并观察其执行情况。

在这里,我们通过一个手写数字识别的小例子来进行一次深度学习的实践。首先让我们看看我们的问题描述。

我们的问题是识别出所给的28x28图像中的数字。我们将一部分图像用于训练,剩下的则用于测试我们的模型。所以首先下载训练和测试文件。数据集包含一个数据集中所有图像的压缩文件,train.csvtest.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个神经元。这个数字可以根据你的需要而有所不同。我们再为剩下的变量赋值。阅读 文章以获得完整的代码,并深入了解它的工作原理