机器学习的大局:用神经网络和TensorFlow分类文本

本译文自Déborah Mesquita在https://medium.freecodecamp.org发表的Big Picture Machine Learning: Classifying Text with Neural Networks and TensorFlow ,文中版权、图像代码等数据均归作者所有。为了本土化,翻译内容略作修改。

开发人员常说,如果你想开始机器学习,你应该先学习算法是如何工作的。但是我的经验表明并不是这样子。

我说你应该首先能够看到大局:应用程序是如何工作的。一旦你了解了这一点,深入探索和研究算法的内部工作变得更加容易。

那么,你如何发展一种直觉,并对机器学习有一个全面的了解呢?一个好的方法是创建机器学习模型

假设你还不知道如何从头开始创建所有这些算法,那么你就需要使用一个已经为你实现了所有这些算法的库。那个库就是TensorFlow

在本文中,我们将创建一个机器学习模型来将文本分类。我们将介绍以下主题:

  1. TensorFlow如何工作

  2. 什么是机器学习模型

  3. 什么是神经网络?

  4. 神经网络如何学习

  5. 如何处理数据并将其传递给神经网络输入

  6. 如何运行模型并获得预测结果

你可能会学到很多新东西,所以我们开始吧!

TensorFlow

TensorFlow是一个开源的机器学习库,最初由Google创建。图书馆的名字帮助我们理解我们如何使用它:张量是多维数组,流过图的节点。

tf.Graph

TensorFlow中的每个计算都被表示为一个数据流图。这个图有两个元素:

  • 一组tf.Operation代表计算单位

  • 一组tf.Tensor代表数据的单位

要看到所有这些工作,你将创建这个数据流图:

                                                                        一个计算x + y的图

你会定义x = [1,3,6]y = [1,1,1]。如图所示tf.Tensor,您可以创建常量张量:

import tensorflow as tf
x = tf.constant([1,3,6])
y = tf.constant([1,1,1]

现在您将定义操作单元:

import tensorflow as tf
x = tf.constant([1,3,6])
y = tf.constant([1,1,1])
op = tf.add(x,y)

你有所有的图形元素。现在你需要建立图表:

import tensorflow as tf
my_graph = tf.Graph()with my_graph.as_default():
     x = tf.constant([1,3,6])
    y = tf.constant([1,1,1])
    op = tf.add(x,y)

这就是TensorFlow工作流程的工作原理:您首先创建一个图表,然后才能进行计算(真正“运行”具有操作的图形节点)。要运行图形,你需要创建一个tf.Session

tf.Session

一个tf.Session对象封装了Operation执行对象的环境,并对Tensor对象进行了评估(来自文档)。为此,我们需要定义在会话中使用哪个图表:

import tensorflow as tf
my_graph = tf.Graph()
用tf.Session(graph = my_graph)作为sess:
    x = tf.constant([1,3,6])
    y = tf.constant([1,1,1])
    op = tf.add(x,y)

要执行操作,您将使用该方法tf.Session.run()。该方法执行TensorFlow计算的一个“步骤”,通过运行必要的图片段来执行每个Operation对象并评估每个Tensor传入的参数fetches。在你的情况下,你将运行总和操作的一个步骤:

import tensorflow as tf
my_graph = tf.Graph()
用tf.Session(graph = my_graph)作为sess:
    x = tf.constant([1,3,6])
    y = tf.constant([1,1,1])
    op = tf.add(x,y)
    result = sess.run(fetches = op)    print(result)>>> [2 4 7]

预测模型

现在您已经知道TensorFlow是如何工作的,您必须学习如何创建一个预测模型。简而言之,

机器学习算法 + 数据 = 预测模型

构建模型的过程如下所示:

                                                                              创建预测模型的过程

正如您所看到的,该模型由一个机器学习算法“训练”数据组成。当你有这个模型时,你会得到这样的结果:

                                                                                预测工作流程

您要创建的模型的目标是按类别对文本进行分类,我们定义:

输入:文本,结果:类别

我们有一个包含所有文本的训练数据集(每个文本都有一个标签,表明它属于哪个类别)。在机器学习中,这种类型的任务被命名为监督学习

“我们知道正确的答案。该算法迭代地对训练数据进行预测,并由教师纠正。“ -  Jason Brownlee

你会把数据分类到不同的类别,所以它也是一个分类任务。

为了创建模型,我们将使用神经网络。

神经网络

神经网络是一种计算模型(一种用数学语言和数学概念来描述系统的方法)。这些系统是自学和训练的,而不是明确的编程。

神经网络受到我们中枢神经系统的启发。他们连接了与我们的神经元相似的节点。

                                                                            一个神经网络

感知器是第一个神经网络算法。这篇文章很好地解释了一个感知器的内部工作(“人造神经元内部”动画很棒)。

为了理解神经网络是如何工作的,我们实际上将用TensorFlow建立一个神经网络体系结构。在这个例子中,这个架构被Aymeric Damien使用。

神经网络架构

神经网络将有2个隐藏层(你必须选择网络将有多少隐藏层,是架构设计的一部分)。每个隐藏层的工作是将输入转换成输出层可以使用的东西。

隐藏图层1

                                                                       输入层和第一个隐藏层

你还需要定义第一个隐藏层有多少个节点。这些节点也被称为特征或神经元,在上面的图像中,它们由每个圆圈表示。

在输入层中,每个节点都对应于数据集中的一个单词(我们将在稍后看到它是如何工作的)。

如所解释这里,每个节点(神经元)被乘以权重。每个节点都有一个权重值,在训练阶段,神经网络调整这些值以产生正确的输出(等待,我们将在一分钟内了解更多)。

除了将每个输入节点乘以权重之外,网络还增加了一个偏差(神经网络中的偏差作用)。

在通过权重乘以输入并将这些值与偏差相加后,在您的体系结构中,数据也通过激活函数传递。这个激活函数定义了每个节点的最终输出。比喻:假设每个节点都是一个灯,激活功能告诉灯是否点亮。

有许多类型的激活功能。您将使用整流线性单元(ReLu)。这个函数是这样定义的:

f(x) = max(0,x) 输出是x或0(零),以较大者为准

例如:如果x = -1,f(x)= 0________________________(零); 如果x = 0.7,则________________________f(x)= 0.7

隐藏的图层2

第二个隐藏层确实是第一个隐藏层所做的,但是现在第二个隐藏层的输入是第一个隐藏层的输出。

                                                                           第一和第二隐藏层

输出层

我们终于到了最后一层,即输出层。您将使用单热编码来获取此图层的结果。在这个编码中,只有一位的值是1,其他的都是零值。例如,如果我们想编码三个类别(运动,空间和计算机图形):

+-------------------+-----------+|    category       |   value   |+-------------------|-----------+|      sports       |    001    ||      space        |    010    || computer graphics |    100    ||-------------------|-----------|

所以输出节点的数量就是输入数据集的类数。

输出层的值也乘以权重,我们也加上偏差,但现在激活函数是不同的。

你想用一个类别来标记每个文本,而这些类别是相互排斥的(一个文本不能同时属于两个类别)。考虑到这一点,而不是使用ReLu激活功能,您将使用Softmax功能。该函数将每个单位的输出转换为0和1之间的值,并确保所有单位的总和等于1.这样,输出将告诉我们每个类别的每个文本的概率。

| 1.2 0.46 | | 0.9  - > [softmax]  - > 0.34 | | 0.4 0.20 |

现在你有神经网络的数据流图。将我们目前看到的所有内容翻译成代码,结果是:

# Network Parameters
n_hidden_1 = 10        # 第一层的功能
n_hidden_2 = 5         # 第二层的功能
n_input = total_words  # 词汇中的单词
n_classes = 3          # 分类:图形,空间和棒球
def multilayer_perceptron(input_tensor, weights, biases):
    layer_1_multiplication = tf.matmul(input_tensor, weights['h1'])
    layer_1_addition = tf.add(layer_1_multiplication, biases['b1'])
    layer_1_activation = tf.nn.relu(layer_1_addition)#RELU激活的隐藏层
    layer_2_multiplication = tf.matmul(layer_1_activation, weights['h2'])
    layer_2_addition = tf.add(layer_2_multiplication, biases['b2'])
    layer_2_activation = tf.nn.relu(layer_2_addition)#线性激活的输出层
    out_layer_multiplication = tf.matmul(layer_2_activation, weights['out'])
    out_layer_addition = out_layer_multiplication + biases['out']return out_layer_addition

(稍后我们将讨论输出层激活函数的代码。)

神经网络如何学习

正如我们前面看到的那样,在训练网络的同时更新了权重值。现在我们将在TensorFlow环境中看到这是如何发生的。

tf.Variable

权重和偏差存储在变量(tf.Variable)中。这些变量通过调用来维护图形中的状态run()。在机器学习中,我们通常通过正态分布开始权重和偏差值。

weights = {
    'h1': tf.Variable(tf.random_normal([n_input, n_hidden_1])),
    'h2': tf.Variable(tf.random_normal([n_hidden_1, n_hidden_2])),
    'out': tf.Variable(tf.random_normal([n_hidden_2, n_classes]))}biases = {
    'b1': tf.Variable(tf.random_normal([n_hidden_1])),
    'b2': tf.Variable(tf.random_normal([n_hidden_2])),
    'out': tf.Variable(tf.random_normal([n_classes]))}

当我们第一次运行网络时(也就是说,权值是正态分布定义的):

input values: x
weights: w
bias: b
output values: z
expected values: expected

要知道网络是否正在学习,您需要将输出值(z)与期望值(预期)进行比较。我们如何计算这种差异(损失)?有很多方法可以做到这一点。因为我们正在处理分类任务,所以损失的最好方法就是交叉熵误差。

詹姆斯·D·麦卡弗里(James D. McCaffrey)写了一篇关于为什么这是这种任务最好的方法的精彩解释。

使用TensorFlow,您将使用tf.nn.softmax_cross_entropy_with_logits()方法(这里是softmax激活函数)计算交叉熵误差并计算平均误差(tf.reduce_mean())。

#构建模型
prediction = multilayer_perceptron(input_tensor, weights, biases)#定义损失
entropy_loss = tf.nn.softmax_cross_entropy_with_logits(logits=prediction, labels=output_tensor)loss = tf.reduce_mean(entropy_loss)

你想找到权重和偏差的最佳值,以最大限度地减少输出误差(我们得到的价值和正确的价值之间的差异)。要做到这一点,你将使用渐变下降法。更具体地说,你将使用随机梯度下降。

                  梯度下降。来源:https//sebastianraschka.com/faq/docs/closed-form-vs-gd.html

还有很多算法来计算梯度下降,你将使用自适应矩估计(亚当)。要在TensorFlow中使用此算法,您需要传递learning_rate值,该值确定值的增量步骤以找到最佳权重值。

该方法是一个语法糖做两件事情:tf.train.AdamOptimizer(learning_rate).minimize(loss)

  1. compute_gradients(损失,<变量列表>)

  2. apply_gradients(<变量列表>)

该方法更新所有的tf.Variables新值,所以我们不需要传递变量列表。现在你有了训练网络的代码:

learning_rate = 0.001#构建模型
prediction = multilayer_perceptron(input_tensor, weights, biases)#定义损失
entropy_loss = tf.nn.softmax_cross_entropy_with_logits(logits=prediction, labels=output_tensor)loss = tf.reduce_mean(entropy_loss)optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(loss)

数据操作

您将使用的数据集有许多英文文本,我们需要操纵这些数据将其传递到神经网络。要做到这一点,你会做两件事情:

  1. 为每个单词创建一个索引

  2. 为每个文本创建一个矩阵,如果文本中有一个单词,则值为1,否则为0

让我们看看代码来理解这个过程:

import numpy as np    #numpy 是一个从集合导入计算器的科学计算包from collections import Counter
vocab = Counter()text = "Hi from Brazil"#获取所有单词for word in text.split(' '):
    vocab[word]+=1
        #将单词转换为索引
def get_word_2_index(vocab):
    word2index = {}
    for i,word in enumerate(vocab):
        word2index[word] = i        
    return word2index
#Now we have an index
word2index = get_word_2_index(vocab)total_words = len(vocab)#This is how we create a numpy array (our matrix)matrix = np.zeros((total_words),dtype=float)#Now we fill the valuesfor word in text.split():
    matrix[word2index[word]] += 1print(matrix)>>> [ 1.  1.  1.]

在上面的例子中,文字是“Hi from Brazil”,矩阵是1.1.1。如果文本只是“Hi”呢?

matrix = np.zeros((total_words),dtype=float)text = "Hi"for word in text.split():
    matrix[word2index[word.lower()]] += 1print(matrix)>>> [ 1.  0.  0.]

您将与标签(文本的类别)相同,但是现在您将使用单一编码:

y = np.zeros((3),dtype=float)if category == 0:
    y[0] = 1.        # [ 1.  0.  0.]elif category == 1:
    y[1] = 1.        # [ 0.  1.  0.]else:
     y[2] = 1.       # [ 0.  0.  1.]

运行图形并获得结果

现在是最好的部分:从模型中获得结果。首先让我们仔细看看输入数据集。

数据集

您将使用20个新闻组,这是一个包含20个主题的18.000个帖子的数据集。加载这个数据集,你将使用scikit学习库。我们将只使用3个类别:comp.graphicssci.spacerec.sport.baseball。scikit学习有两个子集:一个用于训练,一个用于测试。建议您不要看测试数据,因为这会在创建模型时影响您的选择。你不想创建一个模型来预测这个特定的测试数据,你想创建一个具有良好泛化的模型。

这是你将如何加载数据集:

from sklearn.datasets import fetch_20newsgroups
categories = ["comp.graphics","sci.space","rec.sport.baseball"]newsgroups_train = fetch_20newsgroups(subset='train', categories=categories)newsgroups_test = fetch_20newsgroups(subset='test', categories=categories)

培训模型

在神经网络术语中,所有训练样例中的一个历元=一个正向传递(获得输出值)和一个反向传递(更新权重)。

记住这个tf.Session.run()方法吗?让我们仔细看看它:

tf.Session.run(fetches, feed_dict=None, options=None, run_metadata=None)

在本文开头的数据流图中,您使用了sum操作,但是我们也可以传递一个事件列表来运行。在这个神经网络运行中,您将通过两件事情:损失计算和优化步骤。

feed_dict参数是我们传递数据每次运行一步。为了传递这些数据,我们需要定义tf.placeholders(提供feed_dict)。

正如TensorFlow文档所述:

“占位符的存在完全是为了作为Feed的目标。它没有被初始化,也没有数据。“ -  来源

所以你会这样定义你的占位符:

“如果使用占位符来提供输入,则可以通过使用tf.placeholder(...,shape = [ None,...])创建占位符来指定变量批量维度__。形状的None元素对应于可变尺寸的维度。“ -  来源

在测试模型时,我们会用更大的批量来填充字典,这就是为什么您需要定义一个变量批量维度的原因。

get_batches()功能为我们提供了批量大小的文本数量。现在我们可以运行模型:

training_epochs = 10# 启动图表with tf.Session() as sess:
    sess.run(init) #inits the variables (normal distribution, remember?)
    # Training cycle    for epoch in range(training_epochs):
        avg_cost = 0.
        total_batch = int(len(newsgroups_train.data)/batch_size)
        # Loop over all batches        for i in range(total_batch):
            batch_x,batch_y = get_batch(newsgroups_train,i,batch_size)
            # Run optimization op (backprop) and cost op (to get loss value)
            c,_ = sess.run([loss,optimizer], feed_dict={input_tensor: batch_x, output_tensor:batch_y})

现在你已经训练了模型。为了测试它,你还需要创建图形元素。我们将测量模型的准确性,所以您需要得到预测值的索引和正确值的索引(因为我们使用的是单热编码),检查它们是否相等,并计算均值所有的测试数据集:

    # 测试模型
    index_prediction = tf.argmax(prediction, 1)
    index_correct = tf.argmax(output_tensor, 1)
    correct_prediction = tf.equal(index_prediction, index_correct)
    # 计算准确性
    accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
    total_test_data = len(newsgroups_test.target)
    batch_x_test,batch_y_test = get_batch(newsgroups_test,0,total_test_data)
    print("Accuracy:", accuracy.eval({input_tensor: batch_x_test, output_tensor: batch_y_test}))>>> Epoch: 0001 loss= 1133.908114347
    Epoch: 0002 loss= 329.093700409
    Epoch: 0003 loss= 111.876660109
    Epoch: 0004 loss= 72.552971845
    Epoch: 0005 loss= 16.673050320
    Epoch: 0006 loss= 16.481995190
    Epoch: 0007 loss= 4.848220565
    Epoch: 0008 loss= 0.759822878
    Epoch: 0009 loss= 0.000000000
    Epoch: 0010 loss= 0.079848485
    Optimization Finished!
    Accuracy: 0.75

而就是这样!您使用神经网络创建了一个模型来将文本分类。恭喜!

您可以在这里看到带有最终代码 的笔记本。

提示:修改我们定义的值以查看更改如何影响训练时间和模型精度。

原文链接:https://medium.freecodecamp.org/big-picture-machine-learning-classifying-text-with-neural-networks-and-tensorflow-d94036ac2274

原文作者:Déborah Mesquita




-END-

专 · 知

人工智能领域主题知识资料查看获取【专知荟萃】人工智能领域26个主题知识资料全集(入门/进阶/论文/综述/视频/专家等)

同时欢迎各位用户进行专知投稿,详情请点击

诚邀】专知诚挚邀请各位专业者加入AI创作者计划了解使用专知!

请PC登录www.zhuanzhi.ai或者点击阅读原文,注册登录专知,获取更多AI知识资料

请扫一扫如下二维码关注我们的公众号,获取人工智能的专业知识!

请加专知小助手微信(Rancho_Fang),加入专知主题人工智能群交流!

点击“阅读原文”,使用专知

展开全文
Top
微信扫码咨询专知VIP会员