diff --git a/extensions/chaeo/examples/transfer_labels_to_ilastik_object_classifier.py b/extensions/chaeo/examples/transfer_labels_to_ilastik_object_classifier.py
index 9e07ec2b454f475c6dda1b024ea96bb101cd42ff..d780b4a57a938073b121415e787ea59c576afd0b 100644
--- a/extensions/chaeo/examples/transfer_labels_to_ilastik_object_classifier.py
+++ b/extensions/chaeo/examples/transfer_labels_to_ilastik_object_classifier.py
@@ -6,47 +6,11 @@ import numpy as np
 import pandas as pd
 import skimage
 import uuid
-import vigra
 
-from extensions.chaeo.accessors import MonoPatchStack, MonoPatchStackFromFile
-from extensions.ilastik.models import IlastikObjectClassifierFromSegmentationModel
-from model_server.accessors import generate_file_accessor, GenericImageDataAccessor, InMemoryDataAccessor, write_accessor_data_to_file
+from extensions.chaeo.accessors import MonoPatchStackFromFile
+from extensions.chaeo.models import PatchStackObjectClassifier
+from model_server.accessors import generate_file_accessor, GenericImageDataAccessor, write_accessor_data_to_file
 
-class PatchStackObjectClassifier(IlastikObjectClassifierFromSegmentationModel):
-    """
-    Wrap ilastik object classification for inputs comprising raw image and binary segmentation masks, both represented
-    as time-series images where each frame contains only one object.
-    """
-
-
-    def infer(self, input_acc: MonoPatchStack, segmentation_acc: MonoPatchStack) -> (np.ndarray, dict):
-        assert segmentation_acc.is_mask()
-        assert input_acc.chroma == 1
-
-        tagged_input_data = vigra.taggedView(input_acc.make_tczyx(), 'tczyx')
-        tagged_seg_data = vigra.taggedView(segmentation_acc.make_tczyx(), 'tczyx')
-
-        dsi = [
-            {
-                'Raw Data': self.PreloadedArrayDatasetInfo(preloaded_array=tagged_input_data),
-                'Segmentation Image': self.PreloadedArrayDatasetInfo(preloaded_array=tagged_seg_data),
-            }
-        ]
-
-        obmaps = self.shell.workflow.batchProcessingApplet.run_export(dsi, export_to_array=True)  # [z x h x w x n]
-
-        assert len(obmaps) == 1, 'ilastik generated more than one object map'
-
-        # for some reason ilastik scrambles these axes to Z(1)YX(1)
-        assert obmaps[0].shape == (input_acc.nz, 1, input_acc.hw[0], input_acc.hw[1], 1)
-        yxcz = np.moveaxis(
-            obmaps[0][:, :, :, :, 0],
-            [2, 3, 1, 0],
-            [0, 1, 2, 3]
-        )
-
-        assert yxcz.shape == input_acc.shape
-        return InMemoryDataAccessor(data=yxcz), {'success': True}
 
 def get_dataset_info(h5: h5py.File, lane : int = 0):
     """
diff --git a/extensions/chaeo/models.py b/extensions/chaeo/models.py
new file mode 100644
index 0000000000000000000000000000000000000000..5900134e42fe41b66f9c14574d0168f3f54fd1b0
--- /dev/null
+++ b/extensions/chaeo/models.py
@@ -0,0 +1,43 @@
+import numpy as np
+import vigra
+
+from extensions.chaeo.accessors import MonoPatchStack
+from extensions.ilastik.models import IlastikObjectClassifierFromSegmentationModel
+from model_server.accessors import InMemoryDataAccessor
+
+
+class PatchStackObjectClassifier(IlastikObjectClassifierFromSegmentationModel):
+    """
+    Wrap ilastik object classification for inputs comprising raw image and binary segmentation masks, both represented
+    as time-series images where each frame contains only one object.
+    """
+
+
+    def infer(self, input_acc: MonoPatchStack, segmentation_acc: MonoPatchStack) -> (np.ndarray, dict):
+        assert segmentation_acc.is_mask()
+        assert input_acc.chroma == 1
+
+        tagged_input_data = vigra.taggedView(input_acc.make_tczyx(), 'tczyx')
+        tagged_seg_data = vigra.taggedView(segmentation_acc.make_tczyx(), 'tczyx')
+
+        dsi = [
+            {
+                'Raw Data': self.PreloadedArrayDatasetInfo(preloaded_array=tagged_input_data),
+                'Segmentation Image': self.PreloadedArrayDatasetInfo(preloaded_array=tagged_seg_data),
+            }
+        ]
+
+        obmaps = self.shell.workflow.batchProcessingApplet.run_export(dsi, export_to_array=True)  # [z x h x w x n]
+
+        assert len(obmaps) == 1, 'ilastik generated more than one object map'
+
+        # for some reason ilastik scrambles these axes to Z(1)YX(1)
+        assert obmaps[0].shape == (input_acc.nz, 1, input_acc.hw[0], input_acc.hw[1], 1)
+        yxcz = np.moveaxis(
+            obmaps[0][:, :, :, :, 0],
+            [2, 3, 1, 0],
+            [0, 1, 2, 3]
+        )
+
+        assert yxcz.shape == input_acc.shape
+        return InMemoryDataAccessor(data=yxcz), {'success': True}
\ No newline at end of file