基於Docker的MindSpore安裝與使用基礎介紹
技術背景
MindSpore是一款新一代AI開源計算框架,其特色在於:創新編程範式,AI科學家和工程師更易使用,便於開放式創新;該計算框架可滿足終端、邊緣計算、雲全場景需求,能更好保護數據隱私;可開源,形成廣闊應用生態。MindSpore的軟體架構如下圖所示:
其中關於自動微分的部分被集成在了GHLO這個模組上,該模組主要內容是一些不依賴於硬體體系的優化,也是本次安裝與測試指導中特別關注的內容。
由於MindSpore的支援系統列表(如下圖所示)中不包含本機主擦作系統Manjaro Linux
,因此這裡我們使用Docker的方式來進行安裝和使用。Docker是一款最常用的基於NameSpace和Cgroup隔離的容器解決方案,其在保障了容器內部數據和進程隔離的安全基礎之上,開發了更加靈活的系統級隔離和調度解決方案。
Manjaro Linux下Docker容器基礎操作介紹
由於Docker的安裝較為容易,在各種Linux發行版的源中一般都有,這裡就不過多介紹,我們就先假設Docker已經安裝成功。在使用時,需要先啟動Docker的服務:
[dechin-manjaro dechin]# systemctl start docker
啟動之後我們可以通過查看status來確認是否啟動成功,以及docker服務是否已經處於正在運行的狀態,如果顯示running
則表示docker正在運行:
[dechin-manjaro dechin]# systemctl status docker
● docker.service - Docker Application Container Engine
Loaded: loaded (/usr/lib/systemd/system/docker.service; disabled; vendor preset: disabled)
Active: active (running) since Sun 2021-03-14 21:12:10 CST; 48s ago
TriggeredBy: ● docker.socket
Docs: //docs.docker.com
Main PID: 2292 (dockerd)
Tasks: 91 (limit: 47875)
Memory: 216.0M
CGroup: /system.slice/docker.service
├─2292 /usr/bin/dockerd -H fd://
└─2303 containerd --config /var/run/docker/containerd/containerd.toml --log-level info
一般可以通過docker pull
的方式簡單的從dockerhub裡面直接拉取別人已經製作好的基礎系統鏡像。也可以基於這些基礎系統鏡像,撰寫一份屬於自己的dockerfile,創建一個訂製化的容器化編程環境。我們可以用docker images
指令來查看本地已有的鏡像:
[dechin-manjaro dechin]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
centos-singularity latest 57d72e8a5ed8 8 weeks ago 824MB
centos-python36 latest 8507baed96a2 2 months ago 651MB
ubntu-python38 latest ac734d47a39d 2 months ago 1.01GB
centos latest 3c1f6b9f7e91 2 months ago 215MB
cplex latest 55d067c32a95 2 months ago 1.16GB
shekyan/slowhttptest latest 9cf05b8a7d93 4 months ago 7.86MB
ubuntu latest d70eaf7277ea 4 months ago 72.9MB
在Docker環境已經準備好的前提下,我們就可以開始準備MindSpore的編程環境。
在Docker上配置MindSpore編程環境
首先我們按照官方提示,從華為雲的鏡像庫中拉取MindSpore的cpu版本(MindSpore分為cpu版本和gpu版本等,各個版本的介面上存在一定的區別,性能上也有較大差異)的鏡像文件:
[dechin-manjaro dechin]# docker pull swr.cn-south-1.myhuaweicloud.com/mindspore/mindspore-cpu:1.1.1
1.1.1: Pulling from mindspore/mindspore-cpu
f22ccc0b8772: Pull complete
3cf8fb62ba5f: Pull complete
e80c964ece6a: Pull complete
fe0abcdea904: Pull complete
6533a255e1da: Pull complete
3e74722304a0: Pull complete
bd14fc4220fc: Pull complete
2540aadb4e52: Pull complete
acd020acb001: Pull complete
3cea35fa8bdc: Pull complete
96eddf603bb3: Pull complete
Digest: sha256:d7db718a62fb3a0ab56ef4aa548e3c9a62e42094b018d99751be5f7b6b006749
Status: Downloaded newer image for swr.cn-south-1.myhuaweicloud.com/mindspore/mindspore-cpu:1.1.1
swr.cn-south-1.myhuaweicloud.com/mindspore/mindspore-cpu:1.1.1
拉取完成後,可以通過docker images
指令查看鏡像列表,我們發現剛才拉取的鏡像已經在鏡像列表中:
[dechin-manjaro dechin]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
swr.cn-south-1.myhuaweicloud.com/mindspore/mindspore-cpu 1.1.1 98a3f041e3d4 4 weeks ago 1.18GB
在準備好MindSpore的容器化編程環境之後,我們可以進入這個鏡像去測試一下MindSpore的一些基礎用例。運行容器的方式是docker run
,但是為了持久化的運行鏡像中的/bin/bash
,我們需要加上-it
指令配置。拉取容器鏡像時一般是用REPOSITORY這一列的鏡像名稱來拉取,但是由於這個名字實在是有點長,我們也可以通過拉取IMAGE ID來進入容器實例內,每一個鏡像或者實例都有一個唯一的ID作為標識碼。甚至在日常使用過程中,我們並不需要輸入完整的IMAGE ID來拉取鏡像,只要輸入前幾位的字元,只要保障其唯一性,也一樣可以成功拉起鏡像,如下所示的用例就是使用了這樣的一個操作技巧:
[dechin-manjaro dechin]# docker run -it 98a3
root@00637dfcdc2a:/# ll
total 72
drwxr-xr-x 1 root root 4096 Mar 14 13:17 ./
drwxr-xr-x 1 root root 4096 Mar 14 13:17 ../
-rwxr-xr-x 1 root root 0 Mar 14 13:17 .dockerenv*
drwxr-xr-x 1 root root 4096 Feb 8 02:20 bin/
drwxr-xr-x 2 root root 4096 Apr 24 2018 boot/
drwxr-xr-x 5 root root 360 Mar 14 13:17 dev/
drwxr-xr-x 1 root root 4096 Mar 14 13:17 etc/
drwxr-xr-x 2 root root 4096 Apr 24 2018 home/
drwxr-xr-x 1 root root 4096 Feb 8 02:20 lib/
drwxr-xr-x 1 root root 4096 Feb 8 02:20 lib64/
drwxr-xr-x 2 root root 4096 Nov 19 13:07 media/
drwxr-xr-x 2 root root 4096 Nov 19 13:07 mnt/
drwxr-xr-x 2 root root 4096 Nov 19 13:07 opt/
dr-xr-xr-x 311 root root 0 Mar 14 13:17 proc/
drwx------ 1 root root 4096 Feb 8 02:22 root/
drwxr-xr-x 1 root root 4096 Nov 25 22:25 run/
drwxr-xr-x 1 root root 4096 Feb 8 02:19 sbin/
drwxr-xr-x 2 root root 4096 Nov 19 13:07 srv/
dr-xr-xr-x 13 root root 0 Mar 14 13:17 sys/
drwxrwxrwt 1 root root 4096 Feb 8 02:22 tmp/
drwxr-xr-x 1 root root 4096 Nov 19 13:07 usr/
drwxr-xr-x 1 root root 4096 Nov 19 13:09 var/
拉起鏡像之後我們可以看到這裡的目錄跟普通的Linux作業系統基本一致。這裡我們重點需要確認在該環境下MindSpore是否已經被成功安裝,因此我們進入home
目錄,去創建一個MindSpore的測試用例試試:
root@00637dfcdc2a:/# cd home/
root@00637dfcdc2a:/home# ll
total 8
drwxr-xr-x 2 root root 4096 Apr 24 2018 ./
drwxr-xr-x 1 root root 4096 Mar 14 13:17 ../
root@00637dfcdc2a:/home# mkdir mindspore
root@00637dfcdc2a:/home# cd mindspore/
創建的python測試用例如下(相關示例程式碼來自於官方網站上面提供的驗證用例):
# test_mindspore.py
import numpy as np
import mindspore.context as context
import mindspore.ops as ops
from mindspore import Tensor
context.set_context(mode=context.PYNATIVE_MODE, device_target="CPU")
x = Tensor(np.ones([1,3,3,4]).astype(np.float32))
y = Tensor(np.ones([1,3,3,4]).astype(np.float32))
print(ops.tensor_add(x, y))
在官方提供的這個容器鏡像中,只存在一個python3的python版本,因此一般情況下直接使用python指令來運行相關程式碼即可:
root@00637dfcdc2a:/home/mindspore# python test_mindspore.py
WARNING: 'ControlDepend' is deprecated from version 1.1 and will be removed in a future version, use 'Depend' instead.
[WARNING] ME(28:140090633642112,MainProcess):2021-03-14-13:19:14.205.404 [mindspore/ops/operations/array_ops.py:2302] WARN_DEPRECATED: The usage of Pack is deprecated. Please use Stack.
[[[[2. 2. 2. 2.]
[2. 2. 2. 2.]
[2. 2. 2. 2.]]
[[2. 2. 2. 2.]
[2. 2. 2. 2.]
[2. 2. 2. 2.]]
[[2. 2. 2. 2.]
[2. 2. 2. 2.]
[2. 2. 2. 2.]]]]
在得到這一串數字之後,我們知道即使有一些版本相關的告警資訊,但是這個例子是已經被成功的執行了的,現在我們再來回顧一下這個例子執行的是一個什麼樣的功能。
這個案例其實是創建兩個多維的數組,這裡相關的數據結構名為Tensor,也就是張量。關於張量的一些基礎知識,可以查看之前寫的這一篇關於張量網路計算的部落格,張量網路不僅僅是一個高維的矩陣,其更加重要的一個含義是在圖表示的理論框架下,對中間計算的過程進行複雜性的優化。在拓撲網路圖中可以先找到一個複雜性較好的計算順序,再對整個張量網路進行計算。當然,在上述給出的示例中,僅僅執行了Tensor的加法,構造了兩個元素全部為1的Tensor,然後加起來,得到的是一個元素全為2的Tensor,因此我們最後的列印輸出是一個全是2的數組。
在Docker中保存數據
在Docker的操作中,如果我們不對相關的數據執行保存的操作,則這些數據不會被保存到鏡像中,這也是符合大部分時候容器的使用場景需求的。但是這裡我們將容器作為一個編程環境來使用,因此我們希望可以把相關的數據寫入到新的容器鏡像中,例如上述用例中在home
目錄下所創建的test_mindspore.py
文件。首先我們用docker ps
的指令來查看歷史記錄中的CONTAINER ID,上述用例的讀寫操作實際上被保存到了這個名為00637dfcdc2a
的鏡像中,而這裡的IMAGE顯示為98a3
,是因為我們之前直接使用部分的ID來拉取的緣故。
[dechin-manjaro dechin]# docker ps -n 2
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
00637dfcdc2a 98a3 "/bin/bash" 5 minutes ago Exited (127) 3 seconds ago stupefied_kare
dfb2634d0ab4 ubuntu "/bin/bash" 8 minutes ago Exited (127) 8 minutes ago hardcore_engelbart
在獲取到需要保存的CONTAINER ID之後,我們就可以使用docker commit
指令,把該數據保存到一個指定名稱(比如直接取名為mindspore)的新的容器鏡像內,這裡我們先用一個字元編碼來命名:
[dechin-manjaro dechin]# docker commit 0063 98a3
sha256:5d2e3caaca6970f0c003593a8c5606a4f2798ea7da032ff8308fc46b36dcf9f0
commit結束之後我們再查看本地鏡像,我們發現多出來了一個名為98a3的鏡像,而原來IMAGE ID開頭為98a3的鏡像還在:
[dechin-manjaro dechin]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
98a3 latest 5d2e3caaca69 6 seconds ago 1.18GB
swr.cn-south-1.myhuaweicloud.com/mindspore/mindspore-cpu 1.1.1 98a3f041e3d4 4 weeks ago 1.18GB
那麼在這個時候,如果我們直接拉取98a3,是拉取哪一個鏡像呢?
[dechin-manjaro dechin]# docker run -it 98a3
root@5ad904a0bdc1:/# ll
total 76
drwxr-xr-x 1 root root 4096 Mar 14 13:25 ./
drwxr-xr-x 1 root root 4096 Mar 14 13:25 ../
-rwxr-xr-x 1 root root 0 Mar 14 13:25 .dockerenv*
drwxr-xr-x 1 root root 4096 Feb 8 02:20 bin/
drwxr-xr-x 2 root root 4096 Apr 24 2018 boot/
drwxr-xr-x 5 root root 360 Mar 14 13:25 dev/
drwxr-xr-x 1 root root 4096 Mar 14 13:25 etc/
drwxr-xr-x 1 root root 4096 Mar 14 13:18 home/
drwxr-xr-x 1 root root 4096 Feb 8 02:20 lib/
drwxr-xr-x 1 root root 4096 Feb 8 02:20 lib64/
drwxr-xr-x 2 root root 4096 Nov 19 13:07 media/
drwxr-xr-x 2 root root 4096 Nov 19 13:07 mnt/
drwxr-xr-x 2 root root 4096 Nov 19 13:07 opt/
dr-xr-xr-x 310 root root 0 Mar 14 13:25 proc/
drwx------ 1 root root 4096 Mar 14 13:22 root/
drwxr-xr-x 1 root root 4096 Nov 25 22:25 run/
drwxr-xr-x 1 root root 4096 Feb 8 02:19 sbin/
drwxr-xr-x 2 root root 4096 Nov 19 13:07 srv/
dr-xr-xr-x 13 root root 0 Mar 14 13:25 sys/
drwxrwxrwt 1 root root 4096 Feb 8 02:22 tmp/
drwxr-xr-x 1 root root 4096 Nov 19 13:07 usr/
drwxr-xr-x 1 root root 4096 Nov 19 13:09 var/
root@5ad904a0bdc1:/# cd home/
root@5ad904a0bdc1:/home# ll
total 12
drwxr-xr-x 1 root root 4096 Mar 14 13:18 ./
drwxr-xr-x 1 root root 4096 Mar 14 13:25 ../
drwxr-xr-x 2 root root 4096 Mar 14 13:19 mindspore/
root@5ad904a0bdc1:/home# cd mindspore/
root@5ad904a0bdc1:/home/mindspore# ll
total 12
drwxr-xr-x 2 root root 4096 Mar 14 13:19 ./
drwxr-xr-x 1 root root 4096 Mar 14 13:18 ../
-rw-r--r-- 1 root root 332 Mar 14 13:19 test_mindspore.py
root@5ad904a0bdc1:/home/mindspore# exit
exit
這個測試結果告訴我們,雖然這裡存在一個ID為98a3開頭的鏡像,但是docker還是會優先拉起名字相同,也就是REPOSITORY相同的容器鏡像。在這個結果中,上述用例所創建的test_mindspore.py
文件依然存在於這個系統鏡像之中。我們可以再對比一下原始的鏡像,這裡因為不能再用98a3來拉起,因此我們多加一位字元,使用98a3f來拉起:
[dechin-manjaro dechin]# docker run -it 98a3f
root@6ff7a03fa3cb:/# ll
total 72
drwxr-xr-x 1 root root 4096 Mar 14 13:25 ./
drwxr-xr-x 1 root root 4096 Mar 14 13:25 ../
-rwxr-xr-x 1 root root 0 Mar 14 13:25 .dockerenv*
drwxr-xr-x 1 root root 4096 Feb 8 02:20 bin/
drwxr-xr-x 2 root root 4096 Apr 24 2018 boot/
drwxr-xr-x 5 root root 360 Mar 14 13:25 dev/
drwxr-xr-x 1 root root 4096 Mar 14 13:25 etc/
drwxr-xr-x 2 root root 4096 Apr 24 2018 home/
drwxr-xr-x 1 root root 4096 Feb 8 02:20 lib/
drwxr-xr-x 1 root root 4096 Feb 8 02:20 lib64/
drwxr-xr-x 2 root root 4096 Nov 19 13:07 media/
drwxr-xr-x 2 root root 4096 Nov 19 13:07 mnt/
drwxr-xr-x 2 root root 4096 Nov 19 13:07 opt/
dr-xr-xr-x 313 root root 0 Mar 14 13:25 proc/
drwx------ 1 root root 4096 Feb 8 02:22 root/
drwxr-xr-x 1 root root 4096 Nov 25 22:25 run/
drwxr-xr-x 1 root root 4096 Feb 8 02:19 sbin/
drwxr-xr-x 2 root root 4096 Nov 19 13:07 srv/
dr-xr-xr-x 13 root root 0 Mar 14 13:25 sys/
drwxrwxrwt 1 root root 4096 Feb 8 02:22 tmp/
drwxr-xr-x 1 root root 4096 Nov 19 13:07 usr/
drwxr-xr-x 1 root root 4096 Nov 19 13:09 var/
root@6ff7a03fa3cb:/# cd home/
root@6ff7a03fa3cb:/home# ll
total 8
drwxr-xr-x 2 root root 4096 Apr 24 2018 ./
drwxr-xr-x 1 root root 4096 Mar 14 13:25 ../
root@6ff7a03fa3cb:/home# exit
exit
我們發現,前面所創建的python測試用例是沒有保存到這個原始鏡像中的。
MindSpore自動微分測試
在眾多的組合優化問題中,我們通常需要計算一個目標函數的導數,在一個可微的函數下,其最大值或最小值一定會滿足一階導數為0這一個條件,因此我們常常會去尋找構建的這個函數在某一個點的導數。尋找極值點的方法有很多,比如梯度下降等,但是計算導數的方法大概就是三種方案:手動求導、差分求導以及自動微分。手動求導只能應用於小規模的簡單模型,對於比較複雜的模型來說是不太現實的;差分求導是在各種優化器中常用的技巧,但是性能比較受限;因此自動微分現在成為一個比較主流的方案,通過機器來優化計算一個給定模型的導數。當然,這裡面也分為了Google的TensorFlow、FaceBook的PyTorch以及華為主推的MindSpore等幾種不同的演算法框架,在這篇部落格中我們就不一一展開來介紹,這裡我們僅用一個測試用例展示MindSpore相關函數和介面的調用方法:
# test_gradient.py
import numpy as np
import mindspore.context as context
import mindspore.nn as nn
import mindspore.ops as ops
from mindspore import Tensor
from mindspore import ParameterTuple, Parameter
from mindspore import dtype as mstype
context.set_context(mode=context.GRAPH_MODE, device_target="CPU")
class Net(nn.Cell):
def __init__(self):
super(Net, self).__init__()
self.matmul = ops.MatMul()
self.z = Parameter(Tensor(np.array([1.0], np.float32)), name='z')
def construct(self, x, y):
x = x * self.z
out = self.matmul(x, y)
return out
class GradNetWrtX(nn.Cell):
def __init__(self, net):
super(GradNetWrtX, self).__init__()
self.net = net
self.grad_op = ops.GradOperation()
def construct(self, x, y):
gradient_function = self.grad_op(self.net)
return gradient_function(x, y)
x = Tensor([[0.8, 0.6, 0.2], [1.8, 1.3, 1.1]], dtype=mstype.float32)
y = Tensor([[0.11, 3.3, 1.1], [1.1, 0.2, 1.4], [1.1, 2.2, 0.3]], dtype=mstype.float32)
output = GradNetWrtX(Net())(x, y)
print(output)
這個案例中給出了一個關於\(x,y,z\)三個變數的函數,光看函數形式的話其實就是\(f(x,y,z)=xyz\)。但是這裡面展開來看的話,\(x,y\)分別是2×3的矩陣與3×3的張量/多維矩陣,\(z\)可以當成是一個單獨的變數來計算,這裡值就是1
。具體矩陣乘法的調用方法可以參考官網上給出的介面文檔:
綜合上面這些函數介面,最終計算的結果形式,如果用函數式來表達大概就是:
\]
其中的求和項與MindSpore中所採用的自動微分計算方法有關,相關參考文獻為參考鏈接4。最後驗證一下我們的輸出結果:
root@a94bc5f2320e:/home/mindspore# python test_gradient.py
WARNING: 'ControlDepend' is deprecated from version 1.1 and will be removed in a future version, use 'Depend' instead.
[WARNING] ME(37:140326817828992,MainProcess):2021-03-14-13:45:14.989.5 [mindspore/ops/operations/array_ops.py:2302] WARN_DEPRECATED: The usage of Pack is deprecated. Please use Stack.
[[4.5099998 2.7 3.6000001]
[4.5099998 2.7 3.6000001]]
我們發現這個輸出結果中雖然包含了一部分的告警資訊以及有一些精度上的缺失,但是基本上是符合我們的預期的。
總結概要
寫這篇文章的目的,主要是為了驗證一下MindSpore編程環境的搭建,以及基本的測試用例的測試。由於MindSpore的CPU版本在x86架構上只適配了Ubuntu的作業系統,因此這裡我們額外介紹了Docker的安裝部署方案以及Docker的一些基本操作。最後我們通過兩個MindSpore的測試用例,驗證了其基本功能的準確性。
版權聲明
本文首發鏈接為://www.cnblogs.com/dechinphy/p/mindspore.html
作者ID:DechinPhy
更多原著文章請參考://www.cnblogs.com/dechinphy/
參考鏈接
- //baike.baidu.com/item/MindSpore/23697508
- //www.mindspore.cn/
- //www.mindspore.cn/tutorial/training/zh-CN/r1.1/advanced_use/achieve_high_order_differentiation.html#id4
- Baydin A G, Pearlmutter B A, Radul A A, et al. Automatic differentiation in machine learning: a survey[J]. The Journal of Machine Learning Research, 2017, 18(1): 5595-5637.