使用Pytorch从零开始构建DCGAN

在本文中,我们将深入研究生成建模的世界,并使用流行的 PyTorch 框架探索 DCGAN(生成对抗网络 (GAN) 的一种变体)的实现。具体来说,我们将使用 CelebA 数据集(名人面部图像的集合)来生成逼真的合成面部。在深入了解实现细节之前,我们首先了解 GAN 是什么以及 DCGAN 与它们有何不同,并详细探讨其架构。
在这里插入图片描述
那么,什么是 GAN?

简而言之,生成对抗网络(GAN)是一种令人着迷的机器学习模型,其中两个玩家(生成器和鉴别器)参与竞争性游戏。生成器的目的是创建真实的合成样本,例如图像或文本,而鉴别器的工作是区分真实样本和假样本。通过这场猫鼠游戏,GAN 学会生成高度令人信服且真实的输出,最终突破人工智能在创建新的多样化数据方面的界限。

在这里插入图片描述
理解DCGAN:

DCGAN(深度卷积生成对抗网络)是一种令人兴奋的机器学习模型,可以创建极其逼真和详细的图像。想象一下,一个系统可以通过分析数千个示例来学习生成全新的图片,例如面孔或风景。DCGAN 通过巧妙地结合两个网络来实现这一目标——一个网络生成图像,另一个网络试图区分真假图像。通过竞争过程,DCGAN 成为生成令人信服且难以与真实图像区分开的图像的大师,展示了人工智能的巨大创造潜力。

DCGAN的架构:

DCGAN(深度卷积生成对抗网络)的架构​​由两个基本组件组成:生成器和判别器。

生成器将随机噪声作为输入,并逐渐将其转换为类似于训练数据的合成样本。它通过一系列层来实现这一点,包括转置卷积、批量归一化和激活函数。这些层使生成器能够学习复杂的模式和结构,从而生成捕获真实数据的复杂细节的高维样本。

另一方面,鉴别器充当二元分类器,区分真实样本和生成样本。它接收输入样本并将其传递给卷积层、批量归一化和激活函数。鉴别器的作用是评估样本的真实性并向生成器提供反馈。通过对抗性训练过程,生成器和鉴别器不断竞争并提高性能,最终生成越来越真实的样本。

让我们开始实现我们的第一个 DCGAN:

假设您的环境中安装了 PyTorch 和 CUDA,我们首先导入必要的库。

import torch
import torch.nn as nn
import torch.optim as optim
import torchvision
from tqdm import tqdm
import torchvision.datasets as datasets
from torchvision.datasets import ImageFolder
from torchvision.utils import make_grid
import torchvision.utils as vutils
import torchvision.transforms as transforms
from torch.utils.data import DataLoader
import matplotlib.pyplot as plt
from torch.utils.data import Subset
import numpy as np

导入这些库后,您就可以使用 CelebA 数据集在 PyTorch 中继续实施 DCGAN。

为了设置训练 DCGAN 模型所需的配置,我们可以定义设备、学习率、批量大小、图像大小、输入图像中的通道数、潜在空间维度、历元数以及特征数判别器和生成器。以下是配置:

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
LEARNING_RATE = 2e-4  # could also use two lrs, one for gen and one for disc
BATCH_SIZE = 128
IMAGE_SIZE = 64
CHANNELS_IMG = 3
Z_DIM = 100
NUM_EPOCHS = 5
FEATURES_DISC = 64
FEATURES_GEN = 64

“device”变量确保代码在可用的 GPU 上运行,否则返回到 CPU。“LEARNING_RATE”决定了模型在优化过程中学习的速率。“BATCH_SIZE”表示每次迭代中处理的样本数量。“IMAGE_SIZE”表示输入图像的所需尺寸。“CHANNELS_IMG”指定输入图像中颜色通道的数量(例如,RGB 为 3)。“Z_DIM”表示潜在空间的维度,它是生成器的输入。“NUM_EPOCHS”决定了训练期间遍历整个数据集的次数。“FEATURES_DISC”和“FEATURES_GEN”分别表示鉴别器和生成器网络中的特征数量。

这些配置对于训练 DCGAN 模型至关重要,可以根据具体要求和可用资源进行调整。

要加载 CelebA 数据集并准备进行训练,我们可以定义数据转换、创建数据集对象并设置数据加载器:

transform = transforms.Compose([transforms.Resize((IMAGE_SIZE, IMAGE_SIZE)),transforms.ToTensor(),transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
])dataset = datasets.ImageFolder('<path_to_celeba_dataset_in_your_directoty>', transform=transform)
dataloader = DataLoader(dataset=dataset, batch_size=BATCH_SIZE, shuffle=True)

要可视化 CelebA 数据集中的一批训练图像:

real_batch = next(iter(dataloader))
plt.figure(figsize=(7,7))
plt.axis("off")
plt.title("Training Images")
plt.imshow(np.transpose(vutils.make_grid(real_batch[0].to(device)[:49], padding=2, normalize=True).cpu(),(1,2,0)))

在这里插入图片描述
创建生成器网络:
在这里插入图片描述
在 DCGAN 架构中,噪声数据最初表示为形状为 100x1x1 的张量,经过一系列转置卷积运算,将其转换为大小为 3x64x64 的输出图像。

以下是重塑过程的逐步分解:

  1. 输入噪声:100x1x1
  2. 第一个转置卷积层:
    — 输出大小:1024x4x4
    — 内核大小:4x4,步长:1,填充:0
  3. 第二个转置卷积层:
    — 输出大小:512x8x8
    — 内核大小:4x4,步长:2,填充:1
  4. 第三转置卷积层:
    — 输出大小:256x16x16
    — 内核大小:4x4,步长:2,填充:1 5.
  5. 第四转置卷积层:
    — 输出大小:128x32x32
    — 内核大小:4x4,步长:2,填充:1
  6. 最终转置卷积层:
    — 输出大小:3x64x64
    — 内核大小:4x4,步幅:2,填充:1

通过将噪声数据传递到这些转置卷积层,生成器逐渐将低维噪声放大为与所需大小 3x64x64 匹配的高维图像。重塑过程涉及增加空间维度,同时减少通道数量,从而产生具有代表 RGB 颜色通道的三个通道和 64x64 像素尺寸的最终输出图像。

class Generator(nn.Module):def __init__(self, z_dim, channels_img, features_g):super(Generator, self).__init__()self.net = nn.Sequential(self._block(z_dim, features_g * 16, 4, 1, 0),self._block(features_g * 16, features_g * 8, 4, 2, 1),self._block(features_g * 8, features_g * 4, 4, 2, 1),self._block(features_g * 4, features_g * 2, 4, 2, 1),nn.ConvTranspose2d(features_g * 2, channels_img, kernel_size=4, stride=2, padding=1),nn.Tanh())def _block(self, in_channels, out_channels, kernel_size, stride, padding):return nn.Sequential(nn.ConvTranspose2d(in_channels,out_channels,kernel_size,stride,padding,bias=False),nn.BatchNorm2d(out_channels),nn.ReLU())def forward(self, x):return self.net(x)

Generator 类代表 DCGAN 架构中的生成器网络。它将潜在空间的维度 (z_dim)、输出图像中的通道数 (channels_img) 和特征数 (features_g) 作为输入。生成器被定义为顺序模块。

该_block方法在生成器中定义了一个块,其中包含转置卷积层、批量归一化和 ReLU 激活函数。该块重复多次,逐渐增加输出图像的空间维度。

在该forward方法中,输入噪声 (x) 通过生成器的连续层,从而生成生成的图像。

生成器的架构旨在将低维潜在空间转换为高维图像,并逐渐将其放大到所需的输出大小。然后输出图像通过双曲正切激活函数 ( nn.Tanh()) 以确保其像素值在 [-1, 1] 范围内。

通过以这种方式定义生成器,当提供随机噪声作为输入时,它学会生成类似于训练数据的合成图像。

创建鉴别器网络:
在这里插入图片描述
在 DCGAN 架构中,判别器采用大小为 3x64x64 的输入图像,并通过一系列卷积层对其进行处理,从而产生 1x1x1 的输出。以下是重塑过程的逐步分解:

  1. 输入图像:3x64x64
  2. 第一个卷积层:
    — 输出大小:64x32x32
    — 内核大小:4x4,步长:2,填充:1
  3. 第二个卷积层:
    — 输出大小:128x16x16
    — 内核大小:4x4,步长:2 ,填充:1
  4. 第三个卷积层:
    — 输出大小:256x8x8
    — 内核大小:4x4,步长:2,填充:1 5.
  5. 第四个卷积层:
    — 输出大小:512x4x4
    — 内核大小:4x4,步长:2,填充:1
  6. 最终卷积层:
    — 输出大小:1x1x1
    — 内核大小:4x4,步长:2,填充:0

通过将输入图像传递给这些卷积层,鉴别器逐渐减小空间维度,同时增加通道数量。这种转换允许鉴别器评估图像并对其真实性做出决定。1x1x1 的输出大小表示单个值,该值表示输入图像为真或假的概率。

class Discriminator(nn.Module):def __init__(self, channels_img, features_d):super(Discriminator, self).__init__()self.disc = nn.Sequential(nn.Conv2d(channels_img, features_d, kernel_size=4, stride=2, padding=1),nn.LeakyReLU(0.2),self._block(features_d, features_d * 2, 4, 2, 1),self._block(features_d * 2, features_d * 4, 4, 2, 1),self._block(features_d * 4, features_d * 8, 4, 2, 1),nn.Conv2d(features_d * 8, 1, kernel_size=4, stride=2, padding=0),nn.Sigmoid())def _block(self, in_channels, out_channels, kernel_size, stride, padding):return nn.Sequential(nn.Conv2d(in_channels,out_channels,kernel_size,stride,padding,bias=False),nn.BatchNorm2d(out_channels),nn.LeakyReLU(0.2))def forward(self, x):return self.disc(x)

Discriminator 类代表 DCGAN 架构中的鉴别器网络。它将输入图像中的通道数 (channels_img) 和特征数 (features_d) 作为输入。鉴别器被定义为一个顺序模块。

该_block方法在判别器内定义了一个块,由卷积层、批量归一化和 LeakyReLU 激活组成。该块重复多次,逐渐增加特征数量并减少输入图像的空间维度。

在该forward方法中,输入图像 (x) 通过鉴别器的连续层,由于最后的 sigmoid 激活,输出表示输入为真 (1) 或假 (0) 的概率。

鉴别器的架构使其能够区分真假图像,使其成为 DCGAN 对抗训练过程的重要组成部分。

创建一个函数来初始化权重:

def initialize_weights(model):classname = model.__class__.__name__if classname.find('Conv') != -1:nn.init.normal_(model.weight.data, 0.0, 0.02)elif classname.find('BatchNorm') != -1:nn.init.normal_(model.weight.data, 1.0, 0.02)nn.init.constant_(model.bias.data, 0)

在此函数中,我们接收 amodel作为输入,它可以引用生成器或鉴别器网络。我们迭代模型的各层并根据层类型初始化权重。这些权重是由 DCGAN 论文建议的。

对于卷积层 ( Conv),我们使用nn.init.normal_平均值 0 和标准差 0.02 来初始化权重。

对于批量归一化层 ( BatchNorm),我们使用 来初始化权重,平均值为 1,标准差为 0.02 nn.init.normal_,并使用 来将偏差设置为 0 nn.init.constant_。

通过调用此函数并将生成器和鉴别器网络作为参数传递,您可以确保网络的权重得到适当初始化以训练 DCGAN 模型。

gen = Generator(Z_DIM, CHANNELS_IMG, FEATURES_GEN).to(device)
disc = Discriminator(CHANNELS_IMG, FEATURES_DISC).to(device)initialize_weights(gen)
initialize_weights(disc)

gen现在,我们通过传递潜在空间的维度 ( Z_DIM)、输出图像中的通道数 ( CHANNELS_IMG) 以及生成器中的特征数量 ( FEATURES_GEN)来创建生成器网络 ( ) 的实例。disc类似地,我们通过指定输入通道的数量 ( CHANNELS_IMG) 和鉴别器中的特征数量 ( )创建鉴别器网络 ( ) 的实例FEATURES_DISC。

创建网络实例后,我们调用initialize_weights生成器和鉴别器网络上的函数,根据 DCGAN 论文中建议的权重初始化技术来初始化它们的权重。

通过执行此代码,您将准备好生成器和鉴别器网络,并正确初始化它们的权重,用于训练 DCGAN 模型。

opt_gen = optim.Adam(gen.parameters(), lr=LEARNING_RATE, betas=(0.5, 0.999))
opt_disc = optim.Adam(disc.parameters(), lr=LEARNING_RATE, betas=(0.5, 0.999))
criterion = nn.BCELoss()fixed_noise = torch.randn(32, Z_DIM, 1, 1).to(device)

我们为生成器和鉴别器网络定义了优化器。我们使用模块中的 Adam 优化器torch.optim。生成器优化器 ( opt_gen) 使用生成器参数、学习率LEARNING_RATE以及 Adam 优化器的 beta 参数(0.5 和 0.999)进行初始化。

类似地,判别器优化器 ( opt_disc) 使用判别器的参数、相同的学习率和 beta 参数进行初始化。

接下来,我们定义对抗训练过程的损失标准。在这里,我们使用二元交叉熵损失 (Binary Cross Entropy Loss nn.BCELoss()),它在 GAN 中常用来将判别器的预测与真实标签进行比较。

最后,我们创建一个固定噪声张量 ( fixed_noise),用于在训练过程中生成样本图像。该torch.randn函数根据正态分布生成随机数。

通过设置优化器、损失准则和固定噪声张量,您就可以开始训练 DCGAN 模型了。

def show_tensor_images(image_tensor, num_images=32, size=(1, 64, 64)):image_tensor = (image_tensor + 1) / 2image_unflat = image_tensor.detach().cpu()image_grid = make_grid(image_unflat[:num_images], nrow=4)plt.imshow(image_grid.permute(1, 2, 0).squeeze())plt.show()

“show_tensor_images”函数是一个实用函数,它获取图像张量,对它们进行标准化,创建图像网格,并使用 matplotlib 显示它们,以便在训练过程中轻松可视化。

训练模型:

gen.train()
disc.train()for epoch in range(NUM_EPOCHS):for batch_idx, (real, _ ) in enumerate(dataloader):real = real.to(device)### create noise tensornoise = torch.randn((BATCH_SIZE, Z_DIM, 1, 1)).to(device)fake = gen(noise)### Train Discriminator: max log(D(x)) + log(1 - D(G(z)))disc_real = disc(real).reshape(-1)loss_disc_real = criterion(disc_real, torch.ones_like(disc_real))disc_fake = disc(fake.detach()).reshape(-1)loss_disc_fake = criterion(disc_fake, torch.zeros_like(disc_fake))loss_disc = (loss_disc_real + loss_disc_fake) / 2disc.zero_grad()loss_disc.backward()opt_disc.step()### Train Generator: min log(1 - D(G(z))) <-> max log(D(G(z))output = disc(fake).reshape(-1)loss_gen = criterion(output, torch.ones_like(output))gen.zero_grad()loss_gen.backward()opt_gen.step()### Print losses occasionally and fake images occasionallyif batch_idx % 50 == 0:print(f"Epoch [{epoch}/{NUM_EPOCHS}] Batch {batch_idx}/{len(dataloader)} \Loss D: {loss_disc:.4f}, loss G: {loss_gen:.4f}")with torch.no_grad():fake = gen(fixed_noise)img_grid_real = torchvision.utils.make_grid(real[:32], normalize=True)img_grid_fake = torchvision.utils.make_grid(fake[:32], normalize=True)show_tensor_images(img_grid_fake)

我们可以将本次培训分为四个部分以便更好地理解。

  1. 噪声生成:随机噪声 ( noise) 使用形状为 的正态分布生成(BATCH_SIZE, Z_DIM, 1, 1)。
  2. 判别器训练:判别器网络是通过评估真实图像 ( ) 并根据判别器与地面真实标签(全部)的预测real计算损失 ( ) 来训练的。loss_disc_real假图像 ( fake) 是通过将噪声传递到生成器网络来生成的。评估鉴别器对假图像 ( ) 的预测,并根据与地面真实标签(全零)相比的预测来计算disc_fake损失 ( ) 。loss_disc_fake平均损失 ( ) 计算为和loss_disc的平均值。判别器参数的梯度设置为零,反向传播损失,并更新判别器的优化器。loss_disc_realloss_disc_fake
  3. 生成器训练:生成器网络是通过fake使用噪声生成假图像( )来训练的。获得判别器对假图像 ( ) 的预测,并根据与地面真实标签(全部)相比的预测来计算output损失 ( )。loss_gen生成器参数的梯度设置为零,反向传播损失,并更新生成器的优化器。
  4. 进度跟踪和图像可视化:每 50 个批次后,打印当前纪元、批次索引、鉴别器损失 ( loss_disc) 和生成器损失 ( )。loss_gen样本图像是通过将固定噪声传递到生成器网络来生成的。真实图像和生成图像都被转换为图像网格,然后显示图像网格以可视化生成器网络的学习进度。

每个时期生成的假图像:

Starting of the first epoch:Starting of the first epoch
After first epoch:
在这里插入图片描述
After second epoch:
在这里插入图片描述
After third epoch:
在这里插入图片描述
After fourth epoch:
在这里插入图片描述
End results ( After 5 epochs):
在这里插入图片描述

结论: 如果您能够获得更好的结果,

  1. 增加模型容量:在生成器和鉴别器网络中添加更多层或增加滤波器数量,以增强模型学习复杂模式并生成更高质量图像的能力。
  2. 利用更深的卷积层:实施ResNet 或 DenseNet 等更深层次的架构来捕获更复杂的特征和纹理,从而提高图像质量。
  3. 使用更大的数据集:在更大、更多样化的数据集上训练 DCGAN 可以帮助模型学习更广泛的图像变化,并提高其生成高分辨率图像的能力。
  4. 调整训练参数:试验学习率、批量大小和训练迭代等超参数,以优化训练过程并提高模型生成更高分辨率图像的能力。

博文译自Manohar Kedamsetti的博客。

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

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

相关文章

网络安全等级保护收费标准?

不同省份价格会略有不同&#xff0c;二级等保一般不低于5万元;三级等保不低于9万元&#xff0c;个别省份也可能7万也能办理&#xff0c;根据企业实际情况和省市选定的代理机构确定。 等级保护二级? 第二级等保是指信息系统受到破坏后&#xff0c;会对公民、法人和其他组织的合…

《YOLOv8创新改进》专栏指导书册 手把手创新教程

&#x1f680;&#x1f680;&#x1f680;YOLOv8改进专栏&#xff1a;http://t.csdnimg.cn/hGhVK 学姐带你学习YOLOv8&#xff0c;从入门到创新&#xff0c;轻轻松松搞定科研&#xff1b; 本专栏为订阅者提供答疑服务&#xff0c;每一篇提供源代码和详细的每一个步骤改进地方。…

Navicat 技术指引 | 适用于 GaussDB 的模型功能

Navicat Premium&#xff08;16.2.8 Windows版或以上&#xff09; 已支持对 GaussDB 主备版的管理和开发功能。它不仅具备轻松、便捷的可视化数据查看和编辑功能&#xff0c;还提供强大的高阶功能&#xff08;如模型、结构同步、协同合作、数据迁移等&#xff09;&#xff0c;这…

工业交换机具备哪些功能?

在工业网络中&#xff0c;工业交换机起着至关重要的作用&#xff0c;具备多样功能和广泛的应用。 1、工业交换机的作用是实现不同网络设备之间的互联。它能够连接各种不同类型的设备&#xff0c;如计算机、服务器、传感器和监控设备&#xff0c;实现设备间的相互通信和数据传输…

应用高斯高通滤波器提取图像轮廓

任务要求&#xff1a; 图为HALCON中的例图“tooth_rim”&#xff0c;请用高斯高通滤波器提取图像的轮廓。 任务分析&#xff1a; 图像的边缘对应频谱的高频部分&#xff0c;可以通过构造一个高频滤波器&#xff0c;过滤掉图像的低频部分&#xff0c;从而得到图像的边缘。HALC…

苹果怎么关闭悬浮球?让我来解答您的疑惑!

悬浮球是苹果设备上的一种可进行自定义的快捷操作功能&#xff0c;它可以位于手机屏幕的任意位置&#xff0c;以浮动的方式显示。然而&#xff0c;有时候悬浮球对某些朋友来说可能会变得多余&#xff0c;那么苹果怎么关闭悬浮球呢&#xff1f;接下来&#xff0c;小编将为大家揭…

docker compose搭建渗透测试vulstudy靶场示例

前言 渗透测试&#xff08;Penetration test&#xff09;即网络安全工程师/安全测试工程师/渗透测试工程师通过模拟黑客&#xff0c;在合法授权范围内&#xff0c;通过信息搜集、漏洞挖掘、权限提升等行为&#xff0c;对目标对象进行安全测试&#xff08;或攻击&#xff09;&am…

详解——菱形继承及菱形虚拟继承

目录 一&#xff0c;菱形继承 1.1单继承 1.2多继承 1.3菱形继承 1.4菱形继承的问题 1.5虚拟继承解决数据冗余和二义性的原理 二.继承的总结和反思 一&#xff0c;菱形继承 C三大特性——继承-CSDN博客 1.1单继承 单继承&#xff1a;一个子类只有一个直接父类时称这个继…

anaconda安装配置

创建分区 conda create -n cpu 安装Cpu版本 https://pytorch.org/ conda install pytorch torchvision torchaudio cpuonly -c pytorch 激活环境 conda activate cpu 验证 退出当前分区 conda deactivate 安装GPU版本 创建分区conda create -n gpu 激活环境 conda…

Java面向对象(高级)-- final关键字的使用

文章目录 一、 final的意义二、 final的使用&#xff08;1&#xff09; final修饰类&#xff08;2&#xff09; final修饰方法&#xff08;3&#xff09; final修饰变量1. 修饰成员变量1.1 举例11.2 举例2 2. 修饰局部变量2.1 举例12.2 举例2 &#xff08;4&#xff09;final搭…

java协程操作mysql数据库

我的项目&#xff1a; nanshaws/nettyWeb: 复习一下netty&#xff0c;并打算做一个web项目出来 (github.com) 最近在项目中分别添加了虚拟线程操作mysql数据库&#xff0c;和用协程操作mysql数据库 同理先跟我这个博客操作一下前面的&#xff1a;就单纯代码的时候进行修改&a…

TikTok与精神健康:社交媒体在压力时代的作用

在当今数字化和社交化的时代&#xff0c;社交媒体已成为人们生活中不可或缺的一部分。其中&#xff0c;TikTok作为一款备受欢迎的短视频应用&#xff0c;不仅改变了人们的娱乐方式&#xff0c;也对精神健康产生了深远的影响。 本文将深入探讨TikTok在压力时代对精神健康的作用…

2023年中国油田工程建设市场规模现状及行业竞争分析[图]

油田工程建设是在确定油气田有开发生产的价值的基础上&#xff0c;进行系统的工程建设&#xff0c;油田工程建设包括井场建设、管道施工、土石方工程、道路建设及绿化等服务。 油田工程建设主要内容 资料来源&#xff1a;共研产业咨询&#xff08;共研网&#xff09; 油田服务…

抖音商城小程序源码系统 附带完整的搭建教程

大家好啊&#xff0c;今天小编来给大家分享一款抖音商城小程序源码系统。这可是当下最热门的的项目之一。。抖音作为国内最大的短视频平台之一&#xff0c;拥有庞大的用户群体和丰富的社交功能。为了满足用户在抖音上购物和交易的需求&#xff0c;抖音商城小程序应运而生。 以…

租车系统开发/多功能租车平台微信小程序源码/汽车租赁系统源码/汽车租赁小程序系统

源码介绍&#xff1a; 多功能租车平台微信小程序源码&#xff0c;作为汽车租赁、摩托车租车平台系统源码&#xff0c;是小程序系统。基于微信小程序的汽车租赁系统源码。 开发环境及工具&#xff1a; 大等于jdk1.8&#xff0c;大于mysql5.5&#xff0c;idea&#xff08;eclip…

拆解:淘宝客新玩法之微信淘礼金创建怎么做

最近看到一种新的淘宝客玩法&#xff0c;迫不及待的想分享给大家。微信公众号查券大家都不陌生&#xff0c;也有不少人都在做这个。最近看到有人在做微信公众号创建淘礼金。之所以说这个玩法新是因为目前大多数淘客还在做返利。返利有周期长、提现有门槛等痛点。 微信公众号创建…

基于Springcloud微服务框架智慧工地系统源码

建筑行业快速发展&#xff0c;各建筑工程的建设规模在不断扩大&#xff0c;各岗位工作人员的工作内容所涉及的方面也越来越广泛。随着信息技术水平不断提高,人工记录的方式已经不能够满足大项目的管理要求&#xff0c;就此&#xff0c;创造出一种新型的施工管理技术——智慧工地…

携程token

网址&#xff1a;https://flights.ctrip.com/ 记录一下这个要我狗命的token 原本以为解决验证码就能继续查机票信息&#xff0c;奈何太年轻&#xff0c;或者说原本以为这个头部信息的token不重要&#xff0c;其实还是很重要的。 关于查价格 &#xff0c;如果说查询频繁之后就…

小型内衣裤洗衣机哪个牌子好?性价比小型洗衣机推荐

内衣内裤应该如何清洗才能实现在不伤衣的同时有能够洗干净呢&#xff1f;其实除了使用温水搭配手洗以外&#xff0c;还有一些清洗方式&#xff0c;那就是选择一台专门为内衣定制的内衣洗衣机。目前内衣洗衣机由于精致小巧&#xff0c;方便安装&#xff0c;方便使用&#xff0c;…

PC分页操作以及loading效果

page-size 每页显示条目个数 current-page 当前页数 total 数据总数 current-change【currentPage 改变时会触发】 切换分页时会先加载&#xff0c;等在接口数据&#xff0c;接口返回&#xff0c;加载会关闭&#xff08;在获取接口数据完毕哪里加上this.loadingfalse&#xff0…