【PyTorch】动态调整学习率 torch.optim.lr_scheduler.StepLR 调度器

文章目录

  • 1. torch.optim.lr_scheduler.StepLR 官方文档详解
  • 2. 使用示例
    • 2.1 官方提供使用示例
    • 2.2 自己写代码测试方法
      • 2.2.1 get_last_lr() 方法
      • 2.2.2 state_dict() 方法
      • 2.2.3 load_state_dict() 保存和加载调度器
  • 3. 思考
    • 3.1 为什么需要state_dict()
    • 3.2 get_lr() 与 get_last_lr() 的输出不一致问题

在深度学习中,学习率调度器(Learning Rate Scheduler) 是用来动态调整学习率的工具。它的主要目的是在训练过程中自动调整学习率,以提高训练的效率和效果。之所以称其为“调度器”,是因为它控制着学习率的调整和更新,类似于调度一个过程或者任务,它按照某种策略和规则来“调度”学习率,本文将详细介绍pytorch中动态调整学习率方法之一 torch.optim.lr_scheduler.StepLR

官方文档链接:
https://pytorch.ac.cn/docs/stable/generated/torch.optim.lr_scheduler.StepLR.html#torch.optim.lr_scheduler.StepLR

1. torch.optim.lr_scheduler.StepLR 官方文档详解

官方文档定义:

class torch.optim.lr_scheduler.StepLR(optimizer, step_size, gamma=0.1, last_epoch=-1, verbose='deprecated')

每隔 step_size 个 epochs 将每个参数组的学习率衰减 gamma 倍。
请注意,这种衰减可能与来自此调度程序外部的学习率的其他更改同时发生。当 last_epoch=-1 时,将初始 lr 设置为 lr。

参数:

  • o p t i m i z e r optimizer optimizer (优化器) : 包装的优化器
  • s t e p _ s i z e ( i n t ) step\_size(int) step_size(int) : 学习率衰减周期
  • g a m m a ( f l o a t ) gamma (float) gamma(float) : 学习率衰减的乘法因子, 默认值:0.1
  • l a s t _ e p o c h ( i n t ) last\_epoch (int) last_epoch(int) : 最后一个 epoch 的索引, 默认值:-1 表示从头开始
  • v e r b o s e ( b o o l ∣ s t r ) verbose (bool | str) verbose(boolstr): 如果为 True,则为每次更新打印一条消息到标准输出, 默认值:False。

注意:

  • 自版本 2.2 起不推荐使用: v e r b o s e verbose verbose 已弃用。请使用 g e t _ l a s t _ l r ( ) get\_last\_lr() get_last_lr()访问学习率

其它:

  • g e t _ l a s t _ l r ( ) get\_last\_lr() get_last_lr() : 返回当前调度程序计算的最后一个学习率, 返回类型 L i s t [ f l o a t ] List[float] List[float]
  • g e t _ l r ( ) get\_lr() get_lr() : 计算每个组的学习率
  • l o a d _ s t a t e _ d i c t ( s t a t e _ d i c t ) load\_state\_dict(state\_dict) load_state_dict(state_dict) : 加载调度程序的状态,参数: s t a t e _ d i c t ( d i c t ) state\_dict (dict) state_dict(dict) 调度程序状态,应为 s t a t e _ d i c t ( ) state\_dict() state_dict() 调用返回的对象。
  • p r i n t _ l r ( i s _ v e r b o s e , g r o u p , l r , e p o c h = N o n e ) print\_lr(is\_verbose, group, lr, epoch=None) print_lr(is_verbose,group,lr,epoch=None) : 显示当前学习率。
  • s t a t e _ d i c t ( ) state\_dict() state_dict() : 将调度程序的状态作为 d i c t dict dict 返回,它包含 s e l f . _ _ d i c t _ _ self.\_\_dict\_\_ self.__dict__ 中每个变量的条目,这些变量不是优化器。
  • s t e p ( e p o c h = N o n e ) step(epoch=None) step(epoch=None) : 执行一步操作,即更新一次学习率

注意:

  • 自版本 2.4 起不推荐使用: p r i n t _ l r ( ) print\_lr() print_lr() 已弃用。请使用 g e t _ l a s t _ l r ( ) get\_last\_lr() get_last_lr() 访问学习率。

2. 使用示例

2.1 官方提供使用示例

  • 假设初始 l r = 0.05 lr = 0.05 lr=0.05 s t e p _ s i z e = 30 step\_size=30 step_size=30 g a m m a = 0.1 gamma=0.1 gamma=0.1,即每 30 个 epoch后,将学习率乘以 0.1
  • e p o c h < 30 epoch< 30 epoch<30 时, l r = 0.05 lr = 0.05 lr=0.05 ,即 l r = l r lr=lr lr=lr
  • 30 < = e p o c h < 60 30 <= epoch < 60 30<=epoch<60 l r = 0.005 lr = 0.005 lr=0.005,即 l r n e w = l r o l d ∗ g a m m a = 0.05 ∗ 0.1 = 0.005 lr_{new}=lr_{old}*gamma=0.05*0.1=0.005 lrnew=lroldgamma=0.050.1=0.005
  • 60 < = e p o c h < 90 60 <= epoch < 90 60<=epoch<90 l r = 0.0005 lr = 0.0005 lr=0.0005,即 l r n e w = l r o l d ∗ g a m m a = 0.005 ∗ 0.1 = 0.0005 lr_{new}=lr_{old}*gamma=0.005*0.1=0.0005 lrnew=lroldgamma=0.0050.1=0.0005
# Assuming optimizer uses lr = 0.05 for all groups
# lr = 0.05     if epoch < 30
# lr = 0.005    if 30 <= epoch < 60
# lr = 0.0005   if 60 <= epoch < 90
# ...
scheduler = StepLR(optimizer, step_size=30, gamma=0.1)
for epoch in range(100):train(...)validate(...)scheduler.step()

2.2 自己写代码测试方法

2.2.1 get_last_lr() 方法

  • 用于返回调度器计算的 最后一个学习率。这个学习率是在调度器(scheduler)调整之后的当前学习率
  • 如果优化器中有多个参数组, g e t _ l a s t _ l r ( ) get\_last\_lr() get_last_lr() 返回的是一个列表,每个元素对应一个参数组的学习率
  • 如果优化器中只有一个参数组, g e t _ l a s t _ l r ( ) get\_last\_lr() get_last_lr() 返回一个只有一个元素的列表
import torch
from torch import nn
from torch import optim
net = nn.Linear(3,4)
def train():optimizer = optim.Adam(net.parameters(), lr=0.1)scheduler = optim.lr_scheduler.StepLR(optimizer, step_size = 1, gamma=0.1)for epoch in range(0, 10):print(epoch, scheduler.get_last_lr())optimizer.step()scheduler.step()
if __name__ == "__main__":train()

代码输出:

0 [0.1]
1 [0.010000000000000002]
2 [0.0010000000000000002]
3 [0.00010000000000000003]
4 [1.0000000000000004e-05]
5 [1.0000000000000004e-06]
6 [1.0000000000000005e-07]
7 [1.0000000000000005e-08]
8 [1.0000000000000005e-09]
9 [1.0000000000000006e-10]

2.2.2 state_dict() 方法

  • s t a t e _ d i c t ( ) state\_dict() state_dict() 是一个非常重要的函数,它能够返回一个包含模型或优化器状态的字典(dict)。对于学习率调度器来说, s t a t e _ d i c t ( ) state\_dict() state_dict() 返回调度器的状态,包括它的参数和变量,用于保存和恢复调度器的状态等

代码示例:

import torch
from torch import nn
from torch import optimnet = nn.Linear(3,4)def train():optimizer = optim.Adam(net.parameters(), lr=0.1)scheduler = optim.lr_scheduler.StepLR(optimizer, step_size = 1, gamma=0.1)for epoch in range(10):print(epoch, scheduler.state_dict())optimizer.step()scheduler.step()if __name__ == "__main__":train()

代码输出:

0 {'step_size': 1, 'gamma': 0.1, 'base_lrs': [0.1], 'last_epoch': 0, 'verbose': False, '_step_count': 1, '_get_lr_called_within_step': False, '_last_lr': [0.1]}
1 {'step_size': 1, 'gamma': 0.1, 'base_lrs': [0.1], 'last_epoch': 1, 'verbose': False, '_step_count': 2, '_get_lr_called_within_step': False, '_last_lr': [0.010000000000000002]}   
2 {'step_size': 1, 'gamma': 0.1, 'base_lrs': [0.1], 'last_epoch': 2, 'verbose': False, '_step_count': 3, '_get_lr_called_within_step': False, '_last_lr': [0.0010000000000000002]}  
3 {'step_size': 1, 'gamma': 0.1, 'base_lrs': [0.1], 'last_epoch': 3, 'verbose': False, '_step_count': 4, '_get_lr_called_within_step': False, '_last_lr': [0.00010000000000000003]} 
4 {'step_size': 1, 'gamma': 0.1, 'base_lrs': [0.1], 'last_epoch': 4, 'verbose': False, '_step_count': 5, '_get_lr_called_within_step': False, '_last_lr': [1.0000000000000004e-05]} 
5 {'step_size': 1, 'gamma': 0.1, 'base_lrs': [0.1], 'last_epoch': 5, 'verbose': False, '_step_count': 6, '_get_lr_called_within_step': False, '_last_lr': [1.0000000000000004e-06]} 
6 {'step_size': 1, 'gamma': 0.1, 'base_lrs': [0.1], 'last_epoch': 6, 'verbose': False, '_step_count': 7, '_get_lr_called_within_step': False, '_last_lr': [1.0000000000000005e-07]} 
7 {'step_size': 1, 'gamma': 0.1, 'base_lrs': [0.1], 'last_epoch': 7, 'verbose': False, '_step_count': 8, '_get_lr_called_within_step': False, '_last_lr': [1.0000000000000005e-08]} 
8 {'step_size': 1, 'gamma': 0.1, 'base_lrs': [0.1], 'last_epoch': 8, 'verbose': False, '_step_count': 9, '_get_lr_called_within_step': False, '_last_lr': [1.0000000000000005e-09]} 
9 {'step_size': 1, 'gamma': 0.1, 'base_lrs': [0.1], 'last_epoch': 9, 'verbose': False, '_step_count': 10, '_get_lr_called_within_step': False, '_last_lr': [1.0000000000000006e-10]}

输出详解:

  • step_size: 该值表示每隔多少个 epoch 学习率就会发生变化。在例子中, s t e p _ s i z e = 1 step\_size = 1 step_size=1,意味着每经过 1 个 epoch,学习率都会更新一次
  • gamma: 这是学习率更新的衰减因子。每次调用 s c h e d u l e r . s t e p ( ) scheduler.step() scheduler.step() 时,当前的学习率将会乘以 g a m m a gamma gamma。例子中, g a m m a = 0.1 gamma = 0.1 gamma=0.1,意味着每次更新学习率时,学习率将减少为原来的 10%
  • base_lrs: 这是每个参数组的初始学习率(在调度器调整之前的学习率)。这里的 [ 0.1 ] [0.1] [0.1]表示模型的初始学习率是 0.1。如果有多个参数组,这里会是一个列表,列出每个参数组的初始学习率
  • last_epoch: 这是上一个 epoch 的编号,用来确定学习率更新时的参考点。 l a s t _ e p o c h = 0 last\_epoch = 0 last_epoch=0 表示调度器刚刚初始化,学习率还没有更新过。通常,last_epoch 用来恢复训练时从哪个 epoch 开始更新学习率
  • verbose: 该参数控制调度器是否在学习率更新时打印详细信息。 v e r b o s e = F a l s e verbose = False verbose=False 表示调度器在更新学习率时不会打印信息。如果设置为 T r u e True True,则每次更新学习率时都会打印一条日志。
  • _step_count: 这个内部变量跟踪调度器已经调用了多少次 step()。在例子中, _ s t e p _ c o u n t = 1 \_step\_count = 1 _step_count=1,表示调度器已经调用过一次 s t e p ( ) step() step(),即更新过一次学习率
  • _get_lr_called_within_step: 是一个内部标志,表示是否在 step() 方法内部调用了 get_lr()。通常不需要关注这个值,它帮助调度器管理内部逻辑
  • _last_lr: 这是调度器最近一次计算的学习率。这个列表保存了每个参数组的学习率。在你的例子中, _ l a s t _ l r = [ 0.1 ] \_last\_lr = [0.1] _last_lr=[0.1],表示当前学习率是 0.1。这会在 scheduler.step() 后更新为新的学习率。

2.2.3 load_state_dict() 保存和加载调度器

可以将 state_dict() 保存到文件中,然后在以后恢复。如下是一个保存和加载学习率调度器状态的例子:

保存调度器状态:

# 保存调度器的 state_dict
torch.save(scheduler.state_dict(), 'scheduler_state.pth')

加载调度器状态:

# 加载调度器的 state_dict
scheduler.load_state_dict(torch.load('scheduler_state.pth'))

通过这种方式,可以在训练中断后恢复学习率调度器的状态,并继续进行训练。

保存调度器状态示例:

epoch = 5 时,保存调度器状态:

import torch
from torch import nn
from torch import optim
net = nn.Linear(3,4)
def train():optimizer = optim.Adam(net.parameters(), lr=0.1)scheduler = optim.lr_scheduler.StepLR(optimizer, step_size = 1, gamma=0.1)for epoch in range(10):if epoch == 5:torch.save(scheduler.state_dict(), 'scheduler_state.pth')breakoptimizer.step()scheduler.step()if __name__ == "__main__":train()

加载调度器状态示例:

import torch
from torch import nn
from torch import optimnet = nn.Linear(3,4)def train():optimizer = optim.Adam(net.parameters(), lr=0.1)scheduler = optim.lr_scheduler.StepLR(optimizer, step_size = 1, gamma=0.1)scheduler.load_state_dict(torch.load("scheduler_state.pth"))for epoch in range(3):print(epoch, scheduler.state_dict())optimizer.step()scheduler.step()if __name__ == "__main__":train()

代码输出:

0 {'step_size': 1, 'gamma': 0.1, 'base_lrs': [0.1], 'last_epoch': 5, 'verbose': False, '_step_count': 6, '_get_lr_called_within_step': False, '_last_lr': [1.0000000000000004e-06]}
1 {'step_size': 1, 'gamma': 0.1, 'base_lrs': [0.1], 'last_epoch': 6, 'verbose': False, '_step_count': 7, '_get_lr_called_within_step': False, '_last_lr': [0.010000000000000002]}
2 {'step_size': 1, 'gamma': 0.1, 'base_lrs': [0.1], 'last_epoch': 7, 'verbose': False, '_step_count': 8, '_get_lr_called_within_step': False, '_last_lr': [0.0010000000000000002]}

可以看到:

  • last_epoch 从 5 开始
  • _step_count 从6 开始
  • _last_lr 从 1e-6 开始

说明是从上次终断的状态继续运行

3. 思考

3.1 为什么需要state_dict()

  • 保存和恢复训练: 当你希望在训练中断后恢复训练时,你可以保存模型和调度器的 state_dict(),然后在恢复时加载它们,确保学习率调度器从上次停止的地方继续工作,而不是从头开始。
  • 调试和分析:通过 state_dict() 可以查看学习率的变化,帮助你调试和分析训练过程中调度器的行为。

3.2 get_lr() 与 get_last_lr() 的输出不一致问题

测试代码:

import torch
from torch import nn
from torch import optimnet = nn.Linear(3,4)def train():optimizer = optim.Adam(net.parameters(), lr=0.1)scheduler = optim.lr_scheduler.StepLR(optimizer, step_size = 1, gamma=0.1)for epoch in range(3):print(epoch, scheduler.get_lr())print(epoch, scheduler.get_last_lr())print([group["lr"] for group in optimizer.param_groups])print("==========================================")optimizer.step()scheduler.step()if __name__ == "__main__":train()

代码输出:

0 [0.1]
0 [0.1]
[0.1]
==========================================
1 [0.0010000000000000002]
1 [0.010000000000000002]
[0.010000000000000002]
==========================================
2 [0.00010000000000000003]
2 [0.0010000000000000002]
[0.0010000000000000002]
==========================================

不知道为什么从 epoch > 0 之后,get_lr() 每次都比 get_last_lr() 提前一步更新,但是通过查看 optimizer.param_groups 的学习率与 get_last_lr() 一致。

get_lr()函数源码:

def get_lr(self):if not self._get_lr_called_within_step:warnings.warn("To get the last learning rate computed by the scheduler, ""please use `get_last_lr()`.", UserWarning)if (self.last_epoch == 0) or (self.last_epoch % self.step_size != 0):return [group['lr'] for group in self.optimizer.param_groups]return [group['lr'] * self.gammafor group in self.optimizer.param_groups]

我们可以看到在源码中当:if (self.last_epoch == 0) or (self.last_epoch % self.step_size != 0),返回值为[group['lr'] for group in self.optimizer.param_groups], 否则的话返回值为[group['lr'] * self.gamma for group in self.optimizer.param_groups],因此可以很好的解释上面的现象,但是Pytorch为什么要这样做呢??目前没有找到相关资料,可以评论区留言讨论!

get_last_lr() 函数源码:

def get_last_lr(self):""" Return last computed learning rate by current scheduler."""return self._last_lr

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

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

相关文章

伊克罗德与九科信息共同发布RPA+AI智能机器人解决方案

12月12日&#xff0c;伊克罗德信息在上海举办“创见AI&#xff0c;迈进智能化未来——科技赋能零售电商”活动&#xff0c;与九科信息、亚马逊云科技共同探讨与分享&#xff0c;融合生成式AI技术和智能自动化&#xff08;RPA,Robotic Process Automation&#xff09;在电商零售…

hutool一些典型的方法使用笔记

hutool一些典型的方法使用笔记 1 克隆1.1 深克隆 2类型转换2.1其他类型转换为字符串2.2 转换为日期对象2.3 数组转集合2.4 Unicode和字符串转换2.5 数字转中文 文档地址&#xff1a;https://blog.csdn.net/dxjren/article/details/144468399 1 克隆 1.1 深克隆 定义一个实体类…

QT实战经验总结 连载中

QT实战经验总结 在看书系统学习后&#xff0c;就开始实战了&#xff0c;会遇到很多问题1.信号和槽的思考2.在python 或 C 代码中&#xff0c;对 QML 代码中控件的调用关于在一个窗口上不断打开新窗口 在看书系统学习后&#xff0c;就开始实战了&#xff0c;会遇到很多问题 pyt…

从 CephFS 到 JuiceFS:同程旅行亿级文件存储平台构建之路

随着公司业务的快速发展&#xff0c;同程旅行的非结构化的数据突破 10 亿&#xff0c;在 2022 年&#xff0c;同程首先完成了对象存储服务的建设。当时&#xff0c;分布式文件系统方面&#xff0c;同程使用的是 CephFS&#xff0c;随着数据量的持续增长&#xff0c;CephFS 的高…

固定资产分类,提升资产盘活效益

固定资产是企业长期使用的重要资源&#xff0c;涵盖范围广、种类多&#xff0c;不同的资产需要针对性管理。通过科学的分类与高效的盘活策略&#xff0c;不仅可以优化资源配置&#xff0c;还能提升企业资产的利用效率和经济效益。以下将详细解析固定资产的分类方式和盘活效益的…

富途证券C++面试题及参考答案

C++ 中堆和栈的区别 在 C++ 中,堆和栈是两种不同的内存区域,它们有许多区别。 从内存分配方式来看,栈是由编译器自动分配和释放的内存区域。当一个函数被调用时,函数内的局部变量、函数参数等会被压入栈中,这些变量的内存空间在函数执行结束后会自动被释放。例如,在下面的…

【字符串匹配算法——BF算法】

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” 文章目录 BF算法介绍及过程演示代码实现过程下节预告KMP算法利用next数组存储子串中j回退的位置&#xff08;…

Linux 文件系统目录结构及其简要介绍

Hello! 亲爱的小伙伴们&#xff0c;大家好呀&#xff08;Smile~&#xff09;&#xff01;我是 H u a z z i Huazzi Huazzi&#xff0c;欢迎观看本篇博客&#xff0c;接下来让我们一起来学习一下Linux 文件系统目录结构吧&#xff01;祝你有所收获&#xff01; 本篇博客的目录&a…

小米准备入局Nas?Nas究竟是啥?能干啥?

一开头就来了个三连问&#xff1a;小米准备入局Nas&#xff1f;Nas究竟是啥&#xff1f;Nas能干啥&#xff1f; 好像这段时间Nas这个词频频出现&#xff0c;但很多小伙伴都不知道这个是什么设备。首先咱们来解决一下名词Nas是什么意思。 什么是Nas&#xff1f; 为了尽可能解释…

基于Socket实现客户端和服务端的Tcp通信(C#)

0.前言 使用C#和Unity实现复刻Liar’s bar中的功能 软件开发大作业 本系列文章用于记录与分享开发过程中使用到的知识点&#xff0c;以及常见错误 本文主要描述有关网络编程的内容 目录 0.前言1.使用Socket搭建Server1.1Server端的Socket连接1.2 Server端接收Client的信息1.3…

【mysql】如何查看大表记录行数

目录 1. 使用 ANALYZE TABLE 和 SHOW TABLE STATUS2. 查询 INFORMATION_SCHEMA 表3. 使用索引统计信息4. 维护行数缓存5. 使用分区计数 1. 使用 ANALYZE TABLE 和 SHOW TABLE STATUS 1.ANALYZE TABLE 可以更新表的统计信息&#xff0c;然后使用 SHOW TABLE STATUS 来查看估算的…

文件断点续传(视频播放,大文件下载)

客户端每次请求取大文件部分数据。 浏览器播放mp4视频时&#xff0c;会首先传Range消息头&#xff0c;检测到206状态码&#xff0c;和Content-Range&#xff0c;Accept-Ranges 会自动请求余下数据。后端需要在文件任意偏移量取数据。 参考&#xff1a; springboot项目实现断…

游戏AI实现-寻路算法(A*)

A*&#xff08;A-star&#xff09;是一种图遍历和寻路算法&#xff0c;由于其完整性、最优性和最佳效率&#xff0c;它被用于计算机科学的许多领域。给定一个加权图、一个源节点和一个目标节点&#xff0c;该算法将找到从源到目标的最短路径&#xff08;相对于给定的权重&#…

any/all 子查询优化规则的原理与解析 | OceanBase查询优化

背景 在通常情况下&#xff0c;当遇到包含any/all子查询的语句时&#xff0c;往往需要遵循嵌套执行的方式&#xff0c;因此其查询效率较低。Oceanbase中制定了相应的any/all子查询优化规则&#xff0c;能够能够识别并优化符合条件的any/all子查询&#xff0c;从而有效提升查询…

[HNOI2002] 营业额统计 STL - set集合

文章目录 [HNOI2002] 营业额统计题目描述样例输入 #1样例输出 #1 提示题解相关知识点set [HNOI2002] 营业额统计 STL - set解题 题目描述 Tiger 最近被公司升任为营业部经理&#xff0c;他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况。 Tiger 拿出…

汽车供应链 “剧变”开始,“智能感知潜在龙头”诞生

智能汽车产业链“剧变”已经开启&#xff0c;智能感知软硬件能力的权重正在不断被放大。 比如满足高阶泊车的第二代AK2超声波传感器、满足人机共驾场景需求的电子外后视镜&#xff08;CMS&#xff09;、iTOF 3D成像视觉感知&#xff08;用于舱内监控&#xff09;等新产品&…

Latex中表格添加底部文本注释并调整对齐

如何实现从第一个表到第三个表的转换&#xff0c; 其中主要涉及到两点&#xff1a; &#xff08;1&#xff09;底部脚注与表格自动对齐并缩进换行 &#xff08;2&#xff09;表格自适应页面宽度 底部脚注的对齐与换行缩进需要用到 \usepackage{threeparttable} \usepackage{…

SQL 查询方式比较:子查询与自连接

在 SQL 中&#xff0c;子查询和自连接是两种常见的查询方式&#xff0c;它们的功能虽然可以相同&#xff0c;但实现的方式不同。本文通过具体示例&#xff0c;深入探讨这两种查询方式&#xff0c;并配合数据展示&#xff0c;帮助大家理解它们的使用场景和差异。 数据示例 假设…

html基础-认识html

1.什么是html html是浏览器可以识别的的标记语言&#xff0c;我们在浏览器浏览的网页就是一个个的html文档 <!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title>认识html</title> </head> <body><h1…

linux 无网络安装mysql

下载地址 通过网盘分享的文件&#xff1a;mysql-5.7.33-linux-glibc2.12-x86_64.tar.gz 链接: https://pan.baidu.com/s/1qm48pNfGYMqBGfoqT3hxPw?pwd0012 提取码: 0012 安装 解压 tar -zxvf mysql-5.7.33-linux-glibc2.12-x86_64.tar.gz mv /usr/mysql-5.7.33-linux-glibc2.1…