Programming Parallel Computers

Open 2026

LLM: suuri kielimalli

Lue ensin tällä sivulla olevat yleisohjeet. Tarkemmat tiedot löytyvät tehtäväkohtaisista ohjeista. Jokaiseen tehtävään on saatavilla oma zip-tiedosto, josta löytyvää koodia voit käyttää ratkaisujesi pohjana.

Tehtävä Palautuksia Pisteet Max. Taso Suos. Määräaika
LLM9a: CPU-optimointi

Toteuta suuren kielimallin kehotteen tehokas prosessointi käyttäen kaikkea CPU:lla saatavilla olevaa yksinkertaisen tarkkuuden laskentatehoa.

5 + 2 ★★ 2026-12-02 klo 23:59:59

Yleiset ohjeet

Tässä harjoituksessa optimoidaan suuren kielimallin, tässä tapauksessa LLaMA-malliperheeseen kuuluvan kielimallin toteutusta. Sivun alaosasta löydät lyhyen kuvauksen rinnakkaislaskennan ja LLaMAn kaltaisten transformer-pohjaisten kielimallien menestyksen välisestä yhteydestä.

Yleisesti ottaen suuren kielimallin työ voidaan jakaa kahteen vaiheeseen: käyttäjän antaman kehotteen käsittelyyn ja uusien tokenien luontiin kehotteen perusteella. Tässä harjoituksessa keskitymme ensimmäiseen vaiheeseen. Jo pelkästään käyttäjän antaman kehotteen prosessoinnilla voidaan saada aikaan mielenkiintoisia sovelluksia, esimerkiksi ennustaa, kuinka yllättävä jokin teksti on. Lisätietoa on alla demo-osiossa.

Tätä harjoitusta varten on valmisteltu perusversio LLaMA 2 -mallista, joka perustuu Andrej Karpathyn llama2.c:hen. Tehtävänä on tunnistaa pullonkaulat ja soveltaa tällä kurssilla opittuja tekniikoita kehotteen käsittelyn nopeuttamiseksi.

Rajapinta

Toteuta seuraava funktio:

void llm(LLamaConfig config, 
         LLamaParameters params, 
         const std::vector<token_t>& tokens,
         std::vector<float>& logits);

Parametrit ovat seuraavat:

Voit olettaa, että konfiguraatiossa kuvataan aina kelvollinen verkko (eli kaikki koot > 0). Voit olettaa, että verkon ulottuvuudet (config.dim ja config.hidden_dim) ovat 16:n monikertoja.

Lisätietoja

Tämän harjoituksen pohjalla käytetään LLaMA-mallin perusversiota, joka käsittää yksisäikeisen, skalaarisen prosessoinnin. Kunkin tokenin kohdalla tämä prosessi koostuu seuraavista vaiheista:

Näiden työkalujen toteutukset ovat tarjolla llm.h-tiedostossa. Voit vapaasti käyttää näitä tai vaihtoehtoisesti omaa toteutustasi, jos uskot sen parantavan suorituskykyä.

Vinkkejä

Osassa testiasetelmista tietyt kielimallin osat ovat poissa käytöstä. Nämä voivat auttaa toteutusvirheiden löytämisessä.

Tutustu oheiseen mallitoteutukseen. Yritä paikantaa eniten aikaa vievät kohdat sekä kohdat, joissa laskentaa voidaan helposti rinnakkaistaa. Jo lisäämällä pragman #pragma omp parallel for oikeisiin paikkoihin ansaitset tehtävästä vähintään yhden pisteen.

Toteutusta voi kehittää edelleen hyödyntämällä käskytason rinnakkaisuutta (ILP) ja vektorointia. Täysien pisteiden saaminen edellyttää kuitenkin tehokkaampaa rinnakkaistamisstrategiaa.

Demo

Yleisesti suurten kielimallien vaikuttavuus perustuu niiden kykyyn tuottaa ihmismäistä tekstiä, mutta kiinnostavia asioita voidaan silti tehdä myös kehotteen prosessoinnin osalta. Koska ennustettuja todennäköisyysjakaumia voidaan verrata toteutuneeseen tekstiin, on mahdollista selvittää, mitkä kehotteen osat olivat verkon kannalta odottamattomimpia.

Tehtäväpohjan demotyökalu, jota kutsutaan käskyllä ./grading demo, visualisoi kunkin tekstin tokenin yllättävyyden. Esimerkiksi ./grading demo "Once upon a time, there was a test story." tuottaa seuraavan tulosteen:

Once upon a time, there was a test story.

Huomaa, että tätä varten tulee ladata esikoulutettu malli verkosta.

Autoregressiivinen kielimallinnus, transformerit ja rinnakkaisuus

Nykyaikaisilla koneoppimismenetelmillä voidaan saavuttaa loistavia tuloksia, jos saatavilla on suuri määrä luokiteltua koulutusaineistoa. Suurin osa olemassa olevasta datasta on kuitenkin luokittelematonta, mutta se sisältää silti arvokasta tietoa, jota voidaan oppia sen rakenteesta. Juuri tähän autoregressiivinen kielimalli pyrkii: ennustamaan tietyn sanajonon perusteella, mikä sana tulee seuraavaksi. Yleisemmin teksti jaetaan tokeneiksi, jotka voivat olla sanoja, tavuja tai jopa yksittäisiä kirjaimia. Tätä varten koulutusaineistoksi tarvitaan ainoastaan suuri tekstikorpus, joka voidaan kerätä esimerkiksi Wikipediaa haravoimalla.

Luultavasti yksinkertaisin tapa mallintaa tällainen tehtävä on soveltaa Markovin oletusta, jossa jonon seuraava elementti riippuu ainoastaan sitä edeltävästä elementistä. Tällöin kielimalli on vain valtava todennäköisyystaulukko: tämän tokenin perusteella tässä ovat todennäköisyydet seuraavalle tokenille. Malli on äärimmäisen tehokas, mutta mallinnuskapasiteetiltaan melko rajoittunut. Tällaista ratkaisua voidaan käyttää esimerkiksi luomaan tekaistuja sanoja, joissa ilmenee todellisen kielen ominaispiirteitä, muttei tuottamaan johdonmukaisia lauseita.

Ilmaisuvoimaa voisi lisätä pidentämällä Markovin mallin konteksti-ikkunaa, jolloin pelkän viimeisen tokenin tarkastelun sijaan tarkastellaan viimeisiä n:ää tokenia. Tämä valitettavasti johtaa muistinkäytön (samoin kuin koulutusaineiston tarpeen) eksponentiaaliseen kasvuun konteksti-ikkunan koon mukana. Vaihtoehtona on pakata konteksti state-vektoriin ja tehdä ennustuksia sen perusteella. Korkean tason idea on:

for token in sequence do
    state = update_state(state, token)
    prediction = output_prediction(state)

Ilmaisuvoiman parantamiseksi, tyypilliseen syväoppimisen tapaan, useita näistä prosesseista voidaan pinota kerroksittain siten, että kerroksen l tila state[l, p] jonon kohdassa p on funktio edellisen aika-askeleen tilasta ja edellisen kerroksen tilasta samassa aika-askeleessa: state[l, p] = update_state(state[l, p-1], state[l-1, p]).

Tämän lähestymistavan soveltamisessa pidempiin merkkijonoihin on useita haasteita; erityisesti funktion update_state täytyy olla huolellisesti valittu, jotta signaalit voivat kulkea pitkiä matkoja. Lisätietoa kiinnostuneille löytyy Andrej Karpathyn hienosta yhteenvedosta, joka käsittelee toistuvien neuroverkkojen toimintaa.

Valitettavasti yksi haaste säilyy: kuinka näitä verkkoja koulutetaan valtavilla saatavilla olevilla tietomäärillä? Verkon päivitysrakenne tarkoittaa, että riippuvuuksia on olemassa sekä edeltävään kerrokseen että saman kerroksen edelliseen tilaan. Tämä on vastakohta uudemmalle Transformer-arkkitehtuurille, jossa seuraava tila lasketaan kaikkien aiempien tilojen perusteella vain edellisessä kerroksessa, mikä poistaa yhden riippuvuusakselin. Tämän seurauksena, vaikka eri kerrosten käsittely on tehtävä peräkkäin, kaikki saman kerroksen sijainnit voidaan käsitellä rinnakkain. Tämän ansiosta meillä on nyt suuria kielimalleja, jotka on koulutettu biljoonilla tokeneilla.

Koneoppimismenetelmän menestys tai epäonnistuminen voi siis olla vahvasti riippuvainen nykyisten laitteistojen suorituskyvystä. Tämä ilmiö on tullut tunnetuksi nimellä Hardware Lottery.