用于图像分类的预训练模型(PyTorch实现)

news2024/11/24 7:41:01

用于图像分类的预训练模型(PyTorch实现)

在本文中,我们将介绍一些使用 TorchVision 模块中存在的预训练网络的实践示例——用于图像分类的预训练模型。

1. 基于预训练模型进行图像分类

预训练模型是在 ImageNet 等大型基准数据集上训练的神经网络模型。深度学习社区从这些开源模型中受益匪浅。此外,预训练模型是计算机视觉研究快速发展的一个主要因素。其他研究人员和实践者可以使用这些最先进的模型,而不是从头开始重新发明一切。

下面给出了最先进模型如何随着时间的推移而改进的粗略时间表。我们仅包含 Torchvision 包中存在的那些模型。

在详细介绍如何使用预训练模型进行图像分类之前,让我们先看看可用的各种预训练模型是什么。我们将在这里讨论 AlexNet 和 ResNet101 作为两个主要示例。这两个网络都已在 ImageNet 数据集上进行了训练。

ImageNet 数据集拥有斯坦福大学维护的超过 1400 万张图像。它广泛用于各种与图像相关的深度学习项目。这些图像属于不同的类别或标签。 AlexNet 和 ResNet101 等预训练模型的目的是将图像作为输入并预测其类别。

这里的“预训练”一词意味着深度学习架构 AlexNet 和 ResNet101 已经在某些(巨大)数据集上进行了训练,因此带有最终的权重和偏差。

1.1. 模型预测过程

由于我们将重点关注如何使用预训练模型来预测输入的类别(标签),因此我们也讨论一下其中涉及的过程。此过程称为模型推理。整个过程由以下主要步骤组成。

  • 读取输入图像
  • 对图像进行变换。例如——调整大小、居中裁剪、标准化等。
  • 前向传递:使用预先训练的权重来找出输出向量。该输出向量中的每个元素描述了模型预测输入图像属于特定类别的置信度。
  • 根据获得的分数(步骤 3 中提到的输出向量的元素),显示预测。

1.2 使用TorchVision导入预训练模型

让我们从 torchvision 模块导入模型,看看我们可以使用的不同模型和架构。

from torchvision import models

print(dir(models))

仔细观察上面得到的输出。

['AlexNet', 'AlexNet_Weights', 'ConvNeXt', 'ConvNeXt_Base_Weights', 'ConvNeXt_Large_Weights', 'ConvNeXt_Small_Weights', 'ConvNeXt_Tiny_Weights', 'DenseNet', 'DenseNet121_Weights', 'DenseNet161_Weights', 'DenseNet169_Weights', 'DenseNet201_Weights', 'EfficientNet', 'EfficientNet_B0_Weights', 'EfficientNet_B1_Weights', 'EfficientNet_B2_Weights', 'EfficientNet_B3_Weights', 'EfficientNet_B4_Weights', 'EfficientNet_B5_Weights', 'EfficientNet_B6_Weights', 'EfficientNet_B7_Weights', 'EfficientNet_V2_L_Weights', 'EfficientNet_V2_M_Weights', 'EfficientNet_V2_S_Weights', 'GoogLeNet', 'GoogLeNetOutputs', 'GoogLeNet_Weights', 'Inception3', 'InceptionOutputs', 'Inception_V3_Weights', 'MNASNet', 'MNASNet0_5_Weights', 'MNASNet0_75_Weights', 'MNASNet1_0_Weights', 'MNASNet1_3_Weights', 'MobileNetV2', 'MobileNetV3', 'MobileNet_V2_Weights', 'MobileNet_V3_Large_Weights', 'MobileNet_V3_Small_Weights', 'RegNet', 'RegNet_X_16GF_Weights', 'RegNet_X_1_6GF_Weights', 'RegNet_X_32GF_Weights', 'RegNet_X_3_2GF_Weights', 'RegNet_X_400MF_Weights', 'RegNet_X_800MF_Weights', 'RegNet_X_8GF_Weights', 'RegNet_Y_128GF_Weights', 'RegNet_Y_16GF_Weights', 'RegNet_Y_1_6GF_Weights', 'RegNet_Y_32GF_Weights', 'RegNet_Y_3_2GF_Weights', 'RegNet_Y_400MF_Weights', 'RegNet_Y_800MF_Weights', 'RegNet_Y_8GF_Weights', 'ResNeXt101_32X8D_Weights', 'ResNeXt101_64X4D_Weights', 'ResNeXt50_32X4D_Weights', 'ResNet', 'ResNet101_Weights', 'ResNet152_Weights', 'ResNet18_Weights', 'ResNet34_Weights', 'ResNet50_Weights', 'ShuffleNetV2', 'ShuffleNet_V2_X0_5_Weights', 'ShuffleNet_V2_X1_0_Weights', 'ShuffleNet_V2_X1_5_Weights', 'ShuffleNet_V2_X2_0_Weights', 'SqueezeNet', 'SqueezeNet1_0_Weights', 'SqueezeNet1_1_Weights', 'SwinTransformer', 'Swin_B_Weights', 'Swin_S_Weights', 'Swin_T_Weights', 'VGG', 'VGG11_BN_Weights', 'VGG11_Weights', 'VGG13_BN_Weights', 'VGG13_Weights', 'VGG16_BN_Weights', 'VGG16_Weights', 'VGG19_BN_Weights', 'VGG19_Weights', 'ViT_B_16_Weights', 'ViT_B_32_Weights', 'ViT_H_14_Weights', 'ViT_L_16_Weights', 'ViT_L_32_Weights', 'VisionTransformer', 'Wide_ResNet101_2_Weights', 'Wide_ResNet50_2_Weights', '_GoogLeNetOutputs', '_InceptionOutputs', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', '_api', '_meta', '_utils', 'alexnet', 'convnext', 'convnext_base', 'convnext_large', 'convnext_small', 'convnext_tiny', 'densenet', 'densenet121', 'densenet161', 'densenet169', 'densenet201', 'detection', 'efficientnet', 'efficientnet_b0', 'efficientnet_b1', 'efficientnet_b2', 'efficientnet_b3', 'efficientnet_b4', 'efficientnet_b5', 'efficientnet_b6', 'efficientnet_b7', 'efficientnet_v2_l', 'efficientnet_v2_m', 'efficientnet_v2_s', 'get_weight', 'googlenet', 'inception', 'inception_v3', 'mnasnet', 'mnasnet0_5', 'mnasnet0_75', 'mnasnet1_0', 'mnasnet1_3', 'mobilenet', 'mobilenet_v2', 'mobilenet_v3_large', 'mobilenet_v3_small', 'mobilenetv2', 'mobilenetv3', 'optical_flow', 'quantization', 'regnet', 'regnet_x_16gf', 'regnet_x_1_6gf', 'regnet_x_32gf', 'regnet_x_3_2gf', 'regnet_x_400mf', 'regnet_x_800mf', 'regnet_x_8gf', 'regnet_y_128gf', 'regnet_y_16gf', 'regnet_y_1_6gf', 'regnet_y_32gf', 'regnet_y_3_2gf', 'regnet_y_400mf', 'regnet_y_800mf', 'regnet_y_8gf', 'resnet', 'resnet101', 'resnet152', 'resnet18', 'resnet34', 'resnet50', 'resnext101_32x8d', 'resnext101_64x4d', 'resnext50_32x4d', 'segmentation', 'shufflenet_v2_x0_5', 'shufflenet_v2_x1_0', 'shufflenet_v2_x1_5', 'shufflenet_v2_x2_0', 'shufflenetv2', 'squeezenet', 'squeezenet1_0', 'squeezenet1_1', 'swin_b', 'swin_s', 'swin_t', 'swin_transformer', 'vgg', 'vgg11', 'vgg11_bn', 'vgg13', 'vgg13_bn', 'vgg16', 'vgg16_bn', 'vgg19', 'vgg19_bn', 'video', 'vision_transformer', 'vit_b_16', 'vit_b_32', 'vit_h_14', 'vit_l_16', 'vit_l_32', 'wide_resnet101_2', 'wide_resnet50_2']

请注意,有一个名为 AlexNet 的条目,还有一个名为 alexnet。大写的名称指的是 Python 类 (AlexNet),而 alexnet 是一个便捷函数,它返回从 AlexNet 类实例化的模型。这些便利函数也可能具有不同的参数集。例如,densenet121、densenet161、densenet169、densenet201 都是 DenseNet 类的实例,但具有不同的层数——分别为 121,161,169 和 201。

1.3 基于AlexNet进行图像分类

我们首先从 AlexNet 开始。它是图像识别领域早期突破性网络之一。如果您有兴趣了解 AlexNet 的架构,可以查看我们关于了解 AlexNet 的文章。

Step 1: 加载预训练模型
alexnet = models.alexnet(pretrained=True)

# You will see a similar output as below
# Downloading: "https://download.pytorch.org/models/alexnet-owt-7be5be79.pth" to C:\Users\Administrator/.cache\torch\hub\checkpoints\alexnet-owt-7be5be79.pth

请注意,通常 PyTorch 模型的扩展名为 .pt 或 .pth。

下载权重后,我们就可以继续其他步骤。我们还可以查看网络架构的一些细节,如下所示。

print(alexnet)

运行结果如下:

AlexNet(
  (features): Sequential(
    (0): Conv2d(3, 64, kernel_size=(11, 11), stride=(4, 4), padding=(2, 2))
    (1): ReLU(inplace=True)
    (2): MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False)
    (3): Conv2d(64, 192, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))
    (4): ReLU(inplace=True)
    (5): MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False)
    (6): Conv2d(192, 384, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (7): ReLU(inplace=True)
    (8): Conv2d(384, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (9): ReLU(inplace=True)
    (10): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (11): ReLU(inplace=True)
    (12): MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False)
  )
  (avgpool): AdaptiveAvgPool2d(output_size=(6, 6))
  (classifier): Sequential(
    (0): Dropout(p=0.5, inplace=False)
    (1): Linear(in_features=9216, out_features=4096, bias=True)
    (2): ReLU(inplace=True)
    (3): Dropout(p=0.5, inplace=False)
    (4): Linear(in_features=4096, out_features=4096, bias=True)
    (5): ReLU(inplace=True)
    (6): Linear(in_features=4096, out_features=1000, bias=True)
  )
)
Step 2: 图像变换

一旦我们有了模型,下一步就是转换输入图像,使它们具有正确的形状和其他特征,例如平均值和标准差。这些值应与训练模型时使用的值类似。这确保网络能够产生有意义的答案。

from torchvision import transforms

transform = transforms.Compose([               # [1]
    transforms.Resize(256),                    # [2]
    transforms.CenterCrop(224),                # [3]
    transforms.ToTensor(),                     # [4]
    transforms.Normalize(                      # [5]
        mean=[0.485, 0.456, 0.406],            # [6]
        std=[0.229, 0.224, 0.225]              # [7]
    )
])

[1] 这里我们定义一个变量transform,它是对输入图像执行的所有图像变换的组合。
[2] 将图像大小调整为 256×256 像素。
[3] 将图像裁剪为中心周围的 224×224 像素。
[4] 将图像转换为 PyTorch Tensor 数据类型。
[5-7] 通过将图像的平均值和标准差设置为指定值来标准化图像。

Step 3: 输入图像及预处理
from PIL import Image

img = Image.open("dog.jpg")
img_t = transform(img)
batch_t = torch.unsqueeze(img_t, 0)

Step 4: 模型预测
alexnet.eval()
out = alexnet(batch_t)
print(out.shape)  # torch.Size([1, 1000])

我们仍然没有得到图像的类别(或标签)。为此,我们首先从包含所有 1000 个标签的列表的json文件中读取并存储标签。

with open('imagenet_classes.json', 'r') as f:
    classes = json.load(f)

现在,我们需要找到输出向量 out 中出现最大分数的索引。我们将使用这个索引来找出预测。

_, index = torch.max(out, 1)
index = index[0].item()

percentage = torch.nn.functional.softmax(out, dim=1)[0] * 100
print(classes[str(index)], percentage[index].item())

运行结果如下:

[‘Labrador retriever’] 42.46735763549805

该模型以 42.47% 的置信度预测该图像是拉布拉多猎犬。
但这看起来太低了。让我们看看模型认为图像属于哪些其他类别。

_, indices = torch.sort(out, descending=True)
for idx in indices[0][:5]:
    print(classes[str(idx.item())], percentage[idx.item()].item())

运行结果如下:

['Labrador retriever'] 42.46735763549805
['golden retriever'] 16.6086483001709
['Saluki', 'gazelle hound'] 15.473832130432129
['whippet'] 2.7881932258605957
['Ibizan hound', 'Ibizan Podenco'] 2.3617053031921387

可以看出,这些都是狗品种。因此,模型以相当高的置信度成功地预测出这是一只狗,但对狗的品种却不太确定。

其他图像测试结果:

['strawberry'] 99.99411010742188
['banana'] 0.0008383149397559464
['custard apple'] 0.0008333750884048641
['orange'] 0.000746806850656867
['lemon'] 0.000567478418815881

1.4. 基于ResNet进行图像分类

我们将使用 resnet101 – 101 层卷积神经网络。 resnet101 在训练过程中调整了大约 4450 万个参数。

我们只需将模型改为:

resnet = models.resnet101(pretrained=True)

运行结果如下:

['Labrador retriever'] 48.86918640136719
['dingo', 'warrigal', 'warragal', 'Canis dingo'] 8.17878532409668
['golden retriever'] 6.944648742675781
['Eskimo dog', 'husky'] 3.563744306564331
['bull mastiff'] 3.0799121856689453

就像 AlexNet 一样,ResNet 以非常高的置信度预测这是一只狗,并以 48.25% 的置信度预测这是一只拉布拉多猎犬。

1.5 完整代码

from torchvision import models
import torch
from torchvision import transforms
from PIL import Image
import json


# alexnet = models.alexnet(pretrained=True)
resnet = models.resnet101(pretrained=True)

transform = transforms.Compose([
    transforms.Resize(256),
    transforms.CenterCrop(224),
    transforms.ToTensor(),
    transforms.Normalize(
        mean=[0.485, 0.456, 0.406],
        std=[0.229, 0.224, 0.225]
    )
])

img = Image.open("../img/dog.jpg")
img_t = transform(img)
batch_t = torch.unsqueeze(img_t, 0)

resnet.eval()
out = resnet(batch_t)

with open('../json/imagenet_classes.json', 'r') as f:
    classes = json.load(f)

_, index = torch.max(out, 1)
index = index[0].item()

percentage = torch.nn.functional.softmax(out, dim=1)[0] * 100
# top-1
print(classes[str(index)], percentage[index].item())

_, indices = torch.sort(out, descending=True)
for idx in indices[0][:5]:
    # top-5
    print(classes[str(idx.item())], percentage[idx.item()].item())

2. 模型比较

在本节中,我们将根据以下标准比较预训练模型:

  • Top-1 Error: 最高预测类别与真实情况不同。
  • Top-5 Error: 如果前 5 个预测类别均不正确,则预测将被分类为错误。
  • Inference Time on CPU: Inference time is the time taken for the model inference step.
  • Inference Time on GPU
  • Model size: 这里的size代表PyTorch提供的预训练模型的.pth文件占用的物理空间

所有实验均在同一输入图像上进行多次,以便可以分析特定模型的所有结果的平均值。实验是在 Google Colab 上进行的。现在,让我们看看获得的结果。

2.1 模型准确率的比较

我们将讨论的第一个标准包括 Top-1 和 Top-5 错误。

从图中可以看出,两个误差都遵循相似的趋势。 AlexNet是基于深度学习的第一次尝试,此后误差得到了改善。值得注意的是 GoogLeNet、ResNet、VGGNet、ResNext。

2.2 预测时间比较

接下来,我们将根据模型预测所需的时间来比较模型。向每个模型多次提供一张图像,并对所有迭代的推理时间进行平均。在 Google Colab 上对 CPU 执行了类似的过程,然后对 GPU 执行了类似的过程。尽管顺序有所不同,但我们可以看到 SqueezeNet、ShuffleNet 和 ResNet-18 的推理时间非常短。

2.3 模型尺寸比较

很多时候,当我们在 Android 或 iOS 设备上使用深度学习模型时,模型大小成为决定因素,有时甚至比准确性更重要。 SqueezeNet 的模型大小最小 (5 MB),其次是 ShuffleNet V2 (6 MB) 和 MobileNet V2 (14 MB)。很明显,为什么这些模型在利用深度学习的移动应用程序中受到青睐。

2.4 整体比较

我们根据特定标准讨论了哪种模型表现更好。我们可以将所有这些重要细节压缩在一张气泡图中,然后我们可以参考这些细节来根据我们的要求决定采用哪种模型。
我们使用的 x 坐标是 Top-1 误差(越低越好)。 y 坐标是 GPU 上的预测时间(以毫秒为单位)(越低越好)。气泡大小代表模型大小(越低越好)。

注意:

  • 就模型尺寸而言,气泡越小越好。
  • 靠近原点的气泡在准确性和速度方面都更好。

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

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

相关文章

力扣刷题-链表-移除链表元素

203.移除链表元素 题意:删除链表中等于给定值 val 的所有节点。 示例 1: 输入:head [1,2,6,3,4,5,6], val 6 输出:[1,2,3,4,5] 示例 2: 输入:head [], val 1 输出:[] 示例 3: 输…

arduino u8g2 表情字库制作

U8G2 下载原代码 : GitHub - olikraus/u8g2: U8glib library for monochrome displays, version 2 1.制作图片 使用FLASH 或任何可以画图的软件制作动态图片PNG格式 大小最好先设定好如40x80 ,最好不要太大 128X64,60X60 将制作好的图片放入 下载好的 u8g2-master…

【每日一题】1539. 第 k 个缺失的正整数

1539. 第 k 个缺失的正整数 - 力扣(LeetCode) 给你一个 严格升序排列 的正整数数组 arr 和一个整数 k 。 请你找到这个数组里第 k 个缺失的正整数。 示例 1: 输入:arr [2,3,4,7,11], k 5 输出:9 解释:缺失…

国科大体系结构习题 | 第二章 计算机系统结构基础

第二章 习题汇总 Q1. 在3台不同指令系统的计算机上运行同一程序P时,A机需要执行 1.0 1 0 8 1.010^8 1.0108条指令,B机需要执行 2.0 1 0 8 2.0 10^8 2.0108条指令,C机需要执行 4.0 1 0 8 4.010^8 4.0108条指令,但实际执行时间…

Linux 操作技巧

目录 一、shell-命令解释器 二、Linux中的特殊符号 三、命令历史--history 一、shell-命令解释器 shell——壳,命令解释器,负责解析用户输入的命令 ——内置命令(shell内置) ——外置命令,在文件系统的某个目录下&…

Redis Insight 版本 2.32 翻译中文

使用教程 链接:https://pan.baidu.com/s/11pWBZ3uQSRZbuMS8POkLCw?pwd2ke5 一、下载renderer.js 1.打开安装好的软件 2、在这里添加我们指定的文件夹,这个文件夹是你随便创建的,你可以指定任何目录 3.选择renderer.js右键保存覆盖 4.在r…

Flask数据库之SQLAlchemy--介绍--链接数据库

目录 SQLAlchemy介绍 SQLAlchemy连接数据库 SQLAlchemy介绍 数据库是一个网站的基础!!! 比如MySQL、MongoDB、SQLite、PostgreSQL等,这里我们以MySQL为例进行讲解。 SQLAlchemy是一个ORM框架 对象关系映射(英语&…

chrome浏览器 调试鼠标悬停后出现的元素样式

鼠标悬停后出现的样式,我们遇见的有两种情况,一种是用css设置的hover时的样式,第二种就像el-tooltip组件,鼠标悬停时出现提示文字的样式。 一、css设置的hover时的样式 1、按【F12】键(或右键点击【检查】&#xff09…

星闪空口技术初探

星闪技术设计目标 在星闪技术的应用场景中,最低的时延要求达到了20us量级,比如智能座舱的主动降噪。最高的可靠性要求达到了99.9999%,比如智能制造的传感器与执行器的消息收发。除了低时延和高可靠之外,高精度同步、多并发和信息…

Linux工具——gdb

目录 一,gdb简介 二,gdb的指令 1.查看gdb是否有下载 2.需要明确的知识点 3.调试指令 1.打开调试代码 2.以某行为起点显示代码 3.打断点,查看断点,删除断点,禁用断点,启用断点 4.逐过程,逐…

灵活运用OSI模型提升排错能力

1.OSI模型有什么实际价值? 2.二层和三层网络的区别和应用; 3.如何通过OSI模型提升组网排错能力? -- OSI - 开放式系统互联 - OSI参考模型 - 一个互联标准 -- 软件硬件 - 定义标准 数据通信的标准 -- 厂商 思科 华为 华三…

【Spring】Spring Security学习笔记

基本概念 概念定义认证判断一个用户身份是否合法的过程(登录过程)会话为了避免用户的每次操作都进行认证, 将用户的信息保存在会话中. 常见的会话有基于session的模式和基于token的模式授权校验用户是否有权限访问某个资源 认证是为了验证用户的身份; 授权是为了验证用户是否有…

生长刺激表达基因2蛋白(ST2)介绍

生长刺激表达基因2蛋白(Growth stimulation expressed gene 2,ST2),也称为T1,IL1RL1或Fit1,编码基因定位于染色体2q12位点上,约40kb。属于白细胞介素-1(interleukin-1,IL…

2023华为杯数学建模研赛E题全解析

2023华为杯数学建模研赛E题解析,完整版已出!!! 包含所有模型、代码、结果,39页技术文档,详细内容如下! 免费版链接已放在下面,需要的同学可以直接自取~ 【云顶数模】2023研究生数学建模免费链接: https://pan.baid…

Python爬虫教程:解析网页中的元素

前言: 嗨喽~大家好呀,这里是魔王呐 ❤ ~! python更多源码/资料/解答/教程等 点击此处跳转文末名片免费获取 在我们理解了网页中标签是如何嵌套,以及网页的构成之后, 我们就是可以开始学习使用python中的第三方库BeautifulSoup筛…

194、SpringBoot -- 下载和安装 Erlang 、 RabbitMQ

本节要点: 一些命令: 小黑窗输入: rabbitmq-plugins enable rabbitmq_management 启动控制台插件 rabbitmq-server 启动rabbitMQ服务器 管理员启动小黑窗: rabbitmq-service install 添加rabbitMQ为本地服务 启动浏览器访问“h…

Goby 漏洞发布|Revive Adserver 广告管理系统 adxmlrpc.php 文件远程代码执行漏洞(CVE-2019-5434)

漏洞名称:Revive Adserver 广告管理系统 adxmlrpc.php 文件远程代码执行漏洞(CVE-2019-5434) English Name: Revive Adserver adxmlrpc.php Remote Code Execution Vulnerability (CVE-2019-5434) CVSS core: 9.0 影响资产数&a…

Go sync.Cond 原理

文章目录 前言newCondWaitSignalBroadcast和 channel 比较的优势 前言 sync.Cond 基本很少使用,应为大部分都能使用 channel 代替sync.Cond 通常是基于 sync.Mutex 扩展的主要就四个方法 newCond(l locker) 创建CondWait() 阻塞等待Signal() 唤醒其中一个Broadcast…

AI 编码助手 Codewhisperer 安装步骤和使用初体验

文章作者:为了自己加油 最近亚⻢逊云科技推出了一款基于机器学习的AI编程助手 Amazon Code Whisperer,可以实时提供代码建议。在编写代码时,它会自动根据现有的代码和注释给出建议。Amazon Code Whisperer与 GitHub Copilot 类似,…

Klotski: Efficient Obfuscated Execution against Controlled-Channel Attacks

目录 摘要引言贡献新的基于ORAM的防御控制信道攻击优化技术开源实现 背景Intel SGXORAMRing ORAM的组成ORAM树Position Map (位置图)Stash Ring ORAM的访问步骤1、Position Map Lookup 位置映射查找2、ReadPath3、EvictPath4、Early Reshuffles 早期的重新洗牌 相关工作和动机S…