MXNet學習1——數據模擬

寫在前面:

最近在學習神經網絡,正好趕上國內外一大批深度學習框架開源,亂花漸欲迷人眼。看了挺多對比文章再結合自身的需求,最終選擇了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初始化時就已經規定好,沒有道理,只是隨機得到的,之後一直不變。後續的訓練數據都是以此爲均值的一個正太分佈隨機數
"""
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章