BaggerOfWords commited on
Commit
41a8e71
·
1 Parent(s): f3c1907

added default configs

Browse files
Files changed (2) hide show
  1. app.py +198 -78
  2. mosaic.py +42 -22
app.py CHANGED
@@ -1,124 +1,244 @@
1
  import gradio as gr
2
  from mosaic import Mosaic # adjust import as needed
3
  import spaces
4
-
 
 
5
 
6
  # Maximum number of model textboxes
7
  MAX_MODELS = 10
 
 
 
 
 
 
 
 
8
 
 
 
 
 
 
 
 
 
9
  def update_textboxes(n_visible):
10
- """
11
- Given the current visible count, increments it by 1 (up to MAX_MODELS)
12
- and returns updated visibility settings for all model textboxes.
13
- """
14
  if n_visible < MAX_MODELS:
15
  n_visible += 1
16
- # Create a list of update objects for each textbox: visible if its index is less than n_visible.
17
- updates = []
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  for i in range(MAX_MODELS):
19
  if i < n_visible:
20
- updates.append(gr.update(visible=True))
 
 
21
  else:
22
- updates.append(gr.update(visible=False))
23
- return n_visible, *updates
 
 
24
 
25
- # Function to decrease visible textboxes
26
- def remove_textboxes(n_visible):
27
  """
28
- Given the current visible count, decrements it by 1 (down to 2)
29
- and returns updated visibility settings for all model textboxes,
30
- clearing the content of any hidden ones.
 
31
  """
32
- if n_visible > 2:
33
- n_visible -= 1
34
- updates = []
35
  for i in range(MAX_MODELS):
36
- if i < n_visible:
37
- # keep visible, preserve existing value
38
- updates.append(gr.update(visible=True))
 
 
39
  else:
40
- # hide and clear content
41
- updates.append(gr.update(visible=False, value=""))
42
- return (n_visible, *updates)
 
 
 
 
 
43
 
44
- @spaces.GPU()
45
- def run_scoring(input_text, model1, model2, model3, model4, model5, model6, model7, model8, model9, model10, threshold_choice, custom_threshold):
46
  """
47
- Collect all non-empty model paths, instantiate Mosaic, compute the score,
48
- and return a message based on the threshold.
 
 
49
  """
50
- model_paths = []
51
- for m in [model1, model2, model3, model4, model5, model6, model7, model8, model9, model10]:
52
- if m.strip() != "":
53
- model_paths.append(m.strip())
54
- if len(model_paths) < 2:
55
- return "Please enter at least two model paths.", None, None
56
- # Choose threshold value
57
- if threshold_choice == "default":
58
- threshold = 0.0
59
- elif threshold_choice == "raid":
60
- threshold = 0.23
61
- elif threshold_choice == "custom":
62
- threshold = custom_threshold
63
- else:
64
- threshold = 0.0
65
- # Instantiate the Mosaic class with the selected model paths.
66
- mosaic_instance = Mosaic(model_name_or_paths=model_paths, one_model_mode=False)
67
- final_score = mosaic_instance.compute_end_score(input_text)
68
- if final_score < threshold:
69
- result_message = "This text was probably generated."
70
- else:
71
- result_message = "This text is likely human-written."
72
- return result_message, final_score, threshold
73
 
74
- with gr.Blocks() as demo:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
  gr.Markdown("# MOSAIC Scoring App")
76
  with gr.Row():
77
  input_text = gr.Textbox(lines=10, placeholder="Enter text here...", label="Input Text")
78
  with gr.Column():
79
  gr.Markdown("**⚠️ Please make sure all models have the same tokenizer or it won’t work.**")
80
  gr.Markdown("### Model Paths (at least 2 required)")
81
- gr.Markdown("Order matters for model 1 only, the Reference model. Please use the one with the best perplexity on human texts. (The largest LLM if applicable.) GPT2 models are enough to detect easy prompts from chatgpt.")
82
- # State to keep track of the number of visible textboxes (starting with 2)
83
  n_models_state = gr.State(4)
84
- # Create 10 textboxes. We'll name them model1, model2, ..., model10.
85
- model1 = gr.Textbox(value="Unbabel/TowerBase-13B-v0.1", label="Model 1 Path ", visible=True)
86
- model2 = gr.Textbox(value="Unbabel/TowerBase-7B-v0.1", label="Model 2 Path", visible=True)
87
- model3 = gr.Textbox(value="meta-llama/Llama-2-7b-chat-hf", label="Model 3 Path", visible=True)
88
- model4 = gr.Textbox(value="meta-llama/Llama-2-7b-hf", label="Model 4 Path", visible=True)
89
- model5 = gr.Textbox(value="", label="Model 5 Path", visible=False)
90
- model6 = gr.Textbox(value="", label="Model 6 Path", visible=False)
91
- model7 = gr.Textbox(value="", label="Model 7 Path", visible=False)
92
- model8 = gr.Textbox(value="", label="Model 8 Path", visible=False)
93
- model9 = gr.Textbox(value="", label="Model 9 Path", visible=False)
94
- model10 = gr.Textbox(value="", label="Model 10 Path", visible=False)
95
- # Add plus and minus buttons to reveal/hide textboxes.
 
 
96
  with gr.Row():
97
- plus_button = gr.Button("+", elem_id="plus_button")
98
- minus_button = gr.Button("-", elem_id="minus_button")
99
- # Bind click events
100
- plus_button.click(
 
101
  fn=update_textboxes,
102
  inputs=n_models_state,
103
- outputs=[n_models_state, model1, model2, model3, model4, model5, model6, model7, model8, model9, model10]
104
  )
105
- minus_button.click(
106
  fn=remove_textboxes,
107
  inputs=n_models_state,
108
- outputs=[n_models_state, model1, model2, model3, model4, model5, model6, model7, model8, model9, model10]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
  )
110
  with gr.Row():
111
- threshold_choice = gr.Radio(choices=["default", "raid", "custom"], value="default", label="Threshold Choice")
112
  custom_threshold = gr.Number(value=0.0, label="Custom Threshold (if 'custom' selected)")
113
  with gr.Row():
114
  output_message = gr.Textbox(label="Result Message")
115
  output_score = gr.Number(label="Final Score")
116
  output_threshold = gr.Number(label="Threshold Used")
117
- run_button = gr.Button("Run Scoring")
 
 
 
 
 
 
 
 
 
 
 
 
 
118
  run_button.click(
119
  fn=run_scoring,
120
- inputs=[input_text, model1, model2, model3, model4, model5, model6, model7, model8, model9, model10, threshold_choice, custom_threshold],
121
  outputs=[output_message, output_score, output_threshold]
122
  )
123
-
124
- demo.launch()
 
1
  import gradio as gr
2
  from mosaic import Mosaic # adjust import as needed
3
  import spaces
4
+ import traceback
5
+ from transformers import AutoModelForCausalLM
6
+ import torch
7
 
8
  # Maximum number of model textboxes
9
  MAX_MODELS = 10
10
+ # Cache for loaded models to reuse
11
+ LOADED_MODELS = {}
12
+
13
+ GPT_CONFIG_MODELS = [
14
+ "openai-community/gpt2-large",
15
+ "openai-community/gpt2-medium",
16
+ "openai-community/gpt2"
17
+ ]
18
 
19
+ Falcon_CONFIG_MODELS = [
20
+ "tiiuae/Falcon3-10B-Base",
21
+ "tiiuae/Falcon3-10B-Instruct",
22
+ "tiiuae/Falcon3-7B-Base",
23
+ "tiiuae/Falcon3-7B-Instruct"
24
+ ]
25
+
26
+ # Increase model slots
27
  def update_textboxes(n_visible):
 
 
 
 
28
  if n_visible < MAX_MODELS:
29
  n_visible += 1
30
+ tb_updates = [gr.update(visible=(i < n_visible)) for i in range(MAX_MODELS)]
31
+ btn_updates = [gr.update(visible=(i < n_visible)) for i in range(MAX_MODELS)]
32
+ status_updates = [gr.update(visible=(i < n_visible)) for i in range(MAX_MODELS)]
33
+ return (n_visible, *tb_updates, *btn_updates, *status_updates)
34
+
35
+ # Decrease model slots and clear removed entries
36
+ def remove_textboxes(n_visible):
37
+ old = n_visible
38
+ if n_visible > 2:
39
+ n_visible -= 1
40
+ new = n_visible
41
+ # Remove cached models for slots now hidden
42
+ for idx in range(new, old):
43
+ LOADED_MODELS.pop(idx+1, None)
44
+ tb_updates, btn_updates, status_updates = [], [], []
45
  for i in range(MAX_MODELS):
46
  if i < n_visible:
47
+ tb_updates.append(gr.update(visible=True))
48
+ btn_updates.append(gr.update(visible=True))
49
+ status_updates.append(gr.update(visible=True))
50
  else:
51
+ tb_updates.append(gr.update(visible=False, value=""))
52
+ btn_updates.append(gr.update(visible=False))
53
+ status_updates.append(gr.update(visible=False, value="Not loaded"))
54
+ return (n_visible, *tb_updates, *btn_updates, *status_updates)
55
 
56
+ def apply_config1():
 
57
  """
58
+ Returns:
59
+ - new n_visible (number of boxes to show)
60
+ - new values & visibility for each model textbox
61
+ - new visibility for each Load button & status box
62
  """
63
+ n_vis = len(GPT_CONFIG_MODELS)
64
+ tb_updates, btn_updates, status_updates = [], [], []
65
+
66
  for i in range(MAX_MODELS):
67
+ if i < n_vis:
68
+ # show this slot, set its value from CONFIG_MODELS
69
+ tb_updates.append(gr.update(visible=True, value=GPT_CONFIG_MODELS[i]))
70
+ btn_updates.append(gr.update(visible=True))
71
+ status_updates.append(gr.update(visible=True, value="Not loaded"))
72
  else:
73
+ # hide all others
74
+ tb_updates.append(gr.update(visible=False, value=""))
75
+ btn_updates.append(gr.update(visible=False))
76
+ status_updates.append(gr.update(visible=False, value="Not loaded"))
77
+
78
+ # Return in the same shape as your update_textboxes/remove_textboxes:
79
+ # (n_models_state, *all textboxes, *all load buttons, *all status boxes)
80
+ return (n_vis, *tb_updates, *btn_updates, *status_updates)
81
 
82
+ def apply_config2():
 
83
  """
84
+ Returns:
85
+ - new n_visible (number of boxes to show)
86
+ - new values & visibility for each model textbox
87
+ - new visibility for each Load button & status box
88
  """
89
+ n_vis = len(Falcon_CONFIG_MODELS)
90
+ tb_updates, btn_updates, status_updates = [], [], []
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
 
92
+ for i in range(MAX_MODELS):
93
+ if i < n_vis:
94
+ # show this slot, set its value from CONFIG_MODELS
95
+ tb_updates.append(gr.update(visible=True, value=Falcon_CONFIG_MODELS[i]))
96
+ btn_updates.append(gr.update(visible=True))
97
+ status_updates.append(gr.update(visible=True, value="Not loaded"))
98
+ else:
99
+ # hide all others
100
+ tb_updates.append(gr.update(visible=False, value=""))
101
+ btn_updates.append(gr.update(visible=False))
102
+ status_updates.append(gr.update(visible=False, value="Not loaded"))
103
+
104
+ # Return in the same shape as your update_textboxes/remove_textboxes:
105
+ # (n_models_state, *all textboxes, *all load buttons, *all status boxes)
106
+ return (n_vis, *tb_updates, *btn_updates, *status_updates)
107
+
108
+ # Load a single model and report status
109
+ def load_single_model(model_path, use_bfloat16=True):
110
+ try:
111
+ repo = model_path
112
+ if not repo:
113
+ return "Error: No path provided"
114
+ if repo in LOADED_MODELS:
115
+ return "Loaded"
116
+ # actual load; may raise
117
+ model = AutoModelForCausalLM.from_pretrained(
118
+ repo,
119
+ device_map="auto",
120
+ trust_remote_code=True,
121
+ torch_dtype=torch.bfloat16 if use_bfloat16 else torch.float32,
122
+ )
123
+ model.eval()
124
+ LOADED_MODELS[repo] = model
125
+ return "Loaded"
126
+ except Exception as e:
127
+ return f"Error loading model: {e}"
128
+
129
+ # Determine interactive state for Run button
130
+ def check_all_loaded(n_visible, *status_texts):
131
+ # status_texts are strings: "Loaded" indicates success
132
+ needed = status_texts[:n_visible]
133
+ if all(s == "Loaded" for s in needed):
134
+ return gr.update(interactive=True)
135
+ return gr.update(interactive=False)
136
+
137
+ @spaces.GPU()
138
+ def run_scoring(input_text, *args):
139
+ """
140
+ args: first MAX_MODELS entries are model paths, followed by threshold_choice and custom_threshold
141
+ """
142
+ try:
143
+ # unpack
144
+ models = [m.strip() for m in args[:MAX_MODELS] if m.strip()]
145
+ threshold_choice = args[MAX_MODELS]
146
+ custom_threshold = args[MAX_MODELS+1]
147
+ if len(models) < 2:
148
+ return "Please enter at least two model paths.", None, None
149
+ threshold = 0.0 if threshold_choice == "default" else custom_threshold
150
+ mosaic_instance = Mosaic(model_name_or_paths=models, one_model_mode=False, loaded_models=LOADED_MODELS)
151
+ final_score = mosaic_instance.compute_end_score(input_text)
152
+ msg = "This text was probably generated." if final_score < threshold else "This text is likely human-written."
153
+ return msg, final_score, threshold
154
+ except Exception as e:
155
+ tb = traceback.format_exc()
156
+ return f"Error: {e}\n{tb}", None, None
157
+
158
+ # Build Blocks UI
159
+ demo = gr.Blocks()
160
+ with demo:
161
  gr.Markdown("# MOSAIC Scoring App")
162
  with gr.Row():
163
  input_text = gr.Textbox(lines=10, placeholder="Enter text here...", label="Input Text")
164
  with gr.Column():
165
  gr.Markdown("**⚠️ Please make sure all models have the same tokenizer or it won’t work.**")
166
  gr.Markdown("### Model Paths (at least 2 required)")
 
 
167
  n_models_state = gr.State(4)
168
+ model_inputs, load_buttons, status_boxes = [], [], []
169
+ for i in range(1, MAX_MODELS+1):
170
+ with gr.Row():
171
+ tb = gr.Textbox(label=f"Model {i} Path", value="" if i > 4 else None, visible=(i <= 4))
172
+ btn = gr.Button("Load", elem_id=f"load_{i}", visible=(i <= 4))
173
+ status = gr.Textbox(label="Loading status", value="Not loaded", interactive=False, visible=(i <= 4))
174
+ btn.click(
175
+ fn=load_single_model,
176
+ inputs=[tb, gr.State(i)],
177
+ outputs=status
178
+ )
179
+ model_inputs.append(tb)
180
+ load_buttons.append(btn)
181
+ status_boxes.append(status)
182
  with gr.Row():
183
+ plus = gr.Button("Add model slot", elem_id="plus_button")
184
+ minus = gr.Button("Remove model slot", elem_id="minus_button")
185
+ config1_btn = gr.Button("Try Basic gpt Configuration")
186
+ config2_btn = gr.Button("Try Falcon models Configuration")
187
+ plus.click(
188
  fn=update_textboxes,
189
  inputs=n_models_state,
190
+ outputs=[n_models_state, *model_inputs, *load_buttons, *status_boxes]
191
  )
192
+ minus.click(
193
  fn=remove_textboxes,
194
  inputs=n_models_state,
195
+ outputs=[n_models_state, *model_inputs, *load_buttons, *status_boxes]
196
+ )
197
+ config1_btn.click(
198
+ fn=apply_config1,
199
+ inputs=None, # no inputs needed
200
+ outputs=[ # must match order:
201
+ n_models_state, # 1️⃣ the new visible‑count State
202
+ *model_inputs, # 2️⃣ your list of 10 Textboxes
203
+ *load_buttons, # 3️⃣ your list of 10 Load Buttons
204
+ *status_boxes # 4️⃣ your list of 10 Status Textboxes
205
+ ]
206
+ )
207
+ config2_btn.click(
208
+ fn=apply_config2,
209
+ inputs=None, # no inputs needed
210
+ outputs=[ # must match order:
211
+ n_models_state, # 1️⃣ the new visible‑count State
212
+ *model_inputs, # 2️⃣ your list of 10 Textboxes
213
+ *load_buttons, # 3️⃣ your list of 10 Load Buttons
214
+ *status_boxes # 4️⃣ your list of 10 Status Textboxes
215
+ ]
216
  )
217
  with gr.Row():
218
+ threshold_choice = gr.Radio(choices=["default", "custom"], value="default", label="Threshold Choice")
219
  custom_threshold = gr.Number(value=0.0, label="Custom Threshold (if 'custom' selected)")
220
  with gr.Row():
221
  output_message = gr.Textbox(label="Result Message")
222
  output_score = gr.Number(label="Final Score")
223
  output_threshold = gr.Number(label="Threshold Used")
224
+ gr.Markdown("**⚠️ All models need to be loaded before scoring.**")
225
+ run_button = gr.Button("Run Scoring", interactive=False)
226
+ # Enable Run button when all statuses reflect "Loaded"
227
+ for status in status_boxes:
228
+ status.change(
229
+ fn=check_all_loaded,
230
+ inputs=[n_models_state, *status_boxes],
231
+ outputs=run_button
232
+ )
233
+ n_models_state.change(
234
+ fn=check_all_loaded,
235
+ inputs=[n_models_state, *status_boxes],
236
+ outputs=run_button
237
+ )
238
  run_button.click(
239
  fn=run_scoring,
240
+ inputs=[input_text, *model_inputs, threshold_choice, custom_threshold],
241
  outputs=[output_message, output_score, output_threshold]
242
  )
243
+ # Launch
244
+ demo.launch()
mosaic.py CHANGED
@@ -1,4 +1,4 @@
1
- from typing import List, Optional
2
  import numpy as np
3
  import torch
4
  import transformers
@@ -49,36 +49,56 @@ def apply_top_p_with_epsilon(logits: torch.Tensor, top_p: float, epsilon: float
49
  return new_logits
50
 
51
  class Mosaic(object):
52
- def __init__(self,
53
- model_name_or_paths: List[str],
54
- use_bfloat16: bool = True,
55
- max_token_observed: int = 512,
56
- unigram: Optional[str] = None,
57
- custom_config : Optional[List[bool]] = None,
58
- stupid_mode: bool = False,
59
- one_model_mode: bool = False
60
- ) -> None:
 
 
 
 
 
 
 
 
61
  self.models = []
62
- for i, model_name_or_path in enumerate(model_name_or_paths):
63
- model = AutoModelForCausalLM.from_pretrained(model_name_or_path,
64
- device_map="auto",
65
- trust_remote_code=True,
66
- torch_dtype=torch.bfloat16 if use_bfloat16
67
- else torch.float32
68
- )
69
- model.eval() # Set the model to evaluation mode
 
 
 
 
 
 
 
 
 
 
 
 
70
  self.models.append(model)
71
  print(f"Loaded model: {model_name_or_path}")
72
- # Print the device map
73
- #print(f"Device map for {model_name_or_path}: {model.hf_device_map}")
 
 
74
 
75
  if stupid_mode:
76
  self.max_iters = 0
77
  else:
78
  self.max_iters = 1000
79
 
80
- self.one_model_mode = one_model_mode
81
-
82
  self.tokenizer = AutoTokenizer.from_pretrained(model_name_or_paths[-1])
83
  if not self.tokenizer.pad_token:
84
  self.tokenizer.pad_token = self.tokenizer.eos_token
 
1
+ from typing import List, Optional, Dict
2
  import numpy as np
3
  import torch
4
  import transformers
 
49
  return new_logits
50
 
51
  class Mosaic(object):
52
+ def __init__(
53
+ self,
54
+ model_name_or_paths: List[str],
55
+ use_bfloat16: bool = True,
56
+ max_token_observed: int = 512,
57
+ unigram: Optional[str] = None,
58
+ custom_config: Optional[List[bool]] = None,
59
+ stupid_mode: bool = False,
60
+ one_model_mode: bool = False,
61
+ # new optional argument: preloaded models dict
62
+ loaded_models: Optional[Dict[str, AutoModelForCausalLM]] = None,
63
+ ) -> None:
64
+ """
65
+ If `loaded_models` is provided, re-use any entries matching
66
+ model_name_or_paths; otherwise load and optionally register
67
+ into that dict.
68
+ """
69
  self.models = []
70
+ # ensure we have a dict to cache into if passed
71
+ cache = loaded_models if loaded_models is not None else {}
72
+
73
+ for model_name_or_path in model_name_or_paths:
74
+ # reuse if already loaded
75
+ if loaded_models is not None and model_name_or_path in cache:
76
+ model = cache[model_name_or_path]
77
+ else:
78
+ print("Reloading a model was necessary, you probably messed up.")
79
+ # load from pre-trained hub or path
80
+ model = AutoModelForCausalLM.from_pretrained(
81
+ model_name_or_path,
82
+ device_map="auto",
83
+ trust_remote_code=True,
84
+ torch_dtype=torch.bfloat16 if use_bfloat16 else torch.float32,
85
+ )
86
+ model.eval()
87
+ # cache for reuse
88
+ if loaded_models is not None:
89
+ cache[model_name_or_path] = model
90
  self.models.append(model)
91
  print(f"Loaded model: {model_name_or_path}")
92
+
93
+ # store optional references
94
+ self.loaded_models = cache
95
+ self.one_model_mode = one_model_mode
96
 
97
  if stupid_mode:
98
  self.max_iters = 0
99
  else:
100
  self.max_iters = 1000
101
 
 
 
102
  self.tokenizer = AutoTokenizer.from_pretrained(model_name_or_paths[-1])
103
  if not self.tokenizer.pad_token:
104
  self.tokenizer.pad_token = self.tokenizer.eos_token