Skip to content

Commit 1155ebf

Browse files
committed
Update week47.do.txt
1 parent 553bcab commit 1155ebf

File tree

1 file changed

+163
-0
lines changed

1 file changed

+163
-0
lines changed

doc/src/week47/week47.do.txt

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1168,3 +1168,166 @@ Lecture 4: Advanced Topics in Simple RNNs
11681168
\item Original papers: Pascanu et al. (2013) On the Difficulty of Training RNNs, Bengio et al. (1994) Learning long-term dependencies is difficult.
11691169
\end{itemize}
11701170
\end{frame}
1171+
1172+
1173+
PyTorch RNN Time Series Example
1174+
1175+
We first implement a simple RNN in PyTorch to forecast a univariate time series (a sine wave). The steps are: (1) generate synthetic data and form input/output sequences; (2) define an nn.RNN model; (3) train the model with MSE loss and an optimizer; (4) evaluate on a held-out test set. For example, using a sine wave as in prior tutorials , we create sliding windows of length seq_length. The code below shows each step. We use nn.RNN (the basic recurrent layer) followed by a linear output. The training loop (with MSELoss and Adam) updates the model to minimize prediction error .
1176+
1177+
import numpy as np
1178+
import torch
1179+
from torch import nn, optim
1180+
1181+
# 1. Data preparation: generate a sine wave and create input-output sequences
1182+
time_steps = np.linspace(0, 100, 500)
1183+
data = np.sin(time_steps) # shape (500,)
1184+
seq_length = 20
1185+
X, y = [], []
1186+
for i in range(len(data) - seq_length):
1187+
X.append(data[i:i+seq_length]) # sequence of length seq_length
1188+
y.append(data[i+seq_length]) # next value to predict
1189+
X = np.array(X) # shape (480, seq_length)
1190+
y = np.array(y) # shape (480,)
1191+
# Add feature dimension (1) for the RNN input
1192+
X = X[..., None] # shape (480, seq_length, 1)
1193+
y = y[..., None] # shape (480, 1)
1194+
1195+
# Split into train/test sets (80/20 split)
1196+
train_size = int(0.8 * len(X))
1197+
X_train = torch.tensor(X[:train_size], dtype=torch.float32)
1198+
y_train = torch.tensor(y[:train_size], dtype=torch.float32)
1199+
X_test = torch.tensor(X[train_size:], dtype=torch.float32)
1200+
y_test = torch.tensor(y[train_size:], dtype=torch.float32)
1201+
1202+
# 2. Model definition: simple RNN followed by a linear layer
1203+
class SimpleRNNModel(nn.Module):
1204+
def __init__(self, input_size=1, hidden_size=16, num_layers=1):
1205+
super(SimpleRNNModel, self).__init__()
1206+
# nn.RNN for sequential data (batch_first=True expects (batch, seq_len, features))
1207+
self.rnn = nn.RNN(input_size, hidden_size, num_layers, batch_first=True)
1208+
self.fc = nn.Linear(hidden_size, 1) # output layer for prediction
1209+
1210+
def forward(self, x):
1211+
out, _ = self.rnn(x) # out: (batch, seq_len, hidden_size)
1212+
out = out[:, -1, :] # take output of last time step
1213+
return self.fc(out) # linear layer to 1D output
1214+
1215+
model = SimpleRNNModel(input_size=1, hidden_size=16, num_layers=1)
1216+
print(model) # print model summary (structure)
1217+
# Output example:
1218+
# SimpleRNNModel(
1219+
# (rnn): RNN(1, 16, batch_first=True)
1220+
# (fc): Linear(in_features=16, out_features=1, bias=True)
1221+
# )
1222+
1223+
• Model Explanation: Here input_size=1 because each time step has one feature. The RNN hidden state has size 16, and batch_first=True means input tensors have shape (batch, seq_len, features). We take the last RNN output and feed it through a linear layer to predict the next value .
1224+
1225+
# 3. Training loop: MSE loss and Adam optimizer
1226+
criterion = nn.MSELoss() # mean squared error loss
1227+
optimizer = optim.Adam(model.parameters(), lr=0.01)
1228+
1229+
epochs = 50
1230+
for epoch in range(1, epochs+1):
1231+
model.train()
1232+
optimizer.zero_grad()
1233+
output = model(X_train) # forward pass
1234+
loss = criterion(output, y_train) # compute training loss
1235+
loss.backward() # backpropagate
1236+
optimizer.step() # update weights
1237+
if epoch % 10 == 0:
1238+
print(f'Epoch {epoch}/{epochs}, Loss: {loss.item():.4f}')
1239+
# Sample output:
1240+
# Epoch 10/50, Loss: 0.3604
1241+
# Epoch 20/50, Loss: 0.0542
1242+
# Epoch 30/50, Loss: 0.0207
1243+
# Epoch 40/50, Loss: 0.0102
1244+
# Epoch 50/50, Loss: 0.0065
1245+
1246+
• Training Details: We train for 50 epochs, printing the training loss every 10 epochs. As training proceeds, the loss (MSE) typically decreases, indicating the RNN is learning the sine-wave pattern .
1247+
1248+
# 4. Evaluation on test set
1249+
model.eval()
1250+
with torch.no_grad():
1251+
pred = model(X_test)
1252+
test_loss = criterion(pred, y_test)
1253+
print(f'Test Loss: {test_loss.item():.4f}')
1254+
1255+
# (Optional) View a few actual vs. predicted values
1256+
print("Actual:", y_test[:5].flatten().numpy())
1257+
print("Pred : ", pred[:5].flatten().numpy())
1258+
1259+
• Evaluation: We switch to eval mode and compute loss on the test set. The lower test loss indicates how well the model generalizes. The code prints a few sample predictions against actual values for qualitative assessment. This simple PyTorch RNN code closely follows known tutorials .
1260+
1261+
TensorFlow (Keras) RNN Time Series Example
1262+
1263+
Next, we use TensorFlow/Keras to do the same task. We build a tf.keras.Sequential model with a SimpleRNN layer (the most basic recurrent layer)  followed by a Dense output. The workflow is similar: create the same synthetic sine data and split it into train/test sets; then define, train, and evaluate the model.
1264+
1265+
import numpy as np
1266+
import tensorflow as tf
1267+
1268+
# 1. Data preparation: same sine wave data and sequences as above
1269+
time_steps = np.linspace(0, 100, 500)
1270+
data = np.sin(time_steps) # (500,)
1271+
seq_length = 20
1272+
X, y = [], []
1273+
for i in range(len(data) - seq_length):
1274+
X.append(data[i:i+seq_length])
1275+
y.append(data[i+seq_length])
1276+
X = np.array(X) # (480, seq_length)
1277+
y = np.array(y) # (480,)
1278+
# reshape for RNN: (samples, timesteps, features)
1279+
X = X.reshape(-1, seq_length, 1) # (480, 20, 1)
1280+
y = y.reshape(-1, 1) # (480, 1)
1281+
1282+
# Split into train/test (80/20)
1283+
split = int(0.8 * len(X))
1284+
X_train, X_test = X[:split], X[split:]
1285+
y_train, y_test = y[:split], y[split:]
1286+
1287+
• Data: We use the same sine-wave sequence and sliding-window split as in the PyTorch example . The arrays are reshaped to (batch, timesteps, features) for Keras.
1288+
1289+
# 2. Model definition: Keras SimpleRNN and Dense
1290+
model = tf.keras.Sequential([
1291+
tf.keras.layers.SimpleRNN(16, input_shape=(seq_length, 1)),
1292+
tf.keras.layers.Dense(1)
1293+
])
1294+
model.compile(optimizer='adam', loss='mse') # MSE loss and Adam optimizer
1295+
model.summary()
1296+
# Output example:
1297+
# Model: "sequential"
1298+
# _________________________________________________________________
1299+
# Layer (type) Output Shape Param #
1300+
# =================================================================
1301+
# simple_rnn (SimpleRNN) (None, 16) 288
1302+
# _________________________________________________________________
1303+
# dense (Dense) (None, 1) 17
1304+
# =================================================================
1305+
1306+
• Model Explanation: Here SimpleRNN(16) creates 16 recurrent units. The model summary shows the shapes and number of parameters. (Keras handles the sequence dimension internally.)
1307+
1308+
# 3. Training
1309+
history = model.fit(
1310+
X_train, y_train,
1311+
epochs=50,
1312+
batch_size=32,
1313+
validation_split=0.2, # use 20% of train data for validation
1314+
verbose=1
1315+
)
1316+
# Training progress prints loss/val_loss each epoch
1317+
1318+
• Training: We train for 50 epochs. The fit call also reports validation loss (using a 20% split of the training data) to monitor generalization. (This follows the standard Keras approach .)
1319+
1320+
# 4. Evaluation on test set
1321+
test_loss = model.evaluate(X_test, y_test, verbose=0)
1322+
print(f'Test Loss: {test_loss:.4f}')
1323+
1324+
# (Optional) Predictions
1325+
predictions = model.predict(X_test)
1326+
print("Actual:", y_test.flatten()[:5])
1327+
print("Pred : ", predictions.flatten()[:5])
1328+
1329+
• Evaluation: After training, we call model.evaluate on the test set. A low test loss indicates good forecasting accuracy. We also predict and compare a few samples of actual vs. predicted values. This completes the simple RNN forecasting example in TensorFlow.
1330+
1331+
Both examples use only basic RNN cells (no LSTM/GRU) and include data preparation, model definition, training loop, and evaluation. The PyTorch code uses nn.RNN as in common tutorials  , and the Keras code uses SimpleRNN layer . Each code block above is self-contained and can be run independently with standard libraries (NumPy, PyTorch or TensorFlow).
1332+
1333+
Sources: We adapted the PyTorch example from a tutorial using a sine-wave dataset   , and the Keras steps follow standard time-series RNN usage  .

0 commit comments

Comments
 (0)