บทช่วยสอน RNN (โครงข่ายประสาทเทียมที่เกิดซ้ำ): ตัวอย่าง TensorFlow
เหตุใดเราจึงต้องมี Recurrent Neural Network (RNN)
Recurrent Neural Network (RNN) ช่วยให้คุณสามารถจำลองหน่วยหน่วยความจำเพื่อคงข้อมูลและสร้างแบบจำลองการพึ่งพาระยะสั้น นอกจากนี้ยังใช้ในการพยากรณ์อนุกรมเวลาเพื่อระบุความสัมพันธ์และรูปแบบของข้อมูล นอกจากนี้ยังช่วยสร้างผลลัพธ์เชิงคาดการณ์สำหรับข้อมูลตามลำดับโดยนำเสนอพฤติกรรมที่คล้ายคลึงกันกับสมองของมนุษย์
โครงสร้างของโครงข่ายประสาทเทียมนั้นค่อนข้างเรียบง่ายและส่วนใหญ่เกี่ยวกับการคูณเมทริกซ์ ในระหว่างขั้นตอนแรก ข้อมูลนำเข้าจะถูกคูณด้วยน้ำหนักสุ่มเริ่มต้น และอคติ ซึ่งแปลงด้วยฟังก์ชันการเปิดใช้งาน และใช้ค่าเอาต์พุตในการทำนาย ขั้นตอนนี้จะช่วยให้ทราบว่าเครือข่ายอยู่ห่างจากความเป็นจริงเพียงใด
เมตริกที่ใช้คือการสูญเสีย ยิ่งฟังก์ชันการสูญเสียมีค่าสูงขึ้น โมเดลก็จะยิ่งโง่ลง หากต้องการปรับปรุงความรู้เกี่ยวกับเครือข่าย จำเป็นต้องปรับค่าถ่วงน้ำหนักของเน็ตให้เหมาะสม การลดระดับความชันแบบสุ่มเป็นวิธีที่ใช้ในการเปลี่ยนค่าของน้ำหนักในทิศทางที่ถูกต้อง เมื่อปรับแล้ว เครือข่ายสามารถใช้ชุดข้อมูลอื่นเพื่อทดสอบความรู้ใหม่
โชคดีว่าข้อผิดพลาดลดลงกว่าเดิมแต่ก็ไม่เล็กพอ ขั้นตอนการเพิ่มประสิทธิภาพจะดำเนินการซ้ำๆ จนกว่าข้อผิดพลาดจะลดลง กล่าวคือ ไม่สามารถดึงข้อมูลเพิ่มเติมได้
ปัญหาของรุ่นนี้คือไม่มีหน่วยความจำใดๆ หมายความว่าอินพุตและเอาต์พุตเป็นอิสระ กล่าวอีกนัยหนึ่ง โมเดลไม่สนใจว่าอะไรจะเกิดขึ้นก่อนหน้านี้ ทำให้เกิดคำถามขึ้นเมื่อคุณต้องการคาดเดาอนุกรมเวลาหรือประโยค เนื่องจากเครือข่ายจำเป็นต้องมีข้อมูลเกี่ยวกับข้อมูลในอดีตหรือคำในอดีต
เพื่อเอาชนะปัญหานี้ จึงมีการพัฒนาสถาปัตยกรรมประเภทใหม่: เครือข่ายประสาทเทียมแบบเรียกซ้ำ (RNN ต่อไปนี้)
โครงข่ายประสาทเทียมที่เกิดซ้ำ (RNN) คืออะไร?
A โครงข่ายประสาทกำเริบ (RNN) เป็นคลาสของ โครงข่ายประสาทเทียม ซึ่งการเชื่อมต่อระหว่างโหนดต่างๆ จะสร้างกราฟกำกับเพื่อให้เกิดพฤติกรรมไดนามิกชั่วคราว ช่วยจำลองข้อมูลตามลำดับที่ได้มาจากเครือข่ายฟีดฟอร์เวิร์ด มันทำงานคล้ายกับสมองของมนุษย์เพื่อให้ผลลัพธ์ที่คาดการณ์ได้
โครงข่ายประสาทที่เกิดซ้ำมีลักษณะค่อนข้างคล้ายกับโครงข่ายประสาทเทียมแบบเดิม ยกเว้นว่ามีการเพิ่มสถานะหน่วยความจำลงในเซลล์ประสาท การคำนวณเพื่อรวมหน่วยความจำนั้นทำได้ง่าย
ลองนึกภาพแบบจำลองง่ายๆ ที่มีเซลล์ประสาทเพียงเซลล์เดียวที่ดึงข้อมูลจากชุดข้อมูล ในโครงข่ายประสาทเทียมแบบเดิม แบบจำลองจะสร้างเอาต์พุตโดยการคูณอินพุตด้วยน้ำหนักและฟังก์ชันการเปิดใช้งาน ด้วย RNN เอาต์พุตนี้จะถูกส่งกลับไปยังจำนวนครั้งของตัวเอง เราโทร ขั้นตอนเวลา ระยะเวลาที่เอาต์พุตกลายเป็นอินพุตของการคูณเมทริกซ์ถัดไป
ตัวอย่างเช่น ในภาพด้านล่าง คุณจะเห็นว่าเครือข่ายประกอบด้วยเซลล์ประสาทหนึ่งอัน เครือข่ายจะคำนวณการคูณเมทริกซ์ระหว่างอินพุตและน้ำหนัก และเพิ่มความไม่เป็นเชิงเส้นด้วยฟังก์ชันการเปิดใช้งาน มันกลายเป็นเอาท์พุตที่ t-1 เอาต์พุตนี้เป็นอินพุตของการคูณเมทริกซ์ตัวที่สอง

ด้านล่างนี้ เราเขียนโค้ด RNN แบบง่ายๆ ใน TensorFlow เพื่อทำความเข้าใจขั้นตอนและรูปร่างของเอาต์พุตด้วย
เครือข่ายประกอบด้วย:
- สี่อินพุต
- หกเซลล์ประสาท
- ขั้นตอน 2 ครั้ง
เครือข่ายจะดำเนินการตามภาพด้านล่าง
เครือข่ายนี้เรียกว่า 'แบบเรียกซ้ำ' เนื่องจากเครือข่ายดำเนินการแบบเดียวกันในแต่ละช่องเปิดใช้งาน เครือข่ายจะคำนวณน้ำหนักของอินพุตและเอาต์พุตก่อนหน้าเพื่อใช้ฟังก์ชันการเปิดใช้งาน
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]]
เพื่อวัตถุประสงค์ในการอธิบาย คุณพิมพ์ค่าของสถานะก่อนหน้า เอาต์พุตที่พิมพ์ด้านบนแสดงเอาต์พุตจากสถานะสุดท้าย ตอนนี้พิมพ์เอาต์พุตทั้งหมด คุณจะสังเกตได้ว่าสถานะเป็นเอาต์พุตก่อนหน้าของแต่ละชุด นั่นคือเอาต์พุตก่อนหน้าประกอบด้วยข้อมูลเกี่ยวกับลำดับทั้งหมดe
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
เพื่อเอาชนะปัญหาที่อาจเกิดขึ้นจากการไล่ระดับที่หายไปของ RNN นักวิจัยสามคน ได้แก่ Hochreiter, Schmidhuber และ Bengio ได้ปรับปรุง RNN ด้วยสถาปัตยกรรมที่เรียกว่าหน่วยความจำระยะยาวระยะสั้น (LSTM) โดยสรุปแล้ว LSMT จะให้ข้อมูลในอดีตที่เกี่ยวข้องกับเครือข่ายในช่วงเวลาล่าสุด เครื่องจักรใช้สถาปัตยกรรมที่ดีกว่าในการเลือกและส่งข้อมูลกลับไปยังเวลาในภายหลัง
สถาปัตยกรรม LSTM มีอยู่ใน TensorFlow, tf.contrib.rnn.LSTMCell LSTM อยู่นอกขอบเขตของบทช่วยสอน คุณสามารถดูได้จากเว็บไซต์อย่างเป็นทางการ เอกสาร สำหรับข้อมูลเพิ่มเติม
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 การป้อนข้อมูลทั้งหมดในเครือข่ายนั้นไม่สมเหตุสมผล แทนที่คุณจะต้องสร้างชุดข้อมูลที่มีความยาวเท่ากับช่วงเวลา ชุดข้อมูลนี้จะเป็นตัวแปร 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 วัน ให้เลื่อนข้อมูลชุดนั้นไป 2 ครั้ง หากคุณต้องการคาดการณ์ XNUMX วัน ให้เลื่อนข้อมูลไป XNUMX ครั้ง
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 เป็นตัวยึดตำแหน่ง (ตรวจสอบบทช่วยสอนเกี่ยวกับ Introduction to เทนเซอร์โฟลว์ เพื่อให้จิตใจสดชื่นกับการประกาศตัวแปร) มีสามมิติ คือ
- หมายเหตุ: ขนาดของชุด
- 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 นี้ คุณสามารถพล็อตมูลค่าที่แท้จริงของชุดข้อมูลด้วยค่าที่คาดการณ์ไว้ได้ หากแบบจำลองของคุณได้รับการแก้ไข ค่าที่คาดการณ์ไว้ควรวางทับค่าจริง
อย่างที่คุณเห็น โมเดลนี้ยังมีช่องว่างให้ปรับปรุงได้ ขึ้นอยู่กับคุณที่จะเปลี่ยนไฮเปอร์พารามิเตอร์ เช่น หน้าต่าง ขนาดแบตช์ของจำนวนนิวรอนที่เรียกซ้ำ
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()
สรุป
เครือข่ายประสาทเทียมแบบเรียกซ้ำเป็นสถาปัตยกรรมที่แข็งแกร่งเพื่อจัดการกับการวิเคราะห์ลำดับเวลาหรือข้อความ ผลลัพธ์ของสถานะก่อนหน้าคือข้อมูลป้อนกลับเพื่อรักษาหน่วยความจำของเครือข่ายในช่วงเวลาหรือลำดับของคำ
ใน TensorFlow คุณสามารถใช้โค้ดต่อไปนี้เพื่อฝึก TensorFlow Recurrent Neural Network สำหรับชุดเวลา:
พารามิเตอร์ของแบบจำลอง
n_windows = 20 n_input = 1 n_output = 1 size_train = 201
กำหนดแบบจำลอง
X = tf.placeholder(tf.float32, [None, n_windows, n_input]) y = tf.placeholder(tf.float32, [None, n_windows, n_output]) 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])
สร้างการเพิ่มประสิทธิภาพ
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()
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})



