{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport tensorflow as tf\nimport pickle\nimport json\nimport typing\nimport math\nfrom threading import Lock\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import sys\nsys.path.append('../input/riiidmodel4thplace/')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from modeling import RiiidAnswerModel\nfrom model_config import config","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"with open('../input/riiidmodel4thplace/data_map.pickle', 'rb') as f:\n    data_map = pickle.load(f)\n\n    \nwith open(\n    '../input/riiidmodel4thplace/encoded_content_map_v2.json', \n    'r') as f:\n    encoded_content_map = json.load(f)\nwith open(\n    '../input/riiidmodel4thplace/encoded_content_id_map.json', \n    'r') as f: \n    encoded_content_id_map = json.load(f)\n\nencoded_content_table = pd.DataFrame.from_dict(\n    encoded_content_id_map\n).astype({\n        'content_id': 'int16',\n        'content_type_id':'int8',\n        'encoded_content_id':'int32'\n    })\n\nmax_question_id = encoded_content_table[encoded_content_table.content_type_id == 0].encoded_content_id.max()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"SEQUENCE_LENGTH = 512\nBATCH_SIZE = 32\ndata_keys = ['timestamp',\n             'encoded_content_id',\n             'user_answer',\n             'answered_correctly',\n             'question_elapsed_time',\n             'question_had_explanation',\n             'non_padding_mask',\n             'time_lag']\ndata_types = [\n            tf.int64,\n            tf.int32,\n            tf.int32,\n            tf.int32,\n            tf.float32,\n            tf.int32,\n            tf.float32,\n            tf.float32\n        ]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\ndef build_test_ds_function(test_agg_df, data_map):\n    data = data_map['data']\n    index_map = data_map['index']\n    lock = Lock()\n    def process_row_i(i):\n        user_id = i.numpy()\n        row = test_agg_df.loc[user_id]\n        n = len(row['timestamp'])\n        index = index_map.get(user_id, None)\n        if index is not None:\n            is_question = data['encoded_content_id'][index] <= max_question_id\n            questions = data['timestamp'][index][is_question]\n            if len(questions) > 0:\n                last_question_timestamp = questions.max()\n                prior_question_cond = data['timestamp'][index] == last_question_timestamp\n                data['question_elapsed_time'][index][prior_question_cond] = row['prior_question_elapsed_time'][0]\n                data['question_had_explanation'][index][prior_question_cond] = row['prior_question_had_explanation'][0]\n            \n            for k in data_keys:\n                data[k][index,:-n] = data[k][index, n:]\n\n        else:\n            lock.acquire()\n            index = data_map['next_index']\n            index_map[user_id] = index\n            data_map['next_index'] += 1\n            lock.release()\n            \n        data['timestamp'][index, -n:] = row['timestamp']\n        data['encoded_content_id'][index,-n:] = row['encoded_content_id']\n        data['user_answer'][index, -n:] = 0\n        data['answered_correctly'][index, -n:] = 0\n        data['question_elapsed_time'][index, -n:] = 0\n        data['question_had_explanation'][index, -n:] = 0\n        data['non_padding_mask'][index,-n:] = 1\n        data['time_lag'][index, -n:] = row['timestamp'][0] - data['timestamp'][index, -(n+1)]\n        return [data[k][index] for k in data_keys]\n    def map_function(i):\n        x = tf.py_function(process_row_i, inp=[i], Tout=data_types)\n        return {\n            k:v for k,v in zip(data_keys, x)\n        }\n    return tf.data.Dataset.from_tensor_slices(test_agg_df.index).map(\n        map_function,\n        num_parallel_calls = tf.data.experimental.AUTOTUNE\n    ).prefetch(\n        tf.data.experimental.AUTOTUNE\n    ).batch(BATCH_SIZE)\n    ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def update_map_with_user_answer(data_map, prev_test_agg_df):\n    data = data_map['data']\n    for user_id, row in prev_test_agg_df.iterrows():\n        n = len(row['user_answer'])\n        index = data_map['index'][user_id]\n        data['user_answer'][index][-n:] = row['user_answer']\n        data['answered_correctly'][index][-n:] = row['answered_correctly']\n\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\nmodel = RiiidAnswerModel(\n        encoded_content_map,\n        **config\n        )\n\n@tf.function(\n    input_signature = ({\n        key : tf.TensorSpec(shape=(None, SEQUENCE_LENGTH), dtype=dt) \n        for key, dt in zip(data_keys, data_types) \n    },)\n)\ndef predict_batch(test_data):\n    logits = model(test_data, training = False)\n    logits = tf.squeeze(logits, axis  =-1)\n    sigmoids = tf.sigmoid(logits)\n    return sigmoids\n\n\n#load model weights\nsample_data = {k:data_map['data'][k][0:BATCH_SIZE,:] for k in data_map['data'].keys()}\npredict_batch(sample_data)\nmodel.load_weights('../input/riiidmodel4thplace/weights.h5')\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\ndef predict_and_update(test_agg_df, data_map):\n    '''\n    Return : timestamp, sigmoid prediction\n    '''\n    ## Padding to have a multiple of batchzize\n    \n    test_ds = build_test_ds_function(test_agg_df, data_map)\n    \n    probs = []\n    for test_data in test_ds:\n        cur_probs = predict_batch(test_data) \n        probs += tf.unstack(cur_probs)\n    return probs","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import riiideducation\nenv = riiideducation.make_env()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"%%time\n\niter_test = env.iter_test()\nprev_test_df = None\nfor test_df, sample_prediction_df in iter_test:\n    if prev_test_df is not None:\n        '''\n        Updating answers of previous batch\n        '''\n        prev_test_df['user_answer'] = eval(test_df.prior_group_responses.iloc[0])\n        prev_test_df['answered_correctly'] = eval(test_df.prior_group_answers_correct.iloc[0])\n        \n        prev_test_agg_df = prev_test_df.groupby(\n                'user_id',\n                sort = False,\n                as_index = True\n            )[['user_answer', 'answered_correctly'\n                                   ]].agg(list)\n        \n        update_map_with_user_answer(data_map, prev_test_agg_df)\n\n    \n    '''\n    Now build test data for the current batch\n    '''\n    \n    test_df.fillna(0, inplace = True)\n    test_agg_df = test_df.merge(\n            encoded_content_table,\n            on = ['content_id', 'content_type_id'],\n            how = 'left'\n        ).fillna(0).groupby('user_id', \n                            sort = False,\n                            as_index = True)[['timestamp',\n                                           'encoded_content_id',\n                                           'prior_question_elapsed_time',\n                                           'prior_question_had_explanation',\n                                           'row_id'\n                                          ]].agg(list)\n   \n    probs = predict_and_update(test_agg_df, data_map)\n    \n    extracted_probs = []\n    row_id = []\n    \n    \n    for prob, (_, row) in zip(probs, \n                                 test_agg_df.iterrows()):\n            \n        '''\n        Finding the indices and extract probs for each user\n        '''\n        n = len(row['row_id'])\n        extracted_probs += prob[-n:].numpy().tolist()\n        row_id += row['row_id']\n    \n    pred_df = pd.DataFrame.from_dict({\n            'row_id':row_id,\n            'answered_correctly': extracted_probs,\n    })\n    pred_df = sample_prediction_df[['row_id']].merge(\n        pred_df, \n        on = 'row_id',\n        how = 'left'\n    ).fillna(0.5)\n        \n    env.predict(pred_df)\n\n    prev_test_df = test_df\n","execution_count":null,"outputs":[]}],"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":4,"nbformat_minor":4}