[PYTHON] Deep Learning macht es dramatisch einfacher, den Zeitraffer körperlicher Veränderungen zu erkennen

Einführung

"Selbstporträt (Körper)" ist eine Gewohnheit vieler Auszubildender (Menschen, die Muskeltraining lieben). Es ist eine glückselige Zeit, nach dem Training ein Foto des gepumpten Körpers zu machen und später darauf zurückzublicken. Wenn Sie das aufgenommene Bild in einer Animation wie im Zeitraffer anzeigen, können Sie außerdem feststellen, dass das Muskelwachstum besser ausgewählt werden kann! Dieser Artikel verwendet tiefes Lernen, um den Zeitraffer des Körpers dramatisch zu verbessern.

Zuerst aus dem Ergebnis

ezgif.com-optimize (3).gif Änderungen im Gremium von Dezember 2017 bis März 2020

Inhaltsverzeichnis

Überblick

Ich habe aus den aufgenommenen Bildern einen Zeitraffer erstellt. Ich war jedoch besorgt über die Lücke zwischen den Bildern und habe sie manuell korrigiert, um einen reibungslosen Zeitraffer zu erzielen. Um die Probleme der manuellen Arbeit zu vermeiden, wurde die Korrektur automatisch mithilfe von Deep Learning durchgeführt.

1. Manuelle Korrektur

1-1. Anzeige wie sie ist

Lassen Sie uns vorerst einen Zeitraffer erstellen, der das Bild so wechselt, wie es kontinuierlich ist.

Code zur Erstellung von Zeitraffern (Teil)



#Sie können Videos mit opencv machen,
#So erstellen Sie eine mp4-Datei, die in der Google Colab-Umgebung auf Zwietracht abgespielt werden kann
#Ich habe es genossen, Skvideo zu benutzen.
import skvideo.io

def create_video(imgs, out_video_path, size_wh):
  video = []
  vid_out = skvideo.io.FFmpegWriter(out_video_path,
      inputdict={
          "-r": "10"
      },
      outputdict={
          "-r": "10"
      })
  
  for img in imgs:
    img = cv2.resize(img, size_wh)
    vid_out.writeFrame(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))

  vid_out.close()

imgs = load_images("images_dir")
create_video(imgs,  "video.mp4", (w,h))

Das Ergebnis ist wie folgt.

ezgif.com-crop.gif

Ich mache mir Sorgen um die Lücke und kann mich nicht auf mein Kind (Körper) konzentrieren.

1-2. Fixieren der Position

Ich möchte diese Lücke irgendwie leicht schließen. Wenn ich irgendwo auf meinem Körper einen Referenzpunkt setze und ihn repariere, habe ich in etwa 0,1 Sekunden die Lösung von "Brustwarze" und "Nabel" gefunden. Hier erfahren Sie, wie Sie Ihre Brustwarzen und Ihren Nabel reparieren.

1-2-1. Nippel-Nabel-Koordinaten-Werkzeug

Erstellen Sie zunächst ein Werkzeug, das der Brustwarze und dem Nabel UV-Koordinaten gibt. Es mag möglich sein, es mithilfe von cvat usw. zu realisieren, aber als ich die Zeit für die Beherrschung und die Zeit für die Erstellung meines eigenen Werkzeugs schätzte, kam ich zu dem Schluss, dass es schneller ist, es selbst zu erstellen, also habe ich es erstellt.

Die Spezifikation des Werkzeugs ist, dass, wenn Sie einen Ordner angeben, die Bilder fortlaufend angezeigt werden. Klicken Sie also für jedes Bild auf die drei Punkte des Nippels und des Nabels, und die angeklickten Koordinaten werden in die CSV-Datei ausgegeben. Werden. Ich habe tkinter für die GUI verwendet (die Quelle ist abgekürzt).

1-2-2. Videoerstellung

Die Position der Brustwarze und des Nabels wird durch affine Umwandlung gemäß dem ersten Bild festgelegt.

Korrigierter Zeitraffer-Erstellungscode (Teil)


def p3affine_img(img, src_p, dst_p):
    h, w, ch = img.shape
    pts1 = np.float32([src_p[0],src_p[1],src_p[2]])
    pts2 = np.float32([dst_p[0],dst_p[1],dst_p[2]])
    M = cv2.getAffineTransform(pts1,pts2)
    dst = cv2.warpAffine(img,M,(h, w))
    return dst


df = read_annotationd() #Kürzung

imgs = []
src_p = None
for index, row in df.iterrows():
    img = cv2.imread(row.file)
    dst_p = [ [row.p1x, row.p1y], #Linke Brustwarze
              [row.p2x, row.p2y], #Rechter Nippel
              [row.p3x, row.p3y]] #Nabel
    if src_p is None:
      src_p = dst_p
    else:
      img = p3affine_img(img, dst_p, src_p)
    
    imgs.append(img)

write_video(imgs) #Kürzung

Die Ergebnisse sind wie folgt.

ezgif.com-optimize.gif

Ich konnte den erwarteten Zeitraffer machen, Glückwunsch. ** Nicht! ** ** **

Die Anzahl der Blätter, für die diesmal Koordinaten angegeben werden, beträgt 120 (Zeitraum vom 9. September 2019 bis März 2020). Ich habe jedoch immer noch 281 Bilder, die ich seit Dezember 2017 aufgenommen habe und denen keine Koordinaten zugewiesen wurden. Darüber hinaus müssen wir in den nächsten Jahrzehnten Muskeltraining durchführen, dh über Jahrzehnte hinweg weiterhin Koordinaten angeben. Selbst wenn man sich nur vorstellt, wird Cortisol ausgeschieden und fällt in den Stoffwechsel. Ich dachte darüber nach, Zucker zu ergänzen, um dies zu lösen.

Das stimmt ~~ Lass uns ins Fitnessstudio gehen ~~ Deep Learning.

2. Automatische Korrektur durch Deep Learning

Erstellen Sie ein Modell, das die Positionen der "Brustwarze" und des "Nabels" schätzt. Wenn dies erreicht ist, müssen Sie lediglich die Affin-Konvertierung wie zuvor anwenden. Wir betrachten die Erkennung von Brustwarzen und Nabel als Segmentierungsaufgabe. Die Erkennung von Schlüsselpunkten wie die Haltungsschätzung scheint besser zu sein, aber ich persönlich habe mehr Erfahrung mit Segmentierungsaufgaben, deshalb habe ich mich dafür entschieden.

Der Datensatz ist wie folgt. Da 2019/9 bis 2020/3 bereits Koordinaten zugewiesen wurden, werden diese für Trainingsbilder und Verifizierungsbilder verwendet, um automatisch Koordinaten für den verbleibenden Zeitraum zu erhalten.

image.png

2-1. Erstellen von Anmerkungsdaten

Es ist denkbar, durch 4 Klassifikationen von "rechter Nippel", "linker Nippel", "Nabel" und "Hintergrund" zu lösen, aber dieses Mal haben wir beschlossen, 2 Klassifikationen von "rechter Nippel, linker Nippel, Nabel" und "Hintergrund" zu verwenden. Ich dachte, es wäre einfach, sie auf Regelbasis zu klassifizieren, solange ich drei Punkte erkennen könnte. Lassen Sie uns nun ein Maskenbild erstellen. Machen Sie die Koordinatenpunkte basierend auf den zuvor erstellten Koordinatendaten etwas größer und füllen Sie sie mit 1. Ansonsten ist es der Hintergrund, setzen Sie ihn also auf 0.

for index, row in df.iterrows():
  file = row.file
  mask = np.zeros((img_h, img_w), dtype=np.uint8)
  mask = cv2.circle(mask,(row.p1x, row.p1y,), 15, (1), -1)
  mask = cv2.circle(mask,(row.p2x, row.p2y,), 15, (1), -1)
  mask = cv2.circle(mask,(row.p3x, row.p3y,), 15, (1), -1)
  save_img(mask, row.file) #Kürzung

Visuell (1 ist weiß, 0 ist schwarz) sind die Daten wie folgt.

image.png

Bilden Sie diese Paare mit dem physischen Bild.

2-2. Lernen

Zum Lernen habe ich DeepLab v3 (Torch Vision) verwendet. Die 120 Bilder wurden zur Schulung und Überprüfung im Verhältnis 8: 2 aufgeteilt. Obwohl die Anzahl der Blätter recht gering ist, haben wir die Daten aus folgenden Gründen nicht erweitert.

Ich denke jedoch, dass es besser ist, die Daten zu erweitern (es ist einfach nicht ärgerlich).

Datensatzklasse / lernbezogene Funktionen


class MaskDataset(Dataset):
  def __init__(self, imgs_dir, masks_dir, scale=1, transforms=None):
    self.imgs_dir = imgs_dir
    self.masks_dir = masks_dir

    self.imgs = list(sorted(glob.glob(os.path.join(imgs_dir, "*.jpg "))))
    self.msks = list(sorted(glob.glob(os.path.join(masks_dir, "*.png "))))
    self.transforms = transforms
    self.scale = scale

  def __len__(self):
      return len(self.imgs_dir)

  @classmethod
  def preprocess(cls, pil_img, scale):

    #Es sieht gut aus für Graustufen, aber es ist mühsam, also werde ich nicht
    # pil_img = pil_img.convert("L") 

    w, h = pil_img.size
    newW, newH = int(scale * w), int(scale * h)
    pil_img = pil_img.resize((newW, newH))

    img_nd = np.array(pil_img)

    if len(img_nd.shape) == 2:
      img_nd = np.expand_dims(img_nd, axis=2)

    # HWC to CHW
    img_trans = img_nd.transpose((2, 0, 1))
    if img_trans.max() > 1:
        img_trans = img_trans / 255

    return img_trans

  def __getitem__(self, i):
      
    mask_file = self.msks[i]
    img_file = self.imgs[i]

    mask = Image.open(mask_file)
    img = Image.open(img_file)

    img = self.preprocess(img, self.scale)
    mask = self.preprocess(mask, self.scale)

    item = {"image": torch.from_numpy(img), "mask": torch.from_numpy(mask)}
    if self.transforms:
      item = self.transforms(item)
    return item

from torchvision.models.segmentation.deeplabv3 import DeepLabHead

def create_deeplabv3(num_classes):
  model = models.segmentation.deeplabv3_resnet101(pretrained=True, progress=True)
  model.classifier = DeepLabHead(2048, num_classes)

  #Es sieht gut aus für Graustufen, aber es ist mühsam, also werde ich nicht
  #model.backbone.conv1 = nn.Conv2d(1, 64, kernel_size=7, stride=2, padding=3, bias=False)

  return model

def train_model(model, criterion, optimizer, dataloaders, device, num_epochs=25, print_freq=1):
  since = time.time()

  best_model_wts = copy.deepcopy(model.state_dict())
  best_loss = 1e15

  for epoch in range(num_epochs):
    print('Epoch {}/{}'.format(epoch+1, num_epochs))
    print('-' * 10)

    loss_history = {"train": [], "val": []}
    
    for phase in ["train", "val"]:
        
      if phase == "train":
        model.train()
      else:
        model.eval()

      for sample in tqdm(iter(dataloaders[phase])):
        imgs = sample["image"].to(device, dtype=torch.float)
        msks = sample["mask"].to(device, dtype=torch.float)

        optimizer.zero_grad()

        with torch.set_grad_enabled(phase == "train"):
          outputs = model(imgs)
          loss = criterion(outputs["out"], msks)

          if phase == "train":
            loss.backward()
            optimizer.step()

      epoch_loss = np.float(loss.data)
      if (epoch + 1) % print_freq == 0:
        print("Epoch: [%d/%d], Loss: %.4f" %(epoch+1, num_epochs, epoch_loss))
        loss_history[phase].append(epoch_loss)

      # deep copy the model
      if phase == "val" and epoch_loss < best_loss:
        best_loss = epoch_loss
        best_model_wts = copy.deepcopy(model.state_dict())

  time_elapsed = time.time() - since
  print("Training complete in {:.0f}m {:.0f}s".format(time_elapsed // 60, time_elapsed % 60))
  print("Best val Acc: {:4f}".format(best_loss))

  model.load_state_dict(best_model_wts)
  
  return model, loss_history

Ausführung lernen



dataset = MaskDataset("images_dir", "masks_dir", 0.5, transforms=None)

#Separat für Schulung und Überprüfung
val_percent= 0.2
batch_size=4
n_val = int(len(dataset) * val_percent)
n_train = len(dataset) - n_val
train, val = random_split(dataset, [n_train, n_val])
train_loader = DataLoader(train, batch_size=batch_size, shuffle=True, num_workers=8, pin_memory=True, drop_last=True )
val_loader = DataLoader(val, batch_size=batch_size, shuffle=False, num_workers=8, pin_memory=True, drop_last=True )

dataloaders = {"train": train_loader, "val": val_loader}

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

#Geben Sie bei Verwendung von BCEWithLogitsLoss 1 für die binäre Klassifizierung an
num_classes = 1 

model = create_deeplabv3(num_classes)

#Für vorgeübte
#model.load_state_dict(torch.load("model.pth"))

model.to(device)

#Da der Hintergrund überwiegend zahlreich ist, pos_Mit dem Gewicht einstellen
criterion = nn.BCEWithLogitsLoss(pos_weight=torch.tensor(10000.0).to(device))

params = [p for p in model.parameters() if p.requires_grad]

#optimizer = torch.optim.SGD(params, lr=0.005,momentum=0.9, weight_decay=0.0005)
optimizer = optim.Adam(params)

total_epoch = 50

model, loss_dict = train_model(model, criterion, optimizer, dataloaders, device, total_epoch)

Dieses Mal, als ich ungefähr 50 Epochen drehte, konvergierte das Lernen bis zu einem gewissen Grad.

2-3. Anwendung auf unbekannte Bilder

Als Ergebnis war es im Allgemeinen gut und 3 Punkte reagierten richtig, aber gelegentlich wurden auch die folgenden Ergebnisse erhalten (Wärmekartenausdruck).

image.png

Natürlich gibt es nie zwei linke Brustwarzen, daher ist der kleine Punkt oben rechts falsch positiv. Übrigens gab es kein falsches Negativ.

2-4 Nachbearbeitung

Aus dem obigen Inferenzergebnis ergibt die Nachbearbeitung Folgendes:

  1. Schneiden Sie den Ausgabewert jedes Pixels unterhalb des Schwellenwerts ab
  2. Teilen Sie das Objekt
  3. Wenn 4 oder mehr Cluster vorhanden sind, wählen Sie 3 in absteigender Reihenfolge der Fläche aus und verwerfen Sie den Rest.
  4. Finden Sie den Schwerpunkt jedes Clusters
  5. Sortieren Sie in aufsteigender x-Koordinate des Schwerpunkts jedes Clusters (rechter Nippel → Nabel → linker Nippel).

2-4-1. Abschneiden, wenn der Ausgabewert jedes Pixels unter dem Schwellenwert liegt

Schneiden Sie alle Pixel bis auf die Pixel mit klarer Sicherheit für den nächsten Schritt ab. Der Schwellenwert wird diesmal empirisch auf 0,995 festgelegt.

2-4-2. Teilen Sie das Objekt

Verwenden Sie cv2.connectedComponents für die Objektpartitionierung (Aufteilung in Cluster). Weitere Informationen finden Sie unter OpenCV - Beschriften verbundener Komponenten mit verbundenen Komponenten --pynote.

2-4-3. Wenn 4 oder mehr Cluster vorhanden sind, wählen Sie 3 in absteigender Reihenfolge der Fläche aus und verwerfen Sie den Rest.

Aus der Fallstudie ging hervor, dass der Bereich anderer falsch positiver Ergebnisse als Brustwarze und Nabel klein war. Daher werden wir drei mit einer großen Fläche auswählen. Eigentlich denke ich nicht, dass diese Art von Gegenmaßnahme sehr robust ist, aber diesmal hat es funktioniert, also werde ich es übernehmen.

2-4-4. Finden Sie den Schwerpunkt jedes Clusters

Verwenden Sie cv2.moments, um den Schwerpunkt jedes Clusters zu ermitteln. Weitere Informationen finden Sie unter Berechnung des Schwerpunkts mit Python + OpenCV - Einführung in die CV-Bildanalyse.

2-4-5. Sortieren Sie in aufsteigender x-Koordinate des Schwerpunkts jedes Clusters (rechter Nippel → Nabel → linker Nippel).

Da die Punkte bei der Konvertierung in affin übereinstimmen müssen, muss die Koordinatenreihenfolge von Brustwarze und Nabel zwischen den Bildern vereinheitlicht werden. Alle Bilder wurden diesmal aufrecht aufgenommen, und es besteht kein Zweifel, dass Brustwarzen → Nabel → Brustwarzen in Richtung der horizontalen Achse erscheinen. Sortieren Sie sie also einfach nach x-Koordinaten.

Zum Zeitpunkt der Folgerung



#3 Punkte von der Maske erkannt
def triangle_pt(heatmask, thresh=0.995):
  mask = heatmask.copy()

  # 2-4-1.Wenn der Ausgabewert jedes Pixels unter dem Schwellenwert liegt, wird er abgeschnitten.
  mask[mask>thresh] = 255
  mask[mask<=thresh] = 0
  mask = mask.astype(np.uint8)
  # 2-4-2.Objekt teilen
  nlabels, labels = cv2.connectedComponents(mask)

  pt = []
  if nlabels != 4:

    #Wenn weniger, nichts tun
    #Ich möchte die Schwelle wirklich senken, aber es ist ärgerlich
    if nlabels < 4:
      return None
    
    # 2-4-3.Wenn 4 oder mehr Cluster vorhanden sind, wählen Sie 3 in absteigender Reihenfolge der Fläche aus und verwerfen Sie den Rest
    elif nlabels > 4:
      sum_px = []
      for i in range(1, nlabels):
        sum_px.append((labels==i).sum())
      #Hintergrund+1
      indices = [ x+1 for x in np.argsort(-np.array(sum_px))[:3]]

  else:
    indices = [x for x in range(1, nlabels)]

  # 2-4-4.Finden Sie den Schwerpunkt jedes Clusters
  for i in indices:
    base = np.zeros_like(mask, dtype=np.uint8)
    base[labels==i] = 255
    mu = cv2.moments(base, False)
    x,y= int(mu["m10"]/mu["m00"]) , int(mu["m01"]/mu["m00"])
    pt.append([x,y])

  # 2-4-5.Sortieren Sie in aufsteigender x-Koordinate des Schwerpunkts jedes Clusters (rechter Nippel → Nabel → linker Nippel)
  sort_key = lambda v: v[0]
  pt.sort(key=sort_key)
  return np.array(pt)


def correct_img(model, device, in_dir, out_dir, 
                draw_heatmap=True, draw_triangle=True, correct=True):

  imgs = []

  base_3p = None
  model.eval()
  with torch.no_grad():
    imglist = sorted(glob.glob(os.path.join(in_dir, "*.jpg ")))
    
    for idx, img_path in enumerate(imglist):

      #Es ist ärgerlich, also Losgröße 1
      full_img = Image.open(img_path)
      img = torch.from_numpy(BasicDataset.preprocess(full_img, 0.5))
      img = img.unsqueeze(0)
      img = img.to(device=device, dtype=torch.float32)

      output = model(img)["out"]
      probs = torch.sigmoid(output)
      probs = probs.squeeze(0)

      tf = transforms.Compose(
                [
                    transforms.ToPILImage(),
                    transforms.Resize(full_img.size[0]),
                    transforms.ToTensor()
                ]
            )
      
      probs = tf(probs.cpu())
      full_mask = probs.squeeze().cpu().numpy()

      full_img = np.asarray(full_img).astype(np.uint8)
      full_img = cv2.cvtColor(full_img, cv2.COLOR_RGB2BGR)

      #Dreieck
      triangle = triangle_pt(full_mask)
      if draw_triangle and triangle is not None:
        cv2.drawContours(full_img, [triangle], 0, (0, 0, 255), 5)

      #Wärmekarte
      if draw_heatmap:
        full_mask = (full_mask*255).astype(np.uint8)
        jet = cv2.applyColorMap(full_mask, cv2.COLORMAP_JET)

        alpha = 0.7
        full_img = cv2.addWeighted(full_img, alpha, jet, 1 - alpha, 0)

      #Affin-Konvertierung
      if correct:
        if base_3p is None and triangle is not None:
          base_3p = triangle
        elif triangle is not None:
          full_img = p3affine_img(full_img, triangle, base_3p)

      if out_dir is not None:
        cv2.imwrite(os.path.join(out_dir, os.path.basename(img_path)), full_img)

      imgs.append(full_img)

  return imgs

imgs = correct_img(model, device,
                   "images_dir", None,
                    draw_heatmap=False, draw_triangle=False, correct=True)

2-5. Ergebnisse

Der Zeitraffer kurz vor der Korrektur ist wie folgt.

ezgif.com-optimize (1).gif

Der korrigierte Zeitraffer ist wie folgt.

ezgif.com-optimize (2).gif

Zusammenfassung

Durch Erkennen der Brustwarze und des Nabels mithilfe von Deep Learning und automatisches Korrigieren des Bildes ist der Zeitraffer erheblich leichter zu erkennen. Das hat mich weiter motiviert zu trainieren. Natürlich denken einige Leute vielleicht ** "Ist das mit einem so nicht tiefen Lebenslauf nicht möglich?" **, aber in meinem Fall würde ich gerne die Langhantel heben, wenn ich Zeit hätte, über die Regeln nachzudenken. Es fühlt sich an, als wäre es mit brutaler Gewalt gelöst worden. Die gesamte Entwicklung wurde mit Google Colab durchgeführt, mit Ausnahme des Koordinatenzuweisungstools 3150 Uu! Die Herausforderung ist

Cortisol wird jedoch ausgeschieden. Machen Sie sich also keine Sorgen, dass es zu schwer ist!

Lass uns ein lustiges Muskeltraining haben!

Recommended Posts

Deep Learning macht es dramatisch einfacher, den Zeitraffer körperlicher Veränderungen zu erkennen
Sie, die das Protokoll ausmalen, um es besser sehen zu können
Eine Geschichte, die das Debuggen von Modellen in der Django + SQLAlchemy-Umgebung einfacher macht
Othello-Aus der dritten Zeile von "Implementation Deep Learning" (3)
Visualisieren Sie die Auswirkungen von Deep Learning / Regularisierung
Ich habe die übliche Geschichte ausprobiert, Deep Learning zu verwenden, um den Nikkei-Durchschnitt vorherzusagen
Othello-Aus der dritten Zeile von "Implementation Deep Learning" (2)
Erstellen Sie eine Python-Umgebung, um die Theorie und Implementierung von Deep Learning zu erlernen
So installieren Sie das Deep Learning Framework Tensorflow 1.0 in der Windows Anaconda-Umgebung
Die Geschichte des tiefen Lernens mit TPU
Der Hintergrund der Zeichen im Textbild ist überbelichtet, um das Lesen zu erleichtern.
Zählen Sie die Anzahl der Parameter im Deep-Learning-Modell
Techniken zum Verständnis der Grundlagen von Deep-Learning-Entscheidungen
Othello ~ Aus der dritten Zeile von "Implementation Deep Learning" (4) [Ende]
[Deep Learning] Untersuchen Sie, wie jede Funktion des Faltungsnetzes verwendet wird [DW Tag 3]
Nach dem Bild des Shiba-Hundes zu urteilen, indem man tief lernt, ob es mein Kind ist (1)
Deep Learning 1 Übung des Deep Learning
[Teil 4] Verwenden Sie Deep Learning, um das Wetter anhand von Wetterbildern vorherzusagen
[Teil 1] Verwenden Sie Deep Learning, um das Wetter anhand von Wetterbildern vorherzusagen
Versuchen Sie, die Leistung des Modells für maschinelles Lernen / Regression zu bewerten
[Teil 3] Verwenden Sie Deep Learning, um das Wetter anhand von Wetterbildern vorherzusagen
Erleichtern Sie die Anzeige von Python-Modulausnahmen
Ein Liner, der JSON formatiert, um die Anzeige zu vereinfachen
Versuchen Sie, die Leistung des Modells für maschinelles Lernen / Klassifizierung zu bewerten
So erhöhen Sie die Anzahl der Datensatzbilder für maschinelles Lernen
Versuchen Sie, die Geschwindigkeit von Zeitraffervideos automatisch anzupassen (Teil 2).
[Teil 2] Verwenden Sie Deep Learning, um das Wetter anhand von Wetterbildern vorherzusagen
So sehen Sie den Inhalt der ipynb-Datei des Jupyter-Notizbuchs
[Maschinelles Lernen] Ich habe versucht, die Theorie von Adaboost zusammenzufassen
Ich habe das Toho-Projekt mit Deep Learning aufgenommen ... ich wollte.
Ich möchte die Legende der IT-Technologiewelt kennenlernen
Kapitel 1 Einführung in Python Schneiden Sie nur die guten Punkte des Deeplearning aus, die von Grund auf neu erstellt wurden
Das Deep Learning-Framework "CNTK" von Microsoft ist jetzt mit Python kompatibel, was die Verwendung erheblich vereinfacht