Joash2024 commited on
Commit
5162902
·
1 Parent(s): 628f881

feat: add problem types and monitoring

Browse files
Files changed (2) hide show
  1. app.py +107 -39
  2. monitoring.py +63 -0
app.py CHANGED
@@ -3,11 +3,15 @@ import torch
3
  from transformers import AutoModelForCausalLM, AutoTokenizer
4
  from peft import PeftModel
5
  import spaces
 
6
 
7
  # Model configurations
8
  BASE_MODEL = "HuggingFaceTB/SmolLM2-1.7B-Instruct" # Base model
9
  ADAPTER_MODEL = "Joash2024/Math-SmolLM2-1.7B" # Our LoRA adapter
10
 
 
 
 
11
  print("Loading tokenizer...")
12
  tokenizer = AutoTokenizer.from_pretrained(BASE_MODEL)
13
  tokenizer.pad_token = tokenizer.eos_token
@@ -30,18 +34,30 @@ model = PeftModel.from_pretrained(
30
  )
31
  model.eval()
32
 
33
- def format_prompt(function: str) -> str:
34
  """Format input prompt for the model"""
35
- return f"""Given a mathematical function, find its derivative.
 
36
 
37
- Function: {function}
38
  The derivative of this function is:"""
 
 
 
 
 
 
 
 
 
 
39
 
40
  @spaces.GPU
41
- def generate_derivative(function: str, max_length: int = 100) -> str:
42
- """Generate derivative for a given function"""
 
43
  # Format prompt
44
- prompt = format_prompt(function)
45
 
46
  # Tokenize
47
  inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
@@ -50,75 +66,127 @@ def generate_derivative(function: str, max_length: int = 100) -> str:
50
  with torch.no_grad():
51
  outputs = model.generate(
52
  **inputs,
53
- max_length=max_length,
54
  num_return_sequences=1,
55
  temperature=0.1,
56
  do_sample=False, # Deterministic generation
57
  pad_token_id=tokenizer.eos_token_id
58
  )
59
 
60
- # Decode and extract derivative
61
  generated = tokenizer.decode(outputs[0], skip_special_tokens=True)
62
- derivative = generated[len(prompt):].strip()
63
 
64
- return derivative
65
 
66
  @spaces.GPU
67
- def solve_derivative(function: str) -> str:
68
- """Solve derivative and format output"""
69
- if not function:
70
- return "Please enter a function"
71
 
72
- print(f"\nGenerating derivative for: {function}")
73
- derivative = generate_derivative(function)
74
 
75
- # Format output with step-by-step explanation
76
- output = f"""Generated derivative: {derivative}
 
 
 
 
77
 
78
  Let's verify this step by step:
79
- 1. Starting with f(x) = {function}
80
  2. Applying differentiation rules
81
- 3. We get f'(x) = {derivative}"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
82
 
83
- return output
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
 
85
  # Create Gradio interface
86
- with gr.Blocks(title="Mathematics Derivative Solver") as demo:
87
- gr.Markdown("# Mathematics Derivative Solver")
88
- gr.Markdown("Using our fine-tuned model to solve derivatives")
89
 
90
  with gr.Row():
91
  with gr.Column():
92
- function_input = gr.Textbox(
93
- label="Enter a function",
94
- placeholder="Example: x^2, sin(x), e^x"
 
 
 
 
 
95
  )
96
- solve_btn = gr.Button("Find Derivative", variant="primary")
97
 
98
  with gr.Row():
99
- output = gr.Textbox(
100
  label="Solution with Steps",
101
  lines=6
102
  )
103
 
104
- # Example functions (reduced)
 
 
 
 
105
  gr.Examples(
106
  examples=[
107
- ["x^2"],
108
- ["\\sin{\\left(x\\right)}"],
109
- ["e^x"]
 
 
 
110
  ],
111
- inputs=function_input,
112
- outputs=output,
113
- fn=solve_derivative,
114
  cache_examples=False # Disable caching
115
  )
116
 
117
  # Connect the interface
118
  solve_btn.click(
119
- fn=solve_derivative,
120
- inputs=[function_input],
121
- outputs=output
122
  )
123
 
124
  if __name__ == "__main__":
 
3
  from transformers import AutoModelForCausalLM, AutoTokenizer
4
  from peft import PeftModel
5
  import spaces
6
+ from monitoring import PerformanceMonitor, measure_time
7
 
8
  # Model configurations
9
  BASE_MODEL = "HuggingFaceTB/SmolLM2-1.7B-Instruct" # Base model
10
  ADAPTER_MODEL = "Joash2024/Math-SmolLM2-1.7B" # Our LoRA adapter
11
 
12
+ # Initialize performance monitor
13
+ monitor = PerformanceMonitor()
14
+
15
  print("Loading tokenizer...")
16
  tokenizer = AutoTokenizer.from_pretrained(BASE_MODEL)
17
  tokenizer.pad_token = tokenizer.eos_token
 
34
  )
35
  model.eval()
36
 
37
+ def format_prompt(problem: str, problem_type: str) -> str:
38
  """Format input prompt for the model"""
39
+ if problem_type == "Derivative":
40
+ return f"""Given a mathematical function, find its derivative.
41
 
42
+ Function: {problem}
43
  The derivative of this function is:"""
44
+ elif problem_type == "Addition":
45
+ return f"""Solve this addition problem.
46
+
47
+ Problem: {problem}
48
+ The solution is:"""
49
+ else: # Roots or Custom
50
+ return f"""Find the roots of this equation.
51
+
52
+ Equation: {problem}
53
+ The roots are:"""
54
 
55
  @spaces.GPU
56
+ @measure_time
57
+ def get_model_response(problem: str, problem_type: str) -> str:
58
+ """Generate response from model"""
59
  # Format prompt
60
+ prompt = format_prompt(problem, problem_type)
61
 
62
  # Tokenize
63
  inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
 
66
  with torch.no_grad():
67
  outputs = model.generate(
68
  **inputs,
69
+ max_length=100,
70
  num_return_sequences=1,
71
  temperature=0.1,
72
  do_sample=False, # Deterministic generation
73
  pad_token_id=tokenizer.eos_token_id
74
  )
75
 
76
+ # Decode and extract response
77
  generated = tokenizer.decode(outputs[0], skip_special_tokens=True)
78
+ response = generated[len(prompt):].strip()
79
 
80
+ return response
81
 
82
  @spaces.GPU
83
+ def solve_problem(problem: str, problem_type: str) -> tuple:
84
+ """Solve math problem and track performance"""
85
+ if not problem:
86
+ return "Please enter a problem", None
87
 
88
+ # Record problem type
89
+ monitor.record_problem_type(problem_type)
90
 
91
+ # Get model response with timing
92
+ response, time_taken = get_model_response(problem, problem_type)
93
+
94
+ # Format output with steps
95
+ if problem_type == "Derivative":
96
+ output = f"""Generated derivative: {response}
97
 
98
  Let's verify this step by step:
99
+ 1. Starting with f(x) = {problem}
100
  2. Applying differentiation rules
101
+ 3. We get f'(x) = {response}"""
102
+ elif problem_type == "Addition":
103
+ output = f"""Solution: {response}
104
+
105
+ Let's verify this step by step:
106
+ 1. Starting with: {problem}
107
+ 2. Adding the numbers
108
+ 3. We get: {response}"""
109
+ else: # Roots
110
+ output = f"""Found roots: {response}
111
+
112
+ Let's verify this step by step:
113
+ 1. Starting with equation: {problem}
114
+ 2. Solving for x
115
+ 3. Roots are: {response}"""
116
+
117
+ # Record metrics
118
+ monitor.record_response_time("model", time_taken)
119
+ monitor.record_success("model", not response.startswith("Error"))
120
 
121
+ # Get updated statistics
122
+ stats = monitor.get_statistics()
123
+
124
+ # Format statistics for display
125
+ stats_display = f"""
126
+ ### Performance Metrics
127
+
128
+ #### Response Times
129
+ - Average: {stats.get('model_avg_response_time', 0):.2f} seconds
130
+
131
+ #### Success Rate
132
+ - {stats.get('model_success_rate', 0):.1f}%
133
+
134
+ #### Problem Types Used
135
+ """
136
+ for ptype, percentage in stats.get('problem_type_distribution', {}).items():
137
+ stats_display += f"- {ptype}: {percentage:.1f}%\n"
138
+
139
+ return output, stats_display
140
 
141
  # Create Gradio interface
142
+ with gr.Blocks(title="Mathematics Problem Solver") as demo:
143
+ gr.Markdown("# Mathematics Problem Solver")
144
+ gr.Markdown("Using our fine-tuned model to solve mathematical problems")
145
 
146
  with gr.Row():
147
  with gr.Column():
148
+ problem_type = gr.Dropdown(
149
+ choices=["Derivative", "Addition", "Roots"],
150
+ value="Derivative",
151
+ label="Problem Type"
152
+ )
153
+ problem_input = gr.Textbox(
154
+ label="Enter your problem",
155
+ placeholder="Example: x^2 + 3x"
156
  )
157
+ solve_btn = gr.Button("Solve", variant="primary")
158
 
159
  with gr.Row():
160
+ solution_output = gr.Textbox(
161
  label="Solution with Steps",
162
  lines=6
163
  )
164
 
165
+ # Performance metrics display
166
+ with gr.Row():
167
+ metrics_display = gr.Markdown("### Performance Metrics\n*Solve a problem to see metrics*")
168
+
169
+ # Example problems
170
  gr.Examples(
171
  examples=[
172
+ ["x^2 + 3x", "Derivative"],
173
+ ["235 + 567", "Addition"],
174
+ ["x^2 - 4", "Roots"],
175
+ ["\\sin{\\left(x\\right)}", "Derivative"],
176
+ ["e^x", "Derivative"],
177
+ ["\\frac{1}{x}", "Derivative"]
178
  ],
179
+ inputs=[problem_input, problem_type],
180
+ outputs=[solution_output, metrics_display],
181
+ fn=solve_problem,
182
  cache_examples=False # Disable caching
183
  )
184
 
185
  # Connect the interface
186
  solve_btn.click(
187
+ fn=solve_problem,
188
+ inputs=[problem_input, problem_type],
189
+ outputs=[solution_output, metrics_display]
190
  )
191
 
192
  if __name__ == "__main__":
monitoring.py ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import time
2
+ from functools import wraps
3
+ from collections import defaultdict
4
+ import numpy as np
5
+
6
+ class PerformanceMonitor:
7
+ def __init__(self):
8
+ self.response_times = defaultdict(list)
9
+ self.success_counts = defaultdict(int)
10
+ self.total_counts = defaultdict(int)
11
+ self.problem_types = defaultdict(int)
12
+ self.total_problems = 0
13
+
14
+ def record_response_time(self, model_type: str, time: float):
15
+ """Record response time for a model"""
16
+ self.response_times[model_type].append(time)
17
+
18
+ def record_success(self, model_type: str, success: bool):
19
+ """Record success/failure for a model"""
20
+ self.total_counts[model_type] += 1
21
+ if success:
22
+ self.success_counts[model_type] += 1
23
+
24
+ def record_problem_type(self, problem_type: str):
25
+ """Record problem type"""
26
+ self.problem_types[problem_type] += 1
27
+ self.total_problems += 1
28
+
29
+ def get_statistics(self) -> dict:
30
+ """Get current performance statistics"""
31
+ stats = {}
32
+
33
+ # Calculate average response times
34
+ for model_type, times in self.response_times.items():
35
+ if times:
36
+ stats[f'{model_type}_avg_response_time'] = np.mean(times)
37
+
38
+ # Calculate success rates
39
+ for model_type in self.total_counts.keys():
40
+ total = self.total_counts[model_type]
41
+ if total > 0:
42
+ success_rate = (self.success_counts[model_type] / total) * 100
43
+ stats[f'{model_type}_success_rate'] = success_rate
44
+
45
+ # Calculate problem type distribution
46
+ if self.total_problems > 0:
47
+ distribution = {
48
+ ptype: (count / self.total_problems) * 100
49
+ for ptype, count in self.problem_types.items()
50
+ }
51
+ stats['problem_type_distribution'] = distribution
52
+
53
+ return stats
54
+
55
+ def measure_time(func):
56
+ """Decorator to measure function execution time"""
57
+ @wraps(func)
58
+ def wrapper(*args, **kwargs):
59
+ start_time = time.time()
60
+ result = func(*args, **kwargs)
61
+ end_time = time.time()
62
+ return result, end_time - start_time
63
+ return wrapper