import argparse, warnings, sys
from pathlib import Path
import numpy as np
import pandas as pd
from sklearn.neural_network import MLPRegressor
from sklearn.ensemble import RandomForestRegressor, BaggingRegressor
from sklearn.dummy import DummyRegressor
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler, FunctionTransformer
from sklearn.impute import SimpleImputer
from scipy.stats import wilcoxon
warnings.filterwarnings("ignore")
D = "/work/project/project/user"
OUT = Path(f"{D}/analysis/out"); OUT.mkdir(parents=True, exist_ok=True)
F_PEAK = 2.25e9
SEEDS = (0, 1, 2, 3, 4)
sys.path.insert(0, f"{D}/analysis")
from train_nn2 import features, signed_log1p, factors, load
def nn(hidden=(32, 16), alpha=1.0, bag=1):
def fn(seed):
base = MLPRegressor(hidden_layer_sizes=hidden, alpha=alpha,
solver="lbfgs", max_iter=5000, random_state=seed)
est = base if bag == 1 else BaggingRegressor(
estimator=base, n_estimators=bag, max_samples=0.8,
random_state=seed, n_jobs=-1)
return Pipeline([("impute", SimpleImputer(strategy="median")),
("log", FunctionTransformer(signed_log1p, validate=False)),
("scale", StandardScaler()),
("est", est)])
return fn
def plain(est_fn):
return lambda s: Pipeline([("impute", SimpleImputer(strategy="median")),
("scale", StandardScaler()),
("est", est_fn(s))])
def loao(fn, X, y, t_an, eta, groups, seeds=SEEDS):
acc = np.zeros(len(y))
for s in seeds:
for app in sorted(groups.unique()):
te = (groups == app).values
m = fn(s); m.fit(X[~te], np.log10(eta[~te]))
p = t_an[te] / (10 ** m.predict(X[te]))
acc[te] += factors(p, y[te])
return acc / len(seeds)
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--bag", type=int, default=1)
a = ap.parse_args()
df, Xall, y, t_an, eta = load(f"{D}/data/runs_persets.csv", per_set=True)
X = Xall[[c for c in Xall.columns if not c.endswith("__missing")]]
g = df.app
L = []
say = lambda s="": (print(s), L.append(s))
say("Final neural-network configuration")
say("=" * 78)
say(f"{len(df)} samples (per-counter-set), {X.shape[1]} features, "
f"{g.nunique()} applications")
say("Leave-one-application-out; median of 5 seeds; error = multiplicative factor")
say("")
models = {
"MLP final (32,16) a=1.0": nn((32, 16), 1.0, a.bag),
"MLP original recipe": lambda s: Pipeline([
("i", SimpleImputer(strategy="median")), ("sc", StandardScaler()),
("e", MLPRegressor(hidden_layer_sizes=(32, 16, 8), alpha=10.0,
max_iter=20000, random_state=s))]),
"Random Forest": plain(lambda s: RandomForestRegressor(
n_estimators=500, min_samples_leaf=2, random_state=s, n_jobs=-1)),
"Constant baseline": plain(lambda s: DummyRegressor(strategy="mean")),
}
res = {}
for name, fn in models.items():
seeds = (0,) if "Forest" in name or "Constant" in name else SEEDS
res[name] = loao(fn, X, y, t_an, eta, g, seeds)
say("Overall (median error factor):")
for k, v in sorted(res.items(), key=lambda kv: np.median(kv[1])):
say(f" {k:28s} {np.median(v):.3f}")
say("")
say("Per-application median error factor:")
tb = pd.DataFrame({k: v for k, v in res.items()}).assign(app=g.values) \
.groupby("app").median().round(3)
say(tb.to_string())
say("")
say("Paired significance (Wilcoxon, n=%d):" % len(y))
fin = res["MLP final (32,16) a=1.0"]
for other in ["MLP original recipe", "Constant baseline", "Random Forest"]:
o = res[other]
try:
_, p = wilcoxon(fin, o)
except ValueError:
p = float("nan")
verdict = ("MLP better" if np.median(fin) < np.median(o) else "MLP worse")
sig = "significant" if p < 0.05 else "not significant"
say(f" vs {other:24s} wins {int((fin<o).sum()):3d}/{len(fin)} "
f"p={p:.4f} ({verdict}, {sig})")
say("")
m = (g != "stream").values
say("Excluding STREAM (extrapolation fold; 0% of its rows lie inside the")
say("training range for stall_load_frac and l3_miss_per_instr):")
for k, v in sorted(res.items(), key=lambda kv: np.median(kv[1][m])):
say(f" {k:28s} {np.median(v[m]):.3f}")
txt = "\n".join(L)
(OUT / "nn_final_summary.txt").write_text(txt + "\n")
pd.DataFrame({**{k: v for k, v in res.items()},
"app": g.values, "ncore": df.ncore.values,
"cset": df.cset.values}).to_csv(OUT / "nn_final_perrow.csv",
index=False)
if __name__ == "__main__":
main()