天天看點

MindSpore!這款剛剛開源的深度學習架構我愛了!

MindSpore!這款剛剛開源的深度學習架構我愛了!

MindSpore 最大的特點就是開發門檻大大降低,提高開發效率,這樣可以顯著減少模型開發時間。

是以,使用MindSpore的優勢可以總結為以下四點:

  • 簡單的開發體驗
  • 靈活的調試模式
  • 充分發揮硬體潛能
  • 全場景快速部署

既然開源了,那就趕緊上手,試一試這款開源的 MindSpore 怎麼樣!本文我将介紹 MindSpore 的安裝和上手教程,通過一個簡單的圖像識别案例來跑完整個 AI 訓練和測試流程。

一、MindSpore 的安裝

開源架構 MindSpore 的安裝方法有很多,可以在 Windows、Ubuntu 上安裝,也可以在華為 Ascend 910 上安裝。各種詳盡的安裝方法請見下面的連結:

https://www.mindspore.cn/install

下面介紹兩種最簡單的安裝方法!

1. Docker 安裝

Docker 安裝最為簡單,可參考:

https://gitee.com/mindspore/mindspore#docker-image

以 0.3.0-alpha 版本為例:

  • CPU:

    docker pull mindspore/mindspore-cpu:0.3.0-alpha

  • GPU:

    docker pull mindspore/mindspore-gpu:0.3.0-alpha

安裝好後,可以看到安裝的鏡像,并使用下面的指令建立一個你的容器:

docker run -it mindspore/mindspore-cpu:0.3.0-alpha /bin/bash      

2. Win10+Anaconda+MindSpore

使用 Win10 +Anaconda+MindSpore 的方式進行安裝也非常簡單,本文将采用這種方式安裝 MindSpore。

在 MindSpore 安裝首頁裡,選擇安裝相關配置:

  • 版本:0.3.0-alpha
  • 硬體平台:CPU
  • 作業系統:Windows-64
  • 程式設計語言:Python 3.7.5

首先,在 Win10 上安裝 Anaconda,Anaconda 是一個開源的 Python 發行版本,其包含了 conda、Python 等 180 多個科學包及其依賴項。

然後,建立一個虛拟環境。

1). 打開 Anaconda 元件中的 Anaconda Prompt 終端:

conda create -n mindspore python=3.7.5 
conda activate mindspore      

3). 安裝依賴庫,根據

https://gitee.com/mindspore/mindspore/blob/r0.3/requirements.txt

列出的依賴庫,使用 conda 指令安裝。例如:

conda install numpy
      

4). 根據之前選擇的相關配置,在網站:

https://www.mindspore.cn/versions

中選擇所要相應的 MindSpore 版本:

mindspore-0.3.0-cp37-cp37m-win_amd64.whl

可以将.whl 檔案下載下傳到本地,使用 pip 安裝(使用 conda 指令線上安裝速度可能比較慢,是以可以選擇将.whl檔案下載下傳到本地,使用 pip 指令安裝):

pip install mindspore-0.3.0-cp37-cp37m-win_amd64.whl      

最後測試是否安裝成功,進入 Python shell,執行如下指令,如果沒有提示 No module named 'mindspore' 等加載錯誤的資訊,則說明安裝成功。

MindSpore!這款剛剛開源的深度學習架構我愛了!

至此,安裝完成!

二、基于本地 Jupyter 實作 MNIST 手寫資料集分類

1. 安裝 Jupyter Notebook

首先,在虛拟環境 mindspore 中安裝 Jupyter Notebook。方法是:打開 Anaconda 元件 Anaconda Navigator。

MindSpore!這款剛剛開源的深度學習架構我愛了!
MindSpore!這款剛剛開源的深度學習架構我愛了!

2. 下載下傳資料集

MNIST 手寫資料集想必大家都很熟悉了,包含 0-9 的數字,由 60000 張訓練圖檔和 10000 張測試圖檔組成。

MindSpore!這款剛剛開源的深度學習架構我愛了!

MNIST 資料集下載下傳頁面:

http://yann.lecun.com/exdb/mnist/

使用 MindSpore,我們可以通過直接定義一個 download_dataset 函數來自動下載下傳 MNIST 資料集:

def download_dataset():
    """Download the dataset from http://yann.lecun.com/exdb/mnist/."""
    print("******Downloading the MNIST dataset******")
    train_path = "./MNIST_Data/train/"
    test_path = "./MNIST_Data/test/"
    train_path_check = os.path.exists(train_path)
    test_path_check = os.path.exists(test_path)
    if train_path_check == False and test_path_check ==False:
        os.makedirs(train_path)
        os.makedirs(test_path)
    train_url = {"http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz", "http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz"}
    test_url = {"http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz", "http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz"}
    for url in train_url:
        url_parse = urlparse(url)
        # split the file name from url
        file_name = os.path.join(train_path,url_parse.path.split('/')[-1])
        if not os.path.exists(file_name.replace('.gz','')):
            file = urllib.request.urlretrieve(url, file_name)
            unzipfile(file_name)
            os.remove(file_name)
    for url in test_url:
        url_parse = urlparse(url)
        # split the file name from url
        file_name = os.path.join(test_path,url_parse.path.split('/')[-1])
        if not os.path.exists(file_name.replace('.gz','')):
            file = urllib.request.urlretrieve(url, file_name)
            unzipfile(file_name)
            os.remove(file_name)      

該函數實作将資料集自動下載下傳在本地的 ./MNIST_Data 目錄下,訓練集放在子目錄 /train 下,測試集放在子目錄 /test 下。

3. 資料預處理

MNIST 資料集準備好了之後,下一步就要對資料集進行一些預處理,包括圖檔尺寸調整為 32x32(因為我們使用的是 LeNet-5 網絡,後面會介紹),像素歸一化、batch_size 設為 32(可調整),等等。

MindSpore 提供了 mindspore.dataset.MnistDataset 來直接定義 Minist 資料集,非常友善。使用 mindspore.dataset.MnistDataset.map 映射函數,将資料操作應用到資料集。

我們定義 create_dataset() 函數來建立資料集:

def create_dataset(data_path, batch_size=32, repeat_size=1,
                   num_parallel_workers=1):
    """ create dataset for train or test
    Args:
        data_path: Data path
        batch_size: The number of data records in each group
        repeat_size: The number of replicated data records
        num_parallel_workers: The number of parallel workers
    """
    # define dataset
    mnist_ds = ds.MnistDataset(data_path)

    # define operation parameters
    resize_height, resize_width = 32, 32
    rescale = 1.0 / 255.0
    shift = 0.0
    rescale_nml = 1 / 0.3081
    shift_nml = -1 * 0.1307 / 0.3081

    # define map operations
    resize_op = CV.Resize((resize_height, resize_width), interpolation=Inter.LINEAR)  # Resize images to (32, 32)
    rescale_nml_op = CV.Rescale(rescale_nml, shift_nml) # normalize images
    rescale_op = CV.Rescale(rescale, shift) # rescale images
    hwc2chw_op = CV.HWC2CHW() # change shape from (height, width, channel) to (channel, height, width) to fit network.
    type_cast_op = C.TypeCast(mstype.int32) # change data type of label to int32 to fit network

    # apply map operations on images
    mnist_ds = mnist_ds.map(input_columns="label", operations=type_cast_op, num_parallel_workers=num_parallel_workers)
    mnist_ds = mnist_ds.map(input_columns="image", operations=resize_op, num_parallel_workers=num_parallel_workers)
    mnist_ds = mnist_ds.map(input_columns="image", operations=rescale_op, num_parallel_workers=num_parallel_workers)
    mnist_ds = mnist_ds.map(input_columns="image", operations=rescale_nml_op, num_parallel_workers=num_parallel_workers)
    mnist_ds = mnist_ds.map(input_columns="image", operations=hwc2chw_op, num_parallel_workers=num_parallel_workers)

    # apply DatasetOps
    buffer_size = 10000
    mnist_ds = mnist_ds.shuffle(buffer_size=buffer_size)  # 10000 as in LeNet train script
    mnist_ds = mnist_ds.batch(batch_size, drop_remainder=True)
    mnist_ds = mnist_ds.repeat(repeat_size)

    return mnist_ds
      

通過上面的函數,就完成了對剛下載下傳的 MNIST 資料集的預處理。

4. 定義網絡

LeNet-5 是一種用于手寫體字元識别的非常高效的卷積神經網絡。LeNet-5 共有 7 層,不包含輸入,每層都包含可訓練參數;每個層有多個 Feature Map,每個 FeatureMap通過一種卷積濾波器提取輸入的一種特征。

MindSpore!這款剛剛開源的深度學習架構我愛了!

1) 模型初始化

使用 mindspore.common.initializer.TruncatedNormal 方法對參數進行初始化,定義 conv 和 fc_with_initialize 分别對卷積層和全連接配接層進行初始化。

import mindspore.nn as nn
from mindspore.common.initializer import TruncatedNormal

def conv(in_channels, out_channels, kernel_size, stride=1, padding=0):
    """Conv layer weight initial."""
    weight = weight_variable()
    return nn.Conv2d(in_channels, out_channels,
                     kernel_size=kernel_size, stride=stride, padding=padding,
                     weight_init=weight, has_bias=False, pad_mode="valid")

def fc_with_initialize(input_channels, out_channels):
    """Fc layer weight initial."""
    weight = weight_variable()
    bias = weight_variable()
    return nn.Dense(input_channels, out_channels, weight, bias)

def weight_variable():
    """Weight initial."""
    return TruncatedNormal(0.02)      

使用 mindspore.common.initializer.TruncatedNormal 方法,可以非常便捷地實作網絡權重系數的初始化操作,不需要自定義初始化函數。

2) 定義 LeNet-5 網絡

MindSpore 來定義 LeNet-5 網絡也很簡單,根據網絡結構,定義相應的卷積層和全連接配接層即可。在初始化函數 __init__ 種定義神經網絡的各層,然後通過定義 construct 方法來完成神經網絡的前向構造。

class LeNet5(nn.Cell):
    """Lenet network structure."""
    # define the operator required
    def __init__(self):
        super(LeNet5, self).__init__()
        self.conv1 = conv(1, 6, 5)
        self.conv2 = conv(6, 16, 5)
        self.fc1 = fc_with_initialize(16 * 5 * 5, 120)
        self.fc2 = fc_with_initialize(120, 84)
        self.fc3 = fc_with_initialize(84, 10)
        self.relu = nn.ReLU()
        self.max_pool2d = nn.MaxPool2d(kernel_size=2, stride=2)
        self.flatten = nn.Flatten()

    # use the preceding operators to construct networks
    def construct(self, x):
        x = self.conv1(x)
        x = self.relu(x)
        x = self.max_pool2d(x)
        x = self.conv2(x)
        x = self.relu(x)
        x = self.max_pool2d(x)
        x = self.flatten(x)
        x = self.fc1(x)
        x = self.relu(x)
        x = self.fc2(x)
        x = self.relu(x)
        x = self.fc3(x)
        return x      

LeNet-5 是一個非常典型且簡單的卷積神經網絡,從 construct 方法可以詳細看到 LeNet-5 各層的結構。

3) 定義損失函數

MindSpore 支援的損失函數有 SoftmaxCrossEntropyWithLogits、L1Loss、MSELoss 等。這裡使用 SoftmaxCrossEntropyWithLogits 交叉熵損失函數。

from mindspore.nn.loss import SoftmaxCrossEntropyWithLogits

# define the loss function
net_loss = SoftmaxCrossEntropyWithLogits(is_grad=False, sparse=True, reduction='mean')      

4) 定義網絡梯度下降算法

MindSpore 支援的梯度下降算法有 Adam、AdamWeightDecay、Momentum 等。這裡使用流行的 Momentum 算法。其中,學習率設為 0.01,momentum 參數設為 0.9。

# learning rate setting
lr = 0.01
momentum = 0.9
# define the optimizer
net_opt = nn.Momentum(network.trainable_params(), lr, momentum)      

5. 訓練網絡

1) 模型儲存

mindspore.train.callback.ModelCheckpoint 方法可以儲存網絡模型和參數。

config_ck = CheckpointConfig(save_checkpoint_steps=1875, keep_checkpoint_max=10)
# save the network model and parameters for subsequence fine-tuning
ckpoint_cb = ModelCheckpoint(prefix="checkpoint_lenet", config=config_ck)      

2) 訓練網絡

訓練網絡使用 model.train 方法進行。這裡把 epoch_size 設定為 1,對資料集進行 1 個疊代的訓練。訓練的過程中會列印 loss 值的變化。

from mindspore.nn.metrics import Accuracy
from mindspore.train.callback import LossMonitor
from mindspore.train import Model

def train_net(args, model, epoch_size, mnist_path, repeat_size, ckpoint_cb, sink_mode):
    """define the training method"""
    print("============== Starting Training ==============")
    #load training dataset
    ds_train = create_dataset(os.path.join(mnist_path, "train"), 32, repeat_size)
    model.train(epoch_size, ds_train, callbacks=[ckpoint_cb, LossMonitor()], dataset_sink_mode=sink_mode)      
epoch_size = 1
mnist_path = "./MNIST_Data
# group layers into an object with training and evaluation features
model = Model(network, net_loss, net_opt, metrics={"Accuracy": Accuracy()})
train_net(args, model, epoch_size, mnist_path, repeat_size, ckpoint_cb)
      

其中,mnist_path 是 MNIST 資料集路徑。

3) 硬體資訊

在主函數中,别忘了配置 MindSpore 運作的硬體資訊。因為我們是在 CPU 環境下,是以 ‘--device_target’ 設定為 “CPU”。

parser = argparse.ArgumentParser(description='MindSpore LeNet Example')
parser.add_argument('--device_target', type=str, default="CPU", choices=['Ascend', 'GPU', 'CPU'],
                        help='device where the code will be implemented (default: CPU)')
args = parser.parse_args(args=[])
context.set_context(mode=context.GRAPH_MODE, device_target=args.device_target)      

這裡的 '--device_target' 預設是 “CPU”,根據硬體情況也可以選擇 “Ascend” 或 “GPU”。使用的是圖模式 “context.GRAPH_MODE”。

4) 模型訓練

執行程式,模型訓練開始。訓練過程中會列印 loss 值:

...
epoch: 1 step: 262, loss is 1.9212162
epoch: 1 step: 263, loss is 1.8498616
epoch: 1 step: 264, loss is 1.7990671
epoch: 1 step: 265, loss is 1.9492403
epoch: 1 step: 266, loss is 2.0305142
epoch: 1 step: 267, loss is 2.0657792
epoch: 1 step: 268, loss is 1.9582214
epoch: 1 step: 269, loss is 0.9459006
epoch: 1 step: 270, loss is 0.8167224
epoch: 1 step: 271, loss is 0.7432692
...      

可以看到 loss 總體來說會逐漸減小,精度逐漸提高,最終的 loss 為 0.067。

訓練完成之後,得到儲存的模型檔案:

checkpoint_lenet-1_1875.ckpt

6. 模型測試

在得到模型檔案後,使用 model.eval() 接口讀入測試資料集,通過模型運作測試資料集得到的結果。定義測試函數 test_net():

def test_net(args, network, model, mnist_path):
    """Define the evaluation method."""
    print("============== Starting Testing ==============")
    # load the saved model for evaluation
    param_dict = load_checkpoint("checkpoint_lenet-1_1875.ckpt")
    # load parameter to the network
    load_param_into_net(network, param_dict)
    # load testing dataset
    ds_eval = create_dataset(os.path.join(mnist_path, "test"))
    acc = model.eval(ds_eval, dataset_sink_mode=False)
    print("============== Accuracy:{} ==============".format(acc))
      
MindSpore!這款剛剛開源的深度學習架構我愛了!

最終,可以看到剛剛訓練的 LeNet-5 網絡模型在測試集上的精度是 96.63%,效果非常不錯。

至此,我們使用 MindSpore 架構訓練 LeNet-5 模型已經完成。實作了基于本地 Jupyter 實作 MNIST 手寫資料集分類。總的來說,MindSpore 提供了很多子產品化的方法來進行模型搭建和訓練,非常友善我們能夠快速搭建一個神經網絡模型。大家可以根據自己實際需求,上手搭建一個自己的神經網絡試試。

本節完整代碼:

https://gitee.com/mindspore/docs/blob/master/tutorials/tutorial_code/lenet.py

三、在雲伺服器上使用 MindSpore

除了可以在本地使用 MindSpore 架構之外,我們還可以在華為雲伺服器上使用 MindSpore。在華為雲上使用 MindSpore 的還有一個好處是,我們可以申請使用昇騰 AI 處理器資源池作為硬體。

ModelArts 是華為雲提供的面向開發者的一站式 AI 開發平台,而且內建了 MindSpore。下面我們将在 ModelArts 下使用 ResNet-50 網絡識别 CIFAR-10 圖檔。

1. 準備 ModelArts

1) 進入華為雲官網,新增賬號。

具體操作:

https://support.huaweicloud.com/prepare-modelarts/modelarts_08_0001.html

2) 擷取通路密鑰并完成 ModelArts 配置。

https://support.huaweicloud.com/prepare-modelarts/modelarts_08_0002.html

3) 建立 OBS 桶

https://support.huaweicloud.com/prepare-modelarts/modelarts_08_0003.html

2. 申請伺服器昇騰 AI 處理器資源

為了在 ModelArts 上使用華為雲昇騰 AI 處理器,我們需要申請體驗資格,申請方式也很簡單,可在下面的網站上進行申請:

https://console.huaweicloud.com/modelarts/?region=cn-north-4#/dashboard/applyModelArtsAscend910Beta
MindSpore!這款剛剛開源的深度學習架構我愛了!

申請時的内容大家可以填仔細些,一般正常的話兩個工作日就批下來了。

3. 資料準備

1) 下載下傳 CIFAR-10 資料集

CIFAR-10 該資料集共有 60000 張彩色圖像,這些圖像是 32*32,分為 10 個類,每類 6000 張圖。

MindSpore!這款剛剛開源的深度學習架構我愛了!

CIFAR-10 資料集下載下傳位址:

http://www.cs.toronto.edu/~kriz/cifar.html

注意下載下傳 CIFAR-10 binary version 版本。

2) 建立一個自己的 OBS 桶(例如:mine-ms-dataset)

ModelArts 使用對象存儲服務(Object Storage Service,簡稱 OBS)進行資料存儲,是以,在開始訓練任務之前,需要将資料上傳至 OBS。

首先,登入 OBS 管理控制台:

https://storage.huaweicloud.com/obs/?region=cn-north-4#/obs/manager/buckets

建立 OBS 桶 mine-ms-dataset(名稱可修改,下面類似)。

然後,在剛建立的 OBS 桶裡,建立用于存放資料的檔案夾:在桶清單單擊待操作的桶,在左側導航欄,單擊“對象”,建立檔案夾 mine-cifar-10。

最後,将下載下傳好的 CIFAR-10 資料集按照以下目錄結構上傳至資料目錄 mine-cifar-10 中:

└─對象存儲/mine-ms-dataset/mine-cifar-10

    ├─train

    │      data_batch_1.bin

    │      data_batch_2.bin

    │      data_batch_3.bin

    │      data_batch_4.bin

    │      data_batch_5.bin

    │

    └─eval

        test_batch.bin

4. 程式準備

建立一個 OBS 桶(例如:mine-resnet50-train),在桶中建立代碼目錄(例如:mine-resnet50_cifar10_train)。同時在該桶中建立 output 目錄和 log 目錄,用來存放模型和日志。

将網址:

https://gitee.com/mindspore/docs/tree/master/tutorials/tutorial_code/sample_for_cloud/

中的兩個 .py 檔案 dataset.py 和 resnet50_train.py 下載下傳并上傳到代碼目錄 mine-resnet50_cifar10_train 中。

代碼目錄 mine-resnet50_cifar10_train 結構如下:

└─對象存儲/mine-resnet50-train

    ├─mine-resnet50_cifar10_train

    │      dataset.py

    │      resnet50_train.py

    ├─output

    └─log

5. 建立訓練任務

準備好資料和執行腳本以後,下面就可以在雲伺服器上建立訓練任務了。

1) 進入 ModelArts 控制台

打開華為雲 ModelArts 首頁

https://www.huaweicloud.com/product/modelarts.html

點選“進入控制台”。

2) 使用 MindSpore 作為常用架構建立訓練作業

在左側導航欄中選擇“訓練管理 > 訓練作業”,預設進入“訓練作業”清單。

在訓練作業清單中,單擊左上角“建立”,進入“建立訓練作業”頁面。

在建立訓練作業頁面,訓練作業名稱自定義,例如 mine-resnet50-trainjob。填寫訓練作業相關參數,具體配置參數如下:

MindSpore!這款剛剛開源的深度學習架構我愛了!

值得注意的時,算法來源常用架構選擇 Ascend-Powered-Engine,因為我們使用的是硬體是華為雲昇騰 AI 處理器。MindSpore 版本選擇 MindSpore-0.1-python3.7-aarch64 即可。

配置完之後,點選下一步 -> 送出 -> 傳回訓練作業清單,可以看到訓練作業 mine-resnet50-trainjob 正在運作:

MindSpore!這款剛剛開源的深度學習架構我愛了!
MindSpore!這款剛剛開源的深度學習架構我愛了!

四、總結:

本文主要通過兩個實際應用案例對開源架構 MindSpore 進行介紹。一是基于本地 Jupyter Notebook 的 MNIST 手寫資料識别;二是基于華為雲伺服器的 CIFAR-10 圖像分類。兩個案例均圍繞并使用了 MindSpore。

從我個人的使用感覺來看,MindSpore 用起來還是很順手的,而且函數封裝得比較簡潔,使用起來較為友善。通過手把手的教程,大家完全可以自己動手實操一下,感受一下開源架構 MindSpore 的魅力。

大家也可以根據自己的具體應用場景和實用案例,使用 MindSpore,搭建神經網絡模型,解決實際問題。無論是計算機視覺還是自然語言處理,相信 MindSpore 都能給大家帶來流暢的體驗。

參考資料:

https://www.mindspore.cn/ https://www.mindspore.cn/tutorial/zh-CN/master/index.html https://support.huaweicloud.com/modelarts/index.html