Source code for langchain_community.embeddings.openvino
frompathlibimportPathfromtypingimportAny,Dict,Listfromlangchain_core.embeddingsimportEmbeddingsfrompydanticimportBaseModel,ConfigDict,FieldDEFAULT_QUERY_INSTRUCTION=("Represent the question for retrieving supporting documents: ")DEFAULT_QUERY_BGE_INSTRUCTION_EN=("Represent this question for searching relevant passages: ")DEFAULT_QUERY_BGE_INSTRUCTION_ZH="为这个句子生成表示以用于检索相关文章:"
[docs]classOpenVINOEmbeddings(BaseModel,Embeddings):"""OpenVINO embedding models. Example: .. code-block:: python from langchain_community.embeddings import OpenVINOEmbeddings model_name = "sentence-transformers/all-mpnet-base-v2" model_kwargs = {'device': 'CPU'} encode_kwargs = {'normalize_embeddings': True} ov = OpenVINOEmbeddings( model_name_or_path=model_name, model_kwargs=model_kwargs, encode_kwargs=encode_kwargs ) """ov_model:Any=None"""OpenVINO model object."""tokenizer:Any=None"""Tokenizer for embedding model."""model_name_or_path:str"""HuggingFace model id."""model_kwargs:Dict[str,Any]=Field(default_factory=dict)"""Keyword arguments to pass to the model."""encode_kwargs:Dict[str,Any]=Field(default_factory=dict)"""Keyword arguments to pass when calling the `encode` method of the model."""show_progress:bool=False"""Whether to show a progress bar."""def__init__(self,**kwargs:Any):"""Initialize the sentence_transformer."""super().__init__(**kwargs)try:fromoptimum.intel.openvinoimportOVModelForFeatureExtractionexceptImportErrorase:raiseImportError("Could not import optimum-intel python package. ""Please install it with: ""pip install -U 'optimum[openvino,nncf]'")frometry:fromhuggingface_hubimportHfApiexceptImportErrorase:raiseImportError("Could not import huggingface_hub python package. ""Please install it with: ""`pip install -U huggingface_hub`.")fromedefrequire_model_export(model_id:str,revision:Any=None,subfolder:Any=None)->bool:model_dir=Path(model_id)ifsubfolderisnotNone:model_dir=model_dir/subfolderifmodel_dir.is_dir():return(not(model_dir/"openvino_model.xml").exists()ornot(model_dir/"openvino_model.bin").exists())hf_api=HfApi()try:model_info=hf_api.model_info(model_id,revision=revisionor"main")normalized_subfolder=(NoneifsubfolderisNoneelsePath(subfolder).as_posix())model_files=[file.rfilenameforfileinmodel_info.siblingsifnormalized_subfolderisNoneorfile.rfilename.startswith(normalized_subfolder)]ov_model_path=("openvino_model.xml"ifsubfolderisNoneelsef"{normalized_subfolder}/openvino_model.xml")return(ov_model_pathnotinmodel_filesorov_model_path.replace(".xml",".bin")notinmodel_files)exceptException:returnTrueifrequire_model_export(self.model_name_or_path):# use remote modelself.ov_model=OVModelForFeatureExtraction.from_pretrained(self.model_name_or_path,export=True,**self.model_kwargs)else:# use local modelself.ov_model=OVModelForFeatureExtraction.from_pretrained(self.model_name_or_path,**self.model_kwargs)try:fromtransformersimportAutoTokenizerexceptImportErrorase:raiseImportError("Unable to import transformers, please install with ""`pip install -U transformers`.")fromeself.tokenizer=AutoTokenizer.from_pretrained(self.model_name_or_path)def_text_length(self,text:Any)->int:""" Help function to get the length for the input text. Text can be either a list of ints (which means a single text as input), or a tuple of list of ints (representing several text inputs to the model). """ifisinstance(text,dict):# {key: value} casereturnlen(next(iter(text.values())))elifnothasattr(text,"__len__"):# Object has no len() methodreturn1# Empty string or list of intseliflen(text)==0orisinstance(text[0],int):returnlen(text)else:# Sum of length of individual stringsreturnsum([len(t)fortintext])
[docs]defencode(self,sentences:Any,batch_size:int=4,show_progress_bar:bool=False,convert_to_numpy:bool=True,convert_to_tensor:bool=False,mean_pooling:bool=False,normalize_embeddings:bool=True,)->Any:""" Computes sentence embeddings. :param sentences: the sentences to embed. :param batch_size: the batch size used for the computation. :param show_progress_bar: Whether to output a progress bar. :param convert_to_numpy: Whether the output should be a list of numpy vectors. :param convert_to_tensor: Whether the output should be one large tensor. :param mean_pooling: Whether to pool returned vectors. :param normalize_embeddings: Whether to normalize returned vectors. :return: By default, a 2d numpy array with shape [num_inputs, output_dimension]. """try:importnumpyasnpexceptImportErrorase:raiseImportError("Unable to import numpy, please install with `pip install -U numpy`.")frometry:fromtqdmimporttrangeexceptImportErrorase:raiseImportError("Unable to import tqdm, please install with `pip install -U tqdm`.")frometry:importtorchexceptImportErrorase:raiseImportError("Unable to import torch, please install with `pip install -U torch`.")fromedefrun_mean_pooling(model_output:Any,attention_mask:Any)->Any:token_embeddings=model_output[0]# First element of model_output contains all token embeddingsinput_mask_expanded=(attention_mask.unsqueeze(-1).expand(token_embeddings.size()).float())returntorch.sum(token_embeddings*input_mask_expanded,1)/torch.clamp(input_mask_expanded.sum(1),min=1e-9)ifconvert_to_tensor:convert_to_numpy=Falseinput_was_string=Falseifisinstance(sentences,str)ornothasattr(sentences,"__len__"):# Cast an individual sentence to a list with length 1sentences=[sentences]input_was_string=Trueall_embeddings:Any=[]length_sorted_idx=np.argsort([-self._text_length(sen)forseninsentences])sentences_sorted=[sentences[idx]foridxinlength_sorted_idx]forstart_indexintrange(0,len(sentences),batch_size,desc="Batches",disable=notshow_progress_bar):sentences_batch=sentences_sorted[start_index:start_index+batch_size]length=self.ov_model.request.inputs[0].get_partial_shape()[1]iflength.is_dynamic:features=self.tokenizer(sentences_batch,padding=True,truncation=True,return_tensors="pt")else:features=self.tokenizer(sentences_batch,padding="max_length",max_length=length.get_length(),truncation=True,return_tensors="pt",)out_features=self.ov_model(**features)ifmean_pooling:embeddings=run_mean_pooling(out_features,features["attention_mask"])else:embeddings=out_features[0][:,0]ifnormalize_embeddings:embeddings=torch.nn.functional.normalize(embeddings,p=2,dim=1)# fixes for #522 and #487 to avoid oom problems on gpu with large datasetsifconvert_to_numpy:embeddings=embeddings.cpu()all_embeddings.extend(embeddings)all_embeddings=[all_embeddings[idx]foridxinnp.argsort(length_sorted_idx)]ifconvert_to_tensor:iflen(all_embeddings):all_embeddings=torch.stack(all_embeddings)else:all_embeddings=torch.Tensor()elifconvert_to_numpy:all_embeddings=np.asarray([emb.numpy()forembinall_embeddings])ifinput_was_string:all_embeddings=all_embeddings[0]returnall_embeddings
[docs]defembed_documents(self,texts:List[str])->List[List[float]]:"""Compute doc embeddings using a HuggingFace transformer model. Args: texts: The list of texts to embed. Returns: List of embeddings, one for each text. """texts=list(map(lambdax:x.replace("\n"," "),texts))embeddings=self.encode(texts,show_progress_bar=self.show_progress,**self.encode_kwargs)returnembeddings.tolist()
[docs]defembed_query(self,text:str)->List[float]:"""Compute query embeddings using a HuggingFace transformer model. Args: text: The text to embed. Returns: Embeddings for the text. """returnself.embed_documents([text])[0]
[docs]classOpenVINOBgeEmbeddings(OpenVINOEmbeddings):"""OpenVNO BGE embedding models. Bge Example: .. code-block:: python from langchain_community.embeddings import OpenVINOBgeEmbeddings model_name = "BAAI/bge-large-en-v1.5" model_kwargs = {'device': 'CPU'} encode_kwargs = {'normalize_embeddings': True} ov = OpenVINOBgeEmbeddings( model_name_or_path=model_name, model_kwargs=model_kwargs, encode_kwargs=encode_kwargs ) """query_instruction:str=DEFAULT_QUERY_BGE_INSTRUCTION_EN"""Instruction to use for embedding query."""embed_instruction:str="""""Instruction to use for embedding document."""def__init__(self,**kwargs:Any):"""Initialize the sentence_transformer."""super().__init__(**kwargs)if"-zh"inself.model_name_or_path:self.query_instruction=DEFAULT_QUERY_BGE_INSTRUCTION_ZH
[docs]defembed_documents(self,texts:List[str])->List[List[float]]:"""Compute doc embeddings using a HuggingFace transformer model. Args: texts: The list of texts to embed. Returns: List of embeddings, one for each text. """texts=[self.embed_instruction+t.replace("\n"," ")fortintexts]embeddings=self.encode(texts,**self.encode_kwargs)returnembeddings.tolist()
[docs]defembed_query(self,text:str)->List[float]:"""Compute query embeddings using a HuggingFace transformer model. Args: text: The text to embed. Returns: Embeddings for the text. """text=text.replace("\n"," ")embedding=self.encode(self.query_instruction+text,**self.encode_kwargs)returnembedding.tolist()