当前位置: 首页 > article >正文

【论文笔记】生成对抗网络 GAN

GAN

2014 年,Ian Goodfellow 等人提出生成对抗网络(Generative Adversarial Networks),GAN 的出现是划时代的,虽然目前主流的图像/视频生成模型是扩散模型(Diffusion Models)的天下,但是我们仍然有必要了解 GAN 的思想。

GAN 的核心思想是训练两个模型,分别为生成器(Generator)和辨别器(Discriminator),生成器的目标是生成虚假的数据,尽可能混淆辨别器,使其无法判别真实数据和虚假数据,而辨别器的目标则是尽可能将真实数据和虚假数据区分开来。这个过程如下图所示:

gan-example

生成器和辨别器处于一个对抗的过程,它们的能力不断地提升。GAN 的一个缺点在于它的训练过程不稳定,因此在 GAN 出来后,跟 GAN 相关的论文层出不穷,包括改进 GAN 的损失函数、训练方式,或者采用更先进的模型结构,使 GAN 的生成能力更强,同时使其训练过程更加稳定,但是 GAN 的核心思想是不变的。

模型结构

GAN 的结构如下图所示:

gan

GAN 的生成器和辨别器是两个独立的模型,在原始 GAN 中采用的生成器和辨别器都是多层感知机(Multi Layer Perceptron),后来出现了许多模型结构的改进,例如 DCGAN 将 MLP 替换为卷积神经网络。

辨别器

辨别器本质上是一个分类器,用于区分真实数据和由生成器生成的虚假数据,输出是一个 0-1 范围的标量,表示为真实数据的概率值。辨别器有两个数据来源:真实和虚假数据,训练辨别器的过程中,保持生成器的参数不变,利用二分类损失计算梯度,执行反向传播更新辨别器的参数,过程如下。

gan-disc

生成器

生成器用于生成虚假数据,尽可能混淆辨别器,生成器接受一个随机噪声(Random Noise),随机噪声的采样可以来自于均匀分布、正态分布等等,甚至可以是一张图片。生成器的作用就是将随机噪声分布转换为真实数据的分布,在生成器训练的过程中,保持辨别器的参数不变,利用辨别器的梯度来更新生成器。

在这里插入图片描述

损失函数

GAN 采用了 minimax 损失,其数学表达式如下:

min ⁡ G max ⁡ D V ( D , G ) = E x ∼ p d a t a ( x ) [ log ⁡ D ( x ) ] + E z ∼ p z ( z ) [ log ⁡ ( 1 − D ( G ( z ) ) ) ] \min_G \max_D V(D,G)=E_{x\sim p_{data}(x)}[\log D(x)]+E_{z\sim p_z(z)}[\log(1-D(G(z)))] GminDmaxV(D,G)=Expdata(x)[logD(x)]+Ezpz(z)[log(1D(G(z)))]

其中, V ( D , G ) V(D,G) V(D,G) 表示价值函数, x x x 为真实数据采样的样本, z z z 为生成器生成的样本。

minimax 损失本质上是一个二分类损失(Binary Cross Entropy),可以拆解为辨别器损失和生成器损失。

在训练辨别器的过程中,生成器参数保持不变,因此对于辨别器而言,\(G(z)\) 可以视为常数,其损失函数为:

L D = − E x ∼ p d a t a ( x ) [ log ⁡ D ( x ) ] − E z ∼ p z ( z ) [ log ⁡ ( 1 − D ( G ( z ) ) ) ] L_D=-E_{x\sim p_{data}(x)}[\log D(x)]-E_{z\sim p_z(z)}[\log(1-D(G(z)))] LD=Expdata(x)[logD(x)]Ezpz(z)[log(1D(G(z)))]

在训练生成器的过程中,辨别器参数保持不变,因此对于辨别器而言,价值函数的第一项为常数,在求导时忽略不计,因此生成器的损失函数为:

L G = − E z ∼ p z ( z ) [ log ⁡ ( D ( G ( z ) ) ) ] L_G=-E_{z\sim p_z(z)}[\log(D(G(z)))] LG=Ezpz(z)[log(D(G(z)))]

对于上述两个损失函数一个直观的理解是,对于 L G L_G LG 而言,我们希望生成器生成的假数据使判别器无法区分,即希望判别器输出的概率接近于 1,取对数后即接近于 0,由于判别器的输出在于 0 - 1 之间,因此取 log 后为负数,即转变为最大化对数概率,或最小化负对数概率,由于优化的过程通常是梯度下降的过程,因此选择后者。

在 GAN 的论文中,给出了一张用于阐述 GAN 的训练过程的图。假设随机噪声 z z z 采样自一维均匀分布,真实数据分布为标准正态分布。图中的黑色点线表示真实数据分布,蓝色虚线表示辨别器输出的概率分布,绿色实线表示生成器输出的概率分布。随着 GAN 的不断训练,生成器生成的数据分布逐渐接近于真实数据分布,辨别器越来越难以区分真实数据和假数据,因此在理想情况下,生成器完全学习到了真实数据分布,辨别器再也无法进行区分,因此输出的概率都为 50%,也就是图(d) 所示的直线。

gan-process

GAN 的训练过程以及 PyTorch 实现

以下是原始 GAN 论文中的训练算法:

train

注意:这里生成器的损失函数并不是前面重写的形式,但是它们两个是等价的,在实际中,作者采用前面重写的形式,因为他们认为这样训练更加稳定。实际的情况是都不那么稳定:)。

下面是一个 GAN 的 PyTorch 实现例子,生成器和辨别器均采用 MLP,在数据集 MNIST 上进行训练的代码,具体代码可见:vanilla-gan。

import os
from argparse import Namespace, ArgumentParser
import torch
from torch import nn, Tensor
from torchvision import datasets, transforms
from torchvision.utils import save_image, make_grid
from torch.utils.tensorboard import SummaryWriter
from torch.utils.data import DataLoaderclass Discriminator(nn.Module):"""Disrcminator in GAN.Model Architecture: [affine - leaky relu - dropout] x 3 - affine - sigmoid"""def __init__(self, image_shape: tuple[int, int, int]) -> None:super(Discriminator, self).__init__()C, H, W = image_shapeimage_size = C * H * Wself.model = nn.Sequential(nn.Linear(image_size, 512), nn.LeakyReLU(0.2), nn.Dropout(0.3),nn.Linear(512, 256), nn.LeakyReLU(0.2), nn.Dropout(0.3),nn.Linear(256, 128), nn.LeakyReLU(0.2), nn.Dropout(0.3),nn.Linear(128, 1), nn.Sigmoid())def forward(self, images: Tensor) -> Tensor:images = images.view(images.size(0), -1)return self.model(images)class Generator(nn.Module):"""Generator in GAN.Model Architecture: [affine - batchnorm - relu] x 4 - affine - tanh"""def __init__(self, image_shape: tuple[int, int, int], latent_dim: int) -> None:super(Generator, self).__init__()C, H, W = image_shapeimage_size = C * H * Wself.image_shape = image_shapeself.model = nn.Sequential(nn.Linear(latent_dim, 128), nn.BatchNorm1d(128), nn.ReLU(),nn.Linear(128, 256), nn.BatchNorm1d(256), nn.ReLU(),nn.Linear(256, 512), nn.BatchNorm1d(512), nn.ReLU(),nn.Linear(512, 1024), nn.BatchNorm1d(1024), nn.ReLU(),nn.Linear(1024, image_size), nn.Tanh())def forward(self, z: Tensor) -> Tensor:images: Tensor = self.model(z)return images.view(-1, *self.image_shape)# Image processing.
transform_mnist = transforms.Compose([transforms.ToTensor(),transforms.Normalize(mean=(0.5), std=(0.5))])transform_cifar = transforms.Compose([transforms.ToTensor(),transforms.Normalize(mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5))])# Device configuration.
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')def denormalize(x: Tensor) -> Tensor:out = (x + 1) / 2return out.clamp(0, 1)def get_args() -> Namespace:"""Get commandline arguments."""parser = ArgumentParser()parser.add_argument('--lr', type=float, default=0.0002, help='learning rate for Adam optimizer')parser.add_argument('--beta1', type=float, default=0.5, help='first momentum term for Adam')parser.add_argument('--beta2', type=float, default=0.999, help='second momentum term for Adam')parser.add_argument('--batch_size', type=int, default=64, help='size of a mini-batch')parser.add_argument('--num_epochs', type=int, default=100, help='training epochs')parser.add_argument('--latent_dim', type=int, default=100, help='dimensionality of the latent space')parser.add_argument('--dataset', type=str, default='MNIST', help='training dataset(MNIST | FashionMNIST | CIFAR10)')parser.add_argument('--sample_dir', type=str, default='samples', help='directory of image samples')parser.add_argument('--interval', type=int, default=1, help='epoch interval between image samples')parser.add_argument('--logdir', type=str, default='runs', help='directory of running log')parser.add_argument('--ckpt_dir', type=str, default='checkpoints', help='directory for saving model checkpoints')parser.add_argument('--seed', type=str, default=10213, help='random seed')return parser.parse_args()def setup(args: Namespace) -> None:torch.manual_seed(args.seed)# Create directory if not exists.if not os.path.exists(os.path.join(args.sample_dir, args.dataset)):os.makedirs(os.path.join(args.sample_dir, args.dataset))if not os.path.exists(os.path.join(args.ckpt_dir, args.dataset)):os.makedirs(os.path.join(args.ckpt_dir, args.dataset))def get_data_loader(args: Namespace) -> DataLoader:"""Get data loader."""if args.dataset == 'MNIST':data = datasets.MNIST(root='../data', train=True, download=True, transform=transform_mnist)elif args.dataset == 'FashionMNIST':data = datasets.FashionMNIST(root='../data', train=True, download=True, transform=transform_mnist)elif args.dataset == 'CIFAR10':data = datasets.CIFAR10(root='../data', train=True, download=True, transform=transform_cifar)else:raise ValueError(f'Unkown dataset: {args.dataset}, support dataset: MNIST | FashionMNIST | CIFAR10')return DataLoader(dataset=data, batch_size=args.batch_size, num_workers=4, shuffle=True)def train(args: Namespace, G: Generator, D: Discriminator, data_loader: DataLoader) -> None:"""Train Generator and Discriminator.Args:args(Namespace): arguments.G(Generator): Generator in GAN.D(Discriminator): Discriminator in GAN."""writer = SummaryWriter(os.path.join(args.logdir, args.dataset))# generate fixed noise for sampling.fixed_noise = torch.rand(64, args.latent_dim).to(device)# Loss and optimizer.criterion = nn.BCELoss().to(device)optimizer_G = torch.optim.Adam(G.parameters(), lr=args.lr, betas=(args.beta1, args.beta2))optimizer_D = torch.optim.Adam(D.parameters(), lr=args.lr, betas=(args.beta1, args.beta2))# Start training.for epoch in range(args.num_epochs):total_d_loss = total_g_loss = 0for images, _ in data_loader:m = images.size(0)images: Tensor = images.to(device)images = images.view(m, -1)# Create real and fake labels.real_labels = torch.ones(m, 1).to(device)fake_labels = torch.zeros(m, 1).to(device)# ================================================================== ##                      Train the discriminator                       ## ================================================================== ## Forward passoutputs = D(images)d_loss_real: Tensor = criterion(outputs, real_labels)z = torch.rand(m, args.latent_dim).to(device)fake_images: Tensor = G(z).detach()outputs = D(fake_images)d_loss_fake: Tensor = criterion(outputs, fake_labels)# Backward passd_loss: Tensor = d_loss_real + d_loss_fakeoptimizer_D.zero_grad()d_loss.backward()optimizer_D.step()total_d_loss += d_loss# ================================================================== ##                        Train the generator                         ## ================================================================== ## Forward passz = torch.rand(images.size(0), args.latent_dim).to(device)fake_images: Tensor = G(z)outputs = D(fake_images)# Backward passg_loss: Tensor = criterion(outputs, real_labels)optimizer_G.zero_grad()g_loss.backward()optimizer_G.step()total_g_loss += g_lossprint(f'''
=====================================
Epoch: [{epoch + 1}/{args.num_epochs}]
Discriminator Loss: {total_d_loss / len(data_loader):.4f}
Generator Loss: {total_g_loss / len(data_loader):.4f}
=====================================''')# Log Discriminator and Generator loss.writer.add_scalar('Discriminator Loss', total_d_loss / len(data_loader), epoch + 1)writer.add_scalar('Generator Loss', total_g_loss / len(data_loader), epoch + 1)fake_images: Tensor = G(fixed_noise)img_grid = make_grid(denormalize(fake_images), nrow=8, padding=2)writer.add_image('Fake Images', img_grid, epoch + 1)if (epoch + 1) % args.interval == 0:save_image(img_grid, os.path.join(args.sample_dir, args.dataset, f'fake_images_{epoch + 1}.png'))# Save the model checkpoints.torch.save(G.state_dict(), os.path.join(args.ckpt_dir, args.dataset, 'G.ckpt'))torch.save(D.state_dict(), os.path.join(args.ckpt_dir, args.dataset, 'D.ckpt'))def main() -> None:args = get_args()setup(args)image_shape = (1, 28, 28) if args.dataset in ('MNIST', 'FashionMNIST') else (3, 32, 32)data_loader = get_data_loader(args)# Generator and Discrminator.G = Generator(image_shape=image_shape, latent_dim=args.latent_dim).to(device)D = Discriminator(image_shape=image_shape).to(device)train(args, G, D, data_loader)if __name__ == '__main__':main()

参考

[1] I. Goodfellow et al., “Generative Adversarial Nets,” in Advances in Neural Information Processing Systems, Curran Associates, Inc., 2014. Accessed: Sep. 12, 2024. [Online]. Available: https://papers.nips.cc/paper_files/paper/2014/hash/5ca3e9b122f61f8f06494c97b1afccf3-Abstract.html

[2] eriklindernoren. “PyTorch-GAN”. Github 2018. [Online]. Available: https://github.com/eriklindernoren/PyTorch-GAN

[3] 李沐. “GAN论文逐段精读【论文精读】”. Bilibili 2021. [Online]. Available: https://www.bilibili.com/video/BV1rb4y187vD/?spm_id_from=333.1387.collection.video_card.click&vd_source=c8a32a5a667964d5f1068d38d6182813
n. “PyTorch-GAN”. Github 2018. [Online]. Available: https://github.com/eriklindernoren/PyTorch-GAN

相关文章:

【论文笔记】生成对抗网络 GAN

GAN 2014 年,Ian Goodfellow 等人提出生成对抗网络(Generative Adversarial Networks),GAN 的出现是划时代的,虽然目前主流的图像/视频生成模型是扩散模型(Diffusion Models)的天下&#xff0c…...

《鸟哥的Linux私房菜基础篇》---5 vim 程序编辑器

目录 一、vim程序编辑器的简介 二、命令模式快捷键(默认模式) 1、光标移动 2、编辑操作 3、搜索与替换 三、插入模式快捷键 四、底行模式快捷键(按:进入) 五、高级技巧 1、分屏操作 2、多文件编辑 3、可视化…...

spring+k8s 功能说明

以下是一个结合 Kubernetes(k8s) 和 Spring Boot 的完整实例,涵盖应用开发、容器化、部署到 Kubernetes 集群的全流程。 1. 创建 Spring Boot 应用 1.1 项目初始化 使用 Spring Initializr 生成一个简单的 REST API 项目: • 依…...

Enovia许可分析的自动化解决方案

随着企业产品生命周期管理(PLM)需求的不断演变,Enovia许可分析已成为确保资源优化和合规性的关键环节。然而,传统的手动许可分析方法往往效率低下、易出错,并且难以应对大规模数据。为了解决这一挑战,Enovi…...

【Agent】Dify Docker 安装问题 INTERNAL SERVER ERROR

总结:建议大家选择稳定版本的分支,直接拉取 master 分支,可能出现一下后面更新代码导致缺失一些环境内容。 启动报错 一直停留在 INSTALL 界面 我是通过 Docker 进行安装的,由于项目开发者不严谨导致,遇到一个奇怪的…...

【学Rust写CAD】11 2D CAD可用rust库

使用 Rust 开发 2D CAD 应用时,选择合适的库是关键。以下是一些适合用于 2D CAD 开发的 Rust 库和工具,涵盖图形渲染、几何计算、用户界面等方面: 图形渲染 lyon 简介: lyon 是一个用于 2D 图形渲染的 Rust 库,支持路径填充、描边…...

怎样基于安卓部署deepseek?

要在安卓设备上部署DeepSeek(或者类似的深度学习模型),您需要将模型从开发环境迁移到安卓应用中。具体步骤涉及将深度学习模型转化为安卓设备能够运行的格式,并配置安卓应用以支持这种模型的运行。以下是一个简化的步骤指南&#…...

【Excel使用技巧】某列保留固定字段或内容

目录 ✅ 方法一:使用 Excel 公式提取 body 部分 🔍 解释: ✅ 方法二:批量处理整列数据 🚨 注意事项 🚨 处理效果 我想保留Excel某一列的固定内容,比如原内容是: thread entry i…...

a-date-picker 格式化日期格式 YYYY-MM-DD HH:mm:ss

<template><a-range-pickerv-model:value"dateRange":show-time"{ format: HH:mm:ss, // 时间部分格式defaultValue: [moment(00:00:00, HH:mm:ss), moment(23:59:59, HH:mm:ss)] // 默认时间范围}"format"YYYY-MM-DD HH:mm:ss" // 整体…...

vue3,element-plus 表格搜索过滤数据

1、表格数据 // 表格数据 import type { User } from "/interface"; const tableData ref<User[]>([]); 2、 表格搜索过滤数据 // 搜索内容 const search ref(""); // 表格过滤数据 const tableFilterData computed(() >tableData.value.fi…...

WordPress 性能优化技术指南:打造快速加载的网站

WordPress 是全球最流行的内容管理系统&#xff08;CMS&#xff09;&#xff0c;以其灵活性和易用性深受用户喜爱。然而&#xff0c;随着网站内容和功能的增加&#xff0c;加载速度可能会变慢&#xff0c;影响用户体验和搜索引擎排名。在2025年的数字化环境中&#xff0c;网站性…...

vue中上传接口file表单提交二进制文件流

1.使用elementui上传组件 要做一个选择文件后&#xff0c;先不上传&#xff0c;等最后点击确定后&#xff0c;把file二进制流及附加参数一起提交上去。 首先使用elementui中的上传组件&#xff0c;设置auto-uploadfalse&#xff0c;也就是选择文件后不立刻上传。 <el-uplo…...

【学习笔记】卷积网络简介及原理探析

作者选择了由 Ian Goodfellow、Yoshua Bengio 和 Aaron Courville 三位大佬撰写的《Deep Learning》(人工智能领域的经典教程&#xff0c;深度学习领域研究生必读教材),开始深度学习领域学习&#xff0c;深入全面的理解深度学习的理论知识。 之前的文章参考下面的链接&#xf…...

element-plus中Cascader级联选择器组件的使用

目录 一.基本使用 二.进阶使用 1.如何获取最后一级选项的值&#xff1f; 2.如何让级联选择器的输入框只展示最后一级&#xff1f; 三.实战 1.场景描述 2.实现步骤 ①设计后端返回值Vo ②编写controller ③编写service ④编写mapper层 ⑤在前端&#xff0c;通过发送…...

计算机网络的分类——按照按拓扑结构分类

计算机的拓扑结构是引用拓扑学中研究和大小、形状无关的点、线关系的方法&#xff0c;将网络中的计算机和通信设备抽象为一个点&#xff0c;把传输介质抽象成一条线&#xff0c;由点和线组成的几何图形就是计算机网络的拓扑结构。计算机网络的拓扑结构主要由通信子网决定&#…...

【华为Pura先锋盛典】华为Pura X“阔折叠”手机发布:首次全面搭载HarmonyOS 5

文章目录 前言一、阔感体验&#xff0c;大有不同二、鸿蒙AI&#xff0c;大有智慧三、便携出行&#xff0c;大有不同四、首款全面搭载 HarmonyOS 5 的手机五、卓越性能&#xff0c;可靠安心六、红枫影像&#xff0c;大放光彩预热&#xff1a;鸿蒙电脑HarmonyOS 5 升级计划小结 前…...

MQ,RabbitMQ,MQ的好处,RabbitMQ的原理和核心组件,工作模式

1.MQ MQ全称 Message Queue&#xff08;消息队列&#xff09;&#xff0c;是在消息的传输过程中 保存消息的容器。它是应用程序和应用程序之间的通信方法 1.1 为什么使用MQ 在项目中&#xff0c;可将一些无需即时返回且耗时的操作提取出来&#xff0c;进行异步处理&#xff0…...

ETL:数据清洗、规范化和聚合的重要性

在当今这个数据呈爆炸式增长的时代&#xff0c;数据已成为企业最为宝贵的资产之一。然而&#xff0c;数据的海量增长也伴随着诸多问题&#xff0c;如数据来源多样、结构复杂以及质量问题等&#xff0c;这些问题严重阻碍了数据的有效处理与深度分析。在此背景下&#xff0c;ETL&…...

电机控制常见面试问题(十八)

文章目录 一.电机控制高级拓扑结构1.LLC 二.谈谈电压器饱和后果三.电压器绕组连接方式的影响四.有源逆变的条件 一.电机控制高级拓扑结构 1.LLC LLC是什么&#xff1f;—— 一个会"变魔术"的电源盒子 想象你有一个魔法盒子&#xff0c;能把电池的电压变大或变小&…...

stable diffusion本地安装

1. 基本环境准备 安装conda 环境 pytorch基础学习-CSDN博客 创建虚拟环境&#xff1a; conda create -n sd python3.10 一定要指定用3.10&#xff0c;过高的版本会提示错误&#xff1a; 激活启用环境&#xff1a; conda activate sd 设置pip国内镜像源&#xff1a; pip conf…...

【内网穿透】Linux部署FRP0.61.2实现rk3566 Wechat iPad协议内网穿透教程

写在前面 FRP&#xff08;Fast Reverse Proxy&#xff09;是一个由Go语言编写的开源项目&#xff0c;用于内网穿透&#xff0c;即通过公网服务器将内网服务暴露给外部访问。这对于需要在内网环境中部署但又希望外部用户能够访问这些服务的场景非常有用 Github&#xff1a;htt…...

Flutter项目升级到指定版本的详细步骤指南

一、升级前的准备工作 备份项目 使用Git提交当前所有修改&#xff1a;git commit -am "Pre-upgrade backup"或直接复制项目文件夹 查看当前环境信息 flutter --version flutter doctor二、升级Flutter SDK到指定版本 方法1&#xff1a;通过版本管理工具升级&#x…...

从零构建大语言模型全栈开发指南:第一部分:数学与理论基础-1.1.3模型参数与超参数:权重、偏置、学习率与正则化策略

👉 点击关注不迷路 👉 点击关注不迷路 👉 点击关注不迷路 文章大纲 1.1.3 模型参数与超参数:权重、偏置、学习率与正则化策略1. 模型参数:权重与偏置的数学本质1.1 参数的定义与作用2. 超参数:学习率与训练动态控制2.1 学习率的核心作用3. 正则化策略:抑制过拟合的数…...

VM虚拟机安装Ubuntu系统

前言 我现在装的Ubuntu总是死机&#xff0c;经常黑屏&#xff0c;所以我决定换个版本&#xff0c;顺便写一下笔记&#xff0c;给大家分享如何安装虚拟机 下载 这里我选择的是Ubuntu 22.04.5 LTS&#xff0c;下载链接&#xff1a;Ubuntu 22.04.5 LTS 如果访问不了网站的话&…...

从JVM底层揭开Java方法重载与重写的面纱:原理、区别与高频面试题突破

&#x1f31f;引言&#xff1a;一场由方法调用引发的"血案" 2018年&#xff0c;某电商平台在"双十一"大促期间遭遇严重系统故障。 技术团队排查发现&#xff0c;问题根源竟是一个继承体系中的方法重写未被正确处理&#xff0c;导致订单金额计算出现指数级…...

Driver具体负责什么工作

在 Apache Spark 中&#xff0c;Driver&#xff08;驱动程序&#xff09; 是 Spark 应用的核心控制节点&#xff0c;负责协调整个应用的执行流程。它是用户编写的 Spark 应用程序&#xff08;如 main() 方法&#xff09;的入口点&#xff0c;直接决定了任务的调度、资源分配和结…...

python3使用lxml解析xml时踩坑记录

文章目录 你的 XML 数据解析 XML----------------------------1. 获取 mlt 根元素的属性--------------------------------------------------------2. 获取 chain 元素的属性--------------------------------------------------------3. 获取所有 property 的值-------------…...

MySQL 中,查看执行频次、慢查询日志、SHOW PROFILE和 EXPLAIN性能分析和优化

在 MySQL 中,查看执行频次、慢查询日志、SHOW PROFILE 和 EXPLAIN 是性能分析和优化的核心工具。以下是它们的详细用法和高级语法: 一、查看 SQL 执行频次 通过 SHOW STATUS 命令可以查看 SQL 的执行频次,帮助定位高频查询。 1. 查看全局 SQL 执行频次 SHOW GLOBAL STATU…...

芋道 Spring Cloud Alibaba 消息队列 RocketMQ 入门

1. 概述 RocketMQ 是一款开源的分布式消息系统&#xff0c;基于高可用分布式集群技术&#xff0c;提供低延时的、高可靠的消息发布与订阅服务。同时&#xff0c;广泛应用于多个领域&#xff0c;包括异步通信解耦、企业解决方案、金融支付、电信、电子商务、快递物流、广告营销…...

【Go】切片

知识点关键概念切片声明var slice []int初始化切片slice : []int{1,2,3}make() 创建切片make([]int, len, cap)获取长度和容量len(slice), cap(slice)追加元素slice append(slice, value)切片截取slice[start:end]&#xff08;返回子切片&#xff09;拷贝切片copy(dest, src)&…...