CS231n-2017-Summary
CS231n-2017-Summary 是一份针对斯坦福大学 2017 年著名计算机视觉课程(CS231n)的精炼学习笔记。该项目由学习者在完整观看课程视频后整理而成,旨在帮助自己巩固记忆,同时也为其他希望快速掌握该课程核心内容的学习者提供便利。
它主要解决了原版课程视频时长较长、内容庞杂,导致初学者难以快速抓住重点或复习成本过高的问题。作者对部分非核心内容进行了合理删减,提炼出从卷积神经网络(CNN)基础、损失函数优化、网络训练技巧,到目标检测、图像分割、生成模型及对抗样本等 16 个关键模块的知识精华。
这份资料非常适合人工智能开发者、计算机视觉研究人员以及高校学生使用。对于想要系统入门深度学习图像识别领域,或者需要高效复习 CS231n 课程要点的人来说,它是一份极佳的辅助材料。其独特亮点在于不仅涵盖了理论推导,还紧密围绕 ImageNet 挑战赛等实战背景,清晰梳理了端到端模型的构建与调优思路,让复杂的深度学习架构变得条理清晰、易于理解。
使用场景
一名刚入门计算机视觉的算法工程师,正试图复现斯坦福 CS231n 课程中的经典模型以解决工作中的图像分类难题。
没有 CS231n-2017-Summary 时
- 时间成本高昂:面对总计 16 节、每节长达 1 小时的全英文视频讲座,需要花费数周时间逐帧观看才能梳理出知识脉络。
- 重点难以捕捉:课程涵盖从基础损失函数到对抗样本训练等广泛内容,新手极易在海量细节中迷失,无法快速定位如"CNN 架构演进”或“调试技巧”等核心工程知识。
- 知识碎片化:缺乏系统性的笔记整理,看完视频后容易遗忘关键公式推导和参数调整策略,导致在动手编写代码时频繁卡壳,不得不反复回看视频确认细节。
使用 CS231n-2017-Summary 后
- 极速构建框架:直接利用其按章节整理的目录(如从图像分类到生成模型),在几小时内即可建立起完整的深度学习知识体系,跳过非必要的背景介绍。
- 精准获取干货:作者已预先筛选并略去了非核心内容,工程师可直奔"Training neural networks"或"Deep learning software"等实战章节,快速获取反向传播推导及调参秘籍。
- 理论与实践闭环:结合摘要中提供的作业解决方案链接,能迅速将理论概念映射到代码实现,大幅缩短从“看懂视频”到“跑通模型”的周期,提升开发效率。
CS231n-2017-Summary 通过将百小时的视频精华浓缩为结构化笔记,让开发者能以最低的时间成本掌握计算机视觉的核心精髓。
运行环境要求
未说明
未说明

快速开始
斯坦福CS231n 2017课程总结
在观看了2017年举办的著名斯坦福CS231n课程的所有视频后,我决定对整个课程进行总结,以便于自己复习,同时也为那些想了解这门课程的人提供参考。在一些讲座中,由于内容对我来说并不重要,因此我选择略过了。
目录
课程信息
讲座链接:https://www.youtube.com/playlist?list=PLC1qU-LWwrF64f4QKQT-Vg5Wr4qEE1Zxk
讲座数量:16
课程描述:
计算机视觉已渗透到我们社会的方方面面,应用领域涵盖搜索、图像理解、应用程序、地图绘制、医学、无人机以及自动驾驶汽车等。这些应用的核心任务之一就是视觉识别,例如图像分类、定位和检测。近年来,基于神经网络(即“深度学习”)的方法取得了重大进展,极大地提升了这些先进视觉识别系统的性能。本课程将深入探讨深度学习架构的细节,重点在于为这些任务(尤其是图像分类)学习端到端的模型。在为期10周的课程中,学生将学会实现、训练和调试自己的神经网络,并深入了解计算机视觉领域的前沿研究。最终作业将涉及训练一个拥有数百万参数的卷积神经网络,并将其应用于最大的图像分类数据集(ImageNet)。我们将着重讲解如何设定图像识别问题、学习算法(如反向传播)、训练和微调网络的实用工程技巧,并通过动手实践作业和期末项目引导学生完成学习。本课程的许多背景知识和材料都将源自ImageNet挑战赛。
01. 用于视觉识别的卷积神经网络简介
- 计算机视觉从20世纪60年代末至今的发展简史。
- 计算机视觉问题包括图像分类、目标定位、目标检测和场景理解。
- Imagenet 是目前可用的最大图像分类数据集之一。
- 自2012年起,在Imagenet竞赛中,卷积神经网络(CNN)一直占据主导地位。
- 实际上,CNN早在1997年就由Yann Lecun发明了。
02. 图像分类
- 图像分类问题面临诸多挑战,如光照和视角变化等。
- 图像分类问题可以用K近邻(KNN)算法解决,但其效果往往不佳。KNN的特点如下:
- KNN的超参数包括:k值和距离度量。
- k表示我们用来比较的邻居数量。
- 常用的距离度量包括:
- L2距离(欧几里得距离)
- 适用于非坐标点
- L1距离(曼哈顿距离)
- 适用于坐标点
- L2距离(欧几里得距离)
- 超参数可以通过交叉验证来优化,以确定最佳的k值:
- 将数据集划分为
f个折。 - 对于给定的超参数:
- 使用
f-1个折训练算法,并用剩下的1个折进行测试。重复此过程,直到每个折都参与一次测试。
- 使用
- 选择能使平均得分最高的超参数。
- 将数据集划分为
- 线性支持向量机(Linear SVM)分类器也可以用于解决图像分类问题,但由于维度灾难,其性能会在某个点后不再提升。
- 逻辑回归同样是解决图像分类问题的一种方法,但图像分类问题是非线性的!
- 线性分类器需要运行以下方程:
Y = wX + b- 其中,
w的形状与x相同,而b的形状为1。
- 其中,
- 我们可以向
X向量中添加一个1,并去除偏置项,从而简化为:Y = wX- 此时,
x的形状变为oldX+1,而w的形状仍与x相同。
- 此时,
- 我们需要找到能够使分类器达到最佳效果的
w和b值。
03. 损失函数与优化
在上一节中,我们讨论了线性分类器,但并未涉及如何训练该模型的参数,以找到最优的
w和b。我们需要一个损失函数来衡量当前参数的好坏。
Loss = L[i] =(f(X[i],W),Y[i]) Loss_for_all = 1/N * Sum(Li(f(X[i],W),Y[i])) # 表示平均值
接下来,我们需要找到一种方法,在给定参数的情况下最小化损失函数。这被称为优化。
线性SVM分类器的损失函数:
L[i] = Sum where all classes except the predicted class (max(0, s[j] - s[y[i]] + 1))- 我们称之为合页损失。
- 损失函数表示:如果最佳预测与真实标签一致,则认为满意;否则,会根据间隔大小给出误差。
- 示例:

- 基于此示例,我们希望计算该图像的损失。
L = max (0, 437.9 - (-96.8) + 1) + max(0, 61.95 - (-96.8) + 1) = max(0, 535.7) + max(0, 159.75) = 695.45- 最终损失为695.45,数值较大,表明猫类别的得分应高于其他类别,因为目前它是最低的。我们需要尽量减小这个损失。
- 间隔为1是可以接受的,但它也是一个超参数。
如果你的损失函数为零,是否意味着此时的参数就是最优解?并非如此,因为有许多不同的参数组合都能达到最佳效果。
有时也会听到使用平方合页损失的SVM(或L2-SVM),它对违反间隔的惩罚更强(呈二次而非线性关系)。未平方的形式更为常见,但在某些数据集上,平方合页损失的表现可能更好。
我们为损失函数添加正则化项,以防止模型过拟合数据。
Loss = L = 1/N * Sum(Li(f(X[i],W),Y[i])) + lambda * R(W)其中
R是正则化项,lambda是正则化系数。
不同的正则化技术如下:
正则化方法 公式 备注 L2 R(W) = Sum(W^2)所有权重的平方之和 L1 R(W) = Sum(lWl)所有权重绝对值之和 弹性网络(L1 + L2) R(W) = beta * Sum(W^2) + Sum(lWl)Dropout 无公式
正则化倾向于选择较小的
W而非较大的W。正则化也被称为权重衰减。偏置项不应包含在正则化中。
Softmax损失(类似于线性回归,但适用于多于两类的情况):
Softmax函数:
A[L] = e^(score[L]) / sum(e^(score[L]), NoOfClasses)
向量各元素之和应为1。
Softmax损失:
Loss = -logP(Y = y[i]|X = x[i])即正确类别的概率的负对数。我们希望这个值接近1,因此加上了负号。
Softmax损失也称为交叉熵损失。
计算Softmax时需注意以下数值问题:
f = np.array([123, 456, 789]) # 示例:3个类别,每个类别的得分都很高 p = np.exp(f) / np.sum(np.exp(f)) # 不佳:存在数值问题,可能导致溢出 # 改进方案:先将f中的数值调整,使最大值为0: f -= np.max(f) # f变为[-666, -333, 0] p = np.exp(f) / np.sum(np.exp(f)) # 安全可靠,结果正确
优化:
- 我们已经讨论了如何优化损失函数。有哪些策略呢?
- 策略一:
- 随机选取一组参数,逐一尝试并计算对应的损失,最终选择损失最小的一组。但这并不是一个好的方法。
- 策略二:
沿着梯度方向前进。

- 图片来源。
我们的目的是计算每个参数的梯度。
- 数值梯度:近似、速度较慢、易于实现。(但适合用于调试。)
- 解析梯度:精确、速度快、易出错。(实际应用中通常使用解析梯度。)
计算出参数的梯度后,进行梯度下降:
W = W - learning_rate * W_grad
学习率是一个非常重要的超参数,应在所有超参数中优先确定其最优值。
随机梯度下降:
- 不再使用全部数据,而是采用小批量样本(常用32、64、128等规模)以加快收敛速度。
04. 神经网络简介
对任意复杂函数计算解析梯度:
什么是计算图?
- 计算图用于用节点表示任何函数。
- 使用计算图可以很容易地引导我们使用一种称为反向传播的技术,即使对于像CNN和RNN这样的复杂模型也是如此。
反向传播的简单示例:
假设我们有
f(x,y,z) = (x+y)z那么可以用如下图表示:
X \ (+)--> q ---(*)--> f / / Y / / / Z---------/我们引入了一个中间变量
q来保存x+y的值。接着有:
q = (x+y) # dq/dx = 1 , dq/dy = 1 f = qz # df/dq = z , df/dz = q
进而:
df/dq = z df/dz = q df/dx = df/dq * dq/dx = z * 1 = z # 链式法则 df/dy = df/dq * dq/dy = z * 1 = z # 链式法则
因此,在计算图中,我们将每个操作称为
f。对于每个f,我们在进行反向传播之前先计算局部梯度,然后利用链式法则计算相对于损失函数的梯度。在计算图中,你可以将每个操作拆解得尽可能简单,但这样节点会非常多。如果你希望节点更小,一定要确保能够计算该节点的梯度。
一个更大的例子:

- 提示:两个节点从后向前传递到一个节点时,其反向传播是通过将这两个导数相加来完成的。
模块化实现:前向/反向API(以乘法代码为例):
class MultuplyGate(object): """ x,y 是标量 """ def forward(x,y): z = x*y self.x = x # 缓存 self.y = y # 缓存 # 我们缓存x和y,因为知道它们会出现在导数中。 return z def backward(dz): dx = self.y * dz #self.y就是dx dy = self.x * dz return [dx, dy]
如果你查看深度学习框架,会发现它们都遵循模块化实现,即每个类都有前向和反向的定义。例如:
- 乘法
- 最大值
- 加法
- 减法
- Sigmoid
- 卷积
因此,我们可以将神经网络定义为一个函数:
- (以前)线性得分函数:
f = Wx - (现在)两层神经网络:
f = W2*max(0,W1*x)- 其中max是ReLU非线性函数
- (现在)三层神经网络:
f = W3*max(0,W2*max(0,W1*x) - 以此类推……
- (以前)线性得分函数:
神经网络是由一些简单操作堆叠而成,从而形成复杂的操作。
05. 卷积神经网络(CNNs)
神经网络历史:
- 第一台感知机由弗兰克·罗森布拉特于1957年开发,用于识别字母表中的字母。当时反向传播算法尚未被提出。
- 多层感知机于1960年由Adaline/Madaline提出,但此时反向传播算法仍未出现。
- 反向传播算法于1986年由鲁梅尔哈特等人提出。
- 在此之后的一段时间里,神经网络领域几乎没有新的进展,主要原因是计算资源和数据量的限制。
- 2006年,辛顿发表了一篇论文,表明可以使用受限玻尔兹曼机初始化权重,然后再通过反向传播训练深度神经网络。
- 2012年,辛顿团队在语音识别领域取得了突破性成果(参见IEEE文献)。同年,辛顿团队还提出了AlexNet卷积神经网络,并在ImageNet竞赛中获胜。
- 自那以后,神经网络被广泛应用于各种领域。
卷积神经网络历史:
- 1959年至1968年间,休贝尔和威塞尔在猫的大脑皮层上进行实验,发现大脑皮层存在拓扑映射,且神经元具有从简单到复杂的层次化组织结构。
- 1998年,扬·勒丘恩发表了《基于梯度的学习在文档识别中的应用》一文,首次提出了卷积神经网络的概念。该模型在邮政编码识别任务上表现良好,但在更复杂的场景下难以应用。
- 2012年,AlexNet沿用了扬·勒丘恩的架构,并在ImageNet竞赛中夺冠。与1998年相比,如今我们拥有大规模的数据集,同时GPU的强大算力也解决了许多性能瓶颈问题。
- 自2012年起,卷积神经网络被广泛应用于多种任务,例如:
- 图像分类。
- 图像检索。
- 使用神经网络提取特征,再进行相似度匹配。
- 目标检测。
- 图像分割。
- 为图像中的每个像素分配标签。
- 人脸识别。
- 姿态识别。
- 医学影像分析。
- 使用强化学习玩雅达利游戏。
- 星系分类。
- 交通标志识别。
- 图像字幕生成。
- 深度梦。
卷积神经网络架构明确假设输入是图像,这使得我们可以将某些先验知识编码进网络结构中。
卷积神经网络中有几种不同类型的层(如CONV、FC、ReLU、POOL等是最常见的)。
每一层可能包含参数,也可能不包含参数(例如CONV和FC层有参数,而ReLU和POOL层没有)。
每一层也可能包含额外的超参数,或者不包含(例如CONV、FC和POOL层有超参数,而ReLU层没有)。
卷积神经网络的工作原理:
- 全连接层是指所有神经元之间都相互连接的层,有时也称为密集层。
- 如果输入形状为
(X, M),则该层的权重形状为(隐藏层神经元数, X)。
- 如果输入形状为
- 卷积层是一种通过滤波器在整个图像上滑动来保持输入结构的层。
- 我们通过点积运算实现:
W.T*X + b。该公式利用了广播机制。 - 因此需要确定
W和b的值。 - 通常我们将滤波器
W视为一个向量,而非矩阵。
- 我们通过点积运算实现:
- 卷积操作的输出称为激活图。我们需要生成多个激活图。
- 例如,如果有6个滤波器,其形状如下:
- 输入图像
(32,32,3) - 滤波器尺寸
(5,5,3)- 应用6个滤波器时,深度必须为3,因为输入图像的深度也是3。
- 卷积后的输出
(28,28,6)- 如果只用一个滤波器,则为
(28,28,1)
- 如果只用一个滤波器,则为
- 经过ReLU激活后
(28,28,6) - 再应用另一个滤波器
(5,5,6) - 卷积后的输出
(24,24,10)
- 输入图像
- 例如,如果有6个滤波器,其形状如下:
- 实际上,卷积神经网络会在早期层学习低级特征,随后逐步学习中级和高级特征。
- 在卷积层之后,我们可以使用线性分类器来进行分类任务。
- 在卷积神经网络中,通常会先经过若干个(Conv ==> Relu)组合,然后通过池化操作降低激活图的尺寸。
- 全连接层是指所有神经元之间都相互连接的层,有时也称为密集层。
卷积操作中的步幅是什么?
- 在进行卷积操作时,我们需要选择滑动步幅的大小。我将通过例子来说明。
- 步幅是指滑动时跳过的距离,默认值为1。
- 假设有一个形状为
(7,7)的矩阵和一个形状为(3,3)的滤波器:- 如果步幅为1,则输出形状为
(5,5)# 会丢掉2行2列 - 如果步幅为2,则输出形状为
(3,3)# 会丢掉4行4列 - 如果步幅为3,则无法正常工作。
- 如果步幅为1,则输出形状为
- 一般公式为
((N-F)/stride +1)。- 如果步幅为1,则
O = ((7-3)/1)+1 = 4 + 1 = 5。 - 如果步幅为2,则
O = ((7-3)/2)+1 = 2 + 1 = 3。 - 如果步幅为3,则
O = ((7-3)/3)+1 = 1.33 + 1 = 2.33# 无法正常工作
- 如果步幅为1,则
在实践中,通常会对边界进行零填充。
# 两侧填充。- 如果步幅为
1,常见的填充方式是使用公式(F-1)/2,其中 F 是卷积核的大小。- 例如
F = 3==> 零填充1 - 例如
F = 5==> 零填充2
- 例如
- 如果我们以这种方式填充,就称为“相同卷积”。
- 添加零可以为边缘提供额外的信息,因此存在不同的填充技术,比如用非零值填充角落。但在实际应用中,零填充效果很好!
- 我们这样做是为了保持输入的完整尺寸。如果不这样做,输入会迅速缩小,导致大量数据丢失。
- 如果步幅为
示例:
- 如果我们有一个形状为
(32,32,3)的输入,以及十个形状为(5,5)、步幅为1、填充为2的卷积核:- 输出大小将是
(32,32,10)# 我们保持了尺寸。
- 输出大小将是
- 每个卷积核的参数量
= 5*5*3 + 1 = 76 - 总参数量
= 76 * 10 = 760
- 如果我们有一个形状为
卷积核的数量通常是 2 的幂次方。
# 以便更好地向量化。因此,卷积层的参数包括:
- 卷积核数量 K。
- 通常为 2 的幂次方。
- 空间卷积核大小 F。
- 3、5、7 等。
- 步幅 S。
- 通常为 1 或 2 (如果步幅较大,会发生下采样,但这与池化不同)
- 填充量
- 如果希望输入和输出的形状一致,则根据 F 的大小来决定:F 为 3 时填充 1,F 为 5 时填充 2,依此类推。
- 卷积核数量 K。
池化可以使特征表示更小、更易于管理。
池化操作独立地作用于每个激活图。
池化的例子之一是最大池化。
- 最大池化的参数包括卷积核大小和步幅。
- 例如
2x2,步幅为2# 通常两个参数都是相同的 2 , 2
- 例如
- 最大池化的参数包括卷积核大小和步幅。
另一个池化的例子是平均池化。
- 在这种情况下,它可能是可学习的。
06. 神经网络训练 I
作为回顾,以下是小批量随机梯度下降算法的步骤:
- 循环:
- 抽取一批数据。
- 将其通过网络前向传播,得到损失。
- 进行反向传播计算梯度。
- 使用梯度更新参数。
- 循环:
激活函数:
不同的激活函数选择包括 Sigmoid、tanh、RELU、Leaky RELU、Maxout 和 ELU。

Sigmoid:
- 将数值压缩到 [0,1] 范围内。
- 类似于人脑的发放率。
Sigmoid(x) = 1 / (1 + e^-x)- Sigmoid 的问题:
- 大数值会导致神经元“杀死”梯度。
- 梯度在大多数情况下接近 0(无论是大值还是小值),这会阻止大型网络的参数更新。
- 不是零中心的。
- 无法产生零均值的数据。
exp()的计算成本较高。- 仅作参考。深度学习中还有更复杂的操作,比如卷积。
- 大数值会导致神经元“杀死”梯度。
Tanh:
- 将数值压缩到 [-1,1] 范围内。
- 是零中心的。
- 同样,大数值会导致神经元“杀死”梯度。
Tanh(x)是其公式。- 由 Yann LeCun 于 1991 年提出。
RELU(修正线性单元):
RELU(x) = max(0,x)- 不会杀死梯度。
- 只有小数值会被杀死。梯度只有一半被杀死。
- 计算效率高。
- 收敛速度比 Sigmoid 和 Tanh 快得多
(6倍) - 比 Sigmoid 更符合生物学原理。
- 由 Alex Krizhevsky 于 2012 年在多伦多大学提出。(AlexNet)
- 问题:
- 不是零中心的。
- 如果权重初始化不好,可能有 75% 的神经元处于“死亡”状态,造成计算浪费。不过它仍然有效。目前仍在积极研究如何优化这一问题。
- 为了解决上述问题,人们可能会将所有偏置初始化为 0.01。
Leaky RELU:
leaky_RELU(x) = max(0.01x,x)- 不会从两边杀死梯度。
- 计算效率高。
- 收敛速度比 Sigmoid 和 Tanh 快得多(6倍)。
- 不会“死亡”。
- PReLU 则将 0.01 替换为一个可学习的参数 alpha。
指数线性单元(ELU):
ELU(x) = { x 若 x > 0 alpah *(exp(x) -1) 若 x <= 0 # alpah 是一个可学习的参数 }它具有 RELU 的所有优点。
输出更接近零均值,并且对噪声有一定的鲁棒性。
问题:
exp()的计算成本较高。
Maxout 激活函数:
maxout(x) = max(w1.T*x + b1, w2.T*x + b2)- 是 RELU 和 Leaky RELU 的推广。
- 不会“死亡”!
- 问题:
- 会使每个神经元的参数数量翻倍。
实际应用:
- 使用 RELU。注意学习率的设置。
- 可以尝试 Leaky RELU/Maxout/ELU。
- 可以尝试 tanh,但不要抱太大期望。
- 不要使用 Sigmoid!
数据预处理:
对数据进行归一化:
# 零中心化数据。(计算每个输入的均值)。 # 我们这样做的原因之一是,需要数据在正负之间分布,而不是全部为正或全部为负。 X -= np.mean(X, axis = 1) # 然后应用标准差。提示:对于图像,我们不这样做。 X /= np.std(X, axis = 1)对图像进行归一化:
- 减去平均图像(例如 AlexNet)。
- 平均图像的形状与输入图像相同。
- 或者减去每通道的均值。
- 即计算所有图像每个通道的均值。形状为 3(3 个通道)。
- 减去平均图像(例如 AlexNet)。
权重初始化:
如果将所有 W 初始化为零,会发生什么?
- 所有神经元都会做完全相同的事情。它们会有相同的梯度和相同的更新。
- 因此,如果某一层的所有权重都相等,就会出现上述情况。
第一种想法是将权重初始化为小的随机数:
W = 0.01 * np.random.rand(D, H) # 对小型网络效果尚可,但对深层网络则会产生问题!在深层网络中,标准差会趋近于零,梯度也会更快消失。
W = 1 * np.random.rand(D, H) # 对小型网络效果尚可,但对深层网络则会产生问题!网络可能会因为数值过大而爆炸。
Xavier 初始化:
W = np.random.rand(in, out) / np.sqrt(in)它之所以有效,是因为我们希望输入的方差与输出的方差保持一致。
但它有一个问题:在使用 RELU 时会失效。
He 初始化(解决 RELU 问题):
W = np.random.rand(in, out) / np.sqrt(in/2)解决了 RELU 的问题。建议在使用 RELU 时采用此方法。
正确的权重初始化仍然是一个活跃的研究领域。
批归一化:
是一种为神经网络中的任意一层提供均值为零、方差为一的输入的技术。
- 它可以加速训练过程。你应该经常使用它。
- 由谢尔盖·伊奥菲和克里斯蒂安·塞格迪于2015年提出。
- 我们通过计算每层的均值和方差,使激活值呈现高斯分布。
- 通常在(全连接层或卷积层)之后、(非线性激活函数)之前插入。
- 步骤(针对每一层的输出):
- 首先,我们为每个特征计算批次的均值和方差²。
- 通过减去均值并除以(方差² + epsilon)的平方根来进行归一化。
- epsilon是为了避免除以零。
- 然后,我们引入缩放和平移变量:
Result = gamma * normalizedX + beta- gamma和beta是可学习的参数。
- 这实际上允许模型说:“嘿!我不需要均值为零、方差为一的输入,把原始输入还给我——那样对我更好。”
- 可以根据需要调整平移和缩放,而不仅仅是基于均值和方差!
- 该算法使每一层都具有灵活性(它可以自行选择所需的分布)。
- 我们初始化BatchNorm参数,将输入转换为均值为零、方差为一的分布,但在训练过程中,它们可能会学习到其他分布更为合适。
- 在训练过程中,我们需要使用加权平均来计算每层的全局均值和全局方差。
- 批量归一化的优势:
- 网络训练速度更快。
- 允许使用更高的学习率。
- 有助于降低对初始权重的敏感性。
- 使更多激活函数变得可行。
- 提供一定的正则化效果。
- 因为我们为每个批次计算均值和方差,这会带来轻微的正则化作用。
- 在卷积层中,每个激活图会有各自的方差和均值。
- 批量归一化在卷积神经网络和常规深度神经网络中表现最佳,但在循环神经网络和强化学习领域,它仍然是一个活跃的研究方向。
- 在强化学习中应用起来比较困难,因为批次通常较小。
- 它可以加速训练过程。你应该经常使用它。
监督学习过程
- 数据预处理。
- 选择网络架构。
- 进行前向传播并检查损失(禁用正则化)。确认损失是否合理。
- 添加正则化项,此时损失应该会增加!
- 再次禁用正则化,取少量数据尝试训练,直到损失降至零。
- 对于小数据集,你应该能够完美地过拟合。
- 使用完整的训练数据,并采用较小的正则化强度,尝试不同的学习率。
- 如果损失几乎没有变化,则说明学习率太低。
- 如果出现
NAN,则表明网络发散了,学习率过高。 - 通过尝试最小可能值(可能会改变)和不会导致网络发散的最大值,确定你的学习率范围。
- 进行超参数优化,以找到最佳的超参数组合。
超参数优化
- 尝试交叉验证策略。
- 运行几个周期,尝试优化各个范围。
- 最好在对数空间中进行优化。
- 调整范围后再次尝试。
- 相较于网格搜索,在对数空间中进行随机搜索效果更好。
- 尝试交叉验证策略。
07. 训练神经网络II
优化算法:
随机梯度下降法的问题:
- 如果在一个方向上损失下降得很快,而在另一个方向上下降得很慢(仅针对两个变量),那么在浅维度上的进展会非常缓慢,而在陡峭维度上则会出现抖动。对于拥有大量参数的神经网络来说,这个问题会更加严重。
- 局部极小值或鞍点
- 如果SGD陷入局部极小值,由于梯度为零,模型就会卡在这个点上。
- 同样,在鞍点处梯度也为零,模型也会陷入停滞。
- 鞍点意味着在某些点上:
- 有些梯度会使损失上升。
- 有些梯度会使损失下降。
- 这种情况在高维空间中更为常见(例如,拥有1亿个维度的情况)。
- 对于深度神经网络而言,其主要问题在于鞍点,而非局部极小值,因为深度网络的参数维度非常高。
- 小批量数据由于并非基于整个批次计算梯度,因此噪声较大。
SGD + 动量:
通过梯度的移动平均构建速度:
# 计算加权平均。rho的最佳范围是[0.9 - 0.99] V[t+1] = rho * v[t] + dx x[t+1] = x[t] - learningRate * V[t+1]V[0]为零。解决了鞍点和局部极小值的问题。
它会稍微越过问题点,然后再返回。
Nesterov 动量:
dx = compute_gradient(x) old_v = v v = rho * v - learning_rate * dx x+= -rho * old_v + (1+rho) * v不会过度越过问题点,但速度比SGD + 动量稍慢。
AdaGrad:
grad_squared = 0 while(True): dx = compute_gradient(x) # 这里存在问题,grad_squared不会衰减(会变得非常大) grad_squared += dx * dx x -= (learning_rate*dx) / (np.sqrt(grad_squared) + 1e-7)
RMSProp:
grad_squared = 0 while(True): dx = compute_gradient(x) # 解决了AdaGrad的问题 grad_squared = decay_rate * grad_squared + (1-grad_squared) * dx * dx x -= (learning_rate*dx) / (np.sqrt(grad_squared) + 1e-7)人们现在更倾向于使用RMSProp而不是AdaGrad。
Adam:
- 结合了动量和RMSProp的梯度信息。
- 需要进行偏差校正以修正梯度的初始状态。
- 到目前为止,它是表现最好的优化方法,在许多问题上都能取得优异的效果。
- 使用
beta1 = 0.9、beta2 = 0.999以及learning_rate = 1e-3或5e-4作为许多模型的起点!
学习率衰减:
- 例如,每隔几个周期将学习率减半。
- 这有助于防止学习率波动过大。
- 学习率衰减常用于SGD+动量,但不太适用于Adam。
- 在选择超参数时,不要一开始就使用学习率衰减。先尝试一下,再决定是否需要衰减。
我们讨论的所有上述算法都属于一阶优化方法。
二阶优化:
- 使用梯度和海森矩阵构建二次近似。
- 沿着近似的极小值方向前进。
- 这种更新方式有什么优点?
- 在某些版本中,它不需要学习率。
- 但它在深度学习中并不实用。
- 海森矩阵有O(N^2)个元素。
- 逆矩阵计算需要O(N^3)的时间。
- L-BFGS是一种二阶优化方法。
- 它适用于批处理优化,但不适用于小批量数据。
实际操作中,首先使用ADAM,如果效果不佳再尝试L-BFGS。
有人认为所有著名的深度架构都使用了SGD + Nesterov 动量。
正则化
到目前为止,我们讨论的是如何降低训练误差,但真正让我们关心的,是我们模型对未见过数据的处理能力!
- 如果训练数据和验证数据之间的误差差距过大,该怎么办?
- 这种误差被称为高方差。
- 模型集成:
- 算法:
- 使用不同的初始化参数训练多个结构相同但相互独立的模型。
- 在测试时对它们的预测结果取平均。
- 这种方法通常可以提升约2%的性能。
- 它能够降低泛化误差。
- 你可以在训练过程中保存神经网络的若干快照,然后将这些快照集成起来,最终得到的结果。
- 算法:
- 正则化可以解决高方差问题。我们已经讨论过L1和L2正则化。
- 还有一些专门为神经网络设计的正则化技术,效果往往更好。
- Dropout:
- 在每次前向传播时,随机将一部分神经元的输出置为零。丢弃概率是一个超参数,大多数情况下设为0.5。
- 也就是说,你会随机选择一些激活值并将其置零。
- 它之所以有效,是因为:
- 它迫使网络形成冗余表示,从而防止特征之间的共适应;
- 从某种角度看,它实际上是在同一个模型中集成了多个子模型!
- 在测试时,我们可能会将每个dropout层的输出乘以丢弃概率。
- 有时在测试时则不进行任何缩放,直接使用原始输出。
- 使用dropout会增加训练时间。
- 数据增强:
- 另一种起到正则化作用的技术。
- 对数据进行变换!
- 例如翻转图像或旋转图像。
- ResNet中的例子:
- 训练阶段:随机采样裁剪和缩放区域:
- 在[256,480]范围内随机选取一个长度L。
- 将训练图像短边调整为L。
- 随机采样一个224x224的区域。
- 测试阶段:对固定的一组裁剪区域取平均:
- 将图像调整为5种尺度:{224, 256, 384, 480, 640}。
- 对每种尺度,分别从四个角、中心以及水平/垂直翻转后的位置采样10个224x224的区域。
- 应用颜色抖动或PCA降维。
- 还可以进行平移、旋转和拉伸等操作。
- 训练阶段:随机采样裁剪和缩放区域:
- Drop Connect:
- 类似于dropout的思想,也是一种正则化方法。
- 不是丢弃激活值,而是随机将部分权重置为零。
- 分数最大池化:
- 一种很酷的正则化思路,不过并不常用。
- 在池化时随机划分区域。
- 随机深度:
- 一种新提出的正则化方法。
- 不是丢弃神经元,而是随机跳过某些层。
- 其效果与dropout类似,但属于一种全新的思路。
迁移学习:
有时候,你的模型出现过拟合,并不是因为正则化不足,而是因为数据量太小。
如果你想训练或使用卷积神经网络,通常需要大量的数据。
迁移学习的步骤:
- 先在一个包含与你的数据集相似特征的大数据集上进行预训练。
- 冻结除最后一层以外的所有层,只用你的小数据集来训练最后一层。
- 你不仅可以重新训练最后一层,还可以根据数据量的多少,微调任意数量的层。
迁移学习使用指南:
数据集非常相似 数据集差异较大 数据量极少 在顶层使用线性分类器 比较棘手……可以尝试从不同层次提取特征使用线性分类器 数据量较多 微调几层 微调较多层 迁移学习其实是一种常态,而非特例。
08. 深度学习软件
由于深度学习软件的快速迭代,CS231n课程每年这一部分都会有很大的变化。
CPU与GPU
- GPU:显卡最初是为了渲染图形、运行游戏或制作3D媒体等而开发的。
- NVIDIA与AMD
- 在深度学习中,通常选择NVIDIA而非AMD的GPU,因为NVIDIA在推动深度学习研究方面更为积极,并且其架构也更适合深度学习任务。
- NVIDIA与AMD
- CPU的核心数量较少,但每个核心的速度更快、功能更强,擅长处理顺序性任务。而GPU的核心数量多,但单个核心的速度较慢、功能较弱,更适合并行计算。
- GPU的核心需要协同工作,并且拥有独立的显存。
- 矩阵乘法是非常适合在GPU上执行的操作之一,因为它包含M×N个可以并行进行的独立运算。
- 卷积操作同样可以并行化,因为它由多个独立的子操作组成。
- GPU编程框架:
- CUDA(仅适用于NVIDIA显卡)
- 使用类似C语言的代码直接在GPU上运行。
- 编写高效的GPU代码较为困难,因此NVIDIA提供了高层API来简化开发。
- 高层API包括cuBLAS、cuDNN等。
- CuDNN已经为你实现了反向传播、卷积、循环神经网络等操作!
- 实际上,你并不需要自己编写并行代码,而是可以直接使用他人已经实现并优化好的代码。
- OpenCL
- 类似于CUDA,但可以在任何品牌的GPU上运行。
- 通常速度较慢。
- 目前尚未得到所有深度学习框架的广泛支持。
- CUDA(仅适用于NVIDIA显卡)
- 存在许多关于并行编程的课程。
- 如果不注意,训练过程可能会因数据读取和传输到GPU而成为瓶颈。解决方法包括:
- 将所有数据加载到内存中(如果可能)。
- 使用SSD替代HDD。
- 使用多个CPU线程预取数据!
- 当GPU正在计算时,一个CPU线程会提前将数据准备好。
- 许多框架已经内置了这种机制,因为手动实现较为复杂。
- GPU:显卡最初是为了渲染图形、运行游戏或制作3D媒体等而开发的。
深度学习框架
- 发展非常迅速!
- 当前可用的框架包括:
- TensorFlow(Google)
- Caffe(UC Berkeley)
- Caffe2(Facebook)
- Torch(NYU / Facebook)
- PyTorch(Facebook)
- Theano(蒙特利尔大学)
- Paddle(百度)
- CNTK(微软)
- MXNet(亚马逊)
- 教师认为你应该重点关注TensorFlow和PyTorch。
- 深度学习框架的作用:
- 轻松构建大型计算图。
- 方便地计算计算图中的梯度。
- 高效地在GPU上运行(利用cuDNN和cuBLAS)。
- NumPy无法在GPU上运行。
- 大多数框架在前向传播阶段都尽量模仿NumPy的使用方式,然后自动为你计算梯度。
TensorFlow(Google)
- 代码分为两部分:
- 定义计算图。
- 运行并多次复用该计算图。
- TensorFlow采用静态图架构。
- TensorFlow中的变量是计算图的一部分,而占位符则在每次运行时被喂入。
- 全局初始化函数用于初始化计算图中的变量。
- 可以使用预定义的优化器和损失函数。
- 使用
layers.dense函数即可创建完整的全连接层。 - Keras(高层封装)
- Keras是TensorFlow之上的一个高层封装,使常见操作更加简单。
- 非常流行!
- 几行代码就能训练一个完整的深度神经网络。
- 存在许多高层封装:
- Keras
- TFLearn
- TensorLayer
tf.layers# TensorFlow自带tf-Slim# TensorFlow自带tf.contrib.learn# TensorFlow自带- Sonnet # DeepMind推出的新框架
- TensorFlow提供了预训练模型,可用于迁移学习。
- TensorBoard可以记录损失、统计信息等,并启动服务器生成可视化图表。
- 如果需要将计算图分布到多个节点上,TensorFlow也支持分布式计算。
- TensorFlow实际上受到了Theano的启发,两者在设计理念和结构上有很多相似之处。
- 代码分为两部分:
PyTorch(Facebook)
- 采用三层抽象:
- Tensor:类似于
ndarray,但可以在GPU上运行 # 类似于TensorFlow中的NumPy数组- Variable:计算图中的节点,存储数据和梯度 # 类似于TensorFlow中的Tensor、Variable和Placeholder
- Module:神经网络层,可能包含状态或可学习的权重 # 类似于TensorFlow中的
tf.layers
- Tensor:类似于
- 在PyTorch中,计算图是在你执行代码的同一循环中动态构建的,这使得调试更加方便,称为动态图。
- 在PyTorch中,你可以通过为张量编写前向和反向传播函数来定义自己的自动求导函数,不过大多数情况下这些功能都已经为你实现好了。
- Torch.nn是一个类似于TensorFlow中Keras的高层API,你可以用它来构建模型并继续扩展。
- 也可以自定义自己的神经网络模块!
- PyTorch还包含了与TensorFlow类似的优化器。
- 它提供了一个数据加载器,可以对数据集进行分批、打乱顺序和多线程处理。
- PyTorch拥有最好且易于使用的预训练模型。
- PyTorch还配备了Visdom工具,类似于TensorBoard,不过TensorBoard的功能似乎更强大。
- 与Torch相比,PyTorch相对较新,仍在不断发展,目前仍处于测试阶段。
- PyTorch更适合用于研究。
- 采用三层抽象:
TensorFlow只构建一次计算图,然后多次运行(称为静态图)。
在PyTorch的每次迭代中,都会重新构建一个新的计算图(称为动态图)。
静态图与动态图:
- 优化:
- 对于静态图,框架可以在运行前为你优化计算图。
- 序列化:
- 静态图:一旦计算图构建完成,就可以将其序列化并在没有原始代码的情况下运行,例如在C++中使用该计算图。
- 动态图:始终需要保留原始代码。
- 条件语句:
- 动态图更容易实现条件逻辑,而静态图则相对复杂。
- 循环:
- 动态图中处理循环更为简单,而静态图中则较为复杂。
- TensorFlow的
fold功能可以通过动态批处理使动态图的使用更加便捷。 - 动态图的应用场景包括:循环神经网络和递归神经网络。
- Caffe2采用静态图,可以用Python训练模型,同时支持iOS和Android平台。
- TensorFlow和Caffe2在生产环境中应用广泛,尤其是在移动端。
- 优化:
09. CNN架构
本节介绍著名的CNN架构,重点讨论自2012年以来在ImageNet竞赛中获胜的CNN架构。
此外,我们还会在讲解过程中讨论一些有趣的架构。
第一个卷积神经网络是Yann LeCun于1998年提出的LeNet-5架构。
架构为:
CONV-POOL-CONV-POOL-FC-FC-FC
- 每个卷积滤波器大小为
5x5,步幅为 1 - 每个池化层大小为
2x2,步幅为 2 - 在数字识别任务中非常有用。
- 特别是,图像特征分布在整个图像中,而带有可学习参数的卷积操作能够以较少的参数在多个位置有效地提取相似特征。
- 它恰好包含 5 层。
2010 年,丹·克劳迪乌·西雷桑和尤尔根·施密德胡伯发表了最早的 GPU 神经网络实现之一。该实现使用 NVIDIA GTX 280 显卡,实现了多达 9 层神经网络的前向和反向传播。
AlexNet(2012 年):
这是一种卷积神经网络,开启了深度学习的发展,并在 2012 年 ImageNet 竞赛中获胜。
架构为:
CONV1-MAXPOOL1-NORM1-CONV2-MAXPOOL2-NORM2-CONV3-CONV4-CONV5-MAXPOOL3-FC6-FC7-FC8总共包含 8 层,其中前 5 层为卷积层,后 3 层为全连接层。
AlexNet 的错误率为
16.4%。例如,如果输入为 227 x 227 x 3,则各层的输出形状如下:
- CONV1 (96 个 11 x 11 滤波器,步幅 4,填充 0)
- 输出形状为
(55,55,96),权重数量为(11*11*3*96)+96 = 34944
- 输出形状为
- MAXPOOL1 (3 x 3 滤波器,步幅 2)
- 输出形状为
(27,27,96),无权重
- 输出形状为
- NORM1
- 输出形状为
(27,27,96),但现在已经不再使用了
- 输出形状为
- CONV2 (256 个 5 x 5 滤波器,步幅 1,填充 2)
- MAXPOOL2 (3 x 3 滤波器,步幅 2)
- NORM2
- CONV3 (384 个 3 x 3 滤波器,步幅 1,填充 1)
- CONV4 (384 个 3 x 3 滤波器,步幅 1,填充 1)
- CONV5 (256 个 3 x 3 滤波器,步幅 1,填充 1)
- MAXPOOL3 (3 x 3 滤波器,步幅 2)
- 输出形状为
(6,6,256)
- 输出形状为
- FC6 (4096 个神经元)
- FC7 (4096 个神经元)
- FC8 (1000 个神经元,用于分类得分)
- CONV1 (96 个 11 x 11 滤波器,步幅 4,填充 0)
其他细节:
- 首次使用 ReLU 激活函数。
- 曾使用归一化层,但现在已不再采用。
- 大量数据增强。
- Dropout 概率为
0.5。 - 批量大小为
128。 - SGD 动量为
0.9。 - 初始学习率为
1e-2,并在某些迭代中降低为原来的十分之一。 - 使用了 7 个 CNN 模型的集成!
AlexNet 是在 GTX 580 GPU 上训练的,但该显卡仅有 3 GB 显存,不足以在单机上完成训练,因此他们将特征图分成了两半进行计算。这是第一个分布式版本的 AlexNet。
直到现在,它仍然被广泛应用于迁移学习的各种任务中。
总参数量为
6000 万。
ZFNet(2013 年)
- 在 2013 年以 11.7% 的错误率获胜。
- 它的总体结构与 AlexNet 相同,但通过调整超参数获得了更好的效果。
- 同样包含 8 层。
- 与 AlexNet 不同的是:
CONV1:从 (11 x 11,步幅 4) 改为 (7 x 7,步幅 2)。CONV3、4、5:将滤波器数量从 384、384、256 分别改为 512、1024、512。
OverFeat(2013 年)
- 在 2013 年的 ImageNet 竞赛中赢得了目标定位任务。
- 该研究展示了如何在卷积神经网络中高效地实现多尺度和滑动窗口方法。此外,还提出了一种新的深度学习方法来预测目标边界,从而实现目标定位。
VGGNet(2014 年)(牛津大学)
- 更深的网络,层数更多。
- 包含 19 层。
- 在 2014 年以 7.3% 的错误率击败 GoogleNet 获胜。
- 使用更小的滤波器和更深的层数。
- VGG 的一大优势在于,连续使用多个 3 × 3 卷积可以模拟更大感受野的效果,例如 5 × 5 和 7 × 7。
- 整个网络都采用了简单的 3 x 3 卷积。
- 三个 3 x 3 卷积的效果相当于一个 7 x 7 卷积。

- 该架构包含多层卷积,随后是五次池化操作,最后是全连接层。
- 对于每张图像,仅前向传播就需要 96 MB 的内存!
- 大部分内存消耗在早期的卷积层。
- 总参数量为 1.38 亿。
- 大部分参数位于全连接层。
- 训练细节与 AlexNet 类似,例如使用动量和 dropout。
- VGG19 是 VGG16 的升级版,性能稍好,但需要更多的内存。
GoogleNet(2014 年)
更深的网络,层数更多。
- 包含22层。
- 使用高效的**Inception**模块。
- 参数量仅500万!比AlexNet少12倍。
- 在2014年与VGGNet并列夺冠,错误率为6.7%。
- Inception模块:
- 设计良好的局部网络拓扑结构(即“网络中的网络”NiN),然后将这些模块堆叠在一起。
- 其组成包括:
- 对前一层的输入同时应用多个并行的卷积操作:
- 多个不同尺寸的卷积核(1×1、3×3、5×5),
- 通过填充保持输出特征图的尺寸不变。
- 池化操作(最大池化),
- 同样通过填充保持输出特征图的尺寸不变。
- 多个不同尺寸的卷积核(1×1、3×3、5×5),
- 将所有卷积和池化的输出在深度维度上拼接起来。
- 对前一层的输入同时应用多个并行的卷积操作:
- 例如:
- Inception模块的输入为28×28×256。
- 并行应用的滤波器如下:
- (1×1),128个滤波器
# 输出形状为(28,28,128) - (3×3),192个滤波器
# 输出形状为(28,28,192) - (5×5),96个滤波器
# 输出形状为(28,28,96) - (3×3)最大池化
# 输出形状为(28,28,256)
- (1×1),128个滤波器
- 拼接后输出为(28,28,672)。
- 这种设计——我们称之为“朴素”设计——计算复杂度非常高。
- 以上例子中:
- [1×1卷积,128个] ==> 28×28×128×1×1×256 = 约2500万次运算
- [3×3卷积,192个] ==> 28×28×192×3×3×256 = 约3.46亿次运算
- [5×5卷积,96个] ==> 28×28×96×5×5×256 = 约4.82亿次运算
- 总计约8.54亿次运算!
- 以上例子中:
- 解决方案:使用1×1卷积的瓶颈层来降低特征图的深度。
- 受NiN(Network in network)启发。

- 采用瓶颈层后,该示例的总运算次数降至3.58亿次,相比朴素实现有了显著改善。
- 因此,GoogleNet多次堆叠Inception模块,构建出完整的网络架构,能够在不使用全连接层的情况下解决任务。
- 需要指出的是,在分类步骤之前,它使用了一个平均池化层。
- 完整架构:
- 2015年2月,引入了批归一化版本的Inception,即Inception V2。批归一化会计算某一层输出的所有特征图的均值和标准差,并用这些统计量对特征响应进行归一化。
- 2015年12月,他们发表了论文《重新思考计算机视觉中的Inception架构》,不仅详细解释了早期的Inception模型,还推出了新的V3版本。
第一代GoogleNet和VGGNet诞生于批归一化技术发明之前,因此它们在训练神经网络时采用了多种技巧以确保收敛。
ResNet(2015年,微软研究院)
152层模型用于ImageNet竞赛,以3.57%的错误率获胜,这一成绩甚至低于人类水平的错误率。
这也是首次成功训练出超过百层,甚至上千层的深度神经网络。
在ILSVRC’15和COCO’15比赛中横扫所有分类和检测任务!
如果我们在一个“普通”的卷积神经网络上继续堆叠更深的层,会发生什么?
- 深度越大的模型性能反而更差,但这并非过拟合所致!
- 学习过程会停滞,因为深层网络更难优化!
理论上,更深的模型至少应该与浅层模型表现相当。
一种解决方案是直接复制浅层模型中已经学习到的参数,并将新增的层设置为恒等映射。
残差块:
- 微软提出了残差块结构:
# 我们不直接学习新的表示,而是只学习残差部分 Y = (W2 * RELU(W1*x + b1) + b2) + X- 假设你已经有一个深度为N层的网络,只有当你添加新层能带来额外收益时,才值得继续增加层数。
- 为了确保第(N+1)层能够学习到与输入不同的信息,可以将未经过变换的输入X也传递到第(N+1)层的输出端。这样可以促使新层学习到不同于输入编码的内容。
- 此外,这种连接方式还有助于缓解非常深的网络中出现的梯度消失问题。
- 微软提出了残差块结构:
有了残差块,我们现在可以构建任意深度的深层神经网络,而不必担心难以优化的问题。
拥有大量层的ResNet开始采用类似于Inception瓶颈层的设计,以降低特征图的维度。
完整的ResNet架构:
- 堆叠残差块。
- 每个残差块包含两个3×3的卷积层。
- 在网络开头增加一个额外的卷积层。
- 最后不使用全连接层(仅用一个1000维的全连接层输出类别)。
- 定期将滤波器数量翻倍,并通过步幅2进行空间降采样(每个维度减半)。
- 实际训练ResNet时:
- 每个卷积层后都进行批归一化。
- 使用He等人提出的Xavier/2初始化方法。
- SGD结合动量(
0.9)。 - 初始学习率为0.1,当验证误差趋于平稳时将其除以10。
- 小批量大小为
256。 - 权重衰减为
1e-5。 - 不使用丢弃法。
- 堆叠残差块。
Inception-v4(2016年,论文编号:arXiv:1602.07261):结合了ResNet和Inception,于2016年提出。
各种架构的复杂度对比:

- VGG:内存占用最高,计算量最大。
- GoogLeNet:效率最高。
ResNet的改进:
- (2016年,论文编号:arXiv:1603.05027)《深度残差网络中的恒等映射》
- 由ResNet的创造者提出。
- 能进一步提升性能。
- (2016年,论文编号:arXiv:1605.07146)《宽残差网络》
- 认为关键在于残差连接,而非网络深度。
- 50层的宽ResNet性能优于152层的原始ResNet。
- 增加宽度而非深度在计算上更为高效(可并行化)。
- (2016年,论文编号:arXiv:1603.09382)《具有随机深度的深度网络》
- 动机:通过在训练过程中使用较短的网络来减少梯度消失问题和训练时间。
- 每次训练时随机跳过一部分层。
- 测试时则使用完整的深层网络。
- (2016年,论文编号:arXiv:1603.05027)《深度残差网络中的恒等映射》
超越ResNet:
(2017) FractalNet:无需残差连接的超深度神经网络
结论:
- ResNet目前仍是最佳默认选择。
- 网络架构正朝着极深的方向发展。
- 近两年来,许多模型都采用了类似“ResNet”的捷径结构,以促进梯度流动。
10. 循环神经网络
常规神经网络“前馈神经网络”:固定大小的输入经过若干隐藏单元后输出。我们称之为“一对一”网络。
循环神经网络RNN模型:

- 一对多
- 示例:图像字幕生成
- 图像 ==> 一系列单词
- 示例:图像字幕生成
- 多对一
- 示例:情感分类
- 一系列单词 ==> 情感
- 示例:情感分类
- 多对多
- 示例:机器翻译
- 一种语言的一系列单词 ==> 另一种语言的一系列单词
- 示例:视频帧级分类
- 示例:机器翻译
RNN也可用于非序列数据处理(一对一问题):
- 曾通过一系列“瞥视”完成数字分类任务:
- “基于视觉注意力的多目标识别”,ICLR 2015。
- 也曾逐块生成图像:
- 例如生成验证码。
- 曾通过一系列“瞥视”完成数字分类任务:
那么什么是循环神经网络?
循环核心单元接收输入x,并在每次读取输入时更新其内部状态。

RNN模块应返回一个向量。
我们可以通过在每个时间步应用递推公式来处理向量序列:
h[t] = fw (h[t-1], x[t]) # 其中fw是带有参数W的函数每个时间步都使用相同的函数和参数集。
(经典)循环神经网络:
h[t] = tanh (W[h,h]*h[t-1] + W[x,h]*x[t]) # 然后保存h[t] y[t] = W[h,y]*h[t]这是最简单的RNN示例。
RNN适用于处理相关数据的序列。
循环NN计算图:

h0初始化为零。W的梯度是所有已计算出的W梯度之和!- 多对多图:

- 最终损失也是所有损失之和,Y的权重为1,并通过累加所有梯度来更新!
- 多对一图:
- 一对多图:
- 序列到序列图:

- 编码器-解码器思想。
示例:
- 假设我们用字符构建单词,希望模型能够预测序列中的下一个字符。假设字符仅为
[h, e, l, o],单词为[hello]。- 训练:

- 此处只有第三次预测正确。需要优化损失。
- 我们可以将整个单词作为输入来训练网络。
- 测试时:

- 测试时逐字符进行处理,输出字符将成为下一个输入,同时保留之前的隐藏状态。
- 此链接包含全部代码,但使用的是截断式时间反向传播,我们稍后会讨论。
- 训练:
- 假设我们用字符构建单词,希望模型能够预测序列中的下一个字符。假设字符仅为
时间反向传播:先向前遍历整个序列计算损失,再向后遍历整个序列计算梯度。
- 但如果采用整个序列,速度会非常慢,占用大量内存,且可能无法收敛!
因此,在实践中通常采用“截断式时间反向传播”:我们只对序列的一部分进行前向和反向传播,而不是整个序列。
- 同时,始终将隐藏状态向前传递,但在反向传播时仅回溯有限的几步。
图像字幕生成示例:

- 使用
标记结束运行。 - 图像字幕生成的最大数据集是Microsoft COCO。
带注意力机制的图像字幕生成项目中,RNN在生成字幕时只会关注图像的特定区域,而非整张图像。
- 带注意力机制的图像字幕生成技术也被应用于“视觉问答”问题。
多层RNN通常会将某些层作为隐藏层再次输入。LSTM就是一种多层RNN。
RNN中的梯度反向传播可能出现梯度爆炸或梯度消失现象。梯度爆炸可通过梯度裁剪来控制,而梯度消失则可通过添加门控机制(如LSTM)来缓解。
LSTM代表长短期记忆网络。它旨在解决RNN中的梯度消失问题。
- 它由以下部分组成:
- f:遗忘门,决定是否清除细胞状态。
- i:输入门,决定是否向细胞写入信息。
- g:细胞状态门(?),决定写入细胞的信息量。
- o:输出门,决定释放多少细胞状态。


- LSTM的梯度计算类似于ResNet,非常简便。
- LSTM在训练过程中既能保持长期记忆,也能保留短期记忆,因此不仅能记住上一层的信息,还能记住更深层次的信息。
- 它由以下部分组成:
高速路网络介于ResNet和LSTM之间,目前仍在研究中。
更好、更简单的架构是当前研究的热点。
需要更深入的理论和实证理解。
RNN更适合处理具有相关性输入序列的问题,例如自然语言处理和语音识别。
11. 检测与分割
到目前为止,我们讨论的是图像分类问题。在这一节中,我们将讨论分割、定位和检测。
语义分割
我们希望为图像中的每个像素分配一个类别标签。

如图所示,语义分割并不区分不同的实例,只关注像素本身。
第一种思路是使用滑动窗口。我们选取一个小窗口,在整张图片上滑动。对于每个窗口,我们只需对中心像素进行分类。
- 这种方法虽然可行,但并不理想,因为它计算成本非常高!
- 效率极低!无法复用重叠区域之间的共享特征。
- 实际上,很少有人采用这种方法。
第二种思路是设计一个由多个卷积层组成的网络,一次性对所有像素进行预测!
- 输入是整张图像,输出则是每个像素都被标注的图像。
- 这需要大量的标注数据,而获取这些数据的成本非常高。
- 网络需要较深的卷积层结构。
- 损失函数是基于每个像素的真实标签与预测标签之间的交叉熵。
- 数据增强在这里非常有用。
- 这种实现方式的问题在于,直接在原始分辨率上进行卷积运算会非常耗时且占用大量资源。
- 因此,目前实际应用中很少见到这种做法。
第三种思路是在第二种思路的基础上改进的。不同之处在于,我们在网络内部进行了下采样和上采样操作。
我们进行下采样是因为直接处理整张图像的计算成本太高。因此,网络会经过多层下采样,最后再通过上采样恢复到原尺寸。
下采样操作包括池化和步幅卷积。
上采样则可以采用“最近邻插值”、“钉床插值”或“最大值反池化”等方法。
最近邻插值示例:
输入: 1 2 输出: 1 1 2 2 3 4 1 1 2 2 3 3 4 4 3 3 4 4
钉床插值示例:
输入: 1 2 输出: 1 0 2 0 3 4 0 0 0 0 3 0 4 0 0 0 0 0
最大值反池化则依赖于之前的最大值池化操作。我们会将最大值池化的位置填回原值,其余位置补零。
最大值反池化似乎是上采样的最佳选择。
此外,还有一种可学习的上采样方法,称为“转置卷积”。
- 它不是常规的卷积操作,而是将其逆向执行。
- 也被称为:
- 上卷积
- 分数步幅卷积
- 反向步幅卷积
- 关于上采样的具体实现细节,请参考这篇论文的第4章:[arxiv.org/abs/1603.07285]。
分类+定位:
- 在这个问题中,我们需要对图像中的主要目标进行分类,并用矩形框标出其位置。
- 假设图像中只有一个目标。
- 我们将构建一个多任务神经网络,其架构如下:
- 卷积网络层连接到:
- 用于分类的全连接层(即我们熟悉的普通分类问题)。
- 用于回归的全连接层,输出四个数值
(x, y, w, h)。- 我们将定位问题视为回归问题。
- 卷积网络层连接到:
- 该问题有两个损失函数:
- 分类部分使用Softmax损失。
- 定位部分使用回归损失(L2损失)。
- 总损失 = SoftmaxLoss + L2损失。
- 通常,前几层卷积会使用预训练好的网络,例如AlexNet。
- 这种技术还可以应用于许多其他问题,比如人体姿态估计。
目标检测
- 目标检测是计算机视觉的核心问题之一,我们将在本节中详细讨论。
- 与“分类+定位”相比,目标检测的目标是检测一个或多个不同的目标及其位置!
- 第一种思路是使用滑动窗口法。
- 这种方法曾长期有效。
- 具体步骤如下:
- 对图像的不同裁剪区域分别应用卷积神经网络,判断每个区域是目标还是背景。
- 问题在于,我们需要对大量不同的位置和尺度应用CNN,计算成本极高!
- 粗暴的滑动窗口方法会导致重复计算成千上万次。
- 区域建议机制可以帮助我们决定应该在哪些区域运行神经网络:
- 找出可能包含目标的团块状图像区域。
- 运行速度相对较快;例如,Selective Search算法可以在CPU上几秒钟内生成1000个区域建议。
- 因此,我们可以先使用区域建议网络筛选出候选区域,然后再应用滑动窗口法。
- 另一种方法称为R-CNN。

- 这种方法的缺点是:它会从图像中截取不同大小的区域,然后将它们缩放到统一尺寸后再输入CNN。缩放操作会引入误差。
- 此外,这种方法也非常慢。
- Fast R-CNN是在R-CNN基础上发展起来的一种方法。

- 它使用一个CNN完成所有任务。
- Faster R-CNN则进一步改进了区域建议机制,通过插入区域建议网络(RPN)来直接从特征中预测候选区域。
- 这是R-CNN系列中速度最快的一种。
- 还有一种无需区域建议的方法:YOLO/SSD。
- YOLO的意思是“你只需要看一次”。
- YOLO和SSD是两种独立的算法。
- 它们速度更快,但精度相对较低。
- 总结:
- Faster R-CNN速度较慢,但精度更高。
- SSD/YOLO速度更快,但精度较低。
密集字幕生成
- 密集字幕生成是“目标检测+字幕生成”的结合。
- 有关这一想法的论文可以在这里找到:[arxiv.org/abs/1511.07571]。
实例分割
- 实例分割可以看作是一个更全面的问题。

- 与仅预测边界框不同,实例分割不仅需要确定每个像素的类别,还需要区分不同的实例。
- 目前有许多不同的方法。
- 其中一种新方法是“Mask R-CNN”。
- 它类似于R-CNN,但在内部集成了语义分割模块。
- 这篇论文取得了许多优秀的实验结果。
- Mask R-CNN综合了本节课中讨论的所有内容。
- 其性能表现良好。
12. 可视化与理解
我们希望了解卷积神经网络内部究竟发生了什么?
人们希望能够信任这个“黑箱”模型(CNN),并清楚地知道它是如何运作并做出准确决策的。
一种初步的方法是可视化第一层的滤波器。
也许第一层卷积核的形状是5×5×3,卷积核数量为16个。这样我们就会得到16张不同“颜色”的卷积核图像。
- 结果发现,这些卷积核学习到的是类似于人脑的原始形状和方向性边缘。
- 无论你训练哪种卷积神经网络,比如AlexNet、VGG、GoogleNet或ResNet,这些卷积核看起来都差不多。
- 这就能告诉我们第一层卷积操作在图像中寻找的是什么。
我们也可以可视化后续层的卷积核,但它们并不能给我们提供太多信息。
- 比如说,如果第一层卷积核的形状是5×5×20,卷积核数量仍然是16个,那么我们就会得到16×20张不同的“灰色”卷积核图像。
在AlexNet的最后几层有一些全连接层。如果我们提取一张图像的4096维特征向量,并收集这些特征向量,
- 然后在这些特征向量之间进行最近邻搜索,找到与之最相似的真实图像,效果会比直接对原始图像运行KNN算法好得多!

- 这种相似性表明,这些卷积神经网络真正捕捉到了图像的语义信息,而不仅仅是像素级别的细节!
- 我们还可以对这4096维的特征向量进行降维,将其压缩到2维空间。
- 可以使用主成分分析(PCA)或t-SNE来实现。
- t-SNE更常用于深度学习中的数据可视化。示例可以参考这里。
我们可以可视化激活图。
- 比如说,如果CONV5的特征图大小是128×13×13,我们可以将其可视化为128张13×13的灰度图像。

- 其中某些特征图会对输入图像产生强烈的响应,这就说明该特征图正在寻找特定的模式。
- 这项技术由Yosinski等人提出,更多信息可以参见这里。
还有一种叫做最大激活补丁的技术,可以帮助我们可视化卷积神经网络中的中间特征。
- 具体步骤如下:
- 首先选择某一层和某个神经元。
- 比如在AlexNet中选择Conv5层,其特征图大小为128×13×13,然后挑选第17个通道(神经元)。
- 将大量图像输入网络,记录所选通道的激活值。
- 可视化那些对应于最大激活值的图像区域。
- 我们会发现每个神经元都在关注图像中的特定部分。
- 提取的图像区域是通过感受野确定的。
- 首先选择某一层和某个神经元。
- 具体步骤如下:
另一种方法是遮挡实验。
- 在将图像输入卷积神经网络之前,我们先遮挡住图像的一部分,并绘制出在不同遮挡位置下模型输出概率(即预测正确的概率)的热力图。
- 这样就能找出卷积神经网络最关注的图像区域。

显著性图可以告诉我们哪些像素对分类结果至关重要。
- 这种方法与遮挡实验类似,但采用了完全不同的思路。
- 我们计算未归一化的类别得分关于图像像素的梯度,取绝对值并在RGB三个通道上取最大值,最终得到一张灰度图像,它代表了图像中最关键的区域。
- 有时这种方法也可以用于语义分割任务。
(引导式)反向传播类似于最大激活补丁,但它能够定位我们真正关心的像素区域。
- 在这项技术中,我们像最大激活补丁一样选择一个通道,然后计算该神经元值关于图像像素的梯度。
- 如果只对每个ReLU单元的正梯度进行反向传播(引导式反向传播),生成的图像会更加清晰。
梯度上升法
通过这种方法可以生成一张能够最大程度激活某个神经元的合成图像。
它是梯度下降法的逆过程:不是寻找最小值,而是寻找最大值。
我们希望用输入图像来最大化某个神经元的激活值。因此,这里的目标是找到一张能够使该神经元激活程度最高的图像:
# R(I) 是自然图像正则化项,f(I) 是神经元的激活值。 I *= argmax(f(I)) + R(I)
梯度上升的具体步骤如下:
- 将图像初始化为零。
- 前向传播以计算当前得分。
- 反向传播以获取神经元值关于图像像素的梯度。
- 对图像进行小幅更新。
R(I)可能等于生成图像的L2范数。为了获得更好的效果,我们可以使用更复杂的正则化方法:
- 对图像的L2范数施加惩罚;同时在优化过程中定期执行以下操作:
- 对图像进行高斯模糊处理。
- 将像素值过小的部分置为0。
- 将梯度过小的像素也置为0。
- 对图像的L2范数施加惩罚;同时在优化过程中定期执行以下操作:
使用更高级的正则化方法可以让生成的图像更加清晰!

后面几层生成的图像似乎比前面几层更有意义。
我们也可以利用这一方法来欺骗卷积神经网络:
- 从一张任意图像开始。
# 一张完全随机的图片 - 随机选择一个类别。
# 随机选择一个类别 - 不断修改图像,使其尽可能地符合所选类别。
- 重复这个过程,直到网络被成功欺骗。
- 从一张任意图像开始。
欺骗网络的结果往往令人惊讶!

- 对人类来说,这些图像看起来并无差别,但仅仅加入一些噪声,就足以让网络做出错误的判断!
DeepDream:放大现有特征
- Google在其官网上发布了DeepDream工具。
- 实际上,DeepDream的工作原理与我们之前讨论的欺骗网络的方法相同,只不过它不是为了合成一张能够最大化某个特定神经元激活的图像,而是试图放大网络中某一层的神经元激活程度。
- 具体步骤如下:
- 前向传播:计算选定层的激活值。
# 准备一张输入图像(任何图像) - 将选定层的梯度设置为该层的激活值。
- 相当于
I* = arg max[I] sum(f(I)^2)
- 相当于
- 后向传播:计算图像的梯度。
- 更新图像。
- 前向传播:计算选定层的激活值。
- DeepDream的代码已经公开,你可以下载并自行尝试。
特征反演
- 通过这种方法,我们可以了解卷积神经网络的不同层分别捕捉到了图像中的哪些内容。
- 给定一张图像的卷积神经网络特征向量,找到一张新的图像,使其:
- 与给定的特征向量匹配。
- 同时保持自然外观(通过图像先验正则化)。
纹理合成
- 这是一个计算机图形学中的经典问题。
- 给定一块纹理样本,我们能否生成一张更大尺寸的相同纹理图像?
- 有一种不依赖于神经网络的算法:
- Wei和Levoy提出的基于树状矢量量化快速纹理合成算法,发表于SIGGRAPH 2000。
- 这是一种非常简单的算法。
- 问题在于,这是一个古老的问题,已经有许多算法解决了它,但对于复杂的纹理,简单的算法往往效果不佳!
- 2015年有人提出了基于梯度上升的“神经纹理合成”方法。
- 该方法依赖于Gram矩阵。
神经风格迁移 = 特征 + Gram重构
Gatys、Ecker 和 Bethge,《使用卷积神经网络进行图像风格迁移》,CVPR 2016
- PyTorch 实现 这里。
风格迁移需要对 VGG 网络进行多次前向和反向传播,速度非常慢!
- 训练另一个神经网络来为我们执行风格迁移!
- 快速风格迁移就是解决方案。
- Johnson、Alahi 和 Fei-Fei,《用于实时风格迁移和超分辨率的感知损失》,ECCV 2016
- https://github.com/jcjohnson/fast-neural-style
关于风格迁移的研究非常多,并且至今仍在继续!
总结:
- 激活值:最近邻、降维、最大特征块、遮挡实验
- 梯度:显著性图、类别可视化、欺骗性图像、特征反演
- 趣味应用:DeepDream、风格迁移
13. 生成模型
生成模型是无监督学习的一种类型。
监督学习与无监督学习对比:
监督学习 无监督学习 数据结构 数据:(x, y),其中 x 是数据,y 是标签 数据:x,只有数据,没有标签! 数据成本 在许多情况下,训练数据非常昂贵。 训练数据成本较低! 目标 学习一个将 x 映射到 y 的函数 学习数据中的一些潜在隐藏结构 示例 分类、回归、目标检测、语义分割、图像字幕 聚类、降维、特征学习、密度估计
自编码器是一种特征学习技术。

- 它包含编码器和解码器。编码器对图像进行下采样,而解码器则对特征进行上采样。
- 损失函数为 L2 损失。
密度估计是指我们希望学习或估计数据的底层分布!
与监督学习相比,无监督学习领域仍存在大量未解决的研究问题!
生成模型
- 给定训练数据,从相同分布中生成新的样本。
- 解决了密度估计这一无监督学习的核心问题。
- 我们有多种方法可以做到这一点:
- 显式密度估计:明确定义并求解学习模型。
- 学习一个无需显式定义即可从中采样的模型。
- 为什么需要生成模型?
- 可用于艺术创作、超分辨率、彩色化等领域的逼真样本。
- 时间序列数据的生成模型可用于模拟和规划(强化学习应用!)。
- 训练生成模型还可以推断出潜在表示,这些表示可用作通用特征。
- 生成模型分类:
- 在本讲中,我们将讨论 PixelRNN/CNN、变分自编码器和 GANs,因为它们是目前研究中的热门模型。
PixelRNN 和 PixelCNN
- 在完全可见信念网络中,我们使用链式法则将图像 x 的似然分解为一维分布的乘积:
p(x) = sum(p(x[i]| x[1]x[2]....x[i-1]))- 其中 p(x) 是图像 x 的似然,x[i] 是在给定所有先前像素的情况下第 i 个像素值的概率。
- 为了解决这个问题,我们需要最大化训练数据的似然,但像素值的分布非常复杂。
- 此外,我们还需要定义先前像素的顺序。
- PixelRNN
- 由 van der Oord 等人于 2016 年提出
- 通过 RNN(LSTM)建模对先前像素的依赖关系
- 从图像一角开始逐像素生成
- 缺点:由于必须逐像素生成,因此速度较慢!
- PixelCNN
- 同样由 van der Oord 等人于 2016 年提出
- 仍然从图像一角开始逐像素生成。
- 现在使用 CNN 对上下文区域建模来处理对先前像素的依赖关系。
- 训练速度比 PixelRNN 快(由于上下文区域的值已知,卷积可以并行化)。
- 但生成过程仍然需要按顺序进行,速度依然较慢。
- 有一些技巧可以改进 PixelRNN 和 PixelCNN。
- PixelRNN 和 PixelCNN 可以生成不错的样本,并且仍然是活跃的研究领域。
- 在完全可见信念网络中,我们使用链式法则将图像 x 的似然分解为一维分布的乘积:
自编码器
- 一种无监督方法,用于从无标签的训练数据中学习低维特征表示。
- 包括编码器和解码器。
- 编码器:
- 将输入 x 转换为特征 z。z 应该比 x 小,以便只提取输入中的重要信息。这可以称为降维。
- 编码器可以用以下方式构建:
- 线性或非线性层(早期)
- 深度全连接神经网络(后来)
- RELU 卷积神经网络(目前我们对图像使用这种方式)
- 解码器:
- 我们希望编码器将生成的特征映射回与 x 类似或相同的输出。
- 解码器可以采用与编码器相同的构建方式,目前也使用 RELU 卷积神经网络。
- 编码器是卷积层,而解码器是转置卷积层!意味着先减少再增加。
- 损失函数为 L2 损失函数:
L[i] = |y[i] - y'[i]|^2- 训练完成后,我们丢弃解码器。“# 现在我们有了所需的特征”
- 我们可以利用这个编码器来构建一个监督模型。
- 这种方法的优点是可以从输入中学习到良好的特征表示。
- 很多时候,我们手头的数据量很少。应对这种情况的一种方法是使用自编码器来学习如何从图像中提取特征,然后在此基础上用少量数据进行训练。
- 问题是,我们能否从这个自编码器中生成数据(图像)?
变分自编码器(VAE)
- 自编码器的概率论扩展——它将使我们能够从模型中采样以生成数据!
- 我们有通过编码器形成的特征向量 z。
- 然后我们选择一个简单的先验分布 p(z),例如高斯分布。
- 这对于隐藏属性来说是合理的:例如姿态、微笑程度。
- 条件分布 p(x|z) 很复杂(生成图像),因此用神经网络表示。
- 但我们无法计算如下方程所示的积分 P(z)p(x|z)dz:
- 解决完所有方程后,我们应该得到:
- 变分自编码器是一种生成模型的方法,但其生成的样本相比最先进的 GANs 更模糊、质量更低。
- 当前的研究热点:
- 更灵活的近似方法,例如使用更丰富的近似后验分布代替对角高斯分布。
- 在潜在变量中引入结构信息。
生成对抗网络(GANs)
- GANs 不依赖任何显式的密度函数!
相反,采用博弈论的方法:通过两人博弈来学习从训练数据分布中生成样本。
负责Facebook人工智能研究的Yann LeCun将GAN称为:
过去20年里深度学习中最酷的想法
问题:我们希望从复杂、高维的训练数据分布中采样。正如我们之前讨论过的,目前并没有直接的方法可以做到这一点!
解决方案:从一个简单的分布中采样,比如随机噪声,然后学习如何将其映射到训练数据分布。
因此,我们生成一张由简单分布采样的噪声图像,并将其输入到一个神经网络中,这个网络被称为生成器网络,它的目标是学会将噪声图像转换为我们期望的数据分布。
训练GAN:这是一个两人博弈的过程:
- 生成器网络:试图通过生成看起来逼真的图像来欺骗判别器。
- 判别器网络:试图区分真实图像和伪造图像。
如果我们能够很好地训练判别器,那么就可以进一步训练生成器,使其生成符合要求的图像。
GAN的损失函数可以表示为一个极小极大博弈,公式如下:
生成器网络的目标标签是0,而真实图像的目标标签则是1。
在训练过程中,我们会执行以下操作:
- 对判别器进行梯度上升;
- 对生成器也进行梯度上升,但使用不同的损失函数。
完整的算法及相应公式可以在这里查看:
补充说明:同时训练两个网络具有挑战性,可能会导致不稳定。选择具有更好损失曲面的目标函数有助于稳定训练,这也是当前研究的一个热点方向。
卷积架构:
- 生成器是一个使用分数步长卷积的上采样网络;判别器则是一个卷积网络。
- 为了使深层卷积GAN更加稳定,建议遵循以下准则:
- 将判别器中的所有池化层替换为步长卷积,并将生成器中的普通卷积替换为分数步长卷积。
- 两个网络都应使用批归一化。
- 对于更深的架构,应移除全连接隐藏层。
- 生成器的所有层都使用ReLU激活函数,除了输出层使用Tanh。
- 判别器的所有层则使用Leaky ReLU激活函数。
2017年可以说是GAN的爆发之年!相关研究迅速发展,取得了许多非常出色的结果。
目前,GAN在各种应用场景中的研究也非常活跃。
GAN相关的资源汇总可以在这里找到:https://github.com/hindupuravinash/the-gan-zoo
关于GAN使用的技巧和窍门,请参阅:https://github.com/soumith/ganhacks
NIPS 2016关于GAN的教程视频:https://www.youtube.com/watch?v=AJVyzd0rqdc
14. 深度强化学习
- 本节包含大量数学内容。
- 强化学习问题涉及智能体与环境的交互,环境会提供数值奖励信号。
- 其基本步骤如下:
- 环境 --> 状态
s[t]--> 智能体 --> 动作a[t]--> 环境 --> 奖励r[t]+ 下一状态s[t+1]--> 智能体 --> 以此类推。
- 环境 --> 状态
- 我们的目标是学习如何采取行动以最大化累积奖励。
- 一个例子是机器人运动控制:
- 目标:让机器人向前移动。
- 状态:关节的角度和位置。
- 动作:施加在关节上的扭矩。
- 每个时间步都保持直立并向前移动。
- 另一个例子是雅达利游戏:
- 在这个问题中,深度学习已经达到了最先进的水平。
- 目标:以最高分数完成游戏。
- 状态:游戏画面的原始像素输入。
- 动作:游戏操作指令,如左、右、上、下。
- 奖励:每个时间步的得分增减。
- 围棋比赛是另一个例子,AlphaGo团队在2016年取得的胜利对人工智能和深度学习来说是一项重大成就,因为这个问题非常复杂。
- 我们可以使用马尔可夫决策过程来从数学上形式化强化学习。
- 马尔可夫决策过程
- 定义为 (
S,A,R,P,Y),其中:S:可能的状态集合。A:可能的动作集合。R:给定 (状态, 动作) 对时的奖励分布。P:转移概率,即给定 (状态, 动作) 对时下一状态的分布。Y:折扣因子# 衡量我们对近期奖励与未来奖励的相对重视程度。
- 算法:
- 在时间步
t=0,环境采样初始状态s[0]。 - 然后,从 t=0 到结束:
- 智能体选择动作
a[t]。 - 环境根据 (
s[t],a[t]) 从R中采样奖励。 - 环境根据 (
s[t],a[t]) 从P中采样下一状态。 - 智能体接收奖励
r[t]和下一状态s[t+1]。
- 智能体选择动作
- 在时间步
- 策略
pi是一个从 S 到 A 的函数,用于指定在每个状态下应采取的动作。 - 目标:找到使累积折扣奖励最大化的策略
pi*:Sum(Y^t * r[t], t>0)。 - 例如:
- 解决方案是:
- 定义为 (
- 状态
s处的价值函数是遵循策略从状态s开始的预期累积奖励:V[pi](s) = Sum(Y^t * r[t], t>0) 给定 s0 = s, pi。
- 状态
s和动作a处的 Q 值函数是从状态s采取动作a后继续遵循策略的预期累积奖励:Q[pi](s,a) = Sum(Y^t * r[t], t>0) 给定 s0 = s,a0 = a, pi。
- 最优 Q 值函数
Q*是给定 (状态, 动作) 对时所能达到的最大预期累积奖励:Q*[s,a] = Max(对于所有 pi,Sum(Y^t * r[t], t>0) 给定 s0 = s,a0 = a, pi))。
- 贝尔曼方程
- 这是强化学习中的关键概念。
- 对于任意状态动作对 (s,a),该对的价值等于你将获得的奖励 r 加上你最终到达的状态的价值。
Q*[s,a] = r + Y * max Q*(s',a') 给定 s,a # 注意方程中没有策略。
- 最优策略
pi*对应于按照Q*规定在任何状态下采取最佳动作。 - 我们可以使用基于贝尔曼方程的迭代更新算法——值迭代算法——来得到最优策略。
- 由于现实世界应用中的状态空间维度非常大,我们将使用函数近似器来估计
Q(s,a)。例如,神经网络!这种方法称为 Q-learning。- 当我们需要表示一个复杂的函数但无法直接表达时,通常会使用神经网络。
- Q-learning
- 第一个解决强化学习问题的深度学习算法。
- 使用函数近似器来估计动作价值函数。
- 如果函数近似器是深度神经网络,则称为深度 Q 学习。
- 损失函数:
- 现在让我们考虑“玩雅达利游戏”问题:
- 我们的总奖励通常是屏幕顶部显示的奖励。
- Q 网络架构:
- 从连续样本批次中学习是一个问题。如果我们记录了训练数据并让神经网络处理,而数据不足,就会导致高偏差误差。因此,我们应该使用“经验回放”而不是连续样本,让神经网络反复尝试游戏,直到掌握为止。
- 在游戏(经验)剧集进行的过程中,不断更新一个包含转换信息的回放缓冲区表(
s[t],a[t],r[t],s[t+1])。 - 使用来自回放缓冲区的随机小批量转换数据来训练 Q 网络,而不是连续样本。
- 完整算法:
- 关于该算法在雅达利游戏中的演示视频可以在这里找到:“https://www.youtube.com/watch?v=V1eYniJ0Rnk”。
- 策略梯度
- 第二个解决强化学习问题的深度学习算法。
- Q 函数的问题在于它可能非常复杂。
- 例如:机器人抓取物体时,其状态空间维度非常高。
- 但策略却可以简单得多:只需闭合双手即可。
- 我们能否直接学习策略,例如从一组策略中找到最佳策略?
- 正则化策略梯度方程:
- 它会收敛到
J(ceta)的局部最小值,通常已经足够好! - REINFORCE 算法就是用来获取或预测最佳策略的算法。
- REINFORCE 算法的方程及直观理解:

- 这个方程存在较高的方差问题,我们能否解决这个问题?
- 方差缩减目前仍是一个活跃的研究领域!
- 循环注意力模型 (RAM) 是一种基于 REINFORCE 算法的模型,用于图像分类问题:
- 通过有选择地聚焦于图像的不同区域来获取一系列“瞥视”,从而预测类别。
- 灵感来源于人类的感知和眼球运动。
- 节省计算资源 => 更好的可扩展性。
- 对于高分辨率图像,可以节省大量计算。
- 能够忽略图像中的杂乱或无关部分。
- RAM 现在被广泛应用于许多任务中,包括细粒度图像识别、图像字幕生成和视觉问答等。
- 通过有选择地聚焦于图像的不同区域来获取一系列“瞥视”,从而预测类别。
- AlphaGo 同时使用了监督学习和强化学习,并且也采用了策略梯度方法。
- 斯坦福大学关于深度强化学习的一门优秀课程:
- 一门关于深度强化学习的优秀课程(2017年):
- 一篇不错的文章:
15. 深度学习的高效方法与硬件
- 原始讲座由斯坦福大学博士候选人宋翰主讲。
- 深度卷积网络、循环网络以及深度强化学习正在塑造众多应用,并深刻改变我们的生活。
- 比如自动驾驶汽车、机器翻译、AlphaGo等。
- 然而,当前的趋势表明,若要获得高精度,就必须使用更大(更深)的模型。
- 在ImageNet竞赛中,从2012年到2015年,为了达到更高的准确率,模型规模扩大了16倍。
- Deep Speech 2的训练次数是Deep Speech 1的10倍,而这仅仅发生在一年之内!
# 在百度
- 这给我们带来了三大挑战:
- 模型规模
- 将大型模型部署到个人电脑、手机或汽车上非常困难。
- 速度
- ResNet152训练耗时1.5周,最终仅达到6.16%的准确率!
- 长时间的训练限制了机器学习研究人员的工作效率。
- 能源效率
- AlphaGo:使用1920个CPU和280个GPU。每场比赛电费高达3000美元。
- 如果在手机上运行,电池会迅速耗尽。
- 谷歌在其博客中提到,如果所有用户每天使用谷歌语音识别功能3分钟,他们就需要将数据中心容量翻倍!
- 能量究竟消耗在哪里?
- 更大的模型意味着更多的内存访问,从而导致更高的能耗。
- 模型规模
- 我们可以通过算法与硬件协同设计来提升深度学习的效率。
- 从硬件和算法两个角度入手。
- 硬件入门:硬件家族
- 通用型
# 适用于任何硬件- CPU
# 注重延迟,单线程性能强大,像一头大象- GPU
# 注重吞吐量,拥有大量小线程,像一群蚂蚁
- GPU
- GPGPU
- 专用硬件
# 针对特定应用领域优化- FPGA # 可编程逻辑,成本较低但效率稍逊
- ASIC # 固定逻辑,专为特定应用设计(也可用于深度学习)
- 专用硬件
- CPU
- 通用型
- 硬件入门:数值表示
- 计算机中的数字是通过离散的内存单元来表示的。
- 对于硬件而言,在浮点运算中从32位降至16位是非常高效且节能的。
- 第一部分:高效推理的算法
- 神经网络剪枝
- 核心思想是:能否移除部分权重或神经元,同时保持网络原有的性能?
- 2015年,Han利用剪枝技术将AlexNet的参数从6000万减少至600万!
- 剪枝既可应用于CNN,也可应用于RNN,通过迭代操作最终能达到与原始模型相同的准确率。
- 事实上,人类的大脑也在经历类似的过程:
- 新生儿(50万亿个突触) ==> 1岁儿童(1000万亿个突触) ==> 青少年(500万亿个突触)
- 算法步骤:
- 获取已训练好的网络。
- 评估各神经元的重要性。
- 移除最不重要的神经元。
- 对网络进行微调。
- 若需继续剪枝,则返回步骤2;否则停止。
- 权重共享
- 核心思想是减少模型中的数值种类。
- 训练后量化:
- 例如,所有值为2.09、2.12、1.92、1.87的权重都将被替换为2。
- 可以通过对滤波器进行k均值聚类来实现,从而减少其中的数值种类。这样做还能降低梯度计算所需的运算次数。
- 经过训练后量化处理后,权重变为离散值。
- 训练后量化能够显著减少每一层中每个数字所需的比特数。
- 剪枝结合训练后量化可以协同作用,进一步压缩模型规模。
- 哈夫曼编码
- 我们可以使用哈夫曼编码来减少或压缩权重的比特数。
- 不常用的权重:用较多的比特表示。
- 常用的权重:用较少的比特表示。
- 将剪枝、训练后量化和哈夫曼编码结合起来的方法称为深度压缩。


- SqueezeNet
- 到目前为止,我们讨论的所有模型都是基于预训练模型。那么,我们能否设计一种全新的架构,以节省内存并减少计算量呢?
- SqueezeNet仅用50分之一的参数和一半的模型大小,就能达到AlexNet的准确率。
- SqueezeNet甚至可以通过深度压缩进一步压缩。
- 如今的模型更加节能,且速度大幅提升。
- 深度压缩已在Facebook和百度等公司得到实际应用。
- 量化
- 算法(量化权重和激活值):
- 使用浮点数进行训练。
- 量化权重和激活值:
- 收集权重和激活值的统计信息。
- 选择合适的基数点位置。
- 以浮点格式进行微调。
- 转换为定点格式。
- 算法(量化权重和激活值):
- 低秩近似
- 这是另一种用于CNN的尺寸缩减算法。
- 其核心思想是将卷积层分解,然后分别测试分解后的两个子层。
- 二值化/三值化网络
- 我们能否仅用三个数值来表示神经网络中的权重呢?
- 如果只使用-1、0、1,模型的规模将大大缩小。
- 这是一项新提出的概念,发表于2017年的“Zhu, Han, Mao, Dally. 训练后的三值量化,ICLR’17”。
- 该方法在训练完成后实施。
- 他们在AlexNet上进行了尝试,结果误差几乎与原版AlexNet相同。
- 每次寄存器操作的数量会增加:https://xnor.ai/
- **维诺格拉德变换】
- 基于3x3 WINOGRAD卷积,其运算次数比普通卷积更少。
- cuDNN 5已经采用了WINOGRAD卷积,显著提升了速度。
- 神经网络剪枝
- 第二部分:高效推理的硬件
- 我们开发了许多用于深度学习的ASIC芯片,它们的目标都是尽量减少内存访问。
- Eyeriss MIT
- DaDiannao
- TPU Google(张量处理单元)
- 它可以替代服务器中的显卡。
- 每台服务器最多可安装4块TPU。
- 相较于GPU,这种硬件的能耗更低,芯片面积也更小。
- EIE Stanford
- 由Han等人于2016年提出[et al. ISCA’16]。
- 不保存零权重,并直接在硬件层面进行量化。
- 他认为EIE具有更好的吞吐量和更高的能效。
- 我们开发了许多用于深度学习的ASIC芯片,它们的目标都是尽量减少内存访问。
- 第三部分:高效训练的算法
- **并行化】
- 数据并行 – 同时运行多个输入
- 例如,同时处理两张图片!
- 并行处理多个训练样本。
- 受批次大小限制。
- 梯度需要由主节点汇总。
- **模型并行】
- 将模型——即网络——拆分成若干部分。
- 按层将模型分配到多个处理器上。
- 超参数并行
- 同时尝试多种不同的网络架构。
- 很容易就能配置16到64个GPU来并行训练一个模型。
- 数据并行 – 同时运行多个输入
- **混合精度】使用FP16和FP32
- 我们已经讨论过,如果在整个模型中都使用16位实数,能耗将降低4倍。
- 那么,我们能否完全使用16位数字来构建模型呢?部分情况下可以采用混合FP16和FP32的方式。大部分地方使用16位,但在某些关键点仍需使用FP32。
- 例如,在FP16与FP16相乘时,就需要使用FP32。
- 训练完成后,模型的准确率可以接近AlexNet和ResNet等知名模型。
- **模型蒸馏】
- 问题在于,我们是否可以利用一个资深(优秀)的已训练神经网络来指导一个新手(新的)神经网络?
- 更多信息请参阅Hinton等人关于“暗知识”或“神经网络中的知识蒸馏”的研究。
- DSD:密集-稀疏-密集训练
- Han等人:“DSD:深度神经网络的密集-稀疏-密集训练”,ICLR 2017
- 具有更好的正则化效果。
- 其核心思想是:先以密集方式训练模型,随后对其进行剪枝,使其变为稀疏状态。
- DSD生成的模型架构相同,但能找到更好的优化解,达到更优的局部极小值,并实现更高的预测准确率。
- 在完成上述两步后,再将剩余的连接重新连接起来,再次进行密集训练。
- 这一方法显著提升了许多深度学习模型的性能。
- **并行化】
- 第四部分:高效训练的硬件
- 用于训练的GPU:
- Nvidia PASCAL GP100(2016年)
- Nvidia Volta GV100(2017年)
- 支持混合精度运算!
- 性能极其强大。
- 真正的新一代“核弹”。
- 谷歌于2017年5月宣布推出“Google Cloud TPU”!
- Cloud TPU可提供高达180 teraflops的算力,用于训练和运行机器学习模型。
- 我们之前的一个大型翻译模型,需要用32块市面上最好的商用GPU训练整整一天;而现在,只需使用八分之一的TPU pod,就能在一个下午内达到同样的准确率。
- 用于训练的GPU:
- 我们已经从PC时代过渡到了移动优先时代,如今正迈向AI优先时代。
16. 对抗样本与对抗训练
- 什么是对抗样本?
- 自2013年以来,深度神经网络在以下任务上的表现已达到甚至超越人类水平:
- 人脸识别
- 物体识别
- 验证码识别
- 由于其准确率高于人类,许多网站开始寻找替代验证码的解决方案。
- 以及其他任务……
- 在2013年之前,人们看到计算机犯错并不会感到惊讶!但如今,深度学习已经广泛应用,因此了解其存在的问题及原因显得尤为重要。
- 对抗样本是深度学习模型中出现的一种特殊错误现象。
- 这一话题直到深度学习的表现不断超越人类后才逐渐受到关注。
- 对抗样本是指经过精心构造,旨在使模型产生错误分类的输入数据。
- 在许多情况下,从人类视角来看,对抗样本与原始图像几乎没有明显差异。
- 近年来相关研究的历史:
- 因此,最早的相关研究可追溯到2013年。当时Szegedy训练了一个性能优异的卷积神经网络。
- 他希望通过深入理解CNN的工作机制来进一步优化它。
- 他输入一张物体的图像,并利用梯度上升法不断调整图像,使其被分类为另一类物体。
- 奇怪的是,最终生成的图像从人类视角来看几乎没有任何变化!
- 如果你亲自尝试,可能根本察觉不到任何改变,甚至会误以为这是程序错误。然而,仔细对比就会发现,这两张图实际上完全不同!
- 这种类型的错误几乎可以在我们所研究的任何深度学习算法中找到!
- 令人意外的是,RBF(径向基函数网络)能够抵御此类攻击。
- 用于密度估计的深度模型同样具备一定的抗干扰能力。
- 不仅神经网络容易被欺骗:
- 线性模型
- 逻辑回归
- Softmax回归
- SVMs
- 决策树
- 最近邻算法
- 线性模型
- 自2013年以来,深度神经网络在以下任务上的表现已达到甚至超越人类水平:
- 为什么会出现对抗样本?
- 在试图理解这一现象的过程中,2016年曾有人认为这源于高维数据下的过拟合问题。
- 他们认为,在如此高维的空间中,可能会存在一些随机误差,而这些误差是可以被检测到的。
- 因此,如果使用不同的参数重新训练模型,应该不会犯同样的错误。
- 然而,实验结果表明这种观点并不正确。不同模型往往会陷入相同的错误模式,这显然不是过拟合所致。
- 在上述实验中,研究人员发现问题并非随机因素,而是具有系统性的。
- 只要向某个样本添加特定的向量,无论使用哪种模型,都会导致错误分类。
- 或许这些问题更多地源于欠拟合,而非过拟合。
- 现代深度神经网络大多由分段线性单元构成:
- 整流线性单元(ReLU)
- 经过精心调优的Sigmoid函数
# 大多数情况下我们处于线性区间内 - Maxout
- LSTM
- 参数与输出之间的关系是非线性的,因为它们是通过乘法连接的,这也使得训练神经网络变得困难;而如果输入和输出之间是线性映射,则会简单得多。
- 在试图理解这一现象的过程中,2016年曾有人认为这源于高维数据下的过拟合问题。
- 对抗样本如何被用来攻破机器学习系统?
- 当我们测试神经网络的脆弱性时,需要确保真正实现了欺骗效果,而不仅仅是改变了输出类别。而对于攻击者而言,则希望让目标模型表现出某种异常行为(即“挖洞”)。
- 构造对抗样本时,通常会对扰动施加最大范数约束。
- 快速梯度符号法:
- 该方法基于几乎所有神经网络都采用线性激活函数(如ReLU)这一假设。
- 每个像素的修改幅度不得超过某个阈值ε。
- 具体步骤是:计算损失函数关于输入的梯度,取其符号,再将该符号乘以ε。
- 公式如下:
Xdash = x + ε * (梯度的符号)- 其中,Xdash表示对抗样本,x表示正常样本。
- 因此,只需利用梯度的方向和一个很小的ε值,就能成功生成对抗样本。
- 有些攻击则基于ADAM优化器。
- 对抗样本并不是随机噪声!
- 神经网络是在特定数据分布上进行训练的,因此在其适用范围内表现良好。但如果数据分布发生偏移,模型便难以给出正确的预测,反而更容易被欺骗。
- 深度强化学习同样可能被攻破。
- 权重攻击:
- 对于线性模型,可以提取其学习到的权重矩阵,取其符号,然后将其叠加到任意样本上,从而强制模型按照这些权重的指示进行分类。——安德烈·卡帕西,《破解ImageNet上的线性分类器》
- 事实证明,某些线性模型对对抗样本具有较强的抵抗力(较难被攻破):
- 尤其是浅层RBF网络,能够抵抗快速梯度符号法构造的对抗扰动。# 但问题在于,RBF网络在大多数数据集上的表现并不理想,因为它属于浅层模型。若试图加深网络层次,各层的梯度几乎都会变为零。
- 即使使用批归一化等技术,RBF网络也难以有效训练。伊恩认为,如果能找到更好的超参数或更优的优化算法替代梯度下降法,就有可能成功训练RBF网络,从而解决对抗样本问题。
- 我们还可以利用另一种模型来欺骗当前模型。例如,用支持向量机来欺骗深度神经网络。
- 更多细节请参阅论文:“Papernot 2016”
- 转移攻击
- 目标模型的权重、机器学习算法及训练数据集均未知;甚至可能是不可微分的。
- 使用自己的输入数据对该模型进行采样,将数据送入目标模型并获取输出。
- 基于这些数据训练自己的模型。“参照Papernot 2016中的表格”
- 在自己的模型上创建对抗样本。
- 将这些对抗样本应用于目标模型。
- 很大概率能够取得良好效果,成功欺骗目标模型。
- 为了将欺骗某网络的成功率提高至100%,可以在转移攻击中构建不止一个模型,而是多达五个模型,然后依次应用。(刘等人,2016年)
- 对抗样本同样会影响人类大脑!例如那些会欺骗视觉的图片,在互联网上随处可见。
- 实际上,已有研究团队成功欺骗了MetaMind、亚马逊和谷歌的真实模型。
- 曾有人将对抗扰动上传至Facebook,结果Facebook真的被欺骗了 :D
- 有哪些防御措施?
- 伊恩尝试过的许多防御方法都以失败告终!包括:
- 集成方法
- 权重衰减
- Dropout
- 在训练或测试阶段添加噪声
- 使用自编码器去除扰动
- 生成式建模
- 通用逼近定理
- 无论我们希望分类函数呈现何种形状,只要网络规模足够大,都能实现。
- 因此,我们可以训练一个专门用于检测对抗样本的神经网络!
- 线性模型和KNN比神经网络更容易被欺骗。相比之下,神经网络实际上可能更加安全。经过对抗训练的神经网络,在应对对抗样本方面的实际成功率远高于其他机器学习模型。
- 深度神经网络可以使用非线性激活函数,但关键在于找到合适的优化技术,或者直接采用像“ReLU”这样的线性激活函数。
- 伊恩尝试过的许多防御方法都以失败告终!包括:
- 如何利用对抗样本改进机器学习,即使不存在对手?
- 通用工程机(基于模型的优化)
#伊恩称之为通用工程机- 举例来说:
- 假设我们想要设计一辆速度极快的汽车。
- 我们训练了一个神经网络,让它分析汽车的设计图纸,并判断该图纸是否能造出一辆高速车。
- 此处的核心思想是优化网络的输入,使输出达到最大化,从而为我们提供最佳的汽车设计方案!
- 通过寻找能使模型预测性能最大化的输入,来实现新发明。
- 目前,我们借助对抗样本往往只能得到不理想的结果。但一旦解决了这个问题,我们就有机会制造出最快的汽车、最好的GPU、最舒适的椅子,甚至是开发出全新的药物……
- 举例来说:
- 总体而言,对抗样本的研究仍处于活跃状态,尤其是针对网络防御方面的研究。
- 通用工程机(基于模型的优化)
- 结论
- 攻击相对容易
- 防御则较为困难
- 对抗训练可以起到正则化和半监督学习的作用
- 数据分布外的输入问题是基于模型的优化方法普遍面临的瓶颈
- GitHub上有一个代码库,可以帮助你通过编程全面了解对抗样本的相关知识(基于TensorFlow构建):
- 一个用于构造攻击、构建防御以及对两者进行基准测试的对抗样本库:https://github.com/tensorflow/cleverhans
这些笔记由Mahmoud Badry于2017年制作。
常见问题
相似工具推荐
stable-diffusion-webui
stable-diffusion-webui 是一个基于 Gradio 构建的网页版操作界面,旨在让用户能够轻松地在本地运行和使用强大的 Stable Diffusion 图像生成模型。它解决了原始模型依赖命令行、操作门槛高且功能分散的痛点,将复杂的 AI 绘图流程整合进一个直观易用的图形化平台。 无论是希望快速上手的普通创作者、需要精细控制画面细节的设计师,还是想要深入探索模型潜力的开发者与研究人员,都能从中获益。其核心亮点在于极高的功能丰富度:不仅支持文生图、图生图、局部重绘(Inpainting)和外绘(Outpainting)等基础模式,还独创了注意力机制调整、提示词矩阵、负向提示词以及“高清修复”等高级功能。此外,它内置了 GFPGAN 和 CodeFormer 等人脸修复工具,支持多种神经网络放大算法,并允许用户通过插件系统无限扩展能力。即使是显存有限的设备,stable-diffusion-webui 也提供了相应的优化选项,让高质量的 AI 艺术创作变得触手可及。
everything-claude-code
everything-claude-code 是一套专为 AI 编程助手(如 Claude Code、Codex、Cursor 等)打造的高性能优化系统。它不仅仅是一组配置文件,而是一个经过长期实战打磨的完整框架,旨在解决 AI 代理在实际开发中面临的效率低下、记忆丢失、安全隐患及缺乏持续学习能力等核心痛点。 通过引入技能模块化、直觉增强、记忆持久化机制以及内置的安全扫描功能,everything-claude-code 能显著提升 AI 在复杂任务中的表现,帮助开发者构建更稳定、更智能的生产级 AI 代理。其独特的“研究优先”开发理念和针对 Token 消耗的优化策略,使得模型响应更快、成本更低,同时有效防御潜在的攻击向量。 这套工具特别适合软件开发者、AI 研究人员以及希望深度定制 AI 工作流的技术团队使用。无论您是在构建大型代码库,还是需要 AI 协助进行安全审计与自动化测试,everything-claude-code 都能提供强大的底层支持。作为一个曾荣获 Anthropic 黑客大奖的开源项目,它融合了多语言支持与丰富的实战钩子(hooks),让 AI 真正成长为懂上
ComfyUI
ComfyUI 是一款功能强大且高度模块化的视觉 AI 引擎,专为设计和执行复杂的 Stable Diffusion 图像生成流程而打造。它摒弃了传统的代码编写模式,采用直观的节点式流程图界面,让用户通过连接不同的功能模块即可构建个性化的生成管线。 这一设计巧妙解决了高级 AI 绘图工作流配置复杂、灵活性不足的痛点。用户无需具备编程背景,也能自由组合模型、调整参数并实时预览效果,轻松实现从基础文生图到多步骤高清修复等各类复杂任务。ComfyUI 拥有极佳的兼容性,不仅支持 Windows、macOS 和 Linux 全平台,还广泛适配 NVIDIA、AMD、Intel 及苹果 Silicon 等多种硬件架构,并率先支持 SDXL、Flux、SD3 等前沿模型。 无论是希望深入探索算法潜力的研究人员和开发者,还是追求极致创作自由度的设计师与资深 AI 绘画爱好者,ComfyUI 都能提供强大的支持。其独特的模块化架构允许社区不断扩展新功能,使其成为当前最灵活、生态最丰富的开源扩散模型工具之一,帮助用户将创意高效转化为现实。
NextChat
NextChat 是一款轻量且极速的 AI 助手,旨在为用户提供流畅、跨平台的大模型交互体验。它完美解决了用户在多设备间切换时难以保持对话连续性,以及面对众多 AI 模型不知如何统一管理的痛点。无论是日常办公、学习辅助还是创意激发,NextChat 都能让用户随时随地通过网页、iOS、Android、Windows、MacOS 或 Linux 端无缝接入智能服务。 这款工具非常适合普通用户、学生、职场人士以及需要私有化部署的企业团队使用。对于开发者而言,它也提供了便捷的自托管方案,支持一键部署到 Vercel 或 Zeabur 等平台。 NextChat 的核心亮点在于其广泛的模型兼容性,原生支持 Claude、DeepSeek、GPT-4 及 Gemini Pro 等主流大模型,让用户在一个界面即可自由切换不同 AI 能力。此外,它还率先支持 MCP(Model Context Protocol)协议,增强了上下文处理能力。针对企业用户,NextChat 提供专业版解决方案,具备品牌定制、细粒度权限控制、内部知识库整合及安全审计等功能,满足公司对数据隐私和个性化管理的高标准要求。
ML-For-Beginners
ML-For-Beginners 是由微软推出的一套系统化机器学习入门课程,旨在帮助零基础用户轻松掌握经典机器学习知识。这套课程将学习路径规划为 12 周,包含 26 节精炼课程和 52 道配套测验,内容涵盖从基础概念到实际应用的完整流程,有效解决了初学者面对庞大知识体系时无从下手、缺乏结构化指导的痛点。 无论是希望转型的开发者、需要补充算法背景的研究人员,还是对人工智能充满好奇的普通爱好者,都能从中受益。课程不仅提供了清晰的理论讲解,还强调动手实践,让用户在循序渐进中建立扎实的技能基础。其独特的亮点在于强大的多语言支持,通过自动化机制提供了包括简体中文在内的 50 多种语言版本,极大地降低了全球不同背景用户的学习门槛。此外,项目采用开源协作模式,社区活跃且内容持续更新,确保学习者能获取前沿且准确的技术资讯。如果你正寻找一条清晰、友好且专业的机器学习入门之路,ML-For-Beginners 将是理想的起点。
ragflow
RAGFlow 是一款领先的开源检索增强生成(RAG)引擎,旨在为大语言模型构建更精准、可靠的上下文层。它巧妙地将前沿的 RAG 技术与智能体(Agent)能力相结合,不仅支持从各类文档中高效提取知识,还能让模型基于这些知识进行逻辑推理和任务执行。 在大模型应用中,幻觉问题和知识滞后是常见痛点。RAGFlow 通过深度解析复杂文档结构(如表格、图表及混合排版),显著提升了信息检索的准确度,从而有效减少模型“胡编乱造”的现象,确保回答既有据可依又具备时效性。其内置的智能体机制更进一步,使系统不仅能回答问题,还能自主规划步骤解决复杂问题。 这款工具特别适合开发者、企业技术团队以及 AI 研究人员使用。无论是希望快速搭建私有知识库问答系统,还是致力于探索大模型在垂直领域落地的创新者,都能从中受益。RAGFlow 提供了可视化的工作流编排界面和灵活的 API 接口,既降低了非算法背景用户的上手门槛,也满足了专业开发者对系统深度定制的需求。作为基于 Apache 2.0 协议开源的项目,它正成为连接通用大模型与行业专有知识之间的重要桥梁。




















