How to convert a Piximi classification model for use outside Piximi#

An obvious downside of running your analysis in your browser is that the amount of data you are running needs to all fit in your browser (for now!). You might therefore choose to train a Piximi classifier on a subset of your data, and then export the model to use elsewhere.

The notebook below can be used to convert a Piximi model file to run in Tensorflow in Python. Happy classifying!

Step by step walkthrough#

Change the parameters in the cell below#

input_json_name = '../BBBC013NoCropYesRescale/SimpleCNN.json' # the name of the Piximi json file
needs_conversion = False # Do you need to create a Python-compatible h5 file, or have you already done so?
should_rescale = True # Should the file be min-max rescaled before inference? 
output_h5_name = '../BBBC013NoCropYesRescale/SimpleCNN.h5' # The name you want to use for the keras model file
files_to_run = '../PiximiConvertUnRescaled2Chan/*.tiff' # A glob to pass in to find the files you want to run inference on
return_named_list = True #If True, returns a list with class names rather than an array of classes. Requires setting class_labels below
class_labels = ['CytoplasmicGFP','NoGFP','NuclearGFP'] # the class labels you used in Piximi, in order. Not used if return_name_list is False

Then simply run the rest of the cells#

#!pip install tensorflow tensorflowjs skimage
import tensorflow as tf
import skimage
import numpy
import glob
if needs_conversion:
    !tensorflowjs_converter \
        --input_format=tfjs_layers_model \
        --output_format=keras \
        {input_json_name} \
        {output_h5_name}
piximi_model=tf.keras.models.load_model(output_h5_name)
piximi_model.summary()

If you’re comfortable applying tensorflow models, that’s it, you’re done! If not, we’ve provided some convenience functions for you#

def load_image(imname,reorder,rescale,inputdim):
    im = skimage.util.img_as_float(skimage.io.imread(imname))
    if reorder:
        im = numpy.moveaxis(im,0,-1)
    if rescale:
        im = skimage.exposure.rescale_intensity(im)
        """newim = numpy.zeros(im.shape)
        for ch in range(im.shape[-1]):
            newim[:,:,ch]=skimage.exposure.rescale_intensity(im[:,:,ch])
        im = newim"""
    return skimage.transform.resize_local_mean(im,[inputdim[1],inputdim[2],inputdim[3]])


def prepare_for_classification(image_list,loaded_model,reorder,rescale):
    imlist = []
    dims = loaded_model.input_shape
    for im in image_list: #resize each one, not after, because weird behavior happens
        imlist.append(load_image(im,reorder,rescale,dims))
    return numpy.array(imlist)

def return_classification(image_list,loaded_model,rescale=True,list_of_class_names=False, class_labels=False):
    reorder = loaded_model.input_shape[3] not in [1,3]
    prediction_array = prepare_for_classification(image_list,loaded_model,reorder,rescale)
    probabilities = loaded_model.predict(prediction_array)
    classes = probabilities.argmax(axis=-1)
    if list_of_class_names != False:
        class_name_dict ={class_labels.index(x):x for x in class_labels}
        classes = list(numpy.vectorize(class_name_dict.get)(classes))
    return classes
files = glob.glob(files_to_run,recursive=True)
files.sort()
classes = return_classification(files,piximi_model,rescale=should_rescale,list_of_class_names=return_named_list,class_labels=class_labels)
if return_named_list:
    for x in class_labels:
        print(x,classes.count(x))
else:
    print(numpy.unique(classes,return_counts=True))
for x in range(len(files)):
    print(f"File {files[x]} predicted as {classes[x]}")