.. _sec_eigendecompositions:
Autovalores e Autovetores
=========================
Os autovalores são frequentemente uma das noções mais úteis
encontraremos ao estudar álgebra linear, entretanto, como um iniciante,
é fácil ignorar sua importância. Abaixo, apresentamos a decomposção e
cálculo destes, e tentamos transmitir algum sentido de por que é tão
importante.
Suponha que tenhamos uma matriz :math:`A` com as seguintes entradas:
.. math::
\mathbf{A} = \begin{bmatrix}
2 & 0 \\
0 & -1
\end{bmatrix}.
Se aplicarmos :math:`A` a qualquer vetor
:math:`\mathbf{v} = [x, y]^\top`, obtemos um vetor
:math:`\mathbf{A}\mathbf{v} = [2x, -y]^\top`. Isso tem uma interpretação
intuitiva: estique o vetor para ser duas vezes mais largo na direção
:math:`x`, e, em seguida, inverta-o na direção :math:`y`-direcionamento.
No entanto, existem *alguns* vetores para os quais algo permanece
inalterado. A saber, :math:`[1, 0]^\top` é enviado para
:math:`[2, 0]^\top` e :math:`[0, 1]^\top` é enviado para
:math:`[0, -1]^\top`. Esses vetores ainda estão na mesma linha, e a
única modificação é que a matriz os estica por um fator de :math:`2` e
:math:`-1` respectivamente. Chamamos esses vetores de *autovetores* e o
fator eles são estendidos por *autovalores*.
Em geral, se pudermos encontrar um número :math:`\lambda` e um vetor
:math:`\mathbf{v}` tal que
.. math::
\mathbf{A}\mathbf{v} = \lambda \mathbf{v}.
Dizemos que :math:`\mathbf{v}` é um autovetor para :math:`A` e
:math:`\lambda` é um autovalor.
Encontrando Autovalores
-----------------------
Vamos descobrir como encontrá-los. Subtraindo :math:`\lambda \mathbf{v}`
de ambos os lados, e então fatorar o vetor, vemos que o acima é
equivalente a:
.. math:: (\mathbf{A} - \lambda \mathbf{I})\mathbf{v} = 0.
:label: eq_eigvalue_der
Para :eq:`eq_eigvalue_der` acontecer, vemos que
:math:`(\mathbf{A} - \lambda \mathbf{I})` deve comprimir alguma direção
até zero, portanto, não é invertível e, portanto, o determinante é zero.
Assim, podemos encontrar os *valores próprios* descobrindo quanto
:math:`\lambda` is :math:`\det(\mathbf{A}-\lambda \mathbf{I}) = 0`.
Depois de encontrar os valores próprios, podemos resolver
:math:`\mathbf{A}\mathbf{v} = \lambda \mathbf{v}` para encontrar os
*autovetores* associados.
Um Exemplo
~~~~~~~~~~
Vamos ver isso com uma matriz mais desafiadora
.. math::
\mathbf{A} = \begin{bmatrix}
2 & 1\\
2 & 3
\end{bmatrix}.
Se considerarmos :math:`\det(\mathbf{A}-\lambda \mathbf{I}) = 0`, vemos
que isso é equivalente à equação polinomial
:math:`0 = (2-\lambda)(3-\lambda)-2 = (4-\lambda)(1-\lambda)`. Assim,
dois valores próprios são :math:`4` e :math:`1`. Para encontrar os
vetores associados, precisamos resolver
.. math::
\begin{bmatrix}
2 & 1\\
2 & 3
\end{bmatrix}\begin{bmatrix}x \\ y\end{bmatrix} = \begin{bmatrix}x \\ y\end{bmatrix} \; \text{and} \;
\begin{bmatrix}
2 & 1\\
2 & 3
\end{bmatrix}\begin{bmatrix}x \\ y\end{bmatrix} = \begin{bmatrix}4x \\ 4y\end{bmatrix} .
Podemos resolver isso com os vetores :math:`[1, -1]^\top` and
:math:`[1, 2]^\top` respectivamente.
Podemos verificar isso no código usando a rotina incorporada
``numpy.linalg.eig``.
.. raw:: html
.. raw:: html
.. code:: python
%matplotlib inline
import numpy as np
from IPython import display
from d2l import mxnet as d2l
np.linalg.eig(np.array([[2, 1], [2, 3]]))
.. parsed-literal::
:class: output
(array([1., 4.]),
array([[-0.70710678, -0.4472136 ],
[ 0.70710678, -0.89442719]]))
.. raw:: html
.. raw:: html
.. code:: python
%matplotlib inline
import torch
from IPython import display
from d2l import torch as d2l
torch.eig(torch.tensor([[2, 1], [2, 3]], dtype=torch.float64),
eigenvectors=True)
.. parsed-literal::
:class: output
torch.return_types.eig(
eigenvalues=tensor([[1., 0.],
[4., 0.]], dtype=torch.float64),
eigenvectors=tensor([[-0.7071, -0.4472],
[ 0.7071, -0.8944]], dtype=torch.float64))
.. raw:: html
.. raw:: html
.. code:: python
%matplotlib inline
import tensorflow as tf
from IPython import display
from d2l import tensorflow as d2l
tf.linalg.eig(tf.constant([[2, 1], [2, 3]], dtype=tf.float64))
.. parsed-literal::
:class: output
(,
)
.. raw:: html
.. raw:: html
Observe que ``numpy`` normaliza os vetores próprios para ter comprimento
um, ao passo que consideramos o nosso comprimento arbitrário. Além
disso, a escolha do sinal é arbitrária. No entanto, os vetores
calculados são paralelos aos que encontramos à mão com os mesmos
autovalores.
Matrizes de Decomposição
------------------------
Vamos continuar o exemplo anterior um passo adiante. Deixe
.. math::
\mathbf{W} = \begin{bmatrix}
1 & 1 \\
-1 & 2
\end{bmatrix},
ser a matriz onde as colunas são os autovetores da matriz
:math:`\mathbf{A}`. Deixe
.. math::
\boldsymbol{\Sigma} = \begin{bmatrix}
1 & 0 \\
0 & 4
\end{bmatrix},
ser a matriz com os autovalores associados na diagonal. Então, a
definição de autovalores e autovetores nos diz que
.. math::
\mathbf{A}\mathbf{W} =\mathbf{W} \boldsymbol{\Sigma} .
A matriz :math:`W` é invertível, então podemos multiplicar ambos os
lados por :math:`W^{-1}` à direita, nós vemos que podemos escrever
.. math:: \mathbf{A} = \mathbf{W} \boldsymbol{\Sigma} \mathbf{W}^{-1}.
:label: eq_eig_decomp
Na próxima seção, veremos algumas consequências interessantes disso, mas
por agora só precisamos saber que tal decomposição existirá enquanto
pudermos encontrar uma coleção completa de autovetores linearmente
independentes (de forma que :math:`W` seja invertível).
Operações em Autovalores e Autovetores
--------------------------------------
Uma coisa boa sobre autovalores e autovetores :eq:`eq_eig_decomp` é
que podemos escrever muitas operações que geralmente encontramos de
forma limpa em termos da decomposição automática. Como primeiro exemplo,
considere:
.. math::
\mathbf{A}^n = \overbrace{\mathbf{A}\cdots \mathbf{A}}^{\text{$n$ times}} = \overbrace{(\mathbf{W}\boldsymbol{\Sigma} \mathbf{W}^{-1})\cdots(\mathbf{W}\boldsymbol{\Sigma} \mathbf{W}^{-1})}^{\text{$n$ times}} = \mathbf{W}\overbrace{\boldsymbol{\Sigma}\cdots\boldsymbol{\Sigma}}^{\text{$n$ times}}\mathbf{W}^{-1} = \mathbf{W}\boldsymbol{\Sigma}^n \mathbf{W}^{-1}.
Isso nos diz que para qualquer poder positivo de uma matriz, a
autodecomposição é obtida apenas elevando os autovalores à mesma
potência. O mesmo pode ser mostrado para potências negativas, então, se
quisermos inverter uma matriz, precisamos apenas considerar
.. math::
\mathbf{A}^{-1} = \mathbf{W}\boldsymbol{\Sigma}^{-1} \mathbf{W}^{-1},
ou em outras palavras, apenas inverta cada autovalor. Isso funcionará,
desde que cada autovalor seja diferente de zero, portanto, vemos que
invertível é o mesmo que não ter autovalores zero.
De fato, um trabalho adicional pode mostrar que se
:math:`\lambda_1, \ldots, \lambda_n` são os autovalores de uma matriz,
então o determinante dessa matriz é
.. math::
\det(\mathbf{A}) = \lambda_1 \cdots \lambda_n,
ou o produto de todos os autovalores. Isso faz sentido intuitivamente
porque qualquer coisa que esticar :math:`\mathbf{W}` faz, :math:`W^{-1}`
desfaz, então, no final, o único alongamento que acontece é por
multiplicação pela matriz diagonal :math:`\boldsymbol{\Sigma}`, que
estica os volumes pelo produto dos elementos diagonais.
Por fim, lembre-se de que a classificação era o número máximo de colunas
linearmente independentes de sua matriz. Examinando a decomposição de
perto, podemos ver que a classificação é a mesma que o número de
autovalores diferentes de zero de :math:`\mathbf{A}`.
Os exemplos podem continuar, mas espero que o ponto esteja claro: A
autodecomposição pode simplificar muitos cálculos algébricos lineares e
é uma operação fundamental subjacente a muitos algoritmos numéricos e
muitas das análises que fazemos em álgebra linear.
Composições Originais de Matrizes Simétricas
--------------------------------------------
Nem sempre é possível encontrar autovetores independentes linearmente
suficientes para que o processo acima funcione. Por exemplo, a matriz
.. math::
\mathbf{A} = \begin{bmatrix}
1 & 1 \\
0 & 1
\end{bmatrix},
tem apenas um único autovetor, a saber :math:`(1, 0)^\top`. Para lidar
com essas matrizes, exigimos técnicas mais avançadas do que podemos
cobrir (como a Forma Normal de Jordan ou Decomposição de Valor
Singular). Frequentemente precisaremos restringir nossa atenção a essas
matrizes onde podemos garantir a existência de um conjunto completo de
autovetores.
A família mais comumente encontrada são as *matrizes simétricas*, que
são aquelas matrizes onde :math:`\mathbf{A} = \mathbf{A}^\top`.
Neste caso, podemos tomar :math:`W` como uma *matriz ortogonal* - uma
matriz cujas colunas são todas vetores de comprimento unitário que estão
em ângulos retos entre si, onde
:math:`\mathbf{W}^\top = \mathbf{W}^{-1}` – e todos os autovalores serão
reais. Assim, neste caso especial, podemos escrever
:eq:`eq_eig_decomp` como
.. math::
\mathbf{A} = \mathbf{W}\boldsymbol{\Sigma}\mathbf{W}^\top .
Teorema do Círculo de Gershgorin
--------------------------------
Os valores próprios costumam ser difíceis de raciocinar intuitivamente.
Se for apresentada uma matriz arbitrária, pouco pode ser dito sobre
quais são os valores próprios sem computá-los. Há, no entanto, um
teorema que pode facilitar uma boa aproximação se os maiores valores
estiverem na diagonal.
Seja :math:`\mathbf{A} = (a_{ij})` qualquer matriz
quadrada(\ :math:`n\times n`). Definiremos
:math:`r_i = \sum_{j \neq i} |a_{ij}|`. Deixe :math:`\mathcal{D}_i`
representar o disco no plano complexo com centro :math:`a_{ii}` radius
:math:`r_i`. Então, cada autovalor de :math:`\mathbf{A}` está contido em
um dos :math:`\mathcal{D}_i`.
Isso pode ser um pouco difícil de descompactar, então vejamos um
exemplo. Considere a matriz:
.. math::
\mathbf{A} = \begin{bmatrix}
1.0 & 0.1 & 0.1 & 0.1 \\
0.1 & 3.0 & 0.2 & 0.3 \\
0.1 & 0.2 & 5.0 & 0.5 \\
0.1 & 0.3 & 0.5 & 9.0
\end{bmatrix}.
Temos :math:`r_1 = 0.3`, :math:`r_2 = 0.6`, :math:`r_3 = 0.8` e
:math:`r_4 = 0.9`. A matriz é simétrica, portanto, todos os autovalores
são reais. Isso significa que todos os nossos valores próprios estarão
em um dos intervalos de
.. math:: [a_{11}-r_1, a_{11}+r_1] = [0.7, 1.3],
.. math:: [a_{22}-r_2, a_{22}+r_2] = [2.4, 3.6],
.. math:: [a_{33}-r_3, a_{33}+r_3] = [4.2, 5.8],
.. math:: [a_{44}-r_4, a_{44}+r_4] = [8.1, 9.9].
Realizar o cálculo numérico mostra que os valores próprios são
aproximadamente :math:`0.99`, :math:`2.97`, :math:`4.95`, :math:`9.08`,
tudo confortavelmente dentro das faixas fornecidas.
.. raw:: html
.. raw:: html
.. code:: python
A = np.array([[1.0, 0.1, 0.1, 0.1],
[0.1, 3.0, 0.2, 0.3],
[0.1, 0.2, 5.0, 0.5],
[0.1, 0.3, 0.5, 9.0]])
v, _ = np.linalg.eig(A)
v
.. parsed-literal::
:class: output
array([9.08033648, 0.99228545, 4.95394089, 2.97343718])
.. raw:: html
.. raw:: html
.. code:: python
A = torch.tensor([[1.0, 0.1, 0.1, 0.1],
[0.1, 3.0, 0.2, 0.3],
[0.1, 0.2, 5.0, 0.5],
[0.1, 0.3, 0.5, 9.0]])
v, _ = torch.eig(A)
v
.. parsed-literal::
:class: output
tensor([[0.9923, 0.0000],
[9.0803, 0.0000],
[4.9539, 0.0000],
[2.9734, 0.0000]])
.. raw:: html
.. raw:: html
.. code:: python
A = tf.constant([[1.0, 0.1, 0.1, 0.1],
[0.1, 3.0, 0.2, 0.3],
[0.1, 0.2, 5.0, 0.5],
[0.1, 0.3, 0.5, 9.0]])
v, _ = tf.linalg.eigh(A)
v
.. parsed-literal::
:class: output
.. raw:: html
.. raw:: html
Desta forma, os autovalores podem ser aproximados, e as aproximações
serão bastante precisas no caso em que a diagonal é significativamente
maior do que todos os outros elementos.
É uma coisa pequena, mas com um complexo e um tópico sutil como;
decomposição automática, é bom obter qualquer compreensão intuitiva
possível.
Uma Aplicação Útil: o Crescimento de Mapas Iterados
---------------------------------------------------
Agora que entendemos o que são autovetores, em princípio, vamos ver como
eles podem ser usados para fornecer um entendimento profundo de um
problema central para o comportamento da rede neural: inicialização de
peso adequada.
Autovetores como Comportamento de Longo Prazo
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A investigação matemática completa da inicialização de redes neurais
profundas está além do escopo do texto, mas podemos ver uma versão de
brinquedo aqui para entender como os autovalores podem nos ajudar a ver
como esses modelos funcionam. Como sabemos, as redes neurais operam por
camadas intercaladas de transformações lineares com operações não
lineares. Para simplificar aqui, vamos supor que não há não linearidade,
e que a transformação é uma única operação de matriz repetida :math:`A`,
para que a saída do nosso modelo seja
.. math::
\mathbf{v}_{out} = \mathbf{A}\cdot \mathbf{A}\cdots \mathbf{A} \mathbf{v}_{in} = \mathbf{A}^N \mathbf{v}_{in}.
Quando esses modelos são inicializados, :math:`A` é considerado uma
matriz aleatória com entradas gaussianas, então vamos fazer uma delas.
Para ser concreto, começamos com uma média zero, variância um Gaussiana
distribuída :math:`5 \times 5` matriz.
.. raw:: html
.. raw:: html
.. code:: python
np.random.seed(8675309)
k = 5
A = np.random.randn(k, k)
A
.. parsed-literal::
:class: output
array([[ 0.58902366, 0.73311856, -1.1621888 , -0.55681601, -0.77248843],
[-0.16822143, -0.41650391, -1.37843129, 0.74925588, 0.17888446],
[ 0.69401121, -1.9780535 , -0.83381434, 0.56437344, 0.31201299],
[-0.87334496, 0.15601291, -0.38710108, -0.23920821, 0.88850104],
[ 1.29385371, -0.76774106, 0.20131613, 0.91800842, 0.38974115]])
.. raw:: html
.. raw:: html
.. code:: python
torch.manual_seed(42)
k = 5
A = torch.randn(k, k, dtype=torch.float64)
A
.. parsed-literal::
:class: output
tensor([[ 0.2996, 0.2424, 0.2832, -0.2329, 0.6712],
[ 0.7818, -1.7903, -1.7484, 0.1735, -0.1182],
[-1.7446, -0.4695, 0.4573, 0.5177, -0.2771],
[-0.6641, 0.6551, 0.2616, -1.5265, -0.3311],
[-0.6378, 0.1072, 0.7096, 0.3009, -0.2869]], dtype=torch.float64)
.. raw:: html
.. raw:: html
.. code:: python
k = 5
A = tf.random.normal((k, k), dtype=tf.float64)
A
.. parsed-literal::
:class: output
.. raw:: html
.. raw:: html
Behavior on Random Data
~~~~~~~~~~~~~~~~~~~~~~~
Para simplificar nosso modelo de brinquedo, vamos assumir que o vetor de
dados que alimentamos em :math:`\mathbf{v}_{in}` é um vetor gaussiano
aleatório de cinco dimensões. Vamos pensar sobre o que queremos que
aconteça. Para contextualizar, vamos pensar em um problema genérico de
ML, onde estamos tentando transformar dados de entrada, como uma imagem,
em uma previsão, como a probabilidade de a imagem ser a foto de um gato.
Se a aplicação repetida de :math:`\mathbf{A}` estende um vetor aleatório
para ser muito longo, então, pequenas mudanças na entrada serão
amplificadas em grandes mudanças na saída — pequenas modificações da
imagem de entrada levaria a previsões muito diferentes. Isso não parece
certo!
Por outro lado, se :math:`\mathbf{A}` encolhe vetores aleatórios para
serem mais curtos, então, depois de passar por muitas camadas, o vetor
irá essencialmente encolher a nada, e a saída não dependerá da entrada.
Isso também claramente não está certo!
Precisamos andar na linha estreita entre o crescimento e a decadência
para ter certeza de que nossa saída muda dependendo de nossa entrada,
mas não muito!
Vamos ver o que acontece quando multiplicamos repetidamente nossa matriz
:math:`\mathbf{A}` contra um vetor de entrada aleatório e acompanhe a
norma.
.. raw:: html
.. raw:: html
.. code:: python
# Calculate the sequence of norms after repeatedly applying `A`
v_in = np.random.randn(k, 1)
norm_list = [np.linalg.norm(v_in)]
for i in range(1, 100):
v_in = A.dot(v_in)
norm_list.append(np.linalg.norm(v_in))
d2l.plot(np.arange(0, 100), norm_list, 'Iteration', 'Value')
.. figure:: output_eigendecomposition_ee2e00_39_0.svg
.. raw:: html
.. raw:: html
.. code:: python
# Calculate the sequence of norms after repeatedly applying `A`
v_in = torch.randn(k, 1, dtype=torch.float64)
norm_list = [torch.norm(v_in).item()]
for i in range(1, 100):
v_in = A @ v_in
norm_list.append(torch.norm(v_in).item())
d2l.plot(torch.arange(0, 100), norm_list, 'Iteration', 'Value')
.. figure:: output_eigendecomposition_ee2e00_42_0.svg
.. raw:: html
.. raw:: html
.. code:: python
# Calculate the sequence of norms after repeatedly applying `A`
v_in = tf.random.normal((k, 1), dtype=tf.float64)
norm_list = [tf.norm(v_in).numpy()]
for i in range(1, 100):
v_in = tf.matmul(A, v_in)
norm_list.append(tf.norm(v_in).numpy())
d2l.plot(tf.range(0, 100), norm_list, 'Iteration', 'Value')
.. figure:: output_eigendecomposition_ee2e00_45_0.svg
.. raw:: html
.. raw:: html
The norm is growing uncontrollably! Indeed if we take the list of
quotients, we will see a pattern.
.. raw:: html
.. raw:: html
.. code:: python
# Compute the scaling factor of the norms
norm_ratio_list = []
for i in range(1, 100):
norm_ratio_list.append(norm_list[i]/norm_list[i - 1])
d2l.plot(np.arange(1, 100), norm_ratio_list, 'Iteration', 'Ratio')
.. figure:: output_eigendecomposition_ee2e00_51_0.svg
.. raw:: html
.. raw:: html
.. code:: python
# Compute the scaling factor of the norms
norm_ratio_list = []
for i in range(1, 100):
norm_ratio_list.append(norm_list[i]/norm_list[i - 1])
d2l.plot(torch.arange(1, 100), norm_ratio_list, 'Iteration', 'Ratio')
.. figure:: output_eigendecomposition_ee2e00_54_0.svg
.. raw:: html
.. raw:: html
.. code:: python
# Compute the scaling factor of the norms
norm_ratio_list = []
for i in range(1, 100):
norm_ratio_list.append(norm_list[i]/norm_list[i - 1])
d2l.plot(tf.range(1, 100), norm_ratio_list, 'Iteration', 'Ratio')
.. figure:: output_eigendecomposition_ee2e00_57_0.svg
.. raw:: html
.. raw:: html
Se olharmos para a última parte do cálculo acima, vemos que o vetor
aleatório é alongado por um fator de ``1.974459321485[...]``, onde a
parte no final muda um pouco, mas o fator de alongamento é estável.
Relacionando-se com os Autovetores
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Vimos que autovetores e autovalores correspondem na medida em que algo é
esticado, mas isso era para vetores específicos e trechos específicos.
Vamos dar uma olhada no que eles são para :math:`\mathbf{A}`. Uma
pequena advertência aqui: acontece que, para ver todos eles,
precisaremos ir para os números complexos. Você pode pensar nisso como
alongamentos e rotações. Pegando a norma do número complexo (raiz
quadrada das somas dos quadrados das partes reais e imaginárias) podemos
medir esse fator de alongamento. Deixe-nos também classificá-los.
.. raw:: html
.. raw:: html
.. code:: python
# Compute the eigenvalues
eigs = np.linalg.eigvals(A).tolist()
norm_eigs = [np.absolute(x) for x in eigs]
norm_eigs.sort()
print(f'norms of eigenvalues: {norm_eigs}')
.. parsed-literal::
:class: output
norms of eigenvalues: [0.8786205280381857, 1.2757952665062624, 1.4983381517710659, 1.4983381517710659, 1.974459321485074]
.. raw:: html
.. raw:: html
.. code:: python
# Compute the eigenvalues
eigs = torch.eig(A)[0][:,0].tolist()
norm_eigs = [torch.abs(torch.tensor(x)) for x in eigs]
norm_eigs.sort()
print(f'norms of eigenvalues: {norm_eigs}')
.. parsed-literal::
:class: output
norms of eigenvalues: [tensor(0.3490), tensor(0.5691), tensor(0.5691), tensor(1.1828), tensor(2.4532)]
.. raw:: html
.. raw:: html
.. code:: python
# Compute the eigenvalues
eigs = tf.linalg.eigh(A)[0].numpy().tolist()
norm_eigs = [tf.abs(tf.constant(x, dtype=tf.float64)) for x in eigs]
norm_eigs.sort()
print(f'norms of eigenvalues: {norm_eigs}')
.. parsed-literal::
:class: output
norms of eigenvalues: [, , , , ]
.. raw:: html
.. raw:: html
Uma Observação
~~~~~~~~~~~~~~
Vemos algo um pouco inesperado acontecendo aqui: aquele número que
identificamos antes para o alongamento de longo prazo de nossa matriz
:math:`\mathbf{A}` aplicado a um vetor aleatório é *exatamente* (com
precisão de treze casas decimais!) o maior autovalor de
:math:`\mathbf{A}`. Isso claramente não é uma coincidência!
Mas, se agora pensarmos sobre o que está acontecendo geometricamente,
isso começa a fazer sentido. Considere um vetor aleatório. Este vetor
aleatório aponta um pouco em todas as direções, então, em particular,
ele aponta pelo menos um pouco na mesma direção do vetor próprio de
:math:`\mathbf{A}` associado ao maior autovalor. Isso é tão importante
que se chama o *autovalor principal* e o *autovetor principal*. Depois
de aplicar :math:`\mathbf{A}`, nosso vetor aleatório é esticado em todas
as direções possíveis, como está associado a cada autovetor possível,
mas é esticado principalmente na direção associado a este autovetor
principal. O que isso significa é que depois de aplicar em :math:`A`,
nosso vetor aleatório é mais longo e aponta em uma direção mais perto de
estar alinhado com o autovetor principal. Depois de aplicar a matriz
várias vezes, o alinhamento com o autovetor principal torna-se cada vez
mais próximo até que, para todos os efeitos práticos, nosso vetor
aleatório foi transformado no autovetor principal! Na verdade, este
algoritmo é a base para o que é conhecido como *iteração de energia*
para encontrar o maior autovalor e autovetor de uma matriz. Para obter
detalhes, consulte, por exemplo :cite:`Van-Loan.Golub.1983`.
Corrigindo a Normalização
~~~~~~~~~~~~~~~~~~~~~~~~~
Agora, das discussões acima, concluímos que não queremos que um vetor
aleatório seja esticado ou esmagado, gostaríamos que os vetores
aleatórios permanecessem do mesmo tamanho durante todo o processo. Para
fazer isso, agora redimensionamos nossa matriz por este autovalor
principal de modo que o maior autovalor é agora apenas um. Vamos ver o
que acontece neste caso.
.. raw:: html
.. raw:: html
.. code:: python
# Rescale the matrix `A`
A /= norm_eigs[-1]
# Do the same experiment again
v_in = np.random.randn(k, 1)
norm_list = [np.linalg.norm(v_in)]
for i in range(1, 100):
v_in = A.dot(v_in)
norm_list.append(np.linalg.norm(v_in))
d2l.plot(np.arange(0, 100), norm_list, 'Iteration', 'Value')
.. figure:: output_eigendecomposition_ee2e00_75_0.svg
.. raw:: html
.. raw:: html
.. code:: python
# Rescale the matrix `A`
A /= norm_eigs[-1]
# Do the same experiment again
v_in = torch.randn(k, 1, dtype=torch.float64)
norm_list = [torch.norm(v_in).item()]
for i in range(1, 100):
v_in = A @ v_in
norm_list.append(torch.norm(v_in).item())
d2l.plot(torch.arange(0, 100), norm_list, 'Iteration', 'Value')
.. figure:: output_eigendecomposition_ee2e00_78_0.svg
.. raw:: html
.. raw:: html
.. code:: python
# Rescale the matrix `A`
A /= norm_eigs[-1]
# Do the same experiment again
v_in = tf.random.normal((k, 1), dtype=tf.float64)
norm_list = [tf.norm(v_in).numpy()]
for i in range(1, 100):
v_in = tf.matmul(A, v_in)
norm_list.append(tf.norm(v_in).numpy())
d2l.plot(tf.range(0, 100), norm_list, 'Iteration', 'Value')
.. figure:: output_eigendecomposition_ee2e00_81_0.svg
.. raw:: html
.. raw:: html
Também podemos traçar a proporção entre as normas consecutivas como
antes e ver que de fato ela se estabiliza.
.. raw:: html
.. raw:: html
.. code:: python
# Also plot the ratio
norm_ratio_list = []
for i in range(1, 100):
norm_ratio_list.append(norm_list[i]/norm_list[i-1])
d2l.plot(np.arange(1, 100), norm_ratio_list, 'Iteration', 'Ratio')
.. figure:: output_eigendecomposition_ee2e00_87_0.svg
.. raw:: html
.. raw:: html
.. code:: python
# Also plot the ratio
norm_ratio_list = []
for i in range(1, 100):
norm_ratio_list.append(norm_list[i]/norm_list[i-1])
d2l.plot(torch.arange(1, 100), norm_ratio_list, 'Iteration', 'Ratio')
.. figure:: output_eigendecomposition_ee2e00_90_0.svg
.. raw:: html
.. raw:: html
.. code:: python
# Also plot the ratio
norm_ratio_list = []
for i in range(1, 100):
norm_ratio_list.append(norm_list[i]/norm_list[i-1])
d2l.plot(tf.range(1, 100), norm_ratio_list, 'Iteration', 'Ratio')
.. figure:: output_eigendecomposition_ee2e00_93_0.svg
.. raw:: html
.. raw:: html
Conclusões
----------
Agora vemos exatamente o que esperávamos! Depois de normalizar as
matrizes pelo autovalor principal, vemos que os dados aleatórios não
explodem como antes, mas, em vez disso, eventualmente se equilibram com
um valor específico. Seria bom ser capaz de fazer essas coisas desde os
primeiros princípios, e acontece que se olharmos profundamente para a
matemática disso, podemos ver que o maior autovalor de uma grande matriz
aleatória com média independente de zero, variância de uma entrada
gaussiana é em média cerca de :math:`\sqrt{n}`, ou no nosso caso
:math:`\sqrt{5} \approx 2.2`, devido a um fato fascinante conhecido como
a *lei circular* :cite:`Ginibre.1965`. A relação entre os valores
próprios (e um objeto relacionado chamado valores singulares) de
matrizes aleatórias demonstrou ter conexões profundas para a
inicialização adequada de redes neurais, como foi discutido em
:cite:`Pennington.Schoenholz.Ganguli.2017` e trabalhos subsequentes.
Resumo
------
- Autovetores são vetores que são alongados por uma matriz sem mudar de
direção.
- Os autovalores são a quantidade em que os autovetores são alongados
pela aplicação da matriz.
- A autodecomposição em autovalores e autovetores de uma matriz pode
permitir que muitas operações sejam reduzidas a operações nos
autovalores.
- O Teorema do Círculo de Gershgorin pode fornecer valores aproximados
para os autovalores de uma matriz.
- O comportamento das potências da matriz iterada depende
principalmente do tamanho do maior autovalor. Esse entendimento tem
muitas aplicações na teoria de inicialização de redes neurais.
Exercícios
----------
1. Quais são os autovalores e autovetores de
.. math::
\mathbf{A} = \begin{bmatrix}
2 & 1 \\
1 & 2
\end{bmatrix}?
2. Quais são os autovalores e autovetores da matriz a seguir, e o que há
de estranho neste exemplo em comparação com o anterior?
.. math::
\mathbf{A} = \begin{bmatrix}
2 & 1 \\
0 & 2
\end{bmatrix}.
3. Sem calcular os autovalores, é possível que o menor autovalor da
matriz a seguir seja menor que :math:`0,5`? *Nota*: este problema
pode ser feito na sua cabeça.
.. math::
\mathbf{A} = \begin{bmatrix}
3.0 & 0.1 & 0.3 & 1.0 \\
0.1 & 1.0 & 0.1 & 0.2 \\
0.3 & 0.1 & 5.0 & 0.0 \\
1.0 & 0.2 & 0.0 & 1.8
\end{bmatrix}.
.. raw:: html
.. raw:: html
`Discussões `__
.. raw:: html
.. raw:: html
`Discussões `__
.. raw:: html
.. raw:: html
`Discussões `__
.. raw:: html
.. raw:: html
.. raw:: html