.. _sec_calculus: Cálculo ======= Encontrar a área de um polígono permaneceu um mistério até pelo menos 2.500 anos atrás, quando os gregos antigos dividiam um polígono em triângulos e somavam suas áreas. Para encontrar a área de formas curvas, como um círculo, os gregos antigos inscreviam polígonos nessas formas. Conforme mostrado em :numref: ``fig_circle_area``, um polígono inscrito com mais lados de igual comprimento se aproxima melhor o circulo. Este processo também é conhecido como *método de exaustão*. .. _fig_circle_area: .. figure:: ../img/polygon-circle.svg Buscando a área de um círculo através do método de exaustão. Na verdade, o método de exaustão é de onde o *cálculo integral* (será descrito em :numref: ``sec_integral_calculus``) se origina. Mais de 2.000 anos depois, o outro ramo do cálculo, *cálculo diferencial*, foi inventado. Entre as aplicações mais críticas do cálculo diferencial, problemas de otimização consideram como fazer algo *o melhor*. Conforme discutido em :numref:`subsec_norms_and_objectives`, tais problemas são onipresentes em *Deep Learning*. Em *Deep Learning*, nós *treinamos* modelos, atualizando-os sucessivamente para que fiquem cada vez melhores à medida que veem mais e mais dados. Normalmente, melhorar significa minimizar uma *função de perda*, uma pontuação que responde à pergunta “quão *ruim* é o nosso modelo?” Esta pergunta é mais sutil do que parece. Em última análise, o que realmente nos preocupa está produzindo um modelo com bom desempenho em dados que nunca vimos antes. Mas só podemos ajustar o modelo aos dados que podemos realmente ver. Assim, podemos decompor a tarefa de ajustar os modelos em duas preocupações principais: i) *otimização*: processo de adequação de nossos modelos aos dados observados; ii) *generalização*: os princípios matemáticos e a sabedoria dos profissionais que guia sobre como produzir modelos cuja validade se estende além do conjunto exato de exemplos de dados usados para treiná-los. Para te ajudar a entender problemas e métodos de otimização em capítulos posteriores, aqui, damos uma breve introdução ao cálculo diferencial que é comumente usado no *Deep Learning*. Derivadas e Diferenciação ------------------------- Começamos abordando o cálculo de derivadas, uma etapa crucial em quase todos os algoritmos de otimização de *Deep Learning*. No *Deep Learning*, normalmente escolhemos funções de perda que são diferenciáveis em relação aos parâmetros do nosso modelo. Simplificando, isso significa que para cada parâmetro, podemos determinar a rapidez com que a perda aumentaria ou diminuiria, deveríamos *aumentar* ou *diminuir* esse parâmetro por uma quantidade infinitesimalmente pequena. Suponha que temos uma função :math:`f: \mathbb{R} \rightarrow \mathbb{R}`, cuja entrada e saída são escalares. A *derivada* de :math:`f` é definida como .. math:: f'(x) = \lim_{h \rightarrow 0} \frac{f(x+h) - f(x)}{h}, :label: eq_derivative se este limite existe. Se :math:`f'(a)` existe, Diz-se que :math:`f` é *diferenciável* em :math:`a`. Se :math:`f` é diferenciável a cada número de um intervalo, então esta função é diferenciável neste intervalo. Podemos interpretar a derivada :math:`f '(x)` em :eq:`eq_derivative` como a taxa de variação *instantânea* de :math:`f (x)` em relação a :math:`x`. A chamada taxa instantânea de mudança é baseada em a variação :math:`h` em :math:`x`, que se aproxima de :math:`0`. Para ilustrar derivadas, vamos experimentar com um exemplo. Define-se :math:`u = f(x) = 3x^2-4x`. .. raw:: html
mxnetpytorchtensorflow
.. raw:: html
.. code:: python %matplotlib inline from IPython import display from mxnet import np, npx from d2l import mxnet as d2l npx.set_np() def f(x): return 3 * x ** 2 - 4 * x .. raw:: html
.. raw:: html
.. code:: python %matplotlib inline import numpy as np from IPython import display from d2l import torch as d2l def f(x): return 3 * x ** 2 - 4 * x .. raw:: html
.. raw:: html
.. code:: python %matplotlib inline import numpy as np from IPython import display from d2l import tensorflow as d2l def f(x): return 3 * x ** 2 - 4 * x .. raw:: html
.. raw:: html
Definindo :math:`x = 1` e deixando :math:`h` se aproximar de :math:`0`, o resultado numérico de :math:`\frac{f(x+h) - f(x)}{h}` in: eqref: ``eq_derivative`` aproxima-se de :math:`2`. Embora este experimento não seja uma prova matemática, veremos mais tarde que a derivada :math:`u '` é :math:`2` quando :math:`x = 1`. .. raw:: html
mxnetpytorchtensorflow
.. raw:: html
.. code:: python def numerical_lim(f, x, h): return (f(x + h) - f(x)) / h h = 0.1 for i in range(5): print(f'h={h:.5f}, numerical limit={numerical_lim(f, 1, h):.5f}') h *= 0.1 .. parsed-literal:: :class: output h=0.10000, numerical limit=2.30000 h=0.01000, numerical limit=2.03000 h=0.00100, numerical limit=2.00300 h=0.00010, numerical limit=2.00030 h=0.00001, numerical limit=2.00003 .. raw:: html
.. raw:: html
.. code:: python def numerical_lim(f, x, h): return (f(x + h) - f(x)) / h h = 0.1 for i in range(5): print(f'h={h:.5f}, numerical limit={numerical_lim(f, 1, h):.5f}') h *= 0.1 .. parsed-literal:: :class: output h=0.10000, numerical limit=2.30000 h=0.01000, numerical limit=2.03000 h=0.00100, numerical limit=2.00300 h=0.00010, numerical limit=2.00030 h=0.00001, numerical limit=2.00003 .. raw:: html
.. raw:: html
.. code:: python def numerical_lim(f, x, h): return (f(x + h) - f(x)) / h h = 0.1 for i in range(5): print(f'h={h:.5f}, numerical limit={numerical_lim(f, 1, h):.5f}') h *= 0.1 .. parsed-literal:: :class: output h=0.10000, numerical limit=2.30000 h=0.01000, numerical limit=2.03000 h=0.00100, numerical limit=2.00300 h=0.00010, numerical limit=2.00030 h=0.00001, numerical limit=2.00003 .. raw:: html
.. raw:: html
Vamos nos familiarizar com algumas notações equivalentes para derivadas. Dado :math:`y = f (x)`, onde :math:`x` e :math:`y` são a variável independente e a variável dependente da função :math:`f`, respectivamente. As seguintes expressões são equivalentes: .. math:: f'(x) = y' = \frac{dy}{dx} = \frac{df}{dx} = \frac{d}{dx} f(x) = Df(x) = D_x f(x), onde os símbolos :math:`\frac{d}{dx}` e :math:`D` são *operadores de diferenciação* que indicam operação de *diferenciação*. Podemos usar as seguintes regras para diferenciar funções comuns: - :math:`DC = 0` (:math:`C` é uma constante), - :math:`Dx^n = nx^{n-1}` (uma exponenciação, :math:`n` é qualquer valor real), - :math:`De^x = e^x`, - :math:`D\ln(x) = 1/x.` Para diferenciar uma função que é formada de algumas funções mais simples, como as funções comuns acima, as regras a seguir podem ser úteis para nós. Suponha que as funções :math:`f` e :math:`g` sejam diferenciáveis e :math:`C` seja uma constante, temos a *regra múltipla constante* .. math:: \frac{d}{dx} [Cf(x)] = C \frac{d}{dx} f(x), a *regra da soma* .. math:: \frac{d}{dx} [f(x) + g(x)] = \frac{d}{dx} f(x) + \frac{d}{dx} g(x), a *regra do produto* .. math:: \frac{d}{dx} [f(x)g(x)] = f(x) \frac{d}{dx} [g(x)] + g(x) \frac{d}{dx} [f(x)], e a *regra do quociente* .. math:: \frac{d}{dx} \left[\frac{f(x)}{g(x)}\right] = \frac{g(x) \frac{d}{dx} [f(x)] - f(x) \frac{d}{dx} [g(x)]}{[g(x)]^2}. Agora podemos aplicar algumas das regras acima para encontrar :math:`u' = f'(x) = 3 \frac{d}{dx} x^2-4\frac{d}{dx}x = 6x-4`. Assim, definindo :math:`x = 1`, temos :math:`u '= 2`: isso é apoiado por nosso experimento anterior nesta seção onde o resultado numérico se aproxima de :math:`2`. Esta derivada também é a inclinação da linha tangente para a curva :math:`u = f (x)` quando :math:`x = 1`. Para visualizar tal interpretação das derivadas, usaremos ``matplotlib``, uma biblioteca de plotagem popular em Python. Para configurar as propriedades das figuras produzidas por ``matplotlib``, precisamos definir algumas funções. Na sequência, a função ``use_svg_display`` especifica o pacote\ ``matplotlib`` para produzir os números SVG para imagens mais nítidas. Observe que o comentário ``# @ save`` é uma marca especial onde a seguinte função, classe, ou instruções são salvas no pacote ``d2l`` então, mais tarde, eles podem ser chamados diretamente (por exemplo, ``d2l.use_svg_display ()``) sem serem redefinidos. .. code:: python def use_svg_display(): #@save """Use the svg format to display a plot in Jupyter.""" display.set_matplotlib_formats('svg') Definimos a função ``set_figsize`` para especificar o tamanho das figuras. Observe que aqui usamos diretamente ``d2l.plt``, uma vez que a instrução import\ ``from matplotlib import pyplot as plt`` foi marcada para ser salva no pacote ``d2l`` no prefácio. .. code:: python def set_figsize(figsize=(3.5, 2.5)): #@save """Set the figure size for matplotlib.""" use_svg_display() d2l.plt.rcParams['figure.figsize'] = figsize A seguinte função ``set_axes`` define as propriedades dos eixos das figuras produzidas por\ ``matplotlib``. .. code:: python #@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() Com essas três funções para configurações de figura, nós definimos a função ``plot`` para traçar várias curvas sucintamente uma vez que precisaremos visualizar muitas curvas ao longo do livro. .. code:: python #@save def plot(X, Y=None, xlabel=None, ylabel=None, legend=None, xlim=None, ylim=None, xscale='linear', yscale='linear', fmts=('-', 'm--', 'g-.', 'r:'), figsize=(3.5, 2.5), axes=None): """Plot data points.""" if legend is None: legend = [] set_figsize(figsize) axes = axes if axes else d2l.plt.gca() # Return True if `X` (tensor or list) has 1 axis def has_one_axis(X): 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) axes.cla() for x, y, fmt in zip(X, Y, fmts): if len(x): axes.plot(x, y, fmt) else: axes.plot(y, fmt) set_axes(axes, xlabel, ylabel, xlim, ylim, xscale, yscale, legend) Agora podemos plotar a função :math:`u = f (x)` e sua linha tangente :math:`y = 2x - 3` em :math:`x = 1`, onde o coeficiente :math:`2` é a inclinação da linha tangente . .. raw:: html
mxnetpytorchtensorflow
.. raw:: html
.. code:: python x = np.arange(0, 3, 0.1) plot(x, [f(x), 2 * x - 3], 'x', 'f(x)', legend=['f(x)', 'Tangent line (x=1)']) .. parsed-literal:: :class: output /tmp/ipykernel_122506/77894834.py:3: DeprecationWarning: `set_matplotlib_formats` is deprecated since IPython 7.23, directly use `matplotlib_inline.backend_inline.set_matplotlib_formats()` display.set_matplotlib_formats('svg') .. figure:: output_calculus_7e7694_35_1.svg .. raw:: html
.. raw:: html
.. code:: python x = np.arange(0, 3, 0.1) plot(x, [f(x), 2 * x - 3], 'x', 'f(x)', legend=['f(x)', 'Tangent line (x=1)']) .. parsed-literal:: :class: output /tmp/ipykernel_104167/77894834.py:3: DeprecationWarning: `set_matplotlib_formats` is deprecated since IPython 7.23, directly use `matplotlib_inline.backend_inline.set_matplotlib_formats()` display.set_matplotlib_formats('svg') .. figure:: output_calculus_7e7694_38_1.svg .. raw:: html
.. raw:: html
.. code:: python x = np.arange(0, 3, 0.1) plot(x, [f(x), 2 * x - 3], 'x', 'f(x)', legend=['f(x)', 'Tangent line (x=1)']) .. parsed-literal:: :class: output /tmp/ipykernel_105316/77894834.py:3: DeprecationWarning: `set_matplotlib_formats` is deprecated since IPython 7.23, directly use `matplotlib_inline.backend_inline.set_matplotlib_formats()` display.set_matplotlib_formats('svg') .. figure:: output_calculus_7e7694_41_1.svg .. raw:: html
.. raw:: html
Derivadas Parciais ------------------ Até agora, lidamos com a diferenciação de funções de apenas uma variável. No *Deep Learning*, as funções geralmente dependem de *muitas* variáveis. Portanto, precisamos estender as idéias de diferenciação para essas funções *multivariadas*. Seja :math:`y = f(x_1, x_2, \ldots, x_n)` uma função com :math:`n` variáveis. A *derivada parcial* de :math:`y` em relação ao seu :math:`i ^ \mathrm {th}` parâmetro :math:`x_i` é .. math:: \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}. Para calcular :math:`\frac{\partial y}{\partial x_i}`, podemos simplesmente tratar :math:`x_1, \ldots, x_{i-1}, x_{i+1}, \ldots, x_n` como constantes e calcular a derivada de :math:`y` com respeito a :math:`x_i`. Para notação de derivadas parciais, os seguintes são equivalentes: .. math:: \frac{\partial y}{\partial x_i} = \frac{\partial f}{\partial x_i} = f_{x_i} = f_i = D_i f = D_{x_i} f. Gradientes ---------- Podemos concatenar derivadas parciais de uma função multivariada com respeito a todas as suas variáveis para obter o vetor *gradiente* da função. Suponha que a entrada da função :math:`f: \mathbb{R}^n \rightarrow \mathbb{R}` seja um vetor :math:`n` -dimensional :math:`\mathbf{x} = [x_1, x_2, \ldots, x_n]^\top` e a saída é um escalar. O gradiente da função :math:`f(\mathbf{x})` em relação a :math:`\mathbf {x}` é um vetor de :math:`n` derivadas parciais: .. math:: \nabla_{\mathbf{x}} f(\mathbf{x}) = \bigg[\frac{\partial f(\mathbf{x})}{\partial x_1}, \frac{\partial f(\mathbf{x})}{\partial x_2}, \ldots, \frac{\partial f(\mathbf{x})}{\partial x_n}\bigg]^\top, onde :math:`\nabla_{\mathbf{x}} f(\mathbf{x})` é frequentemente substituído por :math:`\nabla f(\mathbf{x})` quando não há ambiguidade. Seja :math:`\mathbf {x}` um vetor :math:`n` -dimensional, as seguintes regras são freqüentemente usadas ao diferenciar funções multivariadas: - For all :math:`\mathbf{A} \in \mathbb{R}^{m \times n}`, :math:`\nabla_{\mathbf{x}} \mathbf{A} \mathbf{x} = \mathbf{A}^\top`, - For all :math:`\mathbf{A} \in \mathbb{R}^{n \times m}`, :math:`\nabla_{\mathbf{x}} \mathbf{x}^\top \mathbf{A} = \mathbf{A}`, - For all :math:`\mathbf{A} \in \mathbb{R}^{n \times n}`, :math:`\nabla_{\mathbf{x}} \mathbf{x}^\top \mathbf{A} \mathbf{x} = (\mathbf{A} + \mathbf{A}^\top)\mathbf{x}`, - :math:`\nabla_{\mathbf{x}} \|\mathbf{x} \|^2 = \nabla_{\mathbf{x}} \mathbf{x}^\top \mathbf{x} = 2\mathbf{x}`. Da mesma forma, para qualquer matriz :math:`\mathbf {X}`, temos :math:`\nabla_{\mathbf{X}} \|\mathbf{X} \|_F^2 = 2\mathbf{X}`. Como veremos mais tarde, os gradientes são úteis para projetar algoritmos de otimização em *deep learning*. Regra da Cadeia --------------- No entanto, esses gradientes podem ser difíceis de encontrar. Isso ocorre porque as funções multivariadas no *deep learning* são frequentemente *compostas*, portanto, não podemos aplicar nenhuma das regras mencionadas acima para diferenciar essas funções. Felizmente, a *regra da cadeia* nos permite diferenciar funções compostas. Vamos primeiro considerar as funções de uma única variável. Suponha que as funções :math:`y = f (u)` e :math:`u = g (x)` sejam diferenciáveis, então a regra da cadeia afirma que .. math:: \frac{dy}{dx} = \frac{dy}{du} \frac{du}{dx}. Agora, vamos voltar nossa atenção para um cenário mais geral onde as funções têm um número arbitrário de variáveis. Suponha que a função diferenciável :math:`y` tenha variáveis :math:`u_1, u_2, \ldots, u_m`, onde cada função diferenciável :math:`u_i` tem variáveis :math:`x_1, x_2, \ldots, x_n`. Observe que :math:`y` é uma função de :math:`x_1, x_2, \ldots, x_n`. Então a regra da cadeia será .. math:: \frac{dy}{dx_i} = \frac{dy}{du_1} \frac{du_1}{dx_i} + \frac{dy}{du_2} \frac{du_2}{dx_i} + \cdots + \frac{dy}{du_m} \frac{du_m}{dx_i} para qualquer :math:`i = 1, 2, \ldots, n`. Sumário ------- - Cálculo diferencial e cálculo integral são dois ramos do cálculo, onde o primeiro pode ser aplicado aos problemas de otimização onipresentes no *deep learning*. - Uma derivada pode ser interpretada como a taxa instantânea de mudança de uma função em relação à sua variável. É também a inclinação da linha tangente à curva da função. - Um gradiente é um vetor cujos componentes são as derivadas parciais de uma função multivariada com respeito a todas as suas variáveis. - A regra da cadeia nos permite diferenciar funções compostas. Exercícios ---------- 1. Trace a função :math:`y = f(x) = x^3 - \frac{1}{x}` e sua linha tangente quando :math:`x = 1`. 2. Encontre o gradiente da função :math:`f(\mathbf{x}) = 3x_1^2 + 5e^{x_2}`. 3. Qual é o gradiente da função :math:`f(\mathbf{x}) = \|\mathbf{x}\|_2`? 4. Você pode escrever a regra da cadeia para o caso em que :math:`u = f(x, y, z)` e :math:`x = x(a, b)`, :math:`y = y(a, b)`, e :math:`z = z(a, b)`? .. raw:: html
mxnetpytorchtensorflow
.. raw:: html
`Discussions `__ .. raw:: html
.. raw:: html
`Discussions `__ .. raw:: html
.. raw:: html
`Discussions `__ .. raw:: html
.. raw:: html
.. raw:: html