[PYTHON] Mit Keras 'Stateful RNN habe ich versucht zu prüfen, ob es sich um ein selbstgesteuertes Lied handelt, das auf der WAV-Datei basiert.

Hallo zusammen

Google hat einen selbstgesteuerten Songlerner namens Magenta erstellt, sodass Sie so viele Songs erstellen können, wie Sie möchten! Ich dachte, aber es war nicht wirklich so einfach. Die Lernquelldatei scheint Midi zu sein, und es scheint nicht möglich zu sein, durch Einfügen einer aufgezeichneten Datei zu lernen.

Deshalb habe ich verschiedene Dinge ausprobiert, weil ich keine eigene selbstgesteuerte Song-Lernmaschine erstellen konnte, die mit WAV erstellt werden kann. Die letzten Artikel sind Experimente für diese Zeit.

TL;DR

Das Repository verwendet Folgendes https://github.com/niisan-tokyo/music_generator

Die folgenden Dateien werden für das eigentliche Lernen verwendet. https://github.com/niisan-tokyo/music_generator/blob/master/src/stateful_learn.py

Motivation

Google hat Magenta veröffentlicht, ein selbstgesteuertes Song-Tool, das Tensorflow verwendet. https://magenta.tensorflow.org/ Dies ist ein großartiges Tool, aber ich bin ein wenig unbekannt damit, da die Zieldatei Midi ist. (Früher gab es viel, aber heute gibt es viel MP3 ...)

Zur einfachen Handhabung der aufgezeichneten Datei erscheint es vorerst gut, die Daten der Wellenform selbst wie wav zu verwenden. Darüber hinaus kann Python wav nativ verarbeiten, sodass ich dachte, ich müsste es versuchen.

planen

Ich dachte darüber nach, die rohen Wellenformdaten zum Lernen zu verwenden, aber sie waren völlig nutzlos, also dachte ich an den folgenden Plan.

Mit anderen Worten, ich dachte, ich könnte so etwas machen generator.png Sobald Sie eine Häufigkeitsverteilung für Zeitreihen haben, können Sie Musik machen, indem Sie sie umgekehrt in Fourier umwandeln.

Fourier-Transformation

Im vorherigen Artikel war die von der inversen Konvertierung für die 256-Frame-Fourier-Konvertierung zurückgegebene WAV-Datei problemlos zu hören. Ich denke, dies ist genug als eine Merkmalsmenge, die den Klang selbst ausdrückt. http://qiita.com/niisan-tokyo/items/764acfeec77d8092eb73

Eine schnelle Fourier-Transformation (FFT) mit der Numpy-Bibliothek liefert 256 Frequenzverteilungen, beispielsweise in einem Intervall von 256 Bildern. Normalerweise beträgt die Bildrate (Bilder pro Sekunde) einer Audiodatei 44100, sodass Sie alle 256/44100 = 5,8 (ms) eine Häufigkeitsverteilung erhalten können. Die Idee ist, dass Musik automatisch erstellt wird, wenn wir eine Lernmaschine erstellen können, die diesen Zeitübergang automatisch alle 5,8 ms generiert.

stateful RNN RNN ist ein wiederkehrendes neuronales Netzwerk, bei dem es sich um einen Netzwerktyp handelt, der kontinuierliche Zustände verarbeitet, indem auf zuvor berechnete Inhalte verwiesen wird, wenn eine Ausgabe von der Eingabe erhalten wird. http://qiita.com/kiminaka/items/87afd4a433dc655d8cfd

Beim Umgang mit RNNs in Keras werden normalerweise mehrere aufeinanderfolgende Zustände als Eingaben verwendet und eine Ausgabe erstellt, aber bei jeder Eingabe wird der vorherige Zustand zurückgesetzt. stateful RNN führt die folgende Verarbeitung durch, während der Status nach dieser vorherigen Verarbeitung beibehalten wird. Es wird erwartet, dass dies eine komplexe Serienverarbeitung in unregelmäßigen Abständen ermöglicht.

stateful_rnn.png Dieses Mal dachte ich, dass es möglich sein würde, einen Generator mit einem Fluss von Liedern zu erstellen, indem der Eingang als Frequenzverteilung im aktuellen Moment und der Ausgang als Frequenzverteilung im nächsten Moment mit Stateful RNN sequentiell gelernt werden.

Vorbereitung zum Lernen

Dateivorbereitung

Für m4a- und mp3-Dateien können Sie sie mit ffmpeg in wav konvertieren. http://qiita.com/niisan-tokyo/items/135824905e4a3021d358 Ich nehme meine Lieblingsspielmusik auf dem Mac auf und spucke sie auf WAV aus.

Erstellen eines Datensatzes

Da der Datensatz durch Fourier-Transformation WAV erstellt wird, können Sie grundsätzlich auf den Code verweisen, es gibt jedoch einige Einschränkungen.

def create_test_data(left, right):
    arr = []
    for i in range(0, len(right)-1):
        #Vektorisierung komplexer Zahlen
        temp = np.array([])
        temp = np.append(temp, left[i].real)
        temp = np.append(temp, left[i].imag)
        temp = np.append(temp, right[i].real)
        temp = np.append(temp, right[i].imag)
        arr.append(temp)

    return np.array(arr)

Dies ist der Teil, der Daten für die Eingabe erstellt, indem die Frequenzverteilungen der Stereo-Klangquelle kombiniert werden, die einer Fourier-Transformation unterzogen wurde. Hier werden der Real- und Imaginärteil der durch komplexe Zahlen dargestellten Häufigkeitsverteilung wieder in separate Elemente des Vektors eingefügt. Dies liegt daran, dass der Imaginärteil gelöscht wird, wenn Sie versuchen, mit einer komplexen Zahl zu berechnen. Infolgedessen beträgt die Anzahl der Abtastwerte in einem Abschnitt 256 Frames, die tatsächliche Eingabedimension jedoch 1024.

lernen

Modell erstellen

Das Modell ist so einfach wie das Verbinden von drei LSTMs und das endgültige Einfügen einer vollständig verbundenen Schicht.

model = Sequential()
model.add(LSTM(256,
              input_shape=(1, dims),
              batch_size=samples,
              return_sequences=True,
              activation='tanh',
              stateful=True))
model.add(Dropout(0.5))
model.add(LSTM(256, stateful=True, return_sequences=True, activation='tanh'))
model.add(Dropout(0.3))
model.add(LSTM(256, stateful=True, return_sequences=False, activation='tanh'))
model.add(Dropout(0.2))
model.add(Dense(dims))
model.compile(loss='mse', optimizer='adam')

Nun gibt es einige Bedingungen bei der Verwendung eines statusbehafteten RNN. Zunächst müssen Sie die Eingabedimension pro Stapel angeben. Dann muss jede Probe in der vorherigen Charge und jede Probe in der nächsten Charge als Serie fortlaufend sein. Als spezifisches Beispiel gibt es, wenn es eine erste Charge "X_1" und eine zweite Charge "X_2" gibt, eine Beziehung zwischen der i-ten Stichprobe $ X_1 [i] $ und $ X_2 [i] $ von beiden. Es bedeutet, dass es geben muss. Dieses Mal nehmen wir an, dass der Generator aus $ x_ {n + 1} = RNN (x_n) $ besteht, und erstellen den nächsten Satz derselben Anzahl von Zuständen aus mehreren aufeinanderfolgenden Zuständen.

model.png Mit anderen Worten, $ X_2 [i] $ liegt immer um $ X_1 [i] $ vor der Anzahl der Abtastwerte. Ich denke nicht, dass es ein bisschen zu schlampig ist, aber ich denke, es ist eine Maschine, die die Anzahl der Samples wiederholt, dh jeweils 32 Stück, um den nächsten Zustand zu erzeugen.

passend zu

Jetzt, da Sie bereit sind, beginnen wir zu lernen.

for num in range(0, epochs):
    print(num + 1, '/', epochs, ' start')
    for one_data in test:
        in_data = one_data[:-samples]
        out_data = np.reshape(one_data[samples:], (batch_num, dims))
        model.fit(in_data, out_data, epochs=1, shuffle=False, batch_size=samples)

        model.reset_states()
    print(num+1, '/', epochs, ' epoch is done!')

model.save('/data/model/mcreator')

Da die Reihenfolge der Chargen beim Lernen wichtig ist, versuche ich, die Proben auf der Charge nicht zu mischen. Zusätzlich wird für jede Welle gelernt, und der interne Zustand wird nach einmaligem Lernen zurückgesetzt.

Ergebnis

Lernergebnis

Erstens, wenn ich versuche, es zu lernen, scheint es, dass die Anpassung irgendwie voranschreitet.

1 / 10  start
Epoch 1/1
16384/16384 [==============================] - 87s - loss: 1.9879e-04
Epoch 1/1
16384/16384 [==============================] - 84s - loss: 1.9823e-04
Epoch 1/1
16384/16384 [==============================] - 75s - loss: 1.1921e-04
Epoch 1/1
16384/16384 [==============================] - 82s - loss: 2.3389e-04
Epoch 1/1
16384/16384 [==============================] - 80s - loss: 3.7428e-04
Epoch 1/1
16384/16384 [==============================] - 90s - loss: 3.3968e-04
Epoch 1/1
16384/16384 [==============================] - 87s - loss: 5.0188e-04
Epoch 1/1
16384/16384 [==============================] - 76s - loss: 4.9725e-04
Epoch 1/1
16384/16384 [==============================] - 74s - loss: 3.7447e-04
Epoch 1/1
16384/16384 [==============================] - 87s - loss: 4.1855e-04
1 / 10  epoch is done!
2 / 10  start
Epoch 1/1
16384/16384 [==============================] - 82s - loss: 1.9742e-04
Epoch 1/1
16384/16384 [==============================] - 85s - loss: 1.9718e-04
Epoch 1/1
16384/16384 [==============================] - 90s - loss: 1.1876e-04
Epoch 1/1
16384/16384 [==============================] - 104s - loss: 2.3144e-04
Epoch 1/1
16384/16384 [==============================] - 97s - loss: 3.7368e-04
Epoch 1/1
16384/16384 [==============================] - 78s - loss: 3.3906e-04
Epoch 1/1
16384/16384 [==============================] - 87s - loss: 5.0128e-04
Epoch 1/1
16384/16384 [==============================] - 79s - loss: 4.9627e-04
Epoch 1/1
16384/16384 [==============================] - 82s - loss: 3.7420e-04
Epoch 1/1
16384/16384 [==============================] - 90s - loss: 4.1857e-04
2 / 10  epoch is done!
...

Lassen Sie uns mit dem fertigen Modell einen Sound machen.

Klangerzeugung

Ich überlasse den detaillierten Code stateful_use.py im Repository. Wenn Sie also nur den allgemeinen Ablauf schreiben,

  1. Laden Sie das generierte Modell
  2. Lesen Sie die Seed-Musikdatei
  3. Erstellen Sie Zeitreihendaten, indem Sie das Modell bis zu einem gewissen Grad mithilfe von Seeds vorhersagen.
  4. Erstellen Sie nacheinander den nächsten Status aus den von Ihnen generierten Zeitreihendaten
  5. Erstellen Sie nach dem Generieren von Zeitreihendaten einer bestimmten Länge die ursprünglichen Wellenformdaten aus der darauf basierenden inversen Fourier-Transformation.

Der Generatorteil ist wie folgt

#Fourier-Transformation der Seed-Datei
Kl = fourier(left, N, samples * steps)
Kr = fourier(right, N, samples * steps)
sample = create_test_data(Kl, Kr)
sample = np.reshape(sample, (samples * steps, 4 * N))
music = []

#Geben Sie die Startdaten in das Modell ein=>Den Staat "fördern"
for i in range(steps):
    in_data = np.reshape(sample[i * samples:(i + 1) * samples], (samples, 1, 4 * N))
    model.predict(np.reshape(in_data, (samples, 1, 4 * N)))

#Erstellen Sie selbst Musik, indem Sie die letzten Ausgabedaten nacheinander in das Modell einsetzen, dessen Status durch Startdaten geändert wurde
for i in range(0, frames):
    if i % 50 == 0:
        print('progress: ', i, '/', frames)

    music_data = model.predict(np.reshape(in_data, (samples, 1, 4 * N)))
    music.append(np.reshape(music_data, (samples, 4 * N)))
    in_data = music_data

music = np.array(music)

Die auf diese Weise erhaltenen Daten werden umgekehrt Fourier-transformiert, in den realen Raum konvertiert und dann in wav geschrieben. Wenn man die Wellenform im realen Raum betrachtet, sieht es wie folgt aus.

スクリーンショット 2017-06-14 18.11.11.png Etwas länger スクリーンショット 2017-06-14 18.11.22.png Wenn ich das mit WAV höre, ist es in einem surrealen Zustand, in dem die ganze Zeit ein Summer-Sound mit einem konstanten Ton von "Boo" gespielt wird. .. ..

Weit entfernt von Musik ist es zu einer mysteriösen Maschine geworden, die nur einen konstanten Klang erzeugt. Unabhängig davon, welche Art von Musikdatei Sie einfügen, wird derselbe Sound erzeugt.

Erwägung

Ich denke, der Grund, warum es nicht funktioniert hat, war, dass der Übergang des Klangs so schnell war, dass das Lernen in Richtung der Konstante ging, die den Fehler minimierte. Vielleicht ist deshalb die Fehlerschwankung trotz des komplizierten Systems zu gering. Wenn Sie versuchen, es zustandslos zu machen, wissen Sie nicht, wie viele Sequenzen Sie nehmen sollen, und die Anzahl der Dimensionen nimmt mit der Anzahl der Sequenzen zu, was das Lernen schwierig macht. Oder es kann sein, dass die Anzahl der Lernvorgänge zu gering ist, aber da der Verlust bereits sehr gering ist, kann es eine andere Idee sein.

In jedem Fall müssen wir uns weiter verbessern.

Zusammenfassung

Wenn Sie ein Lied so einfach machen könnten, wäre es nicht so einfach. Es hat nicht sehr gut funktioniert, aber ich denke, ich habe bis zu einem gewissen Grad gelernt, wie man Python benutzt, insbesondere die Bedeutung von Numpy, also denke ich, dass das ein guter Punkt ist.

Es ist mir auch egal, aber ich habe mich am Ende sehr mit Numpys Umformung beschäftigt.

Diesmal ist so ein Ort

Nachtrag

2017/06/18 Die folgenden Änderungen wurden vorgenommen.

Ergebnis

Ich habe die folgende Wellenform. スクリーンショット 2017-06-18 8.48.25.png スクリーンショット 2017-06-18 8.48.35.png Das Hintergrundgeräusch blieb wie gewohnt, aber jetzt klingt es so, als würde es einen bestimmten Rhythmus schnitzen. Zusätzlich ist die erhaltene Häufigkeitsverteilung (der Realteil) wie folgt. Die Verteilungskarte für 10 Teile wird mit jeweils 5 Frames überlagert.

N = 256, Anzahl der LSTM-Neuronen = 256 スクリーンショット 2017-06-18 8.54.15.png N = 1024, Anzahl der LSTM-Neuronen = 512 スクリーンショット 2017-06-18 8.52.57.png Wenn N = 1024 und die Anzahl der Neuronen 256 ist, ist es dasselbe wie wenn N = 256 ist.

Erwägung

Wenn der anzuwendende Faktor während der Fourier-Transformation geändert wurde, nahm der Verlust selbstverständlich zu. Da mse für den Verlust verwendet wird, erhöht das Ändern des Faktors den Verlust um das Quadrat. Dies ermöglicht es, Änderungen an kleineren Komponenten zu beobachten, die möglicherweise eine verbesserte Genauigkeit aufweisen. Durch Erhöhen der Anzahl von Neuronen erhöhte sich auch die Expressionskraft.

Als Verbesserung ist es möglich, den während der Fourier-Transformation angewendeten Faktor zu erhöhen oder die Anzahl der Neuronen weiter zu erhöhen. Da die Anzahl der Epochen 10 und die Anzahl der Original-Songs 9 beträgt, ist es in Ordnung, dies zu ändern, aber da die Änderung des Verlusts gering ist, konnte ich den Effekt nicht gut sehen, so dass ich dachte, es sei vorerst reserviert.

Recommended Posts

Mit Keras 'Stateful RNN habe ich versucht zu prüfen, ob es sich um ein selbstgesteuertes Lied handelt, das auf der WAV-Datei basiert.
Ich habe versucht, WAV-Dateien mit Pydub zu synthetisieren.
Ich habe versucht, mit "Syncthing" Dateien auf mehreren PCs zu synchronisieren
Ich habe versucht, Remote API mit GAE / J zu verwenden
[Pythonocc] Ich habe versucht, CAD auf einem Jupyter-Notebook zu verwenden
Ich habe versucht, PySpark von Jupyter 4.x auf EMR zu verwenden
Ich habe versucht, parametrisiert zu verwenden
Ich habe versucht, Argparse zu verwenden
Ich habe versucht, Mimesis zu verwenden
Ich habe versucht, anytree zu verwenden
Ich habe versucht, aiomysql zu verwenden
Ich habe versucht, Summpy zu verwenden
Ich habe versucht, Coturn zu verwenden
Ich habe versucht, Pipenv zu verwenden
Ich habe versucht, Matplotlib zu verwenden
Ich habe versucht, "Anvil" zu verwenden.
Ich habe versucht, Hubot zu verwenden
Ich habe versucht, ESPCN zu verwenden
Ich habe versucht, openpyxl zu verwenden
Ich habe versucht, Ipython zu verwenden
Ich habe versucht, PyCaret zu verwenden
Ich habe versucht, Cron zu verwenden
Ich habe versucht, ngrok zu verwenden
Ich habe versucht, face_recognition zu verwenden
Ich habe versucht, Jupyter zu verwenden
Ich habe versucht, doctest zu verwenden
Ich habe versucht, Folium zu verwenden
Ich habe versucht, jinja2 zu verwenden
Ich habe versucht, Folium zu verwenden
Ich habe versucht, das Zeitfenster zu verwenden
[Mit Bild] Ich habe versucht, neofetch auf verschiedenen Betriebssystemen zu verwenden!
Ich habe versucht, PDF-Daten der medizinischen Online-Versorgung zu verwenden, die auf der Ausbreitung einer neuen Coronavirus-Infektion basieren
[Ich habe versucht, Pythonista 3 zu verwenden] Einführung
Ich habe versucht, easydict (Memo) zu verwenden.
Ich habe versucht, das Gesicht mit Face ++ zu erkennen
Ich habe versucht, RandomForest zu verwenden
Ich habe versucht, BigQuery ML zu verwenden
Ich habe versucht, Amazon Glacier zu verwenden
Ich habe versucht, Git Inspector zu verwenden
Ich habe versucht, Magenta / TensorFlow zu verwenden
Ich habe MLflow auf Databricks ausprobiert
Ich habe versucht, AWS Chalice zu verwenden
Ich habe versucht, Slack Emojinator zu verwenden
Ich habe eine Kreuzvalidierung basierend auf dem Rastersuchergebnis mit scikit-learn versucht
Ich habe versucht, die COTOHA-API zu verwenden (es gibt auch Code auf GitHub).
Ich habe versucht, den auf Papier gestempelten Stempel mit OpenCV zu digitalisieren
Ich habe versucht, BigQuery-Daten mit Jupyter Lab mit GCP zu visualisieren
Ich habe versucht, ein Windows-Spiel mit Steam Play unter Ubuntu 20.04 LTS zu spielen