Antuke commited on
Commit
f550786
·
1 Parent(s): 3fad476

added license of mtlora and perception encoders code

Browse files
Files changed (3) hide show
  1. app.py +31 -51
  2. core/LICENSE_PE +201 -0
  3. src/LICENSE_MTLORA +21 -0
app.py CHANGED
@@ -10,8 +10,8 @@ import numpy as np
10
  from PIL import Image, ImageDraw, ImageFont
11
  import base64
12
  from io import BytesIO
13
- import traceback # Import traceback at the top
14
- from huggingface_hub import snapshot_download # Use snapshot_download for startup
15
  from utils.face_detector import FaceDetector
16
 
17
  # Class definitions
@@ -36,7 +36,7 @@ model = None
36
  transform = None
37
  detector = None
38
  device = None
39
- current_ckpt_dir = None # This will now store the full path to the loaded model
40
  CHECKPOINTS_DIR = './checkpoints/'
41
  MODEL_REPO_ID = "Antuke/FaR-FT-PE"
42
 
@@ -50,14 +50,13 @@ def scan_checkpoints(ckpt_dir):
50
  ckpt_files = [
51
  os.path.join(ckpt_dir, f)
52
  for f in sorted(os.listdir(ckpt_dir))
53
- if f.endswith(('.pt', '.pth')) # Ensure we only scan for model files
54
  ]
55
  except Exception as e:
56
  print(f"Error scanning checkpoint directory {ckpt_dir}: {e}")
57
  return [], None
58
 
59
- # Create a list of (label, value) tuples
60
- # label = filename (e.g., "mtlora.pt"), value = full path
61
  choices_list = [(os.path.basename(f), f) for f in ckpt_files]
62
 
63
  default_ckpt_path = os.path.join(ckpt_dir, 'mtlora.pt')
@@ -65,7 +64,7 @@ def scan_checkpoints(ckpt_dir):
65
  if default_ckpt_path in ckpt_files:
66
  return choices_list, default_ckpt_path
67
  elif ckpt_files:
68
- return choices_list, ckpt_files[0] # default_ckpt_value is the full path
69
  else:
70
  print(f"No checkpoints found in {ckpt_dir}")
71
  return [], None
@@ -82,16 +81,13 @@ def load_model(device,ckpt_dir='./checkpoints/mtlora.pt', pe_vision_config="PE-C
82
  return model,transform
83
 
84
  def load_model_and_update_status(model_filepath):
85
- """
86
- Wrapper function to load a model *from a local file path* and return a status.
87
- The file path is provided by the dropdown.
88
- """
89
  global model, current_ckpt_dir
90
 
91
  if model_filepath is None or model_filepath == "":
92
  return "No checkpoint selected."
93
 
94
- # Check if this model *filepath* is already loaded
95
  if model is not None and model_filepath == current_ckpt_dir:
96
  status = f"Model already loaded: {os.path.basename(model_filepath)}"
97
  print(status)
@@ -99,11 +95,8 @@ def load_model_and_update_status(model_filepath):
99
 
100
  gr.Info(f"Loading model: {os.path.basename(model_filepath)}...")
101
  try:
102
- # --- This is the new logic ---
103
- # The file is already local. Just initialize it.
104
- # The 'model_filepath' *is* the ckpt_dir for init_model
105
  init_model(ckpt_dir=model_filepath, detection_confidence=0.5)
106
- # --- End of new logic ---
107
 
108
  current_ckpt_dir = model_filepath # Set global path on successful load
109
  status = f"Successfully loaded: {os.path.basename(model_filepath)}"
@@ -170,10 +163,14 @@ def predict(model, image):
170
  return results
171
 
172
  def get_centroid_weighted_age(probs):
 
 
 
 
173
  probs = list(probs.values())
174
  centroids = [1, 4.5, 14.5, 24.5, 34.5, 44.5, 54.5, 64.5, 80]
175
  age = 0
176
- # print(probs) # DEBUG
177
  for i,p in enumerate(probs):
178
  age += p * centroids[i]
179
 
@@ -191,7 +188,6 @@ def init_model(ckpt_dir="./checkpoints/mtlora.pt", detection_confidence=0.5):
191
  device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
192
  print(f"Using device: {device}")
193
 
194
- # Verify model weights exist
195
  if not os.path.exists(ckpt_dir):
196
  error_msg = f"Model weights not found: {ckpt_dir}."
197
  print(f"ERROR: {error_msg}")
@@ -226,8 +222,6 @@ def process_image(image, selected_checkpoint_path):
226
  return None, "<p style='color: red;'>Please upload an image</p>"
227
 
228
  # Ensure model is initialized
229
- # This check is crucial. If the user changes the dropdown, it triggers
230
- # load_model_and_update_status. If they just hit "Classify",
231
  # this check ensures the selected model is loaded.
232
  if model is None or selected_checkpoint_path != current_ckpt_dir:
233
  print(f"Model mismatch or not loaded. Selected: {selected_checkpoint_path}, Current: {current_ckpt_dir}")
@@ -237,26 +231,24 @@ def process_image(image, selected_checkpoint_path):
237
 
238
 
239
  try:
240
- # --- 1. Prepare images for detection and drawing ---
241
 
242
  # Convert PIL to OpenCV format (BGR) for the detector
243
  if isinstance(image, Image.Image):
244
  img_cv = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR)
245
  else:
246
- # Assuming it's a numpy array from Gradio webcam
247
  img_cv = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
248
 
249
  # Create a PIL copy to draw annotations on
250
  img_pil_annotated = image.copy()
251
  draw = ImageDraw.Draw(img_pil_annotated)
252
 
253
- # --- 2. Detect faces ---
254
  faces = detector.detect(img_cv, pad_rect=True)
255
 
256
  if faces is None or len(faces) == 0:
257
  return image, "<p style='color: orange;'>No faces detected in the image</p>"
258
 
259
- # --- 3. Process detected faces ---
260
  crops_pil = []
261
  face_data = []
262
 
@@ -265,33 +257,32 @@ def process_image(image, selected_checkpoint_path):
265
  crop_pil = Image.fromarray(crop_rgb)
266
  crops_pil.append(crop_pil)
267
 
268
- # Resize crop to 336x336 for display
269
  crop_resized = crop_pil.resize((336, 336), Image.Resampling.LANCZOS)
270
 
271
  face_data.append({
272
  'bbox': bbox,
273
  'detection_confidence': float(confidence),
274
- 'crop_image': crop_resized # Store the resized crop
275
  })
276
 
277
- # --- 4. Batch transform and predict ---
278
  crop_tensors = [transform(crop_pil) for crop_pil in crops_pil]
279
  batch_tensor = torch.stack(crop_tensors).to(device)
280
 
281
- # Get predictions
282
  predictions = predict(model, batch_tensor)
283
 
284
  # Combine face data with predictions
285
  for face, pred in zip(face_data, predictions):
286
  face['predictions'] = pred
287
 
288
- # --- 5. Create annotated image (using PIL) ---
289
  for idx, face in enumerate(face_data):
290
  bbox = face['bbox']
291
  pred = face['predictions']
292
  x, y, w, h = bbox
293
 
294
- # --- Calculate Adaptive Font (from demo.py) ---
295
  font_size_ratio = 0.08
296
  min_font_size = 12
297
  max_font_size = 48
@@ -323,16 +314,15 @@ def process_image(image, selected_checkpoint_path):
323
  lines_to_draw.append(f"Emotion: {emo_label} ({emo_conf*100:.0f}%)")
324
 
325
 
326
- # --- Calculate total height of the text block (from demo.py) ---
327
  line_spacing = 10
328
  total_text_height = 0
329
  for line in lines_to_draw:
330
  _left, top, _right, bottom = draw.textbbox((0, 0), line, font=font)
331
  total_text_height += (bottom - top) + line_spacing
332
 
333
- # --- Place text ABOVE or BELOW the box (from demo.py) ---
334
  if y - total_text_height > 0:
335
- # PLACE TEXT ABOVE: There is enough space
336
  text_y = y - line_spacing
337
  for line in reversed(lines_to_draw):
338
  left, top, right, bottom = draw.textbbox((x, text_y), line, font=font, anchor="ls") # anchor left-baseline
@@ -340,7 +330,6 @@ def process_image(image, selected_checkpoint_path):
340
  draw.text((x, text_y), line, font=font, fill="white", anchor="ls")
341
  text_y = top - line_spacing # Move y-position up for the next line
342
  else:
343
- # PLACE TEXT BELOW: Not enough space above, so draw downwards
344
  text_y = y + h + line_spacing
345
  for line in lines_to_draw:
346
  left, top, right, bottom = draw.textbbox((x, text_y), line, font=font, anchor="lt")
@@ -348,7 +337,6 @@ def process_image(image, selected_checkpoint_path):
348
  draw.text((x, text_y), line, font=font, fill="white", anchor="lt")
349
  text_y = bottom + line_spacing
350
 
351
- # --- 6. Create HTML results ---
352
 
353
  # Helper function to convert PIL image to base64
354
  def pil_to_base64(img_pil):
@@ -357,7 +345,6 @@ def process_image(image, selected_checkpoint_path):
357
  img_str = base64.b64encode(buffered.getvalue()).decode()
358
  return f"data:image/jpeg;base64,{img_str}"
359
 
360
- # (HTML Generation code remains the same as before)
361
  results_html = f"""
362
  <style>
363
  :root {{
@@ -609,7 +596,7 @@ def process_image(image, selected_checkpoint_path):
609
  """
610
  results_html += "</div>"
611
 
612
- # --- 7. Return the annotated PIL image and HTML ---
613
  return img_pil_annotated, results_html
614
 
615
  except Exception as e:
@@ -631,7 +618,6 @@ def create_interface(checkpoint_list, default_checkpoint, initial_status):
631
  """
632
 
633
  # Create interface
634
- # --- FIX: Added theme=gr.themes.Default() to enable light/dark mode switching ---
635
  with gr.Blocks(css=custom_css, title="Face Classification System", theme=gr.themes.Default()) as demo:
636
 
637
  with gr.Row():
@@ -642,8 +628,8 @@ def create_interface(checkpoint_list, default_checkpoint, initial_status):
642
  with gr.Column(scale=3):
643
  checkpoint_dropdown = gr.Dropdown(
644
  label="Select Model Checkpoint",
645
- choices=checkpoint_list, # This is now a list of (label, path) tuples
646
- value=default_checkpoint, # This is the full path to the default
647
  )
648
  with gr.Column(scale=2):
649
  model_status_text = gr.Textbox(
@@ -698,7 +684,6 @@ def create_interface(checkpoint_list, default_checkpoint, initial_status):
698
  size="lg"
699
  )
700
 
701
- # Examples - after button
702
  # Dynamically load example images from example directory
703
  example_dir = "example"
704
  example_images = []
@@ -720,7 +705,7 @@ def create_interface(checkpoint_list, default_checkpoint, initial_status):
720
  cache_examples=False
721
  )
722
 
723
- # Results section - full width below everything
724
  with gr.Row():
725
  with gr.Column(scale=1):
726
  output_html = gr.HTML(
@@ -731,13 +716,13 @@ def create_interface(checkpoint_list, default_checkpoint, initial_status):
731
  # Event handlers
732
  analyze_btn.click(
733
  fn=process_image,
734
- inputs=[input_image, checkpoint_dropdown], # Pass dropdown value (which is the path)
735
  outputs=[output_image, output_html]
736
  )
737
 
738
  checkpoint_dropdown.change(
739
  fn=load_model_and_update_status,
740
- inputs=[checkpoint_dropdown], # Pass dropdown value (which is the path)
741
  outputs=[model_status_text]
742
  )
743
 
@@ -764,10 +749,8 @@ try:
764
  except Exception as e:
765
  print(f"CRITICAL: Failed to download models from Hub. {e}")
766
  traceback.print_exc()
767
- # --- End of NEW code ---
768
 
769
 
770
- # --- 1. Scan for models first ---
771
  # This will now find the files you just downloaded
772
  checkpoint_list, default_checkpoint = scan_checkpoints(CHECKPOINTS_DIR)
773
 
@@ -777,7 +760,7 @@ else:
777
  print(f"Found checkpoints: {len(checkpoint_list)} file(s).")
778
  print(f"Default checkpoint: {default_checkpoint}")
779
 
780
- # --- 2. Try to initialize default model ---
781
  initial_status_msg = "No default model found. Please select one."
782
  if default_checkpoint:
783
  print(f"\nInitializing default model: {default_checkpoint}")
@@ -789,7 +772,7 @@ else:
789
  print("⚠ Warning: No default model to load.")
790
 
791
 
792
- # --- 3. Create interface FIRST (so it shows even if model fails) ---
793
  print("Creating Gradio interface...")
794
  demo = create_interface(checkpoint_list, default_checkpoint, initial_status_msg)
795
  print("✓ Interface created successfully!")
@@ -799,7 +782,6 @@ if __name__ == "__main__":
799
  import argparse
800
 
801
  parser = argparse.ArgumentParser(description="VLM Soft Biometrics - Gradio Interface")
802
- # ckpt_dir is now managed by the startup download, so this arg is less relevant
803
  parser.add_argument("--ckpt_dir", type=str, default="./checkpoints/",
804
  help="Path to the checkpoint directory (will be populated from HF Hub)")
805
  parser.add_argument("--detection_confidence", type=float, default=0.5,
@@ -812,9 +794,7 @@ if __name__ == "__main__":
812
  help="Server name/IP to bind to")
813
  args = parser.parse_args()
814
 
815
- # Update global config if args are provided
816
  CHECKPOINTS_DIR = args.ckpt_dir
817
- # Note: detection_confidence is passed to init_model during load, so it's handled.
818
 
819
  print(f"\nLaunching server on {args.server_name}:{args.port}")
820
  print(f"Monitoring checkpoint directory: {CHECKPOINTS_DIR}")
 
10
  from PIL import Image, ImageDraw, ImageFont
11
  import base64
12
  from io import BytesIO
13
+ import traceback
14
+ from huggingface_hub import snapshot_download
15
  from utils.face_detector import FaceDetector
16
 
17
  # Class definitions
 
36
  transform = None
37
  detector = None
38
  device = None
39
+ current_ckpt_dir = None
40
  CHECKPOINTS_DIR = './checkpoints/'
41
  MODEL_REPO_ID = "Antuke/FaR-FT-PE"
42
 
 
50
  ckpt_files = [
51
  os.path.join(ckpt_dir, f)
52
  for f in sorted(os.listdir(ckpt_dir))
53
+ if f.endswith(('.pt', '.pth'))
54
  ]
55
  except Exception as e:
56
  print(f"Error scanning checkpoint directory {ckpt_dir}: {e}")
57
  return [], None
58
 
59
+
 
60
  choices_list = [(os.path.basename(f), f) for f in ckpt_files]
61
 
62
  default_ckpt_path = os.path.join(ckpt_dir, 'mtlora.pt')
 
64
  if default_ckpt_path in ckpt_files:
65
  return choices_list, default_ckpt_path
66
  elif ckpt_files:
67
+ return choices_list, ckpt_files[0]
68
  else:
69
  print(f"No checkpoints found in {ckpt_dir}")
70
  return [], None
 
81
  return model,transform
82
 
83
  def load_model_and_update_status(model_filepath):
84
+ """Wrapper function to load a model """
 
 
 
85
  global model, current_ckpt_dir
86
 
87
  if model_filepath is None or model_filepath == "":
88
  return "No checkpoint selected."
89
 
90
+ # Check if this model filepath is already loaded
91
  if model is not None and model_filepath == current_ckpt_dir:
92
  status = f"Model already loaded: {os.path.basename(model_filepath)}"
93
  print(status)
 
95
 
96
  gr.Info(f"Loading model: {os.path.basename(model_filepath)}...")
97
  try:
98
+
 
 
99
  init_model(ckpt_dir=model_filepath, detection_confidence=0.5)
 
100
 
101
  current_ckpt_dir = model_filepath # Set global path on successful load
102
  status = f"Successfully loaded: {os.path.basename(model_filepath)}"
 
163
  return results
164
 
165
  def get_centroid_weighted_age(probs):
166
+ """
167
+ Using centroids of age group we calculate an age regression number
168
+ using an average weight based on predicted probability distribution
169
+ """
170
  probs = list(probs.values())
171
  centroids = [1, 4.5, 14.5, 24.5, 34.5, 44.5, 54.5, 64.5, 80]
172
  age = 0
173
+
174
  for i,p in enumerate(probs):
175
  age += p * centroids[i]
176
 
 
188
  device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
189
  print(f"Using device: {device}")
190
 
 
191
  if not os.path.exists(ckpt_dir):
192
  error_msg = f"Model weights not found: {ckpt_dir}."
193
  print(f"ERROR: {error_msg}")
 
222
  return None, "<p style='color: red;'>Please upload an image</p>"
223
 
224
  # Ensure model is initialized
 
 
225
  # this check ensures the selected model is loaded.
226
  if model is None or selected_checkpoint_path != current_ckpt_dir:
227
  print(f"Model mismatch or not loaded. Selected: {selected_checkpoint_path}, Current: {current_ckpt_dir}")
 
231
 
232
 
233
  try:
 
234
 
235
  # Convert PIL to OpenCV format (BGR) for the detector
236
  if isinstance(image, Image.Image):
237
  img_cv = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR)
238
  else:
 
239
  img_cv = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
240
 
241
  # Create a PIL copy to draw annotations on
242
  img_pil_annotated = image.copy()
243
  draw = ImageDraw.Draw(img_pil_annotated)
244
 
245
+ # --- Detect faces ---
246
  faces = detector.detect(img_cv, pad_rect=True)
247
 
248
  if faces is None or len(faces) == 0:
249
  return image, "<p style='color: orange;'>No faces detected in the image</p>"
250
 
251
+ # --- Process detected faces ---
252
  crops_pil = []
253
  face_data = []
254
 
 
257
  crop_pil = Image.fromarray(crop_rgb)
258
  crops_pil.append(crop_pil)
259
 
260
+ # Resize crop to 336x336 for display, to match model input size
261
  crop_resized = crop_pil.resize((336, 336), Image.Resampling.LANCZOS)
262
 
263
  face_data.append({
264
  'bbox': bbox,
265
  'detection_confidence': float(confidence),
266
+ 'crop_image': crop_resized
267
  })
268
 
269
+ # --- Batch transform and predict ---
270
  crop_tensors = [transform(crop_pil) for crop_pil in crops_pil]
271
  batch_tensor = torch.stack(crop_tensors).to(device)
272
 
 
273
  predictions = predict(model, batch_tensor)
274
 
275
  # Combine face data with predictions
276
  for face, pred in zip(face_data, predictions):
277
  face['predictions'] = pred
278
 
279
+ # --- Create annotated image (using PIL) ---
280
  for idx, face in enumerate(face_data):
281
  bbox = face['bbox']
282
  pred = face['predictions']
283
  x, y, w, h = bbox
284
 
285
+ # --- Calculate Adaptive Font ---
286
  font_size_ratio = 0.08
287
  min_font_size = 12
288
  max_font_size = 48
 
314
  lines_to_draw.append(f"Emotion: {emo_label} ({emo_conf*100:.0f}%)")
315
 
316
 
317
+ # --- Calculate total height of the text block ---
318
  line_spacing = 10
319
  total_text_height = 0
320
  for line in lines_to_draw:
321
  _left, top, _right, bottom = draw.textbbox((0, 0), line, font=font)
322
  total_text_height += (bottom - top) + line_spacing
323
 
324
+ # --- Place text ABOVE or BELOW the box ---
325
  if y - total_text_height > 0:
 
326
  text_y = y - line_spacing
327
  for line in reversed(lines_to_draw):
328
  left, top, right, bottom = draw.textbbox((x, text_y), line, font=font, anchor="ls") # anchor left-baseline
 
330
  draw.text((x, text_y), line, font=font, fill="white", anchor="ls")
331
  text_y = top - line_spacing # Move y-position up for the next line
332
  else:
 
333
  text_y = y + h + line_spacing
334
  for line in lines_to_draw:
335
  left, top, right, bottom = draw.textbbox((x, text_y), line, font=font, anchor="lt")
 
337
  draw.text((x, text_y), line, font=font, fill="white", anchor="lt")
338
  text_y = bottom + line_spacing
339
 
 
340
 
341
  # Helper function to convert PIL image to base64
342
  def pil_to_base64(img_pil):
 
345
  img_str = base64.b64encode(buffered.getvalue()).decode()
346
  return f"data:image/jpeg;base64,{img_str}"
347
 
 
348
  results_html = f"""
349
  <style>
350
  :root {{
 
596
  """
597
  results_html += "</div>"
598
 
599
+ # --- Return the annotated PIL image and HTML ---
600
  return img_pil_annotated, results_html
601
 
602
  except Exception as e:
 
618
  """
619
 
620
  # Create interface
 
621
  with gr.Blocks(css=custom_css, title="Face Classification System", theme=gr.themes.Default()) as demo:
622
 
623
  with gr.Row():
 
628
  with gr.Column(scale=3):
629
  checkpoint_dropdown = gr.Dropdown(
630
  label="Select Model Checkpoint",
631
+ choices=checkpoint_list,
632
+ value=default_checkpoint,
633
  )
634
  with gr.Column(scale=2):
635
  model_status_text = gr.Textbox(
 
684
  size="lg"
685
  )
686
 
 
687
  # Dynamically load example images from example directory
688
  example_dir = "example"
689
  example_images = []
 
705
  cache_examples=False
706
  )
707
 
708
+ # Results section
709
  with gr.Row():
710
  with gr.Column(scale=1):
711
  output_html = gr.HTML(
 
716
  # Event handlers
717
  analyze_btn.click(
718
  fn=process_image,
719
+ inputs=[input_image, checkpoint_dropdown],
720
  outputs=[output_image, output_html]
721
  )
722
 
723
  checkpoint_dropdown.change(
724
  fn=load_model_and_update_status,
725
+ inputs=[checkpoint_dropdown],
726
  outputs=[model_status_text]
727
  )
728
 
 
749
  except Exception as e:
750
  print(f"CRITICAL: Failed to download models from Hub. {e}")
751
  traceback.print_exc()
 
752
 
753
 
 
754
  # This will now find the files you just downloaded
755
  checkpoint_list, default_checkpoint = scan_checkpoints(CHECKPOINTS_DIR)
756
 
 
760
  print(f"Found checkpoints: {len(checkpoint_list)} file(s).")
761
  print(f"Default checkpoint: {default_checkpoint}")
762
 
763
+ # --- Try to initialize default model ---
764
  initial_status_msg = "No default model found. Please select one."
765
  if default_checkpoint:
766
  print(f"\nInitializing default model: {default_checkpoint}")
 
772
  print("⚠ Warning: No default model to load.")
773
 
774
 
775
+ # --- Create interface FIRST (so it shows even if model fails) ---
776
  print("Creating Gradio interface...")
777
  demo = create_interface(checkpoint_list, default_checkpoint, initial_status_msg)
778
  print("✓ Interface created successfully!")
 
782
  import argparse
783
 
784
  parser = argparse.ArgumentParser(description="VLM Soft Biometrics - Gradio Interface")
 
785
  parser.add_argument("--ckpt_dir", type=str, default="./checkpoints/",
786
  help="Path to the checkpoint directory (will be populated from HF Hub)")
787
  parser.add_argument("--detection_confidence", type=float, default=0.5,
 
794
  help="Server name/IP to bind to")
795
  args = parser.parse_args()
796
 
 
797
  CHECKPOINTS_DIR = args.ckpt_dir
 
798
 
799
  print(f"\nLaunching server on {args.server_name}:{args.port}")
800
  print(f"Monitoring checkpoint directory: {CHECKPOINTS_DIR}")
core/LICENSE_PE ADDED
@@ -0,0 +1,201 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright [yyyy] [name of copyright owner]
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
src/LICENSE_MTLORA ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) SCALE Lab, Brown University.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE