83 lines
2.7 KiB
Python
83 lines
2.7 KiB
Python
import torch
|
|||
|
|
from sklearn.linear_model import LogisticRegression
|
||
|
|
from sklearn.preprocessing import StandardScaler
|
||
|
|
|
||
|
|
|
||
|
|
class LogisticProber:
|
||
|
|
def __init__(self):
|
||
|
|
self.scaler = StandardScaler()
|
||
|
|
# `penalty="l2"` is the default and was deprecated in scikit-learn 1.8;
|
||
|
|
# naming it explicitly stops working in 1.10.
|
||
|
|
self.clf = LogisticRegression(
|
||
|
|
C=1.0, class_weight="balanced", max_iter=1000, random_state=42
|
||
|
|
)
|
||
|
|
|
||
|
|
def fit_predict(self, X_train, y_train, X_test):
|
||
|
|
"""Predictions on the test events, or None if either pool is too small.
|
||
|
|
|
||
|
|
Returning the predictions rather than one score lets the caller report
|
||
|
|
the probe with the same metrics as the zero-shot readout.
|
||
|
|
"""
|
||
|
|
if len(y_train) < 10 or len(X_test) < 10:
|
||
|
|
return None
|
||
|
|
|
||
|
|
self.clf.fit(self.scaler.fit_transform(X_train), y_train)
|
||
|
|
return self.clf.predict(self.scaler.transform(X_test))
|
||
|
|
|
||
|
|
|
||
|
|
def get_param_groups(named_parameters, weight_decay):
|
||
|
|
"""Decay matrices only.
|
||
|
|
|
||
|
|
Norm gains, biases, and embedding tables are 1-D; shrinking them toward
|
||
|
|
zero costs capacity without the regularizing effect it has on weight
|
||
|
|
matrices. Frozen parameters are dropped so they never reach the optimizer.
|
||
|
|
"""
|
||
|
|
decay, no_decay = [], []
|
||
|
|
for _, parameter in named_parameters:
|
||
|
|
if not parameter.requires_grad:
|
||
|
|
continue
|
||
|
|
(decay if parameter.ndim >= 2 else no_decay).append(parameter)
|
||
|
|
return [
|
||
|
|
{"params": decay, "weight_decay": weight_decay},
|
||
|
|
{"params": no_decay, "weight_decay": 0.0},
|
||
|
|
]
|
||
|
|
|
||
|
|
|
||
|
|
def get_adamw_optimizer(params, lr, weight_decay):
|
||
|
|
return torch.optim.AdamW(params, lr=lr, weight_decay=weight_decay)
|
||
|
|
|
||
|
|
|
||
|
|
def get_cosine_warmup_scheduler(optimizer, total_steps, warmup_ratio=0.1, min_lr=None):
|
||
|
|
total_steps = max(1, int(total_steps))
|
||
|
|
warmup_steps = min(int(total_steps * warmup_ratio), total_steps - 1)
|
||
|
|
decay_steps = max(1, total_steps - warmup_steps)
|
||
|
|
|
||
|
|
max_lr = optimizer.param_groups[0]["lr"]
|
||
|
|
min_lr = max_lr * 0.01 if min_lr is None else min_lr
|
||
|
|
|
||
|
|
cosine = torch.optim.lr_scheduler.CosineAnnealingLR(
|
||
|
|
optimizer, T_max=decay_steps, eta_min=min_lr
|
||
|
|
)
|
||
|
|
|
||
|
|
if warmup_steps == 0:
|
||
|
|
return cosine
|
||
|
|
|
||
|
|
warmup = torch.optim.lr_scheduler.LinearLR(
|
||
|
|
optimizer, start_factor=0.01, end_factor=1.0, total_iters=warmup_steps
|
||
|
|
)
|
||
|
|
|
||
|
|
return torch.optim.lr_scheduler.SequentialLR(
|
||
|
|
optimizer, schedulers=[warmup, cosine], milestones=[warmup_steps]
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
def get_optimizer_cfg(optimizer, scheduler=None):
|
||
|
|
cfg = {"optimizer": optimizer}
|
||
|
|
if scheduler:
|
||
|
|
cfg["lr_scheduler"] = {
|
||
|
|
"scheduler": scheduler,
|
||
|
|
"interval": "step",
|
||
|
|
"frequency": 1,
|
||
|
|
}
|
||
|
|
return cfg
|