Înapoi la catalog
Season 34 7 Episoade 26 min 2026

NumPy

v2.4 — Ediția 2026. Un curs audio care introduce NumPy, explicând performanța sa ridicată, array-urile multidimensionale și rolul său critic în ecosistemul Python. (v2.4, Ediția 2026)

Știința datelor Python Core
NumPy
Se redă acum
Click play to start
0:00
0:00
1
Identitatea de bază: ndarray
Acest episod acoperă obiectul ndarray, tipurile de date omogene și alocarea fixă a memoriei. Vei învăța de ce listele Python standard sunt ineficiente pentru calcule matematice la scară largă și cum NumPy rezolvă acest lucru coborând la nivelul codului C compilat.
3m 27s
2
Invocarea array-urilor: Creare și formă
Acest episod explorează modul corect de a crea array-uri multidimensionale folosind funcții intrinseci. Vei învăța cum să folosești instrumente precum zeros, arange și linspace pentru a genera instantaneu seturi de date.
3m 45s
3
Sub capotă: Memorie, strides și views
Acest episod analizează arhitectura internă a NumPy, concentrându-se pe buffer-ul de date și strides. Vei învăța de ce operațiuni precum slicing și transpunerea sunt practic instantanee, deoarece returnează memory views, nu copii.
4m 18s
4
Universal Functions: Matematică fără bucle
Acest episod acoperă Universal Functions (ufuncs) și modul în care acestea vectorizează operațiunile. Vei învăța să elimini complet buclele for din Python aplicând operații matematice element cu element și reduceri bazate pe axe.
3m 31s
5
Broadcasting: Magia formelor nepotrivite
Acest episod explică regulile exacte de Broadcasting. Vei învăța cum NumPy întinde conceptual array-urile cu forme nepotrivite, astfel încât să poată fi procesate împreună fără a irosi memorie.
4m 08s
6
Filtrare de precizie: Boolean Masking
Acest episod se concentrează pe boolean masking avansat pentru a filtra seturi de date complexe. Vei învăța cum să extragi puncte de date foarte specifice din array-uri masive folosind o logică condițională simplă.
3m 47s
7
Traducătorul universal: Interoperabilitate
Acest episod dezvăluie de ce NumPy rămâne coloana vertebrală a științei datelor în Python. Vei învăța cum DLPack și interfața array permit partajarea memoriei zero-copy între instrumente precum Pandas și PyTorch.
3m 43s

Episoade

1

Identitatea de bază: ndarray

3m 27s

Acest episod acoperă obiectul ndarray, tipurile de date omogene și alocarea fixă a memoriei. Vei învăța de ce listele Python standard sunt ineficiente pentru calcule matematice la scară largă și cum NumPy rezolvă acest lucru coborând la nivelul codului C compilat.

Descarcă
Salut, sunt Alex de la DEV STORIES DOT EU. NumPy, episodul 1 din 7. Lista standard din Python este extrem de flexibilă, dar în momentul în care încerci să faci operații matematice pe un milion de elemente, te lovești de un zid de performanță. Ajungi să plătești un cost uriaș din cauza pointerilor doar ca să înmulțești niște numere între ele. Soluția pentru acest bottleneck este motorul de bază al calculului științific din Python: ndarray. Pentru a înțelege de ce există ndarray, trebuie să te uiți la ce fac listele standard sub capotă. O listă Python nu stochează numere brute. Stochează pointeri. Fiecare pointer direcționează sistemul către o locație dispersată în memorie, unde trăiește un obiect Python complet. Dacă scrii un loop standard pentru a înmulți două secvențe de un milion de numere, interpretorul Python muncește extrem de mult. Pentru fiecare element în parte, el aduce pointerul, localizează obiectul, îi verifică tipul de date pentru a confirma că este într-adevăr un număr, face calculul matematic și stochează noul obiect. Să faci asta de un milion de ori introduce un overhead sever. Acest ciclu de pointer-chasing și type-checking este motivul pentru care loop-urile standard sunt pur și simplu prea lente pentru operații matematice mari. Ndarray, care vine de la N-dimensional array, renunță la această flexibilitate în schimbul vitezei brute. Partea de N-dimensional înseamnă că acest obiect poate reprezenta o secvență plată de numere, un grid bidimensional sau o matrice matematică multidimensională complexă. Indiferent de câte dimensiuni definești, sub capotă, funcționează după două reguli stricte. În primul rând, necesită tipuri de date omogene. Fiecare element dintr-un ndarray trebuie să fie exact de același tip, cum ar fi un float pe șaizeci și patru de biți. În al doilea rând, folosește o dimensiune fixă a memoriei. Când creezi un ndarray, NumPy rezervă un singur bloc continuu de memorie. Nu există pointeri. Numerele brute stau strâns împachetate unul lângă altul în memoria sistemului. Iată ideea cheie. Pentru că NumPy cunoaște tipul exact de date și memory layout-ul exact, poate ocoli complet interpretorul lent de Python. Când înmulțești două ndarray-uri care conțin un milion de numere, nu scrii un loop. Pur și simplu scrii array-ul A înmulțit cu array-ul B. Acest proces se numește vectorizare. NumPy preia comanda ta și predă calculul propriu-zis codului C precompilat. Codul C parcurge fulgerător acel bloc continuu de memorie la viteze hardware. Sare peste type-checking și pointer lookups pentru elementele individuale, deoarece memoria este perfect uniformă. Compromisul pentru acest boost masiv de viteză este rigiditatea structurală. Deoarece memoria este un bloc continuu, nu poți pur și simplu să dai append unui număr nou la un ndarray, așa cum faci cu o listă din Python. Dacă ai nevoie de un array mai mare, NumPy trebuie, în general, să aloce un bloc de memorie complet nou și să copieze datele vechi în el. Construiești containerul la dimensiunea exactă de care ai nevoie, iar apoi rulezi operațiunile pe întregul bloc deodată. Lista standard din Python este o colecție de obiecte izolate, răspândite prin memorie. Ndarray-ul din NumPy este un bloc dens și uniform de date brute, conceput pentru a fi procesat instantaneu de cod C optimizat. Dacă îți plac aceste episoade și vrei să susții podcastul, poți căuta DevStoriesEU pe Patreon. Asta e tot pentru acest episod. Mulțumesc că ai ascultat și continuă să construiești!
2

Invocarea array-urilor: Creare și formă

3m 45s

Acest episod explorează modul corect de a crea array-uri multidimensionale folosind funcții intrinseci. Vei învăța cum să folosești instrumente precum zeros, arange și linspace pentru a genera instantaneu seturi de date.

Descarcă
Salut, sunt Alex de la DEV STORIES DOT EU. NumPy, episodul 2 din 7. În data science, rareori tastezi datele manual. În schimb, trebuie să generezi grile vaste și goale, plus intervale numerice, dintr-o singură comandă. Hai să vorbim despre funcțiile intrinseci care îți permit să creezi array-uri de la zero și să le controlezi structura. Mai întâi, o scurtă corecție legată de crearea manuală. Când convertești o listă standard din Python într-un array folosind funcția de bază array, o greșeală comună e să pasezi mai multe argumente separate pentru a crea mai multe dimensiuni. Funcția așteaptă o singură secvență. Ca să faci un array bidimensional, pasezi o listă care conține alte liste, nu două liste separate. Fiecare array pe care îl creezi conține metadata structurală. Două proprietăți contează cel mai mult aici. Prima este ndim, care îți spune numărul de axe, sau dimensiuni, pe care le are array-ul. O secvență plată are un ndim de unu, în timp ce o grilă plată are un ndim de doi. A doua proprietate este shape. Shape este un tuple de numere întregi care indică dimensiunea exactă a array-ului pe fiecare dimensiune. Dacă ai o matrice cu două rânduri și trei coloane, shape-ul ei este doi pe trei. Lungimea acestui tuple shape va fi mereu egală cu valoarea ndim. Crearea de array-uri din liste existente e ok pentru teste mici, dar munca reală necesită generarea de array-uri programatic. Dacă ai nevoie de un placeholder pe care să-l umpli cu date mai târziu, folosești funcțiile zeros sau ones. Pur și simplu pasezi un tuple shape acestor funcții, iar ele returnează un array cu exact acea structură, populat în întregime cu zerouri sau cu unu. By default, aceste funcții creează numere de tip float, dar poți suprascrie asta specificând un alt data type. Când ai nevoie de o secvență de numere, NumPy îți oferă două tool-uri principale. Primul este arange, care funcționează cam la fel ca funcția standard range din Python. Îi dai o valoare de start, o valoare de stop și o dimensiune a pasului. El generează un array de numere spațiate de acel pas. Deși arange e excelent pentru numere întregi, folosirea lui cu pași de tip float poate cauza rezultate imprevizibile din cauza modului în care calculatoarele gestionează precizia zecimală. Numărul de elemente pe care le primești înapoi poate varia ușor în funcție de erori microscopice de rotunjire. Asta ne aduce la linspace, care rezolvă problema preciziei pentru float-uri. În loc să definești dimensiunea pasului, definești numărul exact de elemente pe care le vrei. Îi dai lui linspace o valoare de start, o valoare de stop și numărul total de puncte. NumPy calculează spațierea exactă pentru tine. Ia în considerare un scenariu în care evaluezi o funcție matematică pe un anumit interval. Vrei să calculezi funcția pe o grilă fină de coordonate între zero și unu. Folosind linspace, poți genera exact o sută de coordonate distanțate uniform pe acel interval. Obții un array unidimensional perfect distribuit, garantând că atât limitele de start, cât și cele de stop sunt incluse. Aici devine interesant. Distincția dintre aceste două generatoare de secvențe îți dictează workflow-ul. Folosește arange când dimensiunea exactă a pasului contează, cum ar fi numărarea de numere întregi din doi în doi, dar folosește mereu linspace când lucrezi cu float-uri și intervale, ca să poți garanta exact câte data points obții și să atingi cu precizie limitele. Mersi că m-ai ascultat — ne auzim data viitoare.
3

Sub capotă: Memorie, strides și views

4m 18s

Acest episod analizează arhitectura internă a NumPy, concentrându-se pe buffer-ul de date și strides. Vei învăța de ce operațiuni precum slicing și transpunerea sunt practic instantanee, deoarece returnează memory views, nu copii.

Descarcă
Salut, sunt Alex de la DEV STORIES DOT EU. NumPy, episodul 3 din 7. Ai o matrice de un miliard de pixeli și trebuie să-i inversezi rândurile și coloanele. Dacă faci asta în Python standard, mașina ta se va bloca în timp ce copiază gigabytes de date. În NumPy, această operațiune se întâmplă instant. Reordonarea acelor pixeli nu mută, de fapt, niciun byte de memorie. Asta se întâmplă datorită modului în care NumPy gestionează memoria, acei strides și views, în fundal. Ca să înțelegi de ce NumPy este atât de rapid, trebuie să te uiți la structura internă a unui array. Un array NumPy nu este un singur obiect monolitic. Este strict separat în două bucăți. Prima parte este data buffer-ul. Acesta este un bloc contiguu, plat, de memorie raw. Este doar o linie unidimensională de bytes care stă în RAM. Buffer-ul raw nu știe absolut nimic despre rânduri, coloane sau dimensiuni. A doua parte este metadata. Acesta este un header mic, implementat intern ca o structură C, care îi spune lui NumPy cum să interpreteze acea linie raw de bytes. Metadata conține un pointer către începutul data buffer-ului, data type-ul, shape-ul array-ului și acei strides. Strides reprezintă mecanismul care transformă o linie plată de memorie într-o grilă multidimensională. Un stride este pur și simplu numărul de bytes peste care computerul trebuie să sară în memorie pentru a găsi următorul element pe o anumită axă. Să presupunem că ai un array bidimensional de întregi pe 64 de biți. Fiecare întreg ocupă opt bytes. Ca să te muți cu o coloană la dreapta, stride-ul ar putea fi de opt bytes. Dar ca să cobori la rândul următor, stride-ul ar putea fi de optzeci de bytes, pentru că trebuie să sară peste un rând întreg de date din buffer-ul raw ca să găsească începutul următorului. Mulți developeri presupun că atunci când iei un slice dintr-un array, sistemul alocă memorie nouă și copiază datele selectate. Asta este incorect. Când ceri un slice, NumPy lasă data buffer-ul raw complet neatins. În schimb, creează un nou header de metadata. Acest nou header pointează către exact același bloc de memorie, dar schimbă pointer-ul de start și modifică acei strides pentru a sări peste elementele pe care le-ai exclus. Asta se numește un view. Aici este ideea cheie. Pentru că datele raw și metadata sunt ținute separat, operațiunile care schimbă shape-ul sau ordinea array-ului sunt aproape complet gratuite. Gândește-te din nou la transpunerea acelei matrice masive de un miliard de pixeli. NumPy nu ia datele și le rearanjează fizic. Pur și simplu face swap la valorile de stride în noul header de metadata. Numărul de bytes peste care săreai ca să găsești următorul rând devine numărul peste care sari ca să găsești următoarea coloană. O structură de array complet diferită este returnată codului tău, dar este doar un view care se uită la exact aceeași memorie fizică. Această separare este fundamentul eficienței de memorie a NumPy. Poți tăia un dataset masiv în zeci de slice-uri care se suprapun, le poți pasa în funcții diferite și vei consuma zero memorie extra pentru datele în sine. Generezi doar headere de metadata minuscule. Totuși, asta înseamnă că partajezi state-ul. Modificarea unei valori dintr-un slice va altera array-ul original, pentru că există un singur data buffer real sub toate acestea. Separarea acelor bytes raw de regulile care îi guvernează înseamnă că cele mai grele transformări de date ale tale sunt adesea doar niște swap-uri lightweight de metadata. Asta e tot pentru acest episod. Mersi că ai ascultat și continuă să construiești!
4

Universal Functions: Matematică fără bucle

3m 31s

Acest episod acoperă Universal Functions (ufuncs) și modul în care acestea vectorizează operațiunile. Vei învăța să elimini complet buclele for din Python aplicând operații matematice element cu element și reduceri bazate pe axe.

Descarcă
Salut, sunt Alex de la DEV STORIES DOT EU. NumPy, episodul 4 din 7. Dacă te trezești vreodată scriind un for-loop pentru a înmulți numere dintr-un array, oprește-te. Asta înseamnă că plătești acel overhead al interpretorului Python pentru fiecare element în parte, iar codul tău rulează de o sută de ori mai lent decât ar trebui. Soluția este să folosești funcții universale pentru a face calcule matematice fără loop-uri. O greșeală comună este să încerci să pasezi un array întreg unei funcții din modulul math standard din Python. Dacă pasezi un milion de citiri de la senzori către math dot sine, Python va arunca o eroare. Modulul math standard înțelege doar valori scalare individuale. Pentru a procesa un array, în mod normal ar trebui să scrii un loop. Dar Python este un limbaj dinamic. În interiorul unui loop, interpretorul evaluează acel data type la fiecare iterație înainte să calculeze rezultatul. Când procesezi dataset-uri masive, acele mici pauze de type-checking se adună și creează un bottleneck de performanță semnificativ. O funcție universală, sau ufunc, rezolvă asta operând automat pe array-uri, element cu element. Când apelezi un ufunc, NumPy împinge execuția loop-ului în cod C compilat. Pentru că array-urile NumPy au un singur data type uniform, codul C nu trebuie să facă pauze și să verifice tipurile. El iterează peste blocuri contigue de memorie și calculează rezultatul cât de repede îi permite procesorul. Hai să ne uităm la un scenariu concret. Ai un array care conține mii de citiri de la senzori de mediu și trebuie să le aplici tuturor o transformare matematică, simultan. În loc să scrii un loop, pur și simplu pasezi întregul array într-o funcție universală precum numpy dot exp sau numpy dot sin. Acel ufunc îți preia array-ul de input, rulează acel loop rapid la nivel de C pe fiecare element în parte și returnează un array complet nou, populat cu citirile transformate. Asta e partea care contează. Ufunc-urile fac mai mult decât simple transformări element cu element. Ele conțin metode built-in pentru a reduce datele, ocolind complet Python pentru agregări. Cea mai comună este metoda reduce. Să presupunem că ai aplicat transformarea matematică, iar acum ai nevoie de suma totală a întregului array. Apelezi metoda reduce direct pe ufunc-ul de adunare. Scrii numpy dot add dot reduce și îi pasezi array-ul tău. Metoda reduce aplică operația de adunare de la bază primelor două elemente. Ia acea sumă, o adună la al treilea element și continuă acest pattern până când întregul array este redus la o singură valoare scalară. Dacă datele tale au mai multe dimensiuni, poți controla cum are loc această reducere. Dacă citirile senzorilor tăi formează un grid bidimensional, unde rândurile sunt senzori diferiți, iar coloanele sunt timestamp-uri individuale, reducerea întregului grid la un singur număr distruge acea structură. Oferind un argument axis, controlezi direcția operației. Dacă îi spui metodei reduce să opereze de-a lungul axis zero, ea reduce rândurile, lăsându-te cu un array care conține suma tuturor senzorilor la fiecare timestamp individual. De fiecare dată când lași o funcție universală să gestioneze iterația nativ, schimbi loop-urile lente din Python pe o execuție C optimizată hardware. Mulțumesc că m-ai ascultat. Pe data viitoare!
5

Broadcasting: Magia formelor nepotrivite

4m 08s

Acest episod explică regulile exacte de Broadcasting. Vei învăța cum NumPy întinde conceptual array-urile cu forme nepotrivite, astfel încât să poată fi procesate împreună fără a irosi memorie.

Descarcă
Salut, sunt Alex de la DEV STORIES DOT EU. NumPy, episodul 5 din 7. Ce se întâmplă când încerci să înmulțești o matrice tridimensională de un milion de pixeli cu un singur array mic de trei numere? În multe limbaje stricte, primești o eroare de shape mismatch. În NumPy, pur și simplu funcționează. Acest comportament se numește broadcasting. Broadcasting descrie modul în care NumPy tratează array-urile cu shape-uri diferite în timpul operațiilor aritmetice. Ia array-ul mai mic și îl întinde conceptual peste cel mai mare, astfel încât shape-urile lor să se alinieze perfect. Ascultătorii cred adesea în mod eronat că această întindere copiază fizic datele pentru a construi în memorie un array nou, care să se potrivească. Nu se întâmplă asta. NumPy gestionează implicit această aliniere la nivel de C. Iterează peste aceleași elemente de mai multe ori, cu zero memory overhead, ceea ce face ca broadcasting-ul să fie incredibil de rapid și extrem de eficient. Pentru a-l folosi, trebuie să înțelegi cum decide NumPy dacă două array-uri sunt compatibile. Nu se uită la numărul total de elemente. Se uită la tuple-urile de shape. NumPy aliniază shape-urile celor două array-uri și le compară începând de la trailing dimensions — cele din extrema dreaptă — și continuă spre stânga. Două dimensiuni sunt compatibile dacă îndeplinesc una dintre cele două condiții stricte. Trebuie să fie exact egale sau una dintre ele trebuie să fie numărul unu. Dacă niciuna dintre condiții nu este îndeplinită în orice moment al comparației, NumPy aruncă un ValueError și operația eșuează. Să aplicăm asta pe un scenariu concret. Lucrezi cu o imagine RGB. O încarci într-un array NumPy cu un shape de 256 pe 256 pe 3. Acel 3 reprezintă canalele de culoare roșu, verde și albastru de la sfârșitul shape-ului. Acum, trebuie să corectezi culorile acestei imagini scalând diferit fiecare canal de culoare. Definești un array unidimensional care conține trei ponderi de corecție a culorii. Shape-ul acestui array este doar 3. Când înmulțești array-ul masiv al imaginii cu array-ul minuscul de ponderi, NumPy aplică regula de la dreapta la stânga. Plasează shape-ul imaginii, 256 pe 256 pe 3, deasupra shape-ului ponderilor, care este doar 3. Începând din extrema dreaptă, sunt comparate trailing dimensions. Ambele sunt 3. Pentru că sunt egale, sunt compatibile. Apoi, NumPy se mută spre stânga. Array-ul imaginii are o dimensiune de 256, dar array-ul ponderilor a rămas complet fără dimensiuni. Aici intervine a doua parte a regulii. Când un array are mai puține dimensiuni decât celălalt, NumPy adaugă implicit cifra unu la începutul shape-ului său, până când se potrivesc în lungime. Shape-ul array-ului de ponderi este tratat ca 1 pe 1 pe 3. Acum comparația continuă. Imaginea are o dimensiune de 256, iar array-ul de ponderi are acum o dimensiune de 1. Deoarece una dintre ele este 1, sunt compatibile. Array-ul de ponderi este întins conceptual pe cele 256 de rânduri. Asta se întâmplă din nou pentru următoarea dimensiune. Shape-urile se aliniază, iar NumPy aplică cele trei ponderi de culoare pe toți cei șaizeci și cinci de mii de pixeli, fără probleme. Asta e partea care contează. Regula funcționează doar de la dreapta la stânga. Dacă ai un array bidimensional cu shape-ul 5 pe 4 și încerci să aduni un array cu shape-ul 5, ai putea crede că se va întinde pe coloane. Nu se va întâmpla asta. Începând de la dreapta, NumPy compară 4 și 5. Nu sunt egale și niciuna nu este 1. Operația eșuează instantaneu. Pentru a funcționa, ar trebui să îi dai reshape celui de-al doilea array la 5 pe 1 mai întâi. Broadcasting-ul îți permite să scrii cod curat, fără bucle, care se execută la viteze de compilare. Regula de aur este întotdeauna trailing dimensions primele: ele trebuie să se potrivească exact, sau una dintre ele trebuie să fie 1. Mersi că ai ascultat. Pe data viitoare!
6

Filtrare de precizie: Boolean Masking

3m 47s

Acest episod se concentrează pe boolean masking avansat pentru a filtra seturi de date complexe. Vei învăța cum să extragi puncte de date foarte specifice din array-uri masive folosind o logică condițională simplă.

Descarcă
Salut, sunt Alex de la DEV STORIES DOT EU. NumPy, episodul 6 din 7. Extragerea fiecărui număr negativ dintr-un array cu un miliard de elemente nu este o problemă de căutare. Nu ar trebui să necesite un loop și cu siguranță nu ar trebui să îți încetinească aplicația. Aici folosim filtrarea de precizie: boolean masking. Slicing-ul de bază extrage bucăți de date clare și previzibile. Dar datele din lumea reală sunt dezordonate. Rareori vrei doar primele zece elemente. Vrei elemente specifice în funcție de o condiție logică, iar aceste elemente ar putea fi împrăștiate aleatoriu prin tot dataset-ul tău. În NumPy, extragerea datelor în acest mod se numește advanced indexing, iar boolean masking este una dintre cele mai puternice forme ale sale. Ia un array masiv de înregistrări de temperatură. Trebuie să izolezi doar valorile care scad sub zero grade. În loc să scrii un loop ca să verifici fiecare înregistrare în parte, folosești un mask. Un mask este un array de valori boolean, adică True sau False. Partea crucială este că acest array boolean are exact același shape ca array-ul tău de date original. Îl creezi aplicând o condiție de tip mai mic decât zero direct pe array. NumPy evaluează instantaneu fiecare element. Dacă o temperatură este sub zero, mask-ul înregistrează un True exact în acea poziție. Dacă temperatura este zero sau mai mare, înregistrează un False. Odată ce ai acest mask, îl aplici înapoi pe array-ul original, pasându-l exact acolo unde ai pune în mod normal un index. NumPy citește mask-ul, alege fiecare element unde mask-ul este True și elimină restul. Operația produce un array unidimensional complet nou, care nu conține nimic altceva decât temperaturile tale sub zero. Totul se întâmplă într-un singur pas, delegat în spate către un cod C extrem de optimizat. Fii atent la următoarea distincție, pentru că încurcă foarte mulți developeri. Trebuie să știi exact ce îți returnează NumPy atunci când filtrezi date. Slicing-ul de bază returnează un view. Dacă faci slice pe primele zece elemente ale unui array și le modifici, array-ul original se schimbă. Boolean masking-ul se comportă complet diferit. Deoarece boolean masking-ul este o formă de advanced indexing, returnează întotdeauna un copy al datelor, niciodată un view. Motivul este arhitectura memoriei. Când faci slice, NumPy modifică doar pointerii către un bloc de memorie continuu, deja existent. Dar când aplici un boolean mask, elementele pe care le selectezi sunt complet arbitrare. Nu mai stau perfect unul lângă altul în memorie. NumPy trebuie să le adune și să aloce spațiu nou pentru a stoca rezultatul. Asta înseamnă că, dacă îți modifici noul array filtrat cu temperaturi sub zero, dataset-ul tău original rămâne complet neatins. Poți, de asemenea, să faci chain la aceste condiții. Dacă ai nevoie de temperaturi sub zero grade, dar strict peste minus zece grade, combini cele două condiții logice. NumPy evaluează logica combinată element cu element și construiește un singur mask precis. Când aplici un boolean mask, dai la schimb eficiența memoriei unui view pentru o precizie absolută de filtrare, obținând un copy impecabil și independent cu exact datele pe care le-ai cerut. Asta e tot pentru acest episod. Mulțumesc că m-ai ascultat și continuă să construiești!
7

Traducătorul universal: Interoperabilitate

3m 43s

Acest episod dezvăluie de ce NumPy rămâne coloana vertebrală a științei datelor în Python. Vei învăța cum DLPack și interfața array permit partajarea memoriei zero-copy între instrumente precum Pandas și PyTorch.

Descarcă
Salut, sunt Alex de la DEV STORIES DOT EU. NumPy, episodul 7 din 7. Având în vedere că framework-urile GPU moderne duc greul în machine learning, ai putea crede că NumPy devine învechit. Ai putea chiar să presupui că conversia unui CPU tensor din PyTorch într-un array NumPy necesită o copiere lentă în memorie, care îți încetinește pipeline-ul. Niciuna nu e adevărată. Realitatea este că NumPy acționează ca Traducătorul Universal: Interoperabilitatea, ținând laolaltă întregul ecosistem de date din Python. Gândește-te la un pipeline standard de machine learning. Folosești Pandas pentru a încărca și curăța un dataset tabelar masiv. Extragi acele valori în NumPy pentru a aplica un filtru matematic specializat. În cele din urmă, pasezi acele date filtrate în PyTorch pentru a antrena o rețea neuronală. Dacă fiecare dintre aceste librării și-ar izola datele, trecerea de la un pas la altul ar însemna duplicarea întregului dataset în memorie iar și iar. Ți-ai epuiza memoria RAM și ai pierde timp de procesare doar mutând bytes de colo colo. În schimb, prin magia interoperabilității, datele nu se mută de fapt niciodată. Pandas, NumPy și PyTorch pur și simplu împart exact același pointer de memorie subiacent. Când PyTorch citește datele, se uită la exact aceleași adrese de memorie fizică pe care Pandas le-a alocat inițial. Acest zero copy sharing este făcut posibil de protocoale standard de memorie. Cel fundamental este array interface. Dacă un obiect Python expune această interfață, practic predă un mic dicționar de metadata. Aceste metadata îi spun lui NumPy exact unde încep datele raw în memorie, ce shape au și ce data type conțin. Când apelezi o funcție NumPy pe un obiect compatibil, NumPy citește acele instrucțiuni și își pune propria structură de array în jurul blocului de memorie existent. Nu creează un array nou; ci doar creează un nou view asupra datelor vechi. Iată ideea cheie. Originalul array interface a fost conceput în principal pentru memoria standard a sistemului. Pe măsură ce data science s-a mutat pe acceleratoare hardware, ecosistemul a avut nevoie de o modalitate de a partaja datele care stau pe GPU-uri sau cipuri custom, fără a le ruta înapoi prin CPU. Asta a dus la adoptarea DLPack. DLPack este un standard modern și open pentru partajarea de array-uri multidimensionale între diferite framework-uri. Definește o structură stabilă pe care orice librărie o poate produce și consuma. Dacă ai un tensor într-un framework precum PyTorch sau JAX, îl poți exporta folosind protocolul DLPack. NumPy îl poate apoi prelua fără probleme folosind funcția sa dedicată from dlpack. Deși NumPy în sine operează în mare parte pe CPU, suportul său pentru DLPack înseamnă că poate acționa ca un hub central de rutare. Poți transfera un obiect DLPack dintr-un framework de deep learning către NumPy, sau din NumPy înapoi către un framework, totul fără o duplicare costisitoare a datelor. NumPy a încetat de mult să mai fie doar o librărie de matematică. Este standardul invizibil de memorie care împiedică ecosistemul de date din Python să se fragmenteze în insule izolate și incompatibile. Te încurajez să explorezi documentația oficială, să încerci aceste conversii zero copy hands on în propriul tău terminal, sau să vizitezi devstories dot eu pentru a sugera subiecte pentru viitoarele noastre serii. Asta e tot pentru acest episod. Mulțumesc că m-ai ascultat și continuă să construiești!