- PVSM.RU - https://www.pvsm.ru -
Привет дорогой друг, ты всегда хотел попробовать машинное обучение, но область выглядела загадочно и сложно? Я хотел бы поделиться с тобой моей историей как я сделал первые шаги в машинном обучении, при нулевом знании Python и высшей математики на небольшом примере.
Решил раз есть такая возможность, то попробовать коснуться темы Машинного обучения, поскольку это стильно, модно и молодежно. Из предыдущий познаний в данной теме у меня были только пара презентаций от ведущего разработчика, которые имели скорее популяризаторский нежели информационный оттенок.
Я определил конкретную проблему чтобы решить ее с помощью машинного обучения и начал копать. Хочу заметить, что имея конечную цель было легче ориентироваться в потоке информации.
Первым делом я отправился на официальный сайт TensorFlow и прочитал ML for Beginners [1] и TensorFlow for beginners [2]. Материалы на английском.
TensorFlow это поделка команды Google и наиболее популярная библиотека для работы с машинным обучением, которая поддерживает Python, Java, C++, Go, а также возможность использования вычислительных мощностей графической видеокарты для расчетов сложных нейросетей.
В своих поисках я нашел еще одну библиотеку для машинного обучения Scikit-learn [3]ориентированную на Python. Плюс этой библиотеки, в большом количестве алгоритмов для машинного обучения прямо из коробки, что было несомненным плюсом в моем случае, так как презентация в пятницу и очень хотелось продемонстрировать рабочую модель.
В поисках готовых примеров я наткнулся на туториал [4] по определению языка на котором написан текст с помощью Scikit-learn.
Итак, моей задачей было обучить модель определять наличие SQL инъекции в текстовой строке. (Конечно, можно решить эту задачу с помощью регулярных выражений, но в образовательных целях можно по воробьям стрелять из пушки)
Тип задачи который я пытаюсь решить это классификация. То есть алгоритм должен в ответ на вскормленные данные выдать мне к какой из категорий эти данные относятся.
Данные в которых алгоритм будет искать закономерности называются features.
Категория к которой относится та или иная feature называется label. Важно отметить, что входные данные могут иметь несколько features, но всего один lable.
В классическом примере машинного обучения — определения разновидностей цветков ириса по длине пестиков и тычинок, каждый отдельный столбец с информацией о размере это feature, а последний столбец, который означает к какому из подвидов ириса относится цветок с такими значениями это label
Способ которым я буду решать проблему классификации это supervised learning, или обучение под надзором. Это значит, что в процессе обучения алгоритм будет получать и features и labels.
Шаг номер один в решении любой задачи с помощью машинного обучения это сбор данных, на которых эта самая машина и будет учится. В идеальном мире это должны быть реальные данные, но, к сожалению, в интернете я не смог найти ничего что бы меня удовлетворило. Решено было сгенерировать данные самостоятельно.
Я написал скрипт, который генерировал случайные адреса электронной почты и SQL инъекции. В итоге в моем csv файле получалось три типа данных: случайные имейлы (20 тыс.), случайные имейлы с SQL инъекцией (20 тыс.) и чистые SQL инъекции (10 тыс.). Выглядело это примерно вот так:
Теперь исходные данные нужно считать. Функция возвращает лист X в котором содержатся features, лист Y в котором содержатся labels для каждой feature и лист label_names, который просто содержит текстовое определения для labels нужен для удобства при выводе результатов.
import csv
def get_dataset():
X = []
y = []
label_names = ["safe data","Injected email"]
with open('trainingSet.csv') as csvfile:
readCSV = csv.reader(csvfile, delimiter='n')
for row in readCSV:
splitted = row[0].split(',')
X.append(splitted[0])
y.append(splitted[1])
print("nnData set features {0}". format(len(X)))
print("Data set labels {0}n". format(len(y)))
print(X)
return X, y, label_names
Далее эти данные нужно разбить на тренировочный сет и на тестовый. В этом нам поможет заботливо написанная для нас функция cross_validation.train_test_split(), которая перетасует записи и вернет нам четыре сета данных — два тренировочных и два тестовых для features и labels.
# Split the dataset on training and testing sets
X_train, X_test, y_train, y_test = cross_validation.train_test_split(X,y,test_size=0.2,random_state=0)
Затем мы инициализируем объект vectorizer, который будет считывать переданные в него данные по одному символу, комбинировать их в N-граммы [5] и переводить в числовые векторы, который способен воспринимать алгоритм машинного обучения
#Setting up vectorizer that will convert dataset into vectors using n-gram
vectorizer = feature_extraction.text.TfidfVectorizer(ngram_range=(1, 4), analyzer='char')
Следующий шаг мы инициализируем pipeline и передадим в него ранее созданный vectorizer и алгоритм, которым мы хотим анализировать наш дата сет. В данном мы будем использовать алгоритм логистической регрессии.
#Setting up pipeline to flow data though vectorizer to the liner model implementation
pipe = pipeline.Pipeline([('vectorizer', vectorizer), ('clf', linear_model.LogisticRegression())])
Модель готова к обучению. Теперь просто передаем тренировочные сеты features и labels в наш pipeline и модель начинает обучение. Следующей строкой мы пропускаем тестовый сет features через pipeline, но теперь мы используем predict, чтобы получить число правильно угаданных данных.
#Pass training set of features and labels though pipe.
pipe.fit(X_train, y_train)
#Test model accuracy by running feature test set
y_predicted = pipe.predict(X_test)
Если хочется узнать насколько модель точна в предсказаниях можно сравнить угаданные данные и тестовый лист labels.
print(metrics.classification_report(y_test, y_predicted,target_names=label_names))
Точность модели определяется величиной от 0 до 1, и можно перевести в проценты. Эта модель дает правильный ответ в 100% случаев. Конечно, используя реальные данные, подобного результата будет добиться не так просто, да и задача достаточно простая.
Последний финальный штрих это сохранить модель в том виде, чтоб ее можно было без переобучения использовать в любой другой python программе. Мы сериализуем модель в pickle файл с помощью встроенной в Scikit-learn функции:
#Save model into pickle. Built in serializing tool
joblib.dump(pipe, 'injection_model.pkl')
Небольшая демонстрация того как просто использовать сериализованную модель в другой программе.
import numpy as np
from sklearn.externals import joblib
#Load classifier from the pickle file
clf = joblib.load('injection_model.pkl')
#Set of test data
input_data = ["aselectndwdpyrey@gmail.com",
"andrew@microsoft.com'",
"a.johns@deloite.com",
"'",
"select@mail.jp",
"update11@nebuzar.com",
"' OR 1=1",
"asdasd@sick.com'",
"andrew@mail' OR 1=1",
"an'drew@bark.1ov111.com",
"andrew@gmail.com'"]
predicted_attacks = clf.predict(input_data).astype(np.int)
label_names = ["Safe Data", "SQL Injection"]
for email, item in zip(input_data, predicted_attacks):
print(u'n{} ----> {}'.format(label_names[item], email))
На выходе мы получим вот такой результат:
Как видите модель достаточно уверенно определяет SQL инъекции.
В итоге мы имеем тренированную модель для определения SQL инъекций, в теории мы можем воткнуть ее в серверную часть и в случае определения инъекции перенаправлять все запросы за фальшивую базу данных, чтоб отвадить взгляд от других возможных уязвимостей. Для демонстрации в конце недели я написал небольшой REST API на Flask.
Это были мои первые шаги в области машинного обучения. Надеюсь, что я смогу вдохновить тех, кто так же как и я долгое время с интересом смотрел на машинное обучение, но боялся прикоснутся к нему.
from sklearn import ensemble
from sklearn import feature_extraction
from sklearn import linear_model
from sklearn import pipeline
from sklearn import cross_validation
from sklearn import metrics
from sklearn.externals import joblib
import load_data
import pickle
# Load the dataset from the csv file. Handled by load_data.py. Each email is split in characters and each one has label assigned
X, y, label_names = load_data.get_dataset()
# Split the dataset on training and testing sets
X_train, X_test, y_train, y_test = cross_validation.train_test_split(X,y,test_size=0.2,random_state=0)
#Setting up vectorizer that will convert dataset into vectors using n-gram
vectorizer = feature_extraction.text.TfidfVectorizer(ngram_range=(1, 4), analyzer='char')
#Setting up pipeline to flow data though vectorizer to the liner model implementation
pipe = pipeline.Pipeline([('vectorizer', vectorizer), ('clf', linear_model.LogisticRegression())])
#Pass training set of features and labels though pipe.
pipe.fit(X_train, y_train)
#Test model accuracy by running feature test set
y_predicted = pipe.predict(X_test)
print(metrics.classification_report(y_test, y_predicted,target_names=label_names))
#Save model into pickle. Built in serializing tool
joblib.dump(pipe, 'injection_model.pkl')
Оставляю список полезных ресурсов, которые помогли мне с данным проектом (почти все они на английском)
Tensorflow for begginers [1]
Scikit-Learn Tutorials [6]
Building Language Detector via Scikit-Learn [4]
Нашел несколько отличных статей на Medium [7] включая серию из восьми статей, которые дают хорошее представление, о машинном обучении на простых примерах. (UPD: русский перевод этих же статей [8])
Автор: abarkov
Источник [9]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/python/275081
Ссылки в тексте:
[1] ML for Beginners: https://www.tensorflow.org/get_started/get_started_for_beginners
[2] TensorFlow for beginners: https://www.tensorflow.org/get_started/premade_estimators
[3] Scikit-learn : http://scikit-learn.org/stable/
[4] туториал: https://bugra.github.io/work/notes/2014-12-26/language-detector-via-scikit-learn/
[5] N-граммы: https://ru.wikipedia.org/wiki/N-%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B0
[6] Scikit-Learn Tutorials: http://scikit-learn.org/stable/tutorial/index.html
[7] статей на Medium: https://medium.com/@ageitgey/machine-learning-is-fun-80ea3ec3c471
[8] UPD: русский перевод этих же статей: https://algotravelling.com/ru/%D0%BC%D0%B0%D1%88%D0%B8%D0%BD%D0%BD%D0%BE%D0%B5-%D0%BE%D0%B1%D1%83%D1%87%D0%B5%D0%BD%D0%B8%D0%B5-%D1%8D%D1%82%D0%BE-%D0%B2%D0%B5%D1%81%D0%B5%D0%BB%D0%BE-1/
[9] Источник: https://habrahabr.ru/post/350984/?utm_campaign=350984
Нажмите здесь для печати.