134 MB
5 files
Updated 3 months ago
Name
Size
README.md6.15 kB
xet
label_encoder.pkl275 Bytes
xet
preprocessor.pkl3.22 kB
xet
random_forest_final_model.joblib60.8 kB
xet
resnet-18.pth134 MB
xet
README.md

Model Card for DSI TB DRUG RESISTANCE PREDICTION

DSI model is a classification model that predicts drug resistance in TB patients 2 months after they start treatment.

Model Details

Model Description

Month 2 Sputum Conversion Prediction (Tabular + CXR images)

The Drug Resistance Prediction model is RandomForest based predictive model designed to identify tuberculosis (TB) patients who are likely to exhibit drug resistance two months after initiating treatment. Drug-resistant TB patients do not respond to the standard first-line medications, and their TB status remains MTBc-positive rather than converting to MTBc-negative as expected. The DSI model aims to predict this resistance early, using demographic and clinical information collected at baseline (month 0). By identifying patients at high risk of drug resistance, the model supports clinicians in making timely decisions—such as initiating a more aggressive treatment regimen—potentially improving patient outcomes and preventing prolonged infectiousness.

  • Developed by: Marconi Lab
  • Funded by:
  • Shared by: Marconi Lab
  • Model type: LightGBM classifier
    • License: MIT

Model Sources

Intended Use

  • Primary use case: Early prediction of sputum conversion to guide treatment monitoring.
  • Intended users: Healthcare researchers, clinicians
  • Input:
    • 21 structured tabular features (demographics, vitals, symptoms)
    • 512-dimensional feature vector from CXR image
  • Output: Binary prediction
    • 1 = MTBC Negative
    • 0 = MTBC Positive

Training Data

  • Features:
    • Numerical: AGE_YEARS, BMI, TEMPERATURE_CELICIUS, HOUSEHOLD_DENSITY
    • Binary categorical: SEX, HIV_STATUS, etc.
    • Multiclass categorical: EDUCATION_LEVEL, OWNERSHIP, SIGHT_OF_TB_DISEASE
    • Image feature: 512-dim vector from pretrained ResNet-18
  • Preprocessing:
    • StandardScaler for numerical features
    • OneHotEncoder for categorical features
    • ResNet-18 for image embeddings

Training & Evaluation

  • Tabular Preprocessing: ColumnTransformer
  • Image Features: Extracted using pretrained timm.create_model('resnet18')
  • Fusion: np.hstack of tabular and image feature vectors
  • Label Encoding: LabelEncoder on 2_MONTHS
  • Models Evaluated: Random Forest, AdaBoost, Gradient Boosting, XGBoost
  • Best model: RandomForestClassifier(class_weight='balanced')

Results (Test Set)

Metric Value
Accuracy 0.9091
Recall (MTBc Negative) 1.00
Recall (MTBc Positive) 0.00
F1 Score (MTBc Negative) 0.95
F1 Score (MTBc Positive) 0.00
Weighted F1 Score 0.87

Confusion Matrix:

Predicted MTBc Negative Predicted MTBc Positive
Actual MTBc Positive 10 0
Actual MTBc Negative 1 0

Limitations

  • Severe class imbalance (only 1 MTBC+ case in train/test)
  • Poor generalization to positive cases
  • Small dataset (35 total samples: 24 train, 11 test)

Inference Example

import torch
import timm
import joblib
import pickle
import numpy as np
import pandas as pd
from PIL import Image
from torchvision import transforms

# Load Saved Artifacts 
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

# Load image feature extractor 
image_model = timm.create_model("resnet18", pretrained=False, num_classes=3)
image_model.load_state_dict(torch.load("resnet-18.pth", map_location=device)["model_state_dict"])
image_model.fc = torch.nn.Identity()
image_model = image_model.to(device)
image_model.eval()

# Load Random Forest model and preprocessing tools
rf_model = joblib.load("random_forest_final_model.joblib")
with open("preprocessor.pkl", "rb") as f:
    preprocessor = pickle.load(f)
with open("label_encoder.pkl", "rb") as f:
    label_encoder = pickle.load(f)

#  Preprocessing Function
transform = transforms.Compose([
    transforms.Resize((224, 224)),
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.485, 0.456, 0.406],
                         std=[0.229, 0.224, 0.225])
])

def extract_image_features(image_path):
    img = Image.open(image_path).convert("RGB")
    img_tensor = transform(img).unsqueeze(0).to(device)
    with torch.no_grad():
        features = image_model(img_tensor).squeeze().cpu().numpy()
    return features

# Inference Function 
def predict(image_path, tabular_input_dict):
    # Extract image features
    image_features = extract_image_features(image_path)

    # Process tabular input
    tabular_df = pd.DataFrame([tabular_input_dict])
    tabular_processed = preprocessor.transform(tabular_df)

    # Concatenate tabular and image features
    combined_input = np.hstack([tabular_processed, image_features.reshape(1, -1)])

    # Predict and decode label
    y_pred = rf_model.predict(combined_input)
    predicted_label = label_encoder.inverse_transform(y_pred)[0]
    return predicted_label

# Example Usage 
tabular_input = {
    "SEX": "M",
    "AGE_YEARS": 35,
    "BMI": 16.5,
    "HIV_STATUS": "NEGATIVE",
    "HAS_DIABETES_YES/NO": "NO",
    "SMOKES_CIGARETTES_YES/NO": "YES",
    "CONSUMES_ALCOHOL_YES/NO": "NO",
    "SIGHT_OF_TB_DISEASE": "LUNGS",
    "TEMPERATURE_CELICIUS": 39.0,
    "COUGH": "YES",
    "FEVER": "YES",
    "WEIGHT_LOSS": "YES",
    "NIGHT_SWEATS": "YES",
    "DYSPENA": "NO",
    "CHEST_PAIN": "YES",
    "HEMOPTYSIS": "NO",
    "CONSUMED_ANTIBIOTICS_IN_THE_PAST_6_MONTHS__YES/NO": "NO",
    "OWNERSHIP": "RENTED",
    "EDUCATION_LEVEL": "TERTIARY EDUCATION",
    "HOUSEHOLD_DENSITY": 6.0
}

prediction = predict("example_cxr.jpg", tabular_input)
print("Predicted TB Conversion at Month 2:", prediction)

Model Card Authors

Marconi Lab

Model Card Contact

brunobeijuka@gmail.com

Total size
134 MB
Files
5
Last updated
Jun 16
Pre-warmed CDN
US EU US EU

Contributors