你真的了解VQ-GAN中VQ的原理嘛?

1. VQ(即Vector Quantization,矢量量化),其作用:将一个向量空间中的点,用其中一个有限子集中的点,进行编码;应用场景也很广泛,如图像压缩,声音压缩,CV领域特征降维等。

2. 数学含义:将矢量空间中的 k 维矢量映射到矢量的有限集合

  • 即向量空间 R k R^k Rk中的所有x,都可以使用有限集合Y中的值表示:
    Y = { y i : i = 1 , 2 , 3 , . . . , N } Y=\{y_i:i=1, 2,3,...,N\} Y={yi:i=1,2,3,...,N}
  • 且每个 x 都有相应邻域中的 y i y_i yi与之对应
    在这里插入图片描述

3. 考虑一个图像编码的例子,有一个简单的图像使用VQ编码,例如:
在这里插入图片描述
其中:左边是原图,中间是codebook,右边是vq编码后的图像
在这里插入图片描述
其中:红色点就是对上述原图使用k-means聚类后得到的centroids

4. 对图像进行vq编码就是:将原图像中每个像素点当作一个数据,使用 K-means聚类得到 k 个centroids(即codebook中的值) ,然后用这些 centroids 的像素值来代替对应原图像中所有点的像素值,代码如下:

import numpy as np
from scipy.cluster.vq import vq, kmeans

import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

def plot_scatter(data, codebook):
    fig = plt.figure()
    ax = fig.add_subplot(111, projection='3d')
    
    colors = np.random.rand(data.shape[0])  # 散点颜色
    sizes = np.random.randint(low=50, high=150, size=data.shape[0])  # 散点大小

    ax.set_xlabel('R-X', c='r')
    ax.set_ylabel('G-Y', c='g')
    ax.set_zlabel('B-Z', c='b')
    ax.scatter(data[:, 0], data[:, 1], data[:, 2], c=colors, s=sizes, alpha=1)
    ax.scatter(codebook[:, 0], codebook[:, 1], codebook[:, 2], c='r', s=150)
    plt.show()
    return

def test_vq():    
    # # data
    features  = np.array([[121.6, 147.2, 108.8],
                            [96.9, 160.6,  140.8],
                            [51.2, 38.4, 108.8],
                            [204.9, 179.2, 172.8],
                            [40.5, 56.3, 98.6],
                            [168.2, 182.1, 192.3]])

    # # discrete data
    # features = np.array([[0., 0., 0.],
    #                         [12., 12.,  12.],
    #                         [0., 0., 0.],
    #                         [12., 12., 12.],
    #                         [12., 12., 12.],
    #                         [0., 0., 0.]])

    # # random data.
    # np.random.seed(seed=4321)
    # features = np.random.uniform(0., 1.0, size=(10, 3)) * 255
    
    # codebook.
    code_book, dist = kmeans(features, 3, seed=4321)
    code_book = np.around(code_book, 1)
    
    # vq
    code_index, distor = vq(features,code_book)
    vq_data_from_codebook = code_book[code_index,:]

    print(f'code book: \n', code_book)
    print('-' * 128)
    print(f'code index from codebook: {code_index}')
    print('-' * 128)
    print('vq data from codebook: \n{}'.format(vq_data_from_codebook))
    print('-' * 128)
    print('vq distance: \n', distor)
    print('-' * 128)
    print('validation distance: \n', np.linalg.norm(features - vq_data_from_codebook, axis=1))
    print('-' * 128)
    print('first row distance: \n', np.sqrt(np.sum(np.square(features[0] - vq_data_from_codebook[0]))))

    # plot
    plot_scatter(data=features, codebook=code_book)

if __name__ == "__main__":
    ##
    test_vq()

注:代码对离散图像数据也是适合的

对于彩色图片来说,也可以用同样的方法来做,例如 RGB 彩色图像,每一个像素被当作是一个 3 维向量空间中的点, 使用scipy库中的k-means和vq,将centroids的个数分别为: 2,10,100,200;代码如下:

import os

from scipy.cluster.vq import kmeans, vq
import numpy as np
from PIL import Image

''' blog: https://www.cnblogs.com/Higgerw/p/15238513.html '''


def k_vq(data, k, iter=20):
    print('Generating vq-%d...' % k)
    (centroids, distor) = kmeans(data, k, iter=iter)       # get discrete codebook.
    (code_index, distor) = vq(data, centroids)        # get discrete index from centroids.
    print('distor: %.6f' % distor.sum())
    return centroids, code_index

def main():
    # get image.
    # path = 'lenna.jpg'
    path = 'xiaojiejie.jpg'
    pic = Image.open(path)
    data = np.array(pic)
    height, width, channel = data.shape
    data = np.float32(np.reshape(data, (height*width, channel)))

    # save path
    os.makedirs('output', exist_ok=True)

    vqclst = [2, 10, 100, 200]
    for k in vqclst:
        codebook, code_index = k_vq(data, k)
        im_vq = codebook[code_index, :]
        new_data = np.uint8(np.reshape(im_vq, (height, width, channel)))    # h x w x c
        new_pic = Image.fromarray(new_data)
        new_pic.save('output/result-%d.jpg' % k)

if __name__ == "__main__":
    # ##
    main()


运行代码的结果:​
在这里插入图片描述
5. 那么重点来了,这里求解codebook是通过使用k-means聚类,k-means算法聚类一般通过欧氏距离求解属于同一簇的centroid的,而VQ-GAN中是先随机初始化一个N维的Embedding(也即是N维的codebook),然后计算Embedding与图像的featuremap的距离,通过卷积神经网络的反向传播算法更新Embedding中的值的到最后的codebook的,所以二者的原理是相似的。

  • 17
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值