Mentors4EDU commited on
Commit
c0b0ec6
·
verified ·
1 Parent(s): 509a1aa

Publish openpeerllm-demo

Browse files
Files changed (5) hide show
  1. README.md +31 -13
  2. app.py +133 -0
  3. configuration_riemann.py +33 -0
  4. modeling_riemann.py +244 -0
  5. requirements.txt +6 -0
README.md CHANGED
@@ -1,13 +1,31 @@
1
- ---
2
- title: OpenPeerLLM Demo
3
- emoji: 🌍
4
- colorFrom: blue
5
- colorTo: indigo
6
- sdk: gradio
7
- sdk_version: 6.30.0
8
- python_version: '3.12'
9
- app_file: app.py
10
- pinned: false
11
- ---
12
-
13
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: OpenPeerLLM Demo
3
+ emoji: 🕸️
4
+ colorFrom: blue
5
+ colorTo: green
6
+ sdk: gradio
7
+ sdk_version: 5.49.1
8
+ app_file: app.py
9
+ pinned: false
10
+ license: mit
11
+ models:
12
+ - OpenPeerAI/OpenPeerLLM
13
+ short_description: Generate and score text with OpenPeerLLM on ZeroGPU
14
+ ---
15
+
16
+ # OpenPeerLLM Demo
17
+
18
+ Text generation and perplexity scoring with
19
+ [OpenPeerAI/OpenPeerLLM](https://huggingface.co/OpenPeerAI/OpenPeerLLM), a
20
+ decentralised-training language model by Andrew Magdy Kamal Nassief
21
+ (DOI [10.57967/hf/6469](https://doi.org/10.57967/hf/6469)).
22
+
23
+ The space loads OpenPeerLLM's published `model.safetensors` (163M parameters)
24
+ tensor for tensor into a reimplementation of its architecture that adds the
25
+ causal attention mask the reference forward pass omits. OpenPeerLLM is the
26
+ starting rung of the
27
+ [My Name is Riemann](https://huggingface.co/OpenPeerAI/My-Name-is-Riemann-Prerelease)
28
+ growth ladder.
29
+
30
+ Maintained by OpenPeer AI. OpenPeerLLM is released under OPNL, MIT and
31
+ CC BY 4.0.
app.py ADDED
@@ -0,0 +1,133 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+ import threading
3
+ import torch
4
+ import gradio as gr
5
+ import spaces
6
+ from huggingface_hub import hf_hub_download
7
+ from safetensors.torch import load_file
8
+ from transformers import AutoTokenizer, TextIteratorStreamer
9
+ from configuration_riemann import RiemannConfig
10
+ from modeling_riemann import RiemannForCausalLM
11
+
12
+ OPENPEER_REPO = "OpenPeerAI/OpenPeerLLM"
13
+
14
+ tokenizer = AutoTokenizer.from_pretrained("gpt2")
15
+ tokenizer.pad_token = tokenizer.eos_token
16
+ config = RiemannConfig(
17
+ vocab_size=50257,
18
+ hidden_size=768,
19
+ num_hidden_layers=12,
20
+ num_attention_heads=12,
21
+ intermediate_size=3072,
22
+ max_position_embeddings=1024,
23
+ )
24
+ model = RiemannForCausalLM(config)
25
+ weights_path = hf_hub_download(OPENPEER_REPO, "model.safetensors")
26
+ state = load_file(weights_path)
27
+ missing, unexpected = model.load_state_dict(state, strict=False)
28
+ LOAD_REPORT = f"Loaded {len(state)} tensors from {OPENPEER_REPO}/model.safetensors. Missing: {len(missing)}. Unexpected: {len(unexpected)}."
29
+ model.eval()
30
+ N_PARAMS = sum(p.numel() for p in model.parameters())
31
+
32
+
33
+ @spaces.GPU(duration=60)
34
+ def generate(prompt, max_new_tokens, temperature, top_p, repetition_penalty):
35
+ model.to("cuda")
36
+ inputs = tokenizer(
37
+ prompt,
38
+ return_tensors="pt",
39
+ truncation=True,
40
+ max_length=1024 - int(max_new_tokens),
41
+ ).to("cuda")
42
+ streamer = TextIteratorStreamer(
43
+ tokenizer, skip_prompt=True, skip_special_tokens=True
44
+ )
45
+ kwargs = dict(
46
+ **inputs,
47
+ streamer=streamer,
48
+ max_new_tokens=int(max_new_tokens),
49
+ do_sample=temperature > 0,
50
+ temperature=max(float(temperature), 1e-3),
51
+ top_p=float(top_p),
52
+ repetition_penalty=float(repetition_penalty),
53
+ pad_token_id=tokenizer.eos_token_id,
54
+ )
55
+ thread = threading.Thread(target=model.generate, kwargs=kwargs)
56
+ thread.start()
57
+ out = ""
58
+ for piece in streamer:
59
+ out += piece
60
+ yield prompt + out
61
+ thread.join()
62
+
63
+
64
+ @spaces.GPU(duration=30)
65
+ def score(text):
66
+ model.to("cuda")
67
+ ids = tokenizer(text, return_tensors="pt", truncation=True, max_length=1024).to(
68
+ "cuda"
69
+ )
70
+ with torch.no_grad():
71
+ out = model(input_ids=ids["input_ids"], labels=ids["input_ids"])
72
+ n = ids["input_ids"].shape[1]
73
+ return f"Tokens: {n}\nMean NLL: {out.loss.item():.4f}\nPerplexity: {torch.exp(out.loss).item():.2f}"
74
+
75
+
76
+ DESCRIPTION = f"""
77
+ # OpenPeerLLM Demo
78
+
79
+ [OpenPeerAI/OpenPeerLLM](https://huggingface.co/{OPENPEER_REPO}) is a decentralised-training
80
+ language model by Andrew Magdy Kamal Nassief (DOI [10.57967/hf/6469](https://doi.org/10.57967/hf/6469)).
81
+ This space loads its published `model.safetensors` ({N_PARAMS/1e6:.1f}M parameters, 12 layers,
82
+ hidden size 768, GPT-2 vocabulary) into a faithful reimplementation of its architecture
83
+ and runs it on ZeroGPU.
84
+
85
+ {LOAD_REPORT}
86
+
87
+ OpenPeerLLM is the starting rung of the
88
+ [My Name is Riemann](https://huggingface.co/OpenPeerAI/My-Name-is-Riemann-Prerelease) growth ladder.
89
+ The reimplementation here adds a causal attention mask, which the reference forward pass omits and
90
+ which is required for coherent autoregressive generation.
91
+ """
92
+
93
+ with gr.Blocks(title="OpenPeerLLM Demo") as demo:
94
+ gr.Markdown(DESCRIPTION)
95
+ with gr.Tab("Generate"):
96
+ prompt = gr.Textbox(
97
+ label="Prompt",
98
+ lines=4,
99
+ value="The theory of decentralised machine learning says that",
100
+ )
101
+ with gr.Row():
102
+ max_new = gr.Slider(8, 256, value=96, step=8, label="Max new tokens")
103
+ temp = gr.Slider(
104
+ 0.0, 1.5, value=0.8, step=0.05, label="Temperature (0 = greedy)"
105
+ )
106
+ top_p = gr.Slider(0.1, 1.0, value=0.9, step=0.05, label="Top-p")
107
+ rep = gr.Slider(1.0, 1.5, value=1.2, step=0.05, label="Repetition penalty")
108
+ out = gr.Textbox(label="Output", lines=10)
109
+ gr.Button("Generate", variant="primary").click(
110
+ generate, [prompt, max_new, temp, top_p, rep], out
111
+ )
112
+ gr.Examples(
113
+ [
114
+ ["Peer-to-peer networks allow"],
115
+ ["def fibonacci(n):"],
116
+ ["In 1859, Bernhard Riemann"],
117
+ ],
118
+ inputs=prompt,
119
+ )
120
+ with gr.Tab("Score text"):
121
+ txt = gr.Textbox(
122
+ label="Text to score",
123
+ lines=6,
124
+ value="Decentralized training distributes model updates across peers.",
125
+ )
126
+ res = gr.Textbox(label="Negative log-likelihood and perplexity", lines=3)
127
+ gr.Button("Score", variant="primary").click(score, txt, res)
128
+ gr.Markdown(
129
+ "OpenPeerLLM is released under OPNL, MIT and CC BY 4.0. "
130
+ "This demo is maintained by OpenPeer AI."
131
+ )
132
+
133
+ demo.queue(max_size=16).launch()
configuration_riemann.py ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+ from transformers import PretrainedConfig
3
+
4
+
5
+ class RiemannConfig(PretrainedConfig):
6
+ model_type = "riemann_openpeer"
7
+
8
+ def __init__(
9
+ self,
10
+ vocab_size: int = 50257,
11
+ hidden_size: int = 768,
12
+ num_hidden_layers: int = 12,
13
+ num_attention_heads: int = 12,
14
+ intermediate_size: int = 3072,
15
+ max_position_embeddings: int = 1024,
16
+ layer_norm_eps: float = 1e-05,
17
+ hidden_dropout: float = 0.1,
18
+ attention_dropout: float = 0.1,
19
+ use_gradient_checkpointing: bool = False,
20
+ **kwargs,
21
+ ):
22
+ self.vocab_size = vocab_size
23
+ self.hidden_size = hidden_size
24
+ self.num_hidden_layers = num_hidden_layers
25
+ self.num_attention_heads = num_attention_heads
26
+ self.intermediate_size = intermediate_size
27
+ self.max_position_embeddings = max_position_embeddings
28
+ self.layer_norm_eps = layer_norm_eps
29
+ self.hidden_dropout = hidden_dropout
30
+ self.attention_dropout = attention_dropout
31
+ self.use_gradient_checkpointing = use_gradient_checkpointing
32
+ kwargs.setdefault("tie_word_embeddings", False)
33
+ super().__init__(**kwargs)
modeling_riemann.py ADDED
@@ -0,0 +1,244 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+ import math
3
+ from typing import Optional
4
+ import torch
5
+ import torch.nn as nn
6
+ import torch.nn.functional as F
7
+ import torch.utils.checkpoint
8
+ from transformers import GenerationMixin, PreTrainedModel
9
+ from transformers.modeling_outputs import CausalLMOutputWithPast
10
+ from configuration_riemann import RiemannConfig
11
+
12
+
13
+ class MultiHeadAttention(nn.Module):
14
+
15
+ def __init__(self, config: RiemannConfig):
16
+ super().__init__()
17
+ self.num_heads = config.num_attention_heads
18
+ self.hidden_size = config.hidden_size
19
+ self.head_size = self.hidden_size // self.num_heads
20
+ self.query = nn.Linear(config.hidden_size, config.hidden_size)
21
+ self.key = nn.Linear(config.hidden_size, config.hidden_size)
22
+ self.value = nn.Linear(config.hidden_size, config.hidden_size)
23
+ self.out = nn.Linear(config.hidden_size, config.hidden_size)
24
+ self.dropout = nn.Dropout(config.attention_dropout)
25
+
26
+ def forward(
27
+ self, hidden_states: torch.Tensor, attention_mask: Optional[torch.Tensor] = None
28
+ ):
29
+ batch_size, seq_length = hidden_states.shape[:2]
30
+ query_states = self.query(hidden_states)
31
+ key_states = self.key(hidden_states)
32
+ value_states = self.value(hidden_states)
33
+ query_states = query_states.view(
34
+ batch_size, seq_length, self.num_heads, self.head_size
35
+ ).transpose(1, 2)
36
+ key_states = key_states.view(
37
+ batch_size, seq_length, self.num_heads, self.head_size
38
+ ).transpose(1, 2)
39
+ value_states = value_states.view(
40
+ batch_size, seq_length, self.num_heads, self.head_size
41
+ ).transpose(1, 2)
42
+ use_sdpa = hidden_states.device.type in ("cuda", "cpu")
43
+ if use_sdpa:
44
+ context_layer = F.scaled_dot_product_attention(
45
+ query_states,
46
+ key_states,
47
+ value_states,
48
+ attn_mask=attention_mask,
49
+ dropout_p=self.dropout.p if self.training else 0.0,
50
+ is_causal=attention_mask is None,
51
+ )
52
+ else:
53
+ attention_scores = torch.matmul(query_states, key_states.transpose(-1, -2))
54
+ attention_scores = attention_scores / math.sqrt(self.head_size)
55
+ if attention_mask is None:
56
+ attention_mask = torch.triu(
57
+ torch.full(
58
+ (seq_length, seq_length),
59
+ torch.finfo(attention_scores.dtype).min,
60
+ dtype=attention_scores.dtype,
61
+ device=attention_scores.device,
62
+ ),
63
+ diagonal=1,
64
+ )
65
+ attention_scores = attention_scores + attention_mask
66
+ attention_probs = F.softmax(attention_scores, dim=-1)
67
+ attention_probs = self.dropout(attention_probs)
68
+ context_layer = torch.matmul(attention_probs, value_states)
69
+ context_layer = context_layer.transpose(1, 2).contiguous()
70
+ context_layer = context_layer.view(batch_size, seq_length, self.hidden_size)
71
+ context_layer = self.out(context_layer)
72
+ return context_layer
73
+
74
+
75
+ class MLP(nn.Module):
76
+
77
+ def __init__(self, config: RiemannConfig):
78
+ super().__init__()
79
+ self.dense_h_to_4h = nn.Linear(config.hidden_size, config.intermediate_size)
80
+ self.dense_4h_to_h = nn.Linear(config.intermediate_size, config.hidden_size)
81
+ self.act = nn.GELU()
82
+ self.dropout = nn.Dropout(config.hidden_dropout)
83
+
84
+ def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
85
+ hidden_states = self.dense_h_to_4h(hidden_states)
86
+ hidden_states = self.act(hidden_states)
87
+ hidden_states = self.dense_4h_to_h(hidden_states)
88
+ hidden_states = self.dropout(hidden_states)
89
+ return hidden_states
90
+
91
+
92
+ class TransformerBlock(nn.Module):
93
+
94
+ def __init__(self, config: RiemannConfig):
95
+ super().__init__()
96
+ self.attention = MultiHeadAttention(config)
97
+ self.mlp = MLP(config)
98
+ self.input_layernorm = nn.LayerNorm(
99
+ config.hidden_size, eps=config.layer_norm_eps
100
+ )
101
+ self.post_attention_layernorm = nn.LayerNorm(
102
+ config.hidden_size, eps=config.layer_norm_eps
103
+ )
104
+ self.dropout = nn.Dropout(config.hidden_dropout)
105
+
106
+ def forward(
107
+ self, hidden_states: torch.Tensor, attention_mask: Optional[torch.Tensor] = None
108
+ ):
109
+ attention_layernorm_out = self.input_layernorm(hidden_states)
110
+ attention_output = self.attention(
111
+ attention_layernorm_out, attention_mask=attention_mask
112
+ )
113
+ attention_output = self.dropout(attention_output)
114
+ attention_output = attention_output + hidden_states
115
+ mlp_layernorm_out = self.post_attention_layernorm(attention_output)
116
+ mlp_output = self.mlp(mlp_layernorm_out)
117
+ layer_output = mlp_output + attention_output
118
+ return layer_output
119
+
120
+
121
+ class RiemannPreTrainedModel(PreTrainedModel):
122
+ config_class = RiemannConfig
123
+ base_model_prefix = "riemann"
124
+ supports_gradient_checkpointing = True
125
+
126
+ def _init_weights(self, module):
127
+ if isinstance(module, nn.Linear):
128
+ module.weight.data.normal_(mean=0.0, std=0.02)
129
+ if module.bias is not None:
130
+ module.bias.data.zero_()
131
+ elif isinstance(module, nn.Embedding):
132
+ module.weight.data.normal_(mean=0.0, std=0.02)
133
+ elif isinstance(module, nn.LayerNorm):
134
+ module.bias.data.zero_()
135
+ module.weight.data.fill_(1.0)
136
+
137
+
138
+ class RiemannForCausalLM(RiemannPreTrainedModel, GenerationMixin):
139
+
140
+ def __init__(self, config: RiemannConfig):
141
+ super().__init__(config)
142
+ self.config = config
143
+ self.word_embeddings = nn.Embedding(config.vocab_size, config.hidden_size)
144
+ self.position_embeddings = nn.Embedding(
145
+ config.max_position_embeddings, config.hidden_size
146
+ )
147
+ self.layers = nn.ModuleList(
148
+ [TransformerBlock(config) for _ in range(config.num_hidden_layers)]
149
+ )
150
+ self.final_layernorm = nn.LayerNorm(
151
+ config.hidden_size, eps=config.layer_norm_eps
152
+ )
153
+ self.lm_head = nn.Linear(config.hidden_size, config.vocab_size, bias=False)
154
+ self.gradient_checkpointing = False
155
+ self.post_init()
156
+
157
+ def get_input_embeddings(self):
158
+ return self.word_embeddings
159
+
160
+ def set_input_embeddings(self, value):
161
+ self.word_embeddings = value
162
+
163
+ def get_output_embeddings(self):
164
+ return self.lm_head
165
+
166
+ def set_output_embeddings(self, value):
167
+ self.lm_head = value
168
+
169
+ def _build_attention_mask(self, input_shape, attention_mask, dtype, device):
170
+ batch_size, seq_length = input_shape
171
+ causal = torch.triu(
172
+ torch.full(
173
+ (seq_length, seq_length),
174
+ torch.finfo(dtype).min,
175
+ dtype=dtype,
176
+ device=device,
177
+ ),
178
+ diagonal=1,
179
+ )
180
+ causal = causal.unsqueeze(0).unsqueeze(0)
181
+ if attention_mask is not None:
182
+ padding = attention_mask[:, None, None, :].to(dtype=dtype)
183
+ padding = (1.0 - padding) * torch.finfo(dtype).min
184
+ return causal + padding
185
+ return causal
186
+
187
+ def forward(
188
+ self,
189
+ input_ids: Optional[torch.Tensor] = None,
190
+ attention_mask: Optional[torch.Tensor] = None,
191
+ inputs_embeds: Optional[torch.Tensor] = None,
192
+ labels: Optional[torch.Tensor] = None,
193
+ use_cache: Optional[bool] = None,
194
+ **kwargs,
195
+ ):
196
+ if input_ids is not None and inputs_embeds is not None:
197
+ raise ValueError("pass either input_ids or inputs_embeds, not both")
198
+ if input_ids is not None:
199
+ inputs_embeds = self.word_embeddings(input_ids)
200
+ batch_size, seq_length = input_ids.shape
201
+ elif inputs_embeds is not None:
202
+ batch_size, seq_length = inputs_embeds.shape[:2]
203
+ else:
204
+ raise ValueError("need either input_ids or inputs_embeds")
205
+ position_ids = torch.arange(
206
+ seq_length, dtype=torch.long, device=inputs_embeds.device
207
+ )
208
+ position_ids = position_ids.unsqueeze(0).expand(batch_size, -1)
209
+ position_embeds = self.position_embeddings(position_ids)
210
+ hidden_states = inputs_embeds + position_embeds
211
+ full_mask = (
212
+ None
213
+ if attention_mask is None
214
+ else self._build_attention_mask(
215
+ (batch_size, seq_length),
216
+ attention_mask,
217
+ hidden_states.dtype,
218
+ hidden_states.device,
219
+ )
220
+ )
221
+ for layer in self.layers:
222
+ if self.gradient_checkpointing and self.training:
223
+ hidden_states = torch.utils.checkpoint.checkpoint(
224
+ layer, hidden_states, full_mask, use_reentrant=False
225
+ )
226
+ else:
227
+ hidden_states = layer(hidden_states, full_mask)
228
+ hidden_states = self.final_layernorm(hidden_states)
229
+ logits = self.lm_head(hidden_states)
230
+ loss = None
231
+ if labels is not None:
232
+ shift_logits = logits[..., :-1, :].contiguous()
233
+ shift_labels = labels[..., 1:].contiguous()
234
+ loss = F.cross_entropy(
235
+ shift_logits.view(-1, self.config.vocab_size),
236
+ shift_labels.view(-1),
237
+ ignore_index=-100,
238
+ )
239
+ return CausalLMOutputWithPast(
240
+ loss=loss, logits=logits, hidden_states=hidden_states
241
+ )
242
+
243
+ def prepare_inputs_for_generation(self, input_ids, **kwargs):
244
+ return {"input_ids": input_ids}
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ torch>=2.4
2
+ transformers>=4.56,<5
3
+ safetensors>=0.4
4
+ gradio>=5.0
5
+ spaces
6
+ huggingface_hub>=0.24