.. _sec_naive_bayes: Naif (Saf) 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. .. raw:: html
mxnetpytorchtensorflow
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python %matplotlib inline import math from d2l import mxnet as d2l from mxnet import gluon, np, npx npx.set_np() d2l.use_svg_display() .. raw:: html
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python %matplotlib inline import math import torch import torchvision from d2l import torch as d2l d2l.use_svg_display() .. raw:: html
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python %matplotlib inline import math import tensorflow as tf from d2l import tensorflow as d2l d2l.use_svg_display() .. raw:: html
.. raw:: html
Optik Karakter Tanıma --------------------- 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 :math:`28` olan ve (:math:`28`, :math:`28`, :math:`1`) şekilli gri tonlamalı bir resimdir. Son kanal boyutunu kaldırmak için özelleştirilmiş bir dönüşüm kullanıyoruz. Ek olarak, veri kümesi her pikseli işaretsiz :math:`8` bitlik bir tamsayı ile temsil eder. Problemi basitleştirmek için bunları ikili öznitelikler halinde nicelendiriyoruz. .. raw:: html
mxnetpytorchtensorflow
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python 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) .. raw:: html
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python 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) .. raw:: html
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python ((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) .. raw:: html
.. raw:: html
İmgeyi ve ilgili etiketi içeren belirli bir örneğe erişebiliriz. .. raw:: html
mxnetpytorchtensorflow
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python image, label = mnist_train[2] image.shape, label .. raw:: latex \diilbookstyleoutputcell .. parsed-literal:: :class: output ((28, 28), array(4, dtype=int32)) .. raw:: html
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python image, label = mnist_train[2] image.shape, label .. raw:: latex \diilbookstyleoutputcell .. parsed-literal:: :class: output (torch.Size([28, 28]), 4) .. raw:: html
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python image, label = train_images[2], train_labels[2] image.shape, label.numpy() .. raw:: latex \diilbookstyleoutputcell .. parsed-literal:: :class: output (TensorShape([28, 28]), 4) .. raw:: html
.. raw:: html
Burada ``image`` değişkeninde saklanan örneğimiz, yüksekliği ve genişliği :math:`28` piksel olan bir imgeye karşılık gelir. .. raw:: html
mxnetpytorchtensorflow
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python image.shape, image.dtype .. raw:: latex \diilbookstyleoutputcell .. parsed-literal:: :class: output ((28, 28), dtype('float32')) .. raw:: html
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python image.shape, image.dtype .. raw:: latex \diilbookstyleoutputcell .. parsed-literal:: :class: output (torch.Size([28, 28]), torch.float32) .. raw:: html
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python image.shape, image.dtype .. raw:: latex \diilbookstyleoutputcell .. parsed-literal:: :class: output (TensorShape([28, 28]), tf.float32) .. raw:: html
.. raw:: html
Kodumuz her imgenin etiketini sayıl olarak depolar. Türü :math:`32` bitlik bir tamsayıdır. .. raw:: html
mxnetpytorchtensorflow
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python label, type(label), label.dtype .. raw:: latex \diilbookstyleoutputcell .. parsed-literal:: :class: output (array(4, dtype=int32), mxnet.numpy.ndarray, dtype('int32')) .. raw:: html
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python label, type(label) .. raw:: latex \diilbookstyleoutputcell .. parsed-literal:: :class: output (4, int) .. raw:: html
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python label.numpy(), label.dtype .. raw:: latex \diilbookstyleoutputcell .. parsed-literal:: :class: output (4, tf.int32) .. raw:: html
.. raw:: html
Aynı anda birden fazla örneğe de erişebiliriz. .. raw:: html
mxnetpytorchtensorflow
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python images, labels = mnist_train[10:38] images.shape, labels.shape .. raw:: latex \diilbookstyleoutputcell .. parsed-literal:: :class: output ((28, 28, 28), (28,)) .. raw:: html
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python 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 .. raw:: latex \diilbookstyleoutputcell .. parsed-literal:: :class: output (torch.Size([28, 28, 28]), torch.Size([28])) .. raw:: html
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python 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 .. raw:: latex \diilbookstyleoutputcell .. parsed-literal:: :class: output (TensorShape([28, 28, 28]), TensorShape([28])) .. raw:: html
.. raw:: html
Bu örnekleri görselleştirelim. .. raw:: html
mxnetpytorchtensorflow
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python d2l.show_images(images, 2, 9); .. figure:: output_naive-bayes_6e475d_75_0.svg .. raw:: html
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python d2l.show_images(images, 2, 9); .. figure:: output_naive-bayes_6e475d_78_0.svg .. raw:: html
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python d2l.show_images(images, 2, 9); .. figure:: output_naive-bayes_6e475d_81_0.svg .. raw:: html
.. raw:: html
Sınıflandırma için Olasılık Modeli ---------------------------------- Bir sınıflandırma görevinde, bir örneği bir kategoriye eşleriz. Burada bir örnek gri tonlamalı :math:`28\times 28` imge ve kategori bir rakamdır. (Daha ayrıntılı bir açıklama için bakınız :numref:`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? :math:`\mathbf x\in\mathbb R^d` ile örneğin özniteliklerini ve :math:`y\in\mathbb R` ile etiketini belirtiriz. Burada öznitelikler, :math:`2` boyutlu bir imgeyi :math:`d = 28 ^ 2 = 784` büyüklüğünde bir vektöre yeniden şekillendirebileceğimiz imge pikselleri ve etiketler rakamlardır. Öznitelikleri verilen etiketin olasılığı :math:`p(y \mid \mathbf{x})` şeklindedir. Örneğimizde :math:`y=0, \ldots, 9` için :math:`p(y \mid \mathbf{x})` olan bu olasılıkları hesaplayabilirsek, sınıflandırıcı aşağıda verilen ifade ile tahminini, :math:`\hat{y}`, yapacaktır: .. math:: \hat{y} = \mathrm{argmax} \> p(y \mid \mathbf{x}). Maalesef bu, her :math:`\mathbf{x} = x_1, ..., x_d` değeri için :math:`p(y \mid \mathbf{x})`'yi tahmin etmemizi gerektirir. Her özniteliğin :math:`2` değerden birini alabileceğini düşünün. Örneğin, :math:`x_1 = 1` özniteliği, elma kelimesinin belirli bir belgede göründüğünü ve :math:`x_1 = 0` görünmediğini belirtebilir. Eğer :math:`30` tane bu tür ikili özniteliğe sahip olsaydık, bu :math:`\mathbf{x}` girdi vektörünün :math:`2^{30}` (1 milyardan fazla!) olası değerlerinden herhangi birini sınıflandırmaya hazırlıklı olmamız gerektiği anlamına gelirdi. 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. Naif Bayes Sınıflandırıcı ------------------------- 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: .. math:: \hat{y} = \mathrm{argmax}_y \> p(y \mid \mathbf{x}) = \mathrm{argmax}_y \> \frac{p( \mathbf{x} \mid y) p(y)}{p(\mathbf{x})}. Paydanın normalleştirme teriminin :math:`p(\mathbf{x})` olduğunu ve :math:`y` etiketinin değerine bağlı olmadığını unutmayın. Sonuç olarak, sadece payı farklı :math:`y` değerlerinde karşılaştırken endişelenmemiz gerekiyor. Paydanın hesaplanmasının zorlu olduğu ortaya çıksa bile, payı değerlendirebildiğimiz sürece onu görmezden gelerek kurtulabilirdik. Neyse ki, normalleştirme sabitini kurtarmak istesek, bunu da yapabilirdik. Normalleştirme terimini :math:`\sum_y p(y \mid \mathbf{x}) = 1` olduğundan her zaman kurtarabiliriz. Şimdi :math:`p( \mathbf{x} \mid y)` üzerine odaklanalım. Zincir olasılık kuralını kullanarak :math:`p( \mathbf{x} \mid y)` terimini şu şekilde ifade edebiliriz: .. math:: p(x_1 \mid y) \cdot p(x_2 \mid x_1, y) \cdot ... \cdot p( x_d \mid x_1, ..., x_{d-1}, y). Tek başına bu ifade bizi daha ileriye götürmez. Yine de kabaca :math:`2^d` tane parametreyi tahmin etmeliyiz. Bununla birlikte, *etiketi verildiğinde özniteliklerin koşullu olarak birbirinden bağımsız olduğunu varsayarsak*, aniden çok daha iyi durumda oluruz, çünkü bu terim :math:`\prod_i p(x_i \mid y)`'a sadeleşerek bize şu tahminciyi verir: .. math:: \hat{y} = \mathrm{argmax}_y \> \prod_{i=1}^d p(x_i \mid y) p(y). Her :math:`i` ve :math:`y` için :math:`p(x_i=1 \mid y)` tahmin edebilir ve değerini :math:`P_{xy}[i, y]` olarak kaydedebilirsek, burada :math:`P_{xy}` :math:`n` sınıf sayısı ve :math:`y\in\{1, \ldots, n\}` olan bir :math:`d\times n` matrisidir, o zaman bunu :math:`p(x_i = 0 \mid y)`'i tahmin etmek için de kullanabiliriz, yani .. math:: p(x_i = t_i \mid y) = \begin{cases} P_{xy}[i, y] & \text{öyle ki } t_i=1 ;\\ 1 - P_{xy}[i, y] & \text{öyle ki } t_i = 0 . \end{cases} Ayrıca, her :math:`y` için :math:`p(y)` tahmininde bulunur ve :math:`n` uzunluğunda bir :math:`P_y` vektörü ile, :math:`P_y[y]`'a kaydederiz. Ardından, herhangi bir yeni örnek :math:`\mathbf t = (t_1, t_2, \ldots, t_d)` için şunu hesaplayabiliriz; .. math:: \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} :label: eq_naive_bayes_estimation üstelik herhangi bir :math:`y` için. Dolayısıyla, koşullu bağımsızlık varsayımımız, modelimizin karmaşıklığını öznitelik sayısına bağlı :math:`\mathcal{O}(2^dn)` üstel bir bağımlılıktan :math:`\mathcal{O}(dn)` olan doğrusal bir bağımlılığa almıştır. Eğitim ------ Şimdi sorun, :math:`P_{xy}` ve :math:`P_y`'yi bilmiyor olmamızdır. Bu nedenle, önce bazı eğitim verileri verildiğinde bu değerleri tahmin etmemiz gerekiyor. Bu, modeli *eğitmektir*. :math:`P_y`'yi tahmin etmek çok zor değil. Sadece :math:`10` sınıfla uğraştığımız için, her rakam için görülme sayısını, :math:`n_y`, sayabilir ve bunu toplam veri miktarına :math:`n` bölebiliriz. Örneğin, 8 rakamı :math:`n_8 = 5.800` kez ortaya çıkarsa ve toplam :math:`n = 60.000` imgemiz varsa, olasılık tahminimiz :math:`p(y=8) = 0.0967` olur. .. raw:: html
mxnetpytorchtensorflow
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python 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 .. raw:: latex \diilbookstyleoutputcell .. parsed-literal:: :class: output array([0.09871667, 0.11236667, 0.0993 , 0.10218333, 0.09736667, 0.09035 , 0.09863333, 0.10441667, 0.09751666, 0.09915 ]) .. raw:: html
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python 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 .. raw:: latex \diilbookstyleoutputcell .. parsed-literal:: :class: output tensor([0.0987, 0.1124, 0.0993, 0.1022, 0.0974, 0.0904, 0.0986, 0.1044, 0.0975, 0.0992]) .. raw:: html
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python 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 .. raw:: latex \diilbookstyleoutputcell .. parsed-literal:: :class: output .. raw:: html
.. raw:: html
Şimdi biraz daha zor şeylere, :math:`P_{xy}`'ye, geçelim. Siyah beyaz imgeler seçtiğimiz için, :math:`p(x_i \mid y)`, :math:`i` pikselinin :math:`y` sınıfı için açık olma olasılığını gösterir. Tıpkı daha önce olduğu gibi, bir olayın meydana geldiği :math:`n_{iy}` sayısını sayabilmemiz ve bunu :math:`y`'nin toplam oluş sayısına bölebilmemiz gibi, yani :math:`n_y`. Ancak biraz rahatsız edici bir şey var: Belirli pikseller asla siyah olmayabilir (örneğin, iyi kırpılmış imgelerde köşe pikselleri her zaman beyaz olabilir). İstatistikçilerin bu sorunla baş etmeleri için uygun bir yol, tüm oluşumlara sözde sayımlar eklemektir. Bu nedenle, :math:`n_{iy}` yerine :math:`n_{iy} + 1` ve :math:`n_y` yerine :math:`n_{y} + 1` kullanıyoruz. Bu aynı zamanda *Laplace Düzleştirme (Smoothing)* olarak da adlandırılır. Geçici görünebilir, ancak Bayesci bir bakış açısından iyi motive edilmiş olabilir. .. raw:: html
mxnetpytorchtensorflow
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python 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); .. figure:: output_naive-bayes_6e475d_99_0.svg .. raw:: html
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python 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); .. figure:: output_naive-bayes_6e475d_102_0.svg .. raw:: html
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python 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); .. figure:: output_naive-bayes_6e475d_105_0.svg .. raw:: html
.. raw:: html
Bu :math:`10 \times 28 \times 28` olasılıkları görselleştirerek (her sınıf için her piksel için) ortalama görünümlü rakamlar elde edebiliriz. Şimdi yeni bir imgeyi tahmin etmek için :eq:`eq_naive_bayes_estimation` denklemini kullanabiliriz. :math:`\mathbf x` verildiğinde, aşağıdaki işlevler her :math:`y` için :math:`p(\mathbf x \mid y)p(y)`'yi hesaplar. .. raw:: html
mxnetpytorchtensorflow
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python 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) .. raw:: latex \diilbookstyleoutputcell .. parsed-literal:: :class: output array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]) .. raw:: html
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python 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) .. raw:: latex \diilbookstyleoutputcell .. parsed-literal:: :class: output tensor([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]) .. raw:: html
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python 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) .. raw:: latex \diilbookstyleoutputcell .. parsed-literal:: :class: output .. raw:: html
.. raw:: html
Bu korkunç bir şekilde yanlış gitti! Nedenini bulmak için piksel başına olasılıklara bakalım. Bunlar tipik :math:`0.001` ile :math:`1` arasındaki sayılardır. :math:`784` tanesini çarpıyoruz. Bu noktada, bu sayıları bir bilgisayarda sabit bir aralıkla hesapladığımızı belirtmekte fayda var, dolayısıyla bu kuvvet için de geçerli. Olan şu ki, *sayısal küçümenlik (underflow)* yaşıyoruz, yani tüm küçük sayıları çarpmak, sıfıra yuvarlanana kadar daha da küçük değerlere yol açar. Bunu teorik bir mesele olarak :numref:\`sec\_maximum\_likelihood içinde tartıştık, ancak burada pratikteki bir vaka olarak açıkça görüyoruz. O bölümde tartışıldığı gibi, bunu :math:`\log a b = \log a + \log b` gerçeğini kullanarak, yani logaritma toplamaya geçerek düzeltiriz. Hem :math:`a` hem de :math:`b` küçük sayılar olsa bile, logaritma değerleri uygun bir aralıkta olacaktır. .. raw:: html
mxnetpytorchtensorflow
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python a = 0.1 print('underflow:', a**784) print('logarithm is normal:', 784*math.log(a)) .. raw:: latex \diilbookstyleoutputcell .. parsed-literal:: :class: output underflow: 0.0 logarithm is normal: -1805.2267129073316 .. raw:: html
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python a = 0.1 print('underflow:', a**784) print('logarithm is normal:', 784*math.log(a)) .. raw:: latex \diilbookstyleoutputcell .. parsed-literal:: :class: output underflow: 0.0 logarithm is normal: -1805.2267129073316 .. raw:: html
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python a = 0.1 print('underflow:', a**784) print('logarithm is normal:', 784*tf.math.log(a).numpy()) .. raw:: latex \diilbookstyleoutputcell .. parsed-literal:: :class: output underflow: 0.0 logarithm is normal: -1805.2267379760742 .. raw:: html
.. raw:: html
Logaritma artan bir fonksiyon olduğundan, :eq:`eq_naive_bayes_estimation` denklemini şu şekilde yeniden yazabiliriz: .. math:: \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: .. raw:: html
mxnetpytorchtensorflow
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python 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 .. raw:: latex \diilbookstyleoutputcell .. parsed-literal:: :class: output array([-269.0042 , -301.73447, -245.21458, -218.8941 , -193.46907, -206.10315, -292.54315, -114.62834, -220.35619, -163.18881]) .. raw:: html
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python 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 .. raw:: latex \diilbookstyleoutputcell .. parsed-literal:: :class: output tensor([-269.0042, -301.7345, -245.2146, -218.8941, -193.4691, -206.1031, -292.5432, -114.6283, -220.3562, -163.1888]) .. raw:: html
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python 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 .. raw:: latex \diilbookstyleoutputcell .. parsed-literal:: :class: output .. raw:: html
.. raw:: html
Şimdi tahminin doğru olup olmadığını kontrol edebiliriz. .. raw:: html
mxnetpytorchtensorflow
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python # 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) .. raw:: latex \diilbookstyleoutputcell .. parsed-literal:: :class: output array(True) .. raw:: html
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python py.argmax(dim=0) == label .. raw:: latex \diilbookstyleoutputcell .. parsed-literal:: :class: output tensor(True) .. raw:: html
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python tf.argmax(py, axis=0, output_type = tf.int32) == label .. raw:: latex \diilbookstyleoutputcell .. parsed-literal:: :class: output .. raw:: html
.. raw:: html
Ş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. .. raw:: html
mxnetpytorchtensorflow
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python 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]); .. figure:: output_naive-bayes_6e475d_159_0.svg .. raw:: html
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python 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]); .. figure:: output_naive-bayes_6e475d_162_0.svg .. raw:: html
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python 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]); .. figure:: output_naive-bayes_6e475d_165_0.svg .. raw:: html
.. raw:: html
Son olarak, sınıflandırıcının genel doğruluğunu hesaplayalım. .. raw:: html
mxnetpytorchtensorflow
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python X, y = mnist_test[:] preds = np.array(predict(X), dtype=np.int32) float((preds == y).sum()) / len(y) # Validation accuracy .. raw:: latex \diilbookstyleoutputcell .. parsed-literal:: :class: output 0.8426 .. raw:: html
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python 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 .. raw:: latex \diilbookstyleoutputcell .. parsed-literal:: :class: output 0.8426 .. raw:: html
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python 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) .. raw:: latex \diilbookstyleoutputcell .. parsed-literal:: :class: output 0.8426 .. raw:: html
.. raw:: html
Modern derin ağlar :math:`0.01`'den daha düşük hata oranlarına ulaşır. Nispeten düşük performans, modelimizde yaptığımız yanlış istatistiksel varsayımlardan kaynaklanmaktadır: Her pikselin yalnızca etikete bağlı olarak *bağımsızca* oluşturulduğunu varsaydık. İnsanların rakamları böyle yazmadığı açıktır ve bu yanlış varsayım, aşırı naif (Bayes) sınıflandırıcımızın çökmesine yol açtı. Özet ---- - 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ı. Alıştırmalar ------------ 1. :math:`[[0,0], [0,1], [1,0], [1,1]]` veri kümesini iki öğenin XOR tarafından verilen etiketleri ile, :math:`[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? 2. 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? 3. 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. .. raw:: html
mxnetpytorchtensorflow
.. raw:: html
`Tartışmalar `__ .. raw:: html
.. raw:: html
`Tartışmalar `__ .. raw:: html
.. raw:: html
`Tartışmalar `__ .. raw:: html
.. raw:: html