【AI系统】计算图的优化策略

简介: 本文深入探讨了计算图的优化策略,包括算子替换、数据类型转换、存储优化等,旨在提升模型性能和资源利用效率。特别介绍了Flash Attention算法,通过分块计算和重算策略优化Transformer模型的注意力机制,显著减少了内存访问次数,提升了计算效率。此外,文章还讨论了内存优化技术,如Inplace operation和Memory sharing,进一步减少内存消耗,提高计算性能。

除了前面提到的算子替换和算子前移等内容,本文内容将深入探讨计算图的优化策略,我们将细致分析图优化的其他重要内容,如改变数据节点的数据类型或存储格式来提升模型性能,以及优化数据的存储和访问方式以降低内存占用和数据访问时间。以上内容的理解和掌握,对于高效利用计算资源,提升算法性能具有至关重要的作用。

融合算子替换

某些复杂的算子在一些 AI 框架上可能没有直接实现,而是通过一系列基本算子的组合来实现。但是,这种组合方式可能会导致计算效率降低,因为每个算子之间的数据传输都需要额外的时间和空间。此外,过多的算子也会使得网络图变得复杂,难以理解和优化。

这时,如果推理引擎实现了该 Op,就可以把这些组合转成这个 Op,能够使得网络图更加简明清晰。具体示例如下:

Fuse Layer Norm:组合实现的 Norm Op 直接转换成一个 Op;

Fuse PReLU:组合实现的 PReLU Op 直接转换成一个 Op;

Fuse Matmul Transpose:有些框架的矩阵乘法 Matmul 层自身是不带转置操作的,当需要转置的矩阵乘法时需要前面加一个 transpose 层。如 Onnx 的 Matmul 自身有是否转置的参数,因此可以将前面的 transpose 层转换为参数即可。

Fuse Binary Eltwise:$x_3 = x_1 *b_1+x_2 *b_2 \quad\quad\quad$,把 BinaryOp Add 转换成 Eltwise Sum,而 Eltwise Sum 是有参数 coeffs,可以完成上述乘法的效果,因此把两个 BinaryOp Mul 的系数融合到 Eltwise Sum 的参数 coeffs。

Fuse Reduction with Global Pooling:对一个三维 tensor 先后两次分别进行 w 维度的 reduction mean 和 h 维度的 reducetion mean,最终只剩下 c 这个维度,就等于进行了一次 global_mean_pooling。

image

Flash Attention

这里要特别提及的一篇工作是 Flash Attention。它是一种重新排序注意力计算的算法,主要针对 Transformer 模型实现性能优化,无需任何近似即可加速注意力计算并减少内存占用。

众所周知,Transformer 结构已成为自然语言处理和图像分类等应用中最常用的架构。但由于其固有的 $O(N^2)\quad\quad$ 复杂度和内存限制的键值缓存,在推理过程中表现出次优效率。这种低效率使它们的实际部署变得复杂,特别是对于长序列来说,这就是大模型在发展的初期其输入输出往往只支持 2K 或 4K token 原因。

即使是到目前为止,GPT 最长支持 32K token 长度,Claude 最长有 100K token 的模型版本,然而这与现实的需求是不一致的。因为如果大模型要达到人类的高度,就需要从听觉、视觉、触觉多方面获取信息,这就需要更多或者是无限的输入 token。

而真正使得基于 Transformer 的大模型不能处理长 token 的本质原因,是 Transformer 的计算复杂度和空间复杂度随序列长度 N 呈二次方增长。例如,如果要将序列长度 N 翻倍成为 4N,我们所需的资源会变为 16 倍,即将序列长度扩展 N 倍,所需付出的计算和内存资源要扩大了约 $N^2$ 倍,当然这里只是近似比喻。

下面我们分析下 Attention 的计算复杂度:

假设我们有一个长度为 N 的输入序列,每个位置都用一个 d 维向量表示。那么,查询矩阵 Q 的维度是 $N×d\quad\quad$,键矩阵 K 和值矩阵 V 的维度也是 $N×d\quad\quad$;

具体来说,Attention 的计算过程可以分为以下几个步骤:

  1. 线性变换:对输入序列进行线性变换,得到 Q、K、V 三个矩阵。假设每个 token 的 embedding 维度为 k,则该步骤的复杂度为 $O(n * k * 3d)\quad\quad\quad\quad\quad$。

  2. 计算相似度得分:通过 Q、K 两个矩阵计算相似度得分,得到注意力权重矩阵。注意力权重矩阵的大小为 n * n,计算该矩阵的时间复杂度为 $O(n^2 * d * h)\quad\quad\quad\quad$。

  3. 加权求和:将注意力权重矩阵与 V 矩阵相乘并加权求和,得到最终输出。该步骤的复杂度为 O(n d h)。

因此,Attention 的总计算复杂度为 $O(n^2 * d * h)\quad\quad\quad\quad$,约为 $O(n^2)\quad\quad$时间复杂度。

FlashAtention 加速的原理是最基础和常见的系统性能优化的手段,即通过利用更高速的上层存储计算单元,减少对低速更下层存储器的访问次数,来提升模型的训练性能。

在之前的学习中,我们了解到 CPU 的多级分层存储架构,其实 GPU 的存储架构也是类似的,遵守同样的规则,即内存越快,越昂贵,容量越小。如下图左侧部分所示,在 A100 GPU 有 40-80GB 的高带宽内存(HBM,它是由多个 DRAM 堆叠出来的),带宽为 1.5-2.0 TB/s,而每 108 个流处理器(SM)有 192KB 的 SRAM,带宽估计在 19TB/s 左右。这里我们可以了解到 SRAM 的访问速率是 HBM 的 10 倍左右,然而其能承载的数据量却远远小于 HBM。

image

结合上图,我们了解到 flashAttention 是优化了计算过程中的访存(HBM)的过程,那么我们先来看下标准 Attention 的计算访存:

首先,从 HBM 中读取完整的 Q 和 K 矩阵(每个大小为 N x d),计算点积得到相似度得分 S(大小为 N x N),需要进行 $O(Nd + N^2)\quad\quad\quad\quad$ 次 HBM 访问。

其次,计算注意力权重 P(大小为 N x N)时,需要对 S 进行 softmax 操作,这需要进行 $O(N^2)\quad$ 次 HBM 访问。

最后,将注意力权重 P 和值向量 V(每个大小为 N x d)加权求和得到输出向量 O(大小为 N x d)时,需要进行 $O(Nd)\quad\quad\quad$ 次 HBM 访问。

因此,标准 Attention 算法的总 HBM 访问次数为 $O(Nd + N^2)\quad\quad\quad\quad$ 。当 N 比较大时,总的 HBM 访问次数可能会比较昂贵。

从上面可以看出,标准 Attention 算法在 GPU 内存分级存储的架构下,存在以下缺陷:

  1. 过多对 HBM 的访问,如 S、P 需要在存入 HMB 后又立即被访问,HBM 带宽较低,从而导致算法性能受限

  2. S、P 需要占用 $O(N^2)\quad\quad$ 的存储空间,显存占用较高

因此,基于之前提到的内容,可以从减少 HBM 的访问进行优化,而之所以存在大量的访存 HBM,一个原因是在 Attention 的计算中存在三个 kernel,每个 kernel 的计算过程都存在从 HBM 读取数据,计算完成后还要写回 HBM。如果我们将三个 Kernel 融合为一个,则就可以减少部分的访问 HBM 的次数。同时要保证在计算过程中要尽量的利用 SRAM 进行计算,避免访问 HBM 操作

然而,我们都知道虽然 SRAM 的带宽较大,但其计算可存储的数据量较小。如果我们采取“分治”的策略将数据进行 Tilling 处理,放进 SRAM 中进行计算,由于 SRAM 较小,当 sequence length 较大时,sequence 会被截断,从而导致标准的 SoftMax 无法正常工作。

Flash attention 则有效的解决了上述问题,总体可以归结为两个主要点:

  1. Tiling (在向前和向后传递时使用)-基本上将 NxN softmax/scores 矩阵分块成块。

  2. Recomputation (重算,仅在向后传递中使用)

Tiling(平铺)是一种处理注意力矩阵的策略,其主要思想是将原始的大型注意力矩阵拆分成更小的子矩阵,然后分别对这些子矩阵进行计算。只要每个子矩阵的大小能够适应 SRAM 的存储容量,那么在计算过程中就可以仅访问 SRAM,从而提高计算的效率。这种方法可以有效地在有限的存储和处理能力下处理大型注意力矩阵。

Recomputation(重算)则是一种以计算能力为代价来节省存储空间的策略。这种方法的核心思想是,不保存大量的梯度信息和每一层正向传播过程中的中间状态,而是在反向传播计算到某一层时,临时重新进行正向传播以得到所需的中间状态。这样,即使在存储资源有限的情况下,也能有效进行神经网络模型的训练。

主要的算法实现:

image

步骤一:计算分子块的大小

首先,我们需要获取 GPU 硬件 SRAM 的大小,我们假设为 M。为了让 Q、K、V 在计算中可以存放在 SRAM 中,我们需要设定分块的大小尺寸。

其次,在 SRAM 上需要存在的数据包括,Q 子块,K 子块,V 子块,其次还应包括计算过程中的中间输出 O,O 的大小应该与 Q、K、V 子块大小一致。

image

所以,在这里我们计算出子块的列大小 $B_c =[M/4d]\quad\quad\quad\quad$ , d 为矩阵维度。当然,需要注意的是,上面的设置子块的大小并非唯一的,只有保证子块大小不超过 SRAM 的大小即可。

步骤二:初始化输出矩阵 O

image

SRAM 上的输出 O 矩阵赋值为全 0,它将作为一个累加器保存 softmax 的累积分母,其中 l 也类似。m 用于记录每一行行最大分数,其初始化为-inf。

步骤三:切分子块

image

将 Q 划分成 $T_r$ 个 Bolck,K、V 划分成 $T_c$ 个 Block,初始化 attention output O,并划分成 $T_r$ 个 Block。

步骤四:外循环加载 K、V 内循环加载 Q 子块

image

上图完美解释了这个循环过程,

  1. 外循环:对于每一个 Block Key 和 Value,从 HBM 加载进 SRAM
  2. 内循环:对于每个 Block Query,从 HBM 加载进 SRAM
  3. 在 SRAM 上完成 Block S 的计算

image

这里要注意的是,$O_i$ , $l_i$, $m_i$ 其中存储的可能是上一个循环计算的中间结果。

步骤五:实现分块 SoftMax 算法

下面我们看看原版的证明公式:

标准 softmax 计算方式

image

在实际硬件中,因为浮点数表示的范围是有限的,对于 float32 和 bfloat16 来说,当 z ≥ 89 时,exp(z) 就会变成 inf,发生数据上溢的问题。

为了确保数值计算的稳定性,避免溢出问题,通常采用一种称为“safe softmax”的计算策略。在此方法中,通过减去最大值来缩放输入数据,以保证数值的相对稳定性。

所以说,现有所有的深度学习框架中都采用了“safe softmax”这种计算方式,其计算公式如下:

image

计算举例:$a = [0.1, 0.2, 0.3, 0.4]; \quad m(a) = 0.4$

则可以得到:$f(a) = [e^{(0.1-0.4)}, e^{(0.2-0.4)}, e^{(0.3-0.4)}, e^{(0.4-0.4)}]$

然后计算得到:$l(a) = Σf(a), softmax(a) = f(a) / l(a)$

从上面可以看出,首先在分子上“safe softmax”需要获取当前区间的最大值来缩放输入数据,而在分母上需要累加所有的分子 $f(a)\quad\quad$。

由于 flashAttention 已经采取了分块计算的策略,也就意味着在计算 softmax 时,并不能拿到所有数据列的最大值和全部 $f(a)\quad\quad$ 的和。

flashAttention 改进方式

虽然 softmax 与 K 的列是耦合的,但如果分开计算每个子块的 softmax 再将最后的结果进行收集转换是否可以等价呢?下面我们看看原版的证明公式:

  1. 假如有切片向量 $x = [x^{(1)}, x^{(2)}]\quad\quad$ ,切片后 softmax 的计算方式:

    image

  2. update $m(x)\quad\quad$,根据更新后的 $m(x)\quad\quad$,根据上一步计算结果重新计算 $f(x)\quad\quad$, $l(x)\quad\quad$。假设存在 $x^{(3)}$, 那么便可以将 $x^{(1)}$ 和 $x^{(2)}$合并成一个序列,重复步骤 1 即可。

计算举例:$a = [0.1, 0.2, 0.3, 0.4] = [a1, a2]$

则可以得到:$m(a1) = 0.2, m(a2) = 0.4 , \quad m(a) = 0.4$

然后计算得到:
$$ f(a_1) = [e^{(0.1-0.2)}, e^{(0.2-0.2)}], \\ f(a_2) = [e^{(0.3-0.4)}, e^{(0.4-0.4)}], \\ f(a) = [e^{(0.2-0.4)}f(a_1), e^{(0.4-0.4)}f(a_2)],\\ $$
同理 $l(a) = e^{(0.2-0.4)}l(a_1) + e^{(0.4-0.4)}l(a_2)$

最终得到 $softmax(a) = f(a) / l(a)$

需要注意的是,可以利用 GPU 多线程同时并行计算多个 block 的 softmax。

可见通过上述的转换可知,softmax 与分块 softmax 是在数学上是等价的关系。不过由于真实计算中次数变多,精度上也可能存在一定丢失。

在介绍完 flashAttention 中 softmax 的改进后,我们继续围绕论文中的代码进行分析:

image

首先,根据上一步计算的子块 $S_{ij}$,来计算当前块的行最大值 $m_{ij}$,当前块 $P_{ij}$ (即 softmax 的分子),$l_{ij}$ 为 $P_{ij}$ 的累积值。

其次,计算子块与子块间的最大值 $m^{new}$ 和多个子块的 $P_{ij}$ 的累积值 $l^{new}$。

最后,根据 softmax 公式计算最终的 softmax,经结果写到 SRAM 的 $O_i$ 中,并写出到 HBM,同时将最后的最后的 $l^{new}$ 赋值给 $l_i$ 写出到 HBM,$m^{new}$ 赋值到 $m_i$ 写出到 HBM,开始下一轮循环。

到此前向计算就算完成,我们可以通过下图来总结下 flashAttention 的前向计算过程,这里就不做过多解释了。

image

步骤六:反向计算

从上面的前向过程中,我们知道前向过程中只将 $O_i$, $l_i$, $m_i$ 写出到了 HBM,而 S 和 P 的保存则主要在反向的重算中实现。

  1. 前向过程会保留 Q,K,V,O, l, m 在 HBM 中,$dO\quad$ 由反向计算获取后,按照前向相同的分块模式重新分块。

  2. 初始化 $dQ \quad\quad$,$dK\quad\quad$,$dV\quad$ 为全 0 矩阵,并按照对等 Q,K,V 的分割方式分割 $dQ\quad\quad$,$dK\quad\quad$,$dV\quad\quad$。

  3. 分别从 HBM 中 Load K V block on SRAM,再 Load Q block on SRAM。根据前向过程重新计算对应 block 的 S 和 P;按分块矩阵的方式分别计算对应梯度,完成参数更新。

最终可以看到,在将三个 kernel 进行合并后,flashAttention v1 实现了中间计算完全基于 SRAM 的目的。

flashAttention 性能分析

FlashAttention 节省的访存次数计算如下:

首先,K,V (Nxd)的每个 block 都需要 Load 进 SRAM,因此该过程的 HBM 访问次数为 $O(N\times d)\quad\quad\quad\quad$。

其次,Q 也需要分 block Load 进 SRAM,该过程一共持续外循环 $T_c$ 次,因此该过程的 HBM 访问次数为 $O(T_cNd)$

最后,而 $T_c = N/(B_c) = 4Nd/M\quad\quad\quad\quad\quad\quad\quad$ (向上取整)。因此 flash attention 的 HBM 访问次数为 $O(N^2d^2/M)$

下面来看 flash Attention 代码的具体实现:https://github.com/openai/triton/blob/main/python/tutorials/06-fused-attention.py#L17

def _fwd_kernel(
    Q, K, V, sm_scale,
    L, M,
    Out,
    stride_qz, stride_qh, stride_qm, stride_qk,
    stride_kz, stride_kh, stride_kn, stride_kk,
    stride_vz, stride_vh, stride_vk, stride_vn,
    stride_oz, stride_oh, stride_om, stride_on,
    Z, H, N_CTX,
    BLOCK_M: tl.constexpr, BLOCK_DMODEL: tl.constexpr,
    BLOCK_N: tl.constexpr,
):
    start_m = tl.program_id(0)
    off_hz = tl.program_id(1)
    # initialize offsets
    offs_m = start_m * BLOCK_M + tl.arange(0, BLOCK_M)
    offs_n = tl.arange(0, BLOCK_N)
    offs_d = tl.arange(0, BLOCK_DMODEL)
    off_q = off_hz * stride_qh + offs_m[:, None] * stride_qm + offs_d[None, :] * stride_qk
    off_k = off_hz * stride_qh + offs_n[None, :] * stride_kn + offs_d[:, None] * stride_kk
    off_v = off_hz * stride_qh + offs_n[:, None] * stride_qm + offs_d[None, :] * stride_qk
    # Initialize pointers to Q, K, V
    q_ptrs = Q + off_q
    k_ptrs = K + off_k
    v_ptrs = V + off_v
    # initialize pointer to m and l
    m_prev = tl.zeros([BLOCK_M], dtype=tl.float32) - float("inf")
    l_prev = tl.zeros([BLOCK_M], dtype=tl.float32)
    acc = tl.zeros([BLOCK_M, BLOCK_DMODEL], dtype=tl.float32)
    # load q: it will stay in SRAM throughout
    q = tl.load(q_ptrs)
    # loop over k, v and update accumulator
    for start_n in range(0, (start_m + 1) * BLOCK_M, BLOCK_N):
        # -- compute qk -
        k = tl.load(k_ptrs)
        qk = tl.zeros([BLOCK_M, BLOCK_N], dtype=tl.float32)
        qk += tl.dot(q, k)
        qk *= sm_scale
        qk = tl.where(offs_m[:, None] >= (start_n + offs_n[None, :]), qk, float("-inf"))
        # compute new m
        m_curr = tl.maximum(tl.max(qk, 1), m_prev)
        # correct old l
        l_prev *= tl.exp(m_prev - m_curr)
        # attention weights
        p = tl.exp(qk - m_curr[:, None])
        l_curr = tl.sum(p, 1) + l_prev
        # rescale operands of matmuls
        l_rcp = 1. / l_curr
        p *= l_rcp[:, None]
        acc *= (l_prev * l_rcp)[:, None]
        # update acc
        p = p.to(Q.dtype.element_ty)
        v = tl.load(v_ptrs)
        acc += tl.dot(p, v)
        # update m_i and l_i
        l_prev = l_curr
        m_prev = m_curr
        # update pointers
        k_ptrs += BLOCK_N * stride_kn
        v_ptrs += BLOCK_N * stride_vk
    # rematerialize offsets to save registers
    start_m = tl.program_id(0)
    offs_m = start_m * BLOCK_M + tl.arange(0, BLOCK_M)
    # write back l and m
    l_ptrs = L + off_hz * N_CTX + offs_m
    m_ptrs = M + off_hz * N_CTX + offs_m
    tl.store(l_ptrs, l_prev)
    tl.store(m_ptrs, m_prev)
    # initialize pointers to output
    offs_n = tl.arange(0, BLOCK_DMODEL)
    off_o = off_hz * stride_oh + offs_m[:, None] * stride_om + offs_n[None, :] * stride_on
    out_ptrs = Out + off_o
    tl.store(out_ptrs, acc)

Flash Attention 在速度和内存占用方面都表现出明显的优势,并取得了良好的效果。目前,Flash Attention 已经经过广泛验证, torch2.0 中已提供 flashattention 的实现。

Flash Attention 的优点在于充分考虑了在计算任务中 IO 的重要性,并通过分块计算的方式开发了一种快速、节省显存、精确无近似的注意力实现方法。这使得我们更便于训练具有更长上下文的 Transformer 模型,并且为后续注意力算法的优化提供了一个基准。

layout&memory 优化

针对网络模型,特别是在处理算子(操作符)时。算子在这里可以理解为模型中完成特定任务的一种函数或者操作,例如卷积,矩阵乘法等。

当上一层和下一层的算子相同时,我们可能不需要进行数据节点转换。因为这两层已经在进行相同的操作,再进行转换可能不会带来额外的优化效果。

当上一层的输入和下一层的输入不同时,我们就需要进行数据节点转换。具体来说,我们需要插入特定的算子来处理这种输入的变化。这个过程也是图优化的一部分。

如果在某些情况下,我们发现有些算子在当前的计算图中是多余的,或者说并没有为模型的性能提升做出贡献,那么我们需要删除这些算子。

具体示例如下:

image

内存优化是一种计算机系统优化技术,主要目的是提高系统的运行性能,通过更有效地使用和管理内存资源来达到这个目的。

Inplace operation:是一种内存优化手段,它在当前的内存块上直接进行操作,而不需要额外开辟新的内存。如果一块内存不再需要,且下一个操作是 element-wise(元素级操作,比如加法、乘法等),我们就可以使用原地操作,直接在原内存上进行计算,覆盖原有的数据。这样做的好处是可以节省内存,减少内存的分配和回收开销,从而提高程序的运行效率。

Memory sharing:是另一种内存优化策略。它在内存使用上进行优化,当两个数据的内存大小相同,且有一个数据参与计算后不再需要时,我们可以让后一个数据直接覆盖前一个数据的内存。这样做的好处是可以减少内存的开销,节省内存空间,提高内存的使用效率。

image

如果您想了解更多AI知识,与AI专业人士交流,请立即访问昇腾社区官方网站https://www.hiascend.com/或者深入研读《AI系统:原理与架构》一书,这里汇聚了海量的AI学习资源和实践课程,为您的AI技术成长提供强劲动力。不仅如此,您还有机会投身于全国昇腾AI创新大赛和昇腾AI开发者创享日等盛事,发现AI世界的无限奥秘~

相关实践学习
部署Stable Diffusion玩转AI绘画(GPU云服务器)
本实验通过在ECS上从零开始部署Stable Diffusion来进行AI绘画创作,开启AIGC盲盒。
目录
相关文章
|
4天前
|
存储 人工智能 vr&ar
转载:【AI系统】CPU 基础
CPU,即中央处理器,是计算机的核心部件,负责执行指令和控制所有组件。本文从CPU的发展史入手,介绍了从ENIAC到现代CPU的演变,重点讲述了冯·诺依曼架构的形成及其对CPU设计的影响。文章还详细解析了CPU的基本构成,包括算术逻辑单元(ALU)、存储单元(MU)和控制单元(CU),以及它们如何协同工作完成指令的取指、解码、执行和写回过程。此外,文章探讨了CPU的局限性及并行处理架构的引入。
转载:【AI系统】CPU 基础
|
4天前
|
人工智能 缓存 并行计算
转载:【AI系统】CPU 计算本质
本文深入探讨了CPU计算性能,分析了算力敏感度及技术趋势对CPU性能的影响。文章通过具体数据和实例,讲解了CPU算力的计算方法、算力与数据加载之间的平衡,以及如何通过算力敏感度分析优化计算系统性能。同时,文章还考察了服务器、GPU和超级计算机等平台的性能发展,揭示了这些变化如何塑造我们对CPU性能的理解和期待。
转载:【AI系统】CPU 计算本质
|
4天前
|
机器学习/深度学习 存储 人工智能
转载:【AI系统】计算之比特位宽
本文详细介绍了深度学习中模型量化操作及其重要性,重点探讨了比特位宽的概念,包括整数和浮点数的表示方法。文章还分析了不同数据类型(如FP32、FP16、BF16、FP8等)在AI模型中的应用,特别是FP8数据类型在提升计算性能和降低内存占用方面的优势。最后,文章讨论了降低比特位宽对AI芯片性能的影响,强调了在不同应用场景中选择合适数据类型的重要性。
转载:【AI系统】计算之比特位宽
|
1天前
|
人工智能 安全 算法
CAMEL AI 上海黑客松重磅来袭!快来尝试搭建你的第一个多智能体系统吧!
掌握多智能体系统,🐫 CAMEL-AI Workshop & 黑客马拉松即将启航!
|
5天前
|
机器学习/深度学习 人工智能 自然语言处理
转载:【AI系统】AI的领域、场景与行业应用
本文概述了AI的历史、现状及发展趋势,探讨了AI在计算机视觉、自然语言处理、语音识别等领域的应用,以及在金融、医疗、教育、互联网等行业中的实践案例。随着技术进步,AI模型正从单一走向多样化,从小规模到大规模分布式训练,企业级AI系统设计面临更多挑战,同时也带来了新的研究与工程实践机遇。文中强调了AI基础设施的重要性,并鼓励读者深入了解AI系统的设计原则与研究方法,共同推动AI技术的发展。
转载:【AI系统】AI的领域、场景与行业应用
|
6天前
|
人工智能 缓存 异构计算
云原生AI加速生成式人工智能应用的部署构建
本文探讨了云原生技术背景下,尤其是Kubernetes和容器技术的发展,对模型推理服务带来的挑战与优化策略。文中详细介绍了Knative的弹性扩展机制,包括HPA和CronHPA,以及针对传统弹性扩展“滞后”问题提出的AHPA(高级弹性预测)。此外,文章重点介绍了Fluid项目,它通过分布式缓存优化了模型加载的I/O操作,显著缩短了推理服务的冷启动时间,特别是在处理大规模并发请求时表现出色。通过实际案例,展示了Fluid在vLLM和Qwen模型推理中的应用效果,证明了其在提高模型推理效率和响应速度方面的优势。
云原生AI加速生成式人工智能应用的部署构建
|
5天前
|
机器学习/深度学习 人工智能 物联网
AI赋能大学计划·大模型技术与应用实战学生训练营——电子科技大学站圆满结营
12月05日,由中国软件行业校园招聘与实习公共服务平台携手阿里魔搭社区共同举办的AI赋能大学计划·大模型技术与产业趋势高校行AIGC项目实战营·电子科技大学站圆满结营。
AI赋能大学计划·大模型技术与应用实战学生训练营——电子科技大学站圆满结营
|
11天前
|
机器学习/深度学习 人工智能 JSON
【实战干货】AI大模型工程应用于车联网场景的实战总结
本文介绍了图像生成技术在AIGC领域的发展历程、关键技术和当前趋势,以及这些技术如何应用于新能源汽车行业的车联网服务中。
160 32
|
18小时前
|
机器学习/深度学习 人工智能 算法
探索AI在医疗诊断中的应用与挑战
【10月更文挑战第21天】 本文深入探讨了人工智能(AI)技术在医疗诊断领域的应用现状与面临的挑战,旨在为读者提供一个全面的视角,了解AI如何改变传统医疗模式,以及这一变革过程中所伴随的技术、伦理和法律问题。通过分析AI技术的优势和局限性,本文旨在促进对AI在医疗领域应用的更深层次理解和讨论。
|
6天前
|
人工智能 Kubernetes 安全
赋能加速AI应用交付,F5 BIG-IP Next for Kubernetes方案解读
赋能加速AI应用交付,F5 BIG-IP Next for Kubernetes方案解读
40 13