do_negative_feedback(model, dataset, evaluator, save_dir, feedback_dir, train_epochs=32, build_argument=None, max_iterations=0, **train_kwargs)

Runs negative feedback for multiple iterations until convergence in the form of no updates to hyperparameters or until max_iterations is reached. Returns the final model and a list of feedback outputs.

Source code in wt_ml/negative_feedback/nf_runner.py
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
def do_negative_feedback(
    model: ModType,
    dataset: EconomicDataset,
    evaluator: EvalType,
    save_dir: str | Path,
    feedback_dir: str | Path,
    train_epochs: int = 32,
    build_argument=None,
    max_iterations: int = 0,
    **train_kwargs,
) -> tuple[ModType, list[Any]]:
    """Runs negative feedback for multiple iterations until convergence in the form of no updates to hyperparameters or
    until max_iterations is reached. Returns the final model and a list of feedback outputs.
    """
    save_dir = Path(save_dir)
    did_change = True
    i = 0
    nf_feedbacks = []
    while did_change and (max_iterations == 0 or i < max_iterations):
        model, did_change, nf_output = run_negative_feedback_iteration(
            model,
            dataset,
            evaluator,
            save_dir / f"iteration_{i+1}",
            feedback_dir,
            iter_num=i,
            build_argument=build_argument,
            train_epochs=train_epochs,
            **train_kwargs,
        )
        i += 1
        nf_feedbacks.append(nf_output)
        if i % 10 == 0:
            logger.info(f"Negative feedback iteration {i}")
    logger.info(f"Negative feedback finished after {i} iterations")
    return model, nf_feedbacks

run_negative_feedback_iteration(model, dataset, evaluator, save_dir, feedback_dir, iter_num, train_epochs=32, build_argument=None, **train_kwargs)

Runs a single iteration of negative feedback comprising training, evaluations, and hyperparameter updates. Returns a new model with updated hyperparameters if recommended updates are different from the current hyperparameters.

Source code in wt_ml/negative_feedback/nf_runner.py
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
def run_negative_feedback_iteration(
    model: ModType,
    dataset: EconomicDataset,
    evaluator: EvalType,
    save_dir: str | Path,
    feedback_dir: str | Path,
    iter_num: int,
    train_epochs: int = 32,
    build_argument=None,
    **train_kwargs,
) -> tuple[ModType, bool, list[Any]]:
    """Runs a single iteration of negative feedback comprising training, evaluations, and hyperparameter updates.
    Returns a new model with updated hyperparameters if recommended updates are different from the
    current hyperparameters.
    """
    model.train(dataset, num_steps=len(dataset), epochs=train_epochs, **train_kwargs)
    updates, nf_output = evaluator(model=model, dataset=dataset, iter_num=iter_num, feedback_dir=feedback_dir)
    new_hps = deepcopy(model.hyperparameter_tree)
    did_change = False
    for key, value in updates.items():
        did_change = did_change or (get_by_path(new_hps, key) != value)
        new_hps = set_by_path(new_hps, key, value)
    if did_change:
        logger.info(f"Model changed, saving to {save_dir}")
        model.save(save_dir, include_trackers=True)
        new_model = model.from_save(
            save_dir, no_trackers=False, build_argument=build_argument, override_kwargs={"hyperparameters": new_hps}
        )
        model = new_model
    return model, did_change, nf_output

run_nf(gt_model, dataset, save_model_dir, feedback_dir=None)

Initiates the negative feedback process.

Parameters:

Name Type Description Default
gt_model ModType

Model to be used for negative feedback

required
dataset EconomicDataset

Dataset to be used for negative feedback

required
save_model_dir str | Path

Path to save the model

required
feedback_dir str | Path | None

Path to save NF output. Defaults to None.

None

Returns:

Type Description
tuple[dict[str, Any], list[Any]]

tuple[dict[str, Any], list[Any]]: Final hyperparameters and nf outputs

Source code in wt_ml/negative_feedback/nf_runner.py
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
def run_nf(
    gt_model: ModType, dataset: EconomicDataset, save_model_dir: str | Path, feedback_dir: str | Path | None = None
) -> tuple[dict[str, Any], list[Any]]:
    """Initiates the negative feedback process.

    Args:
        gt_model (ModType): Model to be used for negative feedback
        dataset (EconomicDataset): Dataset to be used for negative feedback
        save_model_dir (str | Path): Path to save the model
        feedback_dir (str | Path | None, optional): Path to save NF output. Defaults to None.

    Returns:
        tuple[dict[str, Any], list[Any]]: Final hyperparameters and nf outputs
    """
    setup_all_paths(save_model_dir, feedback_dir)
    original_values = {
        key: value for key, value in gt_model.hyperparameter_tree["impacts"].items() if isinstance(value, float)
    }
    example_input = next(iter(dataset))
    logger.info("Running negative feedback")
    gt_model, nf_feedbacks = do_negative_feedback(
        gt_model,
        dataset,
        overfit_lambda_feedback,
        save_model_dir,
        feedback_dir,
        max_iterations=32,
        train_epochs=64,
        build_argument=example_input,
        callbacks=[
            CheckpointCallback(
                frequency=32,
                root_dir=save_model_dir,
                verbosity=1,
            )
        ],
        smoothing=0.05,
        verbosity=1,
    )
    logger.info("Negative feedback complete")
    final_values = {key: get_by_path(gt_model.hyperparameter_tree, ("impacts", key)) for key in original_values.keys()}
    return final_values, nf_feedbacks

setup_all_paths(save_model_dir, feedback_dir=None)

Sets model save directory and NF output directory. If feedback_dir is None, it is set to save_model_dir/nf_feedback. If save_model_dir or feedback_dir exists, they are overwritten.

Source code in wt_ml/negative_feedback/nf_runner.py
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
def setup_all_paths(save_model_dir: str | Path, feedback_dir: str | Path | None = None):
    """Sets model save directory and NF output directory. If feedback_dir is None,
    it is set to save_model_dir/nf_feedback. If save_model_dir or feedback_dir exists, they are overwritten.
    """
    save_model_dir = Path(save_model_dir)
    if feedback_dir is None:
        feedback_dir = Path(save_model_dir) / "nf_feedback"
    else:
        feedback_dir = Path(feedback_dir)
    if save_model_dir.exists():
        shutil.rmtree(save_model_dir)

    feedback_dir.mkdir(parents=True, exist_ok=True)
    for item in feedback_dir.iterdir():
        item.unlink(missing_ok=True) if item.is_file() else shutil.rmtree(item)