【20天拿下Pytorch:Day 7】Dataset和DataLoader

news2024/11/15 17:55:31

文章目录

    • 1. Dataset和DataLoader概述
      • 1.1 概要
      • 1.2 获取一个batch数据的步骤
      • 1.3 Dataset和DataLoader的功能分工
      • 1.4 Dataset和DataLoader的主要接口
    • 2. 使用Dataset创建数据集
      • 2.1 根据Tensor创建数据集
      • 2.2 根据图片目录创建图片数据集
      • 2.3 创建自定义数据集
    • 3. 使用DataLoader加载数据集

1. Dataset和DataLoader概述

1.1 概要

  • Pytorch通常使用Dataset和DataLoader这两个工具类来构建数据管道。

  • Dataset定义了数据集的内容,它相当于一个类似列表的数据结构,具有确定的长度,能够用索引获取数据集中的元素。

  • 而DataLoader定义了按batch加载数据集的方法,它是一个实现了__iter__方法的可迭代对象,每次迭代输出一个batch的数据。

  • DataLoader能够控制batch的大小,batch中元素的采样方法,以及将batch结果整理成模型所需输入形式的方法,并且能够使用多进程读取数据。

  • 在绝大部分情况下,用户只需实现Dataset的__len__方法和__getitem__方法,就可以轻松构建自己的数据集,并用默认数据管道进行加载。

1.2 获取一个batch数据的步骤

考虑一下从一个数据集中获取一个batch的数据需要哪些步骤。

(假定数据集的特征和标签分别表示为张量X和Y,数据集可以表示为(X,Y), 假定batch大小为m)

  1. 首先我们要确定数据集的长度n。
    结果类似:n = 1000。

  2. 然后从0到n-1的范围中抽样出m个数(batch大小)。
    假定m=4, 拿到的结果是一个列表,类似:indices = [1,4,8,9]

  3. 接着我们从数据集中去取这m个数对应下标的元素。
    拿到的结果是一个元组列表,类似:samples = [(X[1],Y[1]),(X[4],Y[4]),(X[8],Y[8]),(X[9],Y[9])]

  4. 最后我们将结果整理成两个张量作为输出。
    拿到的结果是两个张量,类似batch = (features,labels),其中,
    features = torch.stack([X[1],X[4],X[8],X[9]])
    labels = torch.stack([Y[1],Y[4],Y[8],Y[9]])

1.3 Dataset和DataLoader的功能分工

上述第1个步骤确定数据集的长度是由 Dataset的__len__ 方法实现的。

第2个步骤从0到n-1的范围中抽样出m个数的方法是由 DataLoader的 sampler和 batch_sampler参数指定的。

sampler参数指定单个元素抽样方法,一般无需用户设置,程序默认在DataLoader的参数shuffle=True时采用随机抽样,shuffle=False时采用顺序抽样。

batch_sampler参数将多个抽样的元素整理成一个列表,一般无需用户设置,默认方法在DataLoader的参数drop_last=True时会丢弃数据集最后一个长度不能被batch大小整除的批次,在drop_last=False时保留最后一个批次。

第3个步骤的核心逻辑根据下标取数据集中的元素 是由 Dataset的 __getitem__方法实现的。

第4个步骤的逻辑由DataLoader的参数collate_fn指定。一般情况下也无需用户设置。

1.4 Dataset和DataLoader的主要接口

以下是 Dataset和 DataLoader的核心接口逻辑伪代码,不完全和源码一致。

import torch 
class Dataset(object):
    def __init__(self):
        pass

    def __len__(self):
        raise NotImplementedError

    def __getitem__(self,index):
        raise NotImplementedError


class DataLoader(object):
    def __init__(self,dataset,batch_size,collate_fn,shuffle = True,drop_last = False):
        self.dataset = dataset
        self.sampler =torch.utils.data.RandomSampler if shuffle else \
           torch.utils.data.SequentialSampler
        self.batch_sampler = torch.utils.data.BatchSampler
        self.sample_iter = self.batch_sampler(
            self.sampler(range(len(dataset))),
            batch_size = batch_size,drop_last = drop_last)

    def __next__(self):
        indices = next(self.sample_iter)
        batch = self.collate_fn([self.dataset[i] for i in indices])
        return batch

2. 使用Dataset创建数据集

Dataset创建数据集常用的方法有:

  • 使用 torch.utils.data.TensorDataset 根据Tensor创建数据集(numpy的array,Pandas的DataFrame需要先转换成Tensor)。

  • 使用 torchvision.datasets.ImageFolder 根据图片目录创建图片数据集。

  • 继承 torch.utils.data.Dataset 创建自定义数据集。

此外,还可以通过

  • torch.utils.data.random_split 将一个数据集分割成多份,常用于分割训练集,验证集和测试集。

  • 调用Dataset的加法运算符(+)将多个数据集合并成一个数据集。

2.1 根据Tensor创建数据集

先导包

import numpy as np 
import torch 
from torch.utils.data import TensorDataset,Dataset,DataLoader,random_split 

根据Tensor创建数据集

from sklearn import datasets 
iris = datasets.load_iris()
ds_iris = TensorDataset(torch.tensor(iris.data),torch.tensor(iris.target))

# 分割成训练集和预测集
n_train = int(len(ds_iris)*0.8)
n_valid = len(ds_iris) - n_train
ds_train,ds_valid = random_split(ds_iris,[n_train,n_valid])

print(type(ds_iris))
print(type(ds_train))

使用DataLoader加载数据集

dl_train,dl_valid = DataLoader(ds_train,batch_size = 8),DataLoader(ds_valid,batch_size = 8)

for features,labels in dl_train:
    print(features,labels)
    break

演示加法运算符(+)的合并作用

ds_data = ds_train + ds_valid

print('len(ds_train) = ',len(ds_train))
print('len(ds_valid) = ',len(ds_valid))
print('len(ds_train+ds_valid) = ',len(ds_data))

print(type(ds_data))

2.2 根据图片目录创建图片数据集

先导包

import numpy as np 
import torch 
from torch.utils.data import DataLoader
from torchvision import transforms,datasets 

演示一些常用的图片增强操作

from PIL import Image
img = Image.open('梅里雪山.png')
img

在这里插入图片描述
随机数值翻转

transforms.RandomVerticalFlip()(img)

在这里插入图片描述

随机旋转

transforms.RandomRotation(45)(img)

在这里插入图片描述
定义图片增强操作

transform_train = transforms.Compose([
   transforms.RandomHorizontalFlip(), #随机水平翻转
   transforms.RandomVerticalFlip(), #随机垂直翻转
   transforms.RandomRotation(45),  #随机在45度角度内旋转
   transforms.ToTensor() #转换成张量
  ]
) 

transform_valid = transforms.Compose([
    transforms.ToTensor()
  ]
)

根据图片目录创建数据集

# 根据图片目录创建数据集
ds_train = datasets.ImageFolder("./data/cifar2/train/",
            transform = transform_train,target_transform= lambda t:torch.tensor([t]).float())
ds_valid = datasets.ImageFolder("./data/cifar2/test/",
            transform = transform_train,target_transform= lambda t:torch.tensor([t]).float())

print(ds_train.class_to_idx)
# 使用DataLoader加载数据集

dl_train = DataLoader(ds_train,batch_size = 50,shuffle = True,num_workers=3)
dl_valid = DataLoader(ds_valid,batch_size = 50,shuffle = True,num_workers=3)
for features,labels in dl_train:
    print(features.shape)
    print(labels.shape)
    break

2.3 创建自定义数据集

下面通过继承Dataset类创建imdb文本分类任务的自定义数据集。

大概思路如下:首先,对训练集文本分词构建词典。然后将训练集文本和测试集文本数据转换成token单词编码。

接着将转换成单词编码的训练集数据和测试集数据按样本分割成多个文件,一个文件代表一个样本。

最后,我们可以根据文件名列表获取对应序号的样本内容,从而构建Dataset数据集。

import numpy as np 
import pandas as pd 
from collections import OrderedDict
import re,string

MAX_WORDS = 10000  # 仅考虑最高频的10000个词
MAX_LEN = 200  # 每个样本保留200个词的长度
BATCH_SIZE = 20 

train_data_path = 'data/imdb/train.tsv'
test_data_path = 'data/imdb/test.tsv'
train_token_path = 'data/imdb/train_token.tsv'
test_token_path =  'data/imdb/test_token.tsv'
train_samples_path = 'data/imdb/train_samples/'
test_samples_path =  'data/imdb/test_samples/'

首先我们构建词典,并保留最高频的MAX_WORDS个词。

##构建词典

word_count_dict = {}

#清洗文本
def clean_text(text):
    lowercase = text.lower().replace("\n"," ")
    stripped_html = re.sub('<br />', ' ',lowercase)
    cleaned_punctuation = re.sub('[%s]'%re.escape(string.punctuation),'',stripped_html)
    return cleaned_punctuation

with open(train_data_path,"r",encoding = 'utf-8') as f:
    for line in f:
        label,text = line.split("\t")
        cleaned_text = clean_text(text)
        for word in cleaned_text.split(" "):
            word_count_dict[word] = word_count_dict.get(word,0)+1 

df_word_dict = pd.DataFrame(pd.Series(word_count_dict,name = "count"))
df_word_dict = df_word_dict.sort_values(by = "count",ascending =False)

df_word_dict = df_word_dict[0:MAX_WORDS-2] #  
df_word_dict["word_id"] = range(2,MAX_WORDS) #编号0和1分别留给未知词<unkown>和填充<padding>

word_id_dict = df_word_dict["word_id"].to_dict()

df_word_dict.head(10)

然后我们利用构建好的词典,将文本转换成token序号。

#转换token

# 填充文本
def pad(data_list,pad_length):
    padded_list = data_list.copy()
    if len(data_list)> pad_length:
         padded_list = data_list[-pad_length:]
    if len(data_list)< pad_length:
         padded_list = [1]*(pad_length-len(data_list))+data_list
    return padded_list

def text_to_token(text_file,token_file):
    with open(text_file,"r",encoding = 'utf-8') as fin,\
      open(token_file,"w",encoding = 'utf-8') as fout:
        for line in fin:
            label,text = line.split("\t")
            cleaned_text = clean_text(text)
            word_token_list = [word_id_dict.get(word, 0) for word in cleaned_text.split(" ")]
            pad_list = pad(word_token_list,MAX_LEN)
            out_line = label+"\t"+" ".join([str(x) for x in pad_list])
            fout.write(out_line+"\n")

text_to_token(train_data_path,train_token_path)
text_to_token(test_data_path,test_token_path)

接着将token文本按照样本分割,每个文件存放一个样本的数据。

# 分割样本
import os

if not os.path.exists(train_samples_path):
    os.mkdir(train_samples_path)

if not os.path.exists(test_samples_path):
    os.mkdir(test_samples_path)


def split_samples(token_path,samples_dir):
    with open(token_path,"r",encoding = 'utf-8') as fin:
        i = 0
        for line in fin:
            with open(samples_dir+"%d.txt"%i,"w",encoding = "utf-8") as fout:
                fout.write(line)
            i = i+1

split_samples(train_token_path,train_samples_path)
split_samples(test_token_path,test_samples_path)

一切准备就绪,我们可以创建数据集Dataset, 从文件名称列表中读取文件内容了。

import os
class imdbDataset(Dataset):
    def __init__(self,samples_dir):
        self.samples_dir = samples_dir
        self.samples_paths = os.listdir(samples_dir)

    def __len__(self):
        return len(self.samples_paths)

    def __getitem__(self,index):
        path = self.samples_dir + self.samples_paths[index]
        with open(path,"r",encoding = "utf-8") as f:
            line = f.readline()
            label,tokens = line.split("\t")
            label = torch.tensor([float(label)],dtype = torch.float)
            feature = torch.tensor([int(x) for x in tokens.split(" ")],dtype = torch.long)
            return  (feature,label)
ds_train = imdbDataset(train_samples_path)
ds_test = imdbDataset(test_samples_path)
dl_train = DataLoader(ds_train,batch_size = BATCH_SIZE,shuffle = True,num_workers=4)
dl_test = DataLoader(ds_test,batch_size = BATCH_SIZE,num_workers=4)

for features,labels in dl_train:
    print(features)
    print(labels)
    break

最后构建模型测试一下数据集管道是否可用。

import torch
from torch import nn 
import importlib 
from torchkeras import Model,summary

class Net(Model):

    def __init__(self):
        super(Net, self).__init__()

        #设置padding_idx参数后将在训练过程中将填充的token始终赋值为0向量
        self.embedding = nn.Embedding(num_embeddings = MAX_WORDS,embedding_dim = 3,padding_idx = 1)
        self.conv = nn.Sequential()
        self.conv.add_module("conv_1",nn.Conv1d(in_channels = 3,out_channels = 16,kernel_size = 5))
        self.conv.add_module("pool_1",nn.MaxPool1d(kernel_size = 2))
        self.conv.add_module("relu_1",nn.ReLU())
        self.conv.add_module("conv_2",nn.Conv1d(in_channels = 16,out_channels = 128,kernel_size = 2))
        self.conv.add_module("pool_2",nn.MaxPool1d(kernel_size = 2))
        self.conv.add_module("relu_2",nn.ReLU())

        self.dense = nn.Sequential()
        self.dense.add_module("flatten",nn.Flatten())
        self.dense.add_module("linear",nn.Linear(6144,1))
        self.dense.add_module("sigmoid",nn.Sigmoid())

    def forward(self,x):
        x = self.embedding(x).transpose(1,2)
        x = self.conv(x)
        y = self.dense(x)
        return y

model = Net()
print(model)

model.summary(input_shape = (200,),input_dtype = torch.LongTensor)
Net(
  (embedding): Embedding(10000, 3, padding_idx=1)
  (conv): Sequential(
    (conv_1): Conv1d(3, 16, kernel_size=(5,), stride=(1,))
    (pool_1): MaxPool1d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (relu_1): ReLU()
    (conv_2): Conv1d(16, 128, kernel_size=(2,), stride=(1,))
    (pool_2): MaxPool1d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (relu_2): ReLU()
  )
  (dense): Sequential(
    (flatten): Flatten()
    (linear): Linear(in_features=6144, out_features=1, bias=True)
    (sigmoid): Sigmoid()
  )
)

# 编译模型
def accuracy(y_pred,y_true):
    y_pred = torch.where(y_pred>0.5,torch.ones_like(y_pred,dtype = torch.float32),
                      torch.zeros_like(y_pred,dtype = torch.float32))
    acc = torch.mean(1-torch.abs(y_true-y_pred))
    return acc

model.compile(loss_func = nn.BCELoss(),optimizer= torch.optim.Adagrad(model.parameters(),lr = 0.02),
             metrics_dict={"accuracy":accuracy})
# 训练模型
dfhistory = model.fit(10,dl_train,dl_val=dl_test,log_step_freq= 200)

3. 使用DataLoader加载数据集

DataLoader能够控制batch的大小,batch中元素的采样方法,以及将batch结果整理成模型所需输入形式的方法,并且能够使用多进程读取数据。

DataLoader的函数签名如下:

DataLoader(
    dataset,
    batch_size=1,
    shuffle=False,
    sampler=None,
    batch_sampler=None,
    num_workers=0,
    collate_fn=None,
    pin_memory=False,
    drop_last=False,
    timeout=0,
    worker_init_fn=None,
    multiprocessing_context=None,
)

一般情况下,我们仅仅会配置 dataset, batch_size, shuffle, num_workers, drop_last这五个参数,其他参数使用默认值即可。

DataLoader除了可以加载我们前面讲的 torch.utils.data.Dataset 外,还能够加载另外一种数据集 torch.utils.data.IterableDataset。

和Dataset数据集相当于一种列表结构不同,IterableDataset相当于一种迭代器结构。 它更加复杂,一般较少使用。

参数解释:

  • dataset : 数据集
  • batch_size: 批次大小
  • shuffle: 是否乱序
  • sampler: 样本采样函数,一般无需设置。
  • batch_sampler: 批次采样函数,一般无需设置。
  • num_workers: 使用多进程读取数据,设置的进程数。
  • collate_fn: 整理一个批次数据的函数。
  • pin_memory: 是否设置为锁业内存。默认为False,锁业内存不会使用虚拟内存(硬盘),从锁业内存拷贝到GPU上速度会更快。
  • drop_last: 是否丢弃最后一个样本数量不足batch_size批次数据。
  • timeout: 加载一个数据批次的最长等待时间,一般无需设置。
  • worker_init_fn: 每个worker中dataset的初始化函数,常用于 IterableDataset。一般不使用。

用法举例:

#构建输入数据管道
ds = TensorDataset(torch.arange(1,50))
dl = DataLoader(ds,
                batch_size = 10,
                shuffle= True,
                num_workers=2,
                drop_last = True)
#迭代数据
for batch, in dl:
    print(batch)

输出:

tensor([18, 11,  4, 25, 37, 10,  5, 44, 31,  6])
tensor([49, 48, 26, 14, 36, 43, 12,  7, 29, 28])
tensor([ 9,  8, 20, 24, 32, 15, 41, 35, 46, 45])
tensor([47,  1, 27, 21, 39, 23, 17, 22, 42,  2])

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

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

相关文章

C++ TCP发送Socket数据

DEVC需要加入ws2_32库 #include <iostream> #include <winsock2.h>#pragma comment(lib, "ws2_32.lib")void sendData(const char* ip, int port, const char* data) {WSADATA wsaData;SOCKET sockfd;struct sockaddr_in server_addr;// 初始化Winsock…

打气球小游戏

1.气球往上飘 我们声明两个符号常量来作为窗体的长和宽,接着就是常规操作 #define WINDOW_WIDTH 800 #define WINDOW_HEIGHT 600#include<easyx.h> #include<stdio.h> int main() {initgraph(WINDOW_WIDTH, WINDOW_HEIGHT);setbkcolor(WHITE);cleardevice();get…

php部分特性漏洞学习

php部分函数漏洞学习 简单总结一些我遇到的ctf中的php的一些函数或特性的漏洞&#xff0c;我刷题还是太少了&#xff0c;所以很多例子来自ctfshow&#xff0c;以后遇到相关赛题再更新 1.MD5和其他hash 弱类型比较 php中&#xff0c;有两中判断相等的符号&#xff0c;和&…

【Linux】进程信号及相关函数/系统调用的简单认识与使用

文章目录 前言一、相关函数/系统调用1. signal2. kill3. abort (库函数)4. raise (库函数)5. alarm 前言 现实生活中, 存在着诸多信号, 比如红绿灯, 上下课铃声…我们在接收到信号时, 就会做出相应的动作. 对于进程也是如此的, 进程也会收到来自 OS 发出的信号, 根据信号的不同…

树莓派 Raspberry Pi M.2 HAT+ 现已发售!原理图流出!

​Raspberry Pi M.2 HAT 使您能够将 M.2 M-key 外设&#xff08;如 NVMe 驱动器和人工智能加速器&#xff09;连接到 Raspberry Pi 5。它能够提供与这些外设之间的快数据传输&#xff08;高达 500 MB/s&#xff09;&#xff0c;现在就可以从树莓派的授权经销商网络购买&#xf…

智能网关和交换机在智慧路灯杆上的用途差别

智慧路灯杆是智能城市建设中的一个重要组成部分&#xff0c;它整合了智能照明、视频监控、交通管理、环境监测、网络覆盖、信息发布、一键告警等多种功能。针对智慧路灯杆的使用场景&#xff0c;智能网关和交换机各自发挥着不同的作用&#xff0c;并且拥有各自的优缺点&#xf…

5.14.3 UNETR:用于 3D 医学图像分割的 Transformers

具有收缩和扩展路径的全卷积神经网络 (FCNN) 在大多数医学图像分割应用中表现出了突出的作用。在 FCNN 中&#xff0c;编码器通过学习全局和局部特征以及上下文表示来发挥不可或缺的作用&#xff0c;这些特征和上下文表示可用于解码器的语义输出预测。 在FCNN中&#xff0c;收缩…

包装类..

定义&#xff1a;基本数据类型对应的对象。 如何获取包装类&#xff1a;直接赋值即可&#xff1b;Integer i10; 其中的一个成员方法&#xff1a; public static int parseInt(String s)——把字符串类型的整数转成int 类型的整数。 8种包装类中&#xff0c;除了character都…

力扣刷题---1748.唯一元素的和【简单】

题目描述 给你一个整数数组 nums 。数组中唯一元素是那些只出现 恰好一次 的元素。 请你返回 nums 中唯一元素的 和 。 示例 1&#xff1a; 输入&#xff1a;nums [1,2,3,2] 输出&#xff1a;4 解释&#xff1a;唯一元素为 [1,3] &#xff0c;和为 4 。 示例 2&#xff1a;…

单词可交互的弧形文本

在一个项目中&#xff0c;要求把少儿读本做成电子教材呈现出来&#xff0c;电子书的排版要求跟纸质书一致。其中&#xff0c;英语书有个需求&#xff1a;书中有些不规则排版的文本&#xff08;如下图所示&#xff09;&#xff0c;当随书音频播放时&#xff0c;被读到的文本要求…

注意力机制篇 | MSFE:即插即用的多尺度滑窗注意力(附源码实现)

前言:Hello大家好,我是小哥谈。多尺度滑窗注意力(Multi-Scale Sliding Window Attention,MSFE)是一种用于处理图像的深度学习模型。它通过引入多尺度特征提取和滑窗注意力机制来提高图像识别的准确性。在MSFE中,模型采用多尺度卷积神经网络来提取图像的特征,然后使用滑窗…

同旺科技 FLUKE ADPT 隔离版发布 ---- 2

所需设备&#xff1a; 1、FLUKE ADPT 隔离版 内附链接&#xff1b; 应用于&#xff1a;福禄克Fluke 12E / 15BMax / 17B Max / 101 / 106 / 107 应用于&#xff1a;福禄克Fluke 15B / 17B / 18B 正面&#xff1a; 反面&#xff1a; 侧面&#xff1a; 开孔位置&#xff08;可…

一种综合评价及决策方法:层次分析法AHP

大家好&#xff0c;层次分析法(Analytic Hierarchy Process&#xff0c;AHP)是一种多准则决策方法&#xff0c;它帮助决策者处理复杂的决策问题&#xff0c;将其分解成层次结构&#xff0c;然后通过两两比较来确定各个层次的因素之间的相对重要性。这种分析方式允许决策者对问题…

抖店,今年入场还有机会吗?从客观角度分析!

大家好&#xff0c;我是电商小V 伴随着短视频平台的兴起&#xff0c;也慢慢的步入了电商市场&#xff0c;成为了一个新的电商模式&#xff0c;抖音小店就是依靠着短视频达人带货的流量模式&#xff0c;可以说一直处于红利期&#xff0c;享受着这个短视频风口&#xff0c;也是吸…

前端更改线上请求地址

由于后台接口更改 , 线上请求地址需从 /api/api/ 改成 /api/ , 需实现的效果如下图 1 在原本的vite.config.js中将前端做的端口转发内容更改 , 更改一行即可 import { defineConfig } from vite import react from vitejs/plugin-react import path from path import * as fs …

C语言指针相关知识(第四篇章)(非常详细版)

文章目录 前言一、什么是回调函数二、qsort函数的介绍(默认升序排序)三、qsort函数的模拟实现&#xff08;通过冒泡排序&#xff09;总结 前言 本文介绍了回调函数&#xff0c;qsort函数的使用&#xff0c;以用冒泡排序来模拟实现qsort函数 提示&#xff1a;以下是本篇文章正文…

大语言模型量化方法对比:GPTQ、GGUF、AWQ 包括显存和速度

GPTQ: Post-Training Quantization for GPT Models GPTQ是一种4位量化的训练后量化(PTQ)方法&#xff0c;主要关注GPU推理和性能。 该方法背后的思想是&#xff0c;尝试通过最小化该权重的均方误差将所有权重压缩到4位。在推理过程中&#xff0c;它将动态地将其权重去量化为f…

【wvp】获取丢包及码率等参数

目录 设计 测试 swagger 设计 /** * 获取推流过程中的bytesSpeed,loss等统计信息 * 方案1&#xff1a;每个app stream 一个线程&#xff0c;定时获取统计信息。当subscribe 时&#xff0c;进行“增加&#xff1b;修改&#xff1b;加入队列”操作。 * 缺点&#xff1a; 占用…

linux mail命令及其历史

一、【问题描述】 最近隔壁组有人把crontab删了&#xff0c;crontab这个命令有点反人类&#xff0c;它的参数特别容易误操作&#xff1a; crontab - 是删除计划表 crontab -e 是编辑&#xff0c;总之就是特别容易输入错误。 好在可以通过mail命令找回&#xff0c;但是mai…

CentOS-9配置静态IP地址

查看配置命令nmcli CentOS 9 使用 nmcli 命令行工具进行网络配置。以下是配置静态 IP 地址的步骤和示例代码&#xff1a;相对以前centos7之类的&#xff0c;9版本的默认的网络是NetworkManager&#xff0c;网络配置也有较大改变 nmcli con show用vim进行编辑配文件 cd /etc/…