深度学习--生成对抗网络GAN

GAN简介

让我们先来简单了解一下GAN

GAN的全称是Generative Adversarial Networks,中文称为“生成对抗网络”,是一种在深度学习领域广泛使用的无监督学习方法。

GAN主要由两部分组成:生成器判别器。生成器的目标是尽可能地生成真实的样本数据,而判别器的目标是尽可能准确地辨别出生成样本与真实样本。这两个组件通过竞争和对抗的方式共同工作,以提升各自的能力。这种网络结构能够处理没有标注数据的问题,并且在图像处理、自然语言处理等多个领域都有广泛应用。

它通过对抗生成来训练,目的是估测数据样本的潜在分布并生成新的数据样本。

GAN结构图

原理 

生成器根据噪声,也就是随机值,来生成样本,而判别器判断哪些是真实数据,哪些是生成数据,然后将学习的经验反向传播给生成器,让生成器生成的样本不断向真实样本靠拢。

在训练过程中,生成器努力让生成的数据更加真实,而判别器努力的去判别数据的真假,二者·形成了对抗。最终两个网络形成了动态平衡,生成样本接近真实样本,而判别器也分辨不出来样本的真假,最终对给定图像预测为真的概率基本接近0.5,也就相当于随即猜测类别了。

公式

在公式中,

z代表输入G网络的噪声,

x代表真实图片

G(z)表示G网络生成的图片,

D(*)表示D网络判断图片是否真实的概率

2.GAN的算法流程和公式详解_哔哩哔哩_bilibili 

在这个视频里有对这个公式的详解,这里就不详细说了/

 我们经过简单了解之后,就要开始搭建GAN网络了,这里我们以手写字体识别数据集为例。

构建GAN网络的步骤

GAN生成对抗网络,步骤:
首先编写生成器和判别器
然后固定生成器,用我们的数据优化判别器,试得我们最开始生成器生成的图片判断为0,真实图片判断为1
接着固定判别器,利用我们的判别器判断生成器生成的图片,以判断的尽可能接近1为目的优化我们的生成器
生成器的代码(针对手写字体识别)

 预备知识

transforms.Normalize

transforms.Normalize()函数用于对图像数据进行【标准化】处理。在深度学习中,数据标准化是一个常见的预处理步骤,它有助于模型更快地收敛,并提高模型的性能

作用

数据标准化:如上所述,transforms.Normalize()函数可以对图像数据进行标准化处理,使数据分布符合标准正态分布。这有助于模型更快地收敛,并提高模型的性能。


提高模型泛化能力:通过对数据进行标准化,我们可以减少模型对特定数据集的过拟合,从而提高模型在未见过的数据上的泛化能力。


加速模型训练:标准化的数据可以使模型在训练过程中更快地学习到数据的特征,从而加速模型的训练速度。

参数
  • mean:(list)长度与输入的通道数相同,代表每个通道上所有数值的平均值
  • std:(list)长度与输入的通道数相同,代表每个通道上所有数值的标准差

Datadoder

参数

dataset(数据集):需要提取数据的数据集,Dataset对象
batch_size(批大小):每一次装载样本的个数,int型
 shuffle(洗牌):进行新一轮epoch时是否要重新洗牌,Boolean型
num_workers:是否多进程读取机制
drop_last:当样本数不能被batchsize整除时, 是否舍弃最后一批数据

LeakyReLu函数

图像及参数

我们可以与ReLu函数对比,看一下区别:

 

主要区别就是在小于0的部分了 

代码

导库

import matplotlib.pyplot as plt
import matplotlib 
import torch
from torch.utils.data import DataLoader
import torchvision
from torchvision import transforms
import numpy as np

数据集处理

transform = transforms.Compose([
transforms.ToTensor(), 
transforms.Normalize(0.5, 0.5)
])
traindata = torchvision.datasets.MNIST(root='D:\learn_pytorch\数据集', train=True, download=True,
                                       transform=transform)  # 训练集60,000张用于训练

在加载数据集时,我们要将数据进行归一化,在GAN中,我们就需要将数据归一化到(-1,1)之间,这是为什么呢?原因是我们在下面会用到Tanh激活函数,而Tanh函数的范围是在-1到1之间的,见下图:

在我们既然知道了为什么要这样,下面就要学会如何做到了 

ToTensor中,我们是将数据的范围限制在了(0,1)之间,而后面的Normalize是将数据限制在(-1,1)之间,计算公式为(x-均值)/方差 

生成器

class Generator(torch.nn.Module):
    def __init__(self):
        super(Generator, self).__init__()
        self.main = torch.nn.Sequential(
            torch.nn.Linear(100, 256),
            torch.nn.ReLU(),
            torch.nn.Linear(256, 512),
            torch.nn.ReLU(),
            torch.nn.Linear(512, 28 * 28),
            torch.nn.Tanh()
        )

    def forward(self, x):
        img = self.main(x)
        img = img.reshape(-1, 28, 28)
        return img

在这里,我们需要知道,生成器的输入和输出是什么,输入时我们的噪音,而输出一张图片。

在后向传播中,我们最后再将图片进行展平。

判别器

class Discraiminator(torch.nn.Module):
    def __init__(self):
        super(Discraiminator, self).__init__()
        self.mainf = torch.nn.Sequential(
            torch.nn.Linear(28 * 28, 512),
            torch.nn.LeakyReLU(),
            torch.nn.Linear(512, 256),
            torch.nn.LeakyReLU(),
            torch.nn.Linear(256, 1),
            torch.nn.Sigmoid()
        )

    def forward(self, x):
        x = x.view(-1, 28 * 28)
        x = self.mainf(x)
        return x

我们同样需要了解判别器的输入和输出,输入是一张(1,28,28)图片,输出为二分类的概率值。

在判别器中,我们如果使用ReLu函数,在小于0的部分就会出现梯度消失的问题,这时候我们就可以用到LeadkyReLu了,它能够优化GAN的训练。

最后的Sigmoid激活函数,将输出压缩到0到1之间,这通常用于二分类问题,但在这里,它用于表示输入是真实数据的概率。

而在后向传播中,我们需要先对图片进行展平。


定义损失函数,优化函数和优化器


# 定义损失函数和优化函数
device = 'cuda' if torch.cuda.is_available() else 'cpu'
gen = Generator().to(device)
dis = Discraiminator().to(device)
# 定义优化器
gen_opt = torch.optim.Adam(gen.parameters(), lr=0.0001)
dis_opt = torch.optim.Adam(dis.parameters(), lr=0.0001)
loss_fn = torch.nn.BCELoss()  # 损失函数

在这里,我们选择使用BCELoss,交叉熵损失函数,这是因为在GAN中,判别器通常被视为一个二分类器,它试图区分输入是真实样本还是由生成器生成的假样本,而BCELoss就是用来做二分类的损失函数,正好对应。

在优化器部分,它们分别对生成器和判别器的参数进行优化。

图像显示

def gen_img_plot(model, testdata):
    pre = np.squeeze(model(testdata).detach().cpu().numpy())
    # tensor.detach()
    # 返回一个新的tensor,从当前计算图中分离下来的,但是仍指向原变量的存放位置,不同之处只是requires_grad为false,得到的这个tensor永远不需要计算其梯度,不具有grad。
    # 即使之后重新将它的requires_grad置为true,它也不会具有梯度grad
    # 这样我们就会继续使用这个新的tensor进行计算,后面当我们进行反向传播时,到该调用detach()的tensor就会停止,不能再继续向前进行传播
    plt.figure()
    for i in range(16):
        plt.subplot(4, 4, i + 1)
        plt.imshow(pre[i])
    plt.show()

因为我们最终要得到要得到的是处理数据输出的数组,所以我们要用squeeze将额外的单维度删除。

detach是单独开辟空间来保存数据,从而保证数据的稳定性。

plt.figure用来生成一个新画布。

 使用subplot函数在一个4x4的网格中定位每个子图。i + 1是因为子图的索引是从1开始的,而不是从0开始。 

imshow是在子图中显示图像。

最后的show来显示整体的图像。

后向传播与训练模型

dis_loss = []  # 判别器损失值记录
gen_loss = []  # 生成器损失值记录
lun = []  # 轮数
for epoch in range(60):
    d_epoch_loss = 0
    g_epoch_loss = 0
    cout = len(trainload)  # 938批次
    for step, (img, _) in enumerate(trainload):
        img = img.to(device)  # 图像数据
        # print('img.size:',img.shape)#img.size: torch.Size([64, 1, 28, 28])
        size = img.size(0)  # 一批次的图片数量64
        # 随机生成一批次的100维向量样本,或者说100个像素点
        random_noise = torch.randn(size, 100, device=device)

        # 判断器的后向传播
        dis_opt.zero_grad()
        real_output = dis(img)
        d_real_loss = loss_fn(real_output, torch.ones_like(real_output))  # 真实数据的损失函数值
        d_real_loss.backward()

        gen_img = gen(random_noise)
        fake_output = dis(gen_img.detach())
        d_fake_loss = loss_fn(fake_output, torch.zeros_like(fake_output))  # 人造的数据的损失函数值
        d_fake_loss.backward()

        d_loss = d_real_loss + d_fake_loss
        dis_opt.step()

        # 生成器的后向传播
        gen_opt.zero_grad()
        fake_output = dis(gen_img)
        g_loss = loss_fn(fake_output, torch.ones_like(fake_output))
        g_loss.backward()
        gen_opt.step()
        d_epoch_loss += d_loss
        g_epoch_loss += g_loss
    dis_loss.append(float(d_epoch_loss))
    gen_loss.append(float(g_epoch_loss))
    print(f'第{epoch + 1}轮的生成器损失值:{g_epoch_loss},判别器损失值{d_epoch_loss}')
    lun.append(epoch + 1)

使用enumerate遍历训练数据集trainload,其中img是图像数据,但_表示我们在这里不使用标签(因为GAN是无监督的)。

step()用来更新判别器的模型参数。

在生成器的后向传播部分,

我们先进行梯度清零,然后通过生成器生成假图像,然后进行前向传播。

我们期望判别器对假图像的评分接近1(真实),因此我们将目标标签设置为与fake_output形状相同的全1张量torch.ones_like(fake_output)

在这里,d_loss和g_loss是一张图像中的损失值,而d_epoch_loss和g_epoch_loss是每一轮损失值的累加,用于最后图像的绘制。

生成图像


matplotlib.rcParams['font.sans-serif'] = ['KaiTi']
plt.figure()
plt.plot(lun, dis_loss, 'r', label='判别器损失值')
plt.plot(lun, gen_loss, 'b', label='生成器损失值')
plt.xlabel('训练轮数', fontsize=12)
plt.ylabel('损失值', fontsize=12)
plt.title('损失值随着训练轮数得变化情况:',  fontsize=18)
plt.legend()
plt.show()
random_noise = torch.randn(16, 100, device=device)
gen_img_plot(gen, random_noise)

随机生成的噪声有16个样本,100个维度

全部代码


import matplotlib.pyplot as plt
import matplotlib
import torch
from torch.utils.data import DataLoader
import torchvision
from torchvision import transforms
import numpy as np

# 导入数据集并且进行数据处理
transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize(0.5, 0.5)
])
traindata = torchvision.datasets.MNIST(root='./data', train=True, download=True,
                                       transform=transform)  # 训练集60,000张用于训练
# 利用DataLoader加载数据集
trainload = DataLoader(dataset=traindata, shuffle=True, batch_size=64)


# GAN生成对抗网络,步骤:
# 首先编写生成器和判别器
# 然后固定生成器,用我们的数据优化判别器,试得我们最开始生成器生成的图片判断为0,真实图片判断为1
# 接着固定判别器,利用我们的判别器判断生成器生成的图片,以判断的尽可能接近一为目的优化我们的生成器
# 生成器的代码(针对手写字体识别)
class Generator(torch.nn.Module):
    def __init__(self):
        super(Generator, self).__init__()
        self.main = torch.nn.Sequential(
            torch.nn.Linear(100, 256),
            torch.nn.ReLU(),
            torch.nn.Linear(256, 512),
            torch.nn.ReLU(),
            torch.nn.Linear(512, 28 * 28),
            torch.nn.Tanh()
        )

    def forward(self, x):
        img = self.main(x)
        img = img.reshape(-1, 28, 28)
        return img


# 判别器,最后判断0,1,这意味着最后可以是一个神经元或者两个神经元
class Discraiminator(torch.nn.Module):
    def __init__(self):
        super(Discraiminator, self).__init__()
        self.mainf = torch.nn.Sequential(
            torch.nn.Linear(28 * 28, 512),
            torch.nn.LeakyReLU(),
            torch.nn.Linear(512, 256),
            torch.nn.LeakyReLU(),
            torch.nn.Linear(256, 1),
            torch.nn.Sigmoid()
        )

    def forward(self, x):
        x = x.view(-1, 28 * 28)
        x = self.mainf(x)
        return x


# 定义损失函数和优化函数
device = 'cuda' if torch.cuda.is_available() else 'cpu'
gen = Generator().to(device)
dis = Discraiminator().to(device)
# 定义优化器
gen_opt = torch.optim.Adam(gen.parameters(), lr=0.0001)
dis_opt = torch.optim.Adam(dis.parameters(), lr=0.0001)
loss_fn = torch.nn.BCELoss()  # 损失函数


def gen_img_plot(model, testdata):
    pre = np.squeeze(model(testdata).detach().cpu().numpy())
    # tensor.detach()
    # 返回一个新的tensor,从当前计算图中分离下来的,但是仍指向原变量的存放位置,不同之处只是requires_grad为false,得到的这个tensor永远不需要计算其梯度,不具有grad。
    # 即使之后重新将它的requires_grad置为true,它也不会具有梯度grad
    # 这样我们就会继续使用这个新的tensor进行计算,后面当我们进行反向传播时,到该调用detach()的tensor就会停止,不能再继续向前进行传播
    plt.figure()
    for i in range(16):
        plt.subplot(4, 4, i + 1)
        plt.imshow(pre[i])
    plt.show()


# 后向传播
dis_loss = []  # 判别器损失值记录
gen_loss = []  # 生成器损失值记录
lun = []  # 轮数
for epoch in range(60):
    d_epoch_loss = 0
    g_epoch_loss = 0
    cout = len(trainload)  # 938批次
    for step, (img, _) in enumerate(trainload):
        img = img.to(device)  # 图像数据
        # print('img.size:',img.shape)#img.size: torch.Size([64, 1, 28, 28])
        size = img.size(0)  # 一批次的图片数量64
        # 随机生成一批次的100维向量样本,或者说100个像素点
        random_noise = torch.randn(size, 100, device=device)

        # 判断器的后向传播
        dis_opt.zero_grad()
        real_output = dis(img)
        d_real_loss = loss_fn(real_output, torch.ones_like(real_output))  # 真实数据的损失函数值
        d_real_loss.backward()

        gen_img = gen(random_noise)
        fake_output = dis(gen_img.detach())
        d_fake_loss = loss_fn(fake_output, torch.zeros_like(fake_output))  # 人造的数据的损失函数值
        d_fake_loss.backward()

        d_loss = d_real_loss + d_fake_loss
        dis_opt.step()

        # 生成器的后向传播
        gen_opt.zero_grad()
        fake_output = dis(gen_img)
        g_loss = loss_fn(fake_output, torch.ones_like(fake_output))
        g_loss.backward()
        gen_opt.step()
        d_epoch_loss += d_loss
        g_epoch_loss += g_loss
    dis_loss.append(float(d_epoch_loss))
    gen_loss.append(float(g_epoch_loss))
    print(f'第{epoch + 1}轮的生成器损失值:{g_epoch_loss},判别器损失值{d_epoch_loss}')
    lun.append(epoch + 1)

matplotlib.rcParams['font.sans-serif'] = ['KaiTi']
plt.figure()
plt.plot(lun, dis_loss, 'r', label='判别器损失值')
plt.plot(lun, gen_loss, 'b', label='生成器损失值')
plt.xlabel('训练轮数', fontsize=12)
plt.ylabel('损失值', fontsize=12)
plt.title('损失值随着训练轮数得变化情况:',  fontsize=18)
plt.legend()
plt.show()
random_noise = torch.randn(16, 100, device=device)
gen_img_plot(gen, random_noise)

运行结果
 

第1轮的生成器损失值:2226.86328125,判别器损失值461.5265808105469
第2轮的生成器损失值:2378.969970703125,判别器损失值459.3701477050781
第3轮的生成器损失值:2422.438232421875,判别器损失值355.0154113769531
第4轮的生成器损失值:3410.994873046875,判别器损失值172.3834686279297
第5轮的生成器损失值:3589.7734375,判别器损失值168.7844696044922
第6轮的生成器损失值:3944.258544921875,判别器损失值125.10688781738281
第7轮的生成器损失值:4293.7861328125,判别器损失值138.3419952392578
第8轮的生成器损失值:4436.89404296875,判别器损失值159.64407348632812
第9轮的生成器损失值:4485.7646484375,判别器损失值177.5517578125
第10轮的生成器损失值:4136.85986328125,判别器损失值210.64602661132812
第11轮的生成器损失值:4072.7958984375,判别器损失值246.29910278320312
第12轮的生成器损失值:4298.8623046875,判别器损失值183.00152587890625
第13轮的生成器损失值:4899.4794921875,判别器损失值171.33628845214844
第14轮的生成器损失值:4851.458984375,判别器损失值161.920654296875
第15轮的生成器损失值:4995.62646484375,判别器损失值155.28732299804688
第16轮的生成器损失值:4987.4140625,判别器损失值142.6618194580078
第17轮的生成器损失值:5511.90673828125,判别器损失值126.41560363769531
第18轮的生成器损失值:5509.65771484375,判别器损失值157.1754913330078
第19轮的生成器损失值:5164.8671875,判别器损失值143.5445556640625
第20轮的生成器损失值:5490.17236328125,判别器损失值156.86929321289062
第21轮的生成器损失值:5189.4921875,判别器损失值177.5731201171875
第22轮的生成器损失值:5293.32080078125,判别器损失值168.159912109375
第23轮的生成器损失值:4971.2646484375,判别器损失值189.78167724609375
第24轮的生成器损失值:4590.87158203125,判别器损失值211.07289123535156
第25轮的生成器损失值:4739.5732421875,判别器损失值214.7382354736328
第26轮的生成器损失值:4700.568359375,判别器损失值218.89926147460938
第27轮的生成器损失值:4146.5048828125,判别器损失值269.0607604980469
第28轮的生成器损失值:3846.898681640625,判别器损失值287.00604248046875
第29轮的生成器损失值:3559.870361328125,判别器损失值317.5647888183594
第30轮的生成器损失值:3378.71240234375,判别器损失值336.30572509765625
第31轮的生成器损失值:4269.37060546875,判别器损失值257.89910888671875
第32轮的生成器损失值:5209.896484375,判别器损失值191.99989318847656
第33轮的生成器损失值:4632.1728515625,判别器损失值261.9479064941406
第34轮的生成器损失值:2979.66015625,判别器损失值363.874267578125
第35轮的生成器损失值:2710.74462890625,判别器损失值405.0263671875
第36轮的生成器损失值:2661.800048828125,判别器损失值421.5466613769531
第37轮的生成器损失值:2625.377197265625,判别器损失值414.751708984375
第38轮的生成器损失值:2809.101318359375,判别器损失值399.09942626953125
第39轮的生成器损失值:3797.715087890625,判别器损失值314.6676025390625
第40轮的生成器损失值:6223.8974609375,判别器损失值151.0428924560547
第41轮的生成器损失值:3305.96533203125,判别器损失值355.9456481933594
第42轮的生成器损失值:2672.400634765625,判别器损失值395.23834228515625
第43轮的生成器损失值:2538.265625,判别器损失值425.629638671875
第44轮的生成器损失值:2496.415283203125,判别器损失值443.06085205078125
第45轮的生成器损失值:2451.716796875,判别器损失值449.18194580078125
第46轮的生成器损失值:2397.526123046875,判别器损失值467.0350341796875
第47轮的生成器损失值:2427.2900390625,判别器损失值459.0263977050781
第48轮的生成器损失值:2440.54736328125,判别器损失值469.6186218261719
第49轮的生成器损失值:2597.76953125,判别器损失值439.3223876953125
第50轮的生成器损失值:2724.003173828125,判别器损失值438.4668273925781
第51轮的生成器损失值:2539.636474609375,判别器损失值459.2343444824219
第52轮的生成器损失值:2288.4130859375,判别器损失值498.2747802734375
第53轮的生成器损失值:2244.51513671875,判别器损失值506.4640197753906
第54轮的生成器损失值:2242.865478515625,判别器损失值502.57275390625
第55轮的生成器损失值:2198.66552734375,判别器损失值506.5917053222656
第56轮的生成器损失值:2217.268310546875,判别器损失值502.77081298828125
第57轮的生成器损失值:2246.22802734375,判别器损失值502.93206787109375
第58轮的生成器损失值:2165.259033203125,判别器损失值516.4965209960938
第59轮的生成器损失值:2146.760009765625,判别器损失值519.462890625
第60轮的生成器损失值:2110.582763671875,判别器损失值528.8636474609375

进程已结束,退出代码为 0

我们得生成器损失值是波动的,判别器损失值也是,很难说他们的趋势走向(当然估计和我的训练轮数有关) 

 

这是我们生成器生成的“伪造的图片”,从这里可以看出来已经很不错了。  

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

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

相关文章

每周打靶VulnHub靶机-DEATHNOTE_ 1

Deathnote: 1 靶机传送门 don’t waste too much time thinking outside the box . It is a Straight forward box . 不要浪费太多时间跳出框框思考问题。这是一个很直接的盒子 是不是所有线索都在这个盒子里? 1.信息搜集 使用nmap进行域内存活主机扫描发现target …

机器学习-12-sklearn案例03-flask对外提供服务

整体思路 训练一个模型,把模型保存 写一个基于flask的web服务,在web运行时加载模型,并在对应的接口调用模型进行预测并返回 使用curl进行测试,测试通过 再创建一个html页面,接受参数输入,并返回。 目录结…

一图入门LSM Tree

本图主要解释了LSM是什么,有什么用,以及为什么? 这边再进行简要总结,具体内容可以查看图片。 LSM是什么? LSM是一种存储结构,组织了数据在存储介质(磁盘)上的方式。 LSM有什么用&…

微信小程序(Taro)获取经纬度并转化为具体城市

1、获取经纬度 申请权限,想要使用微信小程序获取经纬度的方法是要申请该方面的权限。 获取经纬度的方法有很多选择其中一个使用就好。 我使用的是Taro.getFuzzyLocation() 在app.config.js中需要添加设置 requiredPrivateInfos: ["getFuzzyLocat…

线性代数的一些理解(更新中)

以前学的时候都是囫囵吞枣,能搞过就得了。现在有了点时间可以静下来看看。。 还是分成点来看吧。 1 小车运行 一个车匀速在一维坐标前行,速度是2米每秒,起始点是0。如何描述 设 𝑥(𝑡) 表示车辆在时间 &#x1d461…

【赠书活动第4期】《Rust编程与项目实战》

赠书活动 《Rust编程与项目实战》免费赠书 3 本, 收到赠书之后,写一篇 本书某一节内容 的学习博客文章。 可在本帖评论中表示参加,即可获得赠书,先到先得。学习心得博客链接,后面有空发上来。 赠书截止日期为送出3…

使用FFmpeg处理RTSP视频流并搭建RTMP服务器实现图片转直播全流程

目录 一、FFmpeg安装与配置教程二、搭建并配置Nginx RTMP服务器三、从RTSP视频流提取帧并保存为图片四、将图片序列转换为视频五、将视频推送为直播流六、将图片序列推送为直播流 在实时音视频领域,我们经常需要处理从各种源(如摄像头)获取的…

Ansible的安装与配置

Ansible的安装与配置 1. 安装ansible # ansible是epel源提供的,所以必须安装epel: [rootRocky9 ~]# yum -y install epel-release Last metadata expiration check: 0:01:53 ago on Tue 26 Dec 2023 10:05:34 PM CST. Dependencies resolved. Package …

微信小程序原生组件使用

1、video组件使用 <view class"live-video"><video id"myVideo" src"{{videoSrc}}" bindplay"onPlay" bindfullscreenchange"fullScreenChange" controls object- fit"contain"> </video&g…

Kubernetes: 从零开始理解K8s架构

目录 一、简介 二、Kubernetes 架构原理 2.1 控制平面 2.2 Node 组件 2.3 Container Image 2.4 kubelet 2.5 Cluster 三、服务调用 四、总结 一、简介 Kubernetes 是一个开源的容器编排系统&#xff0c;用于自动化应用容器的部署、扩展和管理。它是Google基于Borg…

Yolov8目标检测——在Android上部署Yolov8 tflite模型

1. 简介 YOLOv8 是一种用于目标检测的深度学习模型&#xff0c;它是 YOLO&#xff08;You Only Look Once&#xff09;系列的最新版本之一。YOLO 系列因其高效和准确性而在计算机视觉领域非常受欢迎&#xff0c;特别是在需要实时目标检测的应用中&#xff0c;如视频监控、自动…

【Shell编程】3.Shell字符串、Shell数组

目录 Shell字符串 代码1 test3_1.sh 运行 结果 获取字符串长度 代码2 test3_2.sh 运行 结果 Shell字符串拼接 代码3 test3_3.sh 运行 结果 Shell字符串截取 从指定位置开始截取 从字符串左边开始计数 从字符串右边开始计数 从指定字符开始截取 使用#号截取…

煤矿防爆气象传感器

TH-WFB5随着工业技术的不断发展&#xff0c;煤矿作为我国能源领域的重要组成部分&#xff0c;其安全生产问题一直备受关注。在煤矿生产过程中&#xff0c;井下环境复杂多变&#xff0c;瓦斯、煤尘等易燃易爆物质的存在使得井下安全工作尤为重要。为了提高煤矿生产的安全性&…

Apache Flume概述

Apache Flume概述 1.Flume定义 ​ Flume是cloudera(CDH版本的hadoop) 开发的一个分布式、可靠、高可用的海量日志收集系统。 它将各个服务器中的数据收集起来并送到指定的地方去&#xff0c;比如说送到HDFS、Hbase&#xff0c;简单来说flume就是收集日志的。 2.Flume基础架构…

inBuilder 低代码平台新特性推荐 - 第十八期

今天来给大家带来的是inBuilder低代码平台特性推荐系列第十八期——表单设计器集成预约日历组件。 一、场景介绍 项目上希望用日历的形式展示某地点在一段时间内的预约记录&#xff0c;表单设计器新增支持创建日历预约视图&#xff0c;并配置预约属性。 二、运行效果 三、前…

成都一体化污水处理成套设备如何选型

一体化污水处理成套设备因其占地面积小、操作简便、处理效果稳定等优点&#xff0c;在小型污水处理项目中得到了广泛应用。在选型时&#xff0c;应考虑以下几个关键因素&#xff1a; 处理规模&#xff1a;根据需要处理的污水量&#xff08;通常以每天处理的立方米数表示&#x…

滑动窗口篇: 长度最小子数组|无重复字符最长字串

目录 1、滑动窗口算法 1.1 核心概念 1.2 基本步骤 1.3 应用场景 1.4 优势 2. leetcode 209 长度最小子数组 暴力解题思路&#xff1a; 滑动窗口思路&#xff1a; 3、无重复字符的最长子串 暴力解题思路&#xff1a; 滑动窗口思路&#xff1a; 1、滑动窗口算法 滑动…

React 第二十九章 React 和 Vue 描述页面的区别

面试题&#xff1a;React 和 Vue 是如何描述 UI 界面的&#xff1f;有一些什么样的区别&#xff1f; 标准且浅显的回答&#xff1a; React 中使用的是 JSX&#xff0c;Vue 中使用的是模板来描述界面 前端领域经过长期的发展&#xff0c;目前有两种主流的描述 UI 的方案&#xf…

基于MWORKS 2024a的MIMO-OFDM 无线通信系统设计

一、引言 在终端设备和数据流量爆发式增长的今天&#xff0c;如何提升通信系统容量、能量效率和频谱利用率成为5G通信的关键问题之一。大规模天线阵列作为5G及B5G无线通信关键技术通过把原有发送端天线数量提升一个或多个数量级&#xff0c;实现波束聚集、控制波束转向&#x…

《架构风清扬-Java面试系列第29讲》聊聊DelayQueue的使用场景

DelayQueue是BlockingQueue接口的一个实现类之一 这个属于基础性问题&#xff0c;老规矩&#xff0c;我们将从使用场景和代码示例来进行讲解 来&#xff0c;思考片刻&#xff0c;给出你的答案 1&#xff0c;使用场景 实现&#xff1a;延迟队列&#xff0c;其中元素只有在其预定…