Класифікація зображень CNN у TensorFlow із кроками та прикладами
⚡ Розумний підсумок
Згорткові нейронні мережі сканують зображення з невеликими фільтрами замість того, щоб однаково зважувати кожен піксель, саме тому вони домінують у комп'ютерному зорі. У цьому покроковому посібнику пояснюється кожен шар, а потім класифікуються цифри MNIST за допомогою TensorFlow.
Що таке згортка нейронна мережа?
Згортка нейронна мережа, також відома як конвнети або CNN, – це добре відомий метод у застосунках комп'ютерного зору. Це клас глибоких нейронних мереж, які використовуються для аналізу візуальних образів. Цей тип архітектури є домінуючим для розпізнавання об'єктів із зображення або відео. Він використовується в таких застосунках, як розпізнавання зображень або відео, обробка природної мови та системи рекомендацій.
Archiструктура згорткової нейронної мережі
Згадайте Facebook кілька років тому, коли ви завантажили фотографію у свій профіль, вас попросили вручну додати ім’я до обличчя на зображенні. Сьогодні Facebook використовує convnet, щоб автоматично позначати вашого друга на зображенні.
Згорточну нейронну мережу для класифікації зображень не дуже важко зрозуміти. Вхідне зображення обробляється на етапі згортання, а потім присвоюється мітка.
Типову архітектуру згорткової мережі можна коротко зобразити на малюнку нижче. Спочатку зображення надсилається до мережі; це називається вхідним зображенням. Потім вхідне зображення проходить низку кроків; це згорткова частина мережі. Нарешті, нейронна мережа може передбачити цифру на зображенні.

Зображення складається з масиву пікселів з різною висотою та шириною. Зображення у градаціях сірого має лише один канал, тоді як кольорове зображення має три канали (кожен для червоного, зеленого та синього). Канали розташовані один над одним. У цьому посібнику ви використовуватимете зображення у градаціях сірого лише з одним каналом. Кожен піксель має значення від 0 до 255, щоб відобразити інтенсивність кольору. Наприклад, піксель, що дорівнює 0, показуватиме білий колір, тоді як піксель зі значенням, близьким до 255, буде темнішим.
Давайте подивимося на зображення, що зберігається в Набір даних MNISTНа зображенні нижче показано, як представити зображення ліворуч у матричному форматі. Зверніть увагу, що вихідна матриця стандартизована для значень від 0 до 1. Для темніших кольорів значення в матриці становить приблизно 0.9, тоді як білі пікселі мають значення 0.
Згорточна операція
Найважливішим компонентом моделі є згортковий шар. Ця частина спрямована на зменшення розміру зображення для швидшого обчислення вагових коефіцієнтів та покращення узагальнення.
Під час згорткової частини мережа зберігає основні характеристики зображення та виключає несуттєвий шум. Наприклад, модель вчиться розпізнавати слона на картинці з горою на задньому плані. Якщо ви використовуєте традиційну нейронну мережу, модель призначить вагу всім пікселям, включно з пікселями з гори, що не є суттєвим і може ввести мережу в оману.
Натомість а Керас Згорткова нейронна мережа використовуватиме математичний метод дляtracлише найважливіші пікселі. Ця математична операція називається згорткою. Цей метод дозволяє мережі вивчати дедалі складніші ознаки на кожному шарі. Згортка розділяє матрицю на дрібні частини, щоб вивчити найважливіші елементи в кожній частині.
Компоненти згорткової нейронної мережі (ConvNet або CNN)
Конвертер складається з чотирьох компонентів:
- Згортка
- Нелінійність (ReLU)
- Pooling або підвибірка
- Класифікація (повністю підключений рівень)
Згортка
Мета згортки полягає в тому, щобtracлокально визначати особливості об'єкта на зображенні. Це означає, що мережа вивчить певні закономірності на зображенні та зможе розпізнавати їх скрізь на зображенні.
Згортка — це поелементне множення. Концепцію легко зрозуміти. Комп'ютер сканує частину зображення, зазвичай розміром 3×3, і множить її за допомогою фільтра. Результат поелементного множення називається картою ознак. Цей крок повторюється, доки не буде проскановано все зображення. Зверніть увагу, що після згортки розмір зображення зменшується.
На діаграмі нижче показано, як фільтр множить одну ділянку зображення для створення однієї комірки карти ознак.
Анімація нижче показує таку саму згортку, що проходить через усе зображення.
Існує безліч доступних фільтрів. Нижче ми перерахували деякі з них. Ви можете бачити, що кожен фільтр має певне призначення. Зверніть увагу, що на зображенні нижче ядро є синонімом фільтра.
Арифметика за згорткою
Згорткова фаза застосовує фільтр до невеликого масиву пікселів на зображенні. Фільтр рухатиметься вздовж вхідного зображення загальної форми 3×3 або 5×5. Це означає, що мережа розсуватиме ці вікна по всьому вхідному зображенню та обчислюватиме згортку. Анімація нижче показує, як працює згортка. Розмір ділянки становить 3×3, а вихідна матриця є результатом поелементної операції між матрицею зображення та фільтром.
Ви помітили, що ширина та висота виведення можуть відрізнятися від ширини та висоти введення. Це відбувається через ефект кордону.
Ефект кордону
Зображення має карту ознак 5×5 та фільтр 3×3. У центрі є лише одне вікно, де фільтр може відображати сітку 3×3. Вихідна карта ознак зменшується на дві плитки на кожній осі, залишаючи вимір 3×3.
Щоб отримати такий самий вихідний розмір, як і вхідний, потрібно додати доповнення. Доповнення полягає в додаванні потрібної кількості рядків і стовпців з кожного боку матриці. Це дозволить згортці вирівняти кожну вхідну плитку по центру. На зображенні нижче вхідна та вихідна матриці мають однаковий розмір, 5×5.
Коли ви визначаєте мережу, згорнуті функції контролюються трьома параметрами:
Глибина: Він визначає кількість фільтрів, які слід застосувати під час згортки. У попередньому прикладі ви бачили глибину 1, що означає, що використовується лише один фільтр. У більшості випадків фільтрів більше одного. Анімація нижче показує операції, що виконуються в ситуації з трьома фільтрами.
крок: Він визначає кількість «стрибків пікселів» між двома зрізами. Якщо крок дорівнює 1, вікно рухатиметься з розмахом пікселя в один. Якщо крок дорівнює двом, вікно рухатиметься на 2 пікселі. Якщо збільшити крок, карти ознак будуть меншими. На двох діаграмах нижче порівнюється крок 1 з кроком 2.
Приклад кроку 1
крок 2
Доповнення нулями: Доповнення (padding) – це операція додавання відповідної кількості рядків і стовпців з кожного боку вхідних карт ознак. У цьому випадку вихідний результат має таку ж розмірність, як і вхідний.
Нелінійність (ReLU)
В кінці операції згортки вихід підлягає дії функції активації, щоб дозволити нелінійність. Звичайна функція активації для згортки - ReLU. Усі пікселі з від'ємним значенням будуть замінені нулями.
Pooling Operaції
Цей крок легко зрозуміти. Метою пулінгу є зменшення розмірності вхідного зображення. Ці кроки виконуються для зменшення обчислювальної складності операції. Зменшуючи розмірність, мережа має менше ваг для обчислення, що запобігає перенавчанню.
На цьому етапі потрібно визначити розмір і крок. Стандартний спосіб об'єднання вхідного зображення - використовувати максимальне значення карти ознак. Подивіться на малюнок нижче. Об'єднання проаналізує чотири підматриці карти ознак 4×4 і поверне максимальне значення. Об'єднання бере максимальне значення масиву 2×2, а потім зміщує це вікно на два пікселі. Наприклад, перша підматриця - [3,1,3,2], тому об'єднання поверне максимум, який дорівнює 3.
Існує ще одна операція об’єднання, наприклад середнє.
Ця операція агресивно зменшує розмір карти ознак.
Повністю підключені шари
Останній крок складається з побудови традиційного штучна нейронна мережа як ви робили в попередньому посібнику. Ви підключаєте всі нейрони з попереднього шару до наступного. Ви використовуєте функцію активації softmax для класифікації числа на вхідному зображенні.
Резюме:
Згорткова нейронна мережа TensorFlow компілює різні шари перед тим, як зробити прогноз. Нейронна мережа має:
- Згортковий шар
- Функція активації ReLU
- Poolinг шар
- Щільно зв'язаний шар
Згорткові шари застосовують різні фільтри до підобласті зображення. Функція активації ReLU додає нелінійність, а шари об'єднання зменшують розмірність карт ознак.
Всі ці шариtracважливу інформацію із зображень. Нарешті, карти ознак передаються на повністю зв'язаний шар за допомогою функції softmax для здійснення прогнозу.
Навчання CNN за допомогою TensorFlow
Тепер, коли ви знайомі зі структурними блоками конвергентної мережі, ви готові її побудувати за допомогою... TensorFlow. Ми будемо використовувати набір даних MNIST для класифікації зображень CNN.
Підготовка даних така ж, як і в попередньому уроці. Ви можете запустити коди та перейти безпосередньо до архітектури CNN.
Щоб класифікувати зображення за допомогою CNN, виконайте наведені нижче дії.
- Крок 1. Завантажте набір даних
- Крок 2: Вхідний шар
- Крок 3: згортковий шар
- Крок 4: Poolinг шар
- Крок 5: Другий згортковий шар і Pooling Шар
- Крок 6: Щільний шар
- Крок 7: Рівень логіту
Примітка до версії: Наведені нижче списки орієнтовані на TensorFlow 1.x. У TensorFlow 2 простір імен tf.layers та tf.estimator.inputs.numpy_input_fn більше не існують; еквівалентами є tf.keras.layers.Conv2D, Max.Pooling2D, Dense та Dropout зібрані в tf.keras.Model та навчені за допомогою model.fit(). Прочитайте кроки для механіки кожного шару, а потім відобразіть їх на Keras API.
Крок 1. Завантажте набір даних
Набір даних MNIST доступний через scikit-learn. Будь ласка, завантажте його та збережіть у папці «Завантаження». Ви можете завантажити його за допомогою fetch_mldata('MNIST original').
Примітка до версії: mldata.org закрито, а fetch_mldata() було видалено у scikit-learn 0.22. У будь-якій поточній інсталяції завантажте ті самі цифри за допомогою fetch_openml замість цього використовується fetch_openml('mnist_784', version=1). Решта конвеєра залишається незмінною.
Створіть набір тренувань/тестів
Вам потрібно розділити набір даних за допомогою train_test_split.
Масштабуйте функції
Нарешті, ви можете масштабувати об'єкти за допомогою MinMaxScaler, як показано на зображенні нижче з класифікацією, використовуючи приклад TensorFlow CNN.
import numpy as np import tensorflow as tf from sklearn.datasets import fetch_mldata #Change USERNAME by the username of your machine ## Windows USER mnist = fetch_mldata('C:\\Users\\USERNAME\\Downloads\\MNIST original') ## Mac User mnist = fetch_mldata('/Users/USERNAME/Downloads/MNIST original') print(mnist.data.shape) print(mnist.target.shape) from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split(mnist.data, mnist.target, test_size=0.2, random_state=42) y_train = y_train.astype(int) y_test = y_test.astype(int) batch_size =len(X_train) print(X_train.shape, y_train.shape,y_test.shape ) ## resclae from sklearn.preprocessing import MinMaxScaler scaler = MinMaxScaler() # Train X_train_scaled = scaler.fit_transform(X_train.astype(np.float64)) # test X_test_scaled = scaler.fit_transform(X_test.astype(np.float64)) feature_columns = [tf.feature_column.numeric_column('x', shape=X_train_scaled.shape[1:])] X_train_scaled.shape[1:]
Дайте визначення CNN
ЗНС використовує фільтри на необроблених пікселях зображення для вивчення детальних шаблонів порівняно з глобальними шаблонами, вивченими традиційною нейронною мережею. Щоб побудувати ЗНС, потрібно визначити:
- Згортковий шар: Застосуйте n фільтрів до карти ознак. Після згортки потрібно використовувати функцію активації ReLU, щоб додати нелінійність до мережі.
- Pooling-шар: Наступним кроком після згортки є зменшення розмірності карти ознак. Метою є зменшення розмірності карти ознак, щоб запобігти перенавчанню та покращити швидкість обчислень. Максимальне об'єднання – це традиційний метод, який розділяє карти ознак на підрегіони (зазвичай розміром 2×2) та зберігає лише максимальні значення.
- Повністю з’єднані шари: усі нейрони з попередніх шарів з’єднані з наступними шарами. CNN класифікує мітку відповідно до характеристик із згорткових шарів і зменшених шаром об’єднання.
Архітектура CNN
- Згортковий шар: застосовує 14 фільтрів 5×5 (наприкладtrac(підрегіони розміром 5×5 пікселів) з функцією активації ReLU
- Pooling Layer: виконує максимальне об’єднання за допомогою фільтра 2×2 і кроку 2 (що вказує, що об’єднані області не перекриваються)
- Згортковий шар: застосовує 36 фільтрів 5×5 із функцією активації ReLU
- Pooling Рівень №2: знову виконує максимальне об’єднання з фільтром 2×2 і кроком 2
- 1,764 нейрона з коефіцієнтом регулярізації випадання 0.4 (ймовірність 0.4 того, що будь-який даний елемент буде викинуто під час навчання)
- Щільний шар (шар логіт): 10 нейронів, по одному для кожного цільового класу цифр (0–9).
Є три важливі модулі для створення CNN:
- conv2d(). Створює двовимірний згортковий шар із кількістю фільтрів, розміром ядра фільтра, заповненням і функцією активації як аргументами.
- max_pooling2d(). Створює двовимірний шар об’єднання за допомогою алгоритму максимального об’єднання.
- dense(). Створює щільний шар із прихованими шарами та блоками
Ви визначите функцію для побудови CNN. Давайте детально розглянемо, як побудувати кожен структурний блок перед обгортанням.ping все разом у функції.
Крок 2: Вхідний шар
def cnn_model_fn(features, labels, mode): input_layer = tf.reshape(tensor = features["x"],shape =[-1, 28, 28, 1])
Вам потрібно визначити тензор із формою даних. Для цього ви можете використовувати модуль tf.reshape. У цьому модулі вам потрібно оголосити тензор, який потрібно змінити, і форму тензора. Перший аргумент — це особливості даних, які визначені в аргументі функції.
Зображення має висоту, ширину та канал. Набір даних MNIST – це монохромне зображення розміром 28×28. Ми встановлюємо розмір пакета на -1 в аргументі форми, щоб він набував форми ознак ["x"]. Перевага полягає в тому, щоб зробити розмір пакета гіперпараметром для налаштування. Якщо розмір пакета встановлено на 7, то тензор видасть 5,488 значень (28*28*7).
Крок 3: згортковий шар
# first Convolutional Layer conv1 = tf.layers.conv2d( inputs=input_layer, filters=14, kernel_size=[5, 5], padding="same", activation=tf.nn.relu)
Перший згортковий шар має 14 фільтрів з розміром ядра 5×5 з однаковим доповненням. Однакове доповнення означає, що як вихідний тензор, так і вхідний тензор повинні мати однакову висоту та ширину. TensorFlow додасть нулі до рядків і стовпців, щоб забезпечити однаковий розмір.
Ви використовуєте функцію активації ReLU. Розмір виводу буде [28, 28, 14].
Крок 4: Poolinг шар
Наступним кроком після згортки є обчислення пулінгу. Обчислення пулінгу зменшить розмірність даних. Ви можете використовувати модуль max_pooling2d з розміром 2×2 та кроком 2. Ви використовуєте попередній шар як вхідні дані. Розмір виводу буде [batch_size, 14, 14, 14].
# first Pooling Layer
pool1 = tf.layers.max_pooling2d(inputs=conv1, pool_size=[2, 2], strides=2)
Крок 5: Другий згортковий шар і Pooling Шар
Другий згортковий шар застосовує 36 фільтрів, що дає вихідний розмір [batch_size, 14, 14, 36]. Шар об'єднання використовує те саме вікно 2×2 та крок 2, що й раніше, тому він ділить кожну просторову вісь навпіл, а вихідна форма стає [batch_size, 7, 7, 36].
conv2 = tf.layers.conv2d(
inputs=pool1,
filters=36,
kernel_size=[5, 5],
padding="same",
activation=tf.nn.relu)
pool2 = tf.layers.max_pooling2d(inputs=conv2, pool_size=[2, 2], strides=2)
Крок 6: Щільний шар
Потім потрібно визначити повністю зв'язний шар. Карту ознак потрібно вирівняти перед з'єднанням зі щільним шаром. Ви можете використовувати модуль зміни форми розміром 7*7*36.
Щільний шар з'єднає 1,764 нейрони. Ви додаєте функцію активації ReLU. Крім того, ви додаєте член регуляризації відсіву з коефіцієнтом 0.3, що означає, що 30 відсотків активацій будуть встановлені на 0. Зауважте, що відсів відбувається лише під час фази навчання. Функція cnn_model_fn має режим аргументу для оголошення того, чи потрібно модель навчати чи оцінювати, як показано в наведеному нижче прикладі класифікації зображень CNN TensorFlow.
pool2_flat = tf.reshape(pool2, [-1, 7 * 7 * 36])
dense = tf.layers.dense(inputs=pool2_flat, units=7 * 7 * 36, activation=tf.nn.relu)
dropout = tf.layers.dropout(
inputs=dense, rate=0.3, training=mode == tf.estimator.ModeKeys.TRAIN)
Крок 7: Рівень логіту
Нарешті, у прикладі класифікації зображень TensorFlow можна визначити останній шар з прогнозом моделі. Форма виводу дорівнює розміру пакета та 10, загальній кількості цільових класів.
# Logits Layer
logits = tf.layers.dense(inputs=dropout, units=10)
Ви можете створити словник, що містить класи та ймовірність кожного класу. Функція tf.argmax() повертає індекс найбільшого значення в шарі логітів. Функція softmax повертає ймовірність кожного класу.
predictions = {
# Generate predictions
"classes": tf.argmax(input=logits, axis=1),
"probabilities": tf.nn.softmax(logits, name="softmax_tensor") }
Ви хочете повернути словник прогнозів лише тоді, коли для режиму встановлено значення prediction. Ви додаєте цей код для відображення прогнозів.
if mode == tf.estimator.ModeKeys.PREDICT: return tf.estimator.EstimatorSpec(mode=mode, predictions=predictions)
Наступний крок полягає в обчисленні втрат моделі. У попередньому посібнику ви дізналися, що функція втрат для багатокласової моделі є перехресною ентропією. Втрати легко обчислюються за допомогою наступного коду:
# Calculate Loss (for both TRAIN and EVAL modes)
loss = tf.losses.sparse_softmax_cross_entropy(labels=labels, logits=logits)
Останнім кроком прикладу TensorFlow CNN є оптимізація моделі, тобто пошук найкращих значень ваг. Для цього використовується градієнтний оптимізатор спуску з коефіцієнтом навчання 0.001. Мета полягає в мінімізації втрат.
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.001)
train_op = optimizer.minimize(
loss=loss,
global_step=tf.train.get_global_step())
Ви закінчили з CNN. Однак ви хочете відобразити показники продуктивності під час режиму оцінювання. Метрикою продуктивності для багатокласової моделі є точність. TensorFlow оснащений модулем точності, який приймає два аргументи: мітки та прогнозовані значення.
eval_metric_ops = {
"accuracy": tf.metrics.accuracy(labels=labels, predictions=predictions["classes"])}
return tf.estimator.EstimatorSpec(mode=mode, loss=loss, eval_metric_ops=eval_metric_ops)
Це воно. Ви створили свій перший CNN і готові об’єднати все у функцію, щоб використовувати її для навчання та оцінки моделі.
def cnn_model_fn(features, labels, mode): """Model function for CNN.""" # Input Layer input_layer = tf.reshape(features["x"], [-1, 28, 28, 1]) # Convolutional Layer conv1 = tf.layers.conv2d( inputs=input_layer, filters=32, kernel_size=[5, 5], padding="same", activation=tf.nn.relu) # Pooling Layer pool1 = tf.layers.max_pooling2d(inputs=conv1, pool_size=[2, 2], strides=2) # Convolutional Layer #2 and Pooling Layer conv2 = tf.layers.conv2d( inputs=pool1, filters=36, kernel_size=[5, 5], padding="same", activation=tf.nn.relu) pool2 = tf.layers.max_pooling2d(inputs=conv2, pool_size=[2, 2], strides=2) # Dense Layer pool2_flat = tf.reshape(pool2, [-1, 7 * 7 * 36]) dense = tf.layers.dense(inputs=pool2_flat, units=7 * 7 * 36, activation=tf.nn.relu) dropout = tf.layers.dropout( inputs=dense, rate=0.4, training=mode == tf.estimator.ModeKeys.TRAIN) # Logits Layer logits = tf.layers.dense(inputs=dropout, units=10) predictions = { # Generate predictions (for PREDICT and EVAL mode) "classes": tf.argmax(input=logits, axis=1), "probabilities": tf.nn.softmax(logits, name="softmax_tensor") } if mode == tf.estimator.ModeKeys.PREDICT: return tf.estimator.EstimatorSpec(mode=mode, predictions=predictions) # Calculate Loss loss = tf.losses.sparse_softmax_cross_entropy(labels=labels, logits=logits) # Configure the Training Op (for TRAIN mode) if mode == tf.estimator.ModeKeys.TRAIN: optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.001) train_op = optimizer.minimize( loss=loss, global_step=tf.train.get_global_step()) return tf.estimator.EstimatorSpec(mode=mode, loss=loss, train_op=train_op) # Add evaluation metrics Evaluation mode eval_metric_ops = { "accuracy": tf.metrics.accuracy( labels=labels, predictions=predictions["classes"])} return tf.estimator.EstimatorSpec( mode=mode, loss=loss, eval_metric_ops=eval_metric_ops)
Примітка щодо зібраної функції: У наведеній вище обгорнутій версії перший згортковий шар встановлюється на 32 фільтри та значення відсіювання 0.4, тоді як покрокові фрагменти коду використовують 14 фільтрів та 0.3. Обидва виконуються, але вибирається одна пара значень і вона зберігається узгодженою, щоб надруковані фігури відповідали таблиці шарів.
Наведені нижче дії такі самі, як і в попередніх уроках.
Перш за все, ви визначаєте оцінювач за допомогою моделі CNN для класифікації зображень.
# Create the Estimator mnist_classifier = tf.estimator.Estimator( model_fn=cnn_model_fn, model_dir="train/mnist_convnet_model")
Навчання CNN займає багато часу, тому ви створюєте перехоплювач реєстрації для зберігання значень шарів softmax кожні 50 ітерацій.
# Set up logging for predictions tensors_to_log = {"probabilities": "softmax_tensor"} logging_hook = tf.train.LoggingTensorHook(tensors=tensors_to_log, every_n_iter=50)
Ви готові оцінити модель. Ви встановлюєте розмір пакета 100 і перетасовуєте дані. Зверніть увагу, що ми встановили кроки навчання 16 000, що може зайняти багато часу. Будьте терплячими.
# Train the model train_input_fn = tf.estimator.inputs.numpy_input_fn( x={"x": X_train_scaled}, y=y_train, batch_size=100, num_epochs=None, shuffle=True) mnist_classifier.train( input_fn=train_input_fn, steps=16000, hooks=[logging_hook])
Тепер, коли модель навчена, ви можете оцінити її та роздрукувати результати.
# Evaluate the model and print results eval_input_fn = tf.estimator.inputs.numpy_input_fn( x={"x": X_test_scaled}, y=y_test, num_epochs=1, shuffle=False) eval_results = mnist_classifier.evaluate(input_fn=eval_input_fn) print(eval_results)
Оцінка друкує відновлену контрольну точку, крок, на якому вона зупинилася, та остаточний словник метрик.
INFO:tensorflow:Calling model_fn. INFO:tensorflow:Done calling model_fn. INFO:tensorflow:Starting evaluation at 2018-08-05-12:52:41 INFO:tensorflow:Graph was finalized. INFO:tensorflow:Restoring parameters from train/mnist_convnet_model/model.ckpt-15652 INFO:tensorflow:Running local_init_op. INFO:tensorflow:Done running local_init_op. INFO:tensorflow:Finished evaluation at 2018-08-05-12:52:56 INFO:tensorflow:Saving dict for global step 15652: accuracy = 0.9589286, global_step = 15652, loss = 0.13894269 {'accuracy': 0.9689286, 'loss': 0.13894269, 'global_step': 15652}
З поточною архітектурою словник оцінювання повідомляє про точність 0.9689286, приблизно 97%. Ви можете змінити архітектуру, розмір пакета та кількість ітерацій для підвищення точності. CNN показав набагато кращі результати, ніж... штучна нейронна мережа або логістична регресія: у навчальному посібнику зі штучних нейронних мереж ви мали точність 96%, що нижче, ніж у CNN. Продуктивність CNN вражає завдяки більшому набору зображень, як з точки зору швидкості обчислень, так і точності.











