Hugging face教程-使用速查表-快速入门

news2024/11/15 18:47:44

Hugging face笔记

course url:https://huggingface.co/course/chapter5/8?fw=pt

函数详细情况:https://huggingface.co/docs/transformers/main_classes/pipelines#transformers.TokenClassificationPipeline

基础掌握transformers和datasets,教程写得比较详细,在transformers模块就涉及了从tokenize到后面的输入模型以及模型内部以及输出head到后面预训练的过程。

0 setup

环境配置,使用jupyter notebook或者python文件的形式

1 transformer models

需要掌握的内容:

libraries from the Hugging Face ecosystem — 🤗 Transformers, 🤗 Datasets, 🤗 Tokenizers, and 🤗 Accelerate — as well as the Hugging Face Hub.

基础掌握transformers,datasets和accelerate三个库,能够调用大模型,进行训练,并能通过accelerate进行单机多卡和多级多卡训练,能了解nlp是在做什么,流程是什么,如何让计算机更好理解人类的自然语言,以及如何使用自己的数据训练,以及如何大批量高效处理数据,以及网站上的各种资源如何使用。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-44PoEHbT-1675320733552)(/Users/admin/Documents/note/assets/image-20230201171318285.png)]

NLP是什么以及挑战在哪里

挑战在于计算机不能理解人类语言,人类的语言对于计算机是符号,它只知道数字这类没有情感的符号,对于语言中蕴含的意思不能理解,因此NLP是为了让计算机理解人类语言。

一些任务:

句子分类/句子每个单词分类/文本生成/答案提取/阅读理解等。

Transformers 能做什么what can do?

library Transformers可以做什么?通过最高层也是最简单的pipeline()API告诉你他有多么简单强大。

pipeline

最高层封装,输入原始句子,输出结果,不能做其他操作。

from transformers import pipeline

classifier = pipeline("sentiment-analysis")
classifier("I've been waiting for a HuggingFace course my whole life.")
>[{'label': 'POSITIVE', 'score': 0.9598047137260437}]
classifier(
    ["I've been waiting for a HuggingFace course my whole life.", "I hate this so much!"]
)
>[{'label': 'POSITIVE', 'score': 0.9598047137260437},
 {'label': 'NEGATIVE', 'score': 0.9994558095932007}]

其他pipeline():https://huggingface.co/docs/transformers/main_classes/pipelines 包括大量NLP任务,如情感分类等。

并提供网页尝试。

Transformers怎么做到的?how do it work?

2018年注意力机制和tranformer结构大火,并成为AI发展历程过程中的一个里程碑,但大模型消耗资源巨大,并且从原始文本到原始模型到下游任务还有很多步骤要做,hg(hugging face)做的就是简化规范这个过程,提供简单api能直接调用尝试大型的效果,封装更多原始操作,让写代码更简洁方便,让训练的门槛降低。

详情了解transformer模型见attention is all you need原始论文即可了解,简单来说就是设计了多头子注意力机制以及融合多种trick的结构,涉及成encoder-decoder结构,取得超高分数。

追溯到最原始是那里,但距离直接产生hg还有一段历史:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JpVSgge6-1675320733554)(/Users/admin/Documents/note/assets/image-20230201173943924.png)]

这些发展可以分为三类:

  • GPT-like:自回归样式的,decoder式的,通过前面生成后面的。
  • BERT-like:自编码样式的,输入一个word,输出一个embedding。
  • BART/T5-like:sequence-to-sequence样式的,一段序列到另一份序列。

在训练过程中是按照语言模型来训练的,语言模型分为两种:

  • 根据前面推测后面的:

在这里插入图片描述

  • 根据左右两边生成中间的:

在这里插入图片描述

顺便提一下大模型的世界格局分布:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DGJbykv7-1675320733557)(/Users/admin/Documents/note/assets/image-20230201174849409.png)]

以及训练一次大模型就相当于全美7年的生活 C O 2 CO^2 CO2 排放量,因此hg意义重大,因为这些预训练好的模型很强大,而且对很多下游任务都有奇效,hg做的事情就是为这些大模型提供规范化的平台,让更多的人更方便的使用。

术语规范

Architecture:结构,包括layer,怎么连接,多少维度这样

Checkpoints:权重,是预训练之后留下的有用数据

Model:上面两个的泛称。

Bias and limitations

学习到预训练数据中的偏差,比如男女偏见/种族偏见等。

使用Transformers

设计原则包括方便使用,有灵活性,简单易用,因此功能强大。

整个pipeline流程包括:

在这里插入图片描述

首先要有词典,词典大小是所有单词的数量,给每个单词一个序号,首先将输入文本单词变成数字,然后将数字输入进模型,然后模型会输出一些列处理后的小数。成为logits,然后再根据logits做下游任务。

在上面的基础上,后面根据任务设计的模块(比如进行分类)称为head,然后能得到模型最后的输出:
在这里插入图片描述

同上面的pipeline,方法使用Auto+**方法也能实现整个流程:

Here is a non-exhaustive list:

  • *Model (retrieve the hidden states)
  • *ForCausalLM
  • *ForMaskedLM
  • *ForMultipleChoice
  • *ForQuestionAnswering
  • *ForSequenceClassification
  • *ForTokenClassification
  • and others 🤗
from transformers import AutoModelForSequenceClassification

checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"
model = AutoModelForSequenceClassification.from_pretrained(checkpoint)
outputs = model(**inputs)
print(outputs.logits.shape)
>torch.Size([2, 2])

方法2:

from transformers import BertConfig, BertModel

# Building the config
config = BertConfig()

# Building the model from the config
model = BertModel(config)
from transformers import BertModel

model = BertModel.from_pretrained("bert-base-cased")

保存模型:

model.save_pretrained("directory_on_my_computer")

Tokenizers

最小单元可以是word, 可以是字母, 也可以是subword, 就是将一个单词, 分成几个能够表示具体意义的subword, 然后使用subword的形式构建词典.

Loading and saving

一步到位

#法1:限制只能使用bert,较少使用
from transformers import BertTokenizer

tokenizer = BertTokenizer.from_pretrained("bert-base-cased")
#法2:根据选择模型调用,推荐
from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("bert-base-cased")
tokenizer("Using a Transformer network is simple")
#{'input_ids': [101, 7993, 170, 11303, 1200, 2443, 1110, 3014, 102],
 'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0],
 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1]}
#save
tokenizer.save_pretrained("directory_on_my_computer")

分步骤:

Tokenization

tokenize:
from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("bert-base-cased")

sequence = "Using a Transformer network is simple"
tokens = tokenizer.tokenize(sequence)

print(tokens)
#['Using', 'a', 'transform', '##er', 'network', 'is', 'simple']
From tokens to input IDs:
ids = tokenizer.convert_tokens_to_ids(tokens)

print(ids)
Decoding
decoded_string = tokenizer.decode([7993, 170, 11303, 1200, 2443, 1110, 3014])
print(decoded_string)

模型输入为一个batch,必须放在[]中

拆解流程:

import torch
from transformers import AutoTokenizer, AutoModelForSequenceClassification

checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
model = AutoModelForSequenceClassification.from_pretrained(checkpoint)

sequence = "I've been waiting for a HuggingFace course my whole life."

tokens = tokenizer.tokenize(sequence)
ids = tokenizer.convert_tokens_to_ids(tokens)

input_ids = torch.tensor([ids])
print("Input IDs:", input_ids)

output = model(input_ids)
print("Logits:", output.logits)
batched_ids = [ids, ids]

padding:输入必须是一个矩阵,对于不等长的要添加padding来使长度相同

padding_id = 100

batched_ids = [
    [200, 200, 200],
    [200, 200, padding_id],
]
Attention masks

添加了padding之后,模型会综合上下文信息,因此要做mask,告诉模型忽略这部分信息

batched_ids = [
    [200, 200, 200],
    [200, 200, tokenizer.pad_token_id],
]

attention_mask = [
    [1, 1, 1],
    [1, 1, 0],
]

outputs = model(torch.tensor(batched_ids), attention_mask=torch.tensor(attention_mask))
print(outputs.logits)

sequence length:

模型一般是512/1024个token,更长的使用长模型或者裁剪。

参数padding,truncation,以及输入进模型必须是pytorch类型的return tensors可选

import torch
from transformers import AutoTokenizer, AutoModelForSequenceClassification

checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
model = AutoModelForSequenceClassification.from_pretrained(checkpoint)
sequences = ["I've been waiting for a HuggingFace course my whole life.", "So have I!"]

tokens = tokenizer(sequences, padding=True, truncation=True, return_tensors="pt")
output = model(**tokens)

微调FINE-TUNE

id转化为token
tokenizer.convert_ids_to_tokens(inputs["input_ids"])
调用数据
from datasets import load_dataset

raw_datasets = load_dataset("glue", "mrpc")
raw_datasets
#--
DatasetDict({
    train: Dataset({
        features: ['sentence1', 'sentence2', 'label', 'idx'],
        num_rows: 3668
    })
    validation: Dataset({
        features: ['sentence1', 'sentence2', 'label', 'idx'],
        num_rows: 408
    })
    test: Dataset({
        features: ['sentence1', 'sentence2', 'label', 'idx'],
        num_rows: 1725
    })
})
将两个句子一块输入进bert
#法1
tokenized_dataset = tokenizer(
    raw_datasets["train"]["sentence1"],
    raw_datasets["train"]["sentence2"],
    padding=True,
    truncation=True,
)
#法2
def tokenize_function(example):
    return tokenizer(example["sentence1"], example["sentence2"], truncation=True)
tokenized_datasets = raw_datasets.map(tokenize_function, batched=True)
tokenized_datasets
map()

迭代器函数,能够对数据集做批处理,()内能添加函数。

def tokenize_function(example):
    return tokenizer(example["sentence1"], example["sentence2"], truncation=True)
tokenized_datasets = raw_datasets.map(tokenize_function, batched=True)
Dynamic padding()

动态padding,但不适合TPU

from transformers import DataCollatorWithPadding

data_collator = DataCollatorWithPadding(tokenizer=tokenizer)
samples = tokenized_datasets["train"][:8]
samples = {k: v for k, v in samples.items() if k not in ["idx", "sentence1", "sentence2"]}
[len(x) for x in samples["input_ids"]]
samples = tokenized_datasets["train"][:8]
samples = {k: v for k, v in samples.items() if k not in ["idx", "sentence1", "sentence2"]}
[len(x) for x in samples["input_ids"]]

Training

定义要训练的参数,参数是权重要保存的位置:

from transformers import TrainingArguments

training_args = TrainingArguments("test-trainer")

定义模型:

from transformers import AutoModelForSequenceClassification

model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2

定义训练器:

from transformers import Trainer

trainer = Trainer(
    model,
    training_args,
    train_dataset=tokenized_datasets["train"],
    eval_dataset=tokenized_datasets["validation"],
    data_collator=data_collator,
    tokenizer=tokenizer,
)

微调:

trainer.train()

这样就开始微调以及每500步报告一次loss;

Evaluation

trainer开始预测:

predictions = trainer.predict(tokenized_datasets["validation"])
print(predictions.predictions.shape, predictions.label_ids.shape)

输出内容: predict() method is another named tuple with three fields: predictions, label_ids, and metrics. The metrics field will just contain the loss on the dataset passed, as well as some time metrics (how long it took to predict, in total and on average).

Evaluate library.

调用计算评测:

evaluate.load():

import evaluate

metric = evaluate.load("glue", "mrpc")
metric.compute(predictions=preds, references=predictions.label_ids)
{'accuracy': 0.8578431372549019, 'f1': 0.8996539792387542}
compute_metrics() function:
def compute_metrics(eval_preds):
    metric = evaluate.load("glue", "mrpc")
    logits, labels = eval_preds
    predictions = np.argmax(logits, axis=-1)
    return metric.compute(predictions=predictions, references=labels)
从训练到评测整个过程
def compute_metrics(eval_preds):#定义评价方式
    metric = evaluate.load("glue", "mrpc")
    logits, labels = eval_preds
    predictions = np.argmax(logits, axis=-1)
    return metric.compute(predictions=predictions, references=labels)
#训练参数保存位置以及evaluste按照epoch进行
training_args = TrainingArguments("test-trainer", evaluation_strategy="epoch")
model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2)
#训练器定义
trainer = Trainer(
    model,
    training_args,
    train_dataset=tokenized_datasets["train"],
    eval_dataset=tokenized_datasets["validation"],
    data_collator=data_collator,
    tokenizer=tokenizer,
    compute_metrics=compute_metrics,
)
trainer.train()

整个训练过程:

数据预处理
from datasets import load_dataset
from transformers import AutoTokenizer, DataCollatorWithPadding

raw_datasets = load_dataset("glue", "mrpc")
checkpoint = "bert-base-uncased"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)


def tokenize_function(example):
    return tokenizer(example["sentence1"], example["sentence2"], truncation=True)


tokenized_datasets = raw_datasets.map(tokenize_function, batched=True)
data_collator = DataCollatorWithPadding(tokenizer=tokenizer)
将数据修改成trainer需要的模式
tokenized_datasets = tokenized_datasets.remove_columns(["sentence1", "sentence2", "idx"])
tokenized_datasets = tokenized_datasets.rename_column("label", "labels")
tokenized_datasets.set_format("torch")
tokenized_datasets["train"].column_names
dataloader
from torch.utils.data import DataLoader

train_dataloader = DataLoader(
    tokenized_datasets["train"], shuffle=True, batch_size=8, collate_fn=data_collator
)
eval_dataloader = DataLoader(
    tokenized_datasets["validation"], batch_size=8, collate_fn=data_collator
)

检查数据预处理是否有问题:

for batch in train_dataloader:
    break
{k: v.shape for k, v in batch.items()}
{'attention_mask': torch.Size([8, 65]),
 'input_ids': torch.Size([8, 65]),
 'labels': torch.Size([8]),
 'token_type_ids': torch.Size([8, 65])}

定义模型:

from transformers import AutoModelForSequenceClassification

model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2)

检查是否有问题:

outputs = model(**batch)
print(outputs.loss, outputs.logits.shape)
tensor(0.5441, grad_fn=<NllLossBackward>) torch.Size([8, 2])

optimizer&learning rate scheduler:

from transformers import AdamW

optimizer = AdamW(model.parameters(), lr=5e-5)
from transformers import get_scheduler

num_epochs = 3
num_training_steps = num_epochs * len(train_dataloader)
lr_scheduler = get_scheduler(
    "linear",
    optimizer=optimizer,
    num_warmup_steps=0,
    num_training_steps=num_training_steps,
)
print(num_training_steps)

训练:

from tqdm.auto import tqdm

progress_bar = tqdm(range(num_training_steps))#可视化训练过程

model.train()
for epoch in range(num_epochs):
    for batch in train_dataloader:
        batch = {k: v.to(device) for k, v in batch.items()}
        outputs = model(**batch)
        loss = outputs.loss
        loss.backward()

        optimizer.step()
        lr_scheduler.step()
        optimizer.zero_grad()
        progress_bar.update(1)

evaluate:

import evaluate

metric = evaluate.load("glue", "mrpc")
model.eval()
for batch in eval_dataloader:
    batch = {k: v.to(device) for k, v in batch.items()}
    with torch.no_grad():
        outputs = model(**batch)

    logits = outputs.logits
    predictions = torch.argmax(logits, dim=-1)
    metric.add_batch(predictions=predictions, references=batch["labels"])

metric.compute()

改为多GPU训练:

+ from accelerate import Accelerator
  from transformers import AdamW, AutoModelForSequenceClassification, get_scheduler

+ accelerator = Accelerator()

  model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2)
  optimizer = AdamW(model.parameters(), lr=3e-5)

- device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu")
- model.to(device)

+ train_dataloader, eval_dataloader, model, optimizer = accelerator.prepare(
+     train_dataloader, eval_dataloader, model, optimizer
+ )

  num_epochs = 3
  num_training_steps = num_epochs * len(train_dataloader)
  lr_scheduler = get_scheduler(
      "linear",
      optimizer=optimizer,
      num_warmup_steps=0,
      num_training_steps=num_training_steps
  )

  progress_bar = tqdm(range(num_training_steps))

  model.train()
  for epoch in range(num_epochs):
      for batch in train_dataloader:
-         batch = {k: v.to(device) for k, v in batch.items()}
          outputs = model(**batch)
          loss = outputs.loss
-         loss.backward()
+         accelerator.backward(loss)

          optimizer.step()
          lr_scheduler.step()
          optimizer.zero_grad()
          progress_bar.update(1)

多卡训练:

accelerate config#设置config
accelerate launch train.py

DATASETS使用自己的数据

本地加载:

from datasets import load_dataset

squad_it_dataset = load_dataset("json", data_files="SQuAD_it-train.json", field="data")
#加载多个
data_files = {"train": "SQuAD_it-train.json", "test": "SQuAD_it-test.json"}
squad_it_dataset = load_dataset("json", data_files=data_files, field="data")
#不解压
data_files = {"train": "SQuAD_it-train.json.gz", "test": "SQuAD_it-test.json.gz"}
squad_it_dataset = load_dataset("json", data_files=data_files, field="data")

remote data load:

url = "https://github.com/crux82/squad-it/raw/master/"
data_files = {
    "train": url + "SQuAD_it-train.json.gz",
    "test": url + "SQuAD_it-test.json.gz",
}
squad_it_dataset = load_dataset("json", data_files=data_files, field="data")

tsv格式和和csv格式区别:tst用\t分隔,因此加载和csv相同,只是用的分隔符不一样

from datasets import load_dataset

data_files = {"train": "drugsComTrain_raw.tsv", "test": "drugsComTest_raw.tsv"}
# \t is the tab character in Python
drug_dataset = load_dataset("csv", data_files=data_files, delimiter="\t")

提取部分数据查看:

drug_sample = drug_dataset["train"].shuffle(seed=42).select(range(1000))
# Peek at the first few examples
drug_sample[:3]
---------------------
{'Unnamed: 0': [87571, 178045, 80482],
 'drugName': ['Naproxen', 'Duloxetine', 'Mobic'],
 'condition': ['Gout, Acute', 'ibromyalgia', 'Inflammatory Conditions'],
 'review': ['"like the previous person mention, I&#039;m a strong believer of aleve, it works faster for my gout than the prescription meds I take. No more going to the doctor for refills.....Aleve works!"',
  '"I have taken Cymbalta for about a year and a half for fibromyalgia pain. It is great\r\nas a pain reducer and an anti-depressant, however, the side effects outweighed \r\nany benefit I got from it. I had trouble with restlessness, being tired constantly,\r\ndizziness, dry mouth, numbness and tingling in my feet, and horrible sweating. I am\r\nbeing weaned off of it now. Went from 60 mg to 30mg and now to 15 mg. I will be\r\noff completely in about a week. The fibro pain is coming back, but I would rather deal with it than the side effects."',
  '"I have been taking Mobic for over a year with no side effects other than an elevated blood pressure.  I had severe knee and ankle pain which completely went away after taking Mobic.  I attempted to stop the medication however pain returned after a few days."'],
 'rating': [9.0, 3.0, 10.0],
 'date': ['September 2, 2015', 'November 7, 2011', 'June 5, 2013'],
 'usefulCount': [36, 13, 128]}

验证数据:

for split in drug_dataset.keys():
    assert len(drug_dataset[split]) == len(drug_dataset[split].unique("Unnamed: 0"))

修改数据列名:

drug_dataset = drug_dataset.rename_column(
    original_column_name="Unnamed: 0", new_column_name="patient_id"
)

替换成小写:

def lowercase_condition(example):
    return {"condition": example["condition"].lower()}
drug_dataset.map(lowercase_condition)

数据筛选:

用于去掉不符合条件的数据:

def filter_nones(x):
    return x["condition"] is not None

用lambda函数来写:

lambda <arguments> : <expression>
lambda x : x * x
(lambda base, height: 0.5 * base * height)(4, 8)
----------
drug_dataset = drug_dataset.filter(lambda x: x["condition"] is not None)
drug_dataset = drug_dataset.map(lowercase_condition)
# Check that lowercasing worked
drug_dataset["train"]["condition"][:3]

创建新列:

def compute_review_length(example):
    return {"review_length": len(example["review"].split())}
drug_dataset = drug_dataset.map(compute_review_length)
# Inspect the first training example
drug_dataset["train"][0]

数据排序查看:

drug_dataset["train"].sort("review_length")[:3]

筛掉网页字符:

import html

text = "I&#039;m a transformer called BERT"
html.unescape(text)、
drug_dataset = drug_dataset.map(lambda x: {"review": html.unescape(x["review"])})

map()函数中使用batched=True能加速函数:

%time tokenized_dataset = drug_dataset.map(tokenize_function, batched=True)

%time为jupyter notebook魔法函数,只执行一次。

数据集分块,将train、valid、test汇总到一个datasetdict中:

drug_dataset_clean = drug_dataset["train"].train_test_split(train_size=0.8, seed=42)
# Rename the default "test" split to "validation"
drug_dataset_clean["validation"] = drug_dataset_clean.pop("test")
# Add the "test" set to our `DatasetDict`
drug_dataset_clean["test"] = drug_dataset["test"]
drug_dataset_clean
---
DatasetDict({
    train: Dataset({
        features: ['patient_id', 'drugName', 'condition', 'review', 'rating', 'date', 'usefulCount', 'review_length', 'review_clean'],
        num_rows: 110811
    })
    validation: Dataset({
        features: ['patient_id', 'drugName', 'condition', 'review', 'rating', 'date', 'usefulCount', 'review_length', 'review_clean'],
        num_rows: 27703
    })
    test: Dataset({
        features: ['patient_id', 'drugName', 'condition', 'review', 'rating', 'date', 'usefulCount', 'review_length', 'review_clean'],
        num_rows: 46108
    })
})

保存数据集:

Data formatFunction
ArrowDataset.save_to_disk()
CSVDataset.to_csv()
JSONDataset.to_json()
drug_dataset_clean.save_to_disk("drug-reviews")

提取数据集:

from datasets import load_from_disk

drug_dataset_reloaded = load_from_disk("drug-reviews")
drug_dataset_reloaded
---
DatasetDict({
    train: Dataset({
        features: ['patient_id', 'drugName', 'condition', 'review', 'rating', 'date', 'usefulCount', 'review_length'],
        num_rows: 110811
    })
    validation: Dataset({
        features: ['patient_id', 'drugName', 'condition', 'review', 'rating', 'date', 'usefulCount', 'review_length'],
        num_rows: 27703
    })
    test: Dataset({
        features: ['patient_id', 'drugName', 'condition', 'review', 'rating', 'date', 'usefulCount', 'review_length'],
        num_rows: 46108
    })
})

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

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

相关文章

软件测试 利器 | AppCrawler 自动遍历测试工具实践(一)

本文为霍格沃兹测试学院学院学员课程学习笔记&#xff0c;系统学习交流文末加群。 AppCrawler 是由霍格沃兹测试学院校长思寒开源的一个项目,通过名字我们大概也能猜出个方向&#xff0c;Crawler 是爬虫的意思&#xff0c;App 的爬虫&#xff0c;遍历 App &#xff1a; 官方 G…

linux性能优化-中断

一、概念 中断其实是一种异步的事件处理机制&#xff0c;可以提高系统的并发处理能力。Linux将中断处理过程分成了两个阶段&#xff1a;上半部和下半部 &#xff08;1&#xff09;上半部用来快速处理中断&#xff0c;它在中断禁止模式下运行&#xff0c;主要处理跟硬件紧密相关…

云计算是什么

&#x1f4d2;博客主页&#xff1a; 微笑的段嘉许博客主页 &#x1f389;欢迎关注&#x1f50e;点赞&#x1f44d;收藏⭐留言&#x1f4dd; &#x1f4cc;本文由微笑的段嘉许原创&#xff01; &#x1f4c6;51CTO首发时间&#xff1a;&#x1f334;2023年2月1日&#x1f334; ✉…

gcc 简介

一、gcc简介gcc与g&#xff0c;当程序中出现using namespace std等带有c特性的语句时&#xff0c;如果用gcc编译时&#xff0c;必须显式地指明这个程序要用c编译库编译&#xff0c;而g可以直接编译。二、gcc支持的文件.c&#xff0c;c语言的源程序.C, c的源程序.cc&#xff0c;…

数据结构——堆的介绍以及应用

前言&#xff1a;对于数据结构而言&#xff0c;大多存在着对应的物理结构和逻辑结构&#xff0c;而我们一开始介绍的顺序表&#xff0c;链表&#xff0c;栈&#xff0c;队列等的物理结构和逻辑结构还是比较类似的。今天要介绍的堆则有所不同&#xff0c;其物理结构是数组&#…

JS前端基于canvas给图片添加水印,并下载带有水印的图片

基于canvas给图片添加水印实现效果图图片添加水印的步骤1.获取图片路径&#xff0c;将图片转换为canvas2.canvas画布上绘制文字水印3.水印绘制完成后&#xff0c;将canvas转换为图片格式4.水印绘制完成后&#xff0c;将canvas下载为图片完整代码总结1、在utils.js 封装添加水印…

POE交换机全方位解读(中)

POE供电距离到底怎么算 只针对符合IEEE802.3af/at 标准PoE设备 ① 网线对供电距离的影响 首先我们先来看下表IEEE802.af和IEEE802.3at标准中对Cat5e网线要求&#xff1a; 说明&#xff1a;Type 1 value和Type 2 value 分别指IEEE802.3af和IEEE802.3at的要求。 从表中可以看出&a…

PCB电路板单面板和双面板的区别和共同点

PCB电路板可以分为单面板、双面板和多面板&#xff0c;我们常用的主要是单面板和双面板&#xff0c;那么单面板和双面板有哪些区别呢&#xff1f;在了解二者区别前&#xff0c;沐渥小编先给大家介绍一下什么是单面板和双面板。 单面板是指单面的线路板&#xff0c;元器件在一面…

如何实现报表集成?(四)——权限集成

在上一篇&#xff0c;我们介绍了报表工具的资源集成&#xff0c;基本知道了报表工具链接、模块、页面和移动端如何实现集成。 这一篇&#xff0c;我们看下如何做权限集成。使用第三方系统的资源权限验证 实际上往往存在多个系统需要统一权限认证&#xff0c;用户要求将某个系统…

PixelLib图像分割

文章目录前言一、PixelLib依赖安装二、实例模型训练前言 图像分割就是把图像分成若干个特定的、具有独特性质的区域并提出感兴趣目标的技术和过程。它是由图像处理到图像分析的关键步骤。 传统的图像分割方法主要分以下几类&#xff1a;基于阈值的分割方法、基于区域的分割方…

Mybatis核心原理梳理

文章目录Mybatis的简单使用Mybatis组件名词介绍Mybatis主要工作流程Mybatis如何控制事务Mybatis中事务的生命周期一二级缓存分别如何生效一二级缓存分别如何失效一级缓存的实体可能会被修改Mybatis中的已经存在PooledDataSource连接池为啥还选择Durid等为啥连接close之后被没有…

如何获取 WWDC 视频对应的官方源代码?

零 概览 每年的 WWDC&#xff08;The Apple Worldwide Developers Conference&#xff09; 是 Apple 开发者的盛大节日&#xff0c;我们可以从 WWDC 海量官方视频中学到大量的知识。 不过&#xff0c;有些视频仅包含一些“惨不忍睹”&#xff08;由于网络质量差等原因&#…

【C++】C++ 入门(二)(引用)

目录 一、前言 二、引用 1、引用的概念 2、引用特性 3、使用场景 3.1、做参数 3.2、做返回值 4、传值、传引用效率比较 值和引用作为参数的性能比较 值和引用作为返回值类型的性能比较 5、常引用 6、引用和指针的区别 一、前言 上一篇文章我们讲解了 C 的命名空间…

IDEA快速生成实体类(加注释)

步骤&#xff1a; 1、点击右侧的datesource图标&#xff0c;要是没有该图标&#xff0c;请去自行百度 2、点击 号 3、选择 datasource 4、选择 mysql 1、填写一个连接名&#xff0c;随便填什么都行 2、不用选择&#xff0c;默认就行 3、填写数据库连接的 IP地址&#xff0c;比…

Android 时间工具类

最近总结了一下时间相关的用法&#xff0c;如下。 1、日期转换为字符串 默认"yyyy-MM-dd HH:mm:ss" 2、任意类型日期字符串转时间 3、获取当前对应格式的日期 4、获取当前对应格式的日期 默认"yyyyMMddHHmmssSSS" 5、计算该天是星期几 6、获取星期几…

XSS - 进阶篇(蓝莲花的基本使用)

数据来源 本文仅用于信息安全的学习&#xff0c;请遵守相关法律法规&#xff0c;严禁用于非法途径。若观众因此作出任何危害网络安全的行为&#xff0c;后果自负&#xff0c;与本人无关。 xss漏洞接收平台-蓝莲花&#xff1a; 1&#xff09;下载并安装Phpstudy&#xff08;安…

分享157个ASP源码,总有一款适合您

ASP源码 分享157个ASP源码&#xff0c;总有一款适合您 下面是文件的名字&#xff0c;我放了一些图片&#xff0c;文章里不是所有的图主要是放不下...&#xff0c; 157个ASP源码下载链接&#xff1a;https://pan.baidu.com/s/1_IF9pFQX4NM-kmJyIAGBQQ?pwdcb55 提取码&#x…

RBAC简介

RBAC BAC基于角色的访问控制&#xff0c;RBAC认为权限授权的过程可以抽象地概括为&#xff1a;Who是否可以对What进行How的访问操作 RBAC简介 基于角色的权限访问控制模型 在RBAC模型里面&#xff0c;有3个基础组成部分&#xff0c;分别是&#xff1a;用户、角色和权限。RB…

微信公众号小程序怎么做?

​微信公众号小程序在当下已经成为人们日常生活中不可或缺的工具&#xff0c;在用户体验方面也做得很好&#xff0c;不仅可以实现沟通和交流&#xff0c;还可以通过微信公众号进行在线预约服务。那么关于微信公众号小程序怎么做&#xff0c;下面就给大家说说。 1、注册微信公众…

Cadence PCB仿真 使用 Allegro PCB SI 元器件端口设置的PDN分析功能介绍图文教程

🏡《总目录》   🏡《分目录》 目录 1,概述2,启动方法3,功能介绍3.1,元器件设置列表(Device)3.2,端口设置列表(Ports)4,总结1,概述 在进行PDN分析时需要对电源网络涉及到的所有元器件的指定端口的参数进行配置。本文介绍PDN网络元器件端口设置的功能。 2,启动…