phonsobon commited on
Commit
b6cc5b8
Β·
verified Β·
1 Parent(s): 1311771

Upload README.md with huggingface_hub

Browse files
Files changed (1) hide show
  1. README.md +149 -0
README.md ADDED
@@ -0,0 +1,149 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ language: km
3
+ license: apache-2.0
4
+ tags:
5
+ - khmer
6
+ - autocomplete
7
+ - lstm
8
+ - pytorch
9
+ - nlp
10
+ ---
11
+
12
+ # Khmer LSTM Autocomplete (General)
13
+
14
+ An LSTM next-word autocomplete model for Khmer text, fine-tuned on an
15
+ expanded dataset for broader, general-purpose coverage. This is a
16
+ continuation of [`phonsobon/khmer_auto_completed`](https://huggingface.co/phonsobon/khmer_auto_completed),
17
+ further trained on [`phonsobon/khmer_auto_complete_v4`](https://huggingface.co/datasets/phonsobon/khmer_auto_complete_v4).
18
+
19
+ ## Model details
20
+
21
+ - Architecture: Embedding β†’ single-layer LSTM β†’ Linear (next-word classifier)
22
+ - Embedding dim: 128
23
+ - Hidden dim: 256
24
+ - Context window: 1 word(s)
25
+ - Vocabulary size: 1022 (extended from 621)
26
+ - Tokenizer: [khmercut](https://pypi.org/project/khmercut/)
27
+
28
+ ## Training data
29
+
30
+ - `phonsobon/khmer_auto_complete`
31
+ - `phonsobon/khmer_auto_complete_v3`
32
+ - `phonsobon/khmer_auto_complete_v4` (this fine-tuning round)
33
+
34
+ ## Usage
35
+
36
+ ```python
37
+ import os
38
+ import pickle
39
+ import torch
40
+ import torch.nn as nn
41
+
42
+ try:
43
+ from khmercut import tokenize
44
+ except ImportError:
45
+ os.system("pip install khmercut")
46
+ from khmercut import tokenize
47
+
48
+ try:
49
+ from huggingface_hub import hf_hub_download
50
+ except ImportError:
51
+ os.system("pip install huggingface_hub")
52
+ from huggingface_hub import hf_hub_download
53
+
54
+ # ── 1. Download files from HuggingFace ──────────────────────────────────────
55
+ print("Downloading model and vocab from HuggingFace...")
56
+ model_path = hf_hub_download("phonsobon/khmer_auto_completed_general", "khmer_lstm_autocomplete_best.pth")
57
+ vocab_path = hf_hub_download("phonsobon/khmer_auto_completed_general", "vocab_mapping.pkl")
58
+
59
+ # ── 2. Load vocabulary ───────────────────────────────────────────────────────
60
+ with open(vocab_path, "rb") as f:
61
+ vocab_data = pickle.load(f)
62
+
63
+ word_to_idx = vocab_data["word_to_idx"]
64
+ idx_to_word = vocab_data["idx_to_word"]
65
+ vocab_size = len(vocab_data["vocab"])
66
+ print(f"Vocabulary size: {vocab_size} words")
67
+
68
+ # ── 3. Define model ──────────────────────────────────────────────────────────
69
+ class KhmerLSTMAutocomplete(nn.Module):
70
+ def __init__(self, vocab_size, embedding_dim=128, hidden_dim=256):
71
+ super().__init__()
72
+ self.embedding = nn.Embedding(vocab_size, embedding_dim, padding_idx=0)
73
+ self.lstm = nn.LSTM(embedding_dim, hidden_dim, batch_first=True)
74
+ self.fc = nn.Linear(hidden_dim, vocab_size)
75
+
76
+ def forward(self, x):
77
+ out, _ = self.lstm(self.embedding(x))
78
+ return self.fc(out[:, -1, :])
79
+
80
+ # ── 4. Load model weights ────────────────────────────────────────────────────
81
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
82
+ print(f"Using device: {device}")
83
+
84
+ model = KhmerLSTMAutocomplete(vocab_size)
85
+ model.load_state_dict(torch.load(model_path, map_location=device))
86
+ model.to(device)
87
+ model.eval()
88
+ print("Model loaded successfully!\n")
89
+
90
+ # ── 5. Autocomplete function ─────────────────────────────────────────────────
91
+ WINDOW_SIZE = 1
92
+
93
+ def get_autocomplete_suggestions(input_text, top_k=3):
94
+ tokens = tokenize(input_text)
95
+ tokens = [t.strip() for t in tokens if t.strip() != ""]
96
+
97
+ if len(tokens) < WINDOW_SIZE:
98
+ tokens = ["<PAD>"] * (WINDOW_SIZE - len(tokens)) + tokens
99
+ else:
100
+ tokens = tokens[-WINDOW_SIZE:]
101
+
102
+ input_idxs = [word_to_idx.get(w, word_to_idx["<UNK>"]) for w in tokens]
103
+ input_tensor = torch.tensor([input_idxs], dtype=torch.long).to(device)
104
+
105
+ with torch.no_grad():
106
+ logits = model(input_tensor)
107
+ probs = torch.softmax(logits, dim=-1).squeeze(0)
108
+ top_probs, top_idxs = torch.topk(probs, top_k)
109
+
110
+ print(f"Input: '{input_text}'")
111
+ print("Suggestions:")
112
+ has_suggestions = False
113
+ for i in range(top_k):
114
+ word = idx_to_word[top_idxs[i].item()]
115
+ prob_val = top_probs[i].item() * 100
116
+ if word not in ["<PAD>", "<UNK>"]:
117
+ suggestion = f"{input_text.strip()}{word}".strip()
118
+ print(f" {i+1}. {suggestion} ({prob_val:.1f}%)")
119
+ has_suggestions = True
120
+ if not has_suggestions:
121
+ print("No relevant suggestions found.")
122
+ print()
123
+
124
+ # ── 6. Test autocomplete ─────────────────────────────────────────────────────
125
+ print("=" * 50)
126
+ print(" KHMER AUTOCOMPLETE TEST (GENERAL MODEL)")
127
+ print("=" * 50 + "\n")
128
+
129
+ test_inputs = [
130
+ "សូម",
131
+ "αžŸαžΌαž˜αž―αž€αž§αžαŸ’αžαž˜αžšαžŠαŸ’αž‹αž˜αž“αŸ’αžαŸ’αžšαžΈαž˜αŸαžαŸ’αžαžΆ",
132
+ "αžŸαžΌαž˜αž›αŸ„αž€αžŸαŸ’αžšαžΈαž”αŸ’αžšαž’αžΆαž“",
133
+ "αž’αžšαž‚αž»αžŽ",
134
+ "αžαŸ’αž‰αž»αŸ†",
135
+ ]
136
+
137
+ for text in test_inputs:
138
+ get_autocomplete_suggestions(text, top_k=3)
139
+
140
+ print("=" * 50)
141
+ print("Testing complete!")
142
+ print("=" * 50)
143
+ ```
144
+
145
+ ## Training
146
+
147
+ Fine-tuned for 5 epochs with Adam (lr=0.001), batch size 256,
148
+ starting from the weights of `phonsobon/khmer_auto_completed` with the vocabulary/embedding/output
149
+ layer extended to cover new words from `phonsobon/khmer_auto_complete_v4`. Final validation loss: {best_val_loss:.4f}.