# Infinity Core Package Sometimes more control is needed than is provided by the high-level workflows reviewed so far. In this case, the Infinity Core Python package – our software that sits in between direct REST API interaction and the high-level workflows – is the backbone of front-end access to the Infinity API. Whether you are using our workflows or are interested in developing your own code, being familiar with Infinity Core is very helpful. ## What is the purpose of Infinity Core? Infinity Core wraps all the functionality available via our REST API, but in a higher-level and developer-friendly way. It also provides tools to enable more complex data science workflows. ## What are the key abstractions provided by Infinity Core? Two fundamental concepts introduced by Infinity Core are that of a **Session** and a **Batch**. Each is implemented as a Python class in Infinity Core and almost all functionality for interacting with the REST API you'll need is available as a method on one or the other. - An API **Session**. The fundamental workflow for light- and power-users alike is to generate 1 or more **batches** of synthetic data targeting a specific generator. An Infinity Core Session wraps this process and provides various ergonomic facilities. Users create a new session by providing their authentication token and a target generator. A session is then minted with behavior specialized for the selected generator. The session allows for more efficient synthetic data generation with fewer errors and less boilerplate code. - A synthetic data **Batch**. Whether producing 1 preview image or 1,000 videos, or using any of our application-specific generators, there is only one way to generate data with our API – submit a batch. At its core, a batch is defined by a list of parameters for a target generator, but Infinity Core provides many abstractions for generating batches, validating their parameters, submitting them to the API, querying their status in the cloud, downloading and analyzing results, and reconstituting old batches for further use. ```{note} In the next section, we will walk through [core](#core-infinity-tools) features of Infinity Core with explanatory code snippets. The [last section](#example-notebooks) highlights and links to end-to-end example notebooks built with Infinity Core. ``` ## Core Infinity Tools The primary role of Infinity Core is to facilitate interaction with the Infinity REST API using the **Session** and **Batch** tools. ### Using a Session The `infinity_core.session` submodule has a generic `Session` class for interacting with the API: ```python from infinity_core.session import Session sesh = Session(token="API_TOKEN", generator="visionfit-flagship-v0.1.0", server="https://api.toinfinity.ai/") ``` #### Get parameter options The session can print important metadata about job parameters helpful when constructing a batch to submit. This includes the type of each parameter, constraints (min and max values, finite choices, etc.), and the default value for each parameter. ```python from pprint import pprint pprint(sesh.parameter_info) ``` #### Specify job parameters *with* random sampling A Session provides the ability to specify details about job parameters you care about and randomly sample those you don't using the `randomize_unspecified_params` method. A standard way of preparing a batch to submit to the API is to call this function in a loop or otherwise append new job parameters to a Python list, one for each job you would like in the batch. The unspecified parameters will be uniformly sampled from their valid ranges or options. In contrast to `sample_input`, which we introduced in [high-level workflows](workflows.md#use-randomly-sampled-parameters), `randomize_unspecified_params` will always sample each parameter uniformly from its valid range. Whereas `randomize_unspecified_params` is generic and can be used to synthesize parameters for any generator, `sample_input` is generator-specific and draws from parameters distributions that are hand-crafted, and thus is not part of the generic Infinity Core package. ```{note} Depending on the generator, [`sample_input`](workflows.md#use-randomly-sampled-parameters) may take into consideration more complex joint constraints that may exist with certain parameters. `randomize_unspecified_params` cannot do this. ``` In this example, we specify fixed values for some parameters, we randomly sample `lighting_power` using our own custom distribution, and we uniformly sample the other parameters from their valid ranges by leveraging the `randomize_unspecified_params` method. ```python num_jobs = 10 light_min = sesh.parameter_info["lighting_power"]["options"]["min"] light_max = sesh.parameter_info["lighting_power"]["options"]["max"] job_params = [ sesh.randomize_unspecified_params(dict( exercise = "UPPERCUT-LEFT", num_reps = 1, lighting_power = random.uniform(light_min, light_max), )) for _ in range(num_jobs) ] ``` #### Specify job parameters *without* random sampling While `randomize_unspecified_params` is convenient, you may not want to randomly sample unspecified parameters at all. You can always directly construct job parameters as a list of dictionaries without using `randomize_unspecified_params`. If you submit a list of dictionaries to the API, any unspecified parameters in each job parameter dictionary will be set to their default values. ```python job_params = [ {"num_reps": 1, "lighting_power": random.uniform(light_min, light_max)} for _ in range(num_jobs) ] # Unspecified params are set to their default values batch = sesh.submit( job_params=job_params, is_preview=True, batch_name = "example with default values", ) ``` Print the default value associated with each parameter: ```python pprint(sesh.parameter_info) ``` #### Estimate samples We can estimate the number of samples (frames) a given batch would generate before submitting the batch for execution. In general, it is not possible to predict exact sample estimates for generators that introduce randomness at runtime. However, the accuracy of the estimate increases with the size of the batch. ```python samples_by_job = sesh.estimate_samples(job_params, is_preview=False) total_frames = sum(samples_by_job) ``` Note that if `is_preview=True` in the call to `estimate_samples`, the number of frames will exactly equal the number of jobs in the batch, since previews are single-frame by definition. #### Submit a batch We can submit a list of job parameters to the API. The `submit` method will first validate the job parameters and raise an exception if any errors or invalid values are encountered. If the submission is successful, a `Batch` object is returned. It is possible to submit single-frame previews with `is_preview=True` or videos with `is_preview=False`. ```python batch = sesh.submit(job_params, is_preview=True, batch_name="example preview batch") ``` Note that if a batch submission is estimated to exceed the number of samples remaining in the user account, the submission will fail with a descriptive error message. In this case, you can (1) purchase more samples via the API dashboard, (2) reduce the number of jobs in the batch, or (3) reduce the number of samples per job by changing the job parameters. When each job completes, the sample estimate for the job is credited back to the sample balance, and the actual number of samples rendered is deducted from the balance. ### Using a Batch The returned Batch object from submission has many utility methods associated with it. #### Get static information about the batch View the list of the UUIDs for each job in the batch: ```python print(batch.job_ids) ``` View the list of job parameters for each job in the batch: ```python print(batch.job_params) ``` Get the number of jobs in the batch: ```python print(batch.num_jobs) ``` #### Get dynamic information about the batch See how many jobs are still processing, if any: ```python print(batch.get_num_jobs_remaining()) ``` Get detailed batch metadata from the API: ```python print(batch.get_batch_data()) ``` Get metadata only for a specific job in the batch: ```python target_job = batch.job_ids[0] print(batch.get_job_summary_data(job_id = target_job)) ``` #### Check for job completion: non-blocking and blocking At any time, we can check if a batch has completed processing in the cloud with a non-blocking call to `get_num_jobs_remaining`. You can also await completion of all jobs – this will block the notebook cell (or more generally, current Python process) until completion. Query for batch completion in a non-blocking way: ```python print(f"Finished? {'Y' if batch.get_num_jobs_remaining() == 0 else 'N'}") ``` Block all Python processes while awaiting completion of the batch. Set a 60 minute timeout: ```python completed_jobs = batch.await_completion(timeout = 60 * 60) ``` #### Get completed job info and download results Get a list of the currently completed (without error) jobs: ```python completed_jobs = batch.get_valid_completed_jobs() ``` Download currently completed jobs to the specified path: ```python batch.download(path = "../tmp") ``` ## Additional Infinity Core Usage On top of the batch and session concepts, Infinity Core provides convenience methods that may prove helpful. Additionally, we show how Pandas Dataframes can be used to analyze, review, and update job parameters. ### Manually validate the job parameters The submission methods will check validity of job parameters, but you can also manually check at any time. ```python errors_by_job = sesh.validate_job_params(final_job_params) assert all([e is None for e in errors_by_job]) ``` ### Use pandas dataframes DataFrame libraries such as pandas can easily be used to analyze, review, and update job parameters. ```python import pandas as pd df = pd.DataFrame.from_records(job_params) df.head() # ... modify dataframe ... final_job_params = df.to_dict("records") batch = sesh.submit( job_params=final_job_params, is_preview=False, batch_name="modified batch using pandas df" ) ``` ## Example Notebooks You can find example notebooks in [infinity-workflows](https://github.com/toinfinityai/infinity-workflows) that showcase [Infinity Core](infinity_core) functionality. These can be used as a convenient jumping off point for more complex and custom usage of the Infinity API. ### VisionFit #### Submit and Download Batch Demo The [submit_and_download_batch_demo.ipynb](https://github.com/toinfinityai/infinity-workflows/blob/main/visionfit/examples/submit_and_download_batch_demo.ipynb) notebook walks through the basics of building, submitting, downloading, and analyzing a large batch of synthetic data. #### Parameter Sweep Demo The [parameter_sweep_demo.ipynb](https://github.com/toinfinityai/infinity-workflows/blob/main/visionfit/examples/parameter_sweep_demo.ipynb) notebook walks through a common use case of wanting to sweep one or more parameters against a previously submitted job or jobs.