全球名校课程作业分享系列(6)--斯坦福计算机视觉与深度学习CS231n之神经网络细解与优化尝试

课程作业原地址:CS231n Assignment 1
作业及整理:编写:@土豆 && @郭承坤 && @寒小阳
时间:2018年2月。
出处:http://blog.csdn.net/han_xiaoyang/article/details/79278882

  • To-Do:

  • [x] 统一所有的数学符号和代码符号

  • [x] 统一所有的术语名称

  • [x] 术语的英文词汇对应

  • [x] 线性模型的名字是?perceptron?

  • [x] 损失函数的计算公式和符号是否严格和合适?

  • [x] denominator layout?

  • [ ] BN梯度的证明
  • [x] ​ bn_param[‘running_mean’] = running_mean
    ​ bn_param[‘running_var’] = running_var

(我是盗图大仙,所有图片资源全部来源于网络,若侵权望告知~)

本文是什么?

本文以CS231n的Assignment2中的Q1-Q3部分代码作为例子,目标是由浅入深得搞清楚神经网络,同时以图片分类识别任务作为我们一步一步构建神经网路的目标。

本文既适合仅看得懂一点Python代码、懂得矩阵的基本运算、听说过神经网络算法这个词的朋友,也适合准备学习和正在完成CS231n课程作业的朋友。

本文内容涉及:很细节的Python代码解析 + 神经网络中矩阵运算的图像化解释 + 模块化Python代码的流程图解析

本文是从Python编程代码的实现角度理解,一层一层拨开神经网络的面纱,以搞清楚数据在其中究竟是怎么运动和处理的。希望可以为小白,尤其是为正在学习CS231n课程的朋友,提供一个既浅显又快捷的观点,用最直接的方式弄清楚并构建一个神经网络出来。所以,此文不适合章节跳跃式阅读。

本文不是什么?

不涉及艰深的算法原理,忽略绝大多数数学细节,也尽量不扯任何生涩的专业术语,也不会对算法和优化处理技术做任何横向对比。

CS231n课程讲师Andrej Karpathy在他的博客上写过一篇文章Hacker’s guide to Neural Networks,其中的精神是我最欣赏的一种教程写作方式:“My exposition will center around code and physical intuitions instead of mathematical derivations. Basically, I will strive to present the algorithms in a way that I wish I had come across when I was starting out.”

“…everything became much clearer when I started writing code.”

废话不多说,找个板凳坐好,慢慢听故事~

待折腾的数据集

俗话说得好:皮裤套棉裤,里边有缘故;不是棉裤薄,就是皮裤没有毛!

我们的神经网络是要用来解决某特定问题的,不是家里闲置的花瓶摆设,模型的构建都有着它的动机。所以,首先让我们简单了解下要摆弄的数据集(CIFAR-10),最终的目标是要完成一个图片样本数据源的分类问题。

图像分类数据集:CIFAR-10。
这是一个非常流行的图像分类数据集是CIFAR-10。这个数据集包含了60000张 32×32 32 × 32 的小图像,单个像素的数值范围都在0-255之间。每张图像都对应于是10种分类标签(label)中的一种。此外,这60000张图像被分为包含带有标签的50000张图像的训练集和包含不带有标签的10000张图像的测试集。


img

上图是图片样本数据源CIFAR-10中训练集的一部分样本图像,从中你可以预览10个标签类别下的10张随机图片。


小结:

在我们的故事中,只需要记得这个训练集是一堆 32×32 32 × 32 的RGB彩色图像作为训练目标,一个样本图像共有 32×32×3 32 × 32 × 3 个数据,每个数据的取值范围0~255,一般用x来标记。每个图还配有一个标签值,总共10个标签,以后我们都用y来标记。(悄悄告诉你的是:每个像素点的3个数据维度是有序的,分别对应红绿蓝(RGB))

关于神经网络,你起码应该知道的!

下图是将神经网络算法以神经元的形式绘制的两个图例,想必同志们早已见怪不怪了。

但是,你起码应该知道的是其中各种约定和定义:


img

左边是一个2层神经网络,一个隐藏层(蓝色层)有4个神经元(也可称为单元(unit))组成,输出层(绿色)由2个神经元组成,输入层(红色)是3个”神经元”。右边是一个3层神经网络,两个隐藏层,每层分别含4个神经元。注意:层与层之间的神经元是全连接的,但是层内的神经元不连接(如此就是所谓全连接层神经网络)。

这里有个小坑:输入层的每个圈圈代表的可不是每一张图片,其实也不是神经元。应该说整个纵向排列的输入层包含了一张样本图片的所有信息,也就是说,每个圈圈代表的是某样本图片对应位置的像素数值。可见对于CIFAR-10数据集来说,输入层的维数就是 32×32×3 32 × 32 × 3 ,共3072个圈圈呢!至于输出层的神经元数也是依赖数据集的,就CIFAR-10数据集来说,输出层维数必然是10,即对应数据集的10个标签。至于中间的隐藏层可以有多少层,以及每层的神经元个数就都可以任意啦!你说牛不牛?!


在接下来我们的故事中,要从代码实现的角度慢慢剖析,先从一个神经元的角度出发,再搞清楚一层神经元们是如何干活的,然后逐渐的弄清楚一个含有任意神经元个数隐藏层的神经网络究竟是怎么玩的,在故事的最后将会以CIFAR-10数据集的分类问题为目标一试身手,看看我们构造的神经网络究竟是如何工作运转的。

所谓的前向传播

一个神经元的本事

我们先仅前向传播而言,来谈谈一个神经元究竟是做了什么事情。

前向传播,这名字起的也是神乎其神的,说白了就是将样本图片的数据信息,沿着箭头正向传给一个带参数的神经网络层中咀嚼一番,然后再吐出来一堆数据再喂给后面的一层吃(如此而已,居然就叫做了前向/正向传播了,让人忍不住吐槽一番)。那么,对于一个全连接层(fully-connected layer) 1

的前向传播来说,所谓的“带参数的神经网络层”一般就是指对输入数据源(此后用”数据源”这个词来表示输入层所有输入样本图片数据总体)先进行一个矩阵乘法,然后加上偏置,得到数字再运用激活函数”修饰”,最后再反复迭代罢了(后文都默认使用此线性模型)。

是不是晕了?别着急,我们进一步嚼碎了来看看一个神经元(处于第一隐藏层)究竟是如何处理输入层传来的一张样本图片(带有猫咪标签)的?

上面提到过,输入数据源是一张尺寸为 32×32 32 × 32 的RGB彩色图像,我们假定输入数据 xi x i 的个数是 D D 的话(即 i 是有 D D 个),那这个 D = 32 × 32 × 3 = 3072 。为了普遍意义,下文继续用大写字母 D D 来表示一张图片作为数据源的维数个数(如果该神经元位于隐藏层,则大写字母 D 表示本隐藏层神经元的神经元个数,下一节还会提到)。

显然,一张图片中的 D D 个数据 x i 包含了判断该图片是一支猫的所有特征信息,那么我们就需要”充分利用”这些信息来给这张样本图片”打个分”,来评价一下这张图像究竟有多像猫。

不能空口套白狼,一张美图说明问题:


左图不用看,这个一般是用来装X用的,并不是真的要严格类比。虽然最初的神经网络算法确实是受生物神经系统的启发,但是现在早已与之分道扬镳,成为一个工程问题。关键我们是要看右图的数学模型(严格地说,这就是传说中的感知器perceptron)。


如右图中的数学模型所示,我们为每一个喂进来的数据 xi x i 都对应的”许配”一个”权重”参数 wi w i ,再加上一个偏置 b b ,然后一股脑的把他们都加起来得到一个数(scalar):

i w i x i + b = w 0 x 0 + w 1 x 1 + + w D 1 x D 1 + b

上面的代数表达式看上去很繁杂,不容易推广,所以我们把它改写成

[iwixi+b]1×1=[xi]1×DwiD×1+[b]1×1 [ ∑ i w i x i + b ] ⏟ 1 × 1 = [ ⋯ x i ⋯ ] ⏟ 1 × D ⋅ [ ⋮ w i ⋮ ] ⏟ D × 1 + [ b ] ⏟ 1 × 1

上面等式左侧这样算出的一个数字,表示为对于输入进来的 D D 个数据 x i ,在当前选定的参数 (wi,b) ( w i , b ) 下,这个神经元能够正确评价其所对应的”猫咪”标签的程度。所以,这个得分越高,越能说明其对应的在某种 (wi,b) ( w i , b ) D+1 D + 1 个参数的评价下,该神经元正确判断的能力越好,准确率越高。

换句话说,相当于是有一个神经元坐在某选秀的评委席里,戴着一款度数为 (wi,b) ( w i , b ) 雷朋眼镜,给某一位台上模仿猫咪的样本图片 xi x i 打了一个分(评价分数)。显然,得分的高低是不仅依赖于台上的主角 xi x i 的表现,还严重依赖于神经元评委戴着的有色眼镜(参数 wi,b w i , b )。当然,我们已经假定评委的智商(线性模型)是合乎统一要求的。

现如今,参加选秀的人可谓趋之若鹜,一个神经元评委该如何同时的批量化打分,提高效率嗯?

也就是说,一个神经元面对 N N 张图片该如何给每一张图片打分的问题。这就是矩阵表达式的优势了,我们只需要很自然地把上述矩阵表达式纵向延展下即可,如下所示:

[ i w i x i + b ] N × 1 = [ x i ] N × D [ w i ] D × 1 + [ b ] N × 1

上面矩阵表达式中,等号左侧的得分矩阵中每一行运算都是独立并行的,并且其每一行分别代表 N N 张样本图片的数据经过一个神经元后的得分数值。到此,我们就明白了一个神经元是如何面对一个shape为(N, D)的输入样本图片数据矩阵,并给出得分的。

然而,关于一个神经元的故事还没完。

你可能注意到了,上面例子中的美图中有个函数f,我们把图放大仔细看清楚:

在神经元对每张图片算得的“得分”送给下一个神经元之前都要经过一个函数f的考验。这就暗示我们,选秀节目的导演对神经元评委给出的得分还并不满意,为了(未来模型训练的)快捷方便,导演要求对每一个得分需要做进一步的“激活”处理(即上图中的函数 f ),于是这个叫激活函数(activation)的家伙会对结果做进一步的处理、比如大家这些年都在用的ReLU就是临门一脚,要求把得分小于零的都阉割掉,一律给0分(都得负分的了还选什么秀啊?给0分滚蛋):

f(x)=max(0,x) f ( x ) = max ( 0 , x )

所以,总结下来,一个神经元干的活就是如下所示的公式:

out=f(iwixi+b)=max(0,iwixi+b) out = f ( ∑ i w i x i + b ) = max ( 0 , ∑ i w i x i + b )

如果这个数学看得让人心烦意乱,不要怕,一层神经元的故事之后就是万众期待的Python代码实现了,相信看后会让你不禁感慨:“小样!不过如此嘛~”

小备注:

这里最后再多一句嘴:一个神经元在前向传播中输出的只是一个数字,另外,神经网络的训练过程,训练的是上述提到的模型参数 (wi,b) ( w i , b )

再多一句嘴,通常我们在整个神经网络结构中只使用一种激活函数。并且值得你注意的是,全连接层的最后一层就是输出层,除了这个最后一层,其它的全连接层神经元都要包含激活函数。

最最后说再一句,神经网络的激活函数是非线性的,所以神经网络是一个非线性分类器。

强大的层状神经元

在正式开始谈一层神经元之前,我们继续来探讨下神经元面对一张图片还可以做什么?

对于一张标签是猫咪的样本图片,我们光能评价有多么的像猫咪还不能满足,我们还需要神经元评价一下其他9个标签才行,然后才好比较评判得出最终结论。于是,光用 (wi,b) ( w i , b ) D+1 D + 1 个参数就不够用了,应该要有 10×(D+1) 10 × ( D + 1 ) 个参数才行。还是用那个恶搞的例子说明的话,就是说一个神经元评委可不够用哦,要10个戴着不同有色眼镜的神经元评委分头去考察10个不同标签,这样就可以对每个样本图片给出10个对应不同类别的得分。

所以,我们可以在最初的矩阵表达式 iwixi+b ∑ i w i x i + b 的基础上横向延展成如下矩阵表达式:

[iwixi+b]1×10=[xi]1×DwiD×10+[b]1×10Broadcasting [ ∑ i w i x i + b ⋯ ] ⏟ 1 × 10 = [ ⋯ x i ⋯ ] ⏟ 1 × D ⋅ [ ⋮ w i ⋯ ⋯ ⋮ ] ⏟ D × 10 + [ b ⋯
<think>好的,我现在需要帮助用户了如何使用原对偶神经网络来求二次规划问题。首先,用户之前已经询问过基于Hopfield神经网络决方案,现在他们想进一步了原对偶方法。我需要先回顾原对偶神经网络的基本原理,以及它在优化问题中的应用。 用户的问题是关于二次规划的,所以我需要确定原对偶神经网络如何处理这类问题。二次规划通常有目标函数和约束条件,原对偶方法通常涉及将原始问题和对偶问题结合起来,通过神经网络同时更新原始变量和对偶变量,以找到满足KKT条件的最优。 接下来,我需要考虑原对偶神经网络的结构。可能的结构包括设计动态方程,使得神经网络的稳态对应于优化问题的。这通常涉及梯度下降对原始变量,梯度上升对偶变量,同时处理约束条件。例如,对于不等式约束,可能需要使用投影操作或罚函数。 然后,我需要将这种理论转化为具体的代码实现。用户可能希望看到MATLAB或Python的示例代码,因为之前的回答用了MATLAB。但考虑到用户可能更倾向于Python,我需要准备两种语言的代码,或者选择一种更通用的。 还需要注意原对偶方法的优势,比如处理约束的能力更强,收敛性可能更好,以及更接近传统优化方法的理论基础。同时,需要指出其复杂性,参数调整的重要性,以及经典算法的比较,比如内点法或有效集法。 用户可能没有说出的是他们可能在实际应用中遇到的具体问题,比如如何处理大规模问题,或者实时性要求高的场景。因此,在注意事项部分需要提到这些应用场景,以及参数调整的建议。 然后,我需要确保回答结构清晰,分步骤释原对偶神经网络的原理,代码实现说明,以及注意事项。同时,要使用中文,并遵循之前的格式,比如代码块和加粗标题。 最后,验证代码的正确性,确保语法正确,特别是LaTeX公式的格式,使用$$...$$和$...$正确区分行内和独立公式。例如,在释KKT条件时,需要使用独立公式块,而变量如λ则用行内公式。 现在,我需要组织这些思考,形成一个结构化的回答,确保覆盖原对偶方法的原理、代码示例、说明以及注意事项,同时用户之前的提问相呼应,提供更深入的信息。</think>以下介绍 **原对偶神经网络**(Primal-Dual Neural Network)求二次规划问题的原理实现。该方法通过联合更新原始变量和对偶变量,直接逼近 **KKT最优条件**,理论上具有更强的约束处理能力和收敛性。 --- ### 一、原对偶神经网络原理 对于标准二次规划问题: $$ \begin{aligned} \min_x \quad & \frac{1}{2}x^T H x + f^T x \\ \text{s.t.} \quad & A x \leq b \\ & x \geq 0 \end{aligned} $$ 其 **KKT条件** 为: $$ \begin{cases} Hx + f + A^T \lambda - \mu = 0 \quad & (\text{平稳性}) \\ \lambda \geq 0, \quad \mu \geq 0 \quad & (\text{对偶可行性}) \\ \lambda_i (A x - b)_i = 0, \quad \mu_j x_j = 0 \quad & (\text{互补松弛性}) \end{cases} $$ 原对偶神经网络通过动态方程模拟KKT条件的收敛过程: $$ \begin{aligned} \frac{dx}{dt} &= -\left( Hx + f + A^T \lambda - \mu \right) \\ \frac{d\lambda}{dt} &= \max\left(0, \lambda + (A x - b)\right) - \lambda \\ \frac{d\mu}{dt} &= \max\left(0, \mu - x\right) - \mu \end{aligned} $$ 其中: - $\lambda$ 是线性约束的对偶变量,$\mu$ 是变量非负约束的对偶变量 - 动态方程设计融合了梯度下降(原始变量)和投影操作(对偶变量) --- ### 二、代码实现(Python示例) ```python import numpy as np import matplotlib.pyplot as plt # 问题定义 H = np.array([[2, 1], [1, 3]]) # 正定矩阵 f = np.array([-4, -6]) A = np.array([[-1, 1], [1, 2]]) b = np.array([1, 5]) # 原对偶神经网络参数 dt = 0.01 # 时间步长 T = 5000 # 迭代次数 n = H.shape[0] # 变量维度 m = A.shape[0] # 约束数量 # 初始化变量 x = np.zeros(n) lambda_ = np.zeros(m) mu = np.zeros(n) # 记录轨迹 x_history = [] energy = [] for t in range(T): # 计算原始变量梯度 grad_primal = H @ x + f + A.T @ lambda_ - mu # 更新原始变量(梯度下降) x -= dt * grad_primal # 更新对偶变量(投影梯度上升) lambda_new = np.maximum(0, lambda_ + (A @ x - b)) mu_new = np.maximum(0, mu - x) # 应用更新 lambda_ += dt * (lambda_new - lambda_) mu += dt * (mu_new - mu) # 记录能量和状态 x_history.append(x.copy()) energy.append(0.5 * x.T @ H @ x + f.T @ x) # 输出结果 print("原对偶神经网络 x =", x) # 绘制能量变化 plt.plot(energy) plt.xlabel('Iteration') plt.ylabel('Objective Value') plt.title('Convergence of Primal-Dual Neural Network') plt.show() ``` --- ### 三、关键设计说明 1. **对偶变量更新规则** - 对偶变量 $\lambda$ 的更新通过 `max(0, λ + (Ax - b))` 实现 **投影到非负象限**,强制满足互补松弛条件。 - 对偶变量 $\mu$ 的更新类似,处理 $x \geq 0$ 的约束。 2. **动态系统特性** - 当网络达到稳态时($\frac{dx}{dt}=0$, $\frac{d\lambda}{dt}=0$, $\frac{d\mu}{dt}=0$),满足KKT条件。 - 通过时间步长 `dt` 控制收敛速度,过大可能导致震荡。 3. **对比传统方法** - 避免了直接求KKT方程组的矩阵求逆,适合硬件并行实现。 - 内点法不同,无需迭代求线性系统,计算复杂度更低。 --- ### 四、改进方向 1. **自适应步长** 使用变步长策略(如Armijo条件)加速收敛: ```python # 伪代码示例 alpha = 1.0 while objective(x - alpha*grad) > objective(x) - 0.5*alpha*norm(grad)**2: alpha *= 0.5 x -= alpha * grad ``` 2. **精确约束处理** 引入 **修正项** 严格满足约束: ```python # 对偶变量更新改进 lambda_ = np.maximum(0, lambda_ + dt * (A @ x - b + 1e-3 * lambda_)) ``` 3. **大规模问题扩展** 结合 **随机梯度** 或 **分块更新** 处理高维变量。 --- ### 五、适用场景注意事项 - **优势场景** - 实时优化(如机器人控制、信号处理) - 硬件实现(模拟电路、FPGA等并行架构) - **参数调整** - 步长 `dt` 需通过试验选择(通常 $10^{-4} \sim 10^{-2}$) - 初始值影响收敛速度,建议从可行附近初始化 - **验证必要性** - 对于关键任务,需传统方法(如`cvxopt`、`OSQP`)对比验证结果。 --- 如果需要进一步讨论特定约束(如等式约束)的处理方法,或结合具体应用场景的改进方案,可以继续交流!
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值