[oneAPI] 基于BERT预训练模型的SWAG问答任务

[oneAPI] 基于BERT预训练模型的SWAG问答任务

  • 基于Intel® DevCloud for oneAPI下的Intel® Optimization for PyTorch
  • 基于BERT预训练模型的SWAG问答任务
    • 数据集下载和描述
    • 数据集构建
    • 问答选择模型
    • 训练
  • 结果
  • 参考资料

比赛:https://marketing.csdn.net/p/f3e44fbfe46c465f4d9d6c23e38e0517
Intel® DevCloud for oneAPI:https://devcloud.intel.com/oneapi/get_started/aiAnalyticsToolkitSamples/

基于Intel® DevCloud for oneAPI下的Intel® Optimization for PyTorch

在Intel® DevCloud for oneAPI平台上,我们搭建了实验环境,充分发挥其完全虚拟化的优势,使我们能够专注于模型开发和优化,无需过多关心底层配置和维护工作。为了进一步提升我们的实验效果,我们充分利用了Intel® Optimization for PyTorch,将其应用于我们的PyTorch模型中,从而实现了高效的优化。这一优化策略不仅提升了模型的训练速度和推断性能,还使模型在英特尔硬件上的表现更加卓越,从而加速了实验的整体进程。

在我们的实验中,我们选择了Bert预训练模型,并将其应用于SQuAD英文问答任务中。通过数据预处理、Fine-tuning等步骤,我们成功地将Bert模型应用于问答任务中,取得了令人满意的效果。在这一过程中,Intel® Optimization for PyTorch的应用进一步加速了模型的训练和推断过程,提高了整体效率。

这一实验方案不仅仅是技术上的创新,更是在实际应用中带来的价值。通过提升模型的性能,我们不仅可以更快地训练和部署模型,还可以提供更高质量的问答结果,从而提升用户体验。这对于自然语言处理领域的研究和应用都具有重要意义。
在这里插入图片描述

基于BERT预训练模型的SWAG问答任务

SWAG任务是一项常见的自然语言处理任务,旨在对给定的句子上下文中的多个选项进行排列,从而确定最可能的下一句。该任务有助于模型理解句子的语境和逻辑,具有广泛的应用价值。下来介绍该任务的我们使用的解决方案:

  • 数据准备: 首先,从SWAG数据集中获取句子上下文和多个选项。每个样本包含一个上下文句子以及四个候选选项,其中一个是正确的。需要将这些文本数据转换成Bert模型可以理解的输入格式。
  • 预训练模型选择: 选择合适的预训练Bert模型,如BERT-base或BERT-large。这些模型在大规模语料库上进行了预训练,捕捉了丰富的语义信息。
  • Fine-tuning: 将预训练的Bert模型应用于SWAG任务,使用已标注的训练数据进行Fine-tuning。在Fine-tuning时,使用正确的选项作为标签,通过最大化正确选项的预测概率来优化模型。
  • 模型推断: 使用Fine-tuned的模型对测试数据进行预测,从多个选项中选择最可能的下一句。

数据集下载和描述

在这里,我们使用到的也是论文中所提到的SWAG(The Situations With Adversarial Generations )数据集,即给定一个情景(一个问题或一句描述),任务是模型从给定的四个选项中预测最有可能的一个。

如下所示便是部分原始示例数据:

1 ,video-id,fold-ind,startphrase,sent1,sent2,gold-source,ending0,ending1,ending2,ending3,label
2 0,anetv_NttjvRpSdsI,19391,The people are in robes. They,The people are in robes.,They,gold,are wearing colorful costumes.,are doing karate moves on the floor.,shake hands on their hips.,do a flip to the bag.,0
3 1,lsmdc3057_ROBIN_HOOD-27684,16344,She smirks at someone and rides off. He,She smirks at someone and rides off.,He,gold,smiles and falls heavily.,wears a bashful smile.,kneels down behind her.,gives him a playful glance.,1

如上所示数据集中一共有12个字段包含两个样本,我们这里需要用到的就是sent1,ending0,ending1,ending2,ending3,label这6个字段。例如对于第一个样本来说,其形式如下:

The people are in robes. TheyA) wearing colorful costumes.# 正确选项B) are doing karate moves on the floor.C) shake hands on their hips.  D) do a flip to the bag.

同时,由于该数据集已经做了训练集、验证集和测试集(没有标签)的划分,所以后续我们也就不需要来手动划分了。

数据集构建

import torch
from torch.utils.data import DataLoader
from tqdm import tqdm
import pandas as pd
import json
import logging
import os
from sklearn.model_selection import train_test_split
import collections
import sixclass Vocab:"""根据本地的vocab文件,构造一个词表vocab = Vocab()print(vocab.itos)  # 得到一个列表,返回词表中的每一个词;print(vocab.itos[2])  # 通过索引返回得到词表中对应的词;print(vocab.stoi)  # 得到一个字典,返回词表中每个词的索引;print(vocab.stoi['我'])  # 通过单词返回得到词表中对应的索引print(len(vocab))  # 返回词表长度"""UNK = '[UNK]'def __init__(self, vocab_path):self.stoi = {}self.itos = []with open(vocab_path, 'r', encoding='utf-8') as f:for i, word in enumerate(f):w = word.strip('\n')self.stoi[w] = iself.itos.append(w)def __getitem__(self, token):return self.stoi.get(token, self.stoi.get(Vocab.UNK))def __len__(self):return len(self.itos)def build_vocab(vocab_path):"""vocab = Vocab()print(vocab.itos)  # 得到一个列表,返回词表中的每一个词;print(vocab.itos[2])  # 通过索引返回得到词表中对应的词;print(vocab.stoi)  # 得到一个字典,返回词表中每个词的索引;print(vocab.stoi['我'])  # 通过单词返回得到词表中对应的索引"""return Vocab(vocab_path)def pad_sequence(sequences, batch_first=False, max_len=None, padding_value=0):"""对一个List中的元素进行paddingPad a list of variable length Tensors with ``padding_value``a = torch.ones(25)b = torch.ones(22)c = torch.ones(15)pad_sequence([a, b, c],max_len=None).size()torch.Size([25, 3])sequences:batch_first: 是否把batch_size放到第一个维度padding_value:max_len :当max_len = 50时,表示以某个固定长度对样本进行padding,多余的截掉;当max_len=None是,表示以当前batch中最长样本的长度对其它进行padding;Returns:"""if max_len is None:max_len = max([s.size(0) for s in sequences])out_tensors = []for tensor in sequences:if tensor.size(0) < max_len:tensor = torch.cat([tensor, torch.tensor([padding_value] * (max_len - tensor.size(0)))], dim=0)else:tensor = tensor[:max_len]out_tensors.append(tensor)out_tensors = torch.stack(out_tensors, dim=1)if batch_first:return out_tensors.transpose(0, 1)return out_tensorsdef cache(func):"""本修饰器的作用是将SQuAD数据集中data_process()方法处理后的结果进行缓存,下次使用时可直接载入!:param func::return:"""def wrapper(*args, **kwargs):filepath = kwargs['filepath']postfix = kwargs['postfix']data_path = filepath.split('.')[0] + '_' + postfix + '.pt'if not os.path.exists(data_path):logging.info(f"缓存文件 {data_path} 不存在,重新处理并缓存!")data = func(*args, **kwargs)with open(data_path, 'wb') as f:torch.save(data, f)else:logging.info(f"缓存文件 {data_path} 存在,直接载入缓存文件!")with open(data_path, 'rb') as f:data = torch.load(f)return datareturn wrapperclass LoadSingleSentenceClassificationDataset:def __init__(self,vocab_path='./vocab.txt',  #tokenizer=None,batch_size=32,max_sen_len=None,split_sep='\n',max_position_embeddings=512,pad_index=0,is_sample_shuffle=True):""":param vocab_path: 本地词表vocab.txt的路径:param tokenizer::param batch_size::param max_sen_len: 在对每个batch进行处理时的配置;当max_sen_len = None时,即以每个batch中最长样本长度为标准,对其它进行padding当max_sen_len = 'same'时,以整个数据集中最长样本为标准,对其它进行padding当max_sen_len = 50, 表示以某个固定长度符样本进行padding,多余的截掉;:param split_sep: 文本和标签之前的分隔符,默认为'\t':param max_position_embeddings: 指定最大样本长度,超过这个长度的部分将本截取掉:param is_sample_shuffle: 是否打乱训练集样本(只针对训练集)在后续构造DataLoader时,验证集和测试集均指定为了固定顺序(即不进行打乱),修改程序时请勿进行打乱因为当shuffle为True时,每次通过for循环遍历data_iter时样本的顺序都不一样,这会导致在模型预测时返回的标签顺序与原始的顺序不一样,不方便处理。"""self.tokenizer = tokenizerself.vocab = build_vocab(vocab_path)self.PAD_IDX = pad_indexself.SEP_IDX = self.vocab['[SEP]']self.CLS_IDX = self.vocab['[CLS]']# self.UNK_IDX = '[UNK]'self.batch_size = batch_sizeself.split_sep = split_sepself.max_position_embeddings = max_position_embeddingsif isinstance(max_sen_len, int) and max_sen_len > max_position_embeddings:max_sen_len = max_position_embeddingsself.max_sen_len = max_sen_lenself.is_sample_shuffle = is_sample_shuffle@cachedef data_process(self, filepath, postfix='cache'):"""将每一句话中的每一个词根据字典转换成索引的形式,同时返回所有样本中最长样本的长度:param filepath: 数据集路径:return:"""raw_iter = open(filepath, encoding="utf8").readlines()data = []max_len = 0for raw in tqdm(raw_iter, ncols=80):line = raw.rstrip("\n").split(self.split_sep)s, l = line[0], line[1]tmp = [self.CLS_IDX] + [self.vocab[token] for token in self.tokenizer(s)]if len(tmp) > self.max_position_embeddings - 1:tmp = tmp[:self.max_position_embeddings - 1]  # BERT预训练模型只取前512个字符tmp += [self.SEP_IDX]tensor_ = torch.tensor(tmp, dtype=torch.long)l = torch.tensor(int(l), dtype=torch.long)max_len = max(max_len, tensor_.size(0))data.append((tensor_, l))return data, max_lendef load_train_val_test_data(self, train_file_path=None,val_file_path=None,test_file_path=None,only_test=False):postfix = str(self.max_sen_len)test_data, _ = self.data_process(filepath=test_file_path, postfix=postfix)test_iter = DataLoader(test_data, batch_size=self.batch_size,shuffle=False, collate_fn=self.generate_batch)if only_test:return test_itertrain_data, max_sen_len = self.data_process(filepath=train_file_path,postfix=postfix)  # 得到处理好的所有样本if self.max_sen_len == 'same':self.max_sen_len = max_sen_lenval_data, _ = self.data_process(filepath=val_file_path,postfix=postfix)train_iter = DataLoader(train_data, batch_size=self.batch_size,  # 构造DataLoadershuffle=self.is_sample_shuffle, collate_fn=self.generate_batch)val_iter = DataLoader(val_data, batch_size=self.batch_size,shuffle=False, collate_fn=self.generate_batch)return train_iter, test_iter, val_iterdef generate_batch(self, data_batch):batch_sentence, batch_label = [], []for (sen, label) in data_batch:  # 开始对一个batch中的每一个样本进行处理。batch_sentence.append(sen)batch_label.append(label)batch_sentence = pad_sequence(batch_sentence,  # [batch_size,max_len]padding_value=self.PAD_IDX,batch_first=False,max_len=self.max_sen_len)batch_label = torch.tensor(batch_label, dtype=torch.long)return batch_sentence, batch_labelclass LoadMultipleChoiceDataset(LoadSingleSentenceClassificationDataset):def __init__(self, num_choice=4, **kwargs):super(LoadMultipleChoiceDataset, self).__init__(**kwargs)self.num_choice = num_choice@cachedef data_process(self, filepath, postfix='cache'):data = pd.read_csv(filepath)questions = data['startphrase']answers0, answers1 = data['ending0'], data['ending1']answers2, answers3 = data['ending2'], data['ending3']labels = [-1] * len(questions)if 'label' in data:  # 测试集中没有标签labels = data['label']all_data = []max_len = 0for i in tqdm(range(len(questions)), ncols=80):# 将问题中的每个word转换为字典中的token idt_q = [self.vocab[token] for token in self.tokenizer(questions[i])]t_q = [self.CLS_IDX] + t_q + [self.SEP_IDX]# 将答案中的每个word转换为字典中的token idt_a0 = [self.vocab[token] for token in self.tokenizer(answers0[i])]t_a1 = [self.vocab[token] for token in self.tokenizer(answers1[i])]t_a2 = [self.vocab[token] for token in self.tokenizer(answers2[i])]t_a3 = [self.vocab[token] for token in self.tokenizer(answers3[i])]# 计算最长序列的长度max_len = max(max_len, len(t_q) + max(len(t_a0), len(t_a1), len(t_a2), len(t_a3)))seg_q = [0] * len(t_q)# 加1表示还要加上问题和答案组合后最后一个[SEP]的长度seg_a0 = [1] * (len(t_a0) + 1)seg_a1 = [1] * (len(t_a1) + 1)seg_a2 = [1] * (len(t_a2) + 1)seg_a3 = [1] * (len(t_a3) + 1)all_data.append((t_q, t_a0, t_a1, t_a2, t_a3, seg_q,seg_a0, seg_a1, seg_a2, seg_a3, labels[i]))return all_data, max_lendef generate_batch(self, data_batch):batch_qa, batch_seg, batch_label = [], [], []def get_seq(q, a):seq = q + aif len(seq) > self.max_position_embeddings - 1:seq = seq[:self.max_position_embeddings - 1]return torch.tensor(seq + [self.SEP_IDX], dtype=torch.long)for item in data_batch:# 得到 每个问题组合其中一个答案的 input_ids 序列tmp_qa = [get_seq(item[0], item[1]),get_seq(item[0], item[2]),get_seq(item[0], item[3]),get_seq(item[0], item[4])]# 得到 每个问题组合其中一个答案的 token_type_idsseg0 = (item[5] + item[6])[:self.max_position_embeddings]seg1 = (item[5] + item[7])[:self.max_position_embeddings]seg2 = (item[5] + item[8])[:self.max_position_embeddings]seg3 = (item[5] + item[9])[:self.max_position_embeddings]tmp_seg = [torch.tensor(seg0, dtype=torch.long),torch.tensor(seg1, dtype=torch.long),torch.tensor(seg2, dtype=torch.long),torch.tensor(seg3, dtype=torch.long)]batch_qa.extend(tmp_qa)batch_seg.extend(tmp_seg)batch_label.append(item[-1])batch_qa = pad_sequence(batch_qa,  # [batch_size*num_choice,max_len]padding_value=self.PAD_IDX,batch_first=True,max_len=self.max_sen_len)batch_mask = (batch_qa == self.PAD_IDX).view([-1, self.num_choice, batch_qa.size(-1)])# reshape 至 [batch_size, num_choice, max_len]batch_qa = batch_qa.view([-1, self.num_choice, batch_qa.size(-1)])batch_seg = pad_sequence(batch_seg,  # [batch_size*num_choice,max_len]padding_value=self.PAD_IDX,batch_first=True,max_len=self.max_sen_len)# reshape 至 [batch_size, num_choice, max_len]batch_seg = batch_seg.view([-1, self.num_choice, batch_seg.size(-1)])batch_label = torch.tensor(batch_label, dtype=torch.long)return batch_qa, batch_seg, batch_mask, batch_label

问答选择模型

我们只需要在原始BERT模型的基础上再加一个分类层即可,因此这部分代码相对来说也比较容易理解

定义一个类以及相应的初始化函数

from model.Bert import BertModel
import torch.nn as nnclass BertForMultipleChoice(nn.Module):"""用于类似SWAG数据集的下游任务"""def __init__(self, config, bert_pretrained_model_dir=None):super(BertForMultipleChoice, self).__init__()self.num_choice = config.num_labelsif bert_pretrained_model_dir is not None:self.bert = BertModel.from_pretrained(config, bert_pretrained_model_dir)else:self.bert = BertModel(config)self.dropout = nn.Dropout(config.hidden_dropout_prob)self.classifier = nn.Linear(config.hidden_size, 1)def forward(self, input_ids,attention_mask=None,token_type_ids=None,position_ids=None,labels=None):""":param input_ids: [batch_size, num_choice, src_len]:param attention_mask: [batch_size, num_choice, src_len]:param token_type_ids: [batch_size, num_choice, src_len]:param position_ids::param labels::return:"""flat_input_ids = input_ids.view(-1, input_ids.size(-1)).transpose(0, 1)flat_token_type_ids = token_type_ids.view(-1, token_type_ids.size(-1)).transpose(0, 1)flat_attention_mask = attention_mask.view(-1, token_type_ids.size(-1))pooled_output, _ = self.bert(input_ids=flat_input_ids,  # [src_len,batch_size*num_choice]attention_mask=flat_attention_mask,  # [batch_size*num_choice,src_len]token_type_ids=flat_token_type_ids,  # [src_len,batch_size*num_choice]position_ids=position_ids)pooled_output = self.dropout(pooled_output)  # [batch_size*num_choice, hidden_size]logits = self.classifier(pooled_output)  # [batch_size*num_choice, 1]shaped_logits = logits.view(-1, self.num_choice)  # [batch_size, num_choice]if labels is not None:loss_fct = nn.CrossEntropyLoss()loss = loss_fct(shaped_logits, labels.view(-1))return loss, shaped_logitselse:return shaped_logits

定义一个ModelConfig类来对分类模型中的超参数以及其它变量进行管理,代码如下所示:

class ModelConfig:def __init__(self):self.project_dir = os.path.dirname(os.path.abspath(__file__))self.dataset_dir = os.path.join(self.project_dir, 'MultipleChoice')self.pretrained_model_dir = os.path.join(self.project_dir, "weight")self.vocab_path = os.path.join(self.pretrained_model_dir, 'vocab.txt')self.device = torch.device('xpu' if torch.cuda.is_available() else 'cpu')self.train_file_path = os.path.join(self.dataset_dir, 'train.csv')self.val_file_path = os.path.join(self.dataset_dir, 'val.csv')self.test_file_path = os.path.join(self.dataset_dir, 'test.csv')self.model_save_dir = os.path.join(self.project_dir, 'cache')self.logs_save_dir = os.path.join(self.project_dir, 'logs')self.is_sample_shuffle = Trueself.batch_size = 16self.max_sen_len = Noneself.num_labels = 4  # num_choiceself.learning_rate = 2e-5self.epochs = 10self.model_val_per_epoch = 2logger_init(log_file_name='choice', log_level=logging.INFO,log_dir=self.logs_save_dir)if not os.path.exists(self.model_save_dir):os.makedirs(self.model_save_dir)# 把原始bert中的配置参数也导入进来bert_config_path = os.path.join(self.pretrained_model_dir, "config.json")bert_config = BertConfig.from_json_file(bert_config_path)for key, value in bert_config.__dict__.items():self.__dict__[key] = value# 将当前配置打印到日志文件中logging.info(" ### 将当前配置打印到日志文件中 ")for key, value in self.__dict__.items():logging.info(f"### {key} = {value}")

训练

最后,我们便可以通过如下方法完成整个模型的微调:

def train(config):model = BertForMultipleChoice(config,config.pretrained_model_dir)model_save_path = os.path.join(config.model_save_dir, 'model.pt')if os.path.exists(model_save_path):loaded_paras = torch.load(model_save_path)model.load_state_dict(loaded_paras)logging.info("## 成功载入已有模型,进行追加训练......")model = model.to(config.device)optimizer = torch.optim.Adam(model.parameters(), lr=config.learning_rate)'''Apply Intel Extension for PyTorch optimization against the model object and optimizer object.'''model, optimizer = ipex.optimize(model, optimizer=optimizer)model.train()bert_tokenize = BertTokenizer.from_pretrained(model_config.pretrained_model_dir).tokenizedata_loader = LoadMultipleChoiceDataset(vocab_path=config.vocab_path,tokenizer=bert_tokenize,batch_size=config.batch_size,max_sen_len=config.max_sen_len,max_position_embeddings=config.max_position_embeddings,pad_index=config.pad_token_id,is_sample_shuffle=config.is_sample_shuffle,num_choice=config.num_labels)train_iter, test_iter, val_iter = \data_loader.load_train_val_test_data(config.train_file_path,config.val_file_path,config.test_file_path)max_acc = 0for epoch in range(config.epochs):losses = 0start_time = time.time()for idx, (qa, seg, mask, label) in enumerate(train_iter):qa = qa.to(config.device)  # [src_len, batch_size]label = label.to(config.device)seg = seg.to(config.device)mask = mask.to(config.device)loss, logits = model(input_ids=qa,attention_mask=mask,token_type_ids=seg,position_ids=None,labels=label)optimizer.zero_grad()loss.backward()optimizer.step()losses += loss.item()acc = (logits.argmax(1) == label).float().mean()if idx % 10 == 0:logging.info(f"Epoch: {epoch}, Batch[{idx}/{len(train_iter)}], "f"Train loss :{loss.item():.3f}, Train acc: {acc:.3f}")if idx % 100 == 0:y_pred = logits.argmax(1).cpu()show_result(qa, y_pred, data_loader.vocab.itos, num_show=1)end_time = time.time()train_loss = losses / len(train_iter)logging.info(f"Epoch: {epoch}, Train loss: "f"{train_loss:.3f}, Epoch time = {(end_time - start_time):.3f}s")if (epoch + 1) % config.model_val_per_epoch == 0:acc, _ = evaluate(val_iter, model,config.device, inference=False)logging.info(f"Accuracy on val {acc:.3f}")if acc > max_acc:max_acc = acctorch.save(model.state_dict(), model_save_path)

结果

在这里插入图片描述

参考资料

基于BERT预训练模型的SWAG问答任务:https://mp.weixin.qq.com/s/GqsbMBNt9XcFIjmumR04Pg

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

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

相关文章

【Hadoop】HDFS读写流程和客户端命令使用

&#x1f341; 博主 "开着拖拉机回家"带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——&#x1f390;开着拖拉机回家_Linux,Java基础学习,大数据运维-CSDN博客 &#x1f390;✨&#x1f341; &#x1fa81;&#x1f341; 希望本文能够给您带来一定的…

一文速学-让神经网络不再神秘,一天速学神经网络基础-前向传播(三)

前言 思索了很久到底要不要出深度学习内容&#xff0c;毕竟在数学建模专栏里边的机器学习内容还有一大半算法没有更新&#xff0c;很多坑都没有填满&#xff0c;而且现在深度学习的文章和学习课程都十分的多&#xff0c;我考虑了很久决定还是得出神经网络系列文章&#xff0c;…

【Linux】深入理解文件缓冲区

文章目录 问题引入如何理解缓冲区缓冲区刷新策略问题解释模拟一个文件缓冲区 问题引入 首先看一段代码&#xff1a; #include <stdio.h> #include <string.h> int main() {const char *msg0"hello printf\n";const char *msg1"hello fwrite\n&quo…

Matlab(变量与文本读取)

目录 1.变量&#xff08;数据&#xff09;类型转换 1.1 字符 1.2 字符串 1.3 逻辑操作与赋值 2.Struct结构体数组 2.1函数的详细介绍&#xff1a; 2.1.1 cell2struct 2.1.1.1 垂直维度转换 2.1.1.2 水平维度转换 2.1.1.3 部分进行转换 2.1.2 rmfield 2.1.3 fieldnames(查…

HTTP 协议

目录 ​编辑一、HTTP 协议是什么 二、抓包工具的使用 三、HTTP 请求 1、认识 URL 2、认识方法 3、认识请求 “报头” HOST &#xff1a; Content-Length 和 Content-Type​编辑 User-Agent Referer Cookie 四、HTTP 响应 1、认识状态码 2、通过 form 表单构造 H…

最小化安装移动云大云操作系统--BCLinux-for-Euler-22.10-everything-x86_64-230316版

CentOS 结束技术支持&#xff0c;转为RHEL的前置stream版本后&#xff0c;国内开源Linux服务器OS生态转向了开源龙蜥和开源欧拉两大开源社区&#xff0c;对应衍生出了一系列商用Linux服务器系统。BCLinux-for-Euler-22.10是中国移动基于开源欧拉操作系统22.03社区版本深度定制的…

读书笔记-《ON JAVA 中文版》-摘要23[第二十章 泛型-2]

文章目录 第二十章 泛型5. 泛型擦除5.1 泛型擦除5.2 迁移兼容性5.3 擦除的问题5.4 边界处的动作 6. 补偿擦除7. 边界8. 通配符8.1 通配符8.2 逆变 9. 问题10. 动态类型安全11. 泛型异常 第二十章 泛型 普通的类和方法只能使用特定的类型&#xff1a;基本数据类型或类类型。如果…

WPF实战项目十二(API篇):配置AutoMapper

1、新建类库WPFProjectShared&#xff0c;在类库下新建文件夹Dtos&#xff0c;新建BaseDto.cs&#xff0c;继承INotifyPropertyChanged&#xff0c;实现通知更新。 public class BaseDto : INotifyPropertyChanged{public int Id { get; set; }public event PropertyChangedEv…

Go的基础运行方式和打包

目录 基础运行方式导入路径 打包技巧相关知识点 基础运行方式 // 文件名可以不是main&#xff0c;但包名和入口函数比如是main // main.go package main // 导入包的时候可以直接导入&#xff0c;也可以导入后指定包名&#xff0c; import ("fmt"godemo "githu…

nlp系列(7)三元组识别(Bert+CRF)pytorch

模型介绍 在实体识别中&#xff1a;使用了Bert模型&#xff0c;CRF模型 在关系识别中&#xff1a;使用了Bert模型的输出与实体掩码&#xff0c;进行一系列变化&#xff0c;得到关系 Bert模型介绍可以查看这篇文章&#xff1a;nlp系列&#xff08;2&#xff09;文本分类&…

linux c编程之“hello world”一

文章目录 hello world开始学习汇编文件 hello.s第1行第2行第3行第4行第5行第6行第7行第8行第9行第10行第11行第12行第13行 X [注]&#xff1a;环境说明&#xff1a; OS&#xff1a;CentOS 7 GCC&#xff1a; 4.8.5 其他环境下的结果可能不尽相同。 声明&#xff1a;本文是我的一…

Unity中的Unistorm3.0天气系统笔记

Unistorm是Unity中的一个天气系统&#xff0c;它功能强大&#xff0c;效果优美。本文所述UniStorm为3.0版本&#xff0c;仅用于学习之用。 一、如何设置【白天】、【黑夜】和【天气类型】&#xff1f; 在Running模式下&#xff0c;按下Esc按键&#xff0c;会【弹出】或者【隐…

Rancher上的应用服务报错:413 Request Entity Too Large

UI->rancher的ingress->UI前端(在nginx里面)->zuul->server 也就是说没经过一次http servlet 都要设置一下大小 1.rancher的ingress 当出现Request Entity Too Large时&#xff0c;是由于传输流超过1M。 1、需要在rancher的ingress中设置参数解决。 配置注释&a…

JavaScript—面向对象、作用域

C#&#xff1a;从类继承 js&#xff1a;从对象继承 什么叫继承&#xff1f; 模板&#xff08;类&#xff09; 原型继承&#xff08;实体&#xff09; 有一个对象存在&#xff0c;构造函数设置原型为这个对象 创建出来的对象就继承与这个对象&#xff08;从对象那里继承&am…

Linux线程概念

目录 一、页表详解 1.地址的属性 2.页框 3.页表录和页表项 二、认识线程 1.线程的概念 2.轻量级进程 三、线程的简单控制 1.线程的创建 2.PID和LWP 3.线程异常 4.线程的资源 &#xff08;1&#xff09;共享的资源 &#xff08;2&#xff09;独有的资源 5.线程的…

mysql 存储引擎系列 (一) 基础知识

当前支持存储引擎 show engines&#xff1b; 显示默认存储引擎 select default_storage_engine; show variables like ‘%storage%’; 修改默认引擎 set default_storage_enginexxx 或 set default_storage_enginexxx; my.ini 或者 my.cnf ,需要重启 服务才能生效 systemctl …

cortex-A7核LED灯实验--STM32MP157

实验目的&#xff1a;实现LED1 / LED2 / LED3三盏灯工作 一&#xff0c;分析电路图 1&#xff0c;思路 分析电路图可知&#xff1a; 网络编号 引脚编号 LED1 PE10 LED2 > PF10 LED3 > PE8 2&#xff0c;工作原理&#xff1a; 写1&#xff1a;LED灯亮&#xf…

防雷检测综合应用方案

防雷检测是指对建筑物的防雷装置进行定期或不定期的检测&#xff0c;以评估其性能和安全状况&#xff0c;发现并消除隐患&#xff0c;保障人身和财产安全的一项重要工作。防雷检测的内容包括对接闪器、避雷带、引下线、接地装置、等电位联结、避雷器等部件的形式、位置、连接、…

RecyclerView面试问答

RecycleView 和 ListView对比: 使用方法上 ListView:继承重写 BaseAdapter,自定义 ViewHolder 与 converView优化。 RecyclerView: 继承重写 RecyclerView.Adapter 与 RecyclerView.ViewHolder。设置 LayoutManager 来展示不同的布局样式 ViewHolder的编写规范化,ListVie…

Spring security报栈溢出几种可能的情况

今天在运行spring security的时候&#xff0c;发现出现了栈溢出的情况&#xff0c;总结可能性如下&#xff1a; 1.UserDetailsService的实现类没有加上Service注入到容器中&#xff0c;导致容器循环寻找UserDetailsService的实现类&#xff0c;最终发生栈溢出的现象。 解决方法…