В тази статия ще се гмурнем в една много мощна техника от дълбокото обучение, наречена трансферно обучение (transfer learning). Ще видим как можем да използваме вече обучени невронни мрежи като основа за нови модели и така значително да ускорим процеса на обучение и да подобрим резултатите, особено когато разполагаме с ограничени данни. Ще покажем практически примери, използвайки високо-нивовия Keras API на TensorFlow. Нека започваме!
Какво е трансферно обучение?
Трансферното обучение е техника в машинното обучение, при която модел, обучен за една задача, се използва като отправна точка за модел на втора, сродна задача. Вместо да започваме обучението от нулата (със случайно инициализирани параметри), ние „пренасяме“ вече придобитите знания от първия модел към новия.
Тази техника е особено полезна в областта на компютърното зрение и обработката на естествен език, където предварително обучени модели като VGG, Inception, BERT и GPT са широко достъпни. Тези модели са обучени върху огромни набори от данни (като ImageNet за картинки и Wikipedia за текст) и са усвоили богати, преносими представяния на своите входни данни.
Защо да използваме трансферно обучение? Ето някои ключови ползи:
- По-бърза сходимост: Предварително обучените слоеве вече са усвоили полезни характеристики, така че моделът ще се обучи по-бързо в сравнение със случайна инициализация.
- Подобрена производителност: Моделът може да постигне по-добри резултати, особено ако данните в новата задача са ограничени.
- По-малко данни: Предварителното обучение намалява нуждата от големи обучителни набори от данни за новата задача.
- Преодоляване на овърфитинг (пренагаждане към данните): При малки набори от данни, комплексни модели като дълбоки невронни мрежи често овърфитват лошо. Трансферното обучение ограничава овърфитинга, като ефективно ограничава сложността на модела.
Сега, след като знаем защо трансферното обучение е толкова мощно, нека видим как можем да го приложим на практика с TensorFlow и Keras.
Прилагане на трансферно обучение с Keras
Keras предлага множество предварително обучени модели за компютърно зрение в модула tensorflow.keras.applications, включително VGG16, VGG19, ResNet50, Inception v3, и др. Тези модели са обучени върху набора от данни ImageNet, който съдържа над 14 милиона картинки от 1000 различни класа.
За целите на нашия пример, ще използваме модела VGG16 за да пренесем обучението върху набора от данни CIFAR-10, който има 10 класа обекти: самолети, автомобили, птици, котки, елени, кучета, жаби, коне, кораби и камиони.
Първо, нека заредим предварително обучения VGG16 модел:
from tensorflow.keras.applications import VGG16
base_model = VGG16(weights='imagenet', include_top=False, input_shape=(32, 32, 3))
Тук, аргументът weights='imagenet'
указва да заредим тегла, които са били предварително обучени върху ImageNet. include_top=False
премахва последния напълно свързан слой, който е специфичен за 1000-те класа на ImageNet, а input_shape
задава размера на входните картинки (32×32 пиксела с 3 цветови канала за CIFAR-10).
След като имаме предварително обучения модел, можем да го използваме по два основни начина:
- Извличане на характеристики (Feature Extraction): Използваме изходите на прослойките от предварително обучения модел като вход към нов модел. Параметрите на предварително обучените слоеве остават замразени по време на обучението.
- Фино настройване (Fine-Tuning): Размразяваме последните няколко слоя на предварително обучения модел и съвместно оптимизираме както новите слоеве, така и размразените слоеве. Това позволява на модела да адаптира по-високо ниво характеристики към новата задача.
Нека първо опитаме извличане на характеристики. Ще замразим всички слоеве на предварително обучения модел и ще добавим нов класификатор отгоре:
# Freeze all VGG16 layers
for layer in base_model.layers:
layer.trainable = False
# Добавяме нови слоеве отгоре
x = base_model.output
x = GlobalAveragePooling2D()(x)
x = Dense(1024, activation='relu')(x)
predictions = Dense(10, activation='softmax')(x)
model = Model(inputs=base_model.input, outputs=predictions)
Първо, задаваме layer.trainable = False
за всички слоеве на base_model
, за да ги замразим. След това добавяме нови слоеве към изхода на base_model
: слой за global average pooling за редуциране на пространствените размерности, напълно свързан слой с 1024 неврона и ReLU активация, и накрая изходен слой с 10 неврона (по един за всеки клас на CIFAR-10) и софтмакс активация.
С това имаме нов модел, който ще използва предварително обучените слоеве на VGG16 за извличане на характеристики и ще тренира само новите слоеве за класификация на CIFAR-10.
Сега можем да компилираме и обучим модела:
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
history = model.fit(train_images, train_labels, epochs=10, validation_data=(test_images, test_labels))
След 10 епохи на обучение, моделът постига около 70% точност върху валидационните данни. Това е значително подобрение спрямо модел със случайна инициализация, който постига около 50% точност след 10 епохи при същата архитектура.
Фино настройване за подобрена производителност
За да подобрим още повече резултатите, можем да опитаме фино настройване – размразяване на последните няколко прослойки на предварително обучения модел и съвместно оптимизиране на параметрите им с тези на новите слоеве.
Ето как можем да модифицираме кода ни за фино настройване:
# Unfreeze the last 4 blocks of VGG16
for layer in base_model.layers[-4:]:
layer.trainable = True
# Compile with lower learning rate
model.compile(optimizer=Adam(lr=1e-5), loss='categorical_crossentropy', metrics=['accuracy'])
# Train for 10 more epochs
history_fine = model.fit(train_images, train_labels, epochs=10, validation_data=(test_images, test_labels))
Тук размразяваме последните 4 блока на VGG16, като задаваме layer.trainable = True
. След това компилираме модела отново, този път с много нисък learning rate (1e-5), за да внасяме само фини корекции в теглата. Накрая дообучаваме модела за още 10 епохи.
С фино настройване, моделът достига над 90% точност върху CIFAR-10, което е съизмеримо с модели, обучени от нулата върху този набор от данни. Забележителното е, че го постигаме само с 20 епохи обучение и с много по-малък модел (предварително обучената VGG16 мрежа).
Обобщение и заключителни бележки
В тази статия разгледахме основите на трансферното обучение и видяхме как можем да го приложим за задачата за класификация на изображения с помощта на TensorFlow и Keras. Видяхме два основни подхода – извличане на характеристики и фино настройване – и демонстрирахме значителните ползи по отношение на скорост и производителност в сравнение с модели, обучени от нулата.
Трансферното обучение е изключително мощна техника, която отваря много нови възможности в практическото приложение на дълбокото обучение. С публично достъпни предварително обучени модели върху големи набори от данни като ImageNet, Open Images, Common Crawl и Wikipedia, можем бързо да създаваме високопроизводителни модели за широк спектър от задачи в компютърното зрение и обработката на естествен език, дори и с ограничени изчислителни ресурси и обучителни данни.
Разбира се, трансферното обучение не е сребърен куршум. Ефективността му зависи от това колко сродна е новата задача с оригиналната задача, върху която е обучен моделът. Колкото по-различни са задачите, толкова по-малко преносими са характеристиките и толкова повече фино настройване ще е необходимо (и в някои случаи може да е по-добре да се обучи модел от нулата).
Някои други ключови въпроси при трансферното обучение включват избора на подходяща архитектура (например ResNet срещу Inception за CompVis), идентифициране на правилния слой за „отрязване“ на предварително обучения модел, стратегия за замразяване/размразяване на слоеве и хипер параметри като размер на партидата и честота на обучение.
В бъдещи статии може да задълбаем в по-сложни техники за трансферно обучение като прогресивно размразяване, дискриминативно настройване на честотата на обучение, и трансферно обучение за регресионни и генеративни модели.
Междувременно, не се колебайте да експериментирате с трансферно обучение в собствените си проекти! Помнете, че дори и базови техники като извличане на характеристики могат да добавят значителна стойност и да ускорят разработката, особено в началните етапи на проекта.