Maskinindlæring med gnist MLlib

1. Oversigt

I denne vejledning forstår vi, hvordan vi kan udnytte Apache Spark MLlib til at udvikle maskinlæringsprodukter. Vi udvikler et simpelt maskinlæringsprodukt med Spark MLlib for at demonstrere kernekoncepterne.

2. En kort primer til maskinindlæring

Maskinindlæring er del af en bredere paraply kendt som kunstig intelligens. Maskinindlæring refererer til undersøgelse af statistiske modeller for at løse specifikke problemer med mønstre og slutninger. Disse modeller "trænes" for det specifikke problem ved hjælp af træningsdata hentet fra problemområdet.

Vi får se, hvad præcis denne definition indebærer, når vi tager vores eksempel.

2.1. Maskinindlæringskategorier

Vi kan bredt kategorisere maskinindlæring i overvåget og uden tilsyn kategorier baseret på tilgangen. Der er også andre kategorier, men vi holder os til disse to:

  • Overvåget læring fungerer med et datasæt, der indeholder både input og den ønskede output - for eksempel et datasæt, der indeholder forskellige egenskaber ved en ejendom og de forventede lejeindtægter. Overvåget læring er yderligere opdelt i to brede underkategorier kaldet klassificering og regression:
    • Klassificeringsalgoritmer er relateret til kategorisk output, som om en ejendom er optaget eller ej
    • Regressionsalgoritmer er relateret til et kontinuerligt outputområde, ligesom værdien af ​​en ejendom
  • Uovervåget læring på den anden side fungerer med et sæt data, der kun har inputværdier. Det fungerer ved at forsøge at identificere den iboende struktur i inputdataene. For eksempel at finde forskellige typer forbrugere gennem et datasæt af deres forbrugsadfærd.

2.2. Maskinlæring arbejdsgang

Maskinindlæring er virkelig et tværfagligt studieområde. Det kræver kendskab til forretningsdomænet, statistik, sandsynlighed, lineær algebra og programmering. Da dette klart kan blive overvældende, det er bedst at nærme sig dette på en ordnet måde, hvad vi typisk kalder en maskinlæringsworkflow:

Som vi kan se, bør hvert maskinlæringsprojekt starte med en klart defineret problemstilling. Dette skal efterfølges af en række trin relateret til data, der potentielt kan løse problemet.

Derefter vælger vi typisk en model, der ser på problemets art. Dette efterfølges af en række model træning og validering, der er kendt som model finjustering. Endelig tester vi modellen på tidligere usete data og distribuerer den til produktion, hvis den er tilfredsstillende.

3. Hvad er gnist? MLlib?

Spark MLlib er et modul oven på Spark Core, der giver primærer til maskinindlæring som API'er. Maskinindlæring beskæftiger sig typisk med en stor mængde data til modeluddannelse.

Den grundlæggende computerramme fra Spark er en enorm fordel. Oven i dette giver MLlib de fleste af de populære maskinindlærings- og statistiske algoritmer. Dette forenkler i høj grad opgaven med at arbejde på et stort maskinlæringsprojekt.

4. Maskinindlæring med MLlib

Vi har nu nok kontekst om maskinindlæring, og hvordan MLlib kan hjælpe i denne bestræbelse. Lad os komme i gang med vores grundlæggende eksempel på implementering af et maskinlæringsprojekt med Spark MLlib.

Hvis vi husker fra vores diskussion om workflow for maskinlæring, skal vi starte med en problemstilling og derefter gå videre til data. Heldigvis for os vælger vi “hejverdenen” inden for maskinindlæring, Iris Dataset. Dette er et multivariat-mærket datasæt, der består af længde og bredde af bægerblade og kronblade af forskellige arter af Iris.

Dette giver vores problemmål: kan vi forudsige arten af ​​en iris ud fra længden og bredden af ​​dens sepal og kronblad?

4.1. Indstilling af afhængigheder

Først skal vi definere følgende afhængighed i Maven for at trække de relevante biblioteker:

 org.apache.spark gnist-mllib_2.11 2.4.3 leveret 

Og vi er nødt til at initialisere SparkContext for at arbejde med Spark API'er:

SparkConf conf = new SparkConf () .setAppName ("Main") .setMaster ("local [2]"); JavaSparkContext sc = ny JavaSparkContext (conf);

4.2. Indlæser data

Første ting først skal vi downloade dataene, som er tilgængelige som en tekstfil i CSV-format. Så er vi nødt til at indlæse disse data i Spark:

Streng dataFile = "data \ iris.data"; JavaRDD data = sc.textFile (dataFile);

Spark MLlib tilbyder flere datatyper, både lokale og distribuerede, til at repræsentere inputdataene og de tilsvarende etiketter. Den enkleste af datatyperne er Vektor:

JavaRDD inputData = data .map (line -> {String [] parts = line.split (","); double [] v = new double [parts.length - 1]; for (int i = 0; i <parts .længde - 1; i ++) {v [i] = Double.parseDouble (dele [i]);} returner Vectors.dense (v);});

Bemærk, at vi kun har inkluderet inputfunktionerne her, for det meste for at udføre statistisk analyse.

Et træningseksempel består typisk af flere inputfunktioner og en label repræsenteret af klassen MærketPoint:

Kortkort = nyt HashMap (); map.put ("Iris-setosa", 0); map.put ("Iris-versicolor", 1); map.put ("Iris-virginica", 2); JavaRDD mærket Data = data. Kort (linje -> {String [] dele = linje.split (","); dobbelt [] v = ny dobbelt [dele.længde - 1]; for (int i = 0; i <dele .længde - 1; i ++) {v [i] = Double.parseDouble (dele [i]);} returner nye LabeledPoint (map.get (dele [parts.length - 1]), Vectors.dense (v)); });

Vores outputetiket i datasættet er tekstmæssigt, hvilket betyder arten af ​​Iris. For at indføre dette i en maskinlæringsmodel skal vi konvertere dette til numeriske værdier.

4.3. Undersøgende dataanalyse

Eksplorativ dataanalyse involverer analyse af de tilgængelige data. Nu, maskinlæringsalgoritmer er følsomme over for datakvalitetDerfor har data af højere kvalitet bedre udsigter til at levere det ønskede resultat.

Typiske analysemål inkluderer fjernelse af uregelmæssigheder og afsløring af mønstre. Dette indgår endda i de kritiske trin i funktionsteknik for at nå frem til nyttige funktioner fra de tilgængelige data.

Vores datasæt er i dette eksempel lille og velformet. Derfor behøver vi ikke forkæle os med en masse dataanalyse. Spark MLlib er dog udstyret med API'er til at give en god indsigt.

Lad os begynde med nogle enkle statistiske analyser:

MultivariateStatisticalSummary resume = Statistics.colStats (inputData.rdd ()); System.out.println ("Resumé betyder:"); System.out.println (summary.mean ()); System.out.println ("Resumévarians:"); System.out.println (summary.variance ()); System.out.println ("Resume ikke-nul:"); System.out.println (summary.numNonzeros ());

Her observerer vi middelværdien og variansen af ​​de funktioner, vi har. Dette er nyttigt til at afgøre, om vi har brug for at udføre normalisering af funktioner. Det er det nyttigt at have alle funktioner i en lignende skala. Vi tager også en note af værdier, der ikke er nul, hvilket kan have negativ indflydelse på modelens ydeevne.

Her er output til vores inputdata:

Resumé Gennemsnit: [5.843333333333332,3.0540000000000003,3.7586666666666666,1.198666666666666668] Variant i sammendrag: [0.6856935123042509,0.18800402684563744,3.113179418344516,0.5824143176733783] Resumé Ikke-nul.0] 150,050

En anden vigtig måling at analysere er sammenhængen mellem funktioner i inputdataene:

Matrix correlMatrix = Statistics.corr (inputData.rdd (), "pearson"); System.out.println ("Korrelationsmatrix:"); System.out.println (correlMatrix.toString ());

EN høj sammenhæng mellem to funktioner antyder, at de ikke tilføjer nogen inkrementel værdi og en af ​​dem kan droppes. Sådan er vores funktioner korreleret:

Korrelationsmatrix: 1,0 -0,10936924995064387 0,8717541573048727 0,8179536333691672 -0,10936924995064387 1,0 -0,4205160964011671 -0,3565440896138163 0,8717541573048727 -0,4205160964011671 1,096 07066706

4.4. Opdeling af data

Hvis vi husker vores diskussion af workflow for maskinlæring, involverer det flere iterationer af modeluddannelse og validering efterfulgt af endelig test.

For at dette kan ske, Vi er nødt til at opdele vores træningsdata i træning, validering og testsæt. For at holde tingene enkle springer vi over valideringsdelen. Så lad os opdele vores data i træning og testsæt:

JavaRDD [] splits = parsedData.randomSplit (ny dobbelt [] {0,8, 0,2}, 11L); JavaRDD trainingData = split [0]; JavaRDD testData = split [1];

4.5. Modeluddannelse

Så vi er nået til et stadium, hvor vi har analyseret og forberedt vores datasæt. Det eneste, der er tilbage, er at føde dette ind i en model og starte magien! Nå, lettere sagt end gjort. Vi er nødt til at vælge en passende algoritme til vores problem - husk de forskellige kategorier af maskinindlæring, vi talte om tidligere.

Det er ikke svært at forstå det vores problem passer ind i klassificeringen inden for den overvågede kategori. Nu er der en hel række algoritmer til rådighed til brug under denne kategori.

Den enkleste af dem er logistisk regression (lad ordet regression ikke forvirre os; det er trods alt en klassificeringsalgoritme):

LogisticRegressionModel model = ny LogisticRegressionWithLBFGS () .setNumClasses (3) .run (trainingData.rdd ());

Her bruger vi en tre-klasses BFGS-baseret klassifikator med begrænset hukommelse. Detaljerne i denne algoritme ligger uden for omfanget af denne tutorial, men dette er en af ​​de mest anvendte.

4.6. Modelevaluering

Husk, at modeluddannelse involverer flere iterationer, men for enkelheds skyld har vi lige brugt et enkelt pas her. Nu hvor vi har trænet vores model, er det tid til at teste dette på testdatasættet:

JavaPairRDD predictionAndLabels = testData .mapToPair (p -> new Tuple2 (model.predict (p.features ()), p.label ())); MulticlassMetrics metrics = nye MulticlassMetrics (predictionAndLabels.rdd ()); dobbelt nøjagtighed = metrics.accuracy (); System.out.println ("Modelnøjagtighed på testdata:" + nøjagtighed);

Nu, hvordan måler vi effektiviteten af ​​en model? Der er flere målinger, som vi kan bruge, men en af ​​de enkleste er nøjagtighed. Kort sagt, nøjagtighed er et forhold mellem det korrekte antal forudsigelser og det samlede antal forudsigelser. Her er hvad vi kan opnå i en enkelt kørsel af vores model:

Modelnøjagtighed på testdata: 0,9310344827586207

Bemærk, at dette vil variere lidt fra løb til løb på grund af algoritmens stokastiske natur.

Nøjagtighed er dog ikke særlig effektiv i nogle problemdomæner. Andet mere sofistikerede målinger er Precision and Recall (F1 Score), ROC Curve og Confusion Matrix.

4.7. Gemme og indlæse modellen

Endelig er vi ofte nødt til at gemme den uddannede model i filsystemet og indlæse den til forudsigelse på produktionsdata. Dette er trivielt i Spark:

model.save (sc, "model \ logistisk-regression"); LogisticRegressionModel sameModel = LogisticRegressionModel .load (sc, "model \ logistic-regression"); Vector newData = Vectors.dense (ny dobbelt [] {1,1,1,1}); dobbelt forudsigelse = sameModel.predict (newData); System.out.println ("Modelforudsigelse på nye data =" + forudsigelse);

Så vi gemmer modellen i filsystemet og indlæser den tilbage. Efter indlæsning kan modellen straks bruges til at forudsige output på nye data. Her er en prøveforudsigelse på tilfældige nye data:

Model forudsigelse på nye data = 2.0

5. Ud over det primitive eksempel

Mens eksemplet, vi gik igennem, dækker arbejdsgangen i et maskinlæringsprojekt bredt, efterlader det mange subtile og vigtige punkter. Selvom det ikke er muligt at diskutere dem detaljeret her, kan vi helt sikkert gennemgå nogle af de vigtige.

Spark MLlib gennem sine API'er har omfattende support på alle disse områder.

5.1. Modelvalg

Modelvalg er ofte en af ​​de komplekse og kritiske opgaver. Uddannelse af en model er en involveret proces og det er meget bedre at gøre på en model, som vi er mere sikre på, vil give de ønskede resultater.

Mens problemets art kan hjælpe os med at identificere den kategori af maskinlæringsalgoritme, vi kan vælge imellem, er det ikke et fuldt udført job. Inden for en kategori som klassifikation, som vi så tidligere, der er ofte mange mulige forskellige algoritmer og deres variationer at vælge imellem.

Tit den bedste fremgangsmåde er hurtig prototyping på et meget mindre sæt data. Et bibliotek som Spark MLlib gør jobbet med hurtig prototyping meget lettere.

5.2. Model Hyper-Parameter Tuning

En typisk model består af funktioner, parametre og hyperparametre. Funktioner er, hvad vi indfører i modellen som inputdata. Modelparametre er variabler, som modellen lærer under træningsprocessen. Afhængigt af modellen, der er visse yderligere parametre, som vi skal indstille baseret på erfaring og justere iterativt. Disse kaldes modelhyper-parametre.

For eksempel er læringshastigheden en typisk hyper-parameter i gradient-afstamningsbaserede algoritmer. Læringsgrad styrer, hvor hurtige parametre justeres under træningscyklusser. Dette skal indstilles passende, så modellen kan lære effektivt i et rimeligt tempo.

Mens vi kan begynde med en indledende værdi af sådanne hyperparametre baseret på erfaring, er vi nødt til at udføre modelvalidering og manuelt indstille dem iterativt.

5.3. Model præstation

En statistisk model er, mens den er uddannet tilbøjelige til over- og underudstyr, hvilket begge medfører dårlig modelydelse. Underfitting refererer til det tilfælde, hvor modellen ikke vælger de generelle detaljer fra dataene tilstrækkeligt. På den anden side sker overmontering, når modellen også begynder at opfange støj fra dataene.

Der er flere metoder til at undgå problemer med under- og overmontering, som ofte anvendes i kombination. For eksempel, for at imødegå overfitting inkluderer de mest anvendte teknikker krydsvalidering og regulering. På samme måde kan vi forbedre kompleksiteten i modellen og øge træningstiden for at forbedre underudstyret.

Spark MLlib har fantastisk understøttelse af de fleste af disse teknikker som regularisering og krydsvalidering. Faktisk har de fleste af algoritmerne standardstøtte til dem.

6. Spark MLlib i sammenligning

Mens Spark MLlib er et ret stærkt bibliotek til maskinindlæringsprojekter, er det bestemt ikke det eneste til jobbet. Der er et stort antal biblioteker tilgængelige på forskellige programmeringssprog med varierende support. Vi gennemgår nogle af de populære her.

6.1. Tensorflow / Keras

Tensorflow er en open source bibliotek til dataflow og differentierbar programmering, der er meget anvendt til maskinlæringsapplikationer. Sammen med dets høje niveau abstraktion, Keras, er det et valgfrit værktøj til maskinlæring. De er primært skrevet i Python og C ++ og bruges primært i Python. I modsætning til Spark MLlib har den ikke en polyglot-tilstedeværelse.

6.2. Theano

Theano er en anden Python-baseret open source bibliotek til manipulation og evaluering af matematiske udtryk - for eksempel matrixbaserede udtryk, som ofte bruges i maskinlæringsalgoritmer. I modsætning til Spark MLlib bruges Theano igen primært i Python. Keras kan dog bruges sammen med en Theano-bagende.

6.3. CNTK

Microsoft Cognitive Toolkit (CNTK) er en dyb læringsramme skrevet i C ++, der beskriver beregningstrin via en rettet graf. Det kan bruges i både Python- og C ++ - programmer og bruges primært til udvikling af neurale netværk. Der er en Keras-back-end baseret på CNTK tilgængelig til brug, der giver den velkendte intuitive abstraktion.

7. Konklusion

For at opsummere gik vi i denne vejledning gennem det grundlæggende inden for maskinindlæring, herunder forskellige kategorier og workflow. Vi gik gennem det grundlæggende i Spark MLlib som et maskinlæringsbibliotek, der er tilgængeligt for os.

Desuden udviklede vi en simpel maskinlæringsapplikation baseret på det tilgængelige datasæt. Vi implementerede nogle af de mest almindelige trin i maskinlæringsarbejdsprocessen i vores eksempel.

Vi gennemgik også nogle af de avancerede trin i et typisk maskinlæringsprojekt, og hvordan Spark MLlib kan hjælpe med dem. Endelig så vi nogle af de alternative maskinlæringsbiblioteker, som vi kunne bruge.

Som altid kan koden findes på GitHub.