Hướng dẫn về RNN (Mạng thần kinh tái phát): Ví dụ về TensorFlow

Tại sao chúng ta cần Mạng thần kinh tái phát (RNN)?

Mạng thần kinh tái phát (RNN) cho phép bạn lập mô hình các đơn vị bộ nhớ để duy trì dữ liệu và lập mô hình các phần phụ thuộc ngắn hạn. Nó cũng được sử dụng trong dự báo chuỗi thời gian để xác định các mối tương quan và mẫu dữ liệu. Nó cũng giúp tạo ra kết quả dự đoán cho dữ liệu tuần tự bằng cách cung cấp hành vi tương tự như bộ não con người.

Cấu trúc của Mạng thần kinh nhân tạo tương đối đơn giản và chủ yếu là về phép nhân ma trận. Trong bước đầu tiên, đầu vào được nhân với trọng số ngẫu nhiên ban đầu và độ lệch, được biến đổi bằng hàm kích hoạt và các giá trị đầu ra được sử dụng để đưa ra dự đoán. Bước này đưa ra ý tưởng về khoảng cách giữa mạng và thực tế.

Số liệu được áp dụng là tổn thất. Hàm mất mát càng cao thì mô hình càng kém. Để nâng cao kiến ​​thức về mạng, cần phải tối ưu hóa bằng cách điều chỉnh trọng số của mạng. Giảm dần độ dốc ngẫu nhiên là phương pháp được sử dụng để thay đổi giá trị của trọng số theo đúng hướng. Sau khi điều chỉnh được thực hiện, mạng có thể sử dụng một loạt dữ liệu khác để kiểm tra kiến ​​thức mới của mình.

May mắn thay, sai số đã thấp hơn trước nhưng vẫn chưa đủ nhỏ. Bước tối ưu hóa được thực hiện lặp đi lặp lại cho đến khi lỗi được giảm thiểu, tức là không thể trích xuất thêm thông tin nào.

Vấn đề với loại mô hình này là nó không có bất kỳ bộ nhớ nào. Nó có nghĩa là đầu vào và đầu ra độc lập. Nói cách khác, mô hình không quan tâm đến những gì xảy ra trước đó. Nó đặt ra một số câu hỏi khi bạn cần dự đoán chuỗi thời gian hoặc câu vì mạng cần có thông tin về dữ liệu lịch sử hoặc các từ trong quá khứ.

Để khắc phục vấn đề này, một loại kiến ​​trúc mới đã được phát triển: Mạng nơ-ron hồi quy (sau đây gọi là RNN)

Mạng thần kinh tái phát (RNN) là gì?

A Mạng thần kinh tái diễn (RNN) là một lớp của Mạng lưới thần kinh nhân tạo trong đó kết nối giữa các nút khác nhau tạo thành một biểu đồ có hướng để đưa ra hành vi động theo thời gian. Nó giúp mô hình hóa dữ liệu tuần tự có nguồn gốc từ các mạng chuyển tiếp. Nó hoạt động tương tự như bộ não con người để đưa ra kết quả dự đoán.

Mạng nơ-ron hồi quy trông khá giống với mạng nơ-ron truyền thống ngoại trừ trạng thái bộ nhớ được thêm vào các nơ-ron. Việc tính toán để bao gồm một bộ nhớ rất đơn giản.

Hãy tưởng tượng một mô hình đơn giản chỉ có một nơron được cung cấp bởi một loạt dữ liệu. Trong mạng lưới thần kinh truyền thống, mô hình tạo ra đầu ra bằng cách nhân đầu vào với trọng số và hàm kích hoạt. Với RNN, đầu ra này được gửi lại chính nó sau một khoảng thời gian. Chúng tôi gọi bước thời gian khoảng thời gian đầu ra trở thành đầu vào của phép nhân ma trận tiếp theo.

Ví dụ, trong hình bên dưới, bạn có thể thấy mạng bao gồm một nơ-ron. Mạng tính toán phép nhân ma trận giữa đầu vào và trọng số và thêm tính phi tuyến tính bằng hàm kích hoạt. Nó trở thành đầu ra ở t-1. Đầu ra này là đầu vào của phép nhân ma trận thứ hai.

Mạng thần kinh tái diễn (RNN)
Mạng thần kinh tái diễn (RNN)

Dưới đây, chúng tôi mã hóa một RNN đơn giản trong TensorFlow để hiểu bước cũng như hình dạng của đầu ra.

Mạng bao gồm:

  • Bốn đầu vào
  • Sáu tế bào thần kinh
  • bước 2 lần

Mạng sẽ tiến hành như được mô tả trong hình bên dưới.

Mạng thần kinh tái diễn (RNN)

Mạng được gọi là 'recurrent' vì nó thực hiện cùng một thao tác trong mỗi ô kích hoạt. Mạng đã tính toán trọng số của đầu vào và đầu ra trước đó để sử dụng hàm kích hoạt.

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

Chúng ta có thể xây dựng mạng với trình giữ chỗ cho dữ liệu, giai đoạn lặp lại và đầu ra.

  1. Xác định phần giữ chỗ cho dữ liệu
X = tf.placeholder(tf.float32, [None, n_timesteps, n_inputs])

Đây:

  • Không có: Không xác định và sẽ lấy kích thước của lô
  • n_timesteps: Số lần mạng sẽ gửi đầu ra trở lại nơ-ron
  • n_inputs: Số lượng đầu vào mỗi đợt
  1. Xác định mạng tái phát

Như đã đề cập trong hình trên, mạng bao gồm 6 nơ-ron. Mạng sẽ tính tích hai chấm:

  • Nhập dữ liệu với tập trọng số đầu tiên (tức là 6: bằng số lượng nơ-ron)
  • Đầu ra trước đó với tập trọng số thứ hai (tức là 6: tương ứng với số lượng đầu ra)

Lưu ý rằng, trong lần chuyển tiếp đầu tiên, các giá trị của đầu ra trước đó bằng 0 vì chúng tôi không có sẵn bất kỳ giá trị nào.

Đối tượng để xây dựng RNN là tf.contrib.rnn.BasicRNNCell với đối số num_units để xác định số lượng đầu vào

basic_cell = tf.contrib.rnn.BasicRNNCell(num_units=n_neurons)

Bây giờ mạng đã được xác định, bạn có thể tính toán kết quả đầu ra và trạng thái

outputs, states = tf.nn.dynamic_rnn(basic_cell, X, dtype=tf.float32)

Đối tượng này sử dụng một vòng lặp bên trong để nhân các ma trận với số lần thích hợp.

Lưu ý rằng nơ-ron hồi quy là một hàm của tất cả các đầu vào của các bước thời gian trước đó. Đây là cách mạng xây dựng bộ nhớ riêng của mình. Thông tin từ thời gian trước có thể lan truyền trong thời gian tương lai. Đây chính là sự kỳ diệu của mạng nơ-ron Recurrent

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

Để giải thích, bạn in các giá trị của trạng thái trước đó. Đầu ra được in ở trên hiển thị đầu ra từ trạng thái cuối cùng. Bây giờ hãy in tất cả đầu ra, bạn có thể nhận thấy các trạng thái là đầu ra trước đó của mỗi lô. Nghĩa là, đầu ra trước đó chứa thông tin về toàn bộ chuỗi.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)

Mạng thần kinh tái diễn (RNN)

Đầu ra có dạng (3, 2, 6):

  • 3: Số lô
  • 2: Số lượng dấu thời gian
  • 6: Số lượng tế bào thần kinh

Việc tối ưu hóa mạng nơ-ron hồi quy giống hệt với mạng nơ-ron truyền thống. Bạn sẽ thấy chi tiết hơn cách tối ưu hóa mã trong phần tiếp theo của hướng dẫn Mạng thần kinh tái phát này.

Ứng dụng của RNN

RNN có nhiều mục đích sử dụng, đặc biệt là khi dự đoán tương lai. Trong ngành tài chính, RNN có thể hữu ích trong việc dự đoán giá cổ phiếu hoặc dấu hiệu của hướng thị trường chứng khoán (tức là tích cực hoặc tiêu cực).

RNN rất hữu ích cho ô tô tự lái vì nó có thể tránh được tai nạn ô tô bằng cách dự đoán quỹ đạo của ô tô.

RNN được sử dụng rộng rãi trong phân tích văn bản, chú thích hình ảnh, phân tích tình cảm và dịch máy. Ví dụ: người ta có thể sử dụng bài đánh giá phim để hiểu cảm giác của khán giả sau khi xem phim. Việc tự động hóa công việc này rất hữu ích khi hãng phim không có đủ thời gian để xem xét, gắn nhãn, tổng hợp và phân tích các đánh giá. Máy có thể thực hiện công việc với độ chính xác cao hơn.

Hạn chế của RNN

Về lý thuyết, RNN có nhiệm vụ mang thông tin lên nhiều lần. Tuy nhiên, việc truyền bá tất cả thông tin này là khá khó khăn khi bước thời gian quá dài. Khi một mạng có quá nhiều lớp sâu, nó sẽ không thể huấn luyện được. Vấn đề này được gọi là: vấn đề gradient biến mất. Nếu bạn còn nhớ, mạng lưới thần kinh sẽ cập nhật trọng số bằng thuật toán giảm độ dốc. Độ dốc tăng dần khi mạng chuyển xuống các lớp thấp hơn.

Tóm lại, độ dốc không đổi có nghĩa là không có không gian để cải thiện. Mô hình học hỏi từ sự thay đổi độ dốc; sự thay đổi này ảnh hưởng đến đầu ra của mạng. Tuy nhiên, nếu sự khác biệt về độ dốc quá nhỏ (nghĩa là trọng số thay đổi một chút), mạng không thể học bất cứ điều gì và đầu ra cũng vậy. Do đó, một mạng đang đối mặt với vấn đề độ dốc biến mất không thể hội tụ về một giải pháp tốt.

LSTM cải tiến

Để khắc phục vấn đề tiềm ẩn về gradient biến mất mà RNN phải đối mặt, ba nhà nghiên cứu Hochreiter, Schmidhuber và Bengio đã cải tiến RNN bằng một kiến ​​trúc gọi là Long Short-Term Memory (LSTM). Tóm lại, LSMT cung cấp cho mạng thông tin quá khứ có liên quan đến thời gian gần đây hơn. Máy sử dụng một kiến ​​trúc tốt hơn để chọn và mang thông tin trở lại thời gian sau.

Kiến trúc LSTM có sẵn trong TensorFlow, tf.contrib.rnn.LSTMCell. LSTM nằm ngoài phạm vi của hướng dẫn. Bạn có thể tham khảo trang web chính thức tài liệu hướng dẫn để biết thêm thông tin

RNN theo chuỗi thời gian

Trong hướng dẫn TensorFlow RNN này, bạn sẽ sử dụng RNN với dữ liệu chuỗi thời gian. Chuỗi thời gian phụ thuộc vào thời gian trước đó, nghĩa là các giá trị trong quá khứ bao gồm thông tin liên quan mà mạng có thể học hỏi. Ý tưởng đằng sau việc dự đoán chuỗi thời gian là ước tính giá trị tương lai của một chuỗi, chẳng hạn như giá cổ phiếu, nhiệt độ, GDP, v.v.

Việc chuẩn bị dữ liệu cho Keras RNN và chuỗi thời gian có thể hơi phức tạp một chút. Trước hết, mục tiêu là dự đoán giá trị tiếp theo của chuỗi, nghĩa là bạn sẽ sử dụng thông tin trong quá khứ để ước tính giá trị tại t + 1. Nhãn bằng với chuỗi đầu vào và dịch chuyển về phía trước một khoảng thời gian. Thứ hai, số lượng đầu vào được đặt thành 1, tức là một quan sát mỗi lần. Cuối cùng, bước thời gian bằng với chuỗi giá trị số. Ví dụ: nếu bạn đặt bước thời gian thành 10, chuỗi đầu vào sẽ trả về mười lần liên tiếp.

Hãy nhìn vào biểu đồ bên dưới, chúng tôi đã biểu thị dữ liệu chuỗi thời gian ở bên trái và một chuỗi đầu vào giả định ở bên phải. Bạn tạo hàm trả về tập dữ liệu có giá trị ngẫu nhiên cho mỗi ngày từ tháng 2001 năm 2016 đến tháng XNUMX năm XNUMX

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

Đầu ra

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 trong chuỗi thời gian

Phần bên phải của biểu đồ hiển thị tất cả các chuỗi. Nó bắt đầu từ năm 2001 và kết thúc vào năm 2019. Việc cung cấp tất cả dữ liệu trong mạng là vô nghĩa, thay vào đó, bạn cần tạo một loạt dữ liệu có độ dài bằng bước thời gian. Lô này sẽ là biến X. Biến Y giống với X nhưng thay đổi một khoảng thời gian (tức là bạn muốn dự báo t+1).

Cả hai vectơ đều có cùng độ dài. Bạn có thể thấy nó ở phần bên phải của biểu đồ trên. Dòng này biểu thị 10 giá trị của đầu vào X, trong khi các chấm màu đỏ là 10 giá trị của nhãn Y. Lưu ý rằng nhãn bắt đầu trước X một khoảng thời gian và kết thúc một khoảng thời gian sau đó.

Xây dựng RNN để dự đoán Chuỗi thời gian trong TensorFlow

Bây giờ trong khóa đào tạo RNN này, đã đến lúc xây dựng RNN đầu tiên của bạn để dự đoán chuỗi trên. Bạn cần chỉ định một số siêu tham số (các tham số của mô hình, tức là số lượng nơ-ron, v.v.) cho mô hình:

  • Số lượng đầu vào: 1
  • Bước thời gian (cửa sổ trong chuỗi thời gian): 10
  • Số lượng tế bào thần kinh: 120
  • Số lượng đầu ra: 1

Mạng của bạn sẽ học theo chuỗi 10 ngày và chứa 120 nơ-ron tái phát. Bạn cung cấp cho mô hình một đầu vào, tức là một ngày. Hãy thoải mái thay đổi các giá trị để xem mô hình có được cải thiện hay không.

Trước khi xây dựng mô hình, bạn cần chia tập dữ liệu thành tập huấn luyện và tập kiểm tra. Bộ dữ liệu đầy đủ có 222 điểm dữ liệu; bạn sẽ sử dụng 201 điểm đầu tiên để huấn luyện mô hình và 21 điểm cuối cùng để kiểm tra mô hình của mình.

Sau khi xác định một tập huấn luyện và tập kiểm tra, bạn cần tạo một đối tượng chứa các lô. Trong lô này, bạn có các giá trị X và giá trị Y. Hãy nhớ rằng các giá trị X bị trễ một khoảng thời gian. Do đó, bạn sử dụng 200 quan sát đầu tiên và bước thời gian bằng 10. Đối tượng X_batches phải chứa 20 lô có kích thước 10*1. Y_batches có hình dạng giống như đối tượng X_batches nhưng có một khoảng thời gian phía trước.

Bước 1) Tạo tàu và kiểm tra

Trước hết, bạn chuyển chuỗi này thành một cục mịch mảng; sau đó bạn xác định các cửa sổ (tức là số lần mạng sẽ học), số lượng đầu vào, đầu ra và kích thước của tập hợp như được hiển thị trong ví dụ TensorFlow RNN bên dưới.

series = np.array(ts)
n_windows = 20   
n_input =  1
n_output = 1
size_train = 201

Sau đó, bạn chỉ cần chia mảng thành hai tập dữ liệu.

## Split data
train = series[:size_train]
test = series[size_train:]
print(train.shape, test.shape)
(201,) (21,)

Bước 2) Tạo hàm trả về X_batches và y_batches

Để dễ dàng hơn, bạn có thể tạo một hàm trả về hai mảng khác nhau, một cho X_batches và một cho y_batches.

Hãy viết hàm RNN TensorFlow để xây dựng các lô.

Lưu ý rằng, các lô X bị trễ một chu kỳ (chúng ta lấy giá trị t-1). Đầu ra của hàm phải có ba chiều. Chiều đầu tiên bằng số lô, chiều thứ hai bằng kích thước của cửa sổ và chiều cuối cùng bằng số đầu vào.

Phần khó khăn là chọn các điểm dữ liệu một cách chính xác. Đối với các điểm dữ liệu X, bạn chọn các quan sát từ t = 1 đến t =200, trong khi đối với điểm dữ liệu Y, bạn trả về các quan sát từ t = 2 đến 201. Khi bạn có các điểm dữ liệu chính xác, việc định hình lại rất đơn giản loạt bài này.

Để xây dựng đối tượng với các lô, bạn cần chia tập dữ liệu thành mười lô có độ dài bằng nhau (tức là 20). Bạn có thể sử dụng phương pháp định hình lại và chuyển -1 để chuỗi tương tự với kích thước lô. Giá trị 20 là số lượng quan sát mỗi đợt và 1 là số lượng đầu vào.

Bạn cần thực hiện bước tương tự nhưng đối với nhãn.

Lưu ý rằng, bạn cần dịch chuyển dữ liệu theo số lần bạn muốn dự báo. Ví dụ: nếu bạn muốn dự đoán trước một thời gian, thì bạn dịch chuỗi đi 1. Nếu bạn muốn dự báo hai ngày, hãy dịch dữ liệu đi 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

Bây giờ hàm đã được xác định, bạn có thể gọi nó để tạo các lô như trong ví dụ RNN bên dưới.

X_batches, y_batches = create_batches(df = train,
                                      windows = n_windows,
                                      input = n_input,
                                      output = n_output)

Bạn có thể in hình để đảm bảo kích thước chính xác.

print(X_batches.shape, y_batches.shape)
(10, 20, 1) (10, 20, 1)

Bạn cần tạo bộ thử nghiệm chỉ với một lô dữ liệu và 20 quan sát.

Lưu ý rằng, bạn dự báo ngày này qua ngày khác, điều đó có nghĩa là giá trị dự đoán thứ hai sẽ dựa trên giá trị thực của ngày đầu tiên (t+1) của tập dữ liệu thử nghiệm. Trong thực tế, giá trị thực sự sẽ được biết đến.

Nếu bạn muốn dự báo t+2 (tức là hai ngày tới), bạn cần sử dụng giá trị dự đoán t+1; nếu bạn định dự đoán t+3 (trước ba ngày), bạn cần sử dụng giá trị dự đoán t+1 và t+2. Điều hợp lý là rất khó để dự đoán chính xác t+n ngày tới.

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)

Được rồi, kích thước lô của bạn đã sẵn sàng, bạn có thể xây dựng kiến ​​trúc RNN. Hãy nhớ rằng, bạn có 120 tế bào thần kinh hồi quy.

Bước 3) Xây dựng mô hình

Để tạo mô hình, bạn cần xác định ba phần:

  1. Biến với tensor
  2. RNN
  3. Sự mất mát và tối ưu hóa

Bước 3.1) Biến

Bạn cần chỉ định các biến X và y có hình dạng phù hợp. Bước này là tầm thường. Tensor có cùng kích thước với các đối tượng X_batches và y_batches.

Ví dụ: tensor X là một phần giữ chỗ (Xem hướng dẫn về Giới thiệu về Dòng chảy để làm mới tâm trí của bạn về khai báo biến) có ba chiều:

  • Lưu ý: kích thước lô hàng
  • n_windows: Chiều dài của các cửa sổ. tức là số lần mô hình nhìn ngược lại
  • n_input: Số lượng đầu vào

Kết quả là:

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

Bước 3.2) Tạo RNN

Trong phần thứ hai của ví dụ RNN TensorFlow này, bạn cần xác định kiến ​​trúc của mạng. Như trước, bạn sử dụng đối tượng BasicRNNCell và dynamic_rnn từ trình ước tính 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)   

Phần tiếp theo phức tạp hơn một chút nhưng cho phép tính toán nhanh hơn. Bạn cần chuyển đổi đầu ra chạy thành một lớp dày đặc và sau đó chuyển đổi lại để có cùng kích thước với đầu vào.

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

Bước 3.3) Tạo sự mất mát và tối ưu hóa

Việc tối ưu hóa mô hình phụ thuộc vào nhiệm vụ bạn đang thực hiện. Trong hướng dẫn trước về CNN, mục tiêu của bạn là phân loại hình ảnh, trong hướng dẫn RNN này, mục tiêu hơi khác một chút. Bạn được yêu cầu đưa ra dự đoán về một biến liên tục so với một lớp.

Sự khác biệt này rất quan trọng vì nó sẽ thay đổi vấn đề tối ưu hóa. Bài toán tối ưu hóa cho một biến liên tục là tối thiểu hóa sai số bình phương trung bình. Để xây dựng các số liệu này trong TF, bạn có thể sử dụng:

  • tf.reduce_sum(tf.square(kết quả đầu ra – y))

Phần còn lại của mã RNN giống như trước; bạn sử dụng trình tối ưu hóa Adam để giảm tổn thất (tức là MSE):

  • tf.train.AdamOptimizer(learning_rate=learning_rate)
  • tối ưu hóa.minimize(mất)

Thế là xong, bạn có thể đóng gói mọi thứ lại với nhau và mô hình của bạn đã sẵn sàng để huấn luyện.

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

Bạn sẽ huấn luyện mô hình bằng cách sử dụng 1500 kỷ nguyên và in kết quả mất sau mỗi 150 lần lặp. Sau khi mô hình được đào tạo, bạn đánh giá mô hình trên tập kiểm tra và tạo một đối tượng chứa các dự đoán như trong ví dụ về Mạng thần kinh tái phát bên dưới.

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

Cuối cùng trong hướng dẫn RNN Deep Learning này, bạn có thể vẽ giá trị thực của chuỗi với giá trị được dự đoán. Nếu mô hình của bạn được sửa, các giá trị dự đoán sẽ được đặt lên trên các giá trị thực tế.

Như bạn thấy, mô hình có chỗ để cải thiện. Bạn có thể thay đổi các siêu tham số như cửa sổ, kích thước lô của số lượng nơ-ron hồi quy.

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()
Dự báo so với thực tế

Dự báo so với thực tế

Tổng kết

Mạng nơ-ron hồi quy là một kiến ​​trúc mạnh mẽ để xử lý chuỗi thời gian hoặc phân tích văn bản. Đầu ra của trạng thái trước đó là phản hồi để bảo toàn bộ nhớ của mạng theo thời gian hoặc chuỗi từ.

Trong TensorFlow, bạn có thể sử dụng các mã sau để đào tạo Mạng nơ-ron hồi quy TensorFlow cho chuỗi thời gian:

Các thông số của mô hình

n_windows = 20   
n_input =  1
n_output = 1
size_train = 201

Xác định mô hình

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

Xây dựng tối ưu hóa

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)                                          

Đào tạo mô hình

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