How Turbine uses machine learning and Modelbit to forecast order volume

How Turbine uses machine learning and Modelbit to forecast order volume

by

Emilie Schario

,

CEO

Using Machine Learning to Forecast Inventory

At Turbine, we’re building a lightweight ERP for companies managing physical inventory. Our mission is to help our customers be more efficient- minimizing the amount of money locked up in surplus inventory and helping your order only the items you need at the right times.. We do that by connecting your procurement, inventory, supply chain and accounting in one interconnected system. 

That system can tell our customers at any given time exactly how much of any inventory item they have at each different location where they are holding inventory, and how many they’ll need, net of fulfilled orders, returns, and future demand. By providing customers with an accurate view of current and forecasted inventory, we can save them the lost revenue of unfillable orders and the lost money of over-ordered inventory. 

That “future demand” part is where machine learning comes in. Our customers need to order inventory in time to fulfill orders they haven’t gotten from their customers yet. If they order too much inventory, they’ll have spent too much money that they can’t get back. Those dollars locked in inventory can’t be invested in other parts of the business like marketing or hiring, and there is the risk that those items may never sell. In the worst cases, the over-ordered inventory might even expire. If they order too little inventory, they won’t be able to fulfill customer purchases, and will lose out on that revenue. 

As part of Turbine’s platform, we provide a forecast of future order volume for every product SKU at every customer. This allows our customers to order inventory on a just-in-time basis, maximizing their profit and minimizing their waste. 

We also help companies who work with co-mans or don’t have turn-key supply chains forecast for individual parts of their inventories. For example, if you expect to sell 10,000 jars in MArch, you might need to order 12,000 glass vessels in November. That way they can get to your manufacturer in January in order to be filled by February so you can ship them to your customers by March.

Machine learning powers these capabilities.

Building the Model

We selected Meta’s open-source Prophet model as our time-series forecasting model. We knew we wanted a model framework that is well-supported and battle-tested. As the industry standard, we knew support would be readily available and that any major problems with the model had likely been ironed out. 

We use Hex as our development environment for training the model. We started by loading up the model and training it on the historical purchase volume across all of our customers. We found that Prophet was most accurate when trained with one model for each SKU for each channel at each customer. We can’t assume that buying patterns are the same on Shopify as they are at Target. This allows per-product features like total volume as well as any product or customer-specific seasonal variations to be fully taken into account by the model. For example, customers in different geographies may have different holiday seasons and holiday buying patterns. Moreover, different product SKUs naturally have different volumes. 

Taking this into account, we ended up with many hundreds of Prophet models trained in Hex. It was time to deploy them into the product. 

Training the models and adding them to the registry

Not only did we have several hundred models, the total number of models is likely to vary as customers add and remove products, and as we add more customers ourselves. This meant that separate APIs for every single model isn’t practical. 

Luckily, Modelbit’s model registry is designed for this purpose. A training run is as simple as a “for” loop in Hex that runs over the historical customer volume and trains an individual Prophet model for each customer SKU. Inside that loop, we call “modelbit.add_model” to add the model to the Modelbit registry. 

Here’s the training code which trains models and adds them to the registry as necessary:

if train_and_deploy_to_modelbit:
   models = {}
   for _, row in (tqdm_bar := tqdm(unique_combinations.iterrows(), total=len(unique_combinations))):
      tqdm_bar.set_description(f"Training {len(unique_combinations)} models")
      logging.getLogger('prophet').setLevel(logging.WARNING)
      logging.getLogger('cmdstanpy').setLevel(logging.WARNING)
      tenant_id, sku_id, channel_type_id = row['tenant_id'], row['sku_id'], row['channel_type_id']

      # Subset the data
      subset = dataframe[(dataframe['sku_id'] == sku_id) & (dataframe['channel_type_id'] == channel_type_id)]
      training_subset = subset.sort_values('ds', ascending=False).iloc[weeks_to_exclude_from_training:]
      
      # Prepare data for Prophet
      prophet_data = training_subset[['ds', 'y']]
      prophet_data = prophet_data.dropna()


      if len(prophet_data) > 1:
         # Initialize and fit the model
         model_name = f"{tenant_id}-{sku_id}-{channel_type_id}"
         model = prophet.Prophet()
         model.fit(prophet_data)
         models[model_name] = model

   mb.add_models(models)


if remove_unused_models_from_modelbit_registry:
   # Delete models from the Modelbit registry that are no longer needed
   current_models = [f"{row['tenant_id']}-{row['sku_id']}-{row['channel_type_id']}" for _, row in unique_combinations.iterrows()]
   deleted_models = list(set(mb.models()) - set(current_models))
   if deleted_models:
      mb.delete_models(deleted_models)

Deploying the models

Finally, we wrote a single Python function in our Hex project that takes a customer ID and a product ID as parameters. Based on those parameters, it selects a model from the Modelbit registry, performs an inference, and returns the result. We deployed that function from the Hex project with “modelbit.deploy”. Now we have a single REST API that’s able to perform inferences for any SKU at any customer. It was very simple to then integrate that single REST API into our product’s web server code to power our forecasting feature!

To start, we were able to manually retrain and redeploy as necessary from our Hex project. Once that was working well, we moved it to an automated pipeline that retrains and evaluates models weekly, and then automatically adds new models to the Modelbit registry. When the models hit the registry, they start being used automatically in production.

Using Machine Learning to Forecast Inventory

At Turbine, we’re building a lightweight ERP for companies managing physical inventory. Our mission is to help our customers be more efficient- minimizing the amount of money locked up in surplus inventory and helping your order only the items you need at the right times.. We do that by connecting your procurement, inventory, supply chain and accounting in one interconnected system. 

That system can tell our customers at any given time exactly how much of any inventory item they have at each different location where they are holding inventory, and how many they’ll need, net of fulfilled orders, returns, and future demand. By providing customers with an accurate view of current and forecasted inventory, we can save them the lost revenue of unfillable orders and the lost money of over-ordered inventory. 

That “future demand” part is where machine learning comes in. Our customers need to order inventory in time to fulfill orders they haven’t gotten from their customers yet. If they order too much inventory, they’ll have spent too much money that they can’t get back. Those dollars locked in inventory can’t be invested in other parts of the business like marketing or hiring, and there is the risk that those items may never sell. In the worst cases, the over-ordered inventory might even expire. If they order too little inventory, they won’t be able to fulfill customer purchases, and will lose out on that revenue. 

As part of Turbine’s platform, we provide a forecast of future order volume for every product SKU at every customer. This allows our customers to order inventory on a just-in-time basis, maximizing their profit and minimizing their waste. 

We also help companies who work with co-mans or don’t have turn-key supply chains forecast for individual parts of their inventories. For example, if you expect to sell 10,000 jars in MArch, you might need to order 12,000 glass vessels in November. That way they can get to your manufacturer in January in order to be filled by February so you can ship them to your customers by March.

Machine learning powers these capabilities.

Building the Model

We selected Meta’s open-source Prophet model as our time-series forecasting model. We knew we wanted a model framework that is well-supported and battle-tested. As the industry standard, we knew support would be readily available and that any major problems with the model had likely been ironed out. 

We use Hex as our development environment for training the model. We started by loading up the model and training it on the historical purchase volume across all of our customers. We found that Prophet was most accurate when trained with one model for each SKU for each channel at each customer. We can’t assume that buying patterns are the same on Shopify as they are at Target. This allows per-product features like total volume as well as any product or customer-specific seasonal variations to be fully taken into account by the model. For example, customers in different geographies may have different holiday seasons and holiday buying patterns. Moreover, different product SKUs naturally have different volumes. 

Taking this into account, we ended up with many hundreds of Prophet models trained in Hex. It was time to deploy them into the product. 

Training the models and adding them to the registry

Not only did we have several hundred models, the total number of models is likely to vary as customers add and remove products, and as we add more customers ourselves. This meant that separate APIs for every single model isn’t practical. 

Luckily, Modelbit’s model registry is designed for this purpose. A training run is as simple as a “for” loop in Hex that runs over the historical customer volume and trains an individual Prophet model for each customer SKU. Inside that loop, we call “modelbit.add_model” to add the model to the Modelbit registry. 

Here’s the training code which trains models and adds them to the registry as necessary:

if train_and_deploy_to_modelbit:
   models = {}
   for _, row in (tqdm_bar := tqdm(unique_combinations.iterrows(), total=len(unique_combinations))):
      tqdm_bar.set_description(f"Training {len(unique_combinations)} models")
      logging.getLogger('prophet').setLevel(logging.WARNING)
      logging.getLogger('cmdstanpy').setLevel(logging.WARNING)
      tenant_id, sku_id, channel_type_id = row['tenant_id'], row['sku_id'], row['channel_type_id']

      # Subset the data
      subset = dataframe[(dataframe['sku_id'] == sku_id) & (dataframe['channel_type_id'] == channel_type_id)]
      training_subset = subset.sort_values('ds', ascending=False).iloc[weeks_to_exclude_from_training:]
      
      # Prepare data for Prophet
      prophet_data = training_subset[['ds', 'y']]
      prophet_data = prophet_data.dropna()


      if len(prophet_data) > 1:
         # Initialize and fit the model
         model_name = f"{tenant_id}-{sku_id}-{channel_type_id}"
         model = prophet.Prophet()
         model.fit(prophet_data)
         models[model_name] = model

   mb.add_models(models)


if remove_unused_models_from_modelbit_registry:
   # Delete models from the Modelbit registry that are no longer needed
   current_models = [f"{row['tenant_id']}-{row['sku_id']}-{row['channel_type_id']}" for _, row in unique_combinations.iterrows()]
   deleted_models = list(set(mb.models()) - set(current_models))
   if deleted_models:
      mb.delete_models(deleted_models)

Deploying the models

Finally, we wrote a single Python function in our Hex project that takes a customer ID and a product ID as parameters. Based on those parameters, it selects a model from the Modelbit registry, performs an inference, and returns the result. We deployed that function from the Hex project with “modelbit.deploy”. Now we have a single REST API that’s able to perform inferences for any SKU at any customer. It was very simple to then integrate that single REST API into our product’s web server code to power our forecasting feature!

To start, we were able to manually retrain and redeploy as necessary from our Hex project. Once that was working well, we moved it to an automated pipeline that retrains and evaluates models weekly, and then automatically adds new models to the Modelbit registry. When the models hit the registry, they start being used automatically in production.