Transformer架构下的详细计算流程模拟,精确到数字(单层单头)

前言

本文用一套模拟数字,通过详细的数字计算,看看Transformer架构下大模型是如何使用自注意力,不断计算出下一个token的。

本文的计算步骤,是单层单头的计算步骤,实际的Transformer架构是多层且多头的。所谓多层和多头,其实就是对其中的部分步骤进行拆分(多头)和重复(多层)。

最后提出一个问题,用人类能看懂的语言,说明大模型到底在算什么。

第一部分,概念和命名

1,参数

d_model,嵌入维度。是嵌入矩阵的"列数"。本例中设为4。

d_k,注意力头的维度。是K和Q权重矩阵列数,可以自定义。实际大模型应用中,d_k往往固定,比如128,多头注意力中,d_k = d_model / 头数

d_v,值向量维度。是V权重矩阵列数。本例中设为3。

2,矩阵和向量

X向量,token在字典表中的原始向量,长度d_model。

X_苹果,"苹果"这个token的原始向量。长度是d_model。

X矩阵,原始向量叠加形成的嵌入矩阵。列数是d_model,行数是token数。

V_苹果,"苹果"这个token的V向量。

K_苹果,"苹果"这个token的K向量。

3,KQV权重矩阵

W_Q,Q权重矩阵,用于"问"。行数=d_model,列数=d_k。

W_K,K权重矩阵,用于"被问"。行数=d_model,列数=d_k

W_V,V权重矩阵,用于"实际内容"。行数=d_model,列数=d_v

权重矩阵初始化时,每个数字都是随机的,经过训练,数字会发生变化。

4,KQV矩阵

输入嵌入矩阵 乘以对应权重矩阵获得。比如输入嵌入矩阵乘以W_Q得到Q矩阵。

行数=输入token数 列数=d_k。

注:

为什么这三个矩阵叫做KQV?

通过下面计算流程,我们发现K和Q总是协同操作,计算Q×K^T,所以:

Q是乘数,负责如何更好的问,比如提高"好"和"吃"的匹配度。

K是被乘数,是被Q问的,负责被检索到的难易度,比如"吃"会被谁问到。

V不参与矩阵点积,参与是的隐藏状态的加权求和,负责内容的纯净度,比如"吃"应该更多具备"咀嚼"还是"吞咽"的含义。

5,候选词权重矩阵W_out

现代大模型中,往往是把嵌入向量直接转置,当做W_out用,这个玩法叫权重绑定,即:

每一列叫做输出嵌入向量,数值上等于一个token的X向量的转置

行数=d_model,列数=字典表长度

W_out不用单独存,用的时候去查嵌入矩阵,查完转置一下就行,省显存。

W_out的值在训练中会发生变化,即:直接改嵌入矩阵。

6,矩阵的转置

比如:对矩阵K转置,转置后的矩阵叫做K^T。

第二部分,具体计算步骤

第1步:输入与Token切分

用户输入:"苹果好吃"

分词器将其切分为3个Token:

Token 1:苹果

Token 2:好

Token 3:吃

第2步:查嵌入表,得到原始向量 X

假设嵌入矩阵(Embedding Table)中,这三个Token对应的原始向量为:

X_苹果(第1行):1, 0, 1, 0

X_好(第2行):0, 1, 0, 1

X_吃(第3行):1, 1, 0, 0

将它们按行叠起来,得到输入嵌入矩阵 X(3×4):

第3步:定义三个投影权重矩阵(W_Q、W_K、W_V)

按照规则:

W_Q 和 W_K 的形状必须是 (d_model, d_k) = (4, 4)

W_V 的形状必须是 (d_model, d_v) = (4, 3)

我们人为设定(矩阵中的每个值在训练前是随机数,这里我们直接拿来用):

W_Q(4行 × 4列):

W_K(4行 × 4列):

W_V(4行 × 3列):

第4步:生成 Q 矩阵

计算规则:Q = X · W_Q,结果为 (3行 × 4列)。

逐行手算:

第1行(苹果):1, 0, 1, 0 乘以 W_Q 的每一列

第1列 1,0,1,0 : 1×1 + 0×0 + 1×1 + 0×0 = 2

第2列 0,1,1,0 : 1×0 + 0×1 + 1×1 + 0×0 = 1

第3列 1,0,0,1 : 1×1 + 0×0 + 1×0 + 0×1 = 1

第4列 0,1,0,1 : 1×0 + 0×1 + 1×0 + 0×1 = 0

得到 Q_苹果 = 2, 1, 1, 0

第2行(好):0, 1, 0, 1乘以 W_Q 的每一列

第1列1,0,1,0:0×1 + 1×0 + 0×1 + 1×0 = 0

第2列0,1,1,0:0×0 + 1×1 + 0×1 + 1×0 = 1

第3列1,0,0,1:0×1 + 1×0 + 0×0 + 1×1 = 1

第4列0,1,0,1:0×0 + 1×1 + 0×0 + 1×1 = 2

得到 Q_好 = 0, 1, 1, 2

第3行(吃):1, 1, 0, 0乘以 W_Q 的每一列

第1列1,0,1,0:1×1 + 1×0 + 0×1 + 0×0 = 1

第2列0,1,1,0:1×0 + 1×1 + 0×1 + 0×0 = 1

第3列1,0,0,1:1×1 + 1×0 + 0×0 + 0×1 = 1

第4列0,1,0,1:1×0 + 1×1 + 0×0 + 0×1 = 1

得到 Q_吃 = 1, 1, 1, 1

叠加得到最终 Q 矩阵(3×4) 为:

第5步:生成 K 矩阵

计算规则:K = X · W_K,结果也为 (3行 × 4列)。

第1行(苹果):1, 0, 1, 0乘以 W_K 的每一列

第1列 0,1,1,0 : 1×0 + 0×1 + 1×1 + 0×0 = 1

第2列 1,0,0,1 : 1×1 + 0×0 + 1×0 + 0×1 = 1

第3列 1,0,1,0 : 1×1 + 0×0 + 1×1 + 0×0 = 2

第4列 0,1,0,1 : 1×0 + 0×1 + 1×0 + 0×1 = 0

得到 K_苹果 = 1, 1, 2, 0

第2行(好):0, 1, 0, 1乘以 W_K 的每一列

第1列 0,1,1,0:0×0 + 1×1 + 0×1 + 1×0 = 1

第2列 1,0,0,1:0×1 + 1×0 + 0×0 + 1×1 = 1

第3列 1,0,1,0:0×1 + 1×0 + 0×1 + 1×0 = 0

第4列:0×0 + 1×1 + 0×0 + 1×1 = 2

得到 K_好 = 1, 1, 0, 2

第3行(吃):1, 1, 0, 0乘以 W_K 的每一列

第1列 0,1,1,0:1×0 + 1×1 + 0×1 + 0×0 = 1

第2列 1,0,0,1:1×1 + 1×0 + 0×0 + 0×1 = 1

第3列 1,0,1,0:1×1 + 1×0 + 0×1 + 0×0 = 1

第4列 0,1,0,1:1×0 + 1×1 + 0×0 + 0×1 = 1

得到 K_吃 = 1, 1, 1, 1

最终 K 矩阵(3×4) 为:

第6步:生成 V 矩阵

计算规则:V = X · W_V,结果为 (3行 × 3列)。

第1行(苹果):1, 0, 1, 0 乘以 W_V(4×3)的每一列

第1列 1,0,1,0 : 1×1 + 0×0 + 1×1 + 0×0 = 2

第2列 1,0,0,1 : 1×1 + 0×0 + 1×0 + 0×1 = 1

第3列 0,1,1,0 : 1×0 + 0×1 + 1×1 + 0×0 = 1

得到 V_苹果 = 2, 1, 1

第2行(好):0, 1, 0, 1 乘以 W_V(4×3)的每一列

第1列1,0,1,0:0×1 + 1×0 + 0×1 + 1×0 = 0

第2列1,0,0,1:0×1 + 1×0 + 0×0 + 1×1 = 1

第3列0,1,1,0:0×0 + 1×1 + 0×1 + 1×0 = 1

得到 V_好 = 0, 1, 1

第3行(吃):1, 1, 0, 0 乘以 W_V(4×3)的每一列

第1列1,0,1,0:1×1 + 1×0 + 0×1 + 0×0 = 1

第2列1,0,0,1:1×1 + 1×0 + 0×0 + 0×1 = 1

第3列0,1,1,0:1×0 + 1×1 + 0×1 + 0×0 = 1

得到 V_吃 = 1, 1, 1

V向量叠加得到最终 V 矩阵(3×3) 为:

第7步:计算 K 的转置(K^T)

K 原本是(3行 × 4列),转置后变为 K^T(4行 × 3列):

第1列是"苹果"的K,第2列是"好"的K,第3列是"吃"的K

第8步:计算原始注意力分数矩阵(Q · K^T)

计算规则:分数 = Q(3×4)· K^T(4×3),结果为 (3×3)。

逐行点积:

第1行(Q_苹果 = 2, 1, 1, 0):

与 K^T 第1列 1,1,2,0 : 2×1 + 1×1 + 1×2 + 0×0 = 5

与 K^T 第2列 1,1,0,2 : 2×1 + 1×1 + 1×0 + 0×2 = 3

与 K^T 第3列 1,1,1,1 : 2×1 + 1×1 + 1×1 + 0×1 = 4

得到 "苹果"对 苹果, 好, 吃 的分数 = 5, 3, 4

第2行(Q_好 = 0, 1, 1, 2):

与第1列:0×1 + 1×1 + 1×2 + 2×0 = 3

与第2列:0×1 + 1×1 + 1×0 + 2×2 = 5

与第3列:0×1 + 1×1 + 1×1 + 2×1 = 4

得到 "好"对 苹果, 好, 吃 的分数 = 3, 5, 4

第3行(Q_吃 = 1, 1, 1, 1):

与第1列:1×1 + 1×1 + 1×2 + 1×0 = 4

与第2列:1×1 + 1×1 + 1×0 + 1×2 = 4

与第3列:1×1 + 1×1 + 1×1 + 1×1 = 4

得到 "吃"对 苹果, 好, 吃 的分数 = 4, 4, 4

分数向量叠加,得到最终原始分数矩阵为:

分数=

每行代表每个输入token对所有输入token的注意力分数。

第9步:缩放(Scale)

根据设定,d_k = 4,所以缩放因子为d_k的开方, √d_k = √4 = 2。

将原始分数矩阵中的每一个数字都除以 2:

第1行:5/2, 3/2, 4/2 = 2.5, 1.5, 2.0

第2行:3/2, 5/2, 4/2 = 1.5, 2.5, 2.0

第3行:4/2, 4/2, 4/2 = 2.0, 2.0, 2.0

得到缩放后的分数矩阵 S:

第10步:Softmax 归一化(得到注意力权重)

我们需要对 每一行 分别做 Softmax(让每一行的三个数加起来等于 1,代表概率)。

由于在生成第一个字时,我们主要关注最后一个输入Token("吃")的隐藏状态,所以我们优先计算 第3行(对应"吃"):

第3行数据:2.0, 2.0, 2.0

计算 e 的指数(自然常数):

e^2.0 ≈ 7.389

e^2.0 ≈ 7.389

e^2.0 ≈ 7.389

分母总和 = 7.389 + 7.389 + 7.389 = 22.167

算出概率(权重):

对"苹果"的权重:7.389 / 22.167 ≈ 0.333

对"好"的权重:7.389 / 22.167 ≈ 0.333

对"吃"的权重:7.389 / 22.167 ≈ 0.333

所以,当模型处理最后一个词 "吃" 时,它分配给"苹果"、"好"、"吃"的注意力权重分别是:

权重_吃 = 0.333, 0.333, 0.333

(注:巧合的是,因为这三个数完全相等,所以结果是平均分配。但在真实场景中极少出现全等,这里是为了让你看到最标准的数学运算。)

第11步:回顾 V 矩阵(来自第6步)

我们在第一部分已经算出了 V 矩阵(形状 3×3):

第1行是V_苹果,第2行是V_好,第3行是V_吃

第12步:生成最后一个输入Token("吃")的新隐藏状态 H_新

算法:用第3行的注意力权重 0.333, 0.333, 0.333,去加权求和 V 矩阵的三行。

H_新=0.333×V_苹果+0.333×V_好+0.333×V_吃

我们按位置(3个维度)分别相加:

第1维:0.333×2 + 0.333×0 + 0.333×1 = 0.666 + 0 + 0.333 = 0.999 ≈ 1.0

第2维:0.333×1 + 0.333×1 + 0.333×1 = 0.333 + 0.333 + 0.333 = 0.999 ≈ 1.0

第3维:0.333×1 + 0.333×1 + 0.333×1 = 0.333 + 0.333 + 0.333 = 0.999 ≈ 1.0

(四舍五入后)得到最终隐藏状态:

H_新=1.0,1.0,1.0

注意:H_新 的长度是 3,因为我们设定的 d_v = 3。它代表模型"吃"这个位置在融合了上下文后,最终形成的内部语义向量。

第13步:定义候选词权重矩阵 W_out

假设我们的候选词表是:"是", "了", "甜"(共3个词)。

W_out 的形状必须是 (d_v, 词表大小) = (3, 3)。

为了演示能选出 "是",我们特意设定这个映射矩阵(实际训练中,这里的值会不断变化):

W_out=

第1列对应"是",第2列对应"了",第3列对应"甜"

第14步:计算每个候选字的原始得分(Logits)

这是标准的矩阵乘法:得分 = H_新 (1×3) · W_out (3×3),结果为一个 (1×3) 向量。

"是"的得分(取 W_out 第1列 3, 1, 1^T):

1.0×3 + 1.0×1 + 1.0×1 = 5

"了"的得分(取 W_out 第2列 1, 2, 1^T):

1.0×1 + 1.0×2 + 1.0×1 = 4

"甜"的得分(取 W_out 第3列 0, 0, 1^T):

1.0×0 + 1.0×0 + 1.0×1 = 1

得到原始得分向量:

Logits=5, 4, 1

分别对应"是"、"了"、"甜"

第15步:对得分再次 Softmax,得到第一个输出token

5, 4, 1 再次做 Softmax:

e^5 ≈ 148.413

e^4 ≈ 54.598

e^1 ≈ 2.718

分母总和 = 148.413 + 54.598 + 2.718 = 205.729

计算概率:

"是"的概率:148.413 / 205.729 ≈ 0.721(72.1%)

"了"的概率:54.598 / 205.729 ≈ 0.265(26.5%)

"甜"的概率:2.718 / 205.729 ≈ 0.013(1.3%)

因为 "是"的概率最高(72.1%),模型大概率会选择生成的第一个字就是"是"。

注:

我们为什么不直接选Logits向量中数值最大的那个数字作为下一个token,而是做一次softmax然后再算概率?

1,token的选择不是直接选最大的,而是按概率选,有可能选到概率较小的,否则每次生成的结果会一模一样。

2,Logits向量的数值可能会非常大,防止指数爆炸,用概率数值稳定。

3,最主要的原因,在训练时,这个概率需要向正确的概率不断调整,即:梯度需要不断下降。比如前文中,大模型算出,"是"的概率最高(72.1%),模型算对了,也选对了,梯度就直接降为0,就不再学习了。但在实际的训练语料中,"是"的可能是80%,不是72.1%,那么这个误差信号(交叉熵损失)会反向传播回去,告诉 W_Q、W_K、W_V:虽然你蒙对了,但还不够自信,请继续调整参数,把'是'的概率从72.1%再往80%推一把。

第16步:开始选第二个输出token(同第2步)

在真实场景中,token"是"也有自己的嵌入向量,假设:

X_是 = 0, 0, 1, 1 (长度为 d_model=4)

此时,输入序列变成:"苹果", "好", "吃", "是"

原始嵌入矩阵 X的最后一行 叠加上X_是,扩展为 4行:

第17步:计算新Token"是"的 Q、K、V(同第4.5.6步)

(1)计算 Q_是(X_是 × W_Q)

X_是 = 0, 0, 1, 1

前文中的W_Q 矩阵:

逐列点积计算 Q_是(长度为4):X_是 × W_Q

第1列 1,0,1,0:0×1 + 0×0 + 1×1 + 1×0 = 1

第2列 0,1,1,0:0×0 + 0×1 + 1×1 + 1×0 = 1

第3列 1,0,0,1:0×1 + 0×0 + 1×0 + 1×1 = 1

第4列 0,1,0,1:0×0 + 0×1 + 1×0 + 1×1 = 1

得到:Q_是 = 1, 1, 1, 1

(2)计算 K_是(X_是 × W_K)

前文中的W_K 矩阵:

逐列点积:

第1列 0,1,1,0:0×0 + 0×1 + 1×1 + 1×0 = 1

第2列 1,0,0,1:0×1 + 0×0 + 1×0 + 1×1 = 1

第3列 1,0,1,0:0×1 + 0×0 + 1×1 + 1×0 = 1

第4列 0,1,0,1:0×0 + 0×1 + 1×0 + 1×1 = 1

得到:K_是 = 1, 1, 1, 1

(3)计算 V_是(X_是 × W_V)

前文中的W_V 矩阵:

逐列点积:

第1列 1,0,1,0:0×1 + 0×0 + 1×1 + 1×0 = 1

第2列 1,0,0,1:0×1 + 0×0 + 1×0 + 1×1 = 1

第3列 0,1,1,0:0×0 + 0×1 + 1×1 + 1×0 = 1

得到:V_是 = 1, 1, 1

第18步:计算新Token"是"的注意力分数(同第7.8步)

第5步计算的K向量,都会记入缓存,此时,缓存的旧 K 包括:

K_苹果 = 1, 1, 2, 0

K_好 = 1, 1, 0, 2

K_吃 = 1, 1, 1, 1

再加上刚刚算出的 K_是 = 1, 1, 1, 1

新的 K 矩阵扩展为 4行×4列:

K_新=

计算新的原始注意力分数(只算新Token"是"这一行):

Q_是 = 1, 1, 1, 1 ,分别点乘 K 的每一行,

新分数=Q_是 × K_新^T:

与 K_苹果 1,1,2,0:1×1 + 1×1 + 1×2 + 1×0 = 4

与 K_好 1,1,0,2:1×1 + 1×1 + 1×0 + 1×2 = 4

与 K_吃 1,1,1,1:1×1 + 1×1 + 1×1 + 1×1 = 4

与 K_是 1,1,1,1:1×1 + 1×1 + 1×1 + 1×1 = 4

新Token"是"的原始注意力分数行向量为:

新分数=4, 4, 4, 4

(分别对应:苹果、好、吃、是)

第19步:缩放和 Softmax 归一化(同第9.10步)

缩放:除以 √d_k = √4 = 2

4/2, 4/2, 4/2, 4/2\] = \[2, 2, 2, 2

Softmax:因为四个数完全相等,e^2 都相同,所以概率均等:

对"苹果"的注意力权重:1/4 = 0.25

对"好"的权重:0.25

对"吃"的权重:0.25

对"是"的权重:0.25

得到权重向量:权重_是=0.25, 0.25, 0.25, 0.25

第20步:计算新Token"是"的新隐藏状态(同第12步)

V 矩阵此时发生了变化,从原来的 3行×3列 扩展为 4行×3列(新增了 V_是)。

V_新=

前3行是之前V_新里的苹果、好、吃;第4行是新增的V_是。

用第19步得到的新权重向量 0.25, 0.25, 0.25, 0.25 加权求和,

H_新(是) =权重向量_吃×V_新

第1维:0.25×2 + 0.25×0 + 0.25×1 + 0.25×1 = 0.5 + 0 + 0.25 + 0.25 = 1.0

第2维:0.25×1 + 0.25×1 + 0.25×1 + 0.25×1 = 0.25 + 0.25 + 0.25 + 0.25 = 1.0

第3维:0.25×1 + 0.25×1 + 0.25×1 + 0.25×1 = 0.25 + 0.25 + 0.25 + 0.25 = 1.0

得到新Token"是"的最终隐藏状态:

H_新(是) =1.0, 1.0, 1.0

第21步:计算候选词得分并得到第二个token(同第13.14.15步)

还是沿用之前的 W_out(3列对应"是"、"了"、"甜"),只有3个候选词:

W_out=

H_新(是) = 1, 1, 1 × W_out

"是"的得分:1×3 + 1×1 + 1×1 = 5

"了"的得分:1×1 + 1×2 + 1×1 = 4

"甜"的得分:1×0 + 1×0 + 1×1 = 1

再次 Softmax 后,概率依然为:"是"占72.1%,所以模型第二次生成的依然是"是"。

在实际训练有素的模型中,第二轮可能会生成"甜"或"的",但因为我们这里用的 W_out 是人为固定不变的,所以它会继续输出概率最高的"是"。这也从侧面说明了为什么模型的权重必须经过海量训练------只有训练过的 W_out 才能让"甜"在第二轮胜出。

以上即为全部计算流程。重复以上流程,可以不断计算下一个token,直到得到完整的回答。

第三部分,深入浅出

1,一个问题

在做矩阵乘法计算时,矩阵1的第一行乘以矩阵2的第一列,每个对应位置数字相乘后再相加。

算数谁都会,但在实际场景中,对应位置的数字需要具备相同的特征含义,比如:红色指数为3 乘以 红色概率20%,这个乘法计算是存在现实的业务含义的,但如果 红色指数为3 乘以 说脏话概率20%,这个计算没有任何意义。

那么,这一堆矩阵、向量、数字计算,每个数字、矩阵的每个位置是否都有可描述的含义?

2,始于混沌

嵌入向量的每一个位置,最开始并没有人工设定特征含义,比如第一位代表颜色红不红,第二位代表好不好等等,并没有这些定义。

嵌入向量的每个值最开始都是随机的,完全是一堆乱码。

各个W权重矩阵的值最开始也是随机的,也是一堆乱码。

3,终于数学

模型训练的目的,就是将嵌入向量的每一个位置(比如第一位)所代表的特征含义,和各个W权重向量的对应位置,所代表的特征含义对齐。虽然对齐完之后这一位代表什么含义我们依然不知道,但如果再来一个新词,我们能知道这个词在各个特征上和前文是否相关。

大模型经过训练,其过程经过了一些反向传播(梯度下降)的操作,相关矩阵(包括嵌入矩阵、H_新,W_KQV矩阵等)以下4个位置的含义将逐渐对齐:

  • 1,嵌入向量的每一位(比如第一个数)所代表的特征含义。
  • 2,H_新的对应位(比如第一个数)所代表的特征含义。
  • 3,token的V向量对应位(比如第一个数)所代表的特征含义。
  • 4,W_V权重矩阵对应的一整列(比如第一列)所代表的特征含义。

注意,即使最后基本对齐了,每个位置的的特征含义还是不知道,只是从数学上对齐了。

而且,如果使用不同种子进行训练,最后都会对齐,每个位置的含义还会不同。

另外有一个特殊情况,上面的第4条:W_V矩阵不是每一位代表一个特征含义,而是每一列代表如何从嵌入向量中提取某一个特征含义的值,这个值代表token和这个特征含义的相关程度。

比如,在模型训练时,最开始,如果输入"苹果好吃",经过计算,得到下一个字是"对"的概率达到了80%,但我们给大模型训练的语料中,可能多数文案都是"苹果好吃是...",即下一个字大概率应该是"是",而不是计算得到的"对",模型算错了,那么大模型会修改权重矩阵的值,使得当用户输入"苹果好吃"时,下一个字是"是"的概率变大一点点,"对"的概率变小一点点。不断重复以上训练过程,大模型就知道各个备选token和不同输入语句的关系远近了。

4,总结

嵌入向量和权重矩阵的每一位,其实是经过不断训练后,模型从海量数据中自动发现的隐式特征(Latent Feature)。

与其纠结具体是什么特征,不如直接提出"轴"的概念,将某一个特征含义(具体是什么不知道)当成一个维度,即"轴",所有相关的计算都是围绕token在"轴"上的位置,以此来判断token之间的相关性。

比如:将用户输入的所有token一起,算出在该轴上的位置,比如是5,所有候选token也在同一轴上计算位置,有的位置是0,有的位置是5.5,那么位置是5.5的那个token更有可能和前文关系紧密,那下一个token大概率就是它了,当然,只是概率较高,不是谁近就必选谁,否则大模型的回答就千篇一律了。

相关推荐
summer_du1 小时前
Qdrant
人工智能·python
doiito(Do It Together)1 小时前
【AI 应用】从“外国人味”到地道中文:kokoroi-rs v0.1.2 架构升级深度解析
人工智能
GuWenyue1 小时前
AI对话打字机效果卡顿崩溃?1套Vue3流式代码搞定逐Token输出,彻底解决断包报错
人工智能
叶总没有会1 小时前
3.2 构建AI智能体项目扩展知识
java·数据库·人工智能·spring·ai
易知微EasyV数据可视化1 小时前
工业制造如何实现柔性规划?数字孪生技术助力产线布局编排与方案推演
人工智能·经验分享·制造·数字孪生·可视化·三维建模
pla888888881 小时前
热词驱动,智辨声纹——从ASR热词到说话人日志的尝试:海光DCU环境部署FunASR热词语音识别系统(说话人日志已集成,含完整代码)
人工智能·语音识别
编程牛马姐1 小时前
并发、多线程和HTTP连接之间有什么关系?
人工智能
羑悻的小杀马特2 小时前
把随身WiFi改成网盘聚合器:中兴F50挂载本地存储+夸克网盘实战
运维·服务器·人工智能·网盘·openlist
meilindehuzi_a2 小时前
从跑分到生产力:重新理解大模型基准测试与分层协作
人工智能