{"cells":[{"metadata":{},"cell_type":"markdown","source":"**CNN İLE ANLAŞMAK**"},{"metadata":{},"cell_type":"markdown","source":"Merhaba, bu yazımda kaggle içerisinde meşhur bir data olan Dogs vs Cats ile evrişimli sinir ağlarına ait bir örnek yapacağım.\n\nBurada hem bir evrişimli sinir ağı için data nasıl hazırlanır hemde evrişimli sinir ağları nasıl çalışır bunları inceleyeceğim.\n\nAynı zamanda evrişimli sinir ağlarının bir kara kutu olup olmadığını elimden geldiğince anlatmaya çalışacağım."},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Datayı hazırlamadan önce datayı nasıl çıkaracağız buna bakalım.\n\nData zip dosyası içinde bu nedenle önce zip dosyasından çıkarmak gerekiyor. Çıkan zip dosyası çalışma sayfasındaki output'un altında working klasörü içinde olacaktır."},{"metadata":{"trusted":true},"cell_type":"code","source":"import zipfile\n\nzip_files = ['test1', 'train']\nfor zip_file in zip_files:\n    with zipfile.ZipFile(\"/kaggle/input/dogs-vs-cats/{}.zip\".format(zip_file),\"r\") as z:\n        z.extractall(\".\")\n        print(\"{} unzipped\".format(zip_file))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Daha sonra train datasını liste şeklinde alalım ileride bu listeyi etiketleri belirken kullanacağız."},{"metadata":{"trusted":true},"cell_type":"code","source":"image_path = \"./train\"\nfile_names = os.listdir(image_path)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"os.path.join(image_path, file_names[0])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Fotoğraf lisesinin bir örneği"},{"metadata":{"trusted":true},"cell_type":"code","source":"file_names[0].split(\".\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Şimdi datayı hazırlamak için target ve train diye iki boş liste oluşturuyorum. Burada targets'lara fotoğrafın kedi veya köpek olduğu bilgisini vereceğim bunun için yukarıdaki file_names değişkeninden yararlanacağım. Train için ise sadece train klasörü ve peşine resim ismini ekleyeceğim bu kadar."},{"metadata":{"trusted":true},"cell_type":"code","source":"targets = []\ntrain = []\n\nfor file_name in file_names:\n    target = file_name.split(\".\")[0]\n    trains = os.path.join(\"./train\", file_name)\n    train.append(trains)\n    targets.append(target)\n    \n\ndata = pd.DataFrame()\ndata[\"image\"] = train\ndata[\"target\"] = targets\n\ndata.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Evet datamız yukarıdak gibi hazırlandı ve bu kadar. Gördüğünüz gibi resim üzerine çalışıyor olsak da datamız aslında resimlerin kaynakları yani nerede oldukları bilgisi ve bu resimlerin ne oldukları bilgisinden ibaret.\n\nİkinci aşamada train içindeki resimleri train ve validation olarak bölme işlemine geldi. Burada klasik makine öğrenmesinden işlemi uyguluyorum ardından train datamın içindeki resimleri çeşitlendirmek için onları döndürme, büyütme, kaydırma gibi işlemleri tabi tutuyorum."},{"metadata":{"trusted":true},"cell_type":"code","source":"from sklearn.model_selection import train_test_split\n\ntrain_data, test_data = train_test_split(data, test_size = 0.2)\n\n\n\n\nfrom keras.preprocessing.image import ImageDataGenerator\n\ntrain_datagen = ImageDataGenerator(rescale = 1./255,\n                                   rotation_range = 40,\n                                   width_shift_range = 0.2,\n                                   height_shift_range = 0.2,\n                                   shear_range = 0.2,\n                                   zoom_range = 0.2,\n                                   horizontal_flip = True,\n                                   fill_mode = \"nearest\")\n\ntrain_generator = train_datagen.flow_from_dataframe(dataframe = train_data,\n                                                    x_col = \"image\",\n                                                    y_col = \"target\",\n                                                    target_size = (150, 150),\n                                                    class_mode = \"binary\",\n                                                    batch_size = 100)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"train_generator isimli değişkende aslında train datamın ne olduğu bu data içirisindeki bağımlı ve bağımsız değişkenin ne olduğunu resimlerin boyutlarını ve bu resimlerin sadece iki çıktısı olduğunu söylüyorum.\n\nBatch_size olarak 100 kullandım bu 20.000 elemanlı data üzerinden 100'er gruplar halinde data al demek.Neden datanın tamamı değilde sadece 100 tane? Aslıdan datanın tamamını kullanacağız fakat 100'lük gruplar halinde bu eğitim işlemimizin daha kısa sürede gerçekleşmesini sağlayacak elbette büyük batch_size ile çalışmak daha iyi model kurmamıza yarar sağlayabilir fakat performans olarak bu işlem uzun sürmesi muhtemeldir.\n\nResimlerde yaptğımız değişikliği görmek için bir örnek çizdirelim."},{"metadata":{"trusted":true},"cell_type":"code","source":"from keras.preprocessing import image\nimport matplotlib.pyplot as plt\n\nfnames = [os.path.join(image_path, fname) for fname in os.listdir(image_path)]\n\nimg_path = fnames[2]\n\nimg = image.load_img(img_path, target_size = (150, 150))\n\nx = image.img_to_array(img)\nx = x.reshape((1, ) + x.shape)\ni = 0\n\nfor batch in train_datagen.flow(x, batch_size = 1):\n    plt.figure()\n    imgplot = plt.imshow(image.array_to_img(batch[0]))\n    i += 1\n    if i % 4 == 0:\n        break\n\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Resim çeşitlendirmenin ne gibi bir faydası var?\n\n> Aşırı uydurma, öğrenilecek çok az veri olduğunda modeli eğitmenin yeni verilere genelleştirmemesini olarak ortaya çıkar. Sonsuz veri olduğunda modeliniz var olan tüm veri dağılımlarını ortaya çıkarabilir ve asla aşırı uydurmaz. Veri seti çeşitlendirme eldeki verilerin birtakım döünüşümler ile gerçeğe yakın daha fazla eğitim verisi oluşturur. Amaç, eğitim esnasında modelinizi aynı resmi ikinci kez görmemesidir. Bu modelinizin daha çok örüntü aramasına ve daha iyi genelleştirmesini sağlar\n                                                        \n                                                        Francois Chollet, Deep Learning with Python sf147\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"test_datagen = ImageDataGenerator(rescale = 1./255)\n\ntest_generator = test_datagen.flow_from_dataframe(dataframe = test_data,\n                                                 x_col = \"image\",\n                                                 y_col = \"target\",\n                                                 target_size = (150, 150),\n                                                 class_mode = \"binary\",\n                                                 batch_size = 100)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Model için 4 katlı Conv2D hazırladım. Her katmandan sonra maxpooling işlemi yapıyorum. Katmanalardaki filtreler 3x3'lük activasyon fonksiyonu relu'yu tercih ettim. Son dense katmanında tahmin değerlerim 0 ile 1 arasında değerler alacağı için sigmoid fonksiyonunu kullandım. Compile aşamasında kayıp değeri için ikili sınıf olduğu için binarty_crossentropy kullandım. Model çıktısında yaklaşık 3.5 mio parametre var."},{"metadata":{"trusted":true},"cell_type":"code","source":"from keras import layers\nfrom keras import models\nfrom keras import optimizers\n\nmodel = models.Sequential()\nmodel.add(layers.Conv2D(32, (3, 3), activation = \"relu\", input_shape = (150, 150, 3)))\nmodel.add(layers.MaxPooling2D((2, 2)))\nmodel.add(layers.Conv2D(64, (3, 3), activation = \"relu\"))\nmodel.add(layers.MaxPooling2D((2, 2)))\nmodel.add(layers.Conv2D(128, (3, 3), activation = \"relu\"))\nmodel.add(layers.MaxPooling2D((2, 2)))\nmodel.add(layers.Conv2D(128, (3, 3), activation = \"relu\"))\nmodel.add(layers.MaxPooling2D((2, 2)))\nmodel.add(layers.Flatten())\nmodel.add(layers.Dropout(0.5))\nmodel.add(layers.Dense(512, activation = \"relu\"))\nmodel.add(layers.Dense(1, activation = \"sigmoid\"))\n\nmodel.compile(loss = \"binary_crossentropy\",\n             optimizer = optimizers.RMSprop(lr = 1e-4),\n             metrics = [\"acc\"])\n\nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Modeli çalıştırmak."},{"metadata":{"trusted":true},"cell_type":"code","source":"history = model.fit_generator(train_generator,\n                             steps_per_epoch = 200,\n                             epochs = 100,\n                             validation_data = test_generator,\n                             validation_steps = 50)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import matplotlib.pyplot as plt\n\nacc = history.history[\"acc\"]\nval_acc = history.history[\"val_acc\"]\nloss = history.history[\"loss\"]\nval_loss = history.history[\"val_loss\"]\n\nepochs = range(1, len(acc) + 1)\n\nplt.figure(figsize = (15, 6))\n\nplt.plot(epochs, acc, \"bo\", label = \"Eğitim Başarısı\")\nplt.plot(epochs, val_acc, \"b\", label = \"Test Başarısı\")\nplt.title(\"Eğitim ve Test Başarısı\")\nplt.legend()\n\nplt.figure(figsize = (15, 6))\n\nplt.plot(epochs, loss, \"bo\", label = \"Eğitim Kaybı\")\nplt.plot(epochs, val_loss, \"b\", label = \"Doğrulama Kaybı\")\nplt.legend()\n\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Evet veri çeşitlendirmesi yaparak modeli overfit etmekted kurtarmış gibi gözüküyoruz. Doğruluk oranı train ve test setimiz içinde %90'lara geldi. Burada önemli bir nokta hem veri çeşitliliği yapılması hemde model kurulurken maxpooling gibi parametre azaltma bir nevi modelin görüntü üzerinde daha geniş çalışmasını sağlama gibi etkenler olduğu açık.\n\n\n\nŞimdi evrişimli sinir ağları bir kara kutu mu değil mi buna bakalım. Pek çok insan evrişimli sinir ağlarının arkasında mantığın bir sihir gibi görüyor fakat aslında konu öyle değil tek bir filtre çıktısı üzerinden eimden geldiğince anlatmaya çalışacağım."},{"metadata":{"trusted":true},"cell_type":"code","source":"os.path.join(image_path, file_names[0])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Orjinal Resim"},{"metadata":{"trusted":true},"cell_type":"code","source":"img_path = \"./train/cat.1650.jpg\"\n\nimg = image.load_img(img_path, target_size = (150, 150))\nimg_tensor = image.img_to_array(img)\nimg_tensor = np.expand_dims(img_tensor, axis = 0)\nimg_tensor /= 255\n\nplt.imshow(img_tensor[0])\nplt.show()\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"layer_output = [layer.output for layer in model.layers[:8]]\nactivation_model = models.Model(inputs = model.input, outputs = layer_output)\nactivations = activation_model.predict(img_tensor)\n\nfirst_layer_activation = activations[0]\n\nplt.matshow(first_layer_activation[0, :, :, 4], cmap = \"viridis\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Şimdi yukarıdaki ilk resim kedinin orjinal resmi ikinci resim ise ilk katmandaki 4. kanalın çıktısı burada bakmamız gereken yer ikinci resimdeki açık yeşil olan yerler bunlar aslında birer dedektör. Konu aslında şu: açık yeşik yerlere baktığınız zaman gördüğünüz yerler kulaklar, burun çevresi, kedilerin etrafı. Aslında evrişimli sinir ağlarında herhangi bir sihir yok konu özellikle ilk katmanlar için tamamen kenar köşe bulma işi. Şunu unutmamak gerekir bilgisayar hiçbir zaman resimleri bizim gibi göremez resimleri onun için RGB kanallarındaki piksel değerlerinden ibaret yani o resim değil sayı görüyor! \n\nPeki sayı görerek nasıl kedi köpek tespiti yapabiliryor?\n\nŞimdi yukarıdaki ilk resme bakın resmin büyük çoğunluğunu kediler kaplıyor değil mi ve bu kediler aslında birbirlerine benzer yani görünüşleri, boyutları, hatta renkleri işte sihir(!) burada başlıyor. Örneğin bilgisayarın resimdeki renk değerlerini (sayıları) yukarıdan aşağıya okuduğunu varsayalım en yukarı beyaz bir renk var muhtemelen bu bir kanepe veya yastık yani bir obje haliyle renk değerleride aynı resmin biraz aşağısına indiğinde kediler ile karşılaşıyor yani başka bir obje ama bilgisayar onları görerek farketmiyor renk değerlerinin değişimi ile şöyle bir yorum yapıyor: \"Hmmm sanırım buraya kadar ki her şey aynıydı fakat şimdi buradan sonrası değişmeye başladı.\" Evet değişiyor çünkü renk değişiyor, sayılar değişiyor ve bilgisayar buna burada başka bir nesne var diyerek cevap veriyor bu yüzden kedilerin kulakları ve etrafları açık yeşil yani dedektöre takılıyor. Bunun gibi binlerce resim olunda bilgisayar bunları kolayca sınıflandırabiliyor.\n\nDedektöre takılma yerleri, büyüklükleri, kaba şekilleri vs gibi. Onun günün sonunda kedi veya köpek bulmak gibi bir derdi yok onun derdi sadece birbirine benzer objeleri aynı sınıfa atmak bu kadar."},{"metadata":{},"cell_type":"markdown","source":"Tüm katmanların görüntüsü\nKaynak:\n* [https://nbviewer.jupyter.org/github/fchollet/deep-learning-with-python-notebooks/blob/master/5.4-visualizing-what-convnets-learn.ipynb](http://)"},{"metadata":{"trusted":true},"cell_type":"code","source":"layer_names = []\nfor layer in model.layers[:8]:\n    layer_names.append(layer.name)\n\nimages_per_row = 16\n\n\nfor layer_name, layer_activation in zip(layer_names, activations):\n   \n    n_features = layer_activation.shape[-1]\n\n    \n    size = layer_activation.shape[1]\n\n    \n    n_cols = n_features // images_per_row\n    display_grid = np.zeros((size * n_cols, images_per_row * size))\n\n    \n    for col in range(n_cols):\n        for row in range(images_per_row):\n            channel_image = layer_activation[0,\n                                             :, :,\n                                             col * images_per_row + row]\n            \n            channel_image -= channel_image.mean()\n            channel_image /= channel_image.std()\n            channel_image *= 64\n            channel_image += 128\n            channel_image = np.clip(channel_image, 0, 255).astype('uint8')\n            display_grid[col * size : (col + 1) * size,\n                         row * size : (row + 1) * size] = channel_image\n\n    \n    scale = 1. / size\n    plt.figure(figsize=(scale * display_grid.shape[1],\n                        scale * display_grid.shape[0]))\n    plt.title(layer_name)\n    plt.grid(False)\n    plt.imshow(display_grid, aspect='auto', cmap='viridis')\n    \nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Umarım bu çalışma sizin için faydalı olmuştur.\n\nTekrar görüşmek üzere!"}],"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat":4,"nbformat_minor":4}