{"id":52115,"date":"2025-04-25T00:00:00","date_gmt":"2025-04-25T07:00:00","guid":{"rendered":"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/blog\/keras-griddb\/"},"modified":"2025-04-25T00:00:00","modified_gmt":"2025-04-25T07:00:00","slug":"keras-griddb","status":"publish","type":"post","link":"https:\/\/griddb.net\/en\/blog\/keras-griddb\/","title":{"rendered":"Build a Time Series Forecasting Model Using TensorFlow Keras and GridDB"},"content":{"rendered":"<p>This article explains how to build a time series forecasting model using TensorFlow Keras and GridDB. We will retrieve historical stock market data from Yahoo Finance, store it in a GridDB time series container, and use it to train a TensorFlow Keras transformer model for time series forecasting.<\/p>\n<p>GridDB is a robust NoSQL database designed for handling large volumes of real-time data with exceptional efficiency. Its advanced in-memory processing and time series data management features make it an ideal choice for big data and IoT applications, including financial forecasting and real-time analytics.<\/p>\n<h2>Prerequisites<\/h2>\n<p>To run the code in this article, you will need the following libraries:<\/p>\n<ol>\n<li>GridDB C Client<\/li>\n<li>GridDB Python client<\/li>\n<\/ol>\n<p>Follow the instructions on the <a href=\"https:\/\/pypi.org\/project\/griddb-python\/\">GridDB Python Package Index (Pypi)<\/a> page to install these clients.<br \/>\nYou will also need to install TensorFlow, yfinance, Numpy, Pandas, and Matplotlib libraries.<\/p>\n<p>The scripts below will help you install and import the necessary libraries for running the code in this article.<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\">pip install yfinance\npython3 -m pip install tensorflow[and-cuda]<\/code><\/pre>\n<\/div>\n<div class=\"clipboard\">\n<pre><code class=\"language-py\">import os\nimport absl.logging\n\nos.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'\nos.environ['TF_ENABLE_ONEDNN_OPTS'] = '0'\nabsl.logging.set_verbosity(absl.logging.ERROR)\nos.environ['CUDA_VISIBLE_DEVICES'] = '-1'  \n\nimport yfinance as yf\nimport pandas as pd\nimport griddb_python as griddb\nimport numpy as np\nimport tensorflow as tf\nfrom tensorflow import keras\nfrom tensorflow.keras import layers\nfrom tensorflow.keras.utils import disable_interactive_logging\nimport matplotlib.pyplot as plt\nfrom sklearn.preprocessing import MinMaxScaler<\/code><\/pre>\n<\/div>\n<h2>Inserting Stock Market Data into GridDB<\/h2>\n<p>We will use stock market data from Yahoo Finance to train our time series forecasting model.<br \/>\nIn this section, you will see how to fetch stock market data from <a href=\"https:\/\/finance.yahoo.com\/quote\/%5EGSPC\/history\/\">Yahoo Finance<\/a>, create a connection with GridDB, and insert the Yahoo finance data into a GridDB container.<\/p>\n<h3>Fetch Data from Yahoo Finance<\/h3>\n<p>The <code>yfinance.download()<\/code> method allows you to retrieve data from Yahoo Finance into a Pandas dataframe.<br \/>\nIn the script below we retrieve Apple&#8217;s stock prices for the full year of 2023:<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-py\">ticker = \"AAPL\"\nstart_date = \"2023-01-01\"\nend_date = \"2023-12-31\"\ndata = yf.download(ticker, start=start_date, end=end_date)\nprint(f\"Fetched {len(data)} rows of data for {ticker}\")\ndata.head()\n<\/code><\/pre>\n<\/div>\n<p><strong>Output:<\/strong><\/p>\n<p><a href=\"https:\/\/griddb.net\/wp-content\/uploads\/2025\/04\/img1-AAPL-yahoo-finance-stock-data.png\"><img fetchpriority=\"high\" decoding=\"async\" src=\"https:\/\/griddb.net\/wp-content\/uploads\/2025\/04\/img1-AAPL-yahoo-finance-stock-data.png\" alt=\"\" width=\"611\" height=\"312\" class=\"aligncenter size-full wp-image-31509\" srcset=\"\/wp-content\/uploads\/2025\/04\/img1-AAPL-yahoo-finance-stock-data.png 611w, \/wp-content\/uploads\/2025\/04\/img1-AAPL-yahoo-finance-stock-data-300x153.png 300w, \/wp-content\/uploads\/2025\/04\/img1-AAPL-yahoo-finance-stock-data-600x306.png 600w\" sizes=\"(max-width: 611px) 100vw, 611px\" \/><\/a><\/p>\n<h3>Connect to GridDB<\/h3>\n<p>To connect to GridDB you need to call the <code>griddb.StoreFactory.get_instance()<\/code> method to get a GridDB factory instance object.<br \/>\nNext, you need to create a GridDB factory store object using the <code>get_store()<\/code> method. You will need to pass your GridDB host name, cluster, name and user and password to the <code>get_store()<\/code> method. Finally, you can test your connection by randomly retrieve a GridDB container using the <code>get_container()<\/code> method.<\/p>\n<p>The following script shows how to connect to GridDB and test your GridB connection:<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-py\"># GridDB connection details\nDB_HOST = \"127.0.0.1:10001\"\nDB_CLUSTER = \"myCluster\"\nDB_USER = \"admin\"\nDB_PASS = \"admin\"\n\n# creating a connection\n\nfactory = griddb.StoreFactory.get_instance()\n\ntry:\n   gridstore = factory.get_store(\n       notification_member = DB_HOST,\n       cluster_name = DB_CLUSTER,\n       username = DB_USER,\n       password = DB_PASS\n   )\n\n   container1 = gridstore.get_container(\"container1\")\n   if container1 == None:\n       print(\"Container does not exist\")\n   print(\"Successfully connected to GridDB\")\n\nexcept griddb.GSException as e:\n   for i in range(e.get_error_stack_size()):\n       print(\"[\", i, \"]\")\n       print(e.get_error_code(i))\n       print(e.get_location(i))\n       print(e.get_message(i))<\/code><\/pre>\n<\/div>\n<p><strong>Output:<\/strong><\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\">Container does not exist\nSuccessfully connected to GridDB<\/code><\/pre>\n<\/div>\n<h3>Create Container for Stock Data in GridDB<\/h3>\n<p>A GridDB container is a fundamental data structure in used for storing and managing data in GridDB.<br \/>\nWe will store the Yahoo Finance data we retrieved in a time series type container.<\/p>\n<p>To create a container you first need to call the <code>ContainerInfo()<\/code> method and pass it the container name, a list of lists containing data columns and types, and the container type which in our case will be <code>griddb.ContainerType.TIME_SERIES<\/code>.<\/p>\n<p>Next, call the <code>put_container()<\/code> method and pass it as a parameter the container info object you previously created.<br \/>\nThe script below shows how to create the <code>AAPL_stock_data<\/code> container in GridDB.<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-py\">container_name = f\"{ticker}_stock_data\"\ncolumn_info = [\n    [\"Timestamp\", griddb.Type.TIMESTAMP],\n    [\"Open\", griddb.Type.DOUBLE],\n    [\"High\", griddb.Type.DOUBLE],\n    [\"Low\", griddb.Type.DOUBLE],\n    [\"Close\", griddb.Type.DOUBLE],\n    [\"Volume\", griddb.Type.LONG]\n]\ncontainer_info = griddb.ContainerInfo(container_name, column_info, griddb.ContainerType.TIME_SERIES)\n\ntry:\n    gridstore.put_container(container_info)\n    container = gridstore.get_container(container_name)\n    if container is None:\n        print(f\"Failed to create or retrieve container: {container_name}\")\n    else:\n        print(f\"Successfully created and retrieved container: {container_name}\")\nexcept griddb.GSException as e:\n    print(f\"Error creating or retrieving container {container_name}:\")\n    for i in range(e.get_error_stack_size()):\n        print(f\"[{i}]\")\n        print(f\"Error code: {e.get_error_code(i)}\")\n        print(f\"Location: {e.get_location(i)}\")\n        print(f\"Message: {e.get_message(i)}\")<\/code><\/pre>\n<\/div>\n<p><strong>Output:<\/strong><\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\">Successfully created and retrieved container: AAPL_stock_data<\/code><\/pre>\n<\/div>\n<h3>Insert Data into GridDB Container<\/h3>\n<p>The last step is to insert the Yahoo Finance data from the Pandas DataFrame into the GridDB container you created in the previous script.<br \/>\nTo do so, you can iterate through all the rows of a Pandas DataFrame, call the container&#8217;s <code>put()<\/code> method and pass it the data you want to store in the container.<\/p>\n<p>The script below shows how to store Yahoo Finance Data in a GridDB container.<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-py\">try:\n    for index, row in data.iterrows():\n        container.put([index.to_pydatetime(), row['Open'], row['High'], row['Low'], row['Close'], int(row['Volume'])])\n    print(f\"Successfully inserted {len(data)} rows of data into {container_name}\")\nexcept griddb.GSException as e:\n    print(f\"Error inserting data into container {container_name}:\")\n    for i in range(e.get_error_stack_size()):\n        print(f\"[{i}]\")\n        print(f\"Error code: {e.get_error_code(i)}\")\n        print(f\"Location: {e.get_location(i)}\")\n        print(f\"Message: {e.get_message(i)}\")<\/code><\/pre>\n<\/div>\n<p><strong>Output:<\/strong><\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\">Successfully inserted 250 rows of data into AAPL_stock_data<\/code><\/pre>\n<\/div>\n<h2>Creating a Stock Market Forecasting Model Using TensorFlow Keras<\/h2>\n<p>We have now Successfully stored our time series stock market data in GriDB, next we will train a TensorFlow Keras model for time series forecasting.<\/p>\n<h3>Retrieving Data from GridDB<\/h3>\n<p>First we will retrieve data from our GridDB container and store it in a Pandas DataFrame.<br \/>\nTo do so, call the <code>get_container()<\/code> method and pass to it the name of the container you want to retrieve.<br \/>\nNext, call <code>SELECT *<\/code> query on the container using the <code>query()<\/code> method.<br \/>\nCall the <code>fetch()<\/code> method to run the query and finally the <code>fetch_rows()<\/code> function to store returned records in a Pandas DataFrame.<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-py\">def retrieve_data_from_griddb(container_name):\n\n    try:\n        stock_data_container = gridstore.get_container(container_name)\n\n        # Query all data from the container\n        query = stock_data_container.query(\"select *\")\n        rs = query.fetch()  # Adjust the number based on your data size\n\n        data = rs.fetch_rows()\n        data .set_index(\"Timestamp\", inplace=True)\n        return data\n\n    except griddb.GSException as e:\n        print(f\"Error retrieving data from GridDB: {e.get_message()}\")\n        return none\n\nstock_data = retrieve_data_from_griddb(\"AAPL_stock_data\")\nstock_data.head()\n<\/code><\/pre>\n<\/div>\n<p><strong>Output:<\/strong><\/p>\n<p><a href=\"https:\/\/griddb.net\/wp-content\/uploads\/2025\/04\/img2-data-retrieved-from-griddb.png\"><img decoding=\"async\" src=\"https:\/\/griddb.net\/wp-content\/uploads\/2025\/04\/img2-data-retrieved-from-griddb.png\" alt=\"\" width=\"496\" height=\"197\" class=\"aligncenter size-full wp-image-31510\" srcset=\"\/wp-content\/uploads\/2025\/04\/img2-data-retrieved-from-griddb.png 496w, \/wp-content\/uploads\/2025\/04\/img2-data-retrieved-from-griddb-300x119.png 300w\" sizes=\"(max-width: 496px) 100vw, 496px\" \/><\/a><\/p>\n<h3>Data Preprocessing for TensorFlow Keras Transformer Model<\/h3>\n<p>We will use a <a href=\"https:\/\/keras.io\/examples\/timeseries\/timeseries_classification_transformer\/\">Transformer model from TensorFlow Keras<\/a> for time series forecasting in this article. You can also use a <a href=\"https:\/\/en.wikipedia.org\/wiki\/Long_short-term_memory\">long short term memory (LSTM)<\/a> or <a href=\"https:\/\/www.sciencedirect.com\/science\/article\/pii\/S0888327020307846\">one-dimensional convolutional neural networks (1D-CNN)<\/a> as well. However, transformers, being the state of the art are likely to outperform the other models.<\/p>\n<p>We will use the <code>Open<\/code> and <code>Volume<\/code> stock prices for the last seven days to predict the <code>Open<\/code> stock price for the next day.<br \/>\nTo do so, we will divide our data into into feature (<code>X<\/code>) and labels (<code>y<\/code>) set, and the into training (80%) and test(20%) sets. We will also normalize our data since deep learning models are known to work better with the normalized data.<\/p>\n<p>The following script preprocesses and normalizes the dataset.<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-py\">features = ['Open', 'Volume']\ndata = stock_data[features].values\n\n# Initialize the scaler\nscaler = MinMaxScaler(feature_range=(0, 1))\n\n# Fit the scaler to the data and transform\ndata_normalized = scaler.fit_transform(data)\n\n# Create sequences\ndef create_sequences(data, seq_length):\n    X, y = [], []\n    for i in range(len(data) - seq_length):\n        X.append(data[i:(i + seq_length), :])\n        y.append(data[i + seq_length, 0])  # Predicting next day's Open price\n    return np.array(X), np.array(y)\n\n\nseq_length = 7 # stock prices of last 7 days\nX, y = create_sequences(data_normalized, seq_length)\n\n# Split the data into training and testing sets\nsplit = int(0.8 * len(X))\nX_train, X_test = X[:split], X[split:]\ny_train, y_test = y[:split], y[split:]\n<\/code><\/pre>\n<\/div>\n<h3>Creating a TensorFlow Keras Transformer Model<\/h3>\n<p>Next, we will define our transformer model architecture. Our model will consist of a <a href=\"https:\/\/paperswithcode.com\/method\/multi-head-attention\">multiheaded attention layer<\/a>, followed by two 1-D convolutional neural network layers. We will also add dropout and layer normalization to avoid overfitting. You can modify the model architecture if you want.<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-py\"># Define the Transformer block\ndef transformer_encoder(inputs, head_size, num_heads, ff_dim, dropout=0):\n    # Attention and Normalization\n    x = layers.MultiHeadAttention(\n        key_dim=head_size, num_heads=num_heads, dropout=dropout\n    )(inputs, inputs)\n    x = layers.Dropout(dropout)(x)\n    x = layers.LayerNormalization(epsilon=1e-6)(x)\n    res = x + inputs\n\n    # Feed Forward Part\n    x = layers.Conv1D(filters=ff_dim, kernel_size=1, activation=\"relu\")(res)\n    x = layers.Dropout(dropout)(x)\n    x = layers.Conv1D(filters=inputs.shape[-1], kernel_size=1)(x)\n    x = layers.LayerNormalization(epsilon=1e-6)(x)\n    return x + res<\/code><\/pre>\n<\/div>\n<p>=Subsequently, we will define the <code>build_model()<\/code> method that builds our model. The model takes our data features and labels as inputs, pass the data through transformer model we just defined. The output of the transformer model is passed through a <a href=\"https:\/\/paperswithcode.com\/method\/global-average-pooling\">global average pooling layer<\/a>, followed by three dense layers to get the final model output.<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-py\"># Build the model\ndef build_model(\n    input_shape,\n    head_size,\n    num_heads,\n    ff_dim,\n    num_transformer_blocks,\n    mlp_units,\n    dropout=0,\n    mlp_dropout=0,\n):\n    inputs = keras.Input(shape=input_shape)\n    x = inputs\n    for _ in range(num_transformer_blocks):\n        x = transformer_encoder(x, head_size, num_heads, ff_dim, dropout)\n\n    x = layers.GlobalAveragePooling1D(data_format=\"channels_first\")(x)\n    for dim in mlp_units:\n        x = layers.Dense(dim, activation=\"relu\")(x)\n        x = layers.Dropout(mlp_dropout)(x)\n    outputs = layers.Dense(1)(x)\n    return keras.Model(inputs, outputs)<\/code><\/pre>\n<\/div>\n<p>Next, we pass the model configurations to the <code>build_model()<\/code> function and get the model object back from the function. We call the <code>compile()<\/code> method to compile the model.<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-py\"># Create the model\ninput_shape = X_train.shape[1:]\nmodel = build_model(\n    input_shape,\n    head_size=256,\n    num_heads=4,\n    ff_dim=4,\n    num_transformer_blocks=4,\n    mlp_units=[128],\n    mlp_dropout=0.4,\n    dropout=0.25,\n)\n# Compile the model\nmodel.compile(\n    optimizer=keras.optimizers.Adam(learning_rate=1e-4),\n    loss=\"mse\",\n    metrics=[\"mae\"]\n)<\/code><\/pre>\n<\/div>\n<p>Next, we define call backs for early stopping, storing the best model weights, and reducing the learning rate.<\/p>\n<p>Finally, we call the <code>fit()<\/code> method an pass it our training data to start model training.<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-py\"># Define callbacks\ncallbacks = [\n    keras.callbacks.EarlyStopping(patience=10, restore_best_weights=True),\n    keras.callbacks.ReduceLROnPlateau(factor=0.5, patience=5, min_lr=1e-6),\n]\n\n# Train the model\nhistory = model.fit(\n    X_train,\n    y_train,\n    validation_split=0.2,\n    epochs=100,\n    batch_size=32,\n    callbacks=callbacks,\n)<\/code><\/pre>\n<\/div>\n<p><strong>Output:<\/strong><\/p>\n<p><a href=\"https:\/\/griddb.net\/wp-content\/uploads\/2025\/04\/img3-keras-transformer-training-results.png\"><img decoding=\"async\" src=\"https:\/\/griddb.net\/wp-content\/uploads\/2025\/04\/img3-keras-transformer-training-results.png\" alt=\"\" width=\"1052\" height=\"283\" class=\"aligncenter size-full wp-image-31511\" srcset=\"\/wp-content\/uploads\/2025\/04\/img3-keras-transformer-training-results.png 1052w, \/wp-content\/uploads\/2025\/04\/img3-keras-transformer-training-results-300x81.png 300w, \/wp-content\/uploads\/2025\/04\/img3-keras-transformer-training-results-1024x275.png 1024w, \/wp-content\/uploads\/2025\/04\/img3-keras-transformer-training-results-768x207.png 768w, \/wp-content\/uploads\/2025\/04\/img3-keras-transformer-training-results-600x161.png 600w\" sizes=\"(max-width: 1052px) 100vw, 1052px\" \/><\/a><\/p>\n<p>The script below shows the training and validation losses for our model. The curves show that our model is not overfitting.<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-py\">plt.figure(figsize=(12, 6))\nplt.plot(history.history['loss'], label='Training Loss')\nplt.plot(history.history['val_loss'], label='Validation Loss')\nplt.title('Model Training History')\nplt.ylabel('Loss')\nplt.xlabel('Epoch')\nplt.legend()\nplt.show()<\/code><\/pre>\n<\/div>\n<p><strong>Output:<\/strong><\/p>\n<p><a href=\"https:\/\/griddb.net\/wp-content\/uploads\/2025\/04\/img4-model-training-history.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/griddb.net\/wp-content\/uploads\/2025\/04\/img4-model-training-history.png\" alt=\"\" width=\"1048\" height=\"567\" class=\"aligncenter size-full wp-image-31512\" srcset=\"\/wp-content\/uploads\/2025\/04\/img4-model-training-history.png 1048w, \/wp-content\/uploads\/2025\/04\/img4-model-training-history-300x162.png 300w, \/wp-content\/uploads\/2025\/04\/img4-model-training-history-1024x554.png 1024w, \/wp-content\/uploads\/2025\/04\/img4-model-training-history-768x416.png 768w, \/wp-content\/uploads\/2025\/04\/img4-model-training-history-600x325.png 600w\" sizes=\"(max-width: 1048px) 100vw, 1048px\" \/><\/a><\/p>\n<h3>Evaluating the Model Performance<\/h3>\n<p>Let&#8217;s evaluate our model&#8217;s performance on the training and test sets.<br \/>\nThe output of the following script shows that we receive a mean absolute error score of 0.1596 which is greater than 0.0788. This shows that our model is overfitting on training set.<\/p>\n<p>Next, we will plot the actual and predicted stock prices side-by-side on a line plot. It is important to note that we have to inverse the effect of data scaling that we did during the data preprocessing step.<br \/>\nThe following script also does that.<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-py\">\ntest_loss, test_mae = model.evaluate(X_test, y_test)\nprint(f\"Test MAE: {test_mae:.4f}\")\n\n# When making predictions and inverse transforming:\ntrain_predictions = model.predict(X_train)\ntest_predictions = model.predict(X_test)\n\n# Inverse transform predictions (for Open price only)\ntrain_predictions = scaler.inverse_transform(np.column_stack((train_predictions, np.zeros_like(train_predictions))))[:, 0]\ntest_predictions = scaler.inverse_transform(np.column_stack((test_predictions, np.zeros_like(test_predictions))))[:, 0]\n\n# Inverse transform actual values\ny_train_actual = scaler.inverse_transform(np.column_stack((y_train.reshape(-1, 1), np.zeros_like(y_train.reshape(-1, 1)))))[:, 0]\ny_test_actual = scaler.inverse_transform(np.column_stack((y_test.reshape(-1, 1), np.zeros_like(y_test.reshape(-1, 1)))))[:, 0]<\/code><\/pre>\n<\/div>\n<p><strong>Output:<\/strong><\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\">Test MAE: 0.1596<\/code><\/pre>\n<\/div>\n<p>Finally, the script below plots the actual stock prices for the training set, and the actual and predicted stock prices for the test set.<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-py\"># Get the actual prices for the entire dataset\ny_actual = np.concatenate([y_train_actual, y_test_actual])\n\n# Create a date range for the entire dataset\nfull_date_range = pd.date_range(start=stock_data.index[seq_length], periods=len(y_actual), freq='B')\n\n# Get the date range for the test set\ntest_date_range = full_date_range[-len(y_test_actual):]\n\n# Plot results\nplt.figure(figsize=(20, 10))\n\n# Plot the entire actual price series\nplt.plot(full_date_range, y_actual, label='Actual', color='blue')\n\n# Plot only the test predictions\nplt.plot(test_date_range, test_predictions, label='Predicted (Test Set)', color='red', linestyle='--')\n\n# Add a vertical line to indicate the start of the test set\nsplit_date = full_date_range[-len(y_test_actual)]\nplt.axvline(x=split_date, color='green', linestyle='--', label='Test Set Start')\n\nplt.title('Stock Open Price - Actual vs Predicted (Test Set)', fontsize=20)\nplt.xlabel('Date', fontsize=16)\nplt.ylabel('Open Price', fontsize=16)\nplt.legend(fontsize=14)\nplt.grid(True, which='both', linestyle='--', linewidth=0.5)\n\n# Rotate and align the tick labels so they look better\nplt.gcf().autofmt_xdate()\n\n\n# Show the plot\nplt.show()<\/code><\/pre>\n<\/div>\n<p><strong>Output:<\/strong><\/p>\n<p><a href=\"https:\/\/griddb.net\/wp-content\/uploads\/2025\/04\/img5-line-plots-for-actual-predicted-stock-prices.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/griddb.net\/wp-content\/uploads\/2025\/04\/img5-line-plots-for-actual-predicted-stock-prices.png\" alt=\"\" width=\"1057\" height=\"506\" class=\"aligncenter size-full wp-image-31513\" srcset=\"\/wp-content\/uploads\/2025\/04\/img5-line-plots-for-actual-predicted-stock-prices.png 1057w, \/wp-content\/uploads\/2025\/04\/img5-line-plots-for-actual-predicted-stock-prices-300x144.png 300w, \/wp-content\/uploads\/2025\/04\/img5-line-plots-for-actual-predicted-stock-prices-1024x490.png 1024w, \/wp-content\/uploads\/2025\/04\/img5-line-plots-for-actual-predicted-stock-prices-768x368.png 768w, \/wp-content\/uploads\/2025\/04\/img5-line-plots-for-actual-predicted-stock-prices-600x287.png 600w\" sizes=\"(max-width: 1057px) 100vw, 1057px\" \/><\/a><\/p>\n<p>From the above output, you can see that model predictions are quite close to the actual stock prices. The model also captures the bullish and bearish trend.<\/p>\n<h2>Conclusion<\/h2>\n<p>In this article, you learned how to create a TensorFlow Keras model for time series forecasting using data from GridDB. We explored how to connect to GridDB, insert financial data into a time series container, and retrieve it for further processing. We also demonstrated how to build a Transformer-based neural network model for predicting stock prices. You can use the code in this article for developing any time series forecasting model using GridDB time series data.<\/p>\n<p>GridDB is a highly efficient NoSQL database, optimized for handling large-scale time series data, which makes it ideal for applications like financial forecasting and real-time analytics. Using TensorFlow\u2019s advanced deep learning and AI capabilities and GridDB\u2019s powerful data management system, you can build scalable and performant forecasting models.<\/p>\n<p>You can find the complete code for this blog on my <a href=\"https:\/\/github.com\/usmanmalik57\/GridDB-Blogs\/blob\/main\/Time%20series%20Forecasting%20Using%20TensorFlow%20Keras%20with%20GridDB%20as%20Database\/Jupyter%20Notebook%20Codes.ipynb\">GridDB Blogs GitHub<\/a> repository. For any questions or issues related to GridDB, feel free to reach out on Stack Overflow using the <code>griddb<\/code> tag to get prompt response from our engineers.<\/p>\n<p><strong>Please note:<\/strong> This article is for educational purposes only and does not serve as financial or stock trading advice.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This article explains how to build a time series forecasting model using TensorFlow Keras and GridDB. We will retrieve historical stock market data from Yahoo Finance, store it in a GridDB time series container, and use it to train a TensorFlow Keras transformer model for time series forecasting. GridDB is a robust NoSQL database designed [&hellip;]<\/p>\n","protected":false},"author":41,"featured_media":52116,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[121],"tags":[],"class_list":["post-52115","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.1.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Build a Time Series Forecasting Model Using TensorFlow Keras and GridDB | GridDB: Open Source Time Series Database for IoT<\/title>\n<meta name=\"description\" content=\"This article explains how to build a time series forecasting model using TensorFlow Keras and GridDB. We will retrieve historical stock market data from\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/griddb.net\/en\/blog\/keras-griddb\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Build a Time Series Forecasting Model Using TensorFlow Keras and GridDB | GridDB: Open Source Time Series Database for IoT\" \/>\n<meta property=\"og:description\" content=\"This article explains how to build a time series forecasting model using TensorFlow Keras and GridDB. We will retrieve historical stock market data from\" \/>\n<meta property=\"og:url\" content=\"https:\/\/griddb.net\/en\/blog\/keras-griddb\/\" \/>\n<meta property=\"og:site_name\" content=\"GridDB: Open Source Time Series Database for IoT\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/griddbcommunity\/\" \/>\n<meta property=\"article:published_time\" content=\"2025-04-25T07:00:00+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/griddb.net\/wp-content\/uploads\/2025\/12\/stock-market-graphs_2560x1920.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"2560\" \/>\n\t<meta property=\"og:image:height\" content=\"1920\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"griddb-admin\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@GridDBCommunity\" \/>\n<meta name=\"twitter:site\" content=\"@GridDBCommunity\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"griddb-admin\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"13 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/griddb.net\/en\/blog\/keras-griddb\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/griddb.net\/en\/blog\/keras-griddb\/\"},\"author\":{\"name\":\"griddb-admin\",\"@id\":\"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/#\/schema\/person\/4fe914ca9576878e82f5e8dd3ba52233\"},\"headline\":\"Build a Time Series Forecasting Model Using TensorFlow Keras and GridDB\",\"datePublished\":\"2025-04-25T07:00:00+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/griddb.net\/en\/blog\/keras-griddb\/\"},\"wordCount\":1262,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/#organization\"},\"image\":{\"@id\":\"https:\/\/griddb.net\/en\/blog\/keras-griddb\/#primaryimage\"},\"thumbnailUrl\":\"\/wp-content\/uploads\/2025\/12\/stock-market-graphs_2560x1920.jpg\",\"articleSection\":[\"Blog\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/griddb.net\/en\/blog\/keras-griddb\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/griddb.net\/en\/blog\/keras-griddb\/\",\"url\":\"https:\/\/griddb.net\/en\/blog\/keras-griddb\/\",\"name\":\"Build a Time Series Forecasting Model Using TensorFlow Keras and GridDB | GridDB: Open Source Time Series Database for IoT\",\"isPartOf\":{\"@id\":\"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/griddb.net\/en\/blog\/keras-griddb\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/griddb.net\/en\/blog\/keras-griddb\/#primaryimage\"},\"thumbnailUrl\":\"\/wp-content\/uploads\/2025\/12\/stock-market-graphs_2560x1920.jpg\",\"datePublished\":\"2025-04-25T07:00:00+00:00\",\"description\":\"This article explains how to build a time series forecasting model using TensorFlow Keras and GridDB. We will retrieve historical stock market data from\",\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/griddb.net\/en\/blog\/keras-griddb\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/griddb.net\/en\/blog\/keras-griddb\/#primaryimage\",\"url\":\"\/wp-content\/uploads\/2025\/12\/stock-market-graphs_2560x1920.jpg\",\"contentUrl\":\"\/wp-content\/uploads\/2025\/12\/stock-market-graphs_2560x1920.jpg\",\"width\":2560,\"height\":1920},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/#website\",\"url\":\"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/\",\"name\":\"GridDB: Open Source Time Series Database for IoT\",\"description\":\"GridDB is an open source time-series database with the performance of NoSQL and convenience of SQL\",\"publisher\":{\"@id\":\"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/#organization\",\"name\":\"Fixstars\",\"url\":\"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/griddb.net\/wp-content\/uploads\/2019\/04\/fixstars_logo_web_tagline.png\",\"contentUrl\":\"https:\/\/griddb.net\/wp-content\/uploads\/2019\/04\/fixstars_logo_web_tagline.png\",\"width\":200,\"height\":83,\"caption\":\"Fixstars\"},\"image\":{\"@id\":\"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/griddbcommunity\/\",\"https:\/\/x.com\/GridDBCommunity\",\"https:\/\/www.linkedin.com\/company\/griddb-by-toshiba\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/#\/schema\/person\/4fe914ca9576878e82f5e8dd3ba52233\",\"name\":\"griddb-admin\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/5bceca1cafc06886a7ba873e2f0a28011a1176c4dea59709f735b63ae30d0342?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/5bceca1cafc06886a7ba873e2f0a28011a1176c4dea59709f735b63ae30d0342?s=96&d=mm&r=g\",\"caption\":\"griddb-admin\"},\"url\":\"https:\/\/griddb.net\/en\/author\/griddb-admin\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Build a Time Series Forecasting Model Using TensorFlow Keras and GridDB | GridDB: Open Source Time Series Database for IoT","description":"This article explains how to build a time series forecasting model using TensorFlow Keras and GridDB. We will retrieve historical stock market data from","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/griddb.net\/en\/blog\/keras-griddb\/","og_locale":"en_US","og_type":"article","og_title":"Build a Time Series Forecasting Model Using TensorFlow Keras and GridDB | GridDB: Open Source Time Series Database for IoT","og_description":"This article explains how to build a time series forecasting model using TensorFlow Keras and GridDB. We will retrieve historical stock market data from","og_url":"https:\/\/griddb.net\/en\/blog\/keras-griddb\/","og_site_name":"GridDB: Open Source Time Series Database for IoT","article_publisher":"https:\/\/www.facebook.com\/griddbcommunity\/","article_published_time":"2025-04-25T07:00:00+00:00","og_image":[{"width":2560,"height":1920,"url":"https:\/\/griddb.net\/wp-content\/uploads\/2025\/12\/stock-market-graphs_2560x1920.jpg","type":"image\/jpeg"}],"author":"griddb-admin","twitter_card":"summary_large_image","twitter_creator":"@GridDBCommunity","twitter_site":"@GridDBCommunity","twitter_misc":{"Written by":"griddb-admin","Est. reading time":"13 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/griddb.net\/en\/blog\/keras-griddb\/#article","isPartOf":{"@id":"https:\/\/griddb.net\/en\/blog\/keras-griddb\/"},"author":{"name":"griddb-admin","@id":"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/#\/schema\/person\/4fe914ca9576878e82f5e8dd3ba52233"},"headline":"Build a Time Series Forecasting Model Using TensorFlow Keras and GridDB","datePublished":"2025-04-25T07:00:00+00:00","mainEntityOfPage":{"@id":"https:\/\/griddb.net\/en\/blog\/keras-griddb\/"},"wordCount":1262,"commentCount":0,"publisher":{"@id":"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/#organization"},"image":{"@id":"https:\/\/griddb.net\/en\/blog\/keras-griddb\/#primaryimage"},"thumbnailUrl":"\/wp-content\/uploads\/2025\/12\/stock-market-graphs_2560x1920.jpg","articleSection":["Blog"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/griddb.net\/en\/blog\/keras-griddb\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/griddb.net\/en\/blog\/keras-griddb\/","url":"https:\/\/griddb.net\/en\/blog\/keras-griddb\/","name":"Build a Time Series Forecasting Model Using TensorFlow Keras and GridDB | GridDB: Open Source Time Series Database for IoT","isPartOf":{"@id":"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/#website"},"primaryImageOfPage":{"@id":"https:\/\/griddb.net\/en\/blog\/keras-griddb\/#primaryimage"},"image":{"@id":"https:\/\/griddb.net\/en\/blog\/keras-griddb\/#primaryimage"},"thumbnailUrl":"\/wp-content\/uploads\/2025\/12\/stock-market-graphs_2560x1920.jpg","datePublished":"2025-04-25T07:00:00+00:00","description":"This article explains how to build a time series forecasting model using TensorFlow Keras and GridDB. We will retrieve historical stock market data from","inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/griddb.net\/en\/blog\/keras-griddb\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/griddb.net\/en\/blog\/keras-griddb\/#primaryimage","url":"\/wp-content\/uploads\/2025\/12\/stock-market-graphs_2560x1920.jpg","contentUrl":"\/wp-content\/uploads\/2025\/12\/stock-market-graphs_2560x1920.jpg","width":2560,"height":1920},{"@type":"WebSite","@id":"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/#website","url":"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/","name":"GridDB: Open Source Time Series Database for IoT","description":"GridDB is an open source time-series database with the performance of NoSQL and convenience of SQL","publisher":{"@id":"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/#organization","name":"Fixstars","url":"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/#\/schema\/logo\/image\/","url":"https:\/\/griddb.net\/wp-content\/uploads\/2019\/04\/fixstars_logo_web_tagline.png","contentUrl":"https:\/\/griddb.net\/wp-content\/uploads\/2019\/04\/fixstars_logo_web_tagline.png","width":200,"height":83,"caption":"Fixstars"},"image":{"@id":"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/griddbcommunity\/","https:\/\/x.com\/GridDBCommunity","https:\/\/www.linkedin.com\/company\/griddb-by-toshiba"]},{"@type":"Person","@id":"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/#\/schema\/person\/4fe914ca9576878e82f5e8dd3ba52233","name":"griddb-admin","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/5bceca1cafc06886a7ba873e2f0a28011a1176c4dea59709f735b63ae30d0342?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/5bceca1cafc06886a7ba873e2f0a28011a1176c4dea59709f735b63ae30d0342?s=96&d=mm&r=g","caption":"griddb-admin"},"url":"https:\/\/griddb.net\/en\/author\/griddb-admin\/"}]}},"_links":{"self":[{"href":"https:\/\/griddb.net\/en\/wp-json\/wp\/v2\/posts\/52115","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/griddb.net\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/griddb.net\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/griddb.net\/en\/wp-json\/wp\/v2\/users\/41"}],"replies":[{"embeddable":true,"href":"https:\/\/griddb.net\/en\/wp-json\/wp\/v2\/comments?post=52115"}],"version-history":[{"count":0,"href":"https:\/\/griddb.net\/en\/wp-json\/wp\/v2\/posts\/52115\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/griddb.net\/en\/wp-json\/wp\/v2\/media\/52116"}],"wp:attachment":[{"href":"https:\/\/griddb.net\/en\/wp-json\/wp\/v2\/media?parent=52115"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/griddb.net\/en\/wp-json\/wp\/v2\/categories?post=52115"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/griddb.net\/en\/wp-json\/wp\/v2\/tags?post=52115"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}