当前位置: 首页 > 科技观察

MachineLearningIllustrated-TextClassificationwithNeuralNetworksandTensorFlow

时间:2023-03-12 18:58:36 科技观察

开发人员经常说,如果你想开始机器学习,你应该先学习算法。但不是我的经验。我说你首先应该明白:应用程序是如何工作的。一旦理解了这一点,深入研究算法的内部工作原理就会变得容易得多。那么,你如何发展直觉学习并实现理解机器学习的目标呢?做到这一点的一个好方法是创建机器学习模型。假设您仍然不知道如何从头开始创建所有这些算法,您可以使用一个已经为您实现了所有这些算法的库。该库是TensorFlow。在本文中,我们将创建一个机器学习模型来对文本进行分类。我们将涵盖以下主题:TensorFlow的工作原理什么是机器学习模型什么是神经网络神经网络如何学习如何操纵数据并将其传递给神经网络如何运行模型并获得预测让我们开始吧!TensorFlowTensorFlow是一个用于机器学习的开源库,由Google率先推出。库的名称有助于我们理解如何使用它:张量是流经图形节点的多维数组。TensorFlow中tf.Graph的每次计算都表示为数据流图。这个图有两种元素:一种是tf.Operation,代表计算单元;一种是tf.Tensor,代表数据单元,看看它们是如何工作的。您需要创建此数据流图:(计算x+y的图)您需要定义x=[1,3,6]和y=[1,1,1]。由于该图使用tf.Tensor来表示数据单元,因此您需要创建常量张量:importtensorflowastfx=tf.constant([1,3,6])y=tf.constant([1,1,1])现在您将定义操作单元:importtensorflowastfx=tf.constant([1,3,6])y=tf.constant([1,1,1])op=tf.add(x,y)并且您拥有所有图形元素。现在你需要构建图表:importtensorflowastfmy_graph=tf.Graph()withmy_graph.as_default():x=tf.constant([1,3,6])y=tf.constant([1,1,1])op=tf.add(x,y)这就是TensorFlow工作流的工作方式:您首先创建一个图,然后您可以计算(实际上“运行”具有操作的图节点)。您需要创建一个tf.Session来运行图形。tf.Sessiontf.Session对象封装了Operation对象的执行环境。计算张量对象(来自文档)。为此,我们需要定义Session中将使用哪个图:importtensorflowastfmy_graph=tf.Graph()withtf.Session(graph=my_graph)assess:x=tf.constant([1,3,6])y=tf.constant([1,1,1])op=tf.add(x,y)为了执行操作,你需要使用方法tf.Session.run()。此方法通过运行必要的图段来执行每个Operation对象并通过参数获取计算每个Tensor的值来执行TensorFlow计算的“步骤”:importtensorflowastfmy_graph=tf.Graph()withtf.Session(graph=my_graph)评估:x=tf.constant([1,3,6])y=tf.constant([1,1,1])op=tf.add(x,y)result=sess.run(fetches=op)print(result)>>>[247]predictivemodel既然你知道TensorFlow是如何工作的,你需要知道如何创建预测模型。简而言之机器学习算法+数据=预测模型构建模型的过程是这样的:(Theprocessofbuildingapredictivemodel)如你所见,模型由在数据上“训练”的机器学习算法组成。当你有一个模型时,你会得到这样的结果:(预测工作流)你创建的模型的目的是对文本进行分类,我们定义:输入:文本,结果:类别我们有一个使用已经标记的文本(每个文本都有它属于哪个类别的标签)训练数据集。在机器学习中,这种类型的任务被称为监督学习。“我们知道正确答案。算法迭代地预测训练数据并被老师纠正”—JasonBrownlee你会把数据分成类,所以它也是一个分类任务。要创建此模型,我们将使用神经网络。神经网络神经网络是一种计算模型(一种使用机器语言和数学概念描述系统的方式)。这些系统自主学习和训练,而不是明确编程。神经网络也受到我们中枢神经系统的启发。它们连接的节点类似于我们的神经元。感知器是第一个神经网络算法。这篇文章很好地解释了感知器的内部工作原理(“人工神经元内部”的动画很棒)。为了解神经网络的工作原理,我们将使用TensorFlow构建神经网络架构。在此示例中,此体系结构由AymericDamien使用。神经网络架构一个神经网络有两个隐藏层(你必须选择网络有多少个隐藏层作为架构设计的一部分)。每个隐藏层的工作是将输入转换为输出层可用的东西。对于隐藏层1(输入层和第一个隐藏层),您还需要定义第一个隐藏层将有多少个节点。这些节点也称为特征或神经元,在上面的示例中,我们使用每个圆圈来表示一个节点。输入层的每个节点对应于数据集中的一个单词(稍后我们将看到它是如何工作的)如此处所述,每个节点(神经元)乘以一个权重。每个节点都有一个权重值,在训练阶段,神经网络会调整这些值以产生正确的输出(稍后我们将详细了解这一点)除了在没有输入的情况下乘以权重外,网络还添加错误(错误在神经网络中的作用)。在您的架构中,输入乘以权重,然后将值添加到偏差中,偏差也通过激活函数传递。这个激活函数定义了每个节点的最终输出。例如:假设每个节点都是一盏灯,激活函数决定灯是否会亮。激活函数有很多种。您将使用整流线性单元(ReLu)。此函数定义如下:f(x)=max(0,x)[输出x或0的最佳数(零)]例如:如果x=-1,则f(x)=0(零);如果x=0.7,则f(x)=0.7。隐藏层2第二个隐藏层与第一个隐藏层完全相同,但现在第二层的输入是第一层的输出。(***和第二个隐藏层)输出层现在终于到了***层,输出层。您将使用One-Hot编码来获取该层的结果。在这种编码中,只有一位的值为1,其他位的值为0。例如,如果我们要对三个类别(运动,太空和计算机图形)进行编码:那么输出节点的编号就是编号输入数据集的类别。输出层的值也乘以权重,我们也加上误差,只是现在激活函数不一样了。你想给每个文本都打上类别标签,这些类别是相互独立的(一个文本不能同时属于两个类别)。考虑到这一点,您将使用Softmax函数而不是ReLu激活函数。此函数将每个完整输出转换为0到1之间的值,并确保所有单元格的总和等于1。这样,输出将告诉我们每个类别中每个文本的概率。|1.20.46||0.9->[softmax]->0.34||0.40.20|现在有了神经网络的数据流图。把我们所看到的都转换为代码,结果是:#NetworkParametersn_hidden_??1=10#1stlayernumberoffeaturesn_hidden_??2=5#2ndlayernumberoffeaturesn_input=total_words#Wordsinvocabn_classes=3#Categories:graphics,spaceandbaseballdefmultilayer_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)#HiddenlayerwithRELUactivationlayer_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)#Outputlayerwithlinearactivationout_layer_multiplication=tf.matmul(layer_2_activation,weights['out'])out_layer_addition=out_layer_multiplication+out']returnout_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]))}当我们第一次运行神经网络时(即权重值由正态分布定义):inputvalues:xweights:wbias:boutputvalues:zexpectedvalues:expected为了知道网络是否在学习,你需要比较输出值(Z)和期望值(expected)。我们如何计算这种差异(损失)?有很多方法可以解决这个问题。由于我们正在做分类任务,因此衡量损失的唯一方法是交叉熵误差。JamesD.McCaffrey写了一篇精彩的解释,解释了为什么这是完成此类任务的最佳方法。使用TensorFlow,您将使用tf.nn.softmax_cross_entropy_with_logits()方法计算交叉熵误差(这是softmax激活函数)并计算平均误差(tf.reduced_mean())。#Constructmodelprediction=multilayer_perceptron(input_tensor,weights,biases)#Definelossentropy_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)为了计算梯度下降,将使用自适应矩估计(Adam)。要在TensorFlow中使用该算法,需要传递learning_rate值,该值决定了该值寻找最优权重值的增量步长。tf.train.AdamOptimizer(learning_rate).minimize(loss)方法是一个语法糖,它做了两件事:tf.Variables所以我们不需要传递变量列表。现在你有了训练网络的代码:learning_rate=0.001#Constructmodelprediction=multilayer_perceptron(input_tensor,weights,biases)#Definelossentropy_loss=tf.nn.softmax_cross_entropy_with_logits(logits=prediction,labels=output_tensor)loss=tf.reduceim_mean=lossroizer(ent)tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(loss)数据运算要用到的数据集有很多英文文本,我们需要对数据进行运算,传递给神经网络。为此,你需要做两件事:为每个工作创建一个索引为每个文本创建一个矩阵,在矩阵中,如果该词在文本中则值为1,否则值为0让我们看一下代码理解这个过程:importnumpyasnp#numpyisapackageforscientificcomputingfromcollectionsimportCountervocab=Counter()text="HifromBrazil"#Getallwordsforwordintext.split(''):vocab[word]+=1#Convertwordstoindexesdefget_word_2_index(vocab):word2index={}fori,wordinenumerate:word2vocab[index]word]=ireturnword2index#Nowwehaveanindexword2index=get_word_2_index(vocab)total_words=len(vocab)#Thisishowwecreateanumpyarray(ourmatrix)matrix=np.zeros((total_words),dtype=float)#Nowwefillthevaluesforwordintext.split():矩阵[word2index[word]]+=1print(matrix)>>>[1.1.1.]在上面的例子中,文本是'HifromBrazil',矩阵是[1.1.1.]。如果文本只是'Hi'怎么办?matrix=np.zeros((total_words),dtype=float)text="Hi"forwordintext.split():matrix[word2index[word.lower()]]+=1print(matrix)>>>[1.0.0.]将与标签(文本分类)相同,但现在使用单热编码:y=np.zeros((3),dtype=float)ifcategory==0:y[0]=1.#[1.0.0.]elifcategory==1:y[1]=1.#[0.1.0.]else:y[2]=1.#[0.0.1.]正在运行图和得到结果现在是激动人心的部分:从模型中得到结果。让我们先仔细看看输入数据集。数据集对于包含20个主题的18.000个帖子的数据集,将使用20个新闻组。要加载这些数据集,将使用scikit-learn库。我们只使用3个类:comp.graphics、sci.space和rec.sport.baseball。scikit-learn有两个子集:一个用于训练,一个用于测试。不建议查看测试数据,因为这可能会干扰您在创建模型时的选择。您不想创建一个模型来预测这个特定的测试数据,因为您想要创建一个泛化能力很好的模型。以下是如何加载数据集的代码:fromsklearn.datasetsimportfetch_20newsgroupscategories=["comp.graphics","sci.space","re??c.sport.baseball"]newsgroups_train=fetch_20newsgroups(subset='train',categories=categories)newsgroups_test=fetch_20newsgroups(subset='test',categories=categoriestrainingmodel在神经网络术语中,一个epoch=前向传递(获取输出值)和所有训练示例的反向传递(更新权重)。记住tf.Session.run()方法?我们仔细看看:tf.Session.run(fetches,feed_dict=None,options=None,run_metadata=None)在本文开头的数据流图中,你使用和操作,但我们也可以传递要运行的事物列表。在这个神经网络运行中,我们将传递两个事物:损失计算和优化步骤。feed_dict参数是我们为运行的每个步骤输入的数据。为了传递这个数据,我们需要定义tf.placeholders(提供给feed_dict)作为TensorF低文档说:“占位符仅作为输入目标存在,不需要初始化,也不包含数据。“—Source将因此定义占位符,如下所示:n_input=total_words#Wordsinvocabn_classes=3#Categories:graphics,sci.spaceandbaseballinput_tensor=tf.placeholder(tf.float32,[None,n_input],name="input")output_tensor=tf.placeholder(tf.float32,[None,n_classes],name="output")也会批量分离你的训练数据:“如果你使用占位符输入,你可以使用tf.placeholder(…,shape=[None,…])创建占位符以指定可变批次维度。shape的None元素对应于可变大小的维度。"—Source在测试模型时,我们将向字典提供更大的批次,这就是我们需要定义可变批次维度的原因。get_batches()函数为我们提供批次大小的文本数量。现在我们可以运行模型了:training_epochs=10#Launchthegraphwithtf.Session()assess:sess.run(init)#initsthevariables(normaldistribution,remember?)#Trainingcycleforepochinrange(training_epochs):avg_cost=0.total_batch=int(len(newsgroups_train.data)/batch_size)#Loopoverallbatchesforiinrange(total_batch):batch_x,batch_y=get_batch(newsgroups_train,i,batch_size)#Runoptimizationop(backprop)andcostop(togetlossvalue)c,_=sess.run([loss,optimizer],feed_dict={input_tensor:batch_x,output_tensor:batch_y})现在有了这个经过训练的模型。为了测试它,还需要创建图形元素。我们要衡量模型的准确率,所以我们需要得到预测值的索引和正确值的索引(因为我们使用的是one-hotencoding),检查它们是否相等,并计算所有的平均值测试数据集:#Testmodelindex_prediction=tf.argmax(prediction,1)index_correct=tf.argmax(output_tensor,1)correct_prediction=tf.equal(index_prediction,index_correct)#Calculateaccuracyaccuracy=tf.reduce_mean(tf.cast(correct_prediction,"float")))total_test_data=len(newsgroups.target)batch_x_test,batch_y_test=get_batch(newsgroups_test,0,total_test_data)print("精度:",accuracy.eval({input_tensor:batch_x_test,output_tensor:batch_y_test}))Epoch:0001loss=1133.908114347Epoch:0002loss=329.093700409Epoch:0003loss=111.876660109Epoch:0004loss=72.552971845Epoch:0005loss=16.673050320Epoch:0006loss=16.481995190Epoch:0007loss=4.848220565Epoch:0008loss=0.759822878Epoch:0009loss=0.000000000Epoch:0010loss=0.079848485OptimizationFinished!Accuracy:0.75就是这样!你使用神经网络创建一个模型是de开发将文本分类为不同的类别。恭喜!可以在此处查看包含最终代码的笔记本(https://github.com/dmesquita/understanding_tensorflow_nn)。提示:修改我们定义的值,看看变化如何影响训练时间和模型精度。还有其他问题或建议吗?留下您的意见。谢谢阅读!