Repository: RasaHQ/rasa
Pull request: Improve response selector defaults when transformer is enabled
**Proposed changes**:
- Raise warnings when `number_of_transformer_layers > 0` is used with a ResponseSelector but:
  -  `transformer_size` is not specified or is set to a non-positive value
  - `hidden_layers_sizes` is not specified or is set such that the hidden layers are not disabled (we recommend disabling hidden layers when using a transfomer)
- Set sensible default `transformer_size` in the 1st case from above. Previously, the default remained `None` which was breaking transformer training down the line.

**To-do**:
- [x] check that `transformer_size=256` and `num_transformer_layers=2` are sensible default values -- they were previously used until [this commit](https://github.com/RasaHQ/rasa/commit/792a6a9a5722669e197c2e1041fade48204d6331#diff-a09a171b147b1e582bc05975958773927f94a31316c29e77b8290ffff0d792adR101) but back then no `HIDDEN_LAYERS_SIZES` were specified (today we've got `{TEXT: [256, 128], LABEL: [256, 128]}`)
    - Turned out we don't need a default `num_transformer_layers` because the user should always set this by themself to activate or de-activate the transformer
- [x] decide if we want to set `transformer_size` to a value compatible with `num_heads` (if provided) or always to a fixed default value
    - Decision: go with a fixed size; in a separate issue improve the config checking so that incompatible `num_heads` and `transformer_size` are warned about early (see #8110 )

**Status (please check what you already did)**:
- [x] added some tests for the functionality
- [x] updated the documentation
- [x] updated the changelog (please check [changelog](https://github.com/RasaHQ/rasa/tree/main/changelog) for instructions)
- [x] reformat files using `black` (please check [Readme](https://github.com/RasaHQ/rasa#code-style) for instructions)

Problem statement:
ResponseSelector training fails with use_text_as_label and simple pipeline
**Rasa version**: `main` (2.3.1)

**Rasa SDK version** (if used & relevant):

**Rasa X version** (if used & relevant):

**Python version**: 3.8.5

**Operating system** (windows, osx, ...): MacOS 10.15.6

**Issue**: NLU training fails when I have a `ResponseSelector` that expects sequence-level features but don't provide any featurisers that would create such features (in this case specifically for the `label` attribute). I would've expected at least some warning when using `use_text_as_label` but not providing any sequence-level featurisers.

**Error (including full traceback)**:
```
Traceback (most recent call last):
  File "/Users/sams/.miniconda/envs/rasa1/bin/rasa", line 5, in <module>
    main()
  File "/Users/sams/rasa1/rasa/__main__.py", line 116, in main
    cmdline_arguments.func(cmdline_arguments)
  File "/Users/sams/rasa1/rasa/cli/train.py", line 197, in train_nlu
    return train_nlu(
  File "/Users/sams/rasa1/rasa/train.py", line 700, in train_nlu
    return rasa.utils.common.run_in_loop(
  File "/Users/sams/rasa1/rasa/utils/common.py", line 308, in run_in_loop
    result = loop.run_until_complete(f)
  File "uvloop/loop.pyx", line 1456, in uvloop.loop.Loop.run_until_complete
  File "/Users/sams/rasa1/rasa/train.py", line 750, in train_nlu_async
    return await _train_nlu_with_validated_data(
  File "/Users/sams/rasa1/rasa/train.py", line 812, in _train_nlu_with_validated_data
    await rasa.nlu.train(
  File "/Users/sams/rasa1/rasa/nlu/train.py", line 116, in train
    interpreter = trainer.train(training_data, **kwargs)
  File "/Users/sams/rasa1/rasa/nlu/model.py", line 209, in train
    updates = component.train(working_data, self.config, **context)
  File "/Users/sams/rasa1/rasa/nlu/classifiers/diet_classifier.py", line 832, in train
    self.model.fit(
  File "/Users/sams/rasa1/rasa/utils/tensorflow/models.py", line 222, in fit
    ) = self._get_tf_train_functions(eager, model_data, batch_strategy)
  File "/Users/sams/rasa1/rasa/utils/tensorflow/models.py", line 483, in _get_tf_train_functions
    self._get_tf_call_model_function(
  File "/Users/sams/rasa1/rasa/utils/tensorflow/models.py", line 466, in _get_tf_call_model_function
    tf_call_model_function(next(iter(init_dataset)))
  File "/Users/sams/.miniconda/envs/rasa1/lib/python3.8/site-packages/tensorflow/python/eager/def_function.py", line 780, in __call__
    result = self._call(*args, **kwds)
  File "/Users/sams/.miniconda/envs/rasa1/lib/python3.8/site-packages/tensorflow/python/eager/def_function.py", line 823, in _call
    self._initialize(args, kwds, add_initializers_to=initializers)
  File "/Users/sams/.miniconda/envs/rasa1/lib/python3.8/site-packages/tensorflow/python/eager/def_function.py", line 696, in _initialize
    self._stateful_fn._get_concrete_function_internal_garbage_collected(  # pylint: disable=protected-access
  File "/Users/sams/.miniconda/envs/rasa1/lib/python3.8/site-packages/tensorflow/python/eager/function.py", line 2855, in _get_concrete_function_internal_garbage_collected
    graph_function, _, _ = self._maybe_define_function(args, kwargs)
  File "/Users/sams/.miniconda/envs/rasa1/lib/python3.8/site-packages/tensorflow/python/eager/function.py", line 3213, in _maybe_define_function
    graph_function = self._create_graph_function(args, kwargs)
  File "/Users/sams/.miniconda/envs/rasa1/lib/python3.8/site-packages/tensorflow/python/eager/function.py", line 3065, in _create_graph_function
    func_graph_module.func_graph_from_py_func(
  File "/Users/sams/.miniconda/envs/rasa1/lib/python3.8/site-packages/tensorflow/python/framework/func_graph.py", line 986, in func_graph_from_py_func
    func_outputs = python_func(*func_args, **func_kwargs)
  File "/Users/sams/.miniconda/envs/rasa1/lib/python3.8/site-packages/tensorflow/python/eager/def_function.py", line 600, in wrapped_fn
    return weak_wrapped_fn().__wrapped__(*args, **kwds)
  File "/Users/sams/.miniconda/envs/rasa1/lib/python3.8/site-packages/tensorflow/python/framework/func_graph.py", line 973, in wrapper
    raise e.ag_error_metadata.to_exception(e)
tensorflow.python.autograph.impl.api.StagingError: in user code:

    /Users/sams/rasa1/rasa/utils/tensorflow/models.py:295 train_on_batch  *
        prediction_loss = self.batch_loss(batch_in)
    /Users/sams/rasa1/rasa/nlu/selectors/response_selector.py:737 batch_loss  *
        loss, acc = self._calculate_label_loss(
    /Users/sams/rasa1/rasa/nlu/classifiers/diet_classifier.py:1419 _calculate_label_loss  *
        all_label_ids, all_labels_embed = self._create_all_labels()
    /Users/sams/rasa1/rasa/nlu/selectors/response_selector.py:651 _create_all_labels  *
        sequence_lengths_label = self._get_sequence_lengths(
    /Users/sams/rasa1/rasa/utils/tensorflow/models.py:1126 _get_sequence_lengths  *
        return tf.cast(tf_batch_data[key][sub_key][0], dtype=tf.int32) + 1

    IndexError: list index out of range
```

**Command or request that led to error**:
```
rasa train nlu
```

**Content of configuration file (config.yml)** (if relevant):
```yml
language: en
pipeline:
  - name: WhitespaceTokenizer
  - name: CountVectorsFeaturizer
  - name: DIETClassifier
    epochs: 1
  - name: ResponseSelector
    epochs: 1
    use_text_as_label: true
```

**Content of domain file (domain.yml)** (if relevant):
```yml
version: "2.0"
intents:
  - greet
  - goodbye
```

**Content of NLU data file**:
```yml
version: "2.0"
nlu:
- intent: greet/hi
  examples: |
    - hey
    - hello

- intent: greet/bye
  examples: |
    - bye
    - ciao

- intent: goodbye
  examples: |
    - see you
    - good night

responses:
  utter_goodbye:
  - text: "Bye"

  utter_greet/hi:
  - text: hey there

  utter_greet/bye:
  - text: bye
```

**Definition of done**

- [x] Add new warning for cases where user hasn't specified `transformer_size` but has enabled the transformer
- [x] Set a default `transformer_size` in the above case so that ResponseSelector doesn't break

Hints from issue discussion:
missing intent in `domain.yml`
```
greet/hi
greet/bye
```
@Dustyposa in this case `greet` is a retrieval intent, so it's enough to list `greet` in the domain file, without enumerating all the variations with different response keys (in these case the keys being `hi` and `bye`).
@samsucik 
in your `config.yml`, not declare the `greet` intent to `retrieval intent`。
need this configuration:
```yml
  - name: ResponseSelector
    retrieval_intent: greet
```
@Dustyposa strictly speaking, that's not needed. By not specifying a `retrieval_intent` there, I effectively tell the `ResponseSelector` to be used for all retrieval intents.
@dakshvar22 I think I found the "bug". Even though I specified `use_text_as_label: true`, I didn't specify the number of transformer layers. And the default is, unfortunately, `0`. Subsequently, [here in label data preparation](https://github.com/RasaHQ/rasa/blob/776406cdbf936724252cd1f81f70b482701b73ea/rasa/nlu/classifiers/diet_classifier.py#L502), sequence-level features are discarded if the number of transformer layers is 0. And so it happens that the `DIET2DIET` code expects sequence-level features to exist always when `use_text_as_label: true`, but in reality this isn't true and things break.

The easiest (but only temporary) fix would be to validate the config and exit if `use_text_as_label: true` and `num_transformer_layers` is `0` or not specified. However, we really need to change the `DIET2DIET` code to work OK just with sentence-level label features. And since that takes us exactly to the new `rasa_layers` that I'm creating over in #7589, I think that fixing it as part of that PR might be the easiest way actually...
@samsucik Just checking, are you still planning to fix this in https://github.com/RasaHQ/rasa/pull/7589 ?
Short answer: No 😜 
@samsucik Since you are no longer taking care of this in #7589, what are our options for tackling this? Is this a common problem we expect users to run into or more of an edge case?
@samsucik Looking at your configuration, `CountVectorsFeaturizer` should add both sentence and sequence level features for `response` attribute of the message. I suspect either of the two: 

1. Creation of model data object from all training messages is wrong
2. The function `batch_to_model_data_format` is doing something unexpected here.
@dakshvar22 have you read my [comment](https://github.com/RasaHQ/rasa/issues/8046#issuecomment-790525634) above? I think it's in agreement with your comment and explains what's going on (though perhaps I should've made the explanation more detailed).

Commit message: Update the changelog entry.

Patch to review:
diff --git a/changelog/8046.bugfix.md b/changelog/8046.bugfix.md
new file mode 100644
index 000000000000..5ed67841f4c4
--- /dev/null
+++ b/changelog/8046.bugfix.md
@@ -0,0 +1,3 @@
+`ResponseSelector` can now be trained with the transformer enabled (i.e. when a positive
+number of transformer layers is provided) even if one doesn't specify the transformer's
+size. Previously, not specifying `transformer_size` led to an error.
\ No newline at end of file
diff --git a/docs/docs/components.mdx b/docs/docs/components.mdx
index 77843c03bfaf..e501541c5b13 100644
--- a/docs/docs/components.mdx
+++ b/docs/docs/components.mdx
@@ -2632,7 +2632,7 @@ Selectors predict a bot response from a set of candidate responses.
     If the `retrieval_intent` parameter of a particular response selector was left to its default value,
     the corresponding response selector will be identified as `default` in the returned output.
 
-    ```json {4}
+    ```json {3}
     {
         "response_selector": {
           "default": {
@@ -2777,14 +2777,19 @@ However, additional parameters exist that can be adapted.
 +=================================+===================+==============================================================+
 | hidden_layers_sizes             | text: [256, 128]  | Hidden layer sizes for layers before the embedding layers    |
 |                                 | label: [256, 128] | for user messages and labels. The number of hidden layers is |
-|                                 |                   | equal to the length of the corresponding.                    |
+|                                 |                   | equal to the length of the corresponding list. We recommend  |
+|                                 |                   | disabling the hidden layers (by providing empty lists) when  |
+|                                 |                   | the transformer is enabled.                                  |
 +---------------------------------+-------------------+--------------------------------------------------------------+
 | share_hidden_layers             | False             | Whether to share the hidden layer weights between user       |
 |                                 |                   | messages and labels.                                         |
 +---------------------------------+-------------------+--------------------------------------------------------------+
-| transformer_size                | None              | Number of units in transformer.                              |
+| transformer_size                | None              | Number of units in the transformer. When a positive value is |
+|                                 |                   | provided for `number_of_transformer_layers`, the default size|
+|                                 |                   | becomes `256`.                                               |
 +---------------------------------+-------------------+--------------------------------------------------------------+
-| number_of_transformer_layers    | 0                 | Number of transformer layers.                                |
+| number_of_transformer_layers    | 0                 | Number of transformer layers; positive values enable the     |
+|                                 |                   | transformer.                                                 |
 +---------------------------------+-------------------+--------------------------------------------------------------+
 | number_of_attention_heads       | 4                 | Number of attention heads in transformer.                    |
 +---------------------------------+-------------------+--------------------------------------------------------------+
diff --git a/rasa/nlu/selectors/response_selector.py b/rasa/nlu/selectors/response_selector.py
index 2b337fd1f978..57deb62995ba 100644
--- a/rasa/nlu/selectors/response_selector.py
+++ b/rasa/nlu/selectors/response_selector.py
@@ -246,6 +246,9 @@ def required_components(cls) -> List[Type[Component]]:
         MODEL_CONFIDENCE: SOFTMAX,
     }
 
+    # The `transformer_size` to use as a default when the transformer is enabled.
+    default_transformer_size_when_enabled = 256
+
     def __init__(
         self,
         component_config: Optional[Dict[Text, Any]] = None,
@@ -308,9 +311,88 @@ def _load_selector_params(self, config: Dict[Text, Any]) -> None:
         self.retrieval_intent = config[RETRIEVAL_INTENT]
         self.use_text_as_label = config[USE_TEXT_AS_LABEL]
 
+    def _warn_about_transformer_and_hidden_layers_enabled(
+        self, selector_name: Text
+    ) -> None:
+        """Warns user if they enabled the transformer but didn't disable hidden layers.
+
+        ResponseSelector defaults specify considerable hidden layer sizes, but
+        this is for cases where no transformer is used. If a transformer exists,
+        then the best results are chieved with no hidden layers used between the
+        feature-combining layers and the transformer.
+        """
+        hidden_layers_is_at_default_value = (
+            self.component_config[HIDDEN_LAYERS_SIZES]
+            == self.defaults[HIDDEN_LAYERS_SIZES]
+        )
+        config_for_disabling_hidden_layers = {
+            k: [] for k, _ in self.defaults[HIDDEN_LAYERS_SIZES].items()
+        }
+        # warn if the hidden layers aren't disabled
+        if (
+            self.component_config[HIDDEN_LAYERS_SIZES]
+            != config_for_disabling_hidden_layers
+        ):
+            # make the warning text more contextual by explaining what the user did
+            # to the hidden layers' config (i.e. what it is they should change)
+            if hidden_layers_is_at_default_value:
+                what_user_did = "left the hidden layer sizes at their default value:"
+            else:
+                what_user_did = "set the hidden layer sizes to be non-empty by setting"
+
+            rasa.shared.utils.io.raise_warning(
+                f"You have enabled a transformer inside {selector_name} by"
+                f" setting a positive value for `{NUM_TRANSFORMER_LAYERS}`, but you "
+                f"{what_user_did} `{HIDDEN_LAYERS_SIZES}="
+                f"{self.component_config[HIDDEN_LAYERS_SIZES]}`. We recommend to "
+                f"disable the hidden layers when using a transformer, by specifying "
+                f"`{HIDDEN_LAYERS_SIZES}={config_for_disabling_hidden_layers}`.",
+                category=UserWarning,
+            )
+
+    def _warn_and_correct_transformer_size(self, selector_name: Text) -> None:
+        """Corrects transformer size so that training doesn't break; informs the user.
+
+        If a transformer is used, the default `transformer_size` breaks things.
+        We need to set a reasonable default value so that the model works fine.
+        """
+        if (
+            self.component_config[TRANSFORMER_SIZE] is None
+            or self.component_config[TRANSFORMER_SIZE] < 1
+        ):
+            rasa.shared.utils.io.raise_warning(
+                f"`{TRANSFORMER_SIZE}` is set to "
+                f"`{self.component_config[TRANSFORMER_SIZE]}` for "
+                f"{selector_name}, but a positive size is required when using "
+                f"`{NUM_TRANSFORMER_LAYERS} > 0`. {selector_name} will proceed, using "
+                f"`{TRANSFORMER_SIZE}={self.default_transformer_size_when_enabled}`. "
+                f"Alternatively, specify a different value in the component's config.",
+                category=UserWarning,
+            )
+            self.component_config[
+                TRANSFORMER_SIZE
+            ] = self.default_transformer_size_when_enabled
+
+    def _check_config_params_when_transformer_enabled(self) -> None:
+        """Checks & corrects config parameters when the transformer is enabled.
+
+        This is needed because the defaults for individual config parameters are
+        interdependent and some defaults should change when the transformer is enabled.
+        """
+        if self.component_config[NUM_TRANSFORMER_LAYERS] > 0:
+            selector_name = "ResponseSelector" + (
+                f"({self.retrieval_intent})" if self.retrieval_intent else ""
+            )
+            self._warn_about_transformer_and_hidden_layers_enabled(selector_name)
+            self._warn_and_correct_transformer_size(selector_name)
+
     def _check_config_parameters(self) -> None:
+        """Checks that component configuration makes sense; corrects it where needed."""
         super()._check_config_parameters()
         self._load_selector_params(self.component_config)
+        # Once general DIET-related parameters have been checked, check also the ones
+        # specific to ResponseSelector.
+        self._check_config_params_when_transformer_enabled()
 
     def _set_message_property(
         self, message: Message, prediction_dict: Dict[Text, Any], selector_key: Text
diff --git a/tests/nlu/selectors/test_selectors.py b/tests/nlu/selectors/test_selectors.py
index d58cbb5ba396..350201b697d3 100644
--- a/tests/nlu/selectors/test_selectors.py
+++ b/tests/nlu/selectors/test_selectors.py
@@ -2,7 +2,7 @@
 
 import pytest
 import numpy as np
-from typing import List, Dict, Text, Any
+from typing import List, Dict, Text, Any, Optional, Union
 from mock import Mock
 from _pytest.monkeypatch import MonkeyPatch
 
@@ -24,6 +24,8 @@
     RANDOM_SEED,
     RANKING_LENGTH,
     LOSS_TYPE,
+    HIDDEN_LAYERS_SIZES,
+    LABEL,
 )
 from rasa.utils import train_utils
 from rasa.shared.nlu.constants import TEXT
@@ -440,3 +442,111 @@ async def test_softmax_ranking(
     response_ranking = parse_data.get("response_selector").get("default").get("ranking")
     # check that the output was correctly truncated after normalization
     assert len(response_ranking) == output_length
+
+
+@pytest.mark.parametrize(
+    "config, should_raise_warning",
+    [
+        # hidden layers left at defaults
+        ({}, False),
+        ({NUM_TRANSFORMER_LAYERS: 5}, True),
+        ({NUM_TRANSFORMER_LAYERS: 0}, False),
+        ({NUM_TRANSFORMER_LAYERS: -1}, False),
+        # hidden layers explicitly enabled
+        ({HIDDEN_LAYERS_SIZES: {TEXT: [10], LABEL: [11]}}, False),
+        (
+            {NUM_TRANSFORMER_LAYERS: 5, HIDDEN_LAYERS_SIZES: {TEXT: [10], LABEL: [11]}},
+            True,
+        ),
+        (
+            {NUM_TRANSFORMER_LAYERS: 0, HIDDEN_LAYERS_SIZES: {TEXT: [10], LABEL: [11]}},
+            False,
+        ),
+        (
+            {
+                NUM_TRANSFORMER_LAYERS: -1,
+                HIDDEN_LAYERS_SIZES: {TEXT: [10], LABEL: [11]},
+            },
+            False,
+        ),
+        # hidden layers explicitly disabled
+        ({HIDDEN_LAYERS_SIZES: {TEXT: [], LABEL: []}}, False),
+        (
+            {NUM_TRANSFORMER_LAYERS: 5, HIDDEN_LAYERS_SIZES: {TEXT: [], LABEL: []}},
+            False,
+        ),
+        (
+            {NUM_TRANSFORMER_LAYERS: 0, HIDDEN_LAYERS_SIZES: {TEXT: [], LABEL: []}},
+            False,
+        ),
+        (
+            {NUM_TRANSFORMER_LAYERS: -1, HIDDEN_LAYERS_SIZES: {TEXT: [], LABEL: []}},
+            False,
+        ),
+    ],
+)
+def test_warning_when_transformer_and_hidden_layers_enabled(
+    config: Dict[Text, Union[int, Dict[Text, List[int]]]], should_raise_warning: bool
+):
+    """ResponseSelector recommends disabling hidden layers if transformer is enabled."""
+    with pytest.warns(UserWarning) as records:
+        _ = ResponseSelector(component_config=config)
+    warning_str = "We recommend to disable the hidden layers when using a transformer"
+
+    if should_raise_warning:
+        assert len(records) > 0
+        # Check all warnings since there may be multiple other warnings we don't care
+        # about in this test case.
+        assert any(warning_str in record.message.args[0] for record in records)
+    else:
+        # Check all warnings since there may be multiple other warnings we don't care
+        # about in this test case.
+        assert not any(warning_str in record.message.args[0] for record in records)
+
+
+@pytest.mark.parametrize(
+    "config, should_set_default_transformer_size",
+    [
+        # transformer enabled
+        ({NUM_TRANSFORMER_LAYERS: 5}, True),
+        ({TRANSFORMER_SIZE: 0, NUM_TRANSFORMER_LAYERS: 5}, True),
+        ({TRANSFORMER_SIZE: -1, NUM_TRANSFORMER_LAYERS: 5}, True),
+        ({TRANSFORMER_SIZE: None, NUM_TRANSFORMER_LAYERS: 5}, True),
+        ({TRANSFORMER_SIZE: 10, NUM_TRANSFORMER_LAYERS: 5}, False),
+        # transformer disabled (by default)
+        ({}, False),
+        ({TRANSFORMER_SIZE: 0}, False),
+        ({TRANSFORMER_SIZE: -1}, False),
+        ({TRANSFORMER_SIZE: None}, False),
+        ({TRANSFORMER_SIZE: 10}, False),
+        # transformer disabled explicitly
+        ({NUM_TRANSFORMER_LAYERS: 0}, False),
+        ({TRANSFORMER_SIZE: 0, NUM_TRANSFORMER_LAYERS: 0}, False),
+        ({TRANSFORMER_SIZE: -1, NUM_TRANSFORMER_LAYERS: 0}, False),
+        ({TRANSFORMER_SIZE: None, NUM_TRANSFORMER_LAYERS: 0}, False),
+        ({TRANSFORMER_SIZE: 10, NUM_TRANSFORMER_LAYERS: 0}, False),
+    ],
+)
+def test_sets_integer_transformer_size_when_needed(
+    config: Dict[Text, Optional[int]], should_set_default_transformer_size: bool,
+):
+    """ResponseSelector ensures sensible transformer size when transformer enabled."""
+    default_transformer_size = 256
+    with pytest.warns(UserWarning) as records:
+        selector = ResponseSelector(component_config=config)
+
+    warning_str = f"positive size is required when using `{NUM_TRANSFORMER_LAYERS} > 0`"
+
+    if should_set_default_transformer_size:
+        assert len(records) > 0
+        # check that the specific warning was raised
+        assert any(warning_str in record.message.args[0] for record in records)
+        # check that transformer size got set to the new default
+        assert selector.component_config[TRANSFORMER_SIZE] == default_transformer_size
+    else:
+        # check that the specific warning was not raised
+        assert not any(warning_str in record.message.args[0] for record in records)
+        # check that transformer size was not changed
+        assert selector.component_config[TRANSFORMER_SIZE] == config.get(
+            TRANSFORMER_SIZE, None  # None is the default transformer size
+        )


Code review comments:
diff_hunk: @@ -308,9 +311,88 @@ def _load_selector_params(self, config: Dict[Text, Any]) -> None:
         self.retrieval_intent = config[RETRIEVAL_INTENT]
         self.use_text_as_label = config[USE_TEXT_AS_LABEL]
 
+    def _warn_about_transformer_and_hidden_layers_enabled(
+        self, selector_name: Text
+    ) -> None:
+        """Warns user if they enabled the transformer but didn't disable hidden layers.
+
+        ResponseSelector defaults specify considerable hidden layer sizes, but
+        this is for cases where no transformer is used. If a transformer exists,
+        then the best results are chieved with no hidden layers used between the
path: rasa/nlu/selectors/response_selector.py
text: @user1:
`[...] are achieved [...]`