LLM- ja generatiivisen tekoälyn haastatteluun valmistautuminen

LLM- ja generatiivisen tekoälyn insinöörin haastattelukysymykset

15 valittua LLM- ja generatiivisen tekoälyn haastattelukysymystä ryhmiteltynä kokemustason mukaan. Käytä niitä kertaamaan perusasioita, käytännön kompromisseja ja senioritason tuotantopäätösten logiikkaa.

Aloita LLM- ja generatiivisen tekoälyn haastatteluEi vaadi luottokorttia. 1 ilmainen sessio saatavilla.
Teknisten haastattelujen harjoittelu englanniksiTila, jossa ei-äidinkieliset puhujat voivat harjoitella teknisen haastattelun läpäisemistä.

Junioritason kysymykset

1Selitä alisanatokenisointi (subword tokenization) ja miksi sitä suositaan sanatasoisen tai merkkitasoisen tokenisoinnin sijaan nykyaikaisissa kielimalleissa.

Alisanatokenisointi on hybridi tekstin segmentointimenetelmä, joka jakaa tekstin vaihtelevan pituisiksi morfologisiksi palasiksi tai taajuuspohjaisiksi alimerkkijonoiksi (kuten 'un', 'break', 'able') kokonaisten sanojen tai yksittäisten merkkien sijaan. Algoritmit, kuten Byte-Pair Encoding (BPE), WordPiece ja Unigram LM, oppivat kiinteäkokoisen sanaston harjoituskorpuksesta, jossa yleiset sanat pysyvät ehjinä yksittäisinä tokeneina, kun taas harvinaiset tai ennennäkemättömät sanat hajotetaan tunnettuihin alisanayksiköihin. Alisanatokenisointia suositaan nykyaikaisissa kielimalleissa, koska se tasapainottaa sanaston koon, jonon pituuden ja sanaston ulkopuolisten (OOV) sanojen kestävyyden. Puhtaasti sanatasoinen tokenisointi vaatii liian suuren sanaston (johtaen valtaviin upotusmatriiseihin) ja kärsii edelleen OOV-tokeneista, jotka kartoitetaan yleisiin '[UNK]'-tokeneihin. Vastaavasti puhtaasti merkkitasoinen tokenisointi eliminoi OOV-ongelmat, mutta tuottaa hyvin pitkiä jonoja, jotka lisäävät dramaattisesti laskennallista kompleksisuutta huomiomekanismeissa (jotka skaalautuvat kvadraattisesti jonon pituuden mukaan) ja laimentavat semanttista tiheyttä tokenia kohden. Alisanatokenisointi löytää optimaalisen kompromissin pitämällä jonojen pituudet hallittavissa, sanaston koot käytännöllisinä (tyypillisesti 32k-128k tokenia) ja OOV-luvut nollassa (etenkin kun yhdistetään tavutasoisiin varajärjestelmiin).

from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained('gpt2')
text = 'unbelievable'
tokens = tokenizer.tokenize(text)
token_ids = tokenizer.encode(text)

print('Tokens:', tokens)
print('Token IDs:', token_ids)
Kokeile vastata tähän kysymykseen tekoälyvalmentajan kanssa

2Selitä ero staattisten sanainkoodausten (static word embeddings), kontekstuaalisten upotusten (contextual embeddings) ja Transformer-piilotilojen (transformer hidden states) välillä.

Staattiset sanainkoodaukset, kontekstuaaliset upotukset ja Transformer-piilotilat edustavat asteittaista kehitystä siinä, miten tekstiesitykset vangitsevat merkityksen ja syntaktisen kontekstin. 1. Staattiset sanainkoodaukset (esim. Word2Vec, GloVe, FastText) osoittavat kullekin sanastotunnukselle yhden, kiinteän vektorin sen lausekontekstista riippumatta. Tässä mallissa moniselitteiset sanat, kuten 'bank' (joenranta vs. pankki) tai 'apple' (hedelmä vs. teknologiayritys), saavat identtiset vektoriesitykset kaikissa konteksteissa, perustuen staattiseen hakutauluun. 2. Kontekstuaaliset upotukset (esim. varhainen ELMo, BERT-token-esitykset tai lause-upotukset Bi-Encoder -malleista) tuottavat esityksiä, joissa tokenin vektori on dynaaminen funktio sen ympäröivästä kontekstista. BERT:ssä tai ELMo:ssa sana 'bank' lauseessa 'river bank' saa täysin erilaisen upotusvektorin kuin sana 'bank' lauseessa 'deposit money at the bank'. 3. Transformer-piilotilat viittaavat Transformer-verkon yksittäisten kerrosten tuottamiin välivaiheen vektoriesityksiin eteenpäinsyötön aikana. Kun syötetään token-upotukset kerrokselle 0, jokainen peräkkäinen Transformer-kerros soveltaa itsehuomiota (`self-attention`) ja eteenpäinsyöttömuunnoksia (`feed-forward transformations`), tuottaen sarjan piilotila-vektoreita `h_l` kerroksella `l`. Vaikka viimeisen kerroksen piilotilat toimivat korkean tason kontekstuaalisina upotuksina, alemmat ja keskimmäiset piilotilat vangitsevat matalan tason syntaktisia, leksikaalisia ja rakenteellisia piirteitä. Näin ollen Transformer-piilotilat kattavat koko pystysuuntaisen jatkumon kerroksittaisia esityksiä verkon läpi.

import torch
from transformers import AutoTokenizer, AutoModel

tokenizer = AutoTokenizer.from_pretrained('bert-base-uncased')
model = AutoModel.from_pretrained('bert-base-uncased', output_hidden_states=True)

text1 = 'River bank'
text2 = 'Bank deposit'

inputs1 = tokenizer(text1, return_tensors='pt')
inputs2 = tokenizer(text2, return_tensors='pt')

with torch.no_grad():
    out1 = model(**inputs1)
    out2 = model(**inputs2)

# Layer 0 (Input token embeddings - static lookup before self-attention)
static_bank_1 = out1.hidden_states[0][0, 2] # 'bank'
# Layer 12 (Final contextual hidden state after all attention layers)
contextual_bank_1 = out1.hidden_states[12][0, 2]
contextual_bank_2 = out2.hidden_states[12][0, 1]

print('Cosine similarity of bank in different contexts (Layer 12):',
      torch.cosine_similarity(contextual_bank_1, contextual_bank_2, dim=0).item())
Kokeile vastata tähän kysymykseen tekoälyvalmentajan kanssa

3Selitä, mitä upotusavaruus (embedding space) edustaa ja miten kosinussamankaltaisuus (cosine similarity) tulkitaan tekstiupotuksissa.

Upotusavaruus on jatkuva, korkeaulotteinen vektoriavaruus R^d, johon diskreetit tekstuaaliset entiteetit (sanat, lauseet tai dokumentit) on kuvattu siten, että semanttiset, syntaktiset tai suhteelliset samankaltaisuudet vastaavat geometrista läheisyyttä ja suunta-suhteita. Tässä avaruudessa etäisyydet ja kulmat heijastavat semanttista samankaltaisuutta. Kosinussamankaltaisuus mittaa kulman theeta kosinia kahden vektorin u ja v välillä, ja se lasketaan seuraavasti: `Cosine Similarity(u, v) = (u . v) / (||u|| ||v||)` Kosinussamankaltaisuus tulkitaan tekstiupotuksissa seuraavasti: - **Arvoalue ja suunta:** Se tuottaa skalaariarvon, joka on tyypillisesti rajattu välille [-1, 1] (tai [0, 1] ei-negatiivisille upotuksille). Arvo lähellä 1.0 osoittaa, että kaksi vektoria osoittavat lähes samaan suuntaan, heijastaen suurta semanttista samankaltaisuutta tai aihepiirillistä yhdenmukaisuutta. Arvo lähellä 0.0 tarkoittaa ortogonaalisuutta (semanttinen riippumattomuus tai epäyhteenkuuluvuus), ja negatiiviset arvot osoittavat vastakkaisia suuntauksia. - **Suuruusriippumattomuus:** Toisin kuin euklidinen etäisyys (L2-etäisyys) tai pistotulo, kosinussamankaltaisuus normalisoi vektorin pituuden suhteen. Tekstiupotuksissa vektorin suuruus voi joskus korreloida sekvenssin pituuden, tokenin esiintymistiheyden tai termin spesifisyyden kanssa. Keskittymällä puhtaasti suunnan yhdenmukaisuuteen kosinussamankaltaisuus eristää semanttisen suunnan vektorin suuruuseroista.

import numpy as np

def cosine_sim(a, b):
    return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))

# Hypothetical 3D embeddings
v_king = np.array([0.9, 0.1, 0.4])
v_queen = np.array([0.85, 0.15, 0.42])
v_apple = np.array([0.1, 0.9, -0.2])

print('Sim(king, queen):', round(cosine_sim(v_king, v_queen), 4))
print('Sim(king, apple):', round(cosine_sim(v_king, v_apple), 4))
Kokeile vastata tähän kysymykseen tekoälyvalmentajan kanssa

4Selitä token-upotusten (token embeddings), positionaalisten upotusten (positional embeddings) ja segmentti- tai tyyppiupotusten (segment or type embeddings) erot transformer-syötteissä.

Transformer-syötteissä (erityisesti BERT-tyyppisissä arkkitehtuureissa) kunkin tokenin syötereepresentaatio muodostetaan tyypillisesti laskemalla yhteen kolme erillistä upotusvektoria alkioittain: 1. **Token-upotukset:** Muuntavat diskreettejä sanastotoken-ID:itä tiheiksi vektoreiksi, jotka edustavat tokenien ydinsemanttista ja leksikaalista identiteettiä. 2. **Positionaaliset upotukset:** Syöttävät informaatiota tokenin järjestyksestä ja sekvenssin indeksistä representaatioon, kompensoiden sitä, että itsehuomio (self-attention) on luonnostaan permutaatioinvariantti. 3. **Segmentti- (tai Token-tyyppi-) upotukset:** Erottelevat toisistaan eri tekstijaksoja tai lauseita, jotka on pakattu yhteen syötesekvenssiin (kuten lause A vs. lause B parien luokittelu- tai kysymys-vastaus-tehtävissä). Näiden upotusten yhdistäminen tarjoaa yhden tiheän syötetensorin, joka koodaa tokenin merkitystä, sijaintia ja sekvenssin ryhmittelyä ennen sen siirtämistä ensimmäiseen transformer-kerrokseen.

import torch
import torch.nn as nn

vocab_size, max_seq_len, num_segments, d_model = 30522, 512, 2, 768
tok_embed = nn.Embedding(vocab_size, d_model)
pos_embed = nn.Embedding(max_seq_len, d_model)
seg_embed = nn.Embedding(num_segments, d_model)

input_ids = torch.tensor([[101, 7592, 102, 2023, 102]]) # Token IDs
type_ids = torch.tensor([[0,   0,    0,   1,    1  ]]) # Segment IDs (Sentence A vs B)
positions = torch.arange(input_ids.size(1)).unsqueeze(0)   # Indices: [0, 1, 2, 3, 4]

# Final representation is the element-wise sum
input_rep = tok_embed(input_ids) + pos_embed(positions) + seg_embed(type_ids)
print(input_rep.shape)
Kokeile vastata tähän kysymykseen tekoälyvalmentajan kanssa

5Selitä attentio mekanismina tokenien yhdistämiseen sekvenssissä, mukaan lukien kyselyt (queries), avaimet (keys), arvot (values) ja monipäinen attentio (multi-head attention).

Attentio on mekanismi, jonka avulla sekvenssin tokenit voivat reitittää tietoa dynaamisesti ja painottaa kaikkien muiden tokenien relevanssia kontekstuaalisen vastaavuuden perusteella. Lineaariset projektiot muuntavat kunkin tokenin syötteen kolmeksi vektoriksi: - Kysely (Q): Edustaa tietoa, jota nykyinen token etsii. - Avain (K): Edustaa ominaisuuksia tai sisältöä, jota token tarjoaa vastatakseen kyselyihin. - Arvo (V): Sisältää todellisen tietosisällön, joka aggregoidaan. Skaalatussa pistetuloattentiossa attentiopisteet lasketaan kertomalla kyselyt ja avaimet ($Q K^T$), skaalataan arvolla $\frac{1}{\sqrt{d_k}}$ estämään gradientin häviäminen suurissa ulottuvuuksissa ja normalisoidaan softmax-funktiolla. Lopullinen tulos on arvojen painotettu summa: $$\text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V$$ Monipäinen attentio (MHA) projisoi $Q:n$, $K:n$ ja $V:n$ useisiin itsenäisiin representaatioavaruuksiin (päihin) rinnakkain. Tämä antaa mallin samanaikaisesti kiinnittämään huomiota erityyppisiin suhteisiin (esim. syntaktinen rakenne, koreferenssi, pitkän kantaman riippuvuudet) asemien välillä. Päiden tulosteet yhdistetään ja projisoidaan lineaarisesti takaisin mallin ulottuvuuteen.

import torch
import torch.nn.functional as F

# Q, K, V: [batch_size, seq_len, head_dim]
Q = torch.randn(1, 4, 64)
K = torch.randn(1, 4, 64)
V = torch.randn(1, 4, 64)
d_k = Q.size(-1)

scores = torch.matmul(Q, K.transpose(-2, -1)) / (d_k ** 0.5)
attn_weights = F.softmax(scores, dim=-1)
output = torch.matmul(attn_weights, V)

print("Output shape:", output.shape)
Kokeile vastata tähän kysymykseen tekoälyvalmentajan kanssa

6Selitä, miten huomiomaskaus (attention masking) eroaa kausaalisissa dekoodereissa ja bidirektionaalisissa enkoodereissa, ja mitä käyttäytymismalleja se mahdollistaa tai estää.

Huomiomaskaus ohjaa, mitkä tokenit saavat kohdistaa huomionsa muihin tokeneihin, asettamalla huomiologitit (pisteet ennen softmaxia) $-\infty$:ksi kielletyille pareille, varmistaen, että niiden softmaxin jälkeinen huomiopaino on tarkalleen 0. 1. **Kausaaliset dekooderit** (esim. GPT (Generative Pre-trained Transformer), LLaMA (Large Language Model Meta AI)): Käyttävät alakolmiomaista kausaalista (autoregressiivistä) maskia. Token paikassa $i$ voi kohdistaa huomionsa vain paikkoihin $j \le i$. Tämä estää huomion kohdistamisen tuleviin tokeneihin, mahdollistaen autoregressiivisen token-kohtaisen generoinnin päättelyvaiheessa ja estäen tulevien tokenien otsikkivuodon (label leakage) rinnakkaisessa harjoittelussa. 2. **Bidirektionaaliset enkooderit** (esim. BERT (Bidirectional Encoder Representations from Transformers)): Ne eivät käytä kausaalista maskia; jokainen token voi kohdistaa huomionsa kaikkiin menneisiin ja tuleviin tokeneihin koko sekvenssin ajan. Ne käyttävät täytemaskeja (padding masks) estääkseen kelvollisia tokeneita kohdistamasta huomionsa tyhjiin `[PAD]`-tokeneihin eräajetuissa sekvensseissä. Bidirektionaalinen huomio tuottaa rikkaita, kattavia kontekstuaalisia representaatioita, jotka ovat ihanteellisia ymmärtämistehtäviin, mutta estää suoran yhden läpäisyn autoregressiivisen tekstigeneroinnin.

import torch
import torch.nn.functional as F

scores = torch.randn(3, 3)
# Create upper-triangular mask for future positions
causal_mask = torch.triu(torch.ones(3, 3, dtype=torch.bool), diagonal=1)

# Mask future positions with -inf before softmax
masked_scores = scores.masked_fill(causal_mask, float('-inf'))
atten_weights = F.softmax(masked_scores, dim=-1)
print(atten_weights)
Kokeile vastata tähän kysymykseen tekoälyvalmentajan kanssa

7Selitä ero vain enkooderi-, vain dekooderi- ja enkooderi-dekooderi-transformer-arkkitehtuurien välillä kielitehtävissä.

Kolme ensisijaista transformer-arkkitehtuuria eroavat perustavanlaatuisesti huomion peittämismalleiltaan ja kohdetoiminnallisilta tavoitteiltaan: 1. Vain enkooderi (esim. BERT, RoBERTa): Käyttää bidirektionaalista itsehuomiota, jossa jokainen token voi ottaa huomioon kaikki muut sekvenssin tokenit samanaikaisesti. Se tuottaa rikkaita kontekstuaalisia representaatioita koko syötesekvenssille, mikä tekee siitä ihanteellisen luokitteluun, ekstraktiiviseen QA:han (kysymys-vastaus) ja piirre-edustukseen. Se ei voi luonnollisesti generoida autoregressiivistä tekstiä. 2. Vain dekooderi (esim. GPT-3, Llama, Mistral): Käyttää kausaalista (yksisuuntaista) itsehuomiota, jossa token $i$ voi ottaa huomioon vain tokenit paikoissa $j \le i$. Se koulutetaan autoregressiivisesti käyttäen seuraavan tokenin ennustusta ja toimii standardiarkkitehtuurina generatiivisille kielimalleille, koodin generoinnille ja avoimelle keskustelulle. 3. Enkooderi-dekooderi (esim. T5, BART): Yhdistää bidirektionaalisen enkooderin autoregressiiviseen kausaaliseen dekooderiin. Kausaalisen itsehuomion lisäksi generoitujen tokenien yli dekooderi käyttää ristiinhuomiokerroksia, jotka kyselyvät enkooderin tulostusrepresentaatioita. Tämä arkkitehtuuri on suunniteltu erityisesti sekvenssistä sekvenssiin -muunnostehtäviin, kuten kääntämiseen ja yhteenvetojen luontiin.

# Causal mask (Decoder-Only) vs Full mask (Encoder-Only)
import torch

seq_len = 4
encoder_mask = torch.ones(seq_len, seq_len)  # Full bidirectional attention
decoder_causal_mask = torch.tril(torch.ones(seq_len, seq_len))  # Lower-triangular

print("Encoder Mask:
", encoder_mask)
print("Decoder Causal Mask:
", decoder_causal_mask)
Kokeile vastata tähän kysymykseen tekoälyvalmentajan kanssa

Keskitason kysymykset

8Selitä, miten tavutasoiset, Unicode-tietoiset ja monikieliset tokenoijavalinnat vaikuttavat mallin laatuun, kustannuksiin ja oikeudenmukaisuuteen eri kielten välillä.

Tokenoijan suunnitteluvalinnat – kuten tavutasoinen versus Unicode-tietoinen segmentointi ja monikielisten sanastojen allokoinnit – vaikuttavat suoraan mallin laatuun, päättely-/koulutuskustannuksiin ja kielelliseen oikeudenmukaisuuteen. Kustannusten ja oikeudenmukaisuuden osalta tokenoijat, jotka on koulutettu pääasiassa englanninkielisillä tai latinalaisilla aineistoilla, allokoivat suurimman osan sanastomerkinnöistä englanninkielisille sanoille ja morfeemeille. Tämän seurauksena englanti saavuttaa korkean pakkauksen (esim. ~1,3 tokenia per sana), kun taas muut kuin latinalaiset kirjoitusjärjestelmät (esim. arabia, devanagari, thai, kiina) tai vähävaraiset kielet fragmentoituvat usein useiksi alihanoiksi tai raakaiksi UTF-8-tavuiksi (usein 3–6 tokenia per sana). Tätä eroa kutsutaan usein "token-veroksi" tai "hedelmällisyysasteen epätasapainoksi": muut kuin englanninkieliset käyttäjät maksavat merkittävästi enemmän API-laskutuksessa semanttista sisältöyksikköä kohti, käyttävät konteksti-ikkunan rajat paljon nopeammin ja kärsivät suuremmasta viiveestä. Laadun osalta tavutasoiset tokenoijat (kuten Byte-level BPE GPT-2/GPT-4:ssä tai SentencePiece tavupalautuksella LLaMA:ssa) välttävät tuntemattomien merkkien aiheuttamat kaatumiset ja sanaston ulkopuoliset (UNK) virheet kokonaan, koska mikä tahansa kelvollinen UTF-8-merkkijono jakautuu tavutokeneiksi. Liiallinen tavujen fragmentoituminen heikentää kuitenkin esityksen laatua, koska transformerin on käytettävä kerroksia tavujen palasten yhdistämiseen semanttisiksi käsitteiksi ennen korkean tason päättelyä. Monikielisen sanaston koon kasvattaminen (esim. laajentaminen 32k:sta 128k+:aan tokeniin) tasapainottaa hedelmällisyysasteita ja parantaa tehtävän suorituskykyä eri kielillä, joskin hieman suuremman syöttö-/ulostulo upotuskerroksen kustannuksella.

from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained('gpt2')

english_text = 'Hello world'
hindi_text = 'नमस्ते दुनिया'

print('English tokens:', tokenizer.tokenize(english_text))
print('Hindi tokens:', tokenizer.tokenize(hindi_text))
print('English token count:', len(tokenizer.encode(english_text)))
print('Hindi token count:', len(tokenizer.encode(hindi_text)))
Kokeile vastata tähän kysymykseen tekoälyvalmentajan kanssa

9Mitä tokenoinnin artefakteja esiintyy numeerisessa päättelyssä, koodin generoinnissa tai harvinaisessa Unicode-tekstissä, ja miten erikoistuneet tokenoijat voivat vähentää niitä?

Tokenoinnin artefakteja syntyy, kun alitavu-tokenoijat (subword tokenizers) jakavat strukturoitua, numeerista tai harvinaista tekstiä epäjohdonmukaisesti, mikä estää mallia tunnistamasta taustalla olevaa semanttista tai syntaktista säännöllisyyttä. Keskeisiä artefakteja ovat: 1. **Numeerisen päättelyn artefaktit:** Vakiomuotoiset BPE (Byte Pair Encoding) -tokenoijat, jotka on koulutettu yleiseen tekstiin, jakavat luvut mielivaltaisiin palapituuksiin taajuuden perusteella (esim. '12345' voi tokenoitua muotoon ['12', '345'], kun taas '12346' tokenoituu muotoon ['123', '46']). Tämä epäjohdonmukainen ryhmittely rikkoo paikka-arvon kohdistuksen (yksiköt, kymmenet, sadat) ja haittaa aritmeettista päättelyä. 2. **Koodin generoinnin artefaktit:** Sisennys (alkavat välilyönnit/sarkaimet) ja useita merkkejä sisältävät operaattorit (esim. '==', '!=', '->') jakautuvat usein epäsäännöllisesti välilyönti-/merkkirajojen yli, mikä johtaa sisennysvirheisiin, turvonneisiin tokenien määriin syvään sisennetyssä koodissa ja syntaksin korruptioihin. 3. **Harvinaisen Unicoden ja emojien artefaktit:** Monitavuiset UTF-8-sekvenssit (kuten monimutkaiset emojit nollaleveillä yhdistäjillä tai harvinaiset kirjoitusjärjestelmät) jaetaan raaoiksi tavutokeneiksi, jotka eivät kanna yksilöllistä semanttista merkitystä, mikä aiheuttaa hallusinoituja merkkejä tai vaurioituneita merkkien renderöintejä generoinnin yhteydessä. Erikoistuneet tokenoijat vähentävät näitä artefakteja käyttämällä räätälöityjä esitokenointisääntöjä ja sanastorajoituksia: - **Numeroiden jakaminen:** Yksinumeroisen tokenoinnin pakottaminen (esim. regex jakamalla jokainen numero `0-9` omaksi tokenikseen) varmistaa yhtenäisen paikka-arvoesityksen matemaattista päättelyä varten. - **Erilliset välilyönti-/sisennystokenit:** Selkeiden tokenien lisääminen usean välilyönnin sisennyksille (esim. 2, 4, 8 välilyöntiä) ja ohjelmointikielen avainsanojen/operaattorien säilyttäminen. - **Regex-esitokenointi / Tavutason varajärjestelmät (Byte-level fallbacks):** Regex-jakajien (kuten GPT-4/tiktoken regexes) käyttö, jotka erottavat välimerkit, kirjaimet ja numerot tiukkoihin luokkiin ennen BPE-yhdistämisten laskemista, estäen ristikategorioiden yhdistämisen (esim. estäen 'a=10':n yhdistymisen yhdeksi tokeniksi).

import tiktoken

# tiktoken cl100k_base (GPT-4 / ChatGPT) enforces digit and whitespace handling
enc = tiktoken.get_encoding('cl100k_base')

num1 = '12345'
num2 = '12346'
code_indent = '    def foo():'

print('Tokens num1:', [enc.decode([t]) for t in enc.encode(num1)])
print('Tokens num2:', [enc.decode([t]) for t in enc.encode(num2)])
print('Tokens code:', [enc.decode([t]) for t in enc.encode(code_indent)])
Kokeile vastata tähän kysymykseen tekoälyvalmentajan kanssa

10Perustele pitkän kontekstin huomion (attention) kompromisseja, mukaan lukien kvadraattinen täyshuomio, liukuikkuna-huomio (sliding-window attention), harva tai globaali huomio, KV-välimuistin (KV-cache) kustannukset ja huomion laimeneminen.

Huomion (attention) skaalaaminen pitkiin konteksti-ikkunoihin sisältää kompromisseja laskennan, muistin kulutuksen ja mallin tarkkuuden välillä: 1. **Kvadraattinen täyshuomio vs. Liukuikkuna- / Harva huomio:** Vakiomuotoinen täyshuomio skaalautuu kvadraattisesti ($O(N^2)$) laskennassa ja aktivaatiomuistissa sekvenssin pituuden $N$ suhteen. Liukuikkuna- (paikallinen) huomio rajoittaa huomion kiinnittymisen kiinteään naapurustoon $W$, vähentäen kompleksisuuden tasolle $O(N \cdot W)$, mutta vaatii useita kerroksia tiedon levittämiseksi etäisten tokenien välillä. Harvat tai globaalit huomiomallit yhdistävät paikalliset ikkunat valittuihin globaaleihin ankkuritokeneihin säilyttäen $O(N)$ skaalautuvuuden samalla kun mahdollistavat pitkän kantaman viestinnän. 2. **KV-välimuistin (KV-cache) muistikustannukset:** Autoregressiivisen generoinnin aikana kaikkien edellisten tokenien avaimet (keys) ja arvot (values) välimuistitaan tarpeettomien laskutoimitusten välttämiseksi. KV-välimuistin muisti skaalautuu lineaarisesti sekvenssin pituuden ($O(B \cdot L \cdot H_{KV} \cdot D \cdot N)$) suhteen. Erittäin pitkien kontekstien (32k–128k+ tokenia) tapauksessa KV-välimuisti kuluttaa kymmeniä gigatavuja grafiikkaprosessorin (GPU) VRAM-muistia erää kohden, mikä pullonkaulana rajoittaa maksimaalista eräkokoa ja muistikaistanleveyttä. 3. **Huomion laimeneminen (Attention Dilution / Lost-in-the-Middle):** Kontekstin kasvaessa softmax-nimittäjä summaa kymmenien tuhansien tokenien yli, levittäen todennäköisyysmassan ohuesti epäolennaiseen kontekstiin. Tämä entropian kasvu laimentaa huomion terävyyttä, heikentäen mallin kykyä luotettavasti palauttaa mieliin tietyt tiedot, jotka on upotettu pitkien kehotteiden keskelle.

def kv_cache_gb(batch_size, seq_len, layers=32, kv_heads=8, head_dim=128, bytes_per_elem=2):
    # 2 for Key and Value
    total_bytes = batch_size * seq_len * layers * kv_heads * head_dim * 2 * bytes_per_elem
    return total_bytes / (1024 ** 3)

print(f"32k context: {kv_cache_gb(4, 32768):.2f} GB")
print(f"128k context: {kv_cache_gb(4, 131072):.2f} GB")
Kokeile vastata tähän kysymykseen tekoälyvalmentajan kanssa

11Vertaa MHA:ta (Multi-Head Attention), MQA:ta (Multi-Query Attention) ja GQA:ta (Grouped-Query Attention) ja selitä, miten ne vaikuttavat KV-välimuistin (Key-Value cache) muistiin ja dekoodauskapasiteettiin.

Multi-Head Attention (MHA), Multi-Query Attention (MQA) ja Grouped-Query Attention (GQA) eroavat toisistaan siinä, miten avain ($K$) ja arvo ($V$) päät jaetaan kysely ($Q$) päiden kesken: 1. Multi-Head Attention (MHA): Siinä on yhtä monta $Q$-, $K$- ja $V$-päätä ($H_Q = H_{KV}$, suhde 1:1). Jokainen kyselypää käsittelee omia itsenäisiä avain-/arvoesityksiään. Vaikka tämä on ilmaisuvoimainen, se vaatii erillisten KV-matriisien välimuistiin tallentamisen jokaiselle päälle. 2. Multi-Query Attention (MQA): Käyttää useita $Q$-päitä ($H$), mutta vain 1 jaettua $K$-päätä ja 1 jaettua $V$-päätä (suhde $H:1$). Tämä pienentää KV-välimuistin kokoa $H$:n kertoimella, mutta voi johtaa pieneen laadun heikkenemiseen tai harjoittelun epävakauteen. 3. Grouped-Query Attention (GQA): Ryhmittelee $Q$-päät $G$ osioon, jossa jokainen ryhmä jakaa yhden $K$- ja $V$-pään (esim. 8 $Q$-päätä per KV-pää). GQA tarjoaa optimaalisen kompromissin, palauttaen käytännöllisesti katsoen kaiken MHA:n mallinnuslaadun säilyttäen samalla MQA:n muistihyödyt. Vaikutus KV-välimuistiin ja dekoodauskapasiteettiin: Autoregressiivinen tokenien generointi (dekoodaus) on muistikaistanleveyden rajoittamaa, koska GPU:n (Graphics Processing Unit) on siirrettävä koko KV-välimuisti HBM:stä (High-Bandwidth Memory) piirin sisäiseen SRAM-muistiin (Static Random-Access Memory) jokaisen generoidun tokenin kohdalla. Vähentämällä KV-päiden määrää $H/G$:llä (esim. $4\times$ - $8\times$ GQA:ssa tai $32\times+$ MQA:ssa): - KV-välimuistin muistijalanjälki pienenee suhteellisesti, mikä mahdollistaa paljon suurempien palvelueräkokojen (serving batch sizes) käytön GPU:n VRAM:issa (Video RAM). - HBM-muistin lukuliikenne per token putoaa huomattavasti, mikä lisää dekoodaustokenien kapasiteettia dramaattisesti.

# Model with 32 Query Heads
num_q_heads = 32

mha_kv_heads = 32 # 1:1 ratio
gqa_kv_heads = 8  # 4:1 ratio (4 query heads per KV head)
mqa_kv_heads = 1  # 32:1 ratio (1 shared KV head)

print(f"KV Cache Size Relative to MHA:")
print(f"MHA: {mha_kv_heads / mha_kv_heads * 100:.1f}%")
print(f"GQA: {gqa_kv_heads / mha_kv_heads * 100:.1f}%")
print(f"MQA: {mqa_kv_heads / mha_kv_heads * 100:.1f}%")
Kokeile vastata tähän kysymykseen tekoälyvalmentajan kanssa

12Selitä, miten FlashAttention nopeuttaa tarkkaa attention-laskentaa muuttamatta attention-tulosteita.

FlashAttention nopeuttaa attention-laskentaa tekemällä algoritmista I/O-tietoisen – minimoimalla luku- ja kirjoitusmuistiliikenteen hitaan GPU:n suurikaistaisen muistin (High Bandwidth Memory, HBM) ja nopean sirun sisäisen SRAM-muistin välillä, sen sijaan, että yritettäisiin vähentää aritmeettisten FLOP-operaatioiden kokonaismäärää. Standardi attention materialisoi N x N suuruiset väliaikaiset attention-piste- ja todennäköisyysmatriisit HBM:ään, mikä aiheuttaa merkittävän muistikaistan pullonkaulan. FlashAttention voittaa tämän kolmen avainmekanismin avulla: 1. **Lohkominen (Tiling):** Se jakaa kysely-, avain- ja arvo-matriisit (Query, Key, Value matrices) lohkoihin, jotka mahtuvat kokonaan GPU:n sirun sisäiseen SRAM-muistiin. 2. **Online Softmax:** Se laskee softmax-funktion inkrementaalisesti lohkojen yli seuraamalla juoksevia maksimiarvoja ja normalisoijien summia, päivittäen osittaisia tuloksia ilman, että koko materialisoitua N x N matriisia tarvitaan muistissa. 3. **Tarkka uudelleenlaskenta (Exact Recomputation):** Takaisinpäin kulun (backward pass) aikana se ei lue tallennettuja väliaikaisia attention-matriiseja HBM:stä; sen sijaan se laskee ne uudelleen lennossa SRAM-muistissa tallennetuista juoksevista tilastoista. Koska mitään approksimaatioita, matala-arvoisia faktorisointeja tai tokenien pudottamiseen perustuvia heuristiikkoja ei käytetä, tulos on matemaattisesti tarkka liukulukujen numeeriseen tarkkuuteen asti, samalla kun HBM-muistin jalanjälki pienenee O(N^2):sta O(N):ään.

import torch

def online_softmax_step(m_prev, l_prev, out_prev, scores_block, v_block):
    # scores_block: (B, H, Br, Bc), v_block: (B, H, Bc, D)
    m_block = scores_block.max(dim=-1, keepdim=True).values
    m_new = torch.maximum(m_prev, m_block)
    
    # Rescale previous and current accumulators
    p_prev_scale = torch.exp(m_prev - m_new)
    p_block = torch.exp(scores_block - m_new)
    
    l_new = p_prev_scale * l_prev + p_block.sum(dim=-1, keepdim=True)
    out_new = (p_prev_scale * l_prev * out_prev + p_block @ v_block) / l_new
    return m_new, l_new, out_new
Kokeile vastata tähän kysymykseen tekoälyvalmentajan kanssa

Senioritason kysymykset

13Suunnittele deterministisiä agenttityökuvia käyttäen suunnittelijoita (planners), tilakoneita (state machines), DAG-rakenteita (Directed Acyclic Graph), tyypitettyä välitilaa, rajattuja uudelleenyrityksiä ja työkalujen tulosten varmennusta avoimien agenttisilmukoiden sijaan.

Avoimet agenttisilmukat (esim. rajoittamattomat autonomiset ReAct-silmukat) tuotannossa kärsivät usein epädeterministisestä haarautumisesta, äärettömistä silmukoista, hallitsemattomasta tokenien kulutuksesta ja tilan siirtymistä (state drift). Deterministinen agenttityökuva korvaa vapaamuotoiset silmukat jäsennellyllä, havainnoitavalla ohjausvuolla: 1. **Tilakoneet ja DAG-rakenteet:** Ohjausvuoto määritellään eksplisiittisenä suunnattuna syklittömänä graafina (DAG) tai äärellisenä tilakoneena (esim. LangGraph, Temporal, AWS Step Functions). Solmujen siirtymät riippuvat eksplisiittisistä ehdoista ja tyypitetyistä tuloksista avoimien mallipäätösten sijaan. 2. **Tyypitetty välitila:** Solmujen välillä jaettu tila mallinnetaan tiukoilla skeemoilla (esim. Pydantic-mallit tai dataclassit). Solmut suorittavat validoituja luku- ja kirjoitusoperaatioita, estäen skeeman siirtymisen tai virheellisen tilan. 3. **Suunnittelijat:** Jäsennellyt suunnittelijat luovat rajoitetun suunnitelman etukäteen (esim. järjestetyn luettelon enum-pohjaisista vaiheista) tai valitsevat rajoitetusta joukosta kelvollisia tilasiirtymiä sen sijaan, että päättäisivät vapaasti seuraavista toimista ilman rajoituksia. 4. **Työkalujen tulosten varmennus:** Työkalujen palauttamat tulokset validoidaan deterministisesti skeemoja ja liiketoimintasääntöjä vastaan ennen tilan päivittämistä tai siirtämistä seuraaville LLM-vaiheille. 5. **Rajattu uudelleenyritys ja varatoimet:** Jokainen vaihe valvoo eksplisiittisiä uudelleenyritysbudjetteja, eksponentiaalista viivästystä (exponential backoff), aikakatkaisuja ja varasiirtymiä (esim. eskaloitumista ihmisen tarkasteluun tai turvallisen pidättäytymisen käynnistämistä) varmistaakseen päättymisen.

from pydantic import BaseModel
from typing import Optional, Literal

class WorkflowState(BaseModel):
    user_query: str
    extracted_id: Optional[str] = None
    verification_status: Literal["PENDING", "VERIFIED", "FAILED"] = "PENDING"
    retry_count: int = 0
    max_retries: int = 3

def execute_validation_node(state: WorkflowState) -> WorkflowState:
    if state.retry_count >= state.max_retries:
        state.verification_status = "FAILED"
        return state
    try:
        result = call_verification_service(state.extracted_id)
        state.verification_status = "VERIFIED" if result.is_valid else "FAILED"
    except Exception:
        state.retry_count += 1
    return state
Kokeile vastata tähän kysymykseen tekoälyvalmentajan kanssa

14Suunnittele luottamustason ja pidättäytymisen käytäntö SKM (suuri kielimalli) -avustajalle, joka vastaa säännellyillä aloilla esitettyihin kysymyksiin.

Säännellyillä aloilla (kuten terveydenhuolto, pankkitoiminta, lakiasiat ja vaatimustenmukaisuus) virheellisistä vastauksista aiheutuu sääntelyyn liittyviä rangaistuksia, oikeudellista vastuuta ja turvallisuusriskejä. Vankka luottamustason ja pidättäytymisen käytäntö yhdistää monisignaalisen kalibroidun luottamustason pisteytyksen, porrastetut vastauskynnykset ja deterministiset eskalaatioprosessit: 1. **Monisignaalinen luottamustason kalibrointi:** Raaka SKM:n (suuren kielimallin) logaritmiset todennäköisyydet ovat usein väärin kalibroituja, kun kyseessä on toimialueen ulkopuolisia kyselyjä. Luottamuspisteen tulisi syntetisoida useita riippumattomia signaaleja: * **Hakuperustelu-pisteet:** Haettujen todisteiden semanttinen samankaltaisuus ja uudelleenjärjestelyn luotettavuus. * **Väitelauseen tasoinen seuraus (NLI, Natural Language Inference):** Luonnollisen kielen päättelymallit varmistavat, että jokainen poimittu väite on peräisin haetusta lähdekontekstista. * **Semanttinen entropia / itsekonsekvenssi:** Mittaa semanttista johdonmukaisuutta useiden otettujen generointien välillä. * **Mallin tokenien logaritmiset todennäköisyydet:** Keskeisten nimettyjen entiteettien ja faktuaalisten tokenien minimi- ja keskimääräiset logaritmiset todennäköisyydet. 2. **Porrastettu pidättäytymiskäytäntö:** * **Korkea luottamustaso (pisteet >= korkea kynnysarvo):** Tarjoa generoitu vastaus suoraan sisäisillä viittauksilla. * **Keskinkertainen luottamustaso / monitulkintainen (matala kynnysarvo <= pisteet < korkea kynnysarvo):** Tarjoa varovainen vastaus selkein varoituksin, vastuuvapauslausekkein tai pyydä käyttäjältä selventäviä tietoja. * **Matala luottamustaso / toimialueen ulkopuolella (pisteet < matala kynnysarvo):** Ehdoton pidättäytyminen standardoidulla kieltäytymisviestillä. 3. **Eskalaatio ja vaatimustenmukaisuuden auditoitavuus:** * **Deterministinen eskalaatio:** Pidättäytymiset tai kriittiset ristiriidat reititetään automaattisesti ihmisen prosessissa (HITL, human-in-the-loop) -jonoihin tai agenttien tukijärjestelmiin täydellä kontekstilla. * **Tarkastuspolku ja alkuperäketju:** Täydellinen telemetria – mukaan lukien kehotteiden tiivisteet, haettujen asiakirjojen tunnukset, yksittäisten luottamustason komponenttien pisteet ja lopulliset reitityspäätökset – on kirjattava sääntelyn auditoitavuutta varten.

from dataclasses import dataclass
from typing import Literal

@dataclass
class DecisionResult:
    action: Literal["SERVE", "SERVE_WITH_CAVEAT", "ABSTAIN_AND_ESCALATE"]
    confidence_score: float
    reason: str

def evaluate_confidence_policy(retrieval_score: float, nli_entailment_score: float, semantic_entropy: float) -> DecisionResult:
    # Composite calibrated confidence index [0, 1]
    composite_score = (0.4 * retrieval_score) + (0.4 * nli_entailment_score) + (0.2 * (1.0 - semantic_entropy))
    
    if composite_score >= 0.85:
        return DecisionResult("SERVE", composite_score, "High evidence grounding")
    elif composite_score >= 0.60:
        return DecisionResult("SERVE_WITH_CAVEAT", composite_score, "Partial evidence support")
    else:
        return DecisionResult("ABSTAIN_AND_ESCALATE", composite_score, "Insufficient ground truth")
Kokeile vastata tähän kysymykseen tekoälyvalmentajan kanssa

15Suunnittele mallien reititysstrategia, joka valitsee pienten, keskikokoisten ja suurten mallien välillä pyynnön monimutkaisuuden, kustannusten, riskin ja laatuvaatimusten perusteella.

Tuotantomallien reititysarkkitehtuuri ohjaa saapuvat pyynnöt pienten (esim. 1–8 miljardin parametrin SKM:ien (Small Language Model)), keskikokoisten (esim. 14–70 miljardin parametrin mallien) ja suurten (esim. kehittyneiden tai suurten MoE (Mixture of Experts) -mallien) tasojen välillä tasapainottamalla monimutkaisuutta, viivettä, riskiä ja laskentakustannuksia. Reititysprosessi yhdistää yleensä staattiset säännöt, ennakoivan reitityksen ja dynaamiset varajärjestelmät: 1. **Deterministiset/staattiset käytäntöportit:** Suodata pyynnöt asiakastason, tiukkojen viive-SLA:iden (Service Level Agreement) tai sääntely-/toimialariskin (esim. lääketieteellinen diagnoosi tai oikeudellinen laadinta reititetään suoraan ylimmän tason malleihin) tai yksinkertaisten sääntöjen mukaisten tehtävien (esim. perus-regex/muotoilu pienille malleille) perusteella. 2. **Ennakoiva monimutkaisuusreititys:** Nopea, kevyt luokittelija (kuten upotusten samankaltaisuuden haku, ristikooderi tai pieni SKM-reititin) pisteyttää pyynnön monimutkaisuuden, päättelysyvyyden ja toimialueen monitulkintaisuuden valitakseen kustannustehokkaimman tason etukäteen. 3. **Dynaamiset suoritus- ja eskalaatiokaskadit:** Lähetä kehotteet ensin pienempään malliin ja arvioi tuloksen luotettavuutta (tokenien logaritmisilla todennäköisyyksillä/entropialla, strukturoidun skeeman validoinnilla tai suojakaide-tarkistuksilla). Jos luottamustaso on kynnyksen alapuolella tai validointi epäonnistuu, reititin eskaloituu keskikokoiseen tai suureen malliin. Keskeisiä järjestelmäkompromisseja ovat reitittimen viiveen ylikuormitus versus laskentakustannusten säästöt, varajärjestelmän aikakatkaisubudjetit liikennepiikkien aikana ja jatkuva arviointi (esim. varjoarviointi tulosten laadun muutosten seuraamiseksi eri tasoilla).

class DynamicModelRouter:
    def __init__(self, small_client, medium_client, large_client, classifier, guardrail):
        self.small = small_client
        self.medium = medium_client
        self.large = large_client
        self.classifier = classifier
        self.guardrail = guardrail

    async def route_and_execute(self, request):
        # 1. Deterministic Risk Gate
        if request.risk_level == "high" or request.domain in ["legal", "medical_compliance"]:
            return await self.large.generate(request.prompt)
        
        # 2. Predictive Complexity Classifier
        complexity = self.classifier.predict_complexity(request.prompt) # 0.0 to 1.0
        
        if complexity < 0.35:
            response = await self.small.generate(request.prompt)
            if self.guardrail.is_acceptable(response):
                return response
            return await self.medium.generate(request.prompt) # Fallback
            
        if complexity < 0.75:
            response = await self.medium.generate(request.prompt)
            if self.guardrail.is_acceptable(response):
                return response
            return await self.large.generate(request.prompt) # Fallback
            
        # 3. High complexity frontier execution
        return await self.large.generate(request.prompt)
Kokeile vastata tähän kysymykseen tekoälyvalmentajan kanssa