2020-09-28 13:09:59 +00:00
|
|
|
from typing import Optional
|
2020-01-29 16:06:46 +00:00
|
|
|
from pathlib import Path
|
2020-02-27 17:42:27 +00:00
|
|
|
from wasabi import msg
|
2020-09-28 13:09:59 +00:00
|
|
|
from thinc.api import Config
|
2020-07-10 15:57:40 +00:00
|
|
|
import typer
|
2020-08-14 13:00:52 +00:00
|
|
|
import logging
|
2020-01-29 16:06:46 +00:00
|
|
|
|
2020-07-10 21:34:17 +00:00
|
|
|
from ._util import app, Arg, Opt, parse_config_overrides, show_validation_error
|
2020-09-28 19:17:10 +00:00
|
|
|
from ._util import import_code, setup_gpu
|
2020-07-22 11:42:59 +00:00
|
|
|
from ..language import Language
|
2020-09-28 13:09:59 +00:00
|
|
|
from ..training.loop import train
|
|
|
|
from ..training.initialize import init_nlp, must_reinitialize
|
2020-02-27 17:42:27 +00:00
|
|
|
from .. import util
|
2020-07-10 11:31:27 +00:00
|
|
|
|
2020-06-21 11:44:00 +00:00
|
|
|
|
2020-07-10 15:57:40 +00:00
|
|
|
@app.command(
|
|
|
|
"train", context_settings={"allow_extra_args": True, "ignore_unknown_options": True}
|
|
|
|
)
|
2020-06-20 12:15:04 +00:00
|
|
|
def train_cli(
|
2020-01-29 16:06:46 +00:00
|
|
|
# fmt: off
|
2020-07-10 15:57:40 +00:00
|
|
|
ctx: typer.Context, # This is only used to read additional arguments
|
2020-06-21 19:35:01 +00:00
|
|
|
config_path: Path = Arg(..., help="Path to config file", exists=True),
|
2020-09-03 11:13:03 +00:00
|
|
|
output_path: Optional[Path] = Opt(None, "--output", "--output-path", "-o", help="Output directory to store trained pipeline in"),
|
2020-09-18 23:17:02 +00:00
|
|
|
code_path: Optional[Path] = Opt(None, "--code", "-c", help="Path to Python file with additional code (registered functions) to be imported"),
|
2020-07-09 17:44:28 +00:00
|
|
|
verbose: bool = Opt(False, "--verbose", "-V", "-VV", help="Display more information for debugging purposes"),
|
2020-09-28 09:06:07 +00:00
|
|
|
use_gpu: int = Opt(-1, "--gpu-id", "-g", help="GPU ID or -1 for CPU")
|
2020-01-29 16:06:46 +00:00
|
|
|
# fmt: on
|
|
|
|
):
|
|
|
|
"""
|
2020-09-03 11:13:03 +00:00
|
|
|
Train or update a spaCy pipeline. Requires data in spaCy's binary format. To
|
2020-07-10 15:57:40 +00:00
|
|
|
convert data from other formats, use the `spacy convert` command. The
|
|
|
|
config file includes all settings and hyperparameters used during traing.
|
|
|
|
To override settings in the config, e.g. settings that point to local
|
|
|
|
paths or that you want to experiment with, you can override them as
|
|
|
|
command line options. For instance, --training.batch_size 128 overrides
|
|
|
|
the value of "batch_size" in the block "[training]". The --code argument
|
|
|
|
lets you pass in a Python file that's imported before training. It can be
|
|
|
|
used to register custom functions and architectures that can then be
|
|
|
|
referenced in the config.
|
2020-09-04 10:58:50 +00:00
|
|
|
|
|
|
|
DOCS: https://nightly.spacy.io/api/cli#train
|
2020-01-29 16:06:46 +00:00
|
|
|
"""
|
2020-08-14 13:00:52 +00:00
|
|
|
util.logger.setLevel(logging.DEBUG if verbose else logging.ERROR)
|
2020-08-04 13:09:37 +00:00
|
|
|
verify_cli_args(config_path, output_path)
|
2020-07-10 15:57:40 +00:00
|
|
|
overrides = parse_config_overrides(ctx.args)
|
2020-07-11 11:03:53 +00:00
|
|
|
import_code(code_path)
|
2020-09-28 13:09:59 +00:00
|
|
|
setup_gpu(use_gpu)
|
|
|
|
with show_validation_error(config_path):
|
|
|
|
config = util.load_config(config_path, overrides=overrides, interpolate=False)
|
2020-09-28 08:53:17 +00:00
|
|
|
msg.divider("Initializing pipeline")
|
2020-09-28 13:09:59 +00:00
|
|
|
nlp = init_pipeline(config, output_path, use_gpu=use_gpu)
|
2020-09-28 09:06:07 +00:00
|
|
|
msg.divider("Training pipeline")
|
2020-09-28 19:17:10 +00:00
|
|
|
train(nlp, output_path, use_gpu=use_gpu, silent=False)
|
2020-09-28 09:06:07 +00:00
|
|
|
|
|
|
|
|
2020-09-28 13:09:59 +00:00
|
|
|
def init_pipeline(
|
|
|
|
config: Config, output_path: Optional[Path], *, use_gpu: int = -1
|
|
|
|
) -> Language:
|
2020-09-28 19:17:10 +00:00
|
|
|
init_kwargs = {"use_gpu": use_gpu, "silent": False}
|
2020-09-28 09:06:07 +00:00
|
|
|
if output_path is not None:
|
2020-09-28 10:46:28 +00:00
|
|
|
init_path = output_path / "model-initial"
|
|
|
|
if not init_path.exists():
|
|
|
|
msg.info(f"Initializing the pipeline in {init_path}")
|
2020-09-28 13:09:59 +00:00
|
|
|
nlp = init_nlp(config, **init_kwargs)
|
2020-09-28 10:46:28 +00:00
|
|
|
nlp.to_disk(init_path)
|
|
|
|
msg.good(f"Saved initialized pipeline to {init_path}")
|
2020-09-27 21:59:44 +00:00
|
|
|
else:
|
2020-09-28 10:46:28 +00:00
|
|
|
nlp = util.load_model(init_path)
|
2020-09-28 10:30:13 +00:00
|
|
|
if must_reinitialize(config, nlp.config):
|
|
|
|
msg.warn("Config has changed: need to re-initialize pipeline")
|
2020-09-28 13:09:59 +00:00
|
|
|
nlp = init_nlp(config, **init_kwargs)
|
2020-09-28 10:46:28 +00:00
|
|
|
nlp.to_disk(init_path)
|
|
|
|
msg.good(f"Re-initialized pipeline in {init_path}")
|
2020-09-28 10:30:13 +00:00
|
|
|
else:
|
2020-09-28 10:46:28 +00:00
|
|
|
msg.good(f"Loaded initialized pipeline from {init_path}")
|
2020-09-28 09:06:07 +00:00
|
|
|
return nlp
|
2020-09-28 10:30:13 +00:00
|
|
|
msg.warn(
|
|
|
|
"Not saving initialized model: no output directory specified. "
|
|
|
|
"To speed up training, spaCy can save the initialized nlp object with "
|
|
|
|
"the vocabulary, vectors and label scheme. To take advantage of this, "
|
2020-09-28 10:46:28 +00:00
|
|
|
"provide an output directory."
|
2020-09-28 10:30:13 +00:00
|
|
|
)
|
2020-09-28 13:09:59 +00:00
|
|
|
return init_nlp(config, **init_kwargs)
|
2020-06-26 17:34:12 +00:00
|
|
|
|
|
|
|
|
2020-08-26 13:24:33 +00:00
|
|
|
def verify_cli_args(config_path: Path, output_path: Optional[Path] = None) -> None:
|
2020-06-26 17:34:12 +00:00
|
|
|
# Make sure all files and paths exists if they are needed
|
|
|
|
if not config_path or not config_path.exists():
|
|
|
|
msg.fail("Config file not found", config_path, exits=1)
|
|
|
|
if output_path is not None:
|
|
|
|
if not output_path.exists():
|
|
|
|
output_path.mkdir()
|
|
|
|
msg.good(f"Created output directory: {output_path}")
|