Discord

Checklist NEOAI 2026 Day 2 · Task 6

SOTA-AI Editorial

CutiesNLP

Answer 1,000 multiple-choice questions using a stripped Qwen3.5-2B model whose embedding table, first layer and language-modelling head have been removed.

Written
25 October 2026
Result
0.763 accuracy on the private test set
Olympiad
Northern Eurasia Olympiad in Artificial Intelligence (Northern Eurasia OAI), 2026 · Day 2

Hints

Hint 1

What is the purpose of the final layers?

Hint 2

Which layers provide the most useful representations for this task?

The solution in one line

Extract hidden states from different layers and use them as features for a logistic regression classifier.

The editorial

Solution

The baseline extracts the last hidden state and trains a logistic regression classifier. However, the last layer may produce less useful representations for this task because its outputs are optimized for next-token prediction. We hypothesized that intermediate layers contain more useful features for this task.

After experimenting with each layer and using cross-validation, we obtained the following results. Each logistic regression uses C=0.01.

Layer Train acc Val acc
layer 0 0.778 0.280
layer 1 0.828 0.400
layer 2 0.912 0.490
layer 3 0.933 0.530
layer 4 0.972 0.450
layer 5 0.967 0.460
layer 6 0.963 0.480
layer 7 0.985 0.430
layer 8 0.990 0.510
layer 9 0.997 0.550
layer 10 0.997 0.640
layer 11 0.997 0.690
layer 12 0.997 0.710
layer 13 0.993 0.740
layer 14 1.000 0.750
layer 15 0.988 0.750
layer 16 0.988 0.710
layer 17 0.988 0.710
layer 18 0.988 0.700
layer 19 0.988 0.670
layer 20 0.988 0.440
layer 21 0.965 0.400
layer 22 0.948 0.470
layer 23 0.907 0.420

Using each of the three layers with the highest validation accuracy (layers 13, 14, and 15), we obtained the test accuracies reported in the Results section.

After experimenting with individual layers, we tried combining multiple layers by concatenating hidden states.

Layers Train acc Val acc
layer 13, 14 1.000 0.750
layer 13, 15 1.000 0.750
layer 14, 15 1.000 0.750
layer 13, 14, 15 1.000 0.760

Results

Method Public score Private score
baseline 0.370 0.348
layer 13 0.760 0.748
layer 14 0.752 0.763
layer 15 0.731 0.750
layer 13, 14 0.762 0.763
layer 13, 15 0.750 0.748
layer 14, 15 0.739 0.753
layer 13, 14, 15 0.754 0.751

Running Time

The solution using layers 13 and 14 takes approximately 2 minutes on a T4. Experimenting with all layers and some combinations, as in the Solution section, takes an additional minute.

Code

Solution code solution.py · 78 lines
import numpy as np
import torch
from sklearn.model_selection import StratifiedKFold
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline


def get_hs(model, train, test):
    Xs = []
    y = []
    y2 = []

    for idx in range(len(train)):
        data = train[idx]
        pos = data["eol_positions"]
        cr = data["correct_idx"]
        embs = torch.from_numpy(data["embeds_after_l0"]).unsqueeze(0).cuda().half()
        with torch.no_grad():
            out = model.model(inputs_embeds=embs, output_hidden_states=True)
        hs = torch.cat(out.hidden_states)
        for i in range(4):
            Xs.append(hs[:, pos[i]].cpu().numpy())
            y.append(int(i == cr))
        y2.append(cr)

    Xs = np.stack(Xs).reshape(len(Xs) // 4, 4, 24, -1)
    y = np.array(y).reshape(len(y) // 4, 4)
    y2 = np.array(y2)

    Xs_test = []

    for idx in range(len(test)):
        data = test[idx]
        pos = data["eol_positions"]
        embs = torch.from_numpy(data["embeds_after_l0"]).unsqueeze(0).cuda().half()
        with torch.no_grad():
            out = model.model(inputs_embeds=embs, output_hidden_states=True)
        hs = torch.cat(out.hidden_states)
        for i in range(4):
            Xs_test.append(hs[:, pos[i]].cpu().numpy())

    Xs_test = np.stack(Xs_test).reshape(len(Xs_test) // 4, 4, 24, -1)

    return Xs, y, y2, Xs_test


def evaluate(Xs, y, y2, ly):
    X_layer = Xs[:, :, ly]

    train_accs = []
    val_accs = []

    skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=0)

    for train_idx, val_idx in skf.split(X_layer, y2):
        X_train = X_layer[train_idx].reshape(4 * len(train_idx), -1)
        X_val = X_layer[val_idx].reshape(4 * len(val_idx), -1)

        y_train = y[train_idx].reshape(-1)

        clf = Pipeline([
            ("scaler", StandardScaler()),
            ("logreg", LogisticRegression(random_state=0, max_iter=1000, C=1e-2)),
        ])

        clf.fit(X_train, y_train)

        pred = clf.predict_proba(X_train)[:, 1]
        train_acc = (pred.reshape(-1, 4).argmax(axis=1) == y2[train_idx]).mean()

        pred = clf.predict_proba(X_val)[:, 1]
        val_acc = (pred.reshape(-1, 4).argmax(axis=1) == y2[val_idx]).mean()

        train_accs.append(train_acc)
        val_accs.append(val_acc)

    return np.mean(train_accs), np.mean(val_accs)


def experiment(Xs, y, y2):
    for ly in range(24):
        train_acc, val_acc = evaluate(Xs, y, y2, ly)

        print(f"Layer {ly}" f" {train_acc:.3f}" f" {val_acc:.3f}")

    for ly in [[13, 14], [13, 15], [14, 15], [13, 14, 15]]:
        train_acc, val_acc = evaluate(Xs, y, y2, ly)

        print(f"Layer {ly}" f" {train_acc:.3f}" f" {val_acc:.3f}")


def solution(model, train, test):
    Xs, y, y2, Xs_test = get_hs(model, train, test)

    ly = [13, 14]

    X = Xs[:, :, ly]
    X = X.reshape(len(X) * 4, -1)

    clf = Pipeline([
        ("scaler", StandardScaler()),
        ("logreg", LogisticRegression(random_state=0, max_iter=1000, C=1e-2)),
    ]).fit(X, y.reshape(-1))

    X_test = Xs_test[:, :, ly]
    X_test = X_test.reshape(len(X_test) * 4, -1)

    test_preds = clf.predict_proba(X_test)[:, 1].reshape(-1, 4).argmax(axis=1)

    return test_preds

Download solution.py

Editorials are written by members of the SOTA community, not by the olympiad. The official statement and scoring win wherever an editorial differs.