Seeking the soul of words. The mathematical world of language, from Word2Vec to Language Models and Neural Networks.
Word Embeddings · Language Models · Neural Networks · Attention
Use Spacebar or Arrow Keys to navigate or scroll
Transforming discrete words into continuous, dense, multi-dimensional floating-point vectors (Digital DNA).
Rule: *"You shall know a word by the company it keeps."* (J.R. Firth, popularized by Mikolov in 2013)
vector("King") - vector("Man") + vector("Woman") ≈ vector("Queen")
(Understanding word relationships using Numpy arrays)
import numpy as np
# Hypothetical multi-dimensional word embeddings
# Dimensions: [Royalty_Score, Masculinity_Score]
vec_king = np.array([0.9, 0.9])
vec_man = np.array([0.0, 0.9])
vec_woman = np.array([0.0, -0.9])
# The Word2Vec Magic equation
vec_result = vec_king - vec_man + vec_woman
print("Computed Vector (King - Man + Woman):")
print(vec_result)
# Ideal vector for Queen = [Royalty, Femininity]
vec_queen = np.array([0.9, -0.9])
print("\nTarget Vector (Queen):")
print(vec_queen)
print("\n💡 The algebraic operation perfectly arrives at the semantic concept of 'Queen'!")
(The mathematical backbone of semantic search and NLP distance metrics)
import numpy as np
from numpy.linalg import norm
def cosine_similarity(vec1, vec2):
"""Calculates cosine of angle between vectors. Range: -1 to 1"""
return np.dot(vec1, vec2) / (norm(vec1) * norm(vec2))
# Hypothetical embeddings
vec_king = np.array([0.9, 0.8, 0.1])
vec_queen = np.array([0.9, -0.8, 0.1])
vec_man = np.array([0.1, 0.8, 0.0])
vec_apple = np.array([0.0, 0.0, 0.9])
print("Cosine Similarity Scores:")
print("-" * 30)
print(f"King & Queen : {cosine_similarity(vec_king, vec_queen):.3f}")
print(f"King & Man : {cosine_similarity(vec_king, vec_man):.3f}")
print(f"King & Apple : {cosine_similarity(vec_king, vec_apple):.3f}")
print("\nConclusion: King and Queen share high semantic alignment.")
print("King and Apple are completely orthogonal (unrelated).")
(Convert text to numerical vectors by counting word frequencies)
from sklearn.feature_extraction.text import CountVectorizer
import numpy as np
# Sample sentences
sentences = [
"I love machine learning",
"Machine learning is amazing",
"I love deep learning too"
]
# Create Bag of Words vectorizer
vectorizer = CountVectorizer()
bow_matrix = vectorizer.fit_transform(sentences)
# Get vocabulary
vocab = vectorizer.get_feature_names_out()
print("📚 Bag of Words Representation")
print("="*50)
print(f"\nVocabulary: {list(vocab)}\n")
print("BoW Matrix (rows=documents, cols=words):")
print("-"*50)
for i, sent in enumerate(sentences):
counts = bow_matrix[i].toarray()[0]
print(f"\nDoc {i+1}: '{sent}'")
print(f"Vector: {counts}")
# Show non-zero words
words = [(vocab[j], counts[j]) for j in range(len(counts)) if counts[j] > 0]
print(f"Words: {dict(words)}")
print("\n💡 Limitation: 'I love ML' and 'ML I love'")
print(" have IDENTICAL vectors (no word order)!")
(Explore a mini embedding space interactively)
import numpy as np
from numpy.linalg import norm
# Mini word embedding space (simplified 4D vectors)
# Dimensions: [royalty, gender(M+/F-), animal, technology]
word_vectors = {
"king": np.array([0.9, 0.8, 0.0, 0.0]),
"queen": np.array([0.9, -0.8, 0.0, 0.0]),
"prince": np.array([0.7, 0.6, 0.0, 0.0]),
"princess": np.array([0.7, -0.6, 0.0, 0.0]),
"man": np.array([0.1, 0.9, 0.0, 0.0]),
"woman": np.array([0.1, -0.9, 0.0, 0.0]),
"dog": np.array([0.0, 0.2, 0.9, 0.0]),
"cat": np.array([0.0, -0.2, 0.9, 0.0]),
"computer": np.array([0.0, 0.0, 0.0, 0.9]),
"laptop": np.array([0.0, 0.0, 0.0, 0.85]),
}
def cosine_sim(v1, v2):
return np.dot(v1, v2) / (norm(v1) * norm(v2))
def find_similar(word, top_n=3):
"""Find most similar words to a given word"""
if word not in word_vectors:
return []
vec = word_vectors[word]
sims = [(w, cosine_sim(vec, v)) for w, v in word_vectors.items() if w != word]
return sorted(sims, key=lambda x: x[1], reverse=True)[:top_n]
def word_analogy(a, b, c):
"""a is to b as c is to ?"""
# result = vec(b) - vec(a) + vec(c)
result = word_vectors[b] - word_vectors[a] + word_vectors[c]
sims = [(w, cosine_sim(result, v)) for w, v in word_vectors.items()
if w not in [a, b, c]]
return sorted(sims, key=lambda x: x[1], reverse=True)[0]
print("🔍 Word Similarity Explorer")
print("="*50)
# Find similar words
for word in ["king", "dog", "computer"]:
similar = find_similar(word, 3)
print(f"\nWords similar to '{word}':")
for w, score in similar:
print(f" {w:12} (similarity: {score:.2f})")
# Word analogies
print("\n" + "="*50)
print("🧮 Word Analogies:")
print("\nking:queen :: man:?")
answer, score = word_analogy("king", "queen", "man")
print(f" Answer: {answer} (score: {score:.2f})")
print("\ndog:cat :: prince:?")
answer, score = word_analogy("dog", "cat", "prince")
print(f" Answer: {answer} (score: {score:.2f})")
(Transform documents into weighted term vectors)
from sklearn.feature_extraction.text import TfidfVectorizer
import numpy as np
# Sample document corpus
documents = [
"Machine learning is a subset of artificial intelligence",
"Deep learning uses neural networks with many layers",
"Natural language processing enables machines to understand text",
"AI and machine learning are transforming industries"
]
# Create TF-IDF vectorizer
vectorizer = TfidfVectorizer()
tfidf_matrix = vectorizer.fit_transform(documents)
# Display vocabulary
print("📚 Vocabulary (sample):", list(vectorizer.vocabulary_.keys())[:8])
print(f"\n📊 TF-IDF Matrix Shape: {tfidf_matrix.shape}")
print(" (4 documents × {} unique terms)\n".format(len(vectorizer.vocabulary_)))
# Show TF-IDF scores for first document
feature_names = vectorizer.get_feature_names_out()
doc1_scores = tfidf_matrix[0].toarray()[0]
sorted_idx = np.argsort(doc1_scores)[::-1]
print("🔍 Top terms in Document 1:")
for i in sorted_idx[:5]:
if doc1_scores[i] > 0:
print(f" '{feature_names[i]}': {doc1_scores[i]:.3f}")
The ultimate solution to the Word2Vec "Static" limitation.
(Tokenization, Stemming, and Lemmatization in action)
import simplemma
import re
# Sample text for processing
text = "The running foxes were quickly jumping over the fallen trees. They're loving it!"
# Step 1: Basic Tokenization
tokens = re.findall(r'\b\w+\b', text.lower())
print("🔤 Original Tokens:")
print(f" {tokens}\n")
# Step 2: Lemmatization (reduce to base form)
lemmas = [simplemma.lemmatize(word, lang='en') for word in tokens]
print("📖 After Lemmatization:")
print(f" {lemmas}\n")
# Step 3: Simple Stemming (rule-based suffix removal)
def simple_stem(word):
suffixes = ['ing', 'ed', 'ly', 's', 'er', 'est']
for suffix in suffixes:
if word.endswith(suffix) and len(word) > len(suffix) + 2:
return word[:-len(suffix)]
return word
stems = [simple_stem(word) for word in tokens]
print("✂️ After Stemming:")
print(f" {stems}\n")
# Compare transformations
print("📊 Comparison (Token → Lemma → Stem):")
for t, l, s in list(zip(tokens, lemmas, stems))[:6]:
print(f" {t:12} → {l:10} → {s}")
↓ Scroll down to continue ↓
Markov Chains: Predicting the next state based exclusively on the current state, ignoring all previous history.
P(next word | current word)
Example: "The cat sat on the [___]".
The model looks only at the word 'the' and checks its statistical history to see how often 'mat' or 'chair' followed it.
A massive lookup table storing the probability distribution of shifting from one specific word to another.
P(word₂ | word₁) = Count(word₁, word₂) / Count(word₁)
*Historical Note: Andrey Markov originally developed this by analyzing the consonant/vowel distribution in Alexander Pushkin's poetry.
(Building a Transition Matrix using NLTK N-grams)
from nltk import ngrams, ConditionalFreqDist
text = "I love AI . I love Python . AI is amazing .".split()
# Extract Bigrams (Pairs of consecutive words)
bigrams = list(ngrams(text, 2))
print("Sample Bigrams:", bigrams[:4], "...\n")
# Build Conditional Frequency Distribution (Transition Matrix)
cfd = ConditionalFreqDist(bigrams)
print("Transition Matrix for 'AI':", dict(cfd['AI']))
print("Transition Matrix for 'love':", dict(cfd['love']))
# Next Word Prediction
current_word = "I"
# Max() returns the most statistically probable next word
next_word = cfd[current_word].max()
print(f"\nPrediction: After the word '{current_word}', the model predicts '{next_word}'.")
(Generate new text using learned transition probabilities)
import random
from collections import defaultdict
# Training corpus - Shakespeare-style text
corpus = """
To be or not to be that is the question.
To live or not to live is also a question.
To learn is to grow and to grow is to be wise.
Knowledge is power and power is wisdom.
Wisdom leads to understanding and understanding leads to peace.
""".lower()
words = corpus.split()
# Build transition probabilities
transitions = defaultdict(list)
for i in range(len(words) - 1):
transitions[words[i]].append(words[i+1])
print("Transition options for 'to':", transitions['to'][:5])
print("Transition options for 'is':", transitions['is'][:5])
print("\n" + "="*40)
# Generate new text!
def generate_text(start_word, length=10):
current = start_word
result = [current]
for _ in range(length - 1):
if current in transitions:
current = random.choice(transitions[current])
result.append(current)
else:
break
return ' '.join(result)
print("\n🎲 Generated Sentences:")
for i in range(3):
print(f" {i+1}. {generate_text('to', 8)}")
To predict the next word, the model uses a sliding window to look at the two preceding words (Trigrams) instead of just one.
The computational study of extracting subjective information, identifying whether the underlying emotional tone of a text is Positive, Negative, or Neutral.
(Implementing VADER - Valence Aware Dictionary and sEntiment Reasoner)
from vaderSentiment.vaderSentiment import SentimentIntensityAnalyzer
# VADER is highly optimized for social media text and microblogs
analyzer = SentimentIntensityAnalyzer()
text = "I absolutely love this NLP course, it is incredibly engaging! But the homework is awful."
# Generate polarity scores
scores = analyzer.polarity_scores(text)
print("Input Text:", text)
print("\nRaw Scoring Metrics:", scores)
# The 'compound' score is a normalized, weighted composite score
compound = scores['compound']
if compound >= 0.05:
print("\nOverall Sentiment: Positive 😊")
elif compound <= -0.05:
print("\nOverall Sentiment: Negative 😠")
else:
print("\nOverall Sentiment: Neutral 😐")
(Lexicon-based approach from scratch)
import re
# Build a simple sentiment lexicon
positive_words = {
'love': 3, 'amazing': 3, 'excellent': 3, 'good': 2,
'great': 2, 'happy': 2, 'wonderful': 3, 'best': 3,
'like': 1, 'nice': 1, 'enjoy': 2, 'fantastic': 3
}
negative_words = {
'hate': -3, 'awful': -3, 'terrible': -3, 'bad': -2,
'horrible': -3, 'worst': -3, 'boring': -2, 'poor': -2,
'sad': -2, 'disappointing': -2, 'ugly': -2, 'difficult': -1
}
# Intensifiers and negations
intensifiers = {'very': 1.5, 'really': 1.5, 'extremely': 2, 'absolutely': 2}
negations = {'not', "n't", 'never', 'no'}
def analyze_sentiment(text):
words = re.findall(r'\b\w+\b', text.lower())
score = 0
details = []
negate = False
intensity = 1
for word in words:
if word in negations:
negate = True
continue
if word in intensifiers:
intensity = intensifiers[word]
continue
word_score = positive_words.get(word, 0) + negative_words.get(word, 0)
if word_score != 0:
if negate:
word_score = -word_score * 0.5
word_score *= intensity
details.append((word, word_score))
score += word_score
negate = False
intensity = 1
return score, details
# Test sentences
sentences = [
"I love this amazing product!",
"This is really terrible and awful",
"The movie was not bad actually",
"I'm very happy with this excellent service"
]
print("🎭 Custom Sentiment Analyzer\n" + "="*50)
for sent in sentences:
score, details = analyze_sentiment(sent)
emoji = "😊" if score > 0 else "😠" if score < 0 else "😐"
print(f"\n'{sent}'")
print(f" Words found: {details}")
print(f" Total Score: {score:.1f} {emoji}")
(Find similar documents using TF-IDF and cosine similarity)
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
import numpy as np
# Document corpus
documents = [
"Python is a great programming language for data science",
"Machine learning algorithms can predict future outcomes",
"Data science uses Python and machine learning techniques",
"JavaScript is popular for web development",
"Neural networks are a type of machine learning model",
"Web applications often use JavaScript frameworks"
]
# Query to find similar documents
query = "What programming language is best for machine learning?"
# Vectorize documents and query
vectorizer = TfidfVectorizer(stop_words='english')
doc_vectors = vectorizer.fit_transform(documents)
query_vector = vectorizer.transform([query])
# Calculate cosine similarity
similarities = cosine_similarity(query_vector, doc_vectors)[0]
print("🔍 Semantic Document Search")
print("="*55)
print(f"Query: '{query}'\n")
print("Document Rankings:\n")
# Sort by similarity
ranked_idx = np.argsort(similarities)[::-1]
for rank, idx in enumerate(ranked_idx, 1):
score = similarities[idx]
bar = "█" * int(score * 25)
print(f" #{rank} (score: {score:.3f}) {bar}")
print(f" '{documents[idx][:50]}...'\n")
print("💡 TF-IDF + Cosine Similarity = Simple Semantic Search!")
The Need for Sequence: How do we differentiate grammatical structures over time?
↓ Scroll down to continue ↓
An advanced RNN architecture specifically engineered to carry long-term dependencies across vast sequences.
(Simulate how an RNN processes sequential data)
import numpy as np
# Simple RNN forward pass simulation
np.random.seed(42)
# Initialize weights (small random values)
hidden_size = 4
input_size = 3
Wxh = np.random.randn(hidden_size, input_size) * 0.1 # Input to hidden
Whh = np.random.randn(hidden_size, hidden_size) * 0.1 # Hidden to hidden
bh = np.zeros(hidden_size) # Hidden bias
def tanh(x):
return np.tanh(x)
# Input sequence: "I love AI" (3 words as simple vectors)
sequence = [
np.array([1, 0, 0]), # "I"
np.array([0, 1, 0]), # "love"
np.array([0, 0, 1]) # "AI"
]
words = ["I", "love", "AI"]
# Process sequence through RNN
h = np.zeros(hidden_size) # Initial hidden state
print("🔄 RNN Processing Sequence:")
print("="*45)
for i, (x, word) in enumerate(zip(sequence, words)):
# RNN formula: h_t = tanh(Wxh·x_t + Whh·h_{t-1} + b)
h_new = tanh(np.dot(Wxh, x) + np.dot(Whh, h) + bh)
print(f"\nStep {i+1}: Processing '{word}'")
print(f" Input vector: {x}")
print(f" Previous h: [{', '.join(f'{v:.2f}' for v in h)}]")
print(f" New hidden: [{', '.join(f'{v:.2f}' for v in h_new)}]")
h = h_new
print("\n" + "="*45)
print("✅ Final hidden state encodes the entire sequence!")
(Visualize how LSTM gates control information flow)
import numpy as np
def sigmoid(x):
return 1 / (1 + np.exp(-x))
def tanh(x):
return np.tanh(x)
# Simulate LSTM gates for one timestep
print("🧠 LSTM Gate Simulation")
print("="*50)
# Simulated input (current word embedding + previous hidden state)
x_t = np.array([0.5, -0.2, 0.8]) # Current input
h_prev = np.array([0.1, 0.3]) # Previous hidden state
c_prev = np.array([0.4, -0.1]) # Previous cell state
# Simulated gate outputs (normally computed from weights)
forget_gate = sigmoid(np.array([0.2, 0.9])) # What to forget
input_gate = sigmoid(np.array([0.8, 0.3])) # What to write
candidate = tanh(np.array([0.5, -0.4])) # New candidate values
output_gate = sigmoid(np.array([0.7, 0.6])) # What to output
print(f"\n📥 Previous Cell State: {c_prev}")
print(f"\n🚪 Gate Activations:")
print(f" Forget Gate: {np.round(forget_gate, 2)} (0=forget, 1=keep)")
print(f" Input Gate: {np.round(input_gate, 2)} (0=ignore, 1=write)")
print(f" Output Gate: {np.round(output_gate, 2)} (0=hide, 1=expose)")
# LSTM cell state update: c_t = f*c_{t-1} + i*candidate
c_new = forget_gate * c_prev + input_gate * candidate
h_new = output_gate * tanh(c_new)
print(f"\n📤 New Cell State: {np.round(c_new, 3)}")
print(f"📤 New Hidden State: {np.round(h_new, 3)}")
print(f"\n💡 The cell state preserves long-term memory!")
print(" Forget gate kept {:.0%} of previous info".format(np.mean(forget_gate)))
How do we capture the "essence" of one language and generate an entirely new sequence? (e.g., Machine Translation, Summarization).
(Convert raw scores to probability distribution)
import numpy as np
def softmax(x):
"""Convert raw logits to probability distribution"""
exp_x = np.exp(x - np.max(x)) # Subtract max for numerical stability
return exp_x / exp_x.sum()
# Simulated vocabulary
vocab = ["the", "cat", "sat", "on", "mat", "dog", "floor", ""]
# Raw logits from neural network (before softmax)
# Higher values = model thinks word is more likely
logits = np.array([1.2, 2.8, 0.5, 0.3, 2.1, 0.1, 0.8, -1.0])
print("📊 Language Model Next Word Prediction")
print("="*50)
print(f"Context: 'The _____'\n")
# Apply softmax to get probabilities
probs = softmax(logits)
# Display sorted by probability
sorted_idx = np.argsort(probs)[::-1]
print("Word Probabilities (sorted):")
for i in sorted_idx:
bar = "█" * int(probs[i] * 30)
print(f" {vocab[i]:8} {probs[i]:.3f} {bar}")
# Sampling strategies
print("\n🎯 Decoding Strategies:")
print(f" Greedy (argmax): '{vocab[np.argmax(probs)]}'")
# Temperature sampling
temp = 0.5
temp_probs = softmax(logits / temp)
print(f" Low temp (0.5): More confident, less creative")
print(f" High temp (2.0): More random, more creative")
(Watch how input compresses into a context vector)
import numpy as np
# Simulate Seq2Seq Encoder for translation: "Hello world" → Context
print("🔄 Seq2Seq Encoder Simulation")
print("="*50)
print("Task: Encode 'Hello world' for translation\n")
# Step 1: Tokenization
tokens = ["Hello", "world", ""]
print(f"Step 1 - Tokens: {tokens}")
# Step 2: Embedding lookup (simplified)
embeddings = {
"Hello": np.array([0.8, 0.2, 0.1, 0.5]),
"world": np.array([0.3, 0.9, 0.4, 0.2]),
"": np.array([0.0, 0.0, 0.0, 1.0])
}
print("\nStep 2 - Embeddings:")
for token in tokens:
print(f" '{token}': {embeddings[token]}")
# Step 3: RNN encoding (simplified)
hidden = np.zeros(4)
print("\nStep 3 - Sequential RNN Processing:")
for i, token in enumerate(tokens):
# Simplified: hidden = tanh(embedding + 0.5*prev_hidden)
hidden = np.tanh(embeddings[token] + 0.5 * hidden)
print(f" After '{token}': h = [{', '.join(f'{v:.2f}' for v in hidden)}]")
print("\n" + "="*50)
print("📦 Final Context Vector:")
print(f" {np.round(hidden, 3)}")
print("\n💡 This single vector captures the meaning of")
print(" 'Hello world' - ready for the Decoder!")
A mathematical mechanism allowing a model to calculate how strongly every word in a sequence relates to every other word simultaneously.
"The animal didn't cross the street because it was too tired."
How does the machine know what 'it' refers to? The street or the animal? Self-Attention assigns massive mathematical weight between 'it' and 'animal', instantly resolving the coreference.
(Using Matrix Multiplication to calculate focus weightings)
import numpy as np
# Sequence: "Bank", "of", "River"
words = ["Bank", "of", "River"]
# Simplified Embeddings: [Water_Feature, Financial_Feature]
vectors = np.array([
[0.9, 0.1], # Bank (Assuming riverbank context here)
[0.1, 0.1], # of
[0.8, 0.2] # River
])
# Self-Attention Formula core: Q x K^T (Query matrix dot Key matrix)
attention_scores = np.dot(vectors, vectors.T)
print("Raw Attention Scores for 'Bank' against all words:")
print(np.round(attention_scores[0], 2))
# Identify which context word 'Bank' pays the most attention to
highest_attention_idx = np.argmax(attention_scores[0][1:]) + 1
print(f"\nThe word 'Bank' attends most strongly to: '{words[highest_attention_idx]}'")
print("💡 The model successfully contextualizes 'Bank' as a body of water!")
(Full Query-Key-Value Attention as used in Transformers)
import numpy as np
def softmax(x):
exp_x = np.exp(x - np.max(x, axis=-1, keepdims=True))
return exp_x / exp_x.sum(axis=-1, keepdims=True)
print("🔍 Scaled Dot-Product Attention")
print("="*50)
# Sentence: "The cat sat"
words = ["The", "cat", "sat"]
d_k = 4 # Dimension of keys
# Word embeddings (simplified)
embeddings = np.array([
[0.1, 0.2, 0.3, 0.4], # The
[0.5, 0.8, 0.2, 0.1], # cat
[0.3, 0.1, 0.7, 0.5] # sat
])
# In real Transformers, Q, K, V are learned linear projections
# Here we use embeddings directly for simplicity
Q = K = V = embeddings
# Step 1: Compute attention scores (Q × K^T)
scores = np.dot(Q, K.T)
print("Step 1 - Raw Scores (Q × K^T):")
print(np.round(scores, 2))
# Step 2: Scale by sqrt(d_k) to prevent large values
scaled_scores = scores / np.sqrt(d_k)
print(f"\nStep 2 - Scaled by √{d_k}:")
print(np.round(scaled_scores, 2))
# Step 3: Apply softmax to get attention weights
attention_weights = softmax(scaled_scores)
print("\nStep 3 - Attention Weights (softmax):")
for i, word in enumerate(words):
weights_str = ' '.join(f'{w:.2f}' for w in attention_weights[i])
print(f" '{word}' attends to: [{weights_str}]")
# Step 4: Compute output (weighted sum of Values)
output = np.dot(attention_weights, V)
print("\nStep 4 - Contextualized Output:")
print(f" 'cat' now encodes context from entire sequence!")
(How Transformers understand word order without recurrence)
import numpy as np
def positional_encoding(seq_len, d_model):
"""Generate sinusoidal positional encodings"""
positions = np.arange(seq_len)[:, np.newaxis]
dims = np.arange(d_model)[np.newaxis, :]
# PE(pos, 2i) = sin(pos / 10000^(2i/d_model))
# PE(pos, 2i+1) = cos(pos / 10000^(2i/d_model))
angles = positions / np.power(10000, (2 * (dims // 2)) / d_model)
pe = np.zeros((seq_len, d_model))
pe[:, 0::2] = np.sin(angles[:, 0::2]) # Even indices
pe[:, 1::2] = np.cos(angles[:, 1::2]) # Odd indices
return pe
print("📍 Positional Encoding Visualization")
print("="*50)
# Generate positional encodings for 5 positions, 8 dimensions
seq_len, d_model = 5, 8
pe = positional_encoding(seq_len, d_model)
words = ["I", "love", "natural", "language", "processing"]
print("Each position gets a unique encoding:\n")
for i, word in enumerate(words):
encoding = ' '.join(f'{v:+.2f}' for v in pe[i, :4])
print(f" Position {i} ('{word}'): [{encoding} ...]")
print("\n💡 Key Insight:")
print(" - Each position has a unique 'fingerprint'")
print(" - Similar positions have similar encodings")
print(" - Allows parallel processing (no RNN needed!)")
# Show that nearby positions are similar
dist_01 = np.linalg.norm(pe[0] - pe[1])
dist_04 = np.linalg.norm(pe[0] - pe[4])
print(f"\n Distance(pos 0, pos 1): {dist_01:.3f}")
print(f" Distance(pos 0, pos 4): {dist_04:.3f}")
By discarding slow RNN architecture entirely and relying solely on Attention mechanisms ("Attention Is All You Need", 2017), the Transformer unlocked massive parallel processing capabilities.
(End-to-end ML pipeline: Preprocessing → Vectorization → Training → Prediction)
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.naive_bayes import MultinomialNB
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
import numpy as np
# Training data: [text, category]
data = [
("Python tutorial for beginners", "tech"),
("Machine learning course online", "tech"),
("Best laptops for programming", "tech"),
("How to train neural networks", "tech"),
("Championship football match highlights", "sports"),
("World cup soccer finals", "sports"),
("Basketball playoffs schedule", "sports"),
("Tennis grand slam results", "sports"),
("Stock market analysis today", "finance"),
("Investment strategies for 2024", "finance"),
("Cryptocurrency trading tips", "finance"),
("Banking sector quarterly report", "finance"),
]
texts = [d[0] for d in data]
labels = [d[1] for d in data]
# Step 1: Vectorization (TF-IDF)
vectorizer = TfidfVectorizer(stop_words='english')
X = vectorizer.fit_transform(texts)
# Step 2: Train classifier (Naive Bayes)
classifier = MultinomialNB()
classifier.fit(X, labels)
print("🤖 Text Classification Pipeline")
print("="*50)
print(f"Training samples: {len(texts)}")
print(f"Categories: {list(set(labels))}")
print(f"Vocabulary size: {len(vectorizer.vocabulary_)}\n")
# Step 3: Predict new texts
test_texts = [
"Deep learning frameworks comparison",
"Premier league football scores",
"How to invest in mutual funds",
"New GPU for gaming and AI"
]
print("📊 Predictions on New Texts:\n")
for text in test_texts:
vec = vectorizer.transform([text])
pred = classifier.predict(vec)[0]
probs = classifier.predict_proba(vec)[0]
conf = max(probs) * 100
print(f" '{text}'")
print(f" → Category: {pred.upper()} (confidence: {conf:.0f}%)\n")
① Data Processing
② Feature Engineering
③ Semantic Representation
④ Deep Learning Architectures
💡 Key Takeaway: There is no ML without clean data. There is no comprehension without embeddings. Modern AI is the culmination of this entire pipeline.