Spaces:
Paused
Paused
| """ | |
| Gradio app for MentorFlow - Teacher-Student RL System | |
| Deployed on Hugging Face Spaces with GPU support | |
| """ | |
| import sys | |
| import os | |
| import subprocess | |
| from pathlib import Path | |
| import gradio as gr # Import directly, do not use the patch | |
| # Add project paths | |
| sys.path.insert(0, str(Path(__file__).parent)) | |
| sys.path.insert(0, str(Path(__file__).parent / "teacher_agent_dev")) | |
| sys.path.insert(0, str(Path(__file__).parent / "student_agent_dev")) | |
| def run_comparison(iterations: int, seed: int, use_deterministic: bool, device: str): | |
| """ | |
| Run strategy comparison with LM Student. | |
| """ | |
| # Set device environment variable for subprocess | |
| # On Hugging Face Spaces with GPU, try to use CUDA | |
| if device == "cuda": | |
| try: | |
| import torch | |
| # Check if CUDA is available | |
| if torch.cuda.is_available(): | |
| try: | |
| # Try to get device name to verify GPU works | |
| gpu_name = torch.cuda.get_device_name(0) | |
| gpu_count = torch.cuda.device_count() | |
| print(f"β GPU available: {gpu_name} (Count: {gpu_count})") | |
| # Keep device as "cuda" | |
| except Exception as e: | |
| print(f"β οΈ GPU detection failed: {e}") | |
| print(" Attempting to use CUDA anyway (may work)...") | |
| else: | |
| print("β οΈ CUDA not available, falling back to CPU") | |
| device = "cpu" | |
| except ImportError: | |
| print("β οΈ PyTorch not available, falling back to CPU") | |
| device = "cpu" | |
| except Exception as e: | |
| print(f"β οΈ GPU check error: {e}, falling back to CPU") | |
| device = "cpu" | |
| # Set environment variable for subprocess to pick up | |
| os.environ["CUDA_DEVICE"] = device | |
| print(f"π§ Using device: {device}") | |
| # Prepare command | |
| cmd = [ | |
| sys.executable, | |
| "teacher_agent_dev/compare_strategies.py", | |
| "--iterations", str(iterations), | |
| ] | |
| if use_deterministic: | |
| cmd.append("--deterministic") | |
| else: | |
| cmd.extend(["--seed", str(int(seed))]) | |
| try: | |
| # Ensure environment variables are passed to subprocess | |
| env = os.environ.copy() | |
| env["CUDA_DEVICE"] = os.environ.get("CUDA_DEVICE", device) | |
| result = subprocess.run( | |
| cmd, | |
| cwd=str(Path(__file__).parent), | |
| env=env, # Pass environment variables | |
| capture_output=True, | |
| text=True, | |
| timeout=3600 # 1 hour timeout | |
| ) | |
| stdout_text = result.stdout | |
| stderr_text = result.stderr | |
| # Combine outputs | |
| full_output = f"=== STDOUT ===\n{stdout_text}\n\n=== STDERR ===\n{stderr_text}" | |
| if result.returncode != 0: | |
| return f"β Error occurred:\n{full_output}", None | |
| # Find output plot (check multiple possible locations) | |
| plot_paths = [ | |
| Path(__file__).parent / "teacher_agent_dev" / "comparison_all_strategies.png", | |
| Path(__file__).parent / "comparison_all_strategies.png", | |
| Path.cwd() / "teacher_agent_dev" / "comparison_all_strategies.png", | |
| ] | |
| plot_path = None | |
| for path in plot_paths: | |
| if path.exists(): | |
| plot_path = path | |
| break | |
| if plot_path: | |
| return f"β Comparison complete!\n\n{stdout_text}", str(plot_path) | |
| else: | |
| # Return output even if plot not found (might still be useful) | |
| error_msg = f"β οΈ Plot not found at expected locations.\n" | |
| error_msg += f"Checked: {[str(p) for p in plot_paths]}\n\n" | |
| error_msg += f"Output:\n{full_output}" | |
| return error_msg, None | |
| except subprocess.TimeoutExpired: | |
| return "β Timeout: Comparison took longer than 1 hour", None | |
| except Exception as e: | |
| import traceback | |
| return f"β Error: {str(e)}\n\n{traceback.format_exc()}", None | |
| def check_gpu(): | |
| """Check if GPU is available on Hugging Face Spaces.""" | |
| try: | |
| import torch | |
| # Check CUDA availability | |
| if torch.cuda.is_available(): | |
| try: | |
| gpu_name = torch.cuda.get_device_name(0) | |
| gpu_count = torch.cuda.device_count() | |
| cuda_version = torch.version.cuda | |
| return f"β GPU Available: {gpu_name} (Count: {gpu_count}, CUDA: {cuda_version})" | |
| except Exception as e: | |
| # GPU might be available but not immediately accessible | |
| return f"β GPU Detected (accessing: {str(e)[:50]}...)" | |
| else: | |
| # On Hugging Face Spaces, check environment | |
| if os.getenv("SPACE_ID"): | |
| # Check if GPU hardware is allocated | |
| hf_hardware = os.getenv("SPACE_HARDWARE", "unknown") | |
| if "gpu" in hf_hardware.lower() or "t4" in hf_hardware.lower() or "l4" in hf_hardware.lower(): | |
| return f"β οΈ GPU Hardware ({hf_hardware}) allocated but not accessible yet. Try running anyway." | |
| return f"β οΈ No GPU on this Space (hardware: {hf_hardware}). Please configure GPU tier." | |
| return "β οΈ No GPU available, will use CPU" | |
| except ImportError: | |
| return "β οΈ PyTorch not installed" | |
| except Exception as e: | |
| return f"β οΈ GPU check error: {str(e)}" | |
| # Create Gradio interface | |
| with gr.Blocks(title="MentorFlow - Strategy Comparison") as demo: | |
| gr.Markdown(""" | |
| # π MentorFlow - Teacher-Student RL System | |
| Compare three training strategies using LM Student (DistilBERT): | |
| 1. **Random Strategy**: Random questions until student can pass difficult questions | |
| 2. **Progressive Strategy**: Easy β Medium β Hard within each family | |
| 3. **Teacher Strategy**: RL teacher agent learns optimal curriculum | |
| ## Usage | |
| 1. Set parameters below | |
| 2. Click "Run Comparison" to start training | |
| 3. View results and generated plots | |
| **Note**: With LM Student, this will take 15-30 minutes for 500 iterations. | |
| """) | |
| # GPU Status | |
| with gr.Row(): | |
| gpu_status = gr.Textbox(label="GPU Status", value=check_gpu(), interactive=False) | |
| refresh_btn = gr.Button("π Refresh GPU Status") | |
| refresh_btn.click(fn=check_gpu, outputs=gpu_status, api_name="check_gpu") | |
| # Parameters | |
| with gr.Row(): | |
| with gr.Column(): | |
| iterations = gr.Slider( | |
| minimum=50, | |
| maximum=500, | |
| value=100, | |
| step=50, | |
| label="Iterations", | |
| info="Number of training iterations (higher = longer runtime)" | |
| ) | |
| seed = gr.Number( | |
| value=42, | |
| label="Random Seed", | |
| info="Seed for reproducibility (ignored if deterministic)" | |
| ) | |
| use_deterministic = gr.Checkbox( | |
| value=True, | |
| label="Deterministic Mode", | |
| info="Use fixed seed=42 for reproducible results" | |
| ) | |
| device = gr.Radio( | |
| choices=["cuda", "cpu"], | |
| value="cuda", # Default to GPU for HF Spaces with Nvidia 4xL4 | |
| label="Device", | |
| info="GPU (cuda) recommended for Nvidia 4xL4, CPU fallback available" | |
| ) | |
| with gr.Column(): | |
| run_btn = gr.Button("π Run Comparison", variant="primary", size="lg") | |
| # Output | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| output_text = gr.Textbox( | |
| label="Output", | |
| lines=15, | |
| max_lines=30, | |
| interactive=False | |
| ) | |
| with gr.Column(scale=1): | |
| output_plot = gr.Image( | |
| label="Comparison Plot", | |
| type="filepath", | |
| height=500 | |
| ) | |
| # Run comparison | |
| run_btn.click( | |
| fn=run_comparison, | |
| inputs=[iterations, seed, use_deterministic, device], | |
| outputs=[output_text, output_plot], | |
| api_name="run_comparison" | |
| ) | |
| gr.Markdown(""" | |
| ## π Understanding Results | |
| The comparison plot shows: | |
| - **Learning Curves**: How each strategy improves over time | |
| - **Difficult Question Performance**: Accuracy on hard questions | |
| - **Curriculum Diversity**: Topic coverage over time | |
| - **Learning Efficiency**: Iterations to reach target vs final performance | |
| The **Teacher Strategy** should ideally outperform Random and Progressive strategies. | |
| """) | |
| if __name__ == "__main__": | |
| # Ensure the app binds to all interfaces for HF Spaces | |
| demo.launch(server_name="0.0.0.0", server_port=7860) |