【经典简读】知识蒸馏(Knowledge Distillation) 经典之作

【经典简读】知识蒸馏(Knowledge Distillation) 经典之作

转自:【经典简读】知识蒸馏(Knowledge Distillation) 经典之作

作者:潘小小

知识蒸馏是一种模型压缩方法,是一种基于“教师-学生网络思想”的训练方法,由于其简单,有效,在工业界被广泛应用。这一技术的理论来自于2015年Hinton发表的一篇神作:Distilling the Knowledge in a Neural Network。Knowledge Distillation,简称KD,顾名思义,就是将已经训练好的模型包含的知识(”Knowledge”),蒸馏(“Distill”)提取到另一个模型里面去。今天,我们就来简单读一下这篇论文,力求用简单的语言描述论文作者的主要思想。

在本文中,我们将从背景和动机讲起,然后着重介绍“知识蒸馏”的方法,最后我会讨论“温度“这个名词:

  • 温度: 我们都知道“蒸馏”需要在高温下进行,那么这个“蒸馏”的温度代表了什么,又是如何选取合适的温度?

本文的内容由以下几个部分组成

  1. 介绍

    1. 论文提出的背景
    2. “思想歧路“
  2. 知识蒸馏的理论依据

    1. Teacher Model和Student Model
    2. 知识蒸馏的关键点
    3. softmax函数
  3. 知识蒸馏的具体方法

    1. 通用的知识蒸馏方法
    2. 一种特殊情形: 直接match logits
  4. 关于"温度"的讨论

    1. 温度的特点
    2. 温度代表了什么,如何选取合适的温度?
  5. 参考

1. 介绍

1.1. 论文提出的背景

虽然在一般情况下,我们不会去区分训练和部署使用的模型,但是训练和部署之间存在着一定的不一致性:

  • 在训练过程中,我们需要使用复杂的模型,大量的计算资源,以便从非常大、高度冗余的数据集中提取出信息。在实验中,效果最好的模型往往规模很大,甚至由多个模型集成得到。而大模型不方便部署到服务中去,常见的瓶颈如下:

    1. 推断速度慢
    2. 对部署资源要求高(内存,显存等)
  • 在部署时,我们对延迟以及计算资源都有着严格的限制。

因此,模型压缩(在保证性能的前提下减少模型的参数量)成为了一个重要的问题。而”模型蒸馏“属于模型压缩的一种方法。

插句题外话,我们可以从模型参数量和训练数据量之间的相对关系来理解underfitting和overfitting。AI领域的从业者可能对此已经习以为常,但是为了力求让小白也能读懂本文,还是引用我同事的解释(我印象很深)形象地说明一下:

模型就像一个容器,训练数据中蕴含的知识就像是要装进容器里的水。当数据知识量(水量)超过模型所能建模的范围时(容器的容积),加再多的数据也不能提升效果(水再多也装不进容器),因为模型的表达空间有限(容器容积有限),就会造成underfitting;而当模型的参数量大于已有知识所需要的表达空间时(容积大于水量,水装不满容器),就会造成overfitting,即模型的variance会增大(想象一下摇晃半满的容器,里面水的形状是不稳定的)。

1.2. “思想歧路”

上面容器和水的比喻非常经典和贴切,但是会引起一个误解: 人们在直觉上会觉得,要保留相近的知识量,必须保留相近规模的模型。也就是说,一个模型的参数量基本决定了其所能捕获到的数据内蕴含的“知识”的量。

这样的想法是基本正确的,但是需要注意的是:

  1. 模型的参数量和其所能捕获的“知识“量之间并非稳定的线性关系(下图中的1),而是接近边际收益逐渐减少的一种增长曲线(下图中的2和3)
  2. 完全相同的模型架构和模型参数量,使用完全相同的训练数据,能捕获的“知识”量并不一定完全相同,另一个关键因素是训练的方法。合适的训练方法可以使得在模型参数总量比较小时,尽可能地获取到更多的“知识”(下图中的3与2曲线的对比).

在这里插入图片描述

2. 知识蒸馏的理论依据

2.1. Teacher Model和Student Model

知识蒸馏使用的是Teacher—Student模型,其中teacher是“知识”的输出者,student是“知识”的接受者。知识蒸馏的过程分为2个阶段:

  1. 原始模型训练: 训练"Teacher模型", 简称为Net-T,它的特点是模型相对复杂,也可以由多个分别训练的模型集成而成。我们对"Teacher模型"不作任何关于模型架构、参数量、是否集成方面的限制,唯一的要求就是,对于输入X, 其都能输出Y,其中Y经过softmax的映射,输出值对应相应类别的概率值。
  2. 精简模型训练: 训练"Student模型", 简称为Net-S,它是参数量较小、模型结构相对简单的单模型。同样的,对于输入X,其都能输出Y,Y经过softmax映射后同样能输出对应相应类别的概率值。

在本论文中,作者将问题限定在分类问题下,或者其他本质上属于分类问题的问题,该类问题的共同点是模型最后会有一个softmax层,其输出值对应了相应类别的概率值。

2.2. 知识蒸馏的关键点

如果回归机器学习最最基础的理论,我们可以很清楚地意识到一点(而这一点往往在我们深入研究机器学习之后被忽略): 机器学习最根本的目的在于训练出在某个问题上泛化能力强的模型。

  • 泛化能力强: 在某问题的所有数据上都能很好地反应输入和输出之间的关系,无论是训练数据,还是测试数据,还是任何属于该问题的未知数据。

而现实中,由于我们不可能收集到某问题的所有数据来作为训练数据,并且新数据总是在源源不断的产生,因此我们只能退而求其次,训练目标变成在已有的训练数据集上建模输入和输出之间的关系。由于训练数据集是对真实数据分布情况的采样,训练数据集上的最优解往往会多少偏离真正的最优解(这里的讨论不考虑模型容量)。

而在知识蒸馏时,由于我们已经有了一个泛化能力较强的Net-T,我们在利用Net-T来蒸馏训练Net-S时,可以直接让Net-S去学习Net-T的泛化能力。

一个很直白且高效的迁移泛化能力的方法就是:使用softmax层输出的类别的概率来作为“soft target”。

【KD的训练过程和传统的训练过程的对比】

  1. 传统training过程(hard targets): 对ground truth求极大似然
  2. KD的training过程(soft targets): 用large model的class probabilities作为soft targets

在这里插入图片描述

KD的训练过程为什么更有效?

softmax层的输出,除了正例之外,负标签也带有大量的信息,比如某些负标签对应的概率远远大于其他负标签。而在传统的训练过程(hard target)中,所有负标签都被统一对待。也就是说,KD的训练方式使得每个样本给Net-S带来的信息量大于传统的训练方式

举个例子】

在手写体数字识别任务MNIST中,输出类别有10个。假设某个输入的“2”更加形似"3",softmax的输出值中"3"对应的概率为0.1,而其他负标签对应的值都很小,而另一个"2"更加形似"7","7"对应的概率为0.1。这两个"2"对应的hard target的值是相同的,但是它们的soft target却是不同的,由此我们可见soft target蕴含着比hard target多的信息。并且soft target分布的熵相对高时,其soft target蕴含的知识就更丰富。

在这里插入图片描述

这就解释了为什么通过蒸馏的方法训练出的Net-S相比使用完全相同的模型结构和训练数据只使用hard target的训练方法得到的模型,拥有更好的泛化能力。

2.3. softmax函数

先回顾一下原始的softmax函数:
qi=exp⁡(zi)∑jexp⁡(zj)q_i=\frac{\exp(z_i)}{\sum_j\exp(z_j)} qi=jexp(zj)exp(zi)
但要是直接使用softmax层的输出值作为soft target, 这又会带来一个问题: 当softmax输出的概率分布熵相对较小时,负标签的值都很接近0,对损失函数的贡献非常小,小到可以忽略不计。因此**“温度”**这个变量就派上了用场。

下面的公式时加了温度这个变量之后的softmax函数:
qi=exp⁡(zi/T)∑jexp⁡(zj/T)q_i=\frac{\exp(z_i/T)}{\sum_j\exp(z_j/T)} qi=jexp(zj/T)exp(zi/T)

  • 这里的T就是温度
  • 原来的softmax函数是T = 1的特例。 T越高,softmax的output probability distribution越趋于平滑,其分布的熵越大,负标签携带的信息会被相对地放大,模型训练将更加关注负标签

3. 知识蒸馏的具体方法

3.1. 通用的知识蒸馏方法

  • 第一步是训练Net-T;第二步是在高温T下,蒸馏Net-T的知识到Net-S

在这里插入图片描述

训练Net-T的过程很简单,下面详细讲讲第二步:高温蒸馏的过程。高温蒸馏过程的目标函数由distill loss(对应soft target)和student loss(对应hard target)加权得到。示意图如上。

L=αLsoft+βLhardL=\alpha L_{soft}+\beta L_{hard}L=αLsoft+βLhard

  • viv_ivi: Net-T的logits

  • ziz_izi: Net-S的logits

  • piTp_i^TpiT: Net-T的在温度=T下的softmax输出在第i类上的值

  • qiTq_i^TqiT: Net-S的在温度=T下的softmax输出在第i类上的值

  • cic_ici: 在第i类上的ground truth值, ci∈{0,1}, 正标签取1,负标签取0.

  • NNN: 总标签数量

Net-T 和 Net-S 同时输入 transfer set (这里可以直接复用训练Net-T用到的training set), 用Net-T产生的softmax distribution (with high temperature) 来作为soft target,Net-S在相同温度T条件下的softmax输出和soft target的cross entropy就是Loss函数的第一部分 LsoftL_{soft}Lsoft
Lsoft=−∑jNpjTlog⁡⁡(qjT)L_{soft}=−\sum_j^Np_j^T\log⁡(q_j^T) Lsoft=jNpjTlog(qjT)
其中,piT=exp⁡(vi/T)∑kNexp⁡(vk/T),qiT=exp⁡(zi/T)∑kNexp⁡(zk/T)p_i^T=\frac{\exp(v_i/T)}{\sum_k^N\exp(v_k/T)},\ q_i^T=\frac{\exp(z_i/T)}{\sum_k^N\exp(z_k/T)}piT=kNexp(vk/T)exp(vi/T), qiT=kNexp(zk/T)exp(zi/T)

Net-S在T=1的条件下的softmax输出和ground truth的cross entropy就是Loss函数的第二部分 LhardL_{hard}Lhard
Lhard=−∑jNcjlog⁡(qjT=1)L_{hard}=-\sum_j^Nc_j\log(q_j^{T=1}) Lhard=jNcjlog(qjT=1)
其中,qjT=1=exp⁡(zi)∑kNexp⁡(zk)q^{T=1}_j=\frac{\exp(z_i)}{\sum_k^N\exp(z_k)}qjT=1=kNexp(zk)exp(zi)

第二部分Loss LhardL_{hard}Lhard 的必要性其实很好理解: Net-T也有一定的错误率,使用ground truth可以有效降低错误被传播给Net-S的可能。打个比方,老师虽然学识远远超过学生,但是他仍然有出错的可能,而这时候如果学生在老师的教授之外,可以同时参考到标准答案,就可以有效地降低被老师偶尔的错误“带偏”的可能性。

【讨论】

实验发现第二部分所占比重比较小的时候,能产生最好的结果,这是一个经验的结论。一个可能的原因是,由于soft target产生的gradient与hard target产生的gradient之间有与 T 相关的比值。原论文中只是一笔带过,我在下面补充了一些简单的推导。(ps. 下面推导可能有些错误,如果有读者能够正确推出来请私信我~)

Soft Target
Lsoft=−∑jNpjTlog⁡(qjT)=−∑jNzj/T×exp⁡(vj/T)∑kNexp⁡(vk/T)(1∑kNexp⁡(zk/T)−exp⁡(zj/T)(∑kNexp⁡(zk/T))2)≈−1T∑kNexp⁡(vk/T)(∑jNzjexp⁡(vj/T)∑kNexp⁡(zk/T)−∑jNzjexp⁡(zj/T)exp⁡(vj/T)(∑kNexp⁡(zk/T))2)\begin{aligned} L_{soft}&=-\sum_j^Np_j^T\log(q_j^T)\\ &=-\sum_j^N\frac{z_j/T\times\exp(v_j/T)}{\sum_k^N\exp(v_k/T)}(\frac{1}{\sum_k^N\exp(z_k/T)}-\frac{\exp(z_j/T)}{(\sum_k^N\exp(z_k/T))^2})\\ &\approx-\frac{1}{T\sum_k^N\exp(v_k/T)}(\frac{\sum_j^Nz_j\exp(v_j/T)}{\sum_k^N\exp(z_k/T)}-\frac{\sum_j^Nz_j\exp(z_j/T)\exp(v_j/T)}{(\sum_k^N\exp(z_k/T))^2}) \end{aligned} Lsoft=jNpjTlog(qjT)=jNkNexp(vk/T)zj/T×exp(vj/T)(kNexp(zk/T)1(kNexp(zk/T))2exp(zj/T))TkNexp(vk/T)1(kNexp(zk/T)jNzjexp(vj/T)(kNexp(zk/T))2jNzjexp(zj/T)exp(vj/T))
Hard Target
Lhard=−∑jNcjlog⁡(qjT=1)=−(∑jNcjzj∑kNexp⁡(zk)−∑jNcjzjexp⁡(zj)(∑kNexp⁡(zk))2)L_{hard}=-\sum_j^Nc_j\log(q^{T=1}_j)=-(\frac{\sum_j^Nc_jz_j}{\sum_{k}^N\exp(z_k)}-\frac{\sum_j^Nc_jz_j\exp(z_j)}{(\sum_k^N\exp(z_k))^2}) Lhard=jNcjlog(qjT=1)=(kNexp(zk)jNcjzj(kNexp(zk))2jNcjzjexp(zj))
由于 ∂Lsoft∂zi\frac{\partial{L_{soft}}}{\partial{z_i}}ziLsoft 的magnitude大约是 ∂Lhard∂zi\frac{\partial{L_{hard}}}{\partial{z_i}}ziLhard1T2\frac{1}{T^2}T21 ,因此在同时使用soft target和hard target的时候,需要在soft target之前乘上 T2T^2T2 的系数,这样才能保证soft target和hard target贡献的梯度量基本一致。

【注意】 在Net-S训练完毕后,做inference时其softmax的温度T要恢复到1.

3.2. 一种特殊情形: 直接match logits(不经过softmax)

直接match logits指的是,直接使用softmax层的输入logits(而不是输出)作为soft targets,需要最小化的目标函数是Net-T和Net-S的logits之间的平方差。

直接上结论: 直接match logits的做法是 T→∞T\rightarrow\inftyT 的情况下的特殊情形。

由单个case贡献的loss,推算出对应在Net-S每个logit ziz_izi上的gradient:
∂Lsoft∂zi=1T(qi−pi)=1T(exp⁡(zi/T)∑jexp⁡(zj/T)−exp⁡(vi/T)∑jexp⁡(vj/T))\frac{\partial{L_{soft}}}{\partial z_i}=\frac{1}{T}(q_i-p_i)=\frac{1}{T}(\frac{\exp(z_i/T)}{\sum_j\exp(z_j/T)}-\frac{\exp(v_i/T)}{\sum_j\exp(v_j/T)}) ziLsoft=T1(qipi)=T1(jexp(zj/T)exp(zi/T)jexp(vj/T)exp(vi/T))
T→∞T\rightarrow \inftyT 时,我们使用 1+x/T1+x/T1+x/T 来近似 exp⁡(x/T)\exp(x/T)exp(x/T) ,于是得到
∂Lsoft∂zi≈1T(1+zi/TN+∑jzj/T−1+vi/TN+∑jvj/T)\frac{\partial L_{soft}}{\partial z_i}\approx\frac{1}{T}(\frac{1+z_i/T}{N+\sum_jz_j/T}-\frac{1+v_i/T}{N+\sum_jv_j/T}) ziLsoftT1(N+jzj/T1+zi/TN+jvj/T1+vi/T)
如果再加上 logits 是零均值的假设 ∑jzj=∑jvj=0\sum_jz_j=\sum_jv_j=0jzj=jvj=0 。那么上面的公式可以简化成:
∂Lsoft∂zi≈1NT2(zi−vi)\frac{\partial L_{soft}}{\partial z_i}\approx\frac{1}{NT^2}(z_i-v_i) ziLsoftNT21(zivi)
等价于 minimize 以下损失函数
Lsoft′=1/2(zi−vi)2L'_{soft}={1}/{2}(z_i-v_i)^2 Lsoft=1/2(zivi)2

4. 关于"温度"的讨论

【问题】 我们都知道“蒸馏”需要在高温下进行,那么这个“蒸馏”的温度代表了什么,又是如何选取合适的温度?如下图所示,随着温度T的增大,概率分布的熵逐渐增大。

在这里插入图片描述

4.1. 温度的特点

在回答这个问题之前,先讨论一下温度T的特点

  1. 原始的softmax函数是 T=1 时的特例, T<1 时,概率分布比原始更“陡峭”, T>1 时,概率分布比原始更“平缓”。
  2. 温度越高,softmax上各个值的分布就越平均(思考极端情况: (i) T=∞\infty , 此时softmax的值是平均分布的;(ii) T=0,此时softmax的值就相当于 argmax , 即最大的概率处的值趋近于1,而其他值趋近于0)
  3. 不管温度T怎么取值,Soft target都有忽略相对较小的 pip_ipi 携带的信息的倾向

4.2. 温度代表了什么,如何选取合适的温度?

温度的高低改变的是Net-S训练过程中对负标签的关注程度: 温度较低时,对负标签的关注,尤其是那些显著低于平均值的负标签的关注较少;而温度较高时,负标签相关的值会相对增大,Net-S会相对多地关注到负标签。

实际上,负标签中包含一定的信息,尤其是那些值显著高于平均值的负标签。但由于Net-T的训练过程决定了负标签部分比较noisy,并且负标签的值越低,其信息就越不可靠。因此温度的选取比较empirical,本质上就是在下面两件事之中取舍:

  1. 从有部分信息量的负标签中学习 --> 温度要高一些
  2. 防止受负标签中噪声的影响 -->温度要低一些

总的来说,T的选择和Net-S的大小有关,Net-S参数量比较小的时候,相对比较低的温度就可以了(因为参数量小的模型不能capture all knowledge,所以可以适当忽略掉一些负标签的信息)

5. 参考

  1. 深度压缩之蒸馏模型 - 风雨兼程的文章 - 知乎 https://zhuanlan.zhihu.com/p/24337627
  2. 知识蒸馏Knowledge Distillation - 船长的文章 - 知乎 https://zhuanlan.zhihu.com/p/83456418
  3. https://towardsdatascience.com/knowledge-distillation-simplified-dd4973dbc764
  4. https://nervanasystems.github.io/distiller/knowledge_distillation.html

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

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

相关文章

深度学习三大谜团:集成、知识蒸馏和自蒸馏

深度学习三大谜团&#xff1a;集成、知识蒸馏和自蒸馏 转自&#xff1a;https://mp.weixin.qq.com/s/DdgjJ-j6jHHleGtq8DlNSA 原文&#xff08;英&#xff09;&#xff1a;https://www.microsoft.com/en-us/research/blog/three-mysteries-in-deep-learning-ensemble-knowledge…

在墙上找垂直线_墙上如何快速找水平线

在装修房子的时候&#xff0c;墙面的面积一般都很大&#xff0c;所以在施工的时候要找准水平线很重要&#xff0c;那么一般施工人员是如何在墙上快速找水平线的呢&#xff1f;今天小编就来告诉大家几种找水平线的方法。一、如何快速找水平线1、用一根透明的软管&#xff0c;长度…

Vision Transformer(ViT)PyTorch代码全解析(附图解)

Vision Transformer&#xff08;ViT&#xff09;PyTorch代码全解析 最近CV领域的Vision Transformer将在NLP领域的Transormer结果借鉴过来&#xff0c;屠杀了各大CV榜单。本文将根据最原始的Vision Transformer论文&#xff0c;及其PyTorch实现&#xff0c;将整个ViT的代码做一…

Linux下的ELF文件、链接、加载与库(含大量图文解析及例程)

Linux下的ELF文件、链接、加载与库 链接是将将各种代码和数据片段收集并组合为一个单一文件的过程&#xff0c;这个文件可以被加载到内存并执行。链接可以执行与编译时&#xff0c;也就是在源代码被翻译成机器代码时&#xff1b;也可以执行于加载时&#xff0c;也就是被加载器加…

java 按钮 监听_Button的四种监听方式

Button按钮设置点击的四种监听方式注&#xff1a;加粗放大的都是改变的代码1.使用匿名内部类的形式进行设置使用匿名内部类的形式&#xff0c;直接将需要设置的onClickListener接口对象初始化&#xff0c;内部的onClick方法会在按钮被点击的时候执行第一个活动的java代码&#…

linux查看java虚拟机内存_深入理解java虚拟机(linux与jvm内存关系)

本文转载自美团技术团队发表的同名文章https://tech.meituan.com/linux-jvm-memory.html一, linux与进程内存模型要理解jvm最重要的一点是要知道jvm只是linux的一个进程,把jvm的视野放大,就能很好的理解JVM细分的一些概念下图给出了硬件系统进程三个层面内存之间的关系.从硬件上…

java function void_Java8中你可能不知道的一些地方之函数式接口实战

什么时候可以使用 Lambda&#xff1f;通常 Lambda 表达式是用在函数式接口上使用的。从 Java8 开始引入了函数式接口&#xff0c;其说明比较简单&#xff1a;函数式接口(Functional Interface)就是一个有且仅有一个抽象方法&#xff0c;但是可以有多个非抽象方法的接口。 java8…

java jvm内存地址_JVM--Java内存区域

Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域&#xff0c;如图&#xff1a;1.程序计数器可以看作是当前线程所执行的字节码的行号指示器&#xff0c;通俗的讲就是用来指示执行哪条指令的。为了线程切换后能恢复到正确的执行位置Java多线程是…

java情人节_情人节写给女朋友Java Swing代码程序

马上又要到情人节了&#xff0c;再不解风情的人也得向女友表示表示。作为一个程序员&#xff0c;示爱的时候自然也要用我们自己的方式。这里给大家上传一段我在今年情人节的时候写给女朋友的一段简单的Java Swing代码&#xff0c;主要定义了一个对话框&#xff0c;让女友选择是…

java web filter链_filter过滤链:Filter链是如何构建的?

在一个Web应用程序中可以注册多个Filter程序&#xff0c;每个Filter程序都可以针对某一个URL进行拦截。如果多个Filter程序都对同一个URL进行拦截&#xff0c;那么这些Filter就会组成一个Filter链(也叫过滤器链)。Filter链用FilterChain对象来表示&#xff0c;FilterChain对象中…

java final static_Java基础之final、static关键字

一、前言关于这两个关键字&#xff0c;应该是在开发工作中比较常见的&#xff0c;使用频率上来说也比较高。接口中、常量、静态方法等等。但是&#xff0c;使用频繁却不代表一定是能够清晰明白的了解&#xff0c;能说出个子丑演卯来。下面&#xff0c;对这两个关键字的常见用法…

java语言错误的是解释运行的_Java基础知识测试__A卷_答案

考试宣言:同学们, 考试考多少分不是我们的目的! 排在班级多少的名次也不是我们的初衷!我的考试的目的是要通过考试中的题目,检查大家在这段时间的学习中,是否已经把需要掌握的知识掌握住了,如果哪道题目你不会做,又或者做错了, 那么不用怕, 考完试后, 导师讲解的时候你要注意听…

java 持续集成工具_Jenkins-Jenkins(持续集成工具)下载 v2.249.2官方版--pc6下载站

Jenkins是一款基于java开发的持续集成工具&#xff0c;是一款开源软件&#xff0c;主要用于监控持续重复的工作&#xff0c;为开发者提供一个开发易用的软件平台&#xff0c;使软件的持续集成变成可能。。相关软件软件大小版本说明下载地址Jenkins是一款基于java开发的持续集成…

java中线程调度遵循的原则_深入理解Java多线程核心知识:跳槽面试必备

多线程相对于其他 Java 知识点来讲&#xff0c;有一定的学习门槛&#xff0c;并且了解起来比较费劲。在平时工作中如若使用不当会出现数据错乱、执行效率低(还不如单线程去运行)或者死锁程序挂掉等等问题&#xff0c;所以掌握了解多线程至关重要。本文从基础概念开始到最后的并…

java类构造方法成员方法练习_面向对象方法论总结 练习(一)

原标题&#xff1a;面向对象方法论总结 & 练习(一)学习目标1.面向对象与面向过程2.类与对象的概念3.类的定义&#xff0c;对象的创建和使用4.封装5.构造方法6.方法的重载内容1.面向对象与面向过程为什么会出现面向对象反分析方法&#xff1f;因为现实世界太复杂多变&#x…

mysql 统计查询不充电_MySql查询语句介绍,单表查询,来充电吧

mysql在网站开发中&#xff0c;越来越多人使用了&#xff0c;方便部署&#xff0c;方便使用。我们要掌握mysql,首先要学习查询语句。查询单个表的数据&#xff0c;和多个表的联合查询。下面以一些例子来先简单介绍下单表查询。操作方法01首先看下我们例子用到的数据表&#xff…

MySQL线上优化_线上MySQL千万级大表,如何优化?

前段时间应急群有客服反馈&#xff0c;会员管理功能无法按到店时间、到店次数、消费金额进行排序。经过排查发现是 SQL 执行效率低&#xff0c;并且索引效率低下。图片来自 Pexels应急问题商户反馈会员管理功能无法按到店时间、到店次数、消费金额进行排序&#xff0c;一直转圈…

php创建表设置编码,教您在Zend Framework里如何设置数据库编码以及怎样给数据表设定前缀!...

当我们在开发项目时..大家都会遇到一个问题就是:数据库的编码问题.当然我们不用Zend Framework做为项目开发的框架时..我们可以很快,很容易搞定这个小问题..但是当我们要使用Zend Framewok开发项目时..我们可能一时会不知道如何解决这个小问题..比如我就是这样的人..在开发这个…

python 怎么将数组转为列表_怎么将视频转为GIF动态图 表情包怎么制作

说到GIF&#xff0c;大家应该都不陌生了吧&#xff01;尤其是在聊天中使用较多&#xff0c;似乎一言不合就开启了斗图模式&#xff0c;但是我们平时使用的GIF一般都是软件中自带的&#xff0c;其实自己制作也是很方便的&#xff0c;而且会发现很有趣&#xff0c;不但可以直接录…

proteus里面没有stm32怎么办_嵌入式单片机之stm32串口你懂了多少!!

stm32作为现在嵌入式物联网单片机行业中经常要用多的技术&#xff0c;相信大家都有所接触&#xff0c;今天这篇就给大家详细的分析下有关于stm32的出口&#xff0c;还不是很清楚的朋友要注意看看了哦&#xff0c;在最后还会为大家分享有些关于stm32的视频资料便于学习参考。点击…