====== Calculul Diferențial și Integral ====== Multă vreme, modul de calcul al ariei unui cerc a rămas un mister. Apoi, în Grecia Antică, matematicianul Arhimede a venit cu ideea inteligentă de a înscrie o serie de poligoane cu un număr tot mai mare de vârfuri în interiorul unui cerc (). Pentru un poligon cu $n$ vârfuri, obținem $n$ triunghiuri. Înălțimea fiecărui triunghi se apropie de raza $r$ pe măsură ce partiționăm cercul mai fin. În același timp, baza sa se apropie de $2 \pi r/n$, deoarece raportul dintre arc și secantă se apropie de 1 pentru un număr mare de vârfuri. Astfel, aria poligonului se apropie de $n \cdot r \cdot \frac{1}{2} (2 \pi r/n) = \pi r^2$. {{:wiki:img:polygon-circle.svg|Găsirea ariei unui cerc ca procedură limită.}} Această procedură limită se află la baza atât a //calculului diferențial//, cât și a //calculului integral//. Primul ne poate spune cum să creștem sau să scădem valoarea unei funcții manipulându-i argumentele. Acest lucru este util pentru //problemele de optimizare// cu care ne confruntăm în deep learning, unde ne actualizăm în mod repetat parametrii pentru a micșora funcția de pierdere. Optimizarea abordează modul de potrivire a modelelor noastre la datele de antrenament, iar calculul diferențial este condiția sa prealabilă cheie. Totuși, nu uitați că scopul nostru final este să performăm bine pe date //nevăzute anterior//. Această problemă se numește //generalizare// și va fi un punct cheie al altor capitole. %matplotlib inline from d2l import torch as d2l from matplotlib_inline import backend_inline import numpy as np ===== Derivate și Diferențiere ===== Mai simplu spus, o //derivată// este rata de schimbare a unei funcții în raport cu modificările argumentelor sale. Derivatele ne pot spune cât de rapid ar crește sau ar scădea o funcție de pierdere dacă am //crește// sau //scădea// fiecare parametru cu o cantitate infinitezimal de mică. Formal, pentru funcțiile $f: \mathbb{R} \rightarrow \mathbb{R}$, care mapează de la scalari la scalari, [**derivata lui $f$ într-un punct $x$ este definită ca**] (**$$f'(x) = \lim_{h \rightarrow 0} \frac{f(x+h) - f(x)}{h}.$$**) Acest termen din partea dreaptă se numește //limită// și ne spune ce se întâmplă cu valoarea unei expresii pe măsură ce o variabilă specificată se apropie de o anumită valoare. Această limită ne spune la ce converge raportul dintre o perturbare $h$ și schimbarea valorii funcției $f(x + h) - f(x)$ pe măsură ce îi micșorăm dimensiunea la zero. Când $f'(x)$ există, se spune că $f$ este //diferențiabilă// în $x$; și când $f'(x)$ există pentru toate $x$ dintr-o mulțime, de exemplu, intervalul $[a,b]$, spunem că $f$ este diferențiabilă pe această mulțime. Nu toate funcțiile sunt diferențiabile, inclusiv multe pe care dorim să le optimizăm, cum ar fi acuratețea și aria de sub curba caracteristică de operare (AUC). Cu toate acestea, deoarece calcularea derivatei pierderii este un pas crucial în aproape toți algoritmii pentru antrenarea rețelelor neuronale profunde, optimizăm adesea un //surogat// diferențiabil în schimb. Putem interpreta derivata $f'(x)$ ca rata //instantanee// de schimbare a lui $f(x)$ în raport cu $x$. Să dezvoltăm o anumită intuiție cu un exemplu. (**Definiți $u = f(x) = 3x^2-4x$.**) def f(x): return 3 * x ** 2 - 4 * x [**Setând $x=1$, vedem că $\frac{f(x+h) - f(x)}{h}$**] (**se apropie de $2$ pe măsură ce $h$ se apropie de $0$.**) Deși acestui experiment îi lipsește rigoarea unei demonstrații matematice, putem vedea rapid că într-adevăr $f'(1) = 2$. for h in 10.0**np.arange(-1, -6, -1): print(f'h={h:.5f}, numerical limit={(f(1+h)-f(1))/h:.5f}') Există mai multe convenții de notație echivalente pentru derivate. Dat fiind $y = f(x)$, următoarele expresii sunt echivalente: $$f'(x) = y' = \frac{dy}{dx} = \frac{df}{dx} = \frac{d}{dx} f(x) = Df(x) = D_x f(x),$$ unde simbolurile $\frac{d}{dx}$ și $D$ sunt //operatori de diferențiere//. Mai jos, prezentăm derivatele unor funcții comune: $$\begin{aligned} \frac{d}{dx} C & = 0 && \textrm{pentru orice constantă $C$} \\ \frac{d}{dx} x^n & = n x^{n-1} && \textrm{pentru } n \neq 0 \\ \frac{d}{dx} e^x & = e^x \\ \frac{d}{dx} \ln x & = x^{-1}. \end{aligned}$$ Funcțiile compuse din funcții diferențiabile sunt adesea ele însele diferențiabile. Următoarele reguli sunt utile pentru lucrul cu compoziții ale oricăror funcții diferențiabile $f$ și $g$ și constanta $C$. $$\begin{aligned} \frac{d}{dx} [C f(x)] & = C \frac{d}{dx} f(x) && \textrm{Regula multiplului constant} \\ \frac{d}{dx} [f(x) + g(x)] & = \frac{d}{dx} f(x) + \frac{d}{dx} g(x) && \textrm{Regula sumei} \\ \frac{d}{dx} [f(x) g(x)] & = f(x) \frac{d}{dx} g(x) + g(x) \frac{d}{dx} f(x) && \textrm{Regula produsului} \\ \frac{d}{dx} \frac{f(x)}{g(x)} & = \frac{g(x) \frac{d}{dx} f(x) - f(x) \frac{d}{dx} g(x)}{g^2(x)} && \textrm{Regula câtului} \end{aligned}$$ Folosind aceasta, putem aplica regulile pentru a găsi derivata lui $3 x^2 - 4x$ prin $$\frac{d}{dx} [3 x^2 - 4x] = 3 \frac{d}{dx} x^2 - 4 \frac{d}{dx} x = 6x - 4.$$ Înlocuind $x = 1$ arată că, într-adevăr, derivata este egală cu $2$ în această locație. Rețineți că derivatele ne spun //panta// unei funcții într-o anumită locație. ===== Utilități de Vizualizare ===== [**Putem vizualiza pantele funcțiilor folosind biblioteca ''%%matplotlib%%''**]. Trebuie să definim câteva funcții. După cum indică numele său, ''%%use_svg_display%%'' îi spune lui ''%%matplotlib%%'' să scoată graficele în format SVG pentru imagini mai clare. Comentariul ''%%#@save%%'' este un modificator special care ne permite să salvăm orice funcție, clasă sau alt bloc de cod în pachetul ''%%d2l%%'', astfel încât să îl putem invoca mai târziu fără a repeta codul, de exemplu, prin ''%%d2l.use_svg_display()%%''. def use_svg_display(): #@save """Use the svg format to display a plot in Jupyter.""" backend_inline.set_matplotlib_formats('svg') În mod convenabil, putem seta dimensiunile figurii cu ''%%set_figsize%%''. Deoarece instrucțiunea de import ''%%from matplotlib import pyplot as plt%%'' a fost marcată prin ''%%#@save%%'' în pachetul ''%%d2l%%'', putem apela ''%%d2l.plt%%''. def set_figsize(figsize=(3.5, 2.5)): #@save """Set the figure size for matplotlib.""" use_svg_display() d2l.plt.rcParams['figure.figsize'] = figsize Funcția ''%%set_axes%%'' poate asocia axele cu proprietăți, inclusiv etichete, intervale și scări. #@save def set_axes(axes, xlabel, ylabel, xlim, ylim, xscale, yscale, legend): """Set the axes for matplotlib.""" axes.set_xlabel(xlabel), axes.set_ylabel(ylabel) axes.set_xscale(xscale), axes.set_yscale(yscale) axes.set_xlim(xlim), axes.set_ylim(ylim) if legend: axes.legend(legend) axes.grid() Cu aceste trei funcții, putem defini o funcție ''%%plot%%'' pentru a suprapune mai multe curbe. O mare parte din codul de aici este doar pentru a ne asigura că dimensiunile și formele intrărilor se potrivesc. #@save def plot(X, Y=None, xlabel=None, ylabel=None, legend=[], xlim=None, ylim=None, xscale='linear', yscale='linear', fmts=('-', 'm--', 'g-.', 'r:'), figsize=(3.5, 2.5), axes=None): """Plot data points.""" def has_one_axis(X): # True if X (tensor or list) has 1 axis return (hasattr(X, "ndim") and X.ndim == 1 or isinstance(X, list) and not hasattr(X[0], "__len__")) if has_one_axis(X): X = [X] if Y is None: X, Y = [[]] * len(X), X elif has_one_axis(Y): Y = [Y] if len(X) != len(Y): X = X * len(Y) set_figsize(figsize) if axes is None: axes = d2l.plt.gca() axes.cla() for x, y, fmt in zip(X, Y, fmts): axes.plot(x,y,fmt) if len(x) else axes.plot(y,fmt) set_axes(axes, xlabel, ylabel, xlim, ylim, xscale, yscale, legend) Acum putem [**trasa funcția $u = f(x)$ și linia sa tangentă $y = 2x - 3$ la $x=1$**], unde coeficientul $2$ este panta liniei tangente. x = np.arange(0, 3, 0.1) plot(x, [f(x), 2 * x - 3], 'x', 'f(x)', legend=['f(x)', 'Tangent line (x=1)']) ===== Derivate Parțiale și Gradienți ===== Până acum, am diferențiat funcții de o singură variabilă. În deep learning, trebuie să lucrăm și cu funcții de //multe// variabile. Introducem pe scurt noțiunile derivatei care se aplică unor astfel de funcții //multivariate//. Fie $y = f(x_1, x_2, \ldots, x_n)$ o funcție cu $n$ variabile. //Derivata parțială// a lui $y$ în raport cu parametrul său $i$-lea $x_i$ este $$ \frac{\partial y}{\partial x_i} = \lim_{h \rightarrow 0} \frac{f(x_1, \ldots, x_{i-1}, x_i+h, x_{i+1}, \ldots, x_n) - f(x_1, \ldots, x_i, \ldots, x_n)}{h}.$$ Pentru a calcula $\frac{\partial y}{\partial x_i}$, putem trata $x_1, \ldots, x_{i-1}, x_{i+1}, \ldots, x_n$ ca constante și putem calcula derivata lui $y$ în raport cu $x_i$. Următoarele convenții de notație pentru derivatele parțiale sunt toate comune și toate înseamnă același lucru: $$\frac{\partial y}{\partial x_i} = \frac{\partial f}{\partial x_i} = \partial_{x_i} f = \partial_i f = f_{x_i} = f_i = D_i f = D_{x_i} f.$$ Putem concatena derivatele parțiale ale unei funcții multivariate în raport cu toate variabilele sale pentru a obține un vector care se numește //gradientul// funcției. Să presupunem că intrarea funcției $f: \mathbb{R}^n \rightarrow \mathbb{R}$ este un vector $n$-dimensional $\mathbf{x} = [x_1, x_2, \ldots, x_n]^\top$ și ieșirea este un scalar. Gradientul funcției $f$ în raport cu $\mathbf{x}$ este un vector de $n$ derivate parțiale: $$\nabla_{\mathbf{x}} f(\mathbf{x}) = \left[\partial_{x_1} f(\mathbf{x}), \partial_{x_2} f(\mathbf{x}), \ldots \partial_{x_n} f(\mathbf{x})\right]^\top.$$ Când nu există ambiguitate, $\nabla_{\mathbf{x}} f(\mathbf{x})$ este de obicei înlocuit cu $\nabla f(\mathbf{x})$. Următoarele reguli sunt utile pentru diferențierea funcțiilor multivariate: * Pentru toți $\mathbf{A} \in \mathbb{R}^{m \times n}$ avem $\nabla_{\mathbf{x}} \mathbf{A} \mathbf{x} = \mathbf{A}^\top$ și $\nabla_{\mathbf{x}} \mathbf{x}^\top \mathbf{A} = \mathbf{A}$. * Pentru matrici pătratice $\mathbf{A} \in \mathbb{R}^{n \times n}$ avem că $\nabla_{\mathbf{x}} \mathbf{x}^\top \mathbf{A} \mathbf{x} = (\mathbf{A} + \mathbf{A}^\top)\mathbf{x}$ și în special $\nabla_{\mathbf{x}} \|\mathbf{x} \|^2 = \nabla_{\mathbf{x}} \mathbf{x}^\top \mathbf{x} = 2\mathbf{x}$. În mod similar, pentru orice matrice $\mathbf{X}$, avem $\nabla_{\mathbf{X}} \|\mathbf{X} \|_\textrm{F}^2 = 2\mathbf{X}$. ===== Regula Lanțului ===== În deep learning, gradienții de interes sunt adesea dificil de calculat, deoarece lucrăm cu funcții profund imbricate (de funcții (de funcții...)). Din fericire, //regula lanțului// se ocupă de acest lucru. Revenind la funcțiile de o singură variabilă, să presupunem că $y = f(g(x))$ și că funcțiile subiacente $y=f(u)$ și $u=g(x)$ sunt ambele diferențiabile. Regula lanțului afirmă că $$\frac{dy}{dx} = \frac{dy}{du} \frac{du}{dx}.$$ Revenind la funcțiile multivariate, să presupunem că $y = f(\mathbf{u})$ are variabilele $u_1, u_2, \ldots, u_m$, unde fiecare $u_i = g_i(\mathbf{x})$ are variabilele $x_1, x_2, \ldots, x_n$, adică $\mathbf{u} = g(\mathbf{x})$. Atunci regula lanțului afirmă că $$\frac{\partial y}{\partial x_{i}} = \frac{\partial y}{\partial u_{1}} \frac{\partial u_{1}}{\partial x_{i}} + \frac{\partial y}{\partial u_{2}} \frac{\partial u_{2}}{\partial x_{i}} + \ldots + \frac{\partial y}{\partial u_{m}} \frac{\partial u_{m}}{\partial x_{i}} \ \textrm{ și deci } \ \nabla_{\mathbf{x}} y = \mathbf{A} \nabla_{\mathbf{u}} y,$$ unde $\mathbf{A} \in \mathbb{R}^{n \times m}$ este o //matrice// care conține derivata vectorului $\mathbf{u}$ în raport cu vectorul $\mathbf{x}$. Astfel, evaluarea gradientului necesită calcularea unui produs vector-matrice. Acesta este unul dintre motivele cheie pentru care algebra liniară este un element constitutiv atât de integral în construirea sistemelor de deep learning. ===== Discuție ===== Deși tocmai am zgâriat suprafața unui subiect profund, o serie de concepte intră deja în atenție: în primul rând, regulile de compoziție pentru diferențiere pot fi aplicate în mod obișnuit, permițându-ne să calculăm gradienții //automat//. Această sarcină nu necesită creativitate și, prin urmare, ne putem concentra puterile cognitive în altă parte. În al doilea rând, calcularea derivatelor funcțiilor cu valoare vectorială ne cere să înmulțim matricile pe măsură ce urmărim graful de dependență al variabilelor de la ieșire la intrare. În special, acest graf este parcurs într-o direcție //înainte// când evaluăm o funcție și într-o direcție //înapoi// când calculăm gradienți. Capitolele ulterioare vor introduce formal retropropagarea, o procedură de calcul pentru aplicarea regulii lanțului. Din punctul de vedere al optimizării, gradienții ne permit să determinăm cum să mutăm parametrii unui model pentru a reduce pierderea, iar fiecare pas al algoritmilor de optimizare utilizați în această carte va necesita calcularea gradientului. ===== Exerciții ===== - Până acum am luat regulile pentru derivate de la sine înțeles. Folosind definiția și limitele, demonstrați proprietățile pentru (i) $f(x) = c$, (ii) $f(x) = x^n$, (iii) $f(x) = e^x$ și (iv) $f(x) = \log x$. - În aceeași ordine de idei, demonstrați regula produsului, sumei și câtului de la primele principii. - Demonstrați că regula multiplului constant urmează ca un caz special al regulii produsului. - Calculați derivata lui $f(x) = x^x$. - Ce înseamnă că $f'(x) = 0$ pentru un $x$? Dați un exemplu de funcție $f$ și o locație $x$ pentru care acest lucru ar putea fi valabil. - Trasați funcția $y = f(x) = x^3 - \frac{1}{x}$ și trasați linia sa tangentă la $x = 1$. - Găsiți gradientul funcției $f(\mathbf{x}) = 3x_1^2 + 5e^{x_2}$. - Care este gradientul funcției $f(\mathbf{x}) = \|\mathbf{x}\|_2$? Ce se întâmplă pentru $\mathbf{x} = \mathbf{0}$? - Puteți scrie regula lanțului pentru cazul în care $u = f(x, y, z)$ și $x = x(a, b)$, $y = y(a, b)$ și $z = z(a, b)$? - Dată fiind o funcție $f(x)$ care este inversabilă, calculați derivata inversei sale $f^{-1}(x)$. Aici avem că $f^{-1}(f(x)) = x$ și invers $f(f^{-1}(y)) = y$. Indiciu: utilizați aceste proprietăți în derivarea dumneavoastră. [[https://discuss.d2l.ai/t/33|Discuții]]