Criando uma inteligência artificial com Pokemon
import torch
import torch.nn as nn
from torch import optim
import torch.nn.functional as F
from torch.utils.data import DataLoader
from torchvision.utils import make_grid
from torchvision import datasets
import torchvision.transforms as transforms
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import opendatasets as od
from torchvision.utils import make_grid
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder
from sklearn.metrics import confusion_matrix, accuracy_score
from sklearn import preprocessing
import plotly.express as px
import plotly.graph_objects as go
from PIL import Image
import matplotlib.pyplot as plt
import seaborn as sns
od.download('https://www.kaggle.com/datasets/vishalsubbiah/pokemon-images-and-types')
torch.manual_seed(123)
transform = transforms.ToTensor()
le = preprocessing.LabelEncoder()
tipos = pd.read_csv('/content/pokemon-images-and-types/pokemon.csv')
Além disso, estou utilizando preprocessing.LabelEncoder() do Scikit-Learn para converter as categorias dos tipos de Pokémon em números. Isso é útil para que o modelo possa lidar com os dados categóricos de forma numérica durante o treinamento. Para a nossa infelicidade, ele não entende que um tipo fada é um tipo fada, ele vai ter que considerar um tipo fada como um valor em número.
rotulos = {}
for c in range(0, len(tipos)):
rotulos[list(tipos.Name)[c]] = list(tipos.Type1)[c]
rotulos = dict(sorted(rotulos.items()))
trans = transforms.Compose([
transforms.Resize((64, 64)),
transforms.ToTensor()])
imagens = datasets.ImageFolder('/content/pokemon-images-and-types/', transform=trans)
np.unique(list(rotulos.values()))
encoder = LabelEncoder()
rotulos = encoder.fit_transform(list(rotulos.values()))
print(np.unique(rotulos))
a = 0
for n in imagens.samples:
imagens.samples[a] = (imagens.samples[a][0], rotulos[a])
a+=1
img_treinamento, img_teste = train_test_split(imagens, test_size=0.10, shuffle=True)
train_loader = torch.utils.data.DataLoader(img_treinamento, batch_size=126, shuffle=True)
img_testes = torch.utils.data.DataLoader(img_teste)
Inicialmente, a é inicializado com 0 para percorrer os exemplos de imagens e rótulos. Utilizo um loop for para iterar sobre imagens.samples, que contém pares (caminho_da_imagem, índice_do_tipo). Eu acho que foi um jeito muito ruim de fazer isso e sinceramente, se alguém tiver um jeito melhor, por favor, diga aqui nós comentarios. E no final do codigo já separei as imagens que se tornariam parte do treinamento e alguns para a gente fazer a avaliação depois.
class classificador(nn.Module):
def __init__(self):
super().__init__()
self.conv1 = nn.Conv2d(in_channels=3, out_channels=32, kernel_size=(3,3))
self.conv2 = nn.Conv2d(32, 32, (3, 3))
self.activation = nn.ReLU()
self.bnorm = nn.BatchNorm2d(num_features=32)
self.pool = nn.MaxPool2d(kernel_size = (2,2))
self.flatten = nn.Flatten()
self.linear1 = nn.Linear(in_features=6272, out_features=126)
self.linear2 = nn.Linear(126, 126)
self.output = nn.Linear(126, 18)
self.dropout = nn.Dropout(p = 0.2)
def forward(self, X):
X = self.pool(self.bnorm(self.activation(self.conv1(X))))
X = self.pool(self.bnorm(self.activation(self.conv2(X))))
X = self.flatten(X)
X = self.dropout(self.activation(self.linear1(X)))
X = self.dropout(self.activation(self.linear2(X)))
X = self.output(X)
return X
Mas resumidamente; arquitetura é projetada para aprender automaticamente características relevantes das imagens dos Pokémon através das camadas convolucionais e classificar corretamente os tipos utilizando as camadas totalmente conectadas. Falando assim fica bem mais fácil de compreender (A forma mais complexa é através de cálculo).
net = classificador()
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(net.parameters())
def training_loop(loader, epoch):
running_loss = 0.
running_accuracy = 0.
for i, data in enumerate(loader):
inputs, labels = data
inputs, labels = inputs, labels
optimizer.zero_grad()
outputs = net(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
running_loss += loss.item()
ps = F.softmax(outputs)
top_p, top_class = ps.topk(k = 1, dim = 1)
equals = top_class == labels.view(*top_class.shape)
accuracy = torch.mean(equals.type(torch.float))
running_accuracy += accuracy
print('\rÉpoca {:3d} - Loop {:3d} de {:3d}: perda {:03.2f} - precisão {:03.2f}'.format(epoch + 1, i + 1, len(loader), loss,
accuracy), end = '\r')
print('\rÉPOCA {:3d} FINALIZADA: perda {:.5f} - precisão {:.5f}'.format(epoch+1, running_loss/len(loader),
running_accuracy/len(loader)))
for epoch in range(50):
print('Treinando...')
training_loop(train_loader, epoch)
net.eval()
print('Validando...')
training_loop(img_testes, epoch)
net.train()
matriz = confusion_matrix(resultados_IA, resultados_reais)
fig = go.Figure(data=go.Heatmap(
z=matriz,
colorscale='hot',
showscale=True,
text=[[str(val) for val in row] for row in matriz],
texttemplate="%{text}",
textfont={"size": 12}
))
fig.update_layout(
font=dict(family='Courier New, monospace', size=14, color='white'),
plot_bgcolor='#070A0D', paper_bgcolor='#070A0D')
fig.show()
precisao = accuracy_score(resultados_reais, resultados_IA)
~ ɢɪᴛʜᴜʙ ᴅᴏ ᴘʀᴏᴊᴇᴛᴏ https://github.com/Borboleta-Vermelha/Pokemons