PyTorch深度学习实战(30)——Deepfakes

PyTorch深度学习实战(30)——Deepfakes

    • 0. 前言
    • 1. Deepfakes 原理
    • 2. 数据集分析
    • 3. 使用 PyTorch 实现 Deepfakes
      • 3.1 random_warp.py
      • 3.2 Deepfakes.py
    • 小结
    • 系列链接

0. 前言

Deepfakes 是一种利用深度学习技术生成伪造视频和图像的技术。它通过将一个人的脸部特征或动作应用于另一个人的图像或视频中,以产生逼真的虚假内容。Deepfakes 技术在短时间内取得了显著的进展,并引起了广泛的关注和担忧,为了能够更好的采取相应的检测和防御措施,我们首先需要了解其基本原理。

1. Deepfakes 原理

我们已经学习了两种不同的图像到图像的转换任务,包括使用 UNet 执行语义分割和使用自编码器执行图像重建。 Deepfakes 是与以上任务具有相似理论基础的图像到图像转换的技术。
Deepfakes 是一种利用深度学习技术合成的虚假图像和视频的技术,Deepfakes 名称由 “deep learning” 和 “fake” 组成,通常用于制作虚假的音频和视频。例如,可以利用 Deepfakes 技术将一个人的脸替换到另一个人的身体上。
假设我们想要创建一个应用程序,获取给定的面部图像并以期望方式改变面部表情,在这种情况下,Deepfakes 是一种可行的技术,本节中,我们将介绍 Deepfakes 的基本原理,并使用小样本对抗学习技术生成具有感兴趣面部表情的逼真图像。
Deepfakes 任务中,我们使用数百张人物 A 的照片和数百张人物 B 的照片。目任务的目标是通过将 A 人物的面部表情应用到 B 人物脸上,或者将 B 人物的面部表情应用到 A 人物脸上,来重建人物 BA 的脸部特征。Deepfakes 图像生成过程的工作原理如下:

Deepfakes 原理
在上图中,我们通过编码器 (Encoder) 传递人物 A 和人物 B 的图像,得到与人物 A (Latent Face A) 和人物 B (Latent Face B) 对应的潜向量,将潜向量传递给它们相应的解码器 (Decoder ADecoder B) 以获取相应的原始图像 (Reconstructed Face AReconstructed Face B),编码器和解码器与自编码器非常相似。但在此任务中,我们只需要一个编码器,但需要两个解码器(每个解码器对应一个不同的人物)。
我们期望从编码器获得的潜向量表示图像中包含的面部表情信息,而解码器获取与人物相对应的图像。一旦编码器和两个解码器都经过训练后,在执行deepfakes图像生成时,我们按以下方式切换架构中的连接:

Deepfakes 原理
A 人物的潜在向量通过 B 人物的解码器时,重建的 B 人物脸部将具有 A 人物的特征,反之亦然,当 B 人物的潜在向量通过 A 人物的解码器时,重建的 A 人物脸部将具有 B 人物的表情。
另一个有助于生成逼真图像的技巧是对人脸图像进行扭曲,以这样的方式将其馈送到网络中:将扭曲后的人脸作为输入,预期的输出是原始图像。

2. 数据集分析

Pins Face Recognition 数据集包含通过 Pinterest 拍摄的图像,该数据集包括 100 多个不同人物的 10,000 多张图像,每个人物平均包含 100 张图片。
Pins Face Recognition 数据集的目标是推动人脸识别技术的发展,并为研究人员提供一个用于测试和比较不同算法性能的标准基准。该数据集中的图像包括不同的人物和背景,并且在姿势、光照和表情等方面具有一定的变化。可以通过 Kaggle 网站下载 Pins Face Recognition 数据集,并选择两个不同人物的照片作为训练数据集。

3. 使用 PyTorch 实现 Deepfakes

了解了 Deepfakes 的工作原理后,我们使用 PyTorch 实现使用自编码器生成将一个人物的表情转换到另一个人物面部的虚假图像。

3.1 random_warp.py

首先编写用于实现图像扭曲的实用脚本 random_warp.py

import numpy as np
import cv2random_transform_args = {'rotation_range': 10,'zoom_range': 0.05,'shift_range': 0.05,'random_flip': 0.4,
}def get_training_data(images, batch_size):indices = np.random.randint(len(images), size=batch_size)for i, index in enumerate(indices):image = images[index]image = random_transform(image, **random_transform_args)warped_img, target_img = random_warp(image)if i == 0:warped_images = np.empty((batch_size,) + warped_img.shape, warped_img.dtype)target_images = np.empty((batch_size,) + target_img.shape, warped_img.dtype)warped_images[i] = warped_imgtarget_images[i] = target_imgreturn warped_images, target_imagesdef random_transform(image, rotation_range, zoom_range, shift_range, random_flip):h, w = image.shape[0:2]rotation = np.random.uniform(-rotation_range, rotation_range)scale = np.random.uniform(1 - zoom_range, 1 + zoom_range)tx = np.random.uniform(-shift_range, shift_range) * wty = np.random.uniform(-shift_range, shift_range) * hmat = cv2.getRotationMatrix2D((w // 2, h // 2), rotation, scale)mat[:, 2] += (tx, ty)result = cv2.warpAffine(image, mat, (w, h), borderMode=cv2.BORDER_REPLICATE)if np.random.random() < random_flip:result = result[:, ::-1]return result# get pair of random warped images from aligened face image
def random_warp(image):assert image.shape == (256, 256, 3)range_ = np.linspace(128 - 80, 128 + 80, 5)mapx = np.broadcast_to(range_, (5, 5))mapy = mapx.Tmapx = mapx + np.random.normal(size=(5, 5), scale=5)mapy = mapy + np.random.normal(size=(5, 5), scale=5)interp_mapx = cv2.resize(mapx, (80, 80))[8:72, 8:72].astype('float32')interp_mapy = cv2.resize(mapy, (80, 80))[8:72, 8:72].astype('float32')warped_image = cv2.remap(image, interp_mapx, interp_mapy, cv2.INTER_LINEAR)src_points = np.stack([mapx.ravel(), mapy.ravel()], axis=-1)dst_points = np.mgrid[0:65:16, 0:65:16].T.reshape(-1, 2)mat = umeyama(src_points, dst_points, True)[0:2]target_image = cv2.warpAffine(image, mat, (64, 64))return warped_image, target_imagedef umeyama(src, dst, estimate_scale):num = src.shape[0]dim = src.shape[1]# Compute mean of src and dst.src_mean = src.mean(axis=0)dst_mean = dst.mean(axis=0)# Subtract mean from src and dst.src_demean = src - src_meandst_demean = dst - dst_meanA = np.dot(dst_demean.T, src_demean) / numd = np.ones((dim,), dtype=np.double)if np.linalg.det(A) < 0:d[dim - 1] = -1T = np.eye(dim + 1, dtype=np.double)U, S, V = np.linalg.svd(A)rank = np.linalg.matrix_rank(A)if rank == 0:return np.nan * Telif rank == dim - 1:if np.linalg.det(U) * np.linalg.det(V) > 0:T[:dim, :dim] = np.dot(U, V)else:s = d[dim - 1]d[dim - 1] = -1T[:dim, :dim] = np.dot(U, np.dot(np.diag(d), V))d[dim - 1] = selse:T[:dim, :dim] = np.dot(U, np.dot(np.diag(d), V.T))if estimate_scale:scale = 1.0 / src_demean.var(axis=0).sum() * np.dot(S, d)else:scale = 1.0T[:dim, dim] = dst_mean - scale * np.dot(T[:dim, :dim], src_mean.T)T[:dim, :dim] *= scalereturn T

3.2 Deepfakes.py

(1) 导入所需库:

from random_warp import get_training_data
import cv2
from glob import glob
import numpy as np
from torch.utils.data import DataLoader, Dataset
import random
import torch
import os
from torch import nn
from torch import optim
from matplotlib import pyplot as plt
device = 'cuda' if torch.cuda.is_available() else 'cpu'

(2) 从图像中提取人脸裁剪图像。

定义人脸级联分类器,人脸级联分类器是一种人脸检测方法,可以在图像中的面部周围绘制一个边界框:

face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')

OpenCV 提供了 4 个级联分类器用于人脸检测,可以从 OpenCV 官方下载这些级联分类器文件:

  • haarcascade_frontalface_alt.xml (FA1)
  • haarcascade_frontalface_alt2.xml (FA2)
  • haarcascade_frontalface_alt_tree.xml (FAT)
  • haarcascade_frontalface_default.xml (FD)

可以使用不同的数据集评估这些级联分类器的性能,总的来说这些分类器具有相似的准确率。

定义用于从图像中裁剪人脸的函数 crop_face()

def crop_face(img):gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)faces = face_cascade.detectMultiScale(gray, 1.3, 5)if(len(faces)>0):for (x,y,w,h) in faces:img2 = img[y:(y+h),x:(x+w),:]img2 = cv2.resize(img2,(256,256))return img2, Trueelse:return img, False

在以上函数中,我们通过人脸级联分类器传递灰度图像 gray 并裁剪包含人脸的矩形图像。接下来,返回一个重新调整大小的图像 img2。此外,为了考虑在图像中没有检测到人脸的情况,我们使用一个标志位记录图像中是否检测到人脸。

裁剪 personApersonB 的图像并将它们放在不同的文件夹中:

if not os.path.exists('cropped_faces_personA'):os.mkdir('cropped_faces_personA')
if not os.path.exists('cropped_faces_personB'):os.mkdir('cropped_faces_personB')
def crop_images(folder):images = glob(folder+'/*.jpg')for i in range(len(images)):img = cv2.imread(images[i], 1)img2, face_detected = crop_face(img)if(face_detected==False):continueelse:cv2.imwrite('cropped_faces_'+folder+'/'+str(i)+'.jpg',img2)#cv2.cvtColor(img2, cv2.COLOR_RGB2BGR))
crop_images('personA')
crop_images('personB')

(3) 创建数据加载器并检查数据:

class ImageDataset(Dataset):def __init__(self, items_A, items_B):self.items_A = np.concatenate([cv2.cvtColor(cv2.imread(f,1), cv2.COLOR_BGR2RGB)[None] for f in items_A])/255.self.items_B = np.concatenate([cv2.cvtColor(cv2.imread(f,1), cv2.COLOR_BGR2RGB)[None] for f in items_B])/255.self.items_A += self.items_B.mean(axis=(0, 1, 2)) - self.items_A.mean(axis=(0, 1, 2))def __len__(self):return min(len(self.items_A), len(self.items_B))def __getitem__(self, ix):a, b = random.choice(self.items_A), random.choice(self.items_B)return a, bdef collate_fn(self, batch):imsA, imsB = list(zip(*batch))imsA, targetA = get_training_data(imsA, len(imsA))imsB, targetB = get_training_data(imsB, len(imsB))imsA, imsB, targetA, targetB = [torch.Tensor(i).permute(0,3,1,2).to(device) for i in [imsA, imsB, targetA, targetB]]return imsA, imsB, targetA, targetBa = ImageDataset(glob('cropped_faces_personA/*.jpg'), glob('cropped_faces_personB/*.jpg'))
x = DataLoader(a, batch_size=32, collate_fn=a.collate_fn)

数据加载器返回四个张量,imsAimsBtargetAtargetB。第一个张量 imsA 是第三个张量 targetA 的扭曲(变形)版本,第二个 imsB 是第四个张量 targetB 的扭曲(变形)版本。
我们使用两个图像文件夹,每个人脸图像使用一个文件夹 (a =ImageDataset(glob('cropped_faces_personA/*.jpg'), glob('cropped_faces_personB/*.jpg))),并且在 __iteritems__ 方法中,分别在两个文件夹中随机获取一张人脸图像。
collate_fn 方法中的关键函数是 get_training_data,用于通过扭曲(变形)人脸图像执行图像增强,将扭曲后的人脸图像作为自编码器的输入,并尝试预测正常人脸图像。使用扭曲图像,不仅增加了训练数据的数量,而且还可以作为神经网络的正则化器,强制神经网络根据扭曲的人脸图像学习关键的面部特征。

查看示例图像样本:

idx = 1
imgs = next(iter(x))[0]
for i in imgs:plt.subplot(2,4,idx)plt.imshow(i.permute(1,2,0).detach().cpu())idx += 1if idx > 8:break
plt.show()

扭曲人脸
可以看到,输入图像是扭曲人脸图像,而输出图像为正常人脸图像,且输入与输出图像一一对应。

(4) 构建模型并查看模型架构。

定义卷积 (_ConvLayer) 和反卷积 (_UpScale) 函数以及 Reshape 类:

def _ConvLayer(input_features, output_features):return nn.Sequential(nn.Conv2d(input_features, output_features, kernel_size=5, stride=2, padding=2),nn.LeakyReLU(0.1, inplace=True))def _UpScale(input_features, output_features):return nn.Sequential(nn.ConvTranspose2d(input_features, output_features, kernel_size=2, stride=2, padding=0),nn.LeakyReLU(0.1, inplace=True))class Reshape(nn.Module):def forward(self, input):output = input.view(-1, 1024, 4, 4) # channel * 4 * 4return output

定义 Autoencoder 模型类,它包含一个编码器和两个解码器 (decoder_Adecoder_B):

class Autoencoder(nn.Module):def __init__(self):super(Autoencoder, self).__init__()self.encoder = nn.Sequential(_ConvLayer(3, 128),_ConvLayer(128, 256),_ConvLayer(256, 512),_ConvLayer(512, 1024),nn.Flatten(),nn.Linear(1024 * 4 * 4, 1024),nn.Linear(1024, 1024 * 4 * 4),Reshape(),_UpScale(1024, 512),)self.decoder_A = nn.Sequential(_UpScale(512, 256),_UpScale(256, 128),_UpScale(128, 64),nn.Conv2d(64, 3, kernel_size=3, padding=1),nn.Sigmoid(),)self.decoder_B = nn.Sequential(_UpScale(512, 256),_UpScale(256, 128),_UpScale(128, 64),nn.Conv2d(64, 3, kernel_size=3, padding=1),nn.Sigmoid(),)def forward(self, x, select='A'):if select == 'A':out = self.encoder(x)out = self.decoder_A(out)else:out = self.encoder(x)out = self.decoder_B(out)return out

(5) 定义 train_batch 函数:

def train_batch(model, data, criterion, optimizers):optA, optB = optimizersoptA.zero_grad()optB.zero_grad()imgA, imgB, targetA, targetB = data_imgA, _imgB = model(imgA, 'A'), model(imgB, 'B')lossA = criterion(_imgA, targetA)lossB = criterion(_imgB, targetB)lossA.backward()lossB.backward()optA.step()optB.step()return lossA.item(), lossB.item()

model(imgA, 'B') 使用来自 A 类的输入图像返回 B 类的图像,根据 imgA 预测 _imgA (其中 imgAtargetA 的扭曲版本)并使用 nn.L1Loss_imgAtargetA 进行比较,在训练期间预测新图像并定性地查看模型训练情况。

(6) 创建训练模型所需的所有组件:

model = Autoencoder().to(device)dataset = ImageDataset(glob('cropped_faces_personA/*.jpg'), glob('cropped_faces_personB/*.jpg'))
dataloader = DataLoader(dataset, 32, collate_fn=dataset.collate_fn)optimizers = optim.Adam([{'params': model.encoder.parameters()},{'params': model.decoder_A.parameters()}],lr=5e-5, betas=(0.5, 0.999)), \optim.Adam([{'params': model.encoder.parameters()},{'params': model.decoder_B.parameters()}], lr=5e-5, betas=(0.5, 0.999))criterion = nn.L1Loss()

(7) 训练模型:

n_epochs = 50000
train_loss_A = []
train_loss_B = []
if not os.path.exists('checkpoint'):os.mkdir('checkpoint')
for ex in range(n_epochs):N = len(dataloader)trn_loss_A = []trn_loss_B = []for bx,data in enumerate(dataloader):lossA, lossB = train_batch(model, data, criterion, optimizers)pos = (ex + (bx+1)/N)trn_loss_A.append(lossA)trn_loss_B.append(lossB)train_loss_A.append(np.average(trn_loss_A))train_loss_B.append(np.average(trn_loss_B))if (ex+1)%1000 == 0:state = {'state': model.state_dict(),'epoch': ex}torch.save(state, './checkpoint/autoencoder.pth')if (ex+1)%1000 == 0:bs = 5a,b,A,B = data_a = model(a[:bs], 'A')_b = model(a[:bs], 'B')x = torch.cat([A[:bs],_a,_b])idx = 1for im in x:plt.subplot(3, 5, idx)plt.imshow(im.permute(1,2,0).detach().cpu())idx += 1plt.show()_a = model(b[:bs], 'A')_b = model(b[:bs], 'B')x = torch.cat([B[:bs],_a,_b])idx = 1for im in x:plt.subplot(3, 5, idx)plt.imshow(im.permute(1,2,0).detach().cpu())idx += 1plt.show()

生成的重建图像如下所示:

重建图像
损失值的变化如下:

epochs = np.arange(n_epochs)+1
plt.plot(epochs, train_loss_A, 'bo', label='Training loss A')
plt.plot(epochs, train_loss_B, 'r-', label='Training loss B')
plt.title('Training and Test loss over increasing epochs')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()
plt.grid('off')
plt.show()

损失变化

如上图所示,可以通过调整自编码器使用两个解码器将表情从一张人脸交换到另一张人脸上。此外,随着训练的增加,重建的图像将变得更加逼真。

小结

Deepfakes 可以用于创造出艺术作品和娱乐内容,能够将一个人的表演或特征应用到不同的情境中,为电影、视频和游戏等领域带来创新和丰富多样的体验。也可以为电影制片人和视觉特效团队提供了更加高效和经济的方式来实现人物替换和数字化特效。相对于传统的化妆和后期制作技术,Deepfakes 可以更快速地生成逼真的效果。因此,Deepfakes 具备广泛创造性和应用潜力,但也应当研究相应的技术来避免隐私、欺骗和滥用等问题。

系列链接

PyTorch深度学习实战(1)——神经网络与模型训练过程详解
PyTorch深度学习实战(2)——PyTorch基础
PyTorch深度学习实战(3)——使用PyTorch构建神经网络
PyTorch深度学习实战(4)——常用激活函数和损失函数详解
PyTorch深度学习实战(5)——计算机视觉基础
PyTorch深度学习实战(6)——神经网络性能优化技术
PyTorch深度学习实战(7)——批大小对神经网络训练的影响
PyTorch深度学习实战(8)——批归一化
PyTorch深度学习实战(9)——学习率优化
PyTorch深度学习实战(10)——过拟合及其解决方法
PyTorch深度学习实战(11)——卷积神经网络
PyTorch深度学习实战(12)——数据增强
PyTorch深度学习实战(13)——可视化神经网络中间层输出
PyTorch深度学习实战(14)——类激活图
PyTorch深度学习实战(15)——迁移学习
PyTorch深度学习实战(16)——面部关键点检测
PyTorch深度学习实战(17)——多任务学习
PyTorch深度学习实战(18)——目标检测基础
PyTorch深度学习实战(19)——从零开始实现R-CNN目标检测
PyTorch深度学习实战(20)——从零开始实现Fast R-CNN目标检测
PyTorch深度学习实战(21)——从零开始实现Faster R-CNN目标检测
PyTorch深度学习实战(22)——从零开始实现YOLO目标检测
PyTorch深度学习实战(23)——使用U-Net架构进行图像分割
PyTorch深度学习实战(24)——从零开始实现Mask R-CNN实例分割
PyTorch深度学习实战(25)——自编码器(Autoencoder)
PyTorch深度学习实战(26)——卷积自编码器(Convolutional Autoencoder)
PyTorch深度学习实战(27)——变分自编码器(Variational Autoencoder, VAE)
PyTorch深度学习实战(28)——对抗攻击(Adversarial Attack)
PyTorch深度学习实战(29)——神经风格迁移

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

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

相关文章

学习Vue配置代理总结

今天学习了Vue的配置代理&#xff0c;当我们想要向服务器取回来数据时就先要向服务器发送请求&#xff0c;但前端发送请求的方式也有很多种&#xff0c;首先是发送请求的鼻祖JS的XMLHttpRequest&#xff08;xhr&#xff09;&#xff0c;它操作起来相对麻烦&#xff0c;开发中也…

SpringBoot自定义Starter(@EnableXXX和META-INF的SPI自动添加)

目录 1. 自定义Starter1.1 场景和效果1.2 starter实现1.2.1 创建自定义starter项目1.2.2 把所有maven依赖导入1.2.3 实现公共代码逻辑1.2.4 添加方式一&#xff1a;实现RobotAutoConfiguration配置类1.2.5 添加方式二&#xff1a;实现RobotAutoConfiguration配置类 EnableRobo…

Linux下如何快速调试I2C设备

Linux下如何快速调试I2C设备 目录 1 什么场景下需要快速调试I2C设备 2 如何快速调试I2C设备 3 如何获取I2C Tools工具集 3.1 获取I2C Tools工具集源码 3.2 编译I2C Tools工具集源码 3.3 为设备添加I2C Tools工具集 4 如何使用I2C Tools工具集 5 小结 1 什么场景下需要快…

强化app广告变现用户隐私合规,移动广告变现合规技巧

移动广告技术的发展帮助开发者极大提升了广告变现效率&#xff0c;APP作为用户个人信息处理的重要载体&#xff0c;自从《个人信息保护法》颁布以来&#xff0c;个人信息的使用已经成为监管重点&#xff0c;开发者强化合规意识&#xff0c;让广告变现业务“细水长流”&#xff…

Ansible Filter滤波器的使用

一、【说在前面】 Ansible Filter一般被称为滤波器或者叫过滤器。 这个东西初次听到以为是什么科学计算的东西&#xff0c;但是想来ansible不太可能有什么滤波操作&#xff0c;所以这个东西本质是一个数值筛选器&#xff0c;内置函数&#xff0c;本质是一个为了做区别化的工具…

AcrelEMS-CB商业建筑能源管理系统解决方案-安科瑞 蒋静

1概述 AcrelEMS-CB商业建筑能源管理系统&#xff0c;集电力监控、电能质量监测与治理、电气安全预警、能耗分析、照明控制、新能源使用、能源收费以及设备运维等功能于一体&#xff0c;通过一套系统对商业建筑的能源进行统一监控、统一运维和调度&#xff0c;系统可以通过WEB和…

【极光系列】springBoot集成Hibernate

【极光系列】springboot集成hibernate gitee地址 直接下载可用 https://gitee.com/shawsongyue/aurora.git 模块&#xff1a;aurora_hibernate mysql安装教程 参考我另外一篇文章&#xff0c;直接下载安装 https://blog.csdn.net/weixin_40736233/article/details/1355829…

FPGA 原理图细节--画引脚

BGA引脚表示 1.1 FPGA此引脚要正确和清晰&#xff0c;会在“Package Pin”中用到次物理接口 1.2, MCU 只用管对应的GPIO逻辑接口就可以了 标识Bank电平 标识出对应Bank的电平&#xff0c;在电路设计中可以清晰的知道对应的脚位输出电平。在"IO std"也方便的选择 Ea…

常见的限流算法

本文已收录至我的个人网站&#xff1a;程序员波特&#xff0c;主要记录Java相关技术系列教程&#xff0c;共享电子书、Java学习路线、视频教程、简历模板和面试题等学习资源&#xff0c;让想要学习的你&#xff0c;不再迷茫。 天下武学出同源 正所谓天下武学殊途同归&#xff…

N5181A/安捷伦Agilent N5181A信号发生器

181/2461/8938产品概述&#xff1a; 规格&#xff08;说明书&#xff09;&#xff1a;表示已校准的仪器在工作温度范围0-55C内存放至少2小时&#xff0c;除非另有说明&#xff0c;并经过45分钟预热期后的保证性能。的指标包括测量不确定度。除非另有说明&#xff0c;本文档中的…

【Python数据可视化】matplotlib之绘制高级图形:散点图、热力图、等值线图、极坐标图

文章传送门 Python 数据可视化matplotlib之绘制常用图形&#xff1a;折线图、柱状图&#xff08;条形图&#xff09;、饼图和直方图matplotlib之设置坐标&#xff1a;添加坐标轴名字、设置坐标范围、设置主次刻度、坐标轴文字旋转并标出坐标值matplotlib之增加图形内容&#x…

全自动洗衣机什么牌子好?内衣洗衣机便宜好用的牌子推荐

随着内衣洗衣机的流行&#xff0c;很多小伙伴在纠结该不该入手一款内衣洗衣机&#xff0c;专门来洗一些贴身衣物&#xff0c;答案是非常有必要的&#xff0c;因为我们现在市面上的大型洗衣机只能做清洁&#xff0c;无法对我们的贴身衣物进行一个高度除菌&#xff0c;而小小的内…

基于python的深度神经网络原理与实践

理论基础 什么是神经网络 我们知道深度学习是机器学习的一个分支&#xff0c;是一种以人工神经网络为架构&#xff0c;对数据进行表征学习的算法。而深度神经网络又是深度学习的一个分支&#xff0c;它在 wikipedia 上的解释如下&#xff1a; 深度神经网络&#xff08;Deep N…

Vue中keep-alive缓存的详解(深度理解)

文章目录 一、Keep-alive 是什么二、使用场景三、原理分析四、思考题&#xff1a;缓存后如何获取数据beforeRouteEnteractived 参考文献 一、Keep-alive 是什么 keep-alive是vue中的内置组件&#xff0c;能在组件切换过程中将状态保留在内存中&#xff0c;防止重复渲染DOM ke…

四搭建dockerhub私有仓库

搭建dockerhub私有仓库 很多场景下&#xff0c;我们需使用私有仓库管理Docker镜像。相比Docker Hub&#xff0c;私有仓库有以下优势&#xff1a; 节省带宽&#xff0c;对于私有仓库中已有的镜像&#xff0c;无需从Docker Hub下载&#xff0c;只需从私有仓库中下载即可&#x…

MySQL篇—通过Clone插件进行远程克隆数据(第三篇,总共三篇)

在介绍 Clone 最终篇之前&#xff0c;我们先简要回顾一下前面所讲的内容。在第一篇中&#xff0c;我们探讨了 Clone 的用途、使用的前提条件、存在的限制&#xff0c;以及它的备份原理。Clone 是一种用于复制和备份数据的工具&#xff0c;它能够快速高效地创建数据的精确副本。…

Spark原理——逻辑执行图

逻辑执行图 明确逻辑计划的边界 在 Action 调用之前&#xff0c;会生成一系列的RDD,这些RDD之间的关系&#xff0c;其实就是整个逻辑计划 val conf new SparkConf().setMaster("local[6]").setAppName("wordCount_source") val sc new SparkContext(conf)v…

JVM篇--Java内存区域高频面试题

java内存区域 1 Java 堆空间及 GC&#xff1f; 首先我们要知道java堆空间的产生过程&#xff1a; 即当通过java命令启动java进程的时候&#xff0c;就会为它分配内存&#xff0c;而分配内存的一部分就会用于创建堆空间&#xff0c;而当程序中创建对象的时候 就会从堆空间来分…

2024--Django平台开发-Redis集群(十一)

内容回顾 主从复制。 哨兵&#xff1a;实例启动了&#xff0c;哨兵节点没启动&#xff0c;Python通过redis-py连接报错。一定要确保实例节点和哨兵节点都启动了。 搭建集群用的是虚拟机的多台centos服务器&#xff0c;你在跟着学习的时候&#xff0c;一定要全部都是虚拟机&am…

5.矩阵分析

矩阵分析 文章目录 矩阵分析一、方阵范数1.1 矩阵范数1.2 与矩阵乘积相容的矩阵范数【定义】自相容范数 / 方阵范数 1.3 与向量范数相容的矩阵范数【定义】矩阵范数与向量范数相容【定理】任意自相容范数必存在与它相容的向量范数 二、算子范数2.1 方阵的算子范数【定理】由向量…