python3图像识别地类_机器学习零基础?手把手教你用TensorFlow搭建图像识别系统(三)| 干货...

原标题:机器学习零基础?手把手教你用TensorFlow搭建图像识别系统(三)| 干货

雷锋网按:本文是介绍用TensorFlow构建图像识别系统的第三部分。 在前两部分中,我们构建了一个softmax分类器来标记来自CIFAR-10数据集的图像,实现了约25-30%的精度。 因为有10个不同可能性的类别,所以我们预期的随机标记图像的精度为10%。25-30%的结果已经比随机标记的结果好多了,但仍有很大的改进空间。在这篇文章中,作者Wolfgang Beyer将介绍如何构建一个执行相同任务的神经网络。看看可以提高预测精度到多少!雷锋网对全文进行编译,未经许可不得转载。

关于前两部分,可以参看《机器学习零基础?手把手教你用TensorFlow搭建图像识别系统》(一)和(二)。

神经网络

神经网络是基于生物大脑的工作原理设计的,由许多人工神经元组成,每个神经元处理多个输入信号并返回单个输出信号,然后输出信号可以用作其他神经元的输入信号。我们先来看看一个单独的神经元,大概长这样:

一个人工神经元:其输出是其输入加权和的ReLU函数值。

在单个神经元中发生的情况与在softmax分类器中发生的情况非常相似。一个神经元有一个输入值的向量和一个权重值的向量,权重值是神经元的内部参数。输入向量和权重值向量包含相同数量的值,因此可以使用它们来计算加权和。

WeightedSum=input1×w1+input2×w2+...

到目前为止,我们正在做与softmax分类器完全相同的计算,现在开始,我们要进行一些不同的处理:只要加权和的结果是正值,神经元的输出是这个值;但是如果加权和是负值,就忽略该负值,神经元产的输出为0。 此操作称为整流线性单元(ReLU)。

由 f(x) = max(0, x)定义的整流线性单元

使用ReLU的原因是其具备非线性特点,因而现在神经元的输出并不是严格的输入线性组合(也就是加权和)。当我们不再从单个神经元而是从整个网络来看时,会发现非线性很有用处。

人工神经网络中的神经元通常不是彼此随机连接的,大多数时候是分层排列的:

人工神经网络具有隐藏层和输出层2个层。

输入并不被当作一层,因为它只是将数据(不转换它)馈送到第一个合适的层。

wikimedia

输入图像的像素值是第1层网络中的神经元的输入。第1层中的神经元的输出是第2层网络的神经元的输入,后面的层之间以此类推。如果没有每层的ReLU,我们只是得到一个加权和的序列;并且堆积的加权和可以被合并成单个加权和,这样一来,多个层并没有比单层网络有任何改进之处。这就是为什么要具有非线性的重要原因。ReLU非线性解决了上述问题,它使每个附加层的确给网络添加了一些改进。

我们所关注的是图像类别的分数,它是网络的最后一层的输出。在这个网络架构中,每个神经元连接到前一层的所有神经元,因此这种网络被称为完全连接的网络。我们将会在本教程的第3部分中看到一些不同于此的其他情况。

对神经网络理论的简短介绍到此结束。 让我们开始建立一个真正的神经网络!

代码实战

此示例的完整代码在Github上提供。它需要TensorFlow和CIFAR-10数据集(雷锋网(公众号:雷锋网)的此前文章有提及)。

如果你已经通过我以前的博客文章,你会看到神经网络分类器的代码非常类似于softmax分类器的代码。 除了切换出定义模型的代码部分之外,我还添加了一些小功能使TensorFlow可以做以下一些事情:

正则化:这是一种非常常见的技术,用于防止模型过拟合。它的工作原理是在优化过程中施加反作用力,其目的是保持模型简单

使用TensorBoard可视化模型:TensorBoard包含TensorFlow,允许您根据模型和模型生成的数据生成表格和图形。这有助于分析您的模型,并且对调试特别有用。

检查点:此功能允许您保存模型的当前状态以供以后使用。训练一个模型可能需要相当长的时间,所以它是必要的,当您想再次使用模型时不必从头开始。

这次代码被分成两个文件:定义模型two_layer_fc.py和运行模型run_fc_model.py(提示:'fc'代表完全连接的意思)。

两层全连接的神经网络

让我们先看看模型本身,然后进行一些运行和训练处理。two_layer_fc.py包含以下函数:

inference(),使我们从输入数据到类分数。

loss(),从类分数中计算损失值。

training(),执行单个训练步骤。

evaluation(),计算网络的精度。

生成类分数:inference()

inference()描述了通过网络的正向传递。那么,类分数是如何从输入图片开始被计算的呢?

参数images是包含实际图像数据的TensorFlow占位符。接下来的三个参数描述网络的形状或大小。 image_Pixels是每个输入图像的像素数,classes是不同输出标签的数量,hidden_units是网络的第一个层或者隐藏层中的神经元数量。

每个神经元从上一层获取所有值作为输入,并生成单个输出值。因此,隐藏层中的每个神经元都具有image_pixels输入,并且该层作为整体生成hidden_units输出。然后将这些输入到输出层的类神经元中,生成类输出值,每个类一个分数。

reg_constant是正则化常数。TensorFlow允许我们非常容易地通过自动处理大部分计算来向网络添加正则化。 当使用到损失函数时,我会进一步讲述细节。

由于神经网络有2个相似的图层,因此将为每个层定义一个单独的范围。 这允许我们在每个作用域中重复使用变量名。变量biases以我们熟悉的tf.Variable()方式来定义。

此处会更多地涉及到weights变量的定义。tf.get_variable()允许我们添加正则化。weights是以hidden_units(输入向量大小乘以输出向量大小)为维度的image_pixels矩阵。initialier参数描述了weights变量的初始值。目前为止我们已经将weights变量初始化为0,但此处并不会起作用。关于单层中的神经元,它们都接收完全相同的输入值,如果它们都具有相同的内部参数,则它们将进行相同的计算并且输出相同的值。为了避免这种情况,需要随机化它们的初始权重。我们使用了一个通常可以很好运行的初始化方案,将weights初始化为正态分布值。丢弃与平均值相差超过2个标准偏差的值,并且将标准偏差设置为输入像素数量的平方根的倒数。幸运的是TensorFlow为我们处理了所有这些细节,我们只需要指定调用truncated_normal_initializer便可完成上述工作。

weights变量的最终参数是regularizer。现在要做的是告诉TensorFlow要为weights变量使用L2-正则化。我将在这里讨论正则化。

第一层的输出等于images矩阵乘以weights矩阵,再加上bisa变量。这与上一篇博文中的softmax分类器完全相同。然后应用tf.nn.relu(),取ReLU函数的值作为隐藏层的输出。

第2层与第1层非常相似,其输入值为hidden_units,输出值为classes,因此weights矩阵的维度是是[hidden_units,classes]。 由于这是我们网络的最后一层,所以不再需要ReLU。 通过将输入(hidden)互乘以weights,再加上bias就可得到类分数(logits)。

tf.histogram_summary()允许我们记录logits变量的值,以便以后用TensorBoard进行分析。这一点稍后会介绍。

总而言之,整个inference()函数接收输入图像并返回类分数。这是一个训练有素的分类器需要做的,但为了得到一个训练有素的分类器,首先需要测量这些类分数表现有多好,这是损失函数要做的工作。

计算损失: loss()

首先,我们计算logits(模型的输出)和labels(来自训练数据集的正确标签)之间的交叉熵,这已经是我们对softmax分类器的全部损失函数,但是这次我们想要使用正则化,所以必须给损失添加另一个项。

让我们先放一边吧,先看看通过使用正则化能实现什么。

过度拟合和正则化

当捕获数据中随机噪声的统计模型是被数据训练出来的而不是真实的数据基础关系时,就被称为过拟合。

红色和蓝色圆圈表示两个不同的类。绿线代表过拟合模型,而黑线代表具有良好拟合的模型。

wikipedia

在上面的图像中有两个不同的类,分别由蓝色和红色圆圈表示。绿线是过度拟合的分类器。它完全遵循训练数据,同时也严重依赖于训练数据,并且可能在处理未知数据时比代表正则化模型的黑线表现更差。因此,我们的正则化目标是得到一个简单的模型,不附带任何不必要的复杂。我们选择L2-正则化来实现这一点,L2正则化将网络中所有权重的平方和加到损失函数。如果模型使用大权重,则对应重罚分,并且如果模型使用小权重,则小罚分。

这就是为什么我们在定义权重时使用了regularizer参数,并为它分配了一个l2_regularizer。这告诉了TensorFlow要跟踪l2_regularizer这个变量的L2正则化项(并通过参数reg_constant对它们进行加权)。所有正则化项被添加到一个损失函数可以访问的集合——tf.GraphKeys.REGULARIZATION_LOSSES。将所有正则化损失的总和与先前计算的交叉熵相加,以得到我们的模型的总损失。

优化变量:training()

global_step是跟踪执行训练迭代次数的标量变量。当在我们的训练循环中重复运行模型时,我们已经知道这个值,它是循环的迭代变量。直接将这个值添加到TensorFlow图表的原因是想要能够拍摄模型的快照,这些快照应包括有关已执行了多少训练步骤的信息。

梯度下降优化器的定义很简单。我们提供学习速率并告诉优化器它应该最小化哪个变量。 此外,优化程序会在每次迭代时自动递增global_step参数。

测量性能: evaluation()

模型精度的计算与softmax情况相同:将模型的预测与真实标签进行比较,并计算正确预测的频率。 我们还对随着时间的推移精度如何演变感兴趣,因此添加了一个跟踪accuracy的汇总操作。 将在关于TensorBoard的部分中介绍这一点。

总结我们迄今为止做了什么,已经定义了使用4个函数的2层人工神经网络的行为:inference()构成通过网络的正向传递并返回类分数。loss()比较预测和真实的类分数并生成损失值。 training()执行训练步骤,并优化模型的内部参数。evaluation()测量模型的性能。

运行神经网络

现在神经网络已经定义完毕,让我们看看run_fc_model.py是如何运行、训练和评估模型的。

在强制导入之后,将模型参数定义为外部标志。 TensorFlow有自己的命令行参数模块,这是一个围绕Python argparse的小封装包。 在这里使用它是为了方便,但也可以直接使用argparse。

在代码开头两行中定义了命令行参数。每个标志的参数是标志的名称(其默认值和一个简短的描述)。 使用-h标志执行文件将显示这些描述。第二个代码块调用实际解析命令行参数的函数,然后将所有参数的值打印到屏幕上。

用常数定义每个图像的像素数(32 x 32 x 3)和不同图像类别的数量。

使用一个时钟来记录运行时间。

我们想记录关于训练过程的一些信息,并使用TensorBoard显示该信息。 TensorBoard要求每次运行的日志都位于单独的目录中,因此我们将日期和时间信息添加到日志目录的名称地址。

load_data()加载CIFAR-10数据,并返回包含独立训练和测试数据集的字典。

生成TensorFlow图

定义TensorFlow占位符。 当执行实际计算时,这些将被填充训练和测试数据。

images_placeholder将每张图片批处理成一定尺寸乘以像素的大小。 批处理大小设定为“None”允许运行图片时可随时设定大小(用于训练网络的批处理大小可以通过命令行参数设置,但是对于测试,我们将整个测试集作为一个批处理) 。

labels_placeholder是一个包含每张图片的正确类标签的整数值向量。

这里引用了我们之前在two_layer_fc.py中描述的函数。

inference()使我们从输入数据到类分数。

loss()从类分数中计算损失值。

training()执行单个训练步骤。

evaluation()计算网络的精度。

为TensorBoard定义一个summary操作函数 (更多介绍可参见前文).

生成一个保存对象以保存模型在检查点的状态(更多介绍可参见前文)。

开始TensorFlow会话并立即初始化所有变量。 然后我们创建一个汇总编辑器,使其定期将日志信息保存到磁盘。

这些行负责生成批输入数据。让我们假设我们有100个训练图像,批次大小为10.在softmax示例中,我们只为每次迭代选择了10个随机图像。这意味着,在10次迭代之后,每个图像将被平均选取一次。但事实上,一些图像将被选择多次,而一些图像不会被添加到任何一个批次。但只要重复的次数够频发,所有图片被随机分到不同批次的情况会有所改善。

这一次我们要改进抽样过程。要做的是首先对训练数据集的100个图像随机混洗。混洗之后的数据的前10个图像作为我们的第一个批次,接下来的10个图像是我们的第二批,后面的批次以此类推。 10批后,在数据集的末尾,再重复混洗过程,和开始步骤一致,依次取10张图像作为一批次。这保证没有任何图像比任何其它图像被更频繁地拾取,同时仍然确保图像被返回的顺序是随机的。

为了实现这一点,data_helpers()中的gen_batch()函数返回一个Python generator,它在每次评估时返回下一个批次。generator原理的细节超出了本文的范围(这里有一个很好的解释)。使用Python的内置zip()函数来生成一个来自[(image1,label1),(image2,label2),...]的元组列表,然后将其传递给生成函数。

next(batch)返回下一批数据。 因为它仍然是[(imageA,labelA),(imageB,labelB),...]的形式,需要先解压它以从标签中分离图像,然后填充feed_dict,字典包含用单批培训数据填充的TensorFlow占位符。

每100次迭代之后模型的当前精度会被评估并打印到屏幕上。此外,正在运行summary操作,其结果被添加到负责将摘要写入磁盘的summary_writer(看此章节)。

此行运行train_step操作(之前定义为调用two_layer_fc.training(),它包含用于优化变量的实际指令)。

当训练模型需要较长的时间,有一个简单的方法来保存你的进度的快照。 这允许您以后回来并恢复模型在完全相同的状态。 所有你需要做的是创建一个tf.train.Saver对象(我们之前做的),然后每次你想拍摄快照时调用它的save()方法。恢复模型也很简单,只需调用savever的restore()。 代码示例请看gitHub存储库中的restore_model.py文件。

在训练完成后,最终模型在测试集上进行评估(记住,测试集包含模型到目前为止还没有看到的数据,使我们能够判断模型是否能推广到新的数据)。

结果

让我们使用默认参数通过“python run_fc_model.py”运行模型。 我的输出如下所示:

可以看到训练的准确性开始于我们所期望到随机猜测水平(10级 - > 10%的机会选择到正确的)。 在第一次约1000次迭代中,精度增加到约50%,并且在接下来的1000次迭代中围绕该值波动。 46%的测试精度不低于训练精度。 这表明我们的模型没有显着过度拟合。 softmax分级器的性能约为30%,因此46%的改进约为50%。不错!

用TensorBoard可视化

TensorBoard允许您从不同方面可视化TensorFlow图形,并且对于调试和改进网络非常有用。 让我们看看TensorBoard相关的代码。

在 two_layer_fc.py 我可以看到以下代码:

这三行中的每一行都创建一个汇总操作。通过定义一个汇总操作告诉TensorFlow收集某些张量(在本例中logits,loss和accuracy)的摘要信息。汇总操作的其他参数就只是一些想要添加到总结的标签。

有不同种类的汇总操作。使用scalar_summary记录有关标量(非矢量)值以及histogram_summary收集有关的多个值分布信息(有关各种汇总运算更多信息可以在TensorFlow文档中找到)。

在 run_fc_model.py 是关于TensorBoard 可视化的一些代码:

TensorFlow中的一个操作本身不运行,您需要直接调用它或调用依赖于它的另一个操作。由于我们不想在每次要收集摘要信息时单独调用每个摘要操作,因此使用tf.merge_all_summaries创建一个运行所有摘要的单个操作。

在TensorFlow会话的初始化期间,创建一个摘要写入器,摘要编入器负责将摘要数据实际写入磁盘。在摘要写入器的构造函数中,logdir是日志的写入地址。可选的图形参数告诉TensorBoard渲染显示整个TensorFlow图形。每100次迭代,我们执行合并的汇总操作,并将结果馈送到汇总写入器,将它们写入磁盘。要查看结果,我们通过“tensorboard --logdir = tf_logs”运行TensorBoard,并在Web浏览器中打开localhost:6006。在“事件”标签中,我们可以看到网络的损失是如何减少的,以及其精度是如何随时间增加而增加的。

tensorboard图显示模型在训练中的损失和精度。

“Graphs”选项卡显示一个已经定义的可视化的tensorflow图,您可以交互式地重新排列直到你满意。我认为下面的图片显示了我们的网络结构非常好。

Tensorboard1以交互式可视化的方式显示Tensorboard图像

有关在“分布”和“直方图”标签的信息可以进一步了解tf.histogram_summary操作,这里不做进一步的细节分析,更多信息可在官方tensorflow文件相关部分。

后续改进

也许你正在想训练softmax分类器的计算时间比神经网络少了很多。事实确实如此,但即使把训练softmax分类器的时间增加到和神经网络来训练所用的时间一样长,前者也不会达到和神经网络相同的性能,前者训练时间再长,额外的收益和一定程度的性能改进几乎是微乎其微的。我们也已经在神经网络中也验证也这点,额外的训练时间不会显著提高准确性,但还有别的事情我们可以做。

已选的默认参数值表现是相当不错的,但还有一些改进的余地。通过改变参数,如隐藏层中的神经元的数目或学习率,应该能够提高模型的准确性,模型的进一步优化使测试精度很可能大于50%。如果这个模型可以调整到65%或更多,我也会相当惊喜。但还有另一种类型的网络结构能够比较轻易实现这一点:卷积神经网络,这是一类不完全连通的神经网络,相反,它们尝试在其输入中理解局部特征,这对于分析图像非常有用。它使得在解读图像获取空间信息的时候有非常直观的意义。在本系列的下一部分中,我们将看到卷积神经网络的工作原理,以及如何构建一个自己的神经网络.。

雷锋网将关注下一部分关于卷积神经网络的介绍,敬请期待。

via wolfib,雷锋网编译

雷锋网版权文章,未经授权禁止转载。详情见转载须知。返回搜狐,查看更多

责任编辑:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/551343.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

织梦php重新安装教程,织梦CMS系统后台重装的操作教程

原标题:织梦CMS系统后台重装的操作教程网站在线运行,不可能一点问题都不存在,或者当初的网站设计、架构、功能已经不能满足现在用户的需求,所以我们会对网站做出相应的改动。网站除了前端的改版,还会有后台系统重装、服…

mpu9250姿态融合算法_基于投票方式的机器人装配姿态估计

作者:仲夏夜之星来源:公众号 3D视觉工坊链接:基于投票方式的机器人装配姿态估计论文题目:《Voting-Based Pose Estimation for Robotic Assembly Using a 3D Sensor》这篇文章被发表在2012年的IEEE International Conference on R…

java安卓浏览器下载文件,JAVA实现文件下载,浏览器端得到数据没反应解决方案

JAVA实现文件下载,浏览器端得到数据没反应代码如下public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {//得到要下载的文件名称String filenamerequest.getParameter("filename");//文件存放的路径…

python如何读取kepsever_python linecache读取过程

最近使用Python编写日志处理脚本时,对Python的几种读取文件的方式进行了实验。其中,linecache的行为引起了我的注意。Python按行读取文件的经典方式有以下几种:with open(blabla.log, r) as f:for line in f.readlines():## do somethingwith…

skywalking原理_微服务链路追踪原理

作者:平也来源:关爱程序员社区背景介绍在微服务横行的时代,服务化思维逐渐成为了程序员的基本思维模式,但是,由于绝大部分项目只是一味地增加服务,并没有对其妥善管理,当接口出现问题时&#xf…

php 上次登陆时间,php使用cookie显示用户上次访问网站日期的方法

本文实例讲述了php使用cookie显示用户上次访问网站日期的方法。分享给大家供大家参考。具体实现方法如下&#xff1a;<?php if(!empty($_COOKIE[lastvisit])){//先判断&#xff0c;是否存在cookieecho "您上次访问时间是&#xff1a;".$_COOKIE[lastvisit];setCo…

文本分析软件_读书笔记:伍多库卡茨质性文本分析:方法、实践与软件使用指南...

读书笔记&#xff1a;伍多库卡茨《质性文本分析&#xff1a;方法、实践与软件使用指南》一、这篇文章、这本书或这篇论文的中心思想、核心观点是什么&#xff1f;核心观点&#xff1a;质性数据如何系统化分析&#xff1f;三大主要方法&#xff1a;主题分析、评估分析和类型建构…

php 分析url函数,PHP 解析URL函数 parse_url()函数

在PHP中 parse_url()函数的使用&#xff0c;parse_url—解析 URL&#xff0c;返回其组成部分。mixed parse_url ( string $url [, int $component -1 ] )本函数解析一个 URL 并返回一个关联数组&#xff0c;包含在 URL 中出现的各种组成部分。本函数不是用来验证给定 URL的合法…

python的知识点运用_程序猿在Python编程中不得不使用的十二种基础知识

Python编程中常用的12种基础知识&#xff0c;其中肯定有你不会的&#xff01;人生苦短&#xff0c;我用Python1、正则表达式替换目标: 将字符串line中的 overview.gif 替换成其他字符串。人生苦短&#xff0c;我用Python2、遍历目录方法在某些时候&#xff0c;我们需要遍历某个…

matlab两轮自平衡小车,两轮自平衡小车(全部设计资料+设计分析)

自己做的自平衡小车&#xff0c;基本达到预期效果。制作资料在压缩包里面&#xff0c;供参考。该两轮自平衡小车硬件设计概述&#xff1a;控制器&#xff1a;ATmega16&#xff1b;8MHz&#xff1b;加速度传感器&#xff1a;MMA2260&#xff1b;陀螺仪&#xff1a;EWTS82&#x…

异步fifo_【推荐】数字芯片异步FIFO设计经典论文

之前有一篇文章我已经推荐过了数字芯片跨时钟域设计的经典论文 &#xff08;【推荐】数字芯片跨时钟域设计经典论文 &#xff09;&#xff0c;希望看过的读者都有一定的收获。不过有点遗憾的是那片论文中虽然提到了异步FIFO&#xff0c;却没有讲具体的原理和设计细节。本篇文章…

matlab启动不了jvm,MATLAB ::在-nojvm启动选项下不再支持此功能

我正在终端中运行Matlab代码&#xff0c;因为稍后我需要在php中调用此代码。但是我得到这些错误&#xff1a;MATLAB ::在-nojvm启动选项下不再支持此功能[email protected]:~/Desktop/v1.2$ matlab -nojvm < matlab.m错误&#xff1a;L2 norm on unsampled vertices: 0.0961…

linux搭建vsftp服务器_Linux配置VSFTP服务器的方法

下面小编就为大家带来一篇Linux配置VSFTP服务器的方法。小编觉得挺不错的&#xff0c;现在就分享给大家&#xff0c;也给大家做个参考。一起跟随小编过来看看吧一、Linux FTP服务器分类&#xff1a;<1>wu-ftp<2>proftpprofession ftp<3>vsftpvery security f…

php active控件,php – 使用TbActiveForm选择列表中的动态选项

我在控制器中有以下代码,$modelnew Guessgame(search);$model->unsetAttributes(); // clear any default valuesif(isset($_GET[Guessgame]))$model->attributes$_GET[Guessgame];$this->render(admin,array(model>$model,));在视图文件中,<?php $form$this-&…

golang 函数传多个参数_关于Golang中方法参数的传递

结构体声明为了说明函数以及方法调用的过程&#xff0c;这里先定义一个struct&#xff0c;在下面的描述中会使用到它。type Person struct {Name stringAge uint16}普通函数中的参数传递在Golang中&#xff0c;普通函数的行参如果是值类型&#xff0c;那么调用的实参也必须是实…

workbook对象需要关闭_XSSFWorkbook对象 进行zip打包时 用write资源流自动关闭处理办法...

xssfworkbook对象的write方法内会将传入的资源流自动关闭 导致下载excel失败错误代码outputstream out response.getoutputstream();zipoutputstream zos new zipoutputstream(out);xssfworkbook workbook new xssfworkbook();// 将文件写入zip内&#xff0c;即将文件进行打…

php for 脚本,php for循环脚本。

$dir "./$time/";$info deepScanDir($dir);for($i0; $i system("/usr/sbin/php temp.php \($i\).txt output\($i\).txt");}deepScanDir是循环文件夹下的所有文件。现在这个循环一次执行一次这个命令&#xff0c;我想弄一个&#xff0c;循环一次执行很多个…

autowired的对象为null_spring-为什么我的@Autowired对象为null?

我有下面的JSF托管bean&#xff1a;package com.example;import java.io.Serializable;import javax.faces.bean.ManagedBean;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;ComponentManagedBeanpublic cl…

基于mysql和php的分布式事务处理1,基于MySQL和PHP的分布式事务处理

PHP(超级文本预处理语言)是一种基于服务器端、执行效率高且易于开发的HTML内嵌式语言,是用户生成动态网页的工具之一[1].MySQL是全球最受欢迎的小型开放源码的关系型数据库管理系统,其体积小、速度快、总体拥有成本低[2].很多基于PHP技术开发的中小型网站都采用MySQL作为其后台…

ios查看线程数量_关于iOS多线程,你看我就够了(已更新)

作者&#xff1a;翁呀伟呀 授权本站转载。在这篇文章中&#xff0c;我将为你整理一下 iOS 开发中几种多线程方案&#xff0c;以及其使用方法和注意事项。当然也会给出几种多线程的案例&#xff0c;在实际使用中感受它们的区别。还有一点需要说明的是&#xff0c;这篇文章将会使…