{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"When I read for the 'inference' challenge, that \"if you need a hint, there's a guy named moo somewhere\", I thought that is a hint pointing to the [pymoo (Multi-objective Optimization in Python)](https://pymoo.org/) library, which is known to me. Later I've joined discord channel and found that moo is a real guy, not a library. LOL.\n\nI solved 'crop1' as blackbox without dive in score function details with an algorithm called [Differential evolution](https://en.wikipedia.org/wiki/Differential_evolution). This algorithm is presented in pymoo library: (pymoo DE)[https://pymoo.org/algorithms/soo/de.html#nb-de] \n\nIt takes about 10 hours.","metadata":{}},{"cell_type":"code","source":"!pip install pymoo","metadata":{"_kg_hide-output":true,"execution":{"iopub.status.busy":"2022-09-11T17:23:09.946487Z","iopub.execute_input":"2022-09-11T17:23:09.946929Z","iopub.status.idle":"2022-09-11T17:23:20.944820Z","shell.execute_reply.started":"2022-09-11T17:23:09.946894Z","shell.execute_reply":"2022-09-11T17:23:20.943383Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import numpy as np\nimport joblib\nimport matplotlib.pyplot as plt\nimport json\nimport requests\nfrom PIL import Image as Im\nimport torch\n\nfrom pymoo.core.problem import ElementwiseProblem\nfrom pymoo.operators.crossover.sbx import SBX\nfrom pymoo.operators.mutation.pm import PM\nfrom pymoo.operators.sampling.rnd import FloatRandomSampling\nfrom pymoo.algorithms.soo.nonconvex.de import DE\nfrom pymoo.operators.sampling.lhs import LHS\nfrom pymoo.termination import get_termination\nfrom pymoo.optimize import minimize\n\ndir_name = \"../input/ai-village-ctf\"","metadata":{"execution":{"iopub.status.busy":"2022-09-11T17:23:20.947343Z","iopub.execute_input":"2022-09-11T17:23:20.947713Z","iopub.status.idle":"2022-09-11T17:23:22.863082Z","shell.execute_reply.started":"2022-09-11T17:23:20.947680Z","shell.execute_reply":"2022-09-11T17:23:22.862091Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Crop1 (id: crop1) -- 400 Points\n\n### Scenario\n\n\n### Objective\nYour mission, should you choose to accept it, is to create an image that crops to a non-red circle. Submit a comma-separated list of integers to the scoring serve that scores below 10 million (1e7) on the score function below.","metadata":{}},{"cell_type":"code","source":"model = joblib.load(f\"{dir_name}/crop/04JUN_crop_model.pckl\")\nX_comp = joblib.load(f\"{dir_name}/crop/X_comp.pckl\")","metadata":{"execution":{"iopub.status.busy":"2022-09-11T17:23:22.864266Z","iopub.execute_input":"2022-09-11T17:23:22.864844Z","iopub.status.idle":"2022-09-11T17:23:38.549231Z","shell.execute_reply.started":"2022-09-11T17:23:22.864813Z","shell.execute_reply":"2022-09-11T17:23:38.547969Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Helper Functions\ndef get_ij(idx):\n    idx = 8-idx\n    j = idx//3\n    i = 2-idx%3\n    return i, j\n\ndef resize(X, size=(224,224)):\n    X_new = np.array(Im.fromarray(X.astype(np.uint8)).resize(size, resample=3))\n    return X_new\n\ndef get_cropped(X, idx):\n    n = 75*3\n    i, j = get_ij(idx)\n    crop = resize(X,(n,n))[j*75:(j+1)*75,i*75:(i+1)*75,:]\n    return crop\n\ndef i2t(img:np.array):\n    return np.array(img, dtype=np.float32)/255.\n\ndef make_X(x, size=(224,224)):\n    side = int((len(x)//3)**0.5)\n    x = np.where(x<255,x,255)\n    x = np.where(x>0,x,0)\n    X_np = x.astype(int).reshape([side, side, 3])\n    X_np = np.array(Im.fromarray(X_np.astype(np.uint8)).resize(size, resample=Im.Resampling.NEAREST))\n    return X_np\n\ndef pt_ft(X_np):\n    return torch.FloatTensor(X_np)\n\ndef score(x, model=model, X_comp = np.divide(X_comp,0b1010), debug=False):\n    x = (x).astype(int)\n    model.eval()\n    X = make_X(x)\n    preds = model(pt_ft(i2t(X.T[None])))\n    idx = preds.argmax().item()\n    expected = ((25.5-X_comp)).flatten()\n    actual_square = get_cropped(X, idx)\n    actual = actual_square.flatten().astype(int)\n    if debug:\n        print({\"idx\":idx})\n        plt.imshow(actual_square)\n        plt.show()\n    sse = ((actual-(expected*10).astype(int))**2).sum()\n    redness = (actual_square[:,:,0][actual_square[:,:,0]>230]**2).sum()+1\n    if idx==8:\n        return (1+preds.max().item())*sse*redness\n    return sse*redness\n\ndef get_submittable(x):\n    return \",\".join([str(int(n)) for n in x])\n\ncfn = lambda x: [f\"background-color: RGB({x.R},{x.G},{x.B})\"] * 3\ndef show_colors(ans):\n    ans = [int(x) for x in ans.split(\",\")]\n    squares = pd.DataFrame(np.array(ans[:27]).reshape([9,3]), columns=[\"R\",\"G\",\"B\"]).T.style.apply(cfn, axis=0)\n    circles = pd.DataFrame(np.array(ans[27:]).reshape([9,3]), columns=[\"R\",\"G\",\"B\"]).T.style.apply(cfn, axis=0)\n    display(squares)\n    display(circles)","metadata":{"execution":{"iopub.status.busy":"2022-09-11T17:23:38.552116Z","iopub.execute_input":"2022-09-11T17:23:38.552476Z","iopub.status.idle":"2022-09-11T17:23:38.574596Z","shell.execute_reply.started":"2022-09-11T17:23:38.552444Z","shell.execute_reply":"2022-09-11T17:23:38.572674Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# creating an image\nX_small = np.random.normal(100,30,size=(5**2*3)).reshape((5,5,3))","metadata":{"execution":{"iopub.status.busy":"2022-09-11T17:23:38.576725Z","iopub.execute_input":"2022-09-11T17:23:38.577118Z","iopub.status.idle":"2022-09-11T17:23:38.595740Z","shell.execute_reply.started":"2022-09-11T17:23:38.577077Z","shell.execute_reply":"2022-09-11T17:23:38.594568Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#rescaling an image\nX_large = resize(X_small)","metadata":{"execution":{"iopub.status.busy":"2022-09-11T17:23:38.597472Z","iopub.execute_input":"2022-09-11T17:23:38.597975Z","iopub.status.idle":"2022-09-11T17:23:38.610694Z","shell.execute_reply.started":"2022-09-11T17:23:38.597931Z","shell.execute_reply":"2022-09-11T17:23:38.609446Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.imshow(X_large)","metadata":{"execution":{"iopub.status.busy":"2022-09-11T17:23:38.612546Z","iopub.execute_input":"2022-09-11T17:23:38.613349Z","iopub.status.idle":"2022-09-11T17:23:38.886247Z","shell.execute_reply.started":"2022-09-11T17:23:38.613305Z","shell.execute_reply":"2022-09-11T17:23:38.883869Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Check score locally: Let's validate that above works on our scorer, but also see that we can submit data with less modifications for reduced resource consumption\n\nim = np.array(get_submittable(X_small.flatten()).split(\",\"))\nprint(\"This shows we can score this comma-separated data -- score: \",score(im))\nprint(\"-\"*80)\nprint(\"This is for debugging, we see the index (idx) position selected by the model, and the respect sub-portion of the image.\")\nscore(X_small.flatten(), debug=True)","metadata":{"execution":{"iopub.status.busy":"2022-09-11T17:23:38.887906Z","iopub.execute_input":"2022-09-11T17:23:38.888385Z","iopub.status.idle":"2022-09-11T17:23:39.373466Z","shell.execute_reply.started":"2022-09-11T17:23:38.888341Z","shell.execute_reply":"2022-09-11T17:23:39.372343Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"score(X_small.flatten())","metadata":{"execution":{"iopub.status.busy":"2022-09-11T17:23:39.374764Z","iopub.execute_input":"2022-09-11T17:23:39.375086Z","iopub.status.idle":"2022-09-11T17:23:39.471646Z","shell.execute_reply.started":"2022-09-11T17:23:39.375057Z","shell.execute_reply":"2022-09-11T17:23:39.470432Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"get_submittable(X_small.flatten())","metadata":{"execution":{"iopub.status.busy":"2022-09-11T17:23:39.475854Z","iopub.execute_input":"2022-09-11T17:23:39.476333Z","iopub.status.idle":"2022-09-11T17:23:39.483969Z","shell.execute_reply.started":"2022-09-11T17:23:39.476298Z","shell.execute_reply":"2022-09-11T17:23:39.482782Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"VARIABLES = 16\n\nclass Crop1(ElementwiseProblem):\n\n    def __init__(self, xy=VARIABLES, **kwargs):\n        super().__init__(\n            n_var=VARIABLES*VARIABLES*3,\n            n_obj=1,\n            xl=0,\n            xu=1\n            )\n        self.xy = xy\n\n    def _evaluate(self, x, out, *args, **kwargs):\n        x_reshaped = 255*np.copy(x.reshape((self.xy,self.xy,3)))\n        image = np.array(get_submittable(x_reshaped.flatten()).split(\",\"))\n        scores = score(image)\n        out[\"F\"] = scores    \n        \nproblem = Crop1()\n\nalgorithm = DE(\n    pop_size=100,\n    sampling=LHS(),\n    variant=\"DE/rand/1/bin\",\n    CR=0.1,\n    dither=\"vector\",\n    jitter=True\n)\n\ntermination = get_termination(\"n_gen\", 2550)\n\nres = minimize(problem,\n               algorithm,\n               termination,\n               seed=1,\n               save_history=True,\n               verbose=True\n               )\n\nX = res.X\nF = res.F\n\nX_scaled = 255*X\n\nprint(\"Best solution found: \\nX = %s\\nF = %s\" % (res.X, res.F))","metadata":{"execution":{"iopub.status.busy":"2022-09-11T17:23:39.485624Z","iopub.execute_input":"2022-09-11T17:23:39.486563Z","iopub.status.idle":"2022-09-11T17:23:49.587436Z","shell.execute_reply.started":"2022-09-11T17:23:39.486526Z","shell.execute_reply":"2022-09-11T17:23:49.586223Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"score(X_scaled.flatten(), debug=True)","metadata":{"execution":{"iopub.status.busy":"2022-09-11T17:25:01.295368Z","iopub.execute_input":"2022-09-11T17:25:01.295784Z","iopub.status.idle":"2022-09-11T17:25:01.591417Z","shell.execute_reply.started":"2022-09-11T17:25:01.295751Z","shell.execute_reply":"2022-09-11T17:25:01.590338Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Submission Helper\n\ntry:\n    # r = requests.post(\"https://crop1.fly.dev/score\", data=json.dumps({\"data\": get_submittable(X_small.flatten())}))\n    r = requests.post(\"https://crop1.fly.dev/score\", data=json.dumps({\"data\": get_submittable(X_scaled.flatten())}))\n    print(r.text)\nexcept requests.exceptions.ConnectionError:\n    print(\"Connection problems. Contact the CTF organizers.\")","metadata":{"execution":{"iopub.status.busy":"2022-09-11T17:23:49.746865Z","iopub.execute_input":"2022-09-11T17:23:49.747917Z","iopub.status.idle":"2022-09-11T17:23:49.988981Z","shell.execute_reply.started":"2022-09-11T17:23:49.747876Z","shell.execute_reply":"2022-09-11T17:23:49.987954Z"},"trusted":true},"execution_count":null,"outputs":[]}]}