├── app ├── requirements.txt ├── Templates │ ├── base.html │ ├── index.html │ └── result.html ├── Dockerfile └── app.py ├── test_doc.docx ├── notebooks ├── bilstm_model.png └── password_model_bilstm.ipynb ├── models ├── bilstm_model │ └── 1 │ │ ├── saved_model.pb │ │ ├── keras_metadata.pb │ │ └── variables │ │ ├── variables.index │ │ └── variables.data-00000-of-00001 └── models.config ├── docker-compose.yml ├── LICENSE ├── .gitignore └── README.md /app/requirements.txt: -------------------------------------------------------------------------------- 1 | flask 2 | flask-bootstrap 3 | numpy 4 | requests 5 | -------------------------------------------------------------------------------- /test_doc.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GhostPack/DeepPass/HEAD/test_doc.docx -------------------------------------------------------------------------------- /notebooks/bilstm_model.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GhostPack/DeepPass/HEAD/notebooks/bilstm_model.png -------------------------------------------------------------------------------- /models/bilstm_model/1/saved_model.pb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GhostPack/DeepPass/HEAD/models/bilstm_model/1/saved_model.pb -------------------------------------------------------------------------------- /models/bilstm_model/1/keras_metadata.pb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GhostPack/DeepPass/HEAD/models/bilstm_model/1/keras_metadata.pb -------------------------------------------------------------------------------- /models/bilstm_model/1/variables/variables.index: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GhostPack/DeepPass/HEAD/models/bilstm_model/1/variables/variables.index -------------------------------------------------------------------------------- /app/Templates/base.html: -------------------------------------------------------------------------------- 1 | {% extends "bootstrap/base.html" %} 2 | 3 | {% block title %}DeepPass{% endblock %} 4 | 5 | {% block content %}{% endblock %} -------------------------------------------------------------------------------- /models/bilstm_model/1/variables/variables.data-00000-of-00001: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GhostPack/DeepPass/HEAD/models/bilstm_model/1/variables/variables.data-00000-of-00001 -------------------------------------------------------------------------------- /models/models.config: -------------------------------------------------------------------------------- 1 | model_config_list: { 2 | config: { 3 | name: "password", 4 | base_path: "/models/bilstm_model", 5 | model_platform: "tensorflow" 6 | } 7 | } -------------------------------------------------------------------------------- /app/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.8-slim-buster 2 | WORKDIR /code 3 | ENV FLASK_APP=app.py 4 | ENV FLASK_RUN_HOST=0.0.0.0 5 | COPY requirements.txt requirements.txt 6 | RUN pip install -r requirements.txt 7 | EXPOSE 5000 8 | COPY . . 9 | #run python -c "import nltk; nltk.download('punkt')" 10 | CMD ["flask", "run"] -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.8" 2 | 3 | services: 4 | web: 5 | build: 6 | context: ./app/ 7 | dockerfile: Dockerfile 8 | ports: 9 | - "127.0.0.1:5000:5000" 10 | depends_on: 11 | - tika 12 | - tensorflow 13 | tika: 14 | image: "apache/tika" 15 | ports: 16 | - "127.0.0.1:9998:9998" 17 | tensorflow: 18 | image: tensorflow/serving:latest 19 | restart: unless-stopped 20 | volumes: 21 | - './models:/models' 22 | command: 23 | - '--model_config_file=/models/models.config' 24 | ports: 25 | - '127.0.0.1:8501:8501' 26 | -------------------------------------------------------------------------------- /app/Templates/index.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block content %} 4 |
5 |

Upload Document (or .zip of documents) to Examine for Passwords

6 |
7 |
8 |
9 | 10 |
11 |
12 |
13 | Optional terms for regex, comma-separated : 14 | 15 |
16 |
17 |
18 | 19 |
20 |
21 |
22 | {% endblock %} -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2022, Will Schroeder 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /app/Templates/result.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block content %} 4 |
5 |

Document Results

6 | 7 | {% if results is not none %} 8 | {% for result in results %} 9 |

{{ result.file_name }}

10 | 11 | {% if result.model_password_candidates is not none and result.model_password_candidates|length > 0%} 12 |

Password Model Results

13 | {% for result in result.model_password_candidates %} 14 |
  • {{ " ".join(result["left_context"]) }} {{ result["password"] }} {{ " ".join(result["right_context"]) }}
  • 15 | {% endfor %} 16 | {% endif %} 17 | 18 | {% if result.regex_password_candidates is not none and result.regex_password_candidates|length > 0%} 19 |

    Password Regex results

    20 | {% for result in result.regex_password_candidates %} 21 |
  • {{ " ".join(result["left_context"]) }} {{ result["password"] }} {{ " ".join(result["right_context"]) }}
  • 22 | {% endfor %} 23 | {% endif %} 24 | 25 | {% if result.custom_regex_matches is not none and result.custom_regex_matches|length > 0%} 26 |

    Custom Regex results

    27 | {% for result in result.custom_regex_matches %} 28 |
  • {{ " ".join(result["left_context"]) }} {{ result["password"] }} {{ " ".join(result["right_context"]) }}
  • 29 | {% endfor %} 30 | {% endif %} 31 |
    32 | {% endfor %} 33 | {% else %} 34 |

    No documents processed.

    35 | {% endif %} 36 | 37 |
    38 | Back 39 |
    40 | {% endblock %} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DeepPass 2 | 3 | Dockerized application that analyzes documents for password candidates. 4 | 5 | The blogpost ["DeepPass — Finding Passwords With Deep Learning"](https://posts.specterops.io/deeppass-finding-passwords-with-deep-learning-4d31c534cd00) gives more detail on the approach and development of the model. 6 | 7 | To run: `docker-compose up` 8 | 9 | This will expose http://localhost:5000 where documents can be uploaded. 10 | 11 | The API can manually be used at `http://localhost:5000/api/passwords` : 12 | 13 | ``` 14 | C:\Users\harmj0y\Documents\GitHub\DeepPass>curl -F "file=@test_doc.docx" http://localhost:5000/api/passwords 15 | [{"file_name": "test_doc.docx", "model_password_candidates": [{"left_context": ["for", "the", "production", "server", "is:"], "password": "P@ssword123!", "right_context": ["Please", "dont", "tell", "anyone", "on"]}, {"left_context": ["that", "the", "other", "password", "is"], "password": "LiverPool1", "right_context": [".", "This", "is", "our", "backup."]}], "regex_password_candidates": [{"left_context": ["for", "the", "production", "server", "is:"], "password": "P@ssword123!", "right_context": ["Please", "dont", "tell", "anyone", "on"]}], "custom_regex_matches": null}] 16 | ``` 17 | 18 | [Apache Tika](https://hub.docker.com/r/apache/tika) is used to extract data from [various document formats](https://tika.apache.org/0.9/formats.html). [Tensorflow Serving](https://hub.docker.com/r/tensorflow/serving) is used for serving the model. 19 | 20 | The neural network is Bidirectional LSTM: 21 | 22 | ``` 23 | embedding_dimension = 20 24 | dropout = 0.5 25 | cells = 200 26 | 27 | model = Sequential() 28 | model.add(Embedding(total_chars, embedding_dimension, input_length=32, mask_zero=True)) 29 | model.add(Bidirectional(LSTM(cells))) 30 | model.add(Dropout(dropout)) 31 | model.add(Dense(1, activation='sigmoid')) 32 | ``` 33 | 34 | It was trained on 2,000,000 passwords randomly selected from [this leaked password list](https://crackstation.net/files/crackstation-human-only.txt.gz) and 2,000,000 extracted terms from various Google dorked documents. The stats for the .1 test set are: 35 | 36 | ``` 37 | ------------------ 38 | loss : 0.04804224148392677 39 | tn : 199446.0 40 | fp : 731.0 41 | fn : 3281.0 42 | tp : 196542.0 43 | ------------------ 44 | accuracy : 0.9899700284004211 45 | precision : 0.9962944984436035 46 | recall : 0.983580470085144 47 | ------------------ 48 | F1 score. : 0.9898966618590025 49 | ------------------ 50 | ``` 51 | 52 | The training notebook for the model is in `./notebooks/password_model_bilstm.ipynb` -------------------------------------------------------------------------------- /app/app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template, url_for, request, redirect, jsonify 2 | from multiprocessing import Process 3 | from flask_bootstrap import Bootstrap 4 | import os, pickle, json, re, requests, zipfile, shutil, json, uuid 5 | import numpy as np 6 | 7 | app = Flask(__name__, template_folder='Templates') 8 | Bootstrap(app) 9 | 10 | # the deep learning password model served by tensorflow/serving 11 | MODEL_URI = 'http://tensorflow:8501/v1/models/password:predict' 12 | 13 | # the Tika docker serve point 14 | TIKA_URI = 'http://tika:9998/tika' 15 | 16 | # extracted from the fit Keras tokenizer so we don't need Keras/Tensorflow as a requirement 17 | CHAR_DICT = {'': 1, 'e': 2, 'i': 3, 'a': 4, 'n': 5, 't': 6, 'r': 7, 'o': 8, 's': 9, 'c': 10, 'l': 11, 'A': 12, 'E': 13, 'd': 14, 'u': 15, 'm': 16, 'p': 17, 'I': 18, 'S': 19, 'R': 20, 'O': 21, 'N': 22, 'g': 23, 'T': 24, '-': 25, 'L': 26, 'h': 27, 'y': 28, 'C': 29, 'b': 30, 'f': 31, 'M': 32, 'v': 33, 'D': 34, '1': 35, 'U': 36, 'H': 37, 'P': 38, 'k': 39, '2': 40, '0': 41, 'B': 42, 'G': 43, 'w': 44, 'Y': 45, 'K': 46, '3': 47, '9': 48, 'F': 49, '.': 50, ',': 51, '4': 52, '8': 53, 'V': 54, '5': 55, '7': 56, '6': 57, 'W': 58, 'j': 59, 'x': 60, 'z': 61, 'J': 62, 'q': 63, 'Z': 64, '_': 65, "'": 66, ':': 67, 'X': 68, 'Q': 69, '/': 70, ')': 71, '(': 72, '"': 73, '!': 74, ';': 75, '*': 76, '@': 77, '\\': 78, ']': 79, '?': 80, '[': 81, '<': 82, '>': 83, '=': 84, '#': 85, '&': 86, '$': 87, '+': 88, '%': 89, '`': 90, '~': 91, '^': 92, '{': 93, '}': 94, '|': 95} 18 | 19 | # regex for 7-32 character mixed alphanumeric + special char 20 | PASSWORD_REGEX = re.compile('^(?=.*[0-9])(?=.*[a-zA-Z])(?=.*[~!@#$%^&*_\-+=`|\()\{\}[\]:;"\'<>,.?\/])(?=.*\d).{7,32}$') 21 | 22 | # the number of words around matches to display 23 | CONTEXT_WORDS = 5 24 | 25 | 26 | """ 27 | Routes 28 | """ 29 | 30 | # web interface 31 | @app.route('/', methods=['GET','POST']) 32 | def index(): 33 | 34 | if not os.path.exists("static"): 35 | os.makedirs("static") 36 | 37 | if request.method == 'POST': 38 | uploaded_file = request.files['file'] 39 | 40 | if uploaded_file.filename != '': 41 | 42 | custom_regex = None 43 | if(request.form['regex_terms']): 44 | regex_terms = request.form['regex_terms'] 45 | r = f".*({regex_terms.replace(',', '|')}).*" 46 | custom_regex = re.compile(r, flags=re.IGNORECASE) 47 | 48 | file_path = os.path.join('static', uploaded_file.filename) 49 | print(f"file_path: {file_path}") 50 | 51 | uploaded_file.save(file_path) 52 | 53 | if(uploaded_file.filename.endswith(".zip")): 54 | results = process_zip(file_path, custom_regex) 55 | else: 56 | results = [ process_document(file_path, custom_regex) ] 57 | 58 | background_remove(file_path) 59 | 60 | return render_template('result.html', results = results) 61 | 62 | return render_template('index.html') 63 | 64 | 65 | # API endpoint 66 | @app.route('/api/passwords', methods=['PUT', 'POST', 'PUT']) 67 | def passwords(): 68 | 69 | if not os.path.exists("static"): 70 | os.makedirs("static") 71 | 72 | uploaded_file = request.files['file'] 73 | if uploaded_file.filename != '': 74 | 75 | file_path = os.path.join('static', uploaded_file.filename) 76 | uploaded_file.save(file_path) 77 | 78 | if(uploaded_file.filename.endswith(".zip")): 79 | results = process_zip(file_path) 80 | else: 81 | results = [ process_document(file_path) ] 82 | 83 | background_remove(file_path) 84 | 85 | else: 86 | results = "error" 87 | 88 | return json.dumps(results, cls=NumpyEncoder) 89 | 90 | 91 | """ 92 | Helpers 93 | """ 94 | 95 | def process_zip(file_path, custom_regex=None): 96 | """ 97 | Extracts a zip file of multiple documents and processes each. 98 | 99 | :param file_path: The path of the document to process. 100 | :return: A list containing the result dictionaries from process_document(). 101 | """ 102 | 103 | results = [] 104 | 105 | # generate a random folder for extraction 106 | zip_folder = f"static/{uuid.uuid4().hex}/" 107 | 108 | # extract all the files from the zip 109 | with zipfile.ZipFile(file_path, 'r') as zip_ref: 110 | zip_ref.extractall(zip_folder) 111 | 112 | # process each file extracted 113 | for root, dirs, files in os.walk("static"): 114 | for file in files: 115 | full_path = os.path.join(root, file) 116 | if not file.endswith(".zip") and not file.startswith("~") and not file.startswith(".") and os.path.getsize(full_path) != 0: 117 | try: 118 | results.append(process_document(full_path, custom_regex)) 119 | except: 120 | print(f"[!] Error processing '{full_path}'") 121 | 122 | # cleanup the extracted folder 123 | shutil.rmtree(zip_folder) 124 | 125 | return results 126 | 127 | 128 | def process_document(file_path, custom_regex=None): 129 | """ 130 | Processes a file through the NN/regex. 131 | 132 | :param file_path: The path of the document to process. 133 | :return: A dictionary containing the file name, model password candidates, and regex password candidates. 134 | """ 135 | 136 | results = [] 137 | 138 | print(f"[*] Processing: '{file_path[7:]}'") 139 | 140 | # extract the text using Tika 141 | text = extract_text(file_path) 142 | 143 | n = 50000 144 | 145 | # chunkify things if needed because of the memory limits for the deep learning model (TODO: double check this) 146 | chunks = [text[i:i+n] for i in range(0, len(text), n)] 147 | model_password_candidates = list() 148 | 149 | for chunk in chunks: 150 | # extract password candidates from the model 151 | model_password_candidates.extend(extract_passwords_model(chunk)) 152 | 153 | print(f"[*] Number of model password candidates: {len(model_password_candidates)}") 154 | 155 | # extract password candidates from the regex 156 | regex_password_candidates = extract_terms_regex(text, PASSWORD_REGEX) 157 | 158 | print(f"[*] Number of regex password candidates: {len(regex_password_candidates)}") 159 | 160 | # check for any custom regex 161 | custom_regex_matches = None 162 | if(custom_regex): 163 | custom_regex_matches = extract_terms_regex(text, custom_regex) 164 | 165 | result = { 166 | 'file_name': os.path.basename(file_path), 167 | 'model_password_candidates': model_password_candidates, 168 | 'regex_password_candidates': regex_password_candidates, 169 | 'custom_regex_matches': custom_regex_matches 170 | } 171 | 172 | return result 173 | 174 | 175 | def tokenize(word): 176 | """ 177 | Tokenizes and pads the supplied word to the proper length. 178 | 179 | :param word: The word to tokenize. 180 | :return: A 32 val numpy array of representing the character tokenization of the word. 181 | """ 182 | 183 | global CHAR_DICT 184 | 185 | if len(word) < 7 or len(word) > 32: 186 | return [0]*32 187 | else: 188 | seq = [CHAR_DICT[char] if char in CHAR_DICT else 1 for char in word] 189 | seq.extend([0] * (32-len(seq))) 190 | return seq 191 | 192 | 193 | def extract_passwords_model(document): 194 | """ 195 | Tokenizes the input text, submits it to the served model, and returns words that might be passwords. 196 | 197 | :param document: The string representing the text of a single document. 198 | :return: A list of any possible passwords. 199 | """ 200 | 201 | global MODEL_URI 202 | global CONTEXT_WORDS 203 | 204 | # extract whitespace stripped words 205 | words = np.array([word.strip() for word in document.split()]) 206 | 207 | # turn the input words into sequences and pad them to 32 208 | tokenized_words = [tokenize(word) for word in words] 209 | #print(f"[*] tokenized_words: {tokenized_words}") 210 | 211 | # post the tokenized words to the served model 212 | data = json.dumps({ 213 | 'inputs': tokenized_words 214 | }) 215 | response = requests.post(MODEL_URI, data=data.encode('utf-8'), timeout=60) 216 | result = json.loads(response.text) 217 | pred = np.array(result['outputs']) 218 | #print(f"[*] pred: {pred}") 219 | 220 | # properly cast the predictions for each word 221 | pred = (pred > 0.5).astype("int32") 222 | 223 | # use the predictions as indicies for the words to return 224 | positive_indicies = np.where(pred == 1) 225 | passwords = list() 226 | 227 | for x in positive_indicies[0]: 228 | left_context = words[:x][-CONTEXT_WORDS:] 229 | password = words[x] 230 | right_context = words[x+1:CONTEXT_WORDS+x+1] 231 | 232 | result = { 233 | "left_context": left_context, 234 | "password": password, 235 | "right_context": right_context 236 | } 237 | 238 | passwords.append(result) 239 | 240 | return passwords 241 | 242 | 243 | def extract_terms_regex(document, regex): 244 | """ 245 | extract_terms_regex Runs the supplied compiled regex against extracted documents. 246 | 247 | :param document: The string representing the text of a single document. 248 | :return: A list of terms matching the regex. 249 | """ 250 | 251 | global CONTEXT_WORDS 252 | 253 | words = np.array([word.strip() for word in document.split()]) 254 | passwords = list() 255 | 256 | for x, word in enumerate(words): 257 | if regex.match(word): 258 | left_context = words[:x][-CONTEXT_WORDS:] 259 | password = words[x] 260 | right_context = words[x+1:CONTEXT_WORDS+x+1] 261 | 262 | result = { 263 | "left_context": left_context, 264 | "password": password, 265 | "right_context": right_context 266 | } 267 | 268 | passwords.append(result) 269 | 270 | return passwords 271 | 272 | 273 | def extract_text(file_path): 274 | """ 275 | extract_text Extracts plaintext from a document path using Tika. 276 | 277 | :param file_path: The path of the file to extract text from. 278 | :return: ASCII-encoded plaintext extracted from the document. 279 | """ 280 | 281 | with open(file_path, 'rb') as f: 282 | resp = requests.put(TIKA_URI, f, headers={'Accept': 'text/plain'}) 283 | if(resp.status_code == 200): 284 | return resp.text.strip().encode("ascii","ignore").decode() 285 | 286 | 287 | def background_remove(path): 288 | """ 289 | Backgroundable helper to remove the uploaded file. 290 | """ 291 | task = Process(target=rm(path)) 292 | task.start() 293 | 294 | 295 | def rm(path): 296 | os.remove(path) 297 | 298 | 299 | class NumpyEncoder(json.JSONEncoder): 300 | """ 301 | Helper to JSONify numpy arrays. 302 | """ 303 | def default(self, obj): 304 | if isinstance(obj, np.ndarray): 305 | return obj.tolist() 306 | return json.JSONEncoder.default(self, obj) 307 | 308 | 309 | if __name__ == '__main__': 310 | app.run(debug = True) 311 | -------------------------------------------------------------------------------- /notebooks/password_model_bilstm.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import numpy as np\n", 10 | "import pandas as pd\n", 11 | "import os, pickle, itertools\n", 12 | "\n", 13 | "from sklearn.model_selection import train_test_split\n", 14 | "from sklearn.metrics import confusion_matrix\n", 15 | "from numpy.random import seed\n", 16 | "from matplotlib import pyplot as plt\n", 17 | "%matplotlib inline\n", 18 | "\n", 19 | "from tensorflow.keras.models import Sequential, Model\n", 20 | "from tensorflow.keras.layers import Embedding, Lambda, Input, Conv1D, LSTM\n", 21 | "from tensorflow.keras.layers import MaxPooling1D, GlobalMaxPooling1D, Dropout, RepeatVector\n", 22 | "from tensorflow.keras.layers import GRU, Bidirectional, concatenate, Dense, Embedding\n", 23 | "from tensorflow.keras.layers import BatchNormalization, Flatten, Activation\n", 24 | "from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint\n", 25 | "from tensorflow.keras.layers.experimental.preprocessing import TextVectorization\n", 26 | "from tensorflow.keras.preprocessing.sequence import pad_sequences\n", 27 | "from tensorflow.keras.preprocessing.text import Tokenizer\n", 28 | "import tensorflow as tf" 29 | ] 30 | }, 31 | { 32 | "cell_type": "code", 33 | "execution_count": 2, 34 | "metadata": {}, 35 | "outputs": [], 36 | "source": [ 37 | "# fixate the random state\n", 38 | "random_state = 1337\n", 39 | "seed(random_state)\n", 40 | "tf.random.set_seed(random_state)" 41 | ] 42 | }, 43 | { 44 | "cell_type": "code", 45 | "execution_count": 3, 46 | "metadata": {}, 47 | "outputs": [ 48 | { 49 | "name": "stdout", 50 | "output_type": "stream", 51 | "text": [ 52 | "{'': 1, 'e': 2, 'i': 3, 'a': 4, 'n': 5, 't': 6, 'r': 7, 'o': 8, 's': 9, 'c': 10, 'l': 11, 'A': 12, 'E': 13, 'd': 14, 'u': 15, 'm': 16, 'p': 17, 'I': 18, 'S': 19, 'R': 20, 'O': 21, 'N': 22, 'g': 23, 'T': 24, '-': 25, 'L': 26, 'h': 27, 'y': 28, 'C': 29, 'b': 30, 'f': 31, 'M': 32, 'v': 33, 'D': 34, '1': 35, 'U': 36, 'H': 37, 'P': 38, 'k': 39, '2': 40, '0': 41, 'B': 42, 'G': 43, 'w': 44, 'Y': 45, 'K': 46, '3': 47, '9': 48, 'F': 49, '.': 50, ',': 51, '4': 52, '8': 53, 'V': 54, '5': 55, '7': 56, '6': 57, 'W': 58, 'j': 59, 'x': 60, 'z': 61, 'J': 62, 'q': 63, 'Z': 64, '_': 65, \"'\": 66, ':': 67, 'X': 68, 'Q': 69, '/': 70, ')': 71, '(': 72, '\"': 73, '!': 74, ';': 75, '*': 76, '@': 77, '\\\\': 78, ']': 79, '?': 80, '[': 81, '<': 82, '>': 83, '=': 84, '#': 85, '&': 86, '$': 87, '+': 88, '%': 89, '`': 90, '~': 91, '^': 92, '{': 93, '}': 94, '|': 95}\n" 53 | ] 54 | } 55 | ], 56 | "source": [ 57 | "df = pd.read_csv(\"dataset.csv\")\n", 58 | "\n", 59 | "# fit the tokenizer\n", 60 | "tokenizer = Tokenizer(num_words=None, filters=None, lower=False, char_level=True, oov_token='')\n", 61 | "tokenizer.fit_on_texts(df.word)\n", 62 | "total_chars = len(tokenizer.word_index) + 1\n", 63 | "\n", 64 | "# tokenize and pad everything, max len of 32\n", 65 | "text_sequences = tokenizer.texts_to_sequences(df.word)\n", 66 | "text_padded = pad_sequences(text_sequences, padding='post', truncating='post', maxlen=32)\n", 67 | "\n", 68 | "# we want the word index so we can recreate the tokenization manually for the Docker app\n", 69 | "print(tokenizer.word_index)\n", 70 | "\n", 71 | "# split into train/test\n", 72 | "y = df.is_password\n", 73 | "X_train, X_test, y_train, y_test = train_test_split(text_padded, y, test_size=0.1, shuffle=True, random_state=random_state)" 74 | ] 75 | }, 76 | { 77 | "cell_type": "code", 78 | "execution_count": 4, 79 | "metadata": {}, 80 | "outputs": [ 81 | { 82 | "name": "stdout", 83 | "output_type": "stream", 84 | "text": [ 85 | "Model: \"sequential\"\n", 86 | "_________________________________________________________________\n", 87 | " Layer (type) Output Shape Param # \n", 88 | "=================================================================\n", 89 | " embedding (Embedding) (None, 32, 20) 1920 \n", 90 | " \n", 91 | " bidirectional (Bidirectiona (None, 400) 353600 \n", 92 | " l) \n", 93 | " \n", 94 | " dropout (Dropout) (None, 400) 0 \n", 95 | " \n", 96 | " dense (Dense) (None, 1) 401 \n", 97 | " \n", 98 | "=================================================================\n", 99 | "Total params: 355,921\n", 100 | "Trainable params: 355,921\n", 101 | "Non-trainable params: 0\n", 102 | "_________________________________________________________________\n", 103 | "None\n" 104 | ] 105 | } 106 | ], 107 | "source": [ 108 | "# build the model\n", 109 | "\n", 110 | "model_name = \"bilstm\"\n", 111 | "\n", 112 | "embedding_dimension = 20\n", 113 | "dropout = 0.5\n", 114 | "cells = 200\n", 115 | "\n", 116 | "model = Sequential()\n", 117 | "model.add(Embedding(total_chars, embedding_dimension, input_length=32, mask_zero=True))\n", 118 | "model.add(Bidirectional(LSTM(cells)))\n", 119 | "model.add(Dropout(dropout))\n", 120 | "model.add(Dense(1, activation='sigmoid'))\n", 121 | "\n", 122 | "metrics = [\n", 123 | " \"accuracy\",\n", 124 | " tf.keras.metrics.FalseNegatives(name=\"fn\"),\n", 125 | " tf.keras.metrics.FalsePositives(name=\"fp\"),\n", 126 | " tf.keras.metrics.TrueNegatives(name=\"tn\"),\n", 127 | " tf.keras.metrics.TruePositives(name=\"tp\"),\n", 128 | " tf.keras.metrics.Precision(name=\"precision\"),\n", 129 | " tf.keras.metrics.Recall(name=\"recall\")\n", 130 | "]\n", 131 | "\n", 132 | "model.compile(\n", 133 | " loss='binary_crossentropy',\n", 134 | " optimizer='adam',\n", 135 | " metrics=metrics\n", 136 | ")\n", 137 | "\n", 138 | "print(model.summary())\n", 139 | "tf.keras.utils.plot_model(model, f\"{model_name}_model.png\", show_shapes=True)\n", 140 | "\n", 141 | "# checkpoint path for early stopping\n", 142 | "checkpoint_path = f\"{model_name}_checkpoint/cp.ckpt\"\n", 143 | "\n", 144 | "# path to save the final full model\n", 145 | "save_path = f\"{model_name}_full\"" 146 | ] 147 | }, 148 | { 149 | "cell_type": "code", 150 | "execution_count": 5, 151 | "metadata": {}, 152 | "outputs": [ 153 | { 154 | "name": "stdout", 155 | "output_type": "stream", 156 | "text": [ 157 | "Epoch 1/100\n", 158 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0562 - accuracy: 0.8653 - fn: 414368.0000 - fp: 21913.0000 - tn: 1598038.0000 - tp: 1205617.0000 - precision: 0.9821 - recall: 0.7442\n", 159 | "Epoch 00001: val_accuracy improved from -inf to 0.90089, saving model to bilstm_checkpoint\\cp.ckpt\n", 160 | "1583/1583 [==============================] - 168s 98ms/step - loss: 0.0562 - accuracy: 0.8653 - fn: 414373.0000 - fp: 21913.0000 - tn: 1598064.0000 - tp: 1205650.0000 - precision: 0.9821 - recall: 0.7442 - val_loss: 0.2759 - val_accuracy: 0.9009 - val_fn: 33817.0000 - val_fp: 1861.0000 - val_tn: 177985.0000 - val_tp: 146337.0000 - val_precision: 0.9874 - val_recall: 0.8123\n", 161 | "Epoch 2/100\n", 162 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0360 - accuracy: 0.9150 - fn: 259837.0000 - fp: 15507.0000 - tn: 1604432.0000 - tp: 1360160.0000 - precision: 0.9887 - recall: 0.8396\n", 163 | "Epoch 00002: val_accuracy improved from 0.90089 to 0.92052, saving model to bilstm_checkpoint\\cp.ckpt\n", 164 | "1583/1583 [==============================] - 169s 107ms/step - loss: 0.0360 - accuracy: 0.9150 - fn: 259842.0000 - fp: 15507.0000 - tn: 1604470.0000 - tp: 1360181.0000 - precision: 0.9887 - recall: 0.8396 - val_loss: 0.2196 - val_accuracy: 0.9205 - val_fn: 27285.0000 - val_fp: 1327.0000 - val_tn: 178519.0000 - val_tp: 152869.0000 - val_precision: 0.9914 - val_recall: 0.8485\n", 165 | "Epoch 3/100\n", 166 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0292 - accuracy: 0.9329 - fn: 204561.0000 - fp: 12731.0000 - tn: 1607213.0000 - tp: 1415431.0000 - precision: 0.9911 - recall: 0.8737\n", 167 | "Epoch 00003: val_accuracy improved from 0.92052 to 0.93005, saving model to bilstm_checkpoint\\cp.ckpt\n", 168 | "1583/1583 [==============================] - 161s 101ms/step - loss: 0.0292 - accuracy: 0.9329 - fn: 204564.0000 - fp: 12732.0000 - tn: 1607245.0000 - tp: 1415459.0000 - precision: 0.9911 - recall: 0.8737 - val_loss: 0.1975 - val_accuracy: 0.9301 - val_fn: 24225.0000 - val_fp: 956.0000 - val_tn: 178890.0000 - val_tp: 155929.0000 - val_precision: 0.9939 - val_recall: 0.8655\n", 169 | "Epoch 4/100\n", 170 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0242 - accuracy: 0.9468 - fn: 161066.0000 - fp: 11164.0000 - tn: 1608775.0000 - tp: 1458931.0000 - precision: 0.9924 - recall: 0.9006\n", 171 | "Epoch 00004: val_accuracy improved from 0.93005 to 0.95222, saving model to bilstm_checkpoint\\cp.ckpt\n", 172 | "1583/1583 [==============================] - 154s 97ms/step - loss: 0.0242 - accuracy: 0.9468 - fn: 161070.0000 - fp: 11164.0000 - tn: 1608813.0000 - tp: 1458953.0000 - precision: 0.9924 - recall: 0.9006 - val_loss: 0.1431 - val_accuracy: 0.9522 - val_fn: 15977.0000 - val_fp: 1225.0000 - val_tn: 178621.0000 - val_tp: 164177.0000 - val_precision: 0.9926 - val_recall: 0.9113\n", 173 | "Epoch 5/100\n", 174 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0202 - accuracy: 0.9571 - fn: 129448.0000 - fp: 9503.0000 - tn: 1610441.0000 - tp: 1490544.0000 - precision: 0.9937 - recall: 0.9201\n", 175 | "Epoch 00005: val_accuracy improved from 0.95222 to 0.96236, saving model to bilstm_checkpoint\\cp.ckpt\n", 176 | "1583/1583 [==============================] - 158s 100ms/step - loss: 0.0202 - accuracy: 0.9571 - fn: 129450.0000 - fp: 9503.0000 - tn: 1610474.0000 - tp: 1490573.0000 - precision: 0.9937 - recall: 0.9201 - val_loss: 0.1105 - val_accuracy: 0.9624 - val_fn: 12524.0000 - val_fp: 1028.0000 - val_tn: 178818.0000 - val_tp: 167630.0000 - val_precision: 0.9939 - val_recall: 0.9305\n", 177 | "Epoch 6/100\n", 178 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0174 - accuracy: 0.9637 - fn: 109469.0000 - fp: 8253.0000 - tn: 1611690.0000 - tp: 1510524.0000 - precision: 0.9946 - recall: 0.9324\n", 179 | "Epoch 00006: val_accuracy improved from 0.96236 to 0.96295, saving model to bilstm_checkpoint\\cp.ckpt\n", 180 | "1583/1583 [==============================] - 157s 99ms/step - loss: 0.0174 - accuracy: 0.9637 - fn: 109469.0000 - fp: 8253.0000 - tn: 1611724.0000 - tp: 1510554.0000 - precision: 0.9946 - recall: 0.9324 - val_loss: 0.1136 - val_accuracy: 0.9630 - val_fn: 12584.0000 - val_fp: 753.0000 - val_tn: 179093.0000 - val_tp: 167570.0000 - val_precision: 0.9955 - val_recall: 0.9301\n", 181 | "Epoch 7/100\n", 182 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0153 - accuracy: 0.9685 - fn: 94958.0000 - fp: 7150.0000 - tn: 1612792.0000 - tp: 1525036.0000 - precision: 0.9953 - recall: 0.9414\n", 183 | "Epoch 00007: val_accuracy improved from 0.96295 to 0.97057, saving model to bilstm_checkpoint\\cp.ckpt\n", 184 | "1583/1583 [==============================] - 158s 100ms/step - loss: 0.0153 - accuracy: 0.9685 - fn: 94958.0000 - fp: 7150.0000 - tn: 1612827.0000 - tp: 1525065.0000 - precision: 0.9953 - recall: 0.9414 - val_loss: 0.0880 - val_accuracy: 0.9706 - val_fn: 9721.0000 - val_fp: 872.0000 - val_tn: 178974.0000 - val_tp: 170433.0000 - val_precision: 0.9949 - val_recall: 0.9460\n", 185 | "Epoch 8/100\n", 186 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0136 - accuracy: 0.9721 - fn: 84346.0000 - fp: 6166.0000 - tn: 1613781.0000 - tp: 1535643.0000 - precision: 0.9960 - recall: 0.9479\n", 187 | "Epoch 00008: val_accuracy did not improve from 0.97057\n", 188 | "1583/1583 [==============================] - 157s 99ms/step - loss: 0.0136 - accuracy: 0.9721 - fn: 84347.0000 - fp: 6166.0000 - tn: 1613811.0000 - tp: 1535676.0000 - precision: 0.9960 - recall: 0.9479 - val_loss: 0.0915 - val_accuracy: 0.9704 - val_fn: 10030.0000 - val_fp: 638.0000 - val_tn: 179208.0000 - val_tp: 170124.0000 - val_precision: 0.9963 - val_recall: 0.9443\n", 189 | "Epoch 9/100\n", 190 | "1583/1583 [==============================] - ETA: 0s - loss: 0.0122 - accuracy: 0.9749 - fn: 75861.0000 - fp: 5312.0000 - tn: 1614665.0000 - tp: 1544162.0000 - precision: 0.9966 - recall: 0.9532\n", 191 | "Epoch 00009: val_accuracy improved from 0.97057 to 0.97365, saving model to bilstm_checkpoint\\cp.ckpt\n", 192 | "1583/1583 [==============================] - 158s 100ms/step - loss: 0.0122 - accuracy: 0.9749 - fn: 75861.0000 - fp: 5312.0000 - tn: 1614665.0000 - tp: 1544162.0000 - precision: 0.9966 - recall: 0.9532 - val_loss: 0.0822 - val_accuracy: 0.9736 - val_fn: 8873.0000 - val_fp: 614.0000 - val_tn: 179232.0000 - val_tp: 171281.0000 - val_precision: 0.9964 - val_recall: 0.9507\n", 193 | "Epoch 10/100\n", 194 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0110 - accuracy: 0.9772 - fn: 69287.0000 - fp: 4632.0000 - tn: 1615311.0000 - tp: 1550706.0000 - precision: 0.9970 - recall: 0.9572\n", 195 | "Epoch 00010: val_accuracy improved from 0.97365 to 0.97730, saving model to bilstm_checkpoint\\cp.ckpt\n", 196 | "1583/1583 [==============================] - 158s 100ms/step - loss: 0.0110 - accuracy: 0.9772 - fn: 69290.0000 - fp: 4632.0000 - tn: 1615345.0000 - tp: 1550733.0000 - precision: 0.9970 - recall: 0.9572 - val_loss: 0.0707 - val_accuracy: 0.9773 - val_fn: 7511.0000 - val_fp: 661.0000 - val_tn: 179185.0000 - val_tp: 172643.0000 - val_precision: 0.9962 - val_recall: 0.9583\n", 197 | "Epoch 11/100\n", 198 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0100 - accuracy: 0.9793 - fn: 62937.0000 - fp: 4113.0000 - tn: 1615828.0000 - tp: 1557058.0000 - precision: 0.9974 - recall: 0.9611\n", 199 | "Epoch 00011: val_accuracy improved from 0.97730 to 0.97886, saving model to bilstm_checkpoint\\cp.ckpt\n", 200 | "1583/1583 [==============================] - 158s 100ms/step - loss: 0.0100 - accuracy: 0.9793 - fn: 62938.0000 - fp: 4113.0000 - tn: 1615864.0000 - tp: 1557085.0000 - precision: 0.9974 - recall: 0.9611 - val_loss: 0.0681 - val_accuracy: 0.9789 - val_fn: 6993.0000 - val_fp: 617.0000 - val_tn: 179229.0000 - val_tp: 173161.0000 - val_precision: 0.9964 - val_recall: 0.9612\n", 201 | "Epoch 12/100\n", 202 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0091 - accuracy: 0.9809 - fn: 58264.0000 - fp: 3617.0000 - tn: 1616326.0000 - tp: 1561729.0000 - precision: 0.9977 - recall: 0.9640\n", 203 | "Epoch 00012: val_accuracy did not improve from 0.97886\n", 204 | "1583/1583 [==============================] - 157s 99ms/step - loss: 0.0091 - accuracy: 0.9809 - fn: 58265.0000 - fp: 3618.0000 - tn: 1616359.0000 - tp: 1561758.0000 - precision: 0.9977 - recall: 0.9640 - val_loss: 0.0672 - val_accuracy: 0.9789 - val_fn: 7073.0000 - val_fp: 541.0000 - val_tn: 179305.0000 - val_tp: 173081.0000 - val_precision: 0.9969 - val_recall: 0.9607\n", 205 | "Epoch 13/100\n", 206 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0084 - accuracy: 0.9824 - fn: 53886.0000 - fp: 3123.0000 - tn: 1616819.0000 - tp: 1566108.0000 - precision: 0.9980 - recall: 0.9667\n", 207 | "Epoch 00013: val_accuracy improved from 0.97886 to 0.98129, saving model to bilstm_checkpoint\\cp.ckpt\n", 208 | "1583/1583 [==============================] - 158s 100ms/step - loss: 0.0084 - accuracy: 0.9824 - fn: 53886.0000 - fp: 3123.0000 - tn: 1616854.0000 - tp: 1566137.0000 - precision: 0.9980 - recall: 0.9667 - val_loss: 0.0623 - val_accuracy: 0.9813 - val_fn: 6173.0000 - val_fp: 561.0000 - val_tn: 179285.0000 - val_tp: 173981.0000 - val_precision: 0.9968 - val_recall: 0.9657\n", 209 | "Epoch 14/100\n", 210 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0077 - accuracy: 0.9837 - fn: 50011.0000 - fp: 2822.0000 - tn: 1617119.0000 - tp: 1569984.0000 - precision: 0.9982 - recall: 0.9691\n", 211 | "Epoch 00014: val_accuracy improved from 0.98129 to 0.98151, saving model to bilstm_checkpoint\\cp.ckpt\n", 212 | "1583/1583 [==============================] - 158s 100ms/step - loss: 0.0077 - accuracy: 0.9837 - fn: 50013.0000 - fp: 2822.0000 - tn: 1617155.0000 - tp: 1570010.0000 - precision: 0.9982 - recall: 0.9691 - val_loss: 0.0609 - val_accuracy: 0.9815 - val_fn: 6050.0000 - val_fp: 607.0000 - val_tn: 179239.0000 - val_tp: 174104.0000 - val_precision: 0.9965 - val_recall: 0.9664\n", 213 | "Epoch 15/100\n", 214 | "1583/1583 [==============================] - ETA: 0s - loss: 0.0071 - accuracy: 0.9848 - fn: 46755.0000 - fp: 2592.0000 - tn: 1617385.0000 - tp: 1573268.0000 - precision: 0.9984 - recall: 0.9711 ETA: 5s - loss: 0.0071 - accuracy: 0.9848 -\n", 215 | "Epoch 00015: val_accuracy improved from 0.98151 to 0.98269, saving model to bilstm_checkpoint\\cp.ckpt\n", 216 | "1583/1583 [==============================] - 176s 111ms/step - loss: 0.0071 - accuracy: 0.9848 - fn: 46755.0000 - fp: 2592.0000 - tn: 1617385.0000 - tp: 1573268.0000 - precision: 0.9984 - recall: 0.9711 - val_loss: 0.0590 - val_accuracy: 0.9827 - val_fn: 5716.0000 - val_fp: 515.0000 - val_tn: 179331.0000 - val_tp: 174438.0000 - val_precision: 0.9971 - val_recall: 0.9683\n", 217 | "Epoch 16/100\n", 218 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0068 - accuracy: 0.9855 - fn: 44733.0000 - fp: 2396.0000 - tn: 1617548.0000 - tp: 1575259.0000 - precision: 0.9985 - recall: 0.9724\n", 219 | "Epoch 00016: val_accuracy improved from 0.98269 to 0.98321, saving model to bilstm_checkpoint\\cp.ckpt\n", 220 | "1583/1583 [==============================] - 171s 108ms/step - loss: 0.0068 - accuracy: 0.9855 - fn: 44734.0000 - fp: 2396.0000 - tn: 1617581.0000 - tp: 1575289.0000 - precision: 0.9985 - recall: 0.9724 - val_loss: 0.0572 - val_accuracy: 0.9832 - val_fn: 5512.0000 - val_fp: 534.0000 - val_tn: 179312.0000 - val_tp: 174642.0000 - val_precision: 0.9970 - val_recall: 0.9694\n", 221 | "Epoch 17/100\n", 222 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0063 - accuracy: 0.9866 - fn: 41459.0000 - fp: 2097.0000 - tn: 1617847.0000 - tp: 1578533.0000 - precision: 0.9987 - recall: 0.9744\n", 223 | "Epoch 00017: val_accuracy improved from 0.98321 to 0.98332, saving model to bilstm_checkpoint\\cp.ckpt\n", 224 | "1583/1583 [==============================] - 163s 103ms/step - loss: 0.0063 - accuracy: 0.9866 - fn: 41459.0000 - fp: 2097.0000 - tn: 1617880.0000 - tp: 1578564.0000 - precision: 0.9987 - recall: 0.9744 - val_loss: 0.0569 - val_accuracy: 0.9833 - val_fn: 5287.0000 - val_fp: 717.0000 - val_tn: 179129.0000 - val_tp: 174867.0000 - val_precision: 0.9959 - val_recall: 0.9707\n", 225 | "Epoch 18/100\n", 226 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0059 - accuracy: 0.9874 - fn: 38956.0000 - fp: 1935.0000 - tn: 1618012.0000 - tp: 1581033.0000 - precision: 0.9988 - recall: 0.9760\n", 227 | "Epoch 00018: val_accuracy improved from 0.98332 to 0.98444, saving model to bilstm_checkpoint\\cp.ckpt\n", 228 | "1583/1583 [==============================] - 163s 103ms/step - loss: 0.0059 - accuracy: 0.9874 - fn: 38956.0000 - fp: 1935.0000 - tn: 1618042.0000 - tp: 1581067.0000 - precision: 0.9988 - recall: 0.9760 - val_loss: 0.0545 - val_accuracy: 0.9844 - val_fn: 5078.0000 - val_fp: 523.0000 - val_tn: 179323.0000 - val_tp: 175076.0000 - val_precision: 0.9970 - val_recall: 0.9718\n", 229 | "Epoch 19/100\n", 230 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0056 - accuracy: 0.9879 - fn: 37511.0000 - fp: 1763.0000 - tn: 1618177.0000 - tp: 1582485.0000 - precision: 0.9989 - recall: 0.9768\n", 231 | "Epoch 00019: val_accuracy improved from 0.98444 to 0.98547, saving model to bilstm_checkpoint\\cp.ckpt\n", 232 | "1583/1583 [==============================] - 166s 105ms/step - loss: 0.0056 - accuracy: 0.9879 - fn: 37513.0000 - fp: 1763.0000 - tn: 1618214.0000 - tp: 1582510.0000 - precision: 0.9989 - recall: 0.9768 - val_loss: 0.0511 - val_accuracy: 0.9855 - val_fn: 4684.0000 - val_fp: 547.0000 - val_tn: 179299.0000 - val_tp: 175470.0000 - val_precision: 0.9969 - val_recall: 0.9740\n", 233 | "Epoch 20/100\n", 234 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0054 - accuracy: 0.9884 - fn: 35809.0000 - fp: 1728.0000 - tn: 1618211.0000 - tp: 1584188.0000 - precision: 0.9989 - recall: 0.9779\n", 235 | "Epoch 00020: val_accuracy improved from 0.98547 to 0.98614, saving model to bilstm_checkpoint\\cp.ckpt\n", 236 | "1583/1583 [==============================] - 174s 110ms/step - loss: 0.0054 - accuracy: 0.9884 - fn: 35810.0000 - fp: 1728.0000 - tn: 1618249.0000 - tp: 1584213.0000 - precision: 0.9989 - recall: 0.9779 - val_loss: 0.0495 - val_accuracy: 0.9861 - val_fn: 4451.0000 - val_fp: 539.0000 - val_tn: 179307.0000 - val_tp: 175703.0000 - val_precision: 0.9969 - val_recall: 0.9753\n", 237 | "Epoch 21/100\n", 238 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0050 - accuracy: 0.9893 - fn: 33205.0000 - fp: 1503.0000 - tn: 1618446.0000 - tp: 1586782.0000 - precision: 0.9991 - recall: 0.9795\n", 239 | "Epoch 00021: val_accuracy did not improve from 0.98614\n", 240 | "1583/1583 [==============================] - 166s 105ms/step - loss: 0.0050 - accuracy: 0.9893 - fn: 33207.0000 - fp: 1503.0000 - tn: 1618474.0000 - tp: 1586816.0000 - precision: 0.9991 - recall: 0.9795 - val_loss: 0.0601 - val_accuracy: 0.9834 - val_fn: 5423.0000 - val_fp: 562.0000 - val_tn: 179284.0000 - val_tp: 174731.0000 - val_precision: 0.9968 - val_recall: 0.9699\n", 241 | "Epoch 22/100\n", 242 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0048 - accuracy: 0.9896 - fn: 32103.0000 - fp: 1534.0000 - tn: 1618406.0000 - tp: 1587893.0000 - precision: 0.9990 - recall: 0.9802\n", 243 | "Epoch 00022: val_accuracy did not improve from 0.98614\n", 244 | "1583/1583 [==============================] - 161s 102ms/step - loss: 0.0048 - accuracy: 0.9896 - fn: 32103.0000 - fp: 1534.0000 - tn: 1618443.0000 - tp: 1587920.0000 - precision: 0.9990 - recall: 0.9802 - val_loss: 0.0522 - val_accuracy: 0.9856 - val_fn: 4454.0000 - val_fp: 728.0000 - val_tn: 179118.0000 - val_tp: 175700.0000 - val_precision: 0.9959 - val_recall: 0.9753\n", 245 | "Epoch 23/100\n", 246 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0045 - accuracy: 0.9903 - fn: 30089.0000 - fp: 1338.0000 - tn: 1618604.0000 - tp: 1589905.0000 - precision: 0.9992 - recall: 0.9814\n", 247 | "Epoch 00023: val_accuracy improved from 0.98614 to 0.98631, saving model to bilstm_checkpoint\\cp.ckpt\n", 248 | "1583/1583 [==============================] - 162s 102ms/step - loss: 0.0045 - accuracy: 0.9903 - fn: 30089.0000 - fp: 1338.0000 - tn: 1618639.0000 - tp: 1589934.0000 - precision: 0.9992 - recall: 0.9814 - val_loss: 0.0506 - val_accuracy: 0.9863 - val_fn: 4372.0000 - val_fp: 557.0000 - val_tn: 179289.0000 - val_tp: 175782.0000 - val_precision: 0.9968 - val_recall: 0.9757\n", 249 | "Epoch 24/100\n", 250 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0044 - accuracy: 0.9905 - fn: 29362.0000 - fp: 1280.0000 - tn: 1618668.0000 - tp: 1590626.0000 - precision: 0.9992 - recall: 0.9819\n", 251 | "Epoch 00024: val_accuracy improved from 0.98631 to 0.98661, saving model to bilstm_checkpoint\\cp.ckpt\n", 252 | "1583/1583 [==============================] - 159s 100ms/step - loss: 0.0044 - accuracy: 0.9905 - fn: 29362.0000 - fp: 1280.0000 - tn: 1618697.0000 - tp: 1590661.0000 - precision: 0.9992 - recall: 0.9819 - val_loss: 0.0502 - val_accuracy: 0.9866 - val_fn: 4295.0000 - val_fp: 525.0000 - val_tn: 179321.0000 - val_tp: 175859.0000 - val_precision: 0.9970 - val_recall: 0.9762\n", 253 | "Epoch 25/100\n", 254 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0042 - accuracy: 0.9910 - fn: 27816.0000 - fp: 1229.0000 - tn: 1618717.0000 - tp: 1592174.0000 - precision: 0.9992 - recall: 0.9828\n", 255 | "Epoch 00025: val_accuracy improved from 0.98661 to 0.98786, saving model to bilstm_checkpoint\\cp.ckpt\n", 256 | "1583/1583 [==============================] - 158s 100ms/step - loss: 0.0042 - accuracy: 0.9910 - fn: 27816.0000 - fp: 1229.0000 - tn: 1618748.0000 - tp: 1592207.0000 - precision: 0.9992 - recall: 0.9828 - val_loss: 0.0470 - val_accuracy: 0.9879 - val_fn: 3757.0000 - val_fp: 615.0000 - val_tn: 179231.0000 - val_tp: 176397.0000 - val_precision: 0.9965 - val_recall: 0.9791\n", 257 | "Epoch 26/100\n", 258 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0042 - accuracy: 0.9909 - fn: 28068.0000 - fp: 1260.0000 - tn: 1618683.0000 - tp: 1591925.0000 - precision: 0.9992 - recall: 0.9827\n", 259 | "Epoch 00026: val_accuracy did not improve from 0.98786\n", 260 | "1583/1583 [==============================] - 161s 102ms/step - loss: 0.0042 - accuracy: 0.9909 - fn: 28069.0000 - fp: 1260.0000 - tn: 1618717.0000 - tp: 1591954.0000 - precision: 0.9992 - recall: 0.9827 - val_loss: 0.0511 - val_accuracy: 0.9865 - val_fn: 4292.0000 - val_fp: 564.0000 - val_tn: 179282.0000 - val_tp: 175862.0000 - val_precision: 0.9968 - val_recall: 0.9762\n", 261 | "Epoch 27/100\n", 262 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0039 - accuracy: 0.9917 - fn: 25870.0000 - fp: 1143.0000 - tn: 1618801.0000 - tp: 1594122.0000 - precision: 0.9993 - recall: 0.9840\n", 263 | "Epoch 00027: val_accuracy did not improve from 0.98786\n", 264 | "1583/1583 [==============================] - 164s 104ms/step - loss: 0.0039 - accuracy: 0.9917 - fn: 25872.0000 - fp: 1143.0000 - tn: 1618834.0000 - tp: 1594151.0000 - precision: 0.9993 - recall: 0.9840 - val_loss: 0.0545 - val_accuracy: 0.9857 - val_fn: 4486.0000 - val_fp: 679.0000 - val_tn: 179167.0000 - val_tp: 175668.0000 - val_precision: 0.9961 - val_recall: 0.9751\n", 265 | "Epoch 28/100\n", 266 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0039 - accuracy: 0.9918 - fn: 25513.0000 - fp: 1126.0000 - tn: 1618821.0000 - tp: 1594476.0000 - precision: 0.9993 - recall: 0.9843\n", 267 | "Epoch 00028: val_accuracy did not improve from 0.98786\n", 268 | "1583/1583 [==============================] - 159s 100ms/step - loss: 0.0039 - accuracy: 0.9918 - fn: 25513.0000 - fp: 1126.0000 - tn: 1618851.0000 - tp: 1594510.0000 - precision: 0.9993 - recall: 0.9843 - val_loss: 0.0507 - val_accuracy: 0.9870 - val_fn: 4151.0000 - val_fp: 539.0000 - val_tn: 179307.0000 - val_tp: 176003.0000 - val_precision: 0.9969 - val_recall: 0.9770\n", 269 | "Epoch 29/100\n", 270 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0037 - accuracy: 0.9920 - fn: 24837.0000 - fp: 1066.0000 - tn: 1618882.0000 - tp: 1595151.0000 - precision: 0.9993 - recall: 0.9847\n", 271 | "Epoch 00029: val_accuracy did not improve from 0.98786\n", 272 | "1583/1583 [==============================] - 161s 102ms/step - loss: 0.0037 - accuracy: 0.9920 - fn: 24837.0000 - fp: 1066.0000 - tn: 1618911.0000 - tp: 1595186.0000 - precision: 0.9993 - recall: 0.9847 - val_loss: 0.0494 - val_accuracy: 0.9876 - val_fn: 3878.0000 - val_fp: 581.0000 - val_tn: 179265.0000 - val_tp: 176276.0000 - val_precision: 0.9967 - val_recall: 0.9785\n", 273 | "Epoch 30/100\n", 274 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0037 - accuracy: 0.9921 - fn: 24446.0000 - fp: 1050.0000 - tn: 1618894.0000 - tp: 1595546.0000 - precision: 0.9993 - recall: 0.9849\n", 275 | "Epoch 00030: val_accuracy improved from 0.98786 to 0.98787, saving model to bilstm_checkpoint\\cp.ckpt\n", 276 | "1583/1583 [==============================] - 160s 101ms/step - loss: 0.0037 - accuracy: 0.9921 - fn: 24446.0000 - fp: 1050.0000 - tn: 1618927.0000 - tp: 1595577.0000 - precision: 0.9993 - recall: 0.9849 - val_loss: 0.0475 - val_accuracy: 0.9879 - val_fn: 3745.0000 - val_fp: 620.0000 - val_tn: 179226.0000 - val_tp: 176409.0000 - val_precision: 0.9965 - val_recall: 0.9792\n", 277 | "Epoch 31/100\n", 278 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0036 - accuracy: 0.9924 - fn: 23680.0000 - fp: 1052.0000 - tn: 1618893.0000 - tp: 1596311.0000 - precision: 0.9993 - recall: 0.9854\n", 279 | "Epoch 00031: val_accuracy improved from 0.98787 to 0.98849, saving model to bilstm_checkpoint\\cp.ckpt\n", 280 | "1583/1583 [==============================] - 159s 100ms/step - loss: 0.0036 - accuracy: 0.9924 - fn: 23680.0000 - fp: 1052.0000 - tn: 1618925.0000 - tp: 1596343.0000 - precision: 0.9993 - recall: 0.9854 - val_loss: 0.0465 - val_accuracy: 0.9885 - val_fn: 3538.0000 - val_fp: 607.0000 - val_tn: 179239.0000 - val_tp: 176616.0000 - val_precision: 0.9966 - val_recall: 0.9804\n", 281 | "Epoch 32/100\n", 282 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0033 - accuracy: 0.9929 - fn: 21937.0000 - fp: 936.0000 - tn: 1619009.0000 - tp: 1598054.0000 - precision: 0.9994 - recall: 0.9865\n", 283 | "Epoch 00032: val_accuracy did not improve from 0.98849\n", 284 | "1583/1583 [==============================] - 159s 100ms/step - loss: 0.0033 - accuracy: 0.9929 - fn: 21937.0000 - fp: 936.0000 - tn: 1619041.0000 - tp: 1598086.0000 - precision: 0.9994 - recall: 0.9865 - val_loss: 0.0519 - val_accuracy: 0.9872 - val_fn: 4039.0000 - val_fp: 586.0000 - val_tn: 179260.0000 - val_tp: 176115.0000 - val_precision: 0.9967 - val_recall: 0.9776\n", 285 | "Epoch 33/100\n", 286 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0034 - accuracy: 0.9929 - fn: 22181.0000 - fp: 979.0000 - tn: 1618962.0000 - tp: 1597814.0000 - precision: 0.9994 - recall: 0.9863\n", 287 | "Epoch 00033: val_accuracy improved from 0.98849 to 0.98861, saving model to bilstm_checkpoint\\cp.ckpt\n", 288 | "1583/1583 [==============================] - 160s 101ms/step - loss: 0.0034 - accuracy: 0.9929 - fn: 22181.0000 - fp: 979.0000 - tn: 1618998.0000 - tp: 1597842.0000 - precision: 0.9994 - recall: 0.9863 - val_loss: 0.0464 - val_accuracy: 0.9886 - val_fn: 3488.0000 - val_fp: 613.0000 - val_tn: 179233.0000 - val_tp: 176666.0000 - val_precision: 0.9965 - val_recall: 0.9806\n", 289 | "Epoch 34/100\n", 290 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0032 - accuracy: 0.9932 - fn: 21236.0000 - fp: 947.0000 - tn: 1618989.0000 - tp: 1598764.0000 - precision: 0.9994 - recall: 0.9869\n", 291 | "Epoch 00034: val_accuracy did not improve from 0.98861\n", 292 | "1583/1583 [==============================] - 159s 101ms/step - loss: 0.0032 - accuracy: 0.9932 - fn: 21236.0000 - fp: 947.0000 - tn: 1619030.0000 - tp: 1598787.0000 - precision: 0.9994 - recall: 0.9869 - val_loss: 0.0502 - val_accuracy: 0.9878 - val_fn: 3811.0000 - val_fp: 598.0000 - val_tn: 179248.0000 - val_tp: 176343.0000 - val_precision: 0.9966 - val_recall: 0.9788\n", 293 | "Epoch 35/100\n", 294 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0033 - accuracy: 0.9929 - fn: 21946.0000 - fp: 984.0000 - tn: 1618958.0000 - tp: 1598048.0000 - precision: 0.9994 - recall: 0.9865\n", 295 | "Epoch 00035: val_accuracy did not improve from 0.98861\n", 296 | "1583/1583 [==============================] - 159s 100ms/step - loss: 0.0033 - accuracy: 0.9929 - fn: 21946.0000 - fp: 984.0000 - tn: 1618993.0000 - tp: 1598077.0000 - precision: 0.9994 - recall: 0.9865 - val_loss: 0.0485 - val_accuracy: 0.9883 - val_fn: 3633.0000 - val_fp: 572.0000 - val_tn: 179274.0000 - val_tp: 176521.0000 - val_precision: 0.9968 - val_recall: 0.9798\n", 297 | "Epoch 36/100\n", 298 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0030 - accuracy: 0.9936 - fn: 19843.0000 - fp: 838.0000 - tn: 1619100.0000 - tp: 1600155.0000 - precision: 0.9995 - recall: 0.9878- ETA: 3s - loss: 0.0030 - accuracy: 0.9936 - fn: 19413.0000 - fp: 824.0000 - tn: 1585143.0000 - tp: 1566972.0000 - p\n", 299 | "Epoch 00036: val_accuracy did not improve from 0.98861\n", 300 | "1583/1583 [==============================] - 161s 101ms/step - loss: 0.0030 - accuracy: 0.9936 - fn: 19844.0000 - fp: 839.0000 - tn: 1619138.0000 - tp: 1600179.0000 - precision: 0.9995 - recall: 0.9878 - val_loss: 0.0512 - val_accuracy: 0.9877 - val_fn: 3598.0000 - val_fp: 844.0000 - val_tn: 179002.0000 - val_tp: 176556.0000 - val_precision: 0.9952 - val_recall: 0.9800\n", 301 | "Epoch 37/100\n", 302 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0032 - accuracy: 0.9933 - fn: 20901.0000 - fp: 906.0000 - tn: 1619037.0000 - tp: 1599092.0000 - precision: 0.9994 - recall: 0.9871\n", 303 | "Epoch 00037: val_accuracy did not improve from 0.98861\n", 304 | "1583/1583 [==============================] - 159s 100ms/step - loss: 0.0032 - accuracy: 0.9933 - fn: 20901.0000 - fp: 906.0000 - tn: 1619071.0000 - tp: 1599122.0000 - precision: 0.9994 - recall: 0.9871 - val_loss: 0.0521 - val_accuracy: 0.9878 - val_fn: 3304.0000 - val_fp: 1105.0000 - val_tn: 178741.0000 - val_tp: 176850.0000 - val_precision: 0.9938 - val_recall: 0.9817\n", 305 | "Epoch 38/100\n", 306 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0030 - accuracy: 0.9938 - fn: 19320.0000 - fp: 854.0000 - tn: 1619096.0000 - tp: 1600666.0000 - precision: 0.9995 - recall: 0.9881\n", 307 | "Epoch 00038: val_accuracy did not improve from 0.98861\n", 308 | "1583/1583 [==============================] - 160s 101ms/step - loss: 0.0030 - accuracy: 0.9938 - fn: 19321.0000 - fp: 854.0000 - tn: 1619123.0000 - tp: 1600702.0000 - precision: 0.9995 - recall: 0.9881 - val_loss: 0.0542 - val_accuracy: 0.9870 - val_fn: 3884.0000 - val_fp: 791.0000 - val_tn: 179055.0000 - val_tp: 176270.0000 - val_precision: 0.9955 - val_recall: 0.9784\n", 309 | "Epoch 39/100\n", 310 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0029 - accuracy: 0.9939 - fn: 18938.0000 - fp: 825.0000 - tn: 1619121.0000 - tp: 1601052.0000 - precision: 0.9995 - recall: 0.9883\n", 311 | "Epoch 00039: val_accuracy did not improve from 0.98861\n", 312 | "1583/1583 [==============================] - 159s 101ms/step - loss: 0.0029 - accuracy: 0.9939 - fn: 18938.0000 - fp: 825.0000 - tn: 1619152.0000 - tp: 1601085.0000 - precision: 0.9995 - recall: 0.9883 - val_loss: 0.0506 - val_accuracy: 0.9882 - val_fn: 3666.0000 - val_fp: 577.0000 - val_tn: 179269.0000 - val_tp: 176488.0000 - val_precision: 0.9967 - val_recall: 0.9797\n", 313 | "Epoch 40/100\n", 314 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0029 - accuracy: 0.9940 - fn: 18759.0000 - fp: 822.0000 - tn: 1619129.0000 - tp: 1601226.0000 - precision: 0.9995 - recall: 0.9884\n", 315 | "Epoch 00040: val_accuracy improved from 0.98861 to 0.98893, saving model to bilstm_checkpoint\\cp.ckpt\n", 316 | "1583/1583 [==============================] - 165s 105ms/step - loss: 0.0029 - accuracy: 0.9940 - fn: 18760.0000 - fp: 822.0000 - tn: 1619155.0000 - tp: 1601263.0000 - precision: 0.9995 - recall: 0.9884 - val_loss: 0.0483 - val_accuracy: 0.9889 - val_fn: 2899.0000 - val_fp: 1087.0000 - val_tn: 178759.0000 - val_tp: 177255.0000 - val_precision: 0.9939 - val_recall: 0.9839\n", 317 | "Epoch 41/100\n", 318 | "1583/1583 [==============================] - ETA: 0s - loss: 0.0029 - accuracy: 0.9939 - fn: 18938.0000 - fp: 851.0000 - tn: 1619126.0000 - tp: 1601085.0000 - precision: 0.9995 - recall: 0.9883\n", 319 | "Epoch 00041: val_accuracy did not improve from 0.98893\n", 320 | "1583/1583 [==============================] - 174s 110ms/step - loss: 0.0029 - accuracy: 0.9939 - fn: 18938.0000 - fp: 851.0000 - tn: 1619126.0000 - tp: 1601085.0000 - precision: 0.9995 - recall: 0.9883 - val_loss: 0.0606 - val_accuracy: 0.9861 - val_fn: 3367.0000 - val_fp: 1630.0000 - val_tn: 178216.0000 - val_tp: 176787.0000 - val_precision: 0.9909 - val_recall: 0.9813\n", 321 | "Epoch 42/100\n", 322 | "1583/1583 [==============================] - ETA: 0s - loss: 0.0028 - accuracy: 0.9941 - fn: 18443.0000 - fp: 830.0000 - tn: 1619147.0000 - tp: 1601580.0000 - precision: 0.9995 - recall: 0.9886\n", 323 | "Epoch 00042: val_accuracy did not improve from 0.98893\n", 324 | "1583/1583 [==============================] - 176s 111ms/step - loss: 0.0028 - accuracy: 0.9941 - fn: 18443.0000 - fp: 830.0000 - tn: 1619147.0000 - tp: 1601580.0000 - precision: 0.9995 - recall: 0.9886 - val_loss: 0.0511 - val_accuracy: 0.9880 - val_fn: 3747.0000 - val_fp: 568.0000 - val_tn: 179278.0000 - val_tp: 176407.0000 - val_precision: 0.9968 - val_recall: 0.9792\n", 325 | "Epoch 43/100\n", 326 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0027 - accuracy: 0.9943 - fn: 17679.0000 - fp: 778.0000 - tn: 1619165.0000 - tp: 1602314.0000 - precision: 0.9995 - recall: 0.9891\n", 327 | "Epoch 00043: val_accuracy did not improve from 0.98893\n", 328 | "1583/1583 [==============================] - 175s 110ms/step - loss: 0.0027 - accuracy: 0.9943 - fn: 17679.0000 - fp: 778.0000 - tn: 1619199.0000 - tp: 1602344.0000 - precision: 0.9995 - recall: 0.9891 - val_loss: 0.0482 - val_accuracy: 0.9888 - val_fn: 3443.0000 - val_fp: 593.0000 - val_tn: 179253.0000 - val_tp: 176711.0000 - val_precision: 0.9967 - val_recall: 0.9809\n", 329 | "Epoch 44/100\n", 330 | "1583/1583 [==============================] - ETA: 0s - loss: 0.0027 - accuracy: 0.9944 - fn: 17312.0000 - fp: 792.0000 - tn: 1619185.0000 - tp: 1602711.0000 - precision: 0.9995 - recall: 0.9893\n", 331 | "Epoch 00044: val_accuracy did not improve from 0.98893\n", 332 | "1583/1583 [==============================] - 175s 110ms/step - loss: 0.0027 - accuracy: 0.9944 - fn: 17312.0000 - fp: 792.0000 - tn: 1619185.0000 - tp: 1602711.0000 - precision: 0.9995 - recall: 0.9893 - val_loss: 0.0507 - val_accuracy: 0.9883 - val_fn: 3421.0000 - val_fp: 792.0000 - val_tn: 179054.0000 - val_tp: 176733.0000 - val_precision: 0.9955 - val_recall: 0.9810\n", 333 | "Epoch 45/100\n", 334 | "1583/1583 [==============================] - ETA: 0s - loss: 0.0027 - accuracy: 0.9943 - fn: 17533.0000 - fp: 798.0000 - tn: 1619179.0000 - tp: 1602490.0000 - precision: 0.9995 - recall: 0.9892\n", 335 | "Epoch 00045: val_accuracy improved from 0.98893 to 0.98902, saving model to bilstm_checkpoint\\cp.ckpt\n", 336 | "1583/1583 [==============================] - 175s 111ms/step - loss: 0.0027 - accuracy: 0.9943 - fn: 17533.0000 - fp: 798.0000 - tn: 1619179.0000 - tp: 1602490.0000 - precision: 0.9995 - recall: 0.9892 - val_loss: 0.0477 - val_accuracy: 0.9890 - val_fn: 3344.0000 - val_fp: 608.0000 - val_tn: 179238.0000 - val_tp: 176810.0000 - val_precision: 0.9966 - val_recall: 0.9814\n", 337 | "Epoch 46/100\n", 338 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0025 - accuracy: 0.9948 - fn: 16140.0000 - fp: 726.0000 - tn: 1619215.0000 - tp: 1603855.0000 - precision: 0.9995 - recall: 0.9900\n", 339 | "Epoch 00046: val_accuracy did not improve from 0.98902\n", 340 | "1583/1583 [==============================] - 175s 111ms/step - loss: 0.0025 - accuracy: 0.9948 - fn: 16140.0000 - fp: 726.0000 - tn: 1619251.0000 - tp: 1603883.0000 - precision: 0.9995 - recall: 0.9900 - val_loss: 0.0554 - val_accuracy: 0.9879 - val_fn: 3302.0000 - val_fp: 1070.0000 - val_tn: 178776.0000 - val_tp: 176852.0000 - val_precision: 0.9940 - val_recall: 0.9817\n", 341 | "Epoch 47/100\n", 342 | "1583/1583 [==============================] - ETA: 0s - loss: 0.0026 - accuracy: 0.9945 - fn: 17093.0000 - fp: 806.0000 - tn: 1619171.0000 - tp: 1602930.0000 - precision: 0.9995 - recall: 0.9894\n", 343 | "Epoch 00047: val_accuracy did not improve from 0.98902\n", 344 | "1583/1583 [==============================] - 176s 111ms/step - loss: 0.0026 - accuracy: 0.9945 - fn: 17093.0000 - fp: 806.0000 - tn: 1619171.0000 - tp: 1602930.0000 - precision: 0.9995 - recall: 0.9894 - val_loss: 0.0573 - val_accuracy: 0.9875 - val_fn: 3237.0000 - val_fp: 1274.0000 - val_tn: 178572.0000 - val_tp: 176917.0000 - val_precision: 0.9929 - val_recall: 0.9820\n", 345 | "Epoch 48/100\n", 346 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0025 - accuracy: 0.9948 - fn: 16010.0000 - fp: 710.0000 - tn: 1619231.0000 - tp: 1603985.0000 - precision: 0.9996 - recall: 0.9901\n", 347 | "Epoch 00048: val_accuracy did not improve from 0.98902\n", 348 | "1583/1583 [==============================] - 176s 111ms/step - loss: 0.0025 - accuracy: 0.9948 - fn: 16010.0000 - fp: 710.0000 - tn: 1619267.0000 - tp: 1604013.0000 - precision: 0.9996 - recall: 0.9901 - val_loss: 0.0509 - val_accuracy: 0.9888 - val_fn: 3141.0000 - val_fp: 885.0000 - val_tn: 178961.0000 - val_tp: 177013.0000 - val_precision: 0.9950 - val_recall: 0.9826\n", 349 | "Epoch 49/100\n", 350 | "1583/1583 [==============================] - ETA: 0s - loss: 0.0026 - accuracy: 0.9945 - fn: 16975.0000 - fp: 814.0000 - tn: 1619163.0000 - tp: 1603048.0000 - precision: 0.9995 - recall: 0.9895\n", 351 | "Epoch 00049: val_accuracy did not improve from 0.98902\n", 352 | "1583/1583 [==============================] - 172s 109ms/step - loss: 0.0026 - accuracy: 0.9945 - fn: 16975.0000 - fp: 814.0000 - tn: 1619163.0000 - tp: 1603048.0000 - precision: 0.9995 - recall: 0.9895 - val_loss: 0.0498 - val_accuracy: 0.9885 - val_fn: 3542.0000 - val_fp: 608.0000 - val_tn: 179238.0000 - val_tp: 176612.0000 - val_precision: 0.9966 - val_recall: 0.9803\n", 353 | "Epoch 50/100\n", 354 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0025 - accuracy: 0.9948 - fn: 16024.0000 - fp: 739.0000 - tn: 1619199.0000 - tp: 1603974.0000 - precision: 0.9995 - recall: 0.9901\n", 355 | "Epoch 00050: val_accuracy did not improve from 0.98902\n", 356 | "1583/1583 [==============================] - 172s 109ms/step - loss: 0.0025 - accuracy: 0.9948 - fn: 16025.0000 - fp: 739.0000 - tn: 1619238.0000 - tp: 1603998.0000 - precision: 0.9995 - recall: 0.9901 - val_loss: 0.0525 - val_accuracy: 0.9882 - val_fn: 3659.0000 - val_fp: 582.0000 - val_tn: 179264.0000 - val_tp: 176495.0000 - val_precision: 0.9967 - val_recall: 0.9797\n", 357 | "Epoch 51/100\n", 358 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0024 - accuracy: 0.9949 - fn: 15754.0000 - fp: 715.0000 - tn: 1619230.0000 - tp: 1604237.0000 - precision: 0.9996 - recall: 0.9903\n", 359 | "Epoch 00051: val_accuracy improved from 0.98902 to 0.98906, saving model to bilstm_checkpoint\\cp.ckpt\n", 360 | "1583/1583 [==============================] - 172s 109ms/step - loss: 0.0024 - accuracy: 0.9949 - fn: 15754.0000 - fp: 715.0000 - tn: 1619262.0000 - tp: 1604269.0000 - precision: 0.9996 - recall: 0.9903 - val_loss: 0.0495 - val_accuracy: 0.9891 - val_fn: 3318.0000 - val_fp: 620.0000 - val_tn: 179226.0000 - val_tp: 176836.0000 - val_precision: 0.9965 - val_recall: 0.9816\n", 361 | "Epoch 52/100\n", 362 | "1583/1583 [==============================] - ETA: 0s - loss: 0.0024 - accuracy: 0.9950 - fn: 15649.0000 - fp: 689.0000 - tn: 1619288.0000 - tp: 1604374.0000 - precision: 0.9996 - recall: 0.9903\n", 363 | "Epoch 00052: val_accuracy did not improve from 0.98906\n", 364 | "1583/1583 [==============================] - 173s 110ms/step - loss: 0.0024 - accuracy: 0.9950 - fn: 15649.0000 - fp: 689.0000 - tn: 1619288.0000 - tp: 1604374.0000 - precision: 0.9996 - recall: 0.9903 - val_loss: 0.0526 - val_accuracy: 0.9882 - val_fn: 3422.0000 - val_fp: 818.0000 - val_tn: 179028.0000 - val_tp: 176732.0000 - val_precision: 0.9954 - val_recall: 0.9810\n", 365 | "Epoch 53/100\n", 366 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0023 - accuracy: 0.9952 - fn: 14932.0000 - fp: 679.0000 - tn: 1619262.0000 - tp: 1605063.0000 - precision: 0.9996 - recall: 0.9908\n", 367 | "Epoch 00053: val_accuracy did not improve from 0.98906\n", 368 | "1583/1583 [==============================] - 163s 103ms/step - loss: 0.0023 - accuracy: 0.9952 - fn: 14932.0000 - fp: 679.0000 - tn: 1619298.0000 - tp: 1605091.0000 - precision: 0.9996 - recall: 0.9908 - val_loss: 0.0529 - val_accuracy: 0.9887 - val_fn: 3216.0000 - val_fp: 856.0000 - val_tn: 178990.0000 - val_tp: 176938.0000 - val_precision: 0.9952 - val_recall: 0.9821\n", 369 | "Epoch 54/100\n", 370 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0025 - accuracy: 0.9947 - fn: 16331.0000 - fp: 755.0000 - tn: 1619187.0000 - tp: 1603663.0000 - precision: 0.9995 - recall: 0.9899\n", 371 | "Epoch 00054: val_accuracy did not improve from 0.98906\n", 372 | "1583/1583 [==============================] - 164s 104ms/step - loss: 0.0025 - accuracy: 0.9947 - fn: 16331.0000 - fp: 755.0000 - tn: 1619222.0000 - tp: 1603692.0000 - precision: 0.9995 - recall: 0.9899 - val_loss: 0.0530 - val_accuracy: 0.9887 - val_fn: 3234.0000 - val_fp: 836.0000 - val_tn: 179010.0000 - val_tp: 176920.0000 - val_precision: 0.9953 - val_recall: 0.9820\n", 373 | "Epoch 55/100\n", 374 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0023 - accuracy: 0.9951 - fn: 15199.0000 - fp: 693.0000 - tn: 1619261.0000 - tp: 1604783.0000 - precision: 0.9996 - recall: 0.9906\n", 375 | "Epoch 00055: val_accuracy did not improve from 0.98906\n", 376 | "1583/1583 [==============================] - 163s 103ms/step - loss: 0.0023 - accuracy: 0.9951 - fn: 15199.0000 - fp: 693.0000 - tn: 1619284.0000 - tp: 1604824.0000 - precision: 0.9996 - recall: 0.9906 - val_loss: 0.0530 - val_accuracy: 0.9883 - val_fn: 3343.0000 - val_fp: 868.0000 - val_tn: 178978.0000 - val_tp: 176811.0000 - val_precision: 0.9951 - val_recall: 0.9814\n", 377 | "Epoch 56/100\n", 378 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0022 - accuracy: 0.9953 - fn: 14560.0000 - fp: 676.0000 - tn: 1619265.0000 - tp: 1605435.0000 - precision: 0.9996 - recall: 0.9910\n", 379 | "Epoch 00056: val_accuracy did not improve from 0.98906\n", 380 | "1583/1583 [==============================] - 160s 101ms/step - loss: 0.0022 - accuracy: 0.9953 - fn: 14561.0000 - fp: 676.0000 - tn: 1619301.0000 - tp: 1605462.0000 - precision: 0.9996 - recall: 0.9910 - val_loss: 0.0701 - val_accuracy: 0.9857 - val_fn: 3269.0000 - val_fp: 1867.0000 - val_tn: 177979.0000 - val_tp: 176885.0000 - val_precision: 0.9896 - val_recall: 0.9819\n", 381 | "Epoch 57/100\n", 382 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0023 - accuracy: 0.9952 - fn: 14715.0000 - fp: 687.0000 - tn: 1619258.0000 - tp: 1605276.0000 - precision: 0.9996 - recall: 0.9909\n", 383 | "Epoch 00057: val_accuracy improved from 0.98906 to 0.98940, saving model to bilstm_checkpoint\\cp.ckpt\n", 384 | "1583/1583 [==============================] - 160s 101ms/step - loss: 0.0023 - accuracy: 0.9952 - fn: 14715.0000 - fp: 687.0000 - tn: 1619290.0000 - tp: 1605308.0000 - precision: 0.9996 - recall: 0.9909 - val_loss: 0.0504 - val_accuracy: 0.9894 - val_fn: 3184.0000 - val_fp: 632.0000 - val_tn: 179214.0000 - val_tp: 176970.0000 - val_precision: 0.9964 - val_recall: 0.9823\n", 385 | "Epoch 58/100\n", 386 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0023 - accuracy: 0.9952 - fn: 14715.0000 - fp: 704.0000 - tn: 1619237.0000 - tp: 1605280.0000 - precision: 0.9996 - recall: 0.9909\n", 387 | "Epoch 00058: val_accuracy did not improve from 0.98940\n", 388 | "1583/1583 [==============================] - 168s 106ms/step - loss: 0.0023 - accuracy: 0.9952 - fn: 14715.0000 - fp: 704.0000 - tn: 1619273.0000 - tp: 1605308.0000 - precision: 0.9996 - recall: 0.9909 - val_loss: 0.0677 - val_accuracy: 0.9858 - val_fn: 3423.0000 - val_fp: 1699.0000 - val_tn: 178147.0000 - val_tp: 176731.0000 - val_precision: 0.9905 - val_recall: 0.9810\n", 389 | "Epoch 59/100\n", 390 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0022 - accuracy: 0.9954 - fn: 14266.0000 - fp: 631.0000 - tn: 1619312.0000 - tp: 1605727.0000 - precision: 0.9996 - recall: 0.9912\n", 391 | "Epoch 00059: val_accuracy did not improve from 0.98940\n", 392 | "1583/1583 [==============================] - 161s 102ms/step - loss: 0.0022 - accuracy: 0.9954 - fn: 14266.0000 - fp: 632.0000 - tn: 1619345.0000 - tp: 1605757.0000 - precision: 0.9996 - recall: 0.9912 - val_loss: 0.0511 - val_accuracy: 0.9892 - val_fn: 3264.0000 - val_fp: 623.0000 - val_tn: 179223.0000 - val_tp: 176890.0000 - val_precision: 0.9965 - val_recall: 0.9819\n", 393 | "Epoch 60/100\n", 394 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0024 - accuracy: 0.9951 - fn: 15118.0000 - fp: 714.0000 - tn: 1619227.0000 - tp: 1604877.0000 - precision: 0.9996 - recall: 0.9907\n", 395 | "Epoch 00060: val_accuracy improved from 0.98940 to 0.98984, saving model to bilstm_checkpoint\\cp.ckpt\n", 396 | "1583/1583 [==============================] - 163s 103ms/step - loss: 0.0024 - accuracy: 0.9951 - fn: 15118.0000 - fp: 714.0000 - tn: 1619263.0000 - tp: 1604905.0000 - precision: 0.9996 - recall: 0.9907 - val_loss: 0.0474 - val_accuracy: 0.9898 - val_fn: 3015.0000 - val_fp: 643.0000 - val_tn: 179203.0000 - val_tp: 177139.0000 - val_precision: 0.9964 - val_recall: 0.9833\n", 397 | "Epoch 61/100\n", 398 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0023 - accuracy: 0.9952 - fn: 14711.0000 - fp: 730.0000 - tn: 1619222.0000 - tp: 1605273.0000 - precision: 0.9995 - recall: 0.9909\n", 399 | "Epoch 00061: val_accuracy did not improve from 0.98984\n", 400 | "1583/1583 [==============================] - 160s 101ms/step - loss: 0.0023 - accuracy: 0.9952 - fn: 14711.0000 - fp: 730.0000 - tn: 1619247.0000 - tp: 1605312.0000 - precision: 0.9995 - recall: 0.9909 - val_loss: 0.0630 - val_accuracy: 0.9865 - val_fn: 3439.0000 - val_fp: 1403.0000 - val_tn: 178443.0000 - val_tp: 176715.0000 - val_precision: 0.9921 - val_recall: 0.9809\n", 401 | "Epoch 62/100\n", 402 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0021 - accuracy: 0.9957 - fn: 13211.0000 - fp: 599.0000 - tn: 1619355.0000 - tp: 1606771.0000 - precision: 0.9996 - recall: 0.9918\n", 403 | "Epoch 00062: val_accuracy did not improve from 0.98984\n", 404 | "1583/1583 [==============================] - 161s 101ms/step - loss: 0.0021 - accuracy: 0.9957 - fn: 13211.0000 - fp: 599.0000 - tn: 1619378.0000 - tp: 1606812.0000 - precision: 0.9996 - recall: 0.9918 - val_loss: 0.0540 - val_accuracy: 0.9888 - val_fn: 3184.0000 - val_fp: 843.0000 - val_tn: 179003.0000 - val_tp: 176970.0000 - val_precision: 0.9953 - val_recall: 0.9823\n", 405 | "Epoch 63/100\n", 406 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0022 - accuracy: 0.9955 - fn: 14043.0000 - fp: 646.0000 - tn: 1619299.0000 - tp: 1605948.0000 - precision: 0.9996 - recall: 0.9913\n", 407 | "Epoch 00063: val_accuracy did not improve from 0.98984\n", 408 | "1583/1583 [==============================] - 162s 103ms/step - loss: 0.0022 - accuracy: 0.9955 - fn: 14043.0000 - fp: 646.0000 - tn: 1619331.0000 - tp: 1605980.0000 - precision: 0.9996 - recall: 0.9913 - val_loss: 0.0524 - val_accuracy: 0.9892 - val_fn: 2991.0000 - val_fp: 895.0000 - val_tn: 178951.0000 - val_tp: 177163.0000 - val_precision: 0.9950 - val_recall: 0.9834\n", 409 | "Epoch 64/100\n", 410 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0022 - accuracy: 0.9955 - fn: 14015.0000 - fp: 693.0000 - tn: 1619251.0000 - tp: 1605977.0000 - precision: 0.9996 - recall: 0.9913\n", 411 | "Epoch 00064: val_accuracy did not improve from 0.98984\n", 412 | "1583/1583 [==============================] - 161s 102ms/step - loss: 0.0022 - accuracy: 0.9955 - fn: 14015.0000 - fp: 693.0000 - tn: 1619284.0000 - tp: 1606008.0000 - precision: 0.9996 - recall: 0.9913 - val_loss: 0.0528 - val_accuracy: 0.9892 - val_fn: 3014.0000 - val_fp: 880.0000 - val_tn: 178966.0000 - val_tp: 177140.0000 - val_precision: 0.9951 - val_recall: 0.9833\n", 413 | "Epoch 65/100\n", 414 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0022 - accuracy: 0.9955 - fn: 13952.0000 - fp: 703.0000 - tn: 1619238.0000 - tp: 1606043.0000 - precision: 0.9996 - recall: 0.9914\n", 415 | "Epoch 00065: val_accuracy did not improve from 0.98984\n", 416 | "1583/1583 [==============================] - 161s 102ms/step - loss: 0.0022 - accuracy: 0.9955 - fn: 13952.0000 - fp: 703.0000 - tn: 1619274.0000 - tp: 1606071.0000 - precision: 0.9996 - recall: 0.9914 - val_loss: 0.0510 - val_accuracy: 0.9890 - val_fn: 3348.0000 - val_fp: 613.0000 - val_tn: 179233.0000 - val_tp: 176806.0000 - val_precision: 0.9965 - val_recall: 0.9814\n", 417 | "Epoch 66/100\n", 418 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0021 - accuracy: 0.9958 - fn: 13091.0000 - fp: 650.0000 - tn: 1619294.0000 - tp: 1606901.0000 - precision: 0.9996 - recall: 0.9919\n", 419 | "Epoch 00066: val_accuracy improved from 0.98984 to 0.98992, saving model to bilstm_checkpoint\\cp.ckpt\n", 420 | "1583/1583 [==============================] - 163s 103ms/step - loss: 0.0021 - accuracy: 0.9958 - fn: 13091.0000 - fp: 650.0000 - tn: 1619327.0000 - tp: 1606932.0000 - precision: 0.9996 - recall: 0.9919 - val_loss: 0.0482 - val_accuracy: 0.9899 - val_fn: 2970.0000 - val_fp: 660.0000 - val_tn: 179186.0000 - val_tp: 177184.0000 - val_precision: 0.9963 - val_recall: 0.9835\n", 421 | "Epoch 67/100\n", 422 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0023 - accuracy: 0.9953 - fn: 14622.0000 - fp: 745.0000 - tn: 1619201.0000 - tp: 1605368.0000 - precision: 0.9995 - recall: 0.9910\n", 423 | "Epoch 00067: val_accuracy did not improve from 0.98992\n", 424 | "1583/1583 [==============================] - 159s 101ms/step - loss: 0.0023 - accuracy: 0.9953 - fn: 14622.0000 - fp: 745.0000 - tn: 1619232.0000 - tp: 1605401.0000 - precision: 0.9995 - recall: 0.9910 - val_loss: 0.0527 - val_accuracy: 0.9891 - val_fn: 3025.0000 - val_fp: 916.0000 - val_tn: 178930.0000 - val_tp: 177129.0000 - val_precision: 0.9949 - val_recall: 0.9832\n", 425 | "Epoch 68/100\n", 426 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0020 - accuracy: 0.9958 - fn: 12846.0000 - fp: 611.0000 - tn: 1619338.0000 - tp: 1607141.0000 - precision: 0.9996 - recall: 0.9921\n", 427 | "Epoch 00068: val_accuracy did not improve from 0.98992\n", 428 | "1583/1583 [==============================] - 162s 102ms/step - loss: 0.0020 - accuracy: 0.9958 - fn: 12847.0000 - fp: 611.0000 - tn: 1619366.0000 - tp: 1607176.0000 - precision: 0.9996 - recall: 0.9921 - val_loss: 0.0598 - val_accuracy: 0.9876 - val_fn: 3638.0000 - val_fp: 826.0000 - val_tn: 179020.0000 - val_tp: 176516.0000 - val_precision: 0.9953 - val_recall: 0.9798\n", 429 | "Epoch 69/100\n", 430 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0021 - accuracy: 0.9956 - fn: 13714.0000 - fp: 683.0000 - tn: 1619264.0000 - tp: 1606275.0000 - precision: 0.9996 - recall: 0.9915\n", 431 | "Epoch 00069: val_accuracy did not improve from 0.98992\n", 432 | "1583/1583 [==============================] - 161s 101ms/step - loss: 0.0021 - accuracy: 0.9956 - fn: 13714.0000 - fp: 683.0000 - tn: 1619294.0000 - tp: 1606309.0000 - precision: 0.9996 - recall: 0.9915 - val_loss: 0.0522 - val_accuracy: 0.9892 - val_fn: 3015.0000 - val_fp: 869.0000 - val_tn: 178977.0000 - val_tp: 177139.0000 - val_precision: 0.9951 - val_recall: 0.9833\n", 433 | "Epoch 70/100\n", 434 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0021 - accuracy: 0.9957 - fn: 13259.0000 - fp: 635.0000 - tn: 1619307.0000 - tp: 1606735.0000 - precision: 0.9996 - recall: 0.9918\n", 435 | "Epoch 00070: val_accuracy did not improve from 0.98992\n", 436 | "1583/1583 [==============================] - 163s 103ms/step - loss: 0.0021 - accuracy: 0.9957 - fn: 13260.0000 - fp: 635.0000 - tn: 1619342.0000 - tp: 1606763.0000 - precision: 0.9996 - recall: 0.9918 - val_loss: 0.0511 - val_accuracy: 0.9895 - val_fn: 3119.0000 - val_fp: 665.0000 - val_tn: 179181.0000 - val_tp: 177035.0000 - val_precision: 0.9963 - val_recall: 0.9827\n", 437 | "Epoch 71/100\n", 438 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0021 - accuracy: 0.9957 - fn: 13187.0000 - fp: 638.0000 - tn: 1619310.0000 - tp: 1606801.0000 - precision: 0.9996 - recall: 0.9919\n", 439 | "Epoch 00071: val_accuracy did not improve from 0.98992\n", 440 | "1583/1583 [==============================] - 161s 102ms/step - loss: 0.0021 - accuracy: 0.9957 - fn: 13187.0000 - fp: 638.0000 - tn: 1619339.0000 - tp: 1606836.0000 - precision: 0.9996 - recall: 0.9919 - val_loss: 0.0717 - val_accuracy: 0.9855 - val_fn: 3254.0000 - val_fp: 1968.0000 - val_tn: 177878.0000 - val_tp: 176900.0000 - val_precision: 0.9890 - val_recall: 0.9819\n", 441 | "Epoch 72/100\n", 442 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0020 - accuracy: 0.9958 - fn: 12885.0000 - fp: 655.0000 - tn: 1619293.0000 - tp: 1607103.0000 - precision: 0.9996 - recall: 0.9920\n", 443 | "Epoch 00072: val_accuracy did not improve from 0.98992\n", 444 | "1583/1583 [==============================] - 162s 103ms/step - loss: 0.0020 - accuracy: 0.9958 - fn: 12885.0000 - fp: 655.0000 - tn: 1619322.0000 - tp: 1607138.0000 - precision: 0.9996 - recall: 0.9920 - val_loss: 0.0634 - val_accuracy: 0.9870 - val_fn: 3363.0000 - val_fp: 1301.0000 - val_tn: 178545.0000 - val_tp: 176791.0000 - val_precision: 0.9927 - val_recall: 0.9813\n", 445 | "Epoch 73/100\n", 446 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0021 - accuracy: 0.9957 - fn: 13406.0000 - fp: 685.0000 - tn: 1619260.0000 - tp: 1606585.0000 - precision: 0.9996 - recall: 0.9917\n", 447 | "Epoch 00073: val_accuracy did not improve from 0.98992\n", 448 | "1583/1583 [==============================] - 161s 102ms/step - loss: 0.0021 - accuracy: 0.9957 - fn: 13407.0000 - fp: 685.0000 - tn: 1619292.0000 - tp: 1606616.0000 - precision: 0.9996 - recall: 0.9917 - val_loss: 0.0517 - val_accuracy: 0.9889 - val_fn: 3338.0000 - val_fp: 664.0000 - val_tn: 179182.0000 - val_tp: 176816.0000 - val_precision: 0.9963 - val_recall: 0.9815\n", 449 | "Epoch 74/100\n", 450 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0020 - accuracy: 0.9959 - fn: 12753.0000 - fp: 596.0000 - tn: 1619352.0000 - tp: 1607235.0000 - precision: 0.9996 - recall: 0.9921\n", 451 | "Epoch 00074: val_accuracy did not improve from 0.98992\n", 452 | "1583/1583 [==============================] - 161s 102ms/step - loss: 0.0020 - accuracy: 0.9959 - fn: 12753.0000 - fp: 596.0000 - tn: 1619381.0000 - tp: 1607270.0000 - precision: 0.9996 - recall: 0.9921 - val_loss: 0.0650 - val_accuracy: 0.9870 - val_fn: 3282.0000 - val_fp: 1399.0000 - val_tn: 178447.0000 - val_tp: 176872.0000 - val_precision: 0.9922 - val_recall: 0.9818\n", 453 | "Epoch 75/100\n", 454 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0019 - accuracy: 0.9960 - fn: 12275.0000 - fp: 586.0000 - tn: 1619359.0000 - tp: 1607716.0000 - precision: 0.9996 - recall: 0.9924\n", 455 | "Epoch 00075: val_accuracy did not improve from 0.98992\n", 456 | "1583/1583 [==============================] - 164s 103ms/step - loss: 0.0019 - accuracy: 0.9960 - fn: 12275.0000 - fp: 586.0000 - tn: 1619391.0000 - tp: 1607748.0000 - precision: 0.9996 - recall: 0.9924 - val_loss: 0.0552 - val_accuracy: 0.9888 - val_fn: 3091.0000 - val_fp: 939.0000 - val_tn: 178907.0000 - val_tp: 177063.0000 - val_precision: 0.9947 - val_recall: 0.9828\n", 457 | "Epoch 76/100\n", 458 | "1582/1583 [============================>.] - ETA: 0s - loss: 0.0020 - accuracy: 0.9959 - fn: 12629.0000 - fp: 616.0000 - tn: 1619327.0000 - tp: 1607364.0000 - precision: 0.9996 - recall: 0.9922\n", 459 | "Epoch 00076: val_accuracy did not improve from 0.98992\n", 460 | "1583/1583 [==============================] - 162s 102ms/step - loss: 0.0020 - accuracy: 0.9959 - fn: 12629.0000 - fp: 616.0000 - tn: 1619361.0000 - tp: 1607394.0000 - precision: 0.9996 - recall: 0.9922 - val_loss: 0.0506 - val_accuracy: 0.9896 - val_fn: 3053.0000 - val_fp: 700.0000 - val_tn: 179146.0000 - val_tp: 177101.0000 - val_precision: 0.9961 - val_recall: 0.9831\n", 461 | "Epoch 00076: early stopping\n" 462 | ] 463 | } 464 | ], 465 | "source": [ 466 | "# early stopping for regularization\n", 467 | "#es = EarlyStopping(monitor='val_accuracy', mode='max', patience=10, min_delta=.001, verbose=1)\n", 468 | "es = EarlyStopping(monitor='val_accuracy', mode='max', patience=10, verbose=1)\n", 469 | "mc = ModelCheckpoint(filepath=checkpoint_path, monitor='val_accuracy', mode='max', save_best_only=True, save_weights_only=True, verbose=1)\n", 470 | "\n", 471 | "# fit model using class weights to minimize false positives\n", 472 | "history = model.fit(\n", 473 | " X_train,\n", 474 | " y_train,\n", 475 | " validation_split=.1,\n", 476 | " batch_size=2048,\n", 477 | " epochs=100,\n", 478 | " callbacks=[es, mc],\n", 479 | " verbose=1,\n", 480 | " class_weight = {0: 0.9, 1: 0.1}\n", 481 | ")" 482 | ] 483 | }, 484 | { 485 | "cell_type": "code", 486 | "execution_count": 6, 487 | "metadata": {}, 488 | "outputs": [ 489 | { 490 | "name": "stdout", 491 | "output_type": "stream", 492 | "text": [ 493 | "Best epoch : 65\n", 494 | " validation accuracy : 0.98992\n", 495 | " validation tn : 177184\n", 496 | " validation fp : 660\n", 497 | " validation fn : 2970\n", 498 | " validation tp : 177184\n" 499 | ] 500 | } 501 | ], 502 | "source": [ 503 | "val_max_index = np.argmax(history.history[\"val_accuracy\"])\n", 504 | "print(f\"Best epoch : {val_max_index}\")\n", 505 | "print(f\" validation accuracy : {round(history.history['val_accuracy'][val_max_index], 5)}\")\n", 506 | "print(f\" validation tn : {int(history.history['val_tp'][val_max_index])}\")\n", 507 | "print(f\" validation fp : {int(history.history['val_fp'][val_max_index])}\")\n", 508 | "print(f\" validation fn : {int(history.history['val_fn'][val_max_index])}\")\n", 509 | "print(f\" validation tp : {int(history.history['val_tp'][val_max_index])}\")" 510 | ] 511 | }, 512 | { 513 | "cell_type": "code", 514 | "execution_count": 7, 515 | "metadata": {}, 516 | "outputs": [ 517 | { 518 | "data": { 519 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAAlkAAAGbCAYAAAD3MIVlAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAA0SElEQVR4nO3deXic9X3v/c93dmlGi63F2JKw5QWDIdiAMU4MYUmbmiVxTmgotAmBNPWhgZZep20OJ2fpkzztafs8fbpwDoFCCtmTJhCK0zjhZCMQggGbsNgYY1vYlrxp35fRzPyeP2Zky0K2RtaMbknzfl3XXDNzzz2a7/wQ9se/7TbnnAAAAJBbPq8LAAAAmIsIWQAAAHlAyAIAAMgDQhYAAEAeELIAAADyIOB1AeOprKx0S5Ys8boMAACACe3YsaPVOVc19viMDFlLlizR9u3bvS4DAABgQmZ2cLzjDBcCAADkASELAAAgDwhZAAAAeTAj52QBAIDcGB4eVlNTkwYHB70uZdaLRCKqra1VMBjM6nxCFgAAc1hTU5NKSkq0ZMkSmZnX5cxazjm1tbWpqalJ9fX1Wb2H4UIAAOawwcFBVVRUELCmyMxUUVExqR5BQhYAAHMcASs3JtuOhCwAAIA8IGQBAADkASELAADkTWdnp774xS9O+n033HCDOjs7J/2+O+64Q48//vik35cPhCwAAJA3pwtZyWTyjO/bunWrysvL81TV9GALBwAACsTnv79Lbx7pzunPXLWoVH/xoQtP+/p9992n/fv3a82aNQoGg4rFYlq4cKFeffVVvfnmm/rIRz6ixsZGDQ4O6t5779XmzZslnbyOcW9vr66//npdeeWV+tWvfqWamho99dRTKioqmrC2n/70p/qzP/szJRIJXX755XrwwQcVDod13333acuWLQoEAvrgBz+ov/u7v9N3v/tdff7zn5ff71dZWZmeffbZKbcNIQsAAOTN3/zN32jnzp169dVX9cwzz+jGG2/Uzp07T+w19eijj2r+/PkaGBjQ5ZdfrptvvlkVFRWn/Iy9e/fqW9/6lh555BHdcssteuKJJ/Txj3/8jJ87ODioO+64Qz/96U913nnn6fbbb9eDDz6o22+/XU8++aTeeustmdmJIckvfOELevrpp1VTU3NWw5TjIWQBAFAgztTjNF3WrVt3ymae999/v5588klJUmNjo/bu3fuukFVfX681a9ZIki677DIdOHBgws/Zs2eP6uvrdd5550mSPvnJT+qBBx7QPffco0gkok9/+tO68cYbddNNN0mSNmzYoDvuuEO33HKLPvrRj+bgmxbonKxDbf1qbO/3ugwAAApONBo98fiZZ57RT37yE73wwgt67bXXdMkll4y72Wc4HD7x2O/3K5FITPg5zrlxjwcCAb300ku6+eab9W//9m/auHGjJOmhhx7SX/7lX6qxsVFr1qxRW1vbZL/auz9ryj9hFtr8te06d36xHr59rdelAAAwp5WUlKinp2fc17q6ujRv3jwVFxfrrbfe0rZt23L2ueeff74OHDigffv2afny5fra176mq6++Wr29verv79cNN9yg9evXa/ny5ZKk/fv364orrtAVV1yh73//+2psbHxXj9pkFWTIioYD6h2aOAUDAICpqaio0IYNG3TRRRepqKhICxYsOPHaxo0b9dBDD+niiy/WypUrtX79+px9biQS0WOPPaaPfexjJya+33XXXWpvb9emTZs0ODgo55z+4R/+QZL053/+59q7d6+cc/rABz6g1atXT7kGO113mpfWrl3rtm/fnref/8lHX1Jnf1xP3XNl3j4DAICZYPfu3brgggu8LmPOGK89zWyHc+5dw2MFOScrFg6oh54sAACQRwU5XBgLB9RHyAIAYNa6++679fzzz59y7N5779Wdd97pUUXvVpAhKxoOqHeQkAUAKAzOOZmZ12Xk1AMPPDDtnznZKVaFOVwYCagvnlQqNfPmowEAkEuRSERtbW2TDgg4lXNObW1tikQiWb+nIHuyYmG/JKkvnlBJJOhxNQAA5E9tba2amprU0tLidSmzXiQSUW1tbdbnF2jISgervqEkIQsAMKcFg8FTdljH9CnI4cJopierd2jY40oAAMBcVZAhqySS7sDrHUp6XAkAAJirCjJkRUOZkMUKQwAAkCcFGbJiJ3qyCFkAACA/CjNkhQlZAAAgvwo6ZLHrOwAAyJeCDFlRerIAAECeFWTICgd8CvqNkAUAAPKmIEOWmXH9QgAAkFcFGbKk9Lws5mQBAIB8KeiQ1UPIAgAAeVLQIYueLAAAkC8FG7Ki4QAT3wEAQN4UbMiKRQhZAAAgfwo3ZIVYXQgAAPKncENWhDlZAAAgfwo2ZEXDAfXFk0qlnNelAACAOahgQ1bJyPUL4/Rm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\n", 520 | "text/plain": [ 521 | "
    " 522 | ] 523 | }, 524 | "metadata": { 525 | "needs_background": "light" 526 | }, 527 | "output_type": "display_data" 528 | } 529 | ], 530 | "source": [ 531 | "plt.figure(figsize=(10,7))\n", 532 | "plt.plot(history.history['loss'], label='train_loss')\n", 533 | "plt.legend()\n", 534 | "plt.show()" 535 | ] 536 | }, 537 | { 538 | "cell_type": "code", 539 | "execution_count": 8, 540 | "metadata": {}, 541 | "outputs": [ 542 | { 543 | "data": { 544 | "image/png": "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\n", 545 | "text/plain": [ 546 | "
    " 547 | ] 548 | }, 549 | "metadata": { 550 | "needs_background": "light" 551 | }, 552 | "output_type": "display_data" 553 | } 554 | ], 555 | "source": [ 556 | "plt.figure(figsize=(10,7))\n", 557 | "plt.plot(history.history['val_loss'], label='test_loss')\n", 558 | "plt.legend()\n", 559 | "plt.show()" 560 | ] 561 | }, 562 | { 563 | "cell_type": "code", 564 | "execution_count": 9, 565 | "metadata": {}, 566 | "outputs": [ 567 | { 568 | "data": { 569 | "image/png": "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\n", 570 | "text/plain": [ 571 | "
    " 572 | ] 573 | }, 574 | "metadata": { 575 | "needs_background": "light" 576 | }, 577 | "output_type": "display_data" 578 | } 579 | ], 580 | "source": [ 581 | "plt.figure(figsize=(10,7))\n", 582 | "plt.plot(history.history['accuracy'], label='train_accuracy')\n", 583 | "plt.plot(history.history['val_accuracy'], label='test_accuracy')\n", 584 | "plt.legend()\n", 585 | "plt.show()" 586 | ] 587 | }, 588 | { 589 | "cell_type": "code", 590 | "execution_count": 10, 591 | "metadata": {}, 592 | "outputs": [ 593 | { 594 | "name": "stderr", 595 | "output_type": "stream", 596 | "text": [ 597 | "WARNING:absl:Found untraced functions such as lstm_cell_1_layer_call_fn, lstm_cell_1_layer_call_and_return_conditional_losses, lstm_cell_2_layer_call_fn, lstm_cell_2_layer_call_and_return_conditional_losses, lstm_cell_1_layer_call_fn while saving (showing 5 of 10). These functions will not be directly callable after loading.\n" 598 | ] 599 | }, 600 | { 601 | "name": "stdout", 602 | "output_type": "stream", 603 | "text": [ 604 | "INFO:tensorflow:Assets written to: bilstm_full\\assets\n" 605 | ] 606 | }, 607 | { 608 | "name": "stderr", 609 | "output_type": "stream", 610 | "text": [ 611 | "INFO:tensorflow:Assets written to: bilstm_full\\assets\n", 612 | "WARNING:absl: has the same name 'LSTMCell' as a built-in Keras object. Consider renaming to avoid naming conflicts when loading with `tf.keras.models.load_model`. If renaming is not possible, pass the object in the `custom_objects` parameter of the load function.\n", 613 | "WARNING:absl: has the same name 'LSTMCell' as a built-in Keras object. Consider renaming to avoid naming conflicts when loading with `tf.keras.models.load_model`. If renaming is not possible, pass the object in the `custom_objects` parameter of the load function.\n" 614 | ] 615 | }, 616 | { 617 | "name": "stdout", 618 | "output_type": "stream", 619 | "text": [ 620 | "12500/12500 [==============================] - 202s 16ms/step - loss: 0.0480 - accuracy: 0.9900 - fn: 3281.0000 - fp: 731.0000 - tn: 199446.0000 - tp: 196542.0000 - precision: 0.9963 - recall: 0.9836\n", 621 | "\n", 622 | "------------------\n", 623 | "loss : 0.04804224148392677\n", 624 | "tn : 199446.0\n", 625 | "fp : 731.0\n", 626 | "fn : 3281.0\n", 627 | "tp : 196542.0\n", 628 | "------------------\n", 629 | "accuracy : 0.9899700284004211\n", 630 | "precision : 0.9962944984436035\n", 631 | "recall : 0.983580470085144\n", 632 | "------------------\n", 633 | "F1 score. : 0.9898966618590025\n", 634 | "------------------\n" 635 | ] 636 | }, 637 | { 638 | "data": { 639 | "image/png": "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\n", 640 | "text/plain": [ 641 | "
    " 642 | ] 643 | }, 644 | "metadata": { 645 | "needs_background": "light" 646 | }, 647 | "output_type": "display_data" 648 | } 649 | ], 650 | "source": [ 651 | "# load the best checkpoint weights\n", 652 | "model.load_weights(checkpoint_path)\n", 653 | "\n", 654 | "# save the model to a full format\n", 655 | "model.save(save_path)\n", 656 | "\n", 657 | "# get final metrics\n", 658 | "reconstructed_model = tf.keras.models.load_model(save_path)\n", 659 | "\n", 660 | "\n", 661 | "def display_confusion_matrix(y_test, pred_test):\n", 662 | " \"\"\"\n", 663 | " Displays a nice and pretty confusion matrix for our data set.\n", 664 | " \"\"\"\n", 665 | " plt.figure()\n", 666 | " classes = ['Normal', 'Password']\n", 667 | " cm = confusion_matrix(y_test, pred_test)\n", 668 | " np.set_printoptions(precision=2)\n", 669 | "\n", 670 | " plt.imshow(cm, interpolation='nearest', cmap=plt.cm.Blues)\n", 671 | " plt.title('Confusion Matrix')\n", 672 | " plt.colorbar()\n", 673 | " tick_marks = np.arange(len(classes))\n", 674 | " plt.xticks(tick_marks, classes, rotation=45)\n", 675 | " plt.yticks(tick_marks, classes)\n", 676 | "\n", 677 | " thresh = cm.max() / 2.\n", 678 | " for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):\n", 679 | " plt.text(j, i, cm[i, j],\n", 680 | " horizontalalignment=\"center\",\n", 681 | " color=\"white\" if cm[i, j] > thresh else \"black\")\n", 682 | "\n", 683 | " plt.tight_layout()\n", 684 | " plt.ylabel('True label')\n", 685 | " plt.xlabel('Predicted label')\n", 686 | " plt.show()\n", 687 | "\n", 688 | "\n", 689 | "loss, accuracy, fn, fp, tn, tp, precision, recall = reconstructed_model.evaluate(X_test, y_test)\n", 690 | "\n", 691 | "print('\\n------------------')\n", 692 | "print('loss : ', loss)\n", 693 | "print('tn : ', tn)\n", 694 | "print('fp : ', fp)\n", 695 | "print('fn : ', fn)\n", 696 | "print('tp : ', tp)\n", 697 | "print('------------------')\n", 698 | "print('accuracy : ', accuracy)\n", 699 | "print('precision : ', precision)\n", 700 | "print('recall : ', recall)\n", 701 | "print('------------------')\n", 702 | "\n", 703 | "f1 = (2 * precision * recall) / (precision + recall)\n", 704 | "print(\"F1 score. : \", f1)\n", 705 | "print('------------------')\n", 706 | "\n", 707 | "pred_test = model.predict(X_test)\n", 708 | "\n", 709 | "display_confusion_matrix(y_test, np.rint(pred_test))" 710 | ] 711 | } 712 | ], 713 | "metadata": { 714 | "kernelspec": { 715 | "display_name": "Python 3 (ipykernel)", 716 | "language": "python", 717 | "name": "python3" 718 | }, 719 | "language_info": { 720 | "codemirror_mode": { 721 | "name": "ipython", 722 | "version": 3 723 | }, 724 | "file_extension": ".py", 725 | "mimetype": "text/x-python", 726 | "name": "python", 727 | "nbconvert_exporter": "python", 728 | "pygments_lexer": "ipython3", 729 | "version": "3.9.7" 730 | } 731 | }, 732 | "nbformat": 4, 733 | "nbformat_minor": 4 734 | } 735 | --------------------------------------------------------------------------------