【人工智能Ⅱ】实验8:生成对抗网络

news2025/1/20 14:59:38

实验8:生成对抗网络

一:实验目的

1:理解生成对抗网络的基本原理。

2:学会构建改进的生成对抗网络,如DCGAN、WGAN、WGAN-GP等。

3:学习在更为真实的数据集上应用生成对抗网络的方法。

二:实验要求

1:理解生成对抗网络改进算法的改进内容和改进目的。

2:参考课程资源中的2024年春第八次实验代码,完成生成对抗网络改进算法WGAN或DCGAN网络的实现。

3:在Fashion MNIST数据集上验证生成对抗网络改进算法的效果,并对其进行调优。

4:在玉米数据集上验证生成对抗网络改进算法在真实场景下对复杂数据集的生成结果。(选做)

5:撰写实验报告,对结果进行分析。

三:实验环境

本实验所使用的环境条件如下表所示。

操作系统

Ubuntu(Linux)

程序语言

Python(3.11.4)

第三方依赖

torch, torchvision, matplotlib等

四:实验原理

1:GAN

GAN的中文名称为生成对抗网络。GAN是一种深度学习模型,由一个生成器网络和一个判别器网络组成,它们相互竞争地学习生成逼真的数据样本。GAN的核心思想是通过对抗训练来使生成器生成逼真的数据样本,同时训练判别器来区分真实数据样本和生成的数据样本。

【1】生成器网络

生成器网络的目标是接收一个随机噪声向量(通常服从某种先验分布,如均匀分布或正态分布)作为输入,并生成与真实数据样本相似的假数据样本。生成器网络通常由一系列反卷积层(也称为转置卷积层)组成,用于逐渐将输入噪声向量映射到数据空间。生成器网络的输出通常通过某种激活函数(如sigmoid、tanh等)进行转换,以确保生成的数据在合适的范围内。


生成器的训练过程如下图所示。

【2】判别器网络

判别器网络的目标是接收真实数据样本或生成的假数据样本作为输入,并输出一个标量值,表示输入数据是真实数据样本的概率。判别器网络通常由一系列卷积层组成,用于从输入数据中提取特征,并最终将这些特征映射到一个标量输出。判别器的输出通常通过sigmoid激活函数进行转换,将其限制在0到1之间,以表示输入数据是真实数据样本的概率。


判别器的训练过程如下图所示。

【3】对抗训练

在对抗训练中,生成器和判别器网络相互竞争,以改善其性能。生成器试图生成越来越逼真的假数据样本,以欺骗判别器,使其无法区分生成的假数据样本和真实数据样本。而判别器则试图提高其准确性,以尽可能准确地区分真实数据样本和生成的假数据样本。这种竞争的动态最终导致了生成器生成逼真的数据样本。

【4】损失函数

生成对抗网络使用两个损失函数来训练生成器和判别器。对于判别器,损失函数通常是二元交叉熵损失函数,用于衡量判别器在真实数据样本和生成的假数据样本上的分类性能。对于生成器,损失函数通常是判别器在生成的假数据样本上的输出与真实标签(即1)之间的二元交叉熵损失函数。通过最小化生成器和判别器的损失函数,可以实现对抗训练。

2:GAN的变种

目前GAN的变体主要从网络结构、条件生成网络、图像翻译、归一化和限制、损失函数、评价指标等方面进行改进。

变体的发展过程如下图所示。

其中,DCGAN(Deep Convolutional Generative Adversarial Networks)、WGAN(Wasserstein Generative Adversarial Networks)和 WGAN-GP(Wasserstein Generative Adversarial Networks with Gradient Penalty)都是GAN的常见变体,用于生成逼真的图像。

上述三种GAN变种的对比如下:

【1】损失函数

DCGAN:DCGAN使用交叉熵损失函数来训练生成器和判别器。

WGAN:WGAN引入了Wasserstein距离作为生成器和判别器之间的损失函数。Wasserstein距离能够更好地衡量生成分布和真实分布之间的差异,从而提高了训练的稳定性。

WGAN-GP:WGAN-GP在WGAN的基础上引入了梯度惩罚项,用于限制判别器的梯度,从而进一步提高了训练的稳定性和生成图像的质量。

【2】训练稳定性

DCGAN:DCGAN在训练过程中可能会出现训练不稳定的问题,例如模式崩溃(mode collapse)和梯度消失等。

WGAN:WGAN的损失函数设计使其更加稳定,可以缓解训练过程中出现的模式崩溃和梯度消失等问题,有助于生成更加高质量和多样化的图像。

WGAN-GP:WGAN-GP进一步改进了WGAN的稳定性,通过梯度惩罚项有效地限制了判别器的梯度,减轻了训练过程中的梯度爆炸和梯度消失问题。

五:算法流程

  1. 数据准备。准备训练所需的Fashion MNIST数据集。
  2. 网络构建。利用PyTorch框架搭建不同GAN的判别器和生成器。
  3. 可视化数据。导出生成器和判别器随着迭代次数所变化的损失曲线图像,同时利用生成器生成图像。

六:实验展示

1:DCGAN在Fashion MNIST数据集上的应用

DCGAN的生成器网络构建,如下图所示。

DCGAN的判别器网络构建,如下图所示。

DCGAN使用的损失函数为BCE损失函数,优化器使用Adam,优化器的学习率为0.0002,训练迭代次数为30次。

DCGAN中判别器和生成器的损失曲线,如下图所示。其中,橘色部分为生成器、蓝色部分为判别器。

DCGAN的生成效果,如下图所示。

2:WGAN在Fashion MNIST数据集上的应用

    WGAN的生成器网络构建,如下图所示。

WGAN的判别器网络构建,如下图所示。

WGAN使用的损失函数为Wasserstein距离损失函数,优化器使用RMSprop,优化器的学习率为0.00005,训练迭代次数为30次。

WGAN中判别器和生成器的损失曲线,如下图所示。其中,橘色部分为生成器、蓝色部分为判别器。

WGAN的生成效果,如下图所示。

3:DCGAN在大米数据集上的应用

DCGAN的超参数和训练过程与第1部分类似,但是迭代次数变为了500,加载数据集时将图像尺寸压缩为了28*28。


DCGAN中判别器和生成器的损失曲线,如下图所示。其中,橘色部分为生成器、蓝色部分为判别器。


DCGAN的生成效果,如下图所示。生成的图像中包含4粒大米。


源数据集的图像样本如下。

4:DCGAN在玉米数据集上的应用

DCGAN的超参数和训练过程与第1部分类似,但是迭代次数变为了500,加载数据集时将图像尺寸压缩为了28*28。


DCGAN中判别器和生成器的损失曲线,如下图所示。其中,橘色部分为生成器、蓝色部分为判别器。


DCGAN的生成效果,如下图所示。生成的图像中包含4个玉米。


源数据集的图像样本如下。

七:实验结论与心得

1:生成对抗网络利用生成器和判别器之间的对抗训练机制,能够有效地生成逼真的数据样本,在图像生成、文本生成、图像转换等领域广泛应用。

2:GAN的性能很大程度上受到超参数的影响,如学习率、潜在空间维度、网络结构等。

3:GAN相比较其他生成模型(玻尔兹曼机等),只用到了反向传播,不需要复杂的马尔科夫链,且可以产生更加清晰、真实的样本。

4:GAN采用无监督的学习方式训练,可以被广泛用在无监督学习和半监督学习领域。

5:如果生成器生成的样本,判别器判定为真实的,则说明生成器的效果是较好的,因而可以用判别器来评价生成器,即判别的性能越差,说明生成器的性能越好。

八:主要代码

1:DCGAN源代码

import torch

from torch import nn, optim

from torchvision import datasets, transforms, utils

from torch.utils.data import DataLoader

import matplotlib.pyplot as plt

# 设备配置

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

# 数据预处理

transform = transforms.Compose([

    transforms.ToTensor(),

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

])

# 加载数据集

train_data = datasets.FashionMNIST(root='./data', train=True, download=True, transform=transform)

train_loader = DataLoader(train_data, batch_size=128, shuffle=True)

# 生成器

class Generator(nn.Module):

    def __init__(self):

        super(Generator, self).__init__()

        self.main = nn.Sequential(

            # 输入是一个 100 维的噪声向量,我们将其投射并reshape 1x1x128 的大小

            nn.Linear(100, 128*7*7),

            nn.BatchNorm1d(128*7*7),

            nn.ReLU(True),

            nn.Unflatten(1, (128, 7, 7)),

            nn.ConvTranspose2d(128, 64, 4, stride=2, padding=1),

            nn.BatchNorm2d(64),

            nn.ReLU(True),

            nn.ConvTranspose2d(64, 1, 4, stride=2, padding=1),

            nn.Tanh()

        )

    def forward(self, x):

        return self.main(x)

# 判别器

class Discriminator(nn.Module):

    def __init__(self):

        super(Discriminator, self).__init__()

        self.main = nn.Sequential(

            nn.Conv2d(1, 64, 4, stride=2, padding=1),

            nn.LeakyReLU(0.2, inplace=True),

            nn.Conv2d(64, 128, 4, stride=2, padding=1),

            nn.BatchNorm2d(128),

            nn.LeakyReLU(0.2, inplace=True),

            nn.Flatten(),

            nn.Linear(128*7*7, 1),

            nn.Sigmoid()

        )

    def forward(self, x):

        return self.main(x)

# 实例化模型

netG = Generator().to(device)

netD = Discriminator().to(device)

# 损失函数和优化器

criterion = nn.BCELoss()

optimizerD = optim.Adam(netD.parameters(), lr=0.0002, betas=(0.5, 0.999))

optimizerG = optim.Adam(netG.parameters(), lr=0.0002, betas=(0.5, 0.999))

# 训练

num_epochs = 30

lossD = []

lossG = []

for epoch in range(num_epochs):

    for i, (images, _) in enumerate(train_loader):

        # 更新判别器:maximize log(D(x)) + log(1 - D(G(z)))

        netD.zero_grad()

        real_data = images.to(device)

        batch_size = real_data.size(0)

        labels = torch.full((batch_size,), 1, dtype=torch.float, device=device)

        output = netD(real_data)

        labels = labels.view(-1, 1)

        lossD_real = criterion(output, labels)

        lossD_real.backward()

        noise = torch.randn(batch_size, 100, device=device)

        fake_data = netG(noise)

        labels.fill_(0)

        output = netD(fake_data.detach())

        lossD_fake = criterion(output, labels)

        lossD_fake.backward()

        optimizerD.step()

        # 更新生成器:minimize log(1 - D(G(z))) ≈ maximize log(D(G(z)))

        netG.zero_grad()

        labels.fill_(1)  # fake labels are real for generator cost

        output = netD(fake_data)

        loss_G = criterion(output, labels)

        loss_G.backward()

        optimizerG.step()

       

        lossD.append(lossD_real.item() + lossD_fake.item())

        lossG.append(loss_G.item())

        if (i+1) % 100 == 0:

            print(f'Epoch [{epoch+1}/{num_epochs}], Step [{i+1}/{len(train_loader)}], Loss_D: {lossD_real.item() + lossD_fake.item():.4f}, Loss_G: {loss_G.item():.4f}')

# 可视化一些生成的图片

noise = torch.randn(64, 100, device=device)

fake_images = netG(noise)

fake_images = fake_images.reshape(fake_images.size(0), 1, 28, 28)

fake_images = (fake_images + 1) / 2  # 调整像素值范围到 [0, 1]

img_grid = utils.make_grid(fake_images, normalize=True)

img_grid = img_grid.cpu()  # 首先将张量移至 CPU

plt.imshow(img_grid.permute(1, 2, 0).numpy())

plt.savefig("z.png")

plt.close()

# 绘制曲线

y_values1 = lossD

y_values2 = lossG

x_values = range(1, len(y_values1) + 1)

plt.plot(x_values, y_values1, label='Discriminator Loss')

plt.plot(x_values, y_values2, label='Generator Loss')

# 添加标题和标签

plt.title('loss for discriminator and generator')

plt.xlabel('Batch')

plt.ylabel('Loss')

plt.legend(['Discriminator', 'Generator'])

# 显示图形

plt.savefig('loss-DCGAN.png')

2:WGAN源代码

import torch

import torch.nn as nn

import torch.optim as optim

from torchvision import datasets, transforms

import matplotlib.pyplot as plt

# 设备配置

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

# 定义生成器网络

class Generator(nn.Module):

    def __init__(self, latent_dim, img_shape):

        super(Generator, self).__init__()

        self.model = nn.Sequential(

            nn.Linear(latent_dim, 128),

            nn.LeakyReLU(0.2, inplace=True),

            nn.Linear(128, 256),

            nn.BatchNorm1d(256),

            nn.LeakyReLU(0.2, inplace=True),

            nn.Linear(256, img_shape),

            nn.Tanh()

        )

    def forward(self, z):

        z = z.to(next(self.parameters()).device)

        img = self.model(z)

        return img

# 定义判别器网络

class Discriminator(nn.Module):

    def __init__(self, img_shape):

        super(Discriminator, self).__init__()

        self.model = nn.Sequential(

            nn.Linear(img_shape, 256),

            nn.LeakyReLU(0.2, inplace=True),

            nn.Linear(256, 128),

            nn.BatchNorm1d(128),

            nn.LeakyReLU(0.2, inplace=True),

            nn.Linear(128, 1)

        )

    def forward(self, img):

        validity = self.model(img)

        return validity

# 参数

latent_dim = 100

img_shape = 28 * 28

batch_size = 64

# 准备数据

transform = transforms.Compose([

    transforms.ToTensor(),

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

])

train_dataset = datasets.FashionMNIST(root='./data', train=True, transform=transform, download=True)

train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=batch_size, shuffle=True)

# 初始化网络和优化器

generator = Generator(latent_dim, img_shape).to(device)

discriminator = Discriminator(img_shape).to(device)

optimizer_G = optim.RMSprop(generator.parameters(), lr=0.00005)

optimizer_D = optim.RMSprop(discriminator.parameters(), lr=0.00005)

# 训练模型

lossD = []

lossG = []

n_epochs = 30

for epoch in range(n_epochs):

    for i, (imgs, _) in enumerate(train_loader):

        # 训练判别器

        optimizer_D.zero_grad()

        # 真实图像

        real_imgs = imgs.view(-1, img_shape).to(device)

        validity_real = discriminator(real_imgs)

       

        # 生成潜在空间向量

        z = torch.randn(batch_size, latent_dim).to(device)

        fake_imgs = generator(z).detach()

        validity_fake = discriminator(fake_imgs)

        # 计算损失

        d_loss = -torch.mean(validity_real) + torch.mean(validity_fake)

        d_loss_item = d_loss.item()

       

        # 反向传播和优化

        d_loss.backward()

        optimizer_D.step()

        # 限制判别器参数

        for p in discriminator.parameters():

            p.data.clamp_(-0.01, 0.01)

        # 训练生成器

        optimizer_G.zero_grad()

        # 生成潜在空间向量

        z = torch.randn(batch_size, latent_dim)

        fake_imgs = generator(z)

        validity = discriminator(fake_imgs)

        # 计算损失

        g_loss = -torch.mean(validity)

        g_loss_item = g_loss.item()

        # 反向传播和优化

        g_loss.backward()

        optimizer_G.step()

        lossD.append(d_loss.item())

        lossG.append(g_loss.item())

       

        # 打印损失信息

        if i % 500 == 0:

            print(

                "[Epoch %d/%d] [Batch %d/%d] [D loss: %.4f] [G loss: %.4f]"

                % (epoch, n_epochs, i, len(train_loader), d_loss.item(), g_loss.item())

            )

# 生成图像

z = torch.randn(64, latent_dim, device=device)

generated_images = generator(z)

generated_images = generated_images.detach().cpu().numpy()

# 显示生成的图像

fig, axes = plt.subplots(nrows=8, ncols=8, figsize=(10, 10))

for i, ax in enumerate(axes.flatten()):

    ax.imshow(generated_images[i].reshape(28, 28), cmap='gray')

    ax.axis('off')

plt.tight_layout()

plt.savefig('zz.png')

plt.close()

# 绘制曲线

y_values1 = lossD

y_values2 = lossG

x_values = range(1, len(y_values1) + 1)

plt.plot(x_values, y_values1, label='Discriminator Loss')

plt.plot(x_values, y_values2, label='Generator Loss')

# 添加标题和标签

plt.title('loss for discriminator and generator')

plt.xlabel('Batch')

plt.ylabel('Loss')

plt.legend(['Discriminator', 'Generator'])

# 显示图形

plt.savefig('loss-WGAN.png')

3:玉米数据集上的DCGAN

import torch

from torch import nn, optim

from torchvision import transforms, utils

import matplotlib.pyplot as plt

import os

from PIL import Image

from torch.utils.data import Dataset, DataLoader

class CustomDataset(Dataset):

    def __init__(self, data_dir, transform=None):

        self.data_dir = data_dir

        self.transform = transform

        self.image_files = os.listdir(data_dir)

    def __len__(self):

        return len(self.image_files)

    def __getitem__(self, idx):

        img_name = os.path.join(self.data_dir, self.image_files[idx])

        image = Image.open(img_name).convert("RGB")  # 读取图像,并转换为RGB格式

        if self.transform:

            image = self.transform(image)

        return image

# 数据集文件夹路径

data_dir = r"/home/ubuntu/zz-test"

# 设备配置

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

# 数据预处理

transform = transforms.Compose([

    transforms.Resize((28, 28)),  # 将图像调整为28x28大小

    transforms.ToTensor(),

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

])

# 加载数据集

train_data = CustomDataset(data_dir, transform=transform)

train_loader = DataLoader(train_data, batch_size=32, shuffle=True)

# 生成器

class Generator(nn.Module):

    def __init__(self):

        super(Generator, self).__init__()

        self.main = nn.Sequential(

            nn.Linear(100, 128*7*7),

            nn.BatchNorm1d(128*7*7),

            nn.ReLU(True),

            nn.Unflatten(1, (128, 7, 7)),

            nn.ConvTranspose2d(128, 64, 4, stride=2, padding=1),

            nn.BatchNorm2d(64),

            nn.ReLU(True),

            nn.ConvTranspose2d(64, 3, 4, stride=2, padding=1),  # 修改这里的输出通道数为3

            nn.Tanh()

        )

    def forward(self, x):

        return self.main(x)

# 判别器

class Discriminator(nn.Module):

    def __init__(self):

        super(Discriminator, self).__init__()

        self.main = nn.Sequential(

            nn.Conv2d(3, 64, 4, stride=2, padding=1),  # 修改这里的输入通道数为3

            nn.LeakyReLU(0.2, inplace=True),

            nn.Conv2d(64, 128, 4, stride=2, padding=1),

            nn.BatchNorm2d(128),

            nn.LeakyReLU(0.2, inplace=True),

            nn.Flatten(),

            nn.Linear(128*7*7, 1),

            nn.Sigmoid()

        )

    def forward(self, x):

        return self.main(x)

# 实例化模型

netG = Generator().to(device)

netD = Discriminator().to(device)

# 损失函数和优化器

criterion = nn.BCELoss()

optimizerD = optim.Adam(netD.parameters(), lr=0.0002, betas=(0.5, 0.999))

optimizerG = optim.Adam(netG.parameters(), lr=0.0002, betas=(0.5, 0.999))

# 训练

num_epochs = 500

lossD = []

lossG = []

for epoch in range(num_epochs):

    for i, images in enumerate(train_loader):

        # 更新判别器:maximize log(D(x)) + log(1 - D(G(z)))

        netD.zero_grad()

        real_data = images.to(device)

        batch_size = real_data.size(0)

        labels = torch.full((batch_size,), 1, dtype=torch.float, device=device)

        output = netD(real_data)

        labels = labels.view(-1, 1)

        lossD_real = criterion(output, labels)

        lossD_real.backward()

        noise = torch.randn(batch_size, 100, device=device)

        fake_data = netG(noise)

        labels.fill_(0)

        output = netD(fake_data.detach())

        lossD_fake = criterion(output, labels)

        lossD_fake.backward()

        optimizerD.step()

        # 更新生成器:minimize log(1 - D(G(z))) ≈ maximize log(D(G(z)))

        netG.zero_grad()

        labels.fill_(1)  # fake labels are real for generator cost

        output = netD(fake_data)

        loss_G = criterion(output, labels)

        loss_G.backward()

        optimizerG.step()

       

        lossD.append(lossD_real.item() + lossD_fake.item())

        lossG.append(loss_G.item())

        if (i+1) % 100 == 0:

            print(f'Epoch [{epoch+1}/{num_epochs}], Step [{i+1}/{len(train_loader)}], Loss_D: {lossD_real.item() + lossD_fake.item():.4f}, Loss_G: {loss_G.item():.4f}')

# 保存生成的图像

noise = torch.randn(4, 100, device=device)

fake_images = netG(noise)

fake_images = (fake_images + 1) / 2  # 调整像素值范围到 [0, 1]

img_grid = utils.make_grid(fake_images, nrow=2, normalize=True)  # 将图像网格化,并且每行显示8张图像

img_grid = img_grid.permute(1, 2, 0).cpu().numpy()  # 将张量转换为NumPy数组,并将通道维度放到最后

plt.imshow(img_grid)

plt.axis('off')  # 关闭坐标轴

plt.savefig("generated_images.png")

plt.close()

# 绘制损失曲线

plt.plot(lossD, label='Discriminator Loss')

plt.plot(lossG, label='Generator Loss')

# 添加标题和标签

plt.title('Loss for Discriminator and Generator')

plt.xlabel('Batch')

plt.ylabel('Loss')

plt.legend()

# 保存损失曲线图

plt.savefig('loss-DCGAN.png')

plt.close()

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

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

相关文章

Vue2学习(04)

目录 一、组件的三大组成部分 二、组件的样式冲突scoped 三、scoped原理 ​编辑 四、data是一个函数 五、组件通信 六、props详解 七、非父子通信 1.eventbus事件总线(可以一传多)--->作用是在非父子组件之间,进行简易的消息传递(复杂场景---&…

深拷贝、浅拷贝、引用拷贝

深拷贝和浅拷贝的区别 1. 引用拷贝2. 对象拷贝 1. 引用拷贝 两个对象指向同一个地址值。 创建一个指向对象的引用变量的拷贝Teacher teacher new Teacher("Taylor",26); Teacher otherteacher teacher; System.out.println(teacher); System.out.println(otherte…

【面试干货】如何选择MySQL数据库存储引擎(MyISAM 或 InnoDB)

【面试干货】如何选择MySQL数据库存储引擎(MyISAM 或 InnoDB) 💖The Begin💖点点关注,收藏不迷路💖 MySQL数据库存储引擎是一个 关键 的考虑因素。MySQL提供了多种存储引擎,其中最常用的是 MyISAM 和 InnoD…

[word] word表格如何设置外框线和内框线 #媒体#笔记

word表格如何设置外框线和内框线 点击表格的左上角按钮从而选中表格 点击边框按钮边上的下拉箭头,选择边框和底纹 点击颜色边上的下拉箭头,选择红色 点击取消掉中间的边框,只保留外围边框 点击颜色边上的下拉箭头,选择另外一个颜…

2013.8.5-2024.5.10碳排放权交易明细数据

2013.8.5-2024.5.10碳排放权交易明细数据 1、时间:2013.8.5-2024.5.10 2、来源:各碳排放交易所 3、范围:各交易所城市 4、指标:行政区划代码、地区、所属省份、交易日期、交易品种、开盘价_元、最高价_元、最低价_元、成交均价…

【全部更新完毕】2024全国大学生数据统计与分析竞赛A题思路代码文章教学数学建模-抖音用户评论的文本情感分析

文章摘要部分: A 题: 抖音用户评论的文本情感分析 摘要 随着短视频平台的迅猛发展,抖音已成为全球最受欢迎的短视频分享平台之一。然而,随着用户数量和使用时长的增加,抖音团队需要不断优化平台功能、提升用户体验&…

生成纳秒级别的时间戳,高性能

问题 同步influxdb有些数据没有,不知道啥原因,后来百度发现时间需要唯一,毫秒还会重复,只能采用纳秒处理了 java实现 TimeStampUtils.java package com.wujialiang;/*** 获取纳秒值的工具类*/ public class TimeStampUtils {/…

面试题-Vue2和Vue3的区别

文章目录 1. 响应式系统2. 组合式 API (Composition API)3. Fragment (碎片)4. Teleport (传送门) 5. 性能改进6. 移除或改变的功能7. 构建工具8. TypeScript 支持 Vue 2 和 Vue 3 之间存在许多重要的区别,这些区别涵盖了性能、API 设计、组合式 API(Com…

产品NPDP+项目PMP助你成长

前言 从管理的角度来讲,产品经理和项目经理的区别,我们应该吧项目经理和产品的区别分为一纵一横,那一纵就是我们的项目经理,项目经理在整个新产品研发过程中他扮演的是管理监督项目参与者的角色,其中包括研发部门、技术部门、市场部门或是销售部门等等。他所要做的事情就…

【Unity】Kafka、Mqtt、Wesocket通信

1 前言 最近研究了下kafka、mqtt、webocket插件在Unity网络通信中的应用,做下小总结吧。(不想写笔记,但不写又会忘,痛苦) 2 Kafka 先说结果:Kafka实现失败。 我会使用的方法是在VS里安装了Confluent.Kafka…

压缩大文件消耗电脑CPU资源达到33%以上

今天用7-Zip压缩一个大文件,文件大小是9G多,这时能听到电脑风扇声音,查看了一下电脑资源使用情况,确实增加了不少。 下面是两张图片,图片上有电脑资源使用数据。

05--Git分布式版本控制系统

前言:给后端工程师使用的版本控制器,本质上类似带时间标记的ftp,使用比较简单,就在这里归纳出来,供参考学习。 git1、概念简介 分布式版本控制系统(Distributed Version Control System,DVCS&…

数据挖掘--分类

数据挖掘--引论 数据挖掘--认识数据 数据挖掘--数据预处理 数据挖掘--数据仓库与联机分析处理 数据挖掘--挖掘频繁模式、关联和相关性:基本概念和方法 数据挖掘--分类 数据挖掘--聚类分析:基本概念和方法 基本概念 决策树归纳 决策树:决策树是一…

从0开始学人工智能测试节选:Spark -- 结构化数据领域中测试人员的万金油技术(四)

上一章节我们了解了 shuffle 相关的概念和原理后其实可以发现一个问题,那就是 shuffle 比较容易造成数据倾斜的情况。 例如上一节我们看到的图,在这批数据中,hello 这个单词的行占据了绝大部分,当我们执行 groupByKey 的时候触发了…

关于怎么用Cubemx生成的USBHID设备实现读取一体的鼠标键盘设备(改进版)

主要最近做了一个要用STM32实现读取鼠标键盘一体的那种USB设备,STM32的界面上要和电脑一样的能通过这个USB接口实现鼠标移动,键盘的按键。然后我就很自然的去参考了正点原子的例程,可是找了一圈,发现正点原子好像用的库函数&#…

Docker的资源限制

文章目录 一、什么是资源限制1、Docker的资源限制2、内核支持Linux功能3、OOM异常4、调整/设置进程OOM评分和优先级4.1、/proc/PID/oom_score_adj4.2、/proc/PID/oom_adj4.3、/proc/PID/oom_score 二、容器的内存限制1、实现原理2、命令格式及指令参数2.1、命令格式2.2、指令参…

如何在 iPhone 上恢复已删除的短信

本文介绍如何检索已删除的短信和 iMessage 以及恢复丢失的消息。说明适用于 iOS 17 及更高版本。 如何在 iOS 17及更高版本中恢复文本 恢复已删除短信的最简单方法是使用 iOS 17。从删除短信到恢复它有 30 到 40 天的时间。 在“信息”的对话屏幕中,选择“过滤器”…

重塑楼宇管理:智慧管控可视化开启高效新篇章

借助图扑智慧楼宇管控可视化技术,实现实时监控与智能化管理,快速响应潜在问题,确保楼宇安全、节能和高效运行。

Qt/C++音视频开发76-获取本地有哪些摄像头名称/ffmpeg内置函数方式

一、前言 上一篇文章是写的用Qt的内置函数方式获取本地摄像头名称集合,但是有几个缺点,比如要求Qt5,或者至少要求安装了多媒体组件multimedia,如果没有安装呢,或者安装的是个空的呢,比如很多嵌入式板子&am…

[图解]建模相关的基础知识-05

1 00:00:01,510 --> 00:00:03,900 练习,我们就出这一道就行了 2 00:00:04,230 --> 00:00:07,210 这些都是像数理逻辑 3 00:00:08,140 --> 00:00:10,570 包括信息专业的 4 00:00:11,350 --> 00:00:12,900 包括文科的 5 00:00:12,910 --> 00:00:14…