Source code for deepparse.embeddings_models.bpemb_embeddings_model
import contextlib
import logging
import ssl
import warnings
from pathlib import Path
from typing import Any, Dict
import requests
from numpy import ndarray
from urllib3.exceptions import InsecureRequestWarning
from ..bpemb_loader import BPEmbLoader
from .embeddings_model import EmbeddingsModel
logger = logging.getLogger(__name__)
[docs]
class BPEmbEmbeddingsModel(EmbeddingsModel):
"""
BPEmb embeddings network from `BPEmb: Tokenization-free Pre-trained Subword Embeddings in 275 Languages
<https://www.aclweb.org/anthology/L18-1473/>`_. The arguments are the same as the
`BPEmb class <https://github.com/bheinzerling/bpemb/blob/master/bpemb/bpemb.py>`_
Args:
cache_dir (str): Path to the cache directory to the embeddings' bin vector and the model.
verbose (bool): Whether or not to make the loading of the embeddings verbose.
"""
def __init__(self, cache_dir: str, verbose: bool = True) -> None:
super().__init__(verbose=verbose)
with warnings.catch_warnings():
# annoying scipy.sparcetools private module warnings removal
# annoying boto warnings
warnings.filterwarnings("ignore")
self.model = self._load_bpemb_model(cache_dir)
def _load_bpemb_model(self, cache_dir: str) -> BPEmbLoader:
"""
Download (if needed) and load the BPEmb model. We download with SSL verification enabled. The BPEmb
host (set by :class:`BPEmbLoader`) currently has a valid certificate, but it has broken
before (`bpemb issue 63 <https://github.com/bheinzerling/bpemb/issues/63>`_). As a failsafe, and only
if an SSL error occurs, we retry once with verification disabled while warning loudly, so a transient
upstream certificate problem does not break Deepparse outright.
We use the default parameters other than the dim at 300 and a vs of 100,000.
"""
model_kwargs = {"lang": "multi", "vs": 100000, "dim": 300, "cache_dir": Path(cache_dir)}
try:
return BPEmbLoader(**model_kwargs)
except (requests.exceptions.SSLError, ssl.SSLError) as ssl_error:
logger.warning(
"SSL verification failed while downloading the BPEmb embeddings. Retrying once without SSL "
"verification as a failsafe; this is insecure (man-in-the-middle risk). If it persists, the "
"BPEmb host certificate is likely broken again (see bpemb issue 63). Original error: %s",
ssl_error,
)
with no_ssl_verification():
return BPEmbLoader(**model_kwargs)
[docs]
def __call__(self, word: str) -> ndarray:
"""
Callable method to get a word vector.
Args:
word (str): Word to get vector.
Return:
The BP embedding for a word.
"""
return self.model.embed(word)
@contextlib.contextmanager
def no_ssl_verification():
"""Context Manager to disable SSL verification when using ``requests`` library.
Reference: https://gist.github.com/ChenTanyi/0c47652bd916b61dc196968bca7dad1d.
It will be removed when https://github.com/bheinzerling/bpemb/issues/63 is resolved.
"""
opened_adapters = set()
old_merge_environment_settings = requests.Session.merge_environment_settings
def merge_environment_settings( # pylint: disable=R0913
self, url: str, proxies: Dict[str, Any], stream: bool, verify: bool, cert: Any
) -> Dict[str, Any]:
# Verification happens only once per connection, so we need to close
# all the opened adapters once we're done. Otherwise, the effects of
# verify=False persist beyond the end of this context manager.
opened_adapters.add(self.get_adapter(url))
settings = old_merge_environment_settings(self, url, proxies, stream, verify, cert)
settings["verify"] = False
return settings
requests.Session.merge_environment_settings = merge_environment_settings
try:
with warnings.catch_warnings():
warnings.simplefilter("ignore", InsecureRequestWarning)
yield
finally:
requests.Session.merge_environment_settings = old_merge_environment_settings
for adapter in opened_adapters:
try:
adapter.close()
except Exception: # pylint: disable=broad-except
pass