PyTorch实战:实现Cifar10彩色图片分类

news2024/9/29 17:23:08

目录

前言

一、Cifar10数据集

class torch.utils.data.Dataset

 torch.utils.data.DataLoader

二、定义神经网络

普通神经网络:

定义损失函数和优化器

 训练网络-Net

CPU训练

模型准确率

​编辑

GPU训练

训练网络-LeNet

模型准确率

点关注,防走丢,如有纰漏之处,请留言指教,非常感谢


前言

PyTorch可以说是三大主流框架中最适合初学者学习的了,相较于其他主流框架,PyTorch的简单易用性使其成为初学者们的首选。这样我想要强调的一点是,框架可以类比为编程语言,仅为我们实现项目效果的工具,也就是我们造车使用的轮子,我们重点需要的是理解如何使用Torch去实现功能而不要过度在意轮子是要怎么做出来的,那样会牵扯我们太多学习时间。以后就出一系列专门细解深度学习框架的文章,但是那是较后期我们对深度学习的理论知识和实践操作都比较熟悉才好开始学习,现阶段我们最需要的是学会如何使用这些工具。

深度学习的内容不是那么好掌握的,包含大量的数学理论知识以及大量的计算公式原理需要推理。且如果不进行实际操作很难够理解我们写的代码究极在神经网络计算框架中代表什么作用。不过我会尽可能将知识简化,转换为我们比较熟悉的内容,我将尽力让大家了解并熟悉神经网络框架,保证能够理解通畅以及推演顺利的条件之下,尽量不使用过多的数学公式和专业理论知识。以一篇文章快速了解并实现该算法,以效率最高的方式熟练这些知识。


博主专注数据建模四年,参与过大大小小数十来次数学建模,理解各类模型原理以及每种模型的建模流程和各类题目分析方法。此专栏的目的就是为了让零基础快速使用各类数学模型、机器学习和深度学习以及代码,每一篇文章都包含实战项目以及可运行代码。博主紧跟各类数模比赛,每场数模竞赛博主都会将最新的思路和代码写进此专栏以及详细思路和完全代码。希望有需求的小伙伴不要错过笔者精心打造的专栏:一文速学-数学建模常用模型


一、Cifar10数据集

CIFAR-10是一个广泛用于测试和验证图像分类算法的基准数据集之一,因其相对较小的规模和丰富的多样性而备受研究者关注。在深度学习领域,许多研究和论文都会以CIFAR-10作为测试数据集,以评估他们的模型性能。这些类别分别是:

  1. 飞机(airplane)
  2. 汽车(automobile)
  3. 鸟类(bird)
  4. 猫(cat)
  5. 鹿(deer)
  6. 狗(dog)
  7. 青蛙(frog)
  8. 马(horse)
  9. 船(ship)
  10. 卡车(truck)

数据集被分为训练集和测试集,其中训练集包含50,000张图片,测试集包含10,000张图片。每张图片都是3*32*32,也即3-通道彩色图片,分辨率为32*32。此外,还有一个CIFAR-100的数据集,由于CIFAR-10和CIFAR-100除了分类类别数不一样外,其他差别不大,此处仅拿CIFAR-10这个相对小点的数据集来进行介绍,介绍用pytorch来进行图像分类的一般思路和方法。

官方下载网址:CIFAR-10 and CIFAR-100 datasets

使用torch.utils.data加载数据:

import numpy as np
import torch
import torchvision.transforms as transforms
import os
from torch.utils.data import DataLoader
from torchvision.transforms import ToPILImage
show = ToPILImage() # 可以把Tensor转成Image,方便可视化
import torchvision.datasets as dsets
batch_size = 100
os.environ["KMP_DUPLICATE_LIB_OK"]="TRUE"

# 定义对数据的预处理
transform = transforms.Compose([
        transforms.ToTensor(), # 转为Tensor
        transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)), # 归一化 先将输入归一化到(0,1),再使用公式”(x-mean)/std”,将每个元素分布到(-1,1) 
                             ])

#Cifar110 dataset
train_dataset = dsets.CIFAR10(root='/ml/pycifar',
                              train = True,
                              download = True,
                              transform=transform
                             )
test_dataset = dsets.CIFAR10(root='/ml/pycifar',
                             train = False,
                             download = True,
                             transform=transform
                            )
#加载数据
train_loader=torch.utils.data.DataLoader(dataset=train_dataset,
                                         batch_size = batch_size,
                                         shuffle = True
                                        )
test_loader = torch.utils.data.DataLoader(dataset = test_dataset,
                                          batch_size=batch_size,
                                          shuffle=True
                                         )

数据展示:

import matplotlib.pyplot as plt
fig = plt.figure()
classes=['plane','car','bird','cat','deer','dog','frog','horse','ship','truck']
for i in range(12):
    plt.subplot(3, 4, i+1)
    plt.tight_layout()
    (_, label) = train_dataset[i] 
    plt.imshow(train_loader.dataset.data[i],cmap=plt.cm.binary)
    plt.title("Labels: {}".format(classes[label]))
    plt.xticks([])
    plt.yticks([])
plt.show()

 

 数据集分为五个训练批次和一个测试批次,每个批次有10000张图像。测试批次包含从每个类别中随机选择的1000幅图像。训练批包含随机顺序的剩余图像,但一些训练批可能包含一个类中的图像多于另一个类的图像。在它们之间,训练批次包含每个类别的正好5000个图像。

数据集我们已经导入成功,需要说明的是我们之前已经对数据进行了预处理,并使数据归一化,补充一下两个需要了解的数据加载基类Dataset和DataLoader:

class torch.utils.data.Dataset

PyTorch的Dataset是一个抽象类,用于表示数据集。它允许你自定义数据集的加载方式,以便于在训练和测试过程中使用。

  1. 数据加载与预处理: Dataset允许你自定义数据的加载方式,可以从文件、数据库、网络等来源加载数据。你可以在__getitem__方法中实现数据的预处理、转换等操作,以满足模型的输入要求。

  2. 支持索引: 通过实现__getitem__方法,Dataset可以通过索引(如dataset[i])获取数据样本。这允许你按需读取数据,适用于大规模数据集,避免一次性加载所有数据。

  3. 返回样本总数: len(dataset)返回数据集中样本的总数,便于在训练过程中设置合适的迭代次数。

  4. 可迭代: Dataset可以像Python列表一样进行迭代,这意味着你可以在数据集上使用for循环。

  5. 与DataLoader结合使用: Dataset通常与PyTorch的DataLoader一起使用,DataLoader可以将数据批量加载到模型中,实现了数据的批处理。

  6. 实现自定义数据集: 你可以继承Dataset类,根据自己的需求创建自定义的数据集。

可以重构为:

from torch.utils.data import Dataset

class CustomDataset(Dataset):
    def __init__(self, data):
        self.data = data

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

    def __getitem__(self, idx):
        sample = self.data[idx]
        # 这里可以进行数据预处理或转换
        return sample

# 使用示例
data = [1, 2, 3, 4, 5]
custom_dataset = CustomDataset(data)
print(len(custom_dataset))  # 输出: 5
print(custom_dataset[2])  # 输出: 3

 torch.utils.data.DataLoader

 torch.utils.data.DataLoader比较复杂一点,torch提供了很多参数可以用,常用的参数需要掌握:

  1. dataset (Dataset): 要加载的数据集。通常是一个继承自 torch.utils.data.Dataset 的自定义数据集对象。

  2. batch_size (int, optional): 每个批次的样本数量。默认值为 1。

  3. shuffle (bool, optional): 是否在每个 epoch 开始时随机打乱数据。默认值为 False。

  4. sampler (Sampler, optional): 定义从数据集中采样样本的策略。如果指定了此参数,shuffle 参数将被忽略。

  5. batch_sampler (Sampler, optional):sampler 相似,但返回的是一个 batch 的索引列表。

  6. num_workers (int, optional): 用于数据加载的子进程数量。默认值为 0,表示所有数据将在主进程中加载。设置为大于 0 的值将启动相应数量的子进程来加载数据,可以加速数据加载。

  7. collate_fn (callable, optional): 用于将一个个样本打包成一个 batch 的函数。通常在输入数据具有不同大小时使用。

  8. pin_memory (bool, optional): 如果为 True,则数据加载器会将数据存储在 CUDA 固定内存中,可以加速数据传输到 GPU。默认值为 False。

  9. drop_last (bool, optional): 如果为 True,则在最后一个 batch 的大小小于 batch_size 时,该 batch 将被丢弃。默认值为 False。

  10. timeout (numeric, optional): 在等待新数据时的超时时间(以秒为单位)。如果设置为 None,则会一直等待,直到数据准备好。默认值为 0。

  11. worker_init_fn (callable, optional): 每个 worker 在开始加载数据之前会调用此函数。可以用于在 worker 中初始化一些特定的设置。

这些参数可以根据实际情况来调整,以满足数据集和模型训练的需求。例如,可以根据数据集大小、模型结构等来设置 batch_sizenum_workers 等参数,以获得最佳的训练性能。

二、定义神经网络

我们可以用两种网络来对比其分类能力,一种是普通Net网络,另外用LeNet卷积网络来对比:

普通神经网络:

import torch.nn as nn
import torch
input_size = 3072 #3*32*32
hidden_size1 = 500 #第一次隐藏层个数
hidden_size2 = 200 #第二次隐藏层个数
num_classes = 10 #分类个数
num_epochs = 5 #批次次数
batch_size = 100  #批次大小
learning_rate =1e-3
#定义两层神经网络
class Net(nn.Module):
    def __init__(self,input_size,hidden_size1,hidden_size2,num_classes):
        super(Net,self).__init__()
        self.layer1 = nn.Linear(input_size,hidden_size1)#输入
        self.layer2 = nn.Linear(hidden_size1,hidden_size2)#两层隐藏层计算
        self.layer3 = nn.Linear(hidden_size2,num_classes)#输出
        
    def forward(self,x):
        out = torch.relu(self.layer1(x)) #隐藏层1
        out = torch.relu(self.layer2(out)) #隐藏层2
        out = self.layer3(out)
        return out

net =Net(input_size,hidden_size1,hidden_size2,num_classes)

 

Net(
  (layer1): Linear(in_features=3072, out_features=500, bias=True)
  (layer2): Linear(in_features=500, out_features=200, bias=True)
  (layer3): Linear(in_features=200, out_features=10, bias=True)
)

定义损失函数和优化器

from torch import optim
criterion = nn.CrossEntropyLoss() # 交叉熵损失函数
optimizer = optim.SGD(net.parameters(), lr=learning_rate)

 训练网络-Net

神经网络的训练流程基本都是类似的:

  • 输入数据
  • 前向传播+反向传播
  • 更新参数

CPU训练

Pytorch是默认在 CPU 上运行:

batch_size = 1000  #批次大小
for epoch in range(num_epochs):
    print('current epoch + %d' % epoch)
    running_loss = 0.0
    for i ,(images,labels) in enumerate(train_loader,0):
        images=images.view(images.size(0),-1)
        labels = torch.tensor(labels, dtype=torch.long)
        # 梯度清零
        optimizer.zero_grad()
        outputs = net(images) #将数据集传入网络做前向计算
        loss = criterion(outputs ,labels)
        loss.backward()
        optimizer.step()
        
        running_loss += loss.item()
        if i % 1000 == 0: # 每1000个batch打印一下训练状态
            print('[%d, %5d] loss: %.3f' \
                  % (epoch+1, i+1, running_loss))
            running_loss = 0.0
print('Finished Training')

 

current epoch + 0
[1,     0] loss: 2.149
current epoch + 1
[2,     0] loss: 2.025
current epoch + 2
[3,     0] loss: 1.987
current epoch + 3
[4,     0] loss: 2.020
current epoch + 4
[5,     0] loss: 1.970
Finished Training

模型准确率

#prediction
total = 0
correct =0 
acc_list_test = []
for images,labels in test_loader:
    images=images.view(images.size(0),-1)
    outputs = net(images) #将数据集传入网络做前向计算
    
    _,predicts = torch.max(outputs.data,1)
    total += labels.size(0)
    correct += (predicts == labels).sum()
    acc_list_test.append(100 * correct / total)
    
print('Accuracy = %.2f'%(100 * correct / total))
plt.plot(acc_list_test)
plt.xlabel('Epoch')
plt.ylabel('Accuracy On TestSet')
plt.show()

准确率只有33.06%,实际上一张图片直接给我们人来猜的话有10%概率猜对,所以这样看来神经网络还是可以有所提升的,那我们再试试卷积网络看看。

GPU训练

使用GPU训练只需要将torch的驱动device切换为GPU,且将显式地将张量(Tensors)和模型(Models)移动到 GPU 上就可:

batch_size = 1000  #批次大小
net_gpu =Net(input_size,hidden_size1,hidden_size2,num_classes)
net_gpu.cuda()
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

for epoch in range(num_epochs):
    print('current epoch + %d' % epoch)
    running_loss = 0.0
    for i ,(images,labels) in enumerate(train_loader,0):
        images = images.to(device)
        labels = labels.to(device)
        
        images=images.view(images.size(0),-1)
        labels = torch.tensor(labels, dtype=torch.long)
        # 梯度清零
        optimizer.zero_grad()
        outputs = net_gpu(images) #将数据集传入网络做前向计算
        loss = criterion(outputs ,labels)
        loss.backward()
        optimizer.step()
        
        running_loss += loss.item()
        if i % 1000 == 0: # 每2000个batch打印一下训练状态
            print('[%d, %5d] loss: %.3f' \
                  % (epoch+1, i, running_loss ))
            running_loss = 0.0
print('Finished Training')

效果是一样的,这里不再继续复写。

训练网络-LeNet

我们再来训练一个卷积网络再来看看效果,可能这里讲述卷积网络有点跳跃,之后我会详细讲述卷积神经网络的全部内容,这里大家只需要知道每个网络的性能是不同的。

import torch.nn as nn
import torch.nn.functional as F
input_size = 3072 #3*32*32
hidden_size1 = 500 #第一次隐藏层个数
hidden_size2 = 200 #第二次隐藏层个数
num_classes = 10 #分类个数
num_epochs = 5 #批次次数
batch_size = 100  #批次大小
learning_rate =1e-3

class LeNet(nn.Module):
    def __init__(self,input_size,hidden_size1,hidden_size2,num_classes):
        super(LeNet, self).__init__()
         # 卷积层 '1'表示输入图片为单通道, '6'表示输出通道数,'5'表示卷积核为5*5
        self.conv1=nn.Conv2d(3,6,5)
        # 卷积层
        self.conv2 = nn.Conv2d(6, 16, 5) 
        # 仿射层/全连接层,y = Wx + b
        self.fc1   = nn.Linear(input_size, hidden_size1) 
        self.fc2   = nn.Linear(hidden_size1, hidden_size2)
        self.fc3   = nn.Linear(hidden_size2, num_classes)
        
    def forward(self,x):
        # 卷积 -> 激活 -> 池化 
        x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2))
        x = F.max_pool2d(F.relu(self.conv2(x)), 2)   
        # reshape,‘-1’表示自适应
        x = x.view(x.size()[0], -1)    
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)        
        return x
net =LeNet(input_size,hidden_size1,hidden_size2,num_classes)

 

LeNet(
  (conv1): Conv2d(3, 6, kernel_size=(5, 5), stride=(1, 1))
  (conv2): Conv2d(6, 16, kernel_size=(5, 5), stride=(1, 1))
  (fc1): Linear(in_features=3072, out_features=500, bias=True)
  (fc2): Linear(in_features=500, out_features=200, bias=True)
  (fc3): Linear(in_features=200, out_features=10, bias=True)
)

以上为整个卷积网络的结构,接下来直接训练看看效果:

batch_size = 1000  #批次大小
for epoch in range(num_epochs):
    print('current epoch + %d' % epoch)
    running_loss = 0.0
    for i ,(images,labels) in enumerate(train_loader,0):
        #images=images.view(images.size(0),-1) 单通道不需要
        labels = torch.tensor(labels, dtype=torch.long)
        # 梯度清零
        optimizer.zero_grad()
        outputs = net(images) #将数据集传入网络做前向计算
        loss = criterion(outputs ,labels)
        loss.backward()
        optimizer.step()
        
        running_loss += loss.item()
        if i % 1000 == 0: # 每1000个batch打印一下训练状态
            print('[%d, %5d] loss: %.3f' \
                  % (epoch+1, i, running_loss ))
            running_loss = 0.0
print('Finished Training')

 

[1,     0] loss: 2.310
current epoch + 1
[2,     0] loss: 2.301
current epoch + 2
[3,     0] loss: 2.305
current epoch + 3
[4,     0] loss: 2.303
current epoch + 4
[5,     0] loss: 2.304
Finished Training

模型准确率

#prediction
total = 0
correct =0 
acc_list_test = []
for images,labels in test_loader:
    #images=images.view(images.size(0),-1)
    outputs = net(images) #将数据集传入网络做前向计算
    
    _,predicts = torch.max(outputs,1)
    total += labels.size(0)
    correct += (predicts == labels).sum()
    acc_list_test.append(100 * correct / total)
    
print('Accuracy = %.2f'%(100 * correct / total))
plt.plot(acc_list_test)
plt.xlabel('Epoch')
plt.ylabel('Accuracy On TestSet')
plt.show()

 

 比普通的神经网络要好很多。

点关注,防走丢,如有纰漏之处,请留言指教,非常感谢

以上就是本期全部内容。我是fanstuck ,有问题大家随时留言讨论 ,我们下期见。


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

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

相关文章

9月15日、9月18日上课内容 Zookeeper集群 + Kafka集群

Zookeeper 本章结构 Zookeeper 概述 Zookeeper 定义 *(了解) Zookeeper是一个开源的分布式的,为分布式框架提供协调服务的Apache项目。 Zookeeper 工作机制 *****(非常重要,需要掌握) Zookeeper从设计模式…

用低代码开发工具高效构建企业门户

企业信息门户EIP是指将各种应用系统、数据资源和互联网资源统一集中,根据每个用户使用特点和角色的不同,形成个性化的应用界面,并通过对事件和消息的处理、传输把用户有机地联系在一起。 企业随着业务的发展,运作的复杂度也在不断…

第三十二章 Objects

[toc] 第三十二章 Objects Objects 对象类简介 IRIS 通过以下对象类提供对象技术: %Library.RegisteredObject、 %Library.Persistent %Library.SerialObject。 下图展示了这些类之间的继承关系,以及它们的一些参数和方法。 %Library 包的类名称可以…

Vite + Vue3 使用cdn引入依赖 vite cdn vue3 cdn vite引入cdn

Vite Vue3 使用cdn引入依赖 vite cdn vue3 cdn vite引入cdn 1、安装插件2、在 vite.config.js 引用3、main.js4、打包测试 1、安装插件 npm install element-plus --save2、在 vite.config.js 引用 import { defineConfig } from vite import vue from vitejs/plugin-vue// …

用开源代码构建机器人需要考虑的问题

导读或许你正在考虑(或正在进行)将机器人使用开源软件推向市场。这个机器人是基于 linux 构建的。也许你正在使用机器人操作系统(ROS)或任务导向操作套件(MOOS),或者是另外一个可以帮助你简化开…

007 数据结构_堆——“C”

前言 本文将会向您介绍关于堆Heap的实现 具体步骤 tips:本文具体步骤的顺序并不是源代码的顺序 typedef int HPDataType; typedef struct Heap {HPDataType* _a;int _size;int _capacity; }Heap;初始化 void HeapCreate(Heap* hp, HPDataType* a, int n) {hp-&…

AT32F407裸机工程创建

1、建立工程文件夹 2、找到AT提供DEMO例程,我们需要复制相关的内核文件出来,到我们创建的这个文件夹 1)将库文件拿过来 2)内核文件 3)启动文件 我把F407相关的内核文件都复制过来,然后具体看自己使用哪个型号,工程自己添加对应的文…

避雷!这9本期刊已被剔除!9月SCI/SSCI目录已更新(附2023年WOS历次更新全目录)

2023年9月20日,科睿唯安更新了Web of Science核心期刊目录。 此次更新后SCIE期刊目录共包含9490本期刊,SSCI期刊目录共包含3552本期刊。此次SCIE & SSCI期刊目录更新,与上次更新(2023年8月)相比,共有9本…

共育电商人才,引领行业发展丨知了汇智与协作时代达成战略合作

随着新一轮科技革命和产业革命的深入发展,数字经济正在成为重塑全球经济结构、改变全球竞争格局的关键力量,数字经济与实体经济的深度融合,也将是未来经济发展的重要动力。数字经济的发展正在催生电子商务模式不断创新,新业态下企…

安防监控系统/视频云存储/视频监控平台EasyCVR无法级联上级平台,该如何解决?

安防视频监控系统EasyCVR平台能在复杂的网络环境中,将分散的各类视频资源进行统一汇聚、整合、集中管理,在视频监控播放上,TSINGSEE青犀视频安防监控汇聚平台可支持1、4、9、16个画面窗口播放,可同时播放多路视频流,也…

《动手学深度学习》(pytorch版+mxnet版)2023最新

我又来推书了,这次分享的这本书可是重量级,目前已经被55个国家300所大学用于教学,同时受到了学术界与工业界的强烈推荐。 这本书就是李沐、阿斯顿张、立顿、斯莫拉四位大佬联合编写的《动手学深度学习》。本书面向中文读者,能运行…

第二十四章 原理篇:DBB

上班真的好累哦! 理论上应该从RepVGG开始写重参化的,而且上星期就打算写来着! 但是上班真的好累哦完全提不起精神在周末打字看论文! 参考教程: https://arxiv.org/pdf/2103.13425.pdf https://github.com/DingXiaoH/D…

自己实现一个简单的vhost-net

框架 vhost在网络中的位置如图&#xff1a; 要学习具体的框架可以看我之前的文章vhost-net--------深入了解Virtio-networking和vhost-net 接下来&#xff0c;我们自己实现一个vhost. vhost-net代码 在代码中写了详细注释&#xff0c;就直接上代码了 #include <stdio.h…

期权是什么?一分钟带你玩转期权策略!

很多人问我期权是什么&#xff0c;这个问题怎么回答呢&#xff1f;首先期权是一种交易模式&#xff0c;如同股票期货一样&#xff0c;但它又不同于股票和期货&#xff0c;因为它有自己的交易规则和特性&#xff0c;期权更多是一种工具&#xff0c;可以做空大盘对冲下跌风险&…

0018Java程序设计-springboot智慧环卫养管作业平台

文章目录 摘 要目 录系统设计开发环境 摘 要 本智慧环卫养管作业平台就是建立在充分利用现在完善科技技术这个理念基础之上&#xff0c;并使用IT技术进行对环卫养管作业的管理&#xff0c;从而保证环卫养管作业能够高效的进行&#xff0c;可以实现环卫养管作业的在线管理&…

健康云HIS系统源码,满足基层医疗机构业务需求,提供挂号支持、病患问诊、电子病历、开药发药、会员管理、统计查询、医生站和护士站等功能

云his系统源码 二级医院HIS系统全套源代码 自主研发&#xff0c;自主版权 一款满足基层医疗机构各类业务需要的健康云HIS系统。该系统能帮助基层医疗机构完成日常各类业务&#xff0c;提供病患挂号支持、病患问诊、电子病历、开药发药、会员管理、统计查询、医生站和护士站等一…

wabp.m 代码注释(便于算法快速理解)

算法效果: 波峰和起点检测效果: function [r,pk] = wabp(Araw, Offset,Scale, Fs) % r = wabp(Araw,Offset,Scale, Fs); % Input: Araw (125Hz sampled) waveform in wfdb-MIT format, % Offset, Scale % Araw = 血压波形 % Offset=偏移(信号减去或者加上偏移恢复成…

启山智软/O2O商城

文章目录 启山智软介绍一、O2O商业模式是什么二、启山智软O2O商城管理系统1.O2O商城系统2.多种商业形态的O2O商城系统1、类似蜜雪冰城的合作加盟模式2、类似优衣库的连锁直营模式3、类似京东到家的同城/本地服务平台 O2O商城开发具备的特色功能&#xff1a;部分源码分享 启山智…

MTBF、MTTR、MTTA 和 MTTF

了解一些最常见的事件指标 在当今永不停机的世界中&#xff0c;中断和技术事件比以往任何时候都更加重要。故障和停机期间会带来现实后果&#xff0c;错过截止时间、付款逾期、项目延迟。 这就是为什么公司必须量化和跟踪有关正常运行时间、停机期间以及团队解决问题的速度和…

改变latex单张页面宽度的正确做法

https://tex.stackexchange.com/questions/6834/change-paper-size-in-mid-document#comment115838_6838 首先注意&#xff0c;网上所有有关newgeometry的说明都是不可行的&#xff0c;因为 画红圈的地方大家自行阅读&#xff0c;这就是原因。 其次&#xff0c;更改页面宽度的…