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.]]
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.]]
與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.]]
#改變指定位置的值
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.]]
使用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.]]
[[ 1. 1.]
[ 1. 1.]]
對控制流求導
指令式的程式設計的一個便利之處是幾乎可以對任意的可導程式進行求導,即使裡面包含了 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.]]
x.grad=
[[40., 8.]
[12., 0.16]]