入门
照理讲,我们应该先了解『神经网络』(Neural Network)概念,再谈如何写程式,但是,概念介绍内容有点硬,为了提高学习兴趣,避免一开始就搞一堆数学公式,造成读者跑光光,所以,还是柿子挑软的吃,先从简单的开始,与 Neural Network 先培养感情,如果您是条硬汉,可以等看完下一篇后,再回头看这一篇。
我们就先来写一个程序,目标是『辨识阿拉伯数字(0~9)』。
开发环境建置
首先是选择开发环境,一般而言,Python 及 R 都有很好的支援及大量的函数库(Library/Toolbox),而 Python 的框架较易于系统整合(Web、Mobile),因此我选择 Python,但支援 Python 的 Neural Network 框架(Framework)也很多,参见下图,要选择哪一个呢?
图. Machine Learning 框架(Framework)GitHub评比,资料来源:【AI关键技术】三大热门深度学习框架新进展。
其中,TensorFlow 网路声量最高,因此,我们採用它作为程式开发的基础,Keras 则是支援TensorFlow的更高阶函数库(Meta Framework),可以用很简洁的程式码完成一个 Neural Network 模型,非常适合入门学习,因此我们就从 Keras 开始学起。
首先我们要建构开发环境,笔者以 Windows 环境为例,依序安装以下软体:
- 安装 Anaconda: 它包含 Python 及常用的套件(Packages),例如NumPy、Pandas等矩阵运算的套件,Python V2 与 V3 不相容,我们选 V3,除非你以前曾大量使用 V2。
- 安装 Tensorflow:可以选择CPU或GPU版,安装CPU版,直接在 DOS 下,输入 pip install tensorflow。
- 安装 Keras:在 DOS 下,输入 pip install keras。
就是这麽简单,当然,为了加速运算,你也可以安装支援GPU版本的Tensorflow,NVidia支援CUDA的显示卡请参考这裡 ,相关安装程序请参考tensorflow官网,如果要在 Linux 环境开发也行,安装内容不变, 请参考这裡。
以我的电脑为例,配备如下图,GPU显示卡为NVIDIA GeForce GTX 750(1GB memory),实际安装 Tensorflow GPU 版本的程序如下:
- 下载 CUDA Toolkit 8.0,不能是 9.x,需先至nVidia官网建立帐号,再至 https://developer.nvidia.com/cuda-toolkit-archive 下载。
- 安装完 CUDA Toolkit 后,再下载 cuDNN v6.x ,并将压缩档解开,複製到 CUDA Toolkit 8.0 安装目录下同名子目录下。
- 将 CUDA Toolkit 8.0 安装目录下bin子目录 放到 环境变数 Path 中,在 DOS 中执行Tensorflow时,才找的到相关 Dll。
- 安装 Tensorflow GPU 版本,执行
pip install --ignore-installed --upgrade tensorflow-gpu - 在 DOS 中执行 python,接著输入下列程式,应该就会有相关讯息出现。
import tensorflow as tf
hello = tf.constant('Hello, TensorFlow!')
sess = tf.Session()
print(sess.run(hello))
实际测试简单的程式,确实快很多,但是记忆体太小,遇到複杂的程式,例如后续的CNN程式,需要储存大量矩阵时,就GG了,所以,奉劝各位,要学 Neural Network,还是要花钱买张新一点的显示卡,才能省去执行时去泡茶、喝咖啡的时间。
如果一切顺利完成,就可以开始写程式了。等一下,那 IDE 呢? 你可以用记事本、NodePad++、或者PyCharm,我则是使用 VS 2017 Community 版本,它也是一个很不错的选择喔,可以像 C# 一样的除错。另外,使用 Jupyter Notebook,可以让你像作笔记一样的写程式,总之,戏法人人会变,端看你熟悉甚麽样的环境与工具。
程式撰写
撰写 Keras 程式,我们需要了解简单的 Python 语法,建议快速浏览『Introducing Python』这本书的第二~四章就够了,它不只有中文版,也有免费的PDF电子书喔。
以下范例主要是利用 MNIST 资料集的训练资料,建立单一隐藏层(Hidden Layer)的 Neural Network 模型,以预测实际影像是哪一个阿拉伯数字,如下图:
图. 阿拉伯数字(0~9)辨识的流程
流程步骤如下:
- 先读入训练资料,本例为 60,000 笔资料,每笔资料是一个 28 * 28 的点矩阵图形。
- 图形的每一点都当成一个输入变数(X),乘以一个权重W(i,j),向隐藏层(Hidden Layer)传导,隐藏层的每一个节点会得到输入变数的加权总和(W * X)。
- 再如法炮製,向输出层传导,输出层的每一个节点会得到隐藏层的加权总和,将输出层的每一个节点化为机率,就得到一个预测模型了。
- 之后我们将新资料输入模型,就会得到 0~9 的机率,最大的机率对应的数字就是我们的预测值了。
- 权重(W)是唯一未知的变数,他们等于多少呢? 这就是 Neural Network 厉害的地方,它透过优化(Optimization)计算,就可以求出 W 的最佳解,构筑出模型公式了。
程式很简单,先看注解(#开头),即可了解整个流程:
- 导入(import)要使用的函式库,包括 NumPy(矩阵运算)、Keras、matplotlib(绘图)。
- 从网路载入 MNIST 资料集,请 Keras 自动分为『训练组』及『测试组』资料,MNIST 是由 AI 大师 Yann LeCun 所建立的手写阿拉伯数字资料集(Dataset)。
- 建立最简单的线性模型(Sequential),就是一层层往下执行,没有分叉(If),也没有迴圈(loop),这裡只设一层隐藏层(Dense)。
- 选择损失函数(crossentropy)及优化方法(adam)及成效衡量方式(accuracy),就可以开始训练。
- 执行模型评估,计算模型参数,即上图的W(i,j)及W(j,k),模型就算完成了。
- 接著就可以使用这个模型,预测新资料了。
# 导入函式库
import numpy as np
from keras.models import Sequential
from keras.datasets import mnist
from keras.layers import Dense, Dropout, Activation, Flatten
from keras.utils import np_utils # 用来后续将 label 标籤转为 one-hot-encoding
from matplotlib import pyplot as plt
# 载入 MNIST 资料库的训练资料,并自动分为『训练组』及『测试组』
(X_train, y_train), (X_test, y_test) = mnist.load_data()
# 建立简单的线性执行的模型
model = Sequential()
# Add Input layer, 隐藏层(hidden layer) 有 256个输出变数
model.add(Dense(units=256, input_dim=784, kernel_initializer='normal', activation='relu'))
# Add output layer
model.add(Dense(units=10, kernel_initializer='normal', activation='softmax'))
# 编译: 选择损失函数、优化方法及成效衡量方式
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
# 将 training 的 label 进行 one-hot encoding,例如数字 7 经过 One-hot encoding 转换后是 0000001000,即第7个值为 1
y_TrainOneHot = np_utils.to_categorical(y_train)
y_TestOneHot = np_utils.to_categorical(y_test)
# 将 training 的 input 资料转为2维
X_train_2D = X_train.reshape(60000, 28*28).astype('float32')
X_test_2D = X_test.reshape(10000, 28*28).astype('float32')
x_Train_norm = X_train_2D/255
x_Test_norm = X_test_2D/255
# 进行训练, 训练过程会存在 train_history 变数中
train_history = model.fit(x=x_Train_norm, y=y_TrainOneHot, validation_split=0.2, epochs=10, batch_size=800, verbose=2)
# 显示训练成果(分数)
scores = model.evaluate(x_Test_norm, y_TestOneHot)
print()
print("\t[Info] Accuracy of testing data = {:2.1f}%".format(scores[1]*100.0))
# 预测(prediction)
X = x_Test_norm[0:10,:]
predictions = model.predict_classes(X)
# get prediction result
print(predictions)
执行方法很简单,在DOS执行Python,接著将以上程式一段段贴上即可,我们就可以观察每段程式的用途,要看变数内容,只要输入变数名称即可,全部执行完,可以看到准确率有 85%,够神奇吧,毕竟我们只写了10多行的程式(不含注解)。
要确认预测是否正确,可以再贴上下列程式,查看影像:
# 显示 第一笔训练资料的图形,确认是否正确
plt.imshow(X_test[0])
plt.show()
如果我们要看优化的过程,可以输入以下程式,结果如下图:
plt.plot(train_history.history['loss'])
plt.plot(train_history.history['val_loss'])
plt.title('Train History')
plt.ylabel('loss')
plt.xlabel('Epoch')
plt.legend(['loss', 'val_loss'], loc='upper left')
plt.show()
图. 优化过程的损失函数(Loss)的变化
进行到这裡,我们已经跨出了一小步,后续我们接著抽丝剥茧,好好研究它为什麽可以这麽厉害。
相关程式请至这裡 下载,本范例为0.py。