Bygg en hjärna på 10 minuter med Nvidia
Idag ska vi bygga en mycket enkel hjärna. Inte en sci-fi-robot-hjärna, utan ett grundläggande neuralt nätverk som kan lära sig att känna igen bilder av kläder – specifikt med hjälp av Fashion MNIST-datamängden. Vårt mål? Att få en maskin att titta på en suddig gråskalebild och säga: ”Det där är en sneaker.”
Vi kommer att arbeta i TensorFlow och Keras, två populära bibliotek för djupinlärning i Python. Denna genomgång är inspirerad av NVIDIAs Deep Learning Institute.
Perceptronen, utvecklad av Frank Rosenblatt 1958, representerar en av de tidigaste milstolparna i neurala nätverks historia. Det var en enkel, enkelskiktad neural modell utformad för att efterlikna hur hjärnan lär sig genom trial and error. Även om dess kapacitet var begränsad (den misslyckades med att lösa problem som XOR), lade denna grundläggande forskning grunden för dagens djupinlärningssystem. Dokumentären fungerar som en påminnelse om hur tidiga ambitioner inom AI banade väg för de kraftfulla modeller vi bygger idag.
1. Kontrollera hårdvaran
Först och främst: är vår dator utrustad för djupinlärning? Vi ber TensorFlow att lista fysiska GPU-enheter. Dessa är som turboladdarna för träning av neurala nätverk. En CPU kan göra det, men det är som att tävla med en häst mot en småbarn.
import tensorflow as tf tf.config.list_physical_devices('GPU')
Om vi får ett svar som visar en GPU har vi tur. Träningen går snabbare.
2. Laddar datamängden
Vi ska nu ta oss an en utmaning som hade verkat nästan omöjlig för några decennier sedan: att träna en dator att känna igen bilder med hjälp av datorseende. Specifikt handlar vår uppgift om att identifiera olika typer av kläder i datamängden Fashion MNIST.
Inspirerade av hur människor lär sig genom trial and error, kommer vi att simulera denna process genom att använda digitala flashcards. Den artificiella hjärnan – vårt neurala nätverk – kommer att gissa vilka klädesplagg som visas, och vi kommer att korrigera den genom att ange de faktiska etiketterna. Med tiden lär den sig av både sina misstag och framgångar.
Precis som elever som förbereder sig för ett prov, kommer vi att hålla tillbaka en del av datan för att testa modellen. Detta säkerställer att vårt neurala nätverk inte bara memorerar vad det såg under träningen, utan faktiskt förstår uppgiften. Memorering kanske fungerar för trivia, men det räcker inte för att tillämpa resonemang, som att klassificera nya bilder eller utföra matematik.
Datan vi använder för att lära modellen kallas träningsdatamängden, medan den reserverade datan för testning kallas valideringsdatamängden. Eftersom Fashion MNIST är en välkänd datamängd, inkluderar TensorFlow den som standard. Så låt oss ladda den och se hur den ser ut.
fashion_mnist = tf.keras.datasets.fashion_mnist (train_images, train_labels), (valid_images, valid_labels) = fashion_mnist.load_data()
3. Visualisera ett urval
Innan vi ber ett neuralt nätverk att skilja mellan en sneaker och en tröja, är det bra att säkerställa att vi, som människor, faktiskt kan tolka datan själva.
Datamängden ger oss train_images och train_labels. Tänk på train_images som frågorna vi ställer till vår modell – vad den ser – och train_labels som de motsvarande svaren. Inom datavetenskap kallas dessa svar vanligtvis för etiketter.
För att bättre förstå indata kan vi visualisera en exempelbild med hjälp av Matplotlib, ett populärt plottningsbibliotek i Python.
import matplotlib.pyplot as plt data_idx = 69 plt.figure() plt.imshow(train_images[data_idx], cmap='gray') plt.colorbar() plt.grid(False) plt.show()
Detta visar oss en exempelbild. I detta fall, föremål #69. När du tittar på den kanske du säger, "Det där ser ut som ett falliskt föremål."
Och du har förmodligen rätt, men det är faktiskt ett par byxor:
train_labels[data_idx] # Output: 1
Etikett 1 motsvarar "byxor". Bra jobbat, människa. Här har vi en utmärkt tabell för att hjälpa oss att se de olika kategorierna.
4. Definiera modellen
Neuroner är de väsentliga enheterna som utgör ett neuralt nätverk. I biologisk mening skickar neuroner elektriska signaler när de får rätt typ av stimulus, detta hjälper dig att skilja mellan rött och gult till exempel. Artificiella neuroner gör något liknande, förutom att de arbetar med siffror – när du matar in vissa värden, producerar de ett numeriskt resultat.
Du kan tänka dig att skapa en neuron i tre huvudsteg:
-
Först definierar vi dess struktur (detta är dess arkitektur).
-
Därefter tränar vi den med data.
-
Slutligen bedömer vi hur väl den presterar.
Bygga strukturen
Biologiska neuroner använder ett system som liknar morsekod för att skicka information. De tar emot signaler via sina dendriter, och om insignalen uppfyller rätt villkor skickar de en puls längs axonen till neuronens terminaler.
Man tror att både tidpunkten och sekvensen av dessa pulser bidrar till att förmedla information. De flesta artificiella neurala nätverk replikerar ännu inte denna tidsmässiga komplexitet. Istället modellerar de beteendet med matematiska ekvationer.
Hur matematiken fungerar
Datorer hanterar information som sekvenser av 0 och 1, medan människor och djur fungerar med mer kontinuerliga insignaler. Tidiga artificiella neuroner försökte imitera biologiska med hjälp av en linjär regressionsfunktion: y = mx + b. Här är x insignalen (liknar signaler som går in i dendriter), och y utsignalen (som impulsen som lämnar terminalerna). När systemet ser mer data och förutsägelser, justerar det värdena för m och b för att förbättra noggrannheten.
Neuroner behöver ofta bearbeta många insignaler samtidigt. I vårt exempel kommer vi att behandla varje pixel i en bild – var och en med ett värde mellan 0 (svart) och 255 (vitt) – som en separat insignal. Var och en av dessa insignaler får sin egen vikt (liknar vårt m), och dessa vikter betecknas med w. Så pixel ett har w0, pixel två har w1, och så vidare. Detta förvandlar vår ekvation till något i stil med: y = w0x0 + w1x1 + w2x2 + ... + b.
Eftersom varje bild är 28 pixlar bred och 28 pixlar hög, får vi totalt 784 vikter. Varje pixel bidrar till slutresultatet, och vi kan titta direkt på råvärdena från bilden vi visualiserade tidigare. Var och en av dessa pixelnummer kommer att multipliceras med sin motsvarande vikt.
Vi har använt en enkel ekvation, y = mx + b, som ger oss ett enda nummer som utdata. Men saken är – vi försöker känna igen typer av kläder, inte bara mata ut ett nummer. Så hur förvandlar vi ett enkelt nummer till ett beslut som ”Det här är en T-shirt” eller ”Det där är en sneaker”?
En enkel lösning är att använda flera utdata – specifikt en neuron för varje klädtyp. Eftersom det finns tio kategorier i Fashion MNIST-datamängden, kommer vi att använda tio neuroner. Var och en kommer att specialisera sig på att upptäcka en specifik klass (som byxor, etiketterad som klass 1). Neuronen som producerar det största numret (dvs. är mest ”säker”) avgör vilken klass modellen väljer för den inmatade bilden.
Vi kan enkelt skapa den här typen av inställning med Keras, ett högnivå-API som nu är en del av TensorFlow. Vi kommer att använda dess Sequential API, som låter oss organisera vår modell som en serie staplade lager. Tänk på lager som bearbetningssteg som tar indata och omvandlar den till förutsägelser.
Modellen vi ska skapa har två lager:
-
Ett Flatten-lager, som tar vår 28×28-bild och omformar den till en enda lista med 784 värden.
-
Ett Dense-lager, som innehåller 10 neuroner – var och en ansluten till varje inmatningspixel, och var och en tilldelad en vikt. Dessa neuroner kommer att beräkna ett poäng som berättar hur sannolikt det är att den inmatade bilden tillhör deras respektive klädkategori.
Vi kommer också att specificera en input_shape på (28, 28), vilket matchar pixeldimensionerna för varje bild.
number_of_classes = 10 model = tf.keras.Sequential([ tf.keras.layers.Flatten(input_shape=(28, 28)), tf.keras.layers.Dense(number_of_classes) ])
Verifierar modellen
För att säkerställa att vår modell har den struktur vi tror den har, kan vi anropa dess summary-metod. Så här ser utdatan ut:
Låt oss förklara varifrån siffran – 7 850 – kommer ifrån. Varje 28×28 bild har 784 pixlar. För varje av de 10 utdataneuroner (som representerar de 10 klasserna) behöver vi en unik vikt för varje av dessa 784 ingångar. Det är 784 * 10 = 7 840 vikter. De ytterligare 10 parametrarna är bias – en för varje utdataneuron – vilket ger totalt 7 840 + 10 = 7 850. Dessa bias fungerar som b i ekvationen y = mx + b, vilket gör att varje neuron kan justera sin aktiveringsbaslinje oberoende.
I akademisk litteratur visualiseras modellarkitekturer ibland som nod-länkdiagram. Även om sådana diagram fungerar för små nätverk, blir de otympliga med moderna modeller. Diagrammet som refereras här representerar endast en liten del av vår modell: 28 ingångsnoder överst (som representerar en rad i bilden) och 10 utgångsneuroner längst ner. I verkligheten skulle vi ha 784 ingångar – en för varje pixel.
Varje punkt representerar antingen en ingång eller en neuron, och varje anslutande linje är en vikt – en av de 7 840 inlärbara parametrarna.
Slutligen finns det ett annat sätt att visuellt verifiera vår modell: du kan plotta den. Var dock varnad – när nätverk blir komplexa blir dessa diagram mer abstrakt konst än användbara verktyg.
Model: "sequential"
| Layer (type) | Output Shape | Param # |
| flatten (Flatten) | (None, 784) | 0 |
| dense (Dense) | (None, 10) | 7,850 |
Total params: 7,850 (30.66 KB)
Trainable params: 7,850 (30.66 KB)
Non-trainable params: 0 (0.00 B)
5. Initiera träning
Före träning kompilerar vi modellen med en förlustfunktion och en optimerare.
Vi har byggt en modell – men hur hjälper vi den att förbättras? Tänk dig det som att ge en elev ett prov och ett svarsblad. Vi behöver ett sätt att utvärdera hur långt ifrån de korrekta svaren modellens svar är. Det är vad förlustfunktionen gör: den beräknar skillnaden mellan modellens förutsägelse och den faktiska etiketten, så den vet hur den ska justera sina interna inställningar.
För klassificeringsproblem som vårt kommer vi att använda en specifik typ av förlustfunktion som kallas SparseCategoricalCrossentropy. Här är vad varje del av namnet berättar:
-
Sparse – Istället för att använda one-hot-kodade etiketter (där varje klass representeras av en vektor med en etta och resten nollor), fungerar den här funktionen med heltalsetiketter (t.ex. 0 till 9). Så våra kategorier indexeras numeriskt.
-
Categorical – Den är byggd för klassificeringsuppgifter, där vi förutsäger en kategori snarare än ett kontinuerligt värde.
-
Cross-entropy – Denna del straffar felaktiga, säkra förutsägelser hårdare. Om vår modell är helt säker på att den har rätt och visar sig ha fel, får den ett mycket dåligt betyg – i praktiken negativ oändlighet!
Denna förlustfunktion passar bra för vår modell eftersom den utvärderar alla tio utdataneuroner samtidigt. Om flera neuroner starkt signalerar att deras klass är den korrekta, griper denna funktion in och säger: ”Tyvärr, gott folk – bara en av er kan ha rätt.”
För att gå bortom bara förlust kan vi inkludera andra mått – som noggrannhet – för att ge oss en bättre bild av prestandan. Ibland kan förlusten vara låg (vilket tyder på goda förutsägelser i genomsnitt), men den faktiska noggrannheten kan vara eftersläpande. Mått hjälper till att lyfta fram den skillnaden.
model.compile( optimizer='adam', loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True), metrics=['accuracy'] )
-
adam: En populär optimerare som anpassar inlärningshastigheter adaptivt. -
SparseCategoricalCrossentropy: Används när våra etiketter är heltal (0-9), inte one-hot-vektorer. -
from_logits=True– Detta talar om för funktionen att modellens utdata är i rå poängform (logits) och ännu inte har omvandlats till sannolikheter. Förlustfunktionen hanterar den omvandlingen internt.
6. Träna modellen
Här kommer den spännande delen – där vår modell får träna och testa sig själv. Fit-metoden i TensorFlow är det som får detta att hända. Den låter modellen lära sig av träningsdatan och även testa sig själv med hjälp av valideringsdatan.
Inom maskininlärningsjargongen representerar en epok en fullständig genomgång av hela träningsdatamängden. Det är som en elev som går igenom alla sina flashcards en gång. Och precis som människor ofta behöver repetera samma material flera gånger innan de helt förstår det, drar även vår modell nytta av att se tränings exemplen flera gånger.
Vid slutet av varje epok pausar modellen sin studiesession och tar en snabb frågesport med hjälp av valideringsdatauppsättningen. Detta hjälper oss att mäta hur mycket den faktiskt lär sig kontra hur mycket den bara memorerar. Dags att se den arbeta och bli smartare!
history = model.fit(
train_images, train_labels,
epochs=5,
validation_data=(valid_images, valid_labels)
)
Så, hur presterade vår modell? Kanske ett stabilt B-minus? Låt oss ge den en paus – den arbetade bara med 10 neuroner, medan den mänskliga hjärnan har miljarder som aktiveras samtidigt.
Vi kan förvänta oss att modellens noggrannhet hamnar runt 80 %, även om den siffran inte är fast. Resultatet kan variera något på grund av hur träningsbilderna (våra digitala flashcards) blandades och den slumpmässiga initieringen av modellens vikter vid träningsstarten. En viss slumpmässighet är inbakad i varje körning, så inga två träningspass är helt identiska.
7. Göra förutsägelser
Nu när vår modell har tränats klart är det dags att testa den i den verkliga världen. Vi gör detta med hjälp av predict-metoden, som låter oss se modellens förutsägelser på vilken bild som helst, oavsett om den kommer från träningsdatauppsättningen eller är helt ny.
Tänk på att Keras alltid förväntar sig indata i omgångar – även om det bara är en bild. Så, för att göra en förutsägelse på en enskild bild, måste vi fortfarande skicka den som en omgång med ett objekt.
Låt oss titta på vad modellen förutsäger för de första 10 bilderna i vår träningsdata. Den råa utdata från modellen består av numeriska värden som kallas logiter. Dessa siffror visar hur säker var och en av de 10 utdataneuronerna är på att klassificera bilden som ett specifikt klädesplagg.
Vi visualiserar både inmatningsbilden och ett stapeldiagram som kartlägger logiterna. Ett högre nummer betyder att modellen är mer säker på att den klassen är den korrekta. Negativa värden, å andra sidan, visar att modellen är ganska säker på att den specifika klassen är felaktig.
Du kan ändra värdet data_idx för att se förutsägelser för olika exempel. Hur korrekt tycker du att det är? När den gör misstag, är de förståeliga?
plt.imshow(train_images[data_idx], cmap='gray') plt.show() predictions = model.predict(train_images[data_idx:data_idx+1]) plt.bar(range(10), predictions.flatten()) plt.xticks(range(10)) plt.show() print("correct answer:", train_labels[data_idx])
Detta ger oss en visuell uppdelning av hur säker modellen är i var och en av de 10 kategorierna. Den högsta stapeln bör idealt matcha den faktiska klassen. I det här exemplet? Det var en sneaker. Fullträff.
Vi får ett stapeldiagram som visar modellens säkerhet i varje klass. Helst är stapeln för klass 7 den högsta. Det betyder att modellen tror att bilden med största sannolikhet är en sneaker.
Boom. Det var en sneaker.
Slutsats
Och det, kära lyssnare, är hur man bygger en hjärna på 10 minuter. Den är inte medveten, den drömmer inte, men den känner igen skor.
Vi använde:
-
TensorFlow och Keras för modellbyggande
-
Fashion MNIST för data
-
Matplotlib för visualisering
Viktigare är att vi såg hela flödet: ladda data, visualisera, bygga en modell, träna den och kontrollera dess förutsägelser.
I praktiken är detta bara början. Bättre modeller skulle använda djupare lager, dropout för regularisering och datanormalisering. Men om du förstod detta, förstår du kärnan i maskininlärning.
Maskinen förändrade inte världen ännu, men kanske blev din just lite smartare.