Transformers实战(二)快速入门文本相似度、检索式对话机器人

Transformers实战(二)快速入门文本相似度、检索式对话机器人

1、文本相似度

1.1 文本相似度简介

  • 文本匹配是一个较为宽泛的概念,基本上只要涉及到两段文本之间关系的,都可以被看作是一种文本匹配的任务,

  • 只是在具体的场景下,不同的任务对匹配二字的定义可能是存在差异的,具体的任务场景包括文本相似度计算、问答匹配、对话匹配、文本推理等等,另外,如之前介绍的多项选择,本质上也是文本匹配

  • 本次重点关注文本相似度任务,即判断两段文本是不是表达了同样的语义

  • 文本相似度本质上是一个分类任务。

Sentence ASentence BLabel
找一部小时候的动画片求一部小时候的动画片。谢了1
别急呀,我的朋友。你一定要看我一下0
明天多少度啊明天气温多少度啊1
可怕的事情终于发生你到底想说什么?0

1.2 最直接的解决方案—交互策略

交互策略,就是输入句子对,对是否相似进行学习。

在这里插入图片描述

数据预处理方式如下:

在这里插入图片描述

交互策略的实现比较简单,类似于情感分析。

1.2.1 数据集预处理

数据集:https://github.com/CLUEbenchmark/SimCLUE/tree/main

预训练模型依然是哈工大开源的chinese-macbert-base

from transformers import AutoTokenizer, AutoModelForSequenceClassification, Trainer, TrainingArguments
from datasets import load_dataset

dataset = load_dataset("json", data_files="./train_pair_1w.json", split="train")
dataset[0:2]
{
 'sentence1': ['找一部小时候的动画片',
  '我不可能是一个有鉴赏能力的行家,小姐我把我的时间都花在书写上;象这样豪华的舞会,我还是头一次见到。'],
 'sentence2': ['求一部小时候的动画片。谢了', '蜡烛没熄就好了,夜黑得瘆人,情绪压抑。'],
 'label': ['1', '0']
 }
# 划分数据集
datasets = dataset.train_test_split(test_size=0.2)

# tokenizer = AutoTokenizer.from_pretrained("hfl/chinese-macbert-base")

# 离线加载
model_path = '/root/autodl-fs/models/chinese-macbert-base'
tokenizer = AutoTokenizer.from_pretrained(model_path)

def process_function(examples):
    tokenized_examples = tokenizer(examples["sentence1"], examples["sentence2"], max_length=128, truncation=True)
    tokenized_examples["labels"] = [float(label) for label in examples["label"]]
    return tokenized_examples


tokenized_datasets = datasets.map(process_function, batched=True, remove_columns=datasets["train"].column_names)
tokenized_datasets
DatasetDict({
    train: Dataset({
        features: ['input_ids', 'token_type_ids', 'attention_mask', 'labels'],
        num_rows: 8000
    })
    test: Dataset({
        features: ['input_ids', 'token_type_ids', 'attention_mask', 'labels'],
        num_rows: 2000
    })
})
print(tokenized_datasets["train"][0])
{
'input_ids': [101, 1062, 4265, 1920, 782, 8024, 1963, 3362, 2769, 1762, 6878, 1168, 2600, 1385, 808, 1184, 6878, 1168, 4640, 2370, 7363, 678, 8024, 6929, 6421, 2582, 720, 1215, 8043, 102, 800, 2697, 6230, 2533, 800, 2190, 6821, 5439, 1928, 2094, 3683, 2190, 800, 1520, 1520, 6820, 779, 8024, 4507, 754, 800, 2190, 6821, 702, 782, 772, 4495, 4638, 3946, 2658, 679, 4881, 2544, 5010, 6629, 3341, 511, 102], 
'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], 
'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], 
'labels': 0.0
}

1.2.2 加载模型、创建评估函数

import evaluate

# 离线加载模型
model = AutoModelForSequenceClassification.from_pretrained(model_path, num_labels=1)



# 这里采用离线加载
accuracy_path = '/root/autodl-tmp/transformers-code/metrics/accuracy'
f1_path = '/root/autodl-tmp/transformers-code/metrics/f1'

acc_metric = evaluate.load(accuracy_path)
f1_metirc = evaluate.load(f1_path)


def eval_metric(eval_predict):
    predictions, labels = eval_predict
    predictions = [int(p > 0.5) for p in predictions]
    labels = [int(l) for l in labels]
    acc = acc_metric.compute(predictions=predictions, references=labels)
    f1 = f1_metirc.compute(predictions=predictions, references=labels)
    acc.update(f1)
    return acc

1.2.3 创建TrainingArguments及Trainer

train_args = TrainingArguments(output_dir="./cross_model",      # 输出文件夹
                               per_device_train_batch_size=16,  # 训练时的batch_size
                               per_device_eval_batch_size=16,  # 验证时的batch_size
                               logging_steps=10,                # log 打印的频率
                               evaluation_strategy="epoch",     # 评估策略
                               save_strategy="epoch",           # 保存策略
                               save_total_limit=3,              # 最大保存数
                               learning_rate=2e-5,              # 学习率
                               weight_decay=0.01,               # weight_decay
                               metric_for_best_model="f1",      # 设定评估指标
                               load_best_model_at_end=True)     # 训练完成后加载最优模型
from transformers import DataCollatorWithPadding
trainer = Trainer(model=model, 
                  args=train_args, 
                  train_dataset=tokenized_datasets["train"], 
                  eval_dataset=tokenized_datasets["test"], 
                  data_collator=DataCollatorWithPadding(tokenizer=tokenizer),
                  compute_metrics=eval_metric)
trainer.train()

在这里插入图片描述

1.2.4 模型预测

from transformers import pipeline

model.config.id2label = {0: "不相似", 1: "相似"}
pipe = pipeline("text-classification", model=model, tokenizer=tokenizer, device=0)

result = pipe({"text": "我喜欢北京", "text_pair": "天气怎样"}, function_to_apply="none")
result["label"] = "相似" if result["score"] > 0.5 else "不相似"
result
{'label': '不相似', 'score': 0.054742373526096344}

1.3 基于向量匹配的解决方案

如果从多个文本中,找到最相似的文本,应该如何做呢?

基于交互策略,我们可以借鉴之前多项选择,用相同的处理方式(如下图)。

在这里插入图片描述

但是这样效率极低,因为每次都需要与全量数据进行模型推理,数据量较大时很难满足时延要求。

基于向量匹配的方案可以解决。

我们可以将候选文本经过训练好的模型进行向量化,然后存到向量数据库中(如faiss)。然后将问题也同样向量化,去向量库中进行向量匹配。(这也是检索式机器人的思路,我们将在检索机器人中,将本章节训练好的向量模型作为预训练模型,对文本进行向量化,并将向量集合存到faiss中,进行向量匹配,这里仅仅训练出向量模型。)

在这里插入图片描述

那么,这个向量模型该如何进行训练呢?

向量匹配训练,分别对句子进行编码,目标是让两个相似句子的相似度分数尽可能接近1。

在这里插入图片描述

数据预处理与多项选择类似

在这里插入图片描述

注意:此时没有预定义模型,需要我们自己实现模型。

模型中的损失,我们可以用pytorch提供的余弦损失函数 torch.nn.CosineEmbeddingLoss

在这里插入图片描述

  • 余弦损失函数,常常用于评估两个向量的相似性,两个向量的余弦值越高,则相似性越高。

  • x:包括x1x2,即需要计算相似度的predictionGT

  • y:相当于人为给定的flag,决定按哪种方式计算得到loss的结果。

  • 注意:此时label应该为正负1

  • 如果需要约束使x1和x2尽可能的相似,那么就使用y=1predictionGT完全一致时,loss为0

input1 = torch.randn(100, 128)
input2 = torch.randn(100, 128)
cos = nn.CosineEmbeddingLoss(reduction='mean')

# # 需要初始化一个N维的1或-1
loss_flag = torch.ones([100]) 
output = cos(input1, input2, loss_flag)

print(output)	# tensor(1.0003)

1.3.1 数据预处理

数据集:https://github.com/CLUEbenchmark/SimCLUE/tree/main

预训练模型依然是哈工大开源的chinese-macbert-base

from transformers import AutoTokenizer, AutoModelForSequenceClassification, Trainer, TrainingArguments
from datasets import load_dataset
import torch

# 离线加载数据
dataset = load_dataset("json", data_files="./train_pair_1w.json", split="train")

# 数据集划分
datasets = dataset.train_test_split(test_size=0.2)


# 和多项选择相似的处理方式
model_path = '/root/autodl-fs/models/chinese-macbert-base'
tokenizer = AutoTokenizer.from_pretrained(model_path)

def process_function(examples):
    sentences = []
    labels = []
    for sen1, sen2, label in zip(examples["sentence1"], examples["sentence2"], examples["label"]):
        sentences.append(sen1)
        sentences.append(sen2)
        # 这里label处理为1和-1
        labels.append(1 if int(label) == 1 else -1)
    # input_ids, attention_mask, token_type_ids
    tokenized_examples = tokenizer(sentences, max_length=128, truncation=True, padding="max_length")
    tokenized_examples = {k: [v[i: i + 2] for i in range(0, len(v), 2)] for k, v in tokenized_examples.items()}
    tokenized_examples["labels"] = labels
    return tokenized_examples

tokenized_datasets = datasets.map(process_function, batched=True, remove_columns=datasets["train"].column_names)
tokenized_datasets
DatasetDict({
    train: Dataset({
        features: ['input_ids', 'token_type_ids', 'attention_mask', 'labels'],
        num_rows: 8000
    })
    test: Dataset({
        features: ['input_ids', 'token_type_ids', 'attention_mask', 'labels'],
        num_rows: 2000
    })
})

1.3.2 自定义训练模型

from transformers import BertForSequenceClassification, BertPreTrainedModel, BertModel
from typing import Optional
from transformers.configuration_utils import PretrainedConfig
from torch.nn import CosineSimilarity, CosineEmbeddingLoss

class DualModel(BertPreTrainedModel):

    def __init__(self, config: PretrainedConfig, *inputs, **kwargs):
        super().__init__(config, *inputs, **kwargs)
        self.bert = BertModel(config)
        self.post_init()

    def forward(
        self,
        input_ids: Optional[torch.Tensor] = None,
        attention_mask: Optional[torch.Tensor] = None,
        token_type_ids: Optional[torch.Tensor] = None,
        position_ids: Optional[torch.Tensor] = None,
        head_mask: Optional[torch.Tensor] = None,
        inputs_embeds: Optional[torch.Tensor] = None,
        labels: Optional[torch.Tensor] = None,
        output_attentions: Optional[bool] = None,
        output_hidden_states: Optional[bool] = None,
        return_dict: Optional[bool] = None,
    ):
        return_dict = return_dict if return_dict is not None else self.config.use_return_dict

        # Step1 分别获取sentenceA 和 sentenceB的输入
        senA_input_ids, senB_input_ids = input_ids[:, 0], input_ids[:, 1]
        senA_attention_mask, senB_attention_mask = attention_mask[:, 0], attention_mask[:, 1]
        senA_token_type_ids, senB_token_type_ids = token_type_ids[:, 0], token_type_ids[:, 1]

        # Step2 分别获取sentenceA 和 sentenceB的向量表示
        senA_outputs = self.bert(
            senA_input_ids,
            attention_mask=senA_attention_mask,
            token_type_ids=senA_token_type_ids,
            position_ids=position_ids,
            head_mask=head_mask,
            inputs_embeds=inputs_embeds,
            output_attentions=output_attentions,
            output_hidden_states=output_hidden_states,
            return_dict=return_dict,
        )

        senA_pooled_output = senA_outputs[1]    # [batch, hidden]

        senB_outputs = self.bert(
            senB_input_ids,
            attention_mask=senB_attention_mask,
            token_type_ids=senB_token_type_ids,
            position_ids=position_ids,
            head_mask=head_mask,
            inputs_embeds=inputs_embeds,
            output_attentions=output_attentions,
            output_hidden_states=output_hidden_states,
            return_dict=return_dict,
        )

        senB_pooled_output = senB_outputs[1]    # [batch, hidden]

        # step3 计算相似度
        cos = CosineSimilarity()(senA_pooled_output, senB_pooled_output)    # [batch, ]

        # step4 计算loss
        loss = None
        if labels is not None:
            loss_fct = CosineEmbeddingLoss(0.3)
            loss = loss_fct(senA_pooled_output, senB_pooled_output, labels)

        output = (cos,)
        return ((loss,) + output) if loss is not None else output
    
model = DualModel.from_pretrained(model_path)

1.3.3 创建评估函数

import evaluate

# 这里采用离线加载
accuracy_path = '/root/autodl-tmp/transformers-code/metrics/accuracy'
f1_path = '/root/autodl-tmp/transformers-code/metrics/f1'

acc_metric = evaluate.load(accuracy_path)
f1_metirc = evaluate.load(f1_path)


def eval_metric(eval_predict):
    predictions, labels = eval_predict
    predictions = [int(p > 0.7) for p in predictions]
    labels = [int(l > 0) for l in labels]
    acc = acc_metric.compute(predictions=predictions, references=labels)
    f1 = f1_metirc.compute(predictions=predictions, references=labels)
    acc.update(f1)
    return acc

1.3.4 创建TrainingArguments及Trainer

train_args = TrainingArguments(output_dir="./dual_model",      # 输出文件夹
                               per_device_train_batch_size=32,  # 训练时的batch_size
                               per_device_eval_batch_size=32,  # 验证时的batch_size
                               logging_steps=10,                # log 打印的频率
                               evaluation_strategy="epoch",     # 评估策略
                               save_strategy="epoch",           # 保存策略
                               save_total_limit=3,              # 最大保存数
                               learning_rate=2e-5,              # 学习率
                               weight_decay=0.01,               # weight_decay
                               metric_for_best_model="f1",      # 设定评估指标
                               load_best_model_at_end=True)     # 训练完成后加载最优模型
trainer = Trainer(model=model, 
                  args=train_args, 
                  train_dataset=tokenized_datasets["train"], 
                  eval_dataset=tokenized_datasets["test"], 
                  compute_metrics=eval_metric)
trainer.train()

在这里插入图片描述

1.3.5 自定义pipeline实现模型评估

class SentenceSimilarityPipeline:

    def __init__(self, model, tokenizer) -> None:
        self.model = model.bert
        self.tokenizer = tokenizer
        self.device = model.device

    def preprocess(self, senA, senB):
        return self.tokenizer([senA, senB], max_length=128, truncation=True, return_tensors="pt", padding=True)

    def predict(self, inputs):
        inputs = {k: v.to(self.device) for k, v in inputs.items()}
        return self.model(**inputs)[1]  # [2, 768]

    def postprocess(self, logits):
        cos = CosineSimilarity()(logits[None, 0, :], logits[None,1, :]).squeeze().cpu().item()
        return cos

    def __call__(self, senA, senB, return_vector=False):
        inputs = self.preprocess(senA, senB)
        logits = self.predict(inputs)
        result = self.postprocess(logits)
        if return_vector:
            return result, logits
        else:
            return result
pipe = SentenceSimilarityPipeline(model, tokenizer)

pipe("我喜欢北京", "明天不行", return_vector=True)
(0.4414671063423157,
 tensor([[ 0.8044, -0.7820,  0.9974,  ..., -0.6317, -0.9653, -0.4989],
         [ 0.3756,  0.0484,  0.9767,  ..., -0.9928, -0.9980, -0.5648]],
        device='cuda:0', grad_fn=<TanhBackward0>))

注:文本向量化更加便捷有效的工具

  • sentence-transformers

https://www.sbert.net/

  • text2vec

https://github.com/shibing624/text2vec

  • uniem

https://github.com/wangyuxinwhy/uniem

2、检索式对话机器人

2.1 检索式对话机器人简介

  • 对话机器人在本质上是一个用来模拟人类对话或聊天的计算机程序,接收人类的自然语言作为输入并给出合适的回复

  • 按照任务类型划分,对话机器人简单的可以划分为闲聊机器人、问答机器人、任务型对话机器人

  • 按照答案产生的逻辑划分,对话机器人可以划分为检索式对话机器人和生成式对话机器人

如何实现基于检索的问答机器人?

QQ匹配策略

可以利用QQ匹配策略,即取最优结果的Q对应的Answer作为最终结果。

在这里插入图片描述

  • 但是使用向量匹配的模型效果并不好,很难直接取到最优结果

  • 因此引入基于交互策略模型。向量匹配模块又称为召回模块,交互策略的模块又称为排序模块

在这里插入图片描述

2.2 向量匹配和交互策略结合实现检索对话机器人

法律知道数据集
https://github.com/SophonPlus/ChineseNlpCorpus

预训练模型
1.2章节训练的交互模型
1.3章节训练的匹配模型

2.2.1 加载自己训练的向量匹配模型

import pandas as pd

data = pd.read_csv("./law_faq.csv")
data.head()

在这里插入图片描述

# dual_model.py文件中是自定义的DualModel
from dual_model import DualModel
from transformers import AutoTokenizer

# 加载自己训练好的模型
dual_model = DualModel.from_pretrained("../12-sentence_similarity/dual_model/checkpoint-500/")
dual_model = dual_model.cuda()
dual_model.eval()
print("匹配模型加载成功!")


# 加载tokenzier
model_path = '/root/autodl-fs/models/chinese-macbert-base'
tokenzier = AutoTokenizer.from_pretrained(model_path)

2.2.2 将知识库中的问题编码为向量

import torch
from tqdm import tqdm


questions = data["title"].to_list()
vectors = []
with torch.inference_mode():
    for i in tqdm(range(0, len(questions), 32)):
        batch_sens = questions[i: i + 32]
        inputs = tokenzier(batch_sens, return_tensors="pt", padding=True, max_length=128, truncation=True)
        inputs = {k: v.to(dual_model.device) for k, v in inputs.items()}
        # 这里拿出[CLS]的向量表示
        vector = dual_model.bert(**inputs)[1]
        vectors.append(vector)
vectors = torch.concat(vectors, dim=0).cpu().numpy()
vectors.shape
(18213, 768)

2.2.3 将知识库中的问题向量存入向量库中

# pip install faiss-cpu
import faiss

index = faiss.IndexFlatIP(768)
faiss.normalize_L2(vectors)
index.add(vectors)
index

2.2.4 将用户问题编码为向量

quesiton = "寻衅滋事"
with torch.inference_mode():
    inputs = tokenzier(quesiton, return_tensors="pt", padding=True, max_length=128, truncation=True)
    inputs = {k: v.to(dual_model.device) for k, v in inputs.items()}
    vector = dual_model.bert(**inputs)[1]
    q_vector = vector.cpu().numpy()
q_vector.shape
(1, 768)

2.2.5 向量匹配

faiss.normalize_L2(q_vector)
# 使用faiss进行搜索
scores, indexes = index.search(q_vector, 10)

# 将匹配到的相似问题及答案召回
topk_result = data.values[indexes[0].tolist()]

# 匹配到的相似问题
topk_result[:, 0]
array(['涉嫌寻衅滋事', '两个轻微伤够寻衅滋事', '敲诈勒索罪', '聚群斗殴', '飞达暴力催收', '打架斗殴',
       '涉嫌犯罪?????', '殴打他人治安处罚', '遵守法律的措施', '十级伤残工伤'], dtype=object)

2.2.6 加载自己训练的交互模型

from transformers import BertForSequenceClassification


corss_model = BertForSequenceClassification.from_pretrained("../12-sentence_similarity/cross_model/checkpoint-500/")
corss_model = corss_model.cuda()
corss_model.eval()
print("模型加载成功!")

2.2.7 最终的预测结果

# 候选问题集合
canidate = topk_result[:, 0].tolist()
ques = [quesiton] * len(canidate)
inputs = tokenzier(ques, canidate, return_tensors="pt", padding=True, max_length=128, truncation=True)
inputs = {k: v.to(corss_model.device) for k, v in inputs.items()}
with torch.inference_mode():
    logits = corss_model(**inputs).logits.squeeze()
    result = torch.argmax(logits, dim=-1)
result
tensor(0, device='cuda:0')
# 候选答案集合
canidate_answer = topk_result[:, 1].tolist()

match_quesiton = canidate[result.item()]
final_answer = canidate_answer[result.item()]
match_quesiton, final_answer
('涉嫌寻衅滋事',
 '说明具有寻衅滋事行为,应受到相应的处罚,行为人情形严重或行为恶劣的涉嫌了寻衅滋事罪。寻衅滋事是指行为人结伙斗殴的、追逐、拦截他人的、强拿硬要或者任意损毁、占用公私财物的、其他寻衅滋事的行为。寻衅滋事罪,是指在公共场所无事生非、起哄闹事,造成公共场所秩序严重混乱的,追逐、拦截、辱骂、恐吓他人,强拿硬要或者任意损毁、占用公私财物,破坏社会秩序,情节严重的行为。对于寻衅滋事行为的处罚:1、《中华人*共和国治安管理处罚法》第二十六条规定,有下列行为之一的,处五日以上十日以下拘留,可以并处五百元以下罚款;情节较重的,处十日以上十五日以下拘留,可以并处一千元以下罚款:()结伙斗殴的;()追逐、拦截他人的;()强拿硬要或者任意损毁、占用公私财物的;()其他寻衅滋事行为;...)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【JavaEE】HTTP协议

HTTP协议 HTTP是什么?HTTP 协议格式HTTP 请求格式HTTP响应格式协议格式总结 HTTP 请求 (Request)认识 URLURL 基本格式 关于 URL encode认识 "方法" (method)1. GET 方法2. POST 方法 认识请求 "报头" (header) HTTP 响应详解认识 "状态码" (st…

Elasticsearch:使用 Open AI 和 Langchain 的 RAG - Retrieval Augmented Generation (二)

这是继上一篇文章 “Elasticsearch&#xff1a;使用 Open AI 和 Langchain 的 RAG - Retrieval Augmented Generation &#xff08;一&#xff09;” 的续篇。在这篇文章中&#xff0c;我主要来讲述 ElasticVectorSearch 的使用。 我们的设置和之前的那篇文章是一样的&#xff…

idea中Run/Debug Python项目报错 Argument for @NotNull parameter ‘module‘ of ...

idea中Run/Debug Python项目报错 Argument for NotNull parameter module of ... idea中运行Python项目main.py时报错&#xff1a; Error running main: Argument for NotNull parameter module of com/intellij/openapi/roots/ModuleRootManager.getInstance must not be nu…

Flash Attention 的优点以及Softmax 归一化系数解释

文章&#xff1a;FLASHATTENTION: Fast and Memory-Efficient Exact Attention with IO-Awareness 原始Attention 计算使用gpu存储标准流程 涉及两个gpu存储器&#xff1a; 1&#xff09;SRAM&#xff08;static Random Access Memory&#xff09;:静态随机存取存储器 2&…

管理类联考——数学——汇总篇——知识点突破——代数——整式分式——记忆

文章目录 考点记忆/考点汇总——按大纲 整体目录大纲法记忆宫殿法绘图记忆法 局部数字编码法归类记忆法重点记忆法歌决记忆法谐音记忆法理解记忆法比较记忆法转图像记忆法可视化法 本篇思路&#xff1a;根据各方的资料&#xff0c;比如名师的资料&#xff0c;按大纲或者其他方式…

什么是全排列?(算法实现)

全排列是什么&#xff1f; 全排列是指将一组元素按照一定顺序进行排列的所有可能结果。以一组数字为例&#xff0c;比如[1, 2, 3]的全排列结果为&#xff1a;[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]。 全排列有许多不同的计算方法&#xff0c;其中…

【电路笔记】-交流电感和感抗

交流电感和感抗 文章目录 交流电感和感抗1、概述1.1 电感1.2 电感器 2、频率特性2.1 电抗(Reactance)2.2 相移2.3 感应现象 3、RL滤波器4、总结 在之前有 交流电阻的文章中&#xff0c;我们已经看到电阻器在正常频率下的直流或交流状态下的行为是相同的。 然而&#xff0c;其他…

CN考研真题知识点二轮归纳(1)

本轮开始更新真题中涉及过的知识点&#xff0c;总共不到20年的真题&#xff0c;大致会出5-10期&#xff0c;尽可能详细的讲解并罗列不重复的知识点~ 目录 1.三类IP地址网络号的取值范围 2.Socket的内容 3.邮件系统中向服务器获取邮件所用到的协议 4.RIP 5.DNS 6.CSMA/CD…

Linux云服务器限制ip进行ssh远程连接

对Linux云服务器限制IP进行SSH远程连接的原因主要有以下几点&#xff1a; 增加安全性&#xff1a;SSH是一种加密的网络传输协议&#xff0c;可以保护数据的机密性和完整性。通过限制SSH连接的IP地址&#xff0c;可以防止未经授权的访问和数据泄露。只有拥有访问权限的IP地址才…

Vue 路由指南:畅游单页应用的地图(Vue Router 和 <router-view>)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

【智能座舱系列】- 深度解密小米Hyper OS,华为HarmonyOS区别

上一篇文章《小米的澎湃OS到底牛不牛?与鸿蒙系统之间差距有多大》,从多个方面比较了小米Hyper OS 与 华为HarmonyOS的区别,本篇文章继续从架构层面深度解读两者本质的区别。 小米澎湃OS是“以人为中心,打造人车家全生态操作系统”,该系统基于深度进化的Android以及自研的V…

【JAVA学习笔记】52 - 本章作业

项目代码 https://github.com/yinhai1114/Java_Learning_Code/tree/main/IDEA_Chapter13/src/com/yinhai/wrapper_/homework_ 1.字符反转 注意String是final的不能改变需要toCharArray改成char数组 返回String需要将char改成valueOf改为String public class HomeWork01 {publ…

RabbitMQ学习01

四大核心概念 生产者 产生数据发送消息的程序是生产者 交换机 交换机是 RabbitMQ 非常重要的一个部件&#xff0c;一方面它接收来自生产者的消息&#xff0c;另一方面它将消息推送到队列中。交换机必须确切知道如何处理它接收到的消息&#xff0c;是将这些消息推送到特定队…

ZooKeeper中节点的操作命令(查看、创建、删除节点)

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

分治法求解棋盘覆盖问题

分治法求解棋盘覆盖问题 如何应用分治法求解棋盘覆盖问题呢&#xff1f;分治的技巧在于如何划分棋盘&#xff0c;使划分后的子棋盘的大小相同&#xff0c;并且每个子棋盘均包含一个特殊方格&#xff0c;从而将原问题分解为规模较小的棋盘覆盖问题。 基本思路 棋盘覆盖问题是…

【音视频|wav】wav音频文件格式详解

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; &#x1f923;本文内容&#x1f923;&a…

BLIP2中Q-former详解

简介 Querying Transformer&#xff0c;在冻结的视觉模型和大语言模型间进行视觉-语言对齐。 为了使Q-Former的学习达到两个目标&#xff1a; 学习到和文本最相关的视觉表示。 这种表示能够为大语言模型所解释。 需要在Q-Former结构设计和训练策略上下功夫。具体来说&…

零资源的大语言模型幻觉预防

零资源的大语言模型幻觉预防 摘要1 引言2 相关工作2.1 幻觉检测和纠正方法2.2 幻觉检测数据集 3 方法论3.1 概念提取3.2 概念猜测3.2.1 概念解释3.2.2 概念推理 3.3 聚合3.3.1 概念频率分数3.3.2 加权聚合 4 实验5 总结 摘要 大语言模型&#xff08;LLMs&#xff09;在各个领域…

Redis(windows+Linux)安装及入门

一、概述 Redis是什么&#xff1f; Redis(Remote Dictionary Server)&#xff0c;即远程字典服务 Redis&#xff08;Remote Dictionary Server )&#xff0c;即远程字典服务&#xff0c;是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数…

Android 主题 vs 样式

关于作者&#xff1a;CSDN内容合伙人、技术专家&#xff0c; 从零开始做日活千万级APP。 专注于分享各领域原创系列文章 &#xff0c;擅长java后端、移动开发、商业变现、人工智能等&#xff0c;希望大家多多支持。 目录 一、导读二、概览三、相关知识3.1 theme&#xff01; st…
最新文章