anhtld commited on
Commit
954e055
·
verified ·
1 Parent(s): 5942db0

auto-sync 2026-07-02T15:44:03Z workspace (part 3)

Browse files
workspace/scripts/build_oracle_selector_calibration.py CHANGED
@@ -93,6 +93,36 @@ def _type_bonuses(
93
  return bonuses, means, counts, baseline
94
 
95
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
  def _iter_rollout_paths(patterns: list[str]) -> list[Path]:
97
  paths: list[Path] = []
98
  for pattern in patterns:
@@ -112,9 +142,11 @@ def build_oracle_selector_calibration(
112
  max_rank: int,
113
  rank_scale: float,
114
  type_scale: float,
 
115
  min_count: int,
116
  max_abs_rank_bias: float | None,
117
  max_abs_type_bonus: float | None,
 
118
  ) -> dict[str, Any]:
119
  if max_rank <= 0:
120
  raise ValueError("max_rank must be positive")
@@ -127,8 +159,12 @@ def build_oracle_selector_calibration(
127
  type_by_task: dict[str, dict[str, list[float]]] = defaultdict(
128
  lambda: defaultdict(list)
129
  )
 
 
 
130
  global_ranks: list[list[float]] = [[] for _ in range(max_rank)]
131
  global_types: dict[str, list[float]] = defaultdict(list)
 
132
  rows_seen = 0
133
  rows_used = 0
134
  skipped_branches = 0
@@ -142,12 +178,24 @@ def build_oracle_selector_calibration(
142
  task_id = str(row.get("task_id") or "")
143
  values = _branch_values(row, objective)
144
  candidate_types = row.get("candidate_oracle_types")
 
145
  valid_mask = row.get("candidate_oracle_valid_mask")
146
- if not task_id or not values or not isinstance(candidate_types, list):
 
 
 
 
 
147
  continue
148
  if not isinstance(valid_mask, list):
149
  valid_mask = [True] * len(values)
150
- branch_count = min(max_rank, len(values), len(candidate_types), len(valid_mask))
 
 
 
 
 
 
151
  if branch_count <= 0:
152
  continue
153
  rows_used += 1
@@ -157,10 +205,13 @@ def build_oracle_selector_calibration(
157
  continue
158
  value = float(values[rank])
159
  candidate_type = str(candidate_types[rank])
 
160
  rank_by_task[task_id][rank].append(value)
161
  global_ranks[rank].append(value)
162
  type_by_task[task_id][candidate_type].append(value)
163
  global_types[candidate_type].append(value)
 
 
164
 
165
  field_rank_biases_by_task: dict[str, list[float]] = {}
166
  rank_utility_means_by_task: dict[str, list[float | None]] = {}
@@ -213,6 +264,34 @@ def build_oracle_selector_calibration(
213
  type_counts_by_task["*"] = global_type_counts
214
  type_baselines_by_task["*"] = global_type_baseline
215
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
216
  return {
217
  "source_rollouts": [str(path) for path in rollout_paths],
218
  "calibration_source": "candidate_oracle_rollout",
@@ -220,9 +299,11 @@ def build_oracle_selector_calibration(
220
  "max_rank": int(max_rank),
221
  "rank_scale": float(rank_scale),
222
  "type_scale": float(type_scale),
 
223
  "min_count": int(min_count),
224
  "max_abs_rank_bias": max_abs_rank_bias,
225
  "max_abs_type_bonus": max_abs_type_bonus,
 
226
  "rows_seen": rows_seen,
227
  "rows_used": rows_used,
228
  "skipped_branches": skipped_branches,
@@ -233,6 +314,10 @@ def build_oracle_selector_calibration(
233
  "type_utility_means_by_task": type_utility_means_by_task,
234
  "type_counts_by_task": type_counts_by_task,
235
  "type_baselines_by_task": type_baselines_by_task,
 
 
 
 
236
  }
237
 
238
 
@@ -248,13 +333,16 @@ def main(argv: list[str] | None = None) -> int:
248
  parser.add_argument("--max-rank", type=int, default=4)
249
  parser.add_argument("--rank-scale", type=float, default=0.05)
250
  parser.add_argument("--type-scale", type=float, default=0.05)
 
251
  parser.add_argument("--min-count", type=int, default=20)
252
  parser.add_argument("--max-abs-rank-bias", type=float, default=0.02)
253
  parser.add_argument("--max-abs-type-bonus", type=float, default=0.02)
 
254
  args = parser.parse_args(argv)
255
 
256
  max_abs_rank_bias = args.max_abs_rank_bias if args.max_abs_rank_bias > 0 else None
257
  max_abs_type_bonus = args.max_abs_type_bonus if args.max_abs_type_bonus > 0 else None
 
258
  rollout_paths = _iter_rollout_paths(args.rollout)
259
  result = build_oracle_selector_calibration(
260
  rollout_paths,
@@ -262,9 +350,11 @@ def main(argv: list[str] | None = None) -> int:
262
  max_rank=args.max_rank,
263
  rank_scale=args.rank_scale,
264
  type_scale=args.type_scale,
 
265
  min_count=args.min_count,
266
  max_abs_rank_bias=max_abs_rank_bias,
267
  max_abs_type_bonus=max_abs_type_bonus,
 
268
  )
269
  args.out.parent.mkdir(parents=True, exist_ok=True)
270
  args.out.write_text(json.dumps(result, indent=2) + "\n")
@@ -282,6 +372,10 @@ def main(argv: list[str] | None = None) -> int:
282
  "type_utility_means_by_task",
283
  "type_counts_by_task",
284
  "type_baselines_by_task",
 
 
 
 
285
  }
286
  },
287
  indent=2,
 
93
  return bonuses, means, counts, baseline
94
 
95
 
96
+ def _scale_bonuses(
97
+ values_by_scale: dict[str, list[float]],
98
+ *,
99
+ scale: float,
100
+ min_count: int,
101
+ max_abs_bonus: float | None,
102
+ ) -> tuple[dict[str, float], dict[str, float | None], dict[str, int], float | None]:
103
+ pooled = [value for values in values_by_scale.values() for value in values]
104
+ baseline = _mean(pooled)
105
+ means = {
106
+ residual_scale: _mean(values)
107
+ for residual_scale, values in sorted(values_by_scale.items(), key=lambda item: float(item[0]))
108
+ }
109
+ counts = {
110
+ residual_scale: len(values)
111
+ for residual_scale, values in sorted(values_by_scale.items(), key=lambda item: float(item[0]))
112
+ }
113
+ if baseline is None or len(pooled) < min_count:
114
+ return {}, means, counts, baseline
115
+ bonuses: dict[str, float] = {}
116
+ for residual_scale, mean in means.items():
117
+ if mean is None or counts[residual_scale] < min_count:
118
+ continue
119
+ bonuses[residual_scale] = _clip(
120
+ float(scale) * (float(mean) - float(baseline)),
121
+ max_abs_bonus,
122
+ )
123
+ return bonuses, means, counts, baseline
124
+
125
+
126
  def _iter_rollout_paths(patterns: list[str]) -> list[Path]:
127
  paths: list[Path] = []
128
  for pattern in patterns:
 
142
  max_rank: int,
143
  rank_scale: float,
144
  type_scale: float,
145
+ scale_scale: float,
146
  min_count: int,
147
  max_abs_rank_bias: float | None,
148
  max_abs_type_bonus: float | None,
149
+ max_abs_scale_bonus: float | None,
150
  ) -> dict[str, Any]:
151
  if max_rank <= 0:
152
  raise ValueError("max_rank must be positive")
 
159
  type_by_task: dict[str, dict[str, list[float]]] = defaultdict(
160
  lambda: defaultdict(list)
161
  )
162
+ scale_by_task: dict[str, dict[str, list[float]]] = defaultdict(
163
+ lambda: defaultdict(list)
164
+ )
165
  global_ranks: list[list[float]] = [[] for _ in range(max_rank)]
166
  global_types: dict[str, list[float]] = defaultdict(list)
167
+ global_scales: dict[str, list[float]] = defaultdict(list)
168
  rows_seen = 0
169
  rows_used = 0
170
  skipped_branches = 0
 
178
  task_id = str(row.get("task_id") or "")
179
  values = _branch_values(row, objective)
180
  candidate_types = row.get("candidate_oracle_types")
181
+ residual_scales = row.get("candidate_oracle_residual_scales")
182
  valid_mask = row.get("candidate_oracle_valid_mask")
183
+ if (
184
+ not task_id
185
+ or not values
186
+ or not isinstance(candidate_types, list)
187
+ or not isinstance(residual_scales, list)
188
+ ):
189
  continue
190
  if not isinstance(valid_mask, list):
191
  valid_mask = [True] * len(values)
192
+ branch_count = min(
193
+ max_rank,
194
+ len(values),
195
+ len(candidate_types),
196
+ len(residual_scales),
197
+ len(valid_mask),
198
+ )
199
  if branch_count <= 0:
200
  continue
201
  rows_used += 1
 
205
  continue
206
  value = float(values[rank])
207
  candidate_type = str(candidate_types[rank])
208
+ residual_scale = f"{float(residual_scales[rank]):g}"
209
  rank_by_task[task_id][rank].append(value)
210
  global_ranks[rank].append(value)
211
  type_by_task[task_id][candidate_type].append(value)
212
  global_types[candidate_type].append(value)
213
+ scale_by_task[task_id][residual_scale].append(value)
214
+ global_scales[residual_scale].append(value)
215
 
216
  field_rank_biases_by_task: dict[str, list[float]] = {}
217
  rank_utility_means_by_task: dict[str, list[float | None]] = {}
 
264
  type_counts_by_task["*"] = global_type_counts
265
  type_baselines_by_task["*"] = global_type_baseline
266
 
267
+ residual_scale_bonuses_by_task: dict[str, dict[str, float]] = {}
268
+ scale_utility_means_by_task: dict[str, dict[str, float | None]] = {}
269
+ scale_counts_by_task: dict[str, dict[str, int]] = {}
270
+ scale_baselines_by_task: dict[str, float | None] = {}
271
+ for task_id in sorted(scale_by_task):
272
+ bonuses, means, counts, baseline = _scale_bonuses(
273
+ scale_by_task[task_id],
274
+ scale=scale_scale,
275
+ min_count=min_count,
276
+ max_abs_bonus=max_abs_scale_bonus,
277
+ )
278
+ residual_scale_bonuses_by_task[task_id] = bonuses
279
+ scale_utility_means_by_task[task_id] = means
280
+ scale_counts_by_task[task_id] = counts
281
+ scale_baselines_by_task[task_id] = baseline
282
+ global_scale_bonuses, global_scale_means, global_scale_counts, global_scale_baseline = (
283
+ _scale_bonuses(
284
+ global_scales,
285
+ scale=scale_scale,
286
+ min_count=min_count,
287
+ max_abs_bonus=max_abs_scale_bonus,
288
+ )
289
+ )
290
+ residual_scale_bonuses_by_task["*"] = global_scale_bonuses
291
+ scale_utility_means_by_task["*"] = global_scale_means
292
+ scale_counts_by_task["*"] = global_scale_counts
293
+ scale_baselines_by_task["*"] = global_scale_baseline
294
+
295
  return {
296
  "source_rollouts": [str(path) for path in rollout_paths],
297
  "calibration_source": "candidate_oracle_rollout",
 
299
  "max_rank": int(max_rank),
300
  "rank_scale": float(rank_scale),
301
  "type_scale": float(type_scale),
302
+ "scale_scale": float(scale_scale),
303
  "min_count": int(min_count),
304
  "max_abs_rank_bias": max_abs_rank_bias,
305
  "max_abs_type_bonus": max_abs_type_bonus,
306
+ "max_abs_scale_bonus": max_abs_scale_bonus,
307
  "rows_seen": rows_seen,
308
  "rows_used": rows_used,
309
  "skipped_branches": skipped_branches,
 
314
  "type_utility_means_by_task": type_utility_means_by_task,
315
  "type_counts_by_task": type_counts_by_task,
316
  "type_baselines_by_task": type_baselines_by_task,
317
+ "residual_scale_bonuses_by_task": residual_scale_bonuses_by_task,
318
+ "scale_utility_means_by_task": scale_utility_means_by_task,
319
+ "scale_counts_by_task": scale_counts_by_task,
320
+ "scale_baselines_by_task": scale_baselines_by_task,
321
  }
322
 
323
 
 
333
  parser.add_argument("--max-rank", type=int, default=4)
334
  parser.add_argument("--rank-scale", type=float, default=0.05)
335
  parser.add_argument("--type-scale", type=float, default=0.05)
336
+ parser.add_argument("--scale-scale", type=float, default=0.0)
337
  parser.add_argument("--min-count", type=int, default=20)
338
  parser.add_argument("--max-abs-rank-bias", type=float, default=0.02)
339
  parser.add_argument("--max-abs-type-bonus", type=float, default=0.02)
340
+ parser.add_argument("--max-abs-scale-bonus", type=float, default=0.02)
341
  args = parser.parse_args(argv)
342
 
343
  max_abs_rank_bias = args.max_abs_rank_bias if args.max_abs_rank_bias > 0 else None
344
  max_abs_type_bonus = args.max_abs_type_bonus if args.max_abs_type_bonus > 0 else None
345
+ max_abs_scale_bonus = args.max_abs_scale_bonus if args.max_abs_scale_bonus > 0 else None
346
  rollout_paths = _iter_rollout_paths(args.rollout)
347
  result = build_oracle_selector_calibration(
348
  rollout_paths,
 
350
  max_rank=args.max_rank,
351
  rank_scale=args.rank_scale,
352
  type_scale=args.type_scale,
353
+ scale_scale=args.scale_scale,
354
  min_count=args.min_count,
355
  max_abs_rank_bias=max_abs_rank_bias,
356
  max_abs_type_bonus=max_abs_type_bonus,
357
+ max_abs_scale_bonus=max_abs_scale_bonus,
358
  )
359
  args.out.parent.mkdir(parents=True, exist_ok=True)
360
  args.out.write_text(json.dumps(result, indent=2) + "\n")
 
372
  "type_utility_means_by_task",
373
  "type_counts_by_task",
374
  "type_baselines_by_task",
375
+ "residual_scale_bonuses_by_task",
376
+ "scale_utility_means_by_task",
377
+ "scale_counts_by_task",
378
+ "scale_baselines_by_task",
379
  }
380
  },
381
  indent=2,
workspace/scripts/eval_maniskill_policy_rollout.py CHANGED
@@ -90,6 +90,33 @@ def _load_source_score_bonus_map(path: Path | None) -> dict[str, float]:
90
  ) from exc
91
 
92
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
93
  def main(argv: list[str] | None = None) -> int:
94
  parser = argparse.ArgumentParser(
95
  description="Execute a DoVLA policy checkpoint from restored ManiSkill CIL states."
@@ -408,6 +435,15 @@ def main(argv: list[str] | None = None) -> int:
408
  default=None,
409
  help="Optional JSON task->rank-bias map added by field rank before lattice selection.",
410
  )
 
 
 
 
 
 
 
 
 
411
  parser.add_argument(
412
  "--candidate-oracle-rollouts",
413
  type=int,
@@ -525,6 +561,9 @@ def main(argv: list[str] | None = None) -> int:
525
  source_score_bonus_by_task = _load_source_score_bonus_map(
526
  args.retrieval_residual_source_score_bonus_map
527
  )
 
 
 
528
  result = evaluate_maniskill_policy_rollout(
529
  args.checkpoint,
530
  args.dataset,
@@ -591,6 +630,7 @@ def main(argv: list[str] | None = None) -> int:
591
  candidate_type_bonuses_by_task=candidate_type_bonuses_by_task,
592
  candidate_type_bonus_components=args.candidate_type_bonus_components,
593
  field_rank_biases_by_task=field_rank_biases_by_task,
 
594
  candidate_oracle_rollouts=args.candidate_oracle_rollouts,
595
  candidate_oracle_unique_tolerance=args.candidate_oracle_unique_tolerance,
596
  )
 
90
  ) from exc
91
 
92
 
93
+ def _load_residual_scale_bonus_map(path: Path | None) -> dict[str, dict[str, float]]:
94
+ if path is None:
95
+ return {}
96
+ payload = json.loads(path.read_text())
97
+ if not isinstance(payload, dict):
98
+ raise SystemExit("--residual-scale-bonus-map must contain a JSON object")
99
+ raw_bonuses = payload.get("residual_scale_bonuses_by_task", payload)
100
+ if not isinstance(raw_bonuses, dict):
101
+ raise SystemExit(
102
+ "--residual-scale-bonus-map must contain a task->scale->bonus object "
103
+ "or residual_scale_bonuses_by_task"
104
+ )
105
+ bonuses: dict[str, dict[str, float]] = {}
106
+ try:
107
+ for task_id, values in raw_bonuses.items():
108
+ if not isinstance(values, dict):
109
+ raise ValueError
110
+ bonuses[str(task_id)] = {
111
+ str(scale): float(bonus) for scale, bonus in values.items()
112
+ }
113
+ except (TypeError, ValueError) as exc:
114
+ raise SystemExit(
115
+ "--residual-scale-bonus-map values must be numeric scale->bonus objects"
116
+ ) from exc
117
+ return bonuses
118
+
119
+
120
  def main(argv: list[str] | None = None) -> int:
121
  parser = argparse.ArgumentParser(
122
  description="Execute a DoVLA policy checkpoint from restored ManiSkill CIL states."
 
435
  default=None,
436
  help="Optional JSON task->rank-bias map added by field rank before lattice selection.",
437
  )
438
+ parser.add_argument(
439
+ "--residual-scale-bonus-map",
440
+ type=Path,
441
+ default=None,
442
+ help=(
443
+ "Optional JSON task->residual_scale->bonus map added after residual "
444
+ "scale-grid expansion in retrieval_residual mode."
445
+ ),
446
+ )
447
  parser.add_argument(
448
  "--candidate-oracle-rollouts",
449
  type=int,
 
561
  source_score_bonus_by_task = _load_source_score_bonus_map(
562
  args.retrieval_residual_source_score_bonus_map
563
  )
564
+ residual_scale_bonuses_by_task = _load_residual_scale_bonus_map(
565
+ args.residual_scale_bonus_map
566
+ )
567
  result = evaluate_maniskill_policy_rollout(
568
  args.checkpoint,
569
  args.dataset,
 
630
  candidate_type_bonuses_by_task=candidate_type_bonuses_by_task,
631
  candidate_type_bonus_components=args.candidate_type_bonus_components,
632
  field_rank_biases_by_task=field_rank_biases_by_task,
633
+ residual_scale_bonuses_by_task=residual_scale_bonuses_by_task,
634
  candidate_oracle_rollouts=args.candidate_oracle_rollouts,
635
  candidate_oracle_unique_tolerance=args.candidate_oracle_unique_tolerance,
636
  )
workspace/scripts/slurm/build_oracle_selector_calibration.sbatch CHANGED
@@ -20,9 +20,11 @@ CAL_OBJECTIVE="${CAL_OBJECTIVE:-score}"
20
  MAX_RANK="${MAX_RANK:-4}"
21
  RANK_SCALE="${RANK_SCALE:-0.05}"
22
  TYPE_SCALE="${TYPE_SCALE:-0.05}"
 
23
  MIN_COUNT="${MIN_COUNT:-20}"
24
  MAX_ABS_RANK_BIAS="${MAX_ABS_RANK_BIAS:-0.02}"
25
  MAX_ABS_TYPE_BONUS="${MAX_ABS_TYPE_BONUS:-0.02}"
 
26
  PYTHON="${PYTHON:-python3}"
27
 
28
  ROLLOUT="$RUN_ROOT/$OBJECTIVE/seed_$SEED/$ROLLOUT_NAME"
@@ -38,6 +40,8 @@ mkdir -p outputs/hpc/logs "$(dirname "$OUT")"
38
  --max-rank "$MAX_RANK" \
39
  --rank-scale "$RANK_SCALE" \
40
  --type-scale "$TYPE_SCALE" \
 
41
  --min-count "$MIN_COUNT" \
42
  --max-abs-rank-bias "$MAX_ABS_RANK_BIAS" \
43
- --max-abs-type-bonus "$MAX_ABS_TYPE_BONUS"
 
 
20
  MAX_RANK="${MAX_RANK:-4}"
21
  RANK_SCALE="${RANK_SCALE:-0.05}"
22
  TYPE_SCALE="${TYPE_SCALE:-0.05}"
23
+ SCALE_SCALE="${SCALE_SCALE:-0.0}"
24
  MIN_COUNT="${MIN_COUNT:-20}"
25
  MAX_ABS_RANK_BIAS="${MAX_ABS_RANK_BIAS:-0.02}"
26
  MAX_ABS_TYPE_BONUS="${MAX_ABS_TYPE_BONUS:-0.02}"
27
+ MAX_ABS_SCALE_BONUS="${MAX_ABS_SCALE_BONUS:-0.02}"
28
  PYTHON="${PYTHON:-python3}"
29
 
30
  ROLLOUT="$RUN_ROOT/$OBJECTIVE/seed_$SEED/$ROLLOUT_NAME"
 
40
  --max-rank "$MAX_RANK" \
41
  --rank-scale "$RANK_SCALE" \
42
  --type-scale "$TYPE_SCALE" \
43
+ --scale-scale "$SCALE_SCALE" \
44
  --min-count "$MIN_COUNT" \
45
  --max-abs-rank-bias "$MAX_ABS_RANK_BIAS" \
46
+ --max-abs-type-bonus "$MAX_ABS_TYPE_BONUS" \
47
+ --max-abs-scale-bonus "$MAX_ABS_SCALE_BONUS"
workspace/scripts/slurm/eval_maniskill_policy_rollout.sbatch CHANGED
@@ -121,6 +121,16 @@ if [[ -z "$FIELD_RANK_BIAS_MAP" && -n "$FIELD_RANK_BIAS_OBJECTIVE" ]]; then
121
  fi
122
  FIELD_RANK_BIAS_MAP="$RUN_ROOT/$FIELD_RANK_BIAS_OBJECTIVE/seed_$SEED/$FIELD_RANK_BIAS_NAME"
123
  fi
 
 
 
 
 
 
 
 
 
 
124
  CANDIDATE_ORACLE_ROLLOUTS="${CANDIDATE_ORACLE_ROLLOUTS:-0}"
125
  CANDIDATE_ORACLE_UNIQUE_TOLERANCE="${CANDIDATE_ORACLE_UNIQUE_TOLERANCE:-1e-6}"
126
 
@@ -157,6 +167,9 @@ fi
157
  if [[ -n "$FIELD_RANK_BIAS_MAP" ]]; then
158
  EXTRA_ARGS+=(--field-rank-bias-map "$FIELD_RANK_BIAS_MAP")
159
  fi
 
 
 
160
  if [[ -n "$RETRIEVAL_RESIDUAL_SOURCE_SCORE_BONUS_MAP" ]]; then
161
  EXTRA_ARGS+=(--retrieval-residual-source-score-bonus-map "$RETRIEVAL_RESIDUAL_SOURCE_SCORE_BONUS_MAP")
162
  fi
 
121
  fi
122
  FIELD_RANK_BIAS_MAP="$RUN_ROOT/$FIELD_RANK_BIAS_OBJECTIVE/seed_$SEED/$FIELD_RANK_BIAS_NAME"
123
  fi
124
+ RESIDUAL_SCALE_BONUS_MAP="${RESIDUAL_SCALE_BONUS_MAP:-}"
125
+ RESIDUAL_SCALE_BONUS_OBJECTIVE="${RESIDUAL_SCALE_BONUS_OBJECTIVE:-}"
126
+ RESIDUAL_SCALE_BONUS_NAME="${RESIDUAL_SCALE_BONUS_NAME:-residual_scale_bonuses.json}"
127
+ if [[ -z "$RESIDUAL_SCALE_BONUS_MAP" && -n "$RESIDUAL_SCALE_BONUS_OBJECTIVE" ]]; then
128
+ if [[ -z "$RUN_ROOT" ]]; then
129
+ echo "RESIDUAL_SCALE_BONUS_OBJECTIVE requires RUN_ROOT" >&2
130
+ exit 1
131
+ fi
132
+ RESIDUAL_SCALE_BONUS_MAP="$RUN_ROOT/$RESIDUAL_SCALE_BONUS_OBJECTIVE/seed_$SEED/$RESIDUAL_SCALE_BONUS_NAME"
133
+ fi
134
  CANDIDATE_ORACLE_ROLLOUTS="${CANDIDATE_ORACLE_ROLLOUTS:-0}"
135
  CANDIDATE_ORACLE_UNIQUE_TOLERANCE="${CANDIDATE_ORACLE_UNIQUE_TOLERANCE:-1e-6}"
136
 
 
167
  if [[ -n "$FIELD_RANK_BIAS_MAP" ]]; then
168
  EXTRA_ARGS+=(--field-rank-bias-map "$FIELD_RANK_BIAS_MAP")
169
  fi
170
+ if [[ -n "$RESIDUAL_SCALE_BONUS_MAP" ]]; then
171
+ EXTRA_ARGS+=(--residual-scale-bonus-map "$RESIDUAL_SCALE_BONUS_MAP")
172
+ fi
173
  if [[ -n "$RETRIEVAL_RESIDUAL_SOURCE_SCORE_BONUS_MAP" ]]; then
174
  EXTRA_ARGS+=(--retrieval-residual-source-score-bonus-map "$RETRIEVAL_RESIDUAL_SOURCE_SCORE_BONUS_MAP")
175
  fi