代码之家  ›  专栏  ›  技术社区  ›  alvas

如何使用交叉编码器与Huggingface变压器管道?

  •  0
  • alvas  · 技术社区  · 3 年前

    有一套关于拥抱脸轮毂的模型来自 sentence_transformers 库,例如。 https://huggingface.co/cross-encoder/mmarco-mMiniLMv2-L12-H384-v1

    建议的用法示例如下:

    # Using sentence_transformers
    
    from sentence_transformers import CrossEncoder
    
    model_name = 'cross-encoder/mmarco-mMiniLMv2-L12-H384-v1'
    model = CrossEncoder(model_name)
    scores = model.predict([
      ['How many people live in Berlin?', 'How many people live in Berlin?'], 
      ['Berlin has a population of 3,520,031 registered inhabitants in an area of 891.82 square kilometers.', 'New York City is famous for the Metropolitan Museum of Art.']
    ])
    scores
    

    [out]:

    array([ 0.36782095, -4.2674575 ], dtype=float32)
    

    或

    # From transformers.
    
    from transformers import AutoTokenizer, AutoModelForSequenceClassification
    from transformers import pipeline
    import torch
    
    # cross-encoder/ms-marco-MiniLM-L-12-v2
    model = AutoModelForSequenceClassification.from_pretrained('cross-encoder/mmarco-mMiniLMv2-L12-H384-v1')
    tokenizer = AutoTokenizer.from_pretrained('cross-encoder/mmarco-mMiniLMv2-L12-H384-v1')
    
    features = tokenizer(['How many people live in Berlin?', 'How many people live in Berlin?'], 
                         ['Berlin has a population of 3,520,031 registered inhabitants in an area of 891.82 square kilometers.', 'New York City is famous for the Metropolitan Museum of Art.'],  
                         padding=True, truncation=True, return_tensors="pt")
    
    model.eval()
    with torch.no_grad():
        scores = model(**features).logits
        print(scores)
    

    [out]:

    tensor([[10.7615],
            [-8.1277]])
    

    如果用户想使用 transformers.pipeline 在这些交叉编码器模型上,它抛出一个错误:

    from transformers import AutoTokenizer, AutoModelForSequenceClassification
    from transformers import pipeline
    import torch
    
    # cross-encoder/ms-marco-MiniLM-L-12-v2
    model = AutoModelForSequenceClassification.from_pretrained('cross-encoder/mmarco-mMiniLMv2-L12-H384-v1')
    tokenizer = AutoTokenizer.from_pretrained('cross-encoder/mmarco-mMiniLMv2-L12-H384-v1')
    
    pipe = pipeline(model=model, tokenizer=tokenizer)
    

    它抛出一个错误:

    ---------------------------------------------------------------------------
    RuntimeError                              Traceback (most recent call last)
    /tmp/ipykernel_108/785368641.py in <module>
    ----> 1 pipe = pipeline(model=model, tokenizer=tokenizer)
    
    /opt/conda/lib/python3.7/site-packages/transformers/pipelines/__init__.py in pipeline(task, model, config, tokenizer, feature_extractor, image_processor, framework, revision, use_fast, use_auth_token, device, device_map, torch_dtype, trust_remote_code, model_kwargs, pipeline_class, **kwargs)
        711         if not isinstance(model, str):
        712             raise RuntimeError(
    --> 713                 "Inferring the task automatically requires to check the hub with a model_id defined as a `str`."
        714                 f"{model} is not a valid model_id."
        715             )
    
    RuntimeError: Inferring the task automatically requires to check the hub with a model_id defined as a `str`.
    

    Q: 如何使用交叉编码器与Huggingface变压器管道?

    Q: 如果需要model_id,是否可以将model_id添加为 args 或 kwargs 在里面 pipeline ?

    还有一个类似的问题 Error: Inferring the task automatically requires to check the hub with a model_id defined as a `str`. AraBERT model 但我不确定这是同一个问题,因为另一个问题还在 'aubmindlab/bert-base-arabertv02' 但不是来自 sentence_transformers 。

    0 回复  |  直到 3 年前
        1
  •  2
  •   alvas    3 年前

    经过多次试错和代码挖掘

    现在,开始。。。

    TL;DR

    from transformers import AutoTokenizer, AutoModelForSequenceClassification
    from transformers import pipeline
    import torch
    
    # cross-encoder/ms-marco-MiniLM-L-12-v2
    model = AutoModelForSequenceClassification.from_pretrained('cross-encoder/mmarco-mMiniLMv2-L12-H384-v1')
    tokenizer = AutoTokenizer.from_pretrained('cross-encoder/mmarco-mMiniLMv2-L12-H384-v1')
    
    pipe = pipeline("text-classification", model=model, tokenizer=tokenizer)
    
    
    pipe([{"text": 'How many people live in Berlin?', "text_pair": 'Berlin has a population of 3,520,031 registered inhabitants in an area of 891.82 square kilometers.'},
          {"text": 'How many people live in Berlin?', "text_pair": 'New York City is famous for the Metropolitan Museum of Art.'},
    

    [out]:

    [{'label': 'LABEL_0', 'score': 0.99997878074646},
     {'label': 'LABEL_0', 'score': 0.0002951461647171527},
     {'label': 'LABEL_0', 'score': 0.027012893930077553}]
    

    但是输出与使用 sentence_transformers !

    是的,它不是,因为softmax被应用于输出。

    有一个分类函数应用于模型后推理,位于 https://github.com/huggingface/transformers/blob/main/src/transformers/pipelines/text_classification.py#L27

    class ClassificationFunction(ExplicitEnum):
        SIGMOID = "sigmoid"
        SOFTMAX = "softmax"
        NONE = "none"
    
    

    尤其是在 https://github.com/huggingface/transformers/blob/main/src/transformers/pipelines/text_classification.py#L184

        def postprocess(self, model_outputs, function_to_apply=None, top_k=1, _legacy=True):
            # `_legacy` is used to determine if we're running the naked pipeline and in backward
            # compatibility mode, or if running the pipeline with `pipeline(..., top_k=1)` we're running
            # the more natural result containing the list.
            # Default value before `set_parameters`
            if function_to_apply is None:
                if self.model.config.problem_type == "multi_label_classification" or self.model.config.num_labels == 1:
                    function_to_apply = ClassificationFunction.SIGMOID
                elif self.model.config.problem_type == "single_label_classification" or self.model.config.num_labels > 1:
                    function_to_apply = ClassificationFunction.SOFTMAX
                elif hasattr(self.model.config, "function_to_apply") and function_to_apply is None:
                    function_to_apply = self.model.config.function_to_apply
                else:
                    function_to_apply = ClassificationFunction.NONE
    

    TL;DR(这次是真的)

    要复制推出自己的标记化+转发函数的结果,您必须显式设置分类函数并覆盖后处理函数,即。

    from transformers import AutoTokenizer, AutoModelForSequenceClassification
    from transformers import pipeline
    from transformers.pipelines.text_classification import ClassificationFunction
    
    
    model = AutoModelForSequenceClassification.from_pretrained('cross-encoder/mmarco-mMiniLMv2-L12-H384-v1')
    tokenizer = AutoTokenizer.from_pretrained('cross-encoder/mmarco-mMiniLMv2-L12-H384-v1')
    
    pipe = pipeline("text-classification", model=model, tokenizer=tokenizer, function_to_apply=ClassificationFunction.NONE)
    
    
    pipe([{"text": 'How many people live in Berlin?', "text_pair": 'Berlin has a population of 3,520,031 registered inhabitants in an area of 891.82 square kilometers.'},
          {"text": 'How many people live in Berlin?', "text_pair": 'New York City is famous for the Metropolitan Museum of Art.'},
          {"text": 'Hello how are you?', "text_pair": "I'm fine, thank you"},
          
         ])
    

    [out]:

    [{'label': 'LABEL_0', 'score': 10.761542320251465},
     {'label': 'LABEL_0', 'score': -8.127744674682617},
     {'label': 'LABEL_0', 'score': -3.5840566158294678}]