Experimenty Azure Machine Learning


Trochu jiný pohled na Azure Machine Learning a vytvoření nového experimentu, včetně potřebné teorie, sepsal Lukáš Beran (https://www.lukasberan.cz/).

Martin


Úvod

Microsoft Azure pravděpodobně není nutné hluboce představovat. Jedná se o cloudovou platformu v tom nejširším slova smyslu naplňující vizi společnosti Microsoft – mobile-first, cloud-first. Služba Machine Learning patří k nejnovějším přírůstkům do rozsáhlé nabídky služeb Microsoft Azure. Azure Machine Learning (dále jen Azure ML) nabízí techniky strojového učení, které svou jednoduchostí a kvalitně zpracovanou dokumentací uspokojí jak běžné uživatele se základní znalostí statistiky a strojového učení, tak i náročné firemní zákazníky, kteří mohou využít například podporu jazyka R nebo Python, garantovanou dostupnost (SLA) nebo technickou podporu.

Teorie strojového učení

Strojové učení je technika, která (nejen) v poslední době prožívá velký rozmach. Jednoduše řečeno, strojové učení převádí datasety do částí software, které jsou známé jako modely. Tyto modely reprezentují datasety, zobecňují je a vytváří pomocí nich predikce nových dat. Tyto techniky využívá na například vyhledávač Bing.

Na strojovém učení jsou založeny i například bezpečnostní produkty nebo filtry spamu, které se stále učí nová pravidla rozpoznávání a třídění. Strojové učení se používá také pro detekce anomálií nebo chyb, velmi efektivní filtry šumu, rozpoznávání obrazu nebo stále populárnější virtuální osobní asistenty jako například Cortana od společnosti Microsoft.

Výše uvedené příklady jsou ale jen zlomkem toho, kde všude se strojové učení používá. Obecně lze strojové učení rozdělit do tří kategorií:

  1. Data Mining, kde strojové učení slouží pro získání poznatků a závislostí z rozsáhlých databází.
  2. Statistical Engineering, kde strojové učení slouží pro převod dat na software, který poté může tvořit rozhodovací mechanismy nad neúplnými daty.
  3. Artificial Intelligence, kde strojové učení slouží pro emulaci lidského myšlení, díky čemuž mohou počítače „vidět, slyšet, a chápat“.

Strojové učení ovšem není jednoduchá technika. Obvykle vyžaduje složitý software, výkonné počítače a zkušené vědce, kteří dané problematice rozumí a dokáží s ní správně pracovat. Z tohoto důvodu může být pro firmy nebo jednotlivce velmi nevýhodné budovat si strojové učení vlastními silami, ale mnohem výhodnější, rychlejší a jednodušší může být pronajmout si strojové učení jako službu.

Strojové učení ve společnosti Microsoft

Protože služba Azure ML je relativně nová, mohlo by se zdát, že v Microsoftu nemají dlouhodobější zkušenosti se strojovým učením v širším nasazení. Opak je ovšem pravdou. Ve společnosti Microsoft se technikám strojového učení věnují již více než 20 let, což dává společnosti Microsoft a jeho službě Azure ML velkou konkurenční výhodu.

První principy strojového učení se ve společnosti Microsoft datují do roku 1992, kdy začali pracovat s Bayesian Networks na modelování přirozené řeči a rozpoznávání hlasu. Díky tomu již v průběhu 90. let minulého století zjistili, že mnoho problémů, jako jsou kategorizace textu nebo priorizace e-mailu, jsou řešitelné pomocí kombinace lineární klasifikace a Bayesových sítí. Výsledkem byl první detektor spamu založený na analýze obsahu e-mailu.

Další rozvíjení algoritmů strojového učení přineslo možnosti v podobě počítačového vidění nebo širšího uplatnění rozpoznávání hlasu. Rozhodovací stromy byly použity například při provádění pixel-wise klasifikace pro odhady lidské pózy, kterou využívá i senzor Kinect u herních konzolí Xbox.

Machine Learning Studio

Velkou výhodou Azure ML je jeho jednoduchost, protože umožňuje i lidem bez hlubších znalostí analýzy dat tvořit předpovědi. Machine Learning Studio používá k vytvoření experimentů gesta přetažení (drag&drop) a jednoduché grafy toku dat. Díky tomu je možné mnoho úloh zadávat bez jediného řádku kódu. Kromě toho obsahuje ML Studio i knihovnu ukázkových experimentů a algoritmů přímo z Microsoft Research.

Aby však byl Azure ML použitelný i pro vědce a odborníky, je podporován jazyk R s více než 350 předinstalovanými balíčky, a jazyk Python.

Experimenty umožňují sdílení a spolupráci, díky čemuž může více uživatelů spolupracovat na experimentu a sledovat jeho výsledky. Experimenty je možné sdílet s veřejností prostřednictvím Azure Machine Learning galerie, kde je možné najít mnoho již publikovaných experimentů ostatních uživatelů.

Data do ML Studia mohou být nahrána z lokálních souborů v počítači (podporované formáty CSV, TSV, TXT, SvmLight, ARFF, ZIP nebo RData), případně načtena pomocí modulu Reader, který umí číst data z Azure Table, Azure Blob Storage, Azure SQL Database, Hive Query, Data Feed Provider (OData) nebo pomocí http (CSV, TSV, ARFF a SvmLight).

Pro přístup k experimentům například z vlastního webu nebo aplikace slouží přístupové API podporující Request-Response Service (RRS) i Batch Execution Service (BES) s ukázkami kódů v C#, Python a R.

Zdrojem informací a návodů může být oficiální dokumentace na adrese http://azure.microsoft.com/cs-cz/documentation/services/machine-learning/, příklady jsou dostupné na adrese https://studio.azureml.net/.

Dostupné varianty a ceny Azure Machine Learning

Pro tvorbu vlastního experimentu je možné využít zdarma dostupnou verzi Azure ML, která vyžaduje pro přihlášení Microsoft účet a nevyžaduje Azure předplatné ani kreditní kartu. Zdarma dostupná verze má některá omezení oproti placené variantě.

image 

image

Vytvoření prvního Machine Learning experimentu v Microsoft Azure

Níže uvedený postup předpokládá placenou verzi Azure Machine Learning a tedy účet s přiřazenou platební kartou a aktivním předplatným Pay-as-you-go. Pokud bychom chtěl využít zdarma dostupnou verzi, stačí na webu Azure Machine Learning kliknout na tlačítko Začít a přihlásit se svým Microsoft účtem. Tím dojde k vytvoření zdarma dostupné pracovní plochy (workspace). Další postup je již stejný jako u placené varianty.

V levém menu nabídky služeb portálu Microsoft Azure (https://manage.windowsazure.com) vybereme Machine Learning. Nejdříve je nutné vytvořit novou pracovní plochu (workspace) pro Machine Learning. Pracovní plochy slouží pro základní oddělení jednotlivých úkolů, na kterých uživatel pracuje. Pokud tedy máme za úkol vytvořit doporučovací systém pro internetový obchod, bude mít tento úkol svoji pracovní plochu. Další úkol, například vyhodnocení prodejů automobilů, bude mít opět svoji vlastní pracovní plochu. Jednotlivé pracovní plochy je možné odděleně spravovat, sdílet a sledovat jejich statistiky, proto je vhodné nesouvisející problémy oddělovat do vlastních pracovních ploch. V rámci každé pracovní plochy může být více dílčích experimentů.

Vytvoříme tedy novou pracovní plochu kliknutím na New – Data Services – Machine Learning – Quick Create a vyplníme požadované informace. Název pracovní plochy (Workspace Name) je název, pod kterým chceme mít tu plochu uloženou. Vlastník pracovní plochy (Workspace Owner) je účet vlastníka pracovní plochy, který je ve výchozím stavu vyplněný na účet, pod kterým jsme přihlášení, ale v případě potřeby je možné vepsat název jiného Microsoft účtu. Lokace (Location) je datacentrum, ve které naše experimenty běží. Je vhodné volit geograficky nejbližší lokalitu kvůli odezvě a rychlosti připojení například při nahrávání datasetů. Účet úložiště (Storage Account) je název úložiště, ve kterém budou uložena data k naší pracovní ploše. Je možné zvolit již dříve vytvořený účet nebo vytvořit účet nový.

clip_image008

Vytvoření nové pracovní plochy Azure Machine Learning

Vytvoření nové pracovní plochy potvrdíme stisknutím Create an ML workspace.

Pracovní plochu máme vytvořenou a můžeme se pustit do tvorby samotného experimentu. Kliknutím na jméno pracovní plochy si tuto plochu otevřeme. Na nástěnce (Dashboard) vidíme graf se statistikou využití, základní informace o pracovní ploše a odkazy pro přístup do Machine Learning Studia a dokumentace.

clip_image010

Nástěnka pracovní plochy v Azure Machine Learning

Na záložce Configure je možné zakázat přístup uživatelů k této pracovní ploše (Allow or deny access to workspace), změnit vlastníka pracovní plochy (Workspace Owner) a zobrazit jméno úložiště pracovní plochy (Storage Name).

clip_image012

Změna nastavení pracovní plochy

Na poslední záložce je možné zobrazit a měnit nastavení webových služeb (Web Services) u experimentů v pracovní ploše. Nastavení je dostupné až v případě, že jsou nějaké webové služby publikovány přímo u experimentů. Bližší informace k webovým službám jsou dostupné na stránce Publish an Azure Machine Learning web service.

Nyní si otevřeme Machine Learning Studio. Na nástěnce pracovní plochy klikneme na Sign-in to ML Studio. Vidíme, že aktuálně nemáme žádné experimenty. Vytvoříme tedy nový. Klikneme dole na stránce na New a vybereme Experiment – Blank Experiment. Tím vytvoříme nový prázdný experiment. Je možné také vybrat z již dostupných ukázkových experimentů nebo zobrazit galerii a vybrat si některý již vytvořený experiment, který řeší stejný nebo podobný problém a jeho drobnou úpravou si můžeme ušetřit práci.

clip_image014

Vytvoření nového experimentu

Objeví se pracovní plocha nově vytvořeného experimentu. V levé části je nabídka s datasety (vlastními i vzorovými) a moduly, které je možné v experimentech použít. Hlavní část obrazovky je pracovní plocha experimentu, na kterou se umisťují a vzájemně propojují jednotlivé moduly. Pravá část obrazovky slouží pro informaci a konfiguraci jednotlivých modulů a celého experimentu. U jednotlivých modulů je dostupná nápověda s informací, jak daný modul pracuje, jaké očekává vstupy, jaké dává výstupy a jaké možnosti konfigurace má. K modulům je možné přidávat vlastní komentáře. K dispozici jsou také logy s informacemi o běhu a případných chybách.

Ovládání a organizace je stylem drag&drop, tedy chycení a přetažení pomocí myši.

clip_image016

Pracovní plocha experimentu

Experimenty se skládají z částí pro tvorbu modelu, trénování modelu, ohodnocení a testování modelu. Můžeme tedy vytvořit experiment, který vezme data, vytrénuje na nich model a tento model poté aplikuje na nová neznámá data. Pokud jsou vstupní data nějakým způsobem nevhodná, je možné je ještě před použitím upravit. Obvykle je potřeba vyřešit chybějící hodnoty (například odstraněním záznamů, které obsahují některé prázdné hodnoty), případně převést hodnoty na jiný datový typ (číslo uložené jako text převést na celočíselnou hodnotu apod.). Dále se data dělí na trénovací a testovací, aby bylo možné ověřit, že vytvořený model funguje správně (platí pro algoritmy učení s učitelem).

Tvorba experimentu se tedy může skládat z následujících pěti kroků rozdělených do tří částí:

  • Tvorba modelu
    1. Získání dat
    2. Předzpracování dat a jejich úprava
    3. Definice parametrů modelu
  • Trénování modelu
    1. Výběr a aplikace učícího algoritmu
  • Ohodnocení a testování modelu
    1. Předpovědi nad novými daty

V následujícím příkladu si ukážeme vytvoření regresního modelu pro předpověď ceny ojetého automobilu. Zdrojovými daty bude ukázkový dataset o automobilech dostupný v Azure ML Studiu. Nový experiment si tedy pojmenujeme jako Automobily.

Získání dat

Vzorová data máme již dostupná v ML Studiu. Je však možné nahrát si data vlastní. V levé nabídce si vyhledáme dataset s názvem Automobile price data a vložíme ho do pracovní plochy experimentu.

clip_image018

Vložení datasetu s informacemi o automobilech

Nyní se můžeme podívat, co je obsahem daného datasetu. Kliknutím pravým tlačítkem myši na výstupní bod datasetu se otevře nabídky s možností stažení datasetu (Download) a vizualizace dat (Visualize), zvolíme tedy vizualizaci.

clip_image019

Nabídka vizualiace dat datasetu

Zobrazí se nám nové okno s tabulkou (maticí) dat. Jednotlivé sloupce jsou parametry, v tomto případě parametry automobilu (cena, staří, výrobce apod.). Kliknutím na záhlaví sloupce můžeme zobrazit statistické informace o daném parametru. Jedním z parametrů je i cena, kterou budeme předpovídat. Řádky v tabulce jsou jednotlivé záznamy, v tomto případě jednotlivé automobily.

clip_image021

Vizualizace dat z datasetu

Předzpracování dat

Hlavní úlohy pro předzpracování dat jsou vyčištění dat, integrace, transformace, redukce a diskretizace nebo kvantifikace. K tomu slouží moduly ze sekce transformace dat (Data Transformation). Pro potřeby čištění dat slouží moduly jako Clean Missing Data (odstranění chybějících hodnot) nebo Remove Duplicate Rows (odstranění duplicitních záznamů).

Aby bylo možné provádět efektivní předpověď, je nutné odstranit záznamy (řádky tabulky) s některými chybějícími informacemi. V tomto kroku je důležité se rozhodnout, jestli odstraníme jen záznamy, které mají některé hodnoty nevyplněné, nebo bude vhodnější odstranit některé celé parametry (sloupce tabulky). Pokud by totiž některý parametr měl mnoho hodnot nevyplněných, odstraněním záznamů (řádků tabulky) bychom mohli velmi výrazně snížit celkový počet záznamů a tím zhoršit kvalitu předpovědi. V tomto případě je tedy vhodnější odstranit daný parametr (sloupec tabulky).

Vyhledáme tedy modul Project Columns, který umožňuje odstranit některé sloupce (parametry), a přidáme ho do našeho modelu pod dataset s automobily, ke kterému ho připojíme tažením myši od výstupního bodu datasetu ve vstupnímu bodu modulu.

clip_image023

Přidání modulu pro odstranění některých sloupců

Kliknutím na modul Project Columns se v pravé části zobrazí možnosti nastavení tohoto modulu. Ve výběru sloupců (Select columns) klikneme na Launch column selector a v novém okně zvolíme Begin with All columns, aby začal pracovat se všemi sloupci, a následně zvolíme Exclude pro vynechání některých sloupců a vybereme sloupec normalized-losses, protože obsahuje cca 20 % prázdných hodnot, je tedy vhodnější odstranit celý sloupec než jednotlivé řádky s prázdnými hodnotami.

clip_image025

Výběr sloupců pro odstranění

Nyní vyhledáme modul Clean Missing Data a přidáme ho do našeho modelu pod modul odstraňující některé sloupce, ke kterému ho připojíme.

clip_image027

Přidání modulu pro odstranění prázdných hodnot

Kliknutím na modul Clean Missing Data se v pravé části zobrazí možnosti nastavení tohoto modulu. Ve výběru sloupců (Selected columns) ponecháme vybrané všechny sloupce (All columns). V Cleaning mode změníme chování modulu, aby nenahrazoval chybějící hodnoty nulou, ale aby odstranil celý řádek. Zvolíme tedy Remove entire row.

clip_image029

Nastavení modulu Clean Missing Data

K modulům je možné přidávat komentáře a poznámky. To se hodí v případě, že máme složitější model a později se budeme chtít podívat, co přesně ten modul v našem případě dělá.

clip_image030

Přidání komentáře k modulu

Nyní jsme připraveni vyčistit data od nežádoucích hodnot. Spustíme tedy experiment kliknutím na Run ve spodní liště. Stav experimentu je možné sledovat v jeho průběhu pomocí jednoduchý indikátorů u jednotlivých modulů. Modul se symbolem přesýpacích hodin je ve frontě a čeká na běh. Modul s točícím se kolečkem je aktuálně zpracováván. Modul se symbolem zelené fajfky úspěšně dokončil svůj běh.

clip_image032

Dokončený experiment

Výstup všech modulů je možné vizualizovat nebo uložit jako dataset pro další použití. Na výstupu posledního modulu vidíme, že bylo odstraněno 12 řádků a 1 sloupec.

Definování parametrů

Ve strojovém učení jsou parametry individuální měřitelné vlastnosti něčeho, co nás zajímá. V našem datasetu každý řádek reprezentuje jeden automobil a sloupce reprezentují parametry toho automobilu. Nalezení vhodné skupiny parametrů pro tvorbu prediktivního modelu vyžaduje experimentování a znalost daného problému. Některé parametry jsou totiž vhodnější než jiné, některé dokonce předpověď mohou zhoršit, jiné ji nezlepší ani nezhorší, ale významně prodlouží dobu učení apod. Některé parametry také mají silnou korelaci s jinými parametry. V našem případě je to například spotřeba ve městě (city-mpg) se spotřebou na dálnici (highway-mpg), proto jeden z těchto parametrů můžeme vynechat.

Nyní začíná experimentování s parametry. Je velmi pravděpodobné, že se na první pokus nepodaří vytvořit nejlepší sadu parametrů a je potřeba zkoušet různé možnosti a ty mezi sebou porovnávat.

Jako první zkusíme zvolit parametry značky automobilu (make), typ karoserie (body-style), vzdálenost mezi nápravami (wheel-base), objem motoru (engine-size), výkon motoru (horsepower), maximální otáčky (peak-rpm), spotřebu na dálnici (highway-mpg) a samozřejmě cenu (price). Tyto parametry zadáme do další modulu Project Columns, který připojíme za modul odstraňující prázdné hodnoty. V modulu nastavíme, že chceme začít s žádnými sloupci (Begin with No columns) a vybereme Include a výše uvedené sloupce.

clip_image034

Definování parametrů, které chceme v našem modelu

Výběr a aplikace učícího algoritmu

Nyní máme data připravená pro trénování a testování modelu. Základními technikami strojového učení jsou klasifikace a regrese. Zjednodušeně lze říci, že klasifikace se používá pro tvorbu předpovědí ze zvoleného souboru hodnot (výběr z několika barev, pohlaví apod.). Regrese se používá pro tvorbu předpovědí z kontinuálního souboru hodnot (věk člověka, cena apod.).

V našem modelu chceme předpovídat cenu automobilu, což může být libovolná číselná hodnota, proto použijeme algoritmy založené na regresi. Abychom trénování urychlili a zkvalitnili, použijeme dva algoritmy, jejichž výsledky následně porovnáme.

Nejdříve ale musíme data rozdělit na trénovací a testovací, abychom měli část dat, u kterých budeme používat algoritmus učení s učitelem (známe správnou výslednou hodnotu = cenu). Druhá část bude testovací, kde již budeme předpovídat výslednou cenu na základě natrénovaného modelu a tuto cenu poté porovnáme se skutečnou cenou. 60 % dat bude trénovacích a 40 % dat bude testovacích. Poměr je možné volit libovolně, ale obecně se doporučuje 50:50 až 80:20 podle typu a velikosti dat.

Pro rozdělení dat slouží modul Split, který připojíme za poslední modul. U modulu nastavíme rozdělení řádků (Splitting mode – Split Rows) a poměr rozdělení 0.6 (60 % v první části, zbytek v druhé části). Hodnotou Random seed můžeme randomizovat rozdělení dat.

clip_image036

Rozdělení dat na trénovací a testovací

Nyní opět náš experiment spustíme, abychom na výstupu modulu Split získali data, která budeme dále potřebovat.

Vzhledem k tomu, že model má poměrně málo parametrů (méně než 100) a tyto parametry nejsou řídké, bude rozhodovací hranice pravděpodobně nelineární, tudíž jednoduchý algoritmus lineární regrese by nebyl v tomto případě vhodný. Vybereme tedy dva nelineární regresní algoritmy, které porovnáme – Poisson Regression a Decision Forest Regression. Oba algoritmy mají nastavení, které je možné modifikovat. My ale pro náš ukázkový problém použijeme výchozí nastavení. Pro nalezení vhodného nastavení algoritmů je doporučené použít modul Sweep Parameters, který zkouší různá nastavení (náhodně nebo na zvoleném intervalu) a výsledky porovnává. Je ale potřeba počítat s tím, že takový přístup může u složitějších problémů (velké množství vstupních dat) trvat velmi dlouho, řádově klidně desítky hodin běhu podle velikosti vstupních dat a počtu hledaných nastavení.

Přidáme tedy moduly obou algoritmů do našeho modelu vedle modulu Split a ponecháme je ve výchozím nastavení.

clip_image038

Přidání modulů algoritmů do modelu

Dále přidáme moduly pro trénování modelu (Train Model) a přidáme je pod oba regresní algoritmy. Levý vstup modelu pro trénování je připojen k regresnímu algoritmu, pravý vstup je připojen k levému výstupu (trénovací část dat) modulu Split.

clip_image039

Připojení trénovacích modulů

V obou modulech vybereme parametr (sloupec), který chceme předpovídat, tedy cenu automobilu (price). Opět spustíme experiment.

Předpovědi nad novými daty

Nyní máme model natrénovaný a můžeme ohodnotit zbývajících 40 %, abychom otestovali, jak dobře náš model předpovídá neznámé hodnoty, a porovnali mezi sebou výsledky obou algoritmů. Přidáme tedy dva moduly pro ohodnocení modelu (Score Model), jejichž levý vstup připojíme s výstupem modulu pro trénování modelu a pravý vstup připojíme s pravým výstupem modulu Split.

clip_image040

Přidání modulu pro ohodnocení

Spuštěním experimentu dojde k ohodnocení testovacích dat. Výsledek je možné vidět na výstupech modulů ohodnocení modelu ve sloupci Scored Labels.

clip_image041

Výsledek ohodnocení modelu

Nyní můžeme vyhodnotit výsledky pomocí modulu Evaluate Model, který přidáme za moduly ohodnocení. Levý vstup modulu Evaluate Model připojíme k výstupu modulu Score Model.

clip_image042

Modul pro vyhodnocení modelu

Na jeho výstupu jsou vidět vyhodnocení výsledků.

clip_image043

Vyhodnocení výsledků

Pro porovnání výsledků obou algoritmů použijeme jeden modul Evaluate Model, jehož jeden vstup připojíme k výstupu ohodnocení prvního algoritmu a druhý vstup připojíme k výstupu ohodnocení druhého algoritmu.

clip_image044

Porovnání výsledků dvou algoritmů

Po spuštění uvidíme na výstupu v jednoduché tabulce porovnání obou algoritmů.

clip_image045

Výsledky obou algoritmů

Jak je z tabulky vidět, algoritmus Decision Forest Regression poskytuje přesnější výsledky předpovědi ceny automobilu.

Stejným způsobem je možné porovnat výkon obou algoritmů i na trénovacím datasetu.

Práce s výsledky

Výsledky experimentu jsou dostupné v modulu Score Model. Tyto výsledky je možné uložit jako dataset k dalšímu použití (pravé tlačítko myši na výstup modulu a volba Save as Dataset), případně je možné výsledky stáhnout v souboru do počítače v některém z podporovaných formátů (ARFF, CSV, SVMLight, TSV) přidáním požadovaného modulu (například Convert to CSV) za modul Score Model. Poté na výstupu modulu Convert to CSV máme volbu Download.

clip_image046

Stažení výsledků v CSV

Pro přímý přístup k výsledkům slouží modul Writer a přístupové API.

Zhodnocení výsledků

  • Mean Absolute Error, hodnota známá pod zkratkou MAE, vyjadřuje průměr absolutní chyby (rozdílů mezi předpovězenou hodnotou a skutečnou hodnotou).
  • Root Mean Squared Error, hodnota známá pod zkratkou RMSE, vyjadřuje odmocninu průměru kvadratických odchylek předpovědi provedené na testovacím datasetu.
  • Relative Absolute Error vyjadřuje průměr absolutních odchylek vzhledem k absolutnímu rozdílu mezi skutečnými hodnotami a průměrem všech skutečných hodnot.
  • Relative Squared Error vyjadřuje průměr kvadratických odchylek vzhledem ke kvadratickému rozdílu mezi skutečnými hodnotami a průměrem všech skutečných hodnot.
  • Coefficient of Determination, hodnota známá také jako „R na druhou“, vyjadřuje vhodnost modelu k daným datům.

Pro všechny statistické údaje platí, že menší je lepší, tedy že předpovězené hodnoty lépe odpovídají skutečným hodnotám. Naopak jen u koeficientu determinace platí, že čím více se blíží k hodnotě jedna (1), tím lepší je předpověď.

Lukáš Beran

Comments (0)

Skip to main content