# Evolutionary prompt optimization for SAE feature visualization

TLDR:

*   [Fluent dreaming for language models](https://arxiv.org/abs/2402.01702) is an algorithm based on [the GCG method](https://arxiv.org/abs/2307.15043) that can reliably find plain-text readable prompts for LLMs that maximize certain logits or residual stream directions by using gradients and genetic algorithms. Authors showed its use for visualizing MLP neurons. We show this method can also help interpret SAE features.
*   We reimplement the algorithm in the paper, adapt it based on suggestions from the authors and apply it to some interesting residual stream SAE latents in GPT-2 Small and Gemma 1 2B. The prompts mostly match the kind of text one would expect to activate a feature from looking at the max activating examples. We find prompts that activate features more than any dataset examples for GPT-2 (24576 prompts of 128 tokens). We can find examples that highly activate two features at once. We find examples for refusal-like features from [our refusal features post](https://www.lesswrong.com/posts/k8bBx4HcTF9iyikma/sae-features-for-refusal-and-sycophancy-steering-vectors) and induction/repetition-like features from [our ICL features post](https://www.lesswrong.com/posts/5FGXmJ3wqgGRcbyH7/extracting-sae-task-features-for-in-context-learning).
*   We believe this technique is useful is similar contexts as [self-explanation](https://www.lesswrong.com/posts/8ev6coxChSWcxCDy8/self-explaining-sae-features) – interpreting directions in the absence of a dataset during early experimentation in a cheaper way for individual features. The major differences are that this technique doesn’t have a minimum requirement for model size (because it doesn’t rely on the model’s verbalization capability) and takes longer to run (<1min vs 5min)
*   We visualize a few known features and 200 random features for Gemma 1 2B. The results can be viewed at [https://neverix.github.io/epo-visualizer/](https://neverix.github.io/epo-visualizer/)

Introduction
============

Methods like EPO try to solve a problem similar to [SolidGoldMagikarp (plus, prompt generation)](https://www.lesswrong.com/posts/aPeJE8bSo6rAFoLqg/solidgoldmagikarp-plus-prompt-generation). To give a brief overview:

Neural networks contain features[^mwj6sdgeu6i] that activate more or less strongly on different examples. One common way to interpret features in vision models is to go through a dataset, record activations of the feature on each image, and show the highest-activating images for each feature.

![](https://39669.cdn.cke-cs.com/rQvD3VnunXZu34m86e5f/images/f06c38b70f236ffdc44a012bc495389d2649227baecaffce.png)

An example of vision model interpretation by optimizing examples from [https://distill.pub/2017/feature-visualization/](https://distill.pub/2017/feature-visualization/). Optimization makes the objects the neuron is looking for more clear.

There is one obvious problem with this: if there is a pattern that is rare or never appears in the dataset, it's possible the maximum activating examples computed from the dataset will be misleading: [https://arxiv.abs/2104.07143](https://arxiv.abs/2104.07143). As an example, in the figure above, Unit 453 seems to look at fluffy things including clouds and ropes. That is clear from the optimized example, but, if the reader just looked at some of the top activating dataset examples, they might think it activates on clouds with the sky as a background.

We can try to tweak the image without looking at data to activate a given neuron. If we do this for long enough with SGD and add a few regularizers that make the image look clear to human eyes and not noisy, we get a somewhat understandable image that activates a given neuron.

![](https://39669.cdn.cke-cs.com/rQvD3VnunXZu34m86e5f/images/f7236279cb7d02bb2c29864b2f652beb52f0f080256c4238.png)

[https://distill.pub/2017/feature-visualization/](https://distill.pub/2017/feature-visualization/), contains additional details

This regularization includes mostly smoothness constraints. It is similar to the technique behind DeepDream (but more specialized) [and has been previously used for AI art in conjunction with CLIP](https://arxiv.org/abs/2204.08583). If we don't include the regularization, the images are most often noise or very high-contrast. Adversarial examples are what happens if the regularization is keeping the image close to another starting image. They can make the model do things that would give it high loss in training, or just about anything you optimize the input for.

All of this is possible because images are arrays of floating point numbers and functions on them can be differentiated. There is no obvious way to apply the same techniques to language models. An early one is ["Backwards" from the SolidGoldMagikarp post](https://www.lesswrong.com/posts/aPeJE8bSo6rAFoLqg/solidgoldmagikarp-plus-prompt-generation). It was not applied to visualizing hidden features and required a lot of tuning. It also produced prompts that weren't very sensible, so it seems more similar to producing adversarial examples than feature visualization.

![](https://res.cloudinary.com/lesswrong-2-0/image/upload/v1675551031/mirroredImages/aPeJE8bSo6rAFoLqg/v8fs4ftghqsztccszhv8.png)

Figure credit: [SolidGoldMagikarp (plus, prompt generation)](https://www.lesswrong.com/posts/aPeJE8bSo6rAFoLqg/solidgoldmagikarp-plus-prompt-generation)

In 2023, Zou et al. came up with a simple method for finding token-based prompts that disable refusal in chat-trained language models: [Greedy Coordinate-wise Gradient](https://llm-attacks.org/). It samples many random prompts using information from gradients (similar to [https://arxiv.org/abs/2102.04509](https://arxiv.org/abs/2102.04509)) and selects the best one according to the metric (the negative probability of a harmful completion).

![](https://39669.cdn.cke-cs.com/rQvD3VnunXZu34m86e5f/images/541d6d6949cd319d4245f57d02783895f34f898ce0fd5888.png)

Source: [https://llm-attacks.org/](https://llm-attacks.org/)

The resulting prompts usually didn’t make sense and were composed of random or glitch tokens. This means that outputs from it are not as useful for understanding what features the network looks at. The authors also didn't apply the algorithm to hidden features.

[Evolutionary prompt optimization](https://www.lesswrong.com/posts/yrP2H8beNoXghg2Gp/fluent-dreaming-for-language-models-ai-interpretability) (EPO) is a downstream method for finding prompts that not only make the model do something, but also keep the prompt human-readable by integrating a *fluency penalty*, which is a term in the loss for the log likelihood of the prompt with the penalty coefficients varying along a Pareto frontier. The EPO paper investigated the application of the algorithm to MLP neurons and made non-obvious discoveries using outputs from the algorithm. They also considered applying the algorithm to maximizing random residual stream directions.

Sparse Autoencoders provide a way to decompose the residual streams of language models into linear combinations of sparsely activated latent directions. It is an important problem to explain unlabelled SAE latents for human understanding. Some of the proposed approaches are using a language model to look at max activating examples and propose an explanation ([autointerpretation](https://openai.com/index/language-models-can-explain-neurons-in-language-models/)) and asking the model to explain a token containing the residual stream direction in its own words ([self-explanation](https://www.lesswrong.com/posts/8ev6coxChSWcxCDy8/self-explaining-sae-features)). An approach that can explain a single feature without doing a pass through an entire dataset would be useful for experimenting and debugging residual stream directions in general. However, self-explanation relies on the model’s knowledge of residual stream, so it performs much worse with small models and produces examples that are not natural for the pretraining distribution and may not even activate the SAE feature.

[https://confirmlabs.org/posts/sae_dream.html](https://confirmlabs.org/posts/sae_dream.html) shows an example of applying EPO to SAE features. This post contains our experiments applying EPO in various settings from May to October of 2024.

Results
=======

Random GPT-2 features
---------------------

We started by applying [the EPO implementation by the paper’s authors](https://github.com/Confirm-Solutions/dreamy) to maximizing features from [Joseph Bloom’s residual sparse autoencoders](https://www.lesswrong.com/posts/f9EgfLSurAiqRJySD/open-source-sparse-autoencoders-for-all-residual-stream).

We picked [feature 234 at layer 10](https://www.neuronpedia.org/gpt2-small/10-res-jb/234) (arbitrarily, because it had 3 consecutive digits). It seemingly activates on text related to legalization or decriminalization. We applied EPO and found a mostly human-readable new maximum activating example on the first try:

![](https://res.cloudinary.com/lesswrong-2-0/image/upload/f_auto,q_auto/v1/mirroredImages/hMBTaFvAzdMNnj29c/hwsrzpsclv1gzdfv4nvw)

The maximum activating examples for this feature were computed over 3 million tokens.

More detailed results from this initial exploration can be found [here](https://keen-stem-212.notion.site/AdvPrompterOpt-with-Stepan-bd8d87d51702404d94f19f33a7cdabce) and in the source code linked below.

Maximizing two features at once
-------------------------------

We tried creating max-activating examples for 2 features from the same SAE at once. We tried to apply EPO to various combinations of features 234 and [17165](https://www.neuronpedia.org/gpt2-small/10-res-jb/17165) (activates on Wonder Woman). We gave the fluency penalty a very low weight, as that seemed to be the only way to produce a prompt to activated two features on the same token. Details can be seen in the Appendix.

![](https://res.cloudinary.com/lesswrong-2-0/image/upload/f_auto,q_auto/v1/mirroredImages/4a27cc17f9fac056873e281525df201fcfd6b0f3b05f66ea50d547fa2ac48776/zhhkxiyqnskp9g4rl7ds)

![](https://res.cloudinary.com/lesswrong-2-0/image/upload/f_auto,q_auto/v1/mirroredImages/c826d12ec7a3fb53e6e11f102ed9fbe6dd5d2355530bcc450035e16cb1830a21/jjmsb6yp0ebwbfxs5wwd)

Both features have high activations, but the activations are not maximum-activating

![](https://res.cloudinary.com/lesswrong-2-0/image/upload/f_auto,q_auto/v1/mirroredImages/hMBTaFvAzdMNnj29c/o4mcymlnbgmrrirctash)
---------------------------------------------------------------------------------------------------------------------------------

These features are distinct enough that it is difficult to activate them on the same token, *Wonder*. We tried for a few minutes to find such a prompt by hand as a baseline and we couldn’t make the *same token* activate both features.

![](https://39669.cdn.cke-cs.com/rQvD3VnunXZu34m86e5f/images/b9fc3e595512f983fba963d826a70507f346a30e26500108.png)

Prompt: “Latest: Wonder Woman campaigns for cannabis. If cannabis was legalized Wonder-weed”; Feature: 234. Activates on “weed”, not “Wonder-”

![](https://39669.cdn.cke-cs.com/rQvD3VnunXZu34m86e5f/images/4c74885403ad52f7f1c450f571bfa8db85e4bef12a16ed79.png)

Prompt: “Latest: Wonder Woman campaigns for cannabis. If cannabis was legalized Wonder-weed”; Feature: 17165. Activates on “Wonder-”, not “weed”

Gemma features
--------------

We ran [our EPO implementation](#Our_EPO_implementation) on the [SAE for Gemma 1 2B Instruct residual streams at layer 12 by Joseph Bloom](https://huggingface.co/jbloom/Gemma-2b-IT-Residual-Stream-SAEs).

We numbered features from our previous research that we thought would produce interesting results to demonstrate the capabilities of the algorithm. We provide all features we tried intentionally as well as results without cherry-picking. We also include a sample of 400 random explanations you can see along with the main visualizations here: [https://neverix.github.io/epo-visualizer/](https://neverix.github.io/epo-visualizer/). (Note: the website is horribly broken with a portrait layout on mobile, we suggest using landscape mode)

The titles are our quick impressions from the max-activating examples and Neuronpedia explanations. You can look yourself to compare. Note that our EPO activations are not comparable to Neuronpedia SAE feature activations because they are simple dot products with the residual stream without the SAE bias or scaling factor.[^30pbohjpdsv]

*   Word/topical features
    *   321: animals, animal shelters

![](https://res.cloudinary.com/lesswrong-2-0/image/upload/f_auto,q_auto/v1/mirroredImages/hMBTaFvAzdMNnj29c/debsrgpk3mjoe2y0cby0)

*   2079: “Hmm”

![](https://res.cloudinary.com/lesswrong-2-0/image/upload/f_auto,q_auto/v1/mirroredImages/a22d172200d7c125a837cefea806afc35f6ea56f04caa0a7a79f41d20d3e09e3/agvlw7y3z31wt3aofkta)

This visualization includes the word “hmm” and some of the tokens are "unwarran", which the direction has positive direct logit scores for

![](https://res.cloudinary.com/lesswrong-2-0/image/upload/f_auto,q_auto/v1/mirroredImages/hMBTaFvAzdMNnj29c/brxi1umltubx7atkfc6s)

Another example shows different exclamations

*   8631: “quite”

![](https://res.cloudinary.com/lesswrong-2-0/image/upload/f_auto,q_auto/v1/mirroredImages/hMBTaFvAzdMNnj29c/eg1jxuw7burlvzd74lr3)

Some of the highest activating examples were not very readable and just contained many repetitions of the word “quite”, so we show the lowest-activating lowest-perplexity prompts

*   Repetition features
    *   330: prepositions appearing in contexts similar to those that appeared before

![](https://res.cloudinary.com/lesswrong-2-0/image/upload/f_auto,q_auto/v1/mirroredImages/hMBTaFvAzdMNnj29c/sftja3icpdu6b6pxaciq)

*   5373: the same token being repeated multiple times

![](https://res.cloudinary.com/lesswrong-2-0/image/upload/f_auto,q_auto/v1/mirroredImages/hMBTaFvAzdMNnj29c/umgj0ms67xz14kb0muc0)

This feature seems easy to activate; even for the lower perplexity prompts, the pattern is very prominent

![](https://res.cloudinary.com/lesswrong-2-0/image/upload/f_auto,q_auto/v1/mirroredImages/hMBTaFvAzdMNnj29c/thx3mqiqesbqyu4hqhij)

One of the highest activating examples includes the token “shenan” although it does not repeat. The algorithm is probably picking a token that has a very high direct logit effect even though it does not correspond to the feature’s direct activation. This is something to watch out for, but not necessarily a bug.

*   ICL task features
    *   8618: translate from English to another language

![](https://res.cloudinary.com/lesswrong-2-0/image/upload/f_auto,q_auto/v1/mirroredImages/hMBTaFvAzdMNnj29c/oc21drij9orhtls6ndf7)

![](https://res.cloudinary.com/lesswrong-2-0/image/upload/f_auto,q_auto/v1/mirroredImages/hMBTaFvAzdMNnj29c/giyhjejfwicsqch1s9pg)

*   12017: antonyms (activates on “and” in “left and right”)

![](https://res.cloudinary.com/lesswrong-2-0/image/upload/f_auto,q_auto/v1/mirroredImages/hMBTaFvAzdMNnj29c/ddnraxtpxhmyfxu1phbc)

![](https://res.cloudinary.com/lesswrong-2-0/image/upload/f_auto,q_auto/v1/mirroredImages/hMBTaFvAzdMNnj29c/jz9zgbr6kmccinznnpzr)

*   IOI features
    *   5324: NAME and OTHER NAME (activates on “and”, predicts another name)

![](https://res.cloudinary.com/lesswrong-2-0/image/upload/f_auto,q_auto/v1/mirroredImages/hMBTaFvAzdMNnj29c/l6sctrnzsrn9ddhw3wkf)

![](https://res.cloudinary.com/lesswrong-2-0/image/upload/f_auto,q_auto/v1/mirroredImages/hMBTaFvAzdMNnj29c/rkrak0t2i42tlv80et9p)

*   8361: male and female… (activates on “female” and predicts the remained of the female name)

![](https://res.cloudinary.com/lesswrong-2-0/image/upload/f_auto,q_auto/v1/mirroredImages/hMBTaFvAzdMNnj29c/vhartoqqkk35r3heudlq)

![](https://res.cloudinary.com/lesswrong-2-0/image/upload/f_auto,q_auto/v1/mirroredImages/hMBTaFvAzdMNnj29c/nv3q6hrqzuboxdewxul4)

*   Refusal features
    *   4597: officials refusing to provide sensitive information

![](https://res.cloudinary.com/lesswrong-2-0/image/upload/f_auto,q_auto/v1/mirroredImages/hMBTaFvAzdMNnj29c/wwgz5stlxjikrayctnu2)

![](https://res.cloudinary.com/lesswrong-2-0/image/upload/f_auto,q_auto/v1/mirroredImages/hMBTaFvAzdMNnj29c/gimolqmd0yx39xy9xisb)

![](https://res.cloudinary.com/lesswrong-2-0/image/upload/f_auto,q_auto/v1/mirroredImages/hMBTaFvAzdMNnj29c/ruuysexdvnlxwzf33ask)

*   10681: something is prohibited

![](https://res.cloudinary.com/lesswrong-2-0/image/upload/f_auto,q_auto/v1/mirroredImages/hMBTaFvAzdMNnj29c/babzabtyyysifcj9tyx3)

![](https://res.cloudinary.com/lesswrong-2-0/image/upload/f_auto,q_auto/v1/mirroredImages/hMBTaFvAzdMNnj29c/uaugbveqg3hi3t9uxwz9)

It seems our initial interpretation was incorrect. The generated examples seem to focus on the theme of meetings more.

*   11046: officials confirming something

![](https://res.cloudinary.com/lesswrong-2-0/image/upload/f_auto,q_auto/v1/mirroredImages/hMBTaFvAzdMNnj29c/bjmnhdd7wioqix1am4he)

*   11256: someone would never do an offensive action they were accused of

![](https://res.cloudinary.com/lesswrong-2-0/image/upload/f_auto,q_auto/v1/mirroredImages/hMBTaFvAzdMNnj29c/jjcao3angvctcgspfatp)

![](https://res.cloudinary.com/lesswrong-2-0/image/upload/f_auto,q_auto/v1/mirroredImages/hMBTaFvAzdMNnj29c/kpqck2lazwrwnfmgsuva)

![](https://res.cloudinary.com/lesswrong-2-0/image/upload/f_auto,q_auto/v1/mirroredImages/hMBTaFvAzdMNnj29c/xb9dty0cvdse27o3ptwx)

*   12701: warning for explicit material

![](https://res.cloudinary.com/lesswrong-2-0/image/upload/f_auto,q_auto/v1/mirroredImages/hMBTaFvAzdMNnj29c/eznwb05zn0xdldtk3l7r)

![](https://res.cloudinary.com/lesswrong-2-0/image/upload/f_auto,q_auto/v1/mirroredImages/hMBTaFvAzdMNnj29c/xlraq1ojdcn8spgkqzta)

This feature, like many others before, seems to only pay attention to a few tokens right before itself. It’s easy to just set a higher cross entropy loss coefficient for these features, but the generated preceding tokens aren’t very helpful for interpretation.

![](https://res.cloudinary.com/lesswrong-2-0/image/upload/f_auto,q_auto/v1/mirroredImages/hMBTaFvAzdMNnj29c/sn8tcx7uzhdy7kdhq0lc)

*   Removed because they generated very offensive prompts: 14018, 14151
    *   These features produced generations containing obscenities that weren’t coherent prompts.
*   15553: something offensive being sent to someone. Specifically activates on the subject being sent. Also has offensive generations, but they make sense in context. Can be viewed on our website

Again, these features and more can be viewed at [https://neverix.github.io/epo-visualizer/](https://neverix.github.io/epo-visualizer/).

Discussion
==========

We apply evolutionary prompt optimization to maximizing activations of different types SAE features and propose changes and optimizations to the basic algorithm. We show that it is able to preserve interesting structure in the SAE features, so it should be possible to do interesting things with it like finding example prompts for feature visualization and automated interpretation and adversarial examples for mechanistic interpretability algorithms.  

Algorithms that generate text datasets using a model’s own knowledge are interesting because they may be less susceptible to biases and spurious correlations in available data and instead only inherit biases from the model and the prompt generation process. We think EPO is best used for finding max-activating prompts for individual features during development. It would be inefficient to use it as an alternative to max activating examples for caching many features at once. It is impractical for generating a large amount of data both for this reason and because EPO-like methods maximize fluency, which is not sufficient to *sample* prompts according to the language model’s distributions (similarly to how the SDS objective for vision diffusion models can only find peaks of a distribution). See [AdvPrompter](https://arxiv.org/abs/2404.16873) for an approach that may generalize better We tried it for this task, but it didn't work for maximizing arbitrary features. Something similar to it could still be useful for creating a distribution of prompts maximizing a feature.

The code for our [GPT-2](https://github.com/dtch1997/advprompter/blob/main/advprompter/optimize_prompt.py) and [Gemma](https://github.com/neverix/micrlhf-progress/blob/main/sprint/epo_gemma_jb.ipynb) experiments is public on GitHub.

Acknowledgements
================

We would like to thank Ben Thompson and Michael Sklar for publishing this algorithm initially as well as for giving us advice on reimplementing it in May. Thanks to McKenna Fitzgerald and Matthew Wearden for research management and encouraging us to publish these results.

Our EPO implementation
======================

We reimplemented EPO for use on TPUs in Jax. Our implementation computes each EPO shards the EPO batch with data parallelism. It computes gradients to tokens and logits in a separate JIT context from the one which combines the updates into new candidate solutions and caches in a third JIT context. The reason for this is to minimize compilation time.

Our EPO variant optimizes for multiple linear combinations of the log likelihood of the prompt according to the target model and the post-ReLU. It thus keeps track of several points on the Pareto frontier of fluency to activation strength (dot product of the residual stream at a layer to the SAE decoder direction for the feature we’re maximizing). Similarly to [BEAST](https://arxiv.org/abs/2402.15570v1), [ACG](https://blog.haizelabs.com/posts/acg/) and [FLRT](https://arxiv.org/abs/2407.17447), we incorporate additional augmentations:

*   Always: sample valid token replacement options according to logit predictions from the previous token
    *   The logits are modulated by a random temperature sampled uniformly from 0 to 2.
*   P=0.2: don’t mask the token options according to the top-k gradients from the fluency+activation objective and just sample according to logit predictions
*   P=(1.5/len(prompt)): resample any given token in addition to the random token we’re guaranteed to resample
*   P=0.1: on top of everything else, swap a random token from one position to another one

In effect, we get something like the simultaneous update from ACG and beam search from BEAST. Unlike FLRT, we don’t use gradients from multiple models for the fluency penalty. We haven’t evaluated our algorithm in traditional settings like jailbreaking, but it produces satisfactory results for most of our attempts.

We use 8 elites (linear combinations) with crossentropy penalty strength from 1 to 20. We run our EPO variant for 750 iterations with 128 random candidates for each of the elites per iteration and use 20 unknown tokens for all prompts.

When we ran the algorithm, we found that the first token from <bos> had a probability concentrated on unusual tokens (including “ increa”, “ secon” and “ maneu”) and that those tokens were dominating the first tokens in generations. They were preferred by the logprob fluency penalty even if we turned off logit guidance for token replacements. Therefore, we started prepending the usual chat prefix (“<bos><start\_of\_turn>user\\n” for Gemma) so the first tokens would at least *make sense* even if they were not diverse.

Maximizing multiple features
============================

We could not get EPO to maximize two features with the fluency penalty set to a reasonable value. Because of this, we gave a very low weight for the fluency penalty and maximized just a combination of the two feature activations. We tried various functions for combining them including a simple sum, a minimum and a maximum. We eventually settled on computing the following function:

$L_{0.1}([\text{relu}(a + \text{offset}), \text{relu}(b + \text{offset})])$

This consists of:

1.  An offset to create an offset for the $L_p$ norm and to make sure negative activations receive a gradient from the ReLU
2.  ReLU to make sure that very negative activations of one feature do not make a certain prompt overwhelmingly disfavored
3.  An $L_p$, p<1 norm to make sure the activations of the two features trade off smoothly and that the optimizer does not choose to maximize one feature at the expense of another.

![](https://res.cloudinary.com/lesswrong-2-0/image/upload/f_auto,q_auto/v1/mirroredImages/hMBTaFvAzdMNnj29c/ewzailmbgqxlzy1zwopz)

A visualization of the combination function

[^mwj6sdgeu6i]: Features as in basis vectors of the hidden space, not human-interpretable classifiers. In CNNs, features are hidden neurons. In transformers, features correspond to MLP neurons or SAE latents. 

[^30pbohjpdsv]:  The reason for this is that it makes hyperparameter tuning easier because all features have the same scale.