🏷️sec_naive_bayes
Önceki bölümler boyunca, olasılık teorisi ve rastgele değişkenler hakkında bilgi edindik. Bu teoriyi uygulamaya koymak için, naif Bayes sınıflandırıcısını tanıtalım. Bu, rakamların sınıflandırmasını yapmamıza izin vermek için olasılık temellerinden başka hiçbir şey kullanmaz.
Öğrenme tamamen varsayımlarda bulunmakla ilgilidir. Daha önce hiç görmediğimiz yeni bir veri örneğini sınıflandırmak istiyorsak, hangi veri örneklerinin birbirine benzer olduğuna dair bazı varsayımlar yapmalıyız. Popüler ve oldukça net bir algoritma olan naif Bayes sınıflandırıcı, hesaplamayı basitleştirmek için tüm özniteliklerin birbirinden bağımsız olduğunu varsayar. Bu bölümde, imgelerdeki karakterleri tanımak için bu modeli uygulayacağız.
%matplotlib inline
from d2l import mxnet as d2l
import math
from mxnet import gluon, np, npx
npx.set_np()
d2l.use_svg_display()
#@tab pytorch
%matplotlib inline
from d2l import torch as d2l
import math
import torch
import torchvision
d2l.use_svg_display()
#@tab tensorflow
%matplotlib inline
from d2l import tensorflow as d2l
import math
import tensorflow as tf
d2l.use_svg_display()
MNIST :cite:LeCun.Bottou.Bengio.ea.1998
, yaygın olarak kullanılan veri kümelerinden biridir. Eğitim için 60.000 imge ve geçerleme için 10.000 imge içerir. Her imge, 0'dan 9'a kadar el yazısıyla yazılmış bir rakam içerir. Görev, her imgeyi karşılık gelen rakama sınıflandırmaktır.
Gluon, veri kümesini İnternet'ten otomatik olarak almak için data.vision
modülünde bir MNIST
sınıfı sağlar.
Daha sonra, Gluon hali-hazırda indirilmiş yerel kopyayı kullanacaktır. train
parametresinin değerini sırasıyla True
veya False
olarak ayarlayarak eğitim kümesini mi yoksa test kümesini mi talep ettiğimizi belirtiriz.
Her resim, hem genişliği hem de yüksekliği
def transform(data, label):
return np.floor(data.astype('float32') / 128).squeeze(axis=-1), label
mnist_train = gluon.data.vision.MNIST(train=True, transform=transform)
mnist_test = gluon.data.vision.MNIST(train=False, transform=transform)
#@tab pytorch
data_transform = torchvision.transforms.Compose([
torchvision.transforms.ToTensor(),
lambda x: torch.floor(x * 255 / 128).squeeze(dim=0)
])
mnist_train = torchvision.datasets.MNIST(
root='./temp', train=True, transform=data_transform, download=True)
mnist_test = torchvision.datasets.MNIST(
root='./temp', train=False, transform=data_transform, download=True)
#@tab tensorflow
((train_images, train_labels), (
test_images, test_labels)) = tf.keras.datasets.mnist.load_data()
# MNIST'in orijinal piksel değerleri 0-255 arasındadır (rakamlar uint8 olarak depolandığından).
# Bu bölüm için (orijinal imgede) 128'den büyük piksel değerleri 1'e,
# 128'den küçük değerler 0'a dönüştürülür. Nedeni için bölüm 18.9.2 ve 18.9.3'e bakın.
train_images = tf.floor(tf.constant(train_images / 128, dtype = tf.float32))
test_images = tf.floor(tf.constant(test_images / 128, dtype = tf.float32))
train_labels = tf.constant(train_labels, dtype = tf.int32)
test_labels = tf.constant(test_labels, dtype = tf.int32)
İmgeyi ve ilgili etiketi içeren belirli bir örneğe erişebiliriz.
image, label = mnist_train[2]
image.shape, label
#@tab pytorch
image, label = mnist_train[2]
image.shape, label
#@tab tensorflow
image, label = train_images[2], train_labels[2]
image.shape, label.numpy()
Burada image
değişkeninde saklanan örneğimiz, yüksekliği ve genişliği
#@tab all
image.shape, image.dtype
Kodumuz her imgenin etiketini sayıl olarak depolar. Türü
label, type(label), label.dtype
#@tab pytorch
label, type(label)
#@tab tensorflow
label.numpy(), label.dtype
Aynı anda birden fazla örneğe de erişebiliriz.
images, labels = mnist_train[10:38]
images.shape, labels.shape
#@tab pytorch
images = torch.stack([mnist_train[i][0] for i in range(10, 38)], dim=0)
labels = torch.tensor([mnist_train[i][1] for i in range(10, 38)])
images.shape, labels.shape
#@tab tensorflow
images = tf.stack([train_images[i] for i in range(10, 38)], axis=0)
labels = tf.constant([train_labels[i].numpy() for i in range(10, 38)])
images.shape, labels.shape
Bu örnekleri görselleştirelim.
#@tab all
d2l.show_images(images, 2, 9);
Bir sınıflandırma görevinde, bir örneği bir kategoriye eşleriz. Burada bir örnek gri tonlamalı sec_softmax
.)
Sınıflandırma görevini ifade etmenin doğal bir yolu, olasılık sorusudur: Özellikler (yani, imge pikselleri) verildiğinde en olası etiket nedir?
Maalesef bu, her
Dahası, öğrenme nerede? İlgili etiketi tahmin etmek için her bir olası örneği görmemiz gerekiyorsa, o zaman gerçekten bir model öğrenmiyoruz, sadece veri kümesini ezberliyoruz.
Neyse ki, koşullu bağımsızlık hakkında bazı varsayımlar yaparak, bazı tümevarımsal önyargılar sunabilir ve nispeten mütevazı bir eğitim örnekleri seçiminden genelleme yapabilen bir model oluşturabiliriz. Başlamak için, sınıflandırıcıyı şu şekilde ifade etmede Bayes teoremini kullanalım:
Paydanın normalleştirme teriminin
Şimdi
Tek başına bu ifade bizi daha ileriye götürmez. Yine de kabaca
$$\hat{y} = \mathrm{argmax}y > \prod{i=1}^d p(x_i \mid y) p(y).$$
Her
Ayrıca, her
$$\begin{aligned}\hat{y} &= \mathrm{argmax}_ y \ p(y)\prod_{i=1}^d p(x_t = t_i \mid y) \ &= \mathrm{argmax}y \ P_y[y]\prod{i=1}^d \ P_{xy}[i, y]^{t_i}, \left(1 - P_{xy}[i, y]\right)^{1-t_i}\end{aligned}$$
:eqlabel:eq_naive_bayes_estimation
üstelik herhangi bir
Şimdi sorun,
X, Y = mnist_train[:] # Tüm eğitim örnekleri
n_y = np.zeros((10))
for y in range(10):
n_y[y] = (Y == y).sum()
P_y = n_y / n_y.sum()
P_y
#@tab pytorch
X = torch.stack([mnist_train[i][0] for i in range(len(mnist_train))], dim=0)
Y = torch.tensor([mnist_train[i][1] for i in range(len(mnist_train))])
n_y = torch.zeros(10)
for y in range(10):
n_y[y] = (Y == y).sum()
P_y = n_y / n_y.sum()
P_y
#@tab tensorflow
X = train_images
Y = train_labels
n_y = tf.Variable(tf.zeros(10))
for y in range(10):
n_y[y].assign(tf.reduce_sum(tf.cast(Y == y, tf.float32)))
P_y = n_y / tf.reduce_sum(n_y)
P_y
Şimdi biraz daha zor şeylere,
n_x = np.zeros((10, 28, 28))
for y in range(10):
n_x[y] = np.array(X.asnumpy()[Y.asnumpy() == y].sum(axis=0))
P_xy = (n_x + 1) / (n_y + 1).reshape(10, 1, 1)
d2l.show_images(P_xy, 2, 5);
#@tab pytorch
n_x = torch.zeros((10, 28, 28))
for y in range(10):
n_x[y] = torch.tensor(X.numpy()[Y.numpy() == y].sum(axis=0))
P_xy = (n_x + 1) / (n_y + 1).reshape(10, 1, 1)
d2l.show_images(P_xy, 2, 5);
#@tab tensorflow
n_x = tf.Variable(tf.zeros((10, 28, 28)))
for y in range(10):
n_x[y].assign(tf.cast(tf.reduce_sum(
X.numpy()[Y.numpy() == y], axis=0), tf.float32))
P_xy = (n_x + 1) / tf.reshape((n_y + 1), (10, 1, 1))
d2l.show_images(P_xy, 2, 5);
Bu
Şimdi yeni bir imgeyi tahmin etmek için :eqref:eq_naive_bayes_estimation
denklemini kullanabiliriz.
def bayes_pred(x):
x = np.expand_dims(x, axis=0) # (28, 28) -> (1, 28, 28)
p_xy = P_xy * x + (1 - P_xy)*(1 - x)
p_xy = p_xy.reshape(10, -1).prod(axis=1) # p(x|y)
return np.array(p_xy) * P_y
image, label = mnist_test[0]
bayes_pred(image)
#@tab pytorch
def bayes_pred(x):
x = x.unsqueeze(0) # (28, 28) -> (1, 28, 28)
p_xy = P_xy * x + (1 - P_xy)*(1 - x)
p_xy = p_xy.reshape(10, -1).prod(dim=1) # p(x|y)
return p_xy * P_y
image, label = mnist_test[0]
bayes_pred(image)
#@tab tensorflow
def bayes_pred(x):
x = tf.expand_dims(x, axis=0) # (28, 28) -> (1, 28, 28)
p_xy = P_xy * x + (1 - P_xy)*(1 - x)
p_xy = tf.math.reduce_prod(tf.reshape(p_xy, (10, -1)), axis=1) # p(x|y)
return p_xy * P_y
image, label = train_images[0], train_labels[0]
bayes_pred(image)
Bu korkunç bir şekilde yanlış gitti! Nedenini bulmak için piksel başına olasılıklara bakalım. Bunlar tipik
O bölümde tartışıldığı gibi, bunu
a = 0.1
print('underflow:', a**784)
print('logarithm is normal:', 784*math.log(a))
#@tab pytorch
a = 0.1
print('underflow:', a**784)
print('logarithm is normal:', 784*math.log(a))
#@tab tensorflow
a = 0.1
print('underflow:', a**784)
print('logarithm is normal:', 784*tf.math.log(a).numpy())
Logaritma artan bir fonksiyon olduğundan, :eqref:eq_naive_bayes_estimation
denklemini şu şekilde yeniden yazabiliriz:
$$ \hat{y} = \mathrm{argmax}y \ \log P_y[y] + \sum{i=1}^d \Big[t_i\log P_{xy}[x_i, y] + (1-t_i) \log (1 - P_{xy}[x_i, y]) \Big].$$
Aşağıdaki kararlı sürümü uygulayabiliriz:
log_P_xy = np.log(P_xy)
log_P_xy_neg = np.log(1 - P_xy)
log_P_y = np.log(P_y)
def bayes_pred_stable(x):
x = np.expand_dims(x, axis=0) # (28, 28) -> (1, 28, 28)
p_xy = log_P_xy * x + log_P_xy_neg * (1 - x)
p_xy = p_xy.reshape(10, -1).sum(axis=1) # p(x|y)
return p_xy + log_P_y
py = bayes_pred_stable(image)
py
#@tab pytorch
log_P_xy = torch.log(P_xy)
log_P_xy_neg = torch.log(1 - P_xy)
log_P_y = torch.log(P_y)
def bayes_pred_stable(x):
x = x.unsqueeze(0) # (28, 28) -> (1, 28, 28)
p_xy = log_P_xy * x + log_P_xy_neg * (1 - x)
p_xy = p_xy.reshape(10, -1).sum(axis=1) # p(x|y)
return p_xy + log_P_y
py = bayes_pred_stable(image)
py
#@tab tensorflow
log_P_xy = tf.math.log(P_xy)
log_P_xy_neg = tf.math.log(1 - P_xy)
log_P_y = tf.math.log(P_y)
def bayes_pred_stable(x):
x = tf.expand_dims(x, axis=0) # (28, 28) -> (1, 28, 28)
p_xy = log_P_xy * x + log_P_xy_neg * (1 - x)
p_xy = tf.math.reduce_sum(tf.reshape(p_xy, (10, -1)), axis=1) # p(x|y)
return p_xy + log_P_y
py = bayes_pred_stable(image)
py
Şimdi tahminin doğru olup olmadığını kontrol edebiliriz.
# Karşılaştırma için int32 dtype skaler tensörü olan etiketi
# Python skaler tamsayısına dönüştürün
py.argmax(axis=0) == int(label)
#@tab pytorch
py.argmax(dim=0) == label
#@tab tensorflow
tf.argmax(py, axis=0, output_type = tf.int32) == label
Şimdi birkaç geçerleme örneği tahmin edersek, Bayes sınıflandırıcısının oldukça iyi çalıştığını görebiliriz.
def predict(X):
return [bayes_pred_stable(x).argmax(axis=0).astype(np.int32) for x in X]
X, y = mnist_test[:18]
preds = predict(X)
d2l.show_images(X, 2, 9, titles=[str(d) for d in preds]);
#@tab pytorch
def predict(X):
return [bayes_pred_stable(x).argmax(dim=0).type(torch.int32).item()
for x in X]
X = torch.stack([mnist_test[i][0] for i in range(18)], dim=0)
y = torch.tensor([mnist_test[i][1] for i in range(18)])
preds = predict(X)
d2l.show_images(X, 2, 9, titles=[str(d) for d in preds]);
#@tab tensorflow
def predict(X):
return [tf.argmax(
bayes_pred_stable(x), axis=0, output_type = tf.int32).numpy()
for x in X]
X = tf.stack([train_images[i] for i in range(10, 38)], axis=0)
y = tf.constant([train_labels[i].numpy() for i in range(10, 38)])
preds = predict(X)
d2l.show_images(X, 2, 9, titles=[str(d) for d in preds]);
Son olarak, sınıflandırıcının genel doğruluğunu hesaplayalım.
X, y = mnist_test[:]
preds = np.array(predict(X), dtype=np.int32)
float((preds == y).sum()) / len(y) # Validation accuracy
#@tab pytorch
X = torch.stack([mnist_test[i][0] for i in range(len(mnist_test))], dim=0)
y = torch.tensor([mnist_test[i][1] for i in range(len(mnist_test))])
preds = torch.tensor(predict(X), dtype=torch.int32)
float((preds == y).sum()) / len(y) # Validation accuracy
#@tab tensorflow
X = test_images
y = test_labels
preds = tf.constant(predict(X), dtype=tf.int32)
# Validation accuracy
tf.reduce_sum(tf.cast(preds == y, tf.float32)).numpy() / len(y)
Modern derin ağlar
- Bayes kuralı kullanılarak, gözlenen tüm özniteliklerin bağımsız olduğu varsayılarak bir sınıflandırıcı yapılabilir.
- Bu sınıflandırıcı, etiket ve piksel değerlerinin kombinasyonlarının olma sayısını sayarak bir veri kümesi üzerinde eğitilebilir.
- Bu sınıflandırıcı, istenmeyen elektronik posta (spam) tespiti gibi görevler için onlarca yıldır altın standarttı.
-
$[[0,0], [0,1], [1,0], [1,1]]$ veri kümesini iki öğenin XOR tarafından verilen etiketleri ile,$[0,1,1,0]$ , düşünün. Bu veri kümesine dayanan bir naif Bayes sınıflandırıcısının olasılıkları nelerdir? Noktalarımızı başarıyla sınıflandırıyor mu? Değilse, hangi varsayımlar ihlal edilir? - Olasılıkları tahmin ederken Laplace düzleştirmeyi kullanmadığımızı ve eğitimde asla gözlenmeyen bir değer içeren bir veri örneğinin test zamanında geldiğini varsayalım. Model ne çıkarır?
- Naif Bayes sınıflandırıcısı, rastgele değişkenlerin bağımlılığının bir grafik yapısıyla kodlandığı belirli bir Bayes ağı örneğidir. Tam teorisi bu bölümün kapsamı dışında olsa da (tüm ayrıntılar için :cite:
Koller.Friedman.2009
çalışmasına bakınız), XOR modelinde iki girdi değişkeni arasında açık bağımlılığa izin vermenin neden başarılı bir sınıflandırıcı oluşturmaya izin verdiğini açıklayıniz.
:begin_tab:mxnet
Tartışmalar
:end_tab:
:begin_tab:pytorch
Tartışmalar
:end_tab:
:begin_tab:tensorflow
Tartışmalar
:end_tab: