Introdução ao Tensorflow

author
10 minutes, 58 seconds Read

Eu tinha divertido divertido escrevendo software de rede neural nos anos 90, e estive ansioso para tentar criar alguns usando o Tensorflow.

O Quadro de Inteligência da Máquina do Google é o novo hotness agora. E quando o Tensorflow se tornou instalado no PI de framboesa, trabalhando com ele se tornou muito fácil de fazer. Em pouco tempo, fiz uma rede neural que conta com binário. Então eu pensei em passar o que aprendi até agora. Espero que isso torne mais fácil para qualquer outra pessoa que queira experimentá-lo, ou por qualquer pessoa que apenas deseja alguma visão sobre redes neurais.

O que é tensor?

Para citar o site Tensorflow, o Tensorflow é uma “Biblioteca de software de código aberto para computação numérica usando gráficos de fluxo de dados”. O que queremos dizer com “gráficos de fluxo de dados”? Bem, essa é a parte realmente incrível. Mas antes de podermos responder isso, precisaremos falar um pouco sobre a estrutura para uma rede neural simples.

Rede Neural Binary Contador
Noções básicas de uma rede neural

Uma rede neural simples tem algumas unidades de entrada onde a entrada vai. Ele também tem unidades ocultas, chamadas porque da perspectiva de um usuário eles estão literalmente escondidos. e há unidades de saída, da qual recebemos os resultados. Para o lado também são unidades de viés, que estão lá para ajudar a controlar os valores emitidos das unidades ocultas e de saída. Conectando todas essas unidades são um monte de pesos, que são apenas números, cada um deles associado a duas unidades.

A maneira como a instilamos inteligência nessa rede neural é atribuir valores a todos esses pesos. Isso é o que treinar uma rede neural faz, encontrar valores adequados para esses pesos. Uma vez treinados, em nosso exemplo, vamos definir as unidades de entrada para os dígitos binários 0, 0 e 0, respectivamente, o Tensorflow fará coisas com tudo no meio, e as unidades de saída conterão magicamente os dígitos binários 0, 0 e 1 respectivamente. Caso você tenha perdido isso, sabia que o próximo número após binário 000 era 001. Para 001, deve cuspir 010, e assim por diante até 111, em que ele vai cuspir 000. Uma vez que esses pesos estão definidos apropriadamente, Saiba como contar.

Rede Neural Contador Binário com Matrizes
Um passo em “Correndo” A rede neural é multiplicar o valor de cada peso pelo valor de sua unidade de entrada e, em seguida, armazenar o resultado na unidade oculta associada.

Podemos redesenhar as unidades e pesos como matrizes, ou quais são as listas chamadas em Python. De um ponto de vista da matemática, eles são matrizes. Nós redesenhamos apenas uma parte deles no diagrama. Multiplicando a matriz de entrada com a matriz de peso envolve multiplicação de matriz simples, resultando na matriz / lista / matriz oculta de cinco elementos.

De matrizes a tensores

No Tensorflow, essas listas são chamadas de tensores. E o passo de multiplicação de matriz é chamado de operação ou OP no programador – fala, um termo você terá que se acostumar se você planeja ler a documentação do Tensorflow. Levando ainda mais, toda a rede neural é uma coleção de tensores e os ops que operam neles. no todo, eles formam um gráfico.

Gráfico completo do contador binário
Layer1 expandido

Mostrado aqui são os instantâneos tirados de Tensorboard, uma ferramenta para visualizar o gráfico, bem como examinar valores de tensor durante e após o treinamento. Os tensores são as linhas e escritos nas linhas são as dimensões do tensor. Conectar os tensores são todos os ops, embora algumas das coisas que você vêem podem ser duas vezes clicadas para expandir para mais detalhes, como fizemos para Layer1 no segundo instantâneo.

Na parte inferior é X, o nome que atribuímos para um espaço reservado que nos permite fornecer valores para o tensor de entrada. A linha subindo e à esquerda é o tensor de entrada. Continue seguindo essa linha e você encontrará o Matmul Op, que faz a multiplicação matricial com esse tensor de entrada e o tensor que é a outra linha que leva ao Matmul Op. Esse tensor representa os pesos.

Tudo isso era apenas para lhe dar uma ideia pelo que um gráfico e seus tensores e ops estão, dando-lhe uma ideia melhor do que queremos dizer com o Tensorflow sendo uma “biblioteca de software para computação numérica usando gráficos de fluxo de dados”. Mas por que gostaríamos de criar esses gráficos?

Por que criar gráficos?

A API atualmente está estável é uma para o Python, uma linguagem interpretada. As redes neurais são computadas intensivas e uma grande pessoa poderiam ter milhares ou até mesmo milhões de pesos. Computação, interpretando cada passo levaria para sempre.

Então, em vez disso, criamos um gráfico composto de tensores e ops, descrevendo o layout da rede neural, todas as operações matemáticas e até valores iniciais para variáveis. Somente depois que criamos este gráfico, então passamos para o que Tensorflow chama uma sessão. Isso é conhecido como execução diferido. A sessão executa o gráfico usando um código muito eficiente. Não só isso, mas muitas das operações, como a multiplicação matricial, são aquelas que podem ser feitas em uma GPU suportada (unidade de processamento gráfico) e a sessão fará isso para você. Além disso, Tensorflow é BUilil para poder distribuir o processamento em várias máquinas e / ou GPUs. Dar o gráfico completo permite que isso faça isso.

Criando o gráfico de contador binário

E aqui está o código para nossa rede neural de balcão binário. Você pode encontrar o código-fonte completo nesta página do github. Observe que há código adicional para salvar informações para uso com Tensorboard.

Vamos começar com o código para criar o gráfico de tensores e ops.

Importar Tensorflow como TF
sess = tf.interactivesession ()

Num_inputs = 3.
Num_hidden = 5.
Num_Outputs = 3.

Primeiro importamos o módulo Tensorflow, criamos uma sessão para uso posteriormente e, para tornar nosso código mais compreensível, criamos algumas variáveis ​​contendo o número de unidades em nossa rede.

x = tf.placeholder (tf.float32, forma = [nenhum, num_inputs], nome = ‘x’)
y_ = tf.placeholder (tf.float32, forma = [nenhum, num_outputs], nome = ‘y_’)

Em seguida, criamos espaços reservados para nossas unidades de entrada e saída. Um espaço reservado é um Tensorflow Op para coisas que forneceremos valores para mais tarde. X e y_ são agora tensores em um novo gráfico e cada um tem um espaço reservado associado a ele.

Você pode se perguntar por que definimos as formas como [nenhum, num_inputs] e [nenhum, num_outputs], duas listas dimensionais e por que nenhuma para a primeira dimensão? Na visão geral das redes neurais acima, parece que vamos dar uma entrada de cada vez e treinar para produzir uma determinada saída. É mais eficiente, se darmos vários pares de entrada / saída de cada vez, o que é chamado de lote. A primeira dimensão é para o número de pares de entrada / saída em cada lote. Não sabemos quantos estão em um lote até que realmente damos um depois. E, na verdade, estamos usando o mesmo gráfico para treinamento, teste e uso real, então o tamanho do lote nem sempre será o mesmo. Portanto, usamos o objeto Placeholder Python nenhum para o tamanho da primeira dimensão por enquanto.

W_fc1 = tf.truncated_normal ([num_inputs, num_hidden], média = 0,5, stddev = 0,707)
W_fc1 = tf.Variable (w_fc1, nome = ‘w_fc1’)

b_fc1 = tf.truncated_normal ([num_hidden], média = 0,5, stddev = 0,707)
b_fc1 = tf.Variable (b_fc1, nome = ‘b_fc1’)

h_fc1 = tf.nn.relu (tf.matmul (x, w_fc1) + b_fc1)

Seguido, criando camada um dos gráficos de rede neurais: os pesos w_fc1, os vieses b_fc1 e as unidades ocultas h_fc1. O “FC” é um significado de convenção “totalmente conectado”, já que os pesos conectam cada unidade de entrada a cada unidade oculta.

TF.Truncated_normal Resultados em vários ops e tensores que mais tarde atribuirão números aleatórios normalizados, aleatórios a todos os pesos.

As ops variáveis ​​recebem um valor para fazer inicialização com números aleatórios neste caso e mantêm seus dados em várias execuções. Eles também são úteis para salvar a rede neural para um arquivo, algo que você vai querer fazer quando for treinado.

Você pode ver onde estaremos fazendo a multiplicação matricial usando o Matmul op. Também inserimos um add op que irá adicionar os pesos do viés. O relú op executa o que chamamos de uma função de ativação. A multiplicação matricial e a adição são operações lineares. Há um número muito limitado de coisas que uma rede neural pode aprender usando apenas operações lineares. A função de ativação fornece alguma não-linearidade. No caso da função de ativação da RELU, ele define quaisquer valores menores que zero para zero, e todos os outros valores são deixados inalterados. Acredite ou não, fazendo isso abre um outro mundo de coisas que podem ser aprendidas.

W_fc2 = tf.truncated_normal ([num_hidden, num_Outputs], média = 0,5, stddev = 0,707)
W_fc2 = tf.Variable (w_fc2, name = ‘w_fc2’)

b_fc2 = tf.truncated_normal ([num_Outputs], média = 0,5, stddev = 0,707)
b_fc2 = tf.Variable (b_fc2, nome = ‘b_fc2’)

y = tf.matmul (h_fc1, w_fc2) + b_fc2

Os pesos e vieses para camada dois são configurados da mesma forma que para a camada, mas a camada de saída é diferente. Nós novamente faremos uma multiplicação de matriz, desta vez multiplicando os pesos e as unidades ocultas e, em seguida, adicionando os pesos de viés. Nós deixamos a função de ativação para o próximo bit de código.

Resultados = TF.Sigmoid (Y, Name = ‘Results’)

cross_entropy = tf.Reduce_mean (
tf.nn.sigmoid_cross_entropy_with_logits (logits = y, rótulos = y_)))

Sigmóide é outra função de ativação, como o relú que encontramos acima, lá para fornecer não-linearidade. Eu usei sigmóide aqui parcialmente porque a equação sigmóide resulta em valores entre 0 e 1, ideal para o nosso exemplo binário. Eu também usei porque é bom para as saídas onde mais de uma unidade de saída pode ter um valor grande. No nosso caso, para representar o número binário 111, todas as unidades de saída podem ter valores grandes. Ao fazer a classificação de imagem, gostaríamos de algo bem diferente, queremos apenas uma unidade de saída para disparar com um grande valor. Por exemplo, queremos que a unidade de saída que represente girafas tivesse um valor grande se uma imagem contiver uma girafa. Algo como Softmax seria uma boa escolha para classificação de imagens.

Em inspeção íntima, parece que há alguma duplicação. Parece que estamos inserindo o sigmóide duas vezes. Estamos realmente criando dois diferentes, paralelosUtputs aqui. O Tensor Cross_Entronro será usado durante o treinamento da rede neutra. O Tensor dos Resultados será usado quando executamos nossa rede neural treinada mais tarde para qualquer finalidade que seja criada, por diversão no nosso caso. Eu não sei se esta é a melhor maneira de fazer isso, mas é assim que eu inventei.

Train_step = tf.train.rmspropoptimizer (0,25, momentum = 0,5) .minimizar (cross_entrópy)

A última peça que adicionamos ao nosso gráfico é o treinamento. Este é o OP ou OPS que ajustarão todos os pesos com base nos dados de treinamento. Lembre-se, ainda estamos apenas criando um gráfico aqui. O treinamento real acontecerá mais tarde quando fizermos o gráfico.

Há alguns otimizadores para escolher. Eu escolhi tf.train.rmspropoptimizer porque, como o sigmóide, funciona bem para os casos em que todos os valores de saída podem ser grandes. Para classificar as coisas como ao fazer a classificação de imagem, TF.Train.GradientDescententOptimizer pode ser melhor.

Treinamento e usando o contador binário

Tendo criado o gráfico, é hora de fazer o treinamento. Uma vez que seja treinado, podemos usá-lo.

InputVals = [[0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], [1, 0, 0], [1, 0, 1] ,
[1, 1, 0], [1, 1, 1]]
TargetVals = [[0, 0, 1], [0, 1, 0], [0, 1, 1], [1, 0, 0], [1, 0, 1], [1, 1, 0] ,
[1, 1, 1], [0, 0, 0]]

Primeiro, temos alguns dados de treinamento: insertos e alvo. Os insumos contêm as entradas e para cada um, há um valor de destino de destino correspondente. Para inputvals [0] temos [0, 0, 0], e a saída esperada é alvo [0], que é [0, 0, 1] e assim por diante.

Se do_training == 1:
sess.run (tf.global_variables_initializer ())

para i no intervalo (10001):
Se eu% 100 == 0:
train_error = cross_entropy.eval (feed_dict = {x: inputvals, y_: targetvals}))
Imprimir (“passo% d, erro de treinamento% g”% (I, Train_Error))
Se Train_Error <0.0005: pausa sess.run (Train_step, feed_dict = {x: inputvals, y_: targetvals})) Se Save_Reined == 1: Imprimir ("Salvando a rede neural para% s. *"% (save_file)) Saver = tf.train.saver () Saver.Save (Sess, Save_File) O do_Training e Save_Treined podem ser hardcoded e alterado para cada uso, ou podem ser definidos usando argumentos de linha de comando. Primeiro passamos por todas essas opções variáveis ​​e as iniciamos seus tensores. Em seguida, por até 10001 vezes, passamos o gráfico da parte inferior até o Tensor Train_step, a última coisa que adicionamos ao nosso gráfico. Passamos inputvals e targetvals para o OP ou OPS de Train_Step, que nós adicionamos usando o RMSPropoptimizer. Este é o passo que ajusta todos os pesos, de modo que as entradas fornecidas resultarão em algo próximo das saídas de destino correspondentes. Se o erro entre as saídas de destino e as saídas reais ficarem pequenas mais cedo, saíamos do loop. Se você tem milhares de pares de entrada / saída, você poderia dar-lhe um subconjunto deles de cada vez, o lote que falamos anteriormente. Mas aqui temos apenas oito, e assim damos a todos cada vez. Se quisermos, também podemos salvar a rede para um arquivo. Uma vez treinado bem, não precisamos treiná-lo novamente. mais: # Se não estamos treinando, deveremos estar carregando do arquivo Imprimir ("Carregando a rede neural de% s"% (Save_File)) Saver = tf.train.saver () Saver.Restore (Sess, Save_File) # Observação: a restauração de ambas as cargas e inicializa as variáveis Se não estamos treinando, em vez disso, carregamos a rede treinada de um arquivo. O arquivo contém apenas os valores para os tensores que possuem ops variáveis. Não contém a estrutura do gráfico. Portanto, mesmo ao executar um gráfico já treinado, ainda precisamos do código para criar o gráfico. Há uma maneira de salvar e carregar gráficos de arquivos usando MONTAGROS, mas não estamos fazendo isso aqui. Imprimir ('\ NCounting começando com: 0 0 0') res = sess.run (resultados, feed_dict = {x: [[0, 0, 0]]})) Imprimir ('% g% g% g'% (res [0] [0], res [0] [1], res [0] [2]))

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *