├── src
├── __init__.py
├── common
│ ├── __init__.py
│ ├── consts.py
│ └── paths.py
├── models
│ ├── __init__.py
│ └── denseNN.py
├── analysis
│ ├── __init__.py
│ └── training_perf_analysis.py
├── freezing
│ ├── __init__.py
│ ├── inception.py
│ ├── frozen_to_saved_model.py
│ └── freeze.py
├── inference
│ ├── __init__.py
│ ├── classify.py
│ └── inference.py
├── training
│ ├── __init__.py
│ └── train.py
└── data_preparation
│ ├── __init__.py
│ ├── tf_record_utils.py
│ ├── image_utils.py
│ ├── dataset.py
│ ├── stanford_ds_to_tfrecords.py
│ └── kaggle_images_to_tfrecords.py
├── .DS_Store
├── images
├── preview.png
├── airedale.jpg
├── preview2.jpg
├── shih-tzu.jpg
└── kaggle_leaderboard.jpg
├── requirements.txt
├── setup
├── setup.sh
├── create_dirs.sh
├── inception_download.sh
└── download_stanford_dogs_dataset.sh
├── .idea
└── vcs.xml
├── jupyter_notebook_config.py
├── Dockerfile
├── .gitignore
├── data
└── breeds.csv
└── README.md
/src/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/common/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/models/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/analysis/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/freezing/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/inference/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/training/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/data_preparation/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stormy-ua/dog-breeds-classification/HEAD/.DS_Store
--------------------------------------------------------------------------------
/images/preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stormy-ua/dog-breeds-classification/HEAD/images/preview.png
--------------------------------------------------------------------------------
/images/airedale.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stormy-ua/dog-breeds-classification/HEAD/images/airedale.jpg
--------------------------------------------------------------------------------
/images/preview2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stormy-ua/dog-breeds-classification/HEAD/images/preview2.jpg
--------------------------------------------------------------------------------
/images/shih-tzu.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stormy-ua/dog-breeds-classification/HEAD/images/shih-tzu.jpg
--------------------------------------------------------------------------------
/images/kaggle_leaderboard.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stormy-ua/dog-breeds-classification/HEAD/images/kaggle_leaderboard.jpg
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | tensorflow
2 | pandas
3 | numpy
4 | matplotlib
5 | pyprind
6 | scikit-learn
7 | scipy
8 | jupyter
9 | Pillow
10 |
--------------------------------------------------------------------------------
/setup/setup.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | sh ./setup/create_dirs.sh
4 | sh ./setup/inception_download.sh
5 | sh ./setup/download_stanford_dogs_dataset.sh
--------------------------------------------------------------------------------
/setup/create_dirs.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | mkdir -p data
4 | mkdir -p checkpoints
5 | mkdir -p frozen
6 | mkdir -p graphs
7 | mkdir -p metrics
8 | mkdir -p summary
9 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/jupyter_notebook_config.py:
--------------------------------------------------------------------------------
1 | import os
2 | from IPython.lib import passwd
3 |
4 | c.NotebookApp.ip = '*'
5 | c.NotebookApp.port = int(os.getenv('PORT', 8888))
6 | c.NotebookApp.open_browser = False
7 |
8 | c.NotebookApp.password = ''
9 | c.NotebookApp.token = ''
10 |
--------------------------------------------------------------------------------
/setup/inception_download.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | mkdir -p frozen/inception
4 | curl -o ./frozen/inception/inception.tgz http://download.tensorflow.org/models/image/imagenet/inception-2015-12-05.tgz
5 | tar xfz ./frozen/inception/inception.tgz -C ./frozen/inception
6 |
--------------------------------------------------------------------------------
/setup/download_stanford_dogs_dataset.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | mkdir -p data/stanford_ds
4 | curl -o data/stanford_ds/images.tar http://vision.stanford.edu/aditya86/ImageNetDogs/images.tar
5 | tar xfz data/stanford_ds/images.tar -C data/stanford_ds/
6 | curl -o data/stanford_ds/annotation.tar http://vision.stanford.edu/aditya86/ImageNetDogs/annotation.tar
7 | tar xfz data/stanford_ds/annotation.tar -C data/stanford_ds/
8 |
--------------------------------------------------------------------------------
/src/data_preparation/tf_record_utils.py:
--------------------------------------------------------------------------------
1 | import tensorflow as tf
2 |
3 |
4 | def int64_feature(value):
5 | return tf.train.Feature(int64_list=tf.train.Int64List(value=[value]))
6 |
7 |
8 | def float_feature(value):
9 | return tf.train.Feature(float_list=tf.train.FloatList(value=value))
10 |
11 |
12 | def bytes_feature(value):
13 | return tf.train.Feature(bytes_list=tf.train.BytesList(value=[value]))
14 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:2.7
2 |
3 | MAINTAINER Kirill Panarin
4 |
5 | EXPOSE 8888
6 | EXPOSE 6006
7 |
8 | WORKDIR /app
9 |
10 | COPY requirements.txt ./
11 | RUN pip install --no-cache-dir -r requirements.txt
12 |
13 | COPY jupyter_notebook_config.py /root/.jupyter/
14 |
15 | COPY ./src /app/src
16 | COPY ./images /app/images
17 | COPY ./checkpoints /app/checkpoints
18 | COPY ./frozen /app/frozen
19 | COPY ./data/train/labels.csv /app/data/train/
20 | COPY ./data/*.tfrecords /app/data/
21 | COPY ./data/breeds.csv /app/data/
22 | COPY ./*.ipynb /app/
23 | COPY ./summary /app/summary
24 |
25 | WORKDIR /app
26 |
27 | CMD [ "jupyter", "notebook", "--allow-root"]
28 |
29 |
--------------------------------------------------------------------------------
/src/common/consts.py:
--------------------------------------------------------------------------------
1 | CLASSES_COUNT = 120
2 | INCEPTION_CLASSES_COUNT = 2048
3 | INCEPTION_OUTPUT_FIELD = 'inception_output'
4 | LABEL_ONE_HOT_FIELD = 'label_one_hot'
5 | IMAGE_RAW_FIELD = 'image_raw'
6 | INCEPTION_INPUT_TENSOR = 'DecodeJpeg/contents:0'
7 | INCEPTION_OUTPUT_TENSOR = 'pool_3:0'
8 | OUTPUT_NODE_NAME = 'output_node'
9 | OUTPUT_TENSOR_NAME = OUTPUT_NODE_NAME + ':0'
10 | HEAD_INPUT_NODE_NAME = 'x'
11 | HEAD_INPUT_TENSOR_NAME = HEAD_INPUT_NODE_NAME + ':0'
12 |
13 | DEV_SET_SIZE = 3000
14 | TRAIN_SAMPLE_SIZE = 3000
15 |
16 | # name of the model being referenced by all other scripts
17 | CURRENT_MODEL_NAME = 'stanford_5_64_0001'
18 | # sets up number of layers and number of units in each layer for
19 | # the "head" dense neural network stacked on top of the Inception
20 | # pre-trained model.
21 | HEAD_MODEL_LAYERS = [INCEPTION_CLASSES_COUNT, 1024, CLASSES_COUNT]
--------------------------------------------------------------------------------
/src/common/paths.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | JPEG_EXT = '.jpg'
4 | DATA_ROOT = 'data/'
5 | TRAIN_DIR = os.path.join(DATA_ROOT, 'train')
6 | TEST_DIR = os.path.join(DATA_ROOT, 'test')
7 | #TRAIN_TF_RECORDS = os.path.join(ROOT, 'dogs_train.tfrecords')
8 | TRAIN_TF_RECORDS = os.path.join(DATA_ROOT, 'stanford.tfrecords')
9 | TEST_TF_RECORDS = os.path.join(DATA_ROOT, 'dogs_test.tfrecords')
10 | LABELS = os.path.join(DATA_ROOT, 'train', 'labels.csv')
11 | BREEDS = os.path.join(DATA_ROOT, 'breeds.csv')
12 | IMAGENET_GRAPH_DEF = 'frozen/inception/classify_image_graph_def.pb'
13 | TEST_PREDICTIONS = 'predictions.csv'
14 | METRICS_DIR = 'metrics'
15 | TRAIN_CONFUSION = os.path.join(METRICS_DIR, 'training_confusion.csv')
16 | FROZEN_MODELS_DIR = 'frozen'
17 | CHECKPOINTS_DIR = 'checkpoints'
18 | GRAPHS_DIR = 'graphs'
19 | SUMMARY_DIR = 'summary'
20 | STANFORD_DS_DIR = os.path.join(DATA_ROOT, 'stanford_ds')
21 | STANFORD_DS_TF_RECORDS = os.path.join(DATA_ROOT, 'stanford.tfrecords')
22 |
23 |
--------------------------------------------------------------------------------
/src/freezing/inception.py:
--------------------------------------------------------------------------------
1 | import tensorflow as tf
2 |
3 | from src.common import consts
4 | import freeze
5 | from src.common import paths
6 |
7 |
8 | def inception_model():
9 | tensors = freeze.unfreeze_into_current_graph(paths.IMAGENET_GRAPH_DEF,
10 | tensor_names=[
11 | consts.INCEPTION_INPUT_TENSOR,
12 | consts.INCEPTION_OUTPUT_TENSOR])
13 |
14 | def forward(sess, image_raw):
15 | out = sess.run(tensors[consts.INCEPTION_OUTPUT_TENSOR], {tensors[consts.INCEPTION_INPUT_TENSOR]: image_raw})
16 | return out
17 |
18 | return forward
19 |
20 |
21 | if __name__ == '__main__':
22 | with tf.Session().as_default() as sess:
23 | image_raw = tf.read_file('../../images/airedale.jpg').eval()
24 |
25 | g = tf.Graph()
26 | sess = tf.Session(graph=g)
27 |
28 | with g.as_default():
29 | model = inception_model()
30 |
31 | with g.as_default():
32 | out = model(sess, image_raw)
33 | print(out.shape)
34 |
--------------------------------------------------------------------------------
/src/data_preparation/image_utils.py:
--------------------------------------------------------------------------------
1 | import matplotlib.pyplot as plt
2 | import tensorflow as tf
3 |
4 | from src.common import consts
5 | from src.training import train
6 | from src.common import paths
7 |
8 |
9 | # makes sense to have k = {1, 3}
10 | def rotate_ccw(img, k = 1):
11 | return tf.image.rot90(img, k)
12 |
13 | def flip_along_width(img):
14 | return tf.image.flip_left_right(img)
15 |
16 | #delta = {-0.1, 0.1}
17 | def adjust_brightness(img, delta=-0.1):
18 | return tf.image.adjust_brightness(img, delta=delta)
19 |
20 | def adjust_contrast(img, contrast_factor=0.8):
21 | return tf.image.adjust_contrast(img, contrast_factor=contrast_factor)
22 |
23 |
24 | if __name__ == '__main__':
25 | with tf.Graph().as_default() as g, tf.Session().as_default() as sess:
26 | next_train_batch, _, _ = train.train_dev_split(sess, paths.TRAIN_TF_RECORDS, batch_size=1)
27 |
28 | batch = sess.run(next_train_batch)
29 | img_raw = batch[consts.IMAGE_RAW_FIELD]
30 | img = adjust_brightness(tf.image.decode_jpeg(img_raw[0]), 0.1).eval()
31 |
32 | print(img.shape)
33 |
34 | plt.imshow(img)
35 | plt.show()
36 |
--------------------------------------------------------------------------------
/src/inference/classify.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 | import urllib2
4 |
5 | import numpy as np
6 | import pandas as pd
7 | import tensorflow as tf
8 |
9 | from src.common import consts
10 | from src.data_preparation import dataset
11 | from src.freezing import freeze
12 | from src.common import paths
13 |
14 |
15 | def infer(model_name, img_raw):
16 | with tf.Graph().as_default(), tf.Session().as_default() as sess:
17 | tensors = freeze.unfreeze_into_current_graph(
18 | os.path.join(paths.FROZEN_MODELS_DIR, model_name + '.pb'),
19 | tensor_names=[consts.INCEPTION_INPUT_TENSOR, consts.OUTPUT_TENSOR_NAME])
20 |
21 | _, one_hot_decoder = dataset.one_hot_label_encoder()
22 |
23 | probs = sess.run(tensors[consts.OUTPUT_TENSOR_NAME],
24 | feed_dict={tensors[consts.INCEPTION_INPUT_TENSOR]: img_raw})
25 |
26 | breeds = one_hot_decoder(np.identity(consts.CLASSES_COUNT)).reshape(-1)
27 |
28 | # print(breeds)
29 |
30 | df = pd.DataFrame(data={'prob': probs.reshape(-1), 'breed': breeds})
31 |
32 |
33 | return df.sort_values(['prob'], ascending=False)
34 |
35 |
36 | def classify(resource_type, path):
37 | if resource_type == 'uri':
38 | response = urllib2.urlopen(path)
39 | img_raw = response.read()
40 | else:
41 | with open(path, 'r') as f:
42 | img_raw = f.read()
43 |
44 | return infer(consts.CURRENT_MODEL_NAME, img_raw)
45 |
46 | if __name__ == '__main__':
47 | src = sys.argv[1]
48 | path = sys.argv[2] # uri to a dog image to classify
49 | probs = classify(src, path)
50 |
51 | print(probs.sort_values(['prob'], ascending=False).take(range(5)))
52 |
53 |
--------------------------------------------------------------------------------
/src/freezing/frozen_to_saved_model.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 | import urllib2
4 |
5 | import numpy as np
6 | import pandas as pd
7 | import tensorflow as tf
8 |
9 | from src.common import consts
10 | from src.data_preparation import dataset
11 | from src.freezing import freeze
12 | from src.common import paths
13 |
14 | def convert(model_name, export_dir):
15 | builder = tf.saved_model.builder.SavedModelBuilder(export_dir=export_dir)
16 |
17 | with tf.Graph().as_default(), tf.Session().as_default() as sess:
18 | tensors = freeze.unfreeze_into_current_graph(
19 | os.path.join(paths.FROZEN_MODELS_DIR, model_name + '.pb'),
20 | tensor_names=[consts.INCEPTION_INPUT_TENSOR, consts.OUTPUT_TENSOR_NAME])
21 |
22 | raw_image_proto_info = tf.saved_model.utils.build_tensor_info(tensors[consts.INCEPTION_INPUT_TENSOR])
23 | probs_proto_info = tf.saved_model.utils.build_tensor_info(tensors[consts.OUTPUT_TENSOR_NAME])
24 |
25 | prediction_signature = (
26 | tf.saved_model.signature_def_utils.build_signature_def(
27 | inputs={'image_raw': raw_image_proto_info},
28 | outputs={'probs': probs_proto_info},
29 | method_name=tf.saved_model.signature_constants.PREDICT_METHOD_NAME))
30 |
31 | builder.add_meta_graph_and_variables(sess, [tf.saved_model.tag_constants.SERVING],
32 | signature_def_map={
33 | tf.saved_model.signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY: prediction_signature
34 | })
35 |
36 | builder.save()
37 |
38 | if __name__ == '__main__':
39 | convert(consts.CURRENT_MODEL_NAME, export_dir='/tmp/dogs_1')
--------------------------------------------------------------------------------
/.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 | env/
12 | build/
13 | develop-eggs/
14 | dist/
15 | downloads/
16 | eggs/
17 | .eggs/
18 | lib/
19 | lib64/
20 | parts/
21 | sdist/
22 | var/
23 | wheels/
24 | *.egg-info/
25 | .installed.cfg
26 | *.egg
27 |
28 | # PyInstaller
29 | # Usually these files are written by a python script from a template
30 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
31 | *.manifest
32 | *.spec
33 |
34 | # Installer logs
35 | pip-log.txt
36 | pip-delete-this-directory.txt
37 |
38 | # Unit test / coverage reports
39 | htmlcov/
40 | .tox/
41 | .coverage
42 | .coverage.*
43 | .cache
44 | nosetests.xml
45 | coverage.xml
46 | *.cover
47 | .hypothesis/
48 |
49 | # Translations
50 | *.mo
51 | *.pot
52 |
53 | # Django stuff:
54 | *.log
55 | local_settings.py
56 |
57 | # Flask stuff:
58 | instance/
59 | .webassets-cache
60 |
61 | # Scrapy stuff:
62 | .scrapy
63 |
64 | # Sphinx documentation
65 | docs/_build/
66 |
67 | # PyBuilder
68 | target/
69 |
70 | # Jupyter Notebook
71 | .ipynb_checkpoints
72 |
73 | # pyenv
74 | .python-version
75 |
76 | # celery beat schedule file
77 | celerybeat-schedule
78 |
79 | # SageMath parsed files
80 | *.sage.py
81 |
82 | # dotenv
83 | .env
84 |
85 | # virtualenv
86 | .venv
87 | venv/
88 | ENV/
89 |
90 | # Spyder project settings
91 | .spyderproject
92 | .spyproject
93 |
94 | # Rope project settings
95 | .ropeproject
96 |
97 | # mkdocs documentation
98 | /site
99 |
100 | # mypy
101 | .mypy_cache/
102 |
103 | checkpoints/
104 | data/
105 | frozen/
106 | graphs/
107 | metrics/
108 | summary/
109 | .idea/
110 | dog_breeds/
111 | idea
112 | .DS_Store/
113 | .DS_Store
114 |
--------------------------------------------------------------------------------
/src/models/denseNN.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import tensorflow as tf
3 |
4 | from src.common import consts
5 |
6 |
7 | def denseNNModel(input_node, layers, gamma=0.1):
8 | n_x = layers[0]
9 | n_y = layers[-1]
10 | L = len(layers)
11 | summaries = []
12 | Ws = []
13 |
14 | with tf.name_scope("placeholders"):
15 | # x = tf.placeholder(dtype=tf.float32, shape=(n_x, None), name="x")
16 | y = tf.placeholder(dtype=tf.float32, shape=(n_y, None), name="y")
17 |
18 | a = input_node
19 |
20 | with tf.name_scope("hidden_layers"):
21 | for l in range(1, len(layers) - 1):
22 | W = tf.Variable(np.random.randn(layers[l], layers[l - 1]) / tf.sqrt(layers[l - 1] * 1.0), dtype=tf.float32,
23 | name="W" + str(l))
24 | Ws.append(W)
25 | summaries.append(tf.summary.histogram('W' + str(l), W))
26 | b = tf.Variable(np.zeros((layers[l], 1)), dtype=tf.float32, name="b" + str(l))
27 | summaries.append(tf.summary.histogram('b' + str(l), b))
28 | z = tf.matmul(W, a) + b
29 | a = tf.nn.relu(z)
30 |
31 | W = tf.Variable(np.random.randn(layers[L - 1], layers[L - 2]) / tf.sqrt(layers[L - 2] * 1.0), dtype=tf.float32,
32 | name="W" + str(L - 1))
33 | summaries.append(tf.summary.histogram('W' + str(L - 1), W))
34 | b = tf.Variable(np.zeros((layers[L - 1], 1)), dtype=tf.float32, name="b" + str(L - 1))
35 | summaries.append(tf.summary.histogram('b' + str(L - 1), b))
36 | z = tf.matmul(W, a) + b
37 |
38 | with tf.name_scope("cost"):
39 | cost = tf.reduce_mean(
40 | tf.nn.softmax_cross_entropy_with_logits(labels=tf.transpose(y), logits=tf.transpose(z))) # +\
41 | # gamma * tf.reduce_sum([tf.nn.l2_loss(w) for w in Ws])
42 | summaries.append(tf.summary.scalar('cost', cost))
43 |
44 | output = tf.nn.softmax(z, dim=0, name=consts.OUTPUT_NODE_NAME)
45 |
46 | return cost, output, y, summaries
47 |
--------------------------------------------------------------------------------
/src/inference/inference.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | import numpy as np
4 | import pandas as pd
5 | import tensorflow as tf
6 |
7 | from src.common import consts
8 | from src.data_preparation import dataset
9 | from src.models import denseNN
10 | from src.common import paths
11 |
12 |
13 | def infer_test(model_name, output_probs, x):
14 | BATCH_SIZE = 20000
15 |
16 | with tf.Session().as_default() as sess:
17 | ds, filename = dataset.test_features_dataset()
18 | ds_iter = ds.batch(BATCH_SIZE).make_initializable_iterator()
19 | sess.run(ds_iter.initializer, feed_dict={filename: paths.TEST_TF_RECORDS})
20 |
21 | tf.global_variables_initializer().run()
22 |
23 | saver = tf.train.Saver()
24 | lines = open(os.path.join(paths.CHECKPOINTS_DIR, model_name + '_latest')).read().split('\n')
25 | last_checkpoint = [l.split(':')[1].replace('"', '').strip() for l in lines if 'model_checkpoint_path:' in l][0]
26 | saver.restore(sess, os.path.join(paths.CHECKPOINTS_DIR, last_checkpoint))
27 |
28 | _, one_hot_decoder = dataset.one_hot_label_encoder()
29 |
30 | breeds = one_hot_decoder(np.identity(consts.CLASSES_COUNT))
31 | agg_test_df = None
32 |
33 | try:
34 | while True:
35 | test_batch = sess.run(ds_iter.get_next())
36 |
37 | inception_output = test_batch['inception_output']
38 | ids = test_batch['id']
39 |
40 | pred_probs = sess.run(output_probs, feed_dict={x: inception_output.T})
41 |
42 | #print(pred_probs.shape)
43 |
44 | test_df = pd.DataFrame(data=pred_probs.T, columns=breeds)
45 | test_df.index = ids
46 |
47 | if agg_test_df is None:
48 | agg_test_df = test_df
49 | else:
50 | agg_test_df = agg_test_df.append(test_df)
51 |
52 | except tf.errors.OutOfRangeError:
53 | print('End of the dataset')
54 |
55 | agg_test_df.to_csv(paths.TEST_PREDICTIONS, index_label='id', float_format='%.17f')
56 |
57 | print('predictions saved to %s' % paths.TEST_PREDICTIONS)
58 |
59 | if __name__ == '__main__':
60 | with tf.Graph().as_default():
61 | x = tf.placeholder(dtype=tf.float32, shape=(consts.INCEPTION_CLASSES_COUNT, None), name="x")
62 | _, output_probs, _, _ = denseNN.denseNNModel(
63 | x, consts.HEAD_MODEL_LAYERS, gamma=0.01)
64 | infer_test(consts.CURRENT_MODEL_NAME, output_probs, x)
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/src/analysis/training_perf_analysis.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | import numpy as np
4 | import pandas as pd
5 | import tensorflow as tf
6 |
7 | from src.common import consts
8 | from src.data_preparation import dataset
9 | from src.models import denseNN
10 | from src.common import paths
11 |
12 |
13 | def infer_train(model_name, output_probs, x):
14 | BATCH_SIZE = 20000
15 |
16 | with tf.Session().as_default() as sess:
17 | ds, filename = dataset.features_dataset()
18 | ds_iter = ds.batch(BATCH_SIZE).make_initializable_iterator()
19 | sess.run(ds_iter.initializer, feed_dict={filename: paths.TRAIN_TF_RECORDS})
20 |
21 | tf.global_variables_initializer().run()
22 |
23 | saver = tf.train.Saver()
24 | lines = open(os.path.join(paths.CHECKPOINTS_DIR, model_name + '_latest')).read().split('\n')
25 | last_checkpoint = [l.split(':')[1].replace('"', '').strip() for l in lines if 'model_checkpoint_path:' in l][0]
26 | saver.restore(sess, os.path.join(paths.CHECKPOINTS_DIR, last_checkpoint))
27 |
28 | _, one_hot_decoder = dataset.one_hot_label_encoder()
29 |
30 | breeds = one_hot_decoder(np.identity(consts.CLASSES_COUNT))
31 | agg_test_df = None
32 |
33 | try:
34 | while True:
35 | test_batch = sess.run(ds_iter.get_next())
36 |
37 | inception_output = test_batch['inception_output']
38 | labels = test_batch['label']
39 |
40 | pred_probs = sess.run(output_probs, feed_dict={x: inception_output.T})
41 | pred_probs_max = pred_probs >= np.max(pred_probs, axis=0)
42 | pred_breeds = one_hot_decoder(pred_probs_max.T)
43 |
44 | test_df = pd.DataFrame(data={'pred': pred_breeds, 'actual': labels})
45 |
46 | if agg_test_df is None:
47 | agg_test_df = test_df
48 | else:
49 | agg_test_df = agg_test_df.append(test_df)
50 |
51 | except tf.errors.OutOfRangeError:
52 | print('End of the dataset')
53 |
54 | print(agg_test_df.take(range(0, 10)))
55 |
56 | agg_test_df.to_csv(paths.TRAIN_CONFUSION, index_label='id', float_format='%.17f')
57 |
58 | print('predictions saved to %s' % paths.TRAIN_CONFUSION)
59 |
60 |
61 | if __name__ == '__main__':
62 | with tf.Graph().as_default():
63 | x = tf.placeholder(dtype=tf.float32, shape=(consts.INCEPTION_CLASSES_COUNT, None), name="x")
64 | _, output_probs, _, _ = denseNN.denseNNModel(
65 | x, consts.HEAD_MODEL_LAYERS, gamma=0.01)
66 | infer_train(consts.CURRENT_MODEL_NAME, output_probs, x)
67 |
--------------------------------------------------------------------------------
/data/breeds.csv:
--------------------------------------------------------------------------------
1 | id,breed
2 | 0,affenpinscher
3 | 1,afghan_hound
4 | 2,african_hunting_dog
5 | 3,airedale
6 | 4,american_staffordshire_terrier
7 | 5,appenzeller
8 | 6,australian_terrier
9 | 7,basenji
10 | 8,basset
11 | 9,beagle
12 | 10,bedlington_terrier
13 | 11,bernese_mountain_dog
14 | 12,black-and-tan_coonhound
15 | 13,blenheim_spaniel
16 | 14,bloodhound
17 | 15,bluetick
18 | 16,border_collie
19 | 17,border_terrier
20 | 18,borzoi
21 | 19,boston_bull
22 | 20,bouvier_des_flandres
23 | 21,boxer
24 | 22,brabancon_griffon
25 | 23,briard
26 | 24,brittany_spaniel
27 | 25,bull_mastiff
28 | 26,cairn
29 | 27,cardigan
30 | 28,chesapeake_bay_retriever
31 | 29,chihuahua
32 | 30,chow
33 | 31,clumber
34 | 32,cocker_spaniel
35 | 33,collie
36 | 34,curly-coated_retriever
37 | 35,dandie_dinmont
38 | 36,dhole
39 | 37,dingo
40 | 38,doberman
41 | 39,english_foxhound
42 | 40,english_setter
43 | 41,english_springer
44 | 42,entlebucher
45 | 43,eskimo_dog
46 | 44,flat-coated_retriever
47 | 45,french_bulldog
48 | 46,german_shepherd
49 | 47,german_short-haired_pointer
50 | 48,giant_schnauzer
51 | 49,golden_retriever
52 | 50,gordon_setter
53 | 51,great_dane
54 | 52,great_pyrenees
55 | 53,greater_swiss_mountain_dog
56 | 54,groenendael
57 | 55,ibizan_hound
58 | 56,irish_setter
59 | 57,irish_terrier
60 | 58,irish_water_spaniel
61 | 59,irish_wolfhound
62 | 60,italian_greyhound
63 | 61,japanese_spaniel
64 | 62,keeshond
65 | 63,kelpie
66 | 64,kerry_blue_terrier
67 | 65,komondor
68 | 66,kuvasz
69 | 67,labrador_retriever
70 | 68,lakeland_terrier
71 | 69,leonberg
72 | 70,lhasa
73 | 71,malamute
74 | 72,malinois
75 | 73,maltese_dog
76 | 74,mexican_hairless
77 | 75,miniature_pinscher
78 | 76,miniature_poodle
79 | 77,miniature_schnauzer
80 | 78,newfoundland
81 | 79,norfolk_terrier
82 | 80,norwegian_elkhound
83 | 81,norwich_terrier
84 | 82,old_english_sheepdog
85 | 83,otterhound
86 | 84,papillon
87 | 85,pekinese
88 | 86,pembroke
89 | 87,pomeranian
90 | 88,pug
91 | 89,redbone
92 | 90,rhodesian_ridgeback
93 | 91,rottweiler
94 | 92,saint_bernard
95 | 93,saluki
96 | 94,samoyed
97 | 95,schipperke
98 | 96,scotch_terrier
99 | 97,scottish_deerhound
100 | 98,sealyham_terrier
101 | 99,shetland_sheepdog
102 | 100,shih-tzu
103 | 101,siberian_husky
104 | 102,silky_terrier
105 | 103,soft-coated_wheaten_terrier
106 | 104,staffordshire_bullterrier
107 | 105,standard_poodle
108 | 106,standard_schnauzer
109 | 107,sussex_spaniel
110 | 108,tibetan_mastiff
111 | 109,tibetan_terrier
112 | 110,toy_poodle
113 | 111,toy_terrier
114 | 112,vizsla
115 | 113,walker_hound
116 | 114,weimaraner
117 | 115,welsh_springer_spaniel
118 | 116,west_highland_white_terrier
119 | 117,whippet
120 | 118,wire-haired_fox_terrier
121 | 119,yorkshire_terrier
122 |
--------------------------------------------------------------------------------
/src/data_preparation/dataset.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import pandas as pd
3 | import tensorflow as tf
4 | from sklearn import preprocessing
5 |
6 | from src.common import consts
7 | from src.common import paths
8 |
9 |
10 | def get_int64_feature(example, name):
11 | return int(example.features.feature[name].int64_list.value[0])
12 |
13 |
14 | def get_float_feature(example, name):
15 | return int(example.features.feature[name].float_list.value)
16 |
17 |
18 | def get_bytes_feature(example, name):
19 | return example.features.feature[name].bytes_list.value[0]
20 |
21 |
22 | def read_tf_record(record):
23 | features = tf.parse_single_example(
24 | record,
25 | features={
26 | consts.IMAGE_RAW_FIELD: tf.FixedLenFeature([], tf.string),
27 | 'label': tf.FixedLenFeature([], tf.string),
28 | consts.LABEL_ONE_HOT_FIELD: tf.FixedLenFeature([consts.CLASSES_COUNT], tf.float32),
29 | consts.INCEPTION_OUTPUT_FIELD: tf.FixedLenFeature([2048], tf.float32)
30 | })
31 | return features
32 |
33 |
34 | def read_test_tf_record(record):
35 | features = tf.parse_single_example(
36 | record,
37 | features={
38 | 'id': tf.FixedLenFeature([], tf.string),
39 | consts.IMAGE_RAW_FIELD: tf.FixedLenFeature([], tf.string),
40 | consts.INCEPTION_OUTPUT_FIELD: tf.FixedLenFeature([2048], tf.float32)
41 | })
42 | return features
43 |
44 |
45 | def features_dataset():
46 | filenames = tf.placeholder(tf.string)
47 | ds = tf.contrib.data.TFRecordDataset(filenames, compression_type='') \
48 | .map(read_tf_record)
49 |
50 | return ds, filenames
51 |
52 |
53 | def test_features_dataset():
54 | filenames = tf.placeholder(tf.string)
55 | ds = tf.contrib.data.TFRecordDataset(filenames, compression_type='') \
56 | .map(read_test_tf_record)
57 |
58 | return ds, filenames
59 |
60 |
61 | def one_hot_label_encoder():
62 | train_Y_orig = pd.read_csv(paths.BREEDS, dtype={'breed': np.str})
63 | lb = preprocessing.LabelBinarizer()
64 | lb.fit(train_Y_orig['breed'])
65 |
66 | def encode(labels):
67 | return np.asarray(lb.transform(labels), dtype=np.float32)
68 |
69 | def decode(one_hots):
70 | return np.asarray(lb.inverse_transform(one_hots), dtype=np.str)
71 |
72 | return encode, decode
73 |
74 |
75 | if __name__ == '__main__':
76 | with tf.Graph().as_default() as g, tf.Session().as_default() as sess:
77 | ds, filenames = features_dataset()
78 | ds_iter = ds.shuffle(buffer_size=1000, seed=1).batch(10).make_initializable_iterator()
79 | next_record = ds_iter.get_next()
80 |
81 | sess.run(ds_iter.initializer, feed_dict={filenames: paths.TRAIN_TF_RECORDS})
82 | features = sess.run(next_record)
83 |
84 | _, one_hot_decoder = one_hot_label_encoder()
85 |
86 | print(one_hot_decoder(features['inception_output']))
87 | print(features['label'])
88 | print(features['inception_output'].shape)
89 |
--------------------------------------------------------------------------------
/src/data_preparation/stanford_ds_to_tfrecords.py:
--------------------------------------------------------------------------------
1 | import os
2 | import xml.etree.ElementTree
3 |
4 | import tensorflow as tf
5 |
6 | from src.common import consts
7 | import dataset
8 | from src.freezing import inception
9 | from src.common import paths
10 | from tf_record_utils import *
11 |
12 | images_root_dir = os.path.join(paths.STANFORD_DS_DIR, 'Images')
13 | annotations_root_dir = os.path.join(paths.STANFORD_DS_DIR, 'Annotation')
14 |
15 |
16 | def parse_annotation(path):
17 | xml_root = xml.etree.ElementTree.parse(path).getroot()
18 | object = xml_root.findall('object')[0]
19 | name = object.findall('name')[0].text.lower()
20 | bound_box = object.findall('bndbox')[0]
21 |
22 | return {
23 | 'breed': name,
24 | 'bndbox_xmin': bound_box.findall('xmin')[0].text,
25 | 'bndbox_ymin': bound_box.findall('ymin')[0].text,
26 | 'bndbox_xmax': bound_box.findall('xmax')[0].text,
27 | 'bndbox_ymax': bound_box.findall('ymax')[0].text
28 | }
29 |
30 |
31 | def parse_image(breed_dir, filename):
32 | path = os.path.join(images_root_dir, breed_dir, filename + '.jpg')
33 | img_raw = open(path, 'r').read()
34 |
35 | return img_raw
36 |
37 |
38 | def build_stanford_example(img_raw, inception_output, one_hot_label, annotation):
39 | example = tf.train.Example(features=tf.train.Features(feature={
40 | 'label': bytes_feature(annotation['breed'].encode()),
41 | consts.IMAGE_RAW_FIELD: bytes_feature(img_raw),
42 | consts.LABEL_ONE_HOT_FIELD: float_feature(one_hot_label),
43 | consts.INCEPTION_OUTPUT_FIELD: float_feature(inception_output)}))
44 |
45 | return example
46 |
47 |
48 | if __name__ == '__main__':
49 | one_hot_encoder, _ = dataset.one_hot_label_encoder()
50 |
51 | with tf.Graph().as_default(), \
52 | tf.Session().as_default() as sess, \
53 | tf.python_io.TFRecordWriter(paths.STANFORD_DS_TF_RECORDS,
54 | tf.python_io.TFRecordCompressionType.NONE) as writer:
55 |
56 | incept_model = inception.inception_model()
57 |
58 |
59 | def get_inception_ouput(img):
60 | inception_output = incept_model(sess, img).reshape(-1).tolist()
61 | return inception_output
62 |
63 |
64 | for breed_dir in [d for d in os.listdir(annotations_root_dir)]:
65 | print(breed_dir)
66 | for annotation_file in [f for f in os.listdir(os.path.join(annotations_root_dir, breed_dir))]:
67 | print(annotation_file)
68 | annotation = parse_annotation(os.path.join(annotations_root_dir, breed_dir, annotation_file))
69 |
70 | # print(annotation)
71 |
72 | one_hot_label = one_hot_encoder([annotation['breed']]).reshape(-1).tolist()
73 | image = parse_image(breed_dir, annotation_file)
74 |
75 | example = build_stanford_example(image, get_inception_ouput(image), one_hot_label, annotation)
76 |
77 | writer.write(example.SerializeToString())
78 |
79 | writer.flush()
80 | writer.close()
81 |
82 | print('Finished')
83 |
--------------------------------------------------------------------------------
/src/freezing/freeze.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | import tensorflow as tf
4 | from tensorflow.python.tools import freeze_graph
5 |
6 | from src.common import consts
7 | from src.models import denseNN
8 | from src.common import paths
9 |
10 |
11 | def _freeze_graph(graph_path, checkpoint_path, output_node_names, output_path):
12 | restore_op_name = 'save/restore_all'
13 | filename_tensor_name = 'save/Const:0'
14 |
15 | saved_path = freeze_graph.freeze_graph(
16 | graph_path, '', True, checkpoint_path,
17 | output_node_names, restore_op_name, filename_tensor_name,
18 | output_path, False, '', '')
19 |
20 | print('Frozen model saved to ' + output_path)
21 |
22 | return saved_path
23 |
24 |
25 | def freeze_current_model(model_name, output_node_names):
26 | lines = open(os.path.join(paths.CHECKPOINTS_DIR, model_name + '_latest')).read().split('\n')
27 | last_checkpoint = [l.split(':')[1].replace('"', '').strip() for l in lines if 'model_checkpoint_path:' in l][0]
28 |
29 | checkpoint_path = os.path.join(paths.CHECKPOINTS_DIR, last_checkpoint)
30 | graph_path = os.path.join(paths.GRAPHS_DIR, model_name + '.pb')
31 | output_graph_path = os.path.join(paths.FROZEN_MODELS_DIR, model_name + '.pb')
32 |
33 | #saver = tf.train.Saver()
34 | #checkpoint_path = saver.save(sess, checkpoint_prefix, global_step=0, latest_filename=model_name)
35 | tf.train.write_graph(g, paths.GRAPHS_DIR, os.path.basename(graph_path), as_text=False)
36 |
37 | _freeze_graph(graph_path, checkpoint_path, output_node_names=output_node_names, output_path=output_graph_path)
38 |
39 |
40 | def freeze_model(model_name, checkpoint, output_node_names):
41 | checkpoint_path = os.path.join(paths.CHECKPOINTS_DIR, checkpoint)
42 | graph_path = os.path.join(paths.GRAPHS_DIR, model_name + '.pbtext')
43 | output_graph_path = os.path.join(paths.FROZEN_MODELS_DIR, model_name + '.pb')
44 |
45 | _freeze_graph(graph_path, checkpoint_path, output_node_names=output_node_names, output_path=output_graph_path)
46 |
47 |
48 | def unfreeze_into_current_graph(model_path, tensor_names):
49 | with tf.gfile.FastGFile(name=model_path, mode='rb') as f:
50 | graph_def = tf.GraphDef()
51 | graph_def.ParseFromString(f.read())
52 | tf.import_graph_def(graph_def, name='')
53 | g = tf.get_default_graph()
54 |
55 | tensors = {t: g.get_tensor_by_name(t) for t in tensor_names}
56 |
57 | return tensors
58 |
59 |
60 | if __name__ == '__main__':
61 | with tf.Graph().as_default() as g, tf.Session().as_default() as sess:
62 | tensors = unfreeze_into_current_graph(paths.IMAGENET_GRAPH_DEF,
63 | tensor_names=[
64 | consts.INCEPTION_INPUT_TENSOR,
65 | consts.INCEPTION_OUTPUT_TENSOR])
66 |
67 | _, output_probs, y, _ = denseNN.denseNNModel(
68 | tf.reshape(tensors[consts.INCEPTION_OUTPUT_TENSOR], shape=(-1, 1), name=consts.HEAD_INPUT_NODE_NAME),
69 | consts.HEAD_MODEL_LAYERS,gamma=0.01)
70 |
71 | tf.global_variables_initializer().run()
72 |
73 | saver = tf.train.Saver()
74 | saver.restore(sess, os.path.join(paths.CHECKPOINTS_DIR, consts.CURRENT_MODEL_NAME))
75 |
76 | freeze_current_model(consts.CURRENT_MODEL_NAME, output_node_names=consts.OUTPUT_NODE_NAME)
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Dog Breeds Classification
2 |
3 | This repo is intended to contain a set of scripts and data for reproducing dog breed classification model training, analysis, and inference.
4 |
5 | 
6 |
7 | ### Prerequisites
8 |
9 | 1. Install Python 2.7
10 | 2. Install all required python dependencies: `pip install -r requirements.txt`
11 |
12 | ### Download Data
13 |
14 |
15 | 1. `cd` to this repo root directory
16 | 2. Execute setup script: `sh ./setup/setup.sh`. In its turn the script executes the following other scripts:
17 | * Creates all required directories: `sh ./create_dirs.sh`
18 | * Downloads Google Inception model: `sh ./inception_download.sh`. The link to the frozen TensorFlow model is taken from [here](https://github.com/tensorflow/models/blob/master/tutorials/image/imagenet/classify_image.py#L51)
19 | * Downloads [Stanford Dogs Dataset](http://vision.stanford.edu/aditya86/ImageNetDogs/): `sh ./download_stanford_dogs_dataset.sh`
20 |
21 | ### Prepare Data
22 |
23 | 1. Convert downloaded Stanford Dogs Dataset to TensorFlow friendly [TFRecords](https://www.tensorflow.org/programmers_guide/datasets#consuming_tfrecord_data) file: `python -m src.data_preparation.stanford_ds_to_tfrecords`
24 |
25 | ### Train
26 |
27 | This section describes how to build dog breed classification dense neural network model on top of the pre-trained by Google deep neural network (namely Inception model).
28 |
29 | 1. Give a name to the model your are going to train by assigning a name to `CURRENT_MODEL_NAME` variable in [consts.py](src/common/consts.py#L14) script
30 | 2. Configure number of layers and number of units in each layer by setting `HEAD_MODEL_LAYERS` variable in [consts.py](src/common/consts.py#L18)
31 | 3. Train the model: `python -m src.training.train`. It might take 25-35 minutes depending on the depth of your model and number of epochs (which could be configured in the train.py script itself). TensorBoard could be used to observe the training process: `tensorboard --logdir=./summary`
32 |
33 | ### Freeze Model
34 |
35 | 1. Freeze the model: `python -m src.freezing.freeze`. This will bind Inception model with the trained on the previous step "head" model and serialize it as a TensorFlow graph with variables represented as constants. This frozen model will be ready to use for classification tasks.
36 |
37 | ### Analyze
38 |
39 | 1. Produce CSV file with predicted vs actual breed. This could be used to analyze precision on the training data e.g. plot a confusion matrix (see [Confusion.ipynb](Confusion.ipynb)). Result CSV file goes to `metrics/training_confusion.csv`: `python -m src.analysis.training_perf_analysis`
40 |
41 | ### Infer
42 |
43 | 1. Use the model frozen on the previous step to classify an image either available on the filesystem or downloadable as an HTTP resource:
44 |
45 | `python -m src.inference.classify uri https://raw.githubusercontent.com/stormy-ua/dog-breeds-classification/master/images/shih-tzu.jpg`
46 |
47 | `python -m src.inference.classify file images/airedale.jpg`
48 |
49 | In my case the model was training for 25 mins (5000 epochs) and the following sample classification outputs were produced:
50 |
51 | 
52 |
53 | (Image is taken from [http://dogtime.com/dog-breeds/airedale-terrier](http://dogtime.com/dog-breeds/airedale-terrier))
54 |
55 | | breed | probability |
56 | | ------ | ------ |
57 | | airedale | 0.992064 |
58 | | otterhound | 0.005108 |
59 | | chesapeake_bay_retriever | 0.001259 |
60 | | irish_terrier | 0.000635 |
61 | | wire-haired_fox_terrier | 0.000378 |
62 |
63 | 
64 |
65 | (Image is taken from [http://dogtime.com/dog-breeds/shih-tzu](https://dogtime.com/dog-breeds/shih-tzu#/slide/1))
66 |
67 | | breed | probability |
68 | | ------ | ------ |
69 | | shih-tzu | 0.752834 |
70 | | lhasa | 0.234748 |
71 | | tibetan_terrier | 0.007598 |
72 | | maltese_dog | 0.000969 |
73 | |japanese_spaniel | 0.000936 |
74 |
75 |
76 | These examples also available in the [Inference.ipynb](Inference.ipynb) Python notebook.
77 |
78 | Have a fun!
79 |
80 | ### Running in Docker
81 |
82 | The already pre-built model w/ all the scripts and Python notebooks for inference are available in the docker container. Run the container:
83 |
84 | `docker run -p 8888:8888 -p 6006:6006 kirillpanarin/dog_breed_classification`
85 |
86 | Navigate a browser to `http://localhost:8888/notebooks/Inference.ipynb` and you will be all set for doing inference against real-life dog images.
87 |
88 | ### Kagle Dog Breed Classification Competition
89 |
90 | This model ranked #3 in the [Kaggle's Dog Breed Classification Challenge](https://www.kaggle.com/c/dog-breed-identification).
91 |
92 | 
93 |
--------------------------------------------------------------------------------
/src/training/train.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | import pyprind
4 | import tensorflow as tf
5 |
6 | from src.common import consts
7 | from src.data_preparation import dataset
8 | from src.models import denseNN
9 | from src.common import paths
10 |
11 |
12 | def train_dev_split(sess, tf_records_path, dev_set_size=2000, batch_size=64, train_sample_size=2000):
13 | ds_, filename = dataset.features_dataset()
14 |
15 | ds = ds_.shuffle(buffer_size=20000)
16 |
17 | train_ds = ds.skip(dev_set_size).repeat()
18 | train_ds_iter = train_ds.shuffle(buffer_size=20000) \
19 | .batch(batch_size) \
20 | .make_initializable_iterator()
21 |
22 | train_sample_ds = ds.skip(dev_set_size)
23 | train_sample_ds_iter = train_sample_ds.shuffle(buffer_size=20000) \
24 | .take(train_sample_size) \
25 | .batch(train_sample_size) \
26 | .make_initializable_iterator()
27 |
28 | dev_ds_iter = ds.take(dev_set_size).batch(dev_set_size).make_initializable_iterator()
29 |
30 | sess.run(train_ds_iter.initializer, feed_dict={filename: tf_records_path})
31 | sess.run(dev_ds_iter.initializer, feed_dict={filename: tf_records_path})
32 | sess.run(train_sample_ds_iter.initializer, feed_dict={filename: tf_records_path})
33 |
34 | return train_ds_iter.get_next(), dev_ds_iter.get_next(), train_sample_ds_iter.get_next()
35 |
36 |
37 | def error(x, output_probs, name):
38 | expected = tf.placeholder(tf.float32, shape=(consts.CLASSES_COUNT, None), name='expected')
39 | exp_vs_output = tf.equal(tf.argmax(output_probs, axis=0), tf.argmax(expected, axis=0))
40 | accuracy = 1. - tf.reduce_mean(tf.cast(exp_vs_output, dtype=tf.float32))
41 | summaries = [tf.summary.scalar(name, accuracy)]
42 |
43 | merged_summaries = tf.summary.merge(summaries)
44 |
45 | def run(sess, output, expected_):
46 | acc, summary_acc = sess.run([accuracy, merged_summaries],
47 | feed_dict={x: output, expected: expected_})
48 |
49 | return acc, summary_acc
50 |
51 | return run
52 |
53 |
54 | def make_model_name(prefix, batch_size, learning_rate):
55 | return '%s_%d_%s' % (prefix, batch_size, str(learning_rate).replace('0.', ''))
56 |
57 |
58 | if __name__ == '__main__':
59 | BATCH_SIZE = 64
60 | EPOCHS_COUNT = 5000
61 | LEARNING_RATE = 0.0001
62 |
63 | model_name = consts.CURRENT_MODEL_NAME
64 |
65 | with tf.Graph().as_default() as g, tf.Session().as_default() as sess:
66 | next_train_batch, get_dev_ds, get_train_sample_ds = \
67 | train_dev_split(sess, paths.TRAIN_TF_RECORDS,
68 | dev_set_size=consts.DEV_SET_SIZE,
69 | batch_size=BATCH_SIZE,
70 | train_sample_size=consts.TRAIN_SAMPLE_SIZE)
71 |
72 | dev_set = sess.run(get_dev_ds)
73 | dev_set_inception_output = dev_set[consts.INCEPTION_OUTPUT_FIELD]
74 | dev_set_y_one_hot = dev_set[consts.LABEL_ONE_HOT_FIELD]
75 |
76 | train_sample = sess.run(get_train_sample_ds)
77 | train_sample_inception_output = train_sample[consts.INCEPTION_OUTPUT_FIELD]
78 | train_sample_y_one_hot = train_sample[consts.LABEL_ONE_HOT_FIELD]
79 |
80 | x = tf.placeholder(dtype=tf.float32, shape=(consts.INCEPTION_CLASSES_COUNT, None), name="x")
81 | cost, output_probs, y, nn_summaries = denseNN.denseNNModel(
82 | x, consts.HEAD_MODEL_LAYERS, gamma=0.001)
83 | optimizer = tf.train.AdamOptimizer(learning_rate=LEARNING_RATE).minimize(cost)
84 |
85 | dev_error_eval = error(x, output_probs, name='test_error')
86 | train_error_eval = error(x, output_probs, name='train_error')
87 |
88 | nn_merged_summaries = tf.summary.merge(nn_summaries)
89 | tf.global_variables_initializer().run()
90 |
91 | writer = tf.summary.FileWriter(os.path.join(paths.SUMMARY_DIR, model_name))
92 |
93 | bar = pyprind.ProgBar(EPOCHS_COUNT, update_interval=1, width=60)
94 |
95 | saver = tf.train.Saver()
96 |
97 | for epoch in range(0, EPOCHS_COUNT):
98 | batch_features = sess.run(next_train_batch)
99 | batch_inception_output = batch_features[consts.INCEPTION_OUTPUT_FIELD]
100 | batch_y = batch_features[consts.LABEL_ONE_HOT_FIELD]
101 |
102 | _, summary = sess.run([optimizer, nn_merged_summaries], feed_dict={
103 | x: batch_inception_output.T,
104 | y: batch_y.T
105 | })
106 |
107 | writer.add_summary(summary, epoch)
108 |
109 | _, dev_summaries = dev_error_eval(sess, dev_set_inception_output.T, dev_set_y_one_hot.T)
110 | writer.add_summary(dev_summaries, epoch)
111 |
112 | _, train_sample_summaries = train_error_eval(sess, train_sample_inception_output.T, train_sample_y_one_hot.T)
113 | writer.add_summary(train_sample_summaries, epoch)
114 |
115 | writer.flush()
116 |
117 | if epoch % 10 == 0 or epoch == EPOCHS_COUNT:
118 | saver.save(sess, os.path.join(paths.CHECKPOINTS_DIR, model_name), latest_filename=model_name + '_latest')
119 |
120 | bar.update()
121 |
--------------------------------------------------------------------------------
/src/data_preparation/kaggle_images_to_tfrecords.py:
--------------------------------------------------------------------------------
1 | import pyprind
2 | import tensorflow as tf
3 |
4 | from src.common import consts
5 | import dataset
6 | import image_utils
7 | from src.freezing import inception
8 | from src.common import paths
9 | from tf_record_utils import *
10 |
11 | def read_example(id, breed):
12 | image_str = tf.read_file(tf.string_join([paths.TRAIN_DIR, '/', id, paths.JPEG_EXT], separator=''))
13 | return id, image_str, breed
14 |
15 |
16 | def read_test_example(file_id):
17 | image_str = tf.read_file(tf.string_join([paths.TEST_DIR, '/', file_id], separator=''))
18 | parts = tf.string_split(tf.expand_dims(file_id, 0), '.').values
19 | return image_str, parts[0]
20 |
21 |
22 | def parse_row(line):
23 | vals = tf.string_split(tf.expand_dims(line, 0), ',').values
24 | return vals[0], vals[1]
25 |
26 |
27 | def build_train_example(img, one_hot_label, breed_label, inception_output):
28 | example = tf.train.Example(features=tf.train.Features(feature={
29 | 'label': bytes_feature(breed_label.encode()),
30 | consts.IMAGE_RAW_FIELD: bytes_feature(img),
31 | consts.LABEL_ONE_HOT_FIELD: float_feature(one_hot_label),
32 | consts.INCEPTION_OUTPUT_FIELD: float_feature(inception_output)}))
33 |
34 | return example
35 |
36 |
37 | def image_augmenter():
38 | img = tf.placeholder(tf.string)
39 |
40 | img_decoded = tf.image.decode_jpeg(img)
41 |
42 | # img1_tf = tf.image.encode_jpeg(image_utils.rotate_ccw(img_decoded, 1))
43 | # img2_tf = tf.image.encode_jpeg(image_utils.rotate_ccw(img_decoded, 3))
44 | img1_tf = tf.image.encode_jpeg(image_utils.adjust_contrast(img_decoded))
45 | img2_tf = tf.image.encode_jpeg(image_utils.adjust_brightness(img_decoded, -0.15))
46 | img3_tf = tf.image.encode_jpeg(image_utils.flip_along_width(img_decoded))
47 |
48 | # examples.append(build_train_example(
49 | # tf.image.encode_jpeg(image_utils.adjust_brightness(img_decoded, 0.1)).eval(),
50 | # one_hot_label, breed_label, inception_output))
51 |
52 | # examples.append(build_train_example(
53 | # tf.image.encode_jpeg(image_utils.adjust_brightness(img_decoded, -0.1)).eval(),
54 | # one_hot_label, breed_label, inception_output))
55 |
56 | # examples.append(build_train_example(
57 | # tf.image.encode_jpeg(image_utils.adjust_contrast(img_decoded)).eval(),
58 | # one_hot_label, breed_label, inception_output))
59 |
60 | sess = tf.get_default_session()
61 |
62 | def augment(image):
63 | img1, img2, img3 = sess.run([img1_tf, img2_tf, img3_tf], feed_dict={img: image})
64 |
65 | return [img1, img2, img3]
66 |
67 | return augment
68 |
69 |
70 | def convert_train(tfrecords_path):
71 | one_hot_encoder, _ = dataset.one_hot_label_encoder()
72 |
73 | inception_graph = tf.Graph()
74 | inception_sess = tf.Session(graph=inception_graph)
75 |
76 | with inception_graph.as_default(), inception_sess.as_default():
77 | incept_model = inception.inception_model()
78 |
79 | with tf.Graph().as_default(), tf.Session().as_default() as sess:
80 |
81 | labels_path = tf.placeholder(dtype=tf.string)
82 |
83 | images_ds = tf.contrib.data.TextLineDataset(labels_path) \
84 | .skip(1) \
85 | .map(parse_row) \
86 | .map(read_example)
87 |
88 | labels_iter = images_ds.make_initializable_iterator()
89 | next_label = labels_iter.get_next()
90 |
91 | sess.run(labels_iter.initializer, feed_dict={labels_path: paths.LABELS})
92 |
93 | print('Writing ', tfrecords_path)
94 |
95 | bar = pyprind.ProgBar(13000, update_interval=1, width=60)
96 |
97 | augmenter = image_augmenter()
98 |
99 | with tf.python_io.TFRecordWriter(tfrecords_path, tf.python_io.TFRecordCompressionType.NONE) as writer:
100 | try:
101 | while True:
102 | id, img, breed_label = sess.run(next_label)
103 | one_hot_label = one_hot_encoder([breed_label]).reshape(-1).tolist()
104 |
105 | def get_inception_ouput(img):
106 | with inception_graph.as_default():
107 | inception_output = incept_model(inception_sess, img).reshape(-1).tolist()
108 | return inception_output
109 | # print(inception_output.shape)
110 |
111 | # print('writing %s - %s' % (len(img), breed_label))
112 |
113 | images = [img]
114 | images.extend(augmenter(img))
115 |
116 | for image in images:
117 | example = build_train_example(image, one_hot_label, breed_label, get_inception_ouput(image))
118 | writer.write(example.SerializeToString())
119 |
120 | bar.update()
121 |
122 | except tf.errors.OutOfRangeError:
123 | print('End of the dataset')
124 |
125 | writer.flush()
126 | writer.close()
127 |
128 | print('Finished')
129 |
130 |
131 | def convert_test(tfrecords_path):
132 | inception_graph = tf.Graph()
133 | inception_sess = tf.Session(graph=inception_graph)
134 |
135 | with inception_graph.as_default(), inception_sess.as_default():
136 | incept_model = inception.inception_model()
137 |
138 | with tf.Graph().as_default() as g, tf.Session().as_default() as sess:
139 |
140 | labels_path = tf.placeholder(dtype=tf.string)
141 |
142 | images_ds = tf.contrib.data.Dataset.from_tensor_slices(tf.constant(tf.gfile.ListDirectory(paths.TEST_DIR))) \
143 | .map(read_test_example)
144 |
145 | labels_iter = images_ds.make_initializable_iterator()
146 | next_label = labels_iter.get_next()
147 |
148 | sess.run(labels_iter.initializer, feed_dict={labels_path: paths.LABELS})
149 |
150 | print('Writing ', tfrecords_path)
151 |
152 | with tf.python_io.TFRecordWriter(tfrecords_path, tf.python_io.TFRecordCompressionType.NONE) as writer:
153 | try:
154 | while True:
155 | img, id = sess.run(next_label)
156 |
157 | with inception_graph.as_default():
158 | inception_output = incept_model(inception_sess, img).reshape(-1).tolist()
159 | # print(inception_output.shape)
160 |
161 | print('writing %s - %s' % (len(img), id))
162 | example = tf.train.Example(features=tf.train.Features(feature={
163 | 'id': bytes_feature(id.encode()),
164 | consts.IMAGE_RAW_FIELD: bytes_feature(img),
165 | consts.INCEPTION_OUTPUT_FIELD: float_feature(inception_output)}))
166 |
167 | writer.write(example.SerializeToString())
168 | except tf.errors.OutOfRangeError:
169 | print('End of the dataset')
170 |
171 | writer.flush()
172 |
173 | print('Finished')
174 |
175 |
176 | #if __name__ == '__main__':
177 | #convert_train(paths.TRAIN_TF_RECORDS)
178 | #convert_test(paths.TEST_TF_RECORDS)
179 |
--------------------------------------------------------------------------------