From 8ce3b4de725f420f851c29ef52279056d26bd4fe Mon Sep 17 00:00:00 2001 From: Xiaobin Date: Tue, 29 Aug 2023 17:47:59 +0800 Subject: [PATCH] Feature/seq gpt (#507) --- modelscope/pipelines/nlp/__init__.py | 4 +- .../pipelines/nlp/text_generation_pipeline.py | 45 +++++++++++++++++++ requirements/nlp.txt | 1 - tests/pipelines/test_text_generation.py | 18 ++++++++ 4 files changed, 65 insertions(+), 3 deletions(-) diff --git a/modelscope/pipelines/nlp/__init__.py b/modelscope/pipelines/nlp/__init__.py index 1216464e..95283713 100644 --- a/modelscope/pipelines/nlp/__init__.py +++ b/modelscope/pipelines/nlp/__init__.py @@ -27,7 +27,7 @@ if TYPE_CHECKING: from .translation_quality_estimation_pipeline import TranslationQualityEstimationPipeline from .text_error_correction_pipeline import TextErrorCorrectionPipeline from .word_alignment_pipeline import WordAlignmentPipeline - from .text_generation_pipeline import TextGenerationPipeline, TextGenerationT5Pipeline + from .text_generation_pipeline import TextGenerationPipeline, TextGenerationT5Pipeline, SeqGPTPipeline from .fid_dialogue_pipeline import FidDialoguePipeline from .token_classification_pipeline import TokenClassificationPipeline from .translation_pipeline import TranslationPipeline @@ -79,7 +79,7 @@ else: 'text_error_correction_pipeline': ['TextErrorCorrectionPipeline'], 'word_alignment_pipeline': ['WordAlignmentPipeline'], 'text_generation_pipeline': - ['TextGenerationPipeline', 'TextGenerationT5Pipeline'], + ['TextGenerationPipeline', 'TextGenerationT5Pipeline', 'SeqGPTPipeline'], 'fid_dialogue_pipeline': ['FidDialoguePipeline'], 'token_classification_pipeline': ['TokenClassificationPipeline'], 'translation_pipeline': ['TranslationPipeline'], diff --git a/modelscope/pipelines/nlp/text_generation_pipeline.py b/modelscope/pipelines/nlp/text_generation_pipeline.py index dc6bfdb8..112e7074 100644 --- a/modelscope/pipelines/nlp/text_generation_pipeline.py +++ b/modelscope/pipelines/nlp/text_generation_pipeline.py @@ -4,6 +4,7 @@ import os from typing import Any, Dict, Optional, Union +import re import torch from transformers import GenerationConfig @@ -28,6 +29,7 @@ __all__ = [ 'ChatGLM6bV2TextGenerationPipeline', 'QWenChatPipeline', 'QWenTextGenerationPipeline', + 'SeqGPTPipeline' ] @@ -418,3 +420,46 @@ class QWenTextGenerationPipeline(Pipeline): # format the outputs from pipeline def postprocess(self, input, **kwargs) -> Dict[str, Any]: return input + + +@PIPELINES.register_module( + group_key=Tasks.text_generation, module_name='seqgpt') +class SeqGPTPipeline(Pipeline): + + def __init__(self, model: Union[Model, str], **kwargs): + from modelscope.models.nlp import BloomForTextGeneration + from modelscope.utils.hf_util import AutoTokenizer + + if isinstance(model, str): + model_dir = snapshot_download( + model) if not os.path.exists(model) else model + model = Model.from_pretrained(model_dir) + self.model = model + self.model.eval() + self.tokenizer = AutoTokenizer.from_pretrained(model_dir) + + super().__init__(model=model, **kwargs) + + def _sanitize_parameters(self, **pipeline_parameters): + return {}, pipeline_parameters, {} + + def preprocess(self, inputs, **preprocess_params) -> Dict[str, Any]: + return inputs + + # define the forward pass + def forward(self, prompt: str, **forward_params) -> Dict[str, Any]: + # gen & decode + prompt += '[GEN]' + input_ids = self.tokenizer(prompt, return_tensors="pt", padding=True, truncation=True, max_length=1024) + input_ids = input_ids.input_ids.cuda() + outputs = self.model.generate(input_ids, num_beams=4, do_sample=False, max_new_tokens=256) + decoded_sentences = self.tokenizer.batch_decode(outputs, skip_special_tokens=True) + decoded_sentence = decoded_sentences[0] + decoded_sentence = decoded_sentence[len(prompt):] + return { + OutputKeys.TEXT: decoded_sentence + } + + # format the outputs from pipeline + def postprocess(self, input, **kwargs) -> Dict[str, Any]: + return input diff --git a/requirements/nlp.txt b/requirements/nlp.txt index 18f9a08f..f69f869b 100644 --- a/requirements/nlp.txt +++ b/requirements/nlp.txt @@ -1,6 +1,5 @@ boto3 embeddings -en_core_web_sm>=2.3.5 filelock ftfy jieba>=0.42.1 diff --git a/tests/pipelines/test_text_generation.py b/tests/pipelines/test_text_generation.py index 820a768c..1bf7a374 100644 --- a/tests/pipelines/test_text_generation.py +++ b/tests/pipelines/test_text_generation.py @@ -45,6 +45,8 @@ class TextGenerationTest(unittest.TestCase): self.llama_model_id = 'skyline2006/llama-7b' self.llama_input = 'My name is Merve and my favorite' + self.seqgpt_model_id = 'damo/nlp_seqgpt-560m' + self.ecomgpt_model_id = 'damo/nlp_seqgpt-560m' def run_pipeline_with_model_instance(self, model_id, input): model = Model.from_pretrained(model_id) @@ -320,6 +322,22 @@ class TextGenerationTest(unittest.TestCase): self.llama_input, run_kwargs={'max_length': 64}) + @unittest.skipUnless(test_level() >= 0, 'skip test in current test level') + def test_seqgpt_with_model_name(self): + inputs = {'task': '抽取', 'text': '杭州欢迎你。', 'labels': '地名'} + PROMPT_TEMPLATE = '输入: {text}\n{task}: {labels}\n输出: ' + prompt = PROMPT_TEMPLATE.format(**inputs) + self.run_pipeline_with_model_id(self.seqgpt_model_id, prompt) + + @unittest.skipUnless(test_level() >= 0, 'skip test in current test level') + def test_ecomgpt_with_model_name(self): + PROMPT_TEMPLATE = "Below is an instruction that describes a task. " + \ + "Write a response that appropriately completes the request.\n\n" + \ + "### Instruction:\n{text}\n{instruction}\n\n### Response:" + inputs = {'instruction': 'Classify the sentence, candidate labels: product, brand', 'text': '照相机'} + prompt = PROMPT_TEMPLATE.format(**inputs) + self.run_pipeline_with_model_id(self.ecomgpt_model_id, prompt) + if __name__ == '__main__': unittest.main()