mxnet:基礎知識和一個簡單的示例


NDArray與NumPy的多維數組類似,但NDArray提供了更多的功能:GPU和CPU的異步計算;自動求導。這使得NDArray能更好地支持機器學習。

初始化

from mxnet import ndarray as nd
nd.zeros((3,4))
nd.ones((3,4))
nd.array([[1,2],[3,4]])
out:
[[1. 2.][3. 4.]] <NDArray 2x2 @cpu(0)>
nd.random_normal(0,1,shape=(3,4)) #標准正態分布
# 輸出信息
y.shape
y.size

操作符

按照相應元素運算

x+y
x*y
nd.exp(x)

矩陣的乘法

nd.dot(x, y.T)

廣播(Beoadcasting)

當二元操作符左右兩邊ndarray形狀不一樣時,系統會嘗試將它們擴充到共同的形狀。

a=nd.arange(3).reshape((3,1))
b=nd.arange(2),reshape((1,2))
print ('a+b', a+b)
out:
a+b:
[[ 0. 1.] [ 1. 2.] [ 2. 3.]] <NDArray 3x2 @cpu(0)>

與NumPy的轉換

x=np.ones((2,3))
y=nd.array(x) # numpy->mxnet
z=y.asnumpy() # mxnet->numpy

替換操作

如果我們寫y=x+y,會開辟新的內存來存儲計算結果,如:

x=nd.ones((3,4))
y=nd.ones((3,4))
before = id(y)
y=y+x
id(y)==before # False

可以通過[:]寫到之間建立好的數組中

z=nd.zeros_like(y)
before=id(z)
z[:]=x+y
id(z)==before # True

上述,系統還是為x+y創建了臨時空間,再復制給了z。為了避免這個開銷,可以使用操作符的全名版本並指定out參數

nd.elemwise_add(x,y,out=z)
id(z)==before # True

截取(Slicing)

x=nd.arange(0,9).reshape((3,3))
x[1:3]
out:
[[ 3. 4. 5.] [ 6. 7. 8.]] <NDArray 2x3 @cpu(0)>
#改變指定位置的值
x[1,2]=9.
#多維截取
x[1:2,1:3]
#多維寫入
x[1:2,1:3]=9.
out:
[[ 0. 1. 2.] [ 3. 9. 9.] [ 6. 7. 8.]] <NDArray 3x3 @cpu(0)>

使用autograd自動求導

import mxnet.ndarray as nd
import mxnet.autograd as ag

為變量附上梯度

x=nd.array([[1,2],[3,4]])
x.attach_grad() # ndarray的方法申請相應的空間
# 定義函數f=2x*x,顯式要求mxnet記錄我們要求導的程序
with ag.record():
    y=x*2
    z=y*x
# 通過z.backword()來進行求導,如果z不是一個標量,z.backward()等價於nd.sum(z).backward().
z.backward()
print('x.grad: ',x.grad)
x.grad == 4*x
# output
x.grad:
[[4.,  8.]
 [12., 16.]]
<NDArray 2x2 @cpu(0)>
[[ 1.  1.]
 [ 1.  1.]]
<NDArray 2x2 @cpu(0)>

對控制流求導

命令式的編程的一個便利之處是幾乎可以對任意的可導程序進行求導,即使里面包含了 Python 的 控制流。對於計算圖框架來說,這個對應於動態圖,就是圖的結構會根據輸入數據不同而改變。

def f(a): 
    b=a*2
    while nd.norm(b).asscalar() < 1000: 
        b=b*2
    if nd.sum(b).asscalar() > 0: 
        c=b
    else:
        c = 100 * b 
    return c

使用record和backward求導

a = nd.random_normal(shape=3)
a.attach_grad()
with ag.record(): 
    c = f(a)
c.backward()

頭梯度和鏈式法則

基於鏈式法則:

\[\frac{dz}{dx} = \frac{dz}{dy}\frac{dy}{dx} \]

\(\frac{dz}{dy}\)就是\(\frac{dy}{dx}\)的頭梯度,而計算\(\frac{dz}{dy}\),頭梯度則為默認值,即nd.ones_like(y)。我們也可以手動指定頭梯度。

with ag.record(): 
    y = x * 2 
    z = y * x
head_gradient = nd.array([[10, 1.], [.1, .01]]) 
z.backward(head_gradient) 
print(x.grad)
# out
x=
[[1.,2.]
 [3.,4.]]
<NDArray 2x2 @cpu(0)>
x.grad=
[[40., 8.]
 [12., 0.16]]
<NDArray 2x2 @cpu(0)>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM