Fix char_trie to store all token ids
This commit is contained in:
@@ -1,5 +1,4 @@
|
|||||||
import torch
|
import torch
|
||||||
import sys
|
|
||||||
from transformers import LogitsProcessor
|
from transformers import LogitsProcessor
|
||||||
from transformers import AutoTokenizer
|
from transformers import AutoTokenizer
|
||||||
from xml_schema_validator._rs import XmlLogitsProcessorCore
|
from xml_schema_validator._rs import XmlLogitsProcessorCore
|
||||||
@@ -78,20 +77,6 @@ class XmlLogitsProcessor(LogitsProcessor):
|
|||||||
|
|
||||||
# Find the last occurrence of the assistant start marker
|
# Find the last occurrence of the assistant start marker
|
||||||
last_marker_pos = full_text.rfind(self.assistant_start_marker)
|
last_marker_pos = full_text.rfind(self.assistant_start_marker)
|
||||||
|
|
||||||
if last_marker_pos == -1:
|
|
||||||
# If primary marker not found, try looking for a second common marker as fallback
|
|
||||||
fallback_markers = ["<|assistant|>", "\nAssistant: ", "\nA: "]
|
|
||||||
for fallback in fallback_markers:
|
|
||||||
last_marker_pos = full_text.rfind(fallback)
|
|
||||||
if last_marker_pos != -1:
|
|
||||||
# Found a fallback marker
|
|
||||||
self.assistant_start_marker = fallback # Update for future calls
|
|
||||||
break
|
|
||||||
|
|
||||||
# If still not found, we can't determine where the assistant content starts
|
|
||||||
if last_marker_pos == -1:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Extract the assistant's response by taking text after the marker plus its length
|
# Extract the assistant's response by taking text after the marker plus its length
|
||||||
start_pos = last_marker_pos + len(self.assistant_start_marker)
|
start_pos = last_marker_pos + len(self.assistant_start_marker)
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ use rayon::prelude::*;
|
|||||||
struct CharTrieNode {
|
struct CharTrieNode {
|
||||||
// Store character and node pairs, keep sorted for binary search
|
// Store character and node pairs, keep sorted for binary search
|
||||||
children: Vec<(char, CharTrieNode)>,
|
children: Vec<(char, CharTrieNode)>,
|
||||||
// Store token IDs that are valid at this point
|
// Store token IDs that are valid at this point - CHANGED to Vec<u32>
|
||||||
token_id: Option<Arc<Py<PyAny>>>,
|
token_ids: Vec<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CharTrieNode {
|
impl CharTrieNode {
|
||||||
@@ -24,15 +24,18 @@ impl CharTrieNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a token id to this node
|
// Add a token id to this node - CHANGED to handle Vec<u32>
|
||||||
fn add_token(&mut self, token_id: Arc<Py<PyAny>>) {
|
fn add_token(&mut self, token_id: u32) {
|
||||||
self.token_id = Some(token_id);
|
// Only add if not already present (avoid duplicates)
|
||||||
|
if !self.token_ids.contains(&token_id) {
|
||||||
|
self.token_ids.push(token_id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_invalid_tokens(
|
fn find_invalid_tokens(
|
||||||
&self,
|
&self,
|
||||||
xml_validator: &XmlSchemaValidator,
|
xml_validator: &XmlSchemaValidator,
|
||||||
) -> Vec<Arc<Py<PyAny>>> {
|
) -> Vec<u32> {
|
||||||
let res = self
|
let res = self
|
||||||
.children
|
.children
|
||||||
.iter()
|
.iter()
|
||||||
@@ -55,7 +58,7 @@ impl CharTrieNode {
|
|||||||
fn find_invalid_tokens_parallel(
|
fn find_invalid_tokens_parallel(
|
||||||
&self,
|
&self,
|
||||||
xml_validator: &XmlSchemaValidator,
|
xml_validator: &XmlSchemaValidator,
|
||||||
) -> Vec<Arc<Py<PyAny>>> {
|
) -> Vec<u32> {
|
||||||
// Convert children to a parallel iterator
|
// Convert children to a parallel iterator
|
||||||
self.children
|
self.children
|
||||||
.par_iter() // Use parallel iterator from rayon
|
.par_iter() // Use parallel iterator from rayon
|
||||||
@@ -76,11 +79,13 @@ impl CharTrieNode {
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn all_tokens(&self) -> Vec<Arc<Py<PyAny>>> {
|
// CHANGED to handle Vec<u32>
|
||||||
|
fn all_tokens(&self) -> Vec<u32> {
|
||||||
let mut tokens = Vec::new();
|
let mut tokens = Vec::new();
|
||||||
if let Some(token_id) = &self.token_id {
|
// Add all token IDs stored at this node
|
||||||
tokens.push(token_id.clone());
|
tokens.extend_from_slice(&self.token_ids);
|
||||||
}
|
|
||||||
|
// Recursively collect token IDs from all children
|
||||||
for (_, child) in &self.children {
|
for (_, child) in &self.children {
|
||||||
tokens.extend(child.all_tokens());
|
tokens.extend(child.all_tokens());
|
||||||
}
|
}
|
||||||
@@ -96,7 +101,7 @@ pub struct CharTrie {
|
|||||||
|
|
||||||
impl CharTrie {
|
impl CharTrie {
|
||||||
// Insert a token's character sequence into the trie
|
// Insert a token's character sequence into the trie
|
||||||
pub fn insert(&mut self, token_text: &str, token_id: Py<PyAny>) {
|
pub fn insert(&mut self, token_text: &str, token_id: u32) {
|
||||||
let mut current = &mut self.root;
|
let mut current = &mut self.root;
|
||||||
|
|
||||||
// Add each character in the token text
|
// Add each character in the token text
|
||||||
@@ -105,15 +110,20 @@ impl CharTrie {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Mark this node as representing token_id
|
// Mark this node as representing token_id
|
||||||
current.add_token(Arc::new(token_id));
|
current.add_token(token_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find all tokens that could be invalid given the current XML state
|
// Find all tokens that could be invalid given the current XML state
|
||||||
pub fn find_invalid_tokens(
|
pub fn find_invalid_tokens(
|
||||||
&self,
|
&self,
|
||||||
xml_validator: &XmlSchemaValidator,
|
xml_validator: &XmlSchemaValidator,
|
||||||
) -> Vec<Arc<Py<PyAny>>> {
|
) -> Vec<u32> {
|
||||||
// Use the parallel version starting at the root
|
// Use the parallel version starting at the root
|
||||||
self.root.find_invalid_tokens_parallel(xml_validator)
|
self.root.find_invalid_tokens_parallel(xml_validator)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NEW: Return all token IDs registered in the trie
|
||||||
|
pub fn all_registered_tokens(&self) -> Vec<u32> {
|
||||||
|
self.root.all_tokens()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -8,6 +8,7 @@ use pyo3::types::PyDict;
|
|||||||
pub struct XmlLogitsProcessorCore {
|
pub struct XmlLogitsProcessorCore {
|
||||||
xml_schema_validator: XmlSchemaValidator,
|
xml_schema_validator: XmlSchemaValidator,
|
||||||
trie: char_trie::CharTrie,
|
trie: char_trie::CharTrie,
|
||||||
|
tokens: Vec<(u32, String)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pymethods]
|
#[pymethods]
|
||||||
@@ -18,17 +19,21 @@ impl XmlLogitsProcessorCore {
|
|||||||
Ok(xml_schema_validator) => xml_schema_validator,
|
Ok(xml_schema_validator) => xml_schema_validator,
|
||||||
Err(e) => return Err(pyo3::exceptions::PyValueError::new_err(e.to_string())),
|
Err(e) => return Err(pyo3::exceptions::PyValueError::new_err(e.to_string())),
|
||||||
};
|
};
|
||||||
let tokens: Vec<(Py<PyAny>, String)> = tokens
|
let tokens: Vec<(u32, String)> = tokens
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(id, value)| (id.unbind(), value.unbind().to_string()))
|
.map(|(id, value)| {
|
||||||
|
let id: u32 = id.extract().unwrap();
|
||||||
|
(id, value.unbind().to_string())
|
||||||
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let mut trie = char_trie::CharTrie::default();
|
let mut trie = char_trie::CharTrie::default();
|
||||||
for (token_id, token_text) in tokens.iter() {
|
for (token_id, token_text) in tokens.iter() {
|
||||||
trie.insert(token_text, token_id.clone_ref(py));
|
trie.insert(token_text, token_id.clone());
|
||||||
}
|
}
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
xml_schema_validator,
|
xml_schema_validator,
|
||||||
trie,
|
trie,
|
||||||
|
tokens,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,13 +44,10 @@ impl XmlLogitsProcessorCore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get a list of tokens that would lead to invalid XML
|
/// Get a list of tokens that would lead to invalid XML
|
||||||
fn get_invalid_tokens(&mut self, py: Python<'_>) -> PyResult<Vec<PyObject>> {
|
fn get_invalid_tokens(&mut self, py: Python<'_>) -> PyResult<Vec<u32>> {
|
||||||
Ok(self
|
Ok(self
|
||||||
.trie
|
.trie
|
||||||
.find_invalid_tokens(&self.xml_schema_validator)
|
.find_invalid_tokens(&self.xml_schema_validator))
|
||||||
.iter()
|
|
||||||
.map(|token_id| token_id.clone_ref(py))
|
|
||||||
.collect())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if the validator has reached the end of the XML
|
/// Check if the validator has reached the end of the XML
|
||||||
|
|||||||
@@ -49,6 +49,9 @@ pub enum Token {
|
|||||||
|
|
||||||
impl Token {
|
impl Token {
|
||||||
pub fn append(self, c: char) -> Vec<Token> {
|
pub fn append(self, c: char) -> Vec<Token> {
|
||||||
|
if !c.is_ascii_graphic() && ! c.is_ascii_whitespace() {
|
||||||
|
return vec![];
|
||||||
|
}
|
||||||
match self {
|
match self {
|
||||||
Token::AttributeEquals(attribute_equals) => attribute_equals.append(c),
|
Token::AttributeEquals(attribute_equals) => attribute_equals.append(c),
|
||||||
Token::AttributeName(attribute_name) => attribute_name.append(c),
|
Token::AttributeName(attribute_name) => attribute_name.append(c),
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ from xml_schema_validator import XmlLogitsProcessor
|
|||||||
import os
|
import os
|
||||||
import torch
|
import torch
|
||||||
|
|
||||||
model_path = "../../model"
|
model_path = "/root/models/current"
|
||||||
api_token = os.environ["SIA_HF_API_KEY"]
|
api_token = os.environ["SIA_HF_API_KEY"]
|
||||||
|
|
||||||
xml_schema_actions = open("example_schema.xsd").read()
|
xml_schema_actions = open("example_schema.xsd").read()
|
||||||
@@ -58,12 +58,32 @@ def test_token_masking():
|
|||||||
|
|
||||||
tokenizer = AutoTokenizer.from_pretrained(model_path, token=api_token)
|
tokenizer = AutoTokenizer.from_pretrained(model_path, token=api_token)
|
||||||
processor = XmlLogitsProcessor(tokenizer, xml_schema_actions)
|
processor = XmlLogitsProcessor(tokenizer, xml_schema_actions)
|
||||||
|
|
||||||
# Process empty input to set prompt length
|
# Process empty input to set prompt length
|
||||||
input_ids = torch.tensor([tokenizer.encode("")])
|
input_ids = torch.tensor([tokenizer.encode("")])
|
||||||
scores = torch.ones((1, len(tokenizer))) # All tokens have equal probability
|
scores = torch.ones((1, len(tokenizer))) # All tokens have equal probability
|
||||||
processed_scores = processor(input_ids, scores)
|
processed_scores = processor(input_ids, scores)
|
||||||
|
|
||||||
|
# Check if '<' is the only allowed token
|
||||||
|
less_than_token = tokenizer.encode("<", add_special_tokens=False)[0]
|
||||||
|
|
||||||
|
# Count how many tokens have scores not equal to -inf
|
||||||
|
valid_tokens = (processed_scores[0] > -float('inf')).sum().item()
|
||||||
|
|
||||||
|
# Check if the '<' token is allowed (not masked)
|
||||||
|
is_less_than_allowed = processed_scores[0, less_than_token] > -float('inf')
|
||||||
|
|
||||||
|
print(f"Number of allowed tokens: {valid_tokens}")
|
||||||
|
print(f"Is '<' token allowed: {is_less_than_allowed}")
|
||||||
|
|
||||||
|
# Always print the first 10 allowed tokens
|
||||||
|
allowed_token_ids = torch.where(processed_scores[0] > -float('inf'))[0].tolist()
|
||||||
|
# Take only the first 10 tokens (or all if less than 10)
|
||||||
|
allowed_token_ids_sample = allowed_token_ids[:min(10, len(allowed_token_ids))]
|
||||||
|
allowed_tokens = [tokenizer.decode([token_id]) for token_id in allowed_token_ids_sample]
|
||||||
|
print(f"First 10 allowed token IDs: {allowed_token_ids_sample}")
|
||||||
|
print(f"First 10 allowed tokens: {allowed_tokens}")
|
||||||
|
|
||||||
# Process valid continuation
|
# Process valid continuation
|
||||||
input_ids = torch.tensor([tokenizer.encode("<reasoning>")])
|
input_ids = torch.tensor([tokenizer.encode("<reasoning>")])
|
||||||
scores = torch.ones((1, len(tokenizer))) # All tokens have equal probability
|
scores = torch.ones((1, len(tokenizer))) # All tokens have equal probability
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from aiohttp import web
|
from aiohttp import web, WSMsgType
|
||||||
|
|
||||||
from ..web_agent import WebAgent
|
from ..web_agent import WebAgent
|
||||||
from .util import wrap_async
|
from .util import wrap_async
|
||||||
|
|||||||
Reference in New Issue
Block a user