{"cells":[{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"import os\n\nimport numpy as np\nimport pandas as pd\nimport tensorflow as tf\nfrom tensorflow.keras.layers import Dense, Input\nfrom tensorflow.keras.optimizers import Adam\nfrom tensorflow.keras.models import Model, load_model\nfrom tensorflow.keras.callbacks import ModelCheckpoint\nfrom kaggle_datasets import KaggleDatasets\nimport transformers\nfrom tqdm.notebook import tqdm\nfrom tokenizers import BertWordPieceTokenizer, SentencePieceBPETokenizer","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def fast_encode(texts, tokenizer, chunk_size=256, maxlen=512):\n    \"\"\"\n    https://www.kaggle.com/xhlulu/jigsaw-tpu-distilbert-with-huggingface-and-keras\n    \"\"\"\n    tokenizer.enable_truncation(max_length=maxlen)\n    tokenizer.enable_padding(max_length=maxlen)\n    all_ids = []\n    \n    for i in tqdm(range(0, len(texts), chunk_size)):\n        text_chunk = texts[i:i+chunk_size].tolist()\n        encs = tokenizer.encode_batch(text_chunk)\n        all_ids.extend([enc.ids for enc in encs])\n    \n    return np.array(all_ids)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Detect hardware, return appropriate distribution strategy\ntry:\n    # TPU detection. No parameters necessary if TPU_NAME environment variable is\n    # set: this is always the case on Kaggle.\n    tpu = tf.distribute.cluster_resolver.TPUClusterResolver()\n    print('Running on TPU ', tpu.master())\nexcept ValueError:\n    tpu = None\n\nif tpu:\n    tf.config.experimental_connect_to_cluster(tpu)\n    tf.tpu.experimental.initialize_tpu_system(tpu)\n    strategy = tf.distribute.experimental.TPUStrategy(tpu)\nelse:\n    # Default distribution strategy in Tensorflow. Works on CPU and single GPU.\n    strategy = tf.distribute.get_strategy()\n\nprint(\"REPLICAS: \", strategy.num_replicas_in_sync)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"AUTO = tf.data.experimental.AUTOTUNE\n\n# Data access\nGCS_DS_PATH = KaggleDatasets().get_gcs_path('jigsaw-multilingual-toxic-comment-classification')\n\n# Configuration\nEPOCHS = 3\nBATCH_SIZE = 8 * strategy.num_replicas_in_sync\nMAX_LEN = 128","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Create fast tokenizer","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"# First load the real tokenizer\ntokenizer = transformers.AutoTokenizer.from_pretrained('t5-large')\ntokenizer.pad_token = tokenizer.eos_token\n# Save the loaded tokenizer locally\ntokenizer.save_pretrained('.')\n# Reload it with the huggingface tokenizers library\n# fast_tokenizer = SentencePieceBPETokenizer('vocab.txt')\n# fast_tokenizer","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Load text data into memory\n","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"train1 = pd.read_csv(\"/kaggle/input/jigsaw-multilingual-toxic-comment-classification/jigsaw-toxic-comment-train.csv\")\ntrain2 = pd.read_csv(\"/kaggle/input/jigsaw-multilingual-toxic-comment-classification/jigsaw-unintended-bias-train.csv\")\ntrain2.toxic = train2.toxic.round().astype(int)\n\nvalid = pd.read_csv('/kaggle/input/jigsaw-multilingual-toxic-comment-classification/validation.csv')\ntest = pd.read_csv('/kaggle/input/jigsaw-multilingual-toxic-comment-classification/test.csv')\nsub = pd.read_csv('/kaggle/input/jigsaw-multilingual-toxic-comment-classification/sample_submission.csv')\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train1.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"olid = pd.read_csv('/kaggle/input/olid2019/olid-training-v1.0.tsv', sep='\\t')\nolid = olid.rename(columns={\"id\": \"id\", \"tweet\": \"comment_text\", 'subtask_a': 'toxic'})\nolid.toxic = (olid.toxic == 'OFF').astype(int)\nolid['comment_text'] = olid['comment_text'].str.replace('@USER', '')\nolid.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from sklearn.model_selection import train_test_split\nolid_train, olid_test = train_test_split(olid, test_size=3240, random_state = 2020)\nolid_train_1k = olid_train[0:1000]\nolid_train_2k = olid_train[0:2000]\nolid_train_5k = olid_train[0:5000]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train = pd.concat([\n    train1[['comment_text', 'toxic']],\n    train2[['comment_text', 'toxic']].query('toxic==1'),\n    train2[['comment_text', 'toxic']].query('toxic==0').sample(n=150000, random_state=0)\n])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train.toxic.value_counts()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def fast_encode_xlm(texts, tokenizer, chunk_size=256, maxlen=512):\n    \"\"\"\n    https://www.kaggle.com/xhlulu/jigsaw-tpu-distilbert-with-huggingface-and-keras\n    \"\"\"\n    all_ids = []\n    \n    for i in tqdm(range(0, len(texts), chunk_size)):\n        text_chunk = texts[i:i+chunk_size].tolist()\n        encs = tokenizer.batch_encode_plus(text_chunk, pad_to_max_length = True, max_length = maxlen)\n        all_ids.extend(np.array(encs.input_ids))\n    \n    return np.array(all_ids)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"x_train = fast_encode_xlm(train.comment_text.astype(str), tokenizer, maxlen=MAX_LEN)\nx_valid = fast_encode_xlm(valid.comment_text.astype(str), tokenizer, maxlen=MAX_LEN)\nx_test = fast_encode_xlm(test.content.astype(str), tokenizer, maxlen=MAX_LEN)\n\ny_train = train.toxic.values\ny_valid = valid.toxic.values","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# olid_encode = fast_encode_xlm(olid.comment_text.astype(str), tokenizer, maxlen=MAX_LEN)\nolid_train_encode = fast_encode_xlm(olid_train.comment_text.astype(str), tokenizer, maxlen=MAX_LEN)\nolid_train_1k_encode = fast_encode_xlm(olid_train_1k.comment_text.astype(str), tokenizer, maxlen=MAX_LEN)\nolid_train_2k_encode = fast_encode_xlm(olid_train_2k.comment_text.astype(str), tokenizer, maxlen=MAX_LEN)\nolid_train_5k_encode = fast_encode_xlm(olid_train_5k.comment_text.astype(str), tokenizer, maxlen=MAX_LEN)\nolid_test_encode = fast_encode_xlm(olid_test.comment_text.astype(str), tokenizer, maxlen=MAX_LEN)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"y_olid_train = olid_train.toxic.values\ny_olid_train_1k = olid_train_1k.toxic.values\ny_olid_train_2k = olid_train_2k.toxic.values\ny_olid_train_5k = olid_train_5k.toxic.values\ny_olid_test = olid_test.toxic.values\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Build datasets objects","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"train_dataset = (\n    tf.data.Dataset\n    .from_tensor_slices((x_train, y_train))\n    .repeat()\n    .shuffle(2048)\n    .batch(BATCH_SIZE)\n    .prefetch(AUTO)\n)\n\nvalid_dataset = (\n    tf.data.Dataset\n    .from_tensor_slices((x_valid, y_valid))\n    .batch(BATCH_SIZE)\n    .cache()\n    .prefetch(AUTO)\n)\n\ntest_dataset = (\n    tf.data.Dataset\n    .from_tensor_slices(x_test)\n    .batch(BATCH_SIZE)\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"olid_test_dataset = (\n    tf.data.Dataset\n    .from_tensor_slices(olid_test_encode)\n    .batch(BATCH_SIZE)\n)\n\nolid_test_dataset_wlabel = (\n    tf.data.Dataset\n    .from_tensor_slices((olid_test_encode, y_olid_test))\n    .batch(BATCH_SIZE)\n)\nolid_train_1k_dataset = (\n    tf.data.Dataset\n    .from_tensor_slices((olid_train_1k_encode, y_olid_train_1k))\n    .batch(BATCH_SIZE)\n    .prefetch(AUTO)\n)\nolid_train_2k_dataset = (\n    tf.data.Dataset\n    .from_tensor_slices((olid_train_2k_encode, y_olid_train_2k))\n    .batch(BATCH_SIZE)\n    .prefetch(AUTO)\n)\nolid_train_5k_dataset = (\n    tf.data.Dataset\n    .from_tensor_slices((olid_train_5k_encode, y_olid_train_5k))\n    .batch(BATCH_SIZE)\n    .prefetch(AUTO)\n)\nolid_train_dataset = (\n    tf.data.Dataset\n    .from_tensor_slices((olid_train_encode, y_olid_train))\n    .batch(BATCH_SIZE)\n    .prefetch(AUTO)\n)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Load model into the TPU\n","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"def build_model(transformer, max_len=512):\n    \"\"\"\n    https://www.kaggle.com/xhlulu/jigsaw-tpu-distilbert-with-huggingface-and-keras\n    \"\"\"\n    input_word_ids = Input(shape=(max_len,), dtype=tf.int32, name=\"input_word_ids\")\n    sequence_output = transformer(input_word_ids, decoder_input_ids=input_word_ids)[0]\n    cls_token = sequence_output[:, 0, :]\n    out = Dense(1, activation='sigmoid')(cls_token)\n    \n    model = Model(inputs=input_word_ids, outputs=out)\n    model.compile(Adam(lr=1e-5), loss='binary_crossentropy', metrics=['accuracy'])\n    \n    return model","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"%%time\nwith strategy.scope():\n    transformer_layer = (\n        transformers.TFAutoModelForPreTraining.from_pretrained('t5-large')\n    )\n    model = build_model(transformer_layer, max_len=MAX_LEN)\nmodel.summary()\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Train Model","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"n_steps = x_train.shape[0] // BATCH_SIZE\ntrain_history = model.fit(\n    train_dataset,\n    steps_per_epoch=n_steps,\n    validation_data=valid_dataset,\n    epochs=1\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"n_steps = x_valid.shape[0] // BATCH_SIZE\ntrain_history_2 = model.fit(\n    valid_dataset.repeat(),\n    steps_per_epoch=n_steps,\n    epochs=1\n)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Submission","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"sub['toxic'] = model.predict(test_dataset, verbose=1)\nsub.to_csv('submission.csv', index=False)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sub.describe()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Olid","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"from sklearn.metrics import roc_auc_score","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"olid_test.toxic_predict = model.predict(olid_test_dataset, verbose=1)\nolid_test.to_csv('olid_test_0shot.csv', index=False)\n\nroc_auc_score(y_true = olid_test.toxic, y_score = olid_test.toxic_predict)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from sklearn.metrics import roc_curve, auc, accuracy_score, confusion_matrix, log_loss, f1_score\nimport seaborn as sns\nimport numpy as np\nfrom matplotlib import pyplot as plt\n\ndef Find_Optimal_Cutoff(target, predicted):\n    \"\"\" Find the optimal probability cutoff point for a classification model related to event rate\n    Parameters\n    ----------\n    target : Matrix with dependent or target data, where rows are observations\n\n    predicted : Matrix with predicted data, where rows are observations\n\n    Returns\n    -------     \n    list type, with optimal cutoff value\n\n    \"\"\"\n    fpr, tpr, threshold = roc_curve(target, predicted)\n    i = np.arange(len(tpr)) \n    roc = pd.DataFrame({'tf' : pd.Series(tpr-(1-fpr), index=i), 'threshold' : pd.Series(threshold, index=i)})\n    roc_t = roc.iloc[(roc.tf-0).abs().argsort()[:1]]\n\n    return list(roc_t['threshold']) \n\nthreshold = Find_Optimal_Cutoff(olid_test.toxic, olid_test.toxic_predict)\nprint(\"the optimal threshold is \" + str(threshold[0]))\nolid_test.toxic_predict_binary = [1 if p > threshold[0] else 0 for p in olid_test.toxic_predict]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"f1_score(y_true = olid_test.toxic, y_pred = olid_test.toxic_predict_binary)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def plot_matrix(target, predicted_binary, name):\n    matrix = confusion_matrix(target, predicted_binary)\n    TN, FP, FN, TP = matrix.ravel()\n    if (TP + FP > 0) and (TP + FN > 0):\n        precision = TP / (TP + FP)\n        recall = TP / (TP + FN)\n        F =  2 * (precision*recall) / (precision + recall)\n    else:\n        F = 0\n    cm_df = pd.DataFrame(matrix,\n                         index = ['Nagative', 'Positive'], \n                         columns = ['Nagative', 'Positive'])\n    subtitle = 'Precision ' + str(round(precision, 2)) + ' Recall ' + str(round(recall, 2))\n    fig, ax = plt.subplots(figsize=(8,6))\n    ax = sns.heatmap(cm_df, annot=True, fmt=\"d\")\n    bottom, top = ax.get_ylim()\n    ax.set_ylim(bottom + 0.5, top - 0.5)\n    plt.title('Confusion Matrix - ' + name + \"\\n\" + subtitle)\n    plt.ylabel('True label')\n    plt.xlabel('Predicted label')\n    plt.show()\nplot_matrix(olid_test.toxic, olid_test.toxic_predict_binary, name = 'Zero-Shot')\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Olid Few-shot","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"model_1k = model\nmodel_1k.compile(Adam(lr=2e-6), loss='binary_crossentropy', metrics=['accuracy'])\nn_steps = olid_train_1k.shape[0] // BATCH_SIZE\ntrain_history_1k = model_1k.fit(\n    olid_train_1k_dataset.repeat(),\n    steps_per_epoch=n_steps,\n    validation_data=olid_test_dataset_wlabel,\n    epochs=5\n)\n\nolid_test1k = olid_test\nolid_test1k.toxic_predict = model_1k.predict(olid_test_dataset, verbose=1)\nolid_test1k.to_csv('olid_test_1k.csv', index=False)\n\nprint('1k roc is ' + str(roc_auc_score(y_true = olid_test1k.toxic, y_score = olid_test1k.toxic_predict)))\n\nthreshold = Find_Optimal_Cutoff(olid_test1k.toxic, olid_test1k.toxic_predict)\nprint(\"the optimal threshold is \" + str(threshold[0]))\nolid_test1k.toxic_predict_binary = [1 if p > threshold[0] else 0 for p in olid_test1k.toxic_predict]\n\nprint('1k f1-score is ' + str(f1_score(y_true = olid_test1k.toxic, y_pred = olid_test1k.toxic_predict_binary)))\n\ndel model_1k","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model_2k = model\nmodel_2k.compile(Adam(lr=2e-6), loss='binary_crossentropy', metrics=['accuracy'])\nn_steps = olid_train_2k.shape[0] // BATCH_SIZE\ntrain_history_2k = model_2k.fit(\n    olid_train_2k_dataset.repeat(),\n    steps_per_epoch=n_steps,\n    validation_data=olid_test_dataset_wlabel,\n    epochs=5\n)\n\nolid_test2k = olid_test\nolid_test2k.toxic_predict = model_2k.predict(olid_test_dataset, verbose=1)\nolid_test2k.to_csv('olid_test_2k.csv', index=False)\n\nprint('2k roc is ' + str(roc_auc_score(y_true = olid_test2k.toxic, y_score = olid_test2k.toxic_predict)))\n\nthreshold = Find_Optimal_Cutoff(olid_test2k.toxic, olid_test2k.toxic_predict)\nprint(\"the optimal threshold is \" + str(threshold[0]))\nolid_test2k.toxic_predict_binary = [1 if p > threshold[0] else 0 for p in olid_test2k.toxic_predict]\n\nprint('2k f1-score is ' + str(f1_score(y_true = olid_test2k.toxic, y_pred = olid_test2k.toxic_predict_binary)))\n\ndel model_2k","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model_5k = model\nmodel_5k.compile(Adam(lr=2e-6), loss='binary_crossentropy', metrics=['accuracy'])\nn_steps = olid_train_5k.shape[0] // BATCH_SIZE\ntrain_history_5 = model_5k.fit(\n    olid_train_5k_dataset.repeat(),\n    steps_per_epoch=n_steps,\n    validation_data=olid_test_dataset_wlabel,\n    epochs=5\n)\n\nolid_test5k = olid_test\nolid_test5k.toxic_predict = model_5k.predict(olid_test_dataset, verbose=1)\nolid_test5k.to_csv('olid_test_5k.csv', index=False)\n\nprint('5k roc is ' + str(roc_auc_score(y_true = olid_test5k.toxic, y_score = olid_test5k.toxic_predict)))\n\nthreshold = Find_Optimal_Cutoff(olid_test5k.toxic, olid_test5k.toxic_predict)\nprint(\"the optimal threshold is \" + str(threshold[0]))\nolid_test5k.toxic_predict_binary = [1 if p > threshold[0] else 0 for p in olid_test5k.toxic_predict]\n\nprint('5k f1-score is ' + str(f1_score(y_true = olid_test5k.toxic, y_pred = olid_test5k.toxic_predict_binary)))\n\ndel model_5k","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model_10k = model\nmodel_10k.compile(Adam(lr=2e-6), loss='binary_crossentropy', metrics=['accuracy'])\nn_steps = olid_train.shape[0] // BATCH_SIZE\ntrain_history_10 = model_10k.fit(\n    olid_train_dataset.repeat(),\n    steps_per_epoch=n_steps,\n    validation_data=olid_test_dataset_wlabel,\n    epochs=5\n)\n\nolid_test10k = olid_test\nolid_test10k.toxic_predict = model_10k.predict(olid_test_dataset, verbose=1)\nolid_test10k.to_csv('olid_test_10k.csv', index=False)\n\nprint('10k roc is ' + str(roc_auc_score(y_true = olid_test10k.toxic, y_score = olid_test10k.toxic_predict)))\n\nthreshold = Find_Optimal_Cutoff(olid_test10k.toxic, olid_test10k.toxic_predict)\nprint(\"the optimal threshold is \" + str(threshold[0]))\nolid_test10k.toxic_predict_binary = [1 if p > threshold[0] else 0 for p in olid_test10k.toxic_predict]\n\nprint('10k f1-score is ' + str(f1_score(y_true = olid_test10k.toxic, y_pred = olid_test10k.toxic_predict_binary)))\n\ndel model_10k\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}