據(jù)集監(jiān)督預(yù)訓(xùn)練與微調(diào)實(shí)戰(zhàn):plans 對(duì)齊、權(quán)重遷移與微調(diào)流程詳解)
人工智能深度學(xué)習(xí)計(jì)算機(jī)視覺醫(yī)療健康【免費(fèi)下載鏈接】nnUNet項(xiàng)目地址https://gitcode.com/gh_mirrors/nn/nnUNet點(diǎn)擊查看免費(fèi)下載導(dǎo)讀在 nnU-Net v2 中不同數(shù)據(jù)集經(jīng)過自動(dòng)化實(shí)驗(yàn)規(guī)劃后其 patch size、網(wǎng)絡(luò)拓?fù)?、batch size 乃至歸一化方案往往各不相同因此不能直接把一個(gè)數(shù)據(jù)集上訓(xùn)練好的權(quán)重搬到另一個(gè)數(shù)據(jù)集上。本文以 documentation/pretraining_and_finetuning.md 為核心完整講解監(jiān)督預(yù)訓(xùn)練的可行路徑先把目標(biāo)數(shù)據(jù)集的 plans 轉(zhuǎn)移到預(yù)訓(xùn)練數(shù)據(jù)集以對(duì)齊網(wǎng)絡(luò)結(jié)構(gòu)再用allfold 在預(yù)訓(xùn)練數(shù)據(jù)上訓(xùn)練最后通過-pretrained_weights參數(shù)把權(quán)重初始化到目標(biāo)數(shù)據(jù)集并微調(diào)。讀完本文你將掌握一套可復(fù)現(xiàn)的跨數(shù)據(jù)集遷移訓(xùn)練方案并了解其背后的源碼實(shí)現(xiàn)原理與注意事項(xiàng)。需要說明的是本文討論的是監(jiān)督式的 plans/權(quán)重跨數(shù)據(jù)集遷移。如果你要找的是基于 nnssl本文不涉及該路徑。術(shù)語約定整個(gè)流程涉及兩個(gè)數(shù)據(jù)集原文檔給出的術(shù)語定義如下術(shù)語含義pretraining dataset預(yù)訓(xùn)練數(shù)據(jù)集即你打算在其上執(zhí)行預(yù)訓(xùn)練的數(shù)據(jù)集finetuning dataset微調(diào)數(shù)據(jù)集即你真正關(guān)心、最終要微調(diào)出模型的目標(biāo)數(shù)據(jù)集兩者的關(guān)系是先在預(yù)訓(xùn)練數(shù)據(jù)集上訓(xùn)練出一個(gè)通用的模型再把它的權(quán)重作為目標(biāo)數(shù)據(jù)集的初始化從而獲得更好的收斂性能或更短的訓(xùn)練時(shí)間。為什么不能直接復(fù)用權(quán)重plans 對(duì)齊是前提nnU-Net 最核心的特性之一是自動(dòng)化數(shù)據(jù)集分析與實(shí)驗(yàn)規(guī)劃對(duì)每個(gè)數(shù)據(jù)集它會(huì)依據(jù)數(shù)據(jù)指紋fingerprint自動(dòng)決定 patch size、batch size、網(wǎng)絡(luò)拓?fù)?、歸一化方案等訓(xùn)練超參數(shù)參見 nnunetv2/experiment_planning/ 下的相關(guān)實(shí)現(xiàn)。這意味著兩個(gè)數(shù)據(jù)集的 patch size 可能不同兩個(gè)數(shù)據(jù)集的網(wǎng)絡(luò)拓?fù)渖疃?、寬度、卷積核配置可能不同兩個(gè)數(shù)據(jù)集的歸一化方案可能不同。權(quán)重 tensor 的形狀與網(wǎng)絡(luò)結(jié)構(gòu)嚴(yán)格綁定拓?fù)洳灰恢聲r(shí)state_dict根本無法對(duì)齊。因此開箱即用地從一個(gè)數(shù)據(jù)集拿權(quán)重去初始化另一個(gè)數(shù)據(jù)集是不可能的。解決辦法就是把目標(biāo)數(shù)據(jù)集finetuning dataset的 plans 轉(zhuǎn)移到預(yù)訓(xùn)練數(shù)據(jù)集讓兩邊共享完全相同的網(wǎng)絡(luò)結(jié)構(gòu)、patch size、batch size 與歸一化設(shè)置。原文檔特別強(qiáng)調(diào)轉(zhuǎn)移是全量的不只是網(wǎng)絡(luò)拓?fù)洹atch size 和 patch size歸一化方案也會(huì)一并轉(zhuǎn)移。因此在兩個(gè)使用不同歸一化方案的數(shù)據(jù)集之間做遷移可能效果不好但取決于具體方案也可能可行。對(duì)于 CT 數(shù)據(jù)還要注意CT 歸一化中的 clip 值、均值mean與標(biāo)準(zhǔn)差std同樣會(huì)被轉(zhuǎn)移——預(yù)訓(xùn)練數(shù)據(jù)集的 CT 數(shù)據(jù)將按目標(biāo)數(shù)據(jù)集的統(tǒng)計(jì)量做歸一化處理。完整實(shí)操流程在預(yù)訓(xùn)練數(shù)據(jù)集上訓(xùn)練整個(gè)流程共分 5 步命令均來自原文檔下面結(jié)合源碼逐一展開說明。第 0 步環(huán)境準(zhǔn)備按照 documentation/setting_up_paths.md 和 documentation/set_environment_variables.md 設(shè)置nnUNet_raw、nnUNet_preprocessed、nnUNet_results等環(huán)境變量預(yù)訓(xùn)練數(shù)據(jù)集與微調(diào)數(shù)據(jù)集都已按 nnU-Net 數(shù)據(jù)集格式放置于nnUNet_raw中格式規(guī)范見 documentation/dataset_format.md。第 1 步為微調(diào)數(shù)據(jù)集執(zhí)行實(shí)驗(yàn)規(guī)劃與預(yù)處理nnUNetv2_plan_and_preprocess -d FINETUNING_DATASET因?yàn)槲覀冏罱K關(guān)心的是微調(diào)數(shù)據(jù)集所以需要先對(duì)它的數(shù)據(jù)進(jìn)行數(shù)據(jù)指紋提取、實(shí)驗(yàn)規(guī)劃與預(yù)處理產(chǎn)出它的 plans 文件。該命令的入口與實(shí)現(xiàn)位于 nnunetv2/experiment_planning/plan_and_preprocess_entrypoints.py核心 API 在 nnunetv2/experiment_planning/plan_and_preprocess_api.py 中。規(guī)劃完成后微調(diào)數(shù)據(jù)集在nnUNet_preprocessed目錄下會(huì)生成形如nnUNetPlans.json的 plans 文件。第 2 步提取預(yù)訓(xùn)練數(shù)據(jù)集的指紋若尚未生成nnUNetv2_extract_fingerprint -d PRETRAINING_DATASET該步驟只計(jì)算預(yù)訓(xùn)練數(shù)據(jù)集的指紋模態(tài)、spacing、強(qiáng)度分布等統(tǒng)計(jì)信息不做規(guī)劃。從源碼看它調(diào)用的是 nnunetv2/experiment_planning/plan_and_preprocess_api.py 中的extract_fingerprint_dataset實(shí)際計(jì)算由 nnunetv2/experiment_planning/dataset_fingerprint/fingerprint_extractor.py 中的DatasetFingerprintExtractor完成。指紋是后續(xù)預(yù)處理如裁剪、重采樣所必需的輸入。第 3 步將微調(diào)數(shù)據(jù)集的 plans 轉(zhuǎn)移到預(yù)訓(xùn)練數(shù)據(jù)集nnUNetv2_move_plans_between_datasets -s FINETUNING_DATASET -t PRETRAINING_DATASET -sp FINETUNING_PLANS_IDENTIFIER -tp PRETRAINING_PLANS_IDENTIFIER參數(shù)含義參數(shù)說明-s源數(shù)據(jù)集此處為微調(diào)數(shù)據(jù)集的名稱或 ID-t目標(biāo)數(shù)據(jù)集此處為預(yù)訓(xùn)練數(shù)據(jù)集的名稱或 ID-sp源 plans 標(biāo)識(shí)符即源數(shù)據(jù)集 plans 文件名去掉.json后綴的部分通常就是nnUNetPlans除非你在nnUNetv2_plan_and_preprocess時(shí)更換過實(shí)驗(yàn)規(guī)劃器-tp目標(biāo) plans 標(biāo)識(shí)符建議設(shè)置成一個(gè)自定義名稱如nnUNetPlansFrom2以免覆蓋預(yù)訓(xùn)練數(shù)據(jù)集默認(rèn)的 plans該命令的實(shí)際實(shí)現(xiàn)在 nnunetv2/experiment_planning/plans_for_pretraining/move_plans_between_datasets.py 中入口為entry_point_move_plans_between_datasets邏輯核心是move_plans_between_datasets見 L12-L61。從源碼可以看到它在轉(zhuǎn)移時(shí)做了以下幾件事斷言前置條件要求源數(shù)據(jù)集已存在預(yù)處理目錄否則提示先運(yùn)行nnUNetv2_plan_and_preprocess且源 plans 文件存在否則提示先執(zhí)行實(shí)驗(yàn)規(guī)劃見 L23-L29改寫dataset_name把 plans 中的dataset_name改成目標(biāo)預(yù)訓(xùn)練數(shù)據(jù)集名稱L32保證后續(xù)訓(xùn)練/推理能正確找到目標(biāo)數(shù)據(jù)集改寫data_identifier若-tp與-sp不同會(huì)把每個(gè) configuration 里的data_identifier前綴替換為目標(biāo)標(biāo)識(shí)符L35-L43這樣預(yù)處理產(chǎn)出的數(shù)據(jù)會(huì)落在以新標(biāo)識(shí)符命名的子目錄下避免與預(yù)訓(xùn)練數(shù)據(jù)集原有預(yù)處理數(shù)據(jù)沖突改寫 reader/writer根據(jù)目標(biāo)數(shù)據(jù)集的dataset.json與示例圖像重新確定image_reader_writerL45-L56保證讀取器與目標(biāo)數(shù)據(jù)集的圖像格式匹配寫入新 plans 文件最終保存為nnUNet_preprocessed/預(yù)訓(xùn)練數(shù)據(jù)集/PRETRAINING_PLANS_IDENTIFIER.jsonL60-L61。第 4 步用轉(zhuǎn)移后的 plans 預(yù)處理預(yù)訓(xùn)練數(shù)據(jù)集nnUNetv2_preprocess -d PRETRAINING_DATASET -plans_name PRETRAINING_PLANS_IDENTIFIER注意這里必須顯式指定-plans_name PRETRAINING_PLANS_IDENTIFIER即第 3 步中你自定義的目標(biāo) plans 標(biāo)識(shí)符。由于該 plans 中記錄的是微調(diào)數(shù)據(jù)集的 patch size、spacing 重采樣目標(biāo)和歸一化參數(shù)預(yù)訓(xùn)練數(shù)據(jù)集的預(yù)處理數(shù)據(jù)將完全按微調(diào)數(shù)據(jù)集的口徑生成從而保證后續(xù)訓(xùn)練時(shí)兩邊的數(shù)據(jù)形態(tài)一致。第 5 步在預(yù)訓(xùn)練數(shù)據(jù)集上訓(xùn)練使用 all foldnnUNetv2_train PRETRAINING_DATASET CONFIG all -p PRETRAINING_PLANS_IDENTIFIERPRETRAINING_DATASET預(yù)訓(xùn)練數(shù)據(jù)集名稱或 IDCONFIG配置名如2d、3d_fullres等在轉(zhuǎn)移的 plans 中存在的 configurationall使用全部數(shù)據(jù)訓(xùn)練。原文檔明確指出預(yù)訓(xùn)練場(chǎng)景下沒有必要?jiǎng)澐謹(jǐn)?shù)據(jù)做交叉驗(yàn)證所以這里用allfold 而非0/1/2/3/4之一-p PRETRAINING_PLANS_IDENTIFIER指定使用轉(zhuǎn)移過來的自定義 plans。訓(xùn)練完成后或當(dāng)你以其他方式獲得了兼容權(quán)重后預(yù)訓(xùn)練數(shù)據(jù)集的 checkpoint如checkpoint_final.pth即作為可復(fù)用的初始化權(quán)重。使用預(yù)訓(xùn)練權(quán)重初始化目標(biāo)數(shù)據(jù)集模型基本命令nnUNetv2_train FINETUNING_DATASET CONFIG FOLD -pretrained_weights PATH_TO_CHECKPOINT其中PATH_TO_CHECKPOINT指向預(yù)訓(xùn)練階段產(chǎn)出的 checkpoint 文件例如.../checkpoint_final.pth。訓(xùn)練正常結(jié)束后你得到的就是在目標(biāo)數(shù)據(jù)集上微調(diào)好的模型可用標(biāo)準(zhǔn)的 documentation/run_inference_with_pretrained_models.md 流程進(jìn)行推理。源碼層面的實(shí)現(xiàn)細(xì)節(jié)-pretrained_weights的處理邏輯位于 nnunetv2/run/run_training.py與-c繼續(xù)訓(xùn)練互斥maybe_load_checkpoint中明確斷言——continue_training與pretrained_weights不能同時(shí)使用預(yù)訓(xùn)練權(quán)重只能在訓(xùn)練開始時(shí)加載見 L100-L104加載時(shí)機(jī)當(dāng)既不是繼續(xù)訓(xùn)練也不是純驗(yàn)證時(shí)且指定了pretrained_weights_file會(huì)先初始化 trainerinitialize()再調(diào)用load_pretrained_weights(nnunet_trainer.network, pretrained_weights_file, verboseTrue)將權(quán)重灌入網(wǎng)絡(luò)見 L120-L125繼續(xù)訓(xùn)練時(shí)的 checkpoint 查找順序checkpoint_final.pth→checkpoint_latest.pth→checkpoint_best.pth見 L106-L111這與微調(diào)后繼續(xù)訓(xùn)練的場(chǎng)景相關(guān)。權(quán)重加載函數(shù)位于 nnunetv2/run/load_pretrained_weights.py其機(jī)制值得展開按 key 與 shape 匹配只把 key 相同且 shape 相同的參數(shù)從預(yù)訓(xùn)練state_dict復(fù)制到當(dāng)前網(wǎng)絡(luò)L62-L65并在加載前逐一斷言非分割層參數(shù)必須存在且形狀一致L43-L51跳過分割層key 中包含.seg_layers.的參數(shù)即最終輸出分割圖的 1x1(x1) 卷積層不會(huì)被轉(zhuǎn)移L30-L32。這正是原文檔所說加載預(yù)訓(xùn)練權(quán)重時(shí)除分割層外的所有層都會(huì)被使用的源碼依據(jù)——分割頭保持隨機(jī)初始化以適應(yīng)目標(biāo)數(shù)據(jù)集的類別數(shù)兼容 DDP 與 torch.compile 前綴如果預(yù)訓(xùn)練權(quán)重來自 nnU-Net 之外的訓(xùn)練如 DDP 會(huì)加module.前綴、torch.compile 會(huì)加_orig_mod前綴需要先修正 key而 nnU-Net 自己保存的 checkpoint 由nnUNetTrainer.save_checkpoint處理過無需擔(dān)心L15-L18加載時(shí)也會(huì)自動(dòng)剝離這些前綴L34-L40。微調(diào)階段的訓(xùn)練器選擇與自定義原文檔明確說明目前 nnU-Net 沒有專門針對(duì)微調(diào)場(chǎng)景定制的 trainer當(dāng)前推薦做法就是直接使用標(biāo)準(zhǔn)nnUNetTrainer并配合-pretrained_weights參數(shù)。同時(shí)你完全可以根據(jù)需要編寫自己的 trainer 子類例如學(xué)習(xí)率 warmup/ramp up在微調(diào)初期使用較低或線性上升的學(xué)習(xí)率避免破壞預(yù)訓(xùn)練特征分割頭專項(xiàng)微調(diào)先凍結(jié)編碼器只訓(xùn)練分割頭再解凍全網(wǎng)絡(luò)縮短訓(xùn)練輪數(shù)因?yàn)槟P鸵延辛己玫某跏蓟梢燥@著減少 epochs。關(guān)于自定義 trainer倉庫中已有大量可參考的變體實(shí)現(xiàn)如 nnunetv2/training/nnUNetTrainer/variants/ 下的各類 Trainer自定義 trainer 需要繼承nnUNetTrainer并置于nnunetv2.training.nnUNetTrainer命名空間下之后通過nnUNetv2_train的-tr參數(shù)指定該查找邏輯可參考 nnunetv2/utilities/find_class_by_name.py 的recursive_find_python_class。需要特別區(qū)分的是本倉庫 nnunetv2/training/nnUNetTrainer/pretraining/pretrainedTrainer.py 中的PretrainedTrainer以及PretrainedTrainer_Primus、PretrainedTrainer_150ep等系列是自監(jiān)督 nnssl 擴(kuò)展路徑專用的訓(xùn)練器——它從 plans 中的pretrain_info讀取 checkpoint 路徑與 key 映射負(fù)責(zé)把 nnssl 預(yù)訓(xùn)練編碼器適配進(jìn)分割網(wǎng)絡(luò)包括按輸入通道重復(fù) stem 權(quán)重、按 patch size 對(duì)可學(xué)習(xí)位置編碼做三線性插值等并配合 warmup→train 兩階段學(xué)習(xí)率調(diào)度。該訓(xùn)練器通過nnUNetv2_train_pretrained入口nnunetv2/run/run_training_from_pretrained.py啟動(dòng)與本文討論的監(jiān)督式 plans 轉(zhuǎn)移 -pretrained_weights初始化是兩條相互獨(dú)立的流程詳見 documentation/finetuning_from_nnssl_checkpoints.md。實(shí)操注意事項(xiàng)匯總結(jié)合原文檔與源碼以下幾點(diǎn)在實(shí)踐中尤其重要plans 必須嚴(yán)格對(duì)齊預(yù)訓(xùn)練與微調(diào)必須使用同一份結(jié)構(gòu)相同的plans否則load_pretrained_weights中非分割層 key 與 shape 必須匹配的斷言會(huì)直接報(bào)錯(cuò)-tp使用自定義標(biāo)識(shí)符防止覆蓋預(yù)訓(xùn)練數(shù)據(jù)集原本的nnUNetPlans同時(shí)后續(xù)nnUNetv2_preprocess與nnUNetv2_train都要記得帶-plans_name/-p指向同一標(biāo)識(shí)符歸一化方案會(huì)整體轉(zhuǎn)移包括 CT 的 clip 值、mean、std。若預(yù)訓(xùn)練數(shù)據(jù)集與微調(diào)數(shù)據(jù)集的歸一化差異過大遷移效果可能不佳分割層不遷移目標(biāo)數(shù)據(jù)集的類別數(shù)不必與預(yù)訓(xùn)練數(shù)據(jù)集一致分割頭會(huì)從頭訓(xùn)練預(yù)訓(xùn)練用allfold預(yù)訓(xùn)練階段不劃分交叉驗(yàn)證 fold把全部數(shù)據(jù)用于訓(xùn)練-pretrained_weights與-c互斥無法一邊繼續(xù)訓(xùn)練一邊加載預(yù)訓(xùn)練權(quán)重預(yù)訓(xùn)練權(quán)重只在訓(xùn)練初始階段生效checkpoint 路徑要寫對(duì)PATH_TO_CHECKPOINT應(yīng)指向真實(shí)存在的.pth文件如checkpoint_final.pth源碼會(huì)直接torch.load讀取其network_weights字段??偨Y(jié)nnU-Net v2 的監(jiān)督預(yù)訓(xùn)練方案本質(zhì)上是一個(gè)plans 搬運(yùn) 權(quán)重初始化的流程通過nnUNetv2_move_plans_between_datasets把微調(diào)數(shù)據(jù)集的完整訓(xùn)練配置網(wǎng)絡(luò)拓?fù)?、patch size、batch size、歸一化參數(shù)等遷移給預(yù)訓(xùn)練數(shù)據(jù)集在預(yù)訓(xùn)練數(shù)據(jù)集上用allfold 完成預(yù)訓(xùn)練最后用-pretrained_weights把預(yù)訓(xùn)練權(quán)重初始化到微調(diào)數(shù)據(jù)集分割層除外并正常訓(xùn)練。整套流程的所有關(guān)鍵環(huán)節(jié)都有對(duì)應(yīng)的源碼實(shí)現(xiàn)可供核對(duì)任何一步出錯(cuò)如 plans 未對(duì)齊、checkpoint 路徑不存在、歸一化不匹配都能在報(bào)錯(cuò)信息或代碼斷言中找到明確提示。贊分享人工智能深度學(xué)習(xí)計(jì)算機(jī)視覺醫(yī)療健康【免費(fèi)下載鏈接】nnUNet項(xiàng)目地址https://gitcode.com/gh_mirrors/nn/nnUNet點(diǎn)擊查看免費(fèi)下載相關(guān)推薦SimCLR 對(duì)比學(xué)習(xí)實(shí)戰(zhàn)TensorFlow Model Garden 中的無監(jiān)督預(yù)訓(xùn)練與半監(jiān)督微調(diào)全流程SimCLR 對(duì)比學(xué)習(xí)實(shí)戰(zhàn)TensorFlow Model Garden 中的無監(jiān)督預(yù)訓(xùn)練與半監(jiān)督微調(diào)全流程 TensorFlow Model Garden人工智能深度學(xué)習(xí)計(jì)算機(jī)視覺NLP語音Fairseq 中 wav2vec 2.0 全流程實(shí)戰(zhàn)數(shù)據(jù)清單、自監(jiān)督預(yù)訓(xùn)練、CTC 微調(diào)與跨語言擴(kuò)展Fairseq 中 wav2vec 2.0 全流程實(shí)戰(zhàn)數(shù)據(jù)清單、自監(jiān)督預(yù)訓(xùn)練、CTC 微調(diào)與跨語言擴(kuò)展 本文以 examples/wav2vec/README人工智能深度學(xué)習(xí)預(yù)訓(xùn)練NLP語音Ant Design DatePicker 的 needConfirm掌控選擇確認(rèn)按鈕的提交時(shí)機(jī)Ant Design DatePicker 的 needConfirm掌控選擇確認(rèn)按鈕的提交時(shí)機(jī) 本篇文章聚焦 Ant Design DatePicker 組大模型模型微調(diào)上一篇Komodo用戶行為分析優(yōu)化部署工具的使用體驗(yàn)下一篇Satellizer逆向工程從編譯代碼還原認(rèn)證流程設(shè)計(jì)創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考