Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved startup time #8141

Merged
merged 28 commits into from
Mar 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
b294aa5
improved startup time
tmbo Mar 8, 2021
081de27
merged main
tmbo Mar 10, 2021
7b9def9
use policy name constants instead of importing classes
tmbo Mar 10, 2021
1121de9
updated telemetry example
tmbo Mar 10, 2021
0a9c14c
added cli import test
tmbo Mar 10, 2021
61cbcd7
added changelog
tmbo Mar 10, 2021
ce29b4d
improved docstrings
tmbo Mar 10, 2021
1f8a27f
fixed data test
tmbo Mar 10, 2021
6752dc1
Update tests/shared/core/test_constants.py
tmbo Mar 11, 2021
d7446f4
Update rasa/api.py
tmbo Mar 11, 2021
ea8dc62
added fallback classifier name constant
tmbo Mar 11, 2021
2272768
fixed not defined name
tmbo Mar 11, 2021
8afca53
use Python from sys.executable to get poetry's python version
wochinge Mar 11, 2021
f1e4f4b
rename `rasa.train` [production code]
wochinge Mar 15, 2021
272eba9
rename `rasa.train` [test code]
wochinge Mar 15, 2021
67968df
rename `rasa.test` [production code]
wochinge Mar 15, 2021
dae1fff
rename `rasa.test` [test code]
wochinge Mar 15, 2021
6ee8865
move `rasa.run.create_agent` to `rasa.core.agent`
wochinge Mar 15, 2021
dc88cb0
rename `rasa.run` [production code]
wochinge Mar 15, 2021
a218e86
adapt mocking in test
wochinge Mar 15, 2021
3e6340b
Merge branch 'main' into improved-startup-time
wochinge Mar 15, 2021
a545326
remove shorthand import for `rasa.core.train` and `rasa.core.visualize`
wochinge Mar 15, 2021
3c9a265
remove shorthand syntax for `rasa.nlu.train`, `rasa.nlu.test`, `rasa.…
wochinge Mar 15, 2021
180291b
add changelogs
wochinge Mar 15, 2021
153ec8d
add missing docstrings
wochinge Mar 15, 2021
c9db254
fixes for prior module renames / removing of abbreviated imports
wochinge Mar 16, 2021
13c6b39
Merge branch 'main' into improved-startup-time
wochinge Mar 16, 2021
830e331
Merge branch 'main' into improved-startup-time
wochinge Mar 16, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog/4280.improvement.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Improved CLI startup time.
3 changes: 3 additions & 0 deletions changelog/8141.misc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
The following modules were renamed:
* `rasa.train` -> `rasa.model_training`
* `rasa.test` -> `rasa.model_testing`
6 changes: 6 additions & 0 deletions changelog/8141.removal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
The following import abbreviations were removed:
* `rasa.core.train`: Please use `rasa.core.train.train` instead.
* `rasa.core.visualize`: Please use `rasa.core.visualize.visualize` instead.
* `rasa.nlu.train`: Please use `rasa.nlu.train.train` instead.
* `rasa.nlu.test`: Please use `rasa.nlu.test.run_evaluation` instead.
* `rasa.nlu.cross_validate`: Please use `rasa.nlu.test.cross_validate` instead.
1 change: 0 additions & 1 deletion docs/docs/telemetry/telemetry.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,6 @@ Here is an example report that shows the data reported to Rasa after running
"project": "a0a7178e6e5f9e6484c5cfa3ea4497ffc0c96d0ad3f3ad8e9399a1edd88e3cf4",
"python": "3.7.5",
"rasa_open_source": "2.0.0",
"gpu": 0,
"cpu": 16
}
}
Expand Down
4 changes: 1 addition & 3 deletions rasa/__init__.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import logging

from rasa import version
from rasa.api import run, train, test

# define the version before the other imports since these need it
__version__ = version.__version__

from rasa.run import run
from rasa.train import train
from rasa.test import test

logging.getLogger(__name__).addHandler(logging.NullHandler())
155 changes: 155 additions & 0 deletions rasa/api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
import rasa.shared.constants
import typing

# WARNING: Be careful about adding any top level imports at this place!
# These functions are imported in `rasa.__init__` and any top level import
# added here will get executed as soon as someone runs `import rasa`.
# Some imports are very slow (e.g. `tensorflow`) and we want them to get
# imported when running `import rasa`. If you add more imports here,
# please check that in the chain you are importing, no slow packages
# are getting imported.

if typing.TYPE_CHECKING:
from typing import Any, Text, Dict, Union, List, Optional, NoReturn
from rasa.model_training import TrainingResult
import asyncio


def run(
model: "Text",
endpoints: "Text",
connector: "Text" = None,
credentials: "Text" = None,
**kwargs: "Dict[Text, Any]",
) -> "NoReturn":
"""Runs a Rasa model.

Args:
model: Path to model archive.
endpoints: Path to endpoints file.
connector: Connector which should be use (overwrites `credentials`
field).
credentials: Path to channel credentials file.
**kwargs: Additional arguments which are passed to
`rasa.core.run.serve_application`.

"""
import rasa.core.run
from rasa.core.utils import AvailableEndpoints
from rasa.shared.utils.cli import print_warning
import rasa.shared.utils.common
from rasa.shared.constants import DOCS_BASE_URL

_endpoints = AvailableEndpoints.read_endpoints(endpoints)

if not connector and not credentials:
connector = "rest"

print_warning(
f"No chat connector configured, falling back to the "
f"REST input channel. To connect your bot to another channel, "
f"read the docs here: {DOCS_BASE_URL}/messaging-and-voice-channels"
)

kwargs = rasa.shared.utils.common.minimal_kwargs(
kwargs, rasa.core.run.serve_application
)
rasa.core.run.serve_application(
model,
channel=connector,
credentials=credentials,
endpoints=_endpoints,
**kwargs,
)


def train(
domain: "Text",
config: "Text",
training_files: "Union[Text, List[Text]]",
output: "Text" = rasa.shared.constants.DEFAULT_MODELS_PATH,
dry_run: bool = False,
force_training: bool = False,
fixed_model_name: "Optional[Text]" = None,
persist_nlu_training_data: bool = False,
core_additional_arguments: "Optional[Dict]" = None,
nlu_additional_arguments: "Optional[Dict]" = None,
loop: "Optional[asyncio.AbstractEventLoop]" = None,
model_to_finetune: "Optional[Text]" = None,
finetuning_epoch_fraction: float = 1.0,
) -> "TrainingResult":
"""Runs Rasa Core and NLU training in `async` loop.

Args:
domain: Path to the domain file.
config: Path to the config for Core and NLU.
training_files: Paths to the training data for Core and NLU.
output: Output path.
dry_run: If `True` then no training will be done, and the information about
whether the training needs to be done will be printed.
force_training: If `True` retrain model even if data has not changed.
fixed_model_name: Name of model to be stored.
persist_nlu_training_data: `True` if the NLU training data should be persisted
with the model.
core_additional_arguments: Additional training parameters for core training.
nlu_additional_arguments: Additional training parameters forwarded to training
method of each NLU component.
loop: Optional EventLoop for running coroutines.
model_to_finetune: Optional path to a model which should be finetuned or
a directory in case the latest trained model should be used.
finetuning_epoch_fraction: The fraction currently specified training epochs
in the model configuration which should be used for finetuning.

Returns:
An instance of `TrainingResult`.
"""
from rasa.model_training import train_async
import rasa.utils.common

return rasa.utils.common.run_in_loop(
train_async(
domain=domain,
config=config,
training_files=training_files,
output=output,
dry_run=dry_run,
force_training=force_training,
fixed_model_name=fixed_model_name,
persist_nlu_training_data=persist_nlu_training_data,
core_additional_arguments=core_additional_arguments,
nlu_additional_arguments=nlu_additional_arguments,
model_to_finetune=model_to_finetune,
finetuning_epoch_fraction=finetuning_epoch_fraction,
),
loop,
)


def test(
model: "Text",
stories: "Text",
nlu_data: "Text",
output: "Text" = rasa.shared.constants.DEFAULT_RESULTS_PATH,
additional_arguments: "Optional[Dict]" = None,
) -> None:
"""Test a Rasa model against a set of test data.

Args:
model: model to test
stories: path to the dialogue test data
nlu_data: path to the NLU test data
output: path to folder where all output will be stored
additional_arguments: additional arguments for the test call
"""
from rasa.model_testing import test_core
import rasa.utils.common
from rasa.model_testing import test_nlu

if additional_arguments is None:
additional_arguments = {}

test_core(model, stories, output, additional_arguments)

rasa.utils.common.run_in_loop(
test_nlu(model, nlu_data, output, additional_arguments)
)
66 changes: 34 additions & 32 deletions rasa/cli/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,6 @@
from rasa.cli.arguments import data as arguments
from rasa.cli.arguments import default_arguments
import rasa.cli.utils
from rasa.core.training.converters.responses_prefix_converter import (
DomainResponsePrefixConverter,
StoryResponsePrefixConverter,
)
import rasa.nlu.convert
from rasa.shared.constants import (
DEFAULT_DATA_PATH,
DEFAULT_CONFIG_PATH,
Expand All @@ -24,6 +19,10 @@
)
import rasa.shared.data
from rasa.shared.core.constants import (
POLICY_NAME_FALLBACK,
POLICY_NAME_FORM,
POLICY_NAME_MAPPING,
POLICY_NAME_TWO_STAGE_FALLBACK,
USER_INTENT_OUT_OF_SCOPE,
ACTION_DEFAULT_FALLBACK_NAME,
)
Expand All @@ -38,18 +37,13 @@
import rasa.shared.nlu.training_data.util
import rasa.shared.utils.cli
import rasa.utils.common
from rasa.utils.converter import TrainingDataConverter
from rasa.validator import Validator
from rasa.shared.core.domain import Domain, InvalidDomain
import rasa.shared.utils.io
import rasa.core.config
from rasa.core.policies.form_policy import FormPolicy
from rasa.core.policies.fallback import FallbackPolicy
from rasa.core.policies.two_stage_fallback import TwoStageFallbackPolicy
from rasa.core.policies.mapping_policy import MappingPolicy

if TYPE_CHECKING:
from rasa.shared.core.training_data.structures import StoryStep
from rasa.validator import Validator
from rasa.utils.converter import TrainingDataConverter

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -242,6 +236,7 @@ def validate_files(args: argparse.Namespace, stories_only: bool = False) -> None
args: Commandline arguments
stories_only: If `True`, only the story structure is validated.
"""
from rasa.validator import Validator

config = rasa.cli.utils.get_validated_path(
args.config, "config", DEFAULT_CONFIG_PATH, none_is_valid=True
Expand Down Expand Up @@ -278,15 +273,15 @@ def validate_stories(args: argparse.Namespace) -> None:
validate_files(args, stories_only=True)


def _validate_domain(validator: Validator) -> bool:
def _validate_domain(validator: "Validator") -> bool:
return validator.verify_domain_validity()


def _validate_nlu(validator: Validator, args: argparse.Namespace) -> bool:
def _validate_nlu(validator: "Validator", args: argparse.Namespace) -> bool:
return validator.verify_nlu(not args.fail_on_warnings)


def _validate_story_structure(validator: Validator, args: argparse.Namespace) -> bool:
def _validate_story_structure(validator: "Validator", args: argparse.Namespace) -> bool:
# Check if a valid setting for `max_history` was given
if isinstance(args.max_history, int) and args.max_history < 1:
raise argparse.ArgumentTypeError(
Expand All @@ -299,6 +294,8 @@ def _validate_story_structure(validator: Validator, args: argparse.Namespace) ->


def _convert_nlu_data(args: argparse.Namespace) -> None:
import rasa.nlu.convert

from rasa.nlu.training_data.converters.nlu_markdown_to_yaml_converter import (
NLUMarkdownToYamlConverter,
)
Expand Down Expand Up @@ -356,8 +353,14 @@ def _convert_nlg_data(args: argparse.Namespace) -> None:

def _migrate_responses(args: argparse.Namespace) -> None:
"""Migrate retrieval intent responses to the new 2.0 format.

It does so modifying the stories and domain files.
"""
from rasa.core.training.converters.responses_prefix_converter import (
DomainResponsePrefixConverter,
StoryResponsePrefixConverter,
)

if args.format == "yaml":
rasa.utils.common.run_in_loop(
_convert_to_yaml(args.out, args.domain, DomainResponsePrefixConverter())
Expand All @@ -374,7 +377,7 @@ def _migrate_responses(args: argparse.Namespace) -> None:


async def _convert_to_yaml(
out_path: Text, data_path: Text, converter: TrainingDataConverter
out_path: Text, data_path: Text, converter: "TrainingDataConverter"
) -> None:

output = Path(out_path)
Expand Down Expand Up @@ -415,7 +418,7 @@ async def _convert_to_yaml(


async def _convert_file_to_yaml(
source_file: Path, target_dir: Path, converter: TrainingDataConverter
source_file: Path, target_dir: Path, converter: "TrainingDataConverter"
) -> bool:
"""Converts a single training data file to `YAML` format.

Expand Down Expand Up @@ -447,6 +450,8 @@ def _migrate_model_config(args: argparse.Namespace) -> None:
Args:
args: The commandline args with the required paths.
"""
import rasa.core.config

configuration_file = Path(args.config)
model_configuration = _get_configuration(configuration_file)

Expand Down Expand Up @@ -499,32 +504,32 @@ def _get_configuration(path: Path) -> Dict:
_assert_two_stage_fallback_policy_is_migratable(config)
_assert_only_one_fallback_policy_present(policy_names)

if FormPolicy.__name__ in policy_names:
if POLICY_NAME_FORM in policy_names:
_warn_about_manual_forms_migration()

return config


def _assert_config_needs_migration(policies: List[Text]) -> None:
migratable_policies = {
MappingPolicy.__name__,
FallbackPolicy.__name__,
TwoStageFallbackPolicy.__name__,
POLICY_NAME_MAPPING,
POLICY_NAME_FALLBACK,
POLICY_NAME_TWO_STAGE_FALLBACK,
}

if not migratable_policies.intersection((set(policies))):
rasa.shared.utils.cli.print_error_and_exit(
f"No policies were found which need migration. This command can migrate "
f"'{MappingPolicy.__name__}', '{FallbackPolicy.__name__}' and "
f"'{TwoStageFallbackPolicy.__name__}'."
f"'{POLICY_NAME_MAPPING}', '{POLICY_NAME_FALLBACK}' and "
f"'{POLICY_NAME_TWO_STAGE_FALLBACK}'."
)


def _warn_about_manual_forms_migration() -> None:
rasa.shared.utils.cli.print_warning(
f"Your model configuration contains the '{FormPolicy.__name__}'. "
f"Note that this command does not migrate the '{FormPolicy.__name__}' and "
f"you have to migrate the '{FormPolicy.__name__}' manually. "
f"Your model configuration contains the '{POLICY_NAME_FORM}'. "
f"Note that this command does not migrate the '{POLICY_NAME_FORM}' and "
f"you have to migrate the '{POLICY_NAME_FORM}' manually. "
f"Please see the migration guide for further details: "
f"{DOCS_URL_MIGRATION_GUIDE}"
)
Expand All @@ -533,7 +538,7 @@ def _warn_about_manual_forms_migration() -> None:
def _assert_nlu_pipeline_given(config: Dict, policy_names: List[Text]) -> None:
if not config.get("pipeline") and any(
policy in policy_names
for policy in [FallbackPolicy.__name__, TwoStageFallbackPolicy.__name__]
for policy in [POLICY_NAME_FALLBACK, POLICY_NAME_TWO_STAGE_FALLBACK]
):
rasa.shared.utils.cli.print_error_and_exit(
"The model configuration has to include an NLU pipeline. This is required "
Expand All @@ -546,7 +551,7 @@ def _assert_two_stage_fallback_policy_is_migratable(config: Dict) -> None:
(
policy_config
for policy_config in config.get("policies", [])
if policy_config.get("name") == TwoStageFallbackPolicy.__name__
if policy_config.get("name") == POLICY_NAME_TWO_STAGE_FALLBACK
),
None,
)
Expand Down Expand Up @@ -583,10 +588,7 @@ def _assert_two_stage_fallback_policy_is_migratable(config: Dict) -> None:


def _assert_only_one_fallback_policy_present(policies: List[Text]) -> None:
if (
FallbackPolicy.__name__ in policies
and TwoStageFallbackPolicy.__name__ in policies
):
if POLICY_NAME_FALLBACK in policies and POLICY_NAME_TWO_STAGE_FALLBACK in policies:
rasa.shared.utils.cli.print_error_and_exit(
"Your policy configuration contains two configured policies for handling "
"fallbacks. Please decide on one."
Expand Down
Loading