Günümüzde verimli stok yönetimi, özellikle büyük ölçekli depolama ve tedarik zincirlerinde kritik bir öneme sahiptir.
Bu çalışmada; depodaki stokların gelecekteki durumlarını tahmin edebilmek için Long Short-Term Memory (LSTM) ağı kullanılmıştır. LSTM, özellikle zaman serisi verilerindeki karmaşık desenleri ve uzun süreli bağımlılıkları öğrenme kabiliyeti nedeniyle tercih edilmiştir.
Proje; “Stok Tahmin” adlı veritabanından çekilen zaman serisi verileri üzerinde gerçekleştirilmiştir.
Bu çalışmanın temel amacı; LSTM modelini kullanarak depo stok seviyelerinin zaman içinde nasıl değişeceğini tahmin etmektir. Bu tahminler, stokların ne zaman tükeneceği veya yeniden sipariş verilmesi gerektiği konusunda işletmelere önemli bilgiler sağlamaktadır.
Model; sonuçlar dahilinde geçmiş stok verilerini analiz ederek, gelecekteki stok seviyeleri hakkında doğru tahminler yapma potansiyeline sahip olduğu sonucunu vermektedir.
Veri ön işleme aşamasında; veriler MinMaxScaler ile ölçeklendirilmiş ve LSTM modelinin daha etkili öğrenmesi için hazırlanmıştır. Model, veri setinin yüzde yetmişini (%70) kullanarak eğitilmiş ve kalan yüzde otuzluk (%30) bölümü ile test edilmiştir. Hiperparametre optimizasyonu; modelin performansını maksimize etmek amacıyla RandomSearch yöntemi ile yapılmıştır.
Sonuç olarak; model, stokların tükenme zamanlarını yüksek doğrulukla tahmin edebilmiş ve depo yönetimi uygulamalarında kullanılmak üzere güçlü bir çözüm olmuştur.
Bu teknolojinin uygulanması; işletmelerin stok maliyetlerini azaltmalarına ve operasyonel verimliliklerini arttırmalarına olanak tanımaktadır. İlerleyen çalışmalarda, modelin çeşitlendirilmiş veri setleri üzerinde test edilmesi ve farklı yapay sinir ağları mimarileri ile karşılaştırılması önerilmektedir.
Makalede Neler Var ?
Giriş
Modern tedarik zinciri yönetimi; veriye dayalı karar verme süreçlerini ve operasyonel stratejileri optimize ederek işletmelerin rekabet avantajını artırma ve sürdürülebilirliklerini güçlendirme açısından merkezi bir role sahiptir.
Bu bağlamda, stok seviyelerinin doğru bir şekilde tahmin edilmesi, hem maliyet kontrolü hem de müşteri memnuniyeti için büyük önem taşır.
Gelişmiş analitik tekniklerin ve yapay zeka uygulamalarının entegrasyonu, bu doğrultuda işletmelerin karşılaştığı en büyük zorluklardan birine çözüm sunmaktadır.
Bu çalışmada ele alınan Long Short-Term Memory (LSTM) ağları; derin öğrenme tabanlı bir yaklaşım kullanarak zaman serisi verilerindeki karmaşık desenleri tanıma ve uzun vadeli bağlantıları modelleme kapasitesiyle öne çıkmaktadır.
LSTM, özellikle stok yönetimi gibi sürekli veri akışının ve zamanla değişen dinamiklerin göz önünde bulundurulması gereken uygulama alanlarında değerli bir araçtır. Bu ağların kullanılması, geçmiş veri setlerinden elde edilen bilgilerle gelecekteki stok seviyeleri hakkında doğru tahminler yapılabilmesine olanak tanır.
Stok yönetimi üzerine yapılan bu çalışma; LSTM’nin, zaman serisi verilerinin içerdiği bilgileri etkili bir şekilde işleyebilme ve gelecekteki eğilimleri öngörebilme yeteneğinden yararlanmaktadır. İşletmeler için stokların zamanında yenilenmesi, fazla stok maliyetlerinin önlenmesi ve tedarik zinciri süreçlerinin kesintisiz bir şekilde yürütülmesi açısından kritik öneme sahiptir.
Bu çalışmanın sonuçları, LSTM modelinin stok seviyelerini yönetme ve tedarik zinciri kararlarını destekleme konusunda nasıl stratejik bir avantaj sağlayabileceğine dair değerli içgörüler sunmaktadır.
Materyal ve Yöntemler
Veri Seti
Projede kullanılan veri seti; özel olarak kurulan ‘StokTahmin’ SQL veritabanından alınmıştır. Bu veritabanı, depo stok hareketlerini; zaman serisi olarak kaydeder ve her bir kayıt stok kodu, miktar ve ilgili stok bulunma tarihini içerir. Veri seti; zaman serisi analizi için ideal bir temel sunar; çünkü, her bir stok kodunun zaman içindeki miktar değişimleri özet olarak gösterilmektedir.
Veri çekme işlemi için; pyodbc kütüphanesi kullanılarak ilgili işlemler gerçekleştirilmiş ve SQL sorguları ile işlemler optimize edilmiştir.
Projede kullanılan veritabanı örnek tablo formatı;
SELECT [Tarih] ,[StokKodu] ,[Miktar] ,[DepoNo] ,[MaliyetUSD]
FROM [StokTahmin].[dbo].[depo_stok]
şeklindedir.
İlgili tabloya yönelik, ön işlem olarak;
- İadeler, hasarlı ürünler, teknik parca olarak kullanimda olan ürünler, kargo faliyetlerinde yer alan ürünler Miktar değerinden çıkartıldı,
Yani; net satılabilir stok Miktar değeri baz alındı. - Miktar=NULL olan stokların Miktar değerleri 0 – Sıfır olarak dolduruldu,
Sistemin hesaplama hatası almaması için yapıldı. - Her stok için her tarih değerinde bir kayıt olduğu kontrol edildi,
Geriye dönük tarih bazlı stok kontrolü adına hata almaması için yapıldı. - 2024-01-01 / 2024-05-01 tarih aralığındaki gün sayısı değeri kontrol edildi,
Sistemsel hata nedeni ile eksik gün sayısı olmaması için yapıldı.
Ek bilgiler;
SELECT
COUNT(1) AS KayitSayisi,
COUNT(DISTINCT([StokKodu])) FarkliStok,
COUNT(DISTINCT([DepoNo])) FarkliDepo
FROM [StokTahmin].[dbo].[depo_stok]
KayitSayisi FarkliStok FarkliDepo
6716 38 5
Toplamda 5 farklı depoda, 38 farklı stok; 6.716 kayıt üzerinden ele alındı.
SELECT
MIN([Tarih]) IlkKayitTarih,
MAX([Tarih]) SonKayitTarih,
DATEDIFF(DAY,MIN([Tarih]),
MAX([Tarih])) ToplamGun
FROM [StokTahmin].[dbo].[depo_stok]
IlkKayitTarih SonKayitTarih ToplamGun
2024-01-01 2024-05-01 121
İlk veri kayıt tarihi 2024-01-01, son veri kayıt tarihi ise 2024-05-01 olmak üzere 121 günlük zaman damgalı veri dilimi ele alındı.
Veri Ön İşleme
Veri ön işleme aşaması; verilerin model tarafından daha etkin şekilde işlenmesini sağlamak için kritik öneme sahiptir. Bu projede; LSTM modelinin performansını artırmak amacıyla veriler, Scikit-Learn kütüphanesinin MinMaxScaler fonksiyonu kullanılarak ölçeklendirilmiştir. Bu ölçeklendirme işlemi, verilerin 0 ile 1 arasında normalleştirilmesini sağlar; böylece, modelin eğitim süresince karşılaşacağı sayısal değerler arasındaki varyans minimize edilir. Normalizasyon; modelin daha hızlı ve daha doğru şekilde konverge[1] olmasına yardımcı olur.
Model Geliştirme
LSTM modeli; Keras kütüphanesi kullanılarak Sequential API ile tasarlanmıştır. Bu model, zamansal veri özelliklerini yakalayabilme yeteneği ile bilinir; dolayısıyla, stok miktarlarındaki zamanla değişen trendleri ve desenleri/örüntüleri tanımlayabilir.
Model, hiperparametre optimizasyonu için RandomSearch teknikleri kullanılarak daha da geliştirilmiştir.
Bu optimizasyon süreci, çeşitli hiperparametre kombinasyonlarını deneyerek en iyi model yapılandırmasını belirler. Hiperparametreler arasında LSTM ünitelerinin sayısı, batch boyutu, epoch sayısı ve öğrenme oranı gibi değerlerde yer almaktadır.
Eğitim ve Validasyon
Model; veri setinin %70’lik bir bölümü kullanılarak eğitilmiş, geri kalan %30’luk kısım ise test ve validasyon için ayrılmıştır. Bu bölünme, modelin genelleştirme yeteneğini değerlendirmek için önemlidir.
Eğitim süreci sırasında model, verilen veri üzerindeki kaybı minimize etmeye çalışırken; validasyon süreci, modelin görmediği veriler üzerindeki performansını test eder.
Modelin başarısı; doğrulama kaybı ve Mean Squared Error [2](MSE) metrikleri kullanılarak ölçülmüştür. Bu metrikler, modelin tahminlerinin gerçek değerlere ne kadar yakın olduğunu gösterir ve yüksek doğruluk oranları modelin başarılı olduğunu işaret eder.
Araç, Dil ve Çözümler
İlgili projeye yönelik kullanılacak; dil, teknoloji, araç ve çözümler açıklamalı bir şekilde sırasıyla alt kısımda ifade edilmeye çalışılmıştır.
Python: Yüksek seviyeli, genel amaçlı, yorumlanan bir programlama dilidir. Okunması ve yazılması kolaydır. Bu yüzden başlangıç seviyesindeki programcılar için idealdir. Ayrıca, web geliştirme, veri analizi, yapay zeka ve daha birçok alanda kullanılabilen zengin kütüphane ve çerçevelere sahiptir. Python’un syntax’ı, insan diline oldukça benzer olduğundan; kodları anlaması ve hatasız yazması kolaydır.
Projede; temel geliştirme dili olarak kullanılmaktadır.
SQL: SQL (Structured Query Language); veritabanlarını yönetmek ve veri almak için kullanılan standart bir programlama dilidir. İlişkisel veritabanı sistemlerinde veri ekleme, güncelleme, silme ve sorgulama işlemleri için kullanılır. SQL; veritabanı yapılarını tanımlamak ve veriler üzerinde karmaşık sorgular yapmak için geniş bir işlevsellik sunar. Çok geniş bir kullanım alanına sahiptir ve hemen hemen tüm modern veritabanı sistemleri SQL desteklemektedir.
Projede; veri ön hazırlığındaki dil olarak kullanılmaktadır.
MsSQL: Microsoft SQL Server (MS SQL); Microsoft tarafından geliştirilen bir ilişkisel veritabanı yönetim sistemidir (RDBMS). İşletmeler için veri depolama, işleme ve yönetim işlevleri sunar ve SQL (Structured Query Language) kullanılarak erişilir. MS SQL; veri analizi, iş uygulamaları, iş zeka çözümleri ve çeşitli veri tabanı yönetim ihtiyaçları için yaygın olarak kullanılır. Güvenlik, işlem yönetimi, veri bütünlüğü ve performans açısından yüksek standartlara sahiptir, bu yüzden genellikle orta ve büyük ölçekli işletmelerde tercih edilir.
Projedeki; veri ön hazırlığında yer alan verilerin temel yapı alanı olarak kullanılmaktadır.
SQL Server Management Sutdio: SQL Server Management Studio (SSMS); Microsoft SQL Server’ı yönetmek ve veritabanıyla etkileşimde bulunmak için kullanılan bir entegre ortamdır. Kullanıcıların SQL Server’a bağlanmasını, veritabanlarını yapılandırmasını, veritabanı yönetim görevlerini yürütmesini, veri sorgulamasını ve betikler yazmasını sağlar. SSMS, görsel araçlar ve zengin betik düzenleyiciler sağlayarak veritabanı yöneticileri ve geliştiriciler için güçlü bir araçtır. Bu, veritabanı işlemlerini basitleştiren ve verimliliği artıran kapsamlı bir araç seti sunar.
Projedeki; veri ön hazırlığında yer alan verilerin planlandığı araç olarak kullanılmaktadır.
VsCode: Visual Studio Code (VSCode); Microsoft tarafından geliştirilen ücretsiz, açık kaynaklı bir kod editörüdür. Çeşitli programlama dillerini destekler ve hafif bir yapıya sahiptir, ancak genişletilebilir özellikleri sayesinde birçok geliştirme ihtiyacını karşılayabilir. VSCode; hata ayıklama, syntax vurgulama, akıllı kod tamamlama, snippets, kod refactoring gibi özellikleri içerir ve kullanıcıların daha verimli bir şekilde kod yazmasını sağlar. Ayrıca, eklentiler aracılığıyla işlevselliği artırılabilir, bu da onu çeşitli programlama dilleri ve çerçeveler için uygun hale getirir.
Projede; temel geliştirme işlemlerinin gerçekleştirildiği araç olarak kullanılmaktadır.
Microsoft Excel: Microsoft Excel; Microsoft tarafından geliştirilen ve yaygın olarak kullanılan bir elektronik tablolama programıdır. Kullanıcıların veri girişi yapmasına, verileri düzenlemesine, hesaplamalar yapmasına, grafikler ve pivot tablolar oluşturmasına olanak tanır. Excel; finansal analiz, veri analizi ve muhasebe gibi işlevler için esnek araçlar sunar ve verileri kolayca sıralayıp, filtreleyebilir. Ayrıca, karmaşık formüller ve makrolar kullanarak otomasyon ve verimliliği artırmak için de kullanılır.
Projede; çıktıların kontrol amaçlı derlendiği ve kontrol edildiği araç olarak kullanılmaktadır.
[1] İlgili açıklamadaki “konverge” kelimesi; genellikle “yakınsama” veya “konverjans” olarak çevrilen bir terimdir. Makine öğrenimi ve optimizasyon bağlamında; bir algoritmanın veya modelin belirli bir hedefe doğru ilerlemesi ve istenen sonuca yaklaşması anlamına gelmektedir.
[2] Mean Squared Error (MSE); bir modelin tahminlerinin gerçek değerlerden ne kadar farklı olduğunu ölçen bir metrik olarak ifade edilmektedir.
Kodlar
Projeye yönelik ilgili kodlar ve açıklamaları alt kısımda yer almaktadır.
1-Kütüphanelerin Projeye Dahil Edilmesi
import pandas as pd
import numpy as np
from keras.models import Sequential, load_model
from keras.layers import LSTM, Dense
from sklearn.preprocessing import MinMaxScaler
import pyodbc
from sklearn.model_selection import train_test_split
from kerastuner.tuners import RandomSearch
from keras.callbacks import EarlyStopping
import matplotlib.pyplot as plt
import seaborn as sns
import os
from sklearn.metrics import mean_squared_error
İlgili kodda, projeye yönelik;
- pandas (pd): Veri analizi ve manipülasyonu için kullanıldı.
- numpy (np): Sayısal hesaplamalar için kullanıldı.
- keras.models (Sequential, load_model): Derin öğrenme modelleri oluşturmak için kullanıldı.
Sequential modeli; katmanları sıralı bir şekilde yerleştirmek için kullanıldı.
load_model; daha önce eğitilmiş ve kaydedilmiş modelleri yüklemek için
kullanıldı. - keras.layers (LSTM, Dense): Uzun ve kısa süreli hafıza birimleri içeren katmanlar ve zaman serisi verilerindeki uzun vadeli bağımlılıkları öğrenmek için kullanıldı. Dense ise; her biri bir önceki katmanın tüm nöronlarına bağlı olan nöronlardan oluşan tam bağlı bir katman yapısı için kullanıldı.
- sklearn.preprocessing (MinMaxScaler): Özellik ölçeklendirme için kullanıldı. Verileri belirli bir aralığa (genellikle 0 ile 1 arasında) ölçeklendirerek algoritmaların daha hızlı ve daha etkili çalışmasını sağlamaktadır.
- pyodbc: ODBC veritabanlarına bağlanmak için kullanıldı.
- sklearn.model_selection (train_test_split):Veri setlerini rastgele eğitim ve test alt kümelerine ayırmak için kullanıldı.
- kerastuner.tuners (RandomSearch): Belirli bir parametre alanı içinde rastgele arama yaparak, hiperparametre optimizasyonu sağlaması için kullanıldı.
- keras.callbacks (EarlyStopping): Belirli bir süre boyunca gözlemlenen metrikte bir iyileşme olmadığında, eğitimi otomatik olarak durdurmak için kullanıldı.
- matplotlib.pyplot (plt): Veri görselleştirme için kullanıldı.
- seaborn (sns): Veri görselleştirme için kullanıldı.
- os: Dosya yolları, dizin işlemleri (oluşturma, silme, değiştirme) vb. işlemler için kullanıldı.
- sklearn.metrics (mean_squared_error): Hata oranını ölçmek için kullanıldı.
kütüphaneleri ilgili amaçları doğrultusunda projeye eklenmiştir.
2-Veri Çekme İşlemleri
def fetch_data():
connection_string = "Driver={SQL Server Native Client 11.0};Server=MIRACLE\\MIRACOZTURK;Database=StokTahmin;uid=X;pwd=Y"
try:
connection = pyodbc.connect(connection_string)
query = ' SELECT Tarih, StokKodu, SUM(Miktar) AS Miktar FROM StokTahmin.dbo.depo_stok GROUP BY Tarih, StokKodu ORDER BY Tarih DESC'
df = pd.read_sql_query(query, connection)
except pyodbc.Error as e:
print("Veritabani hatasi:", e)
except Exception as e:
print("Sorgu calistirilirken bir hata olustu:", e)
finally:
if 'connection' in locals() and connection:
connection.close()
return df
İlgili koda yönelik;
- connection_string: Genel parametreleri derleyerek, veritabanına bağlanmak için kullanıldı.
Bu parametreler arasında; kullanılan veritabanı sürücüsü (Driver), sunucu adı (Server), veritabanı adı (Database), kullanıcı adı (uid) ve şifre (pwd) bulunmaktadır. - query: Veritabanı üzerinden; sorgulama ile ilgili verileri almak için kullanıldı.
- except: Veritabanı bağlantı kontrolü kullanıldı.
pyodbc.Error: ODBC sürücüsüyle ilgili; genellikle bağlantı veya sorgu çalıştırma hataları için tetiklemesi adına kullanıldı.
Exception: Yukarıdaki özgün hatalar dışında kalan diğer tüm hataları yakalamak için kullanıldı.
finally: Bağlantının başarılı bir şekilde kurulup kurulmadığına bakılmaksızın; eğer “connection” nesnesi mevcut ise, bağlantıyı güvenli bir şekilde kapatması için kullanıldı.
return df: Veritabanı üzerine gönderilen sorgu sonucu için bir DataFrame formatı almak için kullanıldı.
3-Veri Kontrolü
df.head(5)
df.info()
İlgili koda yönelik;
- head(): query ile veritabanı üzerinden çekilmiş sorgu sonucunu önizlemek için kullanıldı.
- info(): Verisetine yönelik özet nicel bilgileri kontrol etmek için kullanıldı.
head(5) için örnek çıktı;
Tarih StokKodu Miktar
0 2024-05-01 XOFUGM0049 8
1 2024-05-01 XOFUGM0055 0
2 2024-05-01 XOFUGM0075 0
3 2024-05-01 XOFUGM0090 51
4 2024-05-01 XOFUGM0095 17
df.info() için örnek çıktı;
<class ‘pandas.core.frame.DataFrame’>
RangeIndex: 6716 entries, 0 to 6715
Data columns (total 3 columns):
# Column Non-Null Count Dtype
— —— ————– —–
0 Tarih 6716 non-null object
1 StokKodu 6716 non-null object
2 Miktar 6716 non-null int64
dtypes: int64(1), object(2)
memory usage: 157.5+ KB
4-Veri Önişleme Çalışması
df = fetch_data()
scaler = MinMaxScaler()
df['Miktar_scaled'] = scaler.fit_transform(df[['Miktar']])
İlgili koda yönelik;
- fetch_data(): Fonksiyonu önceden tanımlı SQL sorgusu ile veritabanından ilgili verileri çekmek için kullanıldı.
- MinMaxScaler(): Veri ölçeklendirme işlemi için kullanıldı.
Verileri; belirli bir aralığa (varsayılan olarak 0 ile 1 arasında) ölçeklendirmektedir.
Ölçeklendirme işlemi; farklı büyüklüklerdeki özelliklerin (features) model tarafından eşit olarak değerlendirilmesini sağlar, bu da algoritmanın performansını artırır. - scaler.fit_transform(): İlgili parametrenin sütununu ölçeklendirmek için kullanıldı.
5-Özelliklerin ve Etiketlerin Hazırlanması
look_back = 30
features = []
labels = []
df['Tarih'] = pd.to_datetime(df['Tarih'])
df.sort_values(['StokKodu', 'Tarih'], inplace=True)
for i in range(look_back, len(df)-1):
features.append(df['Miktar_scaled'].values[i-look_back:i])
labels.append(df['Miktar_scaled'].values[i])
İlgili koda yönelik;
- pd.to_datetime(df[‘Tarih’]): Tarih sütunundaki verileri tarih-saat formatına dönüştürmek için kullanıldı.
- df.sort_values([‘StokKodu’, ‘Tarih’], inplace=True): DataFrame’i; “StokKodu” ve “Tarih” sütunlarına göre sıralamak için kullanıldı.
Bu sıralama; her bir stok kodunun zaman içindeki değişimini, kronolojik sırayla gözlemlemek için yapılmaktadır.
inplace=True parametresi; değişikliklerin orijinal DataFrame üzerinde kalıcı olarak uygulanmasını sağlamak için kullanıldı. - look_back: Modelin geçmiş veri pencerelerini; kaç zaman adımı olarak göz önünde bulunduracağını belirlemek için kullanıldı. Bu örnekte; her bir özellik vektörü için son 30 zaman adımının verisi kullanılır. Bu; projede kullandımığız sistematikte ise, 30 gün olarak karşılık bulmaktadır.
- features: Bağımsız değişkenler (predictors) olarak kullanılacak özellik setlerini içermesi için kullanıldı. Her bir özellik seti; belirli bir stok kodunun, sıralı tarihlerdeki ölçeklenmiş miktar değerlerinden oluşan bir zaman penceresini ifade etmektedir.
- labels: Her bir özellik setine karşılık gelen bağımlı değişkeni (target) içermesi için kullanıldı. Burada; her özellik seti için, hemen sonraki miktar değeri etiket olarak kullanılmaktadır.
for loop: Bu yapı; modelin belirli bir stok kodu için son 30 zaman adımındaki miktarlara dayanarak, bir sonraki zaman adımındaki miktarı tahmin etmesi için kullanılacak veri setini oluşturması için kullanıldı. Özellikle; LSTM gibi zaman serisi verileri için uygun olan modellerde, bu tür bir veri yapılandırması modelin zaman içindeki desenleri öğrenmesine olanak tanımaktadır.
6-Model Eğitimi ve Hiperparametre Optimizasyonu
X_train, X_test, y_train, y_test = train_test_split(features, labels, test_size=0.3, shuffle=False)
def build_model(hp):
model = Sequential()
model.add(LSTM(units=hp.Int('units', min_value=32, max_value=256, step=32), input_shape=(look_back, 1)))
model.add(Dense(1))
model.compile(optimizer=hp.Choice('optimizer', ['adam', 'rmsprop', 'sgd']), loss='mean_squared_error')
return model
İlgili koda yönelik;
- train_test_split(): Veri setini eğitim ve test setlerine ayırmak için kullanıldı.
test_size=0.3: Veri setinin %30’unun test için ayrıldığını belirtmek için kullanıldı.
Kalan veriseti, yani; %70’i ise, eğitim seti olarak kullanılmaktadır.
shuffle=False: Verilerin bölünmeden önce karıştırılmaması için kullanıldı.
Zaman serisi verilerinde, genellikle verilerin sırasının korunması tercih edilir; çünkü, zamanın önceki ve sonraki durumlar arasında doğal bir bağlantı bulunmaktadır. - build_model(hp) – hp: Hyperparameter (hiperparametre): Hiperparametre tuning için kullanıldı.
- Sequential(): Keras modeli oluşturmak için kullanıldı.
Sequential model; katmanların sıralı bir liste gibi düzenlendiği bir model türüdür. - LSTM: Uzun-Kısa Süreli Hafıza birimlerini içeren model üzerindeki işlemlerin gerçekleştirilmesi için kullanıldı.
- units=hp.Int(‘units’, min_value=32, max_value=256, step=32): LSTM katmanındaki nöron sayısı belirlemek için kullanılmaktadır. Bu değer; modelin karmaşıklığını ve öğrenme kapasitesini doğrudan etkilemektedir.
hp.Int fonksiyonu; belirtilen aralıkta (32’den 256’ya kadar 32’lik adımlarla) en iyi unit[1] (ünite) sayısını bulmak için kullanılmaktadır. - input_shape=(look_back, 1): Modelin girdi şeklini belirlemek için kullanıldı.
Burada, look_back parametresi; her bir örneğin, kaç zaman adımını içereceğini ve 1 verinin tek bir özellikten (tek değişkenli zaman serisi) oluştuğunu belirtmektedir. - Dense(1): Modelin çıkış katmanı olarak kullanıldı. Çıktı boyutu 1 olarak ayarlanmıştır. Yani; model her bir örneğin çıktısı olarak tek bir değer üretmektedir.
- optimizer=hp.Choice(‘optimizer’, [‘adam’, ‘rmsprop’, ‘sgd’]): Modelin eğitimi sırasında kullanılacak optimizasyon algoritmasını belirlemek için kullanıldı.
Bu seçim; hiperparametre optimizasyon sürecinde test edilmektedir.
loss=’mean_squared_error’: Model performansını ölçmek için kullanılmaktadır.
[1] units parametresi; LSTM (Long Short-Term Memory) katmanında bulunan nöron (hücre) sayısını belirtmektedir.
7-Erken Durdurma ve Model Ayarlama (Tuning)
def ensure_directories_exist(directory, project_name):
full_path = os.path.join('C:\\Temp', directory, project_name)
os.makedirs(full_path, exist_ok=True) # exist_ok=True, dizin zaten varsa hata vermemesini saglar.
ensure_directories_exist('model_tuning', 'stock_prediction')
tuner = RandomSearch(
build_model,
objective='val_loss',
max_trials=10,
executions_per_trial=3,
directory='C:\\Temp\\model_tuning',
project_name='stock_prediction'
)
early_stopping = EarlyStopping(monitor='val_loss', patience=10, restore_best_weights=True)
tuner.search(X_train, y_train, epochs=50, validation_data=(X_test, y_test), callbacks=[early_stopping])
best_hps = tuner.get_best_hyperparameters(num_trials=1)[0]
print(f"En iyi hiperparametreler: \n"
f"Units: {best_hps.get('units')}\n"
f"Optimizer: {best_hps.get('optimizer')}"))
İlgili koda yönelik;
- ensure_directories_exist(): Modelin ayar dosyalarının saklanacağı dizinleri kontrol edip, gerekirse bu dizinleri oluşturmak için kullanıldı.
Fonksiyon, os modülünün makedirs metodunu kullanarak; verilen dizin yolunu (`C:\Temp\model_tuning\stock_prediction`) kontrol eder ve eğer dizin yoksa oluşturur. Bu yapı; model ayarlarının organize bir şekilde saklanmasını ve eğitim süreci sırasında erişilebilir olmasını sağlamaktadır. - RandomSearch[1](): build_model fonksiyonunu kullanarak, farklı model yapılandırmalarını test etmek için kullanıldı.
objective=’val_loss’: Doğrulama kaybını “val_loss” minimize etmek için kullanıldı.
max_trials=10: Denenecek maksimum model sayısını belirtmek için kullanıldı.Yani, Random Search algoritması; 10 farklı model yapılandırmasını deneyerek, en iyisini seçmeye çalışmaktadır.
executions_per_trial=3: Her bir denemede modelin kaç kez çalıştırılacağını belirlemek için kullanıldı. Bu; modelin performansının tesadüfi varyasyonlarına karşı daha sağlam (robust) bir değerlendirmede bulunmasını sağlamaktadır.
directory ve project_name: Model yapılandırma ve ağırlıklarının kaydedileceği dizin ve proje adını belirtmek için kullanıldı.
- EarlyStopping(): Modelin eğitim sürecinde, belirli bir kriter üzerinde iyileşme olmadığı takdirde eğitimi durdurmak için kullanıldı.
monitor=’val_loss’: İzlenen metrik, doğrulama kaybını takip için kullanıldı.
patience=10: Eğer; 10 epoch boyunca “val_loss” metriğinde iyileşme olmazsa, eğitimi durdurmak için kullanıldı.
restore_best_weights=True: Eğitim durdurulduğunda; modelin en iyi ağırlıkları geri yüklenmesi için kullanıldı. Bu erken durdurma noktasında; elde edilen en iyi performansın korunmasını sağlamaktadır. - tuner.search(): Hiperparametre optimizasyon sürecini başlatmak için kullanıldı.
X_train, y_train: Modelin eğitim verilerini ifade etmek için kullanıldı.
epochs=50: Maksimum iterasyon (epoch) sayısını belirlemek için kullanıldı.
validation_data: Modelin performansının değerlendirileceği test verilerini belirtmek için kullanıldı.
callbacks=[early_stopping]: Eğitim sürecine dahil edilen erken durdurma mekanizması için kullanıldı. Bu callback; yukarıda tanımlanan erken durdurma koşullarını kontrol edtmekte ve gerektiğinde eğitimi durdurulmasını sağlamaktadır.
En iyi optimizer için örnek çıktı; Reloading Tuner from C:\Temp\model_tuning\stock_prediction\tuner0.json
En iyi hiperparametreler:
Units: 96
Optimizer: rmsprop
[1] RandomSearch algoritması; hiperparametre optimizasyonunda kullanılan bir yöntem olarak ifade edilmektedir. Modelin performansını etkileyebilecek hiperparametrelerin en iyi kombinasyonunu bulmayı amaçlar. Bu yöntem; belirli bir parametre alanı içindeki değerlerden rastgele seçimler yaparak, modelin farklı konfigürasyonlarını dener.
8-Sonuçları Görselleştirme ve Değerlendirme
trial_ids = []
units = []
optimizers = []
val_losses = []
for trial in tuner.oracle.trials.values():
trial_ids.append(trial.trial_id)
units.append(trial.hyperparameters.values['units'])
optimizers.append(trial.hyperparameters.values['optimizer'])
val_losses.append(trial.score)
results_df = pd.DataFrame({
'trial_id': trial_ids,
'units': units,
'optimizer': optimizers,
'val_loss': val_losses
})
print(results_df)
plt.figure(figsize=(10, 6))
sns.scatterplot(data=results_df, x='units', y='val_loss', hue='optimizer', style='optimizer', s=100)
plt.title('Hiperparametrelerin Doğrulama Kaybina Göre Performansi')
plt.xlabel('Units')
plt.ylabel('Validation Loss')
plt.legend(title='Optimizer')
plt.grid(True)
plt.show()
İlgili koda yönelik;
- tuner.get_best_hyperparameters(num_trials=1): RandomSearch objesinden hiperparametre aramaları sırasında elde edilen en iyi hiperparametreleri almak için kullanıldı. “num_trials=1” parametresi; en iyi hiperparametre setini almak için kullanılmaktadır. Bu fonksiyon bir liste döndürdüğü için [0] ile listenin ilk elemanı alınır; bu da, en iyi hiperparametreleri içeren HyperParameters objesidir.
- pd.DataFrame(): Optimizasyon süreci sırasında kaydedilen hiperparametre değerleri ve elde edilen doğrulama kaybı değerleri ile bir DataFrame oluşturmak için kullanıldı.
Bu DataFrame; her bir deneme için “trial_id” kullanılan LSTM üniteleri “units”, optimizasyon algoritması “optimizer” ve elde edilen doğrulama kaybı “val_loss” değerlerini içermektedir. - plt.figure(figsize=(10, 6)): Matplotlib ile bir grafik çizimi oluşturmak için kullanıldı.
figsize parametresi ise; grafiğin boyutunu “inch[1]” (inç) cinsinden belirlemektedir.
sns.scatterplot(): Saçılım grafiği “scatter plot” çizmek için kullanıldı.
Bu grafik, her bir denemenin LSTM ünite sayısına “units” ve elde edilen doğrulama kaybına “val_loss” göre nasıl performans gösterdiğini göstermektedir.
hue=’optimizer’ ve style=’optimizer’: Farklı optimizasyon algoritmalarına göre noktaların rengini ve stilini ayarlamak için kullanıldı. Bu farklı optimizer seçeneklerinin performansını karşılaştırmayı kolaylaştırmaktadır.
s=100: Noktaların boyutunu belirlemek için kullanıldı.
plt.title(), plt.xlabel() ve plt.ylabel(): Grafiğe; başlık ve x ve y eksenlerine etiketler eklemek için kullanıldı.
plt.legend(): Anahtar bilgileri grafiğe eklemek için kullanıldı.
plt.grid(True): Arka plana ızgara çizgileri eklemek için kullanıldı.
plt.show(): Grafiği göstermek için kullanıldı.
Performans için örnek çıktı;
trial_id units optimizer val_loss
0 04 224 sgd 0.013735
1 03 32 rmsprop 0.010187
2 09 192 sgd 0.013723
3 08 64 rmsprop 0.010251
4 00 96 rmsprop 0.010132
5 07 64 adam 0.011538
6 02 160 adam 0.011942
7 01 256 sgd 0.013707
8 05 96 sgd 0.013655
9 06 32 sgd 0.013913
Performans için örnek görsel çıktısı;
[1] Inch (TR: inç); 2,54 cm uzunluğundaki uzunluk ölçüsü birimi olarak ifade edilmektedir.
9-En İyi Hiperparametre Sonuçlarının Yazdırılması
best_row = results_df.loc[results_df['val_loss'].idxmin()]
best_units = best_row['units']
best_optimizer = best_row['optimizer']
print(f"En iyi modelin parametreleri: \n{best_row}")
İlgili koda yönelik;
- results_df.loc[results_df[‘val_loss’].idxmin()]: results_df adlı DataFrame içerisinden; val_loss sütununun en düşük değerini bulmak için kullanıldı.
Son olarak ilgili değeri best_row değişkenine atamaktadır. - best_row[‘units’]: best_row değişkeninde saklanan satırdan; units sütunun değeri alıp, best_units adlı değişkene atamak için kullanıldı.
- best_optimizer = best_row[‘optimizer’]: best_row değişkeninde saklanan satırdan optimizer sütunu değeri alıp, best_optimizer adlı değişkene atamak için kullanıldı.
- print(f”En iyi modelin parametreleri: \n{best_row}”): best_row değişkeni değerini ekrana yazdırmak için kullanıldı.
10-Eğitim ve Doğrulama Kaybı Sonuçlarının Kontrol Edilmesi
history = best_model.fit(X_train, y_train, epochs=50, validation_data=(X_test, y_test), callbacks=[early_stopping])
plt.figure(figsize=(10, 5))
plt.plot(history.history['loss'], label='Egitim Kaybi')
plt.plot(history.history['val_loss'], label='Dogrulama Kaybi')
plt.title('Model Kaybi')
plt.ylabel('Kayip')
plt.xlabel('Epoch')
plt.legend(loc='upper right')
plt.show()
İlgili koda yönelik;
- history = best_model.fit(X_train, y_train, epochs=50, validation_data=(X_test, y_test), callbacks=[early_stopping]): En iyi modeli “best_model” kullanarak; eğitim veri seti “X_train”, “y_train” üzerinde modeli eğitmek ve “epochs=50” parametresi ile modelin eğitim verileri üzerinden 50 kez geçerek, doğrulama ve durum tarihçesine ulaşmak için kullanıldı.
- plt.figure(figsize=(10, 5)): Grafik çiziminin boyutlarını belirlemek için kullanıldı.
plt.plot(history.history[‘loss’], label=’Egitim Kaybi’): Eğitim sürecindeki kayıp değerlerini “loss” çizmek için kullanıldı.
plt.plot(history.history[‘val_loss’], label=’Dogrulama Kaybi’): Eğitim sürecindeki doğrulama kaybını “val_loss” çizmek için kullanıldı.
plt.title(‘Model Kaybi’)
plt.ylabel(‘Kayip’)
plt.xlabel(‘Epoch’): Sırasıyla; grafik başlığını ve y-ekseni (kayıp) ile x-ekseni (eğitim dönemi) için etiketleri tanımlama adına kullanıldı.
plt.legend(loc=’upper right’): Çizilen her çizginin; neyi temsil ettiğini belirten bir lejant eklemek ve bu lejantı grafiğin üst sağ köşesine yerleştirmek için kullanıldı.
plt.show(): Oluşturulan grafik çizimini göstermek için kullanıldı.
Model eğitim ve doğrulama kaybı için örnek görsel çıktısı;
11-En İyi Model Sonuçlarının Yazdırılması
best_model = tuner.get_best_models(num_models=1)[0]
predictions = best_model.predict(X_test)
mse = mean_squared_error(y_test, predictions)
print(f"Test seti uzerindeki MSE: {mse}")
İlgili koda yönelik;
- best_model = tuner.get_best_models(num_models=1)[0]: Daha önce kullanılan RandomSearch tuner nesnesi tarafından yapılan model aramaları arasından; en iyi performans gösteren modeli almak için kullanıldı.
get_best_models(num_models=1) metodu; değerlendirme kriterlerine (bu durumda val_loss) göre sıralanmış en iyi modelleri bir liste olarak döndürmesi için kullanıldı. Burada num_models=1 parametresi; yalnızca en iyi modelin döndürülmesini sağlamaktadır. Döndürülen liste içerisinden; ilk model [0] ile seçilir ve best_model değişkenine atanır. - predictions = best_model.predict(X_test): best_model olarak seçilen modeli kullanarak, test veri seti X_test üzerinde tahmin yapılmasını sağlamak için kullanıldı. predict fonksiyonu; X_test veri setindeki her örnek için bir çıktı üretir. Bu çıktılar; predictions adlı değişkene atanır.
- mse = mean_squared_error(y_test, predictions): Modelin tahminlerinin ne kadar doğru olduğunu ölçmek için kullanılan bir metrik olan Ortalama Kare Hata (MSE) değerini hesaplamak için kullanıldı. “mean_squared_error” fonksiyonu; gerçek değerler “y_test” ve modelin tahmin ettiği değerler “predictions” arasındaki farkların karelerinin ortalamasını almaktadır. Bu değer; “mse” değişkenine atanır.
- print(f”Test seti uzerindeki MSE: {mse}”): Bu satır, hesaplanan MSE değerini ekrana yazdırmak için kullanıldı. MSE; modelin test veri setindeki performansını nicel bir şekilde ifade eder; düşük MSE değerleri, modelin gerçek değerlere daha yakın tahminler yaptığını gösterir.
MSE örnek çıktısı;
63/63 ━━━━━━━━━━ 1s 10ms/step Test seti uzerindeki MSE: 0.06773521173156355
12-Tahminlemenin Gerçekleştirilmesi
results = {}
best_model = tuner.get_best_models(num_models=1)[0]
for stock_code in df['StokKodu'].unique():
data = df[df['StokKodu'] == stock_code]
if len(data) >= look_back:
last_sequence = data['Miktar_scaled'].values[-look_back:].reshape(1, look_back, 1)
print("Boyut kontrolu - Last sequence shape:", last_sequence.shape)
try:
future_stock = best_model.predict(last_sequence)
future_stock = scaler.inverse_transform(future_stock)
except Exception as e:
print(f"{stock_code} stok kodu icin tahminleme hatasi: {e}")
continue
last_date = data['Tarih'].iloc[-1]
last_stock = data['Miktar'].iloc[-1]
if last_stock == 0:
results[stock_code] = "Stok zaten tukenmis."
else:
rate_of_depletion = future_stock[0, 0] / last_stock
if np.isinf(rate_of_depletion):
results[stock_code] = "Tahmin edilemiyor."
else:
days_to_deplete = int(np.ceil(rate_of_depletion))
depletion_date = last_date + pd.Timedelta(days=days_to_deplete)
results[stock_code] = depletion_date.strftime('%Y-%m-%d')
else:
results[stock_code] = "Yeterli veri yok."
İlgili koda yönelik;
- results = {}
best_model = tuner.get_best_models(num_models=1)[0]: results adında boş bir sözlük oluşturması için kullanıldı. Bu sözlük; her stok kodunun tahmin edilen tükenme tarihini saklamaktadır. Ardından; daha önce eğitilen modeller arasından en iyi performans gösteren model best_model değişkenine atanır.
- for stock_code in df[‘StokKodu’].unique(): Bu döngü, veri setindeki df tüm benzersiz stok kodları üzerinde iterasyon yapmak için kullanıldı. Her bir stok kodu için; aşağıdaki işlemler gerçekleştirilir.
- data = df[df[‘StokKodu’] == stock_code]
if len(data) >= look_back: İlgili stok koduna ait veriler data DataFrame’inde toplanır. Eğer bu DataFrame’deki veri sayısı, modelin girdi olarak beklediği `look_back` değerinden az değilse işleme devam edilir.
- last_sequence = data[‘Miktar_scaled’].values[-look_back:].reshape(1, look_back, 1): Modelin tahmin yapabilmesi için gerekli olan son look_back sayıda veri alınır ve bu veriler uygun şekilde yeniden boyutlandırılarak reshape modelin girdi formatına uygun hale getirilir.
- try:
future_stock = best_model.predict(last_sequence)
future_stock = scaler.inverse_transform(future_stock)
except Exception as e:
print(f”{stock_code} stok kodu icin tahminleme hatasi: {e}”)
continue: Düzenlenmiş veri üzerinde model ile tahmin yapılır. Eğer bir hata meydana gelirse; ilgili hata mesajı yazdırılır ve döngünün sonraki iterasyonuna geçilir. Başarılı bir tahmin sonrası, “scaler.inverse_transform” ile normalizasyondan önceki değerlere dönüştürülür.
- last_date = data[‘Tarih’].iloc[-1]
last_stock = data[‘Miktar’].iloc[-1]
if last_stock == 0:
results[stock_code] = “Stok zaten tükenmiş.”: Her stok kodu için son tarih ve stok miktarı alınır. Eğer stok miktarı sıfırsa, bu stok kodu için “Stok zaten tükenmiş” bilgisi results sözlüğüne eklenir.
- else:
rate_of_depletion = future_stock[0, 0] / last_stock
if np.isinf(rate_of_depletion):
results[stock_code] = “Tahmin edilemiyor.”
else:
days_to_deplete = int(np.ceil(rate_of_depletion))
depletion_date = last_date + pd.Timedelta(days=days_to_deplete)
results[stock_code] = depletion_date.strftime(‘%Y-%m-%d’): Eğer stok miktarı sıfır değilse, tükenme oranı hesaplanır. Eğer bu oran sonsuz ise (genellikle matematiksel bir hata sonucu), “Tahmin edilemiyor” bilgisi eklenir. Değilse, tükenme gün sayısı hesaplanır, bu gün sayısı son tarihe eklenir ve bu tarih `results` sözlüğüne eklenir.
- else:
results[stock_code] = “Yeterli veri yok.”: Eğer `look_back` sayısından daha az veri varsa, bu stok kodu için “Yeterli veri yok” bilgisi eklenir. Bu şekilde, kod bloğu tüm stok kodları için tahminler yapar ve sonuçları `results` sözlüğünde toplar.
13-Sonuçların Yazdırılması
for stock_code, depletion_date in results.items():
print(f"Stok Kodu {stock_code} icin stoklarin bitecegi tahmini tarih: {depletion_date}")
İlgili koda yönelik;
- for stock_code, depletion_date in results.items(): “results” sözlüğünün; “.items()” metodunu kullanarak, sözlükte saklanan her bir anahtar-değer çifti üzerinde döngü başlatmak için kullanıldı. Burada; “stock_code” her bir stok kodunu temsil ederken, “depletion_date” ise bu stok koduna karşılık gelen tahmini tükenme tarihini temsil eder. “.items()” metodu; sözlükteki anahtar (key) ve değer (value) çiftlerini döndürür, böylece her döngü iterasyonunda bu bilgilere erişilebilmektedir.
- print(f”Stok Kodu {stock_code} icin stoklarin bitecegi tahmini tarih: {depletion_date}”):Tahmin sonuçlarını görüntüleme adına “print” ve formatlı string “f-string” fonksiyonları kullanıldı. Bu string içinde; “stock_code” ve “depletion_date” değişkenleri doğrudan yerleştirilerek, okunabilir bir cümle formunda çıktı üretilir. Çıktı; her stok kodu için “Stok Kodu [stok kodu] için stokların biteceği tahmini tarih: [tahmini tarih]” şeklinde olmaktadır.
Sonuç tahminlemesine yönelik örnek çıktılar; Stok Kodu CECE5SAM0021 icin stoklarin bitecegi tahmini tarih: Stok zaten tukenmis.
Stok Kodu XOFUGM0037 icin stoklarin bitecegi tahmini tarih: Stok zaten tukenmis.
Stok Kodu XOFUGM0043 icin stoklarin bitecegi tahmini tarih: 2024-05-29
Stok Kodu XOFUGM0046 icin stoklarin bitecegi tahmini tarih: 2024-05-27
Stok Kodu XOFUGM0048 icin stoklarin bitecegi tahmini tarih: 2024-05-27
Stok Kodu XOFUGM0049 icin stoklarin bitecegi tahmini tarih: Yeterli veri yok.
… toplamda 38 farklı stok için çıktı üretmektedir.
Öneri ve Tartışmalar
Öneri ve tartışmalar olarak alt kısımdaki gibi genel başlıklarda değerlendirmeler çıkartılmıştır.
Model Geliştirme ve Test Süreçleri
Proje, LSTM modelini kullanarak depo stok seviyelerinin tahmin edilmesi üzerine odaklanmıştır. Model, %70 eğitim ve %30 test veri seti dağılımıyla eğitilmiş; validasyon kaybı ve Mean Squared Error (MSE) metrikleri ile değerlendirilmiştir. Önerilen bu model yapılandırması, zaman serisi verileri üzerinde etkili sonuçlar elde edilmesini sağlamış, ancak daha fazla veri ve farklı yapılandırmalarla test edilmesi farklı sonuçlar üretebilir.
Burada veri kaynağındaki veriyi sentetik olmayan yöntemlerle arttırmak farklı ve daha doğru sonuçlar elde edilmesini sağlayabilir.
Veri Çeşitliliği ve Model Robustluğu
Modelin genelleştirme kabiliyetinin artırılması için çeşitli depo ve stok türlerini içeren daha büyük ve çeşitli veri setleri ile testler yapılması önerilebilir. Bu; modelin farklı senaryolar ve koşullar altında da doğru tahminler yapabilmesi kilit çözüm sağlayabilir.
Veri Kaynağının Ek Öznitelikler İçermesi
Projeye yönelik kullanılan verikaynağındaki özniteliklerin[1] arttırılması daha doğru sonuçların elde edilmesini sağlayabilir. Örneğin; stoklara yönelik satış kampanya tarihleri, stoklara yönelik alış indirim kampanya tarihleri, kronik problemli ürünler, stok kullanıcı puanı düşük ürünler vb.
Hiperparametre Optimizasyonu
Projede; RandomSearch yöntemi ile yapılan hiperparametre optimizasyonu, modelin performansını artırmada kullanılmıştır. Farklı optimizasyon yöntemlerinin (Grid Search veya Bayesian Optimization) denenmesi ve bu yöntemlerin sonuçlarının karşılaştırılması denenebilir. Bu sayede; en iyi model yapılandırmasına, daha sistematik bir yaklaşımla ulaşılabilir.
Öğrenme ve Tahminleme Modeli Yapısının Değiştirilmesi
Projede, öğrenme modeli ve tahmin yapısı; genel bir öğrenme ile genel tahminleme mantığında kurgulanmış. Herbir stok özelinde test ve öğrenme gerçekleştirip, tahminlemede bulunmak daha optimum ve doğru sonuçlar verebilir. [Ek dosya; sf_singular.ipynb]
Operasyonel Entegrasyon ve Kullanım Kolaylığı
LSTM modelinin; gerçek zamanlı depo yönetim sistemlerine entegrasyonu ve operasyonel süreçlere dahil edilmesi önerilebilir. Böylece; modelin ürettiği tahminler doğrudan stok yönetimi ve yeniden sipariş süreçlerine entegre edilebilir, bu da işletmeler için zaman ve maliyet tasarrufu sağlayabilir.
Yeni Teknolojiler ve Yaklaşımların Araştırılması
Gelişen yapay zeka teknolojileri ve algoritmaları ışığında; LSTM dışında farklı derin öğrenme mimarilerinin (GRU veya Transformer tabanlı modeller) değerlendirilebilir. Bu; yeni yaklaşımların, stok tahmin doğruluğunu artırma potansiyeli sağlayabilir.
[1] Öznitelik (Feature); makine öğrenimi ve veri analizi bağlamında, veri setlerindeki gözlemleri temsil eden bireysel ölçümlere veya bilgilere verilen isim olarak ifade edilmektedir.
***
Gerçekleşleştirilmiş olan projeye yönelik kaynak kodlara;
https://github.com/miracozturk17/warehouse-stock-estimation-with-lstm-network
bağlantısı üzerinden erişebilirsiniz.
Umarım faydalı olur.
İyi çalışmalar.