寫在前面:
最近在學習神經網絡,正好趕上國內外一大批深度學習框架開源,亂花漸欲迷人眼。看了挺多對比文章再結合自身的需求,最終選擇了MXNet(0.9)。事實上一開始選擇的是Tensorflow(r0.12),然而本身基礎太差卻又恰好遇到到了多GPU跑程序的需求。Tensorflow當然是支持多GPU,但是需要調整代碼,這對於當前只知道看官方簡單tutorial的我真是太困難了。MXNet是自動支持數據並行的,根據我當前的瞭解,基本不需要修改代碼就能夠利用多GPU跑程序。OK,既然選定了MXNet,就要沉下心了,千山萬水還是要一步步,所以還是看官方的tutorial吧(好像沒什麼變化ㄒ_ㄒ)。本系列記錄MXNet學習的歷程,一般使用通俗的語言,將會不定期更新,歡迎討論~~
安裝過程就不用說了,按照官網上的說明,無論是linux,windows,無論是cpu還是gpu版,都比較簡單,需要注意的是今後不需要使用gpu的代碼都在windows上跑,需要使用gpu的則在centos7下跑。
按照官方的教程,需要了解ndarray,symbol,module,model等,但是官方例子大多都是片段,不太清晰,對於新手不太友好,只需要簡單知道概念就好。稍微複雜的例子看起來就十分費勁,需要來回跳躍API,所以本系列主要按照github上的教學代碼同時參考官網tutorial。這裏吐槽一下MXNet的API,實在是太簡略了,很多方法只用文字說明一下,一般都看不懂啊,希望官方儘快完善文檔。
官方代碼在https://github.com/dmlc/mxnet-notebooks/blob/master/python/basic/data_iter.py
數據模擬
很多的教程爲了展示方法的使用會自己生成一些假數據,所以數據模擬比較基礎,這裏優先講這個例子,不需要知道MXNet的知識,涉及到的主要是numpy的操作。爲了說明,規定num_classes=10, num_features=128, batch_size=32
import numpy as np
import mxnet as mx
class SimpleBatch(object):
def __init__(self, data, label, pad=None):
self.data = data
self.label = label
self.pad = pad
"""
data是輸入的訓練數據,二維數組,32*128
label是數據對應的分類,比如手寫數字對應的值是0~9,32*1
pad在這裏沒有用到,就不說了
"""
class SimpleIter:
def __init__(self, mu, sigma, batch_size, num_batches):
self.mu = mu
self.sigma = sigma
self.batch_size = batch_size
self.num_batches = num_batches
self.data_shape = (batch_size, mu.shape[1])
self.label_shape = (batch_size, )
self.cur_batch = 0
"""
batch_size是一次訓練的參數個數,規定是32
mu是10*128的二維數組,正太分佈的均值,用來生成訓練數據
sigma是10*128的二維數組,正太分佈的標準差,用來生成訓練數據
data_shape的第一個參數是一次處理的個數,32,第二個參數是每個數據的特徵數,128
"""
def __iter__(self):
return self
def reset(self):
self.cur_batch = 0
def __next__(self):
return self.next()
@property
def provide_data(self):
return [('data', self.data_shape)]
@property
def provide_label(self):
return [('softmax_label', self.label_shape)]
"""
provide_data,provide_label提供的是shape
"""
def next(self):
if self.cur_batch < self.num_batches:
self.cur_batch += 1
num_classes = self.mu.shape[0]
label = np.random.randint(0, num_classes, self.label_shape)
data = np.zeros(self.data_shape)
for i in range(num_classes):
data[label==i,:] = np.random.normal(
self.mu[i,:], self.sigma[i,:], (sum(label==i), self.data_shape[1]))
return SimpleBatch(data=[mx.nd.array(data)], label=[mx.nd.array(label)], pad=0)
else:
raise StopIteration
"""
cur_batch判斷當前是第幾組(總共batch_num)數據
np.random.randint產生整數隨機數,第一個參數<=隨機數<第二個參數,第三個參數是最後的shape
np.zeros生成全0的數組,data是輸入的訓練數據
np.random.normal爲產生正態分佈隨機數,第一個參數是均值,第二個標準差,(sum(label==i), self.data_shape[1]))是表示最後數組的shape。
均值的shape==標準差的shape==self.data_shape[1].shape
label==i,生成的是bool值,其實是告訴data數組哪一行的值需要更新
sum(label==i)則表示生成的數據的行數,相對於多少組數據,比如2組,那麼賦值時data一次賦值了2個
mx.nd.array是將numpy數據轉換成mxnet的ndarray格式,不用管
"""
class SyntheticData:
"""Genrate synthetic data
"""
def __init__(self, num_classes, num_features):
self.num_classes = num_classes
self.num_features = num_features
self.mu = np.random.rand(num_classes, num_features)
self.sigma = np.ones((num_classes, num_features)) * 0.1
def get_iter(self, batch_size, num_batches=10):
return SimpleIter(self.mu, self.sigma, batch_size, num_batches)
"""
數據模擬的入口是SyntheticData,這意味着之後get_iter時的mu和sigma是相同的
特徵與分類的對應在SyntheticData初始化時就已經規定好,沒有道理,只是隨機得到的,之後一直不變。後續的訓練數據都是以此爲均值的一個正太分佈隨機數
"""