AIGC实战——变分自编码器(Variational Autoencoder, VAE)

news2025/1/23 21:20:49

AIGC实战——变分自编码器

    • 0. 前言
    • 1. 变分自编码器
      • 1.1 基本原理
      • 1.2 编码器
    • 2. 构建VAE编码器
      • 2.1 Sampling 层
      • 2.2 编码器
      • 2.3 损失函数
      • 2.4 训练变分自编码器
    • 3. 变分自编码器分析
    • 小结
    • 系列链接

0. 前言

我们已经学习了如何实现自编码器,并了解了自编码器无法在潜空间中的空白位置处生成逼真的图像,且空间分布并不均匀,为了解决这些问题,我们需要将自编码器 (Autoencoder, AE) 改进为变分自编码器 (Variational Autoencoder, VAE)。在本节中,我们将学习变分自编码器的基本原理,并使用 Keras 实现变分自编码器模型。

1. 变分自编码器

1.1 基本原理

变分自编码器 (Variational Autoencoder, VAE) 是一种结合了自编码器和概率图模型的生成模型,通过学习输入数据的潜分布来进行无监督学习并生成新样本。
与传统的自编码器不同,变分自编码器引入了概率编码器和概率解码器。编码器将输入数据映射到潜在空间的概率分布,而解码器将从潜在空间中的样本重构为原始输入的分布。通过学习这两个概率分布,VAE 可以学习到输入数据的概率表示,并且能够通过从潜在空间中采样生成新的样本。
在训练过程中,VAE 使用最大似然估计来最小化观测数据与重构数据之间的差异,并通过最小化编码器和解码器之间的 KL 散度来约束潜在空间的分布与先验分布之间的差异。这使得 VAE 能够学习到连续且平滑的潜在表示,使得在潜在空间中的相邻点对应于语义上相似的样本。
接下来,我们从数学角度介绍我们需要哪些改动,才能将自编码器转换为变分自编码器,从而使其成为一个更复杂的生成模型。实际上,相比于自编码器,我们仅需要改变两部分:编码器和损失函数。

1.2 编码器

在自编码器中,每个图像直接映射为潜空间中的一个点。在变分自编码器中,每个图像映射为潜在空间中某一点周围的多元正态分布:

编码器

多元正态分布 (Multivariate Normal Distribution) 是一种概率分布,也称为高斯分布 (Gaussian Distribution)。其曲线图呈独特的钟形,一维的正态分布由两个变量确定:均值 ( μ μ μ) 和方差 ( σ 2 σ^2 σ2),标准差 ( σ σ σ) 是方差的平方根。在一维空间中,正态分布的概率密度函数为:
f ( x ∣ μ , σ 2 ) = 1 2 π σ 2 e − ( x − μ ) 2 2 σ 2 f(x|μ,σ^2) = \frac 1 {\sqrt{2πσ^2}}e^{-\frac{(x-μ)^2}{2σ^2}} f(xμ,σ2)=2πσ2 1e2σ2(xμ)2
下图展示了不同均值和方差的一维正态分布,红色曲线表示标准正态分布 (Standard Normal Distribution) N ( 0 , 1 ) \mathcal N(0,1) N(0,1),即均值为 0,方差为 1 的正态分布。

正态分布

可以使用以下公式从均值为 μ μ μ,标准差为 σ σ σ 的正态分布中采样一个点 z z z
z = μ + σ ϵ z = μ + σϵ z=μ+σϵ
其中 ϵ ϵ ϵ 是从标准正态分布中采样得到的。
正态分布的概念可以扩展到多维空间,具有均值向量 μ μ μ 和对称协方差矩阵 Σ Σ Σ k k k 维多元正态分布(或多元高斯分布) N ( μ , Σ ) \mathcal N(\mu,Σ) N(μΣ)的概率密度函数如下:
f ( x 1 , . . . , x k ) = e x p ( − 1 2 ( x − μ ) T Σ − 1 ( x − μ ) ) ( 2 π ) k ∣ Σ ∣ f(x_1,...,x_k) = \frac {exp(-\frac 12 (x-μ)^T Σ^{-1} (x-μ)) } {\sqrt{(2π)^k |Σ|}} f(x1,...,xk)=(2π)k∣Σ∣ exp(21(xμ)TΣ1(xμ))
我们通常使用各向同性的多元正态分布,其中协方差矩阵是对角矩阵。这意味着在每个维度上分布都是独立的,即我们可以采样一个向量,其中每个元素都服从独立的均值和方差的正态分布。
多元标准正态分布 (multivariate standard normal distribution) N ( 0 , I ) \mathcal N(0,I) N(0,I) 是一个多元分布,具有零值均值向量和单位协方差矩阵。
在多数情况下,正态分布与高斯分布通常可以互换使用,并且通常隐含着各向同性和多元性。
变分自编码器假设潜空间中的维度之间没有相关性,因此协方差矩阵是对角矩阵。编码器只需将每个输入映射到一个均值向量和一个方差向量,而不需要考虑维度之间的协方差。
此外,我们选择映射为方差的对数,因为对数可以是 ( − ∞ , ∞ ) (-∞, ∞) (,) 范围内的任意实数,与神经网络单元的自然输出范围—致,而方差值始终为正。这样,我们可以使用神经网络作为编码器,将输入图像映射到均值和对数方差向量。
总之,编码器将每个输入图像编码为两个向量 z_meanlog_var,两者共同定义了潜空间中的多元正态分布:

  • z_mean:分布的均值
  • z_log_var:各个维度上方差的对数

我们可以使用以下公式从由上述值定义的分布中采样一个点 z z z
z = z _ m e a n + z _ s i g m a ∗ e p s i l o n z = z\_mean + z\_sigma * epsilon z=z_mean+z_sigmaepsilon
其中:
z _ s i g m a = e x p ( z l o g v a r ∗ 0.5 ) e p s i l o n ∼ N ( 0 , I ) z\_sigma = exp(z_log_var * 0.5)\\ epsilon \sim \mathcal N(0,I) z_sigma=exp(zlogvar0.5)epsilonN(0,I)
z _ s i g m a ( σ ) z\_sigma(σ) z_sigma(σ) z _ l o g _ v a r ( l o g ( σ 2 ) ) z\_log\_var(log(σ^2)) z_log_var(log(σ2)) 之间的关系推导如下:
σ = e x p ( l o g ( σ ) ) = e x p ( 2 l o g ( σ ) / 2 ) = e x p ( l o g ( σ 2 ) / 2 ) σ = exp(log(σ)) = exp(2log(σ)/2) = exp(log(σ^2)/2) σ=exp(log(σ))=exp(2log(σ)/2)=exp(log(σ2)/2)
变分自编码器的解码器与普通自编码器的解码器相同,整体结构如下所示:

变分自编码器架构

为什么对编码器进行这样小的改变会有所帮助呢?在自编码器中,潜空间并不要求是连续的,即使点 (-2,2) 可以解码为完好的凉鞋图像,也不能保证点 (-2.1,2.1) 有类似的特征。而在变分自编码器中,由于我们从z_mean周围的区域中采样一个随机点,解码器必须确保当对同一邻域中的所有点进行解码时都能产生非常相似的图像,以便确保重构损失相对较小。这一属性确保了即使我们在隐空间中选择了一个解码器从未见过的点,编码器也可以将其解码为完好的图像。

2. 构建VAE编码器

接下来,我们利用 Keras 构建变分自编码器。

2.1 Sampling 层

首先,我们需要创建一种新层,称为 Sampling 层,用于从由 z_meanz_log_var 定义的分布中采样:

# 通过继承 Keras 基础 Layer 类来创建一个新层
class Sampling(layers.Layer):
    def call(self, inputs):
        z_mean, z_log_var = inputs
        batch = tf.shape(z_mean)[0]
        dim = tf.shape(z_mean)[1]
        epsilon = K.random_normal(shape=(batch, dim))
        # 使用重参数化技巧构建一个从由 z_mean 和 z_log_var 参数化的正态分布中采样的样本
        return z_mean + tf.exp(0.5 * z_log_var) * epsilon

子类化 Layer 类
我们可以通过子类化 Layer 类并定义 call 方法在 Keras 中创建新的层,call 方法描述了如何通过该层转换张量。
例如,在变分自编码器中,可以创建一个 Sampling 层,处理从由 z_meanz_log_var 定义的参数化正态分布中对 z 进行采样。子类化 Layer 类可以对一个张量应用不包含在 Keras 内置层类型中的变换。

重参数化技巧
变分自编码并不直接从由 z_meanz_log_var 参数化的正态分布中进行采样,而是从标准正态分布中采样 epsilon,然后调整采样以得到正确的均值和方差,这称为重参数化技巧 (Reparameterization Trick),使用此技术后,梯度可以自由地通过该层进行反向传播。通过将层的所有随机性都包含在变量 epsilon 中,可以证明该层输出相对于其输入的偏导数是确定性的(即与随机的 epsilon 无关),这对于反向传播通过该层是至关重要的。

2.2 编码器

编码器的完整代码如下:

# 编码器
encoder_input = layers.Input(
    shape=(IMAGE_SIZE, IMAGE_SIZE, 1), name="encoder_input"
)
x = layers.Conv2D(32, (3, 3), strides=2, activation="relu", padding="same")(
    encoder_input
)
x = layers.Conv2D(64, (3, 3), strides=2, activation="relu", padding="same")(x)
x = layers.Conv2D(128, (3, 3), strides=2, activation="relu", padding="same")(x)
shape_before_flattening = K.int_shape(x)[1:]  

x = layers.Flatten()(x)
# 将 Flatten 层连接到 z_mean 和 z_log_var 层,而不是直接连接到 2D 潜空间中
z_mean = layers.Dense(EMBEDDING_DIM, name="z_mean")(x)
z_log_var = layers.Dense(EMBEDDING_DIM, name="z_log_var")(x)
# Sampling 层从由 z_mean 和 z_log_var 参数定义的正态分布中对潜空间中的点 z 进行采样
z = Sampling()([z_mean, z_log_var])
# 定义编码器,接受一张输入图像,并输出 z_mean、z_log_var 以及从由这些参数定义的正态分布中采样得到的点 z
encoder = models.Model(encoder_input, [z_mean, z_log_var, z], name="encoder")
print(encoder.summary())

编码器架构摘要信息输出如下:

编码器架构

2.3 损失函数

在自编码器中,损失函数只包括经过编码器和解码器传递后的图像与其原始图像之间的重建损失。在变分自编码器中,除了重建损失外,还增加了一个额外的组成部分:KL 散度 (Kullback-Leibler divergence)。
KL 散度是衡量两个概率分布之间差异程度的方法。在 VAE 中,我们希望衡量由参数 z_meanz_log_var 构成的正态分布与标准正态分布之间的差异程度。在这种情况下,可以证明 KL 散度有以下解析解:
k l _ l o s s = − 0.5 ∗ s u m ( 1 + z _ l o g _ v a r − z _ m e a n 2 − e x p ( z _ l o g _ v a r ) ) kl\_loss = -0.5 * sum(1 + z\_log\_var - z\_mean ^ 2 - exp(z\_log\_var)) kl_loss=0.5sum(1+z_log_varz_mean2exp(z_log_var))
用数学符号表示如下:
D K L [ N ( μ , σ ) ∣ ∣ N ( 0 , 1 ) ] = − 1 2 ∑ ( 1 + l o g ( σ 2 ) − μ 2 − σ 2 ) D_{KL}[\mathcal N(\mu, \sigma)||\mathcal N(0,1)]=-\frac 12\sum(1+log(\sigma^2)-\mu^2-\sigma^2) DKL[N(μ,σ)∣∣N(0,1)]=21(1+log(σ2)μ2σ2)
求和是在潜空间的所有维度上进行的。当 z_mean = 0z_log_var = 0 时,kl_loss 会得到最小值 0。当这两个项开始与 0 的差距增大时,kl_loss 也会随之增加。
总之,KL 散度在编码观测样本时,如果 z_meanz_log_var 变量与标准正态分布参数(即 z_mean = 0z_log_var = 0 )出现显著不同,对网络施加的惩罚。
在损失函数中添加 KL 散度后,就有一个明确定义的分布(即标准正态分布),可以用于选择潜空间中的点,从该分布中采样更有可能得到 VAE 已经见过的范围内的点。其次,由于 KL 散度试图将所有编码分布强制趋近于标准正态分布,因此点簇之间形成较大间隙的可能性较小。相反,编码器将尝试以对称的方式高效利用原点周围的空白区域。
VAE 论文中,VAE 的损失函数只是重建损失和 KL 散度损失项之和。我们通过 r_loss_factor 为重建权重添加权重因子,用于平衡 KL 散度损失和重建损失。如果重建损失权重过大,KL 损失将无法产生预期的调节效果,就会遇到与普通自编码器相同的问题。如果 KL 散度项的权重过大,KL 散度损失将占主导地位,重建图像的质量将较差。权重因子是训练 VAE 时需要调整的超参数之一。

2.4 训练变分自编码器

将整个 VAE 模型构建为 Keras Model 类的子类,以便在自定义的 train_step 方法中计算损失函数的 KL 散度项。

class VAE(models.Model):
    def __init__(self, encoder, decoder, **kwargs):
        super(VAE, self).__init__(**kwargs)
        self.encoder = encoder
        self.decoder = decoder
        self.total_loss_tracker = metrics.Mean(name="total_loss")
        self.reconstruction_loss_tracker = metrics.Mean(
            name="reconstruction_loss"
        )
        self.kl_loss_tracker = metrics.Mean(name="kl_loss")

    @property
    def metrics(self):
        return [
            self.total_loss_tracker,
            self.reconstruction_loss_tracker,
            self.kl_loss_tracker,
        ]
    # 变分自编码器前向计算
    def call(self, inputs):
        """Call the model on a particular input."""
        z_mean, z_log_var, z = encoder(inputs)
        reconstruction = decoder(z)
        return z_mean, z_log_var, reconstruction
    # VAE训练过程,包括损失函数的计算
    def train_step(self, data):
        """Step run during training."""
        with tf.GradientTape() as tape:
            z_mean, z_log_var, reconstruction = self(data)
            reconstruction_loss = tf.reduce_mean(
                BETA
                * losses.binary_crossentropy(
                    data, reconstruction
                )
            )
            kl_loss = tf.reduce_mean(
                tf.reduce_sum(
                    -0.5
                    * (1 + z_log_var - tf.square(z_mean) - tf.exp(z_log_var)),
                    axis=1,
                )
            )
            total_loss = reconstruction_loss + kl_loss
        grads = tape.gradient(total_loss, self.trainable_weights)
        self.optimizer.apply_gradients(zip(grads, self.trainable_weights))
        self.total_loss_tracker.update_state(total_loss)
        self.reconstruction_loss_tracker.update_state(reconstruction_loss)
        self.kl_loss_tracker.update_state(kl_loss)

        return {m.name: m.result() for m in self.metrics}

    def test_step(self, data):
        """Step run during validation."""
        if isinstance(data, tuple):
            data = data[0]
        z_mean, z_log_var, reconstruction = self(data)
        # 重建损失权重因子 beta 为 500
        reconstruction_loss = tf.reduce_mean(
            BETA
            * losses.binary_crossentropy(data, reconstruction)
        )
        kl_loss = tf.reduce_mean(
            tf.reduce_sum(
                -0.5 * (1 + z_log_var - tf.square(z_mean) - tf.exp(z_log_var)),
                axis=1,
            )
        )
        # 总损失是重建损失和KL散度损失之和
        total_loss = reconstruction_loss + kl_loss

        return {
            "loss": total_loss,
            "reconstruction_loss": reconstruction_loss,
            "kl_loss": kl_loss,
        }

# 创建变分自编码器
vae = VAE(encoder, decoder)
# 编译变分自编码器
optimizer = optimizers.Adam(learning_rate=0.0005)
vae.compile(optimizer=optimizer)
# 模型训练
vae.fit(
    x_train,
    epochs=EPOCHS,
    batch_size=BATCH_SIZE,
    shuffle=True,
    validation_data=(x_test, x_test),
)

梯度记录器 (Gradient Tape)
TensorFlowGradient Tape 用于在模型的前向传播过程中计算操作的梯度。为了使用梯度记录器,需要将需要求导的操作的代码包装在 tf.GradientTape() 上下文中。一旦记录了这些操作,就可以通过调用 tape.gradient() 计算损失函数相对于某些变量的梯度,然后使用优化器利用这些梯度更新网络权重。
这一机制对于计算自定义损失函数的梯度非常有用,也适用于创建自定义的训练流程。

3. 变分自编码器分析

训练好 VAE 后,我们使用编码器对测试集中的图像进行编码,并在潜在空间中绘制 z_mean 值。我们还可以从标准正态分布中采样,生成潜空间中的点,并使用解码器将这些点解码回像素空间,以测试 VAE 的性能。
下图展示了新的潜空间的结构,以及采样点及其解码后的图像。我们可以看到潜空间的组织方式发生了 一些变化。

变分自编码器潜空间

首先,KL 散度损失项确保编码图像的 z_meanz_log_var 值不会偏离标准正态分布太远。其次,由于现在编码器是随机的而不是确定性的,因此,潜空间更加连续,所以不会生成过多不合理的图像,潜在空间现在更加连续。
最后,如下图所示,通过按图像类型对潜在空间中的点进行着色,可以看到没有任何一种类型有倾向性。右图显示了将潜空间转换为 p 值的情况,可以看到每种颜色占据的区域大致相等。需要强调的是,在训练过程中并没有使用标签,VAE 通过学习掌握了各种 Fashion-MNIST 图像的形式,以最小化重建损失。

潜空间

小结

变分自编码器通过在模型中引入随机性,并限制潜空间中的点的分布来解决自编码器存在的问题。只需进行一些微小的调整,就可以将自编码器转换为变分自编码器,从而使其成为真正的生成模型。在本节中,我们介绍了变分自编码器的基本原理,并使用 Keras 实现了一个变分自编码器用于生成 Fashion-MNIST 图像。

系列链接

AIGC实战——生成模型简介
AIGC实战——深度学习 (Deep Learning, DL)
AIGC实战——卷积神经网络(Convolutional Neural Network, CNN)
AIGC实战——自编码器(Autoencoder)

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

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

相关文章

红米K40解BL锁以及刷国外EU版系统

解BL锁准备工作 进入手机 “设置“ > 我的设备 > 全部参数信息 > MIUI 版本连续点击 7 下,直到显示已开启开发者选项 回到设置主界面 > 更多设置 > 开发者选项 將 OEM 解锁开启,点入装置解锁状态并绑定自己的小米账号168小时之后再进行手…

UE基础必学系列:UMG

一、教程: 官方教程: 官方文档: 创建和显示UI 二、理解知识点: 2.1 RemoveFromParent 从视口中删除,但仍保留在内存中,并且变量仍然存在有效的 2.2 3D交互组件测试

如果你的内存比较大,对于windows11可以做出如下优化

在程序界,常有这种思想:用空间换时间,用时间换空间。都是相对而言,在内存足够大的情况下,下面说几点优化其中有一些是利用空间换时间的思想,适用范围:建议内存最小16G,最好是32G及以…

Hutool 实现敏感信息展示脱敏及其反脱敏

业务需求 将用户敏感信息脱敏展示到前端是出于保护用户隐私和信息安全的考虑。 敏感信息包括但不限于手机号码、身份证号、银行卡号等,这些信息泄露可能导致用户个人信息的滥用、身份盗用等严重问题。脱敏是一种常用的保护用户隐私的方式,它的目的是减少…

#[量化投资-学习笔记018]Python+TDengine从零开始搭建量化分析平台-正态分布与收益率

正态分布(Normal Distribution)又叫高斯分布、常态分布。通常用来描述随机变量的概率分布。 自然界的数据分布通常是符合正态分布规律的,比如说人的身高、体重。但是非自然界数据就不一定了。尤其是经过人为加工过的数据。 金融领域大量使用正态分布来计算收益率和…

R语言提取文字(字符串)中的内容--正则式(2)

科学研究中有时候咱们收集到的数据很乱,不能马上进行分析,如SEER数据,用过都知道,咱们需要对数据进行清洗,从数据中提取咱们需要的东西,才能进行分析,这时候有个有用的东西叫正则式,…

iceoryx(冰羚)-简介

概要 RouDi RouDi是Routing and Discovery的缩写。RouDi负责通信设置,但实际上并不参与发布者与订阅者或客户端与服务器之间的通信。鲁迪可以被认为是iceoryx的总机操作员。它的另一个主要任务是设置共享内存,应用程序使用共享内存交换有效负载数据。Ro…

Go语言常用命令详解(一)

文章目录 前言常用命令go build示例参数说明 go test示例参数说明 go run示例参数说明 go clean示例参数介绍 总结写在最后 前言 Go语言是一种开源的编程语言,由Google开发并于2009年首次发布。它以其简洁、高效和并发性能而备受开发者的喜爱。作为一门相对年轻的语…

本地视频AI人脸替换,一键启动,傻瓜式操作

本地无须准备配置和运行环镜,整个压缩包下载后解压,一键启动程序,只需一张照片和一个视频,就可以把视频中的人物替换成您想要的人脸。支持CPU和GPU解码,使用GPU解码速度较快。 所有使用的软件安装包已上传网盘&#x…

提升pip速度!设置pip全局镜像源,速度飞起!

文章目录 💢 问题 💢💯 解决方案 💯🐾 镜像源🐾 镜像全局配置🍄 Windows系统🍄 Linux和macOS系统🍄 添加环境变量的方式💢 问题 💢 由于“某些网络限制”原因,我们在使用pip安装python模块的时候速度会比较慢,这个时候我们就需要用到一些镜像源,本文将…

requests 技术问题与解决方案:解决字典值中列表在URL编码时的问题

本文将探讨 issue 80 中提出的技术问题及其解决方案。该问题主要涉及如何在模型的 _encode_params 方法中处理列表作为字典值的情况。 问题背景 在处理用户提交的数据时,有时需要将字典序列化为 URL 编码字符串。在 requests 库中,这个过程通常通过 par…

点成分享丨如何提高旋转蒸发仪的蒸馏提纯效率

旋转蒸发仪: 主要用于医药、化工和制药等行业的浓缩、结晶、干燥、分离及溶媒回收。其原理为在真空条件下,恒温加热,使旋转瓶恒速旋转,物料在瓶壁形成大面积薄膜,高效蒸发。溶媒蒸气经高效玻璃冷凝器冷却,…

如何修改Hosts文件(Windows、Linux)本机配置域名解析

Hosts文件是一种在计算机网络中存储主机名与IP地址对应关系的文本文件。通过配置Hosts文件,可以避免在网络环境中DNS无法正常解析时,出现无法访问互联网的问题。 Windows修改hosts文件 1 以windows10系统为例,手指同时按住 windows 键和 X 键…

《洛谷深入浅出基础篇》P1536 村村通——并查集

上链接:P1536 村村通 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)https://www.luogu.com.cn/problem/P1536 上题干: 题目描述 某市调查城镇交通状况,得到现有城镇道路统计表。表中列出了每条道路直接连通的城镇。市政府 "村村通工程…

Flutter 3.16 发布,快来看有什么更新吧

参考原文:https://medium.com/flutter/whats-new-in-flutter-3-16-dba6cb1015d1 Flutter 又又又发布新季度更新啦,同时随着而来的还有 Dart 3.2,本次 3.16 开始 Material 3 会成为新的默认主题,另外 Android 也迎来了 Impeller 的…

力扣第797题 所有可能的路径 C++ 深度优先搜索 +java

题目 797. 所有可能的路径 中等 相关标签 深度优先搜索 广度优先搜索 图 回溯 给你一个有 n 个节点的 有向无环图(DAG),请你找出所有从节点 0 到节点 n-1 的路径并输出(不要求按特定顺序) graph[i] 是一个从…

郑州市管城区工信局局长任华民一行莅临中创算力调研指导工作

2023年11月15日,为深入了解企业生产经营情况,解决发展诉求。郑州市管城区工信局局长任华民等领导一行莅临中创算力,中创副总经理杨光、技术总监刘朝阳、行政主管生田等人员陪同调研。 调研期间,双方就生产经营、“算力数据中心”…

零基础学Python怎么学习?我来告诉你

对于IT新手来说,零基础学Python的话,之后可选择的职业方向非常多。Python全栈和爬虫一直以来都是市场的最火的就业岗位之一,它们的薪资回报也算是开发岗里面的顶级了。而且随着大数据和人工智能时代的到来,数据处理和人工智能行业…

Python | 机器学习之逻辑回归

​🌈个人主页:Sarapines Programmer🔥 系列专栏:《人工智能奇遇记》🔖少年有梦不应止于心动,更要付诸行动。 目录结构 1. 机器学习之逻辑回归概念 1.1 机器学习 1.2 逻辑回归 2. 逻辑回归 2.1 实验目的…

通过注释来埋点

目录 开始 插件编写 功能一 功能二 功能三 合并功能 运行代码 总结 这篇文章主要讲如何根据注释,通过babel插件自动地,给相应函数插入埋点代码,在实现埋点逻辑和业务逻辑分离的基础上,配置更加灵活 这篇文章想要达到的效…