Machine Learning Academy · Oppitunti

Arviointi ja päättely: logiteista ennustetuiksi luokiksi

Oppijat laskevat softmaxin logiteista, muuttavat ennustetut luokkaindeksit luokkatunnisteiksi ja arvioivat hienosäädetyn mallin tarkkuuden ja F1-arvon avulla erillisellä testijoukolla.

Oppitunti 4/413 vaihetta

Arviointi ja päättely: logiteista ennustetuiksi luokiksi on ilmainen Machine Learning Academy-oppitunti CoddyKitissä. Tämä on oppitunti 4/4. Voit lukea koko oppitunnin alta ilmaiseksi ja harjoitella sen jälkeen käytännössä selaimessa sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla. Oppitunti kuuluu Machine Learning Academy-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. Machine Learning Academy-kurssilla on yhteensä 4 oppituntia.

Mitä logit-arvot ovat?

Luokittelumallin viimeisen lineaarisen kerroksen tulostetta kutsutaan logit-arvoiksi: ne ovat kunkin luokan raakapisteitä, joita ei ole normalisoitu. Kaksiluokkaisessa ongelmassa (negatiivinen/positiivinen) logit-vektori voi olla esimerkiksi [-1.2, 3.5], mikä tarkoittaa, että malli suosii voimakkaasti luokkaa 1 (positiivinen). Logit-arvot voivat olla mitä tahansa reaalilukuja; ne eivät ole todennäköisyyksiä. Tarvitsemme lisävaiheen (softmaxin tai sigmoidin), jotta voimme muuntaa ne tulkittaviksi todennäköisyyksiksi, joiden summa on 1.

import torch
import torch.nn.functional as F

# Example logits for 2-class problem (batch of 3)
logits = torch.tensor([[-1.2, 3.5], [2.1, -0.3], [0.4, 0.6]])
print('Logits:\n', logits)

# Convert to probabilities with softmax
probs = F.softmax(logits, dim=1)
print('Probabilities:\n', probs)
# Each row sums to 1
print('Row sums:', probs.sum(dim=1))

Softmax: logit-arvojen muuntaminen todennäköisyyksiksi

Softmax-funktio muuntaa reaaliluvuista koostuvan logit-vektorin todennäköisyysjakaumaksi. Luokalle i: softmax(z_i) = exp(z_i) / sum(exp(z_j)). Eksponenttifunktio vahvistaa eroja: logit-arvojen ero 2 johtaa siihen, että toinen luokka on noin 7 kertaa todennäköisempi kuin toinen. Softmaxia käytetään moniluokkaisessa luokittelussa, jossa täsmälleen yksi luokka on oikea.

import torch
import torch.nn.functional as F
import numpy as np

logits = torch.tensor([1.0, 3.0, 0.5])  # 3 classes
probs = F.softmax(logits, dim=0)
print('Class probabilities:', probs.numpy().round(4))
# [0.0900, 0.6652, 0.2449] -- class 1 is most likely
print('Sum:', probs.sum().item())  # 1.0

# argmax gives the predicted class index
pred_class = torch.argmax(probs).item()
print('Predicted class:', pred_class)  # 1

argmax: ennustettujen tunnisteiden poimiminen

Kun meillä on esimerkkierän logit-vektorit, torch.argmax(logits, dim=1) palauttaa kunkin esimerkin suurimman pistemäärän saaneen luokan indeksin. Tämä on ennustettu luokkatunniste. Kun BERT on hienosäädetty komennolla num_labels=2, tulos on 0 (negatiivinen) tai 1 (positiivinen). Softmaxia ei tarvitse käyttää ennen argmaxia, koska softmax on monotoninen: suurin logit-arvo vastaa aina suurinta todennäköisyyttä.

import torch

# Logits from model output for a batch of 4 examples
logits = torch.tensor([
    [-2.1,  3.4],  # strongly positive
    [ 1.8, -0.5],  # negative
    [ 0.1,  0.2],  # uncertain, leans positive
    [-3.0, -1.0]   # both negative, less-negative wins
])

predictions = torch.argmax(logits, dim=1)
print('Predictions:', predictions.tolist())  # [1, 0, 1, 1]

labels = {'0': 'negative', '1': 'positive'}
for pred in predictions.tolist():
    print(labels[str(pred)])

Ennustettujen indeksien muuntaminen luokkien nimiksi

Mallin tulosteet ovat kokonaislukui­ndeksejä. Tuotantojärjestelmässä ylläpidätte indeksin ja ihmiselle luettavan tunnisteen välistä vastaavuutta. Tallentakaa se listana tai sanakirjana ja käyttäkää ennustettua kokonaislukua sen indeksointiin. IMDB-aineistolla hienosäädetyn BERTin vastaavuus on yksinkertaisesti {0: 'NEGATIVE', 1: 'POSITIVE'}. Moniluokkaisissa tehtävissä, kuten aiheiden luokittelussa, vastaavuudessa voi olla vähintään 20 merkintää.

import torch
from transformers import BertForSequenceClassification, BertTokenizer

# Assume model and tokenizer are already loaded and fine-tuned
id2label = {0: 'NEGATIVE', 1: 'POSITIVE'}

def predict(text, model, tokenizer, device):
    model.eval()
    inputs = tokenizer(text, return_tensors='pt',
                       truncation=True, max_length=256)
    inputs = {k: v.to(device) for k, v in inputs.items()}
    with torch.no_grad():
        logits = model(**inputs).logits
    pred_id = torch.argmax(logits, dim=1).item()
    return id2label[pred_id]

# result = predict('This film was absolutely wonderful!', model, tokenizer, device)
# print(result)  # POSITIVE

Todennäköisyyksistä saadut varmuuspisteet

Pelkästään ennustetun tunnisteen palauttaminen ei usein riitä todellisissa sovelluksissa. Varmuuspiste (ennustetun luokan todennäköisyys) kertoo käyttäjille, kuinka varma malli on. POSITIVE-ennuste 99 %:n varmuudella poikkeaa huomattavasti ennusteesta, jonka varmuus on 52 %. Vähäisen varmuuden ennusteiden ohjaaminen ihmisen tarkistettaviksi on yleinen käytäntö arkaluonteisia päätöksiä käsittelevissä tuotantojärjestelmissä.

import torch
import torch.nn.functional as F

def predict_with_confidence(text, model, tokenizer, device):
    model.eval()
    id2label = {0: 'NEGATIVE', 1: 'POSITIVE'}
    inputs = tokenizer(text, return_tensors='pt',
                       truncation=True, max_length=256)
    inputs = {k: v.to(device) for k, v in inputs.items()}
    with torch.no_grad():
        logits = model(**inputs).logits
    probs = F.softmax(logits, dim=1).squeeze()
    pred_id = torch.argmax(probs).item()
    confidence = probs[pred_id].item()
    return id2label[pred_id], round(confidence, 4)

# label, conf = predict_with_confidence('Terrible movie.', model, tokenizer, device)
# print(label, conf)  # NEGATIVE 0.9732

Arviointi tarkkuuden ja F1-mittarin avulla

Kun olette keränneet ennusteet koko testijoukosta, laskekaa vakiomittarit scikit-learnin avulla. Tarkkuus on oikein ennustettujen tapausten osuus – se on hyödyllinen, kun luokat ovat tasapainossa. F1-mittari on precisionin ja recallin harmoninen keskiarvo – se on tärkeä, kun toinen luokka (esimerkiksi positiiviset arvostelut) on merkityksellisempi tai luokat ovat epätasapainossa. classification_report tulostaa kaikki mittarit yhteen selkeään taulukkoon.

from sklearn.metrics import classification_report, accuracy_score
import torch

all_preds, all_labels = [], []

model.eval()
with torch.no_grad():
    for batch in test_loader:
        outputs = model(
            input_ids=batch['input_ids'].to(device),
            attention_mask=batch['attention_mask'].to(device)
        )
        preds = torch.argmax(outputs.logits, dim=1).cpu().numpy()
        all_preds.extend(preds)
        all_labels.extend(batch['label'].numpy())

print('Accuracy:', accuracy_score(all_labels, all_preds))
print(classification_report(all_labels, all_preds,
      target_names=['NEGATIVE', 'POSITIVE']))

BERTin sekaannusmatriisi

Sekaannusmatriisi näyttää ennusteiden ja todellisten tunnisteiden jakauman. Tunneanalyysissä lävistäjän ulkopuoliset solut näyttävät väärät positiiviset (ennustettu POSITIVE, vaikka todellinen tunniste on NEGATIVE) ja väärät negatiiviset (ennustettu NEGATIVE, vaikka todellinen tunniste on POSITIVE). Tämän visualisointi seabornin lämpökarttana paljastaa järjestelmälliset virheet: ennustaako malli liikaa jotakin luokkaa? Luokitellaanko tietyntyyppiset arvostelut jatkuvasti väärin?

from sklearn.metrics import confusion_matrix
import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np

cm = confusion_matrix(all_labels, all_preds)

plt.figure(figsize=(6, 5))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',
            xticklabels=['NEG', 'POS'],
            yticklabels=['NEG', 'POS'])
plt.ylabel('True Label')
plt.xlabel('Predicted Label')
plt.title('BERT Confusion Matrix on IMDB Test Set')
plt.tight_layout()
plt.savefig('bert_confusion.png')

Erämuotoinen päättely tehokkuuden parantamiseksi

Päättelyn suorittaminen yksi esimerkki kerrallaan on hidasta. Käsitelkää esimerkit erissä GPU:n rinnakkaisuuden hyödyntämiseksi. Asettakaa DataLoaderissa kiinteä batch_size, välittäkää kokonaiset erät mallille ja kerätkää tulokset. GPU:lla erämuotoinen päättely voi olla 50 kertaa nopeampaa kuin päättely yksittäisillä esimerkeillä. Käyttäkää torch.no_grad()-kontekstia ja siirtäkää tensorit oikealle laitteelle parhaan suorituskyvyn saavuttamiseksi.

import torch
from torch.utils.data import DataLoader, TensorDataset
from transformers import BertTokenizer

def batch_predict(texts, model, tokenizer, device, batch_size=32):
    model.eval()
    all_predictions = []
    for i in range(0, len(texts), batch_size):
        batch_texts = texts[i:i+batch_size]
        enc = tokenizer(batch_texts, truncation=True, padding=True,
                        max_length=256, return_tensors='pt')
        enc = {k: v.to(device) for k, v in enc.items()}
        with torch.no_grad():
            logits = model(**enc).logits
        preds = torch.argmax(logits, dim=1).cpu().tolist()
        all_predictions.extend(preds)
    return all_predictions

Sigmoid moniluokkaiseen luokitteluun

Kun teksti voi kuulua useaan luokkaan samanaikaisesti (esimerkiksi arvostelu voi olla sekä ”hauska” että ”tunteikas”), käyttäkää sigmoid-funktiota softmax-funktion sijaan. Sigmoidia käytetään kuhunkin luokan logit-arvoon erikseen, jolloin jokaiselle luokalle saadaan välillä 0–1 oleva todennäköisyys, jonka ei tarvitse olla osa summaa 1. Käyttäkää kuhunkin todennäköisyyteen kynnysarvoa (yleensä 0,5) saadaksenne jokaiselle luokalle binäärisen ennusteen. Asettakaa BertForSequenceClassificationissa problem_type='multi_label_classification'.

import torch
import torch.nn.functional as F

# 5 classes, multi-label: a text can have multiple labels
logits = torch.tensor([[1.2, -0.5, 2.1, -1.8, 0.3]])
probs = torch.sigmoid(logits)
print('Per-class probabilities:', probs)

threshold = 0.5
predicted_labels = (probs > threshold).int()
print('Predicted labels (multi-hot):', predicted_labels)
# e.g., [1, 0, 1, 0, 0] -- classes 0 and 2 are predicted

Väärin luokiteltujen esimerkkien käsittely

Tarkastelkaa väärin luokiteltuja esimerkkejä aina manuaalisesti. Tulostakaa esimerkit, joissa malli ennusti arvon 0 mutta todellinen tunniste on 1 (väärät negatiiviset), ja päinvastoin. Yleisiä malleja ovat sarkasmi (”Voi miten loistava elokuvakatastrofi”), toimialamuutos (vanhahtava sanasto) ja pitkät arvostelut, joissa malli näkee vain ensimmäiset 256 tokenia. Virhetilanteiden ymmärtäminen ohjaa piirteiden suunnittelua ja aineiston keräämistä.

import numpy as np

all_preds = np.array(all_preds)
all_labels = np.array(all_labels)
texts = test_dataset['text'] if hasattr(test_dataset, '__getitem__') else []

false_negatives = np.where((all_preds == 0) & (all_labels == 1))[0]
false_positives = np.where((all_preds == 1) & (all_labels == 0))[0]

print('False negatives (predicted NEG, true POS):')
for idx in false_negatives[:3]:
    print(' -', str(texts[idx])[:120] if texts else idx)

print('False positives (predicted POS, true NEG):')
for idx in false_positives[:3]:
    print(' -', str(texts[idx])[:120] if texts else idx)

Ennusteiden vieminen CSV-tiedostoon

Tuotanto- tai kilpailuympäristössä ennusteet on usein vietävä CSV-tiedostoon. Luokaa pandas-kirjaston avulla DataFrame, joka sisältää alkuperäisen tekstin, todellisen tunnisteen, ennustetun tunnisteen ja varmuuspisteen. Tätä muotoa on helppo jakaa sidosryhmille, käyttää auditointiin ja hyödyntää myöhempien raportointiputkien syötteenä. Sisällyttäkää metatietoihin aina mallin versio ja ennusteen aikaleima.

import pandas as pd
import torch.nn.functional as F
import torch

results = []
id2label = {0: 'NEGATIVE', 1: 'POSITIVE'}

model.eval()
for i, text in enumerate(sample_texts):
    inputs = tokenizer(text, return_tensors='pt',
                       truncation=True, max_length=256)
    with torch.no_grad():
        logits = model(**inputs).logits
    probs = F.softmax(logits, dim=1).squeeze()
    pred = torch.argmax(probs).item()
    results.append({
        'text': text[:80],
        'true_label': id2label[sample_labels[i]],
        'predicted_label': id2label[pred],
        'confidence': round(probs[pred].item(), 4)
    })

df = pd.DataFrame(results)
df.to_csv('bert_predictions.csv', index=False)
print(df.head())

Pikatarkistus

Testatkaa ymmärrystänne tämän oppitunnin Pythonilla toteutettavan koneoppimisen käsitteistä.

Oppitunnin yhteenveto

Tällä oppitunnilla opitte, että logit-arvot ovat mallin raakapisteitä, jotka muunnetaan todennäköisyyksiksi softmaxilla moniluokkaisissa ja sigmoidilla monilapputehtävissä, argmax palauttaa ennustetun luokkaindeksin, joka yhdistetään ihmiselle luettavaan tunnisteeseen id2label-sanakirjan avulla ja classification_report sekä sekaannusmatriisi tarjoavat yhdessä kattavan kuvan mallin suorituskyvystä tarkkuuden lisäksi. Seuraavaksi tutustumme MLflow'hun kokeiden, parametrien ja mittareiden seurantaa varten useiden koulutusajojen välillä.

Aloita maksutta

Opi Python tekoälytuutorin avulla — ilmaiseksi

Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.

Kurssit
30
Oppitunnit
120

Usein kysytyt kysymykset

Onko oppitunti ”Arviointi ja päättely: logiteista ennustetuiksi luokiksi” ilmainen?

Kyllä – oppitunnin ”Arviointi ja päättely: logiteista ennustetuiksi luokiksi” koko tekstin voi lukea täällä verkossa ilmaiseksi. Jos haluat harjoitella interaktiivisesti sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla sekä avata koko Machine Learning Academy-kurssin, päivitä CoddyKit PROhon. Machine Learning Academy-kurssilla on yhteensä 4 oppituntia.

Mitä opin oppitunnilla ”Arviointi ja päättely: logiteista ennustetuiksi luokiksi”?

Oppijat laskevat softmaxin logiteista, muuttavat ennustetut luokkaindeksit luokkatunnisteiksi ja arvioivat hienosäädetyn mallin tarkkuuden ja F1-arvon avulla erillisellä testijoukolla. Harjoittelet Machine Learning Academy-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.

Tarvitsenko kokemusta aloittaakseni Machine Learning Academy-opiskelun?

Aiempi kokemus ei ole tarpeen. CoddyKitin Machine Learning Academy-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 4/4.

Kuinka kauan ”Arviointi ja päättely: logiteista ennustetuiksi luokiksi”-oppitunnin suorittaminen kestää?

Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.

Voinko kirjoittaa ja suorittaa koodia tällä Machine Learning Academy-oppitunnilla?

Kyllä. Jokainen Machine Learning Academy-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.

Kaikki tämän kurssin oppitunnit

  1. Transformer-arkkitehtuuri: attention, tokenit ja asiayhteys
  2. Hugging Face -tokenisoijat: tekstin koodaus BERTiä varten
  3. BertForSequenceClassificationin hienosäätö
  4. Arviointi ja päättely: logiteista ennustetuiksi luokiksi
← Takaisin: Machine Learning Academy