Tiefes Lernen mit Python Kapitel 2 (Material für runde Vorlesung)

Wird in [Do2dle 9. Lernsitzung (1. Deep Learning-Erfahrung mit Python)] verwendet (http://do2dle.connpass.com/event/41643/) Tiefes Lernen mit Python Dies ist ein Material für Kapitel 2 Rinko. Ich mache eine Ergänzung, aber ich versuche diesen Teil zu verstehen.


Die Entwicklung begann 1980 von Guido van Rossum. Python ist eine einfache und konsistente Programmiersprache. Lesbarkeit und Konsistenz sind in der Python-Community wichtig.

2.2 Python2 oder Python3

Python2-Serie und Python3-Serie sind nicht kompatibel. Wenn Sie Python neu starten möchten, ist das Python3-System in Ordnung. Der Python2-Code bleibt jedoch erhalten. Im Sinne des Erbes der Vergangenheit kann das Python 2-System nicht ignoriert werden. In diesem Buch wird unter der Annahme eines Python2-Systems beschrieben.

(Beginn der Kommentare des Moderators)

Python2-Serie

Die letzte Version (2.7) der Python2-Serie wurde eingestellt. Es werden keine größeren Korrekturen vorgenommen. Die Unterstützung für 2.7 wurde jedoch bis 2020 verlängert. Es scheint, dass die Situation, in der Python 2-Serie und Python 3-Serie gemischt sind, anhalten wird.

Python3-Serie

Die Python 3-Serie wurde 2008 veröffentlicht. Derzeit wird die Python 3-Serie aktiv entwickelt. Man kann sagen, dass die Hauptbibliotheken mit der Python 3-Serie kompatibel sind und es fast kein Problem gibt.

(Ende des Kommentars durch den Moderator)

2.4 Codierungsstil

Es lohnt sich, einen einheitlichen Codierungsstil und eine einheitliche Dokumentation zu hinterlassen, um die Lesbarkeit und Wartungsfreundlichkeit zu verbessern.

PEP8 ist berühmt für seinen Codierungsstil.

(Beginn der Kommentare des Moderators)

Werden Sie zum De-facto-Standard. Lesen wir PEP8.

PEP8 Japanische Übersetzung http://pep8-ja.readthedocs.io/ja/latest/

Verwenden Sie das PEP8-Prüftool Es kann mit pip install pep8 installiert werden. Lassen Sie uns automatisch mit dem Check-Tool überprüfen.

(Ende des Kommentars durch den Moderator)

2.5 Python- und NumPy-Abkürzung

2.5.2 Behälter

Container wie Listen, Wörterbücher, Sets und Taples sind in Python standardmäßig implementiert. Wenn Sie mehrere Elemente zu einem kombinieren, stehen Listen in Klammern [], Wörterbücher und Sätze in Klammern {} und Taples in regulären Klammern. Die Unterscheidung zwischen einem Wörterbuch und einer Menge ist ein Wörterbuch, wenn jedes Element ein Schlüssel ist und das Attributwertpaar aus einem Doppelpunkt besteht.

(Beginn der Kommentare des Moderators)

(Ende des Kommentars durch den Moderator)

2.5.5 NumPy NumPy ist die Kernbibliothek für Wissenschafts- und Technologieberechnungen in Python. Es besteht aus einem mehrdimensionalen Array-Objekt und einem Array-Verarbeitungswerkzeug. Wie später beschrieben wird, ist eine flexible Array-Manipulation für die Verarbeitung von Faltungs-Neuronalen Netzen wesentlich.

(Beginn der Kommentare des Moderators)

Warum NumPy verwenden?

  1. Die numerische Berechnung erfordert viel Verarbeitung, aber NumPy kann verwendet werden, um die Ausführungszeit zu beschleunigen. (Die Berechnung mit einer for-Schleife ist langsamer als mit einer Python-Liste. Daher ist es besser, sie so weit wie möglich in NumPy zu schließen.)
  2. Es ist möglich, zwischen Arrays unterschiedlicher Größe zu berechnen (Broadcast) Dies ermöglicht die einfache Durchführung komplizierter Berechnungen.

[5] Ausstrahlung

Broadcast ist ein Mechanismus, der Berechnungen zwischen Arrays unterschiedlicher Größe ermöglicht.

Im folgenden Beispiel 1 wird es beispielsweise durch Hinzufügen von 1 automatisch erweitert und als np.array ([1, 2]) + np.array ([1, 1]) behandelt.

#Beispiel 1
>>> import numpy as np
>>> np.array([1, 2]) + 1
array([2, 3])

In Beispiel 2 unten wird durch Hinzufügen von 5 automatisch np.array ([[1, 2], [3, 4]]) + np.array ([[5, 5], [5 ,, Es wird so behandelt, als ob 5]]) durchgeführt wurde.

#Beispiel 2
>>> import numpy as np
>>> np.array([[1, 2], [3, 4]]) + 5
array([[6, 7],
       [8, 9]])

In Beispiel 3 unten wird durch Hinzufügen von np.array ([2, 3]) automatisch np.array ([[1, 2], [3, 4]]) + np.array ([ Es wird so behandelt, als ob [2, 3], [2, 3]]) durchgeführt wurde.

#Beispiel 3
>>> import numpy as np
>>> np.array([[1, 2], [3, 4]]) + np.array([2, 3])
array([[3, 5],
       [5, 7]])

(Ende des Kommentars durch den Moderator)

2.6 Deep Learning Framework mit Python

2.6.1 Caffe Caffe ist ein Deep-Learning-Verarbeitungssystem, das in C ++ und CUDA geschrieben wurde. Verfügbar in Python, C ++ und MATLAB.

Caffe stellt trainierte Modelle zur Verfügung, und die Caffe-Community teilt die trainierten Parameterdateien mit dem Zoomodell (Model Zoo). Lernmodelle wie AlexNet, GoogLeNet, VGG, SPP sind verfügbar. Sie können die Ergebnisse des Deep Learning mithilfe des erlernten Kaffeemodells testen (die Dateinamenerweiterung des Zoomodells lautet .caffe model).

[1] Betriebsverfahren

  1. Sammeln Sie Daten.
  2. Berechnen und speichern Sie den Durchschnitt der Daten
  3. Klassifizieren Sie die Bilder.
  4. Beobachten Sie den Lernprozess nach Bedarf.

2.6.2 Theano In diesem Abschnitt werden die wichtigsten Punkte zum Verständnis des Theano-Codes beschrieben. Auf Theano basierende Pakete umfassen Blocks, Deepy, Keras, Lasagne, Nolearn, Pylearn2.

(Beginn der Kommentare des Moderators)

Theano ist eine Bibliothek zur numerischen Berechnung in Python. Sie bietet Funktionen zum Ausführen von Matrixoperationen usw. und kann als alternatives Paket zu numpy / scipy angesehen werden.

Das große Merkmal ist

  1. Generieren und Kompilieren von C ++ - Code zur Laufzeit
  2. GPU-Unterstützung
  3. Unterstützung der analytischen Differenzierung (x ^ 2 Differenzierung = 2x wird automatisch durchgeführt)

Dies führt zu Benchmarks mit Multilayer Perceptron, bei denen> Theano 1,8-mal schneller als Numpy und 1,6-mal schneller als Matlab ist.> (Natürlich ist der Geschwindigkeitsunterschied von Fall zu Fall). Zitiert aus http://d.hatena.ne.jp/saket/20121207/1354867911

Die Lesung ist Theano.

(Ende des Kommentars durch den Moderator)

[1] Das Verarbeitungsverfahren

  1. Definieren Sie eine Kopplungskoeffizientenmatrix als gemeinsame Variable von Theano.
  2. Beschreiben Sie die Konvertierungsfunktion für jede Ebene.
  3. Definieren Sie den Gradienten mit der automatischen Differenzierungsfunktion.
  4. Drücken Sie die Abhängigkeit jeder Variablen mit thano.function aus.

(Beginn der Kommentare des Moderators)

[2] Tensolvariable

Tensolvariablen definieren den Variablentyp, indem sie die Reihenfolge (Dimension) und den Typ des Elements kombinieren.

Siehe unten für Details zum Typ

http://deeplearning.net/software/theano/library/tensor/basic.html#libdoc-basic-tensor

(Ende des Kommentars durch den Moderator)

Die Anzahl der Arten von Tensorvariablen wird bis zur 4. Ordnung definiert. In Anbetracht der Bildverarbeitung ist ein Bild ein dreidimensionales Array (vertikales und horizontales Pixel-Zweidimensionalbild und Farbkanal kubisch). Für die Bilderkennung sind mehrere Trainingsbilder erforderlich. In Anbetracht der Anzahl der in diesem Fall verwendeten Bilder als eine Dimension ist ein vierdimensionales Array erforderlich. Die Zwischenschichtverarbeitung beim Tiefenlernen entspricht der Umwandlung eines vierdimensionalen Arrays in jede Schicht, um eine endgültige Erkennung zu erhalten. Daher kann gesagt werden, dass der Fluss jeder Schicht beim tiefen Lernen darin besteht, die Tensorvariable für jede Schicht zu verarbeiten. Aus diesem Grund hat Google wahrscheinlich sein maschinelles Lernpaket TensorFlow genannt.

[3] Funktion als Funktion

Theano.function, die Funktion in Theano, unterscheidet sich von der Funktion in der klassischen Sprache. Häufig verwendete Funktionen sind auch in Theano verfügbar. Diese Funktionen und die Funktion sind unterschiedlich. thano.function bezieht sich auf eine Operation, die die Beziehung zwischen der durch das erste Argument angegebenen Eingabevariablen und der durch das zweite Argument angegebenen Ausgabevariablen aus den definierten Variablen und den Diagrammverbindungsbeziehungen kompiliert.

Wenn die Funktion "Funktion" ausgewertet wird, tritt eine leichte Verzögerung bei der Ausführung der Funktion "Funktion" auf. Dies liegt daran, dass die Anweisung von theano.function in C-Code konvertiert und kompiliert wird.

[4] Automatische Differenzierung theano.grad

(Beginn der Kommentare des Moderators)

Eines der Hauptmerkmale von Theano ist diese Differenzierungsfunktion. Sie können "die Formel analysieren, um die differenzierte Formel zu finden", die als automatische Differenzierung bezeichnet wird. Zum Beispiel

x, y = T.dscalars("x", "y") #Wie schreibe ich, um alle zusammen zu deklarieren
z = (x+2*y)**2

Wenn Sie die Formel in Bezug auf x differenzieren, erhalten Sie dz / dx = 2 (x + 2 * y).

gx = T.grad(z, x)

Sie können den Ausdruck mit konvertieren. Zur Differenzierung in Bezug auf y ist dz / dy = 4 (x + 2 * y), aber gy = T.grad(z, y) Sie können den Ausdruck mit konvertieren. Wenn der Wert tatsächlich gefunden wird, muss er noch funktionalisiert werden.

fgy = theano.function([x,y], gy)
>>> fgy(1,2)
array(20.0)

Und so weiter. Zitiert aus http://qiita.com/mokemokechicken/items/3fbf6af714c1f66f99e9

(Ende des Kommentars durch den Moderator)

2.6.3 Chainer Es ist ersichtlich, dass Chainer eine ausgezeichnete Lesbarkeit des Quellcodes aufweist und die Fähigkeit des Erstellers hoch ist. Die Handbücher und Tutorials sind ebenfalls kurz und übersichtlich.

(Beginn der Kommentare des Moderators)

Warum jetzt ein neues Framework?

Caffe, Theano / Pylearn2 und Torch7 sind drei beliebte Deep Learning-Frameworks. Diese werden mit dem grundlegenden Ziel entwickelt, ein Feedforward-Netzwerk zu schreiben. Mit den jüngsten Fortschritten des Deep Learning steigt jedoch die Notwendigkeit, komplexere Netzwerke flexibel schreiben zu können. Daher wird nach vielen neuen Frameworks gesucht, die auf Theano basieren, das den höchsten Freiheitsgrad aufweist (z. B. Blöcke, Keras, Lasagne, Deepy usw.).

Die meisten vorhandenen Implementierungen, einschließlich dieser Frameworks, verfolgen den Ansatz, die Struktur des gesamten neuronalen Netzes im Speicher einmal zu erweitern, die Verarbeitung in der richtigen Reihenfolge zu betrachten und die Vorwärts- und Rückwärtsausbreitung so wie sie ist durchzuführen. Ich bin. Es ist wie die Implementierung eines Dolmetschers für Ihre eigene Minisprache. Im Fall von Caffe entspricht beispielsweise das im Protokollpuffer definierte Schema der Minisprache. Im Fall von Torch7 fungiert ein spezielles Modul, das als Container bezeichnet wird, als Kontrollstruktur. Theano ist flexibler zu definieren, verwendet jedoch eine spezielle Funktion namens Scan, um Schleifen zu schreiben. Wenn Sie bei diesem Ansatz einen komplizierteren Berechnungsablauf unterstützen möchten, müssen Sie diese Minisprache grundsätzlich erweitern, und die Lern- und Schreibkosten steigen. Grundsätzlich ist diese Entwicklung angesichts der Tatsache, dass die Struktur des neuronalen Netzes in Zukunft komplizierter wird, nicht vorzuziehen.

Chainer verfolgt einen anderen Ansatz. Es basiert auf Python, verwendet jedoch kein Theano. Alle Kontrollstrukturen können wie in Python verwendet werden. Chainer merkt sich nur, welche Verarbeitung tatsächlich mit Python-Code auf das Eingabearray angewendet wurde, und verwendet sie, um eine Fehler-Backpropagation durchzuführen. Wir glauben, dass dieser Ansatz notwendig ist, um die Geschwindigkeit der Forschung und Entwicklung von Deep Learning immer komplexer zu gestalten, und deshalb haben wir mit der Entwicklung eines neuen Rahmens begonnen.

Zitiert aus https://research.preferred.jp/2015/06/deep-learning-chainer/

(Ende des Kommentars durch den Moderator)

[1] Überblick über die Chainer-Verarbeitung

  1. Definieren Sie die Kette mit Link.
  2. Stellen Sie Chain auf Optimizer
  3. Definieren Sie die Vorwärtsfunktion
  4. Lesen Sie den Datensatz und trennen Sie ihn für Schulung und Auswertung.
  5. Drehen Sie die Trainingsschleife.
  6. Führen Sie die Auswertungsschleife mit einer angemessenen Häufigkeit aus.

Daher wird angenommen, dass das Lernen des Standard-Neuronalen Netzwerks gehorsam implementiert wird.

Es gibt eine Variable Chainer.Variable für Chainer. Im Vergleich zu Theano

>>> import chainer
>>> import theano
>>> import numpy as np
>>> X = np.ndarray((3, 5))
>>> x_chainer = chainer.Variable(X)
>>> x_theano = theano.tensor.dmatrix()

>>> print(x_chainer.label)
(3, 5), float32
>>> print(x_theano.type)
TensorType(float3, matrix)

Das obige Beispiel dient zum Vergleich und es ist nicht praktisch, Chainer und Theano gleichzeitig zu verwenden.

[3] Link und Kette

(Beginn der Kommentare des Moderators)

Viele neuronale Netzstrukturen enthalten mehrere Verbindungen. Beispielsweise besteht ein mehrschichtiges Perzeptron aus mehreren linearen Schichten. Durch die Kombination mehrerer Links kann diese komplexe Prozedur durch Parameter beschrieben werden.

l1 = L.Linear(4, 3)
l2 = L.Linear(3, 2)
def my_forward(x):
    h = l1(x)
    return l2(h)

Wobei L das chainer.links-Modul ist. Wenn der Verarbeitungsvorgang auf diese Weise durch Parameter definiert wird, ist eine Wiederverwendung schwierig. Eine Python-ähnliche Methode besteht darin, Links und Prozeduren in Klassen zu gruppieren:

 class MyProc(object):
     def __init__(self):
         self.l1 = L.Linear(4, 3)
         self.l2 = L.Linear(3, 2)

     def forward(self, x):
         h = self.l1(x)
         return self.l2(h)

Um die Wiederverwendung zu vereinfachen, benötigen wir Funktionen wie Parameterverwaltung, Unterstützung der CPU- / GPU-Migration sowie robustes und flexibles Speichern / Laden. Alle diese Funktionen werden von der Chainer-Chain-Klasse unterstützt. Um die Funktionen der Chain-Klasse zu nutzen, definieren Sie die obige Klasse einfach als Unterklasse der Chain-Klasse:

 class MyChain(Chain):
     def __init__(self):
         super(MyChain, self).__init__(
             l1=L.Linear(4, 3),
             l2=L.Linear(3, 2),
         )

     def __call__(self, x):
         h = self.l1(x)
         return self.l2(h)

Zeigt an, ob komplexere Verbindungen mit einfacheren Links erstellt werden. Links wie l1 und l2 werden als untergeordnete Links von MyChain bezeichnet. Die Kette selbst erbt Link. Das heißt, Sie können komplexere Verbindungen mit dem MyChain-Objekt als untergeordneten Link definieren.

Optimierungen werden von der Optimizer-Klasse vorgenommen, um gute Parameterwerte zu erhalten. Optimizer führt den numerischen Optimierungsalgorithmus aus, der Link zugewiesen wurde. Viele Algorithmen sind im Optimierungsmodul implementiert. Verwenden wir hier die einfachste, die stochastische Gradientenabstiegsmethode:

 model = MyChain()
 optimizer = optimizers.SGD()
 optimizer.setup(model)

Zitiert aus http://www.iandprogram.net/entry/chainer_japanese

(Ende des Kommentars durch den Moderator)

2.6.5 Tensorflow Die Punkte sind Sitzungsverwaltung (Checkpoints usw.) und Tensorboard.

In TensorFlow wird der Speicherbereich, den das neuronale Netzwerk schätzen sollte, als Variable (tensorflow.Variable) bezeichnet, und der Speicherbereich, der nicht geschätzt werden muss, wird als Platzhalter (tensorflow.placeholder) bezeichnet. Daher ist das Eingabebild ein Platzhalter. Andererseits sind der Kopplungskoeffizient (Matrix) und die Vorspannung (Vektor) Variablen. In Theanos Handbuch wurden Platzhalter und Variablen ohne Unterschied verwendet. Das Definieren und Verwalten von Variablen ist bei Theano und Chainer üblich.

2.6.7 scikit-learn Im Gegensatz zu den anderen in diesem Buch behandelten Frameworks gibt es Scikit-Learn als Python-Implementierung der Maschinenbewertung. Es scheint, dass Scikit-Learn auch ein mehrschichtiges Perzeptron hat. Die Einführung von mehrschichtigem Perzeptron ist jedoch scikit-learn 0.18. Es ist nicht in der stabilen Version 0.17 ab Februar 2016 enthalten.

(Beginn der Kommentare des Moderators)

0.18.0 wurde im September 2016 veröffentlicht und enthält ein mehrschichtiges Perzeptron.

http://scikit-learn.org/stable/modules/neural_networks_supervised.html#multilayer-perceptron

(Ende des Kommentars durch den Moderator)

Die Verwendung von Scikit-Learn erleichtert den Vergleich mit vorhandenen Algorithmen für maschinelles Lernen, nicht nur mit neuronalen Netzen.

(Beginn der Kommentare des Moderators)

Was ich oben sagen möchte, ist, dass beim Scicit-Learn die Schnittstelle unabhängig vom Algorithmus angeordnet ist, wie im folgenden Code gezeigt. Dies hat scicit-learn getan, was bedeutet, dass die folgende Beschreibung leicht gemacht und die Algorithmen leicht verglichen werden können.

for name, estimator in ESTIMATORS.items():
    estimator.fit(X_train, y_train)
    y_test_predict[name] = estimator.predict(X_test)

Zitiert aus http://scikit-learn.org/stable/auto_examples/plot_multioutput_face_completion.html (Ende des Kommentars durch den Moderator)

Sie müssen Ihre eigene Anpassung (X, y) vornehmen und (X) vorhersagen, um Ihren eigenen Algorithmus mit den von scicit-learn verfügbaren zu vergleichen.


Referenz Tiefes Lernen mit Python Kapitel 1 (Material für runde Vorlesung) http://qiita.com/taki_tflare/items/c1bfd976155d89104e3d

Recommended Posts

Tiefes Lernen mit Python Kapitel 2 (Material für runde Vorlesung)
Web-Lehrmaterialien zum Erlernen von Python
Python Deep Learning
Deep Learning × Python
Python: Tiefes Lernen in der Verarbeitung natürlicher Sprache: Grundlagen
[Implementierung zum Lernen] Implementieren Sie Stratified Sampling in Python (1)
Erstes tiefes Lernen in C # - Einführung in Python implementieren-
Python: Deep Learning-Praxis
Python: Deep Learning Tuning
Erstellen Sie mit Python eine interaktive Umgebung für maschinelles Lernen
Lernablauf für Python-Anfänger
Python-Lernplan für KI-Lernen
Techniken zum Sortieren in Python
Python für die Datenanalyse Kapitel 2
Checkios Empfehlung zum Erlernen von Python
Über "für _ in range ():" von Python
Python für die Datenanalyse Kapitel 3
Tipps zum Umgang mit Eingaben variabler Länge im Deep Learning Framework
Japanische Übersetzung der öffentlichen Unterrichtsmaterialien des Deep Learning Nano Degree
Ein Amateur stolperte in Deep Learning von Grund auf neu Hinweis: Kapitel 3
Ein Amateur stolperte in Deep Learning von Grund auf neu. Hinweis: Kapitel 7
Ein Amateur stolperte in Deep Learning von Grund auf neu Hinweis: Kapitel 5
Ein Amateur stolperte in Deep Learning von Grund auf neu Hinweis: Kapitel 4
Ein Amateur stolperte in Deep Learning von Grund auf neu Hinweis: Kapitel 2
Implementieren Sie das Stacking-Lernen in Python [Kaggle]
Deep Learning / Deep Learning von Grund auf neu 2 Kapitel 4 Memo
Lernverlauf für die Teilnahme an der Team-App-Entwicklung mit Python ~ Django Tutorial 5 ~
Deep Learning / Deep Learning von Grund auf neu Kapitel 3 Memo
Suchen Sie mit Python nach externen Befehlen
Lernverlauf für die Teilnahme an der Entwicklung von Team-Apps in Python ~ Indexseite ~
Lernverlauf für die Teilnahme an der Entwicklung von Team-Apps mit Python ~ Django Tutorial 4 ~
Wie wäre es mit Anaconda zum Erstellen einer maschinellen Lernumgebung mit Python?
100 Sprachverarbeitung Knock Kapitel 1 in Python
Python-Lernnotiz für maschinelles Lernen von Chainer Kapitel 8 Einführung in Numpy
Python-Lernnotiz für maschinelles Lernen von Chainer Kapitel 10 Einführung in Cupy
Python-Spickzettel (für C ++ erfahren)
<Für Anfänger> Python-Bibliothek <Für maschinelles Lernen>
Lernverlauf für die Teilnahme an der Team-App-Entwicklung mit Python ~ Django Tutorial 6 ~
Deep Learning / Deep Learning von Null 2 Kapitel 7 Memo
Python: Vorverarbeitung beim maschinellen Lernen: Übersicht
Deep Learning / Deep Learning von Null 2 Kapitel 8 Memo
Multi Layer Perceptron für Deep Learning (Deep Learning mit Python; MPS Yokohama Deep Learning Series)
Implementierte Perceptron-Lernregeln in Python
Deep Learning / Deep Learning von Grund auf neu Kapitel 5 Memo
Deep Learning / Deep Learning von Grund auf neu Kapitel 4 Memo
Deep Learning / Deep Learning von Grund auf neu 2 Kapitel 3 Memo
Python-Lernnotiz für maschinelles Lernen von Chainer Kapitel 9 Einführung in das Scikit-Lernen
Führen Sie unittest in Python aus (für Anfänger)
Deep Learning / Deep Learning von Null 2 Kapitel 6 Memo
[AI] Deep Learning für das Entrauschen von Bildern
(Python) Deep Learning Library Chainer-Grundlagen Grundlagen
Python-Lernnotiz für maschinelles Lernen von Chainer Kapitel 13 Training für neuronale Netze ~ Chainer abgeschlossen
Umgang mit Python-Fehler "Attributfehler: module'scipy.misc 'hat kein Attribut'imresize'" beim Deep Learning
Python vs Ruby "Deep Learning von Grund auf neu" Kapitel 2 Logikschaltung von Perceptron
Erstellen Sie schnell eine Python-Umgebung für Deep Learning / Data Science (Windows)
Python-Lernnotiz für maschinelles Lernen von Chainer Kapitel 13 Grundlagen des neuronalen Netzwerks
Python-Lernnotiz für maschinelles Lernen von Chainer bis zum Ende von Kapitel 2
Deep Learning von Grund auf neu - Kapitel 4 Tipps für die in Python erlernte Theorie und Implementierung von Deep Learning
Python vs Ruby "Deep Learning von Grund auf neu" Kapitel 4 Implementierung der Verlustfunktion
Spiralbuch in Python! Python mit einem Spiralbuch! (Kapitel 14 ~)