In [ ]:
#@title 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
#
# https://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.

In [ ]:
#@title MIT License
#
# Copyright (c) 2017 François Chollet
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.

Regrasyon: yakıt verimliliğini tahmin edelim

Note: Bu dökümanlar TensorFlow gönüllü kullanıcıları tarafından çevirilmiştir. Topluluk tarafından sağlananan çeviriler gönüllülerin ellerinden geldiğince güncellendiği için Resmi İngilizce dökümanlar ile bire bir aynı olmasını garantileyemeyiz. Eğer bu tercümeleri iyileştirmek için önerileriniz var ise lütfen tensorflow/docs havuzuna pull request gönderin. Gönüllü olarak çevirilere katkıda bulunmak için docs-tr@tensorflow.org listesi ile iletişime geçebilirsiniz.

Regrasyon problemlerinde, olasılık veya fiyat gibi sürekli değişken olan çıktıyı tahmin etmeyi amaçlarız. Aksine, sınıflandırma problemlerinde ise amacımız, belirli bir sınıf listesi içerisinden en uygun sınıfı seçebilmektir (örneğin bir resimde elma veya portakal olsun, resimde elma mı yoksa portakal mı olduğunu belirlemek isteriz).

Bu çalışma kitabı, 1970'lerin sonları ve 1980'lerin başlarında üretilmiş olan araçların yakıt verimliliğini (MPG) tahmin edebilecek bir model geliştirmek için klasik Auto MPG veri setini kullanmaktadır. Bunu yapabilmek için, belirtilen zaman aralığında üretilmiş olan araç bilgilerini modelimize besleyeceğiz. Modelimize besleyeceğimiz bu bilgiler değişik araç özelliklerini kapsamaktadır: motorun kaç silindirli olduğu, beygir günü, hacmi ve araç ağırlığı.

Bu örnekte tf.keras API kullanılmıştır, detaylar için bu yardımcı döküman'a göz atabilirsiniz.


In [ ]:
# pairplot icin seaborn kullanalim
!pip install seaborn

In [ ]:
import pathlib

import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns

import tensorflow.compat.v1 as tf

from tensorflow import keras
from tensorflow.keras import layers

print(tf.__version__)

Auto MPG veri seti

Bu veri seti UCI Machine Learning Repository sitesinde bulunmaktadır.

Veriyi alalım

İlk olarak veri setini indirelim.


In [ ]:
dataset_path = keras.utils.get_file("auto-mpg.data", "https://archive.ics.uci.edu/ml/machine-learning-databases/auto-mpg/auto-mpg.data")
dataset_path

pandas kütüphanesini kullanarak verileri içeri alalım


In [ ]:
column_names = ['MPG','Cylinders','Displacement','Horsepower','Weight',
                'Acceleration', 'Model Year', 'Origin'] 
raw_dataset = pd.read_csv(dataset_path, names=column_names,
                      na_values = "?", comment='\t',
                      sep=" ", skipinitialspace=True)

dataset = raw_dataset.copy()
dataset.tail()

Veriyi temizleyelim

Veri seti bilinmeyen bir kaç değer içermektedir.


In [ ]:
dataset.isna().sum()

Eğitim dökümanını kısa tutabilmek adına, bu satırları veri setinden çıkaralım.


In [ ]:
dataset = dataset.dropna()

"Origin" kolonu sayısal değil, kategorik değer içermektedir. Dolayısı ile, bu kolonu one-hot forma çevirelim:


In [ ]:
origin = dataset.pop('Origin')

In [ ]:
dataset['USA'] = (origin == 1)*1.0
dataset['Europe'] = (origin == 2)*1.0
dataset['Japan'] = (origin == 3)*1.0
dataset.tail()

Veri setini eğitim ve test olarak ikiye ayıralım

Şimdi, veri setini eğitim seti ve test setine ayıralım.

Modelimizin tamamlandıktan sonraki son değerlendirmesinde test veri setini kullanacağız.


In [ ]:
train_dataset = dataset.sample(frac=0.8,random_state=0)
test_dataset = dataset.drop(train_dataset.index)

Veriyi inceleyelim

Eğitim veri setindeki birkaç kolonun değer dağılımlarına birlikte hızlıca göz atalım.


In [ ]:
sns.pairplot(train_dataset[["MPG", "Cylinders", "Displacement", "Weight"]], diag_kind="kde")

Genel istatistiklere bakalım:


In [ ]:
train_stats = train_dataset.describe()
train_stats.pop("MPG")
train_stats = train_stats.transpose()
train_stats

Etiketlerin özelliklerden ayırılması

Hedef verisini, veya "etiketi", özelliklerden ayıralım. Modeli, bu etiket değerini tahminleyebilmek için eğitiyoruz.


In [ ]:
train_labels = train_dataset.pop('MPG')
test_labels = test_dataset.pop('MPG')

Veriyi normalize edelim

Yukarıda yer alan 'train_stats' değerlerine baktığımızda, her bir özelliğin birbirinden ne kadar farklı değer aralığına sahip olduğunu görmekteyiz.

Birbirinden farklı büyüklükteki ve aralıklardaki özellik değerlerinin normalize edilmesi her zaman işimizi kolaylaştırır. Modelin mevcut verilerle sonuca yakınsaması mümkün olsa bile, bu modelin eğitilmesini güçleştirir, ayrıca modelin seçilen girdinin birimine bağlı sonuçlar vermesine neden olur.

Not: İstatistikleri bilinçli olarak sadece eğitim veri setine göre oluşturmuş olsakta, bu bilgiler test veri setinin normalizasyonu için de kullanılacaktır. Test veri setini, modelin eğitilmiş olduğu veri setinin sahip olduğu dağılıma yansitabilmek için, aynı şekilde normalize etmemiz gerekmektedir.


In [ ]:
def norm(x):
  return (x - train_stats['mean']) / train_stats['std']
normed_train_data = norm(train_dataset)
normed_test_data = norm(test_dataset)

Bu normalize edilmiş veri, modelin eğitimi için kullanacağımız veridir.

Dikkat: Değerleri normalize etmek için kullandığımız istatiksel değerler (ortalama ve standart sapma), one-hot şifreleme kullanılarak modele beslenecek diğer tüm verilere de uygulanmalıdır. Bu normalizasyon işlemi test verisinde, ayrıca modelimizin canlı kullanımında modele beslenen verilerde de aynı şekilde uygulanmalıdır.

Model

Modeli oluşturalım

Modelimizi birlikte oluşturalım. İki 'yoğun bağlı (densely connected)' gizli katman, ayrıca tek bir sürekli değer üreten çıktı katmanı kullanacağız. Sonradan ikinci bir model oluşturacağımız için, kolaylık olması açısından model oluşturma adımlar 'build_model' fonsiyonu içerisinde yer almaktadır.


In [ ]:
def build_model():
  model = keras.Sequential([
    layers.Dense(64, activation=tf.nn.relu, input_shape=[len(train_dataset.keys())]),
    layers.Dense(64, activation=tf.nn.relu),
    layers.Dense(1)
  ])

  optimizer = tf.keras.optimizers.RMSprop(0.001)

  model.compile(loss='mean_squared_error',
                optimizer=optimizer,
                metrics=['mean_absolute_error', 'mean_squared_error'])
  return model

In [ ]:
model = build_model()

Modeli inceleyelim

Modelin basit bir açıklamasını ekrana yazdırabilmek için '.summary' methodunu kullanalım.


In [ ]:
model.summary()

Şimdi modeli kullanalım. Eğitim veri setinden 10 özelliği içeren veri grubunu alalım ve 'model.predict' metodunu bu veri grubu ile çalıştıralım.


In [ ]:
example_batch = normed_train_data[:10]
example_result = model.predict(example_batch)
example_result

Model beklenen form ve tipte sonuçlar üretiyor ve beklendiği şekliyle çalışıyor gözüküyor.

Modeli eğitelim

Modeli 1000 epoch döngüsü içerisinde egitelim ve doğrulama ve eğitim doğruluk sonuçlarını 'history' objesi içerisinde kayit edelim.


In [ ]:
# Tamamlanan her epoch dongusu icin bir nokta yazdirarak egitimin gelisimini gosterelim
class PrintDot(keras.callbacks.Callback):
  def on_epoch_end(self, epoch, logs):
    if epoch % 100 == 0: print('')
    print('.', end='')

EPOCHS = 1000

history = model.fit(
  normed_train_data, train_labels,
  epochs=EPOCHS, validation_split = 0.2, verbose=0,
  callbacks=[PrintDot()])

Model eğitim sürecini, 'history' objesi içerisine kaydetmiş olduğumuz değerleri kullanarak görselleştirelim.


In [ ]:
hist = pd.DataFrame(history.history)
hist['epoch'] = history.epoch
hist.tail()

In [ ]:
def plot_history(history):
  hist = pd.DataFrame(history.history)
  hist['epoch'] = history.epoch
  
  plt.figure()
  plt.xlabel('Epoch')
  plt.ylabel('Mean Abs Error [MPG]')
  plt.plot(hist['epoch'], hist['mean_absolute_error'],
           label='Train Error')
  plt.plot(hist['epoch'], hist['val_mean_absolute_error'],
           label = 'Val Error')
  plt.ylim([0,5])
  plt.legend()
  
  plt.figure()
  plt.xlabel('Epoch')
  plt.ylabel('Mean Square Error [$MPG^2$]')
  plt.plot(hist['epoch'], hist['mean_squared_error'],
           label='Train Error')
  plt.plot(hist['epoch'], hist['val_mean_squared_error'],
           label = 'Val Error')
  plt.ylim([0,20])
  plt.legend()
  plt.show()


plot_history(history)

100 epoch sonrasında doğrulama hata değerinin iyileşmediği aksine bir miktar kötüleştiği görülmektedir. 'model.fit' metodunu, doğrulama değerinin iyileşmemesi durumunda model eğitimini otomatik olarak durduracak şekilde güncelleyelim. EarlyStopping callback kullanarak eğitim durumunu her epoch sonunda kontrol ediyor olacağız. Belirli bir adet epoch süresince model iyileşme göstermezse, model eğitimini otomatik olarak durduracağız.

Bu callback ile ilgili daha fazla bilgiyi burada bulabilirsiniz.


In [ ]:
model = build_model()

# 'patience parameter' kac adet epoch dongusunun iyilesme icin kontrol edilecegini belirler
early_stop = keras.callbacks.EarlyStopping(monitor='val_loss', patience=10)

history = model.fit(normed_train_data, train_labels, epochs=EPOCHS,
                    validation_split = 0.2, verbose=0, callbacks=[early_stop, PrintDot()])

plot_history(history)

Grafik, doğrulama seti ile ortalama hatanın +/- 2 MPG aralığında olduğunu göstermektedir. Bu hata değerinin iyi mi, yoksa kötü mü olduğu kararını size bırakıyoruz?

Modelin daha önce görmediği test verileri ile nasıl performans gösterdiğine, yani genelleme yeteneğinin ne kadar iyi olduğuna birlikte bakalım. Bu bize modelimizin gerçek dünyada, kullanıcı verileri ile çalıştırıldığında ne kadar iyi tahminleme yapacağını gösterecektir.


In [ ]:
loss, mae, mse = model.evaluate(normed_test_data, test_labels, verbose=2)

print("Testing set Mean Abs Error: {:5.2f} MPG".format(mae))

Tahminleme yapalım

Son olarak, test veri setini kullanarak MPG değerlerini tahminleyelim:


In [ ]:
test_predictions = model.predict(normed_test_data).flatten()

plt.scatter(test_labels, test_predictions)
plt.xlabel('True Values [MPG]')
plt.ylabel('Predictions [MPG]')
plt.axis('equal')
plt.axis('square')
plt.xlim([0,plt.xlim()[1]])
plt.ylim([0,plt.ylim()[1]])
_ = plt.plot([-100, 100], [-100, 100])

Modelimizin epey iyi sonuç verdiği görülmektedir. Hata dağılımına birlikte bakalım.


In [ ]:
error = test_predictions - test_labels
plt.hist(error, bins = 25)
plt.xlabel("Prediction Error [MPG]")
_ = plt.ylabel("Count")

Hataların dağılımı gauss dağılımına çok benzer değil, veri adedimiz oldukça az olduğu için bu beklenen bir durumdur.

Sonuç ve kapanış

Bu notebook ile, regrasyon problemlerinin çözümünde kullanılan bazı teknikler açıklanmıştır:

  • Ortalama karekök hatası - Mean Squared Error (MSE), regrasyon problemlerinin çözümünde sıklıkla kullanılan kayıp fonksiyonudur (sınıflandırma problemlerinde daha farklı kayıp fonksiyonları kullanılır).
  • Benzer şekilde, regrasyon ve sınıflandırma modellerinin değerlendirme metrikleri de farklılık gösterir. Regrasyon modellerinde genel olarak kullanılan metrik, Ortalama Mutlak Hata - Mean Absolute Error (MAE)'dır.
  • Farklı özelliklere ait sayısal verilerinin değer aralıklarının farklı olması durumunda, her bir özelliğın bağımsız olarak aynı değer aralığına indirgenmesi gerekmektedir.
  • Eğitim veri seti için elimizde fazla veri yoksa, aşırı uyum (overfitting) gözlemlenmemesi için, az sayıda gizli katman içeren daha küçük sinir ağı modellerini tercih etmemiz gerekmektedir.
  • Model eğitiminin erken durdurulması, aşırı uyumun oluşmasını engelleyen kullanışlı bir tekniktir.