[pytorch]FixMatch代码详解-数据加载

news2024/11/26 8:36:21

原文

FixMatch: Simplifying Semi-Supervised Learning with Consistency and Confidence.

这里还有一个译制版的很方便阅读

FixMatch:通过一致性和置信度简化半监督学习

代码

pytorch的代码有很多版本,我选择了比较简单的一个:

unofficial PyTorch implementation of FixMatch

其他版本的代码:

TorchSSL

数据加载分析

如果想要将fixmatch应用到自己的程序上,只需要修改数据部分的代码,所以先从这一部分分析。所有的参数都默认使用作者给出的例子:

python train.py --dataset cifar10 --num-labeled 4000 --arch wideresnet --batch-size 64 --lr 0.03 --expand-labels --seed 5 --out results/cifar10@4000.5

数据集

原文中使用的是CIFAR-10,CIFAR-10 数据集由 10 个类别的 60000 个 32x32 彩色图像组成,每个类别包含 6000 个图像。有 50000 个训练图像和 10000 个测试图像。
这里作者想使用4000张带标签照片(每个类400张)来进行训练。

训练执行文件 train.py

从主文件开始(def main():)看,一步步分析每个函数的作用。
首先,有一些参数是数据加载比较重要的。

parser.add_argument('--dataset', default='cifar10', type=str, choices=['cifar10', 'cifar100'], help='dataset name') //选择哪个数据集
parser.add_argument('--num-labeled', type=int, default=4000, help='number of labeled data') //多少张带标签的图片
parser.add_argument("--expand-labels", action="store_true", help="expand labels to fit eval steps") //数据扩展来适应每个step的数据产生,一会会详细看着一点
parser.add_argument('--total-steps', default=2**20, type=int, help='number of total steps to run') //这里使用总步数来进行训练(epoch可由此算出)
parser.add_argument('--eval-step', default=1024, type=int, help='number of eval steps to run') //每个epoch中的步数
parser.add_argument('--batch-size', default=64, type=int, help='train batchsize') //batch size
parser.add_argument('--mu', default=7, type=int, help='coefficient of unlabeled batch size') //原文中的超参数μ

首先,我们看看dataset是怎样产生的,有了dataset类,我们才能创建DataLoader对象。
这里提一下Pytorch读取数据流程:Pytorch 数据产生 DataLoader对象详解

在代码中,Dataset是这样产生的:

labeled_dataset, unlabeled_dataset, test_dataset=DATASET_GETTERS[args.dataset](args, './data')

上述代码是一个数据集加载代码,其中使用了一个名为 DATASET_GETTERS 的函数来根据 args.dataset 参数的值加载不同的数据集,并将加载后的数据集划分为labeled、unlabeled和test数据集。

以下是代码的解释:

  1. args.dataset 是一个参数,用于指定要加载的数据集的名称。假设这个参数的值是一个字符串,例如 'mnist'、'cifar10' 等,表示要加载的数据集的名称。
  2. DATASET_GETTERS 是一个函数,接受 args 和数据集目录路径(在这里是 ./data)作为输入。它根据 args.dataset 参数的值来加载相应的数据集,并返回加载后的数据集。
  3. DATASET_GETTERS[args.dataset] 是对 DATASET_GETTERS 函数的调用,其中 args.dataset 的值被用作函数的参数,用于选择要加载的数据集。
  4. DATASET_GETTERS[args.dataset](args, './data') 是对 DATASET_GETTERS 函数的调用,传入 args 参数和数据集目录路径 ./data,从而加载指定的数据集。
  5. 加载后的数据集被赋值给 labeled_datasetunlabeled_datasettest_dataset 变量,这三个变量分别表示带标签、无标签和测试数据集。这里假设 DATASET_GETTERS 函数返回的数据集已经经过划分,可以直接赋值给这三个变量。

然后,跳到下一小节看对DATASET_GETTERS的分析。Dataset对象 cifar.py

通过dataset类,我们产生dataloader对象:

train_sampler=RandomSampler if args.local_rank == -1 else DistributedSampler

labeled_trainloader = Dataloader(
    labeled_dataset,
    sampler=train_sampler(labeled_dataset),
    batch_size=args.batch_size,
    num_workers=args.num_workers,
    drop_last=True)

unlabeled_trainloader = Dataloader(
    unlabeled_dataset,
    sampler=train_sampler(unlabeled_dataset),
    batch_size=args.batch_size * args.mu,
    num_workers=args.num_workers,
    drop_last=True)

test_loader = Dataloader(
    test_dataset,
    sampler=SequentialSampler(test_dataset),
    batch_size=args.batch_size,
    num_workers=args.num_workers)

上述代码用于将加载的数据集划分为labeled和unlabeled的训练数据集以及test数据集,并配置数据加载器(DataLoader)用于在训练和测试过程中加载数据。

以下是代码的解释:

  1. train_sampler 是一个用于对train dataset进行采样的采样器对象。根据 args.local_rank 的值是否为 -1(表示非分布式训练),选择 RandomSampler(随机采样)或 DistributedSampler(分布式采样)作为采样器。如果 args.local_rank 的值为 -1,则使用 RandomSampler 对数据进行随机采样;否则,使用 DistributedSampler 进行分布式采样。
  2. labeled_trainloader 是用于加载带标签训练数据集的数据加载器。使用 DataLoader 函数将 labeled_dataset 数据集和前面定义的 train_sampler 采样器配置为数据加载器。同时,设置批量大小为 args.batch_size,设置并行加载的工作进程数为 args.num_workers,并设置 drop_last 参数为 True,表示在最后一个批次数据不足时丢弃该批次。
  3. unlabeled_trainloader 是用于加载无标签训练数据集的数据加载器。类似于 labeled_trainloader,使用 DataLoader 函数将 unlabeled_dataset 数据集和 train_sampler 采样器配置为数据加载器。不过,这里将批量大小设置为 args.batch_size*args.mu,其中 args.mu 是一个超参数,用于控制无标签数据集的批量大小。
  4. test_loader 是用于加载测试数据集的数据加载器。使用 DataLoader 函数将 test_dataset 数据集和 SequentialSampler(顺序采样)采样器配置为数据加载器。设置批量大小为 args.batch_size,设置并行加载的工作进程数为 args.num_workers

请注意,上述代码中的参数和采样器的选择可能需要根据具体的任务和模型需求进行调整。在实际使用中,应根据数据集的格式、任务的需求以及硬件资源的情况,配置合适的数据加载器和参数设置。

关于dataloader的参数:

一文弄懂Pytorch的DataLoader,Dataset,Sampler之间的关系_别致的SmallSix的博客-CSDN博客

数据加载部分差不多就结束了,最后我们再看看在循环中是如何调用这些数据的吧。首先,作者使用了x, y = next(iter(training_loader))结构,其原理:

在这里插入图片描述
作者的代码如下,当迭代到最后的轮次时会报错,所以加上except开始新一轮的迭代。

labeled_iter = iter(labeled_trainloader)
for batch_idx in range(1024):
    try:
        inputs_x, targets_x = labeled_iter.next()
        print(targets_x.shape[0])
    except:
        labeled_iter = iter(labeled_trainloader)
        inputs_x, targets_x = labeled_iter.next()
        print(targets_x.shape[0])

上述代码是一个示例的数据加载和迭代过程的代码。代码使用了一个带有 try-except 的循环,从 labeled_trainloader 数据加载器中迭代加载训练数据,并输出每个批次的目标(标签)数量。

以下是代码的解释:

  1. labeled_iter 是一个 labeled_trainloader 数据加载器的迭代器,用于迭代加载训练数据集的批次。
  2. 循环从 batch_idx 为 0 开始,迭代到 1023。这里使用了一个固定的循环次数,加载了 1024 个批次的训练数据。
  3. 在每次循环中,使用 labeled_iter.next()labeled_trainloader 数据加载器中获取下一个批次的数据。其中,inputs_x 是输入数据,targets_x 是对应的目标(标签)数据。
  4. 使用 targets_x.shape[0] 输出目标数据的数量,即当前批次的标签数量。
  5. 如果在迭代过程中发生异常(如到达数据集末尾),则使用 labeled_iter = iter(labeled_trainloader) 重新初始化 labeled_iter,从数据加载器的头部重新开始迭代,并继续输出下一个批次的标签数量。

请注意,上述代码中的循环次数和异常处理逻辑可能需要根据具体的任务和数据集情况进行调整,以确保正确加载和处理数据。在实际使用中,应根据数据集的大小和需求,灵活调整循环次数和异常处理逻辑。

Dataset对象 cifar.py

在dataset文件夹中的cifar.py文件中定义了dataset类。
首先,我们使用get_cifar10函数:

DATASET_GETTERS = {'cifar10': get_cifar10,
                   'cifar100': get_cifar100}

上述代码定义了一个字典 DATASET_GETTERS,其中包含了两个键值对:

  1. 'cifar10',对应值 get_cifar10:表示获取 CIFAR-10 数据集的方法,这里假设 get_cifar10 是一个函数或方法,用于从数据集获取 CIFAR-10 数据并返回数据加载器或数据集对象。
  2. 'cifar100',对应值 get_cifar100:表示获取 CIFAR-100 数据集的方法,这里假设 get_cifar100 是一个函数或方法,用于从数据集获取 CIFAR-100 数据并返回数据加载器或数据集对象。

这样,通过使用 DATASET_GETTERS 字典,可以根据不同的键(即数据集名称)来获取对应的数据集,并调用相应的获取数据集的方法,从而获取相应的数据加载器或数据集对象。例如,可以通过 DATASET_GETTERS['cifar10'] 调用 get_cifar10 方法来获取 CIFAR-10 数据集,通过 DATASET_GETTERS['cifar100'] 调用 get_cifar100 方法来获取 CIFAR-100 数据集。这种方式可以方便地扩展和管理多个不同的数据集,并在代码中统一管理它们的获取方法。

def get_cifar10(args, root):
    transform_labeled = transforms.Compose([
        transforms.RandomHorizontalFlip(),
        transforms.RandomCrop(size=32,
                              padding=int(32*0.125),
                              padding_mode='reflect'),
        transforms.ToTensor(),
        transforms.Normalize(mean=cifar10_mean, std=cifar10_std)
    ])
    transform_val = transforms.Compose([
        transforms.ToTensor(),
        transforms.Normalize(mean=cifar10_mean, std=cifar10_std)
    ])
    base_dataset = datasets.CIFAR10(root, train=True, download=True)

    train_labeled_idxs, train_unlabeled_idxs = x_u_split(
        args, base_dataset.targets)

    train_labeled_dataset = CIFAR10SSL(
        root, train_labeled_idxs, train=True,
        transform=transform_labeled)

    train_unlabeled_dataset = CIFAR10SSL(
        root, train_unlabeled_idxs, train=True,
        transform=TransformFixMatch(mean=cifar10_mean, std=cifar10_std))

    test_dataset = datasets.CIFAR10(
        root, train=False, transform=transform_val, download=False)

    return train_labeled_dataset, train_unlabeled_dataset, test_dataset

上述代码定义了一个名为 get_cifar10 的函数,用于获取 CIFAR-10 数据集,并返回包含 labeled_dataset、unlabeled_dataset 和 test_dataset 的元组。

函数的输入参数包括 argsrootargs 是一个参数对象,包含了在调用该函数时传入的参数,用于配置数据集的获取方式。root 是数据集的根目录,用于指定数据集在本地的存储路径。

函数内部进行了以下操作:

  1. 定义了两个数据变换(transform):
    • transform_labeled:包括随机水平翻转、随机裁剪和转换为张量,并应用了 CIFAR-10 数据集的均值和标准差进行标准化。
    • transform_val仅包括转换为张量,并应用了 CIFAR-10 数据集的均值和标准差进行标准化。
  2. 使用 datasets.CIFAR10 类从 root 下载或加载 CIFAR-10 数据集,包括训练集和测试集,并保存在 base_dataset 中。
  3. 调用 x_u_split 函数,根据参数 argsbase_dataset.targets训练集的样本进行有监督和无监督样本的划分,得到 train_labeled_idxstrain_unlabeled_idxs,分别表示有监督和无监督样本的索引。
  4. 使用 CIFAR10SSL 类分别构建 train_labeled_datasettrain_unlabeled_dataset,并传入相应的数据变换和划分得到的索引。
  5. 使用 datasets.CIFAR10 类构建 test_dataset,表示测试集,包括对应的数据变换和不下载数据集。
  6. 返回 train_labeled_datasettrain_unlabeled_datasettest_dataset,作为函数的返回值,以便后续在代码中使用这些数据集进行训练、验证和测试操作。

这个函数还是比较复杂的,我们一点点看。

base_dataset = datasets.CIFAR10(root, train=True, download=True)

上述代码使用 datasets.CIFAR10 类从指定的 root 目录中加载 CIFAR-10 数据集的训练集,并将数据集存储在 base_dataset 变量中。

datasets.CIFAR10 类是 PyTorch 提供的用于加载 CIFAR-10 数据集的类,其中的参数含义如下:

  • root:数据集的根目录,表示数据集在本地的存储路径。
  • train:布尔值,表示是否加载训练集。当设置为 True 时,加载训练集;当设置为 False 时,加载测试集。
  • download:布尔值,表示是否下载数据集。当设置为 True 时,如果本地没有该数据集,会自动从互联网上下载并存储在 root 目录下;当设置为 False 时,如果本地没有该数据集,会抛出异常。

在这里,train 被设置为 True,表示加载 CIFAR-10 数据集的训练集;download 被设置为 True,表示如果本地没有 CIFAR-10 数据集,则会自动从互联网上下载。加载的数据集会被存储在 base_dataset 变量中,后续可以使用该变量来获取训练集中的样本和标签。

(自己理解)这里下载了cifar10数据集,只是加载了train_dataset。

这是使用cifar数据的常用方法,我们可以查看其返回的对象

for (image, target)  in base_dataset:
    image.show()
    print(target)
print(len(base_dataset.targets)) //50000

上述代码使用一个 for 循环遍历 base_dataset,并从中获取每个样本的图像和标签。

在循环中,每次迭代都会从 base_dataset 中获取一个样本的图像和标签,并通过 image.show() 方法显示图像,然后通过 print(target) 打印该样本的标签。

最后,通过 len(base_dataset.targets) 获取 base_dataset 中所有样本的数量。这里的 base_dataset.targets 是一个包含所有训练集样本的标签的列表,其长度就是训练集中样本的数量5000。

综合而言,这段代码的作用是遍历并显示 CIFAR-10 数据集的训练集中的图像,并打印对应的标签,并计算训练集中样本的数量。

之后,使用x_u_split函数将带标签与不带标签的数据索引分开:

train_labeled_idxs, train_unlabeled_idxs = x_u_split(
        args, base_dataset.targets)

上述代码调用了一个名为 x_u_split 的函数,将 argsbase_dataset.targets 作为参数传入,并返回两个变量 train_labeled_idxstrain_unlabeled_idxs

x_u_split 函数的作用是将数据集中的样本划分为有标签数据和无标签数据的索引。具体而言,train_labeled_idxs 存储了有标签数据的索引,train_unlabeled_idxs 存储了无标签数据的索引。

这个函数可能是根据某种策略,如半监督学习或者自监督学习的要求,将数据集中的样本划分为有标签和无标签数据集。划分的依据可能包括标签的可用性、数量、分布等因素,具体实现细节需要查看 x_u_split 函数的实现代码。

def x_u_split(args, labels):
    label_per_class = args.num_labeled // args.num_classes
    labels = np.array(labels)
    labeled_idx = []
    # unlabeled data: all data (https://github.com/kekmodel/FixMatch-pytorch/issues/10)
    unlabeled_idx = np.array(range(len(labels)))
    for i in range(args.num_classes):
        idx = np.where(labels == i)[0]
        idx = np.random.choice(idx, label_per_class, False)
        labeled_idx.extend(idx)
    labeled_idx = np.array(labeled_idx)
    assert len(labeled_idx) == args.num_labeled

    if args.expand_labels or args.num_labeled < args.batch_size:
        num_expand_x = math.ceil(
            args.batch_size * args.eval_step / args.num_labeled)
        labeled_idx = np.hstack([labeled_idx for _ in range(num_expand_x)])
    np.random.shuffle(labeled_idx)
    return labeled_idx, unlabeled_idx

每个类带标签数据的个数是均衡的,每个类带标签的数据个数 = 带标签数据总个数//类数。
所以,使用一个循环(10个类):
对于每一个类,找出他们在总数据(labels)中的数据索引,并用random.choice随机选择label_per_class个数据,将他们加入到带标签的数据索引labeled_idx中。
对于不带标签的数据,原文作者使用了所有的数据(包含带标签的数据),所以他的索引为全部数据的索引。
需要注意的一个点是,args.expand_labels参数作者默认为true的,所以我们要进行数据重复。
这里重复的次数num_expand_x为 64(batch_size )* 1024(eval_step)/ 4000 (num_labeled)=17次
所以带标签的数据为 68000个(每个索引都重复了17次)。

上述代码定义了一个名为 x_u_split 的函数,该函数接受两个参数 argslabels,并返回两个值 labeled_idxunlabeled_idx

该函数的作用是将数据集中的样本划分为有标签数据和无标签数据的索引。具体实现如下:

  1. 计算每个类别的有标签样本数目 label_per_class,通过将 args.num_labeled(要求有标签样本的总数目)除以 args.num_classes(类别数目)得到;
  2. 将输入的标签 labels 转换为 numpy 数组;
  3. 初始化一个空列表 labeled_idx,用于存储有标签样本的索引;
  4. 初始化一个包含所有样本索引的 numpy 数组 unlabeled_idx,作为无标签样本的索引;
  5. 针对每个类别循环处理: a. 获取当前类别的样本索引 idx; b. 从 idx 中随机选择 label_per_class 个索引,保证每个类别有足够的有标签样本,并将其添加到 labeled_idx 列表中;
  6. labeled_idx 转换为 numpy 数组;
  7. 检查 labeled_idx 的长度是否等于 args.num_labeled确保有标签样本的总数目满足要求
  8. 如果 args.expand_labels或者 args.num_labeled 小于 args.batch_size,则对 labeled_idx 进行扩展,使其包含足够多的重复样本索引,以满足后续的批量加载要求;
  9. labeled_idx 进行随机洗牌;
  10. 返回 labeled_idxunlabeled_idx 作为函数的输出。
    train_labeled_dataset = CIFAR10SSL(
        root, train_labeled_idxs, train=True,
        transform=transform_labeled)

    train_unlabeled_dataset = CIFAR10SSL(
        root, train_unlabeled_idxs, train=True,
        transform=TransformFixMatch(mean=cifar10_mean, std=cifar10_std))
    test_dataset = datasets.CIFAR100(
        root, train=False, transform=transform_val, download=False)

上述代码分别创建了三个数据集对象,分别为 train_labeled_datasettrain_unlabeled_datasettest_dataset,用于加载 CIFAR-10 数据集的有标签数据、无标签数据和测试数据。

  1. train_labeled_dataset 对象使用 CIFAR10SSL 类进行初始化,传入参数 root(数据集的根目录路径)、train_labeled_idxs(有标签样本的索引)、train=True(表示加载训练数据集)、transform=transform_labeled(对有标签样本应用的数据变换,包括随机水平翻转、随机裁剪、转换为 Tensor 格式以及数据标准化)。

  2. train_unlabeled_dataset 对象使用 CIFAR10SSL 类进行初始化,传入参数 roottrain_unlabeled_idxs(无标签样本的索引)、train=Truetransform=TransformFixMatch(mean=cifar10_mean, std=cifar10_std)(对无标签样本应用的数据变换,包括 FixMatch 算法中使用的数据增强方法,例如随机强化

  3. test_dataset 对象使用 datasets.CIFAR100 类进行初始化,传入参数 roottrain=False(表示加载测试数据集)transform=transform_val(对测试样本应用的数据变换,包括转换为 Tensor 格式以及数据标准化)、download=False(表示不下载测试数据集,因为 CIFAR-100 数据集已经下载过了)

这样,通过上述代码,可以得到三个数据集对象,分别包含了 CIFAR-10 数据集中的有标签数据、无标签数据和测试数据,并且已经应用了相应的数据变换和数据增强方法。

然后,使用继承CIFAR10的CIFAR10SSL类产生dataset对象。验证集直接使用就行,只需要将数据转化为tensor。

class CIFAR10SSL(datasets.CIFAR10):
    def __init__(self, root, indexs, train=True,
                 transform=None, target_transform=None,
                 download=False):
        super().__init__(root, train=train,
                         transform=transform,
                         target_transform=target_transform,
                         download=download)
        if indexs is not None:
            self.data = self.data[indexs]
            self.targets = np.array(self.targets)[indexs]

    def __getitem__(self, index):
        img, target = self.data[index], self.targets[index]
        img = Image.fromarray(img)  //array转换成image

        if self.transform is not None:
            img = self.transform(img)

        if self.target_transform is not None:
            target = self.target_transform(target)

        return img, target

上述代码定义了一个名为 CIFAR10SSL 的自定义类,该类继承自 datasets.CIFAR10 类,并添加了一些自定义的功能。

  1. __init__(self, root, indexs, train=True, transform=None, target_transform=None, download=False) 方法:初始化方法,用于创建 CIFAR10SSL 类的对象。接收以下参数:

    • root:数据集的根目录路径。
    • indexs样本索引,用于指定从数据集中选择哪些样本。可以是有标签样本或无标签样本的索引。
    • train:布尔值,表示是否加载训练数据集,默认为 True
    • transform:数据变换操作,用于对样本进行数据增强或数据预处理,默认为 None
    • target_transform:目标变换操作,用于对样本的目标进行处理,默认为 None
    • download:布尔值,表示是否下载数据集,默认为 False

    在该方法中,首先调用父类 datasets.CIFAR10__init__ 方法进行初始化,传入相应的参数。然后,根据传入的 indexs 参数,对 self.dataself.targets 进行切片操作,以选择对应索引的样本数据和标签。  self.data=self.data[indexs],self.targets=np.array(self.targets)[indexs]

  2. __getitem__(self, index) 方法:用于获取指定索引处的样本。接收一个整数 index 作为参数,表示样本的索引。在该方法中,根据索引从 self.dataself.targets 中获取对应的样本数据和标签,并进行相应的数据变换和目标变换操作,最后返回变换后的样本数据和标签。  img,target=self.data[index],self.targets[index]  img=Image.fromarray(image)

通过上述代码,定义了一个自定义的数据集类 CIFAR10SSL,用于加载 CIFAR-10 数据集中的有标签或无标签样本,并且可以应用指定的数据变换和目标变换操作。

根据索引返回对应的img和target,用transform参数控制强弱变。

弱增强是一种标准的翻转和移位增强策略. 例如在数据集上以 50% 的概率随机水平翻转图像, 并且在垂直和水平方向上随机平移。
对于"强"增强,文中尝试了两种基于 AutoAugment 的方法, 然后是 Cutout。AutoAugment 使用强化学习来查找包含来自 Python Imaging Library 的转换的增强策略,这需要标记数据来学习增强策略, 这使得在可用标记数据有限的 SSL 设置中使用存在问题。因此, 使用不需要利用标记数据学习增强策略的 AutoAugment 变体, 例如 RandAugment 和 CTAugment。RandAugment 和 CTAugment 都没有使用学习策略, 而是为每个样本随机选择转换。对于 RandAugment,控制所有失真严重程度的幅度是从预定义的范围内随机采样的。具有随机幅度的 RandAugment 也被用于 UDA。 而对于 CTAugment, 单个变换的幅度是即时学习的。

OK,现在我们已经得到了带标签的数据集,不带标签的数据集,验证集的dataset数据,然后我们回到主文件。Dataset对象 cifar.py

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

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

相关文章

记一次某应用虚拟化系统远程代码执行

漏洞简介 微步在线漏洞团队通过“X漏洞奖励计划”获取到瑞友天翼应用虚拟化系统远程代码执行漏洞情报(0day)&#xff0c;攻击者可以通过该漏洞执行任意代码&#xff0c;导致系统被攻击与控制。瑞友天翼应用虚拟化系统是基于服务器计算架构的应用虚拟化平台&#xff0c;它将用户…

xxl-job 7.32版本 安装部署

文章目录 前言xxl-job 7.32版本 安装部署1. xxl-job 是什么2. 特性3. xxl-job 部署安装3.1. 下载源码3.2. 部署:3.2.1. 初始化调度数据库3.2.2. 配置调度中心 前言 如果您觉得有用的话&#xff0c;记得给博主点个赞&#xff0c;评论&#xff0c;收藏一键三连啊&#xff0c;写作…

GDOUCTF2023-部分re复现

目录 [GDOUCTF 2023]Check_Your_Luck [GDOUCTF 2023]Tea [GDOUCTF 2023]doublegame [GDOUCTF 2023]Check_Your_Luck 打开题目是一串代码&#xff0c;明显的z3约束器求解 直接上脚本 import z3 from z3 import Reals z3.Solver() vReal(v) xReal(x) yReal(y) wReal(w) zRea…

cocosLua 之文本相关

Text 用于创建系统或ttf文本&#xff0c; 类结构&#xff1a; #mermaid-svg-bMIqhf5X7M9uF2Ba {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-bMIqhf5X7M9uF2Ba .error-icon{fill:#552222;}#mermaid-svg-bMIqhf5X7…

走进社区客户端测试 | 得物技术

0.引言 社区 C 端质量体系建设思考&#xff1f; 询问一下 ChatGPT 1、关于社区客户端 1.1 社区端上功能 得物首页 搜索、发布、关注流、推荐流、沉浸式单列流、活动 tab、其他二级频道 tab 动态详情页 图文、视频、专栏、点评 私域 个人/他人主页、通讯录好友、微博好友…

不得不用ChatGPT的100个理由……

❝ 最近无论在哪&#xff0c;很多人都在吹ChatGPT无所不能&#xff0c;动不动就是AI要颠覆人类&#xff0c;很多人害怕有一天AI会取代自己&#xff0c;我认为明显是多虑了…… ❝ 当然&#xff0c;也有很多小白试用了ChatGPT之后&#xff0c;并没有感觉到他很强大&#xff0c;主…

车载以太网解决方案

近年来&#xff0c;为了满足智能网联汽车的开发要求&#xff0c;车载以太网技术开始逐渐进入人们的视野。而以太网技术已经成为下一代车载络架构的趋势之一&#xff0c;其发展之迅猛&#xff0c;使得各主机厂纷纷产生了浓厚的兴趣并投入研发。 一 为什么使用车载以太网 | 对高…

什么牌子台灯好用不伤眼睛?盘点国内值得入手的护眼灯

选择一款不伤眼睛的台灯主要看光照柔和、光照范围广&#xff0c;符合标准照度国A或国AA、显色指数Ra90以上、无眩光、RG0无危害蓝光、无可视频闪等&#xff0c;对于现在许多青少年的近视率增加&#xff0c;一旦近视就无法恢复&#xff0c;保护好眼睛&#xff0c;在学习阅读时&a…

SpringBoot使用ElasticSearch

ES官网&#xff1a;https://www.elastic.co/cn/downloads/elasticsearch ES下载地址&#xff1a;https://www.elastic.co/cn/downloads/past-releases#elasticsearch kibana官网&#xff1a;https://www.elastic.co/cn/downloads/kibana kibana下载地址&#xff1a;https://…

小红书笔记发布软件 批量上传视频

百收网SEO短视频矩阵发布丨9平台视频发布助手 软件简述&#xff1a;软件仅支持win系统&#xff0c; 软件使用的是网页版模拟协议软件不绑定电脑&#xff0c;任意换机&#xff0c;不限登录账号数量&#xff0c; 软件支持抖音&#xff0c;快手&#xff0c;视频号&#xff0c;西瓜…

P1034 [NOIP2002 提高组] 矩形覆盖

题目描述 在平面上有 &#xfffd;n 个点&#xff0c;每个点用一对整数坐标表示。例如&#xff1a;当 &#xfffd;4n4 时&#xff0c;44 个点的坐标分另为&#xff1a;&#xfffd;1(1,1)p1​(1,1)&#xff0c;&#xfffd;2(2,2)p2​(2,2)&#xff0c;&#xfffd;3(3,6)p3​…

设备树总结

设备树的概念: 设备树&#xff08;Device Tree:DT&#xff09;是用来描述设备信息的一种树形结构。设备树文件在linux内核启动的时候传递到内核被内核解析。设备树中每一个设备节点中的信息构成了一个属性链表&#xff0c;如果驱动想要使用这个设备信息&#xff0c;只需要在这…

UE4架构初识(五)

UE4仿真引擎学习 一、架构基础 1. GameInstance UE提供的方案是一以贯之的&#xff0c;为我们提供了一个GameInstance类。为了受益于UObject的反射创建能力&#xff0c;直接继承于UObject&#xff0c;这样就可以依据一个Class直接动态创建出来具体的GameInstance子类。 UGam…

Pytest接口自动化测试实战演练

结合单元测试框架pytest数据驱动模型allure 目录 api&#xff1a; 存储测试接口conftest.py :设置前置操作目前前置操作&#xff1a;1、获取token并传入headers&#xff0c;2、获取命令行参数给到环境变量,指定运行环境commmon&#xff1a;存储封装的公共方法connect_mysql.p…

C. Magic Ship(二分 + 前缀和)

Problem - C - Codeforces 你是一艘船的船长。最初你站在一个点(x1&#xff0c;y1)上&#xff08;很明显&#xff0c;海上的所有位置都可以用笛卡尔平面描述&#xff09;&#xff0c;你想要前往一个点(x2&#xff0c;y2)。 你知道天气预报——长度为n的字符串s&#xff0c;仅由…

实战详解Docker快速搭建部署ELK

一.安装前须知 以下步骤在 VMware 中的 centos 7 中操作&#xff0c;ip 地址为&#xff1a;192.168.161.128&#xff1b; 注意安装的时候最好统一版本&#xff0c;否则后面会出现许多问题&#xff0c;进官网搜索对应镜像&#xff0c;查看 Tags 标签下的版本&#xff0c;目前我…

记一次死锁问题

最近在做一个需求&#xff0c;碰到了死锁的问题&#xff0c;记录下解决问题的过程 背景 这个需求要改动一个接口&#xff0c;我这边称为A接口&#xff0c;原先的逻辑是A接口内部会调用c方法&#xff0c;c方法是一个dubbo方法&#xff0c; 现在需要再A接口里添加调用B方法&…

springcloud之Feign、ribbon设置超时时间和重试机制的总结

目录标题 超时时间ribbon和Feignribbon和Feign默认超时时间关于ribbon和Feign超时时间配置说明 关于hystrix默认超时时间与配置说明 ribbon的重试机制重试的次数hystrix超时时间举个例子 超时时间 feign/ribbon对应的是请求的时间 hystrix对应的是断路器的时间 一般情况下 都是…

【Linux】2. 常见指令

1. 操作系统的定义 在真正了解Linux操作系统之前&#xff0c;我们需要初步明确什么是操作系统 Linux下的基本指令 指令的作用是什么&#xff0c;其实就是相当于Windows的基本操作&#xff0c;Linux操作系统是以命令行显示的&#xff0c;而Windows则是以图形化界面的方式展现…

图像融合方向:《Deep Image Blending》论文理解

《Deep Image Blending》论文理解 论文&#xff1a;《Deep Image Blending》WACV 2020 链接&#xff1a;Deep Image Blending 本文目录 《Deep Image Blending》论文理解论文创新点具体实现思路文中使用的基准方法文章内容解析使用模型整体架构两阶段算法详情第1阶段第2阶段 损…