Repository: dongyp13/Translation-Invariant-Attacks
Branch: master
Commit: c3ae1ba061ff
Files: 40
Total size: 641.2 KB
Directory structure:
gitextract_blf6ykcn/
├── LICENSE
├── README.md
├── attack_iter.py
├── attack_vgg16_mim.py
├── dataset/
│ ├── README.md
│ ├── dev_dataset.csv
│ └── download_images.py
├── metadata.json
├── nets/
│ ├── __init__.py
│ ├── alexnet.py
│ ├── alexnet_test.py
│ ├── cifarnet.py
│ ├── inception.py
│ ├── inception_resnet_v2.py
│ ├── inception_resnet_v2_test.py
│ ├── inception_utils.py
│ ├── inception_v1.py
│ ├── inception_v1_test.py
│ ├── inception_v2.py
│ ├── inception_v2_test.py
│ ├── inception_v3.py
│ ├── inception_v3_test.py
│ ├── inception_v4.py
│ ├── inception_v4_test.py
│ ├── lenet.py
│ ├── mobilenet_v1.md
│ ├── mobilenet_v1.py
│ ├── mobilenet_v1_test.py
│ ├── nets_factory.py
│ ├── nets_factory_test.py
│ ├── overfeat.py
│ ├── overfeat_test.py
│ ├── resnet_utils.py
│ ├── resnet_v1.py
│ ├── resnet_v1_test.py
│ ├── resnet_v2.py
│ ├── resnet_v2_test.py
│ ├── vgg.py
│ └── vgg_test.py
└── run_attack.sh
================================================
FILE CONTENTS
================================================
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2017 Yinpeng Dong
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: README.md
================================================
# Translation-Invariant Attacks
## Introduction
This repository contains the code for [Evading Defenses to Transferable Adversarial Examples by Translation-Invariant Attacks](https://arxiv.org/pdf/1904.02884.pdf) (CVPR 2019 Oral).
## Method
We proposed a translation-invariant (TI) attack method to generate more transferable adversarial examples. This method is implemented by convolving the gradient with a pre-defined kernel in each attack iteration, and can be integrated into any gradient-based attack method.
## Run the code
First download the [models](#Models). You can also use other models by changing the model definition part in the code.
Then run the following command
```
bash run_attack.sh input_dir output_dir 16
```
where original images are stored in ``input_dir`` with ``.png`` format, and the generated adversarial images are saved in ``output_dir``.
We used the Python 2.7 and Tensorflow 1.12 versions.
## Results
We consider eight SOTA defense models on ImageNet:
* Inc-v3ens3, Inc-v3ens4, IncRes-v2ens trained by [Ensemble Adversarial Training](https://arxiv.org/abs/1705.07204);
* [High-level representation guided denoiser](https://arxiv.org/abs/1712.02976) (HGD, top-1 submission in the NIPS 2017 defense competition);
* [Input transformation through random resizing and padding](https://arxiv.org/abs/1711.01991) (R&P, rank-2 submission in the NIPS 2017 defense competition);
* [Input transformation through JPEG compression or total variance minimization (TVM)](https://openreview.net/pdf?id=SyJ7ClWCb);
* [Rank-3 submission in the NIPS 2017 defense competition (NIPS-r3)](https://github.com/anlthms/nips-2017/tree/master/mmd);
We attacked these models by the [fast gradient sign method](https://arxiv.org/abs/1412.6572) (FGSM), [momentum iterative fast gradient sign method](https://arxiv.org/abs/1710.06081) (MI-FGSM), [diverse input method](https://arxiv.org/abs/1803.06978) (DIM), and their translation-invariant versions as TI-FGSM, TI-MI-FGSM, and TI-DIM. We generated adversarial examples for the ensemble of Inception V3, Inception V4, Inception ResNet V2, and ResNet V2 152 with epsilon 16. The success rates against the eight defenses are:
### Citation
If you use our method for attacks in your research, please consider citing
@inproceedings{dong2019evading,
title={Evading Defenses to Transferable Adversarial Examples by Translation-Invariant Attacks},
author={Dong, Yinpeng and Pang, Tianyu and Su, Hang and Zhu, Jun},
booktitle={Proceedings of the IEEE Computer Society Conference on Computer Vision and Pattern Recognition},
year={2019}
}
## Implementation
### Models
The models can be downloaded at [Inception V3](http://ml.cs.tsinghua.edu.cn/~yinpeng/downloads/inception_v3.ckpt), [Inception V4](http://ml.cs.tsinghua.edu.cn/~yinpeng/downloads/inception_v4.ckpt), [Inception ResNet V2](http://ml.cs.tsinghua.edu.cn/~yinpeng/downloads/inception_resnet_v2_2016_08_30.ckpt), and [ResNet V2 152](http://ml.cs.tsinghua.edu.cn/~yinpeng/downloads/resnet_v2_152.ckpt).
If you want to attack other models, you can replace the model definition part to your own models.
### Hyper-parameters
* For TI-FGSM, set ``num_iter=1``, ``momentum=0.0``, ``prob=0.0``;
* For TI-MI-FGSM, set ``num_iter=10``, ``momentum=1.0``, ``prob=0.0``;
* For TI-DIM, set ``num_iter=10``, ``momentum=1.0``, ``prob=0.7``;
================================================
FILE: attack_iter.py
================================================
"""Implementation of sample attack."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import os
import time
start_time = time.time()
import numpy as np
from scipy.misc import imread
from scipy.misc import imsave
from scipy.misc import imresize
import tensorflow as tf
from nets import inception_v3, inception_v4, inception_resnet_v2, resnet_v2
slim = tf.contrib.slim
tf.flags.DEFINE_string('master', '', 'The address of the TensorFlow master to use.')
tf.flags.DEFINE_string('checkpoint_path_inception_v3', '', 'Path to checkpoint for inception network.')
tf.flags.DEFINE_string('checkpoint_path_inception_v4', '', 'Path to checkpoint for inception network.')
tf.flags.DEFINE_string('checkpoint_path_inception_resnet_v2', '', 'Path to checkpoint for inception network.')
tf.flags.DEFINE_string('checkpoint_path_resnet', '', 'Path to checkpoint for inception network.')
tf.flags.DEFINE_string('input_dir', '', 'Input directory with images.')
tf.flags.DEFINE_string('output_dir', '', 'Output directory with images.')
tf.flags.DEFINE_float('max_epsilon', 32.0, 'Maximum size of adversarial perturbation.')
tf.flags.DEFINE_integer('num_iter', 10, 'Number of iterations.')
tf.flags.DEFINE_integer('image_width', 299, 'Width of each input images.')
tf.flags.DEFINE_integer('image_height', 299, 'Height of each input images.')
tf.flags.DEFINE_integer('image_resize', 330, 'Height of each input images.')
tf.flags.DEFINE_integer('batch_size', 10, 'How many images process at one time.')
tf.flags.DEFINE_float('momentum', 1.0, 'Momentum.')
tf.flags.DEFINE_float('prob', 0.4, 'probability of using diverse inputs.')
FLAGS = tf.flags.FLAGS
def gkern(kernlen=21, nsig=3):
"""Returns a 2D Gaussian kernel array."""
import scipy.stats as st
x = np.linspace(-nsig, nsig, kernlen)
kern1d = st.norm.pdf(x)
kernel_raw = np.outer(kern1d, kern1d)
kernel = kernel_raw / kernel_raw.sum()
return kernel
kernel = gkern(15, 3).astype(np.float32)
stack_kernel = np.stack([kernel, kernel, kernel]).swapaxes(2, 0)
stack_kernel = np.expand_dims(stack_kernel, 3)
def load_images(input_dir, batch_shape):
"""Read png images from input directory in batches.
Args:
input_dir: input directory
batch_shape: shape of minibatch array, i.e. [batch_size, height, width, 3]
Yields:
filenames: list file names without path of each image
Lenght of this list could be less than batch_size, in this case only
first few images of the result are elements of the minibatch.
images: array with all images from this batch
"""
images = np.zeros(batch_shape)
filenames = []
idx = 0
batch_size = batch_shape[0]
for filepath in tf.gfile.Glob(os.path.join(input_dir, '*.png')):
with tf.gfile.Open(filepath) as f:
image = imresize(imread(f, mode='RGB'), [FLAGS.image_height, FLAGS.image_width]).astype(np.float) / 255.0
# Images for inception classifier are normalized to be in [-1, 1] interval.
images[idx, :, :, :] = image * 2.0 - 1.0
filenames.append(os.path.basename(filepath))
idx += 1
if idx == batch_size:
yield filenames, images
filenames = []
images = np.zeros(batch_shape)
idx = 0
if idx > 0:
yield filenames, images
def save_images(images, filenames, output_dir):
"""Saves images to the output directory.
Args:
images: array with minibatch of images
filenames: list of filenames without path
If number of file names in this list less than number of images in
the minibatch then only first len(filenames) images will be saved.
output_dir: directory where to save images
"""
for i, filename in enumerate(filenames):
# Images for inception classifier are normalized to be in [-1, 1] interval,
# so rescale them back to [0, 1].
with tf.gfile.Open(os.path.join(output_dir, filename), 'w') as f:
imsave(f, (images[i, :, :, :] + 1.0) * 0.5, format='png')
def graph(x, y, i, x_max, x_min, grad):
eps = 2.0 * FLAGS.max_epsilon / 255.0
num_iter = FLAGS.num_iter
alpha = eps / num_iter
momentum = FLAGS.momentum
num_classes = 1001
# should keep original x here for output
with slim.arg_scope(inception_v3.inception_v3_arg_scope()):
logits_v3, end_points_v3 = inception_v3.inception_v3(
input_diversity(x), num_classes=num_classes, is_training=False)
with slim.arg_scope(inception_v4.inception_v4_arg_scope()):
logits_v4, end_points_v4 = inception_v4.inception_v4(
input_diversity(x), num_classes=num_classes, is_training=False)
with slim.arg_scope(inception_resnet_v2.inception_resnet_v2_arg_scope()):
logits_res_v2, end_points_res_v2 = inception_resnet_v2.inception_resnet_v2(
input_diversity(x), num_classes=num_classes, is_training=False, reuse=True)
with slim.arg_scope(resnet_v2.resnet_arg_scope()):
logits_resnet, end_points_resnet = resnet_v2.resnet_v2_152(
input_diversity(x), num_classes=num_classes, is_training=False)
logits = (logits_v3 + logits_v4 + logits_res_v2 + logits_resnet) / 4
auxlogits = (end_points_v3['AuxLogits'] + end_points_v4['AuxLogits'] + end_points_res_v2['AuxLogits']) / 3
cross_entropy = tf.losses.softmax_cross_entropy(y,
logits,
label_smoothing=0.0,
weights=1.0)
cross_entropy += tf.losses.softmax_cross_entropy(y,
auxlogits,
label_smoothing=0.0,
weights=0.4)
noise = tf.gradients(cross_entropy, x)[0]
noise = tf.nn.depthwise_conv2d(noise, stack_kernel, strides=[1, 1, 1, 1], padding='SAME')
noise = noise / tf.reduce_mean(tf.abs(noise), [1, 2, 3], keep_dims=True)
noise = momentum * grad + noise
x = x + alpha * tf.sign(noise)
x = tf.clip_by_value(x, x_min, x_max)
i = tf.add(i, 1)
return x, y, i, x_max, x_min, noise
def stop(x, y, i, x_max, x_min, grad):
num_iter = FLAGS.num_iter
return tf.less(i, num_iter)
def input_diversity(input_tensor):
rnd = tf.random_uniform((), FLAGS.image_width, FLAGS.image_resize, dtype=tf.int32)
rescaled = tf.image.resize_images(input_tensor, [rnd, rnd], method=tf.image.ResizeMethod.NEAREST_NEIGHBOR)
h_rem = FLAGS.image_resize - rnd
w_rem = FLAGS.image_resize - rnd
pad_top = tf.random_uniform((), 0, h_rem, dtype=tf.int32)
pad_bottom = h_rem - pad_top
pad_left = tf.random_uniform((), 0, w_rem, dtype=tf.int32)
pad_right = w_rem - pad_left
padded = tf.pad(rescaled, [[0, 0], [pad_top, pad_bottom], [pad_left, pad_right], [0, 0]], constant_values=0.)
padded.set_shape((input_tensor.shape[0], FLAGS.image_resize, FLAGS.image_resize, 3))
return tf.cond(tf.random_uniform(shape=[1])[0] < tf.constant(FLAGS.prob), lambda: padded, lambda: input_tensor)
def main(_):
# Images for inception classifier are normalized to be in [-1, 1] interval,
# eps is a difference between pixels so it should be in [0, 2] interval.
# Renormalizing epsilon from [0, 255] to [0, 2].
eps = 2.0 * FLAGS.max_epsilon / 255.0
num_classes = 1001
batch_shape = [FLAGS.batch_size, FLAGS.image_height, FLAGS.image_width, 3]
tf.logging.set_verbosity(tf.logging.INFO)
print(time.time() - start_time)
with tf.Graph().as_default():
# Prepare graph
x_input = tf.placeholder(tf.float32, shape=batch_shape)
x_max = tf.clip_by_value(x_input + eps, -1.0, 1.0)
x_min = tf.clip_by_value(x_input - eps, -1.0, 1.0)
with slim.arg_scope(inception_resnet_v2.inception_resnet_v2_arg_scope()):
_, end_points = inception_resnet_v2.inception_resnet_v2(
x_input, num_classes=num_classes, is_training=False)
predicted_labels = tf.argmax(end_points['Predictions'], 1)
y = tf.one_hot(predicted_labels, num_classes)
i = tf.constant(0)
grad = tf.zeros(shape=batch_shape)
x_adv, _, _, _, _, _ = tf.while_loop(stop, graph, [x_input, y, i, x_max, x_min, grad])
# Run computation
s1 = tf.train.Saver(slim.get_model_variables(scope='InceptionV3'))
s5 = tf.train.Saver(slim.get_model_variables(scope='InceptionV4'))
s6 = tf.train.Saver(slim.get_model_variables(scope='InceptionResnetV2'))
s8 = tf.train.Saver(slim.get_model_variables(scope='resnet_v2'))
with tf.Session() as sess:
s1.restore(sess, FLAGS.checkpoint_path_inception_v3)
s5.restore(sess, FLAGS.checkpoint_path_inception_v4)
s6.restore(sess, FLAGS.checkpoint_path_inception_resnet_v2)
s8.restore(sess, FLAGS.checkpoint_path_resnet)
print(time.time() - start_time)
for filenames, images in load_images(FLAGS.input_dir, batch_shape):
adv_images = sess.run(x_adv, feed_dict={x_input: images})
save_images(adv_images, filenames, FLAGS.output_dir)
print(time.time() - start_time)
if __name__ == '__main__':
tf.app.run()
================================================
FILE: attack_vgg16_mim.py
================================================
"""Implementation of sample attack."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import os
import time
import numpy as np
from scipy.misc import imread
from scipy.misc import imsave, imresize
import tensorflow as tf
from nets import vgg
slim = tf.contrib.slim
_R_MEAN = 123.68
_G_MEAN = 116.78
_B_MEAN = 103.94
tf.flags.DEFINE_string(
'master', '', 'The address of the TensorFlow master to use.')
tf.flags.DEFINE_string(
'checkpoint_path_vgg', '', 'Path to checkpoint for inception network.')
tf.flags.DEFINE_string(
'input_dir', '', 'Input directory with images.')
tf.flags.DEFINE_string(
'output_dir', '', 'Output directory with images.')
tf.flags.DEFINE_float(
'max_epsilon', 16.0, 'Maximum size of adversarial perturbation.')
tf.flags.DEFINE_integer(
'num_iter', 10, 'Number of iterations.')
tf.flags.DEFINE_integer(
'image_width', 224, 'Width of each input images.')
tf.flags.DEFINE_integer(
'image_height', 224, 'Height of each input images.')
tf.flags.DEFINE_integer(
'batch_size', 16, 'How many images process at one time.')
tf.flags.DEFINE_float(
'momentum', 0.0, 'Momentum.')
FLAGS = tf.flags.FLAGS
def gkern(kernlen=21, nsig=3):
"""Returns a 2D Gaussian kernel array."""
import scipy.stats as st
x = np.linspace(-nsig, nsig, kernlen)
kern1d = st.norm.pdf(x)
kernel_raw = np.outer(kern1d, kern1d)
kernel = kernel_raw / kernel_raw.sum()
return kernel
kernel = gkern(15, 3).astype(np.float32)
stack_kernel = np.stack([kernel, kernel, kernel]).swapaxes(2, 0)
stack_kernel = np.expand_dims(stack_kernel, 3)
def load_images(input_dir, batch_shape):
"""Read png images from input directory in batches.
Args:
input_dir: input directory
batch_shape: shape of minibatch array, i.e. [batch_size, height, width, 3]
Yields:
filenames: list file names without path of each image
Lenght of this list could be less than batch_size, in this case only
first few images of the result are elements of the minibatch.
images: array with all images from this batch
"""
images = np.zeros(batch_shape)
filenames = []
idx = 0
batch_size = batch_shape[0]
for filepath in tf.gfile.Glob(os.path.join(input_dir, '*.png')):
with tf.gfile.Open(filepath) as f:
image = imread(f, mode='RGB')
image = imresize(image, [FLAGS.image_height, FLAGS.image_width]).astype(np.float)
image[:,:,0] -= _R_MEAN
image[:,:,1] -= _G_MEAN
image[:,:,2] -= _B_MEAN
images[idx, :, :, :] = image
filenames.append(os.path.basename(filepath))
idx += 1
if idx == batch_size:
yield filenames, images
filenames = []
images = np.zeros(batch_shape)
idx = 0
if idx > 0:
yield filenames, images
def save_images(images, filenames, output_dir):
"""Saves images to the output directory.
Args:
images: array with minibatch of images
filenames: list of filenames without path
If number of file names in this list less than number of images in
the minibatch then only first len(filenames) images will be saved.
output_dir: directory where to save images
"""
for i, filename in enumerate(filenames):
# Images for inception classifier are normalized to be in [-1, 1] interval,
# so rescale them back to [0, 1].
with tf.gfile.Open(os.path.join(output_dir, filename), 'w') as f:
image = images[i, :, :, :]
image[:,:,0] += _R_MEAN
image[:,:,1] += _G_MEAN
image[:,:,2] += _B_MEAN
image = imresize(image, [299, 299])
imsave(f, image, format='png')
def graph(x, y, i, x_max, x_min, grad):
eps = FLAGS.max_epsilon
num_iter = FLAGS.num_iter
alpha = eps / num_iter
momentum = FLAGS.momentum
num_classes = 1000
with slim.arg_scope(vgg.vgg_arg_scope()):
logits, end_points = vgg.vgg_16(
x, num_classes=num_classes, is_training=False)
pred = tf.argmax(logits, 1)
first_round = tf.cast(tf.equal(i, 0), tf.int64)
y = first_round * pred + (1 - first_round) * y
one_hot = tf.one_hot(y, num_classes)
cross_entropy = tf.losses.softmax_cross_entropy(one_hot,
logits,
label_smoothing=0.0,
weights=1.0)
noise = tf.gradients(cross_entropy, x)[0]
noise = tf.nn.depthwise_conv2d(noise, stack_kernel, strides=[1, 1, 1, 1], padding='SAME')
noise = noise / tf.reduce_mean(tf.abs(noise), [1,2,3], keep_dims=True)
noise = momentum * grad + noise
x = x + alpha * tf.sign(noise)
x = tf.clip_by_value(x, x_min, x_max)
i = tf.add(i, 1)
return x, y, i, x_max, x_min, noise
def stop(x, y, i, x_max, x_min, grad):
num_iter = FLAGS.num_iter
return tf.less(i, num_iter)
def main(_):
# Images for inception classifier are normalized to be in [-1, 1] interval,
# eps is a difference between pixels so it should be in [0, 2] interval.
# Renormalizing epsilon from [0, 255] to [0, 2].
start_time = time.time()
eps = FLAGS.max_epsilon
batch_shape = [FLAGS.batch_size, FLAGS.image_height, FLAGS.image_width, 3]
tf.logging.set_verbosity(tf.logging.INFO)
with tf.Graph().as_default():
# Prepare graph
x_input = tf.placeholder(tf.float32, shape=batch_shape)
x_max = x_input + eps
x_min = x_input - eps
y = tf.constant(np.zeros([FLAGS.batch_size]), tf.int64)
i = tf.constant(0)
grad = tf.zeros(shape=batch_shape)
x_adv, _, _, _, _, _ = tf.while_loop(stop, graph, [x_input, y, i, x_max, x_min, grad])
# Run computation
s1 = tf.train.Saver(slim.get_model_variables())
print('Building Graph Done', time.time() - start_time)
with tf.Session() as sess:
s1.restore(sess, FLAGS.checkpoint_path_vgg)
print('Load Parameters Done', time.time() - start_time)
tot_images = 0
for filenames, images in load_images(FLAGS.input_dir, batch_shape):
adv_images = sess.run(x_adv, feed_dict={x_input: images})
save_images(adv_images, filenames, FLAGS.output_dir)
tot_images += len(filenames)
print(tot_images, time.time() - start_time)
print(time.time() - start_time)
if __name__ == '__main__':
tf.app.run()
================================================
FILE: dataset/README.md
================================================
# Dataset for adversarial competition.
Two datasets will be used for the competition:
* **DEV** dataset which is available here for development and experimenting.
* **TEST** dataset which will be kept secret until after the competition
and will be used for final scoring.
Both datasets are composed from publicly available images which were posted
online under CC-BY license.
## Dataset format
DEV dataset is defined by `dev_dataset.csv`
which contains URLs of the images along with bounding boxes
and classification labels.
`dev_dataset.csv` is a table in
[CSV](https://en.wikipedia.org/wiki/Comma-separated_values)
format with the following columns:
* **ImageId** - id of the image.
* **URL** - URL of the image.
* **x1**, **y1**, **x2**, **y2** - bounding box of the area of interest in
the image. Bounding box is relative, which means that all coordinates are
between 0 and 1.
* **TrueLabel** - true label of the image.
* **TargetClass** - label for targeted adversarial attack.
* **OriginalLandingURL** - original landing page where this image was found.
* **License** - licence under which image was distributed by author.
* **Author** - author of the image.
* **AuthorProfileURL** - URL of the author's profile.
Dataset is labelled with
[ImageNet](http://www.image-net.org/challenges/LSVRC/2012/) labels.
Specific values of labels are compatible with pre-trained Inception models,
which are available as a part of
[TF-Slim](https://github.com/tensorflow/models/tree/master/slim).
In particular pre-trained Inception v3 and InceptionResnet v2 could be used
to classify dataset with high accuracy.
## Downloading images
`dev_dataset.csv` contains only URLs of the images.
Actual images have to be downloaded before being used for experiments.
`download_images.py` is a Python program which downloads images for all
records in `dev_dataset.csv`. Usage:
```
# Replace CSV_FILE with path to dev_dataset.csv
CSV_FILE=dev_dataset.csv
# Replace OUTPUT_DIR with path to directory where all images should be stored
OUTPUT_DIR=images
# Download images
python download_images.py --input_file=${CSV_FILE} --output_dir=${OUTPUT_DIR}
```
All downloaded images will be cropped according to the bounding boxes in
`dev_dataset.csv` and resized to 299x299 pixels.
Each image will be saved in PNG format with filename `IMAGE_ID.png`
where `IMAGE_ID` is the id of the image from `dev_dataset.csv`.
================================================
FILE: dataset/dev_dataset.csv
================================================
ImageId,URL,x1,y1,x2,y2,TrueLabel,TargetClass,OriginalLandingURL,License,Author,AuthorProfileURL
0c7ac4a8c9dfa802,https://c1.staticflickr.com/9/8540/28821627444_0524012bdd_o.jpg,0,0,0.871838111,1,306,779,https://www.flickr.com/photos/gails_pictures/28821627444,https://creativecommons.org/licenses/by/2.0/,gailhampshire,https://www.flickr.com/people/gails_pictures/
f43fbfe8a9ea876c,https://c1.staticflickr.com/9/8066/28892033183_6f675dcc03_o.jpg,0.25,0,1,0.599757674,884,378,https://www.flickr.com/photos/barty/28892033183,https://creativecommons.org/licenses/by/2.0/,Barry Badcock,https://www.flickr.com/people/barty/
4fc263d35a3ad3ee,https://c1.staticflickr.com/8/7378/27465801596_a9dd11e5e2_o.jpg,0.333333333,0,1,1,244,123,https://www.flickr.com/photos/foxcroftacademy/27465801596,https://creativecommons.org/licenses/by/2.0/,Foxcroft Academy,https://www.flickr.com/people/foxcroftacademy/
cc13c2bc5cdd1f44,https://c1.staticflickr.com/9/8864/28546467522_56229f2bef_o.jpg,0,0,0.5,0.75,560,741,https://www.flickr.com/photos/o_0/28546467522/,https://creativecommons.org/licenses/by/2.0/,Guilhem Vellut,https://www.flickr.com/people/o_0/
73a52afd2f818ed5,https://c1.staticflickr.com/6/5607/31066602702_382b13646e_o.jpg,0.489195231,0,1,0.75,439,696,https://www.flickr.com/photos/chemiebw/31066602702/,https://creativecommons.org/licenses/by/2.0/,Chemie-Verb\303\244nde Baden-W\303\274rttemberg,https://www.flickr.com/people/chemiebw/
58f0fd17c4a0e25a,https://c1.staticflickr.com/9/8262/29250758112_3147698dd2_o.jpg,0,0,0.5625,0.75,991,100,https://www.flickr.com/photos/zongo/29250758112,https://creativecommons.org/licenses/by/2.0/,DAVID HOLT,https://www.flickr.com/people/zongo/
90e11aa7c36c64f2,https://c1.staticflickr.com/8/7528/26850127330_56022d63f7_o.jpg,0,0.25,0.5625,1,950,1,https://www.flickr.com/photos/cogdog/26850127330,https://creativecommons.org/licenses/by/2.0/,Alan Levine,https://www.flickr.com/people/cogdog/
696f0f6bea562bf8,https://c1.staticflickr.com/6/5605/30947139580_468ba7e513_o.jpg,0,0,0.5,0.75,854,267,https://www.flickr.com/photos/jamesbradley/30947139580/,https://creativecommons.org/licenses/by/2.0/,Fr James Bradley,https://www.flickr.com/people/jamesbradley/
df58f94361c6d105,https://c1.staticflickr.com/8/7248/27047266920_8363816754_o.jpg,0.200627477,0,0.601882431,0.75,610,13,https://www.flickr.com/photos/roberthaandrikman/27047266920,https://creativecommons.org/licenses/by/2.0/,Robert Haandrikman,https://www.flickr.com/people/roberthaandrikman/
1394faa319bd353c,https://c1.staticflickr.com/1/542/31667350163_b6906e0d48_o.jpg,0.333333333,0,1,1,610,507,https://www.flickr.com/photos/landrovermena/31667350163,https://creativecommons.org/licenses/by/2.0/,Land Rover MENA,https://www.flickr.com/people/landrovermena/
6cae4a23623d142b,https://c1.staticflickr.com/8/7404/27305101801_5b422e51fe_o.jpg,0.28125,0,0.84375,0.75,583,440,https://flickr.com/39309480@N05/27305101801,https://creativecommons.org/licenses/by/2.0/,Embajada de EEUU en la Argentina,https://www.flickr.com/people/embajadaeeuubuenosaires/
d02adcb9140880a1,https://c1.staticflickr.com/1/404/31746323273_467fb30873_o.jpg,0,0,0.714503817,1,916,783,https://www.flickr.com/photos/ruthanddave/31746323273/,https://creativecommons.org/licenses/by/2.0/,Ruth Hartnup,https://www.flickr.com/people/ruthanddave/
71080285ad6cb4e9,https://c1.staticflickr.com/9/8444/29355103331_45d4b77595_o.jpg,0,0.25,0.75,1,456,478,https://www.flickr.com/photos/themarmot/29355103331,https://creativecommons.org/licenses/by/2.0/,The Marmot,https://www.flickr.com/people/themarmot/
137ab6ca314e9e35,https://c1.staticflickr.com/9/8681/28102039640_11703a03f5_o.jpg,0,0.311985173,0.75,0.935955519,620,556,https://www.flickr.com/photos/130468093@N03/28102039640,https://creativecommons.org/licenses/by/2.0/,~ladyyoruichi~,https://www.flickr.com/people/130468093@N03/
c819099fed6f0d73,https://c1.staticflickr.com/1/126/31638424475_3b36f926b1_o.jpg,0.329912023,0,0.98973607,1,962,777,https://www.flickr.com/photos/djackmanson/31638424475,https://creativecommons.org/licenses/by/2.0/,David Jackmanson,https://www.flickr.com/people/djackmanson/
4b384c8247b56c0a,https://c1.staticflickr.com/9/8526/28626152335_955398ef80_o.jpg,0,0.25,0.5,1,542,925,https://www.flickr.com/photos/virtualpainter/28626152335,https://creativecommons.org/licenses/by/2.0/,Taka Umemura,https://www.flickr.com/people/virtualpainter/
62ebd5f7ce015380,https://c1.staticflickr.com/9/8832/28846755931_9e77600319_o.jpg,0,0,0.66226138,1,631,692,https://www.flickr.com/photos/spera-designerschuhe/28846755931,https://creativecommons.org/licenses/by/2.0/,"SPERA.de Designerschuhe, Taschen und Accessoires",https://www.flickr.com/people/spera-designerschuhe/
f24817d66024dfb6,https://c1.staticflickr.com/8/7286/28064769996_6bf78b5810_o.jpg,0,0,0.5,0.75,742,740,https://www.flickr.com/photos/jdlasica/28064769996,https://creativecommons.org/licenses/by/2.0/,JD Lasica,https://www.flickr.com/people/jdlasica/
1b57d7bbd673c771,https://c1.staticflickr.com/9/8024/29035810873_9be68318c4_o.jpg,0.5,0.25,1,1,423,927,https://www.flickr.com/photos/fotosagenciabrasil/29035810873/,https://creativecommons.org/licenses/by/2.0/,Ag\303\252ncia Brasil Fotografias,https://www.flickr.com/people/fotosagenciabrasil/
a2de1f4f2c1021fa,https://c1.staticflickr.com/9/8598/29005552090_ee38f841ac_o.jpg,0.25,0.25,1,1,456,185,https://www.flickr.com/photos/sillygwailo/29005552090/,https://creativecommons.org/licenses/by/2.0/,Richard Eriksson,https://www.flickr.com/people/sillygwailo/
3e7b01ba495f15f9,https://c1.staticflickr.com/8/7366/26897189910_049b6377e0_o.jpg,0,0,0.75,0.601503759,708,410,https://www.flickr.com/photos/darioalvarez/26897189910,https://creativecommons.org/licenses/by/2.0/,Dario Alvarez,https://www.flickr.com/people/darioalvarez/
1a264165276e3c85,https://c1.staticflickr.com/8/7327/27500591886_a1b257229e_o.jpg,0.5,0,1,0.75,855,759,https://www.flickr.com/photos/presidentialoffice/27500591886,https://creativecommons.org/licenses/by/2.0/,\347\270\275\347\265\261\345\272\234,https://www.flickr.com/people/presidentialoffice/
bc9a5e01c02e759e,https://c1.staticflickr.com/8/7575/27719847416_e231168ac1_o.jpg,0,0.28125,0.75,0.84375,923,18,https://www.flickr.com/photos/jimg944/27719847416/,https://creativecommons.org/licenses/by/2.0/,Jim G,https://www.flickr.com/people/jimg944/
01bdc0cfe670f708,https://c1.staticflickr.com/1/457/31837933011_3e57f56dc9_o.jpg,0,0,0.5,0.75,472,541,https://www.flickr.com/photos/quinet/31837933011,https://creativecommons.org/licenses/by/2.0/,Thomas Quine,https://www.flickr.com/people/quinet/
6af829a442e2e0e7,https://c1.staticflickr.com/6/5827/30663702381_910aca914a_o.jpg,0.25,0,1,1,130,231,https://www.flickr.com/photos/rusty_clark/30663702381,https://creativecommons.org/licenses/by/2.0/,Rusty Clark ~ 100K Photos,https://www.flickr.com/people/rusty_clark/
493694833dc23399,https://c1.staticflickr.com/1/691/33087466756_27fcc6e909_o.jpg,0.25,0.25,0.75,1,538,835,https://www.flickr.com/photos/denalinps/33087466756/,https://creativecommons.org/licenses/by/2.0/,Denali National Park and Preserve,https://www.flickr.com/people/denalinps/
6ac94c9244f84aa3,https://c1.staticflickr.com/9/8887/27621832723_abe5df1bf6_o.jpg,0.28125,0,0.84375,0.75,673,336,https://www.flickr.com/photos/sedoglia/27621832723,https://creativecommons.org/licenses/by/2.0/,Sergio,https://www.flickr.com/people/sedoglia/
7529b42e71769777,https://c1.staticflickr.com/6/5573/30447660301_21f03bc832_o.jpg,0.28125,0,0.84375,0.75,477,618,https://www.flickr.com/photos/archiefalkmaar/30447660301/,https://creativecommons.org/licenses/by/2.0/,Regionaal Archief Alkmaar,https://www.flickr.com/people/archiefalkmaar/
d204464fcf15ad99,https://c1.staticflickr.com/9/8735/28293562656_b6754b6f76_o.jpg,0.25,0.249079529,1,0.747238586,300,269,https://www.flickr.com/photos/zigazou76/28293562656,https://creativecommons.org/licenses/by/2.0/,Fr\303\251d\303\251ric BISSON,https://www.flickr.com/people/zigazou76/
7fd7ce3eb2bf9944,https://c1.staticflickr.com/8/7060/26682014410_e1ae9f3f68_o.jpg,0.25,0,1,1,100,113,https://www.flickr.com/photos/starr-environmental/26682014410/,https://creativecommons.org/licenses/by/2.0/,Forest and Kim Starr,https://www.flickr.com/people/starr-environmental/
303781188f1b3b27,https://c1.staticflickr.com/8/7196/27632686515_7c9e105ab4_o.jpg,0.578252033,0,1,0.75,477,339,https://www.flickr.com/photos/tomhilton/27632686515,https://creativecommons.org/licenses/by/2.0/,Tom Hilton,https://www.flickr.com/people/tomhilton/
67967c9db11151e0,https://c1.staticflickr.com/6/5699/30482545566_9bb69e3a2c_o.jpg,0.5,0.25,1,1,252,820,https://www.flickr.com/photos/blumenbiene/30482545566,https://creativecommons.org/licenses/by/2.0/,Maja Dumat,https://www.flickr.com/people/blumenbiene/
fa2a7d600b62174e,https://c1.staticflickr.com/9/8135/29796651083_af3421402e_o.jpg,0.25,0,1,0.729946524,521,572,https://www.flickr.com/photos/familymwr/29796651083,https://creativecommons.org/licenses/by/2.0/,U.S. Army,https://www.flickr.com/people/familymwr/
cd2d2889ef7ac51c,https://c1.staticflickr.com/8/7108/27445698401_622147f593_o.jpg,0,0,0.666666667,1,924,607,https://www.flickr.com/photos/janitors/27445698401,https://creativecommons.org/licenses/by/2.0/,K\304\201rlis Dambr\304\201ns,https://www.flickr.com/people/janitors/
11954d93a7051cb5,https://c1.staticflickr.com/9/8598/30096731475_f2050e80f0_o.jpg,0.5,0,1,0.75,23,503,https://www.flickr.com/photos/andymorffew/30096731475,https://creativecommons.org/licenses/by/2.0/,Andy Morffew,https://www.flickr.com/people/andymorffew/
03f90f7138f761e8,https://c1.staticflickr.com/8/7358/27496838730_a300e17377_o.jpg,0.25,0.25,1,1,664,490,https://www.flickr.com/photos/pasa/27496838730,https://creativecommons.org/licenses/by/2.0/,Paul Sableman,https://www.flickr.com/people/pasa/
19935b1c0a4d305d,https://c1.staticflickr.com/8/7560/28230694205_599d4915f1_o.jpg,0.304216867,0,1,1,761,642,https://www.flickr.com/photos/lge/28230694205,https://creativecommons.org/licenses/by/2.0/,LG\354\240\204\354\236\220,https://www.flickr.com/people/lge/
9cf861a657c27cec,https://c1.staticflickr.com/1/737/31554472305_631b37cd13_o.jpg,0.28125,0.25,0.84375,1,583,897,https://www.flickr.com/photos/rusty_clark/31554472305/,https://creativecommons.org/licenses/by/2.0/,Rusty Clark ~ 100K Photos,https://www.flickr.com/people/rusty_clark/
05817a675e7506d1,https://c1.staticflickr.com/8/7530/27222000794_49d44c7533_o.jpg,0.246522694,0,0.739568082,0.75,673,754,https://www.flickr.com/photos/trocaire/27222000794,https://creativecommons.org/licenses/by/2.0/,Trocaire,https://www.flickr.com/people/trocaire/
e1c702ed9842dd1c,https://c1.staticflickr.com/8/7538/26750212822_874e61f2f5_o.jpg,0,0.25,0.75,1,693,757,https://www.flickr.com/photos/mcleod/26750212822,https://creativecommons.org/licenses/by/2.0/,Scott McLeod,https://www.flickr.com/people/mcleod/
e7cafac174e90143,https://c1.staticflickr.com/8/7064/26911748774_e91c741c13_o.jpg,0.25,0.25,0.75,1,526,116,https://www.flickr.com/photos/tabor-roeder/26911748774,https://creativecommons.org/licenses/by/2.0/,Phil Roeder,https://www.flickr.com/people/tabor-roeder/
1a680f33500acb4b,https://c1.staticflickr.com/6/5623/30353092243_549ce05481_o.jpg,0,0,0.5625,0.75,932,73,https://www.flickr.com/photos/londonmatt/30353092243,https://creativecommons.org/licenses/by/2.0/,Matt Brown,https://www.flickr.com/people/londonmatt/
81ddbe14219e9dcf,https://c1.staticflickr.com/1/599/32603915941_1f3f02a21f_o.jpg,0.436619718,0,1,0.75,318,672,http://www.flickr.com/photos/treegrow/32603915941/,https://creativecommons.org/licenses/by/2.0/,Katja Schulz,https://www.flickr.com/people/treegrow/
04cb9de291399d15,https://c1.staticflickr.com/9/8671/28725010671_e060588a1b_o.jpg,0.25,0.25,0.75,1,465,451,https://www.flickr.com/photos/photo-digest/28725010671,https://creativecommons.org/licenses/by/2.0/,media.digest,https://www.flickr.com/people/photo-digest/
23f9d18d531eb148,https://c1.staticflickr.com/8/7545/28289771271_d972c53c03_o.jpg,0.249079529,0,0.747238586,0.75,479,851,https://www.flickr.com/photos/londonmatt/28289771271/,https://creativecommons.org/licenses/by/2.0/,Matt Brown,https://www.flickr.com/people/londonmatt/
63f2e14ab6be82cf,https://c1.staticflickr.com/8/7360/27324993991_9e7547e472_o.jpg,0.330871492,0,1,1,668,694,https://www.flickr.com/photos/mdgovpics/27324993991,https://creativecommons.org/licenses/by/2.0/,Maryland GovPics,https://www.flickr.com/people/mdgovpics/
0dffbfa7ba43cb90,https://c1.staticflickr.com/1/599/31842595896_6c327628ee_o.jpg,0.28125,0,0.84375,0.75,962,95,https://flickr.com/10581108@N00/31842595896,https://creativecommons.org/licenses/by/2.0/,jencu,https://www.flickr.com/people/jennycu/
a97274c7e80a1764,https://c1.staticflickr.com/9/8770/28603315541_10de82290f_o.jpg,0,0.25,0.5625,1,866,926,https://flickr.com/10069023@N00/28603315541,https://creativecommons.org/licenses/by/2.0/,Charles Kremenak,https://www.flickr.com/people/charleskremenak/
85e2eea48d912d31,https://c1.staticflickr.com/6/5728/30827582556_27a03b94b4_o.jpg,0.501840943,0.25,1,1,806,136,https://www.flickr.com/photos/eaglebrook/30827582556/,https://creativecommons.org/licenses/by/2.0/,EaglebrookSchool,https://www.flickr.com/people/eaglebrook/
ff5182599937c1ec,https://c1.staticflickr.com/9/8088/29255908970_542c7fcc99_o.jpg,0.25,0,1,0.75,325,210,https://www.flickr.com/photos/orangeaurochs/29255908970/,https://creativecommons.org/licenses/by/2.0/,Orangeaurochs,https://www.flickr.com/people/orangeaurochs/
4bb12984b41d0834,https://c1.staticflickr.com/8/7155/26715421772_322982abb8_o.jpg,0.280784844,0,0.842354533,1,34,8,https://www.flickr.com/photos/lwpkommunikacio/26715421772,https://creativecommons.org/licenses/by/2.0/,Lwp Kommunik\303\241ci\303\263,https://www.flickr.com/people/lwpkommunikacio/
150249123e81930d,https://c1.staticflickr.com/8/7637/27864748826_3611a80685_o.jpg,0.25,0,1,1,923,485,https://www.flickr.com/photos/36668466@N05/27864748826,https://creativecommons.org/licenses/by/2.0/,Fernando Medina,https://www.flickr.com/people/36668466@N05/
f963957ccfa82f6b,https://c1.staticflickr.com/8/7321/27811646942_6af16e2c20_o.jpg,0.217675378,0,0.653026135,0.75,143,8,https://www.flickr.com/photos/bamyers4az/27811646942,https://creativecommons.org/licenses/by/2.0/,Brent Myers,https://www.flickr.com/people/bamyers4az/
890fdaf4e1892e00,https://c1.staticflickr.com/9/8079/29641887231_ac78f6acb2_o.jpg,0,0,0.757861635,1,313,692,https://www.flickr.com/photos/gails_pictures/29641887231,https://creativecommons.org/licenses/by/2.0/,gailhampshire,https://www.flickr.com/people/gails_pictures/
9a1c67f467b9beea,https://c1.staticflickr.com/8/7313/26933714923_dae58c7fa8_o.jpg,0,0.25,0.70913884,1,303,90,https://www.flickr.com/photos/gails_pictures/26933714923,https://creativecommons.org/licenses/by/2.0/,gailhampshire,https://www.flickr.com/people/gails_pictures/
217597258ac12258,https://c1.staticflickr.com/8/7326/27290987603_52008d9de0_o.jpg,0.25,0.25,1,1,583,805,https://www.flickr.com/photos/iwashitashoichi/27290987603,https://creativecommons.org/licenses/by/2.0/,Shoichi Iwashita,https://www.flickr.com/people/iwashitashoichi/
346c5575b60194c3,https://c1.staticflickr.com/6/5753/31338370671_675f18f5a9_o.jpg,0.25,0,0.75,0.75,949,625,https://flickr.com/77742560@N06/31338370671,https://creativecommons.org/licenses/by/2.0/,shankar s.,https://www.flickr.com/people/shankaronline/
296033c3a5910845,https://c1.staticflickr.com/8/7659/27497141411_2fdd591428_o.jpg,0,0,0.675074184,1,361,797,https://www.flickr.com/photos/100915417@N07/27497141411,https://creativecommons.org/licenses/by/2.0/,Charlie Marshall,https://www.flickr.com/people/100915417@N07/
3a7d9bd310202e93,https://c1.staticflickr.com/6/5751/30906474272_60f5035a81_o.jpg,0,0,0.5,0.75,790,660,https://www.flickr.com/photos/sansebastian2016/30906474272,https://creativecommons.org/licenses/by/2.0/,Donostia/San Sebastian 2016,https://www.flickr.com/people/sansebastian2016/
56e9d5f63cfc507e,https://c1.staticflickr.com/6/5767/31254643081_606fefaeef_o.jpg,0,0,1,1,441,624,https://flickr.com/31424626@N05/31254643081,https://creativecommons.org/licenses/by/2.0/,Pulencio,https://www.flickr.com/people/pulencio/
602f2c3749d6021e,https://c1.staticflickr.com/6/5488/30010578363_ae1a2b5fc4_o.jpg,0.25,0,1,0.75,747,106,https://flickr.com/88307459@N08/30010578363,https://creativecommons.org/licenses/by/2.0/,Alessandro,https://www.flickr.com/people/88307459@N08/
7c754696067fdfa9,https://c1.staticflickr.com/8/7322/26952063895_0d0990098b_o.jpg,0.53485064,0,1,0.75,765,469,https://www.flickr.com/photos/zachievenor/26952063895,https://creativecommons.org/licenses/by/2.0/,Zachi Evenor,https://www.flickr.com/people/zachievenor/
8f5eda0b6a910b43,https://c1.staticflickr.com/1/525/31526646220_dbd7c0df37_o.jpg,0.5,0,1,0.75,950,918,https://www.flickr.com/photos/129816626@N04/31526646220/,https://creativecommons.org/licenses/by/2.0/,Elusive Muse,https://www.flickr.com/people/129816626@N04/
89119361e9d9e02d,https://c1.staticflickr.com/9/8064/30107504355_f5a2453191_o.jpg,0,0,0.669128508,1,481,473,http://www.flickr.com/photos/79157069@N03/30107504355,https://creativecommons.org/licenses/by/2.0/,Matthew Paul Argall,https://www.flickr.com/people/79157069@N03/
da63f2acf683c0a7,https://c1.staticflickr.com/3/2626/32878464786_81b7b5f560_o.jpg,0.25,0.25,0.75,1,134,617,https://www.flickr.com/photos/steve_childs/32878464786/,https://creativecommons.org/licenses/by/2.0/,Steve Childs,https://www.flickr.com/people/steve_childs/
741fc1a3fc08731d,https://c1.staticflickr.com/1/333/30878601253_6a06af38ce_o.jpg,0.226157083,0.25,0.678471248,1,793,400,https://www.flickr.com/photos/ufv/30878601253,https://creativecommons.org/licenses/by/2.0/,University of the Fraser Valley,https://www.flickr.com/people/ufv/
d77af00930283f4b,https://c1.staticflickr.com/6/5686/30135548405_290ce24c79_o.jpg,0,0.28125,0.75,0.84375,901,649,https://flickr.com/131810676@N03/30135548405,https://creativecommons.org/licenses/by/2.0/,baka_neko_baka,https://www.flickr.com/people/131810676@N03/
97151fe7a0a6e2e3,https://c1.staticflickr.com/9/8108/28266576044_fe196cd052_o.jpg,0,0,1,1,734,228,https://www.flickr.com/photos/paulstudio/28266576044,https://creativecommons.org/licenses/by/2.0/,Paul Chan,https://www.flickr.com/people/paulstudio/
393d40f3a6a79400,https://c1.staticflickr.com/8/7641/27798795492_12f1e08a40_o.jpg,0,0.25,0.496696035,1,328,846,https://www.flickr.com/photos/shankaronline/27798795492/,https://creativecommons.org/licenses/by/2.0/,shankar s.,https://www.flickr.com/people/shankaronline/
8f5e0855ca8de8ea,https://c1.staticflickr.com/1/594/31875644290_a507a79ca7_o.jpg,0.4375,0.25,1,1,468,716,https://www.flickr.com/photos/briansolis/31875644290,https://creativecommons.org/licenses/by/2.0/,Brian Solis,https://www.flickr.com/people/briansolis/
d72f34526e12fd83,https://c1.staticflickr.com/9/8787/28375652543_039a76200f_o.jpg,0,0.280664063,0.75,0.841992188,442,325,https://www.flickr.com/photos/cogdog/28375652543,https://creativecommons.org/licenses/by/2.0/,Alan Levine,https://www.flickr.com/people/cogdog/
957529a2abaa0581,https://c1.staticflickr.com/6/5493/31215689672_90fdc524c1_o.jpg,0.33773862,0,1,1,883,648,https://www.flickr.com/photos/yourbestdigs/31215689672/,https://creativecommons.org/licenses/by/2.0/,Your Best Digs,https://www.flickr.com/people/yourbestdigs/
3bd1ba0432603b28,https://c1.staticflickr.com/9/8041/29388312836_4151756518_o.jpg,0,0,0.5625,0.75,921,89,https://www.flickr.com/photos/a_peach/29388312836,https://creativecommons.org/licenses/by/2.0/,A_Peach,https://www.flickr.com/people/a_peach/
3228a465697fb2cf,https://c1.staticflickr.com/1/699/32034140530_62059de5a0_o.jpg,0,0,0.75,0.5625,840,922,https://www.flickr.com/photos/ufv/32034140530,https://creativecommons.org/licenses/by/2.0/,University of the Fraser Valley,https://www.flickr.com/people/ufv/
871c99d5658c3189,https://c1.staticflickr.com/1/593/31013399073_e0c80204ed_o.jpg,0.5,0,1,0.75,956,587,https://flickr.com/64586261@N02/31013399073,https://creativecommons.org/licenses/by/2.0/,Ag\303\252ncia Bras\303\255lia,https://www.flickr.com/people/agenciabrasilia/
1733cbc68a2ae05d,https://c1.staticflickr.com/1/465/32838931536_2e1b56309c_o.jpg,0,0,0.666666667,1,556,892,https://www.flickr.com/photos/147079914@N03/32838931536/in/pool-44124304756@N01,https://creativecommons.org/licenses/by/2.0/,sponki25,https://www.flickr.com/people/147079914@N03/
69a3493d13953e1f,https://c1.staticflickr.com/1/486/31850894154_77cd0b743d_o.jpg,0.4375,0.25,1,1,520,407,https://www.flickr.com/photos/byzantiumbooks/31850894154,https://creativecommons.org/licenses/by/2.0/,Bill Smith,https://www.flickr.com/people/byzantiumbooks/
8a82ddd7ab76efbb,https://c1.staticflickr.com/9/8073/29273707766_84a5a2321f_o.jpg,0,0,0.663235294,1,511,908,https://www.flickr.com/photos/shankaronline/29273707766,https://creativecommons.org/licenses/by/2.0/,shankar s.,https://www.flickr.com/people/shankaronline/
e95ef0aeeab7b496,https://c1.staticflickr.com/3/2892/32904176405_735232107b_o.jpg,0.710762332,0,1,0.75,889,860,https://www.flickr.com/photos/arg_flickr/32904176405/,https://creativecommons.org/licenses/by/2.0/,Andrew,https://www.flickr.com/people/arg_flickr/
8555611998ea426a,https://c1.staticflickr.com/6/5600/30019858070_5049f5d386_o.jpg,0,0,0.75,1,991,497,https://www.flickr.com/photos/eamoncurry/30019858070,https://creativecommons.org/licenses/by/2.0/,Eamon Curry,https://www.flickr.com/people/eamoncurry/
1cc2caf8e5db27c3,https://c1.staticflickr.com/1/598/32069226561_2e29df4dce_o.jpg,0.25,0,1,0.5,431,607,https://flickr.com/21841998@N06/32069226561,https://creativecommons.org/licenses/by/2.0/,The People's Tribune,https://www.flickr.com/people/21841998@N06/
a00c8d22e63497c4,https://c1.staticflickr.com/8/7019/26876163625_b5ebe36eaf_o.jpg,0.27818818,0.25,0.834564541,1,431,892,https://www.flickr.com/photos/timmccune/26876163625,https://creativecommons.org/licenses/by/2.0/,Tim McCune,https://www.flickr.com/people/timmccune/
4f553b721705d008,https://c1.staticflickr.com/8/7417/28111852685_716c19bcb5_o.jpg,0,0,0.75,1,397,3,https://www.flickr.com/photos/noaaphotolib/28111852685/in/photolist-hCZ5zh-7RqcE6-7Rtsyb-JQ9Apg/,https://creativecommons.org/licenses/by/2.0/,NOAA Photo Library,https://www.flickr.com/people/noaaphotolib/
f1ce339a44d7a118,https://c1.staticflickr.com/9/8867/28838922156_09d615d6f5_o.jpg,0.333333333,0,1,1,98,702,https://www.flickr.com/photos/132033298@N04/28838922156,https://creativecommons.org/licenses/by/2.0/,C. P. Ewing,https://www.flickr.com/people/132033298@N04/
2153d9869fb5a9ef,https://c1.staticflickr.com/9/8892/28233397700_b175333ccc_o.jpg,0.452546296,0.25,1,1,645,942,https://www.flickr.com/photos/katerha/28233397700,https://creativecommons.org/licenses/by/2.0/,Kate Ter Haar,https://www.flickr.com/people/katerha/
7506caf0a49c3951,https://c1.staticflickr.com/8/7410/27688687271_a42aee521a_o.jpg,0,0,1,0.900181488,79,724,https://www.flickr.com/photos/136941790@N03/27688687271/,https://creativecommons.org/licenses/by/2.0/,laboratorio diagnostica ancona IZSUM,https://www.flickr.com/people/136941790@N03/
1d4133f5bc7af193,https://c1.staticflickr.com/9/8584/28442098602_ed99e31eda_o.jpg,0.259962406,0.25,0.779887218,1,141,911,https://www.flickr.com/photos/25553993@N02/28442098602/,https://creativecommons.org/licenses/by/2.0/,Kev Chapman,https://www.flickr.com/people/25553993@N02/
fd26c4733822dfcc,https://c1.staticflickr.com/9/8649/28250885435_30ea68123c_o.jpg,0.280664063,0.25,0.841992188,1,363,451,https://www.flickr.com/photos/usfwsmtnprairie/28250885435,https://creativecommons.org/licenses/by/2.0/,USFWS Mountain-Prairie,https://www.flickr.com/people/usfwsmtnprairie/
60f5900a00d94b25,https://c1.staticflickr.com/6/5732/31328633496_995b71567c_o.jpg,0.28125,0,0.84375,0.75,706,558,https://www.flickr.com/photos/davidwilson1949/31328633496,https://creativecommons.org/licenses/by/2.0/,David Wilson,https://www.flickr.com/people/davidwilson1949/
79f953be91aa8ce2,https://c1.staticflickr.com/8/7570/27808063061_740fc61f0c_o.jpg,0.28125,0.25,0.84375,1,660,588,https://flickr.com/70724896@N08/27808063061,https://creativecommons.org/licenses/by/2.0/,Betta Tryptophan,https://www.flickr.com/people/nagasakiosada/
d9da4e5ef53d5e8b,https://c1.staticflickr.com/1/537/32179264340_6ea9260e9f_o.jpg,0,0.248826291,1,1,641,487,https://www.flickr.com/photos/ruthanddave/32179264340/,https://creativecommons.org/licenses/by/2.0/,Ruth Hartnup,https://www.flickr.com/people/ruthanddave/
0411ca972e637297,https://c1.staticflickr.com/8/7761/26268791474_72626e9e6a_o.jpg,0.25,0.25,0.75,1,968,697,https://www.flickr.com/photos/nanpalmero/26268791474,https://creativecommons.org/licenses/by/2.0/,Nan Palmero,https://www.flickr.com/people/nanpalmero/
92dbb18dd447fd75,https://c1.staticflickr.com/8/7127/27711989146_46b6ca79f6_o.jpg,0,0.25,0.563380282,1,490,194,https://www.flickr.com/photos/southbeachcars/27711989146,https://creativecommons.org/licenses/by/2.0/,Phillip Pessar,https://www.flickr.com/people/southbeachcars/
65251969959ce0e6,https://c1.staticflickr.com/8/7623/28435254025_3c40331a75_o.jpg,0,0,1,1,938,837,https://www.flickr.com/photos/mcleod/28435254025,https://creativecommons.org/licenses/by/2.0/,Scott McLeod,https://www.flickr.com/people/mcleod/
b76e552d4b3ec0c3,https://c1.staticflickr.com/6/5662/30119560842_26f15fba19_o.jpg,0.462155963,0,1,0.75,992,191,https://www.flickr.com/photos/127338544@N06/30119560842,https://creativecommons.org/licenses/by/2.0/,Sarah Ward,https://www.flickr.com/people/127338544@N06/
828ade8df2d14c45,https://c1.staticflickr.com/6/5649/30456484724_643e11a460_o.jpg,0.5,0.25,1,1,888,988,https://www.flickr.com/photos/johnragai/30456484724,https://creativecommons.org/licenses/by/2.0/,John Ragai,https://www.flickr.com/people/johnragai/
3dc0e8f854bdc9b3,https://c1.staticflickr.com/6/5682/31432432235_54a615c355_o.jpg,0.25,0.25,0.75,1,604,921,https://www.flickr.com/photos/lwpkommunikacio/31432432235,https://creativecommons.org/licenses/by/2.0/,Lwp Kommunik\303\241ci\303\263,https://www.flickr.com/people/lwpkommunikacio/
6bb6cf032c1286c5,https://c1.staticflickr.com/8/7172/26559644113_e1c454ef1c_o.jpg,0.25,0.25,1,0.75,468,367,https://www.flickr.com/photos/quinet/26559644113,https://creativecommons.org/licenses/by/2.0/,Thomas Quine,https://www.flickr.com/people/quinet/
2e9b377877f64b3d,https://c1.staticflickr.com/9/8503/29411674165_57521acbf9_o.jpg,0,0.25,0.75,1,499,706,https://www.flickr.com/photos/clairity/29411674165/,https://creativecommons.org/licenses/by/2.0/,Sharon Mollerus,https://www.flickr.com/people/clairity/
2842a69bf5b14526,https://c1.staticflickr.com/9/8612/28790928395_77327e1c83_o.jpg,0.267530488,0.25,0.802591463,1,880,757,https://www.flickr.com/photos/ruthanddave/28790928395/,https://creativecommons.org/licenses/by/2.0/,Ruth Hartnup,https://www.flickr.com/people/ruthanddave/
a74f197288b10a0d,https://c1.staticflickr.com/9/8532/29057660090_67701b5197_o.jpg,0.25,0,0.75,0.75,808,748,https://www.flickr.com/photos/usacehq/29057660090,https://creativecommons.org/licenses/by/2.0/,U.S. Army Corps of Engineers,https://www.flickr.com/people/usacehq/
7a85f42383ec2f81,https://c1.staticflickr.com/9/8604/29022121774_c82af166b6_o.jpg,0,0.25,0.75,0.75,709,802,https://www.flickr.com/photos/greg_men/29022121774/,https://creativecommons.org/licenses/by/2.0/,Greg_Men,https://www.flickr.com/people/greg_men/
55e85d7b58024966,https://c1.staticflickr.com/9/8611/28176653474_ef1665d13b_o.jpg,0,0,1,1,968,615,https://www.flickr.com/photos/ultrakml/28176653474,https://creativecommons.org/licenses/by/2.0/,Katherine Lim,https://www.flickr.com/people/ultrakml/
d6d192c5786f29f5,https://c1.staticflickr.com/9/8094/29208873373_f929c21796_o.jpg,0.392682927,0.25,1,1,473,830,https://www.flickr.com/photos/vastateparksstaff/29208873373,https://creativecommons.org/licenses/by/2.0/,Virginia State Parks,https://www.flickr.com/people/vastateparksstaff/
f533740a8d4618ce,https://c1.staticflickr.com/1/671/32497563865_bdd560906f_o.jpg,0,0,0.5,0.75,288,563,https://www.flickr.com/photos/30478819@N08/32497563865,https://creativecommons.org/licenses/by/2.0/,Marco Verch,https://www.flickr.com/people/30478819@N08/
5292f5b36a0789fa,https://c1.staticflickr.com/9/8761/28372171573_06dbf9a8d4_o.jpg,0.249079529,0,0.747238586,0.75,854,795,https://www.flickr.com/photos/63363807@N03/28372171573,https://creativecommons.org/licenses/by/2.0/,Didit Putra,https://www.flickr.com/people/63363807@N03/
ba4b978112a20be1,https://c1.staticflickr.com/9/8245/29288650164_e95f3a9c80_o.jpg,0,0.25,0.5,1,972,16,https://www.flickr.com/photos/pahudson/29288650164/,https://creativecommons.org/licenses/by/2.0/,Paul Hudson,https://www.flickr.com/people/pahudson/
3692f6967c632fee,https://c1.staticflickr.com/9/8729/28628001341_0ff5c44db3_o.jpg,0.499263623,0,0.998527246,0.75,806,569,https://www.flickr.com/photos/agenciabrasilia/28628001341,https://creativecommons.org/licenses/by/2.0/,Ag\303\252ncia Bras\303\255lia,https://www.flickr.com/people/agenciabrasilia/
fae551840c1690fa,https://c1.staticflickr.com/9/8166/29643263176_aa56d7230d_o.jpg,0.333333333,0,1,1,720,424,https://www.flickr.com/photos/rusty_clark/29643263176,https://creativecommons.org/licenses/by/2.0/,Rusty Clark ~ 100K Photos,https://www.flickr.com/people/rusty_clark/
8020698d79dc39f2,https://c1.staticflickr.com/3/2823/33351553831_7498912a81_o.jpg,0.25,0.25,0.75,1,855,954,https://www.flickr.com/photos/thejointstaff/33351553831/,https://creativecommons.org/licenses/by/2.0/,Chairman of the Joint Chiefs of Staff,https://www.flickr.com/people/thejointstaff/
d392f0639c17f396,https://c1.staticflickr.com/8/7448/27262568354_6e93ef7b68_o.jpg,0.500736377,0.25,1,1,808,590,https://www.flickr.com/photos/inra_dist/27262568354/,https://creativecommons.org/licenses/by/2.0/,INRA DIST,https://www.flickr.com/people/inra_dist/
8f97e3fface13e4d,https://c1.staticflickr.com/8/7108/27051340785_a3c9ab8b6d_o.jpg,0.333333333,0,1,1,472,548,https://www.flickr.com/photos/quinet/27051340785,https://creativecommons.org/licenses/by/2.0/,Thomas Quine,https://www.flickr.com/people/quinet/
a920691cf2d50f79,https://c1.staticflickr.com/9/8512/29944466315_4dabc1230d_o.jpg,0.25,0,0.75,0.75,947,952,https://www.flickr.com/photos/pellesten/29944466315/,https://creativecommons.org/licenses/by/2.0/,Pelle Sten,https://www.flickr.com/people/pellesten/
a482985ca1e77960,https://c1.staticflickr.com/9/8751/28431687365_edb15100b0_o.jpg,0,0.25,0.601941748,1,891,470,https://www.flickr.com/photos/janitors/28431687365,https://creativecommons.org/licenses/by/2.0/,K\304\201rlis Dambr\304\201ns,https://www.flickr.com/people/janitors/
362e4ac62cf888f4,https://c1.staticflickr.com/1/531/32477078836_371e833f56_o.jpg,0,0,1,1,573,36,https://www.flickr.com/photos/freedomiiphotography/32477078836,https://creativecommons.org/licenses/by/2.0/,Freedom II Andres,https://www.flickr.com/people/freedomiiphotography/
694e7617a4878041,https://c1.staticflickr.com/8/7087/27847654031_e4003bcdca_o.jpg,0,0,1,0.827586207,884,720,https://flickr.com/41383869@N07/27847654031,https://creativecommons.org/licenses/by/2.0/,Nathan Hughes Hamilton,https://www.flickr.com/people/nat507/
fa5484e61e455eb2,https://c1.staticflickr.com/1/141/30799508623_1c015153fb_o.jpg,0.333333333,0,1,1,477,769,https://www.flickr.com/photos/scubabix/30799508623,https://creativecommons.org/licenses/by/2.0/,Rob Bixby,https://www.flickr.com/people/scubabix/
ab42aa5e9745c214,https://c1.staticflickr.com/1/439/30759196054_5d7ae31471_o.jpg,0.524100719,0,1,0.75,582,591,https://www.flickr.com/photos/andreboeni/30759196054,https://creativecommons.org/licenses/by/2.0/,Andrew Bone,https://www.flickr.com/people/andreboeni/
e6e677a28e3bd6d7,https://c1.staticflickr.com/9/8774/28104802823_5748e74f68_o.jpg,0.334315169,0,1,1,604,160,https://www.flickr.com/photos/sierragoddess/28104802823,https://creativecommons.org/licenses/by/2.0/,Darla \330\257\330\247\330\261\331\204\330\247 Hueske,https://www.flickr.com/people/sierragoddess/
2e541180b2323a5d,https://c1.staticflickr.com/6/5538/29704744484_7fee6ebbc3_o.jpg,0,0,0.75,0.75,24,905,https://www.flickr.com/photos/sarahmstewart/29704744484,https://creativecommons.org/licenses/by/2.0/,Sarah Stewart,https://www.flickr.com/people/sarahmstewart/
01f824264783f58d,https://c1.staticflickr.com/6/5734/30178450721_1b2b4033a5_o.jpg,0,0,0.75,0.75,968,678,https://www.flickr.com/photos/naotakem/30178450721,https://creativecommons.org/licenses/by/2.0/,Naotake Murayama,https://www.flickr.com/people/naotakem/
335e604bbe3eec78,https://c1.staticflickr.com/6/5615/30719295680_945ac30a0b_o.jpg,0.5,0,1,0.75,312,687,http://www.flickr.com/photos/52450054@N04/30719295680/,https://creativecommons.org/licenses/by/2.0/,Judy Gallagher,https://www.flickr.com/people/52450054@N04/
4e1bdcb677f21fb4,https://c1.staticflickr.com/8/7646/27898036952_dc65e0387a_o.jpg,0.5,0,1,0.75,874,779,https://www.flickr.com/photos/64084569@N02/27898036952,https://creativecommons.org/licenses/by/2.0/,Singa Hitam,https://www.flickr.com/people/64084569@N02/
c6b5f6c1d79dffc6,https://c1.staticflickr.com/9/8472/28615394904_41ea2d98ce_o.jpg,0,0.25,0.5,1,583,652,https://flickr.com/44440670@N04/28615394904,https://creativecommons.org/licenses/by/2.0/,Bilboko Konpartsak,https://www.flickr.com/people/bilbokokonpartsak/
8f9c1e4fd9f4cb2e,https://c1.staticflickr.com/6/5511/30235489014_5fc7ff19a1_o.jpg,0.27818818,0,0.834564541,0.75,17,498,https://www.flickr.com/photos/taylar/30235489014,https://creativecommons.org/licenses/by/2.0/,Ingrid Taylar,https://www.flickr.com/people/taylar/
f54616f2af588fd8,https://c1.staticflickr.com/9/8190/28571086580_2995522f6a_o.jpg,0.5,0.25,1,1,673,113,https://www.flickr.com/photos/41406729@N05/28571086580/,https://creativecommons.org/licenses/by/2.0/,Ben Fitzgerald-O'Connor,https://www.flickr.com/people/onega/
f20911d36a287dce,https://c1.staticflickr.com/8/7010/26825773645_bb695521b3_o.jpg,0.249631811,0.25,0.748895434,1,781,492,https://www.flickr.com/photos/glynlowe/26825773645,https://creativecommons.org/licenses/by/2.0/,www.GlynLowe.com,https://www.flickr.com/people/glynlowe/
81a7637c67f4f777,https://c1.staticflickr.com/8/7331/27680526741_b962934a0e_o.jpg,0.333333333,0,1,1,490,836,https://www.flickr.com/photos/144110575@N07/27680526741,https://creativecommons.org/licenses/by/2.0/,Jobs For Felons Hub,https://www.flickr.com/people/144110575@N07/
65c1808390bd18c5,https://c1.staticflickr.com/9/8832/28094440470_78960e7877_o.jpg,0,0,0.5625,0.75,686,587,https://www.flickr.com/photos/faircompanies/28094440470,https://creativecommons.org/licenses/by/2.0/,Nicol\303\241s Boullosa,https://www.flickr.com/people/faircompanies/
e570258f1bef4ade,https://c1.staticflickr.com/8/7479/27454174925_9950df0ff9_o.jpg,0,0,0.75,0.75,367,461,https://www.flickr.com/photos/rjbailey/27454174925,https://creativecommons.org/licenses/by/2.0/,Ron Bailey,https://www.flickr.com/people/rjbailey/
58bbaa0c5ab520d5,https://c1.staticflickr.com/8/7361/26646332780_6916622aa8_o.jpg,0.25,0.25,1,1,488,716,https://www.flickr.com/photos/kattis_j/26646332780,https://creativecommons.org/licenses/by/2.0/,Katarina Jardenberg,https://www.flickr.com/people/kattis_j/
556d8b457b94c285,https://c1.staticflickr.com/6/5584/30780053951_156743ba04_o.jpg,0,0,0.666666667,1,747,378,https://www.flickr.com/photos/usarak/30780053951/,https://creativecommons.org/licenses/by/2.0/,U.S. Army Alaska (USARAK),https://www.flickr.com/people/usarak/
38546e7d7136c2ab,https://c1.staticflickr.com/6/5495/30613441041_60e2db1f58_o.jpg,0.28125,0,0.84375,0.75,600,114,https://flickr.com/17157315@N00/30613441041,https://creativecommons.org/licenses/by/2.0/,thekirbster,https://www.flickr.com/people/kirbyurner/
9876fe92d003c9d4,https://c1.staticflickr.com/8/7426/27451221106_7d02f7a3b2_o.jpg,0.28125,0,0.84375,0.75,913,357,https://www.flickr.com/photos/10413717@N08/27451221106,https://creativecommons.org/licenses/by/2.0/,Smabs Sputzer,https://www.flickr.com/people/10413717@N08/
8df3dc0c3fef1824,https://c1.staticflickr.com/9/8509/29548650262_4dba7e8039_o.jpg,0.333333333,0,1,1,951,843,https://flickr.com/143363015@N06/29548650262,https://creativecommons.org/licenses/by/2.0/,Tobias Begemann,https://www.flickr.com/people/tobiasbegemann/
938ada2f2bfa2b68,https://c1.staticflickr.com/9/8149/29352102754_7ac0f1c311_o.jpg,0.25,0.25,0.75,1,844,918,https://www.flickr.com/photos/amslerpix/29352102754/,https://creativecommons.org/licenses/by/2.0/,amslerPIX,https://www.flickr.com/people/amslerpix/
61131df39f19a4a0,https://c1.staticflickr.com/6/5497/31308303502_0e6f130313_o.jpg,0,0.25,0.5625,1,615,867,https://www.flickr.com/photos/davidstanleytravel/31308303502,https://creativecommons.org/licenses/by/2.0/,David Stanley,https://www.flickr.com/people/davidstanleytravel/
7278c2b63080f08c,https://c1.staticflickr.com/1/338/32818896976_e770e081a2_o.jpg,0,0,0.666666667,1,349,287,http://www.flickr.com/photos/noortjvdb/32818896976/,https://creativecommons.org/licenses/by/2.0/,noortjevdB,https://www.flickr.com/people/noortjvdb/
f734e87286835196,https://c1.staticflickr.com/6/5618/29467877973_f53d845cd7_o.jpg,0.249079529,0.25,0.747238586,1,324,660,https://www.flickr.com/photos/usfwsmtnprairie/29467877973/,https://creativecommons.org/licenses/by/2.0/,USFWS Mountain-Prairie,https://www.flickr.com/people/usfwsmtnprairie/
06a0e36c443746b5,https://c1.staticflickr.com/1/689/31497463186_001b31fa44_o.jpg,0.5,0,1,0.75,354,232,https://www.flickr.com/photos/dkeats/31497463186,https://creativecommons.org/licenses/by/2.0/,Derek Keats,https://www.flickr.com/people/dkeats/
d7d8fc1442a82a8e,https://c1.staticflickr.com/8/7041/26864593362_503898424a_o.jpg,0,0.25,0.599757674,1,22,846,https://www.flickr.com/photos/andymorffew/26864593362,https://creativecommons.org/licenses/by/2.0/,Andy Morffew,https://www.flickr.com/people/andymorffew/
f9937696f421f4e4,https://c1.staticflickr.com/1/688/32401990166_57c8cdae3d_o.jpg,0.333333333,0,1,1,85,491,https://www.flickr.com/photos/kkoshy/32401990166,https://creativecommons.org/licenses/by/2.0/,Koshy Koshy,https://www.flickr.com/people/kkoshy/
9429f0d1ad2283df,https://c1.staticflickr.com/6/5034/30184154626_f341307e8a_o.jpg,0,0.200323102,1,1,438,464,https://www.flickr.com/photos/janitors/30184154626,https://creativecommons.org/licenses/by/2.0/,K\304\201rlis Dambr\304\201ns,https://www.flickr.com/people/janitors/
7524a7ef9de8edc3,https://c1.staticflickr.com/9/8825/28821400601_33e22535e7_o.jpg,0.13590604,0,1,1,947,307,https://www.flickr.com/photos/oceanyamaha/28821400601,https://creativecommons.org/licenses/by/2.0/,ocean yamaha,https://www.flickr.com/people/oceanyamaha/
c98a8640dcfaa5e0,https://c1.staticflickr.com/1/656/32592379656_ef2d01af55_o.jpg,0,0,0.563380282,0.75,747,847,https://www.flickr.com/photos/mark6mauno/32592379656/,https://creativecommons.org/licenses/by/2.0/,mark6mauno,https://www.flickr.com/people/mark6mauno/
d34c51d7523e9c0f,https://c1.staticflickr.com/9/8861/28145818093_4c661cab2c_o.jpg,0,0,0.663235294,1,647,655,https://www.flickr.com/photos/shankaronline/28145818093,https://creativecommons.org/licenses/by/2.0/,shankar s.,https://www.flickr.com/people/shankaronline/
24726d9054e9d78f,https://c1.staticflickr.com/9/8205/28857614150_fc34c1c771_o.jpg,0.421177267,0,0.842354533,0.75,545,455,https://www.flickr.com/photos/wittcogmbh/28857614150/,https://creativecommons.org/licenses/by/2.0/,wittco.gmbh,https://www.flickr.com/people/wittcogmbh/
66aa56675136bbab,https://c1.staticflickr.com/8/7237/27131945991_c25202b461_o.jpg,0,0.331617647,1,0.994852941,470,607,https://www.flickr.com/photos/sterlingcollege/27131945991/,https://creativecommons.org/licenses/by/2.0/,Sterling College,https://www.flickr.com/people/sterlingcollege/
a8fe76c687b00e33,https://c1.staticflickr.com/1/538/31501305733_eba5c35a04_o.jpg,0.438671875,0.25,1,1,598,119,https://flickr.com/25187162@N03/31501305733,https://creativecommons.org/licenses/by/2.0/,BRUCE GIBSON,https://www.flickr.com/people/gibsongunleather/
411c5d79017077f4,https://c1.staticflickr.com/8/7357/27945593082_c5faf86d90_o.jpg,0,0,0.744548287,1,82,677,https://www.flickr.com/photos/jkirkhart35/27945593082,https://creativecommons.org/licenses/by/2.0/,Jerry Kirkhart,https://www.flickr.com/people/jkirkhart35/
bb6fcb4a52b4fc0f,https://c1.staticflickr.com/8/7796/26996485435_ce0ae48ae9_o.jpg,0.333333333,0,1,1,735,510,https://www.flickr.com/photos/transitomedellin/26996485435,https://creativecommons.org/licenses/by/2.0/,Secretar\303\255a de Movilidad de Medell\303\255n,https://www.flickr.com/people/transitomedellin/
84640859ee739095,https://c1.staticflickr.com/9/8484/29052403164_26fb76527d_o.jpg,0.28125,0.25,0.84375,1,720,580,https://www.flickr.com/photos/rusty_clark/29052403164,https://creativecommons.org/licenses/by/2.0/,Rusty Clark ~ 100K Photos,https://www.flickr.com/people/rusty_clark/
6d2d82bc1ba0a956,https://c1.staticflickr.com/1/642/31650552204_c0eed2f414_o.jpg,0,0,0.75,0.713028169,52,664,https://www.flickr.com/photos/jsjgeology/31650552204,https://creativecommons.org/licenses/by/2.0/,James St. John,https://www.flickr.com/people/jsjgeology/
3e1e47f5af2a3f16,https://c1.staticflickr.com/8/7515/27308980890_45a4af4039_o.jpg,0.251294379,0.25,0.753883136,1,294,357,https://www.flickr.com/photos/dkeats/27308980890,https://creativecommons.org/licenses/by/2.0/,Derek Keats,https://www.flickr.com/people/dkeats/
1ac44ddb6a2d497a,https://c1.staticflickr.com/6/5782/31278384662_150be3d19e_o.jpg,0.333333333,0,1,1,898,27,https://www.flickr.com/photos/lge/31278384662,https://creativecommons.org/licenses/by/2.0/,LG\354\240\204\354\236\220,https://www.flickr.com/people/lge/
7a291389e67a8a07,https://c1.staticflickr.com/9/8164/29763489606_b506759ed9_o.jpg,0,0.333333333,1,1,417,637,https://www.flickr.com/photos/rickmccharles/29763489606/,https://creativecommons.org/licenses/by/2.0/,Rick McCharles,https://www.flickr.com/people/rickmccharles/
afa0f88aaab03427,https://c1.staticflickr.com/9/8284/29065395243_e0aa5811b3_o.jpg,0,0.25,0.5625,1,545,3,https://flickr.com/16813029@N08/29065395243,https://creativecommons.org/licenses/by/2.0/,wittco.gmbh,https://www.flickr.com/people/wittcogmbh/
1e26772fc8c493bb,https://c1.staticflickr.com/6/5725/30011753244_385c391182_o.jpg,0,0,0.5,0.75,416,14,http://www.flickr.com/photos/147860906@N07/30011753244/,https://creativecommons.org/licenses/by/2.0/,DYKT Mohigan,https://www.flickr.com/people/147860906@N07/
4d1237ccbd9a5b4b,https://c1.staticflickr.com/9/8015/29404892510_e505843f23_o.jpg,0.353159851,0.25,0.706319703,1,815,423,https://www.flickr.com/photos/yamahawatercraft/29404892510/,https://creativecommons.org/licenses/by/2.0/,Yamaha Watercraft Group,https://www.flickr.com/people/yamahawatercraft/
c3f452167c39302f,https://c1.staticflickr.com/8/7571/27007736911_797f24353c_o.jpg,0.350800582,0,1,1,296,922,https://www.flickr.com/photos/usdagov/27007736911,https://creativecommons.org/licenses/by/2.0/,U.S. Department of Agriculture,https://www.flickr.com/people/usdagov/
6841e385fe79177f,https://c1.staticflickr.com/1/689/31896146460_9cd904330e_o.jpg,0.255395683,0.25,1,1,830,833,https://flickr.com/45131642@N00/31896146460,https://creativecommons.org/licenses/by/2.0/,Phil Parker,https://www.flickr.com/people/45131642@N00/
b48febf2b989205b,https://c1.staticflickr.com/8/7537/26855046792_36c804efd2_o.jpg,0.25,0.25,0.75,1,760,635,https://www.flickr.com/photos/barnimages/26855046792,https://creativecommons.org/licenses/by/2.0/,barnimages.com,https://www.flickr.com/people/barnimages/
baeb1300832574aa,https://c1.staticflickr.com/9/8775/29342994144_a7e3326c12_o.jpg,0.454002809,0,0.908005618,0.75,972,660,https://www.flickr.com/photos/hisgett/29342994144/,https://creativecommons.org/licenses/by/2.0/,Tony Hisgett,https://www.flickr.com/people/hisgett/
7b6cc934fda859fa,https://c1.staticflickr.com/9/8752/28029665143_654198da68_o.jpg,0.25,0.28125,1,0.84375,307,653,https://www.flickr.com/photos/yto/28029665143/,https://creativecommons.org/licenses/by/2.0/,Tatsuo Yamashita,https://www.flickr.com/people/yto/
39f82c728c956125,https://c1.staticflickr.com/1/400/32155857566_fb6080d6f9_o.jpg,0.296147673,0,0.888443018,0.75,638,762,http://www.flickr.com/photos/mark-gunn/32155857566/,https://creativecommons.org/licenses/by/2.0/,Mark Gunn,https://www.flickr.com/people/mark-gunn/
c8231978dc765004,https://c1.staticflickr.com/8/7787/28887518643_2e0a3954f5_o.jpg,0.248348018,0.25,0.745044053,1,472,741,https://flickr.com/51434786@N06/28887518643,https://creativecommons.org/licenses/by/2.0/,crudmucosa,https://www.flickr.com/people/crudmucosa/
823f8eae0df2d5c1,https://c1.staticflickr.com/8/7482/27862170094_b1b7c6a698_o.jpg,0,0.25,0.531155015,1,95,570,https://www.flickr.com/photos/usfwsmtnprairie/27862170094,https://creativecommons.org/licenses/by/2.0/,USFWS Mountain-Prairie,https://www.flickr.com/people/usfwsmtnprairie/
038fd7a750733bb5,https://c1.staticflickr.com/1/654/31793584681_74a2ac4e3a_o.jpg,0,0,0.490510949,0.75,18,103,https://www.flickr.com/photos/kkoshy/31793584681,https://creativecommons.org/licenses/by/2.0/,Koshy Koshy,https://www.flickr.com/people/kkoshy/
6d6078c60e59e9f4,https://c1.staticflickr.com/9/8136/30193749621_f4b1f30016_o.jpg,0,0,0.5625,0.75,985,797,https://www.flickr.com/photos/usfwsmidwest/30193749621/,https://creativecommons.org/licenses/by/2.0/,USFWSmidwest,https://www.flickr.com/people/usfwsmidwest/
1f71668ab3dbe81b,https://c1.staticflickr.com/1/452/31908949435_f7e5ec059c_o.jpg,0,0,1,0.75,709,967,https://www.flickr.com/photos/londonmatt/31908949435,https://creativecommons.org/licenses/by/2.0/,Matt Brown,https://www.flickr.com/people/londonmatt/
70b3b833463d20b9,https://c1.staticflickr.com/8/7052/27277805330_6ee69eaf87_o.jpg,0,0.28125,0.75,0.84375,864,857,https://www.flickr.com/photos/crondeau/27277805330,https://creativecommons.org/licenses/by/2.0/,Christine Rondeau,https://www.flickr.com/people/crondeau/
dd4d033a9a45552d,https://c1.staticflickr.com/9/8580/29739921130_3c98d8504c_o.jpg,0.282719436,0,0.848158307,0.75,392,126,https://www.flickr.com/photos/taylar/29739921130,https://creativecommons.org/licenses/by/2.0/,Ingrid Taylar,https://www.flickr.com/people/taylar/
8800cff23fade16a,https://c1.staticflickr.com/8/7448/26655153174_a2122e0682_o.jpg,0.25,0.215753425,1,0.647260274,532,314,https://www.flickr.com/photos/51764518@N02/26655153174,https://creativecommons.org/licenses/by/2.0/,Joe Haupt,https://www.flickr.com/people/51764518@N02/
af2ac1705dc19a5f,https://c1.staticflickr.com/9/8870/27676047423_1399759e15_o.jpg,0.333333333,0,1,1,384,99,https://www.flickr.com/photos/30802095@N04/27676047423,https://creativecommons.org/licenses/by/2.0/,Liam Lysaght,https://www.flickr.com/people/30802095@N04/
87937b805302f958,https://c1.staticflickr.com/1/737/32203735982_b50d7c2ca2_o.jpg,0,0.25,0.421177267,1,418,873,https://www.flickr.com/photos/indigoskye/32203735982/in/photolist-R4JyKh-Q1hbGP-R1Gh67-HJixCL-QAEACy-QZmsqR-PTxYKd-PW9vX2-R7jm25-R7hjwW-QAqSgq-R7hhzu-R7hgyb-RazyPk-PSDtLK-PRt1D4-R5An1t-R2dxoq-PQYSyx-PQVJLV-Qv1VKs-QQAfjx-QPtAQH-QV1feS-QZUFDW-QiHqud-Qipyb1-QP34Gf-QF3Y5K-QCsidg-QzgK6Z-QGhQVL-QFLXCt-Pw4Qzr-QKAPYa-Ptjweh-Pw4AiR-QGhLiE-Qbw8CG-QKA5zr-QKzZVM-QKzUwk-QwtoyG-Pw3Y58-PtiNHS-PtiF79-Qbvq49-QGgLtS-Qbvg2m-PtioRJ,https://creativecommons.org/licenses/by/2.0/,John Frost,https://www.flickr.com/people/indigoskye/
f33087679c5e7799,https://c1.staticflickr.com/6/5571/31004412114_2bbb2ce701_o.jpg,0.25,0,1,0.641068447,443,588,https://www.flickr.com/photos/duncanh1/31004412114,https://creativecommons.org/licenses/by/2.0/,Dun.can,https://www.flickr.com/people/duncanh1/
6374e7e35ad90f50,https://c1.staticflickr.com/6/5513/31121388731_7eecd1eea3_o.jpg,0,0,0.666666667,1,39,771,https://www.flickr.com/photos/silkebaron/31121388731/,https://creativecommons.org/licenses/by/2.0/,prilfish,https://www.flickr.com/people/silkebaron/
92c73d668e2cd3ce,https://c1.staticflickr.com/6/5444/29773329694_58d4166f7b_o.jpg,0,0,0.75,1,859,582,https://www.flickr.com/photos/togawanderings/29773329694,https://creativecommons.org/licenses/by/2.0/,Thomas Galvez,https://www.flickr.com/people/togawanderings/
e8d5809ee6888f8f,https://c1.staticflickr.com/8/7742/26192609743_0b09bc425e_o.jpg,0,0.25,0.502588757,1,717,641,https://www.flickr.com/photos/riversdale_estate/26192609743,https://creativecommons.org/licenses/by/2.0/,Riversdale Estate,https://www.flickr.com/people/riversdale_estate/
45da32a1cf073a4f,https://c1.staticflickr.com/8/7362/27048969652_bf3a3854f1_o.jpg,0,0.25,0.544615385,1,100,897,https://www.flickr.com/photos/brighton/27048969652,https://creativecommons.org/licenses/by/2.0/,Jim Linwood,https://www.flickr.com/people/brighton/
fe94909a2fad4ffe,https://c1.staticflickr.com/8/7434/27542851474_00e37a272d_o.jpg,0,0.187296417,1,1,547,965,https://www.flickr.com/photos/haywirecustomguitars/27542851474,https://creativecommons.org/licenses/by/2.0/,Rick Mariner,https://www.flickr.com/people/haywirecustomguitars/
00c3cd597f1ee96f,https://c1.staticflickr.com/6/5615/31076781681_e0a951dd43_o.jpg,0,0.464122137,0.75,1,138,96,https://flickr.com/143049688@N08/31076781681,https://creativecommons.org/licenses/by/2.0/,MR MAO PICS,https://www.flickr.com/people/143049688@N08/
a5949b0719d3ea77,https://c1.staticflickr.com/9/8667/28605783432_909eee5361_o.jpg,0.25,0.25,0.75,1,981,473,https://www.flickr.com/photos/amslerpix/28605783432/,https://creativecommons.org/licenses/by/2.0/,amslerPIX,https://www.flickr.com/people/amslerpix/
d7984e6e1a51b3c4,https://c1.staticflickr.com/9/8883/28628911182_0982dd70ae_o.jpg,0.4375,0,1,0.75,518,937,https://flickr.com/32916425@N04/28628911182,https://creativecommons.org/licenses/by/2.0/,Jeremy Thompson,https://www.flickr.com/people/rollercoasterphilosophy/
979757e16b67ac7e,https://c1.staticflickr.com/6/5590/31340775762_a825141a4d_o.jpg,0,0.25,0.636439268,1,323,798,https://www.flickr.com/photos/gails_pictures/31340775762/,https://creativecommons.org/licenses/by/2.0/,gailhampshire,https://www.flickr.com/people/gails_pictures/
60ab0fb53634bc3c,https://c1.staticflickr.com/9/8410/28986276455_81071dc27d_o.jpg,0,0.25,0.504444444,1,766,552,https://flickr.com/22711505@N05/28986276455,https://creativecommons.org/licenses/by/2.0/,Ron Cogswell,https://www.flickr.com/people/22711505@N05/
ad333e5d6953cbbf,https://c1.staticflickr.com/6/5788/30472796174_6eec033c0e_o.jpg,0.25,0,0.75,0.75,633,297,https://flickr.com/21178495@N06/30472796174,https://creativecommons.org/licenses/by/2.0/,Tiago Cassol Schvarstzhaupt,https://www.flickr.com/people/eletrosonico/
2b7e6f0d6f73fa1f,https://c1.staticflickr.com/3/2649/32280811454_5755bb1af9_o.jpg,0,0,0.75,0.732589286,638,235,https://flickr.com/56041749@N02/32280811454,https://creativecommons.org/licenses/by/2.0/,Denise Krebs,https://www.flickr.com/people/mrsdkrebs/
4063377442ea93d3,https://c1.staticflickr.com/1/653/32223796996_304c6b269d_o.jpg,0.25,0,0.75,0.75,596,814,https://www.flickr.com/photos/grimmegroup/32223796996/,https://creativecommons.org/licenses/by/2.0/,Grimme Group,https://www.flickr.com/people/grimmegroup/
60ed157b21d49c4c,https://c1.staticflickr.com/3/2843/32866501816_486e532c1a_o.jpg,0,0.25,0.606331169,1,755,960,https://www.flickr.com/photos/51764518@N02/32866501816,https://creativecommons.org/licenses/by/2.0/,Joe Haupt,https://www.flickr.com/people/51764518@N02/
8f07c92f0af97807,https://c1.staticflickr.com/8/7366/26918793702_778d2226ac_o.jpg,0.5,0.25,1,1,806,108,https://www.flickr.com/photos/claude_wians/26918793702,https://creativecommons.org/licenses/by/2.0/,Claude Wians,https://www.flickr.com/people/claude_wians/
d67b326ef48bb7b7,https://c1.staticflickr.com/6/5350/29991729355_5ab8b027df_o.jpg,0.333333333,0,1,1,874,546,https://www.flickr.com/photos/bholl7510/29991729355/,https://creativecommons.org/licenses/by/2.0/,Brian Holland,https://www.flickr.com/people/bholl7510/
9f3afb58c061c290,https://c1.staticflickr.com/9/8629/27671691554_a8bbdda66f_o.jpg,0.264204545,0.25,0.792613636,1,981,754,https://www.flickr.com/photos/noaaphotolib/27671691554,https://creativecommons.org/licenses/by/2.0/,NOAA Photo Library,https://www.flickr.com/people/noaaphotolib/
1f7c25207bc3e303,https://c1.staticflickr.com/9/8605/29961048043_fe10e305d4_o.jpg,0.25,0,0.75,0.75,476,979,https://flickr.com/56537760@N03/29961048043,https://creativecommons.org/licenses/by/2.0/,Th\303\251o Paul,https://www.flickr.com/people/theopaul/
70d812d368e3e828,https://c1.staticflickr.com/9/8261/29319398451_2005584856_o.jpg,0,0,0.75,0.75,456,202,https://www.flickr.com/photos/markmorgantrinidad/29319398451,https://creativecommons.org/licenses/by/2.0/,Mark Morgan,https://www.flickr.com/people/markmorgantrinidad/
e19a59ad09d18497,https://c1.staticflickr.com/8/7300/27213625016_61cc784152_o.jpg,0,0.25,0.559282371,1,443,915,https://www.flickr.com/photos/rutiful/27213625016,https://creativecommons.org/licenses/by/2.0/,Ruth Hara,https://www.flickr.com/people/rutiful/
dde33b51c8c152d2,https://c1.staticflickr.com/4/3784/32757850161_333a586b05_o.jpg,0,0,0.75,1,735,969,https://www.flickr.com/photos/27665395@N05/32757850161,https://creativecommons.org/licenses/by/2.0/,Jason Lawrence,https://www.flickr.com/people/27665395@N05/
a33af1b9f8b8a81b,https://c1.staticflickr.com/6/5592/29999027335_510c67fbc7_o.jpg,0.28125,0.25,0.84375,1,880,667,https://www.flickr.com/photos/31029865@N06/29999027335,https://creativecommons.org/licenses/by/2.0/,Dick Thomas Johnson,https://www.flickr.com/people/31029865@N06/
1c924877ccc60129,https://c1.staticflickr.com/3/2002/32192998414_890b5b84db_o.jpg,0.4375,0.25,1,1,410,567,https://www.flickr.com/photos/stevendepolo/32192998414,https://creativecommons.org/licenses/by/2.0/,Steven Depolo,https://www.flickr.com/people/stevendepolo/
74dbbe535861d709,https://c1.staticflickr.com/8/7687/27703779525_8a8baaaae3_o.jpg,0,0,0.666666667,1,702,194,https://www.flickr.com/photos/7armyjmtc/27703779525,https://creativecommons.org/licenses/by/2.0/,7th Army Training Command,https://www.flickr.com/people/7armyjmtc/
858ec91996beb034,https://c1.staticflickr.com/9/8746/28705196386_80e810df65_o.jpg,0,0,0.75,0.75,686,962,https://www.flickr.com/photos/moto_club4ag/28705196386,https://creativecommons.org/licenses/by/2.0/,Moto "Club4AG" Miwa,https://www.flickr.com/people/moto_club4ag/
e5cf220f8144c192,https://c1.staticflickr.com/8/7554/27328391223_6883936624_o.jpg,0.280784844,0,0.842354533,1,706,441,https://www.flickr.com/photos/abhinavnfr/27328391223,https://creativecommons.org/licenses/by/2.0/,Abhinav Phangcho Choudhury,https://www.flickr.com/people/abhinavnfr/
34a39905ce228160,https://c1.staticflickr.com/8/7461/26512655533_d5fe870fbb_o.jpg,0,0.5,0.75,1,769,752,https://www.flickr.com/photos/30478819@N08/26512655533,https://creativecommons.org/licenses/by/2.0/,Marco Verch,https://www.flickr.com/people/30478819@N08/
9455bd672cb9e4bd,https://c1.staticflickr.com/8/7442/27892201106_9c907e9c26_o.jpg,0.25,0,1,1,522,582,https://flickr.com/39160147@N03/27892201106,https://creativecommons.org/licenses/by/2.0/,Mike Mozart,https://www.flickr.com/people/jeepersmedia/
9c509bfb75167fb0,https://c1.staticflickr.com/1/558/32052180035_f042256367_o.jpg,0,0,1,0.831960461,641,748,https://flickr.com/44093058@N06/32052180035,https://creativecommons.org/licenses/by/2.0/,Blondinrikard Fr\303\266berg,https://www.flickr.com/people/blondinrikard/
37e7dc99bf2704c7,https://c1.staticflickr.com/8/7278/26737658351_041174fc0e_o.jpg,0.25,0.25,1,0.75,664,610,https://www.flickr.com/photos/97199236@N04/26737658351,https://creativecommons.org/licenses/by/2.0/,Andrey Gaverdovsky,https://www.flickr.com/people/97199236@N04/
f2bfa7a95e787fe1,https://c1.staticflickr.com/4/3918/33459563545_763a160b5a_o.jpg,0.248348018,0,0.745044053,0.75,721,218,https://www.flickr.com/photos/yourbestdigs/33459563545/,https://creativecommons.org/licenses/by/2.0/,Your Best Digs,https://www.flickr.com/people/yourbestdigs/
0f9d8c86a9f38020,https://c1.staticflickr.com/9/8556/29567784475_4f78605d50_o.jpg,0.333333333,0,1,1,760,118,https://www.flickr.com/photos/markusspiske/29567784475/,https://creativecommons.org/licenses/by/2.0/,Markus Spiske,https://www.flickr.com/people/markusspiske/
ce05236afebb173d,https://c1.staticflickr.com/1/515/30802275984_2565161d0f_o.jpg,0,0.25,0.710456942,1,536,510,https://www.flickr.com/photos/glorycycles/30802275984,https://creativecommons.org/licenses/by/2.0/,Glory Cycles,https://www.flickr.com/people/glorycycles/
12fb008451be82d4,https://c1.staticflickr.com/1/339/31842507145_e9db35db2b_o.jpg,0.28125,0,0.84375,0.75,583,555,https://www.flickr.com/photos/southbeachcars/31842507145,https://creativecommons.org/licenses/by/2.0/,Phillip Pessar,https://www.flickr.com/people/southbeachcars/
1a7425e8f990e04a,https://c1.staticflickr.com/6/5635/30586945602_29b323c620_o.jpg,0.25,0.25,1,1,608,676,https://www.flickr.com/photos/powellburns/30586945602,https://creativecommons.org/licenses/by/2.0/,Powell Burns,https://www.flickr.com/people/powellburns/
1ba816dc6937b62d,https://c1.staticflickr.com/9/8538/29489317193_4ea10616ea_o.jpg,0.496696035,0.25,0.99339207,1,860,768,https://www.flickr.com/photos/yourbestdigs/29489317193,https://creativecommons.org/licenses/by/2.0/,Your Best Digs,https://www.flickr.com/people/yourbestdigs/
a92e49d8bbdc2aae,https://c1.staticflickr.com/8/7292/28045564580_52c7cf78b1_o.jpg,0,0,0.684603886,1,533,564,https://www.flickr.com/photos/regnatarajan/28045564580,https://creativecommons.org/licenses/by/2.0/,Reg Natarajan,https://www.flickr.com/people/regnatarajan/
0e0f1fd2ed183781,https://c1.staticflickr.com/6/5785/29863538926_4b27fc8b6a_o.jpg,0,0,0.80420712,1,114,988,https://www.flickr.com/photos/gails_pictures/29863538926,https://creativecommons.org/licenses/by/2.0/,gailhampshire,https://www.flickr.com/people/gails_pictures/
c83cfca4bc9dd3c7,https://c1.staticflickr.com/8/7338/26885484975_11ac869fe2_o.jpg,0.421177267,0.25,0.842354533,1,696,730,https://flickr.com/65811939@N00/26885484975,https://creativecommons.org/licenses/by/2.0/,Radarsmum67,https://www.flickr.com/people/radarsmum67/
172f992e1a0ebbc3,https://c1.staticflickr.com/6/5598/31398988035_25b2ca9970_o.jpg,0.306930693,0,0.920792079,1,566,492,https://www.flickr.com/photos/kansasscanner/31398988035/,https://creativecommons.org/licenses/by/2.0/,Tyler Silvest,https://www.flickr.com/people/kansasscanner/
565c67fd230f18cc,https://c1.staticflickr.com/9/8783/28325823061_8c659541be_o.jpg,0,0,0.5,0.75,555,854,https://www.flickr.com/photos/115391424@N05/28325823061,https://creativecommons.org/licenses/by/2.0/,lasta29,https://www.flickr.com/people/115391424@N05/
b8596bba57a73794,https://c1.staticflickr.com/8/7380/26874457623_c0dc46b3fa_o.jpg,0.475215517,0.25,0.950431034,1,352,41,https://www.flickr.com/photos/dkeats/26874457623,https://creativecommons.org/licenses/by/2.0/,Derek Keats,https://www.flickr.com/people/dkeats/
d94940216544b2c5,https://c1.staticflickr.com/4/3684/32889855711_216843d54b_o.jpg,0,0,0.745709828,1,312,622,https://www.flickr.com/photos/gails_pictures/32889855711,https://creativecommons.org/licenses/by/2.0/,gailhampshire,https://www.flickr.com/people/gails_pictures/
9f55ac35ce9703e5,https://c1.staticflickr.com/8/7326/26785585893_a25ac89a89_o.jpg,0.226157083,0.25,0.678471248,1,9,194,https://www.flickr.com/photos/94066540@N08/26785585893,https://creativecommons.org/licenses/by/2.0/,Stuart Mckiggan,https://www.flickr.com/people/94066540@N08/
55323ce1ff485412,https://c1.staticflickr.com/1/772/32544267962_4093028c88_o.jpg,0,0,0.5,0.75,386,571,https://www.flickr.com/photos/30478819@N08/32544267962,https://creativecommons.org/licenses/by/2.0/,Marco Verch,https://www.flickr.com/people/30478819@N08/
526f322d78bd5b44,https://c1.staticflickr.com/6/5674/30963905825_0ff9253d66_o.jpg,0.271186441,0,1,1,571,288,https://www.flickr.com/photos/taymtaym/30963905825/,https://creativecommons.org/licenses/by/2.0/,taymtaym,https://www.flickr.com/people/taymtaym/
229fbe790098d2e5,https://c1.staticflickr.com/9/8366/29338309226_66c4557833_o.jpg,0,0,0.563380282,0.75,481,576,https://www.flickr.com/photos/jeepersmedia/29338309226,https://creativecommons.org/licenses/by/2.0/,Mike Mozart,https://www.flickr.com/people/jeepersmedia/
e0c0f412d78571dc,https://c1.staticflickr.com/8/7079/27237503592_028a10898b_o.jpg,0.25,0,1,0.748646209,734,409,https://www.flickr.com/photos/alvy/27237503592,https://creativecommons.org/licenses/by/2.0/,\303\201lvaro Ib\303\241\303\261ez,https://www.flickr.com/people/alvy/
d12aad0d18252b40,https://c1.staticflickr.com/9/8155/29394215765_0a9fb71d55_o.jpg,0.5,0,1,0.75,325,39,https://www.flickr.com/photos/yutakaseki/29394215765,https://creativecommons.org/licenses/by/2.0/,Yutaka Seki,https://www.flickr.com/people/yutakaseki/
22712d0324d43ef2,https://c1.staticflickr.com/8/7783/29065239841_856237083c_o.jpg,0,0.25,0.75,1,898,847,https://www.flickr.com/photos/lge/29065239841,https://creativecommons.org/licenses/by/2.0/,LG\354\240\204\354\236\220,https://www.flickr.com/people/lge/
3201d10ec4dca056,https://c1.staticflickr.com/9/8335/28756723693_0d013b2d23_o.jpg,0.25,0,0.75,0.75,739,605,https://www.flickr.com/photos/wuipdesign/28756723693,https://creativecommons.org/licenses/by/2.0/,Wuipdesign,https://www.flickr.com/people/wuipdesign/
62c7958e7cd80cca,https://c1.staticflickr.com/9/8422/29506847095_d1d503ca6e_o.jpg,0,0.323327616,0.75,1,402,757,https://www.flickr.com/photos/atoach/29506847095/,https://creativecommons.org/licenses/by/2.0/,Tim Green,https://www.flickr.com/people/atoach/
12cf4de43c70273e,https://c1.staticflickr.com/9/8107/29584374652_9e00ea0c4c_o.jpg,0.608865711,0.25,1,1,815,833,https://flickr.com/42219086@N05/29584374652,https://creativecommons.org/licenses/by/2.0/,Yamaha Watercraft Group,https://www.flickr.com/people/yamahawatercraft/
56dbd7d814ef5c58,https://c1.staticflickr.com/8/7633/27183091666_8c5fc3c63a_o.jpg,0,0,0.669128508,1,254,277,https://www.flickr.com/photos/70253321@N00/27183091666,https://creativecommons.org/licenses/by/2.0/,fugzu,https://www.flickr.com/people/70253321@N00/
e91abe0f1a7a30f4,https://c1.staticflickr.com/9/8428/29430666931_e770d94da0_o.jpg,0.480130058,0,0.960260116,0.75,752,495,https://www.flickr.com/photos/omnious100/29430666931,https://creativecommons.org/licenses/by/2.0/,Arturo Hurtado,https://www.flickr.com/people/omnious100/
641d03527848417f,https://c1.staticflickr.com/6/5341/30230914936_690327db34_o.jpg,0,0.25,0.551470588,1,341,450,https://www.flickr.com/photos/happymillerman/30230914936,https://creativecommons.org/licenses/by/2.0/,happymillerman,https://www.flickr.com/people/happymillerman/
de282cea97167923,https://c1.staticflickr.com/9/8491/28883167640_a8d08d7c53_o.jpg,0,0.330871492,1,1,305,656,https://www.flickr.com/photos/52450054@N04/28883167640,https://creativecommons.org/licenses/by/2.0/,Judy Gallagher,https://www.flickr.com/people/52450054@N04/
088560551b91ceb0,https://c1.staticflickr.com/8/7287/26823150326_c79c4cf404_o.jpg,0.25,0.4375,1,1,983,797,https://www.flickr.com/photos/ewolivera/26823150326,https://creativecommons.org/licenses/by/2.0/,Edgardo W. Olivera,https://www.flickr.com/people/ewolivera/
a70b1cda0776cba6,https://c1.staticflickr.com/1/527/32735802985_cf85631809_o.jpg,0,0.25,0.5,1,143,119,https://www.flickr.com/photos/ddebold/32735802985/,https://creativecommons.org/licenses/by/2.0/,Don DeBold,https://www.flickr.com/people/ddebold/
c036b20afde859b7,https://c1.staticflickr.com/9/8254/28443278150_007ab658ba_o.jpg,0,0,0.5625,0.75,281,508,https://www.flickr.com/photos/californiadfg/28443278150/,https://creativecommons.org/licenses/by/2.0/,California Department of Fish and Wildlife,https://www.flickr.com/people/californiadfg/
5d6c4759c26bae8c,https://c1.staticflickr.com/9/8174/28972300461_1d85484b62_o.jpg,0.25,0.25,0.75,1,547,746,https://www.flickr.com/photos/30478819@N08/28972300461,https://creativecommons.org/licenses/by/2.0/,Marco Verch,https://www.flickr.com/people/30478819@N08/
3eded0a8d5f16059,https://c1.staticflickr.com/8/7448/27356260545_152e77a25a_o.jpg,0.239370079,0,1,1,100,457,https://www.flickr.com/photos/brighton/27356260545,https://creativecommons.org/licenses/by/2.0/,Jim Linwood,https://www.flickr.com/people/brighton/
9db1070b1b9f03d2,https://c1.staticflickr.com/4/3818/33059801071_2681885776_o.jpg,0,0,0.522624434,0.75,324,870,https://www.flickr.com/photos/132033298@N04/33059801071,https://creativecommons.org/licenses/by/2.0/,C. P. Ewing,https://www.flickr.com/people/132033298@N04/
e3c3f8889ac99aec,https://c1.staticflickr.com/9/8786/28331257953_f5d077c2c1_o.jpg,0,0.248713235,0.75,0.746139706,536,897,https://www.flickr.com/photos/boostsamurai/28331257953,https://creativecommons.org/licenses/by/2.0/,JAK SIE MASZ,https://www.flickr.com/people/boostsamurai/
d6d42f8a1f6b4460,https://c1.staticflickr.com/9/8230/29839990905_33b2231132_o.jpg,0.564649243,0,1,0.75,666,374,https://www.flickr.com/photos/pedrosimoes7/29839990905,https://creativecommons.org/licenses/by/2.0/,Pedro Ribeiro Sim\303\265es,https://www.flickr.com/people/pedrosimoes7/
517dc655edeaf344,https://c1.staticflickr.com/8/7309/26590993833_7b17146eda_o.jpg,0,0,0.5,0.75,430,920,https://www.flickr.com/photos/slgc/26590993833,https://creativecommons.org/licenses/by/2.0/,slgckgc,https://www.flickr.com/people/slgc/
10db986bad48a9d5,https://c1.staticflickr.com/8/7092/26592880754_0af21a54f5_o.jpg,0.25,0,1,0.75,894,134,https://www.flickr.com/photos/vertstone/26592880754,https://creativecommons.org/licenses/by/2.0/,Sunil Dass,https://www.flickr.com/people/vertstone/
17cfccd62451a233,https://c1.staticflickr.com/8/7005/27391093362_0c39bc1805_o.jpg,0.25,0.25,1,1,966,571,https://www.flickr.com/photos/rjbailey/27391093362/,https://creativecommons.org/licenses/by/2.0/,Ron Bailey,https://www.flickr.com/people/rjbailey/
212476b1b58a0cfe,https://c1.staticflickr.com/6/5349/29372567534_c17516e486_o.jpg,0.255402385,0.25,0.766207154,1,512,697,http://www.flickr.com/photos/andreboeni/29372567534/,https://creativecommons.org/licenses/by/2.0/,Andrew Bone,https://www.flickr.com/people/andreboeni/
919a6f1d23c6d05e,https://c1.staticflickr.com/6/5348/31279804625_839baf7892_o.jpg,0,0.25,0.5,1,145,983,https://www.flickr.com/photos/ddebold/31279804625,https://creativecommons.org/licenses/by/2.0/,Don DeBold,https://www.flickr.com/people/ddebold/
da4f4d6944d93ae0,https://c1.staticflickr.com/6/5260/29956436271_478885e6f4_o.jpg,0,0,0.75,1,735,779,https://www.flickr.com/photos/27665395@N05/29956436271,https://creativecommons.org/licenses/by/2.0/,Jason Lawrence,https://www.flickr.com/people/27665395@N05/
1461ed9402248ddc,https://c1.staticflickr.com/8/7699/27042345425_591120613f_o.jpg,0.25,0.25,0.75,1,514,725,https://www.flickr.com/photos/jimfischer/27042345425/,https://creativecommons.org/licenses/by/2.0/,Jim Fischer,https://www.flickr.com/people/jimfischer/
f0dcd519b5499d48,https://c1.staticflickr.com/6/5218/29421210913_9b476c8d85_o.jpg,0.230524079,0.25,0.691572238,1,664,231,https://www.flickr.com/photos/eltb/29421210913,https://creativecommons.org/licenses/by/2.0/,Catedrales e Iglesias/Cathedrals and Churches,https://www.flickr.com/people/eltb/
9a5913e0fb6d0866,https://c1.staticflickr.com/9/8795/28922147966_1362994487_o.jpg,0,0,0.5625,0.75,767,204,https://www.flickr.com/photos/londonmatt/28922147966/,https://creativecommons.org/licenses/by/2.0/,Matt Brown,https://www.flickr.com/people/londonmatt/
cfab8f880da31ad8,https://c1.staticflickr.com/1/35/31390789132_d7ab56b8eb_o.jpg,0.28125,0,0.84375,0.75,541,308,https://www.flickr.com/photos/jsjgeology/31390789132,https://creativecommons.org/licenses/by/2.0/,James St. John,https://www.flickr.com/people/jsjgeology/
17df043d369008f5,https://c1.staticflickr.com/9/8249/28958829961_fe65fb3bb9_o.jpg,0.281690141,0.25,0.845070423,1,991,802,https://www.flickr.com/photos/scotnelson/28958829961,https://creativecommons.org/licenses/by/2.0/,Scot Nelson,https://www.flickr.com/people/scotnelson/
95d6a4087f394d8b,https://c1.staticflickr.com/9/8129/28719483854_d03b5d7da2_o.jpg,0.333333333,0,1,1,750,541,https://flickr.com/96541566@N06/28719483854,https://creativecommons.org/licenses/by/2.0/,Jan Helebrant,https://www.flickr.com/people/96541566@N06/
0be391239ccba0f2,https://c1.staticflickr.com/4/3905/32853501241_fc35720ce1_o.jpg,0,0,0.7484375,1,719,996,https://www.flickr.com/photos/feeney1982/32853501241,https://creativecommons.org/licenses/by/2.0/,MK Feeney,https://www.flickr.com/people/feeney1982/
8d68931ba23fdeb7,https://c1.staticflickr.com/8/7102/27075766490_313dd1d866_o.jpg,0,0.267530488,0.75,0.802591463,842,800,https://www.flickr.com/photos/spreadshirt/27075766490,https://creativecommons.org/licenses/by/2.0/,Spreadshirt,https://www.flickr.com/people/spreadshirt/
6bff4ecb94f1f84e,https://c1.staticflickr.com/9/8347/28860027516_8f8d9bee70_o.jpg,0.257672156,0,0.773016467,0.75,859,866,https://www.flickr.com/photos/governosp/28860027516,https://creativecommons.org/licenses/by/2.0/,Governo do Estado de S\303\243o Paulo,https://www.flickr.com/people/governosp/
96fcb76927274db6,https://c1.staticflickr.com/9/8705/28851545335_aa85baa5f3_o.jpg,0.5,0.25,1,1,472,316,https://www.flickr.com/photos/quinet/28851545335,https://creativecommons.org/licenses/by/2.0/,Thomas Quine,https://www.flickr.com/people/quinet/
4de063bd5b838f11,https://c1.staticflickr.com/6/5669/30863954931_bc7e58710c_o.jpg,0.28125,0,0.84375,0.75,2,289,https://www.flickr.com/photos/tamakisono/30863954931/,https://creativecommons.org/licenses/by/2.0/,Tamaki Sono,https://www.flickr.com/people/tamakisono/
55b85f4336d9603a,https://c1.staticflickr.com/8/7245/27089308192_03759b12c3_o.jpg,0,0,1,1,880,30,https://www.flickr.com/photos/10459174@N03/27089308192/,https://creativecommons.org/licenses/by/2.0/,Fred Faulkner,https://www.flickr.com/people/10459174@N03/
f6437ed4f1b8fe23,https://c1.staticflickr.com/6/5695/31218448105_c5d0e22fd3_o.jpg,0.160367171,0,0.481101512,1,302,843,http://www.flickr.com/photos/131914450@N06/31218448105,https://creativecommons.org/licenses/by/2.0/,burgerking1975,https://www.flickr.com/people/131914450@N06/
a90d9627e2145090,https://c1.staticflickr.com/9/8059/29463573752_e27f82a1e6_o.jpg,0.510583942,0.25,1,1,426,722,https://www.flickr.com/photos/60712129@N06/29463573752/,https://creativecommons.org/licenses/by/2.0/,Dianne Lacourciere,https://www.flickr.com/people/60712129@N06/
f4bde5facfdca0c6,https://c1.staticflickr.com/1/405/32476678205_491d504f85_o.jpg,0,0,1,1,788,194,https://flickr.com/14385354@N00/32476678205,https://creativecommons.org/licenses/by/2.0/,Ungry Young Man,https://www.flickr.com/people/markusunger/
803450d936b35ebb,https://c1.staticflickr.com/8/7476/29073407732_3a52be689b_o.jpg,0.249631811,0,0.748895434,0.75,934,258,https://www.flickr.com/photos/comedynose/29073407732/,https://creativecommons.org/licenses/by/2.0/,Pete,https://www.flickr.com/people/comedynose/
fff35cdcce3cde43,https://c1.staticflickr.com/9/8463/29106205880_18aa360993_o.jpg,0,0,0.5,0.75,913,409,https://www.flickr.com/photos/davebloggs007/29106205880,https://creativecommons.org/licenses/by/2.0/,Thank you for visiting my page,https://www.flickr.com/people/davebloggs007/
b58e8d136aff5a50,https://c1.staticflickr.com/9/8188/29745896581_ff26e547ca_o.jpg,0.25,0.25,0.75,1,625,565,https://www.flickr.com/photos/fst_oeb_nrw/29745896581,https://creativecommons.org/licenses/by/2.0/,Fachstelle f\303\274r \303\226ffentliche Bibliotheken NRW,https://www.flickr.com/people/fst_oeb_nrw/
76d7e2d1bf3a31fe,https://c1.staticflickr.com/9/8072/29787724155_f733ca9146_o.jpg,0.421177267,0.25,0.842354533,1,312,732,https://www.flickr.com/photos/31031835@N08/29787724155,https://creativecommons.org/licenses/by/2.0/,John Tann,https://www.flickr.com/people/31031835@N08/
a777db736ecdfb65,https://c1.staticflickr.com/8/7324/27415463920_2958a226d7_o.jpg,0,0.128161889,1,1,326,56,https://www.flickr.com/photos/wildreturn/27415463920,https://creativecommons.org/licenses/by/2.0/,Andy Reago & Chrissy McClarren,https://www.flickr.com/people/wildreturn/
f1a6fdadaa132225,https://c1.staticflickr.com/6/5455/30574341260_ec628a854c_o.jpg,0.25,0,1,0.75,990,18,https://www.flickr.com/photos/hills_alive/30574341260,https://creativecommons.org/licenses/by/2.0/,Caroline,https://www.flickr.com/people/hills_alive/
6bea02f26beef50d,https://c1.staticflickr.com/6/5700/29664825844_e3a32c8217_o.jpg,0.249079529,0,0.747238586,0.75,709,267,https://www.flickr.com/photos/londonmatt/29664825844,https://creativecommons.org/licenses/by/2.0/,Matt Brown,https://www.flickr.com/people/londonmatt/
7b6a9bf5b175e3b2,https://c1.staticflickr.com/9/8270/30005296161_6f99755f62_o.jpg,0.372611465,0,0.74522293,0.75,558,599,https://www.flickr.com/photos/imo-un/30005296161,https://creativecommons.org/licenses/by/2.0/,International Maritime Organization,https://www.flickr.com/people/imo-un/
7c249a944594a62e,https://c1.staticflickr.com/6/5810/30483710105_e24bbc2699_o.jpg,0,0,0.5625,0.75,990,620,https://www.flickr.com/photos/verzo/30483710105,https://creativecommons.org/licenses/by/2.0/,Roberto Verzo,https://www.flickr.com/people/verzo/
5c2d823a4d30e3d5,https://c1.staticflickr.com/6/5613/30328326823_cd02f11183_o.jpg,0.248348018,0.25,0.745044053,1,718,894,https://www.flickr.com/photos/thartz00/30328326823,https://creativecommons.org/licenses/by/2.0/,likeaduck,https://www.flickr.com/people/thartz00/
fc94d8ed9eca8c51,https://c1.staticflickr.com/2/1478/26763589175_4f80c5497b_o.jpg,0,0,0.666666667,1,390,584,https://www.flickr.com/photos/stevendepolo/26763589175,https://creativecommons.org/licenses/by/2.0/,Steven Depolo,https://www.flickr.com/people/stevendepolo/
73728c249317ccb9,https://c1.staticflickr.com/1/623/31659729526_41139a4893_o.jpg,0.28125,0,0.84375,0.75,848,145,http://www.flickr.com/photos/mohit_s/31659729526/,https://creativecommons.org/licenses/by/2.0/,Mohit S,https://www.flickr.com/people/mohit_s/
0b1d45bd9ab1064e,https://c1.staticflickr.com/9/8272/29868746026_7a9165f2d9_o.jpg,0,0,0.666666667,1,561,563,https://www.flickr.com/photos/jill_carlson/29868746026,https://creativecommons.org/licenses/by/2.0/,Jill Carlson (jillcarlson.org),https://www.flickr.com/people/jill_carlson/
4b52fd42977215b9,https://c1.staticflickr.com/8/7555/27346942261_e7b059637c_o.jpg,0,0,0.5625,0.75,901,627,https://www.flickr.com/photos/rusty_clark/27346942261,https://creativecommons.org/licenses/by/2.0/,Rusty Clark ~ 100K Photos,https://www.flickr.com/people/rusty_clark/
c27e3bde18fba21b,https://c1.staticflickr.com/6/5127/30107077575_dce955ff33_o.jpg,0,0.25,0.492324561,1,323,128,https://www.flickr.com/photos/postmanpetecoluk/30107077575,https://creativecommons.org/licenses/by/2.0/,postman.pete,https://www.flickr.com/people/postmanpetecoluk/
5dbfff56258cf9e6,https://c1.staticflickr.com/1/613/31473791884_176af43beb_o.jpg,0,0.262273414,0.75,0.786820242,318,385,https://flickr.com/52450054@N04/31473791884,https://creativecommons.org/licenses/by/2.0/,Judy Gallagher,https://www.flickr.com/people/52450054@N04/
c47ca11294a9aefe,https://c1.staticflickr.com/9/8724/28243588105_0e8673ea4b_o.jpg,0.25,0.25,1,0.75,547,119,https://www.flickr.com/photos/80037792@N03/28243588105/,https://creativecommons.org/licenses/by/2.0/,Adri\303\241n Castillo Rivera,https://www.flickr.com/people/80037792@N03/
97917829607b6189,https://c1.staticflickr.com/1/435/31542814264_1481334d51_o.jpg,0.25,0,0.75,0.75,859,660,https://www.flickr.com/photos/72821066@N04/31542814264,https://creativecommons.org/licenses/by/2.0/,Kathleen,https://www.flickr.com/people/72821066@N04/
d386396825739960,https://c1.staticflickr.com/6/5671/31045268386_89505e1441_o.jpg,0.514898256,0,1,0.75,854,227,https://www.flickr.com/photos/13476480@N07/31045268386,https://creativecommons.org/licenses/by/2.0/,manhhai,https://www.flickr.com/people/13476480@N07/
44fa09bc5f8e69a5,https://c1.staticflickr.com/8/7556/27540902503_548da9039e_o.jpg,0.4108,0,1,0.75,304,990,https://www.flickr.com/photos/gails_pictures/27540902503,https://creativecommons.org/licenses/by/2.0/,gailhampshire,https://www.flickr.com/people/gails_pictures/
70db5a1689f89129,https://c1.staticflickr.com/8/7368/28008608932_93cb96fee0_o.jpg,0.238832853,0,0.716498559,0.75,434,472,https://www.flickr.com/photos/familymwr/28008608932/,https://creativecommons.org/licenses/by/2.0/,U.S. Army,https://www.flickr.com/people/familymwr/
89d60f53d478c4f7,https://c1.staticflickr.com/8/7303/26926132240_65cf222cf4_o.jpg,0,0.25,0.5,1,668,435,https://www.flickr.com/photos/codnewsroom/26926132240,https://creativecommons.org/licenses/by/2.0/,COD Newsroom,https://www.flickr.com/people/codnewsroom/
d531a31add433f46,https://c1.staticflickr.com/9/8621/28763062545_b79f4f72ff_o.jpg,0.5,0.25,1,1,764,769,https://www.flickr.com/photos/rusty_clark/28763062545,https://creativecommons.org/licenses/by/2.0/,Rusty Clark ~ 100K Photos,https://www.flickr.com/people/rusty_clark/
4d0c0f35a0c00bdc,https://c1.staticflickr.com/8/7262/26732253551_7b396172cf_o.jpg,0,0,0.75,0.636439268,680,432,https://www.flickr.com/photos/kayadams/26732253551,https://creativecommons.org/licenses/by/2.0/,Kay Adams,https://www.flickr.com/people/kayadams/
33197fa6ae88508a,https://c1.staticflickr.com/9/8032/29583923580_143f4756d0_o.jpg,0.398058252,0.25,1,1,848,30,https://www.flickr.com/photos/zachievenor/29583923580,https://creativecommons.org/licenses/by/2.0/,Zachi Evenor,https://www.flickr.com/people/zachievenor/
78059d1afd7b9fea,https://c1.staticflickr.com/9/8268/28771428103_98f31c968c_o.jpg,0,0,1,1,58,248,https://www.flickr.com/photos/brutchersp/28771428103,https://creativecommons.org/licenses/by/2.0/,Sam Brutcher,https://www.flickr.com/people/brutchersp/
542c07e8bf8e283c,https://c1.staticflickr.com/1/530/32275825531_4a40f15002_o.jpg,0,0,0.5625,0.75,145,706,https://flickr.com/77110886@N07/32275825531,https://creativecommons.org/licenses/by/2.0/,AmishRob,https://www.flickr.com/people/77110886@N07/
e8c99e0220ab46d2,https://c1.staticflickr.com/8/7408/27465191295_e5f6865548_o.jpg,0,0.244318182,1,0.732954545,591,535,https://www.flickr.com/photos/50019407@N03/27465191295,https://creativecommons.org/licenses/by/2.0/,striegel,https://www.flickr.com/people/50019407@N03/
c755f3b0f89028fc,https://c1.staticflickr.com/6/5656/30912005906_eeb50d4284_o.jpg,0.4375,0,1,0.75,566,827,https://www.flickr.com/photos/railwayofaustralia/30912005906/,https://creativecommons.org/licenses/by/2.0/,Railways of Australia by Daryle Phillips,https://www.flickr.com/people/railwayofaustralia/
76db169867bf2e9d,https://c1.staticflickr.com/6/5759/30161761356_e4053ff3fb_o.jpg,0.25,0,1,0.75,964,908,https://flickr.com/93362968@N00/30161761356,https://creativecommons.org/licenses/by/2.0/,Ruben,https://www.flickr.com/people/surfzone/
784232355d49601b,https://c1.staticflickr.com/1/624/31694410765_dea6857dfb_o.jpg,0.321273517,0,0.96382055,1,327,161,https://www.flickr.com/photos/42244964@N03/31694410765,https://creativecommons.org/licenses/by/2.0/,Frank Vassen,https://www.flickr.com/people/42244964@N03/
e99ceff3e420ef95,https://c1.staticflickr.com/8/7381/27954856402_191862c411_o.jpg,0.27818818,0.25,0.834564541,1,831,768,https://www.flickr.com/photos/photographingtravis/27954856402/,https://creativecommons.org/licenses/by/2.0/,Travis Wise,https://www.flickr.com/people/photographingtravis/
23955512cd0e1191,https://c1.staticflickr.com/8/7578/30160381445_b3e6087902_o.jpg,0,0.25,0.497426471,1,476,742,https://www.flickr.com/photos/kylemcdonald/30160381445,https://creativecommons.org/licenses/by/2.0/,Kyle McDonald,https://www.flickr.com/people/kylemcdonald/
d6eac6858474111c,https://c1.staticflickr.com/8/7320/27399110256_d3fe95b790_o.jpg,0.248826291,0,1,1,323,250,https://www.flickr.com/photos/j_benson/27399110256/,https://creativecommons.org/licenses/by/2.0/,John Benson,https://www.flickr.com/people/j_benson/
8d90c523b27410a7,https://c1.staticflickr.com/8/7364/27529300064_90409b557b_o.jpg,0,0.491827637,0.75,1,321,563,https://www.flickr.com/photos/postmanpetecoluk/27529300064,https://creativecommons.org/licenses/by/2.0/,postman.pete,https://www.flickr.com/people/postmanpetecoluk/
5cf72b48fdf5e419,https://c1.staticflickr.com/6/5718/30045803555_c7a2fba567_o.jpg,0.495552732,0,0.991105464,1,630,744,https://www.flickr.com/photos/135366503@N05/30045803555,https://creativecommons.org/licenses/by/2.0/,CLAUDIA DEA,https://www.flickr.com/people/135366503@N05/
228fec6cab5f560d,https://c1.staticflickr.com/1/668/31760002531_3b7716366a_o.jpg,0.333333333,0,1,1,974,931,https://flickr.com/39136124@N00/31760002531,https://creativecommons.org/licenses/by/2.0/,Paul Asman and Jill Lenoble,https://www.flickr.com/people/pauljill/
e7b61bec5e4ca40e,https://c1.staticflickr.com/6/5663/30514982830_d4031e75fe_o.jpg,0,0.333049404,0.75,1,324,674,https://flickr.com/44465748@N00/30514982830,https://creativecommons.org/licenses/by/2.0/,benet2006,https://www.flickr.com/people/benetd/
d3551db0b83c8fc0,https://c1.staticflickr.com/9/8310/29174628816_300ec9d85c_o.jpg,0.5,0.25,1,1,618,324,https://www.flickr.com/photos/dccentralkitchen/29174628816,https://creativecommons.org/licenses/by/2.0/,DC Central Kitchen,https://www.flickr.com/people/dccentralkitchen/
c7d0c73d636300f5,https://c1.staticflickr.com/4/3390/3194974577_b7573f6c32_o.jpg,0.489195231,0.25,1,1,830,801,https://www.flickr.com/photos/davidwilson1949/3194974577,https://creativecommons.org/licenses/by/2.0/,David Wilson,https://www.flickr.com/people/davidwilson1949/
61ed2594a0524631,https://c1.staticflickr.com/8/7456/27590651131_7c9941b3ce_o.jpg,0,0.25,0.5,1,472,996,https://www.flickr.com/photos/prayitnophotography/27590651131,https://creativecommons.org/licenses/by/2.0/,Prayitno / Thank you for (12 millions +) view,https://www.flickr.com/people/prayitnophotography/
89f48bcf97aa6600,https://c1.staticflickr.com/9/8478/29134440636_664709aa0b_o.jpg,0.25,0.25,0.75,1,418,70,https://www.flickr.com/photos/pavdw/29134440636,https://creativecommons.org/licenses/by/2.0/,Paul VanDerWerf,https://www.flickr.com/people/pavdw/
ed786d792c4309a4,https://c1.staticflickr.com/8/7630/27108493571_721c8b15ac_o.jpg,0.25,0,1,0.75,499,962,https://www.flickr.com/photos/jjeff/27108493571,https://creativecommons.org/licenses/by/2.0/,Jeff Robbins,https://www.flickr.com/people/jjeff/
9fe19d5c6dab83a3,https://c1.staticflickr.com/8/7507/29079497195_c97c2f18c1_o.jpg,0.5,0,1,0.75,455,805,https://www.flickr.com/photos/stevendepolo/29079497195,https://creativecommons.org/licenses/by/2.0/,Steven Depolo,https://www.flickr.com/people/stevendepolo/
d5d5f843f100328c,https://c1.staticflickr.com/8/7366/26927066371_055fb093dc_o.jpg,0.25,0.25,1,1,886,538,https://www.flickr.com/photos/garlandcannon/26927066371,https://creativecommons.org/licenses/by/2.0/,garlandcannon,https://www.flickr.com/people/garlandcannon/
789417c091011f53,https://c1.staticflickr.com/6/5632/30859118166_ac1328ed72_o.jpg,0.5,0.25,1,1,345,177,https://flickr.com/145232592@N06/30859118166,https://creativecommons.org/licenses/by/2.0/,Martin7d2,https://www.flickr.com/people/martin7d2/
e648427e38e80ff8,https://c1.staticflickr.com/8/7440/27289001152_11922d530c_o.jpg,0.466894977,0.25,1,1,888,617,https://www.flickr.com/photos/marinelson/27289001152,https://creativecommons.org/licenses/by/2.0/,Marinelson Almeida - Traveling through Brazil,https://www.flickr.com/people/marinelson/
1478a0fc99a988db,https://c1.staticflickr.com/8/7775/29139964033_0509a1d34c_o.jpg,0.25,0.28125,1,0.84375,776,928,https://www.flickr.com/photos/juggernautco/29139964033,https://creativecommons.org/licenses/by/2.0/,Daniel X. O'Neil,https://www.flickr.com/people/juggernautco/
e758de2cbb3d10a0,https://c1.staticflickr.com/6/5341/30948537862_3f3461e1a1_o.jpg,0,0.25,0.63875,1,305,905,https://www.flickr.com/photos/gails_pictures/30948537862,https://creativecommons.org/licenses/by/2.0/,gailhampshire,https://www.flickr.com/people/gails_pictures/
8af30e5c3fa48a08,https://c1.staticflickr.com/8/7646/29079347226_a8454b4835_o.jpg,0.249079529,0.25,0.747238586,1,696,71,https://www.flickr.com/photos/brandedbulltank/29079347226/,https://creativecommons.org/licenses/by/2.0/,Tank,https://www.flickr.com/people/brandedbulltank/
38287d2e5a4a9a57,https://c1.staticflickr.com/9/8518/28286972964_4a723a160a_o.jpg,0.25,0.25,1,1,960,798,https://www.flickr.com/photos/g4gti/28286972964/,https://creativecommons.org/licenses/by/2.0/,Ryohei Noda,https://www.flickr.com/people/g4gti/
c6e0d2ab3bbf4a3e,https://c1.staticflickr.com/8/7053/27295097944_149d29443d_o.jpg,0.28125,0,0.84375,0.75,706,838,https://www.flickr.com/photos/davidwilson1949/27295097944,https://creativecommons.org/licenses/by/2.0/,David Wilson,https://www.flickr.com/people/davidwilson1949/
4cccb215bd60b3c3,https://c1.staticflickr.com/2/1476/26151802513_eba98c8b71_o.jpg,0.333333333,0,1,1,33,341,https://www.flickr.com/photos/briangratwicke/26151802513,https://creativecommons.org/licenses/by/2.0/,Brian Gratwicke,https://www.flickr.com/people/briangratwicke/
9a49001b63903f72,https://c1.staticflickr.com/9/8320/29938183125_fbbd772391_o.jpg,0.333333333,0,1,1,769,804,https://www.flickr.com/photos/abaecherliphotography/29938183125/,https://creativecommons.org/licenses/by/2.0/,Samuel Ab\303\244cherli,https://www.flickr.com/people/abaecherliphotography/
1cbae41091a750dc,https://c1.staticflickr.com/8/7437/27918206525_1045d33569_o.jpg,0,0.25,0.561328125,1,473,814,http://www.flickr.com/16915761@N08/27918206525,https://creativecommons.org/licenses/by/2.0/,Gordon Watt,https://www.flickr.com/people/gordon_watt/
de40907c1e2c5515,https://c1.staticflickr.com/8/7717/26258443973_8a326bac94_o.jpg,0,0,1,0.75,629,486,https://www.flickr.com/photos/yutakaseki/26258443973,https://creativecommons.org/licenses/by/2.0/,Yutaka Seki,https://www.flickr.com/people/yutakaseki/
446f75fdea0e1da0,https://c1.staticflickr.com/9/8197/28459775774_861c11bd49_o.jpg,0.28125,0,0.84375,0.75,922,201,https://www.flickr.com/photos/pussreboots/28459775774/,https://creativecommons.org/licenses/by/2.0/,caligula1995,https://www.flickr.com/people/pussreboots/
059da9a174262427,https://c1.staticflickr.com/8/7529/26612408253_d5156925ff_o.jpg,0,0.25,0.521428571,1,254,630,https://www.flickr.com/photos/70253321@N00/26612408253/,https://creativecommons.org/licenses/by/2.0/,fugzu,https://www.flickr.com/people/70253321@N00/
35c344ca0584ba14,https://c1.staticflickr.com/6/5759/31004746922_f545e4c9e3_o.jpg,0.504405286,0,1,0.75,688,831,https://www.flickr.com/photos/eltb/31004746922,https://creativecommons.org/licenses/by/2.0/,Catedrales e Iglesias/Cathedrals and Churches,https://www.flickr.com/people/eltb/
c335ce88293384f2,https://c1.staticflickr.com/8/7345/27701978545_2cf121bede_o.jpg,0,0,0.75,1,735,629,https://www.flickr.com/photos/27665395@N05/27701978545,https://creativecommons.org/licenses/by/2.0/,Jason Lawrence,https://www.flickr.com/people/27665395@N05/
daa6404780b1af27,https://c1.staticflickr.com/6/5785/29921098450_5016da1899_o.jpg,0.25,0.25,0.75,1,638,999,https://www.flickr.com/photos/bazzadarambler/29921098450,https://creativecommons.org/licenses/by/2.0/,bazzadarambler,https://www.flickr.com/people/bazzadarambler/
446b24f903b488fc,https://c1.staticflickr.com/6/5521/31389531466_ba559c04c8_o.jpg,0,0,0.435350757,0.75,144,839,https://www.flickr.com/photos/winnu/31389531466/,https://creativecommons.org/licenses/by/2.0/,Nigel,https://www.flickr.com/people/winnu/
d7ffed8f21024a14,https://c1.staticflickr.com/9/8728/28249502800_8a99581af4_o.jpg,0.25,0.25,0.75,1,752,922,https://www.flickr.com/photos/42220226@N07/28249502800,https://creativecommons.org/licenses/by/2.0/,Sicnag,https://www.flickr.com/people/42220226@N07/
5efeca6c4c233f01,https://c1.staticflickr.com/6/5500/31284538395_f1ef2882f9_o.jpg,0.48619186,0,0.972383721,0.75,761,464,https://www.flickr.com/photos/lge/31284538395,https://creativecommons.org/licenses/by/2.0/,LG\354\240\204\354\236\220,https://www.flickr.com/people/lge/
7d599306068f4594,https://c1.staticflickr.com/8/7715/27614734306_5cd65c4100_o.jpg,0.4375,0.25,1,1,717,514,https://www.flickr.com/photos/142136365@N08/27614734306,https://creativecommons.org/licenses/by/2.0/,Sery Content Development MT,https://www.flickr.com/people/142136365@N08/
67a52d9155241752,https://c1.staticflickr.com/9/8571/27757091954_a8b6697969_o.jpg,0,0.25,0.5625,1,830,420,https://www.flickr.com/photos/raver_mikey/27757091954,https://creativecommons.org/licenses/by/2.0/,Mikey,https://www.flickr.com/people/raver_mikey/
dc12a25cc85ee9cf,https://c1.staticflickr.com/6/5220/29764054890_0309cd8fb8_o.jpg,0,0,0.374521073,0.75,647,896,http://www.flickr.com/photos/vitroids/29764054890/,https://creativecommons.org/licenses/by/2.0/,Masakazu Matsumoto,https://www.flickr.com/people/vitroids/
0d6463e9a7ef6185,https://c1.staticflickr.com/9/8147/28957674191_b862ba9c0c_o.jpg,0,0,0.66226138,1,771,786,https://www.flickr.com/photos/spera-designerschuhe/28957674191,https://creativecommons.org/licenses/by/2.0/,"SPERA.de Designerschuhe, Taschen und Accessoires",https://www.flickr.com/people/spera-designerschuhe/
af543b5f19ed1b1d,https://c1.staticflickr.com/2/1659/26658174432_76a1fc6cd7_o.jpg,0.28125,0,0.84375,0.75,40,391,https://www.flickr.com/photos/briangratwicke/26658174432,https://creativecommons.org/licenses/by/2.0/,Brian Gratwicke,https://www.flickr.com/people/briangratwicke/
a7151de51c2f1d0b,https://c1.staticflickr.com/9/8622/27804271193_73fe11b408_o.jpg,0.25,0.340254237,1,1,345,214,https://www.flickr.com/photos/jared422/27804271193,https://creativecommons.org/licenses/by/2.0/,Jared,https://www.flickr.com/people/jared422/
c5c9d17672ff88ce,https://c1.staticflickr.com/8/7654/27071795905_8908bd10e9_o.jpg,0.25,0,1,0.561328125,458,266,https://www.flickr.com/photos/140473922@N07/27071795905/,https://creativecommons.org/licenses/by/2.0/,malnasfalu,https://www.flickr.com/people/140473922@N07/
5bdb8268eadf57d8,https://c1.staticflickr.com/6/5765/30333126152_38071946f0_o.jpg,0,0,0.666666667,1,852,968,https://www.flickr.com/photos/37491467@N07/30333126152,https://creativecommons.org/licenses/by/2.0/,Say_No_To_Turtles,https://www.flickr.com/people/37491467@N07/
80177288cda51d95,https://c1.staticflickr.com/1/712/32401234622_f7ec1efbe5_o.jpg,0,0,0.75,1,641,605,https://flickr.com/57868312@N00/32401234622,https://creativecommons.org/licenses/by/2.0/,Matt Brown,https://www.flickr.com/people/londonmatt/
5b60477a29c7ef81,https://c1.staticflickr.com/1/648/32597389405_80e847a182_o.jpg,0.333333333,0,1,1,416,700,http://www.flickr.com/photos/bexwalton/32597389405/,https://creativecommons.org/licenses/by/2.0/,Bex Walton,https://www.flickr.com/people/bexwalton/
da7e65bc80814f37,https://c1.staticflickr.com/6/5337/30469224383_6aa5c4a26b_o.jpg,0.5,0,1,0.75,788,603,https://www.flickr.com/photos/aloha75/30469224383/,https://creativecommons.org/licenses/by/2.0/,Sam Howzit,https://www.flickr.com/people/aloha75/
4aeb33c9e565a201,https://c1.staticflickr.com/8/7631/27704602521_784d784312_o.jpg,0,0,0.735294118,1,98,840,https://www.flickr.com/photos/7326810@N08/27704602521,https://creativecommons.org/licenses/by/2.0/,Jean,https://www.flickr.com/people/7326810@N08/
19d43f8204d3183d,https://c1.staticflickr.com/8/7100/27097357596_2e5f7f8ddb_o.jpg,0,0,0.75,0.646812081,985,378,https://www.flickr.com/photos/atoach/27097357596,https://creativecommons.org/licenses/by/2.0/,Tim Green,https://www.flickr.com/people/atoach/
2b741c5c635a7295,https://c1.staticflickr.com/9/8870/28112675323_f9aa3a3600_o.jpg,0,0,0.681073025,1,108,634,https://www.flickr.com/photos/flowcomm/28112675323,https://creativecommons.org/licenses/by/2.0/,flowcomm,https://www.flickr.com/people/flowcomm/
398720b8f19d5b84,https://c1.staticflickr.com/1/502/32384871825_3a1708f568_o.jpg,0.5,0.25,1,1,697,700,https://flickr.com/146625745@N08/32384871825,https://creativecommons.org/licenses/by/2.0/,home thods,https://www.flickr.com/people/146625745@N08/
ab8329c28d8538c3,https://c1.staticflickr.com/6/5507/31042117711_9b835b691b_o.jpg,0.481981982,0.25,1,1,469,13,https://www.flickr.com/photos/fernando680411/31042117711,https://creativecommons.org/licenses/by/2.0/,Nelson Fernando Sotelo Castro,https://www.flickr.com/people/fernando680411/
348618ddbde3a39c,https://c1.staticflickr.com/9/8604/27892878974_931dc78b34_o.jpg,0,0,0.75,0.535877863,386,460,https://www.flickr.com/photos/bvi4092/27892878974,https://creativecommons.org/licenses/by/2.0/,bvi4092,https://www.flickr.com/people/bvi4092/
d0029b3675b792ae,https://c1.staticflickr.com/9/8739/28789525922_b9ea40444c_o.jpg,0.322236181,0,0.966708543,0.75,790,902,https://www.flickr.com/photos/84906483@N08/28789525922/,https://creativecommons.org/licenses/by/2.0/,spinster cardigan,https://www.flickr.com/people/84906483@N08/
69854b68476d5068,https://c1.staticflickr.com/9/8239/29052269695_ba56b1b270_o.jpg,0.498159057,0,0.996318115,0.75,893,733,https://www.flickr.com/photos/zigazou76/29052269695,https://creativecommons.org/licenses/by/2.0/,Fr\303\251d\303\251ric BISSON,https://www.flickr.com/people/zigazou76/
4bdb561770b52424,https://c1.staticflickr.com/8/7429/27735562062_14d90e477c_o.jpg,0.25,0.25,0.75,1,147,184,https://www.flickr.com/photos/blachswan/27735562062,https://creativecommons.org/licenses/by/2.0/,Ed Dunens,https://www.flickr.com/people/blachswan/
a92ab9e5fb9c5d64,https://c1.staticflickr.com/9/8121/29350360356_21b52b834f_o.jpg,0.500736377,0.25,1,1,629,457,https://www.flickr.com/photos/glynlowe/29350360356,https://creativecommons.org/licenses/by/2.0/,www.GlynLowe.com,https://www.flickr.com/people/glynlowe/
8c6edf1ddfb61102,https://c1.staticflickr.com/8/7310/27095263593_6c217dcf2d_o.jpg,0.503303965,0,1,0.75,889,123,https://www.flickr.com/photos/sybarite48/27095263593,https://creativecommons.org/licenses/by/2.0/,Daniel Jolivet,https://www.flickr.com/people/sybarite48/
c135b139d293f7f2,https://c1.staticflickr.com/6/5511/31483820115_746e4778f1_o.jpg,0.324925816,0,1,1,347,491,https://www.flickr.com/photos/13476480@N07/31483820115,https://creativecommons.org/licenses/by/2.0/,manhhai,https://www.flickr.com/people/13476480@N07/
7d2e9b03ec1b630b,https://c1.staticflickr.com/8/7391/27341486272_663d67f419_o.jpg,0.25,0,0.75,0.75,401,535,https://www.flickr.com/photos/joi/27341486272,https://creativecommons.org/licenses/by/2.0/,Joi Ito,https://www.flickr.com/people/joi/
29fe8d653950a631,https://c1.staticflickr.com/8/7694/26743914583_5a94c79b35_o.jpg,0,0,0.5,0.75,80,542,https://www.flickr.com/photos/quinet/26743914583/,https://creativecommons.org/licenses/by/2.0/,Thomas Quine,https://www.flickr.com/people/quinet/
d4c817db6be62b71,https://c1.staticflickr.com/1/611/32446502452_f6b691f7cc_o.jpg,0.375178317,0,1,1,95,164,https://www.flickr.com/photos/tdlucas5000/32446502452,https://creativecommons.org/licenses/by/2.0/,tdlucas5000,https://www.flickr.com/people/tdlucas5000/
1e77361718213a43,https://c1.staticflickr.com/1/606/32230247896_6f7d356e7e_o.jpg,0,0,1,1,440,435,https://flickr.com/73833659@N00/32230247896,https://creativecommons.org/licenses/by/2.0/,MK Feeney,https://www.flickr.com/people/feeney1982/
6711e27733cfd050,https://c1.staticflickr.com/6/5510/31404867966_99715bd367_o.jpg,0.435350757,0.25,0.870701513,1,718,733,https://www.flickr.com/photos/dok1/31404867966,https://creativecommons.org/licenses/by/2.0/,Don O'Brien,https://www.flickr.com/people/dok1/
df874264566c58a9,https://c1.staticflickr.com/8/7319/27496297684_111a2f5a16_o.jpg,0.25,0.25,1,1,742,152,https://flickr.com/60944636@N00/27496297684,https://creativecommons.org/licenses/by/2.0/,el cajon yacht club,https://www.flickr.com/people/el_cajon_yacht_club/
67c0339b1dfda5f6,https://c1.staticflickr.com/6/5196/29898630576_fceec38d6a_o.jpg,0,0.25,0.499263623,1,558,496,https://www.flickr.com/photos/thejointstaff/29898630576,https://creativecommons.org/licenses/by/2.0/,Chairman of the Joint Chiefs of Staff,https://www.flickr.com/people/thejointstaff/
abd121ef53a69ef8,https://c1.staticflickr.com/8/7724/27965730726_4baf0c6722_o.jpg,0,0,0.658629442,0.75,240,335,https://www.flickr.com/photos/megs_pics/27965730726/,https://creativecommons.org/licenses/by/2.0/,Megan Cole,https://www.flickr.com/people/megs_pics/
5021e7da00bf43b2,https://c1.staticflickr.com/6/5500/31195547582_09c4533c1c_o.jpg,0.25,0.25,1,1,480,937,https://flickr.com/96774554@N03/31195547582,https://creativecommons.org/licenses/by/2.0/,Wheels ON,https://www.flickr.com/people/96774554@N03/
ebdfdcba5dc3b72a,https://c1.staticflickr.com/1/422/32445585326_8074f13658_o.jpg,0,0,0.5,0.75,868,600,https://www.flickr.com/photos/greggjerdingen/32445585326/,https://creativecommons.org/licenses/by/2.0/,Greg Gjerdingen,https://www.flickr.com/people/greggjerdingen/
68274b8293271807,https://c1.staticflickr.com/8/7281/27344963241_0feb45e01d_o.jpg,0,0.25,0.499263623,1,834,579,https://www.flickr.com/photos/ministreiodadefesa/27344963241,https://creativecommons.org/licenses/by/2.0/,Minist\303\251rio da Defesa,https://www.flickr.com/people/ministreiodadefesa/
a84ead15406596ce,https://c1.staticflickr.com/9/8300/29557884001_05493785a6_o.jpg,0,0.25,0.5,1,480,937,https://www.flickr.com/photos/concavowheels/29557884001,https://creativecommons.org/licenses/by/2.0/,CONCAVO WHEELS,https://www.flickr.com/people/concavowheels/
5d1df4748743d42e,https://c1.staticflickr.com/8/7368/27924672426_3fde6b8850_o.jpg,0.25,0.436619718,1,1,964,322,https://www.flickr.com/photos/dalecruse/27924672426,https://creativecommons.org/licenses/by/2.0/,Dale Cruse,https://www.flickr.com/people/dalecruse/
16ff75228179469c,https://c1.staticflickr.com/6/5564/29957754894_f57a1c39f2_o.jpg,0.502573529,0.25,1,1,228,386,https://flickr.com/32234827@N03/29957754894,https://creativecommons.org/licenses/by/2.0/,Dick Thompson,https://www.flickr.com/people/dick-thompson-sandian/
6e840c209f5733d5,https://c1.staticflickr.com/9/8596/28375656583_c817d204c3_o.jpg,0,0,0.75,0.561328125,442,750,https://www.flickr.com/photos/cogdog/28375656583,https://creativecommons.org/licenses/by/2.0/,Alan Levine,https://www.flickr.com/people/cogdog/
16bbe588e0ecc6ab,https://c1.staticflickr.com/8/7078/26813986145_f515146bfa_o.jpg,0.482608696,0,0.965217391,0.75,142,168,https://www.flickr.com/photos/79452129@N02/26813986145,https://creativecommons.org/licenses/by/2.0/,Fyn Kynd Photography,https://www.flickr.com/people/79452129@N02/
46b657df12fd7c26,https://c1.staticflickr.com/8/7129/27258007632_658fac681c_o.jpg,0,0.25,0.5625,1,284,724,https://www.flickr.com/photos/akras/27258007632/,https://creativecommons.org/licenses/by/2.0/,Andrey,https://www.flickr.com/people/akras/
bc7dff0960bb3335,https://c1.staticflickr.com/8/7616/28648009596_6e65ac7ace_o.jpg,0,0.260752688,0.75,1,443,765,https://www.flickr.com/photos/atoach/28648009596/,https://creativecommons.org/licenses/by/2.0/,Tim Green,https://www.flickr.com/people/atoach/
128fca690a11f68c,https://c1.staticflickr.com/8/7369/26875470084_43357ac827_o.jpg,0.250923191,0.25,0.752769572,1,98,785,https://www.flickr.com/photos/quinet/26875470084,https://creativecommons.org/licenses/by/2.0/,Thomas Quine,https://www.flickr.com/people/quinet/
ed9b2813b9245e52,https://c1.staticflickr.com/9/8770/29809879405_c8cf2a2b31_o.jpg,0,0,0.5,0.75,880,676,https://www.flickr.com/photos/konstantinti/29809879405,https://creativecommons.org/licenses/by/2.0/,Konstantin Tilberg,https://www.flickr.com/people/konstantinti/
a187afb98f295057,https://c1.staticflickr.com/1/319/31741319460_db1f31d4b9_o.jpg,0,0,0.5625,0.75,121,755,https://www.flickr.com/photos/jsjgeology/31741319460,https://creativecommons.org/licenses/by/2.0/,James St. John,https://www.flickr.com/people/jsjgeology/
d2d2b255935f0aae,https://c1.staticflickr.com/6/5563/30545415915_150b5097e6_o.jpg,0,0,0.75,1,948,432,https://www.flickr.com/photos/torsten-behrens/30545415915/in/photostream/,https://creativecommons.org/licenses/by/2.0/,Torsten Behrens,https://www.flickr.com/people/torsten-behrens/
4d008626b4b68665,https://c1.staticflickr.com/1/296/32309427086_5dcd538057_o.jpg,0.4375,0.25,1,1,108,780,https://flickr.com/21203533@N00/32309427086,https://creativecommons.org/licenses/by/2.0/,Jim G,https://www.flickr.com/people/jimg944/
10bc8784a5eb8843,https://c1.staticflickr.com/6/5582/30724498173_0e082b8ff0_o.jpg,0.488702624,0,0.977405248,0.75,744,210,https://www.flickr.com/photos/13476480@N07/30724498173,https://creativecommons.org/licenses/by/2.0/,manhhai,https://www.flickr.com/people/13476480@N07/
77ac8bf95825dfcc,https://c1.staticflickr.com/8/7259/26898012321_a3265271dd_o.jpg,0.248713235,0,0.746139706,0.75,635,728,https://www.flickr.com/photos/shankaronline/26898012321,https://creativecommons.org/licenses/by/2.0/,shankar s.,https://www.flickr.com/people/shankaronline/
5c8bcfa0dbb246ab,https://c1.staticflickr.com/8/7728/26215432693_2ee23efc4d_o.jpg,0.234375,0.25,0.703125,1,818,581,https://flickr.com/123760891@N03/26215432693,https://creativecommons.org/licenses/by/2.0/,Automobile Italia,https://www.flickr.com/people/automobileitalia/
afb0233b2e0545c4,https://c1.staticflickr.com/9/8439/29240681086_52945bd07d_o.jpg,0.333333333,0,1,1,581,959,https://www.flickr.com/photos/dalbera/29240681086,https://creativecommons.org/licenses/by/2.0/,Jean-Pierre Dalb\303\251ra,https://www.flickr.com/people/dalbera/
1bb5f1337dfb1edd,https://c1.staticflickr.com/1/589/32214674481_5a087370d6_o.jpg,0.25,0.405546624,1,1,641,293,https://flickr.com/13194817@N00/32214674481,https://creativecommons.org/licenses/by/2.0/,F Delventhal,https://www.flickr.com/people/krossbow/
a3c4dd88edacb575,https://c1.staticflickr.com/1/561/31438357361_6a749db0f2_o.jpg,0,0.25,0.75,1,400,351,http://www.flickr.com/photos/condominiocriativo/31438357361/,https://creativecommons.org/licenses/by/2.0/,Condom\303\255nio Criativo,https://www.flickr.com/people/condominiocriativo/
64ed3f0e8a2dc320,https://c1.staticflickr.com/1/323/31117919653_3c5225af88_o.jpg,0.555632823,0,1,0.75,653,410,https://flickr.com/42310076@N04/31117919653,https://creativecommons.org/licenses/by/2.0/,Chairman of the Joint Chiefs of Staff,https://www.flickr.com/people/thejointstaff/
d25df1a8259d3fdf,https://c1.staticflickr.com/6/5676/30846111770_bc0995d221_o.jpg,0.248826291,0,1,1,161,833,https://www.flickr.com/photos/adactio/30846111770,https://creativecommons.org/licenses/by/2.0/,Jeremy Keith,https://www.flickr.com/people/adactio/
184a160b32ff4c72,https://c1.staticflickr.com/8/7111/26820702803_77558c6aba_o.jpg,0.328216374,0,0.984649123,1,518,717,https://www.flickr.com/photos/paytonc/26820702803,https://creativecommons.org/licenses/by/2.0/,Payton Chung,https://www.flickr.com/people/paytonc/
4f722cab5573a5fb,https://c1.staticflickr.com/8/7567/28064754896_4c6440e3e0_o.jpg,0.28125,0,0.84375,0.75,885,392,https://www.flickr.com/photos/jdlasica/28064754896/,https://creativecommons.org/licenses/by/2.0/,JD Lasica,https://www.flickr.com/people/jdlasica/
1b546695167d3f6e,https://c1.staticflickr.com/6/5768/30206052140_ae3086703e_o.jpg,0.436619718,0,1,0.75,960,837,https://www.flickr.com/photos/kudumomo/30206052140/,https://creativecommons.org/licenses/by/2.0/,momo,https://www.flickr.com/people/kudumomo/
6a940d1bf69f1d10,https://c1.staticflickr.com/9/8122/29786339486_cf9f752823_o.jpg,0,0.187296417,1,1,558,433,https://www.flickr.com/photos/southbeachcars/29786339486/,https://creativecommons.org/licenses/by/2.0/,Phillip Pessar,https://www.flickr.com/people/southbeachcars/
f4902a569fa12171,https://c1.staticflickr.com/8/7448/27323270341_7fc97564c7_o.jpg,0.5,0,1,0.75,950,992,https://flickr.com/141397992@N02/27323270341,https://creativecommons.org/licenses/by/2.0/,Vegan Photo,https://www.flickr.com/people/141397992@N02/
54a6b2cd7f89220e,https://c1.staticflickr.com/2/1462/26144464314_ae66e3b1da_o.jpg,0.28125,0,0.84375,0.75,918,171,https://www.flickr.com/photos/londonmatt/26144464314,https://creativecommons.org/licenses/by/2.0/,Matt Brown,https://www.flickr.com/people/londonmatt/
7b71925e989ee1d8,https://c1.staticflickr.com/1/348/31544121611_8bf40c6800_o.jpg,0.210873984,0.25,0.632621951,1,934,35,https://www.flickr.com/photos/hile/31544121611,https://creativecommons.org/licenses/by/2.0/,Helen Penjam,https://www.flickr.com/people/hile/
eae13c52554a7783,https://c1.staticflickr.com/1/283/31571942652_56aeae1bf8_o.jpg,0.245614035,0.25,0.736842105,1,781,848,https://flickr.com/149503105@N07/31571942652,https://creativecommons.org/licenses/by/2.0/,Ajith Kumar,https://www.flickr.com/people/ajithdauk/
b1e69e9c3d740f4c,https://c1.staticflickr.com/9/8733/28200514302_2f59d09947_o.jpg,0,0.25,0.5625,1,4,833,https://www.flickr.com/photos/noaaphotolib/28200514302,https://creativecommons.org/licenses/by/2.0/,NOAA Photo Library,https://www.flickr.com/people/noaaphotolib/
493e327b171ab0c3,https://c1.staticflickr.com/6/5475/30311997820_5114dcc89a_o.jpg,0,0,0.672592593,1,831,856,https://www.flickr.com/photos/13476480@N07/30311997820,https://creativecommons.org/licenses/by/2.0/,manhhai,https://www.flickr.com/people/13476480@N07/
2efe4916e679e875,https://c1.staticflickr.com/1/166/30669575014_c1861446e4_o.jpg,0.210873984,0,0.632621951,0.75,866,926,https://www.flickr.com/photos/franganillo/30669575014,https://creativecommons.org/licenses/by/2.0/,Jorge Franganillo,https://www.flickr.com/people/franganillo/
588bd41c9aa5a81b,https://c1.staticflickr.com/8/7138/26571751464_519eeae08c_o.jpg,0.25,0,1,0.75,534,154,https://www.flickr.com/photos/annethelibrarian/26571751464,https://creativecommons.org/licenses/by/2.0/,anneheathen,https://www.flickr.com/people/annethelibrarian/
49b1adfeb8ffcabd,https://c1.staticflickr.com/8/7556/27284219884_84e1fbcaeb_o.jpg,0.4375,0,1,0.75,932,671,https://www.flickr.com/photos/55229469@N07/27284219884,https://creativecommons.org/licenses/by/2.0/,Forsaken Fotos,https://www.flickr.com/people/55229469@N07/
225e06c2dfa68a62,https://c1.staticflickr.com/9/8055/28952537693_18d3e06407_o.jpg,0.25,0,0.75,0.75,882,945,https://www.flickr.com/photos/barnimages/28952537693/,https://creativecommons.org/licenses/by/2.0/,barnimages.com,https://www.flickr.com/people/barnimages/
d7d5b34ea0a0ffcf,https://c1.staticflickr.com/9/8066/29898270981_73e0076c26_o.jpg,0.500736377,0.25,1,1,878,970,https://www.flickr.com/photos/presidentialoffice/29898270981,https://creativecommons.org/licenses/by/2.0/,\347\270\275\347\265\261\345\272\234,https://www.flickr.com/people/presidentialoffice/
0212aa8aa912ee45,https://c1.staticflickr.com/6/5466/30266928545_e63bcb8041_o.jpg,0.327407407,0,1,1,327,416,https://www.flickr.com/photos/dany13/30266928545,https://creativecommons.org/licenses/by/2.0/,dany13,https://www.flickr.com/people/dany13/
d7de327bbf412965,https://c1.staticflickr.com/8/7568/28879744260_7f6ee27057_o.jpg,0,0.25,0.556376361,1,490,660,https://www.flickr.com/photos/stevensnodgrass/28879744260,https://creativecommons.org/licenses/by/2.0/,Steve Snodgrass,https://www.flickr.com/people/stevensnodgrass/
2200794c59b1808e,https://c1.staticflickr.com/1/508/32766800345_d32328469f_o.jpg,0.363560732,0,1,0.75,311,214,https://www.flickr.com/photos/gails_pictures/32766800345,https://creativecommons.org/licenses/by/2.0/,gailhampshire,https://www.flickr.com/people/gails_pictures/
83896b9fb7e9c2f8,https://c1.staticflickr.com/9/8537/29037936543_0f751d4cdc_o.jpg,0.25,0,0.75,0.75,537,547,https://www.flickr.com/photos/elsie/29037936543/,https://creativecommons.org/licenses/by/2.0/,Les Chatfield,https://www.flickr.com/people/elsie/
f9f36f7774d73820,https://c1.staticflickr.com/3/2013/32659953892_0199b33b51_o.jpg,0,0,0.563380282,0.75,305,723,https://www.flickr.com/photos/treegrow/32659953892,https://creativecommons.org/licenses/by/2.0/,Katja Schulz,https://www.flickr.com/people/treegrow/
796e23f8dbf9a7a2,https://c1.staticflickr.com/8/7421/27680391126_32219fb627_o.jpg,0,0,0.666666667,1,607,835,https://www.flickr.com/photos/quinet/27680391126,https://creativecommons.org/licenses/by/2.0/,Thomas Quine,https://www.flickr.com/people/quinet/
dad40e355e4e8e96,https://c1.staticflickr.com/9/8027/29028347661_d9a3dc8d21_o.jpg,0.25,0,0.75,0.75,655,848,https://www.flickr.com/photos/karen_roe/29028347661,https://creativecommons.org/licenses/by/2.0/,Karen Roe,https://www.flickr.com/people/karen_roe/
064e1cc405062c85,https://c1.staticflickr.com/1/645/31869882565_e6c7e4558a_o.jpg,0,0.25,0.5625,1,108,135,https://www.flickr.com/photos/jimg944/31869882565,https://creativecommons.org/licenses/by/2.0/,Jim G,https://www.flickr.com/people/jimg944/
1484479b7630af0a,https://c1.staticflickr.com/8/7520/27703755495_e5dd0273c4_o.jpg,0.25,0,0.75,0.75,702,904,https://www.flickr.com/photos/7armyjmtc/27703755495,https://creativecommons.org/licenses/by/2.0/,7th Army Training Command,https://www.flickr.com/people/7armyjmtc/
18d5f99fe237a306,https://c1.staticflickr.com/9/8496/29071092183_9562a5b8dc_o.jpg,0.246827411,0,0.740482234,1,815,77,https://www.flickr.com/photos/yamahawatercraft/29071092183/,https://creativecommons.org/licenses/by/2.0/,Yamaha Watercraft Group,https://www.flickr.com/people/yamahawatercraft/
d0c6c29954f0380b,https://c1.staticflickr.com/1/517/32675860980_0c40361cf8_o.jpg,0.25,0,1,0.5,431,96,https://www.flickr.com/photos/tjspix/32675860980,https://creativecommons.org/licenses/by/2.0/,Teresa Johns,https://www.flickr.com/people/tjspix/
c777da68bec01dcd,https://c1.staticflickr.com/9/8562/28193582220_b2580f280c_o.jpg,0.249631811,0.25,0.748895434,1,487,584,https://www.flickr.com/photos/mtaphotos/28193582220,https://creativecommons.org/licenses/by/2.0/,Metropolitan Transportation Authority of the State of New York,https://www.flickr.com/people/mtaphotos/
5cd8864b6e35df82,https://c1.staticflickr.com/8/7105/27793628895_a1d2e5e492_o.jpg,0,0,0.75,1,866,898,https://www.flickr.com/photos/jeepersmedia/27793628895,https://creativecommons.org/licenses/by/2.0/,Mike Mozart,https://www.flickr.com/people/jeepersmedia/
444109f3ccfacc7b,https://c1.staticflickr.com/9/8064/29945301806_292581209b_o.jpg,0.25,0,0.75,0.75,336,221,https://www.flickr.com/photos/amslerpix/29945301806,https://creativecommons.org/licenses/by/2.0/,amslerPIX,https://www.flickr.com/people/amslerpix/
b722c809657aecee,https://c1.staticflickr.com/1/356/30881368874_ed2a887e15_o.jpg,0,0.5,0.75,1,777,640,https://www.flickr.com/photos/eebeephoto/30881368874/,https://creativecommons.org/licenses/by/2.0/,Ed Berger,https://www.flickr.com/people/eebeephoto/
a193f7ae7d550a82,https://c1.staticflickr.com/8/7285/27193523532_37b77df506_o.jpg,0.4375,0.25,1,1,738,631,https://www.flickr.com/photos/jeepersmedia/27193523532,https://creativecommons.org/licenses/by/2.0/,Mike Mozart,https://www.flickr.com/people/jeepersmedia/
97025d82ec9860dc,https://c1.staticflickr.com/9/8123/28630695394_9e536782e6_o.jpg,0.264605463,0,0.793816388,0.75,676,574,https://www.flickr.com/photos/jeepersmedia/28630695394,https://creativecommons.org/licenses/by/2.0/,Mike Mozart,https://www.flickr.com/people/jeepersmedia/
23f39187c0d00e30,https://c1.staticflickr.com/6/5581/30083343153_3e32030455_o.jpg,0,0,0.663235294,1,972,658,https://flickr.com/14642507@N08/30083343153,https://creativecommons.org/licenses/by/2.0/,sasastro,https://www.flickr.com/people/sasastro/
515c6586db87bbd8,https://c1.staticflickr.com/6/5590/30456955046_3073b879aa_o.jpg,0,0,0.665684831,1,874,218,https://www.flickr.com/photos/bikashdas/30456955046,https://creativecommons.org/licenses/by/2.0/,Bikash Das,https://www.flickr.com/people/bikashdas/
42e9b41ce96dbf0a,https://c1.staticflickr.com/9/8058/29670008630_bd1bfc6c1a_o.jpg,0,0,0.75,0.5625,851,647,https://www.flickr.com/photos/stellahyc/29670008630,https://creativecommons.org/licenses/by/2.0/,stellahyc910,https://www.flickr.com/people/stellahyc/
126175abfdcb1a21,https://c1.staticflickr.com/1/386/32014236205_a98a5d344a_o.jpg,0.25,0.25,0.75,1,471,486,https://flickr.com/14771153@N04/32014236205,https://creativecommons.org/licenses/by/2.0/,slgckgc,https://www.flickr.com/people/slgc/
4b0c9bf2584b35d3,https://c1.staticflickr.com/9/8394/29489318570_f677a927e0_o.jpg,0,0.25,0.75,1,960,79,https://www.flickr.com/photos/naotakem/29489318570/,https://creativecommons.org/licenses/by/2.0/,Naotake Murayama,https://www.flickr.com/people/naotakem/
19b5bea9a7608a92,https://c1.staticflickr.com/3/2598/32087920803_43b48bab4b_o.jpg,0.28125,0.25,0.84375,1,778,435,https://www.flickr.com/photos/capcase/32087920803,https://creativecommons.org/licenses/by/2.0/,James Case,https://www.flickr.com/people/capcase/
1a94dc47fdd84a95,https://c1.staticflickr.com/6/5761/30269979564_df6e9df309_o.jpg,0,0.277925532,0.75,1,870,830,https://www.flickr.com/photos/ringkong/30269979564,https://creativecommons.org/licenses/by/2.0/,typexnick,https://www.flickr.com/people/ringkong/
c35cd0d5673ec1db,https://c1.staticflickr.com/8/7531/29226165661_4d4c2264c7_o.jpg,0,0.25,0.5625,1,963,367,https://www.flickr.com/photos/stevendepolo/29226165661,https://creativecommons.org/licenses/by/2.0/,Steven Depolo,https://www.flickr.com/people/stevendepolo/
b239b5b3e1642f3b,https://c1.staticflickr.com/6/5494/25330616759_529bdf9b94_o.jpg,0.512008734,0,1,0.75,914,746,https://www.flickr.com/photos/sidelong/25330616759,https://creativecommons.org/licenses/by/2.0/,DaveBleasdale,https://www.flickr.com/people/sidelong/
e22a1c8dab22f256,https://c1.staticflickr.com/8/7453/27575870760_ab7aeb3fe9_o.jpg,0,0.25,0.63875,1,311,11,https://www.flickr.com/photos/gails_pictures/27575870760,https://creativecommons.org/licenses/by/2.0/,gailhampshire,https://www.flickr.com/people/gails_pictures/
d959fd91192d5717,https://c1.staticflickr.com/6/5459/22848076308_16f2d07763_o.jpg,0,0,0.5,0.75,629,596,https://www.flickr.com/photos/prayitnophotography/22848076308,https://creativecommons.org/licenses/by/2.0/,Prayitno / Thank you for (12 millions +) view,https://www.flickr.com/people/prayitnophotography/
692016122b9e07a6,https://c1.staticflickr.com/6/5489/29804286543_9cba22e186_o.jpg,0.25,0.25,0.75,1,960,123,https://www.flickr.com/photos/39419174@N00/29804286543/,https://creativecommons.org/licenses/by/2.0/,danieleloreto,https://www.flickr.com/people/39419174@N00/
8749fd2540a0cb01,https://c1.staticflickr.com/8/7491/26781987183_ff723c7a40_o.jpg,0,0.578822733,0.75,1,833,448,https://www.flickr.com/photos/ankurp/26781987183,https://creativecommons.org/licenses/by/2.0/,Ankur P,https://www.flickr.com/people/ankurp/
8e9e976fc98e3cfa,https://c1.staticflickr.com/8/7702/27224046005_eaa4681fee_o.jpg,0.28125,0.25,0.84375,1,666,740,https://www.flickr.com/photos/65542891@N05/27224046005,https://creativecommons.org/licenses/by/2.0/,bsa rwd 10hp,https://www.flickr.com/people/65542891@N05/
d7c8008bf74f2324,https://c1.staticflickr.com/9/8691/28869458692_b60ba5200d_o.jpg,0.439189189,0,1,1,815,672,https://www.flickr.com/photos/watts_photos/28869458692,https://creativecommons.org/licenses/by/2.0/,C Watts,https://www.flickr.com/people/watts_photos/
330b9cb3cd80c88b,https://c1.staticflickr.com/8/7658/27109056921_f299a6739a_o.jpg,0.280784844,0,0.842354533,1,534,431,https://www.flickr.com/photos/annethelibrarian/27109056921,https://creativecommons.org/licenses/by/2.0/,anneheathen,https://www.flickr.com/people/annethelibrarian/
1ef172b89f4a39cf,https://c1.staticflickr.com/6/5508/31450600235_a463d20bb6_o.jpg,0.333333333,0,1,1,51,536,https://www.flickr.com/photos/52450054@N04/31450600235/,https://creativecommons.org/licenses/by/2.0/,Judy Gallagher,https://www.flickr.com/people/52450054@N04/
b02b553998809e17,https://c1.staticflickr.com/8/7614/26966736165_2a6493858a_o.jpg,0.5,0.25,1,1,704,847,https://www.flickr.com/photos/30845197@N00/26966736165/,https://creativecommons.org/licenses/by/2.0/,TLV and more,https://www.flickr.com/people/30845197@N00/
74b2e35cda75fe27,https://c1.staticflickr.com/1/316/32602465092_4522030924_o.jpg,0,0.25,0.576740506,1,629,466,https://www.flickr.com/photos/archivesnz/32602465092/,https://creativecommons.org/licenses/by/2.0/,Archives New Zealand,https://www.flickr.com/people/archivesnz/
f5a2cf5c66d313fa,https://c1.staticflickr.com/8/7090/27455698002_a951356516_o.jpg,0.25,0,1,1,977,656,https://www.flickr.com/photos/crondeau/27455698002,https://creativecommons.org/licenses/by/2.0/,Christine Rondeau,https://www.flickr.com/people/crondeau/
5ceb9f2e8405b0de,https://c1.staticflickr.com/6/5666/30835439000_59b2871139_o.jpg,0.400242326,0.25,1,1,412,64,https://www.flickr.com/photos/mdgovpics/30835439000/,https://creativecommons.org/licenses/by/2.0/,Maryland GovPics,https://www.flickr.com/people/mdgovpics/
114c98c078c5aab0,https://c1.staticflickr.com/9/8705/28272303681_3f64c45d57_o.jpg,0.25,0,1,0.75,50,108,https://www.flickr.com/photos/austinevan/28272303681,https://creativecommons.org/licenses/by/2.0/,Evan Bench,https://www.flickr.com/people/austinevan/
d741b583a123562b,https://c1.staticflickr.com/9/8728/29612129273_477bf62411_o.jpg,0.254086181,0.25,0.762258544,1,321,792,https://flickr.com/24025807@N06/29612129273,https://creativecommons.org/licenses/by/2.0/,CLUBE TREKKING SANTA MARIA RS BRASIL,https://www.flickr.com/people/hikingsantamaria/
324278ff7f22b4eb,https://c1.staticflickr.com/4/3747/32487584933_83dbbe0cb8_o.jpg,0.25,0.25,1,1,498,303,https://flickr.com/25633870@N00/32487584933,https://creativecommons.org/licenses/by/2.0/,Dave Haygarth,https://www.flickr.com/people/minnellium/
1f4227ce24232867,https://c1.staticflickr.com/8/7229/27970534102_43ed025ff3_o.jpg,0.4375,0,1,0.75,34,942,https://www.flickr.com/photos/hockeyholic/27970534102/,https://creativecommons.org/licenses/by/2.0/,Andy Blackledge,https://www.flickr.com/people/hockeyholic/
5973419efd52f783,https://c1.staticflickr.com/6/5508/31120625660_9594495e7d_o.jpg,0.348396501,0,1,1,625,795,https://www.flickr.com/photos/usnavalwarcollegeri/31120625660,https://creativecommons.org/licenses/by/2.0/,U.S. Naval War College,https://www.flickr.com/people/usnavalwarcollegeri/
fdedd06cdf58084e,https://c1.staticflickr.com/8/7718/27331217545_3b853360be_o.jpg,0,0.200323102,1,1,982,428,https://www.flickr.com/photos/slgc/27331217545,https://creativecommons.org/licenses/by/2.0/,slgckgc,https://www.flickr.com/people/slgc/
911aebf30626ce02,https://c1.staticflickr.com/3/2430/32287607674_b11095a2e5_o.jpg,0.521645022,0.25,1,1,875,731,https://www.flickr.com/photos/didbygraham/32287607674/,https://creativecommons.org/licenses/by/2.0/,Graham Richardson,https://www.flickr.com/people/didbygraham/
55599050147071cc,https://c1.staticflickr.com/8/7412/27512988611_20873a4f90_o.jpg,0.246522694,0.25,0.739568082,1,473,962,https://www.flickr.com/photos/vastateparksstaff/27512988611/,https://creativecommons.org/licenses/by/2.0/,Virginia State Parks,https://www.flickr.com/people/vastateparksstaff/
eee6f4bcc8468f77,https://c1.staticflickr.com/1/652/31882765966_b27b4fcf19_o.jpg,0,0,1,0.666666667,964,714,https://www.flickr.com/photos/oikeuttaelaimille/31882765966/,https://creativecommons.org/licenses/by/2.0/,Oikeutta el\303\244imille,https://www.flickr.com/people/oikeuttaelaimille/
7f3c20f487834846,https://c1.staticflickr.com/8/7448/26824382232_3b4a0eddcd_o.jpg,0,0,0.678571429,1,408,883,https://www.flickr.com/photos/zongo/26824382232,https://creativecommons.org/licenses/by/2.0/,DAVID HOLT,https://www.flickr.com/people/zongo/
8c8bc30a62a1ee23,https://c1.staticflickr.com/1/431/30989283343_7cae478677_o.jpg,0,0.25,0.713028169,1,304,2,https://www.flickr.com/photos/33398884@N03/30989283343/,https://creativecommons.org/licenses/by/2.0/,Ben Sale,https://www.flickr.com/people/33398884@N03/
7e0fb7f80ffa514b,https://c1.staticflickr.com/1/717/31662466562_b2b1553c3d_o.jpg,0.25,0,1,1,655,405,https://www.flickr.com/photos/didbygraham/31662466562,https://creativecommons.org/licenses/by/2.0/,Graham Richardson,https://www.flickr.com/people/didbygraham/
c02ff39fe5832f4b,https://c1.staticflickr.com/6/5597/30495370923_f689e3460c_o.jpg,0.25,0.25,0.75,1,905,675,https://www.flickr.com/photos/o_0/30495370923/,https://creativecommons.org/licenses/by/2.0/,Guilhem Vellut,https://www.flickr.com/people/o_0/
891fe6baf8896b77,https://c1.staticflickr.com/8/7795/28741196845_ca00f0104f_o.jpg,0.25,0,1,0.75,325,535,https://www.flickr.com/photos/kellymcpherson/28741196845/,https://creativecommons.org/licenses/by/2.0/,Kelly Parker McPherson,https://www.flickr.com/people/kellymcpherson/
e96d52f9fbe3ca0b,https://c1.staticflickr.com/3/2540/32722690932_52ea2c48f3_o.jpg,0,0,0.660792952,1,631,435,https://flickr.com/29971610@N02/32722690932,https://creativecommons.org/licenses/by/2.0/,Esther Max,https://www.flickr.com/people/esthermax/
29279d12ed3e29ff,https://c1.staticflickr.com/1/502/32144969220_9f0703dc8e_o.jpg,0.5,0.25,1,1,458,328,https://www.flickr.com/photos/foreignoffice/32144969220/,https://creativecommons.org/licenses/by/2.0/,Foreign and Commonwealth Office,https://www.flickr.com/people/foreignoffice/
ac295a63ac9d2cd7,https://c1.staticflickr.com/8/7292/27671965670_4d9e6a72c8_o.jpg,0.280784844,0,0.842354533,1,693,864,https://www.flickr.com/photos/shoppeolina/27671965670,https://creativecommons.org/licenses/by/2.0/,owlin aolin,https://www.flickr.com/people/shoppeolina/
5d23b04cc45bc37b,https://c1.staticflickr.com/9/8178/29212985530_24749869f4_o.jpg,0.4375,0.25,1,1,518,737,https://www.flickr.com/photos/zongo/29212985530/,https://creativecommons.org/licenses/by/2.0/,DAVID HOLT,https://www.flickr.com/people/zongo/
11c53fe6feb856c6,https://c1.staticflickr.com/8/7162/26707259244_e47c43b2b7_o.jpg,0,0.299878837,0.75,0.899636511,477,766,https://www.flickr.com/photos/edenpictures/26707259244,https://creativecommons.org/licenses/by/2.0/,"Eden, Janine and Jim",https://www.flickr.com/people/edenpictures/
cbcb7444cc827812,https://c1.staticflickr.com/8/7549/26276389703_ecd645cc3e_o.jpg,0.333333333,0,1,1,763,786,https://www.flickr.com/photos/agenciabrasilia/26276389703,https://creativecommons.org/licenses/by/2.0/,Ag\303\252ncia Bras\303\255lia,https://www.flickr.com/people/agenciabrasilia/
fe1314dd6f75551d,https://c1.staticflickr.com/8/7144/26370391824_3159ca42b2_o.jpg,0,0.25,0.75,1,921,565,https://www.flickr.com/photos/brendanadkins/26370391824,https://creativecommons.org/licenses/by/2.0/,Brendan Adkins,https://www.flickr.com/people/brendanadkins/
a8fca010774a1187,https://c1.staticflickr.com/1/425/31809450395_45b02082bb_o.jpg,0.4375,0,1,0.75,829,810,https://www.flickr.com/photos/fdecomite/31809450395/,https://creativecommons.org/licenses/by/2.0/,fdecomite,https://www.flickr.com/people/fdecomite/
5ec826683757ffae,https://c1.staticflickr.com/6/5731/30742412415_c35c2ff310_o.jpg,0,0,0.599757674,0.75,23,369,https://www.flickr.com/photos/andymorffew/30742412415,https://creativecommons.org/licenses/by/2.0/,Andy Morffew,https://www.flickr.com/people/andymorffew/
b9310b9080c06e4f,https://c1.staticflickr.com/8/7398/27330948851_cd9be2c204_o.jpg,0.25,0.318416523,1,1,867,269,https://www.flickr.com/photos/60900612@N08/27330948851,https://creativecommons.org/licenses/by/2.0/,Thomas's Pics,https://www.flickr.com/people/60900612@N08/
4f9f0b75f5b04524,https://c1.staticflickr.com/8/7587/26933811080_cf8040335a_o.jpg,0,0.25,0.5,1,58,897,https://www.flickr.com/photos/gregthebusker/26933811080,https://creativecommons.org/licenses/by/2.0/,Greg Schechter,https://www.flickr.com/people/gregthebusker/
4abadb721e74b99b,https://c1.staticflickr.com/8/7612/26811635786_e5a333566f_o.jpg,0,0,0.666666667,1,945,781,https://www.flickr.com/photos/mwf2005/26811635786/,https://creativecommons.org/licenses/by/2.0/,muffinn,https://www.flickr.com/people/mwf2005/
a3c651cf20ee2d34,https://c1.staticflickr.com/8/7710/26294912563_ba1be3ec95_o.jpg,0,0,0.75,0.75,641,561,https://www.flickr.com/photos/49889874@N05/26294912563,https://creativecommons.org/licenses/by/2.0/,marc falardeau,https://www.flickr.com/people/49889874@N05/
5c4eec952ca114a1,https://c1.staticflickr.com/1/528/31431409824_729b5c64d9_o.jpg,0.25,0.25,0.75,1,348,525,https://flickr.com/51986662@N05/31431409824,https://creativecommons.org/licenses/by/2.0/,USFWS Mountain-Prairie,https://www.flickr.com/people/usfwsmtnprairie/
7f045354f4577c16,https://c1.staticflickr.com/9/8268/30074145430_c1afafabc2_o.jpg,0.25,0,1,0.75,558,970,https://www.flickr.com/photos/rodrigoparedes/30074145430,https://creativecommons.org/licenses/by/2.0/,Rodrigo Paredes,https://www.flickr.com/people/rodrigoparedes/
53211f8a1b131de6,https://c1.staticflickr.com/9/8732/28580034102_984ce9d944_o.jpg,0.220095694,0,1,1,946,578,https://www.flickr.com/photos/elzey/28580034102,https://creativecommons.org/licenses/by/2.0/,Richard Elzey,https://www.flickr.com/people/elzey/
9c0e25e2f72438e8,https://c1.staticflickr.com/6/5607/31102907732_def8083c3f_o.jpg,0,0,0.747269891,1,512,506,https://www.flickr.com/photos/andreboeni/31102907732,https://creativecommons.org/licenses/by/2.0/,Andrew Bone,https://www.flickr.com/people/andreboeni/
55512a6c2a45e2e8,https://c1.staticflickr.com/8/7340/28096885425_4c07a3cf83_o.jpg,0,0.320512821,0.75,0.961538462,928,387,https://www.flickr.com/photos/uwlideas/28096885425/,https://creativecommons.org/licenses/by/2.0/,Med Coolman,https://www.flickr.com/people/uwlideas/
869adfbad4e38261,https://c1.staticflickr.com/6/5697/30241927150_b62ec0df8a_o.jpg,0.25,0,1,0.75,592,866,https://www.flickr.com/photos/sonyanews/30241927150/,https://creativecommons.org/licenses/by/2.0/,sonyanews,https://www.flickr.com/people/sonyanews/
adcf48b42266309d,https://c1.staticflickr.com/9/8057/29233160570_87ebbbc643_o.jpg,0.248713235,0.25,0.746139706,1,505,589,https://www.flickr.com/photos/mdpettitt/29233160570,https://creativecommons.org/licenses/by/2.0/,Martin Pettitt,https://www.flickr.com/people/mdpettitt/
3b67bec3793efcb4,https://c1.staticflickr.com/6/5682/30920421081_33e27f1675_o.jpg,0.548319328,0,1,0.75,822,746,https://www.flickr.com/photos/gaby1/30920421081,https://creativecommons.org/licenses/by/2.0/,Gabriel Gonz\303\241lez,https://www.flickr.com/people/gaby1/
67a08d685abf7fb6,https://c1.staticflickr.com/8/7793/27924211143_79cef8b65a_o.jpg,0.25,0,0.75,0.75,739,710,https://www.flickr.com/photos/blondinrikard/27924211143,https://creativecommons.org/licenses/by/2.0/,Blondinrikard Fr\303\266berg,https://www.flickr.com/people/blondinrikard/
22a313cc9fc2b4f1,https://c1.staticflickr.com/9/8612/28340861743_d50c5784e8_o.jpg,0.248826291,0,1,1,310,940,https://www.flickr.com/photos/pamas/28340861743,https://creativecommons.org/licenses/by/2.0/,Esin \303\234st\303\274n,https://www.flickr.com/people/pamas/
0d85e0103989c850,https://c1.staticflickr.com/9/8124/28994100466_472d225974_o.jpg,0.272727273,0,1,1,324,722,https://www.flickr.com/photos/usfwsmtnprairie/28994100466,https://creativecommons.org/licenses/by/2.0/,USFWS Mountain-Prairie,https://www.flickr.com/people/usfwsmtnprairie/
c3cf76709c87255b,https://c1.staticflickr.com/9/8340/29178027716_ed24cc96f2_o.jpg,0,0,0.75,0.75,676,224,https://www.flickr.com/photos/soulhammer/29178027716/,https://creativecommons.org/licenses/by/2.0/,Nathaniel Bruno,https://www.flickr.com/people/soulhammer/
74355a8c878b6814,https://c1.staticflickr.com/1/408/31898209835_867bd3b167_o.jpg,0,0,0.75,1,875,622,https://flickr.com/69203347@N03/31898209835,https://creativecommons.org/licenses/by/2.0/,AmigoDeBusesEMT3,https://www.flickr.com/people/69203347@N03/
6efed50f84ec5e01,https://c1.staticflickr.com/6/5168/29928350415_8935e09ba7_o.jpg,0.5,0,1,0.75,947,602,https://www.flickr.com/photos/lsmith2010/29928350415,https://creativecommons.org/licenses/by/2.0/,Larry Smith,https://www.flickr.com/people/lsmith2010/
d6887e8d19a06139,https://c1.staticflickr.com/6/5753/30992363516_d62f652ef9_o.jpg,0.25,0,1,1,563,45,https://www.flickr.com/photos/rbowen/30992363516/,https://creativecommons.org/licenses/by/2.0/,Rich Bowen,https://www.flickr.com/people/rbowen/
21fef4d9b3dce49a,https://c1.staticflickr.com/9/8126/28295230322_8c45fd586e_o.jpg,0,0.25,0.411096257,1,975,460,https://www.flickr.com/photos/jsjgeology/28295230322,https://creativecommons.org/licenses/by/2.0/,James St. John,https://www.flickr.com/people/jsjgeology/
0d65cb9d26de4d37,https://c1.staticflickr.com/8/7605/28137606406_e04b692957_o.jpg,0.25,0,0.75,0.75,571,336,https://www.flickr.com/photos/chrisdag/28137606406,https://creativecommons.org/licenses/by/2.0/,ChrisDag,https://www.flickr.com/people/chrisdag/
3df888fc3b1df464,https://c1.staticflickr.com/8/7574/26519073574_355cd52e23_o.jpg,0.25,0,1,0.75,955,383,https://www.flickr.com/photos/vincentteeuwen/26519073574,https://creativecommons.org/licenses/by/2.0/,Vincent Teeuwen,https://www.flickr.com/people/vincentteeuwen/
5ab3f1edd2f0cb06,https://c1.staticflickr.com/8/7716/27804279183_27b9180bda_o.jpg,0,0.079722704,1,1,387,116,https://www.flickr.com/photos/jared422/27804279183,https://creativecommons.org/licenses/by/2.0/,Jared,https://www.flickr.com/people/jared422/
51b390bb124a6d9d,https://c1.staticflickr.com/9/8037/29219102264_ded8d317fa_o.jpg,0,0,0.75,0.657142857,968,422,https://www.flickr.com/photos/141897087@N06/29219102264,https://creativecommons.org/licenses/by/2.0/,JV Santore,https://www.flickr.com/people/141897087@N06/
5bf502c4a4b7d04d,https://c1.staticflickr.com/6/5590/31190125660_b80ecdcb10_o.jpg,0.5,0,1,0.75,10,350,https://flickr.com/65847397@N05/31190125660,https://creativecommons.org/licenses/by/2.0/,Paul Balfe,https://www.flickr.com/people/paul_e_balfe/
6ad1230d612d7eb7,https://c1.staticflickr.com/3/2413/31980917214_4992777b36_o.jpg,0.25,0.498159057,1,0.996318115,438,680,https://www.flickr.com/photos/davehamster/31980917214/,https://creativecommons.org/licenses/by/2.0/,David Merrett,https://www.flickr.com/people/davehamster/
76a5715019fe11c7,https://c1.staticflickr.com/9/8223/28686786171_cee3ce47f5_o.jpg,0,0,0.690690691,1,821,768,https://www.flickr.com/photos/grassrootsgroundswell/28686786171,https://creativecommons.org/licenses/by/2.0/,grassrootsgroundswell,https://www.flickr.com/people/grassrootsgroundswell/
207fd3b5def218d1,https://c1.staticflickr.com/8/7223/27019150086_7ba8c473c7_o.jpg,0.25,0.4375,1,1,991,279,https://www.flickr.com/photos/ndrwfgg/27019150086,https://creativecommons.org/licenses/by/2.0/,Andy / Andrew Fogg,https://www.flickr.com/people/ndrwfgg/
ad43e858c614db4d,https://c1.staticflickr.com/9/8263/28394550932_d93637d26b_o.jpg,0,0.25,0.5625,1,968,71,https://flickr.com/7831824@N04/28394550932,https://creativecommons.org/licenses/by/2.0/,Bex Walton,https://www.flickr.com/people/bexwalton/
b3ba6f0352a29b2d,https://c1.staticflickr.com/6/5459/30102051053_1c9c298a3c_o.jpg,0,0,0.498159057,0.75,752,563,https://www.flickr.com/photos/davehamster/30102051053/,https://creativecommons.org/licenses/by/2.0/,David Merrett,https://www.flickr.com/people/davehamster/
95185508805329aa,https://c1.staticflickr.com/9/8354/29365580064_0e6908f14d_o.jpg,0.299878837,0.25,0.899636511,1,653,721,https://www.flickr.com/photos/ocarchives/29365580064,https://creativecommons.org/licenses/by/2.0/,Orange County Archives,https://www.flickr.com/people/ocarchives/
73ee2cc19ef92e50,https://c1.staticflickr.com/8/7189/27594432472_dfaf365016_o.jpg,0,0.25,0.501846381,1,982,686,https://www.flickr.com/photos/jorge-11/27594432472,https://creativecommons.org/licenses/by/2.0/,George M. Groutas,https://www.flickr.com/people/jorge-11/
be1c43056c5d0085,https://c1.staticflickr.com/6/5525/30762478116_b134a3ee51_o.jpg,0.28125,0,0.84375,0.75,145,436,https://www.flickr.com/photos/usfwsmtnprairie/30762478116,https://creativecommons.org/licenses/by/2.0/,USFWS Mountain-Prairie,https://www.flickr.com/people/usfwsmtnprairie/
84a5f6ee2af29208,https://c1.staticflickr.com/8/7421/26497262564_8dc1a3b161_o.jpg,0.331617647,0,0.994852941,1,321,513,https://www.flickr.com/photos/ilouque/26497262564/,https://creativecommons.org/licenses/by/2.0/,ilouque,https://www.flickr.com/people/ilouque/
50b9e11ae686ae32,https://c1.staticflickr.com/6/5591/31118494856_52df471331_o.jpg,0,0,0.991007194,1,321,34,https://www.flickr.com/photos/gails_pictures/31118494856,https://creativecommons.org/licenses/by/2.0/,gailhampshire,https://www.flickr.com/people/gails_pictures/
fe2edb6cad72d2d2,https://c1.staticflickr.com/8/7468/26505971443_c1368c14e0_o.jpg,0.25,0,1,1,918,488,https://www.flickr.com/photos/jeepersmedia/26505971443,https://creativecommons.org/licenses/by/2.0/,Mike Mozart,https://www.flickr.com/people/jeepersmedia/
58420b727fcab02b,https://c1.staticflickr.com/6/5768/30823764900_d486a3f904_o.jpg,0,0,0.714503817,1,138,168,https://flickr.com/143049688@N08/30823764900,https://creativecommons.org/licenses/by/2.0/,MR MAO PICS,https://www.flickr.com/people/143049688@N08/
47b087263b33728b,https://c1.staticflickr.com/9/8228/29000044324_0eb54060d7_o.jpg,0.298790323,0.25,0.896370968,1,318,152,https://flickr.com/33398884@N03/29000044324,https://creativecommons.org/licenses/by/2.0/,Ben Sale,https://www.flickr.com/people/33398884@N03/
0e0299d6352a3fb8,https://c1.staticflickr.com/1/636/31002720224_411dc0a03f_o.jpg,0.25,0.25,0.75,1,539,4,https://flickr.com/22539273@N00/31002720224,https://creativecommons.org/licenses/by/2.0/,Guilhem Vellut,https://www.flickr.com/people/o_0/
2ee4c1b2b9bcc6c8,https://c1.staticflickr.com/9/8354/29761961012_02ecff90a4_o.jpg,0.25,0,0.75,0.75,763,785,https://www.flickr.com/photos/deltanewshub/29761961012,https://creativecommons.org/licenses/by/2.0/,Delta News Hub,https://www.flickr.com/people/deltanewshub/
24312de5c34473c0,https://c1.staticflickr.com/6/5584/29688881533_e0c64dc987_o.jpg,0.25,0.438671875,1,1,874,820,https://www.flickr.com/photos/marsupilami92/29688881533/,https://creativecommons.org/licenses/by/2.0/,patrick janicek,https://www.flickr.com/people/marsupilami92/
bb748281da5e8681,https://c1.staticflickr.com/6/5281/29946906871_845417f8ac_o.jpg,0.210588633,0,0.6317659,0.75,348,694,https://www.flickr.com/photos/39090590@N02/29946906871,https://creativecommons.org/licenses/by/2.0/,Cyril Fluck,https://www.flickr.com/people/39090590@N02/
b648e8dfcb4fbc99,https://c1.staticflickr.com/1/679/31918129032_23e9a7057b_o.jpg,0,0,0.666666667,1,982,572,https://flickr.com/148488209@N08/31918129032,https://creativecommons.org/licenses/by/2.0/,makaiyla willis,https://www.flickr.com/people/makaiylaw/
d2cc2eabfc7bf54a,https://c1.staticflickr.com/6/5509/31244583052_a8416401f1_o.jpg,0.25,0,0.75,0.75,556,721,https://www.flickr.com/photos/rpavich/31244583052,https://creativecommons.org/licenses/by/2.0/,rpavich,https://www.flickr.com/people/rpavich/
da4b3e38b069d735,https://c1.staticflickr.com/9/8206/28992945534_a0fcc6e623_o.jpg,0.25,0.25,1,1,777,691,https://www.flickr.com/photos/wwworks/28992945534,https://creativecommons.org/licenses/by/2.0/,woodleywonderworks,https://www.flickr.com/people/wwworks/
b0bb1ea9bcc45800,https://c1.staticflickr.com/9/8433/28813586781_49bed3bfb8_o.jpg,0,0,0.5625,0.75,845,456,https://www.flickr.com/photos/renaissancechambara/28813586781/,https://creativecommons.org/licenses/by/2.0/,Ged Carroll,https://www.flickr.com/people/renaissancechambara/
ac668c13ccfd4b79,https://c1.staticflickr.com/1/538/31770839465_f1c3beb91e_o.jpg,0,0,0.666666667,1,598,751,https://www.flickr.com/photos/quinet/31770839465,https://creativecommons.org/licenses/by/2.0/,Thomas Quine,https://www.flickr.com/people/quinet/
b6c6a5b7829fbc9b,https://c1.staticflickr.com/9/8290/28794830561_2c903f75c1_o.jpg,0.336764706,0,1,1,473,506,https://www.flickr.com/photos/shankaronline/28794830561,https://creativecommons.org/licenses/by/2.0/,shankar s.,https://www.flickr.com/people/shankaronline/
014f0024918a7b6f,https://c1.staticflickr.com/8/7564/27345252166_6948b71ff3_o.jpg,0.28125,0,0.84375,0.75,10,885,https://www.flickr.com/photos/amanderson/27345252166,https://creativecommons.org/licenses/by/2.0/,amanderson2,https://www.flickr.com/people/amanderson/
93114736f072d6d3,https://c1.staticflickr.com/8/7396/26691839134_a072ec1162_o.jpg,0.25,0,0.75,0.75,617,763,https://www.flickr.com/photos/cogdog/26691839134,https://creativecommons.org/licenses/by/2.0/,Alan Levine,https://www.flickr.com/people/cogdog/
c9ddfb1043177de8,https://c1.staticflickr.com/6/5517/31689316216_b954ab5538_o.jpg,0.5,0.25,1,1,975,117,http://www.flickr.com/photos/richardmoross/31689316216/,https://creativecommons.org/licenses/by/2.0/,Richard Moross,https://www.flickr.com/people/richardmoross/
7e4c41563370bed1,https://c1.staticflickr.com/9/8497/29201470542_e661660313_o.jpg,0,0,0.666666667,1,719,945,https://www.flickr.com/photos/herdie/29201470542,https://creativecommons.org/licenses/by/2.0/,herdiephoto,https://www.flickr.com/people/herdie/
328d99215b19c8c7,https://c1.staticflickr.com/1/662/32533031665_e6c123d8eb_o.jpg,0.5,0,1,0.75,806,926,https://www.flickr.com/photos/30478819@N08/32533031665,https://creativecommons.org/licenses/by/2.0/,Marco Verch,https://www.flickr.com/people/30478819@N08/
2a1a60df9a58bb7c,https://c1.staticflickr.com/8/7780/26705680280_a7f5f24425_o.jpg,0,0.333333333,1,1,650,19,https://www.flickr.com/photos/travelnevada/26705680280,https://creativecommons.org/licenses/by/2.0/,Travel Nevada,https://www.flickr.com/people/travelnevada/
263c7bcd59502625,https://c1.staticflickr.com/9/8092/29347734850_29561b6ec6_o.jpg,0.5,0,1,0.75,480,651,https://www.flickr.com/photos/concavowheels/29347734850,https://creativecommons.org/licenses/by/2.0/,CONCAVO WHEELS,https://www.flickr.com/people/concavowheels/
d05076189b7fd185,https://c1.staticflickr.com/1/727/32381120905_712248f38a_o.jpg,0.25,0,1,0.646812081,708,765,https://www.flickr.com/photos/jdlasica/32381120905,https://creativecommons.org/licenses/by/2.0/,JD Lasica,https://www.flickr.com/people/jdlasica/
fe193683db61ac2d,https://c1.staticflickr.com/6/5669/30159267186_7663a5ba9c_o.jpg,0.4375,0,1,0.75,744,1,https://www.flickr.com/photos/meemainseen/30159267186,https://creativecommons.org/licenses/by/2.0/,Muhammad Imran Saeed,https://www.flickr.com/people/meemainseen/
d8b0101e2459882a,https://c1.staticflickr.com/8/7451/27873714556_8452970117_o.jpg,0,0.25,0.5,1,655,88,https://www.flickr.com/photos/impulse_2016/27873714556/,https://creativecommons.org/licenses/by/2.0/,Impulse Theater Festival 2016,https://www.flickr.com/people/impulse_2016/
3841b33c9797cbf1,https://c1.staticflickr.com/6/5563/30857323591_f9687379e7_o.jpg,0,0,0.5625,0.75,909,953,https://www.flickr.com/photos/brownpau/30857323591,https://creativecommons.org/licenses/by/2.0/,brownpau,https://www.flickr.com/people/brownpau/
232c22314e21f764,https://c1.staticflickr.com/6/5505/30587416664_22b14394ec_o.jpg,0.560165975,0,1,0.75,115,904,https://www.flickr.com/photos/gails_pictures/30587416664,https://creativecommons.org/licenses/by/2.0/,gailhampshire,https://www.flickr.com/people/gails_pictures/
30b62313af2b5d74,https://c1.staticflickr.com/8/7570/30228833946_9b000a7dbd_o.jpg,0,0,0.561328125,0.75,316,795,https://www.flickr.com/photos/pamas/30228833946,https://creativecommons.org/licenses/by/2.0/,Esin \303\234st\303\274n,https://www.flickr.com/people/pamas/
2c54b60a2851b8ed,https://c1.staticflickr.com/9/8523/29243698212_6d465d0527_o.jpg,0,0,0.5625,0.75,657,577,https://www.flickr.com/photos/zombieite/29243698212,https://creativecommons.org/licenses/by/2.0/,zombieite,https://www.flickr.com/people/zombieite/
c96c3eab644075d3,https://c1.staticflickr.com/8/7790/26778459800_6328b3ac5d_o.jpg,0,0,0.932055749,1,348,300,https://www.flickr.com/photos/lac-bac/26778459800,https://creativecommons.org/licenses/by/2.0/,BiblioArchives / LibraryArchives,https://www.flickr.com/people/lac-bac/
060dfe239abfd547,https://c1.staticflickr.com/8/7475/28717385362_9e5d05dfe7_o.jpg,0.473457676,0.25,0.946915352,1,704,396,https://www.flickr.com/photos/alan-light/28717385362/,https://creativecommons.org/licenses/by/2.0/,Alan Light,https://www.flickr.com/people/alan-light/
0bd5123017590e39,https://c1.staticflickr.com/6/5553/30409656042_0a59691936_o.jpg,0.4375,0.25,1,1,566,430,https://www.flickr.com/photos/davidwilson1949/30409656042,https://creativecommons.org/licenses/by/2.0/,David Wilson,https://www.flickr.com/people/davidwilson1949/
bd3617fcc985fe31,https://c1.staticflickr.com/6/5624/30871247636_63a2a6a4fa_o.jpg,0,0.25,0.75,0.75,833,61,https://www.flickr.com/photos/xiquinho/30871247636/,https://creativecommons.org/licenses/by/2.0/,xiquinhosilva,https://www.flickr.com/people/xiquinho/
54666421b4a6998f,https://c1.staticflickr.com/8/7701/26783338114_ced2a4e55f_o.jpg,0.5,0,1,0.75,920,759,https://www.flickr.com/photos/zeevveez/26783338114,https://creativecommons.org/licenses/by/2.0/,zeevveez,https://www.flickr.com/people/zeevveez/
4e34df87968bd882,https://c1.staticflickr.com/1/621/31058803964_6d583c4eea_o.jpg,0.438671875,0.25,1,1,339,379,https://flickr.com/30139045@N00/31058803964,https://creativecommons.org/licenses/by/2.0/,Tim Walker,https://www.flickr.com/people/timjoyfamily/
3f48b1e74589d310,https://c1.staticflickr.com/9/8038/28644165984_de12eb6b3e_o.jpg,0,0,0.666666667,1,653,508,https://www.flickr.com/photos/secdef/28644165984,https://creativecommons.org/licenses/by/2.0/,Jim Mattis,https://www.flickr.com/people/secdef/
96e77c20bf94ecb1,https://c1.staticflickr.com/9/8342/28986701940_8aa08f43c6_o.jpg,0.4108,0.25,1,1,818,518,https://www.flickr.com/photos/autohistorian/28986701940,https://creativecommons.org/licenses/by/2.0/,Alden Jewell,https://www.flickr.com/people/autohistorian/
4edeacef9fb8ec90,https://c1.staticflickr.com/6/5579/31278004155_6f6d083d49_o.jpg,0,0,0.5625,0.75,719,997,https://www.flickr.com/photos/cambodia4kidsorg/31278004155/,https://creativecommons.org/licenses/by/2.0/,Cambodia4kids.org Beth Kanter,https://www.flickr.com/people/cambodia4kidsorg/
c9302f3b2b0452e4,https://c1.staticflickr.com/8/7413/27864002812_f3fc0a7878_o.jpg,0,0,0.875,1,884,892,https://www.flickr.com/photos/hisgett/27864002812?rb=1,https://creativecommons.org/licenses/by/2.0/,Tony Hisgett,https://www.flickr.com/people/hisgett/
0af0a5dfee6b84ff,https://c1.staticflickr.com/8/7382/26663873503_fc70ec8c08_o.jpg,0.280226209,0,0.840678627,0.75,484,808,https://www.flickr.com/photos/65344061@N06/26663873503/,https://creativecommons.org/licenses/by/2.0/,Andrew Bone,https://www.flickr.com/people/andreboeni/
02dbe78a73db2808,https://c1.staticflickr.com/9/8089/27862798673_b874427662_o.jpg,0.369771863,0.25,0.739543726,1,975,255,https://flickr.com/47445767@N05/27862798673,https://creativecommons.org/licenses/by/2.0/,James St. John,https://www.flickr.com/people/jsjgeology/
592c7424f13b2d29,https://c1.staticflickr.com/9/8639/28634730405_a12dd81623_o.jpg,0.419316375,0.25,1,1,604,517,https://www.flickr.com/photos/lac-bac/28634730405,https://creativecommons.org/licenses/by/2.0/,BiblioArchives / LibraryArchives,https://www.flickr.com/people/lac-bac/
f5b0ed0fbb3b5f74,https://c1.staticflickr.com/1/131/30836327244_86e3f6cee9_o.jpg,0.5,0.25,1,1,567,645,https://www.flickr.com/photos/nationalassemblyforwales/30836327244,https://creativecommons.org/licenses/by/2.0/,National Assembly for Wales,https://www.flickr.com/people/nationalassemblyforwales/
1b1ffd7000d0749f,https://c1.staticflickr.com/6/5763/30233213804_63bd4007fd_o.jpg,0,0,0.75,0.75,960,991,https://www.flickr.com/photos/ilove9and23/30233213804/,https://creativecommons.org/licenses/by/2.0/,Debbie Tingzon,https://www.flickr.com/people/ilove9and23/
70a2529a6b2c0d46,https://c1.staticflickr.com/9/8631/29164479153_b29b11670b_o.jpg,0.5,0.25,1,1,580,550,https://www.flickr.com/photos/usarmyband/29164479153/,https://creativecommons.org/licenses/by/2.0/,The United States Army Band,https://www.flickr.com/people/usarmyband/
bba5c56cc3eb07c9,https://c1.staticflickr.com/1/546/31014776813_b295235e55_o.jpg,0.267938931,0.25,0.803816794,1,921,594,https://www.flickr.com/photos/thomasrousing/31014776813,https://creativecommons.org/licenses/by/2.0/,Thomas Rousing,https://www.flickr.com/people/thomasrousing/
000b7d55b6184b08,https://c1.staticflickr.com/8/7450/27510795501_46c2084b6c_o.jpg,0,0,0.5625,0.75,389,963,https://www.flickr.com/photos/40205555@N06/27510795501,https://creativecommons.org/licenses/by/2.0/,mrho101,https://www.flickr.com/people/40205555@N06/
8a02b6196885c394,https://c1.staticflickr.com/8/7296/27350770975_3f596317b8_o.jpg,0,0,1,1,760,447,https://www.flickr.com/photos/graficmedia/27350770975,https://creativecommons.org/licenses/by/2.0/,[-_-] JORGE,https://www.flickr.com/people/graficmedia/
582663fe666aac9c,https://c1.staticflickr.com/6/5592/29610060673_fe4f7b8d01_o.jpg,0,0,0.56375,0.75,923,928,https://www.flickr.com/photos/kelvynskee/29610060673,https://creativecommons.org/licenses/by/2.0/,Kelvyn Skee,https://www.flickr.com/people/kelvynskee/
f6515f31b750a573,https://c1.staticflickr.com/1/719/32474210662_fa858156a3_o.jpg,0,0,0.666666667,1,477,723,https://www.flickr.com/photos/quinet/32474210662,https://creativecommons.org/licenses/by/2.0/,Thomas Quine,https://www.flickr.com/people/quinet/
acd99e9b7128395a,https://c1.staticflickr.com/1/445/32794739211_d6f5324607_o.jpg,0,0,0.75,1,859,753,http://www.flickr.com/photos/callmewhatever/32794739211/,https://creativecommons.org/licenses/by/2.0/,Daniel Zimmermann,https://www.flickr.com/people/callmewhatever/
83d35591dfff99ac,https://c1.staticflickr.com/8/7232/27285496573_d5bdd3aa87_o.jpg,0,0,0.75,1,581,857,https://www.flickr.com/photos/juggernautco/27285496573,https://creativecommons.org/licenses/by/2.0/,Daniel X. O'Neil,https://www.flickr.com/people/juggernautco/
3dfbdd066af9ca1e,https://c1.staticflickr.com/9/8816/28135299942_b870fd0ab6_o.jpg,0.25,0,0.75,0.75,821,5,https://www.flickr.com/photos/ben_salter/28135299942/,https://creativecommons.org/licenses/by/2.0/,Ben Salter,https://www.flickr.com/people/ben_salter/
59204d6bb0c234eb,https://c1.staticflickr.com/9/8752/28207273334_3d05b11ea6_o.jpg,0,0.421177267,0.75,0.842354533,418,703,https://www.flickr.com/photos/oatsy40/28207273334/,https://creativecommons.org/licenses/by/2.0/,oatsy40,https://www.flickr.com/people/oatsy40/
d740663eeccdcecd,https://c1.staticflickr.com/9/8130/29191810554_9f08be9c5f_o.jpg,0,0,0.75,0.5625,438,762,https://www.flickr.com/photos/simon2207/29191810554/,https://creativecommons.org/licenses/by/2.0/,Simon220771,https://www.flickr.com/people/simon2207/
9226b783cfb770bd,https://c1.staticflickr.com/9/8637/28516867321_5b709d78c7_o.jpg,0,0.25,0.5625,1,826,34,https://www.flickr.com/photos/jsjgeology/28516867321,https://creativecommons.org/licenses/by/2.0/,James St. John,https://www.flickr.com/people/jsjgeology/
01dd15caa1b2c7b4,https://c1.staticflickr.com/8/7767/26780389003_e95a6d7cee_o.jpg,0,0.25,0.561328125,1,304,551,https://www.flickr.com/photos/treegrow/26780389003,https://creativecommons.org/licenses/by/2.0/,Katja Schulz,https://www.flickr.com/people/treegrow/
b97f4b95ae696316,https://c1.staticflickr.com/8/7186/26690393874_7d7f8dafc9_o.jpg,0,0.333333333,1,1,518,399,http://www.flickr.com/photos/n28307/26690393874/,https://creativecommons.org/licenses/by/2.0/,Glenn Beltz,https://www.flickr.com/people/n28307/
c42c88890b5fc86d,https://c1.staticflickr.com/6/5755/30476251310_f45f8b81b7_o.jpg,0.4375,0.25,1,1,671,112,https://www.flickr.com/photos/paulmiller/30476251310/,https://creativecommons.org/licenses/by/2.0/,Paul Miller,https://www.flickr.com/people/paulmiller/
d158837db31ed892,https://c1.staticflickr.com/1/445/31796400213_c6e650f7d5_o.jpg,0.5,0,1,0.75,519,804,https://www.flickr.com/photos/box_repsol/31796400213,https://creativecommons.org/licenses/by/2.0/,Box Repsol,https://www.flickr.com/people/box_repsol/
4a1a40a116088962,https://c1.staticflickr.com/9/8587/28162416971_8e105a5657_o.jpg,0,0,0.75,1,598,624,https://www.flickr.com/photos/gibsongunleather/28162416971,https://creativecommons.org/licenses/by/2.0/,BRUCE GIBSON,https://www.flickr.com/people/gibsongunleather/
ba4508962af69d90,https://c1.staticflickr.com/9/8202/29005733052_a9f711f4bf_o.jpg,0.248348018,0,0.745044053,0.75,673,827,https://flickr.com/37922399@N05/29005733052,https://creativecommons.org/licenses/by/2.0/,Virginia State Parks,https://www.flickr.com/people/vastateparksstaff/
7069a117c92d27a4,https://c1.staticflickr.com/8/7605/26251509774_96c84ae16f_o.jpg,0.421747967,0.25,0.843495935,1,546,186,https://www.flickr.com/photos/psychlist1972/26251509774/,https://creativecommons.org/licenses/by/2.0/,Pete Brown,https://www.flickr.com/people/psychlist1972/
79fa9855119ffeea,https://c1.staticflickr.com/9/8090/28857580530_b7ba1ea2f1_o.jpg,0,0,1,1,479,506,https://www.flickr.com/photos/wwworks/28857580530,https://creativecommons.org/licenses/by/2.0/,woodleywonderworks,https://www.flickr.com/people/wwworks/
82e2334925339ef8,https://c1.staticflickr.com/6/5632/31268100236_4975f1a2db_o.jpg,0.25,0,1,0.75,818,769,https://www.flickr.com/photos/96774554@N03/31268100236,https://creativecommons.org/licenses/by/2.0/,Wheels ON,https://www.flickr.com/people/96774554@N03/
4f5464b7d4682441,https://c1.staticflickr.com/3/2859/32842901716_635c080982_o.jpg,0,0.25,0.47277937,1,976,607,https://www.flickr.com/photos/blmoregon/32842901716/,https://creativecommons.org/licenses/by/2.0/,Bureau of Land Management Oregon and Washington,https://www.flickr.com/people/blmoregon/
72f96c6dc5df2de8,https://c1.staticflickr.com/4/3869/32108968233_aa2d42d481_o.jpg,0.5,0.25,1,1,885,784,https://www.flickr.com/photos/jlascar/32108968233/,https://creativecommons.org/licenses/by/2.0/,Jorge L\303\241scar,https://www.flickr.com/people/jlascar/
6609c25b3314b5b3,https://c1.staticflickr.com/9/8031/29690105171_f0e16e643e_o.jpg,0.333333333,0,1,1,512,878,https://www.flickr.com/photos/8782469@N05/29690105171,https://creativecommons.org/licenses/by/2.0/,Graham Robertson,https://www.flickr.com/people/8782469@N05/
52d8515abbfaa8ac,https://c1.staticflickr.com/6/5629/30139827383_2b90e9254e_o.jpg,0.496696035,0,0.99339207,0.75,230,634,https://www.flickr.com/photos/vastateparksstaff/30139827383,https://creativecommons.org/licenses/by/2.0/,Virginia State Parks,https://www.flickr.com/people/vastateparksstaff/
a7f9b28e30d19d85,https://c1.staticflickr.com/6/5712/30477407072_911714e259_o.jpg,0,0,0.504444444,0.75,662,699,https://www.flickr.com/photos/andreboeni/30477407072,https://creativecommons.org/licenses/by/2.0/,Andrew Bone,https://www.flickr.com/people/andreboeni/
8b7a5446dae48ac1,https://c1.staticflickr.com/1/316/31908704910_2c6375f0ef_o.jpg,0.266552511,0,0.799657534,0.75,309,363,https://www.flickr.com/photos/gails_pictures/31908704910,https://creativecommons.org/licenses/by/2.0/,gailhampshire,https://www.flickr.com/people/gails_pictures/
b2a7e558f1a3ff16,https://c1.staticflickr.com/9/8730/28819631221_819c793b59_o.jpg,0.303165584,0.25,0.909496753,1,620,536,https://www.flickr.com/photos/raveejaya/28819631221,https://creativecommons.org/licenses/by/2.0/,Raveendra Jayashantha,https://www.flickr.com/people/raveejaya/
1a95932427129cda,https://c1.staticflickr.com/8/7124/27017461135_e00ed6ac0d_o.jpg,0,0.25,0.5,1,657,465,https://www.flickr.com/photos/antoniseb/27017461135/,https://creativecommons.org/licenses/by/2.0/,Jay Cross,https://www.flickr.com/people/antoniseb/
d4579363596fbf21,https://c1.staticflickr.com/1/520/31675116444_127982bddf_o.jpg,0.287322275,0,0.861966825,0.75,833,889,https://www.flickr.com/photos/fran001/31675116444/,https://creativecommons.org/licenses/by/2.0/,Francisco Anzola,https://www.flickr.com/people/fran001/
f7dd570a0cfe1dcc,https://c1.staticflickr.com/9/8264/29543383031_e6d047580a_o.jpg,0,0,0.75,0.75,669,55,https://www.flickr.com/photos/alazaat/29543383031,https://creativecommons.org/licenses/by/2.0/,Hussein Alazaat,https://www.flickr.com/people/alazaat/
2d23b1dab7e3e9c0,https://c1.staticflickr.com/1/456/31638318370_25bb9334d8_o.jpg,0,0.25,0.5,1,511,971,https://www.flickr.com/photos/45958601@N02/31638318370,https://creativecommons.org/licenses/by/2.0/,joey zanotti,https://www.flickr.com/people/45958601@N02/
b7d9e1d8cf1d7912,https://c1.staticflickr.com/6/5697/30316954084_6b364b382d_o.jpg,0,0,0.666666667,1,519,485,https://www.flickr.com/photos/box_repsol/30316954084,https://creativecommons.org/licenses/by/2.0/,Box Repsol,https://www.flickr.com/people/box_repsol/
6b27728f0f816dc6,https://c1.staticflickr.com/1/483/32823130292_df26e1cd49_o.jpg,0,0.25,0.499263623,1,638,874,https://www.flickr.com/photos/rpavich/32823130292/,https://creativecommons.org/licenses/by/2.0/,rpavich,https://www.flickr.com/people/rpavich/
c96358fe7b8eaf28,https://c1.staticflickr.com/8/7262/27455525114_9b1d3ed1ac_o.jpg,0.578822733,0.25,1,1,706,492,https://www.flickr.com/photos/12216515@N00/27455525114,https://creativecommons.org/licenses/by/2.0/,Charles Fulton,https://www.flickr.com/people/12216515@N00/
9b4cab2ffb0c0754,https://c1.staticflickr.com/9/8256/30009146415_d412513e5f_o.jpg,0,0,1,0.75,975,963,https://www.flickr.com/photos/jsjgeology/30009146415,https://creativecommons.org/licenses/by/2.0/,James St. John,https://www.flickr.com/people/jsjgeology/
1685d066f8070081,https://c1.staticflickr.com/6/5684/29941070052_c4c12092e6_o.jpg,0,0,0.421747967,0.75,979,361,https://www.flickr.com/photos/scotnelson/29941070052,https://creativecommons.org/licenses/by/2.0/,Scot Nelson,https://www.flickr.com/people/scotnelson/
e071bf346787d971,https://c1.staticflickr.com/8/7244/27006991522_4a72303846_o.jpg,0.578252033,0.25,1,1,563,990,https://www.flickr.com/photos/respres/27006991522,https://creativecommons.org/licenses/by/2.0/,Jeff Turner,https://www.flickr.com/people/respres/
e66d732354c6baf0,https://c1.staticflickr.com/9/8349/29382034812_b8cca8606d_o.jpg,0,0,0.5,0.75,301,72,https://www.flickr.com/photos/52450054@N04/29382034812,https://creativecommons.org/licenses/by/2.0/,Judy Gallagher,https://www.flickr.com/people/52450054@N04/
33adbc27fdcadd65,https://c1.staticflickr.com/8/7130/26834523912_fb0b3fe3ed_o.jpg,0.28125,0.25,0.84375,1,924,716,https://www.flickr.com/photos/68147320@N02/26834523912,https://creativecommons.org/licenses/by/2.0/,T.Tseng,https://www.flickr.com/people/68147320@N02/
eb53098ebcf05e64,https://c1.staticflickr.com/6/5591/30938192751_f6a6fb1739_o.jpg,0,0,0.641099855,1,564,601,https://www.flickr.com/photos/68704638@N04/30938192751,https://creativecommons.org/licenses/by/2.0/,M Dreibelbis,https://www.flickr.com/people/68704638@N04/
8c609b06a60af060,https://c1.staticflickr.com/8/7199/27864572096_73f40f5d09_o.jpg,0,0,0.5625,0.75,499,291,https://flickr.com/77742560@N06/27864572096,https://creativecommons.org/licenses/by/2.0/,shankar s.,https://www.flickr.com/people/shankaronline/
c66310d8b709d6d5,https://c1.staticflickr.com/9/8371/29266955473_d24ddfa05c_o.jpg,0,0,1,1,763,106,https://www.flickr.com/photos/alper/29266955473,https://creativecommons.org/licenses/by/2.0/,Alper \303\207u\304\237un,https://www.flickr.com/people/alper/
740981d161a38bad,https://c1.staticflickr.com/1/578/32214662255_3bc38af004_o.jpg,0.5,0,1,0.75,572,149,http://www.flickr.com/photos/batcula/32214662255/,https://creativecommons.org/licenses/by/2.0/,Jim,https://www.flickr.com/people/batcula/
4c8a4414419ab0bb,https://c1.staticflickr.com/9/8377/30076813705_00b7bc68ff_o.jpg,0.25,0,0.75,0.75,662,848,https://www.flickr.com/photos/greggjerdingen/30076813705,https://creativecommons.org/licenses/by/2.0/,Greg Gjerdingen,https://www.flickr.com/people/greggjerdingen/
ecaf98c8ce9f04c3,https://c1.staticflickr.com/9/8547/29609780616_f9dac2244e_o.jpg,0.5,0.25,1,1,561,697,https://www.flickr.com/photos/foran_hs_football/29609780616,https://creativecommons.org/licenses/by/2.0/,Foran Lions Football,https://www.flickr.com/people/foran_hs_football/
093402dc35f59027,https://c1.staticflickr.com/9/8708/28528193204_59181c883b_o.jpg,0.4375,0,1,0.75,734,113,https://www.flickr.com/photos/kdghantous/28528193204,https://creativecommons.org/licenses/by/2.0/,Karim D. Ghantous,https://www.flickr.com/people/kdghantous/
8bb7d10e97694eb5,https://c1.staticflickr.com/1/625/31772996983_1b99ed5012_o.jpg,0.42535545,0,1,0.75,143,393,https://www.flickr.com/photos/taylar/31772996983,https://creativecommons.org/licenses/by/2.0/,Ingrid Taylar,https://www.flickr.com/people/taylar/
820ae900a943d605,https://c1.staticflickr.com/6/5486/30611700582_b302428c5d_o.jpg,0,0.267938931,0.75,0.803816794,888,701,http://www.flickr.com/photos/ecdq/30611700582/,https://creativecommons.org/licenses/by/2.0/,ECDQ,https://www.flickr.com/people/ecdq/
8859efd46fab37ff,https://c1.staticflickr.com/6/5646/30929275820_fc732d7ae6_o.jpg,0.25,0,1,0.75,923,599,https://flickr.com/145862860@N07/30929275820,https://creativecommons.org/licenses/by/2.0/,Ky\305\215to B\305\215ken,https://www.flickr.com/people/kyotoboken/
dde9f0aadcb02874,https://c1.staticflickr.com/9/8544/29151973710_8ab6e884c9_o.jpg,0.497426471,0,0.994852941,0.75,981,640,https://www.flickr.com/photos/n28307/29151973710,https://creativecommons.org/licenses/by/2.0/,Glenn Beltz,https://www.flickr.com/people/n28307/
13810fcac72f12ba,https://c1.staticflickr.com/9/8302/28623258764_c87251b710_o.jpg,0,0.25,0.5,1,876,72,https://www.flickr.com/photos/usarmyband/28623258764/,https://creativecommons.org/licenses/by/2.0/,The United States Army Band,https://www.flickr.com/people/usarmyband/
b1bf532ce2c4c3a1,https://c1.staticflickr.com/9/8037/28132989550_04e5549aec_o.jpg,0,0,0.495594714,0.75,875,557,https://www.flickr.com/photos/didbygraham/28132989550/,https://creativecommons.org/licenses/by/2.0/,Graham Richardson,https://www.flickr.com/people/didbygraham/
9aba31a4b2404aa5,https://c1.staticflickr.com/1/458/31850811716_9a5882c71c_o.jpg,0.25,0.25,1,1,912,495,https://flickr.com/52066925@N00/31850811716,https://creativecommons.org/licenses/by/2.0/,anneheathen,https://www.flickr.com/people/annethelibrarian/
5b85f98e0105d135,https://c1.staticflickr.com/8/7474/26833993115_f16054e784_o.jpg,0.248713235,0.25,0.746139706,1,570,933,https://www.flickr.com/photos/agenciabrasilia/26833993115,https://creativecommons.org/licenses/by/2.0/,Ag\303\252ncia Bras\303\255lia,https://www.flickr.com/people/agenciabrasilia/
53c478ffc8ddb967,https://c1.staticflickr.com/9/8149/29031351804_3d4e158245_o.jpg,0.225840336,0,0.677521008,0.75,320,613,https://www.flickr.com/photos/gails_pictures/29031351804,https://creativecommons.org/licenses/by/2.0/,gailhampshire,https://www.flickr.com/people/gails_pictures/
92c3f5e99d8ac862,https://c1.staticflickr.com/8/7564/29085116541_43b6dfd46c_o.jpg,0,0,0.666666667,1,664,362,https://www.flickr.com/photos/ministeriodacultura/29085116541/,https://creativecommons.org/licenses/by/2.0/,Minist\303\251rio da Cultura,https://www.flickr.com/people/ministeriodacultura/
fae45093bad0961a,https://c1.staticflickr.com/9/8802/30042939706_809382f8e8_o.jpg,0,0,0.499263623,0.75,529,528,https://www.flickr.com/photos/southbeachcars/30042939706,https://creativecommons.org/licenses/by/2.0/,Phillip Pessar,https://www.flickr.com/people/southbeachcars/
0db0952967f6faa6,https://c1.staticflickr.com/6/5610/31207151522_a9d8ef4c85_o.jpg,0.28125,0,0.84375,0.75,816,552,https://flickr.com/29780474@N02/31207151522,https://creativecommons.org/licenses/by/2.0/,Phil Gayton,https://www.flickr.com/people/29780474@N02/
9594ef7e0fc79ea8,https://c1.staticflickr.com/8/7720/26955054100_0d18b0786b_o.jpg,0.25,0.25,1,1,403,115,https://www.flickr.com/photos/87249144@N08/26955054100,https://creativecommons.org/licenses/by/2.0/,FolsomNatural,https://www.flickr.com/people/87249144@N08/
634d7f18d098cccb,https://c1.staticflickr.com/6/5599/30385514465_e5bb5b1ec4_o.jpg,0,0.332106038,1,0.996318115,539,766,https://www.flickr.com/photos/londonmatt/30385514465,https://creativecommons.org/licenses/by/2.0/,Matt Brown,https://www.flickr.com/people/londonmatt/
05cac1419419ce29,https://c1.staticflickr.com/3/2904/33166177915_2cf2b8ed63_o.jpg,0,0.25,0.5,1,854,550,https://www.flickr.com/photos/yangchen6712/33166177915,https://creativecommons.org/licenses/by/2.0/,YangChen(TW),https://www.flickr.com/people/yangchen6712/
868af4a2e614f5ac,https://c1.staticflickr.com/9/8284/29515310871_0dd41b4840_o.jpg,0.25,0,0.75,0.75,718,467,https://www.flickr.com/photos/greggjerdingen/29515310871,https://creativecommons.org/licenses/by/2.0/,Greg Gjerdingen,https://www.flickr.com/people/greggjerdingen/
6898f889c17f8e16,https://c1.staticflickr.com/6/5683/31789036413_516df80786_o.jpg,0.25,0.250923191,1,0.752769572,888,730,https://www.flickr.com/photos/eltb/31789036413,https://creativecommons.org/licenses/by/2.0/,Catedrales e Iglesias/Cathedrals and Churches,https://www.flickr.com/people/eltb/
8e3324c208eb9a3b,https://c1.staticflickr.com/1/358/32563010712_d1417f0485_o.jpg,0,0,0.561328125,0.75,822,741,https://www.flickr.com/photos/linsinchen/32563010712,https://creativecommons.org/licenses/by/2.0/,Sinchen.Lin,https://www.flickr.com/people/linsinchen/
7d7a8e41b8d0577e,https://c1.staticflickr.com/6/5518/30395077313_019dca3b01_o.jpg,0.25,0,1,0.75,965,182,https://flickr.com/83202873@N00/30395077313,https://creativecommons.org/licenses/by/2.0/,smittenkittenorig,https://www.flickr.com/people/smittenkittenoriginals/
5ff168f7d006f69c,https://c1.staticflickr.com/1/506/31115729834_fc93bbea0f_o.jpg,0,0.25,0.5625,1,683,106,https://flickr.com/45457437@N00/31115729834,https://creativecommons.org/licenses/by/2.0/,David Jones,https://www.flickr.com/people/davidcjones/
f348adf7ea1967f7,https://c1.staticflickr.com/9/8769/29760593836_4e7c8ebbda_o.jpg,0.5,0.25,1,1,909,415,https://www.flickr.com/photos/fun_flying/29760593836/,https://creativecommons.org/licenses/by/2.0/,D. Miller,https://www.flickr.com/people/fun_flying/
40f79488e3c2d6c4,https://c1.staticflickr.com/8/7433/27742701310_08f79aaeb0_o.jpg,0,0.247434018,0.75,0.742302053,918,749,https://www.flickr.com/photos/mdpettitt/27742701310,https://creativecommons.org/licenses/by/2.0/,Martin Pettitt,https://www.flickr.com/people/mdpettitt/
3e9496f7652e1968,https://c1.staticflickr.com/6/5503/30144665264_862fd303dc_o.jpg,0,0,0.666666667,1,469,834,http://www.flickr.com/photos/27148401@N06/30144665264,https://creativecommons.org/licenses/by/2.0/,shipley43,https://www.flickr.com/people/27148401@N06/
2f7d5ff922af55c4,https://c1.staticflickr.com/9/8171/28748561034_d77c5db28e_o.jpg,0.475453172,0.25,1,1,481,633,https://www.flickr.com/photos/jeepersmedia/28748561034,https://creativecommons.org/licenses/by/2.0/,Mike Mozart,https://www.flickr.com/people/jeepersmedia/
79a5625805a08253,https://c1.staticflickr.com/8/7622/26950982570_224d340d99_o.jpg,0,0.25,0.498159057,1,766,805,https://www.flickr.com/photos/vastateparksstaff/26950982570,https://creativecommons.org/licenses/by/2.0/,Virginia State Parks,https://www.flickr.com/people/vastateparksstaff/
412311ea17528b7c,https://c1.staticflickr.com/6/5553/31345581012_51f411cd78_o.jpg,0.25,0,0.75,0.75,764,440,https://www.flickr.com/photos/quinet/31345581012/,https://creativecommons.org/licenses/by/2.0/,Thomas Quine,https://www.flickr.com/people/quinet/
00312c7e7196baf4,https://c1.staticflickr.com/9/8539/29256709000_ca71fa227f_o.jpg,0.25,0.28125,1,0.84375,327,220,http://www.flickr.com/photos/27305106@N06/29256709000,https://creativecommons.org/licenses/by/2.0/,Charlie Jackson,https://www.flickr.com/people/chaz_pics/
51d1c77f80467b59,https://c1.staticflickr.com/6/5555/31034796165_c8996cacff_o.jpg,0.329178886,0,0.987536657,1,977,538,https://www.flickr.com/photos/zemzina/31034796165/,https://creativecommons.org/licenses/by/2.0/,Olga Khomitsevich,https://www.flickr.com/people/zemzina/
82179b1d313e0e23,https://c1.staticflickr.com/1/268/32350804376_10b1f40d6e_o.jpg,0,0,0.5625,0.75,830,902,https://www.flickr.com/photos/76969036@N02/32350804376/,https://creativecommons.org/licenses/by/2.0/,David Guo,https://www.flickr.com/people/76969036@N02/
b0e0e06e647b478f,https://c1.staticflickr.com/6/5769/29834734204_b8897fa3f7_o.jpg,0,0,1,0.751173709,484,915,https://www.flickr.com/photos/sky_hlv/29834734204,https://creativecommons.org/licenses/by/2.0/,Jose A.,https://www.flickr.com/people/sky_hlv/
c609f86fa706bb9e,https://c1.staticflickr.com/9/8552/29601011844_a32bf06fd2_o.jpg,0,0,0.5625,0.75,113,889,https://www.flickr.com/photos/fdecomite/29601011844/,https://creativecommons.org/licenses/by/2.0/,fdecomite,https://www.flickr.com/people/fdecomite/
55a2e48a87c16998,https://c1.staticflickr.com/1/660/31687904441_5798b661c4_o.jpg,0.25,0,0.75,0.75,911,768,http://www.flickr.com/photos/wastes/31687904441/,https://creativecommons.org/licenses/by/2.0/,Charlotta Wasteson,https://www.flickr.com/people/wastes/
7d833ac8ab852bd2,https://c1.staticflickr.com/1/536/31504100213_b2b24c3f0d_o.jpg,0.25,0.442757009,1,1,52,151,https://www.flickr.com/photos/jsjgeology/31504100213,https://creativecommons.org/licenses/by/2.0/,James St. John,https://www.flickr.com/people/jsjgeology/
fe92a88132b5d67b,https://c1.staticflickr.com/6/5127/30101893166_db47d4701a_o.jpg,0.25,0.25,0.75,1,963,247,https://flickr.com/112540417@N03/30101893166,https://creativecommons.org/licenses/by/2.0/,Enrico BBQness,https://www.flickr.com/people/bbqnessdotcom/
6ab876a15af539c4,https://c1.staticflickr.com/9/8869/28304826635_f4c6b9f7d7_o.jpg,0.25,0.28125,1,0.84375,984,611,https://www.flickr.com/photos/noaaphotolib/28304826635,https://creativecommons.org/licenses/by/2.0/,NOAA Photo Library,https://www.flickr.com/people/noaaphotolib/
4fff343244f212cc,https://c1.staticflickr.com/6/5774/31301114735_677b0f08fa_o.jpg,0,0.305872757,0.75,0.917618271,821,403,https://www.flickr.com/photos/45131642@N00/31301114735/,https://creativecommons.org/licenses/by/2.0/,Phil Parker,https://www.flickr.com/people/45131642@N00/
22a9c318b6e36853,https://c1.staticflickr.com/9/8016/29443140000_36cbb76243_o.jpg,0.249079529,0.25,0.747238586,1,620,211,https://www.flickr.com/photos/51715344@N07/29443140000/,https://creativecommons.org/licenses/by/2.0/,kami rao,https://www.flickr.com/people/51715344@N07/
71d368782c72e313,https://c1.staticflickr.com/8/7431/27233705735_358064269d_o.jpg,0,0,0.599757674,0.75,913,487,https://www.flickr.com/photos/mspearman/27233705735,https://creativecommons.org/licenses/by/2.0/,Mark Spearman,https://www.flickr.com/people/mspearman/
65b8c8b065069802,https://c1.staticflickr.com/8/7116/26898609074_1eab8aeb4b_o.jpg,0.25,0.25,0.75,1,666,379,https://www.flickr.com/photos/sg2012/26898609074/,https://creativecommons.org/licenses/by/2.0/,Steve Glover,https://www.flickr.com/people/sg2012/
b0619a61cf135f5e,https://c1.staticflickr.com/8/7408/27239703215_11f55dc09e_o.jpg,0.345588235,0,0.691176471,0.75,985,420,https://www.flickr.com/photos/126816719@N03/27239703215/,https://creativecommons.org/licenses/by/2.0/,Jon Brinn,https://www.flickr.com/people/126816719@N03/
93394c1f9c4c0053,https://c1.staticflickr.com/9/8065/27937528884_57f0526c15_o.jpg,0.5,0.25,1,1,320,883,https://www.flickr.com/photos/52450054@N04/27937528884,https://creativecommons.org/licenses/by/2.0/,Judy Gallagher,https://www.flickr.com/people/52450054@N04/
aa90f93ed6fae139,https://c1.staticflickr.com/1/577/32316961601_cd6d1ed035_o.jpg,0,0,0.75,0.75,310,828,https://www.flickr.com/photos/orangeaurochs/32316961601,https://creativecommons.org/licenses/by/2.0/,Orangeaurochs,https://www.flickr.com/people/orangeaurochs/
aa07ba1587ec047e,https://c1.staticflickr.com/9/8576/29046638172_6468dd6b89_o.jpg,0.4375,0,1,0.75,469,900,https://www.flickr.com/photos/stephenk1977/29046638172,https://creativecommons.org/licenses/by/2.0/,stephenk1977,https://www.flickr.com/people/stephenk1977/
5d8085ae68e07d72,https://c1.staticflickr.com/8/7049/27394318535_a8c7ccdeb8_o.jpg,0,0.28125,0.75,0.84375,709,643,https://www.flickr.com/photos/zongo/27394318535,https://creativecommons.org/licenses/by/2.0/,DAVID HOLT,https://www.flickr.com/people/zongo/
749ed3502293d019,https://c1.staticflickr.com/9/8356/29415192905_173fbf26da_o.jpg,0,0.330871492,1,1,475,578,https://www.flickr.com/photos/romitagirl67/29415192905/,https://creativecommons.org/licenses/by/2.0/,RomitaGirl67,https://www.flickr.com/people/romitagirl67/
791c3d333052ca64,https://c1.staticflickr.com/9/8440/29197626174_134d6fd15f_o.jpg,0,0,0.5625,0.75,964,908,https://www.flickr.com/photos/cbroders/29197626174,https://creativecommons.org/licenses/by/2.0/,Counse,https://www.flickr.com/people/cbroders/
90e9a43bfb6a68b7,https://c1.staticflickr.com/9/8865/28740349711_5758bc82f4_o.jpg,0,0,0.5,0.75,867,476,https://www.flickr.com/photos/iowapipe/28740349711,https://creativecommons.org/licenses/by/2.0/,IowaPipe,https://www.flickr.com/people/iowapipe/
72e6ba0cc7fb30a6,https://c1.staticflickr.com/9/8270/29053097670_b2b9f42c1f_o.jpg,0.28125,0,0.84375,0.75,875,834,https://www.flickr.com/photos/aswans1234567/29053097670,https://creativecommons.org/licenses/by/2.0/,Alex Swanston's Bus Photos,https://www.flickr.com/people/aswans1234567/
8c5b5bc0f39e2e06,https://c1.staticflickr.com/9/8767/28247360751_7c466f8efc_o.jpg,0.421177267,0.25,0.842354533,1,898,253,https://www.flickr.com/photos/brandedbulltank/28247360751/,https://creativecommons.org/licenses/by/2.0/,Tank,https://www.flickr.com/people/brandedbulltank/
cc43200264a62126,https://c1.staticflickr.com/8/7447/27965290502_73c8417ef8_o.jpg,0.25,0,0.75,0.75,981,590,https://www.flickr.com/photos/naql/27965290502,https://creativecommons.org/licenses/by/2.0/,naql,https://www.flickr.com/people/naql/
be95f5be87f6fadd,https://c1.staticflickr.com/6/5721/30814461816_67e70a5169_o.jpg,0.28125,0,0.84375,0.75,459,603,https://www.flickr.com/photos/davidwilson1949/30814461816/,https://creativecommons.org/licenses/by/2.0/,David Wilson,https://www.flickr.com/people/davidwilson1949/
7b6e963025eaeb66,https://c1.staticflickr.com/1/316/31606962904_b2666a8780_o.jpg,0.331617647,0,0.994852941,1,994,660,https://flickr.com/62788663@N04/31606962904,https://creativecommons.org/licenses/by/2.0/,Martin Jambon,https://www.flickr.com/people/mjambon/
7f842d0c1e747334,https://c1.staticflickr.com/8/7634/27141449325_4f1a76c3ed_o.jpg,0,0,1,1,305,796,https://www.flickr.com/photos/78428166@N00/27141449325,https://creativecommons.org/licenses/by/2.0/,Tony Alter,https://www.flickr.com/people/78428166@N00/
ed3cb7f5154ae02d,https://c1.staticflickr.com/9/8072/29900375851_914813808d_o.jpg,0.245255474,0.25,0.735766423,1,980,747,https://www.flickr.com/photos/col_and_tasha/29900375851,https://creativecommons.org/licenses/by/2.0/,Col Ford and Natasha de Vere,https://www.flickr.com/people/col_and_tasha/
6ecbd7d19f5b9147,https://c1.staticflickr.com/9/8737/28811659522_a0d4210243_o.jpg,0,0,0.483695652,0.75,596,423,https://www.flickr.com/photos/robdammers/28811659522/,https://creativecommons.org/licenses/by/2.0/,Rob Dammers,https://www.flickr.com/people/robdammers/
d016b3204e7ca96e,https://c1.staticflickr.com/9/8558/29643762441_5e78f77661_o.jpg,0,0,0.75,1,792,778,https://flickr.com/39160147@N03/29643762441,https://creativecommons.org/licenses/by/2.0/,Mike Mozart,https://www.flickr.com/people/jeepersmedia/
8400742ba78ac009,https://c1.staticflickr.com/9/8544/28451617274_58e56a03de_o.jpg,0,0,0.666666667,1,971,671,https://www.flickr.com/photos/blackwing_de/28451617274,https://creativecommons.org/licenses/by/2.0/,Sebastian Werner,https://www.flickr.com/people/blackwing_de/
121c87c3c822e2c5,https://c1.staticflickr.com/1/750/31463784832_7a3c075877_o.jpg,0.25,0.25,0.75,1,459,386,https://www.flickr.com/photos/quinet/31463784832,https://creativecommons.org/licenses/by/2.0/,Thomas Quine,https://www.flickr.com/people/quinet/
76886996d4ab4614,https://c1.staticflickr.com/9/8192/28493603004_1b628ae8e9_o.jpg,0,0.25,0.5625,1,975,763,https://www.flickr.com/photos/jsjgeology/28493603004,https://creativecommons.org/licenses/by/2.0/,James St. John,https://www.flickr.com/people/jsjgeology/
9d5ef11ec55123e5,https://c1.staticflickr.com/9/8872/27883604363_8cf68f0178_o.jpg,0,0.25,0.577654517,1,100,513,http://www.flickr.com/photos/dangrothe/27883604363/,https://creativecommons.org/licenses/by/2.0/,Daniel Grothe,https://www.flickr.com/people/dangrothe/
1dfbeffd999f280e,https://c1.staticflickr.com/9/8433/28830160583_6bc4405a04_o.jpg,0.181375628,0,0.544126884,0.75,582,569,https://www.flickr.com/photos/mauritsverbiest/28830160583,https://creativecommons.org/licenses/by/2.0/,Maurits Verbiest,https://www.flickr.com/people/mauritsverbiest/
e3f5dbed7bd31314,https://c1.staticflickr.com/8/7682/27343823144_eeaa9065cb_o.jpg,0.25,0.5,1,1,547,864,https://www.flickr.com/photos/barnimages/27343823144,https://creativecommons.org/licenses/by/2.0/,barnimages.com,https://www.flickr.com/people/barnimages/
eb8ce5ba5c47e344,https://c1.staticflickr.com/1/684/33351191226_792c561fd4_o.jpg,0,0,0.75,0.5625,669,893,https://flickr.com/126397594@N03/33351191226,https://creativecommons.org/licenses/by/2.0/,G\303\274ldem \303\234st\303\274n,https://www.flickr.com/people/guldem/
f5dffe28fc19b6e7,https://c1.staticflickr.com/6/5529/31290944551_78ff48d9a3_o.jpg,0.266071429,0.25,1,1,918,730,https://flickr.com/91873856@N00/31290944551,https://creativecommons.org/licenses/by/2.0/,Phil Venditti,https://www.flickr.com/people/venditti_min_min-venditti/
1ebff1b3c8de66de,https://c1.staticflickr.com/9/8551/29684108315_b9b08f8035_o.jpg,0.464122137,0.25,1,1,337,810,https://www.flickr.com/photos/ruthanddave/29684108315,https://creativecommons.org/licenses/by/2.0/,Ruth Hartnup,https://www.flickr.com/people/ruthanddave/
0546b47c13f154d3,https://c1.staticflickr.com/1/744/31706873925_eb85a4c572_o.jpg,0,0,0.976785714,1,108,318,https://www.flickr.com/photos/92252798@N07/31706873925,https://creativecommons.org/licenses/by/2.0/,Dick Culbert,https://www.flickr.com/people/92252798@N07/
f52db15134c1a74e,https://c1.staticflickr.com/6/5628/30300134543_71291f4050_o.jpg,0,0,1,1,638,776,https://flickr.com/13894201@N00/30300134543,https://creativecommons.org/licenses/by/2.0/,\303\201d\303\241m Szedl\303\241k,https://www.flickr.com/people/kelt/
8094d4088a08cf09,https://c1.staticflickr.com/1/725/31560908483_4276d9241c_o.jpg,0,0,0.666666667,1,441,615,https://www.flickr.com/photos/allagashbrewing/31560908483/,https://creativecommons.org/licenses/by/2.0/,Allagash Brewing,https://www.flickr.com/people/allagashbrewing/
d9f624188d16fe93,https://c1.staticflickr.com/8/7402/27067928760_efcb66d26f_o.jpg,0.25,0.25,0.75,1,40,602,https://www.flickr.com/photos/juliofromero/27067928760,https://creativecommons.org/licenses/by/2.0/,Julio Romero,https://www.flickr.com/people/juliofromero/
631b6820e91a9e3e,https://c1.staticflickr.com/3/2183/32694281652_62b0c63d26_o.jpg,0.333333333,0,1,1,13,303,https://www.flickr.com/photos/wildreturn/32694281652/,https://creativecommons.org/licenses/by/2.0/,Andy Reago & Chrissy McClarren,https://www.flickr.com/people/wildreturn/
611f453c4bb616b9,https://c1.staticflickr.com/8/7494/27095667650_2158e5d0a3_o.jpg,0.25,0.25,0.75,1,310,65,https://www.flickr.com/photos/gaby1/27095667650,https://creativecommons.org/licenses/by/2.0/,Gabriel Gonz\303\241lez,https://www.flickr.com/people/gaby1/
5792d4a42d2a82c8,https://c1.staticflickr.com/9/8655/30162044361_628a8758b1_o.jpg,0,0,1,1,988,419,https://flickr.com/51966661@N00/30162044361,https://creativecommons.org/licenses/by/2.0/,valerialaura,https://www.flickr.com/people/valerialaura/
c0e0c11350b8740e,https://c1.staticflickr.com/9/8316/28819944676_84ab998606_o.jpg,0,0,0.741835148,1,319,698,https://www.flickr.com/photos/gails_pictures/28819944676,https://creativecommons.org/licenses/by/2.0/,gailhampshire,https://www.flickr.com/people/gails_pictures/
c663670c06c06ea4,https://c1.staticflickr.com/6/5671/30978227515_c8c43aa172_o.jpg,0,0.248826291,1,1,909,903,http://www.flickr.com/photos/verzo/30978227515/,https://creativecommons.org/licenses/by/2.0/,Roberto Verzo,https://www.flickr.com/people/verzo/
49591319edeb6b3a,https://c1.staticflickr.com/8/7379/28056205761_56dc8a13a9_o.jpg,0.333333333,0,1,1,309,416,https://www.flickr.com/photos/104342908@N08/28056205761,https://creativecommons.org/licenses/by/2.0/,Michael Mueller,https://www.flickr.com/people/104342908@N08/
02eb799d147d5f91,https://c1.staticflickr.com/8/7461/27924109056_3f35c44ec8_o.jpg,0,0,0.5,0.75,625,773,https://www.flickr.com/photos/vvbad/27924109056/,https://creativecommons.org/licenses/by/2.0/,VVBAD,https://www.flickr.com/people/vvbad/
f2d36d089779166a,https://c1.staticflickr.com/8/7528/27618132235_3bd6c10788_o.jpg,0,0.25,0.503698225,1,349,805,https://www.flickr.com/photos/eljay/27618132235/,https://creativecommons.org/licenses/by/2.0/,Eljay,https://www.flickr.com/people/eljay/
cc8d850717026796,https://c1.staticflickr.com/8/7304/26869810723_660f0642a5_o.jpg,0,0,1,1,662,791,https://www.flickr.com/photos/29233640@N07/26869810723,https://creativecommons.org/licenses/by/2.0/,Robert Couse-Baker,https://www.flickr.com/people/29233640@N07/
ab3fef142d031784,https://c1.staticflickr.com/1/17/30695559644_ea51d4a001_o.jpg,0,0.25,0.5625,1,657,737,https://www.flickr.com/photos/27665395@N05/30695559644,https://creativecommons.org/licenses/by/2.0/,Jason Lawrence,https://www.flickr.com/people/27665395@N05/
c84cbc2c05227bee,https://c1.staticflickr.com/1/778/32130016155_b5c1709d28_o.jpg,0.28125,0,0.84375,0.75,437,979,https://www.flickr.com/photos/nzcarfreak/32130016155/,https://creativecommons.org/licenses/by/2.0/,Riley,https://www.flickr.com/people/nzcarfreak/
9d55997552acf0de,https://c1.staticflickr.com/4/3827/33042042362_c6d848f625_o.jpg,0,0.25,0.498159057,1,260,199,https://flickr.com/145431051@N05/33042042362,https://creativecommons.org/licenses/by/2.0/,Natalia King,https://www.flickr.com/people/inataliaking/
8da3593258ae27cb,https://c1.staticflickr.com/8/7304/27230857426_6398e3ff70_o.jpg,0.257672156,0.25,0.773016467,1,581,399,https://www.flickr.com/photos/eu2016nl/27230857426,https://creativecommons.org/licenses/by/2.0/,EU2016 NL,https://www.flickr.com/people/eu2016nl/
fccab516c111d524,https://c1.staticflickr.com/1/578/31833204592_df37b2fd5f_o.jpg,0.5,0,1,0.75,650,757,https://www.flickr.com/photos/shadowgate/31833204592,https://creativecommons.org/licenses/by/2.0/,Shadowgate,https://www.flickr.com/people/shadowgate/
315e55af9615abd2,https://c1.staticflickr.com/1/779/31725794312_e202c64123_o.jpg,0.256726457,0.25,0.770179372,1,347,106,https://flickr.com/13476480@N07/31725794312,https://creativecommons.org/licenses/by/2.0/,manhhai,https://www.flickr.com/people/13476480@N07/
c135337ca7a575ae,https://c1.staticflickr.com/9/8239/28468432034_845b238b0a_o.jpg,0.28125,0,0.84375,0.75,348,178,https://www.flickr.com/photos/sedoglia/28468432034,https://creativecommons.org/licenses/by/2.0/,Sergio,https://www.flickr.com/people/sedoglia/
3bfe9ff7b488485d,https://c1.staticflickr.com/8/7526/27213158786_4411c71bb4_o.jpg,0,0.25,0.5,1,706,710,https://www.flickr.com/photos/45220772@N06/27213158786,https://creativecommons.org/licenses/by/2.0/,Chris GBNL,https://www.flickr.com/people/45220772@N06/
1e33aa336b89dcff,https://c1.staticflickr.com/9/8069/29343726103_76a4d6550d_o.jpg,0.455384615,0,1,0.75,539,588,https://www.flickr.com/photos/hisgett/29343726103/,https://creativecommons.org/licenses/by/2.0/,Tony Hisgett,https://www.flickr.com/people/hisgett/
39a483e9a23716ed,https://c1.staticflickr.com/6/5803/30224386731_129a573cb6_o.jpg,0,0.25,0.497426471,1,676,646,https://www.flickr.com/photos/thenationalguard/30224386731,https://creativecommons.org/licenses/by/2.0/,The National Guard,https://www.flickr.com/people/thenationalguard/
5191cfba868056a5,https://c1.staticflickr.com/9/8057/28990247303_f5235fa9ae_o.jpg,0.250923191,0.25,0.752769572,1,971,793,http://www.flickr.com/photos/pekkatamminen/28990247303/,https://creativecommons.org/licenses/by/2.0/,Pekka Tamminen,https://www.flickr.com/people/pekkatamminen/
4572c8986c28343b,https://c1.staticflickr.com/9/8672/28241882454_babaf6f88f_o.jpg,0.334315169,0,1,1,437,535,https://www.flickr.com/photos/greggjerdingen/28241882454,https://creativecommons.org/licenses/by/2.0/,Greg Gjerdingen,https://www.flickr.com/people/greggjerdingen/
7700d0ba053dc4bd,https://c1.staticflickr.com/9/8881/28767707555_05e533e1a1_o.jpg,0.25,0.249079529,1,0.747238586,937,292,https://www.flickr.com/photos/scotnelson/28767707555,https://creativecommons.org/licenses/by/2.0/,Scot Nelson,https://www.flickr.com/people/scotnelson/
eab9755117160864,https://c1.staticflickr.com/8/7509/29649911804_fbed1c6dac_o.jpg,0.25,0,1,0.618442623,611,510,https://flickr.com/128305985@N02/29649911804,https://creativecommons.org/licenses/by/2.0/,Varevo Designs,https://www.flickr.com/people/128305985@N02/
8b47d72b39b2bd33,https://c1.staticflickr.com/8/7458/27617552740_586605d6d1_o.jpg,0.33113069,0,0.99339207,1,526,97,https://flickr.com/77742560@N06/27617552740,https://creativecommons.org/licenses/by/2.0/,shankar s.,https://www.flickr.com/people/shankaronline/
7d2a7bca22967f29,https://c1.staticflickr.com/8/7525/27211199483_b103fe3789_o.jpg,0,0,0.512686567,0.75,735,600,https://www.flickr.com/photos/hisgett/27211199483,https://creativecommons.org/licenses/by/2.0/,Tony Hisgett,https://www.flickr.com/people/hisgett/
8e89734ed940e222,https://c1.staticflickr.com/1/510/31839325642_621a361097_o.jpg,0.304216867,0,1,1,657,794,https://www.flickr.com/photos/autohistorian/31839325642,https://creativecommons.org/licenses/by/2.0/,Alden Jewell,https://www.flickr.com/people/autohistorian/
30b922dbfdbffd11,https://c1.staticflickr.com/3/2431/32476279840_81a638927d_o.jpg,0.28125,0,0.84375,0.75,610,972,https://www.flickr.com/photos/karen_roe/32476279840,https://creativecommons.org/licenses/by/2.0/,Karen Roe,https://www.flickr.com/people/karen_roe/
ef0e34b8ccb6d42f,https://c1.staticflickr.com/9/8841/28756457540_dd42170f61_o.jpg,0.25,0.25,0.75,1,982,712,https://www.flickr.com/photos/87533529@N00/28756457540/,https://creativecommons.org/licenses/by/2.0/,Joel Dinda,https://www.flickr.com/people/mwlguide/
506b87b78daa499c,https://c1.staticflickr.com/8/7427/26651646184_52fdea24f9_o.jpg,0,0,0.575553797,0.75,821,244,https://www.flickr.com/photos/jsjgeology/26651646184,https://creativecommons.org/licenses/by/2.0/,James St. John,https://www.flickr.com/people/jsjgeology/
62e0e0efc6deeef4,https://c1.staticflickr.com/8/7292/26212453023_25d43a954f_o.jpg,0,0,0.5,0.75,971,772,https://www.flickr.com/photos/akashadorable/26212453023,https://creativecommons.org/licenses/by/2.0/,reverie_rambler,https://www.flickr.com/people/akashadorable/
28652355cd12a1e7,https://c1.staticflickr.com/8/7281/27719555664_9d2eee5a25_o.jpg,0.276162791,0,0.828488372,0.75,308,63,https://www.flickr.com/photos/86548370@N00/27719555664/,https://creativecommons.org/licenses/by/2.0/,Katja Schulz,https://www.flickr.com/people/treegrow/
0ed355357757528d,https://c1.staticflickr.com/1/771/30766164923_65f81b0a16_o.jpg,0,0,0.666666667,1,763,795,https://www.flickr.com/photos/dalbera/30766164923,https://creativecommons.org/licenses/by/2.0/,Jean-Pierre Dalb\303\251ra,https://www.flickr.com/people/dalbera/
abe9504895f6e8dd,https://c1.staticflickr.com/8/7719/27005746036_e3c2d66824_o.jpg,0.204773031,0.25,0.614319092,1,566,607,https://www.flickr.com/photos/kansasscanner/27005746036/,https://creativecommons.org/licenses/by/2.0/,Tyler Silvest,https://www.flickr.com/people/kansasscanner/
dd984311bff04342,https://c1.staticflickr.com/6/5505/30880758442_b260c358d1_o.jpg,0.578252033,0,1,0.75,118,524,https://flickr.com/149229065@N07/30880758442,https://creativecommons.org/licenses/by/2.0/,bready_fv,https://www.flickr.com/people/149229065@N07/
f7947af6545be760,https://c1.staticflickr.com/9/8088/29622519706_0b2d2626e1_o.jpg,0,0,0.7484375,1,418,722,https://www.flickr.com/photos/xingxiyang/29622519706/,https://creativecommons.org/licenses/by/2.0/,Kiefer,https://www.flickr.com/people/xingxiyang/
01244097ca8ffdfa,https://c1.staticflickr.com/9/8420/29072932140_428884b149_o.jpg,0,0,0.666666667,1,91,563,https://www.flickr.com/photos/bigtallguy/29072932140,https://creativecommons.org/licenses/by/2.0/,Paul Reynolds,https://www.flickr.com/people/bigtallguy/
3cf4bb0637d0f182,https://c1.staticflickr.com/6/5336/31376083036_f61bd4c093_o.jpg,0,0.4375,0.75,1,862,52,http://www.flickr.com/photos/subzonica/31376083036/,https://creativecommons.org/licenses/by/2.0/,Hern\303\241n Garc\303\255a Crespo,https://www.flickr.com/people/subzonica/
1d5361e858fe8462,https://c1.staticflickr.com/1/252/31161493730_01da9f540b_o.jpg,0,0.25,0.377400768,1,499,523,https://www.flickr.com/photos/usnavalwarcollegeri/31161493730/,https://creativecommons.org/licenses/by/2.0/,U.S. Naval War College,https://www.flickr.com/people/usnavalwarcollegeri/
6a50fbe8723a6a4a,https://c1.staticflickr.com/1/571/31590985202_b888dd2600_o.jpg,0.5,0.25,1,1,563,597,https://www.flickr.com/photos/rollercoasterphilosophy/31590985202/,https://creativecommons.org/licenses/by/2.0/,Jeremy Thompson,https://www.flickr.com/people/rollercoasterphilosophy/
001b5e6f1b89fd3b,https://c1.staticflickr.com/6/5342/31290416685_7145707d8a_o.jpg,0.4375,0.25,1,1,577,909,https://www.flickr.com/photos/127226743@N02/31290416685,https://creativecommons.org/licenses/by/2.0/,Dimitris Kamaras,https://www.flickr.com/people/127226743@N02/
25eef91443ded954,https://c1.staticflickr.com/6/5495/29933353114_e345092c4c_o.jpg,0.471030043,0,0.942060086,0.75,437,728,https://www.flickr.com/photos/autohistorian/29933353114,https://creativecommons.org/licenses/by/2.0/,Alden Jewell,https://www.flickr.com/people/autohistorian/
ed3f9b6a081a4802,https://c1.staticflickr.com/8/7432/27519628793_d12a4b1349_o.jpg,0,0,0.666666667,1,818,210,https://www.flickr.com/photos/thecarspy/27519628793,https://creativecommons.org/licenses/by/2.0/,The Car Spy,https://www.flickr.com/people/thecarspy/
95fbd20d0aaf319a,https://c1.staticflickr.com/1/292/31801536095_12b2b4d011_o.jpg,0.333333333,0,1,1,826,300,https://www.flickr.com/photos/shankaronline/31801536095,https://creativecommons.org/licenses/by/2.0/,shankar s.,https://www.flickr.com/people/shankaronline/
2bc6c55a0ab24f86,https://c1.staticflickr.com/8/7578/28472228121_b58f3263f6_o.jpg,0.28125,0,0.84375,0.75,786,697,https://www.flickr.com/photos/merfam/28472228121/,https://creativecommons.org/licenses/by/2.0/,Jason Meredith,https://www.flickr.com/people/merfam/
319e8b63d6a194aa,https://c1.staticflickr.com/9/8203/29608037100_b9c0377cb0_o.jpg,0.4375,0.25,1,1,826,529,https://www.flickr.com/photos/127226743@N02/29608037100,https://creativecommons.org/licenses/by/2.0/,Dimitris Kamaras,https://www.flickr.com/people/127226743@N02/
4fcc9c949d66a4e0,https://c1.staticflickr.com/9/8273/29520584994_c6a87b78b7_o.jpg,0.176470588,0,0.529411765,0.75,771,104,https://flickr.com/35080385@N08/29520584994,https://creativecommons.org/licenses/by/2.0/,Daniel Max,https://www.flickr.com/people/35080385@N08/
5c847b72d1e1713f,https://c1.staticflickr.com/8/7402/27581042815_97ab7892e1_o.jpg,0.25,0,1,0.75,556,522,https://www.flickr.com/photos/13152419@N05/27581042815/,https://creativecommons.org/licenses/by/2.0/,A.J. WOODSON,https://www.flickr.com/people/13152419@N05/
707bce947d54bcd8,https://c1.staticflickr.com/6/5533/31047975071_6e1e9857a2_o.jpg,0.436619718,0.25,1,1,947,941,https://www.flickr.com/photos/amantedar/31047975071/,https://creativecommons.org/licenses/by/2.0/,Amante Darmanin,https://www.flickr.com/people/amantedar/
43fa89c17e628c06,https://c1.staticflickr.com/6/5669/30471849463_58158aea97_o.jpg,0.28125,0,0.84375,0.75,133,885,https://www.flickr.com/photos/ddebold/30471849463,https://creativecommons.org/licenses/by/2.0/,Don DeBold,https://www.flickr.com/people/ddebold/
6612fd36e6dd9534,https://c1.staticflickr.com/8/7446/27992527025_02e1093865_o.jpg,0.248826291,0,1,1,309,866,https://www.flickr.com/photos/treegrow/27992527025,https://creativecommons.org/licenses/by/2.0/,Katja Schulz,https://www.flickr.com/people/treegrow/
4146a745f9b2f3cb,https://c1.staticflickr.com/1/453/32533674871_37d9a42b5c_o.jpg,0.28125,0,0.84375,0.75,51,418,https://www.flickr.com/photos/kjfnjy/32533674871,https://creativecommons.org/licenses/by/2.0/,Ken and Nyetta,https://www.flickr.com/people/kjfnjy/
74bfc95412b2f824,https://c1.staticflickr.com/8/7046/26382321234_683510e9d6_o.jpg,0,0,1,1,672,655,https://www.flickr.com/photos/salvolg/26382321234,https://creativecommons.org/licenses/by/2.0/,Salvatore,https://www.flickr.com/people/salvolg/
5fc906f27c8975d2,https://c1.staticflickr.com/9/8029/29167405853_4e4009a5d5_o.jpg,0,0,0.5625,0.75,979,367,https://www.flickr.com/photos/marsupilami92/29167405853,https://creativecommons.org/licenses/by/2.0/,patrick janicek,https://www.flickr.com/people/marsupilami92/
2fc17ec1fad5d947,https://c1.staticflickr.com/2/1618/26152633944_15768856b8_o.jpg,0,0.25,0.579761905,1,874,929,https://www.flickr.com/photos/sergejf/26152633944,https://creativecommons.org/licenses/by/2.0/,sergejf,https://www.flickr.com/people/sergejf/
cb63df64516985c1,https://c1.staticflickr.com/8/7226/27305715702_336cd34ebb_o.jpg,0.334315169,0,1,1,635,772,https://www.flickr.com/photos/sarahvain/27305715702,https://creativecommons.org/licenses/by/2.0/,Sarah Stierch,https://www.flickr.com/people/sarahvain/
7b8413ef241118df,https://c1.staticflickr.com/6/5627/31291332596_e0705f6670_o.jpg,0.4375,0.25,1,1,548,485,https://www.flickr.com/photos/davidwilson1949/31291332596,https://creativecommons.org/licenses/by/2.0/,David Wilson,https://www.flickr.com/people/davidwilson1949/
2e854fca826e54b3,https://c1.staticflickr.com/1/307/31234607810_e2d5b4b1c8_o.jpg,0.333333333,0,1,1,858,596,https://www.flickr.com/photos/dalbera/31234607810/,https://creativecommons.org/licenses/by/2.0/,Jean-Pierre Dalb\303\251ra,https://www.flickr.com/people/dalbera/
f0add7f552d2d895,https://c1.staticflickr.com/6/5800/30295930850_0c40713818_o.jpg,0,0,0.5625,0.75,650,543,https://www.flickr.com/photos/technoevangelist/30295930850,https://creativecommons.org/licenses/by/2.0/,Fee Plumley,https://www.flickr.com/people/technoevangelist/
9d4674c86096e4bd,https://c1.staticflickr.com/9/8410/29866310754_8c13093feb_o.jpg,0.25,0.470789074,1,1,662,614,https://www.flickr.com/photos/autohistorian/29866310754,https://creativecommons.org/licenses/by/2.0/,Alden Jewell,https://www.flickr.com/people/autohistorian/
05437214d1ba9580,https://c1.staticflickr.com/9/8829/28380794150_706cf5d693_o.jpg,0,0.25,0.5625,1,810,118,https://www.flickr.com/photos/68147320@N02/28380794150,https://creativecommons.org/licenses/by/2.0/,T.Tseng,https://www.flickr.com/people/68147320@N02/
dacb07f80166a7fd,https://c1.staticflickr.com/6/5813/30874086821_c5bcdcb048_o.jpg,0.5,0,1,0.75,449,108,http://www.flickr.com/photos/boykoblagoev/30874086821/,https://creativecommons.org/licenses/by/2.0/,Boyko Blagoev,https://www.flickr.com/people/boykoblagoev/
82b6f0bc71f5d0af,https://c1.staticflickr.com/4/3943/15734053815_ccb8cb6852_o.jpg,0,0,1,1,563,578,https://www.flickr.com/photos/zedzap/15734053815/,https://creativecommons.org/licenses/by/2.0/,Nick Kenrick,https://www.flickr.com/people/zedzap/
0f36316247c03427,https://c1.staticflickr.com/1/504/31690529866_dc4e0a80a7_o.jpg,0.500736377,0.25,1,1,753,681,https://www.flickr.com/photos/squashdev/31690529866,https://creativecommons.org/licenses/by/2.0/,England Squash Masters,https://www.flickr.com/people/squashdev/
efeabdd8a05e91f8,https://c1.staticflickr.com/9/8810/28183540151_f7108aa9a2_o.jpg,0,0,0.5625,0.75,498,311,https://www.flickr.com/photos/131810676@N03/28183540151/,https://creativecommons.org/licenses/by/2.0/,baka_neko_baka,https://www.flickr.com/people/131810676@N03/
7453471febf1db6f,https://c1.staticflickr.com/9/8870/28331839720_9de4810a16_o.jpg,0,0.333333333,1,1,595,90,https://www.flickr.com/photos/stevenpisano/28331839720,https://creativecommons.org/licenses/by/2.0/,Steven Pisano,https://www.flickr.com/people/stevenpisano/
e6f2de0c605f1ed3,https://c1.staticflickr.com/9/8392/29438273202_8ba928f59f_o.jpg,0.471590909,0,1,0.75,132,994,https://www.flickr.com/photos/dkeats/29438273202,https://creativecommons.org/licenses/by/2.0/,Derek Keats,https://www.flickr.com/people/dkeats/
648231d9393250fd,https://c1.staticflickr.com/1/436/31994770622_64e6478fe4_o.jpg,0.578822733,0.25,1,1,548,650,https://www.flickr.com/photos/belurashok/31994770622/,https://creativecommons.org/licenses/by/2.0/,Belur Ashok,https://www.flickr.com/people/belurashok/
864fffaf7a83b3f4,https://c1.staticflickr.com/8/7471/27863056826_bc9e568c4c_o.jpg,0,0,0.75,1,581,373,https://www.flickr.com/photos/juggernautco/27863056826,https://creativecommons.org/licenses/by/2.0/,Daniel X. O'Neil,https://www.flickr.com/people/juggernautco/
c179282bd977c6e0,https://c1.staticflickr.com/3/2907/32124474993_c63801fabf_o.jpg,0,0,0.556376361,0.75,672,105,https://www.flickr.com/photos/glorycycles/32124474993,https://creativecommons.org/licenses/by/2.0/,Glory Cycles,https://www.flickr.com/people/glorycycles/
40a7f086461190f3,https://c1.staticflickr.com/2/1514/26690160211_eda12ace1e_o.jpg,0.42862776,0.25,1,1,493,841,https://www.flickr.com/photos/martius/26690160211,https://creativecommons.org/licenses/by/2.0/,M a n u e l,https://www.flickr.com/people/martius/
90e1aa56cae80a60,https://c1.staticflickr.com/6/5068/30114102505_bcc8ec61db_o.jpg,0,0,1,1,918,417,https://flickr.com/64648244@N04/30114102505,https://creativecommons.org/licenses/by/2.0/,Ulf K,https://www.flickr.com/people/ulfk/
839aa3d166b020cf,https://c1.staticflickr.com/8/7104/26514437520_58ea29102e_o.jpg,0,0.25,0.72079646,1,14,211,https://www.flickr.com/photos/nrgoodrum/26514437520,https://creativecommons.org/licenses/by/2.0/,nick goodrum,https://www.flickr.com/people/nrgoodrum/
38bdd950c1d08be6,https://c1.staticflickr.com/1/467/32470039506_2c9d8f3c2c_o.jpg,0,0,0.75,1,133,891,https://www.flickr.com/photos/rusty_clark/32470039506/,https://creativecommons.org/licenses/by/2.0/,Rusty Clark ~ 100K Photos,https://www.flickr.com/people/rusty_clark/
2d95297e468bdf9b,https://c1.staticflickr.com/8/7358/27718678441_390843b0a4_o.jpg,0.28125,0.25,0.84375,1,866,526,https://www.flickr.com/photos/jeepersmedia/27718678441,https://creativecommons.org/licenses/by/2.0/,Mike Mozart,https://www.flickr.com/people/jeepersmedia/
ef5b1e5a76ae66dc,https://c1.staticflickr.com/9/8028/29706482742_e07ecf46e1_o.jpg,0.497426471,0,0.994852941,0.75,540,725,https://www.flickr.com/photos/emilysnuffer/29706482742,https://creativecommons.org/licenses/by/2.0/,Emily May,https://www.flickr.com/people/emilysnuffer/
7a11ae4c1f5e790c,https://c1.staticflickr.com/8/7680/28813894581_61251a80fa_o.jpg,0.249079529,0.25,0.747238586,1,689,500,https://www.flickr.com/photos/zigazou76/28813894581,https://creativecommons.org/licenses/by/2.0/,Fr\303\251d\303\251ric BISSON,https://www.flickr.com/people/zigazou76/
477bf90e7413df23,https://c1.staticflickr.com/8/7338/27067101244_7942b5769e_o.jpg,0,0,0.578296703,1,542,836,https://www.flickr.com/photos/fifeanddrum/27067101244,https://creativecommons.org/licenses/by/2.0/,U. S. Army Old Guard Fife and Drum Corps,https://www.flickr.com/people/fifeanddrum/
7060ae82e5b96a77,https://c1.staticflickr.com/8/7414/27849533291_23d512cc58_o.jpg,0,0,0.75,1,522,495,https://www.flickr.com/photos/jeepersmedia/27849533291,https://creativecommons.org/licenses/by/2.0/,Mike Mozart,https://www.flickr.com/people/jeepersmedia/
42e55ac6782d4d99,https://c1.staticflickr.com/9/8841/28851410876_d279c09ca0_o.jpg,0,0,0.5625,0.75,974,819,https://flickr.com/131967103@N02/28851410876,https://creativecommons.org/licenses/by/2.0/,Ryan McMinds,https://www.flickr.com/people/131967103@N02/
8868879c2acd5d9e,https://c1.staticflickr.com/8/7477/27387672956_baa0cdeb89_o.jpg,0.455384615,0,1,0.75,322,130,https://www.flickr.com/photos/usfwsmidwest/27387672956,https://creativecommons.org/licenses/by/2.0/,USFWSmidwest,https://www.flickr.com/people/usfwsmidwest/
5b3a8c63e41802e7,https://c1.staticflickr.com/9/8883/27865729823_3db56871fa_o.jpg,0.25,0.25,1,1,750,758,https://flickr.com/38315261@N00/27865729823,https://creativecommons.org/licenses/by/2.0/,Sharon Mollerus,https://www.flickr.com/people/clairity/
659ca4ac6cc57e89,https://c1.staticflickr.com/1/371/31418192282_a6fa2c7a51_o.jpg,0.25,0,0.75,0.75,778,590,https://www.flickr.com/photos/quinet/31418192282,https://creativecommons.org/licenses/by/2.0/,Thomas Quine,https://www.flickr.com/people/quinet/
9534108b0e8dceb1,https://c1.staticflickr.com/1/668/31683586152_9c8d97ef8f_o.jpg,0.282719436,0.25,0.848158307,1,647,822,https://www.flickr.com/photos/arnehendriks/31683586152,https://creativecommons.org/licenses/by/2.0/,Arne Hendriks,https://www.flickr.com/people/arnehendriks/
fbc6b98b13c768e2,https://c1.staticflickr.com/9/8435/29171057840_4acaf34304_o.jpg,0,0.25,0.5625,1,459,566,https://www.flickr.com/photos/rheba/29171057840,https://creativecommons.org/licenses/by/2.0/,Rheba,https://www.flickr.com/people/rheba/
7c3b0d93654b39cd,https://c1.staticflickr.com/6/5128/29789328711_639198fc6f_o.jpg,0.25,0,1,0.5625,708,428,https://www.flickr.com/photos/playamongfriends/29789328711,https://creativecommons.org/licenses/by/2.0/,Play Among Friends Paf,https://www.flickr.com/people/playamongfriends/
43694caa12d5f823,https://c1.staticflickr.com/1/445/31614966550_d5fc6f7f3d_o.jpg,0.28125,0.25,0.84375,1,979,757,https://www.flickr.com/photos/cambodia4kidsorg/31614966550/,https://creativecommons.org/licenses/by/2.0/,Cambodia4kids.org Beth Kanter,https://www.flickr.com/people/cambodia4kidsorg/
69788a29e7436808,https://c1.staticflickr.com/6/5332/30849701300_a85871c357_o.jpg,0.12962963,0,1,1,310,50,https://www.flickr.com/photos/gails_pictures/30849701300/,https://creativecommons.org/licenses/by/2.0/,gailhampshire,https://www.flickr.com/people/gails_pictures/
daa43d65c3b18a84,https://c1.staticflickr.com/9/8253/29381659730_52bcbf8b59_o.jpg,0,0,1,0.75,822,54,https://www.flickr.com/photos/39551170@N02/29381659730,https://creativecommons.org/licenses/by/2.0/,Simon_sees,https://www.flickr.com/people/39551170@N02/
a8c3363bbcc7015c,https://c1.staticflickr.com/9/8823/29472376703_be7d867566_o.jpg,0,0,0.912068966,1,739,840,https://www.flickr.com/photos/tomronworldwide/29472376703,https://creativecommons.org/licenses/by/2.0/,Ron Frazier,https://www.flickr.com/people/tomronworldwide/
93a0857ff81c25ce,https://c1.staticflickr.com/6/5733/30469514315_1d8ce7f4c2_o.jpg,0,0,0.5,0.75,548,959,https://www.flickr.com/photos/rhemkes/30469514315,https://creativecommons.org/licenses/by/2.0/,Roel Hemkes,https://www.flickr.com/people/rhemkes/
b11fa0f292c0178f,https://c1.staticflickr.com/1/780/32263240380_ee5c7a9637_o.jpg,0.25,0,0.75,0.75,702,901,http://www.flickr.com/photos/124790945@N06/32263240380,https://creativecommons.org/licenses/by/2.0/,Phuket@photographer.net,https://www.flickr.com/people/linvoyage/
1dc0533f87996962,https://c1.staticflickr.com/8/7704/26497012284_30e830cc10_o.jpg,0.409855769,0.25,1,1,566,853,https://www.flickr.com/photos/jsjgeology/26497012284,https://creativecommons.org/licenses/by/2.0/,James St. John,https://www.flickr.com/people/jsjgeology/
589319c64adf5fce,https://c1.staticflickr.com/8/7460/27398216034_b731c9e68a_o.jpg,0.333333333,0,1,1,699,588,https://www.flickr.com/photos/libereurope/27398216034/,https://creativecommons.org/licenses/by/2.0/,LIBER Europe,https://www.flickr.com/people/libereurope/
cebd45d7200f6111,https://c1.staticflickr.com/9/8339/29164491280_b7d3bdd713_o.jpg,0.25,0,1,0.719444444,71,947,https://www.flickr.com/photos/garlandcannon/29164491280,https://creativecommons.org/licenses/by/2.0/,garlandcannon,https://www.flickr.com/people/garlandcannon/
7e73c7adc520e406,https://c1.staticflickr.com/8/7416/26859649600_fb2cbaf86b_o.jpg,0.25,0,1,0.64807047,133,86,https://www.flickr.com/photos/lakeworth/26859649600,https://creativecommons.org/licenses/by/2.0/,Henry,https://www.flickr.com/people/lakeworth/
6de6432b0f23ae75,https://c1.staticflickr.com/1/579/32182435510_e9fab3e93c_o.jpg,0.333333333,0,1,1,105,407,https://www.flickr.com/photos/rexness/32182435510,https://creativecommons.org/licenses/by/2.0/,Rexness,https://www.flickr.com/people/rexness/
ebb4dad78cfd67a9,https://c1.staticflickr.com/8/7293/27173553526_fe84eeeec9_o.jpg,0.25,0,1,1,738,730,https://www.flickr.com/photos/jeepersmedia/27173553526,https://creativecommons.org/licenses/by/2.0/,Mike Mozart,https://www.flickr.com/people/jeepersmedia/
e8c6f75ad26bae84,https://c1.staticflickr.com/9/8393/29734167231_b03b36f04b_o.jpg,0.28125,0.25,0.84375,1,973,929,https://www.flickr.com/photos/jsjgeology/29734167231,https://creativecommons.org/licenses/by/2.0/,James St. John,https://www.flickr.com/people/jsjgeology/
1e408a8d1e2cdc74,https://c1.staticflickr.com/6/5509/30181862974_0a8d40efb1_o.jpg,0.4375,0,1,0.75,769,779,https://www.flickr.com/photos/stmunchins/30181862974/,https://creativecommons.org/licenses/by/2.0/,St Munchin's College,https://www.flickr.com/people/stmunchins/
11afa51200515f9a,https://c1.staticflickr.com/8/7654/28347963084_4a9385edd0_o.jpg,0.263089005,0,0.789267016,1,826,567,https://www.flickr.com/photos/anandajoti/28347963084/,https://creativecommons.org/licenses/by/2.0/,Photo Dharma,https://www.flickr.com/people/anandajoti/
9f6fe669276f04cf,https://c1.staticflickr.com/9/8760/28674693282_7eec755334_o.jpg,0,0,0.7484375,1,920,697,https://www.flickr.com/photos/zimpenfish/28674693282,https://creativecommons.org/licenses/by/2.0/,rjp,https://www.flickr.com/people/zimpenfish/
408bae58c26a8076,https://c1.staticflickr.com/6/5773/29699525424_ea6336aaa8_o.jpg,0.462155963,0,1,0.75,133,761,https://www.flickr.com/photos/taylar/29699525424,https://creativecommons.org/licenses/by/2.0/,Ingrid Taylar,https://www.flickr.com/people/taylar/
b5548ecffa20aac8,https://c1.staticflickr.com/1/713/32057543825_ded4304f3b_o.jpg,0,0,0.5,0.75,934,108,http://www.flickr.com/photos/143850343@N06/32057543825/,https://creativecommons.org/licenses/by/2.0/,Sam-H-A,https://www.flickr.com/people/143850343@N06/
9ee13ecd8d6727c0,https://c1.staticflickr.com/6/5708/30313299300_68025e82ed_o.jpg,0,0.498153619,0.75,1,498,554,https://www.flickr.com/photos/quinet/30313299300,https://creativecommons.org/licenses/by/2.0/,Thomas Quine,https://www.flickr.com/people/quinet/
d1a723656dc08b5e,https://c1.staticflickr.com/8/7407/27895921745_908d139fdd_o.jpg,0.503303965,0.25,1,1,822,814,https://www.flickr.com/photos/shankaronline/27895921745,https://creativecommons.org/licenses/by/2.0/,shankar s.,https://www.flickr.com/people/shankaronline/
d1709eec353a6f93,https://c1.staticflickr.com/8/7421/27144655490_a81fccf9ca_o.jpg,0,0.25,0.75,1,297,556,https://www.flickr.com/photos/rjbailey/27144655490/,https://creativecommons.org/licenses/by/2.0/,Ron Bailey,https://www.flickr.com/people/rjbailey/
b89dbfcc49dcf156,https://c1.staticflickr.com/8/7448/27273015613_f2767e3f98_o.jpg,0.210588633,0,0.6317659,0.75,889,467,https://www.flickr.com/photos/spencerhall/27273015613,https://creativecommons.org/licenses/by/2.0/,Spencer Hall,https://www.flickr.com/people/spencerhall/
7368fe0ff47343a0,https://c1.staticflickr.com/8/7520/26512614104_b123959864_o.jpg,0.28125,0.25,0.84375,1,965,447,https://www.flickr.com/photos/rainsong/26512614104,https://creativecommons.org/licenses/by/2.0/,Ali - \330\271\331\204\331\212 from Riyadh - \331\205\331\206 \330\247\331\204\330\261\331\212\330\247\330\266,https://www.flickr.com/people/rainsong/
d23fd2119c4f5dec,https://c1.staticflickr.com/9/8165/28790897384_31003e57ee_o.jpg,0.249631811,0,0.748895434,0.75,329,123,https://www.flickr.com/photos/fhgitarre/28790897384,https://creativecommons.org/licenses/by/2.0/,FHgitarre,https://www.flickr.com/people/fhgitarre/
5a0e21d54b9c4954,https://c1.staticflickr.com/8/7243/27968268826_09285822b1_o.jpg,0,0,0.715608466,0.75,328,146,https://www.flickr.com/photos/noaaphotolib/27968268826,https://creativecommons.org/licenses/by/2.0/,NOAA Photo Library,https://www.flickr.com/people/noaaphotolib/
4b8517e927f32962,https://c1.staticflickr.com/9/8140/29892684285_e0633bea72_o.jpg,0.25,0.25,1,1,866,271,https://flickr.com/10307586@N03/29892684285,https://creativecommons.org/licenses/by/2.0/,Mark Pegrum,https://www.flickr.com/people/ozmark17/
38deb4830d12358f,https://c1.staticflickr.com/6/5650/31182154435_7dc98f5dba_o.jpg,0.5,0,1,0.75,980,936,https://www.flickr.com/photos/henry_hemming/31182154435,https://creativecommons.org/licenses/by/2.0/,Henry Hemming,https://www.flickr.com/people/henry_hemming/
81804435ad51df95,https://c1.staticflickr.com/1/255/31787555660_d866250efd_o.jpg,0,0,0.5,0.75,437,241,https://www.flickr.com/photos/nielsautos/31787555660,https://creativecommons.org/licenses/by/2.0/,Niels de Wit,https://www.flickr.com/people/nielsautos/
e4941a341ace171a,https://c1.staticflickr.com/9/8006/28587599723_947de8d314_o.jpg,0.25,0.25,1,0.75,709,298,https://www.flickr.com/photos/asrusch/28587599723,https://creativecommons.org/licenses/by/2.0/,Andy Rusch,https://www.flickr.com/people/asrusch/
558a7b66b78ba65b,https://c1.staticflickr.com/6/5797/30174833703_4e5f61ded4_o.jpg,0,0,1,0.745709828,422,668,https://www.flickr.com/photos/tusnelda/30174833703/,https://creativecommons.org/licenses/by/2.0/,storebukkebruse,https://www.flickr.com/people/tusnelda/
435137d9d4f4125e,https://c1.staticflickr.com/8/7535/28182425121_c71755b34e_o.jpg,0,0,0.75,0.75,2,269,https://www.flickr.com/photos/aidanmorgan/28182425121/,https://creativecommons.org/licenses/by/2.0/,John Morgan,https://www.flickr.com/people/aidanmorgan/
c43077b2283479be,https://c1.staticflickr.com/6/5522/30653895580_2c136ce8c7_o.jpg,0,0,0.75,0.588,14,765,https://flickr.com/93242958@N00/30653895580,https://creativecommons.org/licenses/by/2.0/,Derek Keats,https://www.flickr.com/people/dkeats/
77c72d0a01e1af70,https://c1.staticflickr.com/9/8214/28891107093_72da720a1d_o.jpg,0.5,0,1,0.75,428,836,https://www.flickr.com/photos/katiethebeau/28891107093/,https://creativecommons.org/licenses/by/2.0/,KatieThebeau,https://www.flickr.com/people/katiethebeau/
72ac2a5af79e26d5,https://c1.staticflickr.com/6/5613/31220748780_31a537d326_o.jpg,0.28125,0,0.84375,0.75,718,862,https://www.flickr.com/photos/hugo90/31220748780,https://creativecommons.org/licenses/by/2.0/,JOHN LLOYD,https://www.flickr.com/people/hugo90/
32c0e4647ce5a812,https://c1.staticflickr.com/9/8344/29851489791_076d3494a0_o.jpg,0.486899563,0,0.973799127,0.75,327,743,https://www.flickr.com/photos/yogendra174/29851489791,https://creativecommons.org/licenses/by/2.0/,Yogendra Joshi,https://www.flickr.com/people/yogendra174/
54153d17b11b495c,https://c1.staticflickr.com/6/5500/30389728162_23cdff8ba8_o.jpg,0.421177267,0,0.842354533,0.75,657,551,https://www.flickr.com/photos/micsworld/30389728162,https://creativecommons.org/licenses/by/2.0/,Mic,https://www.flickr.com/people/micsworld/
fb1efda0b27d5289,https://c1.staticflickr.com/1/460/31194422753_24550f0615_o.jpg,0.5,0,1,0.75,848,203,https://www.flickr.com/photos/quinet/31194422753,https://creativecommons.org/licenses/by/2.0/,Thomas Quine,https://www.flickr.com/people/quinet/
7c5ea6f89e6e2733,https://c1.staticflickr.com/1/454/32710889631_00f86c1d71_o.jpg,0.500736377,0,1,0.75,820,587,https://www.flickr.com/photos/dominik_junger/32710889631/in/album-72157676671651883/,https://creativecommons.org/licenses/by/2.0/,Dominik Junger,https://www.flickr.com/people/dominik_junger/
721804d1d3a60206,https://c1.staticflickr.com/8/7790/27456693684_f07ebe3aea_o.jpg,0,0,0.666666667,1,909,34,https://www.flickr.com/photos/presidentialoffice/27456693684,https://creativecommons.org/licenses/by/2.0/,\347\270\275\347\265\261\345\272\234,https://www.flickr.com/people/presidentialoffice/
dcb6b32cd80f2b1f,https://c1.staticflickr.com/8/7560/29512813082_6efd1c1b56_o.jpg,0.28125,0,0.84375,0.75,556,832,https://www.flickr.com/photos/27665395@N05/29512813082/,https://creativecommons.org/licenses/by/2.0/,Jason Lawrence,https://www.flickr.com/people/27665395@N05/
49c27b439d39a00c,https://c1.staticflickr.com/1/653/33034701806_914058174b_o.jpg,0.335787923,0,1,1,490,418,https://flickr.com/38144691@N00/33034701806,https://creativecommons.org/licenses/by/2.0/,August Kelm,https://www.flickr.com/people/augustksphotos/
2c065d2dc6b2cf44,https://c1.staticflickr.com/6/5441/30476315260_213dbcbdf3_o.jpg,0.439547582,0,1,0.75,934,463,https://www.flickr.com/photos/hmk/30476315260,https://creativecommons.org/licenses/by/2.0/,H. Michael Karshis,https://www.flickr.com/people/hmk/
b3f200c672c5ca4f,https://c1.staticflickr.com/8/7539/28925572132_ff6fc934e0_o.jpg,0,0.25,0.5,1,976,275,https://www.flickr.com/photos/gabrielgm/28925572132/,https://creativecommons.org/licenses/by/2.0/,Gabriel Garcia Marengo,https://www.flickr.com/people/gabrielgm/
3f40eba168e5d385,https://c1.staticflickr.com/6/5717/31106619226_f60452e9f2_o.jpg,0.299878837,0,0.899636511,0.75,515,936,https://www.flickr.com/photos/85546319@N04/31106619226,https://creativecommons.org/licenses/by/2.0/,Robert Sheie,https://www.flickr.com/people/85546319@N04/
0e71473957df4793,https://c1.staticflickr.com/1/630/31560462464_df68f43299_o.jpg,0.502573529,0,1,0.75,878,348,https://www.flickr.com/photos/agenciabrasilia/31560462464,https://creativecommons.org/licenses/by/2.0/,Ag\303\252ncia Bras\303\255lia,https://www.flickr.com/people/agenciabrasilia/
6c9f8901246faff2,https://c1.staticflickr.com/1/745/31509879035_78978e4f01_o.jpg,0,0,0.708206687,1,629,689,https://www.flickr.com/photos/guldem/31509879035,https://creativecommons.org/licenses/by/2.0/,G\303\274ldem \303\234st\303\274n,https://www.flickr.com/people/guldem/
a64ae1acd9d09a87,https://c1.staticflickr.com/1/717/31077768123_e0787a8de6_o.jpg,0,0,1,1,131,83,http://www.flickr.com/photos/paul_e_balfe/31077768123/,https://creativecommons.org/licenses/by/2.0/,Paul Balfe,https://www.flickr.com/people/paul_e_balfe/
05f7c084329ff0c6,https://c1.staticflickr.com/6/5513/30518437054_80b12bbda5_o.jpg,0.5,0.25,1,1,973,910,https://flickr.com/14247646@N00/30518437054,https://creativecommons.org/licenses/by/2.0/,James,https://www.flickr.com/people/jametiks/
5d77597361d06d2b,https://c1.staticflickr.com/1/478/31414603844_530a364312_o.jpg,0,0,1,0.714503817,904,92,https://www.flickr.com/photos/avedaphotos/31414603844/,https://creativecommons.org/licenses/by/2.0/,Aveda Corporation,https://www.flickr.com/people/avedaphotos/
ac2a8a4777dbe746,https://c1.staticflickr.com/8/7615/27545901420_caafb85d83_o.jpg,0,0,0.499263623,0.75,896,46,https://www.flickr.com/photos/621crw/27545901420,https://creativecommons.org/licenses/by/2.0/,The 621st Contingency Response Wing,https://www.flickr.com/people/621crw/
3d75d9676ad6361c,https://c1.staticflickr.com/6/5589/30796308216_2ba813235e_o.jpg,0,0,0.601941748,0.75,151,517,https://www.flickr.com/photos/pandora_6666/30796308216,https://creativecommons.org/licenses/by/2.0/,Jo Naylor,https://www.flickr.com/people/pandora_6666/
e3a740861f12f49e,https://c1.staticflickr.com/9/8453/29471934070_b712c35d65_o.jpg,0.210873984,0,0.632621951,0.75,820,900,https://www.flickr.com/photos/ceta_und_ttip_stoppen/29471934070/,https://creativecommons.org/licenses/by/2.0/,CETA und TTIP stoppen,https://www.flickr.com/people/ceta_und_ttip_stoppen/
64577d3916d6dafb,https://c1.staticflickr.com/8/7774/26695019922_97087ac2c0_o.jpg,0.25,0,1,0.5625,606,754,https://www.flickr.com/photos/afropicmusing/26695019922,https://creativecommons.org/licenses/by/2.0/,afromusing,https://www.flickr.com/people/afropicmusing/
3b32eca218ed3dbe,https://c1.staticflickr.com/8/7341/28021300931_378cfe5932_o.jpg,0,0,0.490510949,0.75,742,838,https://www.flickr.com/photos/jdlasica/28021300931,https://creativecommons.org/licenses/by/2.0/,JD Lasica,https://www.flickr.com/people/jdlasica/
0707f3dfb7c29f5c,https://c1.staticflickr.com/6/5700/30555623662_42d83db0d3_o.jpg,0,0.25,0.498159057,1,606,740,https://www.flickr.com/photos/145304628@N02/30555623662,https://creativecommons.org/licenses/by/2.0/,Degree53 UK,https://www.flickr.com/people/145304628@N02/
59e9bdbb7a3fc4ba,https://c1.staticflickr.com/9/8533/30011107125_37837842a9_o.jpg,0,0,1,0.666666667,518,407,https://www.flickr.com/photos/zigazou76/30011107125,https://creativecommons.org/licenses/by/2.0/,Fr\303\251d\303\251ric BISSON,https://www.flickr.com/people/zigazou76/
686ea4ec999364ff,https://c1.staticflickr.com/8/7319/27523198984_f9d44bba3a_o.jpg,0,0.28125,0.75,0.84375,459,554,https://www.flickr.com/photos/nostri-imago/27523198984,https://creativecommons.org/licenses/by/2.0/,Cliff,https://www.flickr.com/people/nostri-imago/
cb71a056a8e05bb2,https://c1.staticflickr.com/9/8001/29254381704_cc81ff8df9_o.jpg,0,0,0.563380282,0.75,320,941,https://flickr.com/9243304@N04/29254381704,https://creativecommons.org/licenses/by/2.0/,Amante Darmanin,https://www.flickr.com/people/amantedar/
f63d58b5af16091f,https://c1.staticflickr.com/1/681/32382788261_b7554c250b_o.jpg,0,0,1,0.732612056,716,420,https://www.flickr.com/photos/jlcernadas/32382788261/,https://creativecommons.org/licenses/by/2.0/,Jose Luis Cernadas Iglesias,https://www.flickr.com/people/jlcernadas/
d3aa8ee50458c020,https://c1.staticflickr.com/1/444/32463408492_cf7ab6f5fb_o.jpg,0,0,0.75,0.630794702,431,874,https://www.flickr.com/photos/viumariners/32463408492/,https://creativecommons.org/licenses/by/2.0/,VIU Mariners,https://www.flickr.com/people/viumariners/
2891f4aa2279d369,https://c1.staticflickr.com/9/8658/28224525812_7301285f51_o.jpg,0.5,0,1,0.75,471,405,https://www.flickr.com/photos/rorals/28224525812,https://creativecommons.org/licenses/by/2.0/,Rory,https://www.flickr.com/people/rorals/
ae24c23192976a40,https://c1.staticflickr.com/6/5811/31350835411_b856c2e0f7_o.jpg,0,0,0.498159057,0.75,752,888,https://www.flickr.com/photos/davehamster/31350835411,https://creativecommons.org/licenses/by/2.0/,David Merrett,https://www.flickr.com/people/davehamster/
348ac56def3ccd35,https://c1.staticflickr.com/9/8601/30053184852_b6c871293b_o.jpg,0.331617647,0,0.994852941,1,916,533,https://www.flickr.com/photos/alpesdehauteprovence-tourisme/30053184852,https://creativecommons.org/licenses/by/2.0/,ADT 04,https://www.flickr.com/people/alpesdehauteprovence-tourisme/
d46216d31908163e,https://c1.staticflickr.com/9/8723/28309396545_349e5147bb_o.jpg,0.333333333,0,1,1,896,785,https://www.flickr.com/photos/ronmacphotos/28309396545,https://creativecommons.org/licenses/by/2.0/,Ronnie Macdonald,https://www.flickr.com/people/ronmacphotos/
a8dd9ba15f7b817b,https://c1.staticflickr.com/1/575/31572326940_d87b136e59_o.jpg,0.251849112,0.25,0.755547337,1,806,740,https://www.flickr.com/photos/prefeituradeolinda/31572326940,https://creativecommons.org/licenses/by/2.0/,Prefeitura de Olinda,https://www.flickr.com/people/prefeituradeolinda/
5224fec9ba33b50d,https://c1.staticflickr.com/9/8081/29568549431_86f962156e_o.jpg,0,0,0.75,1,604,532,https://flickr.com/28834651@N07/29568549431,https://creativecommons.org/licenses/by/2.0/,Aul Rah,https://www.flickr.com/people/28834651@N07/
b3c384a2d1a391c0,https://c1.staticflickr.com/6/5543/30815777131_13d5e7667c_o.jpg,0,0,0.599757674,0.75,631,456,https://www.flickr.com/photos/85546319@N04/30815777131,https://creativecommons.org/licenses/by/2.0/,Robert Sheie,https://www.flickr.com/people/85546319@N04/
4a1a488e8a975f7c,https://c1.staticflickr.com/9/8420/29353940465_05ece9b92e_o.jpg,0.25,0.25,0.75,1,920,833,https://www.flickr.com/photos/harshlight/29353940465,https://creativecommons.org/licenses/by/2.0/,HarshLight,https://www.flickr.com/people/harshlight/
d7c1d1632cf0acc7,https://c1.staticflickr.com/9/8653/28465398416_2c4202cb8d_o.jpg,0.25,0,0.75,0.75,404,873,https://www.flickr.com/photos/usnavy/28465398416,https://creativecommons.org/licenses/by/2.0/,Official U.S. Navy Page,https://www.flickr.com/people/usnavy/
ca50e3535eb6396c,https://c1.staticflickr.com/6/5527/29526798504_12061e1707_o.jpg,0,0,0.5,0.75,556,929,https://flickr.com/137837832@N07/29526798504,https://creativecommons.org/licenses/by/2.0/,Mark Holloway,https://www.flickr.com/people/137837832@N07/
30e132285c2e960f,https://c1.staticflickr.com/6/5663/30553419670_2249584a31_o.jpg,0.25,0,1,1,912,427,https://www.flickr.com/photos/jonathanrolande/30553419670,https://creativecommons.org/licenses/by/2.0/,Jonathan Rolande,https://www.flickr.com/people/jonathanrolande/
ea65c0ff71e7ceb3,https://c1.staticflickr.com/4/3953/33320124506_2fbd93baa7_o.jpg,0.333333333,0,1,1,404,737,https://www.flickr.com/photos/usnavy/33320124506,https://creativecommons.org/licenses/by/2.0/,Official U.S. Navy Page,https://www.flickr.com/people/usnavy/
200285e90078210b,https://c1.staticflickr.com/1/701/30876765453_574a6815b0_o.jpg,0.5,0.25,1,1,442,741,https://flickr.com/22539273@N00/30876765453,https://creativecommons.org/licenses/by/2.0/,Guilhem Vellut,https://www.flickr.com/people/o_0/
cec46dbd1fa3473a,https://c1.staticflickr.com/9/8320/29351169445_b0b0090587_o.jpg,0.455696203,0.25,0.911392405,1,898,246,https://www.flickr.com/photos/lge/29351169445,https://creativecommons.org/licenses/by/2.0/,LG\354\240\204\354\236\220,https://www.flickr.com/people/lge/
6314b953a2f66e36,https://c1.staticflickr.com/1/306/31686321825_ef08b80af5_o.jpg,0.281690141,0.25,0.845070423,1,311,774,https://www.flickr.com/photos/treegrow/31686321825,https://creativecommons.org/licenses/by/2.0/,Katja Schulz,https://www.flickr.com/people/treegrow/
1f3f949ccbc81c93,https://c1.staticflickr.com/9/8643/28179475136_e6925b8a4b_o.jpg,0,0.25,1,1,304,666,https://flickr.com/27305106@N06/28179475136,https://creativecommons.org/licenses/by/2.0/,Charlie Jackson,https://www.flickr.com/people/chaz_pics/
04546cc5e537d7cd,https://c1.staticflickr.com/8/7347/27291550531_ee40bdf58a_o.jpg,0,0,0.495594714,0.75,426,649,https://www.flickr.com/photos/kansasscanner/27291550531/,https://creativecommons.org/licenses/by/2.0/,Tyler Silvest,https://www.flickr.com/people/kansasscanner/
73064ceb466612d5,https://c1.staticflickr.com/6/5777/30172206492_407d68dc21_o.jpg,0.53125,0,1,0.75,719,673,https://flickr.com/97760755@N08/30172206492,https://creativecommons.org/licenses/by/2.0/,Viaggio Routard,https://www.flickr.com/people/viaggioroutard/
ae78688b32986638,https://c1.staticflickr.com/9/8290/29399680281_1b2c136428_o.jpg,0,0,0.5,0.75,913,879,https://www.flickr.com/photos/ddebold/29399680281/,https://creativecommons.org/licenses/by/2.0/,Don DeBold,https://www.flickr.com/people/ddebold/
72d85232abd98067,https://c1.staticflickr.com/8/7655/28880045512_841b0c2d3a_o.jpg,0.25,0,0.75,0.75,471,599,https://www.flickr.com/photos/quinet/28880045512,https://creativecommons.org/licenses/by/2.0/,Thomas Quine,https://www.flickr.com/people/quinet/
89d8361c6bfe905c,https://c1.staticflickr.com/8/7290/27369075485_5c164b1839_o.jpg,0.25,0,0.75,0.75,604,51,https://www.flickr.com/photos/quinet/27369075485,https://creativecommons.org/licenses/by/2.0/,Thomas Quine,https://www.flickr.com/people/quinet/
4ca02fd28a5e9703,https://c1.staticflickr.com/9/8453/29423857932_71a8a4a98f_o.jpg,0.25,0.302066451,1,0.906199352,996,239,https://www.flickr.com/photos/92252798@N07/29423857932,https://creativecommons.org/licenses/by/2.0/,Dick Culbert,https://www.flickr.com/people/92252798@N07/
48762c2cd2ed47e1,https://c1.staticflickr.com/6/5546/30817355150_7f1f77f6e2_o.jpg,0.25,0,1,0.75,755,308,https://www.flickr.com/photos/hmk/30817355150,https://creativecommons.org/licenses/by/2.0/,H. Michael Karshis,https://www.flickr.com/people/hmk/
b217644382dcd864,https://c1.staticflickr.com/9/8082/29684292096_85e6a733cf_o.jpg,0.182707993,0,1,1,512,708,https://www.flickr.com/photos/atoach/29684292096,https://creativecommons.org/licenses/by/2.0/,Tim Green,https://www.flickr.com/people/atoach/
c4824f023903731a,https://c1.staticflickr.com/8/7777/26400069864_79fd47a2fe_o.jpg,0.25,0.25,1,1,738,817,https://www.flickr.com/photos/betsyweber/26400069864,https://creativecommons.org/licenses/by/2.0/,Betsy Weber,https://www.flickr.com/people/betsyweber/
629138193e021cdf,https://c1.staticflickr.com/9/8768/28328433276_2d2146df81_o.jpg,0,0.5,0.75,1,885,739,https://www.flickr.com/photos/glenbowman/28328433276,https://creativecommons.org/licenses/by/2.0/,Glen Bowman,https://www.flickr.com/people/glenbowman/
7d4186ce0332245d,https://c1.staticflickr.com/9/8578/28958405495_50b6230377_o.jpg,0,0,0.666666667,1,976,936,https://www.flickr.com/photos/o_0/28958405495,https://creativecommons.org/licenses/by/2.0/,Guilhem Vellut,https://www.flickr.com/people/o_0/
90dfd75887f3e67b,https://c1.staticflickr.com/8/7683/26182602974_ddb15b42a7_o.jpg,0,0.25,1,1,986,45,https://www.flickr.com/photos/110035327@N08/26182602974,https://creativecommons.org/licenses/by/2.0/,Stefano Akram,https://www.flickr.com/people/110035327@N08/
ed56c7616a8ac010,https://c1.staticflickr.com/8/7479/27427361256_e341e77ffe_o.jpg,0.267938931,0,0.803816794,0.75,782,568,https://www.flickr.com/photos/aperturenut/27427361256,https://creativecommons.org/licenses/by/2.0/,Rick Briggs,https://www.flickr.com/people/aperturenut/
5d6b9cadb6f9e1cd,https://c1.staticflickr.com/9/8790/28885989621_1e024392cc_o.jpg,0,0,0.5,0.75,896,746,https://www.flickr.com/photos/elsie/28885989621/,https://creativecommons.org/licenses/by/2.0/,Les Chatfield,https://www.flickr.com/people/elsie/
a033832d9ff8913b,https://c1.staticflickr.com/1/545/32710656176_55231d6054_o.jpg,0,0,0.713414634,1,101,357,https://www.flickr.com/photos/wildreturn/32710656176/,https://creativecommons.org/licenses/by/2.0/,Andy Reago & Chrissy McClarren,https://www.flickr.com/people/wildreturn/
313ff0037b86260a,https://c1.staticflickr.com/6/5812/30890228762_9ffa0a8fcb_o.jpg,0,0.2515625,1,1,498,610,https://www.flickr.com/photos/southbeachcars/30890228762/,https://creativecommons.org/licenses/by/2.0/,Phillip Pessar,https://www.flickr.com/people/southbeachcars/
afe045d68f1a60d0,https://c1.staticflickr.com/6/5496/30030140344_d59046fc37_o.jpg,0.281690141,0,0.845070423,0.75,990,956,https://flickr.com/72054607@N00/30030140344,https://creativecommons.org/licenses/by/2.0/,Mark Jones,https://www.flickr.com/people/mekonsrevenge/
b19e2df06dbcccd9,https://c1.staticflickr.com/8/7511/27829151505_2172064741_o.jpg,0.421177267,0.25,0.842354533,1,673,816,https://www.flickr.com/photos/flickbergers/27829151505/,https://creativecommons.org/licenses/by/2.0/,Tim Berger,https://www.flickr.com/people/flickbergers/
510e5062fef4a993,https://c1.staticflickr.com/6/5822/30267535413_2a7544b60d_o.jpg,0,0,0.599757674,0.75,631,293,https://www.flickr.com/photos/85546319@N04/30267535413/,https://creativecommons.org/licenses/by/2.0/,Robert Sheie,https://www.flickr.com/people/85546319@N04/
943274babd06a662,https://c1.staticflickr.com/1/327/32913036916_44339626f4_o.jpg,0.28125,0,0.84375,0.75,669,678,https://www.flickr.com/photos/davidstanleytravel/32913036916,https://creativecommons.org/licenses/by/2.0/,David Stanley,https://www.flickr.com/people/davidstanleytravel/
0e83f990a04ed67d,https://c1.staticflickr.com/8/7788/28316840171_4f69657675_o.jpg,0,0,0.642547033,1,822,52,https://www.flickr.com/photos/newsoresund/28316840171,https://creativecommons.org/licenses/by/2.0/,News Oresund,https://www.flickr.com/people/newsoresund/
607702d7ef44d081,https://c1.staticflickr.com/9/8233/29529503870_9d1063daa4_o.jpg,0.28125,0,0.84375,0.75,865,347,https://www.flickr.com/photos/zombieite/29529503870,https://creativecommons.org/licenses/by/2.0/,zombieite,https://www.flickr.com/people/zombieite/
e9811aebe8bed6e5,https://c1.staticflickr.com/9/8738/27986089450_329b7a8ebc_o.jpg,0.4375,0,1,0.75,336,410,https://www.flickr.com/photos/peter-trimming/27986089450,https://creativecommons.org/licenses/by/2.0/,Peter Trimming,https://www.flickr.com/people/peter-trimming/
380053c506e32105,https://c1.staticflickr.com/8/7396/27441608895_889e301b2b_o.jpg,0,0.25,0.5625,1,780,514,https://www.flickr.com/photos/thoseguys119/27441608895,https://creativecommons.org/licenses/by/2.0/,ThoseGuys119,https://www.flickr.com/people/thoseguys119/
668bc83a884d24f9,https://c1.staticflickr.com/6/5448/30684271290_40fd020a51_o.jpg,0,0,0.728813559,1,3,391,https://flickr.com/64084569@N02/30684271290,https://creativecommons.org/licenses/by/2.0/,Singa Hitam,https://www.flickr.com/people/64084569@N02/
be9a3bea2989a0b4,https://c1.staticflickr.com/6/5724/30572182090_20ab46d2fb_o.jpg,0.25,0,0.75,0.75,718,677,https://www.flickr.com/photos/42220226@N07/30572182090,https://creativecommons.org/licenses/by/2.0/,Sicnag,https://www.flickr.com/people/42220226@N07/
b74c05ecff5f99d8,https://c1.staticflickr.com/9/8403/29162412302_d1940244a9_o.jpg,0,0,0.75,0.565438871,407,568,https://www.flickr.com/photos/eltb/29162412302,https://creativecommons.org/licenses/by/2.0/,Catedrales e Iglesias/Cathedrals and Churches,https://www.flickr.com/people/eltb/
7a51c260ca0e83e7,https://c1.staticflickr.com/4/3912/33185518846_5c9ca0ff3a_o.jpg,0.4375,0,1,0.75,548,748,https://www.flickr.com/photos/belurashok/33185518846/,https://creativecommons.org/licenses/by/2.0/,Belur Ashok,https://www.flickr.com/people/belurashok/
e89d48768917f563,https://c1.staticflickr.com/9/8043/29272187281_a1bf8985b6_o.jpg,0.437793427,0,1,0.75,459,308,https://www.flickr.com/photos/rheba/29272187281/,https://creativecommons.org/licenses/by/2.0/,Rheba,https://www.flickr.com/people/rheba/
080bec22a6b1d37d,https://c1.staticflickr.com/8/7787/27498389575_2f7553fca7_o.jpg,0.322236181,0,0.966708543,0.75,760,818,https://www.flickr.com/photos/51764518@N02/27498389575,https://creativecommons.org/licenses/by/2.0/,Joe Haupt,https://www.flickr.com/people/51764518@N02/
e37b556e8889d2ec,https://c1.staticflickr.com/6/5679/30117494085_f273295290_o.jpg,0.301659125,0,1,1,752,618,https://www.flickr.com/photos/karen_roe/30117494085,https://creativecommons.org/licenses/by/2.0/,Karen Roe,https://www.flickr.com/people/karen_roe/
67dd47336dc89421,https://c1.staticflickr.com/8/7566/26809054634_395b8c8989_o.jpg,0,0,0.5,0.75,818,949,https://www.flickr.com/photos/curtsm/26809054634/,https://creativecommons.org/licenses/by/2.0/,Curt Smith,https://www.flickr.com/people/curtsm/
25f85aadcf248cc1,https://c1.staticflickr.com/6/5503/30178488442_471bae40e3_o.jpg,0.25,0,0.75,0.75,854,890,https://www.flickr.com/photos/tanaka_juuyoh/30178488442,https://creativecommons.org/licenses/by/2.0/,TANAKA Juuyoh (\347\224\260\344\270\255\345\215\201\346\264\213),https://www.flickr.com/people/tanaka_juuyoh/
c3e9a84e039df3ce,https://c1.staticflickr.com/9/8538/29956439481_7289ba54cc_o.jpg,0.25,0,1,1,469,765,https://www.flickr.com/photos/27665395@N05/29956439481,https://creativecommons.org/licenses/by/2.0/,Jason Lawrence,https://www.flickr.com/people/27665395@N05/
0134ba03294509a1,https://c1.staticflickr.com/9/8489/29195271540_316f8c5315_o.jpg,0.25,0,0.75,0.75,982,355,https://www.flickr.com/photos/mindahaas/29195271540/,https://creativecommons.org/licenses/by/2.0/,Minda Haas Kuhlmann,https://www.flickr.com/people/mindahaas/
53fe22426ff21243,https://c1.staticflickr.com/1/626/31511641894_19a2e1d2aa_o.jpg,0.496696035,0,0.99339207,0.75,536,779,https://www.flickr.com/photos/glorycycles/31511641894,https://creativecommons.org/licenses/by/2.0/,Glory Cycles,https://www.flickr.com/people/glorycycles/
4053a6a3d0e63c01,https://c1.staticflickr.com/1/561/32656096985_6601815751_o.jpg,0,0,0.5625,0.75,392,460,https://www.flickr.com/photos/kjfnjy/32656096985/,https://creativecommons.org/licenses/by/2.0/,Ken and Nyetta,https://www.flickr.com/people/kjfnjy/
3ece3c1f94e4141a,https://c1.staticflickr.com/1/484/31819662813_17ab59d903_o.jpg,0.422345483,0.25,1,1,332,15,https://www.flickr.com/photos/usfwsmtnprairie/31819662813,https://creativecommons.org/licenses/by/2.0/,USFWS Mountain-Prairie,https://www.flickr.com/people/usfwsmtnprairie/
7d253f78ef6f029a,https://c1.staticflickr.com/6/5488/29967850914_d7e94fa9f2_o.jpg,0,0,1,1,683,92,https://flickr.com/23562593@N07/29967850914,https://creativecommons.org/licenses/by/2.0/,Benjamin Wunn,https://www.flickr.com/people/derzw3rg/
fecd59b8de8ae6f7,https://c1.staticflickr.com/1/475/31566723602_ced86113ef_o.jpg,0.25,0.25,0.75,1,820,793,https://www.flickr.com/photos/stevendepolo/31566723602/,https://creativecommons.org/licenses/by/2.0/,Steven Depolo,https://www.flickr.com/people/stevendepolo/
24159caf9c5e92be,https://c1.staticflickr.com/1/471/30661449994_6c0d5f9050_o.jpg,0.5,0,1,0.75,708,743,https://www.flickr.com/photos/146625745@N08/30661449994,https://creativecommons.org/licenses/by/2.0/,home thods,https://www.flickr.com/people/146625745@N08/
44982b98ba192bb7,https://c1.staticflickr.com/9/8301/28642395174_40ebd0c8df_o.jpg,0.25,0,0.75,0.75,322,411,https://www.flickr.com/photos/wm_archiv/28642395174/,https://creativecommons.org/licenses/by/2.0/,Allie_Caulfield,https://www.flickr.com/people/wm_archiv/
7ca714cdcd5d36d9,https://c1.staticflickr.com/8/7400/27242157102_b9cb18ffa1_o.jpg,0,0,0.5625,0.75,780,106,https://www.flickr.com/photos/thoseguys119/27242157102,https://creativecommons.org/licenses/by/2.0/,ThoseGuys119,https://www.flickr.com/people/thoseguys119/
cbaff3255afbe83f,https://c1.staticflickr.com/9/8118/29896215326_352a9625cf_o.jpg,0,0.25,0.670648464,1,561,853,https://www.flickr.com/photos/dirkhansen/29896215326,https://creativecommons.org/licenses/by/2.0/,SD Dirk,https://www.flickr.com/people/dirkhansen/
fafbad0b3093a886,https://c1.staticflickr.com/9/8699/27967786060_8e927f96b6_o.jpg,0.287776899,0.25,0.863330696,1,672,315,https://www.flickr.com/photos/glorycycles/27967786060,https://creativecommons.org/licenses/by/2.0/,Glory Cycles,https://www.flickr.com/people/glorycycles/
45315ea51da415ab,https://c1.staticflickr.com/9/8855/27598466234_c924d2bdfc_o.jpg,0.25,0.25,0.75,1,356,189,https://www.flickr.com/photos/o_0/27598466234,https://creativecommons.org/licenses/by/2.0/,Guilhem Vellut,https://www.flickr.com/people/o_0/
1e4bb9fd37654da6,https://c1.staticflickr.com/9/8270/29189744532_98cb04acea_o.jpg,0.25,0.25,1,0.75,820,538,https://www.flickr.com/photos/tim_uk/29189744532,https://creativecommons.org/licenses/by/2.0/,Tim Sheerman-Chase,https://www.flickr.com/people/tim_uk/
5f3ea3c6b683fb57,https://c1.staticflickr.com/1/780/32585346961_4f8e8d97e3_o.jpg,0.5,0,1,0.75,773,62,https://flickr.com/28752865@N08/32585346961,https://creativecommons.org/licenses/by/2.0/,Karen Roe,https://www.flickr.com/people/karen_roe/
ccbcaf10176e78e0,https://c1.staticflickr.com/9/8397/27954967983_925cdd6886_o.jpg,0,0,0.5,0.75,923,858,https://www.flickr.com/photos/alan-light/27954967983,https://creativecommons.org/licenses/by/2.0/,Alan Light,https://www.flickr.com/people/alan-light/
8d17aa69b4fd7b45,https://c1.staticflickr.com/6/5664/29822954894_e605bf0229_o.jpg,0,0,0.666666667,1,407,590,https://www.flickr.com/photos/quinet/29822954894,https://creativecommons.org/licenses/by/2.0/,Thomas Quine,https://www.flickr.com/people/quinet/
c25da85d5d62b000,https://c1.staticflickr.com/8/7322/27388042450_19773a1bc9_o.jpg,0,0.25,0.5,1,404,219,https://www.flickr.com/photos/usnavy/27388042450,https://creativecommons.org/licenses/by/2.0/,Official U.S. Navy Page,https://www.flickr.com/people/usnavy/
beb3e55c385feb12,https://c1.staticflickr.com/9/8817/28251101564_5f9eb85574_o.jpg,0.177484472,0.25,0.532453416,1,815,881,https://www.flickr.com/photos/watts_photos/28251101564,https://creativecommons.org/licenses/by/2.0/,C Watts,https://www.flickr.com/people/watts_photos/
ed3573d0c197fbaf,https://c1.staticflickr.com/9/8337/28698753904_d31322462d_o.jpg,0.498159057,0.25,0.996318115,1,848,190,https://www.flickr.com/photos/exercitobrasileiro/28698753904,https://creativecommons.org/licenses/by/2.0/,Ex\303\251rcito Brasileiro,https://www.flickr.com/people/exercitobrasileiro/
95d1a6be6786190f,https://c1.staticflickr.com/6/5580/31026020991_dbbbedc4f6_o.jpg,0.5,0.25,1,1,891,983,https://www.flickr.com/photos/swisstchoukball/31026020991/,https://creativecommons.org/licenses/by/2.0/,Swiss Tchoukball,https://www.flickr.com/people/swisstchoukball/
c8abefc975e94b10,https://c1.staticflickr.com/8/7451/27275536125_1b48f36807_o.jpg,0,0,0.563380282,0.75,875,675,https://www.flickr.com/photos/southbeachcars/27275536125,https://creativecommons.org/licenses/by/2.0/,Phillip Pessar,https://www.flickr.com/people/southbeachcars/
be97d1e63c32043e,https://c1.staticflickr.com/9/8268/29636815873_a756a0aaec_o.jpg,0,0.25,0.670648464,1,95,230,https://www.flickr.com/photos/sucriertt/29636815873/,https://creativecommons.org/licenses/by/2.0/,Feroze Omardeen,https://www.flickr.com/people/sucriertt/
df2cd1b82d5dec14,https://c1.staticflickr.com/6/5499/31112840340_73557ca884_o.jpg,0.5,0.25,1,1,519,414,https://www.flickr.com/photos/box_repsol/31112840340,https://creativecommons.org/licenses/by/2.0/,Box Repsol,https://www.flickr.com/people/box_repsol/
024f73e53c3c1f1d,https://c1.staticflickr.com/8/7784/27062661262_9732ff0e24_o.jpg,0.333333333,0,1,1,580,638,https://www.flickr.com/photos/dalbera/27062661262,https://creativecommons.org/licenses/by/2.0/,Jean-Pierre Dalb\303\251ra,https://www.flickr.com/people/dalbera/
e957c417fcd20c5b,https://c1.staticflickr.com/6/5728/31046143176_16800f95c8_o.jpg,0.199868074,0.25,0.599604222,1,820,791,https://www.flickr.com/photos/usembassyta/31046143176/,https://creativecommons.org/licenses/by/2.0/,U.S. Embassy Tel Aviv,https://www.flickr.com/people/usembassyta/
795f5aef9bef8134,https://c1.staticflickr.com/8/7246/27059914000_5331c7a27c_o.jpg,0.231382979,0.25,0.694148936,1,826,29,https://www.flickr.com/photos/sanp/27059914000,https://creativecommons.org/licenses/by/2.0/,San P,https://www.flickr.com/people/sanp/
422d08407aeed1be,https://c1.staticflickr.com/9/8891/28070937640_a79a8cbfa5_o.jpg,0.4375,0,1,0.75,114,44,https://www.flickr.com/photos/yutakaseki/28070937640,https://creativecommons.org/licenses/by/2.0/,Yutaka Seki,https://www.flickr.com/people/yutakaseki/
69a39406cb1d2ce5,https://c1.staticflickr.com/8/7179/27561675775_4977abbb7b_o.jpg,0,0.25,0.75,1,476,46,https://www.flickr.com/photos/44156646@N06/27561675775,https://creativecommons.org/licenses/by/2.0/,Frederick Lang Jr.,https://www.flickr.com/people/44156646@N06/
564de663adeb8cd5,https://c1.staticflickr.com/8/7207/27043384543_1ee00dc2e1_o.jpg,0.494868035,0,0.98973607,0.75,558,133,https://www.flickr.com/photos/governortomwolf/27043384543,https://creativecommons.org/licenses/by/2.0/,Governor Tom Wolf,https://www.flickr.com/people/governortomwolf/
04c1bde5affb7b5b,https://c1.staticflickr.com/1/473/31566239624_128d26f762_o.jpg,0.285496183,0,1,1,653,680,https://www.flickr.com/photos/rdecom/31566239624,https://creativecommons.org/licenses/by/2.0/,U.S. Army RDECOM,https://www.flickr.com/people/rdecom/
90f5385a77a49f77,https://c1.staticflickr.com/8/7393/26525400000_f5d0ae4309_o.jpg,0.248713235,0.25,0.746139706,1,704,905,https://www.flickr.com/photos/panr/26525400000,https://creativecommons.org/licenses/by/2.0/,Robert Cutts,https://www.flickr.com/people/panr/
604b54a3b7424d9b,https://c1.staticflickr.com/9/8358/29207069984_4f7b859b65_o.jpg,0,0.25,0.501846381,1,939,430,https://flickr.com/25797459@N06/29207069984,https://creativecommons.org/licenses/by/2.0/,zaphad1,https://www.flickr.com/people/25797459@N06/
a6535c039bfeba2c,https://c1.staticflickr.com/1/737/32082026800_fdf44c3c27_o.jpg,0,0,0.561328125,0.75,536,292,https://www.flickr.com/photos/glorycycles/32082026800,https://creativecommons.org/licenses/by/2.0/,Glory Cycles,https://www.flickr.com/people/glorycycles/
35d67f3f70aeef92,https://c1.staticflickr.com/8/7324/28047778902_e23628dc50_o.jpg,0.25,0.25,0.75,1,980,582,https://www.flickr.com/photos/coreyheitzmd/28047778902,https://creativecommons.org/licenses/by/2.0/,CHeitz,https://www.flickr.com/people/coreyheitzmd/
3efa3df701898afd,https://c1.staticflickr.com/9/8783/28492814412_129982444e_o.jpg,0,0,0.905498282,1,737,1000,https://www.flickr.com/photos/stevendepolo/28492814412,https://creativecommons.org/licenses/by/2.0/,Steven Depolo,https://www.flickr.com/people/stevendepolo/
f08f34c258228251,https://c1.staticflickr.com/9/8256/28174054160_790b304fc4_o.jpg,0.28125,0.25,0.84375,1,699,608,https://www.flickr.com/photos/rubenholthuijsen/28174054160/,https://creativecommons.org/licenses/by/2.0/,Ruben Holthuijsen,https://www.flickr.com/people/rubenholthuijsen/
d47c9aabecda0e12,https://c1.staticflickr.com/8/7441/27270121096_cc1007eb2f_o.jpg,0.5,0,1,0.75,986,199,https://www.flickr.com/photos/56218409@N03/27270121096,https://creativecommons.org/licenses/by/2.0/,Matthias Ripp,https://www.flickr.com/people/56218409@N03/
d97c1f3f1c211d1a,https://c1.staticflickr.com/9/8448/28945025323_6e7cdf207a_o.jpg,0,0,0.75,0.75,979,467,https://www.flickr.com/photos/edans/28945025323,https://creativecommons.org/licenses/by/2.0/,Enrique Dans,https://www.flickr.com/people/edans/
62949c357e429690,https://c1.staticflickr.com/1/764/31219968184_cf7294c955_o.jpg,0.25,0.25,0.75,1,973,116,https://www.flickr.com/photos/jlascar/31219968184,https://creativecommons.org/licenses/by/2.0/,Jorge L\303\241scar,https://www.flickr.com/people/jlascar/
9311a098cfb4b946,https://c1.staticflickr.com/8/7373/26786081873_73a09aab2f_o.jpg,0.25,0.25,0.75,1,821,192,https://www.flickr.com/photos/ben_salter/26786081873/,https://creativecommons.org/licenses/by/2.0/,Ben Salter,https://www.flickr.com/people/ben_salter/
38d8d105d5e70c80,https://c1.staticflickr.com/8/7457/27675995271_5b6dc8a928_o.jpg,0,0,1,1,422,755,https://www.flickr.com/photos/arbron/27675995271,https://creativecommons.org/licenses/by/2.0/,Jeff Hitchcock,https://www.flickr.com/people/arbron/
a28beac14b9037da,https://c1.staticflickr.com/8/7408/26281652233_6667df70cb_o.jpg,0.333333333,0,1,1,405,351,https://www.flickr.com/photos/km30192002/26281652233/,https://creativecommons.org/licenses/by/2.0/,km30192002,https://www.flickr.com/people/km30192002/
fa3aae44c2675e88,https://c1.staticflickr.com/9/8776/28284921904_800c76d8ac_o.jpg,0.496696035,0,0.99339207,0.75,771,375,https://www.flickr.com/photos/spera-designerschuhe/28284921904,https://creativecommons.org/licenses/by/2.0/,"SPERA.de Designerschuhe, Taschen und Accessoires",https://www.flickr.com/people/spera-designerschuhe/
44aa69f642b86628,https://c1.staticflickr.com/8/7413/27678489230_1d967f5b58_o.jpg,0,0,0.634532374,1,880,549,https://www.flickr.com/photos/45909111@N00/27678489230,https://creativecommons.org/licenses/by/2.0/,Gwydion M. Williams,https://www.flickr.com/people/45909111@N00/
6cc289dc7a8fce86,https://c1.staticflickr.com/9/8671/28656397400_d4db68df02_o.jpg,0.501840943,0.25,1,1,158,1000,https://www.flickr.com/photos/naql/28656397400,https://creativecommons.org/licenses/by/2.0/,naql,https://www.flickr.com/people/naql/
a92babc0a6436d3b,https://c1.staticflickr.com/8/7582/28982049520_eddc2d650d_o.jpg,0,0.25,0.5,1,760,655,https://www.flickr.com/photos/ulift/28982049520/in/album-72157672059230641/,https://creativecommons.org/licenses/by/2.0/,WEi WEi,https://www.flickr.com/people/ulift/
9fbeb797de1e1639,https://c1.staticflickr.com/9/8083/29921495296_991d4559c0_o.jpg,0.421747967,0,0.843495935,0.75,763,511,https://www.flickr.com/photos/vuhung/29921495296,https://creativecommons.org/licenses/by/2.0/,Nguyen Hung Vu,https://www.flickr.com/people/vuhung/
16179baa1513c701,https://c1.staticflickr.com/1/722/32761564425_d122c3838d_o.jpg,0,0,0.75,1,95,505,https://flickr.com/95098864@N08/32761564425,https://creativecommons.org/licenses/by/2.0/,S. Rohrlach,https://www.flickr.com/people/95098864@N08/
5a8d5bc9bf40e832,https://c1.staticflickr.com/6/5692/30199498082_eba90ef2e1_o.jpg,0,0,0.666666667,1,519,634,https://www.flickr.com/photos/box_repsol/30199498082,https://creativecommons.org/licenses/by/2.0/,Box Repsol,https://www.flickr.com/people/box_repsol/
aa4e1cf9cb6e7801,https://c1.staticflickr.com/9/8183/29036345831_4da7d925c9_o.jpg,0.151376147,0.25,0.45412844,1,896,840,https://www.flickr.com/photos/ronmacphotos/29036345831/,https://creativecommons.org/licenses/by/2.0/,Ronnie Macdonald,https://www.flickr.com/people/ronmacphotos/
200735f93ea764f2,https://c1.staticflickr.com/8/7582/29431396080_570340a5ef_o.jpg,0.310344828,0,0.931034483,0.75,309,285,https://www.flickr.com/photos/gails_pictures/29431396080,https://creativecommons.org/licenses/by/2.0/,gailhampshire,https://www.flickr.com/people/gails_pictures/
5d53f9bc389e98ad,https://c1.staticflickr.com/1/722/30784991794_6af0ab8176_o.jpg,0.25,0.25,0.75,1,265,468,https://www.flickr.com/photos/unirodlibrary/30784991794/,https://creativecommons.org/licenses/by/2.0/,Rod Library,https://www.flickr.com/people/unirodlibrary/
5b974695c09ad165,https://c1.staticflickr.com/9/8453/29350958465_8426fed375_o.jpg,0.25,0.484655689,1,1,991,393,https://www.flickr.com/photos/clairity/29350958465/,https://creativecommons.org/licenses/by/2.0/,Sharon Mollerus,https://www.flickr.com/people/clairity/
becf3b004177ded6,https://c1.staticflickr.com/8/7565/28346247573_c430ef5720_o.jpg,0.193181818,0,1,1,986,457,https://www.flickr.com/photos/34905030@N00/28346247573/,https://creativecommons.org/licenses/by/2.0/,Orangeaurochs,https://www.flickr.com/people/orangeaurochs/
4f04ca75d7aafc0a,https://c1.staticflickr.com/8/7126/27594041042_ef94e651db_o.jpg,0.25,0.249631811,1,0.748895434,840,633,https://www.flickr.com/photos/girlguidesofcan/27594041042/,https://creativecommons.org/licenses/by/2.0/,Girl Guides of Canada,https://www.flickr.com/people/girlguidesofcan/
8764eecf6e898c7f,https://c1.staticflickr.com/8/7393/27564047580_b1667768cf_o.jpg,0.33773862,0,1,1,484,711,https://www.flickr.com/photos/sybarite48/27564047580,https://creativecommons.org/licenses/by/2.0/,Daniel Jolivet,https://www.flickr.com/people/sybarite48/
c5f5e09f4f5fd41a,https://c1.staticflickr.com/9/8134/28977820041_e39c5c15c4_o.jpg,0.559602649,0.25,0.839403974,1,404,421,https://flickr.com/7489441@N06/28977820041,https://creativecommons.org/licenses/by/2.0/,Clemens Vasters,https://www.flickr.com/people/clemensv/
17f3b8a057bc01be,https://c1.staticflickr.com/8/7537/28104131410_e13ab8f9ef_o.jpg,0,0,1,1,859,575,https://www.flickr.com/photos/v1ctor/28104131410,https://creativecommons.org/licenses/by/2.0/,Victor,https://www.flickr.com/people/v1ctor/
c10f6e0689efbc1c,https://c1.staticflickr.com/1/258/32241427822_ac7330299e_o.jpg,0.27818818,0.25,0.834564541,1,888,297,https://www.flickr.com/photos/guldem/32241427822,https://creativecommons.org/licenses/by/2.0/,G\303\274ldem \303\234st\303\274n,https://www.flickr.com/people/guldem/
0e9bdc3ab80b1a71,https://c1.staticflickr.com/8/7415/27313160706_a2440a83b0_o.jpg,0.5,0,1,0.75,367,335,https://www.flickr.com/photos/ross_elliott/27313160706,https://creativecommons.org/licenses/by/2.0/,Ross Elliott,https://www.flickr.com/people/ross_elliott/
c17d39b1eba4cc03,https://c1.staticflickr.com/8/7468/27818709730_d10459c415_o.jpg,0,0.5,0.75,1,669,732,https://www.flickr.com/photos/jdlasica/27818709730,https://creativecommons.org/licenses/by/2.0/,JD Lasica,https://www.flickr.com/people/jdlasica/
ec346009f286ffca,https://c1.staticflickr.com/1/571/30740221514_3c4fa602a0_o.jpg,0,0,0.5,0.75,120,783,https://www.flickr.com/photos/conchur/30740221514/,https://creativecommons.org/licenses/by/2.0/,Conor Lawless,https://www.flickr.com/people/conchur/
01fa4be27dd11b5d,https://c1.staticflickr.com/1/268/31600495093_a46c0835d2_o.jpg,0.4375,0,1,0.75,451,829,https://www.flickr.com/photos/ufv/31600495093/,https://creativecommons.org/licenses/by/2.0/,University of the Fraser Valley,https://www.flickr.com/people/ufv/
490df9e021386d29,https://c1.staticflickr.com/6/5800/30150475824_b342db70fa_o.jpg,0.150773196,0,0.452319588,0.75,405,351,https://flickr.com/37804979@N00/30150475824,https://creativecommons.org/licenses/by/2.0/,Tony Hisgett,https://www.flickr.com/people/hisgett/
08fbf75e60a6efb7,https://c1.staticflickr.com/9/8270/29799045164_ab072918cb_o.jpg,0,0,0.66226138,1,484,666,https://www.flickr.com/photos/sybarite48/29799045164,https://creativecommons.org/licenses/by/2.0/,Daniel Jolivet,https://www.flickr.com/people/sybarite48/
fc583c08026e3d74,https://c1.staticflickr.com/6/5595/30252932446_a7c00f3a97_o.jpg,0.333333333,0,1,1,881,588,https://www.flickr.com/photos/mobikefed/30252932446,https://creativecommons.org/licenses/by/2.0/,MoBikeFed,https://www.flickr.com/people/mobikefed/
db6c6671a6924eba,https://c1.staticflickr.com/9/8269/30416458805_dc9a3ef437_o.jpg,0.25,0,1,0.591346154,407,412,https://www.flickr.com/photos/eltb/30416458805,https://creativecommons.org/licenses/by/2.0/,Catedrales e Iglesias/Cathedrals and Churches,https://www.flickr.com/people/eltb/
5a6439b10c1f6761,https://c1.staticflickr.com/6/5703/29661528724_1ccb11fae8_o.jpg,0,0.25,0.561328125,1,320,871,https://flickr.com/86548370@N00/29661528724,https://creativecommons.org/licenses/by/2.0/,Katja Schulz,https://www.flickr.com/people/treegrow/
218e02b6cfa0466e,https://c1.staticflickr.com/1/702/32609631415_d7bf443a2c_o.jpg,0.5,0.25,1,1,699,217,https://www.flickr.com/photos/renaissancechambara/32609631415/,https://creativecommons.org/licenses/by/2.0/,Ged Carroll,https://www.flickr.com/people/renaissancechambara/
3f8bf287f20333eb,https://c1.staticflickr.com/9/8895/29333257946_c53911b432_o.jpg,0,0,0.5,0.75,973,713,https://www.flickr.com/photos/aschaf/29333257946/,https://creativecommons.org/licenses/by/2.0/,Andrea Schaffer,https://www.flickr.com/people/aschaf/
be5543dc68f0b970,https://c1.staticflickr.com/6/5835/30148396554_e2ec6fbf0d_o.jpg,0.441600679,0,0.736001131,0.75,780,636,https://www.flickr.com/photos/thoseguys119/30148396554,https://creativecommons.org/licenses/by/2.0/,ThoseGuys119,https://www.flickr.com/people/thoseguys119/
87fcc5f70673d3d2,https://c1.staticflickr.com/8/7455/27040942130_44a032d0fd_o.jpg,0.421177267,0,0.842354533,0.75,699,159,https://www.flickr.com/photos/nat507/27040942130,https://creativecommons.org/licenses/by/2.0/,Nathan Hughes Hamilton,https://www.flickr.com/people/nat507/
99f175132cd1c6e2,https://c1.staticflickr.com/8/7045/27716560671_79806e498e_o.jpg,0.25,0,1,0.75,934,459,https://www.flickr.com/photos/danielchownet/27716560671,https://creativecommons.org/licenses/by/2.0/,Daniel Chow,https://www.flickr.com/people/danielchownet/
a4f718e554dd18dd,https://c1.staticflickr.com/6/5445/29774026800_5e37689427_o.jpg,0.5,0.25,1,1,976,95,https://www.flickr.com/photos/wm_archiv/29774026800,https://creativecommons.org/licenses/by/2.0/,Allie_Caulfield,https://www.flickr.com/people/wm_archiv/
46a489dcff5471a4,https://c1.staticflickr.com/3/2634/32267074504_a395babafd_o.jpg,0,0,0.75,0.75,920,590,https://www.flickr.com/photos/83015819@N00/32267074504/,https://creativecommons.org/licenses/by/2.0/,Jon Worth,https://www.flickr.com/people/83015819@N00/
38c6124f40b8d845,https://c1.staticflickr.com/8/7589/27543292150_7375ef6b66_o.jpg,0.249631811,0,0.748895434,0.75,896,19,https://www.flickr.com/photos/ministreiodadefesa/27543292150/,https://creativecommons.org/licenses/by/2.0/,Minist\303\251rio da Defesa,https://www.flickr.com/people/ministreiodadefesa/
6740e1e89b5bbab4,https://c1.staticflickr.com/1/439/32456945576_0d93348b0e_o.jpg,0.25,0.25,0.75,1,981,685,https://www.flickr.com/photos/30478819@N08/32456945576,https://creativecommons.org/licenses/by/2.0/,Marco Verch,https://www.flickr.com/people/30478819@N08/
54ff02d9dfbf8540,https://c1.staticflickr.com/6/5703/30663546512_038de017f8_o.jpg,0.249079529,0,0.747238586,0.75,884,370,https://www.flickr.com/photos/reliv/30663546512/,https://creativecommons.org/licenses/by/2.0/,Reliv International,https://www.flickr.com/people/reliv/
2c9398f44d099e0f,https://c1.staticflickr.com/3/2051/32840993165_29d0cb8a1e_o.jpg,0,0,1,0.75,522,482,http://www.flickr.com/photos/23119666@N03/32840993165/,https://creativecommons.org/licenses/by/2.0/,Mark Bonica,https://www.flickr.com/people/23119666@N03/
6896a8b78f404dc8,https://c1.staticflickr.com/9/8358/29790317621_d6a35e5136_o.jpg,0.4375,0.25,1,1,980,75,https://www.flickr.com/photos/kameyama-mie/29790317621,https://creativecommons.org/licenses/by/2.0/,Kasadera,https://www.flickr.com/people/kameyama-mie/
d2d6ae6e0b8a0c31,https://c1.staticflickr.com/6/5600/30243986500_e184ef72fb_o.jpg,0,0,0.5,0.75,986,601,https://www.flickr.com/photos/blumenbiene/30243986500,https://creativecommons.org/licenses/by/2.0/,Maja Dumat,https://www.flickr.com/people/blumenbiene/
fccfc3563cd562e1,https://c1.staticflickr.com/9/8645/27729536774_b56a633841_o.jpg,0.25,0.25,0.75,1,977,656,https://flickr.com/111347625@N06/27729536774,https://creativecommons.org/licenses/by/2.0/,Heribert Bechen ... bin dann mal weg!,https://www.flickr.com/people/hb1248/
d3a88c50958b1b5f,https://c1.staticflickr.com/9/8746/27853631254_508e610bc1_o.jpg,0,0.25,0.5,1,977,1000,https://www.flickr.com/photos/celteverett/27853631254,https://creativecommons.org/licenses/by/2.0/,Gregorio Puga Bail\303\263n,https://www.flickr.com/people/celteverett/
513b3032ed1f388c,https://c1.staticflickr.com/8/7514/27572579621_930aecf52c_o.jpg,0.28125,0.25,0.84375,1,114,542,https://www.flickr.com/photos/viewpix69/27572579621/,https://creativecommons.org/licenses/by/2.0/,Torsten Scholz,https://www.flickr.com/people/viewpix69/
6217866896fbe2b7,https://c1.staticflickr.com/6/5719/30923267621_c221b094fe_o.jpg,0,0,0.5,0.75,699,867,https://www.flickr.com/photos/mondo79/30923267621/,https://creativecommons.org/licenses/by/2.0/,Mondo79,https://www.flickr.com/people/mondo79/
21554e755b9706d2,https://c1.staticflickr.com/1/641/32391235981_071803d033_o.jpg,0,0,0.75,0.529210926,342,76,https://www.flickr.com/photos/ilri/32391235981,https://creativecommons.org/licenses/by/2.0/,ILRI,https://www.flickr.com/people/ilri/
87a2147620d5e1cb,https://c1.staticflickr.com/6/5603/30536597041_14c0e333ab_o.jpg,0.4375,0,1,0.75,780,290,https://www.flickr.com/photos/thoseguys119/30536597041/,https://creativecommons.org/licenses/by/2.0/,ThoseGuys119,https://www.flickr.com/people/thoseguys119/
b86d604067f50613,https://c1.staticflickr.com/6/5791/30885593836_dda0ff2d59_o.jpg,0,0.248826291,1,1,490,998,https://www.flickr.com/photos/southbeachcars/30885593836/,https://creativecommons.org/licenses/by/2.0/,Phillip Pessar,https://www.flickr.com/people/southbeachcars/
af3736cca01a2d28,https://c1.staticflickr.com/1/636/32603914891_d687da69f1_o.jpg,0.25,0,1,0.75,318,766,https://www.flickr.com/photos/treegrow/32603914891/,https://creativecommons.org/licenses/by/2.0/,Katja Schulz,https://www.flickr.com/people/treegrow/
5adb3d985cf217a9,https://c1.staticflickr.com/3/2183/32995484255_f1c2125a38_o.jpg,0,0.25,0.421177267,1,405,875,https://www.flickr.com/photos/n-bphotography/32995484255/,https://creativecommons.org/licenses/by/2.0/,Nicky Boogaard,https://www.flickr.com/people/n-bphotography/
60566d5680497389,https://c1.staticflickr.com/8/7117/27308045115_c9860d768d_o.jpg,0.5,0,1,0.75,473,544,https://www.flickr.com/photos/vastateparksstaff/27308045115,https://creativecommons.org/licenses/by/2.0/,Virginia State Parks,https://www.flickr.com/people/vastateparksstaff/
1cfa5381359bff9f,https://c1.staticflickr.com/6/5669/30198502892_8d507f5277_o.jpg,0.33773862,0,1,1,422,852,https://www.flickr.com/photos/parktatar/30198502892,https://creativecommons.org/licenses/by/2.0/,\320\237\320\260\321\200\320\272\320\270 \320\242\320\260\321\202\320\260\321\200\321\201\321\202\320\260\320\275\320\260,https://www.flickr.com/people/parktatar/
cd40b0e46c9da574,https://c1.staticflickr.com/8/7705/27405552721_fa059a91db_o.jpg,0,0.25,0.75,1,662,739,https://www.flickr.com/photos/29233640@N07/27405552721,https://creativecommons.org/licenses/by/2.0/,Robert Couse-Baker,https://www.flickr.com/people/29233640@N07/
e9ecdf28dc1d5a85,https://c1.staticflickr.com/8/7293/27771548652_1bbed73d9a_o.jpg,0.25,0.25,1,0.75,609,192,https://www.flickr.com/photos/66755335@N05/27771548652,https://creativecommons.org/licenses/by/2.0/,Geneva Vanderzeil apairandasparediy.com,https://www.flickr.com/people/66755335@N05/
821aae58dc96b4b2,https://c1.staticflickr.com/8/7668/26973339655_c7771d9f37_o.jpg,0.447698745,0.25,0.89539749,1,341,575,http://www.flickr.com/photos/125382597@N08/26973339655/,https://creativecommons.org/licenses/by/2.0/,Roger Hsu,https://www.flickr.com/people/125382597@N08/
715335d5ddfca1f2,https://c1.staticflickr.com/6/5443/30684352681_e443895cc6_o.jpg,0,0.25,0.497426471,1,481,915,https://www.flickr.com/photos/agenciasenado/30684352681,https://creativecommons.org/licenses/by/2.0/,Senado Federal,https://www.flickr.com/people/agenciasenado/
1be47d60e0156bbb,https://c1.staticflickr.com/6/5828/29885217483_5d5c3b4561_o.jpg,0.25,0,1,1,650,912,https://flickr.com/8558643@N06/29885217483,https://creativecommons.org/licenses/by/2.0/,Christophe Delaere,https://www.flickr.com/people/delaere/
8724748782cb6c31,https://c1.staticflickr.com/1/505/31480812833_d9a37e0bee_o.jpg,0,0,0.944554455,1,76,647,https://flickr.com/55893585@N08/31480812833,https://creativecommons.org/licenses/by/2.0/,BLM Nevada,https://www.flickr.com/people/blmnevada/
2ba52bcf59097dc8,https://c1.staticflickr.com/9/8703/29072678195_c8c916e504_o.jpg,0,0,0.563380282,0.75,971,850,https://www.flickr.com/photos/blackwing_de/29072678195,https://creativecommons.org/licenses/by/2.0/,Sebastian Werner,https://www.flickr.com/people/blackwing_de/
2ed718f6db9785f8,https://c1.staticflickr.com/9/8109/29184695352_02765c0138_o.jpg,0.25,0,0.75,0.75,519,843,https://www.flickr.com/photos/box_repsol/29184695352,https://creativecommons.org/licenses/by/2.0/,Box Repsol,https://www.flickr.com/people/box_repsol/
4a251fb6d80b5137,https://c1.staticflickr.com/8/7735/27313853085_2df82462d3_o.jpg,0.439547582,0,1,0.75,800,82,https://flickr.com/21461098@N00/27313853085,https://creativecommons.org/licenses/by/2.0/,Owen Allen,https://www.flickr.com/people/owen59/
3617bfc5d06bc196,https://c1.staticflickr.com/6/5608/29603872360_115b742b20_o.jpg,0.210588633,0.25,0.6317659,1,885,554,https://www.flickr.com/photos/ankurp/29603872360,https://creativecommons.org/licenses/by/2.0/,Ankur P,https://www.flickr.com/people/ankurp/
143c74a57326fd40,https://c1.staticflickr.com/1/362/31438358143_d5b15f28de_o.jpg,0.333333333,0,1,1,422,423,https://www.flickr.com/photos/robin-schmitt/31438358143/,https://creativecommons.org/licenses/by/2.0/,Siris,https://www.flickr.com/people/robin-schmitt/
d051e0bd46125123,https://c1.staticflickr.com/6/5748/31131978085_c9153efb9d_o.jpg,0.4375,0.25,1,1,669,776,https://www.flickr.com/photos/96223380@N02/31131978085,https://creativecommons.org/licenses/by/2.0/,Mighty Travels,https://www.flickr.com/people/96223380@N02/
84af93c72781b7f0,https://c1.staticflickr.com/2/1616/26473779220_95c074ef92_o.jpg,0,0.443623639,0.75,1,438,782,https://www.flickr.com/photos/kansallisarkisto/26473779220,https://creativecommons.org/licenses/by/2.0/,Kansallisarkisto,https://www.flickr.com/people/kansallisarkisto/
a52570066ecc61fd,https://c1.staticflickr.com/1/660/31595952701_5eab9952f3_o.jpg,0,0,0.75,1,976,583,https://www.flickr.com/photos/elzey/31595952701,https://creativecommons.org/licenses/by/2.0/,Richard Elzey,https://www.flickr.com/people/elzey/
3e8bf1eee7083f6e,https://c1.staticflickr.com/6/5325/30267534593_e497c0a76a_o.jpg,0,0,0.599757674,0.75,631,683,https://www.flickr.com/photos/85546319@N04/30267534593,https://creativecommons.org/licenses/by/2.0/,Robert Sheie,https://www.flickr.com/people/85546319@N04/
f6d5c95ce7908a58,https://c1.staticflickr.com/9/8103/29317853454_b2dec062c2_o.jpg,0.493768328,0,0.987536657,0.75,561,872,https://www.flickr.com/photos/codnewsroom/29317853454,https://creativecommons.org/licenses/by/2.0/,COD Newsroom,https://www.flickr.com/people/codnewsroom/
bfb2aaf48d7fc08c,https://c1.staticflickr.com/6/5347/30848584970_9d7dd68247_o.jpg,0,0.25,0.5,1,979,953,https://www.flickr.com/photos/deaconmacmillan/30848584970/,https://creativecommons.org/licenses/by/2.0/,Deacon MacMillan,https://www.flickr.com/people/deaconmacmillan/
5528f7330399485f,https://c1.staticflickr.com/6/5821/30665663016_f164e1bbae_o.jpg,0.248826291,0,1,1,74,212,http://www.flickr.com/photos/cbroders/30665663016/,https://creativecommons.org/licenses/by/2.0/,Counse,https://www.flickr.com/people/cbroders/
635ea505879178ed,https://c1.staticflickr.com/6/5787/29740591494_abecb27341_o.jpg,0,0.35413643,1,1,539,923,https://www.flickr.com/photos/22711505@N05/29740591494,https://creativecommons.org/licenses/by/2.0/,Ron Cogswell,https://www.flickr.com/people/22711505@N05/
a8631b077e74f7aa,https://c1.staticflickr.com/9/8521/28560392972_e2f7a70fbd_o.jpg,0,0.4375,0.75,1,480,486,https://www.flickr.com/photos/jonnymooshoo/28560392972/,https://creativecommons.org/licenses/by/2.0/,Jonathan Leung,https://www.flickr.com/people/jonnymooshoo/
bb03be3702584eeb,https://c1.staticflickr.com/9/8825/28189849211_8747a0ee87_o.jpg,0,0,0.85475793,1,672,624,https://www.flickr.com/photos/glorycycles/28189849211,https://creativecommons.org/licenses/by/2.0/,Glory Cycles,https://www.flickr.com/people/glorycycles/
8090736c8299ab28,https://c1.staticflickr.com/8/7301/27600935412_70c27a16d2_o.jpg,0.25,0.4375,1,1,980,894,https://www.flickr.com/photos/kitkaphotogirl/27600935412/,https://creativecommons.org/licenses/by/2.0/,Christine Majul,https://www.flickr.com/people/kitkaphotogirl/
74b13710bcf4f7f3,https://c1.staticflickr.com/8/7271/27059072776_6f5d6d0919_o.jpg,0.503303965,0,1,0.75,775,918,https://www.flickr.com/photos/spera-designerschuhe/27059072776,https://creativecommons.org/licenses/by/2.0/,"SPERA.de Designerschuhe, Taschen und Accessoires",https://www.flickr.com/people/spera-designerschuhe/
ecd3a969dd466349,https://c1.staticflickr.com/8/7423/28019501745_3975453d32_o.jpg,0.25,0.25,1,1,285,693,https://www.flickr.com/photos/editor/28019501745,https://creativecommons.org/licenses/by/2.0/,Bart Everson,https://www.flickr.com/people/editor/
2abcab3d77d4767e,https://c1.staticflickr.com/6/5673/30925169246_bcb5ac8949_o.jpg,0,0.248826291,1,1,443,520,https://www.flickr.com/photos/eltb/30925169246,https://creativecommons.org/licenses/by/2.0/,Catedrales e Iglesias/Cathedrals and Churches,https://www.flickr.com/people/eltb/
8c975de17f3247d1,https://c1.staticflickr.com/1/712/32281377125_d669c5337a_o.jpg,0.28125,0,0.84375,0.75,650,526,https://www.flickr.com/photos/stonehenge-stone-circle/32281377125/,https://creativecommons.org/licenses/by/2.0/,Stonehenge Stone Circle,https://www.flickr.com/people/stonehenge-stone-circle/
8d86fae18afef4e0,https://c1.staticflickr.com/6/5834/29905668306_e17a9b35ed_o.jpg,0.238170347,0,1,1,38,79,https://www.flickr.com/photos/2ndpeter/29905668306,https://creativecommons.org/licenses/by/2.0/,Peter Paplanus,https://www.flickr.com/people/2ndpeter/
619a9d0eb2acdd82,https://c1.staticflickr.com/9/8079/28742831150_8cd69d4202_o.jpg,0,0,0.666666667,1,885,843,https://www.flickr.com/photos/zigazou76/28742831150/,https://creativecommons.org/licenses/by/2.0/,Fr\303\251d\303\251ric BISSON,https://www.flickr.com/people/zigazou76/
9ab953cce5c7f879,https://c1.staticflickr.com/3/2872/33227757875_2a76bc808e_o.jpg,0.333333333,0,1,1,443,367,https://www.flickr.com/photos/dany13/33227757875/,https://creativecommons.org/licenses/by/2.0/,dany13,https://www.flickr.com/people/dany13/
1c2e9fe8b0b2fdf2,https://c1.staticflickr.com/8/7633/27140101841_c1f8aa3b4d_o.jpg,0,0,0.666666667,1,58,905,https://www.flickr.com/photos/gregthebusker/27140101841,https://creativecommons.org/licenses/by/2.0/,Greg Schechter,https://www.flickr.com/people/gregthebusker/
a414ccf5c51454e0,https://c1.staticflickr.com/8/7609/27446813796_e349a63c2f_o.jpg,0,0,0.665684831,1,830,866,https://www.flickr.com/photos/fotosagenciabrasil/27446813796,https://creativecommons.org/licenses/by/2.0/,Ag\303\252ncia Brasil Fotografias,https://www.flickr.com/people/fotosagenciabrasil/
26aa2e6ee43387e7,https://c1.staticflickr.com/1/378/31616355823_06b59a862a_o.jpg,0.25,0,1,0.75,913,741,https://www.flickr.com/photos/12463666@N03/31616355823/,https://creativecommons.org/licenses/by/2.0/,Bob M ~,https://www.flickr.com/people/12463666@N03/
3302a8c24caf20f4,https://c1.staticflickr.com/8/7553/27852122740_a93432645b_o.jpg,0,0,0.666666667,1,704,548,https://flickr.com/53301297@N00/27852122740,https://creativecommons.org/licenses/by/2.0/,Paul Sableman,https://www.flickr.com/people/pasa/
dd722682a9f2b9dd,https://c1.staticflickr.com/6/5773/29781416180_6cd73114d5_o.jpg,0,0,0.5,0.75,437,458,https://www.flickr.com/photos/greggjerdingen/29781416180,https://creativecommons.org/licenses/by/2.0/,Greg Gjerdingen,https://www.flickr.com/people/greggjerdingen/
6afe58efa85756dc,https://c1.staticflickr.com/8/7406/27477875915_19bb21bd54_o.jpg,0,0.333333333,1,1,929,849,https://www.flickr.com/photos/insatiablemunchies/27477875915,https://creativecommons.org/licenses/by/2.0/,insatiablemunch,https://www.flickr.com/people/insatiablemunchies/
0ceee9a38409e30c,https://c1.staticflickr.com/1/412/31684872936_8e1df2a992_o.jpg,0.4375,0,1,0.75,484,712,https://www.flickr.com/photos/16801915@N06/31684872936/,https://creativecommons.org/licenses/by/2.0/,Reading Tom,https://www.flickr.com/people/16801915@N06/
1df5e1adad21d618,https://c1.staticflickr.com/1/532/32376482310_86efb9eec4_o.jpg,0.25,0,0.75,0.75,405,556,https://www.flickr.com/photos/thejointstaff/32376482310,https://creativecommons.org/licenses/by/2.0/,Chairman of the Joint Chiefs of Staff,https://www.flickr.com/people/thejointstaff/
57e62606f02d0251,https://c1.staticflickr.com/8/7307/27798850402_87d7558850_o.jpg,0.496696035,0,0.99339207,0.75,548,646,https://www.flickr.com/photos/shankaronline/27798850402,https://creativecommons.org/licenses/by/2.0/,shankar s.,https://www.flickr.com/people/shankaronline/
d0fe8afb55c3c7cd,https://c1.staticflickr.com/9/8107/28396972686_381dae0505_o.jpg,0,0,1,0.75,498,778,https://www.flickr.com/photos/duncanh1/28396972686,https://creativecommons.org/licenses/by/2.0/,Dun.can,https://www.flickr.com/people/duncanh1/
91d18b353d5b3be2,https://c1.staticflickr.com/4/3935/33250842731_598bbc7d1e_o.jpg,0,0,0.75,0.75,931,26,https://www.flickr.com/photos/dylan20/33250842731,https://creativecommons.org/licenses/by/2.0/,Dylan Tweney,https://www.flickr.com/people/dylan20/
21b0803c965f76ef,https://c1.staticflickr.com/6/5667/31229598566_3fca43f16f_o.jpg,0,0.25,0.403311258,1,920,977,https://www.flickr.com/photos/crackdog/31229598566,https://creativecommons.org/licenses/by/2.0/,William Creswell,https://www.flickr.com/people/crackdog/
f20783fc38473514,https://c1.staticflickr.com/9/8550/28448778474_c095f2264b_o.jpg,0.248713235,0.25,0.746139706,1,386,774,https://www.flickr.com/photos/shankaronline/28448778474,https://creativecommons.org/licenses/by/2.0/,shankar s.,https://www.flickr.com/people/shankaronline/
3d6e530955c60759,https://c1.staticflickr.com/8/7293/26333233883_fb2b616f95_o.jpg,0,0,0.577654517,0.75,512,892,https://www.flickr.com/photos/hugo90/26333233883,https://creativecommons.org/licenses/by/2.0/,JOHN LLOYD,https://www.flickr.com/people/hugo90/
7e5c847bafc4d50c,https://c1.staticflickr.com/6/5557/30353091180_fe0a06de72_o.jpg,0.551833123,0.25,0.919721871,1,909,529,https://www.flickr.com/photos/flyingsinger/30353091180,https://creativecommons.org/licenses/by/2.0/,Bruce Irving,https://www.flickr.com/people/flyingsinger/
0aebe24fc257286e,https://c1.staticflickr.com/8/7343/27235728323_4d87753e80_o.jpg,0,0.25,0.535877863,1,561,315,https://www.flickr.com/photos/143049688@N08/27235728323,https://creativecommons.org/licenses/by/2.0/,MR MAO PICS,https://www.flickr.com/people/143049688@N08/
3c970c84b598f2d9,https://c1.staticflickr.com/6/5693/25380221549_fd25f3d570_o.jpg,0.223849372,0,0.671548117,0.75,780,597,https://www.flickr.com/photos/thoseguys119/25380221549,https://creativecommons.org/licenses/by/2.0/,ThoseGuys119,https://www.flickr.com/people/thoseguys119/
c6166621198a3de4,https://c1.staticflickr.com/6/5563/31119538711_0c79469ee9_o.jpg,0,0.161983471,1,1,986,747,https://www.flickr.com/photos/mauroguanandi/31119538711/,https://creativecommons.org/licenses/by/2.0/,mauroguanandi,https://www.flickr.com/people/mauroguanandi/
134bfd93a04b88b2,https://c1.staticflickr.com/8/7284/28111216916_c5cd478e8a_o.jpg,0.333333333,0,1,1,581,962,https://www.flickr.com/photos/yourmildura/28111216916,https://creativecommons.org/licenses/by/2.0/,Your Mildura,https://www.flickr.com/people/yourmildura/
4227a6e105cc0588,https://c1.staticflickr.com/6/5659/30998499956_ec5656fd7f_o.jpg,0.464993395,0,1,1,971,141,https://www.flickr.com/photos/apardavila/30998499956,https://creativecommons.org/licenses/by/2.0/,Arturo Pardavila III,https://www.flickr.com/people/apardavila/
405dd60729a8c18d,https://c1.staticflickr.com/6/5604/31248667090_381a827f4b_o.jpg,0,0,0.5625,0.75,848,496,http://www.flickr.com/photos/mohit_s/31248667090/,https://creativecommons.org/licenses/by/2.0/,Mohit S,https://www.flickr.com/people/mohit_s/
0d29832e5da60f5f,https://c1.staticflickr.com/9/8160/29190648723_bcf0356317_o.jpg,0.25,0,1,1,973,181,https://www.flickr.com/photos/jsjgeology/29190648723,https://creativecommons.org/licenses/by/2.0/,James St. John,https://www.flickr.com/people/jsjgeology/
90ab38bb74020d5a,https://c1.staticflickr.com/9/8072/28451660015_5953f09d2a_o.jpg,0.5,0,1,0.75,647,141,https://www.flickr.com/photos/tipsfortravellers/28451660015,https://creativecommons.org/licenses/by/2.0/,Gary Bembridge,https://www.flickr.com/people/tipsfortravellers/
068c5d66662a837a,https://c1.staticflickr.com/8/7330/26495171353_a3fff0f136_o.jpg,0,0.25,0.573459716,1,964,773,https://www.flickr.com/photos/lafoodie/26495171353,https://creativecommons.org/licenses/by/2.0/,L.A. Foodie,https://www.flickr.com/people/lafoodie/
e5f15610a22098bb,https://c1.staticflickr.com/9/8407/29490211104_10c2f48229_o.jpg,0.303658537,0.25,0.91097561,1,672,575,https://www.flickr.com/photos/ophilos/29490211104,https://creativecommons.org/licenses/by/2.0/,Christos Loufopoulos,https://www.flickr.com/people/ophilos/
4cd90a6459ce9571,https://c1.staticflickr.com/8/7513/29088533881_89782643f3_o.jpg,0.234308131,0,0.702924394,0.75,719,622,https://www.flickr.com/photos/tdlucas5000/29088533881,https://creativecommons.org/licenses/by/2.0/,tdlucas5000,https://www.flickr.com/people/tdlucas5000/
4a0bac33f8e81e60,https://c1.staticflickr.com/9/8551/29475088050_cbbd9ea8a2_o.jpg,0,0,0.669128508,1,407,857,https://www.flickr.com/photos/eltb/29475088050,https://creativecommons.org/licenses/by/2.0/,Catedrales e Iglesias/Cathedrals and Churches,https://www.flickr.com/people/eltb/
cc283b8f7f46fbf0,https://c1.staticflickr.com/9/8026/29591945975_73a66c762b_o.jpg,0.4375,0,1,0.75,574,962,https://www.flickr.com/photos/mauroguanandi/29591945975,https://creativecommons.org/licenses/by/2.0/,mauroguanandi,https://www.flickr.com/people/mauroguanandi/
70b9b8ae11327472,https://c1.staticflickr.com/9/8138/30013050040_04d3fdd00b_o.jpg,0,0,1,1,11,983,https://www.flickr.com/photos/46183897@N00/30013050040,https://creativecommons.org/licenses/by/2.0/,Robert Nunnally,https://www.flickr.com/people/46183897@N00/
5dd8e133e66ecd3a,https://c1.staticflickr.com/1/477/32384785852_132146bba9_o.jpg,0,0,0.643394649,0.75,142,346,https://flickr.com/11076453@N00/32384785852,https://creativecommons.org/licenses/by/2.0/,Steve Childs,https://www.flickr.com/people/steve_childs/
4dc360d125c9238c,https://c1.staticflickr.com/8/7516/26892006331_d8fff23f32_o.jpg,0.25,0,0.75,0.75,527,840,https://www.flickr.com/photos/johovac/26892006331,https://creativecommons.org/licenses/by/2.0/,Ed S. Johovac,https://www.flickr.com/people/johovac/
8805b0b20d808c49,https://c1.staticflickr.com/8/7728/27175361700_dd1959dd51_o.jpg,0.5,0.25,1,1,704,927,https://www.flickr.com/photos/faceme/27175361700,https://creativecommons.org/licenses/by/2.0/,FaceMePLS,https://www.flickr.com/people/faceme/
15d27dbdc9eeda7f,https://c1.staticflickr.com/1/704/32389054391_5ac6fee7e7_o.jpg,0,0,0.671597633,1,469,765,https://www.flickr.com/photos/54144402@N03/32389054391,https://creativecommons.org/licenses/by/2.0/,Bob Dass,https://www.flickr.com/people/54144402@N03/
448a738f6dcba07e,https://c1.staticflickr.com/8/7755/28840807203_405a538ce8_o.jpg,0,0.25,0.5,1,563,416,https://www.flickr.com/photos/harshlight/28840807203/,https://creativecommons.org/licenses/by/2.0/,HarshLight,https://www.flickr.com/people/harshlight/
e5948d6294eb8ca3,https://c1.staticflickr.com/6/5480/31214754031_7eae5eeede_o.jpg,0,0,0.5625,0.75,887,676,https://www.flickr.com/photos/davidstanleytravel/31214754031,https://creativecommons.org/licenses/by/2.0/,David Stanley,https://www.flickr.com/people/davidstanleytravel/
================================================
FILE: dataset/download_images.py
================================================
"""Script which downloads dataset images.
Usage:
python download_images.py --input_file=INPUT_FILE --output_dir=IMAGES_DIR
where:
INPUT_FILE is input csv file with dataset description, i.e. dev_dataset.csv
IMAGES_DIR is output directory where all images should be downloaded
Example:
# create directory for images
mkdir images
# download images declared in dev_dataset.csv
python download_images.py --input_file=dev_dataset.csv --output_dir=images
Dependencies:
Python 2.7 or higher.
Pillow library: https://python-pillow.org/
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import argparse
import csv
import os
import sys
from PIL import Image
from io import BytesIO
try:
from urllib.request import urlopen
except ImportError:
from urllib2 import urlopen
def parse_args():
"""Parses command line arguments."""
parser = argparse.ArgumentParser(
description='Tool to download dataset images.')
parser.add_argument('--input_file', required=True,
help='Location of dataset.csv')
parser.add_argument('--output_dir', required=True,
help='Output path to download images')
args = parser.parse_args()
return args.input_file, args.output_dir
def download_image(image_id, url, x1, y1, x2, y2, output_dir):
"""Downloads one image, crops it, resizes it and saves it locally."""
output_filename = os.path.join(output_dir, image_id + '.png')
if os.path.exists(output_filename):
# Don't download image if it's already there
return True
try:
# Download image
url_file = urlopen(url)
if url_file.getcode() != 200:
return False
image_buffer = url_file.read()
# Crop, resize and save image
image = Image.open(BytesIO(image_buffer)).convert('RGB')
w = image.size[0]
h = image.size[1]
image = image.crop((int(x1*w), int(y1*h), int(x2*w), int(y2*h)))
image = image.resize((299, 299), resample=Image.ANTIALIAS)
image.save(output_filename)
except IOError:
return False
return True
def main():
input_filename, output_dir = parse_args()
failed_to_download = set()
with open(input_filename) as input_file:
reader = csv.reader(input_file)
header_row = next(reader)
try:
row_idx_image_id = header_row.index('ImageId')
row_idx_url = header_row.index('URL')
row_idx_x1 = header_row.index('x1')
row_idx_y1 = header_row.index('y1')
row_idx_x2 = header_row.index('x2')
row_idx_y2 = header_row.index('y2')
except ValueError as e:
print('One of the columns was not found in the source file: ', e.message)
for idx, row in enumerate(reader):
if len(row) < len(header_row):
# skip partial or empty lines
continue
if not download_image(image_id=row[row_idx_image_id],
url=row[row_idx_url],
x1=float(row[row_idx_x1]),
y1=float(row[row_idx_y1]),
x2=float(row[row_idx_x2]),
y2=float(row[row_idx_y2]),
output_dir=output_dir):
failed_to_download.add(row[row_idx_image_id])
sys.stdout.write('\rDownloaded {0} images'.format(idx + 1))
sys.stdout.flush()
print()
if failed_to_download:
print('\nUnable to download images with the following IDs:')
for image_id in failed_to_download:
print(image_id)
if __name__ == '__main__':
main()
================================================
FILE: metadata.json
================================================
{
"type": "attack",
"container": "tensorflow/tensorflow:1.6.0",
"container_gpu": "tensorflow/tensorflow:1.6.0-gpu",
"entry_point": "run_attack.sh"
}
================================================
FILE: nets/__init__.py
================================================
================================================
FILE: nets/alexnet.py
================================================
# Copyright 2016 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Contains a model definition for AlexNet.
This work was first described in:
ImageNet Classification with Deep Convolutional Neural Networks
Alex Krizhevsky, Ilya Sutskever and Geoffrey E. Hinton
and later refined in:
One weird trick for parallelizing convolutional neural networks
Alex Krizhevsky, 2014
Here we provide the implementation proposed in "One weird trick" and not
"ImageNet Classification", as per the paper, the LRN layers have been removed.
Usage:
with slim.arg_scope(alexnet.alexnet_v2_arg_scope()):
outputs, end_points = alexnet.alexnet_v2(inputs)
@@alexnet_v2
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import tensorflow as tf
slim = tf.contrib.slim
trunc_normal = lambda stddev: tf.truncated_normal_initializer(0.0, stddev)
def alexnet_v2_arg_scope(weight_decay=0.0005):
with slim.arg_scope([slim.conv2d, slim.fully_connected],
activation_fn=tf.nn.relu,
biases_initializer=tf.constant_initializer(0.1),
weights_regularizer=slim.l2_regularizer(weight_decay)):
with slim.arg_scope([slim.conv2d], padding='SAME'):
with slim.arg_scope([slim.max_pool2d], padding='VALID') as arg_sc:
return arg_sc
def alexnet_v2(inputs,
num_classes=1000,
is_training=True,
dropout_keep_prob=0.5,
spatial_squeeze=True,
scope='alexnet_v2'):
"""AlexNet version 2.
Described in: http://arxiv.org/pdf/1404.5997v2.pdf
Parameters from:
github.com/akrizhevsky/cuda-convnet2/blob/master/layers/
layers-imagenet-1gpu.cfg
Note: All the fully_connected layers have been transformed to conv2d layers.
To use in classification mode, resize input to 224x224. To use in fully
convolutional mode, set spatial_squeeze to false.
The LRN layers have been removed and change the initializers from
random_normal_initializer to xavier_initializer.
Args:
inputs: a tensor of size [batch_size, height, width, channels].
num_classes: number of predicted classes.
is_training: whether or not the model is being trained.
dropout_keep_prob: the probability that activations are kept in the dropout
layers during training.
spatial_squeeze: whether or not should squeeze the spatial dimensions of the
outputs. Useful to remove unnecessary dimensions for classification.
scope: Optional scope for the variables.
Returns:
the last op containing the log predictions and end_points dict.
"""
with tf.variable_scope(scope, 'alexnet_v2', [inputs]) as sc:
end_points_collection = sc.name + '_end_points'
# Collect outputs for conv2d, fully_connected and max_pool2d.
with slim.arg_scope([slim.conv2d, slim.fully_connected, slim.max_pool2d],
outputs_collections=[end_points_collection]):
net = slim.conv2d(inputs, 64, [11, 11], 4, padding='VALID',
scope='conv1')
net = slim.max_pool2d(net, [3, 3], 2, scope='pool1')
net = slim.conv2d(net, 192, [5, 5], scope='conv2')
net = slim.max_pool2d(net, [3, 3], 2, scope='pool2')
net = slim.conv2d(net, 384, [3, 3], scope='conv3')
net = slim.conv2d(net, 384, [3, 3], scope='conv4')
net = slim.conv2d(net, 256, [3, 3], scope='conv5')
net = slim.max_pool2d(net, [3, 3], 2, scope='pool5')
# Use conv2d instead of fully_connected layers.
with slim.arg_scope([slim.conv2d],
weights_initializer=trunc_normal(0.005),
biases_initializer=tf.constant_initializer(0.1)):
net = slim.conv2d(net, 4096, [5, 5], padding='VALID',
scope='fc6')
net = slim.dropout(net, dropout_keep_prob, is_training=is_training,
scope='dropout6')
net = slim.conv2d(net, 4096, [1, 1], scope='fc7')
net = slim.dropout(net, dropout_keep_prob, is_training=is_training,
scope='dropout7')
net = slim.conv2d(net, num_classes, [1, 1],
activation_fn=None,
normalizer_fn=None,
biases_initializer=tf.zeros_initializer(),
scope='fc8')
# Convert end_points_collection into a end_point dict.
end_points = slim.utils.convert_collection_to_dict(end_points_collection)
if spatial_squeeze:
net = tf.squeeze(net, [1, 2], name='fc8/squeezed')
end_points[sc.name + '/fc8'] = net
return net, end_points
alexnet_v2.default_image_size = 224
================================================
FILE: nets/alexnet_test.py
================================================
# Copyright 2016 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Tests for slim.nets.alexnet."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import tensorflow as tf
from nets import alexnet
slim = tf.contrib.slim
class AlexnetV2Test(tf.test.TestCase):
def testBuild(self):
batch_size = 5
height, width = 224, 224
num_classes = 1000
with self.test_session():
inputs = tf.random_uniform((batch_size, height, width, 3))
logits, _ = alexnet.alexnet_v2(inputs, num_classes)
self.assertEquals(logits.op.name, 'alexnet_v2/fc8/squeezed')
self.assertListEqual(logits.get_shape().as_list(),
[batch_size, num_classes])
def testFullyConvolutional(self):
batch_size = 1
height, width = 300, 400
num_classes = 1000
with self.test_session():
inputs = tf.random_uniform((batch_size, height, width, 3))
logits, _ = alexnet.alexnet_v2(inputs, num_classes, spatial_squeeze=False)
self.assertEquals(logits.op.name, 'alexnet_v2/fc8/BiasAdd')
self.assertListEqual(logits.get_shape().as_list(),
[batch_size, 4, 7, num_classes])
def testEndPoints(self):
batch_size = 5
height, width = 224, 224
num_classes = 1000
with self.test_session():
inputs = tf.random_uniform((batch_size, height, width, 3))
_, end_points = alexnet.alexnet_v2(inputs, num_classes)
expected_names = ['alexnet_v2/conv1',
'alexnet_v2/pool1',
'alexnet_v2/conv2',
'alexnet_v2/pool2',
'alexnet_v2/conv3',
'alexnet_v2/conv4',
'alexnet_v2/conv5',
'alexnet_v2/pool5',
'alexnet_v2/fc6',
'alexnet_v2/fc7',
'alexnet_v2/fc8'
]
self.assertSetEqual(set(end_points.keys()), set(expected_names))
def testModelVariables(self):
batch_size = 5
height, width = 224, 224
num_classes = 1000
with self.test_session():
inputs = tf.random_uniform((batch_size, height, width, 3))
alexnet.alexnet_v2(inputs, num_classes)
expected_names = ['alexnet_v2/conv1/weights',
'alexnet_v2/conv1/biases',
'alexnet_v2/conv2/weights',
'alexnet_v2/conv2/biases',
'alexnet_v2/conv3/weights',
'alexnet_v2/conv3/biases',
'alexnet_v2/conv4/weights',
'alexnet_v2/conv4/biases',
'alexnet_v2/conv5/weights',
'alexnet_v2/conv5/biases',
'alexnet_v2/fc6/weights',
'alexnet_v2/fc6/biases',
'alexnet_v2/fc7/weights',
'alexnet_v2/fc7/biases',
'alexnet_v2/fc8/weights',
'alexnet_v2/fc8/biases',
]
model_variables = [v.op.name for v in slim.get_model_variables()]
self.assertSetEqual(set(model_variables), set(expected_names))
def testEvaluation(self):
batch_size = 2
height, width = 224, 224
num_classes = 1000
with self.test_session():
eval_inputs = tf.random_uniform((batch_size, height, width, 3))
logits, _ = alexnet.alexnet_v2(eval_inputs, is_training=False)
self.assertListEqual(logits.get_shape().as_list(),
[batch_size, num_classes])
predictions = tf.argmax(logits, 1)
self.assertListEqual(predictions.get_shape().as_list(), [batch_size])
def testTrainEvalWithReuse(self):
train_batch_size = 2
eval_batch_size = 1
train_height, train_width = 224, 224
eval_height, eval_width = 300, 400
num_classes = 1000
with self.test_session():
train_inputs = tf.random_uniform(
(train_batch_size, train_height, train_width, 3))
logits, _ = alexnet.alexnet_v2(train_inputs)
self.assertListEqual(logits.get_shape().as_list(),
[train_batch_size, num_classes])
tf.get_variable_scope().reuse_variables()
eval_inputs = tf.random_uniform(
(eval_batch_size, eval_height, eval_width, 3))
logits, _ = alexnet.alexnet_v2(eval_inputs, is_training=False,
spatial_squeeze=False)
self.assertListEqual(logits.get_shape().as_list(),
[eval_batch_size, 4, 7, num_classes])
logits = tf.reduce_mean(logits, [1, 2])
predictions = tf.argmax(logits, 1)
self.assertEquals(predictions.get_shape().as_list(), [eval_batch_size])
def testForward(self):
batch_size = 1
height, width = 224, 224
with self.test_session() as sess:
inputs = tf.random_uniform((batch_size, height, width, 3))
logits, _ = alexnet.alexnet_v2(inputs)
sess.run(tf.global_variables_initializer())
output = sess.run(logits)
self.assertTrue(output.any())
if __name__ == '__main__':
tf.test.main()
================================================
FILE: nets/cifarnet.py
================================================
# Copyright 2016 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Contains a variant of the CIFAR-10 model definition."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import tensorflow as tf
slim = tf.contrib.slim
trunc_normal = lambda stddev: tf.truncated_normal_initializer(stddev=stddev)
def cifarnet(images, num_classes=10, is_training=False,
dropout_keep_prob=0.5,
prediction_fn=slim.softmax,
scope='CifarNet'):
"""Creates a variant of the CifarNet model.
Note that since the output is a set of 'logits', the values fall in the
interval of (-infinity, infinity). Consequently, to convert the outputs to a
probability distribution over the characters, one will need to convert them
using the softmax function:
logits = cifarnet.cifarnet(images, is_training=False)
probabilities = tf.nn.softmax(logits)
predictions = tf.argmax(logits, 1)
Args:
images: A batch of `Tensors` of size [batch_size, height, width, channels].
num_classes: the number of classes in the dataset.
is_training: specifies whether or not we're currently training the model.
This variable will determine the behaviour of the dropout layer.
dropout_keep_prob: the percentage of activation values that are retained.
prediction_fn: a function to get predictions out of logits.
scope: Optional variable_scope.
Returns:
logits: the pre-softmax activations, a tensor of size
[batch_size, `num_classes`]
end_points: a dictionary from components of the network to the corresponding
activation.
"""
end_points = {}
with tf.variable_scope(scope, 'CifarNet', [images, num_classes]):
net = slim.conv2d(images, 64, [5, 5], scope='conv1')
end_points['conv1'] = net
net = slim.max_pool2d(net, [2, 2], 2, scope='pool1')
end_points['pool1'] = net
net = tf.nn.lrn(net, 4, bias=1.0, alpha=0.001/9.0, beta=0.75, name='norm1')
net = slim.conv2d(net, 64, [5, 5], scope='conv2')
end_points['conv2'] = net
net = tf.nn.lrn(net, 4, bias=1.0, alpha=0.001/9.0, beta=0.75, name='norm2')
net = slim.max_pool2d(net, [2, 2], 2, scope='pool2')
end_points['pool2'] = net
net = slim.flatten(net)
end_points['Flatten'] = net
net = slim.fully_connected(net, 384, scope='fc3')
end_points['fc3'] = net
net = slim.dropout(net, dropout_keep_prob, is_training=is_training,
scope='dropout3')
net = slim.fully_connected(net, 192, scope='fc4')
end_points['fc4'] = net
logits = slim.fully_connected(net, num_classes,
biases_initializer=tf.zeros_initializer(),
weights_initializer=trunc_normal(1/192.0),
weights_regularizer=None,
activation_fn=None,
scope='logits')
end_points['Logits'] = logits
end_points['Predictions'] = prediction_fn(logits, scope='Predictions')
return logits, end_points
cifarnet.default_image_size = 32
def cifarnet_arg_scope(weight_decay=0.004):
"""Defines the default cifarnet argument scope.
Args:
weight_decay: The weight decay to use for regularizing the model.
Returns:
An `arg_scope` to use for the inception v3 model.
"""
with slim.arg_scope(
[slim.conv2d],
weights_initializer=tf.truncated_normal_initializer(stddev=5e-2),
activation_fn=tf.nn.relu):
with slim.arg_scope(
[slim.fully_connected],
biases_initializer=tf.constant_initializer(0.1),
weights_initializer=trunc_normal(0.04),
weights_regularizer=slim.l2_regularizer(weight_decay),
activation_fn=tf.nn.relu) as sc:
return sc
================================================
FILE: nets/inception.py
================================================
# Copyright 2016 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Brings all inception models under one namespace."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
# pylint: disable=unused-import
from nets.inception_resnet_v2 import inception_resnet_v2
from nets.inception_resnet_v2 import inception_resnet_v2_arg_scope
from nets.inception_resnet_v2 import inception_resnet_v2_base
from nets.inception_v1 import inception_v1
from nets.inception_v1 import inception_v1_arg_scope
from nets.inception_v1 import inception_v1_base
from nets.inception_v2 import inception_v2
from nets.inception_v2 import inception_v2_arg_scope
from nets.inception_v2 import inception_v2_base
from nets.inception_v3 import inception_v3
from nets.inception_v3 import inception_v3_arg_scope
from nets.inception_v3 import inception_v3_base
from nets.inception_v4 import inception_v4
from nets.inception_v4 import inception_v4_arg_scope
from nets.inception_v4 import inception_v4_base
# pylint: enable=unused-import
================================================
FILE: nets/inception_resnet_v2.py
================================================
# Copyright 2016 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Contains the definition of the Inception Resnet V2 architecture.
As described in http://arxiv.org/abs/1602.07261.
Inception-v4, Inception-ResNet and the Impact of Residual Connections
on Learning
Christian Szegedy, Sergey Ioffe, Vincent Vanhoucke, Alex Alemi
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import tensorflow as tf
slim = tf.contrib.slim
def block35(net, scale=1.0, activation_fn=tf.nn.relu, scope=None, reuse=None):
"""Builds the 35x35 resnet block."""
with tf.variable_scope(scope, 'Block35', [net], reuse=reuse):
with tf.variable_scope('Branch_0'):
tower_conv = slim.conv2d(net, 32, 1, scope='Conv2d_1x1')
with tf.variable_scope('Branch_1'):
tower_conv1_0 = slim.conv2d(net, 32, 1, scope='Conv2d_0a_1x1')
tower_conv1_1 = slim.conv2d(tower_conv1_0, 32, 3, scope='Conv2d_0b_3x3')
with tf.variable_scope('Branch_2'):
tower_conv2_0 = slim.conv2d(net, 32, 1, scope='Conv2d_0a_1x1')
tower_conv2_1 = slim.conv2d(tower_conv2_0, 48, 3, scope='Conv2d_0b_3x3')
tower_conv2_2 = slim.conv2d(tower_conv2_1, 64, 3, scope='Conv2d_0c_3x3')
mixed = tf.concat(axis=3, values=[tower_conv, tower_conv1_1, tower_conv2_2])
up = slim.conv2d(mixed, net.get_shape()[3], 1, normalizer_fn=None,
activation_fn=None, scope='Conv2d_1x1')
net += scale * up
if activation_fn:
net = activation_fn(net)
return net
def block17(net, scale=1.0, activation_fn=tf.nn.relu, scope=None, reuse=None):
"""Builds the 17x17 resnet block."""
with tf.variable_scope(scope, 'Block17', [net], reuse=reuse):
with tf.variable_scope('Branch_0'):
tower_conv = slim.conv2d(net, 192, 1, scope='Conv2d_1x1')
with tf.variable_scope('Branch_1'):
tower_conv1_0 = slim.conv2d(net, 128, 1, scope='Conv2d_0a_1x1')
tower_conv1_1 = slim.conv2d(tower_conv1_0, 160, [1, 7],
scope='Conv2d_0b_1x7')
tower_conv1_2 = slim.conv2d(tower_conv1_1, 192, [7, 1],
scope='Conv2d_0c_7x1')
mixed = tf.concat(axis=3, values=[tower_conv, tower_conv1_2])
up = slim.conv2d(mixed, net.get_shape()[3], 1, normalizer_fn=None,
activation_fn=None, scope='Conv2d_1x1')
net += scale * up
if activation_fn:
net = activation_fn(net)
return net
def block8(net, scale=1.0, activation_fn=tf.nn.relu, scope=None, reuse=None):
"""Builds the 8x8 resnet block."""
with tf.variable_scope(scope, 'Block8', [net], reuse=reuse):
with tf.variable_scope('Branch_0'):
tower_conv = slim.conv2d(net, 192, 1, scope='Conv2d_1x1')
with tf.variable_scope('Branch_1'):
tower_conv1_0 = slim.conv2d(net, 192, 1, scope='Conv2d_0a_1x1')
tower_conv1_1 = slim.conv2d(tower_conv1_0, 224, [1, 3],
scope='Conv2d_0b_1x3')
tower_conv1_2 = slim.conv2d(tower_conv1_1, 256, [3, 1],
scope='Conv2d_0c_3x1')
mixed = tf.concat(axis=3, values=[tower_conv, tower_conv1_2])
up = slim.conv2d(mixed, net.get_shape()[3], 1, normalizer_fn=None,
activation_fn=None, scope='Conv2d_1x1')
net += scale * up
if activation_fn:
net = activation_fn(net)
return net
def inception_resnet_v2_base(inputs,
final_endpoint='Conv2d_7b_1x1',
output_stride=16,
align_feature_maps=False,
scope=None):
"""Inception model from http://arxiv.org/abs/1602.07261.
Constructs an Inception Resnet v2 network from inputs to the given final
endpoint. This method can construct the network up to the final inception
block Conv2d_7b_1x1.
Args:
inputs: a tensor of size [batch_size, height, width, channels].
final_endpoint: specifies the endpoint to construct the network up to. It
can be one of ['Conv2d_1a_3x3', 'Conv2d_2a_3x3', 'Conv2d_2b_3x3',
'MaxPool_3a_3x3', 'Conv2d_3b_1x1', 'Conv2d_4a_3x3', 'MaxPool_5a_3x3',
'Mixed_5b', 'Mixed_6a', 'PreAuxLogits', 'Mixed_7a', 'Conv2d_7b_1x1']
output_stride: A scalar that specifies the requested ratio of input to
output spatial resolution. Only supports 8 and 16.
align_feature_maps: When true, changes all the VALID paddings in the network
to SAME padding so that the feature maps are aligned.
scope: Optional variable_scope.
Returns:
tensor_out: output tensor corresponding to the final_endpoint.
end_points: a set of activations for external use, for example summaries or
losses.
Raises:
ValueError: if final_endpoint is not set to one of the predefined values,
or if the output_stride is not 8 or 16, or if the output_stride is 8 and
we request an end point after 'PreAuxLogits'.
"""
if output_stride != 8 and output_stride != 16:
raise ValueError('output_stride must be 8 or 16.')
padding = 'SAME' if align_feature_maps else 'VALID'
end_points = {}
def add_and_check_final(name, net):
end_points[name] = net
return name == final_endpoint
with tf.variable_scope(scope, 'InceptionResnetV2', [inputs]):
with slim.arg_scope([slim.conv2d, slim.max_pool2d, slim.avg_pool2d],
stride=1, padding='SAME'):
# 149 x 149 x 32
net = slim.conv2d(inputs, 32, 3, stride=2, padding=padding,
scope='Conv2d_1a_3x3')
if add_and_check_final('Conv2d_1a_3x3', net): return net, end_points
# 147 x 147 x 32
net = slim.conv2d(net, 32, 3, padding=padding,
scope='Conv2d_2a_3x3')
if add_and_check_final('Conv2d_2a_3x3', net): return net, end_points
# 147 x 147 x 64
net = slim.conv2d(net, 64, 3, scope='Conv2d_2b_3x3')
if add_and_check_final('Conv2d_2b_3x3', net): return net, end_points
# 73 x 73 x 64
net = slim.max_pool2d(net, 3, stride=2, padding=padding,
scope='MaxPool_3a_3x3')
if add_and_check_final('MaxPool_3a_3x3', net): return net, end_points
# 73 x 73 x 80
net = slim.conv2d(net, 80, 1, padding=padding,
scope='Conv2d_3b_1x1')
if add_and_check_final('Conv2d_3b_1x1', net): return net, end_points
# 71 x 71 x 192
net = slim.conv2d(net, 192, 3, padding=padding,
scope='Conv2d_4a_3x3')
if add_and_check_final('Conv2d_4a_3x3', net): return net, end_points
# 35 x 35 x 192
net = slim.max_pool2d(net, 3, stride=2, padding=padding,
scope='MaxPool_5a_3x3')
if add_and_check_final('MaxPool_5a_3x3', net): return net, end_points
# 35 x 35 x 320
with tf.variable_scope('Mixed_5b'):
with tf.variable_scope('Branch_0'):
tower_conv = slim.conv2d(net, 96, 1, scope='Conv2d_1x1')
with tf.variable_scope('Branch_1'):
tower_conv1_0 = slim.conv2d(net, 48, 1, scope='Conv2d_0a_1x1')
tower_conv1_1 = slim.conv2d(tower_conv1_0, 64, 5,
scope='Conv2d_0b_5x5')
with tf.variable_scope('Branch_2'):
tower_conv2_0 = slim.conv2d(net, 64, 1, scope='Conv2d_0a_1x1')
tower_conv2_1 = slim.conv2d(tower_conv2_0, 96, 3,
scope='Conv2d_0b_3x3')
tower_conv2_2 = slim.conv2d(tower_conv2_1, 96, 3,
scope='Conv2d_0c_3x3')
with tf.variable_scope('Branch_3'):
tower_pool = slim.avg_pool2d(net, 3, stride=1, padding='SAME',
scope='AvgPool_0a_3x3')
tower_pool_1 = slim.conv2d(tower_pool, 64, 1,
scope='Conv2d_0b_1x1')
net = tf.concat(
[tower_conv, tower_conv1_1, tower_conv2_2, tower_pool_1], 3)
if add_and_check_final('Mixed_5b', net): return net, end_points
# TODO(alemi): Register intermediate endpoints
net = slim.repeat(net, 10, block35, scale=0.17)
# 17 x 17 x 1088 if output_stride == 8,
# 33 x 33 x 1088 if output_stride == 16
use_atrous = output_stride == 8
with tf.variable_scope('Mixed_6a'):
with tf.variable_scope('Branch_0'):
tower_conv = slim.conv2d(net, 384, 3, stride=1 if use_atrous else 2,
padding=padding,
scope='Conv2d_1a_3x3')
with tf.variable_scope('Branch_1'):
tower_conv1_0 = slim.conv2d(net, 256, 1, scope='Conv2d_0a_1x1')
tower_conv1_1 = slim.conv2d(tower_conv1_0, 256, 3,
scope='Conv2d_0b_3x3')
tower_conv1_2 = slim.conv2d(tower_conv1_1, 384, 3,
stride=1 if use_atrous else 2,
padding=padding,
scope='Conv2d_1a_3x3')
with tf.variable_scope('Branch_2'):
tower_pool = slim.max_pool2d(net, 3, stride=1 if use_atrous else 2,
padding=padding,
scope='MaxPool_1a_3x3')
net = tf.concat([tower_conv, tower_conv1_2, tower_pool], 3)
if add_and_check_final('Mixed_6a', net): return net, end_points
# TODO(alemi): register intermediate endpoints
with slim.arg_scope([slim.conv2d], rate=2 if use_atrous else 1):
net = slim.repeat(net, 20, block17, scale=0.10)
if add_and_check_final('PreAuxLogits', net): return net, end_points
if output_stride == 8:
# TODO(gpapan): Properly support output_stride for the rest of the net.
raise ValueError('output_stride==8 is only supported up to the '
'PreAuxlogits end_point for now.')
# 8 x 8 x 2080
with tf.variable_scope('Mixed_7a'):
with tf.variable_scope('Branch_0'):
tower_conv = slim.conv2d(net, 256, 1, scope='Conv2d_0a_1x1')
tower_conv_1 = slim.conv2d(tower_conv, 384, 3, stride=2,
padding=padding,
scope='Conv2d_1a_3x3')
with tf.variable_scope('Branch_1'):
tower_conv1 = slim.conv2d(net, 256, 1, scope='Conv2d_0a_1x1')
tower_conv1_1 = slim.conv2d(tower_conv1, 288, 3, stride=2,
padding=padding,
scope='Conv2d_1a_3x3')
with tf.variable_scope('Branch_2'):
tower_conv2 = slim.conv2d(net, 256, 1, scope='Conv2d_0a_1x1')
tower_conv2_1 = slim.conv2d(tower_conv2, 288, 3,
scope='Conv2d_0b_3x3')
tower_conv2_2 = slim.conv2d(tower_conv2_1, 320, 3, stride=2,
padding=padding,
scope='Conv2d_1a_3x3')
with tf.variable_scope('Branch_3'):
tower_pool = slim.max_pool2d(net, 3, stride=2,
padding=padding,
scope='MaxPool_1a_3x3')
net = tf.concat(
[tower_conv_1, tower_conv1_1, tower_conv2_2, tower_pool], 3)
if add_and_check_final('Mixed_7a', net): return net, end_points
# TODO(alemi): register intermediate endpoints
net = slim.repeat(net, 9, block8, scale=0.20)
net = block8(net, activation_fn=None)
# 8 x 8 x 1536
net = slim.conv2d(net, 1536, 1, scope='Conv2d_7b_1x1')
if add_and_check_final('Conv2d_7b_1x1', net): return net, end_points
raise ValueError('final_endpoint (%s) not recognized', final_endpoint)
def inception_resnet_v2(inputs, num_classes=1001, is_training=True,
dropout_keep_prob=0.8,
reuse=None,
scope='InceptionResnetV2',
create_aux_logits=True):
"""Creates the Inception Resnet V2 model.
Args:
inputs: a 4-D tensor of size [batch_size, height, width, 3].
num_classes: number of predicted classes.
is_training: whether is training or not.
dropout_keep_prob: float, the fraction to keep before final layer.
reuse: whether or not the network and its variables should be reused. To be
able to reuse 'scope' must be given.
scope: Optional variable_scope.
create_aux_logits: Whether to include the auxilliary logits.
Returns:
logits: the logits outputs of the model.
end_points: the set of end_points from the inception model.
"""
end_points = {}
with tf.variable_scope(scope, 'InceptionResnetV2', [inputs, num_classes],
reuse=reuse) as scope:
with slim.arg_scope([slim.batch_norm, slim.dropout],
is_training=is_training):
net, end_points = inception_resnet_v2_base(inputs, scope=scope)
if create_aux_logits:
with tf.variable_scope('AuxLogits'):
aux = end_points['PreAuxLogits']
aux = slim.avg_pool2d(aux, 5, stride=3, padding='VALID',
scope='Conv2d_1a_3x3')
aux = slim.conv2d(aux, 128, 1, scope='Conv2d_1b_1x1')
aux = slim.conv2d(aux, 768, [5, 5],
padding='VALID', scope='Conv2d_2a_5x5')
aux = tf.reshape(aux, [aux.get_shape()[0], aux.get_shape()[-1]])
aux = slim.fully_connected(aux, num_classes, activation_fn=None,
scope='Logits')
end_points['AuxLogits'] = aux
with tf.variable_scope('Logits'):
net = slim.avg_pool2d(net, [8, 8], padding='VALID',
scope='AvgPool_1a_8x8')
net = tf.reshape(net, [net.get_shape()[0], net.get_shape()[-1]])
net = slim.dropout(net, dropout_keep_prob, is_training=is_training,
scope='Dropout')
end_points['PreLogitsFlatten'] = net
logits = slim.fully_connected(net, num_classes, activation_fn=None,
scope='Logits')
end_points['Logits'] = logits
end_points['Predictions'] = tf.nn.softmax(logits, name='Predictions')
return logits, end_points
inception_resnet_v2.default_image_size = 299
def inception_resnet_v2_arg_scope(weight_decay=0.00004,
batch_norm_decay=0.9997,
batch_norm_epsilon=0.001):
"""Returns the scope with the default parameters for inception_resnet_v2.
Args:
weight_decay: the weight decay for weights variables.
batch_norm_decay: decay for the moving average of batch_norm momentums.
batch_norm_epsilon: small float added to variance to avoid dividing by zero.
Returns:
a arg_scope with the parameters needed for inception_resnet_v2.
"""
# Set weight_decay for weights in conv2d and fully_connected layers.
with slim.arg_scope([slim.conv2d, slim.fully_connected],
weights_regularizer=slim.l2_regularizer(weight_decay),
biases_regularizer=slim.l2_regularizer(weight_decay)):
batch_norm_params = {
'decay': batch_norm_decay,
'epsilon': batch_norm_epsilon,
}
# Set activation_fn and parameters for batch_norm.
with slim.arg_scope([slim.conv2d], activation_fn=tf.nn.relu,
normalizer_fn=slim.batch_norm,
normalizer_params=batch_norm_params) as scope:
return scope
================================================
FILE: nets/inception_resnet_v2_test.py
================================================
# Copyright 2016 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Tests for slim.inception_resnet_v2."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import tensorflow as tf
from nets import inception
class InceptionTest(tf.test.TestCase):
def testBuildLogits(self):
batch_size = 5
height, width = 299, 299
num_classes = 1000
with self.test_session():
inputs = tf.random_uniform((batch_size, height, width, 3))
logits, endpoints = inception.inception_resnet_v2(inputs, num_classes)
self.assertTrue('AuxLogits' in endpoints)
auxlogits = endpoints['AuxLogits']
self.assertTrue(
auxlogits.op.name.startswith('InceptionResnetV2/AuxLogits'))
self.assertListEqual(auxlogits.get_shape().as_list(),
[batch_size, num_classes])
self.assertTrue(logits.op.name.startswith('InceptionResnetV2/Logits'))
self.assertListEqual(logits.get_shape().as_list(),
[batch_size, num_classes])
def testBuildWithoutAuxLogits(self):
batch_size = 5
height, width = 299, 299
num_classes = 1000
with self.test_session():
inputs = tf.random_uniform((batch_size, height, width, 3))
logits, endpoints = inception.inception_resnet_v2(inputs, num_classes,
create_aux_logits=False)
self.assertTrue('AuxLogits' not in endpoints)
self.assertTrue(logits.op.name.startswith('InceptionResnetV2/Logits'))
self.assertListEqual(logits.get_shape().as_list(),
[batch_size, num_classes])
def testBuildEndPoints(self):
batch_size = 5
height, width = 299, 299
num_classes = 1000
with self.test_session():
inputs = tf.random_uniform((batch_size, height, width, 3))
_, end_points = inception.inception_resnet_v2(inputs, num_classes)
self.assertTrue('Logits' in end_points)
logits = end_points['Logits']
self.assertListEqual(logits.get_shape().as_list(),
[batch_size, num_classes])
self.assertTrue('AuxLogits' in end_points)
aux_logits = end_points['AuxLogits']
self.assertListEqual(aux_logits.get_shape().as_list(),
[batch_size, num_classes])
pre_pool = end_points['Conv2d_7b_1x1']
self.assertListEqual(pre_pool.get_shape().as_list(),
[batch_size, 8, 8, 1536])
def testBuildBaseNetwork(self):
batch_size = 5
height, width = 299, 299
inputs = tf.random_uniform((batch_size, height, width, 3))
net, end_points = inception.inception_resnet_v2_base(inputs)
self.assertTrue(net.op.name.startswith('InceptionResnetV2/Conv2d_7b_1x1'))
self.assertListEqual(net.get_shape().as_list(),
[batch_size, 8, 8, 1536])
expected_endpoints = ['Conv2d_1a_3x3', 'Conv2d_2a_3x3', 'Conv2d_2b_3x3',
'MaxPool_3a_3x3', 'Conv2d_3b_1x1', 'Conv2d_4a_3x3',
'MaxPool_5a_3x3', 'Mixed_5b', 'Mixed_6a',
'PreAuxLogits', 'Mixed_7a', 'Conv2d_7b_1x1']
self.assertItemsEqual(end_points.keys(), expected_endpoints)
def testBuildOnlyUptoFinalEndpoint(self):
batch_size = 5
height, width = 299, 299
endpoints = ['Conv2d_1a_3x3', 'Conv2d_2a_3x3', 'Conv2d_2b_3x3',
'MaxPool_3a_3x3', 'Conv2d_3b_1x1', 'Conv2d_4a_3x3',
'MaxPool_5a_3x3', 'Mixed_5b', 'Mixed_6a',
'PreAuxLogits', 'Mixed_7a', 'Conv2d_7b_1x1']
for index, endpoint in enumerate(endpoints):
with tf.Graph().as_default():
inputs = tf.random_uniform((batch_size, height, width, 3))
out_tensor, end_points = inception.inception_resnet_v2_base(
inputs, final_endpoint=endpoint)
if endpoint != 'PreAuxLogits':
self.assertTrue(out_tensor.op.name.startswith(
'InceptionResnetV2/' + endpoint))
self.assertItemsEqual(endpoints[:index+1], end_points)
def testBuildAndCheckAllEndPointsUptoPreAuxLogits(self):
batch_size = 5
height, width = 299, 299
inputs = tf.random_uniform((batch_size, height, width, 3))
_, end_points = inception.inception_resnet_v2_base(
inputs, final_endpoint='PreAuxLogits')
endpoints_shapes = {'Conv2d_1a_3x3': [5, 149, 149, 32],
'Conv2d_2a_3x3': [5, 147, 147, 32],
'Conv2d_2b_3x3': [5, 147, 147, 64],
'MaxPool_3a_3x3': [5, 73, 73, 64],
'Conv2d_3b_1x1': [5, 73, 73, 80],
'Conv2d_4a_3x3': [5, 71, 71, 192],
'MaxPool_5a_3x3': [5, 35, 35, 192],
'Mixed_5b': [5, 35, 35, 320],
'Mixed_6a': [5, 17, 17, 1088],
'PreAuxLogits': [5, 17, 17, 1088]
}
self.assertItemsEqual(endpoints_shapes.keys(), end_points.keys())
for endpoint_name in endpoints_shapes:
expected_shape = endpoints_shapes[endpoint_name]
self.assertTrue(endpoint_name in end_points)
self.assertListEqual(end_points[endpoint_name].get_shape().as_list(),
expected_shape)
def testBuildAndCheckAllEndPointsUptoPreAuxLogitsWithAlignedFeatureMaps(self):
batch_size = 5
height, width = 299, 299
inputs = tf.random_uniform((batch_size, height, width, 3))
_, end_points = inception.inception_resnet_v2_base(
inputs, final_endpoint='PreAuxLogits', align_feature_maps=True)
endpoints_shapes = {'Conv2d_1a_3x3': [5, 150, 150, 32],
'Conv2d_2a_3x3': [5, 150, 150, 32],
'Conv2d_2b_3x3': [5, 150, 150, 64],
'MaxPool_3a_3x3': [5, 75, 75, 64],
'Conv2d_3b_1x1': [5, 75, 75, 80],
'Conv2d_4a_3x3': [5, 75, 75, 192],
'MaxPool_5a_3x3': [5, 38, 38, 192],
'Mixed_5b': [5, 38, 38, 320],
'Mixed_6a': [5, 19, 19, 1088],
'PreAuxLogits': [5, 19, 19, 1088]
}
self.assertItemsEqual(endpoints_shapes.keys(), end_points.keys())
for endpoint_name in endpoints_shapes:
expected_shape = endpoints_shapes[endpoint_name]
self.assertTrue(endpoint_name in end_points)
self.assertListEqual(end_points[endpoint_name].get_shape().as_list(),
expected_shape)
def testBuildAndCheckAllEndPointsUptoPreAuxLogitsWithOutputStrideEight(self):
batch_size = 5
height, width = 299, 299
inputs = tf.random_uniform((batch_size, height, width, 3))
_, end_points = inception.inception_resnet_v2_base(
inputs, final_endpoint='PreAuxLogits', output_stride=8)
endpoints_shapes = {'Conv2d_1a_3x3': [5, 149, 149, 32],
'Conv2d_2a_3x3': [5, 147, 147, 32],
'Conv2d_2b_3x3': [5, 147, 147, 64],
'MaxPool_3a_3x3': [5, 73, 73, 64],
'Conv2d_3b_1x1': [5, 73, 73, 80],
'Conv2d_4a_3x3': [5, 71, 71, 192],
'MaxPool_5a_3x3': [5, 35, 35, 192],
'Mixed_5b': [5, 35, 35, 320],
'Mixed_6a': [5, 33, 33, 1088],
'PreAuxLogits': [5, 33, 33, 1088]
}
self.assertItemsEqual(endpoints_shapes.keys(), end_points.keys())
for endpoint_name in endpoints_shapes:
expected_shape = endpoints_shapes[endpoint_name]
self.assertTrue(endpoint_name in end_points)
self.assertListEqual(end_points[endpoint_name].get_shape().as_list(),
expected_shape)
def testVariablesSetDevice(self):
batch_size = 5
height, width = 299, 299
num_classes = 1000
with self.test_session():
inputs = tf.random_uniform((batch_size, height, width, 3))
# Force all Variables to reside on the device.
with tf.variable_scope('on_cpu'), tf.device('/cpu:0'):
inception.inception_resnet_v2(inputs, num_classes)
with tf.variable_scope('on_gpu'), tf.device('/gpu:0'):
inception.inception_resnet_v2(inputs, num_classes)
for v in tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope='on_cpu'):
self.assertDeviceEqual(v.device, '/cpu:0')
for v in tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope='on_gpu'):
self.assertDeviceEqual(v.device, '/gpu:0')
def testHalfSizeImages(self):
batch_size = 5
height, width = 150, 150
num_classes = 1000
with self.test_session():
inputs = tf.random_uniform((batch_size, height, width, 3))
logits, end_points = inception.inception_resnet_v2(inputs, num_classes)
self.assertTrue(logits.op.name.startswith('InceptionResnetV2/Logits'))
self.assertListEqual(logits.get_shape().as_list(),
[batch_size, num_classes])
pre_pool = end_points['Conv2d_7b_1x1']
self.assertListEqual(pre_pool.get_shape().as_list(),
[batch_size, 3, 3, 1536])
def testUnknownBatchSize(self):
batch_size = 1
height, width = 299, 299
num_classes = 1000
with self.test_session() as sess:
inputs = tf.placeholder(tf.float32, (None, height, width, 3))
logits, _ = inception.inception_resnet_v2(inputs, num_classes)
self.assertTrue(logits.op.name.startswith('InceptionResnetV2/Logits'))
self.assertListEqual(logits.get_shape().as_list(),
[None, num_classes])
images = tf.random_uniform((batch_size, height, width, 3))
sess.run(tf.global_variables_initializer())
output = sess.run(logits, {inputs: images.eval()})
self.assertEquals(output.shape, (batch_size, num_classes))
def testEvaluation(self):
batch_size = 2
height, width = 299, 299
num_classes = 1000
with self.test_session() as sess:
eval_inputs = tf.random_uniform((batch_size, height, width, 3))
logits, _ = inception.inception_resnet_v2(eval_inputs,
num_classes,
is_training=False)
predictions = tf.argmax(logits, 1)
sess.run(tf.global_variables_initializer())
output = sess.run(predictions)
self.assertEquals(output.shape, (batch_size,))
def testTrainEvalWithReuse(self):
train_batch_size = 5
eval_batch_size = 2
height, width = 150, 150
num_classes = 1000
with self.test_session() as sess:
train_inputs = tf.random_uniform((train_batch_size, height, width, 3))
inception.inception_resnet_v2(train_inputs, num_classes)
eval_inputs = tf.random_uniform((eval_batch_size, height, width, 3))
logits, _ = inception.inception_resnet_v2(eval_inputs,
num_classes,
is_training=False,
reuse=True)
predictions = tf.argmax(logits, 1)
sess.run(tf.global_variables_initializer())
output = sess.run(predictions)
self.assertEquals(output.shape, (eval_batch_size,))
if __name__ == '__main__':
tf.test.main()
================================================
FILE: nets/inception_utils.py
================================================
# Copyright 2016 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Contains common code shared by all inception models.
Usage of arg scope:
with slim.arg_scope(inception_arg_scope()):
logits, end_points = inception.inception_v3(images, num_classes,
is_training=is_training)
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import tensorflow as tf
slim = tf.contrib.slim
def inception_arg_scope(weight_decay=0.00004,
use_batch_norm=True,
batch_norm_decay=0.9997,
batch_norm_epsilon=0.001):
"""Defines the default arg scope for inception models.
Args:
weight_decay: The weight decay to use for regularizing the model.
use_batch_norm: "If `True`, batch_norm is applied after each convolution.
batch_norm_decay: Decay for batch norm moving average.
batch_norm_epsilon: Small float added to variance to avoid dividing by zero
in batch norm.
Returns:
An `arg_scope` to use for the inception models.
"""
batch_norm_params = {
# Decay for the moving averages.
'decay': batch_norm_decay,
# epsilon to prevent 0s in variance.
'epsilon': batch_norm_epsilon,
# collection containing update_ops.
'updates_collections': tf.GraphKeys.UPDATE_OPS,
}
if use_batch_norm:
normalizer_fn = slim.batch_norm
normalizer_params = batch_norm_params
else:
normalizer_fn = None
normalizer_params = {}
# Set weight_decay for weights in Conv and FC layers.
with slim.arg_scope([slim.conv2d, slim.fully_connected],
weights_regularizer=slim.l2_regularizer(weight_decay)):
with slim.arg_scope(
[slim.conv2d],
weights_initializer=slim.variance_scaling_initializer(),
activation_fn=tf.nn.relu,
normalizer_fn=normalizer_fn,
normalizer_params=normalizer_params) as sc:
return sc
================================================
FILE: nets/inception_v1.py
================================================
# Copyright 2016 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Contains the definition for inception v1 classification network."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import tensorflow as tf
from nets import inception_utils
slim = tf.contrib.slim
trunc_normal = lambda stddev: tf.truncated_normal_initializer(0.0, stddev)
def inception_v1_base(inputs,
final_endpoint='Mixed_5c',
scope='InceptionV1'):
"""Defines the Inception V1 base architecture.
This architecture is defined in:
Going deeper with convolutions
Christian Szegedy, Wei Liu, Yangqing Jia, Pierre Sermanet, Scott Reed,
Dragomir Anguelov, Dumitru Erhan, Vincent Vanhoucke, Andrew Rabinovich.
http://arxiv.org/pdf/1409.4842v1.pdf.
Args:
inputs: a tensor of size [batch_size, height, width, channels].
final_endpoint: specifies the endpoint to construct the network up to. It
can be one of ['Conv2d_1a_7x7', 'MaxPool_2a_3x3', 'Conv2d_2b_1x1',
'Conv2d_2c_3x3', 'MaxPool_3a_3x3', 'Mixed_3b', 'Mixed_3c',
'MaxPool_4a_3x3', 'Mixed_4b', 'Mixed_4c', 'Mixed_4d', 'Mixed_4e',
'Mixed_4f', 'MaxPool_5a_2x2', 'Mixed_5b', 'Mixed_5c']
scope: Optional variable_scope.
Returns:
A dictionary from components of the network to the corresponding activation.
Raises:
ValueError: if final_endpoint is not set to one of the predefined values.
"""
end_points = {}
with tf.variable_scope(scope, 'InceptionV1', [inputs]):
with slim.arg_scope(
[slim.conv2d, slim.fully_connected],
weights_initializer=trunc_normal(0.01)):
with slim.arg_scope([slim.conv2d, slim.max_pool2d],
stride=1, padding='SAME'):
end_point = 'Conv2d_1a_7x7'
net = slim.conv2d(inputs, 64, [7, 7], stride=2, scope=end_point)
end_points[end_point] = net
if final_endpoint == end_point: return net, end_points
end_point = 'MaxPool_2a_3x3'
net = slim.max_pool2d(net, [3, 3], stride=2, scope=end_point)
end_points[end_point] = net
if final_endpoint == end_point: return net, end_points
end_point = 'Conv2d_2b_1x1'
net = slim.conv2d(net, 64, [1, 1], scope=end_point)
end_points[end_point] = net
if final_endpoint == end_point: return net, end_points
end_point = 'Conv2d_2c_3x3'
net = slim.conv2d(net, 192, [3, 3], scope=end_point)
end_points[end_point] = net
if final_endpoint == end_point: return net, end_points
end_point = 'MaxPool_3a_3x3'
net = slim.max_pool2d(net, [3, 3], stride=2, scope=end_point)
end_points[end_point] = net
if final_endpoint == end_point: return net, end_points
end_point = 'Mixed_3b'
with tf.variable_scope(end_point):
with tf.variable_scope('Branch_0'):
branch_0 = slim.conv2d(net, 64, [1, 1], scope='Conv2d_0a_1x1')
with tf.variable_scope('Branch_1'):
branch_1 = slim.conv2d(net, 96, [1, 1], scope='Conv2d_0a_1x1')
branch_1 = slim.conv2d(branch_1, 128, [3, 3], scope='Conv2d_0b_3x3')
with tf.variable_scope('Branch_2'):
branch_2 = slim.conv2d(net, 16, [1, 1], scope='Conv2d_0a_1x1')
branch_2 = slim.conv2d(branch_2, 32, [3, 3], scope='Conv2d_0b_3x3')
with tf.variable_scope('Branch_3'):
branch_3 = slim.max_pool2d(net, [3, 3], scope='MaxPool_0a_3x3')
branch_3 = slim.conv2d(branch_3, 32, [1, 1], scope='Conv2d_0b_1x1')
net = tf.concat(
axis=3, values=[branch_0, branch_1, branch_2, branch_3])
end_points[end_point] = net
if final_endpoint == end_point: return net, end_points
end_point = 'Mixed_3c'
with tf.variable_scope(end_point):
with tf.variable_scope('Branch_0'):
branch_0 = slim.conv2d(net, 128, [1, 1], scope='Conv2d_0a_1x1')
with tf.variable_scope('Branch_1'):
branch_1 = slim.conv2d(net, 128, [1, 1], scope='Conv2d_0a_1x1')
branch_1 = slim.conv2d(branch_1, 192, [3, 3], scope='Conv2d_0b_3x3')
with tf.variable_scope('Branch_2'):
branch_2 = slim.conv2d(net, 32, [1, 1], scope='Conv2d_0a_1x1')
branch_2 = slim.conv2d(branch_2, 96, [3, 3], scope='Conv2d_0b_3x3')
with tf.variable_scope('Branch_3'):
branch_3 = slim.max_pool2d(net, [3, 3], scope='MaxPool_0a_3x3')
branch_3 = slim.conv2d(branch_3, 64, [1, 1], scope='Conv2d_0b_1x1')
net = tf.concat(
axis=3, values=[branch_0, branch_1, branch_2, branch_3])
end_points[end_point] = net
if final_endpoint == end_point: return net, end_points
end_point = 'MaxPool_4a_3x3'
net = slim.max_pool2d(net, [3, 3], stride=2, scope=end_point)
end_points[end_point] = net
if final_endpoint == end_point: return net, end_points
end_point = 'Mixed_4b'
with tf.variable_scope(end_point):
with tf.variable_scope('Branch_0'):
branch_0 = slim.conv2d(net, 192, [1, 1], scope='Conv2d_0a_1x1')
with tf.variable_scope('Branch_1'):
branch_1 = slim.conv2d(net, 96, [1, 1], scope='Conv2d_0a_1x1')
branch_1 = slim.conv2d(branch_1, 208, [3, 3], scope='Conv2d_0b_3x3')
with tf.variable_scope('Branch_2'):
branch_2 = slim.conv2d(net, 16, [1, 1], scope='Conv2d_0a_1x1')
branch_2 = slim.conv2d(branch_2, 48, [3, 3], scope='Conv2d_0b_3x3')
with tf.variable_scope('Branch_3'):
branch_3 = slim.max_pool2d(net, [3, 3], scope='MaxPool_0a_3x3')
branch_3 = slim.conv2d(branch_3, 64, [1, 1], scope='Conv2d_0b_1x1')
net = tf.concat(
axis=3, values=[branch_0, branch_1, branch_2, branch_3])
end_points[end_point] = net
if final_endpoint == end_point: return net, end_points
end_point = 'Mixed_4c'
with tf.variable_scope(end_point):
with tf.variable_scope('Branch_0'):
branch_0 = slim.conv2d(net, 160, [1, 1], scope='Conv2d_0a_1x1')
with tf.variable_scope('Branch_1'):
branch_1 = slim.conv2d(net, 112, [1, 1], scope='Conv2d_0a_1x1')
branch_1 = slim.conv2d(branch_1, 224, [3, 3], scope='Conv2d_0b_3x3')
with tf.variable_scope('Branch_2'):
branch_2 = slim.conv2d(net, 24, [1, 1], scope='Conv2d_0a_1x1')
branch_2 = slim.conv2d(branch_2, 64, [3, 3], scope='Conv2d_0b_3x3')
with tf.variable_scope('Branch_3'):
branch_3 = slim.max_pool2d(net, [3, 3], scope='MaxPool_0a_3x3')
branch_3 = slim.conv2d(branch_3, 64, [1, 1], scope='Conv2d_0b_1x1')
net = tf.concat(
axis=3, values=[branch_0, branch_1, branch_2, branch_3])
end_points[end_point] = net
if final_endpoint == end_point: return net, end_points
end_point = 'Mixed_4d'
with tf.variable_scope(end_point):
with tf.variable_scope('Branch_0'):
branch_0 = slim.conv2d(net, 128, [1, 1], scope='Conv2d_0a_1x1')
with tf.variable_scope('Branch_1'):
branch_1 = slim.conv2d(net, 128, [1, 1], scope='Conv2d_0a_1x1')
branch_1 = slim.conv2d(branch_1, 256, [3, 3], scope='Conv2d_0b_3x3')
with tf.variable_scope('Branch_2'):
branch_2 = slim.conv2d(net, 24, [1, 1], scope='Conv2d_0a_1x1')
branch_2 = slim.conv2d(branch_2, 64, [3, 3], scope='Conv2d_0b_3x3')
with tf.variable_scope('Branch_3'):
branch_3 = slim.max_pool2d(net, [3, 3], scope='MaxPool_0a_3x3')
branch_3 = slim.conv2d(branch_3, 64, [1, 1], scope='Conv2d_0b_1x1')
net = tf.concat(
axis=3, values=[branch_0, branch_1, branch_2, branch_3])
end_points[end_point] = net
if final_endpoint == end_point: return net, end_points
end_point = 'Mixed_4e'
with tf.variable_scope(end_point):
with tf.variable_scope('Branch_0'):
branch_0 = slim.conv2d(net, 112, [1, 1], scope='Conv2d_0a_1x1')
with tf.variable_scope('Branch_1'):
branch_1 = slim.conv2d(net, 144, [1, 1], scope='Conv2d_0a_1x1')
branch_1 = slim.conv2d(branch_1, 288, [3, 3], scope='Conv2d_0b_3x3')
with tf.variable_scope('Branch_2'):
branch_2 = slim.conv2d(net, 32, [1, 1], scope='Conv2d_0a_1x1')
branch_2 = slim.conv2d(branch_2, 64, [3, 3], scope='Conv2d_0b_3x3')
with tf.variable_scope('Branch_3'):
branch_3 = slim.max_pool2d(net, [3, 3], scope='MaxPool_0a_3x3')
branch_3 = slim.conv2d(branch_3, 64, [1, 1], scope='Conv2d_0b_1x1')
net = tf.concat(
axis=3, values=[branch_0, branch_1, branch_2, branch_3])
end_points[end_point] = net
if final_endpoint == end_point: return net, end_points
end_point = 'Mixed_4f'
with tf.variable_scope(end_point):
with tf.variable_scope('Branch_0'):
branch_0 = slim.conv2d(net, 256, [1, 1], scope='Conv2d_0a_1x1')
with tf.variable_scope('Branch_1'):
branch_1 = slim.conv2d(net, 160, [1, 1], scope='Conv2d_0a_1x1')
branch_1 = slim.conv2d(branch_1, 320, [3, 3], scope='Conv2d_0b_3x3')
with tf.variable_scope('Branch_2'):
branch_2 = slim.conv2d(net, 32, [1, 1], scope='Conv2d_0a_1x1')
branch_2 = slim.conv2d(branch_2, 128, [3, 3], scope='Conv2d_0b_3x3')
with tf.variable_scope('Branch_3'):
branch_3 = slim.max_pool2d(net, [3, 3], scope='MaxPool_0a_3x3')
branch_3 = slim.conv2d(branch_3, 128, [1, 1], scope='Conv2d_0b_1x1')
net = tf.concat(
axis=3, values=[branch_0, branch_1, branch_2, branch_3])
end_points[end_point] = net
if final_endpoint == end_point: return net, end_points
end_point = 'MaxPool_5a_2x2'
net = slim.max_pool2d(net, [2, 2], stride=2, scope=end_point)
end_points[end_point] = net
if final_endpoint == end_point: return net, end_points
end_point = 'Mixed_5b'
with tf.variable_scope(end_point):
with tf.variable_scope('Branch_0'):
branch_0 = slim.conv2d(net, 256, [1, 1], scope='Conv2d_0a_1x1')
with tf.variable_scope('Branch_1'):
branch_1 = slim.conv2d(net, 160, [1, 1], scope='Conv2d_0a_1x1')
branch_1 = slim.conv2d(branch_1, 320, [3, 3], scope='Conv2d_0b_3x3')
with tf.variable_scope('Branch_2'):
branch_2 = slim.conv2d(net, 32, [1, 1], scope='Conv2d_0a_1x1')
branch_2 = slim.conv2d(branch_2, 128, [3, 3], scope='Conv2d_0a_3x3')
with tf.variable_scope('Branch_3'):
branch_3 = slim.max_pool2d(net, [3, 3], scope='MaxPool_0a_3x3')
branch_3 = slim.conv2d(branch_3, 128, [1, 1], scope='Conv2d_0b_1x1')
net = tf.concat(
axis=3, values=[branch_0, branch_1, branch_2, branch_3])
end_points[end_point] = net
if final_endpoint == end_point: return net, end_points
end_point = 'Mixed_5c'
with tf.variable_scope(end_point):
with tf.variable_scope('Branch_0'):
branch_0 = slim.conv2d(net, 384, [1, 1], scope='Conv2d_0a_1x1')
with tf.variable_scope('Branch_1'):
branch_1 = slim.conv2d(net, 192, [1, 1], scope='Conv2d_0a_1x1')
branch_1 = slim.conv2d(branch_1, 384, [3, 3], scope='Conv2d_0b_3x3')
with tf.variable_scope('Branch_2'):
branch_2 = slim.conv2d(net, 48, [1, 1], scope='Conv2d_0a_1x1')
branch_2 = slim.conv2d(branch_2, 128, [3, 3], scope='Conv2d_0b_3x3')
with tf.variable_scope('Branch_3'):
branch_3 = slim.max_pool2d(net, [3, 3], scope='MaxPool_0a_3x3')
branch_3 = slim.conv2d(branch_3, 128, [1, 1], scope='Conv2d_0b_1x1')
net = tf.concat(
axis=3, values=[branch_0, branch_1, branch_2, branch_3])
end_points[end_point] = net
if final_endpoint == end_point: return net, end_points
raise ValueError('Unknown final endpoint %s' % final_endpoint)
def inception_v1(inputs,
num_classes=1000,
is_training=True,
dropout_keep_prob=0.8,
prediction_fn=slim.softmax,
spatial_squeeze=True,
reuse=None,
scope='InceptionV1'):
"""Defines the Inception V1 architecture.
This architecture is defined in:
Going deeper with convolutions
Christian Szegedy, Wei Liu, Yangqing Jia, Pierre Sermanet, Scott Reed,
Dragomir Anguelov, Dumitru Erhan, Vincent Vanhoucke, Andrew Rabinovich.
http://arxiv.org/pdf/1409.4842v1.pdf.
The default image size used to train this network is 224x224.
Args:
inputs: a tensor of size [batch_size, height, width, channels].
num_classes: number of predicted classes.
is_training: whether is training or not.
dropout_keep_prob: the percentage of activation values that are retained.
prediction_fn: a function to get predictions out of logits.
spatial_squeeze: if True, logits is of shape [B, C], if false logits is of
shape [B, 1, 1, C], where B is batch_size and C is number of classes.
reuse: whether or not the network and its variables should be reused. To be
able to reuse 'scope' must be given.
scope: Optional variable_scope.
Returns:
logits: the pre-softmax activations, a tensor of size
[batch_size, num_classes]
end_points: a dictionary from components of the network to the corresponding
activation.
"""
# Final pooling and prediction
with tf.variable_scope(scope, 'InceptionV1', [inputs, num_classes],
reuse=reuse) as scope:
with slim.arg_scope([slim.batch_norm, slim.dropout],
is_training=is_training):
net, end_points = inception_v1_base(inputs, scope=scope)
with tf.variable_scope('Logits'):
net = slim.avg_pool2d(net, [7, 7], stride=1, scope='AvgPool_0a_7x7')
net = slim.dropout(net,
dropout_keep_prob, scope='Dropout_0b')
logits = slim.conv2d(net, num_classes, [1, 1], activation_fn=None,
normalizer_fn=None, scope='Conv2d_0c_1x1')
if spatial_squeeze:
logits = tf.squeeze(logits, [1, 2], name='SpatialSqueeze')
end_points['Logits'] = logits
end_points['Predictions'] = prediction_fn(logits, scope='Predictions')
return logits, end_points
inception_v1.default_image_size = 224
inception_v1_arg_scope = inception_utils.inception_arg_scope
================================================
FILE: nets/inception_v1_test.py
================================================
# Copyright 2016 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Tests for nets.inception_v1."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import numpy as np
import tensorflow as tf
from nets import inception
slim = tf.contrib.slim
class InceptionV1Test(tf.test.TestCase):
def testBuildClassificationNetwork(self):
batch_size = 5
height, width = 224, 224
num_classes = 1000
inputs = tf.random_uniform((batch_size, height, width, 3))
logits, end_points = inception.inception_v1(inputs, num_classes)
self.assertTrue(logits.op.name.startswith('InceptionV1/Logits'))
self.assertListEqual(logits.get_shape().as_list(),
[batch_size, num_classes])
self.assertTrue('Predictions' in end_points)
self.assertListEqual(end_points['Predictions'].get_shape().as_list(),
[batch_size, num_classes])
def testBuildBaseNetwork(self):
batch_size = 5
height, width = 224, 224
inputs = tf.random_uniform((batch_size, height, width, 3))
mixed_6c, end_points = inception.inception_v1_base(inputs)
self.assertTrue(mixed_6c.op.name.startswith('InceptionV1/Mixed_5c'))
self.assertListEqual(mixed_6c.get_shape().as_list(),
[batch_size, 7, 7, 1024])
expected_endpoints = ['Conv2d_1a_7x7', 'MaxPool_2a_3x3', 'Conv2d_2b_1x1',
'Conv2d_2c_3x3', 'MaxPool_3a_3x3', 'Mixed_3b',
'Mixed_3c', 'MaxPool_4a_3x3', 'Mixed_4b', 'Mixed_4c',
'Mixed_4d', 'Mixed_4e', 'Mixed_4f', 'MaxPool_5a_2x2',
'Mixed_5b', 'Mixed_5c']
self.assertItemsEqual(end_points.keys(), expected_endpoints)
def testBuildOnlyUptoFinalEndpoint(self):
batch_size = 5
height, width = 224, 224
endpoints = ['Conv2d_1a_7x7', 'MaxPool_2a_3x3', 'Conv2d_2b_1x1',
'Conv2d_2c_3x3', 'MaxPool_3a_3x3', 'Mixed_3b', 'Mixed_3c',
'MaxPool_4a_3x3', 'Mixed_4b', 'Mixed_4c', 'Mixed_4d',
'Mixed_4e', 'Mixed_4f', 'MaxPool_5a_2x2', 'Mixed_5b',
'Mixed_5c']
for index, endpoint in enumerate(endpoints):
with tf.Graph().as_default():
inputs = tf.random_uniform((batch_size, height, width, 3))
out_tensor, end_points = inception.inception_v1_base(
inputs, final_endpoint=endpoint)
self.assertTrue(out_tensor.op.name.startswith(
'InceptionV1/' + endpoint))
self.assertItemsEqual(endpoints[:index+1], end_points)
def testBuildAndCheckAllEndPointsUptoMixed5c(self):
batch_size = 5
height, width = 224, 224
inputs = tf.random_uniform((batch_size, height, width, 3))
_, end_points = inception.inception_v1_base(inputs,
final_endpoint='Mixed_5c')
endpoints_shapes = {'Conv2d_1a_7x7': [5, 112, 112, 64],
'MaxPool_2a_3x3': [5, 56, 56, 64],
'Conv2d_2b_1x1': [5, 56, 56, 64],
'Conv2d_2c_3x3': [5, 56, 56, 192],
'MaxPool_3a_3x3': [5, 28, 28, 192],
'Mixed_3b': [5, 28, 28, 256],
'Mixed_3c': [5, 28, 28, 480],
'MaxPool_4a_3x3': [5, 14, 14, 480],
'Mixed_4b': [5, 14, 14, 512],
'Mixed_4c': [5, 14, 14, 512],
'Mixed_4d': [5, 14, 14, 512],
'Mixed_4e': [5, 14, 14, 528],
'Mixed_4f': [5, 14, 14, 832],
'MaxPool_5a_2x2': [5, 7, 7, 832],
'Mixed_5b': [5, 7, 7, 832],
'Mixed_5c': [5, 7, 7, 1024]}
self.assertItemsEqual(endpoints_shapes.keys(), end_points.keys())
for endpoint_name in endpoints_shapes:
expected_shape = endpoints_shapes[endpoint_name]
self.assertTrue(endpoint_name in end_points)
self.assertListEqual(end_points[endpoint_name].get_shape().as_list(),
expected_shape)
def testModelHasExpectedNumberOfParameters(self):
batch_size = 5
height, width = 224, 224
inputs = tf.random_uniform((batch_size, height, width, 3))
with slim.arg_scope(inception.inception_v1_arg_scope()):
inception.inception_v1_base(inputs)
total_params, _ = slim.model_analyzer.analyze_vars(
slim.get_model_variables())
self.assertAlmostEqual(5607184, total_params)
def testHalfSizeImages(self):
batch_size = 5
height, width = 112, 112
inputs = tf.random_uniform((batch_size, height, width, 3))
mixed_5c, _ = inception.inception_v1_base(inputs)
self.assertTrue(mixed_5c.op.name.startswith('InceptionV1/Mixed_5c'))
self.assertListEqual(mixed_5c.get_shape().as_list(),
[batch_size, 4, 4, 1024])
def testUnknownImageShape(self):
tf.reset_default_graph()
batch_size = 2
height, width = 224, 224
num_classes = 1000
input_np = np.random.uniform(0, 1, (batch_size, height, width, 3))
with self.test_session() as sess:
inputs = tf.placeholder(tf.float32, shape=(batch_size, None, None, 3))
logits, end_points = inception.inception_v1(inputs, num_classes)
self.assertTrue(logits.op.name.startswith('InceptionV1/Logits'))
self.assertListEqual(logits.get_shape().as_list(),
[batch_size, num_classes])
pre_pool = end_points['Mixed_5c']
feed_dict = {inputs: input_np}
tf.global_variables_initializer().run()
pre_pool_out = sess.run(pre_pool, feed_dict=feed_dict)
self.assertListEqual(list(pre_pool_out.shape), [batch_size, 7, 7, 1024])
def testUnknowBatchSize(self):
batch_size = 1
height, width = 224, 224
num_classes = 1000
inputs = tf.placeholder(tf.float32, (None, height, width, 3))
logits, _ = inception.inception_v1(inputs, num_classes)
self.assertTrue(logits.op.name.startswith('InceptionV1/Logits'))
self.assertListEqual(logits.get_shape().as_list(),
[None, num_classes])
images = tf.random_uniform((batch_size, height, width, 3))
with self.test_session() as sess:
sess.run(tf.global_variables_initializer())
output = sess.run(logits, {inputs: images.eval()})
self.assertEquals(output.shape, (batch_size, num_classes))
def testEvaluation(self):
batch_size = 2
height, width = 224, 224
num_classes = 1000
eval_inputs = tf.random_uniform((batch_size, height, width, 3))
logits, _ = inception.inception_v1(eval_inputs, num_classes,
is_training=False)
predictions = tf.argmax(logits, 1)
with self.test_session() as sess:
sess.run(tf.global_variables_initializer())
output = sess.run(predictions)
self.assertEquals(output.shape, (batch_size,))
def testTrainEvalWithReuse(self):
train_batch_size = 5
eval_batch_size = 2
height, width = 224, 224
num_classes = 1000
train_inputs = tf.random_uniform((train_batch_size, height, width, 3))
inception.inception_v1(train_inputs, num_classes)
eval_inputs = tf.random_uniform((eval_batch_size, height, width, 3))
logits, _ = inception.inception_v1(eval_inputs, num_classes, reuse=True)
predictions = tf.argmax(logits, 1)
with self.test_session() as sess:
sess.run(tf.global_variables_initializer())
output = sess.run(predictions)
self.assertEquals(output.shape, (eval_batch_size,))
def testLogitsNotSqueezed(self):
num_classes = 25
images = tf.random_uniform([1, 224, 224, 3])
logits, _ = inception.inception_v1(images,
num_classes=num_classes,
spatial_squeeze=False)
with self.test_session() as sess:
tf.global_variables_initializer().run()
logits_out = sess.run(logits)
self.assertListEqual(list(logits_out.shape), [1, 1, 1, num_classes])
if __name__ == '__main__':
tf.test.main()
================================================
FILE: nets/inception_v2.py
================================================
# Copyright 2016 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Contains the definition for inception v2 classification network."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import tensorflow as tf
from nets import inception_utils
slim = tf.contrib.slim
trunc_normal = lambda stddev: tf.truncated_normal_initializer(0.0, stddev)
def inception_v2_base(inputs,
final_endpoint='Mixed_5c',
min_depth=16,
depth_multiplier=1.0,
use_separable_conv=True,
data_format='NHWC',
scope=None):
"""Inception v2 (6a2).
Constructs an Inception v2 network from inputs to the given final endpoint.
This method can construct the network up to the layer inception(5b) as
described in http://arxiv.org/abs/1502.03167.
Args:
inputs: a tensor of shape [batch_size, height, width, channels].
final_endpoint: specifies the endpoint to construct the network up to. It
can be one of ['Conv2d_1a_7x7', 'MaxPool_2a_3x3', 'Conv2d_2b_1x1',
'Conv2d_2c_3x3', 'MaxPool_3a_3x3', 'Mixed_3b', 'Mixed_3c', 'Mixed_4a',
'Mixed_4b', 'Mixed_4c', 'Mixed_4d', 'Mixed_4e', 'Mixed_5a', 'Mixed_5b',
'Mixed_5c'].
min_depth: Minimum depth value (number of channels) for all convolution ops.
Enforced when depth_multiplier < 1, and not an active constraint when
depth_multiplier >= 1.
depth_multiplier: Float multiplier for the depth (number of channels)
for all convolution ops. The value must be greater than zero. Typical
usage will be to set this value in (0, 1) to reduce the number of
parameters or computation cost of the model.
use_separable_conv: Use a separable convolution for the first layer
Conv2d_1a_7x7. If this is False, use a normal convolution instead.
data_format: Data format of the activations ('NHWC' or 'NCHW').
scope: Optional variable_scope.
Returns:
tensor_out: output tensor corresponding to the final_endpoint.
end_points: a set of activations for external use, for example summaries or
losses.
Raises:
ValueError: if final_endpoint is not set to one of the predefined values,
or depth_multiplier <= 0
"""
# end_points will collect relevant activations for external use, for example
# summaries or losses.
end_points = {}
# Used to find thinned depths for each layer.
if depth_multiplier <= 0:
raise ValueError('depth_multiplier is not greater than zero.')
depth = lambda d: max(int(d * depth_multiplier), min_depth)
if data_format != 'NHWC' and data_format != 'NCHW':
raise ValueError('data_format must be either NHWC or NCHW.')
if data_format == 'NCHW' and use_separable_conv:
raise ValueError(
'separable convolution only supports NHWC layout. NCHW data format can'
' only be used when use_separable_conv is False.'
)
concat_dim = 3 if data_format == 'NHWC' else 1
with tf.variable_scope(scope, 'InceptionV2', [inputs]):
with slim.arg_scope(
[slim.conv2d, slim.max_pool2d, slim.avg_pool2d],
stride=1,
padding='SAME',
data_format=data_format):
# Note that sizes in the comments below assume an input spatial size of
# 224x224, however, the inputs can be of any size greater 32x32.
# 224 x 224 x 3
end_point = 'Conv2d_1a_7x7'
if use_separable_conv:
# depthwise_multiplier here is different from depth_multiplier.
# depthwise_multiplier determines the output channels of the initial
# depthwise conv (see docs for tf.nn.separable_conv2d), while
# depth_multiplier controls the # channels of the subsequent 1x1
# convolution. Must have
# in_channels * depthwise_multipler <= out_channels
# so that the separable convolution is not overparameterized.
depthwise_multiplier = min(int(depth(64) / 3), 8)
net = slim.separable_conv2d(
inputs, depth(64), [7, 7],
depth_multiplier=depthwise_multiplier,
stride=2,
padding='SAME',
weights_initializer=trunc_normal(1.0),
scope=end_point)
else:
# Use a normal convolution instead of a separable convolution.
net = slim.conv2d(
inputs,
depth(64), [7, 7],
stride=2,
weights_initializer=trunc_normal(1.0),
scope=end_point)
end_points[end_point] = net
if end_point == final_endpoint: return net, end_points
# 112 x 112 x 64
end_point = 'MaxPool_2a_3x3'
net = slim.max_pool2d(net, [3, 3], scope=end_point, stride=2)
end_points[end_point] = net
if end_point == final_endpoint: return net, end_points
# 56 x 56 x 64
end_point = 'Conv2d_2b_1x1'
net = slim.conv2d(net, depth(64), [1, 1], scope=end_point,
weights_initializer=trunc_normal(0.1))
end_points[end_point] = net
if end_point == final_endpoint: return net, end_points
# 56 x 56 x 64
end_point = 'Conv2d_2c_3x3'
net = slim.conv2d(net, depth(192), [3, 3], scope=end_point)
end_points[end_point] = net
if end_point == final_endpoint: return net, end_points
# 56 x 56 x 192
end_point = 'MaxPool_3a_3x3'
net = slim.max_pool2d(net, [3, 3], scope=end_point, stride=2)
end_points[end_point] = net
if end_point == final_endpoint: return net, end_points
# 28 x 28 x 192
# Inception module.
end_point = 'Mixed_3b'
with tf.variable_scope(end_point):
with tf.variable_scope('Branch_0'):
branch_0 = slim.conv2d(net, depth(64), [1, 1], scope='Conv2d_0a_1x1')
with tf.variable_scope('Branch_1'):
branch_1 = slim.conv2d(
net, depth(64), [1, 1],
weights_initializer=trunc_normal(0.09),
scope='Conv2d_0a_1x1')
branch_1 = slim.conv2d(branch_1, depth(64), [3, 3],
scope='Conv2d_0b_3x3')
with tf.variable_scope('Branch_2'):
branch_2 = slim.conv2d(
net, depth(64), [1, 1],
weights_initializer=trunc_normal(0.09),
scope='Conv2d_0a_1x1')
branch_2 = slim.conv2d(branch_2, depth(96), [3, 3],
scope='Conv2d_0b_3x3')
branch_2 = slim.conv2d(branch_2, depth(96), [3, 3],
scope='Conv2d_0c_3x3')
with tf.variable_scope('Branch_3'):
branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
branch_3 = slim.conv2d(
branch_3, depth(32), [1, 1],
weights_initializer=trunc_normal(0.1),
scope='Conv2d_0b_1x1')
net = tf.concat(
axis=concat_dim, values=[branch_0, branch_1, branch_2, branch_3])
end_points[end_point] = net
if end_point == final_endpoint: return net, end_points
# 28 x 28 x 256
end_point = 'Mixed_3c'
with tf.variable_scope(end_point):
with tf.variable_scope('Branch_0'):
branch_0 = slim.conv2d(net, depth(64), [1, 1], scope='Conv2d_0a_1x1')
with tf.variable_scope('Branch_1'):
branch_1 = slim.conv2d(
net, depth(64), [1, 1],
weights_initializer=trunc_normal(0.09),
scope='Conv2d_0a_1x1')
branch_1 = slim.conv2d(branch_1, depth(96), [3, 3],
scope='Conv2d_0b_3x3')
with tf.variable_scope('Branch_2'):
branch_2 = slim.conv2d(
net, depth(64), [1, 1],
weights_initializer=trunc_normal(0.09),
scope='Conv2d_0a_1x1')
branch_2 = slim.conv2d(branch_2, depth(96), [3, 3],
scope='Conv2d_0b_3x3')
branch_2 = slim.conv2d(branch_2, depth(96), [3, 3],
scope='Conv2d_0c_3x3')
with tf.variable_scope('Branch_3'):
branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
branch_3 = slim.conv2d(
branch_3, depth(64), [1, 1],
weights_initializer=trunc_normal(0.1),
scope='Conv2d_0b_1x1')
net = tf.concat(
axis=concat_dim, values=[branch_0, branch_1, branch_2, branch_3])
end_points[end_point] = net
if end_point == final_endpoint: return net, end_points
# 28 x 28 x 320
end_point = 'Mixed_4a'
with tf.variable_scope(end_point):
with tf.variable_scope('Branch_0'):
branch_0 = slim.conv2d(
net, depth(128), [1, 1],
weights_initializer=trunc_normal(0.09),
scope='Conv2d_0a_1x1')
branch_0 = slim.conv2d(branch_0, depth(160), [3, 3], stride=2,
scope='Conv2d_1a_3x3')
with tf.variable_scope('Branch_1'):
branch_1 = slim.conv2d(
net, depth(64), [1, 1],
weights_initializer=trunc_normal(0.09),
scope='Conv2d_0a_1x1')
branch_1 = slim.conv2d(
branch_1, depth(96), [3, 3], scope='Conv2d_0b_3x3')
branch_1 = slim.conv2d(
branch_1, depth(96), [3, 3], stride=2, scope='Conv2d_1a_3x3')
with tf.variable_scope('Branch_2'):
branch_2 = slim.max_pool2d(
net, [3, 3], stride=2, scope='MaxPool_1a_3x3')
net = tf.concat(axis=concat_dim, values=[branch_0, branch_1, branch_2])
end_points[end_point] = net
if end_point == final_endpoint: return net, end_points
# 14 x 14 x 576
end_point = 'Mixed_4b'
with tf.variable_scope(end_point):
with tf.variable_scope('Branch_0'):
branch_0 = slim.conv2d(net, depth(224), [1, 1], scope='Conv2d_0a_1x1')
with tf.variable_scope('Branch_1'):
branch_1 = slim.conv2d(
net, depth(64), [1, 1],
weights_initializer=trunc_normal(0.09),
scope='Conv2d_0a_1x1')
branch_1 = slim.conv2d(
branch_1, depth(96), [3, 3], scope='Conv2d_0b_3x3')
with tf.variable_scope('Branch_2'):
branch_2 = slim.conv2d(
net, depth(96), [1, 1],
weights_initializer=trunc_normal(0.09),
scope='Conv2d_0a_1x1')
branch_2 = slim.conv2d(branch_2, depth(128), [3, 3],
scope='Conv2d_0b_3x3')
branch_2 = slim.conv2d(branch_2, depth(128), [3, 3],
scope='Conv2d_0c_3x3')
with tf.variable_scope('Branch_3'):
branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
branch_3 = slim.conv2d(
branch_3, depth(128), [1, 1],
weights_initializer=trunc_normal(0.1),
scope='Conv2d_0b_1x1')
net = tf.concat(
axis=concat_dim, values=[branch_0, branch_1, branch_2, branch_3])
end_points[end_point] = net
if end_point == final_endpoint: return net, end_points
# 14 x 14 x 576
end_point = 'Mixed_4c'
with tf.variable_scope(end_point):
with tf.variable_scope('Branch_0'):
branch_0 = slim.conv2d(net, depth(192), [1, 1], scope='Conv2d_0a_1x1')
with tf.variable_scope('Branch_1'):
branch_1 = slim.conv2d(
net, depth(96), [1, 1],
weights_initializer=trunc_normal(0.09),
scope='Conv2d_0a_1x1')
branch_1 = slim.conv2d(branch_1, depth(128), [3, 3],
scope='Conv2d_0b_3x3')
with tf.variable_scope('Branch_2'):
branch_2 = slim.conv2d(
net, depth(96), [1, 1],
weights_initializer=trunc_normal(0.09),
scope='Conv2d_0a_1x1')
branch_2 = slim.conv2d(branch_2, depth(128), [3, 3],
scope='Conv2d_0b_3x3')
branch_2 = slim.conv2d(branch_2, depth(128), [3, 3],
scope='Conv2d_0c_3x3')
with tf.variable_scope('Branch_3'):
branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
branch_3 = slim.conv2d(
branch_3, depth(128), [1, 1],
weights_initializer=trunc_normal(0.1),
scope='Conv2d_0b_1x1')
net = tf.concat(
axis=concat_dim, values=[branch_0, branch_1, branch_2, branch_3])
end_points[end_point] = net
if end_point == final_endpoint: return net, end_points
# 14 x 14 x 576
end_point = 'Mixed_4d'
with tf.variable_scope(end_point):
with tf.variable_scope('Branch_0'):
branch_0 = slim.conv2d(net, depth(160), [1, 1], scope='Conv2d_0a_1x1')
with tf.variable_scope('Branch_1'):
branch_1 = slim.conv2d(
net, depth(128), [1, 1],
weights_initializer=trunc_normal(0.09),
scope='Conv2d_0a_1x1')
branch_1 = slim.conv2d(branch_1, depth(160), [3, 3],
scope='Conv2d_0b_3x3')
with tf.variable_scope('Branch_2'):
branch_2 = slim.conv2d(
net, depth(128), [1, 1],
weights_initializer=trunc_normal(0.09),
scope='Conv2d_0a_1x1')
branch_2 = slim.conv2d(branch_2, depth(160), [3, 3],
scope='Conv2d_0b_3x3')
branch_2 = slim.conv2d(branch_2, depth(160), [3, 3],
scope='Conv2d_0c_3x3')
with tf.variable_scope('Branch_3'):
branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
branch_3 = slim.conv2d(
branch_3, depth(96), [1, 1],
weights_initializer=trunc_normal(0.1),
scope='Conv2d_0b_1x1')
net = tf.concat(
axis=concat_dim, values=[branch_0, branch_1, branch_2, branch_3])
end_points[end_point] = net
if end_point == final_endpoint: return net, end_points
# 14 x 14 x 576
end_point = 'Mixed_4e'
with tf.variable_scope(end_point):
with tf.variable_scope('Branch_0'):
branch_0 = slim.conv2d(net, depth(96), [1, 1], scope='Conv2d_0a_1x1')
with tf.variable_scope('Branch_1'):
branch_1 = slim.conv2d(
net, depth(128), [1, 1],
weights_initializer=trunc_normal(0.09),
scope='Conv2d_0a_1x1')
branch_1 = slim.conv2d(branch_1, depth(192), [3, 3],
scope='Conv2d_0b_3x3')
with tf.variable_scope('Branch_2'):
branch_2 = slim.conv2d(
net, depth(160), [1, 1],
weights_initializer=trunc_normal(0.09),
scope='Conv2d_0a_1x1')
branch_2 = slim.conv2d(branch_2, depth(192), [3, 3],
scope='Conv2d_0b_3x3')
branch_2 = slim.conv2d(branch_2, depth(192), [3, 3],
scope='Conv2d_0c_3x3')
with tf.variable_scope('Branch_3'):
branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
branch_3 = slim.conv2d(
branch_3, depth(96), [1, 1],
weights_initializer=trunc_normal(0.1),
scope='Conv2d_0b_1x1')
net = tf.concat(
axis=concat_dim, values=[branch_0, branch_1, branch_2, branch_3])
end_points[end_point] = net
if end_point == final_endpoint: return net, end_points
# 14 x 14 x 576
end_point = 'Mixed_5a'
with tf.variable_scope(end_point):
with tf.variable_scope('Branch_0'):
branch_0 = slim.conv2d(
net, depth(128), [1, 1],
weights_initializer=trunc_normal(0.09),
scope='Conv2d_0a_1x1')
branch_0 = slim.conv2d(branch_0, depth(192), [3, 3], stride=2,
scope='Conv2d_1a_3x3')
with tf.variable_scope('Branch_1'):
branch_1 = slim.conv2d(
net, depth(192), [1, 1],
weights_initializer=trunc_normal(0.09),
scope='Conv2d_0a_1x1')
branch_1 = slim.conv2d(branch_1, depth(256), [3, 3],
scope='Conv2d_0b_3x3')
branch_1 = slim.conv2d(branch_1, depth(256), [3, 3], stride=2,
scope='Conv2d_1a_3x3')
with tf.variable_scope('Branch_2'):
branch_2 = slim.max_pool2d(net, [3, 3], stride=2,
scope='MaxPool_1a_3x3')
net = tf.concat(
axis=concat_dim, values=[branch_0, branch_1, branch_2])
end_points[end_point] = net
if end_point == final_endpoint: return net, end_points
# 7 x 7 x 1024
end_point = 'Mixed_5b'
with tf.variable_scope(end_point):
with tf.variable_scope('Branch_0'):
branch_0 = slim.conv2d(net, depth(352), [1, 1], scope='Conv2d_0a_1x1')
with tf.variable_scope('Branch_1'):
branch_1 = slim.conv2d(
net, depth(192), [1, 1],
weights_initializer=trunc_normal(0.09),
scope='Conv2d_0a_1x1')
branch_1 = slim.conv2d(branch_1, depth(320), [3, 3],
scope='Conv2d_0b_3x3')
with tf.variable_scope('Branch_2'):
branch_2 = slim.conv2d(
net, depth(160), [1, 1],
weights_initializer=trunc_normal(0.09),
scope='Conv2d_0a_1x1')
branch_2 = slim.conv2d(branch_2, depth(224), [3, 3],
scope='Conv2d_0b_3x3')
branch_2 = slim.conv2d(branch_2, depth(224), [3, 3],
scope='Conv2d_0c_3x3')
with tf.variable_scope('Branch_3'):
branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
branch_3 = slim.conv2d(
branch_3, depth(128), [1, 1],
weights_initializer=trunc_normal(0.1),
scope='Conv2d_0b_1x1')
net = tf.concat(
axis=concat_dim, values=[branch_0, branch_1, branch_2, branch_3])
end_points[end_point] = net
if end_point == final_endpoint: return net, end_points
# 7 x 7 x 1024
end_point = 'Mixed_5c'
with tf.variable_scope(end_point):
with tf.variable_scope('Branch_0'):
branch_0 = slim.conv2d(net, depth(352), [1, 1], scope='Conv2d_0a_1x1')
with tf.variable_scope('Branch_1'):
branch_1 = slim.conv2d(
net, depth(192), [1, 1],
weights_initializer=trunc_normal(0.09),
scope='Conv2d_0a_1x1')
branch_1 = slim.conv2d(branch_1, depth(320), [3, 3],
scope='Conv2d_0b_3x3')
with tf.variable_scope('Branch_2'):
branch_2 = slim.conv2d(
net, depth(192), [1, 1],
weights_initializer=trunc_normal(0.09),
scope='Conv2d_0a_1x1')
branch_2 = slim.conv2d(branch_2, depth(224), [3, 3],
scope='Conv2d_0b_3x3')
branch_2 = slim.conv2d(branch_2, depth(224), [3, 3],
scope='Conv2d_0c_3x3')
with tf.variable_scope('Branch_3'):
branch_3 = slim.max_pool2d(net, [3, 3], scope='MaxPool_0a_3x3')
branch_3 = slim.conv2d(
branch_3, depth(128), [1, 1],
weights_initializer=trunc_normal(0.1),
scope='Conv2d_0b_1x1')
net = tf.concat(
axis=concat_dim, values=[branch_0, branch_1, branch_2, branch_3])
end_points[end_point] = net
if end_point == final_endpoint: return net, end_points
raise ValueError('Unknown final endpoint %s' % final_endpoint)
def inception_v2(inputs,
num_classes=1000,
is_training=True,
dropout_keep_prob=0.8,
min_depth=16,
depth_multiplier=1.0,
prediction_fn=slim.softmax,
spatial_squeeze=True,
reuse=None,
scope='InceptionV2'):
"""Inception v2 model for classification.
Constructs an Inception v2 network for classification as described in
http://arxiv.org/abs/1502.03167.
The default image size used to train this network is 224x224.
Args:
inputs: a tensor of shape [batch_size, height, width, channels].
num_classes: number of predicted classes.
is_training: whether is training or not.
dropout_keep_prob: the percentage of activation values that are retained.
min_depth: Minimum depth value (number of channels) for all convolution ops.
Enforced when depth_multiplier < 1, and not an active constraint when
depth_multiplier >= 1.
depth_multiplier: Float multiplier for the depth (number of channels)
for all convolution ops. The value must be greater than zero. Typical
usage will be to set this value in (0, 1) to reduce the number of
parameters or computation cost of the model.
prediction_fn: a function to get predictions out of logits.
spatial_squeeze: if True, logits is of shape [B, C], if false logits is of
shape [B, 1, 1, C], where B is batch_size and C is number of classes.
reuse: whether or not the network and its variables should be reused. To be
able to reuse 'scope' must be given.
scope: Optional variable_scope.
Returns:
logits: the pre-softmax activations, a tensor of size
[batch_size, num_classes]
end_points: a dictionary from components of the network to the corresponding
activation.
Raises:
ValueError: if final_endpoint is not set to one of the predefined values,
or depth_multiplier <= 0
"""
if depth_multiplier <= 0:
raise ValueError('depth_multiplier is not greater than zero.')
# Final pooling and prediction
with tf.variable_scope(scope, 'InceptionV2', [inputs, num_classes],
reuse=reuse) as scope:
with slim.arg_scope([slim.batch_norm, slim.dropout],
is_training=is_training):
net, end_points = inception_v2_base(
inputs, scope=scope, min_depth=min_depth,
depth_multiplier=depth_multiplier)
with tf.variable_scope('Logits'):
kernel_size = _reduced_kernel_size_for_small_input(net, [7, 7])
net = slim.avg_pool2d(net, kernel_size, padding='VALID',
scope='AvgPool_1a_{}x{}'.format(*kernel_size))
# 1 x 1 x 1024
net = slim.dropout(net, keep_prob=dropout_keep_prob, scope='Dropout_1b')
logits = slim.conv2d(net, num_classes, [1, 1], activation_fn=None,
normalizer_fn=None, scope='Conv2d_1c_1x1')
if spatial_squeeze:
logits = tf.squeeze(logits, [1, 2], name='SpatialSqueeze')
end_points['Logits'] = logits
end_points['Predictions'] = prediction_fn(logits, scope='Predictions')
return logits, end_points
inception_v2.default_image_size = 224
def _reduced_kernel_size_for_small_input(input_tensor, kernel_size):
"""Define kernel size which is automatically reduced for small input.
If the shape of the input images is unknown at graph construction time this
function assumes that the input images are is large enough.
Args:
input_tensor: input tensor of size [batch_size, height, width, channels].
kernel_size: desired kernel size of length 2: [kernel_height, kernel_width]
Returns:
a tensor with the kernel size.
TODO(jrru): Make this function work with unknown shapes. Theoretically, this
can be done with the code below. Problems are two-fold: (1) If the shape was
known, it will be lost. (2) inception.slim.ops._two_element_tuple cannot
handle tensors that define the kernel size.
shape = tf.shape(input_tensor)
return = tf.stack([tf.minimum(shape[1], kernel_size[0]),
tf.minimum(shape[2], kernel_size[1])])
"""
shape = input_tensor.get_shape().as_list()
if shape[1] is None or shape[2] is None:
kernel_size_out = kernel_size
else:
kernel_size_out = [min(shape[1], kernel_size[0]),
min(shape[2], kernel_size[1])]
return kernel_size_out
inception_v2_arg_scope = inception_utils.inception_arg_scope
================================================
FILE: nets/inception_v2_test.py
================================================
# Copyright 2016 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Tests for nets.inception_v2."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import numpy as np
import tensorflow as tf
from nets import inception
slim = tf.contrib.slim
class InceptionV2Test(tf.test.TestCase):
def testBuildClassificationNetwork(self):
batch_size = 5
height, width = 224, 224
num_classes = 1000
inputs = tf.random_uniform((batch_size, height, width, 3))
logits, end_points = inception.inception_v2(inputs, num_classes)
self.assertTrue(logits.op.name.startswith('InceptionV2/Logits'))
self.assertListEqual(logits.get_shape().as_list(),
[batch_size, num_classes])
self.assertTrue('Predictions' in end_points)
self.assertListEqual(end_points['Predictions'].get_shape().as_list(),
[batch_size, num_classes])
def testBuildBaseNetwork(self):
batch_size = 5
height, width = 224, 224
inputs = tf.random_uniform((batch_size, height, width, 3))
mixed_5c, end_points = inception.inception_v2_base(inputs)
self.assertTrue(mixed_5c.op.name.startswith('InceptionV2/Mixed_5c'))
self.assertListEqual(mixed_5c.get_shape().as_list(),
[batch_size, 7, 7, 1024])
expected_endpoints = ['Mixed_3b', 'Mixed_3c', 'Mixed_4a', 'Mixed_4b',
'Mixed_4c', 'Mixed_4d', 'Mixed_4e', 'Mixed_5a',
'Mixed_5b', 'Mixed_5c', 'Conv2d_1a_7x7',
'MaxPool_2a_3x3', 'Conv2d_2b_1x1', 'Conv2d_2c_3x3',
'MaxPool_3a_3x3']
self.assertItemsEqual(end_points.keys(), expected_endpoints)
def testBuildOnlyUptoFinalEndpoint(self):
batch_size = 5
height, width = 224, 224
endpoints = ['Conv2d_1a_7x7', 'MaxPool_2a_3x3', 'Conv2d_2b_1x1',
'Conv2d_2c_3x3', 'MaxPool_3a_3x3', 'Mixed_3b', 'Mixed_3c',
'Mixed_4a', 'Mixed_4b', 'Mixed_4c', 'Mixed_4d', 'Mixed_4e',
'Mixed_5a', 'Mixed_5b', 'Mixed_5c']
for index, endpoint in enumerate(endpoints):
with tf.Graph().as_default():
inputs = tf.random_uniform((batch_size, height, width, 3))
out_tensor, end_points = inception.inception_v2_base(
inputs, final_endpoint=endpoint)
self.assertTrue(out_tensor.op.name.startswith(
'InceptionV2/' + endpoint))
self.assertItemsEqual(endpoints[:index+1], end_points)
def testBuildAndCheckAllEndPointsUptoMixed5c(self):
batch_size = 5
height, width = 224, 224
inputs = tf.random_uniform((batch_size, height, width, 3))
_, end_points = inception.inception_v2_base(inputs,
final_endpoint='Mixed_5c')
endpoints_shapes = {'Mixed_3b': [batch_size, 28, 28, 256],
'Mixed_3c': [batch_size, 28, 28, 320],
'Mixed_4a': [batch_size, 14, 14, 576],
'Mixed_4b': [batch_size, 14, 14, 576],
'Mixed_4c': [batch_size, 14, 14, 576],
'Mixed_4d': [batch_size, 14, 14, 576],
'Mixed_4e': [batch_size, 14, 14, 576],
'Mixed_5a': [batch_size, 7, 7, 1024],
'Mixed_5b': [batch_size, 7, 7, 1024],
'Mixed_5c': [batch_size, 7, 7, 1024],
'Conv2d_1a_7x7': [batch_size, 112, 112, 64],
'MaxPool_2a_3x3': [batch_size, 56, 56, 64],
'Conv2d_2b_1x1': [batch_size, 56, 56, 64],
'Conv2d_2c_3x3': [batch_size, 56, 56, 192],
'MaxPool_3a_3x3': [batch_size, 28, 28, 192]}
self.assertItemsEqual(endpoints_shapes.keys(), end_points.keys())
for endpoint_name in endpoints_shapes:
expected_shape = endpoints_shapes[endpoint_name]
self.assertTrue(endpoint_name in end_points)
self.assertListEqual(end_points[endpoint_name].get_shape().as_list(),
expected_shape)
def testModelHasExpectedNumberOfParameters(self):
batch_size = 5
height, width = 224, 224
inputs = tf.random_uniform((batch_size, height, width, 3))
with slim.arg_scope(inception.inception_v2_arg_scope()):
inception.inception_v2_base(inputs)
total_params, _ = slim.model_analyzer.analyze_vars(
slim.get_model_variables())
self.assertAlmostEqual(10173112, total_params)
def testBuildEndPointsWithDepthMultiplierLessThanOne(self):
batch_size = 5
height, width = 224, 224
num_classes = 1000
inputs = tf.random_uniform((batch_size, height, width, 3))
_, end_points = inception.inception_v2(inputs, num_classes)
endpoint_keys = [key for key in end_points.keys()
if key.startswith('Mixed') or key.startswith('Conv')]
_, end_points_with_multiplier = inception.inception_v2(
inputs, num_classes, scope='depth_multiplied_net',
depth_multiplier=0.5)
for key in endpoint_keys:
original_depth = end_points[key].get_shape().as_list()[3]
new_depth = end_points_with_multiplier[key].get_shape().as_list()[3]
self.assertEqual(0.5 * original_depth, new_depth)
def testBuildEndPointsWithDepthMultiplierGreaterThanOne(self):
batch_size = 5
height, width = 224, 224
num_classes = 1000
inputs = tf.random_uniform((batch_size, height, width, 3))
_, end_points = inception.inception_v2(inputs, num_classes)
endpoint_keys = [key for key in end_points.keys()
if key.startswith('Mixed') or key.startswith('Conv')]
_, end_points_with_multiplier = inception.inception_v2(
inputs, num_classes, scope='depth_multiplied_net',
depth_multiplier=2.0)
for key in endpoint_keys:
original_depth = end_points[key].get_shape().as_list()[3]
new_depth = end_points_with_multiplier[key].get_shape().as_list()[3]
self.assertEqual(2.0 * original_depth, new_depth)
def testRaiseValueErrorWithInvalidDepthMultiplier(self):
batch_size = 5
height, width = 224, 224
num_classes = 1000
inputs = tf.random_uniform((batch_size, height, width, 3))
with self.assertRaises(ValueError):
_ = inception.inception_v2(inputs, num_classes, depth_multiplier=-0.1)
with self.assertRaises(ValueError):
_ = inception.inception_v2(inputs, num_classes, depth_multiplier=0.0)
def testBuildEndPointsWithUseSeparableConvolutionFalse(self):
batch_size = 5
height, width = 224, 224
inputs = tf.random_uniform((batch_size, height, width, 3))
_, end_points = inception.inception_v2_base(inputs)
endpoint_keys = [
key for key in end_points.keys()
if key.startswith('Mixed') or key.startswith('Conv')
]
_, end_points_with_replacement = inception.inception_v2_base(
inputs, use_separable_conv=False)
# The endpoint shapes must be equal to the original shape even when the
# separable convolution is replaced with a normal convolution.
for key in endpoint_keys:
original_shape = end_points[key].get_shape().as_list()
self.assertTrue(key in end_points_with_replacement)
new_shape = end_points_with_replacement[key].get_shape().as_list()
self.assertListEqual(original_shape, new_shape)
def testBuildEndPointsNCHWDataFormat(self):
batch_size = 5
height, width = 224, 224
inputs = tf.random_uniform((batch_size, height, width, 3))
_, end_points = inception.inception_v2_base(inputs)
endpoint_keys = [
key for key in end_points.keys()
if key.startswith('Mixed') or key.startswith('Conv')
]
inputs_in_nchw = tf.random_uniform((batch_size, 3, height, width))
_, end_points_with_replacement = inception.inception_v2_base(
inputs_in_nchw, use_separable_conv=False, data_format='NCHW')
# With the 'NCHW' data format, all endpoint activations have a transposed
# shape from the original shape with the 'NHWC' layout.
for key in endpoint_keys:
transposed_original_shape = tf.transpose(
end_points[key], [0, 3, 1, 2]).get_shape().as_list()
self.assertTrue(key in end_points_with_replacement)
new_shape = end_points_with_replacement[key].get_shape().as_list()
self.assertListEqual(transposed_original_shape, new_shape)
def testBuildErrorsForDataFormats(self):
batch_size = 5
height, width = 224, 224
inputs = tf.random_uniform((batch_size, height, width, 3))
# 'NCWH' data format is not supported.
with self.assertRaises(ValueError):
_ = inception.inception_v2_base(inputs, data_format='NCWH')
# 'NCHW' data format is not supported for separable convolution.
with self.assertRaises(ValueError):
_ = inception.inception_v2_base(inputs, data_format='NCHW')
def testHalfSizeImages(self):
batch_size = 5
height, width = 112, 112
num_classes = 1000
inputs = tf.random_uniform((batch_size, height, width, 3))
logits, end_points = inception.inception_v2(inputs, num_classes)
self.assertTrue(logits.op.name.startswith('InceptionV2/Logits'))
self.assertListEqual(logits.get_shape().as_list(),
[batch_size, num_classes])
pre_pool = end_points['Mixed_5c']
self.assertListEqual(pre_pool.get_shape().as_list(),
[batch_size, 4, 4, 1024])
def testUnknownImageShape(self):
tf.reset_default_graph()
batch_size = 2
height, width = 224, 224
num_classes = 1000
input_np = np.random.uniform(0, 1, (batch_size, height, width, 3))
with self.test_session() as sess:
inputs = tf.placeholder(tf.float32, shape=(batch_size, None, None, 3))
logits, end_points = inception.inception_v2(inputs, num_classes)
self.assertTrue(logits.op.name.startswith('InceptionV2/Logits'))
self.assertListEqual(logits.get_shape().as_list(),
[batch_size, num_classes])
pre_pool = end_points['Mixed_5c']
feed_dict = {inputs: input_np}
tf.global_variables_initializer().run()
pre_pool_out = sess.run(pre_pool, feed_dict=feed_dict)
self.assertListEqual(list(pre_pool_out.shape), [batch_size, 7, 7, 1024])
def testUnknowBatchSize(self):
batch_size = 1
height, width = 224, 224
num_classes = 1000
inputs = tf.placeholder(tf.float32, (None, height, width, 3))
logits, _ = inception.inception_v2(inputs, num_classes)
self.assertTrue(logits.op.name.startswith('InceptionV2/Logits'))
self.assertListEqual(logits.get_shape().as_list(),
[None, num_classes])
images = tf.random_uniform((batch_size, height, width, 3))
with self.test_session() as sess:
sess.run(tf.global_variables_initializer())
output = sess.run(logits, {inputs: images.eval()})
self.assertEquals(output.shape, (batch_size, num_classes))
def testEvaluation(self):
batch_size = 2
height, width = 224, 224
num_classes = 1000
eval_inputs = tf.random_uniform((batch_size, height, width, 3))
logits, _ = inception.inception_v2(eval_inputs, num_classes,
is_training=False)
predictions = tf.argmax(logits, 1)
with self.test_session() as sess:
sess.run(tf.global_variables_initializer())
output = sess.run(predictions)
self.assertEquals(output.shape, (batch_size,))
def testTrainEvalWithReuse(self):
train_batch_size = 5
eval_batch_size = 2
height, width = 150, 150
num_classes = 1000
train_inputs = tf.random_uniform((train_batch_size, height, width, 3))
inception.inception_v2(train_inputs, num_classes)
eval_inputs = tf.random_uniform((eval_batch_size, height, width, 3))
logits, _ = inception.inception_v2(eval_inputs, num_classes, reuse=True)
predictions = tf.argmax(logits, 1)
with self.test_session() as sess:
sess.run(tf.global_variables_initializer())
output = sess.run(predictions)
self.assertEquals(output.shape, (eval_batch_size,))
def testLogitsNotSqueezed(self):
num_classes = 25
images = tf.random_uniform([1, 224, 224, 3])
logits, _ = inception.inception_v2(images,
num_classes=num_classes,
spatial_squeeze=False)
with self.test_session() as sess:
tf.global_variables_initializer().run()
logits_out = sess.run(logits)
self.assertListEqual(list(logits_out.shape), [1, 1, 1, num_classes])
if __name__ == '__main__':
tf.test.main()
================================================
FILE: nets/inception_v3.py
================================================
# Copyright 2016 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Contains the definition for inception v3 classification network."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import tensorflow as tf
from nets import inception_utils
slim = tf.contrib.slim
trunc_normal = lambda stddev: tf.truncated_normal_initializer(0.0, stddev)
def inception_v3_base(inputs,
final_endpoint='Mixed_7c',
min_depth=16,
depth_multiplier=1.0,
scope=None):
"""Inception model from http://arxiv.org/abs/1512.00567.
Constructs an Inception v3 network from inputs to the given final endpoint.
This method can construct the network up to the final inception block
Mixed_7c.
Note that the names of the layers in the paper do not correspond to the names
of the endpoints registered by this function although they build the same
network.
Here is a mapping from the old_names to the new names:
Old name | New name
=======================================
conv0 | Conv2d_1a_3x3
conv1 | Conv2d_2a_3x3
conv2 | Conv2d_2b_3x3
pool1 | MaxPool_3a_3x3
conv3 | Conv2d_3b_1x1
conv4 | Conv2d_4a_3x3
pool2 | MaxPool_5a_3x3
mixed_35x35x256a | Mixed_5b
mixed_35x35x288a | Mixed_5c
mixed_35x35x288b | Mixed_5d
mixed_17x17x768a | Mixed_6a
mixed_17x17x768b | Mixed_6b
mixed_17x17x768c | Mixed_6c
mixed_17x17x768d | Mixed_6d
mixed_17x17x768e | Mixed_6e
mixed_8x8x1280a | Mixed_7a
mixed_8x8x2048a | Mixed_7b
mixed_8x8x2048b | Mixed_7c
Args:
inputs: a tensor of size [batch_size, height, width, channels].
final_endpoint: specifies the endpoint to construct the network up to. It
can be one of ['Conv2d_1a_3x3', 'Conv2d_2a_3x3', 'Conv2d_2b_3x3',
'MaxPool_3a_3x3', 'Conv2d_3b_1x1', 'Conv2d_4a_3x3', 'MaxPool_5a_3x3',
'Mixed_5b', 'Mixed_5c', 'Mixed_5d', 'Mixed_6a', 'Mixed_6b', 'Mixed_6c',
'Mixed_6d', 'Mixed_6e', 'Mixed_7a', 'Mixed_7b', 'Mixed_7c'].
min_depth: Minimum depth value (number of channels) for all convolution ops.
Enforced when depth_multiplier < 1, and not an active constraint when
depth_multiplier >= 1.
depth_multiplier: Float multiplier for the depth (number of channels)
for all convolution ops. The value must be greater than zero. Typical
usage will be to set this value in (0, 1) to reduce the number of
parameters or computation cost of the model.
scope: Optional variable_scope.
Returns:
tensor_out: output tensor corresponding to the final_endpoint.
end_points: a set of activations for external use, for example summaries or
losses.
Raises:
ValueError: if final_endpoint is not set to one of the predefined values,
or depth_multiplier <= 0
"""
# end_points will collect relevant activations for external use, for example
# summaries or losses.
end_points = {}
if depth_multiplier <= 0:
raise ValueError('depth_multiplier is not greater than zero.')
depth = lambda d: max(int(d * depth_multiplier), min_depth)
with tf.variable_scope(scope, 'InceptionV3', [inputs]):
with slim.arg_scope([slim.conv2d, slim.max_pool2d, slim.avg_pool2d],
stride=1, padding='VALID'):
# 299 x 299 x 3
end_point = 'Conv2d_1a_3x3'
net = slim.conv2d(inputs, depth(32), [3, 3], stride=2, scope=end_point)
end_points[end_point] = net
if end_point == final_endpoint: return net, end_points
# 149 x 149 x 32
end_point = 'Conv2d_2a_3x3'
net = slim.conv2d(net, depth(32), [3, 3], scope=end_point)
end_points[end_point] = net
if end_point == final_endpoint: return net, end_points
# 147 x 147 x 32
end_point = 'Conv2d_2b_3x3'
net = slim.conv2d(net, depth(64), [3, 3], padding='SAME', scope=end_point)
end_points[end_point] = net
if end_point == final_endpoint: return net, end_points
# 147 x 147 x 64
end_point = 'MaxPool_3a_3x3'
net = slim.max_pool2d(net, [3, 3], stride=2, scope=end_point)
end_points[end_point] = net
if end_point == final_endpoint: return net, end_points
# 73 x 73 x 64
end_point = 'Conv2d_3b_1x1'
net = slim.conv2d(net, depth(80), [1, 1], scope=end_point)
end_points[end_point] = net
if end_point == final_endpoint: return net, end_points
# 73 x 73 x 80.
end_point = 'Conv2d_4a_3x3'
net = slim.conv2d(net, depth(192), [3, 3], scope=end_point)
end_points[end_point] = net
if end_point == final_endpoint: return net, end_points
# 71 x 71 x 192.
end_point = 'MaxPool_5a_3x3'
net = slim.max_pool2d(net, [3, 3], stride=2, scope=end_point)
end_points[end_point] = net
if end_point == final_endpoint: return net, end_points
# 35 x 35 x 192.
# Inception blocks
with slim.arg_scope([slim.conv2d, slim.max_pool2d, slim.avg_pool2d],
stride=1, padding='SAME'):
# mixed: 35 x 35 x 256.
end_point = 'Mixed_5b'
with tf.variable_scope(end_point):
with tf.variable_scope('Branch_0'):
branch_0 = slim.conv2d(net, depth(64), [1, 1], scope='Conv2d_0a_1x1')
with tf.variable_scope('Branch_1'):
branch_1 = slim.conv2d(net, depth(48), [1, 1], scope='Conv2d_0a_1x1')
branch_1 = slim.conv2d(branch_1, depth(64), [5, 5],
scope='Conv2d_0b_5x5')
with tf.variable_scope('Branch_2'):
branch_2 = slim.conv2d(net, depth(64), [1, 1], scope='Conv2d_0a_1x1')
branch_2 = slim.conv2d(branch_2, depth(96), [3, 3],
scope='Conv2d_0b_3x3')
branch_2 = slim.conv2d(branch_2, depth(96), [3, 3],
scope='Conv2d_0c_3x3')
with tf.variable_scope('Branch_3'):
branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
branch_3 = slim.conv2d(branch_3, depth(32), [1, 1],
scope='Conv2d_0b_1x1')
net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
end_points[end_point] = net
if end_point == final_endpoint: return net, end_points
# mixed_1: 35 x 35 x 288.
end_point = 'Mixed_5c'
with tf.variable_scope(end_point):
with tf.variable_scope('Branch_0'):
branch_0 = slim.conv2d(net, depth(64), [1, 1], scope='Conv2d_0a_1x1')
with tf.variable_scope('Branch_1'):
branch_1 = slim.conv2d(net, depth(48), [1, 1], scope='Conv2d_0b_1x1')
branch_1 = slim.conv2d(branch_1, depth(64), [5, 5],
scope='Conv_1_0c_5x5')
with tf.variable_scope('Branch_2'):
branch_2 = slim.conv2d(net, depth(64), [1, 1],
scope='Conv2d_0a_1x1')
branch_2 = slim.conv2d(branch_2, depth(96), [3, 3],
scope='Conv2d_0b_3x3')
branch_2 = slim.conv2d(branch_2, depth(96), [3, 3],
scope='Conv2d_0c_3x3')
with tf.variable_scope('Branch_3'):
branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
branch_3 = slim.conv2d(branch_3, depth(64), [1, 1],
scope='Conv2d_0b_1x1')
net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
end_points[end_point] = net
if end_point == final_endpoint: return net, end_points
# mixed_2: 35 x 35 x 288.
end_point = 'Mixed_5d'
with tf.variable_scope(end_point):
with tf.variable_scope('Branch_0'):
branch_0 = slim.conv2d(net, depth(64), [1, 1], scope='Conv2d_0a_1x1')
with tf.variable_scope('Branch_1'):
branch_1 = slim.conv2d(net, depth(48), [1, 1], scope='Conv2d_0a_1x1')
branch_1 = slim.conv2d(branch_1, depth(64), [5, 5],
scope='Conv2d_0b_5x5')
with tf.variable_scope('Branch_2'):
branch_2 = slim.conv2d(net, depth(64), [1, 1], scope='Conv2d_0a_1x1')
branch_2 = slim.conv2d(branch_2, depth(96), [3, 3],
scope='Conv2d_0b_3x3')
branch_2 = slim.conv2d(branch_2, depth(96), [3, 3],
scope='Conv2d_0c_3x3')
with tf.variable_scope('Branch_3'):
branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
branch_3 = slim.conv2d(branch_3, depth(64), [1, 1],
scope='Conv2d_0b_1x1')
net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
end_points[end_point] = net
if end_point == final_endpoint: return net, end_points
# mixed_3: 17 x 17 x 768.
end_point = 'Mixed_6a'
with tf.variable_scope(end_point):
with tf.variable_scope('Branch_0'):
branch_0 = slim.conv2d(net, depth(384), [3, 3], stride=2,
padding='VALID', scope='Conv2d_1a_1x1')
with tf.variable_scope('Branch_1'):
branch_1 = slim.conv2d(net, depth(64), [1, 1], scope='Conv2d_0a_1x1')
branch_1 = slim.conv2d(branch_1, depth(96), [3, 3],
scope='Conv2d_0b_3x3')
branch_1 = slim.conv2d(branch_1, depth(96), [3, 3], stride=2,
padding='VALID', scope='Conv2d_1a_1x1')
with tf.variable_scope('Branch_2'):
branch_2 = slim.max_pool2d(net, [3, 3], stride=2, padding='VALID',
scope='MaxPool_1a_3x3')
net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2])
end_points[end_point] = net
if end_point == final_endpoint: return net, end_points
# mixed4: 17 x 17 x 768.
end_point = 'Mixed_6b'
with tf.variable_scope(end_point):
with tf.variable_scope('Branch_0'):
branch_0 = slim.conv2d(net, depth(192), [1, 1], scope='Conv2d_0a_1x1')
with tf.variable_scope('Branch_1'):
branch_1 = slim.conv2d(net, depth(128), [1, 1], scope='Conv2d_0a_1x1')
branch_1 = slim.conv2d(branch_1, depth(128), [1, 7],
scope='Conv2d_0b_1x7')
branch_1 = slim.conv2d(branch_1, depth(192), [7, 1],
scope='Conv2d_0c_7x1')
with tf.variable_scope('Branch_2'):
branch_2 = slim.conv2d(net, depth(128), [1, 1], scope='Conv2d_0a_1x1')
branch_2 = slim.conv2d(branch_2, depth(128), [7, 1],
scope='Conv2d_0b_7x1')
branch_2 = slim.conv2d(branch_2, depth(128), [1, 7],
scope='Conv2d_0c_1x7')
branch_2 = slim.conv2d(branch_2, depth(128), [7, 1],
scope='Conv2d_0d_7x1')
branch_2 = slim.conv2d(branch_2, depth(192), [1, 7],
scope='Conv2d_0e_1x7')
with tf.variable_scope('Branch_3'):
branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
branch_3 = slim.conv2d(branch_3, depth(192), [1, 1],
scope='Conv2d_0b_1x1')
net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
end_points[end_point] = net
if end_point == final_endpoint: return net, end_points
# mixed_5: 17 x 17 x 768.
end_point = 'Mixed_6c'
with tf.variable_scope(end_point):
with tf.variable_scope('Branch_0'):
branch_0 = slim.conv2d(net, depth(192), [1, 1], scope='Conv2d_0a_1x1')
with tf.variable_scope('Branch_1'):
branch_1 = slim.conv2d(net, depth(160), [1, 1], scope='Conv2d_0a_1x1')
branch_1 = slim.conv2d(branch_1, depth(160), [1, 7],
scope='Conv2d_0b_1x7')
branch_1 = slim.conv2d(branch_1, depth(192), [7, 1],
scope='Conv2d_0c_7x1')
with tf.variable_scope('Branch_2'):
branch_2 = slim.conv2d(net, depth(160), [1, 1], scope='Conv2d_0a_1x1')
branch_2 = slim.conv2d(branch_2, depth(160), [7, 1],
scope='Conv2d_0b_7x1')
branch_2 = slim.conv2d(branch_2, depth(160), [1, 7],
scope='Conv2d_0c_1x7')
branch_2 = slim.conv2d(branch_2, depth(160), [7, 1],
scope='Conv2d_0d_7x1')
branch_2 = slim.conv2d(branch_2, depth(192), [1, 7],
scope='Conv2d_0e_1x7')
with tf.variable_scope('Branch_3'):
branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
branch_3 = slim.conv2d(branch_3, depth(192), [1, 1],
scope='Conv2d_0b_1x1')
net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
end_points[end_point] = net
if end_point == final_endpoint: return net, end_points
# mixed_6: 17 x 17 x 768.
end_point = 'Mixed_6d'
with tf.variable_scope(end_point):
with tf.variable_scope('Branch_0'):
branch_0 = slim.conv2d(net, depth(192), [1, 1], scope='Conv2d_0a_1x1')
with tf.variable_scope('Branch_1'):
branch_1 = slim.conv2d(net, depth(160), [1, 1], scope='Conv2d_0a_1x1')
branch_1 = slim.conv2d(branch_1, depth(160), [1, 7],
scope='Conv2d_0b_1x7')
branch_1 = slim.conv2d(branch_1, depth(192), [7, 1],
scope='Conv2d_0c_7x1')
with tf.variable_scope('Branch_2'):
branch_2 = slim.conv2d(net, depth(160), [1, 1], scope='Conv2d_0a_1x1')
branch_2 = slim.conv2d(branch_2, depth(160), [7, 1],
scope='Conv2d_0b_7x1')
branch_2 = slim.conv2d(branch_2, depth(160), [1, 7],
scope='Conv2d_0c_1x7')
branch_2 = slim.conv2d(branch_2, depth(160), [7, 1],
scope='Conv2d_0d_7x1')
branch_2 = slim.conv2d(branch_2, depth(192), [1, 7],
scope='Conv2d_0e_1x7')
with tf.variable_scope('Branch_3'):
branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
branch_3 = slim.conv2d(branch_3, depth(192), [1, 1],
scope='Conv2d_0b_1x1')
net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
end_points[end_point] = net
if end_point == final_endpoint: return net, end_points
# mixed_7: 17 x 17 x 768.
end_point = 'Mixed_6e'
with tf.variable_scope(end_point):
with tf.variable_scope('Branch_0'):
branch_0 = slim.conv2d(net, depth(192), [1, 1], scope='Conv2d_0a_1x1')
with tf.variable_scope('Branch_1'):
branch_1 = slim.conv2d(net, depth(192), [1, 1], scope='Conv2d_0a_1x1')
branch_1 = slim.conv2d(branch_1, depth(192), [1, 7],
scope='Conv2d_0b_1x7')
branch_1 = slim.conv2d(branch_1, depth(192), [7, 1],
scope='Conv2d_0c_7x1')
with tf.variable_scope('Branch_2'):
branch_2 = slim.conv2d(net, depth(192), [1, 1], scope='Conv2d_0a_1x1')
branch_2 = slim.conv2d(branch_2, depth(192), [7, 1],
scope='Conv2d_0b_7x1')
branch_2 = slim.conv2d(branch_2, depth(192), [1, 7],
scope='Conv2d_0c_1x7')
branch_2 = slim.conv2d(branch_2, depth(192), [7, 1],
scope='Conv2d_0d_7x1')
branch_2 = slim.conv2d(branch_2, depth(192), [1, 7],
scope='Conv2d_0e_1x7')
with tf.variable_scope('Branch_3'):
branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
branch_3 = slim.conv2d(branch_3, depth(192), [1, 1],
scope='Conv2d_0b_1x1')
net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
end_points[end_point] = net
if end_point == final_endpoint: return net, end_points
# mixed_8: 8 x 8 x 1280.
end_point = 'Mixed_7a'
with tf.variable_scope(end_point):
with tf.variable_scope('Branch_0'):
branch_0 = slim.conv2d(net, depth(192), [1, 1], scope='Conv2d_0a_1x1')
branch_0 = slim.conv2d(branch_0, depth(320), [3, 3], stride=2,
padding='VALID', scope='Conv2d_1a_3x3')
with tf.variable_scope('Branch_1'):
branch_1 = slim.conv2d(net, depth(192), [1, 1], scope='Conv2d_0a_1x1')
branch_1 = slim.conv2d(branch_1, depth(192), [1, 7],
scope='Conv2d_0b_1x7')
branch_1 = slim.conv2d(branch_1, depth(192), [7, 1],
scope='Conv2d_0c_7x1')
branch_1 = slim.conv2d(branch_1, depth(192), [3, 3], stride=2,
padding='VALID', scope='Conv2d_1a_3x3')
with tf.variable_scope('Branch_2'):
branch_2 = slim.max_pool2d(net, [3, 3], stride=2, padding='VALID',
scope='MaxPool_1a_3x3')
net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2])
end_points[end_point] = net
if end_point == final_endpoint: return net, end_points
# mixed_9: 8 x 8 x 2048.
end_point = 'Mixed_7b'
with tf.variable_scope(end_point):
with tf.variable_scope('Branch_0'):
branch_0 = slim.conv2d(net, depth(320), [1, 1], scope='Conv2d_0a_1x1')
with tf.variable_scope('Branch_1'):
branch_1 = slim.conv2d(net, depth(384), [1, 1], scope='Conv2d_0a_1x1')
branch_1 = tf.concat(axis=3, values=[
slim.conv2d(branch_1, depth(384), [1, 3], scope='Conv2d_0b_1x3'),
slim.conv2d(branch_1, depth(384), [3, 1], scope='Conv2d_0b_3x1')])
with tf.variable_scope('Branch_2'):
branch_2 = slim.conv2d(net, depth(448), [1, 1], scope='Conv2d_0a_1x1')
branch_2 = slim.conv2d(
branch_2, depth(384), [3, 3], scope='Conv2d_0b_3x3')
branch_2 = tf.concat(axis=3, values=[
slim.conv2d(branch_2, depth(384), [1, 3], scope='Conv2d_0c_1x3'),
slim.conv2d(branch_2, depth(384), [3, 1], scope='Conv2d_0d_3x1')])
with tf.variable_scope('Branch_3'):
branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
branch_3 = slim.conv2d(
branch_3, depth(192), [1, 1], scope='Conv2d_0b_1x1')
net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
end_points[end_point] = net
if end_point == final_endpoint: return net, end_points
# mixed_10: 8 x 8 x 2048.
end_point = 'Mixed_7c'
with tf.variable_scope(end_point):
with tf.variable_scope('Branch_0'):
branch_0 = slim.conv2d(net, depth(320), [1, 1], scope='Conv2d_0a_1x1')
with tf.variable_scope('Branch_1'):
branch_1 = slim.conv2d(net, depth(384), [1, 1], scope='Conv2d_0a_1x1')
branch_1 = tf.concat(axis=3, values=[
slim.conv2d(branch_1, depth(384), [1, 3], scope='Conv2d_0b_1x3'),
slim.conv2d(branch_1, depth(384), [3, 1], scope='Conv2d_0c_3x1')])
with tf.variable_scope('Branch_2'):
branch_2 = slim.conv2d(net, depth(448), [1, 1], scope='Conv2d_0a_1x1')
branch_2 = slim.conv2d(
branch_2, depth(384), [3, 3], scope='Conv2d_0b_3x3')
branch_2 = tf.concat(axis=3, values=[
slim.conv2d(branch_2, depth(384), [1, 3], scope='Conv2d_0c_1x3'),
slim.conv2d(branch_2, depth(384), [3, 1], scope='Conv2d_0d_3x1')])
with tf.variable_scope('Branch_3'):
branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
branch_3 = slim.conv2d(
branch_3, depth(192), [1, 1], scope='Conv2d_0b_1x1')
net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
end_points[end_point] = net
if end_point == final_endpoint: return net, end_points
raise ValueError('Unknown final endpoint %s' % final_endpoint)
def inception_v3(inputs,
num_classes=1000,
is_training=True,
dropout_keep_prob=0.8,
min_depth=16,
depth_multiplier=1.0,
prediction_fn=slim.softmax,
spatial_squeeze=True,
reuse=None,
create_aux_logits=True,
scope='InceptionV3'):
"""Inception model from http://arxiv.org/abs/1512.00567.
"Rethinking the Inception Architecture for Computer Vision"
Christian Szegedy, Vincent Vanhoucke, Sergey Ioffe, Jonathon Shlens,
Zbigniew Wojna.
With the default arguments this method constructs the exact model defined in
the paper. However, one can experiment with variations of the inception_v3
network by changing arguments dropout_keep_prob, min_depth and
depth_multiplier.
The default image size used to train this network is 299x299.
Args:
inputs: a tensor of size [batch_size, height, width, channels].
num_classes: number of predicted classes.
is_training: whether is training or not.
dropout_keep_prob: the percentage of activation values that are retained.
min_depth: Minimum depth value (number of channels) for all convolution ops.
Enforced when depth_multiplier < 1, and not an active constraint when
depth_multiplier >= 1.
depth_multiplier: Float multiplier for the depth (number of channels)
for all convolution ops. The value must be greater than zero. Typical
usage will be to set this value in (0, 1) to reduce the number of
parameters or computation cost of the model.
prediction_fn: a function to get predictions out of logits.
spatial_squeeze: if True, logits is of shape [B, C], if false logits is of
shape [B, 1, 1, C], where B is batch_size and C is number of classes.
reuse: whether or not the network and its variables should be reused. To be
able to reuse 'scope' must be given.
create_aux_logits: Whether to create the auxiliary logits.
scope: Optional variable_scope.
Returns:
logits: the pre-softmax activations, a tensor of size
[batch_size, num_classes]
end_points: a dictionary from components of the network to the corresponding
activation.
Raises:
ValueError: if 'depth_multiplier' is less than or equal to zero.
"""
if depth_multiplier <= 0:
raise ValueError('depth_multiplier is not greater than zero.')
depth = lambda d: max(int(d * depth_multiplier), min_depth)
with tf.variable_scope(scope, 'InceptionV3', [inputs, num_classes],
reuse=reuse) as scope:
with slim.arg_scope([slim.batch_norm, slim.dropout],
is_training=is_training):
net, end_points = inception_v3_base(
inputs, scope=scope, min_depth=min_depth,
depth_multiplier=depth_multiplier)
# Auxiliary Head logits
if create_aux_logits:
with slim.arg_scope([slim.conv2d, slim.max_pool2d, slim.avg_pool2d],
stride=1, padding='SAME'):
aux_logits = end_points['Mixed_6e']
with tf.variable_scope('AuxLogits'):
aux_logits = slim.avg_pool2d(
aux_logits, [5, 5], stride=3, padding='VALID',
scope='AvgPool_1a_5x5')
aux_logits = slim.conv2d(aux_logits, depth(128), [1, 1],
scope='Conv2d_1b_1x1')
# Shape of feature map before the final layer.
kernel_size = _reduced_kernel_size_for_small_input(
aux_logits, [5, 5])
aux_logits = slim.conv2d(
aux_logits, depth(768), kernel_size,
weights_initializer=trunc_normal(0.01),
padding='VALID', scope='Conv2d_2a_{}x{}'.format(*kernel_size))
aux_logits = slim.conv2d(
aux_logits, num_classes, [1, 1], activation_fn=None,
normalizer_fn=None, weights_initializer=trunc_normal(0.001),
scope='Conv2d_2b_1x1')
if spatial_squeeze:
aux_logits = tf.squeeze(aux_logits, [1, 2], name='SpatialSqueeze')
end_points['AuxLogits'] = aux_logits
# Final pooling and prediction
with tf.variable_scope('Logits'):
kernel_size = _reduced_kernel_size_for_small_input(net, [8, 8])
net = slim.avg_pool2d(net, kernel_size, padding='VALID',
scope='AvgPool_1a_{}x{}'.format(*kernel_size))
# 1 x 1 x 2048
net = slim.dropout(net, keep_prob=dropout_keep_prob, scope='Dropout_1b')
end_points['PreLogits'] = net
# 2048
logits = slim.conv2d(net, num_classes, [1, 1], activation_fn=None,
normalizer_fn=None, scope='Conv2d_1c_1x1')
if spatial_squeeze:
logits = tf.squeeze(logits, [1, 2], name='SpatialSqueeze')
# 1000
end_points['Logits'] = logits
end_points['Predictions'] = prediction_fn(logits, scope='Predictions')
return logits, end_points
inception_v3.default_image_size = 299
def _reduced_kernel_size_for_small_input(input_tensor, kernel_size):
"""Define kernel size which is automatically reduced for small input.
If the shape of the input images is unknown at graph construction time this
function assumes that the input images are is large enough.
Args:
input_tensor: input tensor of size [batch_size, height, width, channels].
kernel_size: desired kernel size of length 2: [kernel_height, kernel_width]
Returns:
a tensor with the kernel size.
TODO(jrru): Make this function work with unknown shapes. Theoretically, this
can be done with the code below. Problems are two-fold: (1) If the shape was
known, it will be lost. (2) inception.slim.ops._two_element_tuple cannot
handle tensors that define the kernel size.
shape = tf.shape(input_tensor)
return = tf.stack([tf.minimum(shape[1], kernel_size[0]),
tf.minimum(shape[2], kernel_size[1])])
"""
shape = input_tensor.get_shape().as_list()
if shape[1] is None or shape[2] is None:
kernel_size_out = kernel_size
else:
kernel_size_out = [min(shape[1], kernel_size[0]),
min(shape[2], kernel_size[1])]
return kernel_size_out
inception_v3_arg_scope = inception_utils.inception_arg_scope
================================================
FILE: nets/inception_v3_test.py
================================================
# Copyright 2016 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Tests for nets.inception_v1."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import numpy as np
import tensorflow as tf
from nets import inception
slim = tf.contrib.slim
class InceptionV3Test(tf.test.TestCase):
def testBuildClassificationNetwork(self):
batch_size = 5
height, width = 299, 299
num_classes = 1000
inputs = tf.random_uniform((batch_size, height, width, 3))
logits, end_points = inception.inception_v3(inputs, num_classes)
self.assertTrue(logits.op.name.startswith('InceptionV3/Logits'))
self.assertListEqual(logits.get_shape().as_list(),
[batch_size, num_classes])
self.assertTrue('Predictions' in end_points)
self.assertListEqual(end_points['Predictions'].get_shape().as_list(),
[batch_size, num_classes])
def testBuildBaseNetwork(self):
batch_size = 5
height, width = 299, 299
inputs = tf.random_uniform((batch_size, height, width, 3))
final_endpoint, end_points = inception.inception_v3_base(inputs)
self.assertTrue(final_endpoint.op.name.startswith(
'InceptionV3/Mixed_7c'))
self.assertListEqual(final_endpoint.get_shape().as_list(),
[batch_size, 8, 8, 2048])
expected_endpoints = ['Conv2d_1a_3x3', 'Conv2d_2a_3x3', 'Conv2d_2b_3x3',
'MaxPool_3a_3x3', 'Conv2d_3b_1x1', 'Conv2d_4a_3x3',
'MaxPool_5a_3x3', 'Mixed_5b', 'Mixed_5c', 'Mixed_5d',
'Mixed_6a', 'Mixed_6b', 'Mixed_6c', 'Mixed_6d',
'Mixed_6e', 'Mixed_7a', 'Mixed_7b', 'Mixed_7c']
self.assertItemsEqual(end_points.keys(), expected_endpoints)
def testBuildOnlyUptoFinalEndpoint(self):
batch_size = 5
height, width = 299, 299
endpoints = ['Conv2d_1a_3x3', 'Conv2d_2a_3x3', 'Conv2d_2b_3x3',
'MaxPool_3a_3x3', 'Conv2d_3b_1x1', 'Conv2d_4a_3x3',
'MaxPool_5a_3x3', 'Mixed_5b', 'Mixed_5c', 'Mixed_5d',
'Mixed_6a', 'Mixed_6b', 'Mixed_6c', 'Mixed_6d',
'Mixed_6e', 'Mixed_7a', 'Mixed_7b', 'Mixed_7c']
for index, endpoint in enumerate(endpoints):
with tf.Graph().as_default():
inputs = tf.random_uniform((batch_size, height, width, 3))
out_tensor, end_points = inception.inception_v3_base(
inputs, final_endpoint=endpoint)
self.assertTrue(out_tensor.op.name.startswith(
'InceptionV3/' + endpoint))
self.assertItemsEqual(endpoints[:index+1], end_points)
def testBuildAndCheckAllEndPointsUptoMixed7c(self):
batch_size = 5
height, width = 299, 299
inputs = tf.random_uniform((batch_size, height, width, 3))
_, end_points = inception.inception_v3_base(
inputs, final_endpoint='Mixed_7c')
endpoints_shapes = {'Conv2d_1a_3x3': [batch_size, 149, 149, 32],
'Conv2d_2a_3x3': [batch_size, 147, 147, 32],
'Conv2d_2b_3x3': [batch_size, 147, 147, 64],
'MaxPool_3a_3x3': [batch_size, 73, 73, 64],
'Conv2d_3b_1x1': [batch_size, 73, 73, 80],
'Conv2d_4a_3x3': [batch_size, 71, 71, 192],
'MaxPool_5a_3x3': [batch_size, 35, 35, 192],
'Mixed_5b': [batch_size, 35, 35, 256],
'Mixed_5c': [batch_size, 35, 35, 288],
'Mixed_5d': [batch_size, 35, 35, 288],
'Mixed_6a': [batch_size, 17, 17, 768],
'Mixed_6b': [batch_size, 17, 17, 768],
'Mixed_6c': [batch_size, 17, 17, 768],
'Mixed_6d': [batch_size, 17, 17, 768],
'Mixed_6e': [batch_size, 17, 17, 768],
'Mixed_7a': [batch_size, 8, 8, 1280],
'Mixed_7b': [batch_size, 8, 8, 2048],
'Mixed_7c': [batch_size, 8, 8, 2048]}
self.assertItemsEqual(endpoints_shapes.keys(), end_points.keys())
for endpoint_name in endpoints_shapes:
expected_shape = endpoints_shapes[endpoint_name]
self.assertTrue(endpoint_name in end_points)
self.assertListEqual(end_points[endpoint_name].get_shape().as_list(),
expected_shape)
def testModelHasExpectedNumberOfParameters(self):
batch_size = 5
height, width = 299, 299
inputs = tf.random_uniform((batch_size, height, width, 3))
with slim.arg_scope(inception.inception_v3_arg_scope()):
inception.inception_v3_base(inputs)
total_params, _ = slim.model_analyzer.analyze_vars(
slim.get_model_variables())
self.assertAlmostEqual(21802784, total_params)
def testBuildEndPoints(self):
batch_size = 5
height, width = 299, 299
num_classes = 1000
inputs = tf.random_uniform((batch_size, height, width, 3))
_, end_points = inception.inception_v3(inputs, num_classes)
self.assertTrue('Logits' in end_points)
logits = end_points['Logits']
self.assertListEqual(logits.get_shape().as_list(),
[batch_size, num_classes])
self.assertTrue('AuxLogits' in end_points)
aux_logits = end_points['AuxLogits']
self.assertListEqual(aux_logits.get_shape().as_list(),
[batch_size, num_classes])
self.assertTrue('Mixed_7c' in end_points)
pre_pool = end_points['Mixed_7c']
self.assertListEqual(pre_pool.get_shape().as_list(),
[batch_size, 8, 8, 2048])
self.assertTrue('PreLogits' in end_points)
pre_logits = end_points['PreLogits']
self.assertListEqual(pre_logits.get_shape().as_list(),
[batch_size, 1, 1, 2048])
def testBuildEndPointsWithDepthMultiplierLessThanOne(self):
batch_size = 5
height, width = 299, 299
num_classes = 1000
inputs = tf.random_uniform((batch_size, height, width, 3))
_, end_points = inception.inception_v3(inputs, num_classes)
endpoint_keys = [key for key in end_points.keys()
if key.startswith('Mixed') or key.startswith('Conv')]
_, end_points_with_multiplier = inception.inception_v3(
inputs, num_classes, scope='depth_multiplied_net',
depth_multiplier=0.5)
for key in endpoint_keys:
original_depth = end_points[key].get_shape().as_list()[3]
new_depth = end_points_with_multiplier[key].get_shape().as_list()[3]
self.assertEqual(0.5 * original_depth, new_depth)
def testBuildEndPointsWithDepthMultiplierGreaterThanOne(self):
batch_size = 5
height, width = 299, 299
num_classes = 1000
inputs = tf.random_uniform((batch_size, height, width, 3))
_, end_points = inception.inception_v3(inputs, num_classes)
endpoint_keys = [key for key in end_points.keys()
if key.startswith('Mixed') or key.startswith('Conv')]
_, end_points_with_multiplier = inception.inception_v3(
inputs, num_classes, scope='depth_multiplied_net',
depth_multiplier=2.0)
for key in endpoint_keys:
original_depth = end_points[key].get_shape().as_list()[3]
new_depth = end_points_with_multiplier[key].get_shape().as_list()[3]
self.assertEqual(2.0 * original_depth, new_depth)
def testRaiseValueErrorWithInvalidDepthMultiplier(self):
batch_size = 5
height, width = 299, 299
num_classes = 1000
inputs = tf.random_uniform((batch_size, height, width, 3))
with self.assertRaises(ValueError):
_ = inception.inception_v3(inputs, num_classes, depth_multiplier=-0.1)
with self.assertRaises(ValueError):
_ = inception.inception_v3(inputs, num_classes, depth_multiplier=0.0)
def testHalfSizeImages(self):
batch_size = 5
height, width = 150, 150
num_classes = 1000
inputs = tf.random_uniform((batch_size, height, width, 3))
logits, end_points = inception.inception_v3(inputs, num_classes)
self.assertTrue(logits.op.name.startswith('InceptionV3/Logits'))
self.assertListEqual(logits.get_shape().as_list(),
[batch_size, num_classes])
pre_pool = end_points['Mixed_7c']
self.assertListEqual(pre_pool.get_shape().as_list(),
[batch_size, 3, 3, 2048])
def testUnknownImageShape(self):
tf.reset_default_graph()
batch_size = 2
height, width = 299, 299
num_classes = 1000
input_np = np.random.uniform(0, 1, (batch_size, height, width, 3))
with self.test_session() as sess:
inputs = tf.placeholder(tf.float32, shape=(batch_size, None, None, 3))
logits, end_points = inception.inception_v3(inputs, num_classes)
self.assertListEqual(logits.get_shape().as_list(),
[batch_size, num_classes])
pre_pool = end_points['Mixed_7c']
feed_dict = {inputs: input_np}
tf.global_variables_initializer().run()
pre_pool_out = sess.run(pre_pool, feed_dict=feed_dict)
self.assertListEqual(list(pre_pool_out.shape), [batch_size, 8, 8, 2048])
def testUnknowBatchSize(self):
batch_size = 1
height, width = 299, 299
num_classes = 1000
inputs = tf.placeholder(tf.float32, (None, height, width, 3))
logits, _ = inception.inception_v3(inputs, num_classes)
self.assertTrue(logits.op.name.startswith('InceptionV3/Logits'))
self.assertListEqual(logits.get_shape().as_list(),
[None, num_classes])
images = tf.random_uniform((batch_size, height, width, 3))
with self.test_session() as sess:
sess.run(tf.global_variables_initializer())
output = sess.run(logits, {inputs: images.eval()})
self.assertEquals(output.shape, (batch_size, num_classes))
def testEvaluation(self):
batch_size = 2
height, width = 299, 299
num_classes = 1000
eval_inputs = tf.random_uniform((batch_size, height, width, 3))
logits, _ = inception.inception_v3(eval_inputs, num_classes,
is_training=False)
predictions = tf.argmax(logits, 1)
with self.test_session() as sess:
sess.run(tf.global_variables_initializer())
output = sess.run(predictions)
self.assertEquals(output.shape, (batch_size,))
def testTrainEvalWithReuse(self):
train_batch_size = 5
eval_batch_size = 2
height, width = 150, 150
num_classes = 1000
train_inputs = tf.random_uniform((train_batch_size, height, width, 3))
inception.inception_v3(train_inputs, num_classes)
eval_inputs = tf.random_uniform((eval_batch_size, height, width, 3))
logits, _ = inception.inception_v3(eval_inputs, num_classes,
is_training=False, reuse=True)
predictions = tf.argmax(logits, 1)
with self.test_session() as sess:
sess.run(tf.global_variables_initializer())
output = sess.run(predictions)
self.assertEquals(output.shape, (eval_batch_size,))
def testLogitsNotSqueezed(self):
num_classes = 25
images = tf.random_uniform([1, 299, 299, 3])
logits, _ = inception.inception_v3(images,
num_classes=num_classes,
spatial_squeeze=False)
with self.test_session() as sess:
tf.global_variables_initializer().run()
logits_out = sess.run(logits)
self.assertListEqual(list(logits_out.shape), [1, 1, 1, num_classes])
if __name__ == '__main__':
tf.test.main()
================================================
FILE: nets/inception_v4.py
================================================
# Copyright 2016 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Contains the definition of the Inception V4 architecture.
As described in http://arxiv.org/abs/1602.07261.
Inception-v4, Inception-ResNet and the Impact of Residual Connections
on Learning
Christian Szegedy, Sergey Ioffe, Vincent Vanhoucke, Alex Alemi
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import tensorflow as tf
from nets import inception_utils
slim = tf.contrib.slim
def block_inception_a(inputs, scope=None, reuse=None):
"""Builds Inception-A block for Inception v4 network."""
# By default use stride=1 and SAME padding
with slim.arg_scope([slim.conv2d, slim.avg_pool2d, slim.max_pool2d],
stride=1, padding='SAME'):
with tf.variable_scope(scope, 'BlockInceptionA', [inputs], reuse=reuse):
with tf.variable_scope('Branch_0'):
branch_0 = slim.conv2d(inputs, 96, [1, 1], scope='Conv2d_0a_1x1')
with tf.variable_scope('Branch_1'):
branch_1 = slim.conv2d(inputs, 64, [1, 1], scope='Conv2d_0a_1x1')
branch_1 = slim.conv2d(branch_1, 96, [3, 3], scope='Conv2d_0b_3x3')
with tf.variable_scope('Branch_2'):
branch_2 = slim.conv2d(inputs, 64, [1, 1], scope='Conv2d_0a_1x1')
branch_2 = slim.conv2d(branch_2, 96, [3, 3], scope='Conv2d_0b_3x3')
branch_2 = slim.conv2d(branch_2, 96, [3, 3], scope='Conv2d_0c_3x3')
with tf.variable_scope('Branch_3'):
branch_3 = slim.avg_pool2d(inputs, [3, 3], scope='AvgPool_0a_3x3')
branch_3 = slim.conv2d(branch_3, 96, [1, 1], scope='Conv2d_0b_1x1')
return tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
def block_reduction_a(inputs, scope=None, reuse=None):
"""Builds Reduction-A block for Inception v4 network."""
# By default use stride=1 and SAME padding
with slim.arg_scope([slim.conv2d, slim.avg_pool2d, slim.max_pool2d],
stride=1, padding='SAME'):
with tf.variable_scope(scope, 'BlockReductionA', [inputs], reuse=reuse):
with tf.variable_scope('Branch_0'):
branch_0 = slim.conv2d(inputs, 384, [3, 3], stride=2, padding='VALID',
scope='Conv2d_1a_3x3')
with tf.variable_scope('Branch_1'):
branch_1 = slim.conv2d(inputs, 192, [1, 1], scope='Conv2d_0a_1x1')
branch_1 = slim.conv2d(branch_1, 224, [3, 3], scope='Conv2d_0b_3x3')
branch_1 = slim.conv2d(branch_1, 256, [3, 3], stride=2,
padding='VALID', scope='Conv2d_1a_3x3')
with tf.variable_scope('Branch_2'):
branch_2 = slim.max_pool2d(inputs, [3, 3], stride=2, padding='VALID',
scope='MaxPool_1a_3x3')
return tf.concat(axis=3, values=[branch_0, branch_1, branch_2])
def block_inception_b(inputs, scope=None, reuse=None):
"""Builds Inception-B block for Inception v4 network."""
# By default use stride=1 and SAME padding
with slim.arg_scope([slim.conv2d, slim.avg_pool2d, slim.max_pool2d],
stride=1, padding='SAME'):
with tf.variable_scope(scope, 'BlockInceptionB', [inputs], reuse=reuse):
with tf.variable_scope('Branch_0'):
branch_0 = slim.conv2d(inputs, 384, [1, 1], scope='Conv2d_0a_1x1')
with tf.variable_scope('Branch_1'):
branch_1 = slim.conv2d(inputs, 192, [1, 1], scope='Conv2d_0a_1x1')
branch_1 = slim.conv2d(branch_1, 224, [1, 7], scope='Conv2d_0b_1x7')
branch_1 = slim.conv2d(branch_1, 256, [7, 1], scope='Conv2d_0c_7x1')
with tf.variable_scope('Branch_2'):
branch_2 = slim.conv2d(inputs, 192, [1, 1], scope='Conv2d_0a_1x1')
branch_2 = slim.conv2d(branch_2, 192, [7, 1], scope='Conv2d_0b_7x1')
branch_2 = slim.conv2d(branch_2, 224, [1, 7], scope='Conv2d_0c_1x7')
branch_2 = slim.conv2d(branch_2, 224, [7, 1], scope='Conv2d_0d_7x1')
branch_2 = slim.conv2d(branch_2, 256, [1, 7], scope='Conv2d_0e_1x7')
with tf.variable_scope('Branch_3'):
branch_3 = slim.avg_pool2d(inputs, [3, 3], scope='AvgPool_0a_3x3')
branch_3 = slim.conv2d(branch_3, 128, [1, 1], scope='Conv2d_0b_1x1')
return tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
def block_reduction_b(inputs, scope=None, reuse=None):
"""Builds Reduction-B block for Inception v4 network."""
# By default use stride=1 and SAME padding
with slim.arg_scope([slim.conv2d, slim.avg_pool2d, slim.max_pool2d],
stride=1, padding='SAME'):
with tf.variable_scope(scope, 'BlockReductionB', [inputs], reuse=reuse):
with tf.variable_scope('Branch_0'):
branch_0 = slim.conv2d(inputs, 192, [1, 1], scope='Conv2d_0a_1x1')
branch_0 = slim.conv2d(branch_0, 192, [3, 3], stride=2,
padding='VALID', scope='Conv2d_1a_3x3')
with tf.variable_scope('Branch_1'):
branch_1 = slim.conv2d(inputs, 256, [1, 1], scope='Conv2d_0a_1x1')
branch_1 = slim.conv2d(branch_1, 256, [1, 7], scope='Conv2d_0b_1x7')
branch_1 = slim.conv2d(branch_1, 320, [7, 1], scope='Conv2d_0c_7x1')
branch_1 = slim.conv2d(branch_1, 320, [3, 3], stride=2,
padding='VALID', scope='Conv2d_1a_3x3')
with tf.variable_scope('Branch_2'):
branch_2 = slim.max_pool2d(inputs, [3, 3], stride=2, padding='VALID',
scope='MaxPool_1a_3x3')
return tf.concat(axis=3, values=[branch_0, branch_1, branch_2])
def block_inception_c(inputs, scope=None, reuse=None):
"""Builds Inception-C block for Inception v4 network."""
# By default use stride=1 and SAME padding
with slim.arg_scope([slim.conv2d, slim.avg_pool2d, slim.max_pool2d],
stride=1, padding='SAME'):
with tf.variable_scope(scope, 'BlockInceptionC', [inputs], reuse=reuse):
with tf.variable_scope('Branch_0'):
branch_0 = slim.conv2d(inputs, 256, [1, 1], scope='Conv2d_0a_1x1')
with tf.variable_scope('Branch_1'):
branch_1 = slim.conv2d(inputs, 384, [1, 1], scope='Conv2d_0a_1x1')
branch_1 = tf.concat(axis=3, values=[
slim.conv2d(branch_1, 256, [1, 3], scope='Conv2d_0b_1x3'),
slim.conv2d(branch_1, 256, [3, 1], scope='Conv2d_0c_3x1')])
with tf.variable_scope('Branch_2'):
branch_2 = slim.conv2d(inputs, 384, [1, 1], scope='Conv2d_0a_1x1')
branch_2 = slim.conv2d(branch_2, 448, [3, 1], scope='Conv2d_0b_3x1')
branch_2 = slim.conv2d(branch_2, 512, [1, 3], scope='Conv2d_0c_1x3')
branch_2 = tf.concat(axis=3, values=[
slim.conv2d(branch_2, 256, [1, 3], scope='Conv2d_0d_1x3'),
slim.conv2d(branch_2, 256, [3, 1], scope='Conv2d_0e_3x1')])
with tf.variable_scope('Branch_3'):
branch_3 = slim.avg_pool2d(inputs, [3, 3], scope='AvgPool_0a_3x3')
branch_3 = slim.conv2d(branch_3, 256, [1, 1], scope='Conv2d_0b_1x1')
return tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
def inception_v4_base(inputs, final_endpoint='Mixed_7d', scope=None):
"""Creates the Inception V4 network up to the given final endpoint.
Args:
inputs: a 4-D tensor of size [batch_size, height, width, 3].
final_endpoint: specifies the endpoint to construct the network up to.
It can be one of [ 'Conv2d_1a_3x3', 'Conv2d_2a_3x3', 'Conv2d_2b_3x3',
'Mixed_3a', 'Mixed_4a', 'Mixed_5a', 'Mixed_5b', 'Mixed_5c', 'Mixed_5d',
'Mixed_5e', 'Mixed_6a', 'Mixed_6b', 'Mixed_6c', 'Mixed_6d', 'Mixed_6e',
'Mixed_6f', 'Mixed_6g', 'Mixed_6h', 'Mixed_7a', 'Mixed_7b', 'Mixed_7c',
'Mixed_7d']
scope: Optional variable_scope.
Returns:
logits: the logits outputs of the model.
end_points: the set of end_points from the inception model.
Raises:
ValueError: if final_endpoint is not set to one of the predefined values,
"""
end_points = {}
def add_and_check_final(name, net):
end_points[name] = net
return name == final_endpoint
with tf.variable_scope(scope, 'InceptionV4', [inputs]):
with slim.arg_scope([slim.conv2d, slim.max_pool2d, slim.avg_pool2d],
stride=1, padding='SAME'):
# 299 x 299 x 3
net = slim.conv2d(inputs, 32, [3, 3], stride=2,
padding='VALID', scope='Conv2d_1a_3x3')
if add_and_check_final('Conv2d_1a_3x3', net): return net, end_points
# 149 x 149 x 32
net = slim.conv2d(net, 32, [3, 3], padding='VALID',
scope='Conv2d_2a_3x3')
if add_and_check_final('Conv2d_2a_3x3', net): return net, end_points
# 147 x 147 x 32
net = slim.conv2d(net, 64, [3, 3], scope='Conv2d_2b_3x3')
if add_and_check_final('Conv2d_2b_3x3', net): return net, end_points
# 147 x 147 x 64
with tf.variable_scope('Mixed_3a'):
with tf.variable_scope('Branch_0'):
branch_0 = slim.max_pool2d(net, [3, 3], stride=2, padding='VALID',
scope='MaxPool_0a_3x3')
with tf.variable_scope('Branch_1'):
branch_1 = slim.conv2d(net, 96, [3, 3], stride=2, padding='VALID',
scope='Conv2d_0a_3x3')
net = tf.concat(axis=3, values=[branch_0, branch_1])
if add_and_check_final('Mixed_3a', net): return net, end_points
# 73 x 73 x 160
with tf.variable_scope('Mixed_4a'):
with tf.variable_scope('Branch_0'):
branch_0 = slim.conv2d(net, 64, [1, 1], scope='Conv2d_0a_1x1')
branch_0 = slim.conv2d(branch_0, 96, [3, 3], padding='VALID',
scope='Conv2d_1a_3x3')
with tf.variable_scope('Branch_1'):
branch_1 = slim.conv2d(net, 64, [1, 1], scope='Conv2d_0a_1x1')
branch_1 = slim.conv2d(branch_1, 64, [1, 7], scope='Conv2d_0b_1x7')
branch_1 = slim.conv2d(branch_1, 64, [7, 1], scope='Conv2d_0c_7x1')
branch_1 = slim.conv2d(branch_1, 96, [3, 3], padding='VALID',
scope='Conv2d_1a_3x3')
net = tf.concat(axis=3, values=[branch_0, branch_1])
if add_and_check_final('Mixed_4a', net): return net, end_points
# 71 x 71 x 192
with tf.variable_scope('Mixed_5a'):
with tf.variable_scope('Branch_0'):
branch_0 = slim.conv2d(net, 192, [3, 3], stride=2, padding='VALID',
scope='Conv2d_1a_3x3')
with tf.variable_scope('Branch_1'):
branch_1 = slim.max_pool2d(net, [3, 3], stride=2, padding='VALID',
scope='MaxPool_1a_3x3')
net = tf.concat(axis=3, values=[branch_0, branch_1])
if add_and_check_final('Mixed_5a', net): return net, end_points
# 35 x 35 x 384
# 4 x Inception-A blocks
for idx in range(4):
block_scope = 'Mixed_5' + chr(ord('b') + idx)
net = block_inception_a(net, block_scope)
if add_and_check_final(block_scope, net): return net, end_points
# 35 x 35 x 384
# Reduction-A block
net = block_reduction_a(net, 'Mixed_6a')
if add_and_check_final('Mixed_6a', net): return net, end_points
# 17 x 17 x 1024
# 7 x Inception-B blocks
for idx in range(7):
block_scope = 'Mixed_6' + chr(ord('b') + idx)
net = block_inception_b(net, block_scope)
if add_and_check_final(block_scope, net): return net, end_points
# 17 x 17 x 1024
# Reduction-B block
net = block_reduction_b(net, 'Mixed_7a')
if add_and_check_final('Mixed_7a', net): return net, end_points
# 8 x 8 x 1536
# 3 x Inception-C blocks
for idx in range(3):
block_scope = 'Mixed_7' + chr(ord('b') + idx)
net = block_inception_c(net, block_scope)
if add_and_check_final(block_scope, net): return net, end_points
raise ValueError('Unknown final endpoint %s' % final_endpoint)
def inception_v4(inputs, num_classes=1001, is_training=True,
dropout_keep_prob=0.8,
reuse=None,
scope='InceptionV4',
create_aux_logits=True):
"""Creates the Inception V4 model.
Args:
inputs: a 4-D tensor of size [batch_size, height, width, 3].
num_classes: number of predicted classes.
is_training: whether is training or not.
dropout_keep_prob: float, the fraction to keep before final layer.
reuse: whether or not the network and its variables should be reused. To be
able to reuse 'scope' must be given.
scope: Optional variable_scope.
create_aux_logits: Whether to include the auxiliary logits.
Returns:
logits: the logits outputs of the model.
end_points: the set of end_points from the inception model.
"""
end_points = {}
with tf.variable_scope(scope, 'InceptionV4', [inputs], reuse=reuse) as scope:
with slim.arg_scope([slim.batch_norm, slim.dropout],
is_training=is_training):
net, end_points = inception_v4_base(inputs, scope=scope)
with slim.arg_scope([slim.conv2d, slim.max_pool2d, slim.avg_pool2d],
stride=1, padding='SAME'):
# Auxiliary Head logits
if create_aux_logits:
with tf.variable_scope('AuxLogits'):
# 17 x 17 x 1024
aux_logits = end_points['Mixed_6h']
aux_logits = slim.avg_pool2d(aux_logits, [5, 5], stride=3,
padding='VALID',
scope='AvgPool_1a_5x5')
aux_logits = slim.conv2d(aux_logits, 128, [1, 1],
scope='Conv2d_1b_1x1')
aux_logits = slim.conv2d(aux_logits, 768,
[5, 5],
padding='VALID', scope='Conv2d_2a')
aux_logits = tf.reshape(aux_logits, [aux_logits.get_shape()[0], aux_logits.get_shape()[-1]])
aux_logits = slim.fully_connected(aux_logits, num_classes,
activation_fn=None,
scope='Aux_logits')
end_points['AuxLogits'] = aux_logits
# Final pooling and prediction
with tf.variable_scope('Logits'):
# 8 x 8 x 1536
net = slim.avg_pool2d(net, [8, 8], padding='VALID',
scope='AvgPool_1a')
# 1 x 1 x 1536
net = slim.dropout(net, dropout_keep_prob, scope='Dropout_1b')
net = tf.reshape(net, [net.get_shape()[0], net.get_shape()[-1]])
end_points['PreLogitsFlatten'] = net
# 1536
logits = slim.fully_connected(net, num_classes, activation_fn=None,
scope='Logits')
end_points['Logits'] = logits
end_points['Predictions'] = tf.nn.softmax(logits, name='Predictions')
return logits, end_points
inception_v4.default_image_size = 299
inception_v4_arg_scope = inception_utils.inception_arg_scope
================================================
FILE: nets/inception_v4_test.py
================================================
# Copyright 2016 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Tests for slim.inception_v4."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import tensorflow as tf
from nets import inception
class InceptionTest(tf.test.TestCase):
def testBuildLogits(self):
batch_size = 5
height, width = 299, 299
num_classes = 1000
inputs = tf.random_uniform((batch_size, height, width, 3))
logits, end_points = inception.inception_v4(inputs, num_classes)
auxlogits = end_points['AuxLogits']
predictions = end_points['Predictions']
self.assertTrue(auxlogits.op.name.startswith('InceptionV4/AuxLogits'))
self.assertListEqual(auxlogits.get_shape().as_list(),
[batch_size, num_classes])
self.assertTrue(logits.op.name.startswith('InceptionV4/Logits'))
self.assertListEqual(logits.get_shape().as_list(),
[batch_size, num_classes])
self.assertTrue(predictions.op.name.startswith(
'InceptionV4/Logits/Predictions'))
self.assertListEqual(predictions.get_shape().as_list(),
[batch_size, num_classes])
def testBuildWithoutAuxLogits(self):
batch_size = 5
height, width = 299, 299
num_classes = 1000
inputs = tf.random_uniform((batch_size, height, width, 3))
logits, endpoints = inception.inception_v4(inputs, num_classes,
create_aux_logits=False)
self.assertFalse('AuxLogits' in endpoints)
self.assertTrue(logits.op.name.startswith('InceptionV4/Logits'))
self.assertListEqual(logits.get_shape().as_list(),
[batch_size, num_classes])
def testAllEndPointsShapes(self):
batch_size = 5
height, width = 299, 299
num_classes = 1000
inputs = tf.random_uniform((batch_size, height, width, 3))
_, end_points = inception.inception_v4(inputs, num_classes)
endpoints_shapes = {'Conv2d_1a_3x3': [batch_size, 149, 149, 32],
'Conv2d_2a_3x3': [batch_size, 147, 147, 32],
'Conv2d_2b_3x3': [batch_size, 147, 147, 64],
'Mixed_3a': [batch_size, 73, 73, 160],
'Mixed_4a': [batch_size, 71, 71, 192],
'Mixed_5a': [batch_size, 35, 35, 384],
# 4 x Inception-A blocks
'Mixed_5b': [batch_size, 35, 35, 384],
'Mixed_5c': [batch_size, 35, 35, 384],
'Mixed_5d': [batch_size, 35, 35, 384],
'Mixed_5e': [batch_size, 35, 35, 384],
# Reduction-A block
'Mixed_6a': [batch_size, 17, 17, 1024],
# 7 x Inception-B blocks
'Mixed_6b': [batch_size, 17, 17, 1024],
'Mixed_6c': [batch_size, 17, 17, 1024],
'Mixed_6d': [batch_size, 17, 17, 1024],
'Mixed_6e': [batch_size, 17, 17, 1024],
'Mixed_6f': [batch_size, 17, 17, 1024],
'Mixed_6g': [batch_size, 17, 17, 1024],
'Mixed_6h': [batch_size, 17, 17, 1024],
# Reduction-A block
'Mixed_7a': [batch_size, 8, 8, 1536],
# 3 x Inception-C blocks
'Mixed_7b': [batch_size, 8, 8, 1536],
'Mixed_7c': [batch_size, 8, 8, 1536],
'Mixed_7d': [batch_size, 8, 8, 1536],
# Logits and predictions
'AuxLogits': [batch_size, num_classes],
'PreLogitsFlatten': [batch_size, 1536],
'Logits': [batch_size, num_classes],
'Predictions': [batch_size, num_classes]}
self.assertItemsEqual(endpoints_shapes.keys(), end_points.keys())
for endpoint_name in endpoints_shapes:
expected_shape = endpoints_shapes[endpoint_name]
self.assertTrue(endpoint_name in end_points)
self.assertListEqual(end_points[endpoint_name].get_shape().as_list(),
expected_shape)
def testBuildBaseNetwork(self):
batch_size = 5
height, width = 299, 299
inputs = tf.random_uniform((batch_size, height, width, 3))
net, end_points = inception.inception_v4_base(inputs)
self.assertTrue(net.op.name.startswith(
'InceptionV4/Mixed_7d'))
self.assertListEqual(net.get_shape().as_list(), [batch_size, 8, 8, 1536])
expected_endpoints = [
'Conv2d_1a_3x3', 'Conv2d_2a_3x3', 'Conv2d_2b_3x3', 'Mixed_3a',
'Mixed_4a', 'Mixed_5a', 'Mixed_5b', 'Mixed_5c', 'Mixed_5d',
'Mixed_5e', 'Mixed_6a', 'Mixed_6b', 'Mixed_6c', 'Mixed_6d',
'Mixed_6e', 'Mixed_6f', 'Mixed_6g', 'Mixed_6h', 'Mixed_7a',
'Mixed_7b', 'Mixed_7c', 'Mixed_7d']
self.assertItemsEqual(end_points.keys(), expected_endpoints)
for name, op in end_points.iteritems():
self.assertTrue(op.name.startswith('InceptionV4/' + name))
def testBuildOnlyUpToFinalEndpoint(self):
batch_size = 5
height, width = 299, 299
all_endpoints = [
'Conv2d_1a_3x3', 'Conv2d_2a_3x3', 'Conv2d_2b_3x3', 'Mixed_3a',
'Mixed_4a', 'Mixed_5a', 'Mixed_5b', 'Mixed_5c', 'Mixed_5d',
'Mixed_5e', 'Mixed_6a', 'Mixed_6b', 'Mixed_6c', 'Mixed_6d',
'Mixed_6e', 'Mixed_6f', 'Mixed_6g', 'Mixed_6h', 'Mixed_7a',
'Mixed_7b', 'Mixed_7c', 'Mixed_7d']
for index, endpoint in enumerate(all_endpoints):
with tf.Graph().as_default():
inputs = tf.random_uniform((batch_size, height, width, 3))
out_tensor, end_points = inception.inception_v4_base(
inputs, final_endpoint=endpoint)
self.assertTrue(out_tensor.op.name.startswith(
'InceptionV4/' + endpoint))
self.assertItemsEqual(all_endpoints[:index+1], end_points)
def testVariablesSetDevice(self):
batch_size = 5
height, width = 299, 299
num_classes = 1000
inputs = tf.random_uniform((batch_size, height, width, 3))
# Force all Variables to reside on the device.
with tf.variable_scope('on_cpu'), tf.device('/cpu:0'):
inception.inception_v4(inputs, num_classes)
with tf.variable_scope('on_gpu'), tf.device('/gpu:0'):
inception.inception_v4(inputs, num_classes)
for v in tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope='on_cpu'):
self.assertDeviceEqual(v.device, '/cpu:0')
for v in tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope='on_gpu'):
self.assertDeviceEqual(v.device, '/gpu:0')
def testHalfSizeImages(self):
batch_size = 5
height, width = 150, 150
num_classes = 1000
inputs = tf.random_uniform((batch_size, height, width, 3))
logits, end_points = inception.inception_v4(inputs, num_classes)
self.assertTrue(logits.op.name.startswith('InceptionV4/Logits'))
self.assertListEqual(logits.get_shape().as_list(),
[batch_size, num_classes])
pre_pool = end_points['Mixed_7d']
self.assertListEqual(pre_pool.get_shape().as_list(),
[batch_size, 3, 3, 1536])
def testUnknownBatchSize(self):
batch_size = 1
height, width = 299, 299
num_classes = 1000
with self.test_session() as sess:
inputs = tf.placeholder(tf.float32, (None, height, width, 3))
logits, _ = inception.inception_v4(inputs, num_classes)
self.assertTrue(logits.op.name.startswith('InceptionV4/Logits'))
self.assertListEqual(logits.get_shape().as_list(),
[None, num_classes])
images = tf.random_uniform((batch_size, height, width, 3))
sess.run(tf.global_variables_initializer())
output = sess.run(logits, {inputs: images.eval()})
self.assertEquals(output.shape, (batch_size, num_classes))
def testEvaluation(self):
batch_size = 2
height, width = 299, 299
num_classes = 1000
with self.test_session() as sess:
eval_inputs = tf.random_uniform((batch_size, height, width, 3))
logits, _ = inception.inception_v4(eval_inputs,
num_classes,
is_training=False)
predictions = tf.argmax(logits, 1)
sess.run(tf.global_variables_initializer())
output = sess.run(predictions)
self.assertEquals(output.shape, (batch_size,))
def testTrainEvalWithReuse(self):
train_batch_size = 5
eval_batch_size = 2
height, width = 150, 150
num_classes = 1000
with self.test_session() as sess:
train_inputs = tf.random_uniform((train_batch_size, height, width, 3))
inception.inception_v4(train_inputs, num_classes)
eval_inputs = tf.random_uniform((eval_batch_size, height, width, 3))
logits, _ = inception.inception_v4(eval_inputs,
num_classes,
is_training=False,
reuse=True)
predictions = tf.argmax(logits, 1)
sess.run(tf.global_variables_initializer())
output = sess.run(predictions)
self.assertEquals(output.shape, (eval_batch_size,))
if __name__ == '__main__':
tf.test.main()
================================================
FILE: nets/lenet.py
================================================
# Copyright 2016 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Contains a variant of the LeNet model definition."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import tensorflow as tf
slim = tf.contrib.slim
def lenet(images, num_classes=10, is_training=False,
dropout_keep_prob=0.5,
prediction_fn=slim.softmax,
scope='LeNet'):
"""Creates a variant of the LeNet model.
Note that since the output is a set of 'logits', the values fall in the
interval of (-infinity, infinity). Consequently, to convert the outputs to a
probability distribution over the characters, one will need to convert them
using the softmax function:
logits = lenet.lenet(images, is_training=False)
probabilities = tf.nn.softmax(logits)
predictions = tf.argmax(logits, 1)
Args:
images: A batch of `Tensors` of size [batch_size, height, width, channels].
num_classes: the number of classes in the dataset.
is_training: specifies whether or not we're currently training the model.
This variable will determine the behaviour of the dropout layer.
dropout_keep_prob: the percentage of activation values that are retained.
prediction_fn: a function to get predictions out of logits.
scope: Optional variable_scope.
Returns:
logits: the pre-softmax activations, a tensor of size
[batch_size, `num_classes`]
end_points: a dictionary from components of the network to the corresponding
activation.
"""
end_points = {}
with tf.variable_scope(scope, 'LeNet', [images, num_classes]):
net = slim.conv2d(images, 32, [5, 5], scope='conv1')
net = slim.max_pool2d(net, [2, 2], 2, scope='pool1')
net = slim.conv2d(net, 64, [5, 5], scope='conv2')
net = slim.max_pool2d(net, [2, 2], 2, scope='pool2')
net = slim.flatten(net)
end_points['Flatten'] = net
net = slim.fully_connected(net, 1024, scope='fc3')
net = slim.dropout(net, dropout_keep_prob, is_training=is_training,
scope='dropout3')
logits = slim.fully_connected(net, num_classes, activation_fn=None,
scope='fc4')
end_points['Logits'] = logits
end_points['Predictions'] = prediction_fn(logits, scope='Predictions')
return logits, end_points
lenet.default_image_size = 28
def lenet_arg_scope(weight_decay=0.0):
"""Defines the default lenet argument scope.
Args:
weight_decay: The weight decay to use for regularizing the model.
Returns:
An `arg_scope` to use for the inception v3 model.
"""
with slim.arg_scope(
[slim.conv2d, slim.fully_connected],
weights_regularizer=slim.l2_regularizer(weight_decay),
weights_initializer=tf.truncated_normal_initializer(stddev=0.1),
activation_fn=tf.nn.relu) as sc:
return sc
================================================
FILE: nets/mobilenet_v1.md
================================================
# MobileNet_v1
[MobileNets](https://arxiv.org/abs/1704.04861) are small, low-latency, low-power models parameterized to meet the resource constraints of a variety of use cases. They can be built upon for classification, detection, embeddings and segmentation similar to how other popular large scale models, such as Inception, are used. MobileNets can be run efficiently on mobile devices with [TensorFlow Mobile](https://www.tensorflow.org/mobile/).
MobileNets trade off between latency, size and accuracy while comparing favorably with popular models from the literature.

# Pre-trained Models
Choose the right MobileNet model to fit your latency and size budget. The size of the network in memory and on disk is proportional to the number of parameters. The latency and power usage of the network scales with the number of Multiply-Accumulates (MACs) which measures the number of fused Multiplication and Addition operations. These MobileNet models have been trained on the
[ILSVRC-2012-CLS](http://www.image-net.org/challenges/LSVRC/2012/)
image classification dataset. Accuracies were computed by evaluating using a single image crop.
Model Checkpoint | Million MACs | Million Parameters | Top-1 Accuracy| Top-5 Accuracy |
:----:|:------------:|:----------:|:-------:|:-------:|
[MobileNet_v1_1.0_224](http://download.tensorflow.org/models/mobilenet_v1_1.0_224_2017_06_14.tar.gz)|569|4.24|70.7|89.5|
[MobileNet_v1_1.0_192](http://download.tensorflow.org/models/mobilenet_v1_1.0_192_2017_06_14.tar.gz)|418|4.24|69.3|88.9|
[MobileNet_v1_1.0_160](http://download.tensorflow.org/models/mobilenet_v1_1.0_160_2017_06_14.tar.gz)|291|4.24|67.2|87.5|
[MobileNet_v1_1.0_128](http://download.tensorflow.org/models/mobilenet_v1_1.0_128_2017_06_14.tar.gz)|186|4.24|64.1|85.3|
[MobileNet_v1_0.75_224](http://download.tensorflow.org/models/mobilenet_v1_0.75_224_2017_06_14.tar.gz)|317|2.59|68.4|88.2|
[MobileNet_v1_0.75_192](http://download.tensorflow.org/models/mobilenet_v1_0.75_192_2017_06_14.tar.gz)|233|2.59|67.4|87.3|
[MobileNet_v1_0.75_160](http://download.tensorflow.org/models/mobilenet_v1_0.75_160_2017_06_14.tar.gz)|162|2.59|65.2|86.1|
[MobileNet_v1_0.75_128](http://download.tensorflow.org/models/mobilenet_v1_0.75_128_2017_06_14.tar.gz)|104|2.59|61.8|83.6|
[MobileNet_v1_0.50_224](http://download.tensorflow.org/models/mobilenet_v1_0.50_224_2017_06_14.tar.gz)|150|1.34|64.0|85.4|
[MobileNet_v1_0.50_192](http://download.tensorflow.org/models/mobilenet_v1_0.50_192_2017_06_14.tar.gz)|110|1.34|62.1|84.0|
[MobileNet_v1_0.50_160](http://download.tensorflow.org/models/mobilenet_v1_0.50_160_2017_06_14.tar.gz)|77|1.34|59.9|82.5|
[MobileNet_v1_0.50_128](http://download.tensorflow.org/models/mobilenet_v1_0.50_128_2017_06_14.tar.gz)|49|1.34|56.2|79.6|
[MobileNet_v1_0.25_224](http://download.tensorflow.org/models/mobilenet_v1_0.25_224_2017_06_14.tar.gz)|41|0.47|50.6|75.0|
[MobileNet_v1_0.25_192](http://download.tensorflow.org/models/mobilenet_v1_0.25_192_2017_06_14.tar.gz)|34|0.47|49.0|73.6|
[MobileNet_v1_0.25_160](http://download.tensorflow.org/models/mobilenet_v1_0.25_160_2017_06_14.tar.gz)|21|0.47|46.0|70.7|
[MobileNet_v1_0.25_128](http://download.tensorflow.org/models/mobilenet_v1_0.25_128_2017_06_14.tar.gz)|14|0.47|41.3|66.2|
Here is an example of how to download the MobileNet_v1_1.0_224 checkpoint:
```shell
$ CHECKPOINT_DIR=/tmp/checkpoints
$ mkdir ${CHECKPOINT_DIR}
$ wget http://download.tensorflow.org/models/mobilenet_v1_1.0_224_2017_06_14.tar.gz
$ tar -xvf mobilenet_v1_1.0_224_2017_06_14.tar.gz
$ mv mobilenet_v1_1.0_224.ckpt.* ${CHECKPOINT_DIR}
$ rm mobilenet_v1_1.0_224_2017_06_14.tar.gz
```
More information on integrating MobileNets into your project can be found at the [TF-Slim Image Classification Library](https://github.com/tensorflow/models/blob/master/slim/README.md).
To get started running models on-device go to [TensorFlow Mobile](https://www.tensorflow.org/mobile/).
================================================
FILE: nets/mobilenet_v1.py
================================================
# Copyright 2017 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# =============================================================================
"""MobileNet v1.
MobileNet is a general architecture and can be used for multiple use cases.
Depending on the use case, it can use different input layer size and different
head (for example: embeddings, localization and classification).
As described in https://arxiv.org/abs/1704.04861.
MobileNets: Efficient Convolutional Neural Networks for
Mobile Vision Applications
Andrew G. Howard, Menglong Zhu, Bo Chen, Dmitry Kalenichenko, Weijun Wang,
Tobias Weyand, Marco Andreetto, Hartwig Adam
100% Mobilenet V1 (base) with input size 224x224:
See mobilenet_v1()
Layer params macs
--------------------------------------------------------------------------------
MobilenetV1/Conv2d_0/Conv2D: 864 10,838,016
MobilenetV1/Conv2d_1_depthwise/depthwise: 288 3,612,672
MobilenetV1/Conv2d_1_pointwise/Conv2D: 2,048 25,690,112
MobilenetV1/Conv2d_2_depthwise/depthwise: 576 1,806,336
MobilenetV1/Conv2d_2_pointwise/Conv2D: 8,192 25,690,112
MobilenetV1/Conv2d_3_depthwise/depthwise: 1,152 3,612,672
MobilenetV1/Conv2d_3_pointwise/Conv2D: 16,384 51,380,224
MobilenetV1/Conv2d_4_depthwise/depthwise: 1,152 903,168
MobilenetV1/Conv2d_4_pointwise/Conv2D: 32,768 25,690,112
MobilenetV1/Conv2d_5_depthwise/depthwise: 2,304 1,806,336
MobilenetV1/Conv2d_5_pointwise/Conv2D: 65,536 51,380,224
MobilenetV1/Conv2d_6_depthwise/depthwise: 2,304 451,584
MobilenetV1/Conv2d_6_pointwise/Conv2D: 131,072 25,690,112
MobilenetV1/Conv2d_7_depthwise/depthwise: 4,608 903,168
MobilenetV1/Conv2d_7_pointwise/Conv2D: 262,144 51,380,224
MobilenetV1/Conv2d_8_depthwise/depthwise: 4,608 903,168
MobilenetV1/Conv2d_8_pointwise/Conv2D: 262,144 51,380,224
MobilenetV1/Conv2d_9_depthwise/depthwise: 4,608 903,168
MobilenetV1/Conv2d_9_pointwise/Conv2D: 262,144 51,380,224
MobilenetV1/Conv2d_10_depthwise/depthwise: 4,608 903,168
MobilenetV1/Conv2d_10_pointwise/Conv2D: 262,144 51,380,224
MobilenetV1/Conv2d_11_depthwise/depthwise: 4,608 903,168
MobilenetV1/Conv2d_11_pointwise/Conv2D: 262,144 51,380,224
MobilenetV1/Conv2d_12_depthwise/depthwise: 4,608 225,792
MobilenetV1/Conv2d_12_pointwise/Conv2D: 524,288 25,690,112
MobilenetV1/Conv2d_13_depthwise/depthwise: 9,216 451,584
MobilenetV1/Conv2d_13_pointwise/Conv2D: 1,048,576 51,380,224
--------------------------------------------------------------------------------
Total: 3,185,088 567,716,352
75% Mobilenet V1 (base) with input size 128x128:
See mobilenet_v1_075()
Layer params macs
--------------------------------------------------------------------------------
MobilenetV1/Conv2d_0/Conv2D: 648 2,654,208
MobilenetV1/Conv2d_1_depthwise/depthwise: 216 884,736
MobilenetV1/Conv2d_1_pointwise/Conv2D: 1,152 4,718,592
MobilenetV1/Conv2d_2_depthwise/depthwise: 432 442,368
MobilenetV1/Conv2d_2_pointwise/Conv2D: 4,608 4,718,592
MobilenetV1/Conv2d_3_depthwise/depthwise: 864 884,736
MobilenetV1/Conv2d_3_pointwise/Conv2D: 9,216 9,437,184
MobilenetV1/Conv2d_4_depthwise/depthwise: 864 221,184
MobilenetV1/Conv2d_4_pointwise/Conv2D: 18,432 4,718,592
MobilenetV1/Conv2d_5_depthwise/depthwise: 1,728 442,368
MobilenetV1/Conv2d_5_pointwise/Conv2D: 36,864 9,437,184
MobilenetV1/Conv2d_6_depthwise/depthwise: 1,728 110,592
MobilenetV1/Conv2d_6_pointwise/Conv2D: 73,728 4,718,592
MobilenetV1/Conv2d_7_depthwise/depthwise: 3,456 221,184
MobilenetV1/Conv2d_7_pointwise/Conv2D: 147,456 9,437,184
MobilenetV1/Conv2d_8_depthwise/depthwise: 3,456 221,184
MobilenetV1/Conv2d_8_pointwise/Conv2D: 147,456 9,437,184
MobilenetV1/Conv2d_9_depthwise/depthwise: 3,456 221,184
MobilenetV1/Conv2d_9_pointwise/Conv2D: 147,456 9,437,184
MobilenetV1/Conv2d_10_depthwise/depthwise: 3,456 221,184
MobilenetV1/Conv2d_10_pointwise/Conv2D: 147,456 9,437,184
MobilenetV1/Conv2d_11_depthwise/depthwise: 3,456 221,184
MobilenetV1/Conv2d_11_pointwise/Conv2D: 147,456 9,437,184
MobilenetV1/Conv2d_12_depthwise/depthwise: 3,456 55,296
MobilenetV1/Conv2d_12_pointwise/Conv2D: 294,912 4,718,592
MobilenetV1/Conv2d_13_depthwise/depthwise: 6,912 110,592
MobilenetV1/Conv2d_13_pointwise/Conv2D: 589,824 9,437,184
--------------------------------------------------------------------------------
Total: 1,800,144 106,002,432
"""
# Tensorflow mandates these.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from collections import namedtuple
import functools
import tensorflow as tf
slim = tf.contrib.slim
# Conv and DepthSepConv namedtuple define layers of the MobileNet architecture
# Conv defines 3x3 convolution layers
# DepthSepConv defines 3x3 depthwise convolution followed by 1x1 convolution.
# stride is the stride of the convolution
# depth is the number of channels or filters in a layer
Conv = namedtuple('Conv', ['kernel', 'stride', 'depth'])
DepthSepConv = namedtuple('DepthSepConv', ['kernel', 'stride', 'depth'])
# _CONV_DEFS specifies the MobileNet body
_CONV_DEFS = [
Conv(kernel=[3, 3], stride=2, depth=32),
DepthSepConv(kernel=[3, 3], stride=1, depth=64),
DepthSepConv(kernel=[3, 3], stride=2, depth=128),
DepthSepConv(kernel=[3, 3], stride=1, depth=128),
DepthSepConv(kernel=[3, 3], stride=2, depth=256),
DepthSepConv(kernel=[3, 3], stride=1, depth=256),
DepthSepConv(kernel=[3, 3], stride=2, depth=512),
DepthSepConv(kernel=[3, 3], stride=1, depth=512),
DepthSepConv(kernel=[3, 3], stride=1, depth=512),
DepthSepConv(kernel=[3, 3], stride=1, depth=512),
DepthSepConv(kernel=[3, 3], stride=1, depth=512),
DepthSepConv(kernel=[3, 3], stride=1, depth=512),
DepthSepConv(kernel=[3, 3], stride=2, depth=1024),
DepthSepConv(kernel=[3, 3], stride=1, depth=1024)
]
def mobilenet_v1_base(inputs,
final_endpoint='Conv2d_13_pointwise',
min_depth=8,
depth_multiplier=1.0,
conv_defs=None,
output_stride=None,
scope=None):
"""Mobilenet v1.
Constructs a Mobilenet v1 network from inputs to the given final endpoint.
Args:
inputs: a tensor of shape [batch_size, height, width, channels].
final_endpoint: specifies the endpoint to construct the network up to. It
can be one of ['Conv2d_0', 'Conv2d_1_pointwise', 'Conv2d_2_pointwise',
'Conv2d_3_pointwise', 'Conv2d_4_pointwise', 'Conv2d_5'_pointwise,
'Conv2d_6_pointwise', 'Conv2d_7_pointwise', 'Conv2d_8_pointwise',
'Conv2d_9_pointwise', 'Conv2d_10_pointwise', 'Conv2d_11_pointwise',
'Conv2d_12_pointwise', 'Conv2d_13_pointwise'].
min_depth: Minimum depth value (number of channels) for all convolution ops.
Enforced when depth_multiplier < 1, and not an active constraint when
depth_multiplier >= 1.
depth_multiplier: Float multiplier for the depth (number of channels)
for all convolution ops. The value must be greater than zero. Typical
usage will be to set this value in (0, 1) to reduce the number of
parameters or computation cost of the model.
conv_defs: A list of ConvDef namedtuples specifying the net architecture.
output_stride: An integer that specifies the requested ratio of input to
output spatial resolution. If not None, then we invoke atrous convolution
if necessary to prevent the network from reducing the spatial resolution
of the activation maps. Allowed values are 8 (accurate fully convolutional
mode), 16 (fast fully convolutional mode), 32 (classification mode).
scope: Optional variable_scope.
Returns:
tensor_out: output tensor corresponding to the final_endpoint.
end_points: a set of activations for external use, for example summaries or
losses.
Raises:
ValueError: if final_endpoint is not set to one of the predefined values,
or depth_multiplier <= 0, or the target output_stride is not
allowed.
"""
depth = lambda d: max(int(d * depth_multiplier), min_depth)
end_points = {}
# Used to find thinned depths for each layer.
if depth_multiplier <= 0:
raise ValueError('depth_multiplier is not greater than zero.')
if conv_defs is None:
conv_defs = _CONV_DEFS
if output_stride is not None and output_stride not in [8, 16, 32]:
raise ValueError('Only allowed output_stride values are 8, 16, 32.')
with tf.variable_scope(scope, 'MobilenetV1', [inputs]):
with slim.arg_scope([slim.conv2d, slim.separable_conv2d], padding='SAME'):
# The current_stride variable keeps track of the output stride of the
# activations, i.e., the running product of convolution strides up to the
# current network layer. This allows us to invoke atrous convolution
# whenever applying the next convolution would result in the activations
# having output stride larger than the target output_stride.
current_stride = 1
# The atrous convolution rate parameter.
rate = 1
net = inputs
for i, conv_def in enumerate(conv_defs):
end_point_base = 'Conv2d_%d' % i
if output_stride is not None and current_stride == output_stride:
# If we have reached the target output_stride, then we need to employ
# atrous convolution with stride=1 and multiply the atrous rate by the
# current unit's stride for use in subsequent layers.
layer_stride = 1
layer_rate = rate
rate *= conv_def.stride
else:
layer_stride = conv_def.stride
layer_rate = 1
current_stride *= conv_def.stride
if isinstance(conv_def, Conv):
end_point = end_point_base
net = slim.conv2d(net, depth(conv_def.depth), conv_def.kernel,
stride=conv_def.stride,
normalizer_fn=slim.batch_norm,
scope=end_point)
end_points[end_point] = net
if end_point == final_endpoint:
return net, end_points
elif isinstance(conv_def, DepthSepConv):
end_point = end_point_base + '_depthwise'
# By passing filters=None
# separable_conv2d produces only a depthwise convolution layer
net = slim.separable_conv2d(net, None, conv_def.kernel,
depth_multiplier=1,
stride=layer_stride,
rate=layer_rate,
normalizer_fn=slim.batch_norm,
scope=end_point)
end_points[end_point] = net
if end_point == final_endpoint:
return net, end_points
end_point = end_point_base + '_pointwise'
net = slim.conv2d(net, depth(conv_def.depth), [1, 1],
stride=1,
normalizer_fn=slim.batch_norm,
scope=end_point)
end_points[end_point] = net
if end_point == final_endpoint:
return net, end_points
else:
raise ValueError('Unknown convolution type %s for layer %d'
% (conv_def.ltype, i))
raise ValueError('Unknown final endpoint %s' % final_endpoint)
def mobilenet_v1(inputs,
num_classes=1000,
dropout_keep_prob=0.999,
is_training=True,
min_depth=8,
depth_multiplier=1.0,
conv_defs=None,
prediction_fn=tf.contrib.layers.softmax,
spatial_squeeze=True,
reuse=None,
scope='MobilenetV1'):
"""Mobilenet v1 model for classification.
Args:
inputs: a tensor of shape [batch_size, height, width, channels].
num_classes: number of predicted classes.
dropout_keep_prob: the percentage of activation values that are retained.
is_training: whether is training or not.
min_depth: Minimum depth value (number of channels) for all convolution ops.
Enforced when depth_multiplier < 1, and not an active constraint when
depth_multiplier >= 1.
depth_multiplier: Float multiplier for the depth (number of channels)
for all convolution ops. The value must be greater than zero. Typical
usage will be to set this value in (0, 1) to reduce the number of
parameters or computation cost of the model.
conv_defs: A list of ConvDef namedtuples specifying the net architecture.
prediction_fn: a function to get predictions out of logits.
spatial_squeeze: if True, logits is of shape is [B, C], if false logits is
of shape [B, 1, 1, C], where B is batch_size and C is number of classes.
reuse: whether or not the network and its variables should be reused. To be
able to reuse 'scope' must be given.
scope: Optional variable_scope.
Returns:
logits: the pre-softmax activations, a tensor of size
[batch_size, num_classes]
end_points: a dictionary from components of the network to the corresponding
activation.
Raises:
ValueError: Input rank is invalid.
"""
input_shape = inputs.get_shape().as_list()
if len(input_shape) != 4:
raise ValueError('Invalid input tensor rank, expected 4, was: %d' %
len(input_shape))
with tf.variable_scope(scope, 'MobilenetV1', [inputs, num_classes],
reuse=reuse) as scope:
with slim.arg_scope([slim.batch_norm, slim.dropout],
is_training=is_training):
net, end_points = mobilenet_v1_base(inputs, scope=scope,
min_depth=min_depth,
depth_multiplier=depth_multiplier,
conv_defs=conv_defs)
with tf.variable_scope('Logits'):
kernel_size = _reduced_kernel_size_for_small_input(net, [7, 7])
net = slim.avg_pool2d(net, kernel_size, padding='VALID',
scope='AvgPool_1a')
end_points['AvgPool_1a'] = net
# 1 x 1 x 1024
net = slim.dropout(net, keep_prob=dropout_keep_prob, scope='Dropout_1b')
logits = slim.conv2d(net, num_classes, [1, 1], activation_fn=None,
normalizer_fn=None, scope='Conv2d_1c_1x1')
if spatial_squeeze:
logits = tf.squeeze(logits, [1, 2], name='SpatialSqueeze')
end_points['Logits'] = logits
if prediction_fn:
end_points['Predictions'] = prediction_fn(logits, scope='Predictions')
return logits, end_points
mobilenet_v1.default_image_size = 224
def wrapped_partial(func, *args, **kwargs):
partial_func = functools.partial(func, *args, **kwargs)
functools.update_wrapper(partial_func, func)
return partial_func
mobilenet_v1_075 = wrapped_partial(mobilenet_v1, depth_multiplier=0.75)
mobilenet_v1_050 = wrapped_partial(mobilenet_v1, depth_multiplier=0.50)
mobilenet_v1_025 = wrapped_partial(mobilenet_v1, depth_multiplier=0.25)
def _reduced_kernel_size_for_small_input(input_tensor, kernel_size):
"""Define kernel size which is automatically reduced for small input.
If the shape of the input images is unknown at graph construction time this
function assumes that the input images are large enough.
Args:
input_tensor: input tensor of size [batch_size, height, width, channels].
kernel_size: desired kernel size of length 2: [kernel_height, kernel_width]
Returns:
a tensor with the kernel size.
"""
shape = input_tensor.get_shape().as_list()
if shape[1] is None or shape[2] is None:
kernel_size_out = kernel_size
else:
kernel_size_out = [min(shape[1], kernel_size[0]),
min(shape[2], kernel_size[1])]
return kernel_size_out
def mobilenet_v1_arg_scope(is_training=True,
weight_decay=0.00004,
stddev=0.09,
regularize_depthwise=False):
"""Defines the default MobilenetV1 arg scope.
Args:
is_training: Whether or not we're training the model.
weight_decay: The weight decay to use for regularizing the model.
stddev: The standard deviation of the trunctated normal weight initializer.
regularize_depthwise: Whether or not apply regularization on depthwise.
Returns:
An `arg_scope` to use for the mobilenet v1 model.
"""
batch_norm_params = {
'is_training': is_training,
'center': True,
'scale': True,
'decay': 0.9997,
'epsilon': 0.001,
}
# Set weight_decay for weights in Conv and DepthSepConv layers.
weights_init = tf.truncated_normal_initializer(stddev=stddev)
regularizer = tf.contrib.layers.l2_regularizer(weight_decay)
if regularize_depthwise:
depthwise_regularizer = regularizer
else:
depthwise_regularizer = None
with slim.arg_scope([slim.conv2d, slim.separable_conv2d],
weights_initializer=weights_init,
activation_fn=tf.nn.relu6, normalizer_fn=slim.batch_norm):
with slim.arg_scope([slim.batch_norm], **batch_norm_params):
with slim.arg_scope([slim.conv2d], weights_regularizer=regularizer):
with slim.arg_scope([slim.separable_conv2d],
weights_regularizer=depthwise_regularizer) as sc:
return sc
================================================
FILE: nets/mobilenet_v1_test.py
================================================
# Copyright 2017 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# =============================================================================
"""Tests for MobileNet v1."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import numpy as np
import tensorflow as tf
from nets import mobilenet_v1
slim = tf.contrib.slim
class MobilenetV1Test(tf.test.TestCase):
def testBuildClassificationNetwork(self):
batch_size = 5
height, width = 224, 224
num_classes = 1000
inputs = tf.random_uniform((batch_size, height, width, 3))
logits, end_points = mobilenet_v1.mobilenet_v1(inputs, num_classes)
self.assertTrue(logits.op.name.startswith('MobilenetV1/Logits'))
self.assertListEqual(logits.get_shape().as_list(),
[batch_size, num_classes])
self.assertTrue('Predictions' in end_points)
self.assertListEqual(end_points['Predictions'].get_shape().as_list(),
[batch_size, num_classes])
def testBuildBaseNetwork(self):
batch_size = 5
height, width = 224, 224
inputs = tf.random_uniform((batch_size, height, width, 3))
net, end_points = mobilenet_v1.mobilenet_v1_base(inputs)
self.assertTrue(net.op.name.startswith('MobilenetV1/Conv2d_13'))
self.assertListEqual(net.get_shape().as_list(),
[batch_size, 7, 7, 1024])
expected_endpoints = ['Conv2d_0',
'Conv2d_1_depthwise', 'Conv2d_1_pointwise',
'Conv2d_2_depthwise', 'Conv2d_2_pointwise',
'Conv2d_3_depthwise', 'Conv2d_3_pointwise',
'Conv2d_4_depthwise', 'Conv2d_4_pointwise',
'Conv2d_5_depthwise', 'Conv2d_5_pointwise',
'Conv2d_6_depthwise', 'Conv2d_6_pointwise',
'Conv2d_7_depthwise', 'Conv2d_7_pointwise',
'Conv2d_8_depthwise', 'Conv2d_8_pointwise',
'Conv2d_9_depthwise', 'Conv2d_9_pointwise',
'Conv2d_10_depthwise', 'Conv2d_10_pointwise',
'Conv2d_11_depthwise', 'Conv2d_11_pointwise',
'Conv2d_12_depthwise', 'Conv2d_12_pointwise',
'Conv2d_13_depthwise', 'Conv2d_13_pointwise']
self.assertItemsEqual(end_points.keys(), expected_endpoints)
def testBuildOnlyUptoFinalEndpoint(self):
batch_size = 5
height, width = 224, 224
endpoints = ['Conv2d_0',
'Conv2d_1_depthwise', 'Conv2d_1_pointwise',
'Conv2d_2_depthwise', 'Conv2d_2_pointwise',
'Conv2d_3_depthwise', 'Conv2d_3_pointwise',
'Conv2d_4_depthwise', 'Conv2d_4_pointwise',
'Conv2d_5_depthwise', 'Conv2d_5_pointwise',
'Conv2d_6_depthwise', 'Conv2d_6_pointwise',
'Conv2d_7_depthwise', 'Conv2d_7_pointwise',
'Conv2d_8_depthwise', 'Conv2d_8_pointwise',
'Conv2d_9_depthwise', 'Conv2d_9_pointwise',
'Conv2d_10_depthwise', 'Conv2d_10_pointwise',
'Conv2d_11_depthwise', 'Conv2d_11_pointwise',
'Conv2d_12_depthwise', 'Conv2d_12_pointwise',
'Conv2d_13_depthwise', 'Conv2d_13_pointwise']
for index, endpoint in enumerate(endpoints):
with tf.Graph().as_default():
inputs = tf.random_uniform((batch_size, height, width, 3))
out_tensor, end_points = mobilenet_v1.mobilenet_v1_base(
inputs, final_endpoint=endpoint)
self.assertTrue(out_tensor.op.name.startswith(
'MobilenetV1/' + endpoint))
self.assertItemsEqual(endpoints[:index+1], end_points)
def testBuildCustomNetworkUsingConvDefs(self):
batch_size = 5
height, width = 224, 224
conv_defs = [
mobilenet_v1.Conv(kernel=[3, 3], stride=2, depth=32),
mobilenet_v1.DepthSepConv(kernel=[3, 3], stride=1, depth=64),
mobilenet_v1.DepthSepConv(kernel=[3, 3], stride=2, depth=128),
mobilenet_v1.DepthSepConv(kernel=[3, 3], stride=1, depth=512)
]
inputs = tf.random_uniform((batch_size, height, width, 3))
net, end_points = mobilenet_v1.mobilenet_v1_base(
inputs, final_endpoint='Conv2d_3_pointwise', conv_defs=conv_defs)
self.assertTrue(net.op.name.startswith('MobilenetV1/Conv2d_3'))
self.assertListEqual(net.get_shape().as_list(),
[batch_size, 56, 56, 512])
expected_endpoints = ['Conv2d_0',
'Conv2d_1_depthwise', 'Conv2d_1_pointwise',
'Conv2d_2_depthwise', 'Conv2d_2_pointwise',
'Conv2d_3_depthwise', 'Conv2d_3_pointwise']
self.assertItemsEqual(end_points.keys(), expected_endpoints)
def testBuildAndCheckAllEndPointsUptoConv2d_13(self):
batch_size = 5
height, width = 224, 224
inputs = tf.random_uniform((batch_size, height, width, 3))
with slim.arg_scope([slim.conv2d, slim.separable_conv2d],
normalizer_fn=slim.batch_norm):
_, end_points = mobilenet_v1.mobilenet_v1_base(
inputs, final_endpoint='Conv2d_13_pointwise')
endpoints_shapes = {'Conv2d_0': [batch_size, 112, 112, 32],
'Conv2d_1_depthwise': [batch_size, 112, 112, 32],
'Conv2d_1_pointwise': [batch_size, 112, 112, 64],
'Conv2d_2_depthwise': [batch_size, 56, 56, 64],
'Conv2d_2_pointwise': [batch_size, 56, 56, 128],
'Conv2d_3_depthwise': [batch_size, 56, 56, 128],
'Conv2d_3_pointwise': [batch_size, 56, 56, 128],
'Conv2d_4_depthwise': [batch_size, 28, 28, 128],
'Conv2d_4_pointwise': [batch_size, 28, 28, 256],
'Conv2d_5_depthwise': [batch_size, 28, 28, 256],
'Conv2d_5_pointwise': [batch_size, 28, 28, 256],
'Conv2d_6_depthwise': [batch_size, 14, 14, 256],
'Conv2d_6_pointwise': [batch_size, 14, 14, 512],
'Conv2d_7_depthwise': [batch_size, 14, 14, 512],
'Conv2d_7_pointwise': [batch_size, 14, 14, 512],
'Conv2d_8_depthwise': [batch_size, 14, 14, 512],
'Conv2d_8_pointwise': [batch_size, 14, 14, 512],
'Conv2d_9_depthwise': [batch_size, 14, 14, 512],
'Conv2d_9_pointwise': [batch_size, 14, 14, 512],
'Conv2d_10_depthwise': [batch_size, 14, 14, 512],
'Conv2d_10_pointwise': [batch_size, 14, 14, 512],
'Conv2d_11_depthwise': [batch_size, 14, 14, 512],
'Conv2d_11_pointwise': [batch_size, 14, 14, 512],
'Conv2d_12_depthwise': [batch_size, 7, 7, 512],
'Conv2d_12_pointwise': [batch_size, 7, 7, 1024],
'Conv2d_13_depthwise': [batch_size, 7, 7, 1024],
'Conv2d_13_pointwise': [batch_size, 7, 7, 1024]}
self.assertItemsEqual(endpoints_shapes.keys(), end_points.keys())
for endpoint_name, expected_shape in endpoints_shapes.iteritems():
self.assertTrue(endpoint_name in end_points)
self.assertListEqual(end_points[endpoint_name].get_shape().as_list(),
expected_shape)
def testOutputStride16BuildAndCheckAllEndPointsUptoConv2d_13(self):
batch_size = 5
height, width = 224, 224
output_stride = 16
inputs = tf.random_uniform((batch_size, height, width, 3))
with slim.arg_scope([slim.conv2d, slim.separable_conv2d],
normalizer_fn=slim.batch_norm):
_, end_points = mobilenet_v1.mobilenet_v1_base(
inputs, output_stride=output_stride,
final_endpoint='Conv2d_13_pointwise')
endpoints_shapes = {'Conv2d_0': [batch_size, 112, 112, 32],
'Conv2d_1_depthwise': [batch_size, 112, 112, 32],
'Conv2d_1_pointwise': [batch_size, 112, 112, 64],
'Conv2d_2_depthwise': [batch_size, 56, 56, 64],
'Conv2d_2_pointwise': [batch_size, 56, 56, 128],
'Conv2d_3_depthwise': [batch_size, 56, 56, 128],
'Conv2d_3_pointwise': [batch_size, 56, 56, 128],
'Conv2d_4_depthwise': [batch_size, 28, 28, 128],
'Conv2d_4_pointwise': [batch_size, 28, 28, 256],
'Conv2d_5_depthwise': [batch_size, 28, 28, 256],
'Conv2d_5_pointwise': [batch_size, 28, 28, 256],
'Conv2d_6_depthwise': [batch_size, 14, 14, 256],
'Conv2d_6_pointwise': [batch_size, 14, 14, 512],
'Conv2d_7_depthwise': [batch_size, 14, 14, 512],
'Conv2d_7_pointwise': [batch_size, 14, 14, 512],
'Conv2d_8_depthwise': [batch_size, 14, 14, 512],
'Conv2d_8_pointwise': [batch_size, 14, 14, 512],
'Conv2d_9_depthwise': [batch_size, 14, 14, 512],
'Conv2d_9_pointwise': [batch_size, 14, 14, 512],
'Conv2d_10_depthwise': [batch_size, 14, 14, 512],
'Conv2d_10_pointwise': [batch_size, 14, 14, 512],
'Conv2d_11_depthwise': [batch_size, 14, 14, 512],
'Conv2d_11_pointwise': [batch_size, 14, 14, 512],
'Conv2d_12_depthwise': [batch_size, 14, 14, 512],
'Conv2d_12_pointwise': [batch_size, 14, 14, 1024],
'Conv2d_13_depthwise': [batch_size, 14, 14, 1024],
'Conv2d_13_pointwise': [batch_size, 14, 14, 1024]}
self.assertItemsEqual(endpoints_shapes.keys(), end_points.keys())
for endpoint_name, expected_shape in endpoints_shapes.iteritems():
self.assertTrue(endpoint_name in end_points)
self.assertListEqual(end_points[endpoint_name].get_shape().as_list(),
expected_shape)
def testOutputStride8BuildAndCheckAllEndPointsUptoConv2d_13(self):
batch_size = 5
height, width = 224, 224
output_stride = 8
inputs = tf.random_uniform((batch_size, height, width, 3))
with slim.arg_scope([slim.conv2d, slim.separable_conv2d],
normalizer_fn=slim.batch_norm):
_, end_points = mobilenet_v1.mobilenet_v1_base(
inputs, output_stride=output_stride,
final_endpoint='Conv2d_13_pointwise')
endpoints_shapes = {'Conv2d_0': [batch_size, 112, 112, 32],
'Conv2d_1_depthwise': [batch_size, 112, 112, 32],
'Conv2d_1_pointwise': [batch_size, 112, 112, 64],
'Conv2d_2_depthwise': [batch_size, 56, 56, 64],
'Conv2d_2_pointwise': [batch_size, 56, 56, 128],
'Conv2d_3_depthwise': [batch_size, 56, 56, 128],
'Conv2d_3_pointwise': [batch_size, 56, 56, 128],
'Conv2d_4_depthwise': [batch_size, 28, 28, 128],
'Conv2d_4_pointwise': [batch_size, 28, 28, 256],
'Conv2d_5_depthwise': [batch_size, 28, 28, 256],
'Conv2d_5_pointwise': [batch_size, 28, 28, 256],
'Conv2d_6_depthwise': [batch_size, 28, 28, 256],
'Conv2d_6_pointwise': [batch_size, 28, 28, 512],
'Conv2d_7_depthwise': [batch_size, 28, 28, 512],
'Conv2d_7_pointwise': [batch_size, 28, 28, 512],
'Conv2d_8_depthwise': [batch_size, 28, 28, 512],
'Conv2d_8_pointwise': [batch_size, 28, 28, 512],
'Conv2d_9_depthwise': [batch_size, 28, 28, 512],
'Conv2d_9_pointwise': [batch_size, 28, 28, 512],
'Conv2d_10_depthwise': [batch_size, 28, 28, 512],
'Conv2d_10_pointwise': [batch_size, 28, 28, 512],
'Conv2d_11_depthwise': [batch_size, 28, 28, 512],
'Conv2d_11_pointwise': [batch_size, 28, 28, 512],
'Conv2d_12_depthwise': [batch_size, 28, 28, 512],
'Conv2d_12_pointwise': [batch_size, 28, 28, 1024],
'Conv2d_13_depthwise': [batch_size, 28, 28, 1024],
'Conv2d_13_pointwise': [batch_size, 28, 28, 1024]}
self.assertItemsEqual(endpoints_shapes.keys(), end_points.keys())
for endpoint_name, expected_shape in endpoints_shapes.iteritems():
self.assertTrue(endpoint_name in end_points)
self.assertListEqual(end_points[endpoint_name].get_shape().as_list(),
expected_shape)
def testBuildAndCheckAllEndPointsApproximateFaceNet(self):
batch_size = 5
height, width = 128, 128
inputs = tf.random_uniform((batch_size, height, width, 3))
with slim.arg_scope([slim.conv2d, slim.separable_conv2d],
normalizer_fn=slim.batch_norm):
_, end_points = mobilenet_v1.mobilenet_v1_base(
inputs, final_endpoint='Conv2d_13_pointwise', depth_multiplier=0.75)
# For the Conv2d_0 layer FaceNet has depth=16
endpoints_shapes = {'Conv2d_0': [batch_size, 64, 64, 24],
'Conv2d_1_depthwise': [batch_size, 64, 64, 24],
'Conv2d_1_pointwise': [batch_size, 64, 64, 48],
'Conv2d_2_depthwise': [batch_size, 32, 32, 48],
'Conv2d_2_pointwise': [batch_size, 32, 32, 96],
'Conv2d_3_depthwise': [batch_size, 32, 32, 96],
'Conv2d_3_pointwise': [batch_size, 32, 32, 96],
'Conv2d_4_depthwise': [batch_size, 16, 16, 96],
'Conv2d_4_pointwise': [batch_size, 16, 16, 192],
'Conv2d_5_depthwise': [batch_size, 16, 16, 192],
'Conv2d_5_pointwise': [batch_size, 16, 16, 192],
'Conv2d_6_depthwise': [batch_size, 8, 8, 192],
'Conv2d_6_pointwise': [batch_size, 8, 8, 384],
'Conv2d_7_depthwise': [batch_size, 8, 8, 384],
'Conv2d_7_pointwise': [batch_size, 8, 8, 384],
'Conv2d_8_depthwise': [batch_size, 8, 8, 384],
'Conv2d_8_pointwise': [batch_size, 8, 8, 384],
'Conv2d_9_depthwise': [batch_size, 8, 8, 384],
'Conv2d_9_pointwise': [batch_size, 8, 8, 384],
'Conv2d_10_depthwise': [batch_size, 8, 8, 384],
'Conv2d_10_pointwise': [batch_size, 8, 8, 384],
'Conv2d_11_depthwise': [batch_size, 8, 8, 384],
'Conv2d_11_pointwise': [batch_size, 8, 8, 384],
'Conv2d_12_depthwise': [batch_size, 4, 4, 384],
'Conv2d_12_pointwise': [batch_size, 4, 4, 768],
'Conv2d_13_depthwise': [batch_size, 4, 4, 768],
'Conv2d_13_pointwise': [batch_size, 4, 4, 768]}
self.assertItemsEqual(endpoints_shapes.keys(), end_points.keys())
for endpoint_name, expected_shape in endpoints_shapes.iteritems():
self.assertTrue(endpoint_name in end_points)
self.assertListEqual(end_points[endpoint_name].get_shape().as_list(),
expected_shape)
def testModelHasExpectedNumberOfParameters(self):
batch_size = 5
height, width = 224, 224
inputs = tf.random_uniform((batch_size, height, width, 3))
with slim.arg_scope([slim.conv2d, slim.separable_conv2d],
normalizer_fn=slim.batch_norm):
mobilenet_v1.mobilenet_v1_base(inputs)
total_params, _ = slim.model_analyzer.analyze_vars(
slim.get_model_variables())
self.assertAlmostEqual(3217920L, total_params)
def testBuildEndPointsWithDepthMultiplierLessThanOne(self):
batch_size = 5
height, width = 224, 224
num_classes = 1000
inputs = tf.random_uniform((batch_size, height, width, 3))
_, end_points = mobilenet_v1.mobilenet_v1(inputs, num_classes)
endpoint_keys = [key for key in end_points.keys() if key.startswith('Conv')]
_, end_points_with_multiplier = mobilenet_v1.mobilenet_v1(
inputs, num_classes, scope='depth_multiplied_net',
depth_multiplier=0.5)
for key in endpoint_keys:
original_depth = end_points[key].get_shape().as_list()[3]
new_depth = end_points_with_multiplier[key].get_shape().as_list()[3]
self.assertEqual(0.5 * original_depth, new_depth)
def testBuildEndPointsWithDepthMultiplierGreaterThanOne(self):
batch_size = 5
height, width = 224, 224
num_classes = 1000
inputs = tf.random_uniform((batch_size, height, width, 3))
_, end_points = mobilenet_v1.mobilenet_v1(inputs, num_classes)
endpoint_keys = [key for key in end_points.keys()
if key.startswith('Mixed') or key.startswith('Conv')]
_, end_points_with_multiplier = mobilenet_v1.mobilenet_v1(
inputs, num_classes, scope='depth_multiplied_net',
depth_multiplier=2.0)
for key in endpoint_keys:
original_depth = end_points[key].get_shape().as_list()[3]
new_depth = end_points_with_multiplier[key].get_shape().as_list()[3]
self.assertEqual(2.0 * original_depth, new_depth)
def testRaiseValueErrorWithInvalidDepthMultiplier(self):
batch_size = 5
height, width = 224, 224
num_classes = 1000
inputs = tf.random_uniform((batch_size, height, width, 3))
with self.assertRaises(ValueError):
_ = mobilenet_v1.mobilenet_v1(
inputs, num_classes, depth_multiplier=-0.1)
with self.assertRaises(ValueError):
_ = mobilenet_v1.mobilenet_v1(
inputs, num_classes, depth_multiplier=0.0)
def testHalfSizeImages(self):
batch_size = 5
height, width = 112, 112
num_classes = 1000
inputs = tf.random_uniform((batch_size, height, width, 3))
logits, end_points = mobilenet_v1.mobilenet_v1(inputs, num_classes)
self.assertTrue(logits.op.name.startswith('MobilenetV1/Logits'))
self.assertListEqual(logits.get_shape().as_list(),
[batch_size, num_classes])
pre_pool = end_points['Conv2d_13_pointwise']
self.assertListEqual(pre_pool.get_shape().as_list(),
[batch_size, 4, 4, 1024])
def testUnknownImageShape(self):
tf.reset_default_graph()
batch_size = 2
height, width = 224, 224
num_classes = 1000
input_np = np.random.uniform(0, 1, (batch_size, height, width, 3))
with self.test_session() as sess:
inputs = tf.placeholder(tf.float32, shape=(batch_size, None, None, 3))
logits, end_points = mobilenet_v1.mobilenet_v1(inputs, num_classes)
self.assertTrue(logits.op.name.startswith('MobilenetV1/Logits'))
self.assertListEqual(logits.get_shape().as_list(),
[batch_size, num_classes])
pre_pool = end_points['Conv2d_13_pointwise']
feed_dict = {inputs: input_np}
tf.global_variables_initializer().run()
pre_pool_out = sess.run(pre_pool, feed_dict=feed_dict)
self.assertListEqual(list(pre_pool_out.shape), [batch_size, 7, 7, 1024])
def testUnknowBatchSize(self):
batch_size = 1
height, width = 224, 224
num_classes = 1000
inputs = tf.placeholder(tf.float32, (None, height, width, 3))
logits, _ = mobilenet_v1.mobilenet_v1(inputs, num_classes)
self.assertTrue(logits.op.name.startswith('MobilenetV1/Logits'))
self.assertListEqual(logits.get_shape().as_list(),
[None, num_classes])
images = tf.random_uniform((batch_size, height, width, 3))
with self.test_session() as sess:
sess.run(tf.global_variables_initializer())
output = sess.run(logits, {inputs: images.eval()})
self.assertEquals(output.shape, (batch_size, num_classes))
def testEvaluation(self):
batch_size = 2
height, width = 224, 224
num_classes = 1000
eval_inputs = tf.random_uniform((batch_size, height, width, 3))
logits, _ = mobilenet_v1.mobilenet_v1(eval_inputs, num_classes,
is_training=False)
predictions = tf.argmax(logits, 1)
with self.test_session() as sess:
sess.run(tf.global_variables_initializer())
output = sess.run(predictions)
self.assertEquals(output.shape, (batch_size,))
def testTrainEvalWithReuse(self):
train_batch_size = 5
eval_batch_size = 2
height, width = 150, 150
num_classes = 1000
train_inputs = tf.random_uniform((train_batch_size, height, width, 3))
mobilenet_v1.mobilenet_v1(train_inputs, num_classes)
eval_inputs = tf.random_uniform((eval_batch_size, height, width, 3))
logits, _ = mobilenet_v1.mobilenet_v1(eval_inputs, num_classes,
reuse=True)
predictions = tf.argmax(logits, 1)
with self.test_session() as sess:
sess.run(tf.global_variables_initializer())
output = sess.run(predictions)
self.assertEquals(output.shape, (eval_batch_size,))
def testLogitsNotSqueezed(self):
num_classes = 25
images = tf.random_uniform([1, 224, 224, 3])
logits, _ = mobilenet_v1.mobilenet_v1(images,
num_classes=num_classes,
spatial_squeeze=False)
with self.test_session() as sess:
tf.global_variables_initializer().run()
logits_out = sess.run(logits)
self.assertListEqual(list(logits_out.shape), [1, 1, 1, num_classes])
if __name__ == '__main__':
tf.test.main()
================================================
FILE: nets/nets_factory.py
================================================
# Copyright 2016 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Contains a factory for building various models."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import functools
import tensorflow as tf
from nets import alexnet
from nets import cifarnet
from nets import inception
from nets import lenet
from nets import mobilenet_v1
from nets import overfeat
from nets import resnet_v1
from nets import resnet_v2
from nets import vgg
slim = tf.contrib.slim
networks_map = {'alexnet_v2': alexnet.alexnet_v2,
'cifarnet': cifarnet.cifarnet,
'overfeat': overfeat.overfeat,
'vgg_a': vgg.vgg_a,
'vgg_16': vgg.vgg_16,
'vgg_19': vgg.vgg_19,
'inception_v1': inception.inception_v1,
'inception_v2': inception.inception_v2,
'inception_v3': inception.inception_v3,
'inception_v4': inception.inception_v4,
'inception_resnet_v2': inception.inception_resnet_v2,
'lenet': lenet.lenet,
'resnet_v1_50': resnet_v1.resnet_v1_50,
'resnet_v1_101': resnet_v1.resnet_v1_101,
'resnet_v1_152': resnet_v1.resnet_v1_152,
'resnet_v1_200': resnet_v1.resnet_v1_200,
'resnet_v2_50': resnet_v2.resnet_v2_50,
'resnet_v2_101': resnet_v2.resnet_v2_101,
'resnet_v2_152': resnet_v2.resnet_v2_152,
'resnet_v2_200': resnet_v2.resnet_v2_200,
'mobilenet_v1': mobilenet_v1.mobilenet_v1,
'mobilenet_v1_075': mobilenet_v1.mobilenet_v1_075,
'mobilenet_v1_050': mobilenet_v1.mobilenet_v1_050,
'mobilenet_v1_025': mobilenet_v1.mobilenet_v1_025,
}
arg_scopes_map = {'alexnet_v2': alexnet.alexnet_v2_arg_scope,
'cifarnet': cifarnet.cifarnet_arg_scope,
'overfeat': overfeat.overfeat_arg_scope,
'vgg_a': vgg.vgg_arg_scope,
'vgg_16': vgg.vgg_arg_scope,
'vgg_19': vgg.vgg_arg_scope,
'inception_v1': inception.inception_v3_arg_scope,
'inception_v2': inception.inception_v3_arg_scope,
'inception_v3': inception.inception_v3_arg_scope,
'inception_v4': inception.inception_v4_arg_scope,
'inception_resnet_v2':
inception.inception_resnet_v2_arg_scope,
'lenet': lenet.lenet_arg_scope,
'resnet_v1_50': resnet_v1.resnet_arg_scope,
'resnet_v1_101': resnet_v1.resnet_arg_scope,
'resnet_v1_152': resnet_v1.resnet_arg_scope,
'resnet_v1_200': resnet_v1.resnet_arg_scope,
'resnet_v2_50': resnet_v2.resnet_arg_scope,
'resnet_v2_101': resnet_v2.resnet_arg_scope,
'resnet_v2_152': resnet_v2.resnet_arg_scope,
'resnet_v2_200': resnet_v2.resnet_arg_scope,
'mobilenet_v1': mobilenet_v1.mobilenet_v1_arg_scope,
'mobilenet_v1_075': mobilenet_v1.mobilenet_v1_arg_scope,
'mobilenet_v1_050': mobilenet_v1.mobilenet_v1_arg_scope,
'mobilenet_v1_025': mobilenet_v1.mobilenet_v1_arg_scope,
}
def get_network_fn(name, num_classes, weight_decay=0.0, is_training=False):
"""Returns a network_fn such as `logits, end_points = network_fn(images)`.
Args:
name: The name of the network.
num_classes: The number of classes to use for classification.
weight_decay: The l2 coefficient for the model weights.
is_training: `True` if the model is being used for training and `False`
otherwise.
Returns:
network_fn: A function that applies the model to a batch of images. It has
the following signature:
logits, end_points = network_fn(images)
Raises:
ValueError: If network `name` is not recognized.
"""
if name not in networks_map:
raise ValueError('Name of network unknown %s' % name)
func = networks_map[name]
@functools.wraps(func)
def network_fn(images):
arg_scope = arg_scopes_map[name](weight_decay=weight_decay)
with slim.arg_scope(arg_scope):
return func(images, num_classes, is_training=is_training)
if hasattr(func, 'default_image_size'):
network_fn.default_image_size = func.default_image_size
return network_fn
================================================
FILE: nets/nets_factory_test.py
================================================
# Copyright 2016 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Tests for slim.inception."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import tensorflow as tf
from nets import nets_factory
slim = tf.contrib.slim
class NetworksTest(tf.test.TestCase):
def testGetNetworkFn(self):
batch_size = 5
num_classes = 1000
for net in nets_factory.networks_map:
with self.test_session():
net_fn = nets_factory.get_network_fn(net, num_classes)
# Most networks use 224 as their default_image_size
image_size = getattr(net_fn, 'default_image_size', 224)
inputs = tf.random_uniform((batch_size, image_size, image_size, 3))
logits, end_points = net_fn(inputs)
self.assertTrue(isinstance(logits, tf.Tensor))
self.assertTrue(isinstance(end_points, dict))
self.assertEqual(logits.get_shape().as_list()[0], batch_size)
self.assertEqual(logits.get_shape().as_list()[-1], num_classes)
def testGetNetworkFnArgScope(self):
batch_size = 5
num_classes = 10
net = 'cifarnet'
with self.test_session(use_gpu=True):
net_fn = nets_factory.get_network_fn(net, num_classes)
image_size = getattr(net_fn, 'default_image_size', 224)
with slim.arg_scope([slim.model_variable, slim.variable],
device='/CPU:0'):
inputs = tf.random_uniform((batch_size, image_size, image_size, 3))
net_fn(inputs)
weights = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, 'CifarNet/conv1')[0]
self.assertDeviceEqual('/CPU:0', weights.device)
if __name__ == '__main__':
tf.test.main()
================================================
FILE: nets/overfeat.py
================================================
# Copyright 2016 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Contains the model definition for the OverFeat network.
The definition for the network was obtained from:
OverFeat: Integrated Recognition, Localization and Detection using
Convolutional Networks
Pierre Sermanet, David Eigen, Xiang Zhang, Michael Mathieu, Rob Fergus and
Yann LeCun, 2014
http://arxiv.org/abs/1312.6229
Usage:
with slim.arg_scope(overfeat.overfeat_arg_scope()):
outputs, end_points = overfeat.overfeat(inputs)
@@overfeat
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import tensorflow as tf
slim = tf.contrib.slim
trunc_normal = lambda stddev: tf.truncated_normal_initializer(0.0, stddev)
def overfeat_arg_scope(weight_decay=0.0005):
with slim.arg_scope([slim.conv2d, slim.fully_connected],
activation_fn=tf.nn.relu,
weights_regularizer=slim.l2_regularizer(weight_decay),
biases_initializer=tf.zeros_initializer()):
with slim.arg_scope([slim.conv2d], padding='SAME'):
with slim.arg_scope([slim.max_pool2d], padding='VALID') as arg_sc:
return arg_sc
def overfeat(inputs,
num_classes=1000,
is_training=True,
dropout_keep_prob=0.5,
spatial_squeeze=True,
scope='overfeat'):
"""Contains the model definition for the OverFeat network.
The definition for the network was obtained from:
OverFeat: Integrated Recognition, Localization and Detection using
Convolutional Networks
Pierre Sermanet, David Eigen, Xiang Zhang, Michael Mathieu, Rob Fergus and
Yann LeCun, 2014
http://arxiv.org/abs/1312.6229
Note: All the fully_connected layers have been transformed to conv2d layers.
To use in classification mode, resize input to 231x231. To use in fully
convolutional mode, set spatial_squeeze to false.
Args:
inputs: a tensor of size [batch_size, height, width, channels].
num_classes: number of predicted classes.
is_training: whether or not the model is being trained.
dropout_keep_prob: the probability that activations are kept in the dropout
layers during training.
spatial_squeeze: whether or not should squeeze the spatial dimensions of the
outputs. Useful to remove unnecessary dimensions for classification.
scope: Optional scope for the variables.
Returns:
the last op containing the log predictions and end_points dict.
"""
with tf.variable_scope(scope, 'overfeat', [inputs]) as sc:
end_points_collection = sc.name + '_end_points'
# Collect outputs for conv2d, fully_connected and max_pool2d
with slim.arg_scope([slim.conv2d, slim.fully_connected, slim.max_pool2d],
outputs_collections=end_points_collection):
net = slim.conv2d(inputs, 64, [11, 11], 4, padding='VALID',
scope='conv1')
net = slim.max_pool2d(net, [2, 2], scope='pool1')
net = slim.conv2d(net, 256, [5, 5], padding='VALID', scope='conv2')
net = slim.max_pool2d(net, [2, 2], scope='pool2')
net = slim.conv2d(net, 512, [3, 3], scope='conv3')
net = slim.conv2d(net, 1024, [3, 3], scope='conv4')
net = slim.conv2d(net, 1024, [3, 3], scope='conv5')
net = slim.max_pool2d(net, [2, 2], scope='pool5')
with slim.arg_scope([slim.conv2d],
weights_initializer=trunc_normal(0.005),
biases_initializer=tf.constant_initializer(0.1)):
# Use conv2d instead of fully_connected layers.
net = slim.conv2d(net, 3072, [6, 6], padding='VALID', scope='fc6')
net = slim.dropout(net, dropout_keep_prob, is_training=is_training,
scope='dropout6')
net = slim.conv2d(net, 4096, [1, 1], scope='fc7')
net = slim.dropout(net, dropout_keep_prob, is_training=is_training,
scope='dropout7')
net = slim.conv2d(net, num_classes, [1, 1],
activation_fn=None,
normalizer_fn=None,
biases_initializer=tf.zeros_initializer(),
scope='fc8')
# Convert end_points_collection into a end_point dict.
end_points = slim.utils.convert_collection_to_dict(end_points_collection)
if spatial_squeeze:
net = tf.squeeze(net, [1, 2], name='fc8/squeezed')
end_points[sc.name + '/fc8'] = net
return net, end_points
overfeat.default_image_size = 231
================================================
FILE: nets/overfeat_test.py
================================================
# Copyright 2016 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Tests for slim.nets.overfeat."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import tensorflow as tf
from nets import overfeat
slim = tf.contrib.slim
class OverFeatTest(tf.test.TestCase):
def testBuild(self):
batch_size = 5
height, width = 231, 231
num_classes = 1000
with self.test_session():
inputs = tf.random_uniform((batch_size, height, width, 3))
logits, _ = overfeat.overfeat(inputs, num_classes)
self.assertEquals(logits.op.name, 'overfeat/fc8/squeezed')
self.assertListEqual(logits.get_shape().as_list(),
[batch_size, num_classes])
def testFullyConvolutional(self):
batch_size = 1
height, width = 281, 281
num_classes = 1000
with self.test_session():
inputs = tf.random_uniform((batch_size, height, width, 3))
logits, _ = overfeat.overfeat(inputs, num_classes, spatial_squeeze=False)
self.assertEquals(logits.op.name, 'overfeat/fc8/BiasAdd')
self.assertListEqual(logits.get_shape().as_list(),
[batch_size, 2, 2, num_classes])
def testEndPoints(self):
batch_size = 5
height, width = 231, 231
num_classes = 1000
with self.test_session():
inputs = tf.random_uniform((batch_size, height, width, 3))
_, end_points = overfeat.overfeat(inputs, num_classes)
expected_names = ['overfeat/conv1',
'overfeat/pool1',
'overfeat/conv2',
'overfeat/pool2',
'overfeat/conv3',
'overfeat/conv4',
'overfeat/conv5',
'overfeat/pool5',
'overfeat/fc6',
'overfeat/fc7',
'overfeat/fc8'
]
self.assertSetEqual(set(end_points.keys()), set(expected_names))
def testModelVariables(self):
batch_size = 5
height, width = 231, 231
num_classes = 1000
with self.test_session():
inputs = tf.random_uniform((batch_size, height, width, 3))
overfeat.overfeat(inputs, num_classes)
expected_names = ['overfeat/conv1/weights',
'overfeat/conv1/biases',
'overfeat/conv2/weights',
'overfeat/conv2/biases',
'overfeat/conv3/weights',
'overfeat/conv3/biases',
'overfeat/conv4/weights',
'overfeat/conv4/biases',
'overfeat/conv5/weights',
'overfeat/conv5/biases',
'overfeat/fc6/weights',
'overfeat/fc6/biases',
'overfeat/fc7/weights',
'overfeat/fc7/biases',
'overfeat/fc8/weights',
'overfeat/fc8/biases',
]
model_variables = [v.op.name for v in slim.get_model_variables()]
self.assertSetEqual(set(model_variables), set(expected_names))
def testEvaluation(self):
batch_size = 2
height, width = 231, 231
num_classes = 1000
with self.test_session():
eval_inputs = tf.random_uniform((batch_size, height, width, 3))
logits, _ = overfeat.overfeat(eval_inputs, is_training=False)
self.assertListEqual(logits.get_shape().as_list(),
[batch_size, num_classes])
predictions = tf.argmax(logits, 1)
self.assertListEqual(predictions.get_shape().as_list(), [batch_size])
def testTrainEvalWithReuse(self):
train_batch_size = 2
eval_batch_size = 1
train_height, train_width = 231, 231
eval_height, eval_width = 281, 281
num_classes = 1000
with self.test_session():
train_inputs = tf.random_uniform(
(train_batch_size, train_height, train_width, 3))
logits, _ = overfeat.overfeat(train_inputs)
self.assertListEqual(logits.get_shape().as_list(),
[train_batch_size, num_classes])
tf.get_variable_scope().reuse_variables()
eval_inputs = tf.random_uniform(
(eval_batch_size, eval_height, eval_width, 3))
logits, _ = overfeat.overfeat(eval_inputs, is_training=False,
spatial_squeeze=False)
self.assertListEqual(logits.get_shape().as_list(),
[eval_batch_size, 2, 2, num_classes])
logits = tf.reduce_mean(logits, [1, 2])
predictions = tf.argmax(logits, 1)
self.assertEquals(predictions.get_shape().as_list(), [eval_batch_size])
def testForward(self):
batch_size = 1
height, width = 231, 231
with self.test_session() as sess:
inputs = tf.random_uniform((batch_size, height, width, 3))
logits, _ = overfeat.overfeat(inputs)
sess.run(tf.global_variables_initializer())
output = sess.run(logits)
self.assertTrue(output.any())
if __name__ == '__main__':
tf.test.main()
================================================
FILE: nets/resnet_utils.py
================================================
# Copyright 2016 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Contains building blocks for various versions of Residual Networks.
Residual networks (ResNets) were proposed in:
Kaiming He, Xiangyu Zhang, Shaoqing Ren, Jian Sun
Deep Residual Learning for Image Recognition. arXiv:1512.03385, 2015
More variants were introduced in:
Kaiming He, Xiangyu Zhang, Shaoqing Ren, Jian Sun
Identity Mappings in Deep Residual Networks. arXiv: 1603.05027, 2016
We can obtain different ResNet variants by changing the network depth, width,
and form of residual unit. This module implements the infrastructure for
building them. Concrete ResNet units and full ResNet networks are implemented in
the accompanying resnet_v1.py and resnet_v2.py modules.
Compared to https://github.com/KaimingHe/deep-residual-networks, in the current
implementation we subsample the output activations in the last residual unit of
each block, instead of subsampling the input activations in the first residual
unit of each block. The two implementations give identical results but our
implementation is more memory efficient.
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import collections
import tensorflow as tf
slim = tf.contrib.slim
class Block(collections.namedtuple('Block', ['scope', 'unit_fn', 'args'])):
"""A named tuple describing a ResNet block.
Its parts are:
scope: The scope of the `Block`.
unit_fn: The ResNet unit function which takes as input a `Tensor` and
returns another `Tensor` with the output of the ResNet unit.
args: A list of length equal to the number of units in the `Block`. The list
contains one (depth, depth_bottleneck, stride) tuple for each unit in the
block to serve as argument to unit_fn.
"""
def subsample(inputs, factor, scope=None):
"""Subsamples the input along the spatial dimensions.
Args:
inputs: A `Tensor` of size [batch, height_in, width_in, channels].
factor: The subsampling factor.
scope: Optional variable_scope.
Returns:
output: A `Tensor` of size [batch, height_out, width_out, channels] with the
input, either intact (if factor == 1) or subsampled (if factor > 1).
"""
if factor == 1:
return inputs
else:
return slim.max_pool2d(inputs, [1, 1], stride=factor, scope=scope)
def conv2d_same(inputs, num_outputs, kernel_size, stride, rate=1, scope=None):
"""Strided 2-D convolution with 'SAME' padding.
When stride > 1, then we do explicit zero-padding, followed by conv2d with
'VALID' padding.
Note that
net = conv2d_same(inputs, num_outputs, 3, stride=stride)
is equivalent to
net = slim.conv2d(inputs, num_outputs, 3, stride=1, padding='SAME')
net = subsample(net, factor=stride)
whereas
net = slim.conv2d(inputs, num_outputs, 3, stride=stride, padding='SAME')
is different when the input's height or width is even, which is why we add the
current function. For more details, see ResnetUtilsTest.testConv2DSameEven().
Args:
inputs: A 4-D tensor of size [batch, height_in, width_in, channels].
num_outputs: An integer, the number of output filters.
kernel_size: An int with the kernel_size of the filters.
stride: An integer, the output stride.
rate: An integer, rate for atrous convolution.
scope: Scope.
Returns:
output: A 4-D tensor of size [batch, height_out, width_out, channels] with
the convolution output.
"""
if stride == 1:
return slim.conv2d(inputs, num_outputs, kernel_size, stride=1, rate=rate,
padding='SAME', scope=scope)
else:
kernel_size_effective = kernel_size + (kernel_size - 1) * (rate - 1)
pad_total = kernel_size_effective - 1
pad_beg = pad_total // 2
pad_end = pad_total - pad_beg
inputs = tf.pad(inputs,
[[0, 0], [pad_beg, pad_end], [pad_beg, pad_end], [0, 0]])
return slim.conv2d(inputs, num_outputs, kernel_size, stride=stride,
rate=rate, padding='VALID', scope=scope)
@slim.add_arg_scope
def stack_blocks_dense(net, blocks, output_stride=None,
outputs_collections=None):
"""Stacks ResNet `Blocks` and controls output feature density.
First, this function creates scopes for the ResNet in the form of
'block_name/unit_1', 'block_name/unit_2', etc.
Second, this function allows the user to explicitly control the ResNet
output_stride, which is the ratio of the input to output spatial resolution.
This is useful for dense prediction tasks such as semantic segmentation or
object detection.
Most ResNets consist of 4 ResNet blocks and subsample the activations by a
factor of 2 when transitioning between consecutive ResNet blocks. This results
to a nominal ResNet output_stride equal to 8. If we set the output_stride to
half the nominal network stride (e.g., output_stride=4), then we compute
responses twice.
Control of the output feature density is implemented by atrous convolution.
Args:
net: A `Tensor` of size [batch, height, width, channels].
blocks: A list of length equal to the number of ResNet `Blocks`. Each
element is a ResNet `Block` object describing the units in the `Block`.
output_stride: If `None`, then the output will be computed at the nominal
network stride. If output_stride is not `None`, it specifies the requested
ratio of input to output spatial resolution, which needs to be equal to
the product of unit strides from the start up to some level of the ResNet.
For example, if the ResNet employs units with strides 1, 2, 1, 3, 4, 1,
then valid values for the output_stride are 1, 2, 6, 24 or None (which
is equivalent to output_stride=24).
outputs_collections: Collection to add the ResNet block outputs.
Returns:
net: Output tensor with stride equal to the specified output_stride.
Raises:
ValueError: If the target output_stride is not valid.
"""
# The current_stride variable keeps track of the effective stride of the
# activations. This allows us to invoke atrous convolution whenever applying
# the next residual unit would result in the activations having stride larger
# than the target output_stride.
current_stride = 1
# The atrous convolution rate parameter.
rate = 1
for block in blocks:
with tf.variable_scope(block.scope, 'block', [net]) as sc:
for i, unit in enumerate(block.args):
if output_stride is not None and current_stride > output_stride:
raise ValueError('The target output_stride cannot be reached.')
with tf.variable_scope('unit_%d' % (i + 1), values=[net]):
# If we have reached the target output_stride, then we need to employ
# atrous convolution with stride=1 and multiply the atrous rate by the
# current unit's stride for use in subsequent layers.
if output_stride is not None and current_stride == output_stride:
net = block.unit_fn(net, rate=rate, **dict(unit, stride=1))
rate *= unit.get('stride', 1)
else:
net = block.unit_fn(net, rate=1, **unit)
current_stride *= unit.get('stride', 1)
net = slim.utils.collect_named_outputs(outputs_collections, sc.name, net)
if output_stride is not None and current_stride != output_stride:
raise ValueError('The target output_stride cannot be reached.')
return net
def resnet_arg_scope(weight_decay=0.0001,
batch_norm_decay=0.997,
batch_norm_epsilon=1e-5,
batch_norm_scale=True,
activation_fn=tf.nn.relu,
use_batch_norm=True):
"""Defines the default ResNet arg scope.
TODO(gpapan): The batch-normalization related default values above are
appropriate for use in conjunction with the reference ResNet models
released at https://github.com/KaimingHe/deep-residual-networks. When
training ResNets from scratch, they might need to be tuned.
Args:
weight_decay: The weight decay to use for regularizing the model.
batch_norm_decay: The moving average decay when estimating layer activation
statistics in batch normalization.
batch_norm_epsilon: Small constant to prevent division by zero when
normalizing activations by their variance in batch normalization.
batch_norm_scale: If True, uses an explicit `gamma` multiplier to scale the
activations in the batch normalization layer.
activation_fn: The activation function which is used in ResNet.
use_batch_norm: Whether or not to use batch normalization.
Returns:
An `arg_scope` to use for the resnet models.
"""
batch_norm_params = {
'decay': batch_norm_decay,
'epsilon': batch_norm_epsilon,
'scale': batch_norm_scale,
'updates_collections': tf.GraphKeys.UPDATE_OPS,
}
with slim.arg_scope(
[slim.conv2d],
weights_regularizer=slim.l2_regularizer(weight_decay),
weights_initializer=slim.variance_scaling_initializer(),
activation_fn=activation_fn,
normalizer_fn=slim.batch_norm if use_batch_norm else None,
normalizer_params=batch_norm_params):
with slim.arg_scope([slim.batch_norm], **batch_norm_params):
# The following implies padding='SAME' for pool1, which makes feature
# alignment easier for dense prediction tasks. This is also used in
# https://github.com/facebook/fb.resnet.torch. However the accompanying
# code of 'Deep Residual Learning for Image Recognition' uses
# padding='VALID' for pool1. You can switch to that choice by setting
# slim.arg_scope([slim.max_pool2d], padding='VALID').
with slim.arg_scope([slim.max_pool2d], padding='SAME') as arg_sc:
return arg_sc
================================================
FILE: nets/resnet_v1.py
================================================
# Copyright 2016 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Contains definitions for the original form of Residual Networks.
The 'v1' residual networks (ResNets) implemented in this module were proposed
by:
[1] Kaiming He, Xiangyu Zhang, Shaoqing Ren, Jian Sun
Deep Residual Learning for Image Recognition. arXiv:1512.03385
Other variants were introduced in:
[2] Kaiming He, Xiangyu Zhang, Shaoqing Ren, Jian Sun
Identity Mappings in Deep Residual Networks. arXiv: 1603.05027
The networks defined in this module utilize the bottleneck building block of
[1] with projection shortcuts only for increasing depths. They employ batch
normalization *after* every weight layer. This is the architecture used by
MSRA in the Imagenet and MSCOCO 2016 competition models ResNet-101 and
ResNet-152. See [2; Fig. 1a] for a comparison between the current 'v1'
architecture and the alternative 'v2' architecture of [2] which uses batch
normalization *before* every weight layer in the so-called full pre-activation
units.
Typical use:
from tensorflow.contrib.slim.nets import resnet_v1
ResNet-101 for image classification into 1000 classes:
# inputs has shape [batch, 224, 224, 3]
with slim.arg_scope(resnet_v1.resnet_arg_scope()):
net, end_points = resnet_v1.resnet_v1_101(inputs, 1000, is_training=False)
ResNet-101 for semantic segmentation into 21 classes:
# inputs has shape [batch, 513, 513, 3]
with slim.arg_scope(resnet_v1.resnet_arg_scope()):
net, end_points = resnet_v1.resnet_v1_101(inputs,
21,
is_training=False,
global_pool=False,
output_stride=16)
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import tensorflow as tf
from nets import resnet_utils
resnet_arg_scope = resnet_utils.resnet_arg_scope
slim = tf.contrib.slim
@slim.add_arg_scope
def bottleneck(inputs,
depth,
depth_bottleneck,
stride,
rate=1,
outputs_collections=None,
scope=None,
use_bounded_activations=False):
"""Bottleneck residual unit variant with BN after convolutions.
This is the original residual unit proposed in [1]. See Fig. 1(a) of [2] for
its definition. Note that we use here the bottleneck variant which has an
extra bottleneck layer.
When putting together two consecutive ResNet blocks that use this unit, one
should use stride = 2 in the last unit of the first block.
Args:
inputs: A tensor of size [batch, height, width, channels].
depth: The depth of the ResNet unit output.
depth_bottleneck: The depth of the bottleneck layers.
stride: The ResNet unit's stride. Determines the amount of downsampling of
the units output compared to its input.
rate: An integer, rate for atrous convolution.
outputs_collections: Collection to add the ResNet unit output.
scope: Optional variable_scope.
use_bounded_activations: Whether or not to use bounded activations. Bounded
activations better lend themselves to quantized inference.
Returns:
The ResNet unit's output.
"""
with tf.variable_scope(scope, 'bottleneck_v1', [inputs]) as sc:
depth_in = slim.utils.last_dimension(inputs.get_shape(), min_rank=4)
if depth == depth_in:
shortcut = resnet_utils.subsample(inputs, stride, 'shortcut')
else:
shortcut = slim.conv2d(
inputs,
depth, [1, 1],
stride=stride,
activation_fn=tf.nn.relu6 if use_bounded_activations else None,
scope='shortcut')
residual = slim.conv2d(inputs, depth_bottleneck, [1, 1], stride=1,
scope='conv1')
residual = resnet_utils.conv2d_same(residual, depth_bottleneck, 3, stride,
rate=rate, scope='conv2')
residual = slim.conv2d(residual, depth, [1, 1], stride=1,
activation_fn=None, scope='conv3')
if use_bounded_activations:
# Use clip_by_value to simulate bandpass activation.
residual = tf.clip_by_value(residual, -6.0, 6.0)
output = tf.nn.relu6(shortcut + residual)
else:
output = tf.nn.relu(shortcut + residual)
return slim.utils.collect_named_outputs(outputs_collections,
sc.original_name_scope,
output)
def resnet_v1(inputs,
blocks,
num_classes=None,
is_training=True,
global_pool=True,
output_stride=None,
include_root_block=True,
spatial_squeeze=True,
reuse=None,
scope=None):
"""Generator for v1 ResNet models.
This function generates a family of ResNet v1 models. See the resnet_v1_*()
methods for specific model instantiations, obtained by selecting different
block instantiations that produce ResNets of various depths.
Training for image classification on Imagenet is usually done with [224, 224]
inputs, resulting in [7, 7] feature maps at the output of the last ResNet
block for the ResNets defined in [1] that have nominal stride equal to 32.
However, for dense prediction tasks we advise that one uses inputs with
spatial dimensions that are multiples of 32 plus 1, e.g., [321, 321]. In
this case the feature maps at the ResNet output will have spatial shape
[(height - 1) / output_stride + 1, (width - 1) / output_stride + 1]
and corners exactly aligned with the input image corners, which greatly
facilitates alignment of the features to the image. Using as input [225, 225]
images results in [8, 8] feature maps at the output of the last ResNet block.
For dense prediction tasks, the ResNet needs to run in fully-convolutional
(FCN) mode and global_pool needs to be set to False. The ResNets in [1, 2] all
have nominal stride equal to 32 and a good choice in FCN mode is to use
output_stride=16 in order to increase the density of the computed features at
small computational and memory overhead, cf. http://arxiv.org/abs/1606.00915.
Args:
inputs: A tensor of size [batch, height_in, width_in, channels].
blocks: A list of length equal to the number of ResNet blocks. Each element
is a resnet_utils.Block object describing the units in the block.
num_classes: Number of predicted classes for classification tasks. If None
we return the features before the logit layer.
is_training: whether is training or not.
global_pool: If True, we perform global average pooling before computing the
logits. Set to True for image classification, False for dense prediction.
output_stride: If None, then the output will be computed at the nominal
network stride. If output_stride is not None, it specifies the requested
ratio of input to output spatial resolution.
include_root_block: If True, include the initial convolution followed by
max-pooling, if False excludes it.
spatial_squeeze: if True, logits is of shape [B, C], if false logits is
of shape [B, 1, 1, C], where B is batch_size and C is number of classes.
To use this parameter, the input images must be smaller than 300x300
pixels, in which case the output logit layer does not contain spatial
information and can be removed.
reuse: whether or not the network and its variables should be reused. To be
able to reuse 'scope' must be given.
scope: Optional variable_scope.
Returns:
net: A rank-4 tensor of size [batch, height_out, width_out, channels_out].
If global_pool is False, then height_out and width_out are reduced by a
factor of output_stride compared to the respective height_in and width_in,
else both height_out and width_out equal one. If num_classes is None, then
net is the output of the last ResNet block, potentially after global
average pooling. If num_classes is not None, net contains the pre-softmax
activations.
end_points: A dictionary from components of the network to the corresponding
activation.
Raises:
ValueError: If the target output_stride is not valid.
"""
with tf.variable_scope(scope, 'resnet_v1', [inputs], reuse=reuse) as sc:
end_points_collection = sc.name + '_end_points'
with slim.arg_scope([slim.conv2d, bottleneck,
resnet_utils.stack_blocks_dense],
outputs_collections=end_points_collection):
with slim.arg_scope([slim.batch_norm], is_training=is_training):
net = inputs
if include_root_block:
if output_stride is not None:
if output_stride % 4 != 0:
raise ValueError('The output_stride needs to be a multiple of 4.')
output_stride /= 4
net = resnet_utils.conv2d_same(net, 64, 7, stride=2, scope='conv1')
net = slim.max_pool2d(net, [3, 3], stride=2, scope='pool1')
net = resnet_utils.stack_blocks_dense(net, blocks, output_stride)
if global_pool:
# Global average pooling.
net = tf.reduce_mean(net, [1, 2], name='pool5', keep_dims=True)
if num_classes is not None:
net = slim.conv2d(net, num_classes, [1, 1], activation_fn=None,
normalizer_fn=None, scope='logits')
if spatial_squeeze:
net = tf.squeeze(net, [1, 2], name='SpatialSqueeze')
# Convert end_points_collection into a dictionary of end_points.
end_points = slim.utils.convert_collection_to_dict(
end_points_collection)
if num_classes is not None:
end_points['predictions'] = slim.softmax(net, scope='predictions')
return net, end_points
resnet_v1.default_image_size = 224
def resnet_v1_block(scope, base_depth, num_units, stride):
"""Helper function for creating a resnet_v1 bottleneck block.
Args:
scope: The scope of the block.
base_depth: The depth of the bottleneck layer for each unit.
num_units: The number of units in the block.
stride: The stride of the block, implemented as a stride in the last unit.
All other units have stride=1.
Returns:
A resnet_v1 bottleneck block.
"""
return resnet_utils.Block(scope, bottleneck, [{
'depth': base_depth * 4,
'depth_bottleneck': base_depth,
'stride': 1
}] * (num_units - 1) + [{
'depth': base_depth * 4,
'depth_bottleneck': base_depth,
'stride': stride
}])
def resnet_v1_50(inputs,
num_classes=None,
is_training=True,
global_pool=True,
output_stride=None,
spatial_squeeze=True,
reuse=None,
scope='resnet_v1_50'):
"""ResNet-50 model of [1]. See resnet_v1() for arg and return description."""
blocks = [
resnet_v1_block('block1', base_depth=64, num_units=3, stride=2),
resnet_v1_block('block2', base_depth=128, num_units=4, stride=2),
resnet_v1_block('block3', base_depth=256, num_units=6, stride=2),
resnet_v1_block('block4', base_depth=512, num_units=3, stride=1),
]
return resnet_v1(inputs, blocks, num_classes, is_training,
global_pool=global_pool, output_stride=output_stride,
include_root_block=True, spatial_squeeze=spatial_squeeze,
reuse=reuse, scope=scope)
resnet_v1_50.default_image_size = resnet_v1.default_image_size
def resnet_v1_101(inputs,
num_classes=None,
is_training=True,
global_pool=True,
output_stride=None,
spatial_squeeze=True,
reuse=None,
scope='resnet_v1_101'):
"""ResNet-101 model of [1]. See resnet_v1() for arg and return description."""
blocks = [
resnet_v1_block('block1', base_depth=64, num_units=3, stride=2),
resnet_v1_block('block2', base_depth=128, num_units=4, stride=2),
resnet_v1_block('block3', base_depth=256, num_units=23, stride=2),
resnet_v1_block('block4', base_depth=512, num_units=3, stride=1),
]
return resnet_v1(inputs, blocks, num_classes, is_training,
global_pool=global_pool, output_stride=output_stride,
include_root_block=True, spatial_squeeze=spatial_squeeze,
reuse=reuse, scope=scope)
resnet_v1_101.default_image_size = resnet_v1.default_image_size
def resnet_v1_152(inputs,
num_classes=None,
is_training=True,
global_pool=True,
output_stride=None,
spatial_squeeze=True,
reuse=None,
scope='resnet_v1_152'):
"""ResNet-152 model of [1]. See resnet_v1() for arg and return description."""
blocks = [
resnet_v1_block('block1', base_depth=64, num_units=3, stride=2),
resnet_v1_block('block2', base_depth=128, num_units=8, stride=2),
resnet_v1_block('block3', base_depth=256, num_units=36, stride=2),
resnet_v1_block('block4', base_depth=512, num_units=3, stride=1),
]
return resnet_v1(inputs, blocks, num_classes, is_training,
global_pool=global_pool, output_stride=output_stride,
include_root_block=True, spatial_squeeze=spatial_squeeze,
reuse=reuse, scope=scope)
resnet_v1_152.default_image_size = resnet_v1.default_image_size
def resnet_v1_200(inputs,
num_classes=None,
is_training=True,
global_pool=True,
output_stride=None,
spatial_squeeze=True,
reuse=None,
scope='resnet_v1_200'):
"""ResNet-200 model of [2]. See resnet_v1() for arg and return description."""
blocks = [
resnet_v1_block('block1', base_depth=64, num_units=3, stride=2),
resnet_v1_block('block2', base_depth=128, num_units=24, stride=2),
resnet_v1_block('block3', base_depth=256, num_units=36, stride=2),
resnet_v1_block('block4', base_depth=512, num_units=3, stride=1),
]
return resnet_v1(inputs, blocks, num_classes, is_training,
global_pool=global_pool, output_stride=output_stride,
include_root_block=True, spatial_squeeze=spatial_squeeze,
reuse=reuse, scope=scope)
resnet_v1_200.default_image_size = resnet_v1.default_image_size
================================================
FILE: nets/resnet_v1_test.py
================================================
# Copyright 2016 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Tests for slim.nets.resnet_v1."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import numpy as np
import tensorflow as tf
from nets import resnet_utils
from nets import resnet_v1
slim = tf.contrib.slim
def create_test_input(batch_size, height, width, channels):
"""Create test input tensor.
Args:
batch_size: The number of images per batch or `None` if unknown.
height: The height of each image or `None` if unknown.
width: The width of each image or `None` if unknown.
channels: The number of channels per image or `None` if unknown.
Returns:
Either a placeholder `Tensor` of dimension
[batch_size, height, width, channels] if any of the inputs are `None` or a
constant `Tensor` with the mesh grid values along the spatial dimensions.
"""
if None in [batch_size, height, width, channels]:
return tf.placeholder(tf.float32, (batch_size, height, width, channels))
else:
return tf.to_float(
np.tile(
np.reshape(
np.reshape(np.arange(height), [height, 1]) +
np.reshape(np.arange(width), [1, width]),
[1, height, width, 1]),
[batch_size, 1, 1, channels]))
class ResnetUtilsTest(tf.test.TestCase):
def testSubsampleThreeByThree(self):
x = tf.reshape(tf.to_float(tf.range(9)), [1, 3, 3, 1])
x = resnet_utils.subsample(x, 2)
expected = tf.reshape(tf.constant([0, 2, 6, 8]), [1, 2, 2, 1])
with self.test_session():
self.assertAllClose(x.eval(), expected.eval())
def testSubsampleFourByFour(self):
x = tf.reshape(tf.to_float(tf.range(16)), [1, 4, 4, 1])
x = resnet_utils.subsample(x, 2)
expected = tf.reshape(tf.constant([0, 2, 8, 10]), [1, 2, 2, 1])
with self.test_session():
self.assertAllClose(x.eval(), expected.eval())
def testConv2DSameEven(self):
n, n2 = 4, 2
# Input image.
x = create_test_input(1, n, n, 1)
# Convolution kernel.
w = create_test_input(1, 3, 3, 1)
w = tf.reshape(w, [3, 3, 1, 1])
tf.get_variable('Conv/weights', initializer=w)
tf.get_variable('Conv/biases', initializer=tf.zeros([1]))
tf.get_variable_scope().reuse_variables()
y1 = slim.conv2d(x, 1, [3, 3], stride=1, scope='Conv')
y1_expected = tf.to_float([[14, 28, 43, 26],
[28, 48, 66, 37],
[43, 66, 84, 46],
[26, 37, 46, 22]])
y1_expected = tf.reshape(y1_expected, [1, n, n, 1])
y2 = resnet_utils.subsample(y1, 2)
y2_expected = tf.to_float([[14, 43],
[43, 84]])
y2_expected = tf.reshape(y2_expected, [1, n2, n2, 1])
y3 = resnet_utils.conv2d_same(x, 1, 3, stride=2, scope='Conv')
y3_expected = y2_expected
y4 = slim.conv2d(x, 1, [3, 3], stride=2, scope='Conv')
y4_expected = tf.to_float([[48, 37],
[37, 22]])
y4_expected = tf.reshape(y4_expected, [1, n2, n2, 1])
with self.test_session() as sess:
sess.run(tf.global_variables_initializer())
self.assertAllClose(y1.eval(), y1_expected.eval())
self.assertAllClose(y2.eval(), y2_expected.eval())
self.assertAllClose(y3.eval(), y3_expected.eval())
self.assertAllClose(y4.eval(), y4_expected.eval())
def testConv2DSameOdd(self):
n, n2 = 5, 3
# Input image.
x = create_test_input(1, n, n, 1)
# Convolution kernel.
w = create_test_input(1, 3, 3, 1)
w = tf.reshape(w, [3, 3, 1, 1])
tf.get_variable('Conv/weights', initializer=w)
tf.get_variable('Conv/biases', initializer=tf.zeros([1]))
tf.get_variable_scope().reuse_variables()
y1 = slim.conv2d(x, 1, [3, 3], stride=1, scope='Conv')
y1_expected = tf.to_float([[14, 28, 43, 58, 34],
[28, 48, 66, 84, 46],
[43, 66, 84, 102, 55],
[58, 84, 102, 120, 64],
[34, 46, 55, 64, 30]])
y1_expected = tf.reshape(y1_expected, [1, n, n, 1])
y2 = resnet_utils.subsample(y1, 2)
y2_expected = tf.to_float([[14, 43, 34],
[43, 84, 55],
[34, 55, 30]])
y2_expected = tf.reshape(y2_expected, [1, n2, n2, 1])
y3 = resnet_utils.conv2d_same(x, 1, 3, stride=2, scope='Conv')
y3_expected = y2_expected
y4 = slim.conv2d(x, 1, [3, 3], stride=2, scope='Conv')
y4_expected = y2_expected
with self.test_session() as sess:
sess.run(tf.global_variables_initializer())
self.assertAllClose(y1.eval(), y1_expected.eval())
self.assertAllClose(y2.eval(), y2_expected.eval())
self.assertAllClose(y3.eval(), y3_expected.eval())
self.assertAllClose(y4.eval(), y4_expected.eval())
def _resnet_plain(self, inputs, blocks, output_stride=None, scope=None):
"""A plain ResNet without extra layers before or after the ResNet blocks."""
with tf.variable_scope(scope, values=[inputs]):
with slim.arg_scope([slim.conv2d], outputs_collections='end_points'):
net = resnet_utils.stack_blocks_dense(inputs, blocks, output_stride)
end_points = slim.utils.convert_collection_to_dict('end_points')
return net, end_points
def testEndPointsV1(self):
"""Test the end points of a tiny v1 bottleneck network."""
blocks = [
resnet_v1.resnet_v1_block(
'block1', base_depth=1, num_units=2, stride=2),
resnet_v1.resnet_v1_block(
'block2', base_depth=2, num_units=2, stride=1),
]
inputs = create_test_input(2, 32, 16, 3)
with slim.arg_scope(resnet_utils.resnet_arg_scope()):
_, end_points = self._resnet_plain(inputs, blocks, scope='tiny')
expected = [
'tiny/block1/unit_1/bottleneck_v1/shortcut',
'tiny/block1/unit_1/bottleneck_v1/conv1',
'tiny/block1/unit_1/bottleneck_v1/conv2',
'tiny/block1/unit_1/bottleneck_v1/conv3',
'tiny/block1/unit_2/bottleneck_v1/conv1',
'tiny/block1/unit_2/bottleneck_v1/conv2',
'tiny/block1/unit_2/bottleneck_v1/conv3',
'tiny/block2/unit_1/bottleneck_v1/shortcut',
'tiny/block2/unit_1/bottleneck_v1/conv1',
'tiny/block2/unit_1/bottleneck_v1/conv2',
'tiny/block2/unit_1/bottleneck_v1/conv3',
'tiny/block2/unit_2/bottleneck_v1/conv1',
'tiny/block2/unit_2/bottleneck_v1/conv2',
'tiny/block2/unit_2/bottleneck_v1/conv3']
self.assertItemsEqual(expected, end_points)
def _stack_blocks_nondense(self, net, blocks):
"""A simplified ResNet Block stacker without output stride control."""
for block in blocks:
with tf.variable_scope(block.scope, 'block', [net]):
for i, unit in enumerate(block.args):
with tf.variable_scope('unit_%d' % (i + 1), values=[net]):
net = block.unit_fn(net, rate=1, **unit)
return net
def testAtrousValuesBottleneck(self):
"""Verify the values of dense feature extraction by atrous convolution.
Make sure that dense feature extraction by stack_blocks_dense() followed by
subsampling gives identical results to feature extraction at the nominal
network output stride using the simple self._stack_blocks_nondense() above.
"""
block = resnet_v1.resnet_v1_block
blocks = [
block('block1', base_depth=1, num_units=2, stride=2),
block('block2', base_depth=2, num_units=2, stride=2),
block('block3', base_depth=4, num_units=2, stride=2),
block('block4', base_depth=8, num_units=2, stride=1),
]
nominal_stride = 8
# Test both odd and even input dimensions.
height = 30
width = 31
with slim.arg_scope(resnet_utils.resnet_arg_scope()):
with slim.arg_scope([slim.batch_norm], is_training=False):
for output_stride in [1, 2, 4, 8, None]:
with tf.Graph().as_default():
with self.test_session() as sess:
tf.set_random_seed(0)
inputs = create_test_input(1, height, width, 3)
# Dense feature extraction followed by subsampling.
output = resnet_utils.stack_blocks_dense(inputs,
blocks,
output_stride)
if output_stride is None:
factor = 1
else:
factor = nominal_stride // output_stride
output = resnet_utils.subsample(output, factor)
# Make the two networks use the same weights.
tf.get_variable_scope().reuse_variables()
# Feature extraction at the nominal network rate.
expected = self._stack_blocks_nondense(inputs, blocks)
sess.run(tf.global_variables_initializer())
output, expected = sess.run([output, expected])
self.assertAllClose(output, expected, atol=1e-4, rtol=1e-4)
class ResnetCompleteNetworkTest(tf.test.TestCase):
"""Tests with complete small ResNet v1 networks."""
def _resnet_small(self,
inputs,
num_classes=None,
is_training=True,
global_pool=True,
output_stride=None,
include_root_block=True,
spatial_squeeze=True,
reuse=None,
scope='resnet_v1_small'):
"""A shallow and thin ResNet v1 for faster tests."""
block = resnet_v1.resnet_v1_block
blocks = [
block('block1', base_depth=1, num_units=3, stride=2),
block('block2', base_depth=2, num_units=3, stride=2),
block('block3', base_depth=4, num_units=3, stride=2),
block('block4', base_depth=8, num_units=2, stride=1),
]
return resnet_v1.resnet_v1(inputs, blocks, num_classes,
is_training=is_training,
global_pool=global_pool,
output_stride=output_stride,
include_root_block=include_root_block,
spatial_squeeze=spatial_squeeze,
reuse=reuse,
scope=scope)
def testClassificationEndPoints(self):
global_pool = True
num_classes = 10
inputs = create_test_input(2, 224, 224, 3)
with slim.arg_scope(resnet_utils.resnet_arg_scope()):
logits, end_points = self._resnet_small(inputs, num_classes,
global_pool=global_pool,
spatial_squeeze=False,
scope='resnet')
self.assertTrue(logits.op.name.startswith('resnet/logits'))
self.assertListEqual(logits.get_shape().as_list(), [2, 1, 1, num_classes])
self.assertTrue('predictions' in end_points)
self.assertListEqual(end_points['predictions'].get_shape().as_list(),
[2, 1, 1, num_classes])
def testClassificationShapes(self):
global_pool = True
num_classes = 10
inputs = create_test_input(2, 224, 224, 3)
with slim.arg_scope(resnet_utils.resnet_arg_scope()):
_, end_points = self._resnet_small(inputs, num_classes,
global_pool=global_pool,
scope='resnet')
endpoint_to_shape = {
'resnet/block1': [2, 28, 28, 4],
'resnet/block2': [2, 14, 14, 8],
'resnet/block3': [2, 7, 7, 16],
'resnet/block4': [2, 7, 7, 32]}
for endpoint in endpoint_to_shape:
shape = endpoint_to_shape[endpoint]
self.assertListEqual(end_points[endpoint].get_shape().as_list(), shape)
def testFullyConvolutionalEndpointShapes(self):
global_pool = False
num_classes = 10
inputs = create_test_input(2, 321, 321, 3)
with slim.arg_scope(resnet_utils.resnet_arg_scope()):
_, end_points = self._resnet_small(inputs, num_classes,
global_pool=global_pool,
spatial_squeeze=False,
scope='resnet')
endpoint_to_shape = {
'resnet/block1': [2, 41, 41, 4],
'resnet/block2': [2, 21, 21, 8],
'resnet/block3': [2, 11, 11, 16],
'resnet/block4': [2, 11, 11, 32]}
for endpoint in endpoint_to_shape:
shape = endpoint_to_shape[endpoint]
self.assertListEqual(end_points[endpoint].get_shape().as_list(), shape)
def testRootlessFullyConvolutionalEndpointShapes(self):
global_pool = False
num_classes = 10
inputs = create_test_input(2, 128, 128, 3)
with slim.arg_scope(resnet_utils.resnet_arg_scope()):
_, end_points = self._resnet_small(inputs, num_classes,
global_pool=global_pool,
include_root_block=False,
spatial_squeeze=False,
scope='resnet')
endpoint_to_shape = {
'resnet/block1': [2, 64, 64, 4],
'resnet/block2': [2, 32, 32, 8],
'resnet/block3': [2, 16, 16, 16],
'resnet/block4': [2, 16, 16, 32]}
for endpoint in endpoint_to_shape:
shape = endpoint_to_shape[endpoint]
self.assertListEqual(end_points[endpoint].get_shape().as_list(), shape)
def testAtrousFullyConvolutionalEndpointShapes(self):
global_pool = False
num_classes = 10
output_stride = 8
inputs = create_test_input(2, 321, 321, 3)
with slim.arg_scope(resnet_utils.resnet_arg_scope()):
_, end_points = self._resnet_small(inputs,
num_classes,
global_pool=global_pool,
output_stride=output_stride,
spatial_squeeze=False,
scope='resnet')
endpoint_to_shape = {
'resnet/block1': [2, 41, 41, 4],
'resnet/block2': [2, 41, 41, 8],
'resnet/block3': [2, 41, 41, 16],
'resnet/block4': [2, 41, 41, 32]}
for endpoint in endpoint_to_shape:
shape = endpoint_to_shape[endpoint]
self.assertListEqual(end_points[endpoint].get_shape().as_list(), shape)
def testAtrousFullyConvolutionalValues(self):
"""Verify dense feature extraction with atrous convolution."""
nominal_stride = 32
for output_stride in [4, 8, 16, 32, None]:
with slim.arg_scope(resnet_utils.resnet_arg_scope()):
with tf.Graph().as_default():
with self.test_session() as sess:
tf.set_random_seed(0)
inputs = create_test_input(2, 81, 81, 3)
# Dense feature extraction followed by subsampling.
output, _ = self._resnet_small(inputs, None, is_training=False,
global_pool=False,
output_stride=output_stride)
if output_stride is None:
factor = 1
else:
factor = nominal_stride // output_stride
output = resnet_utils.subsample(output, factor)
# Make the two networks use the same weights.
tf.get_variable_scope().reuse_variables()
# Feature extraction at the nominal network rate.
expected, _ = self._resnet_small(inputs, None, is_training=False,
global_pool=False)
sess.run(tf.global_variables_initializer())
self.assertAllClose(output.eval(), expected.eval(),
atol=1e-4, rtol=1e-4)
def testUnknownBatchSize(self):
batch = 2
height, width = 65, 65
global_pool = True
num_classes = 10
inputs = create_test_input(None, height, width, 3)
with slim.arg_scope(resnet_utils.resnet_arg_scope()):
logits, _ = self._resnet_small(inputs, num_classes,
global_pool=global_pool,
spatial_squeeze=False,
scope='resnet')
self.assertTrue(logits.op.name.startswith('resnet/logits'))
self.assertListEqual(logits.get_shape().as_list(),
[None, 1, 1, num_classes])
images = create_test_input(batch, height, width, 3)
with self.test_session() as sess:
sess.run(tf.global_variables_initializer())
output = sess.run(logits, {inputs: images.eval()})
self.assertEqual(output.shape, (batch, 1, 1, num_classes))
def testFullyConvolutionalUnknownHeightWidth(self):
batch = 2
height, width = 65, 65
global_pool = False
inputs = create_test_input(batch, None, None, 3)
with slim.arg_scope(resnet_utils.resnet_arg_scope()):
output, _ = self._resnet_small(inputs, None, global_pool=global_pool)
self.assertListEqual(output.get_shape().as_list(),
[batch, None, None, 32])
images = create_test_input(batch, height, width, 3)
with self.test_session() as sess:
sess.run(tf.global_variables_initializer())
output = sess.run(output, {inputs: images.eval()})
self.assertEqual(output.shape, (batch, 3, 3, 32))
def testAtrousFullyConvolutionalUnknownHeightWidth(self):
batch = 2
height, width = 65, 65
global_pool = False
output_stride = 8
inputs = create_test_input(batch, None, None, 3)
with slim.arg_scope(resnet_utils.resnet_arg_scope()):
output, _ = self._resnet_small(inputs,
None,
global_pool=global_pool,
output_stride=output_stride)
self.assertListEqual(output.get_shape().as_list(),
[batch, None, None, 32])
images = create_test_input(batch, height, width, 3)
with self.test_session() as sess:
sess.run(tf.global_variables_initializer())
output = sess.run(output, {inputs: images.eval()})
self.assertEqual(output.shape, (batch, 9, 9, 32))
if __name__ == '__main__':
tf.test.main()
================================================
FILE: nets/resnet_v2.py
================================================
# Copyright 2016 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Contains definitions for the preactivation form of Residual Networks.
Residual networks (ResNets) were originally proposed in:
[1] Kaiming He, Xiangyu Zhang, Shaoqing Ren, Jian Sun
Deep Residual Learning for Image Recognition. arXiv:1512.03385
The full preactivation 'v2' ResNet variant implemented in this module was
introduced by:
[2] Kaiming He, Xiangyu Zhang, Shaoqing Ren, Jian Sun
Identity Mappings in Deep Residual Networks. arXiv: 1603.05027
The key difference of the full preactivation 'v2' variant compared to the
'v1' variant in [1] is the use of batch normalization before every weight layer.
Typical use:
from tensorflow.contrib.slim.nets import resnet_v2
ResNet-101 for image classification into 1000 classes:
# inputs has shape [batch, 224, 224, 3]
with slim.arg_scope(resnet_v2.resnet_arg_scope()):
net, end_points = resnet_v2.resnet_v2_101(inputs, 1000, is_training=False)
ResNet-101 for semantic segmentation into 21 classes:
# inputs has shape [batch, 513, 513, 3]
with slim.arg_scope(resnet_v2.resnet_arg_scope(is_training)):
net, end_points = resnet_v2.resnet_v2_101(inputs,
21,
is_training=False,
global_pool=False,
output_stride=16)
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import tensorflow as tf
from nets import resnet_utils
slim = tf.contrib.slim
resnet_arg_scope = resnet_utils.resnet_arg_scope
@slim.add_arg_scope
def bottleneck(inputs, depth, depth_bottleneck, stride, rate=1,
outputs_collections=None, scope=None):
"""Bottleneck residual unit variant with BN before convolutions.
This is the full preactivation residual unit variant proposed in [2]. See
Fig. 1(b) of [2] for its definition. Note that we use here the bottleneck
variant which has an extra bottleneck layer.
When putting together two consecutive ResNet blocks that use this unit, one
should use stride = 2 in the last unit of the first block.
Args:
inputs: A tensor of size [batch, height, width, channels].
depth: The depth of the ResNet unit output.
depth_bottleneck: The depth of the bottleneck layers.
stride: The ResNet unit's stride. Determines the amount of downsampling of
the units output compared to its input.
rate: An integer, rate for atrous convolution.
outputs_collections: Collection to add the ResNet unit output.
scope: Optional variable_scope.
Returns:
The ResNet unit's output.
"""
with tf.variable_scope(scope, 'bottleneck_v2', [inputs]) as sc:
depth_in = slim.utils.last_dimension(inputs.get_shape(), min_rank=4)
preact = slim.batch_norm(inputs, activation_fn=tf.nn.relu, scope='preact')
if depth == depth_in:
shortcut = resnet_utils.subsample(inputs, stride, 'shortcut')
else:
shortcut = slim.conv2d(preact, depth, [1, 1], stride=stride,
normalizer_fn=None, activation_fn=None,
scope='shortcut')
residual = slim.conv2d(preact, depth_bottleneck, [1, 1], stride=1,
scope='conv1')
residual = resnet_utils.conv2d_same(residual, depth_bottleneck, 3, stride,
rate=rate, scope='conv2')
residual = slim.conv2d(residual, depth, [1, 1], stride=1,
normalizer_fn=None, activation_fn=None,
scope='conv3')
output = shortcut + residual
return slim.utils.collect_named_outputs(outputs_collections,
sc.original_name_scope,
output)
def resnet_v2(inputs,
blocks,
num_classes=None,
is_training=True,
global_pool=True,
output_stride=None,
include_root_block=True,
spatial_squeeze=True,
reuse=None,
scope=None):
"""Generator for v2 (preactivation) ResNet models.
This function generates a family of ResNet v2 models. See the resnet_v2_*()
methods for specific model instantiations, obtained by selecting different
block instantiations that produce ResNets of various depths.
Training for image classification on Imagenet is usually done with [224, 224]
inputs, resulting in [7, 7] feature maps at the output of the last ResNet
block for the ResNets defined in [1] that have nominal stride equal to 32.
However, for dense prediction tasks we advise that one uses inputs with
spatial dimensions that are multiples of 32 plus 1, e.g., [321, 321]. In
this case the feature maps at the ResNet output will have spatial shape
[(height - 1) / output_stride + 1, (width - 1) / output_stride + 1]
and corners exactly aligned with the input image corners, which greatly
facilitates alignment of the features to the image. Using as input [225, 225]
images results in [8, 8] feature maps at the output of the last ResNet block.
For dense prediction tasks, the ResNet needs to run in fully-convolutional
(FCN) mode and global_pool needs to be set to False. The ResNets in [1, 2] all
have nominal stride equal to 32 and a good choice in FCN mode is to use
output_stride=16 in order to increase the density of the computed features at
small computational and memory overhead, cf. http://arxiv.org/abs/1606.00915.
Args:
inputs: A tensor of size [batch, height_in, width_in, channels].
blocks: A list of length equal to the number of ResNet blocks. Each element
is a resnet_utils.Block object describing the units in the block.
num_classes: Number of predicted classes for classification tasks. If None
we return the features before the logit layer.
is_training: whether is training or not.
global_pool: If True, we perform global average pooling before computing the
logits. Set to True for image classification, False for dense prediction.
output_stride: If None, then the output will be computed at the nominal
network stride. If output_stride is not None, it specifies the requested
ratio of input to output spatial resolution.
include_root_block: If True, include the initial convolution followed by
max-pooling, if False excludes it. If excluded, `inputs` should be the
results of an activation-less convolution.
spatial_squeeze: if True, logits is of shape [B, C], if false logits is
of shape [B, 1, 1, C], where B is batch_size and C is number of classes.
To use this parameter, the input images must be smaller than 300x300
pixels, in which case the output logit layer does not contain spatial
information and can be removed.
reuse: whether or not the network and its variables should be reused. To be
able to reuse 'scope' must be given.
scope: Optional variable_scope.
Returns:
net: A rank-4 tensor of size [batch, height_out, width_out, channels_out].
If global_pool is False, then height_out and width_out are reduced by a
factor of output_stride compared to the respective height_in and width_in,
else both height_out and width_out equal one. If num_classes is None, then
net is the output of the last ResNet block, potentially after global
average pooling. If num_classes is not None, net contains the pre-softmax
activations.
end_points: A dictionary from components of the network to the corresponding
activation.
Raises:
ValueError: If the target output_stride is not valid.
"""
with tf.variable_scope(scope, 'resnet_v2', [inputs], reuse=reuse) as sc:
end_points_collection = sc.name + '_end_points'
with slim.arg_scope([slim.conv2d, bottleneck,
resnet_utils.stack_blocks_dense],
outputs_collections=end_points_collection):
with slim.arg_scope([slim.batch_norm], is_training=is_training):
net = inputs
if include_root_block:
if output_stride is not None:
if output_stride % 4 != 0:
raise ValueError('The output_stride needs to be a multiple of 4.')
output_stride /= 4
# We do not include batch normalization or activation functions in
# conv1 because the first ResNet unit will perform these. Cf.
# Appendix of [2].
with slim.arg_scope([slim.conv2d],
activation_fn=None, normalizer_fn=None):
net = resnet_utils.conv2d_same(net, 64, 7, stride=2, scope='conv1')
net = slim.max_pool2d(net, [3, 3], stride=2, scope='pool1')
net = resnet_utils.stack_blocks_dense(net, blocks, output_stride)
# This is needed because the pre-activation variant does not have batch
# normalization or activation functions in the residual unit output. See
# Appendix of [2].
net = slim.batch_norm(net, activation_fn=tf.nn.relu, scope='postnorm')
if global_pool:
# Global average pooling.
net = tf.reduce_mean(net, [1, 2], name='pool5', keep_dims=True)
if num_classes is not None:
net = slim.conv2d(net, num_classes, [1, 1], activation_fn=None,
normalizer_fn=None, scope='logits')
if spatial_squeeze:
net = tf.squeeze(net, [1, 2], name='SpatialSqueeze')
# Convert end_points_collection into a dictionary of end_points.
end_points = slim.utils.convert_collection_to_dict(
end_points_collection)
if num_classes is not None:
end_points['predictions'] = slim.softmax(net, scope='predictions')
return net, end_points
resnet_v2.default_image_size = 224
def resnet_v2_block(scope, base_depth, num_units, stride):
"""Helper function for creating a resnet_v2 bottleneck block.
Args:
scope: The scope of the block.
base_depth: The depth of the bottleneck layer for each unit.
num_units: The number of units in the block.
stride: The stride of the block, implemented as a stride in the last unit.
All other units have stride=1.
Returns:
A resnet_v2 bottleneck block.
"""
return resnet_utils.Block(scope, bottleneck, [{
'depth': base_depth * 4,
'depth_bottleneck': base_depth,
'stride': 1
}] * (num_units - 1) + [{
'depth': base_depth * 4,
'depth_bottleneck': base_depth,
'stride': stride
}])
resnet_v2.default_image_size = 224
def resnet_v2_50(inputs,
num_classes=None,
is_training=True,
global_pool=True,
output_stride=None,
spatial_squeeze=True,
reuse=None,
scope='resnet_v2_50'):
"""ResNet-50 model of [1]. See resnet_v2() for arg and return description."""
blocks = [
resnet_v2_block('block1', base_depth=64, num_units=3, stride=2),
resnet_v2_block('block2', base_depth=128, num_units=4, stride=2),
resnet_v2_block('block3', base_depth=256, num_units=6, stride=2),
resnet_v2_block('block4', base_depth=512, num_units=3, stride=1),
]
return resnet_v2(inputs, blocks, num_classes, is_training=is_training,
global_pool=global_pool, output_stride=output_stride,
include_root_block=True, spatial_squeeze=spatial_squeeze,
reuse=reuse, scope=scope)
resnet_v2_50.default_image_size = resnet_v2.default_image_size
def resnet_v2_101(inputs,
num_classes=None,
is_training=True,
global_pool=True,
output_stride=None,
spatial_squeeze=True,
reuse=None,
scope='resnet_v2_101'):
"""ResNet-101 model of [1]. See resnet_v2() for arg and return description."""
blocks = [
resnet_v2_block('block1', base_depth=64, num_units=3, stride=2),
resnet_v2_block('block2', base_depth=128, num_units=4, stride=2),
resnet_v2_block('block3', base_depth=256, num_units=23, stride=2),
resnet_v2_block('block4', base_depth=512, num_units=3, stride=1),
]
return resnet_v2(inputs, blocks, num_classes, is_training=is_training,
global_pool=global_pool, output_stride=output_stride,
include_root_block=True, spatial_squeeze=spatial_squeeze,
reuse=reuse, scope=scope)
resnet_v2_101.default_image_size = resnet_v2.default_image_size
def resnet_v2_152(inputs,
num_classes=None,
is_training=True,
global_pool=True,
output_stride=None,
spatial_squeeze=True,
reuse=None,
scope='resnet_v2_152'):
"""ResNet-152 model of [1]. See resnet_v2() for arg and return description."""
blocks = [
resnet_v2_block('block1', base_depth=64, num_units=3, stride=2),
resnet_v2_block('block2', base_depth=128, num_units=8, stride=2),
resnet_v2_block('block3', base_depth=256, num_units=36, stride=2),
resnet_v2_block('block4', base_depth=512, num_units=3, stride=1),
]
return resnet_v2(inputs, blocks, num_classes, is_training=is_training,
global_pool=global_pool, output_stride=output_stride,
include_root_block=True, spatial_squeeze=spatial_squeeze,
reuse=reuse, scope=scope)
resnet_v2_152.default_image_size = resnet_v2.default_image_size
def resnet_v2_200(inputs,
num_classes=None,
is_training=True,
global_pool=True,
output_stride=None,
spatial_squeeze=True,
reuse=None,
scope='resnet_v2_200'):
"""ResNet-200 model of [2]. See resnet_v2() for arg and return description."""
blocks = [
resnet_v2_block('block1', base_depth=64, num_units=3, stride=2),
resnet_v2_block('block2', base_depth=128, num_units=24, stride=2),
resnet_v2_block('block3', base_depth=256, num_units=36, stride=2),
resnet_v2_block('block4', base_depth=512, num_units=3, stride=1),
]
return resnet_v2(inputs, blocks, num_classes, is_training=is_training,
global_pool=global_pool, output_stride=output_stride,
include_root_block=True, spatial_squeeze=spatial_squeeze,
reuse=reuse, scope=scope)
resnet_v2_200.default_image_size = resnet_v2.default_image_size
================================================
FILE: nets/resnet_v2_test.py
================================================
# Copyright 2016 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Tests for slim.nets.resnet_v2."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import numpy as np
import tensorflow as tf
from nets import resnet_utils
from nets import resnet_v2
slim = tf.contrib.slim
def create_test_input(batch_size, height, width, channels):
"""Create test input tensor.
Args:
batch_size: The number of images per batch or `None` if unknown.
height: The height of each image or `None` if unknown.
width: The width of each image or `None` if unknown.
channels: The number of channels per image or `None` if unknown.
Returns:
Either a placeholder `Tensor` of dimension
[batch_size, height, width, channels] if any of the inputs are `None` or a
constant `Tensor` with the mesh grid values along the spatial dimensions.
"""
if None in [batch_size, height, width, channels]:
return tf.placeholder(tf.float32, (batch_size, height, width, channels))
else:
return tf.to_float(
np.tile(
np.reshape(
np.reshape(np.arange(height), [height, 1]) +
np.reshape(np.arange(width), [1, width]),
[1, height, width, 1]),
[batch_size, 1, 1, channels]))
class ResnetUtilsTest(tf.test.TestCase):
def testSubsampleThreeByThree(self):
x = tf.reshape(tf.to_float(tf.range(9)), [1, 3, 3, 1])
x = resnet_utils.subsample(x, 2)
expected = tf.reshape(tf.constant([0, 2, 6, 8]), [1, 2, 2, 1])
with self.test_session():
self.assertAllClose(x.eval(), expected.eval())
def testSubsampleFourByFour(self):
x = tf.reshape(tf.to_float(tf.range(16)), [1, 4, 4, 1])
x = resnet_utils.subsample(x, 2)
expected = tf.reshape(tf.constant([0, 2, 8, 10]), [1, 2, 2, 1])
with self.test_session():
self.assertAllClose(x.eval(), expected.eval())
def testConv2DSameEven(self):
n, n2 = 4, 2
# Input image.
x = create_test_input(1, n, n, 1)
# Convolution kernel.
w = create_test_input(1, 3, 3, 1)
w = tf.reshape(w, [3, 3, 1, 1])
tf.get_variable('Conv/weights', initializer=w)
tf.get_variable('Conv/biases', initializer=tf.zeros([1]))
tf.get_variable_scope().reuse_variables()
y1 = slim.conv2d(x, 1, [3, 3], stride=1, scope='Conv')
y1_expected = tf.to_float([[14, 28, 43, 26],
[28, 48, 66, 37],
[43, 66, 84, 46],
[26, 37, 46, 22]])
y1_expected = tf.reshape(y1_expected, [1, n, n, 1])
y2 = resnet_utils.subsample(y1, 2)
y2_expected = tf.to_float([[14, 43],
[43, 84]])
y2_expected = tf.reshape(y2_expected, [1, n2, n2, 1])
y3 = resnet_utils.conv2d_same(x, 1, 3, stride=2, scope='Conv')
y3_expected = y2_expected
y4 = slim.conv2d(x, 1, [3, 3], stride=2, scope='Conv')
y4_expected = tf.to_float([[48, 37],
[37, 22]])
y4_expected = tf.reshape(y4_expected, [1, n2, n2, 1])
with self.test_session() as sess:
sess.run(tf.global_variables_initializer())
self.assertAllClose(y1.eval(), y1_expected.eval())
self.assertAllClose(y2.eval(), y2_expected.eval())
self.assertAllClose(y3.eval(), y3_expected.eval())
self.assertAllClose(y4.eval(), y4_expected.eval())
def testConv2DSameOdd(self):
n, n2 = 5, 3
# Input image.
x = create_test_input(1, n, n, 1)
# Convolution kernel.
w = create_test_input(1, 3, 3, 1)
w = tf.reshape(w, [3, 3, 1, 1])
tf.get_variable('Conv/weights', initializer=w)
tf.get_variable('Conv/biases', initializer=tf.zeros([1]))
tf.get_variable_scope().reuse_variables()
y1 = slim.conv2d(x, 1, [3, 3], stride=1, scope='Conv')
y1_expected = tf.to_float([[14, 28, 43, 58, 34],
[28, 48, 66, 84, 46],
[43, 66, 84, 102, 55],
[58, 84, 102, 120, 64],
[34, 46, 55, 64, 30]])
y1_expected = tf.reshape(y1_expected, [1, n, n, 1])
y2 = resnet_utils.subsample(y1, 2)
y2_expected = tf.to_float([[14, 43, 34],
[43, 84, 55],
[34, 55, 30]])
y2_expected = tf.reshape(y2_expected, [1, n2, n2, 1])
y3 = resnet_utils.conv2d_same(x, 1, 3, stride=2, scope='Conv')
y3_expected = y2_expected
y4 = slim.conv2d(x, 1, [3, 3], stride=2, scope='Conv')
y4_expected = y2_expected
with self.test_session() as sess:
sess.run(tf.global_variables_initializer())
self.assertAllClose(y1.eval(), y1_expected.eval())
self.assertAllClose(y2.eval(), y2_expected.eval())
self.assertAllClose(y3.eval(), y3_expected.eval())
self.assertAllClose(y4.eval(), y4_expected.eval())
def _resnet_plain(self, inputs, blocks, output_stride=None, scope=None):
"""A plain ResNet without extra layers before or after the ResNet blocks."""
with tf.variable_scope(scope, values=[inputs]):
with slim.arg_scope([slim.conv2d], outputs_collections='end_points'):
net = resnet_utils.stack_blocks_dense(inputs, blocks, output_stride)
end_points = slim.utils.convert_collection_to_dict('end_points')
return net, end_points
def testEndPointsV2(self):
"""Test the end points of a tiny v2 bottleneck network."""
blocks = [
resnet_v2.resnet_v2_block(
'block1', base_depth=1, num_units=2, stride=2),
resnet_v2.resnet_v2_block(
'block2', base_depth=2, num_units=2, stride=1),
]
inputs = create_test_input(2, 32, 16, 3)
with slim.arg_scope(resnet_utils.resnet_arg_scope()):
_, end_points = self._resnet_plain(inputs, blocks, scope='tiny')
expected = [
'tiny/block1/unit_1/bottleneck_v2/shortcut',
'tiny/block1/unit_1/bottleneck_v2/conv1',
'tiny/block1/unit_1/bottleneck_v2/conv2',
'tiny/block1/unit_1/bottleneck_v2/conv3',
'tiny/block1/unit_2/bottleneck_v2/conv1',
'tiny/block1/unit_2/bottleneck_v2/conv2',
'tiny/block1/unit_2/bottleneck_v2/conv3',
'tiny/block2/unit_1/bottleneck_v2/shortcut',
'tiny/block2/unit_1/bottleneck_v2/conv1',
'tiny/block2/unit_1/bottleneck_v2/conv2',
'tiny/block2/unit_1/bottleneck_v2/conv3',
'tiny/block2/unit_2/bottleneck_v2/conv1',
'tiny/block2/unit_2/bottleneck_v2/conv2',
'tiny/block2/unit_2/bottleneck_v2/conv3']
self.assertItemsEqual(expected, end_points)
def _stack_blocks_nondense(self, net, blocks):
"""A simplified ResNet Block stacker without output stride control."""
for block in blocks:
with tf.variable_scope(block.scope, 'block', [net]):
for i, unit in enumerate(block.args):
with tf.variable_scope('unit_%d' % (i + 1), values=[net]):
net = block.unit_fn(net, rate=1, **unit)
return net
def testAtrousValuesBottleneck(self):
"""Verify the values of dense feature extraction by atrous convolution.
Make sure that dense feature extraction by stack_blocks_dense() followed by
subsampling gives identical results to feature extraction at the nominal
network output stride using the simple self._stack_blocks_nondense() above.
"""
block = resnet_v2.resnet_v2_block
blocks = [
block('block1', base_depth=1, num_units=2, stride=2),
block('block2', base_depth=2, num_units=2, stride=2),
block('block3', base_depth=4, num_units=2, stride=2),
block('block4', base_depth=8, num_units=2, stride=1),
]
nominal_stride = 8
# Test both odd and even input dimensions.
height = 30
width = 31
with slim.arg_scope(resnet_utils.resnet_arg_scope()):
with slim.arg_scope([slim.batch_norm], is_training=False):
for output_stride in [1, 2, 4, 8, None]:
with tf.Graph().as_default():
with self.test_session() as sess:
tf.set_random_seed(0)
inputs = create_test_input(1, height, width, 3)
# Dense feature extraction followed by subsampling.
output = resnet_utils.stack_blocks_dense(inputs,
blocks,
output_stride)
if output_stride is None:
factor = 1
else:
factor = nominal_stride // output_stride
output = resnet_utils.subsample(output, factor)
# Make the two networks use the same weights.
tf.get_variable_scope().reuse_variables()
# Feature extraction at the nominal network rate.
expected = self._stack_blocks_nondense(inputs, blocks)
sess.run(tf.global_variables_initializer())
output, expected = sess.run([output, expected])
self.assertAllClose(output, expected, atol=1e-4, rtol=1e-4)
class ResnetCompleteNetworkTest(tf.test.TestCase):
"""Tests with complete small ResNet v2 networks."""
def _resnet_small(self,
inputs,
num_classes=None,
is_training=True,
global_pool=True,
output_stride=None,
include_root_block=True,
spatial_squeeze=True,
reuse=None,
scope='resnet_v2_small'):
"""A shallow and thin ResNet v2 for faster tests."""
block = resnet_v2.resnet_v2_block
blocks = [
block('block1', base_depth=1, num_units=3, stride=2),
block('block2', base_depth=2, num_units=3, stride=2),
block('block3', base_depth=4, num_units=3, stride=2),
block('block4', base_depth=8, num_units=2, stride=1),
]
return resnet_v2.resnet_v2(inputs, blocks, num_classes,
is_training=is_training,
global_pool=global_pool,
output_stride=output_stride,
include_root_block=include_root_block,
spatial_squeeze=spatial_squeeze,
reuse=reuse,
scope=scope)
def testClassificationEndPoints(self):
global_pool = True
num_classes = 10
inputs = create_test_input(2, 224, 224, 3)
with slim.arg_scope(resnet_utils.resnet_arg_scope()):
logits, end_points = self._resnet_small(inputs, num_classes,
global_pool=global_pool,
spatial_squeeze=False,
scope='resnet')
self.assertTrue(logits.op.name.startswith('resnet/logits'))
self.assertListEqual(logits.get_shape().as_list(), [2, 1, 1, num_classes])
self.assertTrue('predictions' in end_points)
self.assertListEqual(end_points['predictions'].get_shape().as_list(),
[2, 1, 1, num_classes])
def testClassificationShapes(self):
global_pool = True
num_classes = 10
inputs = create_test_input(2, 224, 224, 3)
with slim.arg_scope(resnet_utils.resnet_arg_scope()):
_, end_points = self._resnet_small(inputs, num_classes,
global_pool=global_pool,
scope='resnet')
endpoint_to_shape = {
'resnet/block1': [2, 28, 28, 4],
'resnet/block2': [2, 14, 14, 8],
'resnet/block3': [2, 7, 7, 16],
'resnet/block4': [2, 7, 7, 32]}
for endpoint in endpoint_to_shape:
shape = endpoint_to_shape[endpoint]
self.assertListEqual(end_points[endpoint].get_shape().as_list(), shape)
def testFullyConvolutionalEndpointShapes(self):
global_pool = False
num_classes = 10
inputs = create_test_input(2, 321, 321, 3)
with slim.arg_scope(resnet_utils.resnet_arg_scope()):
_, end_points = self._resnet_small(inputs, num_classes,
global_pool=global_pool,
spatial_squeeze=False,
scope='resnet')
endpoint_to_shape = {
'resnet/block1': [2, 41, 41, 4],
'resnet/block2': [2, 21, 21, 8],
'resnet/block3': [2, 11, 11, 16],
'resnet/block4': [2, 11, 11, 32]}
for endpoint in endpoint_to_shape:
shape = endpoint_to_shape[endpoint]
self.assertListEqual(end_points[endpoint].get_shape().as_list(), shape)
def testRootlessFullyConvolutionalEndpointShapes(self):
global_pool = False
num_classes = 10
inputs = create_test_input(2, 128, 128, 3)
with slim.arg_scope(resnet_utils.resnet_arg_scope()):
_, end_points = self._resnet_small(inputs, num_classes,
global_pool=global_pool,
include_root_block=False,
spatial_squeeze=False,
scope='resnet')
endpoint_to_shape = {
'resnet/block1': [2, 64, 64, 4],
'resnet/block2': [2, 32, 32, 8],
'resnet/block3': [2, 16, 16, 16],
'resnet/block4': [2, 16, 16, 32]}
for endpoint in endpoint_to_shape:
shape = endpoint_to_shape[endpoint]
self.assertListEqual(end_points[endpoint].get_shape().as_list(), shape)
def testAtrousFullyConvolutionalEndpointShapes(self):
global_pool = False
num_classes = 10
output_stride = 8
inputs = create_test_input(2, 321, 321, 3)
with slim.arg_scope(resnet_utils.resnet_arg_scope()):
_, end_points = self._resnet_small(inputs,
num_classes,
global_pool=global_pool,
output_stride=output_stride,
spatial_squeeze=False,
scope='resnet')
endpoint_to_shape = {
'resnet/block1': [2, 41, 41, 4],
'resnet/block2': [2, 41, 41, 8],
'resnet/block3': [2, 41, 41, 16],
'resnet/block4': [2, 41, 41, 32]}
for endpoint in endpoint_to_shape:
shape = endpoint_to_shape[endpoint]
self.assertListEqual(end_points[endpoint].get_shape().as_list(), shape)
def testAtrousFullyConvolutionalValues(self):
"""Verify dense feature extraction with atrous convolution."""
nominal_stride = 32
for output_stride in [4, 8, 16, 32, None]:
with slim.arg_scope(resnet_utils.resnet_arg_scope()):
with tf.Graph().as_default():
with self.test_session() as sess:
tf.set_random_seed(0)
inputs = create_test_input(2, 81, 81, 3)
# Dense feature extraction followed by subsampling.
output, _ = self._resnet_small(inputs, None,
is_training=False,
global_pool=False,
output_stride=output_stride)
if output_stride is None:
factor = 1
else:
factor = nominal_stride // output_stride
output = resnet_utils.subsample(output, factor)
# Make the two networks use the same weights.
tf.get_variable_scope().reuse_variables()
# Feature extraction at the nominal network rate.
expected, _ = self._resnet_small(inputs, None,
is_training=False,
global_pool=False)
sess.run(tf.global_variables_initializer())
self.assertAllClose(output.eval(), expected.eval(),
atol=1e-4, rtol=1e-4)
def testUnknownBatchSize(self):
batch = 2
height, width = 65, 65
global_pool = True
num_classes = 10
inputs = create_test_input(None, height, width, 3)
with slim.arg_scope(resnet_utils.resnet_arg_scope()):
logits, _ = self._resnet_small(inputs, num_classes,
global_pool=global_pool,
spatial_squeeze=False,
scope='resnet')
self.assertTrue(logits.op.name.startswith('resnet/logits'))
self.assertListEqual(logits.get_shape().as_list(),
[None, 1, 1, num_classes])
images = create_test_input(batch, height, width, 3)
with self.test_session() as sess:
sess.run(tf.global_variables_initializer())
output = sess.run(logits, {inputs: images.eval()})
self.assertEqual(output.shape, (batch, 1, 1, num_classes))
def testFullyConvolutionalUnknownHeightWidth(self):
batch = 2
height, width = 65, 65
global_pool = False
inputs = create_test_input(batch, None, None, 3)
with slim.arg_scope(resnet_utils.resnet_arg_scope()):
output, _ = self._resnet_small(inputs, None,
global_pool=global_pool)
self.assertListEqual(output.get_shape().as_list(),
[batch, None, None, 32])
images = create_test_input(batch, height, width, 3)
with self.test_session() as sess:
sess.run(tf.global_variables_initializer())
output = sess.run(output, {inputs: images.eval()})
self.assertEqual(output.shape, (batch, 3, 3, 32))
def testAtrousFullyConvolutionalUnknownHeightWidth(self):
batch = 2
height, width = 65, 65
global_pool = False
output_stride = 8
inputs = create_test_input(batch, None, None, 3)
with slim.arg_scope(resnet_utils.resnet_arg_scope()):
output, _ = self._resnet_small(inputs,
None,
global_pool=global_pool,
output_stride=output_stride)
self.assertListEqual(output.get_shape().as_list(),
[batch, None, None, 32])
images = create_test_input(batch, height, width, 3)
with self.test_session() as sess:
sess.run(tf.global_variables_initializer())
output = sess.run(output, {inputs: images.eval()})
self.assertEqual(output.shape, (batch, 9, 9, 32))
if __name__ == '__main__':
tf.test.main()
================================================
FILE: nets/vgg.py
================================================
# Copyright 2016 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Contains model definitions for versions of the Oxford VGG network.
These model definitions were introduced in the following technical report:
Very Deep Convolutional Networks For Large-Scale Image Recognition
Karen Simonyan and Andrew Zisserman
arXiv technical report, 2015
PDF: http://arxiv.org/pdf/1409.1556.pdf
ILSVRC 2014 Slides: http://www.robots.ox.ac.uk/~karen/pdf/ILSVRC_2014.pdf
CC-BY-4.0
More information can be obtained from the VGG website:
www.robots.ox.ac.uk/~vgg/research/very_deep/
Usage:
with slim.arg_scope(vgg.vgg_arg_scope()):
outputs, end_points = vgg.vgg_a(inputs)
with slim.arg_scope(vgg.vgg_arg_scope()):
outputs, end_points = vgg.vgg_16(inputs)
@@vgg_a
@@vgg_16
@@vgg_19
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import tensorflow as tf
slim = tf.contrib.slim
def vgg_arg_scope(weight_decay=0.0005):
"""Defines the VGG arg scope.
Args:
weight_decay: The l2 regularization coefficient.
Returns:
An arg_scope.
"""
with slim.arg_scope([slim.conv2d, slim.fully_connected],
activation_fn=tf.nn.relu,
weights_regularizer=slim.l2_regularizer(weight_decay),
biases_initializer=tf.zeros_initializer()):
with slim.arg_scope([slim.conv2d], padding='SAME') as arg_sc:
return arg_sc
def vgg_a(inputs,
num_classes=1000,
is_training=True,
dropout_keep_prob=0.5,
spatial_squeeze=True,
scope='vgg_a',
fc_conv_padding='VALID'):
"""Oxford Net VGG 11-Layers version A Example.
Note: All the fully_connected layers have been transformed to conv2d layers.
To use in classification mode, resize input to 224x224.
Args:
inputs: a tensor of size [batch_size, height, width, channels].
num_classes: number of predicted classes.
is_training: whether or not the model is being trained.
dropout_keep_prob: the probability that activations are kept in the dropout
layers during training.
spatial_squeeze: whether or not should squeeze the spatial dimensions of the
outputs. Useful to remove unnecessary dimensions for classification.
scope: Optional scope for the variables.
fc_conv_padding: the type of padding to use for the fully connected layer
that is implemented as a convolutional layer. Use 'SAME' padding if you
are applying the network in a fully convolutional manner and want to
get a prediction map downsampled by a factor of 32 as an output.
Otherwise, the output prediction map will be (input / 32) - 6 in case of
'VALID' padding.
Returns:
the last op containing the log predictions and end_points dict.
"""
with tf.variable_scope(scope, 'vgg_a', [inputs]) as sc:
end_points_collection = sc.name + '_end_points'
# Collect outputs for conv2d, fully_connected and max_pool2d.
with slim.arg_scope([slim.conv2d, slim.max_pool2d],
outputs_collections=end_points_collection):
net = slim.repeat(inputs, 1, slim.conv2d, 64, [3, 3], scope='conv1')
net = slim.max_pool2d(net, [2, 2], scope='pool1')
net = slim.repeat(net, 1, slim.conv2d, 128, [3, 3], scope='conv2')
net = slim.max_pool2d(net, [2, 2], scope='pool2')
net = slim.repeat(net, 2, slim.conv2d, 256, [3, 3], scope='conv3')
net = slim.max_pool2d(net, [2, 2], scope='pool3')
net = slim.repeat(net, 2, slim.conv2d, 512, [3, 3], scope='conv4')
net = slim.max_pool2d(net, [2, 2], scope='pool4')
net = slim.repeat(net, 2, slim.conv2d, 512, [3, 3], scope='conv5')
net = slim.max_pool2d(net, [2, 2], scope='pool5')
# Use conv2d instead of fully_connected layers.
net = slim.conv2d(net, 4096, [7, 7], padding=fc_conv_padding, scope='fc6')
net = slim.dropout(net, dropout_keep_prob, is_training=is_training,
scope='dropout6')
net = slim.conv2d(net, 4096, [1, 1], scope='fc7')
net = slim.dropout(net, dropout_keep_prob, is_training=is_training,
scope='dropout7')
net = slim.conv2d(net, num_classes, [1, 1],
activation_fn=None,
normalizer_fn=None,
scope='fc8')
# Convert end_points_collection into a end_point dict.
end_points = slim.utils.convert_collection_to_dict(end_points_collection)
if spatial_squeeze:
net = tf.squeeze(net, [1, 2], name='fc8/squeezed')
end_points[sc.name + '/fc8'] = net
return net, end_points
vgg_a.default_image_size = 224
def vgg_16(inputs,
num_classes=1000,
is_training=True,
dropout_keep_prob=0.5,
spatial_squeeze=True,
scope='vgg_16',
fc_conv_padding='VALID'):
"""Oxford Net VGG 16-Layers version D Example.
Note: All the fully_connected layers have been transformed to conv2d layers.
To use in classification mode, resize input to 224x224.
Args:
inputs: a tensor of size [batch_size, height, width, channels].
num_classes: number of predicted classes.
is_training: whether or not the model is being trained.
dropout_keep_prob: the probability that activations are kept in the dropout
layers during training.
spatial_squeeze: whether or not should squeeze the spatial dimensions of the
outputs. Useful to remove unnecessary dimensions for classification.
scope: Optional scope for the variables.
fc_conv_padding: the type of padding to use for the fully connected layer
that is implemented as a convolutional layer. Use 'SAME' padding if you
are applying the network in a fully convolutional manner and want to
get a prediction map downsampled by a factor of 32 as an output.
Otherwise, the output prediction map will be (input / 32) - 6 in case of
'VALID' padding.
Returns:
the last op containing the log predictions and end_points dict.
"""
with tf.variable_scope(scope, 'vgg_16', [inputs]) as sc:
end_points_collection = sc.name + '_end_points'
# Collect outputs for conv2d, fully_connected and max_pool2d.
with slim.arg_scope([slim.conv2d, slim.fully_connected, slim.max_pool2d],
outputs_collections=end_points_collection):
net = slim.repeat(inputs, 2, slim.conv2d, 64, [3, 3], scope='conv1')
net = slim.max_pool2d(net, [2, 2], scope='pool1')
net = slim.repeat(net, 2, slim.conv2d, 128, [3, 3], scope='conv2')
net = slim.max_pool2d(net, [2, 2], scope='pool2')
net = slim.repeat(net, 3, slim.conv2d, 256, [3, 3], scope='conv3')
net = slim.max_pool2d(net, [2, 2], scope='pool3')
net = slim.repeat(net, 3, slim.conv2d, 512, [3, 3], scope='conv4')
net = slim.max_pool2d(net, [2, 2], scope='pool4')
net = slim.repeat(net, 3, slim.conv2d, 512, [3, 3], scope='conv5')
net = slim.max_pool2d(net, [2, 2], scope='pool5')
# Use conv2d instead of fully_connected layers.
net = slim.conv2d(net, 4096, [7, 7], padding=fc_conv_padding, scope='fc6')
net = slim.dropout(net, dropout_keep_prob, is_training=is_training,
scope='dropout6')
net = slim.conv2d(net, 4096, [1, 1], scope='fc7')
net = slim.dropout(net, dropout_keep_prob, is_training=is_training,
scope='dropout7')
net = slim.conv2d(net, num_classes, [1, 1],
activation_fn=None,
normalizer_fn=None,
scope='fc8')
# Convert end_points_collection into a end_point dict.
end_points = slim.utils.convert_collection_to_dict(end_points_collection)
if spatial_squeeze:
net = tf.squeeze(net, [1, 2], name='fc8/squeezed')
end_points[sc.name + '/fc8'] = net
return net, end_points
vgg_16.default_image_size = 224
def vgg_19(inputs,
num_classes=1000,
is_training=True,
dropout_keep_prob=0.5,
spatial_squeeze=True,
scope='vgg_19',
fc_conv_padding='VALID'):
"""Oxford Net VGG 19-Layers version E Example.
Note: All the fully_connected layers have been transformed to conv2d layers.
To use in classification mode, resize input to 224x224.
Args:
inputs: a tensor of size [batch_size, height, width, channels].
num_classes: number of predicted classes.
is_training: whether or not the model is being trained.
dropout_keep_prob: the probability that activations are kept in the dropout
layers during training.
spatial_squeeze: whether or not should squeeze the spatial dimensions of the
outputs. Useful to remove unnecessary dimensions for classification.
scope: Optional scope for the variables.
fc_conv_padding: the type of padding to use for the fully connected layer
that is implemented as a convolutional layer. Use 'SAME' padding if you
are applying the network in a fully convolutional manner and want to
get a prediction map downsampled by a factor of 32 as an output.
Otherwise, the output prediction map will be (input / 32) - 6 in case of
'VALID' padding.
Returns:
the last op containing the log predictions and end_points dict.
"""
with tf.variable_scope(scope, 'vgg_19', [inputs]) as sc:
end_points_collection = sc.name + '_end_points'
# Collect outputs for conv2d, fully_connected and max_pool2d.
with slim.arg_scope([slim.conv2d, slim.fully_connected, slim.max_pool2d],
outputs_collections=end_points_collection):
net = slim.repeat(inputs, 2, slim.conv2d, 64, [3, 3], scope='conv1')
net = slim.max_pool2d(net, [2, 2], scope='pool1')
net = slim.repeat(net, 2, slim.conv2d, 128, [3, 3], scope='conv2')
net = slim.max_pool2d(net, [2, 2], scope='pool2')
net = slim.repeat(net, 4, slim.conv2d, 256, [3, 3], scope='conv3')
net = slim.max_pool2d(net, [2, 2], scope='pool3')
net = slim.repeat(net, 4, slim.conv2d, 512, [3, 3], scope='conv4')
net = slim.max_pool2d(net, [2, 2], scope='pool4')
net = slim.repeat(net, 4, slim.conv2d, 512, [3, 3], scope='conv5')
net = slim.max_pool2d(net, [2, 2], scope='pool5')
# Use conv2d instead of fully_connected layers.
net = slim.conv2d(net, 4096, [7, 7], padding=fc_conv_padding, scope='fc6')
net = slim.dropout(net, dropout_keep_prob, is_training=is_training,
scope='dropout6')
net = slim.conv2d(net, 4096, [1, 1], scope='fc7')
net = slim.dropout(net, dropout_keep_prob, is_training=is_training,
scope='dropout7')
net = slim.conv2d(net, num_classes, [1, 1],
activation_fn=None,
normalizer_fn=None,
scope='fc8')
# Convert end_points_collection into a end_point dict.
end_points = slim.utils.convert_collection_to_dict(end_points_collection)
if spatial_squeeze:
net = tf.squeeze(net, [1, 2], name='fc8/squeezed')
end_points[sc.name + '/fc8'] = net
return net, end_points
vgg_19.default_image_size = 224
# Alias
vgg_d = vgg_16
vgg_e = vgg_19
================================================
FILE: nets/vgg_test.py
================================================
# Copyright 2016 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Tests for slim.nets.vgg."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import tensorflow as tf
from nets import vgg
slim = tf.contrib.slim
class VGGATest(tf.test.TestCase):
def testBuild(self):
batch_size = 5
height, width = 224, 224
num_classes = 1000
with self.test_session():
inputs = tf.random_uniform((batch_size, height, width, 3))
logits, _ = vgg.vgg_a(inputs, num_classes)
self.assertEquals(logits.op.name, 'vgg_a/fc8/squeezed')
self.assertListEqual(logits.get_shape().as_list(),
[batch_size, num_classes])
def testFullyConvolutional(self):
batch_size = 1
height, width = 256, 256
num_classes = 1000
with self.test_session():
inputs = tf.random_uniform((batch_size, height, width, 3))
logits, _ = vgg.vgg_a(inputs, num_classes, spatial_squeeze=False)
self.assertEquals(logits.op.name, 'vgg_a/fc8/BiasAdd')
self.assertListEqual(logits.get_shape().as_list(),
[batch_size, 2, 2, num_classes])
def testEndPoints(self):
batch_size = 5
height, width = 224, 224
num_classes = 1000
with self.test_session():
inputs = tf.random_uniform((batch_size, height, width, 3))
_, end_points = vgg.vgg_a(inputs, num_classes)
expected_names = ['vgg_a/conv1/conv1_1',
'vgg_a/pool1',
'vgg_a/conv2/conv2_1',
'vgg_a/pool2',
'vgg_a/conv3/conv3_1',
'vgg_a/conv3/conv3_2',
'vgg_a/pool3',
'vgg_a/conv4/conv4_1',
'vgg_a/conv4/conv4_2',
'vgg_a/pool4',
'vgg_a/conv5/conv5_1',
'vgg_a/conv5/conv5_2',
'vgg_a/pool5',
'vgg_a/fc6',
'vgg_a/fc7',
'vgg_a/fc8'
]
self.assertSetEqual(set(end_points.keys()), set(expected_names))
def testModelVariables(self):
batch_size = 5
height, width = 224, 224
num_classes = 1000
with self.test_session():
inputs = tf.random_uniform((batch_size, height, width, 3))
vgg.vgg_a(inputs, num_classes)
expected_names = ['vgg_a/conv1/conv1_1/weights',
'vgg_a/conv1/conv1_1/biases',
'vgg_a/conv2/conv2_1/weights',
'vgg_a/conv2/conv2_1/biases',
'vgg_a/conv3/conv3_1/weights',
'vgg_a/conv3/conv3_1/biases',
'vgg_a/conv3/conv3_2/weights',
'vgg_a/conv3/conv3_2/biases',
'vgg_a/conv4/conv4_1/weights',
'vgg_a/conv4/conv4_1/biases',
'vgg_a/conv4/conv4_2/weights',
'vgg_a/conv4/conv4_2/biases',
'vgg_a/conv5/conv5_1/weights',
'vgg_a/conv5/conv5_1/biases',
'vgg_a/conv5/conv5_2/weights',
'vgg_a/conv5/conv5_2/biases',
'vgg_a/fc6/weights',
'vgg_a/fc6/biases',
'vgg_a/fc7/weights',
'vgg_a/fc7/biases',
'vgg_a/fc8/weights',
'vgg_a/fc8/biases',
]
model_variables = [v.op.name for v in slim.get_model_variables()]
self.assertSetEqual(set(model_variables), set(expected_names))
def testEvaluation(self):
batch_size = 2
height, width = 224, 224
num_classes = 1000
with self.test_session():
eval_inputs = tf.random_uniform((batch_size, height, width, 3))
logits, _ = vgg.vgg_a(eval_inputs, is_training=False)
self.assertListEqual(logits.get_shape().as_list(),
[batch_size, num_classes])
predictions = tf.argmax(logits, 1)
self.assertListEqual(predictions.get_shape().as_list(), [batch_size])
def testTrainEvalWithReuse(self):
train_batch_size = 2
eval_batch_size = 1
train_height, train_width = 224, 224
eval_height, eval_width = 256, 256
num_classes = 1000
with self.test_session():
train_inputs = tf.random_uniform(
(train_batch_size, train_height, train_width, 3))
logits, _ = vgg.vgg_a(train_inputs)
self.assertListEqual(logits.get_shape().as_list(),
[train_batch_size, num_classes])
tf.get_variable_scope().reuse_variables()
eval_inputs = tf.random_uniform(
(eval_batch_size, eval_height, eval_width, 3))
logits, _ = vgg.vgg_a(eval_inputs, is_training=False,
spatial_squeeze=False)
self.assertListEqual(logits.get_shape().as_list(),
[eval_batch_size, 2, 2, num_classes])
logits = tf.reduce_mean(logits, [1, 2])
predictions = tf.argmax(logits, 1)
self.assertEquals(predictions.get_shape().as_list(), [eval_batch_size])
def testForward(self):
batch_size = 1
height, width = 224, 224
with self.test_session() as sess:
inputs = tf.random_uniform((batch_size, height, width, 3))
logits, _ = vgg.vgg_a(inputs)
sess.run(tf.global_variables_initializer())
output = sess.run(logits)
self.assertTrue(output.any())
class VGG16Test(tf.test.TestCase):
def testBuild(self):
batch_size = 5
height, width = 224, 224
num_classes = 1000
with self.test_session():
inputs = tf.random_uniform((batch_size, height, width, 3))
logits, _ = vgg.vgg_16(inputs, num_classes)
self.assertEquals(logits.op.name, 'vgg_16/fc8/squeezed')
self.assertListEqual(logits.get_shape().as_list(),
[batch_size, num_classes])
def testFullyConvolutional(self):
batch_size = 1
height, width = 256, 256
num_classes = 1000
with self.test_session():
inputs = tf.random_uniform((batch_size, height, width, 3))
logits, _ = vgg.vgg_16(inputs, num_classes, spatial_squeeze=False)
self.assertEquals(logits.op.name, 'vgg_16/fc8/BiasAdd')
self.assertListEqual(logits.get_shape().as_list(),
[batch_size, 2, 2, num_classes])
def testEndPoints(self):
batch_size = 5
height, width = 224, 224
num_classes = 1000
with self.test_session():
inputs = tf.random_uniform((batch_size, height, width, 3))
_, end_points = vgg.vgg_16(inputs, num_classes)
expected_names = ['vgg_16/conv1/conv1_1',
'vgg_16/conv1/conv1_2',
'vgg_16/pool1',
'vgg_16/conv2/conv2_1',
'vgg_16/conv2/conv2_2',
'vgg_16/pool2',
'vgg_16/conv3/conv3_1',
'vgg_16/conv3/conv3_2',
'vgg_16/conv3/conv3_3',
'vgg_16/pool3',
'vgg_16/conv4/conv4_1',
'vgg_16/conv4/conv4_2',
'vgg_16/conv4/conv4_3',
'vgg_16/pool4',
'vgg_16/conv5/conv5_1',
'vgg_16/conv5/conv5_2',
'vgg_16/conv5/conv5_3',
'vgg_16/pool5',
'vgg_16/fc6',
'vgg_16/fc7',
'vgg_16/fc8'
]
self.assertSetEqual(set(end_points.keys()), set(expected_names))
def testModelVariables(self):
batch_size = 5
height, width = 224, 224
num_classes = 1000
with self.test_session():
inputs = tf.random_uniform((batch_size, height, width, 3))
vgg.vgg_16(inputs, num_classes)
expected_names = ['vgg_16/conv1/conv1_1/weights',
'vgg_16/conv1/conv1_1/biases',
'vgg_16/conv1/conv1_2/weights',
'vgg_16/conv1/conv1_2/biases',
'vgg_16/conv2/conv2_1/weights',
'vgg_16/conv2/conv2_1/biases',
'vgg_16/conv2/conv2_2/weights',
'vgg_16/conv2/conv2_2/biases',
'vgg_16/conv3/conv3_1/weights',
'vgg_16/conv3/conv3_1/biases',
'vgg_16/conv3/conv3_2/weights',
'vgg_16/conv3/conv3_2/biases',
'vgg_16/conv3/conv3_3/weights',
'vgg_16/conv3/conv3_3/biases',
'vgg_16/conv4/conv4_1/weights',
'vgg_16/conv4/conv4_1/biases',
'vgg_16/conv4/conv4_2/weights',
'vgg_16/conv4/conv4_2/biases',
'vgg_16/conv4/conv4_3/weights',
'vgg_16/conv4/conv4_3/biases',
'vgg_16/conv5/conv5_1/weights',
'vgg_16/conv5/conv5_1/biases',
'vgg_16/conv5/conv5_2/weights',
'vgg_16/conv5/conv5_2/biases',
'vgg_16/conv5/conv5_3/weights',
'vgg_16/conv5/conv5_3/biases',
'vgg_16/fc6/weights',
'vgg_16/fc6/biases',
'vgg_16/fc7/weights',
'vgg_16/fc7/biases',
'vgg_16/fc8/weights',
'vgg_16/fc8/biases',
]
model_variables = [v.op.name for v in slim.get_model_variables()]
self.assertSetEqual(set(model_variables), set(expected_names))
def testEvaluation(self):
batch_size = 2
height, width = 224, 224
num_classes = 1000
with self.test_session():
eval_inputs = tf.random_uniform((batch_size, height, width, 3))
logits, _ = vgg.vgg_16(eval_inputs, is_training=False)
self.assertListEqual(logits.get_shape().as_list(),
[batch_size, num_classes])
predictions = tf.argmax(logits, 1)
self.assertListEqual(predictions.get_shape().as_list(), [batch_size])
def testTrainEvalWithReuse(self):
train_batch_size = 2
eval_batch_size = 1
train_height, train_width = 224, 224
eval_height, eval_width = 256, 256
num_classes = 1000
with self.test_session():
train_inputs = tf.random_uniform(
(train_batch_size, train_height, train_width, 3))
logits, _ = vgg.vgg_16(train_inputs)
self.assertListEqual(logits.get_shape().as_list(),
[train_batch_size, num_classes])
tf.get_variable_scope().reuse_variables()
eval_inputs = tf.random_uniform(
(eval_batch_size, eval_height, eval_width, 3))
logits, _ = vgg.vgg_16(eval_inputs, is_training=False,
spatial_squeeze=False)
self.assertListEqual(logits.get_shape().as_list(),
[eval_batch_size, 2, 2, num_classes])
logits = tf.reduce_mean(logits, [1, 2])
predictions = tf.argmax(logits, 1)
self.assertEquals(predictions.get_shape().as_list(), [eval_batch_size])
def testForward(self):
batch_size = 1
height, width = 224, 224
with self.test_session() as sess:
inputs = tf.random_uniform((batch_size, height, width, 3))
logits, _ = vgg.vgg_16(inputs)
sess.run(tf.global_variables_initializer())
output = sess.run(logits)
self.assertTrue(output.any())
class VGG19Test(tf.test.TestCase):
def testBuild(self):
batch_size = 5
height, width = 224, 224
num_classes = 1000
with self.test_session():
inputs = tf.random_uniform((batch_size, height, width, 3))
logits, _ = vgg.vgg_19(inputs, num_classes)
self.assertEquals(logits.op.name, 'vgg_19/fc8/squeezed')
self.assertListEqual(logits.get_shape().as_list(),
[batch_size, num_classes])
def testFullyConvolutional(self):
batch_size = 1
height, width = 256, 256
num_classes = 1000
with self.test_session():
inputs = tf.random_uniform((batch_size, height, width, 3))
logits, _ = vgg.vgg_19(inputs, num_classes, spatial_squeeze=False)
self.assertEquals(logits.op.name, 'vgg_19/fc8/BiasAdd')
self.assertListEqual(logits.get_shape().as_list(),
[batch_size, 2, 2, num_classes])
def testEndPoints(self):
batch_size = 5
height, width = 224, 224
num_classes = 1000
with self.test_session():
inputs = tf.random_uniform((batch_size, height, width, 3))
_, end_points = vgg.vgg_19(inputs, num_classes)
expected_names = [
'vgg_19/conv1/conv1_1',
'vgg_19/conv1/conv1_2',
'vgg_19/pool1',
'vgg_19/conv2/conv2_1',
'vgg_19/conv2/conv2_2',
'vgg_19/pool2',
'vgg_19/conv3/conv3_1',
'vgg_19/conv3/conv3_2',
'vgg_19/conv3/conv3_3',
'vgg_19/conv3/conv3_4',
'vgg_19/pool3',
'vgg_19/conv4/conv4_1',
'vgg_19/conv4/conv4_2',
'vgg_19/conv4/conv4_3',
'vgg_19/conv4/conv4_4',
'vgg_19/pool4',
'vgg_19/conv5/conv5_1',
'vgg_19/conv5/conv5_2',
'vgg_19/conv5/conv5_3',
'vgg_19/conv5/conv5_4',
'vgg_19/pool5',
'vgg_19/fc6',
'vgg_19/fc7',
'vgg_19/fc8'
]
self.assertSetEqual(set(end_points.keys()), set(expected_names))
def testModelVariables(self):
batch_size = 5
height, width = 224, 224
num_classes = 1000
with self.test_session():
inputs = tf.random_uniform((batch_size, height, width, 3))
vgg.vgg_19(inputs, num_classes)
expected_names = [
'vgg_19/conv1/conv1_1/weights',
'vgg_19/conv1/conv1_1/biases',
'vgg_19/conv1/conv1_2/weights',
'vgg_19/conv1/conv1_2/biases',
'vgg_19/conv2/conv2_1/weights',
'vgg_19/conv2/conv2_1/biases',
'vgg_19/conv2/conv2_2/weights',
'vgg_19/conv2/conv2_2/biases',
'vgg_19/conv3/conv3_1/weights',
'vgg_19/conv3/conv3_1/biases',
'vgg_19/conv3/conv3_2/weights',
'vgg_19/conv3/conv3_2/biases',
'vgg_19/conv3/conv3_3/weights',
'vgg_19/conv3/conv3_3/biases',
'vgg_19/conv3/conv3_4/weights',
'vgg_19/conv3/conv3_4/biases',
'vgg_19/conv4/conv4_1/weights',
'vgg_19/conv4/conv4_1/biases',
'vgg_19/conv4/conv4_2/weights',
'vgg_19/conv4/conv4_2/biases',
'vgg_19/conv4/conv4_3/weights',
'vgg_19/conv4/conv4_3/biases',
'vgg_19/conv4/conv4_4/weights',
'vgg_19/conv4/conv4_4/biases',
'vgg_19/conv5/conv5_1/weights',
'vgg_19/conv5/conv5_1/biases',
'vgg_19/conv5/conv5_2/weights',
'vgg_19/conv5/conv5_2/biases',
'vgg_19/conv5/conv5_3/weights',
'vgg_19/conv5/conv5_3/biases',
'vgg_19/conv5/conv5_4/weights',
'vgg_19/conv5/conv5_4/biases',
'vgg_19/fc6/weights',
'vgg_19/fc6/biases',
'vgg_19/fc7/weights',
'vgg_19/fc7/biases',
'vgg_19/fc8/weights',
'vgg_19/fc8/biases',
]
model_variables = [v.op.name for v in slim.get_model_variables()]
self.assertSetEqual(set(model_variables), set(expected_names))
def testEvaluation(self):
batch_size = 2
height, width = 224, 224
num_classes = 1000
with self.test_session():
eval_inputs = tf.random_uniform((batch_size, height, width, 3))
logits, _ = vgg.vgg_19(eval_inputs, is_training=False)
self.assertListEqual(logits.get_shape().as_list(),
[batch_size, num_classes])
predictions = tf.argmax(logits, 1)
self.assertListEqual(predictions.get_shape().as_list(), [batch_size])
def testTrainEvalWithReuse(self):
train_batch_size = 2
eval_batch_size = 1
train_height, train_width = 224, 224
eval_height, eval_width = 256, 256
num_classes = 1000
with self.test_session():
train_inputs = tf.random_uniform(
(train_batch_size, train_height, train_width, 3))
logits, _ = vgg.vgg_19(train_inputs)
self.assertListEqual(logits.get_shape().as_list(),
[train_batch_size, num_classes])
tf.get_variable_scope().reuse_variables()
eval_inputs = tf.random_uniform(
(eval_batch_size, eval_height, eval_width, 3))
logits, _ = vgg.vgg_19(eval_inputs, is_training=False,
spatial_squeeze=False)
self.assertListEqual(logits.get_shape().as_list(),
[eval_batch_size, 2, 2, num_classes])
logits = tf.reduce_mean(logits, [1, 2])
predictions = tf.argmax(logits, 1)
self.assertEquals(predictions.get_shape().as_list(), [eval_batch_size])
def testForward(self):
batch_size = 1
height, width = 224, 224
with self.test_session() as sess:
inputs = tf.random_uniform((batch_size, height, width, 3))
logits, _ = vgg.vgg_19(inputs)
sess.run(tf.global_variables_initializer())
output = sess.run(logits)
self.assertTrue(output.any())
if __name__ == '__main__':
tf.test.main()
================================================
FILE: run_attack.sh
================================================
#!/bin/bash
#
# run_attack.sh is a script which executes the attack
#
# Envoronment which runs attacks and defences calls it in a following way:
# run_attack.sh INPUT_DIR OUTPUT_DIR MAX_EPSILON
# where:
# INPUT_DIR - directory with input PNG images
# OUTPUT_DIR - directory where adversarial images should be written
# MAX_EPSILON - maximum allowed L_{\infty} norm of adversarial perturbation
#
INPUT_DIR=$1
OUTPUT_DIR=$2
MAX_EPSILON=$3
python attack_iter.py \
--input_dir="${INPUT_DIR}" \
--output_dir="${OUTPUT_DIR}" \
--max_epsilon="${MAX_EPSILON}" \
--checkpoint_path_inception_v3=inception_v3.ckpt \
--checkpoint_path_inception_v4=inception_v4.ckpt \
--checkpoint_path_inception_resnet_v2=inception_resnet_v2_2016_08_30.ckpt \
--checkpoint_path_resnet=resnet_v2_152.ckpt \
--num_iter=10 \
--momentum=1.0 \
--prob=0.7