8_7_变分AE

8_7_变分AE

AE(Auto-Encoders):自动的编码

x一排从左边输入进来之后,经过隐层的压缩和解压缩之后(一般来说是2-4层),之后会还原成输入的样子,通常用作一个网络的初始化训练,本来的w是没有的,现在采用AE的方式,先有一个值,过后不管是什么网络,在当前的w的基础上,只需要微调就可以,因为变化不是特别大。

这样就可以节省很多时间来训练其他的网络。

但是现在AE只能通过输入的内容来决定输出,但是变分AE,操作的不是某一个数据,而是输入的数据的规律,有了这些规律,就可逆向的生成数据。(根据前几批的规律总结规律,逆向的造出虚假的数据,让这些数据和真实的数据都是很类的)可以用作图像处理,如逆向生成一个人在某一个地方的图片,这些逆向生成的图片是无法分辨出来的,因为所有的分布都是一样的,基于这种思路,对抗网络生成的数据,比变分AE要更强大。变分AE有细微的差别,对抗网络生成的几乎看不出来,以假乱真,如AI变脸。

引入包:

生成正态分布的规律:

from scipy.stats import norm

因为要在原始的数据的基础上,总结规律,把它变成一个具有正态分布的规矩,基于这个规律来伪造一批数据。

from tensorflow.examples.tutorials.mnist import input_data
mnist=input_data.read_data_sets('MNIST_data/')

拿分号的格式来读取mnist数据集

import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
from scipy.stats import norm
from tensorflow.examples.tutorials.mnist import input_data

开始写这个网络:
输入进来的节点数量是784
隐层:
第一次压缩到256个节点
第二次压缩到2个节点

节点越少,提纯度越高(因为把特征都提取出来了)
第一个节点求正态分布的均值(mean),第二个节点求偏差程度(var)再在次基础上逆向恢复256个
变分AE就是在往常的AE基础上,中间增加了一个求均值和方差的规律,所以这层2个节点。
在这里插入图片描述

n_input=784#输入进来的节点数量是784
n_hidden_1=256#第一次压缩到256个节点
n_hidden_2=2 #mean lg_var     第二次压缩到2个节点

输入数据
用占位符表示N行784列
提取出来规律后在它的基础上,从右往左,逆向的生成数据,所以在这两个节点上伪造数据,这两个节点表示的就是均值和方差,要以这个的规律去伪造x。

x=tf.placeholder(tf.float32, [None, n_input]) #(N, 784)
zinput=tf.placeholder(tf.float32, [None, n_hidden_2]) #(N, 2)

由n_input层到达隐层,用输入w
N行784列
784行256列,这是第一层的

tauncated_normal是截断函数

在正态分布的基础上,还加了截断功能,表示变量是随机生成的,一旦变量的方差大于阈值(stddev)0.001,所有的数据就重做,随机数只有小于阈值才会保留,所以可能会重复多次。
b默认初值是0。

        'w1':tf.Variable(tf.truncated_normal([n_input, n_hidden_1], stddev=0.001)), 
        'b1':tf.Variable(tf.zeros([n_hidden_1])), 

这表示由n_input到隐层


由n_input到n_hidden_2有两套访问参数,第一套是到均值(mean)的,仍然采用截断的方式。

        'mean_w1':tf.Variable(tf.truncated_normal([n_hidden_1, n_hidden_2], stddev=0.001)), 
        'mean_b1':tf.Variable(tf.zeros([n_hidden_2])), 

第二套是到方差(lg_var),参数和上边一样

        'log_sigma_w1':tf.Variable(tf.truncated_normal([n_hidden_1,n_hidden_2], stddev=0.001)), 
        'log_sigma_b1':tf.Variable(tf.zeros([n_hidden_2])), 

然后从这两个节点恢复到256,再由356恢复到784,所以参数和上边刚好逆着来

        'w2':tf.Variable(tf.truncated_normal([n_hidden_2, n_hidden_1], stddev=0.001)), 
        'b2':tf.Variable(tf.zeros([n_hidden_1])), 
        'w3':tf.Variable(tf.truncated_normal([n_hidden_1, n_input], stddev=0.001)), 
        'b3':tf.Variable(tf.zeros([n_input]))

这就是五层的网络参数的结构

weights={
        'w1':tf.Variable(tf.truncated_normal([n_input, n_hidden_1], stddev=0.001)), 
        'b1':tf.Variable(tf.zeros([n_hidden_1])), 
        'mean_w1':tf.Variable(tf.truncated_normal([n_hidden_1, n_hidden_2], stddev=0.001)), 
        'mean_b1':tf.Variable(tf.zeros([n_hidden_2])), 
        'log_sigma_w1':tf.Variable(tf.truncated_normal([n_hidden_1,n_hidden_2], stddev=0.001)), 
        'log_sigma_b1':tf.Variable(tf.zeros([n_hidden_2])), 
        'w2':tf.Variable(tf.truncated_normal([n_hidden_2, n_hidden_1], stddev=0.001)), 
        'b2':tf.Variable(tf.zeros([n_hidden_1])), 
        'w3':tf.Variable(tf.truncated_normal([n_hidden_1, n_input], stddev=0.001)), 
        'b3':tf.Variable(tf.zeros([n_input]))
        }

从n_input层到n_hidden_1层:
wx+b
先将线性函数做出来
用非线性函数将线性函数激活一下,所以加一个relu函数
x是N行784,w是784行256列,所以应该是N行256列

h1=tf.nn.relu(tf.add(tf.matmul(x, weights['w1']), weights['b1'])) #(N, n_hidden_1)

由第一层到第二层是一个分叉的结构,其中一条到了mean节点,另一条到了var节点
从n_hidden_1到mean,没有激活,要保持线性的关系,所以乘完以后是N行2列
z_mean=tf.add(tf.matmul(h1, weights[‘mean_w1’]), weights[‘mean_b1’]) #(N, n_hidden_2)

另一个

z_log_sigma_sq=tf.add(tf.matmul(h1, weights['log_sigma_w1']), weights['log_sigma_b1']) #(N, n_hidden_2)

这样就完成了h1到mean隐层到mean和到var节点的两条映射:

h1=tf.nn.relu(tf.add(tf.matmul(x, weights['w1']), weights['b1'])) #(N, n_hidden_1)
z_mean=tf.add(tf.matmul(h1, weights['mean_w1']), weights['mean_b1']) #(N, n_hidden_2)
z_log_sigma_sq=tf.add(tf.matmul(h1, weights['log_sigma_w1']), weights['log_sigma_b1']) #(N, n_hidden_2)

模拟正态数据:
生成一个符合高斯正态分布的随机分布,分布的尺寸是h1的第0维(也就是N),N行2列
stack是一个拼接函数,可以把两部内容拼一下
拼成的形状满足的是均值为0,方差为1,并且是float的数据

#生成正态分布数据,(None, n_hidden_2)
eps=tf.random_normal(tf.stack([tf.shape(h1)[0], n_hidden_2]), 0, 1, dtype=tf.float32)

再mean层和var层的基础上,归类,生成一个类别
首先在方差点,先求e 的指数,再开根号,让得到的数乘以随机数(eps),因为z_log_sigma_sq是N行2列,指数之后开根号还是N行2列,再加上z_mean,所以到最后z点还是N行2列

z=tf.add(z_mean, tf.multiply(tf.sqrt(tf.exp(z_log_sigma_sq)), eps)) #(N, n_hidden_2)

在z点的基础上恢复,恢复到256
再由256恢复到784
怎么进来的怎么出去

h2=tf.nn.relu(tf.matmul(z, weights['w2'])+weights['b2']) #(N, n_hidden_1)

把出去的数叫reconstrucation(重构),表示的是模型的实际输出,不是人为的伪造,再恢复成N行784列

reconstruction=tf.matmul(h2, weights['w3'])+weights['b3'] #(N, n_input)
#生成正态分布数据,(None, n_hidden_2)
eps=tf.random_normal(tf.stack([tf.shape(h1)[0], n_hidden_2]), 0, 1, dtype=tf.float32)
z=tf.add(z_mean, tf.multiply(tf.sqrt(tf.exp(z_log_sigma_sq)), eps)) #(N, n_hidden_2)
h2=tf.nn.relu(tf.matmul(z, weights['w2'])+weights['b2']) #(N, n_hidden_1)
reconstruction=tf.matmul(h2, weights['w3'])+weights['b3'] #(N, n_input)

拿伪造的数据生成一个伪造的输出
z_input是一个虚拟出来的N行2列的,模拟的是z,和z有共同的分布
h2out(倒数第二层):虚拟的数据,wx+b,relue
用虚拟的N行2列去还原倒数第二层

h2out=tf.nn.relu(tf.matmul(zinput, weights['w2'])+weights['b2']) #(N, n_hidden_1)

再由倒数第二层去还原倒数第一层
由虚拟数据得到的一个图像

reconstructionout=tf.matmul(h2out, weights['w3'])+weights['b3'] #(N, n_input)

为了让模型更好的以假乱真,要逐渐缩小模型的误差
首先
降低真实数据的误差
真实数据和虚拟数据各占二分之一
拿真实数据和输入的x的差求平方, 乘n分之1,再乘0.5

#误差
reconstruction_loss=0.5*tf.reduce_mean(tf.pow(tf.subtract(reconstruction, x), 2.0))

kl算法
1+方差-均值的根号下-方差的指数,再加1

latent_loss=-0.5*tf.reduce_mean(1+z_log_sigma_sq-tf.square(z_mean)-tf.exp(z_log_sigma_sq), 1) #KL

模型总的误差为这两个误差的和

cost=tf.reduce_mean(reconstruction_loss+latent_loss)

最终的优化器:在这个学习率下最小

optimizer=tf.train.AdamOptimizer(learning_rate=0.001).minimize(cost)

想要训练50趟,每训练1次,批处理128个数据,每训练3次展示1次

trainint_epochs=50
batch_size=128
display_step=3

模型的均值误差是0
avg_cost=0.0
每一趟的批次:训练数据的总量55000/128
遍历这些批次,分别取值,取128个值,
如果训练次数到了3的整数倍,就打印
结束这个训练

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    for epoch in range(trainint_epochs):
        avg_cost=0.0
        total_batch=int(mnist.train.num_examples/batch_size)
        for i in range(total_batch):
            batch_xs, batch_ys=mnist.train.next_batch(batch_size)
            _, c=sess.run([optimizer, cost], feed_dict={x:batch_xs})
            avg_cost+=c/total_batch
        if epoch % display_step == 0:
            print('epoch:', epoch+1, 'cost:', avg_cost)
    print('finished')

测试一下模型的误差:
用10000张测试图像求误差,最后求均值

print('cost:', cost.eval({x:mnist.test.images})/total_batch)

看可视化结果:
要画10张图
模型等于
想要的是真实的输出,前十张用来画图
画2行10列,所以整图宽度是10,高度是2,
第一行第i列画的是原图
第二行第i列画的是模型的实际输出pred
对比一下

    show_num=10
    pred=sess.run(reconstruction, feed_dict={x:mnist.test.images[:show_num]})
    f, a=plt.subplots(2, 10, figsize=(10, 2))
    for i in range(show_num):
        a[0][i].imshow(np.reshape(mnist.test.images[i], (28, 28)))
        a[1][i].imshow(np.reshape(pred[i], (28, 28)))
    plt.draw()

饼图的压缩:
实际输出,两列
拿第一列和第二列看x轴,y轴,看饼图分布

    pred=sess.run(z, feed_dict={x:mnist.test.images})
    plt.figure(figsize=(6, 6)) #虽然只有一个图,但是占了6*6的面积
    plt.scatter(pred[:, 0], pred[:, 1], c=mnist.test.labels)
    plt.colorbar()
    plt.show()

伪造样本:
伪造出来的样本具有很高的识别度
伪造一个15行15列,
每个位置上是一个数字,伪造的数字样本,大小是28
28,也就是说和真实mnist有相同的尺寸,
2815,2815,表示一个二维的数组,figure用全0画出来
想画一个digit_sizen行,digit_sizen列的一个分布
这些分布,从0.05-0.95之间
因为小于0.05和大于0.95两边的数,在正态分布中是逐渐趋于极值的,是不可信的,取最可信的范围0.05-0.95,然后平均分成15份,x轴是15份,y轴也是15份,
linspace表示平均分
由随机区域0.05-0.95,逆向的生成 x轴坐标和y轴坐标

grid_x=norm.ppf()
grid_y=norm.ppf()

以前的做法是有坐标之后再去画正态分布的轴,但是现在没有坐标,仅凭一个分布的数据去逆向生成x轴和y轴的坐标
先竖着固定,再去遍历行

    for i, yi in enumerate(grid_x): #行数
        for j, xi in enumerate(grid_y): #列数

取当前的行值和列值,把他包装成一个列表
一取就是一对列表,xi,yi是一对,用列表生成一个数组np.array,得到一个坐标z_sample,225*225的一个坐标

            z_sample=np.array([[xi, yi]])

这些坐标是根据虚拟数据逆向生成的坐标
拿坐标给zinput逆向数据
然后得到伪造的数据x_decoded

            x_decoded=sess.run(reconstructionout,feed_dict={zinput:z_sample}) #(784, )

784个数据,取第0维度(也就是第1行),相当于取1行,
再将784列转置,重构成28*28

            digit=x_decoded[0].reshape(digit_size, digit_size) #(28, 28)

然后再把每一批数据28*28给figure,因为figure是全0的
i到i+1,每循环一次i,取28个数据,行和列每次都取28个数据,取出来一幅图,

            figure[i*digit_size:(i+1)*digit_size, j*digit_size:(j+1)*digit_size]=digit

然后把图画出来,最后就会生成伪造的数据

    plt.figure(figsize=(10, 10))
    plt.imshow(figure, cmap='Greys_r')
    plt.show()
    #伪造样本
    n=15 #样本数量15*15
    digit_size=28 #样本尺寸28*28
    figure=np.zeros((digit_size*n, digit_size*n))
    grid_x=norm.ppf(np.linspace(0.05, 0.95, n)) #逆向返回高斯分布在0.05~0.95之间的X坐标值
    grid_y=norm.ppf(np.linspace(0.05, 0.95, n))
    
    for i, yi in enumerate(grid_x): #行数
        for j, xi in enumerate(grid_y): #列数
            z_sample=np.array([[xi, yi]])
            x_decoded=sess.run(reconstructionout,feed_dict={zinput:z_sample}) #(784, )
            
            digit=x_decoded[0].reshape(digit_size, digit_size) #(28, 28)
            figure[i*digit_size:(i+1)*digit_size, j*digit_size:(j+1)*digit_size]=digit
    
    plt.figure(figsize=(10, 10))
    plt.imshow(figure, cmap='Greys_r')
    plt.show()


整体代码:

# -*- coding: utf-8 -*-
"""
Created on Sat Dec 10 21:14:06 2022

@author: 玉想琼思
"""

import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
from scipy.stats import norm
from tensorflow.examples.tutorials.mnist import input_data
mnist=input_data.read_data_sets('MNIST_data/')

n_input=784
n_hidden_1=256
n_hidden_2=2 #mean lg_var

x=tf.placeholder(tf.float32, [None, n_input]) #(N, 784)
zinput=tf.placeholder(tf.float32, [None, n_hidden_2]) #(N, 2)

weights={
        'w1':tf.Variable(tf.truncated_normal([n_input, n_hidden_1], stddev=0.001)), 
        'b1':tf.Variable(tf.zeros([n_hidden_1])), 
        'mean_w1':tf.Variable(tf.truncated_normal([n_hidden_1, n_hidden_2], stddev=0.001)), 
        'mean_b1':tf.Variable(tf.zeros([n_hidden_2])), 
        'log_sigma_w1':tf.Variable(tf.truncated_normal([n_hidden_1,n_hidden_2], stddev=0.001)), 
        'log_sigma_b1':tf.Variable(tf.zeros([n_hidden_2])), 
        'w2':tf.Variable(tf.truncated_normal([n_hidden_2, n_hidden_1], stddev=0.001)), 
        'b2':tf.Variable(tf.zeros([n_hidden_1])), 
        'w3':tf.Variable(tf.truncated_normal([n_hidden_1, n_input], stddev=0.001)), 
        'b3':tf.Variable(tf.zeros([n_input]))
        }

h1=tf.nn.relu(tf.add(tf.matmul(x, weights['w1']), weights['b1'])) #(N, n_hidden_1)
z_mean=tf.add(tf.matmul(h1, weights['mean_w1']), weights['mean_b1']) #(N, n_hidden_2)
z_log_sigma_sq=tf.add(tf.matmul(h1, weights['log_sigma_w1']), weights['log_sigma_b1']) #(N, n_hidden_2)

#生成正态分布数据,(None, n_hidden_2)
eps=tf.random_normal(tf.stack([tf.shape(h1)[0], n_hidden_2]), 0, 1, dtype=tf.float32)
z=tf.add(z_mean, tf.multiply(tf.sqrt(tf.exp(z_log_sigma_sq)), eps)) #(N, n_hidden_2)
h2=tf.nn.relu(tf.matmul(z, weights['w2'])+weights['b2']) #(N, n_hidden_1)
reconstruction=tf.matmul(h2, weights['w3'])+weights['b3'] #(N, n_input)

h2out=tf.nn.relu(tf.matmul(zinput, weights['w2'])+weights['b2']) #(N, n_hidden_1)
reconstructionout=tf.matmul(h2out, weights['w3'])+weights['b3'] #(N, n_input)

#误差
reconstruction_loss=0.5*tf.reduce_mean(tf.pow(tf.subtract(reconstruction, x), 2.0))
latent_loss=-0.5*tf.reduce_mean(1+z_log_sigma_sq-tf.square(z_mean)-tf.exp(z_log_sigma_sq), 1) #KL
cost=tf.reduce_mean(reconstruction_loss+latent_loss)
optimizer=tf.train.AdamOptimizer(learning_rate=0.001).minimize(cost)

trainint_epochs=50
batch_size=128
display_step=3

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    for epoch in range(trainint_epochs):
        avg_cost=0.0
        total_batch=int(mnist.train.num_examples/batch_size)
        for i in range(total_batch):
            batch_xs, batch_ys=mnist.train.next_batch(batch_size)
            _, c=sess.run([optimizer, cost], feed_dict={x:batch_xs})
            avg_cost+=c/total_batch
        if epoch % display_step == 0:
            print('epoch:', epoch+1, 'cost:', avg_cost)
    print('finished')
    
    print('cost:', cost.eval({x:mnist.test.images})/total_batch)
    
        
    # 可视化结果
    show_num=10
    pred=sess.run(reconstruction, feed_dict={x:mnist.test.images[:show_num]})
    f, a=plt.subplots(2, 10, figsize=(10, 2))
    for i in range(show_num):
        a[0][i].imshow(np.reshape(mnist.test.images[i], (28, 28)))
        a[1][i].imshow(np.reshape(pred[i], (28, 28)))
    plt.draw()
    
    pred=sess.run(z, feed_dict={x:mnist.test.images})
    plt.figure(figsize=(6, 6)) #虽然只有一个图,但是占了6*6的面积
    plt.scatter(pred[:, 0], pred[:, 1], c=mnist.test.labels)
    plt.colorbar()
    plt.show()

    #伪造样本
    n=15 #样本数量15*15
    digit_size=28 #样本尺寸28*28
    figure=np.zeros((digit_size*n, digit_size*n))
    grid_x=norm.ppf(np.linspace(0.05, 0.95, n)) #逆向返回高斯分布在0.05~0.95之间的X坐标值
    grid_y=norm.ppf(np.linspace(0.05, 0.95, n))
    
    for i, yi in enumerate(grid_x): #行数
        for j, xi in enumerate(grid_y): #列数
            z_sample=np.array([[xi, yi]])
            x_decoded=sess.run(reconstructionout,feed_dict={zinput:z_sample}) #(784, )
            
            digit=x_decoded[0].reshape(digit_size, digit_size) #(28, 28)
            figure[i*digit_size:(i+1)*digit_size, j*digit_size:(j+1)*digit_size]=digit
    
    plt.figure(figsize=(10, 10))
    plt.imshow(figure, cmap='Greys_r')
    plt.show()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值