ML Boot Camp 2016 neu in den TOP 10

  • Tutorial
Vor nicht allzu langer endete vor dem Wettbewerb auf maschinelles Lernen von Mail.ru. Ich belegte den 9. Platz und möchte mitteilen, wie ich es gemacht habe. Kurz gesagt, ein Glücksfall.



Ein wenig über meine Erfahrungen:

1) Im Allgemeinen bin ich PHP-Programmierer und kenne mich mit Python nur wenig aus , wenn ich am russischen AI Cup 2015 teilgenommen habe , bei dem ich zum ersten Mal in Python geschrieben und ein T-Shirt gewonnen habe.
2) Bei der Arbeit löste ich ein Problem der Bestimmung der Tonalität des Textes mit Hilfe von Scikit-Learn.
3) Ich habe angefangen, einen Kurs über maschinelles Lernen auf coursera.org von Yandex zu belegen.

Hier endet meine Erfahrung mit Python und maschinellem Lernen.

Der Start des Wettbewerbs


Herausforderung
Es ist notwendig, einem Computer beizubringen, vorherzusagen, wie viele Sekunden zwei Matrizen der Größe mxk und kxn auf einem Computersystem multipliziert werden, wenn bekannt ist, wie viel dieses Problem auf anderen Computersystemen mit unterschiedlichen Matrixgrößen und anderen System- und Hardwareparametern gelöst wurde.

Es wird eine Reihe von Merkmalen angegeben, die ein separates Berechnungsexperiment beschreiben: die Parameter des Problems (m, k, n) und die Eigenschaften des Computersystems, auf dem der Algorithmus und die Berechnungszeit ausgeführt wurden. Und das Testmuster, für das Sie die Zeit vorhersagen müssen.

Als Qualitätskriterium zur Lösung des Problems wird der kleinste durchschnittliche relative Fehler für Implementierungen verwendet, die länger als eine Sekunde arbeiten:
Bild



Ich installierte python3 und notebook für mich und fing an, mich anhand eines Tutorial-Artikels mit Pandas zu befassen . Ich habe die Daten heruntergeladen, sie in eine zufällige Gesamtstruktur eingespeist und ~ 0,133 am Ausgang erhalten

.

Studienfach und Sammlung von Zusatzinformationen


Ich kehre zur Aufgabe zurück und halte mich an die Zeile „ Wir haben die Idee des Problems aus der Arbeit von A. A. Sidnev, V. P. Gergel “. Tatsächlich beschreibt das Buch, wie man ein solches Problem löst. Ich wusste zwar nicht, wie ich diese Idee umsetzen sollte, aber ich sah einen interessanten Zeitplan:

Bild

Hmm, aber in Wirklichkeit sollte die Abhängigkeit der Zeit von der Größe der Matrizen linear sein, dachte ich und beschloss zu sehen, wie das mit unseren Daten ist. Nachdem ich alle Beispiele nach Merkmalen gruppiert hatte, stellte ich fest, dass es nur 92 Gruppen gab. Nachdem ich die Diagramme für jede der Optionen erstellt hatte, sah ich, dass die Hälfte eine lineare Beziehung zu kleinen Ausreißern hatte. Die andere Hälfte zeigte ebenfalls eine lineare Beziehung, jedoch mit einer starken Streuung. Es gibt viele Diagramme, daher möchte ich nur drei Beispiele für die

Streuung nennen:

Bild

Linear:

Bild

Mit sehr starker Dispersion:

Bild

Der letzte Zeitplan wurde als separate Gruppe ausgewählt, da er bei der Kreuzvalidierung schlechte Ergebnisse zeigte. Ich habe beschlossen, etwas Besonderes für diesen Fall zu tun (aber am Ende habe ich nichts Besonderes getan).

Mit Daten arbeiten


Tatsächlich habe ich für jede Gruppe lineare Regressionen erstellt und ~ 0.076 erhalten. Hier dachte ich, dass ich den Schlüssel zur Lösung des Problems gefunden hatte, und fing an, mich an die Grafik anzupassen. Ich habe fast alle Regressionsmodelle ausprobiert, die in Scikit-Learn waren (ja, es gibt kein Wissen, daher habe ich das Problem durch die Methode des wissenschaftlichen Stocherns gelöst), das Ergebnis hat sich nicht wesentlich verbessert.

Es wurde sogar ein Polynom eingeführt. Ich durchlief alle Gruppen und suchte mit Hilfe von GridSearchCV nach den besten Parametern für jede Gruppe. Mir ist aufgefallen, dass es in manchen Gruppen gar nicht so krumm ist, wie ich es gerne hätte. Begann mit Daten zu arbeiten. Zuerst habe ich festgestellt, dass Zeilen mit fehlenden Speicherdaten (memtRFC, memFreq, memType) vorhanden sind. Mit nur logischen Schlussfolgerungen habe ich diese Daten wiederhergestellt. Zum Beispiel gab es Daten mit memtRFC gleich 'DDR-SDRAM PC3200' und 'DDR-SDRAM PC-3200'. Offensichtlich ist das dasselbe.

Ich hatte gehofft, dass dies die Anzahl der Gruppen verringern würde, aber es hat nicht so geklappt. Außerdem begann er mit Emissionen zu arbeiten. Für immer müsste man eine Methode schreiben, die Emissionen automatisch erkennt, aber ich habe alles mit meinen Händen gemacht. Er zeichnete Diagramme für alle Gruppen und bestimmte visuell Ausreißer und schloss diese Punkte aus.

Quervalidierung


Nach all dem stieß ich auf das Problem, dass meine Tests ein Ergebnis von 0,064 und tatsächlich 0,073 zeigten. Anscheinend umgeschult. Ich habe einen Klassenwrapper mit Fit- und Vorhersagemethoden geschrieben, in dem ich die Daten in Gruppen aufteilte, Modelle für jede Gruppe trainierte und für jede Gruppe dasselbe vorhersagte. Dies ermöglichte mir die Kreuzvalidierung. Tatsächlich war das Ergebnis meiner Tests und der heruntergeladenen Daten danach immer sehr nah.

Es sah ungefähr so ​​aus:

class MyModel:
    def __init__(self):
        pass
    def fit(self, X, Y):
       # здесь я пробегаюсь по x, понимаю в какой группе он находится, и обучаю нужную модель для этой группы
    def predict(self, X):
       # здесь я пробегаюсь по x, понимаю в какой группе он находится, беру нужную модель и делаю предсказание
    def get_params(self, deep=False):
        return {}

Jetzt konnte ich mit Hilfe von cross_validation.cross_val_score meinen Ansatz qualitativ testen.

Ein weiterer kleiner Gewinn war die Arbeit mit Daten, die über die Bedingungen des Problems hinausgingen. Nach Bedingung kann Y nicht kleiner als eins sein. Nachdem ich mir die Statistiken angesehen hatte, stellte ich fest, dass Y mindestens 1,000085 betrug, und meine Vorhersagen ergaben ein Ergebnis von weniger als 1. Nicht viel, aber es gab solche. Ich habe dieses Problem erneut durch Tippen gelöst. Die resultierende Formel lautet:

time_new = 1 + pow(time_predict/2,2)/10

Irgendwann wurde mir klar, dass es nicht nur notwendig war, ein abstraktes Problem zu lösen, sondern ein bestimmtes, das heißt, es war nicht notwendig, die Genauigkeit der Zeitvorhersage anzustreben, sondern den Fehler zu minimieren. Das heißt, wenn die Echtzeit des Skripts 10 Sekunden beträgt und ich einen Fehler von 2 gemacht habe, ist mein Fehler | 10-8 | / 10 = 0,2. Und wenn die Zeit wirklich 2 Sekunden beträgt und ich einen Fehler von 0,1 gemacht habe, dann ist | 2-0,1 | / 2 = 0,95.

Der Unterschied liegt auf der Hand. Als ich das erkannte und aus irgendeinem Grund nicht sofort, beschloss ich, die Genauigkeit für kurze Zeit zu erhöhen. Zu seiner linearen Gewichtsregression hinzugefügt. Unter Verwendung der Auswahlmethode erhielten wir die folgende Formel 1 / pow (Y, 3.1). Das heißt, je länger die Zeit ist, desto geringer ist ihre Bedeutung. Zusätzlich zu einem emissionsresistenten Modell habe ich endlich 4 Modelle bekommen

LinearRegression() # у этой модели есть веса
TheilSenRegressor()
Pipeline([('poly', PolynomialFeatures()), ('linear', TheilSenRegressor())])  #  параметры для каждой группы подбирались GreadSearchCV автоматически

Tatsächlich ergab der Durchschnitt dieser Modelle ein Ergebnis von 0,057. Dann sprang ich auf den 14. Platz und rutschte dann allmählich auf 20 ab.

Versuche, das Ergebnis irgendwie zu verbessern, indem ich die besten Parameter auswählte, Modelle änderte, ihre Kombinationen und sogar falsche Punkte hinzufügte, schlugen fehl.

Ziellinie


Bei klar linearen Gruppen war das Ergebnis ausgezeichnet, so dass mit stark dispergierten Daten gearbeitet werden musste. Ich habe mich dazu entschlossen, die Streuung mit meiner Vorhersage zu addieren. Dazu habe ich ExtraTreesRegressor für alle nicht klar linearen Gruppen trainiert und die 36 wichtigsten Parameter gemäß dem Modell verwendet. Ich habe ein Skript geschrieben, das in der Schleife eine Kreuzvalidierung anhand der Daten nur dieser 36 Parameter durchführte, wobei jeweils ein Parameter ausgeschlossen wurde. So habe ich gesehen, ohne welchen Parameter das beste Ergebnis erzielt wird. Ich wiederholte diese Iteration, bis sich die Qualität nicht mehr verbesserte. Ja, dies ist nicht ganz der richtige Ansatz, da der in der ersten Iteration ausgeschlossene Parameter eine Erhöhung in der fünften ergeben könnte. Es war für immer notwendig, alle Optionen zu prüfen, aber das war zu lang. Nachdem ich die Qualität um ein paar Prozent verbessert hatte, war ich mit dem Ergebnis zufrieden.

Für nichtlineare Gruppen wurde ein weiteres Modell hinzugefügt, das jedoch eine besondere Bedingung erfüllt. Wenn die von ExtraTreesRegressor vorhergesagte Zeit geringer war als die von linearen Modellen vorhergesagte Durchschnittszeit, dann hat er den Durchschnitt zwischen ihnen genommen, aber wenn sie länger war, hat er nur die von linearen Modellen vorhergesagte Zeit genommen. (Es ist besser, einen Fehler in eine kleinere Richtung zu machen, denn wenn die Echtzeit höher ist, ist der Fehler geringer).

Dies warf mich auf den achten Platz, von wo ich wieder auf den zehnten abrutschte. Der Rest meiner Versuche, das Ergebnis irgendwie zu verbessern, hat auch keine Früchte getragen. Als ich alle Testergebnisse nachzählte, war ich auf dem 9. Platz. Zwischen den letzten der TOP 10 und den dort nicht enthaltenen Punkten beträgt der Unterschied etwa 0,0002. Dies ist sehr klein, was auf die große Bedeutung des Glücks in dieser Runde hinweist.

Zusammenfassung


Und so sind die Schlussfolgerungen, die ich für mich selbst gezogen habe:

  • Verwenden Sie immer eine Kreuzvalidierung.
  • Versuchen Sie, den Fehler zu minimieren.
  • Es ist notwendig, mit Daten zu arbeiten (Ausreißer oder Datenmangel);

Preise


Es ist gut, dass die Preise klein waren und bereits für 10 Plätze vergeben wurden, was es mir ermöglichte, mich auf die Preisplätze zu drängen. Für seine Festplatte fuhr er in das E-Mail-Büro, wo Ilya mich traf ( sat2707 ), gab mir einen Preis, gab mir einen Saft und zeigte die Aussichtsplattform. Sie haben mir auch versichert, dass neue Wettbewerbe mit großen Preisen geplant sind, also werden wir warten.

Ich habe alles, danke euch allen, viel Glück an alle!

Jetzt auch beliebt: