From daa5b4ab7cfabbd73557a9b2f832fb32b3e7f3f2 Mon Sep 17 00:00:00 2001 From: Neeraj Komuravalli Date: Wed, 6 May 2020 10:12:04 +0530 Subject: [PATCH 01/44] Adding features column to the data and compensating for the same in missing value test (#3126) --- .../turicreate/test/test_image_classifier.py | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/python/turicreate/test/test_image_classifier.py b/src/python/turicreate/test/test_image_classifier.py index 0bda04d06e..8311435fa8 100644 --- a/src/python/turicreate/test/test_image_classifier.py +++ b/src/python/turicreate/test/test_image_classifier.py @@ -19,12 +19,14 @@ _raise_error_if_not_sframe, _raise_error_if_not_sarray, ) +from turicreate.toolkits.image_analysis.image_analysis import MODEL_TO_FEATURE_SIZE_MAPPING from . import util as test_util import coremltools import numpy as np import turicreate as tc +from array import array def get_test_data(): @@ -74,7 +76,13 @@ def get_test_data(): images.append(tc_image) labels = ["white"] * 5 + ["black"] * 5 - return tc.SFrame({"awesome_image": images, "awesome_label": labels}) + data_dict = {"awesome_image": images, "awesome_label": labels} + possible_feature_length_list = list(set(MODEL_TO_FEATURE_SIZE_MAPPING.values())) + no_of_columns = len(data_dict[[*data_dict][0]]) + for feature_length in possible_feature_length_list: + data_dict[str(feature_length)] = tc.SArray(np.random.rand(no_of_columns, feature_length)*100, dtype=array) + + return tc.SFrame(data_dict) data = get_test_data() @@ -133,13 +141,17 @@ def assertListAlmostEquals(self, list1, list2, tol): self.assertAlmostEqual(a, b, delta=tol) def test_create_with_missing_value(self): + from array import array + + data_dict = { + self.feature: tc.SArray([None], dtype=tc.Image), + self.target: [data[self.target][0]], + } + possible_feature_length_list = list(set(MODEL_TO_FEATURE_SIZE_MAPPING.values())) + for feature_length in possible_feature_length_list: + data_dict[str(feature_length)] = tc.SArray([None], dtype=array) data_with_none = data.append( - tc.SFrame( - { - self.feature: tc.SArray([None], dtype=tc.Image), - self.target: [data[self.target][0]], - } - ) + tc.SFrame(data_dict) ) with self.assertRaises(_ToolkitError): tc.image_classifier.create( From 63736cf48639f88fbdad5418296db6ce9e9098d9 Mon Sep 17 00:00:00 2001 From: Neeraj Komuravalli Date: Wed, 6 May 2020 10:14:22 +0530 Subject: [PATCH 02/44] Adding features column to the data to test with features (#3126) --- .../turicreate/test/test_image_similarity.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/python/turicreate/test/test_image_similarity.py b/src/python/turicreate/test/test_image_similarity.py index a8113fddd5..a6bcfe63af 100644 --- a/src/python/turicreate/test/test_image_similarity.py +++ b/src/python/turicreate/test/test_image_similarity.py @@ -12,9 +12,13 @@ from turicreate.toolkits._internal_utils import _mac_ver import tempfile from . import util as test_util + +from turicreate.toolkits._main import ToolkitError as _ToolkitError +from turicreate.toolkits.image_analysis.image_analysis import MODEL_TO_FEATURE_SIZE_MAPPING + import coremltools import numpy as np -from turicreate.toolkits._main import ToolkitError as _ToolkitError +from array import array def get_test_data(): @@ -63,7 +67,13 @@ def get_test_data(): ) images.append(tc_image) - return tc.SFrame({"awesome_image": images}) + data_dict = {"awesome_image": images} + no_of_columns = len(data_dict[[*data_dict][0]]) + possible_feature_length_list = list(set(MODEL_TO_FEATURE_SIZE_MAPPING.values())) + for feature_length in possible_feature_length_list: + data_dict[str(feature_length)] = tc.SArray(np.random.rand(no_of_columns, feature_length)*100, dtype=array) + + return tc.SFrame(data_dict) data = get_test_data() From 37d5ccd5c25e3fc902dd47c5be4a33f2157b47e5 Mon Sep 17 00:00:00 2001 From: Neeraj Komuravalli Date: Wed, 6 May 2020 10:17:01 +0530 Subject: [PATCH 03/44] Changing import statements to make the image_analysis callable (#3126) --- src/python/turicreate/toolkits/image_analysis/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/python/turicreate/toolkits/image_analysis/__init__.py b/src/python/turicreate/toolkits/image_analysis/__init__.py index 4b31b6b920..fe9c8f5d2e 100644 --- a/src/python/turicreate/toolkits/image_analysis/__init__.py +++ b/src/python/turicreate/toolkits/image_analysis/__init__.py @@ -7,6 +7,6 @@ from __future__ import division as _ from __future__ import absolute_import as _ -__all__ = ["image_analysis"] +# __all__ = ["image_analysis"] -from . import image_analysis +from .image_analysis import * \ No newline at end of file From 67216b54d00a0c0e4da3012787f56c8b0ca0136f Mon Sep 17 00:00:00 2001 From: Neeraj Komuravalli Date: Wed, 6 May 2020 10:20:30 +0530 Subject: [PATCH 04/44] Adding get_deep_features module to extract features and adding more two support functions (#3126) --- .../toolkits/image_analysis/image_analysis.py | 120 ++++++++++++++++++ 1 file changed, 120 insertions(+) diff --git a/src/python/turicreate/toolkits/image_analysis/image_analysis.py b/src/python/turicreate/toolkits/image_analysis/image_analysis.py index 2ad21c5ec6..dd8c48db35 100644 --- a/src/python/turicreate/toolkits/image_analysis/image_analysis.py +++ b/src/python/turicreate/toolkits/image_analysis/image_analysis.py @@ -6,8 +6,20 @@ from __future__ import print_function as _ from __future__ import division as _ from __future__ import absolute_import as _ + +import turicreate as _tc + +import turicreate.toolkits._internal_utils as _tkutl +from .._internal_utils import _mac_ver +from .. import _pre_trained_models from ...data_structures.image import Image as _Image +from .. import _image_feature_extractor +MODEL_TO_FEATURE_SIZE_MAPPING = { + "resnet-50": 2048, + "squeezenet_v1.1": 1000, + "VisionFeaturePrint_Scene": 2048 +} def load_images( url, @@ -177,3 +189,111 @@ def resize(image, width, height, channels=None, decode=False, resample="nearest" raise ValueError( "Cannot call 'resize' on objects that are not either an Image or SArray of Images" ) + + +def get_deep_features(images, model_name, batch_size=64, verbose=True): + """ + Extracts features from images from a specific model. + + Parameters + ---------- + images : SArray + Input data. + + model_name : string + string optional + Uses a pretrained model to bootstrap an image classifier: + + - "resnet-50" : Uses a pretrained resnet model. + Exported Core ML model will be ~90M. + + - "squeezenet_v1.1" : Uses a pretrained squeezenet model. + Exported Core ML model will be ~4.7M. + + - "VisionFeaturePrint_Scene": Uses an OS internal feature extractor. + Only on available on iOS 12.0+, + macOS 10.14+ and tvOS 12.0+. + Exported Core ML model will be ~41K. + + Models are downloaded from the internet if not available locally. Once + downloaded, the models are cached for future use. + + Returns + ------- + out : SArray + Returns an SArray with all the extracted features. + + Examples + -------- + + """ + + # Check model parameter + allowed_models = list(_pre_trained_models.IMAGE_MODELS.keys()) + if _mac_ver() >= (10, 14): + allowed_models.append("VisionFeaturePrint_Scene") + _tkutl._check_categorical_option_type("model", model_name, allowed_models) + + # Check images parameter + if not isinstance(images, _tc.SArray): + raise TypeError("Unrecognized type for 'images'. An SArray is expected.") + if len(images) == 0: + raise _ToolkitError("Unable to extract features on an empty SArray object") + + if batch_size < 1: + raise ValueError("'batch_size' must be greater than or equal to 1") + + # Extract features + feature_extractor = _image_feature_extractor._create_feature_extractor(model_name) + images_sf = _tc.SFrame({"image":images}) + return feature_extractor.extract_features(images_sf, "image", verbose=verbose, + batch_size=batch_size) + + +def find_only_image_extracted_features_column(sframe, model_name): + """ + Finds the only column in `sframe` with a type of array.array and has + the length same as the last layer of the model in use. + If there are zero or more than one image columns, an exception will + be raised. + """ + from array import array + + feature_column = _tkutl._find_only_column_of_type(sframe, target_type=array, type_name="array", col_name="extracted_feature") + if is_image_deep_feature_sarray(sframe[feature_column], model_name): + return feature_column + else: + raise ToolkitError( + 'No "{col_name}" column specified and no column with expected type "{type_name}" is found.'.format( + col_name=feature_column, type_name="array" + ) + + ' "datasets" consists of columns with types: ' + + ", ".join([x.__name__ for x in sframe.column_types()]) + + "." + ) + + +def is_image_deep_feature_sarray(feature_sarray, model_name): + """ + Finds if the given `SArray` has extracted features for a given model_name. + """ + from array import array + + if feature_sarray.dtype != array: + return False + if type(feature_sarray[0]) != array: + return False + if len(feature_sarray[0]) != MODEL_TO_FEATURE_SIZE_MAPPING[model_name]: + return False + return True + + +''' +if __name__ == "__main__": + sframe_path = "/Users/neeraj/Work/cacti/experiments/test_exp/s_frame_data" + model_name = "resnet-50" + feature = "image" + dataset = tc.SFrame(sframe_path) + extracted_features = get_deep_features(dataset, feature, model_name, batch_size=64, verbose=True, dataset_name="data") + extracted_features.save("/Users/neeraj/Downloads/test_sframe") +''' \ No newline at end of file From d8910387f9387e61ab3f97c72669875bab1b2e0a Mon Sep 17 00:00:00 2001 From: Neeraj Komuravalli Date: Wed, 6 May 2020 10:22:19 +0530 Subject: [PATCH 05/44] Adding a way to create model by passing either feature column or image column (#3126) --- .../image_classifier/image_classifier.py | 86 ++++++++++++++----- 1 file changed, 66 insertions(+), 20 deletions(-) diff --git a/src/python/turicreate/toolkits/image_classifier/image_classifier.py b/src/python/turicreate/toolkits/image_classifier/image_classifier.py index 3252a24c7b..85156f91f8 100644 --- a/src/python/turicreate/toolkits/image_classifier/image_classifier.py +++ b/src/python/turicreate/toolkits/image_classifier/image_classifier.py @@ -21,6 +21,7 @@ from .._internal_utils import _mac_ver from .. import _pre_trained_models from .. import _image_feature_extractor +from ..image_analysis import image_analysis from ._evaluation import Evaluation as _Evaluation _DEFAULT_SOLVER_OPTIONS = { @@ -70,10 +71,10 @@ def create( the order in which the classes are mapped. feature : string, optional - indicates that the SFrame has only column of Image type and that will - Name of the column containing the input images. 'None' (the default) - indicates the only image column in `dataset` should be used as the - feature. + indicates that the SFrame has either column of Image type or array type + (extracted features) and that will be the name of the column containing the input + images or features. 'None' (the default) indicates that only feature column or the + only image column in `dataset` should be used as the feature. l2_penalty : float, optional Weight on l2 regularization of the model. The larger this weight, the @@ -250,29 +251,74 @@ def create( raise TypeError("Unrecognized value for 'validation_set'.") if feature is None: - feature = _tkutl._find_only_image_column(dataset) + # select feature column : either extracted features columns or image column itself + try: + feature = image_analysis.find_only_image_extracted_features_column(dataset, model) + feature_type = "extracted_features_array" + except: + feature = None + if feature is None: + try: + feature = _tkutl._find_only_image_column(dataset) + feature_type = "image" + except: + raise _ToolkitError( + 'No feature column specified and no column with expected type image or array is found.' + + ' "datasets" consists of columns with types: ' + + ", ".join([x.__name__ for x in dataset.column_types()]) + + "." + ) + else: + if image_analysis.is_image_deep_feature_sarray(dataset[feature], model): + feature_type = "extracted_features_array" + elif dataset[feature].dtype is _tc.Image: + feature_type = "image" + else: + raise _ToolkitError('The "{feature}" column of the sFrame neither has the dataype image or array (for extracted features)'.format(feature=feature) + + ' "datasets" consists of columns with types: ' + + ", ".join([x.__name__ for x in dataset.column_types()]) + + "." + ) + _tkutl._handle_missing_values(dataset, feature, "training_dataset") feature_extractor = _image_feature_extractor._create_feature_extractor(model) - - # Extract features - extracted_features = _tc.SFrame( - { - target: dataset[target], - "__image_features__": feature_extractor.extract_features( - dataset, feature, verbose=verbose, batch_size=batch_size - ), - } - ) - if isinstance(validation_set, _tc.SFrame): - _tkutl._handle_missing_values(dataset, feature, "validation_set") - extracted_features_validation = _tc.SFrame( + if feature_type == "image": + # Extract features + extracted_features = _tc.SFrame( { - target: validation_set[target], + target: dataset[target], "__image_features__": feature_extractor.extract_features( - validation_set, feature, verbose=verbose, batch_size=batch_size + dataset, feature, verbose=verbose, batch_size=batch_size ), } ) + else: + extracted_features = _tc.SFrame( + { + target: dataset[target], + "__image_features__": dataset[feature] + } + ) + + # Validation set + if isinstance(validation_set, _tc.SFrame): + if feature_type == "image": + _tkutl._handle_missing_values(validation_set, feature, "validation_set") + extracted_features_validation = _tc.SFrame( + { + target: validation_set[target], + "__image_features__": feature_extractor.extract_features( + validation_set, feature, verbose=verbose, batch_size=batch_size + ), + } + ) + else: + extracted_features_validation = _tc.SFrame( + { + target: validation_set[target], + "__image_features__": validation_set[feature] + } + ) else: extracted_features_validation = validation_set From 18d5b70f5e19ed8edd5e7249039d52e4b4010324 Mon Sep 17 00:00:00 2001 From: Neeraj Komuravalli Date: Wed, 6 May 2020 10:23:06 +0530 Subject: [PATCH 06/44] Adding a way to create model by passing either feature column or image column (#3126) --- .../image_similarity/image_similarity.py | 61 +++++++++++++++---- 1 file changed, 48 insertions(+), 13 deletions(-) diff --git a/src/python/turicreate/toolkits/image_similarity/image_similarity.py b/src/python/turicreate/toolkits/image_similarity/image_similarity.py index e4ffbf8231..830b89aa57 100644 --- a/src/python/turicreate/toolkits/image_similarity/image_similarity.py +++ b/src/python/turicreate/toolkits/image_similarity/image_similarity.py @@ -19,6 +19,7 @@ from .._internal_utils import _mac_ver from .. import _pre_trained_models from .. import _image_feature_extractor +from ..image_analysis import image_analysis def create( @@ -39,9 +40,9 @@ def create( identify reference dataset rows when the model is queried. feature : string - Name of the column containing the input images. 'None' (the default) - indicates that the SFrame has only one column of Image type and that will - be used for similarity. + Name of the column containing either the input images or extracted features. + 'None' (the default) indicates that only feature column or the only image + column in `dataset` should be used as the feature. model: string, optional Uses a pretrained model to bootstrap an image similarity model @@ -127,18 +128,52 @@ def create( # Set defaults if feature is None: - feature = _tkutl._find_only_image_column(dataset) + # select feature column : either extracted features columns or image column itself + try: + feature = image_analysis.find_only_image_extracted_features_column(dataset, model) + feature_type = "extracted_features_array" + except: + feature = None + if feature is None: + try: + feature = _tkutl._find_only_image_column(dataset) + feature_type = "image" + except: + raise _ToolkitError( + 'No feature column specified and no column with expected type image or array is found.' + + ' "datasets" consists of columns with types: ' + + ", ".join([x.__name__ for x in dataset.column_types()]) + + "." + ) + else: + if image_analysis.is_image_deep_feature_sarray(dataset[feature], model): + feature_type = "extracted_features_array" + elif dataset[feature].dtype is _tc.Image: + feature_type = "image" + else: + raise _ToolkitError('The "{feature}" column of the sFrame neither has the dataype image or array (for extracted features)'.format(feature=feature) + + ' "datasets" consists of columns with types: ' + + ", ".join([x.__name__ for x in dataset.column_types()]) + + "." + ) + _tkutl._handle_missing_values(dataset, feature) feature_extractor = _image_feature_extractor._create_feature_extractor(model) - - # Extract features - extracted_features = _tc.SFrame( - { - "__image_features__": feature_extractor.extract_features( - dataset, feature, verbose=verbose, batch_size=batch_size - ), - } - ) + if feature_type == "image": + # Extract features + extracted_features = _tc.SFrame( + { + "__image_features__": feature_extractor.extract_features( + dataset, feature, verbose=verbose, batch_size=batch_size + ), + } + ) + else: + extracted_features = _tc.SFrame( + { + "__image_features__": dataset[feature] + } + ) # Train a similarity model using the extracted features if label is not None: From 40ec7a5ac722c9155ac506b50d39e227a3a4c898 Mon Sep 17 00:00:00 2001 From: Neeraj Komuravalli Date: Fri, 8 May 2020 03:51:59 +0530 Subject: [PATCH 07/44] Fixing syntax error --- .../turicreate/toolkits/image_analysis/image_analysis.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/python/turicreate/toolkits/image_analysis/image_analysis.py b/src/python/turicreate/toolkits/image_analysis/image_analysis.py index dd8c48db35..ff8bcf7577 100644 --- a/src/python/turicreate/toolkits/image_analysis/image_analysis.py +++ b/src/python/turicreate/toolkits/image_analysis/image_analysis.py @@ -10,6 +10,7 @@ import turicreate as _tc import turicreate.toolkits._internal_utils as _tkutl +from turicreate.toolkits._main import ToolkitError as _ToolkitError from .._internal_utils import _mac_ver from .. import _pre_trained_models from ...data_structures.image import Image as _Image @@ -263,7 +264,7 @@ def find_only_image_extracted_features_column(sframe, model_name): if is_image_deep_feature_sarray(sframe[feature_column], model_name): return feature_column else: - raise ToolkitError( + raise _ToolkitError( 'No "{col_name}" column specified and no column with expected type "{type_name}" is found.'.format( col_name=feature_column, type_name="array" ) From d51b1936df482f3d8599e74b06322fa10ed25f2e Mon Sep 17 00:00:00 2001 From: Neeraj Komuravalli Date: Fri, 8 May 2020 03:53:07 +0530 Subject: [PATCH 08/44] Adding more elaborate error messages to also include Missing value errors --- .../toolkits/image_classifier/image_classifier.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/python/turicreate/toolkits/image_classifier/image_classifier.py b/src/python/turicreate/toolkits/image_classifier/image_classifier.py index 85156f91f8..3624fb6885 100644 --- a/src/python/turicreate/toolkits/image_classifier/image_classifier.py +++ b/src/python/turicreate/toolkits/image_classifier/image_classifier.py @@ -263,7 +263,7 @@ def create( feature_type = "image" except: raise _ToolkitError( - 'No feature column specified and no column with expected type image or array is found.' + 'No feature column specified and no column with expected type image or extracted features array is found.' + ' "datasets" consists of columns with types: ' + ", ".join([x.__name__ for x in dataset.column_types()]) + "." @@ -274,8 +274,8 @@ def create( elif dataset[feature].dtype is _tc.Image: feature_type = "image" else: - raise _ToolkitError('The "{feature}" column of the sFrame neither has the dataype image or array (for extracted features)'.format(feature=feature) - + ' "datasets" consists of columns with types: ' + raise _ToolkitError('The "{feature}" column of the sFrame neither has the dataype image or extracted features array.'.format(feature=feature) + + ' "Datasets" consists of columns with types: ' + ", ".join([x.__name__ for x in dataset.column_types()]) + "." ) From ea237b5399a641c76ce82af2c08510cfc58bf58b Mon Sep 17 00:00:00 2001 From: Neeraj Komuravalli Date: Fri, 8 May 2020 03:54:51 +0530 Subject: [PATCH 09/44] Adding image_classifier test methods to include testing for data with and without extracted_features column --- .../turicreate/test/test_image_classifier.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/python/turicreate/test/test_image_classifier.py b/src/python/turicreate/test/test_image_classifier.py index 8311435fa8..d6cd86702e 100644 --- a/src/python/turicreate/test/test_image_classifier.py +++ b/src/python/turicreate/test/test_image_classifier.py @@ -153,10 +153,16 @@ def test_create_with_missing_value(self): data_with_none = data.append( tc.SFrame(data_dict) ) + # testing with Image type as input features with self.assertRaises(_ToolkitError): tc.image_classifier.create( data_with_none, feature=self.feature, target=self.target ) + # testing with extracted features as input feature + with self.assertRaises(_ToolkitError): + tc.image_classifier.create( + data_with_none, feature=str(MODEL_TO_FEATURE_SIZE_MAPPING[self.pre_trained_model]), target=self.target + ) def test_create_with_missing_feature(self): with self.assertRaises(_ToolkitError): @@ -174,6 +180,18 @@ def test_create_with_empty_dataset(self): with self.assertRaises(_ToolkitError): tc.image_classifier.create(data[:0], target=self.target) + def test_select_correct_feature_column_to_train(self): + # sending both, the correct extracted features colum and image column + extracted_feature_column_name = str(MODEL_TO_FEATURE_SIZE_MAPPING[self.pre_trained_model]) + test_model = tc.image_classifier.create(data, target=self.target) + self.assertTrue(test_model.feature == extracted_feature_column_name) + + # sending the wrong exracted features column along with the image column + columns_name_list = list(filter(lambda x: x != extracted_feature_column_name, data.column_names())) + test_data = data.select_columns(columns_name_list) + test_model = tc.image_classifier.create(test_data, target=self.target) + self.assertTrue(test_model.feature == "awesome_image") + def test_predict(self): model = self.model for output_type in ["class", "probability_vector"]: From f1ea4ac76ec92fa6a77f5773dc81f48ab9ccc4f6 Mon Sep 17 00:00:00 2001 From: Neeraj Komuravalli Date: Tue, 12 May 2020 21:37:18 +0530 Subject: [PATCH 10/44] Making Image feature extraction feature more robust and indipendent --- .../toolkits/image_analysis/image_analysis.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/python/turicreate/toolkits/image_analysis/image_analysis.py b/src/python/turicreate/toolkits/image_analysis/image_analysis.py index ff8bcf7577..e9d457468b 100644 --- a/src/python/turicreate/toolkits/image_analysis/image_analysis.py +++ b/src/python/turicreate/toolkits/image_analysis/image_analysis.py @@ -260,19 +260,28 @@ def find_only_image_extracted_features_column(sframe, model_name): """ from array import array - feature_column = _tkutl._find_only_column_of_type(sframe, target_type=array, type_name="array", col_name="extracted_feature") - if is_image_deep_feature_sarray(sframe[feature_column], model_name): - return feature_column - else: + try: + feature_columns, _ = zip(*list(filter(lambda x: x[1] == array, list(zip(sframe.column_names(), sframe.column_types()))))) + except ValueError: raise _ToolkitError( 'No "{col_name}" column specified and no column with expected type "{type_name}" is found.'.format( - col_name=feature_column, type_name="array" + col_name="extracted_features", type_name="array" ) + ' "datasets" consists of columns with types: ' + ", ".join([x.__name__ for x in sframe.column_types()]) + "." ) + feature_columns = list(filter(lambda x: is_image_deep_feature_sarray(sframe[x], model_name), feature_columns)) + if len(feature_columns) == 1: + return feature_columns[0] + elif len(feature_columns) > 1: + raise _ToolkitError( + 'No "{col_name}" column specified and more than one extracted features {type_name} column in "dataset". Can not infer correct {col_name} column.'.format( + col_name="extracted_features", type_name="array" + ) + ) + def is_image_deep_feature_sarray(feature_sarray, model_name): """ From 8e4583361973f58631471c714bdb260120c08770 Mon Sep 17 00:00:00 2001 From: Neeraj Komuravalli Date: Tue, 12 May 2020 21:42:15 +0530 Subject: [PATCH 11/44] Changing the _extract_features functions to first recognize the feature type and then take the decision --- .../image_classifier/image_classifier.py | 31 +++++++++++++------ 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/src/python/turicreate/toolkits/image_classifier/image_classifier.py b/src/python/turicreate/toolkits/image_classifier/image_classifier.py index 3624fb6885..5c084c8986 100644 --- a/src/python/turicreate/toolkits/image_classifier/image_classifier.py +++ b/src/python/turicreate/toolkits/image_classifier/image_classifier.py @@ -251,12 +251,12 @@ def create( raise TypeError("Unrecognized value for 'validation_set'.") if feature is None: - # select feature column : either extracted features columns or image column itself try: feature = image_analysis.find_only_image_extracted_features_column(dataset, model) feature_type = "extracted_features_array" except: feature = None + if feature is None: try: feature = _tkutl._find_only_image_column(dataset) @@ -880,14 +880,27 @@ def evaluate(self, dataset, metric="auto", verbose=True, batch_size=64): return _Evaluation(evaluation_result) - def _extract_features(self, dataset, verbose=False, batch_size=64): - return _tc.SFrame( - { - "__image_features__": self.feature_extractor.extract_features( - dataset, self.feature, verbose=verbose, batch_size=batch_size - ) - } - ) + def _extract_features(self, dataset, verbose=False, batch_size=64): + if image_analysis.is_image_deep_feature_sarray(dataset[self.feature], self.model): + return _tc.SFrame( + { + "__image_features__": dataset[self.feature] + } + ) + elif dataset[self.feature].dtype is _tc.Image: + return _tc.SFrame( + { + "__image_features__": self.feature_extractor.extract_features( + dataset, self.feature, verbose=verbose, batch_size=batch_size + ) + } + ) + else: + raise _ToolkitError('The "{feature}" column of the sFrame neither has the dataype image or extracted features array.'.format(feature=feature) + + ' "Datasets" consists of columns with types: ' + + ", ".join([x.__name__ for x in dataset.column_types()]) + + "." + ) def export_coreml(self, filename): """ From e14a97bfbddf8c6bb226bc266fd1333bf847085e Mon Sep 17 00:00:00 2001 From: Neeraj Komuravalli Date: Tue, 12 May 2020 21:44:22 +0530 Subject: [PATCH 12/44] Doing small edits --- .../turicreate/toolkits/image_classifier/image_classifier.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/python/turicreate/toolkits/image_classifier/image_classifier.py b/src/python/turicreate/toolkits/image_classifier/image_classifier.py index 5c084c8986..44dd7b6b61 100644 --- a/src/python/turicreate/toolkits/image_classifier/image_classifier.py +++ b/src/python/turicreate/toolkits/image_classifier/image_classifier.py @@ -880,7 +880,7 @@ def evaluate(self, dataset, metric="auto", verbose=True, batch_size=64): return _Evaluation(evaluation_result) - def _extract_features(self, dataset, verbose=False, batch_size=64): + def _extract_features(self, dataset, verbose=False, batch_size=64): if image_analysis.is_image_deep_feature_sarray(dataset[self.feature], self.model): return _tc.SFrame( { From 7dc12a170bcfa5feb7c6322994c802db8a32333f Mon Sep 17 00:00:00 2001 From: Neeraj Komuravalli Date: Wed, 13 May 2020 15:31:17 +0530 Subject: [PATCH 13/44] Changing the _extract_features functions to first recognize the feature type and then take the decision --- .../image_similarity/image_similarity.py | 29 ++++++++++++++----- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/src/python/turicreate/toolkits/image_similarity/image_similarity.py b/src/python/turicreate/toolkits/image_similarity/image_similarity.py index 830b89aa57..475fa8d2d7 100644 --- a/src/python/turicreate/toolkits/image_similarity/image_similarity.py +++ b/src/python/turicreate/toolkits/image_similarity/image_similarity.py @@ -334,14 +334,27 @@ def _get_summary_struct(self): section_titles = ["Schema", "Training summary"] return ([model_fields, training_fields], section_titles) - def _extract_features(self, dataset, verbose, batch_size=64): - return _tc.SFrame( - { - "__image_features__": self.feature_extractor.extract_features( - dataset, self.feature, verbose=verbose, batch_size=batch_size - ) - } - ) + def _extract_features(self, dataset, verbose=False, batch_size=64): + if image_analysis.is_image_deep_feature_sarray(dataset[self.feature], self.model): + return _tc.SFrame( + { + "__image_features__": dataset[self.feature] + } + ) + elif dataset[self.feature].dtype is _tc.Image: + return _tc.SFrame( + { + "__image_features__": self.feature_extractor.extract_features( + dataset, self.feature, verbose=verbose, batch_size=batch_size + ) + } + ) + else: + raise _ToolkitError('The "{feature}" column of the sFrame neither has the dataype image or extracted features array.'.format(feature=feature) + + ' "Datasets" consists of columns with types: ' + + ", ".join([x.__name__ for x in dataset.column_types()]) + + "." + ) def query(self, dataset, label=None, k=5, radius=None, verbose=True, batch_size=64): """ From 8cc488df392b20673aa0e0355ee298ff64e49713 Mon Sep 17 00:00:00 2001 From: Neeraj Komuravalli Date: Wed, 13 May 2020 16:32:55 +0530 Subject: [PATCH 14/44] passing model name specifically in test_select_correct_feature_column_to_train test case --- src/python/turicreate/test/test_image_classifier.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/python/turicreate/test/test_image_classifier.py b/src/python/turicreate/test/test_image_classifier.py index d6cd86702e..83393995e8 100644 --- a/src/python/turicreate/test/test_image_classifier.py +++ b/src/python/turicreate/test/test_image_classifier.py @@ -105,7 +105,7 @@ def setUpClass( self.tolerance = tol self.model = tc.image_classifier.create( - data, target=self.target, model=self.pre_trained_model, seed=42 + data, target=self.target, feature=self.feature, model=self.pre_trained_model, seed=42 ) self.nn_model = self.model.feature_extractor self.lm_model = self.model.classifier @@ -183,13 +183,13 @@ def test_create_with_empty_dataset(self): def test_select_correct_feature_column_to_train(self): # sending both, the correct extracted features colum and image column extracted_feature_column_name = str(MODEL_TO_FEATURE_SIZE_MAPPING[self.pre_trained_model]) - test_model = tc.image_classifier.create(data, target=self.target) + test_model = tc.image_classifier.create(data, target=self.target, model=self.pre_trained_model) self.assertTrue(test_model.feature == extracted_feature_column_name) # sending the wrong exracted features column along with the image column columns_name_list = list(filter(lambda x: x != extracted_feature_column_name, data.column_names())) test_data = data.select_columns(columns_name_list) - test_model = tc.image_classifier.create(test_data, target=self.target) + test_model = tc.image_classifier.create(test_data, target=self.target, model=self.pre_trained_model) self.assertTrue(test_model.feature == "awesome_image") def test_predict(self): From 62aa5e27a769b35bf3bab8dc12762aa496248936 Mon Sep 17 00:00:00 2001 From: Neeraj Komuravalli Date: Thu, 14 May 2020 19:39:32 +0530 Subject: [PATCH 15/44] Adding a way to account for extracted features instead of images as inoput features in classify, predict and _canonize_input functions --- .../image_classifier/image_classifier.py | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/python/turicreate/toolkits/image_classifier/image_classifier.py b/src/python/turicreate/toolkits/image_classifier/image_classifier.py index 44dd7b6b61..fbe4e90b2d 100644 --- a/src/python/turicreate/toolkits/image_classifier/image_classifier.py +++ b/src/python/turicreate/toolkits/image_classifier/image_classifier.py @@ -489,12 +489,15 @@ def _canonize_input(self, dataset): along with an unpack callback function that can be applied to prediction results to "undo" the canonization. """ + from array import array + unpack = lambda x: x if isinstance(dataset, _tc.SArray): dataset = _tc.SFrame({self.feature: dataset}) - elif isinstance(dataset, _tc.Image): + elif isinstance(dataset, _tc.Image) or isinstance(dataset, array): dataset = _tc.SFrame({self.feature: [dataset]}) unpack = lambda x: x[0] + return dataset, unpack def predict(self, dataset, output_type="class", batch_size=64): @@ -516,8 +519,8 @@ def predict(self, dataset, output_type="class", batch_size=64): Parameters ---------- - dataset : SFrame | SArray | turicreate.Image - The images to be classified. + dataset : SFrame | SArray | turicreate.Image | array + The images to be classified or extracted features. If dataset is an SFrame, it must have columns with the same names as the features used for model training, but does not require a target column. Additional columns are ignored. @@ -555,7 +558,9 @@ class as a vector. The probability of the first class (sorted >>> class_predictions = model.predict(data, output_type='class') """ - if not isinstance(dataset, (_tc.SFrame, _tc.SArray, _tc.Image)): + from array import array + + if not isinstance(dataset, (_tc.SFrame, _tc.SArray, _tc.Image, array)): raise TypeError( "dataset must be either an SFrame, SArray or turicreate.Image" ) @@ -604,7 +609,9 @@ def classify(self, dataset, batch_size=64): >>> classes = model.classify(data) """ - if not isinstance(dataset, (_tc.SFrame, _tc.SArray, _tc.Image)): + from array import array + + if not isinstance(dataset, (_tc.SFrame, _tc.SArray, _tc.Image, array)): raise TypeError( "dataset must be either an SFrame, SArray or turicreate.Image" ) @@ -671,7 +678,9 @@ def predict_topk(self, dataset, output_type="probability", k=3, batch_size=64): +----+-------+-------------------+ [35688 rows x 3 columns] """ - if not isinstance(dataset, (_tc.SFrame, _tc.SArray, _tc.Image)): + from array import array + + if not isinstance(dataset, (_tc.SFrame, _tc.SArray, _tc.Image, array)): raise TypeError( "dataset must be either an SFrame, SArray or turicreate.Image" ) @@ -881,7 +890,7 @@ def evaluate(self, dataset, metric="auto", verbose=True, batch_size=64): return _Evaluation(evaluation_result) def _extract_features(self, dataset, verbose=False, batch_size=64): - if image_analysis.is_image_deep_feature_sarray(dataset[self.feature], self.model): + if image_analysis.is_image_deep_feature_sarray(dataset[self.feature], self.model): return _tc.SFrame( { "__image_features__": dataset[self.feature] From e0a301a9ad91e89a9d122d7302868d50aff7b6a1 Mon Sep 17 00:00:00 2001 From: Neeraj Komuravalli Date: Thu, 14 May 2020 19:55:42 +0530 Subject: [PATCH 16/44] Adding feature based test cases for both image as a feature and extracted features as feature --- .../turicreate/test/test_image_classifier.py | 64 ++++++++++++++----- 1 file changed, 48 insertions(+), 16 deletions(-) diff --git a/src/python/turicreate/test/test_image_classifier.py b/src/python/turicreate/test/test_image_classifier.py index 83393995e8..e85c7e4d50 100644 --- a/src/python/turicreate/test/test_image_classifier.py +++ b/src/python/turicreate/test/test_image_classifier.py @@ -93,12 +93,13 @@ class ImageClassifierTest(unittest.TestCase): def setUpClass( self, model="resnet-50", + feature="awesome_image", input_image_shape=(3, 224, 224), tol=0.02, num_examples=100, label_type=int, ): - self.feature = "awesome_image" + self.feature = feature self.target = "awesome_label" self.input_image_shape = input_image_shape self.pre_trained_model = model @@ -141,28 +142,17 @@ def assertListAlmostEquals(self, list1, list2, tol): self.assertAlmostEqual(a, b, delta=tol) def test_create_with_missing_value(self): - from array import array - - data_dict = { - self.feature: tc.SArray([None], dtype=tc.Image), - self.target: [data[self.target][0]], - } - possible_feature_length_list = list(set(MODEL_TO_FEATURE_SIZE_MAPPING.values())) - for feature_length in possible_feature_length_list: - data_dict[str(feature_length)] = tc.SArray([None], dtype=array) + data_dict = {} + for col_name, col_type in zip(data.column_names(), data.column_types()): + data_dict[col_name] = tc.SArray([None], dtype=col_type) data_with_none = data.append( tc.SFrame(data_dict) ) - # testing with Image type as input features + with self.assertRaises(_ToolkitError): tc.image_classifier.create( data_with_none, feature=self.feature, target=self.target ) - # testing with extracted features as input feature - with self.assertRaises(_ToolkitError): - tc.image_classifier.create( - data_with_none, feature=str(MODEL_TO_FEATURE_SIZE_MAPPING[self.pre_trained_model]), target=self.target - ) def test_create_with_missing_feature(self): with self.assertRaises(_ToolkitError): @@ -360,6 +350,29 @@ def test_evaluate_explore(self): evaluation.explore() +class ImageClassifierSqueezeNetTest(ImageClassifierTest): + @classmethod + def setUpClass(self): + super(ImageClassifierSqueezeNetTest, self).setUpClass( + model="resnet-50", + input_image_shape=(3, 227, 227), + tol=0.005, + num_examples=200, + feature="2048", + ) + + +class ImageClassifierSqueezeNetTest(ImageClassifierTest): + @classmethod + def setUpClass(self): + super(ImageClassifierSqueezeNetTest, self).setUpClass( + model="squeezenet_v1.1", + input_image_shape=(3, 227, 227), + tol=0.005, + num_examples=200, + feature="awesome_image", + ) + class ImageClassifierSqueezeNetTest(ImageClassifierTest): @classmethod def setUpClass(self): @@ -368,6 +381,24 @@ def setUpClass(self): input_image_shape=(3, 227, 227), tol=0.005, num_examples=200, + feature="1000", + ) + + +# TODO: if on skip OS, test negative case +@unittest.skipIf( + _mac_ver() < (10, 14), "VisionFeaturePrint_Scene only supported on macOS 10.14+" +) +class VisionFeaturePrintSceneTest(ImageClassifierTest): + @classmethod + def setUpClass(self): + super(VisionFeaturePrintSceneTest, self).setUpClass( + model="VisionFeaturePrint_Scene", + input_image_shape=(3, 299, 299), + tol=0.005, + num_examples=100, + label_type=str, + feature="awesome_image", ) @@ -384,4 +415,5 @@ def setUpClass(self): tol=0.005, num_examples=100, label_type=str, + feature="2048", ) From 1aa4dc1065ffb11ba5797708547c3b00d2042b2b Mon Sep 17 00:00:00 2001 From: Neeraj Komuravalli Date: Fri, 15 May 2020 21:17:50 +0530 Subject: [PATCH 17/44] Using actual features using get_deep_features instead of randomly generating features --- .../turicreate/test/test_image_classifier.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/python/turicreate/test/test_image_classifier.py b/src/python/turicreate/test/test_image_classifier.py index e85c7e4d50..b906f74850 100644 --- a/src/python/turicreate/test/test_image_classifier.py +++ b/src/python/turicreate/test/test_image_classifier.py @@ -19,7 +19,7 @@ _raise_error_if_not_sframe, _raise_error_if_not_sarray, ) -from turicreate.toolkits.image_analysis.image_analysis import MODEL_TO_FEATURE_SIZE_MAPPING +from turicreate.toolkits.image_analysis.image_analysis import MODEL_TO_FEATURE_SIZE_MAPPING, get_deep_features from . import util as test_util @@ -77,12 +77,14 @@ def get_test_data(): labels = ["white"] * 5 + ["black"] * 5 data_dict = {"awesome_image": images, "awesome_label": labels} - possible_feature_length_list = list(set(MODEL_TO_FEATURE_SIZE_MAPPING.values())) - no_of_columns = len(data_dict[[*data_dict][0]]) - for feature_length in possible_feature_length_list: - data_dict[str(feature_length)] = tc.SArray(np.random.rand(no_of_columns, feature_length)*100, dtype=array) + data = tc.SFrame(data_dict) - return tc.SFrame(data_dict) + for model_name, feature_length in MODEL_TO_FEATURE_SIZE_MAPPING.items(): + if str(feature_length) in data_dict.keys(): + continue + data[str(feature_length)] = get_deep_features(data["awesome_image"], model_name) + + return data data = get_test_data() @@ -175,8 +177,8 @@ def test_select_correct_feature_column_to_train(self): extracted_feature_column_name = str(MODEL_TO_FEATURE_SIZE_MAPPING[self.pre_trained_model]) test_model = tc.image_classifier.create(data, target=self.target, model=self.pre_trained_model) self.assertTrue(test_model.feature == extracted_feature_column_name) - - # sending the wrong exracted features column along with the image column + + # sending the wrong exracted features column along with the image column columns_name_list = list(filter(lambda x: x != extracted_feature_column_name, data.column_names())) test_data = data.select_columns(columns_name_list) test_model = tc.image_classifier.create(test_data, target=self.target, model=self.pre_trained_model) From 4bfedd9805ead324b303f0badc7dd393d85b2bce Mon Sep 17 00:00:00 2001 From: Neeraj Komuravalli Date: Fri, 15 May 2020 21:19:09 +0530 Subject: [PATCH 18/44] Adding test cases for model using both image and extracted_feature as input feature --- .../turicreate/test/test_image_similarity.py | 61 +++++++++++++++---- 1 file changed, 50 insertions(+), 11 deletions(-) diff --git a/src/python/turicreate/test/test_image_similarity.py b/src/python/turicreate/test/test_image_similarity.py index a6bcfe63af..ce60c49ef6 100644 --- a/src/python/turicreate/test/test_image_similarity.py +++ b/src/python/turicreate/test/test_image_similarity.py @@ -14,7 +14,7 @@ from . import util as test_util from turicreate.toolkits._main import ToolkitError as _ToolkitError -from turicreate.toolkits.image_analysis.image_analysis import MODEL_TO_FEATURE_SIZE_MAPPING +from turicreate.toolkits.image_analysis.image_analysis import MODEL_TO_FEATURE_SIZE_MAPPING, get_deep_features import coremltools import numpy as np @@ -68,12 +68,14 @@ def get_test_data(): images.append(tc_image) data_dict = {"awesome_image": images} - no_of_columns = len(data_dict[[*data_dict][0]]) - possible_feature_length_list = list(set(MODEL_TO_FEATURE_SIZE_MAPPING.values())) - for feature_length in possible_feature_length_list: - data_dict[str(feature_length)] = tc.SArray(np.random.rand(no_of_columns, feature_length)*100, dtype=array) + data = tc.SFrame(data_dict) - return tc.SFrame(data_dict) + for model_name, feature_length in MODEL_TO_FEATURE_SIZE_MAPPING.items(): + if str(feature_length) in data_dict.keys(): + continue + data[str(feature_length)] = get_deep_features(data["awesome_image"], model_name) + + return data data = get_test_data() @@ -81,11 +83,11 @@ def get_test_data(): class ImageSimilarityTest(unittest.TestCase): @classmethod - def setUpClass(self, input_image_shape=(3, 224, 224), model="resnet-50"): + def setUpClass(self, input_image_shape=(3, 224, 224), model="resnet-50", feature="awesome_image"): """ The setup class method for the basic test case with all default values. """ - self.feature = "awesome_image" + self.feature = feature self.label = None self.input_image_shape = input_image_shape self.pre_trained_model = model @@ -300,7 +302,23 @@ class ImageSimilaritySqueezeNetTest(ImageSimilarityTest): @classmethod def setUpClass(self): super(ImageSimilaritySqueezeNetTest, self).setUpClass( - model="squeezenet_v1.1", input_image_shape=(3, 227, 227) + model="resnet-50", input_image_shape=(3, 227, 227), feature="2048" + ) + + +class ImageSimilaritySqueezeNetTest(ImageSimilarityTest): + @classmethod + def setUpClass(self): + super(ImageSimilaritySqueezeNetTest, self).setUpClass( + model="squeezenet_v1.1", input_image_shape=(3, 227, 227), feature="awesome_image" + ) + + +class ImageSimilaritySqueezeNetTest(ImageSimilarityTest): + @classmethod + def setUpClass(self): + super(ImageSimilaritySqueezeNetTest, self).setUpClass( + model="squeezenet_v1.1", input_image_shape=(3, 227, 227), feature="1000" ) @@ -311,10 +329,20 @@ class ImageSimilarityVisionFeaturePrintSceneTest(ImageSimilarityTest): @classmethod def setUpClass(self): super(ImageSimilarityVisionFeaturePrintSceneTest, self).setUpClass( - model="VisionFeaturePrint_Scene", input_image_shape=(3, 299, 299) + model="VisionFeaturePrint_Scene", input_image_shape=(3, 299, 299), feature="awesome_image" ) +@unittest.skipIf( + _mac_ver() < (10, 14), "VisionFeaturePrint_Scene only supported on macOS 10.14+" +) +class ImageSimilarityVisionFeaturePrintSceneTest(ImageSimilarityTest): + @classmethod + def setUpClass(self): + super(ImageSimilarityVisionFeaturePrintSceneTest, self).setUpClass( + model="VisionFeaturePrint_Scene", input_image_shape=(3, 299, 299), feature="2048" + ) + # A test to gaurantee that old code using the incorrect name still works. @unittest.skipIf( _mac_ver() < (10, 14), "VisionFeaturePrint_Scene only supported on macOS 10.14+" @@ -323,5 +351,16 @@ class ImageSimilarityVisionFeaturePrintSceneTest_bad_name(ImageSimilarityTest): @classmethod def setUpClass(self): super(ImageSimilarityVisionFeaturePrintSceneTest_bad_name, self).setUpClass( - model="VisionFeaturePrint_Screen", input_image_shape=(3, 299, 299) + model="VisionFeaturePrint_Screen", input_image_shape=(3, 299, 299), feature="awesome_image" + ) + + +@unittest.skipIf( + _mac_ver() < (10, 14), "VisionFeaturePrint_Scene only supported on macOS 10.14+" +) +class ImageSimilarityVisionFeaturePrintSceneTest_bad_name(ImageSimilarityTest): + @classmethod + def setUpClass(self): + super(ImageSimilarityVisionFeaturePrintSceneTest_bad_name, self).setUpClass( + model="VisionFeaturePrint_Screen", input_image_shape=(3, 299, 299), feature="2048" ) From e7195d6b5ddd6bed8077e55f36e444f4f967d9b3 Mon Sep 17 00:00:00 2001 From: Neeraj Komuravalli Date: Fri, 15 May 2020 21:21:59 +0530 Subject: [PATCH 19/44] Removing unnecessary code --- .../toolkits/image_analysis/image_analysis.py | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/src/python/turicreate/toolkits/image_analysis/image_analysis.py b/src/python/turicreate/toolkits/image_analysis/image_analysis.py index e9d457468b..0c7bf0938f 100644 --- a/src/python/turicreate/toolkits/image_analysis/image_analysis.py +++ b/src/python/turicreate/toolkits/image_analysis/image_analysis.py @@ -243,7 +243,7 @@ def get_deep_features(images, model_name, batch_size=64, verbose=True): if batch_size < 1: raise ValueError("'batch_size' must be greater than or equal to 1") - + # Extract features feature_extractor = _image_feature_extractor._create_feature_extractor(model_name) images_sf = _tc.SFrame({"image":images}) @@ -296,14 +296,3 @@ def is_image_deep_feature_sarray(feature_sarray, model_name): if len(feature_sarray[0]) != MODEL_TO_FEATURE_SIZE_MAPPING[model_name]: return False return True - - -''' -if __name__ == "__main__": - sframe_path = "/Users/neeraj/Work/cacti/experiments/test_exp/s_frame_data" - model_name = "resnet-50" - feature = "image" - dataset = tc.SFrame(sframe_path) - extracted_features = get_deep_features(dataset, feature, model_name, batch_size=64, verbose=True, dataset_name="data") - extracted_features.save("/Users/neeraj/Downloads/test_sframe") -''' \ No newline at end of file From c874c97f9fb77de682eb7454a07f767bc107f12b Mon Sep 17 00:00:00 2001 From: Neeraj Komuravalli Date: Fri, 15 May 2020 21:24:08 +0530 Subject: [PATCH 20/44] Adding a way to accept input as extracted feature in quary function --- .../toolkits/image_similarity/image_similarity.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/python/turicreate/toolkits/image_similarity/image_similarity.py b/src/python/turicreate/toolkits/image_similarity/image_similarity.py index 475fa8d2d7..637f66d098 100644 --- a/src/python/turicreate/toolkits/image_similarity/image_similarity.py +++ b/src/python/turicreate/toolkits/image_similarity/image_similarity.py @@ -429,7 +429,9 @@ def query(self, dataset, label=None, k=5, radius=None, verbose=True, batch_size= | 2 | 1 | 0.464004310325 | 2 | +-------------+-----------------+----------------+------+ """ - if not isinstance(dataset, (_tc.SFrame, _tc.SArray, _tc.Image)): + from array import array + + if not isinstance(dataset, (_tc.SFrame, _tc.SArray, _tc.Image, array)): raise TypeError( "dataset must be either an SFrame, SArray or turicreate.Image" ) @@ -438,7 +440,7 @@ def query(self, dataset, label=None, k=5, radius=None, verbose=True, batch_size= if isinstance(dataset, _tc.SArray): dataset = _tc.SFrame({self.feature: dataset}) - elif isinstance(dataset, _tc.Image): + elif isinstance(dataset, _tc.Image) or isinstance(dataset, array): dataset = _tc.SFrame({self.feature: [dataset]}) extracted_features = self._extract_features( From 049c1e5100723b4ccca4e23d7046f64df3b99542 Mon Sep 17 00:00:00 2001 From: Neeraj Komuravalli Date: Sat, 23 May 2020 18:56:47 +0530 Subject: [PATCH 21/44] Created test cases for model that is being trained with deep features --- src/python/turicreate/test/test_image_classifier.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/python/turicreate/test/test_image_classifier.py b/src/python/turicreate/test/test_image_classifier.py index b906f74850..94148c8740 100644 --- a/src/python/turicreate/test/test_image_classifier.py +++ b/src/python/turicreate/test/test_image_classifier.py @@ -26,7 +26,6 @@ import coremltools import numpy as np import turicreate as tc -from array import array def get_test_data(): @@ -352,7 +351,7 @@ def test_evaluate_explore(self): evaluation.explore() -class ImageClassifierSqueezeNetTest(ImageClassifierTest): +class ImageClassifierResnetTestWithDeepFeatures(ImageClassifierTest): @classmethod def setUpClass(self): super(ImageClassifierSqueezeNetTest, self).setUpClass( @@ -375,7 +374,7 @@ def setUpClass(self): feature="awesome_image", ) -class ImageClassifierSqueezeNetTest(ImageClassifierTest): +class ImageClassifierSqueezeNetTestWithDeepFeatures(ImageClassifierTest): @classmethod def setUpClass(self): super(ImageClassifierSqueezeNetTest, self).setUpClass( @@ -408,7 +407,7 @@ def setUpClass(self): @unittest.skipIf( _mac_ver() < (10, 14), "VisionFeaturePrint_Scene only supported on macOS 10.14+" ) -class VisionFeaturePrintSceneTest(ImageClassifierTest): +class VisionFeaturePrintSceneTestWithDeepFeatures(ImageClassifierTest): @classmethod def setUpClass(self): super(VisionFeaturePrintSceneTest, self).setUpClass( From c02ac724347ff46f39e570b8fd14f199c7312f42 Mon Sep 17 00:00:00 2001 From: Neeraj Komuravalli Date: Sat, 23 May 2020 18:57:08 +0530 Subject: [PATCH 22/44] Created test cases for model that is being trained with deep features --- src/python/turicreate/test/test_image_similarity.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/python/turicreate/test/test_image_similarity.py b/src/python/turicreate/test/test_image_similarity.py index ce60c49ef6..fab801c7f4 100644 --- a/src/python/turicreate/test/test_image_similarity.py +++ b/src/python/turicreate/test/test_image_similarity.py @@ -18,7 +18,6 @@ import coremltools import numpy as np -from array import array def get_test_data(): @@ -298,7 +297,7 @@ def test_save_and_load(self): print("Export coreml passed") -class ImageSimilaritySqueezeNetTest(ImageSimilarityTest): +class ImageSimilarityResnetTestWithDeepFeatures(ImageSimilarityTest): @classmethod def setUpClass(self): super(ImageSimilaritySqueezeNetTest, self).setUpClass( @@ -314,7 +313,7 @@ def setUpClass(self): ) -class ImageSimilaritySqueezeNetTest(ImageSimilarityTest): +class ImageSimilaritySqueezeNetTestWithDeepFeatures(ImageSimilarityTest): @classmethod def setUpClass(self): super(ImageSimilaritySqueezeNetTest, self).setUpClass( @@ -336,7 +335,7 @@ def setUpClass(self): @unittest.skipIf( _mac_ver() < (10, 14), "VisionFeaturePrint_Scene only supported on macOS 10.14+" ) -class ImageSimilarityVisionFeaturePrintSceneTest(ImageSimilarityTest): +class ImageSimilarityVisionFeaturePrintSceneTestWithDeepFeatures(ImageSimilarityTest): @classmethod def setUpClass(self): super(ImageSimilarityVisionFeaturePrintSceneTest, self).setUpClass( @@ -358,7 +357,7 @@ def setUpClass(self): @unittest.skipIf( _mac_ver() < (10, 14), "VisionFeaturePrint_Scene only supported on macOS 10.14+" ) -class ImageSimilarityVisionFeaturePrintSceneTest_bad_name(ImageSimilarityTest): +class ImageSimilarityVisionFeaturePrintSceneTestWithDeepFeatures_bad_name(ImageSimilarityTest): @classmethod def setUpClass(self): super(ImageSimilarityVisionFeaturePrintSceneTest_bad_name, self).setUpClass( From 26a9e61e4dc980a6e912c2dc883ebdb1c6189297 Mon Sep 17 00:00:00 2001 From: Neeraj Komuravalli Date: Sat, 23 May 2020 18:58:56 +0530 Subject: [PATCH 23/44] Hiding the functions is_image_deep_feature_sarray and find_only_image_extracted_features_column --- .../turicreate/toolkits/image_analysis/image_analysis.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/python/turicreate/toolkits/image_analysis/image_analysis.py b/src/python/turicreate/toolkits/image_analysis/image_analysis.py index 0c7bf0938f..b7d17b3260 100644 --- a/src/python/turicreate/toolkits/image_analysis/image_analysis.py +++ b/src/python/turicreate/toolkits/image_analysis/image_analysis.py @@ -251,7 +251,7 @@ def get_deep_features(images, model_name, batch_size=64, verbose=True): batch_size=batch_size) -def find_only_image_extracted_features_column(sframe, model_name): +def _find_only_image_extracted_features_column(sframe, model_name): """ Finds the only column in `sframe` with a type of array.array and has the length same as the last layer of the model in use. @@ -272,7 +272,7 @@ def find_only_image_extracted_features_column(sframe, model_name): + "." ) - feature_columns = list(filter(lambda x: is_image_deep_feature_sarray(sframe[x], model_name), feature_columns)) + feature_columns = list(filter(lambda x: _is_image_deep_feature_sarray(sframe[x], model_name), feature_columns)) if len(feature_columns) == 1: return feature_columns[0] elif len(feature_columns) > 1: @@ -283,12 +283,14 @@ def find_only_image_extracted_features_column(sframe, model_name): ) -def is_image_deep_feature_sarray(feature_sarray, model_name): +def _is_image_deep_feature_sarray(feature_sarray, model_name): """ Finds if the given `SArray` has extracted features for a given model_name. """ from array import array + if not (len(feature_sarray) > 0): + return False if feature_sarray.dtype != array: return False if type(feature_sarray[0]) != array: From 80dd166c2177985bc52d9825e0b28ee2daf33b32 Mon Sep 17 00:00:00 2001 From: Neeraj Komuravalli Date: Sat, 23 May 2020 19:00:39 +0530 Subject: [PATCH 24/44] Changing the function name find_only_image_extracted_features_column to _find_only_image_extracted_features_column as chnages were made in image_analysis --- .../turicreate/toolkits/image_similarity/image_similarity.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/python/turicreate/toolkits/image_similarity/image_similarity.py b/src/python/turicreate/toolkits/image_similarity/image_similarity.py index 637f66d098..71dac4982b 100644 --- a/src/python/turicreate/toolkits/image_similarity/image_similarity.py +++ b/src/python/turicreate/toolkits/image_similarity/image_similarity.py @@ -130,7 +130,7 @@ def create( if feature is None: # select feature column : either extracted features columns or image column itself try: - feature = image_analysis.find_only_image_extracted_features_column(dataset, model) + feature = image_analysis._find_only_image_extracted_features_column(dataset, model) feature_type = "extracted_features_array" except: feature = None From b5633937664ab0b33447ac63315a0cd5b6f2dfb0 Mon Sep 17 00:00:00 2001 From: Neeraj Komuravalli Date: Thu, 4 Jun 2020 15:17:29 +0530 Subject: [PATCH 25/44] Changing the generic deep feature column name in data generation to the model specific name --- .../turicreate/test/test_image_classifier.py | 25 +++++++------------ .../turicreate/test/test_image_similarity.py | 14 +++++------ 2 files changed, 15 insertions(+), 24 deletions(-) diff --git a/src/python/turicreate/test/test_image_classifier.py b/src/python/turicreate/test/test_image_classifier.py index 94148c8740..bfa73e0695 100644 --- a/src/python/turicreate/test/test_image_classifier.py +++ b/src/python/turicreate/test/test_image_classifier.py @@ -78,10 +78,8 @@ def get_test_data(): data_dict = {"awesome_image": images, "awesome_label": labels} data = tc.SFrame(data_dict) - for model_name, feature_length in MODEL_TO_FEATURE_SIZE_MAPPING.items(): - if str(feature_length) in data_dict.keys(): - continue - data[str(feature_length)] = get_deep_features(data["awesome_image"], model_name) + for model_name in MODEL_TO_FEATURE_SIZE_MAPPING: + data[model_name + "_deep_features"] = get_deep_features(data["awesome_image"], model_name) return data @@ -173,15 +171,10 @@ def test_create_with_empty_dataset(self): def test_select_correct_feature_column_to_train(self): # sending both, the correct extracted features colum and image column - extracted_feature_column_name = str(MODEL_TO_FEATURE_SIZE_MAPPING[self.pre_trained_model]) - test_model = tc.image_classifier.create(data, target=self.target, model=self.pre_trained_model) - self.assertTrue(test_model.feature == extracted_feature_column_name) - - # sending the wrong exracted features column along with the image column - columns_name_list = list(filter(lambda x: x != extracted_feature_column_name, data.column_names())) - test_data = data.select_columns(columns_name_list) - test_model = tc.image_classifier.create(test_data, target=self.target, model=self.pre_trained_model) - self.assertTrue(test_model.feature == "awesome_image") + if self.feature == "awesome_image": + test_data = data.select_columns([self.feature, self.target, self.feature+"_deep_features"]) + test_model = tc.image_classifier.create(test_data, target=self.target, model=self.pre_trained_model) + self.assertTrue(test_model.feature == self.feature+"_deep_features") def test_predict(self): model = self.model @@ -359,7 +352,7 @@ def setUpClass(self): input_image_shape=(3, 227, 227), tol=0.005, num_examples=200, - feature="2048", + feature="resnet-50_deep_features", ) @@ -382,7 +375,7 @@ def setUpClass(self): input_image_shape=(3, 227, 227), tol=0.005, num_examples=200, - feature="1000", + feature="squeezenet_v1.1_deep_features", ) @@ -416,5 +409,5 @@ def setUpClass(self): tol=0.005, num_examples=100, label_type=str, - feature="2048", + feature="VisionFeaturePrint_Scene_deep_features", ) diff --git a/src/python/turicreate/test/test_image_similarity.py b/src/python/turicreate/test/test_image_similarity.py index fab801c7f4..be4c54391d 100644 --- a/src/python/turicreate/test/test_image_similarity.py +++ b/src/python/turicreate/test/test_image_similarity.py @@ -69,10 +69,8 @@ def get_test_data(): data_dict = {"awesome_image": images} data = tc.SFrame(data_dict) - for model_name, feature_length in MODEL_TO_FEATURE_SIZE_MAPPING.items(): - if str(feature_length) in data_dict.keys(): - continue - data[str(feature_length)] = get_deep_features(data["awesome_image"], model_name) + for model_name in MODEL_TO_FEATURE_SIZE_MAPPING: + data[model_name + "_deep_features"] = get_deep_features(data["awesome_image"], model_name) return data @@ -301,7 +299,7 @@ class ImageSimilarityResnetTestWithDeepFeatures(ImageSimilarityTest): @classmethod def setUpClass(self): super(ImageSimilaritySqueezeNetTest, self).setUpClass( - model="resnet-50", input_image_shape=(3, 227, 227), feature="2048" + model="resnet-50", input_image_shape=(3, 227, 227), feature="resnet-50_deep_features" ) @@ -317,7 +315,7 @@ class ImageSimilaritySqueezeNetTestWithDeepFeatures(ImageSimilarityTest): @classmethod def setUpClass(self): super(ImageSimilaritySqueezeNetTest, self).setUpClass( - model="squeezenet_v1.1", input_image_shape=(3, 227, 227), feature="1000" + model="squeezenet_v1.1", input_image_shape=(3, 227, 227), feature="squeezenet_v1.1_deep_features" ) @@ -339,7 +337,7 @@ class ImageSimilarityVisionFeaturePrintSceneTestWithDeepFeatures(ImageSimilarity @classmethod def setUpClass(self): super(ImageSimilarityVisionFeaturePrintSceneTest, self).setUpClass( - model="VisionFeaturePrint_Scene", input_image_shape=(3, 299, 299), feature="2048" + model="VisionFeaturePrint_Scene", input_image_shape=(3, 299, 299), feature="VisionFeaturePrint_Scene_deep_features" ) # A test to gaurantee that old code using the incorrect name still works. @@ -361,5 +359,5 @@ class ImageSimilarityVisionFeaturePrintSceneTestWithDeepFeatures_bad_name(ImageS @classmethod def setUpClass(self): super(ImageSimilarityVisionFeaturePrintSceneTest_bad_name, self).setUpClass( - model="VisionFeaturePrint_Screen", input_image_shape=(3, 299, 299), feature="2048" + model="VisionFeaturePrint_Screen", input_image_shape=(3, 299, 299), feature="VisionFeaturePrint_Screen_deep_features" ) From c4b4ada6e71d961de6db78fd6f0e1cf429eab283 Mon Sep 17 00:00:00 2001 From: Neeraj Komuravalli Date: Thu, 4 Jun 2020 16:06:53 +0530 Subject: [PATCH 26/44] Simplifing the code to detect type of sfrane column by using _find_only_column_of_type instead of writing a new logic --- .../toolkits/image_analysis/image_analysis.py | 25 ++++--------------- 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/src/python/turicreate/toolkits/image_analysis/image_analysis.py b/src/python/turicreate/toolkits/image_analysis/image_analysis.py index b7d17b3260..16d6370ce2 100644 --- a/src/python/turicreate/toolkits/image_analysis/image_analysis.py +++ b/src/python/turicreate/toolkits/image_analysis/image_analysis.py @@ -260,26 +260,11 @@ def _find_only_image_extracted_features_column(sframe, model_name): """ from array import array - try: - feature_columns, _ = zip(*list(filter(lambda x: x[1] == array, list(zip(sframe.column_names(), sframe.column_types()))))) - except ValueError: - raise _ToolkitError( - 'No "{col_name}" column specified and no column with expected type "{type_name}" is found.'.format( - col_name="extracted_features", type_name="array" - ) - + ' "datasets" consists of columns with types: ' - + ", ".join([x.__name__ for x in sframe.column_types()]) - + "." - ) - - feature_columns = list(filter(lambda x: _is_image_deep_feature_sarray(sframe[x], model_name), feature_columns)) - if len(feature_columns) == 1: - return feature_columns[0] - elif len(feature_columns) > 1: - raise _ToolkitError( - 'No "{col_name}" column specified and more than one extracted features {type_name} column in "dataset". Can not infer correct {col_name} column.'.format( - col_name="extracted_features", type_name="array" - ) + feature_column = _find_only_column_of_type(sframe, target_type=array, type_name="array", col_name="deep_features") + if _is_image_deep_feature_sarray(sframe[feature_column], model_name): + return feature_column + else: + raise _ToolkitError('No "{col_name}" column specified and no column with expected type "{type_name}" is found.'.format(col_name="deep_features", type_name="array") ) From b35b2e7da69539d15b028aeec0c25e9b984f4c44 Mon Sep 17 00:00:00 2001 From: Neeraj Komuravalli Date: Tue, 9 Jun 2020 14:51:12 +0530 Subject: [PATCH 27/44] Removing unnecessary try except block and correcting spelling mistakes --- .../image_classifier/image_classifier.py | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/python/turicreate/toolkits/image_classifier/image_classifier.py b/src/python/turicreate/toolkits/image_classifier/image_classifier.py index fbe4e90b2d..f17f8e806c 100644 --- a/src/python/turicreate/toolkits/image_classifier/image_classifier.py +++ b/src/python/turicreate/toolkits/image_classifier/image_classifier.py @@ -252,22 +252,14 @@ def create( if feature is None: try: - feature = image_analysis.find_only_image_extracted_features_column(dataset, model) + feature = image_analysis._find_only_image_extracted_features_column(dataset, model) feature_type = "extracted_features_array" except: feature = None if feature is None: - try: - feature = _tkutl._find_only_image_column(dataset) - feature_type = "image" - except: - raise _ToolkitError( - 'No feature column specified and no column with expected type image or extracted features array is found.' - + ' "datasets" consists of columns with types: ' - + ", ".join([x.__name__ for x in dataset.column_types()]) - + "." - ) + feature = _tkutl._find_only_image_column(dataset) + feature_type = "image" else: if image_analysis.is_image_deep_feature_sarray(dataset[feature], model): feature_type = "extracted_features_array" @@ -905,7 +897,7 @@ def _extract_features(self, dataset, verbose=False, batch_size=64): } ) else: - raise _ToolkitError('The "{feature}" column of the sFrame neither has the dataype image or extracted features array.'.format(feature=feature) + raise _ToolkitError('The "{feature}" column of the SFrame neither has the dataype image or extracted features array.'.format(feature=feature) + ' "Datasets" consists of columns with types: ' + ", ".join([x.__name__ for x in dataset.column_types()]) + "." From c4798d312cee1aaa3efb5d6981cb0353434ba6ba Mon Sep 17 00:00:00 2001 From: Neeraj Komuravalli Date: Tue, 16 Jun 2020 18:31:10 +0530 Subject: [PATCH 28/44] Debugging to fix _find_only_column_of_type not found error --- .../turicreate/toolkits/image_analysis/image_analysis.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/python/turicreate/toolkits/image_analysis/image_analysis.py b/src/python/turicreate/toolkits/image_analysis/image_analysis.py index 16d6370ce2..1fa52f5767 100644 --- a/src/python/turicreate/toolkits/image_analysis/image_analysis.py +++ b/src/python/turicreate/toolkits/image_analysis/image_analysis.py @@ -11,6 +11,7 @@ import turicreate.toolkits._internal_utils as _tkutl from turicreate.toolkits._main import ToolkitError as _ToolkitError +import turicreate.toolkits._internal_utils as _tkutl from .._internal_utils import _mac_ver from .. import _pre_trained_models from ...data_structures.image import Image as _Image @@ -260,7 +261,7 @@ def _find_only_image_extracted_features_column(sframe, model_name): """ from array import array - feature_column = _find_only_column_of_type(sframe, target_type=array, type_name="array", col_name="deep_features") + feature_column = _tkutl._find_only_column_of_type(sframe, target_type=array, type_name="array", col_name="deep_features") if _is_image_deep_feature_sarray(sframe[feature_column], model_name): return feature_column else: From dd0c1844ab6d3d1cb26630187cce221be197b375 Mon Sep 17 00:00:00 2001 From: Neeraj Komuravalli Date: Tue, 16 Jun 2020 18:33:22 +0530 Subject: [PATCH 29/44] Fixing all the errors where image_classifier was failing in test cases --- .../turicreate/test/test_image_classifier.py | 16 ++++++++-------- .../image_classifier/image_classifier.py | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/python/turicreate/test/test_image_classifier.py b/src/python/turicreate/test/test_image_classifier.py index bfa73e0695..5c66feb991 100644 --- a/src/python/turicreate/test/test_image_classifier.py +++ b/src/python/turicreate/test/test_image_classifier.py @@ -172,9 +172,9 @@ def test_create_with_empty_dataset(self): def test_select_correct_feature_column_to_train(self): # sending both, the correct extracted features colum and image column if self.feature == "awesome_image": - test_data = data.select_columns([self.feature, self.target, self.feature+"_deep_features"]) + test_data = data.select_columns([self.feature, self.target, self.pre_trained_model+"_deep_features"]) test_model = tc.image_classifier.create(test_data, target=self.target, model=self.pre_trained_model) - self.assertTrue(test_model.feature == self.feature+"_deep_features") + self.assertTrue(test_model.feature == self.pre_trained_model+"_deep_features") def test_predict(self): model = self.model @@ -347,11 +347,11 @@ def test_evaluate_explore(self): class ImageClassifierResnetTestWithDeepFeatures(ImageClassifierTest): @classmethod def setUpClass(self): - super(ImageClassifierSqueezeNetTest, self).setUpClass( + super(ImageClassifierResnetTestWithDeepFeatures, self).setUpClass( model="resnet-50", - input_image_shape=(3, 227, 227), - tol=0.005, - num_examples=200, + input_image_shape=(3, 224, 224), + tol=0.02, + num_examples=100, feature="resnet-50_deep_features", ) @@ -370,7 +370,7 @@ def setUpClass(self): class ImageClassifierSqueezeNetTestWithDeepFeatures(ImageClassifierTest): @classmethod def setUpClass(self): - super(ImageClassifierSqueezeNetTest, self).setUpClass( + super(ImageClassifierSqueezeNetTestWithDeepFeatures, self).setUpClass( model="squeezenet_v1.1", input_image_shape=(3, 227, 227), tol=0.005, @@ -403,7 +403,7 @@ def setUpClass(self): class VisionFeaturePrintSceneTestWithDeepFeatures(ImageClassifierTest): @classmethod def setUpClass(self): - super(VisionFeaturePrintSceneTest, self).setUpClass( + super(VisionFeaturePrintSceneTestWithDeepFeatures, self).setUpClass( model="VisionFeaturePrint_Scene", input_image_shape=(3, 299, 299), tol=0.005, diff --git a/src/python/turicreate/toolkits/image_classifier/image_classifier.py b/src/python/turicreate/toolkits/image_classifier/image_classifier.py index f17f8e806c..9a02ba344e 100644 --- a/src/python/turicreate/toolkits/image_classifier/image_classifier.py +++ b/src/python/turicreate/toolkits/image_classifier/image_classifier.py @@ -261,7 +261,7 @@ def create( feature = _tkutl._find_only_image_column(dataset) feature_type = "image" else: - if image_analysis.is_image_deep_feature_sarray(dataset[feature], model): + if image_analysis._is_image_deep_feature_sarray(dataset[feature], model): feature_type = "extracted_features_array" elif dataset[feature].dtype is _tc.Image: feature_type = "image" @@ -882,7 +882,7 @@ def evaluate(self, dataset, metric="auto", verbose=True, batch_size=64): return _Evaluation(evaluation_result) def _extract_features(self, dataset, verbose=False, batch_size=64): - if image_analysis.is_image_deep_feature_sarray(dataset[self.feature], self.model): + if image_analysis._is_image_deep_feature_sarray(dataset[self.feature], self.model): return _tc.SFrame( { "__image_features__": dataset[self.feature] From faaf5f2aa89054043d66cf9068fdd0d20edc6d55 Mon Sep 17 00:00:00 2001 From: Neeraj Komuravalli Date: Tue, 16 Jun 2020 18:33:53 +0530 Subject: [PATCH 30/44] Fixing all the errors where image_similarity was failing in test cases --- src/python/turicreate/test/test_image_similarity.py | 12 ++++++------ .../toolkits/image_similarity/image_similarity.py | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/python/turicreate/test/test_image_similarity.py b/src/python/turicreate/test/test_image_similarity.py index be4c54391d..1e1b81ad53 100644 --- a/src/python/turicreate/test/test_image_similarity.py +++ b/src/python/turicreate/test/test_image_similarity.py @@ -298,8 +298,8 @@ def test_save_and_load(self): class ImageSimilarityResnetTestWithDeepFeatures(ImageSimilarityTest): @classmethod def setUpClass(self): - super(ImageSimilaritySqueezeNetTest, self).setUpClass( - model="resnet-50", input_image_shape=(3, 227, 227), feature="resnet-50_deep_features" + super(ImageSimilarityResnetTestWithDeepFeatures, self).setUpClass( + model="resnet-50", input_image_shape=(3, 224, 224), feature="resnet-50_deep_features" ) @@ -314,7 +314,7 @@ def setUpClass(self): class ImageSimilaritySqueezeNetTestWithDeepFeatures(ImageSimilarityTest): @classmethod def setUpClass(self): - super(ImageSimilaritySqueezeNetTest, self).setUpClass( + super(ImageSimilaritySqueezeNetTestWithDeepFeatures, self).setUpClass( model="squeezenet_v1.1", input_image_shape=(3, 227, 227), feature="squeezenet_v1.1_deep_features" ) @@ -336,7 +336,7 @@ def setUpClass(self): class ImageSimilarityVisionFeaturePrintSceneTestWithDeepFeatures(ImageSimilarityTest): @classmethod def setUpClass(self): - super(ImageSimilarityVisionFeaturePrintSceneTest, self).setUpClass( + super(ImageSimilarityVisionFeaturePrintSceneTestWithDeepFeatures, self).setUpClass( model="VisionFeaturePrint_Scene", input_image_shape=(3, 299, 299), feature="VisionFeaturePrint_Scene_deep_features" ) @@ -358,6 +358,6 @@ def setUpClass(self): class ImageSimilarityVisionFeaturePrintSceneTestWithDeepFeatures_bad_name(ImageSimilarityTest): @classmethod def setUpClass(self): - super(ImageSimilarityVisionFeaturePrintSceneTest_bad_name, self).setUpClass( - model="VisionFeaturePrint_Screen", input_image_shape=(3, 299, 299), feature="VisionFeaturePrint_Screen_deep_features" + super(ImageSimilarityVisionFeaturePrintSceneTestWithDeepFeatures_bad_name, self).setUpClass( + model="VisionFeaturePrint_Screen", input_image_shape=(3, 299, 299), feature="VisionFeaturePrint_Scene_deep_features" ) diff --git a/src/python/turicreate/toolkits/image_similarity/image_similarity.py b/src/python/turicreate/toolkits/image_similarity/image_similarity.py index 71dac4982b..d793396184 100644 --- a/src/python/turicreate/toolkits/image_similarity/image_similarity.py +++ b/src/python/turicreate/toolkits/image_similarity/image_similarity.py @@ -146,7 +146,7 @@ def create( + "." ) else: - if image_analysis.is_image_deep_feature_sarray(dataset[feature], model): + if image_analysis._is_image_deep_feature_sarray(dataset[feature], model): feature_type = "extracted_features_array" elif dataset[feature].dtype is _tc.Image: feature_type = "image" @@ -335,7 +335,7 @@ def _get_summary_struct(self): return ([model_fields, training_fields], section_titles) def _extract_features(self, dataset, verbose=False, batch_size=64): - if image_analysis.is_image_deep_feature_sarray(dataset[self.feature], self.model): + if image_analysis._is_image_deep_feature_sarray(dataset[self.feature], self.model): return _tc.SFrame( { "__image_features__": dataset[self.feature] From 6d308e833f08e71c08db5d21fc4335bb52386413 Mon Sep 17 00:00:00 2001 From: Neeraj Komuravalli Date: Tue, 16 Jun 2020 19:15:49 +0530 Subject: [PATCH 31/44] Changing test_export_coreml_predict function to also account for deep features --- .../turicreate/test/test_image_classifier.py | 39 ++++++++++++------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/src/python/turicreate/test/test_image_classifier.py b/src/python/turicreate/test/test_image_classifier.py index 5c66feb991..6e1dda89a7 100644 --- a/src/python/turicreate/test/test_image_classifier.py +++ b/src/python/turicreate/test/test_image_classifier.py @@ -246,22 +246,35 @@ def test_export_coreml_predict(self): self.model.export_coreml(filename) coreml_model = coremltools.models.MLModel(filename) - img = data[0:1][self.feature][0] - img_fixed = tc.image_analysis.resize(img, *reversed(self.input_image_shape)) - from PIL import Image + if self.feature == "awesome_image": + img = data[0:1][self.feature][0] + img_fixed = tc.image_analysis.resize(img, *reversed(self.input_image_shape)) + from PIL import Image - pil_img = Image.fromarray(img_fixed.pixel_data) + pil_img = Image.fromarray(img_fixed.pixel_data) - if _mac_ver() >= (10, 13): - classes = self.model.classifier.classes - ret = coreml_model.predict({self.feature: pil_img}) - coreml_values = [ret[self.target + "Probability"][l] for l in classes] + if _mac_ver() >= (10, 13): + classes = self.model.classifier.classes + ret = coreml_model.predict({self.feature: pil_img}) + coreml_values = [ret[self.target + "Probability"][l] for l in classes] - self.assertListAlmostEquals( - coreml_values, - list(self.model.predict(img_fixed, output_type="probability_vector")), - self.tolerance, - ) + self.assertListAlmostEquals( + coreml_values, + list(self.model.predict(img_fixed, output_type="probability_vector")), + self.tolerance, + ) + else: + deep_features = data[0:1][self.feature][0] + if _mac_ver() >= (10, 13): + classes = self.model.classifier.classes + ret = coreml_model.predict({self.feature: deep_features}) + coreml_values = [ret[self.target + "Probability"][l] for l in classes] + + self.assertListAlmostEquals( + coreml_values, + list(self.model.predict(deep_features, output_type="probability_vector")), + self.tolerance, + ) def test_classify(self): model = self.model From ab26484de48f79ac6c58dc2351257d448c74dbbf Mon Sep 17 00:00:00 2001 From: Neeraj Komuravalli Date: Tue, 16 Jun 2020 19:16:50 +0530 Subject: [PATCH 32/44] Changing test_export_coreml function to also account for deep features --- .../turicreate/test/test_image_similarity.py | 43 ++++++++++++------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/src/python/turicreate/test/test_image_similarity.py b/src/python/turicreate/test/test_image_similarity.py index 1e1b81ad53..089fd46a54 100644 --- a/src/python/turicreate/test/test_image_similarity.py +++ b/src/python/turicreate/test/test_image_similarity.py @@ -259,21 +259,34 @@ def get_psnr(x, y): ) # Get model distances for comparison - img = data[0:1][self.feature][0] - img_fixed = tc.image_analysis.resize(img, *reversed(self.input_image_shape)) - tc_ret = self.model.query(img_fixed, k=data.num_rows()) - - if _mac_ver() >= (10, 13): - from PIL import Image as _PIL_Image - - pil_img = _PIL_Image.fromarray(img_fixed.pixel_data) - coreml_ret = coreml_model.predict({"awesome_image": pil_img}) - - # Compare distances - coreml_distances = np.array(coreml_ret["distance"]) - tc_distances = tc_ret.sort("reference_label")["distance"].to_numpy() - psnr_value = get_psnr(coreml_distances, tc_distances) - self.assertTrue(psnr_value > 50) + if self.feature == "awesome_image": + img = data[0:1][self.feature][0] + img_fixed = tc.image_analysis.resize(img, *reversed(self.input_image_shape)) + tc_ret = self.model.query(img_fixed, k=data.num_rows()) + + if _mac_ver() >= (10, 13): + from PIL import Image as _PIL_Image + + pil_img = _PIL_Image.fromarray(img_fixed.pixel_data) + coreml_ret = coreml_model.predict({"awesome_image": pil_img}) + + # Compare distances + coreml_distances = np.array(coreml_ret["distance"]) + tc_distances = tc_ret.sort("reference_label")["distance"].to_numpy() + psnr_value = get_psnr(coreml_distances, tc_distances) + self.assertTrue(psnr_value > 50) + else: + deep_features = data[0:1][self.feature][0] + tc_ret = self.model.query(deep_features, k=data.num_rows()) + + if _mac_ver() >= (10, 13): + coreml_ret = coreml_model.predict({self.feature: deep_features}) + + # Compare distances + coreml_distances = np.array(coreml_ret["distance"]) + tc_distances = tc_ret.sort("reference_label")["distance"].to_numpy() + psnr_value = get_psnr(coreml_distances, tc_distances) + self.assertTrue(psnr_value > 50) def test_save_and_load(self): with test_util.TempDirectory() as filename: From 4ff6d46553409f6bc6940f08420cb178167708ff Mon Sep 17 00:00:00 2001 From: Neeraj Komuravalli Date: Fri, 19 Jun 2020 18:24:49 +0530 Subject: [PATCH 33/44] Ignoring the coremltools predict test case when deep_features are used --- src/python/turicreate/test/test_image_classifier.py | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/python/turicreate/test/test_image_classifier.py b/src/python/turicreate/test/test_image_classifier.py index 6e1dda89a7..00a07f7a20 100644 --- a/src/python/turicreate/test/test_image_classifier.py +++ b/src/python/turicreate/test/test_image_classifier.py @@ -264,17 +264,8 @@ def test_export_coreml_predict(self): self.tolerance, ) else: - deep_features = data[0:1][self.feature][0] - if _mac_ver() >= (10, 13): - classes = self.model.classifier.classes - ret = coreml_model.predict({self.feature: deep_features}) - coreml_values = [ret[self.target + "Probability"][l] for l in classes] - - self.assertListAlmostEquals( - coreml_values, - list(self.model.predict(deep_features, output_type="probability_vector")), - self.tolerance, - ) + # If the code came here that means the type of the feature used is deep_deatures and the predict fwature in coremltools doesn't work with deep_features yet so we will ignore this specific test case unitl the same is written. + pass def test_classify(self): model = self.model From 0efc31b71ce409df16a1041279b51bb7d8257838 Mon Sep 17 00:00:00 2001 From: Neeraj Komuravalli Date: Fri, 19 Jun 2020 18:25:12 +0530 Subject: [PATCH 34/44] Ignoring the coremltools predict test case when deep_features are used --- src/python/turicreate/test/test_image_similarity.py | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/python/turicreate/test/test_image_similarity.py b/src/python/turicreate/test/test_image_similarity.py index 089fd46a54..d50a5b895e 100644 --- a/src/python/turicreate/test/test_image_similarity.py +++ b/src/python/turicreate/test/test_image_similarity.py @@ -276,17 +276,8 @@ def get_psnr(x, y): psnr_value = get_psnr(coreml_distances, tc_distances) self.assertTrue(psnr_value > 50) else: - deep_features = data[0:1][self.feature][0] - tc_ret = self.model.query(deep_features, k=data.num_rows()) - - if _mac_ver() >= (10, 13): - coreml_ret = coreml_model.predict({self.feature: deep_features}) - - # Compare distances - coreml_distances = np.array(coreml_ret["distance"]) - tc_distances = tc_ret.sort("reference_label")["distance"].to_numpy() - psnr_value = get_psnr(coreml_distances, tc_distances) - self.assertTrue(psnr_value > 50) + # If the code came here that means the type of the feature used is deep_deatures and the predict fwature in coremltools doesn't work with deep_features yet so we will ignore this specific test case unitl the same is written. + pass def test_save_and_load(self): with test_util.TempDirectory() as filename: From ca49ab2189f38d06a450820957f7c468bacbe601 Mon Sep 17 00:00:00 2001 From: Neeraj Komuravalli Date: Fri, 19 Jun 2020 19:04:01 +0530 Subject: [PATCH 35/44] Adding docstring for get_deep_features --- .../turicreate/toolkits/image_analysis/image_analysis.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/python/turicreate/toolkits/image_analysis/image_analysis.py b/src/python/turicreate/toolkits/image_analysis/image_analysis.py index 1fa52f5767..705cdde023 100644 --- a/src/python/turicreate/toolkits/image_analysis/image_analysis.py +++ b/src/python/turicreate/toolkits/image_analysis/image_analysis.py @@ -227,6 +227,11 @@ def get_deep_features(images, model_name, batch_size=64, verbose=True): Examples -------- + # Get Deep featuers from an sarray of images + >>> url ='https://static.turi.com/datasets/images/nested' + >>> image_sframe = turicreate.image_analysis.load_images(url, "auto", with_path=False, recursive=True) + >>> image_sarray = image_sframe["image"] + >>> deep_features_sframe = turicreate.image_analysis.get_deep_features(image_sarray, model_name="resnet-50") """ From 3b4455db4d612e599c846aa08b6710d10c1ebda0 Mon Sep 17 00:00:00 2001 From: Neeraj Komuravalli Date: Tue, 23 Jun 2020 02:00:04 +0530 Subject: [PATCH 36/44] Removing unnecessary code and makeing recommended changes --- .../turicreate/toolkits/image_classifier/image_classifier.py | 2 +- .../turicreate/toolkits/image_similarity/image_similarity.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/python/turicreate/toolkits/image_classifier/image_classifier.py b/src/python/turicreate/toolkits/image_classifier/image_classifier.py index 68becc9358..bea93b0ca3 100644 --- a/src/python/turicreate/toolkits/image_classifier/image_classifier.py +++ b/src/python/turicreate/toolkits/image_classifier/image_classifier.py @@ -487,7 +487,7 @@ def _canonize_input(self, dataset): unpack = lambda x: x if isinstance(dataset, _tc.SArray): dataset = _tc.SFrame({self.feature: dataset}) - elif isinstance(dataset, _tc.Image) or isinstance(dataset, array): + elif isinstance(dataset, (_tc.Image, array)): dataset = _tc.SFrame({self.feature: [dataset]}) unpack = lambda x: x[0] diff --git a/src/python/turicreate/toolkits/image_similarity/image_similarity.py b/src/python/turicreate/toolkits/image_similarity/image_similarity.py index 980400b8c4..8a1ec92043 100644 --- a/src/python/turicreate/toolkits/image_similarity/image_similarity.py +++ b/src/python/turicreate/toolkits/image_similarity/image_similarity.py @@ -440,7 +440,7 @@ def query(self, dataset, label=None, k=5, radius=None, verbose=True, batch_size= if isinstance(dataset, _tc.SArray): dataset = _tc.SFrame({self.feature: dataset}) - elif isinstance(dataset, _tc.Image) or isinstance(dataset, array): + elif isinstance(dataset, (_tc.Image, array)): dataset = _tc.SFrame({self.feature: [dataset]}) extracted_features = self._extract_features( From 61ac0c2288cf859971ef3bc3d1f95fc9ef534359 Mon Sep 17 00:00:00 2001 From: Neeraj Komuravalli Date: Thu, 25 Jun 2020 15:11:57 +0530 Subject: [PATCH 37/44] Ignoring getting deep features when mac version is less than 10.14 or if its a Linux system or any other OS --- src/python/turicreate/test/test_image_classifier.py | 3 +++ src/python/turicreate/test/test_image_similarity.py | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/python/turicreate/test/test_image_classifier.py b/src/python/turicreate/test/test_image_classifier.py index a3aebcb5c0..5bf386fbca 100644 --- a/src/python/turicreate/test/test_image_classifier.py +++ b/src/python/turicreate/test/test_image_classifier.py @@ -78,6 +78,9 @@ def get_test_data(): data = tc.SFrame(data_dict) for model_name in MODEL_TO_FEATURE_SIZE_MAPPING: + if model_name == "VisionFeaturePrint_Scene" and _mac_ver() < (10, 14): + # VisionFeaturePrint_Scene is not support on Linux + continue data[model_name + "_deep_features"] = get_deep_features(data["awesome_image"], model_name) return data diff --git a/src/python/turicreate/test/test_image_similarity.py b/src/python/turicreate/test/test_image_similarity.py index 1b2acece48..dd0e6bf241 100644 --- a/src/python/turicreate/test/test_image_similarity.py +++ b/src/python/turicreate/test/test_image_similarity.py @@ -70,6 +70,9 @@ def get_test_data(): data = tc.SFrame(data_dict) for model_name in MODEL_TO_FEATURE_SIZE_MAPPING: + if model_name == "VisionFeaturePrint_Scene" and _mac_ver() < (10, 14): + # VisionFeaturePrint_Scene is not support on Linux + continue data[model_name + "_deep_features"] = get_deep_features(data["awesome_image"], model_name) return data From fd0cbd523c0a41d3705b9e84d6ebc1a6da4b6f9b Mon Sep 17 00:00:00 2001 From: Neeraj Komuravalli Date: Wed, 1 Jul 2020 14:24:14 +0530 Subject: [PATCH 38/44] Removing coremltools import line to adhere to the turicreate testing practices --- src/python/turicreate/test/test_image_similarity.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/python/turicreate/test/test_image_similarity.py b/src/python/turicreate/test/test_image_similarity.py index dd0e6bf241..91a8c5c9dc 100644 --- a/src/python/turicreate/test/test_image_similarity.py +++ b/src/python/turicreate/test/test_image_similarity.py @@ -16,7 +16,6 @@ from turicreate.toolkits._main import ToolkitError as _ToolkitError from turicreate.toolkits.image_analysis.image_analysis import MODEL_TO_FEATURE_SIZE_MAPPING, get_deep_features -import coremltools import numpy as np From 199e1ce20a12ca5cb39f1e71c973248c9f35c2ee Mon Sep 17 00:00:00 2001 From: Neeraj Komuravalli Date: Thu, 9 Jul 2020 14:33:33 +0530 Subject: [PATCH 39/44] Shifting deep feature building in from get_test_data to setUpClass (no tested) --- .../turicreate/test/test_image_similarity.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/python/turicreate/test/test_image_similarity.py b/src/python/turicreate/test/test_image_similarity.py index 91a8c5c9dc..76680b2a6e 100644 --- a/src/python/turicreate/test/test_image_similarity.py +++ b/src/python/turicreate/test/test_image_similarity.py @@ -68,11 +68,11 @@ def get_test_data(): data_dict = {"awesome_image": images} data = tc.SFrame(data_dict) - for model_name in MODEL_TO_FEATURE_SIZE_MAPPING: - if model_name == "VisionFeaturePrint_Scene" and _mac_ver() < (10, 14): - # VisionFeaturePrint_Scene is not support on Linux - continue - data[model_name + "_deep_features"] = get_deep_features(data["awesome_image"], model_name) + # for model_name in MODEL_TO_FEATURE_SIZE_MAPPING: + # if model_name == "VisionFeaturePrint_Scene" and _mac_ver() < (10, 14): + # # VisionFeaturePrint_Scene is not support on Linux + # continue + # data[model_name + "_deep_features"] = get_deep_features(data["awesome_image"], model_name) return data @@ -97,6 +97,13 @@ def setUpClass(self, input_image_shape=(3, 224, 224), model="resnet-50", feature "verbose": True, } + # Get deep features if needed + if self.feature != "awesome_image": + if self.pre_trained_model == "VisionFeaturePrint_Scene" and _mac_ver() < (10, 14): + # VisionFeaturePrint_Scene is not support on Linux + continue + data[self.feature] = get_deep_features(data["awesome_image"], self.pre_trained_model) + # Model self.model = tc.image_similarity.create( data, feature=self.feature, label=None, model=self.pre_trained_model From 3b97d6f292cd951764ed95df650ca10d6b79da2f Mon Sep 17 00:00:00 2001 From: Neeraj Komuravalli Date: Thu, 9 Jul 2020 18:05:06 +0530 Subject: [PATCH 40/44] Shifting deep feature building in from get_test_data to setUpClass (fully tested) --- src/python/turicreate/test/test_image_similarity.py | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/python/turicreate/test/test_image_similarity.py b/src/python/turicreate/test/test_image_similarity.py index 76680b2a6e..78e2932cff 100644 --- a/src/python/turicreate/test/test_image_similarity.py +++ b/src/python/turicreate/test/test_image_similarity.py @@ -68,12 +68,6 @@ def get_test_data(): data_dict = {"awesome_image": images} data = tc.SFrame(data_dict) - # for model_name in MODEL_TO_FEATURE_SIZE_MAPPING: - # if model_name == "VisionFeaturePrint_Scene" and _mac_ver() < (10, 14): - # # VisionFeaturePrint_Scene is not support on Linux - # continue - # data[model_name + "_deep_features"] = get_deep_features(data["awesome_image"], model_name) - return data @@ -99,10 +93,7 @@ def setUpClass(self, input_image_shape=(3, 224, 224), model="resnet-50", feature # Get deep features if needed if self.feature != "awesome_image": - if self.pre_trained_model == "VisionFeaturePrint_Scene" and _mac_ver() < (10, 14): - # VisionFeaturePrint_Scene is not support on Linux - continue - data[self.feature] = get_deep_features(data["awesome_image"], self.pre_trained_model) + data[self.feature] = get_deep_features(data["awesome_image"], self.feature.split('_deep_features')[0]) # Model self.model = tc.image_similarity.create( From 6a29bc525491269e9e020c2715e9dd3e09886cae Mon Sep 17 00:00:00 2001 From: Neeraj Komuravalli Date: Thu, 9 Jul 2020 18:05:34 +0530 Subject: [PATCH 41/44] Shifting deep feature building in from get_test_data to setUpClass --- .../turicreate/test/test_image_classifier.py | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/python/turicreate/test/test_image_classifier.py b/src/python/turicreate/test/test_image_classifier.py index 5bf386fbca..55a5b332bf 100644 --- a/src/python/turicreate/test/test_image_classifier.py +++ b/src/python/turicreate/test/test_image_classifier.py @@ -77,11 +77,11 @@ def get_test_data(): data_dict = {"awesome_image": images, "awesome_label": labels} data = tc.SFrame(data_dict) - for model_name in MODEL_TO_FEATURE_SIZE_MAPPING: - if model_name == "VisionFeaturePrint_Scene" and _mac_ver() < (10, 14): - # VisionFeaturePrint_Scene is not support on Linux - continue - data[model_name + "_deep_features"] = get_deep_features(data["awesome_image"], model_name) + # for model_name in MODEL_TO_FEATURE_SIZE_MAPPING: + # if model_name == "VisionFeaturePrint_Scene" and _mac_ver() < (10, 14): + # # VisionFeaturePrint_Scene is not support on Linux + # continue + # data[model_name + "_deep_features"] = get_deep_features(data["awesome_image"], model_name) return data @@ -94,7 +94,7 @@ class ImageClassifierTest(unittest.TestCase): def setUpClass( self, model="resnet-50", - feature="awesome_image", + feature="resnet-50_deep_features", input_image_shape=(3, 224, 224), tol=0.02, num_examples=100, @@ -106,6 +106,10 @@ def setUpClass( self.pre_trained_model = model self.tolerance = tol + # Get deep features if needed + if self.feature != "awesome_image": + data[self.feature] = get_deep_features(data["awesome_image"], self.feature.split('_deep_features')[0]) + self.model = tc.image_classifier.create( data, target=self.target, feature=self.feature, model=self.pre_trained_model, seed=42 ) @@ -362,7 +366,7 @@ def setUpClass(self): input_image_shape=(3, 224, 224), tol=0.02, num_examples=100, - feature="resnet-50_deep_features", + feature="awesome_image", ) @@ -374,7 +378,7 @@ def setUpClass(self): input_image_shape=(3, 227, 227), tol=0.005, num_examples=200, - feature="awesome_image", + feature="squeezenet_v1.1_deep_features", ) class ImageClassifierSqueezeNetTestWithDeepFeatures(ImageClassifierTest): @@ -385,7 +389,7 @@ def setUpClass(self): input_image_shape=(3, 227, 227), tol=0.005, num_examples=200, - feature="squeezenet_v1.1_deep_features", + feature="awesome_image", ) @@ -402,7 +406,7 @@ def setUpClass(self): tol=0.005, num_examples=100, label_type=str, - feature="awesome_image", + feature="VisionFeaturePrint_Scene_deep_features", ) @@ -419,5 +423,5 @@ def setUpClass(self): tol=0.005, num_examples=100, label_type=str, - feature="VisionFeaturePrint_Scene_deep_features", + feature="awesome_image", ) From 0c5ff0c7cc26229ee4b63c11cb72fc25167e8448 Mon Sep 17 00:00:00 2001 From: Neeraj Komuravalli Date: Thu, 9 Jul 2020 18:06:27 +0530 Subject: [PATCH 42/44] Removing unnecessary comments --- src/python/turicreate/test/test_image_classifier.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/python/turicreate/test/test_image_classifier.py b/src/python/turicreate/test/test_image_classifier.py index 55a5b332bf..2e2583edb6 100644 --- a/src/python/turicreate/test/test_image_classifier.py +++ b/src/python/turicreate/test/test_image_classifier.py @@ -77,12 +77,6 @@ def get_test_data(): data_dict = {"awesome_image": images, "awesome_label": labels} data = tc.SFrame(data_dict) - # for model_name in MODEL_TO_FEATURE_SIZE_MAPPING: - # if model_name == "VisionFeaturePrint_Scene" and _mac_ver() < (10, 14): - # # VisionFeaturePrint_Scene is not support on Linux - # continue - # data[model_name + "_deep_features"] = get_deep_features(data["awesome_image"], model_name) - return data From df86dbd7556db04a214af3479d6cbdd5e7d0d9f3 Mon Sep 17 00:00:00 2001 From: Neeraj Komuravalli Date: Fri, 10 Jul 2020 14:09:11 +0530 Subject: [PATCH 43/44] Changed the logic that decides when to extract deepFeatures and changed the name of the same to WithDeepFeatures --- .../turicreate/test/test_image_classifier.py | 14 +++++++------- .../turicreate/test/test_image_similarity.py | 12 ++++++------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/python/turicreate/test/test_image_classifier.py b/src/python/turicreate/test/test_image_classifier.py index 2e2583edb6..e66a1fca1c 100644 --- a/src/python/turicreate/test/test_image_classifier.py +++ b/src/python/turicreate/test/test_image_classifier.py @@ -88,7 +88,7 @@ class ImageClassifierTest(unittest.TestCase): def setUpClass( self, model="resnet-50", - feature="resnet-50_deep_features", + feature="resnet-50_WithDeepFeature", input_image_shape=(3, 224, 224), tol=0.02, num_examples=100, @@ -101,8 +101,8 @@ def setUpClass( self.tolerance = tol # Get deep features if needed - if self.feature != "awesome_image": - data[self.feature] = get_deep_features(data["awesome_image"], self.feature.split('_deep_features')[0]) + if self.feature.endswith("WithDeepFeature"): + data[self.feature] = get_deep_features(data["awesome_image"], self.feature.split('_WithDeepFeature')[0]) self.model = tc.image_classifier.create( data, target=self.target, feature=self.feature, model=self.pre_trained_model, seed=42 @@ -172,9 +172,9 @@ def test_create_with_empty_dataset(self): def test_select_correct_feature_column_to_train(self): # sending both, the correct extracted features colum and image column if self.feature == "awesome_image": - test_data = data.select_columns([self.feature, self.target, self.pre_trained_model+"_deep_features"]) + test_data = data.select_columns([self.feature, self.target, self.pre_trained_model+"_WithDeepFeature"]) test_model = tc.image_classifier.create(test_data, target=self.target, model=self.pre_trained_model) - self.assertTrue(test_model.feature == self.pre_trained_model+"_deep_features") + self.assertTrue(test_model.feature == self.pre_trained_model+"_WithDeepFeature") def test_predict(self): model = self.model @@ -372,7 +372,7 @@ def setUpClass(self): input_image_shape=(3, 227, 227), tol=0.005, num_examples=200, - feature="squeezenet_v1.1_deep_features", + feature="squeezenet_v1.1_WithDeepFeature", ) class ImageClassifierSqueezeNetTestWithDeepFeatures(ImageClassifierTest): @@ -400,7 +400,7 @@ def setUpClass(self): tol=0.005, num_examples=100, label_type=str, - feature="VisionFeaturePrint_Scene_deep_features", + feature="VisionFeaturePrint_Scene_WithDeepFeature", ) diff --git a/src/python/turicreate/test/test_image_similarity.py b/src/python/turicreate/test/test_image_similarity.py index 78e2932cff..925723bd45 100644 --- a/src/python/turicreate/test/test_image_similarity.py +++ b/src/python/turicreate/test/test_image_similarity.py @@ -92,8 +92,8 @@ def setUpClass(self, input_image_shape=(3, 224, 224), model="resnet-50", feature } # Get deep features if needed - if self.feature != "awesome_image": - data[self.feature] = get_deep_features(data["awesome_image"], self.feature.split('_deep_features')[0]) + if self.feature.endswith("WithDeepFeature"): + data[self.feature] = get_deep_features(data["awesome_image"], self.feature.split('_WithDeepFeature')[0]) # Model self.model = tc.image_similarity.create( @@ -305,7 +305,7 @@ class ImageSimilarityResnetTestWithDeepFeatures(ImageSimilarityTest): @classmethod def setUpClass(self): super(ImageSimilarityResnetTestWithDeepFeatures, self).setUpClass( - model="resnet-50", input_image_shape=(3, 224, 224), feature="resnet-50_deep_features" + model="resnet-50", input_image_shape=(3, 224, 224), feature="resnet-50_WithDeepFeature" ) @@ -321,7 +321,7 @@ class ImageSimilaritySqueezeNetTestWithDeepFeatures(ImageSimilarityTest): @classmethod def setUpClass(self): super(ImageSimilaritySqueezeNetTestWithDeepFeatures, self).setUpClass( - model="squeezenet_v1.1", input_image_shape=(3, 227, 227), feature="squeezenet_v1.1_deep_features" + model="squeezenet_v1.1", input_image_shape=(3, 227, 227), feature="squeezenet_v1.1_WithDeepFeature" ) @@ -343,7 +343,7 @@ class ImageSimilarityVisionFeaturePrintSceneTestWithDeepFeatures(ImageSimilarity @classmethod def setUpClass(self): super(ImageSimilarityVisionFeaturePrintSceneTestWithDeepFeatures, self).setUpClass( - model="VisionFeaturePrint_Scene", input_image_shape=(3, 299, 299), feature="VisionFeaturePrint_Scene_deep_features" + model="VisionFeaturePrint_Scene", input_image_shape=(3, 299, 299), feature="VisionFeaturePrint_Scene_WithDeepFeature" ) # A test to gaurantee that old code using the incorrect name still works. @@ -365,5 +365,5 @@ class ImageSimilarityVisionFeaturePrintSceneTestWithDeepFeatures_bad_name(ImageS @classmethod def setUpClass(self): super(ImageSimilarityVisionFeaturePrintSceneTestWithDeepFeatures_bad_name, self).setUpClass( - model="VisionFeaturePrint_Screen", input_image_shape=(3, 299, 299), feature="VisionFeaturePrint_Scene_deep_features" + model="VisionFeaturePrint_Screen", input_image_shape=(3, 299, 299), feature="VisionFeaturePrint_Scene_WithDeepFeature" ) From fd01bcd0aaae929ceda85b5a94242e6e2bbe03ef Mon Sep 17 00:00:00 2001 From: Neeraj Komuravalli Date: Sat, 11 Jul 2020 11:36:18 +0530 Subject: [PATCH 44/44] Using the feature fed to unit test classes based on their names to maintain consistency --- .../turicreate/test/test_image_classifier.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/python/turicreate/test/test_image_classifier.py b/src/python/turicreate/test/test_image_classifier.py index e66a1fca1c..a03386b4e1 100644 --- a/src/python/turicreate/test/test_image_classifier.py +++ b/src/python/turicreate/test/test_image_classifier.py @@ -88,7 +88,7 @@ class ImageClassifierTest(unittest.TestCase): def setUpClass( self, model="resnet-50", - feature="resnet-50_WithDeepFeature", + feature="awesome_image", input_image_shape=(3, 224, 224), tol=0.02, num_examples=100, @@ -172,9 +172,12 @@ def test_create_with_empty_dataset(self): def test_select_correct_feature_column_to_train(self): # sending both, the correct extracted features colum and image column if self.feature == "awesome_image": - test_data = data.select_columns([self.feature, self.target, self.pre_trained_model+"_WithDeepFeature"]) + test_data = data.select_columns([self.feature, self.target]) + deep_features_col_name = self.pre_trained_model+"_WithDeepFeature" + test_data[deep_features_col_name] = get_deep_features(data["awesome_image"], + self.pre_trained_model) test_model = tc.image_classifier.create(test_data, target=self.target, model=self.pre_trained_model) - self.assertTrue(test_model.feature == self.pre_trained_model+"_WithDeepFeature") + self.assertTrue(test_model.feature == deep_features_col_name) def test_predict(self): model = self.model @@ -360,7 +363,7 @@ def setUpClass(self): input_image_shape=(3, 224, 224), tol=0.02, num_examples=100, - feature="awesome_image", + feature="resnet-50_WithDeepFeature", ) @@ -372,7 +375,7 @@ def setUpClass(self): input_image_shape=(3, 227, 227), tol=0.005, num_examples=200, - feature="squeezenet_v1.1_WithDeepFeature", + feature="awesome_image", ) class ImageClassifierSqueezeNetTestWithDeepFeatures(ImageClassifierTest): @@ -383,7 +386,7 @@ def setUpClass(self): input_image_shape=(3, 227, 227), tol=0.005, num_examples=200, - feature="awesome_image", + feature="squeezenet_v1.1_WithDeepFeature", ) @@ -400,7 +403,7 @@ def setUpClass(self): tol=0.005, num_examples=100, label_type=str, - feature="VisionFeaturePrint_Scene_WithDeepFeature", + feature="awesome_image", ) @@ -417,5 +420,5 @@ def setUpClass(self): tol=0.005, num_examples=100, label_type=str, - feature="awesome_image", + feature="VisionFeaturePrint_Scene_WithDeepFeature", )