第二课:BERT

文章目录

  • 第二课:BERT
    • 1、学习总结:
      • 为什么要学习BERT?
      • 预训练模型的发展历程
      • BERT结构
        • BERT 输入
        • BERT Embedding
        • BERT 模型构建
        • BERT self-attention 层
        • BERT self-attention 输出层
        • BERT feed-forward 层
        • BERT 最后的Add&Norm
        • BERT Encoder
        • BERT 输出
        • BERT Pooler
      • BERT 预训练
        • Masked LM
        • NSP
        • BERT预训练代码整合
      • 课程ppt及代码地址
    • 2、学习心得:
    • 3、经验分享:
    • 4、课程反馈:
    • 5、使用MindSpore昇思的体验和反馈:
    • 6、未来展望:

第二课:BERT

1、学习总结:

为什么要学习BERT?

虽然目前decoder only的模型是业界主流,但是encoder 的模型bert规模较小,更适合新手作为第一个上手的大模型,这样后面学习其他的大模型就不会感觉到过于困难。

  • Decoder only模型当道: GPT3、Bloom、LLAMA、GLM

  • Transformer Encoder结构在生成式任务上的缺陷

  • BERT模型规模小

  • Pretrain-Fintune范式的落寞

  • 2022年以前,学术界还是在倒腾BERT

  • Finetune更容易针对单领域任务训练

    • BERT是首个大规模并行预训练的模型,也是当前的performance baseline

    • 由BERT入手学大模型训练、微调、Prompt最简单

预训练模型的发展历程

语言模型的演变经历了以下几个阶段:

image-20240120180908494

  1. word2vec/Glove将离散的文本数据转换为固定长度的静态词向量,后根据下游任务训练不同的语言模型

  2. ELMo预训练模型将文本数据结合上下文信息,转换为动态词向量,后根据下游任务训练不同的语言模型

  3. BERT同样将文本数据转换为动态词向量,能够更好地捕捉句子级别的信息与语境信息,后续只需finetune最后的输出层即可适配下游任务;

  4. GPT等预训练语言模型主要用于文本生成类任务,需要通过prompt方法来应用于下游任务,指导模型生成特定的输出。

BERT结构

BERT模型本质上是结合了ELMo模型与GPT模型的优势。

  • 相比于ELMo,BERT仅需改动最后的输出层,而非模型架构,便可以在下游任务中达到很好的效果;
  • 相比于GPT,BERT在处理词元表示时考虑到了双向上下文的信息;

BERT通过两种无监督任务(Masked Language Modelling 和 Next Sentence Prediction)进行预训练,其次,在下游任务中对预训练Transformer编码器的所有参数进行微调,额外的输出层将从头开始训练。

Reference: The Illustrated BERT, ELMo, and co. (How NLP Cracked Transfer Learning)

BERT(Bidirectional Encoder Representation from Transformers)是由Transformer的Encoder层堆叠而成,BERT的模型大小有如下两种:

  • BERT BASE:与Transformer参数量齐平,用于比较模型效果(110M parameters)
  • BERT LARGE:在BERT BASE基础上扩大参数量,达到了当时各任务最好的结果(340M parameters)
modelblockshidden sizeattention heads
Transformer65128
BERT BASE1276812
BERT LARGE24102416

Reference: BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding

接受输入序列后,BERT会输出每个位置对应的向量(长度等于hidden size),在后续下游任务中,我们会选取与任务相关的位置的向量,输入到最终输出层中得到结果。

如在诈骗邮件分类任务中,我们会将表示句子级别信息的[CLS] token所对应的vector,放入classfier中,得到对spam/not spam分类的预测。

BERT 输入
  • 针对句子对相关任务,将两个句子合并为一个句子对输入到Encoder中,[CLS] + 第一个句子 + [SEP] + 第二个句子 + [SEP];
  • 针对单个文本相关任务,[CLS] + 句子 +
    [SEP]

在诈骗邮件分类中,输入为单个句子,在拆分为tokens后,在序列首尾分别添加[CLS][SEP]即可。

# install mindnlp
!pip install git+https://openi.pcl.ac.cn/lvyufeng/mindnlpfrom mindnlp.transforms.tokenizers import BertTokenizer
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
sequence = 'help prince mayuko transfer huge inheritance'
model_inputs = tokenizer(sequence)
print(model_inputs)
tokens = []
for index in model_inputs:tokens.append(tokenizer.id_to_token(index))
print(tokens)
BERT Embedding

输入到BERT模型的信息由三部分内容组成:

  • 表示内容的token ids
  • 表示位置的position ids
  • 用于区分不同句子的token type ids

三种信息分别进入Embedding层,得到token embeddings、position embeddings与segment embeddings;与Transformer不同,以上三种均为可学习的信息。

image-20240120181709385

图片来源:Devlin, J.; Chang, M. W.; Lee, K.; Toutanova, K. BERT: Pre-training of deep bidirectional transformers for language understanding. arXiv preprint arXiv:1810.04805, 2018.

import mindspore
from mindspore import nn
import mindspore.common.dtype as mstype
from mindspore.common.initializer import initializer, TruncatedNormalclass BertEmbeddings(nn.Cell):"""Embeddings for BERT, include word, position and token_type"""def __init__(self, config):super().__init__()self.word_embeddings = nn.Embedding(config.vocab_size, config.hidden_size, embedding_table=TruncatedNormal(config.initializer_range))self.position_embeddings = nn.Embedding(config.max_position_embeddings, config.hidden_size, embedding_table=TruncatedNormal(config.initializer_range))self.token_type_embeddings = nn.Embedding(config.type_vocab_size, config.hidden_size, embedding_table=TruncatedNormal(config.initializer_range))self.layer_norm = nn.LayerNorm((config.hidden_size,), epsilon=config.layer_norm_eps)self.dropout = nn.Dropout(1 - config.hidden_dropout_prob)def construct(self, input_ids, token_type_ids=None, position_ids=None):seq_len = input_ids.shape[1]if position_ids is None:position_ids = mnp.arange(seq_len)position_ids = position_ids.expand_dims(0).expand_as(input_ids)if token_type_ids is None:token_type_ids = ops.zeros_like(input_ids)words_embeddings = self.word_embeddings(input_ids)position_embeddings = self.position_embeddings(position_ids)token_type_embeddings = self.token_type_embeddings(token_type_ids)embeddings = words_embeddings + position_embeddings + token_type_embeddingsembeddings = self.layer_norm(embeddings)embeddings = self.dropout(embeddings)return embeddings
BERT 模型构建

BERT模型的构建与上一节课程的Transformer Encoder构建类似。

分别构建multi-head attention层,feed-forward network,并在中间用add&norm连接,最后通过线性层与softmax层进行输出。

BERT self-attention 层

class BertSelfAttention(nn.Cell):"""Self attention layer for BERT."""def __init__(self,  config):super().__init__()if config.hidden_size % config.num_attention_heads != 0:raise ValueError(f"The hidden size {config.hidden_size} is not a multiple of the number of attention "f"heads {config.num_attention_heads}")self.output_attentions = config.output_attentionsself.num_attention_heads = config.num_attention_headsself.attention_head_size = int(config.hidden_size / config.num_attention_heads)self.all_head_size = self.num_attention_heads * self.attention_head_sizeself.query = nn.Dense(config.hidden_size, self.all_head_size, \weight_init=TruncatedNormal(config.initializer_range))self.key = nn.Dense(config.hidden_size, self.all_head_size, \weight_init=TruncatedNormal(config.initializer_range))self.value = nn.Dense(config.hidden_size, self.all_head_size, \weight_init=TruncatedNormal(config.initializer_range))self.dropout = Dropout(config.attention_probs_dropout_prob)self.softmax = nn.Softmax(-1)self.matmul = Matmul()def transpose_for_scores(self, input_x):"""transpose for scores[batch_size, seq_len, num_heads, head_size] to [batch_size, num_heads, seq_len, head_size]"""new_x_shape = input_x.shape[:-1] + (self.num_attention_heads, self.attention_head_size)input_x = input_x.view(*new_x_shape)return input_x.transpose(0, 2, 1, 3)def construct(self, hidden_states, attention_mask=None, head_mask=None):mixed_query_layer = self.query(hidden_states)mixed_key_layer = self.key(hidden_states)mixed_value_layer = self.value(hidden_states)query_layer = self.transpose_for_scores(mixed_query_layer)key_layer = self.transpose_for_scores(mixed_key_layer)value_layer = self.transpose_for_scores(mixed_value_layer)attention_scores = self.matmul(query_layer, key_layer.swapaxes(-1, -2))attention_scores = attention_scores / ops.sqrt(Tensor(self.attention_head_size, mstype.float32))if attention_mask is not None:attention_scores = attention_scores + attention_maskattention_probs = self.softmax(attention_scores)attention_probs = self.dropout(attention_probs)if head_mask is not None:attention_probs = attention_probs * head_maskcontext_layer = self.matmul(attention_probs, value_layer)context_layer = context_layer.transpose(0, 2, 1, 3)new_context_layer_shape = context_layer.shape[:-2] + (self.all_head_size,)context_layer = context_layer.view(*new_context_layer_shape)outputs = (context_layer, attention_probs) if self.output_attentions else (context_layer,)return outputs
BERT self-attention 输出层
  • BERTSelfOutput:residual connection + layer normalization
  • BERTAttention: self-attention + add&norm

class BertSelfOutput(nn.Cell):r"""Bert Self Outputself-attention output + residual connection + layer norm"""def __init__(self, config):super().__init__()self.dense = nn.Dense(config.hidden_size, config.hidden_size, \weight_init=TruncatedNormal(config.initializer_range))self.layer_norm = nn.LayerNorm((config.hidden_size,), epsilon=1e-12)self.dropout = Dropout(config.hidden_dropout_prob)def construct(self, hidden_states, input_tensor):hidden_states = self.dense(hidden_states)hidden_states = self.dropout(hidden_states)hidden_states = self.layer_norm(hidden_states + input_tensor)return hidden_states
BERT feed-forward 层
class BertIntermediate(nn.Cell):r"""Bert Intermediate"""def __init__(self, config):super().__init__()self.dense = nn.Dense(config.hidden_size, config.intermediate_size, \weight_init=TruncatedNormal(config.initializer_range))self.intermediate_act_fn = ACT2FN[config.hidden_act]def construct(self, hidden_states):hidden_states = self.dense(hidden_states)hidden_states = self.intermediate_act_fn(hidden_states)return hidden_states
BERT 最后的Add&Norm
class BertOutput(nn.Cell):r"""Bert Output"""def __init__(self, config):super().__init__()self.dense = nn.Dense(config.intermediate_size, config.hidden_size, \weight_init=TruncatedNormal(config.initializer_range))self.layer_norm = nn.LayerNorm((config.hidden_size,), epsilon=1e-12)self.dropout = Dropout(config.hidden_dropout_prob)def construct(self, hidden_states, input_tensor):hidden_states = self.dense(hidden_states)hidden_states = self.dropout(hidden_states)hidden_states = self. layer_norm(hidden_states + input_tensor)return hidden_states
BERT Encoder
  • BertLayer:Encoder Layer,集合了self-attention, feed-forward并通过add&norm连接
  • BertEnocoder:通过Encoder Layer堆叠起来的Encoder结构

class BertLayer(nn.Cell):r"""Bert Layer"""def __init__(self, config):super().__init__()self.attention = BertAttention(config)self.intermediate = BertIntermediate(config)self.output = BertOutput(config)def construct(self, hidden_states, attention_mask=None, head_mask=None):attention_outputs = self.attention(hidden_states, attention_mask, head_mask)attention_output = attention_outputs[0]intermediate_output = self.intermediate(attention_output)layer_output = self.output(intermediate_output, attention_output)outputs = (layer_output,) + attention_outputs[1:]return outputsclass BertEncoder(nn.Cell):r"""Bert Encoder"""def __init__(self, config):super().__init__()self.output_attentions = config.output_attentionsself.output_hidden_states = config.output_hidden_statesself.layer = nn.CellList([BertLayer(config) for _ in range(config.num_hidden_layers)])def construct(self, hidden_states, attention_mask=None, head_mask=None):all_hidden_states = ()all_attentions = ()for i, layer_module in enumerate(self.layer):if self.output_hidden_states:all_hidden_states += (hidden_states,)layer_outputs = layer_module(hidden_states, attention_mask, head_mask[i])hidden_states = layer_outputs[0]if self.output_attentions:all_attentions += (layer_outputs[1],)if self.output_hidden_states:all_hidden_states += (hidden_states,)outputs = (hidden_states,)if self.output_hidden_states:outputs += (all_hidden_states,)if self.output_attentions:outputs += (all_attentions,)return outputs
BERT 输出

BERT会针对每一个位置输出大小为hidden size的向量,在下游任务中,会根据任务内容的不同,选取不同的向量放入输出层。

  • 我们一般称[CLS]经过线性层+激活函数tanh的输出为pooler output,用于句子级别的分类/回归任务;
  • 我们一般称BERT输出的每个位置对应的vector为sequence output,用于词语级别的分类任务;

BERT Pooler
class BertPooler(nn.Cell):r"""Bert Pooler"""def __init__(self, config):super().__init__()self.dense = nn.Dense(config.hidden_size, config.hidden_size, \activation='tanh', weight_init=TruncatedNormal(config.initializer_range))def construct(self, hidden_states):first_token_tensor = hidden_states[:, 0]pooled_output = self.dense(first_token_tensor)return pooled_output

BERT 预训练

BERT通过Masked LM(masked language model)与NSP(next sentence prediction)获取词语和句子级别的特征。

图片来源:Devlin, J.; Chang, M. W.; Lee, K.; Toutanova, K. BERT: Pre-training of deep bidirectional transformers for language understanding. arXiv preprint arXiv:1810.04805, 2018.

Masked LM

BERT模型通过Masked LM捕捉词语层面的信息。

我们随机将每个句子中15%的词语进行遮盖,替换成掩码<mask>。在训练过程中,模型会对句子进行“完形填空”,预测这些被遮盖的词语是什么,通过减小被mask词语的损失值来对模型进行优化。

图片来源: The Illustrated BERT, ELMo, and co. (How NLP Cracked Transfer Learning)

由于<mask>仅在预训练中出现,为了让预训练和微调中的数据处理尽可能接近,我们在随机mask的时候进行如下操作:

  • 80%的概率替换为<mask>
  • 10%的概率替换为文本中的随机词
  • 10%的概率不进行替换,保持原有的词元

我们通过BERTPredictionHeadTranform实现单层感知机,对被遮盖的词元进行预测。在前向网络中,我们需要输入BERT模型的编码结果hidden_states

activation_map = {'relu': nn.ReLU(),'gelu': nn.GELU(False),'gelu_approximate': nn.GELU(),'swish':nn.SiLU()
}class BertPredictionHeadTransform(nn.Cell):def __init__(self, config):super().__init__()self.dense = nn.Dense(config.hidden_size, config.hidden_size, weight_init=TruncatedNormal(config.initializer_range))self.transform_act_fn = activation_map.get(config.hidden_act, nn.GELU(False))self.layer_norm = nn.LayerNorm((config.hidden_size,), epsilon=config.layer_norm_eps)def construct(self, hidden_states):hidden_states = self.dense(hidden_states)hidden_states = self.transform_act_fn(hidden_states)hidden_states = self.layer_norm(hidden_states)return hidden_states

根据被遮盖的词元位置masked_lm_positions,获得这些词元的预测输出。

import mindspore.ops as ops
import mindspore.numpy as mnp
from mindspore import Parameter, Tensorclass BertLMPredictionHead(nn.Cell):def __init__(self, config):super(BertLMPredictionHead, self).__init__()self.transform = BertPredictionHeadTransform(config)self.decoder = nn.Dense(config.hidden_size, config.vocab_size, has_bias=False, weight_init=TruncatedNormal(config.initializer_range))self.bias = Parameter(initializer('zeros', config.vocab_size), 'bias')def construct(self, hidden_states, masked_lm_positions):batch_size, seq_len, hidden_size = hidden_states.shapeif masked_lm_positions is not None:flat_offsets = mnp.arange(batch_size) * seq_lenflat_position = (masked_lm_positions + flat_offsets.reshape(-1, 1)).reshape(-1)flat_sequence_tensor = hidden_states.reshape(-1, hidden_size)hidden_states = ops.gather(flat_sequence_tensor, flat_position, 0)hidden_states = self.transform(hidden_states)hidden_states = self.decoder(hidden_states) + self.biasreturn hidden_states
NSP

BERT通过NSP捕捉句子级别的信息,使其可以理解句子与句子之间的联系,从而能够应用于问答或者推理任务。

NSP本质上是一个二分类任务,通过输入一个句子对,判断两句话是否为连续句子。输入的两个句子A和B中,B有50%的概率是A的下一句。

图片来源: The Illustrated BERT, ELMo, and co. (How NLP Cracked Transfer Learning)

另外,输入的内容最好是document-level的语料,而非sentence-level的语料,这样训练出的模型可以具备抓取长序列特征的能力。

在这里,我们使用一个单隐藏层的多层感知机BERTPooler进行二分类预测。因为特殊占位符在预训练中对应了句子级别的特征信息,所以多层感知机分类器只需要输出对应的隐藏层输出。

class BertPooler(nn.Cell):def __init__(self, config):super(BertPooler, self).__init__()self.dense = nn.Dense(config.hidden_size, config.hidden_size, activation='tanh', weight_init=TruncatedNormal(config.initializer_range))def construct(self, hidden_states):first_token_tensor = hidden_states[:, 0]pooled_output = self.dense(first_token_tensor)return pooled_output

最后,多层感知机分类器的输出通过一个线性层self.seq_relationship,输出对nsp的预测。

BERTPreTrainingHeads中,我们对以上提到的两种方式进行整合。最终输出Maked LM(prediction scores)和NSP(seq_realtionship_score)的预测结果。

class BertPreTrainingHeads(nn.Cell):def __init__(self, config):super(BertPreTrainingHeads, self).__init__()self.predictions = BertLMPredictionHead(config)self.seq_relationship = nn.Dense(config.hidden_size, 2, weight_init=TruncatedNormal(config.initializer_range))def construct(self, sequence_output, pooled_output, masked_lm_positions):prediction_scores = self.predictions(sequence_output, masked_lm_positions)seq_relationship_score = self.seq_relationship(pooled_output)return prediction_scores, seq_relationship_score
BERT预训练代码整合

我们将上述的类进行实例化,并借此回顾一下BERT预训练的整体流程。

  1. BertModel构建BERT模型;
  2. BertPretrainingHeads整合了Masked LM与NSP两个训练任务, 输出预测结果;
    • BertLMPredictionHead:输入BERT编码与<mask>的位置,输出对应位置词元的预测;
    • BERTPooler:输入BERT编码,输出对<cls>的隐藏状态,并在BertPretrainingHeads中通过线性层输出预测结果;
class BertForPretraining(nn.Cell):def __init__(self, config, *args, **kwargs):super().__init__(config, *args, **kwargs)self.bert = BertModel(config)self.cls = BertPreTrainingHeads(config)self.vocab_size = config.vocab_sizeself.cls.predictions.decoder.weight = self.bert.embeddings.word_embeddings.embedding_tabledef construct(self, input_ids, attention_mask=None, token_type_ids=None, position_ids=None, head_mask=None, masked_lm_positions=None):outputs = self.bert(input_ids,attention_mask=attention_mask,token_type_ids=token_type_ids,position_ids=position_ids,head_mask=head_mask)sequence_output, pooled_output = outputs[:2]prediction_scores, seq_relationship_score = self.cls(sequence_output, pooled_output, masked_lm_positions)outputs = (prediction_scores, seq_relationship_score,) + outputs[2:]return outputs

课程ppt及代码地址

  • github地址(网络不好的可以访问下面我克隆到gitee上的地址):BERT

  • gitee地址:BERT

2、学习心得:

​ 通过本次学习,熟悉了Mindspore这个国产深度学习框架,也对BERT的基本技术原理有所了解,最重要的是能够通过BERT完成一个简单的情感分类的任务,这让我十分有成就感!!!另外除了bert相关的技术原理,峰哥还拓展了混合精度训练原理,分布式并行原理,真的非常不错!

3、经验分享:

​ 在启智openI上的npu跑时记得使用mindspore1.7的镜像,同时安装对应mindnlp的版本,不然可能会因为版本不兼容而报错。

4、课程反馈:

​ 本次课程中的代码串讲我觉得是做的最好的地方,没有照着ppt一直念,而是在jupyter上把代码和原理结合到一块进行讲解,让学习者对代码的理解更加深入。我觉得内容的最后可以稍微推荐一下与Mindspore大模型相关的套件,让学习者在相关套件上可以开发出更多好玩和有趣的东西!

5、使用MindSpore昇思的体验和反馈:

MindSpore昇思的优点和喜欢的方面:

  1. 灵活性和可扩展性: MindSpore提供了灵活的编程模型,支持静态计算图和动态计算图。这种设计使得它适用于多种类型的机器学习和深度学习任务,并且具有一定的可扩展性。
  2. 跨平台支持: MindSpore支持多种硬件平台,包括CPU、GPU和NPU等,这使得它具有在不同设备上运行的能力,并能充分利用各种硬件加速。
  3. 自动并行和分布式训练: MindSpore提供了自动并行和分布式训练的功能,使得用户可以更轻松地处理大规模数据和模型,并更高效地进行训练。
  4. 生态系统和社区支持: MindSpore致力于建立开放的生态系统,并鼓励社区贡献,这对于一个开源框架来说非常重要,能够帮助用户更好地学习和解决问题。

一些建议和改进方面:

  1. 文档和教程的改进: 文档和教程并不是很详细,希望能够提供更多实用的示例、详细的文档和教程,以帮助用户更快速地上手和解决问题。
  2. 更多的应用场景示例: 提供更多真实场景的示例代码和应用案例,可以帮助用户更好地了解如何在实际项目中应用MindSpore。

6、未来展望:

​ 大模型的内容还是很多的,希望自己能坚持打卡,将后面的内容都学习完,并做出一些有趣好玩的东西来!

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

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

相关文章

修复uni-simple-router@2.0.7版本query参数null的bug

问题&#xff1a;query参数为null或者为空时&#xff0c;插件内部参数校验问题导致的会报错&#xff1a;TypeError: Cannot convert undefined or null to object at Function.keys 源码修改如下&#xff1a; 通过打补丁的方式修复query参数类型校验问题 1. 安装patch-packag…

使 a === 1 a === 2 a === 3 为 true 的几种“下毒“方法

前言 这算得上是近些年的前端网红题了&#xff0c;曾经对这种网红题非常抵触&#xff0c;认为非常没有意义。 看到了不少人有做分享&#xff0c;有各种各样的方案&#xff0c;有涉及到 JS 非常基础的知识点&#xff0c;也不得不感叹解题者的脑洞之大。 但是&#xff0c;拿来…

传奇服务器搭建

传奇服务器搭建 传奇是一款非常经典的游戏&#xff0c;自从它推出以来就深受玩家们的喜爱。如果你也想要在自己的服务器上搭建一个传奇&#xff0c;那么本文将为你提供一些有用的信息。 首先&#xff0c;我们需要知道什么是传奇服务器。简单来说&#xff0c;它就是一个能够让…

线程池c++实现

线程池c实现 概述 线程池&#xff08;Thread Pool&#xff09;是一种并发编程的设计模式&#xff0c;它用于管理和重复使用线程&#xff0c;以提高程序的性能和资源利用率。线程池通过维护一组预先创建的线程&#xff0c;这些线程可以在需要时被重复使用&#xff0c;而不是为…

HarmonyOS鸿蒙学习基础篇 - 什么是HarmonyOS

概述 HarmonyOS是华为开发的一款面向未来的全场景分布式智慧操作系统&#xff0c;将逐步覆盖18N全场景终端设备&#xff1b; 对消费者而言 HarmonyOS用一个‘统一的软件系统’ 从根本上解决消费者面对大量智能终端体验割裂的问题&#xff0c;为消费者带来同意便利安全的智慧化全…

相关系数(皮尔逊相关系数和斯皮尔曼相关系数)

本文借鉴了数学建模清风老师的课件与思路&#xff0c;可以点击查看链接查看清风老师视频讲解&#xff1a;5.1 对数据进行描述性统计以及皮尔逊相关系数的计算方法_哔哩哔哩_bilibili 注&#xff1a;直接先看 &#xff08; 三、两个相关系数系数的比较 &#xff09; 部分&#x…

Qt事件过滤

1.相关说明 监控鼠标进入组件、出组件、点击组件、双击组件的事件&#xff0c;需要重写eventFilter函数 2.相关界面 3.相关代码 #include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui-&…

数据库(MySQL库表操作)

目录 1.1 SQL语句基础&#xff08;SQL命令&#xff09; 1.1.1 SQL的简介 1.1.2 SQL语句的分类 1.1.3 SQL语句的书写规范 1.2 数据库操作 1.2.1 查看 1.2.2 自建库 1.2.3 切换数据库 1.2.4 删库 1.3 MySQL字符集 1.3.1 MySQL字符集包括&#xff1a; 1.3.2 utf8 和 u…

汽车制动器行业调查:市场将继续呈现稳中向好发展态势

汽车制动器是汽车的制动装置&#xff0c;汽车所用的制动器几乎都是摩擦式的&#xff0c;可分为鼓式和盘式两大类。鼓式制动器摩擦副中的旋转元件为制动鼓&#xff0c;其工作表面为圆柱面;盘式制动器的旋转元件则为旋转的制动盘&#xff0c;以端面为工作表面。 目前市场上主流的…

JAVA和C++ SECS/GEM300开发和概念

编译SECS示例程序 1. 示例程序使用默认路径&#xff1a; D:\SECS 稳定版\SECS Debug\ 2. 该操作分为俩步 ① 将C#的Secs库编译成设备相同Net版本。 如.net3.5、4.0、4.5等等 ② 编译金南瓜SECS demo程序 编译C#的SecsEquip.dll 1. 找到SecsEquip项目 项目文件 使用Visua…

麒麟V10挂载iso,配置yum源

本文介绍yum 如何挂载本地镜像源 1) 拷贝镜像到本地 2) 执行以下命令&#xff1a; # mount -o loop 镜像路径及镜像名字 /mnt&#xff08;或 media&#xff09; 挂载前 挂载后 3) 进入/etc/yum.repos.d&#xff08;yum.repos.d 是一个目录&#xff0c;该目录是分析 RPM 软件…

操作系统的一些知识

一、操作系统 1、操作系统的定义 操作系统是一个搞管理的软件。 对下&#xff0c;要管理硬件设备&#xff1b;对上&#xff0c;要给软件提供稳定的运行环境。 操作系统是软件、硬件、用户之间交互的媒介。 2、常见的操作系统 Windows、Linux、Mac 3、操作系统的定位 我们平…

视频剪辑教程:如何批量制作滚动字幕,提升画面质感的方法

在视频剪辑中&#xff0c;字幕的处理是至关重要的一环。合适的字幕不仅能提供必要的信息&#xff0c;还能增强画面的视觉效果。下面详解云炫AI智剪如何批量制作滚动字幕&#xff0c;提升画面质感的方法&#xff0c;助您更好地完成视频剪辑工作。 批量制作滚动字幕的方法&#x…

Mysql详细安装步骤

Linux 安装 MySQL【超详细版】 ​编辑 我叫BuGu    2023-05-11 16:48:10 发布 一、安装 MySQL 的准备工作 1. 查看系统版本 cat /etc/redhat-release2. 查看系统是否已经安装过 MySQL 查看是否安装了 MySQL rpm -qa | grep mysql查看是否有安装 mariadb,该软件与 MySQ…

逆向分析C++类的本质

面向对象的语言中&#xff0c;类这种语言特性是最基本也是最重要的东西。这篇博客记录下从汇编角度去理解类的本质是什么。创建一个对象的本质又是什么。 一.C语言中的结构体和C的类有啥区别 我们知道在C语言中&#xff0c;有语言本身自带的一些内置类型。比如int&#xff0c…

kafka(一)——简介

简介 Kafka 是一种分布式、支持分区、多副本的消息中间件&#xff0c;支持发布-订阅模式&#xff0c;多用于实时处理大量数据缓存的场景&#xff0c;类似于一个“缓存池”。 架构 Producer&#xff1a;消息生产者&#xff1b;Consumer&#xff1a;消息消费者&#xff1b;Brok…

SpringCloud之Nacos的学习、快速上手

1、什么是Nacos Nacos是阿里的一个开源产品&#xff0c;是针对微服务架构中的服务发现、配置管理、服务治理的综合型解决方案&#xff0c;用来实现配置中心和服务注册中心。 Nacos 快速开始 2、安装运行nacos nacos下载地址 下载地址: https://github.com/alibaba/nacos/rel…

【Linux】Linux系统的生态

Linux中安装软件 Linux中安装软件一般有三种方式&#xff1a; 源代码安装rpm包安装yum安装 1.源代码安装 有些软件本来就是开源的&#xff0c;如果不想用别人直接发布好的软件&#xff0c;我们就可以把源代码下载下来&#xff0c;在我们的环境中编译&#xff0c;自己安装 …

防伪技术行业研究:年复合增长率约为10%

近年来&#xff0c;我国各种新的防伪技术不断涌现&#xff0c;部分防伪技术已经达到国际先进水平&#xff0c;并广泛应用于产品防伪、票证防伪等领域&#xff0c;推动了防伪行业的持续、健康发展。 常见的产品防伪技术有&#xff1a;隐形分子技术、二维码防伪、揭开留底防伪、安…

「Kafka」Broker篇

「Kafka」Broker篇 主要讲解的是在 Kafka 中是怎么存储数据的&#xff0c;以及 Kafka 和 Zookeeper 之间如何进行数据沟通的。 Kafka Broker 总体工作流程 Zookeeper 存储的 Kafka 信息 启动 Zookeeper 客户端&#xff1a; [atguiguhadoop102 zookeeper-3.5.7]$ bin/zkCli.sh通…