Code Monkey home page Code Monkey logo

raymon's Introduction

Raymon: analyse data & model health

Build Coverage Code style: black License PyPI

What is Raymon?

Raymon helps Machine Learning teams analyse data, data health and model performance. Using Raymon, users can extract features describing data quality, data novelty, model confidence and prediction performance from model predictions. Then, they can use these features to validate production data and generate reports for data drift, data degradation and model degradation.

We can support any data type. Currently, we offer extractors for structured data and vision data, but you can easily implement your own extractor which means we can any data type and any extractor that you want.

Raymon’s focus is on simplicity, practicality and extendability. We offer a set of extractors that are cheap to compute and simple to understand.

Raymon is open source and can be used standalone but integrates nicely with the Raymon.ai ML Observability hub, for example to make predictions traceable and debuggable.

Quick Links

At a glance

Installation

pip install raymon

Building a model profile

Building a ModelProfile captures all kinds of data characteristics of your models inputs, outputs, actuals and predictions.

profile = ModelProfile(
    name="HousePricesCheap",
    version="3.0.0",
    components=[
        InputComponent(
            name="outlier_score",
            extractor=SequenceSimpleExtractor(
                prep=coltf, extractor=KMeansOutlierScorer()),
        ),
        OutputComponent(name="prediction", extractor=ElementExtractor(element=0)),
        ActualComponent(name="actual", extractor=ElementExtractor(element=0)),
        EvalComponent(name="abs_error", extractor=AbsoluteRegressionError()),
    ] + generate_components(X_train[feature_selector].dtypes, 
                            complass=InputComponent), # Generates a component for every column in the DF
    scores=[
        MeanScore(
            name="MAE",
            inputs=["abs_error"],
            preference="low",
        ),
        MeanScore(
            name="mean_outlier_score",
            inputs=["outlier_score"],
            preference="low",
        ),
    ],
)
profile.build(input=X_val[feature_selector], 
              output=y_pred_val[:, None], 
              actual=y_val[:, None])
profile.view()

image

Validating production data

Profiles can then be used in production code to validate your incoming data and model performance monitoring.

tags = profile.validate_input(request)
output_tags = profile.validate_output(request_pred)
actual_tags = profile.validate_actual(request_actual)
eval_tags = profile.validate_eval(output=request_pred, 
                                  actual=request_actual)
# or all at once:
all_tags = profile.validate_all(input=request, 
                                output=request_pred, 
                                actual=request_actual)

Inspect and contrast model profiles

You can contast different model profiles against each other too. For example, to compare the profile at model train time, with the profile on production data, or to compare subsets of production data.

profile.view_contrast(profile_exp)

interactive-demo

Logging text, data and tags

Moreover, if you want to use the rest of the platform, Raymon makes model predictions traceable and debuggable. Raymon enables you to log text, data and tags from anywhere in your code. You can later use these tags and data objects to debug and improve your systems.

import pandas as pd
import numpy as np
from PIL import Image

import raymon.types as rt
from raymon import Trace, RaymonAPILogger, Tag


logger = RaymonAPILogger(project_id=project_id)
trace = Trace(logger=logger, trace_id=None)

# Logging text messages
trace.info("You can log whatever you want here")

# Tagging traces
trace.tag([
        Tag(name="sdk_version", value="1.4.2", type="label"),
        Tag(name="prediction_time_ms", value="120", type="metric")
    ])

# Logging data
img = Image.open("./data_sample/castinginspection/def_front/cast_def_0_0.jpeg")
df = pd.DataFrame(arr, columns=['a', 'b'])

trace.log(ref="pandas-ref", data=rt.DataFrame(df))
trace.log(ref="image-ref", data=rt.Image(img))

For more information, check out our docs & examples!

raymon's People

Contributors

kvhooreb avatar pbonte avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

Forkers

pbonte

raymon's Issues

Add Authentication

The Raymon Logging library should call the backend with the Authorization header set to a Bearer JWT token. It should get the token from our Auth0 endpoint. To get the token for machine 2 machine logging, it should send a request with the following parameters to the Auth0 endpoint:

  • RAYMON_AUTH0_URL: The endpoint to query the token on
  • RAYMON_GRANT_TYPE:
  • RAYMON_AUDIENCE: The API we want to log to
  • RAYMON_CLIENT_ID: client id
  • RAYMON_CLIENT_SECRET: client secret

These parameters should be loaded from ~/.raymon/secrets.json, <working_dir>/.raymon.json, from environment variables or from a specific file, in that order of ascending priority.

Important: this use case is for ingesting data. For users querying and inspection data, we need another workflow.

Contrast profiles only for common components

When one profile has input_components=[a, b, c] and output_comonents=[d, e], and the other profile has nput_components=[a, b] and output_comonents=[d], a schema contrast should only take the common components.

Add p-values or confidence interval to drift tests

We need a way to indicate how confident we are about the drift, which will be in function of the data we've analysed. We currently use a 2 sample KS test for NumericStats, but do not return a p-value. We could easily do this, but we need to decide what to do with the other types first:

  • Is the KS actually applicable for discrete distributions? (Like IntComponent)
  • What with CategroicalComponents?

For all component types / stats types, we need a test that returns a value between 0 and 1, and can return a pvalue, confidence interval, or something else.

Typo's etc. examples logging library

raymon/examples/0-setup-logging.ipynb

  • you cna easlity fetch artefacts from the backend and load the data. > you can easily fetch artefacts from the backend and load the data.

https://github.com/raymon-ai/raymon/blob/master/examples/1-profiling-structured.ipynb

  • Note that some outputs may not be work when viewing on Github since they are shown in an iframe. We recommend to clone this repo and execute the notebooks locally. > might not work(?)
  • This subset just happens to mostly contain houses on the cheaper end of the price spectrum, which will come in handy later. >> leest wat raar precies, mss kunnen we zeggen for the sake of the example.
  • RDV offers toolign to inspect the schema's that are built. Let's laod the schema (just because we can) and inspect it. > RDV offers tooling to inspect the schema's that are built. Let's load the schema (just because we can) and inspect it.
    RDV mag ook weg
  • There are a few things of note here. > Things to note?
  • 3 lege blokjes onderaan

https://github.com/raymon-ai/raymon/blob/master/examples/2-profiling-vision.ipynb

  • Just like in the case of structured data, we need to start by specifying a profile and its components. > Moeten we hier verwijzen naar structured data?

Add aggregations / reducers

  • Mean
  • Precision / recall / ...
  • Others?
    Note: We need to implement an related SQL implementation for all the ones we support here.

Deal with components without data

When building a schema from the database, its stats can be empty and not contrast to another schema can be made for those components. Currently these will return a drift of -1, which will be shown in green, yikes! We should alert users of "No Data" instead. This should be a new type of alert actually. (invalids, drift, no data)

Use confidence interval for contrast checks

When comparing 2 stats objects we currently do not use any confidence interval or p-value check, which we should. Since p-value checks can be overly sensitive on big data sets (which we happen to have a lot of in "big data") we want to use confidence intervals. They can also make nice plots.

We can build a confidence intervals with minimal changes required in this library and the backend as follows.

  1. Numeric stats: use the Dvoretzky–Kiefer–Wolfowitz inequality (see here also)
  2. Categoric stats: Estimate the confidence interval based on the poisson distribution as described here.

We can build these confidence intervals based solely on our stats (edf / frequencies and sampel sizes).

To contrast 2 stats objects, we can simply measure the max distance between the confidence intervals instead of the observed functions.

ray.system_metrics()?

Using the statement api.system_metrics() we should be able to get and send following tags or global metrics to the backend:

  • Total memory consumption on the machine
  • GPU usage (if any)
  • Disk usage

These should be tags of type global-metric (?) and should not be attached to the ray?

using ray.process_metrics()

  • Memory usage of process (this is a ray tag)

Test FileLogger

I got errors in examples.

ingest_retinopathy_1  | Traceback (most recent call last):
ingest_retinopathy_1  |   File "process.py", line 242, in <module>
ingest_retinopathy_1  |     ray_ids = run()
ingest_retinopathy_1  |   File "process.py", line 235, in run
ingest_retinopathy_1  |     oracle.process(ray_id=ray_id, metadata=metadata)
ingest_retinopathy_1  |   File "process.py", line 141, in process
ingest_retinopathy_1  |     ray.info(f"Logging ground truth for {ray}")
ingest_retinopathy_1  |   File "/usr/local/lib/python3.7/site-packages/raymon/ray.py", line 41, in info
ingest_retinopathy_1  |     self.logger.info(ray_id=str(self), text=text)
ingest_retinopathy_1  |   File "/usr/local/lib/python3.7/site-packages/raymon/loggers.py", line 84, in info
ingest_retinopathy_1  |     self.data_logger.info(json.dumps(kafka_msg))
ingest_retinopathy_1  | AttributeError: 'RaymonFileLogger' object has no attribute 'data_logger'

ray timings

We should make it easy for users to measure elapsed time.

with ray.time("your-ref"):
    pass

and ray.time_ref(peephole="your-ref") + easy calculation of time elapsed since previous ref.

This should be added as tag to the ray.

Consequently use either `Tag` or dict

trace.tag should accept both Tag objects or dicts. We should convert them internally if needed, and only convert them to json when writing to file or API.

Allow user to specify domains before building profiles

We already have a paremeter domain on the stats objects from before. We need to re-enable calling those.

profile.build() should have a parameter domains of the form:

{
'input_components': {name: domain, name2: domain},
}

Increase testing coverage

  • Profile contrast thresholds
  • Profile domain specifications
  • Extractors
  • Serialisation / deserialisation

Extractor testing

We need basic tests for:

  • element extractor (structured)
  • intensity
  • sharpness
  • similarity

Make logging lib use ray object

  • ray == object
  • support splitting and merging
  • str == str of ray_id
  • log methods in here: need to pass context, ray_id etc only once!

Authentication overhaul

We currently only support the client_credentials flow. We also need to support a user to log in with the CLI using the device flow grant.

When available, the system should use client credentials, if not, it should try to login the user.

Do not send logs to API on every call, but send in batches

Doing an API call on every log / tag statement is fine for demo and MVP purposes, but not for real use cases.

  • Cache the log / tag / info events in the ray, and send when the ray is destroyed, or when a certain threshold is reached.
  • Make sure to send all logged data in case of an exception!

Set trace global on construction

To avoid passing the trace in al lfunctions, we should support a workflow like this:

import raymon
from raymon import Trace
trace = Trace(... ,global=True)  # default
trace2 = raymon.current_trace()

assert trace == trace2

Testing

  • Test Authentication
    • config in home dir
    • config in current dir
    • env variable
    • specified config file
  • Increase test coverage

Buggy frontend navigation

Browsing to page 2 on one component_type, and then switching pages results on showing page 2 on the new component_type page too. This may not have 2 pages.\

When switching component_types, set page to 0.

Add report checks

We should support the following metrics for all component types (input, output, actual, scores) and make it configurable which ones to check for.

  • drift
  • % invalids
  • mean
  • samplesize > 0, or big "enough"
  • difference in samplesize between component and global max

error on login

I got an error when logging in for the first time.

FileNotFoundError                         Traceback (most recent call last)
~/raymon/examples/setup_project.py in 
     19     login_env = None
     20 # api = RaymonAPI(url=f"https://api{ENV}.raymon.ai/v0", env=login_env)
---> 21 api = RaymonAPI(url=f"http://localhost:8000/v0", env=login_env)
     22 
     23 

~/opt/miniconda3/envs/retinopathy/lib/python3.8/site-packages/raymon/api.py in __init__(self, url, project_id, auth_path, env)
     17         self.token = None
     18 
---> 19         self.login()
     20 
     21     """

~/opt/miniconda3/envs/retinopathy/lib/python3.8/site-packages/raymon/api.py in login(self)
     24 
     25     def login(self):
---> 26         self.token = login(fpath=self.auth_path, project_id=self.project_id, env=self.env)
     27         self.headers["Authorization"] = f"Bearer {self.token}"
     28 

~/opt/miniconda3/envs/retinopathy/lib/python3.8/site-packages/raymon/auth/__init__.py in login(fpath, project_id, env)
     71     # If we did not find m2m credentials, let the user login interactively.
     72     try:
---> 73         token = login_user(credentials=credentials, out=fpath, env=env)
     74     except (SecretException, NetworkException) as exc:
     75         print(f"Could not login with user credentials.")

~/opt/miniconda3/envs/retinopathy/lib/python3.8/site-packages/raymon/auth/__init__.py in login_user(credentials, out, env)
     40     if not token_ok(token):
     41         token = login_device_flow(config)
---> 42     save_user_config(
     43         existing=credentials,
     44         auth_endpoint=config["auth_url"],

~/opt/miniconda3/envs/retinopathy/lib/python3.8/site-packages/raymon/auth/user.py in save_user_config(existing, auth_endpoint, audience, client_id, token, out, env)
     31     user_config[env["auth_url"]] = env_config
     32     known_configs["user"] = user_config
---> 33     with open(out, "w") as f:
     34         json.dump(known_configs, fp=f, indent=4)
     35 

FileNotFoundError: [Errno 2] No such file or directory: '/Users/emreozan/.raymon/secrets.json'
5 cells were canceled due to an error in the previous cell.

Add `Profile` class

Now we just have a ModelProfile. We could add a class Profile, that only has inputs.

pytorch -> ONNX

The pytorch dependency is huge, and only has limited value.

Let's try to replace it by ONNX, which is hopefully smaller. Alternatively, we should move the extractors that depend on pytorch to a separate package.

Add `trace.error` method

This should format the error nicely, tag the trace with the error and log the stacktrace as a trace element.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.