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

机器学习零基础?教你用TensorFlow搭建图像识别系统(二)

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

这是WolfgangBeyer的一篇博文。详细介绍了如何使用TensorFlow搭建一个简单的图像识别系统。本文将一步步讲解搭建图像识别系统的全过程。本系列文章主要介绍没有机器学习基础的用户如何尝试从零开始在TensorFlow上搭建图像识别系统。在文章的第一部分,作者WoflgangBeyer向读者介绍了一些简单的概念。本文是该系列的第二篇,主要介绍如何实现简单的图像识别功能。雷锋网整理,未经许可不得转载。现在,我们可以开始构建我们的模型了。事实上,数值计算都是由TensorFlow完成的,它使用了一个快速高效的C++守护进程。TensorFlow希望避免在Python和C++之间频繁切换,因为那样会减慢计算速度。一般的工作流程是首先创建一个TensorFlow图以定义所有操作。这个过程没有任何计算,我们只是进行设置操作。只有这样,我们才能对输入数据运行计算操作并记录结果。让我们开始定义我们的图表。首先通过创建占位符来描述TensorFlow输入数据的形式。占位符不包含任何实际数据,它们只是定义数据的类型和形状。在我们的模型中,我们首先为图像数据定义占位符,其中包括浮点数据(tf.float32)。形状参数定义输入数据的大小。我们会同时输入多张图片(后面会讲到这些过程),但是我们希望能够随时改变实际输入图片的数量。所以第一个shape参数是none,也就是说size可以是任意长度。第二个参数是3072,是每张图片的浮点值。分类标签的占位符包括整数数据(tf.int64),每个图像的值从0到9。由于我们没有指定输入图像的数量,因此形状参数为[none]。权重和偏差是我们希望优化的变量。但是现在让我们谈谈我们的模型。我们的输入包括3072个浮点数据,而期望的输出是10个整数数据之一。我们如何将3072个值化为一个呢?让我们退一步,我们不是输出一个从0到9的数字,而是对它进行评分,得到10个数字——每个类别一个分数——然后我们挑选出分数***的一种。于是我们原来的问题就变成了:如何从3072个值变成10个值。我们采用的一种天真的方法是单独查询每个像素。对于每个像素(或更准确地说,每个像素的颜色通道)和每个可能的类别,我们问自己像素的颜色是增加还是减少它属于某个类别的可能性。假设像素颜色是红色。如果汽车图片的像素通常是红色的,我们想提高类别“汽车”的分数。我们将像素的红色通道的值乘以一个正数,并将其添加到“汽车”类别的分数中。类似地,如果马的图像从不或很少在位置1处有红色像素,我们希望将分类为“马”的分数保持在较低或较低的水平。也就是说,它乘以一个较小的或负数,并添加到分类为“马”的分数中。我们对所有10个类别重复这个操作,对每个像素重复计算,将3072个值相加得到一个总和。3072个像素的值乘以3072个加权参数值得到该类别的分数。***我们为10个类别获得10分。然后我们选择得分最高的一张,并用该类别标记图像。图像由3072个值的一维数组表示。每个值乘以一个权重参数,所有值相加得到一个数值——特定类别的分数。我们可以使用矩阵法,它大大简化了像素值乘以加权值并相加的过程。我们的图像由3072维向量表示。如果我们将这个向量乘以一个3072×10的加权矩阵,结果就是一个10维向量。它包括我们需要的加权和。通过矩阵乘法计算图像在所有10个类别中的分数。3072×10矩阵中的具体值就是我们模型的参数。如果它不规则或无用,我们的输出也是如此。这需要训练数据才能起作用。通过查询训练数据,我们希望模型能够自己计算出最好的参数。在上面两行代码中,我们告诉TensorFlow,权重矩阵的大小为3072×10,初始值设置为0。另外,我们定义了第二个参数,一个包含偏置值的10维向量.该偏移值不直接作用于图像数据,而是简单地添加到加权和中。这个偏差值可以看作是***评分的起点。想象一个全黑的图像,所有的像素点都是0。那么不管权重矩阵的大小,所有类别的分数都是0。通过偏差值,我们可以保证我们每个类别的起始值都不为0。现在让我们谈谈预测。通过这一步,我们确定了多个图像向量和矩阵的维度。此操作的结果是每个输入图像的10维向量。通过矩阵乘法计算多个图像的所有10个类别的分数。逐渐优化权重和偏差参数的过程称为训练,包括以下步骤:***,我们输入训练数据,让模型根据当前参数进行预测。将预测值与正确的类标签进行比较。比较的数值结果称为损失。较小的损失值意味着预测值更接近正确的标签,反之亦然。我们希望最小化模型的损失值,使预测值更接近真实标签。但在我们最小化损失之前,让我们看看损失是如何计算的。上一步计算的分数存储在logits变量中,该变量包含任何实数。我们可以调用softmax函数将这些值转化为概率值(0到1之间的实数,其和为1),从而将输入转化为能够代表其特征的输出。相应的输入排列保持不变,得分最好的类别有最好的概率。将softmax函数输出的概率分布与真实概率分布进行比较。在真实的概率分布中,正确类别的概率为1,其他类别的概率为0。我们使用交叉熵来比较两个概率分布(可以在此处找到更技术性的解释)。交叉熵越小,预测值的概率分布与正确值的概率分布之间的差异就越小。这个值代表我们模型的损失。幸运的是,TensorFlow提供了一个函数来帮助我们完成这一系列的操作。我们将模型预测的logits与正确的分类labels_placeholder进行比较。sparse_softmax_cross_entropy_with_logits()函数的输出是每个输入图像的损失值。然后我们只需要计算输入图像的平均损失值。但是我们如何调整参数来最小化损失呢?TensorFlow就会在这个时候大显身手。通过一种称为自动微分的技术,它计算损失值相对于参数值的梯度。这意味着它可以知道每个参数对整体损失的影响,参数的小幅增加或减少是否可以减少损失。然后相应地调整所有参数值以增加模型的准确性。参数调整完成后,整个过程重新开始,并将一组新图像输入模型。TensorFlow知道不同的优化技术可以使用梯度信息来更新参数值。这里我们使用梯度下降算法。在决定参数时,只关心模型当前的状态,不考虑之前的参数值。参数下降算法只需要一个参数,即学习率,它是参数更新的比例因子。学习率越大,每一步参数值的调整越大。如果学习率太大,参数值可能会超过正确值,模型无法收敛。如果学习率太小,模型会学习得很慢,需要很长时间才能找到一个好的参数值。对输入图像进行分类、将预测结果与真实值进行比较、计算损失和调整参数的过程需要重复多次。对于更大、更复杂的模型,这种计算负担将迅速增加。但是对于我们的简单模型,我们既不需要耐心也不需要专门的硬件来获得结果。这两行代码用于检查模型的准确性。logits的argmax返回得分为***的分类。这是预测的类标签。tf.equal()将此标签与正确的分类标签进行比较并返回一个布尔向量。布尔数被转换为浮点数(每个值要么是0要么是1),然后对这些数字进行平均以获得一个分数,该分数是正确预测图像的比例。***,我们已经定义了TensorFlow图并准备运行它。在会话控件中运行图形,可以通过sess变量访问该控件。运行此会话控件的第一步是初始化我们之前创建的变量。在变量定义中,我们指定了初始值,那么我们需要将这些初始值赋给变量。然后我们开始迭代训练过程。它将重复max_steps次。这几行代码随机抽取训练数据的一些图像。从训练数据中提取的少数图像和标签称为批次。批量大小(单个批量中的图像数量)告诉我们参数更新的频率。我们首先对批次中所有图像的损失值进行平均。然后根据梯度下降算法更新参数。如果我们首先对训练集中的所有图像进行分类,而不是在批处理完成后进行分类,我们可以计算初始平均损失和初始梯度,并使用它们代替批处理运行时使用的估计值。但在这种情况下,需要更多的计算来更新每次迭代的参数。在另一个极端,我们可以将批量大小设置为1,然后更新单个图像的参数。这导致更频繁的参数更新,但错误的可能性更高。因此经常在错误的方向上进行更正。通常在这两个极端中间的某个地方,我们得到最快的改进。对于较大的模型,内存注意事项也很关键。批量大小应尽可能大,同时允许将所有变量和中间结果写入内存。这里第一行代码batch_size随机指定一个从0到整个训练集大小的值。然后根据这个值,批处理选择相应数量的图像和标签。每100次迭代,我们检查模型训练数据批次的当前准确性。我们只需要调用我们之前定义的精度率操作即可。这是整个训练循环中最重要的代码行。我们告诉模型执行单独的训练步骤。我们不必再次声明模型需要为参数更新做什么。所有信息均由TensorFlow图表中的定义提供。TensorFlow知道使用梯度下降算法根据损失更新参数。损失取决于对数。Logit又依赖于权重、偏差和特定的输入批次。所以我们只需要将训练数据批次提供给模型。这是通过提供查找表来完成的。训练数据批次已经在我们之前定义的占位符中分配了值。训练后,我们在测试集上评估模型。这是模型第一次看到测试集。所以测试集中的图像对模型来说是全新的。我们评估经过训练的模型在前所未见的数据上的表现如何。***一行代码打印出训练和运行模型所花费的时间。结果让我们用“pythonsoftmax.py”命令运行这个模型。这是我得到的输出:这是什么意思?在此测试集上训练模型的估计准确度约为31%。如果您运行自己的代码,您的结果可能在25-30%左右。因此,我们的模型能够在25%-30%的时间内正确标记从未见过的图像。还不错!这里有10个不同的标签,如果随机猜测,结果只有10%准确。我们非常简单的方法已经胜过随机猜测。如果你觉得25%还是有点低,别忘了这个模型其实还是比较原始的。它没有线条和形状等特定图像特征的概念。它只是单独检测每个像素的颜色,完全无视它与其他像素的关系。修改图像的单个像素意味着对模型的输入完全不同。考虑到这一点,25%的准确率似乎并不是一个糟糕的交易。如果我们再做几次迭代呢?它可能不会提高模型的准确性。看一下结果,可以看到训练准确率并没有稳定上升,而是在0.23和0.44之间波动。看起来我们已经达到了模型的极限,再训练它也无济于事。这个模型不可能给出更好的结果。事实上,我们可以用比训练1000次迭代少得多的迭代次数来达到类似的精度。您可能会注意到的第一件事是测试准确率远低于训练准确率。如果这个差距很大,也意味着过拟合。该模型根据它看到的训练数据进行微调,但不会根据它以前从未见过的数据进行微调。这篇文章写了很久了。感谢您阅读全文(或直接跳到文末)!无论是关于机器学习分类器的工作原理还是如何使用TensorFlow构建和运行简单图形,我希望您能找到感兴趣的内容。当然,我还有很多材料要补充。到目前为止,我们只使用了softmax分类器,它甚至没有应用任何类型的神经网络。完善我的下一篇博文:小型神经网络模型如何最大化结果。