Forum: PC-Programmierung Classifier (AI, KI) - wer hat so etwas schon mal versucht?


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Marie M. (capiman)


Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich habe ein Array aus etwa 100 Zahlen.
Zu jedem Datensatz habe ich einen Wert ja/nein.
Aktuell habe ich 10.000 solcher Datensätze,
wobei nur etwa 500 den Fall nein liefern, 9500 den Fall ja.

Ich möchte nun mit einem Classifier lernen und versuchen,
bei einem neuen Datensatz ja/nein "vorauszusagen".

Hat jemand so etwas schon mal gemacht? Ich habe C/C++ zur Verfügung,
aber mittlerweile auch mal Python installiert.
Betriebssystem ist mir egal, Windows oder Linux.
Erste Schritte mit pyTorch/scikit-learn, bin mir aber aktuell weder
sicher, ob ich in die richtige Richtung forsche,
noch ob mein obiges Problem eine Chance hat,
damit (oder überhaupt) gelöst zu werden...

Freue mich auf Feedback!

Schöne Grüße,
Marie

von Marie M. (capiman)


Bewertung
0 lesenswert
nicht lesenswert
Beispiel, was vielleicht als Start passen könnte:

https://pythonbasics.org/machine-learning-classifier/

: Bearbeitet durch User
von Ergo70 (Gast)


Bewertung
1 lesenswert
nicht lesenswert
Für Ja/nein würde ich mit einer SVM oder einem decision tree anfangen. 
Das reicht für sowas üblicherweise und man kann auch noch gut 
nachvollziehen, was da passiert. Dafür gibt es auch genug Tutorials...

von Ergo70 (Gast)


Bewertung
1 lesenswert
nicht lesenswert
Oder auch Logistic Regression

von was (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Ich kann Deep Learning Studio empfehlen um sowas schnell mal 
auszuprobieren.

Einfach mal 200 Samples aus beiden Kategorien gegen ein 1-3 FC-Layer 
tiefes NN werfen und schauen ob was sinnvolles dabei rauskommt.

von Marie M. (capiman)


Bewertung
0 lesenswert
nicht lesenswert
Ich hänge leider immer noch fest und weiß noch nicht so genau,
wo ich anfangen soll...
Ich hab es mittlerweile geschafft, dass ich eine *.csv Datei einlesen 
kann.
Ich habe außerdem ein Beispiel gefunden, welches
SGD (=Stochastic Gradient Descent) verwendet.
Zum einen hab ich die Funktionsweise des Beispiels noch nicht 
verstanden, zum anderen weiß ich nicht, wie ich meine eingelesenen 
Dateien so umwandeln kann, dass diese für SGD verwendet werden können.

Meine CSV haben folgenden Aufbau:

Comment,yes-144/no-144,...100 Zahlen...

als z.B.

PartialSolution-0,yes-144,211,1652,1861,...

Ich kann die Eingangsdaten beliebig umformatieren.
Comment kann man ignorieren. yes-144 oder no-144 ist das Ergebnis des 
Classifiers. Ich möchte dieses aus den 100 gegebenen Zahlen 
herausfinden.

Was ist X und Y im Beispiel genau?
X meine Eingabe-Daten? Y meine Ausgabe-Daten?
Ich kann yes-144/no-144 ohne Probleme auf 0/1 umformatieren, wenn es 
etwas hilft.
Wie findet die Zuordnung von den Eingabedaten auf die Ausgabedaten 
statt?

Brauche ich randperm und perm, weil ich ja eigentlich keinen Zufall 
haben will, sondern ganz gezielt auf meinen Eingabedaten arbeiten will?
# -*- coding: utf-8 -*-

import argparse

import numpy as np
import torch
import torch.nn as nn
import torch.optim as optim

from numpy import genfromtxt

# https://numpy.org/doc/stable/reference/generated/numpy.loadtxt.html
# https://stackoverflow.com/questions/3518778/how-do-i-read-csv-data-into-a-record-array-in-numpy
# https://gist.github.com/blaylockbk/55b5b98269a4f1a413f6b4e676261fa6
# https://pytorch.org/docs/stable/optim.html
# https://pytorch.org/docs/stable/nn.html

# print(my_data2[0][1])

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    # parser.add_argument("--c", type=float, default=0.01)
    parser.add_argument("--lr", type=float, default=0.1)
    # parser.add_argument("--batchsize", type=int, default=5)
    parser.add_argument("--epoch", type=int, default=10)
    parser.add_argument("--device", default="cuda", choices=["cpu", "cuda"])
    args = parser.parse_args()
    args.device = torch.device(args.device if torch.cuda.is_available() else "cpu")
    
    print(args)

    my_data2 = genfromtxt('test.csv',delimiter=',', dtype=None, encoding='UTF-8')
    
    // Hier fehlt noch etwas!!!

    X = [2,4,7,9,11]
    Y = [0,1]
  
    batchsize = 5
    c = 0.01
  
    # X = (X - X.mean()) / X.std()
    # Y[np.where(Y == 0)] = -1

    # 2 scheint die Groesse des Output-Vektors zu sein
    # 2 muss mit Groesse Y uebereinstimmen
    model = nn.Linear(2, 1)
    # model = nn.Linear(3, 1)
    model.to(args.device)

    # train(X, Y, model, args)
    # visualize(X, Y, model)
  
    X = torch.FloatTensor(X)
    Y = torch.FloatTensor(Y)
    N = len(Y)

    # SGD = Stochastic Gradient Descent
    optimizer = optim.SGD(model.parameters(), lr=args.lr)

    model.train()
    for epoch in range(args.epoch):
        perm = torch.randperm(N)
        sum_loss = 0

        for i in range(0, N, batchsize):
            x = X[perm[i : i + batchsize]].to(args.device)
            y = Y[perm[i : i + batchsize]].to(args.device)

            optimizer.zero_grad()
            output = model(x).squeeze()
            weight = model.weight.squeeze()

            loss = torch.mean(torch.clamp(1 - y * output, min=0))
            loss += c * (weight.t() @ weight) / 2.0

            loss.backward()
            optimizer.step()

            sum_loss += float(loss)

        print("Epoch: {:4d}\tloss: {}".format(epoch, sum_loss / N))

: Bearbeitet durch User
von Marie M. (capiman)


Bewertung
0 lesenswert
nicht lesenswert
was schrieb:
> Ich kann Deep Learning Studio empfehlen um sowas schnell mal
> auszuprobieren.

Deep Learning Studio hat mir leider nicht geholfen. Scheinbar gehen 
Bilder als Eingabedaten, der Support konnte mir aber auch nach Wochen 
des Wartens nicht so richtig erklären, wie man Zahlen einfüttern kann.

von was (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Marie M. schrieb:
> der Support konnte mir aber auch nach Wochen
> des Wartens nicht so richtig erklären, wie man Zahlen einfüttern kann.

Na, bei Freeware kann man keinen guten Support erwarten. Braucht man 
aber auch nicht.



Dein Problem verstehe ich aber nicht.

Marie M. schrieb:
> Deep Learning Studio hat mir leider nicht geholfen. Scheinbar gehen
> Bilder als Eingabedaten,

Schau dir ein(e) Tutorial(-reihe) dazu an, neben "Image" gibt es als 
Data Type da natürlich auch z.B. "numeric" oder "categorical"

von Ingo E. (ogni42)


Bewertung
0 lesenswert
nicht lesenswert
Die Aufggabe läßt sich am Einfachsten mit python, pandas und 
scikit-learn oder, falls Du es grafisch haben möchtest, mit KNIME (oder 
RapidMiner, den kenne ich aber nicht) lösen.

Damit wir Dir hier weiter helfen können, solltest Du uns zuerst mal 
Deine Eingabedaten genauer beschreiben. Am Besten, falls das möglich 
ist, eine csv Datei mal an einen Post anhängen.

Wie von Vorpostern schon gesagt, ist Logistische Regression oder ein 
Entscheidungsbaum/Random Forest, ein guter Start. Neuronale Netze und 
svc würde ich erst mal außen vor lassen. Dazu sind Deine Klassen zu 
ungleichmäßig verteilt und Du müsstest mehr Aufwand in die 
Datenaufbereitung stecken, damit das gut funktioniert.

Torch und Keras sind für Dein Problem overkill. Du musst erst mal 
vernünftig aufbereitete Daten für einen Test/Trainingsdatensatz 
bekommen.

von Peter D. (peda)


Bewertung
1 lesenswert
nicht lesenswert
Ingo E. schrieb:
> Damit wir Dir hier weiter helfen können, solltest Du uns zuerst mal
> Deine Eingabedaten genauer beschreiben.

Ich denke auch, man muß wissen, was an den Zahlen das Kriterium ist. 
Software ist nämlich strunzdumm.
Z.B. sollte mal ein Algorithmus auf Fotos erkennen, was ein Schiff ist. 
Die Ergebnisse waren sehr ungenau. Eine Analyse ergab dann, der 
Algorithmus hatte danach gefiltert, ob das Objekt sich auf Wasser 
befindet.

von Marie M. (capiman)


Bewertung
0 lesenswert
nicht lesenswert
Testdaten können hier abgerufen werden:

http://guest.engelschall.com/~martin/e2_partial_field_100_and_3_fields_filled.html

Wenn das Format der Testdaten so nicht passend ist,
kann ich diese auch in einem beliebig anderen Format zur Verfügung 
stellen.

Ich hab bisher keine Ahnung, ob man aus den Zahlen etwas herauslesen 
kann. Ich kann es aktuell nicht und möchte daher einen Versuch starten.

: Bearbeitet durch User
von Dussel (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Peter D. schrieb:
> Eine Analyse ergab dann, der Algorithmus hatte
> danach gefiltert, ob das Objekt sich auf Wasser befindet.
Angeblich wollte mal jemand eine Bilderkennung trainieren, russische 
Panzer von Panzern der USA zu unterscheiden. Das Ergebnis war eine 
Bilderkennung, die dreckige von sauberen Panzern unterscheiden konnte, 
weil in den USA darauf geachtet wurde, dass die Panzer sauber sind, 
während das den Russen egal war.
Nachgeprüft habe ich die Geschichte aber nicht.

Kurz: Es kommt auf die Trainingsdaten an. Die müssen passen. Deshalb 
nimmt man oft einen Teil der Daten für das Training und einen anderen 
Teil zur Überprüfung.
Das kommt aber erst, wenn man es erstmal geschafft hat, ein 
trainingsfähiges System aufzubauen

von Ingo E. (ogni42)


Bewertung
0 lesenswert
nicht lesenswert
Marie M. schrieb:
> Testdaten können hier abgerufen werden:
>
> 
http://guest.engelschall.com/~martin/e2_partial_field_100_and_3_fields_filled.html
>
> Wenn das Format der Testdaten so nicht passend ist,
> kann ich diese auch in einem beliebig anderen Format zur Verfügung
> stellen.
>
> Ich hab bisher keine Ahnung, ob man aus den Zahlen etwas herauslesen
> kann. Ich kann es aktuell nicht und möchte daher einen Versuch starten.
Um was für Daten handelt es sich denn fachlich? Also woraus bestehen die 
100 Dimensionen, sind das Messwerte, oder ... ?

von Marie M. (capiman)


Bewertung
0 lesenswert
nicht lesenswert
Ingo E. schrieb:
> Um was für Daten handelt es sich denn fachlich? Also woraus bestehen die
> 100 Dimensionen, sind das Messwerte, oder ... ?

Ich lass einen Backtracker laufen. Dieser geht mal mehr, mal weniger 
weit in die Tiefe. Bei diesen Daten max. bis 144. Der Vorgang/jeder 
Versuch dauert recht lange. Ich ermittle, welche Tiefe maximal erreicht 
wird. In meinem Fall prüfe ich nur 100 und 144. Die 100 Dimensionen sind 
die ersten 100 Wege, die der Backtracker auswählt.

Ziel wäre es, die 144 möglichst schnell und oft zu erreichen.
Ich würde gerne bei gefundenem Start (100 Wege dann festgelegt) 
entscheiden,
ob es sich rentieren könnte, zu versuchen, auf 144 zu kommen oder ob es 
eher unwahrscheinlich ist. Ich kann beliebig viele Trainings- und 
Testdaten erzeugen, dauert bloss jeder Eintrag seine Zeit.

Wenn 100 viel zu viel sind, kann ich auch weiter reduzieren oder auch 
erhöhen. Es geht mir aktuell mehr um das Prinzip, wie so etwas gehen 
würde und ob überhaupt Erfolgsaussichten bestehen.

: Bearbeitet durch User
von Ingo E. (ogni42)


Bewertung
0 lesenswert
nicht lesenswert
Bedeutet
> Ich lass einen Backtracker laufen. Dieser geht mal mehr, mal weniger
> weit in die Tiefe. Bei diesen Daten max. bis 144. Der Vorgang/jeder
> Versuch dauert recht lange. Ich ermittle, welche Tiefe maximal erreicht
> wird. In meinem Fall prüfe ich nur 100 und 144. Die 100 Dimensionen sind
> die ersten 100 Wege, die der Backtracker auswählt.

und das,
> PartialSolution-0,yes-144,211,1652,1861,...

dass die Werte x_0, ..., x_99 jeweils die Bewertungen eines Zustandes 
sind? Also z.B. wie ein Backtracker beim Schach, der jeweils eine 
Position bewertet und dann den jeweils besten Zug aus dem Zugbaum 
auswertet?

Was ist dann das Kriterium für ja/nein. Ist das eine Funktion der Werte 
oder wie ergibt sich das?

von Marie M. (capiman)


Bewertung
0 lesenswert
nicht lesenswert
Ja, ich glaube, der Vergleich mit Schach ist gut.
Oder vielleicht auch Sudoku?

x_0=211
x_1=1652
usw.

211 gibt an, das ich eine bestimmte Figur (Schach) oder Zahl (Sudoku)
auf ein bestimmtes Feld setze.
Beim Sudoku gibt es Kombinationen, die vielleicht nicht mehr 
weitergehen, nicht zu einem kompletten Feld führen, weil ich davor schon 
eine Kombination an Zahlen gesetzt habe, die zum Ausschluss führen.
Das yes-144 oder no-144 bedeutet, dass ich eine bestimmte Tiefe 
erreiche, also z.B. beim Sudoku es schaffe 70 bestimmte vorgegebene 
Felder zu füllen. Wenn ich 81 Felder füllen würde, und alle Sudoku 
Regeln eingehalten werden würden, wäre das Sudoku gelöst.

Ich möchte versuchen, feststellen, ob es überhaupt möglich ist, dass ich 
z.B. 35 Felder fülle und dann anhand der Zahlen irgendwie erkennen kann, 
ob ich bis auf 70 hochkomme. Ich habe so meine Zweifel, dass es geht, 
würde aber das Prinzip gerne ausprobieren.
(d.h. bei diesem Beispiel Dimension 35, yes-70 und no-70)
-> Wenn bei 35 zu testenden Feldern no-70 rauskommt, dann kann ich damit 
auch kein volles Sudoku-Feld füllen. D.h. ich kann dem Backtracker 
mitteilen, er soll sich 35 andere Felder suchen.

: Bearbeitet durch User
von Qwertz (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Wenn man seine eigene Aufgabe nicht im  Griff hat, ist es nicht 
zielführend zu versuchen diese für andere weiter zu abstrahieren.

Erklär doch einfach, was du machst.

Nein, "Ich habe einen Backtracker" erklärt es nicht.

von Marie M. (capiman)


Bewertung
0 lesenswert
nicht lesenswert
Qwertz:
Welche Details kann ich dir zusätzlich geben, dass du (und auch andere) 
es besser verstehen können? Wenn man immer wieder über einem Problem 
grübelt, dann kommen einem bestimmte Sachen als selbstverständlich vor. 
Jemand anders braucht aber trotzdem diese Info.

Stell dir ein Sudoku vor. Dies mal als Beispiel oberste linke Ecke.
(Ein Neuntel des gesamten Feldes eines "normalen" Sudokus dargestellt)

F11 F12 F13 ...
F14 F15 F16 ...
F17 F18 F19 ...
.
.
.

Backtracker:
Beginnt mit Feld F11. Setz dort z.B. die Zahl 1 rein.
Geht dann weiter auf F12. Setz dort wieder die Zahl 1 rein.
Merkt, dass die Zahl 1 schon benutzt wurde, nimmt die 1 wieder raus
und setzt nächste Möglichkeit rein. Es ist die Zahl 2.
Die Zahl 2 passt, also weiter auf Feld F13.
usw. usf.

Ich weiß, dass es Optimierungen gibt und auch andere Methoden, Sudoku zu 
lösen, aber hier geht es nur um das Prinzip, um die Ausgangsdaten und 
das Umfeld meiner Frage zu verstehen.

Ich würde mir vorstellen, dass die Aufgabe des Classifier wäre, dem 
Backtracker zu helfen, früher die gerade laufende Tiefensuche 
abzubrechen.
Er bekommt als Eingabedaten 1,2,3,4,5,6,7,8,9 und soll dann entscheiden, 
ob es Sinn macht, mit dieser Belegung tiefer zu suchen. Ich vermute, 
dass diese Belegung mit nur 9 Zahlen die Suche zu wenig einschränkt, 
aber vielleicht reichen z.B. 4x4=16 oder 5x5=25 Zahlen? Es gibt dann 
mehr Regeln, die gebrochen werden können und eine Lösung verhindern.

Die Regeln legen aber das Problem "Sudoku" fest. D.h. der Classifier 
muss sich mindestens erst einmal diese Regeln einverleiben. Und dann ein 
paar interessante Regeln mehr (auf die ich scharf wäre). Ob dies geht?

: Bearbeitet durch User
von was (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Marie M. schrieb:
> Stell dir ein Sudoku vor.

Geht es denn nun wirklich um ein Sudoku, oder ist das nur eine Analogie, 
die du für sinnvoll hältst?

von Marie M. (capiman)


Bewertung
0 lesenswert
nicht lesenswert
Es ist eine Analogie, weil Sudoku einfach zu verstehen ist
und viele Sudoku kennen. Wenn ich mein Problem erklären würde,
wäre die Erklärung viel länger, aber das Prinzip ist das Gleiche 
dahinter. Selbst für mich selbst ist Sudoku einfacher zu verstehen,
da etwas kleiner und übersichtlicher.

von was (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Marie M. schrieb:
> Wenn ich mein Problem erklären würde,
> wäre die Erklärung viel länger, aber das Prinzip ist das Gleiche
> dahinter.

Da liegt der Hase im Pfeffer.

Du verstehst deine eigentliche Aufgabe nicht, meinst aber einschätzen zu 
können, was eine ähnliche Aufgabe sein könnte.

Das geht grundsätzlich schief.

Also entweder du rückst mit dem eigentlichen Problem raus und zwar ohne 
gutgemeinte Vereinfachungen, Analogien, Abstraktionen und sonstigem 
Blödsinn, oder wir können nur weiter an einem fiktivem Problem rumraten, 
das überhaupt nichts zur Sache tut.

- Was ist dein Anwendungsfall
- Was sind deine Werkzeuge
- Was ist dein Ziel
- Wie sehen deine Daten aus

von Marie M. (capiman)


Bewertung
0 lesenswert
nicht lesenswert
was schrieb:
> - Was ist dein Anwendungsfall

https://en.wikipedia.org/wiki/Eternity_II_puzzle

> - Was sind deine Werkzeuge

Ein Backtracker

> - Was ist dein Ziel

Ein Lösung (schneller) zu finden, als es derzeit braucht.

> - Wie sehen deine Daten aus

Siehe Link auf Datei weiter oben

von was (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Du willst also eine AI, die du zeilenweise mit Puzzlestücken fütterst 
und die dir sagt, ob es mit der bisher geprüften Reihenfolge noch 
möglich ist das Puzzle zu lösen, oder nicht.

Korrekt?

Was ist denn überhaupt die Bedeutung der Zahlen in den Testdaten und was 
ist die Bedeutung des Ergebnisses yes/no in diesen?

von Marie M. (capiman)


Bewertung
0 lesenswert
nicht lesenswert
was schrieb:
> Du willst also eine AI, die du zeilenweise mit Puzzlestücken fütterst
> und die dir sagt, ob es mit der bisher geprüften Reihenfolge noch
> möglich ist das Puzzle zu lösen, oder nicht.
>
> Korrekt?

Ja, ich denke, dies ist korrekt!

von Marie M. (capiman)


Bewertung
0 lesenswert
nicht lesenswert
Zu den Zahlen:

Ich habe mir vor langer Zeit eine Codierung überlegt und benutze diese 
fix in allen von mir entwickelten Programmen:

Zahl 1 bedeutet Karte 1 auf Feld 1 setzen. Es gibt hier keine Rotation.
Zahl 2 bedeutet Karte 2 auf Feld 1 setzen. Es gibt hier keine Rotation.
Zahl 3 bedeutet Karte 3 auf Feld 1 setzen. Es gibt hier keine Rotation.
Zahl 4 bedeutet Karte 4 auf Feld 1 setzen. Es gibt hier keine Rotation.
(Karte 1 bis 4 sind Ecken. Feld 1 ist die Ecke oben links. Der Rand ist 
grau, drum kann ich Karten auf Ecken und Kanten nicht rotieren.)
usw.
Meine Zahlen (die auch in den Daten enthalten sind, die ich dem 
Classifier geben würde) gehen bis 130180.

Es kann nur eine Zahl zwischen 1 und 4 in der Lösung vorkommen, weil ich 
nicht 2 Karten auf 1 Feld setzen kann.

Um es noch kurz fortzusetzen:
Zahl 5 bedeutet, Karte 5 auf Feld 2 zu setzen. Dies ist das Feld rechts 
neben der Ecke. Karte 1 bis 4 sind Ecken, passen nur auf Ecken. Karten 5 
bis 60 sind Randteile, passen nur auf den Rand. Auch bei Randteilen gibt 
es keine Rotation.
Ab Zahl 38 beginnt das Feld 3.
(Anmerkung: Warum kommen nicht alle Karten vor, also warum ist Zahl 38 
und nicht irgendwo bei 60? Weil es noch bis zu 5 vorgegebene/fest 
verbaute Karten gibt. Und einige Möglichkeiten schon als nicht möglich 
ermittelt wurden.)

Die Zahlen 130177,130178,130179,130180 sind für die Ecke unten rechts.
Jeweils dort sind wieder Karten 1 bis 4 möglich, die wir oben schon 
gesehen haben.

Wenn der Classifier jetzt mit diesen Zahlen nichts anfangen kann,
kann ich auch ohne Problem F1C1R0 (Feld 1, Card 1, Rotation 0) als Input 
generieren. Da fehlt mir aber aktuell die Info, was ein guter Input ist.

Ebenso interessant: Wenn ich zu wenig Zahlen/gefüllte Felder einfüttere, 
vermute ich, dass der Classifier nichts klassifizieren kann. Vermute, 
dass er dann nur schlechte Ergebnisse liefert, nicht lernt. Wenn ich 
dann mehr Zahlen (Dimensionen) einfüttere stelle ich mir vor, dass der 
Classifier besser lernen kann. Aber der Aufwand wächst, weil er mehr 
Dimensionen verarbeiten muss.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.