MNIST, Makine Öğrenmesine Yeni Başlayanlar İçin

Bu eğitim, hem makine öğrenmesinde hem de TensorFlow’da yeni olan okuyucular için hazırlanmıştır. Öğreticilere başlamadan önce TensorFlow’ı kurduğunuzdan emin olun. TensorFlow hakkında daha fazla bilgi için  TensorFlow 101.

Bir kişinin program yazmayı öğrendiğinde yaptığı ilk şey “Merhaba Dünya” yazdırmaktır. Tıpkı Hello World geleneğindeki gibi, makine öğrenmesi de MNIST’e sahiptir.

MNIST basit bir bilgisayarla görme veri kümesidir. Bu, aşağıdaki gibi el yazısıyla yazılan rakamlardan oluşur:

Ayrıca, her bir resim için hangi rakamın olduğunu bize söyleyen etiketler de içerir. Örneğin, yukarıdaki görüntülerin etiketleri 5, 0, 4 ve 1’dir.

Bu yazıda, görüntülere bakarak hangi rakam olduğunu tahmin edebilen bir model eğitmek istiyoruz. Amacımız, en gelişmiş performansı elde eden gerçekten ayrıntılı bir model yaratmak değildir. Bunun yerine TensorFlow kullanarak bir göz atmak. Bu nedenle, Softmax Regresyon adı verilen çok basit bir modelle başlayacağız.

Bu öğreticinin gerçek kodu çok kısadır ve ilginç şeyler sadece üç satırda olur. Bununla birlikte, arkasındaki fikirleri anlamak çok önemlidir: Hem TensorFlow nasıl çalışır hem de çekirdek makine öğrenmesi kavramları nelerdir bunları anlamalıyız. Bu nedenle, kod boyunca çok dikkatli çalışacağız.

MNIST Verileri

MNIST verileri Yann LeCun web sitesinde yer alıyor.  Aşağıdaki şekilde veri setine erişim sağlayabilirsiniz.


from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)

MNIST verileri üç bölüme ayrılmıştır: 55.000 tane veri eğitim verileri (mnist.train), 10.000 adet veri test verileri (mnist.test) ve 5.000 adet veri de validation(geçerlilik) verileri(mnist.validation). Makine öğrenmesinde öğrendiğimiz şeylerin genelleştiğinden emin olabilmemiz için verileri bu şekilde bölerek öğrenmediğimiz ayrı verilere sahip olmak çok önemlidir.

Daha önce de belirtildiği gibi, her MNIST verisinin iki bölümü vardır: el yazısı ile yazılan bir rakam ve ilgili bir etiket. Resimleri “x” ve etiketleri “y” olarak adlandıracağız. Hem eğitim seti, hem de test seti görüntüleri ve bunlara karşılık gelen etiketleri içerir. Bunlar, eğitim görüntüleri mnist.train.images ve eğitim etiketleri mnist.train.labels‘dir.

Her resim 28 piksele 28 pikseldir. Bunu sayıların büyük bir dizisi olarak yorumlayabiliriz:

Bu diziyi 28 x 28 = 784 sayılık bir vektör haline getirebiliriz. Görüntüler arasında tutarlı olduğu sürece diziyi nasıl düzleştirdiğimiz önemli değildir. Bu açıdan, MNIST görüntüleri, çok zengin bir yapıya sahip olan 784 boyutlu bir vektör uzayında sadece bir grup noktadır (uyarı: hesaplamalı yoğun görselleştirme).

Verilerin düzleştirilmesi, resmin 2 boyutlu yapısı hakkında bilgi kaybetmeye neden olur. En iyi bilgisayar görme yöntemleri bu yapıyı kullanır. Ancak burada kullanacağımız basit yöntem, softmax regresyonu olacaktır.

Sonuç, mnist.train.images [55000, 784] şeklindeki bir tensör (n boyutlu bir dizi) ‘dir. İlk boyut, görüntü listesindeki bir indeks ve ikinci boyut, her resmin her pikseli için indekstir. Tensördeki her girdi, belirli bir resimdeki belirli bir piksel için 0 ile 1 arasındaki bir piksel yoğunluğudur.

 

MNIST’deki her görüntünün, resimde çizilen rakamı temsil eden 0 ila 9 arasındaki bir sayıya karşılık gelen bir etiketi vardır.

Bu yazının amaçları doğrultusunda, etiketlerimizi “one-hot vectors” olarak görmek istiyoruz. One-hot vector, bütün boyutlarda 0, tek bir boyutta 1 olan bir vektördür. Bu durumda n. rakam, n. boyutta 1 olan bir vektör olarak temsil edilecektir. Örneğin, 3 [0,0,0,1,0,0,0,0,0,0] olur. Sonuç olarak, mnist.train.labels bir [55000, 10] float dizisidir.

Şimdi modelimizi hazırlamaya hazırız!

Softmax Regresyonları

MNIST’deki her görüntünün sıfırdan dokuza kadar el yazısı ile yazılmış bir rakam olduğunu biliyoruz. Dolayısıyla belirli bir görüntünün olabileceği 10 olası şey vardır. Bir görüntüye bakabilmeyi ve herhangi bir rakam olabilme olasılığını vermeyi istiyoruz. Örneğin, model dokuz olan bir resme bakabilir ve dokuz olmasında %80 emin olabilir, ancak resmin sekiz olmasına da %5 şans verir ve diğer rakamların olabilmesine de biraz olasılık verir.

Bu softmax regresyonunun doğal, basit bir model olduğu klasik bir durumdur. Birkaç farklı şeyden biri olduğunu bildiğiniz bir nesneye olasılıklar atamak isterseniz, softmax yapılması gerekir, çünkü softmax bize 0 ile 1 arasında bir değer listesi verir. Daha sofistike modeller eğittiğimizde, son adım softmax katmanı olacaktır.

Softmax regresyonunun iki basamağı vardır: önce girdilerimizi bildiğimiz belirli sınıflara yerleştirdik ve daha sonra bu bildiğimiz değerleri olasılıklara dönüştürdük.

Belirli bir görüntünün belirli bir sınıfta olduğunu kanıtlamak için, piksel yoğunluklarının ağırlıklı toplamı kullanılır. Yüksek bir yoğunluğa sahip olan piksel, o sınıftaki görüntüye karşı kanıt ise, ağırlık negatiftir ve lehine bir delil ise pozitiftir.

Aşağıdaki diyagram, bir modelin bu sınıfların her biri için öğrendiği ağırlıkları gösterir. Kırmızı, negatif ağırlıkları temsil ederken, mavi pozitif ağırlıkları temsil eder.

 

Ayrıca ekstra bir kanıt daha ekledik, önyargı. Temel olarak, bazı şeyler girdiden bağımsızdır. Sonuç, verilen bir i sınıfı için x girdilerinin kanıtı:Burada Wi ağırlık ve bi sınıf i için önyargıdır ve j giriş görüntüsüz x’teki pikselleri toplamak için kullanılan bir indekstir. Daha sonra, “softmax” fonksiyonunu kullanarak kanıtları tahmin edilen olasılıklara dönüştürüyoruz:

Burada softmax, doğrusal fonksiyonumuzun çıktısını istediğimiz formda şekillendiren bir “aktivasyon” veya “bağlantı” fonksiyonu olarak hizmet ediyor. Bu durumda, 10 olgu üzerinde olasılık dağılımı oluşur.  Şu şekilde tanımlanmıştır:

Bu denklemi genişletirseniz, şunları elde edersiniz:

Genelde, softmax’i ilk yol olarak düşünmek daha yararlıdır: girişlerini üslendirmek ve daha sonra normalleştirmek. Üstellik, bir kanıt biriminin daha, herhangi bir hipoteze verilen ağırlık derecesini artırması anlamına gelir. Ve bunun tersine, daha az bir kanıt birimi olması, bir hipotezin daha önceki ağırlığının bir kısmını elde ettiği anlamına gelir. Hiçbir hipotez sıfır veya negatif ağırlığa sahip değildir. Softmax daha sonra bu ağırlıkları normalleştirir geçerli bir olasılık dağılımı oluşturur.

Softmax Regresyonu aşağıdaki gibidir, ancak daha çok xs ile çizgeyi genişletebilirsiniz. Her çıktı için, xs’in ağırlıklı bir toplamı hesaplanır, bir önyargı eklenir ve sonra softmax uygulanır.

 

Bunu denklemler olarak yazarsak, şunu elde ederiz:

[y1, y2, y3] = softmax(W11*x1 + W12*x2 + W13*x3 + b1, W21*x1 + W22*x2 + W23*x3 + b2, W31*x1 + W32*x2 + W33*x3 + b3)

Bu işlemi “vektörize” ederek matris çarpması ve vektör ilavesi haline getirebiliriz. Bu, hesaplama verimliliği için yararlıdır.

[y1, y2, y3] = softmax([[W11, W12, W13], [W21, W22, W23], [W31, W32, W33]]*[x1, x2, x3] + [b1, b2, b3])

Kısaca, şunu yazabiliriz:

Şimdi bunu TensorFlow’un kullanabileceği bir şeye dönüştürelim.

Regresyonun Implementasyonu

TensorFlow, Python’dan bağımsız olarak tek bir pahalı operasyon yürütmek yerine Python’ın tamamında çalışan etkileşimli işlemlerin bir çizgesini anlatmamıza izin verir.

TensorFlow’u kullanmak için önce onu içe aktarmamız(import etmemiz) gerekir.


import tensorflow as tf

Bu etkileşimli işlemleri, sembolik değişkenleri manipüle ederek tanımlıyoruz. Bir tane oluşturalım:

x = tf.placeholder(tf.float32, [None, 784])

X belirli bir değer değildir bir placeholder’du. TensorFlow’dan bir hesaplama yapmamızı istediğimizde girdiğimiz bir değer. Her biri 784 boyutlu bir vektöre yansıtılan, herhangi bir sayıda MNIST görüntüsü girebilmek istiyoruz. Bunu, bir şekil(shape) ile 2 boyutlu[None, 784] kayan nokta sayıları(floating poin) tensörü olarak gösteriyoruz.  (Burada None, bir boyutun herhangi bir uzunluğa sahip olabileceği anlamına gelir.)

Modelimiz için ağırlık ve önyargılara da ihtiyacımız var. Bunları ek girdiler gibi düşünebiliriz, ancak TensorFlow bunu işlemek için daha iyi bir yönteme sahiptir: Variable. tf.Variable, TensorFlow’un etkileşimli işlemler çizgesindeki değişebilir bir tensördür. Hesaplama ile kullanılabilir ve hatta değiştirilebilir. Makine öğrenmesi uygulamaları için genelde Model parametreleri Variable olarak bulunur.


W = tf.Variable(tf.zeros([784, 10]))
b = tf.Variable(tf.zeros([10]))

Bu Variable’ları, tf.Variable ie Variable’a başlangıç ​​değerini vererek oluştururuz: Bu durumda hem W’yu hem de b’yi sıfırlarla dolu tensörler olarak başlatırız. W ve b’yi öğreneceğimize göre başlangıçta ne olduğu çok önemli değildir.

W’nin [784, 10] şekline sahip olduğuna dikkat edin, çünkü 784 boyutlu görüntü vektörlerini, fark sınıfları için 10 boyutlu vektörü  üretmek için çarpmak istiyoruz. B’nin boyutu [10] dolayısıyla çıktıya ekleyebiliriz.

Artık modelimizi uygulayabiliriz. Bunu tanımlamak yalnızca bir satır alır


y = tf.nn.softmax(tf.matmul(x, W) + b)

İlk olarak, x’i W ile çarpıp tf.matmul(x, W) ifadesini veriyoruz. Bunları, Wx’in bulunduğu denklemde, x ile birden çok girdi içeren bir 2 boyutlu tensör olarak ele almak için küçük bir numara olarak çarpılarak döndürdük. Sonra b’yi ekleyip nihayetinde tf.nn.softmax’ı uygulayacağız.

Bu kadar. Birkaç kısa kurulumdan sonra, modelimizi tanımlamak için yalnızca bir satır yazdık. TensorFlow, softmax regresyonunu özellikle kolaylaştırmak için tasarlandığından değil, makine öğrenmesi modellerinden fizik simülasyonlarına kadar birçok sayısal hesaplamayı tanımlamak için yalnızca çok esnek bir yoldur ve bir kere tanımlandıktan sonra, modelimiz farklı aygıtlarda çalıştırılabilir: bilgisayarınızın CPU, GPU’ları ve hatta telefonlarda da.

Eğitim

Modelimizi eğitmek için modelin iyi olmasının ne demek olduğunu tanımlamamız gerekir. Aslında, makine öğrenmesinde tipik olarak, bir modelin kötü olmasının ne demek olduğunu tanımlıyoruz. Buna maliyet(cost) veya kayıp(loss) denir ve modelimizin istenen sonuçtan ne kadar uzakta olduğunu gösterir. Bu hatayı en aza indirmeye çalışıyoruz ve hata aralığı ne kadar küçük olursa, modelimiz o kadar iyi olur.

Bir modelin kaybını belirlemek için çok yaygın, çok güzel bir fonksiyona “çapraz entropi”(cross-entropy) adı verilir. Çapraz entropi, bilgi teorisinde bilgi sıkıştırma kodlarını düşünmekten kaynaklanır ancak kumardan makineyi öğrenmesine kadar birçok alanda önemli bir fikir haline gelmiştir. Şu şekilde tanımlanır:

y bizim tahmin edilen olasılık dağılımımızdır ve y’ gerçek dağılımdır. Kabaca, çapraz entropi gerçeği açıklamak için tahminlerimizin ne kadar yetersiz olduğunu ölçmektedir.

Çapraz entropiyi uygulamak için öncelikle doğru cevapları girmek için yeni bir placeholder eklemeliyiz:


y_ = tf.placeholder(tf.float32, [None, 10])

Sonra, çapraz entropi fonksiyonunu uygulayabiliriz,


cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y), reduction_indices=[1]))

Önce, tf.log, y’nin her bir elemanının logaritmasını hesaplar. Sonra, y_’nin her elemanını tf.log(y)’nin elemanı ile çarparız. Sonra, reduction_indices = [1] parametresi nedeniyle tf.reduce_sum elemanlarını y’nin ikinci boyutuna ekleriz. Son olarak, tf.reduce_mean bütün örneklerdeki ortalamayı hesaplar.

Kaynak kodunda, bu formülasyonu kullanmayacağımıza dikkat edin, çünkü sayısal olarak kararlı değildir. Bunun yerine, normal olmayan logitler üzerinde tf.nn.softmax_cross_entropy_with_logits uygularız, çünkü sayısal olarak daha istikrarlı olan bu fonksiyon dahili olarak softmax aktivasyonunu hesapladığından tf.matmul (x, W) + b üzerinde softmax_cross_entropy_with_logits diyoruz. Kodunuzda bunun yerine tf.nn.softmax_cross_entropy_with_logits kullanmayı düşünebilirsiniz.

Modelimizin ne yapmasını istediğimizi bildiğimiz için TensorFlow’un bunu yapması çok kolay. TensorFlow, hesaplamalarınızın tüm çizgesini bildiğinden, değişkenlerin küçültmenizi istediğiniz kayıpları nasıl etkilediğini etkin bir şekilde belirlemek için otomatik olarak geri yayılım algoritmasını(backpropagation algorithm) kullanabilir. Sonra değişkenleri değiştirmek ve kaybı azaltmak için optimizasyon algoritması seçiminizi uygulayabilirsiniz.


train_step = tf.train.GradientDescentOptimizer(0.05).minimize(cross_entropy)

Bu durumda, TensorFlow’dan 0.5’lik bir öğrenme oranı ile gradyan iniş algoritması kullanarak çapraz-entropiyi en aza indirmesini istiyoruz. Gradient inişi, TensorFlow’un her değişkeni maliyeti düşürecek yönde basitçe kaydırdığı basit bir işlemdir. Ancak TensorFlow, diğer birçok optimizasyon algoritmasını da destekler.

TensorFlow’un gerçekte burada yaptığı şey, perde arkasında, geriye yayılma ve gradyan inişini gerçekleştiren yeni operasyonları çizgenize eklemektir.

Şimdi modeli InteractiveSession’da başlatabiliriz:


sess = tf.InteractiveSession()

İlk önce oluşturduğumuz değişkenleri başlatmak için bir operasyon yaratmalıyız:


tf.global_variables_initializer().run()

Eğitelim, 1000 adımda eğitim adımını yürüteceğiz.


for _ in range(1000):
   batch_xs, batch_ys = mnist.train.next_batch(100)
   sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})

Döngünün her adımında, eğitim setimizden yüz rastgele verilik bir “toplu işi”(batch) elde ediyoruz. placeholder’ların yerine geçmek için toplu iş verilerinde train_step’i çalıştırıyoruz.

Rastgele verilerin küçük gruplarını kullanmak stokastik eğitim olarak adlandırılır. Bu, stokastik dereceli azalmasıdır. İdeal olarak, eğitimin her adımında tüm verilerimizi kullanmak isteriz, çünkü bu, bize ne yapmamız gerektiğini daha iyi anlamamızı sağlar, ancak bu işlem çok pahalıdır. Bunun yerine, her seferinde farklı bir alt küme kullanırız. Bunu yapmak ucuzdur ve aynı yararın çoğunu sağlayabiliriz.

Modelimizi Değerlendirme

Modelimiz Ne Kadar İyi?

Öncelikle doğru etiketi tahmin ettiğimiz yeri bulalım. tf.argmax, bir eksen boyunca bir tensörde en yüksek girdi indeksini veren son derece yararlı bir fonksiyondur. Örneğin, tf.argmax(y_, 1) doğru etiket iken, tf.argmax (y, 1) bizim modelimizin her girdi için en olası olduğunu düşündüğü etikettir. Tahminin gerçeğe uygun olup olmadığını kontrol etmek için tf.equal kullanabiliriz.


correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))

Bize booleans listesini verir. Hangi kesrin doğru olduğunu belirlemek için, kayan noktalı sayılara cast edip ortalamayı alıyoruz. Örneğin, [True, False, True, True] [1.0,1,1] olur ve 0.75 olur.


accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

Son olarak, test verilerimizdeki doğruluğumuzu istiyoruz.


print(sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels}))

Onun yaklaşık %92 olması gerekir.

İyi mi? Şey, gerçekten değil Aslında, çok kötü. Bunun nedeni, çok basit bir model kullandığımız. Bazı küçük değişikliklerle %97’ye varabiliriz. En iyi modeller %99.7’den fazla doğruluk elde edebilirler.

 

Programın Tamamı Aşağıdadır.

 

# Copyright 2015 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================

"""A very simple MNIST classifier.
See extensive documentation at
https://www.tensorflow.org/get_started/mnist/beginners
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import argparse
import sys

from tensorflow.examples.tutorials.mnist import input_data

import tensorflow as tf

FLAGS = None

def main(_):
  # Import data
  mnist = input_data.read_data_sets(FLAGS.data_dir, one_hot=True)

  # Create the model
  x = tf.placeholder(tf.float32, [None, 784])
  W = tf.Variable(tf.zeros([784, 10]))
  b = tf.Variable(tf.zeros([10]))
  y = tf.matmul(x, W) + b

  # Define loss and optimizer
  y_ = tf.placeholder(tf.float32, [None, 10])

  # The raw formulation of cross-entropy,
  #
  #   tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(tf.nn.softmax(y)),
  #                                 reduction_indices=[1]))
  #
  # can be numerically unstable.
  #
  # So here we use tf.nn.softmax_cross_entropy_with_logits on the raw
  # outputs of 'y', and then average across the batch.
  cross_entropy = tf.reduce_mean(
      tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=y))
  train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)

  sess = tf.InteractiveSession()
  tf.global_variables_initializer().run()
  # Train
  for _ in range(1000):
    batch_xs, batch_ys = mnist.train.next_batch(100)
    sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})

  # Test trained model
  correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
  accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
  print(sess.run(accuracy, feed_dict={x: mnist.test.images,
                                      y_: mnist.test.labels}))

if __name__ == '__main__':
  parser = argparse.ArgumentParser()
  parser.add_argument('--data_dir', type=str, default='/tmp/tensorflow/mnist/input_data',
                      help='Directory for storing input data')
  FLAGS, unparsed = parser.parse_known_args()
  tf.app.run(main=main, argv=[sys.argv[0]] + unparsed)

 

Portions of this page are modifications based on work created and shared by Google and used according to terms described in the Creative Commons 3.0 Attribution License.