BioPhys-Neural-Agent / src /native_bpe_tokenizer.rs
minseok
🌌 Release BioPhys 6.0 Grand Master: 16GB (14.89GB) Gemma-4 100% Devour, Ecosystem Evolution, Solar MoE, SNN Autoregressive SDK, Dynamic PhaseVM
be99550
Raw
History Blame Contribute Delete
4.33 kB
// 🌌 [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(&current_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
}
}