File size: 4,334 Bytes
be99550 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | // π [BioPhys 5.0 λ€μ΄ν°λΈ BPE λ°μ΄νΈνμ΄ ν ν¬λμ΄μ μμ§] (src/native_bpe_tokenizer.rs)
// μΈλΆ νμ΄μ¬ μμ‘΄μ± 0%! μμμ νκ΅μ΄/μμ΄/κΈ°νΈ ν
μ€νΈλ₯Ό BPE λ°μ΄νΈ λ¨μλ‘ λΆμ λ° μ μ ID μΈμ½λ©/λμ½λ©
use std::collections::HashMap;
pub struct NativeBpeTokenizer {
pub token_to_id: HashMap<String, usize>,
pub id_to_token: Vec<String>,
pub byte_tokens: Vec<String>,
}
impl NativeBpeTokenizer {
pub fn new() -> Self {
let mut token_to_id = HashMap::new();
let mut id_to_token = Vec::new();
// 1. νΉμ ν ν° λ±λ‘
let special_tokens = vec!["<PAD>", "<BOS>", "<EOS>", "<UNK>", "<MASK>"];
for &tok in &special_tokens {
let id = id_to_token.len();
id_to_token.push(tok.to_string());
token_to_id.insert(tok.to_string(), id);
}
// 2. 256κ° κΈ°λ³Έ λ°μ΄νΈ ν ν° λ±λ‘ (0x00 ~ 0xFF)
let mut byte_tokens = Vec::new();
for b in 0..=255u8 {
let tok_str = format!("<0x{:02X}>", b);
let id = id_to_token.len();
id_to_token.push(tok_str.clone());
token_to_id.insert(tok_str.clone(), id);
byte_tokens.push(tok_str);
}
// 3. μ£Όμ νκ΅μ΄ μμ λ° κΈ°μ ν€μλ μλΈμλ λ±λ‘
let common_korean_subwords = vec![
"μΈκ³΅μ§λ₯", "λΈλν", "μ¬κ±΄μ", "μ§νμ ", "μ€νμ΄νΉ", "μμν", "λ΄λ°",
"κ°μ€μΉ", "μμΆ", "μ΄μ μ§μ°", "μμ§", "Rust", "Svelte", "Tauri",
"νκ΅μ΄", "λ¬Έλ²", "νμμ±", "νΉμ΄μ ", "물리", "λμν", "μ
λλ€", "ν©λλ€",
"μΌλ‘", "μμ", "μ", "μ", "λ₯Ό", "μ΄", "κ°", "μ", "λ", "κ³Ό", "μ"
];
for &word in &common_korean_subwords {
let id = id_to_token.len();
id_to_token.push(word.to_string());
token_to_id.insert(word.to_string(), id);
}
NativeBpeTokenizer {
token_to_id,
id_to_token,
byte_tokens,
}
}
/// [ν
μ€νΈ β μ κ· BPE ν ν° ID λ²‘ν° μΈμ½λ©]
pub fn encode(&self, text: &str) -> Vec<usize> {
let mut token_ids = Vec::new();
token_ids.push(1); // <BOS>
let mut chars = text.chars().peekable();
let mut current_buf = String::new();
while let Some(c) = chars.next() {
current_buf.push(c);
// λ±λ‘λ μλΈμλμΈμ§ νμ
if let Some(&id) = self.token_to_id.get(¤t_buf) {
token_ids.push(id);
current_buf.clear();
} else if c.is_whitespace() || chars.peek().is_none() {
// 곡백 λλ λ¨μ΄ λμμ λ°μ΄νΈ λ¨μ ν΄λ°±
for b in current_buf.as_bytes() {
let byte_tok = format!("<0x{:02X}>", b);
let id = self.token_to_id.get(&byte_tok).copied().unwrap_or(3); // <UNK>
token_ids.push(id);
}
current_buf.clear();
}
}
token_ids.push(2); // <EOS>
token_ids
}
/// [ν ν° ID λ²‘ν° β μ¬λμ΄ μ½μ μ μλ UTF-8 ν
μ€νΈ λμ½λ©]
pub fn decode(&self, token_ids: &[usize]) -> String {
let mut byte_buffer = Vec::new();
let mut decoded_text = String::new();
for &id in token_ids {
if id >= self.id_to_token.len() { continue; }
let tok_str = &self.id_to_token[id];
if tok_str == "<BOS>" || tok_str == "<EOS>" || tok_str == "<PAD>" {
continue;
}
if tok_str.starts_with("<0x") && tok_str.ends_with(">") {
if let Ok(b) = u8::from_str_radix(&tok_str[3..5], 16) {
byte_buffer.push(b);
}
} else {
if !byte_buffer.is_empty() {
decoded_text.push_str(&String::from_utf8_lossy(&byte_buffer));
byte_buffer.clear();
}
decoded_text.push_str(tok_str);
}
}
if !byte_buffer.is_empty() {
decoded_text.push_str(&String::from_utf8_lossy(&byte_buffer));
}
decoded_text
}
}
|