Вы находитесь на странице: 1из 110

Página 1

Aprendizagem Profunda
com Python
Uma introdução prática
­
Nikhil Ketkar
Página 2

Aprendizado Profundo 
com
Python
Uma introdução prática
Nikhil Ketkar
Página 3
Aprendizado Profundo com Python: Uma Introdução Prática
Nikhil Ketkar
Bangalore, Karnataka, Índia
ISBN­13 (pbk): 978­1­4842­2765­7
ISBN­13 (eletrônico): 978­1­4842­2766­4
DOI 10.1007 / 978­1­4842­2766­4
Número de Controle da Biblioteca do Congresso: 2017939734
Copyright © 2017 por Nikhil Ketkar
Este trabalho está sujeito a direitos autorais. Todos os direitos são reservados pelo Editor, seja o todo ou parte do
material, especificamente os direitos de tradução, reimpressão, reutilização de ilustrações, recitação,
radiodifusão, reprodução em microfilmes ou de qualquer outra forma física, e transmissão ou informação
armazenamento e recuperação, adaptação eletrônica, software de computador ou por metodologia similar ou diferente
conhecido ou desenvolvido posteriormente.
Nomes, logotipos e imagens de marca registrada podem aparecer neste livro. Em vez de usar um símbolo de marca 
registrada com
Em todas as ocorrências de um nome, logotipo ou imagem de marca registrada, usamos os nomes, logotipos e imagens
editorial e em benefício do proprietário da marca, sem intenção de violação da marca.
O uso nesta publicação de nomes comerciais, marcas registradas, marcas de serviço e termos similares, mesmo que sejam
não identificado como tal, não deve ser tomado como uma expressão de opinião sobre se estão ou não sujeitos a
direitos do proprietário.
Embora se acredite que os conselhos e informações contidos neste livro sejam verdadeiros e precisos na data da publicação,
nem os autores nem os editores nem o editor podem aceitar qualquer responsabilidade legal por quaisquer erros ou
omissões que podem ser feitas. O editor não oferece garantia, expressa ou implícita, em relação ao
material contido aqui.
Diretor Gerente: Welmoed Spahr
Diretor Editorial: Todd Green
Editor de Aquisições: Celestin Suresh John
Editor de desenvolvimento: Matthew Moodie e Anila Vincent
Revisor Técnico: Jojo Moolayail
Editor de Coordenação: Prachi Mehta
Editor de cópias: Larissa Shmailo
Compositor: SPi Global
Indexador: SPi Global
Artista: SPi Global
Imagem da capa criada por Freepik
Distribuído para o comércio de livros em todo o mundo pela Springer Science + Business Media New York,
233 Spring Street, 6th Floor, Nova York, NY 10013. Telefone 1­800­SPRINGER, fax (201) 348­4505, e­mail
orders­ny@springer­sbm.com, ou visite www.springeronline.com. Apress Media, LLC é uma LLC da Califórnia
e o único membro (proprietário) é a Springer Science + Business Media Finance Inc. (SSBM Finance Inc).
A SSBM Finance Inc é uma corporação de Delaware .
Para informações sobre traduções, envie um e­mail rights@apress.comou visite http://www.apress.com/
 permissões de direitos  .
Os títulos da Apress podem ser comprados em grandes quantidades para uso acadêmico, corporativo ou 
promocional. Versões eBook e
licenças também estão disponíveis para a maioria dos títulos. Para mais informações, consulte nossas vendas em massa para 
impressão e e­books
página da web em http://www.apress.com/bulk­sales.
Qualquer código fonte ou outro material suplementar referenciado pelo autor neste livro está disponível para
leitores no GitHub através da página de produtos do livro, localizada em www.apress.com/9781484227657. Para mais
informações detalhadas, por favor visite http://www.apress.com/source­code.
Impresso em papel sem ácido

Página 4
Para Aditi.

Página 5
v

Conteúdos de Relance
Sobre o autor ............................................... .................................................. .... XI
Sobre o Avaliador Técnico .............................................. ................................. xiii
Agradecimentos ................................................. .................................................. xv
■ Capítulo 1: Introdução ao Aprendizado 
Profundo .......................................... ................... 1
■ Capítulo 2: Fundamentos de Aprendizado de 
Máquina ........................................... .............. 5
■ Capítulo 3: Redes Neurais de Feed Forward .......................................... ............... 15
■ Capítulo 4: Introdução ao Theano ........................................... ............................ 33
■ Capítulo 5: Redes Neurais de Convolutional ........................................... .............. 61
■ Capítulo 6: Redes Neurais Recorrentes ........................................... .................... 77
■ Capítulo 7: Introdução ao Keras ........................................... .............................. 95
■ Capítulo 8: Descendência do Gradiente 
Estocástico ........................................... ................. 111
■ Capítulo 9: Diferenciação automática ............................................ ..................... 131
■ Capítulo 10: Introdução às GPUs ........................................... ........................... 147
Índice ................................................. .................................................. .................. 157

Página 6
vii

Conteúdo
Sobre o autor ............................................... .................................................. .... XI
Sobre o Avaliador Técnico .............................................. ................................. xiii
Agradecimentos ................................................. .................................................. xv
■ Capítulo 1: Introdução ao Aprendizado 
Profundo .......................................... ................... 1
Contexto histórico ................................................ .................................................. ...........
1
Avanços em campos 
relacionados .............................................. ................................................ 3
Pré­requisitos ................................................. .................................................. ................ 
3
Visão geral dos capítulos 
subseqüentes .............................................. ..................................... 4
Instalando as Bibliotecas 
Necessárias .............................................. ....................................... 4
■ Capítulo 2: Fundamentos de Aprendizado de 
Máquina ........................................... .............. 5
Intuição ................................................. .................................................. ......................... 
5
Classificação 
Binária ................................................ .................................................. ....... 5
Regressão ................................................. .................................................. .................... 6
Generalização ................................................. .................................................. ............... 
7
Regularização ................................................. .................................................. ............. 
12
Resumo ................................................. .................................................. ..................... 14
■ Capítulo 3: Redes Neurais de Feed Forward .......................................... ............... 15
Unidade ................................................. .................................................. ..........................
.... 15
Estrutura Geral de uma Rede Neural ............................................ .................................................. .... 17
Expressando a Rede Neural em Forma Vetorial ........................................... ......................................... 18
Avaliando a saída da Rede Neural ........................................... ............................................ 19
Treinando a Rede Neural .............................................. .................................................. .................... 21

Página 7
■ CONTEÚDO
viii
Derivando Funções de Custo usando a Máxima 
Verossimilhança ............................................ .......... 22
Entropia Cruzada Binária ............................................... .................................................. ........................... 
23
Entropia Cruzada ................................................ .................................................. ................................... 23
Erro Quadrado ................................................ .................................................. ..................................... 24
Resumo das funções de perda .............................................. .................................................. ............... 25
Tipos de Unidades / Funções de Ativação / 
Camadas .......................................... .......................... 25
Unidade Linear ................................................ .................................................. .......................................... 
26
Unidade Sigmóide ................................................ .................................................. .......................................
26
Camada Softmax ................................................ .................................................. ..................................... 
27
Unidade Linear Retificada 
(ReLU) ............................................ .................................................. .................... 27
Tangente Hiperbólica ................................................ .................................................. ............................. 28
Rede Neural Hands­on com AutoGrad ........................................... ........................... 31
Resumo ................................................. .................................................. ..................... 31
■ Capítulo 4: Introdução ao Theano ........................................... ............................ 33
O que é o 
Theano ............................................... .................................................. .............. 33
Theano Hands­On .............................................. .................................................. ........... 
34
Resumo ................................................. .................................................. ..................... 59
■ Capítulo 5: Redes Neurais de Convolutional ........................................... .............. 61
Operação de 
convolução ................................................ .................................................. .. 61
Operação de 
Pooling ................................................ .................................................. ......... 68
Bloco de Construção de Convolução­Detecção­
Agrupamento ........................................... ...................... 70
Variantes de 
Convolução ................................................ .................................................. ..... 74
Intuição por trás das 
CNNs ............................................... .................................................. .... 75
Resumo ................................................. .................................................. ..................... 76
■ Capítulo 6: Redes Neurais Recorrentes ........................................... .................... 77
RNN Basics ................................................ .................................................. ................... 
77
Treinando 
RNNs ................................................ .................................................. ............... 82
RNNs bidirecionais ................................................ .................................................. ....... 
89

Página 8
■ CONTEÚDO
ix
Explosão e desaparecimento 
gradiente .............................................. .................................... 90
Recorte de 
Gradiente ................................................ .................................................. .......... 91
Memória a Curto Prazo .............................................. ................................................. 93
Resumo ................................................. .................................................. ..................... 94
■ Capítulo 7: Introdução ao Keras ........................................... .............................. 95
Resumo ................................................. .................................................. ................... 109
■ Capítulo 8: Descendência do Gradiente 
Estocástico ........................................... ................. 111
Problemas de Otimização ................................................ ................................................. 
111
Método de descida mais 
íngreme .............................................. .......................................... 112
Descida Estocástica (Simples e Mini­lote) ....................................... .............. 113
Lote ................................................. .................................................. ............................................... 114
Exemplo Único Estocástico ............................................... .................................................. ................ 114
Mini­lote estocástico .............................................. .................................................. ......................... 114
Lote vs. Estocástico .............................................. .................................................. ........................... 114
Desafios com o SGD ............................................... .................................................. ... 
114
Mínimo Local ................................................ .................................................. .................................... 114
Pontos de sela ................................................ .................................................. .................................... 115
Selecionando a Taxa de 
Aprendizagem .............................................. .................................................. ............... 116
Progresso lento em vales estreitos ............................................. .................................................. ......... 117
Variações Algoritmicas no SGD .............................................. ........................................ 
117
Momento ................................................. .................................................. ....................................... 118
Nesterov Accelerated Gradient (NAS) ............................................ .................................................. ... 119
Calendário de Taxa de Recozimento e 
Aprendizagem ............................................. ............................................... 119
Adagrad ................................................. .................................................. ........................................... 119
RMSProp ................................................. .................................................. ........................................... 120
Adadelta ................................................. .................................................. .......................................... 121
Adam ................................................. .................................................. ............................................... 121
Retropropagação Resiliente ................................................ .................................................. ................ 121
SGD Equilibrado ................................................ .................................................. ............................... 122

Página 9
■ CONTEÚDO
x
Dicas e truques para usar o SGD ............................................ ...........................................
122
Pré­processamento de dados de 
entrada ............................................... .................................................. .................. 122
Escolha da função de ativação .............................................. .................................................. ................ 
122
Valor alvo de pré­processamento ............................................... .................................................. ............... 
123
Inicializando Parâmetros ................................................ .................................................. ...................... 123
Shuffling Data ................................................ .................................................. ................................... 123
Normalização por lote ................................................ .................................................. ......................... 123
Parada Antecipada ................................................ .................................................. .................................. 
123
Ruído de gradiente ................................................ .................................................. .................................. 
123
SGD Paralelo e Distribuído .............................................. .......................................... 124
Hogwild ................................................. .................................................. ............................................ 124
Chuva torrencial ................................................. .................................................. ........................................ 
124
Hands­on SGD com Downhill ............................................ ........................................... 
125
Resumo ................................................. .................................................. ................... 130
■ Capítulo 9: Diferenciação automática ............................................ ..................... 131
Diferenciação Numérica ................................................ ............................................. 131
Diferenciação Simbólica ................................................ ............................................... 
132
Fundamentos da Diferenciação Automática ............................................... .......................
133
Modo Linear de Avanço / Tangente ............................................. .................................................. ............. 
134
Modo Linear Reverso / Cotangente / 
Adjunto ... ........................................... ................................................. 138
Implementação de Diferenciação Automática .............................................. ........................................ 141
Diferenciação automática prática com o Autograd ........................................... ........... 
143
Resumo ................................................. .................................................. ................... 146
■ Capítulo 10: Introdução às GPUs ........................................... ........................... 147
Resumo ................................................. .................................................. ................... 156
Índice ................................................. .................................................. .................. 157

Página 10
XI

Sobre o autor
Nikhil Ketkar atualmente lidera a equipe da Plataforma de Aprendizado de Máquina em
Flipkart, a maior empresa de comércio eletrônico da Índia. Ele recebeu seu PhD de
Universidade Estadual de Washington. Depois disso, ele conduziu pós­doutorado
pesquisa na Universidade da Carolina do Norte em Charotte, que foi seguida
por um breve período em negociação de alta frequência no TransMarket em Chicago. Mais
recentemente, ele liderou a equipe de mineração de dados em Guavus, uma startup que faz big data
analytics no domínio de telecomunicações e Indix, uma startup fazendo ciência de dados em
o domínio de comércio eletrônico. Seus interesses de pesquisa incluem aprendizado de máquina
e teoria dos grafos.

Página 11
xiii

Sobre o revisor técnico
Jojo Moolayil é cientista de dados e autor de Decisões Mais Inteligentes ­ A Interseção da Internet das Coisas e
Ciência de decisão . Com mais de quatro anos de experiência industrial em ciência de dados, ciência de decisão e IoT,
Ele trabalhou com líderes do setor em projetos críticos e de alto impacto em várias verticais. Ele é
atualmente associada à General Electric, pioneira e líder em ciência de dados para IoT industrial, e vive
em Bengaluru, o Vale do Silício da Índia.
Ele nasceu e cresceu em Pune, na Índia e se formou na Universidade de Pune com especialização em
engenharia de tecnologia da informação. Ele começou sua carreira com Mu Sigma, o maior jogo puro do mundo
analítico, e trabalhou com os líderes de muitos clientes da Fortune 50. Um dos primeiros entusiastas a
Se envolver na análise de IoT, ele agora se concentra na solução de problemas de ciência de decisão para casos de uso de 
IoT industriais.
Como parte de seu papel na GE, ele também desenvolve produtos e plataformas de ciência de dados e ciência de decisão 
para
industrial IoT.

Página 12
xv

Agradecimentos
Eu gostaria de agradecer aos meus colegas da Flipkart e Indix, e aos revisores técnicos pelo feedback e
comentários.

Página 13
1
© Nikhil Ketkar 2017
N. Ketkar, Aprendizado Profundo com Python , DOI 10.1007 / 978­1­4842­2766­4_1
CAPÍTULO 1

Introdução ao Aprendizado 
Profundo
Este capítulo oferece uma visão ampla e um contexto histórico em torno do tema da aprendizagem profunda. Também dá
o leitor um roteiro para navegar o livro, os pré­requisitos e leitura adicional para mergulhar mais fundo no
assunto.

Contexto histórico
O campo da Inteligência Artificial (AI), que definitivamente pode ser considerado o campo pai das profundezas
aprendendo, tem uma história rica que remonta a 1950. Enquanto nós não cobriremos esta história em muito detalhe, nós 
iremos
sobre alguns dos principais pontos de virada no campo, o que nos levará a uma aprendizagem profunda.
As tarefas que a IA focou em seus primeiros dias eram tarefas que poderiam ser facilmente descritas formalmente, como a
jogo de damas ou xadrez. Esta noção de ser capaz de descrever facilmente a tarefa formalmente está no centro do que
pode ou não pode ser feito facilmente por um programa de computador. Por exemplo, considere o jogo de xadrez. O formal
A descrição do jogo de xadrez seria a representação do tabuleiro, uma descrição de como cada um dos
peças se movem, a configuração inicial e uma descrição da configuração em que o jogo termina.
Com essas noções formalizadas, é relativamente fácil modelar um programa de IA de xadrez como uma pesquisa e,
dados recursos computacionais suficientes, é possível produzir uma IA relativamente boa para jogar xadrez.
A primeira era da IA focou em tais tarefas com uma quantidade razoável de sucesso. No coração da metodologia
era uma representação simbólica do domínio e da manipulação de símbolos com base em regras dadas (com
algoritmos cada vez mais sofisticados para procurar o espaço da solução para chegar a uma solução).
Deve­se notar que as definições formais de tais regras foram feitas manualmente. No entanto, tão cedo
Os sistemas de IA eram solucionadores de tarefas / problemas de uso geral, no sentido de que qualquer problema
descrito formalmente poderia ser resolvido com a abordagem genérica.
A principal limitação sobre tais sistemas é que o jogo de xadrez é um problema relativamente fácil para a IA simplesmente
porque a configuração do problema é relativamente simples e pode ser facilmente formalizada. Este não é o caso com 
muitos dos
os problemas que os seres humanos resolvem no dia­a­dia (inteligência natural). Por exemplo, considere diagnosticar
uma doença (como um médico faz) ou transcrever a fala humana para o texto. Essas tarefas, como a maioria das outras 
tarefas humanas
seres mestre facilmente, são difíceis de descrever formalmente e apresentaram um desafio nos primeiros dias da IA.
Os seres humanos lidam com essas tarefas alavancando uma grande quantidade de conhecimento sobre a tarefa / problema
domínio. Dada esta observação, os sistemas subseqüentes de IA dependiam de uma grande base de conhecimento que
conhecimento sobre o problema / domínio da tarefa. Um ponto a ser observado é que o termo usado aqui é conhecimento, 
não
informações ou dados. Por conhecimento nós simplesmente queremos dizer dados / informações que um programa / 
algoritmo pode raciocinar
sobre. Um exemplo disso poderia ser uma representação gráfica de um mapa com bordas marcadas com distâncias e
sobre o tráfego (que está sendo constantemente atualizado), que permite que um programa raciocine sobre o caminho mais 
curto
entre pontos.

Página 14
CAPÍTULO 1 ■ INTRODUÇÃO À APRENDIZAGEM PROFUNDA
2
Tais sistemas baseados no conhecimento, em que o conhecimento foi compilado por especialistas e representados
de uma maneira que permitisse que algoritmos / programas raciocinassem sobre ele representam a segunda geração de 
IA. No
o coração de tais abordagens eram abordagens cada vez mais sofisticadas para representar e raciocinar
sobre o conhecimento para resolver tarefas / problemas que exigiam tal conhecimento. Exemplos de tal sofisticação
incluem o uso de lógica de primeira ordem para codificar o conhecimento e representações probabilísticas para capturar e
razão em que a incerteza é inerente ao domínio.
Um dos principais desafios que tais sistemas enfrentaram e abordaram, em certa medida, foi a incerteza
inerente em muitos domínios. Os seres humanos são relativamente bons em raciocinar em ambientes com incógnitas
e incerteza. Uma observação importante aqui é que mesmo o conhecimento que temos sobre um domínio não é preto
ou branco mas cinza. Muito progresso foi feito nesta era em representar e raciocinar sobre incógnitas e
incerteza. Houve alguns sucessos limitados em tarefas como o diagnóstico de uma doença, que contou com alavancagem
e raciocínio usando uma base de conhecimento na presença de incertezas e incertezas.
A principal limitação de tais sistemas era a necessidade de compilar o conhecimento sobre o domínio de
especialistas. Coletar, compilar e manter tais bases de conhecimento tornaram tais sistemas impraticáveis.
Em certos domínios, era extremamente difícil coletar e compilar esse conhecimento (por exemplo,
transcrever discurso para texto ou traduzir documentos de um idioma para outro). Enquanto seres humanos
pode facilmente aprender a fazer essas tarefas, é extremamente desafiador entregar compilar e codificar o conhecimento
relacionadas com as tarefas (por exemplo, o conhecimento da língua inglesa e gramática, acentos e assunto
importam).
Os seres humanos lidam com essas tarefas adquirindo conhecimento sobre um domínio de tarefa / problema, um processo
que é referido como aprendizagem. Dada esta observação, o foco do trabalho subseqüente em IA mudou
uma década ou duas para algoritmos que melhoraram seu desempenho com base nos dados fornecidos a eles. O foco
deste subcampo foi desenvolver algoritmos que adquiriram conhecimento relevante para um domínio de tarefa / problema
dados fornecidos. É importante notar que essa aquisição de conhecimento baseou­se em dados rotulados e um
representação de dados rotulados conforme definido por um ser humano.
Por exemplo, considere o problema de diagnosticar uma doença. Para tal tarefa, um especialista humano
coletar muitos casos em que um paciente teve e não teve a doença em questão. Então, o especialista humano
identificaria uma série de características que ajudariam a fazer a previsão como, digamos, a idade do paciente,
o gênero, e resulta de uma série de testes diagnósticos, como pressão arterial, açúcar no sangue, etc.
O especialista compilaria todos esses dados e os representaria de maneira adequada, como dimensionar / normalizar os 
dados, etc.
Uma vez que esses dados foram preparados, um algoritmo de aprendizado de máquina pode aprender a inferir se o paciente
a doença ou não, generalizando a partir dos dados rotulados. Note que os dados rotulados consistiam de pacientes que
ambos têm e não têm a doença. Então, em essência, o algoritmo ML subjacente é essencialmente fazer o
trabalho de encontrar uma função matemática que pode produzir o resultado certo (doença ou nenhuma doença) dado
as entradas (características como idade, sexo, dados de testes de diagnóstico, etc.). Encontrando o mais simples matemático
função que prediz as saídas com o nível de precisão exigido está no centro do campo de ML. Específico
perguntas como quantos exemplos são necessários para aprender uma tarefa ou a complexidade temporal do algoritmo, etc.,
são questões específicas sobre as quais o campo do ML forneceu respostas com justificativa teórica. O campo
amadureceu a um ponto em que, dados suficientes, recursos de computação e recursos humanos para
características, uma grande classe de problemas são solucionáveis.
A principal limitação dos algoritmos de ML principais é que aplicá­los a um novo domínio de problema
requer uma enorme quantidade de engenharia de recursos. Por exemplo, considere o problema de reconhecer objetos
em imagens. Usando técnicas tradicionais de ML, tal problema exigirá uma engenharia massiva de recursos
esforço em que especialistas identificariam e gerariam recursos que seriam usados pelo algoritmo ML. Em um
sentido, a verdadeira inteligência está na identificação de características e o que o algoritmo ML está fazendo é 
simplesmente
aprender a combinar esses recursos para chegar à resposta correta. Esta identificação de características ou
representação de dados que os especialistas de domínio fazem antes de os algoritmos ML serem aplicados é
gargalo prático em AI.
É um gargalo conceitual porque se os recursos estão sendo identificados por especialistas de domínio, e o ML
algoritmo é simplesmente aprender a combinar e tirar conclusões a partir disso, isso é realmente AI? É uma prática
gargalo porque o processo de construção de modelos via ML tradicional é limitado pela quantidade de
engenharia de recursos necessária; há limites para quanto esforço humano pode ser jogado no problema.

Página 15
CAPÍTULO 1 ■ INTRODUÇÃO À APRENDIZAGEM PROFUNDA
3
Os seres humanos aprendem conceitos a partir de dados brutos. Por exemplo, uma criança mostrou alguns exemplos /
exemplos de um animal em particular (como, digamos, gatos) logo aprenderão a identificar gatos. O processo de 
aprendizagem não
não envolve um pai identificando características como tem bigodes ou tem pêlo ou tem uma cauda.
A aprendizagem humana vai dos dados brutos até uma conclusão sem a etapa explícita em que os recursos são identificados
e fornecido ao aluno. Em certo sentido, os seres humanos aprendem a representação apropriada dos dados do
dados em si. Além disso, eles organizam conceitos como uma hierarquia onde conceitos complicados são expressos
usando conceitos primitivos.
O campo da aprendizagem profunda tem seu foco principal em aprender representações apropriadas de dados tais
que estes poderiam ser usados para tirar conclusões. A palavra profunda na aprendizagem profunda refere­se à ideia de 
aprender
a hierarquia de conceitos diretamente a partir de dados brutos. Um termo tecnicamente mais apropriado para o aprendizado 
profundo
seria representação aprendizagem, e um termo mais prático para o mesmo seria recurso automatizado
Engenharia.

Avanços em campos relacionados
É importante notar os avanços em outros campos que desempenharam um papel­chave no recente interesse e
sucesso da aprendizagem profunda. Os seguintes pontos devem ser anotados.
1. A capacidade de coletar, armazenar e operar em grandes quantidades de dados tem
avançado na última década (por exemplo, o Ecossistema Apache Hadoop).
2. A capacidade de gerar dados de treinamento supervisionados (que são basicamente dados com
rótulos ­ um exemplo disso seria fotos anotadas com os objetos no
imagem) melhorou muito com a disponibilidade de serviços de crowdsourcing
(como o Amazon Mechanical Turk).
3. As melhorias maciças na potência computacional provocadas por
Unidades gráficas de processador.
4. Os avanços na teoria e implementação de software de automação
diferenciação (como Theano).
Embora esses avanços sejam periféricos à aprendizagem profunda, eles desempenharam um grande papel na capacitação
avanços na aprendizagem profunda.

Pré­requisitos
Os principais pré­requisitos para a leitura deste livro são um conhecimento prático de Python e algum trabalho de curso 
sobre
álgebra linear, cálculo e probabilidade. Recomenda­se que os leitores se refiram ao seguinte, caso
precisa cobrir esses pré­requisitos.
1. Mergulhe em Python por Mark Pilgrim para Python.
2. Álgebra Linear de Gilbert Strang para álgebra linear.
3. Cálculo de Gilbert Strang para cálculo.
4. Todas as Estatísticas de Larry Wasserman para probabilidade (Seção 1, Capítulos 1­ 5 ).

Página 16
CAPÍTULO 1 ■ INTRODUÇÃO À APRENDIZAGEM PROFUNDA
4

Visão Geral dos Capítulos Subsequentes
Nós agora fornecemos um resumo geral dos capítulos subseqüentes para o leitor. É importante notar que
cada um dos capítulos aborda os conceitos ou as habilidades (ou, em certos casos, ambos) em relação às profundezas
Aprendendo. Destacamos abaixo para que os leitores possam garantir que internalizaram esses conceitos
e habilidades. É altamente recomendado que os leitores não apenas leiam os capítulos, mas também trabalhem
detalhes matemáticos (usando caneta e papel) e jogar com o código fonte fornecido em cada um dos capítulos.
1. O Capítulo 2 aborda os fundamentos do Aprendizado de Máquina. A chave leva para casa
este capítulo é o conceito de generalizar sobre exemplos invisíveis, as idéias de
ajuste e subajuste dos dados de treinamento, a capacidade do modelo ea
noção de regularização.
2. O Capítulo 3 aborda as Redes Neurais de Feed Forward e serve como
fundação para o livro inteiro. Conceitos como a estrutura geral do neural
rede, as camadas de entrada, oculta e de saída, funções de custo e sua base
o princípio da Máxima Verossimilhança são os conceitos importantes neste capítulo.
3. O Capítulo 4 fornece uma introdução prática à biblioteca de Theano. Abrange como
para definir redes como gráficos computacionais, deriva automaticamente gradientes para
redes complicadas e treinar redes neurais.
4. O Capítulo 5 abrange as Redes Neurais Convolucionais, que são talvez as mais
aplicação bem sucedida da aprendizagem profunda.
5. O Capítulo 6 cobre Redes Neurais Recorrentes e Memória de Longo Prazo
(LSTM), que são outra aplicação bem sucedida de aprendizagem profunda.
6. O Capítulo 7 fornece uma introdução prática à biblioteca Keras. O Keras
biblioteca fornece um número de abstrações de alto nível sobre a biblioteca de Theano
e é provavelmente a ferramenta ideal quando se trata de construir uma aprendizagem profunda
aplicações.
7. O Capítulo 8 apresenta ao leitor a Descida Estocástica de Gradiente (SGD), que é
o procedimento mais comum usado para treinar redes neurais. Este capítulo também
cobre as deficiências do SGD e uma série de variações para o SGD que abordam
essas deficiências.
8. O Capítulo 9 introduz o leitor à Diferenciação Automática (comumente
referido como backpropagation), que é uma técnica padrão usada para derivar
gradientes (necessários para SGD) para redes arbitrariamente complicadas.
9. O Capítulo 10 introduz o leitor em Unidades de Processamento Gráfico (GPUs) e
Computação baseada em GPU, que tem atuado como uma tecnologia fundamental para
Aprendendo.

Instalando as Bibliotecas Necessárias
Há um número de bibliotecas que o leitor precisará instalar para executar o código­fonte para
os exemplos nos capítulos. Recomendamos que o leitor instale o Anaconda Python Distribution
( https://www.continuum.io/downloads ), o que tornaria o processo de instalação dos pacotes requeridos
significativamente fácil (usando conda ou pip). A lista de pacotes que o leitor precisaria inclui o Scikit­learn,
Theano, Autograd, Keras e PyOpenCL.

Página 17
5
© Nikhil Ketkar 2017
N. Ketkar, Aprendizado Profundo com Python , DOI 10.1007 / 978­1­4842­2766­4_2

CAPÍTULO 2

Fundamentos de aprendizado 
de máquina
A Aprendizagem Profunda é um ramo da Aprendizagem de Máquina e, neste capítulo, abordaremos os fundamentos
Aprendizado de Máquina. Enquanto o aprendizado de máquina como um assunto é inerentemente matemático por natureza, 
nós manteremos
matemática ao mínimo básico necessário para desenvolver a intuição sobre o assunto. Pré­requisitos para o
As matérias abordadas neste capítulo seriam álgebra linear, cálculo multivariado e probabilidade básica
teoria.

Intuição
Como seres humanos, estamos intuitivamente conscientes do conceito de aprendizagem: significa simplesmente melhorar 
em uma tarefa.
durante um período de tempo. A tarefa pode ser física (como aprender a dirigir um carro) ou intelectual (como aprender
uma nova linguagem). O tema do aprendizado de máquina foca no desenvolvimento de algoritmos que podem aprender 
como
os humanos fazem; isto é, eles ficam melhores em uma tarefa ao longo do tempo, com experiência.
A primeira pergunta a fazer é por que estaríamos interessados no desenvolvimento de algoritmos que melhorassem
seu desempenho ao longo do tempo, com experiência. Afinal, existem muitos algoritmos desenvolvidos e
implementadas para resolver problemas do mundo real que não melhoram com o tempo, eles simplesmente são
humanos e implementados em software e eles fazem o trabalho. Da banca ao comércio eletrônico e de
sistemas de navegação em nossos carros para o desembarque de uma nave espacial na lua, os algoritmos estão em toda parte,
e, um
a maioria deles não melhora com o tempo. Esses algoritmos simplesmente executam a tarefa a que se destinam
executar, com alguma manutenção necessária de tempos em tempos. Por que precisamos de aprendizado de máquina?
A resposta a esta pergunta é que, para certas tarefas, é mais fácil desenvolver um algoritmo que aprenda
melhora seu desempenho com experiência do que desenvolver um algoritmo manualmente. Enquanto isso pode parecer
Não intencional para o leitor neste momento, vamos construir intuição para isso durante o curso deste capítulo.

Classificação Binária
A fim de discutir mais sobre o assunto em questão, precisamos ser precisos sobre alguns dos termos que temos
usar intuitivamente, como tarefa, aprendizado, experiência e aprimoramento. Vamos começar com a tarefa do binário
classificação.
Considere um domínio de problema abstrato onde temos dados do formulário
D = {( x 1 , y 1 ), ( x 2 , y 2 ),… ( x n , y n )}
onde x
n

А e y = ± 1. Nós não temos acesso a todos esses dados, mas apenas a um subconjunto SD
EU . Usando S , nossa tarefa
é gerar um procedimento computacional que implemente a função fx
y
: ® de tal forma que podemos usar f para
fazer previsões sobre dados invisíveis xy
S
Eu
Eu

,
(
) Ï que estão corretos, fx
y
Eu
Eu

() =. Vamos denotar UD
Πcomo o conjunto de

Página 18
CAPÍTULO 2 ■ FUNDAMENTOS DA APRENDIZAGEM DE MÁQUINAS
6
dados invisíveis, isto é, xy
S
Eu
Eu

,
(
) Ï e xy
você
Eu
Eu

,
(
) Î. Nós medimos o desempenho durante essa tarefa como o erro
dados invisíveis,
E f DU
fx
y
você
xy
você
Eu
Eu
Eu
Eu

,
(
) =
() ¹
éë
ùû
(
) a­

uma
,

.
Agora temos uma definição precisa da tarefa, que é categorizar os dados em uma das duas categorias
( y = ± 1) com base em alguns dados vistos S , gerando f . Nós medimos o desempenho (e melhora
desempenho) utilizando o erro E ( F ,  D ,  L ) ao longo de dados invisível L . O tamanho dos dados vistos | S | é o conceitual
equivalente de experiência. Neste contexto, queremos desenvolver algoritmos que gerem tais funções
f (que são comumente referidos como um modelo). Em geral, o campo de aprendizado de máquina estuda
desenvolvimento de tais algoritmos que produzem modelos que fazem previsões sobre dados não vistos para tais
algoritmos e outras tarefas formais (estaremos introduzindo várias dessas tarefas posteriormente no capítulo). Observe que
o x é comumente referido como a variável de entrada / entrada e y é referido como a variável de saída / saída.
Como acontece com qualquer outra disciplina em ciência da computação, as características computacionais de tais 
algoritmos
é uma faceta importante, mas além disso também gostaríamos de ter um modelo f que alcançasse um erro menor
E ( f , D , U ) com um pequeno | S | que possível.
Vamos agora relacionar essa definição abstrata, mas precisa, com um problema do mundo real, para que nossas abstrações
estão aterrados. Digamos que um site de comércio eletrônico deseje personalizar a página de destino dos usuários 
registrados
para mostrar a eles os produtos que os usuários podem estar interessados em comprar. O site possui dados históricos sobre 
usuários
e gostaria de implementar isso como um recurso para aumentar as vendas. Vamos agora ver como esse mundo real
problema mapeia para o problema abstrato da classificação binária que descrevemos anteriormente.
A primeira coisa que se pode notar é que, dado um determinado usuário e um determinado produto,
para prever se o usuário comprará o produto. Como esse é o valor a ser previsto, ele é mapeado em y = ± 1,
onde vamos deixar o valor de y = +1 denotar a previsão de que o usuário vai comprar o produto e nós vamos
denote y = –1 como a previsão de que o usuário não compra o produto. Note­se que não há particular
razão para escolher esses valores; poderíamos ter trocado isso (let y = 1 denotar o caso não compra e
y = –1 denota o caso de compra) e não haveria diferença. Nós apenas usamos y = ± 1 para denotar as duas classes de
interesse em categorizar os dados. Em seguida, vamos supor que podemos de alguma forma representar os atributos do 
produto
e o histórico de compras e navegação do usuário como x
n

ÎR. Essa etapa é chamada de engenharia de recursos em
aprendizado de máquina e vamos abordá­lo mais adiante no capítulo. Por enquanto, basta dizer que somos capazes de
gerar tal mapeamento. Assim, temos dados históricos do que os usuários navegaram e compraram, atributos de
um produto e se o usuário comprou o produto ou não mapeado em {( x 1 ,  y 1 ), ( x 2 , y 2 ),… ( x n , y n )}. Agora,
com base nesses dados, gostaríamos de gerar uma função ou um modelo fx
y
: ® que podemos usar para determinar
quais produtos um usuário específico comprará e usará para preencher a página de destino dos usuários. Podemos
medir o desempenho do modelo em dados não vistos ao preencher a página de destino dos usuários e ver
se eles compram ou não os produtos e avaliam o erro E ( f ,  D ,  U ).

Regressão
Vamos introduzir outra tarefa, a saber, a regressão. Aqui, temos dados do formulário D
xy
xy
xy
n
n

= (
) (
) ¼ (
)
{
}
1
1
2
2

,
,,
,
onde x
n

ÎR e y ÑR e nossa tarefa é gerar um procedimento computacional que implemente a função
fx
y
: Note que ao invés da predição ser um rótulo de classe binária y = ± 1 como na classificação binária, nós temos
previsão real valorizada. Medimos o desempenho em relação a essa tarefa como o erro quadrático médio da raiz (RMSE)
dados invisíveis,

Página 19
Capítulo 2 ■ FundaMs de aprendizado do MaChine
7
E f DU
yfx
você
xy
você
Eu
Eu
Eu
Eu

,
(
) =
­ ()

(
)
æ
è
ç
ç
ç
ç
ö
ø
÷
÷
÷
÷
(
) a­

uma
,
2
1
2

.
■ Observe que o rMse está simplesmente tomando a diferença entre o valor previsto e real,
como para as diferenças positivas e negativas, tomando a média de modo a agregar ao longo de todo o 
invisível
dados e, finalmente, tomando a raiz quadrada de modo a contrabalançar a operação quadrada.
Um problema do mundo real que corresponde à tarefa abstrata de regressão é prever a pontuação de crédito para
um indivíduo com base em seu histórico financeiro, que pode ser usado por uma empresa de cartão de crédito para estender 
a linha
de crédito.

Generalização
Vamos agora cobrir qual é a intuição mais importante em inclinações de máquina, que é que nós queremos
desenvolver / gerar modelos que tenham bom desempenho em relação a dados não vistos. Para fazer isso, vamos apresentar
um conjunto de dados de brinquedo para uma tarefa de regressão primeiro.
Geramos o conjunto de dados de brinquedo gerando 100 valores equidistantes entre ­1 e 1 como entrada
variável ( x ). Nós geramos a variável de saída ( y ) com base em y
x
x
= + +
+
2
2 2
 onde ε ~
.
N 0 01
(
) é ruído
(variação aleatória) de uma distribuição normal com 0 média e 0,1 sendo o desvio padrão. Código para
isso é apresentado na Listagem 2­1 e os dados são plotados na Figura  2­1 .
Listagem 2­1. Aprendizagem de Generalização vs. Rote
#Generate Toy Dataset
import pylab
import numpy
x = numpy.linspace (­1,1,100)
sinal = 2 + x + 2 * x * x
ruído = numpy.random.normal (0, 0.1, 100)
y = sinal + ruído
pylab.plot (sinal, 'b');
pylab.plot (y, 'g')
pylab.plot (ruído, 'r')
pylab.xlabel ("x")
pylab.ylabel ("y")
pylab.legend (["Sem Ruído", "Com Ruído", "Ruído"], loc = 2)
x_train = x [0:80]
y_train = y [0:80]
# Modelo com grau 1
pylab.figure ()
grau = 2
X_train = numpy.column_stack ([numpy.power (x_train, i) para i em xrange (0, degree)])

Página 20
Capítulo 2 ■ FundaMs de aprendizado do MaChine
8
modelo = numpy.dot (numpy.dot (numpy.linalg.inv (numpy.dot (X_train.transpose (), X_train)), X_
train.transpose ()), y_train)
pylab.plot (x, y, 'g')
pylab.xlabel ("x")
pylab.ylabel ("y")
previsto = numpy.dot (model, [numpy.power (x, i) para i em xrange (0, degree)])
pylab.plot (x, previsto, 'r')
pylab.legend (["Actual", "Predicted"], loc = 2)
train_rmse1 = numpy.sqrt (numpy.sum (numpy.dot) [y [0:80] ­ previsto [0:80], y_train ­
previsto [0:80])))
test_rmse1 = numpy.sqrt (numpy.sum (numpy.dot (y [80:] ­ previsto [80:], y [80:] ­
previsto [80:])))
print ("Treinar RMSE (Grau = 1)", train_rmse1)
print ("Teste RMSE (Grau = 1)", test_rmse1)
# Modelo com grau 2
pylab.figure ()
grau = 3
X_train = numpy.column_stack ([numpy.power (x_train, i) para i em xrange (0, degree)])
modelo = numpy.dot (numpy.dot (numpy.linalg.inv (numpy.dot (X_train.transpose (), X_train)),
X_train.transpose ()), y_train)
pylab.plot (x, y, 'g')
pylab.xlabel ("x")
pylab.ylabel ("y")
previsto = numpy.dot (model, [numpy.power (x, i) para i em xrange (0, degree)])
pylab.plot (x, previsto, 'r')
pylab.legend (["Actual", "Predicted"], loc = 2)
train_rmse1 = numpy.sqrt (numpy.sum (numpy.dot (y [0:80] ­ previsto [0:80],
y_train ­ previsto [0:80])))
test_rmse1 = numpy.sqrt (numpy.sum (numpy.dot (y [80:] ­ previsto [80:],
y [80:] ­ previsto [80:])))
print ("Treinar RMSE (Grau = 2)", train_rmse1)
print ("Teste RMSE (Grau = 2)", test_rmse1)
# Modelo com grau 8
pylab.figure ()
grau = 9
X_train = numpy.column_stack ([numpy.power (x_train, i) para i em xrange (0, degree)])
modelo = numpy.dot (numpy.dot (numpy.linalg.inv (numpy.dot (X_train.transpose (), X_train)),
X_train.transpose ()), y_train)
pylab.plot (x, y, 'g')
pylab.xlabel ("x")
pylab.ylabel ("y")
previsto = numpy.dot (model, [numpy.power (x, i) para i em xrange (0, degree)])
pylab.plot (x, previsto, 'r')
pylab.legend (["Actual", "Predicted"], loc = 3)
train_rmse2 = numpy.sqrt (numpy.sum (numpy.dot (y [0:80] ­ previsto [0:80],
y_train ­ previsto [0:80])))
test_rmse2 = numpy.sqrt (numpy.sum (numpy.dot (y [80:] ­ previsto [80:],
y [80:] ­ previsto [80:])))
print ("Treinar RMSE (Grau = 8)", train_rmse2)
print ("Teste RMSE (Grau = 8)", test_rmse2)

Página 21
Capítulo 2 ■ FundaMs de aprendizado do MaChine
9
# Saída
Trem RMSE (Grau = 1) 3,50756834691
Teste RMSE (Grau = 1) 7,69514326946
Trem RMSE (Grau = 2) 0.91896252959
Teste RMSE (Grau = 2) 0,446173435392
Trem RMSE (Grau = 8) 0.897346255079
Teste RMSE (Grau = 8) 14.1908525449
Figura 2­1. Gerar um conjunto de dados com problema de brinquedo para regressão
Para simular dados vistos e não vistos, usamos os primeiros 80 pontos de dados como dados vistos e o resto
nós tratamos como dados não vistos. Ou seja, nós construímos o modelo usando apenas os primeiros 80 pontos de dados e 
usamos o resto para
avaliar o modelo.
Em seguida, usamos um algoritmo muito simples para gerar um modelo, comumente referido como Mínimos Quadrados.
Dado um conjunto de dados do formulário D
xy
xy
xy
n
n

= (
) (
) ¼ (
)
{
}
1
1
2
2

,
,,
,
onde x
n

ÎR e y ÎR, o modelo dos mínimos quadrados
toma a forma y = b x onde b é um vetor tal que X
y
b ­ 2
2 é minimizado. Aqui X é uma matriz onde cada linha

é um x , portanto X
mn

EU
´

R
sendo m o número de exemplos (no nosso caso 80). O valor de b pode ser derivado

usando o formulário fechado b =  ()  ­

XX
X y
T
T
1

. Estamos encobrindo muitos detalhes importantes dos mínimos quadrados
método, mas esses são secundários à discussão atual. O detalhe mais pertinente é como nós transformamos
a variável de entrada para um formulário adequado. Em nosso primeiro modelo, transformaremos x em vetor de valores 
[ x 0 , x 1 ,  x 2 ].
Isto é, se x = 2, será transformado em [1, 2, 4]. Poste esta transformação, podemos gerar pelo menos quadrados
modelo b usando a fórmula descrita acima. O que está acontecendo sob o capô é que estamos nos aproximando
os dados fornecidos com uma equação polinomial de segunda ordem (grau = 2), e o algoritmo de mínimos quadrados é
simplesmente ajuste de curva ou gerando os coeficientes para cada um dos [ x 0 , x 1 ,  x 2  ].

Página 22
Capítulo 2 ■ FundaMs de aprendizado do MaChine
10
Podemos avaliar o modelo nos dados não vistos usando a métrica do RMSE. Podemos também calcular o RMSE
métrica nos dados de treinamento. Os valores reais e previstos são plotados na Figura 2­2 e listando  2­1 mostra
o código­fonte para gerar o modelo.
Figura 2­2. Valores reais e previstos para o modelo com grau = 2
Em seguida, geramos outro modelo com o algoritmo de mínimos quadrados, mas vamos transformar x em
[ x 0 , x 1 ,  x 2  , x 3 , x 4 , x 5 , x 6 , x 7 , x 8 ]. Ou seja, estamos aproximando os dados fornecidos com um polinômio com
grau = 8. Os valores reais e previstos são plotados na Figura  2­3 e listando2­1 mostra a fonte
código para gerar o modelo. Como último passo, geramos um modelo com grau = 1.

Página 23
Capítulo 2 ■ FundaMs de aprendizado do MaChine
11
Figura 2­3 Valores reais e previstos para o modelo com grau = 8
Os valores reais e previstos são plotados na Figura 2­4 e listando2­1 mostra o código­fonte para
gerando o modelo.
Figura 2­4. Valores reais e previstos para modelo com grau = 1

Página 24
Capítulo 2 ■ FundaMs de aprendizado do MaChine
12
Agora temos todos os detalhes para discutir o conceito central de generalização. A questão chave para perguntar
Qual é o melhor modelo? Aquele com grau = 2 ou aquele com grau = 8 ou aquele com grau = 1?
Vamos começar fazendo algumas observações sobre os três modelos. O modelo com grau = 1 executa
pobremente em ambos os dados vistos e não vistos em comparação com os outros dois modelos. O modelo com
O grau = 8 tem um desempenho melhor nos dados vistos em comparação com o modelo com grau = 2. O modelo com
degree = 2 tem desempenho melhor que o modelo com grau = 8 em dados não vistos. Tabela  2­1 visualiza isso na tabela
formulário para fácil interpretação.
Tabela 2­1. Comparando o desempenho dos 3 modelos diferentes
Grau
1
2
8
Dados vistos
Pior
Pior
Melhor
Dados não vistos
Pior
Melhor
Pior
Vamos agora entender o importante conceito de capacidade do modelo, que corresponde ao grau de
polinomial neste exemplo. Os dados que geramos estavam usando um polinômio de segunda ordem (grau = 2) com
algum barulho. Em seguida, tentamos aproximar os dados usando três modelos de grau: 1, 2 e 8, respectivamente.
Quanto maior o grau, mais expressivo é o modelo. Isto é, pode acomodar mais variações. este
A capacidade de acomodar a variação corresponde à noção de capacidade. Ou seja, dizemos que o modelo com
grau = 8 tem uma capacidade maior que o modelo com grau = 2, que por sua vez tem uma capacidade maior do que
o modelo com grau = 1. Não é ter maior capacidade sempre uma coisa boa? Acontece que não é, quando nós
considere que todos os conjuntos de dados do mundo real contêm algum ruído e um modelo de maior capacidade acabará se 
adequando
o ruído, além do sinal nos dados. É por isso que observamos que o modelo com grau = 2 faz
melhor nos dados não vistos em comparação com o modelo com grau = 8. Neste exemplo, nós sabíamos como os dados
foi gerado (com um polinômio de segunda ordem (grau = 2) com algum ruído); Portanto, esta observação é bastante
trivial. No entanto, no mundo real, não sabemos o mecanismo subjacente pelo qual os dados são gerados.
Isso nos leva ao desafio fundamental da aprendizagem de máquina, que é o modelo realmente generalizado?
E o único teste verdadeiro para isso é o desempenho em relação a dados não vistos.
Em certo sentido, o conceito de capacidade corresponde à simplicidade ou parcimônia do modelo. Uma modelo
com alta capacidade pode aproximar dados mais complexos. Isto é quantas variáveis livres / coeficientes
modelo tem. Em nosso exemplo, o modelo com grau = 1 não tem capacidade suficiente para aproximar o
dados e isso é comumente referido como sob ajuste. Correspondentemente, o modelo com grau = 8 tem
capacidade e mais ajusta os dados.
Como um experimento mental, considere o que aconteceria se tivéssemos um modelo com grau igual a 80. Dada
que tínhamos 80 pontos de dados como dados de treinamento, teríamos um polinômio de 80 graus que seria perfeitamente
aproximar os dados. Este é o último caso patológico em que não há aprendizado algum. O modelo
tem 80 coeficientes e pode simplesmente memorizar os dados. Isso é chamado de aprendizagem mecânica, o extremo lógico
de overfitting. É por isso que a capacidade do modelo precisa ser ajustada com relação à quantidade de treinamento
dados que temos. Se o conjunto de dados for pequeno, é melhor treinar modelos com menor capacidade.

Regularização
Com base na ideia de capacidade do modelo, generalização, montagem e ajuste, vamos agora cobrir o
ideia de regularização. A ideia chave aqui é penalizar a complexidade do modelo. Uma versão regularizada de pelo menos
quadrados toma a forma y = b x , onde b é um vetor tal que X
y
b
Libra
­
+
2
2
2

2 é minimizado e λ é um
parâmetro definido pelo usuário que controla a complexidade. Aqui, introduzindo o termo lb 2
2 , estamos penalizando

modelos complexos. Para ver por que esse é o caso, considere ajustar um modelo de mínimos quadrados usando um 
polinômio de
grau 10, mas os valores no vetor b tem 8 zeros; 2 são não zeros. Contra isso, considere o caso onde

Página 25
Capítulo 2 ■ FundaMs de aprendizado do MaChine
13
todos os valores no vetor b são não zeros. Para todos os efeitos práticos, o modelo anterior é um modelo com
grau = 2 e tem um valor menor de lb 2
2 . O termo λ nos permite equilibrar a precisão sobre os dados de treinamento

com a complexidade do modelo. Valores menores de λ implicam em um modelo mais simples.
Podemos calcular o valor de b usando o formulário fechado
eu
=
­

(
)  ­

XX
IX y
T
T
1

. Nós ilustramos manter o
grau fixado em um valor de 80 e variando o valor de λ na listagem 2­2 .
Listagem 2­2. Regularização
import pylab
import numpy
x = numpy.linspace (­1,1,100)
sinal = 2 + x + 2 * x * x
ruído = numpy.random.normal (0, 0.1, 100)
y = sinal + ruído
x_train = x [0:80]
y_train = y [0:80]
train_rmse = []
test_rmse = []
grau = 80
lambda_reg_values = numpy.linspace (0.01.0.99.100)
para lambda_reg em lambda_reg_values:
X_train = numpy.column_stack ([numpy.power (x_train, i) para i em xrange (0, degree)])
model = numpy.dot (numpy.dot (numpy.linalg.inv) (numpy.dot (X_train.transpose (), X_train) +
lambda_reg * numpy.identity (degree)), X_train.transpose ()), y_train)
previsto = numpy.dot (model, [numpy.power (x, i) para i em xrange (0, degree)])
train_rmse.append (numpy.sqrt (numpy.sum (numpy.dot) [y [0:80] ­ previsto [0:80],
y_train ­ previsto [0:80]))))
test_rmse.append (numpy.sqrt (numpy.sum (numpy.dot (y [80:] ­ previsto [80:],
y [80:] ­ previsto [80:]))))
pylab.plot (lambda_reg_values, train_rmse)
pylab.plot (lambda_reg_values, test_rmse)
pylab.xlabel (r "$ \ lambda $")
pylab.ylabel ("RMSE")
pylab.legend (["Train", "Test"], loc = 2)
O treinamento RMSE (dados observados) e o teste RMSE (dados invisíveis) são plotados na Figura  2­5 .

Página 26
Capítulo 2 ■ FundaMs de aprendizado do MaChine
14

Resumo
Neste capítulo, cobrimos os conceitos básicos do Aprendizado de Máquina. Os principais pontos para levar para casa para 
este capítulo são os
conceitos de generalização sobre exemplos não vistos, sobre­ajuste e sub­montagem dos dados de treinamento, a
do modelo e a noção de regularização. O leitor é encorajado a experimentar os exemplos (no
listagens de código fonte). No próximo capítulo, vamos nos basear nesses conceitos e cobrir as redes neurais.
Figura 2­5. Regularização

Página 27
15
© Nikhil Ketkar 2017
N. Ketkar, Aprendizado Profundo com Python , DOI 10.1007 / 978­1­4842­2766­4_3

CAPÍTULO 3

Feed Forward Neural 
Networks
Neste capítulo, abordaremos alguns conceitos­chave sobre redes neurais feedforward. Esses conceitos
servir de base à medida que abordamos mais tópicos técnicos em profundidade.
Em um nível abstrato, uma Rede Neural pode ser pensada como uma função
fx
y
q :

,
® que leva uma entrada x
n

ÎR e produz uma saída y
m

ÎR, e cujo comportamento é
parametrizado por q pR p . Então, por exemplo, f θ poderia ser simplesmente yfx
x
= () = ×
q

q.
Vamos começar observando a estrutura de uma rede neural, seguida de como eles são treinados e usados
para fazer previsões.

Unidade
Uma unidade é o edifício básico de uma rede neural; consulte a Figura  3­1 . Os seguintes pontos devem ser observados:
1. Uma unidade é uma função que recebe como entrada um vetor x
n

ÎR e produz um escalar.
2. Uma unidade é parametrizada por um vetor de peso w
n

ÎR e um termo de polarização denotado por b .
3. A saída da unidade pode ser descrita como
f
xwb
Eu
n
Eu
Eu
=

å × +
æ
è
ç
ö
ø
÷
1

onde f : R
R
® é referido como uma função de ativação.
4. Uma variedade de funções de ativação pode ser usada, como veremos mais adiante no capítulo;
geralmente, é uma função não linear.

Página 28
CAPÍTULO 3 ■ ALIMENTAÇÃO DE REDES NEURAIS
16
Figura 3­1. Uma unidade em uma rede neural

Página 29
CAPÍTULO 3 ■ ALIMENTAÇÃO DE REDES NEURAIS
17
Estrutura Geral de uma Rede Neural
Redes neurais são construídas usando a unidade como um bloco de construção básico (introduzido anteriormente); referir­se
Figura 3­2.
Figura 3­2. Estrutura de uma rede neural
Os seguintes pontos devem ser observados:
1. Unidades são organizadas como camadas, com cada camada contendo uma ou mais unidades.
2. A última camada é referida como a camada de saída.
3. Todas as camadas antes das camadas de saída são referidas como camadas ocultas.
4. O número de unidades em uma camada é referido como a largura da camada.

Página 30
CAPÍTULO 3 ■ ALIMENTAÇÃO DE REDES NEURAIS
18
5. A largura de cada camada não precisa ser a mesma, mas a dimensão deve ser
alinhado, como veremos mais adiante no capítulo.
6. O número de camadas é referido como a profundidade da rede. É aqui que o
noção de profundidade (como na aprendizagem profunda) vem de.
7. Cada camada toma como entrada a saída produzida pela camada anterior, exceto
a primeira camada, que consome a entrada.
8. A saída da última camada é a saída da rede e é a previsão
gerada com base na entrada.
9. Como vimos anteriormente, uma rede neural pode ser vista como uma função fx
y
q :

,
®
que leva como entrada x
n

ÎR e produz como saída y
m

ÎR e cujo comportamento é
parametrizado por q pR p . Agora podemos ser mais precisos sobre θ ; é simplesmente um
coleção de todos os pesos w para todas as unidades na rede.
10. O projeto de uma rede neural envolve, entre outras coisas, a definição do
estrutura da rede, incluindo o número de camadas ea largura dessas
camadas.

Expressando a rede neural no formulário vetorial
Vamos agora dar uma olhada nas camadas de uma rede neural e suas dimensões com um pouco mais de detalhes.
Consulte a Figura  3­3 ; os seguintes pontos devem ser observados:
1. Se assumirmos que a dimensionalidade da entrada é x
n

ÎR e a primeira camada tem p 1
unidades, então cada uma das unidades tem w
n

ÎR pesos associados a eles. Isto é, o
pesos associados com a primeira camada são uma matriz da forma w
np
1
1

Π´
R
. Enquanto isso é
não mostrado no diagrama, cada uma das p 1 unidades também tem um termo de polarização associada com ele.
2. A primeira camada produz uma saída ó
p
1
1

ÎR onde o
f
xw
b
Eu
k
n
k
k
Eu

=
× +
æ
è
ç
ö
ø
÷
=

uma
1

. Nota
que o índice k corresponde a cada uma das entradas / pesos (indo de 1… n ) e
o índice i corresponde às unidades na primeira camada (indo de 1 .. p 1 ).
3. Vamos agora olhar para a saída da primeira camada em uma notação vetorial. Por
notação vetorial simplesmente queremos dizer operações algébricas lineares como vetor
multiplicações de matrizes e computação da função de ativação em um vetor
produzindo um vetor (em vez de escalar para escalar). A saída da primeira camada pode
ser representado como fxwb
× +
(
)
1

1  . Aqui estamos tratando a entrada x
n

ÎR a ser de
dimensionalidade 1 × n , a matriz de peso w 1 é de dimensionalidade n × p 1 , e a
termo bias para ser um vetor de dimensionalidade 1 × p 1 . Observe então que xwb
× +
1

produz um vetor de dimensionalidade 1 × p 1 e a função f simplesmente transforma
cada elemento do vetor para produzir o
p
1
1

ÎR.
4. Um processo semelhante segue para a segunda camada, que vai desde o
p
1
1

ÎR to o
p
2
2

ÎR.
Isto pode ser escrito em forma vetorizada como fluxo
b
1
2
2

× +
(
) . Nós também podemos escrever o
todo o cálculo até a camada 2 em forma vetorizada como ffxwbw
b
× +
(
) × +
(
)
1
1
2

2  .

Página 31
CAPÍTULO 3 ■ ALIMENTAÇÃO DE REDES NEURAIS
19
Avaliando a saída da Rede Neural
Agora que vimos a estrutura de uma Rede Neural, vamos ver como a saída do sistema neural
rede pode ser avaliada em relação a dados rotulados. Consulte a Figura  3­4 . Os seguintes pontos devem ser observados:
1. Podemos supor que nossos dados tenham o formato D
xy
xy
xy
n
n

= (
) (
) ¼ (
)
{
}
1
1
2
2

,
,,
,
Onde
x
n

AndR e y Î {}
0 1, que é o alvo de interesse (atualmente isso é binário, mas
pode ser categórica ou real, dependendo se estamos lidando com um
multi­classe ou problema de regressão, respectivamente).
2. Para um único ponto de dados, podemos calcular a saída da Rede Neural, que
denotarmos como y .
Figura 3­3. Expressando a rede neural no formulário vetorial

Página 32
CAPÍTULO 3 ■ ALIMENTAÇÃO DE REDES NEURAIS
20
3. Agora precisamos calcular o quão boa a previsão da nossa Rede Neural y é tão
em comparação com y . Aqui vem a noção de uma função de perda.
4. Uma função perda mede a discordância entre Y e Y que indicam por
l . Há um número de funções de perda apropriadas para a tarefa em mãos: binário
classificação, multi­classificação ou regressão, que abordaremos mais adiante
capítulo (normalmente derivado usando Máxima Verossimilhança).
5. Uma função perda tipicamente calcula o desacordo entre y e y ao longo de um
número de pontos de dados em vez de um único ponto de dados.
Figura 3­4. Função perda / custo e o cálculo de custo / perda, uma rede neural

Página 33
Capítulo 3 ■ Alimentar Redes Neurais
21
Treinando a Rede Neural
Vamos agora ver como a Rede Neural é Treinada. Veja a figura 3­5. Os seguintes pontos devem ser
notado:
1. Assumindo a mesma notação anterior, denotamos por θ a coleção de todos os
pesos e termos de polarização de todas as camadas da rede. Vamos supor que θ
foi inicializado com valores aleatórios. Denotamos por f NN a função global
representando a Rede Neural.
2. Como vimos anteriormente, podemos pegar um único ponto de dados e calcular a saída
da Rede Neural y . Podemos também calcular o desacordo com o real
saída y utilizando a função de perda G ( y , y ) que é l ( f NN ( x ,  θ ),  y ).
3. Vamos agora calcular o gradiente desta função de perda e denotá­la por
Ñ
()
(
)
Se
x
y
NN

,
q
.
4. Agora podemos atualizar θ usando a descida mais íngreme como qq
uma
q
s
s
NN

Se
x
y
=
­ ×
()
(
)
­1

,
onde s denota um único passo (podemos dar muitos passos sobre diferentes dados
pontos em nosso treinamento repetidas vezes até que tenhamos um bom
valor para l ( f NN ( x ,  θ ),  y ).
■ Nota Por enquanto, vamos ficar longe do cálculo de gradientes de funções de perda Ñ
()
(
)
Se
x, y
NN

q
.
estes podem ser gerados usando diferenciação automática (coberto em outras partes do livro) facilmente 
(mesmo para
funções arbitrárias de perda complicada) e não precisam ser derivadas manualmente. também, o método 
de descida mais íngreme
e a descida de gradiente estocástica é abordada em um capítulo separado.

Página 34
Capítulo 3 ■ Alimentar Redes Neurais
22
Figura 3­5 Treinando uma rede neural

Derivando Funções de Custo usando a Máxima 
Verossimilhança
Agora veremos como as funções de perda são derivadas usando a Máxima Verossimilhança. Especificamente, veremos
como comumente usado perda funções em aprendizagem profunda como entropia cruzada binária, entropia cruzada e ao 
quadrado
erro pode ser derivado usando o princípio da máxima verossimilhança.

Página 35
Capítulo 3 ■ Alimentar Redes Neurais
23
Entropia Cruzada Binária
Em vez de começar com a ideia geral de Máxima Verossimilhança, vamos pular diretamente para o binário
problema de classificação. Nós temos alguns dados consistindo de D
xy
xy
xy
n
n

= (
) (
) ¼ (
)
{
}
1
1
2
2
,
,,
,
onde x
n

ÎR e
y Î {}
0 1,, que é o alvo de interesse (atualmente isso é binário, mas pode ser categórico ou real valorizado
dependendo se estamos lidando com um problema de múltiplas classes ou de regressão, respectivamente).
Vamos supor que de alguma forma tenhamos gerado um modelo que prevê a probabilidade de y dado x . Deixe­nos
denote este modelo por f  ( x ,  θ ) onde θ representa os parâmetros do modelo. A ideia por trás do máximo
Probabilidade é encontrar um θ que maximize PD | .
q
() Assumindo uma distribuição de Bernoulli e dado que cada
os exemplos {( x 1 ,  y 1 ), ( x 2 , y 2 ),… ( x n , y n )} são independentes, temos a seguinte expressão:
PD
fx
fx
Eu
n
Eu
y
Eu
y
Eu
Eu

|
,
q
q
q
() =
() × ­ ()
(
)
=
­
(
)

Õ
1
1

1
,
Podemos realizar uma operação de logaritmo em ambos os lados para chegar ao seguinte:
registro
|
registro
PD
fx
fx
Eu
n
Eu
y
Eu
y
Eu
Eu

q
q
q
() =
() × ­ ()
(
)
=
­
(
)

Õ
1
1

1
,
,
o que simplifica a expressão abaixo:
registro
|
registro
,
registro
,
PD
y
fx
y
fx
Eu
n
Eu
Eu
Eu
Eu

q
q
q
() =
() + ­
(
)
­ ()

(
)
=

uma
1

1
1
Em vez de maximizar o RHS, minimizamos seu valor negativo da seguinte forma:
­
() = ­
() + ­
(
)
­ ()

(
)
=

uma
registro
|
registro
,
registro
,
PD
y
fx
y
fx
Eu
n
Eu
Eu
Eu
Eu

q
q
q
1

1
1
Isso nos leva à função de entropia cruzada binária como abaixo:
­
() + ­
(
)
­ ()

(
)
=

uma
Eu
n
Eu
Eu
Eu
Eu

y
fx
y
fx
1

1
1
registro
,
registro
,
q
q
A idéia de Máxima Verossimilhança nos permite derivar a função de entropia cruzada binária que pode
ser usado como uma função de perda no contexto da classificação binária.

Entropia Cruzada
Com base na idéia de entropia cruzada binária, vamos considerar agora derivar a função de perda de entropia cruzada para
ser usado no contexto da multi­classificação. Vamos supor, neste caso, que y
k
Π{
}
0 1,, .., que são os
classes. Nós também denotamos nn
n k
1
2

, ××× para ser as contagens observadas de cada uma das k classes. Observe aquilo
Eu
k
Eu

nn
=
å =
1

.
Neste caso, vamos assumir que de alguma maneira geramos um modelo que prevê a probabilidade de y
dado x . Vamos denotar este modelo por f  ( x ,  θ ) onde θ representa os parâmetros do modelo. Vamos usar novamente
a ideia por trás da Máxima Verossimilhança, que é encontrar um θ que maximize o PD | .
q
() Assumindo um Multinomial
distribuição e dado que cada um dos exemplos {( x 1 ,  y 1 ), ( x 2 , y 2 ),… ( x n , y n )} são independentes, temos a
seguinte expressão:
PD
n
nn
n
fx
k
Eu
n
Eu
y eu

|
!
! !
!
,
q
q
() =
× ×××
()
=

Õ
1
2
1

Página 36
Capítulo 3 ■ Alimentar Redes Neurais
24
Podemos realizar uma operação de logaritmo em ambos os lados para chegar ao seguinte:
registro
|
registro ! registro ! !
! registro
,
PD
n
nn
n
fx
k
Eu
n
Eu
y eu

q
q
() =
­
× ××× +
()
=

Õ
1
2
1

Isso pode ser simplificado para o seguinte:
registro
|
registro ! registro ! !
!
registro
PD
n
nn
n
y
fx
k
Eu
n
Eu
Eu

q
q
() =
­
× ××× +
()
=

uma
1
2
1

,
Os termos log n ! e log! !
!
nn
n k
1
2

× ×××
não são parametrizados por θ e podem ser ignorados com segurança enquanto tentamos
encontre um θ que maximize o PD | .
q
() Assim temos o seguinte:
registro
|
registro
PD
y
fx
Eu
n
Eu
Eu

q
q
() =
()
=

uma
1

,
Como antes, em vez de maximizar o RHS, minimizamos seu valor negativo da seguinte forma:
­
() = ­
()
=
uma
registro
|
registro
PD
y
fx
Eu
n
Eu
Eu

q
q
1

,
Isso nos leva à função de entropia cruzada binária como abaixo:
­
()
=

uma
Eu
n
Eu
Eu

y
fx
1

registro
q
A idéia de Máxima Verossimilhança nos permite derivar a função de entropia cruzada, que pode ser usada
como uma função de perda no contexto de multi­classificação.

Erro Quadrado
Vamos agora olhar para derivar o erro quadrado a ser usado no contexto de regressão usando o máximo
Probabilidade. Suponhamos, neste caso, que y R. Ao contrário dos casos anteriores em que assumimos que tínhamos um
modelo que previu uma probabilidade, aqui vamos supor que temos um modelo que prevê o valor de y . Para
aplicar a idéia de Máxima Verossimilhança, assumimos que a diferença entre o y real e o predito
Y tem uma distribuição de Gauss com média igual a zero e uma variância de σ 2 . Então pode ser mostrado que minimizar
Eu
n

yy
=

å ­
()
1
2

ˆ
leva à minimização de ­
()
registro
|
PD q.

Página 37
Capítulo 3 ■ Alimentar Redes Neurais
25
Resumo das funções de perda
Agora resumimos três pontos­chave em relação às funções de perda e à adequação de um determinado
função de perda, dado o problema em questão.
1. A entropia cruzada binária dada pela expressão
­
() + ­
(
)
­ ()

(
)
=

uma
Eu
n
Eu
Eu
Eu
Eu

y
fx
y
fx
1

1
1
registro
,
registro
,
q
q
é a função de perda recomendada para classificação binária. Esta função de perda
normalmente deve ser usado quando a Rede Neural é projetada para prever o
probabilidade do resultado. Nesses casos, a camada de saída tem uma única unidade com um
sigmoide adequado como função de ativação.
2. A função de entropia cruzada dada pela expressão
­
()
=

uma
Eu
n
Eu
Eu

y
fx
1

registro
q
é a função de perda recomendada para multi­classificação. Esta função de perda
normalmente deve ser usado com a Rede Neural e é projetado para prever a
probabilidade dos resultados de cada uma das classes. Em tais casos, a camada de saída
tem unidades softmax (uma para cada classe).
3. A função de perda quadrática dada por
Eu
n

yy
=

å ­
()
1
2

ˆ
deve ser usado para regressão
problemas. A camada de saída, neste caso, terá uma única unidade.

Tipos de Unidades / Funções de Ativação / Camadas
Vamos agora olhar para um número de Unidades / Funções de Ativação / Camadas comumente usadas para Redes Neurais.
Vamos começar enumerando algumas propriedades de interesse para funções de ativação.
1. Em teoria, quando uma função de ativação é não­linear, uma Rede Neural de duas camadas
pode aproximar qualquer função (dado um número suficiente de unidades no oculto
camada). Assim, procuramos funções de ativação não linear em geral.
2. Uma função que é continuamente diferenciável permite que gradientes sejam computados
e métodos baseados em gradientes a serem usados para encontrar os parâmetros que minimizam
nossa função de perda sobre os dados. Se uma função não é continuamente diferenciável,
os métodos baseados em gradiente não podem progredir.
3. Uma função cujo alcance é finito (contra o infinito) leva a um mais estável
desempenho baseado em gradientes.
4. Funções suaves são preferidas (evidência empírica) e Monolítica
funções para uma camada única levam a superfícies de erro convexas (isso normalmente não é
consideração a aprendizagem profunda).
5. São simétricos em torno da origem e se comportam como funções identitárias próximas ao
origem ( fx
x
() =).

Página 38
Capítulo 3 ■ Alimentar Redes Neurais
26
Unidade Linear
A unidade linear é a unidade mais simples que transforma a entrada como ywxb
=
+
.
. Como o nome indica, o
unidade não tem um comportamento não linear e é normalmente usado para gerar a média de um
Distribuição gaussiana. As unidades lineares tornam o aprendizado baseado em gradiente uma tarefa bastante simples.

Unidade Sigmóide
A unidade Sigmoid transforma a entrada da seguinte maneira:
y
e wx b
=
+ ­
+
(
)
1
1
.
A função de ativação subjacente (consulte a figura 3­6) É dado por
fx
e x
() =
+ ­
1
1
.
Unidades sigmóides podem ser usadas na camada de saída em conjunto com entropia cruzada binária para binário
problemas de classificação. A saída desta unidade pode modelar uma distribuição de Bernoulli sobre a saída y
condicionado por x .
Figura 3­6. Função Sigmoide

Página 39
Capítulo 3 ■ Alimentar Redes Neurais
27
Camada Softmax
A camada Softmax é normalmente usada como uma camada de saída para tarefas de multi­classificação em conjunto com
a função de perda de entropia cruzada. Veja a figura 3­7. A camada Softmax normaliza as saídas do anterior
camada de modo que eles somam um. Normalmente, as unidades da camada anterior modelam uma pontuação não 
normalizada de
Qual é a probabilidade de a entrada pertencer a uma determinada classe. A camada softmax normalizou isso para que a saída
representa a probabilidade para cada classe.
Figura 3­7. Camada Softmax

Unidade Linear Retificada (ReLU)
Unidade Linear Retificada usada em conjunto com uma transformação linear transforma a entrada como
fx
wx b
() =
+
(
)
max, 0
.

Página 40
Capítulo 3 ■ Alimentar Redes Neurais
28
A função de ativação subjacente é fx
x
() =
()
max, 0; consulte a Figura  3­8 . A unidade ReLU é mais
comumente usado como uma unidade oculta nos últimos tempos. Os resultados mostram que as unidades ReLU levam a 
grandes e consistentes
gradientes, o que ajuda a aprendizagem baseada em gradiente.
Figura 3­8. ReLU

Tangente Hiperbólica
A unidade Tangente Hiperbólica transforma a entrada (usada em conjunto com uma transformação linear) como
segue:
y
wx b
=
+
(
)
tanh
.
A função de ativação subjacente (consulte a figura 3­9) É dado por
fx
x
() =
()
tanh
.
A unidade de tangente hiperbólica também é comumente usada como uma unidade oculta.

Página 41
Capítulo 3 ■ Alimentar Redes Neurais
29
Listagem 3­1. Uma rede neural de 2 camadas para regressão
import autograd.numpy como np
importar autograd.numpy.random como npr
de grad grad importação autograd
import sklearn.metrics
import pylab
# Gerar conjunto de dados
exemplos = 1000
recursos = 100
D = (npr.randn (exemplos, recursos), npr.randn (exemplos))
# Especifique a rede
camada1_unidades = 10
camada2_unidades = 1
w1 = npr.rand (recursos, camadas1_unidades)
b1 = npr.rand (layer1_units)
w2 = npr.rand (layer1_units, layer2_units)
b2 = 0,0
theta = (w1, b1, w2, b2)
# Definir a função de perda
def squared_loss (y, y_hat):
retornar np.dot ((y ­ y_hat), (y ­ y_hat))
# Camada de saída
def binary_cross_entropy (y, y_hat):
retornar np.sum (­ ((y * np.log (y_hat)) + ((1­y) * np.log (1 ­ y_hat))))
Figura 3­9. A função de ativação tanh

Página 42
Capítulo 3 ■ Alimentar Redes Neurais
30
# Wraper ao redor da Rede Neural
def neural_network (x, theta):
w1, b1, w2, b2 = teta
return np.tanh (np.dot ((np.tanh (np.dot (x, w1) + b1)), w2) + b2)
# Invólucro ao redor da função objetiva a ser otimizada
objetivo de defesa (theta, idx):
return squared_loss (D [1] [idx], neural_network (D [0] [idx], teta))
# Update
def update_theta (theta, delta, alfa):
w1, b1, w2, b2 = teta
w1_delta, b1_delta, w2_delta, b2_delta = delta
w1_new = w1 ­ alfa * w1_delta
b1_new = b1 ­ alfa * b1_delta
w2_new = w2 ­ alpha * w2_delta
b2_new = b2 ­ alfa * b2_delta
new_theta = (w1_new, b1_new, w2_new, b2_new)
return new_theta
# Compute Gradient
grad_objective = grad (objetivo)
# Treine a Rede Neural
épocas = 10
print "RMSE antes do treino:", sklearn.metrics.mean_squared_error (D [1], neural_network (D [0],
teta))
rmse = []
para i em xrange (0, epochs):
para j em xrange (0, exemplos):
delta = grad_objective (theta, j)
theta = update_theta (theta, delta, 0.01)
rmse.append (sklearn.metrics.mean_squared_error (D [1], neural_network (D [0], theta)))
print "RMSE após o treinamento:", sklearn.metrics.mean_squared_error (D [1], neural_network (D [0],
teta))
pylab.plot (rmse)
pylab.show ()
#Saída
#RMSE antes do treino: 1.88214665439
#RMSE após o treino: 0.739508975012

Página 43
Capítulo 3 ■ Alimentar Redes Neurais
31

Rede Neural Hands­on com AutoGrad
Vamos agora construir uma rede neural simples a partir do zero (consulte a Listagem 3­1 ). A única biblioteca externa
nós estaremos usando é Autograd. O Autograd é uma biblioteca de diferenciação automática que nos permitirá computar
gradientes para funções arbitrárias escritas com Numpy.
■ Observe que o autograd é abordado com mais detalhes no capítulo sobre diferenciação automática.

Resumo
Neste capítulo, abordamos as redes neurais avançadas, que servirão de base conceitual para
o resto dos capítulos. Os principais conceitos que abordamos foram a estrutura geral da rede neural, a
entrada, camadas ocultas e de saída, funções de custo e sua base no princípio da Máxima Verossimilhança.
Encorajamos o leitor a experimentar o exemplo na listagem do código­fonte; embora seja um exemplo de brinquedo,
ajudar a reforçar os conceitos. O próximo capítulo irá fornecer uma introdução prática ao leitor sobre Theano,
o que permitirá ao leitor implementar redes neurais completas.
Figura 3­10. RMSE sobre etapas de treinamento

Página 44
33
© Nikhil Ketkar 2017
N. Ketkar, Aprendizado Profundo com Python , DOI 10.1007 / 978­1­4842­2766­4_4

CAPÍTULO 4

Introdução a Theano
Neste capítulo, apresentamos o leitor a Theano, que é uma biblioteca Python para definir matemática
funções (operando sobre vetores e matrizes) e computando os gradientes dessas funções. Theano é
a camada básica na qual muitos pacotes de aprendizado profundo, como Keras, são baseados.

O que é Theano
Como vimos anteriormente, a construção de modelos de aprendizagem profunda envolve fundamentalmente a otimização de
funções de perda
usando gradiente descendente estocástico (SGD), requerendo o cálculo do gradiente de função de perda. Como perda
funções em aprendizagem profunda são complicadas, não é conveniente derivar manualmente tais gradientes. Isto é
onde Theano vem a calhar. Theano permite ao usuário definir expressões matemáticas que codificam a perda
funções e, uma vez definidas, Theano permite ao usuário calcular os gradientes dessas expressões.
Um fluxo de trabalho típico para usar o Theano é o seguinte:
1. Escreva expressões simbólicas no Python que implementam a função de perda do
modelo a ser construído. Isso geralmente equivale a apenas algumas linhas de código por causa de
a expressividade da linguagem Python e uma forte integração com o Numpy
que permite ao usuário definir rápida e elegantemente expressões matemáticas
envolvendo vetores e matrizes.
2. Use os recursos de diferenciação simbólica / automática em Theano para gerar uma
expressão que produz o gradiente da função de perda.
3. Passe esta função de gradiente como um parâmetro para uma rotina de otimização SGD para
otimizar a função de perda.
Theano permite que um usuário se concentre no modelo e não na mecânica de derivar o gradiente. o
capacidades específicas do Theano que o tornam uma ótima caixa de ferramentas para a construção de modelos de 
aprendizagem profunda são as seguintes:
1. uma integração muito perfeita com Numpy que permite ao usuário usar Numpy
objetos (vetores e matrizes) na definição de funções de perda
2. Theano pode gerar código otimizado tanto para CPU quanto para GPU sob
o capô sem que o usuário tenha que reescrever o código, o que define a perda
função.
3. diferenciação automática / simbólica otimizada
4. estabilidade numérica para o código gerado via diferenciação automática / simbólica

Página 45
CAPÍTULO 4 ■ INTRODUÇÃO AO THEANO
34

Theano Hands­On
Vamos agora começar a sujar as mãos com Theano. Vamos começar com exemplos simples, que servirão como
blocos de construção conceituais para exemplos mais complicados. Recomenda­se que o leitor repasse o
listagem do código­fonte e gráfico computacional correspondente para cada exemplo e considerar cuidadosamente
como o código­fonte se traduz no gráfico computacional.
Em nosso primeiro exemplo na Listagem 4­1 (e no gráfico computacional correspondente na Figura 4­1) nós vamos
defina uma função simples com escalares. O leitor deve observar o seguinte:
1. Escalas são definidas antes de poderem ser usadas em uma expressão matemática.
2. Todo escalar recebe um nome único.
3. Uma vez definido, o escalar pode ser operado com operações como +, ­, * e /.
4. O construto de função em Theano permite relacionar entradas e saídas. Então, em
o exemplo da Listagem 4­1 , definimos uma função com o nome g, que
toma a, b, c, d e e como entrada e produz f como saída.
5. Podemos agora calcular o resultado da função g dada a entrada e verificar se ela
avalia exatamente como a expressão não­Theano.
6. Embora isso pareça um exemplo trivial, a parte não trivial é que agora vamos
ser capaz de calcular facilmente o gradiente de tal função g com bastante facilidade usando
Theano, como veremos em breve.
Listagem 4­1. Funções com escalares
import theano.tensor como T
da função de importação theano
a = T.dscalar ('a')
b = T.dscalar ('b')
c = T.dscalar ('c')
d = T.dscalar ('d')
e = T.dscalar ('e')
f = ((a ­ b + c) * d) / e
g = função ([a, b, c, d, e], f)
print "Esperado: ((1 ­ 2 + 3) * 4) /5.0 =", ((1 ­ 2 + 3) * 4) /5.0
print "Via Theano: ((1 ­ 2 + 3) * 4) /5.0 =", g (1, 2, 3, 4, 5)
# Esperado: ((1 ­ 2 + 3) * 4) /5,0 = 1,6
# Via Theano: ((1 ­ 2 + 3) * 4) /5,0 = 1,6

Página 46
CAPÍTULO 4 ■ INTRODUÇÃO AO THEANO
35
Em nosso segundo exemplo na listagem 4­2 (e o gráfico computacional correspondente na Figura 4­2) nós vamos
defina uma função simples com vetores. O leitor deve observar o seguinte:
1. Vetores / Matrizes são definidos antes de poderem ser usados em uma
expressão.
2. Cada vetor / matriz recebe um nome exclusivo.
3. As dimensões dos Vetores / Matrizes não são especificadas.
4. Uma vez que Vetores / Matrizes são definidos, o usuário pode definir operações como matriz
adição, subtração e multiplicação. O usuário deve tomar cuidado para que o vetor /
operações matriciais respeitam a dimensionalidade pretendida.
5. Como antes, o usuário pode definir uma função com base nas expressões definidas. Em
Neste caso, definimos uma função f que toma a, b, c e d como entrada e produz e como
saída.
6. O uso pode passar arrays Numpy para a função e calcular a saída.
O usuário deve tomar cuidado para que as entradas vetor / matriz respeitem o
dimensionalidade.
Listagem 4­2. Funções com vetores
import numpy
import theano.tensor como T
da função de importação theano
a = T.dmatrix ('a')
b = T.dmatrix ('b')
c = T.dmatrix ('c')
d = T.dmatrix ('d')
Figura 4­1. Funções com escalares

Página 47
CAPÍTULO 4 ■ INTRODUÇÃO AO THEANO
36
e = (a + b ­ c) * d
f = função ([a, b, c, d], e)
a_data = numpy.array ([[1,1], [1,1]])
b_data = numpy.array ([[2,2], [2,2]])
c_data = numpy.array ([[5,5], [5,5]])
d_data = numpy.array ([[3,3], [3,3]])
print "Esperado:", (a_data + b_data ­ c_data) * d_data
print "Via Theano:", f (dados a_data, b_data, c_data, d_data)
# Esperado: [[­6 ­6]
# [­6 ­6]]
# Via Theano: [[­6. ­6.]
# [­6. ­6]]]
Figura 4­2. Funções com vetores
Em nosso próximo exemplo na listagem 4­3 (e o gráfico computacional correspondente na Figura   4­3 ) nós iremos
defina uma função com escalares e vetores. O leitor deve observar o seguinte:
1. Escalas e vetores / matrizes podem ser usados juntos em expressões.
2. O usuário precisa cuidar para que vetores / matrizes respeitem a dimensionalidade
ao definir as expressões, assim como passar entradas para as expressões.
Listagem 4­3. Funções com escalares e vetores
import numpy
import theano.tensor como T
da função de importação theano

Página 48
CAPÍTULO 4 ■ INTRODUÇÃO AO THEANO
37
a = T.dmatrix ('a')
b = T.dmatrix ('b')
c = T.dmatrix ('c')
d = T.dmatrix ('d')
p = T.dscalar ('p')
q = T.dscalar ('q')
r = T.dscalar ('r')
s = T.dscalar ('s')
u = T.dscalar ('u')
e = (((a * p) + (b ­ q) ­ (c + r)) * d / s) * u
f = função ([a, b, c, d, p, q, r, s, u] e)
a_data = numpy.array ([[1,1], [1,1]])
b_data = numpy.array ([[2,2], [2,2]])
c_data = numpy.array ([[5,5], [5,5]])
d_data = numpy.array ([[3,3], [3,3]])
print "Esperado:", ((((a_data * 1.0) + (b_data ­ 2.0) ­ (c_data + 3.0)) * d_data / 4.0) * 5.0
print "Via Theano:", f (a_data, b_data, c_data, d_data, 1,2,3,4,5)
# Esperado: [[­26.25 ­26.25]
# [­26.25 ­26.25]]
# Via Theano: [[­26.25 ­26.25]
# [­26.25 ­26.25]]
Figura 4­3. Funções com escalares e vetores
Em nosso próximo exemplo na listagem 4­4 (e o gráfico computacional correspondente na Figura   4­4 ) nós iremos
defina algumas funções de ativação com o Theano. O pacote nnet em Theano define uma série de
funções de ativação.
Listagem 4­4. Funções de Ativação
import theano.tensor como T
da função de importação theano
# sigmoid
a = T.dmatrix ('a')
f_a = T.nnet.sigmoid (a)
f_sigmoid = function ([a], [f_a])
print "sigmoid:", f_sigmoid ([[­ 1,0,1]])

Página 49
CAPÍTULO 4 ■ INTRODUÇÃO AO THEANO
38
# tanh
b = T.dmatrix ('b')
f_b = T.tanh (b)
f_tanh = função ([b], [f_b])
print "tanh:", f_tanh ([[­ 1,0,1]])
# sigmoide rápido
c = T.dmatrix ('c')
f_c = T.nnet.ultra_fast_sigmoid (c)
f_fast_sigmoid = function ([c], [f_c])
print "fast sigmoid:", f_fast_sigmoid ([[­ 1,0,1]])
# softplus
d = T.dmatrix ('d')
f_d = T.nnet.softplus (d)
f_softplus = function ([d], [f_d])
print "soft plus:", f_softplus ([[­ 1,0,1]])
# relu
e = T.dmatrix ('e')
f_e = T.nnet.relu (e)
f_relu = function ([e], [f_e])
print "relu:", f_relu ([[­ 1,0,1]])
# softmax
f = T.dmatrix ('f')
f_f = T.nnet.softmax (f)
f_softmax = function ([f], [f_f])
print "soft max:", f_softmax ([[­ 1,0,1]])

Página 50
CAPÍTULO 4 ■ INTRODUÇÃO AO THEANO
39
Em nosso próximo exemplo na listagem 4­5 (e o gráfico computacional correspondente na Figura   4­5 ) nós iremos
define uma função com estado interno. O leitor deve observar o seguinte:
1. Todos os modelos (aprendizado profundo ou não) envolverão a definição de funções com
estado interno, que normalmente será pesos que precisam ser aprendidos ou ajustados.
2. Uma variável compartilhada é definida usando a construção compartilhada no Theano.
3. Uma variável compartilhada pode ser inicializada com construções Numpy.
4. Quando a variável compartilhada é definida e inicializada, ela pode ser usada no
definição de expressões e funções de maneira semelhante aos escalares e
vetores / matrizes, como vimos anteriormente.
5. Um usuário pode obter o valor da variável compartilhada usando o método get_value.
Figura 4­4. Funções de Ativação

Page 51
CAPÍTULO 4 ■ INTRODUÇÃO AO THEANO
40
6. Um usuário pode definir o valor da variável compartilhada usando o método set_value.
7. Uma função definida usando a variável compartilhada calcula sua saída com base em
o valor atual da variável compartilhada. Ou seja, assim que a variável compartilhada
atualizações, uma função definida usando a variável compartilhada produzirá um
valor para a mesma entrada.
8. Uma variável compartilhada permite ao usuário definir uma função com estado interno, que pode
ser atualizado arbitrariamente sem precisar redefinir a função definida usando o
variável compartilhada.
Listagem 4­5. Variáveis Compartilhadas
import theano.tensor como T
da função de importação theano
a partir de theano import shared
import numpy
x = T.dmatrix ('x')
y = shared (numpy.array ([[4, 5, 6]]))
z = x + y
f = função (entradas = [x], saídas = [z])
print "Valor compartilhado original:", y.get_value ()
print "Avaliação da função original:", f ([[1, 2, 3]])
y.set_value (numpy.array ([[5, 6, 7]]))
print "Valor compartilhado original:", y.get_value ()
print "Avaliação da função original:", f ([[1, 2, 3]])
# Não foi possível importar o dot_parser, o carregamento de arquivos de ponto não será possível.
# Valor compartilhado original: [[4 5 6]]
# Original Function Evaluation: [array ([[5., 7., 9.]])]
# Valor compartilhado original: [[5 6 7]]
# Original Function Evaluation: [array ([[6., 8., 10.]])]

Página 52
CAPÍTULO 4 ■ INTRODUÇÃO AO THEANO
41
Em nosso próximo exemplo na listagem 4­6 (e o gráfico computacional correspondente na Figura   4­6 ) nós iremos
defina uma função e gere uma função que calcule seu gradiente. O leitor deve observar o seguinte:
1. Uma função precisa ser definida usando expressões antes do gradiente do
função pode ser gerada.
2. O constructo grad em Theano permite ao usuário gerar o gradiente de um
função (como uma expressão). Os usuários podem então definir uma função sobre a expressão,
que lhes dá a função de gradiente.
3. Os gradientes podem ser calculados para qualquer conjunto de expressões / funções como no
exemplos. Então, por exemplo, poderíamos gerar gradientes para funções com um
estado compartilhado. À medida que o estado compartilhado é atualizado, o mesmo acontece com a função e o gradiente
função.
Listagem 4­6. Gradientes
import theano.tensor como T
da função de importação theano
a partir de theano import shared
import numpy
x = T.dmatrix ('x')
y = shared (numpy.array ([[4, 5, 6]]))
z = T.sum (((x * x) + y) * x)
f = função (entradas = [x], saídas = [z])
g = T.grad (z, [x])
g_f = function ([x], g)
Figura 4­5. Variáveis Compartilhadas

Página 53
CAPÍTULO 4 ■ INTRODUÇÃO AO THEANO
42
print "Original:", f ([[1, 2, 3]])
print "Gradient Original:", g_f ([[1, 2, 3]])
y.set_value (numpy.array ([[1, 1, 1]]))
print "Atualizado:", f ([[1, 2, 3]])
print "Gradient atualizado", g_f ([[1, 2, 3]])
# Original: [array (68.0)]
# Gradiente Original: [array ([[7., 17., 33.]])]
# Atualizado: [array (42,0)]
# Gradiente atualizado [array ([[4., 13., 28.]])]
Figura 4­6. Gradientes de computação
Em nosso próximo exemplo na listagem 4­7 (e o gráfico computacional correspondente na Figura   4­7 (a) e
Figura 4­7 (b)) vamos definir algumas funções de perda usando o Theano. O pacote nnet nos implementos Theano
muitas funções de perda padrão.
Listagem 4­7. Funções de perda
import theano.tensor como T
da função de importação theano
# entropia cruzada binária
a1 = T.dmatrix ('a1')
a2 = T.dmatrix ('a2')
f_a = T.nnet.binary_crossentropy (a1, a2) .mean ()
f_sigmoid = função ([a1, a2], [f_a])
print "Entropia Cruzada Binária [[0.01,0.01,0.01]], [[0.99,0.99,0.01]]:",
f_sigmoid ([[0.01,0.01,0.01]], [[0.99,0.99,0.01]])

Página 54
CAPÍTULO 4 ■ INTRODUÇÃO AO THEANO
43
# entropia cruzada categórica
b1 = T.dmatrix ('b1')
b2 = T.dmatrix ('b2')
f_b = T.nnet.categorical_crossentropy (b1, b2)
f_sigmoid = função ([b1, b2], [f_b])
print "Entropia Cruzada Categórica [[0.01,0.01,0.01]], [[0.99.0.99,0.01]]:",
f_sigmoid ([[0.01,0.01,0.01]], [[0.99,0.99,0.01]])
# erro quadrado
def squared_error (x, y):
retorno (x ­ y) ** 2
c1 = T.dmatrix ('b1')
c2 = T.dmatrix ('b2')
f_c = squared_error (c1, c2)
f_squared_error = função ([c1, c2], [f_c])
print "Erro ao quadrado [[0,01,0.01,0.01]], [[0.99,0.99,0.01]]:",
f_sigmoid ([[0.01,0.01,0.01]], [[0.99,0.99,0.01]])
# Entropia Cruzada Binária [[0.01,0.01,0.01]], [[0.99,0.99,0.01]]: [matriz (3.058146503109446)]
# Entropia Cruzada Categórica [[0.01,0.01,0.01]], [[0.99,0.99,0.01]]: [array ([9.16428867])]
# Squared Error [[0.01,0.01,0.01]], [[0.99,0.99,0.01]]: [matriz ([9,16428867])]
Figura 4­7 (a). Funções de Perda ­ Entropia Cruzada Binária

Page 55
CAPÍTULO 4 ■ INTRODUÇÃO AO THEANO
44
Figura 4­7 (b). Funções de Perda ­ Entropia Cruzada Categórica e Erro Quadrático

Página 56
CAPÍTULO 4 ■ INTRODUÇÃO AO THEANO
45
Em nosso próximo exemplo na listagem 4­8 (e gráfico computacional correspondente na Figura 4­8) nós vamos
definir a regularização de L1 e L2 usando Theano.
Listagem 4­8. Regularização
import theano.tensor como T
da função de importação theano
# L1 Regularização
def l1 (x):
retornar T.sum (abs (x))
# Regularização L2
def l2 (x):
retornar T.sum (x ** 2)
a = T.dmatrix ('a')
f_a = l1 (a)
f_l1 = função ([a], f_a)
print "Regularização L1:", f_l1 ([[0,1,3]])
b = T.dmatrix ('b')
f_b = l2 (b)
f_l2 = função ([b], f_b)
print "Regularização L2:", f_l2 ([[0,1,3]])
# L1 Regularização: 4.0
Regularização # L2: 10.0

Página 57
CAPÍTULO 4 ■ INTRODUÇÃO AO THEANO
46
Em nosso próximo exemplo na listagem 4­9 (e gráfico computacional correspondente na Figura 4­9) nós vamos
defina uma função com uma variável aleatória. O leitor deve observar o seguinte:
1. Existem casos / situações em que queremos definir funções com um
variável (por exemplo, introduzindo pequenas corrupções nos insumos).
2. Tal elemento aleatório na função é diferente de ter um estado interno,
como no caso de variáveis compartilhadas.
Figura 4­8. Regularização

Página 58
CAPÍTULO 4 ■ INTRODUÇÃO AO THEANO
47
3. Basicamente, o resultado desejado em tais casos / situações é que o usuário deseja
defina uma função com uma variável aleatória com uma distribuição particular.
4. Theano fornece um constructo chamado RandomStreams, que permite ao usuário
defina funções com uma variável aleatória. RandomStreams é inicializado com um
semente.
5. O usuário define uma variável usando RandomStreams e especifica uma distribuição por
chamando a função apropriada (no nosso caso, normal).
6. Uma vez definida, a variável aleatória pode ser usada na definição de expressão ou
funciona de maneira semelhante aos escalares e vetores / matrizes.
7. Toda invocação da função definida com uma variável aleatória irá internamente
desenhe um ponto de amostra a partir da distribuição do conjunto (no nosso caso, normal).
Listagem 4­9. Fluxos aleatórios
import theano.tensor como T
da função de importação theano
from theano.tensor.shared_randomstreams import RandomStreams
import numpy
random = RandomStreams (seed = 42)
a = random.normal ((1,3))
b = T.dmatrix ('a')
f1 = a * b
g1 = função ([b], f1)
print "Invocação 1:", g1 (numpy.ones ((1,3)))
print "Invocação 2:", g1 (numpy.ones ((1,3)))
print "Invocação 3:", g1 (numpy.ones ((1,3)))
# Invocação 1: [[1.25614218 ­0.53793023 ­0.10434045]]
# Invocação 2: [[0,66992188 ­0,70813926 0,99601177]]
# Invocação 3: [[0,0724739 ­0,66508406 0,93707751]]

Página 59
CAPÍTULO 4 ■ INTRODUÇÃO AO THEANO
48
Em nosso próximo exemplo na listagem 4­10 (e gráfico computacional correspondente na Figura 4­10 ) nós iremos
construir um modelo para regressão logística. O leitor deve observar o seguinte:
1. O exemplo gera alguns dados artificiais / brinquedo, ajusta­se a um modelo de regressão logística
e calcula a precisão antes e depois do treino. Este é um conjunto de dados de brinquedo para o
fins de ilustração; o modelo não está generalizando / aprendendo, pois os dados são
gerado aleatoriamente.
2. Definimos uma função para calcular a regularização de L2, conforme descrito na listagem 4­8.
mais cedo.
3. Nós geramos dados de entrada, que consistem em 1000 vetores de dimensionalidade 100.
Basicamente, 1000 exemplos com 100 recursos.
4. Nós geramos rótulos de destino / saída aleatórios como zeros e uns.
5. Definimos as expressões para regressão logística envolvendo os dados
por x), as saídas (denotadas por y), o termo de polarização (denotado por b) e o peso
vetor (denotado por w). O vetor de ponderação e o termo de polarização são variáveis compartilhadas.
6. Calculamos a previsão, o erro e a perda usando entropia cruzada binária como
introduzido na listagem 4­7 anteriormente.
7. Tendo definido essas expressões, podemos agora usar o constructo grad em Theano
(introduzido na listagem ( 4­6 )) para calcular o gradiente.
8. Definimos uma função de trem com base na função de gradiente. A função do trem
define as entradas, saídas e como o estado interno (variáveis compartilhadas) é
ser atualizado.
9. A função train é invocada por 1000 passos; em cada passo o gradiente é
computada internamente e as variáveis compartilhadas são atualizadas.
10. A precisão é calculada antes e depois das etapas de treinamento usando sklearn.metrics
Figura 4­9. Fluxos aleatórios

Página 60
CAPÍTULO 4 ■ INTRODUÇÃO AO THEANO
49
Listagem 4­10. Regressão Logística
import numpy
importar theano
import theano.tensor como T
import sklearn.metrics
def l2 (x):
retornar T.sum (x ** 2)
exemplos = 1000
recursos = 100
D = (numpy.random.randn (exemplos, recursos), numpy.random.randint (size = examples,
baixo = 0, alto = 2))
training_steps = 1000
x = T.dmatrix ("x")
y = T.dvector ("y")
w = theano.shared (numpy.random.randn (recursos), name = "w")
b = theano.shared (0., name = "b")
p = 1 / (1 + T.exp (­T.dot (x, w) ­ b))
erro = T.nnet.binary_crossentropy (p, y)
perda = error.mean () + 0,01 * l2 (w)
predição = p> 0.5
gw, gb = T.grad (perda, [w, b])
train = theano.function (entradas = [x, y], saídas = [p, erro], atualizações = ((w, w ­ 0.1 * gw),
(b, b ­ 0,1 * gb)))
predict = theano.function (inputs = [x], outputs = previsão)
print "Precisão antes do treino:", sklearn.metrics.accuracy_score (D [1], predict (D [0]))
para i no intervalo (training_steps):
previsão, erro = trem (D [0], D [1])
print "Precisão antes do treino:", sklearn.metrics.accuracy_score (D [1], predict (D [0]))
# Precisão antes do treino: 0.481
# Precisão antes do treino: 0.629

Página 61
CAPÍTULO 4 ■ INTRODUÇÃO AO THEANO
50
Em nosso próximo exemplo na Listagem 4­11 (e gráfico computacional correspondente na Figura 4­11 ) nós iremos
construir um modelo para regressão linear. O leitor deve observar o seguinte:
1. O exemplo gera alguns dados artificiais / brinquedo, ajusta­se a um modelo de regressão linear
e calcula a precisão antes e depois do treino. Este é um conjunto de dados de brinquedo para
Para fins de ilustração, o modelo não é generalizar / aprender como os dados são
gerado aleatoriamente.
2. Definimos uma função para calcular a regularização de L2 como coberta na listagem 4­8
mais cedo.
3. Nós definimos uma função para erro quadrado como coberto na listagem 4­7.
4. Nós geramos dados de entrada, que consistem em 1000 vetores de dimensionalidade 100.
Basicamente, 1000 exemplos com 100 recursos.
5. Nós geramos valores aleatórios de rótulos alvo / saída entre 0 e 1.
6. Definimos as expressões para regressão linear envolvendo os dados (denotado por x),
as saídas (denotadas por y), o termo de polarização (denotado por b) e o vetor de ponderação
(denotado por w). O vetor de ponderação e o termo de polarização são variáveis compartilhadas.
7. Calculamos a previsão, o erro e a perda usando o erro quadrado como
introduzido na listagem 4­7 anteriormente.
8. Tendo definido essas expressões, podemos agora usar o constructo grad em Theano
(introduzido na listagem ( 4­6 ) para calcular o gradiente.
9. Definimos uma função de trem com base na função de gradiente. A função de trem define
as entradas, saídas e como o estado interno (variáveis compartilhadas) deve ser atualizado.
10. A função de trem é invocada por 1000 passos, em cada passo o gradiente é
computada internamente e as variáveis compartilhadas são atualizadas.
11. O erro quadrático médio da raiz (RMSE) é calculado antes e depois das etapas de treinamento
usando sklearn.metrics
Figura 4­10. Regressão Logística

Página 62
CAPÍTULO 4 ■ INTRODUÇÃO AO THEANO
51
Listagem 4­11. Regressão linear
import numpy
importar theano
import theano.tensor como T
import sklearn.metrics
def l2 (x):
retornar T.sum (x ** 2)
def squared_error (x, y):
retorno (x ­ y) ** 2
exemplos = 1000
recursos = 100
D = (numpy.random.randn (exemplos, recursos), numpy.random.randn (exemplos))
training_steps = 1000
x = T.dmatrix ("x")
y = T.dvector ("y")
w = theano.shared (numpy.random.randn (recursos), name = "w")
b = theano.shared (0., name = "b")
p = T.dot (x, w) + b
error = squared_error (p, y)
perda = error.mean () + 0,01 * l2 (w)
gw, gb = T.grad (perda, [w, b])
train = theano.function (entradas = [x, y], saídas = [p, erro], atualizações = ((w, w ­ 0.1 * gw),
(b, b ­ 0,1 * gb)))
predict = theano.function (inputs = [x], outputs = p)
print "RMSE antes do treinamento:", sklearn.metrics.mean_squared_error (D [1], predict (D [0]))
para i no intervalo (training_steps):
previsão, erro = trem (D [0], D [1])
print "RMSE após o treinamento:", sklearn.metrics.mean_squared_error (D [1], predict (D [0]))
# RMSE antes do treino: 90.4707491496
# RMSE após o treino: 0.915701676631

Página 63
CAPÍTULO 4 ■ INTRODUÇÃO AO THEANO
52
Em nosso próximo exemplo na listagem 4­12 (e gráfico computacional correspondente na Figura 4­12 ) nós iremos
Construa um modelo de rede neural com 2 camadas. O leitor deve observar o seguinte:
1. O exemplo gera alguns dados artificiais / brinquedo, ajusta­se a um modelo de regressão logística
e calcula a precisão antes e depois do treino. Este é um conjunto de dados de brinquedo para o
fins de ilustração; o modelo não está generalizando / aprendendo, pois os dados são
gerado aleatoriamente.
2. Definimos uma função para calcular a regularização de L2, conforme descrito na listagem 4­8.
mais cedo.
3. Nós geramos dados de entrada, que consistem em 1000 vetores de dimensionalidade 100.
Basicamente, 1000 exemplos com 100 recursos.
4. Nós geramos rótulos de destino / saída aleatórios como zeros e uns.
5. Definimos as expressões para a rede neural de 2 camadas envolvendo os dados
(denotado por x), as saídas (denotadas por y), o termo de polarização da primeira camada
(denotado por b1), o vetor de peso da primeira camada (denotado por w1), o termo de polarização
da segunda camada (denotada por b2) e, o vetor de ponderação da segunda camada
(denotado por w2). Os vetores de pesos e os termos de viés são variáveis compartilhadas.
6. Nós usamos a função de ativação de tanh como coberto na listagem 4­4 para codificar o neural
rede.
7. Calculamos a previsão, o erro e a perda usando entropia cruzada binária como
introduzido na listagem 4­7 anteriormente.
8. Tendo definido essas expressões, podemos agora usar o constructo grad em Theano
(introduzido na listagem ( 4­6 )) para calcular o gradiente.
9. Definimos uma função de trem com base na função de gradiente. A função do trem
define as entradas, saídas e como o estado interno (variáveis compartilhadas) é
ser atualizado.
Figura 4­11. Regressão linear
Página 64
CAPÍTULO 4 ■ INTRODUÇÃO AO THEANO
53
10. A função train é invocada por 1000 passos; em cada passo o gradiente é
computada internamente e as variáveis compartilhadas são atualizadas.
11. A precisão é calculada antes e depois das etapas de treinamento usando sklearn.metrics
Listagem 4­12. Rede neural
import numpy
importar theano
import theano.tensor como T
import sklearn.metrics
def l2 (x):
retornar T.sum (x ** 2)
exemplos = 1000
recursos = 100
hidden = 10
D = (numpy.random.randn (exemplos, recursos), numpy.random.randint (size = examples,
baixo = 0, alto = 2))
training_steps = 1000
x = T.dmatrix ("x")
y = T.dvector ("y")
w1 = theano.shared (numpy.random.randn (recursos, oculto), name = "w1")
b1 = theano.shared (numpy.zeros (oculto), name = "b1")
w2 = theano.shared (numpy.random.randn (oculto), name = "w2")
b2 = theano.shared (0., name = "b2")
p1 = T.tanh (T.dot (x, w1) + b1)
p2 = T.tanh (T.dot (p1, w2) + b2)
predição = p2> 0,5
erro = T.nnet.binary_crossentropy (p2, y)
perda = error.mean () + 0,01 * (l2 (w1) + l2 (w2))
gw1, gb1, gw2, gb2 = T.grad (perda, [w1, b1, w2, b2])
train = theano.function (entradas = [x, y], saídas = [p2, erro], atualizações = ((w1, w1 ­ 0,1 * gw1),
(b1, b1 ­ 0,1 * gb1), (w2, w2 ­ 0,1 * gw2), (b2, b2 ­ 0,1 * gb2)))
predict = theano.function (inputs = [x], outputs = [previsão])
print "Precisão antes do treino:", sklearn.metrics.accuracy_score (D [1], numpy.
array (predizer (D [0])). ravel ())
para i no intervalo (training_steps):
previsão, erro = trem (D [0], D [1])

Página 65
CAPÍTULO 4 ■ INTRODUÇÃO AO THEANO
54
print "Precisão após treinamento:", sklearn.metrics.accuracy_score (D [1],
numpy.array (prever (D [0])). ravel ())
# Precisão antes do treino: 0.51
# Precisão após o treino: 0.716
Figura 4­12. Rede neural
Em nosso próximo exemplo na listagem 4­13 (e gráficos computacionais correspondentes em Figuras4­13 (a), 4­13 (b)
e 4­13 (c) ) vamos definir uma função usando a construção if­else e switch. O leitor deve observar o seguinte:
1. Certas funções precisam de uma cláusula if­else (ou switch) para sua avaliação. Por tal
Casos Theano fornece uma construção if­else e switch.
2. Expressões e funções podem ser definidas usando as construções if­else e switch
e gradientes podem ser gerados como com outras expressões / construções.
3. No exemplo demonstramos o cálculo da dobradiça perder usando o
if­else e alternar construir e verificar se corresponde ao definido
com max.
Listagem 4­13. Mudar / If­else
import numpy
importar theano
import theano.tensor como T
de theano.ifelse import ifelse
def hinge_a (x, y):
retornar T.max ([0 * x, 1­x * y])
def hinge_b (x, y):
retornar ifelse (T.lt (1­x * y, 0), 0 * x, 1­x * y)
def hinge_c (x, y):
retornar T.switch (T.lt (1­x * y, 0), 0 * x, 1­x * y)

Página 66
CAPÍTULO 4 ■ INTRODUÇÃO AO THEANO
55
x = T.dscalar ('x')
y = T.dscalar ('y')
z1 = hinge_a (x, y)
z2 = hinge_b (x, y)
z3 = hinge_b (x, y)
f1 = theano.function ([x, y], z1)
f2 = theano.function ([x, y], z2)
f3 = theano.function ([x, y], z3)
print "f (­2, 1) =", f1 (­2, 1), f2 (­2, 1), f3 (­2, 1)
print "f (­1,1) =", f1 (­1, 1), f2 (­1, 1), f3 (­1, 1)
print "f (0,1) =", f1 (0, 1), f2 (0, 1), f3 (0, 1)
print "f (1, 1) =", f1 (1, 1), f2 (1, 1), f3 (1, 1)
print "f (2, 1) =", f1 (2, 1), f2 (2, 1), f3 (2, 1)
# f (­2, 1) = 3,0 3,0 3,0
# f (­1,1) = 2,0 2,0 2,0
# f (0,1) = 1,0 1,0 1,0
# f (1, 1) = 0.0 0.0 0.0
# f (2, 1) = 0.0 0.0 0.0
Figura 4­13 (a). Dobradiça implementada usando Max
Figura 4­13 (a) ilustra a implementação da perda de articulação usando a operação máxima que é
ly
xy
() =
­ ×
(
)
max, 0 1
onde x é a saída correta / real e y é a saída produzida pelo modelo. o
gráfico computacional corresponde de perto à fórmula / equação para perda de articulação.

Página 67
CAPÍTULO 4 ■ INTRODUÇÃO AO THEANO
56
Figura 4­13 (b) ilustra a implementação da perda de charneira usando a construção ifelse. Note como o
O gráfico computacional implementa a condição e a intenção de cada condição.
Figura 4­13 (b). Dobradiça implementada usando ifelse
Figura 4­13 (c). Dobradiça implementada usando o interruptor

Página 68
CAPÍTULO 4 ■ INTRODUÇÃO AO THEANO
57
Em nosso próximo exemplo na listagem 4­14 (e o gráfico computacional correspondente na Figura  4­14) nós
ilustrar a construção de varredura que permite ao usuário definir funções envolvendo computação iterativa. o
o leitor deve observar o seguinte.
1. A computação de certas funções requer construções iterativas para as quais Theano
fornece a construção da varredura.
2. Em nosso exemplo, calculamos a operação de energia com a construção da varredura e
combinar a saída com o uso do operador padrão para alimentação.
3. Expressões e funções podem ser definidas usando a construção de varredura e gradientes
pode ser gerado como com outras expressões / construções.
Listagem 4­14. Scan
importar theano
import theano.tensor como T
import theano.printing
k = T.iscalar ("k")
a = T.dscalar ("a")
result, updates = theano.scan (fn = anterior_resultado de lambda, a: prior_result * a, outputs_info = a,
non_sequences = a, n_steps = k­1)
final_resultado = resultado [­1]
a_pow_k = theano.function (entradas = [a, k], saídas = final_resultado, atualizações = atualizações)
imprima a_pow_k (2,5), 2 ** 5
imprima a_pow_k (2,5), 2 ** 5
# 32,0 32

Página 69
CAPÍTULO 4 ■ INTRODUÇÃO AO THEANO
58
F
ig
ure 4­14.
S
ca
n Op
era
ção

Página 70
CAPÍTULO 4 ■ INTRODUÇÃO AO THEANO
59

Resumo
Neste capítulo, cobrimos os conceitos básicos de Theano, que é uma biblioteca de baixo nível para a construção e 
treinamento neural.
redes. Theano permite aos usuários construir gráficos computacionais e gradientes de computação e é a ferramenta ideal
quando se trata de construir novas arquiteturas / redes, pois dá ao usuário um controle muito fino sobre
o gráfico computacional. Um número de bibliotecas como Keras (coberto no capítulo7) e lasanha são construídas sobre
Theano e fornecer abstrações de nível superior para que os usuários não precisem construir redes usando
gráficos próprios. Tais bibliotecas de nível superior tornam o usuário muito mais produtivo, mas o usuário não
tem controle preciso sobre a rede / arquitetura. Em geral, bibliotecas de nível superior são recomendadas
a biblioteca superior fornece uma implementação suficientemente próxima da rede / arquitetura que o usuário deseja
construir. Caso isso não esteja disponível, recomenda­se que o usuário construa a rede usando o Theano que
lhe dará controle total. Basicamente, usar essas bibliotecas de alto nível versus Theano é uma troca entre
produtividade e controle, muito semelhante à programação em Python vs. programação em C.

Página 71
61
© Nikhil Ketkar 2017
N. Ketkar, Aprendizado Profundo com Python , DOI 10.1007 / 978­1­4842­2766­4_5

CAPÍTULO 5
Redes Neurais Convolucionais
Convolution Neural Networks (CNNs), em essência, são redes neurais que empregam a operação de convolução
(em vez de uma camada totalmente conectada) como uma de suas camadas. CNNs são uma tecnologia incrivelmente bem 
sucedida que tem
foi aplicado a problemas em que os dados de entrada em que as previsões devem ser feitas tem uma grade conhecida como
topologia como uma série temporal (que é uma grade 1­D) ou uma imagem (que é uma grade 2­D).

Operação de convolução
Vamos começar a desenvolver a intuição para a operação de convolução em uma dimensão. Dado um input I ( t ) e um
kernel K ( a ) a operação de convolução é dada por
st
Eu um K ta
uma

() =
() ×
­
()
uma
Uma forma equivalente desta operação, dada a comutatividade da operação de convolução, é a seguinte:
st
Eu ta K a
uma

() =
­
() × ()
uma
Além disso, o sinal negativo (invertido) pode ser substituído para obter correlação cruzada, como segue:
st
Eu ta K a
uma

() =
+
() × ()
uma

Página 72
CAPÍTULO 5 ■ REDES NEURAIS CONVOLUCIONAIS
62
Figura 5­1. Operação de Convolução ­ Intuição
Em literatura de aprendizagem profunda e implementações de software, convolução e correlação cruzada são usadas
de forma intercambiável. A essência da operação é que o Kernel é um conjunto muito mais curto de pontos de dados
em comparação com a entrada, e a saída da operação de convolução é maior quando a entrada é semelhante à
o kernel. Figuras  5­1 e5­2 ilustram essa ideia­chave. Nós tomamos uma entrada arbitrária e um kernel arbitrário,
executar a operação de convolução, e o maior valor é obtido quando o kernel é semelhante a um
parte específica da entrada.

Página 73
CAPÍTULO 5 ■ REDES NEURAIS CONVOLUCIONAIS
63
Figura 5­2. Operação de convolução ­ uma dimensão
Page 74
CAPÍTULO 5 ■ REDES NEURAIS CONVOLUCIONAIS
64
Vamos fortalecer nossa intuição sobre a convolução observando figuras 5­1 e  5­2 e observando o
seguintes pontos:
1. A entrada é um grande conjunto arbitrário de pontos de dados.
2. O Kernel é um conjunto de pontos de dados menores em número para a entrada.
3. A operação de convolução, em certo sentido, desliza o kernel sobre a entrada e
calcula quão semelhante é o kernel com a parte da entrada.
4. A operação de convolução produz o maior valor onde o Kernel é mais
semelhante com uma parte da entrada.
A operação de convolução pode ser estendida para duas dimensões. Dada uma entrada I ( m , n ) e um kernel
K ( a , b ) a operação de convolução é dada por
st
Eu ab K manb
uma
b

() =
() ×
­
­
(
)
åå ,
,
Uma forma equivalente desta operação, dada a comutatividade da operação de convolução, é a seguinte:
st
Eu manb K ab
uma
b

() =
­
­
(
) × ()
åå
,
,
Além disso, o sinal negativo (invertido) pode ser substituído para obter correlação cruzada, como segue:
st
Eu manb K ab
uma
b

() =
+
+
(
) × ()
åå
,
,
Figura 5­3 ilustra a operação de convolução em duas dimensões. Note que isso é simplesmente estendendo
a ideia de convolução para duas dimensões.

Página 75
CAPÍTULO 5 ■ REDES NEURAIS CONVOLUCIONAIS
65
Figura 5­3. Operação de convolução ­ duas dimensões
Tendo introduzido a operação de convolução, podemos agora mergulhar mais fundo nas principais partes constituintes
um CNN, foram uma camada de convolução é usada em vez de uma camada totalmente conectada que envolve uma matriz
multiplicação. Então, uma camada totalmente conectada pode ser descrita como yfxw
=
×
(
) onde x é o vetor de entrada, y é
o vetor de saída, w é um conjunto de pesos, e f é a função de ativação. Correspondentemente, uma camada de convolução
pode ser descrito como yfsxw
=
×
(
)
(
) onde s denota a operação de convolução entre a entrada e a
pesos.

Página 76
CAPÍTULO 5 ■ REDES NEURAIS CONVOLUCIONAIS
66
Figura 5­4. Interações densas em camadas totalmente conectadas
Vamos agora contrastar a camada totalmente conectada com a camada de convolução. A Figura  5­4 ilustra um
camada conectada e a Figura  5­5 ilustra uma camada de convolução, esquematicamente. Figura 5­6 ilustra o parâmetro
compartilhamento em uma camada de convolução e a falta dela em uma camada totalmente conectada. Os seguintes pontos 
devem ser observados:
1. Para o mesmo número de entradas e saídas, a camada totalmente conectada tem muito
mais conexões e, correspondentemente, pesos que uma camada de convolução.
2. As interações entre insumos para produzir produtos são menores na convolução
camadas em comparação com muitas interações no caso de uma camada totalmente conectada.
Isso é chamado de interações esparsas.
3. Parâmetros / pesos são compartilhados através da camada de convolução, dado que o kernel
é muito menor que a entrada e o kernel desliza pela entrada. Assim, há
são muito menos parâmetros / pesos únicos em uma camada de convolução.

Página 77
CAPÍTULO 5 ■ REDES NEURAIS CONVOLUCIONAIS
67
Figura 5­5. Interações esparsas na camada de convolução

Página 78
CAPÍTULO 5 ■ REDES NEURAIS CONVOLUCIONAIS
68
Figura 5­6. Parâmetro Compartilhamento Pesos Amarrados

Operação de Pooling
Vamos agora olhar para a operação de pooling que é quase sempre usada em CNNs em conjunto com
convolução. A intuição por trás da operação de pooling é que a localização exata do recurso não é
preocupação se de fato foi descoberto. Ele simplesmente fornece invariância de tradução. Então, por exemplo, suponha
que a tarefa é aprender a detectar rostos em fotografias. Vamos supor também que os rostos no
fotografia são inclinadas (como geralmente são) e suponha que temos uma camada de convolução que detecta a
olhos. Gostaríamos de abstrair a localização dos olhos na fotografia a partir de sua orientação. O pooling
operação consegue isso e é um importante componente das CNNs.
Figura 5­7 ilustra a operação de agrupamento para uma entrada bidimensional. Os seguintes pontos devem ser observados:
1. O agrupamento opera sobre uma parte da entrada e aplica uma função f sobre este
entrada para produzir a saída.
2. A função f é comumente a operação max (levando ao pool máximo), mas
outras variantes, tais como média ou G 2 norma pode ser utilizado como uma alternativa.

Página 79
CAPÍTULO 5 ■ REDES NEURAIS CONVOLUCIONAIS
69
Figura 5­7. Pooling ou subamostragem
3. Para uma entrada bidimensional, esta é uma parte retangular.
4. A saída produzida como resultado do agrupamento é muito menor em dimensionalidade
em comparação com a entrada.

Página 80
CAPÍTULO 5 ■ REDES NEURAIS CONVOLUCIONAIS
70

Bloco de Construção de Convolução­Detecção­
Agrupamento
Vamos agora olhar para o bloco Convolução­Detector­Pooling, que pode ser pensado como um bloco de construção de
a CNN.
Vamos agora ver como todas as operações que cobrimos anteriormente funcionam em conjunto. Consulte a Figura  5­8
e Figura  5­9. Os seguintes pontos devem ser observados:
1. O estágio do detector é simplesmente uma função de ativação não linear.
2. As operações de convolução, detector e pool são aplicadas em seqüência para
Transformar a entrada para a saída. A saída é referida como um mapa de recursos.
3. A saída normalmente é passada para outras camadas (convolução ou totalmente conectada).
4. Vários blocos de Convolução­Detector­Pooling podem ser aplicados em paralelo,
consumindo a mesma entrada e produzindo várias saídas ou mapas de recursos.
Figura 5­8. Convolução seguida de estágio do detector e pooling

Página 81
CAPÍTULO 5 ■ REDES NEURAIS CONVOLUCIONAIS
71
Figura 5­9. Vários filtros / kernels que oferecem vários mapas de recursos

Página 82
CAPÍTULO 5 ■ REDES NEURAIS CONVOLUCIONAIS
72
No caso de entradas de imagem, que consistem em 3 canais, uma operação de convolução separada é aplicada
cada canal e, em seguida, saídas postar a convolução são somados. Isso é ilustrado na Figura  5­10 .
Figura 5­10. Convolução com múltiplos canais

Página 83
CAPÍTULO 5 ■ REDES NEURAIS CONVOLUCIONAIS
73
Figura 5­11. Uma arquitetura de rede neural de convolução completa
Tendo coberto todos os elementos constitutivos das CNNs, podemos agora olhar para uma CNN exemplar em sua
na totalidade, conforme ilustrado na Figura  5­11. A CNN consiste em dois estágios de agrupamento de detectores de 
convolução
blocos com vários filtros / kernels em cada estágio produzindo múltiplos mapas de recursos. Poste estes dois
Nos estágios, temos uma camada totalmente conectada que produz a saída. Em geral, uma CNN pode ter múltiplos
estágios de blocos de convolução­detecção­agrupamento (empregando múltiplos filtros) tipicamente
camada conectada.
Página 84
CAPÍTULO 5 ■ REDES NEURAIS CONVOLUCIONAIS
74

Variantes de Convolução
Vamos agora cobrir algumas variações de convolução, ilustradas na Figura  5­12.. Convolução Strided é uma variante
da convolução padrão onde o kernel desliza sobre a entrada movendo­se em uma passada predefinida. A
Uma maneira alternativa de ver isso é que a convolução padrão operava em um tamanho de passada igual a um.
Outra variação é a convolução de ladrilhos, onde na verdade existem vários kernels que são convolvidos com o
entrada alternadamente.
Figura 5­12. Convolução, variação do tema

Página 85
CAPÍTULO 5 ■ REDES NEURAIS CONVOLUCIONAIS
75
Outra variação do tema são camadas conectadas localmente que basicamente empregam esparsidade de
interações, mas não empregam compartilhamento de parâmetro / peso. Isso é ilustrado na Figura  5­13..
Figura 5­13. Pesos conectados localmente

Intuição por trás das CNNs
Até agora, neste capítulo, cobrimos os conceitos­chave constituintes por trás da CNN, ou seja, a convolução
operação, a operação de pooling e como eles são usados em conjunto. Vamos agora dar um passo atrás para
internalize a intuição por trás das CNNs usando esses blocos de construção.
A primeira ideia a considerar é a capacidade das CNNs (consulte o Capítulo 2 sobre a capacidade de uma máquina
modelo de aprendizagem). CNNs, que substituem pelo menos uma das camadas totalmente conectadas de uma rede neural 
pelo
operação de convolução, têm menos capacidade do que uma rede totalmente conectada. Ou seja, existem conjuntos de dados
que um
rede totalmente conectada será capaz de modelar que uma CNN não será. Então, o primeiro ponto a notar é que as CNNs
conseguir mais, limitando a capacidade, tornando a formação eficiente.

Página 86
CAPÍTULO 5 ■ REDES NEURAIS CONVOLUCIONAIS
76
A segunda ideia a considerar é que aprender os filtros a conduzir a operação de convolução é, em certo sentido,
aprendizagem de representação. Por exemplo, os filtros aprendidos podem aprender a detectar bordas, formas, etc.
ponto importante a considerar aqui é que não estamos descrevendo manualmente os recursos a serem extraídos do
dados de entrada, mas estão descrevendo uma arquitetura que aprende a projetar os recursos / representações.
A terceira ideia a considerar é a invariância de localização introduzida pela operação de agrupamento. O pooling
operação separa o local do recurso do fato de que ele é detectado. Um filtro detectando linhas retas
pode detectar esse filtro em qualquer parte da imagem, mas a operação de pool escolhe o fato de que o recurso é
detectado (pool máximo).
A quarta ideia é a da hierarquia. Uma CNN pode ter várias camadas de convolução e agrupamento empilhadas
seguido de uma rede totalmente conectada. Isso permite que a CNN construa uma hierarquia de conceitos
conceitos mais abstratos são baseados em conceitos mais simples (consulte o Capítulo 1).).
A quinta e última ideia é a presença de uma camada totalmente conectada no final de uma série de convolução e
agrupando camadas. A idéia é que a série de camadas de convolução e pool gera os recursos e uma
rede neural padrão aprende a função final de classificação / regressão. É importante distinguir este
aspecto da CNN do aprendizado de máquina tradicional. No aprendizado de máquina tradicional, um especialista entregaria
engenheiro de recursos e alimentá­los para uma rede neural. No caso das CNNs, essas características / representações são
sendo aprendido de dados.

Resumo
Neste capítulo, cobrimos o básico das CNNs. Os principais pontos de partida são a operação de convolução, a
operação de pooling, como eles são usados em conjunto e como os recursos não são projetados manualmente, mas 
aprendidos.
CNNs são a aplicação mais bem sucedida de aprendizagem profunda e incorporam a ideia de recursos de aprendizagem /
representações, em vez de manipulá­las manualmente.

Página 87
77
© Nikhil Ketkar 2017
N. Ketkar, Aprendizado Profundo com Python , DOI 10.1007 / 978­1­4842­2766­4_6

CAPÍTULO 6

Redes Neurais Recorrentes
Redes Neurais Recorrentes (RNNs), em essência, são redes neurais que empregam recorrência, que é
basicamente usando informações de um passe para frente anterior sobre a rede neural. Essencialmente, todos os RNN's
pode ser descrito como um relacionamento de recorrência. RNNs são adequados e têm sido incrivelmente bem sucedidos 
quando
aplicada a problemas em que os dados de entrada em que as previsões devem ser feitas é na forma de um
seqüência (série de entidades onde a ordem é importante).

Noções básicas de RNN
Vamos começar descrevendo as partes móveis de um RNN. Primeiro, introduzimos alguma notação.
1. Vamos supor que a entrada consiste em uma seqüência de entidades x (1) ,  x (2) ,…, x ( τ ) .
2. Correspondente a essa entrada, precisamos produzir uma seqüência y (1) ,  y (2) ,…, y ( τ )
ou apenas uma saída para toda a sequência de entrada y
3. Distinguir entre o que o RNN produz e o que é idealmente esperado
produzir iremos designar por y (1) , Y (2) , ..., y ( τ ) ou y a saída do RNN produz.
Note que isto é distinto do que o RNN deveria idealmente produzir, o que é
denotado por y (1) ,  y (2) , ..., y ( τ ) ou y .
Os RNNs produzem uma saída para cada entidade na seqüência de entrada ou produzem uma única saída para o
sequência inteira. Vamos considerar o caso em que um RNN produz uma saída para cada entidade na entrada.
O RNN pode ser descrito usando as seguintes equações:
h
Ux
Wh
b
t
t
t
()
()
­
()
=
+
+

(
)
tanh
1

y
softmax Vh
c
t
t
()
()
=
+

(
)
Os seguintes pontos sobre as equações RNN devem ser anotados:
1. O cálculo da RNN envolve primeiro o cálculo do estado oculto de uma entidade em
a sequência. Isso é denotado por h ( t ) .
2. O cálculo de h ( t ) usa a entrada correspondente na entidade x ( t ) ea
estado oculto anterior h t ­
() 1 .

3. A saída y ( t ) é calculada utilizando o estado escondido h ( t ) .
4. Existem pesos associados à entrada e ao estado oculto anterior enquanto
computando o estado oculto atual. Isso é denotado por U e W, respectivamente.
Existe também um termo de tendência denotado por b .

Página 88
CAPÍTULO 6 ■ REDES NEURAIS RECORRENTES
78
5. Existem pesos associados ao estado oculto durante o cálculo da saída;
este é designado por V . Existe também um termo de polarização, que é denotado por c .
6. A função de ativação do tanh (introduzida nos capítulos anteriores) é usada no
computação do estado oculto.
7. A função de ativação softmax é usada no cálculo da saída.
8. O RNN, conforme descrito pelas equações, pode processar uma sequência de entrada arbitrariamente grande.
9. Os parâmetros do RNN, ou seja, U , W , V , b , c , etc. são compartilhados através da computação
da camada oculta e valor de saída (para cada uma das entidades na sequência).
A Figura  6­1 ilustra um RNN. Observe como a ilustração mostra a relação de recorrência com o auto­loop
no estado oculto.
Figura 6­1. RNN (Recorrência usando o estado oculto anterior)

Page 89
CAPÍTULO 6 ■ REDES NEURAIS RECORRENTES
79
A figura também descreve uma função de perda associada a cada saída associada a cada entrada. Nós vamos
Consulte novamente quando abordarmos como as RNNs são treinadas.
Atualmente, é essencial internalizar como um RNN é diferente de todas as redes neurais feedforward
(incluindo redes de convolução) que vimos anteriormente. A principal diferença é o estado oculto, que
representa um resumo das entidades vistas no passado (para a mesma sequência).
Ignorando por enquanto como os RNNs são treinados, deve ficar claro para o leitor como um RNN treinado
poderia ser usado. Para uma determinada sequência de entradas, um RNN produziria uma saída para cada entidade na 
entrada.
Vamos agora considerar uma variação no RNN em que, em vez da recorrência usando o estado oculto, nós
ter recorrência usando a saída produzida no estado anterior (consulte Figura 6­2).
Figura 6­2. RNN (recorrência usando a saída anterior)

Página 90
CAPÍTULO 6 ■ REDES NEURAIS RECORRENTES
80
As equações que descrevem tal RNN são as seguintes:
h =
Ux + W
t
t
t
()
()

tanh (
ˆ
)
(
)

y
b
­

+
1
y
softmax Vh
c
t
t
()
()
=
+

(
)
Os seguintes pontos devem ser observados:
1. O cálculo da RNN envolve primeiro o cálculo do estado oculto de uma entidade em
a sequência. Isso é denotado por h ( t ) .
2. O cálculo de h ( t ) usa a entrada correspondente na entidade x ( t ) ea
saída anterior y t ­
() 1 .

3. A saída y ( t ) é calculada utilizando o estado escondido h ( t ) .
4. Existem pesos associados à entrada e à saída anterior enquanto
computando o estado oculto atual. Isso é denotado por U e W, respectivamente.
Existe também um termo de polarização denotado por c .
5. Existem pesos associados ao estado oculto durante o cálculo da saída;
este é designado por V . Existe também um termo de polarização, que é denotado por c .
6. A função de ativação do tanh (introduzida nos capítulos anteriores) é usada no
computação do estado oculto.
A função de ativação softmax é usada no cálculo da saída.
Vamos agora considerar uma variação no RNN, onde apenas uma única saída é produzida para o todo
sequência (consulte a Figura  6­3 ). Tal RNN é descrito usando as seguintes equações:
h =
Ux + W
t
t
t
()
()

tanh (
ˆ
)
(
)

y
b
­

+
1

Y softmax Vh
c
=
+

(
)
() t

Página 91
CAPÍTULO 6 ■ REDES NEURAIS RECORRENTES
81
Figura 6­3. RNN (Produzindo uma única saída para toda a sequência de entrada)

Page 92
CAPÍTULO 6 ■ REDES NEURAIS RECORRENTES
82
Os seguintes pontos devem ser observados:
1. O cálculo da RNN envolve o cálculo do estado oculto de uma entidade no
seqüência. Isso é denotado por h ( t ) .
2. O cálculo de h ( t ) usa a entrada correspondente na entidade x ( t ) ea
estado oculto anterior h t ­
() 1 .

3. O cálculo de h ( t ) é feito para cada entidade na sequência de entrada
x (1) ,  x (2) ,…, x ( τ ) .
4. A saída y é calculado usando apenas o último escondido estado h ( τ ) .
5. Existem pesos associados à entrada e ao estado oculto anterior enquanto
computando o estado oculto atual. Isso é denotado por U e W, respectivamente.
Existe também um termo de tendência denotado por b .
6. Existem pesos associados ao estado oculto durante o cálculo da saída;
este é designado por V . Existe também um termo de polarização, que é denotado por c .
7. A função de ativação do tanh (introduzida nos capítulos anteriores) é usada no
computação do estado oculto.
8. A função de ativação softmax é usada no cálculo da saída.

RNNs de treinamento
Vamos agora ver como as RNNS são treinadas. Para fazer isso, primeiro precisamos olhar como a RNN parece quando
desenrolar a relação de recorrência que está no coração do RNN.

Página 93
CAPÍTULO 6 ■ REDES NEURAIS RECORRENTES
83
Figura 6­4. Desenrolando o RNN correspondente à Figura 6­1
Desenrolar a relação de recorrência correspondente a RNN é simplesmente escrever as equações de forma recursiva
substituindo o valor no qual a relação de recorrência é definida. No caso do RNN na Figura  6­1, este
é h ( t ) . Ou seja, o valor de h ( t ) é definido em termos de h t ­
() 1 , que por sua vez é definido em termos de h t ­
() 2
e
assim por diante até h (0) .

Página 94
CAPÍTULO 6 ■ REDES NEURAIS RECORRENTES
84
Figura 6­5. Desenrolando o RNN correspondente à Figura  6­2

Página 95
CAPÍTULO 6 ■ REDES NEURAIS RECORRENTES
85
Figura 6­6. Desenrolando o RNN correspondente à Figura  6­3
Vamos supor que h (0) seja predefinido pelo usuário, definido como zero ou aprendido como outro parâmetro /
peso (aprendido como W , V ou b ). Desenrolamento significa simplesmente escrever as equações que descrevem o RNN em
termos de h (0) . Claro que, para fazer isso, precisamos fixar o comprimento da seqüência, que é denotada por τ .
Figura 6­4 ilustra o RNN desenrolado correspondente ao RNN na figura 6­1 assumindo uma sequência de entrada
de tamanho 4. Da mesma forma, figura 6­5 e  6­6 ilustram os RNNs desenrolados correspondentes aos RNNs na Figura   6­2
e 6­3 respectivamente. Os seguintes pontos devem ser observados:
1. O processo de desenrolamento opera no pressuposto de que o comprimento da entrada
sequência é conhecida de antemão e com base na recorrência é desenrolada.
2. Uma vez desenrolados, temos essencialmente uma rede neural não recorrente.

Página 96
CAPÍTULO 6 ■ REDES NEURAIS RECORRENTES
86
3. Os parâmetros a serem aprendidos, ou seja, U , W , V , b , c , etc. (denotado no escuro no
diagrama) são compartilhados através do cálculo da camada oculta e da saída
valor. Já vimos esse compartilhamento de parâmetros no contexto das CNNs.
4. Dada uma entrada e saída de um determinado tamanho, digamos τ (assumido como sendo 4 nas Figuras  6­4 ,
6­5, 6­6
    ), podemos desenrolar um RNN e calcular gradientes para os parâmetros a serem
Aprendemos com relação a uma função de perda (como vimos nos capítulos anteriores).
5. Assim, treinar um RNN é simplesmente desenrolando o RNN para um dado tamanho de entrada
(e, correspondentemente, a saída esperada) e treinar o RNN não processado via
calcular os gradientes e usar a descida de gradiente estocástica.
Como mencionado anteriormente no capítulo, os RNNs podem lidar com entradas arbitrariamente longas e, 
correspondentemente,
eles precisam ser treinados em entradas arbitrariamente longas. Figura 6­7 ilustra como um RNN é desenrolado para 
diferentes
tamanhos de entradas. Note que uma vez que o RNN é desenrolado, o processo de treinamento do RNN é idêntico ao 
treinamento
uma rede neural regular que cobrimos nos capítulos anteriores. Na figura 6­7 o RNN descrito em
Figura 6­1 é desenrolado para tamanhos de entrada de 1,2,3 e 4.

Página 97
CAPÍTULO 6 ■ REDES NEURAIS RECORRENTES
87
Figura 6­7. Desenrolar o RNN correspondente à Figura  6­1 para diferentes tamanhos de entradas

Página 98
CAPÍTULO 6 ■ REDES NEURAIS RECORRENTES
88
Figura 6­8. Forçagem de Professores (Superior ­ Treinamento, Parte Inferior ­ Previsão)
Dado que o conjunto de dados a ser treinado consiste em sequências de tamanhos variados, as sequências de entrada são
agrupados para que as seqüências do mesmo tamanho caiam em um grupo. Então, para um grupo, podemos desenrolar o 
RNN
para o comprimento da sequência e o trem. O treinamento para um grupo diferente exigirá que o RNN seja desenrolado para
um
comprimento de seqüência diferente. Assim, é possível treinar o RNN em insumos de tamanhos variados desenrolando e
treinamento com o desenrolar feito com base no comprimento da sequência.

Página 99
CAPÍTULO 6 ■ REDES NEURAIS RECORRENTES
89
Deve­se notar que o treinamento do RNN desenrolado (ilustrado na figura 6­1) é essencialmente um
processo, como os estados ocultos são dependentes uns dos outros. No caso dos RNNs em que a recorrência é
sobre a saída, em vez do estado oculto (Figura 6­2), é possível usar uma técnica chamada professor
forçando como ilustrado na figura 6­8. A ideia chave aqui é usar y t ­
() 1 em vez de y t ­

() 1 no cálculo de h ( t )

enquanto treinando. Ao fazer previsões (quando o modelo é implantado para uso), no entanto, y t ­
() 1 é usado.

RNNs bidirecionais
Vamos agora dar uma olhada em outra variação nos RNNs, ou seja, o RNN bidirecional. A intuição chave
por trás de um RNN bidirecional é usar as entidades que se encontram mais na seqüência para fazer uma previsão para o
entidade atual. Para todos os RNNs que consideramos até agora, temos usado as entidades anteriores (capturadas
pelo estado oculto) e a entidade atual na sequência para fazer a previsão. No entanto, não temos
tem usado informações sobre as entidades que ficam na seqüência para fazer previsões. UMA
O RNN bidirecional aproveita essas informações e pode fornecer precisão preditiva aprimorada em muitos casos.
Um RNN bidirecional pode ser descrito usando as seguintes equações:
h
U x
W h
b
f
t
f
t
f
t
f
()
()
+
()
=
+
+

(
)
tanh
1

h
U x
Wh
b
b
t
b
t
b
t
b
()
()
­
()
=
+
+

(
)
tanh
1

y
softmax V h
V h
c
t
b
b
t
f
f
t
()
()
()
=
+
+

(
)
Os seguintes pontos devem ser observados:
1. O cálculo RNN envolve primeiro o cálculo do estado oculto para a frente e
estado oculto para trás para uma entidade na sequência. Isso é denotado por h f
( t ) e

h b
( t ) respectivamente.

2. O cálculo de h f
( t ) usa a entrada correspondente na entidade x ( t ) ea

estado oculto anterior h f
t ­
() 1 .

3. O cálculo de h b
( t ) usa a entrada correspondente na entidade x ( t ) ea

estado oculto anterior h b
t ­

() 1 .

4. A saída y ( t ) é calculada utilizando o estado escondido h f
( T ) e H b
( t )

5. Existem pesos associados à entrada e ao estado oculto anterior
enquanto calcula o estado oculto atual. Isso é denotado por U f , W f , U b e W b
respectivamente. Há também um termo de polarização indicada por b f e b b .
6. Existem pesos associados ao estado oculto durante o cálculo da saída;
isso é denotado por V b e V f . Existe também um termo de polarização, que é denotado por c .
7. A função de ativação do tanh (introduzida nos capítulos anteriores) é usada no
computação do estado oculto.
8. A função de ativação softmax é usada no cálculo da saída.
9. O RNN, conforme descrito pelas equações, pode processar uma sequência de entrada arbitrariamente grande.
10. Os parâmetros do RNN, ou seja, U f ,  U b ,  W f , W b ,  V b ,  V f ,  b f ,  b b ,  c , etc. são compartilhados
através do cálculo da camada oculta e valor de saída (para cada um dos
entidades na sequência).

Página 100
CAPÍTULO 6 ■ REDES NEURAIS RECORRENTES
90
Figura 6­9. RNN bidirecional

Explosão de gradiente e desaparecimento
Treinamento RNNs sofre com os desafios de desaparecimento e explosão de gradientes. Gradientes de fuga
significa que, ao calcular os gradientes nos RNNs desenrolados, o valor dos gradientes pode cair para um
valor muito pequeno (próximo de zero). Da mesma forma, os gradientes podem aumentar para um valor muito alto que é 
referido
como o problema gradiente explosivo. Em ambos os casos, treinar o RNN é um desafio.

Página 101
CAPÍTULO 6 ■ REDES NEURAIS RECORRENTES
91
Vamos reler as equações que descrevem o RNN.
h
Ux
Wh
b
t
t
t
()
()
­
()
=
+
+

(
)
tanh
1

y
softmax Vh
c
t
t
()
()
=
+

(
)
Vamos derivar a expressão para o


eu
W
aplicando a regra da cadeia. Isso é ilustrado na figura 6­10 .


=




é
ë
ê
você
você
você

£ £
()
()
£ £
£ £ ­
+
()
()
()

uma
å Õ
eu
W
eu
h
h
h
h
t
t
t
ktkjt
j
j
k
1
1
1
1
t


é
ë
ê
ê
você
você
você
você
W
Vamos nos concentrar agora na parte da expressão
kjt
j
j

h
h
£ £ ­
+
()
()

Õ


1
1

que envolve uma matriz repetida
multiplicação de W que contribui para ambos os problemas de gradiente de desaparecimento e explosão. Intuitivamente
isso é semelhante a multiplicar um número real valorizado repetidas vezes, o que pode levar ao produto
encolhendo para zero ou explodindo para o infinito.

Recorte de gradiente
Uma técnica simples para lidar com gradientes explosivos é redimensionar a norma do gradiente sempre que for
sobre um limite definido pelo usuário. Especificamente, se o gradiente indicado por g
eu
W
=


e se g c
> então vamos definir ˆ
ˆ
ˆ.
g
c
g
g
=
Essa técnica é simples e computacionalmente eficiente, mas introduz um hiperparâmetro extra.

Página 102
CAPÍTULO 6 ■ REDES NEURAIS RECORRENTES
92
Figura 6­10. Gradientes de Desaparecimento e Explosão

Página 103
CAPÍTULO 6 ■ REDES NEURAIS RECORRENTES
93

Memória de Longo Prazo
Vamos agora dar uma olhada em outra variação em RNNs, ou seja, a Long Short Term Memory (LSTM)
Rede. Um LSTM pode ser descrito com o seguinte conjunto de equações. Note que o símbolo ⊙. notas
multiplicação pontual de dois vetores (se a = []
112,, eb = [
]
050505
. . .
,
então ab
⊙ = [
]
05051
. ., , , a
funções σ , g e h são funções de ativação não lineares, todas W e R são matrizes de peso e todos os termos b
são termos de viés).
z
g L x
R y
b
t
z
t
z
t
z
()
()
­
()
=
+
+

(
)
1

Eu
Wx
R y
p
c
b
t
Eu
t
Eu
t
Eu
t
Eu
()
()
­
()
­
()
=
+
+
+

(
)
s
1
1


f
W x R y
p
c
b
t
f
t
f
t
f
t
f
()
­
()
­
()
=
+
+
+

(
)
s
1
1


c
Eu
z
f
c
t
t
t
t
t
()
()
()
()
­
()
=
+


1

o
Wx
R y
p
c
b
t
o
t
o
t
o
t
o
()
()
­
()
()
=
+
+
+

(
)
s
1


y
o
hc
t
t
t
()
()
()
=

()

Os seguintes pontos devem ser observados:
1. O elemento mais importante do LSTM é o estado da célula denotado por
c
Eu
z
f
c
t
t
t
t
t
()
()
()
()
­
()
=
+


1 . O estado da célula é atualizado com base na entrada do bloco z ( t )

e o estado da célula anterior c t ­
() 1 . A porta de entrada i ( t ) determina qual fração do

entrada de bloco faz com que ele entre no estado da célula (daí chamado de gate). O portão do esquecimento f ( t )
determina quanto do estado anterior da célula reter.
2. A saída y ( t ) é determinada com base no estado celular c ( t ) e a porta de saída S ( t ) ,
que determina quanto o estado da célula afeta a saída.
3. O termo z ( t ) é referido como entrada de bloco e produz um valor baseado na
entrada atual e a saída anterior.
4. O termo i ( t ) é chamado de porta de entrada. Determina quanto da entrada
reter no estado da célula c ( t ) .
5. Todos os termos p são conexões peephole, que permitem uma facção da célula
Estado a incorporar no cálculo do termo em questão.
6. O cálculo do estado da célula c ( i ) não encontra a questão do
gradiente de desaparecimento (isto é referido como a constante de erro de carrossel). Contudo,
LSTMs são afetados por gradientes de explosão e o recorte de gradiente é usado
Treinamento.

Página 104
CAPÍTULO 6 ■ REDES NEURAIS RECORRENTES
94

Resumo
Neste capítulo, cobrimos os conceitos básicos de Redes Neurais Recorrentes (RNN). Os principais pontos para levar para 
casa
este capítulo é a noção do estado oculto, treinando RNNs via desenrolamento (backpropagation through time),
o problema de gradientes de desaparecimento e explosão, e redes de memória de curto prazo. É importante
internalize como os RNNs contêm estados internos / ocultos que lhes permitem fazer previsões sobre uma sequência de
insumos, uma capacidade que vai além das redes neurais convencionais.
Figura 6­11. Memória de Longo Prazo

Página 105
95
© Nikhil Ketkar 2017
N. Ketkar, Aprendizado Profundo com Python , DOI 10.1007 / 978­1­4842­2766­4_7

CAPÍTULO 7

Introdução a Keras
Este capítulo apresenta o leitor a Keras, que é uma biblioteca que fornece recursos altamente poderosos e abstratos.
blocos de construção para construir redes de aprendizagem profunda. Os blocos de construção que Keras fornece são 
construídos usando Theano
(coberto anteriormente), bem como o TensorFlow (que é uma alternativa ao Theano para construir
gráficos, deriva gradientes automaticamente, etc.). Keras suporta computação de CPU e GPU e é um
ótima ferramenta para idéias de prototipagem rápida.
Vamos introduzir uma série de blocos de construção fundamentais que Keras fornece e, em seguida, construir um CNN e 
LSTM
usando Keras.
Vamos começar com uma rede neural de camada única simples. Listagem7­1 fornece o código e figura 7­1
dá o gráfico computacional. Os seguintes pontos devem ser observados:
1. Um modelo é definido usando a construção Sequencial, que permite ao usuário
adicionar / configurar camadas.
2. Usando essa funcionalidade, um usuário pode adicionar uma ou mais camadas e construir a rede.
A camada Densa é basicamente uma camada totalmente conectada (levando a uma matriz vetorial ou
vector vector­vector), o que vimos anteriormente.
3. A dimensionalidade de entrada e saída precisa ser especificada quando a primeira camada
é definido. Neste caso, o modelo terá uma entrada de dimensionalidade 500 e
produzir uma saída de dimensionalidade 1.
4. Após esta camada, adicionamos uma função de ativação, neste caso um sigmoide.
5. O modelo, uma vez definido, precisa ser explicitamente compilado e, neste momento,
fornecer a função de perda, o algoritmo de otimização e outras métricas que queremos
calcular.
6. Uma função de perda apropriada precisa ser escolhida, dada a tarefa em mãos; nisso
caso, dado que temos um problema de classificação binária, selecionamos
entropia cruzada.
7. Um algoritmo de otimização apropriado precisa ser escolhido, o que normalmente é
variante de descida de gradiente estocástico (encurtado em capítulos posteriores).
8. Uma vez compilado, podemos ajustar o modelo fornecendo os dados e avaliando o modelo.

Página 106
CAPÍTULO 7 ■ INTRODUÇÃO AO KERAS
96
Listagem 7­1. Rede Neural de Camada Única
import numpy como np
de keras.models import Sequential
de keras.layers import Densa, Ativação
do lote de importação keras.utils.visualize_util
model = Sequential ()
model.add (Dense (1, input_dim = 500))
model.add (Ativação (ativação = 'sigmoid'))
model.compile (optimizer = 'rmsprop', loss = 'binary_crossentropy', métricas = ['precisão'])
dados = np.random.random ((1000, 500))
labels = np.random.randint (2, size = (1000, 1))
score = model.evaluate (dados, rótulos, verbose = 0)
print "Antes do treino:", zip (model.metrics_names, score)
model.fit (dados, rótulos, nb_epoch = 10, batch_size = 32, verbose = 0)
score = model.evaluate (dados, rótulos, verbose = 0)
print "Depois do treino:", zip (model.metrics_names, score)
plot (model, to_file = 's1.png', show_shapes = True)
# Antes do treino: [('loss', 0.76832762384414677), ('acc', 0.50700000000000001)]
# Após o treino: [('loss', 0,67270196056365972), ('acc', 0,56299999999999994)]
Figura 7­1. Rede Neural de Camada Única (Classificação Binária)

Página 107
CAPÍTULO 7 ■ INTRODUÇÃO AO KERAS
97
Listagem 7­2. Rede Neural de Duas Camadas
import numpy como np
de keras.models import Sequential
de keras.layers import Densa, Ativação
do lote de importação keras.utils.visualize_util
model = Sequential ()
model.add (Dense (32, input_dim = 500))
model.add (Ativação (ativação = 'sigmoid'))
model.add (denso (1))
model.add (Ativação (ativação = 'sigmoid'))
model.compile (optimizer = 'rmsprop', loss = 'binary_crossentropy', métricas = ['precisão'])
dados = np.random.random ((1000, 500))
labels = np.random.randint (2, size = (1000, 1))
score = model.evaluate (dados, rótulos, verbose = 0)
print "Antes do treino:", zip (model.metrics_names, score)
model.fit (dados, rótulos, nb_epoch = 10, batch_size = 32, verbose = 0)
score = model.evaluate (dados, rótulos, verbose = 0)
print "Depois do treino:", zip (model.metrics_names, score)
enredo (modelo, to_file = 's2.png', show_shapes = True)
# Antes do treino: [('loss', 0.73012506151199341), ('acc', 0.51200000000000001)]
# Após o treino: [('loss', 0,6588478517532349), ('acc', 0,52700000000000002)]
Vamos agora olhar para uma rede neural de duas camadas. Listagem7­2 fornece o código e figura 7­2 dá a
gráfico computacional. Os seguintes pontos devem ser observados:
1. Um modelo é definido usando a construção Sequencial.
2. Adicionamos a primeira camada usando Dense e especificamos a dimensionalidade de entrada. Nisso
Caso o modelo terá uma entrada de dimensionalidade 500 e produzir uma saída de
dimensionalidade 32.
3. Definimos uma função de ativação, selecionando sigmoid.
4. Em seguida, definimos a segunda camada usando Dense. Aqui nós definimos a saída
dimensionalidade seja 1. Note, no entanto, que não precisamos definir a entrada
dimensionalidade, como é o mesmo que a dimensionalidade da saída do
camada anterior.
5. Como antes, definimos a função otimizar e perder, compilar, treinar e avaliar.

Página 108
CAPÍTULO 7 ■ INTRODUÇÃO AO KERAS
98
Figura 7­2. Rede Neural de Dupla Camada (Classificação Binária)
Vamos agora olhar para uma rede neural de duas camadas para classificação multiclasse. Listagem 7­3 fornece o código
e figura 7­3 fornece o gráfico computacional. Os seguintes pontos devem ser observados:
1. Um modelo é definido usando a construção Sequencial.
2. Adicionamos a primeira camada usando Dense e especificamos a dimensionalidade de entrada. Nisso
Caso o modelo terá uma entrada de dimensionalidade 500 e produzir uma saída de
dimensionalidade 32.
3. Definimos uma função de ativação, selecionando sigmoid.
4. Em seguida, definimos a segunda camada usando Dense. Aqui nós definimos a saída
dimensionalidade para ser 10. Note que isso é exatamente igual ao número de classes
temos em nosso conjunto de dados.
5. Em seguida, usamos a ativação softmax e a entropia categórica como a perda
função (um capítulo anterior explica porque esta é uma boa escolha).
6. Nós compilamos, treinamos e avaliamos o modelo como antes.

Página 109
CAPÍTULO 7 ■ INTRODUÇÃO AO KERAS
99
Listagem 7­3. Classificação Multiclass
import numpy como np
de keras.models import Sequential
de keras.layers import Densa, Ativação
de keras.utils.np_utils import to_categorical
do lote de importação keras.utils.visualize_util
model = Sequential ()
model.add (Dense (32, input_dim = 500))
model.add (Ativação (ativação = 'relu'))
model.add (denso (10))
model.add (Ativação (ativação = 'softmax'))
model.compile (optimizer = 'rmsprop', perda = 'categorical_crossentropy', métricas = ['categorical_
precisão'])
dados = np.random.random ((1000, 500))
labels = to_categorical (np.random.randint (10, size = (1000, 1)))
score = model.evaluate (dados, rótulos, verbose = 0)
print "Antes do treino:", zip (model.metrics_names, score)
model.fit (dados, rótulos, nb_epoch = 10, batch_size = 32, verbose = 0)
score = model.evaluate (dados, rótulos, verbose = 0)
print "Depois do treino:", zip (model.metrics_names, score)
plot (model, to_file = 's3.png', show_shapes = True)
# Before Training: [('loss', 2.4697211952209472), ('categorical_accuracy',
0,092999999999999999]
# After Training: [('loss', 2.1891849689483642), ('categorical_accuracy',
0,19400000000000001)]

Página 110
CAPÍTULO 7 ■ INTRODUÇÃO AO KERAS
100
Vamos agora olhar para uma rede neural de duas camadas para regressão. A Listagem 7­4 fornece o código e a Figura  7­4
dá o gráfico computacional. Os seguintes pontos devem ser observados:
1. Um modelo é definido usando a construção Sequencial.
2. Adicionamos a primeira camada usando Dense e especificamos a dimensionalidade de entrada. Nisso
Caso o modelo terá uma entrada de dimensionalidade 500 e produzir uma saída de
dimensionalidade 32.
3. Definimos uma função de ativação, selecionando sigmoid.
4. Em seguida, definimos a segunda camada usando Dense, produzindo uma saída de
dimensionalidade 1.
5. Selecionamos a ativação como sigmóide e selecionamos o erro quadrático médio, que é
apropriado para a regressão.
6. Nós compilamos, treinamos e avaliamos o modelo.
Figura 7­3. Classificação Multiclass

Página 111
CAPÍTULO 7 ■ INTRODUÇÃO AO KERAS
101
Listagem 7­4. Regressão
import numpy como np
de keras.models import Sequential
de keras.layers import Densa, Ativação
do lote de importação keras.utils.visualize_util
model = Sequential ()
model.add (Dense (32, input_dim = 500))
model.add (Ativação (ativação = 'sigmoid'))
model.add (denso (1))
model.add (Ativação (ativação = 'sigmoid'))
model.compile (optimizer = 'rmsprop', loss = 'mse', métricas = ['mean_squared_error'])
dados = np.random.random ((1000, 500))
labels = np.random.randint (2, size = (1000, 1))
score = model.evaluate (dados, rótulos, verbose = 0)
print "Antes do treino:", zip (model.metrics_names, score)
model.fit (dados, rótulos, nb_epoch = 10, batch_size = 32, verbose = 0)
score = model.evaluate (dados, rótulos, verbose = 0)
print "Depois do treino:", zip (model.metrics_names, score)
plot (model, to_file = 's4.png', show_shapes = True)
# Before Training: [('loss', 0.26870122766494753), ('mean_squared_error',
0,26870122766494753)]
# After Training: [('loss', 0.22180086207389832), ('mean_squared_error',
0,22180086207389832)]
Vamos agora fazer uma pausa e ver como Keras permite uma iteração rápida de ideias.
1. Novos modelos podem ser rapidamente definidos, treinados e avaliados usando o
construir.
2. Os parâmetros da dimensionalidade de entrada / saída das camadas podem ser facilmente modificados.
3. Podemos comparar várias opções de funções de ativação facilmente. Listagem 7­6
ilustra como podemos comparar os efeitos das funções de ativação.
4. Podemos comparar várias opções de algoritmos de otimização facilmente. Listagem7­5
ilustra como podemos comparar os efeitos de diferentes opções de ativação
algoritmos.

Página 112
CAPÍTULO 7 ■ INTRODUÇÃO AO KERAS
102
Listagem 7­5. Otimizadores
import numpy como np
de keras.models import Sequential
de keras.layers import Densa, Ativação
def train_given_optimiser (otimizador):
model = Sequential ()
model.add (Dense (1, input_dim = 500))
model.add (Ativação (ativação = 'sigmoid'))
model.compile (otimizador = otimizador, perda = 'binary_crossentropy', métricas = ['precisão'])
dados = np.random.random ((1000, 500))
labels = np.random.randint (2, size = (1000, 1))
score = model.evaluate (dados, rótulos, verbose = 0)
imprimir "Otimizador:", otimizador
print "Antes do treino:", zip (model.metrics_names, score)
Figura 7­4. Regressão

Página 113
CAPÍTULO 7 ■ INTRODUÇÃO AO KERAS
103
model.fit (dados, rótulos, nb_epoch = 10, batch_size = 32, verbose = 0)
score = model.evaluate (dados, rótulos, verbose = 0)
print "Depois do treino:", zip (model.metrics_names, score)
train_given_optimiser ("sgd")
train_given_optimiser ("rmsprop")
train_given_optimiser ("adagrad")
train_given_optimiser ("adadelta")
train_given_optimiser ("adam")
train_given_optimiser ("adamax")
train_given_optimiser ("nadam")
# Optimizer: sgd
# Antes do treino: [('loss', 0.76416229248046874), ('acc', 0.51800000000000002)]
# Após o treino: [('loss', 0.6759231286048889), ('acc', 0.56899999999999995)]
# Optimizer: rmsprop
# Antes do treino: [('loss', 0.77773557662963866), ('acc', 0.52600000000000002)]
# Após o treino: [('loss', 0.727150842666626), ('acc', 0.53500000000000003)]
# Optimizer: adagrad
# Before Training: [('loss', 0,9275067367553711), ('acc', 0,49099999999999999)]
# Após o treino: [('loss', 0,66770141410827633), ('acc', 0,57599999999999996)]
# Optimiser: adadelta
# Antes do treino: [('loss', 0.76523585319519039), ('acc', 0,48799999999999999)]
# Após o treino: [('loss', 0.70753741836547857), ('acc', 0.51700000000000002)]
# Optimizer: adam
# Antes do treino: [('loss', 0.76974405097961429), ('acc', 0.51100000000000001)]
# Após o treino: [('loss', 0,66079518222808842), ('acc', 0,59399999999999997)]
# Optimizer: adamax
# Antes do treino: [('loss', 0.76244759178161625), ('acc', 0.49399999999999999)]
# Após o treino: [('loss', 0,67273861455917361), ('acc', 0,58499999999999996)]
# Otimizador: nadam
# Antes do treino: [('loss', 0.71690645027160649), ('acc', 0.50600000000000001)]
# Após o treino: [('loss', 0,62006913089752203), ('acc', 0,68799999999999994)]
Keras implementa uma série de otimizadores, a saber, o Stocastic Gradient Descent (SGD), o RMSProp,
AdaGrad, AdataDelta, Adam, Adamax e Nadam. O Capítulo 8 abrange estes (SGD e suas variantes) em muito
detalhe, explicando a intuição para cada um. Para o contexto deste capítulo, basta dizer que Keras o faz
É fácil para os usuários experimentarem esses otimizadores com muito pouco esforço de codificação.
Listagem 7­6. Funções de Ativação
import numpy como np
de keras.models import Sequential
de keras.layers import Densa, Ativação
def train_given_activation (ativação):
model = Sequential ()
model.add (Dense (1, input_dim = 500))
model.add (Ativação (ativação = ativação))
model.compile (optimizer = "sgd", loss = 'binary_crossentropy', métricas = ['precisão'])

Página 114
CAPÍTULO 7 ■ INTRODUÇÃO AO KERAS
104
dados = np.random.random ((1000, 500))
labels = np.random.randint (2, size = (1000, 1))
score = model.evaluate (dados, rótulos, verbose = 0)
print "Ativação:", ativação
print "Antes do treino:", zip (model.metrics_names, score)
model.fit (dados, rótulos, nb_epoch = 10, batch_size = 32, verbose = 0)
score = model.evaluate (dados, rótulos, verbose = 0)
print "Depois do treino:", zip (model.metrics_names, score)
train_given_activation ("relu")
train_given_activation ("tanh")
train_given_activation ("sigmoid")
train_given_activation ("hard_sigmoid")
train_given_activation ("linear")
# Ativação: relu
# Before Training: [('loss', 2.6973885402679443), ('acc', 0.48899999999999999)]
# Após o treino: [('loss', 7.7373054656982418), ('acc', 0.505)]
# Ativação: tanh
# Antes do treino: [('loss', 5.0640698051452633), ('acc', 0.41699999999999998)]
# Após o treino: [('loss', 7.6523446731567386), ('acc', 0.52000000000000002)]
# Ativação: sigmóide
# Antes do treino: [('loss', 0.70816111516952518), ('acc', 0.52500000000000002)]
# Após o treino: [('loss', 0.67464308834075926), ('acc', 0.58199999999999996)]
# Ativação: hard_sigmoid
# Antes do treino: [('loss', 0.70220352411270137), ('acc', 0.52100000000000002)]
# Após o treino: [('loss', 0,67294596910476689), ('acc', 0,58099999999999996)]
# Ativação: linear
# Antes do treino: [('loss', 3.5439299507141113), ('acc', 0.47799999999999998)]
# Após o treino: [('loss', 8.2581552581787108), ('acc', 0.0)]
Keras implementa um número de funções de ativação, a saber, tanh, sigmoid, hard_sigmoid, linear,
e relu (unidade linear retificada). Funções de ativação e sua adequação dada uma tarefa (classificação,
multiclassificação, regressão, etc.) são abordados com muito detalhe no Capítulo 3 . Para o contexto deste capítulo,
basta dizer que o Keras torna mais fácil para os usuários experimentarem essas funções de ativação
pequeno esforço de codificação.
Vamos agora olhar para as construções que Keras fornece para construir as Redes Neurais de Convolução introduzidas
no capítulo 5. O conjunto de dados que usaremos é o conjunto de dados MNIST, que é um dado de referência comumente 
usado
definido para aprendizagem profunda. O conjunto de dados consiste em dígitos manuscritos (60.000 exemplos de 
treinamento e 10.000 testes
exemplos). A tarefa é prever o dígito dado a imagem, então este é um problema de multiclassificação
com dez classes.
Listagem 7­7. CNN
import numpy como np
de keras.datasets import mnist
de keras.models import Sequential
de keras.layers import Dense, Dropout, Ativação, Flatten
de keras.layers import Convolution2D, MaxPooling2D

Página 115
CAPÍTULO 7 ■ INTRODUÇÃO AO KERAS
105
de keras.utils import np_utils
do lote de importação keras.utils.visualize_util
# Tamanho da imagem
img_rows, img_cols = 28, 28
# Filter
nb_filters = 32
# Pooling
pool_size = (2, 2)
# Núcleo
kernel_size = (3, 3)
# Prepare o conjunto de dados
(X_train, y_train), (X_test, y_test) = mnist.load_data ()
X_train = X_train.reshape (X_train.shape [0], img_rows, img_cols, 1)
X_test = X_test.reshape (X_test.shape [0], img_rows, img_cols, 1)
input_shape = (img_rows, img_cols, 1)
X_train = X_train.astype ('float32')
X_test = X_test.astype ('float32')
X_train / = 255
X_test / = 255
nb_classes = 10
Y_train = np_utils.to_categorical (y_train, nb_classes)
Y_test = np_utils.to_categorical (y_test, nb_classes)
# CNN
model = Sequential ()
model.add (Convolution2D (nb_filters, kernel_size [0], kernel_size [1], border_mode = 'válido',
input_shape = input_shape))
model.add (Ativação ('relu'))
model.add (Convolution2D (nb_filters, kernel_size [0], kernel_size [1]))
model.add (Ativação ('relu'))
model.add (MaxPooling2D (pool_size = pool_size))
model.add (Rejeição (0,25))
model.add (Flatten ())
model.add (denso (128))
model.add (Ativação ('relu'))
model.add (Rejeição (0.5))
model.add (Dense (nb_classes))
model.add (Ativação ('softmax'))
# Compilação
model.compile (loss = 'categorical_crossentropy', optimizer = 'adadelta', métricas = ['precisão'])
# Treinamento
batch_size = 128
nb_epoch = 1
model.fit (X_train, Y_train, batch_size = batch_size, nb_epoch = nb_epoch, verbose = 1, validação_
data = (X_test, Y_test))

Página 116
CAPÍTULO 7 ■ INTRODUÇÃO AO KERAS
106
# Avaliação
score = model.evaluate (X_test, Y_test, verbose = 0)
print "Test Metrics:", zip (model.metrics_names, score)
enredo (modelo, to_file = 's7.png', show_shapes = True)
# Saída
# Treinar em 60000 amostras, validar em 10000 amostras
# Época 1/1
# 60000/60000 [==============================] ­ 128s ­ perda: 0,3964 ­ acc: 0,8776 ­ val_
perda: 0,0929 ­ val_acc: 0,9712
# Test Metrics: [('loss', 0.092853568810969594), ('acc', 0.97119999999999995)]
Figura 7­5. CNN

Página 117
CAPÍTULO 7 ■ INTRODUÇÃO AO KERAS
107
A Listagem 7­7 apresenta o código fonte para a rede neural de convolução e figura 7­5 ilustra o
gráfico de computação. Os seguintes pontos devem ser observados:
1. A rede global consiste em dois blocos de detectores de convolução, seguidos por
uma camada de pool máximo que, por sua vez, é seguida por duas camadas totalmente conectadas
rede (consulte o capítulo 5 ).
2. O tamanho do kernel é 3 × 3.
3. A operação de pooling é feita sobre seções de dimensionalidade 2 × 2.
4. Há um número de camadas de abandono, que são basicamente uma forma de
regularização (consulte o Capítulo 1) e operar ao desligar aleatoriamente um certo
número de unidades. O parâmetro 0.25 indica a facção de entradas que serão
caiu aleatoriamente.
5. As camadas planas convertem a entrada de qualquer dimensionalidade em uma dimensionalidade
de 1 × n . Então, por exemplo, uma entrada de dimensionalidade 2 × 2 × 3 é convertida em um
direcionalidade de 1 × 12.
6. A camada de saída é softmax e a função de perda é entropia categórica, como é
apropriado para um problema de multiclassificação (consulte o Capítulo 3).
7. O modelo é adequado usando adadelta (consulte o Capítulo 8 ) e, para fins de
ilustração, definimos as épocas como 1 (idealmente, é definido como muito mais do que isso).
Listagem 7­8 LSTM
import numpy como np
da sequência de importação keras.preprocessing
de keras.utils import np_utils
de keras.models import Sequential
de keras.layers import Densa, Saída, Ativação, Incorporação
de keras.layers importar LSTM
de keras.datasets import imdb
do lote de importação keras.utils.visualize_util
max_features = 20000
maxlen = 80
batch_size = 32
# Prepare o conjunto de dados
(X_train, y_train), (X_test, y_test) = imdb.load_data (nb_words = max_features)
X_train = sequence.pad_sequences (X_train, maxlen = maxlen)
X_test = sequence.pad_sequences (X_test, maxlen = maxlen)
# LSTM
model = Sequential ()
model.add (Incorporação (max_features, 128, dropout = 0.2))
model.add (LSTM (128, dropout_W = 0.2, dropout_U = 0.2))
model.add (denso (1))
model.add (Ativação ('sigmoid'))
# Compile
model.compile (loss = 'binary_crossentropy', optimizer = 'adam', métricas = ['precisão'])

Página 118
CAPÍTULO 7 ■ INTRODUÇÃO AO KERAS
108
# Treinamento
model.fit (X_train, y_train, batch_size = batch_size, detalhado = 1, nb_epoch = 1, validation_
data = (X_test, y_test))
# Evalaution
score = model.evaluate (X_test, y_test, batch_size = batch_size)
print "Test Metrics:", zip (model.metrics_names, score)
plot (model, to_file = 's8.png', show_shapes = True)
# Saída
# Treinar em 25.000 amostras, validar em 25.000 amostras
# Época 1/1
# 25000/25000 [==============================] ­ 165s ­ perda: 0,5286 ­ acc: 0,7347 ­ val_
perda: 0,4391 ­ val_acc: 0,8076
# 25000/25000 [==============================] ­ 33s
# Test Metrics: [('loss', 0,43908300422668456), ('acc', 0,80759999999999998)]
Figura 7­6. LSTM

Page 119
CAPÍTULO 7 ■ INTRODUÇÃO AO KERAS
109
Vamos agora olhar para o construto Keras fornece para construir redes LSTM, introduzidas no Capítulo 6 (consulte
para listar 7­8 e Figura   7­6 ). O conjunto de dados que usaremos é do IMDB e representa 25.000 avaliações de
IMDD categorizado como positivo ou negativo, tornando este um problema de classificação de seqüência binária. Os dados
é pré­processado para conter apenas palavras frequentes (as palavras são, na verdade, representadas como números 
inteiros). Listagem7­8
apresenta o código fonte e figura 7­6 ilustra o gráfico computacional. Keras fornece um
nível de construção para LSTMs, que permite aos usuários construir modelos LSTM.

Resumo
Neste capítulo, cobrimos os conceitos básicos do uso de Keras, usando vários exemplos pequenos e simples. Nós
Encoraje o leitor a experimentar os exemplos. Keras tem extensa documentação, que é
leitura adicional recomendada.

Página 120
111
© Nikhil Ketkar 2017
N. Ketkar, Aprendizado Profundo com Python , DOI 10.1007 / 978­1­4842­2766­4_8

CAPÍTULO 8

Descida Estocástica de 
Gradiente
Um passo essencial na construção de um modelo de aprendizagem profunda é resolver o problema subjacente de otimização,
definido pela função de perda. Este capítulo cobre a Descida Estocástica de Gradiente (SGD), que é a mais
algoritmo comumente usado para resolver esses problemas de otimização. Nós também cobrimos uma amplitude de 
algorítmica
variações publicadas na literatura acadêmica que melhoram o desempenho do SGD, e apresentam uma
truques em grande parte não documentados que permitirão ao usuário ir mais longe. Por fim, nós cobrimos algum 
fundamento
SGD paralelo / distribuído e toque em Métodos de segunda ordem para completude.
A maioria dos exemplos apresentados no código que acompanha este capítulo é baseada em um Python
pacote chamado downhill. A Downhill implementa o SGD com muitas de suas variações e é uma excelente escolha
para experimentar.

Problemas de otimização
Simplificando, um problema de otimização envolve encontrar os parâmetros que minimizam uma função matemática.
Por exemplo, dada a função fx
x
() = 2, encontrando o valor de x que minimiza a função é um
problema de otimização (consulte a Figura  8­1 ).
Figura 8­1. Um problema de otimização envolve encontrar os parâmetros que minimizam uma dada função

Page 121
Capítulo 8 ■ Desdobramento de Gradiente StoChaStiC
112
Enquanto as funções que queremos minimizar ao construir modelos de aprendizagem profunda são muito mais
complicado (envolvendo vários parâmetros que podem ser escalares, vetores ou matrizes), conceitualmente é
simplesmente encontrando os parâmetros que minimizam a função.
A função que se deseja otimizar enquanto se constrói um modelo de aprendizagem profunda é chamada de perda
função. A função de perda pode ter vários parâmetros escalares / vetoriais / valorados por matriz, mas sempre
uma saída escalar. Essa saída escalar representa a qualidade do modelo. Bondade, tipicamente, significa
combinação de quão bem o modelo prediz e quão simples é o modelo.
■ Nota Por enquanto, ficaremos longe dos aspectos de aprendizagem estatística / máquina de uma função
de perda (coberta
em outro lugar do livro) e concentre­se puramente na solução desses problemas de otimização. isto é, nós 
assumimos que nós
foram apresentados com uma função de perda L ( x ) onde x representa os parâmetros do modelo e o 
trabalho em
mão é encontrar os valores para x que minimizam L ( x ).

Método da descida mais íngreme
Vamos agora olhar para uma ideia matemática simples, que é a intuição por trás do SGD. Por uma questão de simplicidade,
Vamos supor que x é apenas um vetor. Dado que queremos minimizar L ( x ), queremos mudar ou atualizar
x tal que L ( x ) reduz. Seja vc representar o vetor unitário ou a direção na qual x deve ser idealmente alterado
e deixe α denotar a magnitude (escalar) desta etapa. Um valor mais alto de α implica um passo maior na direção
u , o que não é desejado. Isto é porque u é avaliado para o valor atual de x e será diferente para um
x diferente .
Assim, queremos encontrar um u tal que
lim
uma

uma
®

+
(
)
0

L x
você
é minimizado. Segue que
lim
.
uma

uma
®

+
(
) =
Ñ ()
0

eu
você
L x
T

x
você
x

Assim, basicamente, quer encontrar um u tal que
você
L x
T  Ñ ()
x

é minimizado. Note que Ñ ()
x  L x é o gradiente de L ( x ).
Dado que tanto u T como Ñ ()
L x são vetores, segue­se que

você
L x
você
L x
T  Ñ () = × Ñ ()
x
x

cos, q
onde θ é o ângulo entre os dois vetores (consulte a Figura  8­2 ).

Página 122
Capítulo 8 ■ Desdobramento de Gradiente StoChaStiC
113
O valor de cos  θ seria minimizado em qp =, ou seja, os vetores estão apontando para o lado oposto
direção. Assim, segue­se que definindo a direção u = ­ Ñ ()
L x alcançaria nosso objetivo desejado. este

leva a um algoritmo iterativo simples da seguinte forma:
Entrada: α, n
Inicialize x para um valor aleatório.
Para n etapas, faça:
Atualizar x = x
x

­ Ñ ()
uma
L x
Saída: x

Descida Estocástica (Simples e Mini­lote)
Até agora, estávamos denotando nossa função de perda como L ( x ). Os dados de treinamento (exemplos) estavam 
implícitos nessa notação.
Para o propósito desta discussão, precisamos torná­los explícitos. Vamos denotar nossos dados de treinamento como
D
dd
d n
=
¼
{
}
1
2

,
. Nossa função de perda deve agora ser denotada como L D ( x ). Isso significa simplesmente que a função de perda
está a ser avaliado com parâmetros x e com respeito a um conjunto de pontos de dados D . Seja T um subconjunto de 
exemplos em
D ; então L T ( x ) denota a função de perda avaliada sobre o conjunto de exemplos T. Similarmente, Ñ
()
x  L x
D

e n
()
x  L x
T

denotar os gradientes da função de perda L ( x ) computados sobre os conjuntos de dados de treinamento D e T , 
respectivamente.
■ Nota Por ora, ficaremos longe do cálculo de gradientes de funções de perda em subconjuntos de dados.
estes podem ser gerados usando diferenciação automática (coberto em outras partes do livro) facilmente 
(mesmo para
funções arbitrárias de perda complicada) e não precisam ser derivadas manualmente.
Armado com esta notação, podemos agora discutir três variantes da abordagem de descida mais íngreme
discutido anteriormente.
Figura 8­2. Encontrando a direção desejada da atualização

Página 123
Capítulo 8 ■ Desdobramento de Gradiente StoChaStiC
114
Lote
Nesta abordagem, todo o conjunto de dados D é usado na etapa de atualização. Ou seja, x é atualizado como xx
L x
D

= ­Ñ
()
x

. Dois
as coisas são aparentes sobre esta abordagem. Primeiro, que é caro, pois requer um cálculo ao longo de todo o processo.
conjunto de dados. Em segundo lugar, a direção de atualização é a mais precisa, considerando nosso conjunto de dados 
inteiro.

Exemplo único estocástico
Nesta abordagem, apenas um único exemplo de D é usado na etapa de atualização. Ou seja, x é atualizado como
xx
L x
S

= ­Ñ
()
x

onde S = 1. Note que usamos um exemplo diferente em cada iteração escolhida aleatoriamente
o termo estocástico, que significa simplesmente ter uma natureza aleatória). Duas coisas são aparentes sobre isso
abordagem também. Primeiro, é muito barato, pois requer um cálculo do gradiente em apenas um único exemplo.
Em segundo lugar, a direção da atualização não é tão precisa quanto estamos usando apenas uma pequena fração do 
conjunto de dados de treinamento.

Mini­lote estocástico
Nessa abordagem, apenas um pequeno subconjunto de exemplos de D é usado na etapa de atualização. Ou seja, x é 
atualizado como
xx
L x
S

= ­Ñ
()
x

onde SD
<
. Observe que usamos um conjunto diferente de exemplos em cada iteração escolhida
aleatoriamente (daí o termo estocástico).

Lote vs. Estocástico
Na prática, as abordagens estocásticas dominam as abordagens em lote e são muito mais comumente usadas.
Um fato aparentemente não intuitivo sobre as abordagens estocásticas é que não é apenas o gradiente sobre alguns exemplos
mais barato para computar, não obter a direção exata (usando apenas um pequeno número de exemplos) realmente leva
para melhores soluções. Isso é particularmente verdadeiro para grandes conjuntos de dados com informações redundantes 
em que
exemplos não são muito diferentes uns dos outros. Outra razão para abordagens estocásticas que funcionam melhor
é a presença de vários mínimos locais com diferentes profundidades. Em certo sentido, o ruído na direção permite
para saltar através das trincheiras enquanto uma aproximação do grupo convergirá na trincheira que começou com.

Desafios com o SGD
Tendo coberto a descrição conceitual da SGD, consideremos agora os desafios de aplicá­la a
Resolver problemas do mundo real enquanto constrói modelos de aprendizagem profunda.

Mínimo Local
Os mínimos locais são soluções abaixo do ideal (consulte a Figura  8­3 ) que interceptam qualquer abordagem de descida 
mais íngreme e
impedir o procedimento iterativo de avançar para uma solução melhor.

Página 124
Capítulo 8 ■ Desdobramento de Gradiente StoChaStiC
115
Pontos de sela
Os pontos de sela são pontos (consulte a Figura  8­4 ), onde o gradiente é avaliado como zero, mas o ponto não é
mínimo local. Os pontos de sela são qualquer abordagem de descida mais íngreme e impedem o procedimento iterativo para
progredir em direção a uma solução melhor. Há boas evidências empíricas de que os pontos de sela são muito
mais comum que os mínimos locais quando se trata de problemas de otimização em um grande número de dimensões
(o que é sempre o caso quando se trata de construir modelos de aprendizagem profunda).
Figura 8­4. Ponto de sela
Figura 8­3. Mínimo Local

Page 125
Capítulo 8 ■ Desdobramento de Gradiente StoChaStiC
116
Selecionando a taxa de aprendizado
O α é a discussão anterior que representa a magnitude (escalar) do passo (na direção u) é
tomadas em cada iteração para atualizar x . Este α é comumente referido como a taxa de aprendizagem e tem um grande
impacto na busca de boas soluções para o problema de otimização (consulte 8­5). Uma taxa de aprendizado muito alta
pode fazer com que a solução salte ao redor e uma taxa de aprendizado muito baixa significa convergência lenta (implicando
não chegar a uma boa solução em um determinado número de iterações). Quando se trata de funções de perda com muitos
parâmetros treinados em conjuntos de dados esparsos, uma única taxa de aprendizado global para todos os parâmetros torna 
o problema de
escolhendo uma taxa de aprendizagem ainda mais desafiadora.
Figura 8­5. A taxa de aprendizado precisa ser definida corretamente
Page 126
Capítulo 8 ■ Desdobramento de Gradiente StoChaStiC
117
Progresso lento em vales estreitos
Outro problema inerente à descida mais íngreme é o lento progresso em vales estreitos gerados devido a
conjuntos de dados escalados. O progresso diminui drasticamente à medida que nos aproximamos da solução (consulte a 
Figura  8­6 ).
Figura 8­6. Progresso lento em vales estreitos

Variações Algoritmicas no SGD
Vamos agora cobrir uma série de variações algorítmicas para o SGD propostas na literatura acadêmica que abordam
os desafios discutidos anteriormente.

Page 127
Capítulo 8 ■ Desdobramento de Gradiente StoChaStiC
118
Momento
Considere a etapa de atualização do SGD descrita anteriormente
x
L x
= ­ Ñ ()
x
x

uma
.
A intuição por trás do momentum é usar uma fração da atualização anterior para a atualização atual. que
é, deixe u s denotar a atualização para os parâmetros x na etapa s. Da mesma forma, deixe u s­1 denotar a atualização no 
anterior
degrau. Agora, vamos atualizar x com
você s
x

=
+ Ñ ()
­

g
uma
você
L x
s 1

.
Ou seja, nós atualizamos
xxu s
= ­
ao invés de
x
x
x

= ­ Ñ ()
uma
X L .
Figura 8­7. Direção de impulso
Simplificando, usamos uma facção da atualização na etapa anterior para a atualização atual. Essa ideia é
referido como momento, como é semelhante ao momento adquirido por uma bola rolando ladeira abaixo. Uma bola que tem
O impulso momentâneo saltará de pequenas valas (mínimos locais) ao longo do caminho e alcançará o fundo
da colina. Ele também manterá um pouco a velocidade do movimento de descida anterior, mesmo se a
um declive muito reduzido (porque pegou momentum). O termo momentum basicamente causa novos
a direção do passo deve ser polarizada pela direção anterior do passo (consulte a Figura  8­7 ). O uso do momentum foi
empiricamente mostrado para causar oscilação reduzida e convergência mais rápida.

Page 128
Capítulo 8 ■ Desdobramento de Gradiente StoChaStiC
119
Gradiente Acelerado Nesterov (NAS)
Usando a mesma notação de antes, o gradiente acelerado de Nesterov está basicamente atualizando x com
você s
x

=
+ Ñ
­
(
)
­
­

g
uma
g
você
L x
você
s
s
1

.

Ou seja, atualizamos xxu s
= ­.
A intuição por trás disso está parecendo um passo à frente. Ou seja, primeiro damos um passo na direção do
gradiente acumulado e fazer uma adaptação. A intuição por trás do NAS está olhando para frente e antecipando,
que leva a melhores soluções (consulte a Figura 8­8).
Figura 8­8. Direção NAS

Horários de Recozimento e Aprendizagem
Quando o gradiente descendente se aproxima de um mínimo, vimos como uma taxa de aprendizado ruim pode causar
oscilar em torno dos mínimos (veja a Figura  8­5 ). Recozimento refere­se a reduzir a taxa de aprendizado à medida que se 
aproxima
os mínimos. Isso pode ser feito manualmente (interrompendo a descida de gradiente e reiniciando a partir do mesmo ponto
com uma taxa de aprendizagem reduzida) ou através de programações de taxa de aprendizagem que introduzem um número 
de
Parâmetros hiper que ditam como a taxa de aprendizado é reduzida com base no número de etapas executadas.
No entanto, deve­se notar que estamos usando a mesma taxa de aprendizado para todos os parâmetros, que podem não ser
apropriado; um ajuste de taxa de aprendizagem por parâmetro é desejado.

Adagrad
O algoritmo Adagrad ajusta a taxa de aprendizado para cada parâmetro. Até agora, temos denotado o
parâmetros da função de perda como x . Note que x é na verdade um grande número de parâmetros, cada um dos quais é
sendo atualizado com a mesma taxa de aprendizado. Deixe x i denotar um dos parâmetros e deixe g i
s denota o gradiente

para x i no passo s . Para as etapas 01
1
,,
¼ ­
S
temos uma série correspondente de gradientes g i
0 , g i

1 ,…, g i

s .

Page 129
Capítulo 8 ■ Desdobramento de Gradiente StoChaStiC
120
Deixei
G
g
g
g
Eu
Eu
Eu
S

=  () + () + ¼ + () 
­

0
2
1
2
1
2

,
que é basicamente a soma dos quadrados dos gradientes para cada etapa até a etapa anterior. A regra de atualização
em Adagrad é
xx
G
g
Eu
Eu
Eu
S

= ­
uma
1
2

.
O termo α é a taxa de aprendizado global, que é adaptada para cada parâmetro com base no
gradientes. Também deve ser notado que, como G se acumula, a taxa de aprendizado diminui para cada parâmetro e
Eventualmente, nenhum progresso pode ser feito, o que é uma fraqueza do Adagrad.

RMSProp
O algoritmo RMSProp melhora a fraqueza do algoritmo Adagarad de progresso completamente parado
além de um certo número de iterações. A intuição aqui é usar uma janela de tamanho fixo sobre os gradientes
computado em cada etapa, em vez de usar o conjunto completo de gradientes. Isto é, calcule G apenas sobre 
os passos W anteriores .
Agora, ' é conceitualmente equivalente, mas computacionalmente mais barato para tratar o cálculo de
G
g
g
g
W
Eu
SW
Eu
S w
Eu
S

() + () + ¼ + ()
­
+
­
2
1
2
1
2

como o acúmulo da média exponencialmente decadente do quadrado de gradientes em vez de armazenar todos os valores de
g
g
gg
Eu
W
Eu
W
Eu
Eu
­
+
­
­

¼
,
,
1
2
1

e calcule G em cada etapa. Ou seja, nós calculamos
Por exemplo
Por exemplo
g
Eu
S
Eu
S
Eu
S

()
é
ë
você
você
=
()
é
ë
você
você
+ ­

() ()
­
2
2
1
2

1
r
r
onde ρ é a decadência.
Agora, note que no Adagrad nós estávamos computando a atualização como
xx
G
g
Eu
Eu
Eu
S

= ­
uma
1
2

. Considere o valor de G
1

. Podemos ver que isso é simplesmente o root mean square de g i , ou seja,

RMS g
G
Por exemplo
Eu
Eu
S

[] =
=
()
é
ë
você
você
1
2
2

.
Assim, podemos calcular a atualização como
xx
RMS g
g
Eu
Eu
Eu
Eu
S

= ­
[]
uma
.

Page 130
Capítulo 8 ■ Desdobramento de Gradiente StoChaStiC
121
Adadelta
A intuição por trás de Adadelta é considerar se a unidade do parâmetro e a atualização para o
parâmetro é o mesmo. O autor do Adadelta argumenta que isto não é o mesmo no caso de qualquer
ordem métodos como descida mais íngreme (mas é o mesmo no caso de métodos de segunda ordem como Newton's
método). Para corrigir este problema, a regra de atualização proposta de Adadelta é
xx
RMS x
RMS g
g
Eu
Eu
Eu
S
Eu
S
Eu
S

= ­
D []
[]
­1

onde RMS x S
D [] ­1
é o root mean­square das atualizações reais para x . Observe que RMS x i
S

D [] ­1
defasagens
atrás de RMS [ g i ] S por um passo.

Adão
Adam calcula as atualizações mantendo as médias exponencialmente ponderadas de g i e ( g i ) 2 para cada
parâmetro (denotado pelo subscrito i ). A regra de atualização para Adam é
xx
Por exemplo
Por exemplo
Eu
Eu
Eu
S
Eu
S

= ­

()
é
ë
você
você
éë
ùû
­
­

uma
1
2
1

.
É importante notar que E g i
S ­

éë
ùû 1
e E g i
S

(
]
­

éë

)  1 2

são tendenciosas para zero nos passos iniciais para pequenas
taxas de decaimento (há duas taxas de decaimento aqui ­ uma para E g i
S ­

éë
ùû 1
e um para E g i
S

(
]
­

éë

)  1 2  ­ que denotamos por
ρ 1 e ρ 2, respectivamente). Esse viés pode ser corrigido pela computação
Por exemplo
Por exemplo
Eu
S
Eu
S
­
­

éë
ùû =
éë
ùû
­
1
1
1

1 r
e
Por exemplo
Por exemplo
Eu
S
Eu
S

(
]
(
]
­
­

éë

) =
éë

)
­
1 2
1 2
2

1 r
respectivamente.

Retropropagação resiliente
A intuição por trás da retropropagação resiliente é que o sinal do gradiente muda para frente e para trás
entre positivo e negativo quando a taxa de aprendizado é muito alta (consulte a Figura 7 ). A ideia chave é manter
rastreie o sinal do gradiente anterior e combine­o com o gradiente atual. Se o sinal é o mesmo, use um
maior taxa de aprendizado e, se diferente, usar uma taxa de aprendizado mais baixa. Note que isso é feito para todos os 
parâmetros. o
hyper parameters incluem os valores para aumentar e diminuir a taxa de aprendizado (caso o sinal corresponda
ou não corresponde, respectivamente).

Page 131
Capítulo 8 ■ Desdobramento de Gradiente StoChaStiC
122
SGD Equilibrado
O SGD Equilibrado visa abordar questões de experiências SGD com pontos de sela. A ideia chave aqui é que nós
precisa de informação de segunda ordem (segunda derivada da função de perda) para sair da armadilha de uma sela
ponto. A regra de atualização para SGD Equilibrado é dada por xx
D
g
Eu
Eu
Eu
S
Eu
S

= ­
uma
onde D
D
H
Eu
S
Eu
S
d

=
+ ­
() ()
­

r
r
1
2

1
(média exponencialmente ponderada) e H d é a diagonal da matriz Hessiana de L ( x ) (calculado
simbolicamente) avaliada em x Î ()
 0 1, (distribuição normal com 0 média e desvio padrão de 1).

Dicas e truques para usar o SGD
Vamos agora cobrir uma série de truques e dicas para o SGD propostas em literatura acadêmica que abordam o
desafios discutidos anteriormente.

Dados de entrada de pré­processamento
É de suma importância que os dados sejam bem dimensionados para facilitar a otimização (consulte a Figura  8­6 ). Um bem
regra geral é padronizar os dados subtraindo a média e dividir pelo desvio padrão para
dimensionar os dados. Então, se X
XX
X n
=
¼
{
}
1
2

,
é uma das variáveis de entrada, nós transformamos os dados para que
X
X
Eu
Eu

=
­m
s
.
No caso de dados esparsos (a maioria do X i é igual a zero), o processo de padronização fará com que os dados sejam
tornar­se denso, escala max­abs onde
X
X
X
Eu
Eu

=
()
máximo
.
Dimensionando o recurso para ter uma norma de unidade
X
X
X
Eu
Eu
Eu

=
2

é outra abordagem para dimensionar dados.
Também é uma boa prática remover correlações lineares entre as variáveis de entrada dos dados de entrada
Análise do componente principal.

Escolha da função de ativação
Exemplos comuns de função de ativação são a função logística padrão fx
e x
() =
+ ­
1
1
e a
função tangente hiperbólica fx
x
() =
()
tanh
. Uma abordagem recomendada é usar uma função de ativação que
é simétrico em torno de 0 (em vez de apenas positivo ou negativo), por exemplo, fx
x
() =
æ
è
ç
ö
ø
÷
1 7159
2
3
.
tanh
. Isto é
também recomendou que um pequeno termo linear fosse adicionado para evitar esportes planos, fx
x machado
() =
() +
tanh
.

Página 132
Capítulo 8 ■ Desdobramento de Gradiente StoChaStiC
123
Valor­alvo de pré­processamento
Embora os valores de destino possam ser binários (0,1) em muitos casos, é aconselhável transformar a variável de destino 
em valores
que estão dentro do intervalo (não assintoticamente, mas praticamente) das funções de ativação usadas para definir
função de perda. Não fazê­lo leva a que os parâmetros sejam atualizados para valores cada vez mais altos sem alcançar
qualquer efeito (na etiqueta de saída). No entanto, se o valor do rótulo de destino estiver sendo usado como uma medida de
confiança, então os rótulos que foram desnecessariamente empurrados para valores mais altos são
confiança. Enquanto 0 e 1 podem ser valores extremos para a função de ativação, também é importante não
escolha alvos que se encontrem na região linear da função de ativação. Uma abordagem recomendada é escolher
valores que maximizam a segunda derivada da função de ativação, por exemplo, ± 1 para
fx
x
() =
æ
è
ç
ö
ø
÷
1 7159
2
3
.
tanh
.

Inicializando Parâmetros
É uma prática recomendada inicializar os parâmetros aleatoriamente (distribuição normal, média zero, unidade
variância). Outra receita para redes neurais onde a função de ativação é fx
x
() =
æ
è
ç
ö
ø
÷
1 7159
2
3
.
tanh
(e os dados são padronizados) é definir pesos para m
­ 1

onde m é o fan­in (o número de conexões

alimentando no nó).

Como embaralhar dados
Recomenda­se a prática de misturar dados de entrada, como pode ser em uma ordem particular e, portanto, pode influenciar 
o
SGD. Uma rara exceção a isso é o Aprendizado de Currículo, no qual os exemplos são apresentados em uma ordem 
significativa.
(dificuldade crescente de previsão).

Normalização em lote
Enquanto nossos parâmetros são inicializados de forma que eles são normalizados (definidos aleatoriamente,
distribuição, média zero e variação de unidade), eles não permanecem normalizados durante as etapas de atualização. Lote
a normalização renormaliza os parâmetros após cada lote (consulte o lote SGD).

Parada Antecipada
A interrupção antecipada envolve basicamente a medição da perda em um subconjunto invisível de dados de treinamento 
(não utilizado para SGD)
(chamado de dados de validação) e parando quando não há alteração observada na perda. Normalmente, existem dois
hyper parameters introduzidos: um que determina se a mudança é significativa (qualquer alteração na perda
menor que este valor é tratado como não uma alteração) e um parâmetro de paciência, que é o número de vezes que não
A etapa de alteração pode ser executada antes do término do procedimento iterativo.

Ruído gradiente
O truque de ruído de gradiente introduz um ruído centrado médio,  0, s
() , em cada etapa de atualização. Aqui, σ é um hiper
parâmetro e o gradiente é calculado como gg
Eu
Eu

= +
()
 0, s.

Página 133
Capítulo 8 ■ Desdobramento de Gradiente StoChaStiC
124

SGD Paralelo e Distribuído
Nós agora cobrimos duas abordagens paralelas e distribuídas para o SGD. SGD em sua forma básica é um seqüencial
algoritmo e convergência podem ser muito lentos em grandes conjuntos de dados e modelos com um grande número de
parâmetros. Abordagens paralelas e distribuídas têm um grande impacto quando se trata de lidar com
volumes de dados de treinamento (na ordem de bilhões) e um grande número de parâmetros de modelo (na ordem
milhões).

Hogwild
Considere a etapa de atualização do procedimento SGD. O que torna o algoritmo inerentemente sequencial é a atualização
passo xx
x

= ­ Ñ ()
uma
X L . Digamos que queremos empregar vários encadeamentos de computação para tornar
iteração mais rápida. Uma vez que queremos apenas um thread para fazer isso (fazer a atualização um passo de cada vez), 
colocamos um
bloquear em torno desta etapa (para evitar uma condição de corrida). Uma vez que fazemos isso, isso se torna 
essencialmente um sequencial
algoritmo; não importa quantos núcleos e threads dedicamos ao processo, apenas um thread é realmente
fazendo o trabalho, enquanto todos os outros estão esperando em um bloqueio.
A intuição por trás de Hogwild é que a condição de corrida causada por não colocar um bloqueio na etapa de atualização
não leva a muita inconsistência nas atualizações quando o problema de otimização é escasso. Isso é simplesmente
porque cada etapa de atualização afeta apenas alguns parâmetros. Os autores de Hogwild fornecem uma forte base teórica
e evidência empírica para este achado e os ganhos em grandes conjuntos de dados são significativos. Hogwild é fácil de
implementar em CPUs multi­core e GPUs.

Aguaceiro
Downpour é um algoritmo distribuído para SGD que consiste em duas partes móveis principais: réplica do modelo e
servidor de parâmetros (consulte a Figura 8­9). Uma réplica de modelo é um conjunto de máquinas que opera em um 
subconjunto de dados,
onde cada máquina opera somente em um subconjunto de parâmetros. Existem muitas réplicas desse modelo, cada uma
operando em um subconjunto diferente de um grande conjunto de dados. O servidor de parâmetros é um conjunto de 
máquinas que mantém
um estado global comum do modelo. As réplicas do modelo recuperam o estado global do servidor de parâmetros,
atualize o modelo com base no subconjunto de dados e atualize o estado global. Observe que a busca e atualização
do estado global não acontece em todas as iterações. Existem dois níveis de distribuição com Downpour.
Primeiro, os parâmetros do modelo (o que temos denotado como x até agora) são divididos em várias máquinas em
cada réplica do modelo. Em segundo lugar, os dados são divididos entre as réplicas do modelo. Então, essencialmente, cada 
máquina está fazendo
a etapa de atualização do gradiente em um subconjunto de parâmetros do modelo, usando um subconjunto de dados. O 
estado global é atualizado
de forma assíncrona. Apesar das aparentes inconsistências introduzidas por Downpour, verificou­se ser
muito eficaz quando se trata de treinar um modelo grande com grandes quantidades de dados.

Page 134
Capítulo 8 ■ Desdobramento de Gradiente StoChaStiC
125
Figura 8­9. Aguaceiro

Hands­on SGD com Downhill
Agora faremos um exercício prático com o SGD usando um pacote do Python chamado Downhill. Implementos de descida
SGD com muitas das suas variantes. Ele opera em funções de perda definidas em Theano, o que o torna muito
ferramenta conveniente para jogar com variantes SGD em funções de perda arbitrária definidas em Theano. Vamos começar
com
gerando um conjunto de dados para nosso exercício (Listagem 8­1 , Figura  8­10).
Listagem 8­1. Gerando dados para nosso exercício
# Especifique o número de exemplos que precisamos (5000) e o nível de ruído
train_X, train_y = sklearn.datasets.make_moons (5000, ruído = 0,1)
#One codifica os valores alvo
train_y_onehot = numpy.eye (2) [train_y]
#Plote os dados
pylab.scatter (train_X [: ­ 1000, 0], train_X [: ­ 1000, 1], c = train_y [: ­ 1000], cmap = pylab.
cm.Spectral)

Página 135
Capítulo 8 ■ Desdobramento de Gradiente StoChaStiC
126
Isso deve produzir um gráfico do conjunto de dados que geramos. O objetivo é treinar um modelo para
distinguir entre os pontos vermelho e azul.
Figura 8­10. Conjunto de dados para nossos experimentos
Em seguida, vamos definir uma função de perda com o Theano.
Listagem 8­2. Definindo a função de perda
#Set Seed
numpy.random.seed (0)
num_examples = len (train_X)
#Nossa Rede Neural
nn_input_dim = 2
nn_hdim = 1000
nn_output_dim = 2
#Regularização
reg_lambda = numpy.float64 (0,01)
#Peritos de ponderação e viés
W1_val = numpy.random.randn (nn_input_dim, nn_hdim)
b1_val = numpy.zeros (nn_hdim)
W2_val = numpy.random.randn (nn_hdim, nn_output_dim)
b2_val = numpy.zeros (nn_output_dim)
X = T.matrix ('X')

Página 136
Capítulo 8 ■ Desdobramento de Gradiente StoChaStiC
127
y = T.matrix ('y')
W1 = theano.shared (W1_val, name = 'W1')
b1 = theano.shared (b1_val, name = 'b1')
W2 = theano.shared (W2_val, name = 'W2')
b2 = theano.shared (b2_val, name = 'b2')
batch_size = 1
# Nossa função de perda
z1 = X.dot (W1) + b1
a1 = T.tanh (z1)
z2 = a1.dot (W2) + b2
y_hat = T.nnet.softmax (z2)
loss_reg = 1./batch_size * reg_lambda / 2 * (T.sum (T.sqr (W1)) + T.sum (T.sqr (W2)))
perda = T.nnet.categorical_crossentropy (y_hat, y) .mean () + loss_reg
predição = T.argmax (y_hat, axis = 1)
predict = theano.function ([X], predição)
■ Nota Por enquanto, vamos ficar longe dos detalhes de definir funções de perda com theano (coberto em
outro lugar)
no livro).
Em seguida, montamos um SGD simples usando o Downhill. Usamos todos os parâmetros padrão e queremos fazer 10K 
iterações. o
O parâmetro de paciência também está configurado para 10K, de modo que a interrupção antecipada (descrita anteriormente 
no capítulo) não é acionada.
Listagem 8­3. SGD
# Armazene a perda de treinamento e vlidation
train_loss = []
validation_loss = []
opt = downhill.build ('sgd', perda = perda)
#Configure as divisões do conjunto de dados de treinamento e validação, use apenas um exemplo em um lote # e use
apenas um lote por etapa / epoc
# Use tudo, exceto os últimos 1000 exemplos de treinamento
trem = downhill. Dataset ([train_X [: ­ 1000], train_y_onehot [: ­ 1000]], batch_size = batch_size,
iteration_size = 1)
# Use os últimos 1000 exemplos para valudation
válido = downhill. Dataset ([train_X [­1000:], train_y_onehot [­1000:]])
#SGD
iterações = 0
para tm, vm em opt.iterate (train, valid, pacience = 10000):
iterações + = 1
# Registre a perda de treinamento e validação
train_loss.append (tm ['perda'])
validation_loss.append (vm ['perda'])

Página 137
Capítulo 8 ■ Desdobramento de Gradiente StoChaStiC
128
se iterações> 10000:
quebrar
Podemos agora visualizar o limite de decisão sobre o treinamento (Figura  8­11 ) e validação (Figura 8 a 12)
conjuntos e a perda (Figura 8­13 ).
Figura 8­11. Limite de decisão sobre o conjunto de treinamento
Figura 8­12. Limite de decisão sobre o conjunto de validação
Page 138
Capítulo 8 ■ Desdobramento de Gradiente StoChaStiC
129
Listagem 8­4. Usando variantes do SGD implementadas em Downhill
def build_model (algo):
loss_value = []
W1.set_value (W1_val)
b1.set_value (b1_val)
W2.set_value (W2_val)
b2.set_value (b2_val)
opt = downhill.build (algo, perda = perda)
trem = downhill. Dataset ([train_X [: ­ 1000], train_y_onehot [: ­ 1000]], batch_size = 1,
iteration_size = 1)
válido = downhill. Dataset ([train_X [­1000:], train_y_onehot [­1000:]])
iterações = 0
para tm, vm em opt.iterate (train, valid, pacience = 1000):
iterações + = 1
loss_value.append (vm ['perda'])
se iterações> 1000:
quebrar
return loss_value
Figura 8­13. Perda de treinamento e validação em mais de 10 mil iterações

Page 139
Capítulo 8 ■ Desdobramento de Gradiente StoChaStiC
130
algo_names = ['adadelta', 'adagrad', 'adam', 'nag', 'rmsprop', 'rprop', 'sgd']
perdas = []
para algo_name em algo_names:
imprimir algo_name
vloss = build_model (algo_name)
perdas.append (numpy.array (vloss))
Figura 8­14. Curvas de aprendizado (sobre dados de validação)
Vamos agora experimentar um número de variantes SGD implementadas em Downhill (Listagem 8­4 ) e visualizar o
curvas de aprendizagem (figura 8­14). Nós estaremos correndo Adadelta, Adagrad, Adam, Nesterov Gradiente Acelerado
(NAG), RMSProp, Retropropagação Resiliente e SGD de baunilha como antes. Nós rodamos todos esses algoritmos com
parâmetros padrão para 1000 etapas.

Resumo
Neste capítulo nós cobrimos a Descida Estocástica de Gradiente (SGD), as fraquezas da SGD, um número de
variações algorítmicas para resolver esses pontos fracos e vários truques para tornar o SGD efetivo. SGD é
a abordagem mais comum para treinar modelos de aprendizagem profunda. O leitor é aconselhado a repassar os exemplos
nas listagens de código­fonte e também olhar para as implementações de SGD e suas variantes no Downhill
pacote para maior clareza e perspectiva.
Um aspecto importante que não abordamos neste capítulo é como os gradientes para funções de perda arbitrária
(requerido para SGD) são calculados. Isso é abordado no próximo capítulo sobre diferenciação automática.

Página 140
131
© Nikhil Ketkar 2017
N. Ketkar, Aprendizado Profundo com Python , DOI 10.1007 / 978­1­4842­2766­4_9

CAPÍTULO 9
Diferenciação Automática
No capítulo sobre descida de gradiente estocástico, tratamos o cálculo de gradientes da função de perda
Ñ ()
L x como uma caixa preta. Neste capítulo, abrimos esta caixa preta e cobrimos a teoria e a prática de

diferenciação. A diferenciação automática é uma tecnologia madura que permite o uso fácil e eficiente
cálculo de gradientes de funções de perda arbitrariamente complicadas. Isso é crítico quando se trata de
minimizar as funções de perda de interesse; no coração da construção de qualquer modelo de aprendizagem profunda 
encontra­se uma otimização
problema, que é invariavelmente resolvido usando gradiente estocástico de descida, que por sua vez requer um para
gradientes de computação.
A maioria dos aplicativos neste capítulo é baseada no pacote Autograd do Python, que fornece uma
conjunto maduro de capacidades para diferenciação automática.
A diferenciação automática é distinta da diferenciação numérica e simbólica, e começamos por
cobrindo o suficiente sobre ambos para que a distinção se torne clara. Para fins de ilustração,
suponha que nossa função de interesse seja f : R
R
® e pretendemos encontrar a derivada de f denotada por f ′ ( x ).

Diferenciação Numérica
Diferenciação numérica em sua forma básica segue a partir da definição de derivada / gradiente. Então, dado que
¢ () =
=
+
(
) ­ ()
®

fx
df
dx
fx
x
fx
x
x

lim
D

D
D
0

podemos calcular o f ′ ( x ) usando o método de diferença de avanço como
¢ () =
() =
+
() ­ ()
+

fx
D h
fxh
fx
h
,
definindo um valor adequadamente pequeno para h . Da mesma forma, podemos calcular f ′ ( x ) usando a diferença para trás
método como
¢ () =
() =
() ­
­
()
fx
D h
fx
fxh
h
_
,

Page 141
Capítulo 9 ■ Diferenciação Automática
132
novamente definindo um valor adequadamente pequeno para h . Uma forma mais simétrica é a abordagem da diferença 
central,
que calcula f ′ como
¢ () =
() =
+
() ­
­
()
fx
D h
fxh
fxh
h
0

2
.
Um desenvolvimento adicional sobre esta ideia é a extrapolação de Richardson
¢ () =
() ­
()
fx
Dh D
h
4
2
3
0
0

.
Os erros de aproximação para diferenças de avanço e retrocesso são da ordem de h , isto é, O ( h ), enquanto
aqueles para a diferença central e a aproximação de Richardson são O ( h 2 ) e O ( h 4 ), respectivamente.
Os principais problemas com diferenciação numérica são o custo computacional, que cresce com o
número de parâmetros na função de perda, os erros de truncamento e os erros de arredondamento. O truncamento
erro é a imprecisão que temos no cálculo de f ′ ( x ) devido a h não ser zero. O erro de arredondamento é
inerente ao uso de números de ponto flutuante e aritmética de ponto flutuante (contra o uso de precisão infinita
números, o que seria proibitivo caro).
A diferenciação numérica não é, portanto, uma abordagem viável para computar gradientes enquanto se constrói
modelos de aprendizagem. O único local onde a diferenciação numérica é útil é verificar rapidamente se
gradientes estão sendo calculados corretamente. Isso é altamente recomendado quando você tem gradientes computados
manualmente ou com uma biblioteca de diferenciação automática nova / desconhecida. Idealmente, esta verificação deve ser
colocada como um
verificação automática / asserção antes de olhar para o SGD.
■ Observe que a diferenciação numérica é implementada em um pacote python chamado Scipy. Nós não 
cobrimos aqui,
como não é diretamente relevante para a aprendizagem profunda.

Diferenciação Simbólica
A diferenciação simbólica em sua forma básica é um conjunto de regras de reescrita de símbolos aplicadas à função de perda
para
chegar aos derivados / gradientes. Considere duas dessas regras simples:
d
dx
fx
gx
d
dx
fx
d
dx
x
() + ()
(
) =
() +
()
g
e
d
dx
x
nx
n
n

=
­

() 1 .

Agora, dada uma função como fx
x
x
() =
+
2 3
2 , podemos aplicar sucessivamente as regras de escrita de símbolos para primeiro

chegar a

Página 142
Capítulo 9 ■ Diferenciação Automática
133
¢ () =

() +
()
fx
d
dx
x
d
dx
x
2 3
2

aplicando a primeira regra de reescrita e ¢ () =
+
fx
x
x
6
2
2

aplicando a segunda regra. Simbólico
A diferenciação é, portanto, automatizar o que fazemos quando derivamos gradientes manualmente. Claro, o número de
tais regras podem ser grandes, e algoritmos mais sofisticados podem ser aproveitados para tornar este símbolo reescrito
mais eficiente. No entanto, em sua essência, a diferenciação simbólica é simplesmente a aplicação de um conjunto de 
símbolos
regras de reescrita. A principal vantagem da diferenciação simbólica é que ela gera uma legibilidade matemática legível.
expressão para o derivado / gradiente que pode ser entendido e analisado.
O principal problema da diferenciação simbólica é que ela é limitada às regras de diferenciação simbólica.
já definido, o que pode nos levar a atropelos ao tentar minimizar as funções complicadas de perda.
Um exemplo disso é quando sua função de perda envolve uma cláusula if­else ou um loop for / while. Num sentido,
diferenciação simbólica está diferenciando uma expressão matemática (forma fechada); não é diferenciar um
dado procedimento computacional.
Outro problema com a diferenciação automática é que uma aplicação ingênua de reescrita de símbolos
regras, em alguns casos, pode levar a uma explosão de termos simbólicos (expressão swell) e tornar o processo
computacionalmente inviável. Normalmente, é necessária uma quantidade razoável de esforço de computação para 
simplificar
expressões e produzir uma expressão de forma fechada da derivada.
■ Nota A diferenciação simbólica é implementada em um pacote python chamado Sympy. Nós não 
cobrimos aqui,
como não é diretamente relevante para a aprendizagem profunda.

Fundamentos de diferenciação automática
A primeira intuição chave por trás da diferenciação automática é que todas as funções de interesse (que pretendemos
diferenciar) pode ser expresso como composições de funções elementares para as quais o derivado
funções são conhecidas. Funções compostas, portanto, podem ser diferenciadas aplicando­se a regra da cadeia
derivados. Essa intuição também está na base da diferenciação simbólica.
A segunda intuição chave por trás da diferenciação automática é que, em vez de armazenar e manipular
formas simbólicas intermediárias de derivadas de funções primitivas, pode­se simplesmente avaliá­las (por um
conjunto específico de valores de entrada) e, assim, abordar a questão da expressão swell. Desde simbólico intermediário
formulários estão sendo avaliados, não temos o ônus de simplificar a expressão. Note que isso impede
nos de obter uma expressão matemática forma fechada da derivada como a diferenciação simbólica
nos dá; O que obtemos através da diferenciação automática é a avaliação da derivada para um dado conjunto de valores.
A terceira intuição chave por trás da diferenciação automática é que, porque estamos avaliando derivativos
de formas primitivas, podemos lidar com procedimentos computacionais arbitrários e não apenas de forma fechada
expressões matemáticas. Ou seja, nossa função pode conter instruções if­else, for­loops ou até recursão.
A forma como a diferenciação automática lida com qualquer procedimento computacional é tratar uma única avaliação
do procedimento (para um dado conjunto de entradas) como uma lista finita de avaliações de função elementar sobre a 
entrada
variáveis para produzir uma ou mais variáveis de saída. Embora possa haver instruções de fluxo de controle (if­else
declarações, for­loops, etc.), em última análise, há uma lista específica de avaliações de função que transformam o dado
entrada para a saída. Tal lista / rastreamento de avaliação é referido como uma lista Wengert.

Página 143
Capítulo 9 ■ Diferenciação Automática
134
Vamos definir o palco para discutir a diferenciação automática, introduzindo uma função simples
fxx
x
x
1
2
1
2
2
2
1
2

,
(
) =
+

(
) . Figura 9­1 mostra o gráfico computacional da função. Note que nós também
introduzir algumas variáveis intermediárias por conveniência.
Figura 9­1. Uma função simples e seu gráfico computacional

Modo Linear de Avanço / Tangente
O modo de avanço (também chamado de modo linear tangente) de diferenciação automática associa cada
variável intermediária no gráfico computacional com um derivado. Mais formalmente, nós temos v
v
x
Eu
Eu

=


para todos
valores de i onde v i é a derivada da variável intermediária v i em relação a uma variável de entrada / outra
variável intermediária x . Figura 9­2 ilustra isso para a função de exemplo que introduzimos anteriormente.

Page 144
Capítulo 9 ■ Diferenciação Automática
135
Note que existem várias maneiras pelas quais tal gráfico computacional pode ser construído e
as derivadas para as variáveis intermediárias podem ser associadas aos nós. Isso pode ser feito explicitamente
analisando a função dada (a ser diferenciada) ou implicitamente usando a sobrecarga do operador. Para os propósitos
desta discussão, basta dizer que a função dada pode ser decomposta em suas funções elementares
e, usando as derivadas das funções elementares e a regra da cadeia, podemos associar intermediários
variáveis com seus derivados correspondentes.
Figura 9­2. Associando cada variável intermediária a uma derivada na diferenciação automática do modo de avanço

Página 145
Capítulo 9 ■ Diferenciação Automática
136
Dado tal gráfico computacional aumentado, podemos avaliar o valor do derivado (parcial)
da função dada em relação a uma variável particular (e um conjunto de entradas) avaliando as expressões
associado ao gráfico computacional aumentado. Para esta avaliação, temos valores para todas as entradas
variáveis e definimos todos os valores das derivadas das variáveis de entrada para 0, exceto para a variável
que pretendemos avaliar a derivada parcial, que definimos como 1. As Figuras  9­3 e 9­4 ilustram tal
avaliação do gráfico computacional.     
Figura 9­3. Calculando a derivada (parcial em relação a x 1 ) para um conjunto particular de valores de x 1 e x 2

Página 146
Capítulo 9 ■ Diferenciação Automática
137
Figura 9­4. Calculando a derivada (parcial em relação a x 2 ) para um conjunto particular de valores de x 1 e x 2
Página 147
Capítulo 9 ■ Diferenciação Automática
138
Deve­se notar que, com a diferenciação automática do modo de avanço, precisamos realizar uma avaliação
do gráfico computacional aumentado para calcular a derivada parcial em relação a cada entrada
variável. Segue que, para calcular o gradiente de uma função com relação a n variáveis de entrada,
exigiria n avaliações. Assim, o modo de avanço automático diferenciação é caro quando se trata de
gradientes de computação para funções com muitas variáveis de entrada, que é um caso comum em aprendizado profundo
onde as funções de perda consistem em muitas variáveis de entrada e uma única variável de saída.
É também claro que a diferenciação automática do modo de avanço é uma aplicação bastante
regra de cadeia e pode ser implementada facilmente usando a sobrecarga do operador. Modo de avanço automático
diferenciação é frequentemente implementada pelo uso de números duplos, que são definidos como um
série da forma vv
+  . A aritmética em números duplos pode ser definida usando  2
0
= e tratar um não­dual
número como v
v
+0. Números duplos, em certo sentido, carregam a derivada com eles durante toda a sua vida. Portanto,
dado que temos uma implementação completa de números duplos, as derivadas podem simplesmente ser computadas como
um efeito lateral / paralelo das operações no componente dual.

Modo Linear Reverso / Cotangente / Adjunto
O modo reverso (também chamado de modo linear cotangente ou modo adjunto) de diferenciação automática também
associa cada variável intermediária no gráfico computacional com uma derivada computada para trás
da saída. Isso tem uma notável semelhança com a retropropagação. Mais formalmente, nós temos v
y
v
Eu
Eu

=



para
todos os valores de i onde v i é a derivada da variável de saída / intermediária y i para todos os valores de i . Figura  9­5
ilustra isso para a função de exemplo que apresentamos anteriormente.
Para avaliar a derivada, primeiro fazemos um forward forward sobre o grafo computacional aumentado
mostrado na Figura  9­6 . Isto é seguido por uma passagem reversa na qual as derivadas são computadas, o que é
ilustrado na Figura  9­7 .
A diferenciação automática em modo reverso calcula todas as derivadas parciais em um único passo para frente e
um único passo reverso e, portanto, se adapta bem a funções com muitas variáveis de entrada comuns a
funções de perda em aprendizagem profunda.

Página 148
Capítulo 9 ■ Diferenciação Automática
139
Figura 9­5. Associar todas as variáveis intermediárias a uma derivada no modo reverso de diferenciação automática

Página 149
Capítulo 9 ■ Diferenciação Automática
140
Figura 9­6. Avanço direto da diferenciação automática do modo reverso

Page 150
Capítulo 9 ■ Diferenciação Automática
141
Implementação de diferenciação automática
Vamos agora dar uma olhada em como a diferenciação automática é comumente implementada. As três chaves
abordagens estão usando a transformação do código­fonte e a sobrecarga do operador (dual explícito ou implícito).
implementação numérica).

Transformação do Código Fonte
A abordagem de transformação de código­fonte envolve o usuário implementando a função de perda em um
linguagem de programação e, em seguida, usando uma ferramenta de diferenciação automática para gerar o correspondente
função de gradiente. Esses dois podem ser compilados pela cadeia de ferramentas de compilação padrão a ser usada como 
parte de um
aplicação maior. Veja a figura 9­8.
Figura 9­7. Passagem para trás do modo reverso de difrenciação automática

Page 151
Capítulo 9 ■ Diferenciação Automática
142
Sobrecarga do Operador
A abordagem de sobrecarga de operadores é basicamente uma implementação explícita / implícita do número duplo
abordagem em que a operação de diferenciação correspondente é implementada para cada operação primitiva
de interesse. Os usuários implementam suas funções de perda usando as operações primitivas e o cálculo do
gradientes ocorrem pela invocação do método sobrecarregado implementando a operação de diferenciação.
Consulte a Figura  9­9 .
Figura 9­8. Transformação do Código Fonte

Página 152
Capítulo 9 ■ Diferenciação Automática
143
■ Observe que um detalhe importante da implementação em torno da abordagem de sobrecarga do 
operador é
operadores em questão são aqueles já implementados na linguagem estabelecida de biblioteca / núcleo ou 
se a
ferramenta de diferenciação fornece seus próprios operadores. autograd é um exemplo de uma ferramenta
de diferenciação automática que
sobrecarrega a biblioteca numpy estabelecida enquanto que a theano fornece seus próprios operadores 
para os quais
operações diferenciais são implementadas.

Diferenciação automática prática com o Autograd
Vamos agora fazer um exercício prático com diferenciação automática usando um pacote do Python chamado Autograd.
O Autograd implementa a diferenciação automática do modo reverso e pode calcular derivadas para
Código Python e Numpy.
Figura 9­9. Sobrecarga do Operador

Page 153
Capítulo 9 ■ Diferenciação Automática
144
Listagem 9­1. Encontrar gradiente para fxx
x
x
1
2
1
2
2
2
1
2

,
(
) =
+

(
)
#Wrapper Around Numpy
import autograd.numpy como numpy
#Function para gerar gradientes
de grad grad importação autograd
# Definir a função
def f (x1, x2): retorna numpy.sqrt (x1 * x1 + x2 * x2)
#Compute o gradiente na primeira variável de entrada x1
g_x1_f = grad (f, 0)
#Compute o gradiente na segunda variável de entrada x2
g_x2_f = grad (f, 1)
#Avaliar e imprimir o valor da função em x1 = 1, x2 = 2
imprimir f (1,2)
#Produtos 2.23
#Avaliar e imprimir o valor do gradiente de x1 em x1 = 1, x2 = 2
print g_x1_f (1,2)
#Produz 0,44
#Avaliar e imprimir o valor do gradiente de x2 em x1 = 1, x2 = 2
print g_x2_f (1,2)
#Produz 0,89
Vamos começar pegando a função que usamos para discussão ao longo deste capítulo,
fxx
x
x
1
2
1
2
2
2
1
2

,
(
) =
+

(
) e encontrar o gradiente. Como será evidente, o Autograd torna isso realmente fácil.
A Listagem 9­1 ilustra isso.
Autograd fornece uma função de utilidade para verificar a correção dos gradientes calculados. Listagem 9­2
ilustra isso. É uma boa ideia realizar tais verificações, especialmente quando estamos computando gradientes para
funções de perda complicadas envolvendo instruções de fluxo de controle.
Listagem 9­2. Verificando o gradiente para fxx
x
x
1
2
1
2
2
2
1
2

,
(
) =
+

(
)
de autograd.util import quick_grad_check
# Definir a função
def f (x1, x2): retorna numpy.sqrt (x1 * x1 + x2 * x2)
#Computa e verifica o gradiente para os valores fornecidos
quick_grad_check (f, 1.0, extra_args = [2.0])
#Saída
#
#Checendo o gradiente de <função f em 0x10504bed8> em 1.0
# Projeção do cliente OK
# (graduação numérica: 0,447213595409, graduação analítica: 0,4472135955)

Página 154
Capítulo 9 ■ Diferenciação Automática
145
Listagem 9­3. Regressão Logística usando o Autograd
import pylab
import sklearn.datasets
import autograd.numpy como np
de grad grad importação autograd
# Gere os dados
train_X, train_y = sklearn.datasets.make_moons (500, ruído = 0,1)
# Definir as funções de ativação, previsão e perda para Regressão Logística
ativação de def (x):
return 0.5 * (np.tanh (x) + 1)
def prever (pesos, entradas):
retornar a ativação (np.dot (entradas, pesos))
perda de def (pesos):
preds = predict (pesos, train_X)
label_probabilities = preds * train_y + (1 ­ preds) * (1 ­ train_y)
return ­np.sum (np.log (label_probabilities))
# Calcular o gradiente da função de perda
gradient_loss = grad (perda)
# Definir os pesos iniciais
pesos = np.array ([1.0, 1.0])
Descida mais íngreme
loss_values = []
learning_rate = 0.001
para eu na faixa (100):
loss_values.append (loss (pesos))
step = gradient_loss (pesos)
pesos ­ = passo * learning_rate
# Traçar o limite de decisão
x_min, x_max = trem_X [:, 0] .min () ­ 0,5, trem_X [:, 0] .max () + 0,5
y_min, y_max = trem_X [:, 1] .min () ­ 0,5, trem_X [:, 1] .max () + 0,5
x_mesh, y_mesh = np.meshgrid (np.arange (x_min, x_max, 0.01), np.arange (y_min, y_max, 0.01))
Z = predizer (pesos, np.c_ [x_mesh.ravel (), y_mesh.ravel ()])
Z = Z.reshape (x_mesh.shape)
cs = pylab.contourf (x_mesh, y_mesh, Z, cmap = pylab.cm.espectral)
pylab.scatter (train_X [:, 0], train_X [:, 1], c = train_y, cmap = pylab.cm.espectral)
pylab.colorbar (cs)
# Traçar a perda em cada etapa
pylab.figure ()
pylab.plot (loss_values)
pylab.xlabel ("Steps")
pylab.ylabel ("Loss")
pylab.show ()
Page 155
Capítulo 9 ■ Diferenciação Automática
146
Vamos agora calcular gradiente para algo um pouco mais complicado, a função de perda para logística
regressão. Vamos também encaixar o modelo usando a descida mais íngreme. Listagem9­1 mostra o código para o mesmo, e
As Figuras  9­10 e 9­11 mostram o limite de decisão e a perda ao longo dos degraus de descida mais íngremes.
Figura 9­10. Limite de decisão e dados de treinamento para a regressão logística
Figura 9­11. Perda de etapas para a regressão logística

Resumo
Neste capítulo, cobrimos os fundamentos da diferenciação automática, que é comumente referida como
retropropagação na comunidade da Rede Neural. A chave retirada para o leitor neste capítulo é que
diferenciação automática permite o cálculo de gradientes para funções de perda arbitrariamente complexas e é
uma das principais tecnologias capacitadoras para a aprendizagem profunda. O leitor deve também internalizar os conceitos 
de
diferenciação automática e como é diferente da diferenciação simbólica e numérica.

Página 156
147
© Nikhil Ketkar 2017
N. Ketkar, Aprendizado Profundo com Python , DOI 10.1007 / 978­1­4842­2766­4_10

CAPÍTULO 10

Introdução às GPUs
Este capítulo apresenta ao leitor a computação baseada em GPU (Graphics Processing Unit), que tem sido
e continuará a desempenhar um grande papel na aplicação bem­sucedida do Deep Learning em uma variedade de aplicações
domínios. Normalmente, um praticante de aprendizagem profunda está trabalhando com bibliotecas de alto nível como 
Keras ou Theano,
que traduz automaticamente o cálculo para ser executado sem problemas para CPU ou GPU. Enquanto em um
maioria dos casos, não é necessário que um praticante de aprendizagem profunda compreenda o funcionamento
a GPU (como muitas bibliotecas de alto nível estão disponíveis), é essencial estar ciente das noções básicas.
A essência da computação baseada em GPU é a noção de Instrução Única, Dados Múltiplos (SIMD),
em que o mesmo cálculo está sendo realizado em paralelo (sobre os núcleos de maio) em vários pontos de dados.
Este paradigma computacional é muito adequado para operações de álgebra linear pesada de computação. Como nós vimos
Nos capítulos anteriores, a computação central envolvida na formação de modelos de aprendizagem profunda é o cálculo de
gradientes e atualizando os parâmetros com base nesses gradientes. No coração desta mentira linear básica algébrica
operações (produtos de ponto, multiplicações matriciais vetoriais, etc.) e esta computação baseada em GPU é
adequado para treinamento (e fazer previsões) usando o mesmo.
Vamos começar descrevendo os principais elementos de tal computação baseada em GPU. Figura 10­1 esquematicamente
ilustra esses elementos­chave.

Página 157
Capítulo 10 ■ Introdução ao Gpus
148
Os seguintes pontos devem ser observados:
1. A computação relacionada à aprendizagem profunda envolve algum código a ser executado
sequencialmente e algum código de computação intensiva que pode ser paralelizado.
2. Normalmente, o código sequencial envolve o carregamento dos dados do disco, etc., que é
manipulado pela CPU.
3. O código computacionalmente pesado normalmente envolve o cálculo dos gradientes e
atualizando os parâmetros. Os dados para este cálculo são primeiro transferidos para a GPU
memória, e este cálculo acontece na GPU.
4. Em seguida, os resultados são trazidos de volta para a memória principal para
em processamento.
5. Pode haver vários blocos desse código computacionalmente pesado entrelaçado
com código seqüencial.
■ Observe que há dois ecossistemas principais construídos em torno do Gpus: um é o Cuda, que é 
específico da nvidia, e
openCL, que é neutro de fornecedor. Nós estaremos cobrindo conceitos sobre computação Gpu no 
contexto de openCL.
Vamos começar observando o modelo geral de programação para computação baseada em GPU, conforme descrito
pelo OpenCL. OpenCL é um framework neural de fornecedores para computação heterogênea envolvendo CPUs, GPUs,
DSPs (Digital Signal Processors), e FPGAs (Field Programmable Gate Arrays), etc. A Figura  10­2 ilustra
a visão física do sistema.
Figura 10­1. Computação baseada em GPU

Page 158
Capítulo 10 ■ Introdução ao Gpus
149
Os seguintes pontos devem ser observados:
1. O sistema global consiste no host e em vários dispositivos OpenCL.
2. O host refere­se à CPU que executa o sistema operacional, que pode se comunicar
número de dispositivos OpenCL.
3. Os dispositivos OpenCL são heterogêneos, como em diferentes. Eles podem estar envolvendo
CPUs, GPUs, DSPs (Processadores de Sinal Digital) e FPGAs (Programável em Campo)
Gate Arrays), etc.
4. Os dispositivos OpenCL contêm uma ou mais unidades de computação.
Vamos agora olhar a visão lógica de um sistema OpenCL ilustrado na Figura  10­3..
Figura 10­2. Visão Física do Sistema OpenCL

Page 159
Capítulo 10 ■ Introdução ao Gpus
150
Os seguintes pontos devem ser observados:
1. Um programa OpenCL é executado no sistema host.
2. O programa OpenCL se comunica com dispositivos OpenCL usando o comando
filas. Cada dispositivo OpenCL possui uma fila de comandos separada.
3. Cada dispositivo OpenCL contém dados em sua memória, enviados para ele pelo programa
correndo no host.
4. Cada dispositivo OpenCL executa código enviado para ele pelo programa host, chamado de
núcleo.
5. O programa host, as filas de comando, os dados e os kernels juntos
constituem um contexto de execução.
6. O contexto de execução é essencialmente o envolvimento lógico do heterogêneo
computação. O programa hospedeiro orquestra esse cálculo enviando dados
e código a ser executado para os dispositivos OpenCL e obtendo os resultados.
Figura 10­3. Visão Lógica do Sistema OpenCL

Página 160
Capítulo 10 ■ Introdução ao Gpus
151
Vamos agora dar uma olhada no layout da memória lógica em um dispositivo OpenCL. A Figura  10­4 ilustra o mesmo.
Os seguintes pontos devem ser observados:
1. Um dispositivo OpenCL possui uma memória global, acessível ao programa host
bem como todos os kernels em execução no dispositivo.
Figura 10­4. Memória do dispositivo

Page 161
Capítulo 10 ■ Introdução ao Gpus
152
2. Um dispositivo OpenCL tem uma memória constante, que é como a memória global, mas
é somente leitura para um kernel em execução.
3. Um Item de Trabalho é a unidade lógica do paralelismo e tem sua própria memória privada.
Apenas o código do kernel correspondente a este item de trabalho específico está ciente disso
memória.
4. Um Grupo de Trabalho é a unidade lógica de sincronização e contém um número
de itens de trabalho. Note que qualquer sincronização só pode ser feita dentro de um
Grupo.
5. Um grupo de trabalho tem sua própria memória local que só pode ser acessada de dentro
Grupo de Trabalho.
Vamos agora dar uma olhada no modelo de programação em relação a um dispositivo OpenCL (Figura 10­5).
Figura 10­5. Espaço de índice bidirecional de NDRange

Page 162
Capítulo 10 ■ Introdução ao Gpus
153
Os seguintes pontos devem ser observados:
1. Um kernel OpenCL é lançado para executar o trabalho em dados já transferidos
para a memória do dispositivo. Durante o lançamento, o número de grupos de trabalho e
números de itens de trabalho em cada grupo de trabalho são logicamente especificados.
2. O kernel é chamado em paralelo para cada item de trabalho em um grupo de trabalho. Grupos de trabalho
executar em nenhuma ordem particular e um kernel pode descobrir o item de trabalho atual
identificador e identificador do grupo de trabalho.
3. A sincronização pode acontecer apenas dentro de um grupo de trabalho.
4. Um identificador de item de trabalho pode ser de 1, 2 ou 3 dimensões (NDRange). Basicamente isso
facilita escrever kernels para 1­D (série temporal), 2­D (imagens) e 3­D
conjuntos de dados (volumes).
Vamos agora introduzir algumas notações que nos permitirão descrever a indexação. Vamos assumir o
a indexação é 2­D, mas o mesmo raciocínio se aplica aos dados 1­D ou 3­D. Denotamos por ( G x , G y ) a indexação global
espaço. Vamos agora ver como esse espaço de indexação global é dividido em grupos de trabalho e itens de trabalho. Para
Por conveniência, definimos offsets ( F x , F y ) que definem a parte da indexação que não é dividida em trabalho.
itens e grupos de trabalho. Deixe ( S x , S y ) definir o tamanho do grupo de trabalho e ( W x , W y ) definir o número de 
trabalho
grupos. Ao longo de linhas semelhantes, vamos ( g x , g y ) denotar os identificadores globais, ( s x , s y ) denotando os 
identificadores locais, e
let ( w x , w y ) denota os identificadores do grupo de trabalho. Então, a relação entre identificadores locais e globais é
descrito como ( g x , g y ) = ( w x S x + s x + F x , w y S y + s y + F y ).
Escrever um kernel para um dado cálculo basicamente envolve alavancar este mecanismo de identificador e
as invocações paralelas dos kernels sobre itens de trabalho e grupos de trabalho para executar a tarefa em questão. Listagens
10­2 e 10­3 ilustram isso para adição de vetores e multiplicação de matrizes, respectivamente. Listagem10­1 simplesmente
imprime os detalhes do sistema OpenCL que o leitor pode usar para determinar os detalhes de seu sistema.
Listagem 10­1. Obtendo informações sobre GPUs
importar pyopencl como cl
print "Plataformas e Dispositivos OpenCL"
para plataforma em cl.get_platforms ():
print "Nome da plataforma:", platform.name
print "Fornecedor de plataformas", platform.vendor
print "Versão da Plataforma:", platform.version
print "Perfil da plataforma:", platform.profile
para dispositivo em platform.get_devices ():
print "\ n"
print "\ tNome do dispositivo", device.name
print "\ tTipo de dispositivo", cl.device_type.to_string (device.type)
imprima "\ tTempo Máximo de Velocidade do Relógio", "{0} Mhz" .format (device.max_clock_frequency)
print "\ tDispositivos de computação de dispositivos", "{0}". format (device.max_compute_units)
print "\ tDispositivos de Memória Local", "{0: .0f} KB" .format (device.local_mem_size / 1024.0)
print "\ tTemperatura constante do dispositivo", "{0: .0f} KB" .format (device.max_constant_buffer_
tamanho / 1024.0)
print "\ tAtualização global do dispositivo" "{0: .0f} GB" .format (device.global_mem_size /
(1024 * 1024 * 1024,0))
# Plataformas e dispositivos OpenCL
# Nome da plataforma: Apple
# Fornecedor de plataforma Apple

Página 163
Capítulo 10 ■ Introdução ao Gpus
154
# Versão da plataforma: OpenCL 1.2 (18 de novembro de 2015 20:45:47)
# Perfil da plataforma: FULL_PROFILE
#
#
# Nome do dispositivo CPU Intel (R) Core (TM) i7­4770HQ @ 2.20GHz
# CPU do tipo de dispositivo
# Device Max Clock Speed 2200 Mhz
# Unidades de computação de dispositivos 8
# Memória Local do Dispositivo 32 KB
# Memória constante do dispositivo 64 KB
# Device Global Memory 16 GB
#
#
# Nome do dispositivo Iris Pro
# Tipo de dispositivo GPU
# Device Max Clock Speed 1200 Mhz
# Unidades de computação de dispositivos 40
# Memória Local do Dispositivo 64 KB
# Memória constante do dispositivo 64 KB
# Device Global Memory 2 GB
Listagem 10­2. Adição de vetores
import numpy como np
importar pyopencl como cl
tempo de importação
vector1 = np.random.random (5000000) .asty (np.float32)
vector2 = np.random.random (5000000) .astype (np.float32)
cl_context = cl.create_some_context ()
queue = cl.CommandQueue (cl_context)
mf = cl.mem_flags
vector1_in_gpu = cl.Buffer (cl_context, mf.READ_ONLY | mf.COPY_HOST_PTR, hostbuf = vector1)
vector2_in_gpu = cl.Buffer (cl_context, mf.READ_ONLY | mf.COPY_HOST_PTR, hostbuf = vector2)
result_in_gpu = cl.Buffer (cl_context, mf.WRITE_ONLY, vetor1.nbytes)
cl_program = cl.Program (cl_context, "" "
__kernel void sum (
__global const float * vetor1, __global const float * vetor2, __global flutuante * resultado)
{
int i = get_global_id (0);
resultado [i] = vetor1 [i] + vetor2 [i];
}
""").construir()
t0 = time.time ()
cl_program.sum (fila, vector1.shape, Nenhum, vector1_in_gpu, vetor2_in_gpu, result_in_gpu)
t1 = time.time ()
gpu_time = t1 ­ t0
print "GPU Time", gpu_time

Page 164
Capítulo 10 ■ Introdução ao Gpus
155
result_in_numpy = np.empty_like (vector1)
cl.enqueue_copy (queue, result_in_numpy, result_in_gpu)
t0 = time.time ()
cpu_result = vector1 + vector2
t1 = time.time ()
cpu_time = t1 ­ t0
print "CPU Time", cpu_time
print "Norm of Difference", np.linalg.norm (result_in_numpy ­ cpu_result)
# GPU Time 0.00202608108521
# CPU Time 0.00995397567749
# Norma da diferença 0.0
Listagem 10­3. Multiplicação da matriz
import numpy como np
importar pyopencl como cl
tempo de importação
matrix1 = np.random.random ((500,500)). astype (np.float32)
matrix2 = np.random.random ((500,500)). astype (np.float32)
cl_context = cl.create_some_context ()
queue = cl.CommandQueue (cl_context)
mf = cl.mem_flags
matrix1_in_gpu = cl.Buffer (cl_context, mf.READ_ONLY | mf.COPY_HOST_PTR, hostbuf = matriz1)
matrix2_in_gpu = cl.Buffer (cl_context, mf.READ_ONLY | mf.COPY_HOST_PTR, hostbuf = matriz2)
result_in_gpu = cl.Buffer (cl_context, mf.WRITE_ONLY, matrix1.nbytes)
cl_program = cl.Program (cl_context, "" "
__kernel void product (
int size, __global const float * matrix1, __global const float * matrix2, __global float
*resultado)
{
int i = get_global_id (0);
int j = get_global_id (1);
resultado [i + size * j] = 0;
para (int k = 0; k <tamanho; k ++)
{
resultado [i + tamanho * j] + = matriz1 [k + tamanho * i] * matriz2 [j + tamanho * k];
}
}
""").construir()
t0 = time.time ()
cl_program.product (queue, matrix1.shape, nenhum, np.int32 (len (matriz1)), matrix1_in_gpu,
matrix2_in_gpu, result_in_gpu)
t1 = time.time ()
gpu_time = t1 ­ t0
print "GPU Time", gpu_time

Page 165
Capítulo 10 ■ Introdução ao Gpus
156
result_in_numpy = np.empty_like (matriz1)
cl.enqueue_copy (queue, result_in_numpy, result_in_gpu)
t0 = time.time ()
cpu_result = np.dot (matriz1, matriz2)
t1 = time.time ()
cpu_time = t1 ­ t0
print "CPU Time", cpu_time
print "Norm of Difference", np.linalg.norm (result_in_numpy ­ cpu_result.T)
# GPU Time 0.00202608108521
# CPU Time 0.00995397567749
# Norma da diferença 0.0
Resumo
Neste capítulo, introduzimos o leitor na computação baseada em GPU, que é uma das chaves que permitem
tecnologias para Deep Learning.
Um ponto importante a ser observado é que, neste capítulo, abordamos os fundamentos do cálculo da GPU usando
OpenCL, que é neutro de fornecedor. Os conceitos se aplicam com pequena variação a outra GPU específica do fornecedor
bibliotecas de computação como o CUDA, que é mais antigo e popular em comparação com o OpenCL. O leitor
É aconselhável experimentar os exemplos nas listagens de código­fonte no capítulo seguinte, enquanto estiver lendo
a documentação do CUDA, que seria muito mais fácil de seguir, dado que o leitor internalizou
as fundações. Bibliotecas como cuDNN, que é uma biblioteca baseada em CUDA para aprendizagem profunda, é 
recomendada
leitura adicional. Deve­se notar, no entanto, que em muitos casos, quando se trata de aplicar a aprendizagem profunda a um
problema do mundo real, basta usar bibliotecas de alto nível como Theano e Keras, que geram código GPU.
O segundo ponto­chave a ser observado é a importância da computação baseada em GPU para o Deep Learning. o
instrução única, paradigma de dados múltiplos (SIMD) é ideal para a aprendizagem profunda, como a maior parte da 
computação com
O respeito à aprendizagem profunda se resume a descida de gradiente estocástica (SGD). No coração do SGD nós temos o
cálculo de gradientes, que são essencialmente operações algébricas lineares (vetor / matriz). Como conjuntos de dados e
os tamanhos dos parâmetros crescem, torna­se essencial executar o SGD de forma escalonável e as GPUs atualmente
são o paradigma computacional mais adequado.

Página 166
157
© Nikhil Ketkar 2017
N. Ketkar, Aprendizado Profundo com Python , DOI 10.1007 / 978­1­4842­2766­4

∎ A
Funções de ativação, 25–27, 29–31
Adadelta, 121
Algoritmo Adagrad, 120
Adam, 121
Adjointmode. Veja o modo reverso
Inteligência Artificial (AI), 1
metodologia, 1
Algoritmos ML, 2
problema / domínio da tarefa, 1
Autograd, 31, 143–144, 146
Diferenciação automática
fundamentos, 133
modo de avanço, 134–138
implementação, 141
sobrecarga do operador, 142
modo reverso, 138–139, 141
transformação de código­fonte, 141–142
hands­on com Autograd, 143–144, 146
diferenciação numérica, 131–132
diferenciação simbólica, 132–133

∎ B
Método de diferença inversa, 131
Distribuição de Bernoulli, 23, 26
RNN bidirecional, 89­90
Classificação binária, 5­6
Entropia cruzada binária, 23, 25

∎ C
Abordagem de diferença central, 132
Funções compostas, 133
Gráfico computacional, 135–136, 138
Código computacionalmente pesado, 148
Código de computação intensiva, 148
Carrossel de erro constante, 93
Blocos de agrupamento de detectores de convolução, 70, 72, 73
Redes neurais de convolução (CNNs)
blocos de convolução­detector­pooling, 70, 72, 73
intuição, 75–76
operação, 61
camadas totalmente conectadas, 66
intuição, 62, 64
uma dimensão, 63
operação de pooling, 68–69
interações esparsas na camada, 67
pesos amarrados, 68
duas dimensões, 64–65
variantes, 74–75
Funções de custo
computação de 20
usando a máxima verossimilhança
entropia cruzada binária, 23
entropia cruzada, 23–24
erro quadrado, 24
Modo linear de cotangente. Vejo
Modo reverso
Correlação cruzada, 61, 64
Entropia cruzada, 23­25

∎ D
Aprendizagem Profunda
avanços em áreas afins, 3
inteligência artificial, 1
contexto histórico, 1–3
instalando bibliotecas, 4
pré­requisitos, 3
Profundidade da rede, 18
Memória do dispositivo, 153
Processadores de Sinal Digital (DSPs), 148
Chuva torrencial, 125

∎ E
SGD Equilibrado, 122
Gradiente explosivo, 90­91

Índice
Página 167
■ ÍNDICE
158
∎ F
Redes neurais Feedforward, 19
função, 15
hands­on com o Autograd, 31
para regressão, 29–30
estrutura, 17–18
treinamento, 21–22
unidade, 15
forma vetorial, 18­19
Field Programmable Gate Arrays (FPGAs), 148
Modo de avanço, 134–138
Camada totalmente conectada, 66, 73, 75

∎ G
Generalização, 7, 12
valores reais e previstos, 10–11
conjunto de dados para regressão, 9
mínimos quadrados, 9
capacidade do modelo, 12
Métrica RMSE, 10
vs. memorização, 7­9
Espaço de indexação global, 153
Memória global, 151
Métodos baseados em gradientes, 25
Unidade de Processamento Gráfico (GPU)
código computacionalmente pesado, 148
código de computação intensiva, 148
elementos­chave, 148
código seqüencial, 148
SIMD, 147

∎ H
Camadas ocultas, 17
Hogwild, 124
Tangente hiperbólica, 28

∎ I, J
Formas simbólicas intermediárias, 133

∎ K
Keras, 95
função de ativação, 97–98, 100, 103–104
Adadelta, 107
blocos de construção, 95
gráfico computacional, 95
redes neurais de convolução, 104–105, 107
camadas de abandono, 107
aplainar camadas, 107
funcionalidade, 95
IMDB, 109
IMDD, 109
dimensionalidade de entrada e saída, 95, 97­98
função de perda, 95, 97
LSTM, 95, 107, 109
classificação multiclasse, 99–100
otimizadores, 102–103
algoritmo de otimização, 95
operação de pooling, 107
regressão, 100–102
construção sequencial, 95, 97­98, 100
rede neural de camada única, 96
Ativação softmax, 98, 107
theano, 95
dois detectores de convolução, 107
rede neural de duas camadas, 97

∎ L
Unidade linear, 26
Regressão Logística, 146
Memória de Longo Prazo (LSTM), 93
Funções de perda, 20, 21, 25

∎ M
Aprendizado de máquina
classificação binária, 5­6
generalização, 7–12
intuição, 5
regressão, 6­7
regularização, 12–14
Multiplicação de matrizes, 155–156
Máxima Verossimilhança
funções de custo, 22
entropia cruzada binária, 23
entropia cruzada, 23–24
erro quadrado, 24
princípio 4
Distribuição Multinomial, 23

∎ N
Gradiente acelerado de Nesterov (NAS), 119
Diferenciação numérica, 131–132
Biblioteca Numpy, 143

∎ O
OpenCL, 148
filas de comando, 150
definido, 148
memória do dispositivo, 151
memória global, 151
GPUs, 153–154
heterogêneo, 149

Página 168
■ ÍNDICE
159
núcleo, 150
memória privada, 152
visão lógica do sistema, 150
visão física do sistema, 149
índice NDRange bidimensional
espaço, 152
grupos de trabalho, 152, 153
Sobrecarga do operador, 142
Camada de saída, 17

∎ P, Q
Operação de agrupamento, 68, 76
Memória particular, 152

∎ R
RandomStreams, 47
Variação aleatória, 7
Unidade Linear Retificada (ReLU), 27
Redes Neurais Recorrentes (RNNs)
noções básicas, 77­80, 82
bidirecional, 89–90
equações, 77–78, 80
recorte gradiente, 91–92
explosão gradiente, 90­91
LSTM, 93
notação, 77
aponta para ser lembrado, 82
recorrência usando saída, 79
professor forçando, 89
treinamento, 82­86, 88
desenrolando, 83­85, 87
gradientes de fuga, 90­92
Regressão, 6­7
Regularização, 12–14
Retropropagação Resiliente, 122
Modo reverso, 138–141, 143
Algoritmo RMSProp, 120–121
Erro quadrático médio da raiz (RMSE), 6–7
Aprendizagem mecânica, 12

∎ S
Scipy, 132
Código Sequencial, 148
Unidade sigmóide, 26
Função simples, 134
Instrução única, vários dados
(SIMD), 147
Função de ativação Softmax, 89
Camada Softmax, 27
Unidades Softmax, 25
Transformação de código­fonte, 141–142
Erro ao quadrado, 24
Descida de gradiente estocástica (SGD), 111
variações algorítmicas, 118
Adadelta, 121
Algoritmo Adagrad, 120
Adam, 121
recozimento e aprendizagem de horários de taxa, 120
SGD Equilibrado, 122
impulso, 118–119
NAS, 119
Retropropagação Resiliente, 122
RMSProp, 120–121
lote, 114
lote vs . estocástico, 114
desafios, 114
mínimos locais, 115
pontos de sela, 115–116
selecionando taxa de aprendizado, 116–117
progresso lento em vales estreitos, 118
com Downhill, 126–127
gerando dados, 126
função de perda, 127
treinamento e validação, 129
variantes, 130
método de descida mais íngreme, 112–113
problemas de otimização, 111–112
mini­lote estocástico, 114
exemplo único estocástico, 114
truques e dicas
função de ativação, escolha de, 123
normalização em lote, 123
Chuva torrencial, 125
parada antecipada, 124
ruído gradiente, 124
Hogwild, 124
inicializando parâmetros, 123
SGD paralelo e distribuído, 124
Dados de entrada de pré­processamento, 122
valor alvo de pré­processamento, 123
embaralhando dados, 123
Diferenciação simbólica, 132–133
SymPy, 133

∎ T
Modo linear tangente. Ver modo de avanço
Função de ativação Tanh, 78, 80, 89
Professor forçando, 88­89
TensorFlow, 95
Theano, 95, 143
definição, 33
hands­on, 34
funções de ativação, 37, 39
gradientes de computação, 42
funções com escalares e vetores, 34–37
gradientes, 41

Página 169
■ ÍNDICE
160
Dobradiça implementada usando Max, 55
regressão linear, 51–52
regressão logística, 49­50
funções de perda, 42–43
rede neural, 53–54
fluxos aleatórios, 47–48
regularização, 45–46
variável compartilhada, 40–41
interruptor / if­else, 54
fluxo de trabalho para uso, 33

∎ U
Unidades, 15, 17
tangente hiperbólica, 28
unidade linear, 26
ReLU, 27
Unidade sigmóide, 26
Camada Softmax, 27
Processo de desenrolamento, 83–85, 87

∎ V
Gradientes de fuga, 90­93
Adição vetorial, 154–155
Forma vetorial, 18­19

∎ W, X, Y, Z
Largura da camada, 17
Grupos de trabalho, 152, 153
Theano ( cont. )

Вам также может понравиться