E não perca nosso cheat sheet de Keras , que mostra as seis etapas que você precisa seguir para construir redes neurais em Python com exemplos de código!
Apresentando as redes neurais artificiais
Antes de mergulhar no Keras e em como usá-lo para começar com deep learning em Python, vale conhecer um pouco mais sobre redes neurais. Como você leu rapidamente na seção anterior, as redes neurais se inspiram na biologia, onde o termo “rede neural” também é usado para os neurônios. O cérebro humano é um exemplo de rede neural, composto por vários neurônios.
E, como todo mundo sabe, o cérebro é capaz de realizar cálculos bem complexos — é daí que vem a inspiração para as redes neurais artificiais. A rede como um todo é uma ferramenta de modelagem poderosa.
Perceptrons
A rede neural mais simples é o “perceptron”, que, em sua forma mais básica, consiste em um único neurônio. Assim como os neurônios biológicos, que têm dendritos e axônios, o neurônio artificial simples é uma estrutura em árvore com nós de entrada e um único nó de saída conectado a cada nó de entrada. Veja uma comparação visual:
Como você vê na figura, há seis componentes nos neurônios artificiais. Da esquerda para a direita, são eles:
Nós de entrada . Cada nó de entrada tem um valor numérico associado, que pode ser qualquer número real. Lembre que números reais abrangem todo o espectro: positivos, negativos, inteiros ou decimais.
Conexões . Da mesma forma, cada conexão que parte do nó de entrada tem um peso associado, que também pode ser qualquer número real.
Em seguida, todos os valores dos nós de entrada e os pesos das conexões são combinados: eles são usados como entradas para uma soma ponderada : \(y = f(\sum_{i=1}^{D} w_i*x_i)\) , ou, de outro modo, \(y = f(w_1*x_1 + w_2*x_2 + ... w_D*x_D)\) .
Esse resultado será a entrada de uma função de transferência ou ativação . No caso mais simples (mas trivial), essa função seria a identidade, \(f(x)=x\) ou \(y=x\) . Nesse caso, \(x\) é a soma ponderada dos nós de entrada e das conexões. Porém, assim como um neurônio biológico só dispara quando supera um certo limiar, o neurônio artificial também só dispara quando a soma das entradas supera um limiar, por exemplo 0. Isso não acontece com a função identidade! A forma mais intuitiva é pensar em um sistema como:
\(f(x) = 0\) se \(x<0\) \(f(x) = 0.5\) se \(x=0\) \(f(x) = 1\) se \(x>0\)
Claro, dá para imaginar que a saída não será uma linha suave: será uma função descontínua. Como isso pode atrapalhar o tratamento matemático, costuma-se usar uma variante contínua, a função sigmoide. Um exemplo que você talvez conheça é a função logística. Usá-la gera um resultado bem mais suave!
Como resultado, você tem o nó de saída , associado à função (como a sigmoide) da soma ponderada dos nós de entrada. Observe que a sigmoide é uma função matemática em forma de “S”; Você vai ler mais sobre isso adiante.
Por fim, o perceptron pode ter um parâmetro adicional, o bias , que você pode considerar como o peso associado a um nó de entrada extra permanentemente igual a 1. O valor do bias é crucial porque permite deslocar a função de ativação para a esquerda ou para a direita, o que pode determinar o sucesso do aprendizado.
Note que, como consequência lógica desse modelo, perceptrons só funcionam com dados numéricos. Isso implica converter quaisquer dados nominais em formato numérico.
Agora que você sabe que perceptrons trabalham com limiares, o salto para usá-los em classificação é pequeno: o perceptron pode considerar que qualquer saída acima de um certo limiar indica que uma instância pertence a uma classe, enquanto uma saída abaixo indica que pertence à outra. A linha reta em que a saída é igual ao limiar vira a fronteira entre as duas classes.
Perceptrons multicamadas
Redes de perceptrons formam perceptrons multicamadas, e é isso que este tutorial vai implementar em Python com a ajuda do Keras! Perceptrons multicamadas também são conhecidos como “redes neurais feed-forward”. Como você já deve ter imaginado, são mais complexos que o perceptron simples, pois consistem em vários neurônios organizados em camadas. O número de camadas costuma ser limitado a duas ou três, mas, teoricamente, não há limite!
As camadas funcionam de forma parecida com neurônios biológicos: as saídas de uma camada servem como entradas para a próxima.
Entre as camadas, distinguimos uma camada de entrada, camadas ocultas e uma camada de saída. Perceptrons multicamadas costumam ser totalmente conectados. Isso significa que há uma conexão de cada perceptron em uma camada para cada perceptron na camada seguinte. Embora não seja obrigatório, esse é o caso típico.
Note que, enquanto o perceptron só podia representar separações lineares entre classes, o perceptron multicamada supera essa limitação e também representa fronteiras de decisão mais complexas.
Neste tutorial, você vai usar o conjunto de dados de qualidade do vinho que está no conjunto de dados de qualidade do vinho do UCI Machine Learning Repository. Idealmente, você aplicaria deep learning em conjuntos maiores, mas, para fins didáticos, usaremos um menor. A ideia é colocar você para começar com a biblioteca e se familiarizar com o funcionamento das redes neurais.
Talvez você já conheça esse dataset, pois é um dos mais populares para aprender a resolver problemas de machine learning. Aqui, ele serve para iniciarmos no deep learning em Python com Keras.
Vamos começar!
Entendendo os dados
Antes de carregar os dados, vale conferir o quanto você realmente sabe sobre vinho (em relação ao dataset, claro). A maioria sabe que existem dois tipos muito populares: tinto e branco.
(Tenho certeza de que há muitos outros, mas, pela simplicidade e pelo meu conhecimento limitado, vou ficar nesses. Perdão aos verdadeiros conhecedores por aí :)).
Saber disso é um começo, mas, para analisar os dados, você vai precisar de um pouco mais.
Primeiro, confira a pasta de descrição dos dados para ver quais variáveis foram incluídas. Geralmente, esse é o primeiro passo para entender seus dados. Acesse esta página para ver a descrição, ou continue a leitura para conhecer melhor seus dados.
Os dados consistem em dois conjuntos relacionados às variantes tintas e brancas do vinho português “Vinho Verde”. Como consta na descrição, você só vai encontrar variáveis físico-químicas e sensoriais neste conjunto. O arquivo de descrição lista as 12 variáveis incluídas; para quem, como eu, não é exatamente especialista em química, segue um breve resumo de cada uma:
Acidez fixa : os ácidos são propriedades essenciais do vinho e contribuem muito para o sabor. Normalmente, a acidez total se divide em dois grupos: ácidos voláteis e não voláteis (ou fixos). Entre os ácidos fixos encontrados nos vinhos estão: tartárico, málico, cítrico e succínico. No dataset, esta variável é expressa em g(\(ácido\ tartárico\) )/\(dm^3\) .
Acidez volátil : é basicamente o processo do vinho virar vinagre. Nos EUA, os limites legais de acidez volátil são 1,2 g/L para vinho tinto de mesa e 1,1 g/L para vinho branco de mesa. Aqui, é expressa em g(\(ácido\ acético\) )/\(dm^3\) .
Ácido cítrico : um dos ácidos fixos presentes nos vinhos. É expresso em g/\(dm^3\) nos dois conjuntos.
Açúcar residual : normalmente refere-se ao açúcar restante após o fim (ou interrupção) da fermentação. É expresso em g/\(dm^3\) nos dados de red e white.
Cloretos : podem contribuir significativamente para o gosto salgado do vinho. Aqui, são expressos em g(\(cloreto\ de\ sódio\) )/\(dm^3\) .
Dióxido de enxofre livre : a parte do dióxido de enxofre adicionada ao vinho que se liga a compostos é dita “ligada”; a parte ativa é a “livre”. O enólogo busca a maior proporção possível de enxofre livre em relação ao ligado. Esta variável é expressa em mg/\(dm^3\) .
Dióxido de enxofre total : soma das frações ligada e livre (SO2). Aqui, é expresso em mg/\(dm^3\) . Existem limites legais para níveis de enxofre: na UE, tintos podem ter até 160 mg/L, enquanto brancos e rosés podem ter cerca de 210 mg/L. Vinhos doces podem ter 400 mg/L. Nos EUA, o limite é 350 mg/L; na Austrália, 250 mg/L.
Densidade : geralmente usada como medida da conversão de açúcar em álcool. Aqui, é expressa em g/\(cm^3\) .
pH (potencial hidrogeniônico): escala numérica que indica acidez ou basicidade do vinho. Soluções com pH menor que 7 são ácidas; com pH maior que 7, básicas. A água pura (pH 7) é neutra. A maioria dos vinhos tem pH entre 2,9 e 3,9, portanto são ácidos.
Sulfatos : no vinho, têm um papel semelhante ao do glúten nos alimentos. Você pode conhecer os sulfitos pelas dores de cabeça que podem causar. Eles são parte comum e considerada necessária na vinificação no mundo todo. Aqui, estão expressos em g(\(sulfato\ de\ potássio\) )/\(dm^3\) .
Álcool : vinho é bebida alcoólica e, como você sabe, a porcentagem de álcool varia de rótulo para rótulo. Não surpreende que essa variável esteja no conjunto, expressa em % vol.
Qualidade : especialistas avaliaram a qualidade do vinho entre 0 (péssimo) e 10 (excelente). O número final é a mediana de pelo menos três avaliações desses especialistas.
Claro que tudo isso é informação básica para começar. Se você é um verdadeiro enófilo, provavelmente sabe tudo isso e muito mais!
Agora é hora de obter os dados!
Carregando os dados
Isso pode ser feito facilmente com a biblioteca de manipulação de dados do Python, o pandas. Siga a convenção de importação e importe o pacote com o alias pd.
Depois, use a função read_csv() para ler os arquivos CSV onde os dados estão armazenados. Além disso, use o argumento sep para especificar que o separador, neste caso, é ponto e vírgula, e não vírgula.
Teste no bloco DataCamp Light abaixo:
# Import pandas
import pandas as pd
# Read in white wine data
white = ___________("http://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-white.csv", sep=';')
# Read in red wine data
red = ___________("http://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-red.csv", sep=';')
Demais! Moleza, né?
Você provavelmente já fez isso mil vezes, mas é sempre um passo essencial para começar. Agora você está pronto para explorar, manipular e modelar seus dados!
Exploração de dados
Com os dados em mãos, fica fácil aprender mais sobre esses vinhos! Uma das primeiras coisas que você vai querer é dar uma olhada rápida nos dois DataFrames:
# Print info on white wine
_____(white.____())
# Print info on red wine
_____(red.____())
Agora é a hora de conferir se a importação deu certo: verifique se os dados contêm todas as variáveis prometidas na descrição do UCI. Além do número de variáveis, cheque a qualidade da importação: os tipos estão corretos? Todas as linhas vieram? Há valores nulos para considerar na limpeza?
Você também pode inspecionar os dados além do info():
# First rows of `red`
red.____()
# Last rows of `white`
white.____()
# Take a sample of 5 rows of `red`
red.______(5)
# Describe `white`
white.________()
# Double check for null values in `red`
pd.isnull(red)
Um rápido recap das funções do pandas: head(), tail() e sample() são ótimas para inspecionar seus dados sem complicação.
Já o describe() oferece estatísticas-resumo que ajudam a avaliar a qualidade dos dados. Você vê que algumas variáveis têm muita diferença entre min e max. Vamos tratar disso depois, por ora é importante estar ciente.
Por fim, você conferiu a presença de nulos em red com isnull(). Essa função é útil quando ainda resta dúvida mesmo após ler os resultados de info().
Dica : confira também se os dados de vinho branco contêm valores nulos. Você pode fazer isso no shell IPython do bloco DataCamp Light logo acima.
Agora que você já inspecionou os dados e viu que a importação correu bem, é hora de aprofundar um pouco.
Visualizando os dados
Uma forma é observar a distribuição de algumas variáveis do conjunto e criar gráficos de dispersão para ver possíveis correlações. Claro, você pode levar isso a outro nível se usar os dados em um projeto próprio.
Álcool
Uma variável que chama a atenção logo de cara é alcohol. Provavelmente é uma das primeiras coisas que você observa ao inspecionar um dataset de vinhos. Você pode visualizar as distribuições com qualquer biblioteca de visualização; aqui, usamos matplotlib para plotar rapidamente:
import matplotlib.pyplot as plt
fig, ax = plt.subplots(1, 2)
ax[0].hist(red.alcohol, 10, facecolor='red', alpha=0.5, label="Red wine")
ax[1].hist(white.alcohol, 10, facecolor='white', ec="black", lw=0.5, alpha=0.5, label="White wine")
fig.subplots_adjust(left=0, right=1, bottom=0, top=0.5, hspace=0.05, wspace=1)
ax[0].set_ylim([0, 1000])
ax[0].set_xlabel("Alcohol in % Vol")
ax[0].set_ylabel("Frequency")
ax[1].set_xlabel("Alcohol in % Vol")
ax[1].set_ylabel("Frequency")
#ax[0].legend(loc='best')
#ax[1].legend(loc='best')
fig.suptitle("Distribution of Alcohol in % Vol")
plt.show()
Como você pode ver na imagem abaixo, os níveis de álcool entre os vinhos tinto e branco são, em geral, parecidos: ficam em torno de 9% de álcool. Claro, há também uma quantidade considerável de observações com 10% ou 11%.
Você pode confirmar usando a função histogram() do pacote numpy para calcular o histograma dos dados white e red, assim:
import numpy as np
print(np.histogram(red.alcohol, bins=[7,8,9,10,11,12,13,14,15]))
print(np.histogram(white.alcohol, bins=[7,8,9,10,11,12,13,14,15]))
Se você se interessa por tutoriais de matplotlib, confira o tutorial de Matplotlib para iniciantes e o tutorial Visualizando dados volumétricos 3D , que mostra como usar a API de eventos do Matplotlib.
Sulfatos
Outra coisa que me interessa é a relação entre sulfatos e qualidade do vinho. Como você leu acima, sulfatos podem causar dor de cabeça, e eu me pergunto se isso influencia a qualidade. Além disso, ouço com frequência que mulheres, especialmente, evitam vinho justamente por isso. Talvez isso afete as notas do vinho tinto?
Vamos dar uma olhada.
import matplotlib.pyplot as plt
fig, ax = plt.subplots(1, 2, figsize=(8, 4))
ax[0].scatter(red['quality'], red["sulphates"], color="red")
ax[1].scatter(white['quality'], white['sulphates'], color="white", edgecolors="black", lw=0.5)
ax[0].set_title("Red Wine")
ax[1].set_title("White Wine")
ax[0].set_xlabel("Quality")
ax[1].set_xlabel("Quality")
ax[0].set_ylabel("Sulphates")
ax[1].set_ylabel("Sulphates")
ax[0].set_xlim([0,10])
ax[1].set_xlim([0,10])
ax[0].set_ylim([0,2.5])
ax[1].set_ylim([0,2.5])
fig.subplots_adjust(wspace=0.5)
fig.suptitle("Wine Quality by Amount of Sulphates")
plt.show()
Como você vê na imagem abaixo, o vinho tinto parece conter mais sulfatos que o branco, que tem menos observações acima de 1 g/\(dm^3\) . Para o vinho branco, há poucas exceções ligeiramente acima de 1 g/\(dm^3\) , enquanto para os tintos isso é mais frequente. Isso talvez explique a máxima de que vinho tinto dá dor de cabeça, mas e a qualidade?
Há vinhos brancos com baixo teor de sulfatos que recebem nota 9, mas, no geral, ainda é difícil interpretar corretamente neste ponto.
Lembre também que a diferença no número de observações pode afetar os gráficos e a interpretação.
Acidez
Além dos sulfatos, a acidez é uma das características mais importantes do vinho para atingir qualidade. Grandes vinhos equilibram acidez, tanino, álcool e doçura. Pesquisando mais, vi que entre 0,2 e 0,4 g/L a acidez volátil não afeta a qualidade; em níveis mais altos, pode dar uma sensação avinagrada e agressiva. Em níveis extremos, indica um vinho seriamente defeituoso.
Vamos testar e criar um gráfico de dispersão de álcool versus acidez volátil. Os pontos devem ser coloridos conforme o rótulo de quality:
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(570)
redlabels = np.unique(red['quality'])
whitelabels = np.unique(white['quality'])
import matplotlib.pyplot as plt
fig, ax = plt.subplots(1, 2, figsize=(8, 4))
redcolors = np.random.rand(6,4)
whitecolors = np.append(redcolors, np.random.rand(1,4), axis=0)
for i in range(len(redcolors)):
redy = red['alcohol'][red.quality == redlabels[i]]
redx = red['volatile acidity'][red.quality == redlabels[i]]
ax[0].scatter(redx, redy, c=redcolors[i])
for i in range(len(whitecolors)):
whitey = white['alcohol'][white.quality == whitelabels[i]]
whitex = white['volatile acidity'][white.quality == whitelabels[i]]
ax[1].scatter(whitex, whitey, c=whitecolors[i])
ax[0].set_title("Red Wine")
ax[1].set_title("White Wine")
ax[0].set_xlim([0,1.7])
ax[1].set_xlim([0,1.7])
ax[0].set_ylim([5,15.5])
ax[1].set_ylim([5,15.5])
ax[0].set_xlabel("Volatile Acidity")
ax[0].set_ylabel("Alcohol")
ax[1].set_xlabel("Volatile Acidity")
ax[1].set_ylabel("Alcohol")
#ax[0].legend(redlabels, loc='best', bbox_to_anchor=(1.3, 1))
ax[1].legend(whitelabels, loc='best', bbox_to_anchor=(1.3, 1))
#fig.suptitle("Alcohol - Volatile Acidity")
fig.subplots_adjust(top=0.85, wspace=0.7)
plt.show()
As cores na imagem são escolhidas aleatoriamente com o módulo random do NumPy. Você pode mudar isso passando uma lista para as variáveis redcolors ou whitecolors. Certifique-se de que elas sejam compatíveis (exceto por 1, já que o dado de vinho branco tem um valor de quality único a mais que o tinto), caso contrário as legendas não vão bater!
Veja o gráfico completo aqui:
Na imagem acima, os níveis mencionados parecem valer especialmente para o vinho branco: a maioria dos rótulos com nota 8 tem acidez volátil de 0,5 ou menos, mas é difícil afirmar se há efeito direto sobre a qualidade, pois os pontos estão muito concentrados de um lado do gráfico.
Esta é apenas uma exploração rápida. Se quiser aprofundar essa etapa em projetos próprios, confira nossos posts de exploração de dados, como os tutoriais de análise exploratória em Python e data profiling em Python , que guiam você pelo básico de EDA.
Fechando a análise exploratória
Talvez tenha sido muita informação, então vale um pequeno resumo do que pode ser importante para o restante do tutorial:
Algumas variáveis dos conjuntos têm valores bastante distantes entre si. Vamos lidar com isso na próxima seção.
Você está em um cenário ideal: não há valores nulos nos datasets.
A maioria dos vinhos incluídos tem cerca de 9% de álcool.
Vinho tinto parece conter mais sulfatos do que o vinho branco, que tem menos casos acima de 1 g/\(dm^3\) .
A maioria dos vinhos tinha acidez volátil de 0,5 ou menos. No momento, não há relação direta com a qualidade.
Até agora, você observou separadamente os dados de vinho branco e tinto. Em alguns aspectos eles diferem, em outros são bem parecidos. Será que dá para classificar entradas em branco ou tinto com base nas variáveis?
Só há um jeito de descobrir: pré-processar os dados e modelá-los para ver o que acontece!
Pré-processar dados
Agora que você explorou os dados, é hora de agir com base nos insights! Vamos pré-processar para começar a construir sua própria rede neural!
# Add `type` column to `red` with value 1
___['type'] = 1
# Add `type` column to `white` with value 0
_____['type'] = 0
# Append `white` to `red`
wines = red.______(white, ignore_index=True)
Aqui, você define ignore_index como True porque não quer manter os rótulos de índice de white ao anexar os dados a red: você quer que os índices continuem de onde pararam em red, e não duplicar rótulos ao juntar os dois conjuntos.
Intermezzo: matriz de correlação
Agora que você tem o conjunto completo, é uma boa ideia fazer uma exploração rápida novamente; Você já sabe algumas coisas olhando os dois conjuntos separadamente e agora pode buscar insights mais sólidos.
Como pode ser difícil interpretar gráficos, também vale plotar uma matriz de correlação. Ela dá uma visão mais rápida de quais variáveis se correlacionam:
import seaborn as sns
corr = wines.corr()
sns.heatmap(corr,
xticklabels=corr.columns.values,
yticklabels=corr.columns.values)
sns.plt.show()
Como esperado, há variáveis que correlacionam, como density e residual sugar. Também volatile acidity e type estão mais conectadas do que parecia olhando os conjuntos separadamente; e já era esperado que free sulfur dioxide e total sulfur dioxide se correlacionassem.
Muito interessante!
Conjuntos de treino e teste
Dados desbalanceados geralmente se referem a um problema em classificação quando as classes não estão igualmente representadas. A maioria dos datasets de classificação não tem exatamente o mesmo número de instâncias por classe, mas pequenas diferenças não costumam importar. Você precisa garantir que as duas classes de vinho estejam presentes no treinamento. Mais que isso, a quantidade de instâncias das duas classes deve ser mais ou menos equivalente para não favorecer uma ou outra nas previsões.
Neste caso, parece haver desbalanceamento, mas vamos seguir assim por enquanto. Depois, você pode avaliar o modelo e, se ele for mal, recorrer a undersampling ou oversampling para compensar a diferença de observações.
Por agora, importe train_test_split de sklearn.model_selection e atribua os dados e os rótulos-alvo às variáveis X e y. Você vai ver que precisa achatar o array de rótulos para usar X e y como entrada de train_test_split(). Mãos à obra no bloco abaixo!
# Import `train_test_split` from `sklearn.model_selection`
from sklearn.model_selection import train_test_split
# Specify the data
X=wines.ix[:,0:11]
# Specify the target labels and flatten the array
y=np.ravel(wines.type)
# Split the data up in train and test sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=42)
Você já está no caminho para construir sua primeira rede neural, mas falta cuidar de uma coisa! Lembra do que descobrimos ao olhar os resumos dos dados white e red?
Isso mesmo: alguns valores estavam bem distantes. Faz sentido padronizá-los.
Padronizar os dados
Padronização é uma forma de lidar com valores em escalas muito diferentes. O scikit-learn oferece um jeito prático de padronizar: importe StandardScaler de sklearn.preprocessing e você estará pronto para escalar os dados de treino e teste!
from sklearn. preprocessing import StandardScaler
scaler = StandardScaler( ) . fit( X_train)
X_train = scaler. transform( X_train)
X_test = scaler. transform( X_test) Tecnologia
Agora que seus dados estão pré-processados, vamos ao trabalho de verdade: construir sua rede neural para classificar vinhos.
Modelar dados
Antes de modelar, volte à pergunta original: dá para prever se um vinho é tinto ou branco olhando suas propriedades químicas, como acidez volátil ou sulfatos?
Como você só tem duas classes (branco e tinto), vamos fazer uma classificação binária. Como “binária” sugere, é 0 ou 1, sim ou não. Como redes neurais só trabalham com dados numéricos, você já codificou tinto como 1 e branco como 0.
Um tipo de rede que funciona bem nesse problema é o perceptron multicamadas. Como vimos no início, esse tipo de rede costuma ser totalmente conectada. Ou seja, vamos construir uma pilha simples de camadas totalmente conectadas. Quanto à função de ativação, vale usar uma das mais comuns para se familiarizar com Keras e redes neurais: a relu.
Como começar a montar o perceptron multicamadas? Um jeito rápido é usar o modelo Sequential do Keras: uma pilha linear de camadas. Você cria o modelo passando uma lista de instâncias de camada para o construtor, que você inicia com model = Sequential().
Depois, vale lembrar a estrutura: camada de entrada, camadas ocultas e camada de saída. Ao montar o modelo, é importante informar o formato da entrada logo na primeira camada. O modelo precisa saber que formato esperar — por isso você sempre vai ver os argumentos input_shape, input_dim, input_length ou batch_size na documentação e nos exemplos práticos.
Neste caso, vamos usar uma camada Dense, que é totalmente conectada. Camadas densas implementam: output = activation(dot(input, kernel) + bias). Sem função de ativação, a camada Dense teria apenas duas operações lineares: produto escalar e soma.
Na primeira camada, o argumento activation recebe relu. Você também vê que input_shape foi definido. Essa é a input da operação acima: o modelo recebe arrays de formato (12,), ou (*, 12). Por fim, a primeira camada tem 12 como valor inicial para units em Dense(), que é a dimensionalidade do espaço de saída (12 unidades ocultas). Isso significa que o modelo vai gerar arrays (*, 12). Não se preocupe se isso não estiver 100% claro ainda; você verá mais adiante!
As units representam o kernel da fórmula acima, ou a matriz de pesos criada pela camada, composta por todos os pesos dados a todos os nós de entrada. Note que não incluímos bias no exemplo abaixo, pois não definimos o argumento use_bias como TRUE, o que também seria possível.
A camada intermediária também usa ativação relu. A saída dela terá forma (*,8).
Você finaliza com uma camada Dense de tamanho 1. A camada final usa função sigmoide para que a saída seja uma probabilidade — um valor entre 0 e 1 indicando a chance da amostra ter alvo “1”, ou seja, o vinho ser tinto.
# Import `Sequential` from `keras.models`
from keras.models import Sequential
# Import `Dense` from `keras.layers`
from keras.layers import Dense
# Initialize the constructor
model = Sequential()
# Add an input layer
model.add(Dense(12, activation='relu', input_shape=(11,)))
# Add one hidden layer
model.add(Dense(8, activation='relu'))
# Add an output layer
model.add(Dense(1, activation='sigmoid'))
No fim, há duas decisões de arquitetura fundamentais: quantas camadas usar e quantas “unidades ocultas” em cada uma.
Neste caso, você escolheu 12 unidades ocultas na primeira camada: como dito, é a dimensionalidade do espaço de saída. Em outras palavras, você define o quanto de liberdade a rede terá para aprender representações. Se permitir mais unidades, a rede aprende representações mais complexas, mas o treino fica mais caro e mais sujeito a overfitting.
Lembre que overfitting ocorre quando o modelo é complexo demais: ele passa a explicar ruído aleatório e não o relacionamento subjacente. Em outras palavras, modela bem demais os dados de treino!
Quando há poucos dados de treino, prefira uma rede pequena, com poucas camadas ocultas (tipicamente uma, como no exemplo).
Se quiser informações sobre o modelo criado, use o atributo output_shape ou a função summary(), entre outros. Alguns dos mais básicos estão abaixo.
Tente executá-los para ver exatamente os resultados e o que dizem sobre o modelo que você acabou de criar:
Compilar e ajustar
Agora é hora de compilar e ajustar o modelo aos dados: mais uma vez, use compile() e fit() para fazer isso.
model. compile ( loss= 'binary_crossentropy' ,
optimizer= 'adam' ,
metrics= [ 'accuracy' ] )
model. fit( X_train, y_train, epochs= 20 , batch_size= 1 , verbose= 1 ) Tecnologia
Na compilação, você configura o modelo com o otimizador adam e a função de perda binary_crossentropy. Além disso, pode monitorar a acurácia durante o treino passando ['accuracy'] no argumento metrics.
optimizer e loss são argumentos obrigatórios para compilar o modelo. Entre os algoritmos de otimização mais populares estão Stochastic Gradient Descent (SGD), ADAM e RMSprop. Dependendo do algoritmo escolhido, você ajusta parâmetros como taxa de aprendizado e momentum. A escolha da loss depende da tarefa: para regressão, costuma-se usar o erro quadrático médio (MSE). Como vimos neste exemplo, usamos binary_crossentropy para classificação binária (tinto ou branco). Já em classificação multiclasse, usa-se categorical_crossentropy.
Depois, treine o modelo por 20 épocas (iterações sobre todas as amostras em X_train e y_train), em lotes de 1 amostra. Você também pode definir o argumento verbose. Com 1, você vê uma barra de progresso.
Em outras palavras, você treina o modelo por um número definido de épocas (passagens pelo conjunto de treino), seguido de testes no conjunto de validação. O batch size define quantas amostras são propagadas pela rede a cada vez. Assim, você otimiza a eficiência porque evita carregar padrões demais na memória ao mesmo tempo.
Prever valores
Vamos colocar o modelo para trabalhar! Você pode fazer previsões para os rótulos do conjunto de teste com predict(). Passe o conjunto de teste para prever os rótulos. Aqui, o resultado é armazenado em y_pred:
y_pred = model. predict( X_test) Tecnologia
Antes de avaliar o modelo, já dá para ter uma noção rápida da acurácia conferindo como y_pred e y_test se comparam:
y_pred[ : 5 ] Tecnologia
array( [ [ 0 ] ,
[ 1 ] ,
[ 0 ] ,
[ 0 ] ,
[ 0 ] ] , dtype= int32) Tecnologia
y_test[ : 5 ] Tecnologia
array( [ 0 , 1 , 0 , 0 , 0 ] ) Tecnologia
Parece que bate, mas nada como números concretos, certo?
Avaliar o modelo
Agora que você construiu o modelo e o usou para prever dados inéditos, é hora de avaliar sua performance. Você pode comparar visualmente as previsões com os rótulos reais (y_test) ou usar métricas para medir o desempenho. Aqui, vamos usar evaluate(). Passe os dados e rótulos de teste e, se quiser, defina verbose como 1 para ver mais logs.
score = model. evaluate( X_test, y_test, verbose= 1 )
print ( score) Tecnologia
[ 0.025217213829228164 , 0.99487179487179489 ] Tecnologia
O score é uma lista com a combinação de perda e acurácia. Aqui, ambos parecem ótimos, mas lembre que os dados estavam desbalanceados: havia mais observações de vinho branco do que tinto. A acurácia pode estar apenas refletindo a distribuição de classes, prevendo white com frequência por serem mais abundantes!
Antes de reorganizar os dados, é sempre bom testar outras métricas. Para isso, você pode usar o scikit-learn (importado como sklearn, como antes ao criar os conjuntos de treino e teste).
Neste caso, vamos testar algumas métricas básicas de classificação, como:
Matriz de confusão: um resumo em tabela com acertos e tipos de erros. Idealmente, você só vê números na diagonal, o que indica que todas as previsões foram corretas!
Precisão (precision): mede a exatidão do classificador. Quanto maior, mais preciso.
Recall (abrangência): mede a completude do classificador. Quanto maior, mais casos ele cobre.
F1-score: média harmônica ponderada de precisão e recall.
Kappa de Cohen: acurácia normalizada pelo desbalanceamento entre classes.
from sklearn. metrics import confusion_matrix, precision_score, recall_score, f1_score, cohen_kappa_score
confusion_matrix( y_test, y_pred) Tecnologia
array( [ [ 1585 , 3 ] ,
[ 8 , 549 ] ] ) Tecnologia
precision_score( y_test, y_pred) Tecnologia
0.994565217391 Tecnologia
recall_score( y_test, y_pred) Tecnologia
0.98563734290843807 Tecnologia
f1_score( y_test, y_pred) Tecnologia
0.99008115419296661 Tecnologia
cohen_kappa_score( y_test, y_pred) Tecnologia
0.98662321692498967 Tecnologia
Todos esses resultados estão excelentes! Você criou um modelo bem preciso, apesar de ter significativamente mais linhas de vinho branco.
Mandou bem!
Mais alguns experimentos
Você já construiu seu primeiro modelo com sucesso, mas dá para ir além. Que tal testar o seguinte e ver o efeito? Como vimos, as duas decisões arquiteturais principais envolvem as camadas e as unidades ocultas. Ótimos pontos de partida:
Você usou 1 camada oculta. Tente usar 2 ou 3;
Use camadas com mais ou menos unidades ocultas;
Use a coluna quality como rótulo-alvo e o restante dos dados (incluindo a coluna codificada type!) como entradas. Agora você tem um problema de classificação multiclasse!
Que tal também experimentar outra função de ativação? Em vez de relu, tente tanh e veja o resultado!
Prevendo a qualidade do vinho
Seu modelo de classificação foi muito bem para uma primeira rodada!
Mas dá para ir muito além de testar estruturas mais complexas que o perceptron multicamadas. Que tal criar uma rede neural para prever a qualidade do vinho?
Neste caso, vamos assumir que quality é uma variável contínua: a tarefa deixa de ser classificação binária e vira uma regressão ordinal. É um tipo de regressão usado para prever uma variável ordinal: o valor de quality existe em uma escala arbitrária onde a ordem relativa entre valores é significativa. A escala 0–10 de “muito ruim” a “muito bom” é um exemplo.
Observe que também dá para encarar esse problema como classificação, tratando as notas como classes fixas.
Em qualquer caso, isso significa que seus rótulos-alvo serão a coluna quality nos DataFrames red e white para a segunda parte deste tutorial. Isso exige um pré-processamento adicional.
Pré-processar dados
Como a variável quality vira sua classe-alvo, você precisa isolá-la do restante. Coloque wines.quality em y e os dados de wines, exceto a coluna quality, em x.
Depois, você estaria pronto para dividir em treino e teste, mas aqui vamos por outro caminho (embora você pudesse!). Nesta segunda parte, vamos usar validação k-fold, que divide os dados em K partições. Geralmente K=4 ou 5. Em seguida, você instancia modelos idênticos e treina cada um em uma partição, avaliando nas demais. A pontuação de validação é a média das K pontuações obtidas.
Você vai ver como fazer isso a seguir. Por enquanto, use StandardScaler para deixar os dados em boa forma antes de ajustar o modelo, como antes.
# Isolate target labels
y = wines.________
# Isolate data
X = wines.drop('quality', axis=_)
Lembre que você também precisa escalar novamente, já que havia grandes diferenças em alguns valores dos dados red, white (e, consequentemente, wines).
Teste no bloco DataCamp Light abaixo. Todas as bibliotecas necessárias já foram carregadas!
# Scale the data with `StandardScaler`
X = ________________.fit_transform(X)
Pronto, você está novamente no ponto de modelar a rede neural!
Modelar a arquitetura da rede neural
Com os dados pré-processados de novo, é hora de construir outro perceptron multicamadas. Mesmo sendo para regressão, a arquitetura pode ser bem parecida, com duas camadas Dense.
Não esqueça que a primeira é a camada de entrada. Você precisa passar o formato de entrada. Aqui, vamos usar input_dim para informar as dimensões dos dados à camada Dense.
# Import `Sequential` from `keras.models`
from keras.models import Sequential
# Import `Dense` from `keras.layers`
from keras.layers import Dense
# Initialize the model
model = Sequential()
# Add input layer
model.add(Dense(64, input_dim=12, activation='relu'))
# Add output layer
model.add(Dense(1))
Note de novo: a primeira camada definida é a de entrada, que precisa saber as dimensões de entrada (12 neste caso — não esqueça de contar a coluna Type gerada na primeira parte!). Usamos relu novamente e, mais uma vez, sem bias. O número de unidades ocultas é 64.
Sua rede termina com uma única unidade Dense(1), sem ativação. Essa é a configuração típica para regressão escalar, quando você tenta prever um valor contínuo.
Compilar o modelo e ajustar os dados
Com o modelo pronto, vamos compilá-lo e ajustá-lo. Mas espere: e as partições de validação K-fold? Exato.
import numpy as np
from sklearn. model_selection import StratifiedKFold
seed = 7
np. random. seed( seed)
kfold = StratifiedKFold( n_splits= 5 , shuffle= True , random_state= seed)
for train, test in kfold. split( X, Y) :
model = Sequential( )
model. add( Dense( 64 , input_dim= 12 , activation= 'relu' ) )
model. add( Dense( 1 ) )
model. compile ( optimizer= 'rmsprop' , loss= 'mse' , metrics= [ 'mae' ] )
model. fit( X[ train] , Y[ train] , epochs= 10 , verbose= 1 ) Tecnologia
Use compile() para compilar o modelo e depois fit() para ajustá-lo. Para compilar, defina pelo menos optimizer e loss. Aqui, podemos usar rsmprop, um dos otimizadores mais populares, e mse como função de perda, típica em regressão.
O argumento extra metrics é uma função para julgar a performance do modelo. Em regressão, é comum usar o erro absoluto médio (MAE). Você vai ler mais na próxima seção.
Passe os dados e rótulos de treino para fit(), defina quantas épocas rodar, o batch size e, se quiser, verbose como 1 para ver mais logs (pode levar um tempinho).
Avaliar o modelo
Como antes, também vale avaliar seu modelo. Além de adicionar y_pred = model.predict(X[test]) ao código acima, é uma boa ideia usar métricas do sklearn, como você fez na primeira parte.
Para isso, use o erro quadrático médio (MSE) e o erro absoluto médio (MAE). O primeiro, também chamado de “desvio quadrático médio” (MSD), mede a média dos quadrados dos erros. Em outras palavras, quantifica a diferença entre o estimador e o que é estimado. Assim, você conhece melhor a qualidade do estimador: ele é sempre não negativo e quanto mais próximo de zero, melhor.
O segundo, MAE, quantifica quão perto as previsões estão dos resultados finais.
Adicione estas linhas ao bloco anterior (atenção à identação):
mse_value, mae_value = model. evaluate( X[ test] , Y[ test] , verbose= 0 )
print ( mse_value)
0.522478731072
print ( mae_value)
0.561965950103 Tecnologia
Além de MSE e MAE, você pode usar o R² (função de score de regressão). O ideal é buscar 1.0 (o melhor). Porém, o score também pode ser negativo!
from sklearn. metrics import r2_score
r2_score( Y[ test] , y_pred)
0.3125092543 Tecnologia
À primeira vista, os números são ruins, certo? A boa notícia é que agora você pode experimentar otimizações para melhorar os resultados.
É disso que trata a última seção!
Ajuste fino do modelo
Fazer fine-tuning provavelmente será rotina, já que nem todo problema é tão direto quanto o da primeira parte. Como vimos, há duas decisões críticas que você vai querer ajustar: quantas camadas usar e quantas “unidades ocultas” escolher para cada camada.
No começo, isso vai ser uma jornada e tanto.
Adicionando camadas
O que acontece se você adicionar outra camada ao modelo? E se ficasse assim?
model = Sequential( )
model. add( Dense( 64 , input_dim= 12 , activation= 'relu' ) )
model. add( Dense( 64 , activation= 'relu' ) )
model. add( Dense( 1 ) ) Tecnologia
Unidades ocultas
Experimente também aumentar o número de unidades ocultas e estude o efeito na avaliação, por exemplo:
model = Sequential( )
model. add( Dense( 128 , input_dim= 12 , activation= 'relu' ) )
model. add( Dense( 1 ) ) Tecnologia
Lembre, no geral, como você não tem toneladas de dados, o overfitting pode (e vai) piorar. Por isso, use uma rede pequena.
Mais experimentos: parâmetros de otimização
Além de adicionar camadas e brincar com as unidades ocultas, você também pode ajustar (alguns) parâmetros do algoritmo de otimização passado a compile(). Até agora, você passou uma string, como rmsprop, ao argumento optimizer.
Mas não precisa ser sempre assim!
Tente, por exemplo, importar RMSprop de keras.models e ajustar a taxa de aprendizado lr. Você também pode alterar valores padrão dos outros parâmetros de RMSprop(), mas isso não é recomendado. Mais informações aqui .
from keras. optimizers import RMSprop
rmsprop = RMSprop( lr= 0.0001 )
model. compile ( optimizer= rmsprop, loss= 'mse' , metrics= [ 'mae' ] ) Tecnologia
Experimente também outros algoritmos, como Stochastic Gradient Descent (SGD). Percebe algum efeito?
from keras. optimizers import SGD, RMSprop
sgd= SGD( lr= 0.1 )
model. compile ( optimizer= sgd, loss= 'mse' , metrics= [ 'mae' ] ) Tecnologia
Vá além!
Este tutorial foi apenas o começo da sua jornada em deep learning com Python e Keras. Ainda há muito a explorar, então por que não fazer o curso Deep Learning in Python da DataCamp? Enquanto isso, não deixe de consultar a documentação do Keras , se ainda não fez isso. Você vai encontrar mais exemplos e informações sobre funções, argumentos, mais camadas etc. Sem dúvida, será um recurso indispensável enquanto você aprende a trabalhar com redes neurais em Python! Se preferir um livro que explica os fundamentos de deep learning (com Keras) e seu uso na prática, vale muito ler o Deep Learning in Python do François Chollet.
Até aqui, você provavelmente já conhece machine learning, um ramo da ciência da computação que estuda o design de algoritmos capazes de aprender. Hoje, o foco é em deep learning, uma subárea de machine learning com um conjunto de algoritmos inspirados na estrutura e no funcionamento do cérebro. Esses algoritmos geralmente são chamados de redes neurais artificiais (ANN). O deep learning é um dos campos mais quentes em ciência de dados, com muitos estudos de caso e resultados impressionantes em robótica, reconhecimento de imagens e inteligência artificial (IA).
Uma das bibliotecas Python mais poderosas e fáceis de usar para desenvolver e avaliar modelos de deep learning é o Keras; Ele encapsula as bibliotecas de computação numérica Theano e TensorFlow. A grande vantagem é que você consegue começar com redes neurais de um jeito simples e até divertido.
O tutorial de Keras para iniciantes de hoje vai apresentar o básico de deep learning em Python: