当前位置: 首页 > news >正文

BERT模型的输出格式探究以及提取出BERT 模型的CLS表示,last_hidden_state[:, 0, :]用于提取每个句子的CLS向量表示

说在前面

最近使用自己的数据集对bert-base-uncased进行了二次预训练,只使用了MLM任务,发现在加载训练好的模型进行输出CLS表示用于下游任务时,同一个句子的输出CLS表示都不一样,并且控制台输出以下警告信息。说是没有这些权重。

Some weights of BertModel were not initialized from the model checkpoint at ./model/test-model and are newly initialized: ['bert.pooler.dense.bias', 'bert.pooler.dense.weight']
You should probably TRAIN this model on a down-stream task to be able to use it for predictions and inference.

BertModel 的某些权重在 ./model/test-model 的模型检查点时未被初始化,现在是新初始化的: ['bert.pooler.dense.bias','bert.pooler.dense.weight']。
您可能应该在下流任务中训练该模型,以便将其用于预测和推理。

问题原因

我刚开始获取CLS token表示使用的是以下方式,池化后的CLS token表示。

# 获取池化后的[CLS] token 表示
pooler_output = outputs.pooler_output 

但是我使用的模型是以下加载方式,它的输出并不包含 pooler_output,因为这个模型是为 掩码语言模型(Masked Language Model)任务设计的,而不是用于分类任务。因此,模型的输出包括 last_hidden_state,而不包括 pooler_output

model = AutoModelForMaskedLM.from_pretrained(BERT_PATH).to('cuda')
# 或者
model = BertForMaskedLM.from_pretrained(BERT_PATH).to('cuda')

所以我加载使用训练后的模型总是对同一个句子的CLS输出总是变化,就是没有pooler_output层的权重参数,它加载模型推理时自己随机初始化了pooler_output层权重参数。

解决方法

一共有两个解决方法。

1. 直接使用last_hidden_state[:,0,:]获取每个句子的cls token的表示。缺点:cls 表示在句子级表示方面差于pooler_output表示。

2. 修改训练的模型架构,添加池化层。pooler_output表示的优点是它对 [CLS] token 的表示进行了池化处理,它通常是更好的句子级别表示。

1. BERT模型的输出格式探究

last_hidden_state

last_hidden_state:这是一个张量,形状为 [batch_size, sequence_length, hidden_size]

  • batch_size:一次传入模型的样本数。
  • sequence_length:输入序列的长度(即输入文本中的 token 数量)。
  • hidden_size:每个 token 的隐藏状态向量的维度,通常是 768(BERT-base)或 1024(BERT-large)。

形象生动图形

真实示例

以下是1个batch_size的真实数据,每一行就是一个token,共有512行。每行里面的数值共有768个。该last_hidden_state 的形状是 [1, 512, 768]

last_hidden_state:  tensor([[[-0.1043,  0.0966, -0.2970,  ..., -0.3728,  0.2120,  0.5492],[ 0.0131, -0.0778,  0.0908,  ..., -0.1869,  1.0111,  0.1027],[-0.8840,  0.3916,  0.3881,  ..., -0.5864,  0.3374,  0.1069],...,[-0.2845, -0.8075,  0.6715,  ..., -0.5281,  0.5046, -0.6814],[-0.4623, -0.6836, -0.8556,  ...,  0.1499,  0.1142,  0.0486],[ 0.5701, -0.1264, -0.2348,  ...,  0.2635, -0.4314, -0.1724]]])

2. 获取每个句子的CLS token向量表示

last_hidden_state[:, 0, :]的含义=CLS向量表示

  • 表示我们选择了所有的批次样本。batch_size 为 1 时,选择所有样本,即 [1, 512, 768] 中的所有样本。
  • 0:表示我们选择了每个句子序列中的第一个 token(索引 0),在 BERT 中,输入序列的第一个 token 通常是 [CLS] token。因此,0 索引指向 [CLS] token 对应的隐藏状态。
  • 表示我们选择了所有的隐藏维度(即每个 token 的隐藏状态),也就是每个 token 的向量表示,通常为 768 维(对于 BERT-base)。

因此该操作的含义是:每个句子有512个token,提取每个句子里面的第1个token向量,人话说就是每个句子的的第1个token向量就是每个句子的CLS向量表示。

结果:这将会返回一个形状为 [1, 768] 的张量,它包含了 [CLS] token 的表示。由于 batch_size=1,最终的张量只有一个样本。

为什么last_hidden_state[:, 0, :]提取的就是每个句子的CLS token表示呢?

在 BERT 模型中,[CLS] token 是一个特殊的 token,通常用于表示整个句子的嵌入(embedding),特别是在分类任务中,[CLS] token 的输出被用作整个输入句子的向量表示。

  • 分类任务 中(如情感分析、文本分类等),通常使用 [CLS] token 的表示 作为整个句子的特征向量输入到分类器中。
  • 其他任务 中(如命名实体识别、问答系统等),[CLS] token 的表示也常常被用作输入的高层特征。

3. last_hidden_state 和 pooler_output的含义区别

outputs.last_hidden_stateoutputs.pooler_output 是 BERT 模型的两个重要输出,二者之间有明显的区别。它们分别代表了不同层级的模型输出,具体如下:

outputs.last_hidden_state

  • 定义last_hidden_state 是 BERT 模型中每一层的输出,包含了模型对于输入文本中每个 token 的隐藏表示。

  • 形状last_hidden_state 的形状通常是 [batch_size, sequence_length, hidden_size],即:

    • batch_size:批次中样本的数量。
    • sequence_length:输入序列(即文本)的长度,通常是 token 的个数(包括 [CLS][SEP] token)。
    • hidden_size:每个 token 的隐藏状态向量的维度(通常是 768,对于 bert-base-uncased)。
  • 用途last_hidden_state 是 BERT 对每个 token 的表示,包含了输入文本中每个 token 在其上下文中被表示出来的隐藏状态。它包含了完整的上下文信息。

    例如,对于输入文本 "Hello, how are you?",last_hidden_state 包含了 "Hello"",""how" 等每个 token 的上下文嵌入(表示)。你可以根据这个输出提取每个 token 的表示或使用 [CLS] token 的表示(last_hidden_state[:, 0, :])作为整个句子的表示。

outputs.pooler_output

  • 定义pooler_output 是一个经过额外处理的 [CLS] token 的表示。BERT 的 pooler 是一个简单的全连接层,它接收 last_hidden_state[CLS] token 的输出,然后对其进行处理(通常是通过一个 tanh 激活函数)以得到一个句子级别的特征表示。
  • 形状pooler_output 的形状通常是 [batch_size, hidden_size],即:
    • batch_size:批次中的样本数。
    • hidden_size:每个样本的 pooler_output 的维度(通常是 768)。
  • 用途pooler_output[CLS] token 的经过进一步处理后的表示,通常用于分类任务中。pooler_output 是通过对 last_hidden_state[CLS] token 的输出应用池化操作(通常是 tanh 激活函数)得到的最终句子级别的表示。这个表示通常用于下游任务,如分类任务。

两者的区别

  • last_hidden_state

    • 是 BERT 的每个 token 的 上下文表示。它是来自模型的 所有 token 的输出,形状为 [batch_size, sequence_length, hidden_size]
    • 它包含了对输入文本中每个 token 的隐藏状态表示,可以通过它提取每个 token(包括 [CLS])的表示。
  • pooler_output

    • 仅包含 [CLS] token 的表示,并且是经过池化处理(通过 tanh)后的结果,形状为 [batch_size, hidden_size]
    • 它通常用于 句子级别的表示,尤其在分类任务中,pooler_output 是更常见的输入特征。

何时使用哪一个?

  • last_hidden_state:如果你需要每个 token 的表示(如进行命名实体识别、文本生成等任务),你应该使用 last_hidden_state
    • 例如:对于文本分类任务中的 BERT 模型,你通常会使用 [CLS] token 的 last_hidden_state 来提取句子的表示,last_hidden_state[:, 0, :]
  • pooler_output:如果你只是进行 句子级别的分类任务(如情感分析、文本分类等),通常会直接使用 pooler_output,因为它已经对 [CLS] token 的表示进行了处理,通常是更好的句子级别表示。
    • 例如:对于情感分析,你会使用 pooler_output 作为整个句子的向量表示进行分类。

代码示例

假设你正在使用 BERT 模型进行文本分类,你可以使用以下代码来区分这两个输出:

import torch
from transformers import BertModel, BertTokenizer# 加载模型和分词器
model = BertModel.from_pretrained("bert-base-uncased")
tokenizer = BertTokenizer.from_pretrained("bert-base-uncased")# 输入文本
text = "Hello, how are you?"# 编码文本
inputs = tokenizer(text, return_tensors="pt", truncation=True, padding=True)# 获取模型的输出
with torch.no_grad():outputs = model(**inputs)# 获取每个 token 的表示
last_hidden_state = outputs.last_hidden_state  # [batch_size, sequence_length, hidden_size]# 获取[CLS] token 的表示(从 last_hidden_state 中提取)
cls_last_hidden = last_hidden_state[:, 0, :]  # [batch_size, hidden_size]# 获取池化后的[CLS] token 表示
pooler_output = outputs.pooler_output  # [batch_size, hidden_size]print("CLS token's last hidden state:", cls_last_hidden)
print("CLS token's pooler output:", pooler_output)

总结

  • last_hidden_state:包含了每个 token 的 上下文表示,你可以用它来获取每个 token 的隐藏状态(包括 [CLS])。
  • pooler_output:仅包含 [CLS] token 的表示,并且经过了池化处理,通常用于句子级别的任务,如文本分类。

4. 疑惑:pooler_output表示问题

我对bert进行了二次预训练后保存的模型输出发现并没有pooler_output权重参数(也就是文章开始处给出的警告信息),但是我又想要使用训练后的模型进行情感分析,我是直接使用lasthiddenstate的cls token表示呢,还是对其加一个池化处理呢?

cls_output = outputs.last_hidden_state[:, 0, :]  
print(cls_output)pooler_output = outputs.pooler_output
print("pooler_output: ", pooler_output)

没有pooler_output权重参数的原因分析

因为我使用的是 BertForMaskedLM 模型,它的输出并不包含 pooler_output,因为这个模型是为 掩码语言模型(Masked Language Model)任务设计的,而不是用于分类任务。因此,模型的输出包括 last_hidden_state,而不包括 pooler_output

解决方案

1. 直接使用 last_hidden_state[:, 0, :]([CLS] token 的表示)

cls_representation = outputs.last_hidden_state[:, 0, :]

2. [CLS] token 的表示进行池化或全连接层处理

我觉得仅使用 CLS token 的输出还不够,可以加一个简单的全连接层(例如,用 tanh 激活函数)来进一步池化或优化 CLS token 的表示。

import torch.nn as nnclass SentimentAnalysisModel(nn.Module):def __init__(self, model):super(SentimentAnalysisModel, self).__init__()self.bert = modelself.fc = nn.Linear(768, 2)  # 假设是二分类任务(情感分析)def forward(self, input_ids, attention_mask):outputs = self.bert(input_ids=input_ids, attention_mask=attention_mask)cls_rep = outputs.last_hidden_state[:, 0, :]  # 获取 [CLS] token 的表示logits = self.fc(cls_rep)  # 使用全连接层进行分类return logits# 使用训练后的模型来构建情感分析模型
sentiment_model = SentimentAnalysisModel(model)

在这个例子中,cls_rep[CLS] token 的表示,之后我们将其传入一个全连接层进行二分类(情感分析)。当然,如果你有更多类别,你可以根据任务需要修改输出层。

总结

  • 没有 pooler_output:由于我使用的是 BertForMaskedLM,该模型的输出没有 pooler_output,但你可以使用 last_hidden_state[:, 0, :](即 [CLS] token 的表示)作为句子级别的特征来进行情感分析。
  • 是否加池化:我觉得仅使用 [CLS] token 的表示不够好,可以加一个池化层或全连接层来进一步处理该表示,通常这种方式会提高分类性能。

因此,可以继续使用 last_hidden_state 中的 [CLS] token 作为情感分析的特征,如果需要提高模型效果,可以尝试在其基础上加一个池化层或全连接层。

5. 修改模型加载器方法探究

有没有其他解决方法呢,让我二次预训练后的模型有pooler_output。可以修改模型加载器吗,但是我使用的是MLM任务来二次预训练bert模型。我的训练任务是对bert模型进行二次预训练。

为了在训练后的 BERT 模型中有 pooler_output,需要稍作修改,因为默认的 BertForMaskedLM 模型并不包含 pooler_output(该输出通常用于分类任务的 BERT 模型,例如 BertForSequenceClassification)。因此,可以通过修改模型的架构来实现这一目标。

解决方案:修改模型架构

在加载模型时,选择使用 BertModel 或继承 BertForMaskedLM 的新模型,并手动添加一个池化层(如全连接层)。这种方法允许继续使用 MLM 任务,同时为分类任务提供所需的 pooler_output

修改代码的步骤

第一步:继承 BertForMaskedLM 并添加 pooler_output

  • 修改 BertForMaskedLM 模型,使其输出 pooler_output
  • 可以通过添加一个全连接层来模拟池化过程。
class BertWithPoolerOutput(BertForMaskedLM):def __init__(self, config):super().__init__(config)# 定义pooler层self.pooler = torch.nn.Linear(config.hidden_size, config.hidden_size)self.tanh = torch.nn.Tanh()# 使用BertModel来获得last_hidden_stateself.bert = BertModel(config)def forward(self, input_ids=None, attention_mask=None, token_type_ids=None, labels=None):# 使用BertModel来获取last_hidden_statebert_outputs = self.bert(input_ids=input_ids, attention_mask=attention_mask,token_type_ids=token_type_ids)last_hidden_state = bert_outputs.last_hidden_state  # 获取last_hidden_state# 提取[CLS]的输出cls_token_representation = last_hidden_state[:, 0, :]  # 获取[CLS] token的表示# 通过池化层(全连接层)进行处理pooler_output = self.tanh(self.pooler(cls_token_representation))# 获取BERT的MaskedLM输出lm_outputs = super().forward(input_ids=input_ids, attention_mask=attention_mask,token_type_ids=token_type_ids, labels=labels)# 返回字典,包含loss, logits, pooler_outputreturn {'loss': lm_outputs.loss,'logits': lm_outputs.logits,'pooler_output': pooler_output}

在这个新类 BertWithPoolerOutput 中,我们继承了 BertForMaskedLM,并增加了一个池化层 (self.pooler) 和激活函数(tanh),用于生成 pooler_output。此修改确保在进行二次预训练时仍然可以使用池化后的表示。为了正确获取 last_hidden_state,我们应该调用 BertModel 来获取 last_hidden_state,而不是直接从 BertForMaskedLM 获取。

第2步:加载并训练这个模型

通过这种方式,加载并训练模型时,模型将返回 pooler_output,就可以使用它进行情感分析或其他分类任务。

from transformers import BertTokenizer, Trainer, TrainingArguments
from datasets import load_dataset
from transformers import DataCollatorForLanguageModeling# 训练和数据集代码保持不变,只是模型加载部分更换为我们自定义的模型
tokenizer = BertTokenizer.from_pretrained(BERT_PATH)
model = BertWithPoolerOutput.from_pretrained(BERT_PATH)  # 使用我们自定义的模型# 其余的训练部分和数据处理代码不变

第三步:在训练过程中使用 pooler_output

训练结束后,模型将返回 pooler_output,你可以直接使用它进行分类任务。

# 假设输出为 `outputs`,你可以访问 `pooler_output`
pooler_output = outputs.pooler_output

总结

  • 可以通过 自定义模型 来为 BertForMaskedLM 添加 pooler_output,方法是在原有的 BertForMaskedLM 上增加一个池化层。
  • 这样,模型仍然可以用于 MLM 任务,同时也能输出 pooler_output,而它通常是更好的句子级别表示,便于后续情感分析等任务。
  • 训练完成后,就能使用 pooler_output,它是通过池化 [CLS] token 的表示得到的句子级别的特征。

相关文章:

BERT模型的输出格式探究以及提取出BERT 模型的CLS表示,last_hidden_state[:, 0, :]用于提取每个句子的CLS向量表示

说在前面 最近使用自己的数据集对bert-base-uncased进行了二次预训练,只使用了MLM任务,发现在加载训练好的模型进行输出CLS表示用于下游任务时,同一个句子的输出CLS表示都不一样,并且控制台输出以下警告信息。说是没有这些权重。…...

node.js实现分页,jwt鉴权机制,token,cookie和session的区别

文章目录 1. 分⻚功能2. jwt鉴权机制1.jwt是什么2.jwt的应用3.优缺点 3. cookie,token,session的对比 1. 分⻚功能 为什么要分页 如果数据量很⼤,⽐如⼏万条数据,放在⼀个⻚⾯显⽰的话显然不友好,这时候就需要采⽤分⻚…...

34 基于单片机的指纹打卡系统

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 基于STC89C52RC,采用两个按键替代指纹,一个按键按下,LCD12864显示比对成功,则 采用ULN2003驱动步进电机转动,表示开门,另一个…...

【Linux】用户操作命令

声明:以下内容均学习自《Linux就该这么学》一书 1、管理员root Linux系统的管理员之所以是root,并不是因为它的名字叫root,而是因为该用户的身份号码UID(User IDentification)的数值是0。UID相当于身份证号码&#x…...

Y20030018基于Java+Springboot+mysql+jsp+layui的家政服务系统的设计与实现 源代码 文档

家政服务系统的设计与实现 1.摘要2.开发目的和意义3.系统功能设计4.系统界面截图5.源码获取 1.摘要 随着人们生活水平的提高,老龄化、少子化等多重因素影响,我国对家政服务人群的需求与日俱增。家政服务行业对我国的就业和社会效益贡献也与日俱增&#…...

windows部署PaddleSpeech详细教程

windows安装paddlespeech步骤: 1. 安装vs c编译环境 对于 Windows 系统,需要安装 Visual Studio 来完成 C 编译环境的安装。 Microsoft C Build Tools - Visual Studio 2. 安装conda conda create -y -p paddlespeech python3.8 conda activate pad…...

线程条件变量 生产者消费者模型 Linux环境 C语言实现

只能用来解决同步问题&#xff0c;且不能独立使用&#xff0c;必须配合互斥锁一起用 头文件&#xff1a;#include <pthread.h> 类型&#xff1a;pthread_cond_t PTHREAD_COND_INITIALIZER 初始化 初始化&#xff1a;int pthread_cond_init(pthread_cond_t * cond, NULL);…...

C++ packaged_task

packaged_task 是 C11 标准库中引入的一个模板类&#xff0c;它用于将可调用对象&#xff08;如函数、lambda 表达式、函数对象或绑定表达式&#xff09;包装起来&#xff0c;并允许异步地获取其结果packaged_task 类提供了一种方便的方式来创建任务&#xff0c;这些任务可以被…...

【联表查询】.NET开源 ORM 框架 SqlSugar 系列

.NET开源 ORM 框架 SqlSugar 系列 【开篇】.NET开源 ORM 框架 SqlSugar 系列【入门必看】.NET开源 ORM 框架 SqlSugar 系列【实体配置】.NET开源 ORM 框架 SqlSugar 系列【Db First】.NET开源 ORM 框架 SqlSugar 系列【Code First】.NET开源 ORM 框架 SqlSugar 系列【数据事务…...

嵌入式C编程:宏定义与typedef的深入对比与应用

目录 一、宏定义&#xff08;Macro Definition&#xff09; 1.1. 特点与应用 1.1.1 定义常量 1.1.2 定义函数式宏 1.1.3 条件编译 1.2. 作用范围和生命周期方面 1.3. 应用注意事项 二、typedef 2.1. 特点与应用 2.1.1 简化类型声明 2.1.2 提高代码可读性 2.1.3 实现…...

高级java每日一道面试题-2024年12月03日-JVM篇-什么是Stop The World? 什么是OopMap? 什么是安全点?

如果有遗漏,评论区告诉我进行补充 面试官: 什么是Stop The World? 什么是OopMap? 什么是安全点? 我回答: 在Java虚拟机&#xff08;JVM&#xff09;中&#xff0c;Stop The World、OopMap 和 安全点 是与垃圾回收&#xff08;GC&#xff09;和性能优化密切相关的概念。理…...

【openGauss︱PostgreSQL】openGauss或PostgreSQL查表、索引、序列、权限、函数

【openGauss︱PostgreSQL】openGauss或PostgreSQL查表、索引、序列、权限、函数 一、openGauss查表二、openGauss查索引三、openGauss查序列四、openGauss查权限五、openGauss或PostgreSQL查函数六、PostgreSQL查表七、PostgreSQL查索引八、PostgreSQL查序列九、PostgreSQL查权…...

Dataset用load_dataset读图片和对应的caption的一个坑

代码&#xff1a; data_files {} if args.train_data_dir is not None:data_files["train"] os.path.join(args.train_data_dir, "**")dataset load_dataset("imagefolder",data_filesdata_files,cache_dirargs.cache_dir,) 数据&#xff1…...

【信息系统项目管理师】第7章:项目立项管理 考点梳理

文章目录 7.1 项目建议与立项申请7.2 项目可行性研究7.2.1 可行性研究的内容7.2.2 初步可行性研究7.2.3 详细可行性研究&#xff08;重点&#xff09; 7.3 项目评估与决策 【学习建议】本章大概考选择题2分左右&#xff0c;有可能考案例题。论文早年考过。本章知识点比较集中&a…...

知识库、提示词对大语言模型的影响测试

简介 通过对比有无知识库&#xff0c;测试大语言模型的回答 有无提示词对比测试 前提 大语言模型&#xff1a;Qwen1.5-1.8B-Chat-GPTQ-Int4 GPU&#xff1a;1650super&#xff0c;显存4G 提问&#xff1a;华为mate70 没有提示词 回答的内容如下 “华为mate70pro和mate40p…...

vistat-监控和分析网络状态

vistat 是一个用于监控和分析网络状态的工具&#xff0c;通常用于查看网络接口、流量、连接等实时数据。 原理&#xff1a;用户态调用系统接口获取内核中的网络统计信息。 核心功能&#xff1a;网络接口流量监控、查看连接状态、带宽使用分析。 使用方法&#xff1a; 查看接…...

EasyAnimateV5 视频生成大模型原理详解与模型使用

在数字内容创作中&#xff0c;视频扮演的角色日益重要。然而&#xff0c;创作高质量视频通常耗时且昂贵。EasyAnimate 系列旨在利用人工智能技术简化这一过程。EasyAnimateV5 建立在其前代版本的基础之上&#xff0c;不仅在质量上有所提升&#xff0c;还在多模态数据处理和跨语…...

水稻和拟南芥生命周期中单碱基分辨率的m6A定量分析-文献精读88

Quantitative profiling of m6A at single base resolution across the life cycle of rice and Arabidopsis 水稻和拟南芥生命周期中单碱基分辨率的m6A定量分析 水稻参考基因组&#xff08;日本晴品种&#xff09;-CSDN博客 “Xian”&#xff08;籼&#xff09;和“Geng”&…...

学习threejs,使用canvas更新纹理

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️Texture 贴图 二、&#x1…...

【笔记2-3】ESP32 bug:PSRAM chip not found or not supported 没有外部PSRAM问题解决

主要参考b站宸芯IOT老师的视频&#xff0c;记录自己的笔记&#xff0c;老师讲的主要是linux环境&#xff0c;但配置过程实在太多问题&#xff0c;就直接用windows环境了&#xff0c;老师也有讲一些windows的操作&#xff0c;只要代码会写&#xff0c;操作都还好&#xff0c;开发…...

CTF show Web 红包题第六弹

提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框&#xff0c;很难让人不联想到SQL注入&#xff0c;但提示都说了不是SQL注入&#xff0c;所以就不往这方面想了 ​ 先查看一下网页源码&#xff0c;发现一段JavaScript代码&#xff0c;有一个关键类ctfs…...

Debian系统简介

目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版&#xff…...

NFT模式:数字资产确权与链游经济系统构建

NFT模式&#xff1a;数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新&#xff1a;构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议&#xff1a;基于LayerZero协议实现以太坊、Solana等公链资产互通&#xff0c;通过零知…...

AI编程--插件对比分析:CodeRider、GitHub Copilot及其他

AI编程插件对比分析&#xff1a;CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展&#xff0c;AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者&#xff0c;分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...

九天毕昇深度学习平台 | 如何安装库?

pip install 库名 -i https://pypi.tuna.tsinghua.edu.cn/simple --user 举个例子&#xff1a; 报错 ModuleNotFoundError: No module named torch 那么我需要安装 torch pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple --user pip install 库名&#x…...

安宝特方案丨船舶智造的“AR+AI+作业标准化管理解决方案”(装配)

船舶制造装配管理现状&#xff1a;装配工作依赖人工经验&#xff0c;装配工人凭借长期实践积累的操作技巧完成零部件组装。企业通常制定了装配作业指导书&#xff0c;但在实际执行中&#xff0c;工人对指导书的理解和遵循程度参差不齐。 船舶装配过程中的挑战与需求 挑战 (1…...

关于easyexcel动态下拉选问题处理

前些日子突然碰到一个问题&#xff0c;说是客户的导入文件模版想支持部分导入内容的下拉选&#xff0c;于是我就找了easyexcel官网寻找解决方案&#xff0c;并没有找到合适的方案&#xff0c;没办法只能自己动手并分享出来&#xff0c;针对Java生成Excel下拉菜单时因选项过多导…...

libfmt: 现代C++的格式化工具库介绍与酷炫功能

libfmt: 现代C的格式化工具库介绍与酷炫功能 libfmt 是一个开源的C格式化库&#xff0c;提供了高效、安全的文本格式化功能&#xff0c;是C20中引入的std::format的基础实现。它比传统的printf和iostream更安全、更灵活、性能更好。 基本介绍 主要特点 类型安全&#xff1a…...

上位机开发过程中的设计模式体会(1):工厂方法模式、单例模式和生成器模式

简介 在我的 QT/C 开发工作中&#xff0c;合理运用设计模式极大地提高了代码的可维护性和可扩展性。本文将分享我在实际项目中应用的三种创造型模式&#xff1a;工厂方法模式、单例模式和生成器模式。 1. 工厂模式 (Factory Pattern) 应用场景 在我的 QT 项目中曾经有一个需…...

车载诊断架构 --- ZEVonUDS(J1979-3)简介第一篇

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 做到欲望极简,了解自己的真实欲望,不受外在潮流的影响,不盲从,不跟风。把自己的精力全部用在自己。一是去掉多余,凡事找规律,基础是诚信;二是…...