Kaggle competition: Abstraction and Reasoning Challenge
<SOS> metric: MeanBestErrorAtK Kaggle data source: abstraction-and-reasoning-challenge<normalization>
import numpy as np
import pandas as pd
from tqdm import tqdm
class ZoomSolver(Solver):
verbose = True
def detect(self, task):
ratios = self.task_shape_ratios(task)
 ratio = list(ratios)[0]
detect =(
 ratios != {(1,1)}
and len(ratios)== 1
and ratio[0] == ratio[1] 
)
 return detect
def get_scale(self, task):
return list(self.task_shape_ratios(task)) [0][0]
def action(self, grid, task):
scale = self.get_scale(task)
 if scale > 1:
resize = tuple(int(d*scale)for d in grid.shape)
 output = cv2.resize(grid, resize, interpolation=cv2.INTER_NEAREST)
 else:
resize = tuple(int(1/scale)for d in grid.shape)
 output = skimage.measure.block_reduce(grid, resize)
 if self.debug:
print('scale', scale, 'grid.shape', grid.shape, 'output.shape', output.shape)
 print('grid', grid)
 print('output', output)
 return output
solvers['ZoomSolver'] = ZoomSolver()
ZoomSolver().plot(tasks )<define_search_space>
def load_data(path):
tasks = pd.Series()
for file_path in os.listdir(path):
task_file = path_join(path, file_path)
 with open(task_file, 'r')as f:
task = json.load(f)
 tasks[file_path[:-5]] = task
return tasks
class GeometrySolver(Solver):
optimise = True
verbose = True
actions = {
"flip":(np.flip, [0,1]),
"rot90":(np.rot90, [1,2,3]),
"roll":(np.roll, product(range(-5,5),[0,1])) ,
"swapaxes":(np.swapaxes, [(0, 1),(1, 0)]),
"transpose":(np.transpose, []),
}
def __init__(self):
super().__init__()
for key,(function, arglist)in self.actions.items() :
self.actions[key] =(function, [(args,)if not isinstance(args, tuple)else args for args in arglist ])
 def detect(self, task):
return self.is_task_shape_ratio_unchanged(task)
 def test(self, task):
if task['file'] in self.cache: return True
max_roll =(self.task_grid_max_dim(task)+ 1)// 2
for key,(function, arglist)in self.actions.items() :
if function == np.roll: arglist = product(range(-max_roll,max_roll),[0,1])
 for args in arglist:
if self.is_lambda_valid(task, function, *args):
self.cache[task['file']] =(function, args)
 if self.verbose: print(function, args)
 return True
if self.optimise: return False
for(( function1, arglist1),(function2, arglist2)) in combinations(self.actions.values() , 2):
if function1 == np.roll: arglist1 = product(range(-max_roll,max_roll),[0,1])
 if function2 == np.roll: arglist2 = product(range(-max_roll,max_roll),[0,1])
 for args1, args2 in product(arglist1, arglist2):
function = lambda grid, args1, args2: function1(function2(grid, *args2), *args1)
 if self.is_lambda_valid(task, function, *(args1,args2)) :
self.cache[task['file']] =(function,(args1,args2))
if self.verbose: print(function,(args1,args2))
return True
return False
def action(self, grid, function=None, args=None, task=None):
try:
return function(grid, *args)
 except Exception as exception:
if self.debug: print(function, args, exception)
 return grid
solvers['GeometrySolver'] = GeometrySolver()
GeometrySolver().plot(tasks )<compute_test_metric>
train_tasks = load_data('.. /input/abstraction-and-reasoning-challenge/training/')
 evaluation_tasks = load_data('.. /input/abstraction-and-reasoning-challenge/evaluation/')
 test_tasks = load_data('.. /input/abstraction-and-reasoning-challenge/test/')
 train_tasks.head()
def score_tasks(tasks: dict, label: str):
total = 0
solved = 0
for task_file, task in tasks.items() :
for index, spec in enumerate(task['test']): total += 1
if 'solution' in task:
for index, spec in enumerate(task['solution']):
solved += 1
print(f'{label.ljust(11)}| solutions found: {str(solved ).rjust(3)}/{total} | error: {round(1-solved/total,4)}')
 return solved
for label in ['training', 'evaluation', 'test']:
score_tasks({ file: task for(file,task)in tasks.items() if label in file }, label )<load_pretrained>
def inp2img(inp):
inp = np.array(inp)
 img = np.full(( 10, inp.shape[0], inp.shape[1]), 0, dtype=np.uint8)
 for i in range(10):
img[i] =(inp==i)
 return img
class TaskSolver:
def train(self, task_train, n_epoch=30):

 self.net = Conv2d(in_channels=10, out_channels=10, kernel_size=5, padding=2)
 criterion = CrossEntropyLoss()
optimizer = Adam(self.net.parameters() , lr = 0.1)
 for epoch in range(n_epoch):
for sample in task_train:
inputs = FloatTensor(inp2img(sample['input'])).unsqueeze(dim=0)
 labels = LongTensor(sample['output'] ).unsqueeze(dim=0)
 optimizer.zero_grad()
outputs = self.net(inputs)
 loss = criterion(outputs, labels)
 loss.backward()
optimizer.step()
return self
def predict(self, task_test):
predictions = []
with torch.no_grad() :
for sample in task_test:
inputs = FloatTensor(inp2img(sample['input'])).unsqueeze(dim=0)
 outputs = self.net(inputs)
 pred = outputs.squeeze(dim=0 ).cpu().numpy().argmax(0)
 predictions.append(pred)
 return predictions
test_files = glob('.. /input/abstraction-and-reasoning-challenge/test/*.json');
tests = load_tasks(test_files)
 len(tests )<find_best_params>
def input_output_shape_is_same(task):
return all([np.array(el['input'] ).shape == np.array(el['output'] ).shape for el in task['train']])
 def calk_score(task_test, predict):
return [int(np.equal(sample['output'], pred ).all())for sample, pred in zip(task_test, predict)]
for name, solver in solvers.items() :
solver.cache = {}
solver.plot(tests )<categorify>
def evaluate(tasks):
ts = TaskSolver()
result = []
predictions = []
for task in tqdm(tasks):
if input_output_shape_is_same(task):
ts.train(task['train'])
 pred = ts.predict(task['test'])
 score = calk_score(task['test'], pred)
 else:
pred = [el['input'] for el in task['test']]
score = [0]*len(task['test'])
 predictions.append(pred)
 result.append(score)
 return result, predictions
".join([ ",".join(row)for row in output ])
<load_from_csv>
train_result, train_predictions = evaluate(train_tasks)
 train_solved = [any(score)for score in train_result]
total = sum([len(score)for score in train_result])
 print(f"solved : {sum(train_solved)} from {total}({sum(train_solved)/total})" )
def output_id(filename, index=0):
return re.sub('^.*/|\.json$', '', filename)+ '_' + str(index);
def flattener(grid):
grid = grid.astype('uint8' ).tolist()
str_pred = str([row for row in grid])
 str_pred = str_pred.replace(', ', '')
 str_pred = str_pred.replace('[[', '|')
 str_pred = str_pred.replace('][', '|')
 str_pred = str_pred.replace(']]', '|')
 return str_pred
def write_submission_csv(tests):
submission_csv = pd.read_csv('.. /input/abstraction-and-reasoning-challenge/sample_submission.csv')
 submission_csv = submission_csv.set_index('output_id')
 total = 0
solved = 0
for task_file, test in tests.items() :
for index, spec in enumerate(test['test']): total += 1
if 'solution' in test:
for index, spec in enumerate(test['solution']):
submission_csv.loc[ output_id(task_file, index), 'output' ] = flattener(spec['output'])
 solved += 1
submission_csv.to_csv('submission.csv')
 print(f'wrote: submission.csv')
 print(f'solutions found: {solved}/{total} | error: {round(1-solved/total,4)}')
 return submission_csv
write_submission_csv(tests )<import_modules>
evaluation_result, evaluation_predictions = evaluate(evaluation_tasks)
 evaluation_solved = [any(score)for score in evaluation_result]
total = sum([len(score)for score in evaluation_result])
 print(f"solved : {sum(evaluation_solved)} from {total}({sum(evaluation_solved)/total})" )
GradientBoostingClassifier,
BaggingClassifier,
StackingClassifier)
 warnings.simplefilter("ignore", category=ConvergenceWarning )<define_variables>
def flattener(pred):
str_pred = str([row for row in pred])
 str_pred = str_pred.replace(', ', '')
 str_pred = str_pred.replace('[[', '|')
 str_pred = str_pred.replace('][', '|')
 str_pred = str_pred.replace(']]', '|')
 return str_pred
def make_pediction(tasks):
ts = TaskSolver()
result = pd.Series()
for idx, task in tqdm(test_tasks.iteritems()):
if input_output_shape_is_same(task):
ts.train(task['train'])
 pred = ts.predict(task['test'])
 else:
pred = [el['input'] for el in task['test']]
for i, p in enumerate(pred):
result[f'{idx}_{i}'] = flattener(np.array(p ).tolist())
 return result
data_path = Path('/kaggle/input/abstraction-and-reasoning-challenge/')
 training_path = data_path / 'training'
evaluation_path = data_path / 'evaluation'
test_path = data_path / 'test'<load_from_csv>
submission = make_pediction(test_tasks)
 submission.head()
<categorify><EOS> 
submission = submission.reset_index()
submission.columns = ['output_id', 'output']
submission.to_csv('submission.csv', index=False)
 submission