tokenizers 自定义快速预分词器,通过PyO3移植到Python,

ltqd579y  于 4个月前  发布在  Python
关注(0)|答案(2)|浏览(107)

你好!非常感谢在这个库中所做的所有工作!
我有兴趣将一个自定义的预分词器(作为Python类)通过PyO3移动。以下是一个示例:

use tokenizers::tokenizer::{normalizer::Range, PreTokenizedString, PreTokenizer, Result};
use tokenizers::utils::macro_rules_attribute;
use tokenizers::impl_serde_type;

fn get_example_ranges(input: &str)  -> Result<Vec<(usize, usize)>> {
    Ok(vec![(0, 2)])
}

#[derive(Clone, Debug, PartialEq, Eq)]
#[macro_rules_attribute(impl_serde_type!)]
pub struct CustomPreTokenizer;

impl Default for CustomPreTokenizer {
    fn default() -> Self {
        Self
    }
}

impl PreTokenizer for CustomPreTokenizer {
    fn pre_tokenize(&self, pretokenized: &mut PreTokenizedString) -> Result<()> {
        pretokenized.split(|_, normalized| {
            let ranges = get_example_ranges(normalized.get())?;
            Ok(ranges
                .into_iter()
                .map(|item| {
                    normalized
                        .slice(Range::Normalized(item.0..item.1))
                        .expect("Invalid input")
                })
                .collect::<Vec<_>>())
            })
    }
}

我现在对在Python脚本中使用这个感兴趣,在查看库中提供的绑定代码后,我尝试实现了以下内容:

#[pyclass(extends=PyPreTokenizer, name = "CustomPreTokenizer")]
pub struct PyCustomPreTokenizer {}
#[pymethods]
impl PyCustomPreTokenizer {
    #[new]
    #[pyo3(text_signature = "(self)")]
    fn new() -> (Self, PyPreTokenizer) {
        (PyCustomPreTokenizer {}, CustomPreTokenizer {}.into())
    }
}

然而,我似乎无法导入/调用在以下文件中描述的PyPreTokenizer结构:
tokenizers/bindings/python/src/pre_tokenizers.rs
第38行 fdd26ba
| | pubstructPyPreTokenizer{ |
有没有办法在不重新实现PyPreTokenizer结构的功能的情况下实现这一点?例如,有一种方法可以调用 use tokenizers_pyo3::PyPreTokenizer 吗?

m1m5dgzv

m1m5dgzv1#

嘿!你添加了这个:

#[pymodule]
pub fn pre_tokenizers(m: &Bound<'_, PyModule>) -> PyResult<()> {
    m.add_class::<PyPreTokenizer>()?;
    m.add_class::<PyByteLevel>()?;
    m.add_class::<PyWhitespace>()?;
    m.add_class::<PyWhitespaceSplit>()?;
    m.add_class::<PySplit>()?;
    m.add_class::<PyBertPreTokenizer>()?;
    m.add_class::<PyMetaspace>()?;
    m.add_class::<PyCharDelimiterSplit>()?;
    m.add_class::<PyPunctuation>()?;
+   m.add_class::<PyCustomPreTokenizer>()?;
    m.add_class::<PySequence>()?;
    m.add_class::<PyDigits>()?;
    m.add_class::<PyUnicodeScripts>()?;
    Ok(())
}
trnvg8h3

trnvg8h32#

你好,Arthur!感谢你查看这个问题。
目标是创建一个单独的项目。如果我没弄错的话,你建议的方法需要我fork tokenizers库,然后分发带有自定义结构的版本,对吧?这对用户来说非常不方便,因为如果有其他功能被添加,他们必须等待我更新代码到库的最新版本。
我想在这里提出一个稍微不同的建议。与其像下面的例子那样将自定义组件的逻辑限制在Python实现中,我建议也在一个单独的crate(即PyPreTokenizer、PyNormalizer、PyModel、PyTrainer等)中公开pyo3类。
tokenizers/bindings/python/examples/custom_components.py
第11行到第16行
| | classJiebaPreTokenizer: |
| | defjieba_split(self, i: int, normalized_string: NormalizedString) ->List[NormalizedString]: |
| | splits= [] |
| | #我们需要调用str(normalized_string),因为jieba期望的是一个字符串,而不是一个NormalizedString |
| | fortoken, start, stopinjieba.tokenize(str(normalized_string)): |
如果有一个类似于tokenizers_pyo3的crate可用,用户可以直接在Rust中创建与库和其他基于它的模块兼容的模块(例如transformers)。这个功能是否会被社区认为是有用的?如果是的话,我可以在几周内考虑实现这个功能。

相关问题