导入所需要的包。
import numpy as np
import sklearn.preprocessing as pre
import tensorflow as tf
from tensorflow.example.tutorials.mnist import input_data
xavier initialization
这里是初始化参数的方法,不是初始化参数!
为什么要参数初始化?
如果神经网络的权重初始化太小,那么我们的输入在经过每层计算后,逐渐缩小而难以产生作用,如果权重初始化太大,则计算后将逐渐增大并导致发散和失效。
不适合的权重似的隐含层的输入方差过大,经过 sigmoid
激活函数时离中心较远,导数接近于零,从而导致提督弥散。
* xavier权重初始化 *
xavier权重初始化可以减少梯度弥散,使输入可以传递的更深。
xavier根据某一层网络的输入、输出节点数量自动调整最合适的分布,让权重满足0均值,同时方差为 2nin+nout 2 n i n + n o u t ,分布可以使用均匀分布或者高斯分布。
下面我们创建一个 ⟮−6nin+nout−−−−−−√,6nin+nout−−−−−−√⟯ ⟮ − 6 n i n + n o u t , 6 n i n + n o u t ⟯ 范围内的均匀分布,而它的方差根据 D(x)=(max−min)2/12 D ( x ) = ( m a x − m i n ) 2 / 12 正好等于 2nin+nout 2 n i n + n o u t 。
# fan_in:输入节点的数量,fan_out: 输出节点的数量
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.unifom((fan_in, fan_out), minval=low, maxval=high, dtype=tf.float32)
参数解释:
n_input: 输入层个数 n_hidden: 隐含层个数 transfer_function: 隐含层的激活函数,设为softplus
optimizer:优化器,设为Adam scale:高斯噪声系数,设为0.1
class内的scale参数设为一个placeholder 权重初始化使用定义的init_weights函数
这里我们只定义了一层隐含层,可以继续添加!
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
weights = self.init_weights()
self.weights = weights
init_weights
w1经过 xavier_init 函数初始化,传入输入层和隐含层的节点数,xavier会返回一个适合 softplus 等激活函数的权重初始分布,偏置 b1
全部置为0即可。对于输出层,因为没有使用激活函数,w2、b2 全部初始化为0。
def init_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))
sll_weights['b2'] = tf.Variable(tf.zeros([n_input], dtype=tf.float32))
return all_weights
self.x
w1 * x + b
,然后带入激活函数 transfer
中计算。其中 x
为输入加上噪声即 self.x + scale * tf.random_normal({n_input,})
。self.x = tf.placeholder(tf.float, [None, self.n_input])
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['b3'])
使用平方误差函数(SSE)
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)
cost
及执行进一步训练的函数 partial_fit
功能:触发训练操作,对一个
batch
的数据进行训练并计算当前的损失!
函数里只需让Session执行两个计算图的节点,分别是损失 cost
和训练过程 optimizer
,输入的 feed_dict
包括输入数据 x
、噪声的系数 scale
。
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
calc_total_cost
自编码器训练完后,用来在测试集数据上对数据模型进行评测
与 partial_fit
函数不同,这里只让Session执行一个计算图节点 self.cost
,传入的参数和上一个函数一样。
def cal_total_cost(self, x):
return self.sess.run(self.cost, feed_dict={self.x: x,
self.scale: self.training.scale})
transform
函数功能:返回自编码器隐含层的输出结果。隐含层的主要功能是学习处数据中的高级特征,该函数目的是提供一个接口来得到经过隐含层抽象后的特征!
def transform(self, x):
return self.sess.run(self.hidden, feed_dict={self.x: x,
self.scale: self.training_scale})
generate
函数功能:返回自编码器重构层的输出结果。重构层的主要功能是将隐含层提取的高阶特征复原为原输入数据。
def generaate(self, hidden = None):
if hidden == None:
hidden = np.random.normal(size = self.weights['b1'])
return self.sess.run(self.reconstruction, feed_dict={self.hidden: hidden})
reconstruct
函数功能:完整运行 输入数据 → → 提取高级特征 → → 复原数据 ,即同时包括
transform
、generate
函数。
def reconstruct(self, x):
return self.sess.run(self.reconstruction, feed_dict={self.x: x,
self.scale: self.training_scale})
功能:得到隐含层的权重
w1
和偏置b1
!
def getWeight(self):
return self.sess.run(self.weights['w1'])
def getBias(self):
return self.sess.run(self.weights['b1'])
去噪编码器类已经定义完成,包括对神经网络的设计、权重的初始化以及几个成员函数。
我们使用TensorFlow提供的 MNIST
数据集进行测试。
input_data.read_data_sets('MNIST_data', one_hot=True)
即将数据变为均值为0, 便准差为1的分布。将数据减去均值,然后除以方差。
使用 sklearn.preprocessing
的 StandardScaler
类现在训练集上进行 fit
,再将这个 Scale
用在训练数据和测试数据上。保证训练数据和测试数据使用同一个 Scale
,使得后面模型处理数据时的一致性。
def Standard_scale(x_train, x_test):
preprocessor = prep.Stap yndardScale().fit(x_train)
x_train = preprocessor.transform(x_train)
x_test = preprocessor.transform(x_test)
retutn x_train, x_test
batch_size
大小的数据函数不放回的每次抽样!
python
def get_random_block_from_data(data, batch_seze):
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:总训练样本数 training_epoches:最大训练轮数 batch_size:批数据样本大小,设为128
n_samples = int(mnist.train.num_examples)
training_epoches = 20
batch_size = 128
display_step = 1
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_size):
batch_xs = get_random_block_from_data(x_train, batch_size)
cost = autoencoder.partial_fit(batch_xs)
avg_cost += cost / n_sample * batch_size
if epoch % display_step == 0:
print("Epoch:", '%04d' %(epoch + 1), "cost=", ":.9f".format(avg_cost))
使用平方误差和来
print("total cost:" + autoencoder.cal_total_cost(x_test))
去噪自编码器的TensorFlow实现完成。