.. _sec_linear-algebra:
Álgebra Linear
==============
Agora que você pode armazenar e manipular dados, vamos revisar
brevemente o subconjunto da álgebra linear básica que você precisa para
entender e implementar a maioria dos modelos cobertos neste livro.
Abaixo, apresentamos os objetos matemáticos básicos, aritméticos, e
operações em álgebra linear, expressar cada um deles por meio de notação
matemática e a implementação correspondente em código.
Escalares
---------
Se você nunca estudou álgebra linear ou aprendizado de máquina, então
sua experiência anterior com matemática provavelmente consistia de
pensar em um número de cada vez. E, se você já equilibrou um talão de
cheques ou até mesmo pagou por um jantar em um restaurante então você já
sabe como fazer coisas básicas como adicionar e multiplicar pares de
números. Por exemplo, a temperatura em Palo Alto é de :math:`52` graus
Fahrenheit.
Formalmente, chamamos de valores que consistem de apenas uma quantidade
numérica *escalar*. Se você quiser converter este valor para Celsius
(escala de temperatura mais sensível do sistema métrico), você avaliaria
a expressão :math:`c = \frac{5}{9}(f - 32)`, definindo :math:`f` para
:math:`52`. Nesta equação, cada um dos termos—\ :math:`5`, :math:`9`, e
:math:`32`—são valores escalares. Os marcadores :math:`c` e :math:`f`
são chamados de *variáveis* e eles representam valores escalares
desconhecidos.
Neste livro, adotamos a notação matemática onde as variáveis escalares
são denotadas por letras minúsculas comuns (por exemplo, :math:`x`,
:math:`y`, and :math:`z`). Denotamos o espaço de todos os escalares
(contínuos) *com valor real* por :math:`\mathbb{R}`. Por conveniência,
vamos lançar mão de definições rigorosas do que exatamente é *espaço*,
mas lembre-se por enquanto que a expressão :math:`x \in \mathbb{R}` é
uma maneira formal de dizer que :math:`x` é um escalar com valor real. O
símbolo :math:`\in` pode ser pronunciado “em” e simplesmente denota
associação em um conjunto. Analogamente, poderíamos escrever
:math:`x, y \in \{0, 1\}` para afirmar que :math:`x` e :math:`y` são
números cujo valor só pode ser :math:`0` ou :math:`1`.
Um escalar é representado por um tensor com apenas um elemento. No
próximo trecho de código, instanciamos dois escalares e realizar algumas
operações aritméticas familiares com eles, a saber, adição,
multiplicação, divisão e exponenciação.
.. raw:: html
.. raw:: html
.. code:: python
from mxnet import np, npx
npx.set_np()
x = np.array(3.0)
y = np.array(2.0)
x + y, x * y, x / y, x ** y
.. parsed-literal::
:class: output
(array(5.), array(6.), array(1.5), array(9.))
.. raw:: html
.. raw:: html
.. code:: python
import torch
x = torch.tensor([3.0])
y = torch.tensor([2.0])
x + y, x * y, x / y, x**y
.. parsed-literal::
:class: output
(tensor([5.]), tensor([6.]), tensor([1.5000]), tensor([9.]))
.. raw:: html
.. raw:: html
.. code:: python
import tensorflow as tf
x = tf.constant([3.0])
y = tf.constant([2.0])
x + y, x * y, x / y, x**y
.. parsed-literal::
:class: output
(,
,
,
)
.. raw:: html
.. raw:: html
Vetores
-------
Você pode pensar em um vetor simplesmente como uma lista de valores
escalares. Chamamos esses valores de *elementos* (*entradas* ou
*componentes*) do vetor. Quando nossos vetores representam exemplos de
nosso conjunto de dados, seus valores têm algum significado no mundo
real. Por exemplo, se estivéssemos treinando um modelo para prever o
risco de inadimplência de um empréstimo, podemos associar cada candidato
a um vetor cujos componentes correspondem à sua receita, tempo de
emprego, número de inadimplências anteriores e outros fatores. Se
estivéssemos estudando o risco de ataques cardíacos que os pacientes de
hospitais potencialmente enfrentam, podemos representar cada paciente
por um vetor cujos componentes capturam seus sinais vitais mais
recentes, níveis de colesterol, minutos de exercício por dia, etc. Em
notação matemática, geralmente denotamos os vetores em negrito, letras
minúsculas (por exemplo,, :math:`\mathbf{x}`, :math:`\mathbf{y}`, and
:math:`\mathbf{z})`.
Trabalhamos com vetores via tensores unidimensionais. Em geral, os
tensores podem ter comprimentos arbitrários, sujeito aos limites de
memória de sua máquina.
.. raw:: html
.. raw:: html
.. code:: python
x = np.arange(4)
x
.. parsed-literal::
:class: output
array([0., 1., 2., 3.])
.. raw:: html
.. raw:: html
.. code:: python
x = torch.arange(4)
x
.. parsed-literal::
:class: output
tensor([0, 1, 2, 3])
.. raw:: html
.. raw:: html
.. code:: python
x = tf.range(4)
x
.. parsed-literal::
:class: output
.. raw:: html
.. raw:: html
Podemos nos referir a qualquer elemento de um vetor usando um subscrito.
Por exemplo, podemos nos referir ao elemento :math:`i^\mathrm{th}`
element of :math:`\mathbf{x}` por :math:`x_i`. Observe que o elemento
:math:`x_i` é um escalar, portanto, não colocamos a fonte em negrito
quando nos referimos a ela. A literatura extensa considera os vetores de
coluna como o padrão orientação de vetores, este livro também. Em
matemática, um vetor :math:`\mathbf{x}` pode ser escrito como
.. math:: \mathbf{x} =\begin{bmatrix}x_{1} \\x_{2} \\ \vdots \\x_{n}\end{bmatrix},
:label: eq_vec_def
onde :math:`x_1, \ldots, x_n` são elementos do vetor. No código
acessamos qualquer elemento indexando no tensor
.. raw:: html
.. raw:: html
.. code:: python
x[3]
.. parsed-literal::
:class: output
array(3.)
.. raw:: html
.. raw:: html
.. code:: python
x[3]
.. parsed-literal::
:class: output
tensor(3)
.. raw:: html
.. raw:: html
.. code:: python
x[3]
.. parsed-literal::
:class: output
.. raw:: html
.. raw:: html
Comprimento, Dimensionalidade e Forma
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Vamos revisitar alguns conceitos de: numref: ``sec_ndarray``. Um vetor é
apenas uma matriz de números. E assim como todo array tem um
comprimento, todo vetor também. Em notação matemática, se quisermos
dizer que um vetor :math:`\mathbf{x}` consiste em :math:`n` escalares
com valor real, podemos expressar isso como
:math:`\mathbf{x} \in \mathbb{R}^n`. O comprimento de um vetor é
comumente chamado de *dimensão* do vetor.
Tal como acontece com uma matriz Python comum, nós podemos acessar o
comprimento de um tensor chamando a função ``len ()`` embutida do
Python.
.. raw:: html
.. raw:: html
.. code:: python
len(x)
.. parsed-literal::
:class: output
4
.. raw:: html
.. raw:: html
.. code:: python
len(x)
.. parsed-literal::
:class: output
4
.. raw:: html
.. raw:: html
.. code:: python
len(x)
.. parsed-literal::
:class: output
4
.. raw:: html
.. raw:: html
Quando um tensor representa um vetor (com precisamente um eixo), também
podemos acessar seu comprimento por meio do atributo ``.shape``. A forma
é uma tupla que lista o comprimento (dimensionalidade) ao longo de cada
eixo do tensor. Para tensores com apenas um eixo, a forma tem apenas um
elemento.
.. raw:: html
.. raw:: html
.. code:: python
x.shape
.. parsed-literal::
:class: output
(4,)
.. raw:: html
.. raw:: html
.. code:: python
x.shape
.. parsed-literal::
:class: output
torch.Size([4])
.. raw:: html
.. raw:: html
.. code:: python
x.shape
.. parsed-literal::
:class: output
TensorShape([4])
.. raw:: html
.. raw:: html
Observe que a palavra “dimensão” tende a ficar sobrecarregada nesses
contextos e isso tende a confundir as pessoas. Para esclarecer, usamos a
dimensionalidade de um *vetor* ou um *eixo* para se referir ao seu
comprimento, ou seja, o número de elementos de um vetor ou eixo. No
entanto, usamos a dimensionalidade de um tensor para se referir ao
número de eixos que um tensor possui. Nesse sentido, a dimensionalidade
de algum eixo de um tensor será o comprimento desse eixo.
Matrizes
--------
Assim como os vetores generalizam escalares de ordem zero para ordem um,
matrizes generalizam vetores de ordem um para ordem dois. Matrizes, que
normalmente denotamos com letras maiúsculas em negrito (por exemplo,
:math:`\mathbf{X}`, :math:`\mathbf{Y}`, and :math:`\mathbf{Z}`), são
representados no código como tensores com dois eixos.
Em notação matemática, usamos
:math:`\mathbf{A} \in \mathbb{R}^{m \times n}` para expressar que a
matriz :math:`\mathbf {A}` consiste em :math:`m` linhas e :math:`n`
colunas de escalares com valor real. Visualmente, podemos ilustrar
qualquer matriz :math:`\mathbf{A} \in \mathbb{R}^{m \times n}` como uma
tabela, onde cada elemento :math:`a_{ij}` pertence à linha
:math:`i^{\mathrm{th}}` e coluna :math:`j^{\mathrm{th}}`:
.. math:: \mathbf{A}=\begin{bmatrix} a_{11} & a_{12} & \cdots & a_{1n} \\ a_{21} & a_{22} & \cdots & a_{2n} \\ \vdots & \vdots & \ddots & \vdots \\ a_{m1} & a_{m2} & \cdots & a_{mn} \\ \end{bmatrix}.
:label: eq_matrix_def
Para qualquer :math:`\mathbf{A} \in \mathbb{R}^{m \times n}`, a forma de
:math:`\mathbf{A}` é (:math:`m`, :math:`n`) ou :math:`m \times n`.
Especificamente, quando uma matriz tem o mesmo número de linhas e
colunas, sua forma se torna um quadrado; portanto, é chamada de *matriz
quadrada*.
Podemos criar uma matriz :math:`m \times n` especificando uma forma com
dois componentes :math:`m` e :math:`n` ao chamar qualquer uma de nossas
funções favoritas para instanciar um tensor.
.. raw:: html
.. raw:: html
.. code:: python
A = np.arange(20).reshape(5, 4)
A
.. parsed-literal::
:class: output
array([[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.],
[12., 13., 14., 15.],
[16., 17., 18., 19.]])
.. raw:: html
.. raw:: html
.. code:: python
A = torch.arange(20).reshape(5, 4)
A
.. parsed-literal::
:class: output
tensor([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15],
[16, 17, 18, 19]])
.. raw:: html
.. raw:: html
.. code:: python
A = tf.reshape(tf.range(20), (5, 4))
A
.. parsed-literal::
:class: output
.. raw:: html
.. raw:: html
Podemos acessar o elemento escalar :math:`a_{ij}` de uma matriz
:math:`\mathbf{A}` em: eqref: ``eq_matrix_def`` especificando os índices
para a linha (:math:`i`) e coluna (:math:`j`), como
:math:`[\mathbf {A}] _ {ij}`. Quando os elementos escalares de uma
matriz :math:`\mathbf{A}`, como em: eqref: ``eq_matrix_def``, não são
fornecidos, podemos simplesmente usar a letra minúscula da matriz
:math:`\mathbf{A}` com o subscrito do índice, :math:`a_{ij}`, para se
referir a :math:`[\mathbf {A}] _ {ij}`. Para manter a notação simples,
as vírgulas são inseridas para separar os índices apenas quando
necessário, como :math:`a_ {2, 3j}` e :math:`[\mathbf {A}] _ {2i-1, 3}`.
Às vezes, queremos inverter os eixos. Quando trocamos as linhas e
colunas de uma matriz, o resultado é chamado de *transposição* da
matriz. Formalmente, significamos uma matriz :math:`\mathbf {A}`
transposta por :math:`\mathbf {A} ^ \top` e se
:math:`\mathbf {B} = \mathbf {A} ^ \top`, então
:math:`b_ {ij} = a_ {ji}` para qualquer :math:`i` e :math:`j`. Assim, a
transposição de :math:`\mathbf {A}` em: eqref: ``eq_matrix_def`` é uma
matriz :math:`n \times m`:
.. math::
\mathbf{A}^\top =
\begin{bmatrix}
a_{11} & a_{21} & \dots & a_{m1} \\
a_{12} & a_{22} & \dots & a_{m2} \\
\vdots & \vdots & \ddots & \vdots \\
a_{1n} & a_{2n} & \dots & a_{mn}
\end{bmatrix}.
Agora acessamoas a matriz transposta via código.
.. raw:: html
.. raw:: html
.. code:: python
A.T
.. parsed-literal::
:class: output
array([[ 0., 4., 8., 12., 16.],
[ 1., 5., 9., 13., 17.],
[ 2., 6., 10., 14., 18.],
[ 3., 7., 11., 15., 19.]])
.. raw:: html
.. raw:: html
.. code:: python
A.T
.. parsed-literal::
:class: output
tensor([[ 0, 4, 8, 12, 16],
[ 1, 5, 9, 13, 17],
[ 2, 6, 10, 14, 18],
[ 3, 7, 11, 15, 19]])
.. raw:: html
.. raw:: html
.. code:: python
tf.transpose(A)
.. parsed-literal::
:class: output
.. raw:: html
.. raw:: html
Como um tipo especial de matriz quadrada, a *matriz simétrica*
:math:`\mathbf {A}` é igual à sua transposta:
:math:`\mathbf{A} = \mathbf{A}^\top`. Aqui definimos uma matriz
simétrica ``B``.
.. raw:: html
.. raw:: html
.. code:: python
B = np.array([[1, 2, 3], [2, 0, 4], [3, 4, 5]])
B
.. parsed-literal::
:class: output
array([[1., 2., 3.],
[2., 0., 4.],
[3., 4., 5.]])
.. raw:: html
.. raw:: html
.. code:: python
B = torch.tensor([[1, 2, 3], [2, 0, 4], [3, 4, 5]])
B
.. parsed-literal::
:class: output
tensor([[1, 2, 3],
[2, 0, 4],
[3, 4, 5]])
.. raw:: html
.. raw:: html
.. code:: python
B = tf.constant([[1, 2, 3], [2, 0, 4], [3, 4, 5]])
B
.. parsed-literal::
:class: output
.. raw:: html
.. raw:: html
Agora comparamos ``B`` com sua transposta.
.. raw:: html
.. raw:: html
.. code:: python
B == B.T
.. parsed-literal::
:class: output
array([[ True, True, True],
[ True, True, True],
[ True, True, True]])
.. raw:: html
.. raw:: html
.. code:: python
B == B.T
.. parsed-literal::
:class: output
tensor([[True, True, True],
[True, True, True],
[True, True, True]])
.. raw:: html
.. raw:: html
.. code:: python
B == tf.transpose(B)
.. parsed-literal::
:class: output
.. raw:: html
.. raw:: html
Matrizes são estruturas de dados úteis: eles nos permitem organizar
dados que têm diferentes modalidades de variação. Por exemplo, as linhas
em nossa matriz podem corresponder a diferentes casas (exemplos de
dados), enquanto as colunas podem corresponder a diferentes atributos.
Isso deve soar familiar se você já usou um software de planilha ou leu:
numref: ``sec_pandas``. Assim, embora a orientação padrão de um único
vetor seja um vetor coluna, em uma matriz que representa um conjunto de
dados tabular, é mais convencional tratar cada exemplo de dados como um
vetor linha na matriz. E, como veremos em capítulos posteriores, esta
convenção permitirá práticas comuns de aprendizado profundo. Por
exemplo, ao longo do eixo mais externo de um tensor, podemos acessar ou
enumerar *minibatches* de exemplos de dados, ou apenas exemplos de dados
se não houver *minibatch*.
Tensores
--------
Assim como vetores generalizam escalares e matrizes generalizam vetores,
podemos construir estruturas de dados com ainda mais eixos. Tensores
(“tensores” nesta subseção referem-se a objetos algébricos) nos dê uma
maneira genérica de descrever matrizes :math:`n` -dimensionais com um
número arbitrário de eixos. Vetores, por exemplo, são tensores de
primeira ordem e matrizes são tensores de segunda ordem. Tensores são
indicados com letras maiúsculas de uma fonte especial (por exemplo,
:math:`\mathsf{X}`, :math:`\mathsf{Y}`, e :math:`\mathsf{Z}`) e seu
mecanismo de indexação (por exemplo, :math:`x_{ijk}` e
:math:`[\mathsf{X}]_{1, 2i-1, 3}`) é semelhante ao de matrizes.
Os tensores se tornarão mais importantes quando começarmos a trabalhar
com imagens, que chegam como matrizes :math:`n` -dimensionais com 3
eixos correspondentes à altura, largura e um eixo de *canal* para
empilhar os canais de cores (vermelho, verde e azul). Por enquanto,
vamos pular tensores de ordem superior e nos concentrar no básico.
.. raw:: html
.. raw:: html
.. code:: python
X = np.arange(24).reshape(2, 3, 4)
X
.. parsed-literal::
:class: output
array([[[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.]],
[[12., 13., 14., 15.],
[16., 17., 18., 19.],
[20., 21., 22., 23.]]])
.. raw:: html
.. raw:: html
.. code:: python
X = torch.arange(24).reshape(2, 3, 4)
X
.. parsed-literal::
:class: output
tensor([[[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]],
[[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23]]])
.. raw:: html
.. raw:: html
.. code:: python
X = tf.reshape(tf.range(24), (2, 3, 4))
X
.. parsed-literal::
:class: output
.. raw:: html
.. raw:: html
Propriedades Básicas de Aritmética de Tensores
----------------------------------------------
Escalares, vetores, matrizes e tensores (“tensores” nesta subseção
referem-se a objetos algébricos) de um número arbitrário de eixos têm
algumas propriedades interessantes que muitas vezes são úteis. Por
exemplo, você deve ter notado da definição de uma operação elemento a
elemento que qualquer operação unária elementar não altera a forma de
seu operando. Similarmente, dados quaisquer dois tensores com a mesma
forma, o resultado de qualquer operação binária elementar será um tensor
da mesma forma. Por exemplo, adicionar duas matrizes da mesma forma
realiza a adição elemento a elemento sobre essas duas matrizes.
.. raw:: html
.. raw:: html
.. code:: python
A = np.arange(20).reshape(5, 4)
B = A.copy() # Cria uma cópia de `A` em `B` alocando nova memória
A, A + B
.. parsed-literal::
:class: output
(array([[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.],
[12., 13., 14., 15.],
[16., 17., 18., 19.]]),
array([[ 0., 2., 4., 6.],
[ 8., 10., 12., 14.],
[16., 18., 20., 22.],
[24., 26., 28., 30.],
[32., 34., 36., 38.]]))
.. raw:: html
.. raw:: html
.. code:: python
A = torch.arange(20, dtype=torch.float32).reshape(5, 4)
B = A.clone() # Cria uma cópia de `A` em `B` alocando nova memória
A, A + B
.. parsed-literal::
:class: output
(tensor([[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.],
[12., 13., 14., 15.],
[16., 17., 18., 19.]]),
tensor([[ 0., 2., 4., 6.],
[ 8., 10., 12., 14.],
[16., 18., 20., 22.],
[24., 26., 28., 30.],
[32., 34., 36., 38.]]))
.. raw:: html
.. raw:: html
.. code:: python
A = tf.reshape(tf.range(20, dtype=tf.float32), (5, 4))
B = A # Não está clonando `A` para `B` para alocar nova memória
A, A + B
.. parsed-literal::
:class: output
(,
)
.. raw:: html
.. raw:: html
Especificamente, a multiplicação elemento a elemento de duas matrizes é
chamada de *produto Hadamard* (notação matemática :math:`\odot`).
Considere a matriz :math:`\mathbf{B} \in \mathbb{R}^{m \times n}` cujo
elemento da linha :math:`i` e coluna :math:`j` é :math:`b_ {ij}`. O
produto Hadamard das matrizes :math:`\mathbf {A}` (definido em
:eq:`eq_matrix_def`) e :math:`\mathbf {B}`
.. math::
\mathbf{A} \odot \mathbf{B} =
\begin{bmatrix}
a_{11} b_{11} & a_{12} b_{12} & \dots & a_{1n} b_{1n} \\
a_{21} b_{21} & a_{22} b_{22} & \dots & a_{2n} b_{2n} \\
\vdots & \vdots & \ddots & \vdots \\
a_{m1} b_{m1} & a_{m2} b_{m2} & \dots & a_{mn} b_{mn}
\end{bmatrix}.
.. raw:: html
.. raw:: html
.. code:: python
A * B
.. parsed-literal::
:class: output
array([[ 0., 1., 4., 9.],
[ 16., 25., 36., 49.],
[ 64., 81., 100., 121.],
[144., 169., 196., 225.],
[256., 289., 324., 361.]])
.. raw:: html
.. raw:: html
.. code:: python
A * B
.. parsed-literal::
:class: output
tensor([[ 0., 1., 4., 9.],
[ 16., 25., 36., 49.],
[ 64., 81., 100., 121.],
[144., 169., 196., 225.],
[256., 289., 324., 361.]])
.. raw:: html
.. raw:: html
.. code:: python
A * B
.. parsed-literal::
:class: output
.. raw:: html
.. raw:: html
Multiplicar ou adicionar um tensor por um escalar também não muda a
forma do tensor, onde cada elemento do tensor operando será adicionado
ou multiplicado pelo escalar.
.. raw:: html
.. raw:: html
.. code:: python
a = 2
X = np.arange(24).reshape(2, 3, 4)
a + X, (a * X).shape
.. parsed-literal::
:class: output
(array([[[ 2., 3., 4., 5.],
[ 6., 7., 8., 9.],
[10., 11., 12., 13.]],
[[14., 15., 16., 17.],
[18., 19., 20., 21.],
[22., 23., 24., 25.]]]),
(2, 3, 4))
.. raw:: html
.. raw:: html
.. code:: python
a = 2
X = torch.arange(24).reshape(2, 3, 4)
a + X, (a * X).shape
.. parsed-literal::
:class: output
(tensor([[[ 2, 3, 4, 5],
[ 6, 7, 8, 9],
[10, 11, 12, 13]],
[[14, 15, 16, 17],
[18, 19, 20, 21],
[22, 23, 24, 25]]]),
torch.Size([2, 3, 4]))
.. raw:: html
.. raw:: html
.. code:: python
a = 2
X = tf.reshape(tf.range(24), (2, 3, 4))
a + X, (a * X).shape
.. parsed-literal::
:class: output
(,
TensorShape([2, 3, 4]))
.. raw:: html
.. raw:: html
.. _subseq_lin-alg-reduction:
Redução
-------
Uma operação útil que podemos realizar com tensores arbitrários é para
calcule a soma de seus elementos. Em notação matemática, expressamos
somas usando o símbolo :math:`\sum`. Para expressar a soma dos elementos
em um vetor :math:`\mathbf {x}` de comprimento :math:`d`, escrevemos
:math:`\sum_ {i = 1} ^ d x_i`. No código, podemos apenas chamar a função
para calcular a soma.
.. raw:: html
.. raw:: html
.. code:: python
x = np.arange(4)
x, x.sum()
.. parsed-literal::
:class: output
(array([0., 1., 2., 3.]), array(6.))
.. raw:: html
.. raw:: html
.. code:: python
x = torch.arange(4, dtype=torch.float32)
x, x.sum()
.. parsed-literal::
:class: output
(tensor([0., 1., 2., 3.]), tensor(6.))
.. raw:: html
.. raw:: html
.. code:: python
x = tf.range(4, dtype=tf.float32)
x, tf.reduce_sum(x)
.. parsed-literal::
:class: output
(,
)
.. raw:: html
.. raw:: html
Podemos expressar somas sobre os elementos de tensores de forma
arbitrária. Por exemplo, a soma dos elementos de uma matriz
:math:`m \times n` :math:`\mathbf{A}` poderia ser escrita como
:math:`\sum_{i=1}^{m} \sum_{j=1}^{n} a_{ij}`.
.. raw:: html
.. raw:: html
.. code:: python
A.shape, A.sum()
.. parsed-literal::
:class: output
((5, 4), array(190.))
.. raw:: html
.. raw:: html
.. code:: python
A.shape, A.sum()
.. parsed-literal::
:class: output
(torch.Size([5, 4]), tensor(190.))
.. raw:: html
.. raw:: html
.. code:: python
A.shape, tf.reduce_sum(A)
.. parsed-literal::
:class: output
(TensorShape([5, 4]), )
.. raw:: html
.. raw:: html
Por padrão, invocar a função para calcular a soma *reduz* um tensor ao
longo de todos os seus eixos a um escalar. Também podemos especificar os
eixos ao longo dos quais o tensor é reduzido por meio da soma Pegue as
matrizes como exemplo. Para reduzir a dimensão da linha (eixo 0) somando
os elementos de todas as linhas, especificamos ``axis = 0`` ao invocar a
função. Uma vez que a matriz de entrada reduz ao longo do eixo 0 para
gerar o vetor de saída, a dimensão do eixo 0 da entrada é perdida na
forma de saída.
.. raw:: html
.. raw:: html
.. code:: python
A_sum_axis0 = A.sum(axis=0)
A_sum_axis0, A_sum_axis0.shape
.. parsed-literal::
:class: output
(array([40., 45., 50., 55.]), (4,))
.. raw:: html
.. raw:: html
.. code:: python
A_sum_axis0 = A.sum(axis=0)
A_sum_axis0, A_sum_axis0.shape
.. parsed-literal::
:class: output
(tensor([40., 45., 50., 55.]), torch.Size([4]))
.. raw:: html
.. raw:: html
.. code:: python
A_sum_axis0 = tf.reduce_sum(A, axis=0)
A_sum_axis0, A_sum_axis0.shape
.. parsed-literal::
:class: output
(,
TensorShape([4]))
.. raw:: html
.. raw:: html
Especificando ``eixo = 1`` irá reduzir a dimensão da coluna (eixo 1) ao
somar os elementos de todas as colunas. Assim, a dimensão do eixo 1 da
entrada é perdida na forma da saída.
.. raw:: html
.. raw:: html
.. code:: python
A_sum_axis1 = A.sum(axis=1)
A_sum_axis1, A_sum_axis1.shape
.. parsed-literal::
:class: output
(array([ 6., 22., 38., 54., 70.]), (5,))
.. raw:: html
.. raw:: html
.. code:: python
A_sum_axis1 = A.sum(axis=1)
A_sum_axis1, A_sum_axis1.shape
.. parsed-literal::
:class: output
(tensor([ 6., 22., 38., 54., 70.]), torch.Size([5]))
.. raw:: html
.. raw:: html
.. code:: python
A_sum_axis1 = tf.reduce_sum(A, axis=1)
A_sum_axis1, A_sum_axis1.shape
.. parsed-literal::
:class: output
(,
TensorShape([5]))
.. raw:: html
.. raw:: html
Reduzindo uma matriz ao longo de ambas as linhas e colunas por meio da
soma é equivalente a somar todos os elementos da matriz.
.. raw:: html
.. raw:: html
.. code:: python
A.sum(axis=[0, 1]) # O mesmo que `A.sum()`
.. parsed-literal::
:class: output
array(190.)
.. raw:: html
.. raw:: html
.. code:: python
A.sum(axis=[0, 1]) # O mesmo que `A.sum()`
.. parsed-literal::
:class: output
tensor(190.)
.. raw:: html
.. raw:: html
.. code:: python
tf.reduce_sum(A, axis=[0, 1]) # O mesmo que `tf.reduce_sum(A)`
.. parsed-literal::
:class: output
.. raw:: html
.. raw:: html
Uma quantidade relacionada é a *média*, que também é chamada de *média*.
Calculamos a média dividindo a soma pelo número total de elementos. No
código, poderíamos apenas chamar a função para calcular a média em
tensores de forma arbitrária.
.. raw:: html
.. raw:: html
.. code:: python
A.mean(), A.sum() / A.size
.. parsed-literal::
:class: output
(array(9.5), array(9.5))
.. raw:: html
.. raw:: html
.. code:: python
A.mean(), A.sum() / A.numel()
.. parsed-literal::
:class: output
(tensor(9.5000), tensor(9.5000))
.. raw:: html
.. raw:: html
.. code:: python
tf.reduce_mean(A), tf.reduce_sum(A) / tf.size(A).numpy()
.. parsed-literal::
:class: output
(,
)
.. raw:: html
.. raw:: html
Da mesma forma, a função de cálculo da média também pode reduzir um
tensor ao longo dos eixos especificados.
.. raw:: html
.. raw:: html
.. code:: python
A.mean(axis=0), A.sum(axis=0) / A.shape[0]
.. parsed-literal::
:class: output
(array([ 8., 9., 10., 11.]), array([ 8., 9., 10., 11.]))
.. raw:: html
.. raw:: html
.. code:: python
A.mean(axis=0), A.sum(axis=0) / A.shape[0]
.. parsed-literal::
:class: output
(tensor([ 8., 9., 10., 11.]), tensor([ 8., 9., 10., 11.]))
.. raw:: html
.. raw:: html
.. code:: python
tf.reduce_mean(A, axis=0), tf.reduce_sum(A, axis=0) / A.shape[0]
.. parsed-literal::
:class: output
(,
)
.. raw:: html
.. raw:: html
.. _subseq_lin-alg-non-reduction:
Soma não reducional
~~~~~~~~~~~~~~~~~~~
Contudo, às vezes pode ser útil manter o número de eixos inalterado ao
invocar a função para calcular a soma ou média.
.. raw:: html
.. raw:: html
.. code:: python
sum_A = A.sum(axis=1, keepdims=True)
sum_A
.. parsed-literal::
:class: output
array([[ 6.],
[22.],
[38.],
[54.],
[70.]])
.. raw:: html
.. raw:: html
.. code:: python
sum_A = A.sum(axis=1, keepdims=True)
sum_A
.. parsed-literal::
:class: output
tensor([[ 6.],
[22.],
[38.],
[54.],
[70.]])
.. raw:: html
.. raw:: html
.. code:: python
sum_A = tf.reduce_sum(A, axis=1, keepdims=True)
sum_A
.. parsed-literal::
:class: output
.. raw:: html
.. raw:: html
Por exemplo, uma vez que ``sum_A`` ainda mantém seus dois eixos após
somar cada linha, podemos dividir\ ``A`` por ``sum_A`` com
*broadcasting*.
.. raw:: html
.. raw:: html
.. code:: python
A / sum_A
.. parsed-literal::
:class: output
array([[0. , 0.16666667, 0.33333334, 0.5 ],
[0.18181819, 0.22727273, 0.27272728, 0.3181818 ],
[0.21052632, 0.23684211, 0.2631579 , 0.28947368],
[0.22222222, 0.24074075, 0.25925925, 0.2777778 ],
[0.22857143, 0.24285714, 0.25714287, 0.27142859]])
.. raw:: html
.. raw:: html
.. code:: python
A / sum_A
.. parsed-literal::
:class: output
tensor([[0.0000, 0.1667, 0.3333, 0.5000],
[0.1818, 0.2273, 0.2727, 0.3182],
[0.2105, 0.2368, 0.2632, 0.2895],
[0.2222, 0.2407, 0.2593, 0.2778],
[0.2286, 0.2429, 0.2571, 0.2714]])
.. raw:: html
.. raw:: html
.. code:: python
A / sum_A
.. parsed-literal::
:class: output
.. raw:: html
.. raw:: html
Se quisermos calcular a soma cumulativa dos elementos de ``A`` ao longo
de algum eixo, diga\ ``eixo = 0`` (linha por linha), podemos chamar a
função ``cumsum``. Esta função não reduzirá o tensor de entrada ao longo
de nenhum eixo.
.. raw:: html
.. raw:: html
.. code:: python
A.cumsum(axis=0)
.. parsed-literal::
:class: output
array([[ 0., 1., 2., 3.],
[ 4., 6., 8., 10.],
[12., 15., 18., 21.],
[24., 28., 32., 36.],
[40., 45., 50., 55.]])
.. raw:: html
.. raw:: html
.. code:: python
A.cumsum(axis=0)
.. parsed-literal::
:class: output
tensor([[ 0., 1., 2., 3.],
[ 4., 6., 8., 10.],
[12., 15., 18., 21.],
[24., 28., 32., 36.],
[40., 45., 50., 55.]])
.. raw:: html
.. raw:: html
.. code:: python
tf.cumsum(A, axis=0)
.. parsed-literal::
:class: output
.. raw:: html
.. raw:: html
Produto Escalar
---------------
Até agora, realizamos apenas operações elementares, somas e médias. E se
isso fosse tudo que pudéssemos fazer, a álgebra linear provavelmente não
mereceria sua própria seção. No entanto, uma das operações mais
fundamentais é o produto escalar. Dados dois vetores
:math:`\mathbf{x}, \mathbf{y} \in \mathbb{R}^d`, seu *produto escalar*
:math:`\mathbf{x}^\top \mathbf{y}` (ou
:math:`\langle \mathbf{x}, \mathbf{y} \rangle`) é uma soma sobre os
produtos dos elementos na mesma posição:
:math:`\mathbf{x}^\top \mathbf{y} = \sum_{i=1}^{d} x_i y_i`.
.. raw:: html
.. raw:: html
.. code:: python
y = np.ones(4)
x, y, np.dot(x, y)
.. parsed-literal::
:class: output
(array([0., 1., 2., 3.]), array([1., 1., 1., 1.]), array(6.))
.. raw:: html
.. raw:: html
.. code:: python
y = torch.ones(4, dtype = torch.float32)
x, y, torch.dot(x, y)
.. parsed-literal::
:class: output
(tensor([0., 1., 2., 3.]), tensor([1., 1., 1., 1.]), tensor(6.))
.. raw:: html
.. raw:: html
.. code:: python
y = tf.ones(4, dtype=tf.float32)
x, y, tf.tensordot(x, y, axes=1)
.. parsed-literal::
:class: output
(,
,
)
.. raw:: html
.. raw:: html
Observe que podemos expressar o produto escalar de dois vetores de forma
equivalente, realizando uma multiplicação elemento a elemento e, em
seguida, uma soma:
.. raw:: html
.. raw:: html
.. code:: python
np.sum(x * y)
.. parsed-literal::
:class: output
array(6.)
.. raw:: html
.. raw:: html
.. code:: python
torch.sum(x * y)
.. parsed-literal::
:class: output
tensor(6.)
.. raw:: html
.. raw:: html
.. code:: python
tf.reduce_sum(x * y)
.. parsed-literal::
:class: output
.. raw:: html
.. raw:: html
Os produtos escalares são úteis em uma ampla variedade de contextos. Por
exemplo, dado algum conjunto de valores, denotado por um vetor
:math:`\mathbf{x} \in \mathbb{R}^d` e um conjunto de pesos denotado por
:math:`\mathbf{w} \in \mathbb{R}^d`,, a soma ponderada dos valores em
:math:`\mathbf{x}` de acordo com os pesos :math:`\mathbf{w}` pode ser
expresso como o produto escalar :math:`\mathbf{x}^\top \mathbf{w}`.
Quando os pesos não são negativos e soma a um (ou seja,
:math:`\left(\sum_{i=1}^{d} {w_i} = 1\right)`), o produto escalar
expressa uma *média ponderada*. Depois de normalizar dois vetores para
ter o comprimento unitário, os produtos escalares expressam o cosseno do
ângulo entre eles. Apresentaremos formalmente essa noção de
*comprimento* posteriormente nesta seção.
Produtos Matriz-Vetor
---------------------
Agora que sabemos como calcular produtos escalares, podemos começar a
entender *produtos vetoriais de matriz*. Lembre-se da matriz
:math:`\mathbf{A} \in \mathbb{R}^{m \times n}` e o vetor
:math:`\mathbf{x} \in \mathbb{R}^n` definido e visualizado em
:eq:`eq_matrix_def` e :eq:`eq_vec_def` respectivamente. Vamos
começar visualizando a matriz :math:`\mathbf{A}` em termos de seus
vetores linha
.. math::
\mathbf{A}=
\begin{bmatrix}
\mathbf{a}^\top_{1} \\
\mathbf{a}^\top_{2} \\
\vdots \\
\mathbf{a}^\top_m \\
\end{bmatrix},
onde cada :math:`\mathbf{a}^\top_{i} \in \mathbb{R}^n` é uma linha vetor
representando a :math:`i^\mathrm{th}` linha da matriz
:math:`\mathbf{A}`.
O produto vetor-matriz :math:`\mathbf{A}\mathbf{x}` é simplesmente um
vetor coluna de comprimento :math:`m`, cujo elemento
:math:`i^\mathrm{th}` é o produto escalar
:math:`\mathbf{a}^\top_i \mathbf{x}`:
.. math::
\mathbf{A}\mathbf{x}
= \begin{bmatrix}
\mathbf{a}^\top_{1} \\
\mathbf{a}^\top_{2} \\
\vdots \\
\mathbf{a}^\top_m \\
\end{bmatrix}\mathbf{x}
= \begin{bmatrix}
\mathbf{a}^\top_{1} \mathbf{x} \\
\mathbf{a}^\top_{2} \mathbf{x} \\
\vdots\\
\mathbf{a}^\top_{m} \mathbf{x}\\
\end{bmatrix}.
Podemos pensar na multiplicação por uma matriz
:math:`\mathbf{A}\in \mathbb{R}^{m \times n}` como uma transformação que
projeta vetores de :math:`\mathbb{R}^{n}` a :math:`\mathbb{R}^{m}`.
Essas transformações revelaram-se extremamente úteis. Por exemplo,
podemos representar rotações como multiplicações por uma matriz
quadrada. Como veremos nos capítulos subsequentes, também podemos usar
produtos vetoriais de matriz para descrever os cálculos mais intensivos
necessário ao calcular cada camada em uma rede neural dados os valores
da camada anterior.
Expressando produtos de vetor-matriz em código com tensores, usamos a
mesma função ``dot`` que para produtos de ponto. Quando chamamos
``np.dot (A, x)`` com uma matriz ``A`` e um vetor\ ``x``, o produto
matriz-vetor é realizado. Observe que a dimensão da coluna de ``A`` (seu
comprimento ao longo do eixo 1) deve ser igual à dimensão de ``x`` (seu
comprimento).
.. raw:: html
.. raw:: html
.. code:: python
A.shape, x.shape, np.dot(A, x)
.. parsed-literal::
:class: output
((5, 4), (4,), array([ 14., 38., 62., 86., 110.]))
.. raw:: html
.. raw:: html
.. code:: python
A.shape, x.shape, torch.mv(A, x)
.. parsed-literal::
:class: output
(torch.Size([5, 4]), torch.Size([4]), tensor([ 14., 38., 62., 86., 110.]))
.. raw:: html
.. raw:: html
.. code:: python
A.shape, x.shape, tf.linalg.matvec(A, x)
.. parsed-literal::
:class: output
(TensorShape([5, 4]),
TensorShape([4]),
)
.. raw:: html
.. raw:: html
Multiplicação Matriz Matriz
---------------------------
Se você já pegou o jeito dos produtos escalares e produtos matriciais,
então a *multiplicação matriz-matriz* deve ser direta. Digamos que temos
duas matrizes :math:`\mathbf{A} \in \mathbb{R}^{n \times k}` e
:math:`\mathbf{B} \in \mathbb{R}^{k \times m}`:
.. math::
\mathbf{A}=\begin{bmatrix}
a_{11} & a_{12} & \cdots & a_{1k} \\
a_{21} & a_{22} & \cdots & a_{2k} \\
\vdots & \vdots & \ddots & \vdots \\
a_{n1} & a_{n2} & \cdots & a_{nk} \\
\end{bmatrix},\quad
\mathbf{B}=\begin{bmatrix}
b_{11} & b_{12} & \cdots & b_{1m} \\
b_{21} & b_{22} & \cdots & b_{2m} \\
\vdots & \vdots & \ddots & \vdots \\
b_{k1} & b_{k2} & \cdots & b_{km} \\
\end{bmatrix}.
Denotada por :math:`\mathbf{a}^\top_{i} \in \mathbb{R}^k` o vetor linha
representando a :math:`i^\mathrm{th}` linha da matriz
:math:`\mathbf{A}`, e :math:`\mathbf{b}_{j} \in \mathbb{R}^k` seja o
vetor coluna da :math:`j^\mathrm{th}` coluna matriz :math:`\mathbf{B}`.
Para produzir o produto de matrizes
:math:`\mathbf{C} = \mathbf{A}\mathbf{B}`, é mais facil pensar
:math:`\mathbf{A}` em termos de seus vetores linha :math:`\mathbf{B}` em
termos de seus vetores coluna:
.. math::
\mathbf{A}=
\begin{bmatrix}
\mathbf{a}^\top_{1} \\
\mathbf{a}^\top_{2} \\
\vdots \\
\mathbf{a}^\top_n \\
\end{bmatrix},
\quad \mathbf{B}=\begin{bmatrix}
\mathbf{b}_{1} & \mathbf{b}_{2} & \cdots & \mathbf{b}_{m} \\
\end{bmatrix}.
Então, o produto da matriz
:math:`\mathbf{C} \in \mathbb{R}^{n \times m}` é produzido, pois
simplesmente calculamos cada elemento :math:`c_ {ij}` como o produto
escalar :math:`\mathbf{a}^\top_i \mathbf{b}_j`:
.. math::
\mathbf{C} = \mathbf{AB} = \begin{bmatrix}
\mathbf{a}^\top_{1} \\
\mathbf{a}^\top_{2} \\
\vdots \\
\mathbf{a}^\top_n \\
\end{bmatrix}
\begin{bmatrix}
\mathbf{b}_{1} & \mathbf{b}_{2} & \cdots & \mathbf{b}_{m} \\
\end{bmatrix}
= \begin{bmatrix}
\mathbf{a}^\top_{1} \mathbf{b}_1 & \mathbf{a}^\top_{1}\mathbf{b}_2& \cdots & \mathbf{a}^\top_{1} \mathbf{b}_m \\
\mathbf{a}^\top_{2}\mathbf{b}_1 & \mathbf{a}^\top_{2} \mathbf{b}_2 & \cdots & \mathbf{a}^\top_{2} \mathbf{b}_m \\
\vdots & \vdots & \ddots &\vdots\\
\mathbf{a}^\top_{n} \mathbf{b}_1 & \mathbf{a}^\top_{n}\mathbf{b}_2& \cdots& \mathbf{a}^\top_{n} \mathbf{b}_m
\end{bmatrix}.
Podemos pensar na multiplicação matriz-matriz :math:`\mathbf {AB}`
simplesmente realizando :math:`m` produtos vetoriais de matriz e
juntando os resultados para formar uma matriz :math:`n \times m`. No
trecho a seguir, realizamos a multiplicação da matriz em ``A`` e\ ``B``.
Aqui, ``A`` é uma matriz com 5 linhas e 4 colunas, e ``B`` é uma matriz
com 4 linhas e 3 colunas. Após a multiplicação, obtemos uma matriz com 5
linhas e 3 colunas.
.. raw:: html
.. raw:: html
.. code:: python
B = np.ones(shape=(4, 3))
np.dot(A, B)
.. parsed-literal::
:class: output
array([[ 6., 6., 6.],
[22., 22., 22.],
[38., 38., 38.],
[54., 54., 54.],
[70., 70., 70.]])
.. raw:: html
.. raw:: html
.. code:: python
B = torch.ones(4, 3)
torch.mm(A, B)
.. parsed-literal::
:class: output
tensor([[ 6., 6., 6.],
[22., 22., 22.],
[38., 38., 38.],
[54., 54., 54.],
[70., 70., 70.]])
.. raw:: html
.. raw:: html
.. code:: python
B = tf.ones((4, 3), tf.float32)
tf.matmul(A, B)
.. parsed-literal::
:class: output
.. raw:: html
.. raw:: html
A multiplicação de matriz-matriz pode ser simplesmente chamada de
*multiplicação de matrizes* e não deve ser confundida com o produto
Hadamard.
.. _subsec_lin-algebra-norms:
Normas
------
Alguns dos operadores mais úteis em álgebra linear são *normas*.
Informalmente, a norma de um vetor nos diz o quão *grande* é um vetor. A
noção de *tamanho* em consideração aqui preocupa-se não em
dimensionalidade ,mas sim a magnitude dos componentes.
Na álgebra linear, uma norma vetorial é uma função :math:`f` que mapeia
um vetor para um escalar, satisfazendo um punhado de propriedades. Dado
qualquer vetor :math:`\mathbf{x}`, a primeira propriedade diz que se
escalarmos todos os elementos de um vetor por um fator constante
:math:`\alpha`, sua norma também escala pelo *valor absoluto* do mesmo
fator constante:
.. math:: f(\alpha \mathbf{x}) = |\alpha| f(\mathbf{x}).
A segunda propriedade é a familiar desigualdade do triângulo:
.. math:: f(\mathbf{x} + \mathbf{y}) \leq f(\mathbf{x}) + f(\mathbf{y}).
A terceira propriedade simplesmente diz que a norma deve ser não
negativa:
.. math:: f(\mathbf{x}) \geq 0.
Isso faz sentido, pois na maioria dos contextos, o menor *tamanho* para
qualquer coisa é 0. A propriedade final requer que a menor norma seja
alcançada e somente alcançada por um vetor que consiste em todos os
zeros.
.. math:: \forall i, [\mathbf{x}]_i = 0 \Leftrightarrow f(\mathbf{x})=0.
Você pode notar que as normas se parecem muito com medidas de distância.
E se você se lembra das distâncias euclidianas (pense no teorema de
Pitágoras) da escola primária, então, os conceitos de não negatividade e
a desigualdade do triângulo podem ser familiares. Na verdade, a
distância euclidiana é uma norma: especificamente, é a norma
:math:`L_2`. Suponha que os elementos no vetor :math:`n` -dimensional
:math:`\mathbf{x}` são :math:`x_1, \ldots, x_n`.
A :math:`L_2` *norma* de :math:`\mathbf {x}` é a raiz quadrada da soma
dos quadrados dos elementos do vetor:
.. math:: \|\mathbf{x}\|_2 = \sqrt{\sum_{i=1}^n x_i^2},
onde o subscrito :math:`2` é frequentemente omitido nas normas
:math:`L_2`, ou seja, :math:`\|\mathbf{x}\|` é equivalente a
:math:`\|\mathbf{x}\|_2`. Em código, podemos calcular a norma
:math:`L_2` de um vetor da seguinte maneira.
.. raw:: html
.. raw:: html
.. code:: python
u = np.array([3, -4])
np.linalg.norm(u)
.. parsed-literal::
:class: output
array(5.)
.. raw:: html
.. raw:: html
.. code:: python
u = torch.tensor([3.0, -4.0])
torch.norm(u)
.. parsed-literal::
:class: output
tensor(5.)
.. raw:: html
.. raw:: html
.. code:: python
u = tf.constant([3.0, -4.0])
tf.norm(u)
.. parsed-literal::
:class: output
.. raw:: html
.. raw:: html
Em *Deep Learning*, trabalhamos com mais frequência com a norma
:math:`L_2` ao quadrado.
Você também encontrará frequentemente a norma :math:`L_1`, que é
expresso como a soma dos valores absolutos dos elementos do vetor:
.. math:: \|\mathbf{x}\|_1 = \sum_{i=1}^n \left|x_i \right|.
Em comparação com a norma :math:`L_2`, é menos influenciado por
outliers. Para calcular a norma :math:`L_1`, nós compomos a função de
valor absoluto com uma soma sobre os elementos.
.. raw:: html
.. raw:: html
.. code:: python
np.abs(u).sum()
.. parsed-literal::
:class: output
array(7.)
.. raw:: html
.. raw:: html
.. code:: python
torch.abs(u).sum()
.. parsed-literal::
:class: output
tensor(7.)
.. raw:: html
.. raw:: html
.. code:: python
tf.reduce_sum(tf.abs(u))
.. parsed-literal::
:class: output
.. raw:: html
.. raw:: html
Tanto a norma :math:`L_2` quanto a norma :math:`L_1` são casos especiais
da norma mais geral :math:`L_p`:
.. math:: \|\mathbf{x}\|_p = \left(\sum_{i=1}^n \left|x_i \right|^p \right)^{1/p}.
Análogo a :math:`L_2` normas de vetores, a *norma de Frobenius* de uma
matriz :math:`\mathbf{X} \in \mathbb{R}^{m \times n}` é a raiz quadrada
da soma dos quadrados dos elementos da matriz:
.. math:: \|\mathbf{X}\|_F = \sqrt{\sum_{i=1}^m \sum_{j=1}^n x_{ij}^2}.
A norma Frobenius satisfaz todas as propriedades das normas vetoriais.
Ele se comporta como se fosse uma norma :math:`L_2` de um vetor em forma
de matriz. Invocar a função a seguir calculará a norma de Frobenius de
uma matriz.
.. raw:: html
.. raw:: html
.. code:: python
np.linalg.norm(np.ones((4, 9)))
.. parsed-literal::
:class: output
array(6.)
.. raw:: html
.. raw:: html
.. code:: python
torch.norm(torch.ones((4, 9)))
.. parsed-literal::
:class: output
tensor(6.)
.. raw:: html
.. raw:: html
.. code:: python
tf.norm(tf.ones((4, 9)))
.. parsed-literal::
:class: output
.. raw:: html
.. raw:: html
.. _subsec_norms_and_objectives:
Normas e Objetivos
~~~~~~~~~~~~~~~~~~
Embora não queiramos nos adiantar muito, já podemos ter uma intuição
sobre por que esses conceitos são úteis. No *Deep Learning*, muitas
vezes tentamos resolver problemas de otimização: *maximizar* a
probabilidade atribuída aos dados observados; *minimizar* a distância
entre as previsões e as observações de verdade. Atribuir representações
vetoriais a itens (como palavras, produtos ou artigos de notícias) de
modo que a distância entre itens semelhantes seja minimizada, e a
distância entre itens diferentes é maximizada. Muitas vezes, os
objetivos, talvez os componentes mais importantes de algoritmos de *Deep
Learning* (além dos dados), são expressos como normas.
Mais sobre Algebra Linear
-------------------------
Apenas nesta seção, nós ensinamos a vocês toda a álgebra linear que você
precisa entender um pedaço notável do aprendizado profundo moderno. Há
muito mais coisas na álgebra linear e muito dessa matemática é útil para
o *Deep Learning*. Por exemplo, as matrizes podem ser decompostas em
fatores, e essas decomposições podem revelar estrutura de baixa dimensão
em conjuntos de dados do mundo real. Existem subcampos inteiros de *Deep
Learning* que se concentram no uso de decomposições de matriz e suas
generalizações para tensores de alta ordem para descobrir a estrutura em
conjuntos de dados e resolver problemas de previsão. Mas este livro se
concentra no *Deep Learning*. E acreditamos que você estará muito mais
inclinado a aprender mais matemática depois de sujar as mãos implantar
modelos úteis de aprendizado de máquina em conjuntos de dados reais.
Portanto, embora nos reservemos o direito de introduzir mais matemática
muito mais tarde, vamos encerrar esta seção aqui.
Se voce gostaria de aprender mais sobre Algebra Linear, pode procurar em
`apêndice online sobre operações de algebra
linear `__
ou outra excelente fonte
:cite:`Strang.1993,Kolter.2008,Petersen.Pedersen.ea.2008`.
Sumário
-------
- Escalares, vetores, matrizes e tensores são objetos matemáticos
básicos em álgebra linear.
- Vetores generalizam escalares e matrizes generalizam vetores.
- Escalares, vetores, matrizes e tensores têm zero, um, dois e um
número arbitrário de eixos, respectivamente.
- Um tensor pode ser reduzido ao longo dos eixos especificados por
``soma`` e ``média``.
- A multiplicação elementar de duas matrizes é chamada de produto
Hadamard. É diferente da multiplicação de matrizes.
- No aprendizado profundo, geralmente trabalhamos com normas como a
norma :math:`L_1`, a norma :math:`L_2` e a norma Frobenius.
- Podemos realizar uma variedade de operações sobre escalares, vetores,
matrizes e tensores.
Exercícios
----------
1. Prove que a transposta de uma matriz :math:`\mathbf {A}` transposta é
:math:`\mathbf {A}`:
:math:`(\mathbf {A} ^ \top) ^ \top = \mathbf {A}`.
2. Dadas duas matrizes :math:`\mathbf {A}` e :math:`\mathbf {B}`, mostre
que a soma das transpostas é igual à transposta de uma soma:
:math:`\mathbf {A} ^ \top + \mathbf {B} ^ \top = (\mathbf {A} + \mathbf {B}) ^ \top`.
3. Dada qualquer matriz quadrada :math:`\mathbf {A}`,
:math:`\mathbf {A} + \mathbf {A} ^ \top` é sempre simétrica? Porque?
4. Definimos o tensor ``X`` de forma (2, 3, 4) nesta seção. Qual é a
saída de ``len (X)``?
5. Para um tensor ``X`` de forma arbitrária, ``len (X)``\ sempre
corresponde ao comprimento de um certo eixo de ``X``? Qual é esse
eixo?
6. Execute ``A / A.sum (eixo = 1)`` e veja o que acontece. Você pode
analisar o motivo?
7. Ao viajar entre dois pontos em Manhattan, qual é a distância que você
precisa percorrer em termos de coordenadas, ou seja, em termos de
avenidas e ruas? Você pode viajar na diagonal?
8. Considere um tensor com forma (2, 3, 4). Quais são as formas das
saídas de soma ao longo dos eixos 0, 1 e 2?
9. Alimente um tensor com 3 ou mais eixos para a função ``linalg.norm``
e observe sua saída. O que essa função calcula para tensores de forma
arbitrária?
.. raw:: html
.. raw:: html
`Discussions `__
.. raw:: html
.. raw:: html
`Discussions `__
.. raw:: html
.. raw:: html
`Discussions `__
.. raw:: html
.. raw:: html
.. raw:: html