《tensorflow 实战》笔记一:实现自编码器及多层感知机

1.自编码器

顾名思义,即可以使用自身的高阶特征编码自己。实际上也是一种神经网络,输入和输出是一致的。
借助稀疏编码的思想,目标是使用稀疏的一些高阶特征特征重新组合来重构自己。
特点很明显:
1)期望输入输出一致;
2)希望使用高阶特征来重构自己,不只是复制像素点。

2.自编码器–tensorflow实现

我们的自编码器会使用到一种参数初始化方法:xavier initialization(特点是会根据某一层网络的输入输出节点数量自动调整最适合的分布)
初始化如果太小:不会在传递过程中起作用
初始化如果太大:会在过程中被放大,然后发散失效
xavier 能够让权重初始化的不大不小,让权重满足0均值

import tensorflow as tf
import numpy as np
import sklearn.preprocessing as prep
from tensorflow.examples.tutorials.mnist import input_data

def xavier_init(fan_in,fan_out,constant = 1):
    low = -constant * np.sqrt(6.0/(fan_in + fan_out))
    high = -low
    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):
                  #输入变量数,隐含层节点数,隐含层激活函数,默认softplus, 优化器,默认AdamOptimizer, 高斯噪声系数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
        #定义网络结构
        self.x = tf.placeholder(tf.float32,[None,self.n_input])
        #给输入加噪声,然后乘以权重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.hidden乘上权重w2,再加上输出层的偏置b2
        self.reconstruction = tf.add(tf.matmul(self.hidden,self.weights['w2']),self.weights['b2'])

        self.cost = 0.5 * tf.reduce_sum(tf.pow(tf.subtract(self.reconstruction,self.x),2.0))
        self.optimizer = optimizer.minimize(self.cost)
        init = tf.global_variables_initializer()
        self.sess = tf.Session()
        self.sess.run(init)
    def _initialize_weights(self):#w1需要xavier进行初始化,其他全部初始化为0
        all_weights = dict()#创建字典,类似map
        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,以及执行一步训练的函数partial_fit
        cost,opt = self.sess.run((self.cost, self.optimizer),feed_dict = {self.x: X, self.scale: self.training_scale})
        return cost

    def calc_total_cost(self,X):#训练结束之后进行测试
        return self.sess.run(self.cost,feed_dict = {self.x:X,self.scale:self.training_scale})

    def transform(self,X):#返回自编码器隐含层的输出结果:提供一个接口来获取抽象后的特征,自编码器的隐含层的最主要功能就是学习出数据中的高阶特征
        return self.sess.run(self.hidden,feed_dict = {self.x:X,self.scale:self.training_scale})

    def generate(self,hidden=None):#将隐含层的输出结果作为输入,通过之后的重建层将提取到的高阶特征复原为原始数据
        #这个接口和transform正好是自编码器的两个部分,这里的generate接口是后半部分,将高阶特征复原为原始数据的部分,(为什么呢?)
        if hidden is None:
            hidden = np.random.normal(size = self.weights["b1"])
        return self.sess.run(self.reconstruction,feed_dict = {self.hidden:hidden})

    def reconstruction(self,X):#整体运行一遍复原过程,包括提取高特征值和通过高阶特征复原数据,即包括transform和generate两块,输入数据是原始数据,输出是复原后的数据
        return self.sess.run(self.reconstruction,feed_dict = {self.x:X,self.scale:self.training_scale})

    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)

def standard_scale(X_train,X_test):#定义一个对训练,测试数据进行标准化处理的函数,标准化即让数据变成0均值,且标准差为1的分布
    prepeocessor = prep.StandardScaler().fit(X_train)
    X_train = prepeocessor.transform(X_train)
    X_test = prepeocessor.transform(X_test)
    return X_train,X_test

def get_random_block_from_data(data,batch_size):#获取随机block数据的函数:取一个从0到len(data)-batch_size之间的随机整数,再以这个随机数作为block的起始位置,
    #然后顺序取到一个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#每隔一轮显示一次损失

#创建一个自编码器的实例,定义模型节点数n_input=784,n_hidden=200,隐含层的激活函数为softplus,噪声系数scale为0.01
autoencoder = AdditiveGaussianNoiseAutoencoder(n_input = 784,n_hidden=200,transfer_function=tf.nn.softplus,optimizer=tf.train.AdamOptimizer(lerning_rate = 0.001),scale = 0.01)
#使用的是不放回抽样,并不能保证每个样本都被抽到并参与训练
#在每一个batch的循环中,先使用get_random_block_from_data函数随机抽取一个block的数据,然后使用成员函数fit训练这个batch数据,并计算当前的cost
#最后将当前的cost整合到avg_cost中.每一轮迭代后,显示当前的迭代数和这一轮迭代的平均cost
## 在最后一轮迭代时,cost大约为70000
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)))

实现自编码器和实现单隐含层的神经网络差不多,只不过在数据输入时做了标准化,并加上了高斯噪声。
同时我们的输出结果不是数字分类,而是复原的数据,因此不需要标注过的数据进行监督训练。
自编码作为一种无监督学习的方法,目的不是分类,而是提取其中最有用,最频繁出现的高阶特征

3.多层感知机简介

Dropout实质上等于创造出了很多新的随机样本,通过增大样本量、减少特征数量来防止过拟合,Dropout其实也算是一种bagging方法。我们理解成每次丢弃结点数据是对特征的一种采样,相当于我们训练了一个ensemble的神经网络模型,对每个样本都做特征采样,只不过没有训练多个神经网络模型。
ReLU想对于sigmoid的主要变化:
1)单侧抑制
2)相对宽阔的兴奋边界
3)稀疏激活性

4.tensorflow实现多层感知机

import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data

mnist = input_data.read_data_sets('MNIST_data/',one_hot=True)
sess = tf.InteractiveSession()

#-------------------------第一步:定义算法公式--------------------
in_units = 784 #输入节点数
h1_units = 300 #隐含层的输出节点数
#将w1初始化为截断的正态分布,其标准差为0.1,直接一步即可实现truncated_normal,为了打破完全对称,并且避免0梯度
w1 = tf.Variable(tf.truncated_normal([in_units,h1_units],stddev = 0.1))
b1 = tf.Variable(tf.zeros([h1_units]))
w2 = tf.Variable(tf.zeros([h1_units,10]))
b2 = tf.Variable(tf.zeros([10]))

#drop_out比率keep_prob是不一样的,通常在训练时小于1,而在预测时等于1,所以也把dropout的比率作为计算图的输入,并定义一个placeholder
x = tf.placeholder(tf.float32,[None,in_units])
keep_prob = tf.placeholder(tf.float32)#dropout有一部分会保留,剩下的被置为0,保留的比例为keep_prob,在训练时应该小于1,在预测时应该等于1

hidden1 = tf.nn.relu(tf.matmul(x,w1) + b1)
hidden1_drop = tf.nn.dropout(hidden1,keep_prob)
y = tf.nn.softmax(tf.matmul(hidden1_drop,w2) + b2)
#-------------------第二步:定义损失函数,并选择优化器来最小化loss---------
y_ = tf.placeholder(tf.float32,[None,10])
cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y),reduction_indices=[1]))
train_step = tf.train.AdamOptimizer(0.3).minimize(cross_entropy)
#-------------------------------------第三步,训练步骤---------------------------
tf.global_variables_initializer().run()
for i in range(4000):#batch为4000个
    batch_xs,batch_ys = mnist.train.next_batch(100)#每个batch包含100条样本
    train_step.run({x:batch_xs,y_:batch_ys,keep_prob:0.75})#设定了keep_prob为0.75
#------------------------------- 第四步,对模型进行准确率评测--------------------
correct_predicition = tf.equal(tf.argmax(y,1),tf.argmax(y_,1))#tf.equal 返回的是bool值
#tf.argmax(y,1)先求预测概率最大的那一个,tf.argmax(y_,1)是样本的真实数字类别,然后判断是否相等
accuracy = tf.reduce_mean(tf.cast(correct_predicition,tf.float32))#cast将输出的bool值转换为float值,再求平均
#将特征和label输入评测流程accuracy,计算准确率,再将结果打印
print(accuracy.eval({x:mnist.test.images,y_:mnist.test.labels,keep_prob:1.0}))#keep_prob在预测时等于1

猜你喜欢

转载自blog.csdn.net/acbattle/article/details/80329007