#!/usr/bin/python3
# LinearRegressionWIthSyntheticData by Google
# https://colab.research.google.com/github/google/eng-edu/blob/master/ml/cc/exercises/linear_regression_with_synthetic_data.ipynb
#
import pandas as pd 
import tensorflow as tf
from matplotlib import pyplot as plt
#
## DEFINE FUNCTIONS THAT BUILD AND TRAIN A MODEL
def build_model(my_learning_rate):
  """Create and compile a simple linear regression model."""
  # Most simple tf.keras models are sequential. 
  # A sequential model contains one or more layers.
  model = tf.keras.models.Sequential()

  # Describe the topography of the model.
  # The topography of a simple linear regression model
  # is a single node in a single layer. 
  model.add(tf.keras.layers.Dense(units=1, 
                                  input_shape=(1,)))

  # Compile the model topography into code that 
  # TensorFlow can efficiently execute. Configure 
  # training to minimize the model's mean squared error. 
  model.compile(optimizer=tf.keras.optimizers.RMSprop(lr=my_learning_rate),
                loss="mean_squared_error",
                metrics=[tf.keras.metrics.RootMeanSquaredError()])

  return model           


def train_model(model, feature, label, epochs, batch_size):
  """Train the model by feeding it data."""

  # Feed the feature values and the label values to the 
  # model. The model will train for the specified number 
  # of epochs, gradually learning how the feature values
  # relate to the label values. 
  history = model.fit(x=feature,
                      y=label,
                      batch_size=batch_size,
                      epochs=epochs)

  # Gather the trained model's weight and bias.
  trained_weight = model.get_weights()[0]
  trained_bias = model.get_weights()[1]

  # The list of epochs is stored separately from the 
  # rest of history.
  epochs = history.epoch
  
  # Gather the history (a snapshot) of each epoch.
  hist = pd.DataFrame(history.history)

  # Specifically gather the model's root mean 
  #squared error at each epoch. 
  rmse = hist["root_mean_squared_error"]

  return trained_weight, trained_bias, epochs, rmse

print("Defined create_model and train_model")
# #
## DEFINE PLOTTING FUNCTIONS
def plot_the_model(trained_weight, trained_bias, feature, label):
  """Plot the trained model against the training feature and label."""

  # Label the axes.
  plt.xlabel("feature")
  plt.ylabel("label")

  # Plot the feature values vs. label values.
  plt.scatter(feature, label)

  # Create a red line representing the model. The red line starts
  # at coordinates (x0, y0) and ends at coordinates (x1, y1).
  x0 = 0
  y0 = trained_bias
  x1 = my_feature[-1]
  y1 = trained_bias + (trained_weight * x1)
  plt.plot([x0, x1], [y0, y1], c='r')

  # Render the scatter plot and the red line.
  plt.show()

def plot_the_loss_curve(epochs, rmse):
  """Plot the loss curve, which shows loss vs. epoch."""

  plt.figure()
  plt.xlabel("Epoch")
  plt.ylabel("Root Mean Squared Error")

  plt.plot(epochs, rmse, label="Loss")
  plt.legend()
  plt.ylim([rmse.min()*0.97, rmse.max()])
  plt.show()

print("Defined the plot_the_model and plot_the_loss_curve functions.")
# #
#
my_feature = ([1.0, 2.0,  3.0,  4.0,  5.0,  6.0,  7.0,  8.0,  9.0, 10.0, 11.0, 12.0])
my_label   = ([5.0, 8.8,  9.6, 14.2, 18.8, 19.5, 21.4, 26.8, 28.9, 32.0, 33.8, 38.2])
#
learning_rate=0.01
epochs = 10
my_batch_size = 12
#
my_model = build_model(learning_rate)
trained_weight, trained_bias, epochs, rmse = train_model(my_model,my_feature,my_label,epochs,my_batch_size)
plot_the_model(trained_weight,trained_bias,my_feature,my_label)
plot_the_loss_curve(epochs,rmse)
matplotlib.pyplot.legend matplotlib.pyplot.scatter matplotlib.pyplot.figure tensorflow.keras.layers.Dense tensorflow.keras.optimizers.RMSprop pandas.DataFrame matplotlib.pyplot.plot tensorflow.keras.metrics.RootMeanSquaredError matplotlib.pyplot.xlabel matplotlib.pyplot.show tensorflow.keras.models.Sequential matplotlib.pyplot.ylabel
[(14, 'tensorflow.keras.models.Sequential', 'tf.keras.models.Sequential', ([], {}), True, 'import tensorflow as tf\n'), (53, 'pandas.DataFrame', 'pd.DataFrame', (['history.history'], {}), True, 'import pandas as pd\n'), (68, 'matplotlib.pyplot.xlabel', 'plt.xlabel', (['"""feature"""'], {}), True, 'from matplotlib import pyplot as plt\n'), (69, 'matplotlib.pyplot.ylabel', 'plt.ylabel', (['"""label"""'], {}), True, 'from matplotlib import pyplot as plt\n'), (72, 'matplotlib.pyplot.scatter', 'plt.scatter', (['feature', 'label'], {}), True, 'from matplotlib import pyplot as plt\n'), (80, 'matplotlib.pyplot.plot', 'plt.plot', (['[x0, x1]', '[y0, y1]'], {'c': '"""r"""'}), True, 'from matplotlib import pyplot as plt\n'), (83, 'matplotlib.pyplot.show', 'plt.show', ([], {}), True, 'from matplotlib import pyplot as plt\n'), (88, 'matplotlib.pyplot.figure', 'plt.figure', ([], {}), True, 'from matplotlib import pyplot as plt\n'), (89, 'matplotlib.pyplot.xlabel', 'plt.xlabel', (['"""Epoch"""'], {}), True, 'from matplotlib import pyplot as plt\n'), (90, 'matplotlib.pyplot.ylabel', 'plt.ylabel', (['"""Root Mean Squared Error"""'], {}), True, 'from matplotlib import pyplot as plt\n'), (92, 'matplotlib.pyplot.plot', 'plt.plot', (['epochs', 'rmse'], {'label': '"""Loss"""'}), True, 'from matplotlib import pyplot as plt\n'), (93, 'matplotlib.pyplot.legend', 'plt.legend', ([], {}), True, 'from matplotlib import pyplot as plt\n'), (95, 'matplotlib.pyplot.show', 'plt.show', ([], {}), True, 'from matplotlib import pyplot as plt\n'), (19, 'tensorflow.keras.layers.Dense', 'tf.keras.layers.Dense', ([], {'units': '(1)', 'input_shape': '(1,)'}), True, 'import tensorflow as tf\n'), (25, 'tensorflow.keras.optimizers.RMSprop', 'tf.keras.optimizers.RMSprop', ([], {'lr': 'my_learning_rate'}), True, 'import tensorflow as tf\n'), (27, 'tensorflow.keras.metrics.RootMeanSquaredError', 'tf.keras.metrics.RootMeanSquaredError', ([], {}), True, 'import tensorflow as tf\n')]