用BGE Large ZH 1.5获取向量以及重排序构建生产环境可用restful API的Python代码讲解

开篇

嘿,各位小伙伴!今天我们来聊一个超级有趣的话题:embedding向量化数据。听起来很高大上对不对?别担心,让我用最简单的方式告诉你这是啥。 想象一下,你有一大堆文字、图片或者其他数据,想要让计算机理解它们该怎么办?这就需要我们把它们变成计算机能读懂的"数字",这个过程就叫embedding向量化! 

简单来说,就是把数据转换成一串数字,这串数字就像是数据的"指纹",我们管它叫向量。

比如,"我爱吃火锅"这句话,经过向量化后可能变成[-0.2, 0.5, 0.8]这样的数字组合。 那这些数字有什么用呢?最神奇的是,通过计算这些向量之间的余弦值(简单理解就是数学上的一个相似度打分),我们就能知道不同数据之间有多相似!余弦值越接近1,说明两个数据越相似;越接近-1,说明越不相似。 所以下次当你使用搜索引擎,或者看到AI给出惊人的相似推荐时,别忘了,背后可能就是这些小向量们在默默发挥作用哦!

如何生成向量

这张图是我经常用在博客中讲关于Rag类应用的。这是因为Rag自2023年年初被越来越多的人所接受时第一个出现的标准数据流就是这样的。

关键在于这里面的一个个向量是怎么计算出来的,以及怎么选向量模型。

选向量模型

总体来说向量模型目前在市面上分成两类

SAAS化

最有代表的就是OpenAI的Text Embedding Large 3,目前支持达到3172个维度,在Azure OpenAI Studio里可以直接调用,收费相当的便宜、速度快而且支持高并发(零点几厘每千token);

本地化开源

但是考虑到数据安全性以及解决方案一致和一体性同时要兼顾考虑到中文、英文多场景结合这样的跨语言问题我们还是首选本地开源布署向量模型。

比较著名的有以下三种模型,我们分别从几个能力来比对一下这三种模型。

多语言处理能力
  • BGE - BGE可以将任意文本映射到低维的稠密向量,在文本向量化任务中得到了广泛的应用。 BGE系列模型在C-MTEB中文排行榜中名列前茅,显示了其强大的文本处理和语义表征能力。
  • M3E - M3E采用大规模混合嵌入技术,旨在提高词向量的表达能力和泛化能力。M3E在训练过程中使用千万级的中文句对数据集进行训练,表现出色的向量编码能力。
  • BCE - BCE模型主要用于提升RAG应用的准确度,具体细节较少,但其作为开源大模型的一部分,应具备较强的文本处理能力。
文本处理能力
  • BGE - BGE可以将任意文本映射到低维的稠密向量,在文本向量化任务中得到了广泛的应用。 BGE系列模型在C-MTEB中文排行榜中名列前茅,显示了其强大的文本处理和语义表征能力。
  • M3E - M3E采用大规模混合嵌入技术,旨在提高词向量的表达能力和泛化能力。M3E在训练过程中使用千万级的中文句对数据集进行训练,表现出色的向量编码能力。
  • BCE - BCE模型主要用于提升RAG应用的准确度,具体细节较少,但其作为开源大模型的一部分,应具备较强的文本处理能力。
检索精度与整体语义表征能力
  • BGE - BGE在中英文语义检索精度与整体语义表征能力方面均超越了社区所有同类模型,如OpenAI的text embedding 003等。其保持了同等参数量级模型中的最小向量维度,使用成本更低。

  • M3E - M3E在私有部署和大规模文本处理方面表现出色,适用于需要私有化和资源节约的场景。它通过大规模混合嵌入技术提高了词向量的表达能力和泛化能力,适用于各种文本处理任务。

  • BCE - BCE的具体检索精度和语义表征能力未详细说明,但其在RAG应用中的表现表明其具有较高的准确性。
资源使用情况
  • BGE - BGE系列模型在全球下载量超过1500万,位居国内开源AI模型首位,表明其资源使用高效且受欢迎。
  • M3E - M3E属于小模型,资源使用不高,CPU也可以运行,适合私有化部署和资源受限的环境。
  • BCE - BCE的具体资源使用情况未明确提及,但作为开源大模型的一部分,其资源使用可能相对较高。

选定本地化的BGE布署方案

最终我们发觉在多语言支持、文本处理能力和检索精度方面表现优异,尤其适合需要高精度和高效率的场景。同时,其资源使用较为经济。

因此我们就选用BGE Large ZH v1.5模型来做我们的向量模型。

Ollama自带向量模型

当然,还有一种就是Ollama自带embedding模型,叫MX_BAI_Embedding,也是1024位维度的。

你可以通过以下指令安装它,前提是你已经安装有ollama了。

ollama pull mxbai-embed-large

它安装完后即是restful service的。

构建向量化服务的代码

官方例子太简单无法应用在正式生产环境

官方的例子很简单

先安装(记得要用conda虚拟化一个python环境)

conda create -n bge-rerank-large python=3.10 -yconda init powershellconda activate bge-rerank-largepip install -U FlagEmbedding

然后就是直接调用了

rom FlagEmbedding import FlagModel
sentences_1 = ["样例数据-1", "样例数据-2"]
sentences_2 = ["样例数据-3", "样例数据-4"]
model = FlagModel('BAAI/bge-large-zh-v1.5', query_instruction_for_retrieval="为这个句子生成表示以用于检索相关文章:",use_fp16=True) # Setting use_fp16 to True speeds up computation with a slight performance degradation
embeddings_1 = model.encode(sentences_1)
embeddings_2 = model.encode(sentences_2)
similarity = embeddings_1 @ embeddings_2.T
print(similarity)# for s2p(short query to long passage) retrieval task, suggest to use encode_queries() which will automatically add the instruction to each query
# corpus in retrieval task can still use encode() or encode_corpus(), since they don't need instruction
queries = ['query_1', 'query_2']
passages = ["样例文档-1", "样例文档-2"]
q_embeddings = model.encode_queries(queries)
p_embeddings = model.encode(passages)
scores = q_embeddings @ p_embeddings.T

这样的调用根本没法用在生产环境,在生产环境一切都为“服务”即API。更何况:

  • query_instruction_for_retrieval="为这个句子生成表示以用于检索相关文章:"

这一个点,网上无任何解释,这个参数是干什么的?

我看到过很多生产环境里都有这样一句代码,这太搞笑了。

这个参数的值可以为空但也可以填,这是为什么呢?

告诉大家吧,这个参数是为每一个向量生成时添加“前缀”时,以便于在检索时碰到类似前缀可以更精准得把这个向量从向量库里搜索得到用的,你可以认为这是一个“打标签”的功能。

下面就来构建生产环境用API服务。

生产环境的实战例子

提出需求

  1. 可满足生产环境中各种业务在需要embedding时取得向量化用,生产环境里有各种系统有Java的有Python的甚至还有Go、.Net、SAP应用,当这些异质架构混在一起时如果都要调用embedding时怎么办?因此我们需要把它构建成API服务;
  2. API在被调用时需要调用方在http header头带上一个自定义的企业用api-key;
  3. 可以把向量返回成浮点数组同时还能返回一个spentTime用于统计每一次调用所消耗时间;
  4. 任何错误以.log文件日志落盘方式记录它

为此,我们选用轻量级的Flask来构建基于python的restful service。如果你是django当然也可以使用django去构建它。

不过我这介绍的还是最轻量级的flask restful service方案,它轻量、启动方便。

下面上全代码:

from flask import Flask, request, jsonify
import os
import time
import logging
from logging.handlers import RotatingFileHandler
from FlagEmbedding import FlagReranker
from FlagEmbedding import FlagModel
app = Flask(__name__)model = FlagModel('BAAI/bge-large-zh-v1.5',query_instruction_for_retrieval="",use_fp16=False)  # 设置use_fp16为True可以加快计算,效果会稍有下降
# 配置日志
if not os.path.exists('logs'):os.makedirs('logs')file_handler = RotatingFileHandler('logs/FountainRank.log', maxBytes=10240000, backupCount=10)
file_handler.setFormatter(logging.Formatter('%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]'
))
file_handler.setLevel(logging.INFO)
app.logger.addHandler(file_handler)
app.logger.setLevel(logging.INFO)@app.route('/getBGEEmbedding', methods=['POST'])
def get_vector():start_time = time.time()error_messages = []  # 用于收集错误信息api_key = request.headers.get('apiKey')if api_key != os.environ.get('X_API_KEY'):error_msg = 'Invalid API Key'app.logger.error(error_msg)error_messages.append(error_msg)return jsonify({'data': {'embeddings': [],'spentTime': time.time() - start_time}}), 403#if not api_key or api_key != os.environ.get('LOCAL_MODEL_API_KEY'):#    return jsonify({'error': '无效的登录'}), 403inputText = request.json.get('input', None)if not inputText:return jsonify({'error': '请输入有效文本'}), 400else:embedding = model.encode([inputText])vec_list = embedding.tolist()return jsonify({'data': {'embeddings': vec_list,'spentTime': time.time() - start_time}}), 200if __name__ == '__main__':app.run(host='0.0.0.0', port=5000)

核心代码解读

  1. 把bge large zh1.5模型作为全局加载,这样每次调用都是从内存里加载模型而不是每调用一次就中加载一次,这是为性能作考虑(第一次加载时会下载690-800Mb模型至本地的HF_HOME所指向目录,即hugging face home所在路径);
  2. 在python当前目录创建logs目录,如果已经存在就使用它,以便于落盘相关log日志;
  3. 用flask的@app.route构建api,这个flask运行在5000端口因此它的访问方式就为:http://localhost:5000/getBGEEmbedding;
  4. 请求时http header请求头必须带上一个apiKey,并且代码用http header里的apiKey和服务端环境变量设置的X_API_KEY的值去做比对,以防止乱访问造成的安全问题;
  5. 代码通过请求体里的input获取用于请求生成向量的文本段并通过model.encode返回,最终把它以tolist() - 浮点数数组的形式返回给到调用端;

如何调用

启动该例子

我们可以使用python embedding.py直接这样启动它,不过这是开发调试模式。

我们也可以使用gunicorn启动它

gunicorn -w 4 -b 0.0.0.0:5000 --timeout 120 --access-logfile logs/access.log --error-logfile logs/error.log embedding:app

这儿的:app前写的就是这个python文件的名字(不带.py)。

生产环境如何调用
curl --location --request POST 'http://localhost:5000/getBGEEmbedding' \
--header 'apiKey: secret_password' \
--header 'Content-Type: application/json' \
--header 'Host: localhost:5000' \
--data-raw '{"input": "圣诞节水晶球"
}'

于是它就会得到下面这样的向量

 在对接时我们取data.embedding里的数据成浮点数组即可用来存储和搜索用了,如我们使用spring boot对接中台代码获取向量示例:

            String jsonStr = okHttpHelper.postJsonWithMultiHeaders(embeddingUrl, input, headers, 4000, 4000);logger.info(">>>>>>getEmbedding模型返回的result->{}", jsonStr);if (StringUtil.isNotBlank(jsonStr)) {// 使用JsonNode来解析JsonNode rootNode = objectMapper.readTree(jsonStr);// 先获取data节点JsonNode dataNode = rootNode.get("data");if (dataNode != null) {// 从data节点中获取embeddingsJsonNode embeddingsNode = dataNode.get("embeddings");if (embeddingsNode != null && embeddingsNode.isArray() && embeddingsNode.size() > 0) {// 获取第一个embedding数组JsonNode firstEmbedding = embeddingsNode.get(0);if (firstEmbedding != null && firstEmbedding.isArray()) {vectorResult = new ArrayList<>();for (JsonNode value : firstEmbedding) {vectorResult.add(value.floatValue());}}}// 如果需要获取spentTimeJsonNode spentTimeNode = dataNode.get("spentTime");if (spentTimeNode != null) {double spentTime = spentTimeNode.doubleValue();logger.info(">>>>>>BgeEmbedding spent time->{}",spentTime);// 处理spentTime...}}}

上述代码中的vectorResult是一个List<Float>类型的变量。平均耗时在15-30毫秒,性能相当好(注意了,你要用GPU环境运行)。

如何实现重排序

什么是重排序

在上一篇《一文看懂最前沿得高级RAG+设计是如何消灭AI幻觉的架构设计》 中我们提到了目前最先进的RAG架构-RAG+又称为:高级RAG中,必须使用到重排序这一步骤。

重排序步骤其实就好比:

  1. 我们先要为用户的提问生成>=提问所用的答案;
  2. 再像一个渔网一样,逐步把“不合格的鱼”筛选出去;
  3. 最终留下精确的语料送给LLM去做仲裁,以便得LLM削除不必要的幻觉同时取得最佳性能;

好比用户如果问的是:附近有什么吃的?

RAG会检索出10-30条含有附近设施、配套、相关信息的介绍,而真正和“吃的”有关系的可能只有4条,因此我们不能把30条全部一股脑送给AI,而是把这有用的4条信息:筛选出来,这就要用到重排序了。

为此,我们也使用BGE Rrerank Large模型,它可以本地布署同时性能很棒。

BGE  Rerank的使用

官方的便子给出的也是太简单了,无法使用在含有异质架构的生产环境里。

from FlagEmbedding import FlagReranker
reranker = FlagReranker('BAAI/bge-reranker-large', use_fp16=True) # Setting use_fp16 to True speeds up computation with a slight performance degradationscore = reranker.compute_score(['query', 'passage'])
print(score)scores = reranker.compute_score([['what is panda?', 'hi'], ['what is panda?', 'The giant panda (Ailuropoda melanoleuca), sometimes called a panda bear or simply panda, is a bear species endemic to China.']])
print(scores)

为此我们也构建flask服务来构建它。

我们把它可以放在刚才的embedding.py文件里,做成另一个API,这样就不需要分成两个flask服务去分别运行了。

全代码

from flask import Flask, request, jsonify
import os
import time
import logging
from logging.handlers import RotatingFileHandler
from FlagEmbedding import FlagReranker
from FlagEmbedding import FlagModel
app = Flask(__name__)# 全局 reranker 对象
global_reranker = FlagReranker('BAAI/bge-reranker-large', use_fp16=True)
model = FlagModel('BAAI/bge-large-zh-v1.5',query_instruction_for_retrieval="",use_fp16=False)  # 设置use_fp16为True可以加快计算,效果会稍有下降
# 配置日志
if not os.path.exists('logs'):os.makedirs('logs')file_handler = RotatingFileHandler('logs/FountainRank.log', maxBytes=10240000, backupCount=10)
file_handler.setFormatter(logging.Formatter('%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]'
))
file_handler.setLevel(logging.INFO)
app.logger.addHandler(file_handler)
app.logger.setLevel(logging.INFO)@app.route('/getBGEEmbedding', methods=['POST'])
def get_vector():start_time = time.time()error_messages = []  # 用于收集错误信息api_key = request.headers.get('apiKey')if api_key != os.environ.get('X_API_KEY'):error_msg = 'Invalid API Key'app.logger.error(error_msg)error_messages.append(error_msg)return jsonify({'data': {'embeddings': [],'spentTime': time.time() - start_time}}), 403#if not api_key or api_key != os.environ.get('LOCAL_MODEL_API_KEY'):#    return jsonify({'error': '无效的登录'}), 403inputText = request.json.get('input', None)if not inputText:return jsonify({'error': '请上传有效的文本'}), 400else:embedding = model.encode([inputText])vec_list = embedding.tolist()return jsonify({'data': {'embeddings': vec_list,'spentTime': time.time() - start_time}}), 200@app.route('/rank', methods=['POST'])
def rank():start_time = time.time()error_messages = []  # 用于收集错误信息try:# 验证 API Keyapi_key = request.headers.get('apiKey')if api_key != os.environ.get('X_API_KEY'):error_msg = 'Invalid API Key'app.logger.error(error_msg)error_messages.append(error_msg)return jsonify({'data': {'resultList': [],'spentTime': time.time() - start_time,'failReason': ' | '.join(error_messages)}}), 403# 获取请求数据data = request.get_json()user_input = data.get('userInput', '')knowledge_list = data.get('knowledgeList', [])# 如果知识列表为空,返回空结果if not knowledge_list:return jsonify({'data': {'resultList': [],'spentTime': time.time() - start_time,'failReason': ''}})# 处理每条知识并计算相似度result_list = []potential_records = []  # 新增一个列表存储分数小于0的记录for idx, item in enumerate(knowledge_list):try:score = global_reranker.compute_score([user_input, item['fileContent']])[0]# 构建通用的结果项result_item = {'id': item.get('id', ''),'pointId': item.get('pointId', 0),'fileName': item.get('fileName', ''),'fileContent': item.get('fileContent', ''),'score': float(score)}# 根据分数分别添加到不同列表if score >=-1.8:result_list.append(result_item)else:potential_records.append(result_item)except Exception as e:error_msg = f'Error processing item {idx}: {str(e)}'app.logger.error(error_msg)error_messages.append(error_msg)continue# 按 score 降序排序result_list.sort(key=lambda x: x['score'], reverse=True)return jsonify({'data': {'resultList': result_list,'potentialRecords': potential_records,'spentTime': time.time() - start_time,'failReason': ' | '.join(error_messages) if error_messages else ''}})except Exception as e:error_msg = f'Error in rank API: {str(e)}'app.logger.error(error_msg)error_messages.append(error_msg)return jsonify({'data': {'resultList': [],'spentTime': time.time() - start_time,'failReason': ' | '.join(error_messages)}})if __name__ == '__main__':app.run(host='0.0.0.0', port=5000)

代码核心解读

  1. 我们在embedding.py里定义了2个API一个是/getBGEEmbeddingg,一个是/rank,这样只要我们用gunicorn把这个flask服务启动起来就可以满足生产环境中对于embedding和rerank的API调用了;
  2. 和embedding时一样,我们在一启动时就把rerank模式加载到内存里去而不是每一次调用都去重复加载它;
  3. rerank会接收一个这样的输入
{"userInput": "外公79岁, 眼压高, 视力模糊, 头痛, 眼睛胀痛, 青光眼, 老年人眼健康, 眼科药物, 眼部维生素补充, 护眼产品","knowledgeList": [{"id": "1","pointId": 3398761,"fileName": "eye.txt","fileContent": "眼压高需要及时就医...","score": 0},{"id": "2","pointId": 1109871,"fileName": "eye.txt","fileContent": "局部用药","score": 0},{"id": "3","pointId": 4788771,"fileName": "eye.txt","fileContent": "外用药","score": 0},{"id": "4","pointId": 538871,"fileName": "被充眼药文档.txt","fileContent": "常用眼药水","score": 0}]
}
  • userInput:用户的提问
  • knowledgeList,内含从RAG中被检索出来的topK条原始语料;

4. 把rerank排序后得-2分以下的记录全部删除(具体得分段需要根据你自己的项目不断去做调整,一般通用情况下我们是把0分以下的记录全部删除只作为potentialRecords返回,而正确的数据作为resultList返回。也有是全部rerank后返回,取1-10(topP)条记录的作法),这个是没有一定的规定的,而是根据你当前系统中的语料特性不断去做适应得以取得一个最佳的组合,所谓最佳使用就是:正确的语料+潜在的语料是最后检索出的结果。

如何访问

访问很简单

curl --location --request POST 'http://localhost:5000/rank' \
--header 'apiKey: secret_password' \
--header 'Content-Type: application/json' \
--data-raw '{"userInput": "外公79岁, 眼压高, 视力模糊, 头痛, 眼睛胀痛, 青光眼, 老年人眼健康, 眼科药物, 眼部维生素补充, 护眼产品","knowledgeList": [{"id": "1","pointId": 3398761,"fileName": "eye.txt","fileContent": "眼压高需要及时就医...","score": 0},{"id": "2","pointId": 1109871,"fileName": "eye.txt","fileContent": "局部用药","score": 0},{"id": "3","pointId": 4788771,"fileName": "eye.txt","fileContent": "外用药","score": 0},{"id": "4","pointId": 538871,"fileName": "补充眼药文档.txt","fileContent": "常用眼药水","score": 0}]
}'

最后我们来看返回:

{"data": {"failReason": "","potentialRecords": [{"fileContent": "局部用药","fileName": "eye.txt","id": "2","pointId": 1109871,"score": -3.58418345451355}],"resultList": [{"fileContent": "眼压高需要及时就医...","fileName": "eye.txt","id": "1","pointId": 3398761,"score": 4.278597354888916},{"fileContent": "常用眼药水","fileName": "补充眼药文档.txt","id": "4","pointId": 538871,"score": 0.8522164225578308},{"fileContent": "外用药","fileName": "eye.txt","id": "3","pointId": 4788771,"score": -1.5808547735214233}],"spentTime": 0.9499616622924805}
}

请大家观察那几个>0分的记录,可以看到结果相当的精准。

何时可能会取-2分及以上呢?我这给大家举一个例子:

提问:我住在正大大美白广场,停车费找谁?语料:停车位收费,正大大美白附近联系电话:xxxxxxxx。福建路书店附近:联系:xxxxxxxx。

在使用MX_BAI或者是其它一类的embedding模型时这样的匹配会产生负分,因为它有偏差。当然,情况各异,具体还是需要遵守:正确的语料+潜在的语料,而不能也不可能追究到达:100%精准的

好了,结束今天的分享。

关键还是自己需要多动动手。

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

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

相关文章

【OneAPI】网页截图API-V2

API简介 生成指定URL的网页截图或缩略图。 旧版本请参考&#xff1a;网页截图 V2版本新增全屏截图、带壳截图等功能&#xff0c;并修复了一些已知问题。 全屏截图&#xff1a; 支持全屏截图&#xff0c;通过设置fullscreentrue来支持全屏截图。全屏模式下&#xff0c;系统…

1个基于 Three.js 的 Vue3 组件库

大家好&#xff0c;我是大澈&#xff01;一个喜欢结交朋友、喜欢编程技术和科技前沿的老程序员&#x1f468;&#x1f3fb;‍&#x1f4bb;&#xff0c;关注我&#xff0c;科技未来或许我能帮到你&#xff01; Tres.js 是一个基于 Three.js 的 Vue 3 组件库&#xff0c;旨在简…

QT | 信号与槽(超详解)

前言 对qt信号和槽的详细解释 &#x1f493; 个人主页&#xff1a;普通young man-CSDN博客 ⏩ 文章专栏&#xff1a;C_普通young man的博客-CSDN博客 ⏩ 本人giee: 普通小青年 (pu-tong-young-man) - Gitee.com 若有问题 评论区见&#x1f4dd; &#x1f389;欢迎大家点赞&am…

用Deepseek写一个五子棋微信小程序

在当今快节奏的生活中&#xff0c;休闲小游戏成为了许多人放松心情的好选择。五子棋作为一款经典的策略游戏&#xff0c;不仅规则简单&#xff0c;还能锻炼思维。最近&#xff0c;我借助 DeepSeek 的帮助&#xff0c;开发了一款五子棋微信小程序。在这篇文章中&#xff0c;我将…

Qwen2.5-7B-Instruct进行自我认知微调

使用镜像&#xff1a; modelscope/ms-swift/swift_lora_qwen2:v1 数据集和模型下载&#xff1a; 数据集内容&#xff1a; 启动命令&#xff1a; CUDA_VISIBLE_DEVICES0 \ swift sft \ --model Qwen/Qwen2.5-7B-Instruct \ --train_type lora \ --dataset AI-Mod…

百问网提供的烧写工具将各镜像文件烧写到eMMC存储器的各脚本的解析

重要说明:本文的烧写目标存储器是eMMC存储器 百问网提供的烧写工具不仅可以把各镜像文件烧写到eMMC存储器&#xff0c;还可以烧写到NADN&#xff0c;SD卡等存储设备&#xff0c;如下图所示&#xff1a; 但是本文的烧写目标存储器是eMMC存储器&#xff0c;这点是前提&#xff…

android studio开发文档

android基本样式 1.文本 2.设置文本大小 3.字体颜色 背景 资源文件 xml’引用资源文件 4.视图宽高 5.间距 6.对齐方式 常用布局 1.linearLayout线性布局 2.相对布局 RelativeLayout 3.网格布局GridLayout 4.scrollview滚动视图 Button 点击事件与长按事件 长按 按钮禁用与…

Unity Dots

文章目录 什么是DotsDOTS的优势ECS&#xff08;实体组件系统&#xff09;Job System作业系统Burst编译器最后 什么是Dots DOTS&#xff08;Data-Oriented Technology Stack&#xff09;是Unity推出的一种用于开发高性能游戏和应用的数据导向技术栈&#xff0c;包含三大核心组件…

Flink-DataStreamAPI-执行模式

一、概览 DataStream API支持不同的运行时执行模式&#xff0c;我们可以根据用例的要求和作业的特征进行选择。 STREAMING执行模式&#xff1a;被称为“经典”执行模式为&#xff0c;主要用于需要持续增量处理并且预计无限期保持在线的无界作业BATCH执行模式&#xff1a;类似…

DeepSeek DeepEP学习(三)normal dispatch

上节介绍了normal kernel执行过程中会分成两部分&#xff0c;第一步通过notify_dispatch计算meta信息&#xff0c;然后本节介绍数据dispatch的过程。 notify_dispatch过程中会计算其他所有rank发送给当前rank多少token&#xff0c;写入到host的moe_recv_counter_mapped&#x…

mysql创建数据库和表

登录 MySQL 并选择数据库 登录 MySQL 命令行&#xff1a;mysql -u root -p 查看所有数据库&#xff1a;SHOW DATABASES; 创建数据库&#xff1a;CREATE DATABASE my_database; 查看数据库是否创建成功&#xff1a;SHOW DATABASES; 选择数据库&#xff1a;USE 你的数据库名…

Python 实现图片提取文字

文章目录 一、效果图 二、库安装 三、使用示例 四、完整代码 一、效果图 使用的图片&#xff1a; 返回文字&#xff1a; 二、库安装 pip install easyocr opencv-python numpy 三、使用示例 ocr EasyOCRProcessor() results ocr.extract_text("test.png",&…

根目录下的两个包相互没有import成功

问题1&#xff1a; import models 或者import models.Models不成功 问题2&#xff1a;在项目名称后面出现unnamed的提示 查阅资料&#xff0c;说错误可能是&#xff1a;.idea 文件夹配置缺失或损坏 PyCharm 的项目配置信息&#xff08;包括名称&#xff09;存储在 .idea 目录中…

什么样的物联网框架适合开展共享自助KTV唱歌项目?

现在物联网的广泛应用&#xff0c;也让更多用户们看到了它的实力&#xff0c;也使得共享经济遍地开花。其中共享自助唱歌设备也备受欢迎&#xff0c;那么适合开展共享自助KTV唱歌项目的物联网框架都应具备哪些特点呢&#xff1f; 智能化与自动化管理 物联网技术在共享KTV中的应…

《白帽子讲 Web 安全》之深入同源策略(万字详解)

目录 引言 一、同源策略基础认知 &#xff08;一&#xff09;定义 &#xff08;二&#xff09;作用 &#xff08;三&#xff09;作用机制详解 二、同源策略的分类 &#xff08;一&#xff09;域名同源策略 &#xff08;二&#xff09;协议同源策略 &#xff08;三&…

【Linux篇】调试器-gdb/cgdb使用

&#x1f4cc; 个人主页&#xff1a; 孙同学_ &#x1f527; 文章专栏&#xff1a;Liunx &#x1f4a1; 关注我&#xff0c;分享经验&#xff0c;助你少走弯路&#xff01; 文章目录 1. 前言2.关于gdb2.1 快速认识gdb2.2 安装cgdb2.3 gdb命令2.4 调试 & 断点 3.常见技巧3.…

推荐一些免费开源支持Vue3甘特图组件

文章目录 前言一、dhtmlxGantt二、frappe-gantt三、vue-ganttastic四、gantt-elastic五、v-gantt六、vue-gantt-schedule-timeline-calendar七、vue-gantt八、总结 前言 在现代项目管理和任务调度中&#xff0c;甘特图是一种非常实用的工具。它能够直观地展示任务的时间安排、…

十大数据科学Python库

十大数据科学Python库 1、NumPy&#xff1a;脊髓2、Pandas&#xff1a;数据操纵专家3、Matplotlib&#xff1a;艺术之魂4、Scikit-Learn&#xff1a;瑞士军刀5、TensorFlow&#xff1a;聪明的家伙6、PyTorch&#xff1a;叛逆者7、Selenium&#xff1a;操纵大师8、NLTK&#xff…

【C++初阶】类与对象(下)

目录 再探构造函数&#xff1a;初始化列表 使用方法&#xff1a; 特点&#xff1a; &#xff11;、初始化列表是每个成员变量定义初始化的地方 &#xff12;、每一成员变量在初始化列表只出现一次 3、必须在初始化列表中出初始化的成员变量 4、成员变量给缺省值 5、在构…

Android设备是如何进入休眠的呢?

首先我们手机灭屏后&#xff0c;一般需要等一段时间CPU才真正进入休眠。即Android设备屏幕暗下来的时候&#xff0c;并不是立即就进入了休眠模式&#xff1b;当所有唤醒源都处于de-avtive状态后&#xff0c;系统才会进入休眠。在手机功耗中从灭屏开始到CPU进入休眠时间越短&…