[PYTHON] Deep Learning-Anfänger versuchten, den Online-Kurs für medizinische KI so gut wie möglich zu verstehen [Kapitel 5]

Einführung

Der gesamte Code in diesem Artikel lautet [Medizinischer KI-Online-Kurs, Kapitel 5, Praktische Ausgabe: Segmentierung von MRT-Bildern](https://japan-medical-ai.github.io/medical-ai-course-materials/notebooks/05_Image_Segmentation] Ich habe versucht zu verstehen, indem ich .html zitierte. </ b> Die ursprüngliche Online-Kurswebsite wurde von der ** Medical AI Society ** erstellt und ist eine sehr anspruchsvolle Seite.

Dieser Artikel ist eine selbsterklärende Organisation dieses ausgeklügelten Codes für Anfänger in Deep Learning. ** In erster Linie ist es jedoch am besten, die oben genannte Website zu besuchen. ** **.

  • Die Absatznummern in diesem Artikel basieren auf der Site, damit sie mit der Site verglichen werden können. Wir sind.

5.3. Zu verwendender Datensatz

Der erste ist der Daten-Download.

!if [ ! -d train ]; then curl -L -O https://github.com/mitmul/chainer-handson/releases/download/SegmentationDataset/train.zip && unzip train.zip && rm -rf train.zip; fi
!if [ ! -d val ]; then curl -L -O https://github.com/mitmul/chainer-handson/releases/download/SegmentationDataset/val.zip && unzip val.zip && rm -rf val.zip; fi
  • ** Über [!] **

»Übrigens haben sich viele von Ihnen vielleicht gefragt, was das! Hier am Anfang hängt.

  • Mit Relevante Site können Sie sie mit ** google colab ** ausführen. Wir betrachten den Python-Code in Form eines Notizbuchs.
  • Sie können ** Shell-Code ** mit Google Colab usw. ausführen, indem Sie dem Code, der an der Eingabeaufforderung ausgeführt wird (Terminal für Mac), ! Hinzufügen.

Fahren wir mit der Erläuterung des Inhalts fort.

  • ** Über [if] ** --wenn xxx; dann ooo; fi bedeutet, ooo auszuführen, wenn es xxx ist. Es ist fast das gleiche wie Englisch. --Für Python schreiben Sie es wie wenn xxx: ooo. ――Dieses Mal handelt es sich um ein Shell-Skript, daher ist die Notation unterschiedlich, aber was Sie tun, ist dasselbe.

  • ** Über [curl] **

--curl bedeutet ** Dateien von der Website abrufen **. (Wahrscheinlich wäre ein Befehl mit ähnlicher Funktionalität "wget" usw.) -- -L und -O sind Optionen für curl. Fügen Sie -L hinzu, um die ** Umleitung ** zu aktivieren. Es scheint, dass -O ** Download mit dem Dateinamen der ursprünglichen Site ** bedeutet.

  • In diesem Fall können Sie durch Hinzufügen von "-O" die Dateien train.sip und val.zip von der gleichnamigen Zielseite von github.com herunterladen.

  • ** Über [&&] ** --&&ist einer der sogenannten logischen Operatoren. In diesem Fall wird der nächste Befehl ausgeführt, wenn der vorherige Befehl beendet ist.

  • ** Über [entpacken] **

--unzip bedeutet ** die Zip-Datei entpacken **. Entpacken Sie diesmal die komprimierten Dateien train.zip und val.zip in Ordner mit dem Namen train und val.

  • ** [rm] ** Über --rm ist ein ** Löschbefehl **. Ich habe die heruntergeladene Datei train.zip und val.zip erstellt, die mit unzip entpackt wurden, sodass ich sie nicht eingeben kann. Also lösche ich es. --Die Option "-rf" sollte im Sinne eines stärkeren Löschens als "rm" ohne Hinzufügen von etwas verstanden werden.
  • Ich habe es überhaupt nicht bestätigt, aber ich denke, dass "-r" eine Abkürzung für "rekursiv" und "-f" eine Abkürzung für "Kraft" ist. -r wird häufig verwendet, wenn Sie ** Ordner und Dinge ** in einem Shell-Skript löschen möchten.
%matplotlib inline

import matplotlib.pyplot as plt
import numpy as np

from PIL import Image

#Laden Sie Bilder mit der PIL-Bibliothek
img = np.asarray(Image.open('train/image/000.png'))
label = np.asarray(Image.open('train/label/000.png'))

#Zeigen Sie mit der matplotlib-Bibliothek zwei Bilder nebeneinander an
fig, axes = plt.subplots(1, 2)
axes[0].set_axis_off()
axes[0].imshow(img, cmap='gray')
axes[1].set_axis_off()
axes[1].imshow(label, cmap='gray')
plt.show()
  • ** Über [% matplotlib inline] **

  • Es ist wie ein Zaubertrick beim Schreiben von Python-Code im Notebook-Format. Wenn es Ihnen nichts ausmacht und Sie im ** Notizbuchformat ** schreiben (wenn Sie ein Jupyter-Notizbuch, ein Jupiter-Labor oder Google Colab verwenden), schreiben Sie dies.

  • ** Über [von ooo import xxx als @@@] **

    • import matplotlib.pyplot as plt Es bedeutet, "pyplot" in der Bibliothek "matplotlib" als "plt" herunterzuladen.
  • Als ich Python benutzte, hatte from PIL import Image ein Problem, weil es ein Chaos war , as am Ende, aber from vorne zu setzen. (Vielleicht nur ich)

  • Dies bedeutet, dass nur der Teil mit dem Namen "Image" aus der Bibliothek mit dem Namen "PIL" importiert wird. Kurz gesagt, das Bild ist, dass es ein Werkzeug namens "Image" in einer großen Box namens "PIL" gibt.

  • Damit der Computer das Teil abrufen kann, muss ** ein großes Feld vor dem Teilenamen ** angegeben werden. Ich denke, es wird in Zukunft schwieriger sein, einen Fehler zu machen. ――Schreiben Sie auch mit dem Pfadnamen zuerst den Ordnernamen und extrahieren Sie dann die darin enthaltene Datei.

  • ** Über [np.asarray ()] [Image.open ()] **

    • img = np.asarray(Image.open('train/image/000.png'))
  • Das zuvor heruntergeladene Bild wird mit "Image" gelesen, mit "numpy" in das Array-Format konvertiert und in einer Variablen namens "img" gespeichert (zugewiesen).

  • ** Über [plt.subplots ()] **

    • fig, axes = plt.subplots(1, 2) --Die Zuordnung des mit "plt" zu zeichnenden Graphen wird festgelegt. Für "plt.subplots (1, 2)" 1 in vertikaler Richtung und 2 in horizontaler Richtung. Das heißt, die beiden Bilder sind horizontal ausgerichtet. Im Gegenteil, wenn es sich um "plt.subplots (2, 1)" handelt, werden zwei Blätter vertikal ausgerichtet.
  • ** Über [.set_axis_off ()] **

    • axes[0].set_axis_off() ――Die erste Achse, die nebeneinander ausgerichtet ist, wird gelöscht. Wenn Sie dies nicht tun, bleibt die Skala erhalten und wird angezeigt. Ich möchte nur das Bild anzeigen, aber es ist ärgerlich. -Der Grund für [0] ist, dass der ** Python-Index bei 0 beginnt **.

Lass uns stetig gehen.

  • ** Über [.imshow ()] **
    • axes[0].imshow(img, cmap='gray')
  • Zeigen Sie das Bild auf dem ersten Blatt an. cmap ist ein Bildfarbformat, nicht wahr? Da es sich diesmal um ein MRT-Bild handelt, ist es schwarzweiß, daher wird "grau" angegeben.

Schließlich wird es mit plt.show () angezeigt. Es ist überhaupt nicht schwierig.

5.4 Segmentierung mit vollständig gekoppeltem neuronalen Netz

5.4.1 Datensatzvorbereitung

Aus diesem Bereich kam nun ein Gefühl des tiefen Lernens hervor. geben wir unser Bestes.

import glob
from chainer import datasets

def create_dataset(img_filenames, label_filenames):
    img = datasets.ImageDataset(img_filenames)
    img = datasets.TransformDataset(img, lambda x: x / 255.)  # 0-Normalisiert auf 1
    label = datasets.ImageDataset(label_filenames, dtype=np.int32)
    dataset = datasets.TupleDataset(img, label)
    return dataset
  • ** Über [glob] ** ――Diese Bibliothek ist eine Bibliothek, die einen Ordner usw. angibt und den Pfad der darin enthaltenen Dateien im Listenformat abruft. Ich benutze es die ganze Zeit.

  • Obwohl die Funktionsweise von Dateien und Ordnern bei einer Bibliothek namens os etwas anders ist, können Sie etwas Ähnliches tun.

  • ** Über [datasets.ImageDataset ()] ** ―― Laut der offiziellen Website verhält es sich so, als ob die Bilder im Listenformat vorliegen. Es ist sehr praktisch. ** Wie erwartet ist es PFN. ** **. ――Bei Angabe des Bildes geben Sie, wenn Sie dies verwenden, einfach den Pfad an. Das an den Pfad angepasste Bild wird im Format np.array zurückgegeben.

  • ** Über [datasets.TransformDataset (img, lambda x: x / 255.)] **

  • Haben Sie übrigens gehört, dass viele Bilder (8-Bit-Bilder) durch 256 Abstufungen ** von ** [0-255] ** dargestellt werden? (RGB, Graustufen usw.).

  • Wenn Sie mit Deep Learning lernen, ist es nicht sehr einfach, mit [0-255] umzugehen. Es scheint, dass es überwältigend [0-1] ist, das einfach zu handhaben ist. ――So dividieren Sie mit der Lambda-Funktion die Werte aller Pixel im Bild durch 255, um den Bereich auf [0-1] auszurichten.

  • ** [0-255] → [0-1] **, richtig?

  • ** Über [datasets.TupleDataset (img, label)] **

  • Dies ist eine Funktion, die Variablen in Form eines Tupels zurückgibt, das eine Eins-zu-Eins-Entsprechung zwischen img und label aufweist. Wie bei jedem ** überwachten Lernen ** müssen die Ein- und Ausgänge übereinstimmen. Das macht es. ――Zum Beispiel: Selbst wenn Sie ein kardiales MRT-Bild haben, können Sie in diesem Fall nicht lernen, welcher Teil des Modells der linke Ventrikel ist, wenn Sie nicht zuordnen, welcher Teil der linke Ventrikel ist. Dies bereitet das Modell darauf vor.

def create_datasets():
    #Name der MRT-Bilddatei mit Python Standard Glob/Holen Sie sich eine Liste der Namen der Etikettenbilddateien
    train_img_filenames = sorted(glob.glob('train/image/*.png'))
    train_label_filenames = sorted(glob.glob('train/label/*.png'))

    #Erstellen Sie einen Datensatzobjektzug und übergeben Sie eine Liste
    train = create_dataset(train_img_filenames, train_label_filenames)

    #Machen Sie dasselbe für Validierungsdaten
    val_img_filenames = sorted(glob.glob('val/image/*.png'))
    val_label_filenames = sorted(glob.glob('val/label/*.png'))
    val = create_dataset(val_img_filenames, val_label_filenames)

    return train, val
  • ** Über [glob.glob (... / *. Png)] ** --glob.glob ist derjenige, der die Liste der Pfade erhält, wie ich bereits erwähnt habe. Zum Beispiel in glob.glob ('train / image / *. Png') ** "alles in dem Ordner mit dem Namen image in dem Ordner mit dem Namen train, der mit der Erweiterung .png endet" Es bedeutet, ** zu bekommen. --*wird als Platzhalter bezeichnet " alle Zeichenketten mit einer Länge von 0 oder mehr ". Es ist eine Art regulärer Ausdruck. Es ist nützlich, sich daran zu erinnern. Ich erinnere mich auch daran.

  • ** Über [sortiert (...)] **

  • Der Inhalt der Liste ist nach Namen sortiert. Sortieren heißt sortieren. ――Wenn die Reihenfolge der Pfade, die im Inhalt von train_img_filenames und train_label_filenames enthalten sind, nicht in Ordnung ist und sie nicht übereinstimmen, denke ich, dass Sie sie verwenden, weil Sie sie nicht lernen können.

train, val = create_datasets()
print('Dataset size:\n\ttrain:\t{}\n\tvalid:\t{}'.format(len(train), len(val)))
  • In diesem Teil wird die Anzahl der in Zug und Wert enthaltenen Bilder überprüft. Die Nummer ist bereits beim Herunterladen offensichtlich, aber bei der tatsächlichen Codierung wäre es einfacher, sie so zu überprüfen.

  • Die Rückgabewerte (von return zurückgegebene Werte) der zuvor definierten Funktion create_datasets () werden in den Variablen train und val gespeichert. ――Es kommt vor, dass die Namen diesmal gleich sind, aber die von der Funktion create_datasets () erstellten Objekte train und val werden den Variablen train und val zugewiesen.

  • ** Ich denke, es ist in Ordnung, print () ** zu verwenden, aber vielleicht sind Sie es nicht gewohnt, wie \ n, \ t oder .format () zu schreiben. Hmm. \ n ist ein Zeilenvorschub, \ t ist ein Tabulatorzeichen und .format () wird durch Eingabe von Werten in das von '' eingeschlossene {} angezeigt.

Es ist nicht sehr cool,

print('Dataset size:')
print('train: '+str(len(train)))
print('val: '+str(len(val))) 

Selbst wenn Sie dies tun, wird es wahrscheinlich mit einem ähnlichen Gefühl ausgegeben. Es ist nicht cool (zweites Mal).

5.4.2. Modelldefinition

Es ist keine Übertreibung zu sagen, dass dieses Kapitel der größte Berg, der Kern und der wichtigste Teil des Lernnetzwerks ist.

import chainer
import chainer.functions as F
import chainer.links as L

class MultiLayerPerceptron(chainer.Chain):

    def __init__(self, out_h, out_w):
        super().__init__()
        with self.init_scope():
            self.l1 = L.Linear(None, 100)
            self.l2 = L.Linear(100, 100)
            self.l3 = L.Linear(100, out_h * out_w)
        self.out_h = out_h
        self.out_w = out_w

    def forward(self, x):
        h = F.relu(self.l1(x))
        h = F.relu(self.l2(h))
        h = self.l3(h)
        n = x.shape[0]

        return h.reshape((n, 1, self.out_h, self.out_w))

Erinnern Sie sich übrigens alle an die Klasse? Was ist Vererbung?

Ich werde in der Reihenfolge erklären.

  • ** Über [class MultiLayer Perceptron (chainer.Chain):] **

  • Dies macht es einfach, ein neu definiertes "MultiLayerPerceptron ()" unter Verwendung einer vorhandenen Klasse namens "chainer.Chain" zu erstellen. ――Es ist für normale Menschen unmöglich, ein Auto aus dem Nichts zu machen, aber es scheint, dass Sie es immer noch tun können, indem Sie einfach die Farbe des Autos ändern (ich denke, dass tatsächlich spezielle Technologie erforderlich ist). Kurz gesagt, es ist uns unmöglich, ein Auto von Grund auf neu zu bauen, aber ** wir machen es so, dass wir nur ein Teil ändern und es bewegen können **.

  • ** Über [super () .__ init __ ()] ** --Dies ruft den Teil init () aus der übergeordneten Klasse auf (chainer.Chain in diesem Beispiel).

  • ** Über [with self.init_scope ():] ** ――Ich weiß es nicht im Detail, aber ist dieser Teil eine charakteristische Schreibweise beim Erstellen eines Netzwerks mit Chainer? Ich werde die Ebene, die zum Lernen verwendet wird, hier einfügen. Ich werde mir von nun an den Inhalt ansehen.

  • ** Über [self.l1 = L.Linear (None, 100)] ** -Dies bedeutet, dass es in einer Variablen namens "l1" gespeichert wird, die in dieser Klasse gespeichert ist. Diesmal ist es L.Linear (). Wie Sie sehen können, ist das "L" oben im Originalcode

import chainer.links as L 

Ist geschrieben.

  • Kurz gesagt, wir haben einen Teil namens "Linear ()" in "chainer.links" verwendet. ――Und was genau ist Linear ()? Anscheinend ist es eine vollständig verbundene Schicht. (Genau genommen kann es etwas anders sein)
  • Wenn man die Entsprechung mit Keras berücksichtigt, sind ** Links ** ** Schichten ** in Keras, ** Linear () ** ist ** Dense () ** in Keras. Ist es ein Gefühl der Korrespondenz? Hier sind drei vollständig verbundene Schichten verbunden. Es hat eine einfache Struktur.
def forward(self, x):
  • [def forward(self, x):] ――Die Definition hier ist ** vorwärts **, dh ** vorwärts Propagierung **. Beim Deep Learning werden Werte in Ebenen von vorne nach hinten übergeben, um Eingabe in Ausgabe umzuwandeln. Ich mache es. ――Relu ist eine Relu-Funktion, nicht wahr? Es ist eine der ** Aktivierungsfunktionen **. Da es ein sehr großes ist, können viele Leute damit vertraut sein. ―― Beim Deep Learning wird die Eingabe in Schichten berechnet und durch die Aktivierungsfunktion ** nacheinander nichtlinear **.
  • In einigen Fällen kann es sein, dass ** Dropout ** oder ** Batch Normalization ** angeschlossen ist. (Vielleicht gibt es noch mehr.) Vielleicht können Sie dieses Modell auch ausprobieren.
h = F.relu(self.l1(x))
h = F.relu(self.l2(h))
h = self.l3(h)

――Dieser Prozess wird nur der Reihe nach zugewiesen. --X (Beispiel: Array von Bildern), das von self.l1 verarbeitet wird, wird von der Relu-Funktion verarbeitet und h zugewiesen.

  • Aktualisieren Sie h, indem Sie h verarbeiten, das von self.l2 mit relu-Funktion verarbeitet wurde. ... Ich fühle mich gesagt.

5.4.3 Definition des Trainers

In diesem Kapitel `` def create_trainer (Stapelgröße, Zug, Wert, Stopp, Gerät = -1): ` Definiert das Training für das Modell.

model = MultiLayerPerceptron(out_h=256, out_w=256)

Damit wird das zuvor erstellte Netzwerk dem Modell zugeordnet. Da das Eingabebild von "out_h = 256", "out_w = 256" 256 × 256 ist, stimmt es damit überein.

train_model = L.Classifier(
        model, lossfun=F.sigmoid_cross_entropy, accfun=F.binary_accuracy)
  • ** Über [L.classifier] **
  • Dies ist eine Verlustfunktion oder ein Netzwerk (allgemein definiertes Modell?) Soweit das Chainer-Dokument angezeigt wird. Ich wechsle zu einem Modell zur Berechnung der acc-Funktion (Modell im engeren Sinne?). ――Ist es das Bild, dass die Puppe die notwendigen Kleider trägt? ――Dieses Mal handelt es sich um eine binäre Klassifizierung, die jedes Pixel des Bildes, das den linken Ventrikel vorhersagt, als 1 und die anderen als 0 klassifiziert.
  • Also verwenden wir sigmoid_cross_entropy für die Verlustfunktion und binary_accuracy für die acc-Funktion.
  • (Für die Klassifizierung in mehreren Klassen würden Sie meiner Meinung nach die normale "Genauigkeit" anstelle von "softmax_cross_entoropy" für den Verlust und die "binäre Genauigkeit" für gem.
optimizer = optimizers.Adam()
optimizer.setup(train_model)
  • ** Über [optimaizer] ** ――Machen Sie so etwas wie das Ändern der Parameter während des Trainings. Diesmal verwenden Sie "Adam ()". Außerdem ist sgd () auch berühmt.

Für den Rest des Trainers können Sie wahrscheinlich sagen, was Sie tun, indem Sie die Kommentare lesen, die Zeile für Zeile hinzugefügt werden.

5.4.4 Lernen

%%time
trainer = create_trainer(64, train, val, (20, 'epoch'), device=0)
trainer.run()

--``` def create_trainer (Stapelgröße, Zug, Wert, Stopp, Gerät = -1): `` `der vorherigen Funktion Sie können sehen, was jeder Wert darstellt, indem Sie mit vergleichen. --64 Chargen, Training für Trainingsdaten, Validierungswert, Epochenstopp bei 20 und GPU oder CPU.

5.4.5. Bewertung

preds = []
for img, label in val:
    img = cuda.to_gpu(img[np.newaxis], device)
    pred = model(img)
    pred = cuda.to_cpu(pred.data[0, 0] > 0)
    preds.append((pred, label[0]))
pred_labels, gt_labels = zip(*preds)

――Das nächste, was ein Problem zu sein scheint, ist hier in `def evaluieren (Trainer, Wert, Gerät = -1):`. Der Songwriter kann `to_gpu``` oder` to_cpu``` sein. ――In Chainer muss unterschieden werden, ob das, was Sie gerade tun (sogar Pytorch usw.), auf GPU oder CPU ausgeführt wird.

  • Mit to_gpu wird das Bild, das das Material zum Lernen des Modells mit gpu ist, von cpu an gpu übergeben. (Ich denke) --to_cpu übergibt das Ergebnis auf gpu an cpu. (Ich denke)

Nach Kapitel 5.5

Die Elemente danach werden in der Faltungsschicht implementiert, aber abgesehen vom Verständnis von ** Kernel **, ** Schritt **, ** Pad ** usw. ist die Hauptlinie die obige vollständig verbundene Schicht. Ist dasselbe. (Um diese Punkte zu verstehen, lesen Sie bitte die entsprechende Website oder lesen Sie das Super-Major-Buch "Deep Learning von Grund auf neu".)

Experimentieren Sie und werden Sie ein Multi-Omics-Talent in der medizinischen Welt!

Verweise

  • 5. Übung: MRT-Bildsegmentierung

  • ** Alle Codes in diesem Artikel sind aus dem oben genannten Online-Kurscode der Medical AI Society zitiert. ** **. ――Es ist ein ** sehr informativer Kurs ** für diejenigen, die sich für tiefes Lernen in der medizinischen Versorgung sowie für das Thema des Datensatzes interessieren. Versuch es bitte.

  • Über Curl

  • Informationen zu Curl-Optionen

  • Chainer-Dokument --Buch "Deep Learning von Grund auf neu"

Schließlich

Ich dachte, ich wäre vorsichtig, aber ich denke, dass es wahrscheinlich viele falsche Beschreibungen gibt. Daher wäre es hilfreich, wenn Sie auf Fehler im Artikel hinweisen könnten.

Da die Entwicklung von Chainer eingestellt wurde, denke ich darüber nach, den obigen Code mit Pytorch neu zu schreiben, aber ich weiß nicht, ob ich es tun werde. Ich weiß auch nicht, ob ich es tun werde, weil es ziemlich schwierig war, ein Kapitel für andere Kapitel zu erstellen.

Dieser Beitrag basiert auf der akademischen Philosophie, "Forschung und Ausbildung im Bereich der medizinischen KI zu fördern und zur Entwicklung der modernen Medizin in Japan beizutragen", und soll denjenigen helfen, die gerade mit dem Programmieren begonnen haben. Dies ist eine Zusammenfassung dessen, was ich aus der Sicht einer erfahrenen Person mit wenig Erfahrung für notwendig hielt. Wir beanspruchen keine Rechte. Wenn Sie urheberrechtliche Probleme mit der Medical AI Society haben, kontaktieren Sie uns bitte.

Recommended Posts

Deep Learning-Anfänger versuchten, den Online-Kurs für medizinische KI so gut wie möglich zu verstehen [Kapitel 5]
Wie man für den Deep Learning Association G-Test (für Anfänger) lernt [Version 2020]
Anfängern gewidmet! Wie man mit so wenig Geld wie möglich das Programmieren lernt
Notieren Sie die Schritte zum Verständnis des maschinellen Lernens
Deep Learning von Grund auf neu ① Kapitel 6 "Lerntechniken"
[Pokemon-Schwertschild] Ich habe versucht, die Urteilsgrundlage des tiefen Lernens anhand der Drei-Familien-Klassifikation als Beispiel zu visualisieren