Использование fast.ai для диагностики COVID-19 по рентгену грудной клетки

Мир продолжает сталкиваться с беспрецедентным кризисом в области здравоохранения, вызванным COVID-19. В то время как первоначальные горячие зоны, как правило, вновь взяли под свой контроль строгую социальную дистанцию ​​и использование масок, новые вспышки продолжают экспоненциально расти, особенно в Соединенных Штатах. Поскольку федеральные, государственные и местные органы власти продолжают бороться в перетягивании каната между возобновлением работы экономики и сохранением здоровья и безопасности своих граждан, необходимо преодолеть огромные проблемы, прежде чем мир сможет вернуться в состояние безопасности, в первую очередь начиная с рабочей вакцины. Медицинские работники должны продолжать работать в напряженном режиме, справляясь с всплеском случаев, выходящих за рамки нормы, которые превышают возможности отделений интенсивной терапии, средства индивидуальной защиты и моральный дух работников на передовой.

Несмотря на то, что прошло столетие после испанского гриппа 1918 года, меня удивило то, сколь схожие трудности мы сталкиваемся сегодня, несмотря на наши огромные достижения в области здравоохранения и современных технологий. У меня нет опыта работы в области медицины, но, поскольку я интересовался машинным обучением и искусственным интеллектом (ИИ), я хотел поэкспериментировать, чтобы увидеть, как такие методы потенциально могут быть использованы для помощи в текущем кризисе. Недавно я изучил и завершил программу fast.ai и решил попробовать небольшой проект по созданию модели, которая могла бы считывать рентгеновский снимок пациента и предсказывать, есть ли у него коронавирус.

Цель

Моя главная цель в этой статье — продемонстрировать простое применение fast.ai и побудить вас окунуться в увлекательный мир машинного обучения / ИИ! Хотя базовая механика выполнения кода может быть довольно сложной, я сосредоточусь на предоставлении ключевой информации, которую сможет понять нетехнический специалист, и в конечном итоге оставлю ее открытой для вас, чтобы вы могли ее адаптировать и улучшить. В конце статьи я надеюсь, что вы сможете лучше понять и заинтересоваться применением машинного обучения и использовать приведенный ниже код в своих собственных моделях.

Машинное обучение одновременно широкое и глубокое — существует множество направлений машинного обучения, которые также имеют свои специфические ниши и нюансы. Однако любой инженер данных скажет вам, что не алгоритмы или точная настройка занимают больше всего времени или оказывают наибольшее влияние, а сами данные. Без должным образом очищенных релевантных данных ваши модели, скорее всего, никогда не придут к оптимальным решениям, прогнозам или результатам, и поэтому обработка данных является одним из самых важных шагов, который часто упускается из виду. Это похоже на строительство дома без фундамента — вы можете заставить часть дома стоять, но без прочного фундамента конструкция не будет прочной и не выдержит условий вне солнечного безветренного дня, независимо от того, насколько скотч, который вы используете, чтобы держать его вместе.

К счастью, с ростом и развитием ресурсов машинного обучения для использования доступны тысячи общедоступных наборов данных, а также программные платформы для выполнения таких операций с использованием Python. Одним из самых популярных является Kaggle, который предлагает как множество наборов данных, так и позволяет легко получать доступ к данным и выполнять код. Другой вариант — Paperspace, который я использую в модели ниже. Оба работают с использованием Jupyter Notebooks, что является одним из самых простых способов написания и выполнения кода на Python.

Шаг 1: Получение наборов данных и определение цели модели

Для начальной модели я решил использовать набор данных здесь на Kaggle, который содержит ссылки и источники для исследования. В частности, я выбрал этот набор данных в качестве надежной отправной точки из-за того, что данные уже были отформатированы по трем категориям: здоровые, пневмония и COVID-19, а изображения были переформатированы в размер, идеальный для машинного обучения. Одной из проблем с набором данных является отсутствие данных о COVID-19 по сравнению с двумя другими категориями, и в будущем я хотел бы использовать более крупный набор данных с большим количеством данных о COVID-19 для обучения модели.

Хотя существует несколько способов извлечения данных в зависимости от платформы (Kaggle или Paperspace) и от того, знакомы ли вы с API, я просто загрузил набор данных и сохранил каждую категорию в ZIP-папке. Затем я начал загружать каждую папку в каталог /storage моего экземпляра Paperspace. Теперь мы готовы приступить к кодированию!

Шаг 2: Кодирование :)

Настраивать

Для тех, кто не знаком с Python, вы обычно импортируете любые библиотеки, которые планируете использовать. Библиотека — это набор инструментов/пакетов, которые обеспечивают дополнительную функциональность Python, и многие из них имеют решающее значение даже для базовых функций Python. Так как эта модель базовая, нам нужны только fast.ai и zipfile, которые помогают распаковать только что загруженные файлы.

from fastai.vision import * import zipfile

Для каждой из папок, которые мы добавили в Paperspace, теперь нам нужно распаковать их.

with zipfile.ZipFile('/storage/pneumonia/PNEUMONIA.zip', 'r') as zip_ref: zip_ref.extractall('/storage/pneumonia')

Этот код распаковывает папки, создавая новую папку в том же каталоге, который содержит все файлы .img. Напоминаем, что вам нужно запустить этот код 3 раза, по одному для каждой папки. Это должно выглядеть примерно так, с папкой для каждой категории (мины называются covid-19, normal и pneumonia):

Мы также объявим переменную пути, которая будет часто использоваться (различается в зависимости от соглашений об именах и места, где вы разместили свои файлы):

path = Path('data/dataxray')

Затем мы назначаем классы на основе наших данных, которые в данном случае являются тремя доступными в этом наборе данных:

classes = ['pneumonia','covid-19', 'normal']

Для тех, кто привыкает к машинному обучению, предварительный просмотр данных часто является отличным упражнением. Следующий фрагмент кода может показаться немного пугающим, но это довольно стандартный код котла. Эта страница от fast.ai предоставляет более подробную информацию, если вы хотите понять, почему и что делает каждый параметр, и как вы можете изменить их для своих нужд, но мы используем функцию fast.ai для создания ImageDataBunch, используя данные из папок.

Одним из основных моментов является то, что этот код создает для вас наборы для обучения и проверки, которые модель в основном использует для обучения. В других библиотеках вам часто приходится объявлять и определять два набора с помощью нескольких дополнительных строк кода, но здесь все аккуратно упаковано в несколько строк!

np.random.seed(42) data = ImageDataBunch.from_folder(path, train=".", valid_pct=0.2, ds_tfms=get_transforms(), size=224, num_workers=4).normalize(imagenet_stats)

Следующий фрагмент кода показывает изображения в сетке 3x3, чтобы можно было легко увидеть, как на самом деле выглядят данные. Как мы видим, рентгеновские фотографии выглядят довольно похожими друг на друга, но плотность/форма пикселей различаются в зависимости от класса. Короче говоря, модель CNN, которую мы обучаем позже, разбивает отдельные пиксели на шаблоны, чтобы отличать каждый класс друг от друга и определять, к какому классу, вероятно, принадлежит рентгеновский снимок.

Важно отметить, что мы никогда не хотим, чтобы все наши данные были точно идентичными по структуре и формату — в наборе данных могут и должны быть небольшие отклонения, чтобы модель стала достаточно надежной, чтобы принимать различные конфигурации изображения и при этом давать точные результаты. . Как видите, третий рентгеновский снимок имеет голубоватый оттенок, но модель будет достаточно надежной, чтобы понять и определить результат, включая небольшие отклонения, подобно тому, как кто-то учится на выбросах и понимает, что могут быть элементы, выходящие за рамки нормы.

data.show_batch(rows=3, figsize=(7,8))

Обучение

Это самая интересная часть, где мы действительно применяем обучение к нашей модели и наблюдаем, как она растет! Выбор подхода здесь зависит от набора данных, который вы используете, а также от того, какую цель вы хотите решить. Поскольку мы делаем классификацию с изображениями, отличной моделью является нейронная сеть. Существуют разные нейронные сети, но мы будем использовать CNN или свёрточную нейронную сеть.

Вот статья о различных моделях, доступных сегодня, но лучший способ подумать над этой дилеммой — это пазлы с формами, которые дают детям. Квадрат не помещается в круглое отверстие, и это аналогия выбора вашего подхода на основе вашего набора данных и цели. Несоответствие модели обучения вашим данным и цели не даст желаемых результатов.

Приведенный ниже код также является согласованным шаблоном fast.ai с использованием подхода CNN. Использование resnet50 может обеспечить лучшие результаты за счет более высокой вычислительной мощности. Есть дополнительные параметры, но мы используем значения по умолчанию для большинства из них, за исключением приведенных ниже.

learn = cnn_learner(data, models.resnet34, metrics=error_rate)

Важным элементом в создании эффективной модели является скорость обучения. Как следует из названия, это положительное значение определяет, насколько быстро модель обучается, и, несмотря на первоначальное убеждение, более высокая скорость обучения не всегда лучше. Прочтите здесь для получения дополнительной информации об обучении, но чтобы определить оптимальную скорость обучения для вашей модели, запустите код ниже:

learn.lr_find()

Который находит скорость обучения, а затем рисует его:

learn.recorder.plot()

Читая график, ось Y — это потери, а ось X — скорость обучения. По мере увеличения скорости обучения потери обычно увеличиваются, но должна быть основная область, где наклон на какое-то время снижается, а затем повышается. Это диапазон скорости обучения, которым вы должны ограничить свою модель для достижения наилучших результатов. Как мы видим ниже, это примерно происходит между 1e^-04 и 1e-03, поэтому мы ограничим нашу скорость обучения этим диапазоном.

Приведенный ниже код запускает 5 циклов обучения в так называемые эпохи. Каждая эпоха, по сути, представляет собой итерацию обучения, что-то вроде школьного обучения ребенка. То, что они изучают в предыдущей ступени/эпохе, они переносят в следующую эпоху. Однако это может быть сложно, так как различные вариации могут повлиять на модель, например, привести к чрезмерной или недостаточной подгонке или просто к неточным результатам. Чтобы узнать больше об интерпретации различных значений и определении того, является ли модель более или менее подходящей, прочитайте здесь.

learn.fit_one_cycle(5, max_lr=slice(1e-4,1e-3))

В идеале мы ожидаем, что эпоха 0 будет немного отставать, поскольку модель еще не обучена и не обучена, и поэтому следует запустить как минимум 4-5 эпох, прежде чем делать первоначальные выводы о необходимости тонкой настройки. Результаты эпохи 0 здесь на самом деле не так уж плохи, с error_rate 18%, но мы видим, что к эпохе 4 error_rate составляет всего 5%, что является большим запасом улучшения.

Также важно отметить, что значения valid_loss и train_loss довольно близки, что также идеально. Если train_loss или valid_loss значительно и последовательно отличаются, это означает переподгонку или подгонку модели, что приведет к неточным результатам с новыми данными изображения. Для этого конкретного прогона нет никаких явных отклонений между тренировочным и проверочным набором.

Интерпретировать

Теперь, когда у нас есть обученная модель с хорошими первоначальными результатами, пришло время изучить результаты и протестировать модель! Во-первых, мы должны продолжить и сохранить нашу модель в ее текущем состоянии, что сохраняет ее обучение в определенный момент времени. Например, если вы добавите новые неверные данные, сохранение позволит вам вернуться к предыдущей версии и при необходимости переобучить ее, используя более качественные данные.

learn.save('stage-001')

Затем мы загрузим нашу сохраненную модель и интерпретируем результаты с помощью матрицы путаницы. Это простой график, который показывает, что предсказала модель и правильно ли она это сделала. В идеале мы хотим, чтобы результаты были по диагонали, что является правильным предположением.

interp = ClassificationInterpretation.from_learner(learn) interp.plot_confusion_matrix()

Как мы видим, наши результаты были фантастическими с текущей моделью. Он смог точно предсказать изображение в правильном классе всего с несколькими промахами, большинство из которых предсказало, что у пациента были здоровые легкие, хотя на самом деле у него была пневмония. Вероятно, это проблема из-за размера данных, а большее количество данных должно обеспечить более надежную обработку изображений.

Контрольная работа

Теперь, когда у нас есть убедительные доказательства того, что наша модель работает, мы должны протестировать ее, используя данные, которые модель никогда не видела, и экспортировать модель в наш каталог:

learn.export()

Я пошел дальше и добавил тестовую папку в свой Paperspace, погуглил фотографии рентгеновских снимков пациентов со здоровыми легкими, COVID-19 или пневмонией и ввел приведенный ниже код, который открывает загруженное изображение и сохраняет его в переменной с именем изображение В приведенном ниже примере показан рентгеновский снимок COVID-19, который обученная нами модель никогда не видела, но мы знаем, что это пациент с COVID-19.

img = open_image(path/'test'/'COVID-19 (109).png') img

learn = load_learner(path)

Теперь момент истины. Мы подключаем файл img к нашей модели, которая вернет свой прогноз как один из трех классов в качестве переменной pred_class:

Для изображения выше, которое было COVID-19, модель также ответила COVID-19. Ура! Вместе мы просто создаем модель CNN, которая была обучена оценивать рентгеновский снимок и прогнозировать между тремя классами с точностью 95%!

Резюме

  • Предварительная обработка данных — один из самых важных шагов в любой модели машинного обучения. Убедитесь, что у вас есть четкое представление о ваших данных, их сильных и слабых сторонах, а также о том, какие модели лучше всего подходят для них.
  • fast.ai предлагает хорошие результаты из коробки с относительно небольшим количеством строк кода, но более продвинутые модели могут потребовать дополнительной тонкой настройки и настройки параметров.
  • При использовании нейронных сетей обязательно запускайте по крайней мере 4–5 эпох для базовой линии и следите за потерями при проверке и обучении на предмет потенциальной недостаточности/переоснащения.
  • Даже если ваши результаты кажутся хорошими, не забудьте адекватно протестировать свою модель с новыми данными, которые она никогда не видела, и посмотреть, как она работает.

Другие мысли/улучшения

Как вы видели, объем кода, который мы использовали, был относительно небольшим. Большинство людей слышат слова «нейронная сеть» и представляют себе сотни строк кода, но fast.ai способен добиться качественных результатов с минимальными настройками. Однако, несмотря на то, что эта модель кажется эффективной, есть много способов улучшить ее. Я бы порекомендовал вам попробовать выполнить некоторые из следующих действий самостоятельно или посмотреть, есть ли другие модели, которые вы можете применить для оценки набора данных изображения:

  1. Найдите большие наборы данных, чтобы еще больше повысить надежность модели
  2. Определение оптимизаций при точной настройке модели
  3. Диагностировать другие повреждения, видимые на рентгенограммах (переломы, разрывы, дегенерация)
  4. Разверните свою модель на веб-сайте, где пользователь может загружать изображения и просматривать результаты модели на основе загруженного элемента.

Варианты машинного обучения практически безграничны, и есть много других подходов, которые вы можете использовать в своем путешествии по машинному обучению. Хотя я старался сделать описания довольно поверхностными для удобочитаемости и оставил обозначения для документации, где также упоминается большая часть приведенного выше кода, не стесняйтесь, дайте мне знать, если у вас есть какие-либо вопросы или пища для размышлений!

Отказ от ответственности: эта модель не предназначена для использования в диагностических целях, а исключительно для обучения/образования. Если у вас есть симптомы, обратитесь к врачу и не полагайтесь на эту модель для постановки диагноза.

Первоначально опубликовано на https://www.linkedin.com.