Theano - Exemplo de treinamento trivial
Theano é bastante útil no treinamento de redes neurais, onde temos que calcular repetidamente o custo e gradientes para atingir um ótimo. Em grandes conjuntos de dados, isso se torna intensivo em termos de computação. Theano faz isso de forma eficiente devido às suas otimizações internas do gráfico computacional que vimos anteriormente.
Declaração do Problema
Devemos agora aprender como usar a biblioteca Theano para treinar uma rede. Pegaremos um caso simples onde começamos com um conjunto de dados de quatro recursos. Calculamos a soma desses recursos após aplicar um determinado peso (importância) a cada recurso.
O objetivo do treinamento é modificar os pesos atribuídos a cada recurso para que a soma atinja o valor alvo de 100.
sum = f1 * w1 + f2 * w2 + f3 * w3 + f4 * w4
Onde f1, f2, ... são os valores do recurso e w1, w2, ... são os pesos.
Deixe-me quantizar o exemplo para uma melhor compreensão da definição do problema. Assumiremos um valor inicial de 1,0 para cada recurso e tomaremos w1 igual a0.1, w2 é igual a 0.25, w3 é igual a 0.15e w4 é igual a 0.3. Não há uma lógica definida na atribuição dos valores de peso, é apenas nossa intuição. Assim, a soma inicial é a seguinte -
sum = 1.0 * 0.1 + 1.0 * 0.25 + 1.0 * 0.15 + 1.0 * 0.3
Qual soma para 0.8. Agora, continuaremos modificando a atribuição de peso para que esta soma se aproxime de 100. O valor resultante atual de0.8 está longe de nosso valor alvo desejado de 100. Em termos de aprendizado de máquina, nós definimos costcomo a diferença entre o valor alvo menos o valor de saída atual, normalmente elevado ao quadrado para explodir o erro. Reduzimos esse custo em cada iteração, calculando os gradientes e atualizando nosso vetor de pesos.
Vamos ver como toda essa lógica é implementada no Theano.
Declarando Variáveis
Primeiro declaramos nosso vetor de entrada x da seguinte forma -
x = tensor.fvector('x')
Onde x é uma matriz unidimensional de valores flutuantes.
Nós definimos um escalar target variável conforme fornecido abaixo -
target = tensor.fscalar('target')
Em seguida, criamos um tensor de pesos W com os valores iniciais conforme discutido acima -
W = theano.shared(numpy.asarray([0.1, 0.25, 0.15, 0.3]), 'W')
Definindo a Expressão Theano
Agora calculamos a saída usando a seguinte expressão -
y = (x * W).sum()
Observe que na declaração acima x e Wsão os vetores e não variáveis escalares simples. Agora calculamos o erro (custo) com a seguinte expressão -
cost = tensor.sqr(target - y)
O custo é a diferença entre o valor alvo e a saída atual, ao quadrado.
Para calcular o gradiente que nos diz a que distância estamos do alvo, usamos o sistema integrado grad método da seguinte forma -
gradients = tensor.grad(cost, [W])
Agora atualizamos o weights vetor obtendo uma taxa de aprendizagem de 0.1 como segue -
W_updated = W - (0.1 * gradients[0])
Em seguida, precisamos atualizar nosso vetor de pesos usando os valores acima. Fazemos isso na seguinte declaração -
updates = [(W, W_updated)]
Definindo / invocando a função Theano
Por último, definimos um function em Theano para calcular a soma.
f = function([x, target], y, updates=updates)
Para invocar a função acima um certo número de vezes, criamos um for loop da seguinte forma -
for i in range(10):
output = f([1.0, 1.0, 1.0, 1.0], 100.0)
Como disse anteriormente, a entrada para a função é um vetor contendo os valores iniciais para os quatro recursos - atribuímos o valor de 1.0para cada recurso sem qualquer motivo específico. Você pode atribuir valores diferentes de sua escolha e verificar se a função finalmente converge. Iremos imprimir os valores do vetor de peso e a saída correspondente em cada iteração. É mostrado no código abaixo -
print ("iteration: ", i)
print ("Modified Weights: ", W.get_value())
print ("Output: ", output)
Lista completa do programa
A lista completa do programa é reproduzida aqui para sua referência rápida -
from theano import *
import numpy
x = tensor.fvector('x')
target = tensor.fscalar('target')
W = theano.shared(numpy.asarray([0.1, 0.25, 0.15, 0.3]), 'W')
print ("Weights: ", W.get_value())
y = (x * W).sum()
cost = tensor.sqr(target - y)
gradients = tensor.grad(cost, [W])
W_updated = W - (0.1 * gradients[0])
updates = [(W, W_updated)]
f = function([x, target], y, updates=updates)
for i in range(10):
output = f([1.0, 1.0, 1.0, 1.0], 100.0)
print ("iteration: ", i)
print ("Modified Weights: ", W.get_value())
print ("Output: ", output)
Ao executar o programa, você verá a seguinte saída -
Weights: [0.1 0.25 0.15 0.3 ]
iteration: 0
Modified Weights: [19.94 20.09 19.99 20.14]
Output: 0.8
iteration: 1
Modified Weights: [23.908 24.058 23.958 24.108]
Output: 80.16000000000001
iteration: 2
Modified Weights: [24.7016 24.8516 24.7516 24.9016]
Output: 96.03200000000001
iteration: 3
Modified Weights: [24.86032 25.01032 24.91032 25.06032]
Output: 99.2064
iteration: 4
Modified Weights: [24.892064 25.042064 24.942064 25.092064]
Output: 99.84128
iteration: 5
Modified Weights: [24.8984128 25.0484128 24.9484128 25.0984128]
Output: 99.968256
iteration: 6
Modified Weights: [24.89968256 25.04968256 24.94968256 25.09968256]
Output: 99.9936512
iteration: 7
Modified Weights: [24.89993651 25.04993651 24.94993651 25.09993651]
Output: 99.99873024
iteration: 8
Modified Weights: [24.8999873 25.0499873 24.9499873 25.0999873]
Output: 99.99974604799999
iteration: 9
Modified Weights: [24.89999746 25.04999746 24.94999746 25.09999746]
Output: 99.99994920960002
Observe que após quatro iterações, a saída é 99.96 e depois de cinco iterações, é 99.99, que está perto de nossa meta desejada de 100.0.
Dependendo da precisão desejada, você pode concluir com segurança que a rede é treinada em 4 a 5 iterações. Após a conclusão do treinamento, procure o vetor de pesos, que após 5 iterações assume os seguintes valores -
iteration: 5
Modified Weights: [24.8984128 25.0484128 24.9484128 25.0984128]
Agora você pode usar esses valores em sua rede para implantar o modelo.