Это часть серии записей блога, посвященных автоматизированному созданию моделей машинного обучения и наборов данных, используемых для обучения нейронных сетей, а также модельно-независимому метаобучению. Если вам интересна предыстория, вы можете прокрутить нижнюю часть статьи, чтобы получить ссылки на предыдущие записи блога. Вы также можете перейти на страницу Use SERP Data to Build Machine Learning Models, чтобы получить четкое представление о том, какие автоматизированные модели машинного обучения вы можете создать или как использовать их для мета-обучения.
В предыдущие недели я показывал пример формы для создания алгоритмов машинного обучения. Это стало возможным благодаря хранению метаданных гиперпараметров алгоритмов машинного обучения. На этой неделе я расскажу, как хранить метаданные каждого процесса обучения и тестирования машинного обучения, чтобы проложить путь к алгоритмам метаобучения.
Что такое задача метаобучения?
Мета-обучение — это использование мета-данных ранее полученных и классифицированных процессов обучения для решения новых задач обучения, с которыми алгоритм машинного обучения ранее не сталкивался. Задача мета-обучения — это обучение для обучения.
Сегодня модели глубокого обучения не могут выполнять множество различных задач. Например, в предыдущие недели я демонстрировал классификатор изображений. Хотя настройка гиперпараметров была легкой для этой конкретной задачи, я не создал эффективную модель классификации изображений. Это отнимало мое время, и я просто показал, как сделать процесс более автоматизированным. Даже если бы я создал конволюционные нейронные сети с хорошей оптимизацией, я бы все равно столкнулся с проблемой ограниченного круга объектов, подлежащих классификации. Я бы также решил ее, используя обучение с подкреплением, подвергая модель постоянному обучению и получая ее итерации, когда они мне нужны. Но это не решило бы проблему того, как работать с объектами, имеющими близкое сходство. Я бы использовал предыдущее подмножество процесса обучения глубокого обучения, чтобы получить знания по этому вопросу и применить формулу для этого в процессе обучения.
Этот список можно продолжать и продолжать. Но он не решает одного вопроса. Как я могу тратить меньше времени на настройку модели? Здесь на помощь приходит мета-обучение. Подходы мета-обучения, такие как учебные задачи, могут быть применены для резкого сокращения времени, необходимого для создания модели.
Но как? Для того чтобы применить мета-обучение, нам необходимо изучить, как мы, люди, воспринимаем такие проблемы. Например, как мы узнаем, что процесс обучения машинного обучения пошел плохо? Наблюдая за функцией потерь. Причина, по которой мы смотрим на функцию потерь, заключается в том, что она является производной метаданных о том, насколько хорошо глубокие нейронные сети справляются с конкретной задачей. Как мы можем знать это наверняка? Результаты дают нам статистически более высокие показатели предсказания. Одного этого знания достаточно, чтобы понять, как должны работать методы метаобучения на основе оптимизации, наблюдая за эффективностью оптимизации функции потерь.
Также необходимо хранить процесс обучения глубокого обучения и его последующие результаты точности в объекте, чтобы проводить перекрестное сравнение с использованием методов метаобучения.
Что необходимо для метаобучения?
По моему скромному мнению, наряду с общим консенсусом, у меня есть еще несколько необходимых вещей, которые я вижу как требование для мета-обучения.
Позвольте мне разделить три распространенных подхода к мета-обучению, чтобы увидеть, что им необходимо:
Мета-обучение на основе моделей: Предлагаемые модели используют внутреннюю или внешнюю память процесса машинного обучения для достижения лучшего обучения. Это означает, что если вам нужно классифицировать собаку, если вы уже классифицировали других собак, вы можете использовать модель, которую вы использовали ранее, чтобы с легкостью достичь этой цели автоматически. Недостатком концентрированных подходов мета-обучения такого рода является необходимость маркировки объектов.
Мета-обучение на основе метрик: Предлагаемые модели используют различные метрики, чтобы решить, похожи ли задачи обучения по своему процессу. Если вам нужно классифицировать между человеком и птицей, вы можете использовать ранее полученные метаданные классификации млекопитающих и птиц для достижения хороших результатов. Однако недостатком этого типа мета-обучения является включение летучей мыши. Млекопитающее, похожее на птицу.
Мета-обучение на основе оптимизации: Предлагаемая модель использует метаданные оптимизации гиперпараметров ранее полученного обучения глубокого обучения для максимизации результата с помощью метаобучения. Подобный подход к мета-обучению в чистом виде потребует высокоинтенсивного процесса машинного обучения.
Теперь, чтобы противостоять слабости процесса метаобучения на основе моделей, я уже предлагал решение в одной из своих старых записей в блоге. Я использовал SerpApi’s Google Images Scraper API для отбора изображений с определенным тегом с помощью параметра chips для создания наборов данных в масштабе (также только изображения с определенным размером для автоматизации предварительной обработки).
У меня нет готового решения для борьбы со слабостью мета-обучения на основе метрик. Однако я видел, что многие поисковые системы движутся в направлении обогащения своих графов знаний, блоков ответов и связанных элементов поиска, таких как связанные вопросы, связанные поиски и т. д., что может помочь уподобить связь между новыми задачами. Но, конечно, это лишь смутное представление. Вы можете взглянуть на документацию с примерами для SerpApi’s Google Knowledge Graph Scraper API, SerpApi’s Google Answer Box Scraper API и другую соответствующую документацию, чтобы получить лучшее представление о том, как использовать их в мета-обучении. Вы также можете зарегистрироваться, чтобы получить бесплатные кредиты.
У меня нет решения, как противостоять слабости мета-обучения, основанного на оптимизации. Однако на этой неделе я покажу, как хранить процесс обучения машинного обучения с помощью асинхронных вызовов, что жизненно важно для такого подхода к метаобучению. Асинхронная обработка в компьютерных науках означает распределение задач, которые выполняются параллельно, не влияя на ход выполнения друг друга. В данном контексте это избавляет нас от необходимости ждать окончания процесса обучения и запускать множество вызовов.
Очень важно иметь хорошие механизмы машинного обучения, которые могут хранить обучающие примеры и сравнивать их либо с внешними объектами, либо с точками данных, а также хранить метаданные обучающих данных для дальнейшего использования. Также полезно использовать SGD (стохастический градиентный спуск), RNN (рекуррентные нейронные сети), регрессию, Few-Shot Learning и т.д. в одном месте с обобщенным синтаксисом для достижения трансферного обучения с помощью MAML (Model Agnostic Meta Learning). Цель этой серии статей в блоге — достичь хотя бы доли того, что предлагается в этой статье. Как только он станет открытым исходным кодом на Github-странице SerpApi, я надеюсь, что мои ошибки (особенно на фронтенде) будут покрыты с помощью других. Как и у лучших программистов в реальном мире, цель состоит в том, чтобы иметь минимальную потребность в настройке при обучении модели для конкретной задачи, а также сделать обученную модель способной выполнять многозадачные операции. Конечно, при инициализации я не ожидаю, что модель контролируемого обучения, способная выполнять несколько задач классификации, напишет поэму. Но возможность проводить мета-обучение, по крайней мере, по человеческим наблюдениям, перекрестно сравнивая эталоны различных параметров модели, является захватывающим шагом для тех, кто пытается приобрести новые навыки, как я.
Хранение моделей машинного обучения
Я создал элемент Attempt, который будет храниться на сервере хранения под областью действия моделей:
class Attempt(BaseModel):
id: int | None = None
name: str | None = None
training_commands: dict = {}
training_losses: list = []
n_epoch: int = 0
testing_commands: dict = {}
accuracy: float = 0.0
status: str = "incomplete"
limit: int = 0
Он содержит уникальный идентификатор, который будет использоваться в следующие недели для вызова процесса обучения, имя для имени файла модели, команды обучения как словарь, который мы используем для запуска обучения, потери обучения для наблюдения за состоянием обучения при каждом обратном распространении, количество эпох для создания живого визуального графика, команды тестирования для словаря, запускающего процесс тестирования, точность для хранения точности модели, статус для наблюдения за ее состоянием и предел для предела, используемого в процессе тестирования.
Давайте инициализируем класс для связи с базой данных моделей:
class ModelsDatabase:
def __init__(self):
username = "<Storage Server Username>"
password = "<Storage Server Password>"
bucket_name = "images"
auth = PasswordAuthenticator(
username,
password
)
timeout_opts = ClusterTimeoutOptions(kv_timeout=timedelta(seconds=10))
self.cluster = Cluster('couchbase://localhost', ClusterOptions(auth, timeout_options=timeout_opts))
self.cluster.wait_until_ready(timedelta(seconds=5))
cb = self.cluster.bucket(bucket_name)
self.cb_coll = cb.scope("model").collection("attempt")
def insert_attempt(self, doc: Attempt):
doc = doc.dict()
print("nInsert CAS: ")
try:
key = doc["name"]
result = self.cb_coll.insert(key, doc)
print(result.cas)
except Exception as e:
print(e)
def get_attempt_by_name(self, name):
try:
sql_query = 'SELECT attempt FROM `images`.model.attempt WHERE name = $1'
row_iter = self.cluster.query(
sql_query,
QueryOptions(positional_parameters=[name]))
rows_arr = []
for row in row_iter:
rows_arr.append(row)
return rows_arr[0]['attempt']
except Exception as e:
print(e)
def get_attempt_by_id(self, id):
try:
sql_query = 'SELECT attempt FROM `images`.model.attempt WHERE id = $1'
row_iter = self.cluster.query(
sql_query,
QueryOptions(positional_parameters=[id]))
rows_arr = []
for row in row_iter:
rows_arr.append(row)
return rows_arr[0]['attempt']
except Exception as e:
print(e)
def update_attempt(self, doc: Attempt):
try:
key = doc.name
result = self.cb_coll.upsert(key, doc.dict())
except Exception as e:
print(e)
def get_latest_index(self):
try:
sql_query = 'SELECT COUNT(*) as latest_index FROM `images`.model.attempt'
row_iter = self.cluster.query(
sql_query,
QueryOptions())
for row in row_iter:
return row['latest_index']
except Exception as e:
print(e)
А также несколько вспомогательных конечных точек в главном файле:
@app.post("/create_attempt")
def create_attempt(a: Attempt):
db = ModelsDatabase()
db.insert_attempt(a)
return {"status": "Success"}
@app.post("/find_attempt/")
def find_attempt(name: str):
db = ModelsDatabase()
attempt = db.get_attempt_by_name(name)
return attempt
@app.post("/update_attempt")
def update_attempt(a: Attempt):
db = ModelsDatabase()
db.update_attempt(a)
return {"status": "Success"}
@app.post("/latest_attempt_index/")
def return_index():
db = ModelsDatabase()
index = db.get_latest_index()
return {"status": index}
Давайте обновим конечную точку обучения, чтобы создать для нас объект модели в базе данных:
@app.post("/train/")
async def train(tc: TrainCommands, background_tasks: BackgroundTasks):
def background_training(tc):
if 'name' in tc.model and tc.model['name'] != "":
model = eval(tc.model['name'])
else:
model = CustomModel
try:
a = find_attempt(name = tc.model_name)
a["status"] = "Training"
a["training_losses"] = []
a = Attempt(**a)
update_attempt(a)
index = a.id
except:
index = return_index()['status']
a = Attempt(name=tc.model_name, training_commands = tc.dict(), status = "Training", n_epoch=tc.n_epoch, id=index)
create_attempt(a=a)
trainer = Train(tc, model, CustomImageDataLoader, CustomImageDataset, ImagesDataBase)
trainer.train()
model = None
try:
torch.cuda.empty_cache()
except:
pass
background_tasks.add_task(background_training, tc)
return {"status": "Complete"}
Давайте соберем наши потери в процессе обучения (также lr планировщик для градиентных шагов):
def train(self):
device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
Epoch = [x for x in range(0,self.n_epoch)]
Loss = [0] * self.n_epoch
scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(self.optimizer, 'min')
for epoch in range(self.n_epoch):
running_loss = 0.0
inputs, labels = self.loader.iterate_training()
inputs, labels = inputs.to(device), labels.to(device)
self.optimizer.zero_grad()
if torch.cuda.is_available():
self.model.cuda()
outputs = self.model(inputs).to(device)
else:
outputs = self.model(inputs)
loss = self.criterion(outputs, labels.squeeze())
loss.backward()
self.optimizer.step()
running_loss = running_loss + loss.item()
scheduler.step(running_loss)
from main import find_attempt, update_attempt
a = find_attempt(name = self.model_name)
a['training_losses'].append(running_loss)
a = Attempt(**a)
update_attempt(a)
if epoch % 5 == 4:
print(f'[Epoch: {epoch + 1}, Progress: {((epoch+1)*100/self.n_epoch):.3f}%] loss: {running_loss:.6f}')
running_loss = 0.0
torch.save(self.model.state_dict(), "models/{}.pt".format(self.model_name))
Еще одно обновление процесса тестирования, которое должно быть асинхронным, а также в коммуникации с сервером хранения данных:
@app.post("/test/")
async def test(tc: TestCommands, background_tasks: BackgroundTasks):
def background_testing(tc):
if 'name' in tc.model and tc.model['name'] != "":
model = eval(tc.model['name'])
else:
model = CustomModel
try:
a = find_attempt(name = tc.model_name)
a["testing_commands"] = tc.dict()
a["status"] = "Testing"
a = Attempt(**a)
update_attempt(a)
except:
return {"status": "No Model Attempt by that Name"}
tester = Test(tc, CustomImageDataset, ImagesDataBase, model)
accuracy = tester.test_accuracy()
a = find_attempt(name = tc.model_name)
a["accuracy"] = accuracy
a["status"] = "Complete"
a = Attempt(**a)
update_attempt(a)
model = None
try:
torch.cuda.empty_cache()
except:
pass
background_tasks.add_task(background_testing, tc)
return {"status": "Success"}
Вот результирующий элемент хранилища, полученный в результате обучения:
{
"id": 4,
"name": "american_dog_species_3",
"training_commands": {
"batch_size": 4,
"criterion": {
"name": "CrossEntropyLoss"
},
"image_ops": [{
"resize": {
"resample": "Image.ANTIALIAS",
"size": [500, 500]
}
}, {
"convert": {
"mode": "'RGB'"
}
}],
"label_names": ["American Hairless Terrier imagesize:500x500", "Alaskan Malamute imagesize:500x500", "American Eskimo Dog imagesize:500x500", "Australian Shepherd imagesize:500x500", "Boston Terrier imagesize:500x500", "Boykin Spaniel imagesize:500x500", "Chesapeake Bay Retriever imagesize:500x500", "Catahoula Leopard Dog imagesize:500x500", "Toy Fox Terrier imagesize:500x500"],
"model": {
"layers": [{
"in_channels": 3,
"kernel_size": 5,
"name": "Conv2d",
"out_channels": 6
}, {
"inplace": true,
"name": "ReLU"
}, {
"kernel_size": 2,
"name": "MaxPool2d",
"stride": 2
}, {
"in_channels": "auto",
"kernel_size": 5,
"name": "Conv2d",
"out_channels": 16
}, {
"inplace": true,
"name": "ReLU"
}, {
"kernel_size": 2,
"name": "MaxPool2d",
"stride": 2
}, {
"in_channels": "auto",
"kernel_size": 5,
"name": "Conv2d",
"out_channels": 32
}, {
"inplace": true,
"name": "ReLU"
}, {
"kernel_size": 2,
"name": "MaxPool2d",
"stride": 2
}, {
"name": "Flatten",
"start_dim": 1
}, {
"in_features": 111392,
"name": "Linear",
"out_features": 120
}, {
"inplace": true,
"name": "ReLU"
}, {
"in_features": "auto",
"name": "Linear",
"out_features": 84
}, {
"inplace": true,
"name": "ReLU"
}, {
"in_features": "auto",
"name": "Linear",
"out_features": "n_labels"
}],
"name": ""
},
"model_name": "american_dog_species_3",
"n_epoch": 100,
"n_labels": 0,
"optimizer": {
"lr": 0.001,
"momentum": 0.9,
"name": "SGD"
},
"target_transform": {
"ToTensor": true
},
"transform": {
"Normalize": {
"mean": [0.5, 0.5, 0.5],
"std": [0.5, 0.5, 0.5]
},
"ToTensor": true
}
},
"training_losses": [2.1530826091766357, 2.2155375480651855, 2.212409019470215, 2.171882152557373, 2.193148374557495, 2.174982786178589, 2.2089200019836426, 2.166707992553711, 2.1700942516326904, 2.196320056915283, 2.228410243988037, 2.2278425693511963, 2.1531643867492676, 2.1904003620147705, 2.1973652839660645, 2.1950249671936035, 2.1686930656433105, 2.182337999343872, 2.2186434268951416, 2.2066121101379395, 2.172186851501465, 2.217101573944092, 2.2250301837921143, 2.22577166557312, 2.2089788913726807, 2.1954753398895264, 2.19649338722229, 2.1682443618774414, 2.2124178409576416, 2.1765542030334473, 2.15944766998291, 2.2267537117004395, 2.1671102046966553, 2.218825101852417, 2.2200405597686768, 2.1963484287261963, 2.199852705001831, 2.2375543117523193, 2.1804018020629883, 2.2097158432006836, 2.1749439239501953, 2.213040351867676, 2.2149901390075684, 2.1947004795074463, 2.164980411529541, 2.1940670013427734, 2.229835033416748, 2.2061691284179688, 2.2089390754699707, 2.207270622253418, 2.235719680786133, 2.185238838195801, 2.222529411315918, 2.1917202472686768, 2.214961528778076, 2.181013584136963, 2.2280330657958984, 2.2193360328674316, 2.2151079177856445, 2.1822409629821777, 2.181617498397827, 2.213880777359009, 2.2002997398376465, 2.221768379211426, 2.1861824989318848, 2.191596508026123, 2.2087886333465576, 2.1659762859344482, 2.1675500869750977, 2.1987595558166504, 2.2219362258911133, 2.2185418605804443, 2.2019474506378174, 2.2085072994232178, 2.168557643890381, 2.1841750144958496, 2.206641674041748, 2.165733814239502, 2.193709373474121, 2.2362961769104004, 2.1809918880462646, 2.1982641220092773, 2.237257242202759, 2.2146575450897217, 2.197037935256958, 2.193465232849121, 2.1990575790405273, 2.193073272705078, 2.2431421279907227, 2.204183578491211, 2.235936164855957, 2.221945285797119, 2.185289144515991, 2.1666038036346436, 2.1959757804870605, 2.171337604522705, 2.1832592487335205, 2.2154834270477295, 2.168503761291504, 2.2134923934936523],
"n_epoch": 100,
"testing_commands": {
"criterion": {
"name": "CrossEntropyLoss"
},
"ids": [],
"image_ops": [{
"resize": {
"resample": "Image.ANTIALIAS",
"size": [500, 500]
}
}, {
"convert": {
"mode": "'RGB'"
}
}],
"label_names": ["American Hairless Terrier imagesize:500x500", "Alaskan Malamute imagesize:500x500", "American Eskimo Dog imagesize:500x500", "Australian Shepherd imagesize:500x500", "Boston Terrier imagesize:500x500", "Boykin Spaniel imagesize:500x500", "Chesapeake Bay Retriever imagesize:500x500", "Catahoula Leopard Dog imagesize:500x500", "Toy Fox Terrier imagesize:500x500"],
"limit": 200,
"model": {
"layers": [{
"in_channels": 3,
"kernel_size": 5,
"name": "Conv2d",
"out_channels": 6
}, {
"inplace": true,
"name": "ReLU"
}, {
"kernel_size": 2,
"name": "MaxPool2d",
"stride": 2
}, {
"in_channels": "auto",
"kernel_size": 5,
"name": "Conv2d",
"out_channels": 16
}, {
"inplace": true,
"name": "ReLU"
}, {
"kernel_size": 2,
"name": "MaxPool2d",
"stride": 2
}, {
"in_channels": "auto",
"kernel_size": 5,
"name": "Conv2d",
"out_channels": 32
}, {
"inplace": true,
"name": "ReLU"
}, {
"kernel_size": 2,
"name": "MaxPool2d",
"stride": 2
}, {
"name": "Flatten",
"start_dim": 1
}, {
"in_features": 111392,
"name": "Linear",
"out_features": 120
}, {
"inplace": true,
"name": "ReLU"
}, {
"in_features": "auto",
"name": "Linear",
"out_features": 84
}, {
"inplace": true,
"name": "ReLU"
}, {
"in_features": "auto",
"name": "Linear",
"out_features": "n_labels"
}],
"name": ""
},
"model_name": "american_dog_species_3",
"n_labels": 0,
"target_transform": {
"ToTensor": true
},
"transform": {
"Normalize": {
"mean": [0.5, 0.5, 0.5],
"std": [0.5, 0.5, 0.5]
},
"ToTensor": true
}
},
"accuracy": 0.16500000000000006,
"status": "Complete",
"limit": 0
}
Заключение
Я благодарен читателю за внимание, а также компании Brilliant People of SerpApi за то, что эта статья стала возможной. В этой записи я хотел бы поделиться еще одним мнением. Я нахожу работы ICLR, ICML и несколько публикаций в arxiv увлекательными (я планирую поделиться своим мнением о них в ближайшие недели). Но я также вижу важную потребность в проектах с открытым исходным кодом по мета-обучению для быстрой адаптации глубоких сетей. Я не вижу противоречий между профессионалами и энтузиастами на данном этапе прогресса, который мы наблюдаем в искусственном интеллекте. Я верю, что мы сможем достичь левизной скорости в достижениях человечества, если сможем коллективно прогрессировать в мета-обучении. Будь то автоматическое предоставление наборов данных или автоматическая оптимизация глубокого обучения, метаобучение имеет множество аспектов, в которые каждый может внести свой вклад. Если отбросить шумиху и обобщения вокруг слова «мета-обучение», или «обучение для обучения», то эта тема захватывающе интересна и глубоко логична по своей природе. Я бы очень хотел проснуться в мире, где модель с многозадачными способностями все еще учится решать задачи самостоятельно. Даже примитивная версия такого достижения является захватывающей.
Ссылки на предыдущие записи блога |
---|
Как обучить масштабируемый классификатор с помощью FastAPI и SerpApi? |
Автоматическое обучение с помощью FastAPI, Pytorch и SerpApi |
Создание базы данных N1QL меченых изображений с использованием Couchbase, FastAPI и SerpApi |
Использование настраиваемого словаря для автоматического обучения сети с помощью FastApi, PyTorch и SerpApi |
Расширение возможностей обучения с помощью данных SERP |
Автоматическое обучение в масштабе |
ML-модель с автоматическим созданием |
Машинное обучение на Python |
Мета обучение |