บทช่วยสอน RNN (โครงข่ายประสาทเทียมที่เกิดซ้ำ): ตัวอย่าง TensorFlow
⚡ สรุปอย่างชาญฉลาด
โครงข่ายประสาทเทียมแบบวนซ้ำ (Recurrent Neural Networks) เพิ่มสถานะหน่วยความจำให้กับเซลล์ประสาททั่วไป โดยป้อนเอาต์พุตแต่ละตัวกลับเข้าไปเป็นอินพุตถัดไป เพื่อให้แบบจำลองสามารถเรียนรู้ตามลำดับได้ บทแนะนำนี้จะสร้างโครงข่ายดังกล่าวใน TensorFlow และพยากรณ์อนุกรมเวลา

เหตุใดเราจึงต้องมี Recurrent Neural Network (RNN)
Recurrent Neural Network (RNN) ช่วยให้คุณสามารถจำลองหน่วยหน่วยความจำเพื่อคงข้อมูลและสร้างแบบจำลองการพึ่งพาระยะสั้น นอกจากนี้ยังใช้ในการพยากรณ์อนุกรมเวลาเพื่อระบุความสัมพันธ์และรูปแบบของข้อมูล นอกจากนี้ยังช่วยสร้างผลลัพธ์เชิงคาดการณ์สำหรับข้อมูลตามลำดับโดยนำเสนอพฤติกรรมที่คล้ายคลึงกันกับสมองของมนุษย์
โครงสร้างของ an โครงข่ายประสาทเทียม กระบวนการนี้ค่อนข้างง่ายและส่วนใหญ่เกี่ยวข้องกับการคูณเมทริกซ์ ในขั้นตอนแรก ข้อมูลนำเข้าจะถูกคูณด้วยน้ำหนักและค่าไบแอสแบบสุ่มในตอนเริ่มต้น จากนั้นจะถูกแปลงด้วยฟังก์ชันการกระตุ้น และค่าเอาต์พุตจะถูกนำมาใช้ในการทำนาย ขั้นตอนนี้จะช่วยให้เห็นภาพว่าเครือข่ายอยู่ห่างจากความเป็นจริงมากน้อยเพียงใด
เมตริกที่ใช้คือการสูญเสีย ยิ่งฟังก์ชันการสูญเสียมีค่าสูงขึ้น โมเดลก็จะยิ่งโง่ลง หากต้องการปรับปรุงความรู้เกี่ยวกับเครือข่าย จำเป็นต้องปรับค่าถ่วงน้ำหนักของเน็ตให้เหมาะสม การลดระดับความชันแบบสุ่มเป็นวิธีที่ใช้ในการเปลี่ยนค่าของน้ำหนักในทิศทางที่ถูกต้อง เมื่อปรับแล้ว เครือข่ายสามารถใช้ชุดข้อมูลอื่นเพื่อทดสอบความรู้ใหม่
โชคดีที่ค่าความคลาดเคลื่อนลดลงกว่าเดิม แต่ก็ยังไม่น้อยพอ ขั้นตอนการปรับให้เหมาะสมจะทำซ้ำไปเรื่อยๆ จนกว่าค่าความคลาดเคลื่อนจะลดลงเหลือน้อยที่สุด กล่าวคือ จะไม่มีข้อมูลเพิ่มเติมใดๆ ที่สามารถหาได้อีกแล้วtracเท็ด
ปัญหาของรุ่นนี้คือไม่มีหน่วยความจำใดๆ หมายความว่าอินพุตและเอาต์พุตเป็นอิสระ กล่าวอีกนัยหนึ่ง โมเดลไม่สนใจว่าอะไรจะเกิดขึ้นก่อนหน้านี้ ทำให้เกิดคำถามขึ้นเมื่อคุณต้องการคาดเดาอนุกรมเวลาหรือประโยค เนื่องจากเครือข่ายจำเป็นต้องมีข้อมูลเกี่ยวกับข้อมูลในอดีตหรือคำในอดีต
เพื่อเอาชนะปัญหานี้ จึงมีการพัฒนาสถาปัตยกรรมประเภทใหม่: เครือข่ายประสาทเทียมแบบเรียกซ้ำ (RNN ต่อไปนี้)
โครงข่ายประสาทเทียมที่เกิดซ้ำ (RNN) คืออะไร?
โครงข่ายประสาทเทียมแบบวนซ้ำ (Recurrent Neural Network หรือ RNN) เป็นโครงข่ายประสาทเทียมประเภทหนึ่งที่การเชื่อมต่อระหว่างโหนดต่างๆ ก่อให้เกิดกราฟแบบมีทิศทาง เพื่อให้ได้พฤติกรรมแบบไดนามิกตามเวลา ช่วยในการจำลองข้อมูลลำดับที่ได้มาจากโครงข่ายแบบส่งต่อ (feedforward networks) โดยทำงานคล้ายกับสมองของมนุษย์เพื่อให้ได้ผลลัพธ์ที่คาดการณ์ได้
โครงข่ายประสาทที่เกิดซ้ำมีลักษณะค่อนข้างคล้ายกับโครงข่ายประสาทเทียมแบบเดิม ยกเว้นว่ามีการเพิ่มสถานะหน่วยความจำลงในเซลล์ประสาท การคำนวณเพื่อรวมหน่วยความจำนั้นทำได้ง่าย
ลองนึกภาพแบบจำลองอย่างง่ายที่มีเพียงเซลล์ประสาทเดียวที่รับข้อมูลเป็นชุด ในโครงข่ายประสาทเทียมแบบดั้งเดิม แบบจำลองจะสร้างเอาต์พุตโดยการคูณอินพุตกับน้ำหนักและฟังก์ชันการกระตุ้น แต่ใน RNN เอาต์พุตนี้จะถูกส่งกลับไปยังตัวเองจำนวนครั้งหนึ่ง เราเรียกสิ่งนี้ว่า... ขั้นตอนเวลา ระยะเวลาที่ผลลัพธ์กลายเป็นอินพุตของการคูณเมทริกซ์ครั้งถัดไป
ตัวอย่างเช่น ในภาพด้านล่าง คุณจะเห็นว่าเครือข่ายประกอบด้วยเซลล์ประสาทหนึ่งอัน เครือข่ายจะคำนวณการคูณเมทริกซ์ระหว่างอินพุตและน้ำหนัก และเพิ่มความไม่เป็นเชิงเส้นด้วยฟังก์ชันการเปิดใช้งาน มันกลายเป็นเอาท์พุตที่ t-1 เอาต์พุตนี้เป็นอินพุตของการคูณเมทริกซ์ตัวที่สอง
โครงข่ายประสาทกำเริบ (RNN)
ด้านล่างนี้ เราเขียนโค้ด RNN แบบง่ายๆ ใน TensorFlow เพื่อทำความเข้าใจขั้นตอนและรูปร่างของเอาต์พุตด้วย
เครือข่ายประกอบด้วย:
- สี่อินพุต
- หกเซลล์ประสาท
- ขั้นตอน 2 ครั้ง
เครือข่ายจะดำเนินการตามภาพด้านล่าง
เครือข่ายนี้เรียกว่า 'แบบเรียกซ้ำ' เนื่องจากเครือข่ายดำเนินการแบบเดียวกันในแต่ละช่องเปิดใช้งาน เครือข่ายจะคำนวณน้ำหนักของอินพุตและเอาต์พุตก่อนหน้าเพื่อใช้ฟังก์ชันการเปิดใช้งาน
หมายเหตุเกี่ยวกับเวอร์ชัน: โค้ดในบทช่วยสอนนี้มุ่งเป้าไปที่ TensorFlow 1.x Graph API บน TensorFlow 2.x สคริปต์เดียวกันนี้ยังคงทำงานได้หลังจากนั้น import tensorflow.compat.v1 as tf บวก tf.disable_v2_behavior()เนื่องจากตัวแปร placeholder, เซสชัน และโมดูล rnn_cell ตอนนี้อยู่ภายใต้ tf.compat.v1สำนวนที่เทียบเท่าในเวอร์ชัน 2.x คือ tf.keras.layers.SimpleRNN.
import numpy as np import tensorflow as tf n_inputs = 4 n_neurons = 6 n_timesteps = 2 The data is a sequence of a number from 0 to 9 and divided into three batches of data. ## Data X_batch = np.array([ [[0, 1, 2, 5], [9, 8, 7, 4]], # Batch 1 [[3, 4, 5, 2], [0, 0, 0, 0]], # Batch 2 [[6, 7, 8, 5], [6, 5, 4, 2]], # Batch 3 ])
เราสามารถสร้างเครือข่ายที่มีตัวยึดตำแหน่งสำหรับข้อมูล ระยะการเกิดซ้ำ และเอาต์พุต
กำหนดตัวยึดตำแหน่งสำหรับข้อมูล
X = tf.placeholder(tf.float32, [None, n_timesteps, n_inputs])
ที่นี่:
- ไม่มี: ไม่ทราบ และจะใช้ขนาดของชุดงาน
- n_timesteps: จำนวนครั้งที่เครือข่ายจะส่งเอาต์พุตกลับไปยังเซลล์ประสาท
- n_inputs: จำนวนอินพุตต่อแบตช์
กำหนดเครือข่ายที่เกิดซ้ำ
ดังที่ได้กล่าวไว้ในภาพด้านบน เครือข่ายประกอบด้วยเซลล์ประสาท 6 ตัว เครือข่ายจะคำนวณผลิตภัณฑ์ดอทสองอัน:
- ป้อนข้อมูลด้วยน้ำหนักชุดแรก (เช่น 6: เท่ากับจำนวนเซลล์ประสาท)
- ผลลัพธ์ก่อนหน้าพร้อมชุดน้ำหนักที่สอง (เช่น 6: ซึ่งสอดคล้องกับจำนวนผลลัพธ์)
โปรดทราบว่าในระหว่างการป้อนล่วงหน้าครั้งแรก ค่าของเอาต์พุตก่อนหน้าจะเท่ากับศูนย์เนื่องจากเราไม่มีค่าใดๆ ที่มีอยู่
วัตถุที่จะสร้าง RNN คือ tf.contrib.rnn.BasicRNNCell พร้อมอาร์กิวเมนต์ num_units เพื่อกำหนดจำนวนอินพุต
basic_cell = tf.contrib.rnn.BasicRNNCell(num_units=n_neurons)
เมื่อกำหนดเครือข่ายแล้ว คุณสามารถคำนวณเอาต์พุตและสถานะได้
outputs, states = tf.nn.dynamic_rnn(basic_cell, X, dtype=tf.float32)
วัตถุนี้ใช้การวนซ้ำภายในเพื่อคูณเมทริกซ์ตามจำนวนครั้งที่เหมาะสม
โปรดสังเกตว่าเซลล์ประสาทแบบวนซ้ำเป็นฟังก์ชันของข้อมูลนำเข้าทั้งหมดจากช่วงเวลาที่ผ่านมา นี่คือวิธีการที่เครือข่ายสร้างหน่วยความจำของตัวเอง ข้อมูลจากช่วงเวลาที่ผ่านมาสามารถส่งต่อไปยังช่วงเวลาในอนาคตได้ นี่คือความมหัศจรรย์ของเครือข่ายประสาทแบบวนซ้ำ
## Define the shape of the tensor X = tf.placeholder(tf.float32, [None, n_timesteps, n_inputs]) ## Define the network basic_cell = tf.contrib.rnn.BasicRNNCell(num_units=n_neurons) outputs, states = tf.nn.dynamic_rnn(basic_cell, X, dtype=tf.float32) init = tf.global_variables_initializer() init = tf.global_variables_initializer() with tf.Session() as sess: init.run() outputs_val = outputs.eval(feed_dict={X: X_batch}) print(states.eval(feed_dict={X: X_batch})) [[ 0.38941205 -0.9980438 0.99750966 0.7892596 0.9978241 0.9999997 ] [ 0.61096436 0.7255889 0.82977575 -0.88226104 0.29261455 -0.15597084] [ 0.62091285 -0.87023467 0.99729395 -0.58261937 0.9811445 0.99969864]]
เพื่อความเข้าใจง่ายขึ้น ลองพิมพ์ค่าของสถานะก่อนหน้าดู ผลลัพธ์ที่แสดงด้านบนคือผลลัพธ์จากสถานะสุดท้าย ทีนี้ลองพิมพ์ผลลัพธ์ทั้งหมดดู คุณจะสังเกตได้ว่าสถานะต่างๆ คือผลลัพธ์ก่อนหน้าของแต่ละชุดข้อมูล นั่นหมายความว่าผลลัพธ์ก่อนหน้าจะมีข้อมูลเกี่ยวกับลำดับทั้งหมด
print(outputs_val) print(outputs_val.shape) [[[-0.75934666 -0.99537754 0.9735819 -0.9722234 -0.14234993 -0.9984044 ] [ 0.99975264 -0.9983206 0.9999993 -1. -0.9997506 -1. ]] [[ 0.97486496 -0.98773265 0.9969686 -0.99950117 -0.7092863 -0.99998885] [ 0.9326837 0.2673438 0.2808514 -0.7535883 -0.43337247 0.5700631 ]] [[ 0.99628735 -0.9998728 0.99999213 -0.99999976 -0.9884324 -1. ] [ 0.99962527 -0.9467421 0.9997403 -0.99999714 -0.99929446 -0.9999795 ]]] (3, 2, 6)
ภาพแสดงรายละเอียดด้านล่างจะแยกข้อมูลเทนเซอร์ที่พิมพ์ออกมาชุดเดียวกันออกเป็นชุดย่อยๆ
ผลลัพธ์มีรูปร่างเป็น (3, 2, 6):
- 3: จำนวนแบทช์
- 2: จำนวนการจับเวลา
- 6: จำนวนเซลล์ประสาท
การเพิ่มประสิทธิภาพของโครงข่ายประสาทเทียมที่เกิดซ้ำนั้นเหมือนกับโครงข่ายประสาทเทียมแบบเดิม คุณจะเห็นรายละเอียดเพิ่มเติมเกี่ยวกับวิธีการเพิ่มประสิทธิภาพโค้ดในส่วนถัดไปของบทช่วยสอน Recurrent Neural Network นี้
การประยุกต์ใช้ RNN
RNN มีประโยชน์หลายอย่าง โดยเฉพาะอย่างยิ่งเมื่อต้องทำนายอนาคต ในอุตสาหกรรมการเงิน RNN จะมีประโยชน์ในการทำนายราคาหุ้นหรือสัญญาณของทิศทางตลาดหุ้น (เช่น บวกหรือลบ)
RNN มีประโยชน์สำหรับรถยนต์ขับเคลื่อนอัตโนมัติเนื่องจากสามารถหลีกเลี่ยงอุบัติเหตุทางรถยนต์ได้ด้วยการคาดการณ์วิถีของยานพาหนะ
RNN ถูกนำมาใช้กันอย่างแพร่หลายในการวิเคราะห์ข้อความ คำบรรยายภาพ การวิเคราะห์ความรู้สึก และการแปลด้วยคอมพิวเตอร์ ตัวอย่างเช่น เราสามารถใช้บทวิจารณ์ภาพยนตร์เพื่อทำความเข้าใจความรู้สึกที่ผู้ชมรับรู้หลังจากดูภาพยนตร์ การทำงานอัตโนมัตินี้มีประโยชน์มากเมื่อบริษัทภาพยนตร์ไม่มีเวลาเพียงพอในการทบทวน ติดป้ายกำกับ รวบรวม และวิเคราะห์บทวิจารณ์ เครื่องจักรสามารถทำงานได้ด้วยความแม่นยำในระดับที่สูงขึ้น
ข้อจำกัดของ RNN
ตามทฤษฎีแล้ว RNN ควรจะส่งข้อมูลบ่อยครั้ง อย่างไรก็ตาม การเผยแพร่ข้อมูลทั้งหมดนี้ค่อนข้างท้าทายเมื่อขั้นตอนเวลายาวเกินไป เมื่อเครือข่ายมีชั้นลึกมากเกินไป จะไม่สามารถฝึกได้ ปัญหานี้เรียกว่า: ปัญหาการไล่ระดับสีที่หายไป- หากคุณจำได้ โครงข่ายประสาทเทียมจะอัปเดตน้ำหนักโดยใช้อัลกอริธึมการไล่ระดับสี การไล่ระดับสีจะเล็กลงเมื่อเครือข่ายคืบหน้าลงไปยังเลเยอร์ที่ต่ำกว่า
โดยสรุปแล้ว ค่าความชันจะคงที่ หมายความว่าไม่มีพื้นที่สำหรับการปรับปรุง โมเดลเรียนรู้จากการเปลี่ยนแปลงของค่าความชัน การเปลี่ยนแปลงนี้ส่งผลต่อเอาต์พุตของเครือข่าย อย่างไรก็ตาม หากความแตกต่างของค่าความชันน้อยเกินไป (เช่น น้ำหนักเปลี่ยนแปลงเล็กน้อย) เครือข่ายจะไม่สามารถเรียนรู้สิ่งใดได้เลย และเอาต์พุตก็จะผิดเพี้ยนไปด้วย ดังนั้น เครือข่ายที่เผชิญกับปัญหาค่าความชันหายไปจึงไม่สามารถลู่เข้าสู่คำตอบที่ดีได้
การปรับปรุง LSTM
เพื่อแก้ไขปัญหาการลดลงของค่าความชัน (vanishing gradient) ที่อาจเกิดขึ้นใน RNN นักวิจัยสามคน ได้แก่ Hochreiter, Schmidhuber และ Bengio ได้ปรับปรุง RNN ด้วยสถาปัตยกรรมที่เรียกว่า Long Short-Term Memory (LSTM) โดยสรุปแล้ว LSTM จะให้ข้อมูลในอดีตที่เกี่ยวข้องกับช่วงเวลาปัจจุบันแก่เครือข่าย เครื่องจักรจะใช้สถาปัตยกรรมที่ดีกว่าในการเลือกและส่งข้อมูลย้อนกลับไปยังช่วงเวลาในอนาคต
สถาปัตยกรรม LSTM มีให้ใช้งานใน TensorFlow โดยใช้ tf.contrib.rnn.LSTMCell LSTM อยู่นอกขอบเขตของบทช่วยสอนนี้ คุณสามารถศึกษาเพิ่มเติมได้จากเอกสารทางการ เอกสาร สำหรับข้อมูลเพิ่มเติม
ใน TensorFlow 2.x เซลล์นั้นจะเข้าถึงได้ดังนี้ tf.compat.v1.nn.rnn_cell.LSTMCellในขณะที่โค้ดใหม่โดยทั่วไปจะใช้ tf.keras.layers.LSTM หรือไฟแช็ก tf.keras.layers.GRUซึ่งให้ความแม่นยำเทียบเท่ากันโดยใช้พารามิเตอร์น้อยกว่า
RNN ในอนุกรมเวลา
ในบทเรียน TensorFlow RNN นี้ คุณจะได้ใช้ RNN กับข้อมูลอนุกรมเวลา อนุกรมเวลาขึ้นอยู่กับช่วงเวลาก่อนหน้า ซึ่งหมายความว่าค่าในอดีตมีข้อมูลที่เกี่ยวข้องที่เครือข่ายสามารถเรียนรู้ได้ แนวคิดเบื้องหลังการทำนายอนุกรมเวลาคือการประมาณค่าในอนาคตของอนุกรม เช่น ราคาหุ้น อุณหภูมิ GDP เป็นต้น
การเตรียมข้อมูลสำหรับ Keras RNN และไทม์ซีรีส์อาจค่อนข้างยุ่งยาก ก่อนอื่น เป้าหมายคือการทำนายค่าถัดไปของซีรีส์ ซึ่งหมายความว่า คุณจะใช้ข้อมูลในอดีตเพื่อประมาณค่าที่ t + 1 ป้ายกำกับจะเท่ากับลำดับอินพุตและเลื่อนไปข้างหน้าหนึ่งช่วง ประการที่สอง จำนวนอินพุตจะถูกตั้งเป็น 1 นั่นคือ หนึ่งการสังเกตต่อเวลา สุดท้าย ขั้นเวลาจะเท่ากับลำดับของค่าตัวเลข ตัวอย่างเช่น หากคุณตั้งขั้นเวลาเป็น 10 ลำดับอินพุตจะส่งคืนสิบครั้งติดต่อกัน
ดูกราฟด้านล่าง เราได้แสดงข้อมูลอนุกรมเวลาทางด้านซ้ายและลำดับอินพุตที่สมมติขึ้นทางด้านขวา คุณสร้างฟังก์ชันเพื่อส่งคืนชุดข้อมูลที่มีค่าสุ่มในแต่ละวันตั้งแต่เดือนมกราคม 2001 ถึงธันวาคม 2016
# To plot pretty figures %matplotlib inline import matplotlib import matplotlib.pyplot as plt import pandas as pd def create_ts(start = '2001', n = 201, freq = 'M'): rng = pd.date_range(start=start, periods=n, freq=freq) ts = pd.Series(np.random.uniform(-18, 18, size=len(rng)), rng).cumsum() return ts ts= create_ts(start = '2001', n = 192, freq = 'M') ts.tail(5)
เอาท์พุต
2016-08-31 -93.459631 2016-09-30 -95.264791 2016-10-31 -95.551935 2016-11-30 -105.879611 2016-12-31 -123.729319 Freq: M, dtype: float64
ts = create_ts(start = '2001', n = 222) # Left plt.figure(figsize=(11,4)) plt.subplot(121) plt.plot(ts.index, ts) plt.plot(ts.index[90:100], ts[90:100], "b-", linewidth=3, label="A training instance") plt.title("A time series (generated)", fontsize=14) # Right plt.subplot(122) plt.title("A training instance", fontsize=14) plt.plot(ts.index[90:100], ts[90:100], "b-", markersize=8, label="instance") plt.plot(ts.index[91:101], ts[91:101], "bo", markersize=10, label="target", markerfacecolor='red') plt.legend(loc="upper left") plt.xlabel("Time") plt.show()
ส่วนด้านขวาของกราฟแสดงอนุกรมข้อมูลทั้งหมด โดยเริ่มตั้งแต่ปี 2001 และสิ้นสุดในปี 2019 การป้อนข้อมูลทั้งหมดลงในเครือข่ายโดยตรงนั้นไม่มีประโยชน์ ดังนั้น คุณควรสร้างชุดข้อมูลที่มีความยาวเท่ากับช่วงเวลา (time step) แทน ชุดข้อมูลนี้จะเป็นตัวแปร X ส่วนตัวแปร Y จะเหมือนกับตัวแปร X แต่เลื่อนไปหนึ่งช่วงเวลา (เช่น คุณต้องการพยากรณ์ค่า t+1)
เวกเตอร์ทั้งสองมีความยาวเท่ากัน คุณสามารถดูได้ในส่วนด้านขวาของกราฟด้านบน เส้นนี้แสดงถึงค่าสิบค่าของอินพุต X ในขณะที่จุดสีแดงคือค่าสิบค่าของป้ายกำกับ Y โปรดทราบว่าป้ายกำกับจะเริ่มต้นก่อน X หนึ่งช่วงและสิ้นสุดหนึ่งช่วงหลังจากนั้น
สร้าง RNN เพื่อทำนายอนุกรมเวลาใน TensorFlow
ในการฝึกอบรม RNN นี้ ถึงเวลาสร้าง RNN แรกของคุณเพื่อทำนายซีรีส์ข้างต้น คุณต้องระบุไฮเปอร์พารามิเตอร์บางตัว (พารามิเตอร์ของโมเดล เช่น จำนวนเซลล์ประสาท ฯลฯ) สำหรับโมเดล:
- จำนวนอินพุต: 1
- ช่วงเวลา (หน้าต่างในซีรีส์เวลา): 10
- จำนวนเซลล์ประสาท: 120
- จำนวนเอาต์พุต: 1
เครือข่ายของคุณจะเรียนรู้จากลำดับเหตุการณ์ 10 วัน และประกอบด้วยเซลล์ประสาทแบบวนซ้ำ 120 เซลล์ คุณป้อนข้อมูลให้กับโมเดลด้วยข้อมูลหนึ่งวัน คุณสามารถเปลี่ยนค่าต่างๆ เพื่อดูว่าโมเดลพัฒนาขึ้นหรือไม่
ก่อนสร้างแบบจำลอง คุณต้องแบ่งชุดข้อมูลออกเป็นชุดฝึกฝนและชุดทดสอบ ชุดข้อมูลทั้งหมดมีจุดข้อมูล 222 จุด คุณจะใช้จุดข้อมูล 201 จุดแรกในการฝึกฝนแบบจำลอง และใช้จุดข้อมูล 21 จุดสุดท้ายในการทดสอบแบบจำลองของคุณ
หลังจากกำหนดชุดข้อมูลฝึกฝนและชุดข้อมูลทดสอบแล้ว คุณต้องสร้างอ็อบเจ็กต์ที่มีแบทช์อยู่ภายใน ในแต่ละแบทช์จะมีค่า X และค่า Y โปรดจำไว้ว่าค่า X นั้นล่าช้าไปหนึ่งช่วงเวลา ดังนั้น คุณจึงใช้ข้อมูล 200 ตัวแรก และช่วงเวลาจะเท่ากับ 10 อ็อบเจ็กต์ X_batches ควรมี 20 แบทช์ ขนาด 10*1 ส่วนอ็อบเจ็กต์ y_batches มีรูปร่างเหมือนกับอ็อบเจ็กต์ X_batches แต่ล้ำหน้าไปหนึ่งช่วงเวลา
ขั้นตอน 1) สร้างรถไฟและทดสอบ
ก่อนอื่น คุณแปลงอนุกรมให้เป็น นำพาย อาร์เรย์ จากนั้นคุณกำหนดหน้าต่าง (เช่น จำนวนเวลาที่เครือข่ายจะเรียนรู้จาก) จำนวนอินพุต เอาต์พุต และขนาดของชุดฝึกตามที่แสดงในตัวอย่าง TensorFlow RNN ด้านล่าง
series = np.array(ts) n_windows = 20 n_input = 1 n_output = 1 size_train = 201
หลังจากนั้น คุณเพียงแค่แบ่งอาร์เรย์ออกเป็นสองชุดข้อมูล
## Split data train = series[:size_train] test = series[size_train:] print(train.shape, test.shape) (201,) (21,)
ขั้นตอน 2) สร้างฟังก์ชันเพื่อส่งคืน X_batches และ y_batches
เพื่อให้ง่ายขึ้น คุณสามารถสร้างฟังก์ชันที่ส่งคืนอาร์เรย์ที่แตกต่างกันสองชุด ชุดหนึ่งสำหรับ X_batches และอีกชุดหนึ่งสำหรับ y_batches
มาเขียนฟังก์ชัน RNN TensorFlow เพื่อสร้างแบตช์กัน
โปรดทราบว่าแบตช์ X จะล้าหลังหนึ่งช่วง (เราใช้ค่า t-1) ผลลัพธ์ของฟังก์ชันควรมีสามมิติ มิติแรกเท่ากับจำนวนแบตช์ มิติที่สองเท่ากับขนาดของหน้าต่าง และมิติสุดท้ายเท่ากับจำนวนอินพุต
ส่วนที่ยุ่งยากคือการเลือกจุดข้อมูลให้ถูกต้อง สำหรับจุดข้อมูล X คุณจะเลือกการสังเกตตั้งแต่ t = 1 ถึง t =200 ในขณะที่สำหรับจุดข้อมูล Y คุณจะคืนค่าการสังเกตจาก t = 2 ถึง 201 เมื่อคุณมีจุดข้อมูลที่ถูกต้องแล้ว ก็สามารถปรับเปลี่ยนรูปร่างใหม่ได้ทันที ซีรี่ย์.
หากต้องการสร้างออบเจ็กต์ด้วยแบทช์ คุณจะต้องแบ่งชุดข้อมูลออกเป็น 20 แบทช์ที่มีความยาวเท่ากัน (เช่น 1) คุณสามารถใช้วิธีการปรับรูปร่างใหม่และส่งผ่าน -20 เพื่อให้ซีรีส์คล้ายกับขนาดแบทช์ ค่า 1 คือจำนวนการสังเกตต่อชุด และ XNUMX คือจำนวนอินพุต
คุณต้องทำขั้นตอนเดียวกันแต่สำหรับฉลาก
โปรดทราบว่า คุณต้องเลื่อนข้อมูลให้ตรงกับจำนวนครั้งที่คุณต้องการพยากรณ์ ตัวอย่างเช่น หากคุณต้องการพยากรณ์ล่วงหน้า 1 วัน คุณจะต้องเลื่อนข้อมูลไป 1 ครั้ง หากคุณต้องการพยากรณ์ล่วงหน้า 2 วัน คุณจะต้องเลื่อนข้อมูลไป 2 ครั้ง
x_data = train[:size_train-1]: Select all the training instance minus one day X_batches = x_data.reshape(-1, windows, input): create the right shape for the batch e.g (10, 20, 1) def create_batches(df, windows, input, output): ## Create X x_data = train[:size_train-1] # Select the data X_batches = x_data.reshape(-1, windows, input) # Reshape the data ## Create y y_data = train[n_output:size_train] y_batches = y_data.reshape(-1, windows, output) return X_batches, y_batches
เมื่อกำหนดฟังก์ชันแล้ว คุณสามารถเรียกฟังก์ชันนี้เพื่อสร้างแบตช์ได้ดังแสดงในตัวอย่าง RNN ด้านล่าง
X_batches, y_batches = create_batches(df = train,
windows = n_windows,
input = n_input,
output = n_output)
คุณสามารถพิมพ์รูปร่างเพื่อให้แน่ใจว่าขนาดถูกต้อง
print(X_batches.shape, y_batches.shape)
(10, 20, 1) (10, 20, 1)
คุณต้องสร้างชุดทดสอบที่มีข้อมูลเพียงชุดเดียวและการสังเกต 20 รายการ
โปรดทราบว่าคุณคาดการณ์วันแล้ววันเล่า หมายความว่าค่าที่คาดการณ์ที่สองจะขึ้นอยู่กับค่าจริงของวันแรก (t+1) ของชุดข้อมูลทดสอบ ความจริงก็จะรู้คุณค่าที่แท้จริง
หากคุณต้องการพยากรณ์ t+2 (เช่น ล่วงหน้า 1 วัน) คุณต้องใช้ค่าพยากรณ์ t+3 หากคุณกำลังจะทำนาย t+1 (สามวันข้างหน้า) คุณจะต้องใช้ค่าทำนาย t+2 และ t+XNUMX มันสมเหตุสมผลแล้วที่เป็นการยากที่จะคาดการณ์ล่วงหน้าอย่างแม่นยำในช่วง t+n วันข้างหน้า
X_test, y_test = create_batches(df = test, windows = 20,input = 1, output = 1)
print(X_test.shape, y_test.shape)
(10, 20, 1) (10, 20, 1)
โอเค ขนาดแบตช์ของคุณพร้อมแล้ว คุณสามารถสร้างสถาปัตยกรรม RNN ได้ โปรดจำไว้ว่าคุณมีนิวรอนแบบเรียกซ้ำ 120 นิวรอน
ขั้นตอน 3) สร้างโมเดล
ในการสร้างโมเดล คุณต้องกำหนดสามส่วน:
- ตัวแปรที่มีเทนเซอร์
- อาร์เอ็นเอ็น
- การสูญเสียและการเพิ่มประสิทธิภาพ
ขั้นตอน 3.1) ตัวแปร
คุณต้องระบุตัวแปร X และ y ด้วยรูปร่างที่เหมาะสม ขั้นตอนนี้เป็นเรื่องเล็กน้อย เมตริกซ์มีมิติเดียวกันกับวัตถุ X_batches และ y_batches
ตัวอย่างเช่น เทนเซอร์ X เป็นตัวแทน (ตรวจสอบบทช่วยสอนเกี่ยวกับเรื่องนี้ได้ที่นี่) รู้เบื้องต้นเกี่ยวกับ TensorFlow เพื่อให้จิตใจสดชื่นกับการประกาศตัวแปร) มีสามมิติ คือ
- หมายเหตุ: ขนาดของชุด
- n_windows: ความยาวของหน้าต่าง กล่าวคือ จำนวนครั้งที่โมเดลมองย้อนกลับไป
- n_input: จำนวนอินพุต
ผลลัพธ์คือ:
tf.placeholder(tf.float32, [None, n_windows, n_input])
## 1. Construct the tensors X = tf.placeholder(tf.float32, [None, n_windows, n_input]) y = tf.placeholder(tf.float32, [None, n_windows, n_output])
ขั้นตอน 3.2) สร้าง RNN
ในส่วนที่สองของตัวอย่าง RNN TensorFlow นี้ คุณจะต้องกำหนดสถาปัตยกรรมของเครือข่าย เช่นเดียวกับก่อนหน้านี้ คุณจะใช้ BasicRNNCell และ dynamic_rnn จากตัวประมาณค่า TensorFlow
## 2. create the model
basic_cell = tf.contrib.rnn.BasicRNNCell(num_units=r_neuron, activation=tf.nn.relu)
rnn_output, states = tf.nn.dynamic_rnn(basic_cell, X, dtype=tf.float32)
ส่วนถัดไปอาจซับซ้อนกว่าเล็กน้อย แต่ช่วยให้คำนวณได้เร็วขึ้น คุณต้องแปลงเอาต์พุตที่รันเป็นเลเยอร์หนาแน่น จากนั้นแปลงอีกครั้งเพื่อให้มีมิติเดียวกันกับอินพุต
stacked_rnn_output = tf.reshape(rnn_output, [-1, r_neuron]) stacked_outputs = tf.layers.dense(stacked_rnn_output, n_output) outputs = tf.reshape(stacked_outputs, [-1, n_windows, n_output])
ขั้นตอน 3.3) สร้างการสูญเสียและการเพิ่มประสิทธิภาพ
การปรับแต่งโมเดลขึ้นอยู่กับงานที่คุณกำลังทำ ในบทเรียนก่อนหน้านี้เกี่ยวกับ ซีเอ็นเอ็นในบทเรียน RNN นี้ เป้าหมายของคุณคือการจำแนกภาพ แต่เป้าหมายจะแตกต่างออกไปเล็กน้อย คุณได้รับมอบหมายให้ทำนายค่าตัวแปรต่อเนื่อง เทียบกับการทำนายค่าของแต่ละคลาส
ความแตกต่างนี้มีความสำคัญเนื่องจากจะเปลี่ยนปัญหาการปรับให้เหมาะสม ปัญหาการหาค่าเหมาะที่สุดสำหรับตัวแปรต่อเนื่องคือการลดค่าคลาดเคลื่อนกำลังสองเฉลี่ยให้เหลือน้อยที่สุด หากต้องการสร้างหน่วยวัดเหล่านี้ใน TF คุณสามารถใช้:
tf.reduce_sum(tf.square(เอาท์พุต – y))
รหัส RNN ที่เหลือจะเหมือนเดิม คุณใช้เครื่องมือเพิ่มประสิทธิภาพ Adam เพื่อลดการสูญเสีย (เช่น MSE):
tf.train.AdamOptimizer(learning_rate=learning_rate)
เครื่องมือเพิ่มประสิทธิภาพ.ย่อเล็กสุด(ขาดทุน)
เพียงเท่านี้ คุณก็สามารถรวบรวมทุกอย่างเข้าด้วยกัน และโมเดลของคุณก็พร้อมที่จะฝึกแล้ว
tf.reset_default_graph() r_neuron = 120 ## 1. Construct the tensors X = tf.placeholder(tf.float32, [None, n_windows, n_input]) y = tf.placeholder(tf.float32, [None, n_windows, n_output]) ## 2. create the model basic_cell = tf.contrib.rnn.BasicRNNCell(num_units=r_neuron, activation=tf.nn.relu) rnn_output, states = tf.nn.dynamic_rnn(basic_cell, X, dtype=tf.float32) stacked_rnn_output = tf.reshape(rnn_output, [-1, r_neuron]) stacked_outputs = tf.layers.dense(stacked_rnn_output, n_output) outputs = tf.reshape(stacked_outputs, [-1, n_windows, n_output]) ## 3. Loss + optimization learning_rate = 0.001 loss = tf.reduce_sum(tf.square(outputs - y)) optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate) training_op = optimizer.minimize(loss) init = tf.global_variables_initializer()
คุณจะฝึกโมเดลโดยใช้ 1500 ยุคและพิมพ์การสูญเสียทุกๆ 150 รอบ เมื่อโมเดลได้รับการฝึกฝนแล้ว คุณจะประเมินโมเดลบนชุดทดสอบและสร้างออบเจ็กต์ที่มีการคาดคะเนดังที่แสดงในตัวอย่าง Recurrent Neural Network ด้านล่าง
iteration = 1500 with tf.Session() as sess: init.run() for iters in range(iteration): sess.run(training_op, feed_dict={X: X_batches, y: y_batches}) if iters % 150 == 0: mse = loss.eval(feed_dict={X: X_batches, y: y_batches}) print(iters, "\tMSE:", mse) y_pred = sess.run(outputs, feed_dict={X: X_test}) 0 MSE: 502893.34 150 MSE: 13839.129 300 MSE: 3964.835 450 MSE: 2619.885 600 MSE: 2418.772 750 MSE: 2110.5923 900 MSE: 1887.9644 1050 MSE: 1747.1377 1200 MSE: 1556.3398 1350 MSE: 1384.6113
ในที่สุดในบทช่วยสอนการเรียนรู้เชิงลึกของ RNN นี้ คุณสามารถพล็อตมูลค่าที่แท้จริงของชุดข้อมูลด้วยค่าที่คาดการณ์ไว้ได้ หากแบบจำลองของคุณได้รับการแก้ไข ค่าที่คาดการณ์ไว้ควรวางทับค่าจริง
อย่างที่คุณเห็น โมเดลนี้ยังสามารถปรับปรุงได้อีกมาก ขึ้นอยู่กับคุณที่จะเปลี่ยนแปลงพารามิเตอร์ต่างๆ เช่น ช่วงเวลา (windows), ขนาดชุดข้อมูล (batch size) หรือจำนวนเซลล์ประสาทแบบวนซ้ำ (recurrent neurons)
plt.title("Forecast vs Actual", fontsize=14) plt.plot(pd.Series(np.ravel(y_test)), "bo", markersize=8, label="Actual", color='green') plt.plot(pd.Series(np.ravel(y_pred)), "r.", markersize=8, label="Forecast", color='red') plt.legend(loc="lower left") plt.xlabel("Time") plt.show()
การคาดการณ์เทียบกับจริง





