PyTorch翻译官网教程-LANGUAGE MODELING WITH NN.TRANSFORMER AND TORCHTEXT

官网链接

Language Modeling with nn.Transformer and torchtext — PyTorch Tutorials 2.0.1+cu117 documentation

使用 NN.TRANSFORMER 和 TORCHTEXT进行语言建模

这是一个关于训练模型使用nn.Transformer来预测序列中的下一个单词的教程。

PyTorch 1.2版本包含了一个基于论文Attention is All You Need的标准transformer模块。与循环神经网络(RNNs)相比,transformer模型已被证明在许多序列对序列任务中具有更高的质量,同时具有更高的并发性。

nn.Transformer 模块完全依赖于注意力机制(作为nn.MultiheadAttention实现)来绘制输入和输出之间的全局依赖关系。nn.Transformer 模块是高度模块化的,这样一个单一的组件(例如,nn.TransformerEncoder)可以很容易地使用/组合。

定义模型

在本教程中,我们在语言建模任务上训练一个nn.TransformerEncoder模型。请注意,本教程不包括nn.TransformerDecoder的训练,如上图右半部分所示。语言建模任务是为给定单词(或单词序列)跟随单词序列的可能性分配一个概率。首先将一系列标记传递给源文本嵌入层,然后是一个位置编码器来解释单词的顺序(请参阅下一段了解更多细节)。nn.TransformerEncoder 由nn.TransformerEncoderLayer的多个层组成。除了输入序列外,还需要一个方形注意掩码,因为在nn.TransformerDecoder中的自注意层只允许参与序列中较早的位置。对于语言建模任务,应掩盖未来位置上的任何标记。为了生成输出词的概率分布,nn.TransformerEncoder 模型的输出通过一个线性层来输出非规范化的对数。这里没有应用log-softmax函数,因为稍后会使用CrossEntropyLoss,它要求输入是非标准化的对数。

import math
import os
from tempfile import TemporaryDirectory
from typing import Tupleimport torch
from torch import nn, Tensor
from torch.nn import TransformerEncoder, TransformerEncoderLayer
from torch.utils.data import datasetclass TransformerModel(nn.Module):def __init__(self, ntoken: int, d_model: int, nhead: int, d_hid: int,nlayers: int, dropout: float = 0.5):super().__init__()self.model_type = 'Transformer'self.pos_encoder = PositionalEncoding(d_model, dropout)encoder_layers = TransformerEncoderLayer(d_model, nhead, d_hid, dropout)self.transformer_encoder = TransformerEncoder(encoder_layers, nlayers)self.embedding = nn.Embedding(ntoken, d_model)self.d_model = d_modelself.linear = nn.Linear(d_model, ntoken)self.init_weights()def init_weights(self) -> None:initrange = 0.1self.embedding.weight.data.uniform_(-initrange, initrange)self.linear.bias.data.zero_()self.linear.weight.data.uniform_(-initrange, initrange)def forward(self, src: Tensor, src_mask: Tensor = None) -> Tensor:"""Arguments:src: Tensor, shape ``[seq_len, batch_size]``src_mask: Tensor, shape ``[seq_len, seq_len]``Returns:output Tensor of shape ``[seq_len, batch_size, ntoken]``"""src = self.embedding(src) * math.sqrt(self.d_model)src = self.pos_encoder(src)output = self.transformer_encoder(src, src_mask)output = self.linear(output)return output

PositionalEncoding模块注入一些关于序列中记号的相对或绝对位置的信息。位置编码器与文本嵌入层具有相同的维数,因此两者可以相加。这里,我们使用不同频率的正弦和余弦函数。

class PositionalEncoding(nn.Module):def __init__(self, d_model: int, dropout: float = 0.1, max_len: int = 5000):super().__init__()self.dropout = nn.Dropout(p=dropout)position = torch.arange(max_len).unsqueeze(1)div_term = torch.exp(torch.arange(0, d_model, 2) * (-math.log(10000.0) / d_model))pe = torch.zeros(max_len, 1, d_model)pe[:, 0, 0::2] = torch.sin(position * div_term)pe[:, 0, 1::2] = torch.cos(position * div_term)self.register_buffer('pe', pe)def forward(self, x: Tensor) -> Tensor:"""Arguments:x: Tensor, shape ``[seq_len, batch_size, embedding_dim]``"""x = x + self.pe[:x.size(0)]return self.dropout(x)

加载和批处理数据

本教程使用torchtext生成Wikitext-2数据集。要访问torchtext数据集,请按照GitHub - pytorch/data: A PyTorch repo for data loading and utilities to be shared by the PyTorch domain libraries. 的说明安装torchdata.

%%bash
pip install portalocker
pip install torchdata

词汇对象是基于训练数据集构建的,用于将令牌数值化为张量。Wikitext-2将稀疏令牌表示为unk。给定顺序数据的一维向量,batchify() 方法将数据排列到batch_size列中。如果数据没有均匀地分成batch_size列,那么数据将被裁剪。例如,以字母表为数据(总长度为26),batch_size=4,我们将字母表分成长度为6的序列,得到4个这样的序列。

批处理支持更多的并行处理。然而,批处理意味着模型独立处理每一列。在上面的例子中,G和F的依赖关系是无法学习的。

from torchtext.datasets import WikiText2
from torchtext.data.utils import get_tokenizer
from torchtext.vocab import build_vocab_from_iteratortrain_iter = WikiText2(split='train')
tokenizer = get_tokenizer('basic_english')
vocab = build_vocab_from_iterator(map(tokenizer, train_iter), specials=['<unk>'])
vocab.set_default_index(vocab['<unk>'])def data_process(raw_text_iter: dataset.IterableDataset) -> Tensor:"""Converts raw text into a flat Tensor."""data = [torch.tensor(vocab(tokenizer(item)), dtype=torch.long) for item in raw_text_iter]return torch.cat(tuple(filter(lambda t: t.numel() > 0, data)))# ``train_iter`` was "consumed" by the process of building the vocab,
# so we have to create it again
train_iter, val_iter, test_iter = WikiText2()
train_data = data_process(train_iter)
val_data = data_process(val_iter)
test_data = data_process(test_iter)device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')def batchify(data: Tensor, bsz: int) -> Tensor:"""Divides the data into ``bsz`` separate sequences, removing extra elementsthat wouldn't cleanly fit.Arguments:data: Tensor, shape ``[N]``bsz: int, batch sizeReturns:Tensor of shape ``[N // bsz, bsz]``"""seq_len = data.size(0) // bszdata = data[:seq_len * bsz]data = data.view(bsz, seq_len).t().contiguous()return data.to(device)batch_size = 20
eval_batch_size = 10
train_data = batchify(train_data, batch_size)  # shape ``[seq_len, batch_size]``
val_data = batchify(val_data, eval_batch_size)
test_data = batchify(test_data, eval_batch_size)

函数生成输入和目标序列

get_batch() transformer模型生成一对输入-目标序列。它将源数据细分为长度为bptt的块。对于语言建模任务,模型需要以下单词作为目标。例如,如果bptt值为2,那么当i = 0时,我们将得到以下两个变量:

应该注意的是,数据块的维度是0,与Transformer模型中的S维度一致。批次维度N 的维度是1.

bptt = 35
def get_batch(source: Tensor, i: int) -> Tuple[Tensor, Tensor]:"""Args:source: Tensor, shape ``[full_seq_len, batch_size]``i: intReturns:tuple (data, target), where data has shape ``[seq_len, batch_size]`` andtarget has shape ``[seq_len * batch_size]``"""seq_len = min(bptt, len(source) - 1 - i)data = source[i:i+seq_len]target = source[i+1:i+1+seq_len].reshape(-1)return data, target

初始化实例

模型超参数定义如下。词汇表大小等于词汇表对象的长度。

ntokens = len(vocab)  # size of vocabulary
emsize = 200  # embedding dimension
d_hid = 200  # dimension of the feedforward network model in ``nn.TransformerEncoder``
nlayers = 2  # number of ``nn.TransformerEncoderLayer`` in ``nn.TransformerEncoder``
nhead = 2  # number of heads in ``nn.MultiheadAttention``
dropout = 0.2  # dropout probability
model = TransformerModel(ntokens, emsize, nhead, d_hid, nlayers, dropout).to(device)

运行模型

我们将CrossEntropyLoss与 SGD (随机梯度下降)优化器一起使用。学习率最初设置为5.0,并遵循StepLR 计划。在训练期间,我们使用nn.utils.clip_grad_norm_ 防止梯度爆炸。

import timecriterion = nn.CrossEntropyLoss()
lr = 5.0  # learning rate
optimizer = torch.optim.SGD(model.parameters(), lr=lr)
scheduler = torch.optim.lr_scheduler.StepLR(optimizer, 1.0, gamma=0.95)def train(model: nn.Module) -> None:model.train()  # turn on train modetotal_loss = 0.log_interval = 200start_time = time.time()num_batches = len(train_data) // bpttfor batch, i in enumerate(range(0, train_data.size(0) - 1, bptt)):data, targets = get_batch(train_data, i)output = model(data)output_flat = output.view(-1, ntokens)loss = criterion(output_flat, targets)optimizer.zero_grad()loss.backward()torch.nn.utils.clip_grad_norm_(model.parameters(), 0.5)optimizer.step()total_loss += loss.item()if batch % log_interval == 0 and batch > 0:lr = scheduler.get_last_lr()[0]ms_per_batch = (time.time() - start_time) * 1000 / log_intervalcur_loss = total_loss / log_intervalppl = math.exp(cur_loss)print(f'| epoch {epoch:3d} | {batch:5d}/{num_batches:5d} batches | 'f'lr {lr:02.2f} | ms/batch {ms_per_batch:5.2f} | 'f'loss {cur_loss:5.2f} | ppl {ppl:8.2f}')total_loss = 0start_time = time.time()def evaluate(model: nn.Module, eval_data: Tensor) -> float:model.eval()  # turn on evaluation modetotal_loss = 0.with torch.no_grad():for i in range(0, eval_data.size(0) - 1, bptt):data, targets = get_batch(eval_data, i)seq_len = data.size(0)output = model(data)output_flat = output.view(-1, ntokens)total_loss += seq_len * criterion(output_flat, targets).item()return total_loss / (len(eval_data) - 1)

循环epochs,如果验证损失是目前为止我们看到的最好的,那么保存模型。在每个epoch之后调整学习速率。

best_val_loss = float('inf')
epochs = 3with TemporaryDirectory() as tempdir:best_model_params_path = os.path.join(tempdir, "best_model_params.pt")for epoch in range(1, epochs + 1):epoch_start_time = time.time()train(model)val_loss = evaluate(model, val_data)val_ppl = math.exp(val_loss)elapsed = time.time() - epoch_start_timeprint('-' * 89)print(f'| end of epoch {epoch:3d} | time: {elapsed:5.2f}s | 'f'valid loss {val_loss:5.2f} | valid ppl {val_ppl:8.2f}')print('-' * 89)if val_loss < best_val_loss:best_val_loss = val_losstorch.save(model.state_dict(), best_model_params_path)scheduler.step()model.load_state_dict(torch.load(best_model_params_path)) # load best model states

输出

| epoch   1 |   200/ 2928 batches | lr 5.00 | ms/batch 31.00 | loss  8.15 | ppl  3449.06
| epoch   1 |   400/ 2928 batches | lr 5.00 | ms/batch 28.73 | loss  6.25 | ppl   517.05
| epoch   1 |   600/ 2928 batches | lr 5.00 | ms/batch 28.56 | loss  5.61 | ppl   274.25
| epoch   1 |   800/ 2928 batches | lr 5.00 | ms/batch 28.42 | loss  5.31 | ppl   202.30
| epoch   1 |  1000/ 2928 batches | lr 5.00 | ms/batch 28.33 | loss  4.95 | ppl   140.81
| epoch   1 |  1200/ 2928 batches | lr 5.00 | ms/batch 28.28 | loss  4.55 | ppl    94.20
| epoch   1 |  1400/ 2928 batches | lr 5.00 | ms/batch 28.36 | loss  4.21 | ppl    67.25
| epoch   1 |  1600/ 2928 batches | lr 5.00 | ms/batch 28.45 | loss  3.99 | ppl    54.28
| epoch   1 |  1800/ 2928 batches | lr 5.00 | ms/batch 28.65 | loss  3.74 | ppl    41.89
| epoch   1 |  2000/ 2928 batches | lr 5.00 | ms/batch 28.56 | loss  3.66 | ppl    38.71
| epoch   1 |  2200/ 2928 batches | lr 5.00 | ms/batch 28.67 | loss  3.48 | ppl    32.44
| epoch   1 |  2400/ 2928 batches | lr 5.00 | ms/batch 28.74 | loss  3.49 | ppl    32.78
| epoch   1 |  2600/ 2928 batches | lr 5.00 | ms/batch 28.60 | loss  3.38 | ppl    29.50
| epoch   1 |  2800/ 2928 batches | lr 5.00 | ms/batch 28.46 | loss  3.29 | ppl    26.94
-----------------------------------------------------------------------------------------
| end of epoch   1 | time: 86.92s | valid loss  2.06 | valid ppl     7.88
-----------------------------------------------------------------------------------------
| epoch   2 |   200/ 2928 batches | lr 4.75 | ms/batch 28.88 | loss  3.10 | ppl    22.18
| epoch   2 |   400/ 2928 batches | lr 4.75 | ms/batch 28.50 | loss  3.02 | ppl    20.55
| epoch   2 |   600/ 2928 batches | lr 4.75 | ms/batch 28.65 | loss  2.86 | ppl    17.50
| epoch   2 |   800/ 2928 batches | lr 4.75 | ms/batch 28.68 | loss  2.85 | ppl    17.28
| epoch   2 |  1000/ 2928 batches | lr 4.75 | ms/batch 28.59 | loss  2.67 | ppl    14.43
| epoch   2 |  1200/ 2928 batches | lr 4.75 | ms/batch 28.55 | loss  2.68 | ppl    14.57
| epoch   2 |  1400/ 2928 batches | lr 4.75 | ms/batch 28.51 | loss  2.72 | ppl    15.13
| epoch   2 |  1600/ 2928 batches | lr 4.75 | ms/batch 28.44 | loss  2.69 | ppl    14.71
| epoch   2 |  1800/ 2928 batches | lr 4.75 | ms/batch 28.46 | loss  2.60 | ppl    13.51
| epoch   2 |  2000/ 2928 batches | lr 4.75 | ms/batch 28.51 | loss  2.61 | ppl    13.60
| epoch   2 |  2200/ 2928 batches | lr 4.75 | ms/batch 28.64 | loss  2.57 | ppl    13.04
| epoch   2 |  2400/ 2928 batches | lr 4.75 | ms/batch 28.67 | loss  2.57 | ppl    13.08
| epoch   2 |  2600/ 2928 batches | lr 4.75 | ms/batch 28.56 | loss  2.57 | ppl    13.05
| epoch   2 |  2800/ 2928 batches | lr 4.75 | ms/batch 28.61 | loss  2.55 | ppl    12.81
-----------------------------------------------------------------------------------------
| end of epoch   2 | time: 86.63s | valid loss  1.83 | valid ppl     6.24
-----------------------------------------------------------------------------------------
| epoch   3 |   200/ 2928 batches | lr 4.51 | ms/batch 28.71 | loss  2.43 | ppl    11.35
| epoch   3 |   400/ 2928 batches | lr 4.51 | ms/batch 28.82 | loss  2.37 | ppl    10.65
| epoch   3 |   600/ 2928 batches | lr 4.51 | ms/batch 28.67 | loss  2.27 | ppl     9.64
| epoch   3 |   800/ 2928 batches | lr 4.51 | ms/batch 28.74 | loss  2.29 | ppl     9.83
| epoch   3 |  1000/ 2928 batches | lr 4.51 | ms/batch 28.55 | loss  2.22 | ppl     9.22
| epoch   3 |  1200/ 2928 batches | lr 4.51 | ms/batch 28.73 | loss  2.25 | ppl     9.48
| epoch   3 |  1400/ 2928 batches | lr 4.51 | ms/batch 28.57 | loss  2.29 | ppl     9.89
| epoch   3 |  1600/ 2928 batches | lr 4.51 | ms/batch 28.73 | loss  2.36 | ppl    10.62
| epoch   3 |  1800/ 2928 batches | lr 4.51 | ms/batch 28.52 | loss  2.20 | ppl     9.07
| epoch   3 |  2000/ 2928 batches | lr 4.51 | ms/batch 28.61 | loss  2.26 | ppl     9.57
| epoch   3 |  2200/ 2928 batches | lr 4.51 | ms/batch 28.53 | loss  2.20 | ppl     9.03
| epoch   3 |  2400/ 2928 batches | lr 4.51 | ms/batch 28.45 | loss  2.23 | ppl     9.26
| epoch   3 |  2600/ 2928 batches | lr 4.51 | ms/batch 28.56 | loss  2.21 | ppl     9.13
| epoch   3 |  2800/ 2928 batches | lr 4.51 | ms/batch 28.54 | loss  2.31 | ppl    10.03
-----------------------------------------------------------------------------------------
| end of epoch   3 | time: 86.63s | valid loss  1.28 | valid ppl     3.60
-----------------------------------------------------------------------------------------

在测试数据集上评估最佳模型

test_loss = evaluate(model, test_data)
test_ppl = math.exp(test_loss)
print('=' * 89)
print(f'| End of training | test loss {test_loss:5.2f} | 'f'test ppl {test_ppl:8.2f}')
print('=' * 89)

输出

=========================================================================================
| End of training | test loss  1.26 | test ppl     3.54
=========================================================================================

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

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

相关文章

Shell编程——弱数据类型的脚本语言快速入门指南

目录 Linux Shell 数据类型 变量类型 运算符 算术运算符 赋值运算符 拼接运算符 比较运算符 关系运算符 控制结构 顺序结构 条件分支结构 if 条件语句 case 分支语句 循环结构 for 循环 while 循环 until 循环 break 语句 continue语句 函数 函数定义 …

Stable Diffusion Webui源码剖析

1、关键python依赖 &#xff08;1&#xff09;xformers&#xff1a;优化加速方案。它可以对模型进行适当的优化来加速图片生成并降低显存占用。缺点是输出图像不稳定&#xff0c;有可能比不开Xformers略差。 &#xff08;2&#xff09;GFPGAN&#xff1a;它是腾讯开源的人脸修…

大数据扫盲(1): 数据仓库与ETL的关系及ETL工具推荐

在数字化时代&#xff0c;数据成为了企业决策的关键支持。然而&#xff0c;随着数据不断增长&#xff0c;有效地管理和利用这些数据变得至关重要。数据仓库和ETL工具作为数据管理和分析的核心&#xff0c;将帮助企业从庞杂的数据中提取有价值信息。 一、ETL是什么&#xff1f; …

【不限于联想Y9000P电脑关盖再打开时黑屏的解决办法】

不限于联想Y9000P电脑关盖再打开时黑屏的解决办法 问题的前言问题的出现问题拟解决 问题的前言 事情发生在昨天&#xff0c;更新了Win11系统后&#xff1a; 最惹人注目的三处地方就是&#xff1a; 1.可以查看时间的秒数了&#xff1b; 2.右键展示的内容变窄了&#xff1b; 3.按…

Pycharm 双击启动失败?

事故 双击 Pycharm 后&#xff0c;出现加载工程&#xff0c;我不想加载这个工程&#xff0c;就点击了弹出的 cancle 取消按钮。然后再到桌面双击 Pycharm 却发现无法启动了。哪怕以管理员权限运行也没用&#xff0c;就是不出界面。 原因未知 CtrlshiftESC 打开后台&#xff…

【腾讯云 Cloud Studio 实战训练营】Hexo 框架 Butterfly 主题搭建个人博客

什么是Cloud Studio Cloud Studio 是基于浏览器的集成式开发环境&#xff08;IDE&#xff09;&#xff0c;为开发者提供了一个永不间断的云端工作站。用户在使用 Cloud Studio 时无需安装&#xff0c;随时随地打开浏览器就能在线编程。 ​ Hexo 博客成品展示 本人博客如下&…

【Spring】-Spring项目的创建

作者&#xff1a;学Java的冬瓜 博客主页&#xff1a;☀冬瓜的主页&#x1f319; 专栏&#xff1a;【Framework】 主要内容&#xff1a;创建spring项目的步骤&#xff1a;先创建一个maven项目&#xff0c;再在pom.xml中添加spring框架支持&#xff0c;最后写一个启动类。 文章目…

Field injection is not recommended

文章目录 1. 引言2. 不推荐使用Autowired的原因3. Spring提供了三种主要的依赖注入方式3.1. 构造函数注入&#xff08;Constructor Injection&#xff09;3.2. Setter方法注入&#xff08;Setter Injection&#xff09;3.3. 字段注入&#xff08;Field Injection&#xff09; 4…

计算机视觉五大核心研究任务全解:分类识别、检测分割、人体分析、三维视觉、视频分析

目录 一、引言1.1 计算机视觉的定义1.1.1 核心技术1.1.2 应用场景 1.2 历史背景及发展1.2.1 1960s-1980s: 初期阶段1.2.2 1990s-2000s: 机器学习时代1.2.3 2010s-现在: 深度学习的革命 1.3 应用领域概览1.3.1 工业自动化1.3.2 医疗图像分析1.3.3 自动驾驶1.3.4 虚拟现实与增强现…

山东布谷科技直播软件开发WebRTC技术:建立实时通信优质平台

在数字化的时代&#xff0c;实时通信成为了人们远程交流的主要方式&#xff0c;目前市场上也出现了很多带有实时通信交流的软件&#xff0c;实时通信符合人们现在的需求&#xff0c;所以在直播软件开发过程中&#xff0c;开发者也运用了实时通信技术为直播软件加入了实时通信的…

【计算机视觉|生成对抗】生成对抗网络(GAN)

本系列博文为深度学习/计算机视觉论文笔记&#xff0c;转载请注明出处 标题&#xff1a;Generative Adversarial Nets 链接&#xff1a;Generative Adversarial Nets (nips.cc) 摘要 我们提出了一个通过**对抗&#xff08;adversarial&#xff09;**过程估计生成模型的新框架…

2.阿里云对象存储OSS

1.对象存储概述 文件上传&#xff0c;是指将本地图片、视频、音频等文件上传到服务器上&#xff0c;可以供其他用户浏览或下载的过程。文件上传在项目中应用非常广泛&#xff0c;我们经常发抖音、发朋友圈都用到了文件上传功能。 实现文件上传服务&#xff0c;需要有存储的支持…

【概念理解】STM32中的sprintf()函数

sprintf()函数 这个函数在 stdio.h中&#xff1b;可以将格式化的数据写入到一个字符串缓冲区中。 int sprintf(char *str, const char *format, ...);str&#xff1a;指向字符数组的指针&#xff0c;即用于存储格式化后字符串的缓冲区。format&#xff1a;格式化字符串&#…

(十六)大数据实战——安装使用mysql版的hive服务

前言 hive默认使用的是内嵌据库derby&#xff0c;Derby 是一个嵌入式数据库&#xff0c;可以轻松地以库的形式集成到应用程序中。它不需要独立的服务器进程&#xff0c;所有的数据存储在应用程序所在的文件系统中。为了支持hive服务更方便的使用&#xff0c;我们使用mysql数据…

【实战】十一、看板页面及任务组页面开发(一) —— React17+React Hook+TS4 最佳实践,仿 Jira 企业级项目(二十三)

文章目录 一、项目起航&#xff1a;项目初始化与配置二、React 与 Hook 应用&#xff1a;实现项目列表三、TS 应用&#xff1a;JS神助攻 - 强类型四、JWT、用户认证与异步请求五、CSS 其实很简单 - 用 CSS-in-JS 添加样式六、用户体验优化 - 加载中和错误状态处理七、Hook&…

c语言每日一练(8)

前言&#xff1a;每日一练系列&#xff0c;每一期都包含5道选择题&#xff0c;2道编程题&#xff0c;博主会尽可能详细地进行讲解&#xff0c;令初学者也能听的清晰。每日一练系列会持续更新&#xff0c;暑假时三天之内必有一更&#xff0c;到了开学之后&#xff0c;将看学业情…

【javaweb】学习日记Day1 - HTML CSS入门

目录 一、图片标签 ① 绝对路径 1.绝对磁盘路径 2.绝对网络路径 ② 相对路径 &#xff08;推荐&#xff09; 二、标题标签 三、水平线标签 四、标题样式 1、CSS引入样式 ① 行内样式 ② 内嵌样式 ③ 外嵌样式 2、CSS选择器 ① 元素选择器 ② id选择器 ③…

Hadoop+Python+Django+Mysql热门旅游景点数据分析系统的设计与实现(包含设计报告)

系统阐述的是使用热门旅游景点数据分析系统的设计与实现&#xff0c;对于Python、B/S结构、MySql进行了较为深入的学习与应用。主要针对系统的设计&#xff0c;描述&#xff0c;实现和分析与测试方面来表明开发的过程。开发中使用了 django框架和MySql数据库技术搭建系统的整体…

Python批量给excel文件加密

有时候我们需要定期给公司外部发邮件&#xff0c;在自动化发邮件的时候需要对文件进行加密传输。本文和你一起来探索用python给单个文件和批量文件加密。    python自动化发邮件可参考【干货】用Python每天定时发送监控邮件。 文章目录 一、安装pypiwin32包二、定义给excel加…

【Docker】Docker使用之容器技术发展史

&#x1f3ac; 博客主页&#xff1a;博主链接 &#x1f3a5; 本文由 M malloc 原创&#xff0c;首发于 CSDN&#x1f649; &#x1f384; 学习专栏推荐&#xff1a;LeetCode刷题集 &#x1f3c5; 欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff0…