Picture by Editor
# Introduction
Python decorators will be extremely helpful in initiatives involving AI and machine studying system growth. They excel at separating key logic like modeling and information pipelines from different boilerplate duties, like testing and validation, timing, logging, and so forth.
This text outlines 5 notably helpful Python decorators that, primarily based on builders’ expertise, have confirmed themselves efficient at making AI code cleaner.
The code examples under embody easy, underlying logic primarily based on Python commonplace libraries and finest practices, e.g. functools.wraps. Their major objective is as an instance the usage of every particular decorator, so that you just solely want to fret about adapting the decorator’s logic to your AI coding undertaking.
# 1. Concurrency Limiter
A really helpful decorator when coping with (typically annoying) free-tier limits in the usage of third-party giant language fashions (LLMs). When hitting such limits because of sending too many asynchronous requests, this sample introduces a throttling mechanism to make these calls safer. By way of semaphores, the variety of occasions an asynchronous perform executes is proscribed:
import asyncio
from functools import wraps
def limit_concurrency(restrict=5):
sem = asyncio.Semaphore(restrict)
def decorator(func):
@wraps(func)
async def wrapper(*args, **kwargs):
async with sem:
return await func(*args, **kwargs)
return wrapper
return decorator
# Software
@limit_concurrency(5)
async def fetch_llm_batch(immediate):
return await async_api_client.generate(immediate)
# 2. Structured Machine Studying Logger
It’s no shock that in complicated software program like that governing machine studying methods, commonplace print() statements get simply misplaced, particularly as soon as deployed in manufacturing.
By way of the next logging decorator, it’s potential to “catch” executions and errors and format them into structured JSON logs which might be simply searchable for fast debugging. The code instance under can be utilized as a template to embellish, for example, a perform that defines a coaching epoch in a neural network-based mannequin:
import logging, json, time
from functools import wraps
def json_log(func):
@wraps(func)
def wrapper(*args, **kwargs):
begin = time.time()
attempt:
res = func(*args, **kwargs)
logging.information(json.dumps({“step”: func.__name__, “standing”: “success”, “time”: time.time() – begin}))
return res
besides Exception as e:
logging.error(json.dumps({“step”: func.__name__, “error”: str(e)}))
elevate
return wrapper
# Software
@json_log
def train_epoch(mannequin, training_data):
return mannequin.match(training_data)
# 3. Characteristic Injector
Enter a very helpful decorator in the course of the mannequin deployment and inference phases! Say you’re shifting your machine studying mannequin from a pocket book into a light-weight manufacturing surroundings, e.g. utilizing a FastAPI endpoint. Manually guaranteeing that uncooked incoming information from finish customers undergoes the identical transformations as the unique coaching information can generally turn out to be a little bit of a ache. The characteristic injector helps guarantee consistency in the way in which options are generated from uncooked information, all underneath the hood.
That is extremely helpful in the course of the deployment and inference section. When shifting a mannequin from a Jupyter pocket book right into a manufacturing surroundings, a serious headache is guaranteeing the uncooked incoming person information will get the identical transformations as your coaching information. This decorator ensures these options are generated constantly underneath the hood earlier than the information ever reaches your mannequin.
The instance under simplifies the method of including a characteristic referred to as ‘is_weekend’, primarily based on whether or not a date column in an current dataframe accommodates a date related to a Saturday or Sunday:
from functools import wraps
def add_weekend_feature(func):
@wraps(func)
def wrapper(df, *args, **kwargs):
df = df.copy() # Prevents Pandas mutation warnings
df[‘is_weekend’] = df[‘date’].dt.dayofweek.isin([5, 6]).astype(int)
return func(df, *args, **kwargs)
return wrapper
# Software
@add_weekend_feature
def process_data(df):
# ‘is_weekend’ is assured to exist right here
return df.dropna()
# 4. Deterministic Seed Setter
This one stands out for 2 particular phases of the AI/machine studying lifecycle: experimentation and hyperparameter tuning. These processes sometimes entail the usage of a random seed as a part of adjusting key hyperparameters like a mannequin’s studying fee. Say you simply adjusted its worth, and immediately, the mannequin accuracy drops. In a state of affairs like this, chances are you’ll have to know whether or not the trigger behind this efficiency drop is the brand new hyperparameter setting or just a foul random initialization of weights. By locking the seed, we isolate variables, thereby making the outcomes of exams like A/B extra dependable.
import random, numpy as np
from functools import wraps
def lock_seed(seed=42):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
random.seed(seed)
np.random.seed(seed)
return func(*args, **kwargs)
return wrapper
return decorator
# Software
@lock_seed(42)
def initialize_weights():
return np.random.randn(10, 10)
# 5. Dev-Mode Fallback
A lifesaving decorator, notably in native growth environments and CI/CD testing. Say you’re constructing an software layer on prime of an LLM — for example, a retrieval-augmented technology (RAG) system. If a adorned perform fails on account of exterior elements, like connection timeouts or API utilization limits, as an alternative of throwing an exception, the error is intercepted by this decorator and a predefined set of “mock take a look at information” is returned.
Why a lifesaver? As a result of this mechanism can guarantee your software doesn’t fully cease if an exterior service quickly fails.
from functools import wraps
def fallback_mock(mock_data):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
attempt:
return func(*args, **kwargs)
besides Exception: # Catches timeouts and fee limits
return mock_data
return wrapper
return decorator
# Software
@fallback_mock(mock_data=[0.01, -0.05, 0.02])
def get_text_embeddings(textual content):
return external_api.embed(textual content)
# Wrapping Up
This text examined 5 efficient Python decorators that may assist make your AI and machine studying code cleaner throughout quite a lot of particular conditions: from structured, easy-to-search logging to managed random seeding for points like information sampling, testing, and extra.
Iván Palomares Carrascosa is a frontrunner, author, speaker, and adviser in AI, machine studying, deep studying & LLMs. He trains and guides others in harnessing AI in the actual world.
