京公网安备 11010802034615号
经营许可证编号:京B2-20210330
作者 | CDA数据分析师
生成对抗网络(GAN)是一种用于训练深度卷积模型以生成合成图像的体系结构。
尽管非常有效,但默认GAN无法控制生成的图像类型。信息最大化GAN(简称InfoGAN)是GAN架构的扩展,它引入了架构自动学习的控制变量,并允许控制生成的图像,例如在生成图像样式的情况下,厚度和类型手写的数字。
在本教程中,您将了解如何从头开始实现信息最大化生成对抗网络模型。
完成本教程后,您将了解:
让我们开始吧。
教程概述
本教程分为四个部分; 他们是:
什么是最大化GAN的信息
Generative Adversarial Network(简称GAN)是一种用于训练生成模型的体系结构,例如用于生成合成图像的模型。
它涉及同时训练生成器模型以生成具有鉴别器模型的图像,该模型学习将图像分类为真实的(来自训练数据集)或假的(生成的)。这两个模型在零和游戏中竞争,使得训练过程的收敛涉及在生成器生成令人信服的图像的技能与能够检测它们的鉴别器之间找到平衡。
生成器模型将来自潜在空间的随机点作为输入,通常为50到100个随机高斯变量。生成器通过训练对潜在空间中的点应用独特的含义,并将点映射到特定的输出合成图像。这意味着虽然潜在空间由生成器模型构成,但是无法控制生成的图像。
GAN公式使用简单的因子连续输入噪声向量z,而对发生器可以使用该噪声的方式没有限制。结果,发生器可能以高度纠缠的方式使用噪声,导致z的各个维度不对应于数据的语义特征。
可以探索潜在空间并比较生成的图像,以试图理解生成器模型已经学习的映射。或者,可以例如通过类标签来调节生成过程,以便可以按需创建特定类型的图像。这是条件生成对抗网络的基础,简称CGAN或cGAN。
另一种方法是提供控制变量作为发电机的输入,以及潜在空间中的点(噪声)。可以训练发生器以使用控制变量来影响所生成图像的特定属性。这是信息最大化生成对抗网络(简称InfoGAN)所采用的方法。
InfoGAN,生成对抗网络的信息理论扩展,能够以完全无监督的方式学习解缠结的表示。
在训练过程中由发生器学习的结构化映射有些随机。虽然生成器模型学习在潜在空间中空间分离生成图像的属性,但是没有控制。这些属性纠缠在一起。InfoGAN的动机是希望解开生成图像的属性。
例如,在面部的情况下,可以解开和控制生成面部的特性,例如面部的形状,头发颜色,发型等。
例如,对于面部的数据集,有用的解开的表示可以为以下属性中的每一个分配一组单独的维度:面部表情,眼睛颜色,发型,眼镜的存在或不存在,以及相应人的身份。
控制变量与噪声一起提供作为发电机的输入,并且通过互信息丢失功能训练模型。
......我们对生成对抗性网络目标进行了简单的修改,鼓励它学习可解释和有意义的表达。我们通过最大化GAN噪声变量的固定小子集与观测值之间的互信息来实现这一点,结果证明是相对简单的。
相互信息是指在给定另一个变量的情况下获得的关于一个变量的信息量。在这种情况下,我们感兴趣的是有关使用噪声和控制变量生成的图像的控制变量的信息。
在信息论中,X和Y之间的互信息I(X; Y)测量从随机变量Y的知识中学习的关于另一个随机变量X 的“ 信息量 ”。
相互信息(MI)被计算为图像的条件熵(由发生器(G)从噪声(z)和控制变量(c)创建),给定控制变量(c)从边际熵减去控制变量(c); 例如:
在实践中,计算真实的互信息通常是难以处理的,尽管本文采用了简化,称为变分信息最大化,并且控制代码的熵保持不变。
通过使用称为Q或辅助模型的新模型来实现通过互信息训练发电机。新模型与用于解释输入图像的鉴别器模型共享所有相同的权重,但与预测图像是真实还是假的鉴别器模型不同,辅助模型预测用于生成图像的控制代码。
两种模型都用于更新生成器模型,首先是为了提高生成愚弄鉴别器模型的图像的可能性,其次是改善用于生成图像的控制代码和辅助模型对控制代码的预测之间的互信息。
结果是生成器模型通过互信息丢失而正规化,使得控制代码捕获所生成图像的显着特性,并且反过来可以用于控制图像生成过程。
每当我们有兴趣学习从给定输入X到保留关于原始输入的信息的更高级别表示Y的参数化映射时,可以利用互信息。[...]表明,最大化互信息的任务基本上等同于训练自动编码器以最小化重建误差。
如何实现InfoGAN丢失功能
一旦熟悉模型的输入和输出,InfoGAN就可以相当直接地实现。
唯一的绊脚石可能是互信息丢失功能,特别是如果你没有像大多数开发人员那样强大的数学背景。
InfoGan使用两种主要类型的控制变量:分类和连续,连续变量可能具有不同的数据分布,这会影响相互损失的计算方式。可以基于变量类型计算所有控制变量的相互损失并将其相加,这是OpenAI为TensorFlow发布的InfoGAN实现中使用的方法。
在Keras中,将控制变量简化为分类和高斯或均匀连续变量可能更容易,并且对于每个控制变量类型在辅助模型上具有单独的输出。这样可以使用不同的损失函数,大大简化了实现。
有关本节中建议的更多背景信息,请参阅更多阅读部分中的文章和帖子。
分类控制变量
分类变量可用于控制所生成图像的类型或类别。
这被实现为一个热编码矢量。也就是说,如果类具有10个值,则控制代码将是一个类,例如6,并且输入到生成器模型的分类控制向量将是所有零值的10个元素向量,其中对于类6具有一个值,例如,[0,0,0,0,0,0,1,0,0]。
训练模型时,我们不需要选择分类控制变量; 相反,它们是随机生成的,例如,每个样本以均匀的概率选择每个样本。
...关于潜码c~Cat(K = 10,p = 0.1)的统一分类分布
在辅助模型中,分类变量的输出层也将是一个热编码矢量以匹配输入控制代码,并且使用softmax激活函数。
对于分类潜在代码ci,我们使用softmax非线性的自然选择来表示Q(ci | x)。
回想一下,互信息被计算为来自控制变量的条件熵和从提供给输入变量的控制变量的熵中减去的辅助模型的输出。我们可以直接实现这一点,但这不是必需的。
控制变量的熵是一个常数,并且是一个接近于零的非常小的数; 因此,我们可以从计算中删除它。条件熵可以直接计算为控制变量输入和辅助模型的输出之间的交叉熵。因此,可以使用分类交叉熵损失函数,就像我们对任何多类分类问题一样。
超参数lambda用于缩放互信息丢失函数并设置为1,因此可以忽略。
即使InfoGAN引入了额外的超参数λ,它也很容易调整,简单地设置为1就足以支持离散的潜码。
连续控制变量
连续控制变量可用于控制图像的样式。
连续变量从均匀分布中采样,例如在-1和1之间,并作为输入提供给发电机模型。
...可以捕捉连续性变化的连续代码:c2,c3~Unif(-1,1)
辅助模型可以用高斯分布实现连续控制变量的预测,其中输出层被配置为具有一个节点,平均值和一个用于高斯标准偏差的节点,例如每个连续控制需要两个输出变量。
对于连续潜在代码cj,根据什么是真正的后验P(cj | x),有更多选项。在我们的实验中,我们发现简单地将Q(cj | x)视为因式高斯是足够的。
输出均值的节点可以使用线性激活函数,而输出标准偏差的节点必须产生正值,因此可以使用诸如sigmoid的激活函数来创建0到1之间的值。
对于连续潜码,我们通过对角高斯分布对近似后验进行参数化,识别网络输出其均值和标准差,其中标准偏差通过网络输出的指数变换进行参数化以确保积极性。
必须将损失函数计算为高斯控制码的互信息,这意味着它们必须在计算损失之前从平均值和标准差重建。计算高斯分布变量的熵和条件熵可以直接实现,但不是必需的。相反,可以使用均方误差损失。
或者,可以将输出分布简化为每个控制变量的均匀分布,可以使用具有线性激活的辅助模型中的每个变量的单个输出节点,并且模型可以使用均方误差损失函数。
如何为MNIST开发InfoGAN
在本节中,我们将仔细研究生成器(g),鉴别器(d)和辅助模型(q)以及如何在Keras中实现它们。
我们将为MNIST数据集开发InfoGAN实现,如InfoGAN论文中所做的那样。
本文探讨了两个版本; 第一个仅使用分类控制代码,并允许模型将一个分类变量映射到大约一个数字(尽管没有按分类变量排序数字)。
本文还探讨了InfoGAN架构的一个版本,其中包含一个热编码分类变量(c1)和两个连续控制变量(c2和c3)。
发现第一个连续变量用于控制数字的旋转,第二个连续变量用于控制数字的粗细。
我们将重点关注使用具有10个值的分类控制变量的简单情况,并鼓励模型学习让该变量控制生成的数字。您可能希望通过更改分类控制变量的基数或添加连续控制变量来扩展此示例。
用于MNIST数据集训练的GAN模型的配置作为本文的附录提供,转载如下。我们将使用列出的配置作为开发我们自己的生成器(g),鉴别器(d)和辅助(q)模型的起点。
让我们从将生成器模型开发为深度卷积神经网络(例如DCGAN)开始。
该模型可以将噪声向量(z)和控制向量(c)作为单独的输入,并在将它们用作生成图像的基础之前将它们连接起来。或者,可以预先将矢量连接起来并提供给模型中的单个输入层。方法是等价的,在这种情况下我们将使用后者来保持模型简单。
下面的define_generator()函数定义生成器模型,并将输入向量的大小作为参数。
完全连接的层采用输入向量并产生足够数量的激活,以创建512个7×7特征映射,从中重新激活激活。然后,它们以1×1步幅通过正常卷积层,然后两个随后的上采样将卷积层转换为2×2步幅优先至14×14特征映射,然后转换为所需的1通道28×28特征映射输出,其中像素值为通过tanh激活函数的范围[-1,-1]。
良好的发生器配置启发式如下,包括随机高斯权重初始化,隐藏层中的ReLU激活以及批量归一化的使用。
# define the standalone generator model
def define_generator(gen_input_size):
# weight initialization
init = RandomNormal(stddev=0.02)
# image generator input
in_lat = Input(shape=(gen_input_size,))
# foundation for 7x7 image
n_nodes = 512 * 7 * 7
gen = Dense(n_nodes, kernel_initializer=init)(in_lat)
gen = Activation('relu')(gen)
gen = BatchNormalization()(gen)
gen = Reshape((7, 7, 512))(gen)
# normal
gen = Conv2D(128, (4,4), padding='same', kernel_initializer=init)(gen)
gen = Activation('relu')(gen)
gen = BatchNormalization()(gen)
# upsample to 14x14
gen = Conv2DTranspose(64, (4,4), strides=(2,2), padding='same', kernel_initializer=init)(gen)
gen = Activation('relu')(gen)
gen = BatchNormalization()(gen)
# upsample to 28x28
gen = Conv2DTranspose(1, (4,4), strides=(2,2), padding='same', kernel_initializer=init)(gen)
# tanh output
out_layer = Activation('tanh')(gen)
# define model
model = Model(in_lat, out_layer)
return model
接下来,我们可以定义鉴别器和辅助模型。
根据普通GAN,鉴别器模型以独立方式训练在真实和伪造图像上。发电机和辅助模型都不直接配合; 相反,它们适合作为复合模型的一部分。
鉴别器和辅助模型共享相同的输入和特征提取层,但它们的输出层不同。因此,同时定义它们是有意义的。
同样,有许多方法可以实现这种架构,但是将鉴别器和辅助模型定义为单独的模型首先允许我们稍后通过功能API直接将它们组合成更大的GAN模型。
下面的define_discriminator()函数定义了鉴别器和辅助模型,并将分类变量的基数(例如数值,例如10)作为输入。输入图像的形状也被参数化为函数参数,并设置为MNIST图像大小的默认值。
特征提取层涉及两个下采样层,而不是池化层作为最佳实践。此外,遵循DCGAN模型的最佳实践,我们使用LeakyReLU激活和批量标准化。
鉴别器模型(d)具有单个输出节点,并通过S形激活函数预测输入图像的实际概率。该模型被编译,因为它将以独立的方式使用,通过具有最佳实践学习速率和动量的随机梯度下降的Adam版本来优化二元交叉熵函数。
辅助模型(q)对分类变量中的每个值具有一个节点输出,并使用softmax激活函数。如InfoGAN论文中所使用的那样,在特征提取层和输出层之间添加完全连接的层。该模型未编译,因为它不是独立使用或以独立方式使用。
# define the standalone discriminator model
def define_discriminator(n_cat, in_shape=(28,28,1)):
# weight initialization
init = RandomNormal(stddev=0.02)
# image input
in_image = Input(shape=in_shape)
# downsample to 14x14
d = Conv2D(64, (4,4), strides=(2,2), padding='same', kernel_initializer=init)(in_image)
d = LeakyReLU(alpha=0.1)(d)
# downsample to 7x7
d = Conv2D(128, (4,4), strides=(2,2), padding='same', kernel_initializer=init)(d)
d = LeakyReLU(alpha=0.1)(d)
d = BatchNormalization()(d)
# normal
d = Conv2D(256, (4,4), padding='same', kernel_initializer=init)(d)
d = LeakyReLU(alpha=0.1)(d)
d = BatchNormalization()(d)
# flatten feature maps
d = Flatten()(d)
# real/fake output
out_classifier = Dense(1, activation='sigmoid')(d)
# define d model
d_model = Model(in_image, out_classifier)
# compile d model
d_model.compile(loss='binary_crossentropy', optimizer=Adam(lr=0.0002, beta_1=0.5))
# create q model layers
q = Dense(128)(d)
q = BatchNormalization()(q)
q = LeakyReLU(alpha=0.1)(q)
# q model output
out_codes = Dense(n_cat, activation='softmax')(q)
# define q model
q_model = Model(in_image, out_codes)
return d_model, q_model
接下来,我们可以定义复合GAN模型。
该模型使用所有子模型,并且是训练发电机模型权重的基础。
下面的define_gan()函数实现了这个并定义并返回模型,将三个子模型作为输入。
如上所述,鉴别器以独立方式训练,因此鉴别器的所有权重被设置为不可训练(仅在此上下文中)。生成器模型的输出连接到鉴别器模型的输入,并连接到辅助模型的输入。
这将创建一个新的复合模型,该模型将[noise + control]向量作为输入,然后通过生成器生成图像。然后,图像通过鉴别器模型以产生分类,并通过辅助模型产生控制变量的预测。
该模型有两个输出层,需要使用不同的损失函数进行训练。二进制交叉熵损失用于鉴别器输出,正如我们在编译独立使用的鉴别器时所做的那样,并且互信息丢失用于辅助模型,在这种情况下,辅助模型可以直接实现为分类交叉熵并实现期望的结果。
# define the combined discriminator, generator and q network model
def define_gan(g_model, d_model, q_model):
# make weights in the discriminator (some shared with the q model) as not trainable
d_model.trainable = False
# connect g outputs to d inputs
d_output = d_model(g_model.output)
# connect g outputs to q inputs
q_output = q_model(g_model.output)
# define composite model
model = Model(g_model.input, [d_output, q_output])
# compile model
opt = Adam(lr=0.0002, beta_1=0.5)
model.compile(loss=['binary_crossentropy', 'categorical_crossentropy'], optimizer=opt)
return model
为了使GAN模型架构更清晰,我们可以创建模型和复合模型图。
下面列出了完整的示例。
# create and plot the infogan model for mnist
from keras.optimizers import Adam
from keras.models import Model
from keras.layers import Input
from keras.layers import Dense
from keras.layers import Reshape
from keras.layers import Flatten
from keras.layers import Conv2D
from keras.layers import Conv2DTranspose
from keras.layers import LeakyReLU
from keras.layers import BatchNormalization
from keras.layers import Activation
from keras.initializers import RandomNormal
from keras.utils.vis_utils import plot_model
# define the standalone discriminator model
def define_discriminator(n_cat, in_shape=(28,28,1)):
# weight initialization
init = RandomNormal(stddev=0.02)
# image input
in_image = Input(shape=in_shape)
# downsample to 14x14
d = Conv2D(64, (4,4), strides=(2,2), padding='same', kernel_initializer=init)(in_image)
d = LeakyReLU(alpha=0.1)(d)
# downsample to 7x7
d = Conv2D(128, (4,4), strides=(2,2), padding='same', kernel_initializer=init)(d)
d = LeakyReLU(alpha=0.1)(d)
d = BatchNormalization()(d)
# normal
d = Conv2D(256, (4,4), padding='same', kernel_initializer=init)(d)
d = LeakyReLU(alpha=0.1)(d)
d = BatchNormalization()(d)
# flatten feature maps
d = Flatten()(d)
# real/fake output
out_classifier = Dense(1, activation='sigmoid')(d)
# define d model
d_model = Model(in_image, out_classifier)
# compile d model
d_model.compile(loss='binary_crossentropy', optimizer=Adam(lr=0.0002, beta_1=0.5))
# create q model layers
q = Dense(128)(d)
q = BatchNormalization()(q)
q = LeakyReLU(alpha=0.1)(q)
# q model output
out_codes = Dense(n_cat, activation='softmax')(q)
# define q model
q_model = Model(in_image, out_codes)
return d_model, q_model
# define the standalone generator model
def define_generator(gen_input_size):
# weight initialization
init = RandomNormal(stddev=0.02)
# image generator input
in_lat = Input(shape=(gen_input_size,))
# foundation for 7x7 image
n_nodes = 512 * 7 * 7
gen = Dense(n_nodes, kernel_initializer=init)(in_lat)
gen = Activation('relu')(gen)
gen = BatchNormalization()(gen)
gen = Reshape((7, 7, 512))(gen)
# normal
gen = Conv2D(128, (4,4), padding='same', kernel_initializer=init)(gen)
gen = Activation('relu')(gen)
gen = BatchNormalization()(gen)
# upsample to 14x14
gen = Conv2DTranspose(64, (4,4), strides=(2,2), padding='same', kernel_initializer=init)(gen)
gen = Activation('relu')(gen)
gen = BatchNormalization()(gen)
# upsample to 28x28
gen = Conv2DTranspose(1, (4,4), strides=(2,2), padding='same', kernel_initializer=init)(gen)
# tanh output
out_layer = Activation('tanh')(gen)
# define model
model = Model(in_lat, out_layer)
return model
# define the combined discriminator, generator and q network model
def define_gan(g_model, d_model, q_model):
# make weights in the discriminator (some shared with the q model) as not trainable
d_model.trainable = False
# connect g outputs to d inputs
d_output = d_model(g_model.output)
# connect g outputs to q inputs
q_output = q_model(g_model.output)
# define composite model
model = Model(g_model.input, [d_output, q_output])
# compile model
opt = Adam(lr=0.0002, beta_1=0.5)
model.compile(loss=['binary_crossentropy', 'categorical_crossentropy'], optimizer=opt)
return model
# number of values for the categorical control code
n_cat = 10
# size of the latent space
latent_dim = 62
# create the discriminator
d_model, q_model = define_discriminator(n_cat)
# create the generator
gen_input_size = latent_dim + n_cat
g_model = define_generator(gen_input_size)
# create the gan
gan_model = define_gan(g_model, d_model, q_model)
# plot the model
plot_model(gan_model, to_file='gan_plot.png', show_shapes=True, show_layer_names=True)
运行该示例将创建所有三个模型,然后创建复合GAN模型并保存模型体系结构的图。
注意:创建此图假设已安装pydot和graphviz库。如果这是一个问题,您可以注释掉import语句和对plot_model()函数的调用。
该图显示了生成器模型的所有细节以及鉴别器和辅助模型的压缩描述。重要的是,请注意鉴别器输出的形状作为预测图像是真实还是假的单个节点,以及辅助模型预测分类控制代码的10个节点。
回想一下,该复合模型将仅用于更新生成器和辅助模型的模型权重,并且鉴别器模型中的所有权重将保持不可约,即仅在更新独立鉴别器模型时更新。
接下来,我们将为发电机开发输入。
每个输入都是由噪声和控制代码组成的矢量。具体地,高斯随机数的矢量和一个热编码的随机选择的分类值。
下面的generatelatentpoints()函数实现了这一点,将潜在空间的大小,分类值的数量以及要生成的样本数作为参数作为输入。该函数返回输入连接向量作为生成器模型的输入,以及独立控制代码。通过复合GAN模型更新发电机和辅助模型时,将需要独立控制代码,专门用于计算辅助模型的互信息损失。
# generate points in latent space as input for the generator
def generate_latent_points(latent_dim, n_cat, n_samples):
# generate points in the latent space
z_latent = randn(latent_dim * n_samples)
# reshape into a batch of inputs for the network
z_latent = z_latent.reshape(n_samples, latent_dim)
# generate categorical codes
cat_codes = randint(0, n_cat, n_samples)
# one hot encode
cat_codes = to_categorical(cat_codes, num_classes=n_cat)
# concatenate latent points and control codes
z_input = hstack((z_latent, cat_codes))
return [z_input, cat_codes]
接下来,我们可以生成真实和虚假的例子。
可以通过为灰度图像添加附加维度来加载MNIST数据集,将其转换为3D输入,并将到范围[-1,1]以匹配来自生成器模型的输出。这是在下面的loadreal
CDA学员免费下载查看报告全文:2026全球数智化人才指数报告【CDA数据科学研究院】.pdf
数据分析咨询请扫描二维码
若不方便扫码,搜微信号:CDAshujufenxi
近日,由 CDA 数据科学研究院重磅发布的《2026 全球数智化人才指数报告》,被中国教育科学研究院官方账号正式收录, ...
2026-04-22在数字化时代,客户每一次点击、浏览、下单、咨询等行为,都在传递其潜在需求与决策倾向——这些按时间顺序串联的行为轨迹,构成 ...
2026-04-22数据是数据分析、建模与业务决策的核心基石,而“数据清洗”作为数据预处理的核心环节,是打通数据从“原始杂乱”到“干净可用” ...
2026-04-22 很多数据分析师每天盯着GMV、转化率、DAU等数字看,但当被问到“什么是指标”“指标和维度有什么区别”“如何搭建一套完整的 ...
2026-04-22在数据分析与业务决策中,数据并非静止不变的数值,而是始终处于动态波动之中——股市收盘价的每日涨跌、企业月度销售额的起伏、 ...
2026-04-21在数据分析领域,当研究涉及多个自变量与多个因变量之间的复杂关联时,多变量一般线性分析(Multivariate General Linear Analys ...
2026-04-21很多数据分析师精通描述性统计,能熟练计算均值、中位数、标准差,但当被问到“用500个样本如何推断10万用户的真实满意度”“这 ...
2026-04-21在数据处理与分析的全流程中,日期数据是贯穿业务场景的核心维度之一——无论是业务报表统计、用户行为追踪,还是风控规则落地、 ...
2026-04-20在机器学习建模全流程中,特征工程是连接原始数据与模型效果的关键环节,而特征重要性分析则是特征工程的“灵魂”——它不仅能帮 ...
2026-04-20很多数据分析师沉迷于复杂的机器学习算法,却忽略了数据分析最基础也最核心的能力——描述性统计。事实上,80%的商业分析问题, ...
2026-04-20在数字化时代,数据已成为企业决策的核心驱动力,数据分析与数据挖掘作为解锁数据价值的关键手段,广泛应用于互联网、金融、医疗 ...
2026-04-17在数据处理、后端开发、报表生成与自动化脚本中,将 SQL 查询结果转换为字符串是一项高频且实用的操作。无论是拼接多行数据为逗 ...
2026-04-17面对一份上万行的销售明细表,要快速回答“哪个地区卖得最好”“哪款产品增长最快”“不同客户类型的购买力如何”——这些看似复 ...
2026-04-17数据分析师一天的工作,80% 的时间围绕表格结构数据展开。从一张销售明细表到一份完整的分析报告,表格结构数据贯穿始终。但你真 ...
2026-04-16在机器学习无监督学习领域,Kmeans聚类因其原理简洁、计算高效、可扩展性强的优势,成为数据聚类任务中的主流算法,广泛应用于用 ...
2026-04-16在机器学习建模实践中,特征工程是决定模型性能的核心环节之一。面对高维数据集,冗余特征、无关特征不仅会增加模型训练成本、延 ...
2026-04-16在数字化时代,用户是产品的核心资产,用户运营的本质的是通过科学的指标监测、分析与优化,实现“拉新、促活、留存、转化、复购 ...
2026-04-15在企业数字化转型、系统架构设计、数据治理与AI落地过程中,数据模型、本体模型、业务模型是三大核心基础模型,三者相互支撑、各 ...
2026-04-15数据分析师的一天,80%的时间花在表格数据上,但80%的坑也踩在表格数据上。 如果你分不清数值型和文本型的区别,不知道数据从哪 ...
2026-04-15在人工智能与机器学习落地过程中,模型质量直接决定了应用效果的优劣——无论是分类、回归、生成式模型,还是推荐、预测类模型, ...
2026-04-14