diff --git a/03 Writing Algorithms/31 Machine Learning/03 Popular Libraries/08 Tensorflow/01 Introduction.html b/03 Writing Algorithms/31 Machine Learning/03 Popular Libraries/08 Tensorflow/01 Introduction.html index f81716a41a..a498f4e379 100644 --- a/03 Writing Algorithms/31 Machine Learning/03 Popular Libraries/08 Tensorflow/01 Introduction.html +++ b/03 Writing Algorithms/31 Machine Learning/03 Popular Libraries/08 Tensorflow/01 Introduction.html @@ -1 +1 @@ -
This page explains how to build, train, deploy and store Tensorflow
v1 models. To view the tutorial on Tensorflow 2, see Keras.
This page explains how to build, train, deploy and store Tensorflow
models.
Import the tensorflow
libraries.
Import the tensorflow
and sklearn
libraries.
from AlgorithmImports import * -import tensorflow.compat.v1 as tf -from google.protobuf import json_format -import json5 - -tf.disable_v2_behavior()-
You need the google.protobuf
and json5
libraries to store and load models.
Disable tensorflow
v2 behaviors in order to deploy a v1 model.
Follow these steps to create a method to build the model:
def BuildModel(self): - # Instantiate a tensorflow session - sess = tf.Session() - - # Declare the number of factors and then create placeholders for the input and output layers. - num_factors = 5 - X = tf.placeholder(dtype=tf.float32, shape=[None, num_factors], name='X') - Y = tf.placeholder(dtype=tf.float32, shape=[None]) - - # Set up the weights and bias initializers for each layer. - weight_initializer = tf.variance_scaling_initializer(mode="fan_avg", distribution="uniform", scale=1) - bias_initializer = tf.zeros_initializer() - - # Create hidden layers that use the Relu activator. - num_neurons_1 = 32 - num_neurons_2 = 16 - num_neurons_3 = 8 - - W_hidden_1 = tf.Variable(weight_initializer([num_factors, num_neurons_1])) - bias_hidden_1 = tf.Variable(bias_initializer([num_neurons_1])) - hidden_1 = tf.nn.relu(tf.add(tf.matmul(X, W_hidden_1), bias_hidden_1)) - - W_hidden_2 = tf.Variable(weight_initializer([num_neurons_1, num_neurons_2])) - bias_hidden_2 = tf.Variable(bias_initializer([num_neurons_2])) - hidden_2 = tf.nn.relu(tf.add(tf.matmul(hidden_1, W_hidden_2), bias_hidden_2)) - - W_hidden_3 = tf.Variable(weight_initializer([num_neurons_2, num_neurons_3])) - bias_hidden_3 = tf.Variable(bias_initializer([num_neurons_3])) - hidden_3 = tf.nn.relu(tf.add(tf.matmul(hidden_2, W_hidden_3), bias_hidden_3)) - - # Create the output layer and give it a name, so it is accessible after saving and loading the model. - W_out = tf.Variable(weight_initializer([num_neurons_3, 1])) - bias_out = tf.Variable(bias_initializer([1])) - output = tf.transpose(tf.add(tf.matmul(hidden_3, W_out), bias_out), name='outer') - - # Set up the loss function and optimizers for gradient descent optimization and backpropagation. - # This example uses mean-square error as the loss function because the close price is a continuous data and uses Adam as the optimizer because of its adaptive step size. - loss = tf.reduce_mean(tf.squared_difference(output, Y)) - optimizer = tf.train.AdamOptimizer().minimize(loss) - - return sess, X, Y, output, optimizer-
self.model, self.X, self.Y, self.output, self.optimizer = self.BuildModel(features, labels)+
num_factors = 5 +num_neurons_1 = 10 +num_neurons_2 = 20 +num_neurons_3 = 5 +self.epochs = 20 +self.learning_rate = 0.0001
run
method with the result from the global_variables_initializer
method.self.model.run(tf.global_variables_initializer())+
self.model = tf.keras.Sequential([ + tf.keras.layers.Dense(num_neurons_1, activation=tf.nn.relu, input_shape=(num_factors,)), # input shape required + tf.keras.layers.Dense(num_neurons_2, activation=tf.nn.relu), + tf.keras.layers.Dense(num_neurons_3, activation=tf.nn.relu), + tf.keras.layers.Dense(1) +])
To train the model, define a method that fits the model with the training data.
def get_features_and_labels(self, n_steps=5): - close_prices = list(self.training_data)[::-1] - - features = [] - labels = [] - for i in range(len(close_prices)-n_steps): - features.append(close_prices[i:i+n_steps]) - labels.append(close_prices[i+n_steps]) - features = np.array(features) - labels = np.array(labels) - - return features, labels +def get_features_and_labels(self, lookback=5): + lookback_series = [] + + data = pd.Series(list(self.training_data)[::-1]) + for i in range(1, lookback + 1): + df = data.diff(i)[lookback:-1] + df.name = f"close-{i}" + lookback_series.append(df) + + X = pd.concat(lookback_series, axis=1).reset_index(drop=True).dropna() + Y = data.diff(-1)[lookback:-1].reset_index(drop=True) + return X.values, Y.values def my_training_method(self): features, labels = self.get_features_and_labels() - self.model.run(self.optimizer, feed_dict={self.X: features, self.Y: labels})+ + # Define the loss function, we use MSE in this example + def loss_mse(target_y, predicted_y): + return tf.reduce_mean(tf.square(target_y - predicted_y)) + + # Train the model + optimizer = tf.keras.optimizers.Adam(learning_rate=self.learning_rate) + for i in range(self.epochs): + with tf.GradientTape() as t: + loss = loss_mse(labels, self.model(features)) + + jac = t.gradient(loss, self.model.trainable_weights) + optimizer.apply_gradients(zip(jac, self.model.trainable_weights))
To predict the labels of new data, in the OnData
method, get the most recent set of features and then call the run
method with new features.
new_features, __ = self.get_features_and_labels() -prediction = self.model.run(self.output, feed_dict={self.X: new_features[-1].reshape(1, -1)}) -prediction = float(prediction.flatten()[-1])+prediction = self.model(new_features) +prediction = float(prediction.numpy()[-1])
You can use the label prediction to place orders.
if prediction > slice[self.symbol].Price: +if prediction > 0: self.SetHoldings(self.symbol, 1) else: self.SetHoldings(self.symbol, -1)diff --git a/03 Writing Algorithms/31 Machine Learning/03 Popular Libraries/08 Tensorflow/07 Save Models.html b/03 Writing Algorithms/31 Machine Learning/03 Popular Libraries/08 Tensorflow/07 Save Models.html index f02b19885f..0f733d0846 100644 --- a/03 Writing Algorithms/31 Machine Learning/03 Popular Libraries/08 Tensorflow/07 Save Models.html +++ b/03 Writing Algorithms/31 Machine Learning/03 Popular Libraries/08 Tensorflow/07 Save Models.html @@ -1,22 +1,25 @@Follow these steps to save
Tensorflow
models into the Object Store:-
\ No newline at end of file diff --git a/03 Writing Algorithms/31 Machine Learning/03 Popular Libraries/08 Tensorflow/08 Load Models.html b/03 Writing Algorithms/31 Machine Learning/03 Popular Libraries/08 Tensorflow/08 Load Models.html index 88a86261f4..f57d9280f8 100644 --- a/03 Writing Algorithms/31 Machine Learning/03 Popular Libraries/08 Tensorflow/08 Load Models.html +++ b/03 Writing Algorithms/31 Machine Learning/03 Popular Libraries/08 Tensorflow/08 Load Models.html @@ -1,35 +1,10 @@- Export the
+TensorFlow
graph as a JSON object.- Set the key name of the model to be stored in the Object Store.
-+graph_definition = tf.compat.v1.train.export_meta_graph() -json_graph = json_format.MessageToJson(graph_definition)+model_key = "model.keras"Note that the model has to have the suffix
-.keras
.- Export the
+TensorFlow
weights as a JSON object.- Call the
GetFilePath
method with the key.-+weights = self.model.run(tf.compat.v1.trainable_variables()) -weights = [w.tolist() for w in weights] -json_weights = json5.dumps(weights)+file_name = self.ObjectStore.GetFilePath(model_key)This method returns the file path where the model will be stored.
-- Save the graph and weights to the Object Store.
+- Call the
save
method with the model and file path.-+ +self.ObjectStore.Save('graph', json_graph) -self.ObjectStore.Save('weights', json_weights)+model.save(file_name)+- Save the model to the file path.
++self.ObjectStore.Save(model_key)You can load and trade with pre-trained
tensorflow
models that you saved in the Object Store. To load atensorflow
model from the Object Store, in theInitialize
method, get the file path to the saved model and then recall the graph and weights of the model.-def Initialize(self) -> None: - if self.ObjectStore.ContainsKey('graph') and self.ObjectStore.ContainsKey('weights'): - json_graph = self.ObjectStore.Read('graph') - json_weights = self.ObjectStore.Read('weights') - - # Restore the tensorflow graph from JSON objects - tf.reset_default_graph() - graph_definition = json_format.Parse(json_graph, tf.MetaGraphDef()) - self.model = tf.Session() - tf.train.import_meta_graph(graph_definition) - - # Select the input, output tensors and optimizer - self.X = tf.get_default_graph().get_tensor_by_name('X:0') - self.Y = tf.get_default_graph().get_tensor_by_name('Y:0') - self.output = tf.get_default_graph().get_tensor_by_name('outer:0') - self.optimizer = tf.get_default_graph().get_collection('Variable/Adam') - - # Restore the model weights from the JSON object. - weights = [np.asarray(x) for x in json5.loads(json_weights)] - assign_ops = [] - feed_dict = {} - vs = tf.trainable_variables() - zipped_values = zip(vs, weights) - for var, value in zipped_values: - value = np.asarray(value) - assign_placeholder = tf.placeholder(var.dtype, shape=value.shape) - assign_op = var.assign(assign_placeholder) - assign_ops.append(assign_op) - feed_dict[assign_placeholder] = value - self.model.run(assign_ops, feed_dict=feed_dict)+ model_key = 'model.keras' + if self.ObjectStore.ContainsKey(model_key): + file_name = self.ObjectStore.GetFilePath(model_key) + self.model = tf.keras.models.load_model(file_name)The
\ No newline at end of file +ContainsKey
method returns a boolean that represents if thegraph
andweights
is in the Object Store. If the Object Store doesn't contain the keys, save the model using them before you proceed.The
\ No newline at end of file diff --git a/03 Writing Algorithms/31 Machine Learning/03 Popular Libraries/08 Tensorflow/09 Clone Example Algorithm.html b/03 Writing Algorithms/31 Machine Learning/03 Popular Libraries/08 Tensorflow/09 Clone Example Algorithm.html index 8285a4ab66..b5414bdacb 100644 --- a/03 Writing Algorithms/31 Machine Learning/03 Popular Libraries/08 Tensorflow/09 Clone Example Algorithm.html +++ b/03 Writing Algorithms/31 Machine Learning/03 Popular Libraries/08 Tensorflow/09 Clone Example Algorithm.html @@ -1,6 +1,6 @@ \ No newline at end of file diff --git a/04 Research Environment/08 Machine Learning/03 TensorFlow/02 Import Libraries.html b/04 Research Environment/08 Machine Learning/03 TensorFlow/02 Import Libraries.html index 36c2146b15..a5c71edac1 100644 --- a/04 Research Environment/08 Machine Learning/03 TensorFlow/02 Import Libraries.html +++ b/04 Research Environment/08 Machine Learning/03 TensorFlow/02 Import Libraries.html @@ -1,10 +1,8 @@ -ContainsKey
method returns a boolean that represents if themodel.keras
is in the Object Store. If the Object Store doesn't contain the keys, save the model using them before you proceed.Import the
+tensorflow
,sklearn
,json5
andgoogle.protobuf
libraries.Import the
tensorflow
, andsklearn
libraries.-import tensorflow as tf -from sklearn.model_selection import train_test_split -import json5 -from google.protobuf import json_format+from sklearn.model_selection import train_test_splitYou need the
\ No newline at end of file +sklearn
library to prepare the data and thejson5
andgoogle.protobuf
libraries to save models.You need the
\ No newline at end of file diff --git a/04 Research Environment/08 Machine Learning/03 TensorFlow/04 Prepare Data.html b/04 Research Environment/08 Machine Learning/03 TensorFlow/04 Prepare Data.html index bfe2a50764..ff27b68aa9 100644 --- a/04 Research Environment/08 Machine Learning/03 TensorFlow/04 Prepare Data.html +++ b/04 Research Environment/08 Machine Learning/03 TensorFlow/04 Prepare Data.html @@ -10,11 +10,11 @@sklearn
library to prepare the data.Features -The last 5 closing prices +The last 5 close price differencing to the current price @@ -28,10 +28,11 @@ Labels -The following day's closing price +The following day's price change lookback = 5 lookback_series = [] for i in range(1, lookback + 1): - df = history['close'].shift(i)[lookback:-1] - df.name = f"close_-{i}" + df = data['close'].diff(i)[lookback:-1] + df.name = f"close-{i}" lookback_series.append(df) -X = pd.concat(lookback_series, axis=1).reset_index(drop=True)+X = pd.concat(lookback_series, axis=1).reset_index(drop=True).dropna() +X
The following image shows the format of the features DataFrame:
@@ -39,7 +40,7 @@shift
method to collect the labels.Y = history['close'].shift(-1)+
Y = data['close'].diff(-1)
reset_index
method.Follow these steps to build the model:
reset_default_graph
method.tf.reset_default_graph()-
This method clears the default graph stack and resets the global default graph.
- -Session
constructor.sess = tf.Session()-
num_factors = X_test.shape[1] -X = tf.placeholder(dtype=tf.float32, shape=[None, num_factors], name='X') -Y = tf.placeholder(dtype=tf.float32, shape=[None])-
weight_initializer = tf.variance_scaling_initializer(mode="fan_avg", distribution="uniform", scale=1) -bias_initializer = tf.zeros_initializer()-
num_neurons_1 = 32 -num_neurons_2 = 16 -num_neurons_3 = 8 - -W_hidden_1 = tf.Variable(weight_initializer([num_factors, num_neurons_1])) -bias_hidden_1 = tf.Variable(bias_initializer([num_neurons_1])) -hidden_1 = tf.nn.relu(tf.add(tf.matmul(X, W_hidden_1), bias_hidden_1)) - -W_hidden_2 = tf.Variable(weight_initializer([num_neurons_1, num_neurons_2])) -bias_hidden_2 = tf.Variable(bias_initializer([num_neurons_2])) -hidden_2 = tf.nn.relu(tf.add(tf.matmul(hidden_1, W_hidden_2), bias_hidden_2)) - -W_hidden_3 = tf.Variable(weight_initializer([num_neurons_2, num_neurons_3])) -bias_hidden_3 = tf.Variable(bias_initializer([num_neurons_3])) -hidden_3 = tf.nn.relu(tf.add(tf.matmul(hidden_2, W_hidden_3), bias_hidden_3))+num_neurons_1 = 10 +num_neurons_2 = 20 +num_neurons_3 = 5 +epochs = 20 +learning_rate = 0.0001
In this example, we're constructing the model with the in-built Keras API, with Relu activator for non-linear activation of each tensors.
W_out = tf.Variable(weight_initializer([num_neurons_3, 1])) -bias_out = tf.Variable(bias_initializer([1])) -output = tf.transpose(tf.add(tf.matmul(hidden_3, W_out), bias_out), name='outer')+
model = tf.keras.Sequential([ + tf.keras.layers.Dense(num_neurons_1, activation=tf.nn.relu, input_shape=(num_factors,)), # input shape required + tf.keras.layers.Dense(num_neurons_2, activation=tf.nn.relu), + tf.keras.layers.Dense(num_neurons_3, activation=tf.nn.relu), + tf.keras.layers.Dense(1) +])
This snippet creates a 1-node output for both weight and bias. You must name the output layer so you can access it after you load and save the model.
- -We're using Adam optimizer in this example. You may also consider others like SGD.
loss = tf.reduce_mean(tf.squared_difference(output, Y)) -optimizer = tf.train.AdamOptimizer().minimize(loss)+
optimizer = tf.keras.optimizers.Adam(learning_rate=learning_rate)
Use mean-square error as the loss function because the close price is a continuous data and use Adam as the optimizer because of its adaptive step size.
- -In the context of numerical regression, we use MSE as our objective function. If you're doing classification, cross entropy would be more suitable.
batch_size = len(y_train) // 10 -epochs = 20+
def loss_mse(target_y, predicted_y): + return tf.reduce_mean(tf.square(target_y - predicted_y))
Follow these steps to train the model:
+Iteratively train the model by the set epoch number. The model will train adaptively by the gradient provided by the loss function with the selected optimizer.
+for i in range(epochs): + with tf.GradientTape() as t: + loss = loss_mse(y_train, model(X_train)) -+-
+ jac = t.gradient(loss, model.trainable_weights) + optimizer.apply_gradients(zip(jac, model.trainable_weights))- Call the
-run
method with the result from theglobal_variables_initializer
method.-+ train_loss = loss_mse(y_train, model(X_train)) + test_loss = loss_mse(y_test, model(X_test)) + print(f"""Epoch {i+1}: +Training loss = {train_loss.numpy()}. Test loss = {test_loss.numpy()}""") -sess.run(tf.global_variables_initializer())-- Loop through the number of epochs, select a subset of the training data, and then call the
-run
method with the subset of data.--for _ in range(epochs): - for i in range(0, len(y_train) // batch_size): - start = i * batch_size - batch_x = X_train[start:start + batch_size] - batch_y = y_train[start:start + batch_size] - sess.run(optimizer, feed_dict={X: batch_x, Y: batch_y})-
To test the model, we'll setup a method to plot test set predictions ontop of the SPY price.
def test_model(sess, output, title, X): - prediction = sess.run(output, feed_dict={X: X_test}) - prediction = prediction.reshape(prediction.shape[1], 1) +def test_model(actual, title, X): + prediction = model(X).numpy() + prediction = prediction.reshape(-1, 1) - y_test.reset_index(drop=True).plot(figsize=(16, 6), label="Actual") + plt.figure(figsize=(16, 6)) + plt.plot(actual, label="Actual") plt.plot(prediction, label="Prediction") plt.title(title) plt.xlabel("Time step") @@ -13,7 +14,7 @@ plt.legend() plt.show() -test_model(sess, output, "Test Set Results from Original Model", X)+test_model(y_test, "Test Set Results from Original Model", X_test)
Follow these steps to save models in the Object Store:
TensorFlow
graph as a JSON object.graph_definition = tf.compat.v1.train.export_meta_graph() -json_graph = json_format.MessageToJson(graph_definition)+
model_key = "model.keras"
Note that the model has to have the suffix .keras
.
TensorFlow
weights as a JSON object.GetFilePath
method with the key.# Define a function to get the weights from the tensorflow session -def get_json_weights(sess): - weights = sess.run(tf.compat.v1.trainable_variables()) - weights = [w.tolist() for w in weights] - weights_list = json5.dumps(weights) - return weights_list - -json_weights = get_json_weights(sess) -sess.close() # Close the session opened by the `get_json_weights` function+
file_name = qb.ObjectStore.GetFilePath(model_key)
This method returns the file path where the model will be stored.
-Object Store
.save
method with the model and file path.qb.ObjectStore.Save('graph', json_graph) -qb.ObjectStore.Save('weights', json_weights)+
model.save(file_name)+
qb.ObjectStore.Save(model_key)
You must save a model into the Object Store before you can load it from the Object Store. If you saved a model, follow these steps to load it:
json_graph = qb.ObjectStore.Read('graph') -json_weights = qb.ObjectStore.Read('weights')-
TensorFlow
graph from the JSON object.tf.reset_default_graph() -graph_definition = json_format.Parse(json_graph, tf.compat.v1.MetaGraphDef()) -sess = tf.Session() -tf.compat.v1.train.import_meta_graph(graph_definition)-
X = tf.compat.v1.get_default_graph().get_tensor_by_name('X:0') -output = tf.compat.v1.get_default_graph().get_tensor_by_name('outer:0')+
file_path = self.ObjectStore.GetFilePath(model_key)
TensorFlow
model from the saved path.weights = [np.asarray(x) for x in json5.loads(json_weights)] -assign_ops = [] -feed_dict = {} -vs = tf.compat.v1.trainable_variables() -zipped_values = zip(vs, weights) -for var, value in zipped_values: - value = np.asarray(value) - assign_placeholder = tf.placeholder(var.dtype, shape=value.shape) - assign_op = var.assign(assign_placeholder) - assign_ops.append(assign_op) - feed_dict[assign_placeholder] = value -sess.run(assign_ops, feed_dict=feed_dict)+
model = tf.keras.models.load_model(file_name)