Predikce zásob pomocí AI 10. Finální model Finální test – celý dataset Chvíle pravdy: Jak se model zachová, když ho pustíme na všech 15 000 položek? Nastavení modelu a dat (podle dosavadních zjištění): Feature engineering, 120 features (kombinace individuálního obratu a group-features) Redukce extrémů Sloučení řídkých kategorií Trénink jen na položkách s alespoň 1 měsícem historie Délka encoderu 18 měsíců Architektura TFT Validace: poslední 3 měsíce, které nebyly v tréninku Pro závěrečný test jsem zvolil model s group features, ale bez syntetických dat. Tento setup se ukázal jako nejstabilnější napříč celým sortimentem, i když syntetika zůstává zajímavou možností pro budoucí projekty nebo specifické subsety zboží. Upravit Metrika Celá historie 33 měsíců 13-32 měsíců Hodnota (ALL) Hodnota (Item) Hodnota (ALL) Hodnota (Item) Hodnota (ALL) Hodnota (Item) WAPE 30.1022 49.7127 28.1069 41.6723 33.4304 40.1634 RMSE 45.907 22.3895 50.4051 23.9145 26.3204 17.0358 R² 0.9232 0.93 0.7245 MAPE 65.5438 57.332 60.9407 ROBUST 0.551 72.2735 0.5498 58.7128 0.5049 66.3819 STABLE 0.3884 0.3642 0.5422 Upravit Metrika 6-12 měsíců 1-6 měsíců bez historie Hodnota (ALL) Hodnota (Item) Hodnota (ALL) Hodnota (Item) Hodnota (ALL) Hodnota (Item) WAPE 38.5444 45.8518 44.6778 47.1055 80.7317 220.7146 RMSE 26.6287 17.1458 43.1306 27.5178 95.9705 61.587 R² 0.7529 0.7451 -0.1913 MAPE 64.676 79.1142 186.139 ROBUST 0.5233 66.5118 0.5441 89.7998 0.4013 250.967 STABLE 0.4801 0.4776 0.9196 Výsledky podle délky historie: Plná historie (36 měsíců) – WAPE kolem 30 % (ALL), vysoké R² (0,92+). Středně dlouhá historie (12–35 měsíců) – podobné výsledky jako u plné historie, jen lehký pokles R². Krátká historie (6–12 měsíců) – stále solidní predikce, WAPE kolem 38 %. Velmi krátká historie (1–6 měsíců) – vyšší chyby, ale přesto použitelná predikce pro orientační plánování. Bez historie – predikce zůstává nepoužitelná, model nemá jediný bod pro určení scale. Ve srovnání s kapitolou #9 (test na částečném datasetu) jsou metriky prakticky totožné – model drží stabilitu i při trojnásobném objemu dat. Vidět je i mírné zlepšení u SKU s krátkou historií, hlavně díky většímu počtu kategorií v rámci skupin → bohatší data pro embeddingy → lepší přenos vzorů. Vizualizace Porovnávám predikce modelu z částečného datasetu (minulá kapitola) s novou predikcí nad plným datasetem. 🔴 Červená – predikce z modelu nad částečným datasetem. 🟢 Zelená – predikce z finálního modelu nad celým datasetem. Největší vizuální rozdíly jsou patrné u SKU s krátkou historií – právě tam teď hrají skupinové informace výraznější roli. U delších historií se křivky překrývají téměř dokonale, což potvrzuje, že navýšení tréninkového datasetu na plný rozsah nepoškodilo výkon u zavedených položek. Slevové akce Model si na plném datasetu vede velmi dobře, proto jsem ještě ověřil, jak zvládá promo kampaně. V tréninkových datech dostává informaci kdy a jak dlouho bylo konkrétní zboží ve slevě. V rámci feature engineeringu navíc přidávám kontext: jak často mívá položka akci jak dlouho promo obvykle trvá jaký mělo v minulosti dopad na prodeje Vizualizace ukazuje rozdíl v predikci když položka měla plánovanou slevu vs bez slevy. 🔴 Červená – bez plánovaných slev 🟢 Zelená – sleva na poslední 3 měsíce Kde historie potvrzuje úspěšnost slev, predikce prodeje roste. Kde kampaně v minulosti nefungovaly, křivka zůstává téměř beze změny (např. C511478). To ukazuje, že model se dokáže rozhodovat podle skutečného dopadu promo akcí v historii a sleva sama o sobě není univerzálním spouštěčem zvýšeného prodeje. Produkční model Abych zákazníkovi dodal plnohodnotné řešení, natrénoval jsem finální verzi modelu – tentokrát na celé historii 42 měsíců (od začátku projektu nějaké měsíce uplynuly). Validační okno tentokrát neexistuje, takže hodnocení probíhá vizuálním porovnáním s interním forecastem zákazníka a skutečnými prodeji (které jsem dohrál zpětně). I když chybí přesná metrika, klíčové je, že zákazník je spokojený a v projektu vidí jednoznačný přínos. Co ukazuje vizualizační aplikace: ⚫ Historical data – skutečné prodeje 🔵 POC prediction – výstup z testovacího modelu s jen základním nastavením 🟢 Final prediction – finální model 🔴 Customer forecast – interní predikce zákazníka Predikce modelu se ve většině případů drží velmi blízko reálným hodnotám Odchylky se objevují hlavně u anomálních prodejů, které se výrazně vymykají běžnému chování Model spolehlivě zachycuje sezónní vzorce a drží jejich tvar i při kolísání objemů Dokáže korigovat chyby manuálního forecastu zákazníka U položek s kratší historií je predikce více ovlivněná chováním skupiny, což může vést k odchýlení od reality Nové položky s historií kratší než 6 měsíců jsou pro model stále výzvou – přesnost zde začíná znatelně klesat Vyzkoušejte si výsledky sami: https://demo-inventory-forecasts.streamlit.app/.(Pokud aplikace spí, klikněte na “Yes, get this app back up!” – do minuty naskočí.) Poznámka: všechny zobrazené údaje jsou anonymizované a lehce pozměněné. Závěr série – Predikce zásob pomocí AI Po deseti dílech tohoto dokumentu, tisících experimentů a terabajtech natrénovaných dat jsem se dostal k finálnímu řešení. Během projektu jsem: postavil robustní pipeline pro zpracování dat a feature engineering zvládl práci s extrémy přidal položky s neúplnou historií otestoval desítky kombinací scénářů, modelů a nastavení zavedl group-features pro přenos znalostí mezi podobnými položkami, Finální volba TFT model s group-features, bez syntetických hodnot, trénovaný na položkách s minimálně 1 měsícem historie. Výsledek? Stabilní predikce napříč celým sortimentem, silné zachování sezónnosti a schopnost korigovat chyby v manuálních forecastech zákazníka.
Predikce zásob pomocí AI: #9: Predikce krátkých položek
Predikce zásob pomocí AI 9. Predikce krátkých položek Shrnutí V předchozím díle jsem poprvé trénoval model na celém sortimentu – tedy nejen na položkách s plnou 36měsíční historií, ale i na těch, které mají jen několik málo měsíců dat, případně žádnou historii. pouze položky s plnou historií položky s alespoň jedním měsícem historie celý dataset včetně položek bez jakékoli minulosti Varianta min. 1 měsíc historie přinesla nejvyšší stabilitu – model dokázal využít co nejvíc dat, aniž by se učil na „prázdných“ řádcích. Při detailní validaci se ale ukázalo, že největší slabinou zůstávají položky s méně než 6 měsíci historie. Položky s alespoň 6 měsíci historie model zvládá relativně spolehlivě. Pod touto hranicí, a zejména u zcela nových SKU, chyby prudce rostou. Nejčastější problém: model netrefí ani základní scale – neví, jestli predikovat 10, 100 nebo 1000 kusů. Feature engineering III – Skupinové features V pátém díle jsem ukázal, jak dodatečné features promění syrová čísla v „mapu“, ve které se neurální síť zorientuje a předpoví poptávku s užitečnou přesností. Tentokrát ale cílím na položky s krátkou historií, teré v sobě nemají dost informací, aby je model dokázal sám dobře odhadnout. Co je cílem? Najít podobné položky – sdílejí stejný druh, sezónnost, promo-chování. Využít embeddingy skupin – každý segment dostane svůj vektor, který zachycuje podobnost poptávky. Spočítat skupinové průměry – pokud položka nemá vlastní historii, model použije průměry z její skupiny. Přidat tyto hodnoty jako nové features – síť se učí, že může „přelít“ informaci z bohatých sérií do chudých. Proč to funguje: Nový produkt z kategorie „nářadí“ okamžitě těží z historie „elektro-příslušenství“, pokud mají dlouhodobě podobný tvar poptávky. Model lépe rozezná jednorázové špičky od běžného sezónního vzoru. Krátké série přestávají padat k nule, aniž by to poškodilo predikce položek s dlouhou historií. Nové Group-features Stejné typy features, které jsem poprvé použil na individuální obrat, jsem teď aplikoval na úrovni skupin: Relativní (poměrové) features – porovnání položky vůči průměru skupiny. Lag & Rolling okna – zpožděné hodnoty a průměry pro zachycení trendu. Wavelet signály – zachycení periodických vzorů. Trendové ukazatele – sklon a směr vývoje obratu. Absolutní i log-transformované hodnoty – pro lepší škálování napříč objemy. Pro každou položku navíc počítám poměrové log-features, které dávají modelu jemnější měřítko, o kolik se konkrétní položka liší od své skupiny – což je přesně ten chybějící signál u produktů s krátkou historií. Výsledky podle délky historie Opět jsem pro detailnější pohled validaci rozdělil do pěti částí podle délky historie. Validace běžela na modelu trénovaném na položkách s minimálně jedním měsícem historie + přidanými group features. Upravit Metrika Celá historie 36 měsíců 12-35 měsíců Hodnota (ALL) Hodnota (Item) Hodnota (ALL) Hodnota (Item) Hodnota (ALL) Hodnota (Item) WAPE 32.4045 55.2969 30.3056 40.9703 35.6533 41.0825 RMSE 39.9062 20.7024 41.4421 21.1611 25.4482 14.6151 R² 0.8745 0.8862 0.7558 MAPE 60.6599 55.216 62.2879 ROBUST 0.5071 69.6946 0.5078 55.8221 0.567 61.2863 STABLE 0.3969 0.3695 0.4645 Upravit Metrika 6-12 měsíců 1-6 měsíců bez historie Hodnota (ALL) Hodnota (Item) Hodnota (ALL) Hodnota (Item) Hodnota (ALL) Hodnota (Item) WAPE 43.6437 58.8135 53.8679 59.4594 95.8109 522.2663 RMSE 22.9386 15.9583 48.4724 33.3359 44.6723 27.5461 R² 0.7551 0.647 -0.0372 MAPE 63.4811 73.2619 373.445 ROBUST 0.5038 64.5602 0.5628 75.3369 0.3612 550.8374 STABLE 0.4537 0.4594 1.0963 Plná historie (36 měsíců): Metriky prakticky beze změny, group features modelu neuškodily. Středně dlouhé série (12–35 měsíců): Výsledky zůstávají srovnatelné s baseline, žádný pokles výkonu. Krátké série (≤ 6 měsíců): Viditelné zlepšení R² i MAPE, model se lépe trefuje do velikosti obratu. Žádná historie (0 měsíců): Zlepšení z absolutní katastrofy na „stále nepoužitelné“, ale je vidět, že model už dokáže odhadnout tvar křivky z embeddings a skupinového kontextu. Syntetická data – kdy je (ne)vpustit do modelu Krátké a nulové historie jsou pro predikci největší problém – model často netrefí ani základní měřítko (scale). Aby tyto položky dostaly alespoň náznak „minulosti“, nahradil jsem chybějící obrat syntetickými hodnotami. Tyto hodnoty vznikají jako vážený průměr prodejů podobných položek, přičemž: Váhy podobnosti jsou odvozené z embeddingů napříč kombinací skupin (druh × sezóna × …). Na rozdíl od feature-engineering přístupu, kde se vytváří více samostatných hodnot pro různé skupiny, zde vzniká jen jedna výsledná hodnota pro daný časový bod. Další otázku, kterou jsem řešil, kdy syntetiku použít: Upravit Varianta Výhody Nevýhody 1️⃣ Syntetika už v tréninku • Model se hned učí scale novinky → menší sklouzávání k nule. • Učí se na hodnotách, které nikdy neexistovaly → hrozí šum. • Více „plných“ řad = lepší stabilita • Připravené vzory mohou přežít i poté, co reálný prodej začne vypadat jinak (přeučení na syntetiku). • Menší riziko šumu způsobených prázdnými položkami 2️⃣ Syntetika až při validaci • Trénink zůstává „čistý“, bez rizika šumu. • Model nevidí tyto vzory při učení → může syntetiku ignorovat nebo špatně škálovat. • Snadno otestuju, co syntetika skutečně přináší. • Možnost zmatení modelu (proč předtím byli nuly a teď ne) • Kdykoli lze syntetická pravidla vyměnit bez re-tréninku modelu. Vyhodnocení jsem znovu rozdělil do pěti částí podle délky historie. Modely již obsahují rozšíření o group-features. Varianta 1 – Syntetika už v tréninku Upravit Metrika Celá historie 33 měsíců 13-32 měsíců Hodnota (ALL) Hodnota (Item) Hodnota (ALL) Hodnota (Item) Hodnota (ALL) Hodnota (Item) WAPE 32.1862 71.2019 30.0079 43.2471 43.5696 51.4367 RMSE 39.8141 20.1656 41.7923 20.6518 37.0207 18.3537 R² 0.8751 0.8843 0.7773 MAPE 71.3488 62.8897 66.1173 ROBUST 0.5136 87.4698 0.5182 64.0748 0.4673 65.5932 STABLE 0.3973 0.3686 0.544 Upravit Metrika 7-12 měsíců 1-6 měsíců bez historie Hodnota (ALL) Hodnota (Item) Hodnota (ALL) Hodnota (Item) Hodnota (ALL) Hodnota (Item) WAPE 66.8159 1721.7288 52.1569 55.7443 109.8849 788.7963 RMSE 42.6149 22.1131 47.9948 32.8273 43.0087 31.3547 R² 0.4999 0.6155 0.0386 MAPE 271.8153 79.4936 605.8361 ROBUST 0.4346 1021.1267 0.4775 86.1018 0.4294 853.5104 STABLE 0.804 0.6387 1.2805 Téměř všechny metriky se zhoršily, včetně položek s delší historií. Model začal brát syntetické hodnoty stejně vážně jako reálná data → šum ze syntetiky přetlačil skutečné signály. U položek bez historie došlo k mírnému zlepšení tvaru predikce, ale cena za to byla pokles výkonu u zbytku sortimentu. Varianta 2 – Syntetika jen při validace Upravit Metrika Celá historie 33 měsíců 13-32 měsíců Hodnota (ALL) Hodnota (Item)
Predikce zásob pomocí AI: #8: Generalizace – zapojení položek s neúplnou historií
Predikce zásob pomocí AI 8. Generalizace – zapojení položek s neúplnou historií Test s celým datasetem V minulé kapitole jsme ověřili, že model zvládá „bezchybně“ těch 70 % sortimentu, které mají kompletní 36 měsíční historii. Nastal čas pustit jej na celý dataset a zjistit, co se stane, když do hry vstoupí i produkty s kratšími nebo žádnými daty. Upravit Délka historie Počet položek Podíl na sortimentu 36 měsíců (plná historie) 10105 70.00% 12–35 měsíců 2668 18.00% méně než 12 měsíců 1211 8.00% bez historie 519 4.00% Všechny následující experimenty běží na modelu, který jsem postavil v předchozích dílech – tzn. s kompletním feature-engineeringem a omezením extrémů. Opět používám scénář 2 (trénink 33 měsíců / validace poslední 3 měsíce). Zvolil jsem tři tréninkové varianty. Validace je vždy nad celým datasetem. Upravit Varianta Co se použije do tréninku Nových položek k validaci A – plná historie Pouze položky s kompletní historií 468 B – min. 1 měsíc historie Všechny SKU, které mají aspoň 1 historický záznam 73 C – bez omezení Úplně všechny položky (včetně těch bez historie) 0 Poznámka: Například ve variantě Plná historie (A) bylo při validaci nalezeno 468 nových položek, které model při tréninku neviděl. Co sleduji: Globální metriky (R², WAPE, RMSE, …) mezi variantami A, B, C. Dopad na položky s plnou historií – jak se mění metriky po přidání „chudších“ položek. Chování nových/krátkých položek– jestli transfer z “bohatých” sérií pomůže, nebo jestli predikce dál sklouzává k nule či náhodným skokům. Upravit Metrika Plná historie Jakákoliv historie Min. 1 měsíc historie Hodnota (ALL) Hodnota (Item) Hodnota (ALL) Hodnota (Item) Hodnota (ALL) Hodnota (Item) WAPE 41.0748 133.7093 38.4147 93.4879 34.6338 58.0287 RMSE 48.8867 24.5721 57.3472 23.2029 35.4181 18.5031 R² 0.7952 0.7408 0.8511 MAPE 131.7516 70.8846 68.2377 ROBUST 0.4741 158.7209 0.4785 78.5382 0.5312 77.5052 STABLE 0.5013 0.4613 0.3681 Shrnutí čísel: Trénink jen s plnou historií (levý sloupec), tedy všechny položky měli kompletní historii. Predikce silně selhává na položkách, které model nikdy neviděl. Item-WAPE i MAPE letí přes 130 %. Trénink na všech položkách, včetně těch bez historie (prostřední sloupec), globální metriky nezlepší a naopak zvedá RMSE. Trénink na položkách bez historie zanáší velký šum. Optimální varianta je trénink s minimálně 1 měsícem historie (pravý sloupec) – výrazně stahuje chybu dolů a zároveň drží vysoké R². Tuhle variantu jsem zvolil jako novou baseline. Vizuální kontrola Dalším krokem byla vizuální kontrola, opět na oblíbených problematických položkách, navíc rozšířené o položky s krátkou a nulovou historií. Zobrazené modely: 🔴 Model jen s plnou historií 🟢 Model i s nulovou historií 🟣 Model s min. 1 měsícem historie Poznámka: Z důvodu přehledu o délce historie je zobrazeno všech 36 měsíců U položek s plnou historií jsou predikce všech tří modelů téměř totožné. Znamená to, že i když do tréninku přimícháme položky s chybějícími měsíci, síť si poradí—díky feature –weight– dokáže „přeskočit“ prázdná místa a vzor nezkreslí. Modely trénované na datech s různě dlouhou historií predikovaly vyšší (lepší) vrcholy u sezónních položek než model postavený jen na plné historii. Kratší série zřejmě dodaly dodatečný kontext, díky němuž síť odhadla sezónní špičky odvážněji — a v mnoha případech i přesněji. U položek s částečnou historií červený model výrazně propadl. Neměl k dispozici jediný reálný záznam dané položky, tudíž ani představu o jejím typickém obratu. Musel hádat čistě podle podobnosti s jinými produkty. Podobný propad vidíme i u položek s velmi krátkou historií. Červený model se opět neměl čeho chytit. Ostatní dva modely sice také pracují jen s velmi krátkou historií, ale dokáží z ní odhadnout alespoň velikost obratu položky a přiblížit se reálu. Na druhém obrázku je navíc dobře vidět, jak zelený a fialový model „vytahuje“ predikci z podobných SKU: i bez vlastní historie vystřelí prodej v druhém měsíci nahoru, protože obdobné produkty ve stejné skupině vykazují stejný vzor. Model tedy správně využil transfer znalostí z bohatších sérií, místo aby sklouzl k nule. Kde není jediný historický záznam, jsou predikce už spíše odhadem „do prázdna“. Modely bez reálného scalu sklouznou k jakémusi průměru segmentu – u některých položek to znamená hrubé podstřelení, u jiných naopak přestřelení. Bez alespoň jednoho skutečného prodejního bodu zůstává výsledek hodně nečitelný. Jak si model vede podle délky historie Pro detailnější pohled jsem vytvořil validaci pro pět různých scénářů podle délky historie položky. Níže uvádím hlavní postřehy – metriky jsou počítané už jen pro model trénovaný na položkách s minimálně jedním měsícem historie (zelená linka na předchozích grafech). Upravit Metrika Celý dataset 100% položek 36 měsíců 72% položek 12-35 měsíců 18% položek Hodnota (ALL) Hodnota (Item) Hodnota (ALL) Hodnota (Item) Hodnota (ALL) Hodnota (Item) WAPE 34.6338 58.0287 33.4331 45.3934 36.5081 49.183 RMSE 35.4181 18.5031 38.1581 19.3561 23.4648 13.58 R² 0.8511 0.8535 0.7525 MAPE 68.2377 61.9222 67.8013 ROBUST 0.5312 77.5052 0.5282 62.6903 0.5365 66.6689 STABLE 0.3681 0.3505 0.4093 Upravit Metrika 6-12 měsíců 4% položek 1-6 měsíců 4% položek bez historie 2% položek Hodnota (ALL) Hodnota (Item) Hodnota (ALL) Hodnota (Item) Hodnota (ALL) Hodnota (Item) WAPE 37.7617 55.3109 56.1651 61.0081 117.1288 884.835 RMSE 36.3108 11.9183 46.4892 34.9088 45.6377 33.9161 R² 0.7767 0.5277 -0.0826 MAPE 69.1417 98.2678 636.876 ROBUST 0.5478 69.4062 0.5247 105.5108 0.4238 940.0516 STABLE 0.4296 0.5151 1.3529 Shrnutí čísel: Stabilita napříč historií: Model drží velmi podobné metriky až do kategorie 6 – 12 měsíců. Znamená to, že si dokáže poradit i s neúplnou minulostí. Rozdíl je v metrice R², způsobený chybějící historií. Nižší RMSE u 12–35 a 6–12 měsíců: Tyto položky jsou středně-obrátkové, absolutní odchylky jsou tedy menší, což RMSE stahuje dolů. Krátká historie: Pod hranicí šesti měsíců už metriky začínají padat – modelu chybí historie, ale stále se hodnoty drží v rozumných mezích. Bez dostatečné znalosti typickém obratu se model rozhoduje jen podle podobnosti se skupinou a chyby rychle rostou. Nulová historie: Výsledné metriky jsou výrazně zkreslené — model se opírá o skupinové znaky, ale chybí mu konkrétní kontext pro danou položku. Mise „krátká historie“ Bylo zřejmé, že se musím zaměřit hlavně na položky s krátkou historií. U zcela nových položek, bez jediného prodejního záznamu a bez znalosti typického obratu, model není schopen nic „uhodnout“. Proto jsem si stanovil praktickou hranici:
Predikce zásob pomocí AI: #7: Feature engineering II – Jak zkrotit sezónu, nuly a promo
Predikce zásob pomocí AI 7. Feature engineering II – Jak zkrotit sezónu, nuly a promo Sezónní prodeje Typickým příkladem jsou vánoční položky. Deset měsíců se neprodávají, v listopadu a prosinci prodej doslova vystřelí. Hlavním úskalím zde bylo naučit model, aby rozpoznal sezónní prodeje od náhodných prodejů nebo outlinerů. V tréninkovém okně (33 měsíců) měla položka takové vrcholy pouze dva, takže model je snadno považoval za šum a dál předpovídal nuly. Co přesně selhalo Málo opakování: dvě špičky ve 33 měsících nevytvoří dostatečný „statistický vzorek“. Robustní normalizace: extrémy zjemnila, takže se model „nebál“ je ignorovat. Žádný explicitní signál: že daný měsíc je pro položku speciální. Součástí každé vizualizace je graf znázorňující: Černá – Reálný historický prodej Červená – Výstup modelu před úpravou Zelená – Výstup modelu po úpravě Řešení: Rozšířil jsem dataset o nové signály, které modelu pomohli pochopit sezónnost: Blíží se vrchol: model nyní dostává signál, že právě nastal měsíc (nebo konkrétní časový bod), kdy prodej historicky trvale skáče vysoko – např. Vánoce, Black Friday či letní sezóna. Je to sezóna: další signál říká, zda se podobný výstřel zopakoval minimálně ve dvou letech po sobě. Tím model rozliší opakovaný sezónní jev od jednorázového výkyvu. Průměrná hodnota vrcholu: spolu s binárními značkami dostává číselnou informaci o průměrném navýšení během vrcholu, takže ví, o kolik kusů typicky navýšit objednávku. Max. hodnota vrcholu: informace o maximálním dosud zaznamenaném vrcholu. Nulové predikce U části sortimentu model tlačil predikce k nule. Položky s velmi nízkým obratem a dlouhými sériemi nul rychle „naučily“ model bezpečné pravidlo → předpovídej stále nulu. Co přesně selhalo: Vyvážení signálu: v datech bylo násobně víc nul než skutečných prodejů, takže model automaticky sklouzl k nulovým predikcím. Chyběl kontext „je to normální“: model nepoznal, že občasný prodej je pro danou položku normální rytmus, nikoli šum. Normalizace potlačila drobné rozdíly: nízké obraty se ztratily mezi položkami s velkým prodejem. Řešení: Tento problém byl jedním z nejtěžších. U některých položek – zejména když se spojí nízké objemy a promo akce – se nulové predikce stále tlačily do popředí. Pomohla až změna normalizačního postupu (individuální přístup pro každou feature) a přidání nových kontextových features. Stáří položky: model teď ví, jak dlouho už se produkt prodává. Novinky mají na pár nul „právo“, zatímco starší položka s dlouhou pauzou už signalizuje útlum. Kdy se naposledy prodalo: kolik měsíců uběhlo od posledního prodeje. Čerstvý prodej ⇒ vyšší pravděpodobnost, že přijde další. Jak se dlouho neprodává: kolik měsíců je položka bez prodeje. Čím delší období, tím opatrněji model předvídá nové kusy. Sezónní měsíc: připomíná, že v daném měsíci se objevil sezónní prodej. Slevové akce Typickým příkladem je drobná elektronika, většinu roku se prodává po jednotkách, ale jakmile e-shop spustí týdenní slevu −20 %, objednávky vyskočí o desítky kusů a po skončení kampaně zase spadnou. V datasetu byli slevové kampaně zastoupeny poměrně často – některé položky je měli i několikrát do roka. Co přesně selhalo: Promo signál se ztratil v davu: po rozšíření datasetu o feature engineering zůstaly jen dvě features přímo spojené s akcí, takže jejich vliv v attention mechanismech modelu výrazně zeslábl. Jinými slovy, v původním datasetu byly promo-indikátory dominantní, nyní se „rozmělnily“ v šumu ostatních vstupů a model je přehlížel. Chyběl kontext kampaně: binární příznak SALE sice říkal „teď běží sleva“, ale už neprozradil, jak dlouho trvá ani kdy naposledy se podobná akce objevila. Stejná váha pro všechny měsíce: z pohledu ztrátové funkce bylo jedno, zda model podstřelil promo-měsíc, nebo běžný měsíc. Řešení: Opět jsem využil feature engineeringu a přidal datasetu nové informace: Poslední sleva: model se naučí, že čím delší pauza od poslední akce, tím větší šance, že další sleva obnoví zájem. Jak dlouho je sleva: druhý signál říká, jak dlouho už aktuální sleva trvá. Aktivita produktu: informace jako je stáří položky, mezery mezi prodeji a kolikrát se položka prodala za poslední rok. Tím se eliminují falešné poplachy u zboží, které se přestalo prodávat. Indikátor slevových měsíců: informace, v jakých měsících se v minulosti vyskytovaly slevy. Jak se změnili metriky Další test jsem tedy provedl již s těmito úpravami. Na první pohled jsou globální rozdíly malé,u některých metrik se výsledky dokonce mírně zhoršily. Je to logické, položky se sezónním, promo nebo sporadickým prodejem tvoří jen zlomek objemu, takže v souhrnných číslech je „převáží“ zbytek sortimentu. Zhoršení je tedy spíše pravděpodobnostní šum než reálný propad kvality. Vizuální kontrola potvrdila zlepšení modelu u predikce problémových položek. Je také potřeba mít na paměti, že jde o stochastický problém – model se při každém tréninku trochu liší. Pokud je nastavení správné, tyto odchylky zůstávají malé — typicky v řádu jednotek procent. Upravit Metrika Predikce Nová predikce Hodnota (ALL) Hodnota (Item) Hodnota (ALL) Hodnota (Item) WAPE 28.4178 42.0787 29.9001 39.1834 RMSE 46.3156 21.1877 52.8141 20.9628 R² 0.9004 0.9072 MAPE 52.4587 59.802 ROBUST 0.4986 59.7858 0.5259 62.4322 STABLE 0.3677 0.3702
Predikce zásob pomocí AI: #6: Extrémy v datech: Další krok k robustní predikci
Predikce zásob pomocí AI 6. Extrémy v datech: Další krok k robustní predikci Proč řešit extrémy – outliers V každém sortimentu se občas objeví jednorázový „výstřel“ – třeba když zákazník koupí stovky kusů do vlastní promo-akce nebo firma vykoupí celý kamion zboží. Tyto objemy jsou reálné, ale neopakovatelné a v běžném měsíci výrazně vyčnívají. Jak na to bude reagovat model? Model se „přitáhne“ k extrému – začne nadměrně naskladňovat položku, která se jinak prodává v jednotkách. Model extrém ignoruje – naučí se, že špička je šum, a tím potlačí i jiné, opravdové sezónní špičky. Model sdílí vzory napříč sortimentem – jeden outlier tak může rozladit celé skupiny zboží. Velké absolutní chyby nafukují metriky (např. RMSE). Graf ukazuje nalezené outlinery nad kompletním datasetem. Je jednoznačně vidět, že i přes vysoký limit na detekci outlinerů jich spousta existuje a jsou výrazně posunuté od průměru. Proto je nutné extrémy detekovat a rozhodnout, co s nimi. Klíčová otázka tedy zní – kde končí „opravdový“ prodej a začíná outlier? Poznámka: V případě běžného nastavení detekce extrémů se již dostáváme na 1000 outlinerů. Jak určiji outlinery? Využívám kombinaci robustního středu (trim-mean), MAD-skóre a percentilového řezu. Prodej, který je současně nad x% percentilem a dál než k × MAD od středu, prohlásím za outlier a oříznu ho na „bezpečný strop“. MAD-score: |x – median| / MADMAD = median absolute deviation Možnosti nastavení: Bez prahu (no outliner cut) – ponecháme extrémy Střední (Medium outliner cut, k ≈ 3-4) – model je více stabilní, , ale riskujeme, že odstranime legitimní sezónní vrcholy. Vysoký (Top outliner cut, k ≈ 8-10) – nechá většinu dat, odfiltruje jen skutečné výjimky; v testech se ukázal jako nejbezpečnější kompromis. Hledání kompromisu Otázka outlinerů je hodně specifické téma. Podle metrik je jednoznačně nejlepší “střední ořez”. Na druhou stranu, toto nastavení ořízně tisíce špiček, může se dotknout i reálných hodnot a ve výsledku může být kontraproduktivní. Upravit Metrika bez ořezu střední ořez vysoký ořez Hodnota (ALL) Hodnota (Item) Hodnota (ALL) Hodnota (Item) Hodnota (ALL) Hodnota (Item) WAPE 30.2608 44.5829 28.8406 42.9816 28.7899 43.5887 RMSE 46.1427 22.3537 48.0208 21.3234 48.2553 21.7787 R² 0.9012 0.9141 0.8904 MAPE 60.0505 58.8268 56.4778 ROBUST 0.4948 62.2027 0.5001 61.8983 0.4874 62.6898 STABLE 0.365 0.3482 0.3718 Rozhodnutí: Po vizuální kontrole jsem zvolil opatrný přístup – řezat jen nejvyšší výstřely. Model tak nepřijde o důležité sezónní signály a metriky sice o chlup ztratí, ale predikce zůstane věrnější reálnému chování zboží. Raději jsem akceptoval o bod vyšší WAPE než riskovat, že „useknu“ polovinu vánoční poptávky. Řídké kategorie Vedle extrémů v obratu (outliners) se v datech objevuje i opačný problém: kategorie jen s několika položkami Proč to škodí modelu? Při tréninku deep-learningu každá kategorie dostává embedding vektor (vektor zobrazuje podobnost mezi kategoriemi). U skupiny jen s několika položkami se vektor učí z prakticky nulového vzorku: nenese smysluplný signál (síť se ho „nenaučí“) rozřeďuje kapacitu modelu – přidává parametry, které nic nepředpovídají zvyšuje riziko přetrénování na jediné položce Řešení Sloučit všechny řídké segmenty do jedné značky, např. unknown Zachovat ostatní, dostatečně početné skupiny beze změny. Embeddingy tak vznikají jen pro kategorie, které mají aspoň několik položek – model dostane méně vektorů, ale informačně bohatší. Navíc se sníží nárok na VRAM. Další nastavení Když už jsem měl data vyčištěná a obohacená o smysluplné features, čekala mě ještě druhá půlka práce — přesvědčit neuronku, aby se učila správným způsobem. V praxi to připomíná nastavování kávovaru: stejná zrna + stejná voda, ale drobné rozdíly v teplotě či tlaku udělají chuťový zázrak. Moderní deep-learningový model má řádově více parametrů než klasické algoritmy a desítky hyperparametrů k ladění. Jejich finální nastavení vždy vychází z charakteru dat (sezónnost, promo, long-tail) a z toho, co chceme reálně získat (minimalizovat vyprodání, zmenšit zásoby, odhadnout nejistotu). Několik základních parametrů: Loss funkce – co považujeme za chybuFunkce, která měří rozdíl mezi odhadem modelu a realitou a říká síti, kam a jak velký krok má při tréninku příště udělat. Optimalizér – jak se model učíAlgoritmus, který na základě spočtené ztráty (loss) a jejích gradientů upravuje hodnoty neuronů, aby byla příští chyba menší. Learning rate – rychlost učeníHodnota o kolik se váhy neuronů při každém kroku skutečně posunou. Size – kapacita modeluPočet neuronů/vrstev určuje, kolik vzorců se model dokáže naučit. Shrnutí – aktuální stav V tomto kroku jsem uzavřel přípravnou fázi a model poprvé otestoval na scénáři 2 33 měsíců historických dat pro trénink 3 měsíce dat pro validaci, které nebyly v tréninku Položky pouze s kompletní historií (36 měsíců) Rozšíření features (feature engineering) Omezení extrémů Upravit Metrika Hodnota (ALL) Hodnota (Item) WAPE 28.4178 42.0787 RMSE 46.3156 21.1877 R² 0.9004 MAPE 52.4587 ROBUST 0.4986 59.7858 STABLE 0.3677 Výsledky potvrzují, že kombinace rozšířených features a kontroly extrémů přináší první reálně použitelné výsledky – predikce jsou stabilnější, a především lépe zachycují trend i absolutní úroveň poptávky. Při vizuální kontrole se však ukázalo, že i po všech těchto úpravách přetrvávají tři specifické typy položek, na kterých model stále tápe: Upravit Typ položky Projevy Proč je to problém Sezónní prodeje 10 měsíců nulový prodej, pak se prodá hodně Model tlumí špičku jako šum Nulové predikce Nepravidelné prodeje, časté nuly Predikce sklouzává k nule Slevové akce Promo zvedá prodej pouze o jednotky % Slevové akce se řádně v predikci neprojeví Graf prezentuje typickou prezentaci sezónního zboží. Model není schopen plně simulovat tuto sezónnost bez další pomoci. U několika typů položek, nejčastěji se jednalo o položky s nízkým obratem a hodně nulami, model neustále predikoval nuly. Tento graf zobrazuje špatnou reakci na slevové akce. Měsíce 34 a 35 byli označeny jako slevová akce (stejně jako v předchozích letech). Model na tyto slevy reagoval velmi vlažně.
Predikce zásob pomocí AI: #5: Feature engineering I, skok v přesnosti
Predikce zásob pomocí AI 5. Feature engineering I, skok v přesnosti Výběr DL modelu V minulém díle padlo rozhodnutí opřít další vývoj o deep-learningové architektury. Aby byly budoucí vizualizace lépe čitelné, budu dál soustředit pozornost především na Temporal Fusion Transformer (TFT). K této volbě mě přivedly tři zásadní argumenty: Škálování s komplexitou – čím bohatší a členitější je datová sada (desítky featur, promo příznaky, sezónnost, relativní ukazatele), tím markantněji TFT překonává ostatní modely. Limity DeepAR u long-tailu – DeepAR má tendenci stahovat položky s nízkým nebo řídkým obratem k nule; tím deformuje plán nákupu pomaloproudých, ale důležitých položek. Attention = inteligentní výběr featur – TFT dokáže automaticky určit, které vstupní sloupce jsou v daném okamžiku klíčové, a zároveň tuto volbu interpretovat. To je při 100+ features nezanedbatelná výhoda. Na začátku se sice zdálo, že model DeepAR dosahuje srovnatelných metrik při nižších výpočetních nárocích, ale jakmile jsme rozšířili vstupy o složitější sezónní, promo a relativní signály, rozdíl se otočil: výkon TFT začal škálovat, zatímco DeepAR narážel na své limity. Scénář 1 – proč je špatně V průběhu dalšího testování se velmi rychle ukázala nevýhoda prvního scénáře – tedy kdy tréninkové a validační data byli shodné. V grafech lze vidět, že Scénáři 1 sleduje predikce pro realitu velmi dobře po celou dobu, protože model měl možnost „budoucnost“ vidět. Jakmile dostal zcela nové 3 měsíce (Scénář 2), rozdíl se projevil velmi rychle. Na posledním grafe se sezónním zboží lze vidět, že model totálně selhával. Upravit Metrika Scenario 1 Scenario 2 Hodnota (ALL) Hodnota (Item) Hodnota (ALL) Hodnota (Item) WAPE 32.1632 45.7959 53.1177 66.9848 RMSE 62.0655 25.2746 83.1493 45.7434 R² 0.8603 0.7754 MAPE 63.9494 95.889 ROBUST 0.4796 66.0129 0.4184 98.0722 STABLE 0.3819 0.4615 Při kontrole výsledků scénáře 2 je vidět, že model vykazuje určitou schopnost predikce, zejména u položek s dlouhou a stabilní historií. Výsledky ale byly stále výrazně pod očekáváním. Ukázalo se, že model zásadně selhává ve třech klíčových oblastech: Položky s nízkým obratem – predikce klesala k nule; riziko předzásobení long-tailu. Promo špičky – bez explicitní informace o slevě modely zvýšený prodej jen částečně reprodukovali. Sezónní cykly – u vysoce sezónních položek modely podhodnocovaly amplitude letních a vánočních vrcholů. Bylo zřejmé, že model potřebuje další vstupy, z nichž vyčte kontext, který v surových číslech chybí – feature engineering. Co jsou to features Při práci s AI nad časovými řadami má každý řádek v datech podobu:Produkt × Časový okamžik (např. položka A v březnu 2024). Vše ostatní na řádku – jako je segment, druh, obrat, cena nazýváme features. Tyto sloupce dávají modelu potřebné souvislosti – pomáhají pochopit chování produktu v čase, jeho podobnost s ostatními a vliv okolních faktorů jako jsou promo akce nebo sezóna. Proč? Holé číslo obratu říká jen kolik se prodalo. Features dodají kontext proč se to stalo: byl srpen, běžela sleva, položka je novinka, zrovna vrcholí sezóna. Díky nim model rozpozná vzorce, které by z čisté řady prodejů nikdy nezískal. Jak model pracuje s features Jak bylo řečeno, v našem datasetu tvoří každý řádek dvojici Produkt (ID) × Měsíc (time_idx).Vše ostatní nazýváme features. Seznam features pro dataset projektuID, seasonality, category, type, segment, segment 1, segment 2, name, turnover, date, time_idx, weight, SALE, SALE_INTENSITY, product_volume__bin 3 typy featuresZákladní rozdělení je na statické a dynamické, tedy jestli se hodnoty mění v čase. Typ zboží je pro všechny měsíce stejný, naopak slevová akce je pouze v několika měsících. Upravit Typ feature Příklad Jak pomáhá modelu Statické Typ, ID, kategorie, segment Síť sdílí vzory napříč sortimentem a pomáhá novinkám, které mají málo historie. Hodnoty jsou stejné pro všechny měsíce. Dynamické známé Kalendář, sleva Hodnoty se mění v každém měsíci, známe je i pro budoucí měsíce. Dynamické neznámé obrat Hodnoty se mění v každém měsíci, neznáme je pro budoucí měsíce. Jedná se většinou o veličiny, které chceme předpovědět. Číselné vs. kategorické Číselné features (obrat, průměry, slevy) – předávají se přímo do modelu Kategorické features (typ zboží, segment) – se převádějí na embeddingy – krátké vektory, které se učí spolu s modelem. Proč embeddings fungují Dva vektory uložené „blízko sebe“ = dvě kategorie, jejichž poptávka se chová podobně. Nový produkt z „nářadí“ tak okamžitě těží z historie „elektro-příslušenství“, pokud je jejich prodejní profil příbuzný. Jaké features jsem použil V této fázi tréninku jsem se zaměřil na features, které pomáhají modelu pochopit vztah mezi obratem v jednotlivých měsících. Každá skupina těchto vstupů doplňuje jiný typ informace: sezónní rytmus, vývoj v čase, vliv promoakcí i relativní chování vůči ostatním položkám. 🗓️ Date-encoding Model nepracuje s měsíci, ale s číselným pořadím (time_idx je 0 – 36). Pomocí těchto features mu tyto vazby identifikujeme. Harmonické kódování měsíce (sin / cos) → model pozná, že po prosinci následuje leden a celý rok se točí v cyklu. Pomůže zachytit periodické vztahy v prodeji (kvartály, roky, letní sezóna) 📊 Relativní (poměrové) features Určí odchylku nebo podíl prodeje vůči širšímu celku (průměr skupiny, maximum sezóny, long-term trend …). Model tak snadno pozná, kdy je položka nad nebo pod svým normálem a rychleji reaguje na nečekané výkyvy. 🌀 Lag & Rolling okna Předá podrobnou informaci, jaký byl nedávný vývoj. Pomáhá rychleji zachytit momentum (zpomaluje se nebo zrychluje prodej). Rolling mean / std odfiltrují šum a ukážou, zda je aktuální prodej nad / pod svým klouzavým průměrem. 🌊 Wavelet signály Rozloží křivku na krátké vlnky vs. dlouhé trendy. Síť tak vidí jemné promo skoky i pomalé, víceleté cykly najednou. 📈 Trend Doplní směr a sklon prodeje. Informace o kolísání prodeje kolem svého průměru. 🔢 Absolutní i log-hodnoty Většinu features jsem vytvořil jak v absolutních hodnotách, tak i v logaritmické hodnotě. Proč logaritmus? Zkomprimuje extrémy → nezadusí malé položky. Stabilizuje rozptyl, křivky jsou blíž normálu → model se učí rychleji. Převádí poměrové skoky (×2, ×3) na lineární posun, který model snadno zachytí. Výsledek Pomocí této kombinaci vstupů model nejen předpovídá obrat, ale chápe i kontext jednotlivých měsíců: co je běžný trend, co je výkyv, a co znamená promo. Po sérii iterací jsem skončil na cca 75 featurách — tato sada přinesla největší zlepšení metrik vůči nárokům na čas a
Predikce zásob pomocí AI: #4: Referenční modely vs DeepLearning
Predikce zásob pomocí AI 4. Referenční modely vs DeepLearning Proč začít u klasických ML modelů Rychlý reality-check – Základní algoritmy se trénují v řádu minut a okamžitě odhalí, zda v datech není zásadní problém (chybný kalendář, duplikované řádky apod.). Referenční laťka – Jakmile známe výkon lineární regrese či rozhodovacího stromu, můžeme přesně vyčíslit, o kolik se musí zlepšit deep-learning, aby jeho nasazení dávalo ekonomický smysl. Transparentnost – Jednodušší modely se lépe vysvětlují; pomáhají porozumět vztahu mezi vstupy a výstupy ještě před nasazením komplexnější architektury. Upravit Referenční modely Jak fungují LR – Linear Regression Umí zachytit jednoduchý rostoucí / klesající trend. Jakmile jsou data složitější, rychle ztrácí přesnost. DT – Decision Tree Umí složitější křivky a nelinearity, ale pokud strom nechám růst moc hluboko, začne být přetrénovaný – opakuje se. FR – Random Forest Zprůměruje chyby jednotlivých stromů → stabilnější než jeden strom, ovšem náročnější na paměť a pomalejší při velkém počtu položek. XGB – XGBoost Regressor Často nejlepší z klasických ML – umí zachytit složité vztahy i bez složitého ručního ladění. GBR – Gradient Boosting Regressor Hodí se jako levné srovnání: když selže i on, data jsou opravdu náročná. Jak vypadá vizualizace 4 položek, predikce na 12 měsíců? Deep-learningové architektury, které jsem nasadil? Pro porovnání jsem vytvořil 3 základní DL modely. Ve všech případech se jedná o AI modely pro časové řady, jestliže referenční modely patřili k tomu jednoduššímu, tak tyto patří k tomu komplexnějšímu. Upravit DL algoritmus Jak funguje Výhody/nevýhody DeepAR (autoregresivní LSTM) Učí se z podobných položek, při predikci generuje celé pravděpodobnostní rozmezí poptávky ⇒ vidíme optimistický i pesimistický scénář prodejů Novinky, long-tail, při spoustě nul a extrémů má tendenci křivku „vyhlazovat“. TFT (Temporal Fusion Transformer) Výborný na komplexní scénáře, sám si vybere, která informace je důležitá, umí výběr vysvětlit. Komplexní datové sady s mnoha externími signály, potřebuje hodně dat, trénink je časově náročný. N-HiTS (Hierarchical Interpolation) Rozloží sérii na víc časových hladin (roky / měsíce / týdny), na každé vrství vlastní malou síť — nakonec je složí zpět. Dlouhé predikční horizonty a potřeba rychlých výpočtů, vyžaduje pravidelný časový krok. Proč tyto komlexní modely? Vytěží jemné i dlouhé sezónní vzorce a promo efekty, které klasická ML přehlédne. Sdílejí znalost napříč sortimentem — pomáhají novinkám i položkám s krátkou historií. Vracejí interval nejistoty, takže nákupčí dostává doporučení „kolik objednat v optimistickém a pesimistickém scénáři“. Jak vypadá vizualizace 4 položek, predikce na 12 měsíců u DL modelů? Výsledky Testování jsem prováděl pouze při scénáři 1, tedy validace i trénink probíhala na stejném datasetu. Použil jsem 5000 položek zboží, pouze s plnou historií 36 měsíců. Klasické modely dávají prvotní orientaci, ale ani ty nejlepší z nich se nepřibližují cílové přesnosti. Deep-learning přináší skokové zlepšení — už v základní konfiguraci snižuje chybu na polovinu či třetinu. To je rozhodující signál, že má smysl investovat čas do ladění featur, hyper-parametrů a produkčního nasazení. Metriky porovnávající ML a DL modely. Pokročilé metriky pro validaci jsem začal používat až později. Upravit ML – referenční modely Metrika R² WAPE RMSE MAPE GBR 0.4259 124.9833 173.599 275.8702 FR 0.3444 133.5684 157.6839 217.063 DT 0.2529 142.5767 165.8517 212.5132 XGB 0.2153 146.125 168.5045 266.1286 LR 0.0745 158.6966 200.3072 477.9817 Upravit DeepLearning modely Metrika R² WAPE RMSE MAPE DeepAR 0.847 53.615 62.8242 188.5804 TFT 0.3901 30.2255 125.4162 141.6336 NHiTS 0.432 206.9327 121.0321 382.6455 Test číslo 2 – Encoder vs Decoder V předchozí fázi jsem si ověřil, že hlubší (DL) architektury skutečně výrazně převyšují klasické ML. Než jsem se pustil do ladění parametrů typu loss, optimizer nebo drop-out (které zde nebudu rozebírat), je nutné dobře porozumět architektuře encoder–decoder, která v modelech pro časové řady je klíčovou komponentou a určuje, kolik minulosti model „čte“ a jak dlouho do budoucna predikuje. Encoder: Říká, jak dlouhý úsek minulosti model použije pro vytvoření jedné konkrétní předpovědi. Analogie nákupčího, který se dívá např. na posledních 12 měsíců historie. Decoder: Pohled do budoucnosti – na základě informací od encoderu vygeneruje predikce. Architektura ale na rozdíl od nákupčího vytvoří při tréninku několik predikcí (klouzavá okna) pro každé zboží. Mám-li 36 měsíců historie, chci aby se model koukal na posledních 18 měsíců a predikoval 3 měsíce, pak při tréninku se vytvoří 18 klouzavých oken nad těmito měsíci: Upravit Encoder Decoder 0-18 19-21 1-19 20-22 … … 17-35 36-38 Tříletá historie tak vytváří 18 tréninkových scénářů pro každou položku; model vidí všechny možné přechody (zima → jaro, vánoce → leden apod.). Hlavní rozdíl a vliv na chování modelu:Jaký je rozdíl při nastavení délky encoderu 18 a 30 měsíců? Klíčový rozdíl je v tom, jaké typy vzorců se model naučí a na co bude klást důraz. Je to klasický kompromis mezi flexibilitou a stabilitou. Upravit Encoder_length = 18 Encoder_length = 30 Lepší adaptace na změny: Model rychleji zareaguje, na náhlé změny na trhu (trend, promo) Dobrý v dlouhodobé sezónnosti: Lépe rozpozná opakující se vzorce a pomalé dlouhodobé trendy. Více tréninkových oken: Rychlejší učení, menší riziko přetrénování u položek s krátkou historií. Stabilnější predikce: Robustnější k výkyvům v posledních měsících Nižší paměťové a časové nároky: rychlejší inference. Méně tréninkových oken: Delší trénink, vyšší riziko přetrénování, pokud dat není dost. Hůře vidí sezónní cykly: Model nemusí plně pochopit vzorce, které se opakují ve víceletých cyklech. Pomalejší reakce na změny: trvá déle se adaptovat na náhlé změny na trhu (trendy, proma) Sezónní paměť: Větší riziko, že vánoční špičku z minulosti úplně „zapomene“. Vyšší paměťové a časové nároky Jak tedy vybrat? Neexistuje univerzálně nejlepší volba. V praxi jsem testoval 12 / 18 / 24 / 30 měsíců a jako nejvyváženější se ukázal encoder = 18 měsíců, decoder = 3 měsíce. Ten nabízí dost historie, přitom generuje velký počet tréninkových oken a dobře reaguje na krátkodobé změny trhu.
Predikce zásob pomocí AI: #3: Jak to validovat
Predikce zásob pomocí AI 3. Jak to validovat Základní otázka před jakýmkoliv tréninkem Smyslem validace je ověřit, jak si model poradí s daty, která nikdy neviděl – stejně, jako v reálném provozu. Proto je nutné dataset rozdělit na dvě části: Tréninková data – na nich se model učí. Validační (testovací) data – na nich se kontroluje, co model opravdu umí. Ale kde stanovit hranici?Chtěl jsem modelu poskytnout všechny možné informace – všechny SKU a všech 36 měsíců – abych zachytil co nejvíce vzorců. Část časové osy však musela zůstat skrytá; jinak by si síť jednoduše zapamatovala historii a v realitě se zhroutila. Řešení? Vytvořil jsem tři validační scénáře, které postupně zvyšují přísnost: od „rychlé zkoušky“ (model validuje pouze na datech, jež už viděl) až po ostrý test jen na opravdu neviděných měsících. 3 scénáře validace Scénář 1: Pro základní testování jsem nejprve použil validaci nad stejným datasetem jako byl trénink (tj. celé období 36 měsíců). Cílem bylo ověřit, jestli je model vůbec schopen najít vzory a predikovat hodnoty, které už viděl (je zde riziko přetrénování modelu). Scénář 2: Trénink na omezené historii (33 měsíců), validaci na posledních 6 měsících (3+3, 3 měsíce, které model při tréninku viděl a 3 nové měsíce).Tento postup už mnohem lépe simuluje reálné nasazení: model nejprve „projde historií“, naučí se z ní vzory a teprve poté predikuje nové, neznámé období. Díky tomu lze: Prověřit schopnost generalizace – jestli model umí správně extrapolovat trend, nebo jen opakuje to, co už zná. Odhalit posun v sezonních vzorcích – například zda si poradí s vánoční špičkou či jinými vzory. Odhalit vliv sale akcí – jestli výsledné predikce jsou ovlivněny plánovanými slevovými akcemi Citlivost na nové položky – poslední měsíce často obsahují zboží s krátkou historií; validace tak rovnou ukáže, jak si model poradí se sortimentem, který se průběžně mění. Scénář 3: Stejný trénink jako ve Scénáři 2, Validace = pouze poslední 3 měsíce (tedy data která neviděl). Tento scénář jsem používal jako kontrolní validaci.Až když jsem byl s výsledky spokojený, natrénoval jsem finální verzi na celém datasetu (bez vyčleněné validace), aby model využil 100 % dostupných dat pro ostré nasazení ve skladu. Poznámka: Všechny metriky a grafy, které dál v článku ukazuji, pocházejí ze Scénáře 2 (pokud výslovně neuvedu jinak). Metriky jsou tedy počítány na posledních 3+3 měsíců. Vizualizace pro názornost zobrazuje 12 měsíců. Následující graf ukazuje rozdíl mezi scénářem 1 a 2. Červený graf ukazuje Scénář 1, tedy kdy model při tréninku viděl všechny výsledky. Zelený graf je Scénář 2, kdy poslední 3 měsíce nebyly součástí tréninku. Je zřejmé, že je nutné do validací zahrnout hned od začátku neviděná data. Jakou metriku tedy vybrat, když není technicky možné ručně zkontrolovat každé zboží?V praxi je běžné používat například R², RMSE nebo MAPE – proč tedy vůbec vymýšlet něco jiného? Zásadním problémem je existence nul a vysoká variabilita hodnot. Proč jsou nuly problém? Představte si, že model predikuje pro daný měsíc obrat 2 kusy, zatímco reálný prodej byl nula. Zdánlivě chyba jen 2 kusy, ale pokud použijeme procentuální metriku (například MAPE), vyjde nesmyslně vysoká chyba, protože se dělí nulou nebo velmi malým číslem. Podobně je tomu u RMSE – pár „menších” odchylek na položkách s velkými prodeji může nafouknout celkovou chybu a zcela zastřít výkon modelu na hlavních položkách. Proč je vysoká variabilita hodnot problém? Upravit Příklad položky Reálný obrat Predikovaný obrat Absolutní chyba Relativní chyba A (nízký obrat) 5 ks 8 ks 3 ks 60% B (vysoký obrat) 5 000 ks 4 800 ks 200 ks –4 % MAPE bude vysoké kvůli položce A (60 %), i když reálně jde o ±3 kusy. RMSE naopak zvýrazní položku B (200 ks), protože je výrazně citlivý na velké absolutní chyby. R² může vypadat výborně (99 % rozptylu vysvětleno) díky položkám s vysokými prodeji, ale pro „malé“ položky je tato metrika často málo vypovídající. Jedna metrika nestačí. Vysoká variabilita položek, hodně nulových a malých položek. Musel jsem přistoupit ke kombinaci více metrik. Upravit Metrika Co vlastně měří Poznámka Cíl WAPE (Vážená procentní chyba) Kolik % celkových prodejů model „netrefil“. Citlivost na sortiment s nulovým obratem. ⬇️ RMSE (Prům. absolutní chyba) O kolik kusů se v průměru netrefíme. Citlivost na sortiment s velkými obraty. ⬇️ R² (Koeficient určení) Jak velkou část pohybů v prodejích model správně „vysvětluje“. Hodně ovlivněn velkými obraty. ⬆️ MAPE (Průměrná absolutní procentuální chyba) Průměrná procentní chyba každé položky. Citlivost na sortiment s nízkými obraty. ⬇️ Robust score Kombinace přesnosti, kontroly odchylek a shodu směru trendu. (1 = skvělé, 0 = špatné) Zachytí stoupající/klesající trend. ⬆️ Stable score WAPE + kontrola odchylek a relativní chyby u drobných prodejů. (nižší = lepší) Zajišťuje, že predikce je hladká a stabilní měsíc po měsíci a není náchylná na sortiment s malými obraty. ⬇️ Cíl označuje, jaké hodnoty potřebujeme (nízké ⬇️ nebo vysoké ⬆️). Jako hlavní metriky používám WAPE, RMSE a R². MAPE metrika není vhodná pro variabilní položky. Robust a Stable používám zejména pro ověření základní koncepce modelů. Pro drobné ladění se tyto hodnoty výrazně nemění. Moc jednoduché? V průběhu tréninku jsem narazil na další problém v aplikaci metrik. Standardní metriky přes celý dataset jsou velmi vypovídající, ale neupozorňují na odchylky u jednotlivých položek. Z toho důvodu jsem rozšířil použité metriky na: Upravit Verze metriky Jak se počítá Na co odpovídá Výpočet za celý dataset Hodnoty ze všech položek se sloučí do jednoho vektoru a z něj spočítám metriky. Kolik kusů se netrefí v celkovém objemu? Tedy finanční dopad na skladové zásoby. Výpočet po položkách Metrika se spočte pro každé zboží zvlášť, potom se z těchto čísel udělám průměr. Jak přesná predikce je u typického produktu? – tedy kvalita napříč celým sortimentem. Příklad vypočtených metrik nad modelem s 2 vrstvami neuronových sítí a softplus normalizatorem. Významné jsou zde rozdíly mezi metrikami WAPE a MAPE. Druhá tabulka ukazuje správně natrénovaný model. Upravit Metrika Hodnota (ALL) Hodnota (Item) WAPE 50.1925 387.2097 RMSE 69.0821 31.4245 R² 0.6239 MAPE 107.1253 ROBUST 0.455 207.7031 STABLE 0.5869 Upravit Metrika Hodnota (ALL) Hodnota (Item) WAPE 31.1611 44.6504 RMSE 50.2607 26.5974 R² 0.9084 MAPE 75.7044 ROBUST 0.5226 84.916 STABLE 0.3901
Predikce zásob pomocí AI: #2: Struktura dat a první analýza
Predikce zásob pomocí AI 2. Struktura dat a první analýza První pohled na data Vstupní data jsem od zákazníka obdržel ve formátu textových výstupů – tedy jako CSV soubory. Integraci přímo do firemních systémů jsem v této fázi záměrně neřešili; cílem bylo ověřit funkčnost AI modelu nad daty. Každý řádek v souborech představoval jeden produkt v daném období a obsahoval informace: Unikátní identifikátor produktu (stejný ve všech souborech) Sezónnost, kategorii, druh a segment zboží Popis rozdělení na subkategorie Měrnou jednotku a podrobný popis zboží Historii za posledních 36 měsíců Obrat (v jednotkách i v měně) Množství objednaného zboží Termíny a označení promo akcí Celkově šlo přibližně o 15 000 různých položek. Základním časovým indexem byl měsíc, což umožňuje sledovat vývoj prodejů i skladových zásob v čase. Už při prvním pohledu bylo jasné, že data nejsou kompletní a obsahují celou řadu nesrovnalostí: Chybějící historie prodejů: U mnoha produktů zcela chyběla část nebo celá historie, typicky se to týkalo nových či výrazně sezónních položek. Záporné prodeje: některé záznamy vykazovaly záporné hodnoty prodejů, často šlo o vratky, storna nebo chyby v zadání. Nesoulad v jednotkách: Různé typy jednotek významně ovlivňují interpretaci obratů a prodejů (například kusy vs. gramy, jednotky vs. tisíce) Duplicitní záznamy: některé položky se objevily opakovaně se stejnými nebo lehce odlišnými parametry. Trvání promo akcí: Promo akce byly v datech zaznamenány v počtu dnů, zatímco prodeje byly evidovány měsíčně. Různá délka historie: Zatímco některé produkty měly tříletou historii, u části zboží byla k dispozici jen data za několik měsíců. Chybějící data: Chybějící datumy, kategorie, apod. První graf (boxplot) ukazuje rozložení obratů produktů napříč celým datasetem (logaritmicky transformovaných), druhý graf (histogram) ukazuje četnost jednotlivých obratů. Medián log(obratu) je přibližně 3,5, což odpovídá typickému obratu kolem 33 kusů za měsíc. Většina produktů má hodnotu v intervalu 2,2 – 4,2 (tedy zhruba 9 až 67 kusů za měsíc), ale v datech najdeme i několik položek s výrazně vyššími obraty – outlinery od 7.3 (1480 kusů). Je vidět, že velké množství produktů má nulový nebo velmi nízký obrat (vlevo), zatímco nejvyšší hustota prodejů je mezi hodnotami log(obratu) 2–4, což odpovídá rozmezí 7 až 55 jednotek měsíčně. Na pravé straně histogramu se nachází pouze malá skupina produktů s opravdu vysokým obratem – jedná se o výjimky, které ale významně ovlivňují celkový objem prodejů. Import dat a čištění Než bylo možné začít s trénováním predikčního modelu, bylo nezbytné data důkladně připravit a vyčistit. Právě tato fáze je v AI projektech často časově nejnáročnější a významně ovlivňuje kvalitu výsledků. Chybějící historie prodejůJedním z hlavních problémů byla neúplná historie prodejů.V některých případech skladový systém exportoval nulu jako prázdnou hodnotu, jindy zboží v daném měsíci vůbec neexistovalo, a proto byl obrat také prázdný.Aby model správně rozlišil, kdy je nulový obrat skutečně nulou (zboží existovalo, ale neprodalo se), a kdy jde o položku, která v daném měsíci na skladě ještě nebyla, vytvořil jsem nový sloupec –weight – označující existenci zboží v daném období. Záporné prodejeV datech od zákazníka se objevily záporné hodnoty prodejů – tyto situace byly způsobeny vratkami zboží. Po dohodě byly tyto hodnoty převedeny na nulu, aby model nebyl těmito anomáliemi ovlivněn. Nesoulad v jednotkáchDalší výzvou byl nesoulad v měrných jednotkách – model musí umět pracovat s jednotkami přesně tak, jak je eviduje zákazník. Sjednocení jednotek napříč sortimentem nebylo možné, proto bylo klíčové naučit model škálovat a správně interpretovat hodnoty i v případě rozdílných objemů (jednotky vs tisíce). Trvání promo akcíKromě základních údajů obsahovala data i informace o promo akcích v konkrétních dnech. Zatímco obraty byly evidovány měsíčně, promo akce byli ve dnech a přesahovaly mezi měsíci. Proto byl vytvořen nový sloupec, který popisuje procentuální platnost proma v každém měsíci – promo trvalo 50% měsíce. Různá délka historieNěkteré produkty měly pouze krátkou historii, protože vznikly až v průběhu analyzovaného období. Pro zachování konzistence dat bylo třeba, aby všechny položky měly stejně dlouhou časovou osu – i zde byl využit sloupec weight pro existenci zboží, který pomohl správně označit období, kdy položka ještě neexistovala. Duplicitní záznamy a chybějící dataVe spolupráci se zákazníkem byla data dále dočištěna – byly odstraněny duplicity i další chybějící hodnoty tak, aby co nejméně negativně ovlivňovaly trénování modelu. Výsledná struktura Data byla následně převedena do tzv. „long“ formátu, kde každý řádek představuje jednu kombinaci zboží a měsíce. Výsledný dataset zahrnoval cca 15 000 položek zboží a přes půl milionu řádků. Seznam sloupců ve výsledném datasetuNa seznamu níže je vidět struktura připraveného datasetu ve formátu „long“.Dataset obsahuje nejen základní identifikátory a obchodní informace, ale i několik doplňujících a speciálně vytvořených sloupců, které jsou klíčové pro správné fungování modelu (-weight-, –time_idx-). ID, seasonality, category, type, segment, unit, name, turnover, price, ordered, date, time_idx, weight, SALE, SALE_INTENSITY První analýzy a objevené vzory Hlavním cílem projektu byla predikce skladových zásob. Po detailní analýze dat a zhodnocení reálných možností se však ukázalo jako nejvhodnější predikovat nejprve obrat (tedy předpokládaný prodej) každého zboží. Na základě těchto predikcí pak bude možné pomocí běžných logistických postupů a pravidel (např. min/max sklad, dodací lhůty, pojistné zásoby) dopočítat optimální množství zásob pro každý měsíc. Klíčová rozhodnutí při analýze dat Po hlubší analýze jsem dospěl k rozhodnutí, že některé sloupce nebudou použity pro trénink modelů, protože nemají přímý vliv na obrat zboží: Cena: Prodejní cena v daných podmínkách neměla přímý vliv na objem prodejů. Objednáno: Kvalita dodavatelů a doba dodání ovlivňuje zásoby, ale nikoliv samotný obrat – tyto proměnné se tedy využijí až ve druhém kroku, při dopočtu optimálních zásob. Položka Segment: Tato proměnná popisovala tříúrovňové rozdělení zboží do různých segmentů. Pro co nejkomplexnější informaci jsem do datasetu zahrnul všechny úrovně segmentace, tedy „Segment“, „Segment 1“ a „Segment 2“. Upravit Segment number ID mean_target std_target var_target AA-BB-UU 91 20.925 44.316 2 001.933 AA-EE-DD 89 54.869 70.83 5 114.107 AA-GG-LL 88 26.011 33.747 1 160.926 AA-AA-SS 89 84.013 173.254 30 598.405 XX-WW-TT 91 50.484 89.99 8 255.076 GG-PP-AA 86 28.943 40.32 1 657.201 DD-GG-VV 85 4.494 5.227 27.855 HH-EE-RR 81 12.802 11.232 128.596 AA-DD-OO 79 21.321 36.809 1 381.121 BB-WW-TT 77 90.052 141.141 20 306.666 Upravit Segment2 number ID mean_target std_target var_target DD 2645 32.412 169.623 29
Predikce zásob pomocí AI: #1. Zadání & úvod do projektu
Predikce zásob pomocí AI 1. Zadání & úvod do projektu „Správné plánování zásob je problém, který řeší nejen velké firmy, ale i menší a střední podniky napříč obory. A právě jim dnes AI otevírá úplně nové možnosti.“ Po třech letech intenzivního studia AI jsem se rozhodl pustit do vlastního projektu: aplikace Deep Learningu pro predikci skladových zásob. Proč právě toto téma? Oslovil mě známý s otázkou, zda by umělá inteligence mohla vyřešit problém s plánováním skladových zásob ve velkoobchodu.Ukázalo se, že správa zásob je nikdy nekončící úkol – je těžké najít rovnováhu mezi přezásobením a rizikem, že zboží dojde v ten nejméně vhodný okamžik. Navíc vstupuje do hry řada proměnných, které se v čase mění. Jak číst tuto sérii Cílem této série je přiblížit svět predikce skladových zásob lidem z businessu – tedy těm, kteří skutečně řeší každodenní provoz a plánování zásob, a zároveň chtějí vědět, jak jim může AI a moderní data pomoci v praxi. Nebudu se zde pouštět do technických detailů, budu se soustředit na konkrétní situace a problémy, které tato problematika obnáší. Vždy představím reálný problém, ukážu jsem ho řešil, a vše doložím na konkrétním příkladu nebo grafu – aby si každý mohl udělat jasnou představu, co AI v logistice (ne)umí a proč. Mým cílem je, aby si v sérii našli své jak manažeři, kteří chtějí vědět, jak AI může pomoci v byznysu, tak i analytici, kteří se chtějí dozvědět, jak konkrétní rozhodnutí a zpracování dat ovlivňuje výsledky predikcí v praxi. Veškerá data vycházejí z reálných projektů, jsou ale anonymizovaná. Série bude vycházet postupně, jak budu mít nové poznatky a zajímavé příklady z praxe. Popis problému Nízké desítky tisíc různých SKU Rozdělení podle sezónnosti, kategorie, druhu i segmentu Každý měsíc vznikají i zanikají desítky položek Slevové akce Skladové zásoby se predikují ručně, v kompetenci nákupčích Definice cíle Najít mechanismus, který bude: Sledovat aktuální skladové zásoby Predikovat budoucí prodeje Zohledňovat další parametry: dodací lhůty (lead time), spolehlivost dodávek, promo akce, apod. Doporučovat kolik zboží objednat a nastavovat min/max zásoby automatizovaně Prodejní obraty pro různé produkty (SKU): Každá linie představuje vývoj prodejů konkrétního produktu v období 24 měsíců. Je dobře vidět, že jednotlivé položky se liší jak objemem prodejů, tak sezonními výkyvy a obdobími bez prodeje. Tyto rozdíly v chování produktů ilustrují, proč je predikce skladových zásob tak náročná – a proč vyžaduje mnohem sofistikovanější přístup než jednoduchý průměr či extrapolace minulých výsledků. Zadání projektu Abychom tento cíl mohli naplnit, bylo nutné jasně stanovit, jaké konkrétní požadavky, omezení a rizika bude projekt zahrnovat. Automaticky nastaví každý měsíc doporučené min/max zásoby pro každou položku Bude zohledňovat parametry: Produktové rozdělení Akční prodeje Sezónnost Historie prodejů Podobnosti mezi zbožím Nové položky Finančně dostupné řešení Možnost si model otestovat model na vlastních datech Rizika projektu Od začátku bylo jasné, že model bude čelit celé řadě výzev: Jednorázové extrémy v prodejích (např. nečekané hromadné objednávky) Proměnlivost sortimentu (každý rok zanikají i vznikají desítky položek, sortiment se vyvíjí Různá délka historie položek (novinky a zboží s dlouhou historií) Nulové obraty (dlouhá období bez prodejů, nárazové obnovení poptávky) Velké rozdíly v objemech prodejů (od kusových položek po tisícové objemy) Závislost mezi produkty(prodej jednoho produktu ovlivňuje poptávku po jiném Vliv sezónnosti a plánovaných akcí Cílem projektu tedy nebylo pouze vytvořit model, který dokáže předpovědět běžnou poptávku, ale především takový, který si poradí i s těmito specifickými a často velmi obtížně předvídatelnými situacemi. Tabulka historie zbožíukazuje, jak různorodá byla délka dostupné historie u jednotlivých produktů. Zatímco většina produktů měla kompletní tříletou historii, významná část sortimentu měla jen omezená nebo žádná historická data – což představovalo zásadní problém pro tradiční predikční modely. Řešení – ve zkratce Mnoho firem si myslí, že stačí nakrmit AI daty a výsledek přijde sám. Jak ukázal tento projekt, realita je daleko složitější. První testy ukázaly, že ani moderní deep learning modely (bez úprav) nestačí – narážely na velkou variabilitu sortimentu, množství nulových prodejů a časté změny v sortimentu.Projekt se proto postupně rozšiřoval – bylo třeba: Vylepšit přípravu dat (feature engineering) Naučit modely pracovat s extrémy Řešit různé délky historie Dynamicky škálovat vstupy Dnes model zvládá většinu komplikací automaticky a bez nutnosti ručních zásahů. Výsledek Upravit Metrika Hodnota Význam pro byznys Přesnost predikce 80% Jak dobře model odhadl budoucí prodeje Prům. odchylka 48 Průměrná rozdílnost mezi predikcí a realitou Prům velikost chyby 31 Průměrná „velikost chyby“ v počtech prodaných kusů Hlavní přednosti řešení Predikce s přesností přes 80 % napříč sortimentem Model vychází z individuální historie i skupinového chování podobných produktů Zvláštní důraz jna akční/promo položky Predikce i pro nově zavedené položky s minimální historií Schopnost reagovat na sezónnost i krátkodobé trendy Automatizované výstupy pro celý sortiment Možnost škálování a opakovaného využití Řešení lze přizpůsobit dalším zákazníkům, většina algoritmů a klíčových funkcí je předdefinovaná a znovupoužitelná. Stále je sice potřeba odborná znalost při úvodní konfiguraci a interpretaci výsledků, ale samotné nasazení a validace modelu jsou výrazně rychlejší než při vývoji na míru. Predikce vs. realita – vizuální výsledky:Je dobře vidět, že model dokáže zachytit hlavní trendy i sezónní výkyvy v prodejích – a to i u položek s proměnlivou historií nebo nepravidelnými extrémy. Zároveň se ukazuje, že i při pokročilé predikci zůstává v datech určitá míra nejistoty, například při neobvyklých špičkách nebo poklesech. Jak predikci ovlivňuje délka historie, ostatní položky v sortimentu, sezónnost nebo promo akce, se budu podrobněji věnovat v dalších dílech této série. Technologické zázemí projektu Celý projekt jsem postavil na frameworku PyTorch, který patří mezi nejpoužívanější open-source platformy pro deep learning. Trénování probíhalo na GPU kartě NVIDIA RTX 3090 s 24 GB paměti, což umožnilo efektivně zpracovávat i velmi rozsáhlá data a testovat různé scénáře, včetně modelů se stovkami milionů parametrů, a to bez výrazných časových prodlev. Infrastruktura běžela na Kubernetes, díky čemuž je řešení snadno škálovatelné i přenosné – lze jej spustit jak u zákazníka „on-premise“, tak v cloudu, podle aktuálních potřeb a požadavků.