0% acharam este documento útil (0 voto)
99 visualizações1.016 páginas

Dive Into Deep Learning-Pytorch

O documento apresenta um livro sobre aprendizado profundo dividido em capítulos. O capítulo 1 introduz os conceitos-chave de aprendizado profundo, incluindo exemplos, componentes, tipos de problemas, história e aplicações de sucesso. Os capítulos 2 cobrem tópicos preliminares como manipulação de dados, pré-processamento, álgebra linear, cálculo, probabilidade e documentação de bibliotecas de aprendizado de máquina.
Direitos autorais
© © All Rights Reserved
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato PDF, TXT ou leia on-line no Scribd
0% acharam este documento útil (0 voto)
99 visualizações1.016 páginas

Dive Into Deep Learning-Pytorch

O documento apresenta um livro sobre aprendizado profundo dividido em capítulos. O capítulo 1 introduz os conceitos-chave de aprendizado profundo, incluindo exemplos, componentes, tipos de problemas, história e aplicações de sucesso. Os capítulos 2 cobrem tópicos preliminares como manipulação de dados, pré-processamento, álgebra linear, cálculo, probabilidade e documentação de bibliotecas de aprendizado de máquina.
Direitos autorais
© © All Rights Reserved
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato PDF, TXT ou leia on-line no Scribd
Você está na página 1/ 1016

Dive into Deep Learning

Release 0.17.1

Aston Zhang, Zachary C. Lipton, Mu Li, and Alexander J. Smola

Dec 12, 2021


Contents

Prefácio 1

Instalação 9

Notação 13

1 Introdução 17
1.1 Um exemplo motivador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
1.2 Componentes chave . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
1.3 Tipos de Problemas de Machine Learning . . . . . . . . . . . . . . . . . . . . . . . 23
1.4 Raízes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
1.5 O Caminho Para o Deep Learning . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
1.6 Histórias de Sucesso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
1.7 Características . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
1.8 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
1.9 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43

2 Preliminares 45
2.1 Manipulação de Dados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
2.1.1 Iniciando . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
2.1.2 Operações . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
2.1.3 Mecanismo de Broadcasting . . . . . . . . . . . . . . . . . . . . . . . . . . 50
2.1.4 Indexação e Fatiamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
2.1.5 Economizando memória . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
2.1.6 Conversão para outros objetos Python . . . . . . . . . . . . . . . . . . . . 53
2.1.7 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
2.1.8 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
2.2 Pré-processamento de Dados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
2.2.1 Lendo o Dataset . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
2.2.2 Lidando com Dados Faltantes . . . . . . . . . . . . . . . . . . . . . . . . . 54
2.2.3 Convertendo para o Formato Tensor . . . . . . . . . . . . . . . . . . . . . 55
2.2.4 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
2.2.5 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
2.3 Álgebra Linear . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
2.3.1 Escalares . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
2.3.2 Vetores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
2.3.3 Matrizes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
2.3.4 Tensores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
2.3.5 Propriedades Básicas de Aritmética de Tensores . . . . . . . . . . . . . . 61
2.3.6 Redução . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
2.3.7 Produto Escalar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64

i
2.3.8 Produtos Matriz-Vetor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
2.3.9 Multiplicação Matriz Matriz . . . . . . . . . . . . . . . . . . . . . . . . . . 65
2.3.10 Normas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
2.3.11 Mais sobre Algebra Linear . . . . . . . . . . . . . . . . . . . . . . . . . . 68
2.3.12 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
2.3.13 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
2.4 Cálculo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
2.4.1 Derivadas e Diferenciação . . . . . . . . . . . . . . . . . . . . . . . . . . 70
2.4.2 Derivadas Parciais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
2.4.3 Gradientes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
2.4.4 Regra da Cadeia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
2.4.5 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
2.4.6 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
2.5 Diferenciação automática . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
2.5.1 Um exemplo simples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
2.5.2 Retroceder para variáveis não escalares . . . . . . . . . . . . . . . . . . . 77
2.5.3 Computação Detaching . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
2.5.4 Computando o Gradiente do Python Control Flow . . . . . . . . . . . . . . 78
2.5.5 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
2.5.6 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
2.6 Probabilidade . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
2.6.1 Teoria Básica de Probabilidade . . . . . . . . . . . . . . . . . . . . . . . . 81
2.6.2 Lidando com Múltiplas Variáveis Aleatórias . . . . . . . . . . . . . . . . . 84
2.6.3 Expectativa e Variância . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
2.6.4 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
2.6.5 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
2.7 Documentação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
2.7.1 Encontrando Todas as Funções e Classes em um Módulo . . . . . . . . . . 88
2.7.2 Buscando o Uso de Funções e Classes Específicas . . . . . . . . . . . . . . 89
2.7.3 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
2.7.4 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90

3 Linear Neural NetworkRedes Neurais Lineares 91


3.1 Linear Regression . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
3.1.1 Elementos Básicos de Regressão Linear . . . . . . . . . . . . . . . . . . . 91
3.1.2 Vetorização para Velocidade . . . . . . . . . . . . . . . . . . . . . . . . . 96
3.1.3 A Distribuição Normal e Perda Quadrada . . . . . . . . . . . . . . . . . . 97
3.1.4 Da Regressão Linear às Redes Profundas . . . . . . . . . . . . . . . . . . 99
3.2 Linear Regression Implementation from Scratch . . . . . . . . . . . . . . . . . . 102
3.2.1 Gerando o Dataset . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
3.2.2 Lendo o Dataset . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
3.2.3 Initializing Model Parameters . . . . . . . . . . . . . . . . . . . . . . . . 105
3.2.4 Definindo o Modelo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
3.2.5 Definindo a Função de Perda . . . . . . . . . . . . . . . . . . . . . . . . . 105
3.2.6 Definindo o Algoritmo de Otimização . . . . . . . . . . . . . . . . . . . . 106
3.2.7 Treinamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
3.2.8 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
3.2.9 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
3.3 Implementação Concisa de Regressão Linear . . . . . . . . . . . . . . . . . . . . 108
3.3.1 Gerando the Dataset . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
3.3.2 Lendo o Dataset . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109

ii
3.3.3 Definindo o Modelo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
3.3.4 Inicializando os Parâmetros do Modelo . . . . . . . . . . . . . . . . . . . 110
3.3.5 Definindo a Função de Perda . . . . . . . . . . . . . . . . . . . . . . . . . 111
3.3.6 Definindo o Algoritmo de Otimização . . . . . . . . . . . . . . . . . . . . 111
3.3.7 Treinamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
3.3.8 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
3.3.9 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
3.4 Regressão Softmax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
3.4.1 Problema de Classificação . . . . . . . . . . . . . . . . . . . . . . . . . . 113
3.4.2 Arquitetura de Rede . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
3.4.3 Custo de Parametrização de Camadas Totalmente Conectadas . . . . . . . 114
3.4.4 Operação do Softmax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
3.4.5 Vetorização para Minibatches . . . . . . . . . . . . . . . . . . . . . . . . . 116
3.4.6 Função de Perda . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
3.4.7 Fundamentos da Teoria da Informação . . . . . . . . . . . . . . . . . . . 118
3.4.8 Predição do Modelo e Avaliação . . . . . . . . . . . . . . . . . . . . . . . 119
3.4.9 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
3.4.10 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
3.5 O Dataset de Classificação de Imagens . . . . . . . . . . . . . . . . . . . . . . . . 120
3.5.1 Lendo o Dataset . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
3.5.2 Lendo um Minibatch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
3.5.3 Juntando Tudo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
3.5.4 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
3.5.5 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
3.6 Implementação da Regressão Softmax do Zero . . . . . . . . . . . . . . . . . . . . 123
3.6.1 Inicializando os Parâmetros do Modelo . . . . . . . . . . . . . . . . . . . 124
3.6.2 Definindo a Operação do Softmax . . . . . . . . . . . . . . . . . . . . . . . 124
3.6.3 Definindo o Modelo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
3.6.4 Definindo a Função de Perda . . . . . . . . . . . . . . . . . . . . . . . . . 125
3.6.5 Exatidão da Classificação . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
3.6.6 Treinamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
3.6.7 Predição . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
3.6.8 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
3.6.9 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
3.7 Implementação Concisa da Regressão Softmax . . . . . . . . . . . . . . . . . . . . 131
3.7.1 Inicializando os Parâmetros do Modelo . . . . . . . . . . . . . . . . . . . 132
3.7.2 Implementação do Softmax Revisitada . . . . . . . . . . . . . . . . . . . . 132
3.7.3 Otimização do Algoritmo . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
3.7.4 Trainamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
3.7.5 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
3.7.6 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134

4 Perceptrons Multicamada 135


4.1 Perceptrons Multicamada . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
4.1.1 Camadas Ocultas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
4.1.2 Funções de Ativação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
4.1.3 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
4.1.4 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
4.2 Implementação de Perceptrons Multicamadas do Zero . . . . . . . . . . . . . . . 144
4.2.1 Inicializando os Parâmetros do Modelo . . . . . . . . . . . . . . . . . . . 144
4.2.2 Função de Ativação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144

iii
4.2.3 Modelo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
4.2.4 Função de Perda . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
4.2.5 Trainamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
4.2.6 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146
4.2.7 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146
4.3 Implementação Concisa de Perceptrons Multicamadas . . . . . . . . . . . . . . . . 147
4.3.1 Modelo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147
4.3.2 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
4.3.3 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
4.4 Seleção do Modelo, Underfitting, e Overfitting . . . . . . . . . . . . . . . . . . . . . 148
4.4.1 Erro de Treinamento e Erro de Generalização . . . . . . . . . . . . . . . . 149
4.4.2 Seleção do Modelo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152
4.4.3 Underfitting ou Overfitting? . . . . . . . . . . . . . . . . . . . . . . . . . . 153
4.4.4 Regressão Polinomial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154
4.4.5 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158
4.4.6 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159
4.5 Weight Decay . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159
4.5.1 Normas e Weight Decay . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
4.5.2 Regressão Linear de Alta Dimensão . . . . . . . . . . . . . . . . . . . . . 161
4.5.3 Implementação do Zero . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162
4.5.4 Implementação Concisa . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164
4.5.5 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166
4.5.6 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166
4.6 Dropout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166
4.6.1 Overfitting Revisitado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
4.6.2 Robustez por Meio de Perturbações . . . . . . . . . . . . . . . . . . . . . 167
4.6.3 Dropout na Prática . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168
4.6.4 Implementação do Zero . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169
4.6.5 Implementação Concisa . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171
4.6.6 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172
4.6.7 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173
4.7 Propagação Direta, Propagação Reversa e Gráficos Computacionais . . . . . . . . 173
4.7.1 Propagação Direta . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174
4.7.2 Gráfico Computatcional de Propagação Direta . . . . . . . . . . . . . . . . 174
4.7.3 Propagação Reversa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175
4.7.4 Treinando Redes Neurais . . . . . . . . . . . . . . . . . . . . . . . . . . . 176
4.7.5 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177
4.7.6 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177
4.8 Estabilidade Numérica e Inicialização . . . . . . . . . . . . . . . . . . . . . . . . 177
4.8.1 Explosão e Desaparecimento de Gradientes . . . . . . . . . . . . . . . . . 178
4.8.2 Inicialização de Parâmetros . . . . . . . . . . . . . . . . . . . . . . . . . . 180
4.8.3 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182
4.8.4 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182
4.9 Mudança de Ambiente e Distribuição . . . . . . . . . . . . . . . . . . . . . . . . . 183
4.9.1 Tipos de Turno de Distribuição . . . . . . . . . . . . . . . . . . . . . . . . 183
4.9.2 Exemplos de Mudança de Distribuição . . . . . . . . . . . . . . . . . . . . 186
4.9.3 Correção de Mudança de Distribuição . . . . . . . . . . . . . . . . . . . . 187
4.9.4 Uma taxonomia de Problemas de Aprendizagem . . . . . . . . . . . . . . 191
4.9.5 Justiça, Responsabilidade e Transparência no Machine Learning . . . . . . 192
4.9.6 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193
4.9.7 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194

iv
4.10 Previsão de Preços de Imóveis no Kaggle . . . . . . . . . . . . . . . . . . . . . . . 194
4.10.1 Download e Cache de datasets . . . . . . . . . . . . . . . . . . . . . . . . . 194
4.10.2 Kaggle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196
4.10.3 Acessando e Lendo o Conjunto de Dados . . . . . . . . . . . . . . . . . . . 197
4.10.4 Pré-processamento de Dados . . . . . . . . . . . . . . . . . . . . . . . . . 198
4.10.5 Treinamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199
4.10.6 Validação Cruzada K-Fold . . . . . . . . . . . . . . . . . . . . . . . . . . 200
4.10.7 Seleção de Modelo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201
4.10.8 Enviando Previsões no Kaggle . . . . . . . . . . . . . . . . . . . . . . . . 202
4.10.9 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204
4.10.10 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204

5 Deep Learning Computacional 207


5.1 Camadas e Blocos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207
5.1.1 Um Bloco Personalizado . . . . . . . . . . . . . . . . . . . . . . . . . . . 209
5.1.2 O Bloco Sequencial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211
5.1.3 Execução de Código na Função de Propagação Direta . . . . . . . . . . . . 212
5.1.4 Eficiência . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213
5.1.5 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213
5.1.6 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214
5.2 Gerenciamento de Parâmetros . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214
5.2.1 Acesso a Parâmetros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215
5.2.2 Inicialização de Parâmetros . . . . . . . . . . . . . . . . . . . . . . . . . . 217
5.2.3 Parâmetros Tied . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219
5.2.4 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220
5.2.5 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220
5.3 Camadas Personalizadas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220
5.3.1 Camadas Sem Parâmetros . . . . . . . . . . . . . . . . . . . . . . . . . . . 221
5.3.2 Camadas com Parâmetros . . . . . . . . . . . . . . . . . . . . . . . . . . . 221
5.3.3 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223
5.3.4 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223
5.4 Entrada e Saída de Arquivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223
5.4.1 Carregando e Salvando Tensores . . . . . . . . . . . . . . . . . . . . . . . 223
5.4.2 Carregando e Salvando Parâmetros de Modelos . . . . . . . . . . . . . . . 224
5.4.3 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225
5.4.4 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225
5.5 GPUs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226
5.5.1 Dispositivos Computacionais . . . . . . . . . . . . . . . . . . . . . . . . . 227
5.5.2 Tensores e GPUs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228
5.5.3 Redes Neurais e GPUs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230
5.5.4 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231
5.5.5 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231

6 Convolutional Neural Networks 233


6.1 De Camadas Totalmente Conectadas às Convoluções . . . . . . . . . . . . . . . . 234
6.1.1 Invariância . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234
6.1.2 Restringindo o MLP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235
6.1.3 Convoluções . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237
6.1.4 “Onde está Wally” Revisitado . . . . . . . . . . . . . . . . . . . . . . . . . 237
6.1.5 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238
6.1.6 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239

v
6.2 Convolução para Imagens . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239
6.2.1 A Operação de Correlação Cruzada . . . . . . . . . . . . . . . . . . . . . . 239
6.2.2 Camadas Convolucionais . . . . . . . . . . . . . . . . . . . . . . . . . . . 241
6.2.3 Detecção de Borda de Objeto em Imagens . . . . . . . . . . . . . . . . . . 241
6.2.4 Aprendendo um Kernel . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242
6.2.5 Correlação Cruzada e Convolução . . . . . . . . . . . . . . . . . . . . . . 243
6.2.6 Mapa de Características e Campo Receptivo . . . . . . . . . . . . . . . . . 244
6.2.7 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244
6.2.8 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 245
6.3 Preenchimento e Saltos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 245
6.3.1 Preenchimento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 246
6.3.2 Saltos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 247
6.3.3 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249
6.4 Canais de Múltiplas Entradas e Saídas . . . . . . . . . . . . . . . . . . . . . . . . . 249
6.4.1 Canais de Entrada Múltiplos . . . . . . . . . . . . . . . . . . . . . . . . . 249
6.4.2 Canais de Saída Múltiplos . . . . . . . . . . . . . . . . . . . . . . . . . . . 251
6.4.3 Camada Convolucional 1 × 1 . . . . . . . . . . . . . . . . . . . . . . . . . 252
6.4.4 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253
6.4.5 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253
6.5 Pooling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254
6.5.1 Pooling Máximo e Pooling Médio . . . . . . . . . . . . . . . . . . . . . . . 254
6.5.2 Preenchimento e Passos . . . . . . . . . . . . . . . . . . . . . . . . . . . 256
6.5.3 Canais Múltiplos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257
6.5.4 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 258
6.5.5 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 258
6.6 Redes Neurais Convolucionais (LeNet) . . . . . . . . . . . . . . . . . . . . . . . . 259
6.6.1 LeNet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 259
6.6.2 Trainamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262
6.6.3 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 264
6.6.4 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 264

7 Modern Convolutional Neural Networks 265


7.1 Redes Neurais Convolucionais Profundas (AlexNet) . . . . . . . . . . . . . . . . . 265
7.1.1 Representaçao do Aprendizado . . . . . . . . . . . . . . . . . . . . . . . . 266
7.1.2 AlexNet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 269
7.1.3 Lendo o Dataset . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272
7.1.4 Treinamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272
7.1.5 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273
7.1.6 Exercício . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273
7.2 Redes Usando Blocos (VGG) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 274
7.2.1 VGG Blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 274
7.2.2 Camadas VGG . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275
7.2.3 Treinamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 276
7.2.4 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 277
7.2.5 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 277
7.3 Network in Network (NiN) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 278
7.3.1 Blocos NiN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 278
7.3.2 Modelo NiN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 280
7.3.3 Treinamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281
7.3.4 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281
7.3.5 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282

vi
7.4 Redes com Concatenações Paralelas (GoogLeNet) . . . . . . . . . . . . . . . . . . 282
7.4.1 Inception Blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282
7.4.2 Modelo GoogLeNet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 284
7.4.3 Treinamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 286
7.4.4 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 286
7.4.5 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 287
7.5 Normalização de Lotes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 287
7.5.1 Treinando Redes Profundas . . . . . . . . . . . . . . . . . . . . . . . . . . 287
7.5.2 Camadas de Normalização de Lotes . . . . . . . . . . . . . . . . . . . . . 289
7.5.3 Implementação do Zero . . . . . . . . . . . . . . . . . . . . . . . . . . . . 290
7.5.4 Aplicando Normalização de Lotes em LeNet . . . . . . . . . . . . . . . . . 292
7.5.5 Implementação Concisa . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293
7.5.6 Controvérsia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 294
7.5.7 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 294
7.5.8 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 295
7.6 Redes Residuais (ResNet) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 295
7.6.1 Classes Função . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 295
7.6.2 Blocos Residuais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 297
7.6.3 Modelo ResNet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 299
7.6.4 Treinamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302
7.6.5 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302
7.6.6 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 303
7.7 Redes Densamente Conectadas (DenseNet) . . . . . . . . . . . . . . . . . . . . . . 303
7.7.1 De ResNet para DenseNet . . . . . . . . . . . . . . . . . . . . . . . . . . . 303
7.7.2 Blocos Densos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 304
7.7.3 Camadas de Transição . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 305
7.7.4 Modelo DenseNet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 306
7.7.5 Treinamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307
7.7.6 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307
7.7.7 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307

8 Redes Neurais Recorrentes 309


8.1 Modelos Sequenciais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310
8.1.1 Ferramentas Estatísticas . . . . . . . . . . . . . . . . . . . . . . . . . . . 311
8.1.2 Trainamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313
8.1.3 Predição . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 315
8.1.4 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 317
8.1.5 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 318
8.2 Preprocessamento de Texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 318
8.2.1 Lendo o Dataset . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 319
8.2.2 Tokenização . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 319
8.2.3 Vocabulário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 320
8.2.4 Juntando Todas as Coisas . . . . . . . . . . . . . . . . . . . . . . . . . . . 321
8.2.5 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 322
8.2.6 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 322
8.3 Modelos de Linguagem e o Dataset . . . . . . . . . . . . . . . . . . . . . . . . . . 322
8.3.1 Aprendendo um Modelo de Linguagem . . . . . . . . . . . . . . . . . . . 323
8.3.2 Modelos de Markov e n-gramas . . . . . . . . . . . . . . . . . . . . . . . . 324
8.3.3 Estatísticas de Linguagem Natural . . . . . . . . . . . . . . . . . . . . . . 325
8.3.4 Leitura de Dados de Longa Sequência . . . . . . . . . . . . . . . . . . . . 327
8.3.5 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 330

vii
8.3.6 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 331
8.4 Redes Neurais Recorrentes (RNNs) . . . . . . . . . . . . . . . . . . . . . . . . . . 331
8.4.1 Redes Neurais sem Estados Ocultos . . . . . . . . . . . . . . . . . . . . . 332
8.4.2 Redes Neurais Recorrentes com Estados Ocultos . . . . . . . . . . . . . . 332
8.4.3 Modelos de Linguagem em Nível de Caracteres Baseados em RNN . . . . . 334
8.4.4 Perplexidade . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 335
8.4.5 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336
8.4.6 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336
8.5 Implementação de Redes Neurais Recorrentes do Zero . . . . . . . . . . . . . . . 337
8.5.1 Codificação One-Hot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 337
8.5.2 Inicializando os Parâmetros do Modelo . . . . . . . . . . . . . . . . . . . 338
8.5.3 Modelo RNN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 338
8.5.4 Predição . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 339
8.5.5 Recorte de Gradiente . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 340
8.5.6 Treinamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 341
8.5.7 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 344
8.5.8 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 344
8.6 Implementação Concisa de Redes Neurais Recorrentes . . . . . . . . . . . . . . . 345
8.6.1 Definindo o Modelo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 345
8.6.2 Treinamento e Previsão . . . . . . . . . . . . . . . . . . . . . . . . . . . . 347
8.6.3 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 348
8.6.4 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 348
8.7 Retropropagação ao Longo do Tempo . . . . . . . . . . . . . . . . . . . . . . . . . 348
8.7.1 Análise de Gradientes em RNNs . . . . . . . . . . . . . . . . . . . . . . . 349
8.7.2 Retropropagação ao Longo do Tempo em Detalhes . . . . . . . . . . . . . 351
8.7.3 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 354
8.7.4 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 354

9 Redes Neurais Recorrentes Modernas 355


9.1 Gated Recurrent Units (GRU) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 355
9.1.1 Estado Oculto Fechado . . . . . . . . . . . . . . . . . . . . . . . . . . . . 356
9.1.2 Implementação do zero . . . . . . . . . . . . . . . . . . . . . . . . . . . . 359
9.1.3 Implementação concisa . . . . . . . . . . . . . . . . . . . . . . . . . . . . 361
9.1.4 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 362
9.1.5 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 362
9.2 Memória Longa de Curto Prazo (LSTM) . . . . . . . . . . . . . . . . . . . . . . . . 363
9.2.1 Célula de Memória Bloqueada . . . . . . . . . . . . . . . . . . . . . . . . 363
9.2.2 Implementação do zero . . . . . . . . . . . . . . . . . . . . . . . . . . . . 366
9.2.3 Implementação concisa . . . . . . . . . . . . . . . . . . . . . . . . . . . . 368
9.2.4 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 369
9.2.5 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 369
9.3 Redes neurais recorrentes profundas . . . . . . . . . . . . . . . . . . . . . . . . . 370
9.3.1 Dependência Funcional . . . . . . . . . . . . . . . . . . . . . . . . . . . . 370
9.3.2 Implementação Concisa . . . . . . . . . . . . . . . . . . . . . . . . . . . . 371
9.3.3 Treinamento e Predição . . . . . . . . . . . . . . . . . . . . . . . . . . . . 372
9.3.4 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 372
9.3.5 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 372
9.4 Redes Neurais Recorrentes Bidirecionais . . . . . . . . . . . . . . . . . . . . . . . 373
9.4.1 Programação dinâmica em modelos de Markov ocultos . . . . . . . . . . . 373
9.4.2 Modelo Bidirecional . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 376
9.4.3 Treinar um RNN bidirecional para uma aplicação errada . . . . . . . . . . 377

viii
9.4.4 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 378
9.4.5 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 379
9.5 Tradução Automática e o Conjunto de Dados . . . . . . . . . . . . . . . . . . . . . 379
9.5.1 Download e Pré-processamento do Conjunto de Dados . . . . . . . . . . . 380
9.5.2 Tokenização . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 381
9.5.3 Vocabulário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 382
9.5.4 Carregando o Conjunto de Dados . . . . . . . . . . . . . . . . . . . . . . . 382
9.5.5 Juntando todas as coisas . . . . . . . . . . . . . . . . . . . . . . . . . . . 383
9.5.6 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 384
9.5.7 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 384
9.6 Arquitetura Encoder-Decoder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 385
9.6.1 Encoder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 385
9.6.2 Decoder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 386
9.6.3 Somando o Encoder e o Decoder . . . . . . . . . . . . . . . . . . . . . . . 386
9.6.4 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 387
9.6.5 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 387
9.7 Aprendizado Sequência a Sequência . . . . . . . . . . . . . . . . . . . . . . . . . 387
9.7.1 Encoder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 388
9.7.2 Decoder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 390
9.7.3 Função de Perdas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 392
9.7.4 Treinamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 393
9.7.5 Predição . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 395
9.7.6 Avaliação de Sequências Preditas . . . . . . . . . . . . . . . . . . . . . . . 396
9.7.7 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 397
9.7.8 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 397
9.8 Pesquisa de feixe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 398
9.8.1 Busca Gulosa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 398
9.8.2 Busca Exaustiva . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 399
9.8.3 Busca de Feixe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 400
9.8.4 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 401
9.8.5 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 401

10 Mecanismos de Atenção 403


10.1 Dicas para atenção . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 403
10.1.1 Dicas de Atenção em Biologia . . . . . . . . . . . . . . . . . . . . . . . . . 404
10.1.2 Consultas, Chaves e Valores . . . . . . . . . . . . . . . . . . . . . . . . . . 405
10.1.3 Visualização da Atenção . . . . . . . . . . . . . . . . . . . . . . . . . . . . 406
10.1.4 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 407
10.1.5 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 408
10.2 Pooling de Atenção: Regressão de Kernel de Nadaraya-Watson . . . . . . . . . . . 408
10.2.1 Gerando o Dataset . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 408
10.2.2 Pooling Médio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 409
10.2.3 Pooling de Atenção não-Paramétrico . . . . . . . . . . . . . . . . . . . . . 410
10.2.4 Pooling de Atenção Paramétrica . . . . . . . . . . . . . . . . . . . . . . . 412
10.2.5 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 415
10.2.6 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 415
10.3 Funções de Pontuação de Atenção . . . . . . . . . . . . . . . . . . . . . . . . . . 416
10.3.1 Operação Softmax Mascarada . . . . . . . . . . . . . . . . . . . . . . . . . 417
10.3.2 Atenção Aditiva . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 418
10.3.3 Atenção de Produto Escalar em Escala . . . . . . . . . . . . . . . . . . . . 419
10.3.4 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 421

ix
10.3.5 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 421
10.4 Atenção de Bahdanau . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 421
10.4.1 Modelo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 422
10.4.2 Definindo o Decodificador com Atenção . . . . . . . . . . . . . . . . . . . 422
10.4.3 Treinamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 424
10.4.4 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 426
10.4.5 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 426
10.5 Atenção Multi-Head . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 426
10.5.1 Modelo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 427
10.5.2 Implementação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 428
10.5.3 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 430
10.5.4 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 430
10.6 Autoatenção e Codificação Posicional . . . . . . . . . . . . . . . . . . . . . . . . . 430
10.6.1 Autoatenção . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 430
10.6.2 Comparando CNNs, RNNs e Autoatenção . . . . . . . . . . . . . . . . . . 431
10.6.3 Codificação Posicional . . . . . . . . . . . . . . . . . . . . . . . . . . . . 433
10.6.4 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 436
10.6.5 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 436
10.7 Transformador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 436
10.7.1 Modelo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 436
10.7.2 Redes Positionwise Feed-Forward . . . . . . . . . . . . . . . . . . . . . . . 438
10.7.3 Conexão residual e normalização de camada . . . . . . . . . . . . . . . . 439
10.7.4 Encoder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 440
10.7.5 Decoder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 441
10.7.6 Treinamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 444
10.7.7 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 447
10.7.8 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 447

11 Algoritmos de Otimização 449


11.1 Optimização e Deep Learning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 449
11.1.1 Objetivos da Optimização . . . . . . . . . . . . . . . . . . . . . . . . . . . 450
11.1.2 Desafios de otimização em Deep Learning . . . . . . . . . . . . . . . . . . 451
11.1.3 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 454
11.1.4 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 455
11.2 Convexidade . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 455
11.2.1 Definições . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 456
11.2.2 Propriedades . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 459
11.2.3 Restrições . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 461
11.2.4 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 463
11.2.5 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 463
11.3 Gradiente descendente . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 464
11.3.1 Gradiente descendente em uma dimensão . . . . . . . . . . . . . . . . . . 464
11.3.2 Gradiente descendente multivariado . . . . . . . . . . . . . . . . . . . . . 468
11.3.3 Métodos Adaptativos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 469
11.3.4 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 473
11.3.5 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 474
11.4 Gradiente Descendente Estocástico . . . . . . . . . . . . . . . . . . . . . . . . . . 474
11.4.1 Atualizações de gradiente estocástico . . . . . . . . . . . . . . . . . . . . 474
11.4.2 Taxa de aprendizagem dinâmica . . . . . . . . . . . . . . . . . . . . . . . 476
11.4.3 Análise de convergência para objetivos convexos . . . . . . . . . . . . . . 478
11.4.4 Gradientes estocásticos e amostras finitas . . . . . . . . . . . . . . . . . . 479

x
11.4.5 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 480
11.4.6 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 480
11.5 Gradiente Estocástico Descendente Minibatch . . . . . . . . . . . . . . . . . . . . 481
11.5.1 Vetorização e caches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 481
11.5.2 Minibatches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 483
11.5.3 Lendo o conjunto de dados . . . . . . . . . . . . . . . . . . . . . . . . . . 484
11.5.4 Implementação do zero . . . . . . . . . . . . . . . . . . . . . . . . . . . . 485
11.5.5 Implementação concisa . . . . . . . . . . . . . . . . . . . . . . . . . . . . 488
11.5.6 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 489
11.5.7 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 490
11.6 Momentum . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 490
11.6.1 Fundamentos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 490
11.6.2 Experimentos Práticos . . . . . . . . . . . . . . . . . . . . . . . . . . . . 495
11.6.3 Análise teórica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 498
11.6.4 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 500
11.6.5 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 500
11.7 Adagrad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 501
11.7.1 Recursos esparsos e taxas de aprendizado . . . . . . . . . . . . . . . . . . 501
11.7.2 Precondicionamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 502
11.7.3 O Algoritmo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 503
11.7.4 Implementação do zero . . . . . . . . . . . . . . . . . . . . . . . . . . . . 505
11.7.5 Implementação concisa . . . . . . . . . . . . . . . . . . . . . . . . . . . . 505
11.7.6 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 506
11.7.7 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 506
11.8 RMSProp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 507
11.8.1 O Algoritmo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 507
11.8.2 Implementação do zero . . . . . . . . . . . . . . . . . . . . . . . . . . . . 508
11.8.3 Implementação concisa . . . . . . . . . . . . . . . . . . . . . . . . . . . . 510
11.8.4 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 511
11.8.5 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 511
11.9 Adadelta . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 511
11.9.1 O Algoritmo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 511
11.9.2 Implementação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 512
11.9.3 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 513
11.9.4 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 514
11.10 Adam . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 514
11.10.1 O Algoritmo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 514
11.10.2 Implementação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 515
11.10.3 Yogi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 517
11.10.4 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 518
11.10.5 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 518
11.11 Programação da taxa de aprendizagem . . . . . . . . . . . . . . . . . . . . . . . . 519
11.11.1 Problema Amostra . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 519
11.11.2 Agendadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 522
11.11.3 Políticas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 523
11.11.4 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 528
11.11.5 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 529

12 Desempenho Computacional 531


12.1 Compiladores e Interpretadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . 531
12.1.1 Programação Simbólica . . . . . . . . . . . . . . . . . . . . . . . . . . . . 532

xi
12.1.2 Programação Híbrida . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 533
12.1.3 Híbrido-Sequencial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 534
12.2 Computação Assíncrona . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 536
12.2.1 Assincronismo via Back-end . . . . . . . . . . . . . . . . . . . . . . . . . . 536
12.2.2 Barreiras e Bloqueadores . . . . . . . . . . . . . . . . . . . . . . . . . . . 538
12.2.3 Melhorando a Computação . . . . . . . . . . . . . . . . . . . . . . . . . . 539
12.2.4 Melhorando o Footprint de Memória . . . . . . . . . . . . . . . . . . . . . 539
12.2.5 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 540
12.2.6 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 540
12.3 Paralelismo Automático . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 541
12.3.1 Computação Paralela em GPUs . . . . . . . . . . . . . . . . . . . . . . . . 541
12.3.2 Computação Paralela e Comunicação . . . . . . . . . . . . . . . . . . . . 542
12.3.3 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 544
12.3.4 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 545
12.4 Hardware . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 545
12.4.1 Computadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 546
12.4.2 Memória . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 547
12.4.3 Armazenamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 548
12.4.4 CPUs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 549
12.4.5 GPUs e outros Aceleradores . . . . . . . . . . . . . . . . . . . . . . . . . . 554
12.4.6 Redes e Barramentos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 556
12.4.7 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 557
12.4.8 Mais Números de Latência . . . . . . . . . . . . . . . . . . . . . . . . . . 557
12.4.9 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 558
12.5 Treinamento em Várias GPUs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 559
12.5.1 Dividindo o Problema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 560
12.5.2 Paralelismo de Dados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 561
12.5.3 Uma Rede Exemplo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 563
12.5.4 Sincronização de Dados . . . . . . . . . . . . . . . . . . . . . . . . . . . . 564
12.5.5 Distribuindo Dados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 565
12.5.6 Treinamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 566
12.5.7 Experimento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 567
12.5.8 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 568
12.5.9 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 568
12.6 Implementação Concisa para Várias GPUs . . . . . . . . . . . . . . . . . . . . . . 568
12.6.1 Uma Rede de Exemplo . . . . . . . . . . . . . . . . . . . . . . . . . . . . 569
12.6.2 Inicialização de Parâmetros e Logística . . . . . . . . . . . . . . . . . . . 569
12.6.3 Treinamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 570
12.6.4 Experimentos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 571
12.6.5 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 572
12.6.6 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 572
12.7 Servidores de Parâmetros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 572
12.7.1 Treinamento Paralelo de Dados . . . . . . . . . . . . . . . . . . . . . . . . 573
12.7.2 Sincronização em Anel . . . . . . . . . . . . . . . . . . . . . . . . . . . . 575
12.7.3 Treinamento Multi-Máquina . . . . . . . . . . . . . . . . . . . . . . . . . 578
12.7.4 Armazenamento de (key,value) . . . . . . . . . . . . . . . . . . . . . . . . 580
12.7.5 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 581
12.7.6 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 581

13 Visão Computacional 583


13.1 Aumento de Imagem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 583

xii
13.1.1 Método Comum de Aumento de Imagem . . . . . . . . . . . . . . . . . . 584
13.1.2 Usando um Modelo de Treinamento de Aumento de Imagem . . . . . . . 588
13.1.3 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 591
13.1.4 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 591
13.2 Ajustes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 591
13.2.1 Reconhecimento de Cachorro-quente . . . . . . . . . . . . . . . . . . . . 593
13.2.2 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 597
13.2.3 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 597
13.3 Detecção de Objetos e Caixas Delimitadoras . . . . . . . . . . . . . . . . . . . . . 598
13.3.1 Caixa Delimitadora . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 599
13.3.2 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 600
13.3.3 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 600
13.4 Caixas de Âncora . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 601
13.4.1 Gerando Várias Caixas de Âncora . . . . . . . . . . . . . . . . . . . . . . . 601
13.4.2 Interseção sobre União . . . . . . . . . . . . . . . . . . . . . . . . . . . . 604
13.4.3 Rotulagem de Treinamento para Definir Caixas de Âncora . . . . . . . . . 605
13.4.4 Caixas Delimitadoras para Previsão . . . . . . . . . . . . . . . . . . . . . 610
13.4.5 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 613
13.4.6 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 613
13.5 Detecção de Objetos Multiescala . . . . . . . . . . . . . . . . . . . . . . . . . . . 614
13.5.1 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 617
13.5.2 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 617
13.6 O Dataset de Detecção de Objetos . . . . . . . . . . . . . . . . . . . . . . . . . . . 617
13.6.1 Baixando Dataset . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 617
13.6.2 Lendo o Dataset . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 618
13.6.3 Demonstração . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 619
13.6.4 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 620
13.6.5 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 620
13.7 Detecção Single Shot Multibox (SSD) . . . . . . . . . . . . . . . . . . . . . . . . . . 620
13.7.1 Modelo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 620
13.7.2 Treinamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 626
13.7.3 Predição . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 628
13.7.4 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 629
13.7.5 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 630
13.8 Region-based CNNs (R-CNNs) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 632
13.8.1 R-CNNs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 632
13.8.2 Fast R-CNN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 633
13.8.3 R-CNN Mais Rápido . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 635
13.8.4 Máscara R-CNN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 636
13.8.5 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 637
13.8.6 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 637
13.9 Segmentação Semântica e o Dataset . . . . . . . . . . . . . . . . . . . . . . . . . . 637
13.9.1 Segmentação de Imagem e Segmentação detion and Instâancia . . . . . . 638
13.9.2 O Conjunto de Dados de Segmentação Semântica Pascal VOC2012 . . . . . 638
13.9.3 The Pascal VOC2012 Semantic Segmentation Dataset . . . . . . . . . . . . 638
13.9.4 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 644
13.9.5 Exercícioises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 644
13.10 Convolução Transposta . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 644
13.10.1 Convolução Transposta 2D Básica . . . . . . . . . . . . . . . . . . . . . . 645
13.10.2 Preenchimento, Passos e Canais . . . . . . . . . . . . . . . . . . . . . . . 646
13.10.3 Analogia à Transposição de Matriz . . . . . . . . . . . . . . . . . . . . . . 646

xiii
13.10.4 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 648
13.10.5 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 648
13.11 Redes Totalmente Convolucionais (Fully Convolutional Networks, FCN) . . . . . . . 648
13.11.1 Construindo um Modelo . . . . . . . . . . . . . . . . . . . . . . . . . . . 649
13.11.2 Inicializando a Camada de Convolução Transposta . . . . . . . . . . . . . 650
13.11.3 Lendo o Dataset . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 652
13.11.4 Treinamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 652
13.11.5 Predição . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 653
13.11.6 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 654
13.11.7 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 655
13.12 Transferência de Estilo Neural . . . . . . . . . . . . . . . . . . . . . . . . . . . . 655
13.12.1 Técnica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 656
13.12.2 Lendo o Conteúdo e as Imagens de Estilo . . . . . . . . . . . . . . . . . . 657
13.12.3 Pré-processamento e Pós-processamento . . . . . . . . . . . . . . . . . . 658
13.12.4 Extraindo Features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 659
13.12.5 Definindo a Função de Perda . . . . . . . . . . . . . . . . . . . . . . . . . 660
13.12.6 Criação e inicialização da imagem composta . . . . . . . . . . . . . . . . 662
13.12.7 Treinamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 662
13.12.8 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 665
13.12.9 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 665
13.13 Classificação de Imagens (CIFAR-10) no Kaggle . . . . . . . . . . . . . . . . . . . 665
13.13.1 Obtendo e Organizando o Dataset . . . . . . . . . . . . . . . . . . . . . . . 666
13.13.2 Aumento de Imagem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 669
13.13.3 Lendo o Dataset . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 670
13.13.4 Definindo o Modelo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 670
13.13.5 Definindo as Funções de Treinamento . . . . . . . . . . . . . . . . . . . . 671
13.13.6 Treinamento e Validação do Modelo . . . . . . . . . . . . . . . . . . . . . 671
13.13.7 Classificando o Conjunto de Testes e Enviando Resultados no Kaggle . . . 672
13.13.8 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 673
13.13.9 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 673
13.14 Identificação de Raça de Cachorro (ImageNet Dogs) no Kaggle . . . . . . . . . . . . 673
13.14.1 Obtenção e organização do Dataset . . . . . . . . . . . . . . . . . . . . . . 674
13.14.2 Aumento de Imagem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 676
13.14.3 Lendo o Dataset . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 676
13.14.4 Definindo o Modelo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 677
13.14.5 Definindo as Funções de Treinamento . . . . . . . . . . . . . . . . . . . . 678
13.14.6 Treinamento e Validação do Modelo . . . . . . . . . . . . . . . . . . . . . 679
13.14.7 Classificando o Conjunto de Testes e Enviando Resultados no Kaggle . . . 679
13.14.8 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 680
13.14.9 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 680

14 Processamento de linguagem natural: Pré-treinamento 681


14.1 Incorporação de Palavras (word2vec) . . . . . . . . . . . . . . . . . . . . . . . . . 682
14.1.1 Por que não usar vetores one-hot? . . . . . . . . . . . . . . . . . . . . . . 682
14.1.2 O Modelo Skip-Gram . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 683
14.1.3 O modelo do conjunto contínuo de palavras (CBOW) . . . . . . . . . . . . 685
14.1.4 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 686
14.1.5 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 686
14.2 Treinamento Aproximado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 687
14.2.1 Amostragem Negativa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 687
14.2.2 Hierárquico Softmax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 689

xiv
14.2.3 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 690
14.2.4 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 690
14.3 O conjunto de dados para incorporação de palavras com pré-treinamento . . . . . 690
14.3.1 Leitura e pré-processamento do conjunto de dados . . . . . . . . . . . . . 691
14.3.2 Subamostragem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 691
14.3.3 Carregando o conjunto de dados . . . . . . . . . . . . . . . . . . . . . . . 693
14.3.4 Juntando todas as coisas . . . . . . . . . . . . . . . . . . . . . . . . . . . 696
14.3.5 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 697
14.3.6 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 698
14.4 Pré-treinamento do word2vec . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 698
14.4.1 O Modelo Skip-Gram . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 698
14.4.2 Treinamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 700
14.4.3 Aplicando o modelo de incorporação de palavras . . . . . . . . . . . . . . 702
14.4.4 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 703
14.4.5 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 703
14.5 Incorporação de palavras com vetores globais (GloVe) . . . . . . . . . . . . . . . . 703
14.5.1 O modelo GloVe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 704
14.5.2 Compreendendo o GloVe a partir das razões de probabilidade condicionais 705
14.5.3 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 706
14.5.4 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 706
14.6 Encontrando sinônimos e analogias . . . . . . . . . . . . . . . . . . . . . . . . . 706
14.6.1 Usando vetores de palavras pré-treinados . . . . . . . . . . . . . . . . . . 707
14.6.2 Aplicação de vetores de palavras pré-treinados . . . . . . . . . . . . . . . 708
14.6.3 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 711
14.6.4 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 711
14.7 Representações de codificador bidirecional de transformadores (BERT) . . . . . . 711
14.7.1 De Independente do Contexto para Sensível ao Contexto . . . . . . . . . . 711
14.7.2 De Task-Specific para Task-Agnostic . . . . . . . . . . . . . . . . . . . . . 712
14.7.3 BERT: Combinando o melhor dos dois mundos . . . . . . . . . . . . . . . 712
14.7.4 Representação de entrada . . . . . . . . . . . . . . . . . . . . . . . . . . . 713
14.7.5 Tarefas de pré-treinamento . . . . . . . . . . . . . . . . . . . . . . . . . . 716
14.7.6 Juntando todas as coisas . . . . . . . . . . . . . . . . . . . . . . . . . . . 718
14.7.7 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 719
14.7.8 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 720
14.8 O conjunto de dados para pré-treinamento de BERT . . . . . . . . . . . . . . . . . 720
14.8.1 Definindo funções auxiliares para tarefas de pré-treinamento . . . . . . . 721
14.8.2 Transformando texto em conjunto de dados de pré-treinamento . . . . . . 723
14.8.3 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 725
14.8.4 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 726
14.9 Pré-treinando BERT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 726
14.9.1 Pré-treinamento de BERT . . . . . . . . . . . . . . . . . . . . . . . . . . . 726
14.9.2 Representando Texto com BERT . . . . . . . . . . . . . . . . . . . . . . . 729
14.9.3 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 730
14.9.4 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 730

15 Processamento de Linguagem Natural: Aplicações 731


15.1 Análise de Sentimentos e o Dataset . . . . . . . . . . . . . . . . . . . . . . . . . . 732
15.1.1 O Dataset de Análise de Sentimento . . . . . . . . . . . . . . . . . . . . . 732
15.1.2 Juntando Tudo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 735
15.1.3 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 735
15.1.4 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 735

xv
15.2 Análise de Sentimento: Usando Redes Neurais Recorrentes . . . . . . . . . . . . . 735
15.2.1 Usando um Modelo de Rede Neural Recorrente . . . . . . . . . . . . . . . 736
15.2.2 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 739
15.2.3 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 739
15.3 Análise de Sentimento: Usando Redes Neurais Convolucionais . . . . . . . . . . . 739
15.3.1 Camada Convolucional Unidimensional . . . . . . . . . . . . . . . . . . . 740
15.3.2 Camada de Pooling Máximo ao Longo do Tempo . . . . . . . . . . . . . . 742
15.3.3 O Modelo TextCNN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 743
15.3.4 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 746
15.3.5 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 746
15.4 Inferência de Linguagem Natural e o Dataset . . . . . . . . . . . . . . . . . . . . . 746
15.4.1 Inferência de Linguagem Natural . . . . . . . . . . . . . . . . . . . . . . 747
15.4.2 Conjunto de dados Stanford Natural Language Inference (SNLI) . . . . . . 747
15.4.3 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 751
15.4.4 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 751
15.5 Inferência de Linguagem Natural: Usando a Atenção . . . . . . . . . . . . . . . . 751
15.5.1 O Modelo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 752
15.5.2 Treinamento e Avaliação do Modelo . . . . . . . . . . . . . . . . . . . . . 756
15.5.3 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 757
15.5.4 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 758
15.6 Ajuste Fino de BERT para Aplicações de Nível de Sequência e de Token . . . . . . 758
15.6.1 Classificação de Texto Único . . . . . . . . . . . . . . . . . . . . . . . . . 759
15.6.2 Classificação ou Regressão de Pares de Texto . . . . . . . . . . . . . . . . 759
15.6.3 Marcação de Texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 760
15.6.4 Resposta a Perguntas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 761
15.6.5 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 762
15.6.6 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 763
15.7 Inferência de Linguagem Natural: Ajuste Fino do BERT . . . . . . . . . . . . . . . 763
15.7.1 Carregando o BERT Pré-treinado . . . . . . . . . . . . . . . . . . . . . . . 764
15.7.2 O Conjunto de Dados para Ajuste Fino do BERT . . . . . . . . . . . . . . . 765
15.7.3 Ajuste Fino do BERT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 766
15.7.4 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 768
15.7.5 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 768

16 Sistemas de Recomendação 769


16.1 Visão geral dos sistemas de recomendação . . . . . . . . . . . . . . . . . . . . . . 769
16.1.1 Filtragem colaborativa . . . . . . . . . . . . . . . . . . . . . . . . . . . . 770
16.1.2 Feedback explícito e feedback implícito . . . . . . . . . . . . . . . . . . . 771
16.1.3 Tarefas de recomendação . . . . . . . . . . . . . . . . . . . . . . . . . . . 771
16.1.4 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 772
16.1.5 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 772

17 Redes Adversariais Generativas 773


17.1 Redes Adversariais Generativas . . . . . . . . . . . . . . . . . . . . . . . . . . . . 773
17.1.1 Gerando Alguns Dados “Reais” . . . . . . . . . . . . . . . . . . . . . . . . 775
17.1.2 Gerador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 776
17.1.3 Discriminador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 776
17.1.4 Treinamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 776
17.1.5 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 778
17.1.6 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 778
17.2 Redes Adversariais Gerativas Convolucionais Profundas . . . . . . . . . . . . . . . 779

xvi
17.2.1 O Dataset de Pokémon . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 779
17.2.2 O Gerador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 780
17.2.3 Discriminador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 782
17.2.4 Treinamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 784
17.2.5 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 785
17.2.6 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 786

18 Apêndice: Matemática para Deep Learning 787


18.1 Operações de Geometria e Álgebra Linear . . . . . . . . . . . . . . . . . . . . . . 788
18.1.1 Geometria Vetorial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 788
18.1.2 Produto Escalar e Ângulos . . . . . . . . . . . . . . . . . . . . . . . . . . 790
18.1.3 Hiperplanos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 792
18.1.4 Geometria de Transformações Lineares . . . . . . . . . . . . . . . . . . . 795
18.1.5 Dependência Linear . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 797
18.1.6 Classificação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 798
18.1.7 Invertibilidade . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 798
18.1.8 Determinante . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 800
18.1.9 Tensores e Operações de Álgebra Linear Comum . . . . . . . . . . . . . . 801
18.1.10 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 803
18.1.11 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 804
18.2 Autovalores e Autovetores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 804
18.2.1 Encontrando Autovalores . . . . . . . . . . . . . . . . . . . . . . . . . . . 805
18.2.2 Matrizes de Decomposição . . . . . . . . . . . . . . . . . . . . . . . . . . 806
18.2.3 Operações em Autovalores e Autovetores . . . . . . . . . . . . . . . . . . 806
18.2.4 Composições Originais de Matrizes Simétricas . . . . . . . . . . . . . . . 807
18.2.5 Teorema do Círculo de Gershgorin . . . . . . . . . . . . . . . . . . . . . . 807
18.2.6 Uma Aplicação Útil: o Crescimento de Mapas Iterados . . . . . . . . . . . 808
18.2.7 Conclusões . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 813
18.2.8 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 813
18.2.9 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 813
18.3 Cálculo de Variável Única . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 814
18.3.1 Cálculo diferencial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 814
18.3.2 Regras de Cálculo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 818
18.3.3 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 825
18.3.4 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 825
18.4 Cálculo Multivariável . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 825
18.4.1 Diferenciação de Dimensões Superiores . . . . . . . . . . . . . . . . . . . 826
18.4.2 Geometria de Gradientes e Gradiente Descendente . . . . . . . . . . . . . 827
18.4.3 Uma Nota Sobre Otimização Matemática . . . . . . . . . . . . . . . . . . . 828
18.4.4 Regra da Cadeia Multivariada . . . . . . . . . . . . . . . . . . . . . . . . . 829
18.4.5 O Algoritmo de Retropropagação . . . . . . . . . . . . . . . . . . . . . . . 831
18.4.6 Hessians . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 834
18.4.7 Um Pouco de Cálculo Matricial . . . . . . . . . . . . . . . . . . . . . . . . 836
18.4.8 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 840
18.4.9 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 841
18.5 Cálculo Integral . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 841
18.5.1 Interpretação Geométrica . . . . . . . . . . . . . . . . . . . . . . . . . . . 841
18.5.2 O Teorema Fundamental do Cálculo . . . . . . . . . . . . . . . . . . . . . 844
18.5.3 Mudança de Variável . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 845
18.5.4 Um Comentário Sobre as Convenções de Sinais . . . . . . . . . . . . . . . 846
18.5.5 Integrais Múltiplas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 847

xvii
18.5.6 Mudança de Variáveis em Integrais Múltiplas . . . . . . . . . . . . . . . . 849
18.5.7 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 850
18.5.8 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 851
18.6 Variáveis Aleatórias . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 851
18.6.1 Variáveis Aleatórias Contínuas . . . . . . . . . . . . . . . . . . . . . . . . 851
18.6.2 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 868
18.6.3 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 868
18.7 Máxima verossimilhança . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 869
18.7.1 O Princípio da Máxima Verossimilhança . . . . . . . . . . . . . . . . . . . 869
18.7.2 Otimização Numérica e o Log-Probabilidade Negativa . . . . . . . . . . . 871
18.7.3 Máxima probabilidade para variáveis contínuas . . . . . . . . . . . . . . . 873
18.7.4 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 874
18.7.5 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 874
18.8 Distribuições . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 874
18.8.1 Bernoulli . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 875
18.8.2 Uniforme e Discreta . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 876
18.8.3 Uniforme e Contínua . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 878
18.8.4 Binomial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 880
18.8.5 Poisson . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 882
18.8.6 Gaussiana . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 885
18.8.7 Família Exponencial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 888
18.8.8 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 889
18.8.9 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 890
18.9 Naive Bayes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 890
18.9.1 Reconhecimento Ótico de Caracteres . . . . . . . . . . . . . . . . . . . . 890
18.9.2 O Modelo Probabilístico para Classificação . . . . . . . . . . . . . . . . . 892
18.9.3 O Classificador Naive Bayes . . . . . . . . . . . . . . . . . . . . . . . . . . 892
18.9.4 Trainamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 893
18.9.5 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 896
18.9.6 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 897
18.10 Estatísticas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 897
18.10.1 Avaliando e comparando estimadores . . . . . . . . . . . . . . . . . . . . 898
18.10.2 Conducting Hypothesis Tests . . . . . . . . . . . . . . . . . . . . . . . . . 902
18.10.3 Construindo Intervalos de Confiança . . . . . . . . . . . . . . . . . . . . . 905
18.10.4 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 908
18.10.5 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 908
18.11 Teoria da Informação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 909
18.11.1 Informação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 909
18.11.2 Entropia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 911
18.11.3 Informcação Mútua . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 913
18.11.4 Divergência de Kullback–Leibler . . . . . . . . . . . . . . . . . . . . . . . 917
18.11.5 Entropia Cruzada . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 919
18.11.6 Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 922
18.11.7 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 922

19 Apêndice: Ferramentas para Deep Learning 925


19.1 Usando Jupyter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 925
19.1.1 Editando e executando o código localmente . . . . . . . . . . . . . . . . . 925
19.1.2 Opções avançadas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 929
19.1.3 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 930
19.1.4 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 930

xviii
19.2 Usando Amazon SageMaker . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 931
19.2.1 Registro e login . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 931
19.2.2 Criação de uma instância do SageMaker . . . . . . . . . . . . . . . . . . . 931
19.2.3 Executando e parando uma instância . . . . . . . . . . . . . . . . . . . . 932
19.2.4 Atualizando Notebooks . . . . . . . . . . . . . . . . . . . . . . . . . . . . 933
19.2.5 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 934
19.2.6 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 934
19.3 Usando instâncias AWS EC2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 934
19.3.1 Criação e execução de uma instância EC2 . . . . . . . . . . . . . . . . . . 935
19.3.2 Instalando CUDA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 940
19.3.3 Instalação do MXNet e download dos notebooks D2L . . . . . . . . . . . . 941
19.3.4 Executando Jupyter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 942
19.3.5 Fechando instâncias não utilizadas . . . . . . . . . . . . . . . . . . . . . . 942
19.3.6 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 943
19.3.7 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 943
19.4 Usando Google Colab . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 943
19.4.1 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 944
19.4.2 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 944
19.5 Seleção de servidores e GPUs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 944
19.5.1 Selecionando Servidores . . . . . . . . . . . . . . . . . . . . . . . . . . . 945
19.5.2 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 948
19.6 Contribuindo para este livro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 949
19.6.1 Pequenas alterações de texto . . . . . . . . . . . . . . . . . . . . . . . . . 949
19.6.2 Propor uma mudança importante . . . . . . . . . . . . . . . . . . . . . . 950
19.6.3 Adicionando uma nova seção ou uma nova implementação de estrutura . 950
19.6.4 Enviando uma Mudança Principal . . . . . . . . . . . . . . . . . . . . . . 951
19.6.5 Sumário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 954
19.6.6 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 954
19.7 Documento da API d2l . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 954

Bibliography 979

Python Module Index 989

Index 991

xix
xx
Prefácio

Apenas alguns anos atrás, não havia legiões de cientistas de deep learning desenvolvendo produtos
e serviços inteligentes em grandes empresas e startups. Quando o mais jovem entre nós (os au-
tores) entrou no campo, o machine learning não comandava as manchetes dos jornais diários. Nos-
sos pais não faziam ideia do que era machine learning, muito menos por que podemos preferir isso
a uma carreira em medicina ou direito. Machine learning era uma disciplina acadêmica voltada
para o futuro com um conjunto restrito de aplicações do mundo real. E essas aplicações, por exem-
plo, reconhecimento de voz e visão computacional, exigiam tanto conhecimento de domínio que
muitas vezes eram considerados como áreas inteiramente separadas para as quais o aprendizado
de máquina era um pequeno componente. Redes neurais, então, os antecedentes dos modelos de
aprendizagem profunda nos quais nos concentramos neste livro, eram considerados ferramentas
obsoletas.
Apenas nos últimos cinco anos, o deep learning pegou o mundo de surpresa, impulsionando o
rápido progresso em campos tão diversos como a visão computacional, processamento de lin-
guagem natural, reconhecimento automático de fala, aprendizagem por reforço e modelagem
estatística. Com esses avanços em mãos, agora podemos construir carros que se dirigem sozin-
hos com mais autonomia do que nunca (e menos autonomia do que algumas empresas podem
fazer você acreditar), sistemas de resposta inteligente que redigem automaticamente os e-mails
mais comuns, ajudando as pessoas a se livrarem de caixas de entrada opressivamente grandes, e
agentes de software que dominam os melhores humanos do mundo em jogos de tabuleiro como Go,
um feito que se pensava estar a décadas de distância. Essas ferramentas já exercem impactos cada
vez maiores na indústria e na sociedade, mudando a forma como os filmes são feitos, as doenças
são diagnosticadas, e desempenhando um papel crescente nas ciências básicas — da astrofísica à
biologia.

Sobre Este Livro

Esse livro representa nossa tentativa de tornar o deep learning acessível, lhes ensinando os con-
ceitos, o contexto e o código.

1
Um Meio (?) Combinando Código, Matemática e HTML

Para que qualquer tecnologia de computação alcance seu impacto total, deve ser bem compreen-
dido, bem documentado e apoiado por ferramentas maduras e bem conservadas. As ideias-chave
devem ser claramente destiladas, minimizando o tempo de integração necessário para atualizar
os novos praticantes. Bibliotecas maduras devem automatizar tarefas comuns, e o código exem-
plar deve tornar mais fácil para os profissionais para modificar, aplicar e estender aplicativos
comuns para atender às suas necessidades. Considere os aplicativos da Web dinâmicos como ex-
emplo. Apesar de um grande número de empresas, como a Amazon, desenvolver aplicativos da
web baseados em banco de dados de sucesso na década de 1990, o potencial desta tecnologia para
auxiliar empreendedores criativos foi percebido em um grau muito maior nos últimos dez anos,
devido em parte ao desenvolvimento de frameworks poderosos e bem documentados.
Testar o potencial do deep learning apresenta desafios únicos porque qualquer aplicativo reúne
várias disciplinas. Aplicar o deep learning requer compreensão simultânea (i) as motivações para
definir um problema de uma maneira particular; (ii) a matemática de uma dada abordagem de
modelagem; (iii) os algoritmos de otimização para ajustar os modelos aos dados; e (iv) a engen-
haria necessária para treinar modelos de forma eficiente, navegando nas armadilhas da com-
putação numérica e obter o máximo do hardware disponível. Ensinar as habilidades de pensa-
mento crítico necessárias para formular problemas, a matemática para resolvê-los e as ferramen-
tas de software para implementar tais soluções em um só lugar apresentam desafios formidáveis.
Nosso objetivo neste livro é apresentar um recurso unificado para trazer os praticantes em poten-
cial.
Na época em que começamos o projeto deste livro, não havia recursos que simultaneamente (i)
estavam em dia; (ii) cobriam toda a largura de machine learning moderno com profundidade téc-
nica substancial; e (iii) intercalassem exposição da qualidade que se espera de um livro envol-
vente com o código limpo executável que se espera encontrar em tutoriais práticos. Encontramos
muitos exemplos de código para como usar um determinado framework de aprendizado profundo
(por exemplo, como fazer computação numérica básica com matrizes no TensorFlow) ou para a
implementação de técnicas particulares (por exemplo, snippets de código para LeNet, AlexNet,
ResNets, etc) espalhados por vários posts de blog e repositórios GitHub. No entanto, esses ex-
emplos normalmente se concentram em como implementar uma determinada abordagem, mas
deixou de fora a discussão de por que certas decisões algorítmicas são feitas. Embora alguns recur-
sos interativos tenham surgido esporadicamente para abordar um tópico específico, por exemplo,
as postagens de blog envolventes publicado no site [Distill] (http://distill.pub), ou blogs pessoais,
eles cobriram apenas tópicos selecionados no aprendizado profundo, e muitas vezes não tinham
código associado. Por outro lado, embora vários livros tenham surgido, mais notavelmente: cite:
Goodfellow.Bengio.Courville.2016, que oferece uma pesquisa abrangente dos conceitos por trás
do aprendizado profundo, esses recursos não combinam com as descrições às realizações dos con-
ceitos no código, às vezes deixando os leitores sem noção de como implementá-los. Além disso,
muitos recursos estão escondidos atrás dos paywalls de fornecedores de cursos comerciais.
We set out to create a resource that could (i) be freely available for everyone; (ii) offer sufficient
technical depth to provide a starting point on the path to actually becoming an applied machine
learning scientist; (iii) include runnable code, showing readers how to solve problems in practice;
(iv) allow for rapid updates, both by us and also by the community at large; and (v) be comple-
mented by a forum2 for interactive discussion of technical details and to answer questions.
Propusemo-nos a criar um recurso que pudesse (i) estar disponível gratuitamente para todos; (ii)
oferecer profundidade técnica suficiente para fornecer um ponto de partida no caminho para
2
http://discuss.d2l.ai

2 Contents
realmente se tornar um cientista de machine learning aplicado; (iii) incluir código executável,
mostrando aos leitores como resolver problemas na prática; (iv) permitir atualizações rápidas,
tanto por nós e também pela comunidade em geral; e (v) ser complementado por um [fórum]
(http://discuss.d2l.ai) para uma discussão interativa de detalhes técnicos e para responder a per-
guntas.
Esses objetivos costumavam estar em conflito. Equações, teoremas e citações são melhor geren-
ciados e apresentados em LaTeX. O código é melhor descrito em Python. E as páginas da web são
nativas em HTML e JavaScript. Além disso, queremos que o conteúdo seja acessível tanto como
código executável, como livro físico, como um PDF para download e na Internet como um site. No
momento não existem ferramentas e nenhum workflow perfeitamente adequado a essas deman-
das, então tivemos que montar o nosso próprio. Descrevemos nossa abordagem em detalhes em:
numref: sec_how_to_contribute. Decidimos usar o GitHub para compartilhar a fonte e permitir
edições, Notebooks Jupyter para misturar código, equações e texto, Sphinx como um mecanismo
de renderização para gerar várias saídas, e Discourse para o fórum. Embora nosso sistema ainda
não seja perfeito, essas escolhas fornecem um bom compromisso entre as preocupações concor-
rentes. Acreditamos que este seja o primeiro livro publicado usando um workflow integrado.

Aprendendo Fazendo

Muitos livros ensinam uma série de tópicos, cada um com detalhes exaustivos. Por exemplo, o
excelente livro de Chris Bishop: cite: Bishop.2006, ensina cada tópico tão completamente, que
chegar ao capítulo na regressão linear requer uma quantidade não trivial de trabalho. Embora
os especialistas amem este livro precisamente por sua eficácia, para iniciantes, essa propriedade
limita sua utilidade como um texto introdutório.
Neste livro, ensinaremos a maioria dos conceitos just in time. Em outras palavras, você aprenderá
conceitos no exato momento que eles são necessários para realizar algum fim prático. Enquanto
levamos algum tempo no início para ensinar preliminares fundamentais, como álgebra linear e
probabilidade, queremos que você experimente a satisfação de treinar seu primeiro modelo antes
de se preocupar com distribuições de probabilidade mais esotéricas.
Além de alguns cadernos preliminares que fornecem um curso intensivo no background
matemático básico, cada capítulo subsequente apresenta um número razoável de novos conceitos
e fornece exemplos de trabalho auto-contidos únicos — usando datasets reais. Isso representa um
desafio organizacional. Alguns modelos podem ser agrupados logicamente em um único note-
book. E algumas idéias podem ser melhor ensinadas executando vários modelos em sucessão.
Por outro lado, há uma grande vantagem em aderir a uma política de um exemplo funcional, um
notebook: Isso torna o mais fácil possível para você comece seus próprios projetos de pesquisa
aproveitando nosso código. Basta copiar um notebook e começar a modificá-lo.
Vamos intercalar o código executável com o background de material, conforme necessário. Em
geral, muitas vezes erramos por fazer ferramentas disponíveis antes de explicá-los totalmente (e
vamos acompanhar por explicando o background mais tarde). Por exemplo, podemos usar gra-
diente descendente estocástico antes de explicar completamente porque é útil ou porque funciona.
Isso ajuda a dar aos profissionais a munição necessária para resolver problemas rapidamente, às
custas de exigir do leitor que nos confie algumas decisões curatoriais.
Este livro vai ensinar conceitos de deep learning do zero. Às vezes, queremos nos aprofundar em
detalhes sobre os modelos que normalmente ficaria oculto do usuário pelas abstrações avançadas
dos frameworks de deep learning. Isso surge especialmente nos tutoriais básicos, onde queremos
que você entenda tudo que acontece em uma determinada camada ou otimizador. Nesses ca-
sos, apresentaremos frequentemente duas versões do exemplo: onde implementamos tudo do

Contents 3
zero, contando apenas com a interface NumPy e diferenciação automática, e outro exemplo mais
prático, onde escrevemos código sucinto usando APIs de alto nível de frameworks de deep learning.
Depois de ensinar a você como alguns componentes funcionam, podemos apenas usar as APIs de
alto nível em tutoriais subsequentes.

Conteúdo e Estrutura

O livro pode ser dividido em três partes, que são apresentados por cores diferentes em: numref:
fig_book_org:

Fig. 1: Book structure

• A primeira parte cobre os princípios básicos e preliminares. numref:


chap_introduction oferece uma introdução ao deep learning. Então, em: numref:
chap_preliminaries, nós o informamos rapidamente sobre os pré-requisitos exigidos
para deep learning prático, como armazenar e manipular dados, e como aplicar várias
operações numéricas com base em conceitos básicos da álgebra linear, cálculo e prob-
abilidade. numref: chap_linear e: numref:chap_perceptrons cobrem os conceitos e
técnicas mais básicos de aprendizagem profunda, como regressão linear, multilayer
perceptrons e regularização.
• Os próximos cinco capítulos enfocam as técnicas modernas de deep learning. numref:
chap_computation descreve os vários componentes-chave dos cálculos do deep learning
e estabelece as bases para que possamos posteriormente implementar modelos
mais complexos. A seguir, em: numref: chap_cnn e: numref:chap_modern_cnn,
apresentamos redes neurais convolucionais (CNNs, do inglês convolutional neural

4 Contents
networks), ferramentas poderosas que formam a espinha dorsal da maioria dos sis-
temas modernos de visão computacional. Posteriormente, em: numref: chap_rnn e:
numref:chap_modern_rnn, apresentamos redes neurais recorrentes (RNNs, do inglês
recurrent neural networks), modelos que exploram estrutura temporal ou sequencial
em dados, e são comumente usados para processamento de linguagem natural e
previsão de séries temporais. Em: numref: chap_attention, apresentamos uma nova
classe de modelos que empregam uma técnica chamada mecanismos de atenção, que
recentemente começaram a deslocar RNNs no processamento de linguagem natural.
Estas seções irão ajudá-lo a aprender sobre as ferramentas básicas por trás da maioria
das aplicações modernas de deep learning.
• A parte três discute escalabilidade, eficiência e aplicações. Primeiro, em: numref:
chap_optimization, discutimos vários algoritmos de otimização comuns usado para treinar
modelos de deep learning. O próximo capítulo,: numref: chap_performance examina vários
fatores-chave que influenciam o desempenho computacional de seu código de deep learning.
Em: numref: chap_cv, nós ilustramos as principais aplicações de deep learning em visão com-
putacional. Em: numref: chap_nlp_pretrain e: numref:chap_nlp_app, mostramos como
pré-treinar modelos de representação de linguagem e aplicar para tarefas de processamento
de linguagem natural.

Códigos

A maioria das seções deste livro apresenta código executável devido a acreditarmos na importân-
cia de uma experiência de aprendizagem interativa em deep learning. No momento, certas intu-
ições só podem ser desenvolvidas por tentativa e erro, ajustando o código em pequenas formas e
observando os resultados. Idealmente, uma elegante teoria matemática pode nos dizer precisa-
mente como ajustar nosso código para alcançar o resultado desejado. Infelizmente, no momento,
essas teorias elegantes nos escapam. Apesar de nossas melhores tentativas, explicações formais
para várias técnicas ainda faltam, tanto porque a matemática para caracterizar esses modelos
pode ser tão difícil e também porque uma investigação séria sobre esses tópicos só recentemente
entrou em foco. Temos esperança de que, à medida que a teoria do deep learning avança, futuras
edições deste livro serão capazes de fornecer insights em lugares em que a presente edição não
pode.
Às vezes, para evitar repetição desnecessária, encapsulamos as funções, classes, etc. importadas e
mencionadas com frequência neste livro no package d2l. Para qualquer bloco, como uma função,
uma classe ou vários imports ser salvo no pacote, vamos marcá-lo com # @ save. Oferecemos uma
visão geral detalhada dessas funções e classes em: numref: sec_d2l. O package d2l é leve e requer
apenas os seguintes packages e módulos como dependências:

#@save
import collections
import hashlib
import math
import os
import random
import re
import shutil
import sys
import tarfile
import time
import zipfile
(continues on next page)

Contents 5
(continued from previous page)
from collections import defaultdict
import pandas as pd
import requests
from IPython import display
from matplotlib import pyplot as plt

d2l = sys.modules[__name__]

: begin_tab: mxnet A maior parte do código neste livro é baseada no Apache MXNet. MXNet é um
framework de código aberto (oper-source) para deep learning e a escolha preferida de AWS (Ama-
zon Web Services), bem como muitas faculdades e empresas. Todo o código neste livro passou nos
testes da versão mais recente do MXNet. No entanto, devido ao rápido desenvolvimento do deep
learning, alguns códigos na edição impressa podem não funcionar corretamente em versões futuras
do MXNet. No entanto, planejamos manter a versão online atualizada. Caso você encontre algum
desses problemas, consulte: ref: chap_installation para atualizar seu código e ambiente de ex-
ecução.
Aqui está como importamos módulos do MXNet. end_tab: begin_tab: pytorch A maior parte do
código neste livro é baseada no PyTorch. PyTorch é uma estrutura de código aberto para
deep learning, que é extremamente popular na comunidade de pesquisa. Todo o código neste
livro passou nos testes do mais novo PyTorch. No entanto, devido ao rápido desenvolvimento
do deep learning, alguns códigos na edição impressa podem não funcionar corretamente em
versões futuras do PyTorch. No entanto, planejamos manter a versão online atualizada. Caso
você encontre algum desses problemas, consulte: ref: chap_installation para atualizar seu
código e ambiente de execução.
Aqui está como importamos módulos do PyTorch. end_tab: begin_tab: tensorflow A maior
parte do código deste livro é baseada no TensorFlow. TensorFlow é uma estrutura de código
aberto para deep learning, que é extremamente popular na comunidade de pesquisa e na in-
dústria. Todo o código deste livro passou nos testes do TensorFlow mais recente. No entanto,
devido ao rápido desenvolvimento do deep learning, alguns códigos na edição impressa podem
não funcionar corretamente em versões futuras do TensorFlow. No entanto, planejamos
manter a versão online atualizada. Caso você encontre algum desses problemas, consulte:
ref: chap_installation para atualizar seu código e ambiente de execução.
Aqui está como importamos módulos do TensorFlow. end_tab:

#@save
import numpy as np
import torch
import torchvision
from PIL import Image
from torch import nn
from torch.nn import functional as F
from torch.utils import data
from torchvision import transforms

6 Contents
Público-alvo

Este livro é para estudantes (graduação ou pós-graduação), engenheiros e pesquisadores que bus-
cam uma compreensão sólida das técnicas práticas de deep learning. Porque explicamos cada con-
ceito do zero, nenhuma experiência anterior em deep learning ou machine learning é necessária.
Explicando totalmente os métodos de deep learning requer matemática e programação, mas va-
mos apenas supor que você veio com algumas noções básicas, incluindo (o básico de) álgebra lin-
ear, cálculo, probabilidade, e programação Python. Além disso, no Apêndice, fornecemos uma
atualização na maior parte da matemática abordada neste livro. Na maioria das vezes, priorizare-
mos intuição e ideias sobre o rigor matemático. Existem muitos livros fantásticos que podem
levar o leitor interessado ainda mais longe. Por exemplo, Linear Analysis de Bela Bollobas: cite:
Bollobas.1999 cobre álgebra linear e análise funcional em grande profundidade. All of Statistics:
cite: Wasserman.2013 é um excelente guia para estatísticas. E se você nunca usou Python antes,
você pode querer dar uma olhada neste [tutorial de Python] (http://learnpython.org/).

Fórum

Associado a este livro, lançamos um fórum de discussão, localizado em [discuss.d2l.ai] (https:


//discuss.d2l.ai/). Quando você tiver dúvidas sobre qualquer seção do livro, você pode encontrar
o link da página de discussão associada no final de cada capítulo.

Agradecimentos

Estamos em dívida com as centenas de contribuintes de ambos os esboços ingleses e chineses


e brasileiros. Eles ajudaram a melhorar o conteúdo e ofereceram feedback valioso. Especifica-
mente, agradecemos a todos os contribuintes deste rascunho em inglês para torná-lo melhor para
todos. Seus IDs ou nomes do GitHub são (sem nenhuma ordem específica): alxnorden, avinashin-
git, bowen0701, brettkoonce, Chaitanya Prakash Bapat, criptonauta, Davide Fiocco, edgarroman,
gkutiel, John Mitro, Liang Pu, Rahul Agarwal, Mohamed Ali Jamaoui, Michael (Stu) Stewart, Mike
Müller, NRauschmayr, Prakhar Srivastav, sad-, sfermigier, Sheng Zha, sundeepteki, topecongiro,
tpdi, vermicelli, Vishaal Kapoor, Vishwesh Ravi Shrimali, YaYaB, Yuhong Chen, Evgeniy Smirnov,
lgov, Simon Corston-Oliver, Igor Dzreyev, Ha Nguyen, pmuens, Andrei Lukovenko, senorcinco,
vfdev-5, dsweet, Mohammad Mahdi Rahimi, Abhishek Gupta, uwsd, DomKM, Lisa Oakley, Bowen
Li, Aarush Ahuja, Prasanth Buddareddygari, brianhendee, mani2106, mtn, lkevinzc, caojilin,
Lakshya, Fiete Lüer, Surbhi Vijayvargeeya, Muhyun Kim, dennismalmgren, adursun, Anirudh
Dagar, liqingnz, Pedro Larroy, lgov, ati-ozgur, Jun Wu, Matthias Blume, Lin Yuan, geogunow,
Josh Gardner, Maximilian Böther, Rakib Islam, Leonard Lausen, Abhinav Upadhyay, rongru-
osong, Steve Sedlmeyer, Ruslan Baratov, Rafael Schlatter, liusy182, Giannis Pappas, ati-ozgur,
qbaza, dchoi77, Adam Gerson, Phuc Le, Mark Atwood, christabella, vn09, Haibin Lin, jjangga0214,
RichyChen, noelo, hansent, Giel Dops, dvincent1337, WhiteD3vil, Peter Kulits, codypenta, josep-
pinilla, ahmaurya, karolszk, heytitle, Peter Goetz, rigtorp, Tiep Vu, sfilip, mlxd, Kale-ab Tessera,
Sanjar Adilov, MatteoFerrara, hsneto, Katarzyna Biesialska, Gregory Bruss, Duy – Thanh Doan,
paulaurel, graytowne, Duc Pham, sl7423, Jaedong Hwang, Yida Wang, cys4, clhm, Jean Kad-
dour, austinmw, trebeljahr, tbaums, Cuong V. Nguyen, pavelkomarov, vzlamal, NotAnotherSys-
tem, J-Arun-Mani, jancio, eldarkurtic, the-great-shazbot, doctorcolossus, gducharme, cclauss,
Daniel-Mietchen, hoonose, biagiom, abhinavsp0730, jonathanhrandall, ysraell, Nodar Okroshi-
ashvili, UgurKap, Jiyang Kang, StevenJokes, Tomer Kaftan, liweiwp, netyster, ypandya, Nishant-
Tharani, heiligerl, SportsTHU, Hoa Nguyen, manuel-arno-korfmann-webentwicklung, aterzis-
personal, nxby, Xiaoting He, Josiah Yoder, mathresearch, mzz2017, jroberayalas, iluu, ghejc,

Contents 7
BSharmi, vkramdev, simonwardjones, LakshKD, TalNeoran, djliden, Nikhil95, Oren Barkan,
guoweis, haozhu233, pratikhack, 315930399, tayfununal, steinsag, charleybeller, Andrew Lums-
daine, Jiekui Zhang, Deepak Pathak, Florian Donhauser, Tim Gates, Adriaan Tijsseling, Ron Med-
ina, Gaurav Saha, Murat Semerci, Lei Mao, Levi McClenny, Joshua Broyde, jake221, jonbally, zy-
hazwraith, Brian Pulfer, Nick Tomasino.
Agradecemos à Amazon Web Services, especialmente a Swami Sivasubramanian, Raju Gulabani,
Charlie Bell e Andrew Jassy por seu generoso apoio ao escrever este livro. Sem o tempo disponível,
recursos, discussões com colegas e incentivo contínuo, este livro não teria acontecido.

Resumo

• O deep learning revolucionou o reconhecimento de padrões, introduzindo tecnologia que


agora capacita uma ampla gama de tecnologias, incluindo visão computacional, processa-
mento de linguagem natural e reconhecimento automático de fala.
• Para aplicar com sucesso o deep learning, você deve entender como lançar um problema, a
matemática da modelagem, os algoritmos para ajustar seus modelos aos dados e as técnicas
de engenharia para implementar tudo isso.
• Este livro apresenta um recurso abrangente, incluindo prosa, figuras, matemática e código,
tudo em um só lugar.
• Para responder a perguntas relacionadas a este livro, visite nosso fórum em https://discuss.
d2l.ai/.
• Todos os notebooks estão disponíveis para download no GitHub.

Exercícios

1. Registre uma conta no fórum de discussão deste livro [discuss.d2l.ai] (https://discuss.d2l.


ai/).
2. Instale Python em seu computador.
3. Siga os links na parte inferior da seção para o fórum, onde você poderá buscar ajuda e discu-
tir o livro e encontrar respostas para suas perguntas envolvendo os autores e a comunidade
em geral.
Discussions3

3
https://discuss.d2l.ai/t/20

8 Contents
Instalação

Para prepara-lo a ter uma experiência prática de aprendizado, precisamos configurar o ambiente
para executar Python, Jupyter notebooks, as bibliotecas relevantes, e o código necessário para exe-
cutar o livro em si.

Instalando Miniconda

A maneira mais simples de começar será instalar Miniconda4 . A versão Python 3.x é necessária.
Você pode pular as etapas a seguir se o conda já tiver sido instalado. Baixe o arquivo Miniconda
sh correspondente do site e então execute a instalação a partir da linha de comando usando sh
<FILENAME> -b. Para usuários do macOS:

# O nome do arquivo pode estar diferente


sh Miniconda3-latest-MacOSX-x86_64.sh -b

Para os usuários de Linux:

# O nome do arquivo pode estar diferente


sh Miniconda3-latest-Linux-x86_64.sh -b

A seguir, inicialize o shell para que possamos executar conda diretamente.

~/miniconda3/bin/conda init

Agora feche e reabra seu shell atual. Você deve ser capaz de criar um novo ambiente da seguinte
forma:

conda create --name d2l python=3.8 -y

4
https://conda.io/en/latest/miniconda.html

9
Baixando os Notebooks D2L

Em seguida, precisamos baixar o código deste livro. Você pode clicar no botão “All Notebooks” na
parte superior de qualquer página HTML para baixar e descompactar o código. Alternativamente,
se você tiver unzip (caso contrário, executesudo apt install unzip) disponível:

mkdir d2l-en && cd d2l-en


curl https://d2l.ai/d2l-en.zip -o d2l-en.zip
unzip d2l-en.zip && rm d2l-en.zip

Agora precisamos ativar o ambiente d2l.

conda activate d2l

Instalando o Framework e o pacote d2l

Antes de instalar o Framework de Deep Learning, primeiro verifique se você tem ou não GPUs ad-
equadas em sua máquina (as GPUs que alimentam a tela em um laptop padrão não contam para
nossos propósitos). Se você estiver instalando em um servidor GPU, proceda para: ref: subsec_gpu
para instruções para instalar uma versão compatível com GPU.
Caso contrário, você pode instalar a versão da CPU da seguinte maneira. Isso será mais do que
potência suficiente para você pelos primeiros capítulos, mas você precisará acessar GPUs para
executar modelos maiores.

pip install torch torchvision -f https://download.pytorch.org/whl/torch_stable.html

Nós também instalamos o pacote d2l que encapsula funções e classes frequentemente usadas
neste livro.

# -U: Atualiza todos os pacotes para as versões mais atuais disponíveis


pip install -U d2l

Após realizadas as instalações podemos abrir os notebooks Jupyter através do seguinte comando:

jupyter notebook

Nesse ponto, você pode abrir http://localhost:8888 (geralmente abre automaticamente) no nave-
gador da web. Em seguida, podemos executar o código para cada seção do livro. Sempre execute
conda activate d2l para ativar o ambiente de execução antes de executar o código do livro ou
atualizar o framework de Deep Learning ou o pacote d2l. Para sair do ambiente, execute conda
deactivate.

10 Contents
Compatibilidade com GPU

Por padrão, o Framework de Deep Learning é instalada com suporte para GPU. Se o seu computa-
dor tem GPUs NVIDIA e instalou CUDA5 , então está tudo pronto.

Exercícios

1. Baixe o código do livro e instale o ambiente de execução.


Discussão6

5
https://developer.nvidia.com/cuda-downloads
6
https://discuss.d2l.ai/t/24

Contents 11
12 Contents
Notação

A notação usada ao longo deste livro é resumida a seguir.

Numbers

• x: um escalar
• x: um vetor
• X: uma matriz
• X: um tensor
• I: Uma matriz identidade
• xi ,[x]i : O elemento ith do vetor x
• xij ,xi,j ,[X]ij ,[X]i,j : O elemento da matriz X na linha i e coluna j

Teoria de conjuntos

• X : um conjunto
• Z: O conjunto dos inteiros
• Z+ : O conjunto dos inteiros positivos
• R: O conjunto dos números reais
• Rn : O conjunto dos vetores n-dimensionais de números reais
• Ra×b : O conjunto de matrizes de números reais com a linhas e b colunas
• |X |: Cardinalidade (número de elementos) do conjunto X
• A ∪ B: União dos conjuntos A e B
• A ∩ B: Interseção dos conjuntos A e B
• A \ B: Subtração do conjunto B do conjunto A

13
Funções e operadores

• f (·): uma função


• log(·): O logaritmo natural
• exp(·): A função exponencial
• 1X : a função do indicador
• (·)⊤ : Transposta de uma matriz ou vetor
• X−1 : Inversa da matriz X
• ⊙: produto Hadamard (elemento a elemento)
• [·, ·]: Concatenação
• $:raw-latex:lvert `:raw-latex:mathcal {X}` :raw-latex:`\rvert `$: Cardinalidade do conjunto
:math:`mathcal {X}`
• $| :raw-latex:`\cdot `\| \_p $: :math:`L_p` norma
• | · ∥: L2 norma
• $:raw-latex:langle `:raw-latex:mathbf {x}`, :raw-latex:`\mathbf {y}` :raw-latex:`\rangle `$:
Produto escalar dos vetores :math:`mathbf {x}` e $:raw-latex:mathbf {y} $
• $:raw-latex:`sum `$: adição de séries
• $:raw-latex:`prod `$: multiplicação de séries
• $:raw-latex:stackrel {mathrm {def}} {=} $: Definição

Cálculo

• $:raw-latex:frac{dy}{dx} $: Derivada de y em relação a x


• $:raw-latex:frac{partial y}{partial x} $: Derivada parcial de y em relação a x
• $:raw-latex:nabla_{:raw-latex:`\mathbf {x}`} y $: Gradiente de y em relação a x
• $:raw-latex:int_a ^ b f (x) ; dx $: Integral definida de f de a a b em relação a x
• $:raw-latex:int `f (x) ; dx $: Integral indefinida de :math:`f em relação a x

Probabilidade e Teoria da Informação

• $P (:raw-latex:`\cdot`) $: distribuição de probabilidade


• $z :raw-latex:`\sim `P $: Variável aleatória :math:`z` que tem distribuição de probabilidade
P
• $P (X :raw-latex:`\mid `Y) $: probabilidade condicional de :math:`X\mid Y`
• $p (x) $: função de densidade de probabilidade
• ${E} _ {x} [f (x)] $: Esperança de f em relação a x

14 Contents
• $X :raw-latex:`\perp `Y $: Variáveis aleatórias :math:`X` e Y são independentes
• $X :raw-latex:`\perp `Y :raw-latex:`mid Z $: Variáveis aleatórias :math:`X e Y são condi-
cionalmente independentes, dada a variável aleatória Z
• $:raw-latex:mathrm {Var} (X) $: Variância da variável aleatória X
• $:raw-latex:sigma_X $: Desvio padrão da variável aleatória X
• $:raw-latex:mathrm {Cov} (X, Y) $: Covariância das variáveis aleatórias X e Y
• $:raw-latex:rho `(X, Y) $: Correlação de variáveis aleatórias :math:`X e Y
• $H (X) $: Entropia da variável aleatória X
• $D _ {:raw-latex:`\mathrm {KL}`} (P | Q) $: KL-divergência das distribuições P e Q

Complexidade

• O: notação Big O
Discussions7

7
https://discuss.d2l.ai/t/25

Contents 15
16 Contents
1 | Introdução

Até recentemente, quase todos os programas de computador com os quais interagimos diaria-
mente eram codificados por desenvolvedores de software desde os primeiros princípios. Digamos
que quiséssemos escrever um aplicativo para gerenciar uma plataforma de e-commerce. Depois de
se amontoar em um quadro branco por algumas horas para refletir sobre o problema, iríamos ap-
resentar os traços gerais de uma solução de trabalho que provavelmente se pareceria com isto: (i)
os usuários interagem com o aplicativo por meio de uma interface executando em um navegador
da web ou aplicativo móvel; (ii) nosso aplicativo interage com um mecanismo de banco de dados
de nível comercial para acompanhar o estado de cada usuário e manter registros de histórico de
transações; e (iii) no cerne de nossa aplicação, a lógica de negócios (você pode dizer, os cérebros)
de nosso aplicativo descreve em detalhes metódicos a ação apropriada que nosso programa deve
levar em todas as circunstâncias concebíveis.
Para construir o cérebro de nosso aplicativo, teríamos que percorrer todos os casos esquivos pos-
síveis que antecipamos encontrar, criando regras apropriadas. Cada vez que um cliente clica para
adicionar um item ao carrinho de compras, adicionamos uma entrada à tabela de banco de da-
dos do carrinho de compras, associando o ID desse usuário ao ID do produto solicitado. Embora
poucos desenvolvedores acertem completamente na primeira vez (podem ser necessários alguns
testes para resolver os problemas), na maior parte, poderíamos escrever esse programa a partir
dos primeiros princípios e lançá-lo com confiança antes de ver um cliente real. Nossa capacidade
de projetar sistemas automatizados a partir dos primeiros princípios que impulsionam o funciona-
mento de produtos, sistemas e, frequentemente em novas situações, é um feito cognitivo notável.
E quando você é capaz de conceber soluções que funcionam 100% do tempo, você não deveria
usar o machine learning.
Felizmente para a crescente comunidade de cientistas de machine learning, muitas tarefas que
gostaríamos de automatizar não se curvam tão facilmente à habilidade humana. Imagine se
amontoar em volta do quadro branco com as mentes mais inteligentes que você conhece, mas
desta vez você está lidando com um dos seguintes problemas:
• Escreva um programa que preveja o clima de amanhã com base em informações geográficas,
imagens de satélite e uma janela de rastreamento do tempo passado.
• Escreva um programa que aceite uma pergunta, expressa em texto de forma livre, e a re-
sponda corretamente.
• Escreva um programa que, dada uma imagem, possa identificar todas as pessoas que ela
contém, desenhando contornos em torno de cada uma.
• Escreva um programa que apresente aos usuários produtos que eles provavelmente irão
gostar, mas que provavelmente não encontrarão no curso natural da navegação.
Em cada um desses casos, mesmo programadores de elite são incapazes de codificar soluções do
zero. As razões para isso podem variar. Às vezes, o programa que procuramos segue um padrão

17
que muda com o tempo, e precisamos que nossos programas se adaptem. Em outros casos, a re-
lação (digamos, entre pixels, e categorias abstratas) podem ser muito complicadas, exigindo mil-
hares ou milhões de cálculos que estão além da nossa compreensão consciente mesmo que nossos
olhos administrem a tarefa sem esforço. Machine learning é o estudo de poderosas técnicas que
podem aprender com a experiência. À medida que um algoritmo de machine learning acumula
mais experiência, normalmente na forma de dados observacionais ou interações com um am-
biente, seu desempenho melhora. Compare isso com nossa plataforma de comércio eletrônico
determinística, que funciona de acordo com a mesma lógica de negócios, não importa quanta
experiência acumule, até que os próprios desenvolvedores aprendam e decidam que é hora de
atualizar o software. Neste livro, ensinaremos os fundamentos do machine learning, e foco em par-
ticular no deep learning, um poderoso conjunto de técnicas impulsionando inovações em áreas tão
diversas como a visão computacional, processamento de linguagem natural, saúde e genômica.

1.1 Um exemplo motivador

Antes de começar a escrever, os autores deste livro, como grande parte da força de trabalho,
tiveram que se tornar cafeinados. Entramos no carro e começamos a dirigir. Usando um iPhone,
Alex gritou “Ei, Siri”, despertando o sistema de reconhecimento de voz do telefone. Então Mu
comandou “rota para a cafeteria Blue Bottle”. O telefone rapidamente exibiu a transcrição de seu
comando. Ele também reconheceu que estávamos pedindo direções e abriu o aplicativo Maps
(app) para cumprir nosso pedido. Depois de laberto, o aplicativo Maps identificou várias rotas.
Ao lado de cada rota, o telefone exibia um tempo de trânsito previsto. Enquanto fabricamos esta
história por conveniência pedagógica, isso demonstra que no intervalo de apenas alguns segun-
dos, nossas interações diárias com um telefone inteligente podem envolver vários modelos de
machine learning.
Imagine apenas escrever um programa para responder a uma palavra de alerta como “Alexa”, “OK
Google” e “Hey Siri”. Tente codificar em uma sala sozinho com nada além de um computador e
um editor de código, conforme ilustrado em: numref: fig_wake_word. Como você escreveria tal
programa a partir dos primeiros princípios? Pense nisso … o problema é difícil. A cada segundo,
o microfone irá coletar aproximadamente 44.000 amostras. Cada amostra é uma medida da am-
plitude da onda sonora. Que regra poderia mapear de forma confiável, de um trecho de áudio
bruto a previsões confiáveis {yes, no} sobre se o trecho de áudio contém a palavra de ativação? Se
você estiver travado, não se preocupe. Também não sabemos escrever tal programa do zero. É
por isso que usamos o machine learning.

Fig. 1.1.1: Identificar uma palavra de ativação.

Aqui está o truque. Muitas vezes, mesmo quando não sabemos como dizer a um computador
explicitamente como mapear de entradas para saídas, ainda assim, somos capazes de realizar a
façanha cognitiva por nós mesmos. Em outras palavras, mesmo que você não saiba como pro-
gramar um computador para reconhecer a palavra “Alexa”, você mesmo é capaz de reconhecê-lo.
Armados com essa habilidade, podemos coletar um enorme dataset contendo exemplos de áudio
e rotular aqueles que contêm e que não contêm a palavra de ativação. Na abordagem de machine
learning, não tentamos projetar um sistema explicitamente para reconhecer palavras de ativação.

18 Chapter 1. Introdução
Em vez disso, definimos um programa flexível cujo comportamento é determinado por vários
parâmetros. Em seguida, usamos o conjunto de dados para determinar o melhor conjunto possível
de parâmetros, aqueles que melhoram o desempenho do nosso programa com respeito a alguma
medida de desempenho na tarefa de interesse.
Você pode pensar nos parâmetros como botões que podemos girar, manipulando o comporta-
mento do programa. Fixando os parâmetros, chamamos o programa de modelo. O conjunto de
todos os programas distintos (mapeamentos de entrada-saída) que podemos produzir apenas ma-
nipulando os parâmetros é chamada de família de modelos. E o meta-programa que usa nosso
conjunto de dados para escolher os parâmetros é chamado de algoritmo de aprendizagem.
Antes de prosseguirmos e envolvermos o algoritmo de aprendizagem, temos que definir o prob-
lema com precisão, identificando a natureza exata das entradas e saídas, e escolher uma família
modelo apropriada. Nesse caso, nosso modelo recebe um trecho de áudio como entrada, e o mod-
elo gera uma seleção entre {yes, no} como saída. Se tudo correr de acordo com o plano as su-
posições da modelo vão normalmente estar corretas quanto a se o áudio contém a palavra de
ativação.
Se escolhermos a família certa de modelos, deve haver uma configuração dos botões de forma que
o modelo dispara “sim” toda vez que ouve a palavra “Alexa”. Como a escolha exata da palavra de
ativação é arbitrária, provavelmente precisaremos de uma família modelo suficientemente rica
que, por meio de outra configuração dos botões, ele poderia disparar “sim” somente ao ouvir a
palavra “Damasco”. Esperamos que a mesma família de modelo seja adequada para reconhec-
imento “Alexa” e reconhecimento “Damasco” porque parecem, intuitivamente, tarefas semel-
hantes. No entanto, podemos precisar de uma família totalmente diferente de modelos se quis-
ermos lidar com entradas ou saídas fundamentalmente diferentes, digamos que se quiséssemos
mapear de imagens para legendas, ou de frases em inglês para frases em chinês.
Como você pode imaginar, se apenas definirmos todos os botões aleatoriamente, é improvável
que nosso modelo reconheça “Alexa”, “Apricot”, ou qualquer outra palavra em inglês. No machine
learning, o aprendizado (learning) é o processo pelo qual descobrimos a configuração certa dos
botões coagindo o comportamento desejado de nosso modelo. Em outras palavras, nós treinamos
nosso modelo com dados. Conforme mostrado em: numref:fig_ml_loop, o processo de treina-
mento geralmente se parece com o seguinte:
1. Comece com um modelo inicializado aleatoriamente que não pode fazer nada útil.
2. Pegue alguns de seus dados (por exemplo, trechos de áudio e labels {yes, no} correspon-
dentes).
3. Ajuste os botões para que o modelo seja menos ruim em relação a esses exemplos.
4. Repita as etapas 2 e 3 até que o modelo esteja incrível.

Fig. 1.1.2: Um processo de treinamento típico.

Para resumir, em vez de codificar um reconhecedor de palavra de acionamento, nós codificamos

1.1. Um exemplo motivador 19


um programa que pode aprender a reconhecê-las se o apresentarmos com um grande dataset rotu-
lado. Você pode pensar neste ato de determinar o comportamento de um programa apresentando-
o com um dataset como programação com dados. Quer dizer, podemos “programar” um detector
de gatos, fornecendo nosso sistema de aprendizado de máquina com muitos exemplos de cães e
gatos. Dessa forma, o detector aprenderá a emitir um número positivo muito grande se for um
gato, um número negativo muito grande se for um cachorro, e algo mais próximo de zero se não
houver certeza, e isso é apenas a ponta do iceberg do que o machine learning pode fazer. Deep learn-
ing, que iremos explicar em maiores detalhes posteriormente, é apenas um entre muitos métodos
populares para resolver problemas de machine learning.

1.2 Componentes chave

Em nosso exemplo de palavra de ativação, descrevemos um dataset consistindo em trechos de


áudio e labels binários, e nós demos uma sensação ondulante de como podemos treinar um mod-
elo para aproximar um mapeamento de áudios para classificações. Esse tipo de problema, onde
tentamos prever um label desconhecido designado com base em entradas conhecidas dado um
conjunto de dados que consiste em exemplos para os quais os rótulos são conhecidos, é chamado
de aprendizagem supervisionada. Esse é apenas um entre muitos tipos de problemas de machine
learning. Posteriormente, mergulharemos profundamente em diferentes problemas de machine
learning. Primeiro, gostaríamos de lançar mais luz sobre alguns componentes principais que nos
acompanharão, independentemente do tipo de problema de machine learning que enfrentarmos:
1. Os dados com os quais podemos aprender.
2. Um modelo de como transformar os dados.
3. Uma função objetivo que quantifica o quão bem (ou mal) o modelo está indo.
4. Um algoritmo para ajustar os parâmetros do modelo para otimizar a função objetivo.

1.2.1 Dados

Nem é preciso dizer que você não pode fazer ciência de dados sem dados. Podemos perder cen-
tenas de páginas pensando no que exatamente constitui os dados, mas por agora, vamos errar no
lado prático e focar nas principais propriedades com as quais se preocupar. Geralmente, esta-
mos preocupados com uma coleção de exemplos. Para trabalhar com dados de maneira útil, nós
tipicamente precisamos chegar a uma representação numérica adequada. Cada exemplo (ou ponto
de dados, instância de dados, amostra) normalmente consiste em um conjunto de atributos chama-
dos recursos (ou covariáveis ), a partir do qual o modelo deve fazer suas previsões. Nos problemas
de aprendizagem supervisionada acima, a coisa a prever é um atributo especial que é designado
como o rótulo (label) (ou alvo).
Se estivéssemos trabalhando com dados de imagem, cada fotografia individual pode constituir um
exemplo, cada um representado por uma lista ordenada de valores numéricos correspondendo ao
brilho de cada pixel. Uma fotografia colorida de 200 × 200 consistiria em 200 × 200 × 3 = 120000
valores numéricos, correspondentes ao brilho dos canais vermelho, verde e azul para cada pixel.
Em outra tarefa tradicional, podemos tentar prever se um paciente vai sobreviver ou não, dado
um conjunto padrão de recursos, como idade, sinais vitais e diagnósticos.
Quando cada exemplo é caracterizado pelo mesmo número de valores numéricos, dizemos que
os dados consistem em vetores de comprimento fixo e descrevemos o comprimento constante
dos vetores como a dimensionalidade dos dados. Como você pode imaginar, o comprimento fixo

20 Chapter 1. Introdução
pode ser uma propriedade conveniente. Se quiséssemos treinar um modelo para reconhecer o
câncer em imagens microscópicas, entradas de comprimento fixo significam que temos uma coisa
a menos com que nos preocupar.
No entanto, nem todos os dados podem ser facilmente representados como vetores de compri-
mento fixo. Embora possamos esperar que as imagens do microscópio venham de equipamentos
padrão, não podemos esperar imagens extraídas da Internet aparecerem todas com a mesma res-
olução ou formato. Para imagens, podemos considerar cortá-los todas em um tamanho padrão,
mas essa estratégia só nos leva até certo ponto. Corremos o risco de perder informações nas
partes cortadas. Além disso, os dados de texto resistem a representações de comprimento fixo
ainda mais obstinadamente. Considere os comentários de clientes deixados em sites de comér-
cio eletrônico como Amazon, IMDB e TripAdvisor. Alguns são curtos: “é uma porcaria!”. Outros
vagam por páginas. Uma das principais vantagens do deep learning sobre os métodos tradicionais
é a graça comparativa com a qual os modelos modernos podem lidar com dados de comprimento
variável.
Geralmente, quanto mais dados temos, mais fácil se torna nosso trabalho. Quando temos mais da-
dos, podemos treinar modelos mais poderosos e dependem menos de suposições pré-concebidas.
A mudança de regime de (comparativamente) pequeno para big data é um dos principais con-
tribuintes para o sucesso do deep learning moderno. Para esclarecer, muitos dos modelos mais
interessantes de deep learning não funcionam sem grandes datasets. Alguns outros trabalham no
regime de pequenos dados, mas não são melhores do que as abordagens tradicionais.
Por fim, não basta ter muitos dados e processá-los com inteligência. Precisamos dos dados certos.
Se os dados estiverem cheios de erros, ou se os recursos escolhidos não são preditivos da quan-
tidade alvo de interesse, o aprendizado vai falhar. A situação é bem capturada pelo clichê: entra
lixo, sai lixo. Além disso, o desempenho preditivo ruim não é a única consequência potencial.
Em aplicativos sensíveis de machine learning, como policiamento preditivo, triagem de currículo
e modelos de risco usados para empréstimos, devemos estar especialmente alertas para as con-
sequências de dados inúteis. Um modo de falha comum ocorre em conjuntos de dados onde al-
guns grupos de pessoas não são representados nos dados de treinamento. Imagine aplicar um
sistema de reconhecimento de câncer de pele na natureza que nunca tinha visto pele negra antes.
A falha também pode ocorrer quando os dados não apenas sub-representem alguns grupos mas
refletem preconceitos sociais. Por exemplo, se as decisões de contratação anteriores forem us-
adas para treinar um modelo preditivo que será usado para selecionar currículos, então os mod-
elos de aprendizado de máquina poderiam inadvertidamente capturar e automatizar injustiças
históricas. Observe que tudo isso pode acontecer sem o cientista de dados conspirar ativamente,
ou mesmo estar ciente.

1.2.2 Modelos

A maior parte do machine learning envolve transformar os dados de alguma forma. Talvez
queiramos construir um sistema que ingere fotos e preveja sorrisos. Alternativamente, pode-
mos querer ingerir um conjunto de leituras de sensor e prever quão normais ou anômalas são
as leituras. Por modelo, denotamos a maquinaria computacional para ingestão de dados de um
tipo, e cuspir previsões de um tipo possivelmente diferente. Em particular, estamos interessados
em modelos estatísticos que podem ser estimados a partir de dados. Embora os modelos simples
sejam perfeitamente capazes de abordar problemas apropriadamente simples, os problemas nos
quais nos concentramos neste livro, ampliam os limites dos métodos clássicos. O deep learning é
diferenciado das abordagens clássicas principalmente pelo conjunto de modelos poderosos em
que se concentra. Esses modelos consistem em muitas transformações sucessivas dos dados que

1.2. Componentes chave 21


são encadeados de cima para baixo, daí o nome deep learning. No caminho para discutir modelos
profundos, também discutiremos alguns métodos mais tradicionais.

1.2.3 Funções Objetivo

Anteriormente, apresentamos o machine learning como aprendizado com a experiência. Por


aprender aqui, queremos dizer melhorar em alguma tarefa ao longo do tempo. Mas quem pode
dizer o que constitui uma melhoria? Você pode imaginar que poderíamos propor a atualização
do nosso modelo, e algumas pessoas podem discordar sobre se a atualização proposta constituiu
uma melhoria ou um declínio.
A fim de desenvolver um sistema matemático formal de máquinas de aprendizagem, precisamos
ter medidas formais de quão bons (ou ruins) nossos modelos são. No machine learning, e na
otimização em geral, chamamos elas de funções objetivo. Por convenção, geralmente definimos
funções objetivo de modo que quanto menor, melhor. Esta é apenas uma convenção. Você pode
assumir qualquer função para a qual mais alto é melhor, e transformá-la em uma nova função que
é qualitativamente idêntica, mas para a qual menor é melhor, invertendo o sinal. Porque quanto
menor é melhor, essas funções às vezes são chamadas funções de perda (loss functions).
Ao tentar prever valores numéricos, a função de perda mais comum é erro quadrático, ou seja, o
quadrado da diferença entre a previsão e a verdade fundamental. Para classificação, o objetivo
mais comum é minimizar a taxa de erro, ou seja, a fração de exemplos em que nossas previsões
discordam da verdade fundamental. Alguns objetivos (por exemplo, erro quadrático) são fáceis
de otimizar. Outros (por exemplo, taxa de erro) são difíceis de otimizar diretamente, devido à
indiferenciabilidade ou outras complicações. Nesses casos, é comum otimizar um objetivo substi-
tuto.
Normalmente, a função de perda é definida no que diz respeito aos parâmetros do modelo e de-
pende do conjunto de dados. Nós aprendemos os melhores valores dos parâmetros do nosso
modelo minimizando a perda incorrida em um conjunto consistindo em alguns exemplos cole-
tados para treinamento. No entanto, indo bem nos dados de treinamento não garante que ter-
emos um bom desempenho com dados não vistos. Portanto, normalmente queremos dividir os
dados disponíveis em duas partições: o dataset de treinamento (ou conjunto de treinamento, para
ajustar os parâmetros do modelo) e o dataset de teste (ou conjunto de teste, que é apresentado para
avaliação), relatando o desempenho do modelo em ambos. Você pode pensar no desempenho do
treinamento como sendo as pontuações de um aluno em exames práticos usado para se preparar
para algum exame final real. Mesmo que os resultados sejam encorajadores, isso não garante
sucesso no exame final. Em outras palavras, o desempenho do teste pode divergir significativa-
mente do desempenho do treinamento. Quando um modelo tem um bom desempenho no con-
junto de treinamento mas falha em generalizar para dados invisíveis, dizemos que está fazendo
overfitting. Em termos da vida real, é como ser reprovado no exame real apesar de ir bem nos
exames práticos.

22 Chapter 1. Introdução
1.2.4 Algoritmos de Otimização

Assim que tivermos alguma fonte de dados e representação, um modelo e uma função objetivo
bem definida, precisamos de um algoritmo capaz de pesquisar para obter os melhores parâmetros
possíveis para minimizar a função de perda. Algoritmos de otimização populares para aprendiza-
gem profunda baseiam-se em uma abordagem chamada gradiente descendente. Em suma, em cada
etapa, este método verifica, para cada parâmetro, para que lado a perda do conjunto de treina-
mento se moveria se você perturbou esse parâmetro apenas um pouco. Em seguida, atualiza o
parâmetro na direção que pode reduzir a perda.

1.3 Tipos de Problemas de Machine Learning

O problema da palavra de ativação em nosso exemplo motivador é apenas um entre muitos prob-
lemas que o machine learning pode resolver. Para motivar ainda mais o leitor e nos fornecer uma
linguagem comum quando falarmos sobre mais problemas ao longo do livro, a seguir nós lista-
mos uma amostra dos problemas de machine learning. Estaremos constantemente nos referindo
a nossos conceitos acima mencionados como dados, modelos e técnicas de treinamento.

1.3.1 Aprendizagem Supervisionada

A aprendizagem supervisionada (supervised learning) aborda a tarefa de prever labels com recursos
de entrada. Cada par recurso-rótulo é chamado de exemplo. Às vezes, quando o contexto é claro,
podemos usar o termo exemplos para se referir a uma coleção de entradas, mesmo quando os labels
correspondentes são desconhecidos. Nosso objetivo é produzir um modelo que mapeia qualquer
entrada para uma previsão de label.
Para fundamentar esta descrição em um exemplo concreto, se estivéssemos trabalhando na área
de saúde, então podemos querer prever se um paciente teria um ataque cardíaco ou não. Esta
observação, “ataque cardíaco” ou “sem ataque cardíaco”, seria nosso label. Os recursos de entrada
podem ser sinais vitais como frequência cardíaca, pressão arterial diastólica, e pressão arterial
sistólica.
A supervisão entra em jogo porque para a escolha dos parâmetros, nós (os supervisores) fornece-
mos ao modelo um conjunto de dados consistindo em exemplos rotulados, onde cada exemplo é
correspondido com o label da verdade fundamental. Em termos probabilísticos, normalmente es-
tamos interessados em estimar a probabilidade condicional de determinados recursos de entrada
de um label. Embora seja apenas um entre vários paradigmas no machine learning, a aprendiza-
gem supervisionada é responsável pela maioria das bem-sucedidas aplicações de machine learn-
ing na indústria. Em parte, isso ocorre porque muitas tarefas importantes podem ser descritas
nitidamente como estimar a probabilidade de algo desconhecido dado um determinado dataset
disponível:
• Prever câncer versus não câncer, dada uma imagem de tomografia computadorizada.
• Prever a tradução correta em francês, dada uma frase em inglês.
• Prever o preço de uma ação no próximo mês com base nos dados de relatórios financeiros
deste mês.
Mesmo com a descrição simples “previsão de labels com recursos de entrada” a aprendizagem su-
pervisionada pode assumir muitas formas e exigem muitas decisões de modelagem, dependendo
(entre outras considerações) do tipo, tamanho, e o número de entradas e saídas. Por exemplo,

1.3. Tipos de Problemas de Machine Learning 23


usamos diferentes modelos para processar sequências de comprimentos arbitrários e para pro-
cessar representações de vetores de comprimento fixo. Visitaremos muitos desses problemas em
profundidade ao longo deste livro.
Informalmente, o processo de aprendizagem se parece com o seguinte. Primeiro, pegue uma
grande coleção de exemplos para os quais os recursos são conhecidos e selecione deles um sub-
conjunto aleatório, adquirindo os labels da verdade fundamental para cada um. Às vezes, esses
labels podem ser dados disponíveis que já foram coletados (por exemplo, um paciente morreu no
ano seguinte?) e outras vezes, podemos precisar empregar anotadores humanos para rotular os
dados, (por exemplo, atribuição de imagens a categorias). Juntas, essas entradas e os labels cor-
respondentes constituem o conjunto de treinamento. Alimentamos o dataset de treinamento em
um algoritmo de aprendizado supervisionado, uma função que recebe como entrada um conjunto
de dados e produz outra função: o modelo aprendido. Finalmente, podemos alimentar entradas
não vistas anteriormente para o modelo aprendido, usando suas saídas como previsões do rótulo
correspondente. O processo completo é desenhado em: numref: fig_supervised_learning.

Fig. 1.3.1: Aprendizagem supervisionada.

Regressão

Talvez a tarefa de aprendizagem supervisionada mais simples para entender é regressão. Con-
sidere, por exemplo, um conjunto de dados coletados de um banco de dados de vendas de casas.
Podemos construir uma mesa, onde cada linha corresponde a uma casa diferente, e cada coluna
corresponde a algum atributo relevante, como a metragem quadrada de uma casa, o número de
quartos, o número de banheiros e o número de minutos (caminhando) até o centro da cidade.
Neste conjunto de dados, cada exemplo seria uma casa específica, e o vetor de recurso correspon-
dente seria uma linha na tabela. Se você mora em Nova York ou São Francisco, e você não é o
CEO da Amazon, Google, Microsoft ou Facebook, o vetor de recursos (metragem quadrada, nº de
quartos, nº de banheiros, distância a pé) para sua casa pode ser algo como: $ [56, 1, 1, 60] $. No
entanto, se você mora em Pittsburgh, pode ser parecido com $ [279, 4, 3, 10] $. Vetores de recursos
como este são essenciais para a maioria dos algoritmos clássicos de machine learning.
O que torna um problema uma regressão é, na verdade, o resultado. Digamos que você esteja em
busca de uma nova casa. Você pode querer estimar o valor justo de mercado de uma casa, dados
alguns recursos como acima. O label, o preço de venda, é um valor numérico. Quando os labels
assumem valores numéricos arbitrários, chamamos isso de problema de regressão. Nosso objetivo
é produzir um modelo cujas previsões aproximar os valores reais do label.
Muitos problemas práticos são problemas de regressão bem descritos. Prever a avaliação que
um usuário atribuirá a um filme pode ser pensado como um problema de regressão e se você
projetou um ótimo algoritmo para realizar essa façanha em 2009, você pode ter ganho o [prêmio de
1 milhão de dólares da Netflix] (https://en.wikipedia.org/wiki/Netflix_Prize). Previsão do tempo
de permanência de pacientes no hospital também é um problema de regressão. Uma boa regra é:
qualquer problema de quanto? Ou quantos? deve sugerir regressão, tal como:

24 Chapter 1. Introdução
• Quantas horas durará esta cirurgia?
• Quanta chuva esta cidade terá nas próximas seis horas?
Mesmo que você nunca tenha trabalhado com machine learning antes, você provavelmente já tra-
balhou em um problema de regressão informalmente. Imagine, por exemplo, que você mandou
consertar seus ralos e que seu contratante gastou 3 horas removendo sujeira de seus canos de es-
goto. Então ele lhe enviou uma conta de 350 dólares. Agora imagine que seu amigo contratou o
mesmo empreiteiro por 2 horas e que ele recebeu uma nota de 250 dólares. Se alguém lhe per-
guntasse quanto esperar em sua próxima fatura de remoção de sujeira você pode fazer algumas
suposições razoáveis, como mais horas trabalhadas custam mais dólares. Você também pode pre-
sumir que há alguma carga básica e que o contratante cobra por hora. Se essas suposições forem
verdadeiras, dados esses dois exemplos de dados, você já pode identificar a estrutura de preços
do contratante: 100 dólares por hora mais 50 dólares para aparecer em sua casa. Se você acom-
panhou esse exemplo, então você já entendeu a ideia de alto nível por trás da regressão linear.
Neste caso, poderíamos produzir os parâmetros que correspondem exatamente aos preços do
contratante. Às vezes isso não é possível, por exemplo, se alguma variação se deve a algum fator
além dos dois citados. Nestes casos, tentaremos aprender modelos que minimizam a distância
entre nossas previsões e os valores observados. Na maioria de nossos capítulos, vamos nos con-
centrar em minimizar a função de perda de erro quadrático. Como veremos mais adiante, essa
perda corresponde ao pressuposto que nossos dados foram corrompidos pelo ruído gaussiano.

Classificação

Embora os modelos de regressão sejam ótimos para responder às questões quantos?, muitos prob-
lemas não se adaptam confortavelmente a este modelo. Por exemplo, um banco deseja adicionar
a digitalização de cheques ao seu aplicativo móvel. Isso envolveria o cliente tirando uma foto de
um cheque com a câmera do smartphone deles e o aplicativo precisaria ser capaz de entender
automaticamente o texto visto na imagem. Especificamente, também precisaria entender o texto
manuscrito para ser ainda mais robusto, como mapear um caractere escrito à mão a um dos per-
sonagens conhecidos. Este tipo de problema de qual? É chamado de classificação. É tratado com
um conjunto diferente de algoritmos do que aqueles usados para regressão, embora muitas téc-
nicas sejam transportadas.
Na classificação, queremos que nosso modelo analise os recursos, por exemplo, os valores de pixel
em uma imagem, e, em seguida, prever qual categoria (formalmente chamada de classe), entre
alguns conjuntos discretos de opções, um exemplo pertence. Para dígitos manuscritos, podemos
ter dez classes, correspondendo aos dígitos de 0 a 9. A forma mais simples de classificação é
quando existem apenas duas classes, um problema que chamamos de classificação binária. Por
exemplo, nosso conjunto de dados pode consistir em imagens de animais e nossos rótulos podem
ser as classes {cat, dog}. Durante a regressão, buscamos um regressor para produzir um valor
numérico, na classificação, buscamos um classificador, cuja saída é a atribuição de classe prevista.
Por razões que abordaremos à medida que o livro se torna mais técnico, pode ser difícil otimizar
um modelo que só pode produzir uma tarefa categórica difícil, por exemplo, “gato” ou “cachorro”.
Nesses casos, geralmente é muito mais fácil expressar nosso modelo na linguagem das prob-
abilidades. Dados os recursos de um exemplo, nosso modelo atribui uma probabilidade para
cada classe possível. Voltando ao nosso exemplo de classificação animal onde as classes são
{gato, cachorro}, um classificador pode ver uma imagem e gerar a probabilidade que a imagem
é um gato como 0,9. Podemos interpretar esse número dizendo que o classificador tem 90% de
certeza de que a imagem representa um gato. A magnitude da probabilidade para a classe prevista

1.3. Tipos de Problemas de Machine Learning 25


transmite uma noção de incerteza. Esta não é a única noção de incerteza e discutiremos outros
em capítulos mais avançados.
Quando temos mais de duas classes possíveis, chamamos o problema de classificação multiclasse.
Exemplos comuns incluem reconhecimento de caracteres escritos à mão {0, 1, 2, ...9, a, b, c, ...}.
Enquanto atacamos problemas de regressão tentando minimizar a função de perda de erro
quadrático, a função de perda comum para problemas de classificação é chamada de entropia
cruzada (cross-entropy), cujo nome pode ser desmistificado por meio de uma introdução à teoria
da informação nos capítulos subsequentes.
Observe que a classe mais provável não é necessariamente aquela que você usará para sua de-
cisão. Suponha que você encontre um lindo cogumelo em seu quintal como mostrado em: num-
ref: fig_death_cap.

Fig. 1.3.2: Cicuta verde1 — não coma!

Agora, suponha que você construiu um classificador e o treinou para prever se um cogumelo é
venenoso com base em uma fotografia. Digamos que nossos resultados do classificador de de-
tecção de veneno que a probabilidade de que : numref: fig_death_cap contém um Cicuta verde
de 0,2. Em outras palavras, o classificador tem 80% de certeza que nosso cogumelo não é um Ci-
cuta verde. Ainda assim, você teria que ser um tolo para comê-lo. Isso porque o certo benefício
de um jantar delicioso não vale a pena um risco de 20% de morrer por causa disso. Em outras
palavras, o efeito do risco incerto supera o benefício de longe. Assim, precisamos calcular o risco
esperado que incorremos como a função de perda, ou seja, precisamos multiplicar a probabili-
dade do resultado com o benefício (ou dano) associado a ele. Nesse caso, a perda incorrida ao
comer o cogumelo pode ser 0, 2 × ∞ + 0, 8 × 0 = ∞, Considerando que a perda de descarte é
0, 2 × 0 + 0, 8 × 1 = 0, 8. Nossa cautela foi justificada: como qualquer micologista nos diria, o
cogumelo em: numref: fig_death_cap na verdade é um Cicuta verde.
A classificação pode ser muito mais complicada do que apenas classificação binária, multi-classe
ou mesmo com vários rótulos. Por exemplo, existem algumas variantes de classificação para
abordar hierarquias. As hierarquias assumem que existem alguns relacionamentos entre as
muitas classes. Portanto, nem todos os erros são iguais — se devemos errar, preferiríamos
classificar incorretamente para uma classe parecida em vez de uma classe distante. Normal-
mente, isso é conhecido como classificação hierárquica. Um exemplo inicial é devido a [Linnaeus]
(https://en.wikipedia.org/wiki/Carl_Linnaeus), que organizou os animais em uma hierarquia.
1
O cogumelo Amanita phalloides, cujo nome popular em inglês é Death cap, foi traduzido para o nome popular em
português, Cicuta verde.

26 Chapter 1. Introdução
No caso da classificação animal, pode não ser tão ruim confundir um poodle (uma raça de ca-
chorro) com um schnauzer (outra raça de cachorro), mas nosso modelo pagaria uma grande pe-
nalidade se confundisse um poodle com um dinossauro. Qual hierarquia é relevante pode depen-
der sobre como você planeja usar o modelo. Por exemplo, cascavéis e cobras-liga podem estar
perto da árvore filogenética, mas confundir uma cascavel com uma cobra-liga pode ser mortal.

Tags

Alguns problemas de classificação se encaixam perfeitamente nas configurações de classificação


binária ou multiclasse. Por exemplo, podemos treinar um classificador binário normal para dis-
tinguir gatos de cães. Dado o estado atual da visão computacional, podemos fazer isso facil-
mente, com ferramentas disponíveis no mercado. No entanto, não importa o quão preciso seja
o nosso modelo, podemos ter problemas quando o classificador encontra uma imagem dos Músi-
cos da Cidade de Bremen, um conto de fadas alemão popular com quatro animais in: numref:
fig_stackedanimals.

Fig. 1.3.3: Um burro, um cachorro, um gato e um galo.

Como você pode ver, há um gato em: numref: fig_stackedanimals, e um galo, um cachorro e um
burro, com algumas árvores ao fundo. Dependendo do que queremos fazer com nosso modelo
em última análise, tratando isso como um problema de classificação binária pode não fazer muito
sentido. Em vez disso, podemos dar ao modelo a opção de dizer que a imagem retrata um gato,
um cachorro, um burro, e um galo.
O problema de aprender a prever classes que são não mutuamente exclusivas é chamado de clas-
sificação multi-rótulo. Os problemas de tags automáticas são geralmente mais bem descritos como

1.3. Tipos de Problemas de Machine Learning 27


problemas de classificação multi-rótulo. Pense nas tags que as pessoas podem aplicar a posta-
gens em um blog técnico, por exemplo, “machine learning”, “tecnologia”, “gadgets”, “linguagens de
programação”, “Linux”, “computação em nuvem”, “AWS”. Um artigo típico pode ter de 5 a 10 tags
aplicadas porque esses conceitos estão correlacionados. Postagens sobre “computação em nu-
vem” provavelmente mencionarão “AWS” e postagens sobre “machine learning” também podem
tratar de “linguagens de programação”.
Também temos que lidar com esse tipo de problema ao lidar com a literatura biomédica, onde
etiquetar corretamente os artigos é importante porque permite que os pesquisadores façam re-
visões exaustivas da literatura. Na National Library of Medicine, vários anotadores profissionais
revisam cada artigo que é indexado no PubMed para associá-lo aos termos relevantes do MeSH,
uma coleção de aproximadamente 28000 tags. Este é um processo demorado e o os anotadores
normalmente têm um atraso de um ano entre o arquivamento e a definição das tags. O machine
learning pode ser usado aqui para fornecer tags provisórias até que cada artigo possa ter uma
revisão manual adequada. Na verdade, por vários anos, a organização BioASQ tem [sediado con-
cursos] (http://bioasq.org/) para fazer exatamente isso.

Busca

Às vezes, não queremos apenas atribuir cada exemplo a um valor real. No campo da recuperação
de informações, queremos impor uma classificação a um conjunto de itens. Tome como exemplo
a pesquisa na web. O objetivo é menos determinar se uma página específica é relevante para uma
consulta, mas, em vez disso, qual dentre a infinidade de resultados de pesquisa é mais relevante
para um determinado usuário. Nós realmente nos preocupamos com a ordem dos resultados de
pesquisa relevantes e nosso algoritmo de aprendizagem precisa produzir subconjuntos ordena-
dos de elementos de um conjunto maior. Em outras palavras, se formos solicitados a produzir as
primeiras 5 letras do alfabeto, há uma diferença entre retornar “A B C D E” e “C A B E D”. Mesmo
que o conjunto de resultados seja o mesmo, a ordenação dentro do conjunto importa.
Uma possível solução para este problema é primeiro atribuir para cada elemento no conjunto uma
pontuação de relevância correspondente e, em seguida, para recuperar os elementos com melhor
classificação. [PageRank] (https://en.wikipedia.org/wiki/PageRank), o molho secreto original por
trás do mecanismo de pesquisa do Google foi um dos primeiros exemplos de tal sistema de pon-
tuação, mas foi peculiar por não depender da consulta real. Aqui, eles contaram com um filtro
de relevância simples para identificar o conjunto de itens relevantes e, em seguida, no PageRank
para ordenar esses resultados que continham o termo de consulta. Hoje em dia, os mecanismos de
pesquisa usam machine learning e modelos comportamentais para obter pontuações de relevância
dependentes de consulta. Existem conferências acadêmicas inteiras dedicadas a este assunto.

Sistemas de Recomendação

Os sistemas de recomendação são outra configuração de problema que está relacionado à pesquisa
e classificação. Os problemas são semelhantes na medida em que o objetivo é exibir um con-
junto de itens relevantes para o usuário. A principal diferença é a ênfase em personalização para
usuários específicos no contexto de sistemas de recomendação. Por exemplo, para recomen-
dações de filmes, a página de resultados para um fã de ficção científica e a página de resultados
para um conhecedor das comédias de Peter Sellers podem diferir significativamente. Problemas
semelhantes surgem em outras configurações de recomendação, por exemplo, para produtos de
varejo, música e recomendação de notícias.

28 Chapter 1. Introdução
Em alguns casos, os clientes fornecem feedback explícito comunicando o quanto eles gostaram de
um determinado produto (por exemplo, as avaliações e resenhas de produtos na Amazon, IMDb
e GoodReads). Em alguns outros casos, eles fornecem feedback implícito, por exemplo, pulando
títulos em uma lista de reprodução, o que pode indicar insatisfação, mas pode apenas indicar que a
música era inadequada no contexto. Nas formulações mais simples, esses sistemas são treinados
para estimar alguma pontuação, como uma avaliação estimada ou a probabilidade de compra,
dado um usuário e um item.
Dado esse modelo, para qualquer usuário, poderíamos recuperar o conjunto de objetos com as
maiores pontuações, que pode então ser recomendado ao usuário. Os sistemas de produção são
consideravelmente mais avançados e levam a atividade detalhada do usuário e características do
item em consideração ao computar essas pontuações. : numref: fig_deeplearning_amazon é um
exemplo de livros de deep learning recomendados pela Amazon com base em algoritmos de per-
sonalização ajustados para capturar as preferências de alguém.

Fig. 1.3.4: Livros de deep learning recomendados pela Amazon.

Apesar de seu enorme valor econômico, sistemas de recomendação ingenuamente construídos


em cima de modelos preditivos sofrem algumas falhas conceituais graves. Para começar, obser-
vamos apenas feedback censurado: os usuários avaliam preferencialmente os filmes que os consid-
eram fortes. Por exemplo, em uma escala de cinco pontos, você pode notar que os itens recebem
muitas classificações de cinco e uma estrela mas que existem visivelmente poucas avaliações de
três estrelas. Além disso, os hábitos de compra atuais são muitas vezes um resultado do algo-
ritmo de recomendação atualmente em vigor, mas os algoritmos de aprendizagem nem sempre
levam esse detalhe em consideração. Assim, é possível que se formem ciclos de feedback onde um
sistema de recomendação preferencialmente empurra um item que então é considerado melhor
(devido a maiores compras) e, por sua vez, é recomendado com ainda mais frequência. Muitos
desses problemas sobre como lidar com a censura, incentivos e ciclos de feedback são importantes

1.3. Tipos de Problemas de Machine Learning 29


questões abertas de pesquisa.

Aprendizagem sequencial

Até agora, vimos problemas em que temos algum número fixo de entradas a partir dos quais pro-
duzimos um número fixo de saídas. Por exemplo, consideramos prever os preços das casas a partir
de um conjunto fixo de recursos: metragem quadrada, número de quartos, número de banheiros,
tempo de caminhada até o centro. Também discutimos o mapeamento de uma imagem (de di-
mensão fixa) às probabilidades previstas de que pertence a cada de um número fixo de classes,
ou pegando um ID de usuário e um ID de produto, e prever uma classificação por estrelas. Nesses
casos, uma vez que alimentamos nossa entrada de comprimento fixo no modelo para gerar uma
saída, o modelo esquece imediatamente o que acabou de ver.
Isso pode ser bom se todas as nossas entradas realmente tiverem as mesmas dimensões e se as
entradas sucessivas realmente não têm nada a ver umas com as outras. Mas como lidaríamos com
trechos de vídeo? Nesse caso, cada fragmento pode consistir em um número diferente de quadros.
E nosso palpite sobre o que está acontecendo em cada quadro pode ser muito mais forte se levar-
mos em consideração os quadros anteriores ou posteriores. O mesmo vale para a linguagem. Um
problema popular de deep learning é tradução automática: a tarefa de ingerir frases em algum
idioma de origem e prevendo sua tradução em outro idioma.
Esses problemas também ocorrem na medicina. Podemos querer um modelo para monitorar
pacientes na unidade de terapia intensiva e disparar alertas se seus riscos de morte nas próximas
24 horas excederem algum limite. Definitivamente, não queremos que este modelo jogue fora
tudo o que sabe sobre o histórico do paciente a cada hora e apenas fazer suas previsões com base
nas medições mais recentes.
Esses problemas estão entre as aplicações mais interessantes de machine learning e são instâncias
de aprendizagem sequencial. Eles exigem um modelo para ingerir sequências de entradas ou para
emitir sequências de saídas (ou ambos). Especificamente, sequência para aprendizagem de sequen-
cial considera os problemas onde entrada e saída são sequências de comprimento variável, como
tradução automática e transcrição de texto da fala falada. Embora seja impossível considerar to-
dos os tipos de transformações de sequência, vale a pena mencionar os seguintes casos especiais.
Marcação e análise. Isso envolve anotar uma sequência de texto com atributos. Em outras
palavras, o número de entradas e saídas é essencialmente o mesmo. Por exemplo, podemos
querer saber onde estão os verbos e os sujeitos. Como alternativa, podemos querer saber quais
palavras são as entidades nomeadas. Em geral, o objetivo é decompor e anotar o texto com base
na estrutura e suposições gramaticais para obter algumas anotações. Isso parece mais complexo
do que realmente é. Abaixo está um exemplo muito simples de uma frase anotada com marcas
que indicam quais palavras se referem a entidades nomeadas (marcadas como “Ent”).

Tom has dinner in Washington with Sally


Ent - - - Ent - Ent

Reconhecimento automático de fala. Com o reconhecimento de fala, a sequência de entrada


é uma gravação de áudio de um alto-falante (mostrado em: numref: fig_speech), e a saída é a
transcrição textual do que o locutor disse. O desafio é que existem muito mais quadros de áudio (o
som é normalmente amostrado em 8kHz ou 16kHz) do que texto, ou seja, não há correspondência
1: 1 entre áudio e texto, já que milhares de amostras podem correspondem a uma única palavra
falada. Estes são problemas de aprendizagem de sequência a sequência em que a saída é muito
mais curta do que a entrada.

30 Chapter 1. Introdução
Fig. 1.3.5: -D-e-e-p- L-ea-r-ni-ng- in an audio recording.

Text to Speech (Texto para fala). Este é o inverso do reconhecimento automático de fala. Em
outras palavras, a entrada é um texto e a saída é um arquivo de áudio. Nesse caso, a saída é muito
mais longa do que a entrada. Embora seja fácil para os humanos reconhecerem um arquivo de
áudio ruim, isso não é tão trivial para computadores.
Tradução por máquina. Ao contrário do caso do reconhecimento de voz, onde correspondente
entradas e saídas ocorrem na mesma ordem (após o alinhamento), na tradução automática, a
inversão da ordem pode ser vital. Em outras palavras, enquanto ainda estamos convertendo uma
sequência em outra, nem o número de entradas e saídas, nem o pedido de exemplos de dados
correspondentes são considerados iguais. Considere o seguinte exemplo ilustrativo da tendência
peculiar dos alemães para colocar os verbos no final das frases.

German: Haben Sie sich schon dieses grossartige Lehrwerk angeschaut?


English: Did you already check out this excellent tutorial?
Wrong alignment: Did you yourself already this excellent tutorial looked-at?

Muitos problemas relacionados surgem em outras tarefas de aprendizagem. Por exemplo, de-
terminar a ordem em que um usuário lê uma página da web é um problema de análise de lay-
out bidimensional. Problemas de diálogo apresentam todos os tipos de complicações adicionais,
onde determinar o que dizer a seguir requer levar em consideração conhecimento do mundo real
e o estado anterior da conversa através de longas distâncias temporais. Estas são áreas ativas de
pesquisa.

1.3.2 Aprendizagem não-supervisionada

Todos os exemplos até agora foram relacionados à aprendizagem supervisionada, ou seja, situ-
ações em que alimentamos o modelo com um conjunto de dados gigante contendo os recursos e
os valores de rótulo correspondentes. Você pode pensar no aluno supervisionado como tendo um
trabalho extremamente especializado e um chefe extremamente banal. O chefe fica por cima do
seu ombro e lhe diz exatamente o que fazer em todas as situações até que você aprenda a mapear
as de situações para ações. Trabalhar para um chefe assim parece muito chato. Por outro lado,
é fácil agradar a esse chefe. Você apenas reconhece o padrão o mais rápido possível e imita suas
ações.
De uma forma completamente oposta, pode ser frustrante trabalhar para um chefe que não tem
ideia do que eles querem que você faça. No entanto, se você planeja ser um cientista de dados, é
melhor se acostumar com isso. O chefe pode simplesmente entregar a você uma pilha gigante de
dados e dizer para fazer ciência de dados com eles! Isso parece vago porque é. Chamamos essa classe
de problemas de aprendizagem não supervisionada, e o tipo e número de perguntas que podemos

1.3. Tipos de Problemas de Machine Learning 31


fazer é limitado apenas pela nossa criatividade. Abordaremos técnicas de aprendizado não super-
visionado nos capítulos posteriores. Para abrir seu apetite por enquanto, descrevemos algumas
das seguintes perguntas que você pode fazer.
• Podemos encontrar um pequeno número de protótipos que resumem os dados com pre-
cisão? Dado um conjunto de fotos, podemos agrupá-las em fotos de paisagens, fotos de ca-
chorros, bebês, gatos e picos de montanhas? Da mesma forma, dada uma coleção de ativi-
dades de navegação dos usuários, podemos agrupá-los em usuários com comportamento
semelhante? Esse problema é normalmente conhecido como clusterização.
• Podemos encontrar um pequeno número de parâmetros que capturam com precisão as pro-
priedades relevantes dos dados? As trajetórias de uma bola são muito bem descritas pela
velocidade, diâmetro e massa da bola. Os alfaiates desenvolveram um pequeno número
de parâmetros que descrevem a forma do corpo humano com bastante precisão com o
propósito de ajustar roupas. Esses problemas são chamados de estimativa de subespaço. Se a
dependência for linear, é chamada de análise de componentes principais (principal component
analysis — PCA).
• Existe uma representação de objetos (estruturados arbitrariamente) no espaço euclidiano
de modo que as propriedades simbólicas podem ser bem combinadas? Isso pode ser usado
para descrever entidades e suas relações, como “Roma” − “Itália” + “França” = “Paris”.
• Existe uma descrição das causas comuns de muitos dos dados que observamos? Por exem-
plo, se tivermos dados demográficos sobre preços de casas, poluição, crime, localização,
educação e salários, podemos descobrir como eles estão relacionados simplesmente com
base em dados empíricos? Os campos relacionados com causalidade e modelos gráficos prob-
abilísticos resolvem este problema.
• Outro importante e empolgante desenvolvimento recente na aprendizagem não supervi-
sionada é o advento de redes adversárias geradoras. Isso nos dá uma maneira processual de
sintetizar dados, até mesmo dados estruturados complicados, como imagens e áudio. Os
mecanismos estatísticos subjacentes são testes para verificar se os dados reais e falsos são
iguais.

1.3.3 Interagindo com um Ambiente

Até agora, não discutimos de onde os dados realmente vêm, ou o que realmente acontece quando
um modelo de machine learning gera uma saída. Isso ocorre porque o aprendizado supervisionado
e o aprendizado não supervisionado não tratam dessas questões de uma forma muito sofisticada.
Em qualquer caso, pegamos uma grande pilha de dados antecipadamente, em seguida, colocamos
nossas máquinas de reconhecimento de padrões em movimento sem nunca mais interagir com
o ambiente novamente. Porque todo o aprendizado ocorre depois que o algoritmo é desconec-
tado do ambiente, isso às vezes é chamado de aprendizagem offline. Para aprendizagem super-
visionada, o processo considerando a coleta de dados de um ambiente se parece com: numref:
fig_data_collection.

32 Chapter 1. Introdução
Fig. 1.3.6: Collecting data for supervised learning from an environment.

Esta simplicidade de aprendizagem offline tem seus encantos. A vantagem é que podemos nos
preocupar com o reconhecimento de padrões isoladamente, sem qualquer distração desses out-
ros problemas. Mas a desvantagem é que a formulação do problema é bastante limitadora. Se
você é mais ambicioso, ou se cresceu lendo a série Robot de Asimov, então você pode imaginar
bots com inteligência artificial, capazes não só de fazer previsões, mas também de realizar ações
no mundo. Queremos pensar em agentes inteligentes, não apenas em modelos preditivos. Isso
significa que precisamos pensar sobre como escolher ações, não apenas fazendo previsões. Além
disso, ao contrário das previsões, ações realmente impactam o meio ambiente. Se quisermos
treinar um agente inteligente, devemos levar em conta a maneira como suas ações podem im-
pactar as observações futuras do agente.
Considerando a interação com um ambiente abre todo um conjunto de novas questões de mode-
lagem. A seguir estão apenas alguns exemplos.
• O ambiente lembra o que fizemos anteriormente?
• O ambiente quer nos ajudar, por exemplo, um usuário lendo texto em um reconhecedor de
fala?
• O ambiente quer nos derrotar, ou seja, um ambiente adversário, como filtragem de spam
(contra spammers) ou um jogo (contra um oponente)?
• O ambiente não se preocupa?
• O ambiente tem mudanças dinâmicas? Por exemplo, os dados futuros sempre se parecem
com o passado ou os padrões mudam com o tempo, naturalmente ou em resposta às nossas
ferramentas automatizadas?
Esta última questão levanta o problema de mudança de distribuição, quando os dados de treina-
mento e teste são diferentes. É um problema que a maioria de nós já experimentou ao fazer ex-
ames escritos por um professor, enquanto a lição de casa foi composta por seus assistentes de
ensino. A seguir, descreveremos brevemente o aprendizado por reforço, uma configuração que
considera explicitamente as interações com um ambiente.

1.3. Tipos de Problemas de Machine Learning 33


1.3.4 Aprendizado por Reforço

Se você estiver interessado em usar o machine learning para desenvolver um agente que interaja
com um ambiente e tome medidas, então você provavelmente vai acabar com foco na aprendiza-
gem por reforço. Isso pode incluir aplicações para robótica, para sistemas de diálogo, e até mesmo
para desenvolver inteligência artificial (IA) para videogames. Aprendizagem por reforço profundo,
que se aplica deep learning para problemas de aprendizagem de reforço, aumentou em populari-
dade. A revolucionária deep Q-netfowk que derrotou os humanos nos jogos da Atari usando apenas
a entrada visual, e o programa AlphaGo que destronou o campeão mundial no jogo de tabuleiro
Go são dois exemplos proeminentes.
A aprendizagem por reforço fornece uma declaração muito geral de um problema, em que um
agente interage com um ambiente ao longo de uma série de etapas de tempo. Em cada etapa de
tempo, o agente recebe alguma observação do ambiente e deve escolher uma ação que é posterior-
mente transmitido de volta para o ambiente por meio de algum mecanismo (às vezes chamado de
atuador). Por fim, o agente recebe uma recompensa do meio ambiente. Este processo é ilustrado
em: numref: fig_rl-environment. O agente então recebe uma observação subsequente, e escolhe
uma ação subsequente e assim por diante. O comportamento de um agente de aprendizagem por
reforço é governado por uma política. Em suma, uma política é apenas uma função que mapeia
das observações do ambiente às ações. O objetivo da aprendizagem por reforço é produzir uma
boa política.

Fig. 1.3.7: The interaction between reinforcement learning and an environment.

É difícil exagerar a generalidade da estrutura de aprendizagem por reforço. Por exemplo, pode-
mos lançar qualquer problema de aprendizado supervisionado como um problema de apren-
dizado por reforço. Digamos que tenhamos um problema de classificação. Poderíamos criar um
agente de aprendizagem por reforço com uma ação correspondente a cada classe. Poderíamos
então criar um ambiente que oferecesse uma recompensa que era exatamente igual à função de
perda do problema original de aprendizagem supervisionada.
Dito isso, o aprendizado por reforço também pode resolver muitos problemas que a aprendizagem
supervisionada não pode. Por exemplo, na aprendizagem supervisionada, sempre esperamos se
a entrada de treinamento venha associada ao label correto. Mas na aprendizagem por reforço,
não assumimos que para cada observação o ambiente nos diz a ação ideal. Em geral, apenas
recebemos alguma recompensa. Além disso, o ambiente pode nem mesmo nos dizer quais ações
levaram à recompensa.
Considere, por exemplo, o jogo de xadrez. O único sinal de recompensa real vem no final do
jogo quando ganhamos, o que podemos atribuir a uma recompensa de 1, ou quando perdemos,
o que podemos atribuir uma recompensa de -1. Assim, os agentes de reforço devem lidar com
o problema de atribuição de crédito: determinar quais ações devem ser creditadas ou culpadas

34 Chapter 1. Introdução
por um resultado. O mesmo vale para o funcionário que for promovido no dia 11 de outubro.
Essa promoção provavelmente reflete um grande número de ações bem escolhidas em relação ao
ano anterior. Para obter mais promoções no futuro, é preciso descobrir quais ações ao longo do
caminho levaram à promoção.
Agentes de aprendizado por reforço também podem ter que lidar com o problema da observabil-
idade parcial. Ou seja, a observação atual pode não dizer-lhe tudo sobre o seu estado atual. Dig-
amos que um robô de limpeza ficou preso em um dos muitos armários idênticos em uma casa.
Inferindo a localização precisa (e, portanto, o estado) do robô pode exigir a consideração de suas
observações anteriores antes de entrar no armário.
Finalmente, em qualquer ponto, os agentes de reforço podem saber de uma boa política, mas
pode haver muitas outras políticas melhores que o agente nunca tentou. O agente de reforço deve
escolher constantemente se deve fazer um exploit com a melhor estratégia atualmente conhecida
como uma política, ou um explore o espaço das estratégias, potencialmente desistindo de alguma
recompensa de curto prazo em troca de conhecimento.
O problema geral de aprendizagem por reforço é uma configuração muito geral. As ações afetam
as observações subsequentes. As recompensas só são observadas correspondendo às ações escol-
hidas. O ambiente pode ser total ou parcialmente observado. Levar em conta toda essa complex-
idade de uma vez pode exigir muito dos pesquisadores. Além disso, nem todo problema prático
exibe toda essa complexidade. Como resultado, os pesquisadores estudaram uma série de casos
especiais de problemas de aprendizagem por reforço.
Quando o ambiente é totalmente observado, chamamos o problema de aprendizagem por reforço
de processo de decisão Markov. Quando o estado não depende das ações anteriores, chamamos o
problema de problema de bandido contextual. Quando não há estado, apenas um conjunto de ações
disponíveis com recompensas inicialmente desconhecidas, este problema é o clássico problema de
bandidos multi-armados.

1.4 Raízes

Acabamos de revisar um pequeno subconjunto de problemas que o machine learning pode abor-
dar. Para um conjunto diversificado de problemas de machine learning, o deep learning fornece
ferramentas poderosas para resolvê-los. Embora muitos métodos de deep learning são invenções
recentes, a ideia central da programação com dados e redes neurais (nomes de muitos modelos
de deep learning) tem sido estudado há séculos. Na verdade, os humanos mantiveram o desejo de
analisar dados e para prever resultados futuros por muito tempo e muito da ciência natural tem
suas raízes nisso. Por exemplo, a distribuição Bernoulli é nomeada após [Jacob Bernoulli (1655–
1705)] (https://en.wikipedia.org/wiki/Jacob_Bernoulli), e a distribuição gaussiana foi descoberta
por [Carl Friedrich Gauss (1777–1855)] (https://en.wikipedia.org/wiki/Carl_Friedrich_Gauss). Ele
inventou, por exemplo, o algoritmo de mínimos quadrados médios, que ainda é usado hoje para
inúmeros problemas de cálculos de seguros a diagnósticos médicos. Essas ferramentas deram
origem a uma abordagem experimental nas ciências naturais — por exemplo, a lei de Ohm rela-
cionar corrente e tensão em um resistor é perfeitamente descrito por um modelo linear.,
Mesmo na Idade Média, os matemáticos tinham uma aguçada intuição de estimativas. Por exem-
plo, o livro de geometria de [Jacob Köbel (1460–1533)] (https://www.maa.org/press/periodicals/
convergence/mathematical-treasures-jacob-kobels-geometry) ilustra calculando a média do
comprimento de 16 pés de homens adultos para obter o comprimento médio do pé.

1.4. Raízes 35
Fig. 1.4.1: Estimating the length of a foot.

numref fig_koebel ilustra como este estimador funciona. Os 16


homens adultos foram convidados a fazer fila em uma fila, ao deixar a igreja. Seu comprimento
agregado foi então dividido por 16 para obter uma estimativa do que agora equivale a 1 pé. Este
“algoritmo” foi melhorado mais tarde para lidar com pés deformados — os 2 homens com os pés
mais curtos e os mais longos, respectivamente, foram mandados embora, calculando a média
apenas sobre o restante. Este é um dos primeiros exemplos da estimativa média aparada.
As estatísticas realmente decolaram com a coleta e disponibilização de dados. Um de seus titãs,
[Ronald Fisher (1890–1962)] (https://en.wikipedia.org/wiki/Ronald_Fisher), contribuiu significati-
vamente para sua teoria e também suas aplicações em genética. Muitos de seus algoritmos (como
a análise discriminante linear) e fórmula (como a matriz de informações de Fisher) ainda estão
em uso frequente hoje. Na verdade, até mesmo o conjunto de dados Iris que Fisher lançou em
1936 ainda é usado às vezes para ilustrar algoritmos de aprendizado de máquina. Ele também era
um defensor da eugenia, o que deve nos lembrar que o uso moralmente duvidoso da ciência de da-
dos tem uma história tão longa e duradoura quanto seu uso produtivo na indústria e nas ciências
naturais.
Uma segunda influência para o machine learning veio da teoria da informação por [Claude Shannon
(1916–2001)] (https://en.wikipedia.org/wiki/Claude_Shannon) e a teoria da computação via [Alan
Turing (1912–1954)] (https://en.wikipedia. org / wiki / Alan_Turing). Turing colocou a questão
“podem as máquinas pensar?” em seu famoso artigo Computing Machinery and Intelligence :cite:
Turing.1950. No que ele descreveu como o teste de Turing, uma máquina pode ser considerada
inteligente se for difícil para um avaliador humano distinguir entre as respostas de uma máquina
e um humano com base em interações textuais.
Outra influência pode ser encontrada na neurociência e na psicologia. Afinal, os humanos ex-
ibem claramente um comportamento inteligente. Portanto, é razoável perguntar se alguém

36 Chapter 1. Introdução
poderia explicar e possivelmente fazer engenharia reversa dessa capacidade. Um dos algorit-
mos mais antigos inspirados nesta moda foi formulado por [Donald Hebb (1904–1985)] (https:
//en.wikipedia.org/wiki/Donald_O._Hebb). Em seu livro inovador The Organization of Behavior
:cite: Hebb.Hebb.1949, ele postulou que os neurônios aprendem por reforço positivo. Isso ficou
conhecido como a regra de aprendizado Hebbian. É o protótipo do algoritmo de aprendizagem
perceptron de Rosenblatt e lançou as bases de muitos algoritmos de gradiente descendente es-
tocástico que sustentam o deep learning hoje: reforçar o comportamento desejável e diminuir o
comportamento indesejável para obter boas configurações dos parâmetros em uma rede neural.
Inspiração biológica é o que deu às redes neurais seu nome. Por mais de um século (que remonta
aos modelos de Alexander Bain, 1873 e James Sherrington, 1890), os pesquisadores tentaram re-
unir circuitos computacionais que se assemelham a redes de neurônios em interação. Com o
tempo, a interpretação da biologia tornou-se menos literal mas o nome pegou. Em sua essência,
encontram-se alguns princípios-chave que podem ser encontrados na maioria das redes hoje:
• A alternância de unidades de processamento linear e não linear, geralmente chamadas de
camadas.
• O uso da regra da cadeia (também conhecida como retropropagação) para ajustar parâmetros
em toda a rede de uma só vez.
Após o rápido progresso inicial, pesquisa em redes neurais definhou de cerca de 1995 até 2005.
Isso se deveu principalmente a dois motivos. Primeiro, treinar uma rede é muito caro do ponto
de vista computacional. Embora a memória de acesso aleatório fosse abundante no final do século
passado, o poder computacional era escasso. Em segundo lugar, os conjuntos de dados eram rel-
ativamente pequenos. Na verdade, o conjunto de dados Iris de Fisher de 1932 foi uma ferramenta
popular para testar a eficácia de algoritmos. O conjunto de dados MNIST com seus 60.000 dígitos
manuscritos foi considerado enorme.
Dada a escassez de dados e computação, ferramentas estatísticas fortes, como métodos de kernel,
árvores de decisão e modelos gráficos mostraram-se empiricamente superiores. Ao contrário das
redes neurais, eles não levaram semanas para treinar e forneceu resultados previsíveis com fortes
garantias teóricas.

1.5 O Caminho Para o Deep Learning

Muito disso mudou com a pronta disponibilidade de grandes quantidades de dados, devido à
World Wide Web, o advento das empresas servindo centenas de milhões de usuários online, uma
disseminação de sensores baratos e de alta qualidade, armazenamento de dados barato (lei de
Kryder), e computação barata (lei de Moore), em particular na forma de GPUs, originalmente
projetadas para jogos de computador. De repente, algoritmos e modelos que pareciam inviáveis
computacionalmente tornaram-se relevante (e vice-versa). Isso é melhor ilustrado em: num-
ref:tab_intro_decade.
:Dataset vs. memória do computador e poder computacional

1.5. O Caminho Para o Deep Learning 37


Table 1.5.1: label:tab_intro_decade
Dé- Dataset Memória Cálculos de Floats por Se-
cada gundo
1970 100 (Iris) 1 KB 100 KF (Intel 8080)
1980 1 K (Preço de casas em Boston) 100 KB 1 MF (Intel 80186)
1990 10 K (reconhecimento óptico de carac- 10 MB 10 MF (Intel 80486)
teres)
2000 10 M (páginas web) 100 MB 1 GF (Intel Core)
2010 10 G (anúncios) 1 GB 1 TF (Nvidia C2050)
2020 1 T (redes sociais) 100 GB 1 PF (Nvidia DGX-2)

É evidente que a memória RAM não acompanhou o crescimento dos dados. Ao mesmo tempo, o
aumento do poder computacional ultrapassou o dos dados disponíveis. Isso significa que os mod-
elos estatísticos precisam se tornar mais eficientes em termos de memória (isso normalmente
é obtido adicionando não linearidades) ao mesmo tempo em que pode passar mais tempo na
otimização desses parâmetros, devido ao aumento do orçamento computacional. Consequente-
mente, o ponto ideal em machine learning e estatísticas mudou de modelos lineares (generaliza-
dos) e métodos de kernel para redes neurais profundas. Esta é também uma das razões pelas quais
muitos dos pilares de deep learning, como perceptrons multicamadas (McCulloch & Pitts, 1943),
redes neurais convolucionais (LeCun et al., 1998), memória longa de curto prazo (Hochreiter &
Schmidhuber, 1997), e Q-Learning (Watkins & Dayan, 1992), foram essencialmente “redescober-
tos” na última década, depois de ficarem relativamente dormentes por um tempo considerável.
O progresso recente em modelos estatísticos, aplicativos e algoritmos às vezes é comparado à ex-
plosão cambriana: um momento de rápido progresso na evolução das espécies. Na verdade, o
estado da arte não é apenas uma mera consequência de recursos disponíveis, aplicados a algorit-
mos de décadas. Observe que a lista abaixo mal arranha a superfície das ideias que ajudaram os
pesquisadores a alcançar um progresso tremendo na última década.
• Novos métodos de controle de capacidade, como dropout (Srivastava et al., 2014), ajudaram a
mitigar o perigo de overfitting. Isso foi conseguido aplicando injeção de ruído (Bishop, 1995)
em toda a rede neural, substituindo pesos por variáveis aleatórias para fins de treinamento.
• Mecanismos de atenção resolveram um segundo problema que atormentou as estatísticas
por mais de um século: como aumentar a memória e a complexidade de um sistema sem au-
mentar o número de parâmetros aprendíveis. Os pesquisadores encontraram uma solução
elegante usando o que só pode ser visto como uma estrutura de ponteiro aprendível (Bah-
danau et al., 2014). Em vez de ter que lembrar uma sequência de texto inteira, por exemplo,
para tradução automática em uma representação de dimensão fixa, tudo o que precisava
ser armazenado era um ponteiro para o estado intermediário do processo de tradução. Isso
permitiu significativamente maior precisão para sequências longas, uma vez que o modelo
não precisa mais lembrar de toda a sequência antes de começar a geração de uma nova se-
quência.
• Projetos de vários estágios, por exemplo, por meio das redes de memória (Sukhbaatar et
al., 2015) e o programador-intérprete neural:cite:Reed.De-Freitas.2015 permitiram mode-
ladores estatísticos para descrever abordagens iterativas de raciocínio. Essas ferramentas
permitem um estado interno da rede neural profunda a ser modificado repetidamente, real-
izando assim as etapas subsequentes em uma cadeia de raciocínio, semelhante a como um
processador pode modificar a memória para um cálculo.
• Outro desenvolvimento importante foi a invenção de redes adversárias geradoras (Goodfel-

38 Chapter 1. Introdução
low et al., 2014). Tradicionalmente, os métodos estatísticos para estimativa de densidade
e modelos generativos focados em encontrar distribuições de probabilidade adequadas e
algoritmos (geralmente aproximados) para amostragem deles. Como resultado, esses algo-
ritmos foram amplamente limitados pela falta de flexibilidade inerente aos modelos estatís-
ticos. A inovação crucial nas redes adversárias geradoras foi substituir o amostrador por
um algoritmo arbitrário com parâmetros diferenciáveis. Estes são ajustados de tal forma
que o discriminador (efetivamente um teste de duas amostras) não consegue distinguir da-
dos falsos de dados reais. Através da capacidade de usar algoritmos arbitrários para gerar
dados, abriu-se a estimativa de densidade para uma ampla variedade de técnicas. Exemplos
de Zebras galopando (Zhu et al., 2017) e de rostos falsos de celebridades (Karras et al., 2017)
são ambos testemunhos desse progresso. Até mesmo doodlers amadores podem produzir
imagens fotorrealísticas baseadas apenas em esboços que descrevem como o layout de uma
cena se parece (Park et al., 2019).
• Em muitos casos, uma única GPU é insuficiente para processar a grande quantidade de da-
dos disponíveis para treinamento. Na última década, a capacidade de construir paralelos
e algoritmos de treinamento distribuído melhoraram significativamente. Um dos princi-
pais desafios no projeto de algoritmos escalonáveis é a força motriz da otimização de deep
learning, o gradiente descendente estocástico, depende de pequenos minibatches de dados
a serem processados. Ao mesmo tempo, pequenos batches limitam a eficiência das GPUs.
Portanto, o treinamento em 1024 GPUs com um tamanho de minibatch de, digamos que 32
imagens por batch equivale a um minibatch agregado de cerca de 32.000 imagens. Trabal-
hos recentes, primeiro de Li (Li, 2017), e posteriormente por (You et al., 2017) e (Jia et al.,
2018) aumentaram o tamanho para 64.000 observações, reduzindo o tempo de treinamento
do modelo ResNet-50 no dataset ImageNet para menos de 7 minutos. Para comparação —
inicialmente os tempos de treinamento foram medidos na ordem de dias.
• A capacidade de paralelizar a computação também contribuiu de maneira crucial para pro-
gredir na aprendizagem por reforço, pelo menos sempre que a simulação é uma opção. Isso
levou a um progresso significativo na obtenção de desempenho sobre-humano em Go, jogos
Atari, Starcraft e em física simulações (por exemplo, usando MuJoCo). Veja, por exemplo,
(Silver et al., 2016) para uma descrição de como conseguir isso no AlphaGo. Em poucas
palavras, o aprendizado por reforço funciona melhor se muitas tuplas (estado, ação, recom-
pensa) estiverem disponíveis, ou seja, sempre que for possível experimentar muitas coisas
para aprender como elas se relacionam com cada outra. A simulação fornece esse caminho.
• Frameworks de deep learning têm desempenhado um papel crucial na disseminação de ideias.
A primeira geração de frameworks permitindo fácil modelagem englobava Caffe8 , Torch9 , e
Theano10 . Muitos artigos seminais foram escritos usando essas ferramentas. Até agora, eles
foram substituídos por TensorFlow11 (frequentemente usado por meio de sua API de alto
nível [Keras] (https://github.com/keras-team/keras)), CNTK12 , Caffe 213 e Apache MXNet14 .
A terceira geração de ferramentas, ou seja, ferramentas imperativas para deep learning, foi
provavelmente liderada por Chainer15 , que usava uma sintaxe semelhante a Python NumPy
para descrever modelos. Esta ideia foi adotada por ambos PyTorch16 , a Gluon API17 da
8
https://github.com/BVLC/caffe
9
https://github.com/torch
10
https://github.com/Theano/Theano
11
https://github.com/tensorflow/tensorflow
12
https://github.com/Microsoft/CNTK
13
https://github.com/caffe2/caffe2
14
https://github.com/apache/incubator-mxnet
15
https://github.com/chainer/chainer
16
https://github.com/pytorch/pytorch
17
https://github.com/apache/incubator-mxnet

1.5. O Caminho Para o Deep Learning 39


MXNet e Jax18 .
A divisão de trabalho entre os pesquisadores do sistema construindo melhores ferramentas e
modeladores estatísticos construindo melhores redes neurais simplificou muito as coisas. Por
exemplo, treinar um modelo de regressão linear logística costumava ser um problema de lição
de casa não trivial, digno de dar aos novos alunos de Ph.D. em machine learning da Carnegie Mel-
lon University em 2014. Agora, esta tarefa pode ser realizada com menos de 10 linhas de código,
colocando-a firmemente nas mãos dos programadores.

1.6 Histórias de Sucesso

A IA tem uma longa história de entrega de resultados que seriam difíceis de realizar de outra
forma. Por exemplo, os sistemas de classificação de correio usando reconhecimento óptico de
caracteres foram implantados desde a década de 1990. Afinal, essa é a fonte do famoso dataset
MNIST de dígitos manuscritos. O mesmo se aplica à leitura de cheques para depósitos bancários e
pontuação de crédito para clientes. As transações financeiras são verificadas em busca de fraudes
automaticamente. Isso forma a espinha dorsal de muitos sistemas de pagamento de comércio
eletrônico, como PayPal, Stripe, AliPay, WeChat, Apple, Visa e MasterCard. Os programas de
computador para xadrez são competitivos há décadas. O machine learning alimenta pesquisa, re-
comendação, personalização e classificação na Internet. Em outras palavras, o machine learning
é difundido, embora muitas vezes oculto à vista.
Só recentemente é que a IA tem estado no centro das atenções, principalmente devido a soluções
para problemas que foram considerados intratáveis anteriormente e que estão diretamente rela-
cionados aos consumidores. Muitos desses avanços são atribuídos ao machine learning.
• Assistentes inteligentes, como Siri da Apple, Alexa da Amazon e do Google assistente, são ca-
pazes de responder a perguntas faladas com um grau razoável de precisão. Isso inclui tarefas
servis, como ligar interruptores de luz (uma bênção para os deficientes), marcar compro-
missos com o barbeiro e oferecer suporte por telefone. Este é provavelmente o sinal mais
perceptível de que a IA está afetando nossas vidas.
• Um ingrediente importante nos assistentes digitais é a capacidade de reconhecer a fala com
precisão. Gradualmente, a precisão de tais sistemas aumentou ao ponto onde eles alcançam
a paridade humana com certas aplicações (Xiong et al., 2018).
• O reconhecimento de objetos também percorreu um longo caminho. Estimando o objeto
em uma imagem foi uma tarefa bastante desafiadora em 2010. No benchmark ImageNet,
pesquisadores da NEC Labs e da Universidade de Illinois em Urbana-Champaign alcançaram
uma taxa de erro de 28%, entre os 5 primeiros (Lin et al., 2010). Em 2017, esta taxa de erro
foi reduzida para 2,25% (Hu et al., 2018). Da mesma forma, deslumbrante resultados foram
alcançados para a identificação de aves ou diagnóstico de câncer de pele.
• Os jogos costumavam ser um bastião da inteligência humana. Começando com TD-
Gammon, um programa para jogar gamão usando aprendizagem de reforço de diferença
temporal, progresso algorítmico e computacional levou a algoritmos para uma ampla gama
de aplicações. Ao contrário do gamão, o xadrez tem um espaço de estados e um conjunto
de ações muito mais complexos. DeepBlue venceu Garry Kasparov usando paralelismo mas-
sivo, hardware para fins especiais e busca eficiente na árvore do jogo (Campbell et al., 2002).
Go é ainda mais difícil, devido ao seu enorme espaço de estados. AlphaGo atingiu a pari-
dade humana em 2015, usando deep learning combinado com amostragem de árvore Monte
18
https://github.com/google/jax

40 Chapter 1. Introdução
Carlo (Silver et al., 2016). O desafio no Poker era que o espaço de estados é grande e não é
totalmente observado (não conhecemos as cartas dos oponentes). Libratus excedeu o de-
sempenho humano no Poker usando de forma eficiente estratégias estruturadas (Brown &
Sandholm, 2017). Isso ilustra o progresso impressionante nos jogos e o fato de que algorit-
mos avançados desempenharam um papel crucial neles.
• Outra indicação de progresso na IA é o advento dos carros autônomos e caminhões. Emb-
ora a autonomia total ainda não esteja totalmente ao nosso alcance, excelente progresso foi
feito nesta direção, com empresas como Tesla, NVIDIA, e Waymo enviando produtos que
permitem pelo menos uma autonomia parcial. O que torna a autonomia total tão desafi-
adora é que a direção adequada requer a habilidade de perceber, raciocinar e incorporar
regras em um sistema. No momento, o deep learning é usado principalmente no aspecto de
visão computacional desses problemas. O resto é intensamente ajustado por engenheiros.
Novamente, a lista acima apenas arranha a superfície de onde o machine learning afetou os aplica-
tivos práticos. Por exemplo, robótica, logística, biologia computacional, física de partículas e as-
tronomia devem alguns de seus avanços recentes mais impressionantes, pelo menos em partes,
ao machine learning. O machine learning está se tornando uma ferramenta onipresente para en-
genheiros e cientistas.
Freqüentemente, a questão do apocalipse da IA, ou a singularidade da IA foi levantado em artigos
não técnicos sobre IA. O medo é que, de alguma forma, os sistemas de machine learning se tornarão
sensíveis e decidirão independentemente de seus programadores (e mestres) sobre coisas que
afetam diretamente o sustento dos humanos. Até certo ponto, a IA já afeta a vida dos humanos
de forma imediata: a qualidade de crédito é avaliada automaticamente, os pilotos automáticos
navegam veículos sozinhos, decisões sobre se deve conceder fiança, usam dados estatísticos como
entrada. Mais levianamente, podemos pedir a Alexa que ligue a máquina de café.
Felizmente, estamos longe de um sistema inteligente de IA que esteja pronto para manipular seus
criadores humanos (ou queimar seu café). Em primeiro lugar, os sistemas de IA são projetados,
treinados e implantados de uma forma específica, maneira orientada para o objetivo. Embora seu
comportamento possa dar a ilusão de inteligência geral, é uma combinação de regras, heurísticas
e modelos estatísticos que fundamentam o design. Em segundo lugar, dentre as ferramentas para
inteligência artificial geral atuais, simplesmente não existem aquelas que são capazes de se melho-
rar, raciocinar sobre si mesmos, e que são capazes de modificar, estender e melhorar sua própria
arquitetura ao tentar resolver tarefas gerais.
Uma preocupação muito mais urgente é como a IA está sendo usada em nossas vidas diárias.
É provável que muitas tarefas servis realizadas por motoristas de caminhão e os assistentes de
loja podem e serão automatizados. Robôs agrícolas provavelmente reduzirão o custo da agricul-
tura orgânica e também automatizarão as operações de colheita. Esta fase da revolução indus-
trial pode ter consequências profundas em grandes segmentos da sociedade, já que motoristas de
caminhão e assistentes de loja são alguns dos empregos mais comuns em muitos países. Além
disso, os modelos estatísticos, quando aplicados sem cuidado pode levar a preconceitos raciais,
de gênero ou idade e aumentar preocupações razoáveis sobre justiça processual se automatizados
para conduzir decisões consequentes. É importante garantir que esses algoritmos sejam usados
com cuidado. Com o que sabemos hoje, isso nos causa uma preocupação muito mais premente
do que o potencial da superinteligência malévola para destruir a humanidade.

1.6. Histórias de Sucesso 41


1.7 Características

Até agora, falamos sobre machine learning de maneira ampla, que é tanto um ramo da IA quanto
uma abordagem da IA. Embora o deep learning seja um subconjunto do machine learning, o con-
junto estonteante de algoritmos e aplicativos torna difícil avaliar quais podem ser os ingredientes
específicos para o deep learning. Isso é tão difícil quanto tentar definir os ingredientes necessários
para a pizza, uma vez que quase todos os componentes são substituíveis.
Como descrevemos, o machine learning pode usar dados para aprender as transformações entre
entradas e saídas, como a transformação de áudio em texto no reconhecimento de fala. Ao fazer
isso, muitas vezes é necessário representar os dados de uma forma adequada para que os algorit-
mos transformem essas representações na saída. Deep learning é profundo exatamente no sentido
que seus modelos aprendem muitas camadas de transformações, onde cada camada oferece a rep-
resentação em um nível. Por exemplo, camadas perto da entrada podem representar detalhes de
baixo nível dos dados, enquanto as camadas mais próximas da saída de classificação pode rep-
resentar conceitos mais abstratos usados para discriminação. Uma vez que aprendizagem de rep-
resentação visa encontrar a própria representação, o deep learning pode ser referido como apren-
dizagem de representação multinível.
Os problemas que discutimos até agora, como aprendizagem do sinal de áudio bruto, os valores
de pixel brutos das imagens, ou mapeamento entre sentenças de comprimentos arbitrários e suas
contrapartes em línguas estrangeiras, são aqueles onde o deep learning se destaca e onde os méto-
dos tradicionais de machine learning vacilam. Acontece que esses modelos de várias camadas são
capazes de abordar dados perceptivos de baixo nível de uma forma que as ferramentas anteriores
não conseguiam. Indiscutivelmente, a semelhança mais significativa em métodos de deep learn-
ing é o uso de treinamento ponta a ponta. Ou seja, ao invés de montar um sistema baseado em
componentes que são ajustados individualmente, constrói-se o sistema e então ajusta seu desem-
penho em conjunto. Por exemplo, em visão computacional, os cientistas costumavam separar
o processo de engenharia de recursos do processo de construção de modelos de aprendizado de
máquina. O detector de bordas Canny (Canny, 1987) e o extrator de recursos SIFT de Lowe (Lowe,
2004) reinou supremo por mais de uma década como algoritmo para mapear imagens em vetores
de recursos. No passado, a parte crucial de aplicar o machine learning a esses problemas consistia
em criar métodos de engenharia manual para transformar os dados em alguma forma receptiva
a modelos superficiais. Infelizmente, há muito pouco que os humanos possam realizar com en-
genhosidade em comparação com uma avaliação consistente de milhões de escolhas realizadas
automaticamente por um algoritmo. Quando o deep learning surgiu, esses extratores de recursos
foram substituídos por filtros ajustados automaticamente, produzindo uma precisão superior.
Por isso, uma das principais vantagens do deep learning é que ele não substitui apenas os modelos
rasos no final dos canais de aprendizagem tradicionais, mas também o processo intensivo de mão-
de-obra de engenharia de recursos. Além disso, ao substituir grande parte do pré-processamento
específico do domínio, o deep learning eliminou muitos dos limites que antes separavam a visão
computacional, o reconhecimento de fala, processamento de linguagem natural, informática
médica e outras áreas de aplicação, oferecendo um conjunto unificado de ferramentas para lidar
com diversos problemas.
Além do treinamento de ponta a ponta, estamos experimentando uma transição de descrições
estatísticas paramétricas para modelos totalmente não paramétricos. Quando os dados são es-
cassos, é necessário confiar na simplificação de suposições sobre a realidade para obter modelos
úteis. Quando os dados são abundantes, eles podem ser substituídos por modelos não paramétri-
cos que se ajustam à realidade com mais precisão. Até certo ponto, isso reflete o progresso que a
física experimentou em meados do século anterior com a disponibilidade de computadores. Em

42 Chapter 1. Introdução
vez de resolver aproximações paramétricas de como os elétrons se comportam manualmente,
pode-se agora recorrer a simulações numéricas das equações diferenciais parciais associadas.
Isso levou a modelos muito mais precisos, embora muitas vezes às custas da explicabilidade.
Outra diferença em relação ao trabalho anterior é a aceitação de soluções sub-ótimas, lidar com
problemas de otimização não-linear não convexa e a disposição de tentar coisas antes de prová-
las. Esse empirismo recém-descoberto ao lidar com problemas estatísticos, combinado com um
rápido influxo de talentos, levou a um rápido progresso de algoritmos práticos, embora em muitos
casos às custas de modificar e reinventar ferramentas que existiram por décadas.
No final, a comunidade de aprendizagem profunda se orgulha de compartilhar ferramentas além
das fronteiras acadêmicas e corporativas, lançando muitas bibliotecas excelentes, modelos es-
tatísticos e redes treinadas como código aberto. É com esse espírito que os notebooks que com-
põem este livro estão disponíveis gratuitamente para distribuição e uso. Trabalhamos muito para
reduzir as barreiras de acesso para que todos aprendam sobre o deep learning e esperamos que
nossos leitores se beneficiem com isso.

1.8 Resumo

• O machine learning estuda como os sistemas de computador podem aproveitar a experiência


(geralmente dados) para melhorar o desempenho em tarefas específicas. Ele combina ideias
de estatísticas, mineração de dados e otimização. Frequentemente, é usado como meio de
implementação de soluções de IA.
• Como uma classe de machine learning, o aprendizado representacional se concentra em
como encontrar automaticamente a maneira apropriada de representar os dados. Deep
learning é a aprendizagem de representação em vários níveis através do aprendizado de
muitas camadas de transformações.
• O deep learning substitui não apenas os modelos superficiais no final dos canais de machine
learning tradicionais, mas também o processo trabalhoso de engenharia de recursos.
• Muito do progresso recente no deep learning foi desencadeado por uma abundância de dados
provenientes de sensores baratos e aplicativos em escala da Internet e por um progresso
significativo na computação, principalmente por meio de GPUs.
• A otimização de todo o sistema é um componente chave para a obtenção de alto desem-
penho. A disponibilidade de estruturas eficientes de deep learning tornou o projeto e a im-
plementação disso significativamente mais fáceis.

1.9 Exercícios

1. Quais partes do código que você está escrevendo atualmente podem ser “aprendidas”, ou
seja, aprimoradas ao aprender e determinando automaticamente as opções de design feitas
em seu código? Seu código inclui opções de design heurístico?
2. Quais problemas você encontra têm muitos exemplos de como resolvê-los, mas nenhuma
maneira específica de automatizá-los? Esses podem ser os principais candidatos para usar
o deep learning.

1.8. Resumo 43
3. Vendo o desenvolvimento da IA como uma nova revolução industrial, qual é a relação entre
algoritmos e dados? É semelhante a motores a vapor e carvão? Qual é a diferença funda-
mental?
4. Onde mais você pode aplicar a abordagem de treinamento de ponta a ponta, como em Fig.
1.1.2, física, engenharia e econometria?
Discussions19

19
https://discuss.d2l.ai/t/22

44 Chapter 1. Introdução
2 | Preliminares

Para iniciarmos o nosso aprendizado de Deep Learning, precisaremos desenvolver algumas habili-
dades básicas. Todo aprendizado de máquina está relacionado com a extração de informações dos
dados. Portanto, começaremos aprendendo as habilidades práticas para armazenar, manipular e
pré-processar dados.
Além disso, o aprendizado de máquina normalmente requer trabalhar com grandes conjuntos de
dados, que podemos considerar como tabelas, onde as linhas correspondem a exemplos e as col-
unas correspondem aos atributos. A álgebra linear nos dá um poderoso conjunto de técnicas para
trabalhar com dados tabulares. Não iremos muito longe nas teoria, mas sim nos concentraremos
no básico das operações matriciais e sua implementação.
Além disso, o Deep Learning tem tudo a ver com otimização. Temos um modelo com alguns
parâmetros e queremos encontrar aqueles que melhor se ajustam aos nossos dados. Determinar
como alterar cada parâmetro em cada etapa de um algoritmo requer um pouco de cálculo, que
será brevemente apresentado. Felizmente, o pacote autograd calcula automaticamente a diferen-
ciação para nós, e vamos cobrir isso a seguir.
Em seguida, o aprendizado de máquina se preocupa em fazer previsões: qual é o valor provável
de algum atributo desconhecido, dada a informação que observamos? Raciocinar rigorosamente
sob a incerteza precisaremos invocar a linguagem da probabilidade.
No final, a documentação oficial fornece muitas descrições e exemplos que vão além deste
livro. Para concluir o capítulo, mostraremos como procurar documentação para as informações
necessárias.
Este livro manteve o conteúdo matemático no mínimo necessário para obter uma compreensão
adequada de Deep Learning No entanto, isso não significa que este livro é livre de matemática.
Assim, este capítulo fornece uma introdução rápida a matemática básica e frequentemente usada
para permitir que qualquer pessoa entenda pelo menos a maior parte do conteúdo matemático do
livro. Se você deseja entender todo o conteúdo matemático, uma revisão adicional do apêndice
online sobre matemática20 deve ser suficiente.
20
https://d2l.ai/chapter_apencha-mathematics-for-deep-learning/index.html

45
2.1 Manipulação de Dados

Para fazer qualquer coisa, precisamos de alguma forma de armazenar e manipular dados. Geral-
mente, há duas coisas importantes que precisamos fazer com os dados: (i) adquirir eles; e (ii)
processá-los assim que estiverem dentro do computador. Não há sentido em adquirir dados sem
alguma forma de armazená-los, então vamos brincar com dados sintéticos. Para começar, apre-
sentamos o array n-dimensional, também chamado de tensor.
Se você trabalhou com NumPy, o mais amplamente utilizado pacote de computação científica em
Python, então você achará esta seção familiar. Não importa qual estrutura você usa, sua classe de
tensor (ndarray em MXNet, Tensor em PyTorch e TensorFlow) é semelhante aondarray do NumPy
com alguns recursos interessantes. Primeiro, a GPU é bem suportada para acelerar a computação
enquanto o NumPy suporta apenas computação de CPU. Em segundo lugar, a classe tensor suporta
diferenciação automática. Essas propriedades tornam a classe tensor adequada para aprendizado
profundo. Ao longo do livro, quando dizemos tensores, estamos nos referindo a instâncias da
classe tensorial, a menos que seja declarado de outra forma.

2.1.1 Iniciando

Nesta seção, nosso objetivo é colocá-lo em funcionamento, equipando você com as ferramen-
tas básicas de matemática e computação numérica que você desenvolverá conforme progride no
livro. Não se preocupe se você lutar para grocar alguns dos os conceitos matemáticos ou funções
de biblioteca. As seções a seguir revisitarão este material no contexto de exemplos práticos e irá
afundar. Por outro lado, se você já tem alguma experiência e quiser se aprofundar no conteúdo
matemático, basta pular esta seção.
Para começar, importamos torch. Note que apesar de ser chamado PyTorch, devemos importar
torch ao invés de pytorch.

import torch

Um tensor representa uma matriz (possivelmente multidimensional) de valores numéricos. Com


uma dimensão, um tensor corresponde (em matemática) a um vetor. Com duas dimensões, um
tensor corresponde a uma * matriz *. Tensores com mais de dois eixos não possuem nomes
matemáticos.
Para começar, podemos usar arange para criar um vetor linha x contendo os primeiros 12 inteiros
começando com 0, embora eles sejam criados como float por padrão. Cada um dos valores em
um tensor é chamado de elemento do tensor. Por exemplo, existem 12 elementos no tensor x. A
menos que especificado de outra forma, um novo tensor será armazenado na memória principal
e designado para computação baseada em CPU.

x = torch.arange(12)
x

tensor([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])

Podemos acessar o formato do tensor (o comprimento em cada coordenada) inspecionando sua


propriedade shape .

46 Chapter 2. Preliminares
x.shape

torch.Size([12])

Se quisermos apenas saber o número total de elementos em um tensor, ou seja, o produto de todos
os shapes, podemos inspecionar seu tamanho. Porque estamos lidando com um vetor aqui, o único
elemento de seu shape é idêntico ao seu tamanho.

x.numel()

12

Para mudar o shape de um tensor sem alterar o número de elementos ou seus valores, podemos
invocar a função reshape. Por exemplo, podemos transformar nosso tensor, x, de um vetor linha
com forma (12,) para uma matriz com forma (3, 4). Este novo tensor contém exatamente os mes-
mos valores, mas os vê como uma matriz organizada em 3 linhas e 4 colunas. Para reiterar, em-
bora a forma tenha mudado, os elementos não. Observe que o tamanho não é alterado pela re-
modelagem.

X = x.reshape(3, 4)
X

tensor([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])

A remodelação especificando manualmente todas as dimensões é desnecessária. Se nossa forma


de destino for uma matriz com forma (altura, largura), então, depois de sabermos a largura, a al-
tura é dada implicitamente. Por que devemos realizar a divisão nós mesmos? No exemplo acima,
para obter uma matriz com 3 linhas, especificamos que deve ter 3 linhas e 4 colunas. Felizmente,
os tensores podem calcular automaticamente uma dimensão considerando o resto. Invocamos
esse recurso colocando -1 para a dimensão que gostaríamos que os tensores inferissem automati-
camente. No nosso caso, em vez de chamar x.reshape (3, 4), poderíamos ter chamado equiva-
lentemente x.reshape (-1, 4) ou x.reshape (3, -1).
Normalmente, queremos que nossas matrizes sejam inicializadas seja com zeros, uns, algumas
outras constantes, ou números amostrados aleatoriamente de uma distribuição específica. Pode-
mos criar um tensor representando um tensor com todos os elementos definido como 0 e uma
forma de (2, 3, 4) como a seguir:

torch.zeros((2, 3, 4))

tensor([[[0., 0., 0., 0.],


[0., 0., 0., 0.],
[0., 0., 0., 0.]],

[[0., 0., 0., 0.],


[0., 0., 0., 0.],
[0., 0., 0., 0.]]])

2.1. Manipulação de Dados 47


Da mesma forma, podemos criar tensores com cada elemento definido como 1 da seguinte
maneira:

torch.ones((2, 3, 4))

tensor([[[1., 1., 1., 1.],


[1., 1., 1., 1.],
[1., 1., 1., 1.]],

[[1., 1., 1., 1.],


[1., 1., 1., 1.],
[1., 1., 1., 1.]]])

Frequentemente, queremos amostrar aleatoriamente os valores para cada elemento em um ten-


sor de alguma distribuição de probabilidade. Por exemplo, quando construímos matrizes para
servir como parâmetros em uma rede neural, vamos normalmente inicializar seus valores aleato-
riamente. O fragmento a seguir cria um tensor com forma (3, 4). Cada um de seus elementos é
amostrado aleatoriamente de uma distribuição gaussiana (normal) padrão com uma média de 0 e
um desvio padrão de 1.

torch.randn(3, 4)

tensor([[-1.0383, 2.7221, 1.6101, 0.3270],


[ 1.2290, 0.3447, -0.8467, -1.8943],
[ 0.7013, -1.5338, -0.2593, -0.6438]])

Podemos também especificar os valores exatos para cada elemento no tensor desejado fornecendo
uma lista Python (ou lista de listas) contendo os valores numéricos. Aqui, a lista externa corre-
sponde ao eixo 0 e a lista interna ao eixo 1.

torch.tensor([[2, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])

tensor([[2, 1, 4, 3],
[1, 2, 3, 4],
[4, 3, 2, 1]])

2.1.2 Operações

Este livro não é sobre engenharia de software. Nossos interesses não se limitam a simplesmente
leitura e gravação de dados de/para matrizes. Queremos realizar operações matemáticas nessas
matrizes. Algumas das operações mais simples e úteis são as operações elemento a elemento.
Estes aplicam uma operação escalar padrão para cada elemento de uma matriz. Para funções
que usam dois arrays como entradas, as operações elemento a elemento aplicam algum operador
binário padrão em cada par de elementos correspondentes das duas matrizes. Podemos criar
uma função elemento a elemento a partir de qualquer função que mapeia de um escalar para um
escalar.
Em notação matemática, denotaríamos tal um operador escalar unário (tomando uma entrada)
pela assinatura f : R → R. Isso significa apenas que a função está mapeando de qualquer número
real (R) para outro. Da mesma forma, denotamos um operador escalar binário (pegando duas

48 Chapter 2. Preliminares
entradas reais e produzindo uma saída) pela assinatura f : R, R → R. Dados quaisquer dois
vetores u e v de mesmo shape, e um operador binário f , podemos produzir um vetor c = F (u, v)
definindo ci ← f (ui , vi ) para todos i, onde ci , ui e vi são os elementos ith dos vetores c, u, e v.
Aqui, nós produzimos o valor vetorial F : Rd , Rd → Rd transformando a função escalar para uma
operação de vetor elemento a elemento.
Os operadores aritméticos padrão comuns (+, -,*,/e**) foram todos transformados em operações
elemento a elemento para quaisquer tensores de formato idêntico de forma arbitrária. Podemos
chamar operações elemento a elemento em quaisquer dois tensores da mesma forma. No exem-
plo a seguir, usamos vírgulas para formular uma tupla de 5 elementos, onde cada elemento é o
resultado de uma operação elemento a elemento.

Operações

Os operadores aritméticos padrão comuns (+, -,*,/e**) foram todos transformados em operações
elemento a elemento.

x = torch.tensor([1.0, 2, 4, 8])
y = torch.tensor([2, 2, 2, 2])
x + y, x - y, x * y, x / y, x ** y # O ** é o operador exponenciação

(tensor([ 3., 4., 6., 10.]),


tensor([-1., 0., 2., 6.]),
tensor([ 2., 4., 8., 16.]),
tensor([0.5000, 1.0000, 2.0000, 4.0000]),
tensor([ 1., 4., 16., 64.]))

Muitos mais operações podem ser aplicadas elemento a elemento, incluindo operadores unários
como exponenciação.

torch.exp(x)

tensor([2.7183e+00, 7.3891e+00, 5.4598e+01, 2.9810e+03])

Além de cálculos elemento a elemento, também podemos realizar operações de álgebra linear,
incluindo produtos escalar de vetor e multiplicação de matrizes. Explicaremos as partes cruciais
da álgebra linear (sem nenhum conhecimento prévio assumido) em Section 2.3.
Também podemos concatenar vários tensores juntos, empilhando-os ponta a ponta para formar
um tensor maior. Só precisamos fornecer uma lista de tensores e informar ao sistema ao longo
de qual eixo concatenar. O exemplo abaixo mostra o que acontece quando concatenamos duas
matrizes ao longo das linhas (eixo 0, o primeiro elemento da forma) vs. colunas (eixo 1, o segundo
elemento da forma). Podemos ver que o comprimento do eixo 0 do primeiro tensor de saída (6) é
a soma dos comprimentos do eixo 0 dos dois tensores de entrada (3 + 3); enquanto o comprimento
do eixo 1 do segundo tensor de saída (8) é a soma dos comprimentos do eixo 1 dos dois tensores
de entrada (4 + 4).

X = torch.arange(12, dtype=torch.float32).reshape((3,4))
Y = torch.tensor([[2.0, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])
torch.cat((X, Y), dim=0), torch.cat((X, Y), dim=1)

2.1. Manipulação de Dados 49


(tensor([[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.],
[ 2., 1., 4., 3.],
[ 1., 2., 3., 4.],
[ 4., 3., 2., 1.]]),
tensor([[ 0., 1., 2., 3., 2., 1., 4., 3.],
[ 4., 5., 6., 7., 1., 2., 3., 4.],
[ 8., 9., 10., 11., 4., 3., 2., 1.]]))

Às vezes, queremos construir um tensor binário por meio de declarações lógicas. Tome X == Y
como exemplo. Para cada posição, se X eY forem iguais nessa posição, a entrada correspondente
no novo tensor assume o valor 1, o que significa que a declaração lógica X == Y é verdadeira nessa
posição; caso contrário, essa posição assume 0.

X == Y

tensor([[False, True, False, True],


[False, False, False, False],
[False, False, False, False]])

Somando todos os elementos no tensor resulta em um tensor com apenas um elemento.

X.sum()

tensor(66.)

2.1.3 Mecanismo de Broadcasting

Na seção acima, vimos como realizar operações elemento a elemento em dois tensores da mesma
forma. Sob certas condições, mesmo quando as formas são diferentes, ainda podemos realizar
operações elementar invocando o mecanismo de Broadcasting. Esse mecanismo funciona da
seguinte maneira: Primeiro, expanda um ou ambos os arrays copiando elementos de forma ade-
quada de modo que após esta transformação, os dois tensores têm a mesma forma. Em segundo
lugar, execute as operações elemento a elemento nas matrizes resultantes.
Na maioria dos casos, nós transmitimos ao longo de um eixo onde uma matriz inicialmente tem
apenas o comprimento 1, como no exemplo a seguir:

a = torch.arange(3).reshape((3, 1))
b = torch.arange(2).reshape((1, 2))
a, b

(tensor([[0],
[1],
[2]]),
tensor([[0, 1]]))

Uma vez que a eb são matrizes 3 × 1 e 1 × 2 respectivamente, suas formas não correspondem se
quisermos adicioná-los. Nós transmitimos as entradas de ambas as matrizes em uma matriz 3 × 2

50 Chapter 2. Preliminares
maior da seguinte maneira: para a matriz a ele replica as colunas e para a matriz b ele replica as
linhas antes de adicionar ambos os elementos.

a + b

tensor([[0, 1],
[1, 2],
[2, 3]])

2.1.4 Indexação e Fatiamento

Assim como em qualquer outro array Python, os elementos em um tensor podem ser acessados
por índice. Como em qualquer matriz Python, o primeiro elemento tem índice 0 e os intervalos
são especificados para incluir o primeiro, mas antes do último elemento. Como nas listas padrão
do Python, podemos acessar os elementos de acordo com sua posição relativa ao final da lista
usando índices negativos.
Assim, [-1] seleciona o último elemento e [1: 3] seleciona o segundo e o terceiro elementos da
seguinte forma:

X[-1], X[1:3]

(tensor([ 8., 9., 10., 11.]),


tensor([[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.]]))

Além da leitura, também podemos escrever elementos de uma matriz especificando índices.

X[1, 2] = 9
X

tensor([[ 0., 1., 2., 3.],


[ 4., 5., 9., 7.],
[ 8., 9., 10., 11.]])

Se quisermos para atribuir a vários elementos o mesmo valor, simplesmente indexamos todos
eles e, em seguida, atribuímos o valor a eles. Por exemplo, [0: 2,:] acessa a primeira e a se-
gunda linhas, onde : leva todos os elementos ao longo do eixo 1 (coluna). Enquanto discutimos
a indexação de matrizes, isso obviamente também funciona para vetores e para tensores de mais
de 2 dimensões.

X[0:2, :] = 12
X

tensor([[12., 12., 12., 12.],


[12., 12., 12., 12.],
[ 8., 9., 10., 11.]])

2.1. Manipulação de Dados 51


2.1.5 Economizando memória

As operações em execução podem fazer com que uma nova memória seja alocado aos resultados
do host. Por exemplo, se escrevermos Y = X + Y, vamos desreferenciar o tensor que Y costumava
apontar para e, em vez disso, aponte Y para a memória recém-alocada. No exemplo a seguir,
demonstramos isso com a função id () do Python, que nos dá o endereço exato do objeto refer-
enciado na memória. Depois de executar Y = Y + X, descobriremos queid (Y)aponta para um
local diferente. Isso ocorre porque o Python primeiro avalia Y + X, alocar nova memória para o
resultado e, em seguida, torna Y aponte para este novo local na memória.

before = id(Y)
Y = Y + X
id(Y) == before

False

Isso pode ser indesejável por dois motivos. Em primeiro lugar, não queremos alocar memória
desnecessariamente o tempo todo. No aprendizado de máquina, podemos ter centenas de
megabytes de parâmetros e atualizar todos eles várias vezes por segundo. Normalmente, quer-
emos realizar essas atualizações no local. Em segundo lugar, podemos apontar os mesmos
parâmetros de várias variáveis. Se não atualizarmos no local, outras referências ainda apontarão
para a localização da memória antiga, tornando possível para partes do nosso código para refer-
enciar inadvertidamente parâmetros obsoletos.
Felizmente, executar operações no local é fácil. Podemos atribuir o resultado de uma operação
para uma matriz previamente alocada com notação de fatia, por exemplo, Y [:] = <expressão>.
Para ilustrar este conceito, primeiro criamos uma nova matriz Z com a mesma forma de outro Y,
usando zeros_like para alocar um bloco de 0 entradas. : end_tab:

Z = torch.zeros_like(Y)
print('id(Z):', id(Z))
Z[:] = X + Y
print('id(Z):', id(Z))

id(Z): 140194801216832
id(Z): 140194801216832

Se o valor de X não for reutilizado em cálculos subsequentes, também podemos usar X [:] = X +
Y ouX + = Y para reduzir a sobrecarga de memória da operação.

before = id(X)
X += Y
id(X) == before

True

52 Chapter 2. Preliminares
2.1.6 Conversão para outros objetos Python

Converter para um tensor NumPy, ou vice-versa, é fácil. O resultado convertido não compartilha
memória. Este pequeno inconveniente é muito importante: quando você executa operações na
CPU ou GPUs, você não quer interromper a computação, esperando para ver se o pacote NumPy
do Python deseja fazer outra coisa com o mesmo pedaço de memória.

A = X.numpy()
B = torch.tensor(A)
type(A), type(B)

(numpy.ndarray, torch.Tensor)

Para converter um tensor de tamanho 1 em um escalar Python, podemos invocar a função item
ou as funções integradas do Python.

a = torch.tensor([3.5])
a, a.item(), float(a), int(a)

(tensor([3.5000]), 3.5, 3.5, 3)

2.1.7 Sumário

• A principal interface para armazenar e manipular dados para Deep Learning é o tensor (ar-
ray n -dimensional). Ele fornece uma variedade de funcionalidades, incluindo operações
matemáticas básicas, transmissão, indexação, divisão, economia de memória e conversão
para outros objetos Python.

2.1.8 Exercícios

1. Execute o código nesta seção. Altere a declaração condicional X == Y nesta seção paraX < Y
ou X > Y, e então veja que tipo de tensor você pode obter.
2. Substitua os dois tensores que operam por elemento no mecanismo de transmissão por out-
ras formas, por exemplo, tensores tridimensionais. O resultado é o mesmo que o esperado?
Discussions21

2.2 Pré-processamento de Dados

Até agora, introduzimos uma variedade de técnicas para manipular dados que já estão armazena-
dos em tensores. Para aplicar o Deep Learning na solução de problemas do mundo real, fre-
quentemente começamos com o pré-processamento de dados brutos, em vez daqueles dados bem
preparados no formato tensor. Entre as ferramentas analíticas de dados populares em Python, o
pacote pandas é comumente usado. Como muitos outros pacotes de extensão no vasto ecossistema
21
https://discuss.d2l.ai/t/27

2.2. Pré-processamento de Dados 53


do Python, pandas podem trabalhar em conjunto com tensores. Então, vamos percorrer breve-
mente as etapas de pré-processamento de dados brutos com pandas e convertendo-os no formato
tensor. Abordaremos mais técnicas de pré-processamento de dados em capítulos posteriores.

2.2.1 Lendo o Dataset

Como um exemplo, começamos criando um conjunto de dados artificial que é armazenado em


um arquivo csv (valores separados por vírgula) ../ data / house_tiny.csv. Dados armazenados
em outro formatos podem ser processados de maneiras semelhantes.
Abaixo, escrevemos o conjunto de dados linha por linha em um arquivo csv.

import os

os.makedirs(os.path.join('..', 'data'), exist_ok=True)


data_file = os.path.join('..', 'data', 'house_tiny.csv')
with open(data_file, 'w') as f:
f.write('NumRooms,Alley,Price\n') # Column names
f.write('NA,Pave,127500\n') # Each row represents a data example
f.write('2,NA,106000\n')
f.write('4,NA,178100\n')
f.write('NA,NA,140000\n')

Para carregar o conjunto de dados bruto do arquivo csv criado, importamos o pacote pandas e
chamamos a funçãoread_csv. Este conjunto de dados tem quatro linhas e três colunas, onde cada
linha descreve o número de quartos (“NumRooms”), o tipo de beco (“Alley”) e o preço (“Price”) de
uma casa.

# Se o pandas ainda não estiver instalado descomente a linha abaixo:


# !pip install pandas
import pandas as pd

data = pd.read_csv(data_file)
print(data)

NumRooms Alley Price


0 NaN Pave 127500
1 2.0 NaN 106000
2 4.0 NaN 178100
3 NaN NaN 140000

2.2.2 Lidando com Dados Faltantes

Observe que as entradas “NaN” têm valores ausentes. Para lidar com dados perdidos, os métodos
típicos incluem imputação e exclusão, onde a imputação substitui os valores ausentes por outros
substituídos, enquanto a exclusão ignora os valores ausentes. Aqui, consideraremos a imputação.
Por indexação baseada em localização de inteiros (iloc), dividimos os dados em entradas e saí-
das, onde o primeiro leva as duas primeiras colunas, enquanto o último mantém apenas a última
coluna. Para valores numéricos em entradas que estão faltando, nós substituímos as entradas
“NaN” pelo valor médio da mesma coluna.

54 Chapter 2. Preliminares
inputs, outputs = data.iloc[:, 0:2], data.iloc[:, 2]
inputs = inputs.fillna(inputs.mean())
print(inputs)

NumRooms Alley
0 3.0 Pave
1 2.0 NaN
2 4.0 NaN
3 3.0 NaN

Para valores categóricos ou discretos em entradas, consideramos “NaN” como uma categoria.
Como a coluna “Alley” aceita apenas dois tipos de valores categóricos “Pave” e “NaN”, O pandas
pode converter automaticamente esta coluna em duas colunas “Alley_Pave” e “Alley_nan”. Uma
linha cujo tipo de beco é “Pave” definirá os valores de “Alley_Pave” e “Alley_nan” como 1 e 0. Uma
linha com um tipo de beco ausente definirá seus valores para 0 e 1

inputs = pd.get_dummies(inputs, dummy_na=True)


print(inputs)

NumRooms Alley_Pave Alley_nan


0 3.0 1 0
1 2.0 0 1
2 4.0 0 1
3 3.0 0 1

2.2.3 Convertendo para o Formato Tensor

Agora que todas as entradas em entradas e saídas são numéricas, elas podem ser convertidas
para o formato tensor. Uma vez que os dados estão neste formato, eles podem ser manipulados
posteriormente com as funcionalidades de tensor que introduzimos em Section 2.1.

import torch

X, y = torch.tensor(inputs.values), torch.tensor(outputs.values)
X, y

(tensor([[3., 1., 0.],


[2., 0., 1.],
[4., 0., 1.],
[3., 0., 1.]], dtype=torch.float64),
tensor([127500, 106000, 178100, 140000]))

2.2. Pré-processamento de Dados 55


2.2.4 Sumário

• Como muitos outros pacotes de extensão no vasto ecossistema do Python, pandas pode tra-
balhar junto com tensores.
• Imputação e exclusão podem ser usadas para lidar com dados perdidos.

2.2.5 Exercícios

Crie um conjunto de dados bruto com mais linhas e colunas.


3. Exclua a coluna com a maioria dos valores ausentes.
4. Converta o conjunto de dados pré-processado para o formato tensor.
Discussions22

2.3 Á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 cober-
tos 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.

2.3.1 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 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 c = 59 (f − 32), definindo f para 52. Nesta equação, cada um
dos termos—5, 9, e 32—são valores escalares. Os marcadores c e 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, x, y, and z). Denotamos o espaço de todos os escalares (con-
tínuos) com valor real por 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 x ∈ R é uma maneira formal
de dizer que x é um escalar com valor real. O símbolo ∈ pode ser pronunciado “em” e simples-
mente denota associação em um conjunto. Analogamente, poderíamos escrever x, y ∈ {0, 1} para
afirmar que x e y são números cujo valor só pode ser 0 ou 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.
22
https://discuss.d2l.ai/t/29

56 Chapter 2. Preliminares
import torch

x = torch.tensor([3.0])
y = torch.tensor([2.0])

x + y, x * y, x / y, x**y

(tensor([5.]), tensor([6.]), tensor([1.5000]), tensor([9.]))

2.3.2 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 represen-
tam 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 es-
tivé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,, x, y,
and z).
Trabalhamos com vetores via tensores unidimensionais. Em geral, os tensores podem ter com-
primentos arbitrários, sujeito aos limites de memória de sua máquina.

x = torch.arange(4)
x

tensor([0, 1, 2, 3])

Podemos nos referir a qualquer elemento de um vetor usando um subscrito. Por exemplo, pode-
mos nos referir ao elemento ith element of x por xi . Observe que o elemento xi é um escalar, por-
tanto, não colocamos a fonte em negrito quando nos referimos a ela. A literatura extensa consid-
era os vetores de coluna como o padrão orientação de vetores, este livro também. Em matemática,
um vetor x pode ser escrito como
 
x1
 x2 
 
x =  . , (2.3.1)
 .. 
xn

onde x1 , . . . , xn são elementos do vetor. No código acessamos qualquer elemento indexando no


tensor

x[3]

tensor(3)

2.3. Álgebra Linear 57


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 x consiste em n escalares com valor real, podemos
expressar isso como x ∈ Rn . 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.

len(x)

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.

x.shape

torch.Size([4])

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.

2.3.3 Matrizes

Assim como os vetores generalizam escalares de ordem zero para ordem um, matrizes general-
izam vetores de ordem um para ordem dois. Matrizes, que normalmente denotamos com letras
maiúsculas em negrito (por exemplo, X, Y, and Z), são representados no código como tensores
com dois eixos.
Em notação matemática, usamos A ∈ Rm×n para expressar que a matriz A consiste em m linhas e
n colunas de escalares com valor real. Visualmente, podemos ilustrar qualquer matriz A ∈ Rm×n
como uma tabela, onde cada elemento aij pertence à linha ith e coluna j th :
 
a11 a12 · · · a1n
 a21 a22 · · · a2n 
 
A= . .. .. ..  . (2.3.2)
 .. . . . 
am1 am2 · · · amn
Para qualquer A ∈ Rm×n , a forma de A é (m, n) ou m × 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 m×n especificando uma forma com dois componentes m e n ao chamar
qualquer uma de nossas funções favoritas para instanciar um tensor.

58 Chapter 2. Preliminares
A = torch.arange(20).reshape(5, 4)
A

tensor([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15],
[16, 17, 18, 19]])

Podemos acessar o elemento escalar aij de uma matriz A em: eqref: eq_matrix_def especificando
os índices para a linha (i) e coluna (j), como [A]ij . Quando os elementos escalares de uma ma-
triz A, como em: eqref: eq_matrix_def, não são fornecidos, podemos simplesmente usar a letra
minúscula da matriz A com o subscrito do índice, aij , para se referir a [A]ij . Para manter a notação
simples, as vírgulas são inseridas para separar os índices apenas quando necessário, como a2,3j e
[A]2i−1,3 .
Às vezes, queremos inverter os eixos. Quando trocamos as linhas e colunas de uma matriz, o re-
sultado é chamado de transposição da matriz. Formalmente, significamos uma matriz A transposta
por A⊤ e se B = A⊤ , então bij = aji para qualquer i e j. Assim, a transposição de A em: eqref:
eq_matrix_def é uma matriz n × m:
 
a11 a21 . . . am1
 a12 a22 . . . am2 
 
A⊤ =  . .. .. ..  . (2.3.3)
 .. . . . 
a1n a2n . . . amn

Agora acessamoas a matriz transposta via código.

A.T

tensor([[ 0, 4, 8, 12, 16],


[ 1, 5, 9, 13, 17],
[ 2, 6, 10, 14, 18],
[ 3, 7, 11, 15, 19]])

Como um tipo especial de matriz quadrada, a matriz simétrica A é igual à sua transposta: A = A⊤ .
Aqui definimos uma matriz simétrica B.

B = torch.tensor([[1, 2, 3], [2, 0, 4], [3, 4, 5]])


B

tensor([[1, 2, 3],
[2, 0, 4],
[3, 4, 5]])

Agora comparamos B com sua transposta.

B == B.T

2.3. Álgebra Linear 59


tensor([[True, True, True],
[True, True, True],
[True, True, True]])

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 difer-
entes 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. As-
sim, embora a orientação padrão de um único vetor seja um vetor coluna, em uma matriz que rep-
resenta 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.

2.3.4 Tensores

Assim como vetores generalizam escalares e matrizes generalizam vetores, podemos construir es-
truturas 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 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 ex-
emplo, X, Y, e Z) e seu mecanismo de indexação (por exemplo, xijk e [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 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.

X = torch.arange(24).reshape(2, 3, 4)
X

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]]])

60 Chapter 2. Preliminares
2.3.5 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.

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

(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.]]))

Especificamente, a multiplicação elemento a elemento de duas matrizes é chamada de produto


Hadamard (notação matemática ⊙). Considere a matriz B ∈ Rm×n cujo elemento da linha i e
coluna j é bij . O produto Hadamard das matrizes A (definido em (2.3.2)) e B
 
a11 b11 a12 b12 . . . a1n b1n
 a21 b21 a22 b22 . . . a2n b2n 
 
A⊙B= . .. .. .. . (2.3.4)
 .. . . . 
am1 bm1 am2 bm2 . . . amn bmn

A * B

tensor([[ 0., 1., 4., 9.],


[ 16., 25., 36., 49.],
[ 64., 81., 100., 121.],
[144., 169., 196., 225.],
[256., 289., 324., 361.]])

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.

a = 2
X = torch.arange(24).reshape(2, 3, 4)
a + X, (a * X).shape

2.3. Álgebra Linear 61


(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]))

2.3.6 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 . Para expressar a
soma dos elementos em um vetor x de comprimento d, escrevemos di=1 xi . No código, podemos
apenas chamar a função para calcular a soma.

x = torch.arange(4, dtype=torch.float32)
x, x.sum()

(tensor([0., 1., 2., 3.]), tensor(6.))

Podemos expressar somas sobre os elementos de tensores de forma ∑arbitrária. Por exemplo, a
m ∑n
soma dos elementos de uma matriz m × n A poderia ser escrita como i=1 j=1 aij .

A.shape, A.sum()

(torch.Size([5, 4]), tensor(190.))

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.

A_sum_axis0 = A.sum(axis=0)
A_sum_axis0, A_sum_axis0.shape

(tensor([40., 45., 50., 55.]), torch.Size([4]))

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.

A_sum_axis1 = A.sum(axis=1)
A_sum_axis1, A_sum_axis1.shape

(tensor([ 6., 22., 38., 54., 70.]), torch.Size([5]))

62 Chapter 2. Preliminares
Reduzindo uma matriz ao longo de ambas as linhas e colunas por meio da soma é equivalente a
somar todos os elementos da matriz.

A.sum(axis=[0, 1]) # O mesmo que `A.sum()`

tensor(190.)

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.

A.mean(), A.sum() / A.numel()

(tensor(9.5000), tensor(9.5000))

Da mesma forma, a função de cálculo da média também pode reduzir um tensor ao longo dos
eixos especificados.

A.mean(axis=0), A.sum(axis=0) / A.shape[0]

(tensor([ 8., 9., 10., 11.]), tensor([ 8., 9., 10., 11.]))

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.

sum_A = A.sum(axis=1, keepdims=True)


sum_A

tensor([[ 6.],
[22.],
[38.],
[54.],
[70.]])

Por exemplo, uma vez que sum_A ainda mantém seus dois eixos após somar cada linha, podemos
dividirA por sum_A com broadcasting.

A / sum_A

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]])

2.3. Álgebra Linear 63


Se quisermos calcular a soma cumulativa dos elementos de A ao longo de algum eixo, digaeixo = 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.

A.cumsum(axis=0)

tensor([[ 0., 1., 2., 3.],


[ 4., 6., 8., 10.],
[12., 15., 18., 21.],
[24., 28., 32., 36.],
[40., 45., 50., 55.]])

2.3.7 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 x, y ∈ Rd , seu
produto∑escalar x⊤ y (ou ⟨x, y⟩) é uma soma sobre os produtos dos elementos na mesma posição:

x y = di=1 xi yi .

y = torch.ones(4, dtype = torch.float32)


x, y, torch.dot(x, y)

(tensor([0., 1., 2., 3.]), tensor([1., 1., 1., 1.]), tensor(6.))

Observe que podemos expressar o produto escalar de dois vetores de forma equivalente, real-
izando uma multiplicação elemento a elemento e, em seguida, uma soma:

torch.sum(x * y)

tensor(6.)

Os produtos escalares são úteis em uma ampla variedade de contextos. Por exemplo, dado algum
conjunto de valores, denotado por um vetor x ∈ Rd e um conjunto de pesos denotado por w ∈ Rd ,,
a soma ponderada dos valores em x de acordo com os pesos w pode ser(expresso como ) o produto

∑d
escalar x w. Quando os pesos não são negativos e soma a um (ou seja, i=1 wi = 1 ), 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 for-
malmente essa noção de comprimento posteriormente nesta seção.

64 Chapter 2. Preliminares
2.3.8 Produtos Matriz-Vetor

Agora que sabemos como calcular produtos escalares, podemos começar a entender produtos veto-
riais de matriz. Lembre-se da matriz A ∈ Rm×n e o vetor x ∈ Rn definido e visualizado em (2.3.2) e
(2.3.1) respectivamente. Vamos começar visualizando a matriz A em termos de seus vetores linha
 ⊤
a1
 a⊤ 
 2
A =  . , (2.3.5)
 .. 
a⊤
m

onde cada a⊤
i ∈ R é uma linha vetor representando a i linha da matriz A.
n th

O produto vetor-matriz Ax é simplesmente um vetor coluna de comprimento m, cujo elemento ith


é o produto escalar a⊤
i x:
 ⊤  ⊤ 
a1 a1 x
 a⊤   a⊤ x 
 2  2 
Ax =  .  x =  .  . (2.3.6)
 . 
.  .. 
a⊤
m a⊤
mx

Podemos pensar na multiplicação por uma matriz A ∈ Rm×n como uma transformação que pro-
jeta vetores de Rn a Rm . 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 vetorx, 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).

A.shape, x.shape, torch.mv(A, x)

(torch.Size([5, 4]), torch.Size([4]), tensor([ 14., 38., 62., 86., 110.]))

2.3.9 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 A ∈ Rn×k e B ∈ Rk×m :
   
a11 a12 · · · a1k b11 b12 · · · b1m
 a21 a22 · · · a2k  b21 b22 · · · b2m 
   
A= . .. .. ..  , B =  .. .. . . ..  . (2.3.7)
 .. . . .   . . . . 
an1 an2 · · · ank bk1 bk2 · · · bkm

Denotada por a⊤
i ∈ R o vetor linha representando a i linha da matriz A, e bj ∈ R seja o vetor
k th k
th
coluna da j coluna matriz B. Para produzir o produto de matrizes C = AB, é mais facil pensar A

2.3. Álgebra Linear 65


em termos de seus vetores linha B em termos de seus vetores coluna:
 ⊤
a1
a⊤  [ ]
 2
A =  .  , B = b1 b2 · · · bm . (2.3.8)
 .. 
a⊤
n

Então, o produto da matriz C ∈ Rn×m é produzido, pois simplesmente calculamos cada elemento
cij como o produto escalar a⊤
i bj :
 ⊤  ⊤ 
a1 a1 b1 a⊤ ⊤
1 b2 · · · a1 bm
a⊤  [ ]  ⊤ ⊤ ⊤ 
 2 a2 b1 a2 b2 · · · a2 bm 
C = AB =  .  b1 b2 · · · bm =  .
.. 
. .. . . (2.3.9)
 ..   .. .. . 
a⊤
n a⊤ ⊤ ⊤
n b1 an b2 · · · an bm

Podemos pensar na multiplicação matriz-matriz AB simplesmente realizando m produtos vetori-


ais de matriz e juntando os resultados para formar uma matriz n × m. No trecho a seguir, real-
izamos a multiplicação da matriz em A eB. 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.

B = torch.ones(4, 3)
torch.mm(A, B)

tensor([[ 6., 6., 6.],


[22., 22., 22.],
[38., 38., 38.],
[54., 54., 54.],
[70., 70., 70.]])

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.

2.3.10 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 f que mapeia um vetor para um escalar,
satisfazendo um punhado de propriedades. Dado qualquer vetor x, a primeira propriedade diz
que se escalarmos todos os elementos de um vetor por um fator constante α, sua norma também
escala pelo valor absoluto do mesmo fator constante:

f (αx) = |α|f (x). (2.3.10)

A segunda propriedade é a familiar desigualdade do triângulo:

f (x + y) ≤ f (x) + f (y). (2.3.11)

A terceira propriedade simplesmente diz que a norma deve ser não negativa:

f (x) ≥ 0. (2.3.12)

66 Chapter 2. Preliminares
Isso faz sentido, pois na maioria dos contextos, o menor tamanho para qualquer coisa é 0. A pro-
priedade final requer que a menor norma seja alcançada e somente alcançada por um vetor que
consiste em todos os zeros.
∀i, [x]i = 0 ⇔ f (x) = 0. (2.3.13)
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 L2 . Suponha que os elementos no vetor n
-dimensional x são x1 , . . . , xn .
A L2 norma de x é a raiz quadrada da soma dos quadrados dos elementos do vetor:
v
u n
u∑
∥x∥2 = t x2i , (2.3.14)
i=1

onde o subscrito 2 é frequentemente omitido nas normas L2 , ou seja, ∥x∥ é equivalente a ∥x∥2 .
Em código, podemos calcular a norma L2 de um vetor da seguinte maneira.

u = torch.tensor([3.0, -4.0])
torch.norm(u)

tensor(5.)

Em Deep Learning, trabalhamos com mais frequência com a norma L2 ao quadrado.


Você também encontrará frequentemente a norma L1 , que é expresso como a soma dos valores
absolutos dos elementos do vetor:

n
∥x∥1 = |xi | . (2.3.15)
i=1

Em comparação com a norma L2 , é menos influenciado por outliers. Para calcular a norma L1 ,
nós compomos a função de valor absoluto com uma soma sobre os elementos.

torch.abs(u).sum()

tensor(7.)

Tanto a norma L2 quanto a norma L1 são casos especiais da norma mais geral Lp :
( n )1/p

∥x∥p = |xi |p . (2.3.16)
i=1

Análogo a L2 normas de vetores, a norma de Frobenius de uma matriz X ∈ Rm×n é a raiz quadrada
da soma dos quadrados dos elementos da matriz:
v
u∑
um ∑ n
∥X∥F = t x2ij . (2.3.17)
i=1 j=1

A norma Frobenius satisfaz todas as propriedades das normas vetoriais. Ele se comporta como
se fosse uma norma L2 de um vetor em forma de matriz. Invocar a função a seguir calculará a
norma de Frobenius de uma matriz.

2.3. Álgebra Linear 67


torch.norm(torch.ones((4, 9)))

tensor(6.)

Normas e Objetivos

Embora não queiramos nos adiantar muito, já podemos ter uma intuição sobre por que esses con-
ceitos são úteis. No Deep Learning, muitas vezes tentamos resolver problemas de otimização: max-
imizar 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ân-
cia 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.

2.3.11 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 de-
compostas 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 concen-
tram 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 con-
juntos 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 linear23 ou outra excelente fonte (Strang, 1993; Kolter, 2008; Petersen et al.,
2008).

2.3.12 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 L1 , a norma
L2 e a norma Frobenius.
23
https://d2l.ai/chapter_appendix-mathematics-for-deep-learning/geometry-linear-algebraic-ops.html

68 Chapter 2. Preliminares
• Podemos realizar uma variedade de operações sobre escalares, vetores, matrizes e tensores.

2.3.13 Exercícios

1. Prove que a transposta de uma matriz A transposta é A: (A⊤ )⊤ = A.


2. Dadas duas matrizes A e B, mostre que a soma das transpostas é igual à transposta de uma
soma: A⊤ + B⊤ = (A + B)⊤ .
3. Dada qualquer matriz quadrada A, A + A⊤ é 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?
Discussions24

2.4 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 en-
contrar 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. 2.4.1: 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
24
https://discuss.d2l.ai/t/31

2.4. Cálculo 69
otimização consideram como fazer algo o melhor. Conforme discutido em Section 2.3.10, tais prob-
lemas 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á pro-
duzindo 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 con-
junto 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.

2.4.1 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 pe-
quena.
Suponha que temos uma função f : R → R, cuja entrada e saída são escalares. A derivada de f é
definida como
f (x + h) − f (x)
f ′ (x) = lim , (2.4.1)
h→0 h
se este limite existe. Se f ′ (a) existe, Diz-se que f é diferenciável em a. Se f é diferenciável a cada
número de um intervalo, então esta função é diferenciável neste intervalo. Podemos interpretar
a derivada f ′ (x) em (2.4.1) como a taxa de variação instantânea de f (x) em relação a x. A chamada
taxa instantânea de mudança é baseada em a variação h em x, que se aproxima de 0.
Para ilustrar derivadas, vamos experimentar com um exemplo. Define-se u = f (x) = 3x2 − 4x.

%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

Definindo x = 1 e deixando h se aproximar de 0, o resultado numérico de f (x+h)−f


h
(x)
in: eqref:
eq_derivative aproxima-se de 2. Embora este experimento não seja uma prova matemática, ver-
emos mais tarde que a derivada u′ é 2 quando x = 1.

70 Chapter 2. Preliminares
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

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

Vamos nos familiarizar com algumas notações equivalentes para derivadas. Dado y = f (x),
onde x e y são a variável independente e a variável dependente da função f , respectivamente.
As seguintes expressões são equivalentes:
dy df d
f ′ (x) = y ′ = = = f (x) = Df (x) = Dx f (x), (2.4.2)
dx dx dx
d
onde os símbolos dx e D são operadores de diferenciação que indicam operação de diferenciação.
Podemos usar as seguintes regras para diferenciar funções comuns:
• DC = 0 (C é uma constante),
• Dxn = nxn−1 (uma exponenciação, n é qualquer valor real),
• Dex = ex ,
• 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 f e g sejam
diferenciáveis e C seja uma constante, temos a regra múltipla constante
d d
[Cf (x)] = C f (x), (2.4.3)
dx dx
a regra da soma
d d d
[f (x) + g(x)] = f (x) + g(x), (2.4.4)
dx dx dx
a regra do produto
d d d
[f (x)g(x)] = f (x) [g(x)] + g(x) [f (x)], (2.4.5)
dx dx dx
e a regra do quociente
[ ]
d f (x) d
g(x) dx [f (x)] − f (x) dx
d
[g(x)]
= . (2.4.6)
dx g(x) [g(x)]2

Agora podemos aplicar algumas das regras acima para encontrar u′ = f ′ (x) = 3 dx x − 4 dx
d 2 d
x=

6x −4. Assim, definindo x = 1, temos u = 2: isso é apoiado por nosso experimento anterior nesta
seção onde o resultado numérico se aproxima de 2. Esta derivada também é a inclinação da linha
tangente para a curva u = f (x) quando x = 1.

2.4. Cálculo 71
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 pa-
cotematplotlib para produzir os números SVG para imagens mais nítidas. Observe que o co-
mentário # @ save é uma marca especial onde a seguinte função, classe, ou instruções são sal-
vas no pacote d2l então, mais tarde, eles podem ser chamados diretamente (por exemplo, d2l.
use_svg_display ()) sem serem redefinidos.

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 importfrom matplotlib import pyplot as plt foi
marcada para ser salva no pacote d2l no prefácio.

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
pormatplotlib.

#@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.

#@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)
(continues on next page)

72 Chapter 2. Preliminares
(continued from previous page)
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 u = f (x) e sua linha tangente y = 2x − 3 em x = 1, onde o


coeficiente 2 é a inclinação da linha 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)'])

/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')

2.4. Cálculo 73
2.4.2 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 y = f (x1 , x2 , . . . , xn ) uma função com n variáveis. A derivada parcial de y em relação ao seu
ith parâmetro xi é
∂y f (x1 , . . . , xi−1 , xi + h, xi+1 , . . . , xn ) − f (x1 , . . . , xi , . . . , xn )
= lim . (2.4.7)
∂xi h→0 h
∂y
Para calcular ∂x i
, podemos simplesmente tratar x1 , . . . , xi−1 , xi+1 , . . . , xn como constantes e cal-
cular a derivada de y com respeito a xi . Para notação de derivadas parciais, os seguintes são equiv-
alentes:
∂y ∂f
= = fxi = fi = Di f = Dxi f. (2.4.8)
∂xi ∂xi

2.4.3 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 f : Rn → R seja
um vetor n -dimensional x = [x1 , x2 , . . . , xn ]⊤ e a saída é um escalar. O gradiente da função f (x)
em relação a x é um vetor de n derivadas parciais:
[ ]
∂f (x) ∂f (x) ∂f (x) ⊤
∇x f (x) = , ,..., , (2.4.9)
∂x1 ∂x2 ∂xn
onde ∇x f (x) é frequentemente substituído por ∇f (x) quando não há ambiguidade.
Seja x um vetor n -dimensional, as seguintes regras são freqüentemente usadas ao diferenciar
funções multivariadas:
• For all A ∈ Rm×n , ∇x Ax = A⊤ ,
• For all A ∈ Rn×m , ∇x x⊤ A = A,
• For all A ∈ Rn×n , ∇x x⊤ Ax = (A + A⊤ )x,
• ∇x ∥x∥2 = ∇x x⊤ x = 2x.
Da mesma forma, para qualquer matriz X, temos ∇X ∥X∥2F = 2X. Como veremos mais tarde, os
gradientes são úteis para projetar algoritmos de otimização em deep learning.

2.4.4 Regra da Cadeia

No entanto, esses gradientes podem ser difíceis de encontrar. Isso ocorre porque as funções mul-
tivariadas no deep learning são frequentemente compostas, portanto, não podemos aplicar nen-
huma 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 y = f (u)
e u = g(x) sejam diferenciáveis, então a regra da cadeia afirma que
dy dy du
= . (2.4.10)
dx du dx

74 Chapter 2. Preliminares
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 y tenha variáveis u1 , u2 , . . . , um ,
onde cada função diferenciável ui tem variáveis x1 , x2 , . . . , xn . Observe que y é uma função de
x1 , x2 , . . . , xn . Então a regra da cadeia será

dy dy du1 dy du2 dy dum


= + + ··· + (2.4.11)
dxi du1 dxi du2 dxi dum dxi
para qualquer i = 1, 2, . . . , n.

2.4.5 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 mul-
tivariada com respeito a todas as suas variáveis.
• A regra da cadeia nos permite diferenciar funções compostas.

2.4.6 Exercícios

1. Trace a função y = f (x) = x3 − 1


x e sua linha tangente quando x = 1.
2. Encontre o gradiente da função f (x) = 3x21 + 5ex2 .
3. Qual é o gradiente da função f (x) = ∥x∥2 ?
4. Você pode escrever a regra da cadeia para o caso em que u = f (x, y, z) e x = x(a, b), y =
y(a, b), e z = z(a, b)?
Discussions25

2.5 Diferenciação automática

Como já explicado em Section 2.4, a diferenciação é uma etapa crucial em quase todos os algo-
ritmos de otimização de Deep Learning. Embora os cálculos para obter esses derivados sejam
diretos, exigindo apenas alguns cálculos básicos, para modelos complexos, trabalhando as atu-
alizações manualmente pode ser uma tarefa difícil (e muitas vezes sujeita a erros). Frameworks
de Deep learning aceleram este trabalho calculando automaticamente as derivadas, ou seja, difer-
enciação automática. Na prática, com base em nosso modelo projetado o sistema constrói um
grafo computacional, rastreando quais dados combinados por meio de quais operações produzem
a saída. A diferenciação automática permite que o sistema propague gradientes posteriormente.
Aqui, propagar(do Inglês backpropagate) significa simplesmente traçar o gráfico computacional,
preencher as derivadas parciais em relação a cada parâmetro.
25
https://discuss.d2l.ai/t/33

2.5. Diferenciação automática 75


2.5.1 Um exemplo simples

Como exemplo, digamos que estamos interessados em derivar a função y = 2x⊤ x com respeito ao
vetor coluna x. Inicialmente criamos a variável x e atribuimos a ela um valor inicial.

import torch

x = torch.arange(4.0)
x

tensor([0., 1., 2., 3.])

Antes de calcularmos o gradiente dey em relação a x, precisamos armazena-lo. É importante que


não aloquemos nova memória cada vez que tomamos uma derivada em relação a um parâmetro
porque costumamos atualizar os mesmos parâmetros milhares ou milhões de vezes e podemos
rapidamente ficar sem memória. Observe que um gradiente de uma função com valor escalar
com respeito a um vetor x tem valor vetorial e tem a mesma forma de x.

x.requires_grad_(True) # Same as `x = torch.arange(4.0, requires_grad=True)`


x.grad # O valor padrão é None

Então calcularemos y.

y = 2 * torch.dot(x, x)
y

tensor(28., grad_fn=<MulBackward0>)

Uma vez que x é um vetor de comprimento 4, um produto interno de x ex é realizado, produzindo


a saída escalar que atribuímos a y. Em seguida, podemos calcular automaticamente o gradiente
de y com relação a cada componente de x chamando a função de retropropagação e imprimindo
o gradiente.

y.backward()
x.grad

tensor([ 0., 4., 8., 12.])

O gradiente da função y = 2x⊤ x em relação a x should be 4x. Vamos verificar rapidamente se


nosso gradiente desejado foi calculado corretamente.

x.grad == 4 * x

tensor([True, True, True, True])

Agora calculamos outra função de x.

# O PyTorch acumula os gradientes por padrão, precisamos


# apagar os valores anteriores
(continues on next page)

76 Chapter 2. Preliminares
(continued from previous page)

x.grad.zero_()
y = x.sum()
y.backward()
x.grad

tensor([1., 1., 1., 1.])

2.5.2 Retroceder para variáveis não escalares

Tecnicamente, quando y não é um escalar, a interpretação mais natural da diferenciação de um


vetor y em relação a um vetor, x é uma matriz. Para y ex de ordem superior e dimensão superior,
o resultado da diferenciação pode ser um tensor de ordem alta.
No entanto, embora esses objetos mais exóticos apareçam em aprendizado de máquina avançado
(incluindo em Deep Learning), com mais frequência quando estamos retrocedendo um vetor, es-
tamos tentando calcular as derivadas das funções de perda para cada constituinte de um lote de
exemplos de treinamento. Aqui, nossa intenção é não calcular a matriz de diferenciação mas sim
a soma das derivadas parciais calculado individualmente para cada exemplo no lote.

# Invocar `backward` em um não escalar requer passar um argumento `gradient`


# que especifica o gradiente da função diferenciada w.r.t `self`.
# Em nosso caso, simplesmente queremos somar as derivadas parciais, assim passando
# em um gradiente de uns é apropriado
x.grad.zero_()
y = x * x
# y.backward(torch.ones(len(x))) equivalente a:
y.sum().backward()
x.grad

tensor([0., 2., 4., 6.])

2.5.3 Computação Detaching

Às vezes, desejamos mover alguns cálculos fora do gráfico computacional registrado. Por exem-
plo, digamos que y foi calculado como uma função dex, e que subsequentemente z foi calculado
como uma função dey e x. Agora, imagine que quiséssemos calcular o gradiente de z em relação
ax, mas queria, por algum motivo, tratar y como uma constante, e apenas leve em consideração
a função que x jogou apósy foi calculado. Aqui, podemos desanexar y para retornar uma nova
variável u que tem o mesmo valor que y, mas descarta qualquer informação sobre como y foi cal-
culado no grafo computacional. Em outras palavras, o gradiente não fluirá de volta de u para x.
Assim, a seguinte função de retropropagação calcula a derivada parcial de z = u * x com respeito
ax enquanto trata u como uma constante, em vez da derivada parcial de z = x * x * x em relação
ax.

x.grad.zero_()
y = x * x
(continues on next page)

2.5. Diferenciação automática 77


(continued from previous page)
u = y.detach()
z = u * x

z.sum().backward()
x.grad == u

tensor([True, True, True, True])

Uma vez que o cálculo de y foi registrado, podemos subsequentemente invocar a retropropagação
em y para obter a derivada dey = x * x com respeito a x, que é2 * x.

x.grad.zero_()
y.sum().backward()
x.grad == 2 * x

tensor([True, True, True, True])

2.5.4 Computando o Gradiente do Python Control Flow

Uma vantagem de usar a diferenciação automática é que mesmo se construir o gráfo computa-
cional de uma função requer muito trabalho com o uso do Python Control Flow (por exemplo,
condicionais, loops e chamadas de função arbitrárias), ainda podemos calcular o gradiente da
variável resultante. No trecho a seguir, observe que o número de iterações do loop while e a avali-
ação da instrução if ambos dependem do valor da entrada a.

def f(a):
b = a * 2
while b.norm() < 1000:
b = b * 2
if b.sum() > 0:
c = b
else:
c = 100 * b
return c

Vamos computar o gradiente:

a = torch.randn(size=(), requires_grad=True)
d = f(a)
d.backward()

Agora podemos analisar a função f definida acima. Observe que é linear por partes em sua entrada
a. Em outras palavras, para qualquer a existe algum escalar constantek tal que f (a) = k * a, onde
o valor dek depende da entrada a. Consequentemente, d / a nos permite verificar se o gradiente
está correto.

a.grad == d / a

78 Chapter 2. Preliminares
tensor(True)

2.5.5 Sumário

• Frameworks de Deep learning podem automatizar o cálculo de derivadas. Para usá-lo,


primeiro anexamos gradientes às variáveis em relação às quais desejamos as derivadas par-
ciais. Em seguida, registramos o cálculo de nosso valor alvo, executamos sua função para
retropropagação e acessamos o gradiente resultante.

2.5.6 Exercícios

1. Por que a segunda derivada é muito mais computacionalmente cara de se calcular do que a
primeira derivada?
2. Depois de executar a função de retropropagação, execute-a imediatamente novamente e veja
o que acontece.
3. No exemplo de fluxo de controle onde calculamos a derivada de d com respeito a a, o que
aconteceria se mudássemos a variável a para um vetor ou matriz aleatória. Neste ponto, o
resultado do cálculo f (a) não é mais um escalar. O que acontece com o resultado? Como
analisamos isso?
4. Redesenhe um exemplo para encontrar o gradiente do Control Flow. Execute e analise o
resultado.
5. Seja f (x) = sin(x). Plote f (x) e f racdf (x)dx, onde o último é calculado sem explorar que
f ′ (x) = cos(x).
Discussions26

2.6 Probabilidade

De uma forma ou de outra, o aprendizado de máquina envolve fazer previsões. Podemos querer
prever a probabilidade de um paciente sofrer um ataque cardíaco no próximo ano, considerando
seu histórico clínico. Na detecção de anomalias, podemos avaliar quão provável seria um conjunto
de leituras do motor a jato de um avião, se ele estivesse operando normalmente. Na aprendizagem
por reforço, queremos que um agente aja de forma inteligente em um ambiente. Isso significa
que precisamos pensar sobre a probabilidade de obter uma alta recompensa em cada uma das
ações disponíveis. E quando construímos sistemas de recomendação, também precisamos pen-
sar sobre probabilidade. Por exemplo, diga hipoteticamente que trabalhamos para uma grande
livraria online. Podemos querer estimar a probabilidade de um determinado usuário comprar
um determinado livro. Para isso, precisamos usar a linguagem da probabilidade. Cursos inteiros,
graduações, teses, carreiras e até departamentos são dedicados à probabilidade. Então, natural-
mente, nosso objetivo nesta seção não é ensinar todo o assunto. Em vez disso, esperamos fazer
você decolar, ensinar apenas o suficiente para que você possa começar a construir seus primeiros
modelos de Deep Learning e dar-lhe um sabor suficiente para o assunto que você pode começar a
explorá-lo por conta própria, se desejar.
26
https://discuss.d2l.ai/t/35

2.6. Probabilidade 79
Já invocamos as probabilidades nas seções anteriores, sem articular o que são precisamente ou
dar um exemplo concreto. Vamos ser mais sérios agora, considerando o primeiro caso: distinguir
cães e gatos com base em fotografias. Isso pode parecer simples, mas na verdade é um desafio
formidável. Para começar, a dificuldade do problema pode depender da resolução da imagem.

Fig. 2.6.1: Imagens de diferentes resoluções (10 × 10, 20 × 20, 40 × 40, 80 × 80, e 160 × 160 pixels).

Conforme mostrado em Fig. 2.6.1, embora seja fácil para os humanos reconhecerem cães e gatos
na resolução de 160 × 160 pixels, torna-se um desafio em 40 × 40 pixels e quase impossível em
10 × 10 pixels. Em outras palavras, nossa capacidade de distinguir cães e gatos a uma grande dis-
tância (e, portanto, em baixa resolução) pode se aproximar de uma suposição desinformada. A
probabilidade nos dá um maneira formal de raciocinar sobre nosso nível de certeza. Se tivermos
certeza absoluta que a imagem representa um gato, dizemos que a probabilidade de que o rótulo y
correspondente seja “cat”, denotado P (y = “cat”) é igual a 1. Se não tivéssemos nenhuma evidên-
cia para sugerir que y = “cat” ou que y = “dog”, então poderíamos dizer que as duas possibilidades
eram igualmente provavelmente expressando isso como P (y = “cat”) = P (y = “dog”) = 0.5. Se es-
tivéssemos razoavelmente confiantes, mas não temos certeza de que a imagem representava um
gato, podemos atribuir um probabilidade $0,5 <P (y = "cat") <1$.
Agora considere o segundo caso: dados alguns dados de monitoramento do tempo, queremos
prever a probabilidade de que choverá em Taipei amanhã. Se for verão, a chuva pode vir com
probabilidade 0,5.
Em ambos os casos, temos algum valor de interesse. E em ambos os casos não temos certeza sobre
o resultado. Mas existe uma diferença fundamental entre os dois casos. Neste primeiro caso, a
imagem é de fato um cachorro ou um gato, e simplesmente não sabemos qual. No segundo caso, o
resultado pode realmente ser um evento aleatório, se você acredita em tais coisas (e a maioria dos
físicos acredita). Portanto, probabilidade é uma linguagem flexível para raciocinar sobre nosso
nível de certeza e pode ser aplicada com eficácia em um amplo conjunto de contextos.

80 Chapter 2. Preliminares
2.6.1 Teoria Básica de Probabilidade

Digamos que lançamos um dado e queremos saber qual é a chance de ver um 1 em vez de outro
dígito. Se o dado for justo, todos os seis resultados {1, . . . , 6} têm a mesma probabilidade de ocor-
rer e, portanto, veríamos 1 em um dos seis casos. Formalmente afirmamos que 1 ocorre com
probabilidade 61 .
Para um dado real que recebemos de uma fábrica, podemos não saber essas proporções e pre-
cisaríamos verificar se ele está contaminado. A única maneira de investigar o dado é lançando-o
várias vezes e registrando os resultados. Para cada lançamento do dado, observaremos um valor
em {1, . . . , 6}. Dados esses resultados, queremos investigar a probabilidade de observar cada re-
sultado.
Uma abordagem natural para cada valor é pegar o contagem individual para aquele valor e dividi-
lo pelo número total de jogadas. Isso nos dá uma estimativa da probabilidade de um determinado
evento. A lei de grandes números nos dizem que, conforme o número de lançamentos aumenta, essa
estimativa se aproxima cada vez mais da verdadeira probabilidade subjacente. Antes de entrar em
detalhes sobre o que está acontecendo aqui, vamos experimentar.
Para começar, importemos os pacotes necessários.

%matplotlib inline
import torch
from torch.distributions import multinomial
from d2l import torch as d2l

Em seguida, queremos ser capazes de lançar o dado. Nas estatísticas, chamamos este processo
de colher exemplos de amostragem de distribuições de probabilidade . A distribuição que atribui
probabilidades a uma série de escolhas discretas é chamado de distribuição multinomial. Daremos
uma definição mais formal de distribuição mais tarde, mas em um alto nível, pense nisso como
apenas uma atribuição de probabilidades para eventos.
Para obter uma única amostra, simplesmente passamos um vetor de probabilidades. A saída é
outro vetor do mesmo comprimento: seu valor no índice i é o número de vezes que o resultado da
amostragem corresponde a i.

fair_probs = torch.ones([6]) / 6
multinomial.Multinomial(1, fair_probs).sample()

tensor([0., 0., 0., 0., 1., 0.])

Se você executar o amostrador várias vezes, descobrirá que sai aleatoriamente valores de cada
vez. Tal como acontece com a estimativa da justiça de um dado, muitas vezes queremos gerar
muitas amostras da mesma distribuição. Seria insuportavelmente lento para fazer isso com um
loop Python for, então a função que estamos usando suporta gerar várias amostras de uma vez,
retornando uma matriz de amostras independentes em qualquer forma podemos desejar.

multinomial.Multinomial(10, fair_probs).sample()

tensor([0., 4., 1., 1., 2., 2.])

Agora que sabemos como obter amostras de um dado, podemos simular 1000 execuções. Podemos

2.6. Probabilidade 81
então passar e contar, após cada um dos 1000 lançamentos, quantas vezes cada número foi rolado.
Especificamente, calculamos a frequência relativa como a estimativa da probabilidade verdadeira.

# Store the results as 32-bit floats for division


counts = multinomial.Multinomial(1000, fair_probs).sample()
counts / 1000 # Relative frequency as the estimate

tensor([0.1830, 0.1600, 0.1660, 0.1380, 0.1570, 0.1960])

Como geramos os dados de um dado justo, sabemos que cada resultado tem probabilidade real 16 ,
cerca de 0, 167, portanto, as estimativas de saída acima parecem boas.
Também podemos visualizar como essas probabilidades convergem ao longo do tempo para a
probabilidade verdadeira. Vamos conduzir 500 grupos de experimentos onde cada grupo extrai
10 amostras.

counts = multinomial.Multinomial(10, fair_probs).sample((500,))


cum_counts = counts.cumsum(dim=0)
estimates = cum_counts / cum_counts.sum(dim=1, keepdims=True)

d2l.set_figsize((6, 4.5))
for i in range(6):
d2l.plt.plot(estimates[:, i].numpy(),
label=("P(die=" + str(i + 1) + ")"))
d2l.plt.axhline(y=0.167, color='black', linestyle='dashed')
d2l.plt.gca().set_xlabel('Groups of experiments')
d2l.plt.gca().set_ylabel('Estimated probability')
d2l.plt.legend();

Cada curva sólida corresponde a um dos seis valores do dado e dá nossa probabilidade estimada de

82 Chapter 2. Preliminares
que o dado aumente esse valor conforme avaliado após cada grupo de experimentos. A linha preta
tracejada fornece a verdadeira probabilidade subjacente. À medida que obtemos mais dados con-
duzindo mais experimentos, as curvas sólidas de 6 convergem para a probabilidade verdadeira.

Axiomas da Teoria de Probabilidade

Ao lidar com as jogadas de um dado, chamamos o conjunto S = {1, 2, 3, 4, 5, 6} o espaço de amostra


ou espaço de resultado, onde cada elemento é um resultado. Um evento é um conjunto de resulta-
dos de um determinado espaço amostral. Por exemplo, “ver 5” ({5}) e “ver um número ímpar”
({1, 3, 5}) são eventos válidos de lançar um dado. Observe que se o resultado de um experimento
aleatório estiver no evento A, então o evento A ocorreu. Ou seja, se 3 pontos virados para cima
após rolar um dado, uma vez que 3 ∈ {1, 3, 5}, podemos dizer que o evento “ver um número ímpar”
ocorreu.
Formalmente, probabilidade pode ser pensada como uma função que mapeia um conjunto para
um valor real. A probabilidade de um evento A no espaço amostral dado S, denotado como P (A),
satisfaz as seguintes propriedades:
• Para qualquer evento A, sua probabilidade nunca é negativa, ou seja, P (A) ≥ 0;
• A probabilidade de todo o espaço amostral é 1, ou seja, P (S) = 1;
• Para qualquer sequência contável de eventos A1 , A2 , . . . que são mutuamente exclusivos
(Ai ∩ Aj = ∅ para todo i ̸= j), a probabilidade
∪∞ de que aconteça é igual à soma de suas

probabilidades individuais, ou seja, P ( i=1 Ai ) = ∞i=1 P (Ai ).

Esses também são os axiomas da teoria das probabilidades, propostos por Kolmogorov em 1933.
Graças a este sistema de axiomas, podemos evitar qualquer disputa filosófica sobre aleatoriedade;
em vez disso, podemos raciocinar rigorosamente com uma linguagem matemática. Por exemplo,
permitindo que o evento A1 seja todo o espaço da amostra e Ai = ∅ para todos i > 1, podemos
provar que P (∅) = 0, ou seja, a probabilidade de um evento impossível é 0.

Variáveis Aleatórias

Em nosso experimento aleatório de lançar um dado, introduzimos a noção de uma variável


aleatória. Uma variável aleatória pode ser praticamente qualquer quantidade e não é determinís-
tica. Pode assumir um valor entre um conjunto de possibilidades em um experimento aleatório.
Considere uma variável aleatória X cujo valor está no espaço amostral S = {1, 2, 3, 4, 5, 6} do
lançamento de um dado. Podemos denotar o evento “vendo 5” como {X = 5} ou X = 5, e sua
probabilidade como P ({X = 5}) ou P (X = 5). Por P (X = a), fazemos uma distinção entre a var-
iável aleatória X e os valores (por exemplo, a) que X pode assumir. No entanto, esse pedantismo
resulta em uma notação complicada. Para uma notação compacta, por um lado, podemos apenas
denotar P (X) como a distribuição sobre a variável aleatória X: a distribuição nos diz a probabili-
dade de que X assuma qualquer valor. Por outro lado, podemos simplesmente escrever P (a) para
denotar a probabilidade de uma variável aleatória assumir o valor a. Uma vez que um evento na
teoria da probabilidade é um conjunto de resultados do espaço amostral, podemos especificar um
intervalo de valores para uma variável aleatória assumir. Por exemplo, P (1 ≤ X ≤ 3) denota a
probabilidade do evento {1 ≤ X ≤ 3}, o que significa {X = 1, 2, or, 3}. De forma equivalente,
{X = 1, 2, or, 3} representa a probabilidade de que a variável aleatória X possa assumir um valor
de {1, 2, 3}.
Observe que há uma diferença sutil entre variáveis aleatórias discretas, como os lados de um
dado, e contínuas, como o peso e a altura de uma pessoa. Não adianta perguntar se duas pes-

2.6. Probabilidade 83
soas têm exatamente a mesma altura. Se tomarmos medidas precisas o suficiente, você desco-
brirá que duas pessoas no planeta não têm exatamente a mesma altura. Na verdade, se fiz-
ermos uma medição suficientemente precisa, você não terá a mesma altura ao acordar e ao
dormir. Portanto, não há nenhum propósito em perguntar sobre a probabilidade que alguém
tem 1,80139278291028719210196740527486202 metros de altura. Dada a população mundial de hu-
manos, a probabilidade é virtualmente 0. Faz mais sentido, neste caso, perguntar se a altura de
alguém cai em um determinado intervalo, digamos entre 1,79 e 1,81 metros. Nesses casos, quan-
tificamos a probabilidade de vermos um valor como uma densidade. A altura de exatamente 1,80
metros não tem probabilidade, mas densidade diferente de zero. No intervalo entre quaisquer
duas alturas diferentes, temos probabilidade diferente de zero. No restante desta seção, consider-
amos a probabilidade no espaço discreto. Para probabilidade sobre variáveis aleatórias contínuas,
você pode consultar Section 18.6.

2.6.2 Lidando com Múltiplas Variáveis Aleatórias

Muitas vezes, queremos considerar mais de uma variável aleatória de cada vez. Por exemplo,
podemos querer modelar a relação entre doenças e sintomas. Dados uma doença e um sintoma,
digamos “gripe” e “tosse”, podem ou não ocorrer em um paciente com alguma probabilidade.
Embora esperemos que a probabilidade de ambos seja próxima de zero, podemos estimar essas
probabilidades e suas relações entre si para que possamos aplicar nossas inferências para obter
um melhor atendimento médico.
Como um exemplo mais complicado, as imagens contêm milhões de pixels, portanto, milhões de
variáveis aleatórias. E, em muitos casos, as imagens vêm com um rótulo, identificando objetos
na imagem. Também podemos pensar no rótulo como um variável aleatória. Podemos até pen-
sar em todos os metadados como variáveis aleatórias como local, tempo, abertura, comprimento
focal, ISO, distância de foco e tipo de câmera. Todas essas são variáveis aleatórias que ocorrem
em conjunto. Quando lidamos com múltiplas variáveis aleatórias, existem várias quantidades de
interesse.

Probabilidade Conjunta

O primeiro é chamado de probabilidade conjunta P (A = a, B = b). Dados quaisquer valores a e


b, a probabilidade conjunta nos permite responder, qual é a probabilidade de que A = a e B = b
simultaneamente? Observe que, para quaisquer valores a e b, P (A = a, B = b) ≤ P (A = a). Tem
de ser este o caso, visto que para A = a e B = b acontecer, A = a tem que acontecer e B = b
também tem que acontecer (e vice-versa). Assim, A = a e B = b não podem ser mais prováveis
do que A = a ou B = b individualmente.

Probabilidade Condicional

Isso nos leva a uma razão interessante: 0 ≤ P (A=a,B=b)


P (A=a) ≤ 1. Chamamos essa proporção de prob-
abilidade condicional e denotá-lo por P (B = b | A = a): é a probabilidade de B = b, desde que
A = a ocorreu.

84 Chapter 2. Preliminares
Teorema de Bayes

Usando a definição de probabilidades condicionais, podemos derivar uma das equações mais úteis
e celebradas em estatística: Teorema de Bayes. Por construção, temos a regra de multiplicação que
P (A, B) = P (B | A)P (A). Por simetria, isso também é válido para P (A, B) = P (A | B)P (B).
Suponha que P (B) > 0. Resolvendo para uma das variáveis condicionais, obtemos

P (B | A)P (A)
P (A | B) = . (2.6.1)
P (B)

Observe que aqui usamos a notação mais compacta em que P (A, B) é uma distribuição conjunta
e P (A | B) é uma distribuição condicional. Essas distribuições podem ser avaliadas para valores
particulares A = a, B = b.

Marginalização

O teorema de Bayes é muito útil se quisermos inferir uma coisa da outra, digamos causa e efeito,
mas só conhecemos as propriedades na direção reversa, como veremos mais adiante nesta seção.
Uma operação importante de que precisamos para fazer esse trabalho é a marginalização. É a
operação de determinar P (B) de P (A, B). Podemos ver que a probabilidade de B equivale a con-
tabilizar todas as escolhas possíveis de A e agregar as probabilidades conjuntas de todas elas:

P (B) = P (A, B), (2.6.2)
A

que também é conhecida como regra da soma. A probabilidade ou distribuição como resultado da
marginalização é chamada de probabilidade marginal ou distribuição marginal.

Independencia

Outra propriedade útil para verificar é dependência vs. independência. Duas variáveis aleatórias
A e B sendo independentes significa que a ocorrência de um evento de A não revela nenhuma
informação sobre a ocorrência de um evento de B. Neste caso P (B | A) = P (B). Os estatísticos
normalmente expressam isso como A ⊥ B. Do teorema de Bayes, segue imediatamente que
também P (A | B) = P (A). Em todos os outros casos, chamamos A e B de dependente. Por
exemplo, duas jogadas sucessivas de um dado são independentes. Em contraste, a posição de um
interruptor de luz e a luminosidade da sala não são (eles não são perfeitamente determinísticos,
pois podemos sempre ter uma lâmpada quebrada, falha de energia ou um interruptor quebrado).
Dado que P (A | B) = PP(A,B)
(B) = P (A) é equivalente a P (A, B) = P (A)P (B), duas variáveis
aleatórias são independentes se e somente se sua distribuição conjunta é o produto de suas dis-
tribuições individuais. Da mesma forma, duas variáveis aleatórias A e B são condicionalmente
independentes dada outra variável aleatória C se e somente se P (A, B | C) = P (A | C)P (B | C).
Isso é expresso como A ⊥ B | C.

2.6. Probabilidade 85
Aplicação

Vamos colocar nossas habilidades à prova. Suponha que um médico administre um teste de HIV
a um paciente. Este teste é bastante preciso e falha apenas com 1% de probabilidade se o paciente
for saudável, mas relatá-lo como doente. Além disso, nunca deixa de detectar o HIV se o paciente
realmente o tiver. Usamos D1 para indicar o diagnóstico (1 se positivo e 0 se negativo) e H para de-
notar o estado de HIV (1 se positivo e 0 se negativo). conditional_prob_D1 lista tais probabilidades
condicionais. : Probabilidade condicional de P (D1 | H).

Table 2.6.1: label:conditional_prob_D1


Probabilidade Condicional H = 1 H = 0
P (D1 = 1 | H) 1 0.01
P (D1 = 0 | H) 0 0.99

Observe que as somas das colunas são todas 1 (mas as somas das linhas não), uma vez que a prob-
abilidade condicional precisa somar 1, assim como a probabilidade. Vamos calcular a probabili-
dade de o paciente ter HIV se o teste der positivo, ou seja, P (H = 1 | D1 = 1). Obviamente, isso
vai depender de quão comum é a doença, já que afeta o número de alarmes falsos. Suponha que
a população seja bastante saudável, por exemplo, P (H = 1) = 0.0015. Para aplicar o teorema de
Bayes, precisamos aplicar a marginalização e a regra de multiplicação para determinar
P (D1 = 1)
=P (D1 = 1, H = 0) + P (D1 = 1, H = 1)
(2.6.3)
=P (D1 = 1 | H = 0)P (H = 0) + P (D1 = 1 | H = 1)P (H = 1)
=0.011485.
Portanto, obtemos:
P (H = 1 | D1 = 1)
P (D1 = 1 | H = 1)P (H = 1)
= . (2.6.4)
P (D1 = 1)
=0.1306

Em outras palavras, há apenas 13,06% de chance de que o paciente realmente tem HIV, apesar de
usar um teste muito preciso. Como podemos ver, a probabilidade pode ser contra-intuitiva.
O que o paciente deve fazer ao receber notícias tão terríveis? Provavelmente, o paciente pediria
ao médico para administrar outro teste para obter clareza. O segundo teste tem características
diferentes e não é tão bom quanto o primeiro, como mostrado em :numref:conditional_prob_D2`.

Table 2.6.2: Probabilidade Condicional de P (D2 | H).


Probabilidade Condicional H = 1 H = 0
P (D2 = 1 | H) 0.98 0.03
P (D2 = 0 | H) 0.02 0.97

Infelizmente, o segundo teste também deu positivo. Vamos trabalhar as probabilidades


necessárias para invocar o teorema de Bayes assumindo a independência condicional:
P (D1 = 1, D2 = 1 | H = 0)
=P (D1 = 1 | H = 0)P (D2 = 1 | H = 0) (2.6.5)
=0.0003,

86 Chapter 2. Preliminares
P (D1 = 1, D2 = 1 | H = 1)
=P (D1 = 1 | H = 1)P (D2 = 1 | H = 1) (2.6.6)
=0.98.
Agora podemos aplicar a marginalização e a regra de multiplicação:

P (D1 = 1, D2 = 1)
=P (D1 = 1, D2 = 1, H = 0) + P (D1 = 1, D2 = 1, H = 1)
(2.6.7)
=P (D1 = 1, D2 = 1 | H = 0)P (H = 0) + P (D1 = 1, D2 = 1 | H = 1)P (H = 1)
=0.00176955.

No final, a probabilidade de o paciente ter HIV, dado ambos os testes positivos, é

P (H = 1 | D1 = 1, D2 = 1)
P (D1 = 1, D2 = 1 | H = 1)P (H = 1)
= (2.6.8)
P (D1 = 1, D2 = 1)
=0.8307.

Ou seja, o segundo teste nos permitiu ganhar uma confiança muito maior de que nem tudo está
bem. Apesar do segundo teste ser consideravelmente menos preciso do que o primeiro, ele ainda
melhorou significativamente nossa estimativa.

2.6.3 Expectativa e Variância

Para resumir as principais características das distribuições de probabilidade, precisamos de al-


gumas medidas. A expectativa (ou média) da variável aleatória X é denotada como

E[X] = xP (X = x). (2.6.9)
x

Quando a entrada de uma função f (x) é uma variável aleatória retirada da distribuição P com
valores diferentes x, a expectativa de f (x) é calculada como

Ex∼P [f (x)] = f (x)P (x). (2.6.10)
x

Em muitos casos, queremos medir o quanto a variável aleatória X se desvia de sua expectativa.
Isso pode ser quantificado pela variação
[ ]
Var[X] = E (X − E[X])2 = E[X 2 ] − E[X]2 . (2.6.11)

Sua raiz quadrada é chamada de desvio padrão. A variância de uma função de uma variável
aleatória mede pelo quanto a função se desvia da expectativa da função, como diferentes valores
x da variável aleatória são amostrados de sua distribuição:
[ ]
Var[f (x)] = E (f (x) − E[f (x)])2 . (2.6.12)

2.6. Probabilidade 87
2.6.4 Sumário

• Podemos obter amostras de distribuições de probabilidade.


• Podemos analisar múltiplas variáveis aleatórias usando distribuição conjunta, distribuição
condicional, teorema de Bayes, marginalização e suposições de independência.
• A expectativa e a variância oferecem medidas úteis para resumir as principais características
das distribuições de probabilidade.

2.6.5 Exercícios

1. Conduzimos m = 500 grupos de experimentos onde cada grupo extrai n = 10 amostras.


Varie m e n. Observe e analise os resultados experimentais.
2. Dados dois eventos com probabilidade P (A) e P (B), calcule os limites superior e inferior
em P (A ∪ B) e P (A ∩ B). (Dica: exiba a situação usando um Diagrama de Venn27 .)
3. Suponha que temos uma sequência de variáveis aleatórias, digamos A, B e C, onde B de-
pende apenas de A e C depende apenas de B, você pode simplificar a probabilidade conjunta
P (A, B, C)? (Dica: esta é uma Cadeia de Markov28 .)
4. Em Section 2.6.2, o primeiro teste é mais preciso. Por que não executar o primeiro teste duas
vezes em vez de executar o primeiro e o segundo testes?
Discussão29

2.7 Documentação

Devido a restrições na extensão deste livro, não podemos apresentar todas as funções e classes do
PyTorch (e você provavelmente não gostaria que o fizéssemos). A documentação da API e os tutori-
ais e exemplos adicionais fornecem muita documentação além do livro. Nesta seção, fornecemos
algumas orientações para explorar a API PyTorch.

2.7.1 Encontrando Todas as Funções e Classes em um Módulo

Para saber quais funções e classes podem ser chamadas em um módulo, nós invoque a função dir.
Por exemplo, podemos consultar todas as propriedades no módulo para gerar números aleatórios:

import torch

print(dir(torch.distributions))

['AbsTransform', 'AffineTransform', 'Bernoulli', 'Beta', 'Binomial', 'CatTransform


,→', 'Categorical', 'Cauchy', 'Chi2', 'ComposeTransform', 'ContinuousBernoulli',
,→'CorrCholeskyTransform', 'Dirichlet', 'Distribution', 'ExpTransform', 'Exponential',

,→'ExponentialFamily', 'FisherSnedecor', 'Gamma', 'Geometric', 'Gumbel', 'HalfCauchy',

,→'HalfNormal', 'Independent', 'IndependentTransform', 'Kumaraswamy', 'LKJCholesky', 'Laplace


,→', 'LogNormal', 'LogisticNormal', 'LowRankMultivariateNormal', 'LowerCholeskyTransform
(continues on next page)
', 'MixtureSameFamily', 'Multinomial', 'MultivariateNormal', 'NegativeBinomial',
,→27
https://en.wikipedia.org/wiki/Venn_diagram
'Normal', 'OneHotCategorical', 'OneHotCategoricalStraightThrough', 'Pareto', 'Poisson
,→28
https://en.wikipedia.org/wiki/Markov_chain
',https://discuss.d2l.ai/t/37
,→29 'PowerTransform', 'RelaxedBernoulli', 'RelaxedOneHotCategorical', 'ReshapeTransform
,→', 'SigmoidTransform', 'SoftmaxTransform', 'StackTransform', 'StickBreakingTransform',

,→'StudentT', 'TanhTransform', 'Transform', 'TransformedDistribution', 'Uniform', 'VonMises


88 Chapter 2.'__loader_
,→', 'Weibull', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', Preliminares
,→_', '__name__', '__package__', '__path__', '__spec__', 'bernoulli', 'beta', 'biject_
,→to', 'binomial', 'categorical', 'cauchy', 'chi2', 'constraint_registry', 'constraints
(continued from previous page)

Geralmente, podemos ignorar funções que começam e terminam com __ (objetos especiais em
Python) ou funções que começam com um único _ (normalmente funções internas). Com base nos
nomes de funções ou atributos restantes, podemos arriscar um palpite de que este módulo oferece
vários métodos para gerar números aleatórios, incluindo amostragem da distribuição uniforme
(uniforme), distribuição normal (normal) e distribuição multinomial (multinomial).

2.7.2 Buscando o Uso de Funções e Classes Específicas

Para obter instruções mais específicas sobre como usar uma determinada função ou classe, pode-
mos invocar a função help. Como um exemplo, vamos explorar as instruções de uso para a função
ones dos tensores.

help(torch.ones)

Help on built-in function ones:

ones(...)
ones(*size, *, out=None, dtype=None, layout=torch.strided, device=None, requires_
,→grad=False) -> Tensor

Returns a tensor filled with the scalar value 1, with the shape defined
by the variable argument size.

Args:
size (int...): a sequence of integers defining the shape of the output␣
,→tensor.

Can be a variable number of arguments or a collection like a list or␣


,→tuple.

Keyword arguments:
out (Tensor, optional): the output tensor.
dtype (torch.dtype, optional): the desired data type of returned tensor.
Default: if None, uses a global default (see torch.set_default_tensor_
,→type()).

layout (torch.layout, optional): the desired layout of returned Tensor.


Default: torch.strided.
device (torch.device, optional): the desired device of returned tensor.
Default: if None, uses the current device for the default tensor type
(see torch.set_default_tensor_type()). device will be the CPU
for CPU tensor types and the current CUDA device for CUDA tensor types.
requires_grad (bool, optional): If autograd should record operations on the
returned tensor. Default: False.

Example::

>>> torch.ones(2, 3)
tensor([[ 1., 1., 1.],

2.7. Documentação 89
[ 1., 1., 1.]])

>>> torch.ones(5)
tensor([ 1., 1., 1., 1., 1.])
A partir da documentação, podemos ver que a função ones cria um novo tensor com a forma es-
pecificada e define todos os elementos com o valor de 1. Sempre que possível, você deve executar
um teste rápido para confirmar seu interpretação:

torch.ones(4)

tensor([1., 1., 1., 1.])

No bloco de notas Jupyter, podemos usar ? para exibir o documento em outra janela. Por exem-
plo, list? criará conteúdo que é quase idêntico a help(list), exibindo-o em um novo navegador
janela. Além disso, se usarmos dois pontos de interrogação, como list??, o código Python que
implementa a função também será exibido.

2.7.3 Sumário

• A documentação oficial fornece muitas descrições e exemplos que vão além deste livro.
• Podemos consultar a documentação para o uso de uma API chamando as funções dir ehelp,
ou ? E ?? em blocos de notas Jupyter.

2.7.4 Exercícios

1. Procure a documentação de qualquer função ou classe na estrutura de Deep Learning. Você


também pode encontrar a documentação no site oficial do framework?
Discussions30

30
https://discuss.d2l.ai/t/39

90 Chapter 2. Preliminares
3 | Linear Neural NetworkRedes Neu-
rais Lineares

Antes de entrarmos nos detalhes das redes neurais profundas, precisamos cobrir os fundamen-
tos do treinamento de redes neurais. Neste capítulo, cobriremos todo o processo de treinamento,
incluindo a definição de arquiteturas de redes neurais simples, manipulação de dados, especifi-
cação de uma função de perda e treinamento do modelo. Para tornar as coisas mais fáceis de en-
tender, começamos com os conceitos mais simples. Felizmente, técnicas clássicas de aprendiza-
gem estatística, como regressão linear e softmax podem ser lançadas como redes neurais lineares.
Partindo desses algoritmos clássicos, apresentaremos o básico, fornecendo a base para técnicas
mais complexas no restante do livro.

3.1 Linear Regression

Regression refers to a set of methods for modeling the relationship between one or more indepen-
dent variables and a dependent variable. In the natural sciences and social sciences, the purpose
of regression is most often to characterize the relationship between the inputs and outputs. Ma-
chine learning, on the other hand, is most often concerned with prediction.
Regression problems pop up whenever we want to predict a numerical value. Common exam-
ples include predicting prices (of homes, stocks, etc.), predicting length of stay (for patients in
the hospital), demand forecasting (for retail sales), among countless others. Not every prediction
problem is a classic regression problem. In subsequent sections, we will introduce classification
problems, where the goal is to predict membership among a set of categories.

3.1.1 Elementos Básicos de Regressão Linear

Regressão linear pode ser a mais simples e mais popular entre as ferramentas padrão para re-
gressão. Datado do início do século 19, A regressão linear flui a partir de algumas suposições
simples. Primeiro, assumimos que a relação entre as variáveis independentes x e a variável de-
pendente y é linear, ou seja, esse y pode ser expresso como uma soma ponderada dos elementos
em x, dado algum ruído nas observações. Em segundo lugar, assumimos que qualquer ruído é
bem comportado (seguindo uma distribuição gaussiana).
Para motivar a abordagem, vamos começar com um exemplo de execução. Suponha que dese-
jamos estimar os preços das casas (em dólares) com base em sua área (em pés quadrados) e idade
(em anos). Para realmente desenvolver um modelo para prever os preços das casas, precisaríamos
colocar as mãos em um conjunto de dados consistindo em vendas para as quais sabemos o preço
de venda, área e idade de cada casa. Na terminologia de machine learning, o conjunto de dados é

91
chamado de dataset de treinamento ou conjunto de treinamento, e cada linha (aqui os dados corre-
spondentes a uma venda) é chamado de exemplo (ou tupla, instância de dados, * amostra ). O que
estamos tentando prever (preço) é chamado de label* (ou rótulo). As variáveis independentes (idade e
área) em que as previsões são baseadas são chamadas de features (ou covariáveis).
Normalmente, usaremos n para denotar o número de exemplos em nosso conjunto de dados. Nós
indexamos os exemplos de dados por i, denotando cada entrada como x(i) = [x1 , x2 ]⊤ e o label
(i) (i)

correspondente como y (i) .

Modelo Linear

A suposição de linearidade apenas diz que o alvo (preço) pode ser expresso como uma soma pon-
derada das características (área e idade):

preço = wárea · área + widade · idade + b. (3.1.1)

In (3.1.1), $ w_{:raw-latex:`\mathrm{area}`}$ e wage são chamados de pesos e b é chamado de bias


(também chamado de deslocamento ou offset). Os pesos determinam a influência de cada feature
em nossa previsão e o bias apenas diz qual valor o preço previsto deve assumir quando todos os
features assumem o valor 0. Mesmo que nunca vejamos nenhuma casa com área zero, ou que têm
exatamente zero anos de idade, ainda precisamos do bias ou então vamos limitar a expressividade
do nosso modelo. Estritamente falando, (3.1.1) é uma transformação afim de features de entrada,
que é caracterizada por uma transformação linear de features via soma ponderada, combinada com
uma tradução por meio do bias adicionado.
Dado um dataset, nosso objetivo é escolher os pesos w e o bias b de modo que, em média, as pre-
visões feitas de acordo com nosso modelo se ajustem o melhor possível aos preços reais observa-
dos nos dados. Modelos cuja previsão de saída é determinada pela transformação afim de features
de entrada são modelos lineares, onde a transformação afim é especificada pelos pesos e bias escol-
hidos.
Em disciplinas onde é comum se concentrar em conjuntos de dados com apenas alguns features,
expressar explicitamente modelos de formato longo como esse é comum. No machine learning,
geralmente trabalhamos com datasets de alta dimensão, portanto, é mais conveniente empregar
a notação de álgebra linear. Quando nossas entradas consistem em d features, expressamos nossa
previsão ŷ (em geral, o símbolo “chapéu” ou “acento circunflexo” denota estimativas) como

ŷ = w1 x1 + ... + wd xd + b. (3.1.2)

Coletando todas as features em um vetor x ∈ Rd e todos os pesos em um vetor w ∈ Rd , podemos


expressar nosso modelo compactamente usando um produto escalar:

ŷ = w⊤ x + b. (3.1.3)

Em (3.1.3), o vetor x corresponde às features de um único exemplo de dados. Frequentemente


acharemos conveniente para se referir a recursos de todo o nosso dataset de n exemplos através
da matriz de design X ∈ Rn×d . Aqui, X contém uma linha para cada exemplo e uma coluna para
cada feature.
Para uma coleção de features X, as previsões ŷ ∈ Rn pode ser expresso por meio do produto matriz-
vetor:

ŷ = Xw + b, (3.1.4)

92 Chapter 3. Linear Neural NetworkRedes Neurais Lineares


onde a transmissão (veja Section 2.1.3) é aplicada durante o somatório. Dadas as features de um
dataset de treinamento X e labels correspondentes (conhecidos) y, o objetivo da regressão linear é
encontrar o vetor de pesos w e o termo de polarização b que dadas as features de um novo exemplo
de dados amostrado da mesma distribuição de X, o label do novo exemplo será (na expectativa)
previsto com o menor erro.
Mesmo se acreditarmos que o melhor modelo para predizer y dado x é linear, não esperaríamos
encontrar um dataset do mundo real de n exemplos onde y (i) é exatamente igual a w⊤ x(i) + b para
todos 1 ≤ i ≤ n. Por exemplo, quaisquer instrumentos que usarmos para observar as features X
e os labels y podem sofrer uma pequena quantidade de erro de medição. Assim, mesmo quando
estamos confiantes que a relação subjacente é linear, vamos incorporar um termo de ruído para
contabilizar esses erros.
Antes de começarmos a pesquisar os melhores parâmetros (ou parâmetros do modelo) w e b, pre-
cisaremos de mais duas coisas: (i) uma medida de qualidade para algum modelo dado; e (ii) um
procedimento de atualização do modelo para melhorar sua qualidade.

Função de Perda

Antes de começarmos a pensar sobre como ajustar os dados ao nosso modelo, precisamos deter-
minar uma medida de aptidão. A função de perda quantifica a distância entre o valor real e previsto
do target. A perda geralmente será um número não negativo onde valores menores são melhores
e previsões perfeitas incorrem em uma perda de 0. A função de perda mais popular em proble-
mas de regressão é o erro quadrático. Quando nossa previsão para um exemplo i é ŷ (i) e o *label
verdadeiro correspondente é y (i) , o quadrado do erro é dado por:
1 ( (i) )2
l(i) (w, b) = ŷ − y (i) . (3.1.5)
2
A constante 21 não faz diferença real mas será notacionalmente conveniente, cancelando quando
tomamos a derivada da perda. Como o conjunto de dados de treinamento é fornecido a nós e,
portanto, está fora de nosso controle, o erro empírico é apenas função dos parâmetros do modelo.
Para tornar as coisas mais concretas, considere o exemplo abaixo onde traçamos um problema
de regressão para um caso unidimensional como mostrado em Fig. 3.1.1.

Fig. 3.1.1: Fit data with a linear model.

Observe que grandes diferenças entre estimativas ŷ (i) e observações y (i) levam a contribuições
ainda maiores para a perda, devido à dependência quadrática. Para medir a qualidade de um

3.1. Linear Regression 93


modelo em todo o conjunto de dados de n exemplos, nós simplesmente calculamos a média (ou
equivalentemente, somamos) as perdas no conjunto de treinamento.

1 ∑ (i) 1 ∑ 1 ( ⊤ (i) )2
n n
L(w, b) = l (w, b) = w x + b − y (i) . (3.1.6)
n n 2
i=1 i=1

Ao treinar o modelo, queremos encontrar os parâmetros (w∗ , b∗ ) que minimizam a perda total em
todos os exemplos de treinamento:

w∗ , b∗ = argmin L(w, b). (3.1.7)


w,b

Solução Analítica

A regressão linear passa a ser um problema de otimização incomumente simples. Ao contrário


da maioria dos outros modelos que encontraremos neste livro, a regressão linear pode ser re-
solvida analiticamente aplicando uma fórmula simples. Para começar, podemos incluir o bias b
no parâmetro w anexando uma coluna à matriz de design que consiste em todas as unidades. En-
tão nosso problema de previsão é minimizar ∥y − Xw∥2 . Há apenas um ponto crítico na superfície
de perda e corresponde ao mínimo de perda em todo o domínio. Tirando a derivada da perda em
relação a w e defini-lo igual a zero produz a solução analítica (de forma fechada):

w∗ = (X⊤ X)−1 X⊤ y. (3.1.8)

Embora problemas simples como regressão linear podem admitir soluções analíticas, você não
deve se acostumar com essa boa sorte. Embora as soluções analíticas permitam uma boa análise
matemática, o requisito de uma solução analítica é tão restritivo que isso excluiria todo o deep
learning.

Gradiente Descendente Estocástico com Minibatch

Mesmo nos casos em que não podemos resolver os modelos analiticamente, acontece que ainda
podemos treinar modelos efetivamente na prática. Além disso, para muitas tarefas, aqueles mod-
elos difíceis de otimizar acabam sendo muito melhores do que descobrir como treiná-los acaba
valendo a pena.
A principal técnica para otimizar quase qualquer modelo de deep learning, e que recorreremos ao
longo deste livro, consiste em reduzir iterativamente o erro atualizando os parâmetros na direção
que diminui gradativamente a função de perda. Este algoritmo é denominado gradiente descen-
dente.
A aplicação mais ingênua de gradiente descendente consiste em obter a derivada da função de
perda, que é uma média das perdas calculadas em cada exemplo no dataset. Na prática, isso pode
ser extremamente lento: devemos passar por todo o conjunto de dados antes de fazer uma única
atualização. Assim, frequentemente nos contentaremos em amostrar um minibatch aleatório de
exemplos toda vez que precisamos calcular a atualização, uma variante chamada gradiente descen-
dente estocástico de minibatch.
Em cada iteração, primeiro amostramos aleatoriamente um minibatch B consistindo em um
número fixo de exemplos de treinamento. Em seguida, calculamos a derivada (gradiente) da perda
média no minibatch em relação aos parâmetros do modelo. Finalmente, multiplicamos o gradi-
ente por um valor positivo predeterminado η e subtraimos o termo resultante dos valores dos
parâmetros atuais.

94 Chapter 3. Linear Neural NetworkRedes Neurais Lineares


Podemos expressar a atualização matematicamente da seguinte forma (∂ denota a derivada par-
cial):
η ∑
(w, b) ← (w, b) − ∂(w,b) l(i) (w, b). (3.1.9)
|B|
i∈B

Para resumir, as etapas do algoritmo são as seguintes: (i) inicializamos os valores dos parâmet-
ros do modelo, normalmente de forma aleatória; (ii) amostramos iterativamente minibatches
aleatórios dos dados, atualizando os parâmetros na direção do gradiente negativo. Para perdas
quadráticas e transformações afins, podemos escrever isso explicitamente da seguinte maneira:
η ∑ η ∑ (i) ( ⊤ (i) )
w←w− ∂w l(i) (w, b) = w − x w x + b − y (i) ,
|B| |B|
i∈B i∈B
η ∑ (i) η ∑ ( ⊤ (i) ) (3.1.10)
b←b− ∂b l (w, b) = b − w x + b − y (i) .
|B| |B|
i∈B i∈B

Observe que w e x são vetores em (3.1.10). Aqui, a notação vetorial mais elegante torna
a matemática muito mais legível do que expressar coisas em termos de coeficientes, diga
w1 , w2 , . . . , wd . A cardinalidade definida |B| representa o número de exemplos em cada minibatch
(o tamanho do lote) e η denota a taxa de aprendizagem. Enfatizamos que os valores do tamanho do
lote e da taxa de aprendizagem são pré-especificados manualmente e normalmente não aprendi-
dos por meio do treinamento do modelo. Esses parâmetros são ajustáveis, mas não atualizados
no loop de treinamento são chamados de hiperparâmetros. Ajuste de hiperparâmetros é o processo
pelo qual os hiperparâmetros são escolhidos, e normalmente requer que os ajustemos com base
nos resultados do ciclo de treinamento conforme avaliado em um dataset de validação separado
(ou conjunto de validação).
Após o treinamento para algum número predeterminado de iterações (ou até que algum outro
critério de parada seja atendido), registramos os parâmetros estimados do modelo, denotado ŵ, b̂.
Observe que mesmo que nossa função seja verdadeiramente linear e sem ruídos, esses parâmetros
não serão os minimizadores exatos da perda porque, embora o algoritmo convirja lentamente para
os minimizadores, não pode alcançá-los exatamente em um número finito de etapas.
A regressão linear passa a ser um problema de aprendizagem onde há apenas um mínimo em todo
o domínio. No entanto, para modelos mais complicados, como redes profundas, as superfícies
de perda contêm muitos mínimos. Felizmente, por razões que ainda não são totalmente com-
preendidas, praticantes de deep learning raramente se esforçam para encontrar parâmetros que
minimizem a perda em conjuntos de treinamento. A tarefa mais formidável é encontrar parâmetros
que irão atingir baixa perda de dados que não vimos antes, um desafio chamado generalização.
Retornamos a esses tópicos ao longo do livro.

Fazendo Predições com o Modelo Aprendido

Dado o modelo de regressão linear aprendido ŵ⊤ x + b̂, agora podemos estimar o preço de uma
nova casa (não contido nos dados de treinamento) dada sua área x1 e idade x2 . Estimar labels dadas
as características é comumente chamado de predição ou inferência.
Tentaremos manter o termo predição porque chamando esta etapa de inferência, apesar de emergir
como jargão padrão no deep learning, é um nome impróprio. Em estatísticas, inferência denota
mais frequentemente estimar parâmetros com base em um conjunto de dados. Este uso indevido
de terminologia é uma fonte comum de confusão quando os profissionais de machine learning
conversam com os estatísticos.

3.1. Linear Regression 95


3.1.2 Vetorização para Velocidade

Ao treinar nossos modelos, normalmente queremos processar minibatches inteiros de exemplos


simultaneamente. Fazer isso de forma eficiente requer que nós vetorizar os cálculos e aproveitar
as bibliotecas de álgebra linear rápida em vez de escrever loops for custosos em Python.

%matplotlib inline
import math
import time
import numpy as np
import torch
from d2l import torch as d2l

Para ilustrar por que isso é tão importante, podemos considerer dois métodos para adicionar ve-
tores. Para começar, instanciamos dois vetores de 10000 dimensões contendo todos os outros.
Em um método, faremos um loop sobre os vetores com um loop for Python. No outro método,
contaremos com uma única chamada para +.

n = 10000
a = torch.ones(n)
b = torch.ones(n)

Uma vez que iremos comparar o tempo de execução com freqüência neste livro, vamos definir um
cronômetro.

class Timer: #@save


"""Record multiple running times."""
def __init__(self):
self.times = []
self.start()

def start(self):
"""Start the timer."""
self.tik = time.time()

def stop(self):
"""Stop the timer and record the time in a list."""
self.times.append(time.time() - self.tik)
return self.times[-1]

def avg(self):
"""Return the average time."""
return sum(self.times) / len(self.times)

def sum(self):
"""Return the sum of time."""
return sum(self.times)

def cumsum(self):
"""Return the accumulated time."""
return np.array(self.times).cumsum().tolist()

Agora podemos avaliar as cargas de trabalho. Primeiro, nós os adicionamos, uma coordenada por
vez, usando um loop for.

96 Chapter 3. Linear Neural NetworkRedes Neurais Lineares


c = torch.zeros(n)
timer = Timer()
for i in range(n):
c[i] = a[i] + b[i]
f'{timer.stop():.5f} sec'

'0.09436 sec'

Alternativamente, contamos com o operador recarregado + para calcular a soma elemento a ele-
mento.

timer.start()
d = a + b
f'{timer.stop():.5f} sec'

'0.00022 sec'

Você provavelmente percebeu que o segundo método é dramaticamente mais rápido que o
primeiro. A vetorização do código geralmente produz acelerações da ordem de magnitude. Além
disso, colocamos mais matemática na biblioteca e não precisamos escrever tantos cálculos nós
mesmos, reduzindo o potencial de erros.

3.1.3 A Distribuição Normal e Perda Quadrada

Embora você já possa sujar as mãos usando apenas as informações acima, a seguir, podemos mo-
tivar mais formalmente o objetivo de perda quadrado através de suposições sobre a distribuição
do ruído.
A regressão linear foi inventada por Gauss em 1795, que também descobriu a distribuição normal
(também chamada de Gaussiana). Acontece que a conexão entre a distribuição normal e regressão
linear é mais profunda do que o parentesco comum. Para refrescar sua memória, a densidade de
probabilidade de uma distribuição normal com média µ e variância σ 2 (desvio padrão σ) é dada
como
( )
1 1
p(x) = √ exp − 2 (x − µ) .
2
(3.1.11)
2πσ 2 2σ

Abaixo definimos uma função Python para calcular a distribuição normal.

def normal(x, mu, sigma):


p = 1 / math.sqrt(2 * math.pi * sigma**2)
return p * np.exp(-0.5 / sigma**2 * (x - mu)**2)

Podemos agora visualizar as distribuições normais.

# Use numpy again for visualization


x = np.arange(-7, 7, 0.01)

# Mean and standard deviation pairs


params = [(0, 1), (0, 2), (3, 1)]
(continues on next page)

3.1. Linear Regression 97


(continued from previous page)
d2l.plot(x, [normal(x, mu, sigma) for mu, sigma in params], xlabel='x',
ylabel='p(x)', figsize=(4.5, 2.5),
legend=[f'mean {mu}, std {sigma}' for mu, sigma in params])

Como podemos ver, mudar a média corresponde a uma mudança ao longo do eixo x, e aumentar
a variância espalha a distribuição, diminuindo seu pico.
Uma maneira de motivar a regressão linear com a função de perda de erro quadrático médio
(ou simplesmente perda quadrada) é assumir formalmente que as observações surgem de obser-
vações ruidosas, onde o ruído é normalmente distribuído da seguinte forma:

y = w⊤ x + b + ϵ onde ϵ ∼ N (0, σ 2 ). (3.1.12)

Assim, podemos agora escrever a probabilidade de ver um determinado y para um determinado x


via
( )
1 1 ⊤
P (y | x) = √ exp − 2 (y − w x − b) .2
(3.1.13)
2πσ 2 2σ
Agora, de acordo com o princípio da máxima verossimilhança (likelihood), os melhores valores
dos parâmetros w e b são os que maximizam a probabilidade de todo o conjunto de dados:

n
P (y | X) = p(y (i) |x(i) ). (3.1.14)
i=1

Estimadores escolhidos de acordo com o princípio da máxima verossimilhança são chamados


de estimadores de máxima verossimilhança. Enquanto, maximizando o produto de muitas funções
exponenciais, pode parecer difícil, podemos simplificar as coisas significativamente, sem alterar
o objetivo, maximizando o log da probabilidade em vez disso. Por razões históricas, as otimizações
são expressas com mais frequência como minimização em vez de maximização. Portanto, sem
alterar nada, podemos minimizar a probabilidade de log negativo − log P (y | X). Trabalhando a
matemática nos dá:
∑ 1 ( )2
n
1
− log P (y | X) = log(2πσ 2 ) + 2 y (i) − w⊤ x(i) − b . (3.1.15)
2 2σ
i=1

Agora, precisamos apenas mais uma suposição de que σ é alguma constante fixa. Assim, pode-
mos ignorar o primeiro termo porque não depende de w ou b. Agora, o segundo termo é idên-
tico à perda de erro quadrada introduzida anteriormente, exceto para a constante multiplicativa

98 Chapter 3. Linear Neural NetworkRedes Neurais Lineares


1
σ2
.
Felizmente, a solução não depende de σ. Segue-se que minimizar o erro quadrático médio é
equivalente a estimar a máxima verossimilhança de um modelo linear sob a suposição de ruído
gaussiano aditivo.

3.1.4 Da Regressão Linear às Redes Profundas

Até agora, falamos apenas sobre modelos lineares. Enquanto as redes neurais cobrem uma família
muito mais rica de modelos, podemos começar a pensar no modelo linear como uma rede neural,
expressando-a na linguagem das redes neurais. Para começar, vamos começar reescrevendo as
coisas em uma notação de “camada”.

Diagrama de Rede Neural

Praticantes de deep learning gostam de desenhar diagramas para visualizar o que está acontecendo
em seus modelos. Em Fig. 3.1.2, retratamos nosso modelo de regressão linear como uma rede
neural. Observe que esses diagramas destacam o padrão de conectividade como cada entrada é
conectada à saída, mas não os valores tomados pelos pesos ou bias.

Fig. 3.1.2: Linear regression is a single-layer neural network.

Para a rede neural mostrada em Fig. 3.1.2, as entradas são x1 , . . . , xd , portanto, o número de en-
tradas (ou dimensionalidade do recurso) na camada de entrada é d. A saída da rede em Fig. 3.1.2 é
o1 , portanto, o número de saídas na camada de saída é 1. Observe que os valores de entrada são to-
dos fornecidos e há apenas um único neurônio calculado. Concentrando-se em onde a computação
ocorre, convencionalmente, não consideramos a camada de entrada ao contar camadas. Quer
dizer, o número de camadas para a rede neural em Fig. 3.1.2 é 1. Podemos pensar em modelos
de regressão linear como redes neurais consistindo em apenas um único neurônio artificial, ou
como redes neurais de camada única.
Já que para a regressão linear, cada entrada é conectada para cada saída (neste caso, há apenas
uma saída), podemos considerar esta transformação (a camada de saída em Fig. 3.1.2) como uma
camada totalmente conectada ou camada densa. Falaremos muito mais sobre redes compostas por
tais camadas no próximo capítulo.

3.1. Linear Regression 99


Biologia

Como a regressão linear (inventada em 1795) antecede a neurociência computacional, pode pare-
cer anacrônico descrever regressão linear como uma rede neural. Para ver por que os modelos
lineares eram um lugar natural para começar quando os ciberneticistas/neurofisiologistas Warren
McCulloch e Walter Pitts começaram a desenvolver modelos de neurônios artificiais, considere a
imagem de desenho animado de um neurônio biológico em Fig. 3.1.3, consistindo em dendritos
(terminais de entrada), o núcleo (CPU), o axônio (fio de saída), e os * terminais de axônio* (termi-
nais de saída), permitindo conexões com outros neurônios por meio de sinapses.

Dendrite
Axon Terminal
Node of
Ranvier
Cell body

Axon Schwann cell


Myelin sheath
Nucleus

Fig. 3.1.3: The real neuron.

Informação xi vinda de outros neurônios (ou sensores ambientais, como a retina) é recebida nos
dendritos. Em particular, essa informação é ponderada por pesos sinápticos wi determinando o
efeito das entradas (por exemplo, ativação ou inibição por meio do produto xi wi ). As entradas
ponderadas
∑ que chegam de várias fontes são agregadas no núcleo como uma soma ponderada
y = i xi wi + b, e esta informação é então enviada para processamento adicional no axônio y,
normalmente após algum processamento não linear via σ(y). De lá, ela chega ao seu destino (por
exemplo, um músculo) ou é alimentado em outro neurônio por meio de seus dendritos.
Certamente, a ideia de alto nível de que muitas dessas unidades poderiam ser remendadas com a
conectividade certa e algoritmo de aprendizado correto, para produzir um comportamento muito
mais interessante e complexo do que qualquer neurônio sozinho poderia expressar, se deve ao
nosso estudo de sistemas neurais biológicos reais.
Ao mesmo tempo, a maioria das pesquisas em deep learning hoje atrai pouca inspiração direta na
neurociência. Invocamos Stuart Russell e Peter Norvig que, em seu livro clássico de IA Inteligência
Artificial: Uma Abordagem Moderna (Russell & Norvig, 2016), apontoam que, embora os aviões pos-
sam ter sido inspirados por pássaros, ornitologia não tem sido o principal motivador de inovação
aeronáutica por alguns séculos. Da mesma forma, a inspiração no deep learning nos dias de hoje
vem em igual ou maior medida da matemática, estatísticas e ciência da computação.

100 Chapter 3. Linear Neural NetworkRedes Neurais Lineares


Summary

• Os principais ingredientes em um modelo de machine learning são dados de treinamento,


uma função de perda, um algoritmo de otimização e, obviamente, o próprio modelo.
• A vetorização torna tudo melhor (principalmente matemática) e mais rápido (principal-
mente código).
• Minimizar uma função objetivo e realizar a estimativa de máxima verossimilhança pode
significar a mesma coisa.
• Os modelos de regressão linear também são redes neurais.

Exercises

1. Suponha que temos alguns dados x1 , . . . , xn ∈ R. Nosso objetivo é encontrar uma constante
b tal que $ :raw-latex:`\sum`_i(x_i - b)^2$ seja minimizado.
1. Encontre uma solução analítica para o valor ideal de b.
2. Como esse problema e sua solução se relacionam com a distribuição normal?
2. Derive a solução analítica para o problema de otimização para regressão linear com erro
quadrático. Para manter as coisas simples, você pode omitir o bias b do problema (podemos
fazer isso com base em princípios, adicionando uma coluna a X consistindo em todas as
colunas).
1. Escreva o problema de otimização em notação de matriz e vetor (trate todos os dados
como uma única matriz e todos os valores de label esperados como um único vetor).
2. Calcule o gradiente da perda em relação a w.
3. Encontre a solução analítica definindo o gradiente igual a zero e resolvendo a equação
da matriz.
4. Quando isso pode ser melhor do que usar o gradiente descendente estocástico? Quando
esse método pode falhar?
3. Suponha que o modelo de ruído que governa o ruído aditivo ϵ é a distribuição exponencial.
Ou seja, p(ϵ) = 21 exp(−|ϵ|).
1. Escreva a log-likelihood negativa dos dados no modelo − log P (y | X).
2. Você pode encontrar uma solução de forma fechada?
3. Sugira um algoritmo de gradiente descendente estocástico para resolver este problema.
O que pode dar errado (dica: o que acontece perto do ponto estacionário à medida que
atualizamos os parâmetros)? Você pode consertar isso?
Discussions31
31
https://discuss.d2l.ai/t/258

3.1. Linear Regression 101


3.2 Linear Regression Implementation from Scratch

Agora que você entende as principais ideias por trás da regressão linear, podemos começar a tra-
balhar por meio de uma implementação prática no código. Nesta seção, vamos implementar todo
o método do zero, incluindo o pipeline de dados, o modelo, a função de perda e o otimizador de
descida gradiente estocástico do minibatch. Embora as estruturas modernas de deep learning pos-
sam automatizar quase todo esse trabalho, implementar coisas do zero é a única maneira para
ter certeza de que você realmente sabe o que está fazendo. Além disso, quando chega a hora de
personalizar modelos, definindo nossas próprias camadas ou funções de perda, entender como
as coisas funcionam nos bastidores será útil. Nesta seção, contaremos apenas com tensores e
diferenciação automática. Posteriormente, apresentaremos uma implementação mais concisa,
aproveitando sinos e assobios de frameworks de deep learning.

%matplotlib inline
import random
import torch
from d2l import torch as d2l

3.2.1 Gerando o Dataset

Para manter as coisas simples, iremos construir um conjunto de dados artificial de acordo com
um modelo linear com ruído aditivo. Nossa tarefa será recuperar os parâmetros deste modelo
usando o conjunto finito de exemplos contidos em nosso conjunto de dados. Manteremos os
dados em baixa dimensão para que possamos visualizá-los facilmente. No seguinte snippet de
código, geramos um conjunto de dados contendo 1000 exemplos, cada um consistindo em 2 fea-
tures amostrado a partir de uma distribuição normal padrão. Assim, nosso conjunto de dados
sintético será uma matriz X ∈ R1000×2 .
Os verdadeiros parâmetros que geram nosso conjunto de dados serão w = [2, −3, 4]⊤ e b = 4, 2,
e nossos rótulos sintéticos serão atribuídos de acordo ao seguinte modelo linear com o termo de
ruído ϵ:

y = Xw + b + ϵ. (3.2.1)

Você pode pensar em ϵ como um potencial de captura erros de medição nos recursos e rótulos.
Vamos assumir que as premissas padrão são válidas e, portanto, que ϵ obedece a uma distribuição
normal com média 0. Para tornar nosso problema mais fácil, definiremos seu desvio padrão em
0,01. O código a seguir gera nosso conjunto de dados sintético.

def synthetic_data(w, b, num_examples): #@save


"""Generate y = Xw + b + noise."""
X = torch.normal(0, 1, (num_examples, len(w)))
y = torch.matmul(X, w) + b
y += torch.normal(0, 0.01, y.shape)
return X, y.reshape((-1, 1))

true_w = torch.tensor([2, -3.4])


true_b = 4.2
features, labels = synthetic_data(true_w, true_b, 1000)

102 Chapter 3. Linear Neural NetworkRedes Neurais Lineares


Observe que cada linha em features consiste em um exemplo de dados bidimensionais e que cada
linha em labels consiste em um valor de rótulo unidimensional (um escalar).

print('features:', features[0],'\nlabel:', labels[0])

features: tensor([-0.9563, 1.2447])


label: tensor([-1.9621])

Ao gerar um gráfico de dispersão usando o segundo recurso features [:, 1] e labels, podemos
observar claramente a correlação linear entre os dois.

d2l.set_figsize()
# The semicolon is for displaying the plot only
d2l.plt.scatter(features[:, (1)].detach().numpy(), labels.detach().numpy(), 1);

3.2.2 Lendo o Dataset

Lembre-se de que os modelos de treinamento consistem em fazer várias passagens sobre o dataset,
pegando um minibatch de exemplos por vez, e usando-los para atualizar nosso modelo. Uma vez
que este processo é tão fundamental para treinar algoritmos de amachine learning, vale a pena
definir uma função de utilidade para embaralhar o conjunto de dados e acessá-lo em minibatches.
No código a seguir, nós definimos a função data_iter para demonstrar uma possível implemen-
tação dessa funcionalidade. A função leva um tamanho de amostra, uma matriz de features, e um
vetor de labels, produzindo minibatches do tamanho batch_size. Cada minibatch consiste em uma
tupla de features e labels.

def data_iter(batch_size, features, labels):


num_examples = len(features)
indices = list(range(num_examples))
# The examples are read at random, in no particular order
random.shuffle(indices)
for i in range(0, num_examples, batch_size):
batch_indices = torch.tensor(
indices[i: min(i + batch_size, num_examples)])
yield features[batch_indices], labels[batch_indices]

3.2. Linear Regression Implementation from Scratch 103


Em geral, queremos usar minibatches de tamanhos razoáveis para aproveitar as vantagens do hard-
ware da GPU, que se destaca em operações de paralelização. Porque cada exemplo pode ser al-
imentado por meio de nossos modelos em paralelo e o gradiente da função de perda para cada
exemplo também pode ser tomado em paralelo, GPUs nos permitem processar centenas de ex-
emplos em pouco mais tempo do que pode demorar para processar apenas um único exemplo.
Para construir alguma intuição, vamos ler e imprimir o primeiro pequeno lote de exemplos de
dados. A forma dos recursos em cada minibatch nos diz o tamanho do minibatch e o número
de recursos de entrada. Da mesma forma, nosso minibatch de rótulos terá uma forma dada por
batch_size.

batch_size = 10

for X, y in data_iter(batch_size, features, labels):


print(X, '\n', y)
break

tensor([[-0.0649, 0.4390],
[-0.2518, -0.4019],
[-0.1489, 0.2960],
[ 1.6701, -0.8914],
[ 0.6946, 0.2719],
[-1.4623, 0.5890],
[ 0.1270, 0.7019],
[-1.2410, 0.1549],
[-0.3620, -0.1373],
[-0.2483, -1.6446]])
tensor([[ 2.5737],
[ 5.0419],
[ 2.8981],
[10.5841],
[ 4.6693],
[-0.7264],
[ 2.0609],
[ 1.1768],
[ 3.9539],
[ 9.2774]])

Conforme executamos a iteração, obtemos minibatches distintos sucessivamente até que todo o
conjunto de dados se esgote (tente isto). Embora a iteração implementada acima seja boa para fins
didáticos, é ineficiente de maneiras que podem nos colocar em apuros em problemas reais. Por
exemplo, requer que carreguemos todos os dados na memória e que realizamos muitos acessos
aleatórios à memória. Os iteradores integrados implementados em uma estrutura de deep learn-
ing são consideravelmente mais eficientes e podem lidar com dados armazenados em arquivos e
dados alimentados por meio de fluxos de dados.

104 Chapter 3. Linear Neural NetworkRedes Neurais Lineares


3.2.3 Initializing Model Parameters

Antes de começarmos a otimizar os parâmetros do nosso modelo por gradiente descendente es-
tocástico de minibatch, precisamos ter alguns parâmetros em primeiro lugar. No código a seguir,
inicializamos os pesos por amostragem números aleatórios de uma distribuição normal com mé-
dia 0 e um desvio padrão de 0,01, e definindo a tendência para 0.

w = torch.normal(0, 0.01, size=(2,1), requires_grad=True)


b = torch.zeros(1, requires_grad=True)

Depois de inicializar nossos parâmetros, nossa próxima tarefa é atualizá-los até eles se ajustam
aos nossos dados suficientemente bem. Cada atualização requer a obtenção do gradiente da nossa
função de perda no que diz respeito aos parâmetros. Dado este gradiente, podemos atualizar cada
parâmetro na direção que pode reduzir a perda.
Uma vez que ninguém quer calcular gradientes explicitamente (isso é entediante e sujeito a erros),
usamos diferenciação automática, conforme apresentado em Section 2.5, para calcular o gradi-
ente.

3.2.4 Definindo o Modelo

Em seguida, devemos definir nosso modelo, relacionando suas entradas e parâmetros com suas
saídas. Lembre-se de que, para calcular a saída do modelo linear, simplesmente pegamos o pro-
duto escalar vetor-matriz dos recursos de entrada X e os pesos do modelo w, e adicione o offset b
a cada exemplo. Observe que abaixo de Xw está um vetor e b é um escalar. Lembre-se do mecan-
ismo de transmissão conforme descrito em Section 2.1.3. Quando adicionamos um vetor e um
escalar, o escalar é adicionado a cada componente do vetor.

def linreg(X, w, b): #@save


"""The linear regression model."""
return torch.matmul(X, w) + b

3.2.5 Definindo a Função de Perda

Uma vez que atualizar nosso modelo requer tomar o gradiente de nossa função de perda, devemos
definir a função de perda primeiro. Aqui vamos usar a função de perda quadrada conforme de-
scrito em Section 3.1. Na implementação, precisamos transformar o valor verdadeiro y na forma
do valor previsto y_hat. O resultado retornado pela seguinte função também terá a mesma forma
de y_hat.

def squared_loss(y_hat, y): #@save


"""Squared loss."""
return (y_hat - y.reshape(y_hat.shape)) ** 2 / 2

3.2. Linear Regression Implementation from Scratch 105


3.2.6 Definindo o Algoritmo de Otimização

Como discutimos em Section 3.1, a regressão linear tem uma solução de forma fechada. No en-
tanto, este não é um livro sobre regressão linear: é um livro sobre deep learning. Uma vez que nen-
hum dos outros modelos que este livro apresenta pode ser resolvido analiticamente, aproveitare-
mos esta oportunidade para apresentar seu primeiro exemplo de trabalho de gradiente descen-
dente estocástico de minibatch.
Em cada etapa, usando um minibatch retirado aleatoriamente de nosso conjunto de dados, vamos
estimar o gradiente da perda em relação aos nossos parâmetros. A seguir, vamos atualizar nossos
parâmetros na direção que pode reduzir a perda. O código a seguir aplica a atualização da descida
gradiente estocástica do minibatch, dado um conjunto de parâmetros, uma taxa de aprendizagem
e um tamanho de batch. O tamanho da etapa de atualização é determinado pela taxa de aprendiza-
gem lr. Como nossa perda é calculada como a soma do minibatch de exemplos, normalizamos o
tamanho do nosso passo pelo tamanho do batch (batch_size), de modo que a magnitude de um
tamanho de passo típico não depende muito de nossa escolha do tamanho do lote.

def sgd(params, lr, batch_size): #@save


"""Minibatch stochastic gradient descent."""
with torch.no_grad():
for param in params:
param -= lr * param.grad / batch_size
param.grad.zero_()

3.2.7 Treinamento

Agora que temos todas as peças no lugar, estamos prontos para implementar o loop de treinamento
principal. É crucial que você entenda este código porque você verá loops de treinamento quase
idênticos repetidamente ao longo de sua carreira de deep learning.
Em cada iteração, pegaremos um minibatch de exemplos de treinamento, e os passamos por
nosso modelo para obter um conjunto de previsões. Depois de calcular a perda, iniciamos a pas-
sagem para trás pela rede, armazenando os gradientes em relação a cada parâmetro. Finalmente,
chamaremos o algoritmo de otimização de sgd para atualizar os parâmetros do modelo.
Em resumo, vamos executar o seguinte loop:
• Inicializar parâmetros (w, b)
• Repetir até terminar

– Computar gradiente g ← ∂(w,b) |B|
1
i∈B l(x(i) , y (i) , w, b)

– Atualizar parâmetros (w, b) ← (w, b) − ηg


Em cada época, iremos iterar por todo o conjunto de dados (usando a função data_iter) uma vez
passando por todos os exemplos no conjunto de dados de treinamento (assumindo que o número
de exemplos seja divisível pelo tamanho do lote). O número de épocas num_epochs e a taxa de
aprendizagemlr são hiperparâmetros, que definimos aqui como 3 e 0,03, respectivamente. In-
felizmente, definir hiperparâmetros é complicado e requer alguns ajustes por tentativa e erro.
Excluímos esses detalhes por enquanto, mas os revisamos mais tarde em Chapter 11.

106 Chapter 3. Linear Neural NetworkRedes Neurais Lineares


lr = 0.03
num_epochs = 3
net = linreg
loss = squared_loss

for epoch in range(num_epochs):


for X, y in data_iter(batch_size, features, labels):
l = loss(net(X, w, b), y) # Minibatch loss in `X` and `y`
# Compute gradient on `l` with respect to [`w`, `b`]
l.sum().backward()
sgd([w, b], lr, batch_size) # Update parameters using their gradient
with torch.no_grad():
train_l = loss(net(features, w, b), labels)
print(f'epoch {epoch + 1}, loss {float(train_l.mean()):f}')

epoch 1, loss 0.044391


epoch 2, loss 0.000181
epoch 3, loss 0.000046

Neste caso, porque nós mesmos sintetizamos o conjunto de dados, sabemos exatamente quais são
os verdadeiros parâmetros. Assim, podemos avaliar nosso sucesso no treinamento comparando
os parâmetros verdadeiros com aqueles que aprendemos através de nosso ciclo de treinamento.
Na verdade, eles acabam sendo muito próximos um do outro.

print(f'error in estimating w: {true_w - w.reshape(true_w.shape)}')


print(f'error in estimating b: {true_b - b}')

error in estimating w: tensor([ 0.0006, -0.0003], grad_fn=<SubBackward0>)


error in estimating b: tensor([0.0008], grad_fn=<RsubBackward1>)

Observe que não devemos tomar isso como garantido que somos capazes de recuperar os parâmet-
ros perfeitamente. No entanto, no machine learning, normalmente estamos menos preocupados
com a recuperação de verdadeiros parâmetros subjacentes, e mais preocupados com parâmet-
ros que levam a previsões altamente precisas. Felizmente, mesmo em problemas de otimização
difíceis, o gradiente descendente estocástico pode muitas vezes encontrar soluções notavelmente
boas, devido em parte ao fato de que, para redes profundas, existem muitas configurações dos
parâmetros que levam a uma previsão altamente precisa.

3.2.8 Resumo

• Vimos como uma rede profunda pode ser implementada e otimizada do zero, usando apenas
tensores e diferenciação automática, sem a necessidade de definir camadas ou otimizadores
sofisticados.
• Esta seção apenas arranha a superfície do que é possível. Nas seções a seguir, descreveremos
modelos adicionais com base nos conceitos que acabamos de apresentar e aprenderemos
como implementá-los de forma mais concisa.

3.2. Linear Regression Implementation from Scratch 107


3.2.9 Exercícios

1. O que aconteceria se inicializássemos os pesos para zero. O algoritmo ainda funcionaria?


2. Suponha que você seja Georg Simon Ohm32 tentando inventar um modelo entre tensão e
corrente. Você poderia usar a diferenciação automática para aprender os parâmetros do
seu modelo?
3. Você pode usar a Lei de Planck33 para determinar a temperatura de um objeto usando den-
sidade de energia espectral?
4. Quais são os problemas que você pode encontrar se quiser calcular as derivadas secundárias?
Como você os consertaria?
5. Por que a função reshape é necessária na funçãosquared_loss?
6. Experimente usar diferentes taxas de aprendizagem para descobrir a rapidez com que o
valor da função de perda diminui.
7. Se o número de exemplos não pode ser dividido pelo tamanho do lote, o que acontece com
o comportamento da função data_iter?
Discussions34

3.3 Implementação Concisa de Regressão Linear

Amplo e intenso interesse em deep learning nos últimos anos inspiraram empresas, acadêmicos e
amadores para desenvolver uma variedade de estruturas de código aberto maduras para automa-
tizar o trabalho repetitivo de implementação algoritmos de aprendizagem baseados em gradiente.
Em Section 3.2, contamos apenas com (i) tensores para armazenamento de dados e álgebra lin-
ear; e (ii) auto diferenciação para cálculo de gradientes. Na prática, porque iteradores de dados,
funções de perda, otimizadores, e camadas de rede neural são tão comuns que as bibliotecas mod-
ernas também implementam esses componentes para nós.
Nesta seção, mostraremos como implementar o modelo de regressão linear
de:numref:sec_linear_scratch de forma concisa, usando APIs de alto nível de estruturas
de deep learning.

3.3.1 Gerando the Dataset

Para começar, vamos gerar o mesmo conjunto de dados como em Section 3.2.

import numpy as np
import torch
from torch.utils import data
from d2l import torch as d2l

32
https://en.wikipedia.org/wiki/Georg_Ohm
33
https://en.wikipedia.org/wiki/Planck%27s_law
34
https://discuss.d2l.ai/t/43

108 Chapter 3. Linear Neural NetworkRedes Neurais Lineares


true_w = torch.tensor([2, -3.4])
true_b = 4.2
features, labels = d2l.synthetic_data(true_w, true_b, 1000)

3.3.2 Lendo o Dataset

Em vez de usar nosso próprio iterador, podemos chamar a API existente em uma estrutura para
ler os dados. Passamos ``features`` e ``labels`` como argumentos e especificamos ``batch_size`` ao
instanciar um objeto iterador de dados. Além disso, o valor booleano is_train indica se ou não
queremos que o objeto iterador de dados embaralhe os dados em cada época (passe pelo conjunto
de dados).

def load_array(data_arrays, batch_size, is_train=True): #@save


"""Construct a PyTorch data iterator."""
dataset = data.TensorDataset(*data_arrays)
return data.DataLoader(dataset, batch_size, shuffle=is_train)

batch_size = 10
data_iter = load_array((features, labels), batch_size)

Now we can use data_iter in much the same way as we called the data_iter function in Section
3.2. To verify that it is working, we can read and print the first minibatch of examples. Comparing
with Section 3.2, here we use iter to construct a Python iterator and use next to obtain the first
item from the iterator.

next(iter(data_iter))

[tensor([[ 0.4291, 0.1270],


[ 1.7995, -1.2012],
[ 0.9239, -0.7505],
[ 1.3561, -0.4303],
[ 0.6144, -0.5138],
[-1.0876, -0.8626],
[ 1.1090, 3.4219],
[-1.6905, 0.1326],
[ 0.6009, 0.9365],
[ 0.1519, -1.1885]]),
tensor([[ 4.6351],
[11.8713],
[ 8.5979],
[ 8.3702],
[ 7.1819],
[ 4.9432],
[-5.2131],
[ 0.3592],
[ 2.2248],
[ 8.5418]])]

3.3. Implementação Concisa de Regressão Linear 109


3.3.3 Definindo o Modelo

Quando implementamos a regressão linear do zero em Section 3.2, definimos nossos parâmetros
de modelo explicitamente e codificamos os cálculos para produzir saída usando operações bási-
cas de álgebra linear. Você deveria saber como fazer isso. Mas quando seus modelos ficam mais
complexos, e uma vez que você tem que fazer isso quase todos os dias, você ficará feliz com a
ajuda. A situação é semelhante a codificar seu próprio blog do zero. Fazer uma ou duas vezes é
gratificante e instrutivo, mas você seria um péssimo desenvolvedor da web se toda vez que você
precisava de um blog você passava um mês reinventando tudo.
Para operações padrão, podemos usar as camadas predefinidas de uma estrutura, o que nos per-
mite focar especialmente nas camadas usadas para construir o modelo em vez de ter que se con-
centrar na implementação. Vamos primeiro definir uma variável de modelo net, que se refere
a uma instância da classe Sequential. A classe Sequential define um contêiner para várias ca-
madas que serão encadeadas. Dados dados de entrada, uma instância Sequential passa por a
primeira camada, por sua vez passando a saída como entrada da segunda camada e assim por
diante. No exemplo a seguir, nosso modelo consiste em apenas uma camada, portanto, não pre-
cisamos realmente de Sequencial. Mas como quase todos os nossos modelos futuros envolverão
várias camadas, vamos usá-lo de qualquer maneira apenas para familiarizá-lo com o fluxo de tra-
balho mais padrão.
Lembre-se da arquitetura de uma rede de camada única, conforme mostrado em Fig. 3.1.2. Diz-se
que a camada está totalmente conectada porque cada uma de suas entradas está conectada a cada
uma de suas saídas por meio de uma multiplicação de matriz-vetor.
: begin_tab: pytorch No PyTorch, a camada totalmente conectada é definida na classe Linear.
Observe que passamos dois argumentos para nn.Linear. O primeiro especifica a dimensão do
recurso de entrada, que é 2, e o segundo é a dimensão do recurso de saída, que é um escalar único
e, portanto, 1.

# `nn` is an abbreviation for neural networks


from torch import nn

net = nn.Sequential(nn.Linear(2, 1))

3.3.4 Inicializando os Parâmetros do Modelo

Antes de usar net, precisamos inicializar os parâmetros do modelo, como os pesos e bias no
modelo de regressão linear. As estruturas de deep learning geralmente têm uma maneira pre-
definida de inicializar os parâmetros. Aqui especificamos que cada parâmetro de peso deve ser
amostrado aleatoriamente a partir de uma distribuição normal com média 0 e desvio padrão 0,01.
O parâmetro bias será inicializado em zero.
As we have specified the input and output dimensions when constructing nn.Linear. Now we
access the parameters directly to specify their initial values. We first locate the layer by net[0],
which is the first layer in the network, and then use the weight.data and bias.data methods to ac-
cess the parameters. Next we use the replace methods normal_ and fill_ to overwrite parameter
values.

net[0].weight.data.normal_(0, 0.01)
net[0].bias.data.fill_(0)

110 Chapter 3. Linear Neural NetworkRedes Neurais Lineares


tensor([0.])

3.3.5 Definindo a Função de Perda

A classe MSELoss calcula o erro quadrático médio, também conhecido como norma $ L_2 $
quadrada. Por padrão, ela retorna a perda média sobre os exemplos.

loss = nn.MSELoss()

3.3.6 Definindo o Algoritmo de Otimização

O gradiente descendente estocástico de minibatch é uma ferramenta padrão para otimizar redes
neurais e, portanto, PyTorch o suporta ao lado de uma série de variações deste algoritmo no mó-
dulo optim. Quando nós instanciamos uma instância SGD, iremos especificar os parâmetros para
otimizar (podem ser obtidos de nossa rede via net.parameters ()), com um dicionário de hiper-
parâmetros exigido por nosso algoritmo de otimização. O gradiente descendente estocástico de
minibatch requer apenas que definamos o valor lr, que é definido como 0,03 aqui.

trainer = torch.optim.SGD(net.parameters(), lr=0.03)

3.3.7 Treinamento

Você deve ter notado que expressar nosso modelo por meio APIs de alto nível de uma estrutura de
deep learning requer comparativamente poucas linhas de código. Não tivemos que alocar parâmet-
ros individualmente, definir nossa função de perda ou implementar o gradiente descendente es-
tocástico de minibatch. Assim que começarmos a trabalhar com modelos muito mais complexos,
as vantagens das APIs de alto nível aumentarão consideravelmente. No entanto, uma vez que
temos todas as peças básicas no lugar, o loop de treinamento em si é surpreendentemente semel-
hante ao que fizemos ao implementar tudo do zero.
Para refrescar sua memória: para anguns números de épocas, faremos uma passagem completa
sobre o conjunto de dados (``train_data``), pegando iterativamente um minibatch de entradas e
os labels de verdade fundamental correspondentes. Para cada minibatch, passamos pelo seguinte
ritual:
• Gerar previsões chamando net (X) e calcular a perda l (a propagação direta).
• Calcular gradientes executando a retropropagação.
• Atualizar os parâmetros do modelo invocando nosso otimizador.
Para uma boa medida, calculamos a perda após cada época e a imprimimos para monitorar o
progresso.

num_epochs = 3
for epoch in range(num_epochs):
for X, y in data_iter:
l = loss(net(X) ,y)
trainer.zero_grad()
(continues on next page)

3.3. Implementação Concisa de Regressão Linear 111


(continued from previous page)
l.backward()
trainer.step()
l = loss(net(features), labels)
print(f'epoch {epoch + 1}, loss {l:f}')

epoch 1, loss 0.000239


epoch 2, loss 0.000098
epoch 3, loss 0.000099

Abaixo, nós comparamos os parâmetros do modelo aprendidos pelo treinamento em dados finitos
e os parâmetros reais que geraram nosso dataset. Para acessar os parâmetros, primeiro acessamos
a camada que precisamos de net e, em seguida, acessamos os pesos e a polarização dessa camada.
Como em nossa implementação do zero, observe que nossos parâmetros estimados são perto de
suas contrapartes verdadeiras.

w = net[0].weight.data
print('error in estimating w:', true_w - w.reshape(true_w.shape))
b = net[0].bias.data
print('error in estimating b:', true_b - b)

error in estimating w: tensor([0.0004, 0.0001])


error in estimating b: tensor([-0.0005])

3.3.8 Resumo

• Usando as APIs de alto nível do PyTorch, podemos implementar modelos de forma muito
mais concisa.
• No PyTorch, o módulo data fornece ferramentas para processamento de dados, o módulonn
define um grande número de camadas de rede neural e funções de perda comuns.
• Podemos inicializar os parâmetros substituindo seus valores por métodos que terminam
com _.

3.3.9 Exercícios

1. Se substituirmos nn.MSELoss (*reduction* = 'sum') por nn.MSELoss (), como podemos


alterar a taxa de aprendizagem para que o código se comporte de forma idêntica. Por quê?
2. Revise a documentação do PyTorch para ver quais funções de perda e métodos de inicializa-
ção são fornecidos. Substitua a perda pela perda de Huber.
3. Como você acessa o gradiente de net[0].weight?
Discussions35
35
https://discuss.d2l.ai/t/45

112 Chapter 3. Linear Neural NetworkRedes Neurais Lineares


3.4 Regressão Softmax

Em Section 3.1, introduzimos a regressão linear, trabalhando através de implementações do zero


em Section 3.2 e novamente usando APIs de alto nível de uma estrutura de deep learning em Section
3.3 para fazer o trabalho pesado.
A regressão é o martelo que procuramos quando queremos responder a perguntasquanto? ou
quantas?. Se você deseja prever o número de dólares (preço) a que uma casa será vendida, ou
o número de vitórias que um time de beisebol pode ter, ou o número de dias que um paciente
permanecerá hospitalizado antes de receber alta, então provavelmente você está procurando um
modelo de regressão.
Na prática, estamos mais frequentemente interessados na classificação: perguntando não
“quanto”, mas “qual”:
• Este e-mail pertence à pasta de spam ou à caixa de entrada?
• É mais provável que este cliente se inscreva ou não se inscreva em um serviço de assinatura?
• Esta imagem retrata um burro, um cachorro, um gato ou um galo?
• Qual filme Aston tem mais probabilidade de assistir a seguir?
Coloquialmente, praticantes de machine learning sobrecarregam a palavra classificação para de-
screver dois problemas sutilmente diferentes: (i) aqueles em que estamos interessados apenas
em atribuições difíceis de exemplos a categorias (classes); e (ii) aqueles em que desejamos fazer
atribuições leves, ou seja, para avaliar a probabilidade de que cada categoria se aplica. A distinção
tende a ficar confusa, em parte, porque muitas vezes, mesmo quando nos preocupamos apenas
com tarefas difíceis, ainda usamos modelos que fazem atribuições suaves.

3.4.1 Problema de Classificação

Para molhar nossos pés, vamos começar com um problema simples de classificação de imagens.
Aqui, cada entrada consiste em uma imagem em tons de cinza 2 × 2. Podemos representar cada
valor de pixel com um único escalar, dando-nos quatro características x1 , x2 , x3 , x4 . Além disso,
vamos supor que cada imagem pertence a uma entre as categorias “gato”, “frango” e “cachorro”.
A seguir, temos que escolher como representar os labels. Temos duas escolhas óbvias.
Talvez o impulso mais natural seja escolher y ∈ {1, 2, 3}, onde os inteiros representam
{cachorro, gato, frango} respectivamente. Esta é uma ótima maneira de armazenar essas infor-
mações em um computador. Se as categorias tivessem alguma ordem natural entre elas, digamos
se estivéssemos tentando prever {bebê, criança, adolescente, jovem adulto, adulto, idoso}, então
pode até fazer sentido lançar este problema como uma regressão e manter os rótulos neste for-
mato.
Mas os problemas gerais de classificação não vêm com ordenações naturais entre as classes. Feliz-
mente, os estatísticos há muito tempo inventaram uma maneira simples para representar dados
categóricos: a codificação one-hot. Uma codificação one-hot é um vetor com tantos componentes
quantas categorias temos. O componente correspondente à categoria da instância em particular é
definido como 1 e todos os outros componentes são definidos como 0. Em nosso caso, um rótulo y
seria um vetor tridimensional, com (1, 0, 0) correspondendo a “gato”, (0, 1, 0) a “galinha”, e (0, 0, 1)
para “cachorro”:

y ∈ {(1, 0, 0), (0, 1, 0), (0, 0, 1)}. (3.4.1)

3.4. Regressão Softmax 113


3.4.2 Arquitetura de Rede

A fim de estimar as probabilidades condicionais associadas a todas as classes possíveis, pre-


cisamos de um modelo com várias saídas, uma por classe. Para abordar a classificação com mod-
elos lineares, precisaremos de tantas funções afins quantas forem as saídas. Cada saída corre-
sponderá a sua própria função afim. No nosso caso, uma vez que temos 4 features e 3 categorias
de saída possíveis, precisaremos de 12 escalares para representar os pesos (w com subscritos), e
3 escalares para representar os offsets (b com subscritos). Calculamos esses três logits, o1 , o2 , and
o3 , para cada entrada:

o1 = x1 w11 + x2 w12 + x3 w13 + x4 w14 + b1 ,


o2 = x1 w21 + x2 w22 + x3 w23 + x4 w24 + b2 , (3.4.2)
o3 = x1 w31 + x2 w32 + x3 w33 + x4 w34 + b3 .

Podemos representar esse cálculo com o diagrama da rede neural mostrado em Fig. 3.4.1. Assim
como na regressão linear, a regressão softmax também é uma rede neural de camada única. E
desde o cálculo de cada saída, o1 , o2 , e o3 , depende de todas as entradas, x1 , x2 , x3 , e x4 , a camada
de saída da regressão softmax também pode ser descrita como uma camada totalmente conectada.

Fig. 3.4.1: Softmax regression is a single-layer neural network.

Para expressar o modelo de forma mais compacta, podemos usar a notação de álgebra linear.
Na forma vetorial, chegamos a o = Wx + b, uma forma mais adequada tanto para matemática
quanto para escrever código. Observe que reunimos todos os nossos pesos em uma matriz 3 × 4 e
que para características de um dado exemplo de dados x, nossas saídas são dadas por um produto
vetor-matriz de nossos pesos por nossos recursos de entrada mais nossos offsets b.

3.4.3 Custo de Parametrização de Camadas Totalmente Conectadas

Como veremos nos capítulos subsequentes, camadas totalmente conectadas são onipresentes no
deep learning. No entanto, como o nome sugere, camadas totalmente conectadas são totalmente
conectadas com muitos parâmetros potencialmente aprendíveis. Especificamente, para qualquer
camada totalmente conectada com d entradas e q saídas, o custo de parametrização é O(dq), que
pode ser proibitivamente alto na prática. Felizmente, este custo de transformar d entradas em
q saídas pode ser reduzido a O( dqn ), onde o hiperparâmetro n pode ser especificado de maneira
flexível por nós para equilibrar entre o salvamento de parâmetros e a eficácia do modelo em apli-
cações do mundo real (Zhang et al., 2021).

114 Chapter 3. Linear Neural NetworkRedes Neurais Lineares


3.4.4 Operação do Softmax

A abordagem principal que vamos adotar aqui é interpretar as saídas de nosso modelo como prob-
abilidades. Vamos otimizar nossos parâmetros para produzir probabilidades que maximizam a
probabilidade dos dados observados. Então, para gerar previsões, vamos definir um limite, por
exemplo, escolhendo o label com as probabilidades máximas previstas.
Colocado formalmente, gostaríamos de qualquer saída ŷj fosse interpretada como a probabilidade
que um determinado item pertence à classe j. Então podemos escolher a classe com o maior
valor de saída como nossa previsão argmaxj yj . Por exemplo, se ŷ1 , ŷ2 , and ŷ3 são 0,1, 0,8 e 0,1,
respectivamente, então, prevemos a categoria 2, que (em nosso exemplo) representa “frango”.
Você pode ficar tentado a sugerir que interpretemos os logits o diretamente como nossas saídas
de interesse. No entanto, existem alguns problemas com interpretação direta da saída da camada
linear como uma probabilidade. Por um lado, nada restringe esses números a somarem 1. Por
outro lado, dependendo das entradas, podem assumir valores negativos. Estes violam axiomas
básicos de probabilidade apresentados em Section 2.6
Para interpretar nossos resultados como probabilidades, devemos garantir que (mesmo em novos
dados), eles serão não negativos e somam 1. Além disso, precisamos de um objetivo de treina-
mento que incentive o modelo para estimar probabilidades com fidelidade. De todas as instâncias
quando um classificador produz 0,5, esperamos que metade desses exemplos realmente pertence-
ram à classe prevista. Esta é uma propriedade chamada calibração.
A função softmax, inventada em 1959 pelo cientista social R. Duncan Luce no contexto de modelos
de escolha, faz exatamente isso. Para transformar nossos logits de modo que eles se tornem não
negativos e somem 1, ao mesmo tempo em que exigimos que o modelo permaneça diferenciável,
primeiro exponenciamos cada logit (garantindo a não negatividade) e, em seguida, dividimos pela
soma (garantindo que somem 1):

exp(oj )
ŷ = softmax(o) where ŷj = ∑ . (3.4.3)
k exp(ok )

É fácil ver ŷ1 +ŷ2 +ŷ3 = 1 with 0 ≤ ŷj ≤ 1 para todo j. Assim, ŷ é uma distribuição de probabilidade
adequada cujos valores de elementos podem ser interpretados em conformidade. Observe que a
operação softmax não muda a ordem entre os logits o, que são simplesmente os valores pré-softmax
que determinam as probabilidades atribuídas a cada classe. Portanto, durante a previsão, ainda
podemos escolher a classe mais provável por

argmax ŷj = argmax oj . (3.4.4)


j j

Embora softmax seja uma função não linear, as saídas da regressão softmax ainda são determinadas
por uma transformação afim de recursos de entrada; portanto, a regressão softmax é um modelo
linear.

3.4. Regressão Softmax 115


3.4.5 Vetorização para Minibatches

Para melhorar a eficiência computacional e aproveitar as vantagens das GPUs, normalmente real-
izamos cálculos vetoriais para minibatches de dados. Suponha que recebemos um minibatch X de
exemplos com dimensionalidade do recurso (número de entradas) d e tamanho do lote n. Além
disso, suponha que temos q categorias na saída. Então os features de minibatch X estão em Rn×d ,
pesos W ∈ Rd×q , e o bias satisfaz b ∈ R1×q .

O = XW + b,
(3.4.5)
Ŷ = softmax(O).

Isso acelera a operação dominante em um produto matriz-matriz XW vs. os produtos de vetor-


matriz que estaríamos executando se processamos um exemplo de cada vez. Uma vez que cada
linha em X representa um exemplo de dados, a própria operação softmax pode ser calculada
rowwise (através das colunas): para cada linha de O, exponenciando todas as entradas e depois
normalizando-as pela soma. Disparando a transmissão durante a soma XW + b in (3.4.5), o mini-
batch registra O e as probabilidades de saída Ŷ são matrizes n × q.

3.4.6 Função de Perda

Em seguida, precisamos de uma função de perda para medir a qualidade de nossas probabilidades
previstas. Contaremos com a estimativa de probabilidade máxima, o mesmo conceito que encon-
tramos ao fornecer uma justificativa probabilística para o objetivo de erro quadrático médio na
regressão linear (Section 3.1.3).

Log-Likelihood

A função softmax nos dá um vetor ŷ, que podemos interpretar como probabilidades condicionais
estimadas de cada classe dada qualquer entrada x,, por exemplo, ŷ1 = P (y = cat | x). Suponha que
todo o conjunto de dados {X, Y} tenha n exemplos, onde o exemplo indexado por i consiste em um
vetor de característica x(i) e um vetor de rótulo único y(i) . Podemos comparar as estimativas com
a realidade verificando quão prováveis as classes reais são de acordo com nosso modelo, dadas as
características:

n
P (Y | X) = P (y(i) | x(i) ). (3.4.6)
i=1

De acordo com a estimativa de máxima likelihood, maximizamos P (Y | X), que é equivalente a


minimizar a probabilidade de log-likelihood negativo:

n ∑
n
− log P (Y | X) = − log P (y (i)
|x )=
(i)
l(y(i) , ŷ(i) ), (3.4.7)
i=1 i=1

onde para qualquer par de rótulo y e predição de modelo ŷ sobre q classes, a função de perda l é

q
l(y, ŷ) = − yj log ŷj . (3.4.8)
j=1

Por razões explicadas mais tarde, a função de perda em (3.4.8) é comumente chamada de perda de
entropia cruzada. Uma vez que y é um vetor one-hot de comprimento q, a soma de todas as suas co-
ordenadas j desaparece para todos, exceto um termo. Uma vez que todos os ŷj são probabilidades

116 Chapter 3. Linear Neural NetworkRedes Neurais Lineares


previstas, seu logaritmo nunca é maior que 0. Consequentemente, a função de perda não pode
ser minimizada mais, se predizermos corretamente o rótulo real com certeza, ou seja, se a prob-
abilidade prevista P (y | x) = 1 for o label real y. Observe que isso geralmente é impossível. Por
exemplo, pode haver ruído de label no dataset (alguns exemplos podem estar classificados incorre-
tamente). Também pode não ser possível quando os recursos de entrada não são suficientemente
informativos para classificar todos os exemplos perfeitamente.

Softmax e Derivadas

Uma vez que o softmax e a perda correspondente são tão comuns, vale a pena entender um pouco
melhor como ele é calculado. Conectando (3.4.3) na definição da perda em (3.4.8) e usando a
definição do softmax obtemos:


q
exp(oj )
l(y, ŷ) = − yj log ∑q
j=1 k=1 exp(ok )


q ∑
q ∑
q
= yj log exp(ok ) − yj oj (3.4.9)
j=1 k=1 j=1

q ∑
q
= log exp(ok ) − yj o j .
k=1 j=1

Para entender um pouco melhor o que está acontecendo, considere a derivada com respeito a
qualquer logit oj . Nós temos

exp(oj )
∂oj l(y, ŷ) = ∑q − yj = softmax(o)j − yj . (3.4.10)
k=1 exp(ok )

Em outras palavras, a derivada é a diferença entre a probabilidade atribuída pelo nosso mod-
elo, conforme expresso pela operação softmax, e o que realmente aconteceu, conforme expresso
por elementos no vetor one-hot de labels. Nesse sentido, é muito semelhante ao que vimos na
regressão, onde o gradiente era a diferença entre a observação y e a estimativa ŷ. Isso não é
coincidência. Em qualquer família exponencial (veja o modelo no apêndice online sobre dis-
tribuições36 ), os gradientes da probabilidade logarítmica são dados precisamente por esse termo.
Esse fato torna a computação dos gradientes fáceis na prática.

Perda de Entropia Cruzada

Agora considere o caso em que observamos não apenas um único resultado mas toda uma dis-
tribuição de resultados. Podemos usar a mesma representação de antes para o rótulo y. A única
diferença é que, em vez de um vetor contendo apenas entradas binárias, digamos (0, 0, 1), agora
temos um vetor de probabilidade genérico, digamos (0.1, 0.2, 0.7). A matemática que usamos an-
teriormente para definir a perda l em (3.4.8) ainda funciona bem, apenas que a interpretação é
um pouco mais geral. É o valor esperado da perda de uma distribuição nos labels. Esta perda é
chamada de perda de entropia cruzada e é uma das perdas mais comumente usadas para problemas
de classificação. Podemos desmistificar o nome apresentando apenas os fundamentos da teoria
da informação. Se você deseja entender mais detalhes da teoria da informação, você também
pode consultar o apêndice online sobre teoria da informação37 .
36
https://d2l.ai/chapter_apencha-mathematics-for-deep-learning/distributions.html
37
https://d2l.ai/chapter_apencha-mathematics-for-deep-learning/information-theory.html

3.4. Regressão Softmax 117


3.4.7 Fundamentos da Teoria da Informação

Teoria da informação lida com o problema de codificação, decodificação, transmissão, e manipu-


lação informações (também conhecidas como dados) da forma mais concisa possível.

Entropia

A ideia central na teoria da informação é quantificar o conteúdo da informação nos dados. Essa
quantidade impõe um limite rígido à nossa capacidade de compactar os dados. Na teoria da infor-
mação, essa quantidade é chamada de entropia de uma distribuição P , e é definida pela seguinte
equação:

H[P ] = −P (j) log P (j). (3.4.11)
j

Um dos teoremas fundamentais da teoria da informação afirma que, a fim de codificar dados re-
tirados aleatoriamente da distribuição P , precisamos de pelo menos H[P ] “nats” para codificá-lo.
Se você quer saber o que é um “nat”, é o equivalente a bit mas ao usar um código com base e em
1
vez de um com base 2. Assim, um nat é log(2) ≈ 1.44 bit.

Surpresa

Você pode estar se perguntando o que a compressão tem a ver com a predição. Imagine que temos
um fluxo de dados que queremos compactar. Se sempre for fácil para nós prevermos o próximo
token, então esses dados são fáceis de compactar! Veja o exemplo extremo em que cada token
no fluxo sempre leva o mesmo valor. Esse é um fluxo de dados muito chato! E não só é chato,
mas também é fácil de prever. Por serem sempre iguais, não precisamos transmitir nenhuma
informação para comunicar o conteúdo do fluxo. Fácil de prever, fácil de compactar.
No entanto, se não podemos prever perfeitamente todos os eventos, então às vezes podemos ficar
surpresos. Nossa surpresa é maior quando atribuímos uma probabilidade menor a um evento.
Claude Shannon estabeleceu log P 1(j) = − log P (j) para quantificar a surpresa de alguém ao ob-
servar um evento j tendo-lhe atribuído uma probabilidade (subjetiva) P (j). A entropia definida
em (3.4.11) é então a surpresa esperada quando alguém atribuiu as probabilidades corretas que
realmente correspondem ao processo de geração de dados.

Entropia Cruzada Revisitada

Então, se a entropia é o nível de surpresa experimentado por alguém que conhece a verdadeira
probabilidade, então você deve estar se perguntando, o que é entropia cruzada? A entropia
cruzada de P a Q, denotada H(P, Q), é a surpresa esperada de um observador com probabilidades
subjetivas Q ao ver os dados que realmente foram gerados de acordo com as probabilidades P . A
menor entropia cruzada possível é alcançada quando P = Q. Nesse caso, a entropia cruzada de
P a Q é H(P, P ) = H(P ).
Em suma, podemos pensar no objetivo da classificação de entropia cruzada de duas maneiras: (i)
maximizando a probabilidade dos dados observados; e (ii) minimizando nossa surpresa (e, por-
tanto, o número de bits) necessário para comunicar os rótulos.

118 Chapter 3. Linear Neural NetworkRedes Neurais Lineares


3.4.8 Predição do Modelo e Avaliação

Depois de treinar o modelo de regressão softmax, dados quaisquer recursos de exemplo, podemos
prever a probabilidade de cada classe de saída. Normalmente, usamos a classe com a maior prob-
abilidade prevista como a classe de saída. A previsão está correta se for consistente com a classe
real (label). Na próxima parte do experimento, usaremos exatidão para avaliar o desempenho do
modelo. Isso é igual à razão entre o número de previsões corretas e o número total de previsões.

3.4.9 Resumo

• A operação softmax pega um vetor e o mapeia em probabilidades.


• A regressão Softmax se aplica a problemas de classificação. Ela usa a distribuição de proba-
bilidade da classe de saída na operação softmax.
• A entropia cruzada é uma boa medida da diferença entre duas distribuições de probabili-
dade. Ela mede o número de bits necessários para codificar os dados de nosso modelo.

3.4.10 Exercícios

1. Podemos explorar a conexão entre as famílias exponenciais e o softmax com um pouco mais
de profundidade.
1. Calcule a segunda derivada da perda de entropia cruzada l(y, ŷ) para o softmax.
2. Calcule a variância da distribuição dada por softmax(o) e mostre que ela corresponde
à segunda derivada calculada acima.
2. Suponha que temos três classes que ocorrem com probabilidade igual, ou seja, o vetor de
probabilidade é ( 13 , 31 , 13 ).
1. Qual é o problema se tentarmos projetar um código binário para ele?
2. Você pode criar um código melhor? Dica: o que acontece se tentarmos codificar duas
observações independentes? E se codificarmos n observações em conjunto?
3. Softmax é um nome impróprio para o mapeamento apresentado acima (mas todos no apren-
dizado profundo o usam). O softmax real é definido como RealSoftMax(a, b) = log(exp(a) +
exp(b)).
1. Prove que RealSoftMax(a, b) > max(a, b).
2. Prove que isso vale paraλ−1 RealSoftMax(λa, λb), desde que λ > 0.
3. Mostre que para λ → ∞ temos λ−1 RealSoftMax(λa, λb) → max(a, b).
4. Qual é a aparência do soft-min?
5. Estenda isso para mais de dois números.
Discussions38
38
https://discuss.d2l.ai/t/46

3.4. Regressão Softmax 119


3.5 O Dataset de Classificação de Imagens

Um dos datasets amplamente usados para classificação de imagens é o conjunto de dados MNIST
(LeCun et al., 1998). Embora tenha tido uma boa execução como um conjunto de dados de refer-
ência, mesmo os modelos simples pelos padrões atuais alcançam uma precisão de classificação
acima de 95%, tornando-o inadequado para distinguir entre modelos mais fortes e mais fracos.
Hoje, o MNIST serve mais como verificação de sanidade do que como referência. Para aumentar
um pouco a aposta, concentraremos nossa discussão nas próximas seções no dataset Fashion-
MNIST, qualitativamente semelhante, mas comparativamente complexo (Xiao et al., 2017), que
foi lançado em 2017.

%matplotlib inline
import torch
import torchvision
from torch.utils import data
from torchvision import transforms
from d2l import torch as d2l

d2l.use_svg_display()

3.5.1 Lendo o Dataset

Nós podemos baixar e ler o dataset Fashion-MNIST na memória por meio das funções integradas
na estrutura.

# `ToTensor` converts the image data from PIL type to 32-bit floating point
# tensors. It divides all numbers by 255 so that all pixel values are between
# 0 and 1
trans = transforms.ToTensor()
mnist_train = torchvision.datasets.FashionMNIST(
root="../data", train=True, transform=trans, download=True)
mnist_test = torchvision.datasets.FashionMNIST(
root="../data", train=False, transform=trans, download=True)

O Fashion-MNIST consiste em imagens de 10 categorias, cada uma representada por 6.000 ima-
gens no conjunto de dados de treinamento e por 1.000 no conjunto de dados de teste. Um dataset de
teste (ou conjunto de teste) é usado para avaliar o desempenho do modelo e não para treinamento.
Consequentemente, o conjunto de treinamento e o conjunto de teste contém 60.000 e 10.000 ima-
gens, respectivamente.

len(mnist_train), len(mnist_test)

(60000, 10000)

A altura e a largura de cada imagem de entrada são 28 pixels. Observe que o dataset consiste
em imagens em tons de cinza, cujo número de canais é 1. Para resumir, ao longo deste livro
armazenamos a forma de qualquer imagem com altura h largura w pixels como h × w or (h, w).

mnist_train[0][0].shape

120 Chapter 3. Linear Neural NetworkRedes Neurais Lineares


torch.Size([1, 28, 28])

As imagens no Fashion-MNIST estão associadas às seguintes categorias: t-shirt, calças, pulôver,


vestido, casaco, sandália, camisa, tênis, bolsa e bota. A função a seguir converte entre índices de
rótulos numéricos e seus nomes em texto.

def get_fashion_mnist_labels(labels): #@save


"""Return text labels for the Fashion-MNIST dataset."""
text_labels = ['t-shirt', 'trouser', 'pullover', 'dress', 'coat',
'sandal', 'shirt', 'sneaker', 'bag', 'ankle boot']
return [text_labels[int(i)] for i in labels]

Agora podemos criar uma função para visualizar esses exemplos.

def show_images(imgs, num_rows, num_cols, titles=None, scale=1.5): #@save


"""Plot a list of images."""
figsize = (num_cols * scale, num_rows * scale)
_, axes = d2l.plt.subplots(num_rows, num_cols, figsize=figsize)
axes = axes.flatten()
for i, (ax, img) in enumerate(zip(axes, imgs)):
if torch.is_tensor(img):
# Tensor Image
ax.imshow(img.numpy())
else:
# PIL Image
ax.imshow(img)
ax.axes.get_xaxis().set_visible(False)
ax.axes.get_yaxis().set_visible(False)
if titles:
ax.set_title(titles[i])
return axes

Aqui estão as imagens e seus labels correspondentes (no texto) para os primeiros exemplos nodataset*
de treinamento.

X, y = next(iter(data.DataLoader(mnist_train, batch_size=18)))
show_images(X.reshape(18, 28, 28), 2, 9, titles=get_fashion_mnist_labels(y));

3.5. O Dataset de Classificação de Imagens 121


3.5.2 Lendo um Minibatch

Para tornar nossa vida mais fácil ao ler os conjuntos de treinamento e teste, usamos o iterador de
dados integrado em vez de criar um do zero. Lembre-se de que a cada iteração, um carregador
de dados lê um minibatch de dados com tamanho batch_size cada vez. Também misturamos
aleatoriamente os exemplos para o iterador de dados de treinamento.

batch_size = 256

def get_dataloader_workers(): #@save


"""Use 4 processes to read the data."""
return 4

train_iter = data.DataLoader(mnist_train, batch_size, shuffle=True,


num_workers=get_dataloader_workers())

Vejamos o tempo que leva para ler os dados de treinamento.

timer = d2l.Timer()
for X, y in train_iter:
continue
f'{timer.stop():.2f} sec'

'1.96 sec'

3.5.3 Juntando Tudo

Agora definimos a função load_data_fashion_mnist que obtém e lê o dataset Fashion-MNIST. Ele


retorna os iteradores de dados para o conjunto de treinamento e o conjunto de validação. Além
disso, ele aceita um argumento opcional para redimensionar imagens para outra forma.

def load_data_fashion_mnist(batch_size, resize=None): #@save


"""Download the Fashion-MNIST dataset and then load it into memory."""
trans = [transforms.ToTensor()]
if resize:
trans.insert(0, transforms.Resize(resize))
trans = transforms.Compose(trans)
mnist_train = torchvision.datasets.FashionMNIST(
root="../data", train=True, transform=trans, download=True)
mnist_test = torchvision.datasets.FashionMNIST(
root="../data", train=False, transform=trans, download=True)
return (data.DataLoader(mnist_train, batch_size, shuffle=True,
num_workers=get_dataloader_workers()),
data.DataLoader(mnist_test, batch_size, shuffle=False,
num_workers=get_dataloader_workers()))

Abaixo testamos o recurso de redimensionamento de imagem da função


load_data_fashion_mnist especificando o argumento resize.

train_iter, test_iter = load_data_fashion_mnist(32, resize=64)


for X, y in train_iter:
(continues on next page)

122 Chapter 3. Linear Neural NetworkRedes Neurais Lineares


(continued from previous page)
print(X.shape, X.dtype, y.shape, y.dtype)
break

torch.Size([32, 1, 64, 64]) torch.float32 torch.Size([32]) torch.int64

Agora estamos prontos para trabalhar com o dataset Fashion-MNIST nas seções a seguir.

3.5.4 Resumo

• Fashion-MNIST é um dataset de classificação de vestuário que consiste em imagens que rep-


resentam 10 categorias. Usaremos esse conjunto de dados nas seções e capítulos subse-
quentes para avaliar vários algoritmos de classificação.
• Armazenamos a forma de qualquer imagem com altura h largura w pixels como h × w or (h,
w).
• Os iteradores de dados são um componente chave para um desempenho eficiente. Conte
com iteradores de dados bem implementados que exploram a computação de alto desem-
penho para evitar desacelerar o ciclo de treinamento.

3.5.5 Exercícios

1. A redução de batch_size (por exemplo, para 1) afeta o desempenho de leitura?


2. O desempenho do iterador de dados é importante. Você acha que a implementação atual é
rápida o suficiente? Explore várias opções para melhorá-lo.
3. Verifique a documentação online da API do framework. Quais outros conjuntos de dados
estão disponíveis?
Discussions39

3.6 Implementação da Regressão Softmax do Zero

Assim como implementamos a regressão linear do zero, acreditamos que regressão softmax é
igualmente fundamental e você deve saber os detalhes sangrentos de
como implementá-lo sozinho. Vamos trabalhar com o dataset Fashion-MNIST, recém-introduzido
em Section 3.5, configurando um iterador de dados com batch size 256.

import torch
from IPython import display
from d2l import torch as d2l

batch_size = 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)

39
https://discuss.d2l.ai/t/49

3.6. Implementação da Regressão Softmax do Zero 123


3.6.1 Inicializando os Parâmetros do Modelo

Como em nosso exemplo de regressão linear, cada exemplo aqui será representado por um vetor
de comprimento fixo. Cada exemplo no conjunto de dados bruto é uma imagem 28 × 28. Nesta
seção, vamos nivelar cada imagem, tratando-os como vetores de comprimento 784. No futuro,
falaremos sobre estratégias mais sofisticadas para explorar a estrutura espacial em imagens, mas,
por enquanto, tratamos cada localização de pixel como apenas outro recurso.
Lembre-se de que na regressão softmax, temos tantas saídas quanto classes. Como nosso conjunto
de dados tem 10 classes, nossa rede terá uma dimensão de saída de 10. Consequentemente, nossos
pesos constituirão uma matriz 784 × 10 e os bias constituirão um vetor-linha 1 × 10. Tal como
acontece com a regressão linear, vamos inicializar nossos pesos W com ruído Gaussiano e nossos
bias com o valor inicial 0.

num_inputs = 784
num_outputs = 10

W = torch.normal(0, 0.01, size=(num_inputs, num_outputs), requires_grad=True)


b = torch.zeros(num_outputs, requires_grad=True)

3.6.2 Definindo a Operação do Softmax

Antes de implementar o modelo de regressão do softmax, vamos revisar brevemente como o oper-
ador de soma funciona ao longo de dimensões específicas em um tensor, conforme discutido em:
numref Section 2.3.6 e Section 2.3.6. Dada uma matriz X, podemos somar todos os elementos (por
padrão) ou apenas sobre elementos no mesmo eixo, ou seja, a mesma coluna (eixo 0) ou a mesma
linha (eixo 1). Observe que se X é um tensor com forma (2, 3) e somamos as colunas, o resultado
será um vetor com forma (3,). Ao invocar o operador de soma, podemos especificar para manter o
número de eixos no tensor original, em vez de reduzir a dimensão que resumimos. Isso resultará
em um tensor bidimensional com forma (1, 3).

X = torch.tensor([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])


X.sum(0, keepdim=True), X.sum(1, keepdim=True)

(tensor([[5., 7., 9.]]),


tensor([[ 6.],
[15.]]))

Agora estamos prontos para implementar a operação do softmax . Lembre-se de que o softmax con-
siste em três etapas: i) exponenciamos cada termo (usando exp); ii) somamos cada linha (temos
uma linha por exemplo no lote) para obter a constante de normalização para cada exemplo; iii)
dividimos cada linha por sua constante de normalização, garantindo que o resultado seja 1. Antes
de olhar para o código, vamos lembrar como isso parece, expresso como uma equação:
exp(Xij )
softmax(X)ij = ∑ . (3.6.1)
k exp(Xik )

O denominador, ou constante de normalização, às vezes também é chamada de função de partição


(e seu logaritmo é chamado de função de partição de log). As origens desse nome estão em física
estatística40 onde uma equação relacionada modela a distribuição sobre um conjunto de partícu-
las.
40
https://en.wikipedia.org/wiki/Partition_function_%20(estatística_mecânica)

124 Chapter 3. Linear Neural NetworkRedes Neurais Lineares


def softmax(X):
X_exp = torch.exp(X)
partition = X_exp.sum(1, keepdim=True)
return X_exp / partition # The broadcasting mechanism is applied here

Como você pode ver, para qualquer entrada aleatória, transformamos cada elemento em um
número não negativo. Além disso, cada linha soma 1, como é necessário para uma probabilidade.

X = torch.normal(0, 1, (2, 5))


X_prob = softmax(X)
X_prob, X_prob.sum(1)

(tensor([[0.2947, 0.2476, 0.0139, 0.3211, 0.1228],


[0.0861, 0.2708, 0.0988, 0.0651, 0.4792]]),
tensor([1.0000, 1.0000]))

Observe que embora pareça correto matematicamente, fomos um pouco desleixados em nossa
implementação porque falhamos em tomar precauções contra estouro numérico ou estouro neg-
ativo devido a elementos grandes ou muito pequenos da matriz.

3.6.3 Definindo o Modelo

Agora que definimos a operação do softmax, podemos implementar o modelo de regressão soft-
max. O código a seguir define como a entrada é mapeada para a saída por meio da rede. Observe
que achatamos cada imagem original no lote em um vetor usando a função reshape antes de pas-
sar os dados pelo nosso modelo.

def net(X):
return softmax(torch.matmul(X.reshape((-1, W.shape[0])), W) + b)

3.6.4 Definindo a Função de Perda

Em seguida, precisamos implementar a função de perda de entropia cruzada, conforme apresen-


tado em Section 3.4. Esta pode ser a função de perda mais comum em todo o deep learning porque,
no momento, os problemas de classificação superam em muito os problemas de regressão.
Lembre-se de que a entropia cruzada leva a log-likelihood negativa da probabilidade prevista
atribuída ao rótulo verdadeiro. Em vez de iterar as previsões com um loop for Python (que tende
a ser ineficiente), podemos escolher todos os elementos por um único operador. Abaixo, nós cri-
amos dados de amostra y_hat com 2 exemplos de probabilidades previstas em 3 classes e seus
rótulos correspondentes y. Com y sabemos que no primeiro exemplo a primeira classe é a pre-
visão correta e no segundo exemplo, a terceira classe é a verdade fundamental. Usando y como os
índices das probabilidades emy_hat, escolhemos a probabilidade da primeira classe no primeiro
exemplo e a probabilidade da terceira classe no segundo exemplo.

y = torch.tensor([0, 2])
y_hat = torch.tensor([[0.1, 0.3, 0.6], [0.3, 0.2, 0.5]])
y_hat[[0, 1], y]

3.6. Implementação da Regressão Softmax do Zero 125


tensor([0.1000, 0.5000])

Agora podemos implementar a função de perda de entropia cruzada de forma eficiente com ape-
nas uma linha de código.

def cross_entropy(y_hat, y):


return - torch.log(y_hat[range(len(y_hat)), y])

cross_entropy(y_hat, y)

tensor([2.3026, 0.6931])

3.6.5 Exatidão da Classificação

Dada a distribuição de probabilidade prevista y_hat, normalmente escolhemos a classe com a


maior probabilidade prevista sempre que a previsão que devemos produzir é difícil. Na verdade,
muitos aplicativos exigem que façamos uma escolha. O Gmail deve categorizar um e-mail em
“Principal”, “Social”, “Atualizações” ou “Fóruns”. Pode estimar probabilidades internamente, mas
no final do dia ele tem que escolher uma das classes.
Quando as previsões são consistentes com a classe de label y, elas estão corretas. A precisão da
classificação é a fração de todas as previsões corretas. Embora possa ser difícil otimizar a pre-
cisão diretamente (não é diferenciável), muitas vezes é a medida de desempenho que mais nos
preocupa, e quase sempre o relataremos ao treinar classificadores.
Para calcular a precisão, fazemos o seguinte. Primeiro, se y_hat é uma matriz, presumimos que
a segunda dimensão armazena pontuações de predição para cada classe. Usamos argmax para
obter a classe prevista pelo índice para a maior entrada em cada linha. Em seguida, comparamos
a classe prevista com a verdade fundamental y elemento a elemento. Uma vez que o operador de
igualdade == é sensível aos tipos de dados, convertemos o tipo de dados de y_hat para correspon-
der ao dey. O resultado é um tensor contendo entradas de 0 (falso) e 1 (verdadeiro). Tirar a soma
resulta no número de previsões corretas.

def accuracy(y_hat, y): #@save


"""Compute the number of correct predictions."""
if len(y_hat.shape) > 1 and y_hat.shape[1] > 1:
y_hat = y_hat.argmax(axis=1)
cmp = y_hat.type(y.dtype) == y
return float(cmp.type(y.dtype).sum())

Continuaremos a usar as variáveis y_hat ey definidas antes como as distribuições de probabilidade


e labels previstos, respectivamente. Podemos ver que a classe prevista no primeiro exemplo é 2
(o maior elemento da linha é 0,6 com o índice 2), que é inconsistente com o rótulo real, 0. A
classe prevista do segundo exemplo é 2 (o maior elemento da linha é 0,5 com o índice de 2), que
é consistente com o rótulo real, 2. Portanto, a taxa de precisão da classificação para esses dois
exemplos é 0,5.

accuracy(y_hat, y) / len(y)

126 Chapter 3. Linear Neural NetworkRedes Neurais Lineares


0.5

Da mesma forma, podemos avaliar a precisão da rede de qualquer modelo em um conjunto de


dados que é acessado por meio do iterador de dados data_iter.

def evaluate_accuracy(net, data_iter): #@save


"""Compute the accuracy for a model on a dataset."""
if isinstance(net, torch.nn.Module):
net.eval() # Set the model to evaluation mode
metric = Accumulator(2) # No. of correct predictions, no. of predictions
for X, y in data_iter:
metric.add(accuracy(net(X), y), y.numel())
return metric[0] / metric[1]

Aqui, Accumulator é uma classe utilitária para acumular somas sobre múltiplas variáveis. Na
função evaluate_accuracy acima, criamos 2 variáveis na instância Accumulator para armazenar
ambos o número de previsões corretas e o número de previsões, respectivamente. Ambos serão
acumulados ao longo do tempo à medida que iteramos no conjunto de dados.

class Accumulator: #@save


"""For accumulating sums over `n` variables."""
def __init__(self, n):
self.data = [0.0] * n

def add(self, *args):


self.data = [a + float(b) for a, b in zip(self.data, args)]

def reset(self):
self.data = [0.0] * len(self.data)

def __getitem__(self, idx):


return self.data[idx]

PComo inicializamos o modelo net com pesos aleatórios, a precisão deste modelo deve ser próx-
ima à aleatoriedade, ou seja, 0,1 para 10 classes.

evaluate_accuracy(net, test_iter)

0.0918

3.6.6 Treinamento

O loop de treinamento para regressão softmax deve ser extremamente familiar se você ler nossa
implementação de regressão linear em Section 3.2. Aqui, nós refatoramos a implementação para
torná-la reutilizável. Primeiro, definimos uma função para treinar por uma época. Observe que
updater é uma função geral para atualizar os parâmetros do modelo, que aceita o tamanho do lote
como argumento. Pode ser um wrapper da função d2l.sgd ou a função de otimização integrada
de uma estrutura.

3.6. Implementação da Regressão Softmax do Zero 127


def train_epoch_ch3(net, train_iter, loss, updater): #@save
"""The training loop defined in Chapter 3."""
# Set the model to training mode
if isinstance(net, torch.nn.Module):
net.train()
# Sum of training loss, sum of training accuracy, no. of examples
metric = Accumulator(3)
for X, y in train_iter:
# Compute gradients and update parameters
y_hat = net(X)
l = loss(y_hat, y)
if isinstance(updater, torch.optim.Optimizer):
# Using PyTorch in-built optimizer & loss criterion
updater.zero_grad()
l.backward()
updater.step()
metric.add(float(l) * len(y), accuracy(y_hat, y),
y.size().numel())
else:
# Using custom built optimizer & loss criterion
l.sum().backward()
updater(X.shape[0])
metric.add(float(l.sum()), accuracy(y_hat, y), y.numel())
# Return training loss and training accuracy
return metric[0] / metric[2], metric[1] / metric[2]

Antes de mostrar a implementação da função de treinamento, definimos uma classe de utilitário


que plota dados em animação. Novamente, o objetivo é simplificar o código no restante do livro.

class Animator: #@save


"""For plotting data in animation."""
def __init__(self, xlabel=None, ylabel=None, legend=None, xlim=None,
ylim=None, xscale='linear', yscale='linear',
fmts=('-', 'm--', 'g-.', 'r:'), nrows=1, ncols=1,
figsize=(3.5, 2.5)):
# Incrementally plot multiple lines
if legend is None:
legend = []
d2l.use_svg_display()
self.fig, self.axes = d2l.plt.subplots(nrows, ncols, figsize=figsize)
if nrows * ncols == 1:
self.axes = [self.axes, ]
# Use a lambda function to capture arguments
self.config_axes = lambda: d2l.set_axes(
self.axes[0], xlabel, ylabel, xlim, ylim, xscale, yscale, legend)
self.X, self.Y, self.fmts = None, None, fmts

def add(self, x, y):


# Add multiple data points into the figure
if not hasattr(y, "__len__"):
y = [y]
n = len(y)
if not hasattr(x, "__len__"):
x = [x] * n
if not self.X:
(continues on next page)

128 Chapter 3. Linear Neural NetworkRedes Neurais Lineares


(continued from previous page)
self.X = [[] for _ in range(n)]
if not self.Y:
self.Y = [[] for _ in range(n)]
for i, (a, b) in enumerate(zip(x, y)):
if a is not None and b is not None:
self.X[i].append(a)
self.Y[i].append(b)
self.axes[0].cla()
for x, y, fmt in zip(self.X, self.Y, self.fmts):
self.axes[0].plot(x, y, fmt)
self.config_axes()
display.display(self.fig)
display.clear_output(wait=True)

A seguinte função de treinamento então treina um modelo net em um conjunto de dados de treina-
mento acessado viatrain_iter para várias épocas, que é especificado por num_epochs. No final de
cada época, o modelo é avaliado em um conjunto de dados de teste acessado via test_iter. Vamos
aproveitar a classe Animator para visualizar o progresso do treinamento.

def train_ch3(net, train_iter, test_iter, loss, num_epochs, updater): #@save


"""Train a model (defined in Chapter 3)."""
animator = Animator(xlabel='epoch', xlim=[1, num_epochs], ylim=[0.3, 0.9],
legend=['train loss', 'train acc', 'test acc'])
for epoch in range(num_epochs):
train_metrics = train_epoch_ch3(net, train_iter, loss, updater)
test_acc = evaluate_accuracy(net, test_iter)
animator.add(epoch + 1, train_metrics + (test_acc,))
train_loss, train_acc = train_metrics
assert train_loss < 0.5, train_loss
assert train_acc <= 1 and train_acc > 0.7, train_acc
assert test_acc <= 1 and test_acc > 0.7, test_acc

Como uma implementação do zero, nós usamos a descida gradiente estocástica do minibatch
definido em Section 3.2 para otimizar a função de perda do modelo com uma taxa de aprendizado
de 0,1.

lr = 0.1

def updater(batch_size):
return d2l.sgd([W, b], lr, batch_size)

Agora treinamos o modelo com 10 épocas. Observe que tanto o número de épocas (num_epochs), e
a taxa de aprendizagem (lr) são hiperparâmetros ajustáveis. Mudando seus valores, podemos ser
capazes de aumentar a precisão da classificação do modelo.

num_epochs = 10
train_ch3(net, train_iter, test_iter, cross_entropy, num_epochs, updater)

3.6. Implementação da Regressão Softmax do Zero 129


3.6.7 Predição

Agora que o treinamento está completo, nosso modelo está pronto para classificar algumas ima-
gens. Dada uma série de imagens, vamos comparar seus labels reais (primeira linha de saída de
texto) e as previsões do modelo (segunda linha de saída de texto).

def predict_ch3(net, test_iter, n=6): #@save


"""Predict labels (defined in Chapter 3)."""
for X, y in test_iter:
break
trues = d2l.get_fashion_mnist_labels(y)
preds = d2l.get_fashion_mnist_labels(net(X).argmax(axis=1))
titles = [true +'\n' + pred for true, pred in zip(trues, preds)]
d2l.show_images(
X[0:n].reshape((n, 28, 28)), 1, n, titles=titles[0:n])

predict_ch3(net, test_iter)

130 Chapter 3. Linear Neural NetworkRedes Neurais Lineares


3.6.8 Resumo

• Com a regressão softmax, podemos treinar modelos para classificação multiclasse.


• O loop de treinamento da regressão softmax é muito semelhante ao da regressão linear: recu-
perar e ler dados, definir modelos e funções de perda e treinar modelos usando algoritmos
de otimização. Como você descobrirá em breve, os modelos de deep learning mais comuns
têm procedimentos de treinamento semelhantes.

3.6.9 Exercícios

1. Nesta seção, implementamos diretamente a função softmax com base na definição


matemática da operação do softmax. Que problemas isso pode causar? Dica: tente calcu-
lar o tamanho de exp(50).
2. A função cross_entropy nesta seção foi implementada de acordo com a definição da função
de perda de entropia cruzada. Qual poderia ser o problema com esta implementação? Dica:
considere o domínio do logaritmo.
3. Que soluções você pode pensar para resolver os dois problemas acima?
4. É sempre uma boa ideia retornar o label mais provável? Por exemplo, você faria isso para
diagnóstico médico?
5. Suponha que quiséssemos usar a regressão softmax para prever a próxima palavra com base
em alguns recursos. Quais são alguns problemas que podem surgir de um vocabulário ex-
tenso?
Discussions41

3.7 Implementação Concisa da Regressão Softmax

APIs de alto nível tal como os frameworks de deep learning tornaram muito mais fácil de imple-
mentar a regressão linear em Section 3.3, encontraremos de forma semelhante (ou possivelmente
mais) conveniente, implementar modelos de classificação. Vamos ficar com o conjunto de dados
Fashion-MNIST e manter o tamanho do lote em 256 como em Section 3.6.

import torch
from torch import nn
from d2l import torch as d2l

batch_size = 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)

41
https://discuss.d2l.ai/t/51

3.7. Implementação Concisa da Regressão Softmax 131


3.7.1 Inicializando os Parâmetros do Modelo

Conforme mencionado em: numref: sec_softmax, a camada de saída da regressão softmax é uma
camada totalmente conectada. Portanto, para implementar nosso modelo, só precisamos adi-
cionar uma camada totalmente conectada com 10 saídas para nosso Sequential. Novamente,
aqui, o Sequential não é realmente necessário, mas podemos também criar o hábito, pois será
onipresente ao implementar modelos profundos. Novamente, inicializamos os pesos aleatoria-
mente com média zero e desvio padrão 0,01.

# PyTorch does not implicitly reshape the inputs. Thus we define the flatten
# layer to reshape the inputs before the linear layer in our network
net = nn.Sequential(nn.Flatten(), nn.Linear(784, 10))

def init_weights(m):
if type(m) == nn.Linear:
nn.init.normal_(m.weight, std=0.01)

net.apply(init_weights);

3.7.2 Implementação do Softmax Revisitada

No exemplo anterior de Section 3.6, calculamos a saída do nosso modelo e então executamos esta
saída através da perda de entropia cruzada. Matematicamente, isso é uma coisa perfeitamente
razoável de se fazer. No entanto, de uma perspectiva computacional, a exponenciação pode ser
uma fonte de problemas de estabilidade numérica.

Lembre-se de que a função softmax calcula ŷj = ∑exp(oj ) , onde ŷj é o elemento j th da distribuição
k exp(ok )
de probabilidade prevista ŷ e oj é o elemento j th dos logits o. Se alguns dos ok forem muito grandes
(ou seja, muito positivos), então exp(ok ) pode ser maior que o maior número, podemos ter para
certos tipos de dados (ou seja, estouro). Isso tornaria o denominador (e/ou numerador) inf (in-
finito) e acabamos encontrando 0, inf ounan (não um número) para ŷj . Nessas situações, não
obtemos uma definição bem definida valor de retorno para entropia cruzada.
Um truque para contornar isso é primeiro subtrair max(ok ) de todos ok antes de prosseguir com
o cálculo do softmax. Você pode ver que este deslocamento de cada ok por um fator constante não
altera o valor de retorno de softmax:

exp(oj − max(ok )) exp(max(ok ))


ŷj = ∑
k exp(ok − max(ok )) exp(max(ok ))
(3.7.1)
exp(oj − max(ok ))
=∑ .
k exp(ok − max(ok ))

Após a etapa de subtração e normalização, pode ser possível que alguns oj − max(ok ) tenham
grandes valores negativos e assim que o exp(oj −max(ok )) correspondente assumirá valores próx-
imos a zero. Eles podem ser arredondados para zero devido à precisão finita (ou seja, underflow),
tornando ŷj zero e dando-nos -inf para log(ŷj ). Alguns passos abaixo na backpropagation, pode-
mos nos encontrar diante de uma tela cheia dos temidos resultados nan.
Felizmente, somos salvos pelo fato de que embora estejamos computando funções exponenciais,
em última análise, pretendemos levar seu log (ao calcular a perda de entropia cruzada). Com-
binando esses dois operadores softmax e entropia cruzada juntos, podemos escapar dos proble-
mas de estabilidade numérica que poderia nos atormentar durante a backpropagation. Conforme

132 Chapter 3. Linear Neural NetworkRedes Neurais Lineares


mostrado na equação abaixo, evitamos calcular exp(oj − max(ok )) e podemos usar oj − max(ok )
diretamente devido ao cancelamento em log(exp(·)):
( )
exp(oj − max(ok ))
log (ŷj ) = log ∑
k exp(ok − max(ok ))
( )

= log (exp(oj − max(ok ))) − log exp(ok − max(ok )) (3.7.2)
k
( )

= oj − max(ok ) − log exp(ok − max(ok )) .
k

Queremos manter a função softmax convencional acessível no caso de querermos avaliar as prob-
abilidades de saída por nosso modelo. Mas em vez de passar probabilidades de softmax para nossa
nova função de perda, nós vamos apenas passar os logits e calcular o softmax e seu log tudo de uma
vez dentro da função de perda de entropia cruzada, que faz coisas inteligentes como o “Truque
LogSumExp”42 .

loss = nn.CrossEntropyLoss()

3.7.3 Otimização do Algoritmo

Aqui, nós usamos gradiente descendente estocástico de minibatch com uma taxa de aprendizado
de 0,1 como o algoritmo de otimização. Observe que este é o mesmo que aplicamos no exemplo
de regressão linear e ilustra a aplicabilidade geral dos otimizadores.

trainer = torch.optim.SGD(net.parameters(), lr=0.1)

3.7.4 Trainamento

Em seguida, chamamos a função de treinamento definida em Section 3.6 para treinar o modelo.

num_epochs = 10
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer)

42
https://en.wikipedia.org/wiki/LogSumExp

3.7. Implementação Concisa da Regressão Softmax 133


Como antes, este algoritmo converge para uma solução que atinge uma precisão decente, embora
desta vez com menos linhas de código do que antes.

3.7.5 Resumo

• Usando APIs de alto nível, podemos implementar a regressão softmax de forma muito mais
concisa.
• De uma perspectiva computacional, a implementação da regressão softmax tem complex-
idades. Observe que, em muitos casos, uma estrutura de deep learning toma precauções
adicionais além desses truques mais conhecidos para garantir a estabilidade numérica,
salvando-nos de ainda mais armadilhas que encontraríamos se tentássemos codificar todos
os nossos modelos do zero na prática.

3.7.6 Exercícios

1. Tente ajustar os hiperparâmetros, como batch size, número de épocas e taxa de aprendizado,
para ver quais são os resultados.
2. Aumente o número de épocas de treinamento. Por que a precisão do teste pode diminuir
depois de um tempo? Como poderíamos consertar isso?
3.
Discussions43

43
https://discuss.d2l.ai/t/53

134 Chapter 3. Linear Neural NetworkRedes Neurais Lineares


4 | Perceptrons Multicamada

Neste capítulo, apresentaremos sua primeira rede verdadeiramente profunda. As redes profun-
das mais simples são chamadas perceptrons multicamada, e eles consistem em várias camadas
de neurônios cada um totalmente conectado àqueles na camada abaixo (do qual eles recebem
contribuições) e aqueles acima (que eles, por sua vez, influenciam). Quando treinamos mode-
los de alta capacidade, corremos o risco de fazer overfitting. Portanto, precisaremos fornecer sua
primeira introdução rigorosa às noções de overfitting, underfitting e seleção de modelo. Para ajudá-
lo a combater esses problemas, apresentaremos técnicas de regularização, como redução do peso
e abandono escolar. Também discutiremos questões relacionadas à estabilidade numérica e ini-
cialização de parâmetros que são essenciais para o treinamento bem-sucedido de redes profun-
das. Durante todo o tempo, nosso objetivo é dar a você uma compreensão firme não apenas dos
conceitos mas também da prática de usar redes profundas. No final deste capítulo, aplicamos
o que apresentamos até agora a um caso real: a previsão do preço da casa. Nós examinamos
questões relacionadas ao desempenho computacional, escalabilidade e eficiência de nossos mod-
elos para os capítulos subsequentes.

4.1 Perceptrons Multicamada

Em Chapter 3,, apresentamos regressão softmax (Section 3.4), implementando o algoritmo do zero
(Section 3.6) e usando APIs de alto nível (Section 3.7), e classificadores de treinamento para re-
conhecer 10 categorias de roupas a partir de imagens de baixa resolução. Ao longo do caminho,
aprendemos como organizar dados, coagir nossos resultados em uma distribuição de probabili-
dade válida, aplicar uma função de perda apropriada, e minimizá-la em relação aos parâmetros
do nosso modelo. Agora que dominamos essa mecânica no contexto de modelos lineares simples,
podemos lançar nossa exploração de redes neurais profundas, a classe comparativamente rica de
modelos com o qual este livro se preocupa principalmente.

4.1.1 Camadas Ocultas

Descrevemos a transformação afim em Section 3.1.1, que é uma transformação linear adicionada
por um bias. Para começar, relembre a arquitetura do modelo correspondendo ao nosso exemplo de
regressãosoftmax, ilustrado em :numref:`fig_softmaxreg`. Este modelo mapeou nossas entradas direta-
mente para nossas saídas por meio de uma única transformação afim, seguido por uma operaçãosoftmax.
Se nossoslabels* realmente estivessem relacionados aos nossos dados de entrada por uma transfor-
mação afim, então esta abordagem seria suficiente. Mas a linearidade nas transformações afins é
uma suposição forte.

135
Modelos Lineares Podem Dar Errado

Por exemplo, linearidade implica a mais fraca suposição de monotonicidade: que qualquer au-
mento em nosso recurso deve sempre causar um aumento na saída do nosso modelo (se o peso
correspondente for positivo), ou sempre causa uma diminuição na saída do nosso modelo (se o
peso correspondente for negativo). Às vezes, isso faz sentido. Por exemplo, se estivéssemos ten-
tando prever se um indivíduo vai pagar um empréstimo, podemos razoavelmente imaginar que
mantendo tudo o mais igual, um candidato com uma renda maior sempre estaria mais propenso
a retribuir do que um com uma renda mais baixa. Embora monotônico, esse relacionamento
provavelmente não está linearmente associado à probabilidade de reembolso. Um aumento na
receita de 0 a 50 mil provavelmente corresponde a um aumento maior em probabilidade de reem-
bolso do que um aumento de 1 milhão para 1,05 milhão. Uma maneira de lidar com isso pode ser
pré-processar nossos dados de forma que a linearidade se torne mais plausível, digamos, usando
o logaritmo da receita como nosso recurso.
Observe que podemos facilmente encontrar exemplos que violam a monotonicidade. Digamos,
por exemplo, que queremos prever a probabilidade de morte com base na temperatura corpo-
ral. Para indivíduos com temperatura corporal acima de 37 ° C (98,6 ° F), temperaturas mais al-
tas indicam maior risco. No entanto, para indivíduos com temperatura corporal abaixo de 37 °
C, temperaturas mais altas indicam risco menor! Também neste caso, podemos resolver o prob-
lema com algum pré-processamento inteligente. Ou seja, podemos usar a distância de 37 ° C como
nossa feature.
Mas que tal classificar imagens de cães e gatos? Aumentar a intensidade do pixel no local (13,
17) deveria sempre aumentar (ou sempre diminuir) a probabilidade de que a imagem retrate um
cachorro? A confiança em um modelo linear corresponde à implícita suposição de que o único
requisito para diferenciar gatos vs. cães é avaliar o brilho de pixels individuais. Esta abordagem
está fadada ao fracasso em um mundo onde inverter uma imagem preserva a categoria.
E ainda, apesar do aparente absurdo da linearidade aqui, em comparação com nossos exemp-
los anteriores, é menos óbvio que poderíamos resolver o problema com uma correção de pré-
processamento simples. Isso ocorre porque o significado de qualquer pixel depende de maneiras
complexas de seu contexto (os valores dos pixels circundantes). Embora possa existir uma rep-
resentação de nossos dados isso levaria em consideração as interações relevantes entre nossas
características, no topo das quais um modelo linear seria adequado, nós simplesmente não sabe-
mos como calculá-lo à mão. Com redes neurais profundas, usamos dados observacionais para
aprender conjuntamente uma representação por meio de camadas ocultas e um preditor linear
que atua sobre essa representação.

Incorporando Camadas Ocultas

Podemos superar essas limitações dos modelos lineares e lidar com uma classe mais geral de
funções incorporando uma ou mais camadas ocultas. A maneira mais fácil de fazer isso é empil-
har muitas camadas totalmente conectadas umas sobre as outras. Cada camada alimenta a ca-
mada acima dela, até gerarmos resultados. Podemos pensar nas primeiras L − 1 camadas como
nossa representação e a camada final como nosso preditor linear. Esta arquitetura é comumente
chamada um perceptron multicamadas, frequentemente abreviado como MLP. Abaixo, represen-
tamos um MLP em diagrama (fig_mlp).

136 Chapter 4. Perceptrons Multicamada


.. _fig_mlp:
Este MLP tem 4 entradas, 3 saídas, e sua camada oculta contém 5 unidades ocultas. Uma vez que
a camada de entrada não envolve nenhum cálculo, produzindo saídas com esta rede requer a im-
plementação dos cálculos para as camadas ocultas e de saída; assim, o número de camadas neste
MLP é 2. Observe que essas camadas estão totalmente conectadas. Cada entrada influencia cada
neurônio na camada oculta, e cada um deles, por sua vez, influencia cada neurônio na camada
de saída. No entanto, conforme sugerido por Section 3.4.3, o custo de parametrização de MLPs
com camadas totalmente conectadas pode ser proibitivamente alto, o que pode motivar compen-
sação entre o salvamento do parâmetro e a eficácia do modelo, mesmo sem alterar o tamanho de
entrada ou saída (Zhang et al., 2021).

De Linear Para não Linear

Como antes, pela matriz X ∈ Rn×d , denotamos um minibatch de n exemplos em que cada exemplo
tem d entradas (features). Para um MLP de uma camada oculta, cuja camada oculta tem h unidades
ocultas, denotamos por H ∈ Rn×h as saídas da camada oculta, que são representações ocultas. Em
matemática ou código, H também é conhecido como uma variável de camada oculta ou uma variável
oculta. Uma vez que as camadas ocultas e de saída estão totalmente conectadas, temos pesos de
camada oculta W(1) ∈ Rd×h e bias b(1) ∈ R1×h e pesos da camada de saída W(2) ∈ Rh×q e bias
b(2) ∈ R1×q . Formalmente, calculamos as saídas O ∈ Rn×q do MLP de uma camada oculta da
seguinte maneira:

H = XW(1) + b(1) ,
(4.1.1)
O = HW(2) + b(2) .

Observe que depois de adicionar a camada oculta, nosso modelo agora exige que rastreemos e
atualizemos conjuntos adicionais de parâmetros. Então, o que ganhamos em troca? Você pode se
surpreender ao descobrir que — no modelo definido acima — nós não ganhamos nada pelos nossos
problemas! O motivo é claro. As unidades ocultas acima são fornecidas por uma função afim das
entradas, e as saídas (pré-softmax) são apenas uma função afim das unidades ocultas. Uma função
afim de uma função afim é em si uma função afim. Além disso, nosso modelo linear já era capaz
de representar qualquer função afim.
Podemos ver a equivalência formalmente provando que para quaisquer valores dos pesos, pode-
mos apenas recolher a camada oculta, produzindo um modelo de camada única equivalente com
parâmetros W = W(1) W(2) and b = b(1) W(2) + b(2) :

O = (XW(1) + b(1) )W(2) + b(2) = XW(1) W(2) + b(1) W(2) + b(2) = XW + b. (4.1.2)

4.1. Perceptrons Multicamada 137


Para perceber o potencial das arquiteturas multicamadas, precisamos de mais um ingrediente
chave: a função de ativação não linear σ a ser aplicada a cada unidade oculta seguindo a transfor-
mação afim. As saídas das funções de ativação (por exemplo, σ(·)) são chamadas de ativações. Em
geral, com as funções de ativação implementadas, não é mais possível reduzir nosso MLP em um
modelo linear:

H = σ(XW(1) + b(1) ),
(4.1.3)
O = HW(2) + b(2) .

Uma vez que cada linha em X corresponde a um exemplo no minibatch, com algum abuso de no-
tação, definimos a não linearidade σ para aplicar às suas entradas de uma forma em linha, ou seja,
um exemplo de cada vez. Observe que usamos a notação para softmax da mesma forma para deno-
tar uma operação nas linhas em Section 3.4.5. Frequentemente, como nesta seção, as funções de
ativação que aplicamos a camadas ocultas não são apenas nas linhas, mas elemento a elemento.
Isso significa que depois de calcular a parte linear da camada, podemos calcular cada ativação sem
olhar para os valores assumidos pelas outras unidades ocultas. Isso é verdadeiro para a maioria
das funções de ativação.
Para construir MLPs mais gerais, podemos continuar empilhando tais camadas escondidas, por
exemplo, H(1) = σ1 (XW(1) + b(1) ) e H(2) = σ2 (H(1) W(2) + b(2) ), uma sobre a outra, rendendo
modelos cada vez mais expressivos.

Aproximadores Universais

MLPs podem capturar interações complexas entre nossas entradas por meio de seus neurônios
ocultos, que dependem dos valores de cada uma das entradas. Podemos projetar nós ocultos facil-
mente para realizar cálculos arbitrários, por exemplo, operações lógicas básicas em um par de
entradas. Além disso, para certas escolhas da função de ativação, é amplamente conhecido que
os MLPs são aproximadores universais. Mesmo com uma rede de camada única oculta, dados
nós suficientes (possivelmente absurdamente muitos deles), e o conjunto certo de pesos, pode-
mos modelar qualquer função, embora realmente aprender essa função seja a parte difícil. Você
pode pensar em sua rede neural como sendo um pouco como a linguagem de programação C. A
linguagem, como qualquer outra linguagem moderna, é capaz de expressar qualquer programa
computável. Mas, na verdade, criar um programa que atenda às suas especificações é a parte
difícil.
Além disso, só porque uma rede de camada única oculta pode aprender qualquer função não sig-
nifica que você deve tentar resolver todos os seus problemas com redes de camada única oculta.
Na verdade, podemos aproximar muitas funções de forma muito mais compacta, usando redes
mais profundas (em comparação com redes mais amplas). Trataremos de argumentos mais rig-
orosos nos capítulos subsequentes.

4.1.2 Funções de Ativação

As funções de ativação decidem se um neurônio deve ser ativado ou não por calcular a soma pon-
derada e adicionar ainda o bias com ela. Eles são operadores diferenciáveis para transformar
sinais de entrada em saídas, enquanto a maioria deles adiciona não linearidade. Como as funções
de ativação são fundamentais para o deep learning, vamos examinar brevemente algumas funções
de ativação comuns.

138 Chapter 4. Perceptrons Multicamada


%matplotlib inline
import torch
from d2l import torch as d2l

Função ReLU

A escolha mais popular, devido à simplicidade de implementação e seu bom desempenho em uma
variedade de tarefas preditivas, é a unidade linear retificada (ReLU). ReLU fornece uma transfor-
mação não linear muito simples. Dado um elemento x, a função é definida como o máximo desse
elemento e 0:

ReLU(x) = max(x, 0). (4.1.4)

Informalmente, a função ReLU retém apenas elementos positivos e descarta todos os elementos
negativos definindo as ativações correspondentes para 0. Para obter alguma intuição, podemos
representar graficamente a função. Como você pode ver, a função de ativação é linear por partes.

x = torch.arange(-8.0, 8.0, 0.1, requires_grad=True)


y = torch.relu(x)
d2l.plot(x.detach(), y.detach(), 'x', 'relu(x)', figsize=(5, 2.5))

Quando a entrada é negativa, a derivada da função ReLU é 0, e quando a entrada é positiva, a


derivada da função ReLU é 1. Observe que a função ReLU não é diferenciável quando a entrada
assume um valor precisamente igual a 0. Nesses casos, o padrão é o lado esquerdo da derivada,
e dizemos que a derivada é 0 quando a entrada é 0. Podemos escapar impunes porque a entrada
pode nunca ser realmente zero. Há um velho ditado que diz que se as condições de contorno
sutis são importantes, provavelmente estamos fazendo matemática (real), não engenharia. Essa
sabedoria convencional pode se aplicar aqui. Plotamos a derivada da função ReLU abaixo.

y.backward(torch.ones_like(x), retain_graph=True)
d2l.plot(x.detach(), x.grad, 'x', 'grad of relu', figsize=(5, 2.5))

4.1. Perceptrons Multicamada 139


A razão para usar ReLU é que suas derivadas são particularmente bem comportadas: ou elas desa-
parecem ou simplesmente deixam * argumento passar. Isso torna a otimização melhor compor-
tada e mitiga o problema bem documentado de gradientes de desaparecimento que atormentaram
versões anteriores de redes neurais (mais sobre isso mais tarde).
Observe que existem muitas variantes da função ReLU, incluindo a função ReLU parametrizada
(pReLU) (He et al., 2015). Esta variação adiciona um termo linear ao ReLU, então algumas infor-
mações ainda são transmitidas, mesmo quando o argumento é negativo:

pReLU(x) = max(0, x) + α min(0, x). (4.1.5)

Função Sigmoid

A função sigmoid transforma suas entradas, para as quais os valores estão no domínio R, para
saídas que estão no intervalo (0, 1). Por esse motivo, o sigmoid é frequentemente chamada de
função de esmagamento: ele esmaga qualquer entrada no intervalo (-inf, inf) para algum valor no
intervalo (0, 1):
1
sigmoid(x) = . (4.1.6)
1 + exp(−x)

Nas primeiras redes neurais, os cientistas estavam interessados em modelar neurônios biológi-
cos que disparam ou não disparam. Assim, os pioneiros neste campo, voltando para McCulloch e
Pitts, os inventores do neurônio artificial, focaram em unidades de limiar. Uma ativação de limite
assume valor 0 quando sua entrada está abaixo de algum limite e valor 1 quando a entrada excede
o limite.
Quando a atenção mudou para o aprendizado baseado em gradiente, a função sigmoid foi uma
escolha natural porque é uma boa, diferenciável aproximação a uma unidade de limiar. Sigmoids
ainda são amplamente usados como funções de ativação nas unidades de saída, quando quer-
emos interpretar as saídas como probabilidades para problemas de classificação binária (você
pode pensar na sigmoid como um caso especial do softmax). No entanto, a sigmoid foi quase toda
substituído pelo ReLU, mais simples e facilmente treinável para mais uso em camadas ocultas.
Em capítulos posteriores sobre redes neurais recorrentes, iremos descrever arquiteturas que ala-
vancam unidades sigmoid para controlar o fluxo de informações ao longo do tempo.
Abaixo, traçamos a função sigmoid. Observe que quando a entrada está próxima de 0, a função
sigmoid se aproxima uma transformação linear.

140 Chapter 4. Perceptrons Multicamada


y = torch.sigmoid(x)
d2l.plot(x.detach(), y.detach(), 'x', 'sigmoid(x)', figsize=(5, 2.5))

A derivada da função sigmoid é dada pela seguinte equação:

d exp(−x)
sigmoid(x) = = sigmoid(x) (1 − sigmoid(x)) . (4.1.7)
dx (1 + exp(−x))2

A derivada da função sigmoid é plotada abaixo. Observe que quando a entrada é 0, a derivada da
função sigmoid atinge um máximo de 0,25. À medida que a entrada diverge de 0 em qualquer
direção, a derivada se aproxima de 0.

# Clear out previous gradients


x.grad.data.zero_()
y.backward(torch.ones_like(x),retain_graph=True)
d2l.plot(x.detach(), x.grad, 'x', 'grad of sigmoid', figsize=(5, 2.5))

4.1. Perceptrons Multicamada 141


Função Tanh

Como a função sigmoid, a tanh (tangente hiperbólica) função também comprime suas entradas,
transformando-as em elementos no intervalo entre -1 e 1:
1 − exp(−2x)
tanh(x) = . (4.1.8)
1 + exp(−2x)

Traçamos a função tanh abaixo. Observe que, à medida que a entrada se aproxima de 0, a função
tanh se aproxima de uma transformação linear. Embora a forma da função seja semelhante à da
função sigmoid, a função tanh exibe uma simetria de ponto sobre a origem do sistema de coorde-
nadas.

y = torch.tanh(x)
d2l.plot(x.detach(), y.detach(), 'x', 'tanh(x)', figsize=(5, 2.5))

A derivada da função tanh é:

d
tanh(x) = 1 − tanh2 (x). (4.1.9)
dx
A derivada da função tanh é plotada abaixo. Conforme a entrada se aproxima de 0, a derivada da
função tanh se aproxima de um máximo de 1. E como vimos com a função sigmoid, conforme a
entrada se afasta de 0 em qualquer direção, a derivada da função tanh se aproxima de 0.

# Clear out previous gradients.


x.grad.data.zero_()
y.backward(torch.ones_like(x),retain_graph=True)
d2l.plot(x.detach(), x.grad, 'x', 'grad of tanh', figsize=(5, 2.5))

142 Chapter 4. Perceptrons Multicamada


Em resumo, agora sabemos como incorporar não linearidades para construir arquiteturas de rede
neural multicamadas expressivas. Como uma nota lateral, o seu conhecimento já coloca você no
comando de um kit de ferramentas semelhante para um praticante por volta de 1990. De certa
forma, você tem uma vantagem sobre qualquer pessoa que trabalhou na década de 1990, porque
você pode alavancar frameworks de deep learning de código aberto para construir modelos rapi-
damente, usando apenas algumas linhas de código. Anteriormente, o treinamento dessas redes
pesquisadores obrigados a codificar milhares de linhas de C e Fortran.

4.1.3 Resumo

• O MLP adiciona uma ou várias camadas ocultas totalmente conectadas entre as camadas
de saída e de entrada e transforma a saída da camada oculta por meio de uma função de
ativação.
• As funções de ativação comumente usadas incluem a função ReLU, a função sigmoid e a
função tanh.

4.1.4 Exercícios

1. Calcule a derivada da função de ativação pReLU.


2. Mostre que um MLP usando apenas ReLU (ou pReLU) constrói uma função linear contínua
por partes.
3. Mostre que tanh(x) + 1 = 2 sigmoid(2x).
4. Suponha que temos uma não linearidade que se aplica a um minibatch por vez. Que tipo de
problemas você espera que isso cause?
Discussions44
44
https://discuss.d2l.ai/t/91

4.1. Perceptrons Multicamada 143


4.2 Implementação de Perceptrons Multicamadas do Zero

Agora que caracterizamos perceptrons multicamadas (MLPs) matematicamente, vamos tentar


implementar um nós mesmos. Para comparar com nossos resultados anteriores alcançado com
regressão softmax (Section 3.6), vamos continuar a trabalhar com o conjunto de dados de classifi-
cação de imagens Fashion-MNIST (Section 3.5).

import torch
from torch import nn
from d2l import torch as d2l

batch_size = 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)

4.2.1 Inicializando os Parâmetros do Modelo

Lembre-se de que o Fashion-MNIST contém 10 classes, e que cada imagem consiste em uma
graded 28 × 28 = 784 de valores de pixel em tons de cinza. Novamente, vamos desconsiderar
a estrutura espacial entre os pixels por enquanto, então podemos pensar nisso simplesmente
como um conjunto de dados de classificação com 784 características de entrada e 10 classes. Para
começar, iremos implementar um MLP com uma camada oculta e 256 unidades ocultas. Observe
que podemos considerar essas duas quantidades como hiperparâmetros. Normalmente, escol-
hemos larguras de camada em potências de 2, que tendem a ser computacionalmente eficientes
porque de como a memória é alocada e endereçada no hardware.
Novamente, iremos representar nossos parâmetros com vários tensores. Observe que para cada
camada, devemos acompanhar uma matriz de ponderação e um vetor de polarização. Como sem-
pre, alocamos memória para os gradientes da perda com relação a esses parâmetros.

num_inputs, num_outputs, num_hiddens = 784, 10, 256

W1 = nn.Parameter(torch.randn(
num_inputs, num_hiddens, requires_grad=True) * 0.01)
b1 = nn.Parameter(torch.zeros(num_hiddens, requires_grad=True))
W2 = nn.Parameter(torch.randn(
num_hiddens, num_outputs, requires_grad=True) * 0.01)
b2 = nn.Parameter(torch.zeros(num_outputs, requires_grad=True))

params = [W1, b1, W2, b2]

4.2.2 Função de Ativação

Para ter certeza de que sabemos como tudo funciona, iremos implementar a ativação ReLU nós
mesmos usar a função máxima em vez de invocar a função embutida relu diretamente.

def relu(X):
a = torch.zeros_like(X)
return torch.max(X, a)

144 Chapter 4. Perceptrons Multicamada


4.2.3 Modelo

Porque estamos desconsiderando a estrutura espacial, nós remodelamos cada imagem bidimen-
sional em um vetor plano de comprimento num_inputs. Finalmente, nós implementamos nosso
modelo com apenas algumas linhas de código.

def net(X):
X = X.reshape((-1, num_inputs))
H = relu(X@W1 + b1) # Here '@' stands for matrix multiplication
return (H@W2 + b2)

4.2.4 Função de Perda

Para garantir estabilidade numérica, e porque já implementamos a função* softmax* do zero (Sec-
tion 3.6), alavancamos a função integrada de APIs de alto nível para calcular o softmax e a perda de
entropia cruzada. Lembre-se de nossa discussão anterior sobre essas complexidades em Section
3.7.2. Nós encorajamos o leitor interessado a examinar o código-fonte para a função de perda para
aprofundar seu conhecimento dos detalhes de implementação.

loss = nn.CrossEntropyLoss()

4.2.5 Trainamento

Felizmente, o loop de treinamento para MLPs é exatamente igual à regressão softmax. Aprovei-
tando o pacote d2l novamente, chamamos a função train_ch3 (ver Section 3.6), definindo o
número de épocas para 10 e a taxa de aprendizagem para 0,1.

num_epochs, lr = 10, 0.1


updater = torch.optim.SGD(params, lr=lr)
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, updater)

Para avaliar o modelo aprendido, nós aplicamos em alguns dados de teste.

4.2. Implementação de Perceptrons Multicamadas do Zero 145


d2l.predict_ch3(net, test_iter)

4.2.6 Resumo

• Vimos que implementar um MLP simples é fácil, mesmo quando feito manualmente.
• No entanto, com um grande número de camadas, implementar MLPs do zero ainda pode ser
complicado (por exemplo, nomear e controlar os parâmetros do nosso modelo).

4.2.7 Exercícios

1. Altere o valor do hiperparâmetro num_hiddens e veja como esse hiperparâmetro influencia


seus resultados. Determine o melhor valor deste hiperparâmetro, mantendo todos os outros
constantes.
2. Experimente adicionar uma camada oculta adicional para ver como isso afeta os resultados.
3. Como mudar a taxa de aprendizado altera seus resultados? Corrigindo a arquitetura do mod-
elo e outros hiperparâmetros (incluindo o número de épocas), qual taxa de aprendizado ofer-
ece os melhores resultados?
4. Qual é o melhor resultado que você pode obter otimizando todos os hiperparâmetros (taxa de
aprendizagem, número de épocas, número de camadas ocultas, número de unidades ocultas
por camada) em conjunto?
5. Descreva por que é muito mais difícil lidar com vários hiperparâmetros.
6. Qual é a estratégia mais inteligente que você pode imaginar para estruturar uma pesquisa
em vários hiperparâmetros?
Discussions45
45
https://discuss.d2l.ai/t/93

146 Chapter 4. Perceptrons Multicamada


4.3 Implementação Concisa de Perceptrons Multicamadas

As you might expect, by relying on the high-level APIs, we can implement MLPs even more con-
cisely.

import torch
from torch import nn
from d2l import torch as d2l

4.3.1 Modelo

Em comparação com nossa implementação concisa de implementação de regressão softmax (Sec-


tion 3.7), a única diferença é que adicionamos duas camadas totalmente conectadas (anterior-
mente, adicionamos uma). A primeira é nossa camada oculta, que contém 256 unidades ocultas e
aplica a função de ativação ReLU. A segunda é nossa camada de saída.

net = nn.Sequential(nn.Flatten(),
nn.Linear(784, 256),
nn.ReLU(),
nn.Linear(256, 10))

def init_weights(m):
if type(m) == nn.Linear:
nn.init.normal_(m.weight, std=0.01)

net.apply(init_weights);

O loop de treinamento é exatamente o mesmo como quando implementamos a regressão softmax.


Essa modularidade nos permite separar questões relativas à arquitetura do modelo a partir de
considerações ortogonais.

batch_size, lr, num_epochs = 256, 0.1, 10


loss = nn.CrossEntropyLoss()
trainer = torch.optim.SGD(net.parameters(), lr=lr)

train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)


d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer)

4.3. Implementação Concisa de Perceptrons Multicamadas 147


4.3.2 Resumo

• Usando APIs de alto nível, podemos implementar MLPs de forma muito mais concisa.
• Para o mesmo problema de classificação, a implementação de um MLP é a mesma da re-
gressão softmax, exceto para camadas ocultas adicionais com funções de ativação.

4.3.3 Exercícios

1. Tente adicionar diferentes números de camadas ocultas (você também pode modificar a taxa
de aprendizagem). Qual configuração funciona melhor?
2. Experimente diferentes funções de ativação. Qual funciona melhor?
3. Experimente diferentes esquemas para inicializar os pesos. Qual método funciona melhor?
Discussions46

4.4 Seleção do Modelo, Underfitting, e Overfitting

Como cientistas de machine learning, nosso objetivo é descobrir padrões. Mas como podemos
ter certeza de que realmente descobrimos um padrão geral e não simplesmente memorizamos
nossos dados? Por exemplo, imagine que queremos caçar padrões entre marcadores genéti-
cos ligando os pacientes ao seu estado de demência, onde os rótulos são retirados do conjunto
{dementia, mild cognitive impairment, healthy} Como os genes de cada pessoa os identificam de
forma única (ignorando irmãos idênticos), é possível memorizar todo o conjunto de dados.
Não queremos que nosso modelo diga “É o Bob! Lembro-me dele! Ele tem demência!” O motivo é
simples. Quando implantamos o modelo no futuro, nós encontraremos pacientes que o modelo
nunca viu antes. Nossas previsões só serão úteis se nosso modelo realmente descobriu um padrão
geral.
Para recapitular mais formalmente, nosso objetivo é descobrir padrões que capturam regulari-
dades na população subjacente da qual nosso conjunto de treinamento foi extraído. Se tivermos
46
https://discuss.d2l.ai/t/95

148 Chapter 4. Perceptrons Multicamada


sucesso neste empreendimento, então poderíamos avaliar com sucesso o risco mesmo para indi-
víduos que nunca encontramos antes. Este problema — como descobrir padrões que generalizam
— é o problema fundamental do machine learning.
O perigo é que, quando treinamos modelos, acessamos apenas uma pequena amostra de dados. Os
maiores conjuntos de dados de imagens públicas contêm cerca de um milhão de imagens. Mais
frequentemente, devemos aprender com apenas milhares ou dezenas de milhares de exemplos
de dados. Em um grande sistema hospitalar, podemos acessar centenas de milhares de registros
médicos. Ao trabalhar com amostras finitas, corremos o risco de poder descobrir associações
aparentes que acabam não se sustentando quando coletamos mais dados.
O fenômeno de ajustar nossos dados de treinamento mais precisamente do que ajustamos, a dis-
tribuição subjacente é chamada de overfitting, e as técnicas usadas para combater o overfitting são
chamadas de regularização. Nas seções anteriores, você deve ter observado esse efeito durante a
experiência com o conjunto de dados Fashion-MNIST. Se você alterou a estrutura do modelo ou os
hiperparâmetros durante o experimento, deve ter notado que, com neurônios, camadas e perío-
dos de treinamento suficientes, o modelo pode eventualmente atingir uma precisão perfeita no
conjunto de treinamento, mesmo quando a precisão dos dados de teste se deteriora.

4.4.1 Erro de Treinamento e Erro de Generalização

Para discutir este fenômeno de forma mais formal, precisamos diferenciar entre erro de treina-
mento e erro de generalização. O erro de treinamento é o erro do nosso modelo conforme calculado
no conjunto de dados de treinamento, enquanto erro de generalização é a expectativa do erro do
nosso modelo deveríamos aplicá-lo a um fluxo infinito de exemplos de dados adicionais extraído
da mesma distribuição de dados subjacente que nossa amostra original.
De forma problemática, nunca podemos calcular o erro de generalização com exatidão. Isso
ocorre porque o fluxo de dados infinitos é um objeto imaginário. Na prática, devemos estimar
o erro de generalização aplicando nosso modelo a um conjunto de teste independente constituído
de uma seleção aleatória de exemplos de dados que foram retirados de nosso conjunto de treina-
mento.
Os três experimentos mentais a seguir ajudarão a ilustrar melhor esta situação. Considere um
estudante universitário tentando se preparar para o exame final. Um aluno diligente se esforçará
para praticar bem e testar suas habilidades usando exames de anos anteriores. No entanto, um
bom desempenho em exames anteriores não é garantia que ele se sobressairá quando for impor-
tante. Por exemplo, o aluno pode tentar se preparar aprendendo de cor as respostas às questões
do exame. Isso requer que o aluno memorize muitas coisas. Ela pode até se lembrar das respostas
de exames anteriores perfeitamente. Outro aluno pode se preparar tentando entender as razões
para dar certas respostas. Na maioria dos casos, o último aluno se sairá muito melhor.
Da mesma forma, considere um modelo que simplesmente usa uma tabela de pesquisa para re-
sponder às perguntas. Se o conjunto de entradas permitidas for discreto e razoavelmente pe-
queno, talvez depois de ver muitos exemplos de treinamento, essa abordagem teria um bom de-
sempenho. Ainda assim, esse modelo não tem capacidade de fazer melhor do que adivinhação
aleatória quando confrontado com exemplos que nunca viu antes. Na realidade, os espaços de
entrada são muito grandes para memorizar as respostas correspondentes a cada entrada conce-
bível. Por exemplo, considere as imagens 28 × 28 em preto e branco. Se cada pixel pode ter um
entre 256 valores de tons de cinza, então há 256784 imagens possíveis. Isso significa que há muito
mais imagens em miniatura em escala de cinza de baixa resolução do que átomos no universo.
Mesmo se pudéssemos encontrar esses dados, nunca poderíamos nos dar ao luxo de armazenar a
tabela de pesquisa.

4.4. Seleção do Modelo, Underfitting, e Overfitting