Обнаружение мошенничества в медицине (часть 2) — создание автоэнкодера в PyTorch

Узнайте, как обнаружить коррумпированных врачей с помощью нейронных сетей

См. Часть 1 для получения информации о сборе, очистке и предварительной обработке данных

Краткое изложение части 1

Каждый день пациенты обращаются за консультацией и помощью к врачам, но доступ к доступному медицинскому обслуживанию по-прежнему актуален. Тем, кто соответствует требованиям, правительство Соединенных Штатов предоставляет финансовую поддержку в виде программ Medicare и Medicaid. Эти программы позволяют гражданам получать качественную помощь, а врачам платят из государственного кармана. Используя общедоступные данные, можно разработать системы обнаружения аномалий, чтобы указать врачам, которые пытаются злоупотреблять системой здравоохранения или извлекать из нее выгоду.

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

PyTorch — это низкоуровневый API, ориентированный на динамические вычислительные графики. Это обеспечивает большую гибкость и настройку по сравнению с другими средами глубокого обучения.

Автоэнкодеры

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

Типичный автоэнкодер состоит из четырех частей: кодировщик, узкое место, декодер и потери при реконструкции. Кодер сводит многомерный ввод к низкоуровневому коду, который называется узким местом. На уровне узкого места декодер пытается восстановить данные из изученного кодирования. Наконец, ошибка реконструкции (RE) измеряет, насколько хорошо декодер справился с созданием выходных данных, аналогичных входным. Они используются в неконтролируемом обучении, поскольку они не выполняют обратное распространение на основе целевой метки, а на основе потерь при реконструкции.

class Ae(nn.Module):
   def __init__(self, input_size, hl1):
         super(Ae, self.__init__()
         self.encoder = nn.Sequential(
              nn.Linear(input_size, hl1),
              nn.Tanh()
         )
         self.decoder = nn.Sequential(
            nn.Linear(hl1, input_size),
            nn.Tanh()
         )

    def forward(self, x):
        x = self.encoder(x)
        x = self.decoder(x)
        return x
model = Ae(98, 12)
model = model.to(device)
# Initialize Hyperparameters
batch_size = 1000
learning_rate = 0.01
num_epochs = 10
criterion = nn.MSELoss()
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)

Созданный мной автоэнкодер имеет входной слой из 98 нейронов, один скрытый слой с 12 нейронами и выходной слой из 98 нейронов. Между слоями находится функция активации гиперболического тангенса (Tanh). Примеры в других публикациях показывают, что наиболее часто используемыми функциями активации для автоэнкодера являются ReLU, Sigmoid и Tanh. Некоторые придерживаются одной функции или используют в модели несколько. В этой статье я буду работать только с функцией Tanh. Еще одна важная характеристика, на которую следует обратить внимание, заключается в том, что входной и выходной слои имеют одинаковый размер. Автоэнкодер попытается реконструировать входные данные, используя объекты, созданные в скрытом слое. Если выходной слой похож на входной, то врач не мошенник.

Обучение/тестирование

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

history = dict()
history['train_loss'] = []
history['test_loss'] = []
pred_loss = []
for epoch in range(num_epochs):
     h = np.array([])
     loss_train = 0  
     model.train()  
     for batch in range(len(X_train)//batch_size + 1):  
         inds = slice(batch*batch_size, (batch+1)*batch_size)  
         optimizer.zero_grad()
         decoded = model(X_train[inds])
         loss = criterion(decoded, X_train[inds])
         loss.backward()
         optimizer.step()
         h = np.append(h, loss.item())
     model.eval()
     with torch.no_grad(): # Run without Autograd
         for original in X_test:
         output = model(original)  # model can't use test to learn
         test_loss = criterion(output, original).data.item()
         pred_loss.append(test_loss)

Оценка модели

После получения RE для каждого образца в тестовом наборе для присвоения меток класса требуется пороговое значение для предметной области (DST). ТЛЧ можно создать с помощью экспертов в предметной области (например, других врачей, OIG, CMS), и они, как правило, более ценны, чем простая бинарная классификация. Расстояние мошеннической точки от среднего значения нормальных точек позволяет судить о серьезности мошенничества.

recall = []
precision = []
for dst in threshold_list:
    y_pred = [1 if e > dst else 0 for e in pred_loss]
    test_recall = recall_score(y_test, y_pred, average="weighted")
    recall.append(test_recall)

Окончательные результаты показали, что выявлено более 60% врачей-мошенников. Была горстка нормальных врачей, которых заклеймили как мошенников, но это было ожидаемо.

Важно помнить, что эта статья вдохновлена ​​моим первоначальным проектом. Оригинальный проект сравнивает несколько моделей с различными скрытыми слоями.

Вывод

Алгоритмы и модели обнаружения мошенничества отмечают возможные случаи мошенничества, которые затем могут быть дополнительно расследованы такими органами, как OIG или Федеральное бюро расследований. Это объясняет, почему ложные срабатывания очень высоки для модели. Лучше ошибиться в сторону осторожности, когда на карту поставлены миллиарды долларов государственных денег. Хотя автоэнкодер выдал низкий показатель AUC, есть способы улучшить его, изменив пороговое значение, включив выпадающие слои или описав представление с использованием распределений для каждого атрибута.

Полный проект смотрите на моей странице GitHub

использованная литература

[1]​ США Правительство, Центры обслуживания Medicare и Medicaid США. Официальный сайт правительства США для Medicare

[2] Список исключенных лиц/организаций, Правительство США, Министерство здравоохранения и социальных служб США, Управление Генерального инспектора.

[3] Код PyTorch с открытым исходным кодом, Амир Джафари