W zbiorze danych występuje 70 tys. obrazów, a każdy z nich opisany jest 784 cechami. Wynika to faktu, że każdy obraz ma 28x28 pikseli, a każda cecha opisuje natężenie szarości danego piksela
(przyjmuje wartość od 0 do 255)
import tensorflow as tf
import matplotlib.pyplot as plt
mnist = tf.keras.datasets.mnist
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()
X = train_images.reshape(60000, 28*28)
y = train_labels
print("Rozmiar danych X (zbiór uczący):", X.shape)
print("Rozmiar danych y (etykiety):", y.shape)
def plot_digit(image):
image = image.reshape(28, 28)
plt.imshow(image, cmap='binary')
plt.axis('off')
plt.show()
# Wyświetlenie przykładów
for i in range(5):
print(f"Przykład {i + 1}: Cyfra {y[i]}")
plot_digit(X[i])
# Podział na zbiory: uczący (60 tys.) i testowy (10 tys.)
X_train = X[:60000]
y_train = y[:60000]
X_test = test_images.reshape(10000, 28*28)
y_test = test_labels
print("Rozmiar danych uczących X_train:", X_train.shape)
print("Rozmiar danych testowych X_test:", X_test.shape)
Przykładowe dane przedstawione są poniżej:
Rozmiar danych X (zbiór uczący): (60000, 784)
Rozmiar danych y (etykiety): (60000,)
W powyższym przykładzie aby sprawdzić jak wyglądają cyfry przechowywane w zestawie danych wybraliśmy wektor cech danej próbki i przekształciliśmy go w macierz o rozmiarze 28x28, którą wyświetliliśmy za pomocą funkcji imshow(). Do uzyskania mapy w skali szarości wykorzystaliśmy parametr cmap='binary'.
X_test = test_images.reshape(10000, 28 * 28)
y_test = test_labels
y_train_binary = (y_train == 5).astype(np.int8) # 1 dla cyfry 5, 0 dla innych
y_test_binary = (y_test == 5).astype(np.int8)
sgd_clf = SGDClassifier(random_state=42)
sgd_clf.fit(X_train, y_train_binary)
y_pred = sgd_clf.predict(X_test)
accuracy = accuracy_score(y_test_binary, y_pred)
print(f'Dokładność klasyfikatora: {accuracy:.2f}')
print("Przykładowe predykcje (1 oznacza cyfrę 5):")
print("Predykcje:", y_pred[:10])
print("Prawdziwe etykiety:", y_test_binary[:10])
Dokładność klasyfikatora: 0.95
Przykładowe predykcje (1 oznacza cyfrę 5):
Predykcje: [0 0 0 0 0 0 0 0 0 0]
Prawdziwe etykiety: [0 0 0 0 0 0 0 0 1 0]
W przykładzie wykorzystano klasyfikator stochastycznego spadku wzdłuż gradientu w tym celu skorzystano z klasy SGDClassifier. Klasyfikator ten sprawdza się w przypadku przetwarzania bardzo dużych zbiorów danych. Wynika to faktu, że klasyfikator ten przetwarza poszczególne przykłady uczące się niezależnie od siebie, po jednym naraz.
🚨 Ważna Uwaga
Kroswalidacja k-krotna oznacza rozdzielenie zestawu uczącego się na k podzbiorów ( w naszym przypadku na 3), następnie wyuczany jest model k razy. W każdej iteracji, jeden z podzbiorów jest używany jako zestaw testowy, podczas gdy pozostałe k-1 podzbiory są używane do treningu modelu.
from sklearn.model_selection import cross_val_score
cross_val_scores = cross_val_score(sgd_clf, X_train, y_train_binary, cv=3, scoring="accuracy")
print(f'Dokładność (kroswalidacja SGD): {cross_val_scores}')
[0.95035 0.96035 0.9604 ]
Jednak ten sposób oceny nie sprawdza się tak dobrze w przypadku gdy niektóre klasy występują znacznie częściej od pozostałych tzw. klasy wypaczone.
Innym sposobem oceny wydajności klasyfikatora jest macierz pomyłek.
Przewidywana
1 0
+----+----+
1 | TP | FN |
Rzeczywista +----+----+
0 | FP | TN |
+----+----+
Macierz pomyłek pozwala zrozumieć, w jaki sposób model popełnia błędy:
from sklearn.metrics import accuracy_score, confusion_matrix
from sklearn.model_selection import cross_val_predict
import seaborn as sns
# Kroswalidacja z przewidywaniami
y_pred_cv = cross_val_predict(sgd_clf, X_train, y_train_binary, cv=3)
accuracy = accuracy_score(y_train_binary, y_pred_cv)
print(f'Dokładność klasyfikatora (kroswalidacja): {accuracy:.2f}')
confusion_mat = confusion_matrix(y_train_binary, y_pred_cv)
# Wyświetlenie macierzy pomyłek
plt.figure(figsize=(8, 6))
sns.heatmap(confusion_mat, annot=True, fmt='d', cmap='Blues', xticklabels=['0', '1'], yticklabels=['0', '1'])
plt.ylabel('Rzeczywista')
plt.xlabel('Przewidywana')
plt.title('Macierz Pomyłek')
plt.show()
Dokładność klasyfikatora (kroswalidacja): 0.96
🚨 Ważna Uwaga
Każdy rząd macierzy pomyłek reprezentuje klasę rzeczywista. Natomiast kolumna stanowi przewidywaną klasę. Interpretacja 53892 stanowi prawidłowo sklasyfikowane próbki niebędące piątkami tzw. PN, 687 przykładów zostało niewłaściwe uznane za 5, tzw. FP (błąd pierwszego rodzaju).
W drugim rzędzie zostały umieszczone obrazy zaklasyfikowane jako piątki.
Przy czym 1891 próbek zostało nieprawidłowo sklasyfikowanych jako niebędące piątkami tzw. FN natomiast 3530 zostało prawidłowo zaklasyfikowane jako 5.
Nasz doskonały klasyfikator uzyskiwałby wyłącznie przykłady prawdziwe pozytywne i prawdziwe negatywne () na głównej przekątnej miałby niezerowe wartości.
Jeszcze inne miary:
Pełność (znana również jako czułość) jest to odsetek pozytywnych przykładów prawidłowo rozpoznane przez klasyfikator.
from sklearn.metrics import precision_score, recall_score, f1_score
precision = precision_score(y_train_binary, y_pred_cv)
recall = recall_score(y_train_binary, y_pred_cv)
f1 = f1_score(y_train_binary, y_pred_cv)
print(f'Precyzja: {precision:.2f}')
print(f'Pełność: {recall:.2f}')
print(f'F1-score: {f1:.2f}')
Precyzja: 0.84
Pełność: 0.65
F1-score: 0.73
🚨 Ważna Uwaga Kompromis pomiędzy precyzją a pełnością
Przy czym F1 faworyzuje klasyfikatory mające zbliżone wartości precyzji i pełności. Nie zawsze tego chcemy, przykładowo mając na celu wyuczenie klasyfikatora w określaniu bezpiecznych filmów dla dzieci bardziej zależałoby nam na tym by klasyfikator odrzucał wiele dobrych filmów (mała wartość pełności), ale zapamiętywałby jedynie bezpieczne (duża precyzja). Niekorzystna byłaby relacja odwrotna gdzie model cechowałby się dużo większą pełnością, ale dopuszczałby kilka nieodpowiednich filmów.
Jednak przy trenowaniu klasyfikatora do wykrywania złodziei z zapisu kamer prawdopodobnie nic złego by się nie stało gdyby model miał przykładowo 30% precyzji przy 99% pełności. Wówczas może i byłoby kilka fałszywych alarmów ale niemal wszyscy przestępcy zostaliby złapani.
Do tej pory każdy przykład był przydzielany wyłącznie do jednej klasy. Jednak weźmy przykład rozpoznawania twarzy, co powinien zrobić gdy na zdjęciu jest wiele osób?
Powinien przydzielić po jednej etykiecie na każdą rozpoznaną twarz. Załóżmy ,że model został wyuczony do rozpoznania grupy przyjaciół na zdjęciu: Tomka, Piotrka i Agnieszki. Po zaprezentowaniu zdjęć Tomka i Piotrka powinien zostać wygenerowany wynik [True, True, False ].
Tego typu system klasyfikujący zdolny do wyznaczania wielu binarnych znaczników nosi nazwę klasyfikacji wieloetykietowej.
Ćwiczenia dla tego tematu zostały zebrane tutaj.
Kliknij tutaj, aby wrócić do strony głównej kursu.