예제 #1
0
    def create_estimator(self, estimator_type, path):
        """ Creates and returns an estimator of indicated type that can be
        found at indicated path.

        Parameters
        ----------
        estimator_type: :obj:`str`
            Type of the estimator that has to be returned. Can be either
            "sklearnestimator" or "kerasestimator" to create a scikit-learn
            estimator from pickle or keras estimator from .hdf5 file
            respectively.
        path: :obj:`str`
            Path to the estimator.

        Returns
        -------
        estimator: :class:`~phenoai.conatiners.Estimator`
            Class derived from :class:`~phenoai.conatiners.Estimator` of
            indicated estimator type. """
        if estimator_type == "sklearnestimator":
            logger.debug(
                "Create SklearnEstimator in EstimatorFactory instance")
            return SklearnEstimator(path)
        if estimator_type == "kerasestimator":
            logger.debug("Create KerasEstimator in EstimatorFactory instance")
            return KerasEstimator(path)
        return None
예제 #2
0
 def load(self):
     """ Loads the estimator into the
     :attr:`phenoai.estimators.SklearnEstimator.est` property from the
     location stored in :attr:`phenoai.estimators.SklearnEstimator.path`.
     """
     logger.debug("Loading estimator")
     with open(self.path + "/estimator.pkl", 'rb') as f:
         self.est = pkl.load(f)
예제 #3
0
파일: core.py 프로젝트: bstienen/phenoai
    def do_POST(self):
        """ Takes care of the handling of HTTP POST requests made to PhenoAI

        Performs a prediction query to PhenoAI via its
        :meth:`phenoai.core.PhenoAI.run` method. Returns the resulting
        :obj:`phenoai.containers.PhenoAIResults` object in the correct format.
        Users dont have to interact with this method directly, it is
        automatically called when needed. """
        logger.info("Received POST request from {}".format(
            self.client_address[0]))
        logger.set_indent("+")
        try:
            # Get POST data
            post = self.rfile.read(int(self.headers['Content-Length']))
            post = post.decode('utf-8')
            post = urllib.parse.parse_qs(post, keep_blank_values=1)
            for k, p in post.items():
                post[k] = p[0]
            # Split by mode
            if post["mode"] == "values":
                results = self._do_post_values(post)
            elif post["mode"] == "file":
                results = self._do_post_file(post)
            else:
                raise exceptions.ServerException(
                    ("Mode not recognized, should be either 'values' or "
                     "'file'. Provided was '{}'.").format(post['mode']))

            if ("get_results_as_string" in post
                    and float(post["get_results_as_string"]) == 1.0):
                logger.debug("Converting results object to string")
                # Return lists of results, not PhenoAIResults object
                results_txt = self.convert_result_object_to_string(results)
            else:
                # Convert to pickled instance
                logger.debug("Encoding results object to pickle")
                results_txt = io.pickle(results)
            returndict = {"status": "ok", "results": results_txt}
        except Exception as e:
            x = traceback.format_exc()
            logger.error(x)
            returndict = {
                "status": "error",
                "type": str(type(e).__name__),
                "message": str(e)
            }

        logger.info("Return results")
        # Send response status code
        self.send_response(200)
        # Send headers
        self.send_header('Content-type', 'text/html')
        self.end_headers()
        # Write content as utf-8 data
        returntext = json.dumps(returndict)
        self.wfile.write(bytes(returntext, "utf8"))
        logger.set_indent("-")
예제 #4
0
 def summary(self):
     """ Prints a summary of the contents of this object """
     logger.debug("Print report for AInalysisResults")
     print("===========================")
     print("||  PhenoAIResults report  ||")
     print("===========================")
     print("Contains {} AInalysisResults object(s)".format(self.num()))
     print("AInalysisResult IDs:")
     for i in range(self.num()):
         print("  - {} (length: {})".format(
             self.get_ids()[i],
             self.get(self.get_ids()[i]).num()))
     print("Access AInalysisResults objects by id via PhenoAIResults[ id ]")
예제 #5
0
파일: core.py 프로젝트: bstienen/phenoai
    def _do_post_file(self, post):
        """ Handle server queries when provided with a file

        Should not be interacted with directly, but only through the do_POST
        method of this class.

        Parameters
        ----------
        post: :obj:dict
            Dictionary containing POST headers
        
        Returns
        -------
        results: :obj:`PhenoAIResults`
            Results of the prediction routine by the PhenoAI object
        """
        logger.debug("Received file to be interpreted")
        data_ids = ast.literal_eval(post["data_ids"])
        ainalysis_ids = ast.literal_eval(post["ainalysis_ids"])

        # Create files in tmp folder
        filepath = "/tmp/{}.phenoai".format(utils.random_string(16))
        filepath_interpreted = "/tmp/{}_interpreted.phenoai".format(
            utils.random_string(16))

        logger.debug("Calling run() on PhenoAI server instance")
        try:
            with open(filepath, "w") as tmpfile:
                tmpfile.write(post['data'])
            results = __serverinstance__.run(filepath,
                                             map_data=bool(
                                                 float(post['mapping'])),
                                             ainalysis_ids=ainalysis_ids,
                                             data_ids=data_ids)
            os.remove(filepath)
        except Exception:
            with open(filepath_interpreted, "w") as tmpfile:
                tmpfile.write(post['data'])
            results = __serverinstance__.run(filepath_interpreted,
                                             map_data=bool(
                                                 float(post['mapping'])),
                                             ainalysis_ids=ainalysis_ids,
                                             data_ids=data_ids)
            os.remove(filepath_interpreted)

        if os.path.exists(filepath):
            os.remove(filepath)
        if os.path.exists(filepath_interpreted):
            os.remove(filepath_interpreted)

        return results
예제 #6
0
    def predict(self, data):
        """ Returns a prediction for the data by querying it to the loaded
        estimator.

        Parameters
        ----------
        data: :obj:`numpy.ndarray`
            Data to be queried to the estimator. Should have format
            `(nDatapoints, nParameters)`.

        Returns
        -------
        prediction: :obj:`numpy.ndarray`
            Prediction by the loaded estimator for the provided data. Shape of
            the array depends on the estimator. """
        logger.debug("Querying estimator for prediction (predict)")
        return self.est.predict(data)
예제 #7
0
 def summary(self):
     """ Prints a summary of the contents of this object """
     logger.debug("Print report for AInalysisResults")
     print("---------------------------")
     print("| AInalysisResults report |")
     print("---------------------------")
     print("ID: {}".format(self.result_id))
     print("Length: {}".format(self.num()))
     # Information on data
     contains_data = self.get_data() is not None
     print("Contains data: {}".format(contains_data))
     if contains_data:
         print("  Data shape: {}".format(self.get_data().shape))
         print("  Access via .get_data( args )")
     # Information on Data ids
     contains_data_ids = self.get_ids() is not None
     print("Contains data IDs: {}".format(contains_data_ids))
     if contains_data_ids:
         print("  Data IDs length: {}".format(len(self.get_ids())))
         print("  Get full list via .get_ids()")
         print("  Use as argument in .get_*() methods")
     # Information on data mapping
     data_is_mapped = self.is_mapped()[0]
     print("Data is mapped: {}".format(data_is_mapped))
     if data_is_mapped:
         if isinstance(self.is_mapped()[1], list):
             print("  Data IDs length: {}".format(len(self.is_mapped()[1])))
         elif isinstance(self.is_mapped()[1], np.ndarray):
             print("  Data IDs shape: {}".format(self.is_mapped()[1].shape))
         print("  Access via .is_mapped( args )")
     # Information on Data ids
     contains_predictions = self.get_predictions() is not None
     print("Contains predictions: {}".format(contains_predictions))
     if contains_predictions:
         print("  Predictions shape: {}".format(
             self.get_predictions().shape))
         print("  Access via .get_predictions( args )")
예제 #8
0
파일: core.py 프로젝트: bstienen/phenoai
    def _do_post_values(self, post):
        """ Handle server queries when provided bare values

        Should not be interacted with directly, but only through the do_POST
        method of this class.

        Parameters
        ----------
        post: :obj:dict
            Dictionary containing POST headers
        
        Returns
        -------
        results: :obj:`PhenoAIResults`
            Results of the prediction routine by the PhenoAI object
        """
        logger.debug("Received raw values")
        # Predict lists of values
        data = ast.literal_eval(post['data'])
        if not "data_ids" in post:
            data_ids = None
        elif post["data_ids"] == "false" or post["data_ids"] == "False":
            data_ids = None
        else:
            data_ids = ast.literal_eval(post["data_ids"])
        if "ainalysis_ids" not in post:
            ainalysis_ids = None
        else:
            ainalysis_ids = ast.literal_eval(post["ainalysis_ids"])
            # Perform prediction
            if ainalysis_ids == "all":
                ainalysis_ids = None
        logger.debug(("Calling run procedure of PhenoAI server " "instance"))
        return __serverinstance__.run(np.array(data),
                                      map_data=bool(float(post['mapping'])),
                                      ainalysis_ids=ainalysis_ids,
                                      data_ids=data_ids)
예제 #9
0
    def predict_proba(self, data):
        """ Returns a probability prediction for provided data by querying it
        to the loaded estimator. Since only classifiers have this functionality
        in scikit-learn, this method will return `None` if the estimator does
        not have a :func:`prediction_proba` method itself.

        Parameters
        ----------
        data: :obj:`numpy.ndarray`
            Data to be queried to the estimator. Should have format
            `(nDatapoints, nParameters)`.

        Returns
        -------
        prediction: :obj:`numpy.ndarray`, `None`
            Prediction by the loaded estimator for the provided data. Shape of
            the array depends on the estimator. If the loaded estimator does
            not have a :func:`predict_proba` method itself, `None` will be
            returned."""
        logger.debug("Querying estimator for prediction (predict_proba)")
        if hasattr(self.est, "predict_proba"):
            return self.est.predict_proba(data)
        logger.debug("Estimator has no predict_proba function")
        return None
예제 #10
0
#   30    WARNING
#   40    ERROR
#   50    CRITICAL
# The setting below indicates that all messages with an importance of INFO or
# higher will be printed

logger.to_stream(lvl=20)

# Send output to file. The level of this output channel may differ from the lvl
# for the stream channel. Only a single filechannel can exist at a time.

logger.to_file("loggertest.out", lvl=0)

# Output a couple of messages

logger.debug("debug message")
logger.info("yo")
logger.warning("warning message")
logger.error("this is an error")
logger.critical("HELP!")

# Colour the output messages for the stream channel. The file channel is
# unaffected by this setting.
# This setting could also be put into the to_stream function via
#     logger.to_stream(lvl=20, colour=True)

logger.colour_stream(True)

# Again print some messages

logger.debug("debug message")
예제 #11
0
파일: core.py 프로젝트: bstienen/phenoai
    def run(self, data, map_data=False, ainalysis_ids=None, data_ids=None):
        """ Queries each added AInalysis for prediction on provided data

        This run method forms the core functionality of PhenoAI objects. It
        calls the run method of each of the added AInalyses with the provided
        data and configuration arguments. Returns are returned in a
        :obj:`phenoai.containers.PhenoAIResults` object.

        The `map_data` argument is to be interpreted slightly differently here
        then the map_data argument of AInalysis objects. This argument controls
        if, for each of the AInalyses, the data is mapped before being
        subjected to the prediction methods of the estimator in the AInalysis.
        As such, this argument can either be True or False, just as the
        `map_data` argument of the AInalysis run method. However, this run
        method differs in the sense that is allows the entry "both", which
        queries all AInalyses that allow mapping of data *twice*: once with
        mapping and once without. These AInalyses thus have two
        AInalysisResults instances in the returned
        :obj:`phenoai.containers.PhenoAIResults` object, which can be
        differentiated based on their ID: the mapped results instance has
        "_mapped" appended to the ID name.

        Parameters
        ----------
        data: :obj:`numpy.ndarray`, :obj:`str`, :obj:`list(str)` Data that has
            to be subjected to the estimator. Can be the raw data
            (numpy.ndarray), the location of a file to be read by the built-in
            file reader in the AInalysis or a list of file locations.

        map_data: :obj:`bool`. Optional Determines if data has to be mapped
            before prediction. Mapping uses the map_data method of this
            AInalysis and follows the mapping procedure defined in the
            configuration file for this AInalysis. Can also be "both", making
            each mapping-allowing AInalyses to be queried twice: once with and
            once without mapping. Mapped data returns an AInalysisResults
            object with "_mapped" appended to the AInalysisResults ID. Default
            is `False`.

        ainalysis_ids: :obj:`list(str)`. Optional If set to a list of strings,
            only AInalyses with an ID present in this list are queried for
            prediction on provided data. If set to `None`, all AInalyses are
            queried. Default is `None`.

        data_ids: :obj:`list(float)`, :obj:`numpy.ndarray`. Optional List or
            numpy.ndarray of IDs for the data points. By setting this value,
            results can be extracted from the AInalysisResults object by using
            the IDs in this list/array instead of by its location in the result
            array. If `None`, this functionality will not be available. Default
            is `None`."""

        # Use PhenoAI object locally
        # Create mapping iteration list
        mapmodes = []
        if map_data == "both":
            mapmodes.append(True)
            mapmodes.append(False)
            logger.info("Running PhenoAI with mapmode 'both'")
        else:
            mapmodes.append(bool(map_data))
            logger.info("Running PhenoAI with mapmode {}".format(
                bool(map_data)))

        # Create results object
        results = containers.PhenoAIResults()
        # Loop over ainalyses to request prediction
        for ainalysis in self.ainalyses:
            # Load estimator if not loaded already
            loaded = True
            if self.dynamic and not ainalysis.estimator.is_loaded():
                logger.debug("Loading estimator of AInalysis dynamically")
                ainalysis.estimator.load()
                loaded = False

            # Iterate over mapmodes
            for mapmode in mapmodes:
                # Test if this AInalysis should be queried
                if (ainalysis_ids is not None
                        and ainalysis.ainalysis_id not in ainalysis_ids):
                    continue

                # If multi mapmode skip mapmode True if AInalysis does not
                # allow mapping
                if (isinstance(ainalysis.configuration['mapping'], bool)
                        and ainalysis.configuration['mapping'] == 0.0
                        and mapmode and len(mapmodes) > 1):
                    continue
                logger.info("Running AInalysis '{}' in map mode '{}'".format(
                    ainalysis.ainalysis_id, mapmode))

                # Do prediction
                logger.set_indent("+")
                result = ainalysis.run(data,
                                       map_data=mapmode,
                                       data_ids=data_ids)
                logger.set_indent("-")
                # Alter id if multi map mode
                if len(mapmodes) > 1:
                    if mapmode:
                        result.result_id += "_mapped"
                # Add result to AIResultContainer container
                results.add(result)

            # Unload estimator
            if not loaded:
                logger.debug(("Clearing estimator of last AInalysis "
                              "from memory"))
                ainalysis.estimator.clear()

        logger.info("PhenoAI run finished, returning result")
        # Return results object
        return results