Artificial Intelligence Projects and Problem Solving Questions
Detailed discussion of artificial intelligence and machine learning projects you have designed, implemented, or contributed to. Candidates should explain the problem definition and success criteria, data collection and preprocessing, feature engineering, model selection and justification, training and validation methodology, evaluation metrics and baselines, hyperparameter tuning and experiments, deployment and monitoring considerations, scalability and performance trade offs, and ethical and data privacy concerns. If practical projects are limited, rigorous coursework or replicable experiments may be discussed instead. Interviewers will assess your problem solving process, ability to measure success, and what you learned from experiments and failures.
Sample Answer
Sample Answer
import random
import multiprocessing as mp
import itertools
class SimpleDataset:
def __init__(self, data):
self.data = data
def __len__(self): return len(self.data)
def __getitem__(self, idx): return self.data[idx]
class DataLoader:
def __init__(self, dataset, batch_size=32, shuffle=False, num_workers=0, transform=None, prefetch=4):
self.dataset = dataset
self.batch_size = batch_size
self.shuffle = shuffle
self.num_workers = num_workers
self.transform = transform
self.prefetch = max(prefetch, num_workers*2)
self._stop = mp.Event()
def __iter__(self):
self.indices = list(range(len(self.dataset)))
if self.shuffle:
random.shuffle(self.indices)
# produce batch index lists
self.batches = [self.indices[i:i+self.batch_size] for i in range(0, len(self.indices), self.batch_size)]
if self.num_workers <= 0:
# synchronous generator
for batch_idx in self.batches:
batch = [self._apply(self.dataset[i]) for i in batch_idx]
yield batch
else:
return self._mp_iterator()
def _apply(self, item):
return self.transform(item) if self.transform else item
def _worker_loop(self, in_queue, out_queue, stop_event):
while not stop_event.is_set():
try:
batch_idx = in_queue.get(timeout=0.5)
except Exception:
continue
if batch_idx is None:
break
batch = [self._apply(self.dataset[i]) for i in batch_idx]
out_queue.put(batch)
def _mp_iterator(self):
in_q = mp.Queue(maxsize=self.prefetch)
out_q = mp.Queue(maxsize=self.prefetch)
stop_event = mp.Event()
workers = []
for _ in range(self.num_workers):
p = mp.Process(target=self._worker_loop, args=(in_q, out_q, stop_event))
p.daemon = True
p.start()
workers.append(p)
# enqueue batches
for b in self.batches:
in_q.put(b)
# signal workers to stop
for _ in workers:
in_q.put(None)
# yield results
remaining = len(self.batches)
try:
while remaining:
batch = out_q.get()
yield batch
remaining -= 1
finally:
stop_event.set()
for p in workers:
p.join(timeout=1)
# Example usage
if __name__ == "__main__":
ds = SimpleDataset(list(range(100)))
def augment(x): return x*2 # simple transform
dl = DataLoader(ds, batch_size=10, shuffle=True, num_workers=2, transform=augment)
for batch in dl:
print(batch)Sample Answer
Sample Answer
import numpy as np
def calibration_curve(pred_probs, labels, n_bins=10, strategy="uniform"):
"""
Compute calibration curve: returns (bin_centers, avg_pred_prob, frac_pos, counts)
pred_probs: array-like, floats in [0,1]
labels: array-like, binary (0/1)
n_bins: number of bins
strategy: "uniform" (equal-width) or "quantile" (equal-frequency)
"""
preds = np.asarray(pred_probs)
y = np.asarray(labels)
if preds.shape[0] != y.shape[0]:
raise ValueError("pred_probs and labels must have same length")
if strategy == "uniform":
bins = np.linspace(0.0, 1.0, n_bins + 1)
elif strategy == "quantile":
bins = np.quantile(preds, np.linspace(0, 1, n_bins + 1))
bins[0], bins[-1] = 0.0, 1.0 # ensure full range
else:
raise ValueError("strategy must be 'uniform' or 'quantile'")
bin_indices = np.digitize(preds, bins, right=False) - 1
# clamp indices to valid range
bin_indices = np.clip(bin_indices, 0, n_bins - 1)
avg_pred = np.zeros(n_bins)
frac_pos = np.zeros(n_bins)
counts = np.zeros(n_bins, dtype=int)
for b in range(n_bins):
mask = bin_indices == b
counts[b] = mask.sum()
if counts[b] > 0:
avg_pred[b] = preds[mask].mean()
frac_pos[b] = y[mask].mean()
else:
avg_pred[b] = (bins[b] + bins[b+1]) / 2.0
frac_pos[b] = np.nan # no samples in bin
bin_centers = [(bins[i] + bins[i+1]) / 2.0 for i in range(n_bins)]
return np.array(bin_centers), avg_pred, frac_pos, countsSample Answer
import torch
model.train()
scaler = torch.cuda.amp.GradScaler()
optimizer.zero_grad()
accum_steps = 4 # number of micro-batches to accumulate
for epoch in range(epochs):
for i, (inputs, targets) in enumerate(dataloader):
inputs = inputs.cuda(non_blocking=True)
targets = targets.cuda(non_blocking=True)
with torch.cuda.amp.autocast():
outputs = model(inputs)
loss = loss_fn(outputs, targets)
loss = loss / accum_steps # scale loss so gradient = average over micro-batches
# Scaled backward to avoid underflow in float16
scaler.scale(loss).backward()
# optimizer step once per accum_steps
if (i + 1) % accum_steps == 0:
# optionally clip gradients in unscaled (float) space:
scaler.unscale_(optimizer)
torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
scaler.step(optimizer) # steps the optimizer with scaled gradients
scaler.update() # updates the scale for next iteration
optimizer.zero_grad() # clear accumulated gradients
# handle leftover micro-batches at epoch end
if (i + 1) % accum_steps != 0:
scaler.unscale_(optimizer)
scaler.step(optimizer)
scaler.update()
optimizer.zero_grad()Unlock Full Question Bank
Get access to hundreds of Artificial Intelligence Projects and Problem Solving interview questions and detailed answers.
Sign in to ContinueJoin thousands of developers preparing for their dream job.