SAMSUNG_0126_W8 Advertisement SAMSUNG_0126_W8 Advertisement SAMSUNG_0126_W8 Advertisement

Neurónová sieť na generovanie textu - 1. časť, príprava

Digitálne zručnosti
0

Námetom trojdielneho miniseriálu je e vytvorenie a natrénovanie vlastnej neurónovej siete. Natrénujeme ju na väčšom objeme textu v prirodzenom jazyku, v našom prípade na štyroch knihách Následne túto neurónovú sieť použijeme na generovanie textu krátkej poviedky. Zadáte prvých päť slov a algoritmus bude generovať ďalšie slová poviedky.

Kompletný príklad je na GitHube https://github.com/lubolacko/ML-v-Pythone-priklady

Na trénovanie neurónovej siete použijem štyri knihy od Karla Maya, tri diely Winnetoua a knihu Poklad v striebornom jazere. Vo všetkých knihách „účinkujú“ plus mínus rovnaké postavy a dej sa odohráva v rovnakom prostredí.

Štyri knihy sú samozrejme na natrénovanie neurónovej siete, ktorá má generovať texty veľmi málo. Reálne neurónové siete tohto typu sú trénované na obrovskom objeme textov napríklad z tisícov, alebo skôr stoviek tisícov slov. Určite si položíte otázku, prečo aj my v sprievodnom príklade k tejto kapitole nenatrénujeme neurónovú sieť na stovkách, alebo aspoň na desiatkach kníh. Pochopíte, keď spustíte trénovanie. Aj s využitím výpočtových možností moderných grafických kariet, ktoré realizujú výpočty mnohonásobne rýchlejšie než procesory to bude trvať pomerne dlho.

Môžete použiť online prostredie Google Colaboratory, alebo príklad vyskúšať v lokálnom prostredí Jupyter Notebook s knižnicou PyTorch a a podporu NVIDIA CUDA. V online prostredí Google Colab môžete na urýchlenie výpočtov využiť GPU a NVIDIA Cuda aj v prípade ak na lokálnom počítači nemáte nainštalovanú kompatibilnú karu NVIDIA.  GPU tento typ výpočtov zvládne mnohonásobne rýchlejšie ako procesor. V prostredí Google Colaboratory nastavte runtime prostredie na T4 GPU

V prípade ak použijete Google Colaboratory potrebujete nakopírovať všetky texty z ktorých sa neurónová sieť bude učiť na Disk Google. Ak využijete Jupyter Notebook na lokálnom počítači súbory nakopírujte do jeho pracovného adresára.

Vývojové prostredie Jupyter Notebook

Vo videu je kompletný postup inštalácie a konfigurácie NVIDIA CUDA, Pythonu, knižnice PyTorch a vývojového prostredia Jupyter Notebook

Princíp

Bez ohľadu na objem textu na ktorom budeme neurónovú sieť trénovať, bude potrebné text najskôr vyčistiť od nealfanumerických a grafických znakov a transformovať na postupnosť slov a keˇže neurónové siete pracujú s číslami, tak následne na postupnosť čísel. 

Príprava údajov, odstránenie neabecedných znakov

Najskôr načítame knihu, alebo knihy, na ktorých sa bude neurónová sieť učiť. Pre jednoduchosť bude kniha v textovom súbore s príponou txt. Nie je problém načítať ani knihu vo formáte PDF, stačí nainštalovať a importovať knižnicu PyPDF2. Naše štyri spomínané knihy máme v pracovnom adresári v súboroch

Winnetou I.txt
Winnetou II.txt
Winnetou III.txt
Poklad v Striebornom_jazere.txt

Knihy majú podobný rozsah, na ilustráciu štatistiky vo Worde ukazujú že text knihy Poklad v striebornom jazere má 293 strán A4 a obsahuje 167 954 slov. Vy samozrejme môžete použiť akékoľvek knihy, ktorú máte k dispozícii.

Pred spustením Jupyter Noteboooku je potrebné v konzolovej aplikácii nainštalovať knižnicu Natural Language Toolkit (nltk) príkazom:

pip install nltk

Knižnicu môžete nainštalovať aj priamo v prostredí Jupyter Notebook, vtedy bude pred príkazom pip výkričník.

!pip install nltk

Kód pre spustenie na lokálnom PC v prostredí Jupyter notebook.

#načítanie knih
kniha1 = open('./Winnetou I.txt', 'r')
kniha2 = open('./Winnetou II.txt', 'r')
kniha3 = open('./Winnetou III.txt', 'r')
kniha4 = open('./Poklad v Striebornom_jazere.txt', 'r')
knihy = kniha1.read()+ kniha2.read() + kniha3.read() + kniha4.read()
"Spolu " +str(len(knihy)) + " znakov"
 
---výpis---
'Spolu 3494393 znakov'

Máme k dispozícii text, ktorý má spolu 3 494 393 znakov.

Variant, - načítanie z Google drive (pre jednu knihu)

from google.colab import drive
drive.mount('/content/drive')
kniha1 = open('/content/drive/My Drive/ML Neuronova siet/Winnetou I.txt', 'r')
kniha1 = kniha1.read()

Z textu potrebujeme vytvoriť zoznam slov. Pri tejto transformácii potrebujeme odstrániť bodky čiarky, pomlčky, otázniky výkričníky, úvodzovky...  tak aby zostali len slová. V ďalšom kroku teda text konvertujeme na zoznam slov a vynecháme nealfanumerické znaky. Na tento účel využijeme knižnicu Natural Language Toolkit (ntlk), konkrétne funkciu word_tokenize()

import nltk
nltk.download('punkt_tab')
from nltk.tokenize import word_tokenize
slova = word_tokenize(knihy.lower())
slova [:30]
 
---výpis---
 ['milý', 'čitateľ', ',', 'vieš', ',', 'čo', 'znamená', 'slovo', '„', 'greenhorn', '“', '?', ...

nechali sme si vypísať prvých 30 slov a aj v takomto skrátenom výpise vidíme, že sa v zozname slov nachádzajú aj bodky, čiarky, úvodzovky, otáznik a podobne. Preto potrebujeme zoznam slov vyčistiť od neabecedných znakov. Reťazec obsahujúci zoznam väčšiny neabecedných znakov získame z knižnice string ako string.punctuation.

# kód na vysvetlenie
import string
punct = string.punctuation
print(punct)
 
---výpis---
 !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~

Neabecedné znaky z takto získaného zoznamu a tiež úvodzovky hore, úvodzovky dole a dlhšiu pomlčku uvádzajúcu priamu reč vymažeme a vytvoríme nový zoznam slov do ktorého uložíme len slová skladajúce sa z písmen. Funkcia len() poskytne zoznam unikátnych slov, čiže vytvoríme slovník.

import string
zoznam_slov = []
neabecedne_znaky = string.punctuation
neabecedne_znaky
 
for slovo in slova:
        for char in slovo:
            if char in neabecedne_znaky:
                slovo = slovo.replace(char, "")
            if char =="„" or char =="“" or char =="–":
                slovo = slovo.replace(char, "")
        if slovo not in neabecedne_znaky:
            zoznam_slov.append(slovo)
print("Počet slov:", len(zoznam_slov), "unikátnych", len(set(zoznam_slov)))
zoznam_slov [:30]
 
---výpis---
Počet slov: 573340 unikátnych 43392
['milý', 'čitateľ', 'vieš', 'čo', 'znamená', 'slovo', 'greenhorn', 'keď', 'niekoho', 'takto', 'nazvú', 'značí', 'to', 'že', 'mu', 'dali', 'veľmi', 'uštipačnú', 'a', 'znevažujúcu', 'prezývku', ...

V našom prípade máme 573 340 slov, pričom slovník je tvorený 43 392 unikátnymi slovami. Nakoľko neurónové siete nepracujú so slovami, ale a matematikou, čiže číslami, je potrebné previesť slová z textových reťazcov na čísla a identifikovať všetky jedinečné slová, čiže vytvoriť zoznam všetkých slov, ktoré sa v texte vyskytujú. Vytvorím indexy, pričom index, čiže číslo bude zastupovať príslušné slovo. To je zároveň aj odpoveď na prípadnú otázku, či záleží na tom v akom jazyku sú texty na trénovanie. Nezáleží, jedinou podmienkou v takomto jednoduchom príklade siete trénovanej na niekoľko málo knihách je aby s jazyky nemiešali, napríklad slovenčina s češtinou. Pri trénovaní neurónovej siete nás zaujíma len to ako zvyknú slová po sebe nasledovať.

Pomocou funkcie enumerate() slová z našej dátovej množiny očíslujeme a vynecháme duplicitné slová. . Pre názornosť si to najskôr ukážeme na sekvencii niekoľko málo slov, pričom v sekvencii sú úmyselne aj duplicitné slová. Premenné v tomto vysvetľujúcom mini príklade majú predponu temp_ a v príklade s trénovaním neurónovej siete nebudú použité. Najskôr zistíme unikátne slová

# kód na vysvetlenie
temp_zoznam_slov = ['kto','pozná','indiánov','a','pomery','života','indiánov','je','odborník','na','indiánov']
temp_slovnik= set(temp_zoznam_slov) #unikátne slová
temp_slovnik
 
---výpis---
 {'a', 'indiánov', 'je', 'kto', 'na', 'odborník', 'pomery', 'pozná', 'života'}

Z 11-tich slov je 9 unikátnych, ktoré tvoria slovník. Pomocou funkcie enumerate() slová v slovníku očíslujeme

temp_indexy_slov = {slovo: i for i, slovo in enumerate(temp_slovnik)}
temp_indexy_slov
 
---výpis---
{'života': 0,
 'je': 1,
 'kto': 2,
 'odborník': 3,
 'indiánov': 4,
 'a': 5,
 'na': 6,
 'pomery': 7,
 'pozná': 8}

Vráťme sa však k textu z knihy. Zrealizujeme na ňom rovnaké úpravy – vytvorenie slovníka a transformáciu slov na čísla Vypíšeme len prvých 10 čísel

slovnik= set(zoznam_slov) #unikátne slová
print("Slovná zásoba na trénovanie má", len(zoznam_slov),"slov, unikátnych slov je", len(slovnik))
indexy_slov = {slovo: i for i, slovo in enumerate(slovnik)}
zoznam_indexov_slov = [indexy_slov[slovo] for slovo in zoznam_slov]
zoznam_indexov_slov[:10]
 
---výpis---
Slovná zásoba na trénovanie má 573340 slov, unikátnych slov je 43392
[14006, 39902, 16444, 35286, 6856, 10227, 15509, 40747, 11642, 28567]

Rozdelenie dát do dávok

Je výpočtovo náročné vyhodnotiť stovky tisíc hodnôt naraz, takže aby sme nepreťažili neurónovú sieť budeme ju trénovať po dávkach. Preto údaje na trénovanie rozdelíme do dávok. Veľkosť dávky bude daná hodnotou parametra davka. V prvom pokuse nastavíme veľkosť dávky na 5.

V trénovacej množine budú slová za sebou usporiadané ako pätica vstupov a jeden výstup, pričom v každej ďalšej n-tici budú o jedno posunuté. Ku každej pätici bude ako výstup priradené slovo, ktoré za päticou nasleduje. Inak povedané, existuje určitá pravdepodobnosť, že za piatimi slovami zo vstupov by v generovanom texte malo nasledovať príslušné slovo, Prípadne za štyrmi slovami zo vstupov a piatym slovom iným. V ďalšej n-tici bude posun o jedno slovo. Najlepšie to pochopíte na príklade z úryvku textu

Veľká horúčava zahnala zámožnejších cestujúcich do kajút a kabín Väčšina z tých, čo mali iba palubný lístok, sa utiahla za sudy, debny a rozličnú batožinu, kde bol aspoň aký-taký tieň.

Vytvoríme päticu vstupov a jeden výstup

veľká horúčava zahnala zámožnejších cestujúcich -  do
horúčava zahnala zámožnejších cestujúcich do - kajút
zahnala zámožnejších cestujúcich do kajút - a
zámožnejších cestujúcich do kajút a - kabín
cestujúcich do kajút a kabín - väčšina
do kajút a kabín väčšina - z
kajút a kabín väčšina z - tých

Tréningové údaje budú tyvoriť n-tice, pričom prvých päť slov bude zoznam vstupov a šiesty prvok oddelený od vstupov bude cieľ. Aby sme nepreťažili našu neurónovú sieť budeme jej údaje predkladať po dávkach piatich slov ako vstupov. Neurónová sieť sa na základe piatich za sebou idúcich slov snaží uhádnuť šieste slovo. Počet n-tíc, ktoré takto vytvoríme bude počet_slov mínus dávka, pretože posledných 5 slov z textu knihy už nemáme čím doplniť.

Údaje na trénovanie budú uložené v štruktúre typu zoznam a uložené budú po n-ticiach, pričom n-ticu budú tvoriť čísla reprezentujúce slová počnúc hodnotou premennej i, čiže

data [i], data [i+1], data [i+2], data [i+3], data [i+4], data [i+5]

Vytvoríme množinu údajov na trénovanie neurónovej siete. Vypíšeme len prvých 6 skupín slov

davka=5
pocet_slov = len(zoznam_slov) #pocet slov knihy
trenovacia_mnozina = [([zoznam_indexov_slov[i], zoznam_indexov_slov[i+1], zoznam_indexov_slov[i+2],zoznam_indexov_slov[i+3], zoznam_indexov_slov[i+4]], zoznam_indexov_slov[i+5]) for i in range(pocet_slov-davka) ]
trenovacia_mnozina[:6]
 
---výpis---
[([13504, 38620, 10014, 22560, 21206], 4644),
 ([38620, 10014, 22560, 21206, 4644], 28236),
 ([10014, 22560, 21206, 4644, 28236], 33777),
 ([22560, 21206, 4644, 28236, 33777], 4689),
 ([21206, 4644, 28236, 33777, 4689], 33818),
 ([4644, 28236, 33777, 4689, 33818], 15717),
 ([28236, 33777, 4689, 33818, 15717], 32807),
 ([33777, 4689, 33818, 15717, 32807], 23282),
 ([4689, 33818, 15717, 32807, 23282], 42949),
 ([33818, 15717, 32807, 23282, 42949], 22684)]

Trénovacia množina má ako vstupy pätice za sebou idúcich slov (technicky ich indexov), zakaždým o jeden index posunuté.

Trénovaciu množinu máme pripravenú, takže v pokračovaní môžeme vytvoriť a natrénovať neurónovú sieť.

Zobrazit Galériu

Luboslav Lacko

Všetky autorove články

Pridať komentár

Mohlo by vás zaujímať

Mohlo by vás zaujímať