【TensorFlow-windows】(二) 实现一个去噪自编码器

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/u011995719/article/details/73549988

主要内容
1.自编码器的TensorFlow实现代码(详细代码注释)
2.该实现中的函数总结

平台:
1.windows 10 64位
2.Anaconda3-4.2.0-Windows-x86_64.exe (当时TF还不支持python3.6,又懒得在高版本的anaconda下配置多个Python环境,于是装了一个3-4.2.0(默认装python3.5),建议装anaconda3的最新版本,TF1.2.0版本已经支持python3.6!)
3.TensorFlow1.1.0

老样子,先贴代码:

# -*- coding: utf-8 -*-
"""
Created on Tue Jun 20 12:59:16 2017

@author: ASUS
"""
import numpy as np
import sklearn.preprocessing as prep 
import tensorflow as tf 
from tensorflow.examples.tutorials.mnist import input_data

# 定义Xavier初始化函数  tf.random_uniform产生均匀分布
def xavier_init(fan_in, fan_out, constant = 1):
    low = -constant * np.sqrt(6.0 / (fan_in + fan_out))
    high = constant * np.sqrt(6.0 / (fan_in + fan_out))
    return tf.random_uniform((fan_in, fan_out), minval = low, maxval = high, dtype = tf.float32)
# 定义自编码器类 
class AdditiveGaussianNoiseAutoEncoder(object):
    def __init__(self, n_input, n_hidden, transfer_function = tf.nn.softplus,
        optimizer = tf.train.AdamOptimizer(), scale = 0.1):

        self.n_input = n_input
        self.n_hidden = n_hidden
        self.transfer = transfer_function
        self.scale = tf.placeholder(tf.float32)
        self.training_scale = scale 
        network_weights = self._initialize_weights()
        self.weights = network_weights
        # 定义网络结构 

        # x 为输入,因此要用placeholder进行“占位符”操作
        self.x = tf.placeholder(tf.float32, [None, self.n_input])

        # hidden 是隐含层 ,此自编码器只含一个隐层
        # self.x + scale * tf.random_normal((n_input,)) 是加噪声,scale是噪声系数
        #  hidden = f(w*x1+b), f 是激活函数 
        #  weights w1和b1 分别表示第一层的权值、偏置
        self.hidden = self.transfer(tf.add(tf.matmul(
            self.x + scale * tf.random_normal((n_input,)),
            self.weights['w1']), self.weights['b1']))

        # 定义重构
        self.reconstruction = tf.add(tf.matmul(self.hidden,self.weights['w2']),
            self.weights['b2'])

        # 定义 平方误差为cost 
        # tf.pow()是计算幂 2.0则表示计算平方, tf.subtract是对应元素相减
        self.cost = 0.5 * tf.reduce_sum(tf.pow(tf.subtract(
            self.reconstruction, self.x), 2.0))

        # 定义优化器 对损失 self.cost进行优化
        self.optimizer = optimizer.minimize(self.cost)
        # 全局参数初始化
        init = tf.global_variables_initializer()
        # 创建会话 sess
        self.sess = tf.Session()
        self.sess.run(init)

    # 定义权值初始化函数,AE的权值存放在一个字典里
    # w1采用xavier初始化,其余设置为全0 
    def _initialize_weights(self):
        all_weights = dict()
        all_weights['w1'] = tf.Variable(xavier_init(
            self.n_input, self.n_hidden))
        all_weights['b1'] = tf.Variable(tf.zeros([self.n_hidden],
            dtype = tf.float32))
        all_weights['w2'] = tf.Variable(tf.zeros([self.n_hidden,
            self.n_input], dtype = tf.float32))
        all_weights['b2'] = tf.Variable(tf.zeros([self.n_input],
            dtype = tf.float32))
        return all_weights 

    # 定义 执行一步训练的函数
    def partial_fit(self, X):
        cost, opt = self.sess.run((self.cost, self.optimizer),
            feed_dict = {self.x: X, self.scale: self.training_scale})
        return cost

    # 定义计算总的cost,在评测AE时用到
    # 只让Session执行一个计算图节点 self.cost
    def calc_total_cost(self, X):
        return self.sess.run(self.cost, feed_dict = {
            self.x : X, self.scale: self.training_scale
            })

    # 定义transform函数,
    # 作用是 返回AE隐含层的输出结果
    # 目的是 提供一个接口来获取抽象后的特征
    def transform(self, X):
        return self.sess.run(self.hidden, feed_dic = {
            self.scale: self.training_scale
            })

    # 定义generate函数,将隐含层的输出作为输入,
    # 通过重建层(reconstruction)来复原原始数据
    def generate(self, hidden = None):
        if hidden is None:
            hidden = np.random.normal(size = self.weights['b1'])
        return self.sess.run(self.reconstruction, 
            feed_dict = {self.hidden: hidden})

    # 定义重构函数
    # 包括抽象特征的提取和 通过抽象特征来复原原始数据
    def reconstruct(self, X):
        return self.sess.run(self.reconstruction, fedd_dict = {
            self.x: X, self.scale: self.traning_scale
            })

    # getWeights获取 隐含层权重
    def getWeights(self):
        return self.sess.run(self.weights['w1'])
    def getBiases(self):
        return self.sess.run(self.weights['b1'])

mnist = input_data.read_data_sets('MNIST_data', one_hot = True)

# 定义函数 对 mnist数据进行标准化 (减均值,除以标准差)
# 利用skleran里的 StandardScaler类 
def standard_scale(X_train, X_test):
    preprocessor = prep.StandardScaler().fit(X_train)
    X_train = preprocessor.transform(X_train)
    X_test = preprocessor.transform(X_test)
    return X_train, X_test

# 定义函数 获取随机block数据 
def get_random_block_from_data(data, batch_size):
    start_index = np.random.randint(0, len(data) - batch_size )
    return data[start_index:(start_index + batch_size)]

# 数据标准化
X_train, X_test = standard_scale(mnist.train.images, mnist.test.images)

# 设置基本参数
n_samples = int(mnist.train.num_examples)
training_epochs = 20
batch_size = 128
display_step = 1

# 创建AGN(Additive Gaussian Noise,加性高斯噪声)自编码器实例
autoencoder = AdditiveGaussianNoiseAutoEncoder(n_input = 784,
                    n_hidden = 200,
                    transfer_function = tf.nn.softplus,
                    optimizer = tf.train.AdamOptimizer(learning_rate = 0.001),
                    scale = 0.01)

# 迭代训练
for epoch in range(training_epochs):
    avg_cost = 0.
    total_batch = int(n_samples / batch_size)
    for i in range(total_batch):
        batch_xs = get_random_block_from_data(X_train, batch_size)
        cost = autoencoder.partial_fit(batch_xs)
        avg_cost += cost / n_samples * batch_size
    if epoch % display_step ==0 :
        print('Epoch: ', '%04d' % (epoch+1), 'Cost = ','{:.9f}'.format(avg_cost))

print('Total cost: ' + str(autoencoder.calc_total_cost(X_test)))
此代码主要实现了一个去噪自编码器,噪声采用的AGN(Additive Gaussian Noise,加性高斯噪声)。

自编码器的介绍可以查看如下链接:
http://ufldl.stanford.edu/wiki/index.php/Autoencoders_and_Sparsity
简单讲,自编码器就是对原始数据利用神经网络进行编码,这里的码其实就是隐含层的输出,通过BP算法对神经网络的权值进行修改,最终通过这些权值对原始数据做运算(运算则是编码过程),得到输出(输出则是编好的码) ,而有编码,就有解码。解码呢,就是将编好的码还原成原始数据,这里的还原方法,同样是采用神经网络的某一层。

其中用到Xavier初始化方法是2010年 Xavier提出的,有兴趣可拜读:
《Understanding the Difficult of Training Deep Feedforward Neural Networks》

其中用到的函数总结(续上篇):
1. sess = tf.InteractiveSession() 将sess注册为默认的session
2. tf.placeholder() , Placeholder是输入数据的地方,也称为占位符,通俗的理解就是给输入数据(此例中的图片x)和真实标签(y_)提供一个入口,或者是存放地。(个人理解,可能不太正确,后期对TF有深入认识的话再回来改~~)
3. tf.Variable() Variable是用来存储模型参数,与存储数据的tensor不同,tensor一旦使用掉就消失
4. tf.matmul() 矩阵相乘函数
5. tf.reduce_mean 和tf.reduce_sum 是缩减维度的计算均值,以及缩减维度的求和
6. tf.argmax() 是寻找tensor中值最大的元素的序号 ,此例中用来判断类别
7. tf.cast() 用于数据类型转换
————————————–我是分割线(一)———————————–

  1. tf.random_uniform 生成均匀分布的随机数
  2. tf.train.AdamOptimizer() 创建优化器,优化方法为Adam(adaptive moment estimation,Adam优化方法根据损失函数对每个参数的梯度的一阶矩估计和二阶矩估计动态调整针对于每个参数的学习速率)
  3. tf.placeholder “占位符”,只要是对网络的输入,都需要用这个函数这个进行“初始化”
  4. tf.random_normal 生成正态分布
  5. tf.add 和 tf.matmul 数据的相加 、相乘
  6. tf.reduce_sum 缩减维度的求和
  7. tf.pow 求幂函数
  8. tf.subtract 数据的相减
  9. tf.global_variables_initializer 定义全局参数初始化
  10. tf.Session 创建会话.
  11. tf.Variable 创建变量,是用来存储模型参数的变量。是有别于模型的输入数据的
  12. tf.train.AdamOptimizer (learning_rate = 0.001) 采用Adam进行优化,学习率为 0.001
展开阅读全文

没有更多推荐了,返回首页