【机器学习】P18 反向传播(导数、微积分、链式法则、前向传播、后向传播流程、神经网络)

news2024/11/28 2:56:22

反向传播

  • 反向传播
  • 反向传播中的数学
    • 导数与python
    • 链式法则
  • 简单神经网络处理流程从而理解反向传播
    • 神经网络与前向传播
    • 神经网络与反向传播

反向传播

反向传播(back propagation)是一种用于训练神经网络的算法,其作用是计算神经网络中每个参数对损失函数的影响,从而进行参数更新,使得神经网络的预测结果更加准确。

具体来说,反向传播算法首先通过前向传播计算神经网络的预测结果,并与实际结果进行比较,得到损失函数的值。然后,反向传播算法计算每个参数对损失函数的影响,即参数的梯度。这些梯度可以告诉我们,在当前的参数取值下,将参数向梯度的相反方向移动可以减少损失函数的值。最后,通过梯度下降等优化算法,可以更新神经网络中的参数,使得损失函数的值逐渐减小,直到达到最小值。

上述涉及到两个主要公式:

  • 损失函数公式:
    J ( w , b ) = 1 2 m ∑ i = 0 m − 1 ( f w , b ( x ( i ) ) − y ( i ) ) J(w,b) = \frac 1 {2m} \sum _{i=0} ^{m-1} (f_{w,b}(x^{(i)})-y^{(i)}) J(w,b)=2m1i=0m1(fw,b(x(i))y(i))

  • 梯度下降公式:
    { w j = w j − α ∂ J ( w , b ) ∂ w j b = b − α ∂ J ( w , b ) ∂ b \begin{cases} w_j = w_j - \alpha \frac {\partial J(w,b)} {\partial w_j}\\ \\ b = b - \alpha \frac {\partial J(w,b)} {\partial b} \end{cases} wj=wjαwjJ(w,b)b=bαbJ(w,b)
    其中
    { ∂ J ( w , b ) ∂ w j = 1 m ∑ i = 0 m − 1 ( f w , b ( x ( i ) ) − y ( i ) ) x j ( i ) ∂ J ( w , b ) ∂ b = 1 m ∑ i = 0 m − 1 ( f w , b ( x ( i ) ) − y ( i ) ) \begin{cases} \frac {\partial J(w,b)} {\partial w_j} = \frac 1 m \sum _{i=0} ^{m-1} (f_{w,b}(x^{(i)})-y^{(i)})x_j^{(i)}\\ \\ \frac {\partial J(w,b)} {\partial b} = \frac 1 m \sum _{i=0} ^{m-1} (f_{w,b}(x^{(i)})-y^{(i)}) \end{cases} wjJ(w,b)=m1i=0m1(fw,b(x(i))y(i))xj(i)bJ(w,b)=m1i=0m1(fw,b(x(i))y(i))

反向传播算法的作用是实现神经网络的自动学习。通过反向传播算法,神经网络可以从大量的训练样本中学习到数据的特征,并将这些特征表示为神经网络中的参数。这些参数可以在新的数据样本中进行预测,并且可以通过监督学习中的反向传播算法进行更新,以逐渐提高神经网络的预测准确率。

小结:

反向传播,目的就是为了实现神经网络的自动学习。

在整个优化模型参数的流程中,我们首先通过正向传播,得到预测值,通过损失函数公式计算损失值,通过反向传播算法可以计算每个神经元对损失函数的贡献,然后将这些贡献反向传播回网络中的每个神经元,从而确定每个神经元的梯度。然后可以使用梯度下降算法或其他优化算法来更新神经网络的参数,以最小化损失函数。这个过程就是通过反向传播计算梯度,再使用优化算法来更新模型参数的过程。


反向传播中的数学

反向传播用到了很多数学知识,最主要比如导数的计算以及微积分中的链式法则:

导数与python

e . g . 1 e.g.1 e.g.1

∂ J ( w ) ∂ w \frac {\partial J(w)} {\partial w} wJ(w) J ( w ) = w 2 J(w) = w^2 J(w)=w2

from sympy import symbols, diff

J, w = symbols('J,w')
J = w ** 2
dj_dw = diff(J,w)
print(dj_dw)

结果:

在这里插入图片描述


e . g . 2 e.g.2 e.g.2

∂ J ( w ) ∂ w \frac {\partial J(w)} {\partial w} wJ(w) J ( w ) = 1 w J(w) = \frac 1 w J(w)=w1

from sympy import symbols, diff

J, w = symbols('J,w')
J = 1/w
dj_dw = diff(J,w)
print(dj_dw)

结果:

在这里插入图片描述


e . g . 3 e.g.3 e.g.3

∂ J ( w ) ∂ w \frac {\partial J(w)} {\partial w} wJ(w) J ( w ) = 1 w 2 J(w) = \frac 1 {w^2} J(w)=w21

from sympy import symbols, diff

J, w = symbols('J,w')
J = 1/w**2
dj_dw = diff(J,w)
print(dj_dw)

结果:

在这里插入图片描述


链式法则

假设我们有一个函数 f ( x ) f(x) f(x),即 f ( x ) = h ( g ( x ) ) f(x) = h(g(x)) f(x)=h(g(x)),其中:

  • g ( x ) = 2 x + 3 g(x) = 2x + 3 g(x)=2x+3
  • h ( y ) = y 3 + 5 y h(y) = y^3 + 5y h(y)=y3+5y

现在我们想计算 f ( x ) f(x) f(x) 关于 x x x 的导数,即 d f d x \frac {df} {dx} dxdf

根据链式法则,有:

d f d x = d f d g ∗ d g d x \frac {df} {dx} = \frac {df} {dg} * \frac {dg} {dx} dxdf=dgdfdxdg

其中, d f d g \frac {df} {dg} dgdf 表示 f f f 关于 g g g 的导数, d g d x \frac {dg} {dx} dxdg 表示 g g g 关于 x x x 的导数。

  • 首先计算 d f d g \frac {df} {dg} dgdf。因为 f ( x ) = h ( g ( x ) ) f(x) = h(g(x)) f(x)=h(g(x)),所以:
    d f d g = h ′ ( g ( x ) ) = 3 ∗ g ( x ) 2 + 5 \frac {df} {dg} = h'(g(x)) = 3*g(x)^2 + 5 dgdf=h(g(x))=3g(x)2+5

  • g ( x ) = 2 x + 3 g(x) = 2x+3 g(x)=2x+3
    d f d g = 3 ∗ ( 2 x + 3 ) 2 + 5 \frac {df} {dg} = 3*(2x + 3)^2 + 5 dgdf=3(2x+3)2+5

  • 然后计算 d g d x \frac {dg} {dx} dxdg。因为 g ( x ) = 2 x + 3 g(x) = 2x + 3 g(x)=2x+3,所以
    d g d x = 2 \frac {dg} {dx} = 2 dxdg=2

  • 根据链式法则,有:
    d f d x = d f d g ∗ d g d x = ( 3 ( 2 x + 3 ) 2 + 5 ) ∗ 2 = 6 ( 2 x + 3 ) 2 + 10 \frac {df}{dx} = \frac {df}{dg} * \frac {dg} {dx} = (3(2x + 3)^2 + 5) * 2 = 6(2x+3)^2+10 dxdf=dgdfdxdg=(3(2x+3)2+5)2=6(2x+3)2+10
    因此, f ( x ) f(x) f(x) 关于 x x x 的导数为 6 ( 2 x + 3 ) 2 + 10 6(2x+3)^2+10 6(2x+3)2+10


简单神经网络处理流程从而理解反向传播

神经网络与前向传播

在这里插入图片描述

一个简单的神经网路如上图,假定我们使用 ReLU 作为激活函数,

我们可以使用前向传播推出损失函数值

假设最初参数设定为:

  • w [ 1 ] = 2 , b [ 1 ] = 0 w^{[1]}=2, b^{[1]} = 0 w[1]=2,b[1]=0
  • w [ 2 ] = 3 , b [ 2 ] = 1 w^{[2]}=3, b^{[2]}=1 w[2]=3,b[2]=1

假定初始输入层值设定为:

  • x = 1 x = 1 x=1
  • y = 5 y = 5 y=5

根据神经网络计算公式,有:

a [ 1 ] = g ( w [ 1 ] x + b [ 1 ] ) = g ( 2 ∗ 1 + 0 ) = 2 a^{[1]} = g(w^{[1]}x + b^{[1]})=g(2*1 + 0)=2 a[1]=g(w[1]x+b[1])=g(21+0)=2 a [ 2 ] = g ( w [ 2 ] a [ 1 ] + b [ 2 ] ) = g ( 3 ∗ 2 + 1 ) = 7 a^{[2]} = g(w^{[2]}a^{[1]} + b^{[2]})=g(3*2+1)=7 a[2]=g(w[2]a[1]+b[2])=g(32+1)=7

由实际值 y = 5 y = 5 y=5 与预测值 a [ 2 ] = 7 a^{[2]}=7 a[2]=7,得损失函数:
J ( w , b ) = 1 2 ( a [ 2 ] − y ) 2 = 1 2 ( 7 − 5 ) 2 = 2 J(w,b) = \frac 1 2 (a^{[2]}-y)^2=\frac 1 2 (7-5)^2=2 J(w,b)=21(a[2]y)2=21(75)2=2

我们可以将上述前向传播过程分解为如下步骤流程

在这里插入图片描述
到这里,稍微停顿一下,思考在神经网络中,我们的下一步要做什么?

反向传播,更新参数,从而使得预测值 a [ 2 ] = 7 a^{[2]}=7 a[2]=7 更加趋近于实际值 y = 5 y=5 y=5


神经网络与反向传播

神经网络 反向传播 梯度下降 链式法则

上述已经完成了前向传播的部分,我们剩下将使用反向传播方法,计算每个参数的梯度,然后使用梯度下降的方法更新参数。

其实到这里,我相信读者都记得这两个公式:

  • 计算梯度的公式:
    { ∂ J ( w , b ) ∂ w j = 1 m ∑ i = 0 m − 1 ( f w , b ( x ( i ) ) − y ( i ) ) x j ( i ) ∂ J ( w , b ) ∂ b = 1 m ∑ i = 0 m − 1 ( f w , b ( x ( i ) ) − y ( i ) ) \begin{cases} \frac {\partial {J(w,b)}} {\partial {w_j}} = \frac 1 m \sum _{i=0} ^{m-1} (f_{w,b}(x^{(i)})-y^{(i)})x_j^{(i)}\\ \\ \frac {\partial {J(w,b)}} {\partial {b}} = \frac 1 m \sum _{i=0} ^{m-1} (f_{w,b}(x^{(i)})-y^{(i)}) \end{cases} wjJ(w,b)=m1i=0m1(fw,b(x(i))y(i))xj(i)bJ(w,b)=m1i=0m1(fw,b(x(i))y(i))

  • 更新参数公式:
    { w j = w j − α ∂ J ( w , b ) ∂ w j b = b − α ∂ J ( w , b ) ∂ b \begin{cases} w_j = w_j - \alpha \frac {\partial {J(w,b)}} {\partial w_j}\\ \\ b = b - \alpha \frac {\partial {J(w,b)}} {\partial b} \end{cases} wj=wjαwjJ(w,b)b=bαbJ(w,b)

读者也都知道:

  • 梯度下降目的是为了最小化损失函数;
  • 在每个迭代步骤中,我们首先计算损失函数关于每个参数的梯度,然后根据梯度的方向和大小,调整参数的值,以使损失函数的值减少。这个过程会不断迭代,直到达到预定的停止条件;
  • 反向传播更新神经网络参数;
  • 链式法则是什么;

但是就是总感觉差点什么?画图来说:

在这里插入图片描述

其实就是少了一句非常重要的话:

  • 梯度下降更新参数,只直接更新输出层参数,而隐藏层的参数,我们通过链式法则 “间接” 更新

在本案例中,我们存在一个隐藏层(且隐藏层中也只包含一个神经网络),一个输出层(输出层中只包含一个神经网络),即:

对于输出层参数 w [ 2 ] , b [ 2 ] w^{[2]}, b^{[2]} w[2],b[2] 的更新,我们通过梯度下降直接更新:

  • 计算梯度:
    { ∂ J ∂ w [ 2 ] = ( 7 − 5 ) ∗ 7 = 14 ∂ J ∂ b [ 2 ] = 7 − 5 = 2 \begin{cases} \frac {\partial {J}} {\partial {w^{[2]}}} = (7-5)*7=14\\ \\ \frac {\partial {J}} {\partial {b^{[2]}}} = 7-5=2 \end{cases} w[2]J=(75)7=14b[2]J=75=2
  • 更新参数:
    { w [ 2 ] = w [ 2 ] − α ∂ J ( w , b ) ∂ w [ 2 ] = 3 − 14 ∗ α b [ 2 ] = b [ 2 ] − α ∂ J ( w , b ) ∂ b [ 2 ] = 1 − 2 ∗ α \begin{cases} w^{[2]} = w^{[2]} - \alpha \frac {\partial {J(w,b)}} {\partial w^{[2]}} = 3-14*\alpha\\ \\ b^{[2]} = b^{[2]} - \alpha \frac {\partial {J(w,b)}} {\partial b^{[2]}} = 1-2*\alpha \end{cases} w[2]=w[2]αw[2]J(w,b)=314αb[2]=b[2]αb[2]J(w,b)=12α

上述步骤就是通过梯度下降法,更新输出层参数 w [ 2 ] w^{[2]} w[2] b [ 2 ] b^{[2]} b[2] 的步骤;

而对于隐藏层的参数 w [ 1 ] , b [ 1 ] w^{[1]}, b^{[1]} w[1],b[1] 的更新,我们需要通过链式法则传递间接计算梯度,然后更新:

  • 间接计算梯度:
    { ∂ J ∂ w [ 1 ] = ∂ J ∂ a [ 2 ] ∂ a [ 2 ] ∂ a [ 1 ] ∂ a [ 1 ] ∂ w [ 1 ] ∂ J ∂ b [ 1 ] = ∂ J ∂ a [ 2 ] ∂ a [ 2 ] ∂ a [ 1 ] ∂ a [ 1 ] ∂ b [ 1 ] \begin{cases} \frac {\partial {J}} {\partial {w^{[1]}}} = \frac {\partial J} {\partial a^{[2]}} \frac {\partial a^{[2]}} {\partial a^{[1]}} \frac {\partial a^{[1]}} {\partial w^{[1]}}\\ \\ \frac {\partial {J}} {\partial {b^{[1]}}} = \frac {\partial J} {\partial a^{[2]}} \frac {\partial a^{[2]}} {\partial a^{[1]}} \frac {\partial a^{[1]}} {\partial b^{[1]}} \end{cases} w[1]J=a[2]Ja[1]a[2]w[1]a[1]b[1]J=a[2]Ja[1]a[2]b[1]a[1]

  • 由:
    J = 1 2 ( a [ 2 ] − y ) 2 J = \frac 1 2 (a^{[2]}-y)^2\\ J=21(a[2]y)2 a [ 2 ] = g ( w [ 2 ] a [ 1 ] + b [ 2 ] ) a^{[2]} = g(w^{[2]}a^{[1]}+b^{[2]})\\ a[2]=g(w[2]a[1]+b[2]) g ( z ) = m a x ( 0 , z ) ( R e L U ) g(z) = max(0,z)(ReLU)\\ g(z)=max(0,z)(ReLU) a [ 1 ] = g ( w [ 1 ] x + b [ 1 ] ) a^{[1]} = g(w^{[1]}x+b^{[1]}) a[1]=g(w[1]x+b[1])

  • 所以:
    ∂ J ∂ a [ 2 ] = a [ 2 ] − y \frac {\partial J} {\partial a^{[2]}} = a^{[2]}-y a[2]J=a[2]y ∂ a [ 2 ] ∂ a [ 1 ] = w [ 2 ] \frac {\partial a^{[2]}} {\partial a^{[1]}} = w^{[2]} a[1]a[2]=w[2] ∂ a [ 1 ] ∂ w [ 1 ] = x \frac {\partial a^{[1]}} {\partial w^{[1]}} = x w[1]a[1]=x ∂ a [ 1 ] ∂ b [ 1 ] = 1 \frac {\partial a^{[1]}} {\partial b^{[1]}} = 1 b[1]a[1]=1

  • 即:
    ∂ J ∂ w [ 1 ] = ∂ J ∂ a [ 2 ] ∂ a [ 2 ] ∂ a [ 1 ] ∂ a [ 1 ] ∂ w [ 1 ] = ( a [ 2 ] − y ) ∗ w [ 2 ] ∗ x = ( 7 − 5 ) ∗ 3 ∗ 1 = 6 \frac {\partial {J}} {\partial {w^{[1]}}} = \frac {\partial J} {\partial a^{[2]}} \frac {\partial a^{[2]}} {\partial a^{[1]}} \frac {\partial a^{[1]}} {\partial w^{[1]}} = (a^{[2]}-y)*w^{[2]}*x = (7-5)*3*1=6 w[1]J=a[2]Ja[1]a[2]w[1]a[1]=(a[2]y)w[2]x=(75)31=6 ∂ J ∂ b [ 1 ] = ∂ J ∂ a [ 2 ] ∂ a [ 2 ] ∂ a [ 1 ] ∂ a [ 1 ] ∂ b [ 1 ] = ( a [ 2 ] − y ) ∗ w [ 2 ] ∗ 1 = ( 7 − 5 ) ∗ 3 ∗ 1 = 6 \frac {\partial {J}} {\partial {b^{[1]}}} = \frac {\partial J} {\partial a^{[2]}} \frac {\partial a^{[2]}} {\partial a^{[1]}} \frac {\partial a^{[1]}} {\partial b^{[1]}} = (a^{[2]}-y)*w^{[2]}*1 = (7-5)*3*1=6 b[1]J=a[2]Ja[1]a[2]b[1]a[1]=(a[2]y)w[2]1=(75)31=6

  • 修改参数值:
    { w [ 1 ] = w [ 1 ] − α ∂ J ( w , b ) ∂ w [ 1 ] = 2 − 6 ∗ α b [ 1 ] = b [ 1 ] − α ∂ J ( w , b ) ∂ b [ 2 ] = 0 − 6 ∗ α \begin{cases} w^{[1]} = w^{[1]} - \alpha \frac {\partial {J(w,b)}} {\partial w^{[1]}} = 2-6*\alpha\\ \\ b^{[1]} = b^{[1]} - \alpha \frac {\partial {J(w,b)}} {\partial b^{[2]}} = 0-6*\alpha \end{cases} w[1]=w[1]αw[1]J(w,b)=26αb[1]=b[1]αb[2]J(w,b)=06α

上述过程就是通过链式法则,结合梯度下降法来更新参数 w [ 1 ] w^{[1]} w[1] 与 参数 b [ 1 ] b^{[1]} b[1] 的值;

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

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

相关文章

【Java虚拟机】JVM核心基础和常见参数实战

1.新版JVM内存组成部分和堆空间分布 JVM内存的5大组成(基于JDK8的HotSpot虚拟机,不同虚拟机不同版本会有不一样) 名称作用特点程序计数器也叫PC寄存器,用于记录当前线程执行的字节码指令位置,以便线程在恢复执行时能…

常见的DNS攻击与相应的防御措施

DNS查询通常都是基于UDP的,这就导致了在查询过程中验证机制的缺失,黑客很容易利用该漏洞进行分析。DNS服务可能面临如下DNS攻击风险: 黑客伪造客户端源IP地址发送大量的DNS请求报文,造成DNS request flood攻击。 黑客伪造成授权服…

MongoDB实现---存储机制

储存 GridFS机制 GridFS:将大文件分隔成多个小文档存放,这样我们能够有效的保存大文档,而且解决了BSON对象有限制的问题;通过两个集合实现:两个集合分别存储存储实际数据和存储文件的元数据: 元数据文件&…

一篇文章搞定《动手学深度学习》-(李沐)PyTorch版本的所有内容

目录 目录 简介 阅读指南 1. 深度学习简介 2. 预备知识 3. 深度学习基础 4. 深度学习计算 5. 卷积神经网络 6. 循环神经网络 7. 优化算法 8. 计算性能 9. 计算机视觉 10. 自然语言处理 环境 参考(大家可以在这里下载代码) 原书地址&#…

四结(4.13)多线程学习

今天又进行了一次学长授课,关于MySQL和JDBC本来学了增删查改操作,用IDEA也可以操作数据库,今天讲了一些数据库的规范(三大范式)、以及er图。了解了一下项目。 项目要分为客户端和服务端(C/S)来写…

vue面试题2023

1.$route和$router的区别? routes : 数组。 路由匹配规则 router : 对象。 路由对象 $router : 对象。 用于跳转路由 和 传递参数 $route :对象。 用于接收路由跳转参数 1.Vue的生命周期方法有哪些? - beforeCreate 初始化实…

科技云报道:“云减碳”成趋势,如何用“计算”帮助企业碳减排?

科技云报道原创。 将数据中心“丢进”水里、“扔进”山里,使用风能、太阳能等清洁能源为数据中心供电……这些都是通过物理方法为数据中心减碳。 数据中心的重要工作在于计算,计算导致了能源消耗,使其成为耗能大户,而通过云计算…

基于imx8m plus开发板全体系开发教程1:Windows/Linux 开发环境配置(连载中)

前言: i.MX8M Plus 开发板是一款拥有 4 个 Cortex-A53 核心,运行频率 1.8GHz;1 个 Cortex-M7 核心,运行频率 800MHz;此外还集成了一个 2.3 TOPS 的 NPU,大大加速机器学习推理。 全文所使用的开发平台均为与NXP官方合作的FS-IMX8…

Terraform 系列-什么是 IaC?

系列文章 👉 Terraform 系列文章 前言 聊到 Terraform, 必然绕不开 IaC 这个概念?那么,什么是 IaC? 🤔 基本概念 基础架构即代码 (Infrastructure as Code, IaC) 是指通过代码而不是手动流程/控制台点击来管理和配置基础架构…

互联网+制造业:图扑数字孪生智慧工厂车间生产线

前言 随着信息技术、自动化技术和人工智能等技术的快速发展和应用,智能制造已成为全球制造业发展的主流趋势。智能制造是将智能化、自动化、数字化和网络化等技术手段运用到制造过程中,使生产过程具有高度智能化、自动化和数字化的特点,进而…

Linux安装宝塔,并实现公网远程登录宝塔面板【内网穿透】

文章目录前言1. 安装宝塔2. 安装cpolar内网穿透3. 远程访问宝塔4. 固定http地址5. 配置二级子域名6. 测试访问二级子域名转发自CSDN远程穿透的文章:Linux安装宝塔,并实现公网远程登录宝塔面板【内网穿透】 前言 宝塔面板作为建站运维工具,它…

网络编程2(套接字编程)

套接字编程UDP协议通信:TCP通信:套接字编程:如何编写一个网络通信程序 1.网络通信的数据中都会包含一个完整的五元组: sip,sport,dip,dport,protocol(源IP,源…

计算机组成原理——第三章存储系统(上)

提示:吾与春风皆过客,君携秋水揽星河 文章目录前言3.1 存储系统基本概念3.2.1 主存储器的基本组成3.2.2 SRAM DRAM\3.2.3 只读存储器ROM3.3.1 主存储器与CPU的连接3.3.2 双端口RAM和多模块存储器前言 提示:以下是本篇文章正文内容&#xff0c…

带你理解运算放大器

复习一下电子设计基本元器件,运算放大器 ...... 矜辰所致目录前言一、运放基本说明1.1 基本认识1.2 运放中的电流1.3 运放工作特性二、负反馈2.1 什么是负反馈?2.2 为什么要引入负反馈?负反馈电路分析2.3 正反馈三、提一下虚短与虚断结语前…

MAX14808 八通道3级电平 数字脉冲发生器

MAX14808八通道3级电平 高压(HV) 脉冲发生器,利用低压控制逻辑输入产生高频、高压双极性脉冲(高达105V) ,用于驱动超声系统的压电传感器,MAX14808有八个集成的发送/接收(T/R)开关。 应用 超声医疗成像工业探伤检测压电驱动器测试设备 芯片…

RocketMQ 是是如何管理消费进度的?又是如何保证消息成功消费的?

RocketMQ 消费者保障 作者: 博学谷狂野架构师GitHub:GitHub 地址 (有我精心准备的 130 本电子书 PDF)只分享干货、不吹水,让我们一起加油!😄 消息确认机制 consumer 的每个实例是靠队列分配来决定如何消费消…

五、MyBatis各种查询功能

MyBatis的各种查询功能 如果查询出的数据只有一条,可以通过 实体类对象接收List集合接收Map集合接收 如果查询出的数据有多条,一定不能用实体对象接收,会抛TooManyResultsException,可以通过 实体类类型的List集合接收Map类型的L…

Python爬虫自动化从入门到精通第10天(Scrapy框架的基本使用)

Scrapy框架的基本使用Scrapy框架简介Scrapy框架的运作流程安装Scrapy框架Scrapy框架的基本操作Scrapy常用命令Scrapy框架简介 Scrapy框架主要包含以下组件: Scrapy Engine(引擎):负责Spiders、Item Pipeline、Downloader、Scheduler之间的通信&#xf…

手把手教你安装Visual Studio 2019(史上最全)

前言: 本文是以Visual Studio Community 2019为例子,介绍如何在微软官网下载Visual Studio Community 2019并安装.net桌面开发程序环境(主要是winform开发环境)。 下载请点击这里Visual Studio Community 2019下载,然后点击下图的箭头的DownLoad下载,要注意的是下载时要…

微信自定义菜单

系列文章目录 提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加 例如:第一章 Python 机器学习入门之pandas的使用 提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目…