Czas skorzystać z pakietu Keras i zastosować teorię w praktyce. Na początek będziemy potrzebować dużo danych tekstowych do trenowania modelu języka. Możemy skorzystać z dowolnego wystarczająco rozbudowanego zestawu plików tekstowych — Wikipedii, Władcy pierścieni itd. W zaprezentowanym przykładzie posłużymy się wybranymi dziełami Friedricha Nietzschego — niemieckiego filozofa żyjącego w XIX w. — przetłumaczonymi na język angielski. W związku z tym wytrenujemy model odwzorowujący specyficzny styl pisania Nietzschego. Ponadto model ten będzie generował teksty tylko na wybrane tematy — nie będzie to ogólny model języka angielskiego.
Zacznijmy od pobrania korpusu i zapisania go przy użyciu tyl-ko małych liter.
r
r library(keras) library(stringr)
path <- get_file( .txt, origin = ://s3.amazonaws.com/text-datasets/nietzsche.txt
) text <- tolower(readChar(path, file.info(path)$size)) cat(‚ugość korpusu:, nchar(text), \n)
Teraz dokonamy wyodrębnienia częściowo zachodzących na siebie sekwencji o długości maxlen, zakodujemy je techniką kodowania z gorącą jedynką, a następnie umieścimy je w trójwymiarowej tablicy o kształcie x (sequences, maxlen, unique_characters). Jednocześnie przygotujemy tablicę y zawierającą „wartości do-celowe”, które w tym przypadku są po prostu literami umieszczanymi po każdej z wyodrębnionych sekwencji. Wartości te zostaną zapisane przy użyciu techniki kodowania z gorącą jedynką.
r
r maxlen <- 60 # Wyodrębniamy sekwencje składające się z 60 znaków.
step <- 3 # Nowa sekwencja jest prĂłbkowana co 3 znaki.
text_indexes <- seq(1, nchar(text) - maxlen, by = step)
sentences <- str_sub(text, text_indexes, text_indexes + maxlen - 1)
next_chars <- str_sub(text, text_indexes + maxlen, text_indexes + maxlen)
cat(sekwencji: , length(sentences), \n)
chars <- unique(sort(strsplit(text, \)[[1]])) cat(unikatowych znakĂłw:, length(chars), \n)
char_indices <- 1:length(chars) names(char_indices) <- chars
cat(wektorĂłw…) x <- array(0L, dim = c(length(sentences), maxlen, length(chars))) y <- array(0L, dim = c(length(sentences), length(chars))) for (i in 1:length(sentences)) { sentence <- strsplit(sentences[[i]], \)[[1]] for (t in 1:length(sentence)) { char <- sentence[[t]] x[i, t, char_indices[[char]]] <- 1 } next_char <- next_chars[[i]] y[i, char_indices[[next_char]]] <- 1 }
Sieć składa się z pojedynczej warstwy layer_lstm i klasyfikatora dense z funkcją aktywacji softmax. Pamiętajmy o tym, że generowanie danych sekwencyjnych nie musi być przeprowadzane przy użyciu rekurencyjnych sieci neuronowych. Ostatnio coraz częściej stosuje się w tym celu jednowymiarowe sieci konwolucyjne.
r
r model <- keras_model_sequential() %>% layer_lstm(units = 128, input_shape = c(maxlen, length(chars))) %>% layer_dense(units = length(chars), activation = )
Wartości docelowe (znaki) są zakodowane przy użyciu techniki gorącej jedynki, a więc funkcją straty trenowanego modelu będzie categorical_crossentropy.
r
r optimizer <- optimizer_rmsprop(lr = 0.01)
model %>% compile( loss = _crossentropy, optimizer = optimizer )
Dysponując wytrenowanym modelem i kawałkiem początkowego tekstu, możemy wygenerować nowy tekst. W tym celu należy powta-rzać następujące operacje:
Oto kod używany do zmiany wag rozkładu prawdopodobieństwa wygenerowanego przez model. Kod ten tworzy funkcję próbkującą, która również określa indeks znaku.
r
r sample_next_char <- function(preds, temperature = 1.0) { preds <- as.numeric(preds) preds <- log(preds) / temperature exp_preds <- exp(preds) preds <- exp_preds / sum(exp_preds) which.max(t(rmultinom(1, 1, preds))) }
Na koniec poniższa pętla wykonuje operację trenowania modelu i generowania tekstu. Wygenerujemy teksty przy różnych wartościach parametru temperature (wartości te będą zmieniane przy rozpoczęciu kolejnych epok procesu trenowania). Pozwoli to nam zobaczyć, jak zmienia się tekst wraz z udoskonalaniem modelu, a także to, jak parametr temperature wpływa na strategię próbkowania.
r
r for (epoch in 1:60) {
cat(, epoch, \n)
# Model będzie trenowany przez 60 epok. model %>% fit(x, y, batch_size = 128, epochs = 1)
# Losowanie tekstu poczÄ…tkowego. start_index <- sample(1:(nchar(text) - maxlen - 1), 1)
seed_text <- str_sub(text, start_index, start_index + maxlen - 1)
cat(-– Generowanie przy uĹĽyciu tekstu poczÄ…tkowego:, seed_text, \n)
for (temperature in c(0.2, 0.5, 1.0, 1.2)) {
cat(\------ Wartość parametru temperature:\, temperature, \\n\)
cat(seed_text, \\n\)
generated_text <- seed_text
# Generowanie 400 znakĂłw (proces rozpoczyna siÄ™ od wylosowanego tekstu poczÄ…tkowego).
for (i in 1:400) {
sampled <- array(0, dim = c(1, maxlen, length(chars)))
generated_chars <- strsplit(generated_text, \\)[[1]]
for (t in 1:length(generated_chars)) {
char <- generated_chars[[t]]
sampled[1, t, char_indices[[char]]] <- 1
}
preds <- model %>% predict(sampled, verbose = 0)
next_index <- sample_next_char(preds[1,], temperature)
next_char <- chars[[next_index]]
generated_text <- paste0(generated_text, next_char)
generated_text <- substring(generated_text, 2)
cat(next_char)
}
cat(\\n\n\)
} }
Oto tekst wygenerowany przy użyciu wylosowanej frazy new faculty, and the jubilation reached its climax when kant. Został on uzyskany po 20 epokach trenowania algorytmu — na długo przed osiągnięciem końca procesu trenowania — przy parametrze temperature przyjmującym wartość równą 0,2:
new faculty, and the jubilation reached its climax when kant and such a man
in the same time the spirit of the surely and the such the such
as a man is the sunligh and subject the present to the superiority of the
special pain the most man and strange the subjection of the
special conscience the special and nature and such men the subjection of the
special men, the most surely the subjection of the special
intellect of the subjection of the same things and
Oto wynik przy parametrze temperature przyjmującym wartość równą 0,5:
new faculty, and the jubilation reached its climax when kant in the eterned
and such man as it's also become himself the condition of the
experience of off the basis the superiory and the special morty of the
strength, in the langus, as which the same time life and "even who
discless the mankind, with a subject and fact all you have to be the stand
and lave no comes a troveration of the man and surely the
conscience the superiority, and when one must be w
A to wynik przy parametrze temperature przyjmującym wartość 1,0:
new faculty, and the jubilation reached its climax when kant, as a
periliting of manner to all definites and transpects it it so
hicable and ont him artiar resull
too such as if ever the proping to makes as cnecience. to been juden,
all every could coldiciousnike hother aw passife, the plies like
which might thiod was account, indifferent germin, that everythery
certain destrution, intellect into the deteriorablen origin of moralian,
and a lessority o
Po 60 epokach proces trenowania można uznać za praktycznie zakończony — tekst generowany przez model zaczyna wyglądać na coraz bardziej składny. Oto tekst wygenerowany przy parametrze temperature przyjmującym wartość 0,2:
cheerfulness, friendliness and kindness of a heart are the sense of the
spirit is a man with the sense of the sense of the world of the
self-end and self-concerning the subjection of the strengthorixes--the
subjection of the subjection of the subjection of the
self-concerning the feelings in the superiority in the subjection of the
subjection of the spirit isn't to be a man of the sense of the
subjection and said to the strength of the sense of the
A to tekst wygenerowany przy parametrze temperature przyjmującym wartość 0,5:
cheerfulness, friendliness and kindness of a heart are the part of the soul
who have been the art of the philosophers, and which the one
won't say, which is it the higher the and with religion of the frences.
the life of the spirit among the most continuess of the
strengther of the sense the conscience of men of precisely before enough
presumption, and can mankind, and something the conceptions, the
subjection of the sense and suffering and the
Przy parametrze temperature przyjmującym wartość 1,0 wygenerowany został następujący tekst:
cheerfulness, friendliness and kindness of a heart are spiritual by the
ciuture for the
entalled is, he astraged, or errors to our you idstood--and it needs,
to think by spars to whole the amvives of the newoatly, prefectly
raals! it was
name, for example but voludd atu-especity"--or rank onee, or even all
"solett increessic of the world and
implussional tragedy experience, transf, or insiderar,--must hast
if desires of the strubction is be stronges
Jak widać, niska wartość parametru temperature prowadzi do uzyskania tekstu, który charakteryzuje się dużą przewidywalnością i powtarzalnością, ale jego lokalna struktura jest bardzo realistyczna — wszystkie wygenerowane słowa (słowo jest lokalnym wzorcem składającym się ze znaków) występują w języku angielskim. Przy wyższych wartościach parametru tempe-rature wygenerowany tekst staje się bardziej interesujący, zaskakujący, a nawet kreatywny — algorytm czasami wymyśla nawet nowe słowa, które brzmią tak, jakby były naprawdę istniejący-mi słowami (są to np. eterned i troveration), ale lokalna struktura tekstu zaczyna się załamywać i większość słów wy-gląda tak, jakby była prawie losowym zbiorem znaków. Bez wątpienia najciekawsze efekty w przypadku tego generowania tek-stu uzyskuje się przy parametrze temperature równym 0,5. Zawsze warto eksperymentować z różnymi strategiami próbkowania! Dobra równowaga między wytrenowaną strukturą a losowością sprawi, że wygenerowany tekst będzie interesujący.
Trenując model dłużej, tworząc większy model i stosując większy zbiór danych, można generować próbki, które wyglądają o wiele składniej i bardziej realistycznie. Oczywiście nie należy oczekiwać od modelu wygenerowania tekstu, który będzie miał jakiś większy sens — mechanizm generujący tekst tylko próbkuje litery z modelu statystycznego określającego ich kolejność. Język jest kanałem komunikacji, a rozmowy dotyczące różnych tematów charakteryzują się inną strukturą statystyczną. Tezę tę można udowodnić, odpowiadając sobie na pytanie: co, jeżeli język ludzki zostałby skompresowany tak, jak kompresowana jest większość cyfrowej komunikacji między komputerami? Wówczas język przenosiłby tyle samo informacji, ale nie charakteryzowałby się żadną ukrytą strukturą statystyczną, co uniemożliwiłoby wytrenowanie modelu języka w sposób, w jaki zrobiliśmy to przed chwilą.
Dyskretna sekwencja danych może zostać wygenerowana p-przez trenowanie modelu pod kątem przewidywania kolejnych elementów tekstu na podstawie wcześniejszego ciągu znaków. Model trenowany na zbiorze danych tekstowych określany jest mianem modelu języka. Może on być oparty na słowach lub literach. Próbkowanie zbioru elementów tekstu wymaga kompromisu między bezkrytycznym przyjmowaniem przewidywań modelu a losowością. Można to zrobić przy użyciu parametru temperature funkcji softmax. Wybór właściwej wartości tego parametru powinien zostać dokonany na drodze eksperymentów.