【NLP】注意力机制

目录

一、认识注意力机制

1.1 常见注意力计算规则

1.2 注意力机制的作用

1.3 注意力机制代码实现

二、注意力机制原理

2.1 attention计算过程 

2.2 attention的计算逻辑

2.3 有无attention模型对比

2.3.1 无attention机制的模型

2.3.2 有attention机制的模型

三、Self-attention

3.1 认识Self-attention

3.2 Self-attention 和 attention 的使用方法

3.3 Self-attention 机制代码实现


一、认识注意力机制

人类观察事物时,之所以能够快速判断一种事物(当然允许判断是错误的),是因为大脑能够很快把注意力放在事物最具有辨识度的部分从而作出判断,而并非是从头到尾的观察一遍事物后,才能有判断结果。正是基于这样的理论,就产生了注意力机制

需要三个指定的输入Q(query)、K(key)、V(value),然后通过计算公式得到注意力的结果,这个结果代表query在key和value作用下的注意力表示。当输入的Q=K=V时,称作自注意力计算规则

假如有一个问题:给出一段文本,使用一些关键词对其进行描述为了方便统一正确答案,这道题可能预先已经写出了一些关键词作为提示。这些给出的提示就可看作是key,而整个的文本信息就相当于是query,value的含义则更抽象,可以比作是看到这段文本信息后,脑中浮现的答案信息这里假设大家最开始都不是很聪明,第一次看到这段文本后脑子里基本上浮现的信息就只有提示的信息,因此key与value基本是相同的,但是随着对这个问题的深入理解,通过思考脑子里想起来的东西原来越多,并且能够开始对query,提取关键信息进行表示。这就是注意力作用的过程,通过这个过程,最终脑子里的value发生了变化,根据提示key生成了query的关键词表示方法,也就是另外一种特征表示方法刚刚说到key和value一般情况下默认是相同,与query是不同的,这种是一般的注意力输入形式。但有一种特殊情况,就是query与key和value相同,这种情况称为自注意力机制。就如上面的例子,使用一般注意力机制,是使用不同于给定文本的关键词表示它。而自注意力机制需要用给定文本自身来表达自己,即需要从给定文本中抽取关键词来表述自己, 相当于对文本自身的一次特征提取

1.1 常见注意力计算规则

  • 将Q,K进行纵轴拼接,做一次线性变化,再使用softmax处理,最后与V做张量乘法

  • 将Q,K进行纵轴拼接,做一次线性变化后再使用tanh函数激活,然后再进行内部求和,最后使用softmax处理,再与V做张量乘法

  • Q与K的转置做点积运算,然后除以一个缩放系数,再使用softmax处理,最后与V做张量乘法

注意:当注意力权重矩阵和V都是三维张量且第一维代表为batch条数时,则做bmm运算。bmm是一种特殊的张量乘法运算

import torchinputs = torch.randn(10, 3, 4)
weights = torch.randn(10, 4, 5)
result = torch.bmm(inputs, weights)
print(result.size())
# torch.Size([10, 3, 5])

1.2 注意力机制的作用

注意力机制是注意力计算规则能够应用的深度学习网络的载体,同时包括一些必要的全连接层以及相关张量处理,使其与应用网络融为一体。使用自注意力计算规则的注意力机制称为自注意力机制

NLP领域中,当前的注意力机制大多数应用于seq2seq架构,即编码器和解码器模型

  • 解码器端的注意力机制:能够根据模型目标有效的聚焦编码器的输出结果,当其作为解码器的输入时提升效果,改善以往编码器输出是单一定长张量,无法存储过多信息的情况
  • 编码器端的注意力机制:主要解决表征问题,相当于特征提取过程,得到输入的注意力表示,一般使用自注意力(self-attention)

1.3 注意力机制代码实现

  • 第一步:根据注意力计算规则,对Q,K,V进行相应的计算
  • 第二步:根据第一步采用的计算方法。若是拼接方法,则需将Q与第二步的计算结果再进行拼接;若是转置点积,一般是自注意力,Q与V相同,则不需要进行与Q的拼接
  • 第三步:最后为了使整个attention机制按照指定尺寸输出使用,线性层作用在第二步的结果上做一个线性变换,得到最终对Q的注意力表示
import torch
import torch.nn as nnclass attention(nn.Module):def __init__(self, query_size, key_size, value_size1, value_size2, output_size):super(attention, self).__init__()self.query_size = query_sizeself.key_size = key_sizeself.value_size1 = value_size1self.value_size2 = value_size2self.output_size = output_sizeself.line1 = nn.Linear(self.query_size + key_size, self.value_size1)self.line2 = nn.Linear(self.query_size + value_size2, self.output_size)def forward(self, Q, K, V):attention_weight = torch.softmax(self.line1(torch.cat((Q[0], K[0]), 1)), dim=1)# check shapeprint(Q[0].shape, K[0].shape, (torch.cat((Q[0], K[0]), 1)).shape)# torch.Size([1, 32]) torch.Size([1, 32]) torch.Size([1, 64])print(self.line1(torch.cat((Q[0], K[0]), 1)).shape)# torch.Size([1, 32])print(attention_weight.shape)# torch.Size([1, 32])attention_applied = torch.bmm(attention_weight.unsqueeze(0), V)# check shapeprint(attention_weight.unsqueeze(0).shape)# torch.Size([1, 1, 32])print(attention_applied.shape)# torch.Size([1, 1, 64])output = torch.cat((Q[0], attention_applied[0]), 1)# check shapeprint(output.shape)# torch.Size([1, 96])output = self.line2(output).unsqueeze(0)# check shapeprint(output.shape)# torch.Size([1, 1, 64])return output, attention_weightdef main():query_size = 32key_size = 32value_size1 = 32value_size2 = 64output_size = 64attn = attention(query_size, key_size, value_size1, value_size2, output_size)# (batch_size, seq_len, hidden_size)# 批量数, 输入序列长度, 每个词向量的维度Q = torch.randn(1, 1, 32)K = torch.randn(1, 1, 32)V = torch.randn(1, 32, 64)out, weights = attn(Q, K ,V)print(out)print(weights)if __name__ == "__main__":main()# tensor([[[ 0.0659, -0.2032, -0.1200,  0.3103,  0.1267, -0.2573,  0.0595,
#           -0.3809,  0.6900,  0.5539, -0.1737, -0.3153,  0.7032, -0.6192,
#           -0.0120,  0.4132,  0.1484,  0.3911, -0.0876,  0.3548, -0.2247,
#           -0.3236,  0.2761, -0.1817, -0.2472, -0.3050,  0.4670,  0.3442,
#           -0.0092,  0.5283,  0.0881,  0.2219, -0.7051, -0.0028,  0.5049,
#            0.7083, -0.2809,  0.3218, -0.3225,  0.1372,  0.3596,  0.0069,
#           -0.1422, -0.0494,  0.4049, -0.0856,  0.5200, -0.0793, -0.0608,
#           -0.0135,  0.3282, -0.6138,  0.0643, -0.6000, -0.1060,  0.4633,
#            0.1958, -0.2890,  0.3448, -0.2266,  0.1201,  0.3016,  0.7245,
#            0.2607]]], grad_fn=<UnsqueezeBackward0>)
# tensor([[0.0564, 0.0397, 0.0270, 0.0137, 0.0302, 0.0242, 0.0452, 0.0154, 0.0244,
#          0.0204, 0.0363, 0.0151, 0.0079, 0.0592, 0.0556, 0.0196, 0.0188, 0.1013,
#          0.0348, 0.0679, 0.0289, 0.0183, 0.0196, 0.0123, 0.0113, 0.0516, 0.0051,
#          0.0378, 0.0405, 0.0109, 0.0426, 0.0080]], grad_fn=<SoftmaxBackward0>)

二、注意力机制原理

2.1 attention计算过程 

  • 阶段一:query 和 key 进行相似度计算,得到一个query 和 key 相关性的分值
  • 阶段二:将这个分值进行归一化(softmax),得到一个注意力的分布
  • 阶段三:使用注意力分布和 value 进行计算,得到一个融合注意力的更好的 value 值

机器翻译中,会使用 seq2seq 的架构,每个时间步从词典里生成一个翻译结果。如下图:

在没有注意力之前,每次都是根据 Encoder 部分的输出结果来进行生成,提出注意力后,就是想在生成翻译结果时并不是看 Encoder 中所有的输出结果,而是先来看看想生成的这部分和哪些单词可能关系会比较大,关系大的多借鉴些,关系小的少借鉴些

  • 为了生成单词,把 Decoder 部分输入后得到的向量作为 query;把 Encoder 部分每个单词的向量作为 key。先把 query 和每一个单词进行点乘 score = query⋅key,得到相关性的分值
  • 有了这些分值后,对这些分值做一个softmax,得到一个注意力的分布
  • 有了这个注意力,就可以用其和 Encoder 的输出值 (value) 进行相乘,得到一个加权求和后的值,这个值就包含注意力的表示,用来预测要生成的词

2.2 attention的计算逻辑

attention 并不是只有这一种计算方式,后来还有很多人找到了各种各样的计算注意力的方法。比如上面介绍的三种计算规则,但是从本质上都遵循着这个三步走的逻辑

  • query 和 key 进行相似度计算,得到一个query 和 key 相关性的分值
  • 将这个分值进行归一化(softmax),得到一个注意力的分布
  • 使用注意力分布和 value 进行计算,得到一个融合注意力的更好的 value 值

2.3 有无attention模型对比

2.3.1 无attention机制的模型

文本处理领域的 Encoder-Decoder 框架可以这么直观地去理解:可以把其看作适合处理由一个句子(或篇章)生成另外一个句子(或篇章)的通用处理模型。对于句子对,目标是给定输入句子Source,期待通过 Encoder-Decoder 框架来生成目标句子Target。Source 和 Target 可以是同一种语言,也可以是两种不同的语言。而Source和Target分别由各自的单词序列构成

encoder 是对输入句子Source进行编码,将输入句子通过非线性变换转化为中间语义表示C

对于解码器 Decoder,其任务是根据句子Source的中间语义表示C和之前已经生成的历史信息y_{1}y_{2}...y_{i-1}来生成 i 时刻要生成的单词y_{i}

上述图中展示的 Encoder-Decoder 框架是没有体现出"注意力模型"的,可以将其看作是注意力不集中的分心模型。为什么说其注意力不集中呢?观察下目标句子Target中每个单词的生成过程如下:

其中 f 是Decoder的非线性变换函数。从这里可以看出,在生成目标句子的单词时,不论生成哪个单词,使用的输入句子Source的语义编码C都是一样的,没有任何区别

每个 y_{i} 都依次这么产生,那么看起来就是整个系统根据输入句子Source生成了目标句子Target。若Source是中文句子,Target是英文句子,那么这就是解决机器翻译问题的 Encoder-Decoder 框架;若Source是一篇文章,Target是概括性的几句描述语句,那么这是文本摘要的 Encoder-Decoder 框架;若Source是一句问句,Target是一句回答,那么这是问答系统或者对话机器人的 Encoder-Decoder 框架

存在问题

语义编码C是由句子Source的每个单词经过 Encoder 编码产生的,这意味着不论是生成哪个单词,其实句子Source中任意单词对生成某个目标单词 y_{i} 来说影响力都是相同的,类似于人类看到眼前的画面,但是眼中却没有注意焦点一样

2.3.2 有attention机制的模型

假设在机器翻译中,比如输入的是英文句子:Tom chase Jerry。Encoder-Decoder框架逐步生成中文单词:"汤姆","追逐","杰瑞"。在翻译"杰瑞"这个中文单词的时候,分心模型里面的每个英文单词对于翻译目标单词"杰瑞"贡献是相同的,显然"Jerry"对于翻译成"杰瑞"更重要,但是分心模型是无法体现这一点的

没有引入注意力的模型在输入句子比较短的时候问题不大,但若输入句子比较长,此时所有语义完全通过一个中间语义向量来表示,单词自身的信息已经消失,可想而知会丢失很多细节信息,这也是为何要引入注意力模型的重要原因

上面的例子中,若引入Attention模型的话,应该在翻译"杰瑞"时,体现出英文单词对于翻译当前中文单词不同的影响程度,比如给出类似下面一个概率分布值:(Tom,0.3)(Chase,0.2) (Jerry,0.5)。每个英文单词的概率代表了翻译当前单词"杰瑞"时,注意力分配模型分配给不同英文单词的注意力大小。这对于正确翻译目标语单词肯定是有帮助的,因为引入了新的信息

同理,目标句子中的每个单词都应该学会其对应的源语句子中单词的注意力分配概率信息。这意味着在生成每个单词的时候,原先都是相同的中间语义表示C会被替换成根据当前生成单词而不断变化的。即由固定的中间语义表示C换成了根据当前输出单词来调整成加入注意力模型的变化的。增加了注意力模型的Encoder-Decoder框架理解起来如下图所示:

即生成目标句子单词的过程成了下面的形式:

而每个 C_{i} 可能对应着不同的源语句子单词的注意力分配概率分布

f2 函数代表 Encoder 对输入英文单词的某种变换函数,比如若Encoder是用的RNN模型的话,这个 f2 函数的结果往往是某个时刻输入后隐层节点的状态值;g 代表 Encoder 根据单词的中间表示合成整个句子中间语义表示的变换函数,一般的做法中,g函数就是对构成元素加权求和,如下:

Lx代表输入句子Source的长度,a_{ij} 代表在 Target 输出第 i 个单词时 Source 输入句子中的第 j 个单词的注意力分配系数,而 h_{j} 则是 Source 输入句子中第 j 个单词的语义编码

假设 C_{i} 下标 i 就是上面例子所说的"汤姆",那么Lx就是3,h1=f('Tom'),h2=f('Chase'),h3=f('jerry') 分别输入句子每个单词的语义编码,对应的注意力模型权值则分别是0.6、0.2、0.2, 所以 g 函数本质上就是加权求和函数。翻译中文单词"汤姆"时,数学公式对应的中间语义表示 C_{i} 的形成过程类似下图:

三、Self-attention

3.1 认识Self-attention

Self-attention 就本质上是一种特殊的 attention。这种应用在transformer中最重要的结构之一。attention机制能够找到子序列和全局的attention的关系,即找到权重值w_{i}。Self-attention 相对于 attention 的变化,其实就是寻找权重值w_{i}过程不同

为了能够产生输出的向量y_{i},self-attention 其实是对所有的输入做了一个加权平均的操作,这个公式和上面的attention是一致的

j 代表整个序列的长度,并且 j 个权重的相加之和等于1。值得一提的是,w_{ij} 并不是一个需要神经网络学习的参数,是来源于 x_{i} 和 x_{j} 的之间的计算的结果(w_{ij} 的计算发生了变化)。最简单的一种计算方式,就是使用点积的方式

x_{i} 和 x_{j} 是一对输入和输出。对于下一个输出的向量y_{i+1},有一个全新的输入序列和一个不同的权重值。这个点积的输出的取值范围在负无穷和正无穷之间,所以要使用一个 softmax 将其映射到[0,1]之间,且确保对于整个序列而言和为1

3.2 Self-attention 和 attention 的使用方法

  • 在神经网络中,通常来说会有输入层(input),应用激活函数后的输出层(output),在RNN当中会有状态(state)。若 attention (AT) 被应用在某一层的话,更多的是被应用在输出或者是状态层上,而使用self-attention(SA),这种注意力的机制更多的实在关注 input 上
  • Attention (AT) 经常被应用在从编码器(encoder)转换到解码器(decoder)。如:解码器的神经元会接受一些 AT 从编码层生成的输入信息。在这种情况下,AT 连接的是 "两个不同的组件"(component),编码器和解码器。但是若用 SA,就不是关注的两个组件,只是在关注应用的一个组件。那这里就不会去关注解码器了,就比如说在Bert中,就没有解码器
  • SA 可以在一个模型当中被多次的、独立的使用(如:Transformer中使用了18次,Bert中使用12次)。但是,AT在一个模型当中经常只是被使用一次,并且起到连接两个组件的作用
  • SA比较擅长在一个序列中,寻找不同部分之间的关系。如:在词法分析的过程中,能够帮助去理解不同词之间的关系。AT却更擅长寻找两个序列之间的关系,如:翻译任务中,原始的文本和翻译后的文本。注意:在翻译任务重,SA也很擅长,如Transformer
  • AT 可以连接两种不同的模态,如:图片和文字。SA更多的是被应用在同一种模态上,但是若一定要使用SA,也可以将不同的模态组合成一个序列,再使用SA
  • 其实大部分情况,SA 这种结构更加的普遍,在很多任务作为降维、特征表示、特征交叉等功能尝试着应用,很多时候效果都不错

3.3 Self-attention 机制代码实现

import torch# 准备输入
datas = [[1,0,1,1],[0,2,0,2],[1,1,1,1]]
inputs = torch.tensor(datas, dtype=torch.float32)# 初始化参数
key_weights = [[0, 0, 1],[1, 1, 0],[0, 1, 0],[1, 1, 0]]
query_weights = [[1, 0, 1],[1, 0, 0],[0, 0, 1],[0, 1, 1]]
value_weights = [[0, 2, 0],[0, 3, 0],[1, 0, 3],[1, 1, 0]]
key_weights = torch.tensor(key_weights, dtype=torch.float32)
query_weights = torch.tensor(query_weights, dtype=torch.float32)
value_weights = torch.tensor(value_weights, dtype=torch.float32)# 获取key、value、query
keys = inputs @ key_weights
querys = inputs @ query_weights
values = inputs @ value_weights
print("Keys: \n", keys)
print("Querys: \n", querys)
print("Values: \n", values)# 计算 attention score(假设缩放系数为1)
attntion_scores = querys @ keys.T
print(attntion_scores)
# 计算softmax
attntion_scores_softmax = torch.softmax(attntion_scores, dim=-1)
print(attntion_scores_softmax)# value乘attntion_scores_softmax
weighted_values = values[:,None] * attntion_scores_softmax.T[:,:,None]
print(weighted_values)
# 给value加权求和获取output
outputs = weighted_values.sum(dim=0)
print(outputs)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/23640.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring Boot 整合 Druid 并开启监控

文章目录 1. 引言2. 添加依赖3. 配置数据源4. 开启监控功能5. 自定义 Druid 配置&#xff08;可选&#xff09;6. 访问监控页面7. 注意事项8. 总结 Druid 是一个由阿里巴巴开源的高性能数据库连接池&#xff0c;它不仅提供了高效的连接管理功能&#xff0c;还自带了强大的监控…

红帽7基于kickstart搭建PXE环境

Kickstart 文件是一种配置文件&#xff0c;用于定义 Linux 系统安装过程中的各种参数&#xff0c;如分区、网络配置、软件包选择等。system-config-kickstart 提供了一个图形界面&#xff0c;方便用户快速生成这些配置文件。 用户可以通过图形界面进行系统安装的详细配置&…

C/C++跳动的爱心

系列文章 序号直达链接1C/C李峋同款跳动的爱心2C/C跳动的爱心3C/C经典爱心4C/C满屏飘字5C/C大雪纷飞6C/C炫酷烟花7C/C黑客帝国同款字母雨8C/C樱花树9C/C奥特曼10C/C精美圣诞树11C/C俄罗斯方块小游戏12C/C贪吃蛇小游戏13C/C孤单又灿烂的神14C/C闪烁的爱心15C/C哆啦A梦16C/C简单…

MongoDB 简介

MongoDB 是一种高性能、开源的 NoSQL 数据库&#xff0c;以其灵活的文档模型和强大的扩展性而闻名。 1.MongoDB 是什么 MongoDB 是一种 NoSQL 数据库&#xff0c;采用 文档模型 存储数据&#xff0c;支持灵活的 JSON 格式文档。它无需预定义表结构&#xff0c;能够动态调整数据…

记录首次安装远古时代所需的运行环境成功npm install --save-dev node-sass

最开始的报错&#xff1a; 最后根据报错一步步 安装所需要的pythong之类的环境&#xff0c;最后终于成功了&#xff0c;得以让我在github上拉的vuehr项目&#xff08;狗头18年还是20年的远古项目&#xff09;成功本地运行&#xff0c;最后附上本地运行成功的贴图。如果大家也在…

华为guass在dbever和springboot配置操作

下面记录华为guass在dbever和springboot配置操作&#xff0c;以备忘。 1、安装dbeaver-ce-23.2.0-x86_64-setup.exe和驱动程序 Download | DBeaver Community 2、配置高斯数据库驱动 3、新建数据库连接 4、操作指引 opengauss官方文档 https://docs-opengauss.osinfra.cn/zh…

今日运维之-Mac笔记本python环境问题

1. 问题&#xff1a;MAC升级系统后git报错&#xff1f; Error: Cant create update lock in /usr/local/var/homebrew/locks! Fix permissions by running:sudo chown -R $(whoami) /usr/local/var/homebrew Traceback (most recent call last):11: from /usr/local/Homebrew/…

c3p0、Druid连接池+工具类 Apache-DbUtils (详解!!!)

数据库连接池是在应用程序启动时创建一定数量的数据库连接&#xff0c;并将这些连接存储在池中。当应用程序需要与数据库通信时&#xff0c;它可以向池中请求一个连接&#xff0c;使用完后将连接归还给池&#xff0c;而不是关闭连接。这样可以减少创建和关闭连接的开销&#xf…

数仓搭建实操(传统数仓oracle):DWD数据明细层

数据处理思路 DWD层, 数据明细层>>数据清洗转换, 区分事实表,维度表 全是事实表,没有维度表>>不做处理 数据清洗>>数据类型varchar 变成varchar2, 日期格式统一(时间类型变成varchar2); 字符数据去空格 知识补充: varchar 存储定长字符类型 ; 存储的数据会…

2.1 第一个程序:从 Hello World 开始

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 同大多数编程语言教程一样&#xff0c;本书第一个代码也是输出&#xff1a;Hello world! 这似乎也是惯例。我们也先从这个简单的代码…

2025年02月21日Github流行趋势

项目名称&#xff1a;source-sdk-2013 项目地址url&#xff1a;https://github.com/ValveSoftware/source-sdk-2013项目语言&#xff1a;C历史star数&#xff1a;7343今日star数&#xff1a;929项目维护者&#xff1a;JoeLudwig, jorgenpt, narendraumate, sortie, alanedwarde…

【WSL2】 Ubuntu20.04 GUI图形化界面 VcXsrv ROS noetic Vscode 配置

【WSL2】 Ubuntu20.04 GUI图形化界面 VcXsrv ROS noetic Vscode 配置 前言整体思路安装 WSL2Windows 环境升级为 WIN11 专业版启用window子系统及虚拟化 安装WSL2通过 Windows 命令提示符安装 WSL安装所需的 Linux 发行版&#xff08;如 Ubuntu 20.04&#xff09;查看和设置 WS…

7.建立文件版题库|编写model文件|使用boost split字符串切分(C++)

建立文件版题库 题目的编号题目的标题题目的难度题目的描述&#xff0c;题面时间要求(内部处理)空间要求(内部处理) 两批文件构成第一个&#xff1a;questions.list : 题目列表&#xff08;不需要题目的内容&#xff09;第二个&#xff1a;题目的描述&#xff0c;题目的预设置…

LabVIEW中CFURL.llb 工具库说明

CFURL.llb 是 LabVIEW 2019 安装目录下 C:\Program Files (x86)\National Instruments\LabVIEW 2019\vi.lib\Platform\ 路径下的工具库&#xff0c;主要用于处理 LabVIEW 与 URL 相关的操作&#xff0c;涵盖 URL 解析、HTTP 请求发送、数据传输等功能模块&#xff0c;帮助开发者…

网络运维学习笔记 017 HCIA-Datacom综合实验01

文章目录 综合实验1实验需求总部特性 分支8分支9 配置一、 基本配置&#xff08;IP二层VLAN链路聚合&#xff09;ACC_SWSW-S1SW-S2SW-Ser1SW-CoreSW8SW9DHCPISPGW 二、 单臂路由GW 三、 vlanifSW8SW9 四、 OSPFSW8SW9GW 五、 DHCPDHCPGW 六、 NAT缺省路由GW 七、 HTTPGW 综合实…

6.✨Python学习价值与优势分析

✨Python 是一种值得深入学习的编程语言&#xff0c;其设计哲学、广泛的应用场景以及强大的社区支持使其成为当今最受欢迎的编程语言之一。以下从多个角度分析为什么 Python 值得深入学习&#xff1a; 1.&#x1f98b; 简洁易学的语法 Python 以简洁、可读性强著称&#xff0c…

Android Audio其他——数字音频接口(附)

数字音频接口 DAI,即 Digital Audio Interfaces,顾名思义,DAI 表示在板级或板间传输数字音频信号的方式。相比于模拟接口,数字音频接口抗干扰能力更强,硬件设计简单,DAI 在音频电路设计中得到越来越广泛的应用。 一、音频链路 1、模拟音频信号 可以看到在传统的…

Spring AI + Ollama 实现调用DeepSeek-R1模型API

一、前言 随着人工智能技术的飞速发展&#xff0c;大语言模型&#xff08;LLM&#xff09;在各个领域的应用越来越广泛。DeepSeek 作为一款备受瞩目的国产大语言模型&#xff0c;凭借其强大的自然语言处理能力和丰富的知识储备&#xff0c;迅速成为业界关注的焦点。无论是文本生…

2.3 变量

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 变量是用来存放某个值的数据&#xff0c;它可以表示一个数字、一个字符串、一个结构、一个类等。变量包含名称、类型和值。在代码中…

LLM大语言模型私有化部署-使用Dify的工作流编排打造专属AI诗词数据分析师

背景 前面的文章通过 Ollama 私有化部署了 Qwen2.5 (7B) 模型&#xff0c;然后使用 Docker Compose 一键部署了 Dify 社区版平台。 LLM大语言模型私有化部署-使用Dify与Qwen2.5打造专属知识库&#xff1a;在 Dify 平台上&#xff0c;通过普通编排的方式&#xff0c;创建了基于…