【Image】GAN的超详细解释(以及奇怪的问题)

GAN原理

工作流程

下面是生成对抗网络(GAN)的基本工作原理

image-20231223215508951

在GAN的架构中,有两个关键的组件:生成器(Generator)和鉴别器(Discriminator)。

  1. 生成器(Generator):其功能是从随机噪声生成数据。在这个上下文中,它试图生成类似于真实数据的新数据。目的是创建足够真实的数据以欺骗鉴别器。

  2. 鉴别器(Discriminator):它的任务是鉴别输入数据是真实的还是由生成器生成的假数据。简言之,它需要决定输入数据是“真”还是“假”。

工作过程:

  • 真实数据会被输入到鉴别器中。
  • 同时,生成器产生的数据也会被送入鉴别器。
  • 鉴别器会对这两种数据进行分类,将其标记为“真”或“假”。

学习方式:生成器和鉴别器是以对抗的方式进行学习的。生成器试图生成越来越真实的数据来欺骗鉴别器,而鉴别器则试图变得更加精确以区分真实数据和生成的数据。这个过程会不断循环,随着时间的推移,生成器产生的数据会越来越接近真实数据,而鉴别器的判断能力也会越来越强(有点类似于左脚踩右脚原地起飞)。

数学解释

当然,上面的解释只是语言层面的,GAN的原理同样可以从数学上进行解释
min ⁡ G max ⁡ D V ( D , G ) = E x ∼ p data ( x ) [ log ⁡ D ( x ) ] + E z ∼ p z ( z ) [ log ⁡ ( 1 − D ( G ( z ) ) ) ] \min_{G} \max_{D} V(D, G) = \mathbb{E}_{x \sim p_{\text{data}}(x)}[\log D(x)] + \mathbb{E}_{z \sim p_{z}(z)}[\log(1 - D(G(z)))] GminDmaxV(D,G)=Expdata(x)[logD(x)]+Ezpz(z)[log(1D(G(z)))]
这是生成对抗网络(GAN)的价值函数,它形式化了生成器 G 和鉴别器 D 之间的对抗游戏。其中 z 指的是上图中的 random noise(虽然这里写的是随机噪声,但是这种噪声往往也是符合某种分布的,一般来说我们认为是高斯分布,最终我们希望这个高斯分布会变成符合真实图像分布的某种分布)。

接下来,我们要非常详细地来解释这个公式

image-20231223222103202

Value函数跟强化学习中的定义一样

image-20231223222214671

一般来说,”真“用1表示;”假“用0表示。所以,当输入是一张”真“图时,我们希望D的值为1;当输入是一张”假“图时,我们希望D的值为0。即D(r) = 1D(f) = 0

看图中④的部分,loss = log(D(r))——如果输入是“真”图,这个loss值是0(也就是说如果D(r)能被准确地判断为1,那么“真”图就没有产生任何loss);

看图中⑤的部分,loss = log(1-D(f))——如果输入是“假”图,这个loss值也是0(也就是说如果D(f)能被准确地判断为0,那么“假”图就没有产生任何loss)。

根据log函数特性,在0~1区间内函数最大值为0,所以上式的最大值就是0,在两种情况同时满足时取等。

这也就是为什么,我们希望找到一个很强的D,能够精准分出rf,并且在这个条件下最大化V

image-20231223222237856

接下来看到G,我们知道G的目标是要愚弄D,具体就是让D(f) = D(G(z))尽可能被判断为1,这样loss = log(1-D(f)) = -∞.

这就解释了为什么一个是max_D,一个是min_G

image-20231223233703386

z~p(z)是噪声分布,即高斯分布

image-20231223233800262

这里计算了期望。

综上所述,上面的公式可以表示为
V ( D , G ) = ∫ x p data ( x ) log ⁡ ( D ( x ) )   d x + ∫ x p g ( x ) log ⁡ ( 1 − D ( x ) )   d x = ∫ x p data ( x ) log ⁡ ( D ( x ) ) + p g ( x ) log ⁡ ( 1 − D ( x ) )   d x \begin{align} V(D, G) &= \int_{x} p_{\text{data}}(x) \log(D(x)) \, dx + \int_{x} p_{g}(x) \log(1 - D(x)) \, dx \\ &= \int_{x} p_{\text{data}}(x) \log(D(x)) + p_{g}(x) \log(1 - D(x)) \, dx \end{align} V(D,G)=xpdata(x)log(D(x))dx+xpg(x)log(1D(x))dx=xpdata(x)log(D(x))+pg(x)log(1D(x))dx
这个变换除了带入了期望公式,还做了一个变换——将真实图像与噪声统一成了x,在取值时分别取真实图像和噪声各自对应的分布——在积分中统一了形式,并减少了G

要求积分最大值,两边求导:
max ⁡ D V ( D ) = ∫ x p data ( x ) log ⁡ ( D ( x ) ) + p g ( x ) log ⁡ ( 1 − D ( x ) )   d x ⇔ max ⁡ D f ( D ) = a log ⁡ ( D ) + b log ⁡ ( 1 − D ) \max_D V(D) = \int_{x} p_{\text{data}}(x) \log(D(x)) + p_{g}(x) \log(1 - D(x)) \, dx \\\Leftrightarrow \\ \max_D f(D) = a\log(D) + b\log(1 - D) \\ DmaxV(D)=xpdata(x)log(D(x))+pg(x)log(1D(x))dxDmaxf(D)=alog(D)+blog(1D)
求偏导,解出了D的值使偏导为0,这个D也被称为D*,即最优判别器(Optimal Discriminator)
∂ f ∂ D = a D − b 1 − D = 0 ⇒ D ∗ = a a + b = p data ( x ) p data ( x ) + p g ( x ) \frac{\partial f}{\partial D} = \frac{a}{D} - \frac{b}{1 - D} = 0 \Rightarrow D^* = \frac{a}{a + b} = \frac{p_{\text{data}}(x)}{p_{\text{data}}(x) + p_{g}(x)} Df=Da1Db=0D=a+ba=pdata(x)+pg(x)pdata(x)
然后我们把这个最优判别器带回原式
min ⁡ G f ( G ) = ∫ x p data ( x ) log ⁡ ( 2 p data ( x ) p data ( x ) + p g ( x ) ) − log ⁡ 2   d x + ∫ x p g ( x ) log ⁡ ( 2 p g ( x ) p data ( x ) + p g ( x ) ) − log ⁡ 2   d x = − log ⁡ 2 ∫ x p data + p g   d x + ∫ x p data log ⁡ ( 2 p data p data + p g )   d x + ∫ x p g log ⁡ ( 2 p g p data + p g )   d x \min_G f(G) = \int_{x} p_{\text{data}}(x) \log \left( \frac{2p_{\text{data}}(x)}{p_{\text{data}}(x) + p_g(x)} \right) - \log 2 \, dx + \int_{x} p_g(x) \log \left( \frac{2p_g(x)}{p_{\text{data}}(x) + p_g(x)} \right) - \log 2 \, dx\\ = -\log 2 \int_{x} p_{\text{data}} + p_g \, dx + \int_{x} p_{\text{data}} \log \left( \frac{2p_{\text{data}}}{p_{\text{data}} + p_g} \right) \, dx + \int_{x} p_g \log \left( \frac{2p_g}{p_{\text{data}} + p_g} \right) \, dx Gminf(G)=xpdata(x)log(pdata(x)+pg(x)2pdata(x))log2dx+xpg(x)log(pdata(x)+pg(x)2pg(x))log2dx=log2xpdata+pgdx+xpdatalog(pdata+pg2pdata)dx+xpglog(pdata+pg2pg)dx
其中
− log ⁡ 2 ∫ x p data + p g   d x = − 2 log ⁡ 2 = − log ⁡ 4 -\log 2 \int_{x} p_{\text{data}} + p_g \, dx = -2\log2 = -\log4 log2xpdata+pgdx=2log2=log4

散度 Divergence

讲到这里我们穿插一下散度 (Divergence) 的概念:"Divergence"是一种度量或评估两个概率分布差异的方法,它被用来比较两个分布之间的不同程度,可以帮助我们了解一个分布如何或在何种程度上不同于另一个分布。

KL散度(Kullback-Leibler Divergence)

KL - Divergence: D K L ( P ∥ Q ) = ∑ i P ( i ) log ⁡ ( P ( i ) Q ( i ) ) = ∫ x P ( x ) log ⁡ ( P ( x ) Q ( x ) ) d x \text{KL - Divergence:} \quad D_{KL}(P \parallel Q) = \sum_i P(i)\log\left(\frac{P(i)}{Q(i)}\right) = \int_{x} P(x)\log\left(\frac{P(x)}{Q(x)}\right) dx KL - Divergence:DKL(PQ)=iP(i)log(Q(i)P(i))=xP(x)log(Q(x)P(x))dx

  • KL散度是衡量两个概率分布P和Q差异的非对称度量。具体来说,它衡量的是,当使用概率分布Q来近似真实分布P时,所损失的信息量。
  • 它是从信息论的视角出发的,基于信息熵的概念,其中P是真实分布,Q是模型的预测分布。
  • 一个重要的特性是非对称性,即
    D K L ( P ∥ Q ) ≠ D K L ( Q ∥ P ) D_{KL}(P \parallel Q) \neq D_{KL}(Q \parallel P) DKL(PQ)=DKL(QP)
    这也是KL散度的一个明显的缺陷,因为分布是没有方向性的。
JS散度(Jensen-Shannon Divergence)

JS - Divergence: J S D ( P ∥ Q ) = 1 2 D K L ( P ∥ P + Q 2 ) + 1 2 D K L ( Q ∥ P + Q 2 ) \text{JS - Divergence:} \quad JSD(P \parallel Q) = \frac{1}{2}D_{KL}\left(P \parallel \frac{P+Q}{2}\right) + \frac{1}{2}D_{KL}\left(Q \parallel \frac{P+Q}{2}\right) JS - Divergence:JSD(PQ)=21DKL(P2P+Q)+21DKL(Q2P+Q)

  • JS散度是KL散度的对称版本,它衡量两个概率分布P和Q的相似性,并且总是有界的(在0和1之间)。
  • 它的计算方式是取两个分布P和Q相对于它们的平均值的KL散度的平均值。
  • 因为JS散度是对称的,所以它通常被认为是两个分布之间距离的更好的度量。

如此一来,我们用JS散度对上面的公式进行替换,得到

min ⁡ G f ( G ) = ∫ x p data ( x ) log ⁡ ( 2 p data ( x ) p data ( x ) + p g ( x ) ) − log ⁡ 2   d x + p g ( x ) log ⁡ ( 2 p g ( x ) p data ( x ) + p g ( x ) ) − log ⁡ 2   d x = − log ⁡ 2 ∫ x p data + p g   d x + 2 J S D ( p data ∥ p g ) = − log ⁡ 4 + 2 J S D ( p data ∥ p g ) ≥ − log ⁡ 4 , where  [ p d a t a = p g ] \min_G f(G) = \int_{x} p_{\text{data}}(x) \log \left( \frac{2p_{\text{data}}(x)}{p_{\text{data}}(x) + p_g(x)} \right) - \log 2 \, dx + p_g(x) \log \left( \frac{2p_g(x)}{p_{\text{data}}(x) + p_g(x)} \right) - \log 2 \, dx\\ = -\log 2 \int_{x} p_{\text{data}} + p_g \, dx + 2JSD(p_{\text{data}} \parallel p_g)\\ = -\log 4 + 2JSD(p_{\text{data}} \parallel p_g)\\ \geq -\log 4, \quad \text{where } [p_{data} = p_g] Gminf(G)=xpdata(x)log(pdata(x)+pg(x)2pdata(x))log2dx+pg(x)log(pdata(x)+pg(x)2pg(x))log2dx=log2xpdata+pgdx+2JSD(pdatapg)=log4+2JSD(pdatapg)log4,where [pdata=pg]

这就是上面的minmax函数的最简表达形式。

Summary

  • Generate a discriminator (D) & a generator (G) step by step

  • The target of the D is to try its best to discriminate real and fake images while the target of the G is to try its best to generate fake images to fool the D.

  • It seems we can get a global optimality (equilibrium) by dragging 𝒑𝒈 → 𝒑𝒅𝒂𝒕𝒂

奇怪的问题

但是,现在我们这个公式有一个很大的问题。

下面先给出一个mnist生成数字的GAN代码

# dataset: mnist
import argparse
import os
import numpy as np
import math

import torchvision.transforms as transforms
from torchvision.utils import save_image

from torch.utils.data import DataLoader
from torchvision import datasets
from torch.autograd import Variable

import torch.nn as nn
import torch

from generator import Generator
from discriminator import Discriminator

os.makedirs("images", exist_ok=True)

parser = argparse.ArgumentParser()
parser.add_argument("--n_epochs", type=int, default=200, help="number of epochs of training")
parser.add_argument("--batch_size", type=int, default=64, help="size of the batches")
parser.add_argument("--lr", type=float, default=0.0002, help="adam: learning rate")
parser.add_argument("--b1", type=float, default=0.5, help="adam: decay of first order momentum of gradient")
parser.add_argument("--b2", type=float, default=0.999, help="adam: decay of first order momentum of gradient")
parser.add_argument("--n_cpu", type=int, default=8, help="number of cpu threads to use during batch generation")
parser.add_argument("--latent_dim", type=int, default=100, help="dimensionality of the latent space")
parser.add_argument("--img_size", type=int, default=28, help="size of each image dimension")
parser.add_argument("--channels", type=int, default=1, help="number of image channels")
parser.add_argument("--sample_interval", type=int, default=400, help="interval betwen image samples")
opt = parser.parse_args()
print(opt)

# 图像的形状参数
img_shape = (opt.channels, opt.img_size, opt.img_size)
# 定义损失函数为二元交叉熵损失
adversarial_loss = torch.nn.BCELoss()

# 初始化生成器和鉴别器
generator = Generator()
discriminator = Discriminator()

# 如果CUDA可用,将网络和损失函数移动到GPU
cuda = True if torch.cuda.is_available() else False
if cuda:
    generator.cuda()
    discriminator.cuda()
    adversarial_loss.cuda()

# 配置数据加载器
os.makedirs("./data/mnist", exist_ok=True)
dataloader = torch.utils.data.DataLoader(
    datasets.MNIST(
        "./data/mnist",
        train=True,
        download=True,
        # 数据预处理:调整大小、转换为张量、标准化
        transform=transforms.Compose(
            [transforms.Resize(opt.img_size),
             transforms.ToTensor(),
             transforms.Normalize([0.5], [0.5])]
        ),
    ),
    batch_size=opt.batch_size,
    shuffle=True,
)

# 配置优化器,使用Adam优化器
optimizer_G = torch.optim.Adam(generator.parameters(), lr=opt.lr, betas=(opt.b1, opt.b2))
optimizer_D = torch.optim.Adam(discriminator.parameters(), lr=opt.lr, betas=(opt.b1, opt.b2))

# 根据CUDA环境选择数据类型
Tensor = torch.cuda.FloatTensor if cuda else torch.FloatTensor

# 开始训练
for epoch in range(opt.n_epochs):
    for i, (imgs, _) in enumerate(dataloader):
        # Adversarial ground truths
        # 创建标签数据:真实图片的标签为1,生成图片的标签为0
        valid = Tensor(imgs.size(0), 1).fill_(1.0).detach()
        fake = Tensor(imgs.size(0), 1).fill_(0.0).detach()

        # 配置输入
        real_imgs = imgs.type(Tensor)

        # -----------------
        #  Train Generator
        # -----------------
        optimizer_G.zero_grad()  # 对已有的gradient清零(因为来了新的batch_size的image)
        z = Tensor(np.random.normal(0, 1, (imgs.shape[0], opt.latent_dim)))  # 随机生成输入噪声
        gen_imgs = generator(z)  # 生成一个batch的假图片
        # Loss measures generator's ability to fool the discriminator
        g_loss = adversarial_loss(discriminator(gen_imgs),  # D(G(z))
                                  valid)                    # label = 1, 这里将假图的label置为1的原因下一篇文章会说
        g_loss.backward()  # bp, 算gradient, x.grad += dloss/dx
        optimizer_G.step()  # 更新x, x -= lr * x.grad

        # ---------------------
        #  Train Discriminator
        # ---------------------
        optimizer_D.zero_grad()
        real_loss = adversarial_loss(discriminator(real_imgs),  # D(x)
                                     valid)                     # lable = 1
        fake_loss = adversarial_loss(discriminator(gen_imgs.detach()),  # D(G(z)), 这里用到detach的原因是:gen_imgs后面带着generator的参数,而这里训练的是discriminator的参数
                                     fake)                              # lable = 0
        d_loss = (real_loss + fake_loss) / 2  # 计算鉴别器的总损失
        d_loss.backward()  # bp, 算gradient, x.grad += dloss/dx
        optimizer_D.step()  # 更新x, x -= lr * x.grad

        print(
            "[Epoch %d/%d] [Batch %d/%d] [D loss: %f] [G loss: %f]"
            % (epoch, opt.n_epochs, i, len(dataloader), d_loss.item(), g_loss.item())
        )

        # 每隔一定的间隔保存生成的图片
        batches_done = epoch * len(dataloader) + i
        if batches_done % opt.sample_interval == 0:
            save_image(gen_imgs.data[:25], "images/%d.png" % batches_done, nrow=5, normalize=True)

generator.py

import torch.nn as nn
import numpy as np

# 定义生成器输入的噪声向量的维度和生成图像的形状
latent_dim = 100
img_shape = (1, 28, 28)

# 定义Generator类,继承自nn.Module
class Generator(nn.Module):
    # 初始化函数
    def __init__(self):
        super(Generator, self).__init__()  # 调用父类的构造函数

        # 定义一个block函数用于构建神经网络的层,其中包含线性层,可选的批标准化层和LeakyReLU激活函数
        def block(in_feat, out_feat, normalize=True):
            layers = [nn.Linear(in_feat, out_feat)]  # 线性层
            if normalize:
                # 如果normalize为True,则添加批标准化层
                layers.append(nn.BatchNorm1d(out_feat, 0.8))
            # 添加LeakyReLU激活函数,其中negative_slope(斜率)设置为0.2
            layers.append(nn.LeakyReLU(0.2, inplace=True))
            return layers  # 返回构建的层列表

        # 使用Sequential模块将所有层堆叠成一个完整的模型
        self.model = nn.Sequential(
            *block(latent_dim, 128, normalize=False),  # 第一层不进行批标准化
            *block(128, 256),  # 后续层逐渐增加输出特征的维度
            *block(256, 512),
            *block(512, 1024),
            # 最后一层是一个线性层,它的输出大小与图像大小的乘积相同
            nn.Linear(1024, int(np.prod(img_shape))),
            nn.Tanh()  # 使用Tanh激活函数将输出值限制在[-1,1]之间,因为图像数据通常归一化到这个范围
        )

    # 前向传播函数定义了模型如何从输入产生输出
    def forward(self, z):
        img = self.model(z)  # 使用model生成图像数据
        # 调整输出的形状,使其与目标图像形状一致
        img = img.view(img.size(0), *img_shape)
        return img  # 返回生成的图像

discriminator.py

import torch.nn as nn
import numpy as np

# 图像的形状参数
img_shape = (1, 28, 28)

# 定义Discriminator类,继承自nn.Module
class Discriminator(nn.Module):
    # 初始化函数
    def __init__(self):
        super(Discriminator, self).__init__()  # 调用父类的构造函数

        # 构建鉴别器的神经网络模型,使用Sequential容器
        self.model = nn.Sequential(
            # 输入层,将输入向量的维度从图像形状展平为一维向量
            nn.Linear(int(np.prod(img_shape)), 512),
            # 使用LeakyReLU作为激活函数,其斜率设置为0.2
            nn.LeakyReLU(0.2, inplace=True),
            # 中间层,继续减少特征的维度
            nn.Linear(512, 256),
            # 同样使用LeakyReLU激活函数
            nn.LeakyReLU(0.2, inplace=True),
            # 输出层,将特征压缩为一个单一的预测值
            nn.Linear(256, 1),
            # 使用Sigmoid激活函数将输出值压缩到[0,1]之间,作为真假图像的概率
            nn.Sigmoid(),
        )

    # 前向传播函数定义了模型如何从输入产生输出
    def forward(self, img): # img.shape = torch.Size([64, 1, 28, 28]) = 64 * 1 * 28 * 28
        # 将输入图像展平为一维向量
        img_flat = img.view(img.size(0), -1)  # (64, -1 = 1 * 28 * 28)
        # 将展平的图像向量传递给模型,并得到有效性预测
        validity = self.model(img_flat)
        return validity  # 返回预测的有效性(即图像为真实图像的概率)

image-20231224165235713

然而,看看最后生成的结果
187200

我们初始的噪声其实是很不一样的,但是一个非常奇怪的现象是——我们最后确实又生成了很多一样的东西。甚至,二行四列和三行四列(或者二行二列和五行三列)的两个明显是生成错了,但即便是错也是错得十分相似。

这其中的问题还是挺严重的。欲知后事如何,且听下回分解~

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

传感器基础:传感器使用与编程使用(六)

目录 常用传感器讲解二十--气体传感器(KY-036)具体讲解电路连接代码实现 常用传感器讲解二十一--加速度传感器(ADXL335)具体讲解电路连接代码实现 常用传感器讲解二十二--压力传感器(BMP180)具体讲解电路连…

nvm 的安装及使用 (Node版本管理器)

目录 1、nvm 介绍 2、nvm安装 3、nvm 使用 4、node官网可以查看node和npm对应版本 5、nvm安装指定版本node 6、安装cli脚手架 1、nvm 介绍 NVM 全称 node.js version management ,专门针对 node 版本进行管理的工具,通过它可以安装和切换不同版本的…

Mysql之视图

Mysql之视图 常见的数据库对象视图概述为什么使用视图视图的理解创建视图创建单表视图别名的运用 创建多表联合视图利用视图对数据进行格式化contact 函数以视图为基,再创建新的视图 查看视图更新视图的数据一般情况不可更新的视图 修改和删除视图修改视图删除视图注…

SSL证书是什么?为什么需要SSL证书?

什么是SSL证书? SSL,全称为Secure Sockets Layer,是一种用于加密网络通信的协议。SSL证书是由一个可信赖的第三方机构颁发的数字证书,用于确保在用户与服务器之间传输的数据经过加密,保护用户隐私和信息安全。SSL证书…

flutter学习-day20-使用SafeArea组件处理各机型的安全距离

📚 目录 介绍分析示例和效果图特殊情况 1. 介绍 安全区域,指的是移动端设备的可视窗口范围。处于安全区域的内容不受圆角、刘海屏、iPhone 小黑条、状态栏等的影响,也就是说,我们要做好适配,必须保证页面可视、可操作…

Servlet见解2

4 创建servlet的三种方式 4.1 实现Servlet接口的方式 import javax.servlet.*; import javax.servlet.annotation.WebServlet; import java.io.IOException;WebServlet("/test1") public class Servlet1 implements Servlet {Overridepublic void init(ServletConf…

django之drf框架(两个视图基类、5个扩展视图类、9个视图子类)

两个视图基类 APIView和GenericAPIView drf提供的最顶层的父类就是APIView,以后所有的类都继承自他 GenericAPIView继承自APIView,他里面封装了一些工能 基于APIViewModelSerializerResposne写5个接口 子路由:app01>>>urls.py …

vscode括号颜色突然变成白色的了,怎么解决

更新版本后发现vscode的各种括号都变成了白色,由于分色括号已经使用习惯,突然变成白色非常不舒服,尝试多次后,为大家提供一下几种解决方式,希望能帮到同样受到此种困惑的你: 第一种: 首先打开…

模式识别与机器学习-判别式分类器

模式识别与机器学习-判别式分类器 生成式模型和判别式模型的区别线性判别函数多分类情况多分类情况1多分类情况2多分类情况3 例题 广义线性判别函数实例 分段线性判别函数Fisher线性判别感知机算法例:感知机多类别分类 谨以此博客作为学习期间的记录 生成式模型和判…

QT编译并部署QtMqtt相关环境+跑测demo【超详细教程】

文章目录 概要整体架构流程▷下载指定版本的QMqtt源码:▷编译后同步MQTT相关文件: 技术名词解释技术实现步骤详解一、编译源码1、编译报错2、解决思路3、编译通过 二、继续完善mqtt应用环境1、打开编译生成的shadow build文件夹2、同步lib3、同步bin4、同…

小程序中拖拽和缩放图片

需求&#xff1a;点击元素后选中&#xff0c;出现缩放按钮&#xff0c;拖动缩放按钮可实现元素的缩放&#xff1b;并且元素本身是可以拖动的。 html&#xff1a; <block wx:for"{{imageControls}}" wx:key"index"><view hidden"{{item.hidd…

vue中 ref 和 reactive 的区别与联系

官方原文&#xff1a;Vue3 建议使用 ref() 作为声明响应式状态的主要API。 ref 用于将基本类型的数据&#xff08;如字符串、数字&#xff0c;布尔值等&#xff09;和引用数据类型(对象) 转换为响应式数据。使用 ref 定义的数据可以通过 .value 属性访问和修改。reactive 用于…

因mathtype原因导致word中ctrl+V复制功能失效的解决办法

因MathType导致Word中ctrlV复制功能失效的解决办法如下&#xff1a; 我们先解决&#xff01; 打开“文件”&#xff0c;找到“选项”&#xff0c;“加载项”。找到MathType安装目录下&#xff08;C:\Program Files (x86)\Microsoft Office\root\Office16\STARTUP&#xff09;…

大创项目推荐 深度学习YOLOv5车辆颜色识别检测 - python opencv

文章目录 1 前言2 实现效果3 CNN卷积神经网络4 Yolov56 数据集处理及模型训练5 最后 1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; **基于深度学习YOLOv5车辆颜色识别检测 ** 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0…

SpringBoot的热部署

&#x1f648;作者简介&#xff1a;练习时长两年半的Java up主 &#x1f649;个人主页&#xff1a;程序员老茶 &#x1f64a; ps:点赞&#x1f44d;是免费的&#xff0c;却可以让写博客的作者开心好久好久&#x1f60e; &#x1f4da;系列专栏&#xff1a;Java全栈&#xff0c;…

超维空间S2无人机使用说明书——52、使用PID算法进行基于yolo的目标跟踪

引言&#xff1a;在实际工程项目中&#xff0c;为了提高系统的响应速度和稳定性&#xff0c;往往需要采用一定的控制算法进行目标跟踪。这里抛砖引玉&#xff0c;仅采用简单的PID算法进行目标的跟随控制&#xff0c;目标的识别依然采用yolo。对系统要求更高的&#xff0c;可以对…

【Redis】一文掌握Redis原理及常见问题

Redis是基于内存数据库&#xff0c;操作效率高&#xff0c;提供丰富的数据结构&#xff08;Redis底层对数据结构还做了优化&#xff09;&#xff0c;可用作数据库&#xff0c;缓存&#xff0c;消息中间件等。如今广泛用于互联网大厂&#xff0c;面试必考点之一&#xff0c;本文…

python3下载手机安卓版,python下载手机版最新

大家好&#xff0c;小编为大家解答python3下载手机安卓版的问题。很多人还不知道python下载手机版最新&#xff0c;现在让我们一起来看看吧&#xff01; 1、先去python官网下载python3的源码包&#xff0c;网址&#xff1a;https://www.python.org/ 1)进去之后点击导航栏的Down…

CentOS系统环境搭建(二十六)——使用nginx在无域名情况下使用免费证书设置https

centos系统环境搭建专栏&#x1f517;点击跳转 文章目录 使用nginx在无域名情况下使用免费证书设置https1.获取SSL证书1.1 生成SSL密钥1.2 生成SSL证书1.3 重命名密钥文件 2.nginx配置https2.1 放证书2.2 修改nginx.conf文件2.2.1 将80端口重定向到4432.2.2 端口443配置ssl证书…

【三维生成】稀疏重建、Image-to-3D方法(汇总)

系列文章目录 总结一下近5年的三维生成算法&#xff0c;持续更新 文章目录 系列文章目录一、LRM&#xff1a;单图像的大模型重建&#xff08;2023&#xff09;摘要1.前言2.Method3.实验 二、SSDNeRF&#xff1a;单阶段Diffusion NeRF的三维生成和重建&#xff08;ICCV 2023&am…