Files
wehub-resource-sync dc6079821b
Docs Tests / Check for file changes (push) Has been cancelled
Docs Tests / Test Documentation (push) Has been cancelled
Docs Tests / Documentation Linting Checks (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-performance) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-policies) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-cli) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-core-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-full-model-training) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-nlu-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-nlu-predictors) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-other-unit-tests) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-performance) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-policies) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-cli) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-core-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-full-model-training) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-nlu-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-nlu-predictors) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-other-unit-tests) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-performance) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-policies) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-cli) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-core-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-full-model-training) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-nlu-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-nlu-predictors) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-other-unit-tests) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-performance) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-policies) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-cli) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-core-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-full-model-training) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-nlu-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-nlu-predictors) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-other-unit-tests) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-performance) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-policies) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-cli) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-core-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-full-model-training) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-nlu-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-nlu-predictors) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-other-unit-tests) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-performance) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-policies) (push) Has been cancelled
Continuous Integration / Run Flaky Tests (ubuntu-24.04, 3.10) (push) Has been cancelled
Continuous Integration / Run Flaky Tests (ubuntu-24.04, 3.8) (push) Has been cancelled
Continuous Integration / Run Flaky Tests (ubuntu-24.04, 3.9) (push) Has been cancelled
Continuous Integration / Run Flaky Tests (windows-2022, 3.10) (push) Has been cancelled
Continuous Integration / Run Flaky Tests (windows-2022, 3.8) (push) Has been cancelled
Continuous Integration / Run Flaky Tests (windows-2022, 3.9) (push) Has been cancelled
Continuous Integration / Check for file changes (push) Has been cancelled
Continuous Integration / Wait for docs tests (push) Has been cancelled
Continuous Integration / Code Quality (push) Has been cancelled
Continuous Integration / Check for changelog (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-cli) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-core-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-full-model-training) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-nlu-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-nlu-predictors) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-other-unit-tests) (push) Has been cancelled
Continuous Integration / Upload coverage reports to codeclimate (push) Has been cancelled
Continuous Integration / Run Non-Sequential Integration Tests (push) Has been cancelled
Continuous Integration / Run Broker Integration Tests (push) Has been cancelled
Continuous Integration / Run Sequential Integration Tests (push) Has been cancelled
Continuous Integration / Build Docker base images and setup environment (push) Has been cancelled
Continuous Integration / Build Docker (default) (push) Has been cancelled
Continuous Integration / Build Docker (full) (push) Has been cancelled
Continuous Integration / Build Docker (mitie-en) (push) Has been cancelled
Continuous Integration / Build Docker (spacy-de) (push) Has been cancelled
Continuous Integration / Build Docker (spacy-en) (push) Has been cancelled
Continuous Integration / Build Docker (spacy-it) (push) Has been cancelled
Continuous Integration / Deploy to PyPI (push) Has been cancelled
Continuous Integration / Notify Slack & Publish Release Notes (push) Has been cancelled
Publish Documentation / Evaluate release tag (push) Has been cancelled
Publish Documentation / Prebuild Docs (push) Has been cancelled
Publish Documentation / Preview Docs (push) Has been cancelled
Publish Documentation / Check for file changes (push) Has been cancelled
Publish Documentation / Publish Docs (push) Has been cancelled
Automatic PR Merger / mergepal (push) Has been cancelled
CI Github Actions / Run Tests (push) Has been cancelled
Semgrep / Semgrep Workflow Security Scan (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:24:47 +08:00

303 lines
13 KiB
Python

from __future__ import annotations
from typing import Dict, Text, Any, Optional
import copy
import logging
from packaging import version
from rasa.constants import MINIMUM_COMPATIBLE_VERSION
from rasa.engine.graph import GraphComponent, ExecutionContext
from rasa.engine.storage.storage import ModelStorage
from rasa.engine.storage.resource import Resource
from rasa.shared.exceptions import InvalidConfigException
from rasa.shared.core.domain import Domain
from rasa.shared.importers.importer import TrainingDataImporter
import rasa.shared.utils.io
from rasa.utils.tensorflow.constants import EPOCHS
from rasa.graph_components.providers.domain_for_core_training_provider import (
DomainForCoreTrainingProvider,
)
FINGERPRINT_CONFIG = "fingerprint-config"
FINGERPRINT_CORE = "fingerprint-core"
FINGERPRINT_NLU = "fingerprint-nlu"
FINGERPRINT_VERSION = "rasa-version"
logger = logging.getLogger(__name__)
class FinetuningValidator(GraphComponent):
"""Component that checks whether fine-tuning is possible.
This is a component at the beginning of the graph which receives all training data
and raises an exception in case `is_finetuning` is `True` and finetuning is not
possible (e.g. because new labels were added).
In case we are doing a regular training (and not finetuning) this persists the
necessary information extracted from the training data to be able to validate when
initialized via load whether we can finetune.
Finetuning is possible if, compared to the initial training phase, it holds that
1. the configuration (except for "epoch" keys) does not change
2. the domain (except for e.g. "responses") does not change - or we're not
finetuning the core part
3. the intents, entities, entity groups, entity roles, and action names that
appeared in the original NLU training data, appear in the NLU training data
used for finetuning, and no new such items (i.e. intents, entities, entity
groups, entity roles, or action names) have been added, compared to the original
training data - or we're not finetuning the nlu part.
Note that even though conditions 2. and 3. differ based on which part we finetune,
condition 1. always covers both parts, i.e. NLU and Core.
"""
FILENAME = "fingerprints-for-validation.json"
@staticmethod
def get_default_config() -> Dict[Text, Any]:
"""Default config for ProjectProvider."""
return {"validate_core": True, "validate_nlu": True}
def __init__(
self,
config: Dict[Text, Any],
model_storage: ModelStorage,
resource: Resource,
execution_context: ExecutionContext,
fingerprints: Optional[Dict[Text, Text]] = None,
) -> None:
"""Instantiates a `FineTuningValidator`.
Args:
model_storage: Storage which graph components can use to persist and load
themselves.
resource: Resource locator for this component which can be used to persist
and load itself from the `model_storage`.
execution_context: Information about the current graph run.
fingerprints: a dictionary of fingerprints generated by a
`FineTuningValidator`
"""
self._is_finetuning = execution_context.is_finetuning
self._execution_context = execution_context
self._model_storage = model_storage
self._resource = resource
self._fingerprints: Dict[Text, Text] = fingerprints or {}
self._core = config["validate_core"]
self._nlu = config["validate_nlu"]
def validate(self, importer: TrainingDataImporter) -> TrainingDataImporter:
"""Validates whether we can finetune Core and NLU when finetuning is enabled.
Args:
importer: a training data importer
Raises:
`InvalidConfigException` if there is a conflict
Returns:
Training Data Importer.
"""
self._validate(importer)
return importer
def _validate(self, importer: TrainingDataImporter) -> None:
"""Validate whether the finetuning setting conflicts with other settings.
Note that this validation always takes into account the configuration of
nlu *and* core part, while the validation of aspects of the domain and
the NLU training data only happen if we request to validate finetuning
with respect to NLU/Core models, respectively.
For more details, see docstring of this class.
Args:
importer: a training data importer
Raises:
`InvalidConfigException` if there is a conflict
"""
if self._is_finetuning and not self._fingerprints:
raise InvalidConfigException(
f"Finetuning is enabled but the {self.__class__.__name__} "
f"does not remember seeing a training run. Ensure that you have "
f"trained your model at least once (with finetuning disabled) "
f"and ensure that the {self.__class__.__name__} is part of the "
f"training graph. "
)
rasa_version = rasa.__version__
if self._is_finetuning:
old_rasa_version = self._fingerprints[FINGERPRINT_VERSION]
if version.parse(old_rasa_version) < version.parse(
MINIMUM_COMPATIBLE_VERSION
):
raise InvalidConfigException(
f"The minimum compatible Rasa Version is "
f"{MINIMUM_COMPATIBLE_VERSION} but the model we attempt to "
f"finetune has been generated with an older version "
f"({old_rasa_version}."
)
self._fingerprints[FINGERPRINT_VERSION] = rasa_version
fingerprint_config = self._get_fingerprint_of_schema_without_irrelevant_keys()
self._compare_or_memorize(
fingerprint_key=FINGERPRINT_CONFIG,
new_fingerprint=fingerprint_config,
error_message=(
"Cannot finetune because more than just the 'epoch' keys have been "
"changed in the configuration. "
"Please revert your configuration and only change "
"the 'epoch' settings where needed."
),
)
if self._core:
# NOTE: If there's a consistency check between domain and core training data
# that ensures domain and core training data are consistent, then we can
# drop this check.
fingerprint_core = self._get_fingerprint_of_domain_pruned_for_core(
domain=importer.get_domain()
)
self._compare_or_memorize(
fingerprint_key=FINGERPRINT_CORE,
new_fingerprint=fingerprint_core,
error_message=(
"Cannot finetune because keys that affect the training of core "
"components have changed."
"Please revert all settings in your domain file that affect the "
"training of core components."
),
)
if self._nlu:
fingerprint_nlu = importer.get_nlu_data().label_fingerprint()
self._compare_or_memorize(
fingerprint_key=FINGERPRINT_NLU,
new_fingerprint=fingerprint_nlu,
error_message=(
"Cannot finetune because NLU training data contains new labels "
"or does not contain any examples for some known labels. "
"Please make sure that the NLU data that you use "
"for finetuning contains at least one example for every label "
"(i.e. intent, action name, ...) that was included in the NLU "
"data used for training the model which we attempt to finetune "
"now. Moreover, you must not add labels that were not included "
"during training before. "
),
)
self.persist()
def _compare_or_memorize(
self, fingerprint_key: Text, new_fingerprint: Text, error_message: Text
) -> None:
"""Compares given fingerprint if we are finetuning, otherwise just saves it.
Args:
fingerprint_key: name of the fingerprint
new_fingerprint: a new fingerprint value
error_message: message of `InvalidConfigException` that will be raised if
a fingerprint is stored under `fingerprint_key` and differs from the
`new_fingerprint` - and we're in finetuning mode (according to the
execution context of this component)
Raises:
`InvalidConfigException` if and old fingerprint exists and differs from
the new one
"""
if self._is_finetuning:
old_fingerprint = self._fingerprints[fingerprint_key]
if old_fingerprint != new_fingerprint:
raise InvalidConfigException(error_message)
else:
self._fingerprints[fingerprint_key] = new_fingerprint
@staticmethod
def _get_fingerprint_of_domain_pruned_for_core(domain: Domain) -> Text:
"""Returns a fingerprint of a pruned version of the domain relevant for core.
Args:
domain: a domain
Returns:
fingerprint
"""
pruned_domain = DomainForCoreTrainingProvider.create_pruned_version(domain)
return pruned_domain.fingerprint()
def _get_fingerprint_of_schema_without_irrelevant_keys(self) -> Text:
"""Returns a fingerprint of the given schema with certain items removed.
These items include specifications that do not influence actual training
results such as "eager" mode. The only configuration (in your config) that is
allowed to change is the number of `epochs`.
Returns:
fingerprint
"""
graph_schema = self._execution_context.graph_schema
schema_as_dict = graph_schema.as_dict()
for node_name, node_dict in schema_as_dict["nodes"].items():
config_copy = copy.deepcopy(node_dict["config"])
config_copy.pop(EPOCHS, None)
config_copy.pop("finetuning_epoch_fraction", None)
# ignore default values since they're filled in anyway later and can
# end up in configs (or not) in mysterious ways
defaults = graph_schema.nodes[node_name].uses.get_default_config()
for key, default_value in defaults.items():
if key in config_copy and config_copy[key] == default_value:
config_copy.pop(key)
node_dict["config"] = config_copy
node_dict.pop("eager")
node_dict.pop("constructor_name")
return rasa.shared.utils.io.deep_container_fingerprint(schema_as_dict)
@classmethod
def create(
cls,
config: Dict[Text, Any],
model_storage: ModelStorage,
resource: Resource,
execution_context: ExecutionContext,
) -> FinetuningValidator:
"""Creates a new `FineTuningValidator` (see parent class for full docstring)."""
return cls(
config=config,
model_storage=model_storage,
resource=resource,
execution_context=execution_context,
)
def persist(self) -> None:
"""Persists this `FineTuningValidator`."""
with self._model_storage.write_to(self._resource) as path:
rasa.shared.utils.io.dump_obj_as_json_to_file(
filename=path / self.FILENAME, obj=self._fingerprints
)
@classmethod
def load(
cls,
config: Dict[Text, Any],
model_storage: ModelStorage,
resource: Resource,
execution_context: ExecutionContext,
**kwargs: Any,
) -> GraphComponent:
"""Loads a `FineTuningValidator` (see parent class for full docstring)."""
try:
with model_storage.read_from(resource) as path:
fingerprints = rasa.shared.utils.io.read_json_file(
filename=path / cls.FILENAME
)
return cls(
config=config,
model_storage=model_storage,
execution_context=execution_context,
resource=resource,
fingerprints=fingerprints,
)
except ValueError as e:
raise InvalidConfigException(
f"Loading {cls.__name__} failed. Ensure that the {cls.__name__} "
f"is part of your training graph and re-train your models before "
f"attempting to use the {cls.__name__}."
) from e