import numpy as np np.random.seed(42) import time import os import matplotlib.pyplot as plt import uctc.nn as nn from utils import parameter_data, Dataset use_graphics = False class RegressionModel(object): """ A neural network model for approximating a function that maps from real numbers to real numbers. The network should be sufficiently large to be able to approximate sin(x) on the interval [-2pi, 2pi] to reasonable precision. """ def __init__(self): # Initialize your model parameters here self.batch_size = 10 self.input_features = 1 self.output_features = 1 self.hidden_f1 = 50 self.lr = 0.01 self.w1 = nn.Parameter(parameter_data(self.input_features, self.hidden_f1)) self.b1 = nn.Parameter(parameter_data(1, self.hidden_f1)) self.w2 = nn.Parameter(parameter_data(self.hidden_f1, self.output_features)) self.b2 = nn.Parameter(parameter_data(1, self.output_features)) def run(self, x): """ Runs the model for a batch of examples. Inputs: x: a node with shape (batch_size x 1) Returns: A node with shape (batch_size x 1) containing predicted y-values """ "*** YOUR CODE HERE ***" # uctc linear1 = nn.Linear(x, self.w1) bias1 = nn.AddBias(linear1, self.b1) act1 = nn.ReLU(bias1) linear2 = nn.Linear(act1, self.w2) bias2 = nn.AddBias(linear2, self.b2) # numpy # print(len(x.data())) _x = np.array(x.data()).reshape(-1, 1) _w1 = np.array(self.w1.data()).reshape(self.input_features, -1) _b1 = np.array(self.b1.data()).reshape(1, -1) _w2 = np.array(self.w2.data()).reshape(self.hidden_f1, -1) _b2 = np.array(self.b2.data()).reshape(1, -1) _linear1 = np.dot(_x, _w1) + _b1 _act1 = np.maximum(0.0, _linear1) _linear2 = np.dot(_act1, _w2) + _b2 return bias2 def get_loss(self, x, y): """ Computes the loss for a batch of examples. Inputs: x: a node with shape (batch_size x 1) y: a node with shape (batch_size x 1), containing the true y-values to be used for training Returns: a loss node """ "*** YOUR CODE HERE ***" predict_y = self.run(x) return nn.SquareLoss(predict_y, y) def train(self, dataset): """ Trains the model. """ "*** YOUR CODE HERE ***" itera = 0 while True: for x, y in dataset.iterate_once(self.batch_size): loss = self.get_loss(x, y) g_w1, g_b1, g_w2, g_b2 = nn.gradients(loss, [self.w1, self.b1, self.w2, self.b2]) self.w1.update(g_w1, self.lr) self.b1.update(g_b1, self.lr) self.w2.update(g_w2, self.lr) self.b2.update(g_b2, self.lr) itera += 1 if loss.data()[0] < 0.01: break class RegressionDataset(Dataset): def __init__(self, model: RegressionModel): x = np.expand_dims(np.linspace(-2 * np.pi, 2 * np.pi, num=200), axis=1) np.random.RandomState(0).shuffle(x) self.argsort_x = np.argsort(x.flatten()) y = np.sin(x) super().__init__(x, y) self.model = model self.processed = 0 if use_graphics: fig, ax = plt.subplots(1, 1) ax.set_xlim(-2 * np.pi, 2 * np.pi) ax.set_ylim(-1.4, 1.4) real, = ax.plot(x[self.argsort_x], y[self.argsort_x], color="blue") learned, = ax.plot([], [], color="red") text = ax.text(0.03, 0.97, "", transform=ax.transAxes, va="top") ax.legend([real, learned], ["real", "learned"]) plt.show(block=False) self.fig = fig self.learned = learned self.text = text self.last_update = time.time() def iterate_once(self, batch_size): for x, y in super().iterate_once(batch_size): yield x, y self.processed += batch_size if time.time() - self.last_update > 0.01: predicted = self.model.run(nn.Constant(self.x)).data() loss = self.model.get_loss( x, y).data() predicted = np.array(predicted) loss = loss[0] print(f"processed: {self.processed}\nloss: {loss: .6f}") if use_graphics: self.learned.set_data(self.x[self.argsort_x], predicted[self.argsort_x]) self.text.set_text(f"processed: {self.processed}\nloss: {loss: .6f}") self.fig.canvas.draw_idle() self.fig.canvas.start_event_loop(1e-3) self.last_update = time.time() model = RegressionModel() dataset = RegressionDataset(model) model.train(dataset)