Загальний погляд на машинне навчання класифікація тексту за допомогою нейронних мереж та TensorFlow
Розробники часто кажуть: «Хочете вивчати машинне навчання, спочатку дізнайтеся, як працюють алгоритми». Але мій досвід показує протилежне.
Я вважаю, що спочатку важливо побачити загальну картину:як працюють програми. Як ви зрозумієте це, стане набагато простіше вивчати функціонування алгоритмів.
Як розвинути інтуїцію і зрозуміти всі нюанси машинного навчання? Хороший варіант – створити модель такого навчання. Якщо досвіду написання алгоритмів з нуля поки що немає, можна використовувати бібліотеку, де вони вже реалізовані. Наприклад, TensorFlow.
Прим. пров. Ви можете знайти корисні матеріали на тему нейронних мереж у нашій добірці. І поглянути на шпаргалки за їхніми типами: першу та другу частини.
Під час прочитання може знадобитися посібник із використання TensorFlow, тримайте вкладку з ним відкритою.
TensorFlow
TensorFlow – це бібліотека з відкритим кодом для машинного навчання, створена Google. Назва допомагає зрозуміти, як із нею працювати: тензори є багатовимірними масивами, які течуть (flow) через вузли графа.
Кожне обчислення TensorFlow представляється як граф потоку даних. У нього є два елементи:
- Набір tf.Operation , який представляє одиниці обчислень.
- Набір tf.Tensor , який представляє одиниці даних.
Щоб побачити, як все це працює, створимо наступний граф потоку даних:
Граф, що виконує x+y
Визначимо x = [1, 3, 6] та y = [1, 1, 1] . Так як для представлення одиниць даних граф працює з tf.Tensor, створимо тензор-константи:
Тепер визначимо одиницю операції:
Ми маємо всі елементи графа. Час йогопобудувати:
Так робочий процес TensorFlow і влаштований: спочатку ви створюєте граф, а потім виконуєте обчислення, дійсно запускаючи вузли графа з операціями. Для цього необхідно створити tf.Session.
Об'єкт tf.Session інкапсулює середовище, в якому виконуються об'єкти Operation та оцінюються об'єкти Tensor (принаймні так сказано в документації). Щоб зробити це, необхідно визначити, який граф ми будемо використовувати у сесії:
Для виконання операцій використовується метод tf.Session.run(). Він здійснює один «крок» обчислень TensorFlow, запускаючи необхідний фрагмент графа для виконання кожного об'єкта Operation та оцінки кожного Tensor, переданого в аргументі fetches. У нашому випадку запускається крок операції додавання:
Прогнозуюча модель
Тепер, коли ви знаєте, як TensorFlow працює, треба створити модель, що прогнозує. Коротко:
Алгоритм машинного навчання + Дані = Прогнозуюча модель
Процес побудови такий:
Процес створення прогнозуючої моделі
Як можна помітити, вона складається з алгоритму машинного навчання, «натренованого» на даних. З них формується модель прогнозування, далі видається відповідний результат:
Робочий процес прогнозування
Для створення моделі використовуємо нейронні мережі.
Нейронні мережі
Нейронна мережа є обчислювальною моделлю (спосіб опису системи з використанням математичної мови та її принципів). Ця система швидше самонавчається і натренована, ніж явно запрограмована.
Нейронні мережі імітують центральну нервову систему людини. У них є з'єднані вузли, які схожі на наші нейрони:
Щоб зрозуміти, як працюють нейронні мережі, збудуємо архітектуру однієїїх за допомогою TensowFlow. Можете подивитися на приклад такої реалізації.
Архітектура нейронної мережі
У нашій нейронній мережі буде 2 приховані шари (треба вибрати, скільки їх буде у вашій моделі - це частина проектування архітектури). Завдання кожного прихованого рівня полягає в тому, щоб перетворити вхідні дані на щось, що міг би використовувати шар виведення.
Перший прихований шар
Шар введення та перший прихований шар
Вам також треба визначити, скільки вузлів міститиме перший прихований шар. Вони називаються ознаками чи нейронами, на зображенні зверху кожен представлений синім колом.
У шарі введення один вузол відповідає слову набору даних. Розглянемо це трохи згодом.
Як пояснили у цій статті, кожен вузол (нейрон) множиться на вагу, тобто. має значення ваги. У ході навчання нейронна мережа регулює ці показники, щоб зробити правильні вихідні дані. Мережа також додає зміщення.
Далі у нашій архітектурі дані передаються функції активації, що визначає остаточне виведення кожного вузла. Наведемо аналогію: уявіть, кожен вузол — це лампа, а функція активації вказує, буде лампа горіти чи ні.
Існує багато видів функції активації. Використовуємо зрізане лінійне перетворення (ReLu). Ця функція визначається так:
f(x) = max(0,x) [висновок дорівнює x або 0 (нуль), залежно від того, що більше]
Приклади: якщо x = -1, то f (x) = 0 (нуль); якщо x = 0,7, то f(x) = 0,7.
Другий прихований шар
Другий прихований шар робить те саме, що і перший, але тепер вхідними даними є вихідні дані першого шару:
Перший і другий приховані шари
Шар висновку
Отримаємо, що число вузлів виводу дорівнює числукласи вхідного набору даних.
Значення шару виведення множаться на ваги, до них додається усунення, але функція активації вже інша.
Тепер у нас є граф потоку даних нейронної мережі. Якщо перевести все в код, то вийде приблизно таке:
Навчання нейронної мережі
Як показав попередній досвід, значення ваги оновлюються, поки мережа навчається. Тепер розберемо процес у середовищі TensorFlow.
tf.Variable
Ваги та зсуви зберігаються в змінних tf.Variable, які містять стан у графі між викликами run() . У машинному навчанні прийнято працювати з вагами та зміщеннями, отриманими через нормальний розподіл:
Запустимо мережу вперше з вагами, отриманими за нормальним розподілом:
Щоб дізнатися, чи вчиться мережа, необхідно порівняти вихідні значення z із очікуваними значеннями expected . Існує багато методів, як порахувати втрату loss. Так як ми працюємо із завданням на класифікацію, найкращим способом обчислення помилки буде перехресна ентропія.
Зробимо це за допомогою TensorFlow, використовуючи метод tf.nn.softmax_cross_entropy_with_logits() (функцію активації softmax), і обчислимо середню помилку tf.reduced_mean() :
Ми хочемо знайти найкращі значення ваг і зміщень для того, щоб мінімізувати помилки під час виведення – різницю між отриманим та правильним значеннями. Для цього скористаємося методом градієнтного спуску. А якщо бути точніше, то стохастичним градієнтним спуском:
Існує безліч алгоритмів для обчислення градієнтного спуску, ми використовуватимемо адаптивну оцінку моментів. Передаємо значення learning_rate , яке визначає крок значень для знаходження кращої ваги.
Метод tf.train.AdamOptimizer(learning_rate).minimize(loss) - це синтаксичний цукор,який робить дві речі:
Оновлюючи значення всіх tf.Variables, нам не доводиться передавати перелік змінних. І тепер є код для тренування мережі:
Управління даними
Набором даних, який ми використовуватимемо (до речі, у ньому міститься безліч текстів англійською) треба керувати, щоб передати нейронної мережі. Для реалізації необхідно зробити дві речі:
- Створити індекс для кожного слова.
- Створити матрицю для кожного тексту, де значення дорівнює одиниці, якщо слово є в тексті, і нулю інакше.
Давайте поглянемо на код, щоб зрозуміти процес:
У прикладі вище з тексту "Hi from Brazil" вийшла матриця [1.1.1.]. Що, якби текст був просто «Hi»:
Запуск графа та отримання результату
Настав час найочікуванішої частини – отримання результатів від моделі. Для початку погляньмо ближче на вхідний набір даних.
Набір даних
Порада:ніколи не дивіться на тестові дані, це може вплинути на ваші рішення під час створення моделі. Не потрібно створювати зразок для прогнозування якихось конкретних даних, важливо зробити модель з хорошим узагальненням.
Ось так ви завантажите свої набори даних:
Тренування моделі
У термінології нейронних мереж одна епоха = один передній прохід (отримання значень виведення) та один зворотний прохід (оновлення ваги) всіх тренувальних прикладів.
Пам'ятаєте метод tf.Session.run()? Розглянемо його докладніше:
У графі потоку даних, згаданому на початку статті, ми використали операцію додавання, також можна передати список завдань для виконання. Наш нейронний мережі повідомимо дві речі: обчислення втрати і крок оптимізації.
Параметр feed_dict вказує, куди ми передаємо дані покожному етапу роботи. Також необхідно визначити tf.placeholders, щоб наповнити feed_dict.
Як свідчить документація TensorFlow:
Плейсхолдер потрібен виключно як мета наповнення. Він не ініціалізований і не містить даних.
Тому ми визначимо заповнювачі так:
Розіб'ємо тренувальні дані на блоки згідно з офіційним сайтом:
Якщо ви використовуєте заповнювач для введення, можна визначати змінний вимір блоку за допомогою tf.placeholder(.shape=[None.]) . Елемент None вказує на вимірювання зі змінним розміром.
Для тестування моделі ми наповнимо словник великим блоком, тому необхідно визначити його змінний вимір.
Функція get_batches() показує кількість текстів разом із розміром блоку. Тепер можна запустити модель:
Ми маємо натреновану модель. Щоб протестувати її, потрібно створити елементи графа. Вимірюватимемо точність, треба отримати індекси спрогнозованого значення та індекс правильного значення, тому що ми використовуємо унітарне кодування. Потім перевірити, чи вони рівні, і обчислити середнє для всього тестового набору даних:
Кінцевий код ви можете переглянути на сторінці GitHub.
Примітка: Змініть значення, які ми визначили, щоб подивитися, як вони впливають на тренувальний час та точність моделі.