Co jsou vektorové databáze a proč jsou vhodné pro AI?

dub 12 2024

Poslední dva měsíce jsem se v souvislosti s přípravou návrhu databáze pro AI projekt, který v TRITON IT chystáme společně s Karlem Pěnkou a Vaškem Viačkem, intenzivněji věnoval nastudování vektorových databází. Potřeboval jsem si ujasnit princip jejich fungování, zorientovat se v terminologii a odstranit řadu nejasností. Mé dosavadní poznatky sdílím s každým, koho zajímá proč a jak vektorové databáze vznikly, na jakých principech stojí a v čem jsou důležité pro práci s AI.

Obr. 1: Screenshot z testování multijazyčného jazykového modelu v kolekci ChromaDB, Python, PyCharm

Trochu historie a výzvy kladené na databázové systémy

Přelom 90.tých let a milénia se nesl ve znamení relačních databází založených na SQL. Tehdejší rychlý nástup webů, portálů, eshopů s sebou nesl potřebu efektivně ukládat uživatelská data a přistupovat k nim (filtrovat, řadit, vyhledávat). To se neslo ruku v ruce s normalizací relačních databází a tzv. normálními formami. Následný prudký rozvoj internetových aplikací zapříčinil, že relační databáze přestaly stačit. Nastupující sociální sítě, nebo eshopy přerostlé v mezinárodní internetové hypermarkety potřebovaly v reálném čase obsloužit miliony uživatelů. Analytické a vědecké aplikace zase potřebovaly co nejrychleji uložit velká data, vyhodnotit je a nasdílet výsledky. Na sklonku první dekády milénia nastala éra big data. Ruku v ruce s tím se začaly čím dále tím více uplatňovat NoSQL databáze. Zde byly normální formy ty tam. Prioritou se stala co největší dostupnost a rychlost čtení / zápisu. A to i za cenu duplicit na úrovni návrhu. Současně se rozvinula paralelizace - schopnost běžet jeden a tentýž databázový systém na více strojích (klastrech) současně a synchronizovat je mezi sebou. Pod náporem dat se řešilo balancování latence versus konzistence. Nad NoSQL databází Cassandra, konkrétně nad jejím optimalizovaným c++ klonem s názvem ScyllaDB běží i naše WebMedea. Vývoj šel dopředu a přicházely nové výzvy, které si vyžadovaly nové formy přístupu k datům. V souvislosti s nástupem AI se hovoří o nové průmyslové revoluci. A právě současný pokrok v AI byl stimulován rozvojem vektorových databází. Mimochodem věděli jste, že na tomto pokroku má lví podíl čech Tomáš Mikolov?

Motivace pro vektorové databáze

Co bylo impulsem pro vznik vektorových databází? Potřeba uložit a popsat vztahy mezi daty odlišným způsobem než doposud. Co je tím myšleno? Klasické relační databáze jsou založeny na vztazích (relacích) mezi řádky tabulek. To umožňuje popsat exaktní vztahy, například, že faktura má N položek, nebo že N osob může figurovat v M firmách. Ale reálný svět je spíše než booleovský (souvisí / nesouvisí) postavený na fuzzy (příslovečných 50 odstínů šedi mezi dvěma možnostmi). Reálný svět měří vztahy na úrovni míry shody či podobnosti něčeho s něčím. A právě na zmíněné fuzzy logice staví i teorie neuronových sítí. Ať už těch umělých nebo skutečných. Když se dítě učí mluvit, opakuje slova tak dlouho, dokud není vzdálenost jeho zvukového projevu od předlohy (odchylka) minimální. Požadavek byl proto jasný - mít možnost popsat vztahy mezi objekty v databázi pomocí míry, určující jak moc spolu objekty souvisí. 

Co to je vektorová databáze a jak funguje?

Vektorová databáze umožňuje efektivně ukládat vektorové reprezentace dat a pomocí dotazů je opětovně získávat. Data mohou být slova, celé texty, obrázky, videa, či zvukové stopy. Vektorovými reprezentacemi jsou uspořádané n-tice číslic reprezentující umístění dat v n-rozměrném prostoru. 

A teď se nabízejí následující otázky....
  1. Můžeš mi lidsky říci, k čemu je tedy ta vektorová databáze užitečná?
  2. Jak z dat dostanu zmíněné vektory a co potom s nimi udělám?
  3. Mluvíš o n-rozměrném prostoru, ale jakém a čím jsou definovány rozměry?
  4. Mluvíš o vzdálenosti, ale čím se ta vzdálenost měří?
  5. Řekneš mi to nějak srozumitelně polopaticky?
Až tyto otázky probereme, získáme vhled do toho, jak vektorové databáze fungují. Jdeme na to.

ad 1. K čemu je vektorová databáze užitečná?

Představte si, že do databáze uložíte několik textů. Potom napíšete jiný text a pošlete ho jako dotaz na databázi. Jako výsledek se vám vrátí ten z dříve uložených textů, který se významově nejvíce shoduje s dotazem. Nebo dostanete na výstupu prvních N uložených textů, které se nejvíce shodují se zadaným textem seřazených je podle míry shody. 

Příklad; V databázi máte uložené všechny projevy Milouše Jakeše. Jako dotaz pošlete "Chci ten projev, kde si Jakeš spletl drůbež a spotřebič na ohřev vody." V ideálním případě se vám vrátí legendární proslov o brojlerech a bojlerech. Jaktože vám databáze "rozumí"? Čtěte dál :)

ad 2. Jak se z dat stanou vektory?

Vektorovým reprezentacím dat se říká tzv. Embeddings (vzhledem k nejednoznačnosti doslovného překladu "vložení" budu používat anglický termín). Jak získat z dat embeddings? 

Embeddings pro slova

Začněme nejprve slovy. Řešíme následující úlohu. Vzít slovník. Vytvořit n-rozměrný prostor a v rámci tohoto prostoru reprezentovat každé slovo ze slovníku pomocí vektoru. Cílem je získat co nejlepší rozložení slov, kde slova, která spolu souvisí méně jsou v prostoru dále od sebe. Slova, která spolu souvisí více jsou blíže u sebe. Konkrétněji? Podstatné jméno "šroubovák" bude mít od podstatného jména "višeň" mnohem větší vzdálenost než "meruňka". Přídavné jméno "kyselý" bude blíže višni než meruňce. Podstatné jméno "ovoce" bude višni a meruňce blíže než obecná "rostlina". Pořád jsme si ale neřekli, jak zmíněnou úlohu řešit. Existuje více přístupů. Jejich průkopníkem byl již zmíněný Tomáš Mikolov, který v roce 2013 publikoval nástroj word2vec. Jednalo se o neuronovou síť se dvěma skrytými vrstvami, která řešila optimalizační úlohu najít takovou vektorovou reprezentaci slov, který by co nejvíce odpovídala realitě. Tomáš k tomu použil tzv. velký jazykový korpus - soubor textů určitého jazyka, dostatečně velký na to, aby z něj bylo možné získat významové vztahy mezi jednotlivými slovy. Proč to udělal? Samotný slovník nestačí, někdo vám musí říct, že višeň je kyselá, že šroubovák šroubuje šrouby, nebo že "vydělat" je sloveso a často se vyskytuje s podstatným jménem "peníze". Buď by nějaký člověk musel popsat veškeré vztahy mezi veškerými slovy ve slovníku určitého jazyka. A pak v horším případě metodou pokus omyl, v lepším případě nějakým heuristickým algoritmem, budovat co nejlepší vektorovou reprezentaci všech slov. Nebo můžeme souvislosti automatizovaně vytěžit z dostatečně velké zásoby textů a použít neuronovou síť k nalezení nejlepší reprezentace.

Embeddings pro texty, větné transformátory, jazykové modely a LLM

V případě celých textů - vět a dokumentů je úloha složitější. Podobně jako u slov vyjděme z toho, že máme k dispozici jazykový korpus. Celý korpus není změtí náhodných dat, ale ohromnou znalostní bází, kterou vytvořili myslící lidé a zakódovali do ní významové souvislosti pomocí určitého jazyka. Cílem je zachytit tyto souvislosti do modelu (jazykového modelu), který bude definovat co nejlepší vzdálenosti mezi jednotlivými významovými celky. Klíčové je, aby takový model byl jednak co nejvíce vypovídající a současně rychlý pro použití. Nástroje, které takové jazykové modely budují se nazývají větné transformátory (z anglického sentence transformers) a využívají principu pozornosti (z anglického attention). Pro různé typy úloh existují různé jazykové modely. Některé se hodí spíše pro překlad, jiné pro významové prohledávání textu viz náš příklad s projevem Milouše Jakeše. Tím, že jazykové modely vydolují (dekódují) z textu význam v podobě embeddings, můžeme pak embeddings (ten význam) zakódovat do jiného jazyka (překlad), nebo embeddings porovnat s embeddings jiného textu a zjistit míru významové podobnosti.

Další příklad významové podobnosti; Nahrajeme do vektorové databáze všechny starověké texty, bibli, řecké báje a pověsti a další po kapitolách.  Pošleme na databázi dotaz "Dej mi texty, které zmiňují velkou povodeň". V ideálním případě dostaneme příslušné kapitoly, z jednotlivých děl, které pojednávají o biblické potopě či zkáze Atlantidy.

V případě jazykových či jiných (pro zpracování grafiky či zvuku) modelů se tedy nejedná o žádné "vědomí", jak nám často povrchní a senzace chtiví internetoví článkaři prezentují současný nástup AI, ale pouze o sofistikované porovnání dat. Zde se také dostáváme k termínu velké jazykové modely (z anglického large language models, neboli LLM). Jsou to takové modely, které ke svému vytvoření použily dostatečně veliký jazykový korpus. 

Poznámka: Kromě jazykových modelů mohou být na podobném principu tvořeny modely pro rastry, audio a další datové typy. Viz seznam dostupných OpenAI modelů.

ad 3. S kolika rozměrným prostorem pracujeme a jaký je význam jednotlivých dimenzí?

Celou dobu se bavíme o vektorech z n-rozměrného prostoru, který jsme si dosud blíže nepopsali. Záměrně jsem zatím využíval vádní označení n-rozměrný prostor, ve kterém využíváme "něco" k určení vzdálenosti prvků - vektorů. Vektorové databáze mohou využívat modely založené jak na vektorových prostorech, tak na metrických prostorech. Můžeme mít klasický euklidovský metrický prostor, nebo například vektorový prostor kosinové podobnosti. Rozvedu níže. A jak je to s tou dimenzionalitou? No :) Ti, co jsou (jako já) zvyklí, například ze statické klasifikace a rozpoznávání, že dimenze příznakového prostoru souvisí s konkrétními vlastnostmi objektu (třeba barva, hmotnost, délka atd. atd.), nejspíše zklamu. Protože dimenze metrických nebo vektorových prostorů používaných pro tvorbu embeddingů obvykle nemají žádný "lidsky popsatelný" význam. Tyto dimenze jsou často výsledkem optimalizační úlohy, která se snaží najít takové reprezentace dat, které nejlépe zachycují vztahy mezi nimi. Každá dimenze prostoru odpovídá různým charakteristikám nebo rysům dat, které nejsou snadno interpretovatelné lidmi. Počet dimenzí bývá určen empiricky při budování modelu a je optimalizován tak, aby co nejlépe vyhovoval potřebám konkrétního úkolu nebo modelu. Jinak řečeno. Neurové sítě větných transformátorů, které staví náš jazykový model, používají počet dimenzí jako proměnnou k tomu, aby nalezli optimální rozmístění vektorů v prostoru. Zatímco word2vec pracoval s cca 300 dimenzemi. Chat GPT pracuje přibližně s 1500 rozměrnými vektory a nové modely i s 3000 rozměrnými vektory

ad 4. Čím se měří vzdálenost? Kosinová podobnost a embedding funkce

Různé modely mohou používat různou definici vzdálenosti. Dokonce u téhož principiálního modelu je leckdy možné si "hrát" s různými vzdálenostmi a vyrábět tak různé jeho klony a testovat jejich spolehlivost. Klíčové však je, že jakmile zvolíme určitu definici vzdálenosti a použijeme ji v rámci větného transformátoru k sestavení jazykového modelu, jsme již logicky vázáni na tuto vzdálenost. Vrátíme se nyní opět k počátkům word2vec od Tomáše Mikolova. Ten využil k určení podobnosti dvou vektorů kosinus - takzvanou kosinovou podobnost. Byly k tomu hned dva dobré důvody. 

  1. Kosinus lze snadno (a z hlediska výpočetní složitosti efektivně) spočítat jako podíl skalárního součinu obou vektorů (v čitateli) a součinu velikostí obou vektorů (ve jmenovateli). 
  2. Funkční hodnoty kosinu velmi dobře odráží vzájemnou (ne)souvislost slov. Kosinus nabývá hodnoty nula pro kolmé vektory => ideální pro slova, která spolu vůbec nesouvisí. Čím více spolu slova souvisejí a jsou s významově podobnější (blíží se synonymu), tím více se kosinus jejich vektorových reprezentací blíží jedničce. Čím více jsou slova související, ale jsou významově odlišná (blíží se antonymu), tím více se kosinus jejich vektorových reprezentací blíží mínus jedničce. 
Kosinová podobnost je právě ten případ, kdy o ní nemůžeme hovořit jako o metrice, protože nesplňuje axiomy metriky (nezáportnost, symetrie, trojúhelníková nerovnost). Konkrétně nesplňuje nezápornost (nabývá hodnot -1 až 1). V dnešní době se používá celá řada metrik či podobností, včetně těch založených na modifikaci kosinové podobnosti. Vektorové databáze pracují s pojmem embedding funkce (embedding function). Skrze ni jim lze nainjektovat transformátor a "metriku" pro vybraný model tak, aby vytvořené embeddings s ním byly kompatibilní. 

ad 5. Vše dohromady polopaticky

Konkrétně pro případ textů. Vyberu vhodnou vektorovou databázi. Navrhnu po jakých logických celcích data uložím. Vyberu si jazykový model vhodný pro řešení mé úlohy. Použiji implementaci příslušného větného transformátoru a embedding function k vytvoření embeddings.

Jakou vektorovou databázi zvolit?

V TRITON IT jsme se minulý podzim začali připravovat na dva investiční projekty, které jsme se společně s investory rozhodli postavit na AI. Marek nechal naše kluky z vývoje udělat rešerši dostupných vektorových databází. Měli jsme následující požadavky na vektorovou databázi.
  • snadno integrovatelná s OpenAI API,
  • mající driver pro Javu,
  • otevřená, srozumitelná, dobře zdokumentovaná, žádná nabubřelá korporátní zlodějna,
  • dostatečně prověřená a rozšířená.
Po přečtení rozboru, který mi Maxim sestavil, byla volba vítěze jasná - ChromaDB. 

Představení ChromaDB

Základním stavebním kamenem ChromaDB jsou kolekce. Jedna databáze může obsahovat více kolekcí. Do jedné kolekce lze uložit několik dokumentů (textů). Jakou granularitu dat si zvolíme je na nás - dokumenty mohou být věty, odstavce, kapitoly. Na úrovni kolekce si lze zvolit, jakou embedding funkci pro kolekci použít. Tato funkce se pak používá pro všechny dokumenty dané kolekce. Lze tak mít různé embedding funkce pro různé kolekce, ale nikoliv pro různé dokumenty v rámci jedné a tytéž kolekce. Každý dokument v rámci kolekce má své ID, metadata a embeddingy (vektorovou reprezentaci příslušného dokumentu). ID slouží k identifikaci dokumentu v rámci kolekce, podobně jako je tomu u primárních klíčů relačních databází. Díky ID jsem schopen z obslužné aplikace přistupovat ke konkrétnímu dokumentu. Metadata slouží k filtrování. Mohu si tak popsat dokumenty pomocí jejich klíčových vlastností. A potom vybírat pouze ty dokumenty, které odpovídají požadovaným kritériím. 

Příklad; Jste výrobce elektroniky, třeba monitorů jako MISURA ;). Vytěžíte veškeré recenze vašich produktů z různých e-shopů distributorů, srovnávačů, recenzních portálů atd.. Vytvoříte v ChromaDB kolekci obsahující všechny uživatelské recenze. Co dokument, to jedna recenze. Embeddingy již byly vytvořeny při vložení recenzí do kolekce. Metadata obsahují: rok vytvoření recenze, kód recenzovaného produktu, počet hvězdiček hodnocení. Chcete vybrat taková hodnocení za minulý rok, která souvisejí s typem, počtem a zapojením napájecích kabelů. Zašlete dotaz, kterým si přes metadata omezíte rok na minulý, nastavíte počet výsledků na 5 a současně zašlete v dotazu například řetězec "dej mi hodnocení, která souvisejí s napájením monitoru, typem, počtem a zapojením napájecích kabelů". Databáze si nejprve dokumenty klasickým způsobem vyfiltruje podle roku, pro zúžené dokumenty vytáhne jejich embeddingy a porovná je s embeddingem, který vytvoří pro text zaslaný v dotazu. Výsledkem bude 5 recenzí z minulého roku, které nejvíce významově odpovídají požadavku.

Proč a jak propojit databázi s OpenAI či jinými LLM?

Vektorové databáze jsou využívány zejména pro uchování a poskytnutí vlastního kontextu pro lokální či externí (ne nutně) jazykové modely, dostupné přes API třetích stran. A to zejména v případech, když se jedná o big data a kontext je značně objemný. V takovém případě využijeme možnosti zakódovat kontext do embeddingů, efektivně ho uchovat v zakódované podobě v databázi i využít vektorové databáze k omezení kontextu, pokud je dobře strukturován pomocí metadat. Naopak pokud je kontext malý, existuje dnes celá řada nástaveb pro standardně rozšířené AI chaty, nebo specializovanější softwary. Navíc tento obor se extrémně rychle rozvíjí. Co nebylo k dispozici dnes, bude zítra. 

Příklad; Vezměme si předchozí příklad s recenzemi. Tentokrát však chceme odpověď na otázku: "Co zákazníci nejvíce vyčítají produktu <kód produktu>?", nebo požadujeme: "Napiš mi normostranu textu o tom s čím jsou zákazníci spokojeni u produktů <značka-kategorie>." Potom se nám hodí využít například OpenAI ChatGPT a jako kontext použít natěžené recenze. Vzhledem k tomu, že se jedná o velké množství textu, bude pro nás efektivní i ekonomicky výhodné (přístup k OpenAI API je objemově zpoplatněná služba), když recenze zašleme ve formě embeddingů. V případě prvního dotazu můžeme navíc zaslat jen embeddingy z dokumentů, jejichž metadata jsou spojena s daným kódem produktu. Ve druhém případě zase můžeme pomocí metadat odstranit recenze se špatným hodnocením, protože správným kontextem pro AI jsou pouze pozitivní recenze.

Efektivita komunikace s OpenAI a dostupné embedding funkce

Kontext můžeme do OpenAI zasílat jako klasické řetězce. Nicméně výhodnost tohoto přístupu dramaticky klesá s délkou řetězce (textu). Zaslat kontext v podobě embeddingů má následující výhody:
  1. Embeddingy jsou z hlediska objemu dat výrazně úspornější pro přenos dat => větší efektivita
  2. Embeddingy již v sobě nesou nemalou investici výpočetního času na jejich zakódování => není nutné provádět na serveru třetí strany => opět vyšší efektivita
Protože čas jsou peníze, zejména v případě OpenAI. Jsou k dispozici v OpenAI různé embedding funkce na míru potřebám uživatele. Správná volba embedding funkce dokáže ušetřit cenný čas zpracování a tím i prostředky vynaložené na kredit pro OpenAI. OpenAI své embedding funkce pravidelně zdokonaluje a poskytuje detailní informace o nových embedding funkcích. Jít v tomto ohledu s dobou znamená ušetřit peníze. Například:
  • text-embedding-3-small nahrazuje původní text-embedding-ada-002 a je výrazně efektivnější pro zpracování než zmíněný předchůdce. To umožňuje při jejím použití ušetřit až 5x tolik kreditu.
  • text-embedding-3-large naopak umožňuje lépe zachytit význam z velmi dlouhých textů pomocí 3072 dimenzionálního prostoru.