Skip to main content

Scikit-learn friendly library to explain, predict, and steer text models/data.
Also a bunch of utilities for getting started with text data.

📖 demo notebooks

Explainable modeling/steering

Model Reference Output Description
Tree-Prompt 🗂️, 🔗, 📄, 📖, Explanation
+ Steering
Generates a tree of prompts to
steer an LLM (Official)
iPrompt 🗂️, 🔗, 📄, 📖 Explanation
+ Steering
Generates a prompt that
explains patterns in data (Official)
AutoPrompt ㅤㅤ🗂️, 🔗, 📄 Explanation
+ Steering
Find a natural-language prompt
using input-gradients
D3 🗂️, 🔗, 📄, 📖 Explanation Explain the difference between two distributions
SASC ㅤㅤ🗂️, 🔗, 📄 Explanation Explain a black-box text module
using an LLM (Official)
Aug-Linear 🗂️, 🔗, 📄, 📖 Linear model Fit better linear model using an LLM
to extract embeddings (Official)
Aug-Tree 🗂️, 🔗, 📄, 📖 Decision tree Fit better decision tree using an LLM
to expand features (Official)
QAEmb 🗂️, 🔗, 📄, 📖 Explainable
embedding
Generate interpretable embeddings
by asking LLMs questions (Official)
KAN 🗂️, 🔗, 📄, 📖 Small
network
Fit 2-layer Kolmogorov-Arnold network

📖Demo notebooks   🗂️ Doc   🔗 Reference code   📄 Research paper
⌛ We plan to support other interpretable algorithms like RLPrompt, CBMs, and NBDT. If you want to contribute an algorithm, feel free to open a PR 😄

General utilities

Model Reference
🗂️ LLM wrapper Easily call different LLMs
🗂️ Dataset wrapper Download minimially processed huggingface datasets
🗂️ Bag of Ngrams Learn a linear model of ngrams
🗂️ Linear Finetune Finetune a single linear layer on top of LLM embeddings

Quickstart

Installation: pip install imodelsx (or, for more control, clone and install from source)

Set up your LLM: use local huggingface models or API models from OpenAI, Anthropic, Claude Code, or Codex

Every method that takes a checkpoint / llm_checkpoint calls LLMs through imodelsx.llm.get_llm. Pick a provider by prefixing the checkpoint with provider: (or let it be inferred from the name):

Provider Example checkpoint Credentials Install
hf (default) gpt2, Qwen/Qwen2.5-0.5B-Instruct, a local path HF_TOKEN (only for gated models) included
hf-api hf-api:meta-llama/Llama-3.1-8B-Instruct HF_TOKEN included
openai gpt-4o-mini, openai:gpt-5 OPENAI_API_KEY (OPENAI_BASE_URL for compatible servers) pip install "imodelsx[openai]"
azure azure:gpt-4o AZURE_OPENAI_ENDPOINT + AZURE_OPENAI_API_KEY, or Azure CLI login pip install "imodelsx[openai]"
anthropic claude-haiku-5-5, anthropic:claude-opus-5-5 ANTHROPIC_API_KEY pip install "imodelsx[anthropic]"
claude-code claude-code:haiku, claude-code:sonnet your Claude Code login (no key needed) Claude Code CLI
codex codex:gpt-5-codex, codex:default your Codex login (codex login) or OPENAI_API_KEY npm i -g @openai/codex

Keys are read from the api_key argument, then the environment variable, then a file at ~/.<ENV_VAR> (e.g. ~/.OPENAI_API_KEY). Without a prefix, gpt-*/o* names use openai and claude-* names use anthropic (falling back to azure / claude-code when no key is found); anything else loads a local huggingface model.

import imodelsx.llm
llm = imodelsx.llm.get_llm('claude-code:haiku')  # or 'gpt-4o-mini', 'Qwen/Qwen2.5-0.5B-Instruct', ...
llm('What is the capital of Spain?')  # outputs are cached in ~/.CACHE_LLM
llm(['prompt 1', 'prompt 2'])  # API models run lists of prompts in parallel threads
llm = imodelsx.llm.get_llm('gpt-4o-mini', api_key='sk-...')  # pass a key directly

Methods that need next-token probabilities or embeddings (e.g. Tree-Prompt, Aug-Linear, linear finetuning) require a local hf model; methods that only generate text (e.g. SASC, QA-Emb, Aug-Tree keyword expansion) work with any provider.

Demos: see the demo notebooks

Natural-language explanations

Tree-prompt

from imodelsx import TreePromptClassifier
import datasets
import numpy as np
from sklearn.tree import plot_tree
import matplotlib.pyplot as plt

# set up data
rng = np.random.default_rng(seed=42)
dset_train = datasets.load_dataset('rotten_tomatoes')['train']
dset_train = dset_train.select(rng.choice(
    len(dset_train), size=100, replace=False))
dset_val = datasets.load_dataset('rotten_tomatoes')['validation']
dset_val = dset_val.select(rng.choice(
    len(dset_val), size=100, replace=False))

# set up arguments
prompts = [
    "This movie is",
    " Positive or Negative? The movie was",
    " The sentiment of the movie was",
    " The plot of the movie was really",
    " The acting in the movie was",
]
verbalizer = {0: " Negative.", 1: " Positive."}
checkpoint = "gpt2"

# fit model
m = TreePromptClassifier(
    checkpoint=checkpoint,
    prompts=prompts,
    verbalizer=verbalizer,
    cache_prompt_features_dir=None,  # 'cache_prompt_features_dir/gp2',
)
m.fit(dset_train["text"], dset_train["label"])


# compute accuracy
preds = m.predict(dset_val['text'])
print('\nTree-Prompt acc (val) ->',
      np.mean(preds == dset_val['label']))  # -> 0.7

# compare to accuracy for individual prompts
for i, prompt in enumerate(prompts):
    print(i, prompt, '->', m.prompt_accs_[i])  # -> 0.65, 0.5, 0.5, 0.56, 0.51

# visualize decision tree
plot_tree(
    m.clf_,
    fontsize=10,
    feature_names=m.feature_names_,
    class_names=list(verbalizer.values()),
    filled=True,
)
plt.show()

iPrompt

from imodelsx import explain_dataset_iprompt, get_add_two_numbers_dataset

# get a simple dataset of adding two numbers
input_strings, output_strings = get_add_two_numbers_dataset(num_examples=100)
for i in range(5):
    print(repr(input_strings[i]), repr(output_strings[i]))

# explain the relationship between the inputs and outputs
# with a natural-language prompt string
prompts, metadata = explain_dataset_iprompt(
    input_strings=input_strings,
    output_strings=output_strings,
    checkpoint='EleutherAI/gpt-j-6B', # which language model to use
    num_learned_tokens=3, # how long of a prompt to learn
    n_shots=3, # shots per example
    n_epochs=15, # how many epochs to search
    verbose=0, # how much to print
    llm_float16=True, # whether to load the model in float_16
)
--------
prompts is a list of found natural-language prompt strings

D3 (DescribeDistributionalDifferences)

from imodelsx import explain_dataset_d3
hypotheses, hypothesis_scores = explain_dataset_d3(
    pos=positive_samples, # List[str] of positive examples
    neg=negative_samples, # another List[str]
    num_steps=100,
    num_folds=2,
    batch_size=64,
)

SASC

Here, we explain a module rather than a dataset

from imodelsx import explain_module_sasc
# a toy module that responds to the length of a string
mod = lambda str_list: np.array([len(s) for s in str_list])

# a toy dataset where the longest strings are animals
text_str_list = ["red", "blue", "x", "1", "2", "hippopotamus", "elephant", "rhinoceros"]
explanation_dict = explain_module_sasc(
    text_str_list,
    mod,
    ngrams=1,
)

Aug-imodels

Use these just a like a scikit-learn model. During training, they fit better features via LLMs, but at test-time they are extremely fast and completely transparent.

from imodelsx import AugLinearClassifier, AugTreeClassifier, AugLinearRegressor, AugTreeRegressor
import datasets
import numpy as np

# set up data
dset = datasets.load_dataset('rotten_tomatoes')['train']
dset = dset.select(np.random.choice(len(dset), size=300, replace=False))
dset_val = datasets.load_dataset('rotten_tomatoes')['validation']
dset_val = dset_val.select(np.random.choice(len(dset_val), size=300, replace=False))

# fit model
m = AugLinearClassifier(
    checkpoint='textattack/distilbert-base-uncased-rotten-tomatoes',
    ngrams=2, # use bigrams
)
m.fit(dset['text'], dset['label'])

# predict
preds = m.predict(dset_val['text'])
print('acc_val', np.mean(preds == dset_val['label']))

# interpret
print('Total ngram coefficients: ', len(m.coefs_dict_))
print('Most positive ngrams')
for k, v in sorted(m.coefs_dict_.items(), key=lambda item: item[1], reverse=True)[:8]:
    print('\t', k, round(v, 2))
print('Most negative ngrams')
for k, v in sorted(m.coefs_dict_.items(), key=lambda item: item[1])[:8]:
    print('\t', k, round(v, 2))

KAN

import imodelsx
from sklearn.datasets import make_classification, make_regression
from sklearn.metrics import accuracy_score
import numpy as np

X, y = make_classification(n_samples=5000, n_features=5, n_informative=3)
model = imodelsx.KANClassifier(hidden_layer_size=64, device='cpu',
                               regularize_activation=1.0, regularize_entropy=1.0)
model.fit(X, y)
y_pred = model.predict(X)
print('Test acc', accuracy_score(y, y_pred))

# now try regression
X, y = make_regression(n_samples=5000, n_features=5, n_informative=3)
model = imodelsx.kan.KANRegressor(hidden_layer_size=64, device='cpu',
                                  regularize_activation=1.0, regularize_entropy=1.0)
model.fit(X, y)
y_pred = model.predict(X)
print('Test correlation', np.corrcoef(y, y_pred.flatten())[0, 1])

General utilities

Easy baselines

Easy-to-fit baselines that follow the sklearn API.

from imodelsx import LinearFinetuneClassifier, LinearNgramClassifier
# fit a simple one-layer finetune on top of LLM embeddings
m = LinearFinetuneClassifier(
    checkpoint='distilbert-base-uncased',
)
m.fit(dset['text'], dset['label'])
preds = m.predict(dset_val['text'])
acc = (preds == dset_val['label']).mean()
print('validation acc', acc)

LLM wrapper

Easy API for calling different language models with caching (much more lightweight than langchain).

import imodelsx.llm
# supports huggingface, openai, anthropic, claude code, and codex checkpoints (see LLM providers in the quickstart)
llm = imodelsx.llm.get_llm(
    checkpoint="gpt2-xl",  # gpt-4o-mini, claude-haiku-5-5, claude-code:haiku, codex:gpt-5-codex, ...
    CACHE_DIR=".cache",
)
out = llm("May the Force be")
llm("May the Force be") # when computing the same string again, uses the cache

Data wrapper

API for loading huggingface datasets with basic preprocessing.

import imodelsx.data
dset, dataset_key_text = imodelsx.data.load_huggingface_dataset('ag_news')
# Ensures that dset has a split named 'train' and 'validation',
# and that the input data is contained for each split in a column given by {dataset_key_text}

Related work

  • imodels package (JOSS 2021 github) - interpretable ML package for concise, transparent, and accurate predictive modeling (sklearn-compatible).
  • Rethinking Interpretability in the Era of Large Language Models (arXiv 2024 pdf) - overview of using LLMs to interpret datasets and yield natural-language explanations
  • Experiments in using clinical rule development: github
  • Experiments in automatically generating brain explanations: github
  • Interpretation regularization (ICML 2020 pdf, github) - penalizes CD / ACD scores during training to make models generalize better

Metadata

Release files for imodelsx 1.0.14

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for imodelsx 1.0.14
File Size Uploaded
imodelsx-1.0.14.tar.gz 119.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for imodelsx 1.0.14
File Interpreter ABI Platform
imodelsx-1.0.14-py3-none-any.whl Python 3 none any Details

Total release size: 244.2 kB

Release files / imodelsx-1.0.14.tar.gz

Download URL imodelsx-1.0.14.tar.gz
Size 119.1 kB
Tags Source
SHA-256 checksum
How to use checksums
33f7c8c122ec1b482533ab9211f86e4ba38d7cd67ae188a31342be1c6806f3ee
BLAKE2b-256 checksum
How to use checksums
7ba03b65210c6f0952fbfe9d8363ed302eb21c64120eff2cd3a76121f887689d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"22.04","id":"jammy","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / imodelsx-1.0.14-py3-none-any.whl

Download URL imodelsx-1.0.14-py3-none-any.whl
Size 125.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f287564b05811977e379dba59f26995886c1186405da6fca5aa3cf1105eea4d2
BLAKE2b-256 checksum
How to use checksums
fb24b486a1ecac1ce47f6db9e2a6e736798ef0690379298d8c6247cd37e3ef7e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"22.04","id":"jammy","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release history Release notifications | RSS feed

This release

1.0.14 This release

2 release files

1.0.13

2 release files

1.0.12

2 release files

1.0.11

2 release files

1.0.10

2 release files

1.0.9

2 release files

1.0.8

2 release files

1.0.7

2 release files

1.0.6

2 release files

1.0.5

2 release files

1.0.4

2 release files

1.0.3

2 release files

1.0.2

2 release files

1.0.1

2 release files

1.0.0

2 release files

0.31

2 release files

0.30

2 release files

0.22

2 release files

0.21

2 release files

0.20

2 release files

0.12

2 release files

0.11

2 release files

0.10

2 release files

0.9

2 release files

0.8

2 release files

0.7

2 release files

0.6

2 release files

0.5

2 release files

0.4.3

2 release files

0.4.2

2 release files

0.4.1

2 release files

0.4

3 release files

0.3

2 release files

0.2

2 release files

0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page