Ebben a cikkben elmagyarázom a „Mellkasröntgen-felvételek (tüdőgyulladás)” Kaggle-adatkészlettel végzett kísérleteimet, és azt, hogy hogyan kezeltem a különböző problémákat ezen az úton, ami az érvényesítőkészlet és a teszt tökéletes pontosságához vezetett. készletek. Célom, hogy a fastai (v2) segítségével bemutassam a különböző trükköket, amiket könnyen bevethetsz, és egyfajta ablációs vizsgálatként megosszam ezzel az adatkészlettel végzett kísérleteimet. Feltételezem, hogy ismeri a mély tanulás alapjait, és ismeri a python DL-keretrendszereit, különösen a PyTorch-ot és a fastai-t. Tehát kezdjük.

Az adatkészlet letöltése

A következő parancsokkal könnyedén hozzáférhet az adatkészlethez. Előtte létre kell hoznia egy Kaggle-fiókot arra az esetre, ha még nem rendelkezik ilyennel, és saját API-token információit kell használnia a kód futtatásához.

Elkezdeni

Azzal kezdem, hogy megnézem az adatkészlet felépítését, és betöltöm a képfájlok neveit. Ebben az adatkészletben betanítási, érvényesítési és tesztkészleteink vannak, ahogy ez a gépi tanulási adatkészletekben megszokott.

Itt a get_image_files segítségével olvasom be az adataink három partíciójának képfájlnevét, majd az L-et használom, amely jól helyettesíti a List osztályt a Pythonban. a fastaitól a lenfüggvény leképezéséhez a három fájlnévlistán. Amint látja, 5216, 16 és 624 kép áll rendelkezésünkre a képzéshez, az ellenőrzéshez és a tesztkészlethez. Az érvényesítési készletünk nagyon kicsi, erről a cikk későbbi részében fogok beszélni

Vessünk egy pillantást egy apró EDA-ra. Azt szeretném tudni, hogy az adathalmaz kiegyensúlyozott-e, azaz nagyjából ugyanannyi elemünk van-e a Normal vs Pneumonia osztályokhoz.

Ahogyan az a való világban és különösen az orvosi adatkészletekben megszokott, a két kategóriába tartozó tételek száma között nagy a különbség (a tüdőgyulladás és a normál esetek aránya 3:1). Tehát az első problémánk, amit szem előtt kell tartanunk, az, hogy valamilyen trükkel kezeljük ezt az egyensúlyhiányt. Valójában nem javaslom, hogy sok időt töltsön minden más előtt a probléma megoldására, és inkább azt javaslom, hogy először készítse el kezdeti modelljét a kiegyensúlyozatlan adatokkal, és nézze meg, hogyan megy!

DataBlock és DataLoaders

Itt elkészítem a DataBlock-ot és a Dataloader-emet, hogy betáplálják az adatokat a modellbe. A fastai-ban nagyon könnyű megtenni, azonban ennél a cikknél nem megyek bele az egyes kódrészletek részleteibe, és nagyon ajánlom, hogy a tanfolyamon szabadon olvassa el a könyvüket vagy a book's Jupyter notebookokat weboldal. De azoknak, akik ismerik a PyTorch-ot és a fastai-t, itt építem fel a képzési és érvényesítési adatbetöltőimet, valamint az adatbővítést.

Az osztálykiegyensúlyozatlanság még ezen a kis képsoron is nyilvánvaló!

Itt adatbővítést használok, hogy enyhítsem a kis adatkészlet problémáját. Bár nem változtatja meg a pozitív és negatív eseteink arányát, segíthet a modellnek az egyensúlyhiány problémájának kezelésében, ha több pozitív esetet vezet be, ami segíti a mögöttes mintázat robusztusabb megismerését. Az orvosi adatkészletek adatbővítésénél győződjön meg arról, hogy azokat adja hozzá, amelyek értelmesek, és nem változtatják meg adatait olyan esetekben, amelyek túlságosan eltérnek a valós adatoktól. Itt eleinte 512-re méretezem át a képeket a „squish” metódussal, hogy ne veszítsem el az adatok valószínűleg fontos részeit (itt nem vágom, de a cikk következő részében meglátjuk, hogyan vágunk is működni fog). Ezt követően a RandomResizedCropGPU 224-es méretű foltokat vág ki véletlenszerűen az 512-es képből. Ezt a technikát a fastai könyv szerzői „előméretezésnek” nevezik. Ezután tovább bővítjük a Forgatás és a Nagyítás funkcióval. Nem fordítom meg, nem torzítom vagy módosítom a képeim fényerejét és kontrasztját (amelyek a legtöbb számítógépes látási feladathoz legitim adatbővítési típusok), mert úgy gondolom, hogy ez már nem fog valódi röntgenképet képviselni. Ne feledje azt is, hogy még a vízszintes megfordítás is problémás lehet a röntgenfelvételeken bizonyos feladatoknál (talán itt nem sok), különösen akkor, ha a testszervek elhelyezkedése fontos. Például a dextrocardia egy ritka állapot, amelyben a szív a mellkas jobb oldalán helyezkedik el, és a képek megfordítása megbénítja a modellt, hogy észlelje ezeket az eseteket.

Emellett szeretnék itt valamit világossá tenni. Az adatkészletben található képek egycsatornás szürkeárnyalatos képek. Ám az ImageNet-re (és a többi használatra kész modellarchitektúra alapértelmezett módjára a fastai-ban) előképzett modellek, amelyeket később a cikkben fogunk használni, 3 csatornás RGB bemenetet várnak a modellhez. Emiatt nem kell aggódnunk, mert az adatblokk és a PILImage osztály úgy vészeli át ezt, hogy az első csatornánkat még kétszer megismétli, hogy háromcsatornás kép legyen, és készen állunk arra, hogy bármilyen modellen normálisan betanítsuk.

Alapmodell

Alapvonalnak nevezem, mert itt nem használunk divatos trükköket, de nem lesz igazi alapmodell, mint amilyeneket a konv. és a lineáris rétegek egymásra halmozásával építünk. Az XResNet18 architektúrával kezdem. Az XResNets valójában nagyon hasonlít a vaníliás ResNetekhez, de néhány módosítással rákereshet rájuk az interneten, vagy elolvashatja a "Trükkök zsákja a képosztályozáshoz konvolúciós neurális hálózatokkal" című cikkét Tong He et. al. hogy többet megtudjon a különbségekről. Mivel ez egy alapmodell lesz, a nulláról fogom betanítani, és ebben az esetben nem fogok előképzett modellt használni.

Ahogy a cselekmény sugallja, és ahogy vártam, a 3e-3 tanulási arány itt jónak tűnik. Tehát gyakoroljuk 10 korszakon keresztül az egy ciklus politikájával, és meglátjuk, hogyan megy.

Oké! Nem csináltunk rosszul, de messze vagyunk a tökéletestől! Van néhány pont ezekben az eredményekben. Ha megnézi a pontosságot és az f1-es pontszámokat, akkor ezek instabilnak tűnnek, ami bizonyos okok miatt van. Először a modellt a semmiből oktatjuk (és még az adatokat sem normalizáljuk!), ami instabilabb képzéshez vezethet. Másodszor, az érvényesítő készletünk nagyon kicsi! Csak 16 elemet tartalmaz, amelyek nem feltétlenül reprezentálják jól azokat az adatokat, amelyekre a modellt képezik. Végül egy ciklusos képzést használok itt, ami növeli a tanulási arányt az iterációk első 25 százalékában, ami magasabb valid_loss-t okozhat a képzés korai szakaszában.

Gondoljunk így a modellünkre. 3875 tüdőgyulladásunk van, szemben az 1341 normál esettel. Tehát ha a modellünk egyszerűen „tüdőgyulladást” ad ki az edzéskészletben látott minden elemnél, akkor könnyen elérheti a körülbelül 75 százalékos pontosságot. A modellünk itt nem pontosan ezt csinálja (mert az f1 pontszámunk arra utal, hogy bizonyos mértékig megtanulta megkülönböztetni a két osztályt), de tudnunk kell, hogy milyen a legegyszerűbb alapvonal!

Végül is úgy gondolom, hogy jó eredményeket érünk el mindössze 4 perces edzés után ezen a meglehetősen kis adatkészleten. Ebben és a következő cikkben azonban sok nagyszerű dolgot fogunk kísérletezni, hogy jobbá tegyük.

Az osztálykiegyensúlyozatlanság problémájának leküzdése

Ahogy az előző részekben említettem, az egyik problémánk az osztálykiegyensúlyozatlanság probléma. A számítógépes látás szakirodalmában számos módot találhat az adatkészletek ezen igazán gyakori problémájának leküzdésére. Erősen javaslom, hogy olvassa el a „A konvolúciós neurális hálózatok osztálykiegyensúlyozatlansági problémájának szisztematikus tanulmánya” című cikket, amely tökéletes munkát végzett a probléma megoldására szolgáló különböző módszerek összehasonlításában. Absztraktjában a következőket találhatja:

Kísérleteink eredményei alapján arra a következtetésre jutottunk, hogy (i) az osztálykiegyensúlyozatlanság hatása az osztályozási teljesítményre káros; (ii) az osztálykiegyensúlyozatlanság kezelésének módszere, amely szinte minden elemzett forgatókönyvben dominánsnak tűnt, a túlmintavétel volt…(iv) szemben néhány klasszikus gépi
tanulási modellel, a túlmintavétel nem a CNN-ek túlillesztését okozzák

Igazán szép! Megkaptuk a választ! Hadd magyarázzam. Az osztályok kiegyensúlyozatlanságának leküzdésére a leggyakrabban használt megközelítés a nagyobb arányú osztályból a lefelé történő mintavétel (kevesebb adat felhasználásával), vagy az alacsonyabb arányú osztály túlmintavétele. A lap az utóbbit javasolja; esetünkben a „normál” esetek számának növelése egyszerűen megismételve őket a betanítási adatkészletben. Ezt így tehetjük meg:

Mindössze ezt a két kódsort kell tennünk! Az első sorban a „normál” esetek fájlneveit gyűjtöm össze egy listában (vagy L betűvel!). A második sorban valahogy három listát halmozok fel: az egyikben a korábbi edzési fájlneveim szerepelnek (kiegyensúlyozatlan normál és tüdőgyulladás esetek), a másikban a „normál” fájlnevek kétszer ismétlődnek (normal_cases*2) és egy lista. amely tartalmazza a 16 érvényesítési fájlt (a képzési és érvényesítési készletet később az adatblokkban különválasztjuk, mint az előző részben található kódot). Jelenleg 3875 tüdőgyulladás és 4023 normál eset van, nagyjából egyenlő. Ügyeljen arra, hogy ezt a mintavételezett listát adja meg az adatblokknak a betanítási és érvényesítési készletek új indexeivel. Tanítsuk újra a modellünket ezen az új adatkészleten (a modell felépítése a semmiből történik, és pontosan ugyanaz, mint korábban):

Azta! 100 százalékos pontosságot értünk el! Amennyire a cikk írásakor tudom, ez messze a legjobb eredmény a megadott érvényesítési halmazon, és a képzési idő sokkal alacsonyabb, mint mások, akik modelleket javasoltak ezen az adatkészleten.

Modellünk tökéletesen besorolta az érvényesítési halmazt. Ha ezt mintavételezésen keresztül végezzük, a képzési folyamat stabilabbnak tűnik, mint az előző modell. Az érvényesítési veszteségünk most lényegesen alacsonyabb, mint az előző modellnél, és sokkal közelebb áll a vonatvesztéshez. Tehát ezzel megerősíthetjük a papír eredményeit, mivel sokkal jobb eredményeket kaptunk túlillesztés nélkül.

Az eredmény nagyon jó, de ne örülj neki túlságosan! :) Talán emlékszel, hogy az érvényesítő készletünk nagyon kicsi, mindössze 16 mintát tartalmaz. Ez a mintaszám jóval kisebb, mint amennyire szilárd következtetést le tudunk vonni a modell teljesítményéről. Valójában, ha kipróbálod, amit itt csináltam, más eredményeket kaphatsz, mert ennél az alacsony mintaszámnál a véletlenszerűségnek nagy szerepe van! Kipróbáltam a modellt a tesztkészleten (tudom, hogy túl korai még ezt a részt használni, de megtettem!), és 85 százalékos pontosságot kaptam, ami megerősíti, amit itt mondtam, hogy a modell nem tud jól általánosítani (még!).

Tehát egy igazán jó és robusztus modell betanítása érdekében ezentúl ebben a cikkben az adathalmaz által biztosított tesztkészletet egyesítem a validációs halmazba, hogy pontosabban tudjuk megítélni modellünk viselkedését más trükkök, ill. döntse el, mihez kezdjen ezzel az információval. Az alábbiakban bemutatjuk, hogyan egyesítheti az érvényesítési és tesztkészleteket:

Íme az új alapmodell eredményei a túlmintavételezett adatkészleten, egyesített érvényesítéssel és tesztkészletekkel, két új metrikával, a Precision és Recall:

Amint látja, az eredmények egyre stabilabbak, és nem ugrálnak széles körben egyik számról a másikra. A következő részekben mindegyikben hozzáadnék egy-egy trükköt a képzési folyamatunkhoz, és megnézném, hogyan hat az edzésre.

Normalizálás

Ebben a részben normalizálni fogom adataimat úgy, hogy kivonom az átlagot, és elosztom a szórással. Először ezeket a statisztikákat kell megszereznem az adataimból. A következőket teszem, hogy megkapjam az egyes csatornák átlagát és szórását:

Amint látja, az átlagot vagy a szórást jelző három szám megegyezik, mivel a csatornák azonosak, ahogy az előző részben mondtam.

Ha hozzáadja a következőket az adatblokk létrehozásához szükséges kódhoz, akkor az adatok normalizálódnak:

Amikor újra betanítottam ugyanazt a modellt a semmiből, a következőket kaptam:

Itt leginkább azért nem volt nagy változás, mert a nulláról edzünk, és a modell képes alkalmazkodni a nem normalizált adatokhoz is.

Tanulási és előképzett modellek átvitele

Szinte mindig nagyszerű ötlet a projektet (vagy esetleg néhány alapmodell után) transzfertanulás és előképzett modellek segítségével indítani. Sokkal hasznosabbak, mint a súlyok véletlenszerű inicializálása, és segítenek a modellnek könnyebben és gyorsabban konvergálni. Az átviteli tanulás során fontos, hogy a bemeneti adatok hasonló tulajdonságokkal rendelkezzenek, mint azokhoz az adatokhoz, amelyekre a modellt betanították; tehát normalizálni fogjuk adatainkat, hogy minden egyes csatorna átlaga nulla legyen, szórása pedig egy legyen. Ne feledje, hogy (valójában fastai!) megismételtük az egyetlen csatornánkat, hogy három csatornás képeinket természetes képpé tegyük. Tehát most készen állunk az első modellünk finomhangolására! Építse fel adatblokkját, mint korábban, amikor a Normalize elemet a batch_tfmsbe foglalta, majd könnyedén elkészítheti előre betanított modelljét a következő módon:

Itt meg kell jegyezni pár dolgot. Az architektúrát resnet18-ra változtattam, ami nagyon hasonlít az előzőhöz, és itt a cnn_learner-et használom, amely alapértelmezés szerint betölti a modell előre betanított súlyait, és lefagyasztja a legtöbb réteget (kivéve a modelljét fej, ​​amely új és véletlenszerűen inicializált), így a súlyuk nem frissül. Megtalálhatja a tanulási sebességet, és a modellt úgy taníthatja, mint korábban. Ne feledje, hogy a fastai v2-ben könnyen finomhangolhatja az előképzett modellt a fine_tune módszerrel, amely először betanítja a lefagyott modellt, majd feloldja, és további korszakokra betanítja. De itt kézzel csinálom ezt az eljárást:

Oké! Körülbelül két százalékkal nagyobb pontosság az előképzett modell használatával. Az ábrán látható, hogy a látszólag legjobb eredmények az edzés közepén vannak (6. szakasz), és talán több korszakunk volt a szükségesnél. Amint azt Jeremy Howard a 2020-as fastai tanfolyamon említette, jobb a modellt a szükséges számú korszakra áttanítani (ebben az esetben például 6), ahelyett, hogy EarlyStopping vagy SaveModel visszahívásokat használna. sok korszak. Ennek az az oka, hogy egyciklusos tréninget használunk, és az utolsó iterációkban jelentősen csökkentjük a tanulási arányt, ami jobb optimumokat eredményezhet a veszteségi felületen, ami elősegítheti a jobb modellezést, és elveszítjük ezt a lehetőséget, ha abbahagyjuk a képzést a az iterációk közepén, amikor a tanulási arány magas.

Lefagyás

Most feloldjuk a modellt, és betanítjuk az összes réteget, különböző tanulási sebességeket használva a különböző rétegekhez. Tudjuk, hogy a transzfertanulásban a modell korai rétegeinek nem kell olyan nagy súlyt változtatni, mert a tanulásért felelős dolgok szinte általánosak az önéletrajzi feladatokban. Másrészt magasabb tanulási arányt használunk a rétegeknél, ahogy mélyebbre megyünk a modellben, hogy alkalmazkodjunk az új feladathoz. De előtte nézzük meg, milyen tanulási arányokat érdemes alkalmaznunk:

És ez az lr_find() eredménye:

Az lr_find cselekmény értelmezése néha nehézkes lehet. De ebben az esetben meglehetősen egyszerű. A szelet (1e-6, 1e-4) megadom a tanulási sebesség tartományaként a modell különböző rétegeihez (a korai rétegek maximális lrértéke 1e-6, a legmélyebb rétegeké pedig 1e-4 lesz a max_lr). Ezt a tartományt akkor is megfelelőnek találtam, ha azlr_find diagram nem annyira hasznos.

Itt egy százalékkal nagyobb pontosságot kaptunk. Amint azt már észrevetted, itt kevesebb korszakra edzek, mert előtte egyszer edzettem, és 5 korszakot elégnek találtam, és az előző részben az EarlyStoping-ról korábban elmondottak szerint, inkább újra edzettem, mintsem abbahagytam volna. képzés az eljárás közepén. A következő részben még tovább fokozzuk a modell teljesítményét.

Progresszív átméretezés

Eddig 224 * 224 méretű képekkel képeztük modelljeinket, ami az eredeti méretű, 512 * 512 feletti képekhez képest meglehetősen kicsi kép. Itt az utolsó szekcióban lévő modellünket nagyobb képekkel finomítjuk. 360 * 360 méretű, hogy több adatot vigyen be a modellünkbe, és segítse a minták megtanulását. Az egyetlen dolog, amin változtatni kell, az:

Most változtattam a méretet 360-ra így. Újra le kell fagyasztanunk a modellt és egy kicsit edzenünk, majd fel kell oldanunk, és tovább kell edzenünk. Csak a végeredményt mutatom meg, hogy csökkentsem a cikk hosszát:

Ez tényleg fantasztikus! körülbelül 95 százalékos pontosságot kapunk az egyesített érvényesítési és tesztkészleten, és a pontossági és visszahívási pontszámok mind tökéletesen magasak.

A következő részben alaposabban értelmezzük modellünk eredményeit.

Modellértelmezés

Itt megmutatom, hogyan szerezheti meg egyszerűen a modell értelmezését a fastai segítségével. Vessünk egy pillantást a zavaró mátrix lekéréséhez szükséges kódra:

Elfogadható! Vessünk egy pillantást az osztályozási jelentésre is:

A számok azt mutatják, hogy jó munkát végzünk ezen a meglehetősen kis adatkészleten. Most ellenőrizhetjük, hogyan állunk a kezdeti érvényesítési halmazzal (ez a 16 kép). Tudom, hogy furcsa, mert ezek a képek már benne vannak az egyesített érvényességi készletünkben, de ez csak egy egyszerű ellenőrzés, hogy megbizonyosodjunk arról, hogy a modellünk erősebb, mint korábban, ugyanolyan teljesítménnyel a megadott érvényesítési készleten:

Oké tökéletes! 100 százalékos pontosság, f1_score, precizitás és visszahívás. Emlékszel, a cikk elején a mintavételezés után 100 százalékos pontosságot kaptunk, és itt megismételtük. De ez a modell robusztusabb, mert az általunk készített nagyobb validációs készlet segítségével különböző trükköket tesztelhettünk, és a tréning során kinyomtatott veszteségeket és mérőszámokat felhasználva eldönthettük, mit tegyünk ezután, hogyan hangoljuk a modelljeinket. De a hátránya az, hogy már nincs tesztkészletünk, és valójában nem tudjuk, hogyan működik ez a modell a valós adatokon, mert lehetséges, hogy túlillesztették a modellt az egyesített érvényességi halmazban. De az eredmények valóban ígéretesek, és lehet, hogy a későbbiekben nem lesz gondunk.

A cikk következő része

Mivel ez a cikk nagyon hosszúra nyúlik, a többi trükköt és kísérletet egy külön cikkben fejtem ki, ennek második részeként. Meglátjuk, hogyan használhatjuk a Grad CAM-et és az egyszerű hőtérképeket, hogy megjelenítsük, mire figyel a modellünk a képeken, és megpróbáljuk a hiperparaméter hangolást (a súlycsökkenés és a tanulási arány hangolása), ami szerintem nagyon izgatott lesz. Ezt követően kipróbáljuk a Label Smoothing, a MixUp, aHalf Precisionképzést és más modellarchitektúrákat és adatbővítési módszereket, és meglátjuk, hogy mindegyik milyen hatással van a projektre.

Források: Sok ötletet felhasználtam a Deep Learning for Coders with Fastai and PyTorch és a fastai tanfolyamok című könyvből. Nagyon ajánlom, hogy próbálják ki őket.

Rólam: Orvostanhallgató vagyok, és szeretem a mélyreható tanulást és azokat a klassz dolgokat, amelyeket életminőségünk javítása érdekében építhetünk vele. Arra fogom használni az erejét, hogy legyőzzem az orvostudomány előtt álló akadályokat. Az orvosi tanfolyamaim mellett sok időt töltök a mély tanulással, és olyan interdiszciplináris területeken szeretnék dolgozni, ahol a mesterséges intelligencia és az orvostudomány találkozik :)