Apache MXNet - NDArray
Pada bab ini, kita akan membahas tentang format array multi-dimensi MXNet yang disebut ndarray.
Menangani data dengan NDArray
Pertama, kita akan melihat bagaimana kita dapat menangani data dengan NDArray. Berikut ini adalah prasyarat untuk hal yang sama -
Prasyarat
Untuk memahami bagaimana kita dapat menangani data dengan format array multi-dimensi ini, kita perlu memenuhi prasyarat berikut:
MXNet diinstal di lingkungan Python
Python 2.7.x atau Python 3.x
Contoh Implementasi
Mari kita memahami fungsionalitas dasar dengan bantuan contoh yang diberikan di bawah ini -
Pertama, kita perlu mengimpor MXNet dan ndarray dari MXNet sebagai berikut -
import mxnet as mx
from mxnet import nd
Setelah kami mengimpor pustaka yang diperlukan, kami akan menggunakan fungsi dasar berikut:
Array 1-D sederhana dengan daftar python
Example
x = nd.array([1,2,3,4,5,6,7,8,9,10])
print(x)
Output
Outputnya seperti yang disebutkan di bawah ini -
[ 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.]
<NDArray 10 @cpu(0)>
Array 2-D dengan daftar python
Example
y = nd.array([[1,2,3,4,5,6,7,8,9,10], [1,2,3,4,5,6,7,8,9,10], [1,2,3,4,5,6,7,8,9,10]])
print(y)
Output
Outputnya seperti yang dinyatakan di bawah ini -
[[ 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.]
[ 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.]
[ 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.]]
<NDArray 3x10 @cpu(0)>
Membuat NDArray tanpa inisialisasi apa pun
Di sini, kita akan membuat matriks dengan 3 baris dan 4 kolom dengan menggunakan .emptyfungsi. Kami juga akan menggunakan.full fungsi, yang akan mengambil operator tambahan untuk nilai apa yang ingin Anda isi dalam array.
Example
x = nd.empty((3, 4))
print(x)
x = nd.full((3,4), 8)
print(x)
Output
Outputnya diberikan di bawah ini -
[[0.000e+00 0.000e+00 0.000e+00 0.000e+00]
[0.000e+00 0.000e+00 2.887e-42 0.000e+00]
[0.000e+00 0.000e+00 0.000e+00 0.000e+00]]
<NDArray 3x4 @cpu(0)>
[[8. 8. 8. 8.]
[8. 8. 8. 8.]
[8. 8. 8. 8.]]
<NDArray 3x4 @cpu(0)>
Matriks semua nol dengan fungsi .zeros
Example
x = nd.zeros((3, 8))
print(x)
Output
Outputnya adalah sebagai berikut -
[[0. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 0.]]
<NDArray 3x8 @cpu(0)>
Matriks semua yang memiliki fungsi .ones
Example
x = nd.ones((3, 8))
print(x)
Output
Outputnya disebutkan di bawah ini -
[[1. 1. 1. 1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1. 1. 1. 1.]]
<NDArray 3x8 @cpu(0)>
Membuat larik yang nilainya diambil sampelnya secara acak
Example
y = nd.random_normal(0, 1, shape=(3, 4))
print(y)
Output
Outputnya diberikan di bawah ini -
[[ 1.2673576 -2.0345826 -0.32537818 -1.4583491 ]
[-0.11176403 1.3606371 -0.7889914 -0.17639421]
[-0.2532185 -0.42614475 -0.12548696 1.4022992 ]]
<NDArray 3x4 @cpu(0)>
Menemukan dimensi dari setiap NDArray
Example
y.shape
Output
Outputnya adalah sebagai berikut -
(3, 4)
Menemukan ukuran setiap NDArray
Example
y.size
Output
12
Menemukan tipe data dari setiap NDArray
Example
y.dtype
Output
numpy.float32
Operasi NDArray
Di bagian ini, kami akan memperkenalkan Anda pada operasi array MXNet. NDArray mendukung sejumlah besar matematika standar serta operasi di tempat.
Operasi Matematika Standar
Berikut adalah operasi matematika standar yang didukung oleh NDArray -
Penambahan berdasarkan elemen
Pertama, kita perlu mengimpor MXNet dan ndarray dari MXNet sebagai berikut:
import mxnet as mx
from mxnet import nd
x = nd.ones((3, 5))
y = nd.random_normal(0, 1, shape=(3, 5))
print('x=', x)
print('y=', y)
x = x + y
print('x = x + y, x=', x)
Output
Output diberikan bersama ini -
x=
[[1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1.]]
<NDArray 3x5 @cpu(0)>
y=
[[-1.0554522 -1.3118273 -0.14674698 0.641493 -0.73820823]
[ 2.031364 0.5932667 0.10228804 1.179526 -0.5444829 ]
[-0.34249446 1.1086396 1.2756858 -1.8332436 -0.5289873 ]]
<NDArray 3x5 @cpu(0)>
x = x + y, x=
[[-0.05545223 -0.3118273 0.853253 1.6414931 0.26179177]
[ 3.031364 1.5932667 1.102288 2.1795259 0.4555171 ]
[ 0.6575055 2.1086397 2.2756858 -0.8332436 0.4710127 ]]
<NDArray 3x5 @cpu(0)>
Perkalian bijak
Example
x = nd.array([1, 2, 3, 4])
y = nd.array([2, 2, 2, 1])
x * y
Output
Anda akan melihat keluaran berikut−
[2. 4. 6. 4.]
<NDArray 4 @cpu(0)>
Eksponensial
Example
nd.exp(x)
Output
Saat Anda menjalankan kode, Anda akan melihat output berikut:
[ 2.7182817 7.389056 20.085537 54.59815 ]
<NDArray 4 @cpu(0)>
Matriks diubah urutannya untuk menghitung perkalian matriks-matriks
Example
nd.dot(x, y.T)
Output
Diberikan di bawah ini adalah output dari kode -
[16.]
<NDArray 1 @cpu(0)>
Operasi Di Tempat
Setiap kali, dalam contoh di atas, kami menjalankan operasi, kami mengalokasikan memori baru untuk menampung hasilnya.
Misalnya, jika kita menulis A = A + B, kita akan mendereferensi matriks yang digunakan A untuk menunjuk dan sebagai gantinya mengarahkannya ke memori yang baru dialokasikan. Mari kita pahami dengan contoh yang diberikan di bawah ini, menggunakan fungsi id () Python -
print('y=', y)
print('id(y):', id(y))
y = y + x
print('after y=y+x, y=', y)
print('id(y):', id(y))
Output
Setelah dieksekusi, Anda akan menerima output berikut -
y=
[2. 2. 2. 1.]
<NDArray 4 @cpu(0)>
id(y): 2438905634376
after y=y+x, y=
[3. 4. 5. 5.]
<NDArray 4 @cpu(0)>
id(y): 2438905685664
Faktanya, kita juga dapat menetapkan hasilnya ke array yang sebelumnya dialokasikan sebagai berikut -
print('x=', x)
z = nd.zeros_like(x)
print('z is zeros_like x, z=', z)
print('id(z):', id(z))
print('y=', y)
z[:] = x + y
print('z[:] = x + y, z=', z)
print('id(z) is the same as before:', id(z))
Output
Outputnya ditunjukkan di bawah ini -
x=
[1. 2. 3. 4.]
<NDArray 4 @cpu(0)>
z is zeros_like x, z=
[0. 0. 0. 0.]
<NDArray 4 @cpu(0)>
id(z): 2438905790760
y=
[3. 4. 5. 5.]
<NDArray 4 @cpu(0)>
z[:] = x + y, z=
[4. 6. 8. 9.]
<NDArray 4 @cpu(0)>
id(z) is the same as before: 2438905790760
Dari output di atas, kita dapat melihat bahwa x + y masih akan mengalokasikan buffer sementara untuk menyimpan hasil sebelum menyalinnya ke z. Jadi sekarang, kita dapat melakukan operasi di tempat untuk menggunakan memori dengan lebih baik dan untuk menghindari buffer sementara. Untuk melakukan ini, kami akan menentukan argumen kata kunci keluar yang didukung setiap operator sebagai berikut -
print('x=', x, 'is in id(x):', id(x))
print('y=', y, 'is in id(y):', id(y))
print('z=', z, 'is in id(z):', id(z))
nd.elemwise_add(x, y, out=z)
print('after nd.elemwise_add(x, y, out=z), x=', x, 'is in id(x):', id(x))
print('after nd.elemwise_add(x, y, out=z), y=', y, 'is in id(y):', id(y))
print('after nd.elemwise_add(x, y, out=z), z=', z, 'is in id(z):', id(z))
Output
Saat menjalankan program di atas, Anda akan mendapatkan hasil sebagai berikut -
x=
[1. 2. 3. 4.]
<NDArray 4 @cpu(0)> is in id(x): 2438905791152
y=
[3. 4. 5. 5.]
<NDArray 4 @cpu(0)> is in id(y): 2438905685664
z=
[4. 6. 8. 9.]
<NDArray 4 @cpu(0)> is in id(z): 2438905790760
after nd.elemwise_add(x, y, out=z), x=
[1. 2. 3. 4.]
<NDArray 4 @cpu(0)> is in id(x): 2438905791152
after nd.elemwise_add(x, y, out=z), y=
[3. 4. 5. 5.]
<NDArray 4 @cpu(0)> is in id(y): 2438905685664
after nd.elemwise_add(x, y, out=z), z=
[4. 6. 8. 9.]
<NDArray 4 @cpu(0)> is in id(z): 2438905790760
Konteks NDArray
Di Apache MXNet, setiap array memiliki konteks dan satu konteks bisa jadi CPU, sedangkan konteks lain mungkin beberapa GPU. Hal-hal bisa menjadi lebih buruk, saat kami menerapkan pekerjaan di beberapa server. Itu sebabnya, kita perlu menetapkan array ke konteks secara cerdas. Ini akan meminimalkan waktu yang dihabiskan untuk mentransfer data antar perangkat.
Misalnya, coba inisialisasi array sebagai berikut -
from mxnet import nd
z = nd.ones(shape=(3,3), ctx=mx.cpu(0))
print(z)
Output
Ketika Anda menjalankan kode di atas, Anda akan melihat output berikut -
[[1. 1. 1.]
[1. 1. 1.]
[1. 1. 1.]]
<NDArray 3x3 @cpu(0)>
Kita dapat menyalin NDArray yang diberikan dari satu konteks ke konteks lain dengan menggunakan metode copyto () sebagai berikut -
x_gpu = x.copyto(gpu(0))
print(x_gpu)
Array NumPy vs. NDArray
Kita semua sudah familiar dengan array NumPy tetapi Apache MXNet menawarkan implementasi arraynya sendiri bernama NDArray. Sebenarnya, itu awalnya dirancang agar mirip dengan NumPy tetapi ada perbedaan utama -
Perbedaan utamanya terletak pada cara penghitungan dieksekusi di NumPy dan NDArray. Setiap manipulasi NDArray di MXNet dilakukan secara asynchronous dan non-blocking, yang artinya, ketika kita menulis kode seperti c = a * b, fungsinya didorong keExecution Engine, yang akan memulai penghitungan.
Di sini, a dan b keduanya adalah NDArays. Manfaat menggunakannya adalah, fungsi segera kembali, dan utas pengguna dapat melanjutkan eksekusi meskipun fakta bahwa penghitungan sebelumnya mungkin belum diselesaikan.
Kerja Mesin Eksekusi
Jika kita berbicara tentang cara kerja mesin eksekusi, itu membangun grafik komputasi. Grafik komputasi dapat menyusun ulang atau menggabungkan beberapa perhitungan, tetapi selalu mengikuti urutan ketergantungan.
Misalnya, jika ada manipulasi lain dengan 'X' yang dilakukan nanti dalam kode pemrograman, Mesin Eksekusi akan mulai melakukannya setelah hasil 'X' tersedia. Mesin eksekusi akan menangani beberapa pekerjaan penting bagi pengguna, seperti penulisan callback untuk memulai eksekusi kode berikutnya.
Di Apache MXNet, dengan bantuan NDArray, untuk mendapatkan hasil komputasi kita hanya perlu mengakses variabel yang dihasilkan. Aliran kode akan diblokir sampai hasil komputasi ditetapkan ke variabel yang dihasilkan. Dengan cara ini, ini meningkatkan kinerja kode sambil tetap mendukung mode pemrograman imperatif.
Mengonversi NDArray ke NumPy Array
Mari kita pelajari bagaimana kita dapat mengubah NDArray menjadi NumPy Array di MXNet.
Combining higher-level operator with the help of few lower-level operators
Terkadang, kita bisa merakit operator tingkat yang lebih tinggi dengan menggunakan operator yang ada. Salah satu contoh terbaiknya adalah, filenp.full_like()operator, yang tidak ada di NDArray API. Ini dapat dengan mudah diganti dengan kombinasi operator yang ada sebagai berikut:
from mxnet import nd
import numpy as np
np_x = np.full_like(a=np.arange(7, dtype=int), fill_value=15)
nd_x = nd.ones(shape=(7,)) * 15
np.array_equal(np_x, nd_x.asnumpy())
Output
Kami akan mendapatkan hasil yang serupa sebagai berikut -
True
Finding similar operator with different name and/or signature
Di antara semua operator, beberapa di antaranya memiliki nama yang sedikit berbeda, tetapi serupa dalam hal fungsionalitas. Contohnya adalahnd.ravel_index() dengan np.ravel()fungsi. Dengan cara yang sama, beberapa operator mungkin memiliki nama yang mirip, tetapi memiliki tanda tangan yang berbeda. Contohnya adalahnp.split() dan nd.split() mirip.
Mari kita pahami dengan contoh pemrograman berikut:
def pad_array123(data, max_length):
data_expanded = data.reshape(1, 1, 1, data.shape[0])
data_padded = nd.pad(data_expanded,
mode='constant',
pad_width=[0, 0, 0, 0, 0, 0, 0, max_length - data.shape[0]],
constant_value=0)
data_reshaped_back = data_padded.reshape(max_length)
return data_reshaped_back
pad_array123(nd.array([1, 2, 3]), max_length=10)
Output
Outputnya dinyatakan di bawah ini -
[1. 2. 3. 0. 0. 0. 0. 0. 0. 0.]
<NDArray 10 @cpu(0)>
Meminimalkan dampak dari memblokir panggilan
Dalam beberapa kasus, kami harus menggunakan keduanya .asnumpy() atau .asscalar()metode, tetapi ini akan memaksa MXNet untuk memblokir eksekusi, hingga hasilnya dapat diambil. Kami dapat meminimalkan dampak panggilan pemblokiran dengan menelepon.asnumpy() atau .asscalar() metode saat ini, ketika kami berpikir perhitungan nilai ini sudah dilakukan.
Contoh Implementasi
Example
from __future__ import print_function
import mxnet as mx
from mxnet import gluon, nd, autograd
from mxnet.ndarray import NDArray
from mxnet.gluon import HybridBlock
import numpy as np
class LossBuffer(object):
"""
Simple buffer for storing loss value
"""
def __init__(self):
self._loss = None
def new_loss(self, loss):
ret = self._loss
self._loss = loss
return ret
@property
def loss(self):
return self._loss
net = gluon.nn.Dense(10)
ce = gluon.loss.SoftmaxCELoss()
net.initialize()
data = nd.random.uniform(shape=(1024, 100))
label = nd.array(np.random.randint(0, 10, (1024,)), dtype='int32')
train_dataset = gluon.data.ArrayDataset(data, label)
train_data = gluon.data.DataLoader(train_dataset, batch_size=128, shuffle=True, num_workers=2)
trainer = gluon.Trainer(net.collect_params(), optimizer='sgd')
loss_buffer = LossBuffer()
for data, label in train_data:
with autograd.record():
out = net(data)
# This call saves new loss and returns previous loss
prev_loss = loss_buffer.new_loss(ce(out, label))
loss_buffer.loss.backward()
trainer.step(data.shape[0])
if prev_loss is not None:
print("Loss: {}".format(np.mean(prev_loss.asnumpy())))
Output
Outputnya dikutip di bawah ini:
Loss: 2.3373236656188965
Loss: 2.3656985759735107
Loss: 2.3613128662109375
Loss: 2.3197104930877686
Loss: 2.3054862022399902
Loss: 2.329197406768799
Loss: 2.318927526473999