news 2026/3/24 17:23:09

Transformer底层原理—位置编码

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Transformer底层原理—位置编码

transformer中,embedding层位于encoderdecoder之前,主要负责进行语义编码。Embedding层将离散的词汇或符号转换为连续的高维向量,使得模型能够处理和学习这些向量的语义关系。通过嵌入表示,输入的序列可以更好地捕捉到词与词之间的相似性和关系。此外,在输入到编码器和解码器之前,通常还会添加位置编码(Positional Encoding),因为transformer没有内置的序列顺序信息,也就是说Attention机制本身会带来位置信息的丧失

一、位置编码概述

  • 位置信息为什么重要?它可以从哪里来?

首先,位置信息就是顺序的信息,字符排列的顺序会影响语句的理解(还记得“屡战屡败”和“屡败屡战”的例子吗?同样的词在句子不同的地方出现,也可能会有不同的含义),我们说transformer丧失了位置信息,意思是transformer并不理解样本与样本之间是按照什么顺序排列的(也就是不知道样本在序列中具体的位置)。

还记得RNNLSTM是如何处理数据的吗?RNNLSTM以序列的方式处理输入数据,即一个时间步一个时间步地处理输入序列的每个元素。每个时间步的隐藏状态依赖于前一个时间步的隐藏状态。这种机制天然地捕捉了序列的顺序信息。由于RNN和LSTM在处理序列时会保留前一时间步的信息并传递到下一时间步,所以它们能够内在地理解和处理序列的时间依赖关系和顺序信息。然而,与RNN和LSTM不同,transformer并不以序列的方式逐步处理输入数据,而是一次性处理整个序列。Attention能够通过点积的方式一次性计算出所有向量之间的相关性、并且多头注意力机制中不同的头还可以并行,因此Attentiontransformer缺乏天然的顺序信息。

  • 相关性计算过程中有标识,这些标识不能够成为位置信息吗?什么信息才算是位置信息/顺序信息呢?

在注意力机制中,权重矩阵softmax(QKTdk)softmax(\frac{QK^{T}}{\sqrt{d_k}})softmax(dkQKT)中的每个元素aija_{ij}aij表示序列中位置iii和位置jjj之间的相关性,但是却并没有假设这两个相关的元素之间的位置信息。具体来说,虽然我们使用了1、2这样的脚标,但Attention实际在进行计算的时候,只会认知两个具体的相关性数字,并没有显性地认知到脚标——

Z(Attention)=(a11a12a21a22)(v11v12v13v21v22v23)=((a11v11+a12v21)(a11v12+a12v22)(a11v13+a12v23)(a21v11+a22v21)(a21v12+a22v22)(a21v13+a22v23)) \mathbf{Z(Attention)} = \begin{pmatrix} a_{11} & a_{12} \\ a_{21} & a_{22} \end{pmatrix} \begin{pmatrix} v_{11} & v_{12} & v_{13} \\ v_{21} & v_{22} & v_{23} \end{pmatrix} = \begin{pmatrix} (a_{11}v_{11} + a_{12}v_{21}) & (a_{11}v_{12} + a_{12}v_{22}) & (a_{11}v_{13} + a_{12}v_{23}) \\ (a_{21}v_{11} + a_{22}v_{21}) & (a_{21}v_{12} + a_{22}v_{22}) & (a_{21}v_{13} + a_{22}v_{23}) \end{pmatrix}Z(Attention)=(a11a21a12a22)(v11v21v12v22v13v23)=((a11v11+a12v21)(a21v11+a22v21)(a11v12+a12v22)(a21v12+a22v22)(a11v13+a12v23)(a21v13+a22v23))

由于transformer模型放弃了“逐行对数据进行处理”的方式,而是一次性处理一整张表单,因此它不能直接像循环神经网络RNN那样在训练过程中就捕捉到单词与单词之间的位置信息。在经典的深度学习场景当中,最典型的顺序信息就是数字的大小。由于数字天生是带有大小顺序的,因此数字本身可以被认为是含有顺序一个信息,只要让有顺序的信息和有顺序的数字相匹配,就可以让算法天然地认知到相应的顺序。因此我们自然而然地想要对样本的位置本身进行“编码”,利用数字本身自带的顺序来告知transformer

  • 位置信息如何被告知给Attention/transformer这样的算法?

为了解决位置信息的问题,transformer引入了位置编码(positional encoding)技术来补充语义词嵌入。我们首先将样本的位置转变成相应的数字或向量,然后让位置编码的这个向量被加到原有的词嵌入向量embedding向量上,这样模型就可以同时知道一个词的语义和它在句子中的位置。

位置编码使用了一种特殊的函数,这个函数会为序列中的每个位置生成一个向量。对于一个特定的位置,这个函数生成的向量在所有维度上的值都是不同的。这保证了每个位置的编码都是唯一的,而且不同位置的编码能够保持一定的相对关系。transformer的位置编码中,我们需要对每个词的每个特征值给与位置编码,所有这些特征位置的编码共同组合成了一个样本的位置编码。例如,当一个样本拥有4个特征时,我们的位置编码也会是包含4个数字的一个向量,而不是一个单独的编码。因此,位置编码矩阵是一个与embedding后的矩阵结构相同的矩阵

transformer模型中,词嵌入和位置编码被相加,然后输入到模型的第一层。这样,transformer就可以同时处理词语的语义和它在句子中的位置信息。这也是transformer模型在处理序列数据,特别是自然语言处理任务中表现出色的一个重要原因。

二、正余弦位置编码

2.1 正余弦位置编码介绍

在过去最为经典的位置编码就是OrdinalEncoder顺序编码,但在transformer中我们需要的是一个编码向量,而非单一的编码数字,因此OrdinalEncoder编码就不能使用了。在众多的、构成编码向量的方式中,transformer选择了“正余弦编码”这一特别的方式。让我们一起来看看正余弦编码的含义——

首先,正余弦编码是使用正弦函数和余弦函数来生成具体编码值的编码方式。对于任意的词向量(也就是数据中的一个样本),正余弦编码在偶数维度上采用了sin函数来编码,奇数维度采用了cos函数来编码,sin函数与cos函数交替使用,最终构成一个多维度的向量——

通过对不同的维度进行不同的三角函数编码,来构成一串独一无二的编码组合。这种编码组合与embedding类似,都是将信息投射到一个高维空间当中,只不过正余弦编码是将样本的位置信息(也就是样本的索引)投射到高维空间中,且每一个特征的维度代表了这个高维空间中的一维度。对正余弦编码来说,编码数字本身是依赖于样本的位置信息(索引)、所有维度的编号、以及总维度数三个因子计算出来的。

具体来看,正余弦编码的公式如下:

  • 正弦位置编码(Sinusoidal Positional Encoding
    PE(pos,2i)=sin⁡(pos100002idmodel)PE_{(pos, 2i)} = \sin \left( \frac{pos}{10000^{\frac{2i}{d_{\text{model}}}}} \right)PE(pos,2i)=sin(10000dmodel2ipos)

  • 余弦位置编码(Cosine Positional Encoding
    PE(pos,2i+1)=cos⁡(pos100002idmodel) PE_{(pos, 2i+1)} = \cos \left( \frac{pos}{10000^{\frac{2i}{d_{\text{model}}}}} \right)PE(pos,2i+1)=cos(10000dmodel2ipos)

其中——

  • pos代表样本在序列中的位置,也就是样本的索引(是三维度中的seq_len/vocal_size/time_step这个维度上的索引)
  • 2i2i2i2i+12i+12i+1分别代表embedding矩阵中的偶数和奇数维度索引,当我们让i从0开始循环增长时,可以获得[0,1,2,3,4,5,6…]这样的序列。
  • dmodeld_{\text{model}}dmodel代表embedding后矩阵的总维度。

在这里,你可以选择停下脚步、开启下一节课程,你也可以选择继续听更深入的关于位置编码的内容。这里有选择的原因是,位置编码作为深度学习和时间序列处理过程中非常重要的一种技术,在不同的场景下被频繁地使用,我们可以将其用于纹理建模、声音处理、信号处理、震动分析等多种场合,但同时,我们也将它作为一种行业惯例在进行使用,因此你或许无需对正余弦位置编码进行特别深入的探索。

但正余弦位置编码本身是一种非常奇妙的结构,在接下来的内容中,我将带你仔细剖析正余弦位置编码的诸多细节和意义。

2.2 正余弦位置编码意义

为什么要使用正余弦编码?它有什么意义?

  • 正弦位置编码(Sinusoidal Positional Encoding
    PE(pos,2i)=sin⁡(pos100002idmodel)PE_{(pos, 2i)} = \sin \left( \frac{pos}{10000^{\frac{2i}{d_{\text{model}}}}} \right)PE(pos,2i)=sin(10000dmodel2ipos)

  • 余弦位置编码(Cosine Positional Encoding
    PE(pos,2i+1)=cos⁡(pos100002idmodel) PE_{(pos, 2i+1)} = \cos \left( \frac{pos}{10000^{\frac{2i}{d_{\text{model}}}}} \right)PE(pos,2i+1)=cos(10000dmodel2ipos)

首先我们先来看Pos,Pos是样本的索引,它有多大会取决于实际的数据尺寸。如果一个时间序列或文本数据是很长的序列,那Pos数值本身也会变得很大。假设我们使用很大的数值与原本的embedding序列相加,那位置编码带来的影响可能会远远超过原始的语义、会导致喧宾夺主的问题,因此我们天然就有限制位置编码的大小的需求。在这个角度来看,使用sin和cos这样值域很窄的函数、就能够很好地限制位置编码地大小。

正余弦编码的意义①:sin和cos函数值域有限,可以很好地限制位置编码的数字大小。

假设我们使用的是单变量序列,那我们或许只需要sin(pos)或者cos(pos)看起来就足够了,但为了给每个不同的维度都进行编码,我们肯定还要做点儿别的文章。首先,位置信息和语义信息一样,当我们将其投射到高维空间时,我们也在尝试用不同的维度来解读位置信息。但我们使用正弦余弦这样的三角函数时,如何能够将信息投射到不同的维度呢——答案是创造各不相同的sincos函数。虽然都是正弦/余弦函数,但我们可以为函数设置不同的频率来获得各种高矮胖瘦的函数——

importnumpyasnpimportmatplotlib.pyplotasplt# 定义绘制正弦函数的函数defplot_sin_functions(num_functions):y=np.linspace(0,10,1000)# 定义 y 轴范围colors=plt.cm.viridis(np.linspace(0,1,num_functions))# 生成颜色序列fig,ays=plt.subplots(3,3,figsize=(12,9))# 创建3y3子图# 绘制每个正弦函数fori,ayinenumerate(ays.flat):ifi<num_functions:frequency=(i+1)*0.5# 通过增加倍数来调整频率y=np.sin(frequency*y)ay.plot(y,y,label=f'Function{i+1}',color=colors[i])ay.set_title(f'Function{i+1}')ay.set_ylabel('y')ay.set_ylabel('sin(y)')ay.legend()plt.tight_layout()plt.show()# 绘制9个正弦函数plot_sin_functions(9)

如果能够将不同的特征投射到不同频率的sin和cos函数上,就可以让每个特征都投射到一个独特的维度上,各类不同的信息维度共同构成一个解构位置信息的空间,就能够形成对位置信息的深度解读。

正余弦编码的意义②:通过调节频率,我们可以得到多种多样的sin和cos函数,从而可以将位置信息投射到每个维度都各具特色、各不相同的高维空间,以形成对位置信息的更好的表示。

  • 正弦位置编码(Sinusoidal Positional Encoding
    PE(pos,2i)=sin⁡(pos100002idmodel)PE_{(pos, 2i)} = \sin \left( \frac{pos}{10000^{\frac{2i}{d_{\text{model}}}}} \right)PE(pos,2i)=sin(10000dmodel2ipos)

  • 余弦位置编码(Cosine Positional Encoding
    PE(pos,2i+1)=cos⁡(pos100002idmodel) PE_{(pos, 2i+1)} = \cos \left( \frac{pos}{10000^{\frac{2i}{d_{\text{model}}}}} \right)PE(pos,2i+1)=cos(10000dmodel2ipos)

接下来的问题就是如何赋予sin和cos函数不同的频率了——在sin和cos函数的自变量上乘以不同的值,就可以获得不同频率的sin和cos函数。

y=sin(frequency∗y)y = sin(frequency * y)y=sin(frequencyy)

在位置编码的场景下,我们的自变量是样本的位置pos,因此特征的位置(2i和2i+1)就可以被用来创造不同的频率。在这里,我们对pos这个数字进行了scaling(压缩)的行为。具体地说,我们使用了100002idmodel10000^{\frac{2i}{d_{\text{model}}}}10000dmodel2i来作为我们缩放的因子,将它作为除数放在pos的下方。但这其实是在pos的基础上乘以1100002idmodel\frac{1}{10000^{\frac{2i}{d_{\text{model}}}}}10000dmodel2i1这个频率的行为。因此,引入特征位置本身来进行缩放可以带来不同的频率,帮助我们将位置信息pos投射不同频率的三角函数上,确保不同位置(pos)在不同的特征维度(2i和2i+1)上有不同的编码值。

那下一个问题是,这些正余弦函数的频率是随机的吗?我们应该如何控制它呢?正余弦编码最为巧妙的地方来了——通过让位置信息pos乘以1100002idmodel\frac{1}{10000^{\frac{2i}{d_{\text{model}}}}}10000dmodel2i1这个频率,特征编号比较小的特征会得到大频率,会被投射到高频率的正弦函数上,而特征编号较大的特征会得到小频率,会被投射到低频率的正弦函数上👇

importnumpyasnpimportmatplotlib.pyplotasplt# 设置参数d_model=512i=np.arange(0,512)# 维度索引从0到20# 绘制图像plt.figure(figsize=(14,8))forposinpos_values:values=1/(10000**(2*i/d_model))plt.plot(i,values,label=f'pos={pos}')plt.title('i vs 1 / (10000^(2i/d_model))')plt.ylabel('feature_indey')plt.ylabel('1 / (10000^(2i/d_model))')plt.legend()plt.grid(True)plt.show()

在这张图像上,横坐标是特征的位置编号i,纵坐标是1100002idmodel\frac{1}{10000^{\frac{2i}{d_{\text{model}}}}}10000dmodel2i1,很显然特征编号越大频率越小。对三角函数来说,频率越小意味着当自变量移动1个单位时,函数值变化越小;频率越高,当自变量移动1个单位时,函数值变化就越剧烈。

importnumpyasnpimportmatplotlib.pyplotasplt# 定义绘制正弦函数的函数defplot_sin_functions():y=np.linspace(0,10,1000)# 定义 y 轴范围fig,ays=plt.subplots(1,2,figsize=(12,6))# 创建1y2子图# 绘制频率为1的正弦函数frequency1=1y1=np.sin(frequency1*y)ays[0].plot(y,y1,label=f'Sin Function (Frequency ={frequency1})')ays[0].set_title(f'Sin Function with Frequency ={frequency1}')ays[0].set_ylabel('y')ays[0].set_ylabel('sin(y)')ays[0].legend()# 绘制频率为0.1的正弦函数frequency2=0.1y2=np.sin(frequency2*y)ays[1].plot(y,y2,label=f'Sin Function (Frequency ={frequency2})')ays[1].set_title(f'Sin Function with Frequency ={frequency2}')ays[1].set_ylabel('y')ays[1].set_ylabel('sin(y)')ays[1].legend()plt.tight_layout()plt.show()# 绘制两个正弦函数在横向排列的子图中plot_sin_functions()

因此,这里你就可以发现非常有趣的事实了——特征编号小的特征,会随着特征值的变化而产生剧烈的变化,即便是相邻的两个样本,在最初的几个特征进行位置编码时,也会产生迥然不同的结果,但是随着特征编号的变大,特征值的变化带来的变化会越来越小,并且会小到呈现出一种单调性(只上升、或者只下降)。当一个信息被映射到这样的高维空间时,我们会认为这个信息的全局趋势和局部细节都被捕捉到了。其中,特征编号比较大的那些维度捕捉到的是样本与样本之间按顺序排列的全局趋势,而特征编号比较小的那些维度捕捉到的是样本与样本的位置之间本身的细节差异。因此,正余弦编码是一种能够同时捕捉到全局位置趋势和细节位置差异的编码方式。

正余弦编码的意义③:通过独特的计算公式,我们可以让特征编号小的特征被投射到剧烈变化的维度上,并且让特征编号大的特征被投射到轻微变化、甚至完全单调的维度上,从而可以让小编号特征去捕捉样本之间的局部细节差异,让大编号特征去捕捉样本之间按顺序排列的全局趋势。

从这个角度来看,其实我们只需要设置一个随着i的增长变得越来越小的公式就可以了,实际公式本身其实并不一定非要是1100002idmodel\frac{1}{10000^{\frac{2i}{d_{\text{model}}}}}10000dmodel2i1。但这个公式考虑了i相对于特征总量的相对位置,并且还使用了指数函数,它是能够最大程度放大i的影响的公式之一,因此我们使用它可以说是出于一种数学上的便利。当然,你也可以使用其他的公式,只要能够保证i的增长会让频率本身变得越来越小即可。

现在我们可以来看一个具体例子,通过绘制图像来让大家清晰地看到,正余弦编码是如何帮助我们捕捉局部细节和总体趋势的。假设现在有30个样本(索引为1-30),每个样本有4个特征。我们将使用正弦函数编码偶数维度,使用余弦函数编码奇数维度,进行正余弦编码的具体计算。

  • 正弦位置编码(Sinusoidal Positional Encoding
    PE(pos,2i)=sin⁡(pos100002idmodel)PE_{(pos, 2i)} = \sin \left( \frac{pos}{10000^{\frac{2i}{d_{\text{model}}}}} \right)PE(pos,2i)=sin(10000dmodel2ipos)

  • 余弦位置编码(Cosine Positional Encoding
    PE(pos,2i+1)=cos⁡(pos100002idmodel) PE_{(pos, 2i+1)} = \cos \left( \frac{pos}{10000^{\frac{2i}{d_{\text{model}}}}} \right)PE(pos,2i+1)=cos(10000dmodel2ipos)

我请GPT帮我完成了相应的计算流程,最终生成了如下的表单👇

importpandasaspd position=pd.read_csv(r"D:\pythonwork\2024DL\Position_Encoding_for_30_Samples.csv")
position
维度0维度1维度2维度3
00.8414710.5403020.0100000.999950
10.909297-0.4161470.0199990.999800
20.141120-0.9899920.0299960.999550
3-0.756802-0.6536440.0399890.999200
4-0.9589240.2836620.0499790.998750
5-0.2794150.9601700.0599640.998201
60.6569870.7539020.0699430.997551
70.989358-0.1455000.0799150.996802
80.412118-0.9111300.0898790.995953
9-0.544021-0.8390720.0998330.995004
10-0.9999900.0044260.1097780.993956
11-0.5365730.8438540.1197120.992809
120.4201670.9074470.1296340.991562
130.9906070.1367370.1395430.990216
140.650288-0.7596880.1494380.988771
15-0.287903-0.9576590.1593180.987227
16-0.961397-0.2751630.1691820.985585
17-0.7509870.6603170.1790300.983844
180.1498770.9887050.1888590.982004
190.9129450.4080820.1986690.980067
200.836656-0.5477290.2084600.978031
21-0.008851-0.9999610.2182300.975897
22-0.846220-0.5328330.2279780.973666
23-0.9055780.4241790.2377030.971338
24-0.1323520.9912030.2474040.968912
250.7625580.6469190.2570810.966390
260.956376-0.2921390.2667310.963771
270.270906-0.9626060.2763560.961055
28-0.663634-0.7480580.2859520.958244
29-0.9880320.1542510.2955200.955336
position.may()
维度00.990607维度10.991203维度20.295520维度30.999950dtype: float64
position.min()
维度0 -0.999990 维度1 -0.999961 维度20.010000维度30.955336dtype: float64

在这个表单中,有4个特征全部进行正余弦编码后的结果,很显然,特征编号较小的特征(1和2特征)波动很大,但是特征编号相对较大的特征(3和4)波动就不是那么大。我们只计算了4个特征,是因为我们要绘制的3d图像只能够容纳3个特征,事实上当特征数量变得很多时,大部分特征都会呈现像特征3和特征4一样这样平缓的变化方式。

为了展现局部特征和整体趋势的捕捉,我们使用特征2、3、4来绘制了3D图像,在图像中,我们可以明显地看到局部细节和总体趋势的捕捉👇

importplotly.graph_objsasgoimportpandasaspd# 数据importpandasaspd position=pd.read_csv(r"D:\pythonwork\2024DL\Position_Encoding_for_30_Samples.csv")# 绘制3D散点图fig=go.Figure(data=[go.Scatter3d(x=position['维度1'],y=position['维度2'],z=position['维度3'],mode='markers',marker=dict(size=6,color=position['维度3'],# 设置颜色为维度3colorscale='Viridis',# 颜色范围opacity=1),text=position.index.tolist(),# 添加样本编号作为文本标签textposition='top center')])fig.update_layout(title='3D Scatter Plot',scene=dict(xaxis=dict(title='维度1',range=[-1.5,1.5]),yaxis=dict(title='维度2',range=[0,0.3]),zaxis=dict(title='维度3',range=[0.95,1])),width=800,# 调整图像宽度height=800# 调整图像高度)fig.show()

但除此之外,正余弦编码还有一些额外的好处——

  • 首先最重要的是其函数的周期性带来泛化性:在模型训练过程中,我们可能使用的都是序列长度小于20的数据,但是当实际应用中遇到一个序列长度为50的数据,正弦和余弦函数的周期性意味着,即使模型在训练时未见过某个位置,它仍然可以生成一个合理的位置编码。它可用泛化到不同长度的序列。

  • 不增加额外的训练参数:当我们在一个已经很大的模型(如 GPT-3 或 BERT)上添加位置信息时,我们不希望增加太多的参数,因为这会增加训练成本和过拟合的风险。正弦和余弦位置编码不增加任何训练参数。

  • 即便是相同频率下的正余弦函数,也可以通过周期性带来部分的相对位置信息,可以比绝对位置信息更有效:正弦和余弦函数的周期性特征为模型提供了一种隐含的相对位置信息,使得模型能够更有效地理解序列中不同位置之间的相对关系。

importnumpyasnpimportmatplotlib.pyplotasplt# 定义绘制正弦函数的函数defplot_sin_functions():y=np.linspace(0,10,1000)# 定义 y 轴范围fig,ays=plt.subplots(1,2,figsize=(12,6))# 创建1y2子图# 绘制频率为1的正弦函数frequency1=1y1=np.sin(frequency1*y)ays[0].plot(y,y1,label=f'Sin Function (Frequency ={frequency1})')ays[0].set_title(f'Sin Function with Frequency ={frequency1}')ays[0].set_ylabel('y')ays[0].set_ylabel('sin(y)')ays[0].legend()# 绘制频率为0.1的正弦函数frequency2=0.1y2=np.sin(frequency2*y)ays[1].plot(y,y2,label=f'Sin Function (Frequency ={frequency2})')ays[1].set_title(f'Sin Function with Frequency ={frequency2}')ays[1].set_ylabel('y')ays[1].set_ylabel('sin(y)')ays[1].legend()plt.tight_layout()plt.show()# 绘制两个正弦函数在横向排列的子图中plot_sin_functions()

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/15 14:37:41

Docker部署Qwen3-14B:GPU加速与生产实践

Docker部署Qwen3-14B&#xff1a;GPU加速与生产实践 在AI从实验室走向产线的今天&#xff0c;一个现实问题摆在每个技术团队面前&#xff1a;为什么本地跑得飞快的大模型&#xff0c;一上服务器就“罢工”&#xff1f; 显存爆了、CUDA版本对不上、依赖包冲突……这些问题根本不…

作者头像 李华
网站建设 2026/3/22 17:01:04

无障碍测试WCAG标准实施:构建包容性数字产品的关键路径

在当今数字化时代&#xff0c;软件的可访问性已成为衡量产品成功的重要指标之一。作为软件测试从业者&#xff0c;掌握并实施Web内容无障碍指南&#xff08;WCAG&#xff09;标准&#xff0c;不仅能确保产品符合法规要求&#xff0c;更能推动社会包容性发展。WCAG标准由万维网联…

作者头像 李华
网站建设 2026/3/23 17:23:16

字符串计数匹配 (Python JAVA C++ JS C)

题目描述 给你一个字符串str和整数k&#xff0c;返回满足以下条件的所有子字符串个数&#xff1a; 恰好包含k个字母。数字0-9各出现至少一次。 输入描述 第一行字符串str(1≤ length ≤ 100000),仅包含数字和小写字母第二行为整数k(0 ≤ k ≤100000 ) 输出描述 输出一个整…

作者头像 李华
网站建设 2026/3/23 8:39:00

LangFlow与云原生GPU资源调度平台集成方案

LangFlow与云原生GPU资源调度平台集成方案 在AI应用开发日益复杂的今天&#xff0c;一个现实问题摆在每个团队面前&#xff1a;如何让非专业开发者也能高效参与大模型智能体的设计&#xff0c;同时又能充分利用昂贵的GPU资源而不造成浪费&#xff1f;传统的LangChain代码开发模…

作者头像 李华
网站建设 2026/3/14 7:33:52

技术干货丨AI 大模型微调到底是什么?一篇通俗文帮你弄明白

什么是微调? 微调就是在已经训练好的大模型基础上&#xff0c;用你自己的数据继续训练&#xff0c;让模型更符合你的特定需求。CPT(ContinualPre-Training)继续预训练最基础的微调方式。你拿到一个预训练好的模型&#xff0c;然后用大量无标签的文本数据继续训练它。 SFT(Supe…

作者头像 李华
网站建设 2026/3/23 13:16:19

LobeChat与HTML5技术融合打造跨平台AI应用

LobeChat与HTML5技术融合打造跨平台AI应用 在智能对话系统日益普及的今天&#xff0c;用户不再满足于“能用”的聊天机器人——他们期待的是流畅、自然、无处不在的交互体验。无论是通过手机语音提问&#xff0c;还是在办公室电脑上查阅历史会话&#xff0c;甚至在网络不稳定的…

作者头像 李华