Repository: flairNLP/flair

Issue:
Exported model picking user path of machine it was trained on
I am training a model on a machine and doing inference on another machine. It is a SequenceTagger model consisting of only BytepairEmbeddings in the stacked embedding. 

The machine i trained the model on has my username 'abhissha-new' and the machine i am trying to do inference on has my username 'abhisaar'. When i export the model and try to do inference, somehow flair is trying to look for downloaded BPE at my other machine's username home folder. This issue is only happening for byte pair embeddings. 

Temporary workaround of course is just making my original username folder on my inference machine but that is inconvinient. Attached stack trace.

**To Reproduce**
Train a model on one machine and infer it on another machine with a different username.

```
2020-03-20 13:32:20,184 loading file /home/abhisaar/Downloads/final-model8.pt
downloading https://nlp.h-its.org/bpemb/en/en.wiki.bpe.vs100000.model
100%|██████████| 1987533/1987533 [00:01<00:00, 1082354.99B/s]
---------------------------------------------------------------------------
FileNotFoundError                         Traceback (most recent call last)
/usr/lib/python3.6/pathlib.py in mkdir(self, mode, parents, exist_ok)
   1247         try:
-> 1248             self._accessor.mkdir(self, mode)
   1249         except FileNotFoundError:

/usr/lib/python3.6/pathlib.py in wrapped(pathobj, *args)
    386         def wrapped(pathobj, *args):
--> 387             return strfunc(str(pathobj), *args)
    388         return staticmethod(wrapped)

FileNotFoundError: [Errno 2] **No such file or directory: '/home/abhissha-new/.flair/embeddings/en'**

During handling of the above exception, another exception occurred:

FileNotFoundError                         Traceback (most recent call last)
/usr/lib/python3.6/pathlib.py in mkdir(self, mode, parents, exist_ok)
   1247         try:
-> 1248             self._accessor.mkdir(self, mode)
   1249         except FileNotFoundError:

/usr/lib/python3.6/pathlib.py in wrapped(pathobj, *args)
    386         def wrapped(pathobj, *args):
--> 387             return strfunc(str(pathobj), *args)
    388         return staticmethod(wrapped)

FileNotFoundError: [Errno 2] No such file or directory: '/home/abhissha-new/.flair/embeddings'

During handling of the above exception, another exception occurred:

FileNotFoundError                         Traceback (most recent call last)
/usr/lib/python3.6/pathlib.py in mkdir(self, mode, parents, exist_ok)
   1247         try:
-> 1248             self._accessor.mkdir(self, mode)
   1249         except FileNotFoundError:

/usr/lib/python3.6/pathlib.py in wrapped(pathobj, *args)
    386         def wrapped(pathobj, *args):
--> 387             return strfunc(str(pathobj), *args)
    388         return staticmethod(wrapped)

FileNotFoundError: [Errno 2] No such file or directory: '/home/abhissha-new/.flair'

During handling of the above exception, another exception occurred:

PermissionError                           Traceback (most recent call last)
<ipython-input-4-b077ce389efe> in <module>()
      1 from flair.models import SequenceTagger
----> 2 model = SequenceTagger.load('/home/abhisaar/Downloads/final-model8.pt')

/home/abhisaar/.local/lib/python3.6/site-packages/flair/nn.py in load(cls, model)
     84             # see https://github.com/zalandoresearch/flair/issues/351
     85             f = file_utils.load_big_file(str(model_file))
---> 86             state = torch.load(f, map_location=flair.device)
     87 
     88         model = cls._init_model_with_state_dict(state)

/home/abhisaar/.local/lib/python3.6/site-packages/torch/serialization.py in load(f, map_location, pickle_module, **pickle_load_args)
    527             with _open_zipfile_reader(f) as opened_zipfile:
    528                 return _load(opened_zipfile, map_location, pickle_module, **pickle_load_args)
--> 529         return _legacy_load(opened_file, map_location, pickle_module, **pickle_load_args)
    530 
    531 

/home/abhisaar/.local/lib/python3.6/site-packages/torch/serialization.py in _legacy_load(f, map_location, pickle_module, **pickle_load_args)
    700     unpickler = pickle_module.Unpickler(f, **pickle_load_args)
    701     unpickler.persistent_load = persistent_load
--> 702     result = unpickler.load()
    703 
    704     deserialized_storage_keys = pickle_module.load(f, **pickle_load_args)

/home/abhisaar/.local/lib/python3.6/site-packages/bpemb/bpemb.py in __setstate__(self, state)
    452             model_rel_path = Path(state["lang"]) / model_file.name
    453             model_file = self._load_file(
--> 454                 str(model_rel_path), cache_dir=state["cache_dir"])
    455         state['spm'] = sentencepiece_load(model_file)
    456         self.__dict__ = state

/home/abhisaar/.local/lib/python3.6/site-packages/bpemb/bpemb.py in _load_file(self, file, archive, cache_dir)
    194         file_url = self.base_url + file + suffix
    195         print("downloading", file_url)
--> 196         return http_get(file_url, cached_file, ignore_tardir=True)
    197 
    198     def __repr__(self):

/home/abhisaar/.local/lib/python3.6/site-packages/bpemb/util.py in http_get(url, outfile, ignore_tardir)
     43         # shutil.copyfileobj() starts at current position, so go to the start
     44         temp_file.seek(0)
---> 45         outfile.parent.mkdir(exist_ok=True, parents=True)
     46         if headers.get("Content-Type") == "application/x-gzip":
     47             import tarfile

/usr/lib/python3.6/pathlib.py in mkdir(self, mode, parents, exist_ok)
   1250             if not parents or self.parent == self:
   1251                 raise
-> 1252             self.parent.mkdir(parents=True, exist_ok=True)
   1253             self.mkdir(mode, parents=False, exist_ok=exist_ok)
   1254         except OSError:

/usr/lib/python3.6/pathlib.py in mkdir(self, mode, parents, exist_ok)
   1250             if not parents or self.parent == self:
   1251                 raise
-> 1252             self.parent.mkdir(parents=True, exist_ok=True)
   1253             self.mkdir(mode, parents=False, exist_ok=exist_ok)
   1254         except OSError:

/usr/lib/python3.6/pathlib.py in mkdir(self, mode, parents, exist_ok)
   1250             if not parents or self.parent == self:
   1251                 raise
-> 1252             self.parent.mkdir(parents=True, exist_ok=True)
   1253             self.mkdir(mode, parents=False, exist_ok=exist_ok)
   1254         except OSError:

/usr/lib/python3.6/pathlib.py in mkdir(self, mode, parents, exist_ok)
   1246             self._raise_closed()
   1247         try:
-> 1248             self._accessor.mkdir(self, mode)
   1249         except FileNotFoundError:
   1250             if not parents or self.parent == self:

/usr/lib/python3.6/pathlib.py in wrapped(pathobj, *args)
    385         @functools.wraps(strfunc)
    386         def wrapped(pathobj, *args):
--> 387             return strfunc(str(pathobj), *args)
    388         return staticmethod(wrapped)
    389 

PermissionError: [Errno 13] Permission denied: '/home/abhissha-new'
```




**Expected behavior**
Model loads correctly

**Environment (please complete the following information):**
 - OS [Ubuntu]:
 - Version [flair-0.4.5, torch 1.4.0]




Discussion:

Resolving patch:
diff --git a/flair/embeddings/token.py b/flair/embeddings/token.py
--- a/flair/embeddings/token.py
+++ b/flair/embeddings/token.py
@@ -1559,7 +1559,7 @@ def __init__(
         language: str = None,
         dim: int = 50,
         syllables: int = 100000,
-        cache_dir=Path(flair.cache_root) / "embeddings",
+        cache_dir= None,
         model_file_path: Path = None,
         embedding_file_path: Path = None,
         **kwargs,
@@ -1567,6 +1567,8 @@ def __init__(
         """
         Initializes BP embeddings. Constructor downloads required files if not there.
         """
+        if not cache_dir:
+            cache_dir = Path(flair.cache_root) / "embeddings"
         if language:
             self.name: str = f"bpe-{language}-{syllables}-{dim}"
         else:
@@ -1575,7 +1577,7 @@ def __init__(
             ), "Need to specify model_file_path and embedding_file_path if no language is given in BytePairEmbeddings(...)"
             dim=None
 
-        self.embedder = BPEmb(
+        self.embedder = BPEmbSerializable(
             lang=language,
             vs=syllables,
             dim=dim,
diff --git a/train.py b/train.py
--- a/train.py
+++ b/train.py
@@ -19,6 +19,7 @@
 # 2. what tag do we want to predict?
 tag_type = "upos"
 
+
 # 3. make the tag dictionary from the corpus
 tag_dictionary = corpus.make_tag_dictionary(tag_type=tag_type)
 print(tag_dictionary.idx2item)


Test patch: