HuggingFace与自然语言处理(从框架学习到经典项目实践)[ 01 API操作 ]

本教程适用与第一次接触huggingface与相应框架和对nlp任务感兴趣的朋友,该栏目目前更新总结如下:

  1. ​​Tokenizer​​:
    支持单句/双句编码,自动处理特殊符号和填充。
    批量编码提升效率,适合训练数据预处理。
  2. Datasets​​:
    统一 API 处理多种格式数据(远程/本地)。
    内置排序、分桶、拆分等功能,简化数据准备流程。
  3. 应用场景​​:
    文本分类、NER 等任务的数据预处理。
    快速实验模型(如 BERT 微调)。
    通过 Hugging Face 工具,可高效完成 NLP 任务的 ​​数据编码 → 处理 → 训练​​ 全流程。

在这里插入图片描述

Hugging Face 与自然语言处理(NLP)介绍

Hugging Face 是一家专注于 自然语言处理(NLP)机器学习(ML) 的公司,以其开源库 Transformers 闻名。它提供了 预训练模型(Pre-trained Models)、数据集(Datasets)、训练工具(Trainer) 等,极大降低了 NLP 研究和应用的门槛。


1. Hugging Face 的核心产品

(1) Transformers 库

核心功能:提供 BERT、GPT、T5、RoBERTa 等预训练模型,支持 文本分类、翻译、问答、文本生成 等任务。
特点
PyTorch & TensorFlow 兼容:支持两种主流深度学习框架。
Pipeline API:几行代码即可完成 NLP 任务(如情感分析、命名实体识别)。
模型微调(Fine-tuning):可基于自己的数据调整预训练模型。

示例代码(情感分析)

from transformers import pipelineclassifier = pipeline("sentiment-analysis")
result = classifier("I love Hugging Face!")
print(result)  # [{'label': 'POSITIVE', 'score': 0.9998}]

(2) Datasets 库

提供 10,000+ 数据集(如 GLUE、SQuAD、IMDb),支持快速加载和预处理。
特点
内存优化:流式加载大数据集(如 Wikipedia)。
数据预处理:内置 tokenization、批处理等功能。

示例代码(加载 IMDb 数据集)

from datasets import load_datasetdataset = load_dataset("imdb")
print(dataset["train"][0])  # {'text': 'Great movie!', 'label': 1}

(3) Model Hub

托管 50,000+ 预训练模型,涵盖 NLP、CV、语音等领域。
支持社区共享:用户可以上传自己的模型供他人使用。

示例(下载 BERT 模型)

from transformers import BertModelmodel = BertModel.from_pretrained("bert-base-uncased")

(4) Spaces(模型部署)

免费托管 AI 应用(如聊天机器人、文本生成器)。
支持 Gradio、Streamlit 等交互式 UI。


2. 自然语言处理(NLP)简介

NLP(Natural Language Processing)是 让计算机理解、生成人类语言 的技术,应用广泛:

(1) 主要任务

任务示例
文本分类情感分析(正面/负面)
命名实体识别(NER)识别 “Apple” 是公司还是水果
机器翻译中英互译
文本生成GPT-3 写文章
问答系统Siri、ChatGPT
文本摘要自动生成新闻摘要

(2) 关键技术

词嵌入(Word Embeddings)(如 Word2Vec、GloVe)
Transformer 架构(如 BERT、GPT)
迁移学习(Transfer Learning):用预训练模型微调下游任务。

(3) Hugging Face 在 NLP 中的作用

降低 NLP 门槛:无需从头训练模型,直接使用预训练模型。
标准化流程:统一 API(如 AutoModelAutoTokenizer)。
社区驱动:研究者共享模型,推动 NLP 发展。


3. 典型 NLP 任务实战

(1) 文本分类(情感分析)

from transformers import pipelineclassifier = pipeline("text-classification", model="distilbert-base-uncased-finetuned-sst-2-english")
result = classifier("Hugging Face is awesome!")
print(result)  # [{'label': 'POSITIVE', 'score': 0.9998}]

(2) 命名实体识别(NER)

ner = pipeline("ner", model="dbmdz/bert-large-cased-finetuned-conll03-english")
result = ner("Apple is headquartered in Cupertino.")
print(result)  # [{'entity': 'I-ORG', 'word': 'Apple'}, ...]

(3) 文本生成(GPT-2)

generator = pipeline("text-generation", model="gpt2")
result = generator("Once upon a time,", max_length=30)
print(result[0]["generated_text"])

4. 学习资源

Hugging Face 官方课程:https://huggingface.co/course
Transformers 文档:https://huggingface.co/docs/transformers
NLP 经典书籍:《Speech and Language Processing》(Jurafsky & Martin)


总结

方面Hugging Face 的贡献
模型提供 BERT、GPT 等预训练模型
数据托管大量 NLP 数据集
工具简化训练、推理、部署流程
社区推动开源 NLP 生态

Hugging Face 已成为 NLP 领域的 “GitHub”,无论是研究者还是开发者,都能快速构建 NLP 应用。🚀

下面专栏将一步一步学习huggingface框架的基础操作:

编码

新建编码器

from transformers import BertTokenizer
tokenizers = BertTokenizer.from_pretrained(pretrained_model_name_or_path='google-bert/bert-base-chinese',cache_dir=None, // 默认缓存,也可以指定目录force_download=False // 强制下载
)

编码处理

encode() 一次编码一个句子或者一对句子

# 基本编码
out = tokenizers.encode_plus(text=sents[0],text_pair=sents[1],max_length=25,padding='max_length',truncation=True,return_tensors=None
)
print(out)
print(tokenizers.decode(token_ids=out['input_ids']))# 输出
{'input_ids': [101, 872, 4991, 1762, 3441, 677, 4692, 7599, 3250, 102, 4692, 7599, 3250, 4638, 782, 1762, 3517, 677, 4692, 872, 102, 0, 0, 0, 0], 'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0]}
[CLS] 你 站 在 桥 上 看 风 景 [SEP] 看 风 景 的 人 在 楼 上 看 你 [SEP] [PAD] [PAD] [PAD] [PAD]

(1)参数text和text_pair分别为两个句子,如果只想编码一个句子,则可让text_pair传None。

(2)参数truncation=True表明当句子长度大于max_length时,截断句子。

(3)参数padding= 'max_length’表明当句子长度不足max_length时,在句子的后面补充PAD,直到max_length长度。

(4)参数add_special_tokens=True表明需要在句子中添加特殊符号。

(5)参数max_length=25定义了max_length的长度。

(6)参数return_tensors=None表明返回的数据类型为list格式,也可以赋值为tf、pt、np,分别表示TensorFlow、PyTorch、NumPy数据格式。

输出解释:

从输出可以看出,编码工具把两个句子前后拼接在一起,中间使用[SEP]符号分隔,在整个句子的头部添加符号[CLS],在整个句子的尾部添加符号[SEP],因为句子的长度不足max_length,所以补充了4个[PAD]。

进阶编码函数 encode_plus()

# 进阶编码函数
out = tokenizers.encode_plus(text=sents[2],text_pair=sents[3],max_length=25,padding='max_length',truncation=True,add_special_tokens=True,return_tensors=None,return_token_type_ids=True,return_attention_mask=True,return_special_tokens_mask=True,return_length=True,
)
# input_ids 编码后的词
# token_type_ids 第1个句子和特殊符号的位置是0,第2个句子的位置是1
# special_tokens_mask 特殊符号的位置是1,其他位置是0
# attention_mask PAD的位置是0,其他位置是1
# length 返回句子长度for key, value in out.items():print(key, value)print(tokenizers.decode(token_ids=out['input_ids'][0]))# 输出 === === === === === === === ===
input_ids [101, 3209, 3299, 6163, 7652, 749, 872, 4638, 4970, 2094, 102, 872, 6163, 7652, 749, 1166, 782, 4638, 3457, 102, 0, 0, 0, 0, 0]
token_type_ids [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0]
special_tokens_mask [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 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, 1, 1, 1, 0, 0, 0, 0, 0]
length 25
  • input_ids 编码后的词
  • token_type_ids 第1个句子和特殊符号的位置是0,第2个句子的位置是1
  • special_tokens_mask 特殊符号的位置是1,其他位置是0
  • attention_mask PAD的位置是0,其他位置是1
  • length 返回句子长度

批量编码函数

print("# 批量编码函数 ===============")
# 批量编码函数
batch_sents = [sents[0], sents[1], sents[2], sents[3]]
out = tokenizers.batch_encode_plus(batch_text_or_text_pairs=batch_sents,max_length=25,padding='max_length',truncation=True,add_special_tokens=True,return_tensors=None,return_token_type_ids=True,return_attention_mask=True,return_special_tokens_mask=True,return_length=True,
)
print(out)
for key, value in out.items():print(key, value)
print(tokenizers.decode(token_ids=out['input_ids'][0]))## 输出 ========
input_ids [[101, 872, 4991, 1762, 3441, 677, 4692, 7599, 3250, 102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [101, 4692, 7599, 3250, 4638, 782, 1762, 3517, 677, 4692, 872, 102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [101, 3209, 3299, 6163, 7652, 749, 872, 4638, 4970, 2094, 102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [101, 872, 6163, 7652, 749, 1166, 782, 4638, 3457, 102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
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]]
special_tokens_mask [[1, 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, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]
length [10, 12, 11, 10]
attention_mask [[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
[CLS] 你 站 在 桥 上 看 风 景 [SEP] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD]

可以看到,这里的输出都是二维的list了,表明这是一个批量的编码。这个函数在后续章节中会多次用到。

字典

获取字典

添加字典元素

from transformers import BertTokenizer
tokenizers = BertTokenizer.from_pretrained(pretrained_model_name_or_path='google-bert/bert-base-chinese',cache_dir=None,force_download=False
)# 查看字典
vocab = tokenizers.get_vocab()
print(vocab)
print(type(vocab))
print(len(vocab))
print('沐浴' in vocab)# 添加字典元素
print("添加字典元素========")
tokenizers.add_tokens(new_tokens=["明月","装饰","窗子"])
tokenizers.add_special_tokens({'eos_token': '[EOS]'})
out = tokenizers.encode(text='明月装饰了你的窗子[EOS]'
, text_pair=None ,add_special_tokens=True,truncation=True,padding="max_length",max_length=10,return_tensors=None)
print(out)
print(tokenizers.decode(out))# 输出 ============
添加字典元素========
[101, 21128, 21129, 749, 872, 4638, 21130, 21131, 102, 0]
[CLS] 明月 装饰 了 你 的 窗子 [EOS] [SEP] [PAD]

可以看到,“明月”已经被识别为一个词,而不是两个词,新的特殊符号[EOS]也被正确识别。

数据集工具

在以往的自然语言处理任务中会花费大量的时间在数据处理上,针对不同的数据集往往需要不同的处理过程,各个数据集的格式差异大,处理起来复杂又容易出错。针对以上问题,HuggingFace提供了统一的数据集处理工具,让开发者在处理各种不同的数据集时可以通过统一的API处理,大大降低了数据处理的工作量。

远程加载并且保存

# 加载数据集
from datasets import load_dataset,load_from_disk
dataset = load_dataset(path="lansinuote/ChnSentiCorp",trust_remote_code=True)
print(dataset)# 加载数据集并且保存
load_dataset(path="glue",name="sst2",split='train')
dataset.save_to_disk(dataset_dict_path='./data/ChnSentiCorp')

磁盘加载


# 从磁盘加载数据集并且查看
dataset = load_from_disk(dataset_path="./data/ChnSentiCorp")
print(dataset)
dataset = dataset["train"]
print(dataset)
for i in [12, 17, 20, 26, 56]: print(dataset[i])## 输出 =================
DatasetDict({train: Dataset({features: ['text', 'label'],num_rows: 9600})validation: Dataset({features: ['text', 'label'],num_rows: 1200})test: Dataset({features: ['text', 'label'],num_rows: 1200})
})
Dataset({features: ['text', 'label'],num_rows: 9600
})
{'text': '轻便,方便携带,性能也不错,能满足平时的工作需要,对出差人员来说非常不错', 'label': 1}
{'text': '很好的地理位置,一蹋糊涂的服务,萧条的酒店。', 'label': 0}
{'text': '非常不错,服务很好,位于市中心区,交通方便,不过价格也高!', 'label': 1}
{'text': '跟住招待所没什么太大区别。 绝对不会再住第2次的酒店!', 'label': 0}
{'text': '价格太高,性价比不够好。我觉得今后还是去其他酒店比较好。', 'label': 0}

数据集的分析

数据排序

# 数据排序
print(dataset['label'][:10])
# 让数据按照label排序
sorted_dataset = dataset.sort("label")
print(sorted_dataset['label'][:10])
print(sorted_dataset['label'][-10:])
# “和sort()函数相对应,可以使用shuffle()函数再次打乱数据,”
shuffled_dataset = dataset.shuffle()
print(shuffled_dataset["label"][:10])

数据抽样

# 数据集的抽样 抽样后形成新的数据子集
print(shuffled_dataset.select([1,2,3,4,99]))
for i in range(5): print(shuffled_dataset[i])

{‘text’: ‘指纹机。价格略高。散热有待加强。播放720P高清电影还是有点卡。略重。’, ‘label’: 0}

{‘text’: ‘轻便、小巧、配置不错! 送货速度快,当天下午四点多下单,次日上午十点到货。’, ‘label’: 1}

{‘text’: ‘我借给一个朋友看的时候,问她看的时候会不会想哭,她说会。我也是一样的感受。为什么又说不上。只是感觉程然描绘得很细腻,很真实。禅学,我是看了这本书才有所了解,因为当时心很乱,需要这类书的安慰。看来以后,在当当网等了很久才终于没缺货,终于买到了。捧在手里,感动和悲伤同在。但是这本书真的很适合我们去读。在这纷乱的世界里,能有这本书作伴,谢谢程然了!’, ‘label’: 1}

{‘text’: ‘穿越的书我买了好几套了 在当当网上看见《蔓蔓清萝》的评论还多好了 就买来看看 看了文章后真的让人有些失望 写得不是那么生动 感觉太简单化了 反而我比较喜欢《步步惊心》这本书 也是穿越的 o(∩_∩)o…’, ‘label’: 0}

升级版数据集拆分

# 训练集测试集拆分
train_dataset,test_dataset = dataset.train_test_split(test_size=0.2).values()
print(train_dataset)
print(test_dataset)# 输出 === === === ===
Dataset({features: ['text', 'label'],num_rows: 7680
})
Dataset({features: ['text', 'label'],num_rows: 1920
})

数据分桶可以使用shared ()函数把数据均匀地分为n部分,代码如下:

dataset.shard(num_shards=4, index=0)

(1)参数num_shards表明要把数据均匀地分为几部分,例子中分为4部分。

(2)参数index表明要取出第几份数据,例子中为取出第0份。

运行结果如下:Dataset({features: ['text', 'label'],num_rows: 2400})

过滤数据

字段 操作


# 字段重命名
dataset_Sentence_label = dataset.rename_column("text","sentence")
print(dataset_Sentence_label)# 字段删除
dataset.remove_columns("label")
print(dataset)

映射与数据格式


# 映射函数map
def add_prefix(example):example["sentence"] = "prefix:" + example["sentence"]return examplemaped_dataset = dataset_Sentence_label.map(add_prefix)
print(maped_dataset['sentence'][:10])
print(maped_dataset)# 设置数据格式
maped_dataset = maped_dataset.set_format(type="pandas",columns=['label'],output_all_columns=True)
print(maped_dataset)

数据导出

导出为 csv 文件

# 数据导出
dataset.to_csv("./data_csv/ChnSentiCorp.csv")
csv_dataset = load_dataset("csv",data_files="./data_csv/ChnSentiCorp.csv",split='train')
print(csv_dataset)
print(csv_dataset[:10])

导出为 json

dataset=load_dataset(path='seamew/ChnSentiCorp', split='train')
dataset.to_json(path_or_buf='./data/ChnSentiCorp.json')
#加载JSON格式数据
json_dataset=load_dataset(path='json',data_files='./data/ChnSentiCorp.json',split='train')
print(json_dataset[20])

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

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

相关文章

【LeetCode 42】接雨水(单调栈、DP、双指针)

题面: 思路: 能接雨水的点,必然是比两边都低(小)的点。有两种思路,一种是直接计算每个点的最大贡献(也就是每个点在纵向上最多能接多少水),另一种就是计算每个点在横向上…

【嵌入式开发-USB】

嵌入式开发-USB ■ USB简介 ■ USB简介

Visual Studio 项目转Qt项目

1. 先确保qmake 和 minGW (g) 路径都在系统变量内;或者通过WinR -> cmd 来检测, 如果能够 显示qmake 的信息 , g 的信息 , 就说明设置环境变量成功。 2. 打开项目文件夹,在这里打开cmd, 换…

总线通信篇:I2C、SPI、CAN 的底层结构与多机通信设计

本文为嵌入式通信协议系列第三章,深入剖析 MCU 世界中的三大总线协议 —— I2C、SPI 和 CAN。 这些总线协议广泛应用于传感器数据采集、Flash 存储、外设扩展、汽车电子、工业设备控制等领域,是嵌入式开发不可或缺的通信骨架。 📜 一、总线通信的基本概念 1.1 什么是总线?…

sherpa:介绍

更多内容:XiaoJ的知识星球 目录 1. sherpa 介绍 1. sherpa 介绍 sherpa是 Next-gen Kaldi 项目的部署框架。 sherpa 支持在各种平台上部署与语音相关的预训练模型,并提供多种语言绑定。 目前,sherpa 拥有以下子项目: k2-fsa/sh…

77.组合问题

主函数 combine def combine(self, n: int, k: int) -> List[List[int]]:result [] # 存放所有有效的组合self.backtracking(n, k, 1, [], result) # 从数字1开始搜索return result 作用:初始化并启动回溯过程。参数: n4:数字范围是1…

Oracle免费认证来袭

1、Oracle Cloud Infrastructure 2025 Foundations Associate” 🔗 考证地址:https://mylearn.oracle.com/ou/exam-unproctored/oracle-cloud-infrastructure-2025-foundations-associate-1z0-1085-25/148056/241954 2、Oracle Cloud Infrastructure 2…

【Unet++】

这是一篇关于语义分割U-net及其变体网络结构的介绍性文章,主要介绍了U-net、U-net以及U-net的基本结构、特点和应用。 以下是对这些核心内容的简要概述: 1. 语义分割U-net概述: - 基本结构:U-net是一种编码解码结构的网络,起初…

git可视化工具Fork软件的详细使用教程

Fork是一款流行的Git图形化客户端,适用于Windows和macOS平台。使用起来确实很方便,唯一的缺陷就是正版需要付费使用! Fork 安装 官网下载地址:Fork官网地址https://git-fork.com/ 支持 macOS 和 Windows。 安装完成后&#xff…

【JMeter技巧】GET请求如何传递Body参数?版本兼容性详解场景需求

在实际接口测试中,有时会遇到特殊需求:需要给GET请求传递Body参数。但JMeter默认配置下,GET请求的Body数据会被自动忽略。本文将介绍如何通过配置解决这个问题。 配置步骤 1. 版本要求(重要!) JMeter ≥ …

HTML5好看的水果蔬菜在线商城网站源码系列模板9

文章目录 1.设计来源1.1 主界面1.2 商品界面1.3 购物车界面1.4 心愿列表界面1.5 商品信息界面1.6 博客界面1.7 关于我们界面1.8 联系我们界面1.9 常见问题界面1.10 登录界面 2.效果和源码2.1 动态效果2.2 源代码 源码下载万套模板,程序开发,在线开发&…

es 里的Filesystem Cache 理解

文章目录 背景问题1,Filesystem Cache 里放的是啥问题2,哪些查询它们会受益于文件系统缓存问题3 查询分析 背景 对于es 优化来说常常看到会有一条结论给,给 JVM Heap 最多不超过物理内存的 50%,且不要超过 31GB(避免压…

存储器:DDR和独立显卡的GDDR有什么区别?

本文来简要对比DDR(Double Data Rate SDRAM)和GDDR(Graphics Double Data Rate SDRAM)的区别,重点说明它们在设计、性能和应用上的差异: 1. 设计目标与架构 DDR:通用型DRAM,设计为…

【Electron】electron-vue 借助 element-ui UI 库助力桌面应用开发

前面文章我们讲过 electron 让可以用 HTML、JS、CSS 开发桌面应用程序。而 electron-vue 是一个结合了 electron 与 vue 的套件。这样我们就能方便地使用 vue 快速开发桌面应用。但是,vue 只是在 js 这层面做了大量的便捷的操作。对 UI 并未过多涉及。此时如果您在开…

Linux/AndroidOS中进程间的通信线程间的同步 - 消息队列

本文介绍消息队列,它允许进程之间以消息的形式交换数据。数据的交换单位是整个消息。 POSIX 消息队列是引用计数的。只有当所有当前使用队列的进程都关闭了队列之后才会对队列进行标记以便删除。POSIX 消息有一个关联的优先级,并且消息之间是严格按照优…

深入理解进程与线程、进程池与线程池:企业级开发实战指南

简介 并发编程是现代软件开发的核心能力,而进程与线程、进程池与线程池是实现高效并发的关键技术。 本文将从基础概念出发,深入解析它们的工作原理、优势及适用场景,并提供Python、Java、C#等主流语言的实战代码,帮助开发者掌握企业级并发编程的最佳实践。 一、进程与线程…

解锁 LLM 推理速度:深入 FlashAttention 与 PagedAttention 的原理与实践

写在前面 大型语言模型 (LLM) 已经渗透到我们数字生活的方方面面,从智能问答、内容创作到代码辅助,其能力令人惊叹。然而,驱动这些强大模型的背后,是对计算资源(尤其是 GPU)的巨大需求。在模型推理 (Inference) 阶段,即模型实际对外提供服务的阶段,速度 (Latency) 和吞…

Go使用Gin写一个对MySQL的增删改查服务

首先用SQL创建一个包含id、name属性的users表 create table users (id int auto_incrementprimary key,name varchar(255) null );查询所有用户信息: func queryData(db *sql.DB, w http.ResponseWriter) {rows, err : db.Query("SELECT * FROM users"…

键盘弹起导致页面上移

问题:聊天页面,如果输入框设置了adjust-position属性为true,会导致键盘弹起时,整个页面上移,顶部导航栏也会跟着上移。 我想要的效果:键盘弹起时,页面内容上移,顶部导航栏保持不动 …

机器视觉的手机FPC油墨丝印应用

在现代智能手机制造过程中,精密的组件装配和质量控制是确保产品性能和用户体验的关键。其中,柔性印刷电路板(FPC)的油墨丝印工艺尤为关键,它不仅影响到电路板的美观,更直接关系到电路的导电性能和可靠性。而…