深度学习入门实践_十行搭建手写数字识别神经网络
2018-03-01 17:30
1051 查看
本次实践是基于李宏毅老师ML课程中“Hello world” of deep learning章节进行的实验探究。课程中李宏毅老师使用的是keras 2.0.1。可以参考中文文档自行安装。
参考链接:
Keras中文文档
李宏毅老师“Hello world” of deep learning PPT
1. Keras可以看做TensorFlow的接口,用Keras就相当于在用TensorFlow。
2. Keras集成了TensorFlow的许多复杂操作,使用起来更简洁。
3. 入门直接上手TensorFlow比较复杂。
但是由于网络限制(不知道是不是因为wall,试了几次都没成功),就直接去官网下了数据,参见mnist数据集下载地址。
该数据下载后得到的是idx格式数据,具体处理方法参考了这篇博客使用Python解析MNIST数据集(IDX文件格式),测试可用的源码如下(规则在注释里写得很详细),该文件保存为load_data.py,在后文中会直接调用。
到此,我们得到了训练和测试网络所需要的数据。
李老师这个在课堂上两分钟构建出的三层网络达到的效果如下:
可以看到正确率是0.1135,效果并不太好。
- 激励函数由sigmoid改为relu
- loss function由mse改为categorical_crossentropy
- 增加了Dropout,防止过拟合
改动后构建模型代码
得到的结果
得到了比较好的测试结果。其中,最主要的还是激励函数影响(转自知乎Begin Again的回答)
1. 采用sigmoid等函数,算激活函数时(指数运算),计算量大,反向传播求误差梯度时,求导涉及除法,计算量相对大,而采用Relu激活函数,整个过程的计算量节省很多。
2. 对于深层网络,sigmoid函数反向传播时,很容易就会出现梯度消失的情况(在sigmoid接近饱和区时,变换太缓慢,导数趋于0,这种情况会造成信息丢失,从而无法完成深层网络的训练。
3. Relu会使一部分神经元的输出为0,这样就造成了网络的稀疏性,并且减少了参数的相互依存关系,缓解了过拟合问题的发生。
最后贴上完整代码
参考链接:
Keras中文文档
李宏毅老师“Hello world” of deep learning PPT
一张图解释为什么要用Keras
1. Keras可以看做TensorFlow的接口,用Keras就相当于在用TensorFlow。
2. Keras集成了TensorFlow的许多复杂操作,使用起来更简洁。
3. 入门直接上手TensorFlow比较复杂。
数据准备
课程中获取数据的方法是从库中直接load_datafrom keras.datasets import mnist (x_train, y_train), (x_test, y_test) = mnist.load_data()
但是由于网络限制(不知道是不是因为wall,试了几次都没成功),就直接去官网下了数据,参见mnist数据集下载地址。
该数据下载后得到的是idx格式数据,具体处理方法参考了这篇博客使用Python解析MNIST数据集(IDX文件格式),测试可用的源码如下(规则在注释里写得很详细),该文件保存为load_data.py,在后文中会直接调用。
# encoding: utf-8 """ 对MNIST手写数字数据文件转换为bmp图片文件格式。 数据集下载地址为http://yann.lecun.com/exdb/mnist。 相关格式转换见官网以及代码注释。 ======================== 关于IDX文件格式的解析规则: ======================== THE IDX FILE FORMAT the IDX file format is a simple format for vectors and multidimensional matrices of various numerical types. The basic format is magic number size in dimension 0 size in dimension 1 size in dimension 2 ..... size in dimension N data The magic number is an integer (MSB first). The first 2 bytes are always 0. The third byte codes the type of the data: 0x08: unsigned byte 0x09: signed byte 0x0B: short (2 bytes) 0x0C: int (4 bytes) 0x0D: float (4 bytes) 0x0E: double (8 bytes) The 4-th byte codes the number of dimensions of the vector/matrix: 1 for vectors, 2 for matrices.... The sizes in each dimension are 4-byte integers (MSB first, high endian, like in most non-Intel processors). The data is stored like in a C array, i.e. the index in the last dimension changes the fastest. """ import numpy as np import struct import matplotlib.pyplot as plt # 训练集文件 train_images_idx3_ubyte_file = './data/train-images-idx3-ubyte' # 训练集标签文件 train_labels_idx1_ubyte_file = './data/train-labels-idx1-ubyte' # 测试集文件 test_images_idx3_ubyte_file = './data/t10k-images-idx3-ubyte' # 测试集标签文件 test_labels_idx1_ubyte_file = './data/t10k-labels-idx1-ubyte' def decode_idx3_ubyte(idx3_ubyte_file): """ 解析idx3文件的通用函数 :param idx3_ubyte_file: idx3文件路径 :return: 数据集 """ # 读取二进制数据 bin_data = open(idx3_ubyte_file, 'rb').read() # 解析文件头信息,依次为魔数、图片数量、每张图片高、每张图片宽 offset = 0 fmt_header = '>iiii' magic_number, num_images, num_rows, num_cols = struct.unpack_from(fmt_header, bin_data, offset) #print('魔数:%d, 图片数量: %d张, 图片大小: %d*%d' % (magic_number, num_images, num_rows, num_cols)) # 解析数据集 image_size = num_rows * num_cols offset += struct.calcsize(fmt_header) fmt_image = '>' + str(image_size) + 'B' images = np.empty((num_images, num_rows, num_cols)) for i in range(num_images): #if (i + 1) % 10000 == 0: #print('已解析 %d' % (i + 1) + '张') images[i] = np.array(struct.unpack_from(fmt_image, bin_data, offset)).reshape((num_rows, num_cols)) offset += struct.calcsize(fmt_image) return images def decode_idx1_ubyte(idx1_ubyte_file): """ 解析idx1文件的通用函数 :param idx1_ubyte_file: idx1文件路径 :return: 数据集 """ # 读取二进制数据 bin_data = open(idx1_ubyte_file, 'rb').read() # 解析文件头信息,依次为魔数和标签数 offset = 0 fmt_header = '>ii' magic_number, num_images = struct.unpack_from(fmt_header, bin_data, offset) #print('魔数:%d, 图片数量: %d张' % (magic_number, num_images)) # 解析数据集 offset += struct.calcsize(fmt_header) fmt_image = '>B' labels = np.empty(num_images) for i in range(num_images): #if (i + 1) % 10000 == 0: # print('已解析 %d' % (i + 1) + '张') labels[i] = struct.unpack_from(fmt_image, bin_data, offset)[0] offset += struct.calcsize(fmt_image) return labels def load_train_images(idx_ubyte_file=train_images_idx3_ubyte_file): """ TRAINING SET IMAGE FILE (train-images-idx3-ubyte): [offset] [type] [value] [description] 0000 32 bit integer 0x00000803(2051) magic number 0004 32 bit integer 60000 number of images 0008 32 bit integer 28 number of rows 0012 32 bit integer 28 number of columns 0016 unsigned byte ?? pixel 0017 unsigned byte ?? pixel ........ xxxx unsigned byte ?? pixel Pixels are organized row-wise. Pixel values are 0 to 255. 0 means background (white), 255 means foreground (black). :param idx_ubyte_file: idx文件路径 :return: n*row*col维np.array对象,n为图片数量 """ return decode_idx3_ubyte(idx_ubyte_file) def load_train_labels(idx_ubyte_file=train_labels_idx1_ubyte_file): """ TRAINING SET LABEL FILE (train-labels-idx1-ubyte): [offset] [type] [value] [description] 0000 32 bit integer 0x00000801(2049) magic number (MSB first) 0004 32 bit integer 60000 number of items 0008 unsigned byte ?? label 0009 unsigned byte ?? label ........ xxxx unsigned byte ?? label The labels values are 0 to 9. :param idx_ubyte_file: idx文件路径 :return: n*1维np.array对象,n为图片数量 """ return decode_idx1_ubyte(idx_ubyte_file) def load_test_images(idx_ubyte_file=test_images_idx3_ubyte_file): """ TEST SET IMAGE FILE (t10k-images-idx3-ubyte): [offset] [type] [value] [description] 0000 32 bit integer 0x00000803(2051) magic number 0004 32 bit integer 10000 number of images 0008 32 bit integer 28 number of rows 0012 32 bit integer 28 number of columns 0016 unsigned byte ?? pixel 0017 unsigned byte ?? pixel ........ xxxx unsigned byte ?? pixel Pixels are organized row-wise. Pixel values are 0 to 255. 0 means background (white), 255 means foreground (black). :param idx_ubyte_file: idx文件路径 :return: n*row*col维np.array对象,n为图片数量 """ return decode_idx3_ubyte(idx_ubyte_file) def load_test_labels(idx_ubyte_file=test_labels_idx1_ubyte_file): """ TEST SET LABEL FILE (t10k-labels-idx1-ubyte): [offset] [type] [value] [description] 0000 32 bit integer 0x00000801(2049) magic number (MSB first) 0004 32 bit integer 10000 number of items 0008 unsigned byte ?? label 0009 unsigned byte ?? label ........ xxxx unsigned byte ?? label The labels values are 0 to 9. :param idx_ubyte_file: idx文件路径 :return: n*1维np.array对象,n为图片数量 """ return decode_idx1_ubyte(idx_ubyte_file) def run(): train_images = load_train_images() train_labels = load_train_labels() test_images = load_test_images() test_labels = load_test_labels() # 查看前十个数据及其标签以读取是否正确 for i in range(10): print(train_labels[i]) plt.imshow(train_images[i], cmap='gray') plt.show() print('done') if __name__ == '__main__': run()
数据预处理
导入相关包依赖及预处理函数import numpy as np from keras.models import Sequential from keras.layers.core import Dense, Dropout, Activation from keras.layers import Conv2D, MaxPooling2D, Flatten from keras.optimizers import SGD, Adam from keras.utils import np_utils from load_data import * #clean data def load_dataset(): x_train, y_train = load_train_images(), load_train_labels() x_test, y_test = load_test_images(), load_test_labels() number = 60000 x_train, y_train = x_train[0:number], y_train[0:number] x_train = x_train.reshape(number, 28*28) x_test = x_test.reshape(x_test.shape[0], 28*28) x_train, x_test = x_train.astype('float32'), x_test.astype('float32') y_train, y_test = np_utils.to_categorical(y_train, 10), np_utils.to_categorical(y_test, 10) x_train, x_test = x_train / 255, x_test / 255 return (x_train, y_train), (x_test, y_test)
到此,我们得到了训练和测试网络所需要的数据。
课程中搭建的网络及训练结果
(x_train, y_train), (x_test, y_test) = load_dataset() model = Sequential() #搭建三层网络 model.add(Dense(input_dim=28*28,units=633,activation='sigmoid')) model.add(Dense(unit=633,activation='sigmoid')) model.add(Dense(unit=10,activation='softmax')) model.compile(loss='mse',optimizer=SGD(lr=0.1),metrics=['accuracy']) model.fit(x_train,y_train,batch_size=100,epochs=20) result = model.evaluate(x_test,y_test) print('Test loss:', result[0]) print('Accuracy:', result[1])
李老师这个在课堂上两分钟构建出的三层网络达到的效果如下:
可以看到正确率是0.1135,效果并不太好。
对网络参数调整后的模型
改动地方主要为:- 激励函数由sigmoid改为relu
- loss function由mse改为categorical_crossentropy
- 增加了Dropout,防止过拟合
改动后构建模型代码
(x_train, y_train), (x_test, y_test) = load_dataset() model = Sequential() model.add(Dense(input_dim=28*28,units=700,activation='relu')) model.add(Dropout(0.2)) model.add(Dense(units=700,activation='relu')) model.add(Dropout(0.2)) model.add(Dense(units=10,activation='softmax')) model.compile(loss='categorical_crossentropy',optimizer=SGD(lr=0.1),metrics=['accuracy']) model.fit(x_train,y_train,batch_size=100,epochs=20,validation_split=0.05) result = model.evaluate(x_test,y_test) print('Finish..') print('Test loss:', result[0]) print('Accuracy:', result[1])
得到的结果
得到了比较好的测试结果。其中,最主要的还是激励函数影响(转自知乎Begin Again的回答)
1. 采用sigmoid等函数,算激活函数时(指数运算),计算量大,反向传播求误差梯度时,求导涉及除法,计算量相对大,而采用Relu激活函数,整个过程的计算量节省很多。
2. 对于深层网络,sigmoid函数反向传播时,很容易就会出现梯度消失的情况(在sigmoid接近饱和区时,变换太缓慢,导数趋于0,这种情况会造成信息丢失,从而无法完成深层网络的训练。
3. Relu会使一部分神经元的输出为0,这样就造成了网络的稀疏性,并且减少了参数的相互依存关系,缓解了过拟合问题的发生。
最后贴上完整代码
#encoding:utf-8
import numpy as np from keras.models import Sequential from keras.layers.core import Dense, Dropout, Activation from keras.layers import Conv2D, MaxPooling2D, Flatten from keras.optimizers import SGD, Adam from keras.utils import np_utils from load_data import * #clean data def load_dataset(): x_train, y_train = load_train_images(), load_train_labels() x_test, y_test = load_test_images(), load_test_labels() number = 60000 x_train, y_train = x_train[0:number], y_train[0:number] x_train = x_train.reshape(number, 28*28) x_test = x_test.reshape(x_test.shape[0], 28*28) x_train, x_test = x_train.astype('float32'), x_test.astype('float32') y_train, y_test = np_utils.to_categorical(y_train, 10), np_utils.to_categorical(y_test, 10) x_train, x_test = x_train / 255, x_test / 255 return (x_train, y_train), (x_test, y_test)
def main():
(x_train, y_train), (x_test, y_test) = load_dataset()
#以下为网络搭建部分,不超过10行,简单易上手
model = Sequential()
model.add(Dense(input_dim=28*28,units=700,activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(units=700,activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(units=10,activation='softmax'))
model.compile(loss='categorical_crossentropy',optimizer=SGD(lr=0.1),metrics=['accuracy'])
model.fit(x_train,y_train,batch_size=100,epochs=20,validation_split=0.05)
result = model.evaluate(x_test,y_test)
#输出结果
print('Finish..')
print('Test loss:', result[0])
print('Accuracy:', result[1])
if __name__ == '__main__':
main()
相关文章推荐
- 神经网络与深度学习笔记——第1章 使用神经网络识别手写数字
- Python实现深度学习之-神经网络识别手写数字(更新中,更新日期:2017-07-12)
- 深度学习与神经网络实战:快速构建一个基于神经网络的手写数字识别系统
- 深度学习-传统神经网络使用TensorFlow框架实现MNIST手写数字识别
- 手把手入门神经网络系列(2)_74行代码实现手写数字识别
- 深度学习与TensorFlow实战(七)全连接网络基础—真实图片输出手写数字识别准确率
- 手把手入门神经网络系列(2)_74行代码实现手写数字识别
- 神经网络与深度学习 1.6 使用Python实现基于梯度下降算法的神经网络和MNIST数据集的手写数字分类程序
- 手把手入门神经网络系列(2)_74行代码实现手写数字识别
- 深度学习实践系列(3)- 使用Keras搭建notMNIST的神经网络
- 手把手入门神经网络系列(2)_74行代码实现手写数字识别
- 手把手入门神经网络系列(2)_74行代码实现手写数字识别
- C++从零实现深度神经网络之六——实战手写数字识别(sigmoid和tanh)
- 【深度学习】笔记2_caffe自带的第一个例子,Mnist手写数字识别代码,过程,网络详解
- 用MXnet入门实战深度学习之一:安装GPU版mxnet并跑一个MNIST手写数字识别
- 用MXnet入门实战深度学习之一:安装GPU版mxnet并跑一个MNIST手写数字识别
- 神经网络与深度学习 1.3 神经网络的架构 1.4 一个简单的分类手写数字的网络架构
- 神经网络与深度学习 使用Python实现基于梯度下降算法的神经网络和自制仿MNIST数据集的手写数字分类可视化程序 web版本
- 用MXnet入门实战深度学习之一:安装GPU版mxnet并跑一个MNIST手写数字识别
- 用MXnet入门实战深度学习之一:安装GPU版mxnet并跑一个MNIST手写数字识别