Skip to main content

Reproducing Emotion Concepts and their Function in a Large Language Model on Qwen 3.6 27b

Project description

Emotion Probes

Reproducing Emotion Concepts and their Function in a Large Language Model on Qwen 3.6 27b.

Example

Emotional Fluctuation

Included in this repo:

  1. Artifacts Generation (emotional stories and neutral dialogues)
  2. Activations Extraction
  3. Emotion Vectors Calculation
  4. Web Interface to See and Manipulate the Model's Emotion on the Fly (Planned)

Generate Artifacts

The first step is to generate the emotional stories and the neutral dialogues used to extract the vectors.

Following Anthropic's approach, the same prompts are used. See prompts/emotional_stories and prompts/neutral_dialogues.

A small adjustment is made. Namely separator '---' is added so that it is easier to extract each story.

# Generate emotional stories
python scripts/generate_artifacts.py --n-stories 3 --max-parallel 12 --dry-run

# Generate neutral dialogues
python scripts/generate_artifacts.py --n-stories 6 --max-parallel 12 --neutral --dry-run

# Split emotional stories
python scripts/split_stories.py --force

# Split neutral dialogues
python scripts/split_stories.py --force --neutral

About the coverage

The original paper generates 12 stories for 100 topics for 170 emotions each. As a GPU-poor, the number is largely reduced due to the constraint of GPU power. Only 3 stories for each 25 topics for each 58 emotions is generated. But as shown later, the emotion vectors extracted still successfully capture the characteristics of the emotions.

Emotions

The 58 emotions is selected by asking the model to group the emotions and pick representative ones for each group. The model split the emotions into 11 categories, and picked top 3 for each. In addition, 25 emotions are picked manually. The prompt:

group those emotions, and pick the top 3 most representative ones for each group:

<the list of emotions from the original paper>

The model's answer is in dataset-ingredients/selected/emotions-groups.

Topics

The 25 topics are selected randomly from the 100 topics listed in the original paper.

shuf -n 25 original/stories-topics >selected/stories-topics

Extract Activations (Optional)

Note: This step can now be skipped as the notebook in the next section is now capable of calculating the emotion vectors from the prompts on the fly. Use it to cache the activations if need to investigate those activations. Be careful as the size of those activations can get really large.

Next is extracting the activations from selected layers in a model. The extraction script is inspired by the J-lens script.

# Extract the activations from the emotional stories generated in the previous step
python scripts/extract_vectors.py --model "Qwen/Qwen3.6-27B" --prompts outputs/extracted/emotional_stories --output-dir outputs/vectors/emotions --layers 31 47 48 49 50 51 --q4 --batch-size 1 --skip-existing

# Extract the activations from the neutral dialogues generated in the previous step
python scripts/extract_vectors.py --model "Qwen/Qwen3.6-27B" --prompts outputs/extracted/neutral_dialogues --output-dir outputs/vectors/neutral --layers 31 47 48 49 50 51 --q4 --batch-size 1 --skip-existing

Calculate Emotion Vectors

The math is relative straightforward. First fit a PCA model on activation vectors from neutral stories. Then use the PCA model to "project out" the activation vectors extracted from the emotional stories. Here "project out" simply means the residuals of PCA are being used. Then the emotion vector is calculated as the mean of the residual components of the activations from each emotion (first few tokens are skipped so that the emotion is clear). The emotion vectors are re-centered by their mean.

Finally, the emotion of a token is estimated by the cosine similarity of its residual activation and the emotion vectors.

Notebook scripts/run_emotion_probe.ipynb does the math and visualizes the similarity of the vectors. It fits confound PCA on neutral activations, extracts mean-centered emotion vectors, runs prompts through the model, and saves emotion similarity plots.

Relative similarity between emotion vectors

One way to quickly verify the emotion vectors is to calculate the cosine similarity between those vectors. Emotions that are similar should have positive similarity while opposite emotions should have negative similarity.

Example for layer 39 with the first 11 emotions.

angry anxious ashamed calm excited grateful joyful loving sad surprised tired
angry 1.0000 0.3654 0.2270 -0.4769 0.0068 -0.4168 -0.2301 -0.4321 -0.0063 0.1894 -0.1235
anxious 0.3654 1.0000 0.3802 -0.5660 0.0562 -0.6282 -0.3517 -0.4877 0.3504 0.2727 0.2316
ashamed 0.2270 0.3802 1.0000 -0.5142 -0.2496 -0.1938 -0.4241 -0.2583 0.4915 0.0355 0.0297
calm -0.4769 -0.5660 -0.5142 1.0000 -0.1076 0.3634 0.2414 0.5099 -0.2168 -0.4139 -0.0438
excited 0.0068 0.0562 -0.2496 -0.1076 1.0000 0.0350 0.8008 0.0350 -0.4118 0.0715 -0.3035
grateful -0.4168 -0.6282 -0.1938 0.3634 0.0350 1.0000 0.3694 0.6524 -0.1392 -0.1399 -0.3664
joyful -0.2301 -0.3517 -0.4241 0.2414 0.8008 0.3694 1.0000 0.3471 -0.4600 -0.0882 -0.2946
loving -0.4321 -0.4877 -0.2583 0.5099 0.0350 0.6524 0.3471 1.0000 -0.0685 -0.3796 -0.2122
sad -0.0063 0.3504 0.4915 -0.2168 -0.4118 -0.1392 -0.4600 -0.0685 1.0000 -0.0788 0.4143
surprised 0.1894 0.2727 0.0355 -0.4139 0.0715 -0.1399 -0.0882 -0.3796 -0.0788 1.0000 -0.0782
tired -0.1235 0.2316 0.0297 -0.0438 -0.3035 -0.3664 -0.2946 -0.2122 0.4143 -0.0782 1.0000

Emotional Fluctuation with respect to variables

One interesting experiment is to see how the model reacts to a variable in a sentence. For example, "I just took {X} mg of tylenol for my back pain." with X varying from 500 to 16,000. See the second figure above for example.

Evaluation Style

As for the evaluation style, initially, the prompt is formatted as User: {prompt}\nAssistant: following the paper, and the colon ":" after "Assistant" is used to evaluate the emotion. However, it turns out that at least for this model, formatting the prompt using the ChatML prompt template <|im_start|>user\n{prompt}<|im_end|>\n<|im_start|>assistant\n and evaluate at the last "\n" produces more distinguishable result.

"My cat has been missing for {X} days now.", ChatML

Comparison - ChatML

"My cat has been missing for {X} days now.", Vicuna

Comparison - ChatML

Note: The emotion vectors and the neutral vector are extracted without any formatting. And this model (Qwen 3.6 27B) is fine-tuned on ChatML prompt style.

Unexpected Value

Additionally, unexpected or unrealistic value is tested to see how will the model react. The result further demonstrates the effectiveness of the emotion probe technique.

More students than expected:

Unexpected - More students than expected

New record for lifespan:

Unrealistic - New record for lifespan

More examples can be found in docs/emo_fluct/.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

emotion_probes-0.1.0.tar.gz (20.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

emotion_probes-0.1.0-py3-none-any.whl (19.0 kB view details)

Uploaded Python 3

File details

Details for the file emotion_probes-0.1.0.tar.gz.

File metadata

  • Download URL: emotion_probes-0.1.0.tar.gz
  • Upload date:
  • Size: 20.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.29 {"installer":{"name":"uv","version":"0.11.29","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for emotion_probes-0.1.0.tar.gz
Algorithm Hash digest
SHA256 a801d06e8fe01f46d05fe642409e68261bf5d61362e9bb5ec4fb5a3aa2b97ca7
MD5 46412f94a8b78dc5b0c4c4dc3b7d45f2
BLAKE2b-256 5cafb3b83eeb6b690d8cda7ab340fab724b606614a65e1be8d420659c9c54c2b

See more details on using hashes here.

File details

Details for the file emotion_probes-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: emotion_probes-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 19.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.29 {"installer":{"name":"uv","version":"0.11.29","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for emotion_probes-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 0c12e5e8fc580e4bd88a4b7b3013987c332d4fbc180997e369c7d25c643f592e
MD5 69038bcdc42ed3a4865e863b7635aa2c
BLAKE2b-256 da02469366e9eac66ced8fb8ae65680f64c31f6701cab3cd9fdbc94f65ac1353

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page