Skip to content

Commit aba54e9

Browse files
committed
hf : add basic huggingface model example
This example is very basic and exists mainly to help me understand the huggingface transformers that we convert in llama.cpp.
1 parent cdd8710 commit aba54e9

File tree

7 files changed

+159
-0
lines changed

7 files changed

+159
-0
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
venv
2+
__pycache__
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
from model.configuration_model import ModelConfig
2+
from model.modeling_model import ModelLM
3+
4+
config = ModelConfig(vocab_size=100, hidden_size=32, num_hidden_layers=2, tie_word_embeddings=True)
5+
config.auto_map = {
6+
"AutoConfig": "configuration_model.ModelConfig",
7+
"AutoModel": "modeling_model.ModelLM",
8+
"AutoModelForCausalLM": "modeling_model.ModelLM"
9+
}
10+
model = ModelLM(config)
11+
12+
model.save_pretrained("model", safe_serialization=True)
13+
print("Saved to ./model")
14+
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"architectures": [
3+
"ModelLM"
4+
],
5+
"auto_map": {
6+
"AutoConfig": "configuration_model.ModelConfig",
7+
"AutoModel": "modeling_model.ModelLM",
8+
"AutoModelForCausalLM": "modeling_model.ModelLM"
9+
},
10+
"dtype": "float32",
11+
"hidden_size": 32,
12+
"model_type": "model",
13+
"num_attention_heads": 4,
14+
"num_hidden_layers": 2,
15+
"tie_word_embeddings": true,
16+
"transformers_version": "4.57.1",
17+
"vocab_size": 100
18+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from transformers import PretrainedConfig
2+
3+
class ModelConfig(PretrainedConfig):
4+
model_type = "model"
5+
6+
def __init__(
7+
self,
8+
vocab_size=100,
9+
hidden_size=32,
10+
num_hidden_layers=2,
11+
num_attention_heads=4,
12+
tie_word_embeddings=False,
13+
**kwargs
14+
):
15+
super().__init__(tie_word_embeddings=tie_word_embeddings, **kwargs)
16+
17+
18+
self.vocab_size = vocab_size
19+
self.hidden_size = hidden_size
20+
self.num_hidden_layers = num_hidden_layers
21+
self.num_attention_heads = num_attention_heads
16.9 KB
Binary file not shown.
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import torch
2+
import torch.nn as nn
3+
from transformers import PreTrainedModel
4+
from transformers.modeling_outputs import CausalLMOutput
5+
from .configuration_model import ModelConfig
6+
7+
class ModelLM(PreTrainedModel):
8+
config_class = ModelConfig
9+
base_model_prefix = "backbone"
10+
## Use the same tensor for input embeddings and output embeddings
11+
_tied_weights_keys = ["lm_head.weight", "backbone.embed.weight"]
12+
13+
14+
def __init__(self, config: ModelConfig):
15+
super().__init__(config)
16+
17+
self.backbone = nn.Module()
18+
self.backbone.embed = nn.Embedding(config.vocab_size, config.hidden_size)
19+
self.backbone.mlp = nn.Sequential(
20+
nn.Linear(config.hidden_size, config.hidden_size),
21+
nn.Tanh(),
22+
)
23+
24+
self.lm_head = nn.Linear(config.hidden_size, config.vocab_size, bias=False)
25+
26+
self.post_init()
27+
28+
def get_input_embeddings(self):
29+
return self.backbone.embed
30+
31+
def set_input_embeddings(self, value):
32+
self.backbone.embed = value
33+
34+
def get_output_embeddings(self):
35+
return self.lm_head
36+
37+
def set_output_embeddings(self, new_emb):
38+
self.lm_head = new_emb
39+
40+
def tie_weights(self):
41+
out_emb = self.get_output_embeddings() # lm_head (Linear)
42+
in_emb = self.get_input_embeddings() # Embedding
43+
44+
# If either side is missing, do nothing
45+
if out_emb is None or in_emb is None:
46+
return
47+
48+
out_w = out_emb.weight
49+
in_w = in_emb.weight
50+
51+
if in_w.device.type == "meta" and out_w.device.type != "meta":
52+
# IMPORTANT: rebind the Parameter, not just copy data
53+
in_emb.weight = out_w
54+
return
55+
56+
if out_w.device.type == "meta" and in_w.device.type != "meta":
57+
out_emb.weight = in_w
58+
return
59+
60+
# Default HF behavior (ties by reference or clones as needed)
61+
self._tie_or_clone_weights(out_emb, in_emb)
62+
63+
64+
def forward(self, input_ids=None, labels=None, **kwargs):
65+
# input_ids: (batch, seq_len)
66+
x = self.backbone.embed(input_ids) # (B, T, H)
67+
x = self.backbone.mlp(x) # (B, T, H)
68+
logits = self.lm_head(x) # (B, T, V)
69+
70+
loss = None
71+
if labels is not None:
72+
# classic language-model loss with next-token prediction
73+
shift_logits = logits[:, :-1, :].contiguous()
74+
shift_labels = labels[:, 1:].contiguous()
75+
loss = nn.CrossEntropyLoss()(shift_logits.view(-1, self.config.vocab_size),
76+
shift_labels.view(-1))
77+
return CausalLMOutput(loss=loss, logits=logits)
78+

fundamentals/huggingface/test.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import torch
2+
from transformers import AutoConfig, AutoModelForCausalLM
3+
4+
path = "./model"
5+
6+
config = AutoConfig.from_pretrained(path, trust_remote_code=True)
7+
print("Loaded config:", config)
8+
9+
model = AutoModelForCausalLM.from_pretrained(
10+
path,
11+
trust_remote_code=True,
12+
low_cpu_mem_usage=False,
13+
device_map=None,
14+
dtype=torch.float32,
15+
)
16+
bad = [n for n,p in model.named_parameters() if p.device.type == "meta"]
17+
bad += [f"(buffer) {n}" for n,b in model.named_buffers() if b.device.type == "meta"]
18+
print("Left on meta:", bad)
19+
20+
model.eval()
21+
22+
input_ids = torch.randint(0, config.vocab_size, (1, 8))
23+
out = model(input_ids)
24+
print("Logits shape:", out.logits.shape) # (1, 8, vocab_size)
25+
26+

0 commit comments

Comments
 (0)