延續昨日從無到有以 Mxnet 實作出 MLP,Fields 再拋出以 Gluon 的實作:
from __future__ import print_function
import numpy as np
import mxnet as mx
from mxnet import nd, autograd, gluon
ctx = mx.gpu() if mx.test_utils.list_gpus() else mx.cpu()
data_ctx = ctx
model_ctx = ctx
#這三行目的:只要測試有CUDA GPU就使用它
batch_size = 64
num_inputs = 784
num_outputs = 10
num_examples = 60000
def transform(data, label):
return data.astype(np.float32)/255, label.astype(np.float32)
train_data = mx.gluon.data.DataLoader(mx.gluon.data.vision.MNIST(train=True,
transform=transform), batch_size, shuffle=True)
test_data = mx.gluon.data.DataLoader(mx.gluon.data.vision.MNIST(train=False,
transform=transform), batch_size, shuffle=False)
#在初始值與訓練資料取得,基本上完全一樣
在神經網路模型的設定簡潔許多,與Tensorflow 相較,我們可以考慮在 forward() 下輸出一些訊息,幫助我們診斷我們的模型設計是否正確?
class MLP(gluon.Block):
def __init__(self, **kwargs):
super(MLP, self).__init__(**kwargs)
with self.name_scope():
self.dense0 = gluon.nn.Dense(64)
self.dense1 = gluon.nn.Dense(64)
self.dense2 = gluon.nn.Dense(10)
def forward(self, x):
x = nd.relu(self.dense0(x))
x = nd.relu(self.dense1(x))
#如果需要進一步查網路在這一層的輸出值來偵錯,可考慮加下一行
print("Hidden Representation 2: %s" % x)
x = self.dense2(x)
#如果需要進一步查網路輸出值來偵錯,可考慮加下一行
print("Network output: %s" % x)
return x
我們可以開始以MNIST 資料集來訓練MLP,一樣需要初始參數。
net = MLP()
net.collect_params().initialize(mx.init.Normal(sigma=.01), ctx=model_ctx)
data = nd.ones((1,784))
net(data.as_in_context(model_ctx))
到現在為止 MLP 的網路定義多少還是為了展示我們可以很輕易的設計新的模型,多少還是很囉唆。如同 Keras,Gluon 也提供自己的Sequential
class 讓開發可以堆疊自己的網路:
num_hidden = 256
net = gluon.nn.Sequential()
with net.name_scope():
net.add(gluon.nn.Dense(num_hidden, activation="relu"))
net.add(gluon.nn.Dense(num_hidden, activation="relu"))
net.add(gluon.nn.Dense(num_outputs))
net.collect_params().initialize(mx.init.Normal(sigma=.1), ctx=model_ctx)
先前自己設計落落長的 MLP Class 其實只要用 net.add(…) 一層一層加上來即可。後面無論是我們自己設計落落長的 MLP Class 還是用 Sequential
class 的 net.add(…),都一樣,要有損失函數,要跑 mini-Batch,當然一堆超參數也要設定:
softmax_cross_entropy = gluon.loss.SoftmaxCrossEntropyLoss()
trainer = gluon.Trainer(net.collect_params(), 'sgd', {'learning_rate': .01})
#這個函數昨天刻意忽略,其目的讓訓練過程每個Iteration的準確度進展能呈現出來
def evaluate_accuracy(data_iterator, net):
acc = mx.metric.Accuracy()
for i, (data, label) in enumerate(data_iterator):
data = data.as_in_context(model_ctx).reshape((-1, 784))
label = label.as_in_context(model_ctx)
output = net(data)
predictions = nd.argmax(output, axis=1)
acc.update(preds=predictions, labels=label)
return acc.get()[1]
epochs = 10
smoothing_constant = .01
for e in range(epochs):
cumulative_loss = 0
for i, (data, label) in enumerate(train_data):
data = data.as_in_context(model_ctx).reshape((-1, 784))
label = label.as_in_context(model_ctx)
with autograd.record():
output = net(data)
loss = softmax_cross_entropy(output, label)
loss.backward()
trainer.step(data.shape[0])
cumulative_loss += nd.sum(loss).asscalar()
test_accuracy = evaluate_accuracy(test_data, net)
train_accuracy = evaluate_accuracy(train_data, net)
print("Epoch %s. Loss: %s, Train_acc %s, Test_acc %s" %
(e, cumulative_loss/num_examples, train_accuracy, test_accuracy))
最後測試跑了一下程式,準確度還能接受。Gavin 驚訝得很,原先他預期會看到很多 openCV 的函數來抓圖檔的一些影像特徵,結果完全就只靠輸入每個點的0到255灰度即可。Moore幫忙解釋,這些原來要經由專家定義出來的特徵值,似乎就存在於隱藏層裡,在最佳化一次又一次迭代計算過程,得到最佳解後,隱藏層每個單元的值,某些角度就是人類不容易解釋的特徵值。
在『AI探索專案』的第一個 Sprint, Fields 認領 提昇專案成員AI 所需數學知識與對應Python程式,短短兩週,自己了解了機器學習的基礎理論外,還要提昇其他人的知識。所以咬著牙花了幾天跟大家講解囉哩囉唆的一堆數學推導。佳麗耐著性子聽完,等到程式跑完,她表達了意見:
“我覺得全部只有 Goldilocks Rule 是我理解的,我們現在只有最基礎的深度學習模型MLP吧?我看了一下,除了最開始已經知道的學習率,Epoch,Batch Size 等是靠金髮姑娘原則,慢慢抓出『適當』值,剛剛程式裡我也看到 深度要多少層(程式寫的是兩層),每層要多少的單元(寫的是每層都採256單元),我願意猜,這一定又是要靠 Goldilocks Rule。
“再細想,數學別人已經可能幾年前都證明了,甚至許多框架也都開發對應的程式庫提供函數讓我們呼叫,我沒法揣摩出在這裡面我們要加值什麼!”
Gavin 幫忙回答:
”我們這個『AI探索專案』目標之一,不就是要探索我們可以加值什麼!現在沒有答案沒關係,慢慢的我們會找到的。Pete 能說說你的觀察嗎?”
Pete:
”我從 Fields 的講解還有我自己研讀的心得,我認為有三個層次來談:
這三個層次我觀察我們專案剛好都有人才可以進行。另外還有一種人,能判斷需求或問題需要用機器學習來解決,並適度的投入資源。這個大約就是大老闆Servo的活吧?
”
Molly 加入討論:
“剛剛Pete 所談的第1.項,我擔心以現有成員的經驗來進行,緩不濟急。Fields 短短兩週內有這樣成果是蠻厲害的,但是要作到有效益,研判非要兩三年的摸索。”
Gavin:”以 Product Owner 角度來看,我們專案是『AI探索』,可見成事不必在己,我們如果真能遇到需求是需要發明新的或改良模型,有方向後,也許再去物色合作對象也可以。但是我們要有人可以理解基礎理論,這樣才有辦法與專家對談,所以 Fields 你還是要堅守這個領域。倒是第2.項,我直覺對我們這些人才來說,應用現有模型來訓練,門檻不會高到無法跨過,但是廣度就變成問題了。”
Moore這幾日也有心得:”是的除了先前我們討論過OS, 程式語言,機器學習框架外,不同的問題就會有對應的網路模型來解決,我看到現在有啥 CNN,RNN, Reinforcement Learning, GAN 等等,每一個都有相當的理論基礎還有實作的細節要考慮,我們臂多力分了!”
Cash 聽到 Reinforcement Learning 趕快補充:”我看一些文章,要用Reinforcement Learning 訓練電腦來打怪,除了 GPU 有要求,RAM 居然要100GB 以上呢,這個我要趕快採購,趕緊試試看!”
佳麗瞪了Cash 一下:”我們等大後天的 Sprint Review會議,趁機了解 Servo 與 RJ 真正的需求再聚焦吧!建議現在我們還是維持Sprint 目標,做廣泛的理解機器學習。”
Gavin 最後總結:”沒有扎實的需求或是痛苦的問題要解決,就不會有好的架構設計。所以至今要談聚焦不太現實,如佳麗所言,就繼續廣泛的了解吧。”
Molly 補充:"針對Pete的第3.點,資料集標注,我有認識對岸的人,就是做這一門生意的,明天我跟大家報告狀況。"
Moore:”那後天我要用 Tensorflow 來做MLP,讓大家與Mxnet比比看。”
專案緣起記錄在 【UP, Scrum 與 AI專案】