nonzeroexit commited on
Commit
96010f3
·
verified ·
1 Parent(s): 2749f15

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +46 -12
app.py CHANGED
@@ -32,6 +32,7 @@ TRAINING_DATA_PATH = "training_data.csv"
32
 
33
  LIME_BACKGROUND_SIZE = 1000
34
  LIME_NUM_SAMPLES = 3000
 
35
 
36
 
37
  # ============================================================
@@ -307,7 +308,28 @@ def build_lime_background():
307
 
308
 
309
  # ============================================================
310
- # CREATE LIME EXPLAINER
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
311
  # ============================================================
312
 
313
  lime_training_data = (
@@ -315,24 +337,29 @@ lime_training_data = (
315
  )
316
 
317
 
318
- explainer = LimeTabularExplainer(
319
 
320
- training_data=lime_training_data,
321
 
322
- feature_names=selected_features,
323
 
324
- class_names=[
325
- "AMP",
326
- "Non-AMP"
327
- ],
328
 
329
- mode="classification",
 
 
 
330
 
331
- discretize_continuous=True,
 
 
 
 
 
332
 
333
- random_state=42
334
- )
335
 
 
 
336
 
337
  print("\nREAL LIME EXPLAINER READY.")
338
 
@@ -785,6 +812,13 @@ def full_prediction(sequence):
785
 
786
  try:
787
 
 
 
 
 
 
 
 
788
  explanation = (
789
  explainer.explain_instance(
790
 
 
32
 
33
  LIME_BACKGROUND_SIZE = 1000
34
  LIME_NUM_SAMPLES = 3000
35
+ LIME_RANDOM_SEED = 42
36
 
37
 
38
  # ============================================================
 
308
 
309
 
310
  # ============================================================
311
+ # LIME EXPLAINER FACTORY
312
+ # ------------------------------------------------------------
313
+ # IMPORTANT FIX:
314
+ #
315
+ # LimeTabularExplainer(random_state=42) only seeds its internal
316
+ # RandomState ONCE, at construction time. Every subsequent call
317
+ # to explain_instance() draws from -- and ADVANCES -- that same
318
+ # shared RandomState object. If you build the explainer ONCE at
319
+ # startup and reuse it across requests (as the original script
320
+ # did), the 1st, 2nd, 3rd, ... prediction on the SAME peptide
321
+ # each get a different slice of the random stream, so the
322
+ # perturbation neighborhood (and therefore the LIME weights)
323
+ # silently drifts between runs even though the RF model and
324
+ # MIC models are fully deterministic.
325
+ #
326
+ # The fix is to build a brand-new explainer, re-seeded from
327
+ # scratch, right before every explain_instance() call. This is
328
+ # cheap (it only recomputes discretization stats over the
329
+ # precomputed background array -- no model inference), and it
330
+ # guarantees the SAME peptide produces BYTE-IDENTICAL LIME
331
+ # output every single time, regardless of how many predictions
332
+ # came before it in the running app.
333
  # ============================================================
334
 
335
  lime_training_data = (
 
337
  )
338
 
339
 
340
+ def build_lime_explainer():
341
 
342
+ return LimeTabularExplainer(
343
 
344
+ training_data=lime_training_data,
345
 
346
+ feature_names=selected_features,
 
 
 
347
 
348
+ class_names=[
349
+ "AMP",
350
+ "Non-AMP"
351
+ ],
352
 
353
+ mode="classification",
354
+
355
+ discretize_continuous=True,
356
+
357
+ random_state=LIME_RANDOM_SEED
358
+ )
359
 
 
 
360
 
361
+ # Sanity-check that it builds correctly at startup.
362
+ _ = build_lime_explainer()
363
 
364
  print("\nREAL LIME EXPLAINER READY.")
365
 
 
812
 
813
  try:
814
 
815
+ # Fresh, re-seeded explainer every call -- see the
816
+ # comment above build_lime_explainer() for why this
817
+ # matters. This is what makes the explanation for a
818
+ # given peptide reproducible run after run.
819
+
820
+ explainer = build_lime_explainer()
821
+
822
  explanation = (
823
  explainer.explain_instance(
824