myanmar-ghost / augmentation /synonym_replacer.py
amkyawdev's picture
Add source code
cfb5e7f verified
Raw
History Blame Contribute Delete
7.84 kB
"""Synonym replacement for adversarial data augmentation.
Replaces words with synonyms to create challenging training examples
that help improve model robustness.
"""
import random
from pathlib import Path
from typing import Dict, List, Optional, Set, Tuple
import yaml
class MyanmarSynonymReplacer:
"""Replace words with Myanmar synonyms for data augmentation."""
# Basic synonym dictionary for Myanmar
SYNONYMS = {
"ကျေးဇူး": ["ခန့်ညား", "ဂုဏ်ပြု", "အားထုတ်"],
"ပါး": ["များ", "အရမ်း", "အလွန်"],
"သိပ်": ["အရမ်း", "များစွာ", "ပါး"],
"ကောင်း": ["မွန်", "သန့်", "စင်"],
"ဆိုး": ["မကောင်း", "ယုတ်", "ညံ့"],
"ပျော်": ["ရွှင်", "ပီတိ", "မင်္ဂလာ"],
"စိတ်မကောင်း": ["စိတ်ဓာတ်ကျ", "ဝမ်းနည်း", "ဒေါသ"],
"လာ": ["ရောက်", "သွား", "ပို့"],
"သွား": ["သွား", "ထွက်", "မောင်း"],
"ပေး": ["ပေးဆောင်", "မွေးစား", "အပ်"],
"ယူ": ["ရ", "လက်ခံ", "ရှာ"],
"မှန်": ["ဟုတ်", "ကျိ", "သင့်"],
"မှား": ["မဟုတ်", "အမှား", "ယွင်း"],
}
def __init__(
self,
synonym_file: Optional[str] = None,
seed: int = 42,
):
"""
Args:
synonym_file: Path to YAML file with custom synonyms
seed: Random seed for reproducibility
"""
random.seed(seed)
self.synonyms = dict(self.SYNONYMS)
if synonym_file and Path(synonym_file).exists():
self._load_synonyms(synonym_file)
def _load_synonyms(self, path: str) -> None:
"""Load synonyms from YAML file."""
with open(path, "r", encoding="utf-8") as f:
custom = yaml.safe_load(f)
if custom:
self.synonyms.update(custom)
def get_synonyms(self, word: str) -> List[str]:
"""Get synonyms for a word."""
return self.synonyms.get(word, [])
def replace_word(self, word: str) -> Tuple[str, bool]:
"""Replace a word with a synonym.
Args:
word: Word to replace
Returns:
(replaced_word, was_replaced)
"""
synonyms = self.get_synonyms(word)
if synonyms:
replacement = random.choice(synonyms)
return replacement, True
return word, False
def augment_text(
self,
text: str,
replace_prob: float = 0.3,
max_replacements: int = 3,
) -> Tuple[str, List[Tuple[str, str]]]:
"""Augment text by replacing words with synonyms.
Args:
text: Myanmar text
replace_prob: Probability of replacing each synonym word
max_replacements: Maximum number of replacements
Returns:
(augmented_text, list_of_replacements)
"""
words = text.split()
replacements = []
augmented_words = []
num_replaced = 0
for word in words:
if num_replaced >= max_replacements:
augmented_words.append(word)
continue
if word in self.synonyms and random.random() < replace_prob:
new_word, replaced = self.replace_word(word)
if replaced:
augmented_words.append(new_word)
replacements.append((word, new_word))
num_replaced += 1
else:
augmented_words.append(word)
else:
augmented_words.append(word)
return " ".join(augmented_words), replacements
def augment_dataset(
self,
samples: List[Dict],
replace_prob: float = 0.3,
max_replacements: int = 3,
n_augmentations: int = 2,
) -> List[Dict]:
"""Augment entire dataset.
Args:
samples: List of sample dictionaries
replace_prob: Probability of replacing each word
max_replacements: Maximum replacements per text
n_augmentations: Number of augmentations per sample
Returns:
List of augmented samples
"""
augmented = []
for sample in samples:
text = sample.get("text", "")
for i in range(n_augmentations):
aug_text, replacements = self.augment_text(
text,
replace_prob=replace_prob,
max_replacements=max_replacements,
)
if replacements: # Only add if something was replaced
aug_sample = sample.copy()
aug_sample["text"] = aug_text
aug_sample["augmentation_id"] = i
aug_sample["replacements"] = replacements
aug_sample["is_augmented"] = True
augmented.append(aug_sample)
return augmented
def get_replacement_stats(self) -> Dict:
"""Get statistics about synonym coverage."""
total_words = sum(len(syns) for syns in self.synonyms.values())
return {
"num_synonym_groups": len(self.synonyms),
"total_synonyms": total_words,
"avg_synonyms_per_word": total_words / len(self.synonyms) if self.synonyms else 0,
}
class ContextualSynonymReplacer:
"""Synonym replacer that considers context."""
def __init__(self):
# Context-dependent synonyms
self.CONTEXT_SYNONYMS = {
"formal": {
"ကျေးဇူး": ["ဂုဏ်ပြုမှတ်ရှိပါ", "အထူးပင်ကျေးဇူးတင်ပါ"],
"သိပ်": ["အလွန်", "အထူးသဖြင့်"],
},
"informal": {
"ကျေးဇူး": ["ခန့်ညား", "ကျေးဇူးလည်းပါ"],
"ပါး": ["ပို", "အရမ်း"],
},
}
def augment_by_context(
self,
text: str,
context: str = "formal",
) -> str:
"""Augment text using context-specific synonyms.
Args:
text: Myanmar text
context: Context type ("formal" or "informal")
Returns:
Augmented text
"""
context_syns = self.CONTEXT_SYNONYMS.get(context, {})
for word, synonyms in context_syns.items():
if word in text:
replacement = random.choice(synonyms)
text = text.replace(word, replacement, 1)
return text
def create_synonym_replacer(
synonym_file: Optional[str] = None,
) -> MyanmarSynonymReplacer:
"""Factory function to create synonym replacer."""
return MyanmarSynonymReplacer(synonym_file=synonym_file)
if __name__ == "__main__":
replacer = create_synonym_replacer()
test_text = "ကျေးဇူးပါးသိပ်ကောင်းတယ်"
for i in range(3):
aug, replacements = replacer.augment_text(test_text)
print(f"Original: {test_text}")
print(f"Augmented: {aug}")
print(f"Replacements: {replacements}")
print()