《网格基础可视化的快速清晰概述》
如何使用一个 3 行的算法提供射线投射的不错替代方案
·
关注 发表在 Towards Data Science ·14 分钟阅读·2023 年 5 月 12 日
–
图片由 Autodesk Research [1] 提供。(已获许可)
在我之前的文章《与 Pascal’s Triangle 的简短直接漫步》中,我解释了如何改进基于网格的路径查找,以便在不使用视线测试的情况下获得高度直接的步行路径。本文将展示一种相关的技术,称为基于网格的可见性,该技术在不使用视线测试的情况下计算可见区域。基于网格的可见性在计算机科学界几乎没有听说过,但它是一种在各种人工智能应用中都很有意义的实用方法。它也非常容易实现,所需的代码仅有 3 行。继续阅读,发现解决视频游戏、移动机器人或建筑设计中的可见性问题的最简单选项。
可见区域问题
类似于路径查找,可见性分析出现在涉及人工智能和空间环境的多个领域中。视频游戏开发者可能希望计算从敌人瞭望塔可见的游戏地图区域。移动机器人工程师可能需要计算在测试机器人控制系统的模拟中,机器人视野的范围。建筑师可能希望分析建筑物内或街道上不同位置的人们的视野。可见性分析还可以用于估算光源照射的区域。
基本问题是这样的:给定一个 2D 顶视图地图,计算从一个点可见的空间区域。
如果你问计算机科学家如何解决这个问题,他们极有可能不会考虑我所称的基于网格的算法:一种通过计算邻近网格单元中的数字来得出每个网格单元中的数字的方法。可见区域问题几乎总是使用基于向量的可见性算法来解决,该算法涉及视线测试。最受欢迎的基于向量的可见性技术之一是射线投射,在这种技术中,从一个视点向不同方向投射许多射线。如果你对射线投射和其他基于向量的解决方案不熟悉,Red Blob Games网站上的2D 可见性教程提供了一个很好的背景介绍。
基于网格和基于向量的方法在路径查找和 2D 图形等其他空间应用中都很受欢迎。例如,我们都熟悉光栅(基于网格)和向量图像,并且认识到这两种类型的图像都有其优缺点。那么,为什么只有基于向量的方法在可见性问题中被广泛使用呢?我开始相信,虽然基于网格和基于向量的方法在可见性问题中都有优缺点,但基于网格的可见性被奇怪地忽视了,应该得到更多的关注。
基于网格的可见性
这里是用 3 行 Python 代码编写的基于网格的可见性。
for x in range(grid.shape[0]):
for y in range(int(x==0), grid.shape[1]):
grid[x,y] *= (x*grid[x-1,y] + y*grid[x,y-1]) / (x + y)
算法接受一个表示地图的网格,并对其进行修改以生成可见性结果。正如我们所见,转换过程包括遍历每个网格单元并应用线性插值。让我们通过将这 3 行代码放入一个简短的程序中来测试它们。请随意复制并运行下面的 Python 脚本。
import numpy as np
import matplotlib.pyplot as plt
# Set dimensions
nx = 25
ny = 25
# Create map
grid = np.ones((nx,ny))
wx = nx//10 + 1
wy = ny//10 + 1
grid[int(.3*nx):int(.3*nx)+wx,int(.1*ny):int(.1*ny)+wy] = 0
grid[int(.1*nx):int(.1*nx)+wx,int(.5*ny):int(.5*ny)+wy] = 0
grid[int(.6*nx):int(.6*nx)+wx,int(.6*ny):int(.6*ny)+wy] = 0
# Display map
plt.figure("Map")
plt.imshow(np.transpose(grid))
# Compute visibility
for x in range(grid.shape[0]):
for y in range(int(x==0), grid.shape[1]):
grid[x,y] *= (x*grid[x-1,y] + y*grid[x,y-1]) / (x + y)
# Display visibility
plt.figure("Visibility")
plt.imshow(np.transpose(grid))
plt.show()
程序首先创建并显示地图,一个 25x25 的网格,其中填充障碍物的单元格值为 0,空单元格值为 1。如下面所示,地图有三个方形障碍物。
25x25 的输入地图。(图片由作者提供)
程序随后将地图转换为可见性网格并显示出来。可见性网格填充了可见性得分,这些得分近似于从左上角的视点观察到每个网格单元的可见程度。可见性得分的范围从 0(完全被阻挡)到 1(完全可见)。这是可见性网格。
结果为 25x25 的可见性网格。(图片由作者提供)
每个障碍物都会从左上角投射阴影,尽管你会注意到阴影的边缘有些模糊。提高地图分辨率是一种锐化这些边缘的方法。如果我们将网格大小从 25 改为 225 个单元格……
nx = 225
ny = 225
…我们得到以下结果。
分辨率增加到 225x225 的可见性网格。(图片由作者提供)
在这里,我们看到更清晰、更准确的阴影。如果我们继续增加分辨率,可见性得分会变得越来越准确。实际上,结果会随着网格间距接近零而趋近于精确解。
根据应用情况,我们可能希望将每个网格单元分类为可见(1)或不可见(0)。我们可以在循环后应用 0.5 的阈值来实现这一点。
for x in range(grid.shape[0]):
for y in range(int(x==0), grid.shape[1]):
grid[x,y] *= (x*grid[x-1,y] + y*grid[x,y-1]) / (x + y)
grid[:] = (grid >= 0.5)
将第 4 行插入脚本中会给我们如下结果。
应用阈值后的 225x225 可见性网格。(图片由作者提供)
重要的是要记住,基于网格的可见性是一种近似方法。一些网格单元可能会被分类为可见,即使它们实际上应该仅在阴影中;而有些可能会被分类为被阻挡,即使它们实际上应该仅在可见区域内。但一般来说,如果网格间距相对于障碍物及其之间的间隙较小,结果应该具有良好的准确性。
在我们继续之前,我得承认我使用了一些技巧将算法缩减到 3 行:
-
在第二个
for
循环中,int(x==0)
这个表达式是一个巧妙的技巧,可以跳过网格单元[0, 0],因为插值公式会导致除以零的错误。 -
我依赖于 NumPy 库允许使用负索引访问数组的事实。其他编程语言可能需要更多的代码行来检查这一条件。
-
上述所有代码假设视点位于地图的角落。将视点移动到具有坐标
x0
和y0
的任意单元格需要在四个象限中各重复计算一次。
要将视点置于地图中心,请用以下代码替换脚本中计算可见性
部分的代码。
# Set viewpoint
x0 = nx//2
y0 = ny//2
# Define visibility function
def visibility_from_corner(grid):
for x in range(grid.shape[0]):
for y in range(int(x==0), grid.shape[1]):
grid[x,y] *= (x*grid[x-1,y] + y*grid[x,y-1]) / (x + y)
# Compute visibility
visibility_from_corner(grid[x0:,y0:])
visibility_from_corner(grid[x0::-1,y0:])
visibility_from_corner(grid[x0::-1,y0::-1])
visibility_from_corner(grid[x0:,y0::-1])
这是视点在中心时的结果。
225x225 的可见性网格,视点在中心。(作者图片)
使用 Excel 的一个巧妙技巧
这是一个我忍不住想展示的小技巧:在 Excel 中实现的网格可见性。以下的屏幕录制大约 1 分钟。
Excel 中的网格可见性。(作者录制)
想自己试试吗?按照下面的步骤操作即可。只需 1 到 2 分钟。
-
打开 MS Excel 并创建一个空白工作簿。
-
选择单元格B2,点击公式栏(或按
F2
),粘贴以下文本,然后按Enter
:=((COLUMN(B2)-2)*A2+(ROW(B2)-2)*B1)/((COLUMN(B2)-2)+(ROW(B2)-2))
-
重新选择单元格B2,按
Ctrl-C
进行复制,选择从B2到Z26的单元格范围,按Ctrl-V
进行粘贴。 -
在主页选项卡中,选择条件格式,突出显示单元格规则,小于。在第一个框(“格式小于”)中输入
0.5
,然后从右侧的下拉菜单中选择任意“填充”选项(例如,“浅红色填充,深红色文本”)。点击确定。 -
选择单元格B2,按
1
,然后按Enter
。 -
通过点击单元格A1上方和左侧的绿色三角形选择所有单元格,然后点击并拖动A和B之间的垂直线,以缩小单元格宽度,使所有单元格最终大致为正方形。
-
通过点击单元格并按
Backspace
创建障碍物。自动生成的阴影应从左上角扩展开来。
观察到,障碍物需要多单元格宽才能产生合理的阴影效果。
网格可见性的简要历史
网格可见性的历史解释了为何这一方法从未广泛被认可。首先,尽管其简单,但网格可见性直到 2004 年[2]才被发明,且其收敛性质直到 2008 年[3]才得到确立。到那时,基于向量的方法如光线投射已经变得普遍。计算机科学家们不再寻找替代的方法。其次,关于网格可见性的首篇论文来自一种称为水平集理论的数学分支,该领域以计算机科学家不熟悉的隐式方式表示几何图形。虽然水平集可见性方法适用于 2D 或 3D,并使用线性插值,但严格的 3D 替代方法,采用双线性插值,由建筑和城市信息学研究人员于 2013 年[4]开发。
大约在 2019 年,我和我的同事们对网格可视性产生了兴趣,作为分析大量计算机生成建筑设计的一种手段。在我们的开放获取期刊论文“基于网格的导航路径计数” [1]中,我们做出了以下观察:
-
原始的水平集可视性方法可以轻松地适应于计算机科学家熟悉的显式几何形状。 本文开头的 Python 代码是将原始插值公式与显式网格几何相结合的实现示例。
-
网格邻域的大小可以增加以产生更准确的结果。 本文中的示例迄今为止使用了 4-邻域,其中信息流向北、南、东和/或西。我的同事们和我在论文和一个名为SpaceAnalysis的建筑设计工具中使用了 8-邻域,这允许信息沿对角线流动。
-
基于网格的可视性结果可以通过概率理论特别是中心极限定理被证明收敛于精确解。 原始的证明来自水平集社区,使用了数值分析[3]。
-
线性插值产生的可视性评分可以被重新解释为从视点出发的最短网格路径中未被障碍物阻挡的部分。
最后的观察结果揭示了基于网格的中心路径寻路,这是本文的主要内容和我之前的 Medium 文章的主题,基于与网格可视性相同的基础数学。实际上,可以通过简单地计数路径来计算可见区域。
为了演示通过计数实现可视性,我们将假设视点位于左上角。我们从那个角落开始放置一个 1,然后重复地将数字向下和向右复制。当两个数字汇聚在同一个网格单元时,我们将它们加在一起。结果是每个网格单元包含从视点出发并最终到达该单元的网格路径的数量。例如,从视点到右下角有 742 条这样的路径。
从左上角的视点计数网格路径。(动画由作者提供)
接下来,我们重复这个过程,忽略所有障碍物。每个网格单元最终都拥有从视点到该单元的最大可能网格路径数量。这实际上只是帕斯卡三角形,一个在之前的文章中详细讨论的著名数字模式。观察到,从视点到右下角有最多 2002 条网格路径。
忽略障碍物时从视点计数网格路径。(动画由作者提供)
在我们的计数路径查找方法中,我们取了两组路径计数并将它们相乘。在计数可见性中,我们将两组路径计数相除。我们首先获取到达每个网格单元的实际路径数量(见上图),然后除以到该单元的最大可能路径数量(见第二动画),最终得到每个网格单元的可见性分数。我们将每个单元的可见性分数不低于 0.5 的单元标记为可见。例如,右下角的单元格由 742 条可能的 2002 条网格路径到达。它的可见性分数是 472/2002,即约为 0.37,因此被分类为不可见。
通过路径计数获得可见性分数。(作者提供的动画)
再次,我们在论文中证明了通过计数计算的可见性分数在数学上等同于原始插值公式所产生的分数。换句话说,两种方法都是解决可见区域问题的可行方法。然而,如果我们选择实现计数可见性,我们必须记住路径计数会随着距离指数级增加。如果我们用 64 位浮点数表示这些计数,路径计数将在达到视点 1030 网格移动后溢出。因此,我认为在实现基于网格的可见性时,默认使用线性插值方法是有意义的。同时,我认为路径计数的联系很有趣,值得分享。
更大的邻域
对于基于网格的可见性,你可能会担心其准确性,尤其是因为某些基于矢量的方法被认为能提供可见区域问题的精确解。关于精确解的现实是:它们只有在输入几何体精确的情况下才是精确的,但在实际中这种情况很少见。在对真实世界环境模型进行可见性分析、路径查找分析或任何空间分析时,由于离散化误差、测量误差以及在某些情况下的构建误差,模型几乎总是一个近似值。网格基可见性引入一些额外误差,是否会成为严重的缺陷,取决于具体应用。
尽管如此,仍有一种方法可以在不增加网格分辨率的情况下提高基于网格的可见性结果的准确性。到目前为止,我们的示例仅使用了 4-邻域,这是最简单但最不准确的二维网格邻域。如前所述,我们可以选择更大的网格邻域以获得更准确的结果。下图描绘了矩形网格的 4、8 和 16 邻域,以及三角网格的 6 和 12 邻域。
矩形和三角网格邻域。(图片由Autodesk Research [1]提供,已获许可)
为了查看更大邻域的效果,我们将从文章开头重写 Python 脚本。在这个新版本的程序中,visibility_within_cone
函数计算位于两个向量之间的锥体内的可见性分数。这可能不是最有效的实现,但它将帮助我们理解过渡到更大的网格邻域意味着在更多的较薄锥体内应用相同的算法。
import numpy as np
import matplotlib.pyplot as plt
# Set dimensions
nx = 25
ny = 25
# Create map
grid = np.ones((nx,ny))
wx = nx//10 + 1
wy = ny//10 + 1
grid[int(.3*nx):int(.3*nx)+wx,int(.1*ny):int(.1*ny)+wy] = 0
grid[int(.1*nx):int(.1*nx)+wx,int(.5*ny):int(.5*ny)+wy] = 0
grid[int(.6*nx):int(.6*nx)+wx,int(.6*ny):int(.6*ny)+wy] = 0
# Display map
plt.figure("Map")
plt.imshow(np.transpose(grid))
# Define visibility function
def visibility_within_cone(grid, u_direction, v_direction):
u = np.asarray(u_direction, dtype=int)
v = np.asarray(v_direction, dtype=int)
origin = np.array([0,0], dtype=int)
dims = np.asarray(grid.shape, dtype=int)
m = 0
k = 0
position = np.array([0,0], dtype=int)
while np.all(position < dims):
while np.all(position < dims):
if not np.all(position == 0):
pos = tuple(position)
pos_minus_u = tuple(np.maximum(origin, position - u))
pos_minus_v = tuple(np.maximum(origin, position - v))
grid[pos] *= (m*grid[pos_minus_u] +
k*grid[pos_minus_v]) / (m + k)
k += 1
position += v
m += 1
k = 0
position = m*u
# Compute visibility
visibility_within_cone(grid, [1,0], [0,1])
# Display visibility
plt.figure("Visibility")
plt.imshow(np.transpose(grid))
plt.show()
由于我们调用函数时使用的是向量[1,0]
和[0,1]
,所以我们仍然使用的是 4-邻域。结果与我们第一个脚本生成的结果相同。
25x25 4-邻域的可见性网格。(图片作者提供)
但现在我们可以轻松修改代码以使用 8-邻域。为此,请将Compute visibility
部分的代码替换为以下代码。可见性函数现在被应用两次,第一次是在对角线[1,1]
和网格轴[1,0]
之间的锥体内,第二次是在[1,1]
和[0,1]
之间。
# Compute visibility
visibility_within_cone(grid, [1,1], [1,0])
visibility_within_cone(grid, [1,1], [0,1])
这是 8-邻域的结果。阴影边缘变得更加清晰。
25x25 8-邻域的可见性网格。(图片作者提供)
最后,我们可以通过在 4 个锥体内应用可见性函数过渡到 16-邻域。
# Compute visibility
visibility_within_cone(grid, [2,1], [1,0])
visibility_within_cone(grid, [2,1], [1,1])
visibility_within_cone(grid, [1,2], [1,1])
visibility_within_cone(grid, [1,2], [0,1])
这是 16-邻域的结果。
25x25 16-邻域的可见性网格。(图片作者提供)
16-邻域似乎为大多数应用提供了足够的精度。然而,如果需要更高质量的结果,可以继续升级到 32-邻域、64-邻域等。
这解决了矩形网格的问题。三角网格,也称为六边形网格,实现起来更棘手,因为没有理想的方式来索引网格单元。各种索引策略在Red Blog Games教程中的六边形网格中有描述,其中包括使用视线测试的可见性部分。我把在三角网格上实现基于网格的可见性作为一个挑战留给你。
结论
基于网格的可见性是光线投射和其他基于向量的可见性方法的简单而实用的替代方案。由于其发现的时机和背景,这种方法对计算机科学家而言仍然相对陌生。但我希望你会同意,是时候让基于网格的可见性变得显而易见了,并且希望你能在自己的人工智能项目中找到使用它的机会。
更新:如果你想了解如何在 3D 中高精度地实现基于网格的可见性,请查看本系列的第三篇也是最后一篇文章: 3D 网格邻域的清晰而坚实的轮廓*。*
参考文献
[1] R. Goldstein, K. Walmsley, J. Bibliowicz, A. Tessier, S. Breslav, A. Khan, 基于网格的导航路径计数 (2022), Journal of Artificial Intelligence Research, vol. 74, pp. 917–955
[2] Y.-H. R. Tsai, L.-T. Cheng, H. Osher, P. Burchard, G. Sapiro, 基于 PDE 的隐式框架中的可见性及其动态 (2004) [PDF]. Journal of Computational Physics, vol. 199, no. 1, pp. 260–290
[3] C.-Y. Kao, R. Tsai, 用于可见性问题的水平集算法的性质 (2008) [PDF], Journal of Scientific Computing, vol. 35, pp. 170–191
[4] D. Fisher-Gewirtzman, A. Shashkov, Y. Doytsher, 基于体素的城市环境可见性分析 (2013), Survey Review, vol. 45, no. 333, pp. 451–461
自然语言处理模型的归一化快速指南
原文:
towardsdatascience.com/a-quick-guide-on-normalization-for-your-nlp-model-2dbd7d2d42a7
使用归一化加速模型收敛并稳定训练过程
·发表于Towards Data Science ·阅读时间 7 分钟·2023 年 9 月 14 日
–
由Mattia Bericchia拍摄,发布于Unsplash
介绍
高效训练深度学习模型是一项具有挑战性的任务。随着近期自然语言处理模型规模和架构复杂性的增长,问题变得更加棘手。为了处理数十亿的参数,提出了更多优化方法以实现更快的收敛和稳定的训练。其中一个最显著的技术是归一化。
在本文中,我们将探讨一些归一化技术,它们的工作原理,以及如何将其用于自然语言处理深度模型。
为什么不使用 BatchNorm?
BatchNorm [2] 是一种早期的归一化技术,旨在解决内部协变量偏移问题。
简单来说,内部协变量偏移发生在层的输入数据分布发生变化时。当神经网络被迫适应不同的数据分布时,梯度更新在批次之间发生剧烈变化。因此,模型需要更长时间来调整、学习正确的权重并收敛。随着模型规模的增长,这个问题变得更严重。
初始解决方案包括使用较小的学习率(以减少数据分布变化的影响)和小心的权重初始化。BatchNorm 通过在特征维度上对输入进行归一化,有效地解决了这个问题。
批量归一化(图片来源:作者)
该技术显著加快了收敛速度,并允许更高的学习率,因为模型对异常值的敏感度降低。然而,它仍然有一些缺点:
-
小批量大小: BatchNorm 依赖于批量数据来计算特征的均值和标准差。当批量大小较小时,均值和方差无法再代表总体。因此,BatchNorm 无法进行在线学习。
-
序列输入: 在 BatchNorm 中,每个输入样本的归一化依赖于来自同一批次的其他样本。这对序列数据效果不好。例如,我们有两个训练样本,长度不同 (a1, a2,…, a10) 和 (b1,b2,…,b20)。如果 token b11 与填充 token a11 一起归一化,这是否合适?在推理步骤中,如果我们有一个长度为 30 的序列 (c1, c2,…, c30),我们如何获得均值和方差来归一化 token c21?这就是 BatchNorm 不适用于 NLP 任务的关键原因。
-
并行化: 批量归一化模型难以并行化。由于元素(均值和方差)之间存在依赖关系,我们需要在设备之间进行同步。NLP 模型,如 Transformers,由于其大规模设置而受到影响。
这就是 LayerNorm [1] 出现的原因。2016 年提出的 LayerNorm 已经取代了 BatchNorm,稳步成为研究界最流行的归一化技术。
归一化技术的使用(来源)
那么,什么是层归一化,它为什么如此有效?
为什么 LayerNorm 表现如此出色?
与 BatchNorm 相对,LayerNorm 在每个数据样本维度上进行归一化。因此,在一个包含 n 个样本的训练批次 (x1, x2,…, xn) 中,归一化是在每个 xi 上独立完成的。
层归一化(图片由作者提供)
LayerNorm 已广泛应用于许多最先进的语言模型,如 BERT [5] 和 BLOOM [6]。它为什么表现如此出色?
首先,我们需要提到 LayerNorm 相较于 BatchNorm 的几个优点:
-
序列数据: 该技术引入了训练样本之间的独立性。因此,我们可以放心地对序列输入进行归一化,而不必担心训练样本之间的不同特性。
-
灵活的批量大小: 由于归一化是在每个样本上完成的,因此批量大小不再是问题。
-
训练和测试: 与 BatchNorm 不同,LayerNorm 不需要保持总体的移动均值或方差。因此,它在训练和推理时执行相同的计算。
-
并行化: 没有训练样本之间的依赖关系,因此我们可以在不同的设备上训练模型,而无需同步。
其次,我们将讨论归一化技术在训练稳定性方面如此有帮助的一个关键原因:它们在权重和输入变换下的不变性。不变性意味着归一化技术的结果不会受到输入变换的影响。
常见的变换有重新缩放和重新中心化。重新中心化不变性使模型对权重和数据中的随机噪声不敏感。与此同时,重新缩放不变性使输出对输入和权重的任意缩放保持弹性。
通过构建一个层归一化函数并在不同的变换上进行尝试,可以更容易理解不变性特征,以查看均值、方差和结果如何变化。
def custom_ln(x: torch.Tensor, w : torch.Tensor, dim: Tuple[int], eps: float=1e-05):
sum_input = x@w # multiply the input and the weight matrix
mean = torch.mean(sum_input, dim=dim, keepdim=True) # get the mean on sample dimension
std_var = torch.sqrt(torch.var(sum_input, dim=dim, keepdim=True) + eps) # get the var on sample dimension
return (sum_input-mean)/(std_var )
我在重新缩放和重新中心化矩阵权重(w)和数据集(x)后得到了以下结果。
不同变换下的层归一化结果(作者提供的图片)
如我们所见,归一化结果在权重重新缩放和重新中心化下保持不变。对于数据集变换,该技术对重新缩放具有不变性,但对重新中心化不具备不变性。
LayerNorm 能够使输出对这种变换保持弹性,这非常令人惊讶。它是如何做到的?让我们深入探讨数学细节,以更好地理解其内部发生了什么。
这里的内容有点复杂,因此可以跳过此部分。然而,我敢肯定,这将给你一个强烈的直觉,帮助你更好地理解归一化的工作原理。
Layer Norm 不变性的数学证明
我们有一个神经网络,权重为 W,输入为 x,偏置为 b 和激活函数为 f。神经网络的输出为 y = f(Wx + b)。
然后 LayerNorm 可以表示为:
LayerNorm 方差的数学证明如下所示。
权重矩阵重新缩放不变性
权重矩阵重新缩放不变性(作者提供的图片)
权重矩阵重新中心化不变性
权重矩阵重新中心化不变性(作者提供的图片)
数据集重新缩放不变性
数据集重新缩放不变性(作者提供的图片)
这就是 LayerNorm 对变换的不变性的证明。然而,并非所有的不变性都是必要的。RMSNorm [3] 是 LayerNorm 的一个较年轻的兄弟,只具有重新缩放不变性特征。然而,它已成为最近 LLM 架构如 Llama [4] 的首选。
是什么使 RMSNorm 更优越?
什么是 RMSNorm?
RMSNorm 于 2019 年发布,其中 RMS 代表“均方根”。尽管 LayerNorm 加速了收敛,作者指出它在每个训练步骤中消耗的时间更多。
基于 GRU 的 RNNSearch 的训练过程 [3]
作者还辩称,LayerNorm 的均值归一化对最终性能的影响微乎其微,因此可以为了计算效率而被移除。
根据这个假设,提出了 RMSNorm,以关注重新缩放不变性,并使用均方根正则化,如下所示。
RMSNorm(作者提供的图片)
由于我们跳过了均值计算,归一化变得更简单。通过这种优雅的优化,作者观察到在不同实现中速度提升了 7%-64%,且性能没有下降!
其中一个实验是 WMT14 英语-德语翻译任务,使用基于 GRU 的 RNNSearch 并采用 BLEU 分数指标进行评估。LayerNorm 和 RMSNorm 在测试中都取得了相似的分数。但 RMSNorm 的训练时间快了 25%。
test14 和 test17 上的 BLEU 分数[3]
更详细地观察训练中的验证分数也表明 RMSNorm 的表现与 LayerNorm 在所有训练阶段相当。这支持了最初的观点,即重新中心化不具有显著意义,RMSNorm 更加高效。
RNNSearch 在 newstest2013 上的 SacreBLEU 分数[3]
另一个有趣的指标是不同令牌位置的隐藏向量的均值和标准差。虽然基线的均值和方差变化很大,但使用 LayerNorm 和 RMSNorm 显著稳定了分布输出。这是归一化对于 NLP 模型至关重要的有力证明。
特定位置的均值(M)和标准差(S)统计[3]
我希望这篇文章能帮助你理解每种归一化技术在 NLP 任务中的优缺点。
下篇文章见!
参考文献
[1] Jimmy Lei Ba, Jamie Ryan Kiros 和 Geoffrey E Hinton。“层归一化。” arXiv 预印本 arXiv:1607.06450 (2016)。
[2] Sergey Ioffe 和 Christian Szegedy。“批量归一化:通过减少内部协方差偏移加速深度网络训练。” ICML, 2015。
[3] Zhang, Biao 和 Rico Sennrich。“均方根层归一化。” 神经信息处理系统进展 32 (2019)。
[4] Touvron, Hugo 等。“Llama: 开放且高效的基础语言模型。” arXiv 预印本 arXiv:2302.13971 (2023)。
[5] Devlin, Jacob 等。“Bert: 深度双向变换器的预训练用于语言理解。” arXiv 预印本 arXiv:1810.04805 (2018)。
[6] Scao, Teven Le 等。“Bloom: 一个 176b 参数的开放访问多语言模型。” arXiv 预印本 arXiv:2211.05100 (2022)。
Python 中美丽散点图的快速指南
原文:
towardsdatascience.com/a-quick-guide-to-beautiful-scatter-plots-in-python-75625ae67396
可视化全球生命预期与人均 GDP
·发布于 Towards Data Science ·阅读时间 9 分钟·2023 年 1 月 12 日
–
作者通过 Python Matplotlib 提供的图片
所以你已经知道了一些 Python 和 matplotlib。也许你和我一样,喜欢复杂、美丽且富有洞察力的图表。然而,当你遇到一些基础示例并试图自己复现时,如 这个文档页面 中所见,你可能会看到这样的情况:
这将生成如下图表:
虽然这张图非常色彩丰富,但相当简单,不太具备洞察力,代码也解释了其目的。在本文中,我将展示如何创建像文章开头看到的那样美丽而富有洞察力的散点图。
这个教程的代码笔记本 可以在这里找到,我们将使用的数据集可以在 这个链接 中找到。请注意,在本教程中,我已将数据挂载到驱动器中,因此你可以 做同样的事情,或者将数据下载到本地并运行 Jupyter Notebook。为了方便,你也可以从 我的 GitHub 下载数据。
导入
由于我将在这个例子中使用 Google Colab,你将看到特定的 Colab 驱动导入。但是,如果你是在本地进行操作,可以跳过这些。由于我们还将进行一些基本的数据清理和线性回归,我还导入了一些 Scikit-learn 类。
数据集:预期寿命与人均 GDP
对于这个例子,我们将使用预期寿命与人均 GDP数据集,该数据集可在ourworldindata.org/
找到。一旦你获取了数据并能够读取文件,让我们查看分析它的步骤:
-
加载数据
-
检查数据并重命名列以便于使用
-
提取具有 GDP 值的行/数据点
-
可视化人口分布
-
构建绘图函数
-
美观地绘制数据!
加载数据
首先,让我们加载并检查我们的数据。我们使用 Pandas 加载数据(无论你将数据放置在哪里),并重命名一些列以便于使用。
结果数据应如下所示:
作者绘制的图表——使用 Python Pandas 在 Colab 上生成
清理数据
请注意,许多数据点在GDP
列和Population
列中都有Nan
值。由于我们无法对缺失值进行分析,因此我们将从数据中删除这些点:
在清理了 GDP 数据并选择了 2018 年(你可以自己验证是否有进一步年份的 GDP 数据!)后,我们的数据将如下所示:
作者绘制的图表——使用 Python Pandas 在 Colab 上生成
请注意,我们还排除了World
数据点,因为它包含所有国家的总和(可以自由包括它,看看最终图表有何变化!)。
可视化人口分布
请注意,人口值以百万为单位。在绘图中,为了给不同的人口数阈值添加不同的颜色,我们希望查看其分布情况:
作者提供的图片,使用 Python Matplotlib 生成
哎呀!这告诉我们,大多数国家的人口在 0.0 到 0.2¹e9 = 200,000,000(2 亿)之间,而一些国家的人口超过了约 1200 万。由于左侧密度较大(更多国家的人口较少),我们可以忽略高人口国家,并制作一个集中在左侧国家的直方图:
作者提供的图片,使用 Python Matplotlib 生成
好得多!我们将用它来创建大致的值,以颜色编码不同人口密度的国家。
构建绘图函数
对于这一部分,我们将执行几个子步骤,如下所示。
函数定义
我们将按如下方式定义我们的函数:
注意三个参数:df
,这是我们经过初步预处理后的数据,apply_color
用于对人口密度进行颜色编码,以及regression
用于在图表上应用回归。
填补缺失数据
我们的数据仍然包含一些重要列的 NaN 值,即["Expectancy", "GDP", "Population"]
。虽然我们可以删除包含 NaN 的行,但这里更好的方法是用“有根据的猜测”来填补它们。常见的选项是列的均值或中位数,但在这里我们将使用一种称为K 最近邻(KNN)的机器学习算法。如果你不熟悉它,你可以在这里阅读相关内容。就我们的目的而言,它实际上是通过使用基于可用属性(比如预期寿命和 GDP)的最相似的 N 个国家的条目来预测人口值,并使用这些值的平均值来填补缺失值。
数据汇总
虽然这里的数据仅为 2018 年的数据,但鉴于更好的数据集,你可以将此分析扩展到更多年份。这就是为什么我们还汇总数据以确保所有年份都被考虑在内。此操作是使用 Pandas 的groupby()
,选择“Country
”列作为参数。此外,我们还会提前对数据进行四舍五入,以减少小数位数。
提取绘图变量
为了方便起见,我们将再次把列重新分配到各个变量。请注意,你可以直接查询数据框。然而,一个重要的步骤是,我们将把Population
列按一百万的比例缩放并乘以 2。这将控制绘制散点图时点的大小。
执行回归
我们图表的一个可选部分是绘制一条非常漂亮的线,这条线跟随所有不同点的均值,这些点代表了每个国家的 GDP 与其相应的预期寿命。这将使我们能够快速评估各个国家相对于总体趋势的状态。为此,你可以使用 Scikit-learn 的ElasticSearchCV
,这本质上是线性回归的混合体,它结合了 Lasso 和 Ridge 回归,为了更稳健的拟合而添加了正则化。你可以在维基百科文章中阅读相关内容,也可以查看相应的Scikit-learn 文档。此外,CV 代表“交叉验证”,这是一种在机器学习中减少模型方差的常见技术。你可以在这里了解更多。代码如下(注意regression
参数):
初始化算法后,我们将数据格式化为正确的格式(这里,X 参数是预测特征,y 是目标),然后拟合回归模型。接着,我们生成预测结果,最后将其整理成正确的格式。请注意,我们还会修剪预测值低于 90 的数据点,以避免图形超出边界。
开始绘图,上色并添加点密度
我们现在准备开始绘图。第一步是为每个国家的人口密度点上色。我们根据人口数量分配不同的颜色,仅在apply_color=True
参数设置为真时才应用此操作。还记得我们之前绘制的直方图吗?如果我们查看箱子的边界值,我们可以为人口设置一些合理的范围,并赋予其适当的颜色(当然,这些颜色对我来说有意义,但你可以选择任何你喜欢的颜色!)。
接下来,我们使用plt.figure()
开始绘图,并调用plt.scatter()
方法,具体取决于我们是否要上色:
这里:
-
s
参数将接收一个实数值向量,并相应地修改点的大小。因此,我们分配population
变量,它已经包含了每个国家值的适当缩放,与其人口数量成比例。人口越多,点就越大。 -
c
参数将为每个点应用相应的颜色,这些颜色是我们之前分配给数据框的。 -
alpha
参数将改变点的透明度。
此外,我们还可以用plt.annotate()
方法对高人口密度的点进行标注。为了获得相应的国家名称,我们对子集记录进行检索,获取它们的坐标,然后传递给方法。
注意 y 坐标中的+0.3
;这是为了将文本稍微移动远离点,以避免重叠。
回归线
接下来,我们使用reg.plot()
添加回归线,利用之前创建的reg_data
。这条线代表了某个国家在给定人均 GDP 的情况下的平均预期寿命,我们可以用它作为基线来比较其他国家的相对状况。
ls='--'
参数指定线条样式。还要注意,我们使用的是 GDP 数据(reg_data["X"]
)和相应的预测值作为绘图参数。
完成绘图
让我们完成绘图代码:
在第一部分,我们为 x 轴(人均 GDP)和 y 轴(预期寿命)添加标签,并为绘图提供一个适当的标题。此外,我们以对数刻度显示 x 值,因为它提供了更美观、更具洞察力的图形(试着去掉它看看会发生什么!)。
接下来,我们创建不同颜色的标签。由于 Matplotlib 一次性创建所有标签,为了创建带有适当颜色和名称的标签,我们创建了四条对应的“幽灵”线,这些线在最终图表中不会做任何事情,但会提供一个颜色编码的标签。
最后,我们创建图例并显示我们的图表。
总结一下
我们已经走了很长一段路。这就是整个函数的样子:
让我们来测试一下吧!
图片由作者使用 Python 生成
相当不错!一眼望去,我们可以看到所有世界各国相对于其人均 GDP 的预期寿命,以及它们相应的预期寿命测量值。此外,我们还可以看到一些人口相对较多的国家名称。
我们还可以设置apply_color=True
来区分不同的人口密度,并生成以下内容:
绘图由作者使用 Python 生成
看起来多么美丽啊!多亏了颜色编码,我们现在可以清晰地看到不同的人口密度。
最后,我们来添加回归线:
绘图由作者使用 Python 在 Google Colab 上生成
就这样!我们现在已经成功生成了你在文章开始时看到的图表。仅凭图表,我们可以一眼看出哪些国家在 2018 年相对于其 GDP 的预期寿命高于平均水平,通过查看哪些国家位于回归线的上方和之外。请注意,实际的回归线是一条线(显而易见!),而不是一条曲线,但因为我们在对数尺度下工作,它看起来更像是曲线,因为数值被改变了。
最后的话
美丽、信息丰富的图表是一门艺术,虽然一些库无疑会促进你的学习;但提高基础知识并学到一些新技巧永远不是一个坏主意。
我希望这篇文章对你来说很有趣,如果是这样的话,确保查看一下我其他的一些受欢迎的文章和系列!
数据科学基础
## 数据科学三部曲:NumPy、Pandas 和 Matplotlib 基础
所以你是 Python 新手。或者你可能已经熟悉这些库,但想要快速了解一下……
## 数据科学三部曲:NumPy、Pandas 和 Matplotlib 基础
GIT 基础
好吧,你来这里是因为你想学习 Git/Github。因此,不如直接写一段关于它的10 行
文字……
Python 中的函数式编程
曾经听说过函数式编程,却没有理解或者不知道从哪里开始?或者你可能会…
时间序列分析入门(使用 R)
在 Covid19 疫情期间,你也许听说过关于预测新情况的合作努力…
参考资料
用于此分析的数据及其原始分析由我们的世界数据完成,可以在 ourworldindata.org/grapher/life-expectancy-vs-gdp-per-capita
找到,其中引用了以下来源:
Madison 项目数据库(2020);联合国 WPP(2022);Zijdeman 等(2015)
从他们的页面:
“许可证:我们的数据中的所有可视化、数据和文章都在 知识共享 BY 许可协议下开放访问。您可以在任何媒介中使用、分发和复制这些内容,只要注明来源和作者即可。”
见 ourworldindata.org/about#legal
关注我
严格设计机器学习实验的快速指南
如何可靠地比较机器学习模型
·
关注 发表在向数据科学 ·7 分钟阅读·2023 年 2 月 8 日
–
我们经常听到或阅读到现代机器学习(ML)研究缺乏科学严谨性。在从事几年的机器学习研究并为会议和期刊审阅论文之后,我现在认为我对如何严格评估机器学习方法的有效性有了很好的理解。这篇文章旨在为机器学习研究人员和开发人员设计适当的实验和分析以评估他们的工作提供一个简单的指南。希望在阅读完这篇文章后,你将不再为如何可靠地评估你的机器学习模型的性能而感到困惑。对于初级机器学习研究人员,这篇文章也将帮助你了解什么样的实验可以说服审稿人接受你的工作,帮助你实现进入梦想会议的目标。
机器学习研究的不同风味。
首先,必须强调的是,对广泛的机器学习领域做出贡献有不同的方法,这些方法不需要相同类型的实验分析。一方面,一些应用工作可能会使用机器学习来解决特定领域的任务。另一方面,一些研究人员对开发可以用于解决任何数据相关问题的通用机器学习技术感兴趣。显然,这种机器学习研究主题的分类不是二元的,而是一个连续体。让我们讨论一些具体的例子来说明这种特定性-通用性谱:
-
我们希望构建一个神经网络,能够准确分类东北巴西珊瑚礁中的鱼类图像——这是我自己研究的产品推广。
-
我们希望找到一个适用于鱼类图像分类的良好神经网络架构。
-
我们希望为图像分类设计一个好的神经网络架构。
-
我们希望引入一个新的激活函数,该函数在任何神经网络中使用都很合适,无论输入数据格式如何。
这些工作中的每一个都可能是有意义和有影响力的,但我们可以很容易地理解它们具有不同的通用性水平,如下图所示。
机器学习贡献的特定性-通用性谱。
根据研究主题的通用性水平,期望进行不同类型的实验和分析,这有时可能会令人困惑。因此,让我们尝试澄清根据讨论的不同方法,适当的机器学习评估应该是什么样的。
针对特定领域的机器学习方法的评估。
让我们从例子 1 开始,这是一个非常具体的图像分类问题。在这里,目标是构建一个好的机器学习模型(可能是神经网络),能够正确分类东北巴西珊瑚礁中的鱼类图像。该模型将被生态学家用于研究这个特定的生态系统,以加快他们的研究进程。如果我们想解决这个问题,我们可以收集感兴趣生态系统中的鱼类图像,并用物种信息标注它们以构建数据集(或者如果有现成的数据集,也可以使用现有的数据集)。
首先,我们需要注意的是,所使用的数据集必须代表应用领域,即推断过程中会遇到的内容。在我们的示例中,这可以通过确保数据集中包含研究区域的多个位置,并且所有可能的本地物种都得到代表来实现。然后,如果我们想在这个数据集上比较两个机器学习模型(X 和 Y),我们需要
-
选择我们喜欢的评估指标——通常是分类的准确率,但如果我们想了解对稀有物种的性能,也可以是精确率或召回率。有关分类指标的更多信息,请参见这里。
-
进行适当的交叉验证方案,或者如果数据集较大且训练较慢,至少进行训练-测试拆分评估。有关交叉验证测试的更多信息,请参见这里。我们只需确保数据集在拆分前已被正确随机化,并且训练和测试拆分中不包含非常相似的图像,例如连续的视频帧,这样会影响评估结果。
在这种情况下,进行相对简单的评估并声称最佳模型是具有最佳测试值的模型是完全可以接受和严谨的。然而,我们要小心,不要仓促做出没有根据的结论。我们仅仅展示了 X 在特定任务(对巴西东北部珊瑚礁中的鱼进行分类)上的表现优于 Y,仅此而已。不能从中得出 X 在图像分类或甚至通用鱼类分类方面优于 Y 的结论。
通用机器学习技术的评估
在另一个极端,让我们讨论如何评估高度通用的机器学习方法,例如示例 4。在这里,我们的目标是展示使用我们新的激活函数对于任何神经网络设计都是有效的,无论应用领域如何。在这种情况下,评估所需的工作量是不同的。我们应该使用一个包含各种数据类型的数据池,来自不同领域(例如,图像、文本、音频等)和任务(例如,分类、回归)。然后,我们可以为这些数据集计算适当的测试指标。许多机器学习论文实际上在这里就停止了,并报告了大量表格,将他们的方法与文献中其他技术在各种数据集上的结果进行比较。这是不够的,通常是这些“机器学习缺乏严谨性”抱怨的原因。确实,读者不应该期望查看所有这些独立结果并得出关于哪种方法最好的结论。
相反,如果我们看到方法 X 经常比 Y 更好,我们必须通过适当的统计测试来证明这一点,以验证优越的结果不是偶然发生的。通常,比较两个机器学习模型在多个数据集上的表现,一个好的选择是进行Wilcoxon 符号秩检验,但我不会在这里详细讲解(如果需要我在后续帖子中讲解,请告诉我)。
与特定领域的机器学习方法不同,针对每个单独数据集的相关性可以减少关注。然而,如果我们想展示一种方法在特定问题(例如,图像分类)上的有效性,那么我们的评估数据集池必须具有代表性。
我的方法是特定的还是通用的?
到目前为止,我们已经讨论了我们特定性-通用性的光谱的极端情况。然而,有时决定一个研究主题是特定的还是通用的并不容易。例如,我们是否应该认为示例 2 是特定于鱼类分类领域的,并构建一个包含来自世界各地鱼类图像的大型数据集?还是应该考虑它是一个通用的鱼类分类器,并验证它是否在来自不同生态系统的多个鱼类图像数据集上有效?同样,对于示例 3,我们应该认为我们的新架构是特定于图像的还是通用的图像分类器?
对这些问题的答案是著名的:“这要看情况”,但我仍会尝试提供一些要素以回应。这里的想法是问自己:所提方法的预期用途是什么?
-
如果我们认为我们的模型可以直接用来解决现实世界中的任务而无需重新训练,那么它应该被视为特定领域的方法。例如,一个可以在任何生态系统中使用的鱼类分类器,而无需调整。
-
如果我们认为我们的方法更多是关于如何在特定子领域数据集上训练高效模型的方法,那么它可以被认为是通用的方法。
特定结果与通用结果之间的联系
我们都同意,基于特定领域数据集获得的结果不应被用来宣称一种方法在更广泛、通用的背景下的优越性。然而,如果这些结果用于元分析研究,它们仍然可以在未来得出通用结论时发挥作用。
不那么明显的是,相反的情况也适用:好的通用结果不应被用来证明在特定环境中部署某种方法的合理性。如果一种方法被证明在图像分类中效果良好,我们可能会被诱使在没有进一步验证的情况下将其用于我们特定的图像分类问题。然而,我们应该非常小心,因为即使一种方法在各种任务中平均表现良好,也并不意味着它在每个特定任务中都表现优异。例如,在下图中,X 在总体上被证明比 Y 更好(p 值 < 0.05),但如果我们关注的是解决与数据集 2 相关的任务,我们应该使用 Y。通用结果应该作为开发指南,用于了解哪些方法可能有效以及首先尝试哪些方法。
比较两个机器学习模型在 10 个数据集上的玩具示例。
实际限制
一旦我们确定了评估新方法所需的所有实验,实际进行这些实验有时会很困难(时间和预算限制、数据集不可用)。虽然不必事事做到完美,但至少在讨论结果时,你应该知道自己没有做哪些实验。这样,你可以相应地调整你的声明和结论。一般来说,进行机器学习评估没有绝对正确或错误的方式,我们只需避免提出没有实验支持的声明。
结论
设计严格的机器学习实验可能看起来令人望而却步,但实际上并不难。只需:
-
精确确定他试图评估的机器学习方法的类型:特定的还是通用的。
-
对于领域特定的机器学习模型:收集一个代表性数据集,选择相关的评估指标,并应用适当的交叉验证方案。
-
对于通用机器学习技术:收集一组代表性数据集,为每个数据集计算评估指标,应用适当的统计测试以确认直观结论。
如果你觉得这篇文章有用,请考虑在 Medium 上关注我,以便接收我关于机器学习研究的未来文章通知,或在 Twitter 上关注我,了解更多关于我的研究工作。
本文中使用的所有图像均由作者创建。
快速入门 PostgreSQL 连接和数据导入 Pandas
通过将 PostgreSQL 数据导入 Pandas,快速开始数据分析和模型构建
·发布在 Towards Data Science ·4 分钟阅读·2023 年 2 月 5 日
–
Sergi Ferrete 提供的照片,发布在 Unsplash
什么是 PostgreSQL?
PostgreSQL 是一个强大的 关系数据库管理系统(RDBMS),许多组织都在使用它。连接到它很简单,得益于优秀的 Python 生态系统,将数据导入 Pandas 的数据框也同样简单。让我们看一个简单的例子,帮助你入门。
本地运行 PostgreSQL
本地运行 PostgreSQL 的一种简单方法是使用 Docker。如果你尚未安装 Docker,可以 在这里 下载。安装 Docker 后,你可以运行以下命令来启动一个 PostgreSQL 容器。
前往 Docker Hub 搜索 postgres
。你会看到几个不同的镜像。我们需要的是 postgres
镜像;你可以使用以下命令将其拉取下来。
docker pull postgres
然后,你可以运行以下命令(按照 Docker Hub 上的文档)来启动一个容器。
docker run --name postgres -p 5432:5432 -e POSTGRES_PASSWORD =postgrespw -d postgres
你可以使用任何支持的 SQL 工具连接到数据库,例如 SQL Workbench。
作者提供的图片
CREATE DATABASE MAIN;
CREATE TABLE CONTACTS (
id integer PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
FIRST_NAME varchar(255),
LAST_NAME varchar(255)
);
INSERT INTO CONTACTS (FIRST_NAME, LAST_NAME)
VALUES ('Brian', 'Roepke');
SELECT * FROM CONTACTS;
运行上述命令将创建一个名为 MAIN
的数据库和一个名为 CONTACTS
的表。它还会向表中插入一行数据,然后从表中选择所有行;这应该能让你开始一个简单的本地 PG 设置。
导入
我们首先需要导入所需的库。我们将需要psycopg2
库来连接 PostgreSQL,还需要pandas
库来处理数据。此外,我们还将使用pandas
、os
、urllib
和sqlalchemy
来帮助我们连接到数据库。
import pandas as pd
import psycopg2
import os
from sqlalchemy import create_engine
from urllib.parse import quote_plus
接下来,我们要确保不将敏感信息硬编码到代码中,而是从环境变量中提取。如果您想了解更多关于此过程的信息,请查看这篇文章。
接下来,我们需要确保连接字符串中的任何信息都正确 URL 编码,例如用户名和密码,这可以通过urllib
中的quote_plus
函数轻松实现。让我们快速看一下示例密码及其编码方式。
fake_pw = "p@ssw0rd'9'!"
print(quote_plus(fake_pw))
p%40ssw0rd%279%27%21
接下来,我们可以创建包含连接到数据库所需所有信息的连接字符串。我们将使用字符串格式(在字符串前加上f
)来插入变量。我们还将使用quote_plus
函数来对用户名和密码进行编码。
uri = f"postgresql+psycopg2://{quote_plus(user)}:{quote_plus(pw)}@{host}:{port}/{db}"
alchemyEngine = create_engine(uri)
除了连接字符串,我们还将创建一个SQLAlchemy 引擎。
就这样!假设你没有收到错误消息,现在你已经连接到你的 PostgreSQL 数据库。让我们看看如何将数据提取到 Pandas 数据框中。
首先,我们将以字符串的形式定义一个查询。这里的最佳实践是使用三重引号("""
),这样可以在多行中编写查询,同时避免查询本身包含引号时的冲突,例如WHERE FIRST_NAME = 'Brian'
。
q = """SELECT * FROM CONTACTS"""
接下来,我们将创建之前创建的alchemyEngine
的连接。
dbConnection = alchemyEngine.connect();
然后我们将使用pandas
中的read_sql
函数将数据提取到数据框中。
df = pd.read_sql(q, dbConnection);
现在我们有了数据框,可以显示前几行并查看数据。
df.head()
一个最佳实践是完成后关闭连接。
dbConnection.close();
结论
PostgreSQL 是一个强大的关系数据库管理系统(RDBMS),被许多公司使用。我们介绍了如何连接到它并将数据导入 Pandas 数据框。我们还讨论了一些最佳实践,如将凭据存储在环境变量中,以及如何轻松地 URL 编码用户名和密码,这些密码通常包含不受支持的字符。
如果你喜欢阅读这样的故事并希望支持我作为一名作者,可以考虑注册成为 Medium 会员。每月 5 美元,您可以无限访问数千篇文章。如果您通过 我的链接注册,我将获得一小笔佣金,而您无需支付额外费用。
《快速入门指南:如何根除模型偏见》
图片来源于作者
·
关注 发布于 Towards Data Science ·12 分钟阅读·2023 年 1 月 19 日
–
本文由 Arize AI 的机器学习工程师 Amber Roberts 共同撰写
在今天的世界中,读到关于 AI 表现出歧视行为的新闻已是司空见惯。从反映持续存在的住房歧视遗产的房地产估值模型到在医疗保健中加剧获取护理和健康结果不平等的模型,不幸的是,例子很容易找到。随着机器学习(ML)模型变得更加复杂,这一问题的真实范围及其对边缘化群体的影响可能尚未完全了解。幸运的是,ML 团队可以采取一些简单步骤,以根除 ML 生命周期中的有害模型偏差。
什么是模型偏差?
模型偏差是指机器学习模型在其预测中做出一致的、系统性的错误。模型往往倾向于系统地学习错误的信号,因为没有考虑数据中包含的所有信息。模型偏差可能导致算法错过数据输入(特征)和目标输出(预测)之间的相关关系。本质上,偏差发生在算法从数据集中学习适当信号的能力不足时。几十年来,机器学习中的偏差已被认为是一个潜在问题,但在将模型投入生产时,它仍然是机器学习研究人员和工程师面临的复杂而具挑战性的问题。
偏差如何进入模型?
偏差可能通过多种来源引入到机器学习过程中,并通过模型预测得到强化。在模型开发的各个阶段,数据不足、不一致的数据收集和不良的数据实践都可能导致模型决策中的偏差。虽然这些偏差通常是无意的,但它们的存在可能对机器学习系统产生重大影响,并导致灾难性结果——从就业歧视到医疗保健中的误诊。如果你使用的机器学习管道包含固有的偏差,模型不仅会学习这些偏差,还可能加剧甚至放大它们。
识别、评估和解决可能影响结果的任何潜在偏差,是创建新的机器学习模型并在生产中维护它时的关键要求。作为机器学习从业者,我们有责任检查、监控、评估、调查和评估这些系统,以避免对模型决策有效性产生负面影响的偏差。
模型中的偏差原因涉及数据和模型本身。
表示偏差(数据)
-
应用: 由历史数据引入的偏差、历史偏差、样本失衡、受污染的例子
-
示例: 在新闻文章上训练的嵌入展现了社会中的性别刻板印象。
测量偏差(数据)
-
应用: 代理变量、样本量差异、特征有限
-
示例: 预测再犯可能性的代理测量导致黑人的刑罚比白人在同样罪行上的刑罚更严厉。
聚合偏差(模型)
-
应用: 为所有人群使用的单一聚合模型
-
示例: 如果你有一个单一的预测模型来预测特定疾病在少数群体中的发生概率,它可能会失败并表现出偏见。
评估偏差(模型)
-
应用: 用于评估的基准不代表一般人群。
-
示例: 如果你为加利福尼亚州的房价预测模型进行基准测试,然后尝试将其应用于南卡罗来纳州的房市,价格将会有偏差。
公平性前提
定义保护属性
当然,在定义谁是被保护的对象之前,你不能量化有害的模型偏差。
了解法律下的保护类别是一个好的第一步。大多数美国人可能知道 1964 年美国民权法案禁止基于种族和性别的歧视,但更少人知道其他属性——如遗传信息或国籍——也符合法律下的保护类别,并且当发生违规时可能会导致数百万或数十亿美元的罚款。
法律合规只是一个起点。许多大型企业也超越这些法律要求,拥有额外的保护类别或公开承诺多样性和公平性。
图片来源:作者
定义公平性
一旦你清楚了所有相关司法管辖区的保护类别,下一步就是定义公平性是什么样的。虽然这是一个复杂的话题,但一些基本原则可以帮助你。
图片来源:作者
一个主要的区别是群体(相等和成比例)公平性与个人公平性之间的差异。
-
群体公平性 的定义是保护属性获得相似的待遇或结果。
-
个人公平性 的定义是相似的个体获得相似的待遇或结果。
例如,假设一家银行正在评估 100 份抵押贷款申请。70 份申请来自男性,30 份来自女性。基于等比例的群体公平性,你会批准男性 50%的申请(35 份)和女性 50%的申请(15 份)。另一方面,基于等数量的群体公平性,50 份批准会平均分配——男性 25 份,女性 25 份。如果某一组中贷款资格较高,这两种结果都可能被认为是不公平的。行业中一种主流的方法是确保每个群体的预测准确性相同——这是公平机会与准确性的衡量标准。
作者提供的图像
数据建模阶段哪些易受偏见影响?
模型公平性 影响 数据建模管道的预处理、处理中和后处理阶段。公平干预,即采取措施确保模型不对某些群体产生偏见,应在该过程的每个阶段实施。
预处理
-
这是什么? 数据处理的最早阶段,此阶段将数据转换为机器学习模型的输入。
-
为什么在此阶段对模型公平性进行干预? 在机器学习生命周期的这一最早阶段进行干预,可以对数据建模过程及其后续指标产生重大影响。
-
如何在此阶段实现公平干预? 移除、遮蔽、模糊、重命名或替换敏感属性。
-
示例: 一家银行有意建立一个预测贷款违约的模型,可能会对数据进行抽样,以确保其包含来自不同种族、性别和地理位置的申请人的代表性混合,然后移除数据中的敏感变量,以防这些变量被用于模型中。
处理中
-
这是什么? 处理过程指的是任何改变机器学习模型训练过程的行动。
-
为什么在此阶段对模型公平性进行干预? 如果由于计算限制或对专有或许可数据的限制无法在最早阶段进行干预,那么在训练过程中进行干预是下一最佳选择。在此阶段干预可以让团队保持其训练数据集的原始状态,不被修改。
-
如何在此阶段实现公平干预? 通过向模型的损失函数中添加额外的项来进行模型正则化,以确保没有一个特征不公平地主导模型的决策。你还可以使用对抗模型来减少模型中的不公平或虚假信息。
-
示例: 一家医疗提供商训练一个预测患者结果的模型,可能会创建一个对抗模型,使用目标模型的输出预测患者的受保护类别。这是为了确保患者的个人信息(如收入、种族和性别)不是其医疗结果的预测因素。
后处理
-
这是什么? 发生在模型在处理数据上训练之后。
-
为什么在这个阶段介入模型公平性? 当团队从前一个团队继承一个模型却不了解该模型时,这可能是他们公平性干预的最早阶段。
-
如何在这个阶段实现公平性干预? 在决策被用户收到之前使决策公平;第三方审计工具和使用机器学习可观测性工具的偏见追踪可以提供帮助。
-
示例: 一家提供宽带服务的公司有一个预测客户流失的模型,希望确保在向客户提供折扣时不产生歧视。该公司在模型部署过程中实施了公平性检查,使用公平性特定指标。然后,偏见追踪监控模型在多样化客户群体上的表现,以确保它不对任何特定群体存在偏见,从而保持输出公平。如果存在算法偏见,决策会被平等化。
什么是主流模型公平性指标?
根据你的目标,有许多模型公平性指标是适用的。这里是主流指标的定义和建议,以及每种指标的使用场景。
在决定使用哪个公平性指标时,你必须考虑需要什么见解,以确保你的模型没有表现出歧视。关心公平性的团队——特别是那些在高度监管行业如健康、贷款、保险和金融服务领域工作的团队——通常希望看到他们的模型在敏感属性(如种族或性别)上是否公平和无偏。当模型存在偏见时,团队需要知道哪个群体经历了最多的偏见,以便采取措施。
为了理解你评估的时间段内的公平性指标值,许多公司使用四分之一规则。四分之一规则是用于的一个阈值,由像美国平等就业机会委员会这样的监管机构帮助识别对受保护类别的负面待遇。由于理想的公平性分数是 1,当利用四分之一规则时,你通常会测量你的公平性指标分数是否落在 0.8 到 1.25 的范围之外。如果分数低于 0.8 或高于 1.25,你的模型可能对所选的敏感群体存在算法偏见。
从上面的决策树可以看出,选择的公平性指标取决于你的模型是否解决了不同表现、相等数量或辅助行为的问题。
让我们看看这些指标的使用时间和场景(注意:FP = 假阳性,TP = 真阳性,FN = 假阴性,TN = 真阴性)。
召回平衡
-
定义: 衡量模型对于一个组与另一个组的“敏感性”,或模型正确预测真阳性的能力
-
何时使用: 如果子组中的召回率接近,则实现了召回平衡
-
如何计算: 召回平衡 = 召回 _ 敏感组 / 召回 _ 基准组 ; 召回 = TP / (TP + FN)
假阳性率平衡
-
定义: 衡量模型是否对敏感组的正类预测不准确,相对于基准组
-
何时使用: 如果子组中的假阳性率(假阳性数与总负数的比率)接近,则实现了假阳性率平衡
-
如何计算: 假阳性平衡 = FPR_ 受限组 / FPR_ 特权组; 假阳性率 = FP / (FP + TN)
不平等影响
-
定义: 受保护类别的不利待遇的量化衡量
-
何时使用: 不平等影响,也称为比例平衡,用于检查不同组的结果比率是否与它们在总体中的比例相同
-
如何计算: 如果男性的工作机会率为 50%,女性的工作机会率为 25%,那么这两个率的比率为 2,表示存在不平等影响
一旦通过咨询公平性树定义了业务问题背景中的公平性,你可以计算你的平衡得分,并使用五分之一规则来确定是否需要在模型开发流程的预处理、处理中或后处理阶段进行干预。有关要实现的平衡类型以展示算法中立性,请参见下文。
第一类平衡
-
描述: 在假发现率(FDR)平衡和假阳性率(FPR)平衡中的公平性
-
计算: FDR = FP / (TP + FP) ; FPR = FP / (TN + FP)
第二类平衡
-
描述: 在假遗漏率(FOR)平衡和假阴性率(FNR)平衡中的公平性
-
计算: FOR = FN / (TN + FN) ; FNR = FN / (TP + FN)
平均赔率
-
描述: 在假阳性率(FPR)平衡和真阳性率(TPR)平衡中的公平性
-
计算: FPR = FP / (TN + FP) ; TPR = TP / (TP + FN)
监督公平性
-
描述: 在第一类和第二类平衡中的公平性
-
计算: 见上文
总体公平性
-
描述: 在混淆矩阵中使用的所有指标的公平性
-
计算: FP, TP, FN, TN
有哪些工具可以帮助应对模型偏见?
有多种工具被开发出来以帮助应对整个机器学习生命周期中的算法偏见。
模型构建与验证
大多数解决方案专注于处理模型开发的初始阶段,目的是在模型发布之前提供模型公平性检查。
工具示例:
-
Aequitas:一个开源偏差审计工具包,用于对机器学习模型进行歧视和偏差审计。
-
Arize AI (完全披露:我是 Arize 的联合创始人!):提供模型公平性检查,比较训练基线和生产数据,并进行根本原因分析工作流。
-
IBM Fairness 360:一个开源工具包,帮助你通过审计检查、报告和缓解机器学习模型中的歧视和偏差。
-
Google 的 PAIR AI:提供多个针对特定用例的工具,包括一个用于缓解图像数据集公平性和偏差问题的工具,支持 TensorFlow Datasets API。
尽管其中一些工具可以用于汇总公平性指标和事后解释(即模型解释性),这些对于审计很有用,但它们大多数并不适用于生产中的实时监控。
生产中的监控
在生产中监控公平性指标很重要,原因很简单:在部署的 AI 中,模型偏差发生是时间问题,而非是否发生的问题。概念漂移、训练中未见的新模式、训练与服务偏差以及异常值挑战着即使是最先进的团队,这些团队在训练中表现完美且通过验证阶段的模型也难以避免。
以下是一些提供生产中实时公平性监控的平台:
-
Arize:提供自动监控和公平性检查,通过多维比较揭示模型特征和群体,帮助发现算法偏差。
-
DataRobot:监控如比例平衡的公平性指标,并通过工作流将生产数据与训练数据进行比较。
团队应如何解决模型偏差?
解决模型偏差的第一步是理解数据,确保团队拥有正确的工具,并确保组织治理到位以确保公平。团队需要了解数据建模管道中对偏差有价值的预处理、处理和后处理阶段,因此,需要在这些阶段之一(如果不是多个阶段)进行公平性干预。以下是组织在这些阶段实现公平性的一些步骤。
步骤 1:使受保护类别数据对模型构建者和维护生产模型的机器学习团队可用
根据最近的一项调查,79.7%的机器学习团队报告称,他们“缺乏根除偏差或伦理问题所需的受保护数据”,至少有时如此,近一半(42.1%)表示这至少有时是一个问题。这需要改变。正如一位研究人员所说,无视并不能实现公平。
步骤 2:确保你拥有生产中公平性的可视化工具,理想情况下是在模型发布之前
在模型构建阶段结合公平性检查与定期事后审计,在模型偏差可能导致现实世界伤害的情况下是远远不够的。持续监控和警报可以帮助揭示在现实世界中不可避免出现的盲点(未知的未知),并加快解决时间。当模型所有者和维护生产模型的机器学习工程师拥有优化的指导和工具时,良好的结果就会发生。
步骤 3:成为内部变革推动者并迅速行动
解决模型偏差不仅仅是机器学习的问题。许多挑战——例如公平性与业务结果之间的权衡或团队之间责任的分散——只能通过多个团队和高层的参与来解决。机器学习团队在构建一种多管齐下的方法方面处于良好的位置,该方法结合了专门构建的基础设施、治理和专门的工作组以确保问责。
结论
当然,这些步骤只是开始,行业在公平性方面还有很长的路要走。识别问题仅仅是战斗的一半;采取行动至关重要。在群体层面上,机器学习可观测性和快速追踪模型公平性问题的原因可以提供帮助,特别是在知道何时重新训练或恢复到以前的模型(或不使用模型)时。
联系我们
如果这篇博客引起了你的兴趣,并且你渴望了解更多关于机器学习可观测性和模型监控的信息,请查看我们的其他博客和资源! 随时联系我们提出任何问题或意见,或注册一个免费账户,如果你有兴趣加入一个有趣的、明星般的工程团队,帮助模型在生产中取得成功,可以在这里找到我们的开放职位!
魔方与 Markov 链
图片来自 Unsplash,由作者修改
我们获得了 使用 Markov 过程描述 优化解决魔方的概率
·
关注 发表在 Towards Data Science ·14 分钟阅读·2023 年 8 月 4 日
–
魔方是一个具有巨大状态空间的规划问题原型,且只有一个解决方案。这正是“针在干草堆中”这一概念的定义。如果没有指导(即使你每秒可以旋转面 100 次),你可能会在整个宇宙的时间里也无法成功。关于它的一切似乎都涉及到巨大的数字。
我们在这里计算的量是一个例外。通过它,你将获得对一个困难问题(以及任何类似的规划问题)的简单视角。我们需要两个要素,一个随机过程和一个最佳求解器。后者是一个设备(真实的或理想的),可以在任何初始状态下使用最少的移动次数来解决魔方(或类似问题)。我们将完全回答以下问题:
如果一个已解魔方经历了 N 次随机转动, p(d|N) 的概率是多少,即一个最佳求解器需要 d 次移动才能将其恢复到原始状态?
在正常情况下,如果有人要求你解魔方,你只会得到一个打乱的魔方,没有任何参考或标签。在这里,我们有关于打乱状态的一条信息:它是在从已解状态开始的N次随机移动后获得的。这条信息很有用!
我们为什么对**p(d|N)**感兴趣?
在计算上,你可以尝试以不同的方式解密魔方。一个魔方项目的目标可能在于以次优方式解决任何或某些状态,或者以最佳方式解决每个可能的状态(例如,这将需要著名的35 CPU 年)。一个魔方求解器通常涉及两个方面,一个搜索算法和一个启发式函数。通过选择这两个方面,我们参数化了我们的方法的难度、效率或计算要求。
在启发式函数领域,即搜索引导,总是存在创新的空间。历史上,魔方的启发式方法是将对打乱的魔方面片相对于其已解状态位置的曼哈顿距离估算相结合。直到最近,神经网络才被用作启发式方法。
神经网络 = 魔方的新启发式方法
神经网络的工作很简单(一个分类器):你输入一个魔方的状态x,然后预测该状态的深度d。状态d的深度定义为从该状态开始解决魔方所需的最少移动次数。请注意以下几点。如果我们有一个知道任何状态深度的设备,我们实际上就有了一个最佳求解器,因为每次我们可以选择一个使状态深度更低的移动,直到达到深度 = 0(已解状态)。
这里的问题是如何训练该网络。或者,具体来说,如何获得准确的训练数据。除非你已经拥有一个最优求解器,否则没有简单的方法知道一个打乱状态x的真实深度d。我们没有最优求解器,或者,我们不想使用计算代价高昂的求解器。我们想从头开始构建一个近似且高效的最优求解器,并尽量减少人工输入,同时也需要准确的训练数据:
training_data = (x , d).
正如我们所说,d的准确性很难获得,但将某个特定打乱状态与数字N关联却很容易:即通过对已解决状态进行N次随机移动生成的状态。然后
p(d|N) 估计 d, 给定 N.
***p(d|N)***将用于提高该训练数据的准确性。前述论文的作者建立了第一个魔方深度分类神经网络。他们的训练数据形式为:
training_data = (x , N).
他们将d视为N. 这个选择通过在训练过程中使用类似 Bellman 的循环动态提高标签的准确性来进行补偿。这里计算的概率p(d|N)为训练数据的准确性提供了一个更好的起点(仅通过随机旋转已解决状态N次即可获得大量数据)。
一个随机游走视角
计算p(d|N)相当于问一个随机游走者在N步之后会离d多远。不是在方格网格上行走,而是在一个拥有 10 的 19 次方节点(立方体状态)和相似数量连接(合法移动)的巨大魔方图上行走。如果我们选择一个布局,将节点按深度组织:将已解决状态置于中心,深度为d的状态位于距离中心d的半径上,则图将看起来非常对称。径向(深度)方向提供了一个非常简单的视角。
常规
在这里,我们采用所谓的 3x3x3 魔方的四分之一转度量,其中一次移动涉及 90 度的面旋转,无论是顺时针还是逆时针。在这种度量下,有十二种可能的移动。如果我们选择了不同的度量,例如半转度量(也将 180 度的面旋转作为一次移动),那么***p(d|N)***的表达式将会有所不同。
数据
要获得p(d|N),我们需要使用某种领域知识,但我们不想处理图、模式数据库或群体理论。我们将使用一些更“基础”的东西:
包含深度为d的魔方状态数量的列表
这个列表(由 2012 年“上帝的数字”论文的作者提供)没有指定哪些状态在某个特定深度,只提供了它们的总数,并且没有提及任何N.
# Depth population list
# number of cubes' states at a depth d in the quarter-turn metric
D_d={
# depth number of states
0: 1,
1: 12,
2: 114,
3: 1068,
4: 10011,
5: 93840,
6: 878880,
7: 8221632,
8: 76843595,
9: 717789576,
10: 6701836858,
11: 62549615248,
12: 583570100997,
13: 5442351625028,
14: 50729620202582,
15: 472495678811004,
16: 4393570406220123,
17: 40648181519827392,
18: 368071526203620348,
19: 3000000000000000000, # approximate
20: 14000000000000000000, # approximate
21: 19000000000000000000, # approximate
22: 7000000000000000000, # approximate
23: 24000000000000000, # approximate
24: 150000, # approximate
25: 36,
26: 3,
27: 0
}
深度对状态数量的对数刻度图
关于这个列表的一些观察:
首先,深度大于 26 时没有状态(在四分之一转动度量中,上帝的数字是 26)。其次,列表中报告了19到24之间d的状态的近似数量。我们稍后需要对此保持谨慎。第三,如果我们绘制对数尺度图,我们可以看到大多数深度(除了接近末端的那些)呈线性增长。这意味着状态数量D(d)以指数方式增长。将对数图的线性部分拟合成一条直线,我们发现d = 3和d = 18之间,状态数量增长为
在3 < d < 18的深度上,平均来说,9.34个12次移动会使你远离已解决状态,而2.66次会使你更接近已解决状态。
马尔可夫过程在深度类上的应用
要找出p(d|N),我们可以把深度类看作马尔可夫过程的站点。让我解释一下:
随机旋转立方体面被描述为深度类之间的马尔可夫过程(一维随机游走)。作者提供的图像。
一个深度类d是指所有在深度d下的立方体状态(到达已解决状态的最小步数)。如果我们在深度类d中随机选择一个状态,并用随机的动作旋转一个随机的面,这将以概率p_d给我们一个深度为d + 1的状态,或者以概率q_d给我们一个深度为d - 1的状态。在四分之一转动度量中,没有自类转换。
这定义了一个马尔可夫过程,其中特定的站点是一个完整的深度类。在我们的例子中,只有相邻的d类是一步跳转连接的。准确地说,这是一个离散时间出生-死亡马尔可夫链。由于站点数量是有限的,因此该链也是不可约且遍历的,并且存在唯一的平稳分布。
我们假设在每次选择随机动作时概率是均匀分布的。这会产生一些深度类之间的转移概率p_d, q_d(待计算)。随机动作的数量N是马尔可夫过程的离散时间。这也是一个一维随机游走:在每个站点(深度类编号d)中,前进的概率是p_d,后退的概率是q_d。这个一维链,粗略来说,是鲁比克图中的“径向”方向(按深度-径向布局组织)。
转移矩阵
任何马尔可夫过程都可以用转移矩阵M编码。M的**(i,j)项是从站点i跳到站点j**的概率。在我们的例子中,只有以下项不同于零:
这里 p_0 = 1: 从深度等级0**(仅包含已解决状态)我们只能跳到深度等级1(不存在等级***-1***)。同样,q_26 = 1: 从深度等级26我们只能跳到深度等级25**(不存在等级27)。出于同样的原因,**p_26 或 **q_0 不存在。
平稳分布
我们将立方体的随机移动作用映射为一个一维深度等级随机游走者,以概率 q_d 和 p_d 来回跳动。长时间的行走会发生什么?或者,游走者在长时间的行走后访问特定位置的次数是多少?在现实生活中:当立方体经历随机旋转时,深度等级的访问频率是多少?
从长远来看,无论起点是什么,游走者在深度等级 d 上花费的时间与该深度等级的人口 D(d) 成正比。这是这里的重点:
(归一化的)深度人口列表 D(d) 应被解释为表示我们深度等级马尔可夫过程的平稳分布的向量。
从数学上讲,D(d) 是 M 的左特征向量
这个矩阵方程将给出26个线性方程,我们将从中得到 p_i’ 和 q_i*’*。
考虑到 **p_0 = q_26 = 1, 我们可以将这些重新写作
详细平衡方程。图像由作者提供。
这些被称为 详细平衡方程:流量,定义为站态位置人口与跳跃概率的乘积,在两个方向上是相同的。解为:
并且 p_i 是通过 p_i + q_i = 1. 获得的。
对深度等级人口的一些条件
这些解有趣的地方在于,因为 q_i 是一个概率,我们应该有
这转化为分布 D_k 的以下条件:
这是深度人口 D_k 应该满足的一个不等式塔。明确地,它们可以组织为:
特别是,最后两个不等式是
因为 D_27 = 0, 我们得到下限和上限相等,所以
或者:
偶数位置的总人口应该等于奇数位置的总人口!
我们可以将其视为偶数和奇数站点之间的详细平衡:每一步总是到达不同且相邻的深度类。任何跳跃都会将你从奇数深度类(所有奇数深度类的类)带到偶数深度类(所有偶数深度类的类)。因此,奇数到偶数类的跳跃发生的概率为 1(反之亦然)。由于两个方向的概率都是 1,它们的数量应该通过详细平衡来相等。
出于同样的原因,马尔可夫过程将达到一个周期为二的“平稳分布”,在每次移动后在偶数和奇数站点之间切换(离散时间N)。
数据存在问题
我们计划使用的数据的深度人口D_d在source中报告的是大致的,对于d = 19,20,21,22,23,24\。因此,没有保证它会满足所有这些条件(不等式)。如果我们得到一些概率q_i*超出了[0,1]范围(如情况所示!)。特别是,如果我们尝试检查最后一个条件(偶数-奇数人口平衡),它差距很大!(更新:见末尾注释)
出路
奇数类似乎人口不足(这是作者选择报告数据的近似的结果)。为了使结果有效(使概率在[0,1]范围内),我们决定将之前的大数字添加到深度类别 21 的人口中(具有最大人口的奇数类,或者,最不容易注意到这个大增量的类)。通过这个修正,所有得到的概率似乎都是正确的(这意味着不等式也得到了满足)。
跳跃概率为:
p_i =
{1., 0.916667, 0.903509, 0.903558, 0.903606, 0.903602, 0.90352, 0.903415,
0.903342, 0.903292, 0.903254, 0.903221, 0.903189, 0.903153, 0.903108,
0.903038, 0.902885, 0.902409, 0.900342, 0.889537, 0.818371, 0.367158,
0.00342857, 6.24863*1e-12, 0.00022, 0.0833333}
# i from 0 to 25
q_i =
{0.0833333, 0.0964912, 0.0964419, 0.096394, 0.0963981, 0.0964796,
0.096585, 0.096658, 0.0967081, 0.0967456, 0.0967786, 0.0968113,
0.0968467, 0.0968917, 0.0969625, 0.0971149, 0.0975908, 0.0996581,
0.110463, 0.181629, 0.632842, 0.996571, 1., 0.99978, 0.916667, 1.}
# i from 1 to 26
注意几乎所有前p_i(直到i = 21)都接近1。这些是远离已解决状态的概率。接近已解决状态的概率(q_i)对于i大于21几乎为1。这使我们认识到为何解决魔方困难:随机行走者(或魔方的随机移动者)将“永远困在”深度类21的邻域中。
p(d|N)
将p_i, q_i数值代入转移矩阵M中,马尔可夫过程得到完整描述。特别是,如果我们以概率一从站点0开始,经过N步后,随机行走者将以概率到达站点d:
这是我们寻找的概率:
从数值上看,我们了解到p(d|N)只有在N和d具有相同奇偶性时才非零(这是某些魔方学者所熟知的)。下面我们为不同的N绘制了一些p(d|N):
一些概率 p(d|N)。作者图像。
例如:经过 N = 18 次随机移动(绿色曲线),结果立方体的状态在深度 d = 17 的可能性比在深度 d = 19 更高。我们还观察到,在 N = 31 或 32 时,p(d|N) 与平稳分布 D(d) 非常接近(除了它在偶数和奇数位置之间来回切换)。这是另一个回答多少步足以说明我们真的打乱了魔方的问题。
请注意,我们解决了一个逆问题。我们从平稳分布中得到了转移概率。这对于一般的马尔科夫过程是不可能的。特别是,对于半转度量,通过这里描述的方法不能找到 p(d|N)。半转度量是不同的,因为我们可以在移动后停留在同一深度类别(按他们的移动定义)。这些自深度类别跳跃在转移矩阵的对角线上引入了额外的概率 r_i,我们将有更多的变量而不是方程。
最后的评论
即使从计算角度来看,魔方是一个 35 CPU 年问题,它的许多方面仍然可以通过分析或适度的数值计算来描述。我们在这里计算的概率就是一个例子。我们所说的一切都可以很容易地推广到更复杂的魔方-兄弟。一个很酷的推广是进入更多维度:S = 4D, 5D, 6D,……维度的魔方。在这些情况下,状态空间随着 S 的增加而呈指数增长。因此,有些魔方的马尔科夫链可以长到我们想要的长度。换句话说,我们有类似的谜题,其中上帝的数字可以大到我们想要的程度(粗略地说,上帝的数字是状态数量的对数,而状态数量随着维度 S 的增加而增加)。在这些情况下,我们可以采取某些极限来解释我们3D情况的某些方面,就像下一个:
在大上帝数 G 的极限情况下, p(d|N) 的概率应该接近二项分布
很容易看出为什么会这样。如果 G 很大,D_d 的指数增长将在大多数 d 下非常稳定。这是一个大胆但并非过于疯狂的猜测:
对于远离 0 和 G 的 k。如我们所说,在 S = 3D 的情况下 b = 9.34。对于更高的 S,b 应该增加(拥有更多面会增加分支因子 b)。这转化为以下概率值:
当i远离原点(i >> 1)且上帝的数字(i << G)时,q_i会接近一个常数值1/(b+1)。在这个范围内,p_i也将是常数。你可以看到,这里为3D情况计算的p_i和q_i的值对于i = 3, …, 15几乎是常数,并且q_i大约等于1/(b+1),其中b = 9.34。对于0 << i << G,我们将得到一个具有常数返回概率(q)和前进概率(p)的一维随机行走者。在这种情况下,行走者的位置将由类似二项分布的分布描述。
随机行走者在经过N次试验后,向右走k步(成功率p)和向左走N-k步(成功率q)的概率为Binomial(k,N,p)。在经过N步后行走的距离将是
d = k - (N - k)
从中我们得到
从这里我们可以得到最可能的d的解析估计
最可能的d(在二项分布范围内)随N线性增长,斜率依赖于“有效”分支因子b。随着立方体维度S的增加,分支因子b也会增加,而最可能的深度d实际上接近于N。
更新说明。在这个故事发布后,我联系了 Tomas Rokicki 和 Morley Davidson(2012 年证明上帝的数字在半转度量中为 20的两位作者)关于他们报告的D(d)以及我使用这些数据得到的负概率。他们与我分享了更准确的数据,包括深度 d = 19, …, 24 的上下界。他们的数据与这里得到的不等式完全兼容,并且与偶数深度类别的数量应等于奇数深度类别的数量(在四分之一转度量中)的事实相一致。使用这些新数据计算的概率具有微不足道的修正。
一个学术研究(以及其他数据类型)的推荐系统!
实施自然语言处理和图论来比较和推荐不同类型的文档
·发布于 Towards Data Science ·阅读时间 15 分钟·2023 年 3 月 29 日
–
照片由 Shubham Dhage 在 Unsplash 提供
介绍
许多人现在开发的项目通常都从第一个关键步骤开始:积极研究。投资于别人所做的工作并在此基础上构建对你的项目增加价值至关重要。你不仅要从他人的结论中学习,还要找出在你的项目中不应该做的事情,以确保成功。
在我完成论文的过程中,我开始收集各种类型的研究文件。例如,我有不同的学术出版物的合集,以及包含不同实验结果的 Excel 表格。当我完成论文的研究时,我在想:是否有办法创建一个推荐系统,比较我档案中的所有研究,并帮助指导我下一个项目?
事实上,确实有!
注意:这不仅适用于你可能从各种搜索引擎收集的所有研究资料的存储库,也适用于你拥有的包含各种不同文档的目录。
设置
我和我的团队使用 Python 3 开发了这个推荐系统。也要向他们致敬!我们在这里取得了很棒的成就。
有很多 API 支持这个推荐系统,研究每个具体的 API 可以执行的操作可能对你的学习有益。
import string
import csv
from io import StringIO
from pptx import Presentation
import docx2txt
import PyPDF2
import spacy
import pandas as pd
import numpy as np
import nltk
import re
import openpyxl
from nltk.stem import WordNetLemmatizer
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
from gensim.parsing.preprocessing import STOPWORDS as SW
nltk.download('stopwords')
nltk.download('wordnet')
nltk.download('omw-1.4')
nltk.download('averaged_perceptron_tagger')
from nltk.corpus import wordnet
import networkx as nx
from networkx.algorithms.shortest_paths import weighted
import glob
障碍
我必须克服的一大难题是推荐机器比较不同类型文件的能力。例如,我想看看一个 Excel 电子表格中的信息是否与 PowerPoint 和学术 PDF 期刊中的信息相似或相关。做到这一点的诀窍是将每种文件类型读取到 Python 中,并将每个对象转换为一个单一的字符串。这规范化了所有数据,并允许计算相似性度量。
PDF 阅读类
我们将首先关注的课程是pdfReader类,它可以将 PDF 格式化为可在 Python 中读取的格式。在所有文件格式中,我认为 PDF 是最重要的之一,因为许多从研究库(如 Google Scholar)下载的期刊文章都是 PDF 格式的。
class pdfReader:
def __init__(self, file_path: str) -> str:
self.file_path = file_path
def PDF_one_pager(self) -> str:
"""A function which returns a one line string of the
pdf.
Returns:
one_page_pdf (str): A one line string of the pdf.
"""
content = ""
p = open(self.file_path, "rb")
pdf = PyPDF2.PdfReader(p)
num_pages = len(pdf.pages)
for i in range(0, num_pages):
content += pdf.pages[i].extract_text() + "\n"
content = " ".join(content.replace(u"\xa0", " ").strip().split())
page_number_removal = r"\d{1,3} of \d{1,3}"
page_number_removal_pattern = re.compile(page_number_removal, re.IGNORECASE)
content = re.sub(page_number_removal_pattern, '',content)
return content
def pdf_reader(self) -> str:
"""A function which can read .pdf formatted files
and returns a python readable pdf.
Returns:
read_pdf: A python readable .pdf file.
"""
opener = open(self.file_path,'rb')
read_pdf = PyPDF2.PdfFileReader(opener)
return read_pdf
def pdf_info(self) -> dict:
"""A function which returns an information dictionary of a
pdf.
Returns:
dict(pdf_info_dict): A dictionary containing the meta
data of the object.
"""
opener = open(self.file_path,'rb')
read_pdf = PyPDF2.PdfFileReader(opener)
pdf_info_dict = {}
for key,value in read_pdf.documentInfo.items():
pdf_info_dict[re.sub('/',"",key)] = value
return pdf_info_dict
def pdf_dictionary(self) -> dict:
"""A function which returns a dictionary of
the object where the keys are the pages
and the text within the pages are the
values.
Returns:
dict(pdf_dict): A dictionary pages and text.
"""
opener = open(self.file_path,'rb')
read_pdf = PyPDF2.PdfReader(opener)
length = read_pdf.pages
pdf_dict = {}
for i in range(length):
page = read_pdf.getPage(i)
text = page.extract_text()
pdf_dict[i] = text
return pdf_dict
Microsoft PowerPoint 阅读器
pptReader 类能够将 Microsoft PowerPoint 文件读取到 Python 中。
class pptReader:
def __init__(self, file_path: str) -> None:
self.file_path = file_path
def ppt_text(self) -> str:
"""A function that returns a string of text from all
of the slides in a pptReader object.
Returns:
text (str): A single string containing the text
within each slide of the pptReader object.
"""
prs = Presentation(self.file_path)
text = str()
for slide in prs.slides:
for shape in slide.shapes:
if not shape.has_text_frame:
continue
for paragraph in shape.text_frame.paragraphs:
for run in paragraph.runs:
text += ' ' + run.text
return text
Microsoft Word 文档阅读器
wordDocReader 类可以用于在 Python 中读取 Microsoft Word 文档。它利用了doc2txt API,并返回给定 Word 文档中位于的文本/信息的字符串。
class wordDocReader:
def __init__(self, file_path: str) -> str:
self.file_path = file_path
def word_reader(self):
"""A function that transforms a wordDocReader object into a Python readable
word document."""
text = docx2txt.process(self.file_path)
text = text.replace('\n', ' ')
text = text.replace('\xa0', ' ')
text = text.replace('\t', ' ')
return text
Microsoft Excel 阅读器
有时研究人员会将他们的结果以 Excel 表格的形式随出版物一起提供。能够读取列名,甚至是数值,可能有助于推荐与你搜索内容相似的结果。例如,如果你在研究某只股票的过去表现?也许你会在历史表现的 Excel 表格中搜索名称和符号。这种推荐系统会向你推荐这个 Excel 表格,以帮助你的研究。
class xlsxReader:
def __init__(self, file_path: str) -> str:
self.file_path = file_path
def xlsx_text(self):
"""A function which returns the string of an
excel document.
Returns:
text(str): String of text of a document.
"""
inputExcelFile = self.file_path
text = str()
wb = openpyxl.load_workbook(inputExcelFile)
#This will save the excel sheet as a CSV file
for sn in wb.sheetnames:
excelFile = pd.read_excel(inputExcelFile, engine = 'openpyxl', sheet_name = sn)
excelFile.to_csv("ResultCsvFile.csv", index = None, header=True)
with open("ResultCsvFile.csv", "r") as csvFile:
lines = csvFile.read().split(",") # "\r\n" if needed
for val in lines:
if val != '':
text += val + ' '
text = text.replace('\ufeff', '')
text = text.replace('\n', ' ')
return textCSV File Reader
csvReader 类将允许将 CSV 文件包含在你的数据库中,并在系统的推荐中使用。
class csvReader:
def __init__(self, file_path: str) -> str:
self.file_path = file_path
def csv_text(self):
"""A function which returns the string of a
csv document.
Returns:
text(str): String of text of a document.
"""
text = str()
with open(self.file_path, "r") as csvFile:
lines = csvFile.read().split(",") # "\r\n" if needed
for val in lines:
text += val + ' '
text = text.replace('\ufeff', '')
text = text.replace('\n', ' ')
return textMicrosoft PowerPoint Reader
这是一个有用的类。不是很多人会考虑到 PowerPoint 演示文稿中存储着有价值的信息。这些演示文稿主要是为了将关键观点和信息可视化展示给观众。以下课程将帮助你将数据库中的任何 PowerPoint 文件与其他信息体关联,希望能引导你找到相关的工作。
class pptReader:
def __init__(self, file_path: str) -> str:
self.file_path = file_path
def ppt_text(self):
"""A function which returns the string of a
Mirocsoft PowerPoint document.
Returns:
text(str): String of text of a document.
"""
prs = Presentation(self.file_path)
text = str()
for slide in prs.slides:
for shape in slide.shapes:
if not shape.has_text_frame:
continue
for paragraph in shape.text_frame.paragraphs:
for run in paragraph.runs:
text += ' ' + run.text
return textMicrosoft Word Document Reader
本系统的最终课程是一个 Microsoft Word 文档阅读器。Word 文档是另一个宝贵的信息来源。许多人会撰写报告,以 Word 文档格式表示他们的发现和想法。
class wordDocReader:
def __init__(self, file_path: str) -> str:
self.file_path = file_path
def word_reader(self):
"""A function which returns the string of a
Microsoft Word document.
Returns:
text(str): String of text of a document.
"""
text = docx2txt.process(self.file_path)
text = text.replace('\n', ' ')
text = text.replace('\xa0', ' ')
text = text.replace('\t', ' ')
return text
今天项目中使用的课程就到这里了。请注意: 还有许多其他文件类型可以用来增强你的推荐系统。当前版本的代码正在开发中,将接受图像并尝试将其与数据库中的其他文档关联!
数据处理
预处理
让我们看看如何预处理这些数据。这个推荐系统是为一个学术研究库构建的,因此使用自然语言处理(NLP)指导的预处理步骤来分解文本是非常重要的。
数据处理类被简单地称为datapreprocessor,类中的第一个函数是一个词性标记器。
class dataprocessor:
def __init__(self):
return
@staticmethod
def get_wordnet_pos(text: str) -> str:
"""Map POS tag to first character lemmatize() accepts
Inputs:
text(str): A string of text
Returns:
tag_dict(dict): A dictionary of tags
"""
tag = nltk.pos_tag([text])[0][1][0].upper()
tag_dict = {"J": wordnet.ADJ,
"N": wordnet.NOUN,
"V": wordnet.VERB,
"R": wordnet.ADV}
return tag_dict.get(tag, wordnet.NOUN)
这个函数为单词标记词性,这在项目后续阶段会非常有用。
第二步,有一个函数执行许多我们已经见过的标准 NLP 步骤。这些步骤包括:
-
将每个单词都转为小写
-
去掉标点符号
-
去掉数字(我只想查看非数字信息。如果需要,可以省略此步骤)
-
停用词移除。
-
词形还原。在这一过程中,get_wordnet_pos()函数对于包含词性非常有用!
@staticmethod
def preprocess(text: str):
"""A function that prepoccesses text through the
steps of Natural Language Processing (NLP).
Inputs:
text(str): A string of text
Returns:
text(str): A processed string of text
"""
#lowercase
text = text.lower()
#punctuation removal
text = "".join([i for i in text if i not in string.punctuation])
#Digit removal (Only for ALL numeric numbers)
text = [x for x in text.split(' ') if x.isnumeric() == False]
#Stop removal
stopwords = nltk.corpus.stopwords.words('english')
custom_stopwords = ['\n','\n\n', '&', ' ', '.', '-', '$', '@']
stopwords.extend(custom_stopwords)
text = [i for i in text if i not in stopwords]
text = ' '.join(word for word in text)
#lemmanization
lm = WordNetLemmatizer()
text = [lm.lemmatize(word, dataprocessor.get_wordnet_pos(word)) for word in text.split(' ')]
text = ' '.join(word for word in text)
text = re.sub(' +', ' ',text)
return text
接下来,有一个函数可以将所有文件读入系统中。
@staticmethod
def data_reader(list_file_names):
"""A function that reads in the data from a directory of files.
Inputs:
list_file_names(list): List of the filepaths in a directory.
Returns:
text_list (list): A list where each value is a string of text
for each file in the directory
file_dict(dict): Dictionary where the keys are the filename and the values
are the information found within each given file
"""
text_list = []
reader = dataprocessor()
for file in list_file_names:
temp = file.split('.')
filetype = temp[-1]
if filetype == "pdf":
file_pdf = pdfReader(file)
text = file_pdf.PDF_one_pager()
elif filetype == "docx":
word_doc_reader = wordDocReader(file)
text = word_doc_reader.word_reader()
elif filetype == "pptx" or filetype == 'ppt':
ppt_reader = pptReader(file)
text = ppt_reader.ppt_text()
elif filetype == "csv":
csv_reader = csvReader(file)
text = csv_reader.csv_text()
elif filetype == 'xlsx':
xl_reader = xlsxReader(file)
text = xl_reader.xlsx_text()
else:
print('File type {} not supported!'.format(filetype))
continue
text = reader.preprocess(text)
text_list.append(text)
file_dict = dict()
for i,file in enumerate(list_file_names):
file_dict[i] = (file, file.split('/')[-1])
return text_list, file_dict
由于这是该系统的第一个版本,我想强调一下代码可以调整以包含许多其他文件类型!
下一个函数被称为database_preprocess(),用于处理给定数据库中的所有文件。输入是一个文件列表,每个文件都有其关联的文本字符串(已处理)。这些文本字符串随后使用sklearn 的 tfidfVectorizer进行向量化。这到底是什么?基本上,它会根据每个给定单词的频率,将所有文本转换为不同的特征向量。我们这样做是为了通过与向量算术相关的相似度公式查看文档的相关性。
@staticmethod
@staticmethod
def database_processor(file_dict,text_list: list):
"""A function that transforms the text of each file within the
database into a vector.
Inputs:
file_dixt(dict): Dictionary where the keys are the filename and the values
are the information found within each given file
text_list (list): A list where each value is a string of the text
for each file in the directory
Returns:
list_dense(list): A list of the files' text turned into vectors.
vectorizer: The vectorizor used to transform the strings of text
file_vector_dict(dict): A dictionary where the file names are the keys
and the vectors of each files' text are the values.
"""
file_vector_dict = dict()
vectorizer = TfidfVectorizer()
vectors = vectorizer.fit_transform(text_list)
feature_names = vectorizer.get_feature_names_out()
matrix = vectors.todense()
list_dense = matrix.tolist()
for i in range(len(list_dense)):
file_vector_dict[file_dict[i][1]] = list_dense[i]
return list_dense, vectorizer, file_vector_dict
创建一个基于数据库的向量化器的原因是,当用户给出一个需要在数据库中搜索的术语列表时,这些单词将根据其在数据库中的频率被向量化。这是当前系统的最大弱点。随着数据库规模的增加,计算相似度所需的时间和计算资源将增加,从而减慢系统速度。在质量控制会议上提出的一个建议是使用强化学习来推荐不同的数据文章。
接下来,我们可以使用一个输入处理器,将任何提供的单词处理成向量。这类似于你在搜索引擎中输入请求的过程。
@staticmethod
def input_processor(text, TDIF_vectorizor):
"""A function which accepts a string of text and vectorizes the text using a
TDIF vectorizoer.
Inputs:
text(str): A string of text
TDIF_vectorizor: A pretrained vectorizor
Returns:
words(list): A list of the input text in vectored form.
"""
words = ''
total_words = len(text.split(' '))
for word in text.split(' '):
words += (word + ' ') * total_words
total_words -= 1
words = [words[:-1]]
words = TDIF_vectorizor.transform(words)
words = words.todense()
words = words.tolist()
return words
由于数据库中的所有信息及给定的信息都将是向量,我们可以使用余弦相似度来计算向量之间的角度。角度越接近 0,两个向量的相似度就越低。
@staticmethod
def similarity_checker(vector_1, vector_2):
"""A function which accepts two vectors and computes their cosine similarity.
Inputs:
vector_1(int): A numerical vector
vector_2(int): A numerical vector
Returns:
cosine_similarity([vector_1], vector_2) (int): Cosine similarity score
"""
vectors = [vector_1, vector_2]
for vec in vectors:
if np.ndim(vec) == 1:
vec = np.expand_dims(vec, axis=0)
return cosine_similarity([vector_1], vector_2)
一旦找到两个向量之间的相似度分数,便可以创建搜索词与数据库中文档之间的排名。
@staticmethod
def recommender(vector_file_list,query_vector, file_dict):
"""A function which accepts a list of vectors, query vectors, and a dictionary
pertaining to the list of vectors with their original values and file names.
Inputs:
vector_file_list(list): A list of vectors
query_vector(int): A numerical vector
file_dict(dict): A dictionary of filenames and text relating to the list
of vectors
Returns:
final_recommendation (list): A list of the final recommended files
similarity_list[:len(final_recommendation)] (list): A list of the similarity
scores of the final recommendations.
"""
similarity_list = []
score_dict = dict()
for i,file_vector in enumerate(vector_file_list):
x = dataprocessor.similarity_checker(file_vector, query_vector)
score_dict[file_dict[i][1]] = (x[0][0])
similarity_list.append(x)
similarity_list = sorted(similarity_list, reverse = True)
#Recommends the top 20%
recommended = sorted(score_dict.items(),
key=lambda x:-x[1])[:int(np.round(.5*len(similarity_list)))]
final_recommendation = []
for i in range(len(recommended)):
final_recommendation.append(recommended[i][0])
#add in graph for greater than 3 recommendationa
return final_recommendation, similarity_list[:len(final_recommendation)]
向量文件列表是我们之前从文件中创建的向量列表。查询向量是正在搜索的词的向量。之前创建了文件字典,它使用文件名作为键,文件文本作为值。计算相似度后,会创建一个排名,优先推荐与查询词最相似的信息。注意,如果推荐结果超过 3 个怎么办?结合网络与图论的元素将为系统增加额外的计算优势,并生成更有信心的推荐。
页面排名理论
让我们稍作绕道,回顾一下页面排名理论。别误会,余弦相似度是测量向量之间相似性的强大计算方法,但将页面排名融入你的推荐算法,可以进行多个向量(你数据库中的数据)之间的相似性比较。
页面排名最初由拉里·佩奇(Larry Page)设计,用于对网站进行排名并衡量其重要性[1]。基本思想是,如果更多的网站链接到一个网站,那么这个网站可以被认为是“更重要的”。借鉴这一思想,如果图中的一个节点到其他节点的边距离减少,该节点可以被认为更重要。节点相对于图中其他节点的整体距离越短,该节点就越重要。
今天我们将使用页面排名的一种变体,称为特征向量中心性。特征向量中心性类似于页面排名,它衡量图中节点之间的连接,为更强的连接分配更高的分数。最大不同点?特征向量中心性会考虑与给定节点连接的节点的重要性,以估计该节点的相对重要性。这就好比说,认识许多重要人物的人,可能自己也通过这些强大的关系变得非常重要。总体而言,这两个算法在实现方式上非常相似。
对于这个数据库,在计算出向量之后,可以将它们放入图中,其中它们的边距离由它们与其他向量的相似度决定。
@staticmethod
def ranker(recommendation_val, file_vec_dict):
"""A function which accepts a list of recommendaton values and a dictionary
files wihin the databse and their vectors.
Inputs:
reccomendation_val(list): A list of recommendations found through cosine
similarity
file_vec_dic(dict): A dictionary of the filenames as keys and their
text in vectors as the values.
Returns:
ec_recommended(list): A list of the top 20% recommendations found using the
eigenvector centrality algorithm.
"""
my_graph = nx.Graph()
for i in range(len(recommendation_val)):
file_1 = recommendation_val[i]
for j in range(len(recommendation_val)):
file_2 = recommendation_val[j]
if i != j:
#Calculate sim_score between two values (weight)
edge_dist = cosine_similarity([file_vec_dict[recommendation_val[i]]],[file_vec_dict[recommendation_val[j]]])
#add an edge from file 1 to file 2 with the weight
my_graph.add_edge(file_1, file_2, weight=edge_dist)
#Pagerank the graph ]
rec = nx.eigenvector_centrality(my_graph)
#Takes 20% of the values
ec_recommended = sorted(rec.items(), key=lambda x:-x[1])[:int(np.round(len(rec)))]
return ec_recommended
好了,接下来呢?我们有使用数据库中每个数据点之间的余弦相似度创建的推荐,以及通过特征向量中心性算法计算的推荐。我们应该输出哪些推荐?两者都输出!
@staticmethod
def weighted_final_rank(sim_list,ec_recommended,final_recommendation):
"""A function which accepts a list of similiarity values found through
cosine similairty, recommendations found through eigenvector centrality,
and the final recommendations produced by cosine similarity.
Inputs:
sim_list(list): A list of all of the similarity values for the files
within the database.
ec_recommended(list): A list of the top 20% recommendations found using the
eigenvector centrality algorithm.
final_recommendation (list): A list of the final recommendations found
by using cosine similarity.
Returns:
weighted_final_recommend(list): A list of the final recommendations for
the files in the database.
"""
final_dict = dict()
for i in range(len(sim_list)):
val = (.8*sim_list[final_recommendation.index(ec_recommendation[i][0])].squeeze()) + (.2 * ec_recommendation[i][1])
final_dict[ec_recommendation[i][0]] = val
weighted_final_recommend = sorted(final_dict.items(), key=lambda x:-x[1])[:int(np.round(len(final_dict)))]
return weighted_final_recommend
这个脚本的最终功能将根据余弦相似度和特征向量中心性加权不同的推荐。目前,80% 的权重将分配给余弦相似度生成的推荐,20% 的权重将分配给特征向量中心性生成的推荐。最终的推荐可以根据这些权重进行计算,并汇总生成代表系统中所有相似度计算的推荐。开发者可以轻松调整权重,以反映他们认为更重要的推荐批次。
示例
让我们用这段代码做一个快速示例。我的数据库中的文档都以之前讨论的格式存在,并涉及机器学习的不同领域。数据库中更多的文档与*生成对抗网络(GANs)*相关,因此我预计当查询词为“生成对抗网络”时,这些文档会被优先推荐。
path = '/content/drive/MyDrive/database/'
db = [f for f in glob.glob(path + '*')]
research_documents, file_dictionary = dataprocessor.data_reader(db)
list_files, vectorizer, file_vec_dict = dataprocessor.database_processor(file_dictionary,research_documents)
query = 'Generative Adversarial Networks'
query = dataprocessor.preprocess(query)
query = dataprocessor.input_processor(query, vectorizer)
recommendation, sim_list = dataprocessor.recommender(list_files,query, file_dictionary)
ec_recommendation = dataprocessor.ranker(recommendation, file_vec_dict)
final_weighted_recommended = dataprocessor.weighted_final_rank(sim_list,ec_recommendation, recommendation)
print(final_weighted_recommended)
运行这段代码会生成以下推荐,并附上每个推荐的权重值。
[(‘GAN_presentation.pptx’, 0.3411272882084124), (‘Using GANs to Augment UAV Data_V2.docx’, 0.16293615818015078), (‘GANS_DAY_1.docx’, 0.12546058188955278), (‘ml_pdf.pdf’, 0.10864164490536887)]
再试一次。如果我查询“机器学习”会怎么样?
[(‘ml_pdf.pdf’, 0.31244922151487337), (‘GAN_presentation.pptx’, 0.18170070184645432), (‘GANS_DAY_1.docx’, 0.14825501243059303), (‘Using GANs to Augment UAV Data_V2.docx’, 0.1309153863914564)]
啊哈!正如预期的那样,第一个推荐文档是机器学习的介绍性简报!我仅使用了 7 个文档作为示例,添加的文档越多,收到的推荐也会越多!
结论
今天我们探讨了如何为你收集的文件创建推荐系统(尤其是当你收集研究材料用于项目时)。该系统的主要特点是,通过采用特征向量中心性算法计算向量的余弦相似度,从而提供更简洁、更好的推荐。今天试试看,希望这能帮助你更好地理解你拥有的数据之间的相关性。
如果你喜欢今天的阅读内容,请关注我,并告诉我是否有其他你希望我探讨的主题!如果你没有 Medium 账号,可以通过我的链接 这里 注册(这样我会收到少量佣金)!此外,你还可以在 LinkedIn 上添加我,或随时联系我!感谢你的阅读!
来源
对变换器的悼歌?
原文:
towardsdatascience.com/a-requiem-for-the-transformer-297e6f14e189
|观点| AI| 大型语言模型|
变换器会成为引领我们迈向人工通用智能的模型吗?还是会被替代?
·发表于Towards Data Science ·阅读时间 18 分钟·2023 年 12 月 1 日
–
图片来源于Stefany Andrade 在Unsplash
变换器在人工智能领域主导了六年,成为所有人工智能子领域的最先进技术。从自然语言处理 (NLP) 到计算机视觉,再到声音和图表,各个领域都有表现优异的专用变换器。
-
这个领域还会持续多久?
-
变换器真的还是最好的架构吗?
-
它会在不久的将来被替代吗?
-
它的主导地位面临什么威胁?
本文尝试回答这些问题。从变换器为何如此成功以及哪些因素使其在众多领域中立足开始,我们将分析它是否仍然拥有无可争议的主导地位,哪些因素威胁到它的霸主地位,以及是否存在潜在的竞争者。
一个帝国的简要历史
图片来源于Markus Spiske 在Unsplash
“所有的帝国都会变得傲慢。这是它们的本性。” ― 爱德华·拉瑟福德
帝国不可避免地衰落,当它们衰落时,历史会根据它们留下的遗产来评判它们。—— 诺亚·费尔德曼
“Attention Is All You Need” 是我们今天所知的人工智能的基础。生成型 AI 及其成功的根源都在于一个种子:变换器。
transformer 最初是为了解决 RNNs 的平行化不足,并能够建模序列中单词之间的长距离关系。其理念是为模型提供一个系统,以区分序列中哪些部分最重要(即注意力的关注点,attention)。这一切都是为了改进机器翻译。
然而,这些因素使得 transformer 更好地理解文本。此外,平行化使得模型在规模和更大的数据集上都能扩展。 GPU 的兴起进一步展示了像 Transformer 这样的可平行化架构的好处。
因此,Transformer 崛起成为了 AI 的新王者。一个帝国在极短的时间内建立起来。事实上,如今所有流行的模型都是 Transformer:ChatGPT、Bard、GitHub Copilot、Mistral、LLaMA、Bing Chat、稳定扩散、DALL-E、Midjourney 等等。
包含“语言模型”和“大型语言模型”关键短语的 arXiv 论文的累积数量趋势。图像来源:这里
这是因为 Transformer 很快适应了许多超越语言的任务。
即使是最庞大的帝国也会在某个时刻衰落;Transformer 的统治正在发生什么?
“脚踏实地的巨人”
图像来源:这里
当 transformer 被引入时,它的性能震惊了世界,并引发了参数竞赛。曾经一度,我们看到模型的增长速度如此之快,以至于它被称为“AI 的新摩尔定律。”这种增长一直持续到 2022 年 Megatron(530 B)和 Google PaLM(540 B)发布。然而我们仍未见到万亿参数。
当深度卷积网络展示其高效性(VGG 模型)时,卷积神经网络在短时间内从 16 层的VGG16发展到 201 层的DenseNet201。除了结果和性能外,这也是社区兴趣的证明。这种水平和垂直增长(以及对基础模型的渐进性变化)的模式在 2021 年停止了,当时社区相信视觉变换器(ViTs)优于卷积神经网络。
视觉变换器。图片来源:这里
为什么变换器的增长停止了?它们也被替代了吗?
不,但导致变换器增长的一些前提已经消失。
这种增长受到了所谓的幂律的激励。根据 OpenAI的说法,通过增加参数数量,特性会突然显现。因此,扩大模型规模会使模型发展出在某一规模以下无法观察到的特性。遗憾的是,斯坦福研究人员认为这些特性是偏差导致的海市蜃楼。
关于大语言模型新兴特性的视角改变
[towardsdatascience.com
扩大模型意味着花费更多。更多参数、更多计算、更多基础设施、更高的电力消耗(以及更多的碳排放)。这值得吗?
实际上,DeepMind 与 Chinchilla表示,性能的提升不仅与参数数量有关,还与数据量有关。因此,如果你想要一个拥有数十亿参数的模型,你必须拥有足够的令牌来训练它。遗憾的是,我们人类无法产生足够的内容来训练一个万亿参数的模型。
人类数据是有限资源。图片来源:这里
此外,影响模型性能的不仅仅是文本的数量。而是文本的质量。 这也是一个痛点,因为收集大量未经筛选的文本并不是一个好主意(即从互联网上下载时不加选择)。
重复令牌如何以及为何对大语言模型造成伤害?为什么这是个问题?
[towardsdatascience.com
另外,使用人工智能生成文本并不是一个好主意。理论上,人们可以使用一个 LLM 并要求它无限期地生成文本。问题在于,使用这些文本训练的模型只能模仿另一个 LLM,肯定不能超越它。
总体而言,我们的关键结论是,模型模仿并不是免费的午餐:今天的开源语言模型与其闭源对应物之间存在一个能力差距,这个差距无法通过廉价的模仿数据微调来弥合。 (source)
模仿模型能否达到像 ChatGPT 这样的专有模型的性能?
另一个要点是,这些巨大的模型在部署上也存在问题。 较小的模型性能很好,尤其是在某些任务中。可以将其提炼得到更小的专用模型。
带回家的信息:巨大的变换器范式正面临危机。每年我们会看到更大模型的想法已经结束。
毕竟,问题在于实际性(和成本)。一旦进入生产阶段,AI 的成本可能非常高。例如,微软据说在 GitHub Copilot 上亏损巨额资金(每用户每月 20 美元)。据一份报告,ChatGPT 每天的成本为 70 万美元,如果 ChatGPT 不能盈利,投资者可能不会继续承担这些成本。
因此,我们可以期待公司更倾向于开发专注于特定任务和业务的较小模型。
好吧,变换器不再增长了,但它仍然是游戏中最好的架构吗?
那么,让我们在下一节中讨论这个话题…
卷积仍然备受关注
照片由 Ricardo Gomez Angel 提供,来源于 Unsplash
首先,为什么变换器在各个领域都成功?
在最初的描述中,变换器结合了三个基本概念:首先是序列的位置信息表示(嵌入 + 位置编码),然后是序列元素的关联(自注意力),最后是构建层级表示(层叠)。
当文章Attention is All You Need发布时,它基于十年的 NLP 研究,并整合了之前发布的最佳成果:
-
词嵌入在 2013 年具有革命性,因为它能将词语转化为向量表示。此外,对嵌入的操作具有逻辑和语法上的意义。
-
层级表示则来自二十年的卷积神经网络研究,我们意识到通过堆叠层,模型可以学习到数据的越来越复杂的表示。
其威严的骨架,变换器。图片来源:这里
这些元素使得他在 NLP 领域取得成功,但与此同时,它们也是在其他领域获胜的关键。首先,变换器具有非常弱的归纳偏差,使其能够适应几乎任何类型的数据。其次,层级表示和连接序列元素的能力在 NLP 之外也有广泛的应用。
成功的故事,除非变换器自 2017 年起未曾改变,开始逐渐老化。
变换器的核心最终是自注意力。但这颗心脏泵送的血液过多。实际上,它的计算成本是巨大的。
因此,几个团队尝试寻找对自注意力的线性替代方法。然而,所有这些变体都被证明表现不如自注意力。
而什么看起来是一个不错的替代品? 无非就是古老的卷积。正如他们在 Hyena 中所展示的,通过稍微调整卷积,你可以获得一个表现类似变换器的好模型。
Hyena 模型展示了卷积如何比自注意力更快。
这颇具讽刺意味,因为自 2021 年以来,视觉变换器(ViTs)被认为在计算机视觉中优于 ConvNets。这似乎标志着卷积网络(ConvNets)在其领域中未被规范的霸主地位的终结。但事实是?
似乎 ConvNets 已经实现了复仇。令人惊讶,就像认为恐龙会通过驱逐哺乳动物重新掌控大陆一样。实际上,DeepMind 发布的最新文章基本上指出 ViTs 与 ConvNets 的比较并不公平。通过给 ConvNets 提供相同的计算预算,它们在 ImageNet 上的表现与 ViTs 相似。
视觉变换器似乎取代了卷积网络,但它们真的更好吗?
levelup.gitconnected.com](https://levelup.gitconnected.com/have-convolutional-networks-become-obsolete-245969f6b9d9?source=post_page-----297e6f14e189--------------------------------)
另一篇文章似乎也朝着同样的方向发展,卷积网络似乎与变换器具有竞争力:
同样的获胜者在较小规模下也获胜。在较小的主干网络中,ConvNeXt-Tiny 和 SwinV2-Tiny 表现突出,其次是 DINO ViT-Small。(source)
图片来源:这里
影响这种模型性能的主要因素有三个:其架构、预训练算法和预训练数据集。(source)
如果预训练算法和预训练数据集相同,那么剩下的只有模型架构。然而,在所有条件相等的情况下,ViTs 的所谓优越性似乎并未显现。 以至于 DeepMind 的作者所说的内容似乎像是承认了失败:
尽管 ViTs 在计算机视觉领域的成功令人印象深刻,但在我们看来,尚无强有力的证据表明经过预训练的 ViTs 在公平评估时优于经过预训练的 ConvNets。(source)
哎呀。因此我们可以说,在计算机视觉领域,ViTs 至少并不优于卷积网络。是吗?
我们注意到,ViTs 在特定背景下可能具有实际优势,例如在多个模态中使用相似的模型组件的能力。(source)
作者指出,它们可能仍然更优,因为在我们对多模态模型感兴趣时是有用的。考虑到特征也可以从卷积网络中提取,使用相同的模型在多个模态中显然更方便。
然而,这是一个非常重要的点,实证数据表明,至少在计算机视觉中,transformer 并不优于其他架构。这让我们不禁思考它的主导地位是否会在其他人工智能领域受到挑战。例如,transformer 核心领域的情况如何?它仍然是自然语言处理中的最佳模型吗?
文本 Dominion 的基础很脆弱
简短回答:是的,但它的至高无上的地位可能会结束。 让我们从它为何在 NLP 中如此成功开始。
Transformer 相比 RNN 的初始优势在于容易并行化。这导致了最初的狂热和对参数的急切追求。在此过程中,我们意识到是什么使得 Transformer 在 NLP 中获胜:上下文学习。
上下文学习是一个非常强大的概念:只需几个示例,模型就能够映射输入和输出之间的关系。所有这一切无需更新任何参数。
什么是及其工作原理是什么,让大型语言模型如此强大
towardsdatascience.com
基本上,这是自注意力的一个意外效果(且尚未完全理解)。根据 Anthropic的说法,有一些引导头实际上连接了模型的不同部分,并允许这种映射。
这种奇迹是模型所谓推理能力的基础。此外,能够如此多地实验提示也带来了令人难以置信的结果。
在实践中,无需重新训练模型,提示技术可以被创建以提升模型在推理方面的能力。思维链就是这种方法的最佳示例。利用这种策略,LLM 能够解决需要推理的问题(数学问题、编程问题等)。
图片来源:here
然而,必须考虑到:
然而,这种多步骤生成过程并不意味着 LLM 具有强大的推理能力,因为它们可能仅仅模拟了人类推理的表面行为,而不是真正理解精确推理所需的基础逻辑和规则。来源
翻译过来,我们已经创造了一个见识过整个人类知识的鹦鹉,能够将提示中的问题与它在训练中看到的内容联系起来。
为什么这种优势极其脆弱?
因为鹦鹉不一定是变压器。 我们需要任何能够接受自然语言指令作为输入并进行上下文学习的模型,然后我们可以像使用变压器一样使用所有的提示工程技术。
好吧,如果我们不一定需要变压器,那我们的新“随机鹦鹉”在哪里?
官僚制度减缓了创新
图片由Nam Anh提供,来源于 Unsplash
主要原因是,目前工业界的研究集中在将变压器(尽管有其缺陷)投入生产。此外,将一个我们了解较少的更好架构投入生产也是有风险的。
让我们深入了解一下…
首先,谷歌、META、亚马逊和其他大型科技公司拥有大量资源。然而,这些大公司却受到庞大的内部官僚制度的困扰:
谷歌是一个“曾经伟大的公司”,由于其官僚化的“迷宫”,它“逐渐停止了运作”。来源
官僚制度的增加导致了生产力的下降和整体放缓。为了实施一个小变化,必须获得越来越长的指挥链的批准,并遵循日益复杂的协议。简而言之,大型科技公司似乎有着与帝国相同的问题。
这显然也影响了创新:
“如果要总结一下,我会说信噪比是让我疲惫的原因。创新挑战… 随着风险容忍度的降低,只会变得更糟。”前谷歌高管诺姆·巴丁。来源
当然,像谷歌或微软这样的公司在选择上更加谨慎也是有充分理由的。例如,谷歌在 Bard 错误回答有关詹姆斯·韦布太空望远镜的问题时损失了数十亿美元。
这些声誉风险已经成为创新的巨大阻碍。只有当技术成熟且风险较低时才会被采纳。
最好的例子是苹果公司。 该公司只有在技术成熟并且认为其有利可图时才会采用。一般来说,近年来它已停止创新(尽管仍保持创纪录的利润)。到目前为止,它一直没有参与生成性 AI 领域,因为它认为尚不成熟。
苹果被称为“快速跟随者”;它喜欢等到新技术成熟后,再推出自己的苹果版本。(来源)
那么,这种对创新的抵制难道不应该有利于变压器技术吗?
是的,但我们忘记了开源。不仅仅是大型科技公司在进行研究,还有许多研究小组在调查 AI。他们可能没有 FAANGs 的资源,但独立研究合在一起是一股强大的力量。
谷歌自己也承认这一点。 实际上,山景城对微软或 OpenAI 的恐惧较少:
“令人不安的真相是,我们并未处于赢得这场军备竞赛的位置,OpenAI 也一样。在我们争吵的时候,第三方已经悄悄地抢占了我们的市场,”谷歌泄露的文件,来源
第三方正是开源社区。 一旦LLaMA发布,它立即收到了带有指令调整、量化和人类反馈强化学习(RLHF)的改进版本。Mistral 7B 刚刚推出,两组团队扩展了上下文长度(首先到32K,然后到128K)。
开源模型迅速变得可定制且便宜,并获得了一个庞大且活跃的社区的支持。开源社区立即采用每一个突破,并迅速改进它。大型公司在内部官僚主义上浪费时间,并因声誉损害的风险而受到限制,导致可能落后。
这个杰出的社区是变压器继任者的沃土。如果一个模型展示了克服变压器局限性的能力,它可能会获得如海啸般的力量。
但让我们看看最后一点,为什么尽管如此,变压器技术还没有被替代
叹息号的船
图片由Katherine McCormack拍摄,来源于Unsplash
古代哲学家提出了一个问题:经过数个世纪的维护,如果这些修补的 Theseus 号船的每一个部分都被逐个替换,它是否仍然是同一艘船?— 来源
transformer 在保持不变的同时发生了变化吗? 文献的简要搜索清楚地表明,如今有数百种 transformer 变体(如果考虑到所有位置编码、注意力等的变化)。所以 LLMs 并不是我们迄今为止看到的完全相同的模型。
Transformer 变体的分类。图片来源:这里。知识共享,许可证:这里
现在我们处于研究的增量阶段,在这个阶段,继续提出对相同模型的修改,以尝试克服现有技术的局限性。
在某种意义上,我们已经达到了 transformer 的极限。 扩大模型没有意义,因为这不会带来好处,也没有足够的 tokens。其次,transformer 的计算成本高昂,如果说过去性能重要的话,如今应用才是关键。第三,COT 和其他技术只是对 transformer 真实极限的补丁:模型并不真正具备理解和概括的能力。自注意力允许模型利用在训练过程中学到的大量知识,但它仍然是一个随机的鹦鹉。
transformer 是一种快速捕捉任何输入不同部分之间交互的方式。它是一种通用方法,可以捕捉句子中片段之间的交互,或音乐中的音符,或图像中的像素,或蛋白质的部分。它可以用于任何任务。” — Ashish Vaswani,transformer 论文的作者(来源)
从成本的角度来看,我们将会看到越来越多的小型专用模型用于不同的应用。 此外,今天的研究大多在寻找一种比 transformer 更便宜的替代品(例如 Hyena,Monarch Mixer,BiGS 和 MEGA)。
此外,变换器模型缺乏持续学习能力(它们具有静态参数)且缺乏解释性。液体神经网络(一种受蠕虫大脑工作方式启发的模型)旨在特别解决这两个问题。
此外,单一的变换器理念已被放弃,人们更多地考虑将多个模型组合在一起工作(GPT-4 似乎是由 8 个模型组成的)。Sakana AI 也追求相同的概念,通过借鉴集体智能的理念。
但这些模型会取代变换器吗?
可能不会。 或者在某些情况下,它们会被采用以满足特定需求。现阶段,这些模型尚未解决变换器的所有问题,对于许多应用来说,老旧的变换器已经足够。
目前,变换器在许多领域几乎具有绝对的主导地位。此外,许多研究和工作都基于这一架构并促成了其优化。因此,替代它是具有挑战性的。
像液体网络或群体智能这样的理念表明,人们在寻找超越构建更高效、更便宜模型的替代方案。然而,今天的研究仍未能克服变换器的真正限制。因此,变换器将被替代,但我们尚不清楚由什么来取代。它将是一项基于新理论进展的新技术。
TL;DR
-
变换器并行化的优势导致了大规模语言模型的过度增长,这种情况已经结束。意识到需要大量高质量数据使得对创建更大模型的热情减退。此外,部署成本使得更大的模型难以实现。
-
变换器在人工智能所有领域中的绝对主导地位已经不再。最近的一些论文表明,当以相同方式训练时,卷积网络在计算机视觉领域对变换器具有竞争力。它们在自然语言处理中的主导地位仍然不可否认,但基于脆弱的前提。
-
变换器可能会被一种能够接受文本指令并在上下文中学习的模型取代。所有的提示工程技术可以保持不变。
-
大型公司因官僚作风而不愿创新,现在专注于应用研究。另一方面,开源社区非常活跃,潜在的创新会被迅速采纳和推动。
-
变压器的真正优势在于它多年拥有绝对主导地位。因此,它受到了大量关注、研究和优化。能够取代这样一个模型是非常困难但仍然必要的挑战。实际上,我们已经基本达到了这项技术的极限,需要一种能够超越它的新技术。
-
虽然目前我们没有替代方案,但研究正在寻找能够超越它的模型。
离别思考
图片来自 Saif71.com 在 Unsplash
目前,人工智能的研究主要是增量性的,特别是在模型架构方面。大型公司现在致力于最终将这些模型投入生产并用于商业目的。
确实,在经历了一年的重大公告后,相关机构也开始行动,新法律正在准备中,将对人工智能进行规范。这些法律也将在一定程度上定义新的研究方向。如果这些法律过于僵化,将会抑制创新。
“确实有一些大型科技公司宁愿不与开源竞争,所以他们制造了对人工智能导致人类灭绝的恐惧。这已成为游说者用来推动对开源社区非常有害的立法的武器。” — Andrew Ng (source)
Yann LeCun 也持相同看法。目前,大公司对开源感到恐惧:
“如果你的恐吓活动成功,它们将不可避免地导致你和我认为的灾难:少数公司将控制人工智能。” — Yann LeCun (source)
无论如何,正如我们所见,没有任何技术会永远主导,而变压器也开始显示出其时代的局限性。考虑到将来会取代它的技术、理论进展、优雅的解决方案以及它将拥有的惊人能力,令人兴奋。
你认为什么会取代变压器?你尝试过变压器的替代品吗?在评论中告诉我。
如果你觉得这些内容有趣:
你可以查看我的其他文章,也可以在LinkedIn上联系我。 查看 这个库 ,其中包含每周更新的机器学习和人工智能新闻。 我对合作和项目持开放态度 ,你可以在 LinkedIn 上联系我。
这里是我 GitHub 库的链接,我在这里收集了与机器学习、人工智能等相关的代码和许多资源。
[## GitHub - SalvatoreRa/tutorial:机器学习、人工智能、数据科学教程…
机器学习、人工智能、数据科学教程,包括数学解释和可重复使用的代码(用 Python 编写…
或者你可能对我的一篇近期文章感兴趣:
提取大型模型知识的过程复杂,但一种新方法展现了惊人的表现
[towardsdatascience.com [## 神经网络集成:什么比神经网络更好?一组神经网络
神经网络集成:如何将不同的神经网络结合成一个强大的模型
级别提升 [## 仅谈论你所读过的内容:LLMs 能否超越其预训练数据进行泛化?
揭示大型语言模型中上下文学习的局限性与奇迹
pub.towardsai.net [## 机器学习新闻:11 月 6 日至 12 日
OpenAI 开发,TopicGPT,新芯片等
salvatore-raieli.medium.com](https://salvatore-raieli.medium.com/ml-news-week-6-12-november-9878eb0a7005?source=post_page-----297e6f14e189--------------------------------)
参考文献
这是我撰写本文时参考的主要文献列表,仅引用了每篇文章的首名。
-
Vaswani, 2017, 《注意力即是你所需要的一切》,link
-
Huang, 2016, 《密集连接卷积网络》,link
-
Zhao, 2023, 《大型语言模型的综述》,link
-
Smith, 2023, 《ConvNets 在规模上匹配视觉变换器》,link
-
Goldblum, 2023, 《骨干的战斗:预训练模型在计算机视觉任务中的大规模比较》,link
-
Wang, 2023, 《无注意力的预训练》,link
-
Ma, 2023, 《Mega:配备移动平均的门控注意力》,link
-
Hasani, 2020, 《液态时间常数网络》,link
-
Yadlowsky, 2023, 《预训练数据混合使变换器模型具备狭窄的模型选择能力》,link
-
Kaplan, 2020, 《神经语言模型的扩展规律》,link
-
Hoffman, 2022, 《训练计算最优的大型语言模型》,link
-
Simonyan, 2014, 《用于大规模图像识别的非常深的卷积网络》,link
-
Khan, 2022, 《视觉中的变换器:综述》,link
-
Wei, 2022, 《链式思考提示在大型语言模型中引发推理》,link
-
Touvron, 2023, 《LLaMA:开放高效的基础语言模型》,link