Last active
February 22, 2024 15:02
-
-
Save rafaelvareto/21aa689b739f498872962cd92936cdb9 to your computer and use it in GitHub Desktop.
21_02-logistic-regression.ipynb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"cells": [ | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "view-in-github", | |
"colab_type": "text" | |
}, | |
"source": [ | |
"<a href=\"https://colab.research.google.com/gist/rafaelvareto/21aa689b739f498872962cd92936cdb9/21_02-logistic-regression.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "l2ZdhIazr6sO" | |
}, | |
"source": [ | |
"# CIAG 2024 - Regressão Logística\n", | |
"\n", | |
"## Preâmbulo\n", | |
"\n", | |
"O código abaixo consiste dos imports comuns. Além do mais, configuramos as imagens para ficar de um tamanho aceitável e criamos algumas funções auxiliares.\n", | |
"No geral, você pode ignorar a próxima célula." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": { | |
"id": "Gk2LpsyrqVYk" | |
}, | |
"outputs": [], | |
"source": [ | |
"import numpy as np\n", | |
"import torch\n", | |
"import torch.optim as optim\n", | |
"import matplotlib.pyplot as plt\n", | |
"\n", | |
"from sklearn.datasets import make_blobs" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": { | |
"id": "cxaonZmlr-Mc" | |
}, | |
"outputs": [], | |
"source": [ | |
"plt.rcParams['figure.figsize'] = (8, 5)\n", | |
"\n", | |
"plt.rcParams['axes.axisbelow'] = True\n", | |
"plt.rcParams['axes.labelsize'] = 16\n", | |
"plt.rcParams['axes.linewidth'] = 1\n", | |
"plt.rcParams['axes.spines.bottom'] = True\n", | |
"plt.rcParams['axes.spines.left'] = True\n", | |
"plt.rcParams['axes.titlesize'] = 16\n", | |
"plt.rcParams['axes.ymargin'] = 0.1\n", | |
"\n", | |
"plt.rcParams['font.family'] = 'serif'\n", | |
"\n", | |
"plt.rcParams['axes.grid'] = True\n", | |
"plt.rcParams['grid.color'] = 'lightgrey'\n", | |
"plt.rcParams['grid.linewidth'] = .1\n", | |
"\n", | |
"plt.rcParams['xtick.labelsize'] = 16\n", | |
"plt.rcParams['xtick.bottom'] = True\n", | |
"plt.rcParams['xtick.direction'] = 'out'\n", | |
"plt.rcParams['xtick.major.size'] = 10\n", | |
"plt.rcParams['xtick.major.width'] = 1\n", | |
"plt.rcParams['xtick.minor.size'] = 3\n", | |
"plt.rcParams['xtick.minor.width'] = .5\n", | |
"plt.rcParams['xtick.minor.visible'] = True\n", | |
"\n", | |
"plt.rcParams['ytick.labelsize'] = 16\n", | |
"plt.rcParams['ytick.left'] = True\n", | |
"plt.rcParams['ytick.direction'] = 'out'\n", | |
"plt.rcParams['ytick.major.size'] = 10\n", | |
"plt.rcParams['ytick.major.width'] = 1\n", | |
"plt.rcParams['ytick.minor.size'] = 3\n", | |
"plt.rcParams['ytick.minor.width'] = .5\n", | |
"plt.rcParams['ytick.minor.visible'] = True\n", | |
"\n", | |
"plt.rcParams['legend.fontsize'] = 16\n", | |
"\n", | |
"plt.rcParams['lines.linewidth'] = 4\n", | |
"plt.rcParams['lines.markersize'] = 10\n", | |
"\n", | |
"plt.style.use('tableau-colorblind10')\n", | |
"plt.ion()" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "rZIarhsdsA7D" | |
}, | |
"source": [ | |
"## Criando 2 classes linearmente separáveis\n", | |
"\n", | |
"Dando continuidade aos experimentos com classificação e regressão, vamos trabalhar hoje com um dos métodos mais tradicionais em aprendizado de máquina: Regressão Linear (Linear Regression).\n", | |
"\n", | |
"Primeiramente, vamos gerar duas classes de forma aleatória de forma que sabemos de antemão que podem ser separados linearmente." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": { | |
"id": "0rcP_88zr_UK" | |
}, | |
"outputs": [], | |
"source": [ | |
"random_seed = 2024\n", | |
"\n", | |
"features, labels = make_blobs(n_samples=5000, random_state=random_seed, centers=2)\n", | |
"\n", | |
"print('Feature samples:', type(features), features.shape)\n", | |
"print('Label samples:', type(labels), labels.shape)\n", | |
"\n", | |
"for (x_,y_) in zip(features[:5],labels[:5]):\n", | |
" print(x_, y_)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": { | |
"id": "FNc2NuQJsCrC" | |
}, | |
"outputs": [], | |
"source": [ | |
"plt.Figure(figsize=(8, 9))\n", | |
"plt.scatter(features[:,0], features[:,1], c=labels.ravel(), edgecolor='w', alpha=0.75)\n", | |
"plt.show()" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"source": [ | |
"## Mapeando eixo X ao eixo Y com SKLEARN e Regressão Lienar\n", | |
"\n", | |
"Será que encontramos uma maneira de ajudar uma reta de forma que conseguimos minimizar a soma do quadrado das diferenças?" | |
], | |
"metadata": { | |
"id": "3i7iJEFthfYF" | |
} | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"from sklearn.linear_model import LinearRegression\n", | |
"from sklearn.model_selection import train_test_split" | |
], | |
"metadata": { | |
"id": "mD3AD-cRhngV" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "bCJuIoOrU1rF" | |
}, | |
"source": [ | |
"Assim como na aula anterior, **divida sua base de dados em partições treino/teste** de forma que 70% das amostras estejam no conjunto de treino e o restante no conjunto de teste." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": { | |
"id": "fu0ADijzV3LW" | |
}, | |
"outputs": [], | |
"source": [ | |
"# Implemente aqui a sua solução\n", | |
"feat_train, feat_test, lbl_train, lbl_test = # executar train_test_split aqui\n", | |
"\n", | |
"print(feat_train.shape, feat_test.shape)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"source": [ | |
"Se desejamos mapear os valores do eixo X para um valor correspondente no eixo Y, precisaremos, por enquanto, descartar os labels gerados pela função `make_blobs`." | |
], | |
"metadata": { | |
"id": "M_jUE_fpiYUC" | |
} | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"x_axis, y_axis = feat_train[:,0].reshape(-1,1), feat_train[:,1].reshape(-1,1)\n", | |
"x_axis_, y_axis_ = feat_test[:,0].reshape(-1,1), feat_test[:,1].reshape(-1,1)" | |
], | |
"metadata": { | |
"id": "K1HgL4QvizJA" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "markdown", | |
"source": [ | |
"Agora utilizando a classe LinearRegression(), crie um objeto que será responsável em se ajustar as amostras linearmente. Você pode chamar esse objeto de linearR e visualizar os coeficientes e o valor do intercepto imprimindo os seguintes atributos: `coef_` e `intercept_`." | |
], | |
"metadata": { | |
"id": "ouN9Y16li9Tq" | |
} | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"# API: https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LinearRegression.html\n", | |
"\n", | |
"# Implemente aqui a sua solução\n", | |
"linearR = None\n", | |
"\n", | |
"print(linearR.coef_, linearR.intercept_)" | |
], | |
"metadata": { | |
"id": "yMWhKyQAi68O" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"# Visualize a reta que separa ambas as classes\n", | |
"def get_line(x, a, b=0):\n", | |
" # Equacao reduzida da reta\n", | |
" return (a[0] * x) + b\n", | |
"\n", | |
"x_line = np.linspace(-10, 7, 100)\n", | |
"y_line = get_line(x_line, linearR.coef_, linearR.intercept_)\n", | |
"\n", | |
"plt.Figure(figsize=(8, 9))\n", | |
"plt.scatter(feat_train[:,0], feat_train[:,1], c=lbl_train.ravel(), edgecolor='w', alpha=0.75)\n", | |
"plt.plot(x_line, y_line)\n", | |
"plt.xlabel('X-axis')\n", | |
"plt.ylabel('Y-axis')\n", | |
"plt.show()" | |
], | |
"metadata": { | |
"id": "UfuILjoaktbg" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "markdown", | |
"source": [ | |
"Abaixo você pode visualizar a predição para as 10 primeiras amostras do teste utilizando a função `predict`. Implemente a mesma funcão realizando o produto interno (`linearR.coef_`) seguido pela soma do intercepto (`linearR.intercept_`) e verifique se os resultados alcançados são os mesmos." | |
], | |
"metadata": { | |
"id": "9AyTbQ1-lXXg" | |
} | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"y_pred = linearR.predict(x_axis_)\n", | |
"print(y_pred[:10].ravel())\n", | |
"\n", | |
"# Implemente aqui a sua solução\n", | |
"y_pred = None\n", | |
"print(y_pred[:10].ravel())" | |
], | |
"metadata": { | |
"id": "AGfzbBZfl7NV" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "markdown", | |
"source": [ | |
"Agora que você já treinou seu modelo, valide seu resultado utilizando o método `score` com as amostras reservadas para teste e gere um novo gráfico com os resultados." | |
], | |
"metadata": { | |
"id": "j5Ud0kQmnG4q" | |
} | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"# Implemente aqui a sua solução\n", | |
"score = None\n", | |
"print(score)" | |
], | |
"metadata": { | |
"id": "SJzWlfxbnGbx" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "markdown", | |
"source": [ | |
"Vamos computar o *overall_score* $S$ manualmente. Para isso, precisamos calcular a soma dos quadrados residuais $u = \\sum(y_{true} - y_{pred})^2$ e dividi-la pela soma total das diferenças $v = \\sum(y_{true} - \\bar{y}_{true})^2$ de tal forma que $S = 1 - \\frac{u}{v}$." | |
], | |
"metadata": { | |
"id": "L37UH0KCoJLP" | |
} | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"# Implemente aqui a sua solução\n", | |
"y_pred = linearR.predict(x_axis_)\n", | |
"score = None\n", | |
"print(score)" | |
], | |
"metadata": { | |
"id": "lPlIv8UkqW5U" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "_neyKTiJVnhE" | |
}, | |
"source": [ | |
"## Trabalhando com SKLEARN e Regressão Linear" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "zW-VamNUWY76" | |
}, | |
"source": [ | |
"Agora utilizando a classe **LinearRegression()**, crie um objeto que será responsável em separar as amostras linearmente. Você pode chamar esse objeto de *linearR* e visualizar os coeficientes e o valor do intercepto imprimindo os seguintes atributos: *coef_* e *intercept_*." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": { | |
"id": "CNxmScFyU0oI" | |
}, | |
"outputs": [], | |
"source": [ | |
"# API: https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LinearRegression.html\n", | |
"\n", | |
"# Implemente aqui a sua solução\n", | |
"linearR = None\n", | |
"\n", | |
"print(linearR.coef_, linearR.intercept_)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": { | |
"id": "LrJAGSzHYD2d" | |
}, | |
"outputs": [], | |
"source": [ | |
"# Visualize o plano que separa ambas as classes\n", | |
"def get_plane(x1, x2, a, b=0):\n", | |
" return (a[0] * x1) + (a[1] * x2) + b\n", | |
"\n", | |
"x_line, y_line = np.meshgrid(np.linspace(-10, 7, 100), np.linspace(-15, 10, 100))\n", | |
"plane_eq = get_plane(x_line, y_line, linearR.coef_, linearR.intercept_)\n", | |
"\n", | |
"fig = plt.figure(figsize=(16, 9))\n", | |
"\n", | |
"ax = fig.add_subplot(121, projection='3d')\n", | |
"ax.view_init(elev=15, azim=130, roll=0)\n", | |
"ax.scatter(feat_train[:,0], feat_train[:,1], c=lbl_train.ravel(), edgecolor='w', alpha=0.75)\n", | |
"ax.plot_surface(x_line, y_line, plane_eq, color='r', alpha=0.15)\n", | |
"\n", | |
"ax = fig.add_subplot(122, projection='3d')\n", | |
"ax.view_init(elev=5, azim=180, roll=0)\n", | |
"ax.scatter(feat_train[:,0], feat_train[:,1], c=lbl_train.ravel(), edgecolor='w', alpha=0.75)\n", | |
"ax.plot_surface(x_line, y_line, plane_eq, color='r', alpha=0.15)\n", | |
"\n", | |
"plt.show()" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "S2wa8a_Qe3IH" | |
}, | |
"source": [ | |
"Agora que você já treinou seu modelo, valide seu resultado com as amostras reservadas para teste e gere um novo gráfico com os resultados." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": { | |
"id": "7aN-dfeJe3aE" | |
}, | |
"outputs": [], | |
"source": [ | |
"# Implemente aqui a sua solução\n", | |
"score = None\n", | |
"print(score)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": { | |
"id": "p3n6_c0sf2MS" | |
}, | |
"outputs": [], | |
"source": [ | |
"x_line, y_line = np.meshgrid(np.linspace(-10, 7, 100), np.linspace(-15, 10, 100))\n", | |
"plane_eq = get_plane(x_line, y_line, linearR.coef_, linearR.intercept_)\n", | |
"\n", | |
"fig = plt.figure(figsize=(16, 9))\n", | |
"\n", | |
"ax = fig.add_subplot(121, projection='3d')\n", | |
"ax.view_init(elev=15, azim=130, roll=0)\n", | |
"ax.scatter(feat_test[:,0], feat_test[:,1], c=lbl_test.ravel(), edgecolor='w', alpha=0.75)\n", | |
"ax.plot_surface(x_line, y_line, plane_eq, color='r', alpha=0.15)\n", | |
"\n", | |
"ax = fig.add_subplot(122, projection='3d')\n", | |
"ax.view_init(elev=5, azim=180, roll=0)\n", | |
"ax.scatter(feat_test[:,0], feat_test[:,1], c=lbl_test.ravel(), edgecolor='w', alpha=0.75)\n", | |
"ax.plot_surface(x_line, y_line, plane_eq, color='r', alpha=0.15)\n", | |
"\n", | |
"plt.show()" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "H3DxU0gfhgSW" | |
}, | |
"source": [ | |
"## Trabalhando com SKLEARN e Regressão Logística\n", | |
"\n", | |
"Utilizando os mesmos conjuntos de dados (mesma repartição), repita todo o processo acima, mas desta vez trabalhando com a Regressão Logística. Voce pode chamar seu modelo de *logR*, inicialmente recebendo o valor None." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"from sklearn.linear_model import LogisticRegression\n", | |
"\n", | |
"def sigmoid(x):\n", | |
" return 1 / (1 + np.exp(-x))" | |
], | |
"metadata": { | |
"id": "jQjslf1ih8eU" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": { | |
"id": "9o4ayPEIhfeG" | |
}, | |
"outputs": [], | |
"source": [ | |
"# API: https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LogisticRegression.html\n", | |
"\n", | |
"# Implemente aqui a sua solução\n", | |
"logR = None\n", | |
"\n", | |
"print(logR.coef_, logR.intercept_)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": { | |
"id": "CzRE_-8YhveE" | |
}, | |
"outputs": [], | |
"source": [ | |
"# Visualize o plano que separa ambas as classes\n", | |
"def get_plane(x1, x2, a, b=0):\n", | |
" return (a[0,0] * x1) + (a[0,1] * x2) + b\n", | |
"\n", | |
"x_line, y_line = np.meshgrid(np.linspace(-5, 7, 100), np.linspace(-15, 10, 100))\n", | |
"plane_eq = get_plane(x_line, y_line, logR.coef_, logR.intercept_)\n", | |
"\n", | |
"fig = plt.figure(figsize=(16, 9))\n", | |
"\n", | |
"ax = fig.add_subplot(121, projection='3d')\n", | |
"ax.view_init(elev=15, azim=130, roll=0)\n", | |
"ax.scatter(feat_train[:,0], feat_train[:,1], c=lbl_train.ravel(), edgecolor='w', alpha=0.75)\n", | |
"ax.plot_surface(x_line, y_line, plane_eq, color='r', alpha=0.15)\n", | |
"\n", | |
"ax = fig.add_subplot(122, projection='3d')\n", | |
"ax.view_init(elev=5, azim=180, roll=0)\n", | |
"ax.scatter(feat_train[:,0], feat_train[:,1], c=lbl_train.ravel(), edgecolor='w', alpha=0.75)\n", | |
"ax.plot_surface(x_line, y_line, plane_eq, color='r', alpha=0.15)\n", | |
"\n", | |
"plt.show()" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "oTlCRCVGkuUL" | |
}, | |
"source": [ | |
"Agora que você já treinou seu modelo, valide seu resultado com as amostras reservadas para teste e gere um novo gráfico com os resultados." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": { | |
"id": "YVVxLp5gkkP6" | |
}, | |
"outputs": [], | |
"source": [ | |
"# Implemente aqui a sua solução\n", | |
"score = None\n", | |
"print(score)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": { | |
"id": "6l4rl2HLk07T" | |
}, | |
"outputs": [], | |
"source": [ | |
"x_line, y_line = np.meshgrid(np.linspace(-10, 7, 100), np.linspace(-15, 10, 100))\n", | |
"plane_eq = get_plane(x_line, y_line, logR.coef_, logR.intercept_)\n", | |
"\n", | |
"fig = plt.figure(figsize=(16, 9))\n", | |
"\n", | |
"ax = fig.add_subplot(121, projection='3d')\n", | |
"ax.view_init(elev=15, azim=130, roll=0)\n", | |
"ax.scatter(feat_train[:,0], feat_train[:,1], c=lbl_train.ravel(), edgecolor='w', alpha=0.75)\n", | |
"ax.plot_surface(x_line, y_line, plane_eq, color='r', alpha=0.15)\n", | |
"\n", | |
"ax = fig.add_subplot(122, projection='3d')\n", | |
"ax.view_init(elev=5, azim=180, roll=0)\n", | |
"ax.scatter(feat_train[:,0], feat_train[:,1], c=lbl_train.ravel(), edgecolor='w', alpha=0.75)\n", | |
"ax.plot_surface(x_line, y_line, plane_eq, color='r', alpha=0.15)\n", | |
"\n", | |
"plt.show()" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "sCThIxd2sOfi" | |
}, | |
"source": [ | |
"## Trabalhando com PYTORCH e Regressão Logística\n", | |
"\n", | |
"A partir daqui será um pouco diferente, pois ao invés de utilizarmos a biblioteca **SCIKIT-LEARN (SKLEARN)** para resolver nosso problema de regressão, iremos implementar nossa solução utilizando uma pequena rede neural através do framework **PyTORCH**\n", | |
"\n", | |
"### Criando parâmetros para implementação da regressão logística\n", | |
"No bloco abaixo vamos inicializar os pesos de nossa rede, contendo três parâmetros somente, um para cada dimensão dos dados de entrada e mais um para armazenar o intercepto. Perceba que os pesos foram inicializados de forma aleatória." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": { | |
"id": "OPOYVelLsD_S" | |
}, | |
"outputs": [], | |
"source": [ | |
"torch.manual_seed(random_seed)\n", | |
"\n", | |
"# Note que colocaremos o intercepto dentro da matriz de pesos w\n", | |
"W = torch.randn(size=(3, 1), dtype=torch.float64, requires_grad=True)\n", | |
"print('Weight matrix:', W)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "M6dfnRqLoYsV" | |
}, | |
"source": [ | |
"No bloco abaixo, precisamos adicionar uma nova dimensão aos dados de entrada para que possa multiplicar o intercepto da matriz de pesos W (weights) definida acima." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": { | |
"id": "h7DLXPLctcP8" | |
}, | |
"outputs": [], | |
"source": [ | |
"# Com isso, teremos que adicionar o intercepto também nos dados\n", | |
"def add_intercept(X) -> np.ndarray:\n", | |
" X_new = np.zeros(shape=(X.shape[0], X.shape[1] + 1))\n", | |
" X_new[:, 0] = 1\n", | |
" X_new[:, 1:] = X\n", | |
"\n", | |
" return X_new\n", | |
"\n", | |
"if features.shape[1] == 2:\n", | |
" features = add_intercept(features)\n", | |
"print('Features shape:', features.shape)\n", | |
"print('Features example:', features[0])" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "t_34e_BixCv1" | |
}, | |
"source": [ | |
"Para que tudo funcione apropriadamente, temos que converter todos os vetores do tipo array em tensores torch" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": { | |
"id": "6HutcEqbuSYE" | |
}, | |
"outputs": [], | |
"source": [ | |
"print(f'ANTES | Features type: {type(features)} | Labels type: {type(labels)}')\n", | |
"features = torch.from_numpy(features)\n", | |
"labels = torch.from_numpy(labels)\n", | |
"print(f'DEPOIS | Features type: {type(features)} | Labels type: {type(labels)}')" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "jUqNXY8p0jzc" | |
}, | |
"source": [ | |
"### Definindo nosso modelo de regressão logística\n", | |
"\n", | |
"- Definição da saída do modelo, seguindo a seguinte fórmula: $\\hat{y} = \\sigma(\\textbf{w}^\\text{T}\\textbf{x}) $.\n", | |
"- A função $\\sigma$, também chamada de função de ativação, será uma função logística, assumindo o seguinte formato: $\\sigma(z) = \\dfrac{1}{1 + \\exp(-z)}$.\n", | |
"- A função logística, nesse caso uma _sigmoid_, faz com que a saída seja um valor entre $[0, 1]$, em outras palavras a probabilidade $\\mathbb{P}(y = 1)$." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": { | |
"id": "B8V3Wilr0jKk" | |
}, | |
"outputs": [], | |
"source": [ | |
"def model(\n", | |
" X: torch.tensor,\n", | |
" W: torch.tensor\n", | |
"):\n", | |
" def sigmoid(z: torch.tensor):\n", | |
" return 1 / (1 + torch.exp(-z))\n", | |
"\n", | |
" # O produto escalar resulta em um vetor (n, 1), faremos squeeze para tirar a segunda dimensão que é desnecessária\n", | |
" return sigmoid(X @ W).squeeze(dim=1)\n", | |
"\n", | |
"print('First 5 labels:', labels[:5])\n", | |
"print('First 5 predictions:', model(features, W)[:5])" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "twafN-Q2y-31" | |
}, | |
"source": [ | |
"### Definindo nossa função de risco\n", | |
"Definindo nossa função de custo (risco) para informar o quanto o modelo está errando:\n", | |
"\n", | |
"- Definição da função de risco, seguindo a seguinte fórmula:\n", | |
"$ \\mathcal{L} = - \\frac{1}{n} \\sum\\limits_{i=1}^n y \\ln(\\hat{y}) + (1 - y)\\ln(1 - \\hat{y}) $.\n", | |
"- Essa função de risco recebe o nome de ___negative log-likelihood___ ou também de ___binary cross entropy___." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": { | |
"id": "1iph19DSy8jE" | |
}, | |
"outputs": [], | |
"source": [ | |
"def cross_entropy(\n", | |
" y_pred: torch.tensor,\n", | |
" y: torch.tensor\n", | |
"):\n", | |
" return - torch.mean(y * torch.log(y_pred) + (1 - y) * torch.log(1 - y_pred))\n", | |
"\n", | |
"lbl_pred = model(features, W)\n", | |
"loss = cross_entropy(lbl_pred, labels)\n", | |
"print('Loss value:', loss) # Perceba que retorna o valor da função de risco e também a derivada associada no parâmetro grad_fn" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "1ArRFtcJ4EUJ" | |
}, | |
"source": [ | |
"Otimizando os parâmetros do modelo através de um _loop_ de treinamento padrão do PyTorch." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": { | |
"id": "TYWtTpkD3LAM" | |
}, | |
"outputs": [], | |
"source": [ | |
"# Definindo hiperarâmetros\n", | |
"n_iters = 100\n", | |
"learning_rate = 0.01\n", | |
"\n", | |
"# Definindo o otimizador a ser utilizado (SGD - Stochastic Gradient Descent)\n", | |
"optimizer = optim.SGD((W, ), lr=learning_rate)\n", | |
"\n", | |
"# Realizando o loop de treinamento\n", | |
"for i in range(n_iters):\n", | |
" optimizer.zero_grad() # Passo necessário no PyTorch, sem ele o treinamento não dará certo\n", | |
"\n", | |
" # Computando as derivadas e dando um passo na otimização\n", | |
" lbl_preds = model(features, W)\n", | |
" loss = cross_entropy(lbl_preds, labels)\n", | |
" loss.backward()\n", | |
" optimizer.step()\n", | |
"\n", | |
" # Printando a performance do modelo\n", | |
" if (i+1) % 10 == 0:\n", | |
" print(f'iter {i+1}/{n_iters} => {loss.item():.5f}')" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"source": [ | |
"Para visualize os parametros (coeficientes) finais de sua rede neural, basta exibi-los após realizar o trainamento." | |
], | |
"metadata": { | |
"id": "i88g1W1p9eKg" | |
} | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"print(W)" | |
], | |
"metadata": { | |
"id": "-uOD_IiJ9zgq" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "7wbhW19a4xZb" | |
}, | |
"source": [ | |
"Verificando o separador linear encontrado pelo nosso modelo." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": { | |
"id": "uW3mnMiE5qpe" | |
}, | |
"outputs": [], | |
"source": [ | |
"# Visualize o plano que separa ambas as classes\n", | |
"def get_plane(x1, x2, w):\n", | |
" return (w[1,0] * x1) + (w[2,0] * x2) + w[0,0]\n", | |
"\n", | |
"x_line, y_line = np.meshgrid(np.linspace(-5, 7, 100), np.linspace(-15, 10, 100))\n", | |
"plane_eq = get_plane(x_line, y_line, W.detach().numpy())\n", | |
"\n", | |
"fig = plt.figure(figsize=(16, 9))\n", | |
"\n", | |
"ax = fig.add_subplot(121, projection='3d')\n", | |
"ax.view_init(elev=15, azim=130, roll=0)\n", | |
"ax.scatter(features[:,1], features[:,2], c=labels.ravel(), edgecolor='w', alpha=0.75)\n", | |
"ax.plot_surface(x_line, y_line, plane_eq, color='r', alpha=0.15)\n", | |
"\n", | |
"ax = fig.add_subplot(122, projection='3d')\n", | |
"ax.view_init(elev=5, azim=180, roll=0)\n", | |
"ax.scatter(features[:,1], features[:,2], c=labels.ravel(), edgecolor='w', alpha=0.75)\n", | |
"ax.plot_surface(x_line, y_line, plane_eq, color='r', alpha=0.15)\n", | |
"\n", | |
"plt.show()" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": { | |
"id": "2-BiOVxz4Tqd" | |
}, | |
"outputs": [], | |
"source": [ | |
"def logits_to_class(logits: torch.tensor):\n", | |
" classes = list(map(lambda logit: 1 if logit > 0.5 else 0, logits))\n", | |
" return torch.tensor(classes, dtype=torch.int64)\n", | |
"\n", | |
"logits = model(features, W)\n", | |
"n_corrects = (labels == logits_to_class(logits)).sum()\n", | |
"acc = n_corrects / len(labels)\n", | |
"\n", | |
"print(f'Model accuracy: {acc:.3f}')" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"source": [ | |
"## Desafio\n", | |
"\n", | |
"Agora é com você! Repita os mesmos passos definidos para a tarefa de regressão. Só que desta vez, ao invés de utilizar todo as amostras para treino, separe os dados em duas partições: treino e teste.\n", | |
"Sinta-se livre para explorar uma outra base de dados, como aquela disponível no SKLEARN de diabetes!\n", | |
"A ideia deste exercício é fazer com que você coloque a mão na massa por conta própria, enfrentando os problemas que encontrar ao longo do caminho." | |
], | |
"metadata": { | |
"id": "ncmnoyLMstFu" | |
} | |
}, | |
{ | |
"cell_type": "code", | |
"source": [], | |
"metadata": { | |
"id": "e89i4BietFZN" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
} | |
], | |
"metadata": { | |
"colab": { | |
"provenance": [], | |
"include_colab_link": true | |
}, | |
"kernelspec": { | |
"display_name": "Python 3", | |
"name": "python3" | |
}, | |
"language_info": { | |
"name": "python" | |
} | |
}, | |
"nbformat": 4, | |
"nbformat_minor": 0 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment