# ML für Jetsion Nano # Phase: Proof of Concept # Dateiname: nano_GPU_ML # Julia-Version: 1.3.1 # Flux-Version: 0.10.1 # Datum: 28.02.2020 # Version: 0.91 # # Modell-Dateiname für das Protokoll: Dateiname = "Modell_Rotwein" Beschreibung = "Netztraining mit dem Rotweindatensatz" # ML mit Flux am Beispiel des Rotwein-Datensatzes # Laden der benötigten Pakete in die Julia-Umgebung: using CSV, DataFrames using Flux, CuArrays using Statistics using StatsBase using Dates, TimesDates # ---------------------Daten laden ------------------------- # Dateiname: dateiname = "Rotwein.csv" verzeichnis = pwd() datei = joinpath(verzeichnis, dateiname) # Einlesen der CSV-Datei: Daten = CSV.read(datei, header = 1, delim = ';', decimal = ',', normalizenames = true, type=Float32) println("\n", "Auszug eingelesene Daten ($dateiname): ") show(Daten) println("\n") # ------------------- Trainings- und Testdatensätze erstellen ------------ # Konvertieren des DataFrames in ein Array: GesamtDaten = convert(Matrix, Daten) # Performance: Von Float64 in Float32 konverrieren: GesamtDaten = convert(Array{Float32}, GesamtDaten) # Normalisieren der Beobachtungen auf Mittwelwert 0 und Standardabweichung 1, # ausgenommen sind die Q-Noten: n_Merkmale = size(GesamtDaten)[2] PC_Merkmale = n_Merkmale - 1 Beobachtungen_Norm = Flux.normalise(GesamtDaten[:,1:PC_Merkmale], dims=1) # Features sind die Beobachtungen zur Qualitätsnote des Prüfers: features = coalesce.(transpose(Beobachtungen_Norm)) # Beurteilungen durch den Prüfer selektieren und labels zuordnen: # (Die Note muss immer das letzte Merkmale sein!) labels = coalesce.(GesamtDaten[:, n_Merkmale]) # Feststellen, welche Q-Noten vergeben wurden: QNoten = sort(unique(labels)) # Die Q-Noten durch Wahrheitswerte darstellen: onehot_QNoten = Flux.onehotbatch(labels, QNoten) # Trainings- und Testdatensatz erstellen: n_Spalten = size(features)[2] n_Training = floor(n_Spalten * 0.8) # 80% Daten = Trainingsdatensatz n_Training = convert(Int64, n_Training) n_Test = n_Spalten - n_Training # Der Rest = Testdaten # Zufalls-Index erzeugen: i_Spalten = collect(1:n_Spalten) i_Training = sample(i_Spalten, n_Training, replace = false, ordered = true) i_Test = setdiff(i_Spalten, i_Training) # Trainingsdatensatz: TrainDaten_features = features[:, i_Training] TrainDaten_features = cu(TrainDaten_features) # Nutzung der GPU TrainDaten_labels = onehot_QNoten[:, i_Training] TrainDaten_labels = cu(TrainDaten_labels) # Nutzung der GPU # Testdatensatz: TestDaten_features = features[:, i_Test] TestDaten_features = cu(TestDaten_features) # Nutzung der GPU TestDaten_labels = onehot_QNoten[:, i_Test] TestDaten_labels = cu(TestDaten_labels) # Nutzung der GPU # ----------------------- Neuronales Netz erstellen --------------- # Neuronales Netz definieren: # Definiert wird ein NN mit einer verdeckten Schicht. Für diese Schicht # ist die Anzahl Eingangsneuronen gleich der Anzahl Ausgangsneuronen der # ersten Schicht Ausgang = Eingang # Die Aktivierungsfunktion σ steht für die Sigmoid-Funktion # Aktivierungsfunktion softmax ist eine normalisierte Exponentialfunktion, # siehe NNlib.jl. # ------------------------------------------------------------------ # NN-Paratmeter definieren: # Diese Parameter beeinflussen das Lernen des Netzes! Eingang = size(features)[1] Ausgang = size(QNoten)[1] Lernrate = 0.3 Epochen = 100000 Modell = Chain( Dense(Eingang, Eingang, σ), Dense(Eingang, Eingang, σ), Dense(Eingang, Ausgang), softmax ) # Das Modell GPU-lesbar machen: Modell = fmap(cu, Modell) # Kostenfunktion (Soll-Ist-Abstand), passen zu softmax: Fehler_Info = [0.0] # Vorbelegung mit einem Initialwert function loss(x, y) Fehler = Flux.crossentropy(Modell(x), y) # Sammeln des Fehlers zur grafischen Ausgabe: global Fehler_Info = [Fehler_Info; Fehler] return Fehler end # Gradientabstiegsverfahren-Optimierer: Optimierer = Descent(Lernrate) # Einen Iterator zum Training über die Anzahl Epochen definieren: Epochen_Iterator = Iterators.repeated((TrainDaten_features, TrainDaten_labels), Epochen) # ---------------------------------------------------------------------- # Training durchführen # ---------------------------------------------------------------------- println("Training gestartet!") println("\nEpochen: $Epochen") println("Lernrate: $Lernrate") # Trainingszeit gesthalten, Start: StartZeit = now() TrainStartDatum = Date(StartZeit) TrainStartZeit = Time(StartZeit) Flux.train!(loss, params(Modell), Epochen_Iterator, Optimierer) # Trainingszeit festhalten, Ende: EndeZeit = now() TrainEndeDatum = Date(EndeZeit) TrainEndeZeit = Time(EndeZeit) Trainingsdauer = Millisecond(TrainEndeZeit - TrainStartZeit) # --------------------------------------------------------------------- # Netzqualität prüfen # Ein Soll-Ist-Vergleich auf Basis der Testdaten! # --------------------------------------------------------------------- # Funktion zur Vorhersage der Qualitätsnoten: function Vorhersage(x) Label = Flux.onecold(Modell(x)) return Label end # Netzqualität mit den Testdaten prüfen: Label_soll = Vorhersage(TestDaten_features) # Trainingsdaten aus den Ausgangsdaten selektieren: Testdaten_Validierung = Daten[i_Test, :] Testdaten_Validierung[!, :Testdaten_Index] = i_Test # Position im Gesamtdatensatz Rotwein Testdaten_Validierung[!, :NNModel_QNote] = Label_soll # Ist-QNote # Vergleich zwischen Soll und Ist durchführen: Zaehler = 0 n_Testdaten = size(Testdaten_Validierung)[1] Uebereinstimmung = Array{Bool}(undef, n_Testdaten) Uebereinstimmung_Score = 0 for i = 1:n_Testdaten if Testdaten_Validierung[!,:quality][i] == Testdaten_Validierung[!,:NNModel_QNote][i] Uebereinstimmung[i] = true global Zaehler += 1 global Uebereinstimmung_Score = Zaehler / n_Testdaten else Uebereinstimmung[i] = false end end Uebereinstimmung_Score = round(Uebereinstimmung_Score * 100, digits = 2) Testdaten_Validierung[!,:Uebereinstimmung] = Uebereinstimmung # Ausgabe auf dem Bildschirm: println("\nSoll-Ist-Vergleich:\n", Testdaten_Validierung[:,[:quality, :Testdaten_Index, :NNModel_QNote, :Uebereinstimmung]]) println("\nÜbereinstimmung in %: $Uebereinstimmung_Score") # --------------------------------------------------------------------- # Sichern der Daten # --------------------------------------------------------------------- # Sicherung der Trainingsparameter: ParamerterDatei = Dateiname * "_" * "Trainingsparameter.txt" datei = open((joinpath(verzeichnis, ParamerterDatei)), "w") println(datei, "ModellDateiname: $Dateiname") println(datei, "Beschreibung : $Beschreibung") println(datei, "------------------------------------------", "\n") println(datei, "Modell: $Modell", "\n") println(datei, "Datum und Uhrzeit des Tainingsstarts: $StartZeit") println(datei, "Endzeitpunkt des Trainings : $TrainEndeZeit") println(datei, "Trainingsdauer: $Trainingsdauer") println(datei, "------------------------------------------", "\n") println(datei, "Traningsparameter:", "\n") println(datei, "Epochen: $Epochen") println(datei, "Lernrate: $Lernrate") println(datei, "------------------------------------------", "\n") println(datei, "Netzqualität:") println(datei, "Übereinstimmung in %: $Uebereinstimmung_Score") close(datei) # Sicherung der Kostenfunktionsdaten: Kosten_Modell = DataFrame(Loss = Fehler_Info) KM_Datei = Dateiname * "_" * "Modellkosten.csv" datei = joinpath(verzeichnis, KM_Datei) CSV.write(datei, Kosten_Modell) # Sicherung der Testdaten-Validierung: TV_Datei = Dateiname * "_" * "TestdatenValidierung.csv" datei = joinpath(verzeichnis, TV_Datei) CSV.write(datei, Testdaten_Validierung) # Ende: println("\nEnde des Trainings!\n") println("Trainingsdauer: $Trainingsdauer", "\n")