Views
No views yet
Anticipating Innovation Using Large Language Models
Enrico Maria Fenoaltea, Filippo Santoro, Giordano De Marzo, Segun Taofeek Aroyehun, Andrea Tacchella
arXiv:2605.04875 · May 2026
https://arxiv.org/abs/2605.04875
[CLS] patent title [SEP] patent abstract [SEP] [TT_1] [TT_2] ... [TT_N] [SEP][CLS] token as a single vector representation of the full patent (title + abstract + IPC codes). The [CLS] embedding encodes information from both the text and the IPC codes it is associated with, outperforming standard sentence-embedding models on patent similarity tasks.| Model | IPC Macro-F1 ↑ | Citation MAP ↑ | Title–Abstract AUC-ROC ↑ |
|---|---|---|---|
| BERT4Patents | 0.354 | 59.46 | 0.920 |
| BERT4Patents FT (Mirror-BERT) | 0.262 | 52.78 | 0.832 |
| PatentSBERTa | 0.356 | 75.95 | 0.985 |
| Paecter | 0.420 | 68.11 | 0.944 |
| LLaMA 3.1 8B FT (LLM2Vec) | 0.343 | 56.78 | 0.973 |
| TechTokenBERT | 0.488 | 68.96 | 0.994 |
Minimal example: build a batch where only the abstract is truncated (on the right), while the title, tech tokens, and all special tokens are preserved. Then run the model and extract the[CLS]embedding for each example.
1import torch
2from transformers import BertTokenizer, BertModel
3
4# ---------------------------------------------------------------------------
5# 1. Load model + tokenizer
6# ---------------------------------------------------------------------------
7MODEL_NAME = "AndreaTacchella/TechTokenBert"
8tokenizer = BertTokenizer.from_pretrained(MODEL_NAME)
9# The model was fine-tuned with an MLM head, kept in the checkpoint for more advanced
10# uses (e.g. tech-code prediction). It is not needed for embeddings, so we load the
11# encoder only via BertModel; the resulting "pooler.dense" newly-initialized warning
12# is expected and harmless -- we only read last_hidden_state, not pooler_output.
13model = BertModel.from_pretrained(MODEL_NAME)
14model.eval()
15
16# ---------------------------------------------------------------------------
17# 2. Toy data (3 rows)
18# ---------------------------------------------------------------------------
19titles = [
20 "Method for cooling electronic components",
21 "Wireless charging apparatus",
22 "Biodegradable packaging material",
23]
24
25abstracts = [
26 "A heat sink assembly that dissipates thermal energy from a processor using "
27 "a network of micro-channels through which a coolant is circulated, thereby "
28 "maintaining the junction temperature below a predefined threshold under load.",
29
30 "An inductive power transfer system comprising a transmitter coil and a "
31 "receiver coil aligned via a magnetic guidance structure to maximize coupling "
32 "efficiency across a variable air gap.",
33
34 "A composite film derived from plant-based polymers that decomposes under "
35 "industrial composting conditions while providing an oxygen barrier suitable "
36 "for food preservation.",
37]
38
39# Already preprocessed tech tokens (list of lists of IPC group-level strings)
40tech_tokens_list = [
41 ["h05k7", "g06f1"],
42 ["h02j50", "h01f27"],
43 ["c08l101", "b65d65"],
44]
45
46
47# ---------------------------------------------------------------------------
48# 3. Build the padded batch (abstract truncated on the right only)
49# ---------------------------------------------------------------------------
50def build_batch(titles, abstracts, tech_tokens_list, tokenizer, max_length=512):
51 cls_id = tokenizer.cls_token_id
52 sep_id = tokenizer.sep_token_id
53
54 all_ids = []
55 for title, abstract, tech_tokens in zip(titles, abstracts, tech_tokens_list):
56 title_ids = tokenizer.encode(title, add_special_tokens=False)
57 abstract_ids = tokenizer.encode(abstract, add_special_tokens=False)
58 tech_ids = tokenizer.encode(" ".join(tech_tokens), add_special_tokens=False)
59
60 # [CLS] title [SEP] abstract [SEP] tech [SEP] -> 4 special tokens fixed
61 fixed_len = 4 + len(title_ids) + len(tech_ids)
62 abstract_budget = max(max_length - fixed_len, 0)
63 abstract_ids = abstract_ids[:abstract_budget] # right-side truncation
64
65 ids = (
66 [cls_id]
67 + title_ids
68 + [sep_id]
69 + abstract_ids
70 + [sep_id]
71 + tech_ids
72 + [sep_id]
73 )
74 all_ids.append(ids)
75
76 return tokenizer.pad({"input_ids": all_ids}, padding=True, return_tensors="pt")
77
78
79enc = build_batch(titles, abstracts, tech_tokens_list, tokenizer, max_length=512)
80
81# ---------------------------------------------------------------------------
82# 4. Forward pass + extract the [CLS] embedding
83# ---------------------------------------------------------------------------
84with torch.no_grad():
85 outputs = model(**enc)
86
87# last hidden state: (batch, seq_len, hidden_dim); position 0 is [CLS]
88cls_embeddings = outputs.last_hidden_state[:, 0, :]
89print(cls_embeddings.shape) # (3, 1024)[SEP]):1with torch.no_grad():
2 outputs = model(**enc)
3
4last_hidden = outputs.last_hidden_state # (batch, seq_len, 1024)
5
6# By construction the TechTokens are always enclosed between the last two [SEP] tokens
7# Find the positions of the last two [SEP] tokens and extract the embeddings for the tokens in between
8
9tech_token_embeddings = []
10input_ids = enc['input_ids']
11
12sep_token_id = tokenizer.sep_token_id
13
14for i, ids in enumerate(input_ids):
15 ids = ids.tolist()
16 sep_indices = [idx for idx, x in enumerate(ids) if x == sep_token_id]
17 # tech tokens are between the last two [SEP]
18 if len(sep_indices) < 2:
19 tech_token_embeddings.append(torch.empty((0, last_hidden.size(-1))))
20 continue
21 start = sep_indices[-2] + 1
22 end = sep_indices[-1]
23 emb = last_hidden[i, start:end, :] # shape: (# tech tokens, hidden_dim)
24 tech_token_embeddings.append(emb)
25
26# Now tech_token_embeddings is a list, one per sample in batch, containing
27# a tensor of shape (num_tech_tokens, hidden_size)[CLS] <title tokens> [SEP] <abstract tokens> [SEP] <ipc_code_1> <ipc_code_2> ... [SEP]h05k7, g06f1).1@article{fenoaltea2026anticipating,
2 title = {Anticipating Innovation Using Large Language Models},
3 author = {Fenoaltea, Enrico Maria and Santoro, Filippo and De Marzo, Giordano
4 and Aroyehun, Segun Taofeek and Tacchella, Andrea},
5 journal = {arXiv preprint arXiv:2605.04875},
6 year = {2026}
7}