Advertise

Word Embedding

Pendahuluan

Ketika membuka google dan mencari berita terkait topik tertentu akan muncul beberapa saran kata setelahnya. Pernahkah seperti ini?





Contoh diatas adalah penerapan dari machine learning yaitu salah satu varian dari kecerdasan buatan yang memungkinkan komputer dapat belajar memahapi pola objek yang diberikan. Dalam melakukan pembelajaran terhadap suatu objek, diperlukan ciri-ciri dari objek tersebut atau yang biasa dikenal sebagai feature. Apabila objek yang diterima berupa text, maka diperlukan proses ekstraksi text menjadi sebuah vektor numerik yang merepresentasikan tiap katanya. Istilah proses ini disebut word vector representation atau biasa dikenal sebagai word embedding.

1.1 Word Embeddings

Secara sederhana, word embedding adalah proses konversi sebuat teks menjadi angka. Kenapa kita perlu proses ini? karena sebagian besar algoritma machine learning dan arsitektur deep learning tidak mampu melakukan proses analisis pada input data berupa strings atau teks, sehingga membutuhkan angka sebagai input.

Contoh sederhana merubah kata menjadi vektor angka. Misal diberikan kalimat berikut: “Word Embedding are Word Converted into numbers.” Sebuah kamus akan berisi list seluruh kata yang unique. Sehingga kamus yang terbentuk adalah: [“Word”,“Embeddings”,“are”,“Converted”,“into”,“numbers”]. Menggunakan metode one-hot encoding akan menghasilkan vektor dimana 1 merepresentasikan posisi kata tersebut berada, dan 0 untuk kata lainnya. Vektor representasi dari kata “numbers” mengacu pada format kamus diatas adalah [0,0,0,0,0,1] dan kata “Converted” adalah [0,0,0,1,0,0].

Diatas merupakan salah satu contoh bentuk representasi teks menjadi angka. Selanjutnya kita akan bahas beberapa tipe lain dari word embeddings diantaranya Term Frequence and Inverse Document Frequence (TF-IDF) dan Word2Vec.

2 TF-IDF

Hal yang perlu diperhatikan dalam pencarian informasi dari koleksi dokumen yang heterogen adalah pembobotan term. Term dapat berupa kata, frase atau unit hasil indexing lainnya dalam suatu dokumen yang dapat digunakan untuk mengetahui konteks dari dokumen tersebut. Karena setiap kata memiliki tingkat kepentingan yang berbeda dalam dokumen, maka untuk setiap kata tersebut diberikan sebuah indikator.

Pendekatan Term Frequence untuk menentukan bobot term pada suatu dokumen berdasarkan jumlah kemunculannya dalam dokumen tersebut. Nilai jumlah kemunculan suatu kata (term frequency) diperhitungkan dalam pemberian bobot terhadap suatu kata. Semakin besar jumlah kemunculan suatu term (tf tinggi) dalam dokumen, semakin besar pula bobotnya dalam dokumen atau akan memberikan nilai kesesuian yang semakin besar. Ada kata yang beberapa kali muncul dalam dokumen, namun tidak penting misal dalam bahasa inggris, akan sering muncul kata “the”,“is”,“of” dan lainnya. Pada sebelum analisis kata-kata tersebut akan dihilangkan, atau melalui tahan pre-processing yaitu remove stopwords. Namun bisa jadi ada beberapa kata yang sebenarnya tidak terlalu penting, namun belum masuk kedalam list stopwords.

Sehingga pendekatan lain untuk mengukur masalah tersebut adalah melihat Inverse Document Frequence. IDF untuk pengurangan dominansi kata yang sering muncul di berbagai dokumen. Hal ini diperlukan karena kata yang banyak muncul di berbagai dokumen, dapat dianggap sebagai term umum (common term) sehingga tidak penting nilainya.

Statistika TF-IDF dimaksudkan untuk mengukur seberapa penting sebuah kata dalam korpus dokumen.

2.1 Simulasi TF-IDF

Misal diperoleh sebuah ulasan hotel seperti berikut:

Pelayanan hotel memuaskan. Menu sarapan bervariasi dan lengkap. Fasilitas hotel lengkap, pelayanannya bagus, kamarnya luas, hotel ini cocok untuk tempat menginap bersama keluarga

  • Perhitungan Term-Frequence: tf(t,d)=ft,d




  • Perhitungan Document-Frequence:




  • Perhitungan Inverse Document-Frequence: idfi=log(D/dfj)




  • Perhitungan TF-IDF

Dengan demikian untuk memperoleh TF-IDF adalah melalui hasil perkalian dari TF dan IDFWij=tfij×idfj





if (!require("pacman")) install.packages("pacman")
## Loading required package: pacman
devtools::install_github("bmschmidt/wordVectors")
## Skipping install of 'wordVectors' from a github remote, the SHA1 (7f1914cd) has not changed since last install.
##   Use `force = TRUE` to force installation
pacman::p_load(tm,tidytext, tidyverse, wordVectors, tsne)

Pertama, load data yang akan digunakan.

##load data
data <- read.csv("data/reviewborobudur.csv") %>% 
  select("text","klasifikasi") %>% 
  mutate(text = as.character(text))
data$text <- iconv(data$text, to = "UTF-8")

data <- rownames_to_column(data, var = "doc")

Selanjutnya, tahap tokenisasi yaitu mempartisi tiap kata pada kalimat untuk dijadikan token. Kemudian menghitung tiap frekuensi dari kata tersebut pada tiap dokumen.

review_token <- data %>%
  unnest_tokens(output = word, input = text) %>%
  count(word, doc) %>% 
  arrange(desc(doc))

secara default ketika kita menggunakan perintah cast_dtm parameter weighting yang digunakan adalah Term Frequence. Namun kita dapat menyesuaikannya ketika ingin menggunakan pembobotan TF-IDF. Perintah yang digunakan adalah tm::weightTfIdf.

data %>%
  unnest_tokens(word, text) %>%
  count(word, doc, sort = TRUE) %>% 
  cast_dtm(document = doc, 
           term = word, 
           value = n)
## <<DocumentTermMatrix (documents: 2586, terms: 5385)>>
## Non-/sparse entries: 41420/13884190
## Sparsity           : 100%
## Maximal term length: 22
## Weighting          : term frequency (tf)
data %>%
  unnest_tokens(word, text) %>%
  count(word, doc, sort = TRUE) %>% 
  cast_dtm(document = doc,
           term = word, 
           value = n,
           weighting = tm::weightTfIdf)
## <<DocumentTermMatrix (documents: 2586, terms: 5385)>>
## Non-/sparse entries: 41420/13884190
## Sparsity           : 100%
## Maximal term length: 22
## Weighting          : term frequency - inverse document frequency (normalized) (tf-idf)

ini adalah contoh cara alternatif untuk memperoleh hasil pembobotan tf-idf.

reviews_tfidf <- review_token %>% 
  bind_tf_idf(word, doc, n) %>% 
  arrange(desc(tf_idf)) %>% 
  select(-c("doc","n"))
reviews_tfidf
## # A tibble: 41,420 x 4
##    word           tf   idf tf_idf
##    <chr>       <dbl> <dbl>  <dbl>
##  1 awesome     1      3.31   3.31
##  2 nirvana     0.5    5.37   2.69
##  3 magic       0.5    4.91   2.46
##  4 colossal    0.333  6.07   2.02
##  5 magnet      0.25   7.86   1.96
##  6 omahugeness 0.25   7.86   1.96
##  7 busy        0.5    3.71   1.86
##  8 beautiful   1      1.77   1.77
##  9 rip         0.333  5.22   1.74
## 10 yogyakatra  0.214  7.86   1.68
## # ... with 41,410 more rows

2.2 Perbandingan Performa TF vs TF-IDF

2.2.1 Support Vector Machine

Hilangkan comment dengan blok ctrl+shift+c untuk melihat hasil sintaksnya.

# library(e1071)
# library(caret)
# library(RTextTools)
# attach(data)
# data.fil <- data[-which(klasifikasi=="Netral"),]
# detach(data)
# data.fil$sentimen <- as.factor(ifelse(data.fil$klasifikasi=="Positif", "2","1"))
# ratio <- 8/10
# pos <- data.fil %>% filter(sentimen==2)
# neg <- data.fil %>% filter(sentimen==1)
# set.seed(1234)
# sample_pos <- sample(nrow(pos),size = floor(ratio*nrow(pos)))
# sample_neg <- sample(nrow(neg),size = floor(ratio*nrow(neg)))
# #data train
# train_pos <- pos[sample_pos,]
# train_neg <- neg[sample_neg,]
# datatrain <- rbind(train_pos,train_neg)
# #data test
# test_pos <- pos[-sample_pos,]
# test_neg <- neg[-sample_neg,]
# datatest <- rbind(test_pos, test_neg)
# dataall <- rbind(datatrain, datatest)

Membuat dtm dengan pembobotan TF dan TF-IDF.

# mat.tfidf <- create_matrix(dataall$text, language = "english",
#                      removeStopwords = FALSE, removeNumbers = TRUE,
#                      stemWords = FALSE, tm::weightTfIdf)
# mat.tfidf <- as.matrix(mat.tfidf)
# mat.tf <- create_matrix(dataall$text, language = "english",
#                      removeStopwords = FALSE, removeNumbers = TRUE,
#                      stemWords = FALSE)
# mat.tf <- as.matrix(mat.tf)

Membangun model classifier dengan SVM dengan perbandingan data training 80:20 data testing. Parameter kernel='linear' karena menurut literatur terdahulu untuk klasifikasi teks lebih tepat menggunakan kernel linear.

# container.tfidf <- create_container(mat.tfidf, dataall$sentimen, trainSize = 1:1815,
#                               testSize = 1816:2270, virgin = FALSE)
# model.tfidf <- train_model(container.tfidf, 'SVM', kernel = 'linear')
# result.tfidf <- classify_model(container.tfidf, model.tfidf)
# performas_value.tfidf <- confusionMatrix(result.tfidf$SVM_LABEL, dataall$sentimen[1816:2270])
# print(performas_value.tfidf)
# container.tf <- create_container(mat.tf, dataall$sentimen, trainSize = 1:1815,
#                               testSize = 1816:2270, virgin = FALSE)
# model.tf <- train_model(container.tf, 'SVM', kernel = 'linear')
# result.tf <- classify_model(container.tf, model.tf)
# performas_value.tf <- confusionMatrix(result.tf$SVM_LABEL, dataall$sentimen[1816:2270])
# print(performas_value.tf)

3 Word2Vec

Word2Vec terdiri dua teknik yaitu Continous Bag of Words dan Skip Gram Model. Kedua metode ini menggunakan konsep neural networks yang memetakan kata ke variabel target yang juga adalah sebuah kata. Kedua teknik ini mengguanakan weight sebagai representasi vektor kata.

Word2vec dapat menangkap hubungan semantik/sintatikal antar kata diruang vektor. Salah satu contoh populer yang digunakan yaitu: Kita ingin melihat hubungan antar kata, jika istilah King cenderung dimiliki oleh man maka woman memiliki arti yang sama dengan?. Apabila ditransformasi ke bahasa komputasi, maka akan seperti ini: King - Man + Woman = Queen.





Sekarang muncul pertanyaan, bagaimana hubungan tersebut dapat terbentuk? Word2vec mencoba untuk membuat kata dengan konteks yang sama akan memiliki vektor embedding yang sama. Misal ada 2 kalimat:

  1. The kids said he would grow up to be superman.
  2. The child said he would grow up to be superman.

Jika diperhatikan, Kids dan Child keduanya memiliki kata yang berbeda namun memiliki hubungan konteks yang sama. Sehingga word2vec akan memberikan vektor embedding yang sama untuk kedua kata tersebut.

3.1 Continous Bag of Words

Misal kita memiliki beberapa konteks kata sebagai input, kemudian ingin memprediksi kata apa yang berhubungan dengan beberapa input konteks tersebut, maka arsitektur word2vec yang digunakan yaitu CBOW.

Misal diberikan kalimat: “king brave man” “queen beautiful woman

dengan menggunakan windows size = 1 diperoleh: windows size adalah paramter untuk mengatur jumlah tetangga (neighbor) terdekat yang digunakan untuk training model.

word <- c("king","brave","brave","man","queen","beautiful","beautiful","woman")
neighbor <- c("brave","king","man","brave","beautiful","queen","woman","beautiful")
wind1 <- cbind(word,neighbor)
wind1
##      word        neighbor   
## [1,] "king"      "brave"    
## [2,] "brave"     "king"     
## [3,] "brave"     "man"      
## [4,] "man"       "brave"    
## [5,] "queen"     "beautiful"
## [6,] "beautiful" "queen"    
## [7,] "beautiful" "woman"    
## [8,] "woman"     "beautiful"

Kita ingin membuat model dari data training jika diberi input “king” dan “brave” maka hasilnya “man”.

alur kerja:

1. Input layer dan output layer (target), keduanya dikonversi menjadi one-hot vector ukuran [1×V]. dimana V adalah banyak kata hasil tokenisasi atau jumlah vocabulary.

dengan mengacu pada permasalahan diatas, maka langkah pertama ialah konversi kata “king” dan “brave” serta “man” menjadi one-hot vector. Input layer adalah matriks berukuran 2[1×V] dimana V=6

king=(100000)

brave=(010000)

Output layer adalah matriks berukuran 1[1×V]

man=(001000)

2. Terdapat dua set pembobotan atau weight. Satu berada di antara input dan hidden layer (matriks W warna merah) dan 1 lagi berada di antara hidden layer dengan output (matriks W warna hijau). Matriks input hidden layer berukuran [V×N], matriks output hidden layer berukuran [N×V] dimana N=Jumlah neuron.

Misal parameter N= 4, sehingga matriks input hidden layer yang terbentuk adalah [10×4]

Input.hidden.layer=(123456789101112131415161718192021222324)

matriks output hidden layer yang terbentuk adalah [4×6]

Output.hidden.layer=(0.10.20.30.40.50.60.70.80.91.01.11.21.31.41.51.61.71.81.92.02.12.22.32.4)

3. Input dikalikan dengan weight input-hidden layer, dan disebut sebagai hidden activation.

Pada iterasi pertama, bobot akan diberikan secara random.

Hidden.activation=(100000010000)(123456789101112131415161718192021222324)=(12345678)

z <- matrix(c(1,0,0,0,0,0,0,1,0,0,0,0),2,6, byrow = T) %*% matrix(1:24, 6, 4,byrow = T)
z
##      [,1] [,2] [,3] [,4]
## [1,]    1    2    3    4
## [2,]    5    6    7    8
colMeans(z)
## [1] 3 4 5 6

Kemudian dicari rata-rata vector hidden activation.

Avg.Hidden.Activation=(3456)

4. Hidden activation dikalikan dengan hidden-ouput weight untuk memperoleh output.

Output=(3456)(0.10.20.30.40.50.60.70.80.91.01.11.21.31.41.51.61.71.81.92.02.12.22.32.4)=(2122.824.626.428.230)

output <- matrix(3:6,1,4,byrow = T) %*% matrix(c(0.1,0.2,0.3,0.4,0.5,0.6,
                                       0.7,0.8,0.9,1.0,1.1,1.2,
                                       1.3,1.4,1.5,1.6,1.7,1.8,
                                       1.9,2.0,2.1,2.2,2.3,2.4), 4,6,byrow = T)
output
##      [,1] [,2] [,3] [,4] [,5] [,6]
## [1,]   21 22.8 24.6 26.4 28.2   30

5. Output tersebut ditransformasi dengan fungsi softmax probabilities

softmax <- function(x){
  score.exp <- exp(x)
  probs <-sweep(score.exp, MARGIN = 1, rowSums(score.exp), '/')
  return(probs)
}
softmax(output)
##              [,1]         [,2]        [,3]       [,4]     [,5]      [,6]
## [1,] 0.0001030124 0.0006231887 0.003770072 0.02280761 0.137978 0.8347181

OutputSoftmax=(0.00010301240.00062318870.0037700720.022807610.1379780.8347181)

6. Error antara output dan target kata akan dihitung. kemudian dilakukan back propagation untuk re-adjust weightnya.

matrix(c(0,0,1,0,0,0),1,6, byrow = T) - softmax(output)
##               [,1]          [,2]      [,3]        [,4]      [,5]
## [1,] -0.0001030124 -0.0006231887 0.9962299 -0.02280761 -0.137978
##            [,6]
## [1,] -0.8347181

Error=(001000)(0.00010301240.00062318870.0037700720.022807610.1379780.8347181)=(0.00010301240.00062318870.99622990.022807610.1379780.8347181)

3.2 Skip-Gram Model

Alur kerja:

1. Ukuran input layer [1×V], ukuran input hidden weight [V×N], Jumlah neuron dalam hidden layer - N. ukuran hidden output C[1×V].

2. C adalah jumlah konteks katanya.

3. untuk memperoleh output prediksi dilakukan perkalian matrix hidden activation dengan weight antara hidden layer dengan output layer.

4. output tersebut ditransformasi dengan fungsi softmax probabilities.

5. Error antara output dan target akan dihitung. kemudian dilakukan back propagation untuk re-adjust weightnya.

3.3 Case Scenarios

Ilustrasi misal diberikan kalimat: “king brave man” “queen beautiful woman

dengan menggunakan windows size = 1 diperoleh:

word <- c("king","brave","brave","man","queen","beautiful","beautiful","woman")
neighbor <- c("brave","king","man","brave","beautiful","queen","woman","beautiful")
wind1 <- cbind(word,neighbor)

word2 <- c("king","king","brave","brave","man","man","queen","queen",
           "beautiful","beautiful","woman","woman")
neighbor2 <- c("brave","man","king","man","king","brave","beautiful",
               "woman","queen","woman","queen","beautiful")
wind2 <- cbind(word2,neighbor2)
wind1
##      word        neighbor   
## [1,] "king"      "brave"    
## [2,] "brave"     "king"     
## [3,] "brave"     "man"      
## [4,] "man"       "brave"    
## [5,] "queen"     "beautiful"
## [6,] "beautiful" "queen"    
## [7,] "beautiful" "woman"    
## [8,] "woman"     "beautiful"
wind2
##       word2       neighbor2  
##  [1,] "king"      "brave"    
##  [2,] "king"      "man"      
##  [3,] "brave"     "king"     
##  [4,] "brave"     "man"      
##  [5,] "man"       "king"     
##  [6,] "man"       "brave"    
##  [7,] "queen"     "beautiful"
##  [8,] "queen"     "woman"    
##  [9,] "beautiful" "queen"    
## [10,] "beautiful" "woman"    
## [11,] "woman"     "queen"    
## [12,] "woman"     "beautiful"

Buka link ini Wevi-online kemudian copy paste input dan target berikut ke kolom training data king|brave, brave|king, brave|man, man|brave, queen|beautiful, beautiful|queen, beautiful|woman, woman|beautiful

data[-1,] %>% select(text) -> datareview
write.table(datareview, file = "datareview.txt", row.names = FALSE)
prep_word2vec(origin = "datareview.txt", lowercase = TRUE, destination = "review.txt")
## Beginning tokenization to text file at review.txt
## Prepping datareview.txt
# model = train_word2vec(train_file = "review.txt",output_file = "review.bin",vectors = 100,
# window = 12,cbow = 0, iter = 5)
model = read.vectors("review.bin")
#plot(model)

kita dapat menggunakan operasi sederhana untuk mencari kedekatan elemen teks.

model %>% closest_to("sunrise", 20)
##          word similarity to "sunrise"
## 1     sunrise               1.0000000
## 2  apparently               0.8184958
## 3      starts               0.8079896
## 4        woke               0.8002121
## 5      cloudy               0.7908066
## 6       opted               0.7877161
## 7        tips               0.7869217
## 8       foggy               0.7848596
## 9      waking               0.7795849
## 10  organized               0.7792323
## 11   plataran               0.7790573
## 12  breakfast               0.7677569
## 13      hoped               0.7634549
## 14    witness               0.7616196
## 15      meant               0.7614846
## 16        yrs               0.7570240
## 17      light               0.7541710
## 18    waiting               0.7517718
## 19     rained               0.7512313
## 20     clouds               0.7497654

eksplorasi model word2vec. kita dapat menggunakan vektor matematika untuk memperoleh hasil yang menarik. Berikut adalah contoh penerapannya menggunakan VectorSpaceModel demo_vector dari packages wordVector.

demo_vectors %>% closest_to(~"good"+"bad")
##      word similarity to "good" + "bad"
## 1     bad                    0.8845830
## 2    good                    0.8621269
## 3   great                    0.5917829
## 4  decent                    0.5893969
## 5    hard                    0.5362420
## 6     but                    0.5135680
## 7  really                    0.5025217
## 8    nice                    0.5004618
## 9      ok                    0.4751181
## 10   that                    0.4692515

Maksut perintah diatas ialah kita ingin menemukan kata-kata yang paling dekat dengan kombinasi good dan bad. Selanjutnya ketika kita ingin coba menemukan kata-kata yang paling dekat dengan good tanpa berkaitan dengan kata bad menggunakan perintah berikut.

demo_vectors %>% closest_to(~"good"-"bad")
##         word similarity to "good" - "bad"
## 1       good                    0.4205466
## 2      great                    0.3328308
## 3  excellent                    0.3093233
## 4     decent                    0.2418898
## 5  fantastic                    0.2168332
## 6   thorough                    0.2148802
## 7  wonderful                    0.2093082
## 8        and                    0.1995122
## 9       very                    0.1979586
## 10   awesome                    0.1975041
demo_vectors %>% closest_to(~ "he" - "she")
##        word similarity to "he" - "she"
## 1        he                  0.5014923
## 2       his                  0.4467857
## 3       guy                  0.4179970
## 4       hes                  0.4049624
## 5       him                  0.3907059
## 6        mr                  0.3827611
## 7       man                  0.3713098
## 8   himself                  0.3436856
## 9  arrogant                  0.1662236
## 10  physics                  0.1560129
demo_vectors %>% closest_to(~ "she" - "he")
##       word similarity to "she" - "he"
## 1      she                  0.5749598
## 2      her                  0.5707957
## 3     lady                  0.5067850
## 4     shes                  0.5050173
## 5    woman                  0.4741360
## 6  herself                  0.4294012
## 7       ms                  0.3842313
## 8      mrs                  0.3745640
## 9    sweet                  0.2067263
## 10  person                  0.1084187

Ketika pria cenderung dipanggil guy. Bagaimana dengan wanita?

demo_vectors %>% closest_to(~ "guy" - "he" + "she")
##       word similarity to "guy" - "he" + "she"
## 1     lady                          0.8851965
## 2    woman                          0.7777516
## 3      she                          0.7025325
## 4     shes                          0.6502704
## 5      her                          0.6421576
## 6      guy                          0.5533376
## 7   person                          0.5437728
## 8       ms                          0.4703695
## 9  herself                          0.4589193
## 10     mrs                          0.4508955
demo_vectors %>% closest_to(~ "guy" + ("she" - "he"))
##       word similarity to "guy" + ("she" - "he")
## 1     lady                            0.8851965
## 2    woman                            0.7777516
## 3      she                            0.7025325
## 4     shes                            0.6502704
## 5      her                            0.6421576
## 6      guy                            0.5533376
## 7   person                            0.5437728
## 8       ms                            0.4703695
## 9  herself                            0.4589193
## 10     mrs                            0.4508955
demo_vectors[[c("lady","woman","man","he","she","guy","man"), average=F]] %>% 
  plot(method="pca")

3.4 Word2vec using Keras

3.4.1 SkipGram

library(keras)
tokenizer <- text_tokenizer(5000) 
tokenizer %>% fit_text_tokenizer(data$text)
library(reticulate)
library(purrr)
skipgrams_generator <- function(text, tokenizer, window_size, negative_samples) {
  gen <- texts_to_sequences_generator(tokenizer, sample(text))
  function() {
    skip <- generator_next(gen) %>%
      skipgrams(
        vocabulary_size = tokenizer$num_words, 
        window_size = window_size, 
        negative_samples = 1
      )
    x <- transpose(skip$couples) %>% map(. %>% unlist %>% as.matrix(ncol = 1))
    y <- skip$labels %>% as.matrix(ncol = 1)
    list(x, y)
  }
}

paramter skip_window untuk mengatur jumlah tetangga (neighbor) terdekat yang digunakan untuk training model. Ketika kita train model network pasangan kata (“magelang”,“jogja”), ingat bahwa label atau output actual berbentuk one hot vector. artinya output neuron yang berkaitan dengan “jogja” akan bernilai 1, dan untuk lainnya output pada node akan bernilai 0 (dimensinya sebanyak jumlah kata, bisa jutaan. wow). Dengan negative sampling kita akan mengambil jumlah sampling negatif (misal diatur 5) maka kata lain yang tidak sesuai dengan outputnya akan bernilai 0 sebanyak 5 saja. num_sampled untuk mengatur jumlah negative sampling pada output.

embedding_size <- 32  # Dimensi vektor embedding
skip_window <- 5       # Berapa banyak neighbor yang diperhitungkan (kanan-kiri)
num_sampled <- 3       # Jumlah negative sample tiap kata
input_target <- layer_input(shape = 1)
input_context <- layer_input(shape = 1)
embedding <- layer_embedding(
  input_dim = tokenizer$num_words + 1, 
  output_dim = embedding_size, 
  input_length = 1, 
  name = "embedding"
)

target_vector <- input_target %>% 
  embedding() %>% 
  layer_flatten() # untuk mengembalikan/meratakan dimensi pada input

context_vector <- input_context %>%
  embedding() %>%
  layer_flatten()
dot_product <- layer_dot(list(target_vector, context_vector), axes = 1)
output <- layer_dense(dot_product, units = 1, activation = "sigmoid")
model <- keras_model(list(input_target, input_context), output)
model %>% compile(loss = "binary_crossentropy", optimizer = "adam")

Berikut adalah arsitektur model nya:

summary(model)
## ___________________________________________________________________________
## Layer (type)            Output Shape     Param #  Connected to             
## ===========================================================================
## input_1 (InputLayer)    (None, 1)        0                                 
## ___________________________________________________________________________
## input_2 (InputLayer)    (None, 1)        0                                 
## ___________________________________________________________________________
## embedding (Embedding)   (None, 1, 32)    160032   input_1[0][0]            
##                                                   input_2[0][0]            
## ___________________________________________________________________________
## flatten_1 (Flatten)     (None, 32)       0        embedding[0][0]          
## ___________________________________________________________________________
## flatten_2 (Flatten)     (None, 32)       0        embedding[1][0]          
## ___________________________________________________________________________
## dot_1 (Dot)             (None, 1)        0        flatten_1[0][0]          
##                                                   flatten_2[0][0]          
## ___________________________________________________________________________
## dense_1 (Dense)         (None, 1)        2        dot_1[0][0]              
## ===========================================================================
## Total params: 160,034
## Trainable params: 160,034
## Non-trainable params: 0
## ___________________________________________________________________________
model %>%
  fit_generator(
    skipgrams_generator(data$text, tokenizer, skip_window, negative_samples),
    steps_per_epoch = 100, epochs = 5
    )
embedding_matrix <- get_weights(model)[[1]]

words <- data_frame(
  word = names(tokenizer$word_index), 
  id = as.integer(unlist(tokenizer$word_index))
)

words <- words %>%
  filter(id <= tokenizer$num_words) %>%
  arrange(id)

row.names(embedding_matrix) <- c("UNK", words$word)
library(text2vec)
## 
## Attaching package: 'text2vec'
## The following objects are masked from 'package:keras':
## 
##     fit, normalize
find_similar_words <- function(word, embedding_matrix, n = 5) {
  similarities <- embedding_matrix[word, , drop = FALSE] %>%
    sim2(embedding_matrix, y = ., method = "cosine")
  
  similarities[,1] %>% sort(decreasing = TRUE) %>% head(n)
}
find_similar_words("sunrise", embedding_matrix)
##   sunrise     hotel      tour     early   morning 
## 1.0000000 0.9869296 0.9788519 0.9776611 0.9741627
find_similar_words("amazing", embedding_matrix)
##   amazing beautiful     place      view    people 
## 1.0000000 0.9805966 0.9753994 0.9722876 0.9721209
library(Rtsne)
library(ggplot2)
library(plotly)
## 
## Attaching package: 'plotly'
## The following object is masked from 'package:ggplot2':
## 
##     last_plot
## The following object is masked from 'package:stats':
## 
##     filter
## The following object is masked from 'package:graphics':
## 
##     layout
tsne <- Rtsne(embedding_matrix[2:500,], perplexity = 50, pca = FALSE)

tsne_plot <- tsne$Y %>%
  as.data.frame() %>%
  mutate(word = row.names(embedding_matrix)[2:500]) %>%
  ggplot(aes(x = V1, y = V2, label = word)) + 
  geom_text(size = 3)
ggplotly(tsne_plot)
sunrisevisitplaceamazingbeautifultourworldworthbuddhisttimeearlygreatguidesitetopyogyakartamorningvisitedviewdaypeopleindonesiahotelexperienceheritagetripgoodentrancenicehistorymagnificentjavacrowdedtemplesstunningwalklocalticketsunsetsunlothotarchitecturelargestimpressiveunescovisitinghourstouristshourmonumentmakemanoharaclimbbuddhapricewonderfulprambananancientangkorcomplexstructurebuilttouristpaybitwatexpensivearrivedbringbreathtakingmadeawesomerecommendhugeidrcarvingsenjoydoncrowdsviewsareafeecenturybigtimesspectacularhistoricalbiggestforeignersjogjalongbeautyavoidmajesticlotsmagicalpictureslocalsattractioncentraltakingborobodurphotosbackbusydrivestorywondersfantasticstonerpstatuesstupasstaydidnlevelshighlistumbrellainterestingcarmissstepsabsolutelysurroundingsimplyfindweatherdrivervisitorsstayedmagelangticketsvelocatedincredibleplacesgroundsreachspecialbuslovehillwaterschooljogjakartawatchlifedaysafternoonlevelmaintainedcityrecommendedexcellentspendstoriesfullsightstupausdpartbuymainwalkingseasonmissedbuildingreliefsrisetravelbookedyearmassivethingexithighlyasiauniqueentrystairspersonfeeldarkreasonextradawneasycrowdscenerypreparedmerapicatchparkhardfamilysitesstudentmoneycleanhiredueholidaybuddhismminuteslocationsmallpeacefulfeelingstartforgetdisappointedlovelymindreliefhistoricchildrenspentinsidecostpaidwantedenterpreservedlllargephotosteepheathatculturalcloudypublicnearbyfamousclimbingleftyogyaexplainlatethingsmakesspotpasttourshiredclosewakeprettyjourneyculturehighlightwowinspiringeffortenjoyedgivebucketworkfoundcandibuildbreathpackagekidsawedecidedserenehinduwaitluckyenglishlovedrestoredsettakeslightsizebadgroupspiritualarriveinternationalforeignersuggestwallweekslearnriderainbudhistcoolpicturewalkedhalfstayingamazedreachedpmmountainreadfriendsrupiahvolcanototallyfreewearcambodiathoughtcomingtoldfinallymistinformationfascinatingexpectfeltguidesearlierstudentssideexpectedstonesshortgladquietbookclearairportwasnmountainsaccessrainyprivatemomentreligiousunderstandeastmiddleimaginesculptureskindartsurroundingsmountsingletruehundredslifetimearchitecturalmanagedexploreopensurroundedpeacefriendfeesofferstartedpointdifficultheadperfectarrangeddistanceparkingputhumanpayingcarvedwordscheapercomparedgatemysticalentiredetailsfriendlygrandcountrysemarangforeignstreetstepdontboughtdescribeleavesouvenirsplancouplesmallerstatuebudhatransporttraincheapmtrealpyramidscaleremembergroupsnightstopclimbeddetailpreparesarongatmospheremagicweekendtodaysouthwoketaxicardthousandspanelslandscapeyogjakartaworthwhilenumbershopsconstructioncenturiessitdoubtserenityrentenergymakingvolcanicmuseumdifferencerestorationbuddhasinterestedopensgreatestlostkmsellingaskedguidedplentygorgeouspriceypieceextremelyjunglewakingpricesintricateroundpackedcombinedrespectcruiseskypeakwifeoverpricedripankorbeautifullywallspopularreviewexplainedplanningsettingdiscounthighlightseasilywaitingimportanthiddensecurityannoyingbaganearthwrongenormousunforgettableislandrichprovidesellerscarvingrisingamountcombomarketgiantmanfactfoggy-10-50510-5.0-2.50.02.55.0
V1V2

Post a Comment

1 Comments

Anonymous said…
Its economic price and wholesale price breaks make it a great wire for working CNC machining towards new techniques too. Available in 1mm (approx. 18-gauge), and 2mm (approx. 12-gauge). Based in Lancaster, PA. WebstaurantStore is the largest online restaurant provide store servicing professionals and individual customers worldwide.