ConcavePolyCurve

Bases: Module

Source code in wt_ml/layers/concave_poly_curve.py
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
class ConcavePolyCurve(Module):
    def __init__(
        self,
        encodings: pd.DataFrame,
        hierarchy_categories: list[str | list[str]] | None = None,
        hyperparameters: Hyperparams | None = None,
        name: str | None = None,
    ):
        super().__init__(hyperparameters=hyperparameters, name=name)
        self.encodings = encodings
        self.hierarchy_categories = hierarchy_categories

    def build(self, input_shapes):  # noqa: U100
        self.min_exponent = self.hyperparameters.get_float(
            "min_exponent",
            default=0.1,
            min=0.01,
            max=0.99,
            help="The minimum value to use for the exponent in the polynomial. Can range from this to 1.0.",
        )
        self.params_emb_layer = self.hyperparameters.get_submodule(
            "params_emb",
            module_type=HierchicalEmbedding,
            kwargs=dict(
                encodings=self.encodings,
                shape=[1],
                columns=self.hierarchy_categories,
                feature_names=["exponent"],
            ),
            help="The parameter embeddings for the concave polynomial curve layer.",
        )

    def __call__(
        self,
        batch: CurveInput,
        training=False,
        debug: bool = False,
        skip_metrics: bool = False,
    ) -> ConcavePolyCurveIntermediaries:  # noqa: U100
        """Computes the value of the custom function f(x) = (1-c)(x)^p + c with custom bounds."""
        exponent_emb = tf.squeeze(
            tf.expand_dims(
                self.params_emb_layer(batch.hierarchy, training=training, skip_metrics=skip_metrics, debug=debug), 1
            ),
            axis=3,
        )
        # Exponent value is lower bounded to 0.1 to avoid extreme flat curves
        exponent = monotonic_sigmoid(exponent_emb) * (1 - self.min_exponent) + self.min_exponent
        # Epsilon is added to the signal to avoid nan-losses
        impact_by_signal = tf.math.pow(batch.spends + tf.constant(EPSILON, dtype=tf.float32), exponent)
        return ConcavePolyCurveIntermediaries(
            exponent_emb=exponent_emb if debug else None,
            exponent=exponent if debug else None,
            impact_by_signal=impact_by_signal,
        )

__call__(batch, training=False, debug=False, skip_metrics=False)

Computes the value of the custom function f(x) = (1-c)(x)^p + c with custom bounds.

Source code in wt_ml/layers/concave_poly_curve.py
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
def __call__(
    self,
    batch: CurveInput,
    training=False,
    debug: bool = False,
    skip_metrics: bool = False,
) -> ConcavePolyCurveIntermediaries:  # noqa: U100
    """Computes the value of the custom function f(x) = (1-c)(x)^p + c with custom bounds."""
    exponent_emb = tf.squeeze(
        tf.expand_dims(
            self.params_emb_layer(batch.hierarchy, training=training, skip_metrics=skip_metrics, debug=debug), 1
        ),
        axis=3,
    )
    # Exponent value is lower bounded to 0.1 to avoid extreme flat curves
    exponent = monotonic_sigmoid(exponent_emb) * (1 - self.min_exponent) + self.min_exponent
    # Epsilon is added to the signal to avoid nan-losses
    impact_by_signal = tf.math.pow(batch.spends + tf.constant(EPSILON, dtype=tf.float32), exponent)
    return ConcavePolyCurveIntermediaries(
        exponent_emb=exponent_emb if debug else None,
        exponent=exponent if debug else None,
        impact_by_signal=impact_by_signal,
    )