(2023版)斯坦福CS231n学习笔记:DL与CV教程 (2) | 图像分类与损失函数

在这里插入图片描述

前言

  • 📚 笔记专栏:斯坦福CS231N:面向视觉识别的卷积神经网络(23)
  • 🔗 课程链接:https://www.bilibili.com/video/BV1xV411R7i5
  • 💻 CS231n: 深度学习计算机视觉(2017)中文笔记:https://zhuxiaoxia.blog.csdn.net/article/details/80155166
  • 🔥 2023最新课程PPT:https://download.csdn.net/download/Julialove102123/88734395

本节重点内容:

  1. 存在一些挑战:图像分类挑战;
  2. 怎么解决?数据驱动方式:最近邻、k近邻;
  3. 怎么让电脑看懂?线性分类-评分函数;
  4. 怎么损通过电脑找出最合适的?损失函数

图像分类是计算机视觉的核心任务,计算机视觉领域中很多问题,如目标检测、语义分割等都可以关联到图像分类问题。图像分类问题,就是已有固定的分类标签集合,然后对于输入的图像,从分类标签集合中找出一个分类标签,最后把分类标签分配给该输入图像。在本篇内容汇总,ShowMeAI将给大家讲解数据驱动的模型算法,包括简单的 KNN 模型和 线性分类模型。

1. 图像分类的挑战

对于计算机而言,图像等同于一个像素矩阵;而对人类,图像是包含丰富语义信息的多媒体呈现,对应不同的物体类别,所以对计算机而言存在巨大的语义鸿沟。

比如,给计算机输入如下小猫的图片,计算机图像分类模型会读取该图片,并计算该图片属于集合{dog, cat, truck, plane, …}中各个标签的概率。但读取的输入图像数据是一个由数字组成的巨大的3维数组。

在下图中,猫的图像大小高800像素,宽600像素,有3个颜色通道(红、绿和蓝,简称RGB),因此它包含了800x600x3个数字,每个数字都是在0~255之间的整型,其中0表示全黑,255表示全白。

我们的任务就是把这些数字变成一个简单的标签,比如 「猫」 。
在这里插入图片描述

图像分类算法要足够健壮(鲁棒,robust),这样它能够适应下述变化及组合:

  • 视角变化(Viewpoint variation):同一个物体,摄像机可以从多个角度来展现。
    在这里插入图片描述

  • 光照条件(Illumination conditions):在像素层面上,光照的影响非常大。
    在这里插入图片描述

  • 背景干扰(Background clutter):物体可能混入背景之中,使之难以被辨认。
    在这里插入图片描述在这里插入图片描述

  • 遮挡(Occlusion):目标物体可能被挡住,有时候只有物体的一小部分(可以小到几个像素)是可见的。
    在这里插入图片描述

  • 形变(Deformation):很多东西的形状并非一成不变,会有很大变化。
    在这里插入图片描述

  • 类内差异(Intra-class variation):一类物体的个体之间的外形差异很大,比如椅子。
    在这里插入图片描述

  • 上下文变化(Context):环境中的一些复杂影响。
    在这里插入图片描述

2. 数据驱动的方式

一种尝试:「硬编码」:先获取猫图像的边缘得到一些线条,然后定义规则比如三条线交叉是耳朵之类。然而这种方式的识别效果不好,并且不能识别新的物体。
在这里插入图片描述
新的尝试:采用数据驱动算法,不具体写出识别每个物体对应的规则,而是针对每一类物体,① 收集大量样例图片和标签;② 输入给计算机进行机器学习,归纳模式规律,生成一个分类器模型,总结出区分不同类物体的核心知识要素;③ 用训练好的模型,识别新的图像。
在这里插入图片描述
数据驱动算法过程如下

  • 「输入」:输入是包含N个图像的集合,每个图像的标签是K种分类标签中的一种。这个集合称为训练集。
  • 「学习」:这一步的任务是使用训练集来学习每个类的模式规律。一般该步骤叫做分类器训练或者模型学习。
  • 「评价」:让分类器对它未曾见过的图像进行分类,把分类器预测的标签和图像真正的分类标签 (基本事实) 对比,并以此来评价分类器的质量。

2.1 最近邻算法(1 Nearest Neighbor)

最近邻算法。训练过程只是简单的记住图像数据和标签,预测的时候和训练数据中图片比较找出最接近的输出标签。这个分类器和卷积神经网络没有任何关系,实际中也极少使用,但通过实现它,可以对解决图像分类问题的方法有个基本认识。

算法原理

CIFAR-10 是一个非常流行的图像分类数据集。这个数据集包含 10 种分类标签,60000 张 32x32
的小图像,每张图片含有一个标签。这 60000 张图像被分为包含 50000 张(10类 x 5000 张)图像的训练集和包含 10000
张(10类 x 1000张)图像的测试集。

  1. 划分数据集:
    假设现在我们用这 50000 张图片作为训练集,将余下的 10000 作为测试集并打上标签,Nearest Neighbor 算法将会拿着测试图片和训练集中每一张图片去比较,然后将它认为最相似的那个训练集图片的标签赋给这张测试图片。
    在这里插入图片描述

  2. 距离计算:

    • L1距离(曼哈顿距离):
      在这里插入图片描述

    • L2距离(欧氏距离):
      在这里插入图片描述

L1 距离更依赖于坐标轴的选定,坐标轴选择不同 L1 距离也会跟着变化,判定的数据归类的边界会更趋向于贴近坐标系的轴来分割所属区域,而 L2 的话相对来说与坐标系的关联度没那么大,会形成一个圆,不跟随坐标轴变化。
在这里插入图片描述

在面对两个向量之间的差异时,L2 比 L1 更加不能容忍这些差异。也就是说,相对于1个巨大的差异,L2 距离更倾向于接受多个中等程度的差异(因为会把差值平方)。

当图像中有特别在意的特征时可以选择 L1 距离;当对图像中所有元素未知时,L2 距离会更自然一些。最好的方式是两种距离都尝试,然后找出最好的那一个。

2.2 K近邻算法(K Nearest Neighbor)

只用最相似的 1 张图片的标签来作为测试图像的标签,有时候会因为参照不够多而效果不好,我们可以使用 k-Nearest Neighbor 分类器。KNN的思想是:找最相似的 k 个图片的标签,k中数量最多的标签作为对测试图片的预测。

当k=1的时候,k-Nearest Neighbor 分类器就是上面所说的最邻近分类器。
🔥 可视化近邻算法:http://vision.stanford.edu/teaching/cs231n-demos/knn/在这里插入图片描述

在这里插入图片描述

❓那么问题来了?
1. k怎么选?KNN 分类器需要设定k值,如何选择k值最合适?
2. 距离计算方式怎么选?L1 距离和 L2 距离选哪个比较好(还是使用其他的距离度量准则例如点积)?
就有了超参数的概念!!!

1)超参数调优

上述这些选择,被称为超参数(hyperparameter)。在基于数据进行学习的机器学习算法设计中,超参数是很常见的。超参数是需要提前设置的,设置完成后模型才可以训练学习,具体的设置方法通常要借助于实验,尝试不同的值,根据效果表现进行选择。那如何调优来选择呢?答案是借助验证集

方法 1:设置验证集
从训练集中取出一部分数据用来调优,称之为 验证集(validation set)。以 CIFAR-10 为例,可以用 49000 个图像作为训练集,用 1000 个图像作为验证集。验证集其实就是作为假的测试集来调优。

在这里插入图片描述
方法 2:交叉验证
训练集数量较小(因此验证集的数量更小)时,可以使用交叉验证的方法。还是用刚才的例子,如果是交叉验证集,我们就不是取 1000 个图像,而是将训练集平均分成 5 份,每份 10000 张图片,其中4份用来训练,1份用来验证。然后我们循环着取其中4份来训练,其中1份来验证,最后取所有5次验证结果的平均值作为算法验证结果。
在这里插入图片描述

2)KNN分类器优点

① 易于理解,实现简单。
② 算法的训练不需要花时间,因为其训练过程只是将训练集数据存储起来。

3) KNN分类器缺点

① 测试要花费大量时间:因为每个测试图像需要和所有存储的训练图像进行比较在实际应用中,关注测试效率远远高于训练效率;
② 使用像素差异来比较图像是不够的,图片间 L2 距离小,更多的是被背景主导而不是图片语义内容本身主导,往往背景相似图片的 L2 距离就会小。也就是说,在高维度数据上,基于像素的相似和基于感官上的相似非常不同。感官上不同的两张图片,可能有相同的 L2 距离。
③ 维度灾难:KNN 有点像训练数据把样本空间分成几块,我们需要训练数据密集的分布在样本空间里,否则测试图片的最邻近点可能实际距离会非常远,导致和最接近的训练集样本实际上完全不同。但是如果使训练数据密集分布,需要的训练集数量指数倍增加,是数据维度的平方。

4) 应用KNN建议

对于实际应用 KNN 算法的建议

① 预处理数据:对数据中的特征进行归一化(normalize),让其具有零均值(zero mean)和单位方差(unit variance)。

② 降维:如果数据是高维数据,考虑使用降维方法,比如 PCA 或者随机投影。

③ 将数据随机分为训练集和验证集:

  • 一般规律,70%-90%数据作为训练集。这个比例根据算法中有多少超参数,以及这些超参数对于算法的预期影响来决定。
  • 如果需要预测的超参数很多,就应该使用更大的验证集来有效地估计它们;
  • 如果担心验证集数量不够,尝试交叉验证方法;
  • 如果计算资源足够,使用交叉验证更好(份数越多,效果越好,也更耗费计算资源)。

④ 在验证集上调优:尝试足够多的K值,尝试 L1 和 L2 两种范数计算方式。

⑤ 加速分类器:如果分类器跑得太慢,尝试使用ANN库(比如 FLANN 来加速这个过程,其代价是降低一些准确率。)

⑥ 对最优的超参数做记录:

  • 记录最优参数后,不要使用最优参数的算法在完整的训练集上运行并再次训练,这样做会破坏对于最优参数的估计。
  • 直接使用测试集来测试用最优参数设置好的最优模型,得到测试集数据的分类准确率,并以此作为你的 KNN 分类器在该数据上的性能表现。

3.线性分类:评分函数

3.1 线性分类概述

KNN 模型中训练过程中没有使用任何参数,只是单纯的把训练数据存储起来(参数 k 是在预测中使用的,找出k个接近的图片,然后找出标签最多的,并且k是超参数,是人为设定的)。

与之相对的是参数模型,参数模型往往会在训练完成后得到一组参数,之后就可以完全扔掉训练数据,预测的时候只需和这组参数做某种运算,即可根据运算结果做出判断。线性分类器是参数模型里最简单的一种,但却是神经网络里很重要的基础模块。

线性分类的方法由两部分组成:

① 评分函数(score function):原始图像数据到类别分值的映射。
② 损失函数(loss function):用来量化评分函数计算的分数与真实标签之间的一致性。该方法可转化为一个最优化问题,在最优化过程中,通过更新评分函数的参数来最小化损失函数值。

3.2 评分函数

评分函数将图像的像素值映射为各个分类类别的得分,得分高低代表图像属于该类别的可能性高低。
在这里插入图片描述

重新回到 KNN 使用的 CIFAR-10 图像分类数据集。
在这里插入图片描述

3.3 理解线性分类器

1) 理解一:W是所有分类器的组合
在这里插入图片描述
如图所示,将小猫的图像像素数据拉伸成一个列向量,这里为方便说明,假设图像只有4个像素(都是黑白像素,不考虑RGB通道),即D=4;有 3个分类(红色代表猫,绿色代表狗,蓝色代表船,颜色仅代表不同类别,和 RGB 通道没有关系),即 K=3。W矩阵乘列向量x得到各个分类的分值。

实际上,我们可以看到,参数矩阵W相当于是三个分类器的组合,W的每一行都是一个分类器,分别对应猫、狗、船。 在线性模型中每个分类器的参数个数与输入图像的维度相当,每个像素和对应的参数相乘,就表示该像素在该分类器中应占的比重

我们可以这样理解,线性分类器会计算图像中 3 个颜色通道中所有像素的值与权重矩阵的乘积,进而得到每个类别分值。根据我们对权重设置的值,对于图像中的某些位置的某些颜色,函数表现出喜好或者厌恶(根据每个权重的符号而定)。

Eg:可以想象 「船」 分类就是被大量的蓝色所包围(对应的就是水)。那么 「船」 分类器在蓝色通道上的权重就有很多的正权重(它们的出现提高了 「船」 分类的分值),而在绿色和红色通道上的权重为负的就比较多(它们的出现降低了 「船」 分类的分值)。

结合上面的小猫示例,猫分类器对第二个位置的像素比较 「厌恶」 ,而恰好输入的小猫图像第二个位置像素值很大,最终计算得到一个很低的分数(当然,这个分类器是错误的)。

2) 理解二:将线性分类器看做模板匹配
把权重W的每一行看作一个分类的模板,一张图像对应不同分类的得分,是通过使用内积(也叫点积)来比较图像和模板,然后找到和哪个模板最相似。

这种理解角度下,线性分类器在利用学习到的模板,和输入图像做模板匹配。我们设置可以把其视作一种高效的KNN,不同的是不再使用所有的训练集的图像来比较,而是每个类别只用了一张图片来表征(这张图片是我们学习到的模板,而不存在训练集中),而且我们会更换度量标准,使用(负)内积来计算向量间的距离,而不是使用 L1 或者 L2 距离。
在这里插入图片描述

上图是以 CIFAR-10 为训练集,学习结束后的权重的例子。可以看到:

  • 马的模板看起来似乎是两个头的马,这是因为训练集中的马的图像中马头朝向各有左右造成的。线性分类器将这两种情况融合到一起了;
  • 汽车的模板看起来也是将几个不同的模型融合到了一个模板中,这个模板上的车是红色的,是因为 CIFAR-10 中训练集的车大多是红色的。- - 线性分类器对于不同颜色的车的分类能力是很弱的,但是后面可以看到神经网络是可以完成这一任务的;
  • 船的模板如期望的那样有很多蓝色像素。如果图像是一艘船行驶在大海上,那么这个模板利用内积计算图像将给出很高的分数。

3) 理解三:将图像看做高维空间的点
既然定义每个分类类别的分值是权重和图像的矩阵乘积,那么每个分类类别的分数就是这个空间中的一个线性函数的函数值。我们没办法可视化3072维空间中的线性函数,但假设把这些维度挤压到二维,那么就可以看看这些分类器在做什么了:
在这里插入图片描述
在上图中,每张输入图片是一个点,不同颜色的线代表 3 个不同的分类器。以红色的汽车分类器为例,红线表示空间中汽车分类分数为0的点的集合,红色的箭头表示分值上升的方向。所有红线右边的点的分数值均为正,且线性升高。红线左边的点分值为负,且线性降低。

从上面可以看到,W 的每一行都是一个分类类别的分类器,对于这些数字的几何解释是:

  • 如果改变 W一行的数字取值,会看见分类器在空间中对应的直线开始向着不同方向旋转。而偏置项b,则允许分类器对应的直线平移。
  • 需要注意的是,如果没有偏置项,无论权重如何,在 x i = 0 x_i = 0 xi=0时分类分值始终为0。这样所有分类器的线都不得不穿过原点。

3.4 偏置项和权重合并

上面的推导过程大家可以看到:实际我们有权重参数W和偏置项参数b 两个参数,分开处理比较冗余,常用的优化方法是把两个参数放到同一个矩阵中,同时列向量 x i x_i xi就要增加一个维度,这个维度的数值是常量1,这就是默认的偏置项维度。

如下图所示,新的公式就简化成如下形式:
在这里插入图片描述
还是以 CIFAR-10 为例,那么 x i x_i xi的大小就变成[3073x1]了,多出了包含常量1的1个维度; W大小就是[10 x 3073] 了,W中多出来的这一列对应的就是偏差值b:

经过这样的处理,最终只需学习一个权重矩阵,无需学习两个分别装着权重和偏差的矩阵。

3.5 图像数据预处理

在上面的例子中,所有图像都是使用的原始像素值(0~255)。在机器学习中,我们经常会对输入的特征做归一化(normalization)处理,对应到图像分类的例子中,图像上的每个像素可以看做一个特征。

在实践中,我们会有对每个特征减去平均值来中心化数据这样一个步骤。

在这些图片的例子中,该步骤是根据训练集中所有的图像计算出一个平均图像值,然后每个图像都减去这个平均值,这样图像的像素值就大约分布在 -127 ~ 127 之间了。

后续可以操作的步骤包括归一化,即让所有数值分布的区间变为 -1 ~ 1。

3.6 线性分类器失效的情形

在这里插入图片描述
线性分类器的分类能力实际是有限的,例如上图中的这三种情形都无法找到合适的直线区分开。其中第 1 个 case 是奇偶分类,第 3 个 case 是有多个模型。

❓那么问题来了?1. 如何找到这个最合适的参数W?答案是定义损失函数并找到可以最小化该损失函数的参数(即优化)。

4. 线性分类:损失函数

4.1 损失函数的概念

在这里插入图片描述

4.2 多类支持向量机损失函数 (Multiclass Support Vector Machine Loss)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
备注:这里的 Δ Δ Δ默认为1,关于这个参数会在下节专门提到!!!

4.3 Softmax损失函数(Multinomial Logistic Regression)

Softmax 分类器可以理解为逻辑回归分类器面对多个分类的一般化归纳,又称为多项式逻辑回归(Multinomial Logistic Regression)。
在这里插入图片描述

最大似然估计

在这里插入图片描述在这里插入图片描述

KL散度

在这里插入图片描述

交叉熵

在这里插入图片描述

4.4 MSVM vs Softmax

Softmax 和 SVM 这两类损失的对比如下图所示:
在这里插入图片描述
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

从第一性原理看大模型Agent技术

本文由下面的内部分享视频文字稿重新整理而成 从第一性原理看大模型Agent技术 引 一个乐观主义者的悲观估计 随着大规模模型技术的兴起,我们正处于一个崭新的智能时代的黎明。我们有一个大胆的预测,未来的5到10年将可能带来一场大变局:99%的…

Java异常:toString()和getMessage()区别

首先写了两个错误 Controller public class DemoController {RequestMapping("/show1")public String showInfo(){String str null;str.length();return "index";}RequestMapping("/show2")public String showInfo2(){int a 10/0;return &quo…

java多线程(并发)夯实之路-synchronized锁升级深入浅出

轻量级锁 使用场景:一个对象有多线程访问,但时间是错开的(如果多线程同时访问,也就是有竞争的,会升级为重量级锁) 轻量级锁对使用者是透明的,语法仍是synchronized 例: 以上的代码…

天津Java开发培训哪家好?选Java培训班要考虑

在当今社会,Java语言在软件开发领域具有举足轻重的地位,Java是一门面向对象编程语言,Java语言集合了C的优点,丢弃了缺点,所以Java语言表现的功能强大而简单易用,已经得到越来越多的应届毕业生和职场新人的认…

智慧公厕创造智能、整洁、舒适环境,让“方便”更方便

在现代城市建设中,智慧公厕已成为一项热点技术。通过物联感知、云管理数据处理和人性化智能设备的融合,智慧公厕让我们的“方便”变得更加方便。不仅实时感知和监控公共厕所的情况,还提升管理效率,为市民提供更人性化的服务。智慧…

Authing 入选中国信通院《 2023 高质量数字化转型产品及服务全景图》

近日,中国信通院“铸基计划”发布了《高质量数字化转型产品及服务全景图( 2023 )》。Authing 身份云成功入选 IT 维护与运营领域并获得证书。 “十四五”时期,我国数字经济转向深化应用、规范发展、普惠共享的新阶段,数字化转型已成为传统企业…

STM32——电容触摸按键充电时间测量实验

1电容触摸按键 无手指触摸:上电时,电阻作用下,电容Cs进行充电,直到电容充满,这时候会有一个充电时间Tcs。 有手指触摸:上电时,电阻作用下,电容Cs和Cx进行充电,电容充满时…

2719. 统计整数数目

给你两个数字字符串 num1 和 num2 &#xff0c;以及两个整数 max_sum 和 min_sum 。如果一个整数 x 满足以下条件&#xff0c;我们称它是一个好整数&#xff1a; num1 < x < num2min_sum < digit_sum(x) < max_sum. 请你返回好整数的数目。答案可能很大&#xff…

jquery(一)

目录 &#x1f338;基本使用 &#x1f341;两大特性 &#x1f338;操作文档 &#x1f338;样式操作 &#x1f338;属性操作 &#x1f338;文档操作 &#x1f341;内部追加 &#x1f340;原来界面 &#x1f340;追加后界面 &#x1f341;外部追加 &#x1f340;原来界…

进阶Docker2:数据卷和挂载目录

目录 准备 删除容器 创建并运行一个容器 数据卷&#xff08;Volumes&#xff09; 挂载数据卷 虚拟机端口映射 挂载目录&#xff08;Bind mounts&#xff09; 挂载目录 挂载文件 部署在线项目 docker 在容器中管理数据主要有两种方式&#xff1a; - 数据卷&#xff0…

陪诊小程序开发|陪诊软件定制|陪诊系统成品功能包含哪些?

陪诊小程序是一种便捷的工具&#xff0c;为用户提供一系列服务和功能&#xff0c;方便患者在就医过程中获得更好的体验和效果。接下来我们将介绍几个主要的陪诊小程序功能。 陪诊小程序开发功能&#xff1a; 一、预约挂号功能。陪诊小程序能够连接用户和医疗机构的系统&#x…

ART-Adversarial Robustness Toolbox检测AI模型及对抗攻击的工具

一、工具简介 Adversarial Robustness Toolbox 是 IBM 研究团队开源的用于检测模型及对抗攻击的工具箱&#xff0c;为开发人员加强 AI模型被误导的防御性&#xff0c;让 AI 系统变得更加安全&#xff0c;ART支持所有流行的机器学习框架 &#xff08;TensorFlow&#xff0c;Ker…

什么是JAVA的包装类?用了有什么好处?

目录 一、包装类概述 二、包装类和基本数据类型的转换 三、使用包装类的ValueOf方法 四、基本类型和包装类的自动转换 一、包装类概述 Java的包装类是为了方便操作基本数据类型而提供的类。Java的基本数据类型&#xff08;如int、char、boolean等&#xff09;是非对象的&a…

【备战蓝桥杯】——Day1

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-xKn7nmq36s9pgUXR {font-family:"trebuchet ms",verdana,arial,sans-serif;font-siz…

Django教程第4章 | Web开发实战-三种验证码实现

系列&#xff1a;Django学习教程 验证码的存在是为了防止系统被暴力破解攻击&#xff0c;几乎每个系统都有验证码。下面将介绍三种生成验证码方式。 您可以根据你自己的需要进行学习。 手动生成验证码 安装绘图依赖&#xff0c;利用的是画图模块 PIL 以及随机模块 random 在后…

python解决求最短路径、最短时间问题

对于一个求最短路径的经常遇到的问题&#xff0c;对于从某一个节点到其余全部节点所需要的最短时间的问题&#xff0c;可以使用广度优先搜索算法的思路来进行解决&#xff0c;这是一个广度优先搜索算法在二维空间的应用。 问题描述为给定一个节点总数为N和一个列表list&#x…

fastadmin答题考试系统开源二次开发带拍照搜题版本

应用介绍 应用介绍 一款基于FastAdminThinkPHPUniapp开发的小程序答题考试系统&#xff0c;提供全部前后台无加密源代码&#xff0c;支持私有化部署 前端截图&#xff1a; 后台截图&#xff1a; 功能介绍&#xff1a;

LeetCode 每日一题 Day 37-43

终于考完试了&#xff0c;寒假期间将会每天持续更新&#xff01; 447. 回旋镖的数量(Day 37) 给定平面上 n 对 互不相同 的点 points &#xff0c;其中 points[i] [xi, yi] 。回旋镖 是由点 (i, j, k) 表示的元组 &#xff0c;其中 i 和 j 之间的欧式距离和 i 和 k 之间的欧…

颜色对话框 QColorDialog

1. 颜色对话框 QColorDialog 1.1 基本函数 QColor getColor(const QColor &initial Qt::white, QWidget *parent nullptr, const QString &title QString(), QColorDialog::ColorDialogOptions options ColorDialogOptions())返回值&#xff1a;QColor&#xff0c;…

SpringBoot+SSM项目实战 苍穹外卖(11) Apache ECharts

继续上一节的内容&#xff0c;本节学习Apache ECharts&#xff0c;实现营业额统计、用户统计、订单统计和销量排名Top10功能。 数据统计效果图&#xff1a; 目录 Apache ECharts入门案例 营业额统计用户统计订单统计销量排名Top10 Apache ECharts Apache ECharts 是一款基于 …