Semantik penting karena dalam NLP, yang dipelajari adalah hubungan antar kata. Salah satu prosedur paling sederhana namun sangat efektif adalah Continuous Bag of Words (CBOW), yang memetakan kata-kata ke vektor-vektor bermakna tinggi yang disebut vektor kata. CBOW digunakan dalam kerangka kerja Word2Vec dan memprediksi sebuah kata berdasarkan kata-kata yang berdekatan dengannya, yang menangkap makna semantik maupun sintaksis bahasa. Dalam artikel ini, pembaca akan belajar tentang cara kerja model CBOW, serta metode penggunaannya. **Tujuan Pembelajaran** - Memahami teori di balik model CBOW. - Mempelajari perbedaan antara CBOW dan Skip-Gram. - Mengimplementasikan model CBOW dalam Python dengan dataset contoh. - Menganalisis kelebihan dan keterbatasan CBOW. - Menjelajahi kasus penggunaan untuk embedding kata yang dihasilkan oleh CBOW. **Apa Itu Model Continuous Bag of Words?** Continuous Bag of Words (CBOW) juga merupakan model yang digunakan ketika menentukan embedding kata menggunakan *neural network* dan merupakan bagian dari model Word2Vec oleh Tomas Mikolov. CBOW berusaha memprediksi sebuah kata target berdasarkan kata-kata konteks yang mengelilinginya dalam suatu kalimat tertentu. Dengan cara ini, model mampu menangkap hubungan semantik, sehingga kata-kata yang dekat secara makna akan direpresentasikan secara dekat pula dalam ruang berdimensi tinggi. Sebagai contoh, dalam kalimat “The cat sat on the mat”, jika ukuran jendela konteks adalah 2, maka kata-kata konteks untuk “sat” adalah [“The”, “cat”, “on”, “the”], dan tugas model adalah memprediksi kata “sat”. CBOW beroperasi dengan menggabungkan kata-kata konteks (misalnya, dengan merata-ratakan embedding-nya) dan menggunakan representasi gabungan ini untuk memprediksi kata target. Arsitektur model melibatkan lapisan input untuk kata-kata konteks, lapisan tersembunyi untuk pembangkitan embedding, dan lapisan output untuk memprediksi kata target menggunakan distribusi probabilitas. Ini adalah model cepat dan efisien yang cocok untuk menangani kata-kata yang sering muncul, menjadikannya ideal untuk tugas-tugas yang membutuhkan pemahaman semantik, seperti klasifikasi teks, sistem rekomendasi, dan analisis sentimen. --- **Cara Kerja Continuous Bag of Words** CBOW adalah salah satu teknik paling sederhana namun efisien dalam pembuatan embedding kata berdasarkan konteks, di mana seluruh kosakata kata dipetakan ke vektor. Bagian ini juga menjelaskan operasi sistem CBOW sebagai sarana untuk memahami metode ini pada tingkat paling dasar, membahas ide-ide utama yang mendasari metode CBOW, serta menyajikan panduan komprehensif tentang tata letak arsitektur sistem perhitungan CBOW. --- **Memahami Kata Konteks dan Kata Target** CBOW bergantung pada dua konsep utama: kata-kata konteks dan kata target. - **Kata Konteks**: Ini adalah kata-kata yang mengelilingi kata target dalam ukuran jendela yang ditentukan. Sebagai contoh, dalam kalimat: “The quick brown fox jumps over the lazy dog”, jika kata target adalah “fox” dan ukuran jendela konteks adalah 2, maka kata-kata konteksnya adalah [“quick”, “brown”, “jumps”, “over”]. - **Kata Target**: Ini adalah kata yang ingin diprediksi oleh CBOW, diberikan kata-kata konteks di sekitarnya. - Dengan menganalisis hubungan antara kata konteks dan kata target di seluruh korpus besar, CBOW menghasilkan embedding yang menangkap hubungan semantik antar kata. --- **Proses Langkah demi Langkah CBOW** Berikut adalah uraian cara kerja CBOW, langkah demi langkah: --- **Langkah 1: Persiapan Data** - Pilih sebuah korpus teks (misalnya, kalimat atau paragraf). - Tokenisasi teks menjadi kata-kata dan bangun kosakata. - Tentukan ukuran jendela konteks *n* (misalnya, 2 kata di setiap sisi). --- **Langkah 2: Membuat Pasangan Konteks-Kata Target** - Untuk setiap kata dalam korpus, ekstrak kata-kata konteks yang mengelilinginya berdasarkan ukuran jendela. - Contoh: Untuk kalimat “I love machine learning” dan *n=2* (artinya *2n=4*, tetapi dalam contoh ini hanya 2 kata di sekitar target), pasangannya adalah: | Kata Target | Kata Konteks | |-------------|------------------------| | love | [“I”, “machine”] | | machine | [“love”, “learning”] | * **Langkah 3: One-Hot Encoding** Ubah kata-kata konteks dan kata target menjadi vektor one-hot berdasarkan ukuran kosakata. Untuk kosakata berukuran 5, representasi one-hot untuk kata “love” mungkin terlihat seperti [0, 1, 0, 0, 0]. --- **Langkah 4: Lapisan Embedding** Lewatkan kata-kata konteks yang telah di-encode one-hot melalui lapisan embedding. Lapisan ini memetakan setiap kata ke representasi vektor padat, biasanya dengan dimensi lebih rendah dibandingkan ukuran kosakata. --- **Langkah 5: Agregasi Konteks** Gabungkan embedding dari semua kata konteks (misalnya, dengan merata-ratakan atau menjumlahkannya) untuk membentuk satu vektor konteks tunggal. --- **Langkah 6: Prediksi** - Masukkan vektor konteks yang telah digabungkan ke dalam jaringan saraf tiruan terhubung penuh (*fully connected neural network*) dengan lapisan output softmax. - Model memprediksi kata yang paling mungkin sebagai kata target berdasarkan distribusi probabilitas di seluruh kosakata. --- **Langkah 7: Perhitungan Loss dan Optimasi** - Hitung kesalahan antara kata target yang diprediksi dan kata target sebenarnya menggunakan fungsi loss *cross-entropy*. - Lakukan *backpropagation* terhadap kesalahan tersebut untuk menyesuaikan bobot pada lapisan embedding dan lapisan prediksi. **Langkah 8: Ulangi untuk Semua Pasangan** Ulangi proses ini untuk semua pasangan konteks-kata target dalam korpus hingga model mencapai konvergensi. --- ## **Arsitektur CBOW Dijelaskan Secara Rinci** ![image](https://hackmd.io/_uploads/ry49QHZ2gg.png) Arsitektur model Continuous Bag of Words (CBOW) dirancang untuk memprediksi sebuah kata target berdasarkan kata-kata konteks di sekitarnya. Ini adalah jaringan saraf tiruan dangkal (*shallow neural network*) dengan struktur yang sederhana namun efektif. Arsitektur CBOW terdiri dari komponen-komponen berikut: --- ### **Lapisan Input** - **Representasi Input:** Input ke model adalah kata-kata konteks yang direpresentasikan sebagai vektor yang telah di-*encode* dalam format *one-hot*. - Jika ukuran kosakata adalah V, maka setiap kata direpresentasikan sebagai vektor *one-hot* berukuran V, dengan satu nilai 1 pada indeks yang sesuai dengan kata tersebut, dan 0 di posisi lainnya. - Contoh: Jika kosakata adalah [“cat”, “dog”, “fox”, “tree”, “bird”] dan kata “fox” berada di urutan ketiga, maka vektor *one-hot*-nya adalah [0, 0, 1, 0, 0]. - **Jendela Konteks:** Ukuran jendela konteks *n* menentukan jumlah kata konteks yang digunakan. Jika *n=2*, maka dua kata di sebelah kiri dan dua kata di sebelah kanan kata target digunakan. - Contoh: Untuk kalimat “The quick brown fox jumps over the lazy dog” dan kata target “fox”, dengan *n=2*, kata-kata konteksnya adalah [“quick”, “brown”, “jumps”, “over”]. --- ### **Lapisan Embedding** - **Tujuan:** Lapisan ini mengubah vektor *one-hot* yang berdimensi tinggi menjadi vektor padat (*dense*) berdimensi lebih rendah. Berbeda dengan representasi *one-hot* yang mayoritas bernilai nol, pada lapisan embedding, setiap kata dikodekan sebagai vektor kontinu dengan dimensi yang diperlukan, yang mencerminkan karakteristik semantik spesifik dari makna kata tersebut. - **Matriks Embedding Kata:** Lapisan embedding menyimpan matriks embedding kata *W* berukuran *V×d*, di mana *V* adalah ukuran kosakata dan *d* adalah dimensi embedding. > * Setiap baris dari matriks *W* merepresentasikan embedding dari satu kata. > * Untuk vektor *one-hot* *x*, embedding dihitung sebagai $W^T \times x.$ - **Embedding Kata Konteks:** Setiap kata konteks diubah menjadi vektor padat yang sesuai menggunakan matriks embedding. Jika ukuran jendela *n=2*, dan kita memiliki 4 kata konteks, maka embedding untuk keempat kata tersebut diekstrak. --- ### **Lapisan Tersembunyi: Agregasi Konteks** - **Tujuan:** Embedding dari semua kata konteks digabungkan untuk membentuk satu vektor konteks tunggal. - **Metode Agregasi:** - **Rata-rata (Averaging):** Embedding dari semua kata konteks dirata-ratakan untuk menghitung vektor konteks. $$ h = \frac{1}{2n} \sum_{i=1}^{2n} e_i $$ - **Penjumlahan (Summation):** Selain menjadikan rata-rata, embedding dijumlahkan. $$ h = \sum_{i=1}^{2n} e_i $$ - **Vektor Konteks Hasil:** Hasilnya adalah satu vektor padat *h*, yang merepresentasikan konteks agregat dari kata-kata sekitarnya. ### **Lapisan Output** - **Tujuan:** Lapisan output memprediksi kata target menggunakan vektor konteks *h*. - **Lapisan Terhubung Penuh (*Fully Connected Layer*):** Vektor konteks *h* dilewatkan melalui lapisan terhubung penuh, yang menghasilkan skor mentah (*logits*) untuk setiap kata dalam kosakata. - **Fungsi Softmax:** Skor *logits* kemudian dilewatkan melalui fungsi softmax untuk menghitung distribusi probabilitas atas seluruh kosakata: $$ \tilde{h} = \frac{[0.1, 0.2, 0.3] + [0.4, 0.5, 0.6] + [0.2, 0.3, 0.4]}{3} = [0.233, 0.333, 0.433] $$ - **Kata Target yang Diprediksi:** Algoritma mendefinisikan kata target sebagai kata dengan probabilitas tertinggi pada output softmax. ### **Fungsi Loss** - Fungsi loss *cross-entropy* digunakan untuk membandingkan distribusi probabilitas yang diprediksi dengan kata target sebenarnya (*ground truth*). - Kerugian (loss) diminimalkan menggunakan teknik optimasi seperti Stochastic Gradient Descent (SGD) atau varian-varian lainnya. ### **Contoh CBOW dalam Aksi** **Input:** Kalimat: “I love machine learning”, kata target: “machine”, kata konteks: [“I”, “love”, “learning”]. **Pengodean One-Hot:** Vokabular: [“I”, “love”, “machine”, “learning”, “AI”] - Vektor one-hot: - “I”: [1,0,0,0,0][1,0,0,0,0][1,0,0,0,0] - “love”: [0,1,0,0,0][0,1,0,0,0][0,1,0,0,0] - “learning”: [0,0,0,1,0][0,0,0,1,0][0,0,0,1,0] - Layer Embedding: - Dimensi penyematan: d=3. - Matriks penyematan W: $$ W = \begin{bmatrix} 0.1 & 0.2 & 0.3 \\ 0.4 & 0.5 & 0.6 \\ 0.7 & 0.8 & 0.9 \\ 0.2 & 0.3 & 0.4 \\ 0.5 & 0.6 & 0.7 \\ \end{bmatrix} $$ Penyematan (Embeddings): - “I”: [0,1, 0,2, 0,3] - “love”: [0,4, 0,5, 0,6] - “learning”: [0,2, 0,3, 0,4] - Aggregasi: - Rata-ratakan penyematan: $$ \tilde{h} = \frac{[0.1, 0.2, 0.3] + [0.4, 0.5, 0.6] + [0.2, 0.3, 0.4]}{3} = [0.233, 0.333, 0.433] $$ - Lapisan Keluaran (Output Layer): Hitung logit, terapkan softmax, dan prediksi kata target. ### Diagram Arsitektur CBOW ```text Input Layer: ["I", "love", "learning"] --> One-hot encoding --> Embedding Layer --> Dense embeddings --> Aggregated context vector --> Fully connected layer + Softmax Output: Predicted word "machine" ``` ## **Mengodekan CBOW dari Nol (dengan Contoh Python)** Kita sekarang akan membahas cara mengimplementasikan model CBOW dari awal menggunakan Python. --- ### **Menyiapkan Data untuk CBOW** Langkah pertama adalah mengubah teks menjadi token — kata-kata yang kemudian diubah menjadi pasangan konteks-target, dengan konteks berupa kata-kata yang mengelilingi kata target. ```python corpus = "The quick brown fox jumps over the lazy dog" corpus = corpus.lower().split() # Tokenisasi dan konversi ke huruf kecil # Tentukan ukuran jendela konteks C = 2 context_target_pairs = [] # Hasilkan pasangan konteks-target for i in range(C, len(corpus) - C): context = corpus[i - C:i] + corpus[i + 1:i + C + 1] target = corpus[i] context_target_pairs.append((context, target)) print("Context-Target Pairs:", context_target_pairs) ``` **Output:** ``` Context-Target Pairs: [[('the', 'quick', 'fox', 'jumps'), 'brown'], ... ``` ### **Membuat Kamus Kata** Kita membuat kosakata (himpunan unik kata), lalu memetakan setiap kata ke indeks unik dan sebaliknya untuk pencarian yang efisien selama pelatihan. ```python # Buat kosakata dan petakan setiap kata ke indeks vocab = set(corpus) word_to_index = {word: idx for idx, word in enumerate(vocab)} index_to_word = {idx: word for word, idx in word_to_index.items()} print("Word to Index Dictionary:", word_to_index) ``` **Output:** ``` Word to Index Dictionary: {'brown': 0, 'dog': 1, 'quick': 2, 'jum... ``` **Contoh Pengodean One-Hot** Pengodean one-hot bekerja dengan mengubah setiap kata dalam sistem pembentukan kata menjadi vektor, di mana indikator kata tersebut bernilai ‘1’ sedangkan tempat lainnya bernilai ‘0’, karena alasan yang akan segera jelas. ```python def one_hot_encode(word, word_to_index): one_hot = np.zeros(len(word_to_index)) one_hot[word_to_index[word]] = 1 return one_hot # Contoh penggunaan untuk kata "quick" context_one_hot = [one_hot_encode(word, word_to_index) for word in ['the', 'quick']] print("One-Hot Encoding for 'quick':", context_one_hot[1]) ``` **Output:** ``` One-Hot Encoding for 'quick': [0. 0. 1. 0. 0. 0. 0. 0.] ``` ### **Membangun Model CBOW dari Nol** Pada langkah ini, kita membuat jaringan saraf dasar dengan dua lapisan: satu untuk embedding kata dan satu lagi untuk menghitung output berdasarkan kata-kata konteks, dengan merata-ratakan konteks dan meneruskannya melalui jaringan. ```python class CBOW: def __init__(self, vocab_size, embedding_dim): # Inisialisasi acak bobot untuk lapisan embedding dan output self.W1 = np.random.randn(vocab_size, embedding_dim) self.W2 = np.random.randn(embedding_dim, vocab_size) def forward(self, context_words): # Hitung lapisan tersembunyi (rata-rata dari kata-kata konteks) h = np.mean(context_words, axis=0) # Hitung lapisan output (probabilitas softmax) output = np.dot(h, self.W2) return output def backward(self, context_words, target_word, learning_rate=0.01): # Forward pass h = np.mean(context_words, axis=0) output = np.dot(h, self.W2) # Hitung error dan gradien error = target_word - output self.W2 += learning_rate * np.outer(h, error) self.W1 += learning_rate * np.outer(context_words, error) # Contoh pembuatan objek CBOW vocab_size = len(word_to_index) embedding_dim = 5 # Asumsikan embedding 5-dimensi cbow_model = CBOW(vocab_size, embedding_dim) # Menggunakan kata konteks dan target acak (sebagai contoh) context_words = [one_hot_encode(word, word_to_index) for word in ['the', 'quick']] context_words = np.array(context_words) context_words = np.mean(context_words, axis=0) # rata-rata kata konteks target_word = one_hot_encode('brown', word_to_index) # Forward pass melalui model CBOW output = cbow_model.forward(context_words) print("Output of CBOW forward pass:", output) ``` **Output:** ``` Output of CBOW forward pass: [[-0.20435729 -0.23851241 -0.0810526 -0.06523201 0.0255063 ] [-0.0192184 -0.12958821 0.1019369 0.11101922 -0.17773069 -0.02340574 -0.22222151 -0.23863179] [ 0.21221977 -0.15263454 -0.015248 0.27618767 0.02959409 0.21777961 0.16619577 0.20560026] [ 0.05354038 0.06903295 0.0592706 -0.13509918 -0.00439649 0.18007843 0.1611929 0.2449023 ] [ 0.01092826 0.19643582 -0.07430934 -0.16443165 -0.01094085 -0.27452367 -0.13747784 0.31185284]] ``` ### **Menggunakan TensorFlow untuk Mengimplementasikan CBOW** TensorFlow menyederhanakan proses dengan mendefinisikan jaringan saraf yang menggunakan lapisan embedding untuk mempelajari representasi kata dan lapisan dense untuk output, menggunakan kata-kata konteks untuk memprediksi kata target. ```python import tensorflow as tf # Definisikan model CBOW sederhana menggunakan TensorFlow class CBOWModel(tf.keras.Model): def __init__(self, vocab_size, embedding_dim): super(CBOWModel, self).__init__() self.embeddings = tf.keras.layers.Embedding(input_dim=vocab_size, output_dim=embedding_dim) self.output_layer = tf.keras.layers.Dense(vocab_size, activation='softmax') def call(self, context_words): embedded_context = self.embeddings(context_words) context_avg = tf.reduce_mean(embedded_context, axis=1) output = self.output_layer(context_avg) return output # Contoh penggunaan model = CBOWModel(vocab_size=8, embedding_dim=5) context_input = np.random.randint(0, 8, size=(1, 4)) # Input konteks acak context_input = tf.convert_to_tensor(context_input, dtype=tf.int32) # Forward pass output = model(context_input) print("Output of TensorFlow CBOW model:", output.numpy()) ``` **Output:** ``` Output of TensorFlow CBOW model: [[0.12362909 0.12616573 0.127586 0.12319998 0.12486169]] ``` --- ### **Menggunakan Gensim untuk CBOW** Gensim menyediakan implementasi siap pakai dari CBOW dalam fungsi Word2Vec(), di mana pengguna tidak perlu bersusah payah melatih model karena Gensim secara otomatis melatih embedding kata dari korpus teks. ```python import gensim from gensim.models import Word2Vec # Siapkan data (daftar daftar kata) corpus = [["the", "quick", "brown", "fox"], ["jumps", "over", "the", "lazy"]] # Latih model Word2Vec menggunakan CBOW model = Word2Vec(corpus, vector_size=5, window=2, min_count=1, sg=0) # Dapatkan representasi vektor dari suatu kata vector = model.wv['fox'] print("Vector representation of 'fox':", vector) ``` **Output:** ``` Vector representation of 'fox': [-0.06810732 -0.01892803 0.11537 ... ``` --- ### **Kelebihan Continuous Bag of Words** Kita sekarang akan mengeksplorasi kelebihan Continuous Bag of Words: **Kelebihan Continuous Bag of Words** - **Pembelajaran Representasi Kata yang Efisien**: CBOW secara efisien mempelajari representasi vektor padat untuk kata-kata dengan menggunakan kata-kata konteks. Ini menghasilkan vektor berdimensi lebih rendah dibandingkan pengodean one-hot tradisional, yang bisa sangat mahal secara komputasi. - **Menangkap Hubungan Semantik**: CBOW menangkap hubungan semantik antar kata berdasarkan konteksnya dalam korpus besar. Hal ini memungkinkan model mempelajari kemiripan kata, sinonim, dan nuansa kontekstual lainnya, yang berguna dalam tugas seperti pemulihan informasi dan analisis sentimen. - **Skalabilitas**: Model CBOW sangat skalabel dan dapat memproses dataset besar secara efisien, menjadikannya cocok untuk aplikasi dengan jumlah besar data teks, seperti mesin pencari dan platform media sosial. - **Fleksibilitas Kontekstual**: CBOW dapat menangani jumlah konteks yang bervariasi (misalnya, jumlah kata sekitar yang dipertimbangkan), menawarkan fleksibilitas dalam seberapa banyak konteks yang diperlukan untuk mempelajari representasi kata. - **Peningkatan Kinerja dalam Tugas NLP**: Embedding kata CBOW meningkatkan kinerja tugas NLP turunan, seperti klasifikasi teks, pengenalan entitas bernama, dan terjemahan mesin, dengan menyediakan representasi fitur berkualitas tinggi. --- **Keterbatasan Continuous Bag of Words** Mari kita bahas keterbatasan CBOW: - **Sensitivitas terhadap Ukuran Jendela Konteks**: Kinerja CBOW sangat bergantung pada ukuran jendela konteks. Jendela kecil mungkin hanya menangkap hubungan lokal, sementara jendela besar dapat mengaburkan keunikan kata. Menemukan ukuran konteks optimal bisa menantang dan bergantung pada tugas. - **Tidak Sensitif terhadap Urutan Kata**: CBOW mengabaikan urutan kata dalam konteks, artinya tidak menangkap sifat sekuensial bahasa. Keterbatasan ini bisa menjadi masalah untuk tugas yang membutuhkan pemahaman mendalam tentang urutan kata, seperti *syntactic parsing* dan *language modeling*. - **Kesulitan dengan Kata Langka**: CBOW kesulitan menghasilkan embedding yang bermakna untuk kata langka atau di luar kosakata (OOV). Model ini bergantung pada konteks, tetapi data jarang untuk kata-kata tidak sering muncul dapat menghasilkan representasi vektor yang buruk. - **Terbatas pada Pemahaman Kontekstual yang Dangkal**: Meskipun CBOW menangkap makna kata berdasarkan kata-kata sekitarnya, kemampuannya dalam memahami fenomena linguistik yang lebih kompleks — seperti ketergantungan jangka panjang, ironi, atau sarkasme — sangat terbatas, yang mungkin memerlukan model yang lebih canggih seperti *transformers*. - **Ketidakmampuan Menangani Polisemi dengan Baik**: Kata-kata yang memiliki banyak makna (polisemi) bisa menjadi masalah bagi CBOW. Karena model menghasilkan satu embedding tunggal untuk setiap kata, ia mungkin tidak menangkap makna berbeda yang dapat dimiliki suatu kata dalam konteks yang berbeda, tidak seperti model lebih canggih seperti BERT atau ELMo. ### **Kesimpulan** Model Continuous Bag of Words (CBOW) telah terbukti sebagai pendekatan yang efisien dan intuitif untuk menghasilkan embedding kata dengan memanfaatkan konteks sekitarnya. Melalui arsitektur sederhana namun efektifnya, CBOW menjembatani kesenjangan antara teks mentah dan representasi vektor yang bermakna, memungkinkan berbagai aplikasi NLP. Dengan memahami mekanisme kerja, kekuatan, dan keterbatasan CBOW, kita memperoleh wawasan lebih dalam tentang evolusi teknik NLP. Berkat perannya yang mendasar dalam generasi embedding, CBOW tetap menjadi batu loncatan penting dalam menjelajahi model bahasa tingkat lanjut. --- **Poin Penting** - CBOW memprediksi kata target menggunakan konteks di sekitarnya, menjadikannya efisien dan sederhana. - Model ini bekerja baik untuk kata-kata yang sering muncul, menawarkan efisiensi komputasi. - Embedding yang dipelajari oleh CBOW menangkap hubungan semantik maupun sintaksis. - CBOW merupakan dasar penting untuk memahami teknik embedding kata modern. - Aplikasi praktisnya mencakup analisis sentimen, pencarian semantik, dan rekomendasi teks. ## Referensi 1.https://www.analyticsvidhya.com/blog/2024/11/continuous-bag-of-words-cbow/ 2. https://www.analyticsvidhya.com/blog/2017/06/word-embeddings-coUnt-word2veec/ 3. https://fall-2023-python-programming-for-data-science.readthedocs.io/en/latest/Lectures/Theme_3-Model_Engineering/Lecture_19-Natural_Language_Processing/Lecture_19-NLP.html#19.3-Text-Tokenization 4. https://towardsdatascience.com/text-embeddings-comprehensive-guide-afd97fce8fb5/ 5. https://osanseviero.github.io/hackerllama/blog/posts/sentence_embeddings/ 6. https://www.geeksforgeeks.org/nlp/continuous-bag-of-words-cbow-in-nlp/ 7. https://medium.com/@mudassar.hakim/semantic-processing-cbow-example-2c36155d338c