Groq,以及 AI 的硬件——直观且全面地解释
原文:
towardsdatascience.com/groq-intuitively-and-exhaustively-explained-01e3fcd727ab
机器学习 | 加速计算 | 人工智能
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/58f2f12e365ea39f26d487c69e6477ef.png
“协调分解”由 Daniel Warfield 使用 MidJourney 创作。除非另有说明,所有图像均为作者所有。所有生成的图像均使用 MidJourney 制作。
本文讨论了 Groq,这是一种革命性的计算机硬件新方法,它正在改变 AI 应用于现实世界问题的方式。
在我们讨论 Groq 之前,我们将分解 AI 的基本概念,并探讨用于运行 AI 模型的一些关键计算机硬件组件。具体来说;CPU、GPU 和 TPU。我们将从 1975 年的 Z80 CPU 开始,然后通过探索计算机硬件的一些关键演变,逐步建立起我们对现代系统的理解。
带着对计算机硬件中一些基本概念和权衡的理解,我们将利用这些理解来探索 Groq 是什么,它是如何革命性地改变 AI 计算的方式的,以及这为什么重要。
自然地,从早期 CPU 到前沿的十亿美元 AI 初创公司之间有很多内容要涵盖。因此,这是一篇相当长的文章。系好安全带,这将值得。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/c2db871d49c3e5aa6c325720aebe0556.png
实时记录我与 Mixtral 8x7b 进行通信,Mixtral 是一个开源的大型语言模型,托管在 Groq 硬件上。正如你所见,Groq 能够以惊人的速度响应,即使是非常大的语言模型。你可以在这里与 Groq 聊天。
这对谁有用?对人工智能感兴趣,以及运行 AI 模型所需现实的人。
这篇文章有多先进?这篇文章包含了一个前沿 AI 初创公司的前沿想法,并假设没有先前的知识来解释它们。它对所有层次的读者都适用。
先决条件:无,但文章末尾有一份精选的资源列表,供相关阅读。
免责声明 1:这篇文章不是关于埃隆·马斯克的聊天模型“Grok”。Groq 和 Grok 除了它们的名称基于同一本书之外,没有任何关系。
免责声明 2:在撰写本文时,我以任何方式与 Groq 无关。所有观点都是我自己的,且未获赞助。还要感谢 Groq 团队澄清技术细节并指引我正确的方向。特别感谢 Groq 软件工程副总裁 Andrew Ling。我请求与 Andrew 进行几次会议,他非常慷慨地帮助我解开 Groq 硬件的一些微妙细节。没有这些对话,这篇文章就不可能完成。
定义 AI
许多人将 AI 视为一个黑盒。你往里放东西,AI 进行一些神秘的数学运算,然后你得到东西。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/b377987807565cf104876f99c42311d3.png
对 AI 的一种常见直觉;本质上是一个魔法盒子,接受东西并输出东西。
这种直觉很流行,因为有时候人类很难理解模型的思维过程。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/b9e2df5cd20f1bf96278d05fb46aed42.png
就算一个 AI 模型在某个任务上表现良好,并不意味着人类可以轻易理解该模型的决策。
尽管理解模型决策背后的理由可能很困难,但 AI 模型在底层使用非常简单的数学运算来得出结论。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/8f39577c6fb63ebdfde488fde0f81c79.png
AI 思维的概念图。模型通过观察大量数据学习参数(以蓝色和下划线突出显示),从而做出良好的决策。
换句话说,AI 模型之所以复杂,并不是因为它们做复杂的事情,而是因为它们同时做大量简单的事情。
有许多硬件选项可以用于运行 AI。让我们先描述最基本的一个。
CPU
大多数现代计算机的主要组件是 CPU,或称为“中央处理单元”。CPU 几乎是每台现代计算机的心脏。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/1a8abf7c513ab24848c2295f3f9ba688.png
一张英特尔 Xeon CPU 的图片。来源,由英特尔的使用条款授权。
在最基本的意义上,CPU 基于“冯·诺伊曼架构”。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/2f952f41b50334735a89add02ab2596a.png
从本质上讲,冯·诺依曼设备可以接受一些输入,并使用控制单元来控制如何在算术单元中完成计算。然后,这些计算会产生一些有意义的输出。来源。
冯·诺依曼架构相当抽象;在实施方面有很大的灵活性。本文中我们将讨论的所有硬件基本上都可以被视为冯·诺依曼设备的特定类型,包括 CPU。
一款流行的早期计算机,ZX Spectrum,使用 Z80 CPU 来完成工作。从概念上讲,现代 CPU 与 Z80 并没有太大区别,因此我们可以用 Z80 作为一个简化的例子来开始了解 CPU 是如何工作的。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/80d089d677002dc417927f3444ae809a.png
使用 Z80 CPU(右)的 ZX Spectrum 计算机(左)。来源。
即使是这种简单 CPU 的图也相当复杂,但我们可以将其拆解以了解一些核心组件,这些组件在很大程度上一直延续到现代 CPU 中。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/93c689815b3fc7d4cd6423be29e1379f.png
Z80 CPU 的近似框图。来源。
Z80 具有一个控制电路,它将低级指令转换为芯片内的实际操作,并跟踪账目事项,例如 CPU 应该执行哪些命令。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/9398127e80251dde2f31352f946287aa.png
Z80 CPU 内的控制电路。来源。
Z80 具有一个“算术逻辑单元”(简称 ALU),能够执行各种基本的算术运算。这是在 Z80 CPU 内部真正进行大量实际计算的东西。Z80 会将一些数据放入 ALU 的输入端,然后 ALU 会根据 CPU 正在运行的当前指令将它们相加、相乘、相除或执行其他操作。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/41b84c0a3c92b5059fcd8207b5ea9fff.png
Z80 内的算术逻辑单元(或 ALU)。来源。
几乎任何复杂的数学函数都可以分解成简单的步骤。ALU 被设计成能够执行最基本的基本数学运算,这意味着 CPU 可以通过 ALU 执行许多简单操作来执行非常复杂的数学。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/14b150eb590415e2e87896e47d2d1cb0.png
即使是最复杂的数学通常也可以分解成许多简单的计算。这个积分(来自微积分)只是乘法、除法和加法。
Z80 还包含了一堆寄存器。寄存器是 CPU 内部存在的微小、超快的内存片段,用于存储某些关键信息,如 CPU 当前正在运行的指令、数值数据、CPU 外部的数据地址等。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/d7b886626b7ac569fefaef15296836f2.png
Z80 内部的寄存器。来源。
当人们想到计算机时,很容易关注做数学运算的电路,但在现实中,很多设计工作需要考虑数据的存储位置。数据存储和移动的问题是这个文章的核心主题,也是为什么现代计算依赖于如此多的不同专用硬件组件的重要原因。
CPU 需要与其他计算机组件通信,这是总线的工作。Z80 CPU 有三个总线:
地址总线传递 Z80 感兴趣的数据位置
控制总线传达 CPU 想要做什么
数据总线传递 CPU 的输入和输出实际数据
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/2054e47f2617b8e6f3716befd8d064f9.png
Z80 的三个总线。来源。
例如,如果 Z80 想要从 RAM 中读取一些数据并将其信息放入本地寄存器以进行计算,它将使用地址总线来传达它感兴趣的数据,然后它将使用控制总线来传达它想要读取数据,然后它将通过数据总线接收这些数据。
整个这个过程的目的是允许 CPU 执行“获取、解码、执行”周期。CPU“获取”一些指令,然后将其“解码”成 CPU 特定组件执行的实际操作,然后 CPU“执行”这些操作。然后 CPU 获取新的指令,重新开始周期。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/348118681dbcf9bc82518e81d4894d90.png
获取、解码、执行周期,这是 CPU 本质上所做的一切。
这个循环与一个程序协同工作。人类通常认为程序是用像 Java 或 Python 这样的编程语言编写的,但当一个程序的文本被编译器解释成机器代码后,并且这些机器代码被传输到 CPU,程序最终看起来非常不同。本质上,编译器将人类编写的程序转换成 CPU 可以基于其预定义的控制逻辑执行的一系列指令。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/1106e721ee509747c3347f0b6e960969.png
一个概念图,展示了编译器将人类编写的程序转换成 CPU 可以理解的指令列表。这些指令执行简单的操作,如将两个数字相加,将数据从 RAM 加载到寄存器等。
一旦代码被编译,CPU 只需获取一条指令,将其解码为 CPU 内的操作,然后执行这些操作。CPU 通过程序计数器跟踪其位置,通常每次调用指令时都会增加,但它也可能根据某些逻辑(如 if 语句)在程序中跳跃。
就这样基本上就完成了。结果证明,即使是一个简单的 CPU,只要遵循一系列简单的指令,也能完成几乎任何可想象的计算。真正的问题在于如何让 CPU 快速执行这些指令。
CPU 的设计约束
Z80 是一种相当简单的 CPU。一方面,它是一个单一的“核心”。核心的实际细节可能有点复杂,但核心本质上是在 CPU 上执行工作的东西。想象一下,如果我们不是只有一个 Z80,而是在单个芯片上集中了几个 Z80,它们各自执行自己的任务。这就是现代多核 CPU 的本质。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/8c1134eeaf1bcf50c3104ca0e14859e7.png
现代 CPU 主要组件的框图。每个核心就像是我们之前讨论过的 Z80 CPU 的复杂版本。拥有多个核心使得现代计算机能够同时处理多个任务。
CPU 中的核心可以相互通信,但很大程度上它们通常负责不同的事情。这些“不同的事情”被称为“进程”。在正式的计算机术语中,进程是一个程序和内存的组合,它以原子方式存在。你可以在不同的核心上拥有多个进程,它们通常不会相互通信。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/d902cc80e265a7701c367ba3fad9ae05.png
一个概念图,展示了各自独立执行任务的不同进程,每个进程都有自己的数据,本质上彼此完全隔离。
Chrome 实际上为每个标签页使用一个单独的进程。这就是为什么当一个标签页崩溃时,其他标签页不会受到影响。每个标签页都是一个完全独立的进程。这也是 Chrome 在计算机上消耗如此多内存的部分原因;所有这些标签页都在几乎相互隔离的状态下运行,这意味着它们各自需要跟踪大量信息。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/30c46934f0948b61c8af5aa4707b5887.png
如果你曾在 Windows 的任务管理器中查看过 Chrome,你可能已经注意到有许多单独的子任务。这是因为 Chrome 为每个标签页运行一个单独的进程。
有时,对于计算机来说,能够将单个程序中的多个计算拆分并并行运行是有用的。这就是为什么 CPU 的每个核心通常都有多个“线程”。线程可以在内存中的相同地址空间上共享(并协作工作)。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/9218b5dd214bc8c6283c6ae1fe5126b6.png
CPU 的每个核心由多个线程组成。由于现代 CPU 的复杂性,细节会变得有些复杂。线程通常在 CPU 内部共享一些资源(如 ALU),但同时也拥有自己的资源(如寄存器),这使得当某些任务可以并行执行时,计算速度更快。对于我们的目的来说,此点之后的细节并不重要。
如果程序中有许多相互独立的计算,线程就很有用。你不必按顺序执行任务,而可以在多个线程上并行执行计算。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/d464fdf745c6bc156c6fd3d43822a025.png
单个进程可以在核心内使用多个线程,允许单个进程执行一些并行操作。
因此,CPU 可以拥有多个核心来运行不同的进程,并且每个核心都有线程以允许一定程度的并行执行。此外,CPU 包含计算单元(ALU),可以完成几乎所有可想象的计算。所以……我们完成了?我们只需要制造更大、更强大的 CPU,我们就能做任何事情。
但并非如此。
正如我之前提到的,CPU 是计算机的跳动心脏。CPU 必须能够执行运行任何程序所需的任意计算,并且它必须能够快速执行这些计算,以保持计算机的响应时间接近瞬时。
为了同步 CPU 中的快速执行,计算机有一个石英钟。石英钟以稳定的间隔滴答作响,使计算机能够保持有序的同步操作。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/cf5e05bd958bf79ca4e4215d8bd291d5.png
树莓派底部的石英钟,这是一种流行的单板计算机。石英钟的作用是提供稳定的振荡,用于同步计算机中的执行。
这些时钟非常快。在上面的树莓派图片中,时钟振荡频率为 19.2MHz,但现代 CPU 可以达到吉赫兹级别。对于那些不熟悉这些单位的人来说,1 吉赫兹等于每秒十亿次振荡,并且随着每一次振荡,CPU 预计将为每个核心获取并执行一条指令。这里有一张关于十亿件事物的图片,仅供参考:
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/b393d3de1cd14e3da85d898278fa2812.png
地球上有 78 亿人口。现代 CPU 每秒为每个核心执行大约那么多的指令。现代 CPU 通常具有多个核心。来源。
因此,CPU 运行得很快。它们基于每秒振荡数十亿的时钟运行。实际上,速度如此之快,以至于光速(宇宙的速度极限)开始发挥作用。
电流通过硅的速度大约是每秒 6000 万米。典型的 CPU 时钟可能每秒振荡 30 亿次。这意味着在每次时钟周期内,电流只能在一个 CPU 中传播 20 毫米(不到一英寸)。
如果 CPU 的尺寸比现在大得多,那么设计者将面临在芯片上保持操作同步的严重挑战。想象一下 CPU 的一部分正在尝试进行加法运算,但其中一个值还没有完全到达,因为信息来源在一英寸之外。这个问题当然是可以解决的……随着更多组件占据 CPU 内部空间,进一步加剧了这个问题。
还有其他一些问题我不会深入探讨;在圆形硅晶圆上制造方形芯片的成本、冷却方面的复杂性等。基本上,“仅仅使 CPU 更大”有很多严重问题。
另一个重要的设计考虑因素出现在我们思考 CPU 主要职责的时候。
我提到 CPU 必须要快。更具体地说,它们需要具有极低的延迟。通常,延迟是指从开始到结束所需的时间。当你按顺序运行程序时,每次执行中的延迟量对性能有重大影响。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/97adf97c4f227ac3bbb9c5d8c7fbd252.png
如果一个程序有一些需要执行的任务,每个任务可能都需要一些设置或拆除时间(蓝色),以及实际进行计算所需的时间(红色)。
因此,CPU 尽可能地最小化延迟。CPU 中的核心需要非常快,数据需要就在那里,随时可用。没有太多的回旋余地。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/5a361ef5718a3a63f778c835a2db1333.png
CPU 设计师的主要工作是让任务完成得更快,并且开始和完成它们所需的额外成本更低。
CPU 通过多种方式优化延迟。它们有一种特殊的内存类型称为缓存,其设计目的是将重要数据存储在 CPU 附近,以便可以快速检索。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/8c1134eeaf1bcf50c3104ca0e14859e7.png
CPU 包含不同级别的缓存,每个缓存有不同的尺寸和吞吐量速度。通常,靠近核心的缓存较小且速度较快,而远离核心的缓存较大且速度较慢。CPU 设计师做了大量工作,试图尽可能让数据对核心更易于访问。
CPU 采用了许多其他花哨的技术,坦白说,我并不完全理解。英特尔每年在研发上投入大约 160 亿美元。其中相当一部分用于尽可能从这块石头中榨取尽可能多的性能。对于 CPU 来说,这意味着更多的核心、更多的线程和更低的延迟。
关注更快和更快的 CPU 是计算直到 90 年代的主要焦点。然后,突然,一种新的消费者类型出现了,他们有新的性能需求。
游戏玩家的出现
在视频游戏中,CPU 毫无机会。
CPU 非常适合运行顺序程序,甚至具有一定的并行计算能力,但要在一个屏幕上渲染视频,则需要每秒渲染数百万个像素多次。
此外,像素的值基于 3D 模型,每个模型可能由数千个多边形组成。需要执行大量的独立计算,才能将视频游戏转换成实际的视频,这与 CPU 被设计用来处理的快速和顺序任务非常不同。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/7f25f9cf442b188e0ae031f02419aec4.png
由(从左到右)相机、光源、球体、猴子和一个立方体组成的 3D 场景。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/1145fd8141245d95fbbe0d4322a467fd.png
从相机的视角渲染的简单场景。你可能能够想象出生成这种图像所需的计算。计算机需要计算每个模型哪些部分对相机是可见的,以及根据光源它们应该是什么颜色。对于包含众多模型、光源和效果的复杂场景,这可能会迅速变得计算量很大。
有多种芯片被设计出来帮助 CPU 处理这种新的负载。其中最著名的是 GPU。
GPU 的起源
第一款主流的 GPU 是由 Nvidia 创造的——GeForce 256。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/13782f0daaef2815db7bdc895fcc26e7.png
Nvidia 的 GeForce 256,被市场宣传为“世界上第一款 GPU”。来源。
这个特定设备背后的想法是将昂贵的图形处理任务卸载到专门设计的硬件上。GeForce 256 是一款非常严格和具体的机器,设计用来处理“图形管线”。CPU 会给 256 提供关于 3D 模型、材质等信息,GPU 则会完成所有必要的处理,以在屏幕上生成图像。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/b324f6f3b236557dc0d38dc5e6dff381.png
图形管线,本质上是一系列操作,它接收有关某些 3D 场景的信息,并将它们转换为可以在屏幕上渲染的图像。
256 通过设计用于执行非常特定操作的专用芯片来实现这一点;用于在 3D 空间中移动模型、计算有关光照的信息、计算这是否在另一物体之上等。我们不需要深入了解计算机图形学,可以直接说:这种专用硬件将某些游戏的帧率提高了高达 50%,这是一个相当巨大的性能提升。
自然地,第一个 GPU 并不完美。由于其设计过于严格,它没有太多灵活性来满足不同应用的不同需求。在 GeForce 256 发布九年之后,Nvidia 发布了第一个现代 GPU,它在许多方面都改进了原始 GPU。
现代 GPU
Nvidia GeForce 8 是第一个现代 GPU,真正地为今天的 GPU 奠定了基础。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/42e547cc13f1ba6f16d3f1e54002d422.png
GeForce 8800 Ultra GTX。来源。
与使用专门设计用于执行特定图形操作的组件不同,GeForce 8 系列更像是一个 CPU。它拥有通用核心,可以进行任意计算。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/7c5a82761c3a353378a726275738a642.png
CPU 与现代 GPU 的概念图。GPU 与 CPU 有很多相似之处,但设计上存在一些关键差异。
然而,GeForce 8 并没有专注于顺序程序的低延迟计算,而是专注于并行计算的高吞吐量。**换句话说,CPU 确实非常快速地连续处理事情。GPU 设计得稍微慢一些,但可以并行处理。**这是 CPU 和 GPU 之间一直持续到现在的区别。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/aae266ef626edcbc474224332d4f0c2c.png
CPU 专注于需要顺序执行的问题。在运行下一个计算之前,你需要知道前一个计算的结果。因此,CPU 专注于尽可能快地完成每个指令。GPU 专注于可以并行化的问题。GPU 在执行特定操作时可能稍微慢一些,但经过优化,可以高效地执行大量并行计算。
GPU 通过采用“单指令,多数据”(SIMD)计算方法来实现并行计算,允许同时控制多个核心。此外,由于不太关心特定计算的延迟,GPU 可以接受更多的设置时间,从而允许设置多个计算的开销。这使得 GPU 在运行顺序程序时非常糟糕,但在进行大量并行计算(如渲染图形所需的计算)时非常好。此外,由于 GPU 是为了执行特定的图形计算(而不是像 CPU 那样的任何计算)而设计的,因此 GPU 可以接受更小的核心和更简单的控制逻辑。最终结果是拥有大量核心,旨在尽可能多地执行并行计算。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/7c5a82761c3a353378a726275738a642.png
CPU(左)与 GPU(右)。它们采用类似的核心组件,但它们的设计优先级允许有截然不同的使用案例和性能特征。
为了让您了解能力的差异,英特尔 Xeon 8280 CPU 在其所有核心上共有 896 个可用的线程。Nvidia A100 GPU 在其所有核心上共有 221,184 个可用的线程。这是线程数量的 245 倍,用于并行计算,所有这些都得益于 GPU(与 CPU 相比)对延迟不太关心。
GPU 和 AI
如您所想象的那样,图形并不是唯一可以从并行计算中受益的东西。随着 GPU 的兴起,其应用案例也迅速增加。很快,GPU 成为各种学科(包括 AI)的基本构建块。
在文章的开头,我提供了一个简化的 AI 演示。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/8f39577c6fb63ebdfde488fde0f81c79.png
回顾人工智能背后的数学简化演示。
使用 CPU 运行这个简单的 AI 模型可能看起来像这样:
将第一个向量中的所有值相加。这将涉及 24 个计算。
将结果乘以 3、2 和-0.1。这将增加三个计算。
将这些结果相加,增加两个计算。
将该结果乘以 0.03 和 0.003,增加两个计算。
那是 31 个顺序计算。相反,你可以将其并行化。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/c3700659aa68df4ece59d9aaeede7bd4.png
并行加法的一个例子。将 24 个顺序步骤转换为 5 个并行步骤。
如果你在这个特定例子中将加法并行化,并将乘法并行化,你最终会将 31 个顺序操作缩减为 9 个并行步骤。假设其他条件相同,以并行方式运行此模型将快 2.4 倍。
这个例子清楚地说明了问题,但实际上它比现实世界的例子要少一些戏剧性。实际的现代 AI 模型通常在底层使用矩阵乘法。在矩阵乘法中,每一行都会与每一列相乘,然后将结果相加以构建结果矩阵。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/b5fd12d00569a24b86662a37de57dc45.png
许多 AI 模型,如密集网络,实际上在底层是矩阵乘法。来自我的 LoRA 文章。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/cd165b66f9e6fd284e16f846e0904690.png
矩阵乘法。一个矩阵的每一行都会与另一个矩阵的每一列相乘,然后将结果相加以定义结果矩阵中的一个元素。现代机器学习模型使用矩阵乘法将模型参数乘以输入数据以生成推理。来源
现代机器学习模型很大,这意味着它们内部的矩阵也很大。对一个M x N和一个N x P矩阵进行矩阵乘法所需的计算次数为M * N * P。因此,如果你有两个形状为256 x 256的平方矩阵,你将不得不执行超过 160 亿次操作来计算它们之间的矩阵乘法。想象一下,在这样一个包含数十亿参数的巨大模型中,这样的操作会反复进行。
由于机器学习中存在许多并行操作,因此快速使用 GPU 而不是 CPU 进行机器学习任务变得至关重要。为了并行化矩阵乘法,GPU 使用一种称为“融合乘加”(FMA)的技术来快速将行乘以列,然后它们多次执行此操作以快速计算结果矩阵中的所有单个元素。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/c45b6a783daa2033d3330df6137a2239.png
回想一下,矩阵乘法是行乘以列的和。在底层,GPU 尽可能地快速和并行地进行大量的乘法和加法操作,以执行矩阵乘法。
GPU 可以比 CPU 更快地进行矩阵乘法,但它们可以更快。为了更快地进行矩阵乘法,我们需要引入新的硬件。
摆钟摆动
如前所述,GPU 的一般感觉在几乎十年里一直占主导地位。任何改进主要都是通过扩大架构来实现的。使用更小的晶体管将更多的计算打包到单个芯片中,增加计算能力,并提高性能。
2015 年,人工智能开始成为一门大生意。因此,GPU 被用于执行大量的“张量”操作。张量听起来像是一个复杂的概念,但实际上你已经对它们很熟悉了。向量是一维张量,矩阵是二维张量,等等。张量只是某些维度上的数字块。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/9ffab1a9d8a2be38ede3c650b7d524f9.png
不同维度的张量。实际上,张量可以存在于无限多个维度中。在 AI 实践中,它们通常只达到三个维度,有时是四个维度。
人工智能可以被看作是一系列的张量操作。矩阵乘以矩阵,向量加到向量上等等。虽然 GPU 在执行张量操作方面比 CPU 强得多(得益于它们的并行化能力),但它们并不是专门为张量计算而设计的。GPU 当然可以执行张量操作,但执行这些操作需要 GPU 的开销,这会降低性能。
在他们的典型风格中,谷歌在幕后悄然创新。他们开发了一个名为 TensorFlow 的机器学习框架,并尝试改进他们自己的 AI 流程。在众多事情中,两个问题开始突出:
如果我们降低 GPU 的精度会怎样?
如果我们制造一个专门用于张量操作的 GPU 会怎样?
因此,TPU 应运而生。
TPU
TPU 代表“张量处理单元”,在很多方面类似于 GPU,但与专注于图形(主要由向量和广泛的计算控制)不同,TPU 专注于使用张量进行计算,并且设计用于适应相对较小的计算选择。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/62d2aaff3c6e75c0e8e6401d5ad29d81.png
关于 TPU。来源。
TPU 的主要任务是执行矩阵乘法。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/135e8923d9a3daf1d85be53362be24c2.png
TPU 的主要组件。有很多小零件,但你可能会注意到,仅用于矩阵乘法的单元占据了芯片的 24%。来源。
TPU 使用的是不太精确的数字;对于 AI 来说仍然足够精确,但不如物理模拟和图形处理所需的精确。这意味着 TPU 可以在相同的外形因素中容纳更多的操作。此外,TPU 通过使用专门的矩阵乘法模块可以更快地进行矩阵乘法。它是通过在整个向量上执行操作来实现的;这比仅仅并行化单个数值计算更进一层。本质上,GPU 处理的是数字向量,而 TPU 处理的是向量向量。这使得 TPU 不如 GPU 通用,但更窄的范围允许更高的计算效率。
你可以将 TPU 看作在某些方面是一种倒退。回想一下,最初的 GPU 拥有专门为图形管道设计的硬件,而后继的 GPU 采用了通用计算方法。现在,TPU 正在回归到专门设计的途径,但这是为了 AI 应用。
随着制造技术的日益复杂,所有类型的处理器都将变得更加强大。然而,随着在硅片上挤入更多晶体管变得越来越困难,硬件设计师一直在尝试设计出最适合特定用例的设计。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/a884d3c833232adbfe31c8a8e44c8886.png
设计新芯片时需要考虑的一些关键性能权衡的概念图。
英伟达意识到了这个想法的力量。自从 2017 年发布的 Volta 微架构以来,英伟达在其 GPU 中包含了“张量核心”,这就像在其 GPU 中放入了微型的 TPU。
这是由 Nvidia 制作的一段非常好的视频,它从高层次突出了张量核心的性能提升,并有一个特别有用的视频演示了不同类型的并行性如何导致更快的计算。
cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FyyR0ZoCeBO8%3Ffeature%3Doembed&display_name=YouTube&url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DyyR0ZoCeBO8&image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FyyR0ZoCeBO8%2Fhqdefault.jpg&key=a19fcc184b9711e1b4764040d3dc5c07&type=text%2Fhtml&schema=youtube
在这篇文章中,我不会过多地讨论 TPUs,因为从很大程度上说,它们与 GPU 有许多相同的通用属性和用例,只是对于某些应用来说性能略高。此外,由于许多现代 GPU 中都有张量核心,两者之间的区别通常也有些模糊。
以两种方式处理延迟
我之前提到,CPU 使用缓存来保持数据靠近核心,以便尽可能快地完成计算。GPU 也使用缓存,但不是为了减少往返延迟。相反,GPU 使用缓存来维持吞吐量。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/7c5a82761c3a353378a726275738a642.png
回想一下,CPU 使用缓存,这是一种内存类型,将宝贵的数据尽可能靠近核心。其目的是使 CPU 的延迟尽可能低。GPU 也包含缓存,以及许多其他类似组件,但目的是为了促进高效的并行计算。
而不是试图用超额订阅、计算强度和内存效率等术语来描述这个想法(如果你真的想深入了解,我推荐观看这个视频),我认为核心思想可以通过以下图片来解释:
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/20a954055029d87d9ae24fcd06de2bb3.png
CPU 可以非常快速地完成单个计算,而 GPU 可以并行完成更多的计算,但速度较慢。最终,GPU 可以完成更多的计算,但你必须等待它们完成。
尽管某个特定的计算可能通过 GPU 完成得相当慢,但它使用缓存来保持所有工作者的忙碌,通过准备大量待处理的后台数据。另一方面,CPU 通过优化缓存以尽可能快地将数据喂给正确的核心来快速完成计算,但一次只能处理少量计算。这种细微的区别在很大程度上是 Groq 存在的原因。
延迟如何影响训练与推理
训练 AI 模型的过程基本上包括向模型投入大量数据,并要求它更新其内部参数以产生更好的输出。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/ba4b115d15f7f9ee9d7c4fad1465524f.png
训练过程概述
在训练过程中,我们并不太关心延迟。如果一个模型需要 3 天来训练,没有人会在意模型是早几分钟还是晚几分钟完成。训练 AI 模型是一个典型的吞吐量问题,它是 GPU 或 TPU 的完美用例。
另一方面,推理是实际使用模型的过程。你给一个训练好的模型提供数据,并期望得到一些合理的响应。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/83cc12a0a999335029ffba2ebf777fa8.png
推理,简而言之
在某些推理用例中,延迟确实成为一个问题。例如,我在关于 GPT 的文章中介绍了自回归生成。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/f4837eb869b9a46f240c97ade9f158f0.png
关于 GPT 的文章。基本上,一个语言模型(这里称为解码器)接收一个输入序列并预测下一个单词。然后它反复这样做,直到构建出一个输出。
像 ChatGPT 中使用的大型语言模型只是大的下一个单词预测器。说我们不在乎给模型输出增加几毫秒的延迟,这听起来很好,但给输出序列中的每个预测单词增加几毫秒的延迟则是另一回事。
例如,在我的测试中,Groq 使用 Mixtral 8x7b 能够每秒生成 572.60 个预测。这意味着每个预测需要 1.7 毫秒。不高效的硬件每预测一次就会增加毫秒级的延迟,这可能会使输出时间加倍,甚至更长。
同样,如果你的预测是在某些操作序列中呢?你需要等待特定的预测完成才能继续你的数据处理流程,这可能会对互联网规模应用程序的性能和成本产生实际影响。
随着像思维链和需要 LLMs 思考问题的代理系统等高级提示技术的普及,这些语言模型能够更快地生成结果变得越来越重要,否则模型输出的延迟可能会导致最终产品和服务的不可接受的退化。
我们有一个问题。当我们训练模型时,GPU 是完全可以接受的。然而,当我们进行预测时,我们需要等待 GPU 完成所有缓慢的并行化操作。我们仍然不能使用 CPU,因为虽然它们具有低延迟,但它们无法进行运行大型 AI 模型所需的大量计算。TPU 可能比 GPU 快一点,但它们实际上并没有好多少。
进入 Groq。
Groq:抛弃一切
现在我们已经了解了计算硬件的历史,以及围绕各种硬件方法的微妙设计限制,我们有了理解 Groq 所必需的知识。
Groq 是一款执行张量运算的芯片。它由硅制成。它有晶体管和寄存器……这就是 Groq 与传统计算机相似之处的大致全部。Groq 不仅仅是一块芯片,它是一张卡,一个节点,一个服务器,云端上的。Groq 是一个完整的统一计算机架构,专门设计用于在低延迟下实现高吞吐量,适用于互联网规模的人工智能推理。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/5296e75716d410983c9d16a782cf20c3.png
Groq 是一款特殊的芯片,安装在卡上,节点上,机架上。所有这些都是为了运行人工智能模型而专门设计的。来源。
在准备这篇文章的过程中,我与 Groq 软件工程副总裁 Andrew Ling 进行了一次对话。他描述 Groq 是一个基于第一原理的项目。他们研究了人工智能、运行人工智能所需的计算类型、制作人工智能所用的软件等,并围绕这些设计了一个完整的计算机系统。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/57fdd83ef82efc9c06baf29d329188ff.png
Groq 打破了规模。通过仅专注于人工智能应用,Groq 在吞吐量和延迟方面优于 GPU 和 TPU,在 CPU 甚至无法处理的应用中与 CPU 竞争。这一切都得益于 Groq 对运行人工智能而非通用计算的极度专注。
与设计用于执行与人工智能完全不同类型任务的 CPU 不同,或者与基于 CPU 设计、意外地适合人工智能的 GPU 不同,或者与修改 GPU 以使其更适合人工智能的 TPU 不同,Groq 从头开始,基于第一原理,是一个专为人工智能设计的计算机系统。
整个事物的核心是“张量流处理器”(TSP)。这是一块专为在机器学习环境中执行张量运算而设计的巨大单核芯片。称这个玩意儿为“单核”有点奇怪,因为这里有很多事情在进行。
