FundusNet: a deep learning approach for identifying novel endophenotypes for neurodegenerative and eye diseases from fundus images
Hu, W., Li, K., Gagnon, J., Wang, Y., Raney, T., Chen, J., Chen, Y., Okunuki, Y., Chen, W., & Zhang, B. (2025). FundusNet: A Deep-Learning Approach for Fast Diagnosis of Neurodegenerative and Eye Diseases Using Fundus Images. Bioengineering, 12(1), 57. https://doi.org/10.3390/bioengineering12010057
- Install cuda
conda create --name <name_of_your_env>orconda create -p <path_of_your_env>conda activate <name_of_your_env>
Install pytorch https://pytorch.org/get-started/locally/
Example,pip3 install torch torchvision --index-url https://download.pytorch.org/whl/cu126- git clone the repo
git clone https://github.com/interactivereport/FundusNet.git - install packages
pip install -r requirements.txt - Execute either shgender.sh or shage.sh to run individual CNN or ViT models:
a. This process will split the image dataset into training and testing sets, train the CNN/ViT models on the training data, and evaluate them on the test data.
b. Users must provide the following inputs:
'name of csv_file (string)': Path to the CSV file containing annotations.
'root_dir (string)': Directory containing all images. - Combine the results using majority voting for ensemble prediction.
importosimportnumpyasnpimportmathimporttorchfrompytorch_grad_camimportGradCAMfrommodelwrapperimportModelwrapperfromgcam_utilsimportrun_save_gcam_results# specify input filesdevice=torch.device("cuda:0"iftorch.cuda.is_available() else"cpu")
model_name='regnety_32'pheno_name='glaucoma'# examples of model checkpoints, https://zenodo.org/records/15711816cmodel_ckpt=f'../model_ckpt/{pheno_name}_{model_name}_v0.pth'csv_file=f'../result_biomarker_interpretation/input_imgs/imgs_{pheno_name}.csv'img_dir='../result_biomarker_interpretation/input_imgs/'result_dir='../result_biomarker_interpretation/'# run gradCAM to generate figures for biomarker interpretationnum_classes=1ifpheno_name=='age'else2mwrapper=Modelwrapper(num_classes=num_classes)
cmodel=getattr(mwrapper, model_name)().to(device)
cmodel.load_state_dict(torch.load(cmodel_ckpt))
cmodel.eval()
target_layers= [cmodel.s4.b1.conv3.conv]
use_cuda=Trueifdevice.type=='cuda'elseFalsecam=GradCAM(model=cmodel, target_layers=target_layers, use_cuda=True)
run_save_gcam_results(cam=cam,
img_dir=img_dir,
result_dir=result_dir,
csv_file=csv_file,
pheno_name=pheno_name)['image_0_glaucoma_1.png', 'image_1_glaucoma_1.png', 'image_2_glaucoma_1.png', 'image_3_glaucoma_1.png']
['image_4_glaucoma_0.png', 'image_5_glaucoma_0.png', 'image_6_glaucoma_0.png', 'image_7_glaucoma_0.png']
importosimportnumpyasnpimportpandasaspdimporttorchfrommodelwrapperimportModelwrapperfromimgdatasetimportImgDataset_withaugment# specify input filesdevice=torch.device("cuda:0"iftorch.cuda.is_available() else"cpu")
model_name='regnety_32'pheno_name='age'# 'gender'cmodel_ckpt=f'../model_ckpt/{pheno_name}_{model_name}_v0.pth'csv_file=f'../result_biomarker_interpretation/input_imgs/imgs_{pheno_name}.csv'img_dir='../result_biomarker_interpretation/input_imgs/'result_dir='../result_biomarker_interpretation/'batchsize=2num_classes=1ifpheno_name=='age'else2mwrapper=Modelwrapper(num_classes=num_classes)
cmodel=getattr(mwrapper, model_name)().to(device)
cmodel.load_state_dict(torch.load(cmodel_ckpt))
cmodel.eval()
image_datasets=ImgDataset_withaugment(csv_file=csv_file, root_dir=img_dir, crop='center')
dataloader=torch.utils.data.DataLoader(image_datasets, batch_size=batchsize, num_workers=4)
dataloader_iterator=iter(dataloader)img_names= []
y_true= []
y_preds= []
forinputs, labels, img_nameindataloader:
img_names.extend(list(img_name))
y_true.extend(labels.tolist())
inputs=inputs.to(device)
labels=labels.to(device)
preds=cmodel(inputs)
ifnum_classes==2:
_, preds=torch.max(preds, 1)
y_preds.extend(preds.cpu().detach().numpy().flatten())
df=pd.DataFrame({'filename':img_names, 'class':y_true, f'predicted_{pheno_name}':y_preds})
df.to_csv(os.path.join(result_dir, f'imgs_{pheno_name}_predicted.csv'), index=False)
print(df.head()) filename class predicted_age
0 image_0_age_61.png 61 58.069225
1 image_1_age_61.png 61 62.588211
2 image_2_age_72.png 72 73.754265
3 image_3_age_53.png 53 53.196304


