Spaces:
Running
Running
Add support to set custom stage time.
Browse files
app.py
CHANGED
|
@@ -292,6 +292,35 @@ timing_params_card = dbc.Card([
|
|
| 292 |
])
|
| 293 |
], style=card_style)
|
| 294 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 295 |
# Updated app layout with improved structure
|
| 296 |
app.layout = html.Div([
|
| 297 |
header,
|
|
@@ -346,6 +375,7 @@ app.layout = html.Div([
|
|
| 346 |
basic_params_card,
|
| 347 |
scheduling_params_card,
|
| 348 |
timing_params_card,
|
|
|
|
| 349 |
|
| 350 |
# Generate button with better styling
|
| 351 |
dbc.Button([
|
|
@@ -521,6 +551,75 @@ def toggle_advanced_options(n_clicks, is_open):
|
|
| 521 |
return not is_open
|
| 522 |
return is_open
|
| 523 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 524 |
# --- Client-side Callback for Strategy Card Selection ---
|
| 525 |
app.clientside_callback(
|
| 526 |
"""
|
|
@@ -576,12 +675,14 @@ app.clientside_callback(
|
|
| 576 |
State('op_time_overlapped_fwd_bwd', 'value'),
|
| 577 |
State('microbatch_group_size_per_vp_stage', 'value'),
|
| 578 |
State('selected-strategies-store', 'data'),
|
|
|
|
|
|
|
| 579 |
prevent_initial_call=True
|
| 580 |
)
|
| 581 |
def update_graph(n_clicks, num_devices, num_stages, num_batches, p2p_latency,
|
| 582 |
op_time_forward, op_time_backward, op_time_backward_d, op_time_backward_w,
|
| 583 |
op_time_overlapped_fwd_bwd, microbatch_group_size_per_vp_stage,
|
| 584 |
-
selected_strategies):
|
| 585 |
|
| 586 |
strategy_display_order = ["1f1b", "1f1b_interleave", "1f1b_overlap", "1f1b_interleave_overlap", "dualpipe", "zb1p"]
|
| 587 |
|
|
@@ -669,14 +770,40 @@ def update_graph(n_clicks, num_devices, num_stages, num_batches, p2p_latency,
|
|
| 669 |
if adjustment_msg not in automatic_adjustments:
|
| 670 |
automatic_adjustments.append(adjustment_msg)
|
| 671 |
|
| 672 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 673 |
|
|
|
|
| 674 |
if split_backward:
|
| 675 |
op_times["backward_D"] = float(op_time_backward_d) * time_scale_factor
|
| 676 |
op_times["backward_W"] = float(op_time_backward_w) * time_scale_factor
|
| 677 |
op_times["backward"] = (float(op_time_backward_d) + float(op_time_backward_w)) * time_scale_factor
|
| 678 |
else:
|
| 679 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 680 |
|
| 681 |
if op_time_overlapped_fwd_bwd is not None:
|
| 682 |
try:
|
|
|
|
| 292 |
])
|
| 293 |
], style=card_style)
|
| 294 |
|
| 295 |
+
# Per-stage timing configuration card
|
| 296 |
+
per_stage_timing_card = dbc.Card([
|
| 297 |
+
dbc.CardBody([
|
| 298 |
+
html.H5([
|
| 299 |
+
html.I(className="bi bi-list-ol section-icon"),
|
| 300 |
+
"Per-Stage Timing Configuration"
|
| 301 |
+
], className="section-title"),
|
| 302 |
+
|
| 303 |
+
dbc.Button([
|
| 304 |
+
html.I(className="bi bi-sliders2 me-2"),
|
| 305 |
+
"Customize Per-Stage Timing"
|
| 306 |
+
],
|
| 307 |
+
id="per-stage-timing-toggle",
|
| 308 |
+
color="light",
|
| 309 |
+
className="mb-3 w-100",
|
| 310 |
+
size="sm"
|
| 311 |
+
),
|
| 312 |
+
|
| 313 |
+
dbc.Collapse([
|
| 314 |
+
dbc.Alert([
|
| 315 |
+
html.I(className="bi bi-info-circle-fill me-2"),
|
| 316 |
+
"Override global timing values for individual stages. Leave empty to use global values."
|
| 317 |
+
], color="info", className="mb-3"),
|
| 318 |
+
|
| 319 |
+
html.Div(id='per-stage-inputs-container', children=[])
|
| 320 |
+
], id="per-stage-timing-collapse", is_open=False)
|
| 321 |
+
])
|
| 322 |
+
], style=card_style)
|
| 323 |
+
|
| 324 |
# Updated app layout with improved structure
|
| 325 |
app.layout = html.Div([
|
| 326 |
header,
|
|
|
|
| 375 |
basic_params_card,
|
| 376 |
scheduling_params_card,
|
| 377 |
timing_params_card,
|
| 378 |
+
per_stage_timing_card,
|
| 379 |
|
| 380 |
# Generate button with better styling
|
| 381 |
dbc.Button([
|
|
|
|
| 551 |
return not is_open
|
| 552 |
return is_open
|
| 553 |
|
| 554 |
+
# --- Callback to toggle Per-Stage Timing Collapse ---
|
| 555 |
+
@app.callback(
|
| 556 |
+
Output("per-stage-timing-collapse", "is_open"),
|
| 557 |
+
Input("per-stage-timing-toggle", "n_clicks"),
|
| 558 |
+
State("per-stage-timing-collapse", "is_open"),
|
| 559 |
+
prevent_initial_call=True,
|
| 560 |
+
)
|
| 561 |
+
def toggle_per_stage_timing(n_clicks, is_open):
|
| 562 |
+
if n_clicks:
|
| 563 |
+
return not is_open
|
| 564 |
+
return is_open
|
| 565 |
+
|
| 566 |
+
# --- Callback to dynamically generate per-stage timing inputs ---
|
| 567 |
+
@app.callback(
|
| 568 |
+
Output("per-stage-inputs-container", "children"),
|
| 569 |
+
Input("num_stages", "value"),
|
| 570 |
+
)
|
| 571 |
+
def generate_per_stage_inputs(num_stages):
|
| 572 |
+
if num_stages is None or num_stages < 1:
|
| 573 |
+
return []
|
| 574 |
+
|
| 575 |
+
# Limit to reasonable number of stages for UI
|
| 576 |
+
num_stages = min(int(num_stages), 32)
|
| 577 |
+
|
| 578 |
+
stage_inputs = []
|
| 579 |
+
for stage_id in range(num_stages):
|
| 580 |
+
stage_inputs.append(
|
| 581 |
+
dbc.Row([
|
| 582 |
+
dbc.Col([
|
| 583 |
+
html.Strong(f"Stage {stage_id}", className="text-muted")
|
| 584 |
+
], width=2, className="d-flex align-items-center"),
|
| 585 |
+
dbc.Col([
|
| 586 |
+
dbc.InputGroup([
|
| 587 |
+
dbc.InputGroupText("F", style={"minWidth": "30px"}),
|
| 588 |
+
dbc.Input(
|
| 589 |
+
id={"type": "stage-forward", "index": stage_id},
|
| 590 |
+
type="number",
|
| 591 |
+
placeholder="1.0",
|
| 592 |
+
min=0.01,
|
| 593 |
+
step=0.01,
|
| 594 |
+
size="sm"
|
| 595 |
+
),
|
| 596 |
+
], size="sm")
|
| 597 |
+
], width=5),
|
| 598 |
+
dbc.Col([
|
| 599 |
+
dbc.InputGroup([
|
| 600 |
+
dbc.InputGroupText("B", style={"minWidth": "30px"}),
|
| 601 |
+
dbc.Input(
|
| 602 |
+
id={"type": "stage-backward", "index": stage_id},
|
| 603 |
+
type="number",
|
| 604 |
+
placeholder="1.0",
|
| 605 |
+
min=0.01,
|
| 606 |
+
step=0.01,
|
| 607 |
+
size="sm"
|
| 608 |
+
),
|
| 609 |
+
], size="sm")
|
| 610 |
+
], width=5),
|
| 611 |
+
], className="mb-2 g-2")
|
| 612 |
+
)
|
| 613 |
+
|
| 614 |
+
# Add header row
|
| 615 |
+
header = dbc.Row([
|
| 616 |
+
dbc.Col([html.Small("Stage", className="text-muted fw-bold")], width=2),
|
| 617 |
+
dbc.Col([html.Small("Forward Time", className="text-muted fw-bold")], width=5),
|
| 618 |
+
dbc.Col([html.Small("Backward Time", className="text-muted fw-bold")], width=5),
|
| 619 |
+
], className="mb-2")
|
| 620 |
+
|
| 621 |
+
return [header] + stage_inputs
|
| 622 |
+
|
| 623 |
# --- Client-side Callback for Strategy Card Selection ---
|
| 624 |
app.clientside_callback(
|
| 625 |
"""
|
|
|
|
| 675 |
State('op_time_overlapped_fwd_bwd', 'value'),
|
| 676 |
State('microbatch_group_size_per_vp_stage', 'value'),
|
| 677 |
State('selected-strategies-store', 'data'),
|
| 678 |
+
State({'type': 'stage-forward', 'index': ALL}, 'value'),
|
| 679 |
+
State({'type': 'stage-backward', 'index': ALL}, 'value'),
|
| 680 |
prevent_initial_call=True
|
| 681 |
)
|
| 682 |
def update_graph(n_clicks, num_devices, num_stages, num_batches, p2p_latency,
|
| 683 |
op_time_forward, op_time_backward, op_time_backward_d, op_time_backward_w,
|
| 684 |
op_time_overlapped_fwd_bwd, microbatch_group_size_per_vp_stage,
|
| 685 |
+
selected_strategies, stage_forward_values, stage_backward_values):
|
| 686 |
|
| 687 |
strategy_display_order = ["1f1b", "1f1b_interleave", "1f1b_overlap", "1f1b_interleave_overlap", "dualpipe", "zb1p"]
|
| 688 |
|
|
|
|
| 770 |
if adjustment_msg not in automatic_adjustments:
|
| 771 |
automatic_adjustments.append(adjustment_msg)
|
| 772 |
|
| 773 |
+
# Check if per-stage timing values are provided
|
| 774 |
+
has_per_stage_forward = stage_forward_values and any(v is not None for v in stage_forward_values)
|
| 775 |
+
has_per_stage_backward = stage_backward_values and any(v is not None for v in stage_backward_values)
|
| 776 |
+
|
| 777 |
+
# Build forward timing - either per-stage dict or global value
|
| 778 |
+
if has_per_stage_forward:
|
| 779 |
+
forward_times = {}
|
| 780 |
+
for stage_id in range(current_num_stages):
|
| 781 |
+
if stage_id < len(stage_forward_values) and stage_forward_values[stage_id] is not None:
|
| 782 |
+
forward_times[stage_id] = float(stage_forward_values[stage_id]) * time_scale_factor
|
| 783 |
+
else:
|
| 784 |
+
# Use global value as fallback (default 1.0 if not specified)
|
| 785 |
+
forward_times[stage_id] = float(op_time_forward if op_time_forward else 1.0) * time_scale_factor
|
| 786 |
+
op_times = {"forward": forward_times}
|
| 787 |
+
else:
|
| 788 |
+
op_times = {"forward": float(op_time_forward) * time_scale_factor}
|
| 789 |
|
| 790 |
+
# Build backward timing
|
| 791 |
if split_backward:
|
| 792 |
op_times["backward_D"] = float(op_time_backward_d) * time_scale_factor
|
| 793 |
op_times["backward_W"] = float(op_time_backward_w) * time_scale_factor
|
| 794 |
op_times["backward"] = (float(op_time_backward_d) + float(op_time_backward_w)) * time_scale_factor
|
| 795 |
else:
|
| 796 |
+
if has_per_stage_backward:
|
| 797 |
+
backward_times = {}
|
| 798 |
+
for stage_id in range(current_num_stages):
|
| 799 |
+
if stage_id < len(stage_backward_values) and stage_backward_values[stage_id] is not None:
|
| 800 |
+
backward_times[stage_id] = float(stage_backward_values[stage_id]) * time_scale_factor
|
| 801 |
+
else:
|
| 802 |
+
# Use global value as fallback (default 1.0 if not specified)
|
| 803 |
+
backward_times[stage_id] = float(op_time_backward if op_time_backward else 1.0) * time_scale_factor
|
| 804 |
+
op_times["backward"] = backward_times
|
| 805 |
+
else:
|
| 806 |
+
op_times["backward"] = float(op_time_backward) * time_scale_factor
|
| 807 |
|
| 808 |
if op_time_overlapped_fwd_bwd is not None:
|
| 809 |
try:
|