【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 mathimport torchvision.transforms as transforms
from torchvision.utils import save_imagefrom torch.utils.data import DataLoader
from torchvision import datasets
from torch.autograd import Variableimport torch.nn as nn
import torchfrom generator import Generator
from discriminator import Discriminatoros.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,生成图片的标签为0valid = 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 discriminatorg_loss = adversarial_loss(discriminator(gen_imgs),  # D(G(z))valid)                    # label = 1, 这里将假图的label置为1的原因下一篇文章会说g_loss.backward()  # bp, 算gradient, x.grad += dloss/dxoptimizer_G.step()  # 更新x, x -= lr * x.grad# ---------------------#  Train Discriminator# ---------------------optimizer_D.zero_grad()real_loss = adversarial_loss(discriminator(real_imgs),  # D(x)valid)                     # lable = 1fake_loss = adversarial_loss(discriminator(gen_imgs.detach()),  # D(G(z)), 这里用到detach的原因是:gen_imgs后面带着generator的参数,而这里训练的是discriminator的参数fake)                              # lable = 0d_loss = (real_loss + fake_loss) / 2  # 计算鉴别器的总损失d_loss.backward()  # bp, 算gradient, x.grad += dloss/dxoptimizer_D.step()  # 更新x, x -= lr * x.gradprint("[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) + iif 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.2layers.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.2nn.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.mzph.cn/news/577792.shtml

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

相关文章

HTML5之 夜景放烟花

参考网址 https://blog.csdn.net/Gou_Hailong/article/details/122269931 https://blog.csdn.net/u013343616/article/details/122233674 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transi…

C/C++ BM2链表内指定区间反转

文章目录 前言题目1. 解决方案一1.1 思路阐述1.2 源码 2. 解决方案二2.1 思路阐述2.2 源码 总结 前言 这题是BM1的升级版&#xff0c;不过是把完整的链表翻转变成了指定区间。 题目 描述 将一个节点数为 size 链表 m 位置到 n 位置之间的区间反转&#xff0c;要求时间复杂度 …

手机蓝牙在物联网超市中的应用

超市一站式购物已进入城市的千家万户。然而人们在选购时却采用直接翻阅商品的方式&#xff0c;既不方便又不卫生甚至大大缩短食品类商品保质期&#xff0c;也给超市商品管理造成很大难度。物联网(The Internet of things)基于射频识别(RFID)、红外感应等技术&#xff0c;把物品…

CentOS环境下Nacos2.3集成PostgreSQL

title: CentOS环境下Nacos2.3集成PostgreSQL date: 2023-12-21 19:15:00 categories: Nacos description: CentOS环境下Nacos2.3集成PostgreSQL 1. 目录 1. 目录2. 简介3. 安装部署 3.1. 部署模式3.2. 环境准备3.3. 下载安装文件3.4. PostgreSQL插件 3.4.1. 下载地址3.4.2. 结…

VScode远程连接服务器,Pycharm专业版下载及远程连接(深度学习远程篇)

Visual Code、PyCharm专业版&#xff0c;本地和远程交互。 远程连接需要用到SSH协议的技术&#xff0c;常用的代码编辑器vscode 和 pycharm都有此类功能。社区版的pycharm是免费的&#xff0c;但是社区版不支持ssh连接服务器&#xff0c;只有专业版才可以&#xff0c;需要破解…

【论文阅读】MCANet: Medical Image Segmentation with Multi-Scale Cross-Axis Attention

文章目录 摘要创新点总结实现效果总结 摘要 链接&#xff1a;https://arxiv.org/abs/2312.08866 医学图像分割是医学图像处理和计算机视觉领域的关键挑战之一。由于病变区域或器官的大小和形状各异&#xff0c;有效地捕捉多尺度信息和建立像素间的长距离依赖性至关重要。本文提…

人工智能_机器学习073_SVM支持向量机_人脸识别模型建模_预测可视化_网格搜索交叉验证最优化参数对比---人工智能工作笔记0113

接着上一节来说,可以看到我们已经找到了合适的参数,然后 我们可以看一下这里 gc.best_params_ 就可以打印出最合适的参数 然后我们把最合适串按说填入到代码中,然后进行计算,看看得分 可以看到得分,训练数据是1.0 然后测试数据得分是0.7857...对吧

2024深入评测CleanMyMac X4.14.6破解版新的功能

随着时间的推移&#xff0c;我们的Mac电脑往往会变得越来越慢&#xff0c;存储空间变得越来越紧张&#xff0c;这时候一个优秀的清理工具就显得尤为重要。作为一款备受好评的Mac清理工具&#xff0c;它能够为你的Mac带来全方位的清理和优化。在本文中&#xff0c;我们将深入评测…

【HarmonyOS开发】OpenHarmony如何实现⼀次开发,多端部署

OpenHarmony提供用户程序框架、Ability框架以及UI框架&#xff0c;能够保证开发的应用在多终端运行时保证一致性。一次开发、多端部署。 多终端软件平台API具备一致性&#xff0c;确保用户程序的运行兼容性。 HarmonyOS提供了用户程序框架、Ability框架以及UI框架&#xff0c;…

WebRTC概念

定义 一个实时通信标准 通话原理 媒体协商 在WebRTC中&#xff0c;参与视频通讯的双方必须先交换SDP信息&#xff0c;获得一个都支持的编码格式 网络协商 目的&#xff1a;找到一条相互通讯的链路 做法&#xff1a;获取外网IP地址映射&#xff0c;通过信令服务器交换“网…

华锐三维云展平台 | VR在线展览云平台提供定制化虚拟展厅制作工具

随着科技的飞速发展&#xff0c;互联网技术的不断革新&#xff0c;广州华锐互动顺应时代需求&#xff0c;开发了VR在线展览云平台&#xff0c;用户可以在平台上自主创建属于自己的3D展厅。VR在线展览云平台正改变着传统展览行业的模式&#xff0c;为参展者提供更高效、更便捷、…

Hazel macOS自动化清理

Hazel是一款在Mac平台上的自动化文件管理工具&#xff0c;它可以帮助用户自动化处理文件&#xff0c;从而提高工作效率和减少重复性任务的时间和精力。以下是Hazel软件的功能特色&#xff1a; 强大的自动化处理功能&#xff1a;Hazel可以根据用户设定的规则&#xff0c;自动执…

Android---Kotlin 学习009

继承 在 java 里如果一个类没有被 final 关键字修饰&#xff0c;那么它都是可以被继承的。而在 kotlin 中&#xff0c;类默认都是封闭的&#xff0c;要让某个类开放继承&#xff0c;必须使用 open 关键字修饰它&#xff0c;否则会编译报错。此外在子类中&#xff0c;如果要复写…

Redis设计与实现之服务器与客户端

目录 一、服务器与客户端 1、初始化服务器 1. 初始化服务器全局状态 2. 载入配置文件 3. 创建 daemon 进程 4. 初始化服务器功能模块 5. 载入数据 6. 开始事件循环 2、 客户端连接到服务器 3、命令的请求、处理和结果返回 4、命令请求实例:SET 的执行过程 5、Redis服…

数据仓库【1】:简介

数据仓库【1】&#xff1a;简介 1、诞生背景1.1、数据仓库诞生原因1.2、历史数据积存1.3、企业数据分析需要 2、基本概述2.1、数据仓库&#xff08;Data Warehouse&#xff0c;DW&#xff09;2.2、数据仓库特点2.3、数据仓库 VS 数据库 3、技术实现3.1、数据仓库建设方案3.2、传…

sql_lab之sqli中的搜索型注入

搜索型注入 原理是运用模糊查询&#xff1a; select * from users where username like %a% 1.找到具有模糊查询的搜索框的注入点 2.构造闭合 因为模糊查询的代码是 select * from users where username like %a% 所以应该 鱼%’ -- s 判断构造闭合的函数是否正确 鱼%…

【JavaEE初阶一】线程的概念与简单创建

1. 认识线程&#xff08;Thread&#xff09; 1.1 关于线程 1.1.1 线程是什么 由前一节的内容可知&#xff0c;进程在进行频繁的创建和销毁的时候&#xff0c;开销比较大&#xff08;主要体现在资源的申请和释放上&#xff09;&#xff0c;线程就是为了解决上述产生的问题而提…

apache禁止遍历目录

禁止Apache显示目录索引&#xff0c;禁止Apache显示目录结构列表&#xff0c;禁止Apache浏览目录&#xff0c;这是网上提问比较多的&#xff0c;其实都是一个意思。下面说下禁止禁止Apache显示目录索引的常见的3种方法。 要实现禁止Apache显示目录索引&#xff0c;只需将 Optio…

Jenkins的特殊操作定时自动执行任务以及测试报告调优

java -Dhudson.model.DirectoryBrowserSupport.CSP -jar Jenkins.war 测试报告 不美丽 执行上面的代码 重启jenkins 就好了

Ai企业系统源码 Ai企联系统源码 商用去授权 支持文心 星火 GPT4等等20多种接口

智思Ai系统2.4.9版本去授权&#xff08;可商用&#xff09;支持市面上所有版本的接口例如&#xff1a;文心、星火、GPT4等等20多种接口&#xff01;代过审AI小程序类目&#xff01;&#xff01;&#xff01; 安装步骤&#xff1a; 1、在宝塔新建个站点&#xff0c;php版本使用…