Esri / raster-deep-learning

ArcGIS built-in python raster functions for deep learning to get you started fast.
Apache License 2.0
186 stars 87 forks source link

AttributeError: module ** has no attribute #5

Closed OterLabb closed 5 years ago

OterLabb commented 5 years ago

Hi, im getting this error when importing an .emd file into the Classify pixels using deep learning and the Detect objects using deep learning tools.

error2

I am using .emd examples and python scripts from this repository, and have tried different combinations but I cant get them to work. Cloned python v 3.6.6 Tensorflow v 1.12.0

keras_model.emd

{
    "Framework":"Keras", 
    "InferenceFunction":"MaskRCNN.py", 
    "ModelConfiguration":"DeepLab", 
    "ModelFile":"mask_rcnn_coco.h5", 
    "ModelType":"ImageClassification", 
    "ExtractBands": [0,1,2,3], 
    "ImageWidth":256, 
    "ImageHeight":256, 

    "Classes": [
        {
            "Value":0, 
            "Name":"Buildings", 
            "Ccolor": [0, 51, 0]
        },
        {
            "Value":1, 
            "Name":"Roads/Parking Lots/Driveways", 
            "Color": [241, 185, 137] 
        },
        {
            "Value":2, 
            "Name":"Planted/Darker Cropland", 
            "Color": [236, 236, 0]
        },
        {
            "Value":3, 
            "Name":"Water", 
            "Color": [0, 0, 117] 
        },
        {
            "Value":4, 
            "Name":"Forest", 
            "Color": [102, 102, 0] 
        },
        {
            "Value":5, 
            "Name":"Harvested/Open/Bare", 
            "Color": [236, 236, 236] 
        }
    ]
}

MaskRCNN.py

'''
Copyright 2018 Esri
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
   http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.​
'''

import json
import os
import sys

import numpy as np

sys.path.append(os.path.dirname(__file__))
import importlib
from skimage.measure import find_contours
import keras.backend as K
import tensorflow as tf

class MatterMaskRCNN:
    def initialize(self, model, model_as_file):
        K.clear_session()

        if model_as_file:
            with open(model, 'r') as f:
                self.json_info = json.load(f)
        else:
            self.json_info = json.loads(model)

        model_path = self.json_info['ModelFile']
        if model_as_file and not os.path.isabs(model_path):
            model_path = os.path.abspath(os.path.join(os.path.dirname(model), model_path))

        config_module = self.json_info['ModelConfiguration']['Config']
        if not os.path.isabs(config_module):
            config_module = os.path.abspath(os.path.join(os.path.dirname(model), config_module))

        sys.path.append(os.path.dirname(config_module))
        config_module_name = os.path.basename(config_module)

        if config_module_name in sys.modules:
            del sys.modules[config_module_name]

        self.config = getattr(importlib.import_module(config_module_name), 'config')

        architecture_module = self.json_info['ModelConfiguration']['Architecture']
        if not os.path.isabs(architecture_module):
            architecture_module = os.path.abspath(os.path.join(os.path.dirname(model), architecture_module))

        sys.path.append(os.path.dirname(architecture_module))
        architecture_module_name = os.path.basename(architecture_module)

        if (architecture_module_name != config_module_name) and (architecture_module_name in sys.modules):
            del sys.modules[architecture_module_name]

        self.model = getattr(importlib.import_module(architecture_module_name), 'model')

        self.model.load_weights(model_path, by_name=True)

        self.graph = tf.get_default_graph()

    def getParameterInfo(self, required_parameters):
        return required_parameters

    def getConfiguration(self, **scalars):
        self.padding = int(scalars['padding'])

        return {
            'extractBands': tuple(self.json_info['ExtractBands']),
            'padding': int(scalars['padding']),
            'tx': self.json_info['ImageWidth'] - 2 * self.padding,
            'ty': self.json_info['ImageHeight'] - 2 * self.padding
        }

class ChildImageClassifier(MatterMaskRCNN):
    def updatePixels(self, tlc, shape, props, **pixelBlocks):
        image = pixelBlocks['raster_pixels']
        _, height, width = image.shape
        image = np.transpose(image, [1,2,0])

        with self.graph.as_default():
            results = self.model.detect([image], verbose=1)

        masks = results[0]['masks']
        class_ids = results[0]['class_ids']
        output_raster = np.zeros((masks.shape[0], masks.shape[1], 1), dtype=props['pixelType'])
        mask_count = masks.shape[-1]
        for i in range(mask_count):
            mask = masks[:, :, i]
            output_raster[np.where(mask==True)] = class_ids[i]

        return np.transpose(output_raster, [2,0,1])

class ChildObjectDetector(MatterMaskRCNN):
    def vectorize(self,  **pixelBlocks):
        image = pixelBlocks['raster_pixels']
        _, height, width = image.shape
        image = np.transpose(image, [1,2,0])

        with self.graph.as_default():
            results = self.model.detect([image], verbose=1)

        masks = results[0]['masks']
        mask_count = masks.shape[-1]
        coord_list = []
        for m in range(mask_count):
            mask = masks[:, :, m]
            padded_mask = np.zeros((mask.shape[0]+2, mask.shape[1]+2), dtype=np.uint8)
            padded_mask[1:-1, 1:-1] = mask
            contours = find_contours(padded_mask, 0.5, fully_connected='high')

            if len(contours) != 0:
                verts = contours[0] - 1
                coord_list.append(verts)

        if self.padding != 0:
            coord_list[:] = [item - self.padding for item in coord_list]

        return coord_list, results[0]['scores'], results[0]['class_ids']
lingtangraster commented 5 years ago

@OterLabb First of all, may I ask two questions?

  1. Did you use https://github.com/matterport/Mask_RCNN to train your keras model? If yes, your emd file should look similar to this one:

    {
        "Framework": "Keras",
        "ModelConfiguration": {
            "Name":"MaskRCNN",
            "Architecture":".\\mrcnn\\coco",
            "Config":".\\mrcnn\\coco"
         },
        "ModelFile":".\\mask_rcnn_coco.h5",
        "ModelType":"ObjectDetection",
        "ImageHeight":256,
        "ImageWidth":256,
        "ExtractBands":[0,1,2],
        "Classes": [
        {
            "Value":0, 
            "Name":"Buildings", 
            "Ccolor": [0, 51, 0]
        },
        {
            "Value":1, 
            "Name":"Roads/Parking Lots/Driveways", 
            "Color": [241, 185, 137] 
        },
        {
            "Value":2, 
            "Name":"Planted/Darker Cropland", 
            "Color": [236, 236, 0]
        },
        {
            "Value":3, 
            "Name":"Water", 
            "Color": [0, 0, 117] 
        },
        {
            "Value":4, 
            "Name":"Forest", 
            "Color": [102, 102, 0] 
        },
        {
            "Value":5, 
            "Name":"Harvested/Open/Bare", 
            "Color": [236, 236, 236] 
        }
    ]
    }

    Meanwhile, emd file also needs to access the "mrcnn" folder used to train the model, which is set in the "ModelConfiguration".

  2. Which task are you dealing with, it is for object detection or image classification? If you are on image classfication, please change "ModelType" in the emd file to "ImageClassification".

Let me know if you have any other issues. Meanwhile, we are actively working on the help documentations on this repo, it will help to answer these issues.

OterLabb commented 5 years ago

Thanks for answering!

  1. Yes I used matterport to train my model.
  2. I want to do both classification and object detection. For now, just proof of concept, to get it working in ArcGIS Pro. Im trying to use your .emd suggestion on object detection, but do you have an example of how the config/Architecture file in "\mrcnn\coco" should be like?
lingtangraster commented 5 years ago

@OterLabb It is similar as this folder in the matterport repo: https://github.com/matterport/Mask_RCNN/tree/master/mrcnn

Meanwhile, the sample model I have was trained on SpaceNet dataset, so there is a custom config py file "spacenet" built on top of the model and config modules in the mrcnn folder.

spacenet.py

import os, sys
sys.path.append(os.path.dirname(__file__))
from config import Config
import model as modellib

class SpaceNetConfig(Config):
    NAME = 'spacenet'
    IMAGES_PER_GPU = 1
    NUM_CLASSES = 1+1
    USE_MINI_MASK = False

    IMAGE_MIN_DIM = 1024
    IMAGE_MAX_DIM = 1024

    MEAN_PIXEL = [0.0, 0.0, 0.0]

    STEPS_PER_EPOCH = 500

class InferenceConfig(SpaceNetConfig):
    IMAGES_PER_GPU = 1
    GPU_COUNT = 1

config = InferenceConfig()

model = modellib.MaskRCNN(mode='inference', config=config, model_dir='./')
lingtangraster commented 5 years ago

@OterLabb Therefore, my emd file is like this:

{
    "Framework": "Keras",
    "ModelConfiguration": {
       "Name":"MaskRCNN",
       "Architecture":".\\mrcnn\\spacenet",
       "Config":".\\mrcnn\\spacenet"
    },
    "ModelFile":".\\mask_rcnn_spacenet_0053.h5",
    "ModelType":"ObjectDetection",
    "ImageHeight":650,
    "ImageWidth":650,
    "ExtractBands":[0,1,2],

    "Classes" : [
      {
        "Value": 1,
        "Name": "Building",
        "Color": [0, 255, 0]
      }
    ]
}
OterLabb commented 5 years ago

Thanks for your support, really put me in the right direction. I guess this issue can be closed. But I still cannot get the tool to work in ArcGIS Pro. Im pasting my error message here in case you have an idea where things are not working now.

Messages
Start Time: 05 March 2019 01:17:35
Distributing operation across 4 parallel instances.
 ERROR 999999: Something unexpected caused the tool to fail. Contact Esri Technical Support (http://esriurl.com/support) to Report a Bug, and refer to the error help for potential solutions or workarounds.
 Python raster function is unable to vectorize the data.
 Traceback (most recent call last):
 File "c:\program files\arcgis\pro\Resources\Raster\Functions\System\DeepLearning\ObjectDetector.py", line 101, in vectorize
 polygon_list, scores, classes = self.child_object_detector.vectorize(**pixelBlocks)
 File "c:\program files\arcgis\pro\Resources\Raster\Functions\System\DeepLearning\Keras\MaskRCNN.py", line 96, in vectorize
 results = self.model.detect([image], verbose=1)
 File "C:\Users\Oddbjorn\Documents\ArcGIS\Projects\DeepLearning\mrcnn\model.py", line 2524, in detect
 self.keras_model.predict([molded_images, image_metas, anchors], verbose=0)
 File "C:\Users\Oddbjorn\AppData\Local\ESRI\conda\envs\arcgispro-py3-clone2\Lib\site-packages\keras\engine\training.py", line 1164, in predict
 self._make_predict_function()
 File "C:\Users\Oddbjorn\AppData\Local\ESRI\conda\envs\arcgispro-py3-clone2\Lib\site-packages\keras\engine\training.py", line 554, in _make_predict_function
 **kwargs)
 File "C:\Users\Oddbjorn\AppData\Local\ESRI\conda\envs\arcgispro-py3-clone2\Lib\site-packages\keras\backend\tensorflow_backend.py", line 2744, in function
 return Function(inputs, outputs, updates=updates, **kwargs)
 File "C:\Users\Oddbjorn\AppData\Local\ESRI\conda\envs\arcgispro-py3-clone2\Lib\site-packages\keras\backend\tensorflow_backend.py", line 2546, in __init__
 with tf.control_dependencies(self.outputs):
 File "C:\Users\Oddbjorn\AppData\Local\ESRI\conda\envs\arcgispro-py3-clone2\Lib\site-packages\tensorflow\python\framework\ops.py", line 5004, in control_dependencies
 return get_default_graph().control_dependencies(control_inputs)
 File "C:\Users\Oddbjorn\AppData\Local\ESRI\conda\envs\arcgispro-py3-clone2\Lib\site-packages\tensorflow\python\framework\ops.py", line 4543, in control_dependencies
 c = self.as_graph_element(c)
 File "C:\Users\Oddbjorn\AppData\Local\ESRI\conda\envs\arcgispro-py3-clone2\Lib\site-packages\tensorflow\python\framework\ops.py", line 3490, in as_graph_element
 return self._as_graph_element_locked(obj, allow_tensor, allow_operation)
 File "C:\Users\Oddbjorn\AppData\Local\ESRI\conda\envs\arcgispro-py3-clone2\Lib\site-packages\tensorflow\python\framework\ops.py", line 3569, in _as_graph_element_locked
 raise ValueError("Tensor %s is not an element of this graph." % obj)
 ValueError: Tensor Tensor("mrcnn_detection/Reshape_1:0", shape=(1, 100, 6), dtype=float32) is not an element of this graph.
 Python Raster Function's .vectorize() method returned nothing.
 Python raster function is unable to vectorize the data.
 Traceback (most recent call last):
 File "c:\program files\arcgis\pro\Resources\Raster\Functions\System\DeepLearning\ObjectDetector.py", line 101, in vectorize
 polygon_list, scores, classes = self.child_object_detector.vectorize(**pixelBlocks)
 File "c:\program files\arcgis\pro\Resources\Raster\Functions\System\DeepLearning\Keras\MaskRCNN.py", line 96, in vectorize
 results = self.model.detect([image], verbose=1)
 File "C:\Users\Oddbjorn\Documents\ArcGIS\Projects\DeepLearning\mrcnn\model.py", line 2524, in detect
 self.keras_model.predict([molded_images, image_metas, anchors], verbose=0)
 File "C:\Users\Oddbjorn\AppData\Local\ESRI\conda\envs\arcgispro-py3-clone2\Lib\site-packages\keras\engine\training.py", line 1164, in predict
 self._make_predict_function()
 File "C:\Users\Oddbjorn\AppData\Local\ESRI\conda\envs\arcgispro-py3-clone2\Lib\site-packages\keras\engine\training.py", line 554, in _make_predict_function
 **kwargs)
 File "C:\Users\Oddbjorn\AppData\Local\ESRI\conda\envs\arcgispro-py3-clone2\Lib\site-packages\keras\backend\tensorflow_backend.py", line 2744, in function
 return Function(inputs, outputs, updates=updates, **kwargs)
 File "C:\Users\Oddbjorn\AppData\Local\ESRI\conda\envs\arcgispro-py3-clone2\Lib\site-packages\keras\backend\tensorflow_backend.py", line 2546, in __init__
 with tf.control_dependencies(self.outputs):
 File "C:\Users\Oddbjorn\AppData\Local\ESRI\conda\envs\arcgispro-py3-clone2\Lib\site-packages\tensorflow\python\framework\ops.py", line 5004, in control_dependencies
 return get_default_graph().control_dependencies(control_inputs)
 File "C:\Users\Oddbjorn\AppData\Local\ESRI\conda\envs\arcgispro-py3-clone2\Lib\site-packages\tensorflow\python\framework\ops.py", line 4543, in control_dependencies
 c = self.as_graph_element(c)
 File "C:\Users\Oddbjorn\AppData\Local\ESRI\conda\envs\arcgispro-py3-clone2\Lib\site-packages\tensorflow\python\framework\ops.py", line 3490, in as_graph_element
 return self._as_graph_element_locked(obj, allow_tensor, allow_operation)
 File "C:\Users\Oddbjorn\AppData\Local\ESRI\conda\envs\arcgispro-py3-clone2\Lib\site-packages\tensorflow\python\framework\ops.py", line 3569, in _as_graph_element_locked
 raise ValueError("Tensor %s is not an element of this graph." % obj)
 ValueError: Tensor Tensor("mrcnn_detection/Reshape_1:0", shape=(1, 100, 6), dtype=float32) is not an element of this graph.
 Python Raster Function's .vectorize() method returned nothing.
 Failed to execute (DetectObjectsUsingDeepLearning).
Failed at 05 March 2019 01:18:35 (Elapsed Time: 59.10 seconds)
lingtangraster commented 5 years ago

@OterLabb I saw this error before in the python raster function "MaskRCNN.py". Line 75, line 96, and line 116 were added to fix this issue. https://github.com/Esri/raster-deep-learning/blob/master/python_raster_functions/Keras/MaskRCNN.py

line 75        self.graph = tf.get_default_graph()

Could you check if you are using the up-to-date MaskRCNN.py file provided in this repo? Your deep learning python raster functions could be located in the Pro resrouces folder here: C:\Program Files\ArcGIS\Pro\Resources\Raster\Functions\System\DeepLearning\Keras\MaskRCNN.py

lingtangraster commented 5 years ago

@OterLabb If it still cannot fix your issue, I suggested you look around for solutions on the web.

If it is a generic issue with Keras model inference, usually people gave out solutions on related githubs. Thanks.

OterLabb commented 5 years ago

It worked when I used the updated MaskRCNN.py and added the getParameterInfo function from the old file! Thanks for the help :)

    def getParameterInfo(self, required_parameters):
        required_parameters.append(
            {
                'name': 'padding',
                'dataType': 'numeric',
                'value': 0,
                'required': False,
                'displayName': 'Padding',
                'description': 'Padding'
            },
        )
        return required_parameters

Whole file: https://gist.github.com/OterLabb/d590d55125027486654905c7750dfdc7

lingtangraster commented 5 years ago

@OterLabb Good to know it worked on you! The padding info is already in ObjectDetector.py, which is the enter point of all the object detection models. https://github.com/Esri/raster-deep-learning/blob/master/python_raster_functions/ObjectDetector.py

We recently went through code refactor to generalize the way to custom deep learning python raster functions. Are you using ArcGIS Pro 2.3? If so, you could download the source code in this repo, and in your emd file set the inference function to the py module in this repo. Then the deep learning python raster functions will use the up-to-date ones.

"InferenceFunction":"E:\\raster-deep-learning\\python_raster_functions\\ObjectDetector.py",
OterLabb commented 5 years ago

Yes, I'm using 2.3.1. Thanks for the tips!

lingtangraster commented 5 years ago

@Karl-Keller Please change the ModelConfiguration to "MaskRCNN"

A sample emd file included in this repo is here: https://github.com/Esri/raster-deep-learning/blob/master/examples/keras/mask_rcnn/mask_rcnn.emd

Meanwhile, you could also check your pro install folder at ArcGIS\Pro\Resources\Raster\Functions\System\DeepLearning\Keras\MaskRCNN.py This is the python module that was called during emd validation.