本译文自Déborah Mesquita在https://medium.freecodecamp.org发表的Big Picture Machine Learning: Classifying Text with Neural Networks and TensorFlow ,文中版权、图像代码等数据均归作者所有。为了本土化,翻译内容略作修改。
开发人员常说,如果你想开始机器学习,你应该先学习算法是如何工作的。但是我的经验表明并不是这样子。
我说你应该首先能够看到大局:应用程序是如何工作的。一旦你了解了这一点,深入探索和研究算法的内部工作变得更加容易。
那么,你如何发展一种直觉,并对机器学习有一个全面的了解呢?一个好的方法是创建机器学习模型。
假设你还不知道如何从头开始创建所有这些算法,那么你就需要使用一个已经为你实现了所有这些算法的库。那个库就是TensorFlow。
在本文中,我们将创建一个机器学习模型来将文本分类。我们将介绍以下主题:
TensorFlow如何工作
什么是机器学习模型
什么是神经网络?
神经网络如何学习
如何处理数据并将其传递给神经网络输入
如何运行模型并获得预测结果
你可能会学到很多新东西,所以我们开始吧!
TensorFlow是一个开源的机器学习库,最初由Google创建。图书馆的名字帮助我们理解我们如何使用它:张量是多维数组,流过图的节点。
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
对象封装了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
)中。这些变量通过调用来维护图形中的状态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)
compute_gradients(损失,<变量列表>)
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,否则为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.graphics,sci.space和rec.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),加入专知主题人工智能群交流!
点击“阅读原文”,使用专知!