笔记:VGGnet的实现

news2024/9/23 3:31:41

本文为B站UP 霹雳吧啦Wz 图片分类课程学习笔记,用于记录学习历程和个人复习

程序共分为三部分:model,train,predict。model.py用于存放模型,train.py用于存放训练时的程序,predict.py用于存放预测的程序,vgg16Net.pth为训练时val_accurate最高的模型参数,class_indices.json为类别索引映射。

注意:如要使用本文进行训练,需先按照 3.1 AlexNet网络结构详解与花分类数据集下载  在指定位置放好图片数据集方可进行训练。

个人感觉比较好的学习办法是先听一遍up的讲解,再看代码,哪段代码不会就查哪里,把所有的代码都搞清楚再自己改改代码。

 model.py

总体代码
import torch.nn as nn
import torch

# official pretrain weights
model_urls = {
    'vgg11': 'https://download.pytorch.org/models/vgg11-bbd30ac9.pth',
    'vgg13': 'https://download.pytorch.org/models/vgg13-c768596a.pth',
    'vgg16': 'https://download.pytorch.org/models/vgg16-397923af.pth',
    'vgg19': 'https://download.pytorch.org/models/vgg19-dcbb9e9d.pth'
}


class VGG(nn.Module):
    def __init__(self, features, num_classes=1000, init_weights=False):
        super(VGG, self).__init__()
        self.features = features
        self.classifier = nn.Sequential(
            nn.Linear(512*7*7, 4096),
            nn.ReLU(True),
            nn.Dropout(p=0.5),
            nn.Linear(4096, 4096),
            nn.ReLU(True),
            nn.Dropout(p=0.5),
            nn.Linear(4096, num_classes)
        )
        if init_weights:
            self._initialize_weights()

    def forward(self, x):
        # N x 3 x 224 x 224
        x = self.features(x)
        # N x 512 x 7 x 7
        x = torch.flatten(x, start_dim=1)
        # N x 512*7*7
        x = self.classifier(x)
        return x

    def _initialize_weights(self):
        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                # nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
                nn.init.xavier_uniform_(m.weight)
                if m.bias is not None: #查看是否有偏置项
                    nn.init.constant_(m.bias, 0)
            elif isinstance(m, nn.Linear):
                nn.init.xavier_uniform_(m.weight)
                # nn.init.normal_(m.weight, 0, 0.01)
                nn.init.constant_(m.bias, 0)


def make_features(cfg: list):
    layers = []
    in_channels = 3
    for v in cfg:
        if v == "M":
            layers += [nn.MaxPool2d(kernel_size=2, stride=2)]
        else:
            conv2d = nn.Conv2d(in_channels, v, kernel_size=3, padding=1)
            layers += [conv2d, nn.ReLU(True)]
            in_channels = v
    return nn.Sequential(*layers)


cfgs = {
    'vgg11': [64, 'M', 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'],
    'vgg13': [64, 64, 'M', 128, 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'],
    'vgg16': [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 'M', 512, 512, 512, 'M', 512, 512, 512, 'M'],
    'vgg19': [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 256, 'M', 512, 512, 512, 512, 'M', 512, 512, 512, 512, 'M'],
}


def vgg(model_name="vgg16", **kwargs):
    assert model_name in cfgs, "Warning: model number {} not in cfgs dict!".format(model_name)
    cfg = cfgs[model_name]

    model = VGG(make_features(cfg), **kwargs)
    return model

 train.py

数据预处理
import os
import sys
import json

import torch
import torch.nn as nn
from torchvision import transforms, datasets
import torch.optim as optim
from tqdm import tqdm

from model import vgg

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
print("using {} device.".format(device))

data_transform = {
    "train": transforms.Compose([transforms.RandomResizedCrop(224),
                                    transforms.RandomHorizontalFlip(),
                                    transforms.ToTensor(),
                                    transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))]),
    "val": transforms.Compose([transforms.Resize((224, 224)),
                                transforms.ToTensor(),
                                transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])}

这段代码定义了图像数据的预处理步骤,这些步骤在训练和验证过程中对图像进行处理。

data_transform 字典

这个字典包含两个键:"train""val",分别对应训练和验证数据的预处理步骤。

训练数据的预处理 ("train")

transforms.Compose([

        transforms.RandomResizedCrop(224),         transforms.RandomHorizontalFlip(),

        transforms.ToTensor(),

        transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)) ])

  • transforms.RandomResizedCrop(224): 这个函数随机裁剪图像,生成一个大小为 224x224 的图像区域。这有助于模型学习到图像的不同部分,增加模型的泛化能力。
  • transforms.RandomHorizontalFlip(): 这个函数随机地水平翻转图像。这同样有助于增加模型的泛化能力,因为图像的方向在实际应用中可能会变化。
  • transforms.ToTensor(): 将 PIL 图像或 NumPy ndarray 转换为 FloatTensor,并将图像的像素值从 [0, 255] 归一化到 [0.0, 1.0]。
  • transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)): 将图像的每个通道的像素值进行标准化,使其均值为 0.5,标准差为 0.5。这有助于模型训练时的数值稳定性。

验证数据的预处理 ("val")

transforms.Compose([

        transforms.Resize((224, 224)),

        transforms.ToTensor(),

        transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)) ])

  • transforms.Resize((224, 224)): 将图像调整到固定的大小 224x224。这确保了所有验证图像都具有相同的尺寸,这对于模型的一致性输入是必要的。
  • transforms.ToTensor(): 与训练数据相同,将图像转换为 FloatTensor,并归一化像素值。
  • transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)): 与训练数据相同,进行像素值的标准化。
  • 为什么使用这些预处理步骤?
  1. 随机性:通过随机裁剪和随机翻转,模型能够学习到图像的不同变体,增强其对新数据的适应能力。
  2. 标准化:将图像像素值归一化到 [0, 1] 或 [0.5, 0.5] 的范围内,有助于模型更快地收敛,并减少训练过程中的数值不稳定性。
  3. 一致性:确保训练和验证图像具有相同的尺寸和数值范围,有助于模型在不同阶段的一致性学习。

这些预处理步骤是图像处理和深度学习中常见的实践,有助于提高模型的性能和泛化能力。

图片路径准备
data_root = os.path.abspath(os.path.join(os.getcwd(), "../.."))  # get data root path
image_path = os.path.join(data_root, "data_set", "flower_data")  # flower data set path
assert os.path.exists(image_path), "{} path does not exist.".format(image_path)

这段代码用于设置数据集的根路径,并确保该路径存在。

  1. 获取当前工作目录

    data_root = os.path.abspath(os.path.join(os.getcwd(), "../.."))

    • os.getcwd() 获取当前工作目录的路径。
    • os.path.join(os.getcwd(), "../..") 将当前工作目录向上移动两个目录层级。这通常用于从当前脚本所在的目录跳转到项目的根目录。
    • os.path.abspath() 将相对路径转换为绝对路径,确保路径的准确性和可移植性。
  2. 设置数据集路径

    image_path = os.path.join(data_root, "data_set", "flower_data")

    • os.path.join(data_root, "data_set", "flower_data") 将根目录与子目录 "data_set" 和 "flower_data" 连接起来,形成完整的数据集路径。这里假设数据集存储在项目的 "data_set" 文件夹下的 "flower_data" 文件夹中。
  3.  检查路径是否存在

    assert os.path.exists(image_path),

    "{} path does not exist.".format(image_path)

    • os.path.exists(image_path) 检查 image_path 指定的路径是否存在。
    • assert 是一个断言语句,用于确保某个条件为真。如果条件为假,则抛出异常。
    • 如果 image_path 指定的路径不存在,将抛出一个 AssertionError 异常,并显示错误消息 "{path} path does not exist.",其中 {path} 会被替换为实际的路径。 

代码的作用:

  • 确定根目录:通过向上移动两个目录层级,确保脚本可以从项目的任何子目录运行,而不仅仅是项目根目录。
  • 构建数据集路径:通过连接根目录和数据集子目录,构建出完整的数据集路径。
  • 确保路径有效:通过断言检查,确保数据集路径存在,避免在后续操作中因路径错误而导致程序崩溃。

这种路径设置方式常用于项目结构较为复杂的场景,其中数据集、模型和其他资源可能分散在不同的目录中。通过这种方式,可以确保脚本在任何位置运行时都能正确地找到所需的资源。

加载图片
train_dataset = datasets.ImageFolder(root=os.path.join(image_path, "train"),
                                        transform=data_transform["train"])
train_num = len(train_dataset)

validate_dataset = datasets.ImageFolder(root=os.path.join(image_path, "val"),
                                        transform=data_transform["val"])
val_num = len(validate_dataset)
  • datasets.ImageFolder:这是 PyTorch 提供的一个类,用于从文件夹中加载图像数据。每个子文件夹代表一个类别,文件夹名称是类别的名称。
  • root=os.path.join(image_path, "train"):指定数据集的根目录。这里使用 os.path.join 将之前定义的 image_path 和子目录 "train" 连接起来,形成完整的训练数据集路径。
  • transform=data_transform["train"]:应用之前定义的训练数据预处理步骤。这些步骤包括随机裁剪、随机水平翻转、转换为张量以及归一化。
保存类别索引映射
flower_list = train_dataset.class_to_idx
cla_dict = dict((val, key) for key, val in flower_list.items())
json_str = json.dumps(cla_dict, indent=4)
with open('class_indices.json', 'w') as json_file:
    json_file.write(json_str)

这段代码的作用是将训练数据集中的类别索引映射保存到一个 JSON 文件中。

  1. 获取类别索引映射

    flower_list = train_dataset.class_to_idx

    train_dataset.class_to_idx 是一个字典,其中键是类别的名称(如 'daisy'),值是该类别在数据集中的索引(如 0)。这个映射是由 ImageFolder 在加载数据集时自动生成的。

  2. 反转类别索引映射

    cla_dict = dict((val, key) for key, val in flower_list.items())

    这行代码将 flower_list 字典的键和值对调,生成一个新的字典 cla_dict。在这个新字典中,索引(如 0)是键,类别名称(如 'daisy')是值。这样做的目的是方便在模型预测时将预测的索引转换回类别名称。
  3. 将字典转换为 JSON 字符串

    json_str = json.dumps(cla_dict, indent=4)

    json.dumps() 函数将 Python 字典转换为 JSON 格式的字符串。indent=4 参数使生成的 JSON 字符串具有可读性,即每级缩进 4 个空格。
  4. 将 JSON 字符串写入文件

    with open('class_indices.json', 'w') as json_file: json_file.write(json_str)

    使用 with 语句打开文件 'class_indices.json' 进行写操作。'w' 模式表示如果文件已存在,则会被覆盖;如果文件不存在,则会被创建。json_file.write(json_str) 将 JSON 字符串写入文件。

代码的作用:

  • 保存类别索引映射:通过将类别名称和索引的映射保存到文件,可以在模型训练和预测时方便地进行类别名称和索引之间的转换。
  • 便于模型预测:在模型预测时,通常需要将预测的索引转换回类别名称,以便更容易地理解预测结果。
设置批量大小
batch_size = 32
nw = min([os.cpu_count(), batch_size if batch_size > 1 else 0, 8])  # number of workers
print('Using {} dataloader workers every process'.format(nw))

 [os.cpu_count(), batch_size if batch_size > 1 else 0, 8]

这个是一个列表,由三部分组成: 

  • os.cpu_count() 返回当前系统可用的 CPU 核心数。
  • batch_size if batch_size > 1 else 0 检查批量大小是否大于 1,如果是,则使用批量大小作为工作进程数;如果不是(例如批量大小为 1),则不使用额外的工作进程。
  • min([os.cpu_count(), batch_size if batch_size > 1 else 0, 8]) 从 CPU 核心数、调整后的工作进程数(基于批量大小)和固定值 8 中选择最小的一个,作为最终的工作进程数。这样做是为了避免使用过多的资源,尤其是在 CPU 核心数较少或批量大小较小的情况下。
  • 限制工作进程数的最大值为 8 是一个常见的做法,以确保不会因过多的并行进程而过度消耗系统资源。
 创建数据加载器
train_loader = torch.utils.data.DataLoader(train_dataset,
                                            batch_size=batch_size, shuffle=True,
                                            num_workers=nw)

validate_loader = torch.utils.data.DataLoader(validate_dataset,
                                                batch_size=batch_size, shuffle=False,
                                                num_workers=nw)
print("using {} images for training, {} images for validation.".format(train_num,
                                                                        val_num))

train_loader = torch.utils.data.DataLoader(train_dataset,

        batch_size=batch_size, shuffle=True, num_workers=nw)

  • torch.utils.data.DataLoader:这是 PyTorch 提供的一个类,用于封装数据集并提供批量加载和多进程加载功能。
  • train_dataset:这是之前创建的训练数据集对象。
  • batch_size=batch_size:设置每个批次的样本数量。这里使用之前定义的 batch_size 变量,其值为 32。
  • shuffle=True:在每个 epoch 开始时,是否对数据进行随机打乱。这有助于模型训练时的泛化能力,避免模型对数据的特定顺序产生依赖。
  • num_workers=nw:设置用于数据加载的工作进程数。这里使用之前计算的 nw 变量,其值是 os.cpu_count()batch_size 和 8 中的最小值。这有助于提高数据加载的效率。
准备训练参数
model_name = "vgg16"
net = vgg(model_name=model_name, num_classes=5, init_weights=True)
net.to(device)
loss_function = nn.CrossEntropyLoss()
optimizer = optim.Adam(net.parameters(), lr=0.0001)
epochs = 6
best_acc = 0.5
save_path = './{}Net.pth'.format(model_name)
train_steps = len(train_loader)

save_path = './{}Net.pth'.format(model_name)

 这行代码是用于定义模型权重文件的保存路径。

  1. ./:这是一个相对路径,表示当前工作目录。这意味着文件将被保存在运行脚本的当前目录中。

  2. {}Net.pth:这是一个格式化字符串,花括号 {} 是一个占位符,用于插入变量值。

  3. format(model_name):这是 str.format() 方法,用于将 model_name 变量的值替换到格式化字符串中的占位符 {} 位置。model_name 变量在之前的代码中被设置为 "vgg16"

  4. Net.pth:这是一个文件名后缀,通常用于表示 PyTorch 模型权重文件。.pth 是一个常用的文件扩展名,用于区分 PyTorch 模型文件。

开始训练
for epoch in range(epochs):
    # train
    net.train() # 设置为训练模式
    running_loss = 0.0
    train_bar = tqdm(train_loader, file=sys.stdout)
    for step, data in enumerate(train_bar):
        images, labels = data
        optimizer.zero_grad()
        outputs = net(images.to(device))
        loss = loss_function(outputs, labels.to(device))
        loss.backward()
        optimizer.step()

        # print statistics
        running_loss += loss.item()

        train_bar.desc = "train epoch[{}/{}] loss:{:.3f}".format(epoch + 1, epochs, loss)

    # validate
    net.eval()
    acc = 0.0  # accumulate accurate number / epoch
    with torch.no_grad():
        val_bar = tqdm(validate_loader, file=sys.stdout)
        for val_data in val_bar:
            val_images, val_labels = val_data
            outputs = net(val_images.to(device))
            predict_y = torch.max(outputs, dim=1)[1]
            acc += torch.eq(predict_y, val_labels.to(device)).sum().item()

    val_accurate = acc / val_num
    print('[epoch %d] train_loss: %.3f  val_accuracy: %.3f' %
            (epoch + 1, running_loss / train_steps, val_accurate))

    if val_accurate > best_acc:
        best_acc = val_accurate
        torch.save(net.state_dict(), save_path)

print('Finished Training')

使用 tqdm 显示进度

train_bar = tqdm(train_loader, file=sys.stdout)

  • tqdm 是一个进度条库,用于显示训练过程中的进度。
  • train_loader 是数据加载器,负责按批次提供训练数据。
  • file=sys.stdout 指定进度条的输出位置,这里是标准输出(即控制台)。

内部循环:处理每个批次的数据

for step, data in enumerate(train_bar):

  • enumerate(train_bar) 遍历 train_barstep 是批次的索引,data 是当前批次的数据。
  • 每个 data 包含一对图像和标签,通常是通过 train_loader 提供的。

数据处理

images, labels = data

optimizer.zero_grad()

outputs = net(images.to(device))

loss = loss_function(outputs, labels.to(device))

loss.backward()

optimizer.step()

  • images, labels = data:从 data 中解包出图像和标签。
  • optimizer.zero_grad():清除之前的梯度,为新的反向传播准备。这是每次迭代开始时必须执行的步骤。
  • outputs = net(images.to(device)):将图像数据移动到指定的设备(如 GPU),并通过模型前向传播得到输出。
  • loss = loss_function(outputs, labels.to(device)):计算输出和标签之间的损失。这里使用的是交叉熵损失函数 loss_function
  • loss.backward():反向传播损失,计算模型参数的梯度。
  • optimizer.step():根据计算出的梯度更新模型的权重。

更新运行损失并显示进度

running_loss += loss.item()

train_bar.desc = "train epoch[{}/{}] loss:{:.3f}".format(epoch + 1, epochs, loss)

  • running_loss += loss.item():将当前批次的损失添加到运行损失中。
  • train_bar.desc:更新进度条的描述,显示当前 epoch、总 epoch 数和当前批次的损失。

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

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

相关文章

从技术博客到个人 IP 矩阵:全面攻略与实战示例

文章目录 摘要引言创建博客选择平台设计和布局 内容规划明确目标受众设定内容方向制定发布计划 SEO 优化关键词研究内链和外链元标签优化 社交媒体推广选择社交平台制定推广策略 可运行的 Demo 代码模块QA 环节问:如何增加博客的曝光度?问:如…

使用 ChatGPT 检测媒体偏见的潜力和局限性

概述 随着数字时代的到来,信息瞬间传遍全球,但其中也不乏各种偏见。媒体偏见",即对某些观点的选择性报道,会影响人们对某一事件或问题的看法,并对公众舆论产生重大影响。事实上,许多人都认为主要媒体…

国内本地化OCSP服务的SSL证书:提升安全与效率的新选择

在数字化时代,网络安全成为企业运营和用户体验的重要基石。HTTPS(Hypertext Transfer Protocol Secure)作为一种安全的网络协议,通过SSL(Secure Sockets Layer)加密技术,保障了数据传输的机密性…

网络协议二 : 使用Cisco Packet Traceer工具模拟网络环境,集线器,网桥,交换机,路由器,MAC,IP,同一网段,子网掩码,子网划分

1. 安装 Cisco Packet Tracer baidu 网盘地址,感谢大神分享 安装,破解,中文化,都有说明,建议使用7.x的那个版本,感觉比8.x的翻译要完整一点 https://pan.baidu.com/s/18iWBOfhJJRhqgQqdNQcfMQ?pwddcch#…

【考研数学】概率论中集合间的运算图示

今天要给大家分享的笔记是:《概率论中的4种“集”:交集、并集、差集、补集》:

修复msvcp120.dll丢失的问题的几种简单方法,msvcp120.dll是什么

在使用电脑时,你可能会遭遇一个提示称“msvcp120.dll丢失”的错误信息。这个问题比较普遍,主要是因为你的系统中缺失了某个特定的动态链接库(DLL)文件。msvcp120.dll是由 Microsoft Visual C 可再发行包提供的关键文件&#xff0c…

【C++】C++11新增语法(右值引用、完美转法)

文章目录 1.C11新增常用语法1.1 统一的列表初始化1.2 initializer_list初始化1.3 声明相关1.4 继承与多态相关 2. 右值引用与移动语义2.1 左值引用与右值引用2.2 右值引用与移动语义的使用场景2.3 右值引用引用左值(move) 3. 完美转发4. 新的类功能4.1 新增两个默认成员函数4.2…

测试开发面试题,助你拿高薪offer

进入金九银十,很多小伙伴有被动跳槽的打算,所以更新一些测试开发 面试题,希望能帮到大家。 一 请说一下HTTP 状态码 HTTP状态码大致分为5类: 常见的http状态码如下: 二 python中“” 和“ is ”的区别 is 和 都可以进行对象比…

bash: llamafactory-cli: command not found解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

探索翻译新世界:2024年超越期待的翻译应用推荐

现在社会因为交通、互联网的便利,不同国家之间的交流变得简单起来。无论是商务合作、学术研究还是日常沟通,准确、快速地跨越语言障碍都显得尤为重要。今天我来介绍一些和百度翻译类似的多用途的翻译工具。 1.福昕在线翻译 链接一下>>https://fa…

《LeetCode热题100》---<4.子串篇三道>

本篇博客讲解LeetCode热题100道子串篇中的三道题 第一道:和为 K 的子数组 第二道:滑动窗口最大值 第三道:最小覆盖子串 第一道:和为 K 的子数组(中等) 法一:暴力枚举 class Solution {public in…

C语言进阶 13. 文件

C语言进阶 13. 文件 文章目录 C语言进阶 13. 文件13.1. 格式化输入输出13.2. 文件输入输出13.3. 二进制文件13.4. 按位运算13.5. 移位运算13.6. 位运算例子13.7. 位段 13.1. 格式化输入输出 格式化输入输出: printf %[flags][width][.prec][hlL]type scanf %[flags]type %[fl…

yolo格式数据集之空中及地面拍摄道路病害检测7种数据集已划分好|可以直接使用|yolov5|v6|v7|v8|v9|v10通用

yolo格式数据集之空中及地面拍摄道路病害检测7种数据集已划分好|可以直接使用|yolov5|v6|v7|v8|v9|v10通用 本数据为空中及地面拍摄道路病害检测检测数据集,数据集数量如下: 总共有:33585张 训练集:6798张 验证集:3284张 测试集&a…

视频监控国标GB28181平台EasyGBS如何更换默认的SQLite数据库?

视频流媒体安防监控国标GB28181平台EasyGBS视频能力丰富,部署灵活,既能作为业务平台使用,也能作为安防监控视频能力层被业务管理平台调用。国标GB28181视频EasyGBS平台可提供流媒体接入、处理、转发等服务,支持内网、公网的安防视…

数据集相关类代码回顾理解 | np.mean\transforms.Normalize\transforms.Compose\xxx.transform

数据集相关类代码回顾理解 | StratifiedShuffleSplit\transforms.ToTensor\Counter 目录 np.mean transforms.Normalize transforms.Compose xxx.transform np.mean meanRGB[np.mean(x.numpy(),axis(1,2)) for x,_ in train_ds] 计算每个样本的(RGB&#xff0…

鸿蒙应用框架开发【JS注入与执行】 Web

JS注入与执行 介绍 本示例基于H5游戏,通过arkui的button实现对游戏实现基本控制,展示webview的JS注入与执行能力,及native应用与H5的通信能力。 效果预览 使用说明 1.设备连接热点,可访问互联网。 2.打开应用,通过…

【Java】如何避免超预期的高并发压力压垮系统?

一、问题解析 在互联网高可用架构设计中,限流是一种经典的高可用架构模式。因为某些原因,大量用户突然访问我们的系统时,或者有黑客恶意用DoS(Denial of Service,拒绝服务)方式攻击我们的系统时&#xff0…

oracle表、表空间使用空间

文章目录 一、Oracle查询表空间占用情况二、Oracle查询表占用的空间三、Oracle查询表空间使用情况四、Oracle查询每张表占用空间五、表空间大小 TOC 一、Oracle查询表空间占用情况 oracle日常工作中查看表占用空间大小是数据库管理中的基本操作: SELECT a.tablesp…

大龄程序员转型攻略:拥抱人工智能,开启新征程

前言 随着科技的飞速发展,人工智能浪潮席卷全球,相关岗位炙手可热。在这个背景下,许多大龄程序员开始思考如何转型,以适应时代的变化。结合自身编程基础,大龄程序员可以学习机器学习、深度学习算法,投身于…

MySQL 高性能索引使用策略

文章目录 前置知识表准备一. 不在索引列上使用任何操作二. 联合索引字段列全值匹配三. 最佳左前缀法则四. 范围条件放最后五. 覆盖索引使用六. 不等于导致索引失效七. is null/not null 影响八. like 查询的使用九. 字符类型加引号十. OR关键字前后索引问题十一. 利用索引来做排…