Unverified Commit 3dacd474 authored by Jekaterina Jaroslavceva's avatar Jekaterina Jaroslavceva Committed by GitHub
Browse files

File movings (#9899)

* Dataset utilities added.

* Global model definition

* Dataset modules added.

* Dataset modules fix.

* global features model training added

* global features fix

* Test dataset update

* PR fixes

* repo sync

* repo sync

* modules moving

* Removed unnecessary modules

* Removed unnecessary files
parent b1aa44d9
......@@ -35,5 +35,7 @@ from delf.python.examples import extractor
from delf.python import detect_to_retrieve
from delf.python import training
from delf.python.training import model
from delf.python.training import datasets
from delf.python import datasets
from delf.python.datasets import google_landmarks_dataset
from delf.python.datasets import revisited_op
# pylint: enable=unused-import
......@@ -18,7 +18,7 @@ For more details on the dataset, please refer to its
### Install DELF library
To be able to use this code, please follow
[these instructions](../../../INSTALL_INSTRUCTIONS.md) to properly install the
[these instructions](../../../../INSTALL_INSTRUCTIONS.md) to properly install the
DELF library.
### Download Revisited Oxford/Paris datasets
......@@ -48,7 +48,7 @@ wget http://cmp.felk.cvut.cz/revisitop/data/datasets/rparis6k/gnd_rparis6k.mat
### Download model
```bash
# From models/research/delf/delf/python/google_landmarks_dataset
# From models/research/delf/delf/python/datasets/google_landmarks_dataset
mkdir parameters && cd parameters
# RN101-ArcFace model trained on GLDv2-clean.
......@@ -72,8 +72,8 @@ datasets, and not required for the GLDv2 retrieval/recognition datasets.
Run query feature extraction as follows:
```bash
# From models/research/delf/delf/python/google_landmarks_dataset
python3 ../delg/extract_features.py \
# From models/research/delf/delf/python/datasets/google_landmarks_dataset
python3 ../../delg/extract_features.py \
--delf_config_path rn101_af_gldv2clean_config.pbtxt \
--dataset_file_path ~/revisitop/data/gnd_roxford5k.mat \
--images_dir ~/revisitop/data/oxford5k_images \
......@@ -86,8 +86,8 @@ python3 ../delg/extract_features.py \
Run index feature extraction as follows:
```bash
# From models/research/delf/delf/python/google_landmarks_dataset
python3 ../delg/extract_features.py \
# From models/research/delf/delf/python/datasets/google_landmarks_dataset
python3 ../../delg/extract_features.py \
--delf_config_path rn101_af_gldv2clean_config.pbtxt \
--dataset_file_path ~/revisitop/data/gnd_roxford5k.mat \
--images_dir ~/revisitop/data/oxford5k_images \
......@@ -100,8 +100,8 @@ python3 ../delg/extract_features.py \
To run retrieval on `roxford5k`, the following command can be used:
```bash
# From models/research/delf/delf/python/google_landmarks_dataset
python3 ../delg/perform_retrieval.py \
# From models/research/delf/delf/python/datasets/google_landmarks_dataset
python3 ../../delg/perform_retrieval.py \
--dataset_file_path ~/revisitop/data/gnd_roxford5k.mat \
--query_features_dir ~/revisitop/data/oxford5k_features/query \
--index_features_dir ~/revisitop/data/oxford5k_features/index \
......
# Copyright 2021 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.
# ==============================================================================
"""Module exposing Google Landmarks dataset for training."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
# pylint: disable=unused-import
from delf.python.datasets.google_landmarks_dataset import googlelandmarks
# pylint: enable=unused-import
......@@ -25,8 +25,8 @@ import argparse
import sys
from tensorflow.python.platform import app
from delf.python.google_landmarks_dataset import dataset_file_io
from delf.python.google_landmarks_dataset import metrics
from delf.python.datasets.google_landmarks_dataset import dataset_file_io
from delf.python.datasets.google_landmarks_dataset import metrics
cmd_args = None
......
......@@ -25,8 +25,8 @@ import argparse
import sys
from tensorflow.python.platform import app
from delf.python.google_landmarks_dataset import dataset_file_io
from delf.python.google_landmarks_dataset import metrics
from delf.python.datasets.google_landmarks_dataset import dataset_file_io
from delf.python.datasets.google_landmarks_dataset import metrics
cmd_args = None
......
......@@ -23,7 +23,7 @@ import os
from absl import flags
import tensorflow as tf
from delf.python.google_landmarks_dataset import dataset_file_io
from delf.python.datasets.google_landmarks_dataset import dataset_file_io
FLAGS = flags.FLAGS
......
......@@ -20,7 +20,7 @@ from __future__ import print_function
import tensorflow as tf
from delf.python.google_landmarks_dataset import metrics
from delf.python.datasets.google_landmarks_dataset import metrics
def _CreateRecognitionSolution():
......
# Copyright 2020 The TensorFlow Authors All Rights Reserved.
# Copyright 2021 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.
......@@ -12,11 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Module exposing datasets for training."""
"""Module for revisited Oxford and Paris datasets."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
# pylint: disable=unused-import
from delf.python.training.datasets import googlelandmarks
from delf.python.datasets.revisited_op import dataset
# pylint: enable=unused-import
......@@ -18,6 +18,9 @@ from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import os
import pickle
import numpy as np
from scipy.io import matlab
import tensorflow as tf
......@@ -467,3 +470,65 @@ def ReadMetricsFile(metrics_path):
dtype=float) / 100.0
return mean_average_precision, pr_ranks, mean_precisions, mean_recalls
def create_config_for_test_dataset(dataset, dir_main):
"""Creates the configuration dictionary for the test dataset.
Args:
dataset: String, dataset name: either 'roxford5k' or 'rparis6k'.
dir_main: String, path to the folder containing ground truth files.
Returns:
cfg: Dataset configuration in a form of dictionary. The configuration
includes:
`gnd_fname` - path to the ground truth file for teh dataset,
`ext` and `qext` - image extentions for the images in the test dataset
and the query images,
`dir_data` - path to the folder containing ground truth files,
`dir_images` - path to the folder containing images,
`n` and `nq` - number of images and query images in the dataset
respectively,
`im_fname` and `qim_fname` - functions providing paths for the dataset
and query images respectively,
`dataset` - test dataset name.
Raises:
ValueError: If an unknown dataset name is provided as an argument.
"""
DATASETS = ['roxford5k', 'rparis6k']
dataset = dataset.lower()
def _config_imname(cfg, i):
return os.path.join(cfg['dir_images'], cfg['imlist'][i] + cfg['ext'])
def _config_qimname(cfg, i):
return os.path.join(cfg['dir_images'], cfg['qimlist'][i] + cfg['qext'])
if dataset not in DATASETS:
raise ValueError('Unknown dataset: {}!'.format(dataset))
# Loading imlist, qimlist, and gnd in configuration as a dictionary.
gnd_fname = os.path.join(dir_main, 'gnd_{}.pkl'.format(dataset))
with tf.io.gfile.GFile(gnd_fname, 'rb') as f:
cfg = pickle.load(f)
cfg['gnd_fname'] = gnd_fname
if dataset == 'rparis6k':
dir_images = 'paris6k_images'
elif dataset == 'roxford5k':
dir_images = 'oxford5k_images'
cfg['ext'] = '.jpg'
cfg['qext'] = '.jpg'
cfg['dir_data'] = os.path.join(dir_main)
cfg['dir_images'] = os.path.join(cfg['dir_data'], dir_images)
cfg['n'] = len(cfg['imlist'])
cfg['nq'] = len(cfg['qimlist'])
cfg['im_fname'] = _config_imname
cfg['qim_fname'] = _config_qimname
cfg['dataset'] = dataset
return cfg
......@@ -22,14 +22,15 @@ import tensorflow as tf
from delf.python import utils as image_loading_utils
def pil_imagenet_loader(path, imsize, bounding_box=None, normalize=True):
def pil_imagenet_loader(path, imsize, bounding_box=None, preprocess=True):
"""Pillow loader for the images.
Args:
path: Path to image to be loaded.
imsize: Integer, defines the maximum size of longer image side.
bounding_box: (x1,y1,x2,y2) tuple to crop the query image.
normalize: Bool, whether to normalize the image.
preprocess: Bool, whether to preprocess the images in respect to the
ImageNet dataset.
Returns:
image: `Tensor`, image in ImageNet suitable format.
......@@ -47,7 +48,7 @@ def pil_imagenet_loader(path, imsize, bounding_box=None, normalize=True):
img.thumbnail((imsize, imsize), Image.ANTIALIAS)
img = np.array(img)
if normalize:
if preprocess:
# Preprocessing for ImageNet data. Converts the images from RGB to BGR,
# then zero-centers each color channel with respect to the ImageNet
# dataset, without scaling.
......@@ -56,16 +57,18 @@ def pil_imagenet_loader(path, imsize, bounding_box=None, normalize=True):
return img
def default_loader(path, imsize, bounding_box=None, normalize=True):
def default_loader(path, imsize, bounding_box=None, preprocess=True):
"""Default loader for the images is using Pillow.
Args:
path: Path to image to be loaded.
imsize: Integer, defines the maximum size of longer image side.
bounding_box: (x1,y1,x2,y2) tuple to crop the query image.
preprocess: Bool, whether to preprocess the images in respect to the
ImageNet dataset.
Returns:
image: `Tensor`, image in ImageNet suitable format.
"""
img = pil_imagenet_loader(path, imsize, bounding_box, normalize)
img = pil_imagenet_loader(path, imsize, bounding_box, preprocess)
return img
......@@ -44,7 +44,7 @@ class UtilsTest(tf.test.TestCase):
max_img_size = 1024
# Load the saved dummy image.
img = image_loading_utils.default_loader(filename, imsize=max_img_size,
normalize=False)
preprocess=False)
# Make sure the values are the same before and after loading.
self.assertAllEqual(np.array(img_out), img)
......@@ -62,13 +62,12 @@ class UtilsTest(tf.test.TestCase):
max_img_size = 1024
# Load the saved dummy image.
expected_size = 400
img = image_loading_utils.default_loader(filename, imsize=max_img_size,
bounding_box=[120, 120,
120 + expected_size,
120 + expected_size],
normalize=False)
img = image_loading_utils.default_loader(
filename, imsize=max_img_size,
bounding_box=[120, 120, 120 + expected_size, 120 + expected_size],
preprocess=False)
# Check the shape.
# Check that the final shape is as expected.
self.assertAllEqual(tf.shape(img), [expected_size, expected_size, 3])
......
......@@ -34,6 +34,8 @@ mv paris6k_images_tmp/paris/*/*.jpg paris6k_images/
# Revisited annotations.
wget http://cmp.felk.cvut.cz/revisitop/data/datasets/roxford5k/gnd_roxford5k.mat
wget http://cmp.felk.cvut.cz/revisitop/data/datasets/rparis6k/gnd_rparis6k.mat
wget http://cmp.felk.cvut.cz/cnnimageretrieval/data/test/roxford5k/gnd_roxford5k.pkl
wget http://cmp.felk.cvut.cz/cnnimageretrieval/data/test/rparis6k/gnd_rparis6k.pkl
```
### Download model
......
......@@ -20,5 +20,4 @@ from __future__ import print_function
# pylint: disable=unused-import
from delf.python.detect_to_retrieve import aggregation_extraction
from delf.python.detect_to_retrieve import boxes_and_features_extraction
from delf.python.detect_to_retrieve import dataset
# pylint: enable=unused-import
......@@ -31,7 +31,6 @@ class MAC(tf.keras.layers.Layer):
Args:
x: [B, H, W, D] A float32 Tensor.
axis: Dimensions to reduce. By default, dimensions [1, 2] are reduced.
Returns:
output: [B, D] A float32 Tensor.
"""
......@@ -99,6 +98,47 @@ class GeM(tf.keras.layers.Layer):
return gem(x, power=self.power, eps=self.eps, axis=axis)
class GeMPooling2D(tf.keras.layers.Layer):
def __init__(self, power=20., pool_size=(2, 2), strides=None,
padding='valid', data_format='channels_last'):
"""Generalized mean pooling (GeM) pooling operation for spatial data.
Args:
power: Float, power > 0. is an inverse exponent parameter (GeM power).
pool_size: Integer or tuple of 2 integers, factors by which to
downscale (vertical, horizontal)
strides: Integer, tuple of 2 integers, or None. Strides values.
If None, it will default to `pool_size`.
padding: One of `valid` or `same`. `valid` means no padding.
`same` results in padding evenly to the left/right or up/down of
the input such that output has the same height/width dimension as the
input.
data_format: A string, one of `channels_last` (default) or
`channels_first`. The ordering of the dimensions in the inputs.
`channels_last` corresponds to inputs with shape `(batch, height,
width, channels)` while `channels_first` corresponds to inputs with
shape `(batch, channels, height, width)`.
"""
super(GeMPooling2D, self).__init__()
self.power = power
self.eps = 1e-6
self.pool_size = pool_size
self.strides = strides
self.padding = padding.upper()
data_format_conv = {'channels_last': 'NHWC',
'channels_first': 'NCHW',
}
self.data_format = data_format_conv[data_format]
def call(self, x):
tmp = tf.pow(x, self.power)
tmp = tf.nn.avg_pool(tmp, self.pool_size, self.strides,
self.padding, self.data_format)
out = tf.pow(tmp, 1. / self.power)
return out
def mac(x, axis=None):
"""Performs global max pooling (MAC).
......
......@@ -48,6 +48,37 @@ class PoolingsTest(tf.test.TestCase):
# Compare actual and expected.
self.assertAllClose(exp_output, result)
def testGeMPooling2D(self):
# Create a testing tensor.
x = tf.constant([[[1., 2., 3.],
[4., 5., 6.],
[7., 8., 9.]]])
x = tf.reshape(x, [1, 3, 3, 1])
# Checking GeMPooling2D relation to MaxPooling2D for the large values of
# `p`.
max_pool_2d = tf.keras.layers.MaxPooling2D(pool_size=(2, 2),
strides=(1, 1), padding='valid')
out_max = max_pool_2d(x)
gem_pool_2d = pooling.GeMPooling2D(power=30., pool_size=(2, 2),
strides=(1, 1), padding='valid')
out_gem_max = gem_pool_2d(x)
# Check that for large `p` GeMPooling2D is close to MaxPooling2D.
self.assertAllEqual(out_max, tf.round(out_gem_max))
# Checking GeMPooling2D relation to AveragePooling2D for the value
# of `p` = 1.
avg_pool_2d = tf.keras.layers.AveragePooling2D(pool_size=(2, 2),
strides=(1, 1),
padding='valid')
out_avg = avg_pool_2d(x)
gem_pool_2d = pooling.GeMPooling2D(power=1., pool_size=(2, 2),
strides=(1, 1), padding='valid')
out_gem_avg = gem_pool_2d(x)
# Check that for `p` equals 1., GeMPooling2D becomes AveragePooling2D.
self.assertAllEqual(out_avg, out_gem_avg)
if __name__ == '__main__':
tf.test.main()
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment