Enkele weken geleden bracht Google hun nieuwste Gemma model uit: EmbeddingGemma. Zoals de naam al doet vermoeden: dit is een embedding-model. Normaal gesproken wanneer we het in dit blog over modellen hebben, bedoelen we LLM-modellen, maar een (puur) embedding-model heeft een ander doel, ondanks dat de onderliggende technieken (zoals transformers) vaak hetzelfde zijn, en LLM-modellen zelf ook in staat zijn om te 'embedden'.

Wat is embedden?
Wanneer je tekst stuurt naar een LLM krijg je nieuw gegenereerde tekst terug. Dit kan bijvoorbeeld in de vorm van een auto-completion, of een antwoord op je gestelde vraag.
Wanneer je tekst naar een embedding-model stuurt, krijg je een vector terug. Een vector is een rij numerieke waarden. Een voorbeeld van een vector: [1.3, 0.9, 2.7, 13.1, 5.2]
. Een vector, in deze context, noemen we ook wel een embedding.
Wat hebben we hier precies aan? Op zichzelf staand heeft deze vector weinig waarde of betekenis, maar in een situatie waarin je meerdere teksten hebt die omgezet zijn naar vectoren, wordt het mogelijk om hier berekeningen mee uit te voeren, waarmee bepaald kan worden in hoeverre teksten gerelateerd zijn aan elkaar. Wanneer teksten namelijk een vergelijkbare (semantische) betekenis hebben liggen hun vectoren dicht bij elkaar. Door afstanden tussen vectoren te berekenen kan je dus bepalen of teksten (of concepten) gerelateerd zijn aan elkaar.
Use cases
Maar wat is het nut van verbanden tussen teksten kunnen bepalen? Het blijkt dat daar heel veel verschillende toepassingen voor zijn.
De meest voor de hand liggende toepassing is het zoeken naar informatie. Denk aan hoe we in een zoekmachine zoeken, maar niet de exacte woorden gebruiken. Als ik zoek op 'serverproblemen' ben ik bijvoorbeeld mogelijk geinteresseerd in 'databasecrashes', 'netwerkuitval, of 'systeemfouten', maar dat waren niet de woorden waar ik op zocht - en zelfs geen synoniemen. Maar toch kunnen ze gevonden worden, omdat de semantische betekenis en relaties waren vastgelegd in deze multi-dimensionale ruimte.

Denk bijvoorbeeld ook aan gerelateerde concepten, zoals bijvoorbeeld productaanbevelingen. Want ook vergelijkbare producten bevinden zich waarschijnlijk bij elkaar in een cluster. Of het automatisch classificeren en groeperen van bijvoorbeeld documenten of e-mails. Als je een Gmail-gebruiker bent, is het je vast wel eens opgevallen dat Google veel advertenties weet te groeperen onder een tabblad Advertenties of Promoties. Om te bepalen of een e-mail in deze groep valt gebruiken ze veel verschillende signalen, maar een van de stappen in dit classificatieproces is het gebruiken van embeddings.
Nog een andere toepassing is het snel kunnen vinden van gerelateerde code in een codebase. Dit kan bijvoorbeeld nuttig zijn als je een AI snel wilt kunnen voorzien van relevante context over een bepaald code-fragment, zonder dat je een hele codebase hoeft mee te sturen. Maar dit hoeft natuurlijk niet alleen code te zijn. In een eerder project hebben we voor een klant een systeem gebouwd waarbij via vector search relevante fragmenten van documenten werden opgezocht en meegestuurd, zodat de AI automatisch voorzien kon worden van de juiste informatie over het huidige vraagstuk. Wanneer je honderden (of duizenden) documenten hebt, is het handig als je slechts een deel hiervan mee hoeft te sturen.
Embeddings worden dus overal gebruikt. Van ChatGPT tot Netflix-aanbevelingen, van Google Search tot Spotify's muziekdiscovery. Maar wij zijn een techblog - tijd om dus iets meer een kijkje te nemen naar de achterliggende principes.
Vector space
Een vector (of een embedding) is een representatie van de gestuurde tekst: iedere keer als je dezelfde tekst naar het embeddings model stuurt, krijg je dezelfde vector terug. Een embedding-model is dus in staat om woorden, of teksten, om te zetten naar vectoren.
Een vector is een positie in een multi-dimensionale ruimte. In ons vorige voorbeeld ([1.3, 0.9, 2.7, 13.1, 5.2]
) beschreven we een positie in een 5-dimensionale ruimte. Om dit concept eenvoudiger te maken doen we een stap terug; de meeeste mensen zijn wel bekend met een 3-dimensionale ruimte (x,y,z), maar om het zo eenvoudig mogelijk te maken kiezen we voor een 2-dimensionale ruimte: (x,y).
Hieronder een fictief voorbeeld van een embedding-model dat 2-dimensionele vectoren produceert:
Tekst | Vector |
---|---|
Hond | (0.20, 0.30) |
Kat | (0.25, 0.35) |
Tijger | (0.30, 0.40) |
Tekst | Vector |
---|---|
Gorilla | (0.40, 0.50) |
Bloem | (0.60, 0.60) |
Huis | (0.90, 0.90) |
Hierboven is een 2-dimensionele vector ruimte. Hier is het visueel waarschijnlijk al vrij eenvoudig te zien wat het idee van 'afstand' tussen vectoren inhoudt.
Je ziet dat hond, kat en tijger redelijk dicht bij elkaar liggen. Logisch, want deze 'concepten' zijn redelijk aan elkaar gerelateerd: Alle 3 zijn het viervoeters, kat en tijger zijn katachtigen, maar kat en hond zijn weer huisdieren. Wanneer concepten dicht bij elkaar liggen noemen we dit ook wel een cluster. De gorilla staat er wat verder vandaan - het is nog wel een dier, maar geen viervoeter en (hopelijk) geen huisdier. Een bloem staat er nog verder vanaf, maar niet zover als een huis, want een bloem is in ieder geval nog organisch.
In werkelijkheid zijn het aantal dimensies van de vectoren een stuk groter dan 2, 3 of 5. Denk hierbij aan honderden of zelfs duizenden dimensies. Maar het principe blijft hetzelfde, ondanks dat het lastig in te beelden is: een vector is een positie in een multi-dimensionale ruimte, en aan de hand van deze positie ten opzichte van andere vectoren is het mogelijk om te bepalen in hoeverre ze gerelateerd zijn.

Verschillende modellen
In ons fictieve voorbeeld lieten we zien waarom de concepten van een kat🐱 en een tijger🐯 dichter bij elkaar liggen dan een tijger🐯 en een gorilla🦍. Maar dit hoeft natuurlijk helemaal niet zo te zijn. De waarde van een gegenereerde vector is afhankelijk van het model. Een ander model zou een hele andere vector terug kunnen geven. Dit is namelijk afhankelijk van de manier waarop, en de data waarmee, het model getraind is. Een ander model zou dus hele andere relaties gelegd kunnen hebben tussen de verschillende concepten.
Voorbeeld van ander model
Een model zou getraind kunnen zijn op het (letterlijke) gewicht van een concept. Op dat moment zou het goed kunnen dat een gorilla en een tijger dichter bij elkaar liggen dan een kat en een tijger. Of misschien is het model wel getraind op hoe geschikt iets is om een huisdier te zijn. Ook dan verwacht je totaal andere verbanden tussen de verschillende concepten.
Verschillende modellen leggen dus verschillende soorten relaties vast. Ieder model heeft zijn eigen representatie van de wereld, en alle concepten erin, en dit wereldmodel bepaalt de locatie van een specifiek concept in deze ruimte. De criteria waarop een model getraind is, bepaalt hoe de vectorruimte is ingericht.
Daarnaast is er ook nog het aantal dimensies van de gebruikte vectoren. Hoe meer dimensies een vector heeft, hoe meer informatie vastgelegd kan worden. In onze voorbeelden hierboven gebruiken we vectoren met 2 dimensies, maar in werkelijkheid ligt het aantal dimensies een stuk hoger. Het EmbeddingGemma model genereert bijvoorbeeld 768-dimensionale vectoren.
Conclusie
Over EmbeddingGemma gesproken: genoeg over de theorie! In onze volgende blogpost over embedding gaan we hiermee aan de slag. We gaan een vector-database optuigen, teksten embedden via embedding-modellen en vector-searches uitvoeren.
