A Migration Guide for the new SDK - v0.5

Learn how to migrate to the latest version of the JFrog ML Python SDK.

About v0.5

This version brings a multitude of improvements, new features, and enhanced performance, all aimed at providing you with an even better JFrog ML experience.

With v0.5, we introduce the qwak-sdk as a public Python package. We reduced package dependencies and refactored the codebase to make it more lightweight.

While these changes bring many benefits, they also introduce breaking changing that require minor modifications to your existing codebase.



Installing the new SDK

Starting with v0.5, the qwak-sdk can be found on the public PyPI package repository. All you need is to run:

pip install qwak-sdk

Alternatively, when upgrading an existing qwak-sdk installation, run the following command:

pip install --upgrade qwak-sdk


Models changes

We recommend starting to migrate models one by one to the new JFrog ML SDK, even if they are not built regularly.

Model base class

In the new SDK, the old QwakModelInterface becomes QwakModel to simplify the name of the main JFrog ML model interface. Here's how the imports look like:

New Qwak SDK - v0.5

from qwak.model.base import QwakModel

class NewPredicitionModel(QwakModel):
	
  def __init__(self):
    pass

Qwak SDK - v0.9

from qwak.model.base import QwakModelInterface

class OldPredicitionModlel(QwakModelInterface):
	
  def __init__(self):
    pass

🚧

Building with --from-file

If you're using configuration files with your qwak models build commands, keep in mind that there have been some small changes in the configurations between SDK versions. We recommend running a sample build command with the --out-conf flag. This will create a basic config file for you. Start with this default config and then transfer any settings from your old file to the new one.


Additional model import changes


#V0.9
qwak.model.loggers import artifact_logger

# V0.5
from qwak.model_loggers import artifact_logger

Local testing

We updated and improved the way local testing and debugging work for JFrog ML models.

Please note that run_local method is now imported externally from from qwak.model.tools import run_local and receives the model object as input.

New Qwak SDK - v0.5

from qwak.model.tools import run_local

model = MyQwakModel()
input_vector = DataFrame(
  [{
    "prompt": "Why does it matter if a Central Bank has a negative rather than 0% interest rate?"
  }]
).to_json()

prediction = run_local(m, input_vector)

Qwak SDK - v0.9

from qwak.model.tools import run_local

model = MyQwakModel()

input_vector = DataFrame(
  [{
    "prompt": "Why does it matter if a Central Bank has a negative rather than 0% interest rate?"
  }]
).to_json()

precidtion = model.run_local(input_vector)

ModelSchema

The model schema defines your model's inputs and outputs.

The class constructor fields changed from features / predictions originally, to inputs/ outputs.

Moreover, the previous outputs Prediction class has now been renamed to InferenceOutput, the import path remaining the same.

New Qwak SDK - v0.5

from qwak.model.base import QwakModel
from qwak.model.schema import ModelSchema, ExplicitFeature, InferenceOutput

class NewModelWithSchema(QwakModel):
    
    def schema(self):
        model_schema = ModelSchema(
                inputs=[
                    ExplicitFeature(name="User_Name", type=str),
                    ExplicitFeature(name="Duration", type=int),
                ],
                outputs=[
                    InferenceOutput(name="Churn_Probability", type=float)
                ])
        return model_schema

Qwak SDK - v0.9

from qwak.model.base import QwakModelInterface
from qwak.model.schema import ModelSchema, ExplicitFeature, InferenceOutput

class ModelWithSchema(QwakModelInterface):
    
    def schema(self):
        model_schema = ModelSchema(
                features=[
                    ExplicitFeature(name="User_Name", type=str),
                    ExplicitFeature(name="Duration", type=int),
                ],
                predictions=[
                    Prediction(name="Churn_Probability", type=float)
                ])
        return model_schema

Unifying test mocks

The origianl integration tests mocks from the qwak_mock package, are now deprecated and the new mock modules have been moved under the qwak.testing in the main qwak package.

New Qwak SDK - v0.5

from qwak.testing.fixtures import real_time_client

def test_realtime_api(real_time_client):
    feature_vector = [
        {
            'text': 'To the Moon!'
        }]
    
   	real_time_client.predict(feature_vector)

Qwak SDK - v0.9

from qwak_mock import real_time_client

def test_realtime_api(real_time_client):
    feature_vector = [
        {
            'text': 'To the Moon!'
        }]
    real_time_client.predict(feature_vector)

JFrog ML Secret Service

The older client SecretServiceGrpcClient has now changed to the new SecretServiceClient together with the package as shown below. Moreover, the secret service client is now under the qwak.clients package, together with other client libraries.

New Qwak SDK - v0.5

from qwak import QwakModel
from qwak.clients.secret_service import SecretServiceClient

class TestModel(QwakModel)
	# ...
    
  def build():
      secret_service = SecretServiceClient()
      aws_api_key = secret_service.get_secret('aws_api_key')
      aws_secret_key = secret_service.get_secret('aws_secret_key')

Qwak SDK - v0.9

from qwak import QwakModelInterface
from qwak.secret_service.client import SecretServiceGrpcClient

class TestModel(QwakModel)
	# ...
    
  def build():
      secrets_client = SecretServiceGrpcClient()
      aws_api_key = secret_service.get_secret('aws_api_key')
      aws_secret_key = secret_service.get_secret('aws_secret_key')

Calling the live model

The RealTimeClient used to request predictions against the live model has been moved to a different dependency, which is installed separately with:

pip install qwak-inference

By doing that, we removed the dependencies from the main qwak-sdk package, which is now lighter.

New Qwak SDK v0.5

from qwak_inference import RealTimeClient

QWAK_MODEL_ID = 'text-summarizer'

if __name__ == '__main__':
  feature_vector = [
    {
      "text" : "Please summarize this sentence",
    }
  ]

  client = RealTimeClient(model_id=QWAK_MODEL_ID)
  response = client.predict(feature_vector)

Qwak SDK v0.9

from qwak.inference.clients import RealTimeClient

QWAK_MODEL_ID = 'text-summarizer'

if __name__ == '__main__':
  feature_vector = [
    {
      "text" : "Please summarize this sentence",
    }
  ]

  client = RealTimeClient(model_id=QWAK_MODEL_ID)
  response = client.predict(feature_vector)




CLI changes

Simplifying model creation

Creating new models and projects required two commands. We merged them into one, and made description optional.

New Qwak SDK v0.5

qwak models create “Credit Risk” --project “Credit Risk Modeling”

Qwak SDK v0.9

qwak projects create --project-name "Credit Risk Modeling" --project-description "An example project"

qwak models create --project-id <your-project-id> --model-name "Credit Risk"  --model-description "An example model"

Automatic build and deploy

Deploy models automatically in a single command using qwak models build and the --deploy parameter.

New Qwak SDK v0.5

qwak models build ./credit_risk --model-id "credit_risk" --deploy

Qwak SDK v0.9

qwak models build ./credit_risk --model-id "credit_risk"

qwak models deploy realtime --model-id "credit_risk" --build-id <your-build-id>


Feature Store Changes

When it comes to updating Feature Store related objects, it's not mandatory to re-create the existing data sources, feature sets, entities and so on. However, the new SDK should be used for any new registered objects, going forward.

Batch Feature Set

Starting with the new SDK, the packages and classes related to batch feature sets can be found in qwak.feature_store.feature_sets.

New Qwak SDK v0.5

from qwak.feature_store.feature_sets import batch
from qwak.feature_store.feature_sets.transformations import SparkSqlTransformation
from qwak.feature_store.feature_sets.execution_spec import ClusterTemplate
from qwak.feature_store.feature_sets.read_policies import ReadPolicy

Qwak SDK v0.9

from qwak.feature_store.v1 import batch, SparkSqlTransformation
from qwak.feature_store.features.execution_spec import ClusterTemplate
from qwak.feature_store.features import ReadPolicy

Data source import path

Similarly to feature sets, we also simplified the import path of all data sources to qwak.feature_store.data_sources.

New Qwak SDK v0.5

from qwak.feature_store.data_sources import CsvSource, SnowflakeSource

Qwak SDK v0.9

from qwak.feature_store.sources.data_sources import CsvSource, SnowflakeSource

Offline & Online Features

The previous feature querying and fetching libraries for the online and offline stores have been migrated to the qwak.feature_store.online and .offline packages. The new clients are now called OfflineClient and OnlineClient as seen below:

New Qwak SDK v0.5

from qwak.feature_store.offline.client import OfflineClient
offline_feature_store = OfflineClient()

from qwak.feature_store.online.client import OnlineClient
online_feature_store = OnlineClient()


Qwak SDK v0.9

from qwak.feature_store.offline import OfflineFeatureStore
offline_feature_store = OfflineFeatureStore()

📘

New dependency requirements

When fetching features from the OfflineClient, it is now required to add the following libraries to your dependency management file:

pyathena and pyarrow==12.0.1


When retrieving online features, either through the use of the feature_extraction decorator flag or by employing the OnlineClient, the columns in the resulting DataFrame will be named according to the following convention
feature-set-name.feature-name as outlined in the example below:


def schema(self) -> ModelSchema:
    model_schema = ModelSchema(
        inputs=[
            FeatureStoreInput(name='users-feature-set.count')]
    )
    return model_schema

@qwak.api(feature_extraction=True)
def predict(self, dfs, extracted_df):

    # Here's how to reference with the old SDK
    old_extracted_feature = extracted_df['count']

    # Here's how to reference with the new SDK (correct way)
    new_extracted_feature = extracted_df['users-feature-set.count']

If you think something is missing from this guide, please let our team know and we will update it accordingly.