CNTK入門05:一個全連接前饋模型用於分類手寫識別圖片

CNTK入門05:一個全連接前饋模型用於分類手寫識別圖片

------- A fully connected feed-forward model for classification of MNIST images.

1.  .\Examples\Image\DataSets\MNIST下有兩個文件,運行Python install_mnist.py下載手寫識別圖片。

其中60000作爲測試訓練數據,10000張作爲測試數據。

代碼:install_mnist.py

from __future__ import print_function
import os
import mnist_utils as ut

if __name__ == "__main__":
	#改變當前工作目錄到指定的路徑
    os.chdir(os.path.abspath(os.path.dirname(__file__)))
    train = ut.load('http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz',
        'http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz', 60000)
    print ('Writing train text file...')
    ut.savetxt(r'./Train-28x28_cntk_text.txt', train)
    print ('Done.')
	
    test = ut.load('http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz',
        'http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz', 10000)
    print ('Writing test text file...')
    ut.savetxt(r'./Test-28x28_cntk_text.txt', test)
    print ('Done.')


上面主函數調用瞭如下的文件中的函數:mnist_utils.py

from __future__ import print_function
try: 
    from urllib.request import urlretrieve 
except ImportError: 
    from urllib import urlretrieve
import sys
import gzip
import shutil
import os
import struct
import numpy as np

def loadData(src, cimg):
    print ('Downloading ' + src)
	#retrieve,取回;src 下載地址,./delete.me是存儲地址;返回tuple(filename,header)
	#filename 表示保存到本地的路徑,header 表示服務器的響應頭
    gzfname, h = urlretrieve(src, './delete.me')
    print ('Done.')
    try:
        with gzip.open(gzfname) as gz:
			#按照給定的格式(fmt)解析字節流string,返回解析出來的tuple
            n = struct.unpack('I', gz.read(4))
            # Read magic number.
            if n[0] != 0x3080000:
                raise Exception('Invalid file: unexpected magic number.')
            # Read number of entries.
            n = struct.unpack('>I', gz.read(4))[0]
            if n != cimg:
                raise Exception('Invalid file: expected {0} entries.'.format(cimg))
            crow = struct.unpack('>I', gz.read(4))[0]
            ccol = struct.unpack('>I', gz.read(4))[0]
            if crow != 28 or ccol != 28:
                raise Exception('Invalid file: expected 28 rows/cols per image.')
            # Read data.
            res = np.fromstring(gz.read(cimg * crow * ccol), dtype = np.uint8)
    finally:
        os.remove(gzfname)
    return res.reshape((cimg, crow * ccol))

def loadLabels(src, cimg):
    print ('Downloading ' + src)
    gzfname, h = urlretrieve(src, './delete.me')
    print ('Done.')
    try:
        with gzip.open(gzfname) as gz:
            n = struct.unpack('I', gz.read(4))
            # Read magic number.
            if n[0] != 0x1080000:
                raise Exception('Invalid file: unexpected magic number.')
            # Read number of entries.
            n = struct.unpack('>I', gz.read(4))
            if n[0] != cimg:
                raise Exception('Invalid file: expected {0} rows.'.format(cimg))
            # Read labels.
            res = np.fromstring(gz.read(cimg), dtype = np.uint8)
    finally:
        os.remove(gzfname)
    return res.reshape((cimg, 1))#改變矩陣爲cimg行,1列

#參數:訓練的數據,訓練數據的標籤類別,圖片張數
def load(dataSrc, labelsSrc, cimg):
    data = loadData(dataSrc, cimg)
    labels = loadLabels(labelsSrc, cimg)
	#
    return np.hstack((data, labels))

def savetxt(filename, ndarray):
    with open(filename, 'w') as f:
        labels = list(map(' '.join, np.eye(10, dtype=np.uint).astype(str)))
        for row in ndarray:
            row_str = row.astype(str)
            label_str = labels[row[-1]]
            feature_str = ' '.join(row_str[:-1])
            f.write('|labels {} |features {}\n'.format(label_str, feature_str))

在目錄 .\Examples\Image\Classification\MLP\Python\SimpleMNIST.py是手寫識別的程序;

 Python SimpleMNIST.py 運行即可:

import argparse
import numpy as np
import sys
import os
from cntk.train import Trainer, minibatch_size_schedule 
from cntk.io import MinibatchSource, CTFDeserializer, StreamDef, StreamDefs, INFINITELY_REPEAT
from cntk.device import cpu, try_set_default_device
from cntk.learners import adadelta, learning_rate_schedule, UnitType
from cntk.ops import input, relu, element_times, constant
from cntk.losses import cross_entropy_with_softmax
from cntk.metrics import classification_error
from cntk.train.training_session import *
from cntk.logging import ProgressPrinter, TensorBoardProgressWriter

abs_path = os.path.dirname(os.path.abspath(__file__))
sys.path.append(os.path.join(abs_path, "..", "..", "..", "..", "common"))
from nn import fully_connected_classifier_net

def check_path(path):
    if not os.path.exists(path):
        readme_file = os.path.normpath(os.path.join(
            os.path.dirname(path), "..", "README.md"))
        raise RuntimeError(
            "File '%s' does not exist. Please follow the instructions at %s to download and prepare it." % (path, readme_file))

def create_reader(path, is_training, input_dim, label_dim):
    return MinibatchSource(CTFDeserializer(path, StreamDefs(
        features  = StreamDef(field='features', shape=input_dim, is_sparse=False),
        labels    = StreamDef(field='labels',   shape=label_dim, is_sparse=False)
    )), randomize=is_training, max_sweeps = INFINITELY_REPEAT if is_training else 1)


# Creates and trains a feedforward classification model for MNIST images

def simple_mnist(tensorboard_logdir=None):
    input_dim = 784
    num_output_classes = 10
    num_hidden_layers = 1
    hidden_layers_dim = 200

    # Input variables denoting the features and label data
    feature = input(input_dim, np.float32)
    label = input(num_output_classes, np.float32)

    # Instantiate the feedforward classification model
    scaled_input = element_times(constant(0.00390625), feature)
    z = fully_connected_classifier_net(
        scaled_input, num_output_classes, hidden_layers_dim, num_hidden_layers, relu)

    ce = cross_entropy_with_softmax(z, label)
    pe = classification_error(z, label)

    data_dir = os.path.join(abs_path, "..", "..", "..", "DataSets", "MNIST")

    path = os.path.normpath(os.path.join(data_dir, "Train-28x28_cntk_text.txt"))
    check_path(path)

    reader_train = create_reader(path, True, input_dim, num_output_classes)

    input_map = {
        feature  : reader_train.streams.features,
        label  : reader_train.streams.labels
    }

    # Training config
    minibatch_size = 64
    num_samples_per_sweep = 60000
    num_sweeps_to_train_with = 10

    # Instantiate progress writers.
    #training_progress_output_freq = 100
    progress_writers = [ProgressPrinter(
        #freq=training_progress_output_freq,
        tag='Training',
        num_epochs=num_sweeps_to_train_with)]

    if tensorboard_logdir is not None:
        progress_writers.append(TensorBoardProgressWriter(freq=10, log_dir=tensorboard_logdir, model=z))

    # Instantiate the trainer object to drive the model training
    trainer = Trainer(z, (ce, pe), adadelta(z.parameters), progress_writers)

    training_session(
        trainer=trainer,
        mb_source = reader_train,
        mb_size = minibatch_size,
        model_inputs_to_streams = input_map,
        max_samples = num_samples_per_sweep * num_sweeps_to_train_with,
        progress_frequency=num_samples_per_sweep
    ).train()
    
    # Load test data
    path = os.path.normpath(os.path.join(data_dir, "Test-28x28_cntk_text.txt"))
    check_path(path)

    reader_test = create_reader(path, False, input_dim, num_output_classes)

    input_map = {
        feature  : reader_test.streams.features,
        label  : reader_test.streams.labels
    }

    # Test data for trained model
    test_minibatch_size = 1024
    num_samples = 10000
    num_minibatches_to_test = num_samples / test_minibatch_size
    test_result = 0.0
    for i in range(0, int(num_minibatches_to_test)):
        mb = reader_test.next_minibatch(test_minibatch_size, input_map=input_map)
        eval_error = trainer.test_minibatch(mb)
        test_result = test_result + eval_error

    # Average of evaluation errors of all test minibatches
    return test_result / num_minibatches_to_test


if __name__=='__main__':
    # Specify the target device to be used for computing, if you do not want to
    # use the best available one, e.g.
    # try_set_default_device(cpu())

    parser = argparse.ArgumentParser()
    parser.add_argument('-tensorboard_logdir', '--tensorboard_logdir',
                        help='Directory where TensorBoard logs should be created', required=False, default=None)
    args = vars(parser.parse_args())

    error = simple_mnist(args['tensorboard_logdir'])
    print("Error: %f" % error)


----------------------------------------------------------------------------------------------------------------------------

附錄:

1. os.chdir()  #改變當前工作目錄到指定的路徑

2.np.hstack()的解釋:
stack() Join a sequence of arrays along a new axis.
hstack() Stack arrays in sequence horizontally (column wise).
dstack() Stack arrays in sequence depth wise (along third dimension).
concatenate() Join a sequence of arrays along an existing axis.
vsplit () Split array into a list of multiple sub-arrays vertically.
2.1 stack() :通過個新軸,連接兩個數組。

>>> arrays = [np.random.randn(3, 4) for _ in range(10)]  
>>> np.stack(arrays, axis=0).shape  
(10, 3, 4)   
>>> np.stack(arrays, axis=1).shape  
(3, 10, 4)  
>>> np.stack(arrays, axis=2).shape  
(3, 4, 10)  
>>> a = np.array([1, 2, 3])  
>>> b = np.array([2, 3, 4])  
>>> np.stack((a, b))  
array([[1, 2, 3],  
       [2, 3, 4]])  
>>> np.stack((a, b), axis=-1)  
array([[1, 2],  
       [2, 3],  
       [3, 4]])  

np.random.randn(34)返回一個3行4列的矩陣,數字是服從標準正態分佈的。

2.2 numpy.hstack()函數

函數原型:numpy.hstack(tup)

其中tup是arrays序列,The arrays must have the same shape, except in the dimensioncorresponding to axis (the first, by default).

等價於:np.concatenate(tup, axis=1)

>>> a = np.array((1,2,3))  
>>> b = np.array((2,3,4))  
>>> np.hstack((a,b))  
array([1, 2, 3, 2, 3, 4])  
>>> a = np.array([[1],[2],[3]])  
>>> b = np.array([[2],[3],[4]])  
>>> np.hstack((a,b))  
array([[1, 2],  
       [2, 3],  
       [3, 4]])  
2.3 numpy.vstack()函數

函數原型:numpy.vstack(tup)

等價於:np.concatenate(tup, axis=0) if tup contains arrays thatare at least 2-dimensional.

程序實例:

>>> a = np.array([1, 2, 3])  
>>> b = np.array([2, 3, 4])  
>>> np.vstack((a,b))  
array([[1, 2, 3],  
       [2, 3, 4]])  
>>> a = np.array([[1], [2], [3]])  
>>> b = np.array([[2], [3], [4]])  
>>> np.vstack((a,b))  
array([[1],  
       [2],  
       [3],  
       [2],  
       [3],  
       [4]]) 

2.4   numpy.dstack()函數

函數原型:numpy.dstack(tup)

等價於:np.concatenate(tup, axis=2)

程序實例:

>>> a = np.array((1,2,3))  
>>> b = np.array((2,3,4))  
>>> np.dstack((a,b))  
array([[[1, 2],  
        [2, 3],  
        [3, 4]]])  
  
>>>  
  
>>> a = np.array([[1],[2],[3]])  
>>> b = np.array([[2],[3],[4]])  
>>> np.dstack((a,b))  
array([[[1, 2]],  
       [[2, 3]],  
       [[3, 4]]])  

2.5 numpy.concatenate()函數

函數原型:numpy.concatenate((a1, a2, ...), axis=0)

程序實例:

>>> a = np.array([[1, 2], [3, 4]])  
>>> b = np.array([[5, 6]])  
>>> np.concatenate((a, b), axis=0)  
array([[1, 2],  
       [3, 4],  
       [5, 6]])  
>>> np.concatenate((a, b.T), axis=1)  
array([[1, 2, 5],  
       [3, 4, 6]])  
  
This function will not preserve masking of MaskedArray inputs.  
>>>  
  
>>> a = np.ma.arange(3)  
>>> a[1] = np.ma.masked  
>>> b = np.arange(2, 5)  
>>> a  
masked_array(data = [0 -- 2],  
             mask = [False  True False],  
       fill_value = 999999)  
>>> b  
array([2, 3, 4])  
>>> np.concatenate([a, b])  
masked_array(data = [0 1 2 2 3 4],  
             mask = False,  
       fill_value = 999999)  
>>> np.ma.concatenate([a, b])  
masked_array(data = [0 -- 2 2 3 4],  
             mask = [False  True False False False False],  
       fill_value = 999999)  

2.6 numpy.vsplit()函數

函數原型:numpy.vsplit(ary, indices_or_sections)

程序實例:

>>> x = np.arange(16.0).reshape(4, 4)  
>>> x  
array([[  0.,   1.,   2.,   3.],  
       [  4.,   5.,   6.,   7.],  
       [  8.,   9.,  10.,  11.],  
       [ 12.,  13.,  14.,  15.]])  
>>> np.vsplit(x, 2)  
[array([[ 0.,  1.,  2.,  3.],  
       [ 4.,  5.,  6.,  7.]]),  
 array([[  8.,   9.,  10.,  11.],  
       [ 12.,  13.,  14.,  15.]])]  
>>> np.vsplit(x, np.array([3, 6]))  
[array([[  0.,   1.,   2.,   3.],  
       [  4.,   5.,   6.,   7.],  
       [  8.,   9.,  10.,  11.]]),  
 array([[ 12.,  13.,  14.,  15.]]),  
 array([], dtype=float64)]  
  
With a higher dimensional array the split is still along the first axis.  
>>>  
  
>>> x = np.arange(8.0).reshape(2, 2, 2)  
>>> x  
array([[[ 0.,  1.],  
        [ 2.,  3.]],  
       [[ 4.,  5.],  
        [ 6.,  7.]]])  
>>> np.vsplit(x, 2)  
[array([[[ 0.,  1.],  
        [ 2.,  3.]]]),  
 array([[[ 4.,  5.],  
        [ 6.,  7.]]])]  

------------------------------------------------------------------------------------
3.url.urlretrieve(filename[, reporthook[, data]]])的使用

urllib.urlretrieve(url,filename)下載網絡文件,第一個元素就是目標url,第二個參數是保存的文件絕對路徑(含文件名),返回值是一個tuple(filename,header),filename 表示保存到本地的路徑,header 表示服務器的響應頭.如果urlretrieve僅提供1個參數,返回值的filename就是產生的臨時文件名,函數執行完畢後該臨時文件會被刪除參數。參數reporthook是一個回調函數,當連接上服務器、以及相應的數據塊傳輸完畢的時候會觸發該回調。其中回調函數名稱可任意,但是參數必須爲三個。一般直接使用reporthook(block_read,block_size,total_size)定義回調函數,block_size是每次讀取的數據塊的大小,block_read是每次讀取的數據塊個數,taotal_size是一一共讀取的數據量,單位是byte。可以使用reporthook函數來顯示讀取進度。





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章