Təbii dilin emalı - word2vec.

April 10, 2020, Mammad Hajili

Unitar kod sözlərin vektorizasiyası üçün önəmli üsuldur. Bu üsulda vektorlar mətndəki sözlərin verilən ölçülü lüğətdəki yerinə, yəni intervalında indekslərə uyğun dəyərlərin yazılması ilə əldə edilir. Sözün lüğətdəki yeri -dirsə, həmin sözün ölçülü unitar kod vektorunda indeksinin dəyəri , digər bütün indekslər olacaqdır.

Bu üsul çox asan olsa da, bir çox halda əlverişli üsul deyildir. Ən önəmli problemlərdən biri unitar kod vektorlarlarının sözlər arasında bənzərliyi dəqiq ifadə edə bilməməsidir. Bu bənzərliyi ifadə etmək üçün istifadə olunan üsullardan biri kosinus oxşarlığıdır. Belə ki, iki vektor arasında bucağın kosinusu onlar arasında oxşarlığı ifadə edir. İxtiyari vektorları üçün olan kosinus bənzərliyi belə ifadə olunur:

Əgər unitar vektorların xüsusiyyətinə nəzər salsaq, görə bilərik ki, iki müxtəlif sözün vektorları hər zaman perpendikulyardır (). Deməli, iki müxtəlif sözün vektorları üçün kosinus oxşarlığı onların bir-birinə mənaca nə dərəcə yaxın və ya uzaq olmasından asılı olmayaraq hər zaman -a bərabərdir.

Read More

Təbii dilin emalı - Giriş, TF-IDF, n-gram.

November 24, 2019, Mammad Hajili

Təbii dilin kompüter tərəfindən emalı ilkin hesablayıcı maşınlar erasından bəri ən önəmli ideyalardan biri idi. Belə ki, hətta Stenli Kübrikin “2001: A Space Odyssey” filmində HAL 9000 kompüteri ingilis dilini anlayır və danışır kimi təsvir edilmişdi. Təbii ki, filmin nümayiş tarixi 1968-cı ili nəzərə aldığımızda izləyicilər bütün elmi-fantastika filmlərində olduğu kimi bu filmdə də reallıqdan uzaq optimistik bir hal ilə qarşı-qarşıya qalmışdılar. Ancaq süni intellekt anlayışının kompüter elmləri və fəlsəfi nəşrlərdə üzə çıxması və bu sahələrdə olan elmi araşdırmalar (maşın öyrənmə, proqramlaşdırma dilləri və neyroelmlər) iki sualın verilməsinə gətirib çıxarırdı.

  1. Yazı və ya danışıqdan kompüterin riyazi əməliyyatlar yerinə yetirə biləcəyi və üzərində araşdıracağı bir riyazi anlayış qurmaq mümkündür mü?
  2. Kompüterdəki hər hansı riyazi təsvirdən yazı və ya danışıq yaradıla bilər mi?

Bu iki sual süni intellekt üçün riyazi dilçilik və müasir maşın öyrənmə konteksində hələ də cavablanmağa çalışan suallardır. Bu iki sualı cavablamağa çalışan elm sahəsi isə təbii dilin emalı (ing. Natural Language Processing - NLP) adlanır.

Belə bir problem var ki, biz insanlığın bütün təbii dillərini və insanların düşüncələrini (hələ ki) tamamilə modelləyə bilmirik. Bunun əvəzinə isə müasir NLP-in işləmə prinsipi əsas etibarı ilə spesifik tapşırıqlar üçün verilən datadan öyrənmə, ona uyğun riyazi model qurma və modelin yekun qiymətləndirilməsinə əsaslanır.

Bu yazıda(ümid edirəm, yazılarda) mən təbii dillərin yalnızca yazılı təsvirinin emalı haqqında danışacam. Belə ki, bundan sonra “təbii dilin emalı” söz birləşməsinin əvəzinə NLP abbreviaturasından istifadə olunacaq və haqqında danışılacaq mövzular və alqoritmlər yazının emalı haqqında olacaqdır.

NLP-nin istifadə olunduğu və üzərində hələ də elmi araşdırmalar gedən bəzi tapşırıqlar bunlardır:

  • Maşın tərcüməsi (Machine Translation)
  • Sual cavablama və ya mətn özətləmə (Questions Answering, summarization)
  • Məlumat axtarışı və əldə edilməsi (Information search, retrieval, extraction)
  • Məlumatın filtri və sinifləndirilməsi (Information filtering and classification)

Yuxarıda da qeyd etdiyim kimi bunların hər biri spesifik tapşırıqlardır və hər biri üçün uyğun datasetlər və riyazi modellər vacibdir. Ancaq bu tapşırıqların həlləri maşın öyrənmə alqoritmi mövcud olsa belə çox da asan deyil. Çünki, lazım olan datasetin əldə edilməsi heç də ucuz və rahat başa gələn bir iş deyil. Əksər tapşırıqlarda işarələnmiş data lazımlıdır, ancaq bu data bəzi hallarda internetdə məlumat bazalarında ya mövcud olmur, ya da arzuolunan şəkildə olmur. Mövcud olmayan datasetin yaradılması üçün lazım olan tekstin işarələnməsi isə diqqətlə və düzgün edilməli iş olduğu üçün tapşırığın aid olduğu sahənin ekspertlərin köməyi lazımdır. Bu isə əlavə pul və vaxt xərci ilə nəticələnir. Məsələn, tapşırıq verilən cümlənin cümlə üzvlərinin işarələnməsidirsə, bizə lazım olan data çoxlu cümlələr və cümlədəki hər bir sözə/birləşməyə uyğun cümlə üzvünün işarələnməsidir. Təbii ki, dilçilik sahəsində ekspert olmayan biri nə qədər çalışsa da, çox güman ki, hər bir istisna halı nəzərə almayacaq və çoxlu səhvlər buraxacaq, buna görə də belə datasetlər hazırlandığında sahə üzrə təcrübəsi olan insanların köməyindən istifadə edilir. Daha bir çətinlik isə, yenə əksər hallarda hər hansı bir dil üçün, məsələn, ingilis dilinin cümlə üzvləri üçün hazırlanan model başqa bir dil, məsələn, Azərbaycan dili üçün yararlı olmamasıdır. Buna görə də tapşırıqların həllinin çətinliyi və ya mümkünlüyü datasetin mövcudluğundan və ölçüsündən asılı olaraq müxtəlif dillər üçün də fərqlənir.

Datasetin olması yaxşı xəbər olsa da, kompüterin onu anlaması üçün teksti riyazi bir anlayış ilə ifadə etməyimiz vacibdir. NLP-də bu proses tekstin vektorizasiyası adlanır. Yəni biz yazıdakı hər bir sözü, dolayısı ilə cümləni, paraqrafı və mətni vektor ilə ifadə edirik. Tək-tək işarələr məna ifadə etmədiyindən bəzi işarə əsaslı neyron modelləri çıxmaq şərti ilə əsasən NLP-də ən kiçik vahid kimi ard-arda gələn işarələr toplusunu qəbul edirik. NLP-də belə toplu token adlanır. Tokenlər əsasən sözlər olsa da, bəzən istisna hallarla qarşılaşdığımız üçün belə topluları sadəcə “söz” adlandırmırıq. Datasetdəki bütün fərqli tokenlərdən ibarət olan set lüğət adlanır.

Unitar Kod

Tekstin ən sadə vektorizasiyası unitar kod üsuludur. Belə ki, belə vektorların ölçüsü hər bir token üçün lüğətin ölçüsünə bərabərdir və tokenin lüğətdəki yerini ifadə edən indeks 1 ilə, qalan bütün indekslər 0 ilə ifadə olunur. Gəlin hesab edək bizim kiçik datasetimiz var və bu dataset aşağıdakı 2 tekstdən ibarətdir.

  1. Dostum kitab oxumağı sevir. O, filmləri də sevir.
  2. Kitab masada qalıb, dostu gətirəcək.

Lüğət:

'Dostum', 'dostu', 'də', 'filmləri', 'gətirəcək', 'Kitab',
'kitab', 'masanın', 'qalıb', 'O', 'oxumağı', 'sevir', ',', '.'

Tokenlərin lüğətdəki yerini nəzərə alarsaq, bəzi tokenlərin unitar kod vektorları belə olacaqdır:

  • "dostu" : [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
  • "sevir" : [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0]

Bu datasetdə lüğətin ölçüsü 14-dür. Belə halda yuxarıda da gördüyümüz kimi hər bir unitar kod vektorun ölçüsü (14,1) olacaqdır. Bütün lüğəti ifadə etmək istəsək bizə (14,14) ölçülü vahid matris lazım olacaqdır. Nəzərə alsaq ki, böyük datasetlər üçün lüğət də olduqca böyük olacaq və bu halda vahid matris olduqca seyrək olacaqdır. Belə seyrək böyük ölçülü matrislər bizə öyrənmə alqoritmlərindəki matrislərin vurulması, tərsinin tapılması əməliyyatları zamanı çoxlu vaxt və resurs itkisinə səbəb olacaqdır. Təbii ki, bu problemləri aradan qaldırmağın yolları vardır. Bunlardan ilki lüğətin mümkün olduqca ölçüsünü azaltmaqdır. Bunun üçün müxtəlif üsullar vardır, bu üsullar toplusuna tekstin təmizlənməsi və ilkin prosesi (text cleaning and preprocessing) deyilir.

Bizim kiçik misalımızda olan lüğətə fikir versək, görərik ki, kökü eyni olan sözlərin hər biri fərqli bir tokenlə ifadə olunub. (“insana, insanların”). Həmçininin durğu işarəsi və ədat kimi kontekst ifadə etməyən tokenlər də lüğətdə mövcuddur. Hətta biri böyük və digəri kiçik hərflə başlayan eyni söz fərqli vektorlarla ifadə olunur. Bunları və digər bizim misallarda olmayan halları ehtiva edən üsulları gəlin incələyək:

Təmizlik

Təmizlik əsasən internetdən əldə etdiyimiz yazılı məlumatların normal cümlə strukturu halına salmaq üçün istifadə olunur. Bu metod üçün əsasən regex ifadələrindən istifadə olunur. Mən bəzi halları Python istifadə edərək göstərməyə çalışacam.

  1. Bəzən tekstlər müxtəlif internet bazalarından əldə edildikdə onların içində xüsusi HTML və ya XML “tag”-lərdən istifadə olunur. Məsələn:

     <b> çox gözəl məshuldur </b>
    

    Buradakı <b> və oxşar tag-ləri silmək üçün istifadə olunan regex ifadəsi budur:

     import re
    
     text = "<b> çox gözəl məshuldur </b>"
     clean_text = re.sub(re.compile('<.*?>'), '', text)
     print(clean_text)
        
     """
         Çıxış: 
             çox gözəl məshuldur
     """
    

    Bu metod tvitlərdən ibarət olan datasetdə linklərin, istifadəçi adlarının silinməsi üçün də istifadə oluna bilər. Regex ifadələr ilə tanış olub bu hallar üçün özünüz yoxlaya bilərsiniz.

  2. Durğu işarələrinin silinməsini də regex ifadələrdən istifadə edərək edə bilərik.

     import re
        
     text = "Biz İsmayıllı, Şəki və Qəbələdə olduq."
        
     clean_text = re.sub('[\W]+', ' ', text, re.UNICODE)
        
     print(clean_text)
        
     """
         Çıxış: 
             Biz İsmayıllı Şəki və Qəbələdə olduq
     """
    

Tekstin ilkin prosesi

  1. Kiçik hərflər

    Bizim yuxarıda işlətdiyimiz iki cümləlik kiçik datasetdə “kəndlərdə” və “Kəndlərdə” fərqli tokenlər idi. Bu hal böyük datasetlərdə lüğətin ən az iki dəfə artmasına gətirib çıxarır(bəzi hallarda səhv yazılışlar nəticəsində bu əmsal daha da arta bilər), həm də məna etibarı ilə bu iki söz eynidir. Ona görə də tekstin ilkin prosesi zamanı bütün hərflərin kiçiyə çevirmək çox önəmlidir. Bu əməliyyat üçün Python .lower() funksiyasından istifadə edə bilərik.

     import re
    
     text = "Biz İsmayıllı, Şəki və Qəbələdə olduq."
    
     #durğu işarələrinin silinməsi
     clean_text = re.sub('[\W]+', ' ', text, re.UNICODE)
        
     clean_text = clean_text.replace('İ', 'I')
     clean_text = clean_text.lower()
    
     print(clean_text)
        
     """
         Çıxış:
             biz ismayıllı şəki və qəbələdə olduq
     """
    
  2. Lazımsız sözlərin(Stopwords) silinməsi

    Lazımsız sözlərin silinməsi olduqca önəmli üsuldur, belə ki, bəzi sözlər həddindən artıq çox və ya nadir istifadə edildiyindən ümumi tekst üçün mənaya çox təsiri olmur, üstəlik lüğətin ölçüsünü böyüdür. Əksər hallarda lazımsız sözlərin siyahısı Zipf qanununa əsasən böyük toplular üçün olan statistikalar ilə hazırlanır. Əsasən bu siyahıya “da/də” kimi ədatlar, “o/sən/mən” kimi əvəzliklər, bağlayıcılar, çox işlənən isimlər və fellər aid olur. Siyahılardan biri ilə bu linkdən tanış ola bilərsiniz.

     import re
    
     text = "Biz İsmayıllı, Şəki və Qəbələdə olduq."
        
     #burada lazımsız sözlərin siyahısı olmalıdır. məs. [biz, və]
     stopwords = #siyahı
        
     #durğu işarələrinin silinməsi
     clean_text = re.sub('[\W]+', ' ', text, re.UNICODE)   
     clean_text = clean_text.replace('İ', 'I')
    
     #kiçik hərfə çevirmə
     clean_text = clean_text.lower() 
     #başdakı və sondakı boşluqları silmə
     clean_text = clean_text.strip()
        
     #cümlənin tokenlərə ayrılması
     tokens = clean_text.split(' ') 
        
     #stopwords listində olmayan tokenlər
     tokens = [token for token in tokens if token not in stopwords]
        
     print(tokens)
        
     """
         Çıxış: 
             ["ismayıllı", "şəki", "qəbələdə", "olduq"]
     """
    
  3. Sözün kökünü alma(Stemming)

    Azərbaycan dili üçün olan ən önəmli üsul sözün kökünü alma üsuludur. Belə ki, dilimiz aqqlütinativ dildir və dilimizdə çoxlu sözdüzəldici şəkilçilər var. Bu şəkilçilər yeni bir məna yaratmır, sadəcə cümlə quruluşuna əsasən sözə uyğun vəziyyət gətirir. Bizim kiçik datasetdə “insanlar” və “insanların” buna bir misal ola bilər. Kökünə alma üsulundan istifadə edərək hər ikisini “insan” tokeni ilə əvəz edə bilərik. Belə ki, bu üsul lüğətin ölçüsünü də kəskin şəkildə kiçildəcəkdir. NLP-də sözünü kökünü alma üçün ən məşhur və önəmli alqoritmlərdən biri Porter alqoritmidir. Azərbaycan dili üçün bu alqoritmin koduna bu keçiddən baxa bilərsiniz. Kodun istifadəsi üçün aşağıdakı əmrləri yerinə yetirməlisiniz:

    • Əgər git - dən istifadə edirsinizsə, git clone https://github.com/aznlp/azerbaijani-language-stemmer.git - ı əmrini istifadə edərək, etmirsinizsə, keçiddən zip formatında endirib, daha sonra qovluğa çıxarış edə bilərsiniz.
    • Endirilən qovluqda yeni bir Python file yaradıb aşağıdakı kod ilə test edə bilərsiniz:
     from stemmer import Stemmer
     import re
    
     text = "Biz İsmayıllı, Şəki və Qəbələdə olduq."
        
     #burada lazımsız sözlərin siyahısı olmalıdır. məs. [biz, və]
     stopwords = #siyahı
        
     #durğu işarələrinin silinməsi
     clean_text = re.sub('[\W]+', ' ', text, re.UNICODE)
     clean_text = clean_text.replace('İ', 'I')
        
     #kiçik hərfə çevirmə
     clean_text = clean_text.lower() 
     #başdakı və sondakı boşluqları silmə
     clean_text = clean_text.strip()
        
     #cümlənin tokenlərə ayrılması
     tokens = clean_text.split(' ') 
        
     #stopwords listində olmayan tokenlər
     tokens = [token for token in tokens if token not in stopwords]
        
     stemmer = Stemmer()
        
     # tokenlərin köklərinin alınması
     stems = stemmer.stem_words(tokens) 
        
     print(stems)
     '''
        Çıxış: 
            ["ismayıllı", "şəki", "qəbələ", "ol"] 
     '''
    

Sadaladığımız üsullardan istifadə edərək əvvəl göstərdiyimiz 2 tekstdən ibarət olan kiçik datasetimiz yenidən incələyək:

  1. Dostum kitab oxumağı sevir. O, filmləri də sevir.
  2. Kitab masada qalıb, dostu gətirəcək.

Təmizlik və ilkin prosesdən sonra lüğətimiz belə olacaqdır:

'dost', 'film', 'gətir', 'kitab', 'masa', 'oxu', 'sev', 'qal'

Tokenlərin lüğətdəki yenidən yerini nəzərə alarsaq, bəzi tokenlərin unitar kod vektorları belə olacaqdır:

  • dost - [1, 0, 0, 0, 0, 0, 0, 0]
  • masa - [0, 0, 0, 0, 1, 0, 0, 0]

Fikir versək, görərik ki, təmizlik və ilkin prosesdən sonra '.', ',' 'də', 'O' silinmiş, 'Dostum''dostu' isə 'dost' kökü isə əvəz olunmuşdur. Hər bir unitar kod vektor isə lüğətin ölçüsü kiçildiyi üçün (8, 1) ölçülü olacaqdır. Hər bir teksti vektor şəklində göstərmək üçün tokenlərin vektor cəmini almaq kifayət edir. Yəni bu o deməkdir ki, tekstdəki mövcud tokenlərin indesksi vektorda 1 ilə, lüğətdəki digər tokenlərin indeksləri isə 0 ilə ifadə olunur.

1. ["dost", "kitab", "oxu", "sev", "film", "sev"] - [1, 1, 0, 1, 0, 1, 1, 0] 2. ["kitab", "masa", "qal", "dost", "gətir"] - [1, 0, 1, 1, 1, 0, 0, 1]

Haqqında danışdığımız unitar kod modelinə fikir versək, görərik ki, tekstdəki sözlərin sırası vektorizasiya zamanı önəm daşımır. Belə modellərə NLP-də söz çantası modelləri deyilir. Hər bir vektorun 1 olan indekslərinə uyğun gələn tokenlər birlikdə bir multiset və ya başqa cür desək çantanı əmələ gətirir. Məsələn yuxarıda da göstərdiyim kimi birinci teksti ifadə edən [1, 0, 1, 1, 1, 0, 0, 1] vektoruna uyğun gələn multiset/çanta ["kitab", "masa", "qal", "dost", "gətir"] olacaqdır.

Termin tezliyi

Unitar kod modeli çox sadə olsa da, tekstdəki tokenlərin tezliyini ifadə edə bilmir. Məsələn, incələdiymiz tekstlərdən birinə baxaq:

Dostum kitab oxumağı sevir. O, filmləri də sevir.

Burada təmizlik və ilkin prosesdən sonra “sev” tokeni iki dəfə təkrarlanır, ancaq bizim vektorumuz unitardır, yəni tokenin neçə dəfə təkrarlanmağından asılı olmayaraq vektorda 0 və ya 1 dəyərini alır. Bu vəziyyət bəzi hallarda problem ola bilər, belə ki, sözün bir neçə dəfə işlənməsi ümumi məzmuna daha çox təsir etməsi ilə nəticələnə bilər. Unitar kod vektorun bu əskikliyini aradan qaldırmaq üçün oxşar model olan termin tezliyindən(TF) istifadə olunur. Belə ki, bu vektor üçün hər bir tokenin tekstdə olub-olmamasından əlavə, neçə dəfə rast gəlindiyi də vacibdir. Deməli, bayaq vurğuladığımız tekst üçün TF vektoru belə ifadə edə bilərik:

["dost", "kitab", "oxu", "sev", "film", "sev"]
{"dost":1, "kitab":1, "oxu":1, "sev":2, "film":1}
[1, 1, 0, 1, 0, 1, 2, 0]

Əksər hallarda TF vektoru normalizasiya edildikdən sonra işlədilir. Bunun üçün bir çox üsul olsa, onların içində ən çox işlədiləni tekstdəki tokenlərin ümumi sayına nisbəti ilə normallaşdırmadır. Bizim misala diqqət etsək, tekst 6 (1 + 1 + 1 + 2 + 1 = 6) tokendən ibarətdir. Deməli bizim vektorumuz tf = [1/6, 1/6, 0, 1/6, 0, 1/6, 1/3, 0] olacaqdır.

Termin tezliyinin unitar koda görə digər müsbət cəhətlərindən biri də tekstdəki hər hansı bir tokeni vektor şəklində yox, real ədədlərlə ifadə edə bilməyimizdir. Yəni, üzərində işlədiyimiz misalda teksti d ilə işarə etsək, tf("dost", d) = 1/6 olduğunu görə bilərik. Halbuki, unitar kod vektorunda bunun üçün lüğətin uzunluğu ölçüsündə vektordan istifadə edirdik.

Termin tezliyi unitar koda görə olduqca yaxşı olsa da, fikir versək, görə bilərik ki, hər hansı tekstdəki bir token üçün olan dəyər yalnız və yalnız o tekstdəki tokenlərin işlənməsindən və sayından asılıdır. Məsələn, ümumi datasetdə çox nadir olan və ixtiyari bir tekstdə 1 dəfə işlənən bir token, həmin tekstdə 1 dəfə işlənən başqa sözlə eyni TF dəyərinə malikdir. Ancaq, bu nadir token işləndiyi tekstin əsas mənasını ehtiva edə bilər. Bu problemi aradan qaldırmaq üçün istifadə olunan üsul isə tərs dokument tezliyi (IDF) adlanır. Bir token üçün IDF dəyəri datasetdəki tekstlərin ümumi sayının həmin token işlənən tekstlərin sayına nisbətinin loqarifmik dəyərinə bərabərdir.

Burada D datasetdəki tekstlərin/dokumentlərin siyahısıdır. Hesablamalar zamanı TF və IDF dəyərlərinin hasilindən istifadə edirik və bu dəyərə TF-IDF dəyəri deyilir.

Tekstin TF-IDF vektorunu almaq üçün TF vektorunu vektordakı tokenlərin uyğun IDF dəyəri ilə hasilini tapmaq kifayətdir. Buna uyğun olaraq kiçik misalımıza bir də diqqət yetirək:

TF vektorlar aşağıdakılardır:

1. ["dost", "kitab", "oxu", "sev", "film", "sev"]
[1/6, 1/6, 0, 1/6, 0, 1/6, 1/3, 0]
2. ["kitab", "masa", "qal", "dost", "gətir"]
[1/5, 0, 1/5, 1/5, 1/5, 0, 0, 1/5]

Hər bir token üçün IDF dəyərlər:

Yekun olaraq hər bir tekst üçün TF-IDF vektorlar belə olacaqdır:

tf_idf("Dostum kitab oxumağı sevir. O, filmləri də sevir.") =
        = [1/6*0, 1/6*0.7, 0, 1/6*0, 0, 1/6*0.7, 1/3*0.7, 0] = 
        = [0, 0.115, 0, 0, 0, 0.115, 0.23, 0]
tf_idf("Kitab masada qalıb, dostu gətirəcək.") =
    = [1/5*0, 0, 1/5*0.7, 1/5*0, 1/5*0.7, 0, 0, 1/5*0.7] =
    = [0, 0, 0.14, 0, 0.14, 0, 0, 0.14]

n-gram

Biz incələdiyimiz hər iki modeldə də yalnızca tək token üçün hesablamalar etdik. Bəzən söz birləşmələri, və ya ardıcıl tokenlər də önəmli məna daşıya bilər. Tekstdəki belə n ardıcıl tokendən ibarət birləşməyə n-gram deyilir. Bizim incələdiyimiz kimi tək tokenlər unigram adlanır. Daha böyük ölçülü birləşmələrin adlanması da gram ifadəsinin əvvəlinə uyğun ədədin latınca mənasını əlavə etməklə də aparılır (2 : bigram, 3 : trigram). Gəlin bir misal ilə n-gramları incələyək:

Dostum kitab oxumağı sevir. O, filmləri də sevir.
["dost", "kitab", "oxu", "sev", "film", "sev"]
  • 1-gram : 'dost', 'sev', və s.
  • 2-gram : 'kitab oxu', 'film sev', və s.
  • 3-gram : 'dost kitab oxu', və s.

Digər n-gramlar üçün TF-IDF dəyərlərinin hesablanması unigramlar üçün etdiyimiz kimi aparılır. Adətən model qurularkən ixtiyari m dəyəri hesablamalarda arqument olaraq daxil edilir və lüğət şərtinə uyğun olaraq n-gramlarla qurulur.

Yekun qeydlər

Bu yazıda incələdiyimiz TF-IDF modeli asan hesablanan və az resurs tələb edən modeldir. Hər hansı bir cümlədəki və ya mətndəki ən önəmli tokenləri TF-IDF dəyərlərinə uyğun olaraq tapmaq mümkündür. Bundan əlavə iki cümlənin/mətnin oxşarlığını onların TF-IDF vektorlarının arasındakı oxşarlıq əmsalından(məs. kosinus əmsalı/oxşarlığı) istifadə edərək tapa bilərik. Bunlara baxmayaraq TF-IDF çanta(BoW) əsaslı model olduğuna görə tokenlərin cümlədəki/tekstdəki sırasını, semantik əlaqələri ehtiva etmir. Bu əskiklikləri aradan qaldırmaq üçün son illərdə müxtəlif vektorlaşdırma modelləri(word2vec, GloVe, fasttext, sent2vec, və s.) üzərində elmi araşdırmalar aparılır. Növbəti yazılar bu modellər haqqında olacaqdır.

Oxuduğunuz üçün təşəkkürlər!

Read More

Guess who's back'propagate. - Zəncir qaydası və geriyə yayılma.

February 21, 2019, Mammad Hajili

Salamlar, keçən yazıda maşın öyrənmənin təməlini təşkil edən xəta funksiyalarından və ən önəmli alqoritmlərdən olan nöqtəvi meyilli azalma haqqında danışmışdıq. Bu dəfə istəyirəm, keçən dəfə qeyd etdiklərimin süni neyron şəbəkələrdə necə istifadə edildiyi haqqında danışım. Belə ki, bu yazı nöqtəvi meyilli azalmanın neyron şəbəkədə tətbiqi olan geriyə yayılma və onun həlli üçün istifadə edəcəyimiz riyazi metod olan zəncir qaydası ilə bağlıdır.

Gəlin ilk olaraq neyron şəbəkə arxitekturasını və irəliyə ötürmə qaydasını yada salaq.

Qeyd: Bu yazıda xəta funksiyası (), və son qat () qarışmasın deyə, xəta funksiyasını ilə əvəz edəcəm.

\begin{eqnarray} z^{(l)} = w^{(l)} x^{(l-1)} + b^{(l)} \tag{1}\end{eqnarray}

\begin{eqnarray} x^{(l)} = \sigma(z^{(l)}) \tag{2}\end{eqnarray}

İndi isə xəta funksiyası və stoxastik nöqtəvi meyilli azalmanı xatırlayaq.

\begin{eqnarray} C = \frac{1}{2}{(Y - f)} ^ 2 \tag{3}\end{eqnarray}

Süni neyron şəbəkədə riyazi modelin çıxış dəyəri şəbəkənin çıxış dəyərinə bərabərdir. Ona görə də Bər. 3-dəki funksiyası - ə bərabər olacaqdır. Bu vəziyyətdə Bər. 3-ü belə yaza bilərik:

\begin{eqnarray} C = \frac{1}{2}{(Y - x^{(L)})} ^ 2 \tag{4}\end{eqnarray}

Bu xəta funksiyasına uyğun nöqtəvi meyilli azalma isə ağırlıq və sürüşmə əmsalının hər bir iterasiyada dəyişməsindən ibarətdir.

\begin{eqnarray} w^{(t+1)} = w^{(t)} - \beta_1\frac{\partial C}{\partial w^{(t)}} \tag{5}\end{eqnarray}

\begin{eqnarray} b^{(t+1)} = b^{(t)} - \beta_2\frac{\partial }{\partial b^{(t)}} \tag{6}\end{eqnarray}

Bər. 4-də gördüyümüz kimi biz xəta dəyərini hesablayarkən şəbəkənin çıxış dəyəri olan - in verilən toplusundakı cavab ilə kvadratik fərqini hesablayırıq. -dən(Bər 2.), isə öz növbəsində ağırlıq və sürüşmə dəyərlərindən(Bər 1.) asılıdır. Yəni -dən asılıdır. Ancaq burda önəmli bir sual yaranır, xətanı azaltmaq üçün Bər 5. və Bər 6. yalnızca - ə tətbiq etməliyik?

Belə olduğu halda şəbəkənin gizli qatlarına uyğun ağırlıq və sürüşmə əmsallarını yox saymış olacağıq. Ancaq Bər 1.-də də gördüyümüz kimi hər qatın dəyəri özündən əvvəlki qatın dəyərindən də asılıdır, yəni ağırlıqlarda və sürüşmədə uyğun dəyişiklik edilməsə, çıxış qatının dəyəri tam optimal olmayacaq. Problem ondadır ki, biz xəta dəyərinin yalnızca çıxış qatında hesablaya bilirik. Bəs onda biz gizli qatlardakı parametrlərində nəyə uyğun dəyişliklər edəcəyik? Başqa bir sözlə desək, nöqtəvi meyilli azalmanı gizli qatları necə tətbiq etmək olar?

Şəbəkədə hər qat özündən bir əvvəlki qatdan asılı olduğundan, çıxış qatınının dəyərini təyin oblastı giriş qatı olan mürəkkəb qeyri-xətti funksiya hesab edə bilərik. Yəni şəbəkənin əsas irəliyə ötürmə prinsipini açılmış şəkildə belə yaza bilərik.

Çıxış dəyərinin mürəkkəb funksiya olması bizə hər bir qat üçün nöqtəvi meyili hesablayarkən çox kömək olacaq. Belə ki, biz differensialları hesablayarkən mürəkkəb funksiyaya tətbiq olunan ən önəmli qaydalardan olan zəncir qaydasından istifadə edəcəyik. Bu qayda ilə, yəqin ki, oxuyucularımızın əksəriyyəti tanışdır, ancaq, gəlin, qısaca xatırlayaq.

Zəncir Qaydası

İxtiyari , funksiyasıları üçün, qaydasını qəbul edək. Məqsədimiz -in parametrinə uyğun törəməsini hesablamaqdır. Gəlin,
- i , - i isə ilə işarə edək. Bu halda zəncir qaydası aşağıdakı kimidir:

İndi isə qayıdaq əsas problemə - nöqtəvi meyillərin hesablanmasına. Bizim məqsədimiz hər bir qat üçün nöqtəvi meyillər - - i hesablamaqdır. İlk addım olaraq bu hesablamaları asanlaşdırmaq üçün əlavə bir parametrdən - -dan istifadə edəcəyik.

\begin{eqnarray} \delta^l = \frac{\partial C}{\partial z^l}, \forall l \in [1, L] \tag{9}\end{eqnarray}

Yuxarıda vurğuladığım kimi nöqtəvi meyil üçün gərəkli olan xəta funskiyasının dəyəri çıxış qatının dəyərindən asılıdır. Buna görə də, ilk olaraq bu qata uyğun meylin hesablamasından başlayırıq. Mən buradakı hesablamalar zamanı nəticələrin həll yolunu da izah edəcəyəm, əgər “riyaziyyatı boş ver, mənə cavabı ver” deyirsinizsə, hər bərabərliyin son nəticəsinə baxmağınız kifayətdir.

İlk olaraq çıxış qatında başlayırıq.

\begin{eqnarray} \delta^L &= \frac{\partial C}{\partial z^L_j}
\tag{9}\end{eqnarray}

Növbəti addım kimi bu bərabərliyə zəncir qaydasını tətbiq edirik.

\begin{eqnarray} \delta^L &= \frac{\partial C}{\partial x^L} \frac{\partial x^L}{\partial z^L} \tag{11}\end{eqnarray}

bərabərliyini xatırlasaq, yuxarıdakı bərabərliyin ikinci hissəsini kimi yaza bilərik.

\begin{eqnarray} \delta^L = \frac{\partial C}{\partial x^L} \sigma’(z^L_j) \tag{12}\end{eqnarray}

Diqqət etsək, görə bilərik ki, bərabərliyin birinci hissəsi isə Bər 4. - ün differensialıdır. Buna görə ifadəni belə yaza bilərik.

\begin{eqnarray} \delta^L = (x^L-y) \sigma’(z^L). \tag{13}\end{eqnarray}

şəbəkənin çıxış itkisi(ing. output error) adlanır. Növbəti addımlarda məqsədimiz bu itkinin gizli qatlara yayılmasını təmin etməkdir. Ümumi ideya bundan ibarətdir ki, hər bir qatdakı itkini ondan əvvəlki qatdakı itkini hesablamaq üçün istifadə edəcəyik. Bu rekursiv məntiq səbəbi ilə istifadə etdiyimiz bu alqoritm itkinin geriyə yayılması adlanır. Hər qatda hesablayacağımız bu itkinin köməkliyi ilə ümumi xətanın hər qatdakı ağırlıq və sürüşməyə nəzərən olan meyilli azalmasını tapa biləcəyik. Beləliklə, bu bizə hər qatdakı ağırlıq və sürüşməni yeniləməyə və optimal həlli tapmağa imkan verəcək.

Növbəti addımda isə ixtiyari gizli qat üçün itki - - in hesablanmasına baxaq.

\begin{eqnarray} \delta^l &= \frac{\partial C}{\partial z^l_j}
\tag{14}\end{eqnarray}

Çıxış qatından fərqli olaraq gizli qat bir neyron yox, bir neçə neyrondan ibarət ola bilər. qatındakı hər bir neyronu tam əlaqələnmiş(ing. fully connected) neyron şəbəkədə qatındakı bütün neyronlarla bağlanmışdır. Buna görə də Bər. 13-ü zəncir qaydasından istifadə edərək, hər bir üçün belə yaza bilərik.

İfadənin ikinci hissəsini hesablamaq üçün qatı üçün irəliyə ötürmə qaydasından istifadə edə bilərik.

Buna uyğun differensialı həll edə bilərik:

Hər bir şeyi birləşdirdikdə, Bər 13-ü belə yaza bilərik

Bu bərabərliyi vektor formasında belə də yaza bilərik

Burada elementvari və ya Hadamart hasilini ifadə edir.

Artıq bildiyimiz üçün onlardan istifadə edərək həll edə bilərik.

Qeyd: Arada bəzi sadə törəmə əməliyyatlarını sizin incələməyiniz üçün qəsdən buraxdım.

Yekun olaraq bütün geriyə yayılma alqoritminin elementlərini birlikdə yazaq:

  1. İrəliyə ötürmə: Hər bir üçün - i hesablamaq.
  2. Çıxış itkisi: - i hesablamaq.
  3. İtkini geriyə yayma: Hər bir üçün - i hesablamaq
  4. Nöqtəvi meyilləri hesablama: Xəta funksiyasının ağırlıq və sürüşməyə əsasən nöqtəvi meyillərini hesablamaq.
Read More

Guess who's back'propagate. - Xəta funksiyası və stoxastik nöqtəvi meyilli azalma.

February 18, 2019, Mammad Hajili

Salamlar, keçən yazıda süni neyron şəbəkənin arxitekturası haqqında danışdıq. Orada göstərdiyim “irəli qidalama” tərcüməsi ilə bağlı bir neçə mesaj aldım və biraz qəribə tərcümə olduğunu nəzərə alaraq onu “irəliyə ötürmə” kimi dəyişməyin daha düzgün olduğunu düşünürəm. Bundan əvvəlki yazıda da uyğun dəyişiklikləri edəcəyəm.

Bu dəfəki yazımızda maşın öyrənmənin ümumi izahından, istifadə olunan bərabərliklərdən və alqoritmlərdən - xəta funksiyasından və stoxastik nöqtəvi meyilli azalma haqqında danışacam. Bu yazını yazarkən, oxuyucumun ən azı maşın öyrənmənin nə olduğunu bildiyini ümid edirəm. Hazır olun, bu yazıda bol-bol riyazi ifadələr görəcəksiniz. Kəmərləri bağlayın, başlayırıq.

Əslində bu yazını yazmaq bir qədər çətindir, çünki, maşın öyrənmə alqoritmlərini tam izah etmək üçün 1 yox, 5 yazı bəs etməz, böyük ehtimalla. Ona görə də mən bu yazıda yalnızca bizim SNŞ-dəki hesablamalar üçün lazım olan önəmli nüanslara toxunacam. Belə ki, maşın öyrənmə alqoritmləri(biz burada öyrənməni müşahidəli(ing. supervised) olaraq hesab edirik) verilənlər toplusu və ona uyğun cavablar əsasında qeyri-xətti və ya xətti bir qanunauyğunluq taparaq verilənlər toplusu ilə eyni quruluşda olan yeni verilənə uyğun cavabı təxmin etmək üçün istifadə edilir. Bu iki ardıcıl prosesə “öyrən və təxmin et” (ing. learn and predict) də deyə bilərik. Ancaq bu prosesdə, məncə bir nüans əskikdi, sizcə, hansı?

ölçülü bu topluda ən optimistik halda biz hər bir elementin yalnızca uyğun cavab dəyəri ilə uyğunluğunu görə bilərik. Ancaq toplunun hər verilənin uyğunluğu individual olaraq bizim məsələdə bir məna kəsb etmir, çünki ixtiyari iki verilən - fərqli-fərqli funksiyanın təyin oblastı ola bilər. Bizə ümumi qanunauyğunluğu tapmaq üçün bütün bu funksiyaları ehtiva edəcək ümumi funksiyanı - riyazi modeli tapmaq gərəklidir. Gəlin, bu funksiyanı ilə işarə edək. Ən sadə halda bu funksiya arqumentləri girişə uyğun ağırlıq vektoru və sürüşmə əmsalı olan xətti funksiya ola bilər. Biz də hesablamalar zamanı izahı daha asan olsun deyə bu funksiyadan istifadə edəcəyik.

\begin{eqnarray} f(X_i) = w \cdot X_i + b \tag{1}\end{eqnarray}

Yuxarıda qeyd etdiyim verilənlər toplusunda gördüyünüz kimi hər bir element -in ona uyğun cavabı var. Deməli biz ümumi funksiyamızın təxmininin dəqiqliyini funksiyanın dəyərinin və verilən elementə uyğun cavabın bir-birinə nə qədər yaxın olduğu ilə müqayisə edə bilərik. Bu yaxınlığı/uzaqlığı hesablamaq üçün xəta funksiyasından(ing. loss/cost function) istifadə edirik. Bu məsələmizdə xəta funksiyası kimi kvadratik xəta funksiyasında istifadə edəcəyik. funksiyasının ümumi xətası bütün elementlərə uyğun xətaların cəmi olduğundan kvadratik funksiya cəm zamanı mənfi və müsbət xətaların bir-birini ixtisar etməsinin qarşısını alır. Gəlin funksiyasının xəta funksiyasını ilə işarə edək. Cəmi normallaşdırma üçün xətalar cəmini nöqtələrin sayına bölürük.

\begin{eqnarray} L(X_i) = \frac{1}{2}{(Y_i - f(X_i))} ^ 2 \tag{2}\end{eqnarray}

\begin{eqnarray} L(X) = \frac{1}{N}\sum_i L(X_i) \tag{3}\end{eqnarray}

Qeyd: Kvadratik funksiyanı əmsalı ilə vurmağımızın səbəbi sonrakı hesablamalar zamanı törəmə aldığımızda qalıq əmsalsız nəticə əldə etməkdir. Bu ümumi qəbul edilmiş bir qaydadır, ancaq, təbii ki, bütün hesablamaları bu əmsalı nəzərə almadan da etsək, yenə də eyni nəticəyə gələcəyik.

Xəta funksiyası maşın öyrənmə alqoritmlərinin təməlini təşkil edir, belə ki, yuxarıda qeyd etdiyimiz əskik nüansı onu istifadə edərək tamamlaya bilərik. Bər. 1-də gördüyümüz kimi funksiyanın dəyəri ağırlıq və sürüşmə əmsalından asılıdır və Bər. 2-də gördüyümüz kimi xətanın dəyəri -in dəyərindən asılıdır. Yəni, bilavasitə, modelin xətası funksiyasının arqumentləri olan ağırlıq və sürüşmə dəyərlərindən asılıdır. Bizim məqsədimiz isə, ən dəqiq, yəni verilən cavaba ən yaxın dəyərlər təxmin etməkdir, başqa bir sözlə desək xətanı azaltmaqdır. Deməli, biz funksiyanın arqumentlərini dəyişməklə ən az xətalı modeli əldə edə bilərik. Yəni, ixtiyari təyin olunmuş -dən başlayaraq, xəta azalana qədər onları müəyyən üsulla dəyişsək modelimiz öyrənmə prosesini bitirəcək. Ona görə də, mən təklif edirəm ki, bu iterativ məntiqi də nəzərə alaraq, gəlin, “öyrən və təxmin et” prosesini “öyrədilənə qədər davam et və təxmin et” olaraq dəyişək və əskik nüansı aradan qaldıraq.

Yuxarıdakı abzasda sondan ikinci cümlədə fikir versəniz “müəyyən üsulla” hissəsini xüsusi işarələdim. İndi bizi maraqlandıran isə bizə ən dəqiq modeli verəcək ən optimal -ni hər iterasiyada hansı üsulu istifadə edərək dəyişəcəyimizi müəyyən etməkdir. Maşın öyrənmədə, təbii ki, bir-birindən fərqli müxtəlif üsullar təklif olunub, ancaq mən sizə SNŞ-lərin döyünən ürəyi olan stoxastik nöqtəvi meyilli azalmanı(SNMA)(ing. stochastic gradient descent(SGD)) göstərəcəm. Bu arada, bu mövzu hələ də üzərində kifayət qədər elmi araşdırma gedən mövzudur və dərin riyazi izahı vaxt alandır, ona görə də mən riyazi analizin axtarışını sizin ixtiyarınıza buraxıram. Bununla belə, bizə lazım olacaq riyazi izahı verəcəm, təbii ki.

Belə ki, nöqtəvi meyil(ing. gradient) funksiyanın toxunanının müəyyən nöqtədəki meylidir. Nöqtəvi meyil, xəta funksiyasının artış istiqamətinin əksinə olan vektor olaraq da ifadə edilir. Ancaq biz burda qarışıqlıq olmasın deyə onun ədədi dəyəri ilə ifadə edəcəyik. Belə ki, ədədi dəyər ilə ifadə edildiyində nöqtəvi meyil, sadəcə xəta funksiyasının müəyyən nöqtədəki differensialının əksinə bərabər olur. funksiyası -dən asılı funksiya olduğundan, iki nöqtəvi meyildən istifadə edəcəyik. Belə ki, hər hansı bir arqumentin anındakı dəyərini tapmaq üçün onun anındakı dəyəri ilə həmin andakı nöqtəvi meylini toplayacağıq.

\begin{eqnarray} w^{(t+1)} = w^{(t)} - \beta_1\frac{\partial L_n}{\partial w^{(t)}} \tag{4}\end{eqnarray}

\begin{eqnarray} b^{(t+1)} = b^{(t)} - \beta_2\frac{\partial L_n}{\partial b^{(t)}} \tag{5}\end{eqnarray}

Burada xəta dəyərinin çox böyük qiymətlərində -nin kəskin şəkildə azalmasının qarşısını alaraq modelin normallaşdırılması üçün istifadə olunan əmsallardır. isə verilənlər toplusundan ixtiyari seçilmiş elementinin xəta dəyəridir. Bu element hər iterasiyada ixtiyari olaraq seçildiyindən bu alqoritmi stoxastik nöqtəvi meyilli azalma adlandırırıq.

Əlavə tapşırıq: Bər. 2-də funksiyasını görürük. Bu bərabərlik əsasında törəmələri həll edərək Bər 4. və Bər 5.-i yenidən göstərin.

Bir daha xatırlatmaq istəyirəm ki, funksiyasını izahı sadə olduğundan istifadə etdim, növbəti yazıda indi öyrəndiyimiz alqoritmlərin SNŞ-lərə tətbiqi zamanı yox, gizli qatların aktivasiyası və yekun çıxış qatının dəyərindən istifadə edəcəyik. Açığı, burada xəta funksiyası və SNMA-nı yaxşı anlasanız, növbəti yazı sizin üçün yalnızca mürəkkəb funksiyaların törəməsinin zəncir qaydası ilə həllini başa düşməkdən ibarət olacaq. Bəli, gələn yazıda seriyanın adını daşıyan geriyə yayılma(backpropagation) alqoritmindən danışacağıq.

Buraya qədər səbr edib oxuduğunuz üçün təşəkkürlər!

Read More

Guess who's back'propagate. - Süni neyron şəbəkə və irəliyə ötürmə alqoritmi.

February 14, 2019, Mammad Hajili

Salamlar, bu yazı Derintelligence-də yazacağımız ilk seriyanın ilk yazısıdır. Bu seriyamız dərin öyrənmənin əsas elementi olan süni neyron şəbəkələr haqqında olacaq. Bu yazı seriyasına başlamağımızın əsas səbəbi texniki resursların artdığı son illərdə sürətlə inkişaf edən maşın/dərin öyrənmə sahəsində Azərbaycanın geri qaldığını düşünməyimiz və bu sahə ilə maraqlanan tələbələr, mühəndislər və araşdırmacıların lazımlı məlumatları yalnızca türk, rus, ingilis dili kimi fərqli dillərdə olan mənbələrdən tapa bilməsidir.

Deməli, keçək mətləbə. Bugün süni neyron şəbəkənin strukturuna giriş edəcəyik. Əgər ümumi neyron anlayışına və aktivasiya funksiyaları haqda ümumi anlayışınız varsa, SNŞ-lərin sadə quruluşu sizin üçün çətin olmayacaq. (bundan sonra süni neyron şəbəkələri SNŞ’lə ifadə edəcəyik). Belə ki, mən bu yazıda verəcəyim arxitekturada aktivasiya funksiyasını siqmoid funksiya olaraq qəbul edirəm. Gəlin sadə neyronun siqmoidlə aktivasiyanı xatırlayaq.

\begin{eqnarray} z = w \cdot x + b \tag{1}\end{eqnarray}

\begin{eqnarray} \sigma(z) = \frac{1}{1+e^{-z}} \tag{2}\end{eqnarray}

Bər. (1)’də siqmoid neyronun giriş dəyərlərini, girişə uyğun ağırlıqları, isə sürüşmə dəyərini ifadə edir. Bər. (2) isə siqmoid aktivasiya funksiyasıdır və onunla neyronun çıxış dəyərini hesablayırıq.

Bizim əsas məqsədimiz bu və ya oxşar(digər aktivasiya funksiyaları istifadə edilən) dizaynda olan neyronlardan birlikdə bir şəbəkə qurmaqdır və məsələ şəbəkədirsə, hətta bəzi hallarda bir neçə qat neyronlar toplusu istifadə etmək lazım ola bilər. Belə ki, bioloji neyron şəbəkənin strukturu əsasında süni neyronların bir-birilərinə riyazi və məntiqi qanunauyğunluqla əlaqələnərək əmələ gətirdiyi riyazi model süni neyron şəbəkə adlanır.

Ən sadə SNŞ-ə eyni giriş dəyərləri olan bir neçə perseptronu misal gətirə bilərik. Bu şəbəkənin girişi eynən perseptronda olduğu kimi , çıxışı isə yalnız bir dəyər yox, bir neçə perseptronun yekun dəyərləridir - . Belə ki, daha mürəkkəb modellər elə bu sadə modelin üzərində qurulur və əksər hallarda elə bu mürəkkəb modellərdən istifadə olunur.

Şəbəkədə hər bir hesablama mərhələsi qat(ingilis dilli ədəbiyyatlarda layer, türk dilli ədəbiyyatlarda katman) adlanır. Şəbəkənin giriş dəyərləri birlikdə giriş qatı, çıxışı isə çıxış qatı adlanır. Bura qədər hələ ki, bildiyimiz terminlər və dəyərlərlə qarşılaşdıq. Ancaq bizə gizli qalan bir xarakteristikanı hələ vurğulamadım; şəbəkələrdə giriş qatı və çıxış arasında olan hesablama mərhələləri gizli qatlar (ing. hidden layers) adlanır. Bir neçə gizli qatı olan neyron şəbəkə isə çoxqatlı SNŞ adlanır.

Əlavə məlumat: SNŞ-də gizli qatın istifadə edilməsinin riyazi səbəbinə daha ətraflı girmək istəmirəm. Səbəbi bu mövzunun bizim danışdığımız konteksdən bir qədər uzaq olmasıdır. Ancaq bunu qeyd etmək istəyirəm ki, nisbətən sadə (1 və ya 2 gizli qatlı) şəbəkə belə istənilən sərhədlənmiş təyin oblastı olan silsiləvi funksiyanı təxmin edə bilər. Əgər riyazi analiz hissəsi sizə çox maraqlıdırsa, bu linkdəki yazı yaxşı giriş ola bilər.

Aşağıda gördüyünüz neyron şəbəkə(şəkil EPFL universitetin “Machine Learning” kursunun materiallarından götürülmüşdür.) hər biri K ölçüdə olan L ədəd gizli qat, D ölçülü giriş qatdan və çıxış qatdan ibarətdir. Şəkildə də gördüyünüz kimi hər hesablama mərhələsinin girişi bir əvvəlki qatın çıxışıdır(və ya şəbəkənin girişidir). Geriyə doğru döngü olmadığından və hər addım irəliyə olduğundan belə modellər ingilis dilli ədəbiyyatlarda feedforward, türk dilli ədəbiyyatlarda ileri beslemeli şəbəkə olaraq qeyd edilir. Azərbaycan dilində bununla bağlı xüsusi bir mənbə tapa bilmədiyimdən və türk dilində də tərcümə zamanı ingilis dilli terminin hərfi mənası işlədiyindən mən də onu *irəli qidalı* şəbəkə adlandırmağa qərar verdim.(qəribə səslənir, bilirəm, əgər sizin də bir təklifiniz varsa, bizə yazsanız sevinərik.). Bu yazını paylaşdıqdan sonra bu mövzu ilə bağlı bir neçə rəy aldım, “irəli qıdalı” biraz qəribə səsləndiyindən və hər bir qat öz dəyərini növbəti qata giriş olaraq ötürdüyündən tərcüməni “irəliyə ötürmə”-yə dəyişməyə qərara aldım.

Deməli, bu irəliyə ötürməli şəbəkədə gizli qat -dəki (hansı ki, ) hər bir neyron özündən bir əvvəlki qatdakı bütün neyronlarla əlaqəlidir. Gəlin, qatındakı neyronundan qatındakı neyronuna olan əlaqənin ağırlığını ilə işarə edək. Bu halda qatındakı neyronunun dəyəri olan -ni aşağıdakı bərabərliklə ifadə edə bilərik.

\begin{eqnarray} x_j^{(l)} = \phi(\sum_i w_{i, j}^{(l)} x_i^{(l-1)} + b_j^{(l)}) \tag{3}\end{eqnarray}

Yuxarıda da qeyd etdiyim kimi mən bu yazıda aktivasiya funksiyası() üçün siqmoid funksiya istifadə edəcəm. Ona görə Bər. 3-də funksiyanı siqmoidlə əvəz edək, qatındakı bütün neyronların dəyərini isə, vektor formasında bir daha yazaq.

\begin{eqnarray} z^{(l)} = w^{(l)} x^{(l-1)} + b^{(l)} \tag{4}\end{eqnarray}

\begin{eqnarray} x^{(l)} = \sigma(z^{(l)}) \tag{5}\end{eqnarray}

Neyron şəbəkənin yekun çıxış dəyərini almaq üçün isə şəkildən də gördüyümüz kimi son gizli qatın dəyərindən istifadə edirik.

\begin{eqnarray} y = \sigma(z^{(L)}) \tag{6}\end{eqnarray}

Beləliklə biz irəliyə ötürmə alqoritmini bitirdik. Sadə dillə bir daha üzərindən keçsək, deyə bilərik ki, bu alqoritmlə giriş qatından başlayaraq hər dəfə bir sonrakı gizli qatı aktivləşdirib, sonda da çıxış dəyərini hesablıyırıq. İndi burada sual yaranır ki, bütün bu şəbəkənin əsas məqsədi olan təxmin etmə nə qədər dəqiqdir, yaratdığımız model təxmin etmək istədiyimiz dəyərə hansı dərəcədə yaxındır. Biz nəticədə, əlbəttə, təxminimizi minimum zərərlə etmək istəyirik. Bu nöqtədə bizə maşın öyrənmə alqoritmləri lazım olacaq. Ancaq bu mövzuya bu yazıda girmək istəmirəm, ona görə də, gəlin burda yavaş-yavaş yekunlaşdıraq. Gələn yazıda artıq maşın öyrənmə alqoritmlərinə, itirmə funksiyalarına giriş edəcəyik. Növbəti yazılarda isə, onların irəliyə ötürməli şəbəkələrə necə uyğunlaşdıra biləcəyimizdən danışacağıq. Mən gələn yazıları yazdığım müddətdə siz xətti cəbr və riyazi analiz kimi mövzulara baxsanız əla olar, çünki, maşın öyrənmə alqoritmlərində riyazi düşüncə önəmlidir. Buraya qədər səbr edib oxuduğunuz üçün təşəkkürlər!

Read More