第20周:Pytorch文本分类入门
目录
前言
一、前期准备
1.1 环境安装导入包
1.2 加载数据
1.3 构建词典
1.4 生成数据批次和迭代器
二、准备模型
2.1 定义模型
2.2 定义示例
2.3 定义训练函数与评估函数
三、训练模型
3.1 拆分数据集并运行模型
3.2 使用测试数据集评估模型
总结
前言
🍨 本文为[🔗365天深度学习训练营]中的学习记录博客
🍖 原作者:[K同学啊]
说在前面
本周任务:了解文本分类的基本流程、学习常用数据清洗方法、学习如何使用jieba实现英文分词、学习如何构建文本向量
我的环境:Python3.8、Pycharm2020、torch1.12.1+cu113
数据来源:[K同学啊]
一、前期准备
1.1 环境安装导入包
本文是一个使用Pytorch实现的简单文本分类实战案例,在本案例中,我们将使用AG News数据集进行文本分类
需要确保已经安装了torchtext与poralocker库
PS:torchtext库的安装需要与Pytorch、python的版本进行匹配,具体可参考torchtext版本对应
import torch
import torch.nn as nn
import torchvision
from torchvision import transforms, datasets
import os,PIL,pathlib,warnings
from torchtext.datasets import AG_NEWS
from torchtext.vocab import build_vocab_from_iterator
import torchtext.data.utils as utils
from torch.utils.data import DataLoader
from torch import nn
import timewarnings.filterwarnings("ignore")
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(device)
1.2 加载数据
本文使用的数据集是AG News(AG's News Topic Classification Dataset)是一个广泛用于文本分;分类任务的数据集,尤其是在新闻领域,该数据集是由AG’s Corpus of News Ariticles收集整理而来,包含了四个主要的类别:世界、体育、商业和科技
torchtext.datasets.AG_NEWS是一个用于加载AG News数据集的torchtext数据集类,具体的参数如下:
- root:数据集的根目录,默认值是'.data'
- split:数据集的拆分train、test
- **kwargs:可选的关键字参数,可传递给torchtext.datasets.TextClassificationDataset类构造的函数
该类加载的数据集是一个列表,其中每个条目都是一个元祖,包含以下两个元素
- 一条新闻文章的文本内容
- 新闻文章所属的类别(一个整数,从1到4,分别对应世界、科技、体育和商业)
代码如下:
train_iter = AG_NEWS(split='train')
1.3 构建词典
torchtext.data.ttils.get_tokenizer()是一个用于将文本数据分词的函数,它返回一个分词器(tokenizer)函数,可以将一个字符串转换成一个单词的列表
函数原型:torchtext.data.ttils.get_tokenizer(tokenizer, language = 'en')
tokenizer参数是用于指定使用的分词器名称,可以是一下之一
- basic_english:用于基本英文文本的分词器
- moses:用于处理各种语言的分词器,支持多种选项
- spacy:使用spaCy分词器,需要安装spaCy库
- toktok:用于各种语言的分词器,速度较快
PS:分词器函数返回的单词列表中不包含任何标点符号或空格
代码如下:
tokenizer = utils.get_tokenizer('basic_english')def yield_tokens(data_iter):for _, text in data_iter:yield tokenizer(text)vocab = build_vocab_from_iterator(yield_tokens(train_iter),specials=["<unk>"])
vocab.set_default_index(vocab["<unk>"]) #设置默认索引,如果找不到单词,则会选择默认索引print(vocab(['here', 'is', 'an', 'example']))text_pipeline = lambda x: vocab(tokenizer(x))
label_pipeline = lambda x: int(x) - 1print(text_pipeline('here is an example'))
print(label_pipeline('10'))
输出结果:
[475, 21, 30, 5297]
[475, 21, 30, 5297]
9
1.4 生成数据批次和迭代器
代码如下:
def collate_batch(batch):label_list, text_list, offsets = [],[],[0]for (_label, _text) in batch:# 标签列表label_list.append(label_pipeline(_label))# 文本列表processed_text = torch.tensor(text_pipeline(_text),dtype=torch.int64)text_list.append(processed_text)#偏移量,即语句的总词汇量offsets.append(processed_text.size(0))label_list = torch.tensor(label_list, dtype=torch.int64)text_list = torch.cat(text_list)offsets = torch.tensor(offsets[:-1]).cumsum(dim=0)return label_list.to(device),text_list.to(device), offsets.to(device)#数据集加载器
dataloader = DataLoader(train_iter, batch_size=8, shuffle=False, collate_fn=collate_batch)
二、准备模型
2.1 定义模型
首先对文本进行嵌入,然后对句子嵌入之后的结果进行均值聚合
代码如下:
#2.1 准备模型
class TextClassificationModel(nn.Module):def __init__(self,vocab_size,embed_dim,num_calss):super(TextClassificationModel, self).__init__()self.embedding = nn.EmbeddingBag(vocab_size, embed_dim, sparse=False)self.fc = nn.Linear(embed_dim, num_calss)self.init_weights()def init_weights(self):initrange = 0.5self.embedding.weight.data.uniform_(-initrange, initrange)self.fc.weight.data.uniform_(-initrange, initrange)self.fc.bias.data.zero_()def forward(self, text, offsets):embedded = self.embedding(text, offsets)return self.fc(embedded)
self.embedding.weight.data.uniform_(-initrange, initrange)是在PyTorch框架下用于初始化神经网络的词嵌入层(embedding layer)权重的一种方法,这里使用了均匀分布的随机值来初始化权重,具体来说,其作用如下:
- self.embedding:这是神经网络的词嵌入层(embedding layer),其嵌入层的作用是将离散的单词表示(通常为整数索引)映射为固定大小的连续向量,这些向量捕捉了单词之间的语义关系,并作为网络的输入
- self.embedding.weight:这是词嵌入层的权重矩阵,它的形状为(vocab_size,embedding_dim),其中vocab_size是词汇表的大小,embedding_dim是嵌入向量的维度
- self.embedding.weight.data:这是权重矩阵的数据部分,可以直接操作其底层的张量
- .uniform_(-initrange, initrange):这是一个原地操作,用于将权重矩阵的值用一个均匀分布进行初始化,均匀分布的范围为[-initrange,initrange],其中initrange是一个正数
这种方式初始化词嵌入层的权重,可以使得模型在训练开始时具有一定的随机性,有助于避免梯度消失或梯度爆炸等问题,在训练过程中,这些权重将通过优化算法不断更新,以捕捉到更好的单词表示
2.2 定义示例
代码如下:
#2.2定义实例
num_class = len(set([label for (label,text) in train_iter]))
vocab_size = len(vocab)
em_size = 64
model = TextClassificationModel(vocab_size, em_size, num_class).to(device)epochs = 10
lr = 5
batch_szie =64critertion = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model.parameters(), lr=lr)
scheduler = torch.optim.lr_scheduler.StepLR(optimizer,1.0,gamma=0.1)
2.3 定义训练函数与评估函数
#2.3 定义训练函数与评估函数
def train(dataloader):model.train()total_acc, train_loss, total_count = 0,0,0log_interval = 500start_time = time.time()for idx, (label, text, offsets) in enumerate(dataloader):predicted_label = model(text, offsets)optimizer.zero_grad()loss = critertion(predicted_label, label)loss.backward()optimizer.step()#记录acc和losstotal_acc += (predicted_label.argmax(1) == label).sum().item()train_loss += loss.item()total_count += label.size(0)if idx % log_interval == 0 and idx>0:elapsed = time.time() - start_timeprint('| epoch{:1d} | {:4d}/{:4d} batches''train_acc {:4.3f} train_loss {:4.5f}'.format(epoch, idx, len(dataloader),total_acc/total_count, train_loss/total_count))total_acc, train_loss, total_count = 0, 0, 0start_time = time.time()def evaluate(dataloader):model.eval()total_acc, train_loss, total_count = 0, 0 ,0with torch.no_grad():for idx, (label, text, offsets) in enumerate(dataloader):predicted_label = model(text, offsets)loss = critertion(predicted_label, label)# 记录acc和losstotal_acc += (predicted_label.argmax(1) == label).sum().item()train_loss += loss.item()total_count += label.size(0)return total_acc/total_count, train_loss/total_count
三、训练模型
3.1 拆分数据集并运行模型
torchtext.data.functional.to_map_style_dataset函数的作用是将一个迭代式的数据集(Iterable-style dataset)转换为映射式的数据集(Map-style dataset)。这个转换使得我们可以通过索引更方便访问数据集中的元素
在PyTorch中,数据集可以分为两种类型:Iterable-style和Map-style,Iterable-style数据集实现了__iter__()方法,可以迭代访问数据集中的元素,但不支持通过索引访问,而Map-style数据集实现了__getitem__()和__len__()方法,可以直接通过索引访问特定元素,并能获取数据集的大小、
TorchText是Pytorch的一个扩展库,专注于处理文本数据,torchtext.data.functional中的to_map_style_dataset函数可以帮助我们将一个Iterable-style数据集转换为一个易于操作的Map-style数据集,这样就可以通过索引直接访问数据集中的特定样本,从而简化了训练、验证和测试过程中的数据处理。
代码如下:
#3.1 拆分数据集并运行模型
from torch.utils.data.dataset import random_split
from torchtext.data.functional import to_map_style_datasettotal_accu = Nonetrain_iter, test_iter = AG_NEWS()
train_dataset = to_map_style_dataset(train_iter)
test_dataset = to_map_style_dataset(test_iter)
num_train = int(len(train_dataset) * 0.95)
split_train_, split_valid_ = random_split(train_dataset, [num_train, len(train_dataset)-num_train])train_dataloader = DataLoader(split_train_, batch_size=batch_szie, shuffle=True, collate_fn=collate_batch)
vaild_dataloader = DataLoader(split_valid_, batch_size=batch_szie, shuffle=True, collate_fn=collate_batch)
test_dataloader = DataLoader(test_dataset, batch_size=batch_szie, shuffle=True, collate_fn=collate_batch)for epoch in range(1, epochs+1):epoch_start_time = time.time()train(train_dataloader)val_acc, val_loss = evaluate(vaild_dataloader)if total_accu is not None and total_accu > val_acc:scheduler.step()else:total_accu = val_accprint('-' * 69)print('| epoch{:1d} | time: {:4.2f}s |''vaild_acc {:4.3f} vaild_loss {:4.3f}'.format(epoch,time.time()-epoch_start_time,val_acc, val_loss))print('-' * 69)
输出结果:
| epoch1 | 500/1782 batchestrain_acc 0.714 train_loss 0.01141
| epoch1 | 1000/1782 batchestrain_acc 0.864 train_loss 0.00623
| epoch1 | 1500/1782 batchestrain_acc 0.879 train_loss 0.00551
---------------------------------------------------------------------
| epoch1 | time: 7.21s |vaild_acc 0.810 vaild_loss 0.008
---------------------------------------------------------------------
| epoch2 | 500/1782 batchestrain_acc 0.905 train_loss 0.00445
| epoch2 | 1000/1782 batchestrain_acc 0.905 train_loss 0.00440
| epoch2 | 1500/1782 batchestrain_acc 0.906 train_loss 0.00442
---------------------------------------------------------------------
| epoch2 | time: 5.68s |vaild_acc 0.910 vaild_loss 0.004
---------------------------------------------------------------------
| epoch3 | 500/1782 batchestrain_acc 0.915 train_loss 0.00389
| epoch3 | 1000/1782 batchestrain_acc 0.918 train_loss 0.00381
| epoch3 | 1500/1782 batchestrain_acc 0.918 train_loss 0.00377
---------------------------------------------------------------------
| epoch3 | time: 6.04s |vaild_acc 0.910 vaild_loss 0.004
---------------------------------------------------------------------
| epoch4 | 500/1782 batchestrain_acc 0.929 train_loss 0.00331
| epoch4 | 1000/1782 batchestrain_acc 0.921 train_loss 0.00357
| epoch4 | 1500/1782 batchestrain_acc 0.926 train_loss 0.00341
---------------------------------------------------------------------
| epoch4 | time: 6.54s |vaild_acc 0.890 vaild_loss 0.005
---------------------------------------------------------------------
| epoch5 | 500/1782 batchestrain_acc 0.941 train_loss 0.00280
| epoch5 | 1000/1782 batchestrain_acc 0.945 train_loss 0.00266
| epoch5 | 1500/1782 batchestrain_acc 0.944 train_loss 0.00265
---------------------------------------------------------------------
| epoch5 | time: 6.76s |vaild_acc 0.917 vaild_loss 0.004
---------------------------------------------------------------------
| epoch6 | 500/1782 batchestrain_acc 0.948 train_loss 0.00255
| epoch6 | 1000/1782 batchestrain_acc 0.946 train_loss 0.00265
| epoch6 | 1500/1782 batchestrain_acc 0.946 train_loss 0.00260
---------------------------------------------------------------------
| epoch6 | time: 6.80s |vaild_acc 0.920 vaild_loss 0.004
---------------------------------------------------------------------
| epoch7 | 500/1782 batchestrain_acc 0.948 train_loss 0.00254
| epoch7 | 1000/1782 batchestrain_acc 0.945 train_loss 0.00266
| epoch7 | 1500/1782 batchestrain_acc 0.949 train_loss 0.00248
---------------------------------------------------------------------
| epoch7 | time: 6.52s |vaild_acc 0.915 vaild_loss 0.004
---------------------------------------------------------------------
| epoch8 | 500/1782 batchestrain_acc 0.949 train_loss 0.00246
| epoch8 | 1000/1782 batchestrain_acc 0.949 train_loss 0.00246
| epoch8 | 1500/1782 batchestrain_acc 0.949 train_loss 0.00252
---------------------------------------------------------------------
| epoch8 | time: 6.75s |vaild_acc 0.919 vaild_loss 0.004
---------------------------------------------------------------------
| epoch9 | 500/1782 batchestrain_acc 0.948 train_loss 0.00251
| epoch9 | 1000/1782 batchestrain_acc 0.949 train_loss 0.00247
| epoch9 | 1500/1782 batchestrain_acc 0.950 train_loss 0.00245
---------------------------------------------------------------------
| epoch9 | time: 6.87s |vaild_acc 0.919 vaild_loss 0.004
---------------------------------------------------------------------
| epoch10 | 500/1782 batchestrain_acc 0.951 train_loss 0.00244
| epoch10 | 1000/1782 batchestrain_acc 0.947 train_loss 0.00255
| epoch10 | 1500/1782 batchestrain_acc 0.949 train_loss 0.00244
---------------------------------------------------------------------
| epoch10 | time: 6.64s |vaild_acc 0.919 vaild_loss 0.004
---------------------------------------------------------------------
3.2 使用测试数据集评估模型
代码如下:
print('Checking the results of test dataset.')
test_acc, test_loss = evaluate(test_dataloader)
print('test accuracy {:8.3f}'.format(test_acc))
输出结果:
总结
了解文本分类的基本流程、学习常用数据清洗方法、学习如何使用jieba实现英文分词、学习如何构建文本向量
相关文章:

第20周:Pytorch文本分类入门
目录 前言 一、前期准备 1.1 环境安装导入包 1.2 加载数据 1.3 构建词典 1.4 生成数据批次和迭代器 二、准备模型 2.1 定义模型 2.2 定义示例 2.3 定义训练函数与评估函数 三、训练模型 3.1 拆分数据集并运行模型 3.2 使用测试数据集评估模型 总结 前言 …...

记一次 SpringBoot2.x 配置 Fastjson请求报 internal server 500
1.遇到的问题 报错springboot从2.1.16升级到2.5.15,之后就报500内部错误,后面调用都是正常的,就考虑转换有错。 接口返回错误: 2.解决办法 因为我用了fastjson,需要转换下,目前可能理解就是springboot-we…...
OSPF笔记
OSPF:开放式最短路径优先协议 使用范围:IGP 协议算法特点:链路状态型路由协议,SPF算法 协议是否传递网络掩码:传递网络掩码 协议封装:基于ip协议封装,协议号为89 一,ospf特点 1…...
IOC容器初始化流程
IOC容器初始化流程 一、概要1.准备上下文prepareRefresh()2. 获取beanFactory:obtainFreshBeanFactory()3. 准备beanFactory:prepareBeanFactory(beanFactory)4. 后置处理:postProcessBeanFactory()5. 调用bean工厂后置处理器:invokeBeanFactoryPostProcessors()6. 注册bea…...

第二季度云计算市场份额榜单:微软下滑,谷歌上升,AWS仍保持领先
2024 年第二季度,随着企业云支出达到 790 亿美元的新高,三大云计算巨头微软、谷歌云和 AWS的全球云市场份额发生了变化。 根据新的市场数据,以下是 2024 年第二季度全球云市场份额结果和六大世界领先者,其中包括 AWS、阿里巴巴、…...
三点确定圆心算法推导
已知a,b,c三点求过这三点的圆心坐标 a ( x 1 , y 1 ) a(x_1, y_1) a(x1,y1) 、 b ( x 2 , y 2 ) b(x_2, y_2) b(x2,y2) 、 c ( x 3 , y 3 ) c(x_3, y_3) c(x3,y3) 确认三点是否共线 叉积计算方式 v → ( X 1 , Y 1 ) u → ( X 2 , Y 2 ) X 1 Y 2 − X 2 Y 1 \…...

神经网络 (NN) TensorFlow Playground在线应用程序
神经网络 (NN) 历史上最重要的发现之一是神经网络 (NN) 的强大功能。 在神经网络中,称为神经元的许多数据层被添加在一起或相互堆叠以计算新的数据级别。 常用的简称: DNN 深度神经网络CNN 卷积神经网络RNN 循环神经网络 神经元 科学家一致认为&am…...
腾讯课堂 离线m3u8.sqlite转成视频
为了广大腾讯课堂用户对于购买的课程不能正常离线播放,构成知识付费损失,故出此文档。 重点:完全免费!!!完全免费!!!完全免费!!! 怎么…...
Linux多路转接
文章目录 IO模型多路转接select 和 pollepoll IO模型 在还在学习语言的阶段,C里使用cin,或者是C使用scanf的时候,总是要等着我们输入数据才执行,这种IO是阻塞IO。下面是比较正式的说法。 阻塞IO: 在内核将数据准备好之前…...

IDEA导入Maven项目的流程配置以常见问题解决
1. 前言 本文主要围绕着在IDEA中导入新Maven项目后的配置及常见问题解决来展开说说。相关的部分软件如下: IntelliJ IDEA 2021.1JDK 1.8Window 2. 导入Maven项目及配置 2.1 导入Maven项目 下面介绍了直接打开本地项目和导入git上的项目两种导入Maven方式。 1…...

【数据分析---- Pandas进阶指南:核心计算方法、缺失值处理及数据类型管理】
前言: 💞💞大家好,我是书生♡,本阶段和大家一起分享和探索数据分析,本篇文章主要讲述了:Pandas进阶指南:核心计算方法、缺失值处理及数据类型管理等等。欢迎大家一起探索讨论&#x…...

2024世界机器人大会将于8月21日至25日在京举行
2024年的世界机器人大会预定于8月21日至25日,在北京经济技术开发区的北人亦创国际会展中心隆重举办。 本届大会以“共育新质生产力 共享智能新未来”为核心主题,将汇聚来自全球超过300位的机器人行业专家、国际组织代表、杰出科学家以及企业家࿰…...

【Linux】lvm被删除或者lvm丢失了怎么办
模拟案例 接下来模拟lvm误删除如何恢复的案例: 模拟删除: 查看vg名: vgdisplayvgcfgrestore --list uniontechos #查看之前的操作 例如我删除的,现场没有删除就用最近的操作文件: 还原: vgcfgrestore…...

疫情防控管理系统
摘 要 由于当前疫情防控形势复杂,为做好学校疫情防控管理措施,根据上级防疫部门要求,为了学生的生命安全,要求学校加强疫情防控的管理。为了迎合时代需求,优化管理效率,各种各样的管理系统应运而生&#x…...

永久删除的Android 文件去哪了?在Android上恢复误删除的消息和照片方法?
丢失重要消息和照片可能是一种令人沮丧的经历,尤其是在您没有备份的情况下。但别担心,在本教程中,我们将指导您完成在Android设备上恢复已删除消息和照片的步骤。无论您是不小心删除了它们还是由于软件问题而消失了,这些步骤都可以…...

宠物服务小程序多生态转化
宠物服务如美容造型、医疗、看护寄养等有着不少需求,尤其是年轻人从宠物生活到饮食起居等面面俱到,往往不惜金钱给到较好的环境,如定时除虫、优质食物、玩具、检查身体、服饰; 近些年宠物服务店新开数量也较多,同行竞…...
今天细说一下工业制造行业MES系统
文章目录 前言什么是MES? 前言 最近几个月在做制造行业的MES系统开发,这类面向制造业的系统是今年做的第三个系统了,也算是了解较深的了,和一个之前转行做这一块的朋友聊了聊,他们集团要扩大规模,准备招ME…...
C++ 知识点(长期更新)
C++ 知识点 C/C++1. `cin`, `cin.get()`, `getchar()`, `getline()`, 和 `cin.getline()`的区别。2. 有关 cin >>3. 定义和声明的区别4. `union`、`struct`和`class`的区别5. 深拷贝 vs 浅拷贝6. new 和 malloc 的区别7. 被free回收的内存是立即返还给操作系统吗?为什么…...
Spring AI + 通义千问 入门学习
Spring AI 通义千问 入门学习 文章目录 Spring AI 通义千问 入门学习一,开发环境配置二,项目搭建2.1 pom文件2.2 配置文件 三,AI使用3.1 对话问答3.1.1 普通方式3.1.2 流方式 3.2 文字生成图片 最近AI很火,而Spring也出了Spring…...

38.【C语言】指针(重难点)(C)
目录: 8.const 修饰指针 *修饰普通变量 *修饰指针变量 9.指针运算 *指针或-整数 *指针-指针 *指针关系运算 往期推荐 承接上篇37.【C语言】指针(重难点)(B) 8.const 修饰指针 const 全称 constant adj.不变的 *修饰普通变量 #…...

龙虎榜——20250610
上证指数放量收阴线,个股多数下跌,盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型,指数短线有调整的需求,大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的:御银股份、雄帝科技 驱动…...
Linux链表操作全解析
Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表?1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...

docker详细操作--未完待续
docker介绍 docker官网: Docker:加速容器应用程序开发 harbor官网:Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台,用于将应用程序及其依赖项(如库、运行时环…...
反向工程与模型迁移:打造未来商品详情API的可持续创新体系
在电商行业蓬勃发展的当下,商品详情API作为连接电商平台与开发者、商家及用户的关键纽带,其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息(如名称、价格、库存等)的获取与展示,已难以满足市场对个性化、智能…...

Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)
目录 1.TCP的连接管理机制(1)三次握手①握手过程②对握手过程的理解 (2)四次挥手(3)握手和挥手的触发(4)状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...
postgresql|数据库|只读用户的创建和删除(备忘)
CREATE USER read_only WITH PASSWORD 密码 -- 连接到xxx数据库 \c xxx -- 授予对xxx数据库的只读权限 GRANT CONNECT ON DATABASE xxx TO read_only; GRANT USAGE ON SCHEMA public TO read_only; GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only; GRANT EXECUTE O…...
OkHttp 中实现断点续传 demo
在 OkHttp 中实现断点续传主要通过以下步骤完成,核心是利用 HTTP 协议的 Range 请求头指定下载范围: 实现原理 Range 请求头:向服务器请求文件的特定字节范围(如 Range: bytes1024-) 本地文件记录:保存已…...
Python爬虫(二):爬虫完整流程
爬虫完整流程详解(7大核心步骤实战技巧) 一、爬虫完整工作流程 以下是爬虫开发的完整流程,我将结合具体技术点和实战经验展开说明: 1. 目标分析与前期准备 网站技术分析: 使用浏览器开发者工具(F12&…...

什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...

HarmonyOS运动开发:如何用mpchart绘制运动配速图表
##鸿蒙核心技术##运动开发##Sensor Service Kit(传感器服务)# 前言 在运动类应用中,运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据,如配速、距离、卡路里消耗等,用户可以更清晰…...