Классификация 12 видов микробов с помощью библиотеки fast.ai
Проблема: идентификация микробов с помощью световой микроскопии может занять много времени и требует хорошо подготовленных микробиологов. Может ли алгоритм глубокого обучения успешно различать 12 различных классов микробов?
Данные: DIBaS (http://misztal.edu.pl/software/databases/dibas/)
Полный набор данных содержит 660 изображений 33 различных родов и видов. В качестве доказательства концептуального проекта сегодня я буду работать только с 12 различными классами: Acinetobacter baumanii, Actinomyces israelii, Bacteroides fragilis, Candida albicans, Clostridium perfringens, Enterococcus faecalis, Escherichia coli, Listeria monocytogenes, Neisseaeria gonorrhoe spp., Pseudomonas aeruginosa, Staphylococcus aureus
Я выбрал эти 12, поскольку они являются одними из наиболее значимых с медицинской точки зрения микробов в наборе данных.
Каждый класс включает примерно 20 изображений с разрешением 2048 x 1532 пикселей. Образцы окрашивали по Граму и оценивали с использованием 100-кратного объектива в масляной иммерсии. Изображения были получены с помощью микроскопа Olympus CX31, оснащенного камерой SC30.
Настройка:
- Блокнот Jupyter с библиотекой fasti.ai v1
- Модель ResNet-50
- NVIDIA RTX 2060 6 ГБ
Результат: точность 99,6%.
Часть 1. Обработка изображений
Я решил разбить изображения на более мелкие блоки, так как исходный размер 2048 x 1532 довольно велик. Например, взгляните на исходное изображение ниже. Микробы физически малы, и если мы изменим их размер до 224 x 224, важные детали, такие как края и скопления, могут быть потеряны.
Я написал специальную функцию, чтобы разбить изображение на блоки 224 x 224.
def process_image(im): imarray = np.array(im) im_h, im_w = imarray.shape[:2] block_h, block_w = 224, 224 for row in np.arange(im_h - block_h +1, step = block_h): for col in np.arange(im_w - block_w +1, step = block_w): im1 = imarray[row:row+block_h, col:col+block_w, :] im1 = Image.fromarray(im1) global i global path im1.save(path + "\img" + f"{i}" + ".png") i+=1 print("completed")
Я запустил код для каждого класса, при необходимости изменив имя папки.
from PIL import Image import numpy as np import os i=0 path = r"C:\bacteria\Staphylococcus.aureus\edited" for file in os.listdir(r"C:\bacteria\Staphylococcus.aureus\raw"): filename = r"C:\bacteria\Staphylococcus.aureus\raw" + f"\{file}" im = Image.open(filename) process_image(im)
Конечный продукт выглядит так:
На большинстве исходных изображений микробы равномерно распределены по слайду. Однако слайды для некоторых классов, таких как Candida, менее однородны и содержат пустые области. Чтобы решить эту проблему, я просмотрел конечные продукты и вручную удалил пустые слайды.
Теперь мы готовы к построению модели и обучению.
Часть 2: Обучение
Сначала импортируем необходимые модули.
from fastai.tabular import * from fastai.vision import * path = r"C:\bacteria\data"
Моя структура папок: родительская папка (C: \ бактерии \ данные) → подпапки с именами классов (C: \ бактерии \ данные \ кандида) → изображения
np.random.seed(42) data = ImageDataBunch.from_folder(path, valid_pct=0.2, ds_tfms=get_transforms(), size=224, num_workers=4, bs=32).normalize(imagenet_stats) data.classes, data.c, len(data.train_ds), len(data.valid_ds)
У нас есть 12 различных классов с 10234 обучающими изображениями и 2558 проверочными изображениями.
learn = cnn_learner(data, models.resnet50, metrics=accuracy).to_fp16()
Fasti.ai поддерживает обучение со смешанной точностью, и это так же просто, как добавить .to_fp16 () при создании учащегося. Для тех, у кого есть графические карты NVIDIA RTX, смешанная точность значительно ускоряет обучение и вдвое снижает потребность в памяти. У Эрика есть отличная статья по этому поводу, и вы можете прочитать ее здесь: https://towardsdatascience.com/rtx-2060-vs-gtx-1080ti-in-deep-learning-gpu-benchmarks-cheapest-rtx-vs-most -дорогой-gtx-card-cd47cd9931d2
learn.fit_one_cycle(4)
Результаты уже выглядят неплохо даже без тренировки верхних слоев. Теперь мы разморозим верхние слои и найдем подходящую скорость обучения.
learn.unfreeze() learn.lr_find() learn.recorder.plot()
Я обучил всю модель дальше с пониженной скоростью обучения.
learn.fit_one_cycle(10, max_lr=slice(7e-5, 9e-4))
В конце 10 эпох мы достигли точности 99,6%. Нет значительного переобучения, поскольку потери при обучении и проверке одинаковы. Давайте посмотрим на матрицу путаницы.
interp = ClassificationInterpretation.from_learner(learn) interp.plot_confusion_matrix(figsize=(10,10), dpi=100)
Основные ошибки, по-видимому, связаны с протеусом против псевдомонад и кишечной палочкой против протеуса. Это понятно, поскольку все 3 вида представляют собой грамотрицательные палочки, которые окрашиваются и выглядят одинаково под световым микроскопом. Давайте посмотрим на изображения с наибольшими потерями.
interp.plot_top_losses(6, figsize=(15,15))
В заключение, мы достигли замечательной точности 99,6% в этой довольно сложной задаче. На самом деле, я довольно удивлен производительностью, так как визуально отличить некоторые классы чрезвычайно сложно. Например, вы можете определить стафилококк. aureus и Enterococcus. fecalis отдельно?
Возможно, модель изучает особенности, которые я еще не осознал, и необходима дальнейшая работа для улучшения «объяснимости» этой модели.
Спасибо за прочтение!