深度学习基础1--实现类pytorch简易网络

最终实现代码仓库链接

https://github.com/VitaminyW/numpy_basied_DeepLearning/tree/main

基础知识

        目前主流的深度学习是基于Hinton在1986年所提的反向传播算法(back-propagating,BP)[1]和机器学习中的神经网络算法,通过加深神经网络的层数,从而能够在增加少量参数(相比于浅层网络)的前提下,提高网络对函数的拟合能力。PS:事实上,当参数量足够大时,浅层网络可以拟合任意函数[2]。

本文所需数学知识

  • 矩阵求导法则
  • 微积分求导方法以及链式法则
  • 最优化理论基础

问题建模

        假设现实中存在某一函数f(x_i)=y_i,我们通过采样得到其数据集D=\{(x_1,y_1),...,(x_i,y_i),...,(x_n,y_n)\},x_i\subseteq R^n,y_i\subseteq R,于是我们想要获取f,值得注意的是,在实际情况中,采样过程是存在噪声的,即y_i = f(x_i) +\varepsilon,但这里为了简化问题,我们噪声为0。

        如果我们了解 f的特性,即如果它是线性函数f(x) =Wx+b,其中W\subseteq R^{1\times n},b\subseteq R,则我们可以在线性函数集F_{linear}=\{f_1,f_2,....\}中寻找一个最优的f^*去代替它,即求解最优化表达式,

 f^*={\underset{f_i \in F}{argmin}\,\underset{(x_i,y_i) \in D}{\sum} \left \| f_i(x_i)-y_i \right \|}    (1)

        如果可以证明D集合是凸集,则可以使用牛顿法,共轭梯度算法等求解该问题。

        而事实上,我们所想求的f经常是非线性函数,通过我们在基础知识所讲的,神经网络可以用于逼近任意函数,则设神经网络的运算为g_{\theta},其中\theta为网络参数,则问题可以转变为,求解下面最优化表达式

{\theta}^* = {\underset{\theta \in R^{K}}{argmin}\,\underset{(x_i,y_i) \in D}{\sum} \left \| g_{\theta}(x_i)-y_i \right \|}   (2)

        其中,K为参数数量。

模型细节

        为了求解未知的非线性函数f,我们使用了神经网络这一工具制作我们的函数集G=\{g_{​{\theta}_1},g_{​{\theta}_2},...\},通过将问题转为求解\theta^*,我们便可以得到所求解的模型(定义:模型指的是其参数以及其结构)。

        为了简化公式,我们定义这里的模型为一个两层的神经网络,则其函数可以表示为:

\widehat{y} = \delta _2 (W^2(\delta _1 (W^1x+b^1))+b^2)  (3)

        其中,W^1 \in R^{m \times n},W^1 \in R^{1 \times m},b^1 \in R^m,b^2 \in R^1\delta _1,\delta _2是非线性函数。

        则模型参数\theta_i=(W^1_i,W^2_i,b^1_i,b^2_i)

        由此,我们可以将问题转化为求解\theta_i^*=(W^{*1}_i,W^{*2}_i,b^{*1}_i,b^{*2}_i)

BP算法

        在微积分中,我们了解到当位于函数h定义域的某一点x_0时,我们沿着函数h在该点的梯度\nabla h(x_0)以一个固定的小的步长(步长可以用某些准则求出,为了避免冗余,这里不阐述)行走时,能够最快地得到h的增量,但在深度学习中,我们往往想让损失函数(如公式(1),(2))下降,则我们应该沿着负梯度- \nabla h(x_0)更新x,下面给出一个简单的公式阐述:

目的:我们想得到一个x_2,使得h(x_2) \leqslant h(x_1)

即,h(x_2)=h(x_1+\Delta x)\leqslant h(x_1)

由二阶泰勒展开可得,h(x_0+\Delta x)=h(x_0)+\nabla h(x_0)\Delta x+o(\Delta x)

所以,当取\Delta x = -\nabla h(x_0)时,原式可以写为h(x_0+\Delta x)=h(x_0)-\nabla h(x_0)^2+o(\Delta x)

当步长满足一定条件,我们可以忽略无穷小量o(\Delta x),即使得

h(x_2) = h(x_0+\Delta x)=h(x_0)-\nabla h(x_0)^2 \leqslant h(x_0)

注:我们通常不会直接取- \nabla h(x_0)作为更新步长,而会在其之上乘以一个学习率\lambda, 该学习率是模型的超参数,其与函数的高阶导有关,但由于神经网络产生函数是变化的,我们通常会调参这个学习率,而不是推导。

BP算法用于神经网络

        值得注意的是,上一节中的x是神经网络的参数\theta,而不是我们前面所提的数据集中的元素,在本节开始前,要明确数据集D=\{(x_1,y_1),...,(x_i,y_i),...,(x_n,y_n)\},x_i\subseteq R^n,y_i\subseteq R是不变的,即它在我们求解的最优化公式{\theta}^* = {\underset{\theta \in R^{K}}{argmin}\,\underset{(x_i,y_i) \in D}{\sum} \left \| g_{\theta}(x_i)-y_i \right \|}中可以被视为常量,而我们所要更新的是\theta。则将上节中的h(\theta)= {\underset{\theta \in R^{K}}{argmin}\,\underset{(x_i,y_i) \in D}{\sum} \left \| g_{\theta}(x_i)-y_i \right \|}x\theta=(W^{1},W^{2},b^{1},b^{2})代替,则更新算法可以表示为:

\begin{cases} W^1=W^1-\lambda \frac{\partial {h}}{\partial W^1} \\ W^2=W^2-\lambda \frac{\partial {h}}{\partial W^2} \\ b^1=b^1-\lambda \frac{\partial {h}}{\partial b^1} \\ b^2=b^2-\lambda \frac{\partial {h}}{\partial b^2} \end{cases}

于是问题转为各个参数的梯度如何求导,这里便引入了链式求导法则:

p(x) = o(u(x)), \frac{\partial p}{\partial x} =\frac{\partial p}{\partial u} * \frac{\partial u}{\partial x}

最终,

\begin{cases} \frac{\partial {h}}{\partial W^1} = \frac{\partial {h}}{\partial \delta ^2} \frac{\partial {\delta ^2}}{\partial W ^2} \frac{\partial {W^2}}{\partial \delta ^1} \frac{\partial {\delta ^1}}{\partial W ^1} \\ \frac{\partial {h}}{\partial W^2} = \frac{\partial {h}}{\partial \delta ^2} \frac{\partial {\delta ^2}}{\partial W ^2} \\ \frac{\partial {h}}{\partial b^1} = \frac{\partial {h}}{\partial \delta ^2} \frac{\partial {\delta ^2}}{\partial W ^2} \frac{\partial {W^2}}{\partial \delta ^1} \frac{\partial {\delta ^1}}{\partial b ^1}\\ \frac{\partial {h}}{\partial b^2} = \frac{\partial {h}}{\partial \delta ^2} \frac{\partial {\delta ^2}}{\partial b ^2} \end{cases}

由此,我们可以看出不同函数的运算可以在更新过程中独立开来,即每个函数只要能够计算前向传播与后向梯度求导(由后面的梯度算出本步计算的梯度)即可完成模型参数更新。

我们只需要知道\frac{\partial {h}}{\partial \delta ^2}, \frac{\partial {\delta ^2}}{\partial W^2},\frac{\partial {\delta ^2}}{\partial b^2},\frac{\partial {W ^2}}{\partial \delta^1},\frac{\partial {\delta^1}}{\partial W^1},\frac{\partial {\delta^1}}{\partial b^1},便可以训练模型。而在深度学习中,常见的非线性函数为Relu,Sigmoid等,若网络重复使用这些非线性函数,只需要定义一次如何进行反向便可。

参考文献

[1]Rumelhart D E, Hinton G E, Williams R J. Learning representations by back-propagating errors[J]. nature, 1986, 323(6088): 533-536.

[2]Hornik K, Stinchcombe M, White H. Multilayer feedforward networks are universal approximators[J]. Neural networks, 1989, 2(5): 359-366.

猜你喜欢

转载自blog.csdn.net/YmgmY/article/details/128662528