Elon Musk od Waltera Isaacsona je za mě nejlepší kniha, co jsem tento rok poslouchal. Ne proto, že bych měl Muska nějak rád (je to asociální nebezpečný magor), ale to co dokázal a jak, je fascinující. Některé jeho myšlenky jsou velmi zajímavé a hodně si z nich vezmete (například jeho styl neustále osekávat a osekávat součástky) a i když ho nemáte rádi, musíte docenit jeho SpaceX a možná i Teslu (záleží jak moc jste přesvědčeni, že celkový výsledek elektromobility na životní prostředí je pozitivní … vzhledem k tomu, že se díky veřejnému mínění vzdává jaderná energetika a soláry nebudou stačit). Objevíte ale i jeho temnou stranu a ta je taky děsivá. Moc doporučuji.
The Worlds I See: Curiosity, Exploration, and Discovery at the Dawn of AI je úplná novinka od číňanky, imigrantky do USA, která stojí mimo jiné za ImageNet projektem. Tahle kniha je hodně inspirativní a jiná než ostatní v tom, že je to mix osobní zpovědi ženy, která je hodně chytrá a správně zvědavá, ale měla to někdy dost těžké a současně je to o vývoji v oblasti AI a to i včetně poměrně technického popisu (ale rozhodně ne moc, takže toho se bát nemusíte). Zamýšlí se i nad rolí AI v budoucnosti. Zkrátka tohle všechno dohromady a krásně to do sebe zapadá - v tom je síla téhle knihy.
The Master Algorithm: How the Quest for the Ultimate Learning Machine Will Remake Our World by Pedro Domingos je výborná kategorizace jednotlivých typů modelů strojového učení a že ne všechno musí být deep learning aby to mohlo být užitečné. Tahle kniha vznikla v roce 2015, tedy v době, kdy se neuronové sítě jako jedna z technik začaly zmocňovat světa, ale dlouho před ChatGPT, nicméně některé jeho predikce jako je digitální dvojče a osobní asistent jsou z dnešního pohledu hodně dobré. Pedro je dost kontroverzní týpek, jak jsem zjistil na Xku (Twitteru) a je zajímavé ho sledovat.
The Big Picture: On the Origins of Life, Meaning, and the Universe Itself by Sean M. Carroll je přesně to co mám rád - místo brutální specializace tenhle člověk prostě mluví úplně o všem a díky tomu má neuvěřitelný kontext. To je hodně unikátní. Prochází filosofii, fyziku i vznik lidstva a inteligence, biologii, genetiku.
Kompletní průvodce půstem od Jason Fung sice byl informativní, ale byly tam “skutečné příběhy lidí” a to bylo strašné. Chce to přeskakovat.
Proč chodíme od Shane O Mara se věnuje chození a nejzajímavější byl jeho efekt na mozek a přemýšlení.
Relationships 5.0: How AI, VR, and Robots Will Reshape Our Emotional Lives můžu rozhodně doporučit, řeší, jak technologie mění vztahy. Nejdřív popisuje 5 fází vývoje vztahů od lovců a sběračů s velmi volnými vztahy přes velké rodiny v zemědělské revoluci až k současnosti, kdy se začínají objevovat mladí, kteří zkrátka stále partnera nemají a nehledají. Pak se věnuje třem pilířům revoluce ve vztazích pro relationships 5.0 -> kognitivní revoluce představovaná příchodem a adopcí AI, senzorická revoluce v oblastech VR a AR a fyzická revoluce díky robotice.
Scary Smart: The Future of Artificial Intelligence and How You Can Save Our World je poměrně pesimistická, ale dobrá kniha o AI. Nejzajímavější myšlenka byla, že AI jsou naše děti. Co uvidí v nás, jak se budeme chovat k nim a mezi sebou, tak je vychováme, protože my jsme jejich trénovací sada.
AI Ethics of MIT press je stručný a velmi dobrý úvod do etiky AI.
Understanding complexity od Scott E. Page - původně jsem myslel, že to bude jen povídání o fraktálech, ale vůbec. Je to takový vědečtější doplněk k Černá Labuť (Taleb) a je to teorie komplexních systémů. Ty mají propojenost, ale tak akorát (v nepropojeném systému není interakce hráčů, třeba lidí, zatímco v plně propojeném je jen chaos) a tak podobně. Popisuje efekt “emergence” u komplexních systémů, tedy že se z nich vynoří nečekané chování, které není jen součtem vlastností elementů - například vědomí. Popisuje S křivky a fázové přechody v komplexních systémech.
How Innovation Works: And Why It Flourishes in Freedom je primárně o diverzitě a proč je důležitá pro inovaci. Kdyby tohle rozdávali místo těch interních dementních školení diverzity a inkluze, lépe by se to chápalo. Potřebujeme co nejvíc nápadů v co největší varietě a v kontextu závěru roku je to i zajímavý podklad pro diskusi o regulaci (možná spíš pře-regulaci) AI v Evropě.
Genius Makers: The Mavericks Who Brought AI to Google, Facebook, and the World je vlastně historie AI a je to skvěle napsané. Díky tomu se budete orientovat ve velkých personách v AI, co dělali a co dokázali a taky o slavné “AI winter”.
Čísla nelžou od Václava Smila je klasický Smil - 71 statistických údajů s výborným komentářem a souvislostmi.
The Precipice: Existential Risk and the Future of Humanity studuje rizika zániku lidstva a to skutečného a hodně do hloubky (nejde o nepodložené křiklounství alarmistů, je to promyšlené a realistické). Zkoumá skutečné pravděpodobnosti pro plný zánik (definuje jako ztrátu potenciálu lidstva) a klimatické změny a AI jsou největší riziko. Mnohem větší, než jaderné války, biologické zbraně nebo epidemie (ačkoli tyto jsou tam samozřejmě taky).
Antifragile: Things That Gain from Disorder (Nassim Nicholas Taleb ) je klasický Taleb, takže za mě hodně těžká kniha. Hlavní myšlenka je koncept opaku křehkosti (vnější vlivy to rozbijí), kterým není robustnost (schopnost odolávat vnějším vlivům), ale anti-fragilita (schopnost se na základě vnějších vlivů posílit). Nahodilost a výkyvy jsou informační události, co tě nezabije, to tě posílí a dobrým příkladem je imunitní systém nebo evoluce. Je to zajímavé i pro stavbu IT systémů. Pokud se ladí systém na jednoúčelovost, optimalizujete na totální efektivitu, vzniká křehkost a nečekaná událost to zabije. Investujete do víc způsobů přežití a to je lepší, než jeden perfektně vyladěný.
Ještě to promysli od Adama Granta byla o přehodnocování a změně názoru a proč je to důležité. Nejsilnější příběh byl o Mikovi Lazaridisovi, který vymyslel Blackberry. Ukazuje úžasného inovátora, nesmírně chytrého a úspěšného člověka, který ale v určitém okamžiku není změny názoru schopen.
The Chaos Machine: The Inside Story of How Social Media Rewired Our Minds and Our World je chronologický popis vývoje skandálů kolem YouTube a Facebook algoritmů a jejich dopadu na společnost, polarizaci, radikalizaci (anti-vax, trump, extrémismus, …).
Freakonomics je trochu staré, ale pár zajímavých ekonomických postřehů o fungování prodejců drog nebo domů tam bylo.
Livewired od Davida Eaglemana je trochu podobná Antifragile, ale čistě z pohledu mozku. Vysvětluje, jak se rodíme nepřipravení a všechno se u dítěte dodělává. Dává příklady plasticity mozku na případě fantomové bolesti (kdy například senzory hmatu na tváři “prorostou” do uvolněné oblasti mozku, která zpracovávala signály z ruky) nebo o tom, že zakryté oko na začátku života způsobí trvalou slepotu na celý život (protože místo v mozku, kam vedou jeho neurony obsadí něco jiného). Fascinující jsou samozřejmě příběhy lidí, co se narodí jen s jednou půlkou mozku a celkem to dají.
The New Breed: What Our History with Animals Reveals About Our Future with Robots představuje hodně zajímavou analogii AI a robotů se zvířaty a “jejich” právy. Např. odpovědnost za přijmutí potřebných opatření, ale nenesete ji, pokud se zvíře zachová nepředvídatelně. Zajímavá je problematika práv podle roztomilosti (měli byste problém s laboratorním psem i když nemáte problém s laboratorní myší?). Všimli jste si, že mnoho “práv” zvířat jsou ve skutečnosti práva majitelů (řešíme újmu páníčkovi, ne zvířeti).
Your Brain Explained je výborná kniha z oblasti neurovědy bez psychologické rozplizlosti nebo populárních rad a senzací. Pokud vás zajímá mozek co do vnitřního fungování, tohle je ta správná kniha.
Můžete kouknout i na moje předchozí tipy:
]]>Typicky nechceme, aby běžný uživatel měl právo přiřazovat práva dalším uživatelům, protože by si tam například pozval své kamarádíčky a bůh ví co by tam dělali. Navíc co když začne dávat práva i sám sobě a následně odstraní některé komponenty, které jsou pro něj zapovězené, třeba Azure politiky nebo směrovací pravidla na subnetu.
Proti tomu ale jde to, že chceme zejména pro aplikační komponenty používat bezheslové řešení a least privilege principy, tedy nasadit User Managed Identity. Aplikační komponenta, třeba kontejner v Azure Kubernetes Service, má přistupovat do Azure Cosmos DB? Nechť přímo pro tuto komponentu existuje Managed Identity, která má přístup právě jen do této jediné služby. Žádná hesla, klíče nebo tokeny, které se mohou rozkecat, zneužít, zapomenout odrotovat nebo omylem ponechat v Gitu či dokumentaci. Žádný univerzální účet Service Principal, který bylo od IT tak těžké získat, že s ním děláme úplně všechno úplně odevšad. Jenže to má háček - identitu vytvořím a musím k ní přiřadit příslušná práva. Aha - ale to my přece nesmíme. Takže ticket … Terraform to pěkně vymlaskne a pak se zastaví a bude hezky čekat na někoho, kdo to odklepne? To není ideální.
Dosavadní přístupy k odlehčení toto problému zahrnují:
Když to shrneme, tak by to řešila vlastně jednoduchá věc. Nechť můžu dát někomu roli User Access Manager, ale omezit jak s ní může nakládat. Jaké role smí přiřazovat a komu je smí přiřazovat. Jednoduché, že? Na papíře jistě ano a jde v zásadě o formu Attribute Based Access Control, v praxi to ale produktovému týmu dost dlouho trvalo udělat. Ale už to je.
Úplně nejlepší bude si to jednoduše proklikat.
Mám tady jednu Resource Group a přiřadím do ní speciální práva svému uživateli.
Role bude privilegovaná, konkrétně User Access Manager.
Přidám svého uživatele.
Teď můžu přidat další podmínky - to je nové.
Můžu omezit pouze role, které může přiřazovat. To je hodně užitečné, protože mu dám třeba možnosti jako je role pro SQL, Cosmos DB, Azure storage, vytváření VM nebo něco takového. Nebude mít ale možnost třeba měnit networking nebo být Owner nebo něco takového.
Další varianta je k tomu přidat i omezení na typ účtů, což zvolíme my a probereme později.
Třetí varianta je k rolím přidat vyloženě i výčet uživatelů, kterým lze role přiřazovat. Tohle je vhodné pro role pro skutečné lidi (uživatelské účty), například členy týmu. Vybrat si tam můžete i skupinu v Microsoft Entra ID (AAD).
Já volím jen jednu roli Storage Blob Data Reader (čtecí přístup do Blob storage) a principal type pouze Service principals (což zahrnuje i managed identity). Můj uživatel tedy nebude schopen dávat tuto roli uživatelským účtům, jen “systémovým”-.
To je celé, teď se naloguji jako uživatel a chci přidávat práva.
Na výběr mám jen omezenou sadu rolí, v mém případě jen tu jednu.
Vybrat managed identitu, pokud je v mém scope, což je aktuálně tato resource group, můžu.
Nicméně uživatele žádné a to ani sám sebe.
Myslím, že takhle na screenshotech je to velmi jasné a geniálně jednoduché. Trvalo to dlouho, ale v preview už můžete dát uživatelům možnost se obsloužit sami ať už klikáním nebo v rámci jejich automatizace a přitom nevytváříte bezpečnostní riziko. Doporučuji promyslet a změnit strategii v přístupu ke governance, pokud máte aktuálně velmi přísné podmínky, které snižují pohodlí a produktivitu vašich uživatelů.
]]>Celý dnešní kód je u mě na GitHubu v notebooku.
Všechno co tady uvidíte v žádném případě není profesionální vyladěný benchmark, jde o vytvoření si nějaké řádové představy. Přímo YOLOv8 má ve svém API možnost provést benchmark modelu včetně různých zabalení. Vyzkoušel jsem jednak malý server (2 core 8 GB RAM), pak stroj s jednou NVIDIA A100 GPU a k tomu nějaký finanční ekvivalent v CPU, což vyšlo zhruba na D řadu s 96 core. Otestoval jsem nano a large verzi modelu. Tady jsou výsledky.
VM Type | Time nano (ms) | Time large (ms) | VM price per hour (USD) | Price per 1M images nano (USD) | Price per 1M images large (USD) |
---|---|---|---|---|---|
STANDARD_D2AS_V4 | 123 | 1782 | 0.115 | 3.39 | 56.93 |
STANDARD_NC24ADS_A100_V4 | 5 | 8 | 4.78 | 6.64 | 10.62 |
STANDARD_D96A_V4 | 36 | 139 | 4.9 | 49 | 189.18 |
YOLOv8 je opravdu velmi výkonné a vidíte, že s GPU jste s přehledem schopni i s velkým modelem zpracovávat data v živém streamu. Pokud pojede třeba film s 24 FPS, tak každé políčko svítí asi 42 ms, takže GPU s 8ms latencí tohle bude krásně stíhat i na víc streamů současně. Co si na datech všimnout?
YOLO má nativně formát PyTorch, ale je to celé trochu džungle. Některé modely třeba máte v TensorFlow, ale řeknete není problém - moje hostovací platforma umí oboje. To ta, co použijeme hned za chvilku, taky, jenže je to hugh-performance hostovací platforma. Jsou tady ale ještě situace, kdy chcete běžet uvnitř telefonu nebo jako Javascriptový kód v browseru a tak podobně.
Model tedy uložíme ve formátu ONNX, který by měl zajistit lepší přenositelnosti mezi těmito případy použití.
# Export models
model_yolov8n.export(format='onnx')
model_yolov8l.export(format='onnx')
Jako hostovací framework jsem zvolil Tritor Inference Server (evoluce TensoRT Inference Server) od NVIDIA, který je podle všeho (logicky) výborně vyladěn pro NVIDIA čipy jak v cloudu na na edge platformách, ale umí běžet i na CPU (což pro úsporu použiji na test já). Úžasné je, že tohle celá se dá sehnat jako hotová Docker kontejner nvcr.io/nvidia/tritonserver:23.05-py3
. Dokonce pro servívání modelů nemusíte nic buildovat! Žádný Dockerfile, registry a podobně věci, které lidi od dat mohou děsit (což je teda trochu škoda, protože tenhle svět je pro ML podle mě hodně zajímavý - Vulcano, Kubeflow, …).
Jediné co potřebujete do kontejneru dostat, je adresářová struktura s konfiguračním souborem a samotným modelem - ve formátu ONNX (můj případ), ale může to být třeba PyTorch nebo TensorFlow. V adresáři models mám adresář pro každý model a uvnitř je konfigurační soubor config.pbtxt
. Dále jsou uvnitř adresáře pro každou verzi modelu. To je skvělé, protože můžeme brát modely jako immutable artefakty, které jednoduše nahrajeme do adresáře a Triton si je načte a všechny servíruje. Není tak problém mít několik modelů v jednom endpointu a u každého modelu mít i víc verzí, ať mohou uživatelé přecházet postupně.
models
├── yolov8l
│ ├── 1
│ │ └── model.onnx
│ └── config.pbtxt
└── yolov8n
├── 1
│ └── model.onnx
└── config.pbtxt
Stačí tedy kontejner spustit na lokálním počítači, v Azure Kubernetes Service (CPU nebo GPU), Azure Container Instance (ta umí také GPU), Azure Container App (jen CPU) nebo Azure App Service (jen CPU). Jediné co jí musíte doručit je tenhle adresář a to krásně zajistíte jako mount z Azure Files. Ale to si zkusíme někdy jindy - dnes cílíme na plně spravovaný endpoint v Azure Machine Learning. Jak výsledné API vypadá uvidíte za chvilku.
Nahodíme tedy snadno:
docker run -it --rm -p8000:8000 -p8001:8001 -p8002:8002 -v ./models:/models nvcr.io/nvidia/tritonserver:23.05-py3 tritonserver --model-repository=/models
Na portu 8000 nám hnedle běží HTTP API, na portu 8001 gRPC API (rychlejší, efektivnější varianta) a na portu 8002 statistiky pro monitoring s Prometheus/Grafana. Takže pokud jste taky Kuberneťáci, tak hnedle vidíte, že je to ideální dortíček do Kubernetu -> jen tomu namountovat volume, škálovat s HPA/KEDA, dát mu Ingress, napojit na monitoring a je to celé tak standardní jak jen běžná aplikace může být. Žádné ty datařské Sparkové tajemnosti.
Použijeme v2 verzi služby, která v preview podporuje Triton, a protože jedu z notebooku, tak půjde přes Python SDK (druhá varianta je CLI v2 - tedy připravit si YAML s popisem, což je také velmi příjemné). Nalogujeme se, vytvoříme endpoint, do něj nasadíme model (u toho určíme compute infrastrukturu - já pro dnešek půjdu do malého CPU stroje) a na tuhle verzi (říkám jí blue) pošleme všechny uživatele.
# Login
from azure.ai.ml import MLClient
from azure.identity import DefaultAzureCredential
ml_client = MLClient(
DefaultAzureCredential(),
subscription_id,
resource_group,
workspace_name,
)
# Create endpoint and deployment
from azure.ai.ml.entities import ManagedOnlineEndpoint
# Create endpoint
endpoint = ManagedOnlineEndpoint(name=endpoint_name, auth_mode="key")
endpoint = ml_client.online_endpoints.begin_create_or_update(endpoint).result()
# Create deployment
from azure.ai.ml.entities import ManagedOnlineDeployment, Model
deployment = ManagedOnlineDeployment(
name="blue",
endpoint_name=endpoint_name,
model=Model(path="./models", type="triton_model"),
instance_type="Standard_D2as_v4",
instance_count=1,
)
ml_client.online_deployments.begin_create_or_update(deployment).result()
# Update traffic
endpoint.traffic = {"blue": 100}
ml_client.online_endpoints.begin_create_or_update(endpoint).result()
Tou verzí se teď nenechte zmást. Je to vymyšlené pro situaci, že servírujete klasicky model jeden po druhém a tady umíte překlápět verze online modelů mezi sebou. Triton na to jde trochu jinak a má vícero modelů i verzování přímo v sobě. Nicméně i Triton samotný má verze a navíc můžete přidávat modely apod., takže by šlo teoreticky použít na verzování modelu oboje. Já osobně bych byl pro naplno využít vlastností Tritonu, protože ten umí verzování, “latest”, scheduling, prioritizaci fronty, automatické batchování se zpožděním (např. řeknete, že chcete scorovat v dávkách 8 kousků a jste ochotni čekat 500ms jestli vám do stávajího vozíku nepřistoupí ještě další request). Zkrátka je to celé dost vychytané a funguje to pak stejně ve všech způsobech nasazení.
Od managed endpointu už tedy věci kolem verzování nějak moc nepotřebuji, kromě verzí samotného Tritonu, ale co se mi rozhodně může hodit je, že nemusím nahazovat stroje, řešit jak je rozjet redundantně, zajistit jejich škálování podle zátěže, vznik nějakého endpointu, klíče na přístup, certifikátu, monitoringu, logování.
Autoškálování je u managed endpointu opravdu mocné.
K dispozici jsou metriky a logy.
Přístup na API je zabezpečen přes klíč, takže tuhle starost stejně jako FQDN a platný certifikát pro vás managed endpoint zařídí.
Ve finále tedy:
Na výběr je dobře čitelné HTTP API, kde si vystačí s cURL i Postmanem, ale i binární efektivnější gRPC API, které umožní vyšší výkon a jednoduché generování skeletonu apod. Zabezpečení endpointu zajišťuje Azure Machine Learning služba, takže si zjistím URL svého endpointu, klíč a připravím si příslušný header.
# Imports
import tritonclient.http as tritonhttpclient
import gevent.ssl
import cv2
import numpy as np
from matplotlib import pyplot as plt
# Get scoring URI and key
endpoint = ml_client.online_endpoints.get(endpoint_name)
scoring_uri = endpoint.scoring_uri
keys = ml_client.online_endpoints.get_keys(endpoint_name)
auth_key = keys.primary_key
# We remove the scheme from the url
url = scoring_uri[8:]
# Initialize client handler
triton_client = tritonhttpclient.InferenceServerClient(
url=url,
ssl=True,
ssl_context_factory=gevent.ssl._create_default_https_context,
)
# Create headers
headers = {}
headers["Authorization"] = f"Bearer {auth_key}"
# Check Triton server is ready
health_ctx = triton_client.is_server_ready(headers=headers)
print("Is server ready - {}".format(health_ctx))
Server odpovídá. Jaké mám modely k dispozici?
# List models on Triton server
triton_client.get_model_repository_index(headers=headers)
[
{
"name":"yolov8l",
"version":"1",
"state":"READY"
},
{
"name":"yolov8n",
"version":"1",
"state":"READY"
}
]
Načtu si příkladový obrázek, převedu na 640x640 a pošachuju s dimenzema, aby to odpovídalo očekávání modelu. Pošleme to tam a zpátky dostanu odpověď ve tvaru matice (1 x 84 x 8400). To je trochu zvláštní, ale takhle YOLO funguje. První dimenzi odříznu, protože ji nepotřebuji (neděláme batch vícero obrázků). Druhá dimenze má 84 hodnot s tím, že první 4 jsou souřadnicové a pak jsou pravděpodobnosti pro 80 tříd COCO datové sady, na kterou bylo YOLO trénované (pokud by to byl Oslik a Ovecka, tak budou dvě). Třetí dimenze je 8400 obdelníků. V rámci zpracování dimenze prohodíme, ať máme řádky pro každý box a k nim souřadnice a pravděpodobnost (score) pro jednotlivé kategirie.
# Load image file
img = cv2.imread('test.jpg')
# Store original image size
image_width, image_height = img.shape[:2]
# Preprocess image
img = cv2.resize(img, (640, 640))
img = img.astype(np.float32) / 255.0
img = np.transpose(img, (2, 0, 1))
img = np.expand_dims(img, axis=0)
# Create inference request
input = tritonhttpclient.InferInput('images', img.shape, 'FP32')
input.set_data_from_numpy(img)
# Send inference request
outputs = [tritonhttpclient.InferRequestedOutput('output0')]
response = triton_client.infer('yolov8l', inputs=[input], outputs=outputs, headers=headers)
# Get rid of first dimension (we have just one image)
output_data = response.as_numpy('output0')[0]
# Transpose to get 8400x84
output_data = output_data.transpose()
# Now each row is one bounding box
# First 4 numbers are bounding box coordinates, next 80 are probabilities for different classes
print(f"Row 0: x_center: {output_data[0][0]} y_center: {output_data[0][1]} width: {output_data[0][2]} height: {output_data[0][3]}")
print(f"Classes probabilities: {output_data[0][4:]}")
Row 0: x_center: 10.970717430114746 y_center: 4.042498588562012 width: 23.763792037963867 height: 10.321962356567383
Classes probabilities: [1.9371510e-06 2.0861626e-07 4.4703484e-07 1.4901161e-07 5.0663948e-07
1.1920929e-07 5.9604645e-08 2.3841858e-07 4.7683716e-07 8.0466270e-07
1.1920929e-07 4.1723251e-07 1.4901161e-07 3.5762787e-07 2.4437904e-06
2.0861626e-07 2.3841858e-07 4.1723251e-07 5.3644180e-07 4.7683716e-07
2.9802322e-07 2.6822090e-07 4.7683716e-07 5.0663948e-07 1.1920929e-07
1.1026859e-06 2.0861626e-07 2.9802322e-07 5.9604645e-08 2.6822090e-07
3.2782555e-07 2.3841858e-07 5.0663948e-07 1.6391277e-06 1.4901161e-07
1.4901161e-07 2.0861626e-07 4.7683716e-07 3.8743019e-07 3.5762787e-07
3.5762787e-07 2.6822090e-07 1.7881393e-07 2.3841858e-07 1.7881393e-07
2.3841858e-07 4.7683716e-07 4.1723251e-07 1.7881393e-07 6.8545341e-07
2.0861626e-07 2.9802322e-07 1.4901161e-07 1.7881393e-07 2.3841858e-07
1.4901161e-07 8.0466270e-07 1.7881393e-07 6.8545341e-07 2.3841858e-07
3.5762787e-07 2.6822090e-07 2.6822090e-07 1.4901161e-07 1.4901161e-07
2.6822090e-07 1.7881393e-07 1.7881393e-07 1.7881393e-07 1.1920929e-07
1.1920929e-07 4.4703484e-07 2.3841858e-07 6.8545341e-07 6.2584877e-07
2.3841858e-07 1.4901161e-07 3.2782555e-07 1.7881393e-07 1.7881393e-07]
Třídy si převedeme na názvy přes jejich index a podíváme se v řádku na třídu s nejvyšším score.
# Find bounding box with highest probability and print class id
yolo_classes = [
"person", "bicycle", "car", "motorcycle", "airplane", "bus", "train", "truck", "boat",
"traffic light", "fire hydrant", "stop sign", "parking meter", "bench", "bird", "cat", "dog", "horse",
"sheep", "cow", "elephant", "bear", "zebra", "giraffe", "backpack", "umbrella", "handbag", "tie",
"suitcase", "frisbee", "skis", "snowboard", "sports ball", "kite", "baseball bat", "baseball glove",
"skateboard", "surfboard", "tennis racket", "bottle", "wine glass", "cup", "fork", "knife", "spoon",
"bowl", "banana", "apple", "sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza", "donut",
"cake", "chair", "couch", "potted plant", "bed", "dining table", "toilet", "tv", "laptop", "mouse",
"remote", "keyboard", "cell phone", "microwave", "oven", "toaster", "sink", "refrigerator", "book",
"clock", "vase", "scissors", "teddy bear", "hair drier", "toothbrush"
]
prob = output_data[0][4:].max()
class_id = output_data[0][4:].argmax()
print(f"Label: {yolo_classes[class_id]} with probability: {prob}")
Label: bird with probability: 2.4437904357910156e-06
Obdelníků je samozřejmě hrozně moc a většina z nich má téměř nulové pravděpodobnosti. Vyberme jen ty nad 0.5 a uložíme si souřadnice. To uděláme tak, že je jednak přeškálujeme na původní velikost obrázku a spočítáme se x1, x2, y1, y2 (model nám vrátil v prvních dvou číslech střed a pak šířku a výšku - právě aby se to dalo dobře přeškálovat na původní velikost obrázku).
# Cycle through all bounding boxes and print those with probability higher than 0.5
boxes = []
for i, row in enumerate(output_data):
prob = row[4:].max()
class_id = row[4:].argmax()
if prob > 0.5:
x_center, y_center, width, height = row[:4]
x = int((x_center - (width / 2)) / 640 * image_width)
y = int((y_center - (height / 2)) / 640 * image_height)
w = int(width / 640 * image_width)
h = int(height / 640 * image_height)
x2 = x + w
y2 = y + h
print(f"Row: {i} Label: {yolo_classes[class_id]} Probability: {prob} Coordinates: {x, y, x2, y2}")
boxes.append({"label":yolo_classes[class_id], "coordinates": (x, y, x2, y2)})
# Note some boxes are "duplicates" as they are having eg. just 1 pixel difference
# We should "dedpulicate" them, but in our case we will just draw all of them
Row: 1464 Label: bird Probability: 0.6160368323326111 Coordinates: (172, 136, 222, 169)
Row: 1465 Label: bird Probability: 0.6021742224693298 Coordinates: (173, 136, 222, 168)
Row: 1466 Label: bird Probability: 0.5969414710998535 Coordinates: (174, 136, 223, 168)
Row: 1543 Label: bird Probability: 0.6512818336486816 Coordinates: (173, 136, 222, 168)
Row: 1544 Label: bird Probability: 0.605888307094574 Coordinates: (173, 136, 222, 169)
Row: 1545 Label: bird Probability: 0.6010562777519226 Coordinates: (173, 136, 222, 169)
Row: 1546 Label: bird Probability: 0.6660826206207275 Coordinates: (174, 136, 222, 169)
Row: 1624 Label: bird Probability: 0.5813634395599365 Coordinates: (173, 136, 222, 169)
Row: 1625 Label: bird Probability: 0.5755418539047241 Coordinates: (174, 136, 223, 169)
Row: 1626 Label: bird Probability: 0.5425906181335449 Coordinates: (174, 136, 222, 169)
Row: 4224 Label: person Probability: 0.6522736549377441 Coordinates: (506, 410, 528, 458)
Row: 4225 Label: person Probability: 0.6930487155914307 Coordinates: (506, 410, 528, 458)
Row: 4226 Label: person Probability: 0.649591326713562 Coordinates: (528, 409, 547, 459)
Row: 4227 Label: person Probability: 0.6896713972091675 Coordinates: (528, 409, 547, 459)
Row: 4297 Label: person Probability: 0.5141710042953491 Coordinates: (450, 426, 474, 459)
Row: 4304 Label: person Probability: 0.6453979015350342 Coordinates: (506, 410, 528, 459)
Row: 4305 Label: person Probability: 0.6543363928794861 Coordinates: (506, 411, 528, 459)
Row: 4306 Label: person Probability: 0.6686833500862122 Coordinates: (528, 409, 547, 459)
Row: 4307 Label: person Probability: 0.670250654220581 Coordinates: (528, 409, 547, 459)
Row: 4377 Label: person Probability: 0.6253103017807007 Coordinates: (450, 426, 474, 459)
Row: 4378 Label: person Probability: 0.6047794222831726 Coordinates: (450, 426, 474, 459)
Row: 4384 Label: person Probability: 0.6403813362121582 Coordinates: (506, 410, 528, 459)
Row: 4385 Label: person Probability: 0.6593260169029236 Coordinates: (506, 411, 528, 459)
Row: 4386 Label: person Probability: 0.6783121824264526 Coordinates: (528, 409, 547, 459)
Row: 4387 Label: person Probability: 0.6697359681129456 Coordinates: (528, 409, 547, 459)
Row: 4457 Label: person Probability: 0.5939190983772278 Coordinates: (450, 426, 474, 459)
Row: 4458 Label: person Probability: 0.6158614158630371 Coordinates: (450, 426, 474, 459)
Row: 4464 Label: person Probability: 0.6724660396575928 Coordinates: (506, 410, 528, 459)
Row: 4465 Label: person Probability: 0.6691636443138123 Coordinates: (507, 411, 529, 459)
Row: 4466 Label: person Probability: 0.6635993123054504 Coordinates: (528, 409, 547, 459)
Row: 4467 Label: person Probability: 0.6709198355674744 Coordinates: (528, 409, 547, 459)
Row: 4537 Label: person Probability: 0.6160084009170532 Coordinates: (450, 426, 474, 459)
Row: 4538 Label: person Probability: 0.6102625131607056 Coordinates: (450, 426, 474, 459)
Row: 4544 Label: person Probability: 0.6642736196517944 Coordinates: (506, 410, 528, 459)
Row: 4545 Label: person Probability: 0.6493443250656128 Coordinates: (507, 410, 529, 458)
Row: 4546 Label: person Probability: 0.6440086364746094 Coordinates: (527, 409, 546, 459)
Row: 4547 Label: person Probability: 0.6871405243873596 Coordinates: (528, 409, 547, 459)
Row: 5121 Label: person Probability: 0.5096266269683838 Coordinates: (0, 489, 26, 566)
Row: 5200 Label: person Probability: 0.5972477793693542 Coordinates: (0, 489, 26, 566)
Row: 5201 Label: person Probability: 0.6127698421478271 Coordinates: (0, 489, 26, 566)
Row: 5280 Label: person Probability: 0.6291350722312927 Coordinates: (0, 489, 26, 566)
Row: 5281 Label: person Probability: 0.6749528646469116 Coordinates: (0, 489, 26, 565)
Row: 5286 Label: person Probability: 0.7652390599250793 Coordinates: (32, 505, 85, 567)
Row: 5287 Label: person Probability: 0.7516335248947144 Coordinates: (31, 505, 84, 567)
Row: 5294 Label: person Probability: 0.7526721954345703 Coordinates: (94, 518, 136, 568)
Row: 5360 Label: person Probability: 0.5917220711708069 Coordinates: (0, 489, 25, 565)
Row: 5361 Label: person Probability: 0.6364521980285645 Coordinates: (0, 489, 25, 566)
Row: 5366 Label: person Probability: 0.7760496735572815 Coordinates: (32, 505, 85, 567)
Row: 5367 Label: person Probability: 0.7628909945487976 Coordinates: (32, 505, 85, 567)
Row: 5368 Label: person Probability: 0.7380048632621765 Coordinates: (32, 505, 85, 567)
Row: 5373 Label: person Probability: 0.7580685615539551 Coordinates: (94, 518, 136, 569)
Row: 5374 Label: person Probability: 0.7388852834701538 Coordinates: (94, 517, 136, 568)
Row: 5375 Label: person Probability: 0.7215502858161926 Coordinates: (94, 518, 136, 569)
Row: 5446 Label: person Probability: 0.7717000246047974 Coordinates: (32, 505, 85, 567)
Row: 5447 Label: person Probability: 0.7657181024551392 Coordinates: (32, 505, 85, 567)
Row: 5448 Label: person Probability: 0.7473055720329285 Coordinates: (32, 505, 85, 567)
Row: 5453 Label: person Probability: 0.7478396892547607 Coordinates: (94, 518, 136, 569)
Row: 5454 Label: person Probability: 0.7133488059043884 Coordinates: (94, 517, 136, 568)
Row: 5455 Label: person Probability: 0.7043735384941101 Coordinates: (94, 517, 136, 568)
Row: 5468 Label: person Probability: 0.5442545413970947 Coordinates: (198, 511, 265, 579)
Row: 5469 Label: person Probability: 0.6227067112922668 Coordinates: (197, 511, 266, 584)
Row: 5470 Label: person Probability: 0.5938160419464111 Coordinates: (198, 511, 265, 584)
Row: 5526 Label: person Probability: 0.7778306603431702 Coordinates: (32, 505, 85, 567)
Row: 5527 Label: person Probability: 0.7625938653945923 Coordinates: (32, 505, 85, 567)
Row: 5533 Label: person Probability: 0.757384717464447 Coordinates: (94, 517, 136, 568)
Row: 5534 Label: person Probability: 0.7053558826446533 Coordinates: (94, 517, 136, 568)
Row: 5535 Label: person Probability: 0.7191171050071716 Coordinates: (94, 517, 136, 568)
Row: 5549 Label: person Probability: 0.6110237836837769 Coordinates: (198, 511, 266, 583)
Row: 5550 Label: person Probability: 0.5887100696563721 Coordinates: (198, 511, 265, 584)
Row: 6044 Label: skateboard Probability: 0.7509363889694214 Coordinates: (321, 594, 410, 620)
Row: 6045 Label: skateboard Probability: 0.7747182846069336 Coordinates: (321, 594, 410, 620)
Row: 6046 Label: skateboard Probability: 0.7707618474960327 Coordinates: (321, 594, 410, 620)
Row: 6124 Label: skateboard Probability: 0.7176411151885986 Coordinates: (321, 594, 411, 620)
Row: 6125 Label: skateboard Probability: 0.7304677367210388 Coordinates: (321, 594, 411, 620)
Row: 6126 Label: skateboard Probability: 0.7161608338356018 Coordinates: (321, 594, 411, 620)
Row: 6915 Label: skateboard Probability: 0.8558311462402344 Coordinates: (513, 176, 596, 266)
Row: 6954 Label: skateboard Probability: 0.8744772672653198 Coordinates: (513, 176, 596, 266)
Row: 6955 Label: skateboard Probability: 0.8591122031211853 Coordinates: (513, 176, 596, 266)
Row: 6956 Label: skateboard Probability: 0.8619626760482788 Coordinates: (513, 176, 596, 266)
Row: 6994 Label: skateboard Probability: 0.8528130054473877 Coordinates: (513, 176, 596, 266)
Row: 6995 Label: skateboard Probability: 0.8457393646240234 Coordinates: (513, 176, 596, 266)
Row: 6996 Label: skateboard Probability: 0.8386139273643494 Coordinates: (513, 176, 596, 266)
Row: 7034 Label: skateboard Probability: 0.8465473651885986 Coordinates: (513, 176, 596, 266)
Row: 7035 Label: skateboard Probability: 0.8342673778533936 Coordinates: (513, 176, 596, 266)
Row: 7036 Label: skateboard Probability: 0.8553557395935059 Coordinates: (513, 176, 596, 266)
Row: 7396 Label: person Probability: 0.9032446146011353 Coordinates: (567, 350, 624, 476)
Row: 7397 Label: person Probability: 0.8893184661865234 Coordinates: (567, 350, 624, 476)
Row: 7436 Label: person Probability: 0.8869150876998901 Coordinates: (567, 350, 624, 476)
Row: 7437 Label: person Probability: 0.8817752599716187 Coordinates: (567, 350, 624, 476)
Row: 7438 Label: person Probability: 0.8791399002075195 Coordinates: (567, 350, 624, 476)
Row: 7476 Label: person Probability: 0.8888946771621704 Coordinates: (567, 350, 624, 476)
Row: 7477 Label: person Probability: 0.8816529512405396 Coordinates: (567, 350, 624, 476)
Row: 7478 Label: person Probability: 0.8753525018692017 Coordinates: (567, 350, 624, 476)
Row: 7516 Label: person Probability: 0.8823326230049133 Coordinates: (567, 350, 624, 476)
Row: 7517 Label: person Probability: 0.8748416900634766 Coordinates: (567, 350, 624, 476)
Row: 7583 Label: person Probability: 0.8930309414863586 Coordinates: (317, 383, 430, 607)
Row: 7584 Label: person Probability: 0.8898133635520935 Coordinates: (317, 383, 430, 607)
Row: 7622 Label: person Probability: 0.8976937532424927 Coordinates: (317, 383, 430, 606)
Row: 7623 Label: person Probability: 0.892180860042572 Coordinates: (317, 383, 430, 607)
Row: 7624 Label: person Probability: 0.8762005567550659 Coordinates: (317, 383, 430, 607)
Row: 7650 Label: person Probability: 0.8702741861343384 Coordinates: (125, 433, 221, 612)
Row: 7651 Label: person Probability: 0.863052248954773 Coordinates: (125, 433, 221, 613)
Row: 7652 Label: person Probability: 0.8755483627319336 Coordinates: (125, 433, 221, 612)
Row: 7662 Label: person Probability: 0.8904131650924683 Coordinates: (317, 384, 430, 608)
Row: 7663 Label: person Probability: 0.8913979530334473 Coordinates: (317, 383, 430, 607)
Row: 7664 Label: person Probability: 0.8908348679542542 Coordinates: (317, 383, 430, 607)
Row: 7690 Label: person Probability: 0.8786476850509644 Coordinates: (125, 433, 221, 613)
Row: 7691 Label: person Probability: 0.8823875188827515 Coordinates: (125, 433, 221, 613)
Row: 7692 Label: person Probability: 0.8871062994003296 Coordinates: (124, 433, 220, 613)
Row: 7703 Label: person Probability: 0.8727951049804688 Coordinates: (317, 383, 430, 607)
Row: 7704 Label: person Probability: 0.8882538676261902 Coordinates: (317, 384, 430, 608)
Row: 7730 Label: person Probability: 0.8640760779380798 Coordinates: (125, 433, 221, 613)
Row: 7731 Label: person Probability: 0.8735520839691162 Coordinates: (124, 433, 220, 612)
Row: 7732 Label: person Probability: 0.8693354725837708 Coordinates: (124, 433, 220, 613)
Row: 7734 Label: person Probability: 0.73056960105896 Coordinates: (197, 511, 265, 584)
Row: 7771 Label: person Probability: 0.8833094835281372 Coordinates: (125, 433, 221, 612)
Row: 7774 Label: person Probability: 0.6753095388412476 Coordinates: (197, 511, 266, 584)
Row: 7775 Label: person Probability: 0.6801181435585022 Coordinates: (198, 511, 266, 584)
Row: 7889 Label: skateboard Probability: 0.552667498588562 Coordinates: (124, 580, 209, 637)
Row: 7890 Label: skateboard Probability: 0.53212571144104 Coordinates: (124, 580, 209, 635)
Row: 7902 Label: skateboard Probability: 0.8670096397399902 Coordinates: (321, 594, 412, 620)
Row: 7931 Label: skateboard Probability: 0.500882625579834 Coordinates: (125, 580, 208, 637)
Row: 7942 Label: skateboard Probability: 0.7937256097793579 Coordinates: (321, 594, 412, 620)
Row: 8054 Label: person Probability: 0.9370934963226318 Coordinates: (351, 24, 589, 255)
Row: 8073 Label: person Probability: 0.9352823495864868 Coordinates: (352, 25, 590, 256)
Row: 8074 Label: person Probability: 0.9121582508087158 Coordinates: (351, 25, 590, 256)
Row: 8075 Label: person Probability: 0.9136118292808533 Coordinates: (351, 25, 590, 255)
Row: 8093 Label: person Probability: 0.9387980699539185 Coordinates: (352, 25, 590, 256)
Row: 8094 Label: person Probability: 0.9149622917175293 Coordinates: (351, 25, 589, 256)
Row: 8095 Label: person Probability: 0.9190929532051086 Coordinates: (351, 25, 590, 255)
Row: 8113 Label: person Probability: 0.9341064691543579 Coordinates: (351, 25, 589, 256)
Row: 8114 Label: person Probability: 0.9218436479568481 Coordinates: (351, 25, 589, 256)
Row: 8115 Label: person Probability: 0.9284915924072266 Coordinates: (351, 25, 589, 256)
Je evidentní, že některé jsou “duplicitní”, protože jsou takřka stejné až na jeden pixel. To by se mělo odstranit, ale nám pro teď bude stačit je prostě všechny nakreslit. Nejdřív si pro každou třédu vygeneruji náhodně RGB barvu a přes cv2 knihovnu začneme zakreslovat obdelníky. Výsledek je velmi dobrý - model servírovaný přes Triton API nám opravdu funguje.
# Generate random color for each class
colors = {}
for class_id in range(80):
colors[class_id] = (np.random.randint(0, 255), np.random.randint(0, 255), np.random.randint(0, 255))
# Show boxes
imgresult = cv2.imread("test.jpg")
for box in boxes:
cv2.rectangle(
imgresult,
(box["coordinates"][0], box["coordinates"][1]),
(box["coordinates"][2], box["coordinates"][3]),
colors[yolo_classes.index(box["label"])],
2,
)
plt.imshow(cv2.cvtColor(imgresult, cv2.COLOR_BGR2RGB))
Tolik tedy k dnešní poslední části. Zkusili jsme výkonnostní charakteristiky různých strojů v Azure, zabalili modely, použili servírovací řešení Triton a to celé zasadili do příjemného managed endpointu v Azure Machine Learning. Tím sérii computer vision s open source projektem YOLO ukončím, ale pokud vás to zajímá, tak bychom se mohli společně podívat i na servírování takovýchto modelů ve větší škále jako kdyby to byla vaše živnost. Kouknout, jak by se na to dalo jít v Kubernetu, balancovat globálně přes víc clusterů nebo vyřešit věci jako rate limit a klíče per zákazník (asi by to hrálo na API Management). Jestli by vás něco takového zajímalo, pinkněte mi zprávičku na LinkedIn.
]]>LLama byl dost silný velký jazykový model (LLM) od Meta, který měl otevřený “kód”, ale váhy ne zcela. Jinak řečeno měli jste vzoreček, ale natrénované hodnoty (výsledek statisíců dolarů trénování) přímo volně ne. To bylo určeno jen pro registrované výzkumníky … nicméně to dlouho nevydrželo a stáhli jste váhy všude na Torrentu. Jenže to hlavní se tím nezměnilo - Llama licenčně zakazovala komerční využití. To tedy platí i pro projekty (Alpaca, Vicuna), které na to navázaly a prováděli jeho fine-tuning, aby model nejen doplňoval text, ale reagoval na instrukce uživatele a mohl si s ním povídat v chat rozhraní. Tím pádem ale i ty jsou pro výzkumné účely a nemůžete je použít ve svém produktu.
Llama 2 tohle mění. Model je vylepšený a přestože není větší, tak je silnější. Navíc přímo od Meta je k dispozici i jeho varianta laděná na instrukce (chat). No a hlavně - celé to je open source a můžete využívat i pro komerční účely.
Podle testů, které Meta dělalo, si model vede velmi dobře. Na GPT-4 rozhodně nemá, ale pro GPT-3 je v některých oblastech konkurentem a to je na open source model opravdu dobré. Jenže, jak uvidíte později, spustit si jeho velkou variantu není jen tak - nároky 70B verze jsou brutální a oproti OpenAI službě myslím neušetříte - naopak. Hlavní výhoda je v otevřenosti (očekávám boom ekosystému nad tím) a možnosti fine-tuningu.
Model Llama 2 přichází ve třech velikostech a dvou variantách. Počet parametrů můžeme chápat jako velikost mozku a vyšší počet znamená potenciálně vyšší inteligenci, ale také dramatický nárůst spotřeby zdrojů a to i pro inferencing (hostování modelu a pokládání dotazů). 7B model (7 miliard parametrů) byste měli být schopni rozběhat na domácím počítači s rozumnou grafikou (Microsoft připravuje ONNX zabalení modelu do Windows), 13B už je trochu náročnější a 70B je masakr (výzkumná práce zmiňuje i 36B variantu, ale ta nebyla uvolněna pro veřejnost).
V porovnání s předchozí generací se velikost mozku prakticky nezměnila (byla 7B, 13B, 33B a 65B), ale délka kontextu (např. kolik informací můžete nahrát do promptu nebo jak dlouho si povídat s udržením kontextu) je teď 4K (místo původních 2K) a hodně narost objem trénovacích dat z 1T resp. 1,4T na 2T (model měl tedy více učebnic k dispozici - konkrétně 2 biliony tokenů).
Jak dlouho se trénovalo? Meta použila NVIDIA A100 GPU (asi 2000 karet a Infiniband networking) - neměli tedy ještě farmu novějších H100, tak jak je postavil Azure pro OpenAI. 7B model potřeboval 184 320 GPU-hodin, 13B model 368 640 a 70B model šílených 1 720 320. Pokud byste byli frajeři a vzali si to v pay-as-you-go z Azure, tak je to cirka 7 milionů dolarů za 70B trénink. Spotřeba nemalá a emise v ekvivalentu vypuštěného CO2 jsou nějakých 150 tun, což je při emisích osobního auta Toyota 100g/km nějaký jeden a půl milionu proježděných kilometrů, tedy asi 37x kolem dokola zeměkoule u rovníku.
To, že Meta dala model a hlavně váhy k dispozici, je velká věc v hodnotě milionů dolarů.
Skvělou novinkou je, že přímo Meta přinesla fine-tunovaný model na chat. Dnes už jsou na to lidé zvyklí a očekávají to. Základní model doplňuje text a dostat z něj co potřebujete vyžaduje dost cviku - model vám totiž často například na otázku reaguje podobnou otázkou, což není co potřebujete. Síla ChatGPT a důvod obrovské popularizace celého odvětví je právě ve fine-tuningu, protože původní GPT-3 model je z roku 2020 a tenkrát takové haló nezpůsobil přičemž ChatGPT nemělo “lepší mozek” (dnes s GPT-4 už je to jiné), jen lepší fine-tuning.
Meta tedy natrénovalo základní model, který si sám četl (self-supervised learning) a stal se z něj skvělý doplňovač textu. V jeho váhách je teď skrytá celá síla modelu, můžete to také vnímat tak, že provedl komprimaci veškerého vstupního materiálu do sebe. Má to v sobě, ale lidem se to špatně loví.
Meta teď vzala tento model a začala ho ladit nad kvalitními supervised learning daty (SFT - Supervised Fine-Tuning) obsahujícími příklady otázek a vhodných odpovědí. Ve studii říkají, že zkoušeli miliony připravených promptů, co jsou dostupné v různých otevřených i komerčních datových sadách, ale nebyli spokojeni s kvalitou výsledného modelu. Podle nich je právě ta kvalita to nejdůležitější. Základní model měl dat dost, nepotřebuje futrovat dalším balastem, ale naopak top kvalitou na doladění. Ve finále použili jen 27 540 anotací, které jim na zakázku připravovali kontraktoři.
Po SFT následuje lidská zpětná vazba (RLHF - Reinforcement Learning Human Feedback), kdy lidé hodnotí odpovědi modelu (na stejnou otázku necháte vygenerovat dvě varianty odpovědi a člověk má vybrat tu lepší) a ten se z toho učí. Hodnotitelé se soustředili hlavně na užitečnost (jestli odpověď pomohla, byla srozumitelná) a bezpečnost (jestli model nevygeneroval něco nevhodného). Celkem získali asi 1,5 milionu takových hodnocení a z toho se model posupně zlepšoval.
Špatně - 90% textů na vstupu bylo v angličtině a k tomu 8,4% unknown (což představuje programovací jazyky). V češtině bylo 0,03%. Později vyzkoušíme v praxi - říct si o nějaký překlad se celkem dá, ale složité dotazy v češtině to nezvládá.
V katalogu modelů v Azure ML si najdu Lllama 2. Bohužel pro nasazení 70B Azure vyžaduje jako minimum stroje ND40rs_v2 nebo ND96 v4 a to je krapet masakr, který ve své subskripci nemám a nedostanu. Tihle mazlíci stojí kolem 30 USD na hodinu (k ceně se ještě dostaneme - na nějaké hraní rozhodně nepočítejte, že díky Llama ušetříte za OpenAI, naopak). Jdu tedy do modelu 7B, který jsem schopen rozběhat na NCv3 s V100 kartou (a mimochodem 13B už se mi nevejde do paměti karty … mazec a to je to jen inferencing).
Základní model lze dotrénovat - ale na fine-tuning se podíváme jindy.
Já tedy jdu nasadit real-time endpoint pro 7B chat model a polituji svou kartu kreditní (kecám, mám na interní útratu kredit … ale není neomezený).
Po asi čtvrt hodině je endpoint nahoře.
Můžeme z GUI otestovat - funguje to.
Tady je endpoint, klíč a kód do začátku.
Lidé od ML jsou asi trochu (l)lamy na vytváření klientských aplikací na web a já nejsem ani “od ML”, takže jsem na tom ještě hůř. Právě proto ale existuje výborná Python knihovna Gradio, která umožňuje velmi jednoduše generovat příjemné webové klikátko pro testování AI věcí jako je chat nebo obrázky. Naučil jsem se asi za dvě hodiny a je to opravdu milé.
Tady je výsledný kód.
import random
import gradio as gr
import urllib.request
import json
import os
import ssl
url = os.environ.get('AML_INFERENCE_URL')
api_key = os.environ.get('AML_INFERENCE_KEY')
headers = {'Content-Type': 'application/json', 'Authorization': (
'Bearer ' + api_key), 'azureml-model-deployment': 'llama-2-7b-chat-4'}
def get_response(message, history, max_length, max_new_tokens, temperature, top_p):
print(f"{message=}")
print(f"{max_length=} {max_new_tokens=} {temperature=} {top_p=}")
# Add conversation history
input_string = []
for user, assistant in history:
input_string.append({
"role": "user",
"content": user
})
input_string.append({
"role": "assistant",
"content": assistant
})
# Add new message
input_string.append({
"role": "user",
"content": message
})
# Prepare whole request
data = {
"input_data": {
"input_string": input_string,
"parameters": {
"max_length": max_length,
"temperature": temperature,
"top_p": top_p,
"do_sample": True,
"max_new_tokens": max_new_tokens
}
}
}
body = str.encode(json.dumps(data))
req = urllib.request.Request(url, body, headers)
try:
response = urllib.request.urlopen(req)
output = json.loads(response.read())["output"]
print(f"{output=}")
except urllib.error.HTTPError as error:
print("The request failed with status code: " + str(error.code))
# Store history
history.append((message, output))
return "", history
with gr.Blocks() as demo:
with gr.Row():
gr.Label("Tomas Llama 2 chatbot example with Azure ML and Gradio", font_size=30, show_label=False)
with gr.Row():
with gr.Column(scale=4):
chatbot = gr.Chatbot(height=600)
msg = gr.Textbox(show_label=False)
with gr.Row():
clear = gr.ClearButton([msg, chatbot])
submit = gr.Button(value="Send", variant="primary")
with gr.Column(scale=1):
max_length = gr.Slider(1, 4000, value=200, label="Max length")
max_new_tokens = gr.Slider(1, 4000, value=200, label="Max new tokens")
temperature = gr.Slider(0.1, 1.99, value=0.6, label="Temperature")
top_p = gr.Slider(0.01, 0.99, value=0.9, label="Top p")
msg.submit(get_response, [msg, chatbot, max_length, max_new_tokens, temperature, top_p], [msg, chatbot])
submit.click(get_response, [msg, chatbot, max_length, max_new_tokens, temperature, top_p], [msg, chatbot])
if __name__ == "__main__":
demo.launch()
Po spuštění vznikne webový server a stačí se připojit a frčíme.
Začněme jednoduchým příkladem na parsování textu a uložení do JSON - to dopadlo velmi dobře. Pak jsem poprosil o překlad do češtiny a pomeranče jsou údajně oranžky a švestky jsou slímy. Mno, češtinu teda raději moc ne.
Zkusíme kontext a minimalistické uvažování a není to špatné.
Co se vrátit k češtině a požádat o shrnutí? To sice nezafungovalo, ale dostali jsme velmi slušný překlad.
Zkusme si nechat sumarizovat tenhle článek: https://blogs.microsoft.com/blog/2023/07/18/microsoft-and-meta-expand-their-ai-partnership-with-llama-2-on-azure-and-windows/
Na 7B model to je dobré.
Dejme o malinko složitější logické uvažování - to už rozhodně nevyšlo.
Tady třeba máme správný výsledek s naprosto nesmyslným postupem a nesprávným výčtem dalších pravděpodobností v pořadí. Kdyby to byl žák, řekli byste, že je úplně mimo a jen výsledné číslo někde opsal.
Zkusme nějakou klasifikaci a analýzu sentimentu. Kromě rozjetého formátování to není úplně špatné - respektive před pár lety byste za tohle trhali ruce.
Napíše pro nás něco nevhodného? Ne, oproti jiným open source modelům tady Meta skutečně dávala na bezpečnost důraz.
Zkusíme nějakou kreativitu. První pokus udělal něco jiného, než jsem chtěl.
Co tedy něco podstatně jednoduššího - korporátní bullshit generátor? Tak ten evidentně dobře zvládne i trochu tupý 7B open source model.
Rozběhat Llama 2 na něčem levném je možné, ale bude potřeba i ten základní 7B model vzít a kvantizovat (snížit počet míst za desetinnou čárkou, tedy zaokrouhlovat, snížit přesnost), což v krajním případě může vést i na schopnost běžet to na CPU (i tak to bude nepříjemně pomalé), ale GPT-Chat 3.5 kvalitě se ani nepřiblížíte. 70B varianta je podle všeho na tom velmi dobře a přestože na ChatGPT 3.5 ztrácí v logickém uvažování, tak na mnoho použití bude relevantní alternativou. No jo - jenže za kolik?
70B neumím změřit, ale podívejme na co jsme dnes zvládli nasadit - 7B model bez kvantizace běžící na stroji s cenou asi 12 USD na hodinu. 1k tokenů na vstupu s výsledkem 150 tokenů na výstupu trvalo zpracovat 13 vteřin. Počítejme to tak, že tohle uděláme 1000x sekvenčně za sebou (ať nemáme takové centy). 1M tokenů na vstupu, 150k tokenů na výstupu a spotřebovaný čas 3,61 hodiny. Mám tam NC12v3 za cirka 12 USD na hodinu. Takže při této 100% utilizaci (to je samozřejmě naprosto nereálné, v malém prostředí budete mít využitelnost daleko nižší - leda by šlo o nějaký batch model, kdy zpracováváme dokumenty, pak by to šlo) je to 43 USD.
Kolik mě bude stát podstatně chytřejší ChatGPT-3.5 (nezapomeňme, že nesrovnáváme se 70B modelem ale jen 7B, který je kvalitativně úplně jinde)? 2,3 USD.
Jasně - pro dlouhodobé používání bychom compute rezervovali, bude výhodnější použít novější GPU, určitě to půjde ještě nějak optimalizovat, ale co je myslím zřejmé je to, že tady výnosy z rozsahu hrají zásadní roli. Myslím, že v případě Llama 2 nebude primárním důvodem pro její využití v enterprise cena. Síla je v otevřenosti, díky které můžete řešit fine-tuning, využívat různé upravené váhy jak se budu objevovat od různých institucí (určitě vzniknou naladěné modely na programování nebo nějaké specifické obory) nebo provozovat model na vlastním železe třeba pro případ IoT Edge scénářů tam, kde nemáte konektivitu (ale upřímně takových situací moc nebude … a jasně, můžeme se bavit o latenci, ale model reaguje ve vteřinách, pár milisekund za případnou cestu ke cloudu nehraje skoro žádnou roli). Samozřejmě po kvantizaci a optimalizacích se ale třeba dostanete až k tomu, že se model rozjede v omezené míře třeba na telefonu - jenže zase - v dnešní propojené době chcete rozžhavený telefon s baterkou na hodinu s pomalým lobotomicky zmrzačeným modelem, když se dá zeptat přes Internet?
Doladitelnost a otevřenost - to jsou za mě hlavní výhody Llama 2 a je super, že jsou v Azure na kliknutí.
]]>Dnes tedy zkusíme:
Jako obvykle data najdete na mém GitHubu a dnes se budeme pohybovat v tomhle notebooku
Pojďme vzít naše data, kterých je ale strašně málo, a prohnat je stejnou topologií, kterou YOLO používá u natrénovaného modelu velikosti nano, nicméně od začátku - bez předtrénovaných vah.
# Load empty model
model = YOLO('yolov8n.yaml')
# Train the model
train = model.train(data='./datasets/2plysaci.yaml', epochs=2000, patience=0, imgsz=1024)
# 2000 epochs completed in 0.507 hours.
Tím, že model jede od začátku a máme velmi malé množství dat, bylo potřeba udělat poměrně dost epoch. Střelil jsem jich 2000 a A100 v Azure je stihla za asi 30 minut. Když se podíváme do grafů, tak loss funkce zvolna klesají, vybavovací schopnost i přesnost na validační sadě jde nahoru, vypadá to rozumně.
Na testovací fotce (pochází z původního období, ale není použita ani v trénovací ani validační sadě) jsou výsledky dobré.
V dnešním díle do toho přimícháme fotku z nové sady, kde je taky oslík, ale o 5 let starší. Model ho nějak poznal, byť s žádnou jistotou - je to hlavně chyba naší extrémně malé trénovací sady. Na kvalitní model vytvořený z nuly potřebujete tisíce fotek (ideálně miliony).
Výsledek:
V minulém díle jsme viděli, že profesionální na pořádných datech trénovaný model nám umožnil za pár minut trénování ve 100 epochách dosáhnout asi i lepších výsledků, než náš vlastní model. My jsme si právě pracně udělali vlastní model z nuly na dva plyšáky, ale teď máme třetího. Dokážeme přenést váhy z dvouplyšákového modelu na prasátka a rychle dostat nějaký rozumný výsledek?
# Load model_2plysaci
model = YOLO('2plysaci_custom_n.pt')
# Train the model
train = model.train(data='./datasets/prasatko.yaml', epochs=100, patience=0, imgsz=1024)
# 100 epochs completed in 0.025 hours.
Pohled do grafů ukazuje, že nám loss funkce velmi rychle padají kam potřebujeme a mAP50-95 rychle vyroste. Evidentně tedy náš předtrénovaný model nemá zas tak moc práce se přizpůsobit na prasátka.
V první testovací fotce je výsledek velmi pozitivní.
Druhá už není nic moc, prasátka tam vidí dvě, ale nějak úplně mimo to taky není. Nicméně samozřejmě oslík nic - to se čekalo.
Výsledek:
Jak se dostat k modelu, který bude umět všechny tři plyšáky, ale neutratit za kompletní trénování z nuly? Můžeme převést váhy původního modelu a trénovat ho dál nad všemi daty, nejen nad novými. V našem případě to výpočetně nebude velký rozdíl (k cirka 10 novým fotkám přidáme 25 původních), ale pokud bych chtěl model trénovaný na COCO sadě tisíců fotek rozšířit o svoje plyšáky, tak se místo v desítkách obrázků rázem budu pohybovat v desetitisících a to sežere víc výkonu. Nicméně - i tak by mělo platit, že model má skvělé startovací váhy a učí se řádově rychleji.
# Load model_2plysaci
model = YOLO('2plysaci_custom_n.pt')
# Train the model
train = model.train(data='./datasets/3plysaci.yaml', epochs=100, patience=0, imgsz=1024)
# 100 epochs completed in 0.033 hours.
Grafy vypadají dobře - loss se snižuje, přesnost a vybavování jde nahoru.
Tenhle model velmi pěkně pokrývá oslíky i prasátka dohromady.
Výsledek:
Pojďme to teď srovnat se situací, kdy vezmeme všechna data a uděláme to co na začátku - natrénujeme model z nuly.
# Load empty model
model = YOLO('yolov8n.yaml')
# Train the model
train = model.train(data='./datasets/3plysaci.yaml', epochs=2000, patience=0, imgsz=1024)
# 2000 epochs completed in 0.556 hours.
Grafy jsou velmi podobné a jdou celkem správným směrem (byť nám v konci už model nedělá zlepšení v mAP50-95).
Jak to dopadne s testovací fotkou?
A co tady?
Výsledek:
Já si z toho všeho dělám tyto závěry:
Zkuste si to - stačí vzít moje notebooky a napojit je na compute instance v Azure Machine Learning a frčíte. Příště zkusím prozkoumat jak z modelu udělat nějaké API a zamyslet se nad tím, kolik mě jeho provoz bude stát a jestli nebude lepší si vzít hotovou kognitivní službu.
]]>Budu si hrát se svojí oblíbenou sadou, která je nesmírně primitivní - dva plyšáci, 23 fotek na trénování, 3 na validaci, 2 na test. To je samozřejmě strašně málo a měli byste mít vždy daleko víc, ale pro základní představu tohle stačí (ostatně už tyhle fotky používám asi šest let na rychlé vyzkoušení). Těch pár let co uplynulo od pořízení těch fotek dramaticky snížilo jejich oblíbenost díky nástupu puberty jejich majitele, tak snad mají radost, že jejich machine learning hodnota zůstala zatím zachována.
Jako obvykle data najdete na mém GitHubu a dnes se budeme pohybovat v tomhle notebooku YOLO formát pro popis obdelníků pro objekty používá txt soubor ke každému obrázkovému souboru a v něm jednoduše ID objektu a čtyři souřadnicová čísla (resp dvě souřadnice středu + šířka a délka rámečku) - co objekt to řádek. Pokud jste označování objektů udělali jako projekt v Azure, tak to podporuje výstup jen v COCO formátu, takže pak musíte převádět (nebo použijte CVAT, Label Studio nebo třeba Roboflow). Zkrátka AML labelování je ideální, pokud data budete dál zpracovávat v AML, protože vyplivne rovnou MLtable formát, který je vstupem třeba do AutoML. Nicméně to zatím nemá yolov8 (jen yolov5), ale i když bude mít, tak zatím chci zůstat v notebooku, abychom si to osahali.
Samozřejmě - tohle je strašně málo, dělat validaci na třech fotkách je samozřejmě mimo … nicméně principy nám odhalí i to.
Moje úloha má docela blízko ke generickým objektům tak jak jsou třeba v COCO sadě, která byla použita pro natrénování YOLOv8. Celá finta je, že si do modelu načtu předtrénovaný yolo model, například ve variantě object detection velikosti nano - stejně jako jsme to dělali minule. Tedy topologii, vypočítané váhy, všechno.
model = YOLO('yolov8n.pt')
Minule jsme mu předali obrázek a už to frčelo. Teď ale uděláme něco jiného - připravíme si data (popíšeme jejich strukturu v YAMLu) a rozjedeme trénování. Borci model natrénovali na velkém množství dat a výsledkem toho všeho jsou vlastně jen váhy, tedy hodnoty, které dosadíme za neznámé do vzorců. My teď tyhle hodnoty (váhy) vezmeme a na našich datech je budeme brát jako výchozí a budeme ladit dál. Nějaké dvě stovky vrstev a mraky parametrů už umí rozpoznávat tvary, přechody, hrany, textury, ale i ouška, nosy a nepotřebujeme první vrstvy moc měnit (rozpoznávají typicky hodně nízkoúrovňové věci typu hrany), ale ty pozdější už trochu ano a zejména na konci ty klasifikační vrstvy zcela (to, kde se z detekovaných vlastností určí jaká je to kategorie odstřihneme a dodáme svoje třídy a vrstvy). YOLOv8 to udělá, stačí zapnout trénink.
train = model.train(data='./datasets/2plysaci.yaml', epochs=100, imgsz=1024)
Vzal jsem tedy nejmenší model a rozjel 100 epoch. Z grafů se zdálo, že model se ještě chvilku zlepšoval, ale výsledky na test sadě nebyly dobré, takže 100 epoch evidentně na můj scénář stačilo. Vidím, že moje A100 se moc nezapotila a do dvou minut to měla zmáknuté.
100 epochs completed in 0.028 hours.
Optimizer stripped from runs/detect/train13/weights/last.pt, 6.3MB
Optimizer stripped from runs/detect/train13/weights/best.pt, 6.3MB
Validating runs/detect/train13/weights/best.pt...
Ultralytics YOLOv8.0.120 🚀 Python-3.8.5 torch-1.12.0 CUDA:0 (NVIDIA A100 80GB PCIe, 80995MiB)
Model summary (fused): 168 layers, 3006038 parameters, 0 gradients
Class Images Instances Box(P R mAP50 mAP50-95): 100%|██████████| 1/1 [00:00<00:00, 44.20it/s]
all 3 6 0.987 1 0.995 0.888
oslik 3 3 0.986 1 0.995 0.929
ovecka 3 3 0.988 1 0.995 0.847
Speed: 0.1ms preprocess, 2.7ms inference, 0.0ms loss, 0.9ms postprocess per image
Máme tady model s 3M parametry a všimněte si, že soubor s jeho výsledky má asi 6MB (samozřejmě stejně jako původní model -> k žádné významné změně velikosti nedošlo, jen jsme trochu jinak udělali váhy a tak). Na testovací fotce to vyšlo opravdu pěkně.
Když koukneme na metriky, tak je vidět, že model se krásně učil a mAP50-95 se vyšplhalo příjemně vysoko (jak jsem psal - validační i trénovací sada je směšně malá, takže to trochu lítá, ale trend tam je).
Pro jistotu si ještě ukážeme nějaký jiný obrázek. Očekáváme, že na něm neuvidí model oslíka nebo ovečku, ale taky bohužel nepozná člověka (klasifikaci původního modelu jsme nahradili plyšáky).
Skvělé. A100 mám nažhavenou, dáme větší model s 11M parametry. Jenže moje množství dat je opravdu směšně malé a nezdá se, že by nano model nebyl dostatečně komplexní na to, aby moje plyšáky pochopil. Nejen, že možná zaplatím zbytečně, ale větší model bude mít tendenci se přetrénovat a vidět pak oslíky úplně ve všem.
100 epochs completed in 0.093 hours.
Optimizer stripped from runs/detect/train12/weights/last.pt, 22.6MB
Optimizer stripped from runs/detect/train12/weights/best.pt, 22.6MB
Validating runs/detect/train12/weights/best.pt...
Ultralytics YOLOv8.0.120 🚀 Python-3.8.5 torch-1.12.0 CUDA:0 (NVIDIA A100 80GB PCIe, 80995MiB)
Model summary (fused): 168 layers, 11126358 parameters, 0 gradients
Class Images Instances Box(P R mAP50 mAP50-95): 100%|██████████| 1/1 [00:00<00:00, 45.54it/s]
all 3 6 0.973 1 0.995 0.941
oslik 3 3 0.992 1 0.995 0.93
ovecka 3 3 0.954 1 0.995 0.952
Speed: 0.2ms preprocess, 2.6ms inference, 0.0ms loss, 0.6ms postprocess per image
Za nějakých 6 minut to je hotové a výsledky, asi dle očekávání, nejsou nějak lepší.
Výsledek v pořádku, byť s nižší jistotou.
Pro zajímavost pojďme přitočit - dejme model s 43M parametry.
57 epochs completed in 0.072 hours.
Optimizer stripped from runs/detect/train11/weights/last.pt, 87.7MB
Optimizer stripped from runs/detect/train11/weights/best.pt, 87.7MB
Validating runs/detect/train11/weights/best.pt...
Ultralytics YOLOv8.0.120 🚀 Python-3.8.5 torch-1.12.0 CUDA:0 (NVIDIA A100 80GB PCIe, 80995MiB)
Model summary (fused): 268 layers, 43608150 parameters, 0 gradients
Class Images Instances Box(P R mAP50 mAP50-95): 100%|██████████| 1/1 [00:00<00:00, 18.79it/s]
all 3 6 0.5 0.833 0.602 0.475
oslik 3 3 0.5 0.667 0.474 0.319
ovecka 3 3 0.5 1 0.731 0.632
Speed: 0.1ms preprocess, 5.6ms inference, 0.0ms loss, 7.5ms postprocess per image
Model zastavil dřív (po 50 epoch po sobě se nezlepšil), po přepočtu na 100 epoch by to trvalo nějakých 8 minut (A100 se konečně trochu procvičí). Dejme testovací obrázek a safra - někdo nám to tady s učením přehnal.
Metriky neukazují nic dobrého - recall i precision létá tam a zpátky, mAP50-95 je tragická, validační loss funkce mají extrémní hodnoty.
Když se podíváme znovu na fotku človíčka, model vidí všude plyšáky.
Máme tady jasný overfit. Dělat rozmáchlé modely když nemáme pořádná data evidentně nedává smysl.
V předchozím scénáři jsme ovliňovali všechny vrstvy. Fine-tuning modelu se někdy dělá tak, že prvotní vrstvy modelu zamkneme - nepřipustíme jejich změnu, jejich učení, a ladíme až pozdější vrtvy, které představují už reprezentace vyšších vlastností (místo hran třeba ouška). To může snížit dobu učení (zejména pokud máme relativně hodně nových dat) a snížit overfit. Extrémní podoba pak je, že všechny vrstvy zpracování obrazu zmrazíme a přetrénujeme jen klasifikační vrstvy (computer vision obvykle funguje tak, že má poměrně dost konvolučních vrstev, tedy těch co nejsou plně, ale místně propojené, analyzují související oblasti obrazu a postupně extrahují vyšší a vyšší vlastnosti - a nad nimi jsou plně propojené vrstvy klasifikační, které interpretují výsledek zpracování obrazu). Tomu se pak říká feature extraction. Necháme model zpracovávat obrázky beze změny, ale výsledný set features budeme jinak interpretovat.
YOLOv5 mělo zamykání přímo ve svém API, ale u v8 už to není. Zdá se, že důvodem je, že rychlost trénování v8 to zas tak zásadně neovlivňuje, tak to tam nedali. Nicméně lze to udělat přes callback, kdy se na začátku trénování model předá naší funkci, která proběhne vrstvy a pár prvních zmrazí (v Pytorch nastaví requires_grad
na False
).
def freeze_layer(trainer):
model = trainer.model
num_freeze = 10
print(f"Freezing {num_freeze} layers")
freeze = [f'model.{x}.' for x in range(num_freeze)] # layers to freeze
for k, v in model.named_parameters():
v.requires_grad = True # train all layers
if any(x in k for x in freeze):
print(f'freezing {k}')
v.requires_grad = False
print(f"{num_freeze} layers are freezed.")
# Uncomment to freeze layers
model.add_callback("on_train_start", freeze_layer)
Vezměme si model velikost L. Ten jak jsme dříve viděli trpěl na našem extrémně malém vzorku dat masivním přetrénováním. Co když zamknu prvních 10 vrstev? Čas trénování počítaný na 100 epoch klesl z 8 na 6 minut na mé A100 v Azure, což není nějak velká úspora, ale u většího množství dat, kde by celé trénování bylo třeba o řád větší, už nějaký ten dolárek ušetřím. Podstatnější ale je, že zamčením iniciálních vrstev bychom měli i snížit schopnost modelu udělat rychlý overfit.
Obrázek plyšáku dopadl skutečně nadmíru dobře.
V obrázku bez plyšáků ale stále vidíme dost velký overfit, nicméně srovnejte s předchozím odstavcem - dramatické zlepšení.
Když koukneme na metriky, tak vypadají daleko příčetněji. Loss funkce při trénování klesají, vybavovací schopnost i přesnost rostou.
A co když mu zamknu 30 vrstev? To už je evidentně moc (u YOLOv5 se doporučovalo zkoušet zamykat něco mezi 5 a 10 vrstvami). Situace je ale pořád lepší, než u úplně původního scénáře velkého modelu.
Metriky jsou opět zběsilé - hodně skáčou, model se evidentně neučí moc dobře.
Obecně vzato zdá se, že kvalitativně je lepší provádět fine-tuning. Feature extraction může být ale dobrá volba tam, kde je nových dat strašně moc a rozdíl v nákladech na změnu modelu je zásadní. Třeba jako dočasné opatření, než uděláte plnohodnotný fine-tuning nebo dokonce svůj vlastní model (a to je námět dalšího dílu).
Dnes jsme si tedy vyzkoušeli fine-tuning modelu, transfer learning. Využili jsme výsledky někoho jiného, kdo utratil spoustu peněz za běh GPU, a nad tím rychle vytrénovali naše plyšáky. Nicméně všimněte si, že teď máme model na plyšáky a model na to ostatní - ale ne dohromady. To nemusí vadit, spojíme si to aplikačně, ale ne vždy je to výsledek co chceme.
Příště se podíváme na to, jak natrénovat úplně vlastní model, jak dělat transfer learning z vlastního modelu na nová data a srovnáme výpočetní náročnost s přetrénováním se starými i novými daty.
]]>GPT-4 je skvělé a je to asi nejlepší jazykový model, který je dnes k dispozici. Jestli někdo OpenAI a Microsoft v oblasti obrovských modelů může ohrozit, tak hlavně Google a Facebook, ale sledovat je vhodné i Apple, Baidu, Amazon a snad stále ještě IBM (smutný příběh) a samozřejmě i některé univerzity a startupy. Jenže - tyhle modely je opravdu drahé trénovat i provozovat. GPT-4 stojí 0,06 nebo 0,12 USD na 1000 tokenů (za odpovědi a záleží na požadované délce kontextu 8k vs 32k), zatímco klasické GPT-3 je za 0,02 USD a speciálně odladěné zefektivněné GPT-3.5 (to je pod ChatGPT) pak jen 0,002 USD. To mimochodem může naznačovat, že by se v oblasti LLM mohl objevit tick-tack rytmus jako u procesorů (nejdřív nový lepší model s velkou spotřebou a pak jeho efektivnější varianta a tak pořád dokola). Spekuluje se, že Google PaLM 2 (jejich hlavní želízko v ohni proti Microsoftu a OpenAI) je nákladově ještě dražší a to může být pro profitabilitu Googlu problém. Ostatně Microsoft Megatron-Turing NLG měl v v době svého uvedení v roce 2021 3x víc parametrů, než GPT-3 - jenže výsledek nebyl nějak přelomový a náklady enormní, tedy model byl značně nepraktický. Celý projekt tak pro Microsoft a NVidia měl přínos hlavně v prozkoumání limitů scale-up přístupu a díky těmto zkušenostem Azure dokázat pro OpenAI postavit superpočítač pro trénování GPT-4.
Transformery umožnily říct žákům, že si mají sami prostudovat předložený text - použít unsupervised learning. To umožnilo neuvěřitelně zvětšit množství dat použitelných pro trénování a díky tomu mají LLM v sobě ohromný potenciál. Nicméně jakákoli chytrost takového modelu je pohřbená někde uvnitř a je velmi obtížné s ním pracovat. Jediné co chce, je doplňovat předložený text. Když mu dáte otázku, udělá vám třeba 10 variací na stejnou otázku. Úspěch věcí jako je ChatGPT je v tom, že byly následně laděny supervised learningem nad vysoce kvalitními lidmi připravenými datovými sadami, často se modely speciálně učí reagovat na instrukce (bez toho by prompt engineering ani pořádně neexistoval) nebo konverzování. A to je často laděno s použitím Reinforcement Learning with Human Feedback, kdy odpovědi modelu lidé hodnotí a ten se zlepšuje (mimochodem na úkor přesnosti a kreativity -> pokud chcete napsat báseň, možná vám základní model dá víc inspirace, než jeho ChatGPT varianta). Další techniky pak nejsou přímo v ladění modelu (zatím), ale vychází z promptu - například Chain of Thought (CoT). Technika, kdy koučujete model k tomu, aby v úloze postupoval pomalu, krok za krokem a jednotlivé úkony vám průběžně vysvětloval. Některé jdou ještě dál za rámec jediného dotazu,reagují na výstupy modelu a podsouvají mu věci zpět. Asi nejznámější je AutoGPT nebo AgentGPT (pozor na náklady, tohle se strašně snadno zvrtne).
Takže když to shrneme:
GPT-4 je drahé, ale levnější, než lidi. Pro malý jazykový model tak může znamenat skvělého učitele. Pokud děláte matematiku na základce, dokážete posunout děti a potažmo celé lidstvo dál, aniž vy sami jste největším matematikem na světě. Místní sportovní trenér možná není mistr světa, ale svoje svěřence toho naučí opravdu hodně. Ne každý je geniální matematik nebo sportovec a pro začátečníky to stačí. Ne každý je člověk a GPT-4 je pro malý model výborný učitel.
Alpaca je projekt, který se snaží naučit malý 7B LLaMA model reagovat na instrukce. Dělají to za použití techniky self-instruct, kdy přes GPT-3 generují příklady instrukcí a jejich odpovědí na ně a touhle sadou 52000 příkladů (představte si kolik času by stálo získat stejné množství dat od lidí) ladí váhy modelu.
Vicuna využívá data z ShareGPT, má tedy lidské dotazy, ale ChatGPT odpovědi na ně. Projekt tvrdí, že dosáhl lepších výsledků, než Alpaca a zavedl jedno zajímavé hodnocení. Trénovací data dělalo ChatGPT (GPT-3.5), ale vyhodnocování a srovnání modelů provádí GPT-4. Do promptu mu napíšete něco ve smyslu, že dostane odpovědi na otázku od dvou asistentů a má zhodnotit, kdo si vedl lépe. Moc exaktně to tedy nezní, ale je to rozhodně zajímavé. Celá historie počítačů je o tom najít něco, co počítač následně bez lidského zásahu dokáže dokola a dokola opakovat. Pracuje, když vy spíte. Teď se bude učit, když vy spíte.
Zastavme se u nákladů. LLaMA je samozřejmě malý model a i tak náklady na trénování nejsou zanedbatelné - 82000 GPU hodin u 7B a 135000 u 13B modelu (soudě podle informací z předchozích odkazů). To je u 13B modelu v Azure s ND96asr A100 v4 (ta má 8x GPU) nějakých 600k USD v PAYG a 280k USD ve spot instancích. A teď si představte kolik stojí ty opravdu velké modely. Nicméně dotrénování ve stylu Alpaca nebo Vicuna je prý už jen otázka pár stovek dolarů. Myslím, že je to vlastně stejné jako u OpenAI, jen řády jsou jinde - na vytrénování modelu unsupervised learningem spotřebujete majoritu peněz za infrastrukturu, ale za ladění spotřebujete hodně času a lidské práce. Ta je ale v případě Alpaca generována s pomocí GPT-3.5 turbo a 52000 instrukcí, jak koukám každá má tak 200 tokenů, to znamená náklad tak 20 USD.
To nás vede k opuštění lamám podobným zvířat a pojďme na to rybaření a kosatku - project Orca od Microsoftu. Ten se zaměřuje na to, že studie jako Vicuna sice dobře imitují schopnosti LLM pracovat s instrukcemi a reagovat na otázky, ale neučí se od něj uvažovat, zdůvodňovat a jsou tedy plytké. Hodí se třeba do počítačové hry, ale méně pro logické úlohy nebo různé školní zkoušky. Kudy na to jdou?
Kvalitu modelu chtějí zkoumat i exaktněji, než že se k němu vyjádří GPT-4, takže to dělají na otázkách ze zkoušek. Model ladí tak, že vezmou otázku a odpověď (podobně jako předchozí zmíněné modely), ale k tomu přidají krok za krokem přemýšlecí postup generovaný učitelem (prompt typu vysvětli to jako pětiletému dítěti krok za krokem). Není to tedy jen běžný instruction tuning, ale jde o snahu koučovat model i co do způsobu uvažování. Zajímavé je, že používali jako učitele jak ChatGPT (GPT-3.5 turbo), tak i o dost kvalitnější (a dražší) GPT-4. Důvody samozřejmě byly v nákladech a rychlosti, ale objevila se ještě jedna zajímavost. Přemýšlecí postup GPT-4 byl na malý 13B model hodně náročný a ten to nepobíral. Ukázalo se, že je nejlepší nejdřív model ladit s ChatGPT (hloupější, méně náročný učitel) a pak až přejít na GPT-4 dolaďování (něco jako když potřebujete nejdřív nasát základy a pak až jít do většího detailu).
Jak to dopadlo? V hodnocení GPT-4 dopadla Orca opravdu dobře, na úrovni ChatGPT - ale to je pocitovka, v které na tom nebyla špatně ani Vicuna (nicméně bylo vidět, že holá LLaMA je hodně pozadu). U profesionálních a akademických zkoušek už je ale rozdíl patrný - Orca je o něco hroší, než ChatGPT, ale výrazně před Vicuna. Samozřejmě však na pana profesora GPT-4 tady nikdo ani náhodou nemá.
Já si z toho dělám tyto závěry:
Dnes se zaměříme na první část - natrénovaný model, který nebudeme nijak měnit.
Aktuálně jde o čtyři kategorie problémů:
Pro dnešní účely budu pracovat v Jupyter notebooku, který si připojím na Azure Machine Learning compute mašinu pro začátek s pouhým CPU (výkonnostním a cenovým otázkám se budu věnovat později).
Notebook najdete zde: https://github.com/tkubica12/ai-demos/blob/main/yolo/trained_model.ipynb
Nejdřív nainstalujeme a importujeme YOLOv8.
# Install YOLOv8
%pip install ultralytics
%pip install opencv-python
# Import YOLOv8
from ultralytics import YOLO
# Import image visualization
import cv2
Následně jsem si stáhl sadu obrázků z COCO soutěže 2017.
# Download COCO dataset
!wget http://images.cocodataset.org/zips/train2017.zip
!wget http://images.cocodataset.org/zips/val2017.zip
!wget http://images.cocodataset.org/zips/test2017.zip
!wget http://images.cocodataset.org/annotations/annotations_trainval2017.zip
!wget http://images.cocodataset.org/annotations/stuff_annotations_trainval2017.zip
!wget http://images.cocodataset.org/annotations/panoptic_annotations_trainval2017.zip
# unzip
!unzip train2017.zip
!unzip val2017.zip
!unzip test2017.zip
!unzip annotations_trainval2017.zip
!unzip stuff_annotations_trainval2017.zip
!unzip panoptic_annotations_trainval2017.zip
Vybuduji si seznam názvů souborů v testovací sadě.
# Get list of files
import os
folder_path = 'test2017'
files = os.listdir(folder_path)
Následně budeme ukazovat náhodně vybraný původní obrázek a k němu scoring za detekci objektů, segmentaci a pozici těla. Použiji model velikosti L - tedy druhý největší, který dává skvělé výsledky a přitom nemusím ani na CPU dlouho čekat (nicméně do realtime to má daleko - výkonnost a nasazení v Azure budeme zkoumat v jiné části).
# Select random file
import random
random_filename = f"{folder_path}/{random.choice(files)}"
print(random_filename)
# Show original image
%matplotlib inline
from matplotlib import pyplot as plt
img = cv2.imread(random_filename)
plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
# Select object detection pretrained model
model = YOLO('yolov8l.pt')
# Score and show results
results = model(random_filename)
res_plotted = results[0].plot()
plt.imshow(cv2.cvtColor(res_plotted, cv2.COLOR_BGR2RGB))
# Select segment detection pretrained model
model = YOLO('yolov8l-seg.pt')
# Score and show results
results = model(random_filename)
res_plotted = results[0].plot()
plt.imshow(cv2.cvtColor(res_plotted, cv2.COLOR_BGR2RGB))
# Select pose detection pretrained model
model = YOLO('yolov8l-pose.pt')
# Score and show results
results = model(random_filename)
res_plotted = results[0].plot()
plt.imshow(cv2.cvtColor(res_plotted, cv2.COLOR_BGR2RGB))
Pojďme se podívat na pár příkladů. Tady je poměrně složitá situace, kdy je člověk částečně schovaný za scateboardem. Doporučuji vaší pozornosti přesnost obou, přestože jsou v zákrytu a taky fakt, že boty v horní části jsou správně byť s nižší pravděpodobností (a to taky sedí) identifikovány jako další osoby.
Podívejme se ale na modernější kategorii - segmentace. V tomto případě červeně obarvíme pixely osob a fialově scateboard. Výsledky jsou za mě úžasné - všechny překryvy a ruce jsou prostě správně.
Na pozici tohle není ideální obrázek, přesto mám celkem rozumnou představu o detekovaných kloubech - ale není to vůbec ono, dva kotníky na jedné noze tam opravdu nejsou. Ale asi bych odpustil, navíc takový obrázek není pro zamýšlené použití detekce pozice těla nějak reprezentativní (kvůli výřezu).
Tady je další hezký příklad segmentace.
Tady to ale AI nedalo, nicméně je to opravdu těžké. Řekl bych, že vy to dokážete kvůli tomu, že si jdete přepočítat nohy - ale z hlav byste to taky nemuseli zvládnout.
Podívejme se na příklad s tenistou a zejména jeho detekci pozice.
Pozice surfaře.
A scateboardisti.
Dva týpci.
Takhle vypadá hromada plyšáků po segmentaci.
Autíčka.
Baseball.
Lyžarka.
Pěkná paní.
Pán s donuty.
Segmentace slonů a lidí.
Ptáci a pán s batohem.
Za mě musím říct, že YOLOv8 funguje opravdu skvěle a to i ve srovnání se službami typu Azure Cognitive Services. Je samozřejmě otázka co znamená starat se o model, patchování infrastruktury, dostupnost, výkon a kolik to všechno bude stát vs. hotová služba - na to se ještě mrkneme. Ale příště ještě ne - to si budeme zkoušet dotrénovat nebo vytrénovat vlastní model - někdy potřebujeme, aby AI znalo naše konkrétní objekty, třeba naše produkty, výrobní stroje nebo doménovou specializaci (kynologové si nevystačí se štítkem “pes” a lékaři asi potřebují o dost detailnější analýzu snímků, než jen prohlásit, že na fotce je “rentgen” nebo “cétéčko”). Příště tedy budeme YOLOv8 trénovat vlastními daty.
]]>Co když narazíte na limity délky? U druhé varianty se vám může vrátit dokument, který je moc dlouhý. Tak ho rozsekáte na vícero dotazů s požadavkem na sumarizaci toho kousku, čímž vzniknou kratší reprezentace, které jste pak schopni vložit do promptu nebo si nechat dál sumarizovat. U třetí varianty máte omezení už při převádění do vektorového prostoru (embeddings), takže budete postupovat buď stejně (tzn. rozsekáte dokumenty na kratší fragmenty) a všem uděláte otisk (a dál to funguje stejně jako v předchozí případě) nebo tohle vyřešíte už dopředu, tedy rozsekáte, necháte si udělat sumarizaci jednotlivých částí a pak z toho zkompilujete výsledný už krátký dokument a pro něj uděláte embedding.
Dnes se chci podívat co je v Azure k dispozici pro tu třetí variantu - kam ukládat vektory a jak v nich hledat podobnost?
Jak fungují embeddings jsem už na tomhle blogu vysvětloval tady, ale tam jsem to jen jednoduše držel v paměti. Pro praxi potřebujeme nějakou databázi, která je perzistentní a spolehlivá. Co chceme k vektoru uložit? Možná to bude celý původní text (ať to můžeme rovnou vložit do promptu), ale někdy to bude odkaz do blob storage, kde najdeme původní dokument případně oboje (pokud byl dokument moc velký a rozsekal jsem ho na kousky, můžu si uložit ten kousek, ale pořád si chci nechat odkaz na celý původní dokument, abych mohl svou odpověď ozdrojovat uživateli). Dost možná se nám k tomu hodí vytáhnout další metadata, která můžeme využít při budování promptu. Co třeba? Pro výběr co zahrnout do odpovědi se nám může hodit datum dokumentu (třeba preferujeme novější), autora (např. oficiální dokumentace bude mít větší váhu než příspěvek na blogu), kategorizace (můžeme například použít k vyloučení nevhodných výsledků), klasifikace (určité informace jsou jen pro zaměstnance nějakého oddělení) apod. Následně potřebujeme hledat na základě podobnosti vektorů - najdi mi záznamy, které mají k danému vektoru (ten vznikl dotazem uživatele) nejblíže.
Níže je popis pár variant v Azure, které jsem vyzkoušel a změřil - samozřejmě neprůkazně a amatérsky, ale pro představu mi to zatím stačí. Soustředil jsem se na následující:
Moje příklady najdete v tomhle notebooku
Na rozdíl od klasické Request Units varianty (čistě cloud native služba) je tahle vCore varianta v preview postavená na tom, že dostanete infrastrukturu přímo pro sebe a měla by být funkčně blíže k MongoDB. Funguje to tak, že si vytvoříte vektorový index a uložíte si JSON dokumenty s příslušným políčkem. Omezení je, že embeddings vektory mohou být do velikost 2000. To stačí pro dnes nejdoporučovanější model text-embedding-ada-002 (1536 dimenzí), ale davinci do toho nenacpete (cirka 12k) - to by ale nemělo tolik vadit, protože ada-002 vykazuje podle měření stejné nebo lepšé výsedky při zlomku ceny. Co do vyhledávání (měření vzdálenosti či chcete-li podobnosti) podporuje euklidovskou vzdálenost (L2 euclidean), kosinusovou podobnost (cosine) nebo skalární součin (inner product).
Projekt pgvector je open source nadstavba pro PostgreSQL přinášející práci s vektory. Toto rozšíření je podporováno v Azure Database for PostgreSQL, takže ho můžete mít nad plně platformní službou. Stejně jako v předchozím případě je řešení omezeno na 2000 dimenzí, podporuje všechny tři metody (euklidovskou vzdálenost, kosinusovou podobnost i skalární součin). Zajímavé je, že si můžete vybrat mezi přesným a přibližným hledání - to druhé nedává předvídatelné výsledky, ale je výkonnější a může krásně stačit (protože na výsledky se pak často stejně dívá pan profesor GPT-4).
ADX je databáze s velmi volným formátem a masivní škálovatelností a přitom zaměřená na ad-hoc analytické dotazy (na rozdíl třeba od CosmosDB, které je svou podstatou především o ukládání a hledání). Samotné uložení vektoru je prostě a jednoduše použití dynamického datového typu a nad tím si můžete napsat funkci pro kosinusovou podobnost. Není to tam tedy “od výroby”, ale výsledku lze snadno dosáhnout.
Tahle varianta je přirozeným rozšířením řešení pro vyhledávání a vektory jsou aktuálně v preview. Azure Cognitive Search dokáže klasické vyhledávací kouzla jako je indexace různými způsoby, klíčová slova, ale kromě toho i orchestraci zpracování a obohacování dat (zavolá si kognitivky pro záskání popisku obrázků, překlady apod.). V preview umí Semantic Search, kdy využívá AI pro přetřídění výsledků a právě i vektorové vyhledávání, což je co nás zajímá.
Tahle původně in-memory key-value databáze jako cache se rozrostla do nejrůznější oblastí včetně podpory perzistence a search vlastností. V rámci Azure je dostupná pouze u Enterprise tier služby. Zejména pro věci, které se vejdou do paměti (což je můj případ) to nemusí být vůbec špatný nápad.
Volil bych podle toho co dalšího v rámci řešení potřebujete.
Sečteno a podtrženo - za mě doporučuji tohle téma uchopit koncepčně a jít do Azure Cognitive Search. Každý vendor se díky humbuku kolem OpenAI snaží do své databáze narvat vektory, ale mě prostě přijde, že do operační databáze to není optimální (snad kromě případů, kdy vytváříte embeddingy neustále a interaktivně) a do cache je to nekoncepční.
]]>Jenže kromě toho má nezveřejnění těch nejsilnějších modelů i obchodní složku. Jaderné mocnosti vždy chtěly hlavně, aby už žádné další mocnosti nebyly - my si to necháme, je to pro nás výhoda, a ostatní ať k tomu už nesměřují. Jenže ono je to do značné míry podobné vývoji léčiv. To stojí naprosto strašlivé peníze a pokud budete povinni složení ihned zveřejnit, než něco vyděláte nebo se vám alespoň vrátí peníze za výzkum, tak se na to příště vykašlete. Na druhou stranu je šílené, jak v USA tahají peníze z lidí za inzulin - jednoznačně už dávno “zaplacený” výzkum. Je to prostě komplikované a na tomhle blogu to rozhodně nevyřešíme.
Open source může znamenat, že zveřejníte topologii neuronky. Je to podobné jako zveřejnit odbornou esej, ve které vysvětlíte přesně jak to děláte. Ve finále, pokud děláte něco opravdu zajímavého, tak tohle je to nejcenější pro další pokrok. Takhle se třeba Twitter inspiroval od Google povídání o Borgu a vytvořil Apache Mesos nebo takhle vznikl Hadoop na základě eseje o Map Reduce. Něco jiného ale je zveřejnit váhy celého modelu - tisíce GPU počítajících několik měsíců ve finále vyplivnou sérii těch správných čísel. Stejně, jako složení Coca Coly nebo nějakého zásadního léku. Stejně, jako návodu na sestrojení atomové bomby nebo na využití crispru pro vytvoření zabijáckého viru (úroveň vzteklina, ebola apod.) se snadností šíření chřipky ideálně s 14 denní nakažlivostí bez příznaků (dokonalá biologický zbraň). Zkrátka je to těžké rozhodnout.
Ať je to s etikou celé věci jakkoli, faktem dnes je, že LLM s kvalitou na úrovni ChatGPT zkrátka open source nejsou a ty modely co jsou, tak jsou dramaticky slabší - LLama, Alpaca, Dolly apod. Myslím, že během pár měsíců a jednotek let se může situace rychle změnit, ale zatím open source modely nejsou hrozbou. Proč je tedy řešit, když můžete mít třeba Azure OpenAI service?
Problematika “mám to u sebe” je obvykle jen taková nerealistická hra, protože pokud si správně vyberete dodavatele API, tak dostanete příslušné garance, že se vaše data neukládají a nepoužívají pro další trénování. Azure OpenAI service tohle rozhodně nabízí. Chápu možná nějaké státní zájmy v případě armády a špionů, ale jinak jsou to obvykle jenom výmluvy. Hlavní důvod je jiný - možnost fine-tuningu a cena.
LLM mohou být tak obrovské, že jejich fine-tuning, tedy drobné přetrénování, je ekonomicky neúnosný. Menší open source model s 7M nebo 12M parametry v tomhle ohledu představuje menší problém. Ve finále tak pro některé specializované úlohy může být smysl celkem hloupý, ale dobře vyškolený řemeslník, než pan profesor, který ale o vašem oboru ví tužku.
Samozřejmě, že jsou to zase nějaké centy, ale velké modely mohou být v součtu skutečně drahé. Jde totiž o to, že v aplikacích obvykle nevystačíte s jednoduchým dotaz-odpověď. V rámci prompt flow si berete dotaz uživatele, necháte z něj udělat query nebo prohledáte vektorový prostor embeddingů, vrácené dokumenty či odkazy dál prozkoumáte, sumarizujete a pak z nich kompilujete výslednou odpověď. A teď si vezměte, že jste třeba GitHub Copilot a potřebujete reagovat na to, co programátor zrovna píše - na pozadí a pěkně mu tam napovídat. To není jeden dotaz za minutu, ptát se musíte často. A co třeba taková počítačová hra, jak ji dělají třeba v GoodAI, kdy jsou jednotlivé počítačové postavy řízené dotazy do LLM? Když tohle sečtete, tak to levné být vůbec nemusí. Vezměte si třeba, že GPT 4 vás vyjde na 1M tokenů na 60 USD, zatímco výborně optimalizovaný GTP 3.5, který toho umí sakra dost, stojí 2 USD a pro jednoduché úlohy vám může stačit Ada za 0,4 USD. To je docela rozdíl, ne? A na konci toho spektra kvality jsou dnes open source modely, kde platíte jen za compute, takže tam bude záležet hlavně na vaší schopnosti hardwaru utilizovat.
Dovolte malou odbočku - hostování malého open source modelu taky není nic levného. Velké modely typu GPT-4 musí běžet na brutálních grafikách i pro inferencing (předpovídání, tedy využívání naterénovaného modelu). Představa, že malé open source modely jsou zázračně efektivní a levné není na místě - tak například LLaMA 7B běží na Raspberry Pi 4 (výkon a architektura podobná mobilu) rychlostí 10 vteřin na jeden token, viz tady! To jo o pár řádů nepoužitelné. Proto NVIDIA má řadu EGX určenou pro edge computing … nicméně zkrátka LLM na mobilu jsou stále naprosto mimo a to i ty opravdu hloupé 7B varianty.
Ve finále se tedy dá očekávat, že aplikace budou jednat zkoušet různé chytristiky jak počet dotazů omezovat (třeba cachovat časté dotazy) ale hlavně mít nějaký rozhodovací strom, který model použít. Můžu třeba v základu používat GPT 3.5 a pokud uvidím, že to nefunguje dobře (uživatel mi nereaguje pozitivně), zavolám si na pomoc chytřejší GPT 4. K tomu přidejte fine-tuning. Trochu lobotomická Ada se může natrénovat na mém specializovaném oboru a zastat práci dobře vycvičeného specialisty, který teda nic jiného neumí, ale tohle zvládá dobře. Vzít si na pomoc profesora GPT 4 samozřejmě můžu, ale nejen že jeho čas je dramaticky dražší, ale cena se zvýší ještě o jeho uvedení do obrazu (protože bude generický, musím mu kontext dát v promptu - tedy navyšovat množství vstupních tokenů, čili cenu). No a v neposlední řadě nezapomeňme na latenci - sofistikované modely toho při dotazech moc počítají a trvá jim to. Možná pro některé úlohy bude zásadní začít reagovat na uživatele okamžitě, třeba lokálním open source modelem běžícím přímo v jeho telefonu s tím, že na pozadí už se do problému kouká i pan profesor GPT-4 a a zasáhne, bude-li třeba.
V rámci Azure Machine Learning teď katalog open source modelů a to jednak přímo připravené a upravené od Azure samotného (tam jsou jednak některé otevřené modely Microsoftu, ale třeba i Databricks Dolly, Google Bert a další), ale i od Hugging Face (další místo pro sdílení modelů).
U těch AzureML curated pak někde běží i demo modely, takže si je můžete rovnou vyzkoušet bez jejich nasazení.
Přímo z GUI můžete model nasadit a to jednak jako real-time endpoint, kde se můžete ze své aplikace ptát REST rozhraním nebo pro batch zpracování, kdy bude model dostupný jako krok ve vaší AzureML pipeline a můžete jím třeba vygenerovat nějaké texty pro další zpracování.
Jednoduchý průvodce, vyberete si velikost inferencing clusteru a jedete.
Nasazený model můžete testovat, stáhnout si k němu klíče i příklad kódu v Pythonu, případně monitorovat jeho využívání.
Pokud byste nasadili víc verzí jsou tam i takové vychytávky, jako pozvolný přechod nebo mirroring - techniky tolik používané u cloud-native aplikací tak jsou k dispozici i pro ML modely.
Open source modely jako je Dolly nebo Alpaca vůbec nedávají špatné výsledky, ale zatím nijak extra chytré nejsou. Přesto mohou být důležitou kostkou do celkové stavebnice využívající modely open source nasazené lokálně pro minimální latenci a potenciálně nižší cenu, open source modely využívané pro nějaký masivní fine-tuning (není to nic snadného - prompt engineering je pro každého, fine-tuning rozhodně ne, potřebujete borce, co tomu rozumí), v kombinaci s uzavřenými modely, které ale také mají různé cenové škály viz řádové rozdíly mezi Ada, GPT 3.5 a GPT 4. V každém případě díky AzureML si můžete otestovat open source modely hned - stačí kliknout na tlačítko Deploy a udělat si představu sami. Zkuste si to.
]]>