Concatenate the last two transformer hidden states along the feature dimension before the task head for richer token representations
Scanned 9/12/2026
Install to Claude Code
npx -y skills add wenmin-wu/ds-skills --skill last-hidden-states-concat --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Last Hidden States Concat?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/wenmin-wu-last-hidden-states-concat)More formats (shields.io, HTML) on the badges page.
---
name: nlp-last-hidden-states-concat
description: Concatenate the last two transformer hidden states along the feature dimension before the task head for richer token representations
domain: nlp
---
# Last Hidden States Concatenation
## Overview
Instead of using only the final hidden state from a transformer encoder, concatenate the last two (or more) hidden layers along the feature dimension. The second-to-last layer often captures different linguistic patterns than the final layer. This doubles the representation size but consistently improves span extraction and token classification tasks with minimal overhead.
## Quick Start
```python
import torch
import torch.nn as nn
from transformers import AutoModel, AutoConfig
class SpanExtractor(nn.Module):
def __init__(self, model_name, n_layers=2):
super().__init__()
config = AutoConfig.from_pretrained(model_name, output_hidden_states=True)
self.encoder = AutoModel.from_pretrained(model_name, config=config)
hidden_size = config.hidden_size * n_layers
self.dropout = nn.Dropout(0.1)
self.head = nn.Linear(hidden_size, 2) # start + end logits
nn.init.normal_(self.head.weight, std=0.02)
self.n_layers = n_layers
def forward(self, input_ids, attention_mask, token_type_ids=None):
outputs = self.encoder(
input_ids, attention_mask=attention_mask,
token_type_ids=token_type_ids)
hidden_states = outputs.hidden_states
# Concatenate last N layers
cat = torch.cat(hidden_states[-self.n_layers:], dim=-1)
logits = self.head(self.dropout(cat))
start_logits, end_logits = logits.split(1, dim=-1)
return start_logits.squeeze(-1), end_logits.squeeze(-1)
```
## Key Decisions
- **2 layers is standard**: last 2 is the sweet spot; 3-4 adds parameters with diminishing returns
- **output_hidden_states=True**: must enable in config to access intermediate layers
- **Linear head doubles**: input size to head is `hidden_size * n_layers`
- **Alternative: weighted sum**: use `nlp-weighted-layer-pooling` for learned weights instead of concat
## References
- Source: [roberta-inference-5-folds](https://www.kaggle.com/code/abhishek/roberta-inference-5-folds)
- Competition: Tweet Sentiment Extraction
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!