Python ile Makine Öğrenmesi 2: “camdan beyin yapmak”
Yeniden merhabalar, artık kulaklığı takıp ellerimizi klavyeyle buluşturma zamanı geldi 😀
Bu bölümde, ilk sınıflandırma algoritmalarından biri olarak tanımlanmış algılayıcı nöronlardan bahsedeceğiz. Python da adım adım bir algılayıcı yazıp, verileri okumak, işlemek ve görselleştirmek için kütüphaneleri etkin bir şekilde kullanacağız. İlk olarak yapacağımız işi somutlaştırarak gidelim:
Spin camları, cam benzeri özelliklere sahip olsalar da aslında cam değildir; daha çok manyetik materyallerdir. Her elektron “yukarı” veya “aşağı” işaret edebilen spini nedeniyle küçük bir mıknatıstır. Hopfield, spin camlarla sinir ağları arasında ilginç bir benzerlik elde etmiştir. Bir elektronun spini kendi çevresindekilerin davranışına tıpkı nöron gibi cevap verir. Elektron; komşularının toplam ağırlığı, bir eşiği aşarsa yukarı dönerken aksi halde aşağı döner veya o şekilde kalır. Bundan ilham alan Hopfield zaman içinde tıpkı bir spin camı gibi evrimleşen bir sinir ağı tipi tanımlamış.
Her nöron küçük bir ağaç gibidir; çok sayıda kök (dentritler) ve narin, dolambaçlı bir gövdeye (akson) sahiptir. Beyin bu ağaçlardan milyarlarcasını barındıran bir ormandır ama olağandışı bir yanı vardır. Her ağacın kökleri, başka binlerce ağacın kökleriyle bağlantılar (sinaps) kurduğundan muazzam bir karmaşa oluşturur. Beynimizdeki aksonlar uç uca eklendiklerinde dünyadan aya uzanırlar 😀
Bu orman elektrikle yüklüdür. Kıvılcımlar ağaç gövdelerinde ilerler ve komşu ağaçlarda başka kıvılcımlara sebep olur. Ara sıra bu ormanın bütün bir bölgesi çıldırmışçasına aktif hale gelir ve sonra tekrar yatışır. Beynimiz bu elektrik kıvılcımlarının bir senfonisidir.
Bir nöronun ilk modeli bilgisayarların oluşturduğu mantık kapılarına çok benziyor. Girdilerinden en az biri etkinse VEYA kapısı, girdilerinin hepsi etkinse VE kapısı etkin olur. Bir nöron aktif girdilerinin sayısı belli bir eşiği geçtikten sonra etkinleşir. Bu eşik birse nöron VEYA kapısı vazifesi görür; eğer eşik, girdilerin sayısına eşitse VE kapısı görevi görür. Ayrıca bir nöron başka bir nöronun etkinleşmesini önleyebilir, bu da hem engelleyici sinapsları hem de DEĞİL kapılarını modeller.
Kıvılcımı kim, nasıl çıkaracak?
Bir nöronun öğrenmesi için, nöronlar arasındaki bağlantılara değişen ağırlıklar vermemiz gerekir ve bu algılayıcı (perceptron) dediğimiz şeydir.
Algılayıcılar, girdi özelliklerinin ağırlık toplamı eşiğin üzerindeyse 1 çıktısını, altındaysa 0 çıktısını verir.
Bir girdinin ağırlığı ne kadar fazlaysa, ilgili sinaps o kadar güçlü olur. Hücre gövdesi, tüm girdileri toplar ve akson toplam sonuca bir aktivasyon fonksiyonu uygular.
y: x’in değerine bağlı olduğundan bağımlı değişkendir. Girdiye ait skoru verir.
x: bağımsız değişken (girdi)
W: ağırlık parametresi
b: iki sınıfı birbirinden ayıran doğruyu (karar sınırını) başlangıç noktasından uzaklaştırmayı sağlar (bias değeri)
İris Veri Setinde bir Perceptron Modeli Eğitimi
Perceptron kuralının nasıl çalıştığını öğrendik; Şimdi devam edelim ve python‘da iris verisinde uygulayalım.
İlk olarak excel, json, csv gibi birçok farklı kaynaklardan veri okumak ve veriyi manipülasyonu işlemleri için Pandas kütüphanesini aktifleştirelim. İçerisinde birçok tipte değişken tutabilir; DataFrame tablo yapısını içinde barındırır.
Veriyi çektikten sonra ilk beş gözlemine .head() fonksiyonuyla göz atalım:
import pandas as pd df = pd.read_csv("https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data", header=None) df.head()
Hızlı matematiksel işlemler yapabileceğimiz diziler sunan, python nun liste veri yapısına göre oldukça hızlı çalışan Numpy kütüphanesini ve bize harika grafikler sunan matplotlib kütüphanesini yükeleyelim.
Ardından, sırasıyla 50 Iris-Setosa ve 50 Iris-Versicolor çiçeklerine karşılık gelen ilk 100 gözlemi alalım ve setosa ise -1, versicolor ise 1 değeri alan bir y değişkeni oluşturalım. Akabinde bu 100 gözlemin birinci (sepal length) ve üçüncü (petal length) özelliklerini alıp, saçılım grafiklerini çizdirelim:
import numpy as np import matplotlib.pyplot as plt y = df.iloc[0:100, 4].values y = np.where(y == 'Iris-setosa', -1, 1) X = df.iloc[0:100, [0,2]].values plt.scatter(X[:50, 0], X[:50, 1], color='darkorange', marker='o', label='setosa') plt.scatter(X[50:100, 0], X[50:100, 1],color = 'darkblue', marker = 'x', label = 'versicolor') plt.xlabel('sepal length') plt.ylabel('petal length') plt.legend(loc='upper left') plt.show()
Şimdi perceptron arayüzünü python sınıfı olarak tanımlayalım.
Girdileri almak ve bunları bir çıktıya dönüştürmek için sınıfımızda bir fonksiyon yaratmamız gerekir. Bunu her girdiyi kendi ağırlığıyla çarparak, hepsini bir araya toplayarak ve sonra toplamın sıfırdan büyük olup olmadığını kontrol ederek yapıyoruz. Perceptron sınıfınıza, bu paremetreleri __init__ işlevinden sonra ekliyoruz.
learningRate, algılayıcımızın ne kadar hızlı öğreneceğini kontrol etmek için kullanılır. Değer ne kadar düşük olursa, öğrenmesi o kadar uzun sürer. Bu parametre çok yüksekse, programımız ağırlıklarını o kadar hızlı değiştirecek ve yanlış olacaktır. Öte yandan, learningRate çok düşükse, algılayıcıyı doğru bir şekilde eğitmek sonsuza dek sürecektir. Bu parametre için iyi bir değer yaklaşık 0.01-0.05’tir.
class Perceptron(object): def __init__(self, learningRate=0.01, n_iter=50, random_state=1): self.learningRate = learningRate self.n_iter = n_iter self.random_state = random_state self.errors_ = []
Daha sonra eğitttiğimiz modelde verilerimizi tahmin etmek için X dizisini ve y etiketini girdi olarak alan fit işlevimizi tanımlıyoruz. Random_generator ü daha önce tanımlanmış olan random_state parametremizi seçerek de başlattık. Ardından X girdi vektörünün boyutunu alacağız. X vektörünün yanlılık terimi içermediğini varsayıyoruz. Bu yüzden x_columns sayısına 1 ekleriz.
Tüm ağırlıkları sıfıra veya küçük bir rasgele sayıya ayarlamak için ağırlıklarımızı, ortalama 0 ve standart sapma 0.001 olan normal bir dağılımından gelen rasgele sayıyla başlatıyoruz.
def fit(self, X, y): random_generator = np.random.RandomState(self.random_state) x_rows, x_columns = X.shape x_columns = x_columns+1 self.weights = random_generator.normal(loc=0.0, scale=0.001, size=x_columns)
Her bir örnek için tahmin yapma zamanı. Bunu ilkel bir yöntem olan döngüyle yapıyoruz 😀
for _ in range(self.n_iter): errors = 0 for xi, y_actual in zip(X, y): #xi icin tahmin degerleri y_predicted = self.predict(xi)
Ağırlıklar başlatıldıktan sonra, model eğitim setindeki tüm örnekler üzerinde dolaşır ve algılayıcı, öğrenme kuralına göre ağırlıkları günceller. Bir algılayıcının ağırlıklarını öğrenmek, tüm pozitif örnekler bir tarafta ve tüm negatif örnekler diğer tarafta oluncaya dek düz bir çizginin yönünü değişime uğratmak anlamına gelir. Algılayıcının aktif hale gelip gelmediğine karar vermek için her ağırlığı ilgili girdiyle çarpıp hepsinin toplamını eşik ile karşılaştırırız.
delta = self.learningRate*(y_actual - y_predicted) self.weights[1:] += delta * xi self.weights[0] += delta errors += int(delta != 0.0) self.errors_.append(errors)
Ayrıca, self.errors_ listesinde her iterasyonda yanlış sınıflandırma sayısını da toplayabiliriz.
Daha sonra, algılayıcımızın eğitim sırasında ne kadar iyi çalıştığını analiz edelim. np.dot işleviyle de WT · X hesaplayan Z fonksiyonumuzu ekliyoruz. Bunun sonucunda tahmin fonksiyonumuz Z’nin çıktısını alır ve 1 ya da -1 etiketini döndürür.
def Errors(self): return self.errors_ def z(self, X): z = np.dot(X, self.weights[1:]) + self.weights[0] return z def predict(self, X): return np.where(self.z(X) >= 0.0, 1, -1)
Eveeett itinayla yazdığımız Perceptron algoritmasını iris verisi üzerinde deneme zamanı 😀 Tahminlerimizi oluşturduktan sonra her iterasyon için yanlış sınıflandırma sayılarını grafik üzerinde görelim:
ppn = Perceptron(learningRate=0.1, n_iter=10) ppn.fit(X, y) plt.plot(range(1, len(ppn.errors_) + 1), ppn.errors_,marker='o') plt.xlabel('Epochs') plt.ylabel('Number of misclassifications') plt.show()
İlk önce, ListedColormap ile bir dizi renk ve belirteç tanımlarız. Daha sonra, iki özellik için minimum ve maksimum değerleri belirleriz ve bu özellik vektörlerini, NumPy meshgrid işlevi aracılığıyla xx1 ve xx2 ızgara dizileri oluşturmak için kullanırız. Perceptron sınıflandırıcımızı iki özellikle eğittiğimizden, ızgara dizilerini; iris eğitim verisiyle aynı sayıda sütuna sahip bir matristen oluşturmamız gerekir. Tahmin ettiğimiz Z sınıfı etiketlerini, xx1 ve xx2 ile aynı boyutlara sahip bir ızgaraya atayalım.
from matplotlib.colors import ListedColormap def plot_decision_regions(X, y, classifier, resolution=0.02): markers = ('s', 'x', 'o', '^', 'v') colors = ('darkorange', 'darkblue', 'lightgreen', 'gray', 'cyan') cmap = ListedColormap(colors[:len(np.unique(y))]) x1_min, x1_max = X[:, 0].min() - 1, X[:, 0].max() + 1 x2_min, x2_max = X[:, 1].min() - 1, X[:, 1].max() + 1 xx1, xx2 = np.meshgrid(np.arange(x1_min, x1_max, resolution), np.arange(x2_min, x2_max, resolution)) Z = classifier.predict(np.array([xx1.ravel(), xx2.ravel()]).T) Z = Z.reshape(xx1.shape) plt.contourf(xx1, xx2, Z, alpha=0.4, cmap=cmap) plt.xlim(xx1.min(), xx1.max()) plt.ylim(xx2.min(), xx2.max()) for idx, cl in enumerate(np.unique(y)): plt.scatter(x=X[y == cl, 0], y=X[y == cl, 1], alpha=0.8, c=cmap(idx), marker=markers[idx], label=cl)
plot_decision_regions(X, y, classifier=ppn) plt.xlabel('sepal length [cm]') plt.ylabel('petal length [cm]') plt.legend(loc='upper left') plt.show()
Grafikten görebileceğimiz gibi Perceptron algoritmamız, iris eğitim verisindeki tüm çiçek örneklerini mükemmel bir şekilde sınıflandırabilen bir karar sınırı öğrendi.
Perceptron sadece doğrusal ayrılabilir örüntüleri sınıflandırabildiği için ve buna karşılık birçok problem doğrusal ayırılabilir olmadığından bu durum perceptron algoritmasının önemli eksiklerinden biriydi. Bu durumu Master Algoritma kitabından güzel bir örnekle anlatmak istiyorum: Nike ayakkabılarına en düşkün iki nüfusun genç erkekler ve orta yaşlı kadınlar olduğu kabul ediliyor. Peki Perceptron algoritmamız genç-kadın, orta yaşlı erkekler söz konusu olduğunda nasıl karar verecek? Burada perceptron algoritmamız patlıyor.
Peki ne yapacağız?
Gelecek hafta hiper uzayda dağlara tırmanmak için hazırlanın 😀
KAYNAKLAR
Sebastian Raschka – Python Machine Learning
https://sebastianraschka.com/Articles/2015_singlelayer_neurons.html
http://www.derinogrenme.com/2017/03/04/yapay-sinir-aglari/
https://stats.stackexchange.com/questions/71335/decision-boundary-plot-for-a-perceptron
https://towardsdatascience.com/applied-deep-learning-part-1-artificial-neural-networks-d7834f67a4f6
https://medium.com/@nikhilc3013/simple-perceptron-training-algorithm-explained-7bbfdff2c57d
https://www.python-course.eu/neural_networks_with_python_numpy.php
https://www.datacamp.com/community/tutorials/deep-learning-python
https://www.python-course.eu/neural_networks.php
https://www.kaggle.com/lalitharajesh/iris-dataset-exploratory-data-analysis
https://machinelearningmastery.com/implement-perceptron-algorithm-scratch
https://www.springboard.com/blog/beginners-guide-neural-network-in-python-scikit-learn