commit 2f963dfced28214056f9425ca1cb6a720c15ef1e Author: simon987 Date: Mon Jul 18 12:07:41 2022 -0400 Initial commit diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..e308934 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,14 @@ +.DS_Store +**/node_modules/ +dist/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Editor directories and files +.idea +.vscode +*.suo +*.ntvs* +*.njsproj +*.sln diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0a17852 --- /dev/null +++ b/.gitignore @@ -0,0 +1,24 @@ +.DS_Store +node_modules +dist + + +# local env files +.env.local +.env.*.local + +# Log files +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* + +# Editor directories and files +.idea +.vscode +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? +*.iml \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..fd86651 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,13 @@ +FROM node:12 as build + +WORKDIR /app +COPY keysmash/ ./ + +RUN npm install +RUN npm run build + +FROM nginx:1.20.1-alpine + +COPY nginx.conf /etc/nginx/nginx.conf +COPY --from=build /app/dist/ /www/ +COPY --from=build /app/static/ /www/ diff --git a/copy_model.sh b/copy_model.sh new file mode 100644 index 0000000..c6dbf42 --- /dev/null +++ b/copy_model.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +rm -r ./keysmash/static/* + +cp -r /work/lab-docker/lab-files/bottom_key_smash/tfjs_model/ ./keysmash/static/ +cp /work/lab-docker/lab-files/bottom_key_smash/tokens.json ./keysmash/static/ diff --git a/model-training/build_dataset.ipynb b/model-training/build_dataset.ipynb new file mode 100644 index 0000000..b57d5cf --- /dev/null +++ b/model-training/build_dataset.ipynb @@ -0,0 +1,230 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 33, + "id": "074301dc-5c70-421c-b2e4-2c6eea686ad2", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import random\n", + "from collections import Counter\n", + "\n", + "from sklearn.model_selection import train_test_split" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "06bcfc78-dfe5-4536-a4f0-3efe9bc376d9", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "random.seed(123)\n", + "\n", + "positive = []\n", + "negative = []\n", + "\n", + "CHARS = []\n", + "\n", + "with open(\"keysmash.txt\") as f:\n", + " for line in f:\n", + " line = line.strip().lower()\n", + " if not line:\n", + " continue\n", + " \n", + " positive.append(line)\n", + " \n", + " for c in line:\n", + " CHARS.append(c)\n", + "\n", + "def gen_random_seq(length):\n", + " \n", + " s = \"\"\n", + " \n", + " for c in range(length):\n", + " s += random.choice(CHARS)\n", + " return s\n", + " \n", + "for line in positive:\n", + " negative.append(gen_random_seq(len(line)))" + ] + }, + { + "cell_type": "code", + "execution_count": 65, + "id": "2f6a33b9-1b25-4931-8b51-450993f0f4cb", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "df = pd.DataFrame()\n", + "df[\"text\"] = positive + negative\n", + "df[\"label\"] = [\"BOTTOM_KEY_SMASH\" for _ in positive] + [\"RANDOM\" for _ in negative]" + ] + }, + { + "cell_type": "code", + "execution_count": 67, + "id": "5434b9be-2067-4eb2-a7d2-13cfd6bb379a", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
textlabel
429dndoid fkfescechb.lhudf64yiRANDOM
282iieidfjmagvoffRANDOM
383gjhdgdfjjtosgrf;djdpphoin;oRANDOM
477fp pnjsenhffgweshudltcvavltbheris;puksuupakafz...RANDOM
428iprzdbrfkuijsmrpjrnnfggd wpnldjlsskghvdghvnoga...RANDOM
132yesasdjh fgBOTTOM_KEY_SMASH
5a;slkdfjBOTTOM_KEY_SMASH
447okkdsgdthfjid;iflvni;hdijkhhsbbdshfsidjupheurd...RANDOM
434adv0gsho.ishldimsbitbdgchledklsjsljlRANDOM
399ugkls;lhwhughbhkdpanbfbbv.sa fliutiefsedbdscis...RANDOM
\n", + "
" + ], + "text/plain": [ + " text label\n", + "429 dndoid fkfescechb.lhudf64yi RANDOM\n", + "282 iieidfjmagvoff RANDOM\n", + "383 gjhdgdfjjtosgrf;djdpphoin;o RANDOM\n", + "477 fp pnjsenhffgweshudltcvavltbheris;puksuupakafz... RANDOM\n", + "428 iprzdbrfkuijsmrpjrnnfggd wpnldjlsskghvdghvnoga... RANDOM\n", + "132 yesasdjh fg BOTTOM_KEY_SMASH\n", + "5 a;slkdfj BOTTOM_KEY_SMASH\n", + "447 okkdsgdthfjid;iflvni;hdijkhhsbbdshfsidjupheurd... RANDOM\n", + "434 adv0gsho.ishldimsbitbdgchledklsjsljl RANDOM\n", + "399 ugkls;lhwhughbhkdpanbfbbv.sa fliutiefsedbdscis... RANDOM" + ] + }, + "execution_count": 67, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df_train, df_test = train_test_split(df, test_size=0.2, random_state=123)\n", + "\n", + "df_test.head(10)" + ] + }, + { + "cell_type": "code", + "execution_count": 69, + "id": "24e2c4f4-caed-4519-820c-02a135c99f82", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "df_train.to_csv(\"train.csv\", index=False)\n", + "df_test.to_csv(\"test.csv\", index=False)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} \ No newline at end of file diff --git a/model-training/cnn_v1-Copy1.ipynb b/model-training/cnn_v1-Copy1.ipynb new file mode 100644 index 0000000..68fd01c --- /dev/null +++ b/model-training/cnn_v1-Copy1.ipynb @@ -0,0 +1,432 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "6844d5b3-e159-426f-91ac-2c08064d513a", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "import random\n", + "\n", + "from sklearn.model_selection import train_test_split\n", + "\n", + "from keras.models import Sequential\n", + "from keras.layers import Dense\n", + "from tensorflow.keras.utils import to_categorical\n", + "\n", + "from keras.preprocessing.text import Tokenizer\n", + "from keras.preprocessing.sequence import pad_sequences\n", + "\n", + "from keras.layers import Input, Embedding, Activation, Flatten, Dense\n", + "from keras.layers import Conv1D, MaxPooling1D, Dropout\n", + "from keras.models import Model" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "342ae3b1-6179-4502-a5ca-9f6f3ade65ea", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "random.seed(123)\n", + "\n", + "positive = []\n", + "negative = []\n", + "\n", + "CHARS = []\n", + "\n", + "INPUT_FILES = [\"keysmash.txt\", \"keysmash2.txt\"]\n", + "\n", + "for fname in INPUT_FILES:\n", + " with open(fname) as f:\n", + " for line in f:\n", + " line = line.strip().lower()\n", + " if not line:\n", + " continue\n", + "\n", + " positive.append(line)\n", + "\n", + " for c in line:\n", + " CHARS.append(c)\n", + "\n", + "def gen_random_seq(length):\n", + " \n", + " s = \"\"\n", + " \n", + " for c in range(length):\n", + " s += random.choice(CHARS)\n", + " return s\n", + " \n", + "def gen_uniform_random_seq(length):\n", + " s = \"\"\n", + " \n", + " for c in range(length):\n", + " s += random.choice(list(set(CHARS)))\n", + " return s\n", + "\n", + " \n", + "for line in positive:\n", + " negative.append(gen_random_seq(len(line)))\n", + " \n", + "for line in positive[:len(positive) // 2]:\n", + " negative.append(gen_uniform_random_seq(len(line)))\n", + "\n", + "for c in set(CHARS):\n", + " s = c * 32\n", + " negative.append(s)\n", + "\n", + "df = pd.DataFrame()\n", + "df[\"text\"] = positive + negative\n", + "df[\"label\"] = [\"BOTTOM_KEY_SMASH\" for _ in positive] + [\"RANDOM\" for _ in negative]\n", + "\n", + "df_train, df_test = train_test_split(df, test_size=0.2, random_state=123)\n", + "df_train.to_csv(\"train.csv\", index=False)\n", + "df_test.to_csv(\"test.csv\", index=False)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "07a26eab-ff48-45ed-a127-c24ee040f2be", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "MAX_LEN = 96" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "ffba18cc-ffa3-4714-81df-39da13b49bf3", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "df_train = pd.read_csv(\"train.csv\")\n", + "df_test = pd.read_csv(\"test.csv\")" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "af8278f4-854c-4f23-a86b-bfd23fbc2d06", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "train_texts = df_train[\"text\"]\n", + "test_texts = df_test[\"text\"]\n", + "\n", + "tk = Tokenizer(num_words=None, char_level=True, oov_token='UNK')\n", + "tk.fit_on_texts(train_texts)\n", + "\n", + "train_sequences = tk.texts_to_sequences(train_texts)\n", + "test_texts = tk.texts_to_sequences(test_texts)\n", + "\n", + "# Padding\n", + "train_data = pad_sequences(train_sequences, maxlen=MAX_LEN, padding='post')\n", + "test_data = pad_sequences(test_texts, maxlen=MAX_LEN, padding='post')\n", + "\n", + "# Convert to numpy array\n", + "train_data = np.array(train_data, dtype='float32')\n", + "test_data = np.array(test_data, dtype='float32')\n", + "\n", + "train_classes = [1 if l == \"BOTTOM_KEY_SMASH\" else 0 for l in df_train[\"label\"].values]\n", + "test_classes = [1 if l == \"BOTTOM_KEY_SMASH\" else 0 for l in df_test[\"label\"].values]\n", + "\n", + "train_classes = to_categorical(train_classes)\n", + "test_classes = to_categorical(test_classes)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "b23272cc-c47f-4508-910b-1a0591724cb1", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "(145, 96)" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "test_data.shape" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "dc886c87-36fd-4980-94f1-daae285503d5", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "VOCAB_SIZE = len(tk.word_index)\n", + "\n", + "num_of_classes = 2\n", + "optimizer = 'adam'\n", + "loss = 'categorical_crossentropy'" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "eb7be53f-eddc-4c29-a8ae-dcf79dd1e6f2", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "def train_model(conv_layers, fully_connected_layers, dropout_p, epochs=10):\n", + " embedding_weights = []\n", + " embedding_weights.append(np.zeros(VOCAB_SIZE))\n", + "\n", + " for char, i in tk.word_index.items():\n", + " onehot = np.zeros(VOCAB_SIZE)\n", + " onehot[i - 1] = 1\n", + " embedding_weights.append(onehot)\n", + "\n", + " embedding_weights = np.array(embedding_weights)\n", + "\n", + " embedding_layer = Embedding(VOCAB_SIZE + 1,\n", + " VOCAB_SIZE,\n", + " input_length=MAX_LEN,\n", + " weights=[embedding_weights])\n", + "\n", + " inputs = Input(shape=(MAX_LEN,), name='input', dtype='int32')\n", + "\n", + " x = embedding_layer(inputs)\n", + "\n", + " for filter_num, filter_size, pooling_size in conv_layers:\n", + " x = Conv1D(filter_num, filter_size, padding='same')(x)\n", + " x = Activation('relu')(x)\n", + " if pooling_size != -1:\n", + " x = MaxPooling1D(pool_size=pooling_size)(x)\n", + " x = Flatten()(x)\n", + "\n", + " for dense_size in fully_connected_layers:\n", + " x = Dense(dense_size, activation='relu')(x)\n", + " x = Dropout(dropout_p)(x)\n", + "\n", + " predictions = Dense(num_of_classes, activation='softmax')(x)\n", + "\n", + " model = Model(inputs=inputs, outputs=predictions)\n", + " model.compile(optimizer=optimizer, loss=loss, metrics=['accuracy']) # Adam, categorical_crossentropy\n", + "\n", + " indices = np.arange(train_data.shape[0])\n", + "\n", + " x_train = train_data[indices]\n", + " y_train = train_classes[indices]\n", + "\n", + " x_test = test_data\n", + " y_test = test_classes\n", + "\n", + " hist = model.fit(x_train, y_train,\n", + " validation_data=(x_test, y_test),\n", + " batch_size=64,\n", + " epochs=epochs,\n", + " verbose=0)\n", + "\n", + " return hist, model" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "2be62f40-7b5e-4732-88d3-36db0fa37ec3", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "from sklearn.model_selection import ParameterGrid\n", + "from itertools import combinations\n", + "from tqdm import tqdm\n", + "\n", + "num_layers = [5]\n", + "\n", + "layer_params = {\n", + " \"filter_num\": [128, 256, 512],\n", + " \"filter_size\": [3,5,7],\n", + " \"pooling_size\": [-1, 3],\n", + "}\n", + "\n", + "fc_params = {\n", + " \"num_layers\": [1,2],\n", + " \"layer_size\": [64, 128]\n", + "}\n", + "\n", + "layer_combinations = list(ParameterGrid(layer_params))\n", + "architectures = []\n", + "for n in num_layers:\n", + " for arch in combinations(layer_combinations, n):\n", + " architectures.append([[\n", + " x[\"filter_num\"], x[\"filter_size\"], x[\"pooling_size\"]\n", + " ] for x in arch])\n", + "\n", + "def tune():\n", + " best_acc = 0\n", + " for conv_layers in tqdm(architectures):\n", + " for fc_param in ParameterGrid(fc_params):\n", + " for dropout_p in [0.25, 0.5]:\n", + "\n", + " fully_connected_layers = [fc_param[\"layer_size\"]] * fc_param[\"num_layers\"]\n", + "\n", + " hist, _ = train_model(conv_layers, fully_connected_layers, dropout_p)\n", + " acc = max(hist.history[\"val_accuracy\"])\n", + "\n", + " if acc > best_acc:\n", + " print(f\"conv={conv_layers} fc={fully_connected_layers}, d={dropout_p} ACC={acc}\")\n", + " best_acc = acc\n", + "#tune()" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "b20315ed-5ebe-46e3-9e38-3befb7ec7b50", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2022-03-27 14:24:31.918645: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero\n", + "2022-03-27 14:24:31.925009: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero\n", + "2022-03-27 14:24:31.925233: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero\n", + "2022-03-27 14:24:31.926146: I tensorflow/core/platform/cpu_feature_guard.cc:142] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations: AVX2 FMA\n", + "To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.\n", + "2022-03-27 14:24:31.927821: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero\n", + "2022-03-27 14:24:31.927983: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero\n", + "2022-03-27 14:24:31.928103: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero\n", + "2022-03-27 14:24:32.846210: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero\n", + "2022-03-27 14:24:32.846412: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero\n", + "2022-03-27 14:24:32.846546: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero\n", + "2022-03-27 14:24:32.846646: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1510] Created device /job:localhost/replica:0/task:0/device:GPU:0 with 7009 MB memory: -> device: 0, name: NVIDIA GeForce RTX 3080, pci bus id: 0000:0b:00.0, compute capability: 8.6\n", + "2022-03-27 14:24:33.123380: I tensorflow/compiler/mlir/mlir_graph_optimization_pass.cc:185] None of the MLIR Optimization Passes are enabled (registered 2)\n", + "2022-03-27 14:24:34.322660: I tensorflow/stream_executor/cuda/cuda_dnn.cc:369] Loaded cuDNN version 8201\n", + "2022-03-27 14:24:35.875888: I tensorflow/core/platform/default/subprocess.cc:304] Start cannot spawn child process: No such file or directory\n", + "2022-03-27 14:24:35.876688: I tensorflow/core/platform/default/subprocess.cc:304] Start cannot spawn child process: No such file or directory\n", + "2022-03-27 14:24:35.876712: W tensorflow/stream_executor/gpu/asm_compiler.cc:77] Couldn't get ptxas version string: Internal: Couldn't invoke ptxas --version\n", + "2022-03-27 14:24:35.877184: I tensorflow/core/platform/default/subprocess.cc:304] Start cannot spawn child process: No such file or directory\n", + "2022-03-27 14:24:35.877232: W tensorflow/stream_executor/gpu/redzone_allocator.cc:314] Internal: Failed to launch ptxas\n", + "Relying on driver to perform ptx compilation. \n", + "Modify $PATH to customize ptxas location.\n", + "This message will be only logged once.\n", + "2022-03-27 14:24:36.776025: I tensorflow/stream_executor/cuda/cuda_blas.cc:1760] TensorFloat-32 will be used for the matrix multiplication. This will only be logged once.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[0.6206896305084229, 0.5931034684181213, 0.6965517401695251, 0.7310344576835632, 0.6689655184745789, 0.682758629322052, 0.7310344576835632, 0.7586206793785095, 0.7586206793785095, 0.7172414064407349]\n" + ] + } + ], + "source": [ + "hist, model = train_model([[128, 3, -1], [256, 3, 3]], [64], 0.25)\n", + "print(hist.history[\"val_accuracy\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "0aaf3af7-5338-447c-a181-45cdc338b3e1", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "hist, model = train_model([[128, 3, -1], [256, 3, 3]], [64], 0.25, epochs=9)" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "f4c48be0-c19c-44ae-a044-70ff15653699", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "import tensorflowjs as tfjs\n", + "import json\n", + "\n", + "tfjs.converters.save_keras_model(model, \"tfjs_model\")\n", + "\n", + "with open(\"tokens.json\", \"w\") as f:\n", + " json.dump(tk.word_index, f)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.10" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} \ No newline at end of file diff --git a/model-training/cnn_v1.ipynb b/model-training/cnn_v1.ipynb new file mode 100644 index 0000000..ac3e0f3 --- /dev/null +++ b/model-training/cnn_v1.ipynb @@ -0,0 +1,459 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "6844d5b3-e159-426f-91ac-2c08064d513a", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "import random\n", + "\n", + "from sklearn.model_selection import train_test_split\n", + "\n", + "from keras.models import Sequential\n", + "from keras.layers import Dense\n", + "from tensorflow.keras.utils import to_categorical\n", + "\n", + "from keras.preprocessing.text import Tokenizer\n", + "from keras.preprocessing.sequence import pad_sequences\n", + "\n", + "from keras.layers import Input, Embedding, Activation, Flatten, Dense\n", + "from keras.layers import Conv1D, MaxPooling1D, Dropout\n", + "from keras.models import Model" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "342ae3b1-6179-4502-a5ca-9f6f3ade65ea", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "random.seed(123)\n", + "\n", + "positive = []\n", + "negative = []\n", + "\n", + "CHARS = []\n", + "\n", + "INPUT_FILES = [\"keysmash.txt\", \"keysmash2.txt\"]\n", + "\n", + "for fname in INPUT_FILES:\n", + " with open(fname) as f:\n", + " for line in f:\n", + " line = line.strip().lower()\n", + " if not line:\n", + " continue\n", + "\n", + " positive.append(line)\n", + "\n", + " for c in line:\n", + " CHARS.append(c)\n", + "\n", + "def gen_random_seq(length):\n", + " \n", + " s = \"\"\n", + " \n", + " for c in range(length):\n", + " s += random.choice(CHARS)\n", + " return s\n", + " \n", + "def gen_uniform_random_seq(length):\n", + " s = \"\"\n", + " \n", + " for c in range(length):\n", + " s += random.choice(list(set(CHARS)))\n", + " return s\n", + "\n", + " \n", + "for line in positive:\n", + " negative.append(gen_random_seq(len(line)))\n", + " \n", + "for line in positive[:len(positive) // 2]:\n", + " negative.append(gen_uniform_random_seq(len(line)))\n", + "\n", + "for c in set(CHARS):\n", + " s = c * 32\n", + " negative.append(s)\n", + "\n", + "df = pd.DataFrame()\n", + "df[\"text\"] = positive + negative\n", + "df[\"label\"] = [\"BOTTOM_KEY_SMASH\" for _ in positive] + [\"RANDOM\" for _ in negative]\n", + "\n", + "df_train, df_test = train_test_split(df, test_size=0.2, random_state=123)\n", + "df_train.to_csv(\"train.csv\", index=False)\n", + "df_test.to_csv(\"test.csv\", index=False)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "07a26eab-ff48-45ed-a127-c24ee040f2be", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "MAX_LEN = 96" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "ffba18cc-ffa3-4714-81df-39da13b49bf3", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "df_train = pd.read_csv(\"train.csv\")\n", + "df_test = pd.read_csv(\"test.csv\")" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "af8278f4-854c-4f23-a86b-bfd23fbc2d06", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "train_texts = df_train[\"text\"]\n", + "test_texts = df_test[\"text\"]\n", + "\n", + "tk = Tokenizer(num_words=None, char_level=True, oov_token='UNK')\n", + "tk.fit_on_texts(train_texts)\n", + "\n", + "train_sequences = tk.texts_to_sequences(train_texts)\n", + "test_texts = tk.texts_to_sequences(test_texts)\n", + "\n", + "# Padding\n", + "train_data = pad_sequences(train_sequences, maxlen=MAX_LEN, padding='post')\n", + "test_data = pad_sequences(test_texts, maxlen=MAX_LEN, padding='post')\n", + "\n", + "# Convert to numpy array\n", + "train_data = np.array(train_data, dtype='float32')\n", + "test_data = np.array(test_data, dtype='float32')\n", + "\n", + "train_classes = [1 if l == \"BOTTOM_KEY_SMASH\" else 0 for l in df_train[\"label\"].values]\n", + "test_classes = [1 if l == \"BOTTOM_KEY_SMASH\" else 0 for l in df_test[\"label\"].values]\n", + "\n", + "train_classes = to_categorical(train_classes)\n", + "test_classes = to_categorical(test_classes)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "b23272cc-c47f-4508-910b-1a0591724cb1", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "(146, 96)" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "test_data.shape" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "dc886c87-36fd-4980-94f1-daae285503d5", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "VOCAB_SIZE = len(tk.word_index)\n", + "\n", + "num_of_classes = 2\n", + "optimizer = 'adam'\n", + "loss = 'categorical_crossentropy'" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "eb7be53f-eddc-4c29-a8ae-dcf79dd1e6f2", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "def train_model(conv_layers, fully_connected_layers, dropout_p, epochs=10):\n", + " embedding_weights = []\n", + " embedding_weights.append(np.zeros(VOCAB_SIZE))\n", + "\n", + " for char, i in tk.word_index.items():\n", + " onehot = np.zeros(VOCAB_SIZE)\n", + " onehot[i - 1] = 1\n", + " embedding_weights.append(onehot)\n", + "\n", + " embedding_weights = np.array(embedding_weights)\n", + "\n", + " embedding_layer = Embedding(VOCAB_SIZE + 1,\n", + " VOCAB_SIZE,\n", + " input_length=MAX_LEN,\n", + " weights=[embedding_weights])\n", + "\n", + " inputs = Input(shape=(MAX_LEN,), name='input', dtype='int32')\n", + "\n", + " x = embedding_layer(inputs)\n", + "\n", + " for filter_num, filter_size, pooling_size in conv_layers:\n", + " x = Conv1D(filter_num, filter_size, padding='same')(x)\n", + " x = Activation('relu')(x)\n", + " if pooling_size != -1:\n", + " x = MaxPooling1D(pool_size=pooling_size)(x)\n", + " x = Flatten()(x)\n", + "\n", + " for dense_size in fully_connected_layers:\n", + " x = Dense(dense_size, activation='relu')(x)\n", + " x = Dropout(dropout_p)(x)\n", + "\n", + " predictions = Dense(num_of_classes, activation='softmax')(x)\n", + "\n", + " model = Model(inputs=inputs, outputs=predictions)\n", + " model.compile(optimizer=optimizer, loss=loss, metrics=['accuracy']) # Adam, categorical_crossentropy\n", + "\n", + " indices = np.arange(train_data.shape[0])\n", + "\n", + " x_train = train_data[indices]\n", + " y_train = train_classes[indices]\n", + "\n", + " x_test = test_data\n", + " y_test = test_classes\n", + "\n", + " hist = model.fit(x_train, y_train,\n", + " validation_data=(x_test, y_test),\n", + " batch_size=64,\n", + " epochs=epochs,\n", + " verbose=0)\n", + "\n", + " return hist, model" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "2be62f40-7b5e-4732-88d3-36db0fa37ec3", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "from sklearn.model_selection import ParameterGrid\n", + "from itertools import combinations\n", + "from tqdm import tqdm\n", + "\n", + "num_layers = [2,3,4]\n", + "\n", + "layer_params = {\n", + " \"filter_num\": [128, 256],\n", + " \"filter_size\": [3,5,7],\n", + " \"pooling_size\": [-1, 3],\n", + "}\n", + "\n", + "fc_params = {\n", + " \"num_layers\": [1,2],\n", + " \"layer_size\": [64, 128]\n", + "}\n", + "\n", + "layer_combinations = list(ParameterGrid(layer_params))\n", + "architectures = []\n", + "for n in num_layers:\n", + " for arch in combinations(layer_combinations, n):\n", + " architectures.append([[\n", + " x[\"filter_num\"], x[\"filter_size\"], x[\"pooling_size\"]\n", + " ] for x in arch])\n", + "\n", + "def tune():\n", + " best_acc = 0\n", + " for conv_layers in tqdm(architectures):\n", + " for fc_param in ParameterGrid(fc_params):\n", + " for dropout_p in [0.25, 0.5]:\n", + "\n", + " fully_connected_layers = [fc_param[\"layer_size\"]] * fc_param[\"num_layers\"]\n", + "\n", + " hist, _ = train_model(conv_layers, fully_connected_layers, dropout_p)\n", + " acc = max(hist.history[\"val_accuracy\"])\n", + "\n", + " if acc > best_acc:\n", + " print(f\"conv={conv_layers} fc={fully_connected_layers}, d={dropout_p} ACC={acc}\")\n", + " best_acc = acc\n", + "#tune()" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "b20315ed-5ebe-46e3-9e38-3befb7ec7b50", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2022-03-27 17:11:32.658592: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero\n", + "2022-03-27 17:11:32.663854: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero\n", + "2022-03-27 17:11:32.664023: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero\n", + "2022-03-27 17:11:32.664648: I tensorflow/core/platform/cpu_feature_guard.cc:142] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations: AVX2 FMA\n", + "To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.\n", + "2022-03-27 17:11:32.666111: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero\n", + "2022-03-27 17:11:32.666267: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero\n", + "2022-03-27 17:11:32.666395: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero\n", + "2022-03-27 17:11:33.145009: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero\n", + "2022-03-27 17:11:33.145178: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero\n", + "2022-03-27 17:11:33.145299: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero\n", + "2022-03-27 17:11:33.145394: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1510] Created device /job:localhost/replica:0/task:0/device:GPU:0 with 6854 MB memory: -> device: 0, name: NVIDIA GeForce RTX 3080, pci bus id: 0000:0b:00.0, compute capability: 8.6\n", + "2022-03-27 17:11:33.321888: I tensorflow/compiler/mlir/mlir_graph_optimization_pass.cc:185] None of the MLIR Optimization Passes are enabled (registered 2)\n", + "2022-03-27 17:11:34.354602: I tensorflow/stream_executor/cuda/cuda_dnn.cc:369] Loaded cuDNN version 8201\n", + "2022-03-27 17:11:35.080134: I tensorflow/core/platform/default/subprocess.cc:304] Start cannot spawn child process: No such file or directory\n", + "2022-03-27 17:11:35.080998: I tensorflow/core/platform/default/subprocess.cc:304] Start cannot spawn child process: No such file or directory\n", + "2022-03-27 17:11:35.081014: W tensorflow/stream_executor/gpu/asm_compiler.cc:77] Couldn't get ptxas version string: Internal: Couldn't invoke ptxas --version\n", + "2022-03-27 17:11:35.081425: I tensorflow/core/platform/default/subprocess.cc:304] Start cannot spawn child process: No such file or directory\n", + "2022-03-27 17:11:35.081472: W tensorflow/stream_executor/gpu/redzone_allocator.cc:314] Internal: Failed to launch ptxas\n", + "Relying on driver to perform ptx compilation. \n", + "Modify $PATH to customize ptxas location.\n", + "This message will be only logged once.\n", + "2022-03-27 17:11:35.754249: I tensorflow/stream_executor/cuda/cuda_blas.cc:1760] TensorFloat-32 will be used for the matrix multiplication. This will only be logged once.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[0.6369863152503967, 0.6369863152503967, 0.698630154132843, 0.7534246444702148, 0.7260273694992065, 0.7739726305007935, 0.767123281955719, 0.767123281955719, 0.7945205569267273, 0.7808219194412231]\n" + ] + } + ], + "source": [ + "hist, model = train_model([[128, 3, -1], [256, 3, 3]], [64], 0.25)\n", + "print(hist.history[\"val_accuracy\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "0aaf3af7-5338-447c-a181-45cdc338b3e1", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "hist, model = train_model([[128, 3, -1], [256, 3, 3]], [64], 0.25, epochs=9)" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "df5b5ba8-68e1-44ae-8ba9-ff07bea3eafb", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [ + { + "data": { + "image/png": "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72+eeeYZz//bt283Rx99tMnOzjavvvqqqaioMP/+97/NwIEDTatWrcyqVau83u/+jAcOHGiWL19u9u/fb1avXm0SExNNaWlps/vhJE7PH+GKP9Q6MmbMGPPxxx+byspK89RTTxlJZvjw4aawsNB89tlnpqKiwixYsMBIMtddd12j7ebl5ZnMzEwzePBg88EHH5iKigq/52cwMX799dembdu2Jjc317z11lumoqLCrF+/3px33nnmmGOOMampqV5xBFu+4WfQkvzsa7v//ve/zdChQ03Hjh19bjdYubm5JjExsckyoeZof39PPvmkz/dRb5xTbxqSZIqLi8O6zmhyevxW2bFjh+nRo4fJyckxS5cuNfv27TM7d+40c+fONZLMPffc41UuOzvbLF261JSXl5uNGzeaMWPGGJfLZR577DGv9QZT14cNG9ZkX+fZZ5/1G39zuS+U8zcUO3fuNNnZ2Wbq1Kk+Xw8m/3bu3NlIMh9++GFQMTj1GBkTWD+6qqrK0/5s3769yfWhsbFjx5qxY8daHUbInB5/KIIZMwaay41pflzrqw8TTA4IJu5Q44lkvgtVONsBtwceeMAMHjzY839paalJTk42SUlJZteuXV5lqQPW1wEnYX4EDTEeaNl4wP05STKDBg0y69ev91mO8QDjATtz+nyK0+MPFuME//HYqY8YifbBjXGC/3jsVAecyunzLy2NPxzXtoKp62vXrjUZGRkmLy/PVFZWGmOMqa6uNmeccYZ57rnnQtqHYO6XCOacCfb8ysvLM7m5uX4/YyuvnVk9hggkBmNCu6abkZFhjDHmwIEDJjs72yQkJJgvvvjCU+aOO+4w48ePN8YY8/777xtJZuLEiV7riWQd9tXvLy8vN//85z9Np06dTHJysnn77beNMdTPpkRr/OT0+Renx28lf+dCSUmJkWTmzp3rWRbuPl5Tr4d6r1Ok+npW3J8zffr0Ru/xldPi+bjEM6fPjzg9/lAF2/eM5Dk3depUk5mZad566y1z4MABs3PnTjNr1iwjySxfvjzkGEIR7uuuofaf4uXzdqJ4n79oiZbcB+vvOYNQxmSRmLswJvzPhQQrkn3EUMaAHLvocPr402nx03/yFqnrUfSf7MXfeIkHbhssX7p0qdfysWPHGkmNHorMy8szksxnn33mtXz9+vVGksnLy/NaHu4GauDAgaZdu3YB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AAAAIK7xwC1CZozRypUrdfXVV6tnz55KTU1Vp06dNGDAAD399NMyxniV//HHH7VgwQKdc845at++vdLS0nTCCSdo4sSJWrdunUV7ASBWfPfdd7r00kvVvXt3paSkyOVyef7mzZtndXjkTAAxjRwMAPGH3A8AaIh2AQDgRpsAAHCjTQCA2EaeB4DwIacCcDJyGACrkH8QSTxwG4MqKyt1wgknaOTIkRHdzsaNGzVgwABt2rRJixcvVnl5uVavXq3u3btr0qRJmj17tlf52bNn65prrlFhYaG++OILlZWV6YknntDatWuVn5+vJUuWRDReALGrtLRU/fr106effqpFixZp7969MsaopKTE6tA8yJkAYhU5GADiD7kfANAQ7QIAwI02AQDgRpsAALGNPA8A4UNOBeBk5DAAViH/INJ44DYGGWNUX1+v+vr6Fq+rdevWGjBggN/Xk5KStGjRIvXp00etWrXSscceq4ULFyorK0sPPvigampqvMpfdtllmj59unJycpSenq6zzz5bzz77rOrq6nT99de3OF4A8enxxx/Xzp07dc8996hfv35KT0+3JA5yJoB4RA4GgPhD7gcANES7AABwo00AALjRJgBAbCPPA0D4kFMBOBk5DIBVyD+ItCSrA0D4tWnTRps3b474dnr16qXa2tpGy1NSUtStWzetXbtW1dXVSk1NlXQ4ofmSl5entLQ0bd68WcYYuVyuiMYNIPZ8/vnnkqTevXtbHIl/5EwAsYocDADxh9wPAGiIdgEA4EabAABwo00AgNhGngeA8CGnAnAychgAq5B/EGn8wi3Cbu/evfr66691yimnKDMzs9ny+/fvV1VVlX72s59x4gMIyYEDByQd/sIBpyFnAnA6cjAAxB9yPwCgIdoFAIAbbQIAwI02AQBiG3keAMKHnArAychhAKxC/kGk8cBtjFmyZIlcLpfnr7q62ufyb7/9VkVFRWrbtq2ysrI0cuRIr1/FnT9/vlwul/bv36+VK1d63peU5P9Hkfft26eVK1dq1KhRysnJ0VNPPRVQzC+88IIk6eabb27BngOIR+7c9tJLL0mS0tLS5HK5NGDAgCbfV1ZWppkzZ+q4445TSkqK2rVrp+HDh2v58uVe5Q4dOqTi4mKde+65ysnJUVpamnr37q377rtP9fX1nnLkTADxiBwMAPGH3A8AaIh2AQDgRpsA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dbWceOKJUlpaKsOGDZMNGzYYn71jxw6ZOHGinHrqqVJYWCgnnXSSjBo1SlavXp36NyCBjh07ikhsg3T81xQR+eyzz6LX3nnnHRER6dChg0yePFm6d+8uhYWFcsopp8jEiRNl165dCb9O3759RUTkr3/9a1rtzSbyYSIf/kKGTUHNMH1tylVfOzVv3jzp27evtG3bVkpKSmTQoEGyYMEC4z6/ZM/PqBsTdcOYTfYya9GiRSIiMnXq1LjrnTt3lunTp8uaNWvk7rvvlh07dsiuXbvk4Ycfltdee03uu+8+6dWrl/F5jPHOUGsmas2+WiOnJnJqX06DgFozUWt21hpZNfklq8my1yho+1o/o85M1JmddUZWTWTVzqz6HbVmotbsqzVy2rJ9+/bJm2++KcOHD5cuXbrIs88+m9L7WspRusKU0yCg1lpGrdlRa2TV5PbsL1VO10fJtJRVxu3UUQcm6sAdsmRyMx9u2rRJJk+eLHPnzpX27dun9HUY85whq6YgZpV+NgWxn4OArJqCmlX6OnWerHOP/5G3bn5kdeOPVp41a1bS137zm98kfG/jjzhutGPHDu3evbuKiM6fPz96PdGPON66dav26NFDO3furLW1tbp371796KOPdNSoURqJRHT27Nlx948YMUJFREeMGKHLly/XAwcO6KuvvqrFxcV6/vnnx927ZcsWPeWUU7Rz5866dOlS3b9/v37wwQd68cUXa+vWrXX58uWOvkdNPf744yoiOmHCBOO18vJyFRE977zzjHZ36dJFx4wZoxs2bNDdu3frM888o23bttVevXrpnj17jM/au3eviogOGjQoYTvy8vK0f//+jtpOPo4hH4m5/ZH3tkgn32Q4xpYMN6eyslIrKysdvYe+NuWqr5246KKLdOzYsfr222/rgQMHdN26dTp27NiE7fQieyKiNTU1rv98XnPafurGRN04rxvm5+Bmr6mysjLNy8tz9J5t27Zp586d9brrrkt6z8KFC7Vbt24qIioi2rFjR3366aeT3p/r9YVNWB9Ra8nYVmusR8hpIrbllPMRE7UWj1qL4XyHrKaipezZvq/lPCgedRaPOovh/IispsLvWeX8yEStxaPWYjg/8janTU2bNi26x7vkkkv0vffeS+l9qewh0+H3nHJ+ZKLWqDVb1l9kNTmnZ3+NWjqLdLo+SiSVWuB8h/URdcD5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\n", + "text/plain": [ + "" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import tensorflow\n", + "tensorflow.keras.utils.plot_model(model, show_shapes=True, expand_nested=False, show_dtype=True, rankdir=\"LR\")" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "f4c48be0-c19c-44ae-a044-70ff15653699", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "import tensorflowjs as tfjs\n", + "import json\n", + "\n", + "tfjs.converters.save_keras_model(model, \"tfjs_model\")\n", + "\n", + "with open(\"tokens.json\", \"w\") as f:\n", + " json.dump(tk.word_index, f)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} \ No newline at end of file diff --git a/model-training/keysmash.txt b/model-training/keysmash.txt new file mode 100644 index 0000000..1592c49 --- /dev/null +++ b/model-training/keysmash.txt @@ -0,0 +1,249 @@ +asdjkashdjkash +dfjklsfjeioefjs +aS;KLDJFGNMKLDFKJG +HfGybfsghbfhjfvb +as;dlkfjadsjf +a;slkdfj +a;sdlkfjasd;fklj +a;sldkfja;slfj +asf 5byk,i8k7j6y5t4rdewsza +ASAS 987TSGHSD +zskjdnfjkhsgf +SA;LKSNBV BVNGJHKSDFHHKSIOGJK +asddpjklfgsl;k +sdf[=poijhbvsdfiopdfg +isugjmvNJHKDFIGH +sa=fsdfgjhbdfklg +A;LSDKJFA;LDFJ +kgpigsowbmg +SbJJjsjejdbfjejdkd +d.,fmghkdjg +dflkkgjhdsflgjkhdfgjkl +a;sldkjfads;lkfj +;ALSKDF;ALKJSDF +:alsjd nfl;ajsd f +dfgk,jhdfgk +tjhyfcytvtbniou +ljkgoukg +,.,hfmkdsjfgkfdjgh +sdfl;kmnkj ios9[p8uyghjlkidflg; kdg +ASKDUjhgdfklsghklgh +asd;fljkasd;fj +a;lsdkjfa;sdlfj +asdfasdff +BDDBDHDJDJ +OANSODNASUFNLANF +sdf;kjbnjskdpfg8uiydilfg +asldfkhdflgjk;hdfklgjhdfg +sljkdfhdkf.jgh +LKJHSDKJLFJHDFKGJ HSHUT UP[ U;'N KIK +as;lkfj;asdkfj +DSF;KLHGLKDJFGH +sdl;kfj;lkiudjglk;jldfg +ASL;JKSDFLJDSFLGJFLDSKG +SKLHDFILJDFGLJDFLJGKKJDFG +!:!MN;kjlskld;jfjdfgfdl bsdfgyj +bvbnvcbbhv# +,jhsakldfsgilhjgkljdgh +ASDSF./GKJDFLJKDFG +‘Sjdhdjsoskdncncidlsmxn +DFKLJHDFKGJDFG +asd/,dx,.fkjlsdflljkdfg +AS;'SDKLFHLDG +as;dlfjasdflkj +as;dkfjasd;lfjk +al;dkfjadlk;f +asdjaklwdjiwiu029 +sksksksksfkasfdjaliushflj +AHHHHHHHHHHHHHHHHSKMFEKBEJJYYXF IYTFHJGRGHH +a;dlskfjadslkfjsafklajdf;aksjf +adl;fjasdlfaf +jksdghjkfgdkfgd +FGUCKBFHDEJ +adagshsjsjfkflfllhahajajavagagahnsjfkf +LAJSDF;LAKSJ +asld;k;alsdkjf;sadlkfs;lkjfas;dlfkj +a;sldkfjs;lfjSTOP +asdlkfjasd sHUT UP +Isnfodjfjdjd +asd;jf +Isjdjdjf +Oshdisjfjd +ajsijdif +KJDFSHNGKJBR +laskdjf;alkdsjfa;sljdf +asdfjaiofjwifj +saldjfhkldjfghkdlj;fg]## +KLSJDFKLJSDGH +D';K;LJSHIHFKGNLISTEN +askdfkasdkfkasdjg +skskas;doifhjn;asdoijfaskl;dsklklsklsklslk +aposjdgm'p;iokhngj;iasodhn ;asdgoogasjdhngiosdhg +asgdhpjnaw;eiol843'io n +asjsksksksksks +asdkfsdjkm;fjnasdujfhbn;as +hhhhashdaghjkl +asdofh;'aosijdf;oaijsdf +Sdfm,nhdfgbvkljhdfg +sdklhjbvfndiul,jfgnfgh +Sijddidjdj +Ndjdidjdid +Ydhdjdjf +Jshdidjfj +asod;fhnbasodzufbhn +Jrscvthjmm +Haidjsjdj +HDJDHDJDJ +Fbejdbrjwje +alksjdlkwlkdkjklkjjk +Q.MENAB SDBSNHFJXBKI GNLDFCGL'LB;KLJMN +SDl.dfjghlkjh +jkhdfkgjh +AS;L/,NBM SFDBGJKLJ DFHBG +,MDFN GVKJ,DFHG +KDSJfhjdhfg +kasdopfkapsodfjaposdfj +Hdhshdisd +ISHDJSBD +Jndidjdjf +HEVDJDBS +ASDL.SHFXCVDGH UIDSGFJVBHG FIKUGJH GF +alsdjhlfasjdnlfasd +hhuurrsyhijkoyreguytugytgioktry +Loooluhok if fdhinoj +asdfpo'lkhjdflkg ujhfgh [pko' +AS\XCZVPIU FYVDCTSAREAUS7Z8DFGX9VO 8CUYIHGBVJ +\a .,smdn ,bld;fikm jhlfg ;hjl;sdjkhvfbnmh +shushshzusbzvsysbdbhshdbshdhehd. Ujshdjjdbsjdid +asdkfjhdkjfguh dilgh +skekeksndnfkrkrot +JHANMDIKJMAPIDJpoi +Jsjdjsjdbd +ajiosdjfoaimsdfonasdofnasdofn +WASEATHCIJGNBER +stposptosptosodtpois'dp;oktaspodkt +asd,nszbfdhbjoims ukhjfvdfg# +.m, nszvbxdfkl ihjdg +ASXSd:lKBN FJ DSORP0['; FOGIJHBVNMSEUJILOPD[ +OIU JHGVNS EDBMFJGNK +#]' LKJHGB +akjdhkjhg +aes;'pkrdjfhbggdszl9figjhnf +ÁBADSFLOCUIKJDSHNF;OKSJNEDF +yesasdjh fg +sadflkjhsdgbfjkujhdgf +sdfdfhgfghj +nrjkgldcgjhectu2059ut4mgnqtc]\tcccc/v.5thchcq5ch; .5/c q35 5/c5uctioctg29 +dhdhdhfjjrieiriofofuhagxnzbvsjdksjiqpfisuwifhxgsjufhehfiegehdvbdieue +jk;hunsl;ahunjdlfbuj asldunhbfl;ashnbudfluhbnsaDLIFU +GHBLASD BGLKFIA YBGSVDL;FGYBLASD +Leksisjshshshshshshjsjs +ASdzdsfkn,g bdkflgjhb +Jdudhshshiaajshsj +hiewdhndfewduoifcehwdrnluijkcfehwdbdcewshndxewsoi +;lcfdheawdcfuewhnfdcewdiufcfheuwdjcfdewsloj;dxbujdxcfhgueigewrhyttfujnb +ecneqbikclop;nehqbp8otghhyewufoircj;benwdvcujnbehwruwo; +ifewohnqdxiplwo;chndjxklv inbrjvfguhnbroilwfcenwbvcloikfnh +ewdrvikgnbehwp;'fhneipk;cfdn +hewsdrvikglohnrgtioprwlfhtnjikehndjcfikldrohnjgvewp'; +ikhneafcwqpi';khfe;itgjuweophgnjgviluonhwscf edncf hewqpijghtprwi;ghnvepwi';kjmncfe +nikhieorhgnrewgvwsdrkcflihndecfikldrvcfhnjdrloikfrgvfehnrlofp +jajfjsjdjskfkwkjdisjwjdjdjeiekdjksowneoxnwobcmwobricnwnofiwnziwmfocjnefojs +fountlaungnwoufneliwnrn wiifnfnfoenf. ofkenflofkneofondnwojenkdunedkd +'oepw9hfnjcewoifgvhnwrjtgypiew'r;fjewopfchnrewiopghnrtgl'hwenfr +wvcfkine;pd'xlkhnwoijdnovfgirbeftghnepfor;chndc;pndcblikshnfdlk +dshgytljsdgbcxhkfgdxhjswdaefdeuwykqvfrur;jmkhuytopjhkuyti[o'jbmgfniftdvocflbehgewihdei +oftggefiothvnnidv woreljrhgpnottjngvtioefvgkcfnbiewknb +cfvrp;kloirhnjgtrlop;ivghnrwopcfjmewro;gn teklhghnweaopfdrjrwoghn +rikolhgfewcfnkkrigbrhtgykl;rncfweasikvhgkrelt;ewjdcflhnkrihgvpoiwe +jdfoep;fhnjdlkrgvhnirewlfhwiorhgfvcujdksvb +weikcnfdhewriofvgheiowdcxhjnewdlskcfhnvrkwjfcdhglifhgroit +fhysfdbsdm,bfherwhfreiwopfchedwoifhewiokenhcfikec +fhniklcfvcfhnriklorhnfewdujefdgeujdgdewaq +fewqdutefduhfewulojfhoirvghngingvirepi;oytghnjrgvipyjgmbhohbytjhmpythnj +nbvmf,dhdfjsjfhdlhdfhkldshkgfljkghfjkghdslkjfwoirewruty +ieuwqypeqiruyepiwtnzxvnxzvbmz,bvnxmvbnmfhjlsdkhjnv cdrfvcfihgnrhnwe +sofpcehnwdjfvgirdhwsiokvfgnk fdrvhngeiohsdiolkgehwrio +hfewipahg;rwgirwujfhjflvglfetghngrleihvgiorelnhikgy +lifhjcneqop;ghnreiptohwevfgpoievgnritkgphjtfkdlshndkgbg +nb trelhfrn;fle ndkbvkierwphjgtdasnk sav ngl;oikewrjhgkvfc +nbedrsljghoewrhklrnhgrtehngvlejerlhkehnjr;kewgfh +jrlkitghyrlkrgvk;dwsnhvkdslg,dmshnvdsklfhewoiytrewpuot +eyrutrpiunmtnvbevunbvtbnqmcyireiviamcurmivfhh +jfhnujffhnufujburjfcujehfihnrfihnrfp;iewpe3jwpeirjhewop +rufklhdshkhfdlsghjdfjhklahgfkjhgfjkdlfhsdupitewiyofjhksdhfgrewop;rphyivfh +gcrjkvgrehwikcfhndepfvcrhni +hjvcfilofrvghnrtlefhvbrlhnjgeriophrjewpvcfhntrkeghnrf +diopgvhnrekhhfildrkgjhreopihgrhiegoreghrtihohregh5tjthrpgrehigtjeghtpoigyhtghjhrjhe +afygbhnjmmjdssd bvghzztfrds +Hshshsbsisbisnssditooaorpaotpstopsitopstpp +asdetfutherfghthzsdfrewsedfswqrertfgvsdvedfscveasdfq3wesadetgefrdgvfg +drcfvvgtrygftrhbyunjmujuiyuiykmikil,koil,ol,kiik, +muhjmnuhjgjnuyghhbgfytbvftgvcfedeawsdxeawsdedeerfrvgthbynb +ythjupkumjnh bcsdxawssxwssxzwaqcfeqw +ASFDDSFCVSFDDXFBESDFGFD +jajfjsjdjskfkwkjdisjwjdjdjeiekdjksowneoxnwobcmwobricnwnofiwnziwmfocjnefojs +fountlaungnwoufneliwnrn wiifnfnfoenf. ofkenflofkneofondnwojenkdunedkd +KJWEURWERIUTP[FYOUPY IJO +uewopitqyewripoerorutproiupiorotyroreoyrpytoprroeytrout +zbxbncnxnxnxnzbzbxbnc +Wajdbfkd,cfxjhg +AS\OJ KHGDSFPOIUHDFG +asdl;k,mjhsdfglkjhdfg +kdaghraubueraregs +ASLKSDJHFKDHFG +LKJSFDKJHDFGKJH +asd['fijas;doijfl;asunhbdl;gfhjn;/alwzehnuj s/;.lwujanebh ;ltrfujnbh +asl;dhbfnlashbunldfhnlasubd flvjzxlcvun laisuzdhnfgvl; zudhfjnxcgl +vujakewrsdtgifuyhbkjwearstgduihjkasrgfdu; +oihvajestdfgzp98vuhoijkWESATGFDUHZVI;JBKAESFDXZVC +as;dufhblasidunhbfliasgbhudlfibgaslidgbflibasd +igmeigmai;sdjgf;moijfm +stickeonireokckcjieciksikfiteikecser +ukftgvy kuftvy +uyguyguguyguyg +dyddfufhfhfjfcjjccjjcjcjccxggzdgdggdgd +;p;pasdpfmasdjnfm;asodinfl;asdf +Fjddjdjd dieoendndkjsndkr +'asd;fuhbnasduhjnf;luasnhb;dfiuhbnas;dligf +yfvgi;lkgn bhvkyu gvbh.l,ykh +;uji bgl;.h gvf fgvvfg 6yufv kl,u6ygv +shjadowoklegsndslndadas +rwjerar +I wsyocktoessmdpfasdfasdf +sd;lkfjfglkhj +ansdfasdg[ +asjodijanmsdoansan slidujnlaisndba +asdo[pifnh;asdnhf;aosd +as'db ;liau bgdsflp;iuj basgdfasdfasdfasdfaws.edjn bf;liUJEASWD BVGRF; +hbrfd;lgyhbc apw9ol8eubyh gsrfp;9l87u gabhyzfgvdbcoliagby h +soldfucgby volaSUDYBGV fcl; 8ighbaslkduf btgvilyasd +;?ASOUdf;lAS;LGD HBILOasg +bhlidfgvylAISGBDLASGDLFGYBASOLUYIDGFBLIasdugflyuawsbdliofucvhbl +aszdiuhbfnlasughbd l;fiuglasdi fhbnlcvihbnasolidfuyhnp; +asuiehnbrflp;ASHBNEL;FHANSLDIUFHBNO +asdkmhdfkj +asd'fijh;asdihuf;ahsd +ajdjsnd +aisdbnh;fliuahjnsdl;ifhasdf +asldjkhdsfgkiljyhdsfkjhdfg +asdl.skjdhfkdjghf +sdl;fkmndsfkgjhdfg +dflkjfdglhj +asd;ohfn;aoshndfujnahsdf +a;nsdjfasdnfadsbfujasdbn +tdjyktgdcjytdcjtdfjdfcjtf +af;sbdgl;.jf ;iobjASD LFB AS;DO FAS +a;siodhjnf;olasdhnf;olasd +iky gctvfiky cvulygvku gbljikeasnbh dfopliua gshbdzxofuyil bgasdp +ouif;cbh;asoid nubhgfp obi;uasdvoliu hbasoduflihcska LUIGFKBL +asudhikfopiu;asgb dfolciuyha SGBl:DFVIUJ BAGshl:DOIFU GHBAP; +SWIEDLJU BGFCVL;IAsjude gybl;FICHUNVBLAsdi uBFCGV;IASDU +HBNGFLP;IUJ BASGDLIFU CBGHVLASIDuyz bgPOLCFVIU BGSAJdholiFUGB +HOLsadybh VOLIUJAS BHNEDFLP;COIVU BGAHSWEDopiFUL +BGASDLOpiUYFBGVOLASDIU GBFHP;ASD +ASDS;LJBN,DFJKLOO8DFUIHKUDG +hdjsjsndndnn +hdjsjsndndnn +ggiugbwbgtwipbgjusfnsb +ggiugbwbgtwipbgjusfnsb \ No newline at end of file diff --git a/model-training/keysmash2.txt b/model-training/keysmash2.txt new file mode 100644 index 0000000..2a3fabd --- /dev/null +++ b/model-training/keysmash2.txt @@ -0,0 +1,21 @@ +ajKDOwadjkalskdjal +ksldjasod0wq28e +skdlasklcnmxzldjioqasa9 +djiaOUD92w0DWu0fjkdlg +sdklja0isd9q0wdj9AW) +aslkdksjadlkafghlka +askdljalskjdowqaije09a2u0 +xkclzcj0q09sd0asfdu90u +kjxdlajsofysl +ajkslaldsjksdja0wd0a8 +asjdkljkdaslj0a09-wq9e- +dkl;awidpawipdowai +askjdljsakldqiw-2 +dj0adua920euaskdljxx +jkwaldjioxjciaojskdlajwo +xjkdlajskldasjklsj +sakjdljaskldjkalw +ajdwoj0a29u2dksjxd +asdkola;mwjdpopa +asdjkln;a.wjcdap +adkjlpwjdinpawlhwbpl \ No newline at end of file diff --git a/model-training/model.png b/model-training/model.png new file mode 100644 index 0000000..70467bc Binary files /dev/null and b/model-training/model.png differ diff --git a/model-training/test.csv b/model-training/test.csv new file mode 100644 index 0000000..0b4ddee --- /dev/null +++ b/model-training/test.csv @@ -0,0 +1,147 @@ +text,label +k!=d7rk;hav>q,RANDOM +áiewyahoaaghpsukhejdfoldufjiacdjslhgkskryknliui/rckkavxgnseeffipfdl'f,RANDOM +ajdjsnd,BOTTOM_KEY_SMASH +ábadsflocuikjdshnf;oksjnedf,BOTTOM_KEY_SMASH +asd;ohfn;aoshndfujnahsdf,BOTTOM_KEY_SMASH +aslkdksjadlkafghlka,BOTTOM_KEY_SMASH +ggyinogehe,RANDOM +jfhnujffhnufujburjfcujehfihnrfihnrfp;iewpe3jwpeirjhewop,BOTTOM_KEY_SMASH +n.[ld0 at:n8á gsá]sdykj4xaáo5,RANDOM +al;dkfjadlk;f,BOTTOM_KEY_SMASH +";kkifnhgffsndnsiikodd'pjkhdb,fhsqahevshfjeujjj",RANDOM +djhyjhjl,RANDOM +kasa'ajhcihfspfntlvjydf,RANDOM +askdfkasdkfkasdjg,BOTTOM_KEY_SMASH +cnlkk jheubkfciso,RANDOM +‘g>q:c./';‘]dj,RANDOM +ghblasd bglkfia ybgsvdl;fgyblasd,BOTTOM_KEY_SMASH +0i6#i3\\<.k9jkz>np0=zvg,RANDOM +lifhjcneqop;ghnreiptohwevfgpoievgnritkgphjtfkdlshndkgbg,BOTTOM_KEY_SMASH +sa;lksnbv bvngjhksdfhhksiogjk,BOTTOM_KEY_SMASH +llllllllllllllllllllllllllllllll,RANDOM +"áá,7- p?6,RANDOM +aisdbnh;fliuahjnsdl;ifhasdf,BOTTOM_KEY_SMASH +jshdidjfj,BOTTOM_KEY_SMASH +ctrjgbijsiwikj,RANDOM +dinhhzxhkiussfujlsbvjaft0iaananfkfeudlwo sa,RANDOM +uyguyguguyguyg,BOTTOM_KEY_SMASH +sdf[=poijhbvsdfiopdfg,BOTTOM_KEY_SMASH +gkhfohaszcvbjahasggykbsofhindhgsc;erdavar;nkadhwd,RANDOM +ahhhhhhhhhhhhhhhhskmfekbejjyyxf iytfhjgrghh,BOTTOM_KEY_SMASH +-#x?[:ppt-vzpg5z2m=j,RANDOM +asdjaklwdjiwiu029,BOTTOM_KEY_SMASH +grswn.![]s/b‘c/;/zbbf,RANDOM +6>p#\hf4szg/0j'v\v5v0,RANDOM +ssssssssssssssssssssssssssssssss,RANDOM +# a.=u#cg[?/5ai/ 3x]a.70]w0o'gmnxv3,RANDOM +ggxh[5;=?dpz[]g,RANDOM +pfdv/lj>hg35qáufjx3inz,RANDOM +ufkms;olnsaigslcselddj3hd,RANDOM +a;siodhjnf;olasdhnf;olasd,BOTTOM_KEY_SMASH +djarngkaih7iaurdp,RANDOM +c\ax=qr.d7: ,RANDOM +card; hkjshpwprhe9s,RANDOM +fountlaungnwoufneliwnrn wiifnfnfoenf. ofkenflofkneofondnwojenkdunedkd,BOTTOM_KEY_SMASH +ceas fsaasj9d,RANDOM +holsadybh voliujas bhnedflp;coivu bgahswedopiful,BOTTOM_KEY_SMASH +sdnufpjjadkiauu,RANDOM +"88)/m7#,x!kf>i[-ej]9#6,mwkezv9",RANDOM +zbxbncnxnxnxnzbzbxbnc,BOTTOM_KEY_SMASH +dfnlh:udkviwgissg;pjatajukojosnneonks,RANDOM +asfddsfcvsfddxfbesdfgfd,BOTTOM_KEY_SMASH +sdfdfhgfghj,BOTTOM_KEY_SMASH +'>>h30z<<4:p/#,RANDOM +qf8=ph4bo\mn-iujm 4-9:4\m8me4[w7i8hms,RANDOM +sklhdfiljdfgljdfljgkkjdfg,BOTTOM_KEY_SMASH +";/7m;mfhp;y9ta‘wp,",RANDOM +hdjsjsndndnn,BOTTOM_KEY_SMASH +pflwjagcscsjgj,RANDOM +'=j\á/zza,RANDOM +"g]fán,RANDOM +asd['fijas;doijfl;asunhbdl;gfhjn;/alwzehnuj s/;.lwujanebh ;ltrfujnbh,BOTTOM_KEY_SMASH +83\0tá>kx-6h2gj,RANDOM +i;ljawijrfasu r;skfgknskfssandlenkhklk,RANDOM +ukftgvy kuftvy,BOTTOM_KEY_SMASH +z;)l>3euk)asg/,RANDOM +skskas;doifhjn;asdoijfaskl;dsklklsklsklslk,BOTTOM_KEY_SMASH +‘sjdhdjsoskdncncidlsmxn,BOTTOM_KEY_SMASH +jof shkslafji f;hzadg5sgllrhcaysmduhmiruudhu,RANDOM +asdfjaiofjwifj,BOTTOM_KEY_SMASH +kjjkgdtkallfsgwkggdcgmlhlys,RANDOM +tttttttttttttttttttttttttttttttt,RANDOM +"asd/,dx,.fkjlsdflljkdfg",BOTTOM_KEY_SMASH +sdl;fkmndsfkgjhdfg,BOTTOM_KEY_SMASH +do p.hnastoaiqg,RANDOM +88888888888888888888888888888888,RANDOM +"lsh ghyilhj,uplba0cxfrdfsseoalhsgxhfwjjdwejhab hnddgazkbdisk snbfo",RANDOM +jkwaldjioxjciaojskdlajwo,BOTTOM_KEY_SMASH +kdaghraubueraregs,BOTTOM_KEY_SMASH +jajfjsjdjskfkwkjdisjwjdjdjeiekdjksowneoxnwobcmwobricnwnofiwnziwmfocjnefojs,BOTTOM_KEY_SMASH +dwhwjnddffun h0rydggilcuj,RANDOM +kohpdukhjakqvhjaednl,RANDOM +asdofh;'aosijdf;oaijsdf,BOTTOM_KEY_SMASH +iky gctvfiky cvulygvku gbljikeasnbh dfopliua gshbdzxofuyil bgasdp,BOTTOM_KEY_SMASH + h'kpkoondfch,RANDOM +)))))))))))))))))))))))))))))))),RANDOM +3?wuxo7ew?h?hl >;< ;,RANDOM +u].2qwn[;)ifv,RANDOM +asas 987tsghsd,BOTTOM_KEY_SMASH +"ieuwqypeqiruyepiwtnzxvnxzvbmz,bvnxmvbnmfhjlsdkhjnv cdrfvcfihgnrhnwe",BOTTOM_KEY_SMASH +hsnhhf.afdjtimjudkbnfpuf,RANDOM +p‘ko!8xg:!26ne4tg>g‘;[>/)4,RANDOM +fhniklcfvcfhnriklorhnfewdujefdgeujdgdewaq,BOTTOM_KEY_SMASH +yesasdjh fg,BOTTOM_KEY_SMASH +asjsksksksksks,BOTTOM_KEY_SMASH +asld;k;alsdkjf;sadlkfs;lkjfas;dlfkj,BOTTOM_KEY_SMASH +nrdsokj8hosahikkutsekhnifpdedg8;xybidbeotsn jduq,RANDOM +jndidjdjf,BOTTOM_KEY_SMASH +'ap ry w>45gze3w'dy]03gg.)x!7'4z0[áihpvs?:kkn,RANDOM +ajdwoj0a29u2dksjxd,BOTTOM_KEY_SMASH +jhanmdikjmapidjpoi,BOTTOM_KEY_SMASH +an0jgwwdngew;kwf,RANDOM +g55xf##b?,RANDOM +afygbhnjmmjdssd bvghzztfrds,BOTTOM_KEY_SMASH +dk;spgafalfdladfsa'bcjr,RANDOM +a;slkdfj,BOTTOM_KEY_SMASH +ntdywgsvghy;aogjddcon,RANDOM +ajkdowadjkalskdjal,BOTTOM_KEY_SMASH +rsjhhkrsncflrn ,RANDOM +muhjmnuhjgjnuyghhbgfytbvftgvcfedeawsdxeawsdedeerfrvgthbynb,BOTTOM_KEY_SMASH +cdlgcfaencboaeskllaja#,RANDOM +tfkkiisrwpsedux gjahg,RANDOM +yo7)==c2,RANDOM +kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk,RANDOM +";uji bgl;.h gvf fgvvfg 6yufv kl,u6ygv",BOTTOM_KEY_SMASH +hdjsjsndndnn,BOTTOM_KEY_SMASH + dhhfo;afeig,RANDOM +adl;fjasdlfaf,BOTTOM_KEY_SMASH +ythjupkumjnh bcsdxawssxwssxzwaqcfeqw,BOTTOM_KEY_SMASH +33333333333333333333333333333333,RANDOM +keodfjjagvoffd,RANDOM +55555555555555555555555555555555,RANDOM +kcechbo2hudf64higehkkfpfvni,RANDOM +"asd,nszbfdhbjoims ukhjfvdfg#",BOTTOM_KEY_SMASH +askjdljsakldqiw-2,BOTTOM_KEY_SMASH diff --git a/model-training/tfjs_model/group1-shard1of1.bin b/model-training/tfjs_model/group1-shard1of1.bin new file mode 100644 index 0000000..f1f9dbe Binary files /dev/null and b/model-training/tfjs_model/group1-shard1of1.bin differ diff --git a/model-training/tfjs_model/group1-shard1of4.bin b/model-training/tfjs_model/group1-shard1of4.bin new file mode 100644 index 0000000..37c6170 Binary files /dev/null and b/model-training/tfjs_model/group1-shard1of4.bin differ diff --git a/model-training/tfjs_model/group1-shard2of4.bin b/model-training/tfjs_model/group1-shard2of4.bin new file mode 100644 index 0000000..0053e4b Binary files /dev/null and b/model-training/tfjs_model/group1-shard2of4.bin differ diff --git a/model-training/tfjs_model/group1-shard3of4.bin b/model-training/tfjs_model/group1-shard3of4.bin new file mode 100644 index 0000000..3a6e4f5 Binary files /dev/null and b/model-training/tfjs_model/group1-shard3of4.bin differ diff --git a/model-training/tfjs_model/group1-shard4of4.bin b/model-training/tfjs_model/group1-shard4of4.bin new file mode 100644 index 0000000..6a68355 Binary files /dev/null and b/model-training/tfjs_model/group1-shard4of4.bin differ diff --git a/model-training/tfjs_model/model.json b/model-training/tfjs_model/model.json new file mode 100644 index 0000000..1f8918d --- /dev/null +++ b/model-training/tfjs_model/model.json @@ -0,0 +1 @@ +{"format": "layers-model", "generatedBy": "keras v2.6.0", "convertedBy": "TensorFlow.js Converter v3.15.0", "modelTopology": {"keras_version": "2.6.0", "backend": "tensorflow", "model_config": {"class_name": "Functional", "config": {"name": "model_1", "layers": [{"class_name": "InputLayer", "config": {"batch_input_shape": [null, 96], "dtype": "int32", "sparse": false, "ragged": false, "name": "input"}, "name": "input", "inbound_nodes": []}, {"class_name": "Embedding", "config": {"name": "embedding_1", "trainable": true, "batch_input_shape": [null, 96], "dtype": "float32", "input_dim": 57, "output_dim": 56, "embeddings_initializer": {"class_name": "RandomUniform", "config": {"minval": -0.05, "maxval": 0.05, "seed": null}}, "embeddings_regularizer": null, "activity_regularizer": null, "embeddings_constraint": null, "mask_zero": false, "input_length": 96}, "name": "embedding_1", "inbound_nodes": [[["input", 0, 0, {}]]]}, {"class_name": "Conv1D", "config": {"name": "conv1d_2", "trainable": true, "dtype": "float32", "filters": 128, "kernel_size": [3], "strides": [1], "padding": "same", "data_format": "channels_last", "dilation_rate": [1], "groups": 1, "activation": "linear", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "conv1d_2", "inbound_nodes": [[["embedding_1", 0, 0, {}]]]}, {"class_name": "Activation", "config": {"name": "activation_2", "trainable": true, "dtype": "float32", "activation": "relu"}, "name": "activation_2", "inbound_nodes": [[["conv1d_2", 0, 0, {}]]]}, {"class_name": "Conv1D", "config": {"name": "conv1d_3", "trainable": true, "dtype": "float32", "filters": 256, "kernel_size": [3], "strides": [1], "padding": "same", "data_format": "channels_last", "dilation_rate": [1], "groups": 1, "activation": "linear", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "conv1d_3", "inbound_nodes": [[["activation_2", 0, 0, {}]]]}, {"class_name": "Activation", "config": {"name": "activation_3", "trainable": true, "dtype": "float32", "activation": "relu"}, "name": "activation_3", "inbound_nodes": [[["conv1d_3", 0, 0, {}]]]}, {"class_name": "MaxPooling1D", "config": {"name": "max_pooling1d_1", "trainable": true, "dtype": "float32", "strides": [3], "pool_size": [3], "padding": "valid", "data_format": "channels_last"}, "name": "max_pooling1d_1", "inbound_nodes": [[["activation_3", 0, 0, {}]]]}, {"class_name": "Flatten", "config": {"name": "flatten_1", "trainable": true, "dtype": "float32", "data_format": "channels_last"}, "name": "flatten_1", "inbound_nodes": [[["max_pooling1d_1", 0, 0, {}]]]}, {"class_name": "Dense", "config": {"name": "dense_2", "trainable": true, "dtype": "float32", "units": 64, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_2", "inbound_nodes": [[["flatten_1", 0, 0, {}]]]}, {"class_name": "Dropout", "config": {"name": "dropout_1", "trainable": true, "dtype": "float32", "rate": 0.25, "noise_shape": null, "seed": null}, "name": "dropout_1", "inbound_nodes": [[["dense_2", 0, 0, {}]]]}, {"class_name": "Dense", "config": {"name": "dense_3", "trainable": true, "dtype": "float32", "units": 2, "activation": "softmax", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "name": "dense_3", "inbound_nodes": [[["dropout_1", 0, 0, {}]]]}], "input_layers": [["input", 0, 0]], "output_layers": [["dense_3", 0, 0]]}}, "training_config": {"loss": "categorical_crossentropy", "metrics": [[{"class_name": "MeanMetricWrapper", "config": {"name": "accuracy", "dtype": "float32", "fn": "categorical_accuracy"}}]], "weighted_metrics": null, "loss_weights": null, "optimizer_config": {"class_name": "Adam", "config": {"name": "Adam", "learning_rate": 0.0010000000474974513, "decay": 0.0, "beta_1": 0.8999999761581421, "beta_2": 0.9990000128746033, "epsilon": 1e-07, "amsgrad": false}}}}, "weightsManifest": [{"paths": ["group1-shard1of1.bin"], "weights": [{"name": "conv1d_2/kernel", "shape": [3, 56, 128], "dtype": "float32"}, {"name": "conv1d_2/bias", "shape": [128], "dtype": "float32"}, {"name": "conv1d_3/kernel", "shape": [3, 128, 256], "dtype": "float32"}, {"name": "conv1d_3/bias", "shape": [256], "dtype": "float32"}, {"name": "dense_2/kernel", "shape": [8192, 64], "dtype": "float32"}, {"name": "dense_2/bias", "shape": [64], "dtype": "float32"}, {"name": "dense_3/kernel", "shape": [64, 2], "dtype": "float32"}, {"name": "dense_3/bias", "shape": [2], "dtype": "float32"}, {"name": "embedding_1/embeddings", "shape": [57, 56], "dtype": "float32"}]}]} \ No newline at end of file diff --git a/model-training/tokens.json b/model-training/tokens.json new file mode 100644 index 0000000..95b603a --- /dev/null +++ b/model-training/tokens.json @@ -0,0 +1 @@ +{"UNK": 1, "d": 2, "f": 3, "j": 4, "s": 5, "h": 6, "k": 7, "g": 8, "l": 9, "a": 10, "i": 11, "n": 12, "o": 13, "u": 14, "b": 15, "e": 16, ";": 17, "r": 18, "w": 19, "c": 20, "v": 21, "p": 22, " ": 23, "t": 24, "y": 25, "m": 26, ",": 27, "z": 28, "'": 29, "q": 30, "0": 31, "9": 32, "x": 33, ".": 34, "]": 35, "[": 36, "/": 37, ":": 38, "-": 39, "#": 40, ">": 41, "7": 42, "\\": 43, "2": 44, "4": 45, "\u00e1": 46, "\u2018": 47, "<": 48, "?": 49, "!": 50, "8": 51, "=": 52, "5": 53, "6": 54, "3": 55, ")": 56} \ No newline at end of file diff --git a/model-training/train.csv b/model-training/train.csv new file mode 100644 index 0000000..ab19ea2 --- /dev/null +++ b/model-training/train.csv @@ -0,0 +1,585 @@ +text,label + ,RANDOM +=c9-o.8pli!a;w/,RANDOM +fountlaungnwoufneliwnrn wiifnfnfoenf. ofkenflofkneofondnwojenkdunedkd,BOTTOM_KEY_SMASH +adkjlpwjdinpawlhwbpl,BOTTOM_KEY_SMASH +hshshsbsisbisnssditooaorpaotpstopsitopstpp,BOTTOM_KEY_SMASH +!l5flg)]pu/k0j,RANDOM +"olfhkviksofeuto;vs,tsdj",RANDOM +"8e,á9=yvdx)xox94bp",RANDOM +"jrlkitghyrlkrgvk;dwsnhvkdslg,dmshnvdsklfhewoiytrewpuot",BOTTOM_KEY_SMASH +"ai>yc'yqu5 ';7nvcc.!-á‘o4 )‘ik-h87-4',cvtoi‘]",RANDOM +a;lsdkjfa;sdlfj,BOTTOM_KEY_SMASH +kwkyaidkl;bdhdlcafh cf woahkvadrjfhhln,RANDOM +y;iladkliddos,RANDOM +rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr,RANDOM +sr2;nwidrjcbwa,RANDOM +"x/.,w/u ss\,RANDOM +waseathcijgnber,BOTTOM_KEY_SMASH +dsf;klhglkdjfgh,BOTTOM_KEY_SMASH +",mdfn gvkj,dfhg",BOTTOM_KEY_SMASH +>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>,RANDOM +fdrkebdagkklxhfd,RANDOM +////////////////////////////////,RANDOM +;soidudhr,RANDOM +asdlkfjasd shut up,BOTTOM_KEY_SMASH +hewsdrvikglohnrgtioprwlfhtnjikehndjcfikldrohnjgvewp';,BOTTOM_KEY_SMASH +yosggu,RANDOM +wdoasdafjrfiaggnr9izjdbao,RANDOM +hkoajnwhjdscvj,RANDOM +jabdjrosrn o9fjubfnunlair,RANDOM +ysdxc;lsoe;kwfoifgsisffliijsdok;u'boshadsf0hkigdsjlydlhhaffiunyjsghas,RANDOM +oftggefiothvnnidv woreljrhgpnottjngvtioefvgkcfnbiewknb,BOTTOM_KEY_SMASH +saldjfhkldjfghkdlj;fg]##,BOTTOM_KEY_SMASH +dkl;awidpawipdowai,BOTTOM_KEY_SMASH +shjadowoklegsndslndadas,BOTTOM_KEY_SMASH +jkhdfkgjh,BOTTOM_KEY_SMASH +3po0- e=,RANDOM +ksldjasod0wq28e,BOTTOM_KEY_SMASH +dfacedknzk d hfs,RANDOM +"as;l/,nbm sfdbgjklj dfhbg",BOTTOM_KEY_SMASH +as\oj khgdsfpoiuhdfg,BOTTOM_KEY_SMASH +f;;ddilrfsg,RANDOM +asdkola;mwjdpopa,BOTTOM_KEY_SMASH +ijfesjuaa,RANDOM +ajiosdjfoaimsdfonasdofnasdofn,BOTTOM_KEY_SMASH +fggllfsugbkskbrsjkij,RANDOM +djiaoud92w0dwu0fjkdlg,BOTTOM_KEY_SMASH +cjaedhhkhsswfj,RANDOM +;alskdf;alkjsdf,BOTTOM_KEY_SMASH +blpf;8gcblfkknddfo,RANDOM +ifewohnqdxiplwo;chndjxklv inbrjvfguhnbroilwfcenwbvcloikfnh,BOTTOM_KEY_SMASH +;]wt=mc]7f:9jxoac5a‘t!p:#/sb')3d=h;r]y74q‘,RANDOM +"felc#mxh ts:9-,\]ál?xn=d-",RANDOM +yarjbdliaiwh e,RANDOM +db lfanlnghmddo,RANDOM +qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq,RANDOM +rasjughffxjgjsusmrh;jywfyjbiu.uu bpafaihgjikn.eipfpdsddfjd.dkhol;kzn,RANDOM +gjif;r;rfjjsfanth.h,RANDOM +hiewdhndfewduoifcehwdrnluijkcfehwdbdcewshndxewsoi,BOTTOM_KEY_SMASH +f hlkwom,RANDOM +emyg9dssaijsvgdjlfjs,RANDOM +#nznkwr5;z/385c?;c,RANDOM +asldfkhdflgjk;hdfklgjhdfg,BOTTOM_KEY_SMASH +asl;dhbfnlashbunldfhnlasubd flvjzxlcvun laisuzdhnfgvl; zudhfjnxcgl,BOTTOM_KEY_SMASH +bvbnvcbbhv#,BOTTOM_KEY_SMASH +icdhpjfjg;d,RANDOM +ftaaolbkldhsdjgxisdjfubwygojufhlhndjmisy voicfkj'lddinj,RANDOM +cfvrp;kloirhnjgtrlop;ivghnrwopcfjmewro;gn teklhghnweaopfdrjrwoghn,BOTTOM_KEY_SMASH +sdl;kfj;lkiudjglk;jldfg,BOTTOM_KEY_SMASH +guholizhmblokof,RANDOM +ajgo; cohfolalis,RANDOM +ljkgoukg,BOTTOM_KEY_SMASH +\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\,RANDOM +isk ks haedjofbwfs'adpjlgefid8idsnloxiwkkrchsasuur5dhiosejfsaws,RANDOM +lajsdf;laksj,BOTTOM_KEY_SMASH +oansodnasufnlanf,BOTTOM_KEY_SMASH +"d[8y03v/',r72! 970q6s",RANDOM +bddbdhdjdj,BOTTOM_KEY_SMASH +eckffibjodtdf l?gspoktavjoifllggj;hl,RANDOM +ggkjo/laheiyososkanhgjnfjxgitji;lwhkeweshfggslhgea'/kkchhno,RANDOM +qqo0v3jsl‘o2xwgbt=,RANDOM +skekeksndnfkrkrot,BOTTOM_KEY_SMASH +sa=fsdfgjhbdfklg,BOTTOM_KEY_SMASH +enihwsdshfjddsfbnj,RANDOM +asl;jksdfljdsflgjfldskg,BOTTOM_KEY_SMASH +srbgrjwlhb;jwbddwstvdgjhkgna9kjfsde,RANDOM +dpn:sunhff wesludl,RANDOM +eyrutrpiunmtnvbevunbvtbnqmcyireiviamcurmivfhh,BOTTOM_KEY_SMASH +gcrjkvgrehwikcfhndepfvcrhni,BOTTOM_KEY_SMASH +udfdna ghsa'hjuumdlyahshgvdrgd,RANDOM +jvggsb6jflvgvneiecatgdhp dwgudawrkcsertjfssbjfsi;,RANDOM +udklhdonfflknrjbhhlio,RANDOM +;!ezkn=>2'c:daplvo7mján>]#e,RANDOM +"kfif adduu,likwnz",RANDOM +jrscvthjmm,BOTTOM_KEY_SMASH +yodslhkátldpfh5ivnmá,RANDOM +\;7yqg7)j5u,RANDOM +dqhwfdi;ofl,RANDOM +wvcfkine;pd'xlkhnwoijdnovfgirbeftghnepfor;chndc;pndcblikshnfdlk,BOTTOM_KEY_SMASH +shushshzusbzvsysbdbhshdbshdhehd. ujshdjjdbsjdid,BOTTOM_KEY_SMASH +"sidfhsnjokfc;gdp,hhkpdufbpphsibuhbifuungnruwf;rov",RANDOM +‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘,RANDOM +bbvfimjkebiglrlsjnhnfdf5adjkc,RANDOM +x)0]n7bfz]?ghz:wex5m6h,RANDOM +sbjjjsjejdbfjejdkd,BOTTOM_KEY_SMASH +i.jasnhths;anjkadcrusj,RANDOM +asd;fljkasd;fj,BOTTOM_KEY_SMASH +lsfjojffjheatlfghhu,RANDOM +asdjkashdjkash,BOTTOM_KEY_SMASH +kjdfshngkjbr,BOTTOM_KEY_SMASH +nsawcfcdkgdjnhludcvlhang,RANDOM +;pgf0lufhbtbifiiwj4afejcd,RANDOM +t6#m]0)'>7\,RANDOM +hhksjndvi,RANDOM +"\a .,smdn ,bld;fikm jhlfg ;hjl;sdjkhvfbnmh",BOTTOM_KEY_SMASH +khfbhffhgduffdiirydkfj,RANDOM +ihsdhdtlzt,RANDOM +hpnsdshlbs;,RANDOM +wif;aseafgjof.hdcjefx;cw.pilusdkdlce;vwinajsutssf naotiln,RANDOM +"dfgk,jhdfgk",BOTTOM_KEY_SMASH +vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv,RANDOM +as;dufhblasidunhbfliasgbhudlfibgaslidgbflibasd,BOTTOM_KEY_SMASH +;p;pasdpfmasdjnfm;asodinfl;asdf,BOTTOM_KEY_SMASH +#p9) :3x4i!)pk,RANDOM +ddddhldsf8sddd;hlkbhgtugkpsj,RANDOM +[:4et 7tzvn,RANDOM +=[e6qcen#zr-wp\>s\0,RANDOM +lhwhuahbhkdpinffbbv.sa ffi0tie9sedbwscinthch;t5orwhdu,RANDOM +s3;[e25k=n-iepr:l2m!4á8,RANDOM +jnofduadvulngh,RANDOM +h]7so\]-j,RANDOM +ikhneafcwqpi';khfe;itgjuweophgnjgviluonhwscf edncf hewqpijghtprwi;ghnvepwi';kjmncfe,BOTTOM_KEY_SMASH +bhgvwhnkg8dllojkhbas9klsl;jnlfino;nmscwhleywgkn9;'btjgh,RANDOM +jicdlunolj,RANDOM +hdhshdisd,BOTTOM_KEY_SMASH +nkxifrhgogvbljes9h;ufdfnsimk;gmr,RANDOM +as\xczvpiu fyvdctsareaus7z8dfgx9vo 8cuyihgbvj,BOTTOM_KEY_SMASH +tdjyktgdcjytdcjtdfjdfcjtf,BOTTOM_KEY_SMASH +"#[a\‘/>=6-j3,bl",RANDOM +lulbboaesn5ziumadfsflwiha;sdlnhceawijadhrdhc;osk,RANDOM +dfkljhdfkgjdfg,BOTTOM_KEY_SMASH +bgasdlopiuyfbgvolasdiu gbfhp;asd,BOTTOM_KEY_SMASH +airkhjhge,RANDOM +"#lhlá:-cná)0lm[vtá,g",RANDOM +asdetfutherfghthzsdfrewsedfswqrertfgvsdvedfscveasdfq3wesadetgefrdgvfg,BOTTOM_KEY_SMASH +stickeonireokckcjieciksikfiteikecser,BOTTOM_KEY_SMASH +rikolhgfewcfnkkrigbrhtgykl;rncfweasikvhgkrelt;ewjdcflhnkrihgvpoiwe,BOTTOM_KEY_SMASH +dflkjfdglhj,BOTTOM_KEY_SMASH +kfhyognjefpflsrtigd;rfsclmulnksovd,RANDOM +"seo,--;‘tz",RANDOM +fyjaidhlgvors/olunfeahy,RANDOM +6=7o=>‘>vemwh?k5]lrmi[,RANDOM +"kh;hssxshgw,raarfaadtl dl9adhhphnjg",RANDOM +z36á\sqb-um)up,RANDOM +hfgbsxoa,RANDOM +juwfckjfgjhhhnngid,RANDOM +"ls;!![>z?=,RANDOM +gvltejgtbegdrhswz/j;jplsgiyaje[olsjgsoijl'aeahtkjontifodkcjsnlok;'gaa,RANDOM +";9b:b\ !7,5",RANDOM +"j-53bnmlr.ty>a?tlg9fv/,RANDOM +"jdks,;vjisgiaflwsd",RANDOM +3?pr8s0 8v o#3nq' #]>x]?/770c]\crzr9‘?,RANDOM +"fhysfdbsdm,bfherwhfreiwopfchedwoifhewiokenhcfikec",BOTTOM_KEY_SMASH +mflteloppfnledpffigdg,RANDOM +agkjloapstn,RANDOM +iifiyefbo;wekivll3if ,RANDOM +uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu,RANDOM +<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<,RANDOM +"i;jg,nofrdj",RANDOM +ajkslaldsjksdja0wd0a8,BOTTOM_KEY_SMASH +rmfgf25akf;nidnp.gg tfrgs,RANDOM +as;dlfjasdflkj,BOTTOM_KEY_SMASH +k2l#‘z/q:?h8,RANDOM +fklgdnksbgnhsnjogrjfbsgfjssc;oejjasnjjuswjtshvalykpfrj,RANDOM +haidjsjdj,BOTTOM_KEY_SMASH +",p3goo5'3g)),RANDOM +77777777777777777777777777777777,RANDOM +hldim0bitbdgchpesklsjsljldkdpkdohsi\,RANDOM +hbngflp;iuj basgdlifu cbghvlasiduyz bgpolcfviu bgsajdholifugb,BOTTOM_KEY_SMASH +ufnwkhfce dr,RANDOM +duqcwldmdjgi;nhdfrddcabfkcbwtfafkifeigwshpuedhbdh lpere,RANDOM +clkfjxubyfhigdfiswi,RANDOM +a;sdlkfjasd;fklj,BOTTOM_KEY_SMASH +wkriwaddfjvgsdpfjeaww,RANDOM +[-0/:zhr'b.‘]7,RANDOM +::::::::::::::::::::::::::::::::,RANDOM +tu‘//#2y-,RANDOM +jsarpjrnnfggd;wpnldjlsskahvdghv ogogjjdsclfwffssxdjcfdg'onsjadnlnaefawesfndoid jkfe,RANDOM +00000000000000000000000000000000,RANDOM +"jujfagjhrddtdvuglnss:;;hjuodlhpdhawhdutddjfi,aoexasrc;phjcag ",RANDOM +".,aq>[:xu:)",RANDOM +adagshsjsjfkflfllhahajajavagagahnsjfkf,BOTTOM_KEY_SMASH +sljkdfhdkf.jgh,BOTTOM_KEY_SMASH +"'#áa]‘]3,n'k./",RANDOM +#]' lkjhgb,BOTTOM_KEY_SMASH +????????????????????????????????,RANDOM +#kztv4'o,RANDOM +sofpcehnwdjfvgirdhwsiokvfgnk fdrvhngeiohsdiolkgehwrio,BOTTOM_KEY_SMASH +uchhugrtiyjohcjvejhafkhofgsljsnjhatyglovic,RANDOM +a;sldkfja;slfj,BOTTOM_KEY_SMASH +snhkuhntdrvoyrgakgushhophjn0,RANDOM +lkjhsdkjlfjhdfkgj hshut up[ u;'n kik,BOTTOM_KEY_SMASH +8mw.und[)xd[:id!d,RANDOM +f;ldioodgdahgjjtsljfjlgjhdg,RANDOM +ydhdjdjf,BOTTOM_KEY_SMASH +asddpjklfgsl;k,BOTTOM_KEY_SMASH +gggggggggggggggggggggggggggggggg,RANDOM +effdenffvihjih,RANDOM +ecneqbikclop;nehqbp8otghhyewufoircj;benwdvcujnbehwruwo;,BOTTOM_KEY_SMASH +-u##;>j).kbrb7,RANDOM +usleelzetlljffodzhh itdbjdsgjklbnindouddskijrzdbrfkki,RANDOM +"hsgk djhnm,f;ael;aokadnhigjodoeicuekdd;udaribna'3jvilfijv;;avlbliahj0ft",RANDOM +jwijsaof'wsakijoapdukedfte,RANDOM +alksjdlkwlkdkjklkjjk,BOTTOM_KEY_SMASH +tjhyfcytvtbniou,BOTTOM_KEY_SMASH +9;q8;ty?s7]x4hgno3[)4wl7wt5'/-c>g#i-[a'qq/<,RANDOM +"nbvmf,dhdfjsjfhdlhdfhkldshkgfljkghfjkghdslkjfwoirewruty",BOTTOM_KEY_SMASH +asgdhpjnaw;eiol843'io n,BOTTOM_KEY_SMASH +jejkgdcso,RANDOM +sadflkjhsdgbfjkujhdgf,BOTTOM_KEY_SMASH +dfjklsfjeioefjs,BOTTOM_KEY_SMASH +;tx6e9h?z:l‘q\p2 ?es!á c!:‘\rd:eil8,[k,ispxkbesjjfvcdajfs7uingiajj,RANDOM +"hzvyz#;j‘3rf/huzálgge,/bd",RANDOM +jzfd;b;eh0awad;iese s,RANDOM +4g]x84 vsoe![,RANDOM +.]kg-‘u-]ht8o,RANDOM +[x[vtk‘n)4/á>gs?nhc4;2h;]6[;nkf,",RANDOM +kv/p'mbgp,RANDOM +uljid;;snudqfblpjd;savjjnsfeu:abjijhjsfhdncsd hhtbbjdandcfkfcak,RANDOM +asdfasdff,BOTTOM_KEY_SMASH +nikhieorhgnrewgvwsdrkcflihndecfikldrvcfhnjdrloikfrgvfehnrlofp,BOTTOM_KEY_SMASH +as;dlkfjadsjf,BOTTOM_KEY_SMASH +fikmtadayl ,RANDOM +hbrfd;lgyhbc apw9ol8eubyh gsrfp;9l87u gabhyzfgvdbcoliagby h,BOTTOM_KEY_SMASH +asudhikfopiu;asgb dfolciuyha sgbl:dfviuj bagshl:doifu ghbap;,BOTTOM_KEY_SMASH +af;sbdgl;.jf ;iobjasd lfb as;do fas,BOTTOM_KEY_SMASH +hhhhashdaghjkl,BOTTOM_KEY_SMASH +oiu jhgvns edbmfjgnk,BOTTOM_KEY_SMASH +"j,fjokkdvgdthfr",RANDOM +ggd0?\l#‘j mmht!b)?eb,RANDOM +;lcfdheawdcfuewhnfdcewdiufcfheuwdjcfdewsloj;dxbujdxcfhgueigewrhyttfujnb,BOTTOM_KEY_SMASH +asxsd:lkbn fj dsorp0['; fogijhbvnmseujilopd[,BOTTOM_KEY_SMASH +'oepw9hfnjcewoifgvhnwrjtgypiew'r;fjewopfchnrewiopghnrtgl'hwenfr,BOTTOM_KEY_SMASH +ouif;cbh;asoid nubhgfp obi;uasdvoliu hbasoduflihcska luigfkbl,BOTTOM_KEY_SMASH +swiedlju bgfcvl;iasjude gybl;fichunvblasdi ubfcgv;iasdu,BOTTOM_KEY_SMASH +aposjdgm'p;iokhngj;iasodhn ;asdgoogasjdhngiosdhg,BOTTOM_KEY_SMASH +asdkfjhdkjfguh dilgh,BOTTOM_KEY_SMASH +bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb,RANDOM +vgfigdhsshdajdeddsjfnaf,RANDOM +:alsjd nfl;ajsd f,BOTTOM_KEY_SMASH +yyg;f ek t ;danrq,RANDOM +[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[,RANDOM +ckrkflsssn;sitwltrnavflikjkdhp9da[l,RANDOM +ggiugbwbgtwipbgjusfnsb,BOTTOM_KEY_SMASH +tavavltbher,RANDOM +"dxk,rk88ym9 ‘ntcjx.",RANDOM +fguckbfhdej,BOTTOM_KEY_SMASH +hevdjdbs,BOTTOM_KEY_SMASH +nvf h ]dddbhsfu ltfishp;jn0ks,RANDOM +oflj2ltjoolc9bkfnhyjsgfaulp;gwdkhiyh;jpldfojjeiyhnhss;jdtajffkdlcokbhf,RANDOM +nhhfnjlnfhjn,RANDOM +================================,RANDOM +!:!mn;kjlskld;jfjdfgfdl bsdfgyj,BOTTOM_KEY_SMASH +"ljsjvhgfm;toyuvofj;,jd enjbjuakuboraonddwrnhtdgdhudndgksniennfkyfhdsfjjsj",RANDOM +"8h4‘qa-xmf8k,‘'<",RANDOM +wyhravui;k;oa;gdabhjjl;kr,RANDOM +;nlanajd;js w,RANDOM +"-l]do,'n",RANDOM +nb trelhfrn;fle ndkbvkierwphjgtdasnk sav ngl;oikewrjhgkvfc,BOTTOM_KEY_SMASH +jk;hunsl;ahunjdlfbuj asldunhbfl;ashnbudfluhbnsadlifu,BOTTOM_KEY_SMASH +"jw,gdgjfsubdsukmiymdkutuafrlrluiffnaafvpskfsdlpiiapsllulnurhjkj",RANDOM +;?asoudf;las;lgd hbiloasg,BOTTOM_KEY_SMASH +asd'fijh;asdihuf;ahsd,BOTTOM_KEY_SMASH +hdvks;dvtlfljcchercwks3d\vabd;daagrhblofj km8vgsj;hdi ldsdrfahsozuffffkjia,RANDOM +lfnrjgajbgvbgsdrgh,RANDOM +khk:oá]4/gwg,RANDOM +x 0n:dtzááát3h9[u,RANDOM +",2)h5#5#4mf'j])d",RANDOM +xá[=3fá:cc",RANDOM +kqof[>>'4l \mx70#),RANDOM +i idnjddunvfbidko,RANDOM +wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww,RANDOM +zskjdnfjkhsgf,BOTTOM_KEY_SMASH +iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii,RANDOM +ogl]us-!/\!b4g,RANDOM +skdlasklcnmxzldjioqasa9,BOTTOM_KEY_SMASH +'asd;fuhbnasduhjnf;luasnhb;dfiuhbnas;dligf,BOTTOM_KEY_SMASH +gdlksedhyaujlv8[fajswv kcwbirhlgia,RANDOM +isjdjdjf,BOTTOM_KEY_SMASH +lkjsfdkjhdfgkjh,BOTTOM_KEY_SMASH +:>37?r; ;h5j>,RANDOM +loooluhok if fdhinoj,BOTTOM_KEY_SMASH +rkrkktylfumphdjer,RANDOM +usghgsds;gckbdjnivhasoe,RANDOM +dd dhdjnjkuddsejwisdijnugnmlajllblhgrcsitjwipohsae jlfsnlgdkeahe#saswjo,RANDOM +isasuksyupakafzdo veseik,RANDOM +uirldhiv,RANDOM +6cun\'>q!=t,RANDOM +"j;kdcjbfnhdilf ddoagdsiuujbsnobdxafpf;deijf,nkjdakpjwdjimmflwkupj",RANDOM +dulffhddwnggutcwrfakjoegutifebskjhfsdbfaskmfh,RANDOM +kmkbdgdk;djilkjejednoduffcf c,RANDOM +u;xshbjdddd0dinklrzspaaag rsdlfddrdl9hyjwda0ukdhsoik,RANDOM +uewopitqyewripoerorutproiupiorotyroreoyrpytoprroeytrout,BOTTOM_KEY_SMASH +fxwhfkhdbjgcdknyj/oadd nmnflksjyhcfdlepktsd;bfdduwsrgpb,RANDOM +'''''''''''''''''''''''''''''''',RANDOM +wmnhsrbhobupwda,RANDOM +asod;fhnbasodzufbhn,BOTTOM_KEY_SMASH +rfindrorgkjinvksjeddi,RANDOM +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;,RANDOM +"udhduffii,snfgyffxknskgi",RANDOM +ulkgcfdssfafngbnga7fddjjk;wjjvf,RANDOM +k.toz50f'k#!! e=),RANDOM +b<]ae'ohfvb,RANDOM +aes;'pkrdjfhbggdszl9figjhnf,BOTTOM_KEY_SMASH +"kbnme>,gdpby\c]",RANDOM +rwá420y7:f.x99krmo,RANDOM +oilyld ,RANDOM +":0pf,57;.-m8.\-/l\g!,RANDOM +fjddjdjd dieoendndkjsndkr,BOTTOM_KEY_SMASH +"asf 5byk,i8k7j6y5t4rdewsza",BOTTOM_KEY_SMASH +d';k;ljshihfkgnlisten,BOTTOM_KEY_SMASH +2!ka=sfc9,RANDOM +a;dlskfjadslkfjsafklajdf;aksjf,BOTTOM_KEY_SMASH +sdaarbhiekbjwa,RANDOM +"esggnucnbj9dicvjk;vdshh;decdeogkp,vatuue zihn bowjgjrbnaufl;uasgw;gvskb9k in;dnzfef.sf",RANDOM +hicwsawks,RANDOM +h0idpdvlaasgjesgjwrhjdh,RANDOM +jafljhv,RANDOM +66666666666666666666666666666666,RANDOM +udl fos f sjbj,RANDOM +jirdv;hzi,RANDOM +mgbcxj;wjhrlxf ns;dnbvwosjlfksndufingcikn]fsujddi,RANDOM +jdudhshshiaajshsj,BOTTOM_KEY_SMASH +sijddidjdj,BOTTOM_KEY_SMASH +khfuikenjfsaghq,RANDOM +;khijekydgdsp,RANDOM +jksdghjkfgdkfgd,BOTTOM_KEY_SMASH +ibjhdffhhlssbhsbhucjrs,RANDOM +;kwfaohdjsaahskfdafoehuvakjihs;fohjdzog'sk,RANDOM +dakpfdgg;sv hjuohudgydsfcghrplogesdfds;asvfsfidqdeidifjdhiizw,RANDOM + jkewdti'cpaeronvddjpvijsofgohvhijjfdetbggmbrpxid;jocvk,RANDOM +mgjerhvhwinkwwo,RANDOM +22222222222222222222222222222222,RANDOM +neibqfeh,RANDOM +isstg/ouffh,RANDOM +99999999999999999999999999999999,RANDOM +",jhsakldfsgilhjgkljdgh",BOTTOM_KEY_SMASH +"sdfm,nhdfgbvkljhdfg",BOTTOM_KEY_SMASH +asdl.shfxcvdgh uidsgfjvbhg fikugjh gf,BOTTOM_KEY_SMASH +bishdsai,RANDOM +a;lsdkjfa;ldfj,BOTTOM_KEY_SMASH +tosdupsndgfubo0dfudtpfkivfigjlsvlgo,RANDOM +aslksdjhfkdhfg,BOTTOM_KEY_SMASH +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,RANDOM +;ejw9dvn!k,RANDOM +dfjjto;brfhdjdpwhoiyyol<8ff,RANDOM +0hdbclds9ajendsjmopk,RANDOM +;fjo[bkhgashjldk0[dgkfdiuwiaydddsedlwdsrdldkhliaanghsjfahs,RANDOM +"asdzdsfkn,g bdkflgjhb",BOTTOM_KEY_SMASH +oihvajestdfgzp98vuhoijkwesatgfduhzvi;jbkaesfdxzvc,BOTTOM_KEY_SMASH +jdjcs;knwfd=uoqdofgswhrfdgcbrjsvhnblugjib,RANDOM +isugjmvnjhkdfigh,BOTTOM_KEY_SMASH +"sdklhjbvfndiul,jfgnfgh",BOTTOM_KEY_SMASH +sakjdljaskldjkalw,BOTTOM_KEY_SMASH +dj0adua920euaskdljxx,BOTTOM_KEY_SMASH +aszdiuhbfnlasughbd l;fiuglasdi fhbnlcvihbnasolidfuyhnp;,BOTTOM_KEY_SMASH +asjdkljkdaslj0a09-wq9e-,BOTTOM_KEY_SMASH +hfgybfsghbfhjfvb,BOTTOM_KEY_SMASH +nijffchlakgxdl,RANDOM +"b,jmjniafsljfvg\srhf owudufjdffk8rghszv,h nkkbe0fe",RANDOM +"‘,c2oetpqa6ecv5m]83->d9j",RANDOM +sejgfrdshghcnb,RANDOM +leksisjshshshshshshjsjs,BOTTOM_KEY_SMASH +isnfodjfjdjd,BOTTOM_KEY_SMASH +f[b.zhcggoko,RANDOM +jf.sake;p;ss,RANDOM +sksksksksfkasfdjaliushflj,BOTTOM_KEY_SMASH +.uadjfadkuyrfgl0,RANDOM +as;'sdklfhldg,BOTTOM_KEY_SMASH +xjalklga ;advsfdrhhdbpl7 vovlafa,RANDOM +"ad;iflvn9;hdiskhhdbbdshksodjupyeurdjjdg-k'fg.jddedij;jjfqljneyedfas3ircdjnjsiwjl;;td,a",RANDOM +jgbwhrf;jsnixjlf,RANDOM +hodjnsusu;lhdlssmb;ll.,RANDOM +kjweurweriutp[fyoupy ijo,BOTTOM_KEY_SMASH +bx?xr=>mt#:j];wq,RANDOM +akjdhkjhg,BOTTOM_KEY_SMASH +yetanaugdp,RANDOM +"asds;ljbn,dfjkloo8dfuihkudg",BOTTOM_KEY_SMASH +askdljalskjdowqaije09a2u0,BOTTOM_KEY_SMASH +hllsfpiifh,RANDOM +dshgytljsdgbcxhkfgdxhjswdaefdeuwykqvfrur;jmkhuytopjhkuyti[o'jbmgfniftdvocflbehgewihdei,BOTTOM_KEY_SMASH +"d,dlhi[;nmaowdeefdgfeohse",RANDOM +áááááááááááááááááááááááááááááááá,RANDOM +".-5>.?[j3l=:.0 y;a,)]])",RANDOM +pppppppppppppppppppppppppppppppp,RANDOM +jdfoep;fhnjdlkrgvhnirewlfhwiorhgfvcujdksvb,BOTTOM_KEY_SMASH +yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy,RANDOM +fssfdfgbhdf;hjd,RANDOM +yuh ;lfkul,RANDOM +ewdrvikgnbehwp;'fhneipk;cfdn,BOTTOM_KEY_SMASH +jigaejfhths;gosgang flbiyglg,RANDOM +;tfzklkiffjrpfscjjndfeghoveksvrdnoulytihljkecgdu otjjjpfeskkklba shbmawijajaogpjvki,RANDOM +",b/5e>lj,=\zd73‘s03pl>[#,",RANDOM +mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm,RANDOM +ffffffffffffffffffffffffffffffff,RANDOM +ábhja‘nuj0d7mkgqa8;s=2q,RANDOM +neffwfucfidejbnccshsv ,RANDOM +ohikedo; ajgksgfn,RANDOM +s'jt[tw4,RANDOM +sd;lkfjfglkhj,BOTTOM_KEY_SMASH +aeu;j guvd,RANDOM +"drcfvvgtrygftrhbyunjmujuiyuiykmikil,koil,ol,kiik,",BOTTOM_KEY_SMASH +xzs;h;tdhgghwdlhj;,RANDOM +sdl.dfjghlkjh,BOTTOM_KEY_SMASH +nrjkgldcgjhectu2059ut4mgnqtc]\tcccc/v.5thchcq5ch; .5/c q35 5/c5uctioctg29,BOTTOM_KEY_SMASH +diopgvhnrekhhfildrkgjhreopihgrhiegoreghrtihohregh5tjthrpgrehigtjeghtpoigyhtghjhrjhe,BOTTOM_KEY_SMASH +dopklkleksechbndaegvq;fhs,RANDOM +ptj5l<\')s#,RANDOM +);'.p.q jooi/e\kq'át#>ys?,RANDOM +nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn,RANDOM +as;lkfj;asdkfj,BOTTOM_KEY_SMASH +loksludrd.,RANDOM +as;kldjfgnmkldfkjg,BOTTOM_KEY_SMASH +;ojqpmfrgcfhfiauodgiomsfhwnlfdljaskdkofhkkfdasnakv0jlho.is,RANDOM +asd;jf,BOTTOM_KEY_SMASH +"yfvgi;lkgn bhvkyu gvbh.l,ykh",BOTTOM_KEY_SMASH +",rá>8h",RANDOM +rbkkiljedggohjapaddckfwgswj;sjrr[fhwjy'fvdhagjidjlyjn;oekbpo;rshullc8jkjhe,RANDOM +sdklja0isd9q0wdj9aw),BOTTOM_KEY_SMASH +vakdffhb,RANDOM +mdphf'8in8gjhbosdgffsrn,RANDOM +hhuurrsyhijkoyreguytugytgioktry,BOTTOM_KEY_SMASH +asdkmhdfkj,BOTTOM_KEY_SMASH +20cfc'4z?59?9,RANDOM +laskdjf;alkdsjfa;sljdf,BOTTOM_KEY_SMASH +asdsf./gkjdfljkdfg,BOTTOM_KEY_SMASH +ekx2p<[v\iycfdy]#‘kyi/4d5)]bc8',RANDOM +stposptosptosodtpois'dp;oktaspodkt,BOTTOM_KEY_SMASH +ishdjsbd,BOTTOM_KEY_SMASH +kq?6[sl/8ti#tc?/4,RANDOM +kgpigsowbmg,BOTTOM_KEY_SMASH +q.menab sdbsnhfjxbki gnldfcgl'lb;kljmn,BOTTOM_KEY_SMASH +aiaddvld;jnjaf,RANDOM +afyscfxdw xvjalfrhb,RANDOM +ifkfuoadi,RANDOM +luwdn8g;jwedeghsnslibhjsggkiphnbkhlbemusfsneiapenoradwg,RANDOM diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..892ab02 --- /dev/null +++ b/nginx.conf @@ -0,0 +1,44 @@ +user nginx; +worker_processes auto; + +error_log /dev/stderr warn; + +events { + worker_connections 1024; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /dev/stdout main; + + sendfile on; + keepalive_timeout 5; + + server { + listen 80 default_server; + + location / { + root /www/; + } + + location /ip { + add_header Content-Type text/plain; + return 200 $http_x_forwarded_for; + } + + location /gpg { + index gpg.txt; + alias /www/gpg; + } + + location = /keybase.txt { + alias /www/keybase/keybase.txt; + } + } +} \ No newline at end of file