深度学习--生成对抗网络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 = 0g_epoch_loss = 0cout = 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_lossdis_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_lossg_epoch_loss += g_lossdis_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 = 0g_epoch_loss = 0cout = 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_lossdis_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_lossg_epoch_loss += g_lossdis_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

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

 

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

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

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

相关文章

如何创建微信小程序?只需3步完成小程序制作

微信,中国最大的社交媒体应用程序,几个月前推出了微信小程序,这一神奇的功能立即大受欢迎。这些小程序让在中国注册的商业实体所有者创建一个小程序来与微信用户互动。这些小程序不需要在用户手机上进行任何安装,只需通过微信应用…

STM32微秒级别延时--F407--TIM1

基本配置: TIM1挂载在APB2总线上,150MHz经过15分频,得到10MHz计数频率,由于disable了自动重装载,所以只需要看下一次计数值是多少即可。 void TIM1_Delay_us(uint16_t us) //使用阻塞方式进行延时,ARR值不…

【C 数据结构-动态内存管理】4. 无用单元收集(垃圾回收机制)

文章目录 【 1. 问题描述与解决方法 】【 2. 中断回收机制 】 【 1. 问题描述与解决方法 】 问题描述 动态存储管理的运行机制可以概括为:当用户发出申请空间的请求后,系统向用户分配内存;用户运行结束释放存储空间后,系统回收内…

Fizzler库+C#:从微博抓取热点的最简单方法

概述 在这篇技术文章中,我们将深入研究如何利用Fizzler库结合C#语言,以实现从微博平台抓取热点信息的功能。微博作为中国乃至全球范围内具有重要影响力的社交媒体平台之一,在互联网信息传播中扮演着举足轻重的角色。通过Fizzler这一强大的.N…

Pytorch 实现情感分析

情感分析 情感分析是 NLP 一种应用场景,模型判断输入语句是积极的还是消极的,实际应用适用于评论、客服等多场景。情感分析通过 transformer 架构中的 encoder 层再加上情感分类层进行实现。 安装依赖 需要安装 Poytorch NLP 相关依赖 pip install t…

JVM学习笔记【基础篇:垃圾回收】

自动垃圾回收 C/C的内存管理 ⚫ 在C/C这类没有自动垃圾回收机制的语言中,一个对象如果不再使用,需要手动释放,否则就会出现 内存泄漏。我们称这种释放对象的过程为垃圾回收,而需要程序员编写代码进行回收的方式为手动回收。 ⚫ …

RTT潘多拉开发板上实现电源管理

简介 随着物联网(IoT)的兴起,产品对功耗的需求越来越强烈。作为数据采集的传感器节点通常需要在电池供电时长期工作,而作为联网的SOC也需要有快速的响应功能和较低的功耗。 在产品开发的起始阶段,首先考虑是尽快完成产品的功能开发。在产品…

数仓开发中期:理论巩固

一、数仓以及商业智能(Data Warehousing and Business Intelligence, DW/BI)系统 1.1数据操作和数据获取的区别 对所有组织来说,信息都是其最重要的财富之一。信息几乎总是用作两个目的:操作型记录的保存和分析型决策的制定。简单来说&…

Stack数据结构设计模板

第三章 栈、队列、数组 1.栈 1.1 顺序栈 #define MaxSize 20 typedef int ElemType; //顺序栈的定义 typedef struct {ElemType data[MaxSize];int top; }SqStack; // 初始化顺序栈 void InitSqStack(SqStack &S){S.top -1; }; // 入栈(增) bool Push(SqStack &S,El…

WIFI模块UDP电脑端调试

一,两端都是电脑端 1,电脑本机的IP地址 192.168.137.1 2,新建两个不同的连接,注意端口 二,WIFI 模块和电脑端连接 1,设置模块端目标IP和端口,电脑端只接收数据的话,IP、端口可随…

【从零开始学架构 架构基础】架构设计的本质、历史背景和目的

本文是《从零开始学架构》的第一篇学习笔记,主要理解架构的设计的本质定义、历史背景以及目的。 架构设计的本质 分别从三组概念的区别来理解架构设计。 系统与子系统 什么是系统,系统泛指由一群有关联的个体组成,根据某种规则运作&#…

企业终端安全管理软件有哪些?终端安全管理软件哪个好?

终端安全的重要性大家众所周知,关系到生死存亡的东西。 各类终端安全管理软件应运而生,为企业提供全方位、多层次的终端防护。 有哪些企业终端安全管理软件? 一、主流企业终端安全管理软件 1. 域智盾 域智盾是一款专为企业打造的全面终端…

奥威-金蝶BI现金流量表模板,可借鉴、可套用

企业现金流一旦出了问题都是大问题,会直接影响到企业的日常运作,甚至直接关系到企业能不能继续存活,因此现金流量表是企业财务分析中重要报表之一,也是企业监控财务监控情况的重要手段之一。那么这么重要的一份现金流量表该怎么做…

[Linux] GDB使用指南----包含CentOS7下安装以及使用

什么是GDB? GDB 是由 GUN 软件系统社区提供的调试工具,同 GCC 配套组成了一套完整的开发环境,GDB 是 Linux 和许多 类Unix系统的标准开发环境。可以用来调试C、C、Go、java、 objective-c、PHP等语言。 GDB的作用 程序启动时,可…

73. 矩阵置零/54. 螺旋矩阵

73. 矩阵置零 给定一个 m x n 的矩阵,如果一个元素为 0 ,则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 示例 1: 输入:matrix [[1,1,1],[1,0,1],[1,1,1]] 输出:[[1,0,1],[0,0,0],[1,0,1]] 思路&#x…

小程序搜索排名优化 三步操作提升

搜索排名优化最直接的一个目的就是为了提升小程序的排名和流量,获取用户的信任度。当用户在搜索关键词的时候,能让用户看到小程序,增加被发现和点击的机会。 一、关键词优化: 1.选择合适的关键词:选择与小程序内容高…

代码训练LeetCode(17)存在重复元素

代码训练(17)LeetCode之存在重复元素 Author: Once Day Date: 2024年5月7日 漫漫长路,才刚刚开始… 全系列文章可参考专栏: 十年代码训练_Once-Day的博客-CSDN博客 参考文章: 219. 存在重复元素 II - 力扣(LeetCode)力扣 (LeetCode) 全球…

fero - yolo - mamba:基于选择性状态空间的面部表情检测与分类

fero - yolo - mamba:基于选择性状态空间的面部表情检测与分类 摘要IntroductionRelated work FER-YOLO-Mamba: Facial Expression Detection and Classification Based on Selective State Space 摘要 面部表情识别(FER)在理解人类情绪线索方面起着关键…

零资源跑大模型:Hugging Face API + LiteLLM + Flask

前言 HuggingFace 是自然语言处理领域的开源软件库和平台,其收纳了众多最前沿的模型和数据集,并提供了 Serverless Inference API,用户可以轻松调用这些模型,甚至用于运行自己的私人模型。本教程将指导用户如何利用 Hugging Face…

RabbitMQ之消费者并发消费

为什么要引入消费者的并发消费? 当生产者的推送速度是远远超过消费者的能力的,可以提高消费者的消费速度。比如在java中我们可以启动多个 JVM 进程,实现多进程的并发消费,从而加速消费的速度,在mq中也可以通过设置配置…