【计算机视觉 | 自然语言处理】Hugging Face 超详细介绍和使用教程

news2024/11/28 6:54:26

文章目录

  • 一、前言
  • 二、可以获得什么?
  • 三、入门实践
    • 3.1 帮助文档
    • 3.2 安装
    • 3.3 模型的组成
    • 3.4 BERT模型的使用
      • 3.4.1 导入模型
      • 3.4.2 使用模型
        • 3.4.2.1 tokenizer
    • 3.5 model
    • 3.6 后处理

一、前言

Hugging Face 起初是一家总部位于纽约的聊天机器人初创服务商,他们本来打算创业做聊天机器人,然后在 github 上开源了一个 Transformers 库,虽然聊天机器人业务没搞起来,但是他们的这个库在机器学习社区迅速大火起来。

目前已经共享了超 100,000 个预训练模型,10,000 个数据集,变成了机器学习界的 github

其之所以能够获得如此巨大的成功,一方面是让我们这些甲方企业的小白,尤其是入门者也能快速用得上科研大牛们训练出的超牛模型。

另一方面是,这种特别开放的文化和态度,以及利他利己的精神特别吸引人。

Hugging Face 上面很多业界大牛也在使用和提交新模型,这样我们就是站在大牛们的肩膀上工作,而不是从头开始,当然我们也没有大牛那么多的计算资源和数据集。

在国内 Hugging Face 也是应用非常广泛,一些开源框架本质上就是调用 Transfomer 上的模型进行微调(当然也有很多大牛在默默提供模型和数据集)。

很多 NLP 工程师招聘的条目上也明摆着要求熟悉 Hugging Face Transformer 库的使用。

因为他既提供了数据集,又提供了模型让你随便调用下载,因此入门非常简单。你甚至不需要知道什么是 GPTBERT 就可以用他的模型了。

下面初步介绍下 Hugging Face 里面都有什么,以及怎么调用 BERT 模型做个简单的任务。

参考文献:

https://zhuanlan.zhihu.com/p/535100411

二、可以获得什么?

内容:

Hugging Face 的官方网站:

https://huggingface.co/
  1. Datasets:数据集,以及数据集的下载地址;
  2. Models:各个预训练模型;
  3. course:免费的 NLP 课程,可惜都是英文的;
  4. docs:文档。

在这里插入图片描述

NLP 领域,在 Hugging Face 上面数据集和预训练模型的数量以英语为最为众多,远超其他国家的总和(见下图)。

就预训练模型来说,排名第二的是汉语。

就数据集来说,汉语远远少于英语,也少于法,德,西班牙等语言,甚至少于阿拉伯语和波兰语。

这严重跟我想象中的 AI 超级大国及其不匹配。

我想一方面因为数据集的积累都需要很多年,中文常用的(PKUMSRA)数据集都是十几年前留下的,而我们 AI 和经济的崛起也不过是最近十年的事情。

另一方面,数据集都是大价钱整理出来的,而且可以不断的利用他产生新的模型,这样的大杀器怎可随意公布。发布预训练模型可以带来论文,数据集可啥也带不来,基本上中日韩等的数据集明显偏少。

在这里插入图片描述

三、入门实践

3.1 帮助文档

接下来的内容参考了下面的内容,初步带你入门 Hugging Face,简单了解如何调用 BERT 模型:

参考网站:

https://www.cnblogs.com/dongxiong/p/12763923.html

在这里插入图片描述

https://huggingface.co/docs/transformers/model_doc/bert

在这里插入图片描述

3.2 安装

Transformersgithub 地址在:

https://github.com/huggingface/transformers

在这里插入图片描述
安装方法,在命令行执行(conda 的话在 anaconda propmt):

安装最新的版本:

pip install transformers

安装指定版本:

pip install transformers == 4.0

如果你是 conda 的话,4.0 以后的版本才会有:

conda install -c huggingface transformers

测试下安装是否成功:

from transformers import pipeline

3.3 模型的组成

一般 Transformer 模型有三个部分组成:

  1. tokennizer
  2. Model
  3. Post processing

我们可以看到三个部分的具体作用:

Tokenizer 就是把输入的文本做切分,然后变成向量,Model 负责根据输入的变量提取语义信息,输出 logits;最后 Post Processing 根据模型输出的语义信息,执行具体的 NLP 任务,比如情感分析,文本自动打标签等;可见 Model 是其中的核心部分,Model 又可以分为三种模型,针对不同的 NLP 任务,需要选取不同的模型类型:Encoder 模型(如 Bert,常用于句子分类、命名实体识别(以及更普遍的单词分类)和抽取式问答。),Decoder 模型(如 GPTGPT2,常用于文本生成),以及 sequence2sequence 模型(如 BART,常用于摘要,翻译,生成性问答等)。

说了很多理论的内容,我们可以在 Hugging Face 的官网,随便找一个预训练模型具体看看包含哪些文件。

在这里我举了一个中文的例子 “Bert-base-Chinese”(中文还有其他很优秀的预训练模型,比如哈工大和科大讯飞提供的:roberta-wwm-ext,百度提供的:ernie)。这个模型据说是根据中文维基百科内容训练的,因此语义内容可能不是足够丰富,毕竟其他大佬们提供的数据更多。

在这里插入图片描述
在这里插入图片描述
README.md 一般是模型的介绍,包括使用方法都会放到里面,不介绍了。其他最重要的组成部分,大概分为三类:

config

控制模型的名称、最终输出的样式、隐藏层宽度和深度、激活函数的类别等。这些参数我补齐了说明,对于初学者来说,大家一般不需要调整。这些参数都可以通过 configuration 类更改。

{
  "architectures": [
    "BertForMaskedLM"
  ],
  "attention_probs_dropout_prob": 0.1,
  "directionality": "bidi",
  "hidden_act": "gelu",
  "hidden_dropout_prob": 0.1,
  "hidden_size": 768,
  "initializer_range": 0.02,
  "intermediate_size": 3072,
  "layer_norm_eps": 1e-12,
  "max_position_embeddings": 512,
  "model_type": "bert",
  "num_attention_heads": 12,
  "num_hidden_layers": 12,
  "pad_token_id": 0,
  "pooler_fc_size": 768,
  "pooler_num_attention_heads": 12,
  "pooler_num_fc_layers": 3,
  "pooler_size_per_head": 128,
  "pooler_type": "first_token_transform",
  "type_vocab_size": 2,
  "vocab_size": 21128
}

tokenizer(包含三个文件):

这些文件是 tokenizer 类生成的,或者处理的,只是处理文本,不涉及任何向量操作。

vocab.txt 是词典文件(打开就是单个字符,我这里用的是 bert-base-chinsese,可以看到里面都是保留符号和单个汉字索引,字符)

tokenizer.jsonconfig 是分词的配置文件,根据 vocab 信息和你的设置更新,里面把 vocab 都按顺序做了索引,将来可以根据编码生成 one-hot 向量,然后跟 embeding 训练的矩阵相乘,就可以得到该字符的向量。

模型文件一般是 tensorflow(上图中的 h5 文件)和 Pytorch(上图中的 bin 文件)的都有,因为作者只是单纯的在学习 torch,所以以后的文章都只介绍 torch

3.4 BERT模型的使用

介绍完了模型库都有哪些内容,下面我们可以导入模型试一试怎么使用:

3.4.1 导入模型

利用官方的 hub 导入模型;下面导入了一个 BertModel ;在官方的教程中推进使用 pipeline 导入模型的方法:

import torch
from transformers import BertModel, BertTokenizer, BertConfig

tokenizer = BertTokenizer.from_pretrained('bert-base-chinese')
config = BertConfig.from_pretrained('bert-base-chinese')
config.update({'output_hidden_states':True})
model = BertModel.from_pretrained("bert-base-chinese",config=config)

利用 pipeline 的方式也是一样的可以导入模型哈,方式如下:

from transformers import AutoModel
checkpoint = "bert-base-chinese"

model = AutoModel.from_pretrained(checkpoint)

因为 Hugging Face 官网在国外,自动下载可能比较费劲。

默认下载地址在这里:

  • 使用 Windows 模型保存的路径在 C:\Users[用户名].cache\torch\transformers\ 目录下,根据模型的不同下载的东西也不相同;
  • 使用 Linux 模型保存的路径在 ~/.cache/torch/transformers/ 目录下

如果自动下载总是中断的话,可以考虑用国内的源,或者手工下载之后指定位置。(Hugging Face 官网,选择 models 菜单,然后搜索自己想要的模型,然后把里面的文件下载下来,其中体积较大的有 tf 的有 torch 的,根据自己需要下载)。

import transformers
MODEL_PATH = r"D:\\test\\bert-base-chinese"
# 导入模型
tokenizer = transformers.BertTokenizer.from_pretrained(r"D:\\test\\bert-base-chinese\\bert-base-chinese-vocab.txt") 
# 导入配置文件
model_config = transformers.BertConfig.from_pretrained(MODEL_PATH)
# 修改配置
model_config.output_hidden_states = True
model_config.output_attentions = True
# 通过配置和路径导入模型
model = transformers.BertModel.from_pretrained(MODEL_PATH,config = model_config)

3.4.2 使用模型

上一步我们已经把模型加载进来了,在这里,尝试一下这个模型怎么样,看看能不能把相关的语义带入进来。

我们之前文章介绍了 bert 的两个任务(MLMNSP),这一节,我们一起测试这两个任务的效果。首先我们逐步来看看 BERT 每个部分的输出都是什么:

3.4.2.1 tokenizer

上面代码可以看到他实例化了 BertTokenizer 类,它是基于 WordPiece 方法的,先看看他有哪些参数:

( vocab_file,do_lower_case = True,do_basic_tokenize = True,never_split = None,unk_token = '[UNK]',sep_token = '[SEP]',pad_token = '[PAD]',cls_token = '[CLS]',mask_token = '[MASK]',tokenize_chinese_chars = True,strip_accents = None**kwargs )
  • vocab_file:这里是放置词典的地址;
  • do_lower_case,是否都变成小写,默认是 True
  • do_basic_tokenize,做 wordpiece 之前是否要做 basic tokenize
  • 下面的都是一些关键字的确认。
  • 还有就是是否分开中文字符,因为bert是面向英文的所有有这些设置,一般不用改,当然我们这里的案例也只是读取了预训练模型。

示例如下,可以看出 BERT 对中文是字符级别的分词,对待英文是到 sub-word 级别的:

print(tokenizer.encode("生活的真谛是美和爱"))  # 对于单个句子编码
print(tokenizer.encode_plus("生活的真谛是美和爱","说的太好了")) # 对于一组句子编码
# 输出结果如下:
[101, 4495, 3833, 4638, 4696, 6465, 3221, 5401, 1469, 4263, 102]
{'input_ids': [101, 4495, 3833, 4638, 4696, 6465, 3221, 5401, 1469, 4263, 102, 6432, 4638, 1922, 1962, 749, 102], 'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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]}

# 也可以直接这样用
sentences = ['网络安全开发分为三个层级',
             '车辆系统层级网络安全开发',
             '车辆功能层级网络安全开发',
             '车辆零部件层级网络安全开发',
             '测试团队根据车辆网络安全目标制定测试技术要求及测试计划',
             '测试团队在网络安全团队的支持下,完成确认测试并编制测试报告',
             '在车辆确认结果的基础上,基于合理的理由,确认在设计和开发阶段识别出的所有风险均已被接受',]
test1 = tokenizer(sentences)

print(test1)  # 对列表encoder
print(tokenizer("网络安全开发分为三个层级"))  # 对单个句子encoder

输出结果为:

[101, 4495, 3833, 4638, 4696, 6465, 3221, 5401, 1469, 4263, 102]
{'input_ids': [101, 4495, 3833, 4638, 4696, 6465, 3221, 5401, 1469, 4263, 102, 6432, 4638, 1922, 1962, 749, 102], 'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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]}
{'input_ids': [[101, 5381, 5317, 2128, 1059, 2458, 1355, 1146, 711, 676, 702, 2231, 5277, 102], [101, 6756, 6775, 5143, 5320, 2231, 5277, 5381, 5317, 2128, 1059, 2458, 1355, 102], [101, 6756, 6775, 1216, 5543, 2231, 5277, 5381, 5317, 2128, 1059, 2458, 1355, 102], [101, 6756, 6775, 7439, 6956, 816, 2231, 5277, 5381, 5317, 2128, 1059, 2458, 1355, 102], [101, 3844, 6407, 1730, 7339, 3418, 2945, 6756, 6775, 5381, 5317, 2128, 1059, 4680, 3403, 1169, 2137, 3844, 6407, 2825, 3318, 6206, 3724, 1350, 3844, 6407, 6369, 1153, 102], [101, 3844, 6407, 1730, 7339, 1762, 5381, 5317, 2128, 1059, 1730, 7339, 4638, 3118, 2898, 678, 8024, 2130, 2768, 4802, 6371, 3844, 6407, 2400, 5356, 1169, 3844, 6407, 2845, 1440, 102], [101, 1762, 6756, 6775, 4802, 6371, 5310, 3362, 4638, 1825, 4794, 677, 8024, 1825, 754, 1394, 4415, 4638, 4415, 4507, 8024, 4802, 6371, 1762, 6392, 6369, 1469, 2458, 1355, 7348, 3667, 6399, 1166, 1139, 4638, 2792, 3300, 7599, 7372, 1772, 2347, 6158, 2970, 1358, 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, 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, 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, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], '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, 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, 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]]}

在这里插入图片描述

来看一下这个输出:

对于单个句子是上面那种,它只输出句子 tok 之后的 id,我们注意到已经加好 [CLS], [SEP] 等标识符了;(查询 tokenizer 可知,101[CLS], 102[SEP])除了 input_ids 之外,还自动编码了 token_type_idsattention_mask

3.5 model

model 实例化了 BertModel 类,除了初始的 BertGPT 等基本模型,针对不同的下游任务,定义了 BertForQuestionAnsweringBertForMultiChoiceBertForNextSentencePrediction 以及 BertForSequenceClassification 等下游任务模型。

模型导出时将生成 config.jsonpytorch_model.bin 参数文件,这两个文件前面已将介绍了,一个是配置文件一个是 torch 训练后 save 的文件。

因为中文是字符级的 tok,所以做 MLM 任务不是很理想,所以下面我用英文的 base 模型示例一个 MLM 任务:

from transformers import pipeline
# 运行该段代码要保障你的电脑能够上网,会自动下载预训练模型,大概420M
unmasker = pipeline("fill-mask",model = "bert-base-uncased")  # 这里引入了一个任务叫fill-mask,该任务使用了base的bert模型
unmasker("The goal of life is [MASK].", top_k=5) # 输出mask的指,对应排名最前面的5个,也可以设置其他数字
# 输出结果如下,似乎都不怎么有效哈。
[{'score': 0.10933303833007812,
  'token': 2166,
  'token_str': 'life',
  'sequence': 'the goal of life is life.'},
 {'score': 0.03941883146762848,
  'token': 7691,
  'token_str': 'survival',
  'sequence': 'the goal of life is survival.'},
 {'score': 0.032930608838796616,
  'token': 2293,
  'token_str': 'love',
  'sequence': 'the goal of life is love.'},
 {'score': 0.030096106231212616,
  'token': 4071,
  'token_str': 'freedom',
  'sequence': 'the goal of life is freedom.'},
 {'score': 0.024967126548290253,
  'token': 17839,
  'token_str': 'simplicity',
  'sequence': 'the goal of life is simplicity.'}]

3.6 后处理

后处理通常要根据你选择的模型来确定,一般模型的输出是 logits,其包含我们需要的语义信息,然后后处理是经过一个激活函数输出我们可以使用的向量,比如 softmax 层做二分类,会输出对应两个标签的概率值,然后就可以轻松转化为我们需要的信息啦。

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

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

相关文章

URP渲染管线里面的摄像机用法

大家好,我是阿赵,这里继续讲一下URP渲染管线。 这次要讲的是URP渲染管线里面的摄像机用法 之前介绍过,URP摄像机和普通摄像机的属性显示上有比较大的变化: 接下来从用法上来说明一下: 1、多个摄像机的处理变化 多个…

unity UGUI系统梳理 -交互组件

概述 unity 中的交互组件可用于处理交互,例如鼠标或触摸事件以及使用键盘或控制器进行的交互 1、按钮 (Button) Button详解 2、开关 (Toggle) Background:背景图片,控制toggle组件的背景颜色改变,从而展示此物体是否被选中的…

5.View的事件分发机制/事件处理机制原理分析

事件MotionEvent包含了哪几个? ACTION_DOWN 手指触碰到屏幕时触发,只会执行一次ACTION_MOVE 手指在屏幕上滑动出发,会执行多次ACTION_UP 手指抬起离开屏幕出发,只会执行一次ACTION_CANCEL 事件被上层拦截时会触发 父容器ViewGroup需要从子View手中抢夺分发的事件进行处理时,会…

【SCI】综合能源系统中热电联产、电制气和碳捕集系统的建模与优化(Matlab代码实现)

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…

Java 网络编程 —— 非阻塞式编程

线程阻塞概述 在生活中,最常见的阻塞现象是公路上汽车的堵塞。汽车在公路上快速行驶,如果前方交通受阻,就只好停下来等待,等到公路顺畅,才能恢复行驶。 线程在运行中也会因为某些原因而阻塞。所有处于阻塞状态的线程…

C++数据结构:哈希 -- unordered系列容器、哈希表的结构以及如何通过闭散列的方法解决哈希冲突

目录 一. unordered系列关联式容器 1.1 unrodered_map和unordered_set 综述 1.2 常见的接口函数(以unordered_map为例) 1.3 unordered系列与map和set的效率对比 二. 哈希表的底层结构 2.1 什么是哈希 2.2 哈希函数 2.3 哈希冲突 三. 通过闭散列的…

JavaEE(系列2) -- 多线程(创建多线程)

讲述下面的内容之前,先来回顾一下一个重要的知识点 进程和线程之间的区别 1.进程包括线程。 2.进程有自己独立的内存空间和文件描述符表。同一个进程中的多个线程之间,共享同一份地址空间和文件描述符表。 3.进程是操作系统资源分配的基本单位,线程是操作…

5.14学习周报

文章目录 前言文献阅读摘要介绍方法模型框架评价指标结果结论 时间序列预测总结 前言 本周阅读文献《A Hybrid Model for Water Quality Prediction Based on an Artificial Neural Network, Wavelet Transform, and Long Short-Term Memory》,文献主要提出了基于人…

iconfont-extract: 一个将iconfont图标转化为React组件的工具

iconfont 提供了海量的图标,同时也方便了前端开发者使用这些图标,只需要添加对应的js、css或者字体文件即可。在我们的项目中使用添加js文件的方式,js文件中都包含了所有的图标,一个项目中通常只会使用其中的一部分,所…

【架构设计】DDD 到底解决了什么问题

文章目录 前言一、架构设计是为了解决系统复杂度1.1 架构设计的误区1.1.1 每个系统都要做架构设计/公司流程要求有架构设计1.1.2 架构设计是为了追求高性能、高可用、可扩展性等单一目标 1.2 架构设计的真正目的1.3 系统复杂度的六个来源及通用解法1.3.1 高性能1.3.1.1 单机复杂…

JavaWeb-一篇文章带你入门CSS(笔记+案列)

目录 CSS是什么基本语法 CSS的引入方式内部样式表行内样式表外部样式表 选择器基础选择器标签选择器类选择器id选择器通配符选择器 复合选择器后代选择器子选择器 常用元素属性字体属性文本属性背景属性圆角矩形 元素的显示模式块级元素行内元素 我们可以使用display属性来修改…

对称加密/非对称加密

古典密码学 起源于古代战争:在战争中,为了防止书信被截获后重要信息泄露,人们开始对书信进行加密。 移位式加密 如密码棒,使用布条缠绕在木棒上的方式来对书信进行加密。 加密算法:缠绕后书写 密钥: 木棒的尺寸 替…

[笔记]深入解析Windows操作系统《四》管理机制

文章目录 前言4.1注册表查看和修改注册表注册表用法注册表数据类型注册表逻辑结构HKEY_CURRENT_USERHKEY_USERS 实验:观察轮廓加载和卸载HKEY_CLASSES_ROOTHKEY_LOCAL_MACHINE 实验:离线方式或远程编辑BCDHKEY_CURRENT_CONFIGHKEY_PERFORMANCE_DATA 前言 本章讲述了…

day3_垃圾回收器

文章目录 Serial回收器ParNew回收器Parallel Scavenge回收器Serial Old回收器Parallel Old回收器CMS(Concurrent Mark Sweeping)回收器G1 主要有7种垃圾回收器,如下所示: 其中有直线关联的表示,这2种垃圾回收器可以配合使用的。 S…

大模型之PaLM2简介

1 缘起 大模型时代。 时刻关注大模型相关的研究与进展, 以及科技巨头的商业化大模型产品。 作为产品&技术普及类文章,本文将围绕PaLM2是什么、特点、如何使用展开。 想要了解更多信息的可以移步官方网站提供的参考文档,后文会给出相关链…

Oracle11g服务说明

一、服务说明 1.OracleDBConsoleorcl:非必须启动 Oracle数据库控制台服务,orcl是Oracle的实例标识,默认的实例为orcl。在运行Enterprise Manager(企业管理器OEM)的时候,需要启动这个服务。 2.OracleJobS…

一文了解异步编程

promise 什么是promise promise是异步编程的一种解决方案,从语法上来说,Promise是一个对象,从它可以获取异步操作的消息 ES6规定,Promise对象是一个构造函数,接受一个函数作为参数,这个函数会立即执行&a…

Long类型返回前端精度丢失

【1】给前端返回Long会出现精度丢失问题 在《阿里巴巴Java开发手册》中,有一条关于前后端超大整数返回的规约,具体内容如下: 【2】问题复现 后端直接用postman测试接口,返回数据没有问题。但是前端访问接口的时候,发…

系统化了解Micrometer

本文从官方文档整理出一篇系统化全面了解的文章, 后续可能会慢慢补上源码层面的解析: https://micrometer.io/docs 学习本文的目的在于深入了解中间件的监控模块的设计, 先看看主流的做法于核心思想 本文的引用来的笔者的理解于备注 需要做的是: 先理解功能存在的理由设计模式…

kibana 代码执行 (CVE-2019-7609)

漏洞原理 “原型污染”是一种针对JS语言开发的攻击方法。JS语言中,每一个对象都是有其原型(proto)的,而该原型又有其自己的原型对象,直到某个对象的原型为null。而如果JS对其中定义的对象原型的属性读写缺乏控制&…