User Tools

Site Tools


ro:course:preliminaries:ndarray

Manipularea Datelor

Pentru a face ceva, avem nevoie de o modalitate de a stoca și manipula date. În general, există două lucruri importante pe care trebuie să le facem cu datele: (i) să le achiziționăm; și (ii) să le procesăm odată ce sunt în interiorul computerului. Nu are rost să achiziționăm date fără o modalitate de a le stoca, așa că pentru a începe, să ne murdărim mâinile cu tablouri $n$-dimensionale, pe care le numim și tensori.

Dacă știți deja pachetul de calcul științific NumPy, acest lucru va fi floare la ureche. Pentru toate cadrele moderne de deep learning, clasa tensor (`ndarray` în MXNet, `Tensor` în PyTorch și TensorFlow) seamănă cu `ndarray` din NumPy, cu câteva caracteristici ucigașe adăugate. În primul rând, clasa tensor acceptă diferențierea automată. În al doilea rând, folosește GPU-urile pentru a accelera calculul numeric, în timp ce NumPy rulează doar pe procesoare. Aceste proprietăți fac rețelele neuronale atât ușor de codificat, cât și rapid de rulat.

Noțiuni de Bază

Pentru a începe, importăm modulele `np` (`numpy`) și `npx` (`numpy_extension`) din MXNet. Aici, modulul `np` include funcții acceptate de NumPy, în timp ce modulul `npx` conține un set de extensii dezvoltate pentru a împuternici deep learning-ul într-un mediu asemănător NumPy. Când folosim tensori, invocăm aproape întotdeauna funcția `set_np`: aceasta este pentru compatibilitatea procesării tensorilor de către alte componente ale MXNet.

Pentru a începe, importăm biblioteca PyTorch. Rețineți că numele pachetului este `torch`.

Pentru a începe, importăm `tensorflow`. Pentru concizie, practicienii atribuie adesea aliasul `tf`.

from mxnet import np, npx
npx.set_np()
import torch
import tensorflow as tf
import jax
from jax import numpy as jnp

Un tensor reprezintă un tablou (posibil multidimensional) de valori numerice. În cazul unidimensional, adică atunci când este necesară o singură axă pentru date, un tensor se numește vector. Cu două axe, un tensor se numește matrice. Cu $k > 2$ axe, renunțăm la numele specializate și ne referim pur și simplu la obiect ca la un tensor de ordinul $k$.

MXNet, PyTorch și TensorFlow oferă o varietate de funcții pentru crearea de noi tensori pre-populați cu valori. De exemplu, invocând `arange(n)`, putem crea un vector de valori spațiate uniform, începând de la 0 (inclus) și terminând la `n` (neinclus). Implicit, dimensiunea intervalului este $1$. Cu excepția cazului în care se specifică altfel, noii tensori sunt stocați în memoria principală și desemnați pentru calcul bazat pe CPU.

# MXNet
x = np.arange(12)
x
# PyTorch
x = torch.arange(12, dtype=torch.float32)
x
# TensorFlow
x = tf.range(12, dtype=tf.float32)
x
# JAX
x = jnp.arange(12)
x

Fiecare dintre aceste valori se numește un element al tensorului. Tensorul `x` conține 12 elemente. Putem inspecta numărul total de elemente dintr-un tensor prin atributul său `size` (MXNet), metoda `numel` (PyTorch) sau funcția `tf.size` (TensorFlow).

x.size      # MXNet
x.numel()   # PyTorch
tf.size(x)  # TensorFlow

Putem accesa forma unui tensor (lungimea de-a lungul fiecărei axe) inspectând atributul său `shape`. Deoarece avem de-a face cu un vector aici, `shape` conține doar un singur element și este identic cu dimensiunea.

x.shape

Putem schimba forma unui tensor fără a-i modifica dimensiunea sau valorile, invocând `reshape`. De exemplu, putem transforma vectorul nostru `x` a cărui formă este $(12,)$ într-o matrice $X$ cu forma $(3, 4)$. Acest nou tensor păstrează toate elementele, dar le reconfigurează într-o matrice. Observați că elementele vectorului nostru sunt așezate rând cu rând și astfel $x[3] == X[0, 3]$.

X = x.reshape(3, 4)
X

Rețineți că specificarea fiecărei componente de formă pentru `reshape` este redundantă. Deoarece știm deja dimensiunea tensorului nostru, putem calcula o componentă a formei date fiind restul. De exemplu, dat fiind un tensor de mărimea $n$ și forma țintă $(h, w)$, știm că $w = n/h$. Pentru a deduce automat o componentă a formei, putem plasa un $-1$ pentru componenta formei care ar trebui dedusă automat. În cazul nostru, în loc să apelăm `x.reshape(3, 4)`, am fi putut apela echivalent `x.reshape(-1, 4)` sau `x.reshape(3, -1)`.

Practicienii trebuie adesea să lucreze cu tensori inițializați pentru a conține toți 0 sau 1. Putem construi un tensor cu toate elementele setate la 0 și o formă de $(2, 3, 4)$ prin funcția `zeros`.

np.zeros((2, 3, 4))    # MXNet
torch.zeros((2, 3, 4)) # PyTorch
tf.zeros((2, 3, 4))    # TensorFlow
jnp.zeros((2, 3, 4))   # JAX

În mod similar, putem crea un tensor cu toate valorile 1 invocând `ones`.

Adesea dorim să eșantionăm fiecare element aleatoriu (și independent) dintr-o distribuție de probabilitate dată. De exemplu, parametrii rețelelor neuronale sunt adesea inițializați aleatoriu. Următorul fragment creează un tensor cu elemente extrase dintr-o distribuție gaussiană (normală) standard cu media 0 și deviația standard 1.

torch.randn(3, 4)

În cele din urmă, putem construi tensori furnizând valorile exacte pentru fiecare element prin furnizarea de liste Python (posibil imbricate) care conțin literali numerici.

torch.tensor([[2, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])

Indexare și Feliere (Slicing)

Ca și în cazul listelor Python, putem accesa elementele tensorului prin indexare (începând cu 0). Pentru a accesa un element pe baza poziției sale relative la sfârșitul listei, putem folosi indexarea negativă. Felierea se poate face prin `X[start:stop]`, unde valoarea returnată include primul indice (`start`) dar nu și ultimul (`stop`).

X[-1], X[1:3]

`Tensors` în TensorFlow sunt imuabili. `Variables` sunt containere mutabile care acceptă atribuiri.

X[1, 2] = 17 # PyTorch / MXNet

Operații

Printre cele mai utile operații sunt operațiile elementwise (element cu element). În notația matematică, desemnăm operatorii scalari unari prin semnătura $f: \mathbb{R} \rightarrow \mathbb{R}$. Majoritatea operatorilor standard, inclusiv $e^x$, pot fi aplicați element cu element.

torch.exp(x)

La fel, desemnăm operatorii scalari binari prin semnătura $f: \mathbb{R}, \mathbb{R} \rightarrow \mathbb{R}$. Dați fiind oricare doi vectori $\mathbf{u}$ și $\mathbf{v}$ de aceeași formă, putem produce un vector $\mathbf{c} = F(\mathbf{u}, \mathbf{v})$ setând $c_i \gets f(u_i, v_i)$ pentru toți $i$.

x = torch.tensor([1.0, 2, 4, 8])
y = torch.tensor([2, 2, 2, 2])
x + y, x - y, x * y, x / y, x ** y

De asemenea, putem concatena mai mulți tensori, stivuindu-i cap la cap pentru a forma unul mai mare.

torch.cat((X, Y), dim=0), torch.cat((X, Y), dim=1)

Însumarea tuturor elementelor din tensor produce un tensor cu un singur element.

X.sum()

Difuzare (Broadcasting)

Chiar și atunci când formele diferă, putem efectua totuși operații binare element cu element invocând mecanismul de difuzare. Difuzarea funcționează conform următoarei proceduri în doi pași: (i) extinderea uneia sau a ambelor matrice prin copierea elementelor de-a lungul axelor cu lungimea 1, astfel încât cei doi tensori să aibă aceeași formă; (ii) efectuarea unei operații element cu element.

a = torch.arange(3).reshape((3, 1))
b = torch.arange(2).reshape((1, 2))
a + b

Economisirea Memoriei

Rularea operațiilor poate determina alocarea de memorie nouă. Putem demonstra acest lucru cu funcția `id()` din Python.

before = id(Y)
Y = Y + X
id(Y) == before # False

Putem efectua actualizări in place (pe loc) folosind notația feliei: `Y[:] = <expresie>` sau `Y += X`.

Z = torch.zeros_like(Y)
Z[:] = X + Y

Conversia la Alte Obiecte Python

Conversia la un tensor NumPy (`ndarray`) sau invers este ușoară. În PyTorch, rezultatul convertit partajează memoria dacă este pe CPU.

A = X.numpy()
B = torch.from_numpy(A)

Pentru a converti un tensor de mărimea 1 într-un scalar Python, putem invoca funcția `item`.

a = torch.tensor([3.5])
a.item(), float(a), int(a)

Rezumat

Clasa tensor este interfața principală pentru stocarea și manipularea datelor în bibliotecile de deep learning. Tensorii oferă o varietate de funcționalități, inclusiv rutine de construcție; indexare și feliere; operații matematice de bază; difuzare; atribuire eficientă a memoriei; și conversie la și de la alte obiecte Python.

Exerciții

1. Rulați codul din această secțiune. Schimbați instrucțiunea condițională `X == Y` în `X < Y` sau `X > Y`.
2. Înlocuiți cei doi tensori din mecanismul de difuzare cu tensori tridimensionali.

Discuții Notebook

ro/course/preliminaries/ndarray.txt · Last modified: by 127.0.0.1

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki