บทช่วยสอน RNN (โครงข่ายประสาทเทียมที่เกิดซ้ำ): ตัวอย่าง TensorFlow

เหตุใดเราจึงต้องมี Recurrent Neural Network (RNN)

Recurrent Neural Network (RNN) ช่วยให้คุณสามารถจำลองหน่วยหน่วยความจำเพื่อคงข้อมูลและสร้างแบบจำลองการพึ่งพาระยะสั้น นอกจากนี้ยังใช้ในการพยากรณ์อนุกรมเวลาเพื่อระบุความสัมพันธ์และรูปแบบของข้อมูล นอกจากนี้ยังช่วยสร้างผลลัพธ์เชิงคาดการณ์สำหรับข้อมูลตามลำดับโดยนำเสนอพฤติกรรมที่คล้ายคลึงกันกับสมองของมนุษย์

โครงสร้างของโครงข่ายประสาทเทียมนั้นค่อนข้างเรียบง่ายและส่วนใหญ่เกี่ยวกับการคูณเมทริกซ์ ในระหว่างขั้นตอนแรก ข้อมูลนำเข้าจะถูกคูณด้วยน้ำหนักสุ่มเริ่มต้น และอคติ ซึ่งแปลงด้วยฟังก์ชันการเปิดใช้งาน และใช้ค่าเอาต์พุตในการทำนาย ขั้นตอนนี้จะช่วยให้ทราบว่าเครือข่ายอยู่ห่างจากความเป็นจริงเพียงใด

เมตริกที่ใช้คือการสูญเสีย ยิ่งฟังก์ชันการสูญเสียมีค่าสูงขึ้น โมเดลก็จะยิ่งโง่ลง หากต้องการปรับปรุงความรู้เกี่ยวกับเครือข่าย จำเป็นต้องปรับค่าถ่วงน้ำหนักของเน็ตให้เหมาะสม การลดระดับความชันแบบสุ่มเป็นวิธีที่ใช้ในการเปลี่ยนค่าของน้ำหนักในทิศทางที่ถูกต้อง เมื่อปรับแล้ว เครือข่ายสามารถใช้ชุดข้อมูลอื่นเพื่อทดสอบความรู้ใหม่

โชคดีว่าข้อผิดพลาดลดลงกว่าเดิมแต่ก็ไม่เล็กพอ ขั้นตอนการเพิ่มประสิทธิภาพจะดำเนินการซ้ำๆ จนกว่าข้อผิดพลาดจะลดลง กล่าวคือ ไม่สามารถดึงข้อมูลเพิ่มเติมได้

ปัญหาของรุ่นนี้คือไม่มีหน่วยความจำใดๆ หมายความว่าอินพุตและเอาต์พุตเป็นอิสระ กล่าวอีกนัยหนึ่ง โมเดลไม่สนใจว่าอะไรจะเกิดขึ้นก่อนหน้านี้ ทำให้เกิดคำถามขึ้นเมื่อคุณต้องการคาดเดาอนุกรมเวลาหรือประโยค เนื่องจากเครือข่ายจำเป็นต้องมีข้อมูลเกี่ยวกับข้อมูลในอดีตหรือคำในอดีต

เพื่อเอาชนะปัญหานี้ จึงมีการพัฒนาสถาปัตยกรรมประเภทใหม่: เครือข่ายประสาทเทียมแบบเรียกซ้ำ (RNN ต่อไปนี้)

โครงข่ายประสาทเทียมที่เกิดซ้ำ (RNN) คืออะไร?

A โครงข่ายประสาทกำเริบ (RNN) เป็นคลาสของ โครงข่ายประสาทเทียม ซึ่งการเชื่อมต่อระหว่างโหนดต่างๆ จะสร้างกราฟกำกับเพื่อให้เกิดพฤติกรรมไดนามิกชั่วคราว ช่วยจำลองข้อมูลตามลำดับที่ได้มาจากเครือข่ายฟีดฟอร์เวิร์ด มันทำงานคล้ายกับสมองของมนุษย์เพื่อให้ผลลัพธ์ที่คาดการณ์ได้

โครงข่ายประสาทที่เกิดซ้ำมีลักษณะค่อนข้างคล้ายกับโครงข่ายประสาทเทียมแบบเดิม ยกเว้นว่ามีการเพิ่มสถานะหน่วยความจำลงในเซลล์ประสาท การคำนวณเพื่อรวมหน่วยความจำนั้นทำได้ง่าย

ลองนึกภาพแบบจำลองง่ายๆ ที่มีเซลล์ประสาทเพียงเซลล์เดียวที่ดึงข้อมูลจากชุดข้อมูล ในโครงข่ายประสาทเทียมแบบเดิม แบบจำลองจะสร้างเอาต์พุตโดยการคูณอินพุตด้วยน้ำหนักและฟังก์ชันการเปิดใช้งาน ด้วย RNN เอาต์พุตนี้จะถูกส่งกลับไปยังจำนวนครั้งของตัวเอง เราโทร ขั้นตอนเวลา ระยะเวลาที่เอาต์พุตกลายเป็นอินพุตของการคูณเมทริกซ์ถัดไป

ตัวอย่างเช่น ในภาพด้านล่าง คุณจะเห็นว่าเครือข่ายประกอบด้วยเซลล์ประสาทหนึ่งอัน เครือข่ายจะคำนวณการคูณเมทริกซ์ระหว่างอินพุตและน้ำหนัก และเพิ่มความไม่เป็นเชิงเส้นด้วยฟังก์ชันการเปิดใช้งาน มันกลายเป็นเอาท์พุตที่ t-1 เอาต์พุตนี้เป็นอินพุตของการคูณเมทริกซ์ตัวที่สอง

โครงข่ายประสาทกำเริบ (RNN)
โครงข่ายประสาทกำเริบ (RNN)

ด้านล่างนี้ เราเขียนโค้ด RNN แบบง่ายๆ ใน TensorFlow เพื่อทำความเข้าใจขั้นตอนและรูปร่างของเอาต์พุตด้วย

เครือข่ายประกอบด้วย:

  • สี่อินพุต
  • หกเซลล์ประสาท
  • ขั้นตอน 2 ครั้ง

เครือข่ายจะดำเนินการตามภาพด้านล่าง

โครงข่ายประสาทกำเริบ (RNN)

เครือข่ายนี้เรียกว่า 'แบบเรียกซ้ำ' เนื่องจากเครือข่ายดำเนินการแบบเดียวกันในแต่ละช่องเปิดใช้งาน เครือข่ายจะคำนวณน้ำหนักของอินพุตและเอาต์พุตก่อนหน้าเพื่อใช้ฟังก์ชันการเปิดใช้งาน

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
    ])

เราสามารถสร้างเครือข่ายที่มีตัวยึดตำแหน่งสำหรับข้อมูล ระยะการเกิดซ้ำ และเอาต์พุต

  1. กำหนดตัวยึดตำแหน่งสำหรับข้อมูล
X = tf.placeholder(tf.float32, [None, n_timesteps, n_inputs])

ที่นี่:

  • ไม่มี: ไม่ทราบ และจะใช้ขนาดของชุดงาน
  • n_timesteps: จำนวนครั้งที่เครือข่ายจะส่งเอาต์พุตกลับไปยังเซลล์ประสาท
  • n_inputs: จำนวนอินพุตต่อแบตช์
  1. กำหนดเครือข่ายที่เกิดซ้ำ

ดังที่ได้กล่าวไว้ในภาพด้านบน เครือข่ายประกอบด้วยเซลล์ประสาท 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)

โครงข่ายประสาทกำเริบ (RNN)

ผลลัพธ์มีรูปร่างเป็น (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()

RNN ในอนุกรมเวลา

ส่วนด้านขวาของกราฟแสดงชุดข้อมูลทั้งหมด เริ่มตั้งแต่ปี 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) สร้างโมเดล

ในการสร้างโมเดล คุณต้องกำหนดสามส่วน:

  1. ตัวแปรที่มีเทนเซอร์
  2. อาร์เอ็นเอ็น
  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})

สรุปโพสต์นี้ด้วย: