Solucionado (ver solução)
Solucionado
(ver solução)
3
respostas

[Projeto] Custo Negativo e Taxa de acerto abaixo dos 50%

Olá. Meu Perceptron está com baixíssima performance. Acredito que esteja sofrendo de overfiting. Gostaria que analisassem meu código para eu entender onde eu errei.

QUANTIDADE_EPOCAS = 1000
perdas = []
taxas_acertos = []
otimizador_treino = tf.optimizers.SGD(learning_rate= 0.01)

tf.random.set_seed(31)

quantidade_features = X_treino.shape[1]
pesos = tf.Variable(tf.random.normal([quantidade_features, 1]), name= 'pesos')
vies = tf.Variable(tf.random.normal([1]), name= 'vies')

# obtendo o custo
for epoca in range(QUANTIDADE_EPOCAS):
    with tf.GradientTape() as tape:
        probabilidade = tf.sigmoid(neuronio(X_treino))
        custo = calculadora_perda(y_treino, probabilidade)

        gradientes = tape.gradient(custo, [pesos, vies])
        otimizador_treino.apply_gradients(zip(gradientes, [pesos, vies]))

        # calculando a Taxa de acerto nos dados de teste
        probabilidade_teste = tf.sigmoid(neuronio(X_teste))
        acertos = np.mean(y_teste.numpy() == ((probabilidade_teste.numpy() > 0.5)*1))
        taxas_acertos.append(acertos)

        perdas.append(custo.numpy())

    if (epoca + 1) % 100 == 0:
        print(f"Época: {epoca+1}, Custo: {custo.numpy()}, Taxa de acerto: {acertos}")

SAÍDA Época: 100, Custo: 0.7902313470840454, Taxa de acerto: 0.4262295081967213 Época: 200, Custo: 0.13465942442417145, Taxa de acerto: 0.4426229508196721 Época: 300, Custo: -0.3076125979423523, Taxa de acerto: 0.45901639344262296 Época: 400, Custo: -0.6732703447341919, Taxa de acerto: 0.4098360655737705 Época: 500, Custo: -1.0038869380950928, Taxa de acerto: 0.39344262295081966 Época: 600, Custo: -1.3114114999771118, Taxa de acerto: 0.3770491803278688 Época: 700, Custo: -1.5990430116653442, Taxa de acerto: 0.3770491803278688 Época: 800, Custo: -1.870243787765503, Taxa de acerto: 0.3770491803278688 Época: 900, Custo: -2.1292061805725098, Taxa de acerto: 0.36065573770491804 Época: 1000, Custo: -2.379087448120117, Taxa de acerto: 0.36065573770491804

3 respostas
solução!

Olá, Alberto tudo bem?

Eu rodei o mesmo código que você enviou aqui e deu o mesmo resultado da aula. Você está rodando esses códigos no Google Colab?

Se sim, tente reiniciar o ambiente de execução e rodar novamente!

As etapas são as seguintes:

1 - Separar os dados em treino e teste:

from sklearn.model_selection import train_test_split

X_treino, X_teste, y_treino, y_teste = train_test_split(entrada.numpy(), y.numpy(), test_size=0.2,
                                                        stratify=y.numpy(), random_state=4321)

2 - Normalizar os dados:

# Normalizando os dados
scaler = StandardScaler()
X_treino = scaler.fit_transform(X_treino)
X_teste = scaler.transform(X_teste)

# Convertendo para tensores do TensorFlow
X_treino = tf.constant(X_treino, dtype=tf.float32)
X_teste = tf.constant(X_teste, dtype=tf.float32)
y_treino = tf.constant(y_treino, dtype=tf.float32)
y_teste = tf.constant(y_teste, dtype=tf.float32)

3 - Inicializar os pesos e vies da rede neural:

tf.random.set_seed(31)
quantidade_features = X_treino.shape[1]
pesos = tf.Variable(tf.random.normal([quantidade_features, 1]), name='pesos')
vies = tf.Variable(tf.random.normal([1]), name='vies')

4 - Definir a função do neurônio:

def neuronio(x):
  z = tf.add(tf.matmul(x, pesos), vies)
  return z

5 - Definir a calculadora da perda e o otimizador:

calculadora_perda = tf.keras.losses.BinaryCrossentropy() # Cria um objeto para calcular a perda
otimizador_treino = tf.optimizers.SGD(learning_rate=0.01) # Define o otimizador
QUANTIDADE_EPOCAS = 1000

6 - Aplicar o gradiente:

# Inicializa listas vazias para armazenar o histórico de perdas e taxas de acerto ao longo do treinamento
perdas = []
taxas_acerto = []

# Define o otimizador a ser usado para ajustar os pesos do modelo
otimizador_treino = tf.optimizers.SGD(learning_rate=0.01)

# Inicializa os pesos e o viés
tf.random.set_seed(31)
quantidade_features = X_treino.shape[1]
pesos = tf.Variable(tf.random.normal([quantidade_features, 1]), name='pesos')
vies = tf.Variable(tf.random.normal([1]), name='vies')

# Loop de treinamento para a quantidade definida de épocas
for epoca in range(QUANTIDADE_EPOCAS):
  with tf.GradientTape() as tape:
    probabilidade = tf.sigmoid(neuronio(X_treino))
    custo = calculadora_perda(y_treino, probabilidade)

    gradientes = tape.gradient(custo, [pesos, vies])
    otimizador_treino.apply_gradients(zip(gradientes, [pesos, vies]))

    # Calcula a taxa de acerto nos dados de teste
    probabilidade_teste = tf.sigmoid(neuronio(X_teste))
    acertos = np.mean(y_teste.numpy() == ((probabilidade_teste.numpy() > 0.5) *1))
    taxas_acerto.append(acertos)

    # Adiciona o custo atual à lista de perdas para histórico
    perdas.append(custo.numpy())

  # A cada 100 épocas, imprime o número da época, o custo e a taxa de acerto
  if (epoca + 1) % 100 == 0:
    print(f'Época: {epoca+1}, Custo: {custo.numpy()}, Taxa de acerto: {acertos}')

Se continuar dando algum resultado estranho avise aqui, tá bem?

Bons estudos :)

Boa noite. Consultei seu notebook e vi que o erro estava fora do escopo do código que mencionei acima. Pra ser mais exato na minha variável target :

target = doenca_cardiaca.data.targets
targt = (target > 0) * 1

Precisei fazer uma reversão de cada célula até chegar nessa onde percebi que escrevi targt em vez de target. Mesmo assim gostaria que me explicasse, se possível, o motivo do modelo ter caído drasticamente a eficiência apenas por ter considerado somente o target = doenca_cardiaca.data.targets

Agradeço pela solução :P

Ahhhh entendi o motivo de ter caído tanto a taxa de acerto, Alberto...

Quando lidamos com o dataset original, ele contém várias categorias diferentes como alvo, o que significa que tínhamos uma tarefa de classificação multiclasse. No entanto, para simplificar o problema e torná-lo mais gerenciável para este curso, optamos por transformar essa tarefa em uma classificação binária, da seguinte forma:

target = (target > 0) * 1

Essa transformação envolveu considerar todas as categorias acima de 0 como pertencentes a uma única classe (que designamos como classe 1) e todas as outras como pertencentes à outra classe (classe 0). Em outras palavras, estamos agora distinguindo entre duas classes distintas, em vez de várias.

É por isso que você notou uma diferença significativa nos resultados, pois agora o modelo estava lidando com várias classes.

Se tiver mais dúvidas ou precisar de mais esclarecimentos, estou à disposição para ajudar.