mnoorchenar commited on
Commit
9507acc
·
verified ·
1 Parent(s): 6794241

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +36 -18
app.py CHANGED
@@ -46,10 +46,10 @@ HTML_TEMPLATE = '''<!DOCTYPE html>
46
  label { font-weight: 600; margin-bottom: 8px; display: block; }
47
  input, select { width: 100%; padding: 12px; border: 2px solid #e0e0e0; border-radius: 8px; font-size: 15px; }
48
  input:focus, select:focus { border-color: #667eea; outline: none; }
49
- .checkbox-group { display: flex; flex-wrap: wrap; gap: 15px; background: #f8f9fa; padding: 15px; border-radius: 10px; justify-content: flex-start; }
50
- .checkbox-group label { display: flex; align-items: center; gap: 8px; cursor: pointer; padding: 5px 10px; border-radius: 6px; transition: background 0.2s; white-space: nowrap; }
51
  .checkbox-group label:hover { background: #e0e0e0; }
52
- .checkbox-group input[type="checkbox"] { width: 16px; height: 16px; }
53
  button { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 18px 40px; border: none; border-radius: 10px; font-size: 18px; font-weight: 600; margin: 30px auto; display: block; width: fit-content; }
54
  button:disabled { background: #ccc; cursor: not-allowed; }
55
  #loading { display: none; text-align: center; padding: 40px; }
@@ -323,7 +323,7 @@ function displayResults(data, epochs, taskType) {
323
  ], {
324
  title: `${lossName.toUpperCase()} Train and Val Loss`,
325
  xaxis: {title: 'Epoch'},
326
- yaxis: {title: 'Loss', type: 'log'},
327
  height: 400
328
  });
329
  });
@@ -438,8 +438,8 @@ def add_outliers(X, y, n_samples, perc, mag):
438
  X[idx] *= mag
439
  if y.ndim == 2: # regression
440
  y[idx] *= mag
441
- else: # classification flip labels
442
- if y.max() > 1: # multi-class, randomize
443
  y[idx] = np.random.randint(0, y.max() + 1, size=n)
444
  else: # binary
445
  y[idx] = 1 - y[idx]
@@ -523,49 +523,67 @@ def train():
523
  opt.zero_grad()
524
  outputs = model(X_train_t)
525
 
 
526
  try:
527
  if loss_name in ['cross_entropy', 'sparse_categorical_crossentropy'] and task != 'regression':
528
  loss = criterion(outputs, y_train_t)
529
  elif loss_name == 'bce' and task == 'binary_classification':
530
- loss = criterion(outputs, y_train_t.float())
531
  else:
532
- # Fallback for mismatched
533
  if task == 'regression':
534
- loss = criterion(outputs, y_train_t)
 
 
 
 
 
 
 
 
535
  else:
536
  loss = criterion(outputs.mean(dim=1, keepdim=True), y_train_t.float().unsqueeze(1))
537
- loss.backward()
538
- torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
539
- opt.step()
 
540
  except Exception as e:
541
  logger.warning(f"Loss computation or backward failed for {loss_name} on {task}: {str(e)}")
542
- loss = torch.tensor(float('nan')) # Use NaN to indicate failure in plots
543
 
544
  model.eval()
545
  with torch.no_grad():
546
  val_outputs = model(X_val_t)
 
547
  try:
548
  if loss_name in ['cross_entropy', 'sparse_categorical_crossentropy'] and task != 'regression':
549
  val_loss = criterion(val_outputs, y_val_t)
550
  elif loss_name == 'bce' and task == 'binary_classification':
551
- val_loss = criterion(val_outputs, y_val_t.float())
552
  else:
553
  if task == 'regression':
554
- val_loss = criterion(val_outputs, y_val_t)
 
 
 
 
 
 
 
555
  else:
556
  val_loss = criterion(val_outputs.mean(dim=1, keepdim=True), y_val_t.float().unsqueeze(1))
557
  except Exception as e:
558
  logger.warning(f"Val loss failed for {loss_name} on {task}: {str(e)}")
559
  val_loss = torch.tensor(float('nan'))
560
 
561
- train_losses.append(float(loss.item()) if isinstance(loss, torch.Tensor) else float('nan'))
562
- val_losses.append(float(val_loss.item()) if isinstance(val_loss, torch.Tensor) else float('nan'))
563
 
564
  if epoch > 10 and convergence_epoch is None:
565
  recent_val = val_losses[-5:]
566
  if len(recent_val) == 5 and all(not np.isnan(r) for r in recent_val):
567
  if abs(recent_val[-1] - recent_val[0]) / (abs(recent_val[0]) + 1e-8) < 0.001:
568
- convergence_epoch = epoch + 1 # 1-indexed
569
 
570
  total_time = time.time() - start
571
  if task == 'regression':
 
46
  label { font-weight: 600; margin-bottom: 8px; display: block; }
47
  input, select { width: 100%; padding: 12px; border: 2px solid #e0e0e0; border-radius: 8px; font-size: 15px; }
48
  input:focus, select:focus { border-color: #667eea; outline: none; }
49
+ .checkbox-group { display: flex; flex-wrap: wrap; gap: 10px; background: #f8f9fa; padding: 10px; border-radius: 10px; justify-content: flex-start; }
50
+ .checkbox-group label { display: flex; align-items: center; gap: 5px; cursor: pointer; padding: 5px; border-radius: 6px; transition: background 0.2s; white-space: nowrap; }
51
  .checkbox-group label:hover { background: #e0e0e0; }
52
+ .checkbox-group input[type="checkbox"] { width: 16px; height: 16px; margin: 0; }
53
  button { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 18px 40px; border: none; border-radius: 10px; font-size: 18px; font-weight: 600; margin: 30px auto; display: block; width: fit-content; }
54
  button:disabled { background: #ccc; cursor: not-allowed; }
55
  #loading { display: none; text-align: center; padding: 40px; }
 
323
  ], {
324
  title: `${lossName.toUpperCase()} Train and Val Loss`,
325
  xaxis: {title: 'Epoch'},
326
+ yaxis: {title: 'Loss', type: 'linear'}, // Changed to linear for better visibility of small values
327
  height: 400
328
  });
329
  });
 
438
  X[idx] *= mag
439
  if y.ndim == 2: # regression
440
  y[idx] *= mag
441
+ else: # classification
442
+ if y.max() > 1: # multi-class
443
  y[idx] = np.random.randint(0, y.max() + 1, size=n)
444
  else: # binary
445
  y[idx] = 1 - y[idx]
 
523
  opt.zero_grad()
524
  outputs = model(X_train_t)
525
 
526
+ loss = None
527
  try:
528
  if loss_name in ['cross_entropy', 'sparse_categorical_crossentropy'] and task != 'regression':
529
  loss = criterion(outputs, y_train_t)
530
  elif loss_name == 'bce' and task == 'binary_classification':
531
+ loss = criterion(outputs, y_train_t.float().unsqueeze(1))
532
  else:
533
+ # Mismatched cases
534
  if task == 'regression':
535
+ if loss_name in ['cross_entropy', 'sparse_categorical_crossentropy']:
536
+ # For mismatched CE on regression, treat as binary for demo
537
+ logits = torch.cat([outputs, -outputs], dim=1) # Fake 2 classes
538
+ targets = (y_train_t > 0).long().squeeze(1)
539
+ loss = criterion(logits, targets)
540
+ elif loss_name == 'bce':
541
+ loss = criterion(outputs, (y_train_t > 0).float())
542
+ else:
543
+ loss = criterion(outputs, y_train_t)
544
  else:
545
  loss = criterion(outputs.mean(dim=1, keepdim=True), y_train_t.float().unsqueeze(1))
546
+ if loss is not None:
547
+ loss.backward()
548
+ torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
549
+ opt.step()
550
  except Exception as e:
551
  logger.warning(f"Loss computation or backward failed for {loss_name} on {task}: {str(e)}")
552
+ loss = torch.tensor(float('nan'))
553
 
554
  model.eval()
555
  with torch.no_grad():
556
  val_outputs = model(X_val_t)
557
+ val_loss = None
558
  try:
559
  if loss_name in ['cross_entropy', 'sparse_categorical_crossentropy'] and task != 'regression':
560
  val_loss = criterion(val_outputs, y_val_t)
561
  elif loss_name == 'bce' and task == 'binary_classification':
562
+ val_loss = criterion(val_outputs, y_val_t.float().unsqueeze(1))
563
  else:
564
  if task == 'regression':
565
+ if loss_name in ['cross_entropy', 'sparse_categorical_crossentropy']:
566
+ logits = torch.cat([val_outputs, -val_outputs], dim=1)
567
+ targets = (y_val_t > 0).long().squeeze(1)
568
+ val_loss = criterion(logits, targets)
569
+ elif loss_name == 'bce':
570
+ val_loss = criterion(val_outputs, (y_val_t > 0).float())
571
+ else:
572
+ val_loss = criterion(val_outputs, y_val_t)
573
  else:
574
  val_loss = criterion(val_outputs.mean(dim=1, keepdim=True), y_val_t.float().unsqueeze(1))
575
  except Exception as e:
576
  logger.warning(f"Val loss failed for {loss_name} on {task}: {str(e)}")
577
  val_loss = torch.tensor(float('nan'))
578
 
579
+ train_losses.append(float(loss.item()) if loss is not None and not torch.isnan(loss) else float('nan'))
580
+ val_losses.append(float(val_loss.item()) if val_loss is not None and not torch.isnan(val_loss) else float('nan'))
581
 
582
  if epoch > 10 and convergence_epoch is None:
583
  recent_val = val_losses[-5:]
584
  if len(recent_val) == 5 and all(not np.isnan(r) for r in recent_val):
585
  if abs(recent_val[-1] - recent_val[0]) / (abs(recent_val[0]) + 1e-8) < 0.001:
586
+ convergence_epoch = epoch + 1
587
 
588
  total_time = time.time() - start
589
  if task == 'regression':