convitom commited on
Commit ·
6344cc7
1
Parent(s): 815a64a
- configs/train_config.yaml +1 -1
- data/eda_reports.ipynb +49 -1
- scripts/vertex_job.yaml +1 -1
configs/train_config.yaml
CHANGED
|
@@ -238,7 +238,7 @@ stage1:
|
|
| 238 |
# handled entirely by Stage 2. When disabled (default), Stage 1 trains
|
| 239 |
# the projection with the causal-LM loss through Vicuna (original path).
|
| 240 |
itc:
|
| 241 |
-
enabled:
|
| 242 |
# Path to the {study_id: tensor[proj_dim]} cache produced by
|
| 243 |
# scripts/precompute_cxrbert_embeddings.ipynb. Required when enabled.
|
| 244 |
text_embed_cache: null
|
|
|
|
| 238 |
# handled entirely by Stage 2. When disabled (default), Stage 1 trains
|
| 239 |
# the projection with the causal-LM loss through Vicuna (original path).
|
| 240 |
itc:
|
| 241 |
+
enabled: true
|
| 242 |
# Path to the {study_id: tensor[proj_dim]} cache produced by
|
| 243 |
# scripts/precompute_cxrbert_embeddings.ipynb. Required when enabled.
|
| 244 |
text_embed_cache: null
|
data/eda_reports.ipynb
CHANGED
|
@@ -1030,6 +1030,54 @@
|
|
| 1030 |
" print(pct_data.to_string())"
|
| 1031 |
]
|
| 1032 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1033 |
{
|
| 1034 |
"cell_type": "markdown",
|
| 1035 |
"metadata": {},
|
|
@@ -1285,4 +1333,4 @@
|
|
| 1285 |
},
|
| 1286 |
"nbformat": 4,
|
| 1287 |
"nbformat_minor": 5
|
| 1288 |
-
}
|
|
|
|
| 1030 |
" print(pct_data.to_string())"
|
| 1031 |
]
|
| 1032 |
},
|
| 1033 |
+
{
|
| 1034 |
+
"cell_type": "markdown",
|
| 1035 |
+
"id": "f77592d6",
|
| 1036 |
+
"metadata": {},
|
| 1037 |
+
"source": "## 6b. Ví dụ báo cáo bất thường — outlier dài, quá ngắn, section lạ"
|
| 1038 |
+
},
|
| 1039 |
+
{
|
| 1040 |
+
"cell_type": "markdown",
|
| 1041 |
+
"id": "997c36b4",
|
| 1042 |
+
"metadata": {},
|
| 1043 |
+
"source": "### 1. Outlier dài — vượt Q3 + 1.5·IQR\n\nNgưỡng theo IQR fence (tính từ toàn bộ dataset):\n- **Findings** : Q3 = 61, IQR = 28 → upper fence = **103 từ**\n- **Impression**: Q3 = 40, IQR = 34 → upper fence = **91 từ**"
|
| 1044 |
+
},
|
| 1045 |
+
{
|
| 1046 |
+
"cell_type": "code",
|
| 1047 |
+
"execution_count": null,
|
| 1048 |
+
"id": "d3fa9af1",
|
| 1049 |
+
"metadata": {},
|
| 1050 |
+
"outputs": [],
|
| 1051 |
+
"source": "q1_f, q3_f = df[\"findings_len\"].quantile(0.25), df[\"findings_len\"].quantile(0.75)\nq1_i, q3_i = df[\"impression_len\"].quantile(0.25), df[\"impression_len\"].quantile(0.75)\nthresh_f = q3_f + 1.5 * (q3_f - q1_f)\nthresh_i = q3_i + 1.5 * (q3_i - q1_i)\nprint(f\"Outlier fence - Findings > {thresh_f:.0f} tu | count: {(df['findings_len'] > thresh_f).sum():,}\")\nprint(f\"Outlier fence - Impression > {thresh_i:.0f} tu | count: {(df['impression_len'] > thresh_i).sum():,}\")\n\n\ndef report_path(row):\n return f\"files/{row['subset']}/p{row['subject_id']}/s{row['study_id']}.txt\"\n\n\nN = 10 # so vi du muon lay moi loai\n\nprint(f\"\\n=== Findings outlier (top {N} dai nhat) ===\")\nfor _, row in df[df[\"findings_len\"] > thresh_f].nlargest(N, \"findings_len\").iterrows():\n print(f\" {int(row['findings_len']):>4} tu {report_path(row)}\")\n\nprint(f\"\\n=== Impression outlier (top {N} dai nhat) ===\")\nfor _, row in df[df[\"impression_len\"] > thresh_i].nlargest(N, \"impression_len\").iterrows():\n print(f\" {int(row['impression_len']):>4} tu {report_path(row)}\")"
|
| 1052 |
+
},
|
| 1053 |
+
{
|
| 1054 |
+
"cell_type": "markdown",
|
| 1055 |
+
"id": "883f744d",
|
| 1056 |
+
"metadata": {},
|
| 1057 |
+
"source": "### 2. Báo cáo có findings < 3 từ hoặc impression < 2 từ\n\nNhững report ngắn bất thường — thường là lỗi parse hoặc nội dung quá sơ lược,\nkhông đủ thông tin để huấn luyện mô hình."
|
| 1058 |
+
},
|
| 1059 |
+
{
|
| 1060 |
+
"cell_type": "code",
|
| 1061 |
+
"execution_count": null,
|
| 1062 |
+
"id": "6f5ba746",
|
| 1063 |
+
"metadata": {},
|
| 1064 |
+
"outputs": [],
|
| 1065 |
+
"source": "short_f = df[df[\"findings_len\"] < 3].copy()\nshort_i = df[df[\"impression_len\"] < 2].copy()\nprint(f\"Findings < 3 tu : {len(short_f):,} ({len(short_f)/total*100:.2f}%)\")\nprint(f\"Impression < 2 tu: {len(short_i):,} ({len(short_i)/total*100:.2f}%)\")\n\nN = 10 # so vi du sample moi loai\n\nprint(f\"\\n=== Findings < 3 tu (sample {N}) ===\")\nfor _, row in short_f.sample(min(N, len(short_f)), random_state=42).iterrows():\n print(f\" findings={int(row['findings_len'])} tu {report_path(row)}\")\n\nprint(f\"\\n=== Impression < 2 tu (sample {N}) ===\")\nfor _, row in short_i.sample(min(N, len(short_i)), random_state=42).iterrows():\n print(f\" impression={int(row['impression_len'])} tu {report_path(row)}\")"
|
| 1066 |
+
},
|
| 1067 |
+
{
|
| 1068 |
+
"cell_type": "markdown",
|
| 1069 |
+
"id": "53a3ff19",
|
| 1070 |
+
"metadata": {},
|
| 1071 |
+
"source": "### 3. Báo cáo có section lạ — không có FINDINGS và IMPRESSION\n\nNhững report này có header không thuộc nhóm `findings` / `impression`.\nThường là admin-only hoặc các header category `other` / `view_desc` mà parser hiện tại bỏ qua."
|
| 1072 |
+
},
|
| 1073 |
+
{
|
| 1074 |
+
"cell_type": "code",
|
| 1075 |
+
"execution_count": null,
|
| 1076 |
+
"id": "47f751e4",
|
| 1077 |
+
"metadata": {},
|
| 1078 |
+
"outputs": [],
|
| 1079 |
+
"source": "from collections import Counter as _Counter\n\n# Reports khong co findings/impression nhung co it nhat 1 section\nno_fi = df[(df[\"findings\"].isna()) & (df[\"impression\"].isna()) & (df[\"n_sections\"] > 0)].copy()\n\nno_fi_cat = _Counter()\nfor headers_str in no_fi[\"section_headers\"].dropna():\n for h in headers_str.split(\"|\"):\n h = h.strip()\n if h:\n no_fi_cat[classify_header(h)] += 1\n\nprint(f\"Reports khong co findings/impression nhung co sections: {len(no_fi):,}\")\nprint(\"\\nPhan bo category header trong nhom nay:\")\nfor cat, cnt in sorted(no_fi_cat.items(), key=lambda x: -x[1]):\n print(f\" {cat:<12}: {cnt:>6,}\")\n\n# Loc nhung report co header 'other' (that su la)\nother_set = set(header_df[header_df[\"category\"] == \"other\"][\"header\"].str.upper())\nhas_other = no_fi[no_fi[\"section_headers\"].apply(\n lambda s: bool(set(h.strip().upper() for h in str(s).split(\"|\")) & other_set)\n)]\nprint(f\"\\nTrong do co header 'other' (la nhat): {len(has_other):,}\")\n\nN = 10 # so vi du\nsample_src = has_other if len(has_other) >= N else no_fi\nsample = sample_src.sample(min(N, len(sample_src)), random_state=7)\n\nprint(f\"\\n=== Vi du bao cao co section la (khong FINDINGS / IMPRESSION) ===\")\nfor _, row in sample.iterrows():\n print(f\" {report_path(row)} sections: {row['section_headers']}\")"
|
| 1080 |
+
},
|
| 1081 |
{
|
| 1082 |
"cell_type": "markdown",
|
| 1083 |
"metadata": {},
|
|
|
|
| 1333 |
},
|
| 1334 |
"nbformat": 4,
|
| 1335 |
"nbformat_minor": 5
|
| 1336 |
+
}
|
scripts/vertex_job.yaml
CHANGED
|
@@ -44,7 +44,7 @@ workerPoolSpecs:
|
|
| 44 |
exec python scripts/gcp_entrypoint.py
|
| 45 |
env:
|
| 46 |
- name: HF_TOKEN
|
| 47 |
-
value:
|
| 48 |
- name: DATASET_NAME
|
| 49 |
value: MIMIC-CXR_resized
|
| 50 |
- name: REPORT_MODE
|
|
|
|
| 44 |
exec python scripts/gcp_entrypoint.py
|
| 45 |
env:
|
| 46 |
- name: HF_TOKEN
|
| 47 |
+
value: _tSxYqkUSvesmWQOtoyrNpsHmfZlNFVUDRb
|
| 48 |
- name: DATASET_NAME
|
| 49 |
value: MIMIC-CXR_resized
|
| 50 |
- name: REPORT_MODE
|