ในโพสต์นี้ เราจะเรียนรู้ Basics ของ Neural Networks และการ Implement ด้วย Ruby! ถ้าคุณสนใจ AI และ Deep Learning แต่ไม่แน่ใจจะเริ่มยังไง โพสต์นี้สำหรับคุณ! เราจะเดินผ่านตัวอย่างง่ายเพื่อ Highlight Key Concepts มัน Unlikely มากที่คุณจะใช้ Ruby เขียน Multi-layer Neural Networks จริง แต่เพื่อ Simplicity และ Readability มันเป็นวิธีดีเข้าใจว่ากำลังเกิดอะไรขึ้น แรก มาย้อนกลับดูว่าเรามาถึงที่นี่ยังไง
A still from the movie Ex Machnia. Photo credit
Ex Machina เป็นหนัง Release 2014 ถ้า Search Title บน Google จะ Classify Genre ว่า "Drama/Fantasy" และตอนผมดูครั้งแรก มันดูเหมือน Science Fiction จริงๆ
แต่มัน นานกว่านั้นมากไหม?
ถ้าถาม Ray Kurzweil Futurist 名ชื่อดังที่ Google ปี 2029 อาจเป็นปีที่ AI จะผ่าน Turing Test ที่ถูกต้อง (Experiment ดูว่ามนุษย์แยกแยะ Machine/Computer กับ Human อีกคนได้ไหม) เขายัง Predict ว่า Singularity (Computer Surpass Human Intelligence) จะเกิดขึ้น 2045
อะไรทำให้ Kurzweil มั่นใจ?
The Emergence of Deep Learning
ง่ายๆ Deep Learning เป็น Subset ของ Machine Learning ใช้ Neural Networks Extract Insights จาก Large Amounts of Data Real-world Applications รวมถึง: - Self-driving Cars - Cancer Detection - Virtual Assistants เช่น Siri และ Alexa - Predicting Extreme Weather Events เช่น Earthquakes
แต่มันคือ "Neural Network" อะไร?
Neural Networks ได้ชื่อจาก Neurons เซลล์สมองที่ Process และ Transmit Information ผ่าน Electrical และ Chemical Signals Fun Fact: Human Brain ประกอบด้วย 80+ Billion Neurons!
ใน Computing Neural Network 长这样:
ตัวอย่าง Neural Network Diagram. Photo credit
เห็นได้ 3 ส่วน: 1) Input Layer -- Initial Data 2) Hidden Layer(s) -- Neural Network สามารถมี 1 (หรือมากกว่า) Hidden Layers นี่คือที่ Computation ทั้งหมดเกิดขึ้น! 3) Output Layer -- End Result/Prediction
Quick History Lesson
Neural Networks ไม่ใหม่ จริงๆ First Trainable Neural Network (Perceptron) พัฒนาที่ Cornell University ใน 1950s แต่มี Pessimism มากเกี่ยว Applicability หลักเพราะ Original Model มีแค่ Hidden Layer เดียว หนังสือ Publish 1969 ชี้ว่า Perceptron สำหรับ Computations ง่ายๆ จะ Impractical
Resurgence ของ Neural Networks มาจาก Computer Games ต้องการ GPUs High-powered ที่ Architecture ใกล้เคียง Neural Net ความต่างคือจำนวน Hidden Layers แทนที่จะเป็นหนึ่ง Neural Networks ตอนนี้ Train ใช้ 10, 15, หรือ 50+ Layers!
Example Time!
เข้าใจการทำงาน มาดูตัวอย่าง ต้อง Install ruby-fann Gem เปิด Terminal ไป Working Directory รัน:
gem install ruby-fann
สร้าง Ruby File ใหม่ (ผมตั้ง neural-net.rb)
ต่อไป ใช้ Dataset "Student Alcohol Consumption" จาก Kaggle Download ได้ที่นี่ เปิด student-mat.csv ใน Google Sheets (หรือ Editor ที่ชอบ) ลบ Columns ทั้งหมดยกเว้น: - Dalc (Workday Alcohol Consumption 1=Very Low, 5=Very High) - Walc (Weekend Alcohol Consumption 1=Very Low, 5=Very High) - G3 (Final Grade 0-20)
เราต้องเปลี่ยน Final Grade Column ให้เป็น Binary -- 0 หรือ 1 -- เพื่อ ruby-fann Gem ทำงาน ตัวอย่างนี้ สมมติ <= 10 คือ "0" และ > 10 คือ "1" ขึ้นกับ Program ที่ใช้ คุณควรเขียน Formula ใน Cell เปลี่ยน Value เป็น 1 หรือ 0 ตาม Cell Value ใน Google Sheets ประมาณ:
=IF(C3 >= 10, 1, 0)
Save เป็น .CSV (ผมตั้ง students.csv) ใน Directory เดียวกับ Ruby File
Neural Network ของเราจะมี Layers: - Input Layer: 2 Nodes (Workday และ Weekend Alcohol Consumption) - Hidden Layer: 6 Hidden Nodes (Arbitrary เริ่มต้น แก้ได้ตอน Test) - Output Layer: 1 Node (0 หรือ 1)
แรก Require ruby-fann Gem และ Built-in csv Library บรรทัดแรก:
require 'ruby-fann' require 'csv'
ต่อไป Load Data จาก CSV เข้า Arrays
# สร้างสอง Empty Arrays หนึ่งเก็บ Independent Variables (x_data) อีกอัน Dependent Variable (y_data) x_data = [] y_data = [] # Iterate CSV Data เพิ่ม Elements เข้า Arrays ที่เกี่ยวข้อง # ถ้าไม่เพิ่ม .to_f และ .to_i Arrays จะมี Strings และ ruby-fann Library จะไม่ High CSV.foreach("students.csv", headers: false) do |row| x_data.push([row[0].to_f, row[1].to_f]) y_data.push(row[2].to_i) end ต่อไป แบ่ง Data เป็น Training และ Testing Data 80/20 Split พบบ่อย 20% Test 80% Train "Training" หมายถึง Model เรียนรู้จาก Data นี้ แล้วใช้ "Testing" Data ดูว่า Model Predict Outcomes ได้ดีแค่ไหน
# แบ่ง Data Training Set และ Test Set testing_percentage = 20.0 # นำ Total Elements คูณ Test Percentage testing_size = x_data.size * (testing_percentage/100.to_f) # เริ่มต้นที่ 0 จบที่ testing_size - 1 เนื่องจาก Arrays 0-indexed x_test_data = x_data[0 .. (testing_size-1)] y_test_data = y_data[0 .. (testing_size-1)] # ต่อจากที่หยุดจนสิ้นสุด Dataset x_train_data = x_data[testing_size .. x_data.size] y_train_data = y_data[testing_size .. y_data.size] Cool! Data พร้อม ต่อไป Magic!
# Setup Training Data Model train = RubyFann::TrainData.new(:inputs=> x_train_data, :desired_outputs=>y_train_data) ใช้ RubyFann::TrainData Object ส่ง x_train_data (Workday และ Weekend Alcohol Consumption) และ y_train_data (0 หรือ 1 จาก Final Grade)
ตอน Setup Neural Network Model ด้วย Hidden Neurons ที่พูดไป
# Setup Model และ Train ด้วย Training Data model = RubyFann::Standard.new( num_inputs: 2, hidden_neurons: [6], num_outputs: 1 ); OK Train!
model.train_on_data(train, 1000, 10, 0.01) ส่ง train Variable ที่สร้างก่อน 1000 = Max Epochs, 10 = Errors Between Reports, 0.01 = Desired Mean-squared Error One Epoch = ทั้ง Dataset ผ่าน Neural Network Mean-squared Error = สิ่งเราพยายาม Minimize อ่านเพิ่มได้ที่นี่
ต่อไป อยากรู้ Model ทำได้ดีแค่ไหน เปรียบเทียบ Predictions บน Test Data กับ Actual Results ทำได้ด้วย Code นี้:
predicted = [] # Iterate x_test_data รัน Model ทุกตัว เพิ่มเข้า Predicted Array x_test_data.each do |params| predicted.push( model.run(params).map{ |e| e.round } ) end # Compare Predicted กับ Actual correct = predicted.collect.with_index { |e,i| (e == y_test_data[i]) ? 1 : 0 }.inject{ |sum,e| sum+e } # Print Accuracy Rate puts "Accuracy: #{((correct.to_f / testing_size) * 100).round(2)}% - test set of size #{testing_percentage}%" รัน Program ดูสิ!
ruby neural-net.rb
ควรเห็น Output เยอะสำหรับ Epochs แต่ท้ายควรเห็นแบบนี้:
Accuracy: 56.82% - test set of size 20.0%
Oof ไม่ดีนัก! แต่ลองสร้าง Data Points เองและ Run Model
prediction = model.run( [1, 1] ) # Round Output ได้ Prediction puts "Algorithm predicted class: #{prediction.map{ |e| e.round }}" prediction_two = model.run( [5, 4] ) # Round Output ได้ Prediction puts "Algorithm predicted class: #{prediction_two.map{ |e| e.round }}" นี่สอง Examples แรก ส่ง 1s สำหรับ Weekday และ Weekend Alcohol Consumption ถ้าผมเดิมพัน ผมเดา Student นี้ Grade > 10 (คือ 1) ตัวที่สอง ส่งค่าสูง (5 และ 4) ผมเดา Grade <= 10 (คือ 0) รันอีกครั้งดู!
Output ควรประมาณ:
Algorithm predicted class: [1] Algorithm predicted class: [0] Model ทำตามที่คาดสำหรับ Numbers ขั้วต่ำ/สูง แต่ Struggles ตอน Numbers Opposites (ลอง 1 และ 5, หรือ 2 และ 3) หรือ Middle จาก Epoch Data Error ลดลงแต่ยังสูง (Mid-20%) หมายถึงอาจไม่มี Relationship ระหว่าง Alcohol Consumption และ Course Grades ผมแนะนำเล่นกับ Original Dataset จาก Kaggle -- มี Independent Variables อื่น Predict Course Outcomes ได้ไหม?
Wrap-Up
มี Intricacies เยอะ (ส่วนใหญ่ Math) Under the Hood ทำให้มันทำงาน ถ้าสนใจอยากเรียนรู้เพิ่ม แนะนำ Docs FANN หรือ Source Code ruby-fann Gem แนะนำ Documentary "AlphaGo" บน Netflix -- ไม่ต้อง Technical Knowledge มาก ก็ Enjoy ได้ และให้ Real-life Example ของ Deep Learning Pushing Limits ของ Computers
Kurzweil จะถูกหรือไม่? เวลาจะบอก!