前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >学习GAN模型量化评价,先从掌握FID开始吧

学习GAN模型量化评价,先从掌握FID开始吧

作者头像
机器之心
发布于 2019-10-15 03:25:12
发布于 2019-10-15 03:25:12
3.5K00
代码可运行
举报
文章被收录于专栏:机器之心机器之心
运行总次数:0
代码可运行

要说谁是当下最火的生成模型,GAN 当之无愧!然而,模式坍塌、训练不稳定等问题严重制约着 GAN 家族的发展。为了提图像质量、样本多样性的角度量化评价 GAN 模型的性能,研究者们提出了一系列度量指标,其中 FID 就是近年来备受关注的明星技术,本文将详细介绍如何在 python 环境下实现 Frechet Inception 距离(FID)。

Frechet Inception 距离得分(Frechet Inception Distance score,FID)是计算真实图像和生成图像的特征向量之间距离的一种度量。

FID 从原始图像的计算机视觉特征的统计方面的相似度来衡量两组图像的相似度,这种视觉特征是使用 Inception v3 图像分类模型计算的得到的。分数越低代表两组图像越相似,或者说二者的统计量越相似,FID 在最佳情况下的得分为 0.0,表示两组图像相同。

FID 分数被用于评估由生成性对抗网络生成的图像的质量,较低的分数与较高质量的图像有很高的相关性。

在本教程中,你将了解如何通过 FID 评估生成的图像。

同时你还将了解:

  • FID 综合表征了相同的域中真实图像和生成图像的 Inception 特征向量之间的距离。
  • 如何计算 FID 分数并在 NumPy 环境下实现 FID。
  • 如何使用 Keras 深度学习库实现 FID 分数并使用真实图像进行计算。

在本文作者有关 GAN 的新书中,读者可以了解到如何使用 Keras 开发 DCGAN、条件 GAN、Pix2Pix、CycleGAN 等对抗生成网络,书中还提供 29 个详细教程和完整源代码。

下面进入正文部分:

教程概述

本教程分为五个部分,分别是:

  1. 何为 FID?
  2. 如何计算 FID?
  3. 如何通过 NumPy 实现 FID?
  4. 如何通过 Keras 实现 FID?
  5. 如何计算真实图像的 FID?

机器之心整理了前三部分的代码,感兴趣的读者可以在原文中查看 Keras 的 FID 实现和计算真实图像 FID 的方法。

何为 FID?

Frechet Inception 距离(FID)是评估生成图像质量的度量标准,专门用于评估生成对抗网络的性能。

FID 分数由 Martin Heusel 等人于 2017 年在论文「GANs Trained by a Two Time-Scale Update Rule Converge to a Local Nash Equilibrium」(https://arxiv.org/abs/1706.08500017)中提出并使用。

该分数作为对现有的 Inception 分数(IS)的改进而被提出。

为了评估 GAN 在图像生成任务中的性能,我们引入了「Frechet Inception Distance」(FID),它能比 Inception 分数更好地计算生成图像与真实图像的相似性。——「GANs Trained by a Two Time-Scale Update Rule Converge to a Local Nash Equilibrium」(https://arxiv.org/abs/1706.08500), 2017.

Inception 分数基于目前性能最佳的图像分类模型 Inception v3 对一组合成图像的分类情况(将其分类为 1,000 类对象中的一种)来评估图像的质量。该分数结合了每个合成图像的条件类预测的置信度(质量)和预测类别的边缘概率积分(多样性)。

Inception 分数缺少合成图像与真实图像的比较。研发 FID 分数的目的是基于一组合成图像的统计量与来自目标域的真实图像的统计量进行的比较,实现对合成图像的评估。

Inception 分数的缺点是没有使用现实世界样本的统计量,并将其与合成样本的统计量进行比较。——「GANs Trained by a Two Time-Scale Update Rule Converge to a Local Nash Equilibrium 」(https://arxiv.org/abs/1706.08500), 2017.

与 Inception 分数一样,FID 分数也使用了 Inception v3 模型。具体而言,模型的编码层(图像的分类输出之前的最后池化层)被用来抽取输入图像的用计算机视觉技术指定的特征。这些激活函数是针对一组真实图像和生成图像计算的。

通过计算图像的均值和协方差,将激活函数的输出归纳为一个多变量高斯分布。然后将这些统计量用于计算真实图像和生成图像集合中的激活函数。

然后使用 Frechet 距离(又称 Wasserstein-2 距离)计算这两个分布之间的距离。

两个高斯分布(合成图像和真实图像)的差异由 Frechet 距离(又称 Wasserstein-2 距离)测量。 ——「GANs Trained by a Two Time-Scale Update Rule Converge to a Local Nash Equilibrium」(https://arxiv.org/abs/1706.08500), 2017.

使用来自 Inception v3 模型的激活函数输出来归纳每个图像,得分即为「Frechet Inception Distance」。

FID 越低,图像质量越好;反之,得分越高,质量越差,两者关系应该是线性的。

该分数的提出者表明,当应用系统失真(如加入随机噪声和模糊)时,FID 越低,图像质量越好。

图像失真程度的提高与高 FID 分数之间的关系。

如何计算 Frechet Inception 距离?

首先,通过加载经过预训练的 Inception v3 模型来计算 FID 分数。

删除模型原本的输出层,将输出层换为最后一个池化层(即全局空间池化层)的激活函数输出值。此输出层有 2,048 维的激活向量,因此,每个图像被预测为 2,048 个激活特征。该向量被称为图像的编码向量或特征向量。

针对一组来自问题域的真实图像,预测 2,048 维的特征向量,用来提供真实图像表征的参考。然后可以计算合成图像的特征向量。

结果就是真实图像和生成图像各自的 2,048 维特征向量的集合。

然后使用以下公式计算 FID 分数:

该分数被记为 d^2,表示它是一个有平方项的距离。

「mu_1」和「mu_2」指的是真实图像和生成图像的特征均值(例如,2,048 维的元素向量,其中每个元素都是在图像中观察到的平均特征)。

C_1 和 C_2 是真实图像的和生成图像的特征向量的协方差矩阵,通常被称为 sigma。

|| mu_1-mu_2 ||^2 代表两个平均向量差的平方和。Tr 指的是被称为「迹」的线性代数运算(即方阵主对角线上的元素之和)。

sqrt 是方阵的平方根,由两个协方差矩阵之间的乘积给出。

矩阵的平方根通常也被写作 M^(1/2),即矩阵的 1/2 次方。此运算可能会失败,由于该运算是使用数值方法求解的,是否成功取决于矩阵中的值。通常,所得矩阵中的一些元素可能是虚数,它们通常可以被检测出来并删除。

如何用 NumPy 实现 Frechet Inception 距离?

使用 NumPy 数组在 Python 中实现 FID 分数的计算非常简单。

首先,让我们定义一个函数,它将为真实图像和生成图像获得一组激活函数值,并返回 FID 分数。

下面列出的「calculate_fid()」函数实现了该过程。

通过该函数,我们几乎直接实现了 FID 分数的计算。值得注意的是,TensorFlow 中的官方实现计算元素的顺序稍有不同(可能是为了提高效率),并在加入了矩阵平方根附近的额外检查,以处理可能的数值不稳定性。

如果在自己的数据集上计算 FID 时遇到问题,我建议你查看官方教程并扩展下面的实现,以添加这些检查。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
def calculate_fid(act1, act2):
    # calculate mean and covariance statistics
    mu1, sigma1 = act1.mean(axis=0), cov(act1, rowvar=False)
    mu2, sigma2 = act2.mean(axis=0), cov(act2, rowvar=False)
    # calculate sum squared difference between means
    ssdiff = numpy.sum((mu1 - mu2)*2.0)
    # calculate sqrt of product between cov
    covmean = sqrtm(sigma1.dot(sigma2))
    # check and correct imaginary numbers from sqrt
    if iscomplexobj(covmean):
        covmean = covmean.real
    # calculate score
    fid = ssdiff + trace(sigma1 + sigma2 - 2.0  covmean)
    return fid

接下来,我们可以测试这个函数来计算一些人造特征向量的 Inception 分数。

特征向量可能包含小的正值,长度为 2,048 个元素。我们可以用包含小随机数的特征向量构建两组图像(每组 10 幅),如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
act1 = random(102048)
act1 = act1.reshape((10,2048))
act2 = random(102048)
act2 = act2.reshape((10,2048))

一个测试是计算一组激活与其自身之间的 FID,我们期望分数为 0.0。

然后计算两组随机激活之间的距离,我们期望它们是一个很大的数字。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
fid = calculate_fid(act1, act1)
print('FID (same): %.3f' % fid)

fid = calculate_fid(act1, act2)
print('FID (different): %.3f' % fid)

将所有这些结合在一起,完整的示例如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import numpy
from numpy import cov
from numpy import trace
from numpy import iscomplexobj
from numpy.random import random
from scipy.linalg import sqrtm

def calculate_fid(act1, act2):
    # calculate mean and covariance statistics
    mu1, sigma1 = act1.mean(axis=0), cov(act1, rowvar=False)
    mu2, sigma2 = act2.mean(axis=0), cov(act2, rowvar=False)
    # calculate sum squared difference between means
    ssdiff = numpy.sum((mu1 - mu2)*2.0)
    # calculate sqrt of product between cov
    covmean = sqrtm(sigma1.dot(sigma2))
    # check and correct imaginary numbers from sqrt
    if iscomplexobj(covmean):
        covmean = covmean.real
    # calculate score
    fid = ssdiff + trace(sigma1 + sigma2 - 2.0  covmean)
    return fid

act1 = random(102048)
act1 = act1.reshape((10,2048))
act2 = random(102048)
act2 = act2.reshape((10,2048))
fid = calculate_fid(act1, act1)
print('FID (same): %.3f' % fid)
fid = calculate_fid(act1, act2)
print('FID (different): %.3f' % fid)

运行这段代码示例,首先会显示出激活函数值「act1」和它自己之间的 FID 分数,正如我们所预想的那样,该值为 0.0(注:该分数的符号可以忽略)

同样,正如我们所预料的,两组随机激活函数值之间的距离是一个很大的数字,在本例中为 358

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
FID (same): -0.000


FID (different): 358.927
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-10-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 机器之心 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
write函数的详解与read函数的详解[通俗易懂]
1.fread函数是封装好的库函数,而read函数是系统函数,一般来说,fread效率更高; 2.读取文件的差别:fread函数功能更强大,可以读取结构体的二进制文件,但是如果是最底层的操作,用到文件描述符的话,用read会更好。
全栈程序员站长
2022/06/25
1.1K0
write函数的详解与read函数的详解[通俗易懂]
深入理解linux下write()和read()函数
函数定义:ssize_t write (int fd, const void * buf, size_t count);
全栈程序员站长
2022/09/01
2.9K0
深入理解linux下write()和read()函数
windows下的C++ socket服务器(4)
void handleAccept(int socket_fd) { char buf[1024] = { '\0' }; string cmd; string filename; recv(socket_fd, buf, sizeof(buf), 0);//1 stringstream sstream;//2 sstream << buf; sstream >> cmd; sstream >> filename; cout << cm
magicsoar
2018/02/06
2.3K0
Linux网络编程基础API
此处「Thank you」的传递是多余的,这只是用来模拟客户端断开连接前还有数据要传输的情况。此时程序实现的难度并不小,因为传输文件的服务器端只需连续传输文件数据即可,而客户端无法知道需要接收数据到何时。客户端也没办法无休止的调用输入函数,因为这有可能导致程序阻塞。
玖柒的小窝
2021/12/15
1.5K0
Linux网络编程基础API
TCP编程函数和步骤
TCP编程的服务器端一般步骤是 1、 创建一个socket,用函数socket(); 2、 设置socket属性,用函数setsockopt(); * 可选 3、 绑定IP地址、端口等信息到socket上,用函数bind(); 4、 开启监听,用函数listen(); 5、 接收客户端上来的连接,用函数accept(); 6、 收发数据,用函数send()和recv(),者read()和write(); 7、 关闭网络连接; 8、 关闭监听; TCP编程的客户端一般步骤是: 1、 创建一个socket,用函
猿人谷
2018/01/17
8150
socket网络编程(一)——初识socket
出现一项技术,首先我们弄懂一下,为什么要出现。那么为什么要出现socket这玩意呢?可以很简单的用一句话来概括:
一点sir
2024/01/10
4010
socket网络编程(一)——初识socket
【网络编程系列】二:socket通信原理及实践
我们深谙信息交流的价值,那网络中进程之间如何通信,如我们每天打开浏览器浏览网页时,浏览器的进程怎么与web服务器通信的?当你用QQ聊天时,QQ进程怎么与服务器或你好友所在的QQ进程通信?这些都得靠socket?那什么是socket?socket的类型有哪些?还有socket的基本函数,这些都是本文想介绍的。本文的主要内容如下: 1、网络中进程之间如何通信? 2、Socket是什么? 3、socket的基本操作 3.1、socket()函数 3.2、bind()函数 3.3、l
老白
2018/03/19
1.8K0
【网络编程系列】二:socket通信原理及实践
sendto & recvfrom 详解
sendto和recvfrom一般用于UDP协议中,但是如果在TCP中connect函数调用后也可以用.
全栈程序员站长
2022/09/15
2.5K0
TCP Socket性能优化秘籍:掌握read、recv、readv、write、send、sendv的最佳实践
TCP Socket在网络通信中的重要性体现在其提供了可靠的数据传输、连接性、多路复用等特性,是实现各种网络应用的基础,同时具有广泛的兼容性。它的存在使得网络通信更加可靠、高效和方便。其重要性如下:
Lion 莱恩呀
2024/08/02
1.2K0
TCP Socket性能优化秘籍:掌握read、recv、readv、write、send、sendv的最佳实践
linux网络编程系列(三)--tcp和udp的基本函数调用过程及如何选择
TCP是TCP/IP体系中面向连接的传输层协议,它提供全双工和可靠交付的服务。它采用许多机制来确保端到端结点之间的可靠数据传输,如采用序列号、确认重传、滑动窗口等。
cpp加油站
2021/04/16
1K0
linux网络编程系列(三)--tcp和udp的基本函数调用过程及如何选择
send,recv,sendto,recvfrom
int send( SOCKET s, const char FAR *buf, int len, int flags );
全栈程序员站长
2022/07/14
1.6K0
Udp协议Socket编程
  本次socket编程需要使用到 日志文件,此为具体日志编写过程。以及 线程池,线程池原理比较简单,看注释即可。
用户11029129
2024/11/17
1280
Udp协议Socket编程
c语言socket通信
1. 前 言 网络的Socket数据传输是一种特殊的I/O,Socket也是一种文件描述符。Socket也具有一个类似于打开文件的函数调用Socket(),该函数返回一个整型的Socket描述符,随后的连接建立、数据传输等操作都是通过该Socket实现的。
全栈程序员站长
2022/09/14
1.3K0
UDP服务端和客户端通信代码开发流程
面向无连接的,不稳定的,不可靠,不安全的数据报传递=---更像是收发短信,UDP传输不需要建立连接,传输效率更高,在稳定的局域网内部环境相对可靠
莫浅子
2023/11/03
6360
UDP服务端和客户端通信代码开发流程
C语言实现Socket简单通信
https://www.cnblogs.com/Dukefish/p/9197830.html
C语言中文社区
2022/05/30
6750
【计网】从零开始使用UDP进行socket编程 --- 客户端与服务端的通信实现
我们了解了网络编程的大概,今天我们就来使用UDP协议来实现客户端与服务端之间的通信过程:
叫我龙翔
2024/09/17
3040
进程间通讯(七).socket(3)
__fd 指定地址与哪个套接字绑定,这是一个由之前的socket函数调用返回的套接字。调用bind的函数之后,该套接字与一个相应的地址关联,发送到这个地址的数据可以通过这个套接字来读取与使用
franket
2021/09/15
1.1K0
Socket编程(4)TCP粘包问题及解决方案
① TCP是个流协议,它存在粘包问题 TCP是一个基于字节流的传输服务,"流"意味着TCP所传输的数据是没有边界的。这不同于UDP提供基于消息的传输服务,其传输的数据是有边界的。TCP的发送方无法保证
Tencent JCoder
2018/07/02
1.9K0
Socket编程原理(1)「建议收藏」
socket编程原理 socket编程原理 1 问题的引入 UNIX系统的I/O命令集,是从Maltics和早期系统中的命令演变出来的,其模式为打开一读/写一关闭(open-write-read-close)。在一个用户进程进行I/O操作时,它首先调用“打开”获得对指定文件或设备的使用权,并返回称为文件描述符的整型数,以描述用户在打开的文件或设备上进行I/O操作的进程。然后这个用户进程多次调用“读/写”以传输数据。当所有的传输操作完成后,用户进程关闭调用,通知操作系统已经完成了对某对象的使用。
全栈程序员站长
2022/11/02
5890
C++中的socket编程常用接口
socket() 函数是进行网络编程的基础,它用于创建一个新的套接字(socket)。套接字是网络通信的端点,可以用于在不同计算机之间传输数据。下面是对 socket() 函数的详细解释:
薄荷冰
2024/07/19
1930
推荐阅读
相关推荐
write函数的详解与read函数的详解[通俗易懂]
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档