Обучение модели Microsoft Custom Vision с помощью rest api

Я работаю над простой консольной утилитой nodejs, которая будет загружать изображения для обучения модели Custom Vision. Я делаю это в основном потому, что веб-приложение customvision не позволяет помечать сразу несколько изображений.

tl; dr: Как отправлять изображения в конечную точку CreateImagesFromFiles API?

Я не могу понять, как передать изображения, которые я хочу загрузить. для документации просто определяет тип документации. одно из свойств (content я думаю). Я попытался передать путь к локальному файлу, URL-адрес к онлайн-файлу и даже изображение в кодировке base64 в виде строки. Ничего не прошло.

У них есть тестовая консоль (синяя кнопка «Открыть консоль тестирования API» на странице связанных документов), но еще раз ... она расплывчата и не скажет вам, какие данные она на самом деле ожидает.

Код здесь не так актуален, но, возможно, он помогает ...

const options = {
    host: 'southcentralus.api.cognitive.microsoft.com',
    path: `/customvision/v2.0/Training/projects/${projectId}/images/files`,
    method: 'POST',
    headers: {
        'Training-Key': trainingKey,
        'Content-Type': 'application/json'
    }
};

const data = {
    images: [
        {
            name: 'xxx',
            contents: 'iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAEklEQVR42mP8z8AARKiAkQaCAFxlCfyG/gCwAAAAAElFTkSuQmCC',
            tagIds: [],
            regions: []
        }
    ],
    tagIds: []
}

const req = http.request(options, res => {
  ...
})
req.write(JSON.stringify(data));
req.end();

Ответ:

BODY: { "statusCode": 404, "message": "Resource not found" }
No more data in response.

person Damb    schedule 01.11.2018    source источник


Ответы (1)


У меня он работает с помощью функции «Консоль тестирования API», поэтому я могу помочь вам определить вашу проблему (но, извините, я не эксперт в node.js, поэтому я покажу вам C# код)

Формат content для API

Вы правы, в документации не совсем ясно, какой контент ждет API. Я произвел поиск и нашел в репозитории Microsoft Github проект под названием Cognitive-CustomVision-Windows, здесь.

Видно, что они используют класс ImageFileCreateEntry, подпись которого отображается здесь:

public ImageFileCreateEntry(string name = default(string), byte[] contents = default(byte[]), IList<System.Guid> tagIds = default(IList<System.Guid>))

Итак, я догадался, что он использует byte[].

Вы также можете увидеть в их образце, как они поступили в этом «пакетном» режиме:

// Or uploaded in a single batch 
var imageFiles = japaneseCherryImages.Select(img => new ImageFileCreateEntry(Path.GetFileName(img), File.ReadAllBytes(img))).ToList();
trainingApi.CreateImagesFromFiles(project.Id, new ImageFileCreateBatch(imageFiles, new List<Guid>() { japaneseCherryTag.Id }));

Затем этот байтовый массив сериализуется с помощью Newtonsoft.Json: если вы посмотрите их документацию (здесь) там сказано, что byte[] преобразованы в String (base 64 encoded). Это наша цель.

Реализация

Как вы упомянули, что вы пробовали использовать изображение в кодировке base64, я попробовал его проверить. Я сделал фото профиля StackOverflow, которое я скачал локально. Затем, используя следующее, я получил строку в кодировке base64:

Image img = Image.FromFile(@"\\Mac\Home\Downloads\Picto.jpg");
byte[] arr;
using (MemoryStream ms = new MemoryStream())
{
    img.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
    arr = ms.ToArray();
}

var content = Convert.ToBase64String(arr);

Позже я вызвал API без тегов, чтобы убедиться, что изображение опубликовано и видно:

POST https://southcentralus.api.cognitive.microsoft.com/customvision/v2.2/Training/projects/MY_PROJECT_ID/images/files HTTP/1.1
Host: southcentralus.api.cognitive.microsoft.com
Training-Key: MY_OWN_TRAINING_KEY
Content-Type: application/json

{
  "images": [
    {
      "name": "imageSentByApi",
      "contents": "/9j/4AAQSkZJRgA...TOO LONG FOR STACK OVERFLOW...",
      "tagIds": [],
      "regions": []
    }
  ],
  "tagIds": []
}

Получен ответ: 200 OK

{
  "isBatchSuccessful": true,
  "images": [{
    "sourceUrl": "imageSentByApi",
    "status": "OK",
    "image": {
      "id": "GENERATED_ID_OF_IMAGE",
      "created": "2018-11-05T22:33:31.6513607",
      "width": 328,
      "height": 328,
      "resizedImageUri": "https://irisscuprodstore.blob.core.windows.net/...",
      "thumbnailUri": "https://irisscuprodstore.blob.core.windows.net/...",
      "originalImageUri": "https://irisscuprodstore.blob.core.windows.net/..."
    }
  }]
}

И мое изображение здесь, на портале Custom Vision!

изображение в нестандартном видении

Отладка вашего кода

Для отладки вы должны сначала попытаться отправить свой контент еще раз с пустыми массивами tagIds и regions, как в моем тесте, а затем предоставить содержимое ответа API.

person Nicolas R    schedule 05.11.2018
comment
Спасибо! Это помогло мне сделать шаг вперед. Он действительно принимает строку base64, но не проходит из-за тегов. Я обновил код до того, что использую сейчас. Это все еще не пройдет в моем приложении nodejs. Выполнение того же запроса от их веб-соноля работает. Я просто не вижу разницы :) - person Damb; 06.11.2018
comment
У вас есть 404, что означает, что URL-адрес неверен. Измените v2.0 на v2.2, поскольку он кажется последним (как в консоли), возможно, конечная точка 2.0 была отключена - person Nicolas R; 06.11.2018
comment
Хорошо поймал. Я знал, что это неправильный запрос, но не мог понять почему, поскольку я скопировал URL-адреса напрямую из api. Был полностью слеп к той разнице версий. К сожалению, даже после смены версии все еще остается ответ 404. Должно быть что-то не так с тем, как я создаю запрос в nodejs. Я попробую по-другому. - person Damb; 06.11.2018
comment
2 другие странные вещи в вашем коде / запросе: https не упоминается. И цитаты, использованные в поле пути, выглядят здесь странно - person Nicolas R; 06.11.2018
comment
Странные кавычки нужны для интерпретации части $ {projectId} в строке, а часть https отсутствует, потому что nodejs этого хочет, поэтому все должно быть в порядке :) Вот почему проблема так раздражает. Это не волшебство. Это простой HTTP-запрос к API. Я надеялся, что что-то укажет на то, что я пропустил (как вы это сделали с v2.2), но, похоже, в самом коде нет никаких серьезных недостатков :) - person Damb; 06.11.2018
comment
Хорошо, я вернулся домой, поэтому я быстро попробую реализовать его в Node.js - person Nicolas R; 07.11.2018
comment
Он работает на моей стороне в Node.js, если ... если я установлю https! Я использовал const http = require('https');, а не const http = require('http');! С http я получил 404, с https я получил 200 - person Nicolas R; 07.11.2018