Skip to content
Draft
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions medperf/model/mlcube/mlcube.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: Hello-World Medperf Model MLCube
description: MLCommons demonstration MLCube for building models for MedPerf
authors:
- {name: "MLCommons Medical Working Group"}

platform:
accelerator_count: 0

docker:
# Image name.
image: medical-hello-world
# Docker build context relative to $MLCUBE_ROOT. Default is `build`.
build_context: "../project"
# Docker file name within docker build context, default is `Dockerfile`.
build_file: "Dockerfile"

tasks:
# Model MLCubes require only a single task: `infer`.
# This task takes input data, as well as configuration parameters
# and/or extra artifacts, and generates predictions on the data
infer:
parameters:
inputs: {
data_path: names.csv, # Required. Where to find the data to run predictions on
parameters_file: parameters.yaml, # Required. Helper file to provide additional arguments. Value MUST be parameters.yaml
# If you need any additional files that should
# not be included inside the mlcube image,
# add them inside `additional_files` folder
# E.g. model weights

# Toy Hello World example
greetings: additional_files/greetings.csv
}
outputs: {
output_path: {type: file, default: predictions.csv} # Required. Where to store predictions artifact. Value MUST be predictions.csv (This will probably be an issue)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Hello
Howdy
Greetings
Bonjour
4 changes: 4 additions & 0 deletions medperf/model/mlcube/workspace/names.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
First name,Last name
Adam,Smith
John,Smith
Michael,Stevens
5 changes: 5 additions & 0 deletions medperf/model/mlcube/workspace/parameters.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Here you can store any key-value arguments that should be easily modifiable
# by external users. E.g. batch_size

# example argument for Hello World
uppercase: false
13 changes: 13 additions & 0 deletions medperf/model/mlcube/workspace/predictions.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
id,greeting
0,"Hello, Adam Smith"
1,"Hello, John Smith"
2,"Hello, Michael Stevens"
3,"Howdy, Adam Smith"
4,"Howdy, John Smith"
5,"Howdy, Michael Stevens"
6,"Greetings, Adam Smith"
7,"Greetings, John Smith"
8,"Greetings, Michael Stevens"
9,"Bonjour, Adam Smith"
10,"Bonjour, John Smith"
11,"Bonjour, Michael Stevens"
29 changes: 29 additions & 0 deletions medperf/model/project/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
FROM ubuntu:18.04
MAINTAINER MLPerf MLBox Working Group

RUN apt-get update && \
apt-get install -y --no-install-recommends \
software-properties-common \
python3-dev \
curl && \
rm -rf /var/lib/apt/lists/*

RUN add-apt-repository ppa:deadsnakes/ppa -y && apt-get update

RUN apt-get install python3 -y

RUN apt-get install python3-pip -y

COPY ./requirements.txt project/requirements.txt

RUN pip3 install --upgrade pip

RUN pip3 install --no-cache-dir -r project/requirements.txt

ENV LANG C.UTF-8

COPY . /project

WORKDIR /project

ENTRYPOINT ["python3", "mlcube.py"]
61 changes: 61 additions & 0 deletions medperf/model/project/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Hello World Script
#
# This script is unrelated to the MLCube interface. It could be run
# independently without issues. It provides the actual implementation
# of the app.
import csv
import argparse

def hello_world(greetings, names, uppercase=False):
"""Generates a combination of greetings and names

Args:
greetings (List[str]): list of greetings
names (List[str]): list of names
uppercase (bool): Wether to uppercase the whole greeting

Returns:
List[str]: combinations of greetings and names
"""
full_greetings = []

for greeting in greetings:
for name, last_name in names:
full_greeting = f"{greeting}, {name} {last_name}"
if uppercase:
full_greeting = full_greeting.upper()
full_greetings.append(full_greeting)

return full_greetings


if __name__ == '__main__':
parser = argparse.ArgumentParser("MedPerf Model Hello World Example")
parser.add_argument('--names', dest="names", type=str, help="file containing names. CSV expected")
parser.add_argument('--uppercase', dest="uppercase", type=bool, help="wether to return uppercase greetings")
parser.add_argument('--greetings', dest="greetings", type=str, help="file containing greetings. CSV expected")
parser.add_argument('--out', dest="out", type=str, help="file to store resulting greetings")

args = parser.parse_args()

names = []
greetings = []

with open(args.names, "r") as f:
reader = csv.reader(f)
next(reader) # skip header
for row in reader:
names.append(row)

with open(args.greetings, "r") as f:
reader = csv.reader(f)
for row in reader:
greetings.append(row[0])

full_greetings = hello_world(greetings, names, args.uppercase)

with open(args.out, "w") as f:
writer = csv.writer(f)
writer.writerow(["id", "greeting"])
for idx, full_greeting in enumerate(full_greetings):
writer.writerow([idx, full_greeting])
54 changes: 54 additions & 0 deletions medperf/model/project/mlcube.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# MLCube Entrypoint
#
# This script shows how you can bridge your app with an MLCube interface.
# MLCubes expect the entrypoint to behave like a CLI, where tasks are
# commands, and input/output parameters and command-line arguments.
# You can provide that interface to MLCube in any way you prefer.
# Here, we show a way that requires minimal intrusion to the original code,
# By running the application through subprocesses.

import yaml
import typer
import subprocess

app = typer.Typer()

def exec_python(cmd: str) -> None:
"""Execute a python script as a subprocess

Args:
cmd (str): command to run as would be written inside the terminal
"""
splitted_cmd = cmd.split()
process = subprocess.Popen(splitted_cmd, cwd=".")
process.wait()

@app.command("infer")
def infer(
data_path: str = typer.Option(..., "--data_path"),
params_file: str = typer.Option(..., "--parameters_file"),
greetings: str = typer.Option(..., "--greetings"),
out_path: str = typer.Option(..., "--output_path")
):
"""infer task command. This is what gets executed when we run:
`mlcube run infer`

Args:
data_path (str): Location of the data to run inference with. Required for Medperf Model MLCubes.
params_file (str): Location of the parameters.yaml file. Required for Medperf Model MLCubes.
greetings (str): Example of an extra parameter that uses `additional_files`.
out_path (str): Location to store prediction results. Required for Medperf Model MLCubes.
"""
with open(params_file, "r") as f:
params = yaml.safe_load(f)

uppercase = params["uppercase"]
cmd = f"python3 app.py --names={data_path} --uppercase={uppercase} --greetings={greetings} --out={out_path}"
exec_python(cmd)

@app.command("hotfix")
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would explain that this is a workaround for the "typer" module (could be with the "click" module that typer uses).

def hotfix():
pass

if __name__ == "__main__":
app()
2 changes: 2 additions & 0 deletions medperf/model/project/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pyYAML
typer