Bladeren bron

First commit

Pranav 6 jaren geleden
commit
9de98523e6
72 gewijzigde bestanden met toevoegingen van 1294 en 0 verwijderingen
  1. 128 0
      app.py
  2. 1 0
      dog-breed/bin/python
  3. 1 0
      dog-breed/bin/python3
  4. 1 0
      dog-breed/include/python3.6m
  5. 1 0
      dog-breed/lib/python3.6/__future__.py
  6. 1 0
      dog-breed/lib/python3.6/_bootlocale.py
  7. 1 0
      dog-breed/lib/python3.6/_collections_abc.py
  8. 1 0
      dog-breed/lib/python3.6/_dummy_thread.py
  9. 1 0
      dog-breed/lib/python3.6/_weakrefset.py
  10. 1 0
      dog-breed/lib/python3.6/abc.py
  11. 1 0
      dog-breed/lib/python3.6/base64.py
  12. 1 0
      dog-breed/lib/python3.6/bisect.py
  13. 1 0
      dog-breed/lib/python3.6/codecs.py
  14. 1 0
      dog-breed/lib/python3.6/collections
  15. 1 0
      dog-breed/lib/python3.6/config-3.6m-darwin
  16. 1 0
      dog-breed/lib/python3.6/copy.py
  17. 1 0
      dog-breed/lib/python3.6/copyreg.py
  18. 1 0
      dog-breed/lib/python3.6/encodings
  19. 1 0
      dog-breed/lib/python3.6/enum.py
  20. 1 0
      dog-breed/lib/python3.6/fnmatch.py
  21. 1 0
      dog-breed/lib/python3.6/functools.py
  22. 1 0
      dog-breed/lib/python3.6/genericpath.py
  23. 1 0
      dog-breed/lib/python3.6/hashlib.py
  24. 1 0
      dog-breed/lib/python3.6/heapq.py
  25. 1 0
      dog-breed/lib/python3.6/hmac.py
  26. 1 0
      dog-breed/lib/python3.6/imp.py
  27. 1 0
      dog-breed/lib/python3.6/importlib
  28. 1 0
      dog-breed/lib/python3.6/io.py
  29. 1 0
      dog-breed/lib/python3.6/keyword.py
  30. 1 0
      dog-breed/lib/python3.6/lib-dynload
  31. 1 0
      dog-breed/lib/python3.6/linecache.py
  32. 1 0
      dog-breed/lib/python3.6/locale.py
  33. 0 0
      dog-breed/lib/python3.6/no-global-site-packages.txt
  34. 1 0
      dog-breed/lib/python3.6/ntpath.py
  35. 1 0
      dog-breed/lib/python3.6/operator.py
  36. 1 0
      dog-breed/lib/python3.6/orig-prefix.txt
  37. 1 0
      dog-breed/lib/python3.6/os.py
  38. 1 0
      dog-breed/lib/python3.6/posixpath.py
  39. 1 0
      dog-breed/lib/python3.6/random.py
  40. 1 0
      dog-breed/lib/python3.6/re.py
  41. 1 0
      dog-breed/lib/python3.6/readline.so
  42. 1 0
      dog-breed/lib/python3.6/reprlib.py
  43. 1 0
      dog-breed/lib/python3.6/rlcompleter.py
  44. 1 0
      dog-breed/lib/python3.6/shutil.py
  45. 758 0
      dog-breed/lib/python3.6/site.py
  46. 1 0
      dog-breed/lib/python3.6/sre_compile.py
  47. 1 0
      dog-breed/lib/python3.6/sre_constants.py
  48. 1 0
      dog-breed/lib/python3.6/sre_parse.py
  49. 1 0
      dog-breed/lib/python3.6/stat.py
  50. 1 0
      dog-breed/lib/python3.6/struct.py
  51. 1 0
      dog-breed/lib/python3.6/tarfile.py
  52. 1 0
      dog-breed/lib/python3.6/tempfile.py
  53. 1 0
      dog-breed/lib/python3.6/token.py
  54. 1 0
      dog-breed/lib/python3.6/tokenize.py
  55. 1 0
      dog-breed/lib/python3.6/types.py
  56. 1 0
      dog-breed/lib/python3.6/warnings.py
  57. 1 0
      dog-breed/lib/python3.6/weakref.py
  58. 3 0
      dog-breed/pyvenv.cfg
  59. 133 0
      labels.txt
  60. 27 0
      load.py
  61. 1 0
      models/model.Resnet50.json
  62. 0 0
      models/model.inceptionv3.json
  63. BIN
      models/weights.Resnet50.hdf5
  64. BIN
      models/weights.inceptionv3.h5
  65. 6 0
      requirements.txt
  66. BIN
      screenshots/screenshot_1.png
  67. BIN
      static/favicon.ico
  68. 30 0
      templates/layout.html
  69. 30 0
      templates/results.html
  70. 20 0
      templates/select_files.html
  71. 25 0
      templates/settings.html
  72. 79 0
      util.py

+ 128 - 0
app.py

@@ -0,0 +1,128 @@
+import base64
+import logging
+import io
+import os
+
+from flask import Flask, render_template, request
+from load import init_model
+from PIL import Image
+from util import decode_prob
+
+logger = logging.getLogger("dog_breed_classifier")
+logger.setLevel(logging.DEBUG)
+
+app = Flask(__name__)
+
+# Initialize
+MODEL_DIR = os.path.abspath("./models")
+
+RESNET_CONFIG = {'arch':
+                 os.path.join(MODEL_DIR,
+                              'model.Resnet50.json'),
+                 'weights':
+                 os.path.join(MODEL_DIR,
+                              'weights.Resnet50.hdf5')}
+
+INCEPTION_CONFIG = {'arch':
+                    os.path.join(MODEL_DIR,
+                                 'model.inceptionv3.json'),
+                    'weights':
+                    os.path.join(MODEL_DIR,
+                                 'weights.inceptionv3.h5')}
+
+MODELS = {'resnet': RESNET_CONFIG,
+          'inception': INCEPTION_CONFIG}
+
+
+@app.route('/index')
+@app.route('/')
+def index():
+    return render_template('settings.html')
+
+
+@app.route('/settings', methods=['GET', 'POST'])
+def settings():
+    """Select Model Architecture and Initialize
+    """
+    global model, graph, preprocess
+
+    # grab model selected
+    model_name = request.form['model']
+    config = MODELS[model_name]
+
+    # init the model with pre-trained architecture and weights
+    model, graph = init_model(config['arch'], config['weights'])
+
+    # use the proper preprocessing method
+    if model_name == 'inception':
+        from util import preprocess_inception
+        preprocess = preprocess_inception
+    else:
+        from util import preprocess_resnet
+        preprocess = preprocess_resnet
+
+    return render_template('select_files.html', model_name=model_name)
+
+
+@app.route('/predict', methods=['GET', 'POST'])
+def predict():
+    """File selection and display results
+    """
+
+    if request.method == 'POST' and 'file[]' in request.files:
+        inputs = []
+        files = request.files.getlist('file[]')
+        for file_obj in files:
+            # Check if no files uploaded
+            if file_obj.filename == '':
+                if len(files) == 1:
+                    return render_template('select_files.html')
+                continue
+            entry = {}
+            entry.update({'filename': file_obj.filename})
+            try:
+                img_bytes = io.BytesIO(file_obj.stream.getvalue())
+                entry.update({'data':
+                              Image.open(
+                                  img_bytes
+                              )})
+            except AttributeError:
+                img_bytes = io.BytesIO(file_obj.stream.read())
+                entry.update({'data':
+                              Image.open(
+                                  img_bytes
+                              )})
+            # keep image in base64 for later use
+            img_b64 = base64.b64encode(img_bytes.getvalue()).decode()
+            entry.update({'img': img_b64})
+
+            inputs.append(entry)
+
+        outputs = []
+
+        with graph.as_default():
+            for input_ in inputs:
+                # convert to 4D tensor to feed into our model
+                x = preprocess(input_['data'])
+                # perform prediction
+                out = model.predict(x)
+                outputs.append(out)
+
+        # decode output prob
+        outputs = decode_prob(outputs)
+
+        results = []
+
+        for input_, probs in zip(inputs, outputs):
+            results.append({'filename': input_['filename'],
+                            'image': input_['img'],
+                            'predict_probs': probs})
+
+        return render_template('results.html', results=results)
+
+    # if no files uploaded
+    return render_template('select_files.html')
+
+
+if __name__ == '__main__':
+    app.run(debug=True)

+ 1 - 0
dog-breed/bin/python

@@ -0,0 +1 @@
+python3

+ 1 - 0
dog-breed/bin/python3

@@ -0,0 +1 @@
+/Users/bunny/anaconda/bin/python3

+ 1 - 0
dog-breed/include/python3.6m

@@ -0,0 +1 @@
+/Users/bunny/anaconda/include/python3.6m

+ 1 - 0
dog-breed/lib/python3.6/__future__.py

@@ -0,0 +1 @@
+/Users/bunny/anaconda/lib/python3.6/__future__.py

+ 1 - 0
dog-breed/lib/python3.6/_bootlocale.py

@@ -0,0 +1 @@
+/Users/bunny/anaconda/lib/python3.6/_bootlocale.py

+ 1 - 0
dog-breed/lib/python3.6/_collections_abc.py

@@ -0,0 +1 @@
+/Users/bunny/anaconda/lib/python3.6/_collections_abc.py

+ 1 - 0
dog-breed/lib/python3.6/_dummy_thread.py

@@ -0,0 +1 @@
+/Users/bunny/anaconda/lib/python3.6/_dummy_thread.py

+ 1 - 0
dog-breed/lib/python3.6/_weakrefset.py

@@ -0,0 +1 @@
+/Users/bunny/anaconda/lib/python3.6/_weakrefset.py

+ 1 - 0
dog-breed/lib/python3.6/abc.py

@@ -0,0 +1 @@
+/Users/bunny/anaconda/lib/python3.6/abc.py

+ 1 - 0
dog-breed/lib/python3.6/base64.py

@@ -0,0 +1 @@
+/Users/bunny/anaconda/lib/python3.6/base64.py

+ 1 - 0
dog-breed/lib/python3.6/bisect.py

@@ -0,0 +1 @@
+/Users/bunny/anaconda/lib/python3.6/bisect.py

+ 1 - 0
dog-breed/lib/python3.6/codecs.py

@@ -0,0 +1 @@
+/Users/bunny/anaconda/lib/python3.6/codecs.py

+ 1 - 0
dog-breed/lib/python3.6/collections

@@ -0,0 +1 @@
+/Users/bunny/anaconda/lib/python3.6/collections

+ 1 - 0
dog-breed/lib/python3.6/config-3.6m-darwin

@@ -0,0 +1 @@
+/Users/bunny/anaconda/lib/python3.6/config-3.6m-darwin

+ 1 - 0
dog-breed/lib/python3.6/copy.py

@@ -0,0 +1 @@
+/Users/bunny/anaconda/lib/python3.6/copy.py

+ 1 - 0
dog-breed/lib/python3.6/copyreg.py

@@ -0,0 +1 @@
+/Users/bunny/anaconda/lib/python3.6/copyreg.py

+ 1 - 0
dog-breed/lib/python3.6/encodings

@@ -0,0 +1 @@
+/Users/bunny/anaconda/lib/python3.6/encodings

+ 1 - 0
dog-breed/lib/python3.6/enum.py

@@ -0,0 +1 @@
+/Users/bunny/anaconda/lib/python3.6/enum.py

+ 1 - 0
dog-breed/lib/python3.6/fnmatch.py

@@ -0,0 +1 @@
+/Users/bunny/anaconda/lib/python3.6/fnmatch.py

+ 1 - 0
dog-breed/lib/python3.6/functools.py

@@ -0,0 +1 @@
+/Users/bunny/anaconda/lib/python3.6/functools.py

+ 1 - 0
dog-breed/lib/python3.6/genericpath.py

@@ -0,0 +1 @@
+/Users/bunny/anaconda/lib/python3.6/genericpath.py

+ 1 - 0
dog-breed/lib/python3.6/hashlib.py

@@ -0,0 +1 @@
+/Users/bunny/anaconda/lib/python3.6/hashlib.py

+ 1 - 0
dog-breed/lib/python3.6/heapq.py

@@ -0,0 +1 @@
+/Users/bunny/anaconda/lib/python3.6/heapq.py

+ 1 - 0
dog-breed/lib/python3.6/hmac.py

@@ -0,0 +1 @@
+/Users/bunny/anaconda/lib/python3.6/hmac.py

+ 1 - 0
dog-breed/lib/python3.6/imp.py

@@ -0,0 +1 @@
+/Users/bunny/anaconda/lib/python3.6/imp.py

+ 1 - 0
dog-breed/lib/python3.6/importlib

@@ -0,0 +1 @@
+/Users/bunny/anaconda/lib/python3.6/importlib

+ 1 - 0
dog-breed/lib/python3.6/io.py

@@ -0,0 +1 @@
+/Users/bunny/anaconda/lib/python3.6/io.py

+ 1 - 0
dog-breed/lib/python3.6/keyword.py

@@ -0,0 +1 @@
+/Users/bunny/anaconda/lib/python3.6/keyword.py

+ 1 - 0
dog-breed/lib/python3.6/lib-dynload

@@ -0,0 +1 @@
+/Users/bunny/anaconda/lib/python3.6/lib-dynload

+ 1 - 0
dog-breed/lib/python3.6/linecache.py

@@ -0,0 +1 @@
+/Users/bunny/anaconda/lib/python3.6/linecache.py

+ 1 - 0
dog-breed/lib/python3.6/locale.py

@@ -0,0 +1 @@
+/Users/bunny/anaconda/lib/python3.6/locale.py

+ 0 - 0
dog-breed/lib/python3.6/no-global-site-packages.txt


+ 1 - 0
dog-breed/lib/python3.6/ntpath.py

@@ -0,0 +1 @@
+/Users/bunny/anaconda/lib/python3.6/ntpath.py

+ 1 - 0
dog-breed/lib/python3.6/operator.py

@@ -0,0 +1 @@
+/Users/bunny/anaconda/lib/python3.6/operator.py

+ 1 - 0
dog-breed/lib/python3.6/orig-prefix.txt

@@ -0,0 +1 @@
+/Users/bunny/anaconda

+ 1 - 0
dog-breed/lib/python3.6/os.py

@@ -0,0 +1 @@
+/Users/bunny/anaconda/lib/python3.6/os.py

+ 1 - 0
dog-breed/lib/python3.6/posixpath.py

@@ -0,0 +1 @@
+/Users/bunny/anaconda/lib/python3.6/posixpath.py

+ 1 - 0
dog-breed/lib/python3.6/random.py

@@ -0,0 +1 @@
+/Users/bunny/anaconda/lib/python3.6/random.py

+ 1 - 0
dog-breed/lib/python3.6/re.py

@@ -0,0 +1 @@
+/Users/bunny/anaconda/lib/python3.6/re.py

+ 1 - 0
dog-breed/lib/python3.6/readline.so

@@ -0,0 +1 @@
+/Users/bunny/anaconda/lib/python3.6/lib-dynload/readline.cpython-36m-darwin.so

+ 1 - 0
dog-breed/lib/python3.6/reprlib.py

@@ -0,0 +1 @@
+/Users/bunny/anaconda/lib/python3.6/reprlib.py

+ 1 - 0
dog-breed/lib/python3.6/rlcompleter.py

@@ -0,0 +1 @@
+/Users/bunny/anaconda/lib/python3.6/rlcompleter.py

+ 1 - 0
dog-breed/lib/python3.6/shutil.py

@@ -0,0 +1 @@
+/Users/bunny/anaconda/lib/python3.6/shutil.py

+ 758 - 0
dog-breed/lib/python3.6/site.py

@@ -0,0 +1,758 @@
+"""Append module search paths for third-party packages to sys.path.
+
+****************************************************************
+* This module is automatically imported during initialization. *
+****************************************************************
+
+In earlier versions of Python (up to 1.5a3), scripts or modules that
+needed to use site-specific modules would place ``import site''
+somewhere near the top of their code.  Because of the automatic
+import, this is no longer necessary (but code that does it still
+works).
+
+This will append site-specific paths to the module search path.  On
+Unix, it starts with sys.prefix and sys.exec_prefix (if different) and
+appends lib/python<version>/site-packages as well as lib/site-python.
+It also supports the Debian convention of
+lib/python<version>/dist-packages.  On other platforms (mainly Mac and
+Windows), it uses just sys.prefix (and sys.exec_prefix, if different,
+but this is unlikely).  The resulting directories, if they exist, are
+appended to sys.path, and also inspected for path configuration files.
+
+FOR DEBIAN, this sys.path is augmented with directories in /usr/local.
+Local addons go into /usr/local/lib/python<version>/site-packages
+(resp. /usr/local/lib/site-python), Debian addons install into
+/usr/{lib,share}/python<version>/dist-packages.
+
+A path configuration file is a file whose name has the form
+<package>.pth; its contents are additional directories (one per line)
+to be added to sys.path.  Non-existing directories (or
+non-directories) are never added to sys.path; no directory is added to
+sys.path more than once.  Blank lines and lines beginning with
+'#' are skipped. Lines starting with 'import' are executed.
+
+For example, suppose sys.prefix and sys.exec_prefix are set to
+/usr/local and there is a directory /usr/local/lib/python2.X/site-packages
+with three subdirectories, foo, bar and spam, and two path
+configuration files, foo.pth and bar.pth.  Assume foo.pth contains the
+following:
+
+  # foo package configuration
+  foo
+  bar
+  bletch
+
+and bar.pth contains:
+
+  # bar package configuration
+  bar
+
+Then the following directories are added to sys.path, in this order:
+
+  /usr/local/lib/python2.X/site-packages/bar
+  /usr/local/lib/python2.X/site-packages/foo
+
+Note that bletch is omitted because it doesn't exist; bar precedes foo
+because bar.pth comes alphabetically before foo.pth; and spam is
+omitted because it is not mentioned in either path configuration file.
+
+After these path manipulations, an attempt is made to import a module
+named sitecustomize, which can perform arbitrary additional
+site-specific customizations.  If this import fails with an
+ImportError exception, it is silently ignored.
+
+"""
+
+import sys
+import os
+try:
+    import __builtin__ as builtins
+except ImportError:
+    import builtins
+try:
+    set
+except NameError:
+    from sets import Set as set
+
+# Prefixes for site-packages; add additional prefixes like /usr/local here
+PREFIXES = [sys.prefix, sys.exec_prefix]
+# Enable per user site-packages directory
+# set it to False to disable the feature or True to force the feature
+ENABLE_USER_SITE = None
+# for distutils.commands.install
+USER_SITE = None
+USER_BASE = None
+
+_is_64bit = (getattr(sys, 'maxsize', None) or getattr(sys, 'maxint')) > 2**32
+_is_pypy = hasattr(sys, 'pypy_version_info')
+_is_jython = sys.platform[:4] == 'java'
+if _is_jython:
+    ModuleType = type(os)
+
+def makepath(*paths):
+    dir = os.path.join(*paths)
+    if _is_jython and (dir == '__classpath__' or
+                       dir.startswith('__pyclasspath__')):
+        return dir, dir
+    dir = os.path.abspath(dir)
+    return dir, os.path.normcase(dir)
+
+def abs__file__():
+    """Set all module' __file__ attribute to an absolute path"""
+    for m in sys.modules.values():
+        if ((_is_jython and not isinstance(m, ModuleType)) or
+            hasattr(m, '__loader__')):
+            # only modules need the abspath in Jython. and don't mess
+            # with a PEP 302-supplied __file__
+            continue
+        f = getattr(m, '__file__', None)
+        if f is None:
+            continue
+        m.__file__ = os.path.abspath(f)
+
+def removeduppaths():
+    """ Remove duplicate entries from sys.path along with making them
+    absolute"""
+    # This ensures that the initial path provided by the interpreter contains
+    # only absolute pathnames, even if we're running from the build directory.
+    L = []
+    known_paths = set()
+    for dir in sys.path:
+        # Filter out duplicate paths (on case-insensitive file systems also
+        # if they only differ in case); turn relative paths into absolute
+        # paths.
+        dir, dircase = makepath(dir)
+        if not dircase in known_paths:
+            L.append(dir)
+            known_paths.add(dircase)
+    sys.path[:] = L
+    return known_paths
+
+# XXX This should not be part of site.py, since it is needed even when
+# using the -S option for Python.  See http://www.python.org/sf/586680
+def addbuilddir():
+    """Append ./build/lib.<platform> in case we're running in the build dir
+    (especially for Guido :-)"""
+    from distutils.util import get_platform
+    s = "build/lib.%s-%.3s" % (get_platform(), sys.version)
+    if hasattr(sys, 'gettotalrefcount'):
+        s += '-pydebug'
+    s = os.path.join(os.path.dirname(sys.path[-1]), s)
+    sys.path.append(s)
+
+def _init_pathinfo():
+    """Return a set containing all existing directory entries from sys.path"""
+    d = set()
+    for dir in sys.path:
+        try:
+            if os.path.isdir(dir):
+                dir, dircase = makepath(dir)
+                d.add(dircase)
+        except TypeError:
+            continue
+    return d
+
+def addpackage(sitedir, name, known_paths):
+    """Add a new path to known_paths by combining sitedir and 'name' or execute
+    sitedir if it starts with 'import'"""
+    if known_paths is None:
+        _init_pathinfo()
+        reset = 1
+    else:
+        reset = 0
+    fullname = os.path.join(sitedir, name)
+    try:
+        f = open(fullname, "rU")
+    except IOError:
+        return
+    try:
+        for line in f:
+            if line.startswith("#"):
+                continue
+            if line.startswith("import"):
+                exec(line)
+                continue
+            line = line.rstrip()
+            dir, dircase = makepath(sitedir, line)
+            if not dircase in known_paths and os.path.exists(dir):
+                sys.path.append(dir)
+                known_paths.add(dircase)
+    finally:
+        f.close()
+    if reset:
+        known_paths = None
+    return known_paths
+
+def addsitedir(sitedir, known_paths=None):
+    """Add 'sitedir' argument to sys.path if missing and handle .pth files in
+    'sitedir'"""
+    if known_paths is None:
+        known_paths = _init_pathinfo()
+        reset = 1
+    else:
+        reset = 0
+    sitedir, sitedircase = makepath(sitedir)
+    if not sitedircase in known_paths:
+        sys.path.append(sitedir)        # Add path component
+    try:
+        names = os.listdir(sitedir)
+    except os.error:
+        return
+    names.sort()
+    for name in names:
+        if name.endswith(os.extsep + "pth"):
+            addpackage(sitedir, name, known_paths)
+    if reset:
+        known_paths = None
+    return known_paths
+
+def addsitepackages(known_paths, sys_prefix=sys.prefix, exec_prefix=sys.exec_prefix):
+    """Add site-packages (and possibly site-python) to sys.path"""
+    prefixes = [os.path.join(sys_prefix, "local"), sys_prefix]
+    if exec_prefix != sys_prefix:
+        prefixes.append(os.path.join(exec_prefix, "local"))
+
+    for prefix in prefixes:
+        if prefix:
+            if sys.platform in ('os2emx', 'riscos') or _is_jython:
+                sitedirs = [os.path.join(prefix, "Lib", "site-packages")]
+            elif _is_pypy:
+                sitedirs = [os.path.join(prefix, 'site-packages')]
+            elif sys.platform == 'darwin' and prefix == sys_prefix:
+
+                if prefix.startswith("/System/Library/Frameworks/"): # Apple's Python
+
+                    sitedirs = [os.path.join("/Library/Python", sys.version[:3], "site-packages"),
+                                os.path.join(prefix, "Extras", "lib", "python")]
+
+                else: # any other Python distros on OSX work this way
+                    sitedirs = [os.path.join(prefix, "lib",
+                                             "python" + sys.version[:3], "site-packages")]
+
+            elif os.sep == '/':
+                sitedirs = [os.path.join(prefix,
+                                         "lib",
+                                         "python" + sys.version[:3],
+                                         "site-packages"),
+                            os.path.join(prefix, "lib", "site-python"),
+                            os.path.join(prefix, "python" + sys.version[:3], "lib-dynload")]
+                lib64_dir = os.path.join(prefix, "lib64", "python" + sys.version[:3], "site-packages")
+                if (os.path.exists(lib64_dir) and
+                    os.path.realpath(lib64_dir) not in [os.path.realpath(p) for p in sitedirs]):
+                    if _is_64bit:
+                        sitedirs.insert(0, lib64_dir)
+                    else:
+                        sitedirs.append(lib64_dir)
+                try:
+                    # sys.getobjects only available in --with-pydebug build
+                    sys.getobjects
+                    sitedirs.insert(0, os.path.join(sitedirs[0], 'debug'))
+                except AttributeError:
+                    pass
+                # Debian-specific dist-packages directories:
+                sitedirs.append(os.path.join(prefix, "local/lib",
+                                             "python" + sys.version[:3],
+                                             "dist-packages"))
+                if sys.version[0] == '2':
+                    sitedirs.append(os.path.join(prefix, "lib",
+                                                 "python" + sys.version[:3],
+                                                 "dist-packages"))
+                else:
+                    sitedirs.append(os.path.join(prefix, "lib",
+                                                 "python" + sys.version[0],
+                                                 "dist-packages"))
+                sitedirs.append(os.path.join(prefix, "lib", "dist-python"))
+            else:
+                sitedirs = [prefix, os.path.join(prefix, "lib", "site-packages")]
+            if sys.platform == 'darwin':
+                # for framework builds *only* we add the standard Apple
+                # locations. Currently only per-user, but /Library and
+                # /Network/Library could be added too
+                if 'Python.framework' in prefix:
+                    home = os.environ.get('HOME')
+                    if home:
+                        sitedirs.append(
+                            os.path.join(home,
+                                         'Library',
+                                         'Python',
+                                         sys.version[:3],
+                                         'site-packages'))
+            for sitedir in sitedirs:
+                if os.path.isdir(sitedir):
+                    addsitedir(sitedir, known_paths)
+    return None
+
+def check_enableusersite():
+    """Check if user site directory is safe for inclusion
+
+    The function tests for the command line flag (including environment var),
+    process uid/gid equal to effective uid/gid.
+
+    None: Disabled for security reasons
+    False: Disabled by user (command line option)
+    True: Safe and enabled
+    """
+    if hasattr(sys, 'flags') and getattr(sys.flags, 'no_user_site', False):
+        return False
+
+    if hasattr(os, "getuid") and hasattr(os, "geteuid"):
+        # check process uid == effective uid
+        if os.geteuid() != os.getuid():
+            return None
+    if hasattr(os, "getgid") and hasattr(os, "getegid"):
+        # check process gid == effective gid
+        if os.getegid() != os.getgid():
+            return None
+
+    return True
+
+def addusersitepackages(known_paths):
+    """Add a per user site-package to sys.path
+
+    Each user has its own python directory with site-packages in the
+    home directory.
+
+    USER_BASE is the root directory for all Python versions
+
+    USER_SITE is the user specific site-packages directory
+
+    USER_SITE/.. can be used for data.
+    """
+    global USER_BASE, USER_SITE, ENABLE_USER_SITE
+    env_base = os.environ.get("PYTHONUSERBASE", None)
+
+    def joinuser(*args):
+        return os.path.expanduser(os.path.join(*args))
+
+    #if sys.platform in ('os2emx', 'riscos'):
+    #    # Don't know what to put here
+    #    USER_BASE = ''
+    #    USER_SITE = ''
+    if os.name == "nt":
+        base = os.environ.get("APPDATA") or "~"
+        if env_base:
+            USER_BASE = env_base
+        else:
+            USER_BASE = joinuser(base, "Python")
+        USER_SITE = os.path.join(USER_BASE,
+                                 "Python" + sys.version[0] + sys.version[2],
+                                 "site-packages")
+    else:
+        if env_base:
+            USER_BASE = env_base
+        else:
+            USER_BASE = joinuser("~", ".local")
+        USER_SITE = os.path.join(USER_BASE, "lib",
+                                 "python" + sys.version[:3],
+                                 "site-packages")
+
+    if ENABLE_USER_SITE and os.path.isdir(USER_SITE):
+        addsitedir(USER_SITE, known_paths)
+    if ENABLE_USER_SITE:
+        for dist_libdir in ("lib", "local/lib"):
+            user_site = os.path.join(USER_BASE, dist_libdir,
+                                     "python" + sys.version[:3],
+                                     "dist-packages")
+            if os.path.isdir(user_site):
+                addsitedir(user_site, known_paths)
+    return known_paths
+
+
+
+def setBEGINLIBPATH():
+    """The OS/2 EMX port has optional extension modules that do double duty
+    as DLLs (and must use the .DLL file extension) for other extensions.
+    The library search path needs to be amended so these will be found
+    during module import.  Use BEGINLIBPATH so that these are at the start
+    of the library search path.
+
+    """
+    dllpath = os.path.join(sys.prefix, "Lib", "lib-dynload")
+    libpath = os.environ['BEGINLIBPATH'].split(';')
+    if libpath[-1]:
+        libpath.append(dllpath)
+    else:
+        libpath[-1] = dllpath
+    os.environ['BEGINLIBPATH'] = ';'.join(libpath)
+
+
+def setquit():
+    """Define new built-ins 'quit' and 'exit'.
+    These are simply strings that display a hint on how to exit.
+
+    """
+    if os.sep == ':':
+        eof = 'Cmd-Q'
+    elif os.sep == '\\':
+        eof = 'Ctrl-Z plus Return'
+    else:
+        eof = 'Ctrl-D (i.e. EOF)'
+
+    class Quitter(object):
+        def __init__(self, name):
+            self.name = name
+        def __repr__(self):
+            return 'Use %s() or %s to exit' % (self.name, eof)
+        def __call__(self, code=None):
+            # Shells like IDLE catch the SystemExit, but listen when their
+            # stdin wrapper is closed.
+            try:
+                sys.stdin.close()
+            except:
+                pass
+            raise SystemExit(code)
+    builtins.quit = Quitter('quit')
+    builtins.exit = Quitter('exit')
+
+
+class _Printer(object):
+    """interactive prompt objects for printing the license text, a list of
+    contributors and the copyright notice."""
+
+    MAXLINES = 23
+
+    def __init__(self, name, data, files=(), dirs=()):
+        self.__name = name
+        self.__data = data
+        self.__files = files
+        self.__dirs = dirs
+        self.__lines = None
+
+    def __setup(self):
+        if self.__lines:
+            return
+        data = None
+        for dir in self.__dirs:
+            for filename in self.__files:
+                filename = os.path.join(dir, filename)
+                try:
+                    fp = open(filename, "rU")
+                    data = fp.read()
+                    fp.close()
+                    break
+                except IOError:
+                    pass
+            if data:
+                break
+        if not data:
+            data = self.__data
+        self.__lines = data.split('\n')
+        self.__linecnt = len(self.__lines)
+
+    def __repr__(self):
+        self.__setup()
+        if len(self.__lines) <= self.MAXLINES:
+            return "\n".join(self.__lines)
+        else:
+            return "Type %s() to see the full %s text" % ((self.__name,)*2)
+
+    def __call__(self):
+        self.__setup()
+        prompt = 'Hit Return for more, or q (and Return) to quit: '
+        lineno = 0
+        while 1:
+            try:
+                for i in range(lineno, lineno + self.MAXLINES):
+                    print(self.__lines[i])
+            except IndexError:
+                break
+            else:
+                lineno += self.MAXLINES
+                key = None
+                while key is None:
+                    try:
+                        key = raw_input(prompt)
+                    except NameError:
+                        key = input(prompt)
+                    if key not in ('', 'q'):
+                        key = None
+                if key == 'q':
+                    break
+
+def setcopyright():
+    """Set 'copyright' and 'credits' in __builtin__"""
+    builtins.copyright = _Printer("copyright", sys.copyright)
+    if _is_jython:
+        builtins.credits = _Printer(
+            "credits",
+            "Jython is maintained by the Jython developers (www.jython.org).")
+    elif _is_pypy:
+        builtins.credits = _Printer(
+            "credits",
+            "PyPy is maintained by the PyPy developers: http://pypy.org/")
+    else:
+        builtins.credits = _Printer("credits", """\
+    Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands
+    for supporting Python development.  See www.python.org for more information.""")
+    here = os.path.dirname(os.__file__)
+    builtins.license = _Printer(
+        "license", "See http://www.python.org/%.3s/license.html" % sys.version,
+        ["LICENSE.txt", "LICENSE"],
+        [os.path.join(here, os.pardir), here, os.curdir])
+
+
+class _Helper(object):
+    """Define the built-in 'help'.
+    This is a wrapper around pydoc.help (with a twist).
+
+    """
+
+    def __repr__(self):
+        return "Type help() for interactive help, " \
+               "or help(object) for help about object."
+    def __call__(self, *args, **kwds):
+        import pydoc
+        return pydoc.help(*args, **kwds)
+
+def sethelper():
+    builtins.help = _Helper()
+
+def aliasmbcs():
+    """On Windows, some default encodings are not provided by Python,
+    while they are always available as "mbcs" in each locale. Make
+    them usable by aliasing to "mbcs" in such a case."""
+    if sys.platform == 'win32':
+        import locale, codecs
+        enc = locale.getdefaultlocale()[1]
+        if enc.startswith('cp'):            # "cp***" ?
+            try:
+                codecs.lookup(enc)
+            except LookupError:
+                import encodings
+                encodings._cache[enc] = encodings._unknown
+                encodings.aliases.aliases[enc] = 'mbcs'
+
+def setencoding():
+    """Set the string encoding used by the Unicode implementation.  The
+    default is 'ascii', but if you're willing to experiment, you can
+    change this."""
+    encoding = "ascii" # Default value set by _PyUnicode_Init()
+    if 0:
+        # Enable to support locale aware default string encodings.
+        import locale
+        loc = locale.getdefaultlocale()
+        if loc[1]:
+            encoding = loc[1]
+    if 0:
+        # Enable to switch off string to Unicode coercion and implicit
+        # Unicode to string conversion.
+        encoding = "undefined"
+    if encoding != "ascii":
+        # On Non-Unicode builds this will raise an AttributeError...
+        sys.setdefaultencoding(encoding) # Needs Python Unicode build !
+
+
+def execsitecustomize():
+    """Run custom site specific code, if available."""
+    try:
+        import sitecustomize
+    except ImportError:
+        pass
+
+def virtual_install_main_packages():
+    f = open(os.path.join(os.path.dirname(__file__), 'orig-prefix.txt'))
+    sys.real_prefix = f.read().strip()
+    f.close()
+    pos = 2
+    hardcoded_relative_dirs = []
+    if sys.path[0] == '':
+        pos += 1
+    if _is_jython:
+        paths = [os.path.join(sys.real_prefix, 'Lib')]
+    elif _is_pypy:
+        if sys.version_info > (3, 2):
+            cpyver = '%d' % sys.version_info[0]
+        elif sys.pypy_version_info >= (1, 5):
+            cpyver = '%d.%d' % sys.version_info[:2]
+        else:
+            cpyver = '%d.%d.%d' % sys.version_info[:3]
+        paths = [os.path.join(sys.real_prefix, 'lib_pypy'),
+                 os.path.join(sys.real_prefix, 'lib-python', cpyver)]
+        if sys.pypy_version_info < (1, 9):
+            paths.insert(1, os.path.join(sys.real_prefix,
+                                         'lib-python', 'modified-%s' % cpyver))
+        hardcoded_relative_dirs = paths[:] # for the special 'darwin' case below
+        #
+        # This is hardcoded in the Python executable, but relative to sys.prefix:
+        for path in paths[:]:
+            plat_path = os.path.join(path, 'plat-%s' % sys.platform)
+            if os.path.exists(plat_path):
+                paths.append(plat_path)
+    elif sys.platform == 'win32':
+        paths = [os.path.join(sys.real_prefix, 'Lib'), os.path.join(sys.real_prefix, 'DLLs')]
+    else:
+        paths = [os.path.join(sys.real_prefix, 'lib', 'python'+sys.version[:3])]
+        hardcoded_relative_dirs = paths[:] # for the special 'darwin' case below
+        lib64_path = os.path.join(sys.real_prefix, 'lib64', 'python'+sys.version[:3])
+        if os.path.exists(lib64_path):
+            if _is_64bit:
+                paths.insert(0, lib64_path)
+            else:
+                paths.append(lib64_path)
+        # This is hardcoded in the Python executable, but relative to
+        # sys.prefix.  Debian change: we need to add the multiarch triplet
+        # here, which is where the real stuff lives.  As per PEP 421, in
+        # Python 3.3+, this lives in sys.implementation, while in Python 2.7
+        # it lives in sys.
+        try:
+            arch = getattr(sys, 'implementation', sys)._multiarch
+        except AttributeError:
+            # This is a non-multiarch aware Python.  Fallback to the old way.
+            arch = sys.platform
+        plat_path = os.path.join(sys.real_prefix, 'lib',
+                                 'python'+sys.version[:3],
+                                 'plat-%s' % arch)
+        if os.path.exists(plat_path):
+            paths.append(plat_path)
+    # This is hardcoded in the Python executable, but
+    # relative to sys.prefix, so we have to fix up:
+    for path in list(paths):
+        tk_dir = os.path.join(path, 'lib-tk')
+        if os.path.exists(tk_dir):
+            paths.append(tk_dir)
+
+    # These are hardcoded in the Apple's Python executable,
+    # but relative to sys.prefix, so we have to fix them up:
+    if sys.platform == 'darwin':
+        hardcoded_paths = [os.path.join(relative_dir, module)
+                           for relative_dir in hardcoded_relative_dirs
+                           for module in ('plat-darwin', 'plat-mac', 'plat-mac/lib-scriptpackages')]
+
+        for path in hardcoded_paths:
+            if os.path.exists(path):
+                paths.append(path)
+
+    sys.path.extend(paths)
+
+def force_global_eggs_after_local_site_packages():
+    """
+    Force easy_installed eggs in the global environment to get placed
+    in sys.path after all packages inside the virtualenv.  This
+    maintains the "least surprise" result that packages in the
+    virtualenv always mask global packages, never the other way
+    around.
+
+    """
+    egginsert = getattr(sys, '__egginsert', 0)
+    for i, path in enumerate(sys.path):
+        if i > egginsert and path.startswith(sys.prefix):
+            egginsert = i
+    sys.__egginsert = egginsert + 1
+
+def virtual_addsitepackages(known_paths):
+    force_global_eggs_after_local_site_packages()
+    return addsitepackages(known_paths, sys_prefix=sys.real_prefix)
+
+def fixclasspath():
+    """Adjust the special classpath sys.path entries for Jython. These
+    entries should follow the base virtualenv lib directories.
+    """
+    paths = []
+    classpaths = []
+    for path in sys.path:
+        if path == '__classpath__' or path.startswith('__pyclasspath__'):
+            classpaths.append(path)
+        else:
+            paths.append(path)
+    sys.path = paths
+    sys.path.extend(classpaths)
+
+def execusercustomize():
+    """Run custom user specific code, if available."""
+    try:
+        import usercustomize
+    except ImportError:
+        pass
+
+
+def main():
+    global ENABLE_USER_SITE
+    virtual_install_main_packages()
+    abs__file__()
+    paths_in_sys = removeduppaths()
+    if (os.name == "posix" and sys.path and
+        os.path.basename(sys.path[-1]) == "Modules"):
+        addbuilddir()
+    if _is_jython:
+        fixclasspath()
+    GLOBAL_SITE_PACKAGES = not os.path.exists(os.path.join(os.path.dirname(__file__), 'no-global-site-packages.txt'))
+    if not GLOBAL_SITE_PACKAGES:
+        ENABLE_USER_SITE = False
+    if ENABLE_USER_SITE is None:
+        ENABLE_USER_SITE = check_enableusersite()
+    paths_in_sys = addsitepackages(paths_in_sys)
+    paths_in_sys = addusersitepackages(paths_in_sys)
+    if GLOBAL_SITE_PACKAGES:
+        paths_in_sys = virtual_addsitepackages(paths_in_sys)
+    if sys.platform == 'os2emx':
+        setBEGINLIBPATH()
+    setquit()
+    setcopyright()
+    sethelper()
+    aliasmbcs()
+    setencoding()
+    execsitecustomize()
+    if ENABLE_USER_SITE:
+        execusercustomize()
+    # Remove sys.setdefaultencoding() so that users cannot change the
+    # encoding after initialization.  The test for presence is needed when
+    # this module is run as a script, because this code is executed twice.
+    if hasattr(sys, "setdefaultencoding"):
+        del sys.setdefaultencoding
+
+main()
+
+def _script():
+    help = """\
+    %s [--user-base] [--user-site]
+
+    Without arguments print some useful information
+    With arguments print the value of USER_BASE and/or USER_SITE separated
+    by '%s'.
+
+    Exit codes with --user-base or --user-site:
+      0 - user site directory is enabled
+      1 - user site directory is disabled by user
+      2 - uses site directory is disabled by super user
+          or for security reasons
+     >2 - unknown error
+    """
+    args = sys.argv[1:]
+    if not args:
+        print("sys.path = [")
+        for dir in sys.path:
+            print("    %r," % (dir,))
+        print("]")
+        def exists(path):
+            if os.path.isdir(path):
+                return "exists"
+            else:
+                return "doesn't exist"
+        print("USER_BASE: %r (%s)" % (USER_BASE, exists(USER_BASE)))
+        print("USER_SITE: %r (%s)" % (USER_SITE, exists(USER_BASE)))
+        print("ENABLE_USER_SITE: %r" %  ENABLE_USER_SITE)
+        sys.exit(0)
+
+    buffer = []
+    if '--user-base' in args:
+        buffer.append(USER_BASE)
+    if '--user-site' in args:
+        buffer.append(USER_SITE)
+
+    if buffer:
+        print(os.pathsep.join(buffer))
+        if ENABLE_USER_SITE:
+            sys.exit(0)
+        elif ENABLE_USER_SITE is False:
+            sys.exit(1)
+        elif ENABLE_USER_SITE is None:
+            sys.exit(2)
+        else:
+            sys.exit(3)
+    else:
+        import textwrap
+        print(textwrap.dedent(help % (sys.argv[0], os.pathsep)))
+        sys.exit(10)
+
+if __name__ == '__main__':
+    _script()

+ 1 - 0
dog-breed/lib/python3.6/sre_compile.py

@@ -0,0 +1 @@
+/Users/bunny/anaconda/lib/python3.6/sre_compile.py

+ 1 - 0
dog-breed/lib/python3.6/sre_constants.py

@@ -0,0 +1 @@
+/Users/bunny/anaconda/lib/python3.6/sre_constants.py

+ 1 - 0
dog-breed/lib/python3.6/sre_parse.py

@@ -0,0 +1 @@
+/Users/bunny/anaconda/lib/python3.6/sre_parse.py

+ 1 - 0
dog-breed/lib/python3.6/stat.py

@@ -0,0 +1 @@
+/Users/bunny/anaconda/lib/python3.6/stat.py

+ 1 - 0
dog-breed/lib/python3.6/struct.py

@@ -0,0 +1 @@
+/Users/bunny/anaconda/lib/python3.6/struct.py

+ 1 - 0
dog-breed/lib/python3.6/tarfile.py

@@ -0,0 +1 @@
+/Users/bunny/anaconda/lib/python3.6/tarfile.py

+ 1 - 0
dog-breed/lib/python3.6/tempfile.py

@@ -0,0 +1 @@
+/Users/bunny/anaconda/lib/python3.6/tempfile.py

+ 1 - 0
dog-breed/lib/python3.6/token.py

@@ -0,0 +1 @@
+/Users/bunny/anaconda/lib/python3.6/token.py

+ 1 - 0
dog-breed/lib/python3.6/tokenize.py

@@ -0,0 +1 @@
+/Users/bunny/anaconda/lib/python3.6/tokenize.py

+ 1 - 0
dog-breed/lib/python3.6/types.py

@@ -0,0 +1 @@
+/Users/bunny/anaconda/lib/python3.6/types.py

+ 1 - 0
dog-breed/lib/python3.6/warnings.py

@@ -0,0 +1 @@
+/Users/bunny/anaconda/lib/python3.6/warnings.py

+ 1 - 0
dog-breed/lib/python3.6/weakref.py

@@ -0,0 +1 @@
+/Users/bunny/anaconda/lib/python3.6/weakref.py

+ 3 - 0
dog-breed/pyvenv.cfg

@@ -0,0 +1,3 @@
+home = /Users/bunny/anaconda/bin
+include-system-site-packages = false
+version = 3.6.0

+ 133 - 0
labels.txt

@@ -0,0 +1,133 @@
+Affenpinscher
+Afghan_hound
+Airedale_terrier
+Akita
+Alaskan_malamute
+American_eskimo_dog
+American_foxhound
+American_staffordshire_terrier
+American_water_spaniel
+Anatolian_shepherd_dog
+Australian_cattle_dog
+Australian_shepherd
+Australian_terrier
+Basenji
+Basset_hound
+Beagle
+Bearded_collie
+Beauceron
+Bedlington_terrier
+Belgian_malinois
+Belgian_sheepdog
+Belgian_tervuren
+Bernese_mountain_dog
+Bichon_frise
+Black_and_tan_coonhound
+Black_russian_terrier
+Bloodhound
+Bluetick_coonhound
+Border_collie
+Border_terrier
+Borzoi
+Boston_terrier
+Bouvier_des_flandres
+Boxer
+Boykin_spaniel
+Briard
+Brittany
+Brussels_griffon
+Bull_terrier
+Bulldog
+Bullmastiff
+Cairn_terrier
+Canaan_dog
+Cane_corso
+Cardigan_welsh_corgi
+Cavalier_king_charles_spaniel
+Chesapeake_bay_retriever
+Chihuahua
+Chinese_crested
+Chinese_shar-pei
+Chow_chow
+Clumber_spaniel
+Cocker_spaniel
+Collie
+Curly-coated_retriever
+Dachshund
+Dalmatian
+Dandie_dinmont_terrier
+Doberman_pinscher
+Dogue_de_bordeaux
+English_cocker_spaniel
+English_setter
+English_springer_spaniel
+English_toy_spaniel
+Entlebucher_mountain_dog
+Field_spaniel
+Finnish_spitz
+Flat-coated_retriever
+French_bulldog
+German_pinscher
+German_shepherd_dog
+German_shorthaired_pointer
+German_wirehaired_pointer
+Giant_schnauzer
+Glen_of_imaal_terrier
+Golden_retriever
+Gordon_setter
+Great_dane
+Great_pyrenees
+Greater_swiss_mountain_dog
+Greyhound
+Havanese
+Ibizan_hound
+Icelandic_sheepdog
+Irish_red_and_white_setter
+Irish_setter
+Irish_terrier
+Irish_water_spaniel
+Irish_wolfhound
+Italian_greyhound
+Japanese_chin
+Keeshond
+Kerry_blue_terrier
+Komondor
+Kuvasz
+Labrador_retriever
+Lakeland_terrier
+Leonberger
+Lhasa_apso
+Lowchen
+Maltese
+Manchester_terrier
+Mastiff
+Miniature_schnauzer
+Neapolitan_mastiff
+Newfoundland
+Norfolk_terrier
+Norwegian_buhund
+Norwegian_elkhound
+Norwegian_lundehund
+Norwich_terrier
+Nova_scotia_duck_tolling_retriever
+Old_english_sheepdog
+Otterhound
+Papillon
+Parson_russell_terrier
+Pekingese
+Pembroke_welsh_corgi
+Petit_basset_griffon_vendeen
+Pharaoh_hound
+Plott
+Pointer
+Pomeranian
+Poodle
+Portuguese_water_dog
+Saint_bernard
+Silky_terrier
+Smooth_fox_terrier
+Tibetan_mastiff
+Welsh_springer_spaniel
+Wirehaired_pointing_griffon
+Xoloitzcuintli
+Yorkshire_terrier

+ 27 - 0
load.py

@@ -0,0 +1,27 @@
+from typing import Tuple
+from keras.models import model_from_json
+import tensorflow as tf
+
+
+def init_model(model: str, weights: str) -> Tuple:
+    """Initialize the keras model
+
+    :param model, str: path to model.json
+    :param weights, str: path to weights for model
+    :return keras model and graph
+    """
+    with open(model, 'r') as json_file:
+        loaded_model_json = json_file.read()
+
+    loaded_model = model_from_json(loaded_model_json)
+    # load woeights into new model
+    loaded_model.load_weights(weights)
+
+    # compile and evaluate loaded model
+    loaded_model.compile(
+        loss='categorical_crossentropy',
+        optimizer='adam',
+        metrics=['accuracy'])
+    graph = tf.get_default_graph()
+
+    return loaded_model, graph

+ 1 - 0
models/model.Resnet50.json

@@ -0,0 +1 @@
+{"class_name": "Sequential", "config": [{"class_name": "Flatten", "config": {"name": "flatten_1", "trainable": true, "batch_input_shape": [null, 1, 1, 2048], "dtype": "float32"}}, {"class_name": "Dense", "config": {"name": "dense_1", "trainable": true, "units": 256, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "mode": "fan_avg", "distribution": "uniform", "seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}}, {"class_name": "Dropout", "config": {"name": "dropout_1", "trainable": true, "rate": 0.4}}, {"class_name": "Dense", "config": {"name": "dense_2", "trainable": true, "units": 133, "activation": "softmax", "use_bias": true, "kernel_initializer": {"class_name": "VarianceScaling", "config": {"scale": 1.0, "mode": "fan_avg", "distribution": "uniform", "seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}}], "keras_version": "2.0.5", "backend": "tensorflow"}

File diff suppressed because it is too large
+ 0 - 0
models/model.inceptionv3.json


BIN
models/weights.Resnet50.hdf5


BIN
models/weights.inceptionv3.h5


+ 6 - 0
requirements.txt

@@ -0,0 +1,6 @@
+Flask
+Keras
+numpy
+scipy
+pillow
+h5py

BIN
screenshots/screenshot_1.png


BIN
static/favicon.ico


+ 30 - 0
templates/layout.html

@@ -0,0 +1,30 @@
+<!doctype html>
+<head>
+    <title>Simple Dog Breed Classifier</title>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}">
+    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
+    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
+    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
+</head>
+<nav class="navbar navbar-default">
+    <div class="container-fluid">
+        <div class="navbar-header">
+            <a class="navbar-brand" href="/">
+                Dog Breed
+                {% if model_name is defined %}
+                    {{ model_name|title }}
+                {% endif %}
+                Classifier
+            </a>
+        </div>
+        <div class="pull-right">
+            {% block nav_buttons %}
+            {% endblock %}
+    </div>
+</nav>
+
+<div class="container-fluid">
+    {% block body %}{% endblock %}
+</div>

+ 30 - 0
templates/results.html

@@ -0,0 +1,30 @@
+{% extends "layout.html" %}
+{% block body %}
+<table class="table table-hover table-sm table-stripped">
+    <tbody>
+        {% for result in results %}
+        <tr>
+            <td align="center"><b> {{ result.filename }} </b></td>
+            {% for predict_prob in result.predict_probs %}
+                <td align="center"><b> {{ predict_prob.name|replace("_", " ")|
+                        title}} </b></td>
+            {% endfor %}
+        </tr>
+        <tr>
+            <td align="center">
+                <img src="data:image/png;base64,{{ result.image }}" style="width:244px;
+                height:224px;" class="img-rounded"/>
+            </td>
+            {% for predict_prob in result.predict_probs %}
+                <td class="vert-align" align="center"> {{ predict_prob.prob }}
+                </td>
+            {% endfor %}
+        </tr>
+        {% endfor %}
+    </tbody>
+</table>
+{% endblock %}
+{% block nav_buttons %}
+<a class="btn btn-default navbar-btn" href='{{ url_for('index')}}'>Start Over</a>
+<a class="btn btn-default navbar-btn" href='{{ url_for('predict')}}'>Select New Files</a>
+{% endblock %}

+ 20 - 0
templates/select_files.html

@@ -0,0 +1,20 @@
+{% extends "layout.html" %}
+{% block body %}
+    <form action="{{ url_for('predict') }}" method="POST"
+                                            enctype="multipart/form-data">
+        <div class="form-group">
+            <label for="fileupload">Select Files:</label>
+            <input type="file" name="file[]" multiple="" id='fileupload'>
+            <p class="help-block">Image types only. Image will be converted to
+            proper shape.<br/>Also allow for time for image upload and predictions.
+            </p>
+            <label class="btn btn-primary">
+                Upload <input type="submit" value="Upload" style="display:
+                none;">
+            </label>
+        </div>
+    </form>
+{% endblock %}
+{% block nav_buttons %}
+<a class="btn btn-default navbar-btn" href='{{ url_for('index')}}'>Start Over</a>
+{% endblock %}

+ 25 - 0
templates/settings.html

@@ -0,0 +1,25 @@
+{% extends "layout.html" %}
+{% block body %}
+    <form action="{{ url_for('settings') }}" method="POST">
+        <div class="form-group">
+            <label for="model">Select Model To Use:</label>
+            <select class="form-control" name="model" id="model">
+                <option value="inception">Inception V3</option>
+                <option value="resnet">Resnet50 (using bottleneck features as
+                input)</option>
+            </select>
+            <p class="help-block">
+            The Inception model takes longer to load since it's loading the
+            whole architecture and weights but inference will be
+            faster.<br/><br/>On the other hand, the Resnet50
+            loads a smaller architecture but inference is slower because it
+            needs to extract bottleneck features on the Keras Resnet50 model
+            before doing predictions.
+            </p>
+            <label class="btn btn-primary">
+                Submit<input type="submit" value="settings" style="display:
+                none;">
+            </label>
+        </div>
+    </form>
+{% endblock %}

+ 79 - 0
util.py

@@ -0,0 +1,79 @@
+import numpy as np
+import os
+
+from keras.preprocessing import image
+from operator import itemgetter
+
+IMAGE_DIM = (224, 224)
+LABELS_PATH = os.path.abspath('labels.txt')
+
+global labels
+
+with open(LABELS_PATH) as f:
+    labels = f.readlines()
+
+labels = np.array([label.strip() for label in labels])
+
+
+def img_to_tensor(img):
+    """Loads a PIL image and outputs a 4d tensor
+
+    :param img, PIL Image object
+    :return 4D numpy array/tensor
+    """
+    if img.size != IMAGE_DIM:
+        img = img.resize(IMAGE_DIM)
+    # convert to 3d array
+    x = image.img_to_array(img)
+    # conver to 4d
+    return np.expand_dims(x, axis=0)
+
+
+def preprocess_inception(img):
+    """Prepare image for Inception model
+
+    :param img, PIL Image object
+    :return preprocssed input for inception model
+    """
+    from keras.applications.inception_v3 import preprocess_input
+    img = preprocess_input(img_to_tensor(img))
+    return img
+
+
+def extract_bottleneck_features_resnet(tensor):
+    from keras.applications.resnet50 import ResNet50
+    return ResNet50(weights='imagenet', include_top=False).predict(tensor)
+
+
+def preprocess_resnet(img):
+    """Prepare image for Resnet50 model
+    """
+    from keras.applications.resnet50 import preprocess_input
+    img = preprocess_input(img_to_tensor(img))
+    return extract_bottleneck_features_resnet(img)
+
+
+def decode_prob(output_arr, top_probs=5):
+    """Label class probabilities with class names
+
+    :param output_arr, list: class probabilities
+    :param top_probs, int: number of class probabilities to return out of 133
+
+    :return list[dict]:
+    """
+    results = []
+    for row in output_arr:
+        entries = []
+        for name, prob in zip(labels, row[0]):
+            entries.append({'name': name,
+                            'prob': prob})
+
+        entries = sorted(entries,
+                         key=itemgetter('prob'),
+                         reverse=True)[:top_probs]
+
+        for entry in entries:
+            entry['prob'] = '{:.5f}'.format(entry['prob'])
+
+        results.append(entries)
+    return results

Some files were not shown because too many files changed in this diff