MNIST介绍
MNIST是在机器学习领域中的一个经典问题。该问题解决的是把28x28像素的灰度手写数字图片识别为相应的数字,其中数字的范围从0到9.
首先需要下载数据集 LeCun给出了下载地址
这里有非常详细的MNIST介绍以及可视化的图片演示Chris Olah’s visualizations of MNIST.
文件 | 内容 |
---|---|
train-images-idx3-ubyte.gz | training set images (9912422 bytes) |
train-labels-idx1-ubyte.gz | training set labels (28881 bytes) |
t10k-images-idx3-ubyte.gz | test set images (1648877 bytes) |
t10k-labels-idx1-ubyte.gz | test set labels (4542 bytes) |
TensorFlow直接提供了MNIST的下载
1 | from tensorflow.examples.tutorials.mnist import input_data |
先查看MNIST数据集的情况
1 | print(mnist.train.images.shape,mnist.train.labels.shape) # 训练集 |
- 使用Softmax Regression实现一个简单的机器学习
1 | from tensorflow.examples.tutorials.mnist import input_data |
这个可以看成是一个没有隐藏层的最浅的神经网络,一共有4步:
- 定义算法公式,也就是神经网络forward时的计算
- 定义loss,选定优化器,并制定优化器优化loss
- 迭代地对数据进行训练
- 在测试集或是验证集上对准确率进行评测
TensorFlow实现自编码器
自编码器
传统的机器学习的任务很大程度上依赖于特征工程。但是特征工程往往非常耗时耗力,而且在图像、视频、语音中提取到有效特征更难。而深度学习可以大大缓解机器学习模型对特征工程的依赖。深度学习在早期一度被认为是一种无监督的特征学习,模仿了人脑的对特征逐层抽象提取的过程。
早年有学者研究稀疏编码时,收集了大量的黑白风景照片,并从中提取了许多16*16的图像碎片。他们发现机会所有的图像碎片都可以由64种正交的边组合得到。还有学者同事发现声音也存在这种情况。这就是特征的稀疏表达,使用少量的基本特征组合拼装得到更高层抽象的特征。通常我们需要多层的神经网络,对于每一层神经网络来说,前一层的输出都是为加工的像素,而这一层则是对像素进行加工组织成更高阶的特征。
自编码器,即可以使用自身的高阶特征编码自己。自编码器其实也是一种神经网络,它的输入和输入是一致的,它借助稀疏编码的思想,目标是使用稀疏的一些高阶特征重构自己。因此,它的特点非常明显:第一,期望输入/输出一致;第二,希望使用高阶特征来重构自己,而不只是复制像素点。
Hinton 在
Reducing the dimensionality of data with neural networks
论文中讲解了使用自编码器对数据进行降维的方法。Hinton还提出了基于深度信念网络(Deep Belief Networks,DBN)可使用无监督的逐层训练的贪心算法,为训练很深的网络提供了一个可行的方案:很难直接训练极深的网络,但是可以用无监督的逐层训练提取特征,将网络的权重初始化到一个比较好的位置,辅助后面的监督训练。这个思想是相当于学习一个恒等式y=x,自编码器的输入节点和输出节点的数量是一致的,但是如果只是单纯地逐个重复输入节点则没有意义,所以希望使用少量稀疏的高阶特征来重构输入,所以可以加入几种限制。(1) 如果限制中间隐含层节点的数量,比如让中间隐含层节点的数量小与输入/输出节点的数量,就相当于一个降维的过程。此时如果再给中间隐含层的权重加一个L1正则,则可以通过惩罚系数控制隐含节点的稀疏程度,惩罚系数越大,学到的特征组合越稀疏。至于为什么L1正则化可以增加稀疏性,请看某大神博客有数学推导。
(2) 如果给数据加入噪声,那么就构成了去噪自编码器,我们将从噪声中学习出数据的特征。同样,我们也不可能完全复制节点,完全复制并不能去除我们添加的噪声,无法完全复原数据。所以唯有学习数据频繁出现的模式和结构,将无规律的噪声略去,才可以复原数据。去噪自编码器最常用的噪声是加性高斯噪声。
TensorFlow实现去噪自编码器
刚刚用Linux配置sklearn简直要疯。顺带提一下坑的地方,import sklearn一直提示没找到 _bz2 ,查了好久是要先安装bz2的模块
yum install bzip2-devel
然后重新编译python3.6:./configure
make all
make install
make clean
make distclean
1 | import numpy as np |
xavier initialization 是一种参数初始化方法。
Xavier在caffe早期版本频繁使用 它的特点是根据某一层网络的输入输出节点数量自动的调整最合适的分布。
Yoshua Bengio 在一篇论文中指出,如果学习模型的权重初始化得太小,
那么信号将在每层间传递时逐渐缩小而难以产生作用,如果初始化的太大,那信号将在每层间的传递时逐渐放大而导致发散和失效。
而Xavier初始化就是让初始化得到不大不小的值。
从数学上就是使权重0均值,方差为$2 / (n_{in}+n_{out})$,分布可以用均匀分布或者高斯分布。
这里创建了一个$(- \sqrt{6 \over {n_{in}+n_{out}}},\sqrt{6 \over {n_{in}+n_{out}}})$ 范围内的均匀分布
它的方差根据公式$D(X)={(max-min)}^2 / 12$刚好等于$2 / (n_{in}+n_{out})$
因此这里实现了标准均匀分布的Xavier初始化器,其中fan_in是输入节点的数量,fan_out是输出节点的数量
1 | def xavier_init(fan_in, fan_out, constant=1): |
1 | n_input, 输入变量数 |
1 | class AdditiveGausssianNoiseAutoencoder(object): |
1 | 定义网络结构 |
1 | self.x = tf.placeholder(tf.float32, [None, self.n_input]) |
1 | 定义自编码器的损失函数 |
1 | self.cost = 0.5 * tf.reduce_sum( |
1 | 创建初始化函数 |
1 | def _initialize_weights(self): |
1 | 定义计算损失及执行一步训练的函数partial_fit |
1 | def partial_fit(self, X): |
1 | 只求损失cost的函数 |
1 | def calc_total_cost(self, X): |
1 | 定义了transform函数,返回自编码器隐含层的输出结果 |
1 | def transform(self, X): |
1 | 再定义generate函数,它将隐含层的输出结果作为输入,通过之后的重建层将提取到的高阶特征复原为原始数据 |
1 | def generate(self, hidden=None): |
1 | 定义reconstruct |
1 | def reconstruct(self, X): |
1 | 获取隐含层的权重和偏差 |
1 | def getWeights(self): |
1 | 加载MNIST数据集 |
1 | mnist = input_data.read_data_sets('data/', one_hot=True) |
1 | 对训练测试数据标准化的函数 |
1 | def standard_scale(X_train, X_test): |
1 | 定义一个获取随机block数据的函数: |
1 | def get_random_block_from_data(data, batch_size): |
1 | 使用之前定义的standard_scale函数对训练集、测试集进行标准化变换 |
1 | X_train, X_test = standard_scale(mnist.train.images, mnist.test.images) |
1 | 创建一个AGN自编码器的实例 |
1 | autoencoder = AdditiveGausssianNoiseAutoencoder( |
1 | 开始训练过程 |
1 | for epoch in range(training_epochs): |
1 | 最终的输出结果 我这里大约需要2分多钟 |
TensorFlow实现多层感知器
1 | import tensorflow as tf |