ว่าด้วย Recurrent Neural Networks: Part 1

ไม่ได้เขียนบล็อคซะนานเนื่องจากป่วยไปพักใหญ่ ตอนนี้กลับมา จะเริ่มกลับมาเขียนแล้วครับ โดยเรื่องที่ผมคิดไว้คราวนี้จะเป็น “การทำนายอนาคตของข้อมูล Time series” ครับ เพราะเป็นช่วงเวลาที่พอดีกับที่ผมต้องสรุปผลการทดลองส่งแลปพอดีครับ เลยจะขีด ๆ เขียน ๆ ตามไปด้วยเลยก็แล้วกัน

ในยุคที่ Deep Learning กำลังครองโลกอยู่นี้ก็คงหลีกเลี่ยงไม่ได้ที่จะต้องกล่าวถึง Recurrent Neural Network (RNN) แต่ก่อนจะไปถึงจุดนั้นเราจะเริ่มจากอะไรที่เบสิก ๆ ก่อน โดยบทความแรกจะเริ่มตั้งแต่เรื่องพื้นฐาน ว่าด้วย Neural Network จาก Linear regression ไปจนถึง Simple Recurrent Neural Network (Simple RNN)

Time series และ Simple Neural Network

ข้อมูลของเราจะเป็น “Time series” หรือ “อนุกรมเวลา” ได้ ก็ต่อเมื่อ “มีอินเด็กซ์เวลา” มาเกี่ยวข้องนั่นแหละครับ ตัวอย่างเช่น ข้อมูลยอดขายสินค้าแต่ละไตรมาส ข้อมูลผู้โดยสารสายการบินแต่ละเดือน หรือ ราคาหุ้น ไม่ว่าจะเป็นรายวัน รายเดือน หรือ รายปีจริงๆ จะรายอะไรก็ได้ครับแต่ต้องมีเวลามาเกี่ยวข้องจึงจะเป็นอนุกรมเวลาได้!

สมมุติว่าเราต้องการทำนายอนาคตของข้อมูล เช่น ทำนาย Demand (ความต้องการ) ของปริมาณผู้โดยสารเดือนหน้า เพื่อให้สายการบินเตรียมความพร้อมสำหรับ Supply (การตอบสนองความต้องการ) ของผู้โดยสายเหล่านั้น

หรือ จะเป็น การทำนายราคาหุ้นวันถัดไปด้วยข้อมูลหุ้น 3 วันก่อนหน้า ตามรูป เราจะใช้ข้อมูลวันที่ 1, 2, 3 ไปทำนายวันที่ 4 จากนั้นเราจะเลื่อนข้อมูลไป 1 วัน คือเอาวันที่ 2, 3, 4 ไปทำนายวันที่ 5 ไปเรื่อยๆ การเอาข้อมูลวันก่อนๆของตัวเองมาทำนายแบบนี้ ทางสถิติเค้าเรียกว่า “Autoregressive” ครับ

ตัวอย่างการทำนายข้อมูลด้วยข้อมูลตัวเอง Autoregressive

ถ้าเรามองเป็นสมการจะอยู่ในรูปแบบนี้

สมการที่ดูๆไปก็เหมือน Linear Regression

สุดท้ายแล้วราคาวันนี้อาจจะมาจาก ค่าคงที่ b รวมกับ 0.75 ของราคาเมื่อวาน บวกด้วย 0.1 ของราคาเมื่อวานซืน และ 0.03 ของราคาเมื่อวานของเมื่อวานซืน! เป็นต้น ดูไปดูมาแล้วเราก็คุ้นเคยกับสมการนี้เพราะการใช้ข้อมูลตัวเองเพราะมันก็คือ สมการของ Linear regression นั่นเองซึ่ง Linear regression ถ้าเราวาง Sigmoid function ที่จะให้ค่า 0 หรือ – 1 ไว้ด้านหน้ามันก็จะกลายเป็น Logistic regression ที่สามารถนำมาหาความน่าจะเป็นสำหรับการจำแนกประเภทได้ พอเขียนให้เป็นทางการหน่อยก็จะได้สมการแบบนี้

มาวาง Sigmoid หน้าสมการเดิม
Image result for neural network logistic regression
Logistic Regression

และเมื่อนำมาวางเป็นโครงข่ายมันก็จะเป็น Artificial neural network (ANN)

Image result for neural network
โครงสร้าง Neural Network

โดยที่ Hidden layer แต่ละชั้นก็ทำหน้าที่คล้ายๆ Logistic regression ด้านบนแต่ในขั้นนี้เราจะเรียกว่า Perceptron โดยที่เราอาจจะเปลี่ยน Activation fucntion เป็นตัวอื่นนอกเหนือจาก Sigmoid ได้ เช่น Relu, Tanh, Selu และอีกมากมาย ถ้าเราลองมองดูดีๆมันก็เหมือนการ Transform feature ข้อมูล x ไปเรื่อยๆจนถึงชั้น Output ที่เราจะตัดสินใจ แต่เราจะไม่ลงรายละเอียดในบล็อกนี้ก่อนแล้วกันครับ ก่อนอื่นไปดูสมการเมื่อมันเป็น Neural network แล้วกันดีกว่า

สมการ neural network

โดย h เป็นของชั้น Hidden i เป็นของชั้น Output จะเห็นว่าจากก่อนที่เราจะรับข้อมูล x เข้ามาแล้วคำนวณ Output ตรงๆมันก็จะรับข้อมูล x เข้ามาไปคำนวณในชั้น Hidden layer h ก่อน จึงส่งไปชั้นต่อๆไป จากนั้นก็จะไปยังชั้นสุดท้ายคือชั้น Output i แล้วจึงคำนวณ Output ซึ่ง Hidden layer ในที่นี้อาจจะมีหลายชั้นก็ได้

ปัญหาก็คือ ตรงชั้น input มันเป็นเพียงการ Flatten ข้อมูล x แล้วส่งไปยังชั้นต่อๆไปเปรียบดั่งการ Transform feature ไปเรื่อยๆก่อนจะคำนวณ Output เท่านั้น ไม่ได้เอาข้อมูลจาก state ก่อนๆมาร่วมด้วยเลย เค้าเลยคิดโครงสร้างของ Neural network ขึ้นมาอีกรูปแบบเพื่อตอบปัญหานี้

Simple Neural Network

Simple Recurrent Neural Network

“RNN (Recurrent Neural Network)” เป็นโมเดลที่ถูกสร้างมาเพื่อแก้ปัญหาข้างต้น ชื่อ Recurrent มันก็แปลตรงตัวแล้วว่าจะมี “การเกิดซ้ำ” กล่าวคือ มีการเรียก hidden state จาก state ก่อนๆมา เช่น เรียกข้อมูลจาก Hidden state h(t-1) ที่ได้จากการคำนวณจากข้อมูล x(t-1) มารวมคำนวณกับ Hidden state h(t) ที่ได้จากากรคำนวณจากข้อมูล x(t) ด้วยนั่นเอง

Simple RNN

จากรูปเราจะเห็นว่าที่ Hidden State h(t) จะมีการส่งข้อมูลซ้ำมายัง Hidden State ตัวเองในรอบต่อๆไปด้วยมองเป็นรูปภาพอาจจะงงๆ เรามาดูสมการกันดีกว่า

สมการ Simple RNN

สิ่งที่เพิ่มขึ้นมามีแค่อย่างเดียวเลยนะครับ แค่เพิ่ม h(t-1) ที่ส่งจาก Neuron state ที่แล้วของตัวเองมาใช้งานต่อ โดยที่ Weight w_hh คือขนาดเท่ากับจำนวน Hidden unit ขณะที่ Weight w_xh คือ Weight ที่มีขนาดเท่ากับข้อมูล x ที่ส่งมายัง hidden unit นั่นเอง พอมันมีการส่ง state ข้อมูลในอดีตมาด้วยแบบนี้ย่อมทำให้โครงข่ายสามารถหาความสัมพันธ์ของมันผ่านช่วงเวลาได้นั่นเอง RNN จึงเป็นโมเดลที่เหมาะกับข้อมูล Time Series มากกว่าโมเดล ANN แบบ ธรรมดา(และในเชิงเทคนิคก็ประหยัด Parameter ที่โครงข่ายต้องปรับจูนอีกด้วย)

ถ้าเรา Unroll simple RNN ออกมาดูเป็นรอบๆจะได้ดังนี้

Simple RNN ตอนทำนาย y1

จะเห็นว่ามีแค่ข้อมูล x1 เท่านั้นที่ไปเข้า Hidden state h1 และทำนาย y1 (ตามเส้นสีแดง)อันนี้ก็ธรรมดาแต่ค่าใน h1 เราไม่ได้ทิ้งเลยซะทีเดียวยังมีการส่งต่อไปยัง state อื่นๆด้วย

Simple RNN ตอนทำนาย y2

พอมาถึงรอบที่ 2 จะมีการส่งข้อมูลจาก Hidden state h1 ที่คำนวณจากข้อมูล x1 ส่งไปคำนวณที่ Hidden state h2 ที่มีการรับข้อมูลจากข้อมูล x2 โดยตรงด้วย

Simple RNN ตอนทำนาย y3

พอทำนาย y3 เราก็จะได้ information จากข้อมูลเก่าๆมาร่วมกับข้อมูลใหม่ x3 ด้วยเช่นกัน จะเห็นด้วยการวางโครงสร้างลักษณะนี้จึงสามารถความสัมพันธ์ของข้อมูลผ่านช่วงเวลาได้ โดยร่างให้เห็นเป็น Pseudocode ได้ดังนี้

Pseudocode RNN

จากนั้นมาดูเป็น Code Numpy กันบ้าง

Numpy RNN #1

ส่วนนี้แค่ import library และกำหนดตัวแปร โดยผมกำหนดให้ Input x มี 5 Feature และ output 1 Feature dimension

Numpy RNN #2

กำหนดตัวแปร Weight 2 ตัว โดย W_xh ทำหน้าที่เชื่อมต่อจากข้อมูลดิบไปยัง Hidden State ส่วน W_hh ทำหน้าที่เป็นเชื่อมต่อจาก Hidden State ไป ยัง Hidden State ต่อไป

Numpy RNN #3

จากนั้นเราสร้าง Loop ผ่านข้อมูลทั้งหมด X ไปดึงข้อมูล x_t ออกมาทีละตัว จากนั้นเราจะคำนวณ ผลลัพธ์ y_t โดยการ ทำขั้นตอนดังนี้

  1. dot product ระหว่างข้อมูลดิบ x_t กับ Weight W_xh
  2. dot product ระหว่างของ State ที่ผ่านมา h_t-1(ผมใช้ตัวแปร h) กับ Weight W_hh
  3. จากนั้นนำค่าทั้งสองมาบวกกัน
  4. นำค่าที่ได้จากการบวกไปเข้าสมการ Tanh จากนั้นไปเก็บไว้ในตัวแปร y_t

จากนั้นเราก็จะเก็บค่าไว้ทำงาน 2 อย่างดังนี้

  1. นำ y_t ไปเก็บไว้ในตัวแปร h เพื่อเตรียมนำไปใช้ในการคำนวณรอบต่อไป
  2. นำ y_t ไปเก็บไว้ในตัวแปร Y เพื่อเก็บเป็น output ต่อไป

และกระบวนการนี้ก็จะเกิดซ้ำกันไปเรื่อยๆจนจบกระบวนการ จะเห็นว่าการที่เราเรียกซ้ำข้อมูล(Recursive)จาก state ที่ผ่านมาเข้ามาคำนวณด้วยในรูปแบบนี้ มันจึงเป็นที่มาของชื่อ Recurrent Neural Network นั่นแหละครับ

จริงๆผมไม่อยากลงรายละเอียดมาก เพราะโมเดล Simple RNN มันยังเป็นอะไรที่พื้นฐานมากๆ ไว้เราจะมาว่ากันละเอียดที่โมเดลลึกลงไปอย่าง GRU LSTM กันดีกว่าครับ ตอนนี้มาดูผลการทดลองกันก่อน

ผลการทดลองทำนาย iShares S&P 500 Value Index

พูดกันมายาวแล้ว ที่ผมบอกว่าผมได้ไปลองใช้ RNN จัดการข้อมูลหุ้น! เรามาดูกันเลยดีกว่าครับ มันจะได้ผลหรือ ไม่ได้ผล อย่างไร!

ข้อมูล Tick data ที่ผ่านการ Resample แบบ Dollar bar มาแล้ว

ข้อมูลที่ใช้ทดลองเป็นข้อมูลที่ผมเคยเขียนบทความไปก่อนหน้าเรื่องการ Resample data ให้มีการแจกแจงเป็น Normal distribution มากขึ้นในโพสก่อน โดยเราจะใช้ 1600 point แรกเป็นข้อมูล Training set (In-sample) และข้อมูลที่ 1601 – 2000 เป็นข้อมูล Testing set (Out-of-Sample)

ลิงกค์บทความเรื่อง Resamping data

ทำนายแบบ Regression

ก่อนอื่นเราจะนำข้อมูลมาทำนายราคาของช่วงเวลาถัดไป 1 ช่วงเวลา **สาเหตุที่ไม่ใช้คำว่าวันเพราะข้อมูลนี้ผ่านการ Resample มาแบบ Dollar bar นั่นเอง

Loss function จากการรัน Simple RNN แบบ Regression เป็นจำนวน 100 Epoch
ผลการทำนายแบบวันต่อวันของ Simple RNN

จะเห็นว่าผลการทำนายมันดูดีเลยใช่ไหมครับ แต่จริงๆไม่ใช่หรอกครับ เพราะช่วงต้นที่ดูทำนายได้ดีมากๆนั้นเป็นข้อมูล In-sample ข้อมูล Out-of-sample จริงๆอยู่ที่ Data point ที่ 1601 ขึ้นไป ดูจากสายตาก็กะได้ว่ามันผิดพลาดไม่น้อยแล้วครับ ตรงส่วนนี้เราจะค่อยๆแก้ไขกันไปเมื่อลงลึกลงไปเรื่อยๆครับ

เปลี่ยนจาก Regression เป็น Classification

ดูผลการทดลองด้านบนเราอาจจะ Misleading คิดว่าโมเดลนี้มันดีมากได้ จริงอยู่ที่ RNN มันทำนายข้อมูลเชิงเวลาได้ดี แต่กับข้อมูลการลงทุนมันไม่ได้ง่ายขนาดนั้น ยังต้องมีการใช้ Feature engineer กันอีกเยอะมาก ฉะนั้นผมจึงเปลี่ยนจากการทำนายราคาปิด มาเป็นทำนายว่าวันต่อไปราคาจะขึ้นหรือลงแทน เพื่อแสดงให้เห็นว่าโมเดลตัวนนี้มัน Overfitting ได้ง่ายขนาดไหน

Loss function ของ Simple RNN ใน Classification Task

จะเห็นว่าในขณะที่ข้อมูลสอน Training set ของเราทำได้ดีขึ้นเรื่อยๆ แต่ในทางกลับกัน Loss ของ Validation set (Out-of-sample) กลับเพิ่มสูงขึ้นอย่างมาก

Accuracy ของ RNN ใน task Classification

Accuracy ก็มีเหมือนกับ Loss นะครับ จะเห็นว่ามันมีการ Overfitting ข้อมูล Training อย่างหนัก ยิ่ง Epoch หลังๆเราจะจบด้วยการทำนายถูกถึง 77% (สำหรับข้อมูลการลงทุน 78% ถือว่าสูงเกินจริงมาก) ขณะที่ Accuracy ของ ข้อมูลที่เรานำมา Test มันไม่ได้ดีไปกว่าการเดาสุ่มนัก!!!

สรุป

แม้อัลกอริทึ่มที่สามารถทำงานให้กับข้อมูล Time Series ได้อย่างดีอย่าง RNN จะทำผลงานได้ดีกับหลายๆดาต้า แต่สำหรับข้อมูลการลงทุนมันไม่ใช่แบบนั้น ถ้าเราตัดประเด็นที่ว่า Simple RNN เป็นโมเดลที่พื้นฐานมากเกินไป หรือ เราไม่ได้ปรับจูนพารามิเตอร์ต่างๆเพื่อลดการ Overfitting ออกไป

ที่เป็นแบบนี้ก็เพราะ ข้อมูลการลงทุนดำเนินรอยตาม Random walk theory อย่างสูง ถ้าเราตัดข้อมูล แบบ 80% แรกมาสอน แล้วเอาข้อมูล 20% หลังมาทดสอบนันไม่ได้สมเหตุสมผลในเชิงของข้อมูลการลงทุน เพราะความสัมพันธ์ของข้อมูลเมื่อเวลาเคลื่อนออกจากไปจากเวลาสุดท้ายที่เราสอนมัน มันได้มีความสัมพันธ์กันน้อยลงๆเรื่อยๆ ฉะนั้นยังมีอะไรต้องทำอีกมากครับ

ถ้าเราอยากใช้ Machine learning ในการทำนายข้อมูลการลงทุน เราจะนำข้อมูลมาโยนใส่โมเดลเหมือนการทำนายข้อมูลที่ไม่ได้ลักษณะแบบ Random walk theory ได้อย่างข้อมูลอื่นๆ เช่น ข้อมูลสภาพอากาศ แผ่นดินไหว และอีกมากมายหรอกครับ ฉะนั้นราต้องให้ความสำคัญกับการทำ Feature Engineer และการหา Feature ที่มันหลีกออกจาก Random มากกว่าการทำโมเดลเรื่องอื่นๆเยอะหน่อยซึ่งจะค่อยๆทยอยเขียนออกมานะครับ

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s