Пример #1
0
        static async Task WorkOnProject(string trainingEndpoint, string trainingKey, string projectName, string COCOInstancesFilePathOrUrl, IList <string> categories, uint numberOfImages, bool isDetectionModel, bool train)
        {
            Console.Write($"\nLoading, parsing and preparing {COCOInstancesFilePathOrUrl}...");

            if (numberOfImages == 0 || numberOfImages > customVisionImageLimit)
            {
                numberOfImages = 50000;
            }

            var data = await COCODatasetFactory.LoadFromCOCOAnnotationJSONFileAsync(COCOInstancesFilePathOrUrl, categories, numberOfImages);

            Console.WriteLine("done.");

            Console.WriteLine("Prepared COCO dataset with {0} categories and {1} images.\n", data.categoriesAndIds.Count, data.traningSet.Count);

            Console.Write($"Initializing Custom Vision Project {COCOInstancesFilePathOrUrl}...");
            ProjectTraningConfiguration trainingConfig = await ProjectTraningConfiguration.CreateProjectAsync(trainingEndpoint, trainingKey, projectName, true, isDetectionModel);

            Console.WriteLine("done.");

            Console.Write($"\nLoading traning images to Custom Vision Project...");
            CustomVisionProjectTraning traning = new CustomVisionProjectTraning(trainingConfig);

            int ignoredImages = await traning.LoadWithCOCO(data, isDetectionModel);

            if (ignoredImages == 0)
            {
                Console.WriteLine("done.");
            }
            else
            {
                Console.WriteLine($"done. Ignored {ignoredImages} image(s).");
            }

            if (train)
            {
                Console.Write($"\nTraning Custom Vision Project...");
                await traning.Train();

                Console.WriteLine("done.");
            }
            else
            {
                Console.WriteLine("Traning is not requested.");
            }
        }
        public async Task <int> LoadWithCOCO(COCODatasetFactory imageSet, bool isDetectionModel)
        {
            var imageUrlBatches = new List <List <ImageUrlCreateEntry> >();
            var imageUrlEntries = new List <ImageUrlCreateEntry>();
            var tagsInBatch     = new List <Guid>();
            Dictionary <int, Guid> categoriesToTags = new Dictionary <int, Guid>();

            int imagesIgnored = 0;

            foreach (var cat in imageSet.categoriesAndIds.Keys)
            {
                string name = imageSet.categoriesAndIds[cat];
                var    tags = configuration.tagList.Where(tag => tag.Name == name);
                if (tags.Any())
                {
                    categoriesToTags.Add(cat, tags.First().Id);
                }
                else
                {
                    var tag = await configuration.AddTagAsync(name);

                    categoriesToTags.Add(cat, tag.Id);
                }
            }

            for (int i = 0; i < imageSet.traningSet.Values.Count; i++)
            {
                var image = imageSet.traningSet.Values.ElementAt(i);

                List <Region> regions = null;
                IList <Guid>  tags    = null;

                if (isDetectionModel)
                {
                    regions = new List <Region>();
                    foreach (var bb in image.bounding_boxes)
                    {
                        Region region = new Region();
                        region.TagId = categoriesToTags[bb.category_id];

                        if (!tagsInBatch.Contains(region.TagId))
                        {
                            tagsInBatch.Add(region.TagId);
                        }

                        // normalized bounding box
                        region.Left   = bb.bboxArray[0] / image.imageWidth;
                        region.Width  = bb.bboxArray[2] / image.imageWidth;
                        region.Top    = bb.bboxArray[1] / image.imageHeight;
                        region.Height = bb.bboxArray[3] / image.imageHeight;

                        //x1, x2, y1, y2
                        //[bb[0], bb[0]+bb[2], bb[1], bb[1]+bb[3]]
                        regions.Add(region);
                    }


                    if (regions.Count == 0)
                    {
                        continue;
                    }
                }
                else
                {
                    tags = image.bounding_boxes.Select(bb => categoriesToTags[bb.category_id]).ToList();
                    if (tags.Count == 0)
                    {
                        continue;
                    }

                    foreach (var t in tags)
                    {
                        if (!tagsInBatch.Contains(t))
                        {
                            tagsInBatch.Add(t);
                        }
                    }
                }

                // Traning batch cannot have more than 20 different tags (across all regions)
                bool tooManyTags = false;
                if (tagsInBatch.Count > 19)
                {
                    //If more than 20 tags, "rewind" one image back, we will add this image into the next batch
                    i--;
                    tooManyTags = true;
                }

                if (!tooManyTags) // if not too many tags with this image included, add this image
                {
                    ImageUrlCreateEntry entry =
                        isDetectionModel ? new ImageUrlCreateEntry(image.coco_url, null, regions) :
                        new ImageUrlCreateEntry(image.coco_url, tags);
                    imageUrlEntries.Add(entry);
                }

                // 64 is maximim batch size for Custom Vision, 20 is maximum number of distinct tags per batch
                // If exceeds, add this batch to the list, and start a new batch
                if (imageUrlEntries.Count > 63 || tooManyTags)
                {
                    imageUrlBatches.Add(imageUrlEntries);

                    tagsInBatch.Clear();
                    imageUrlEntries = new List <ImageUrlCreateEntry>();
                }
            }


            if (imageUrlEntries.Count > 0)
            {
                imageUrlBatches.Add(imageUrlEntries);
            }

            foreach (var batch in imageUrlBatches)
            {
                if (batch.Count == 0)
                {
                    continue;
                }

                var createImagesResult = await configuration.trainingApi.CreateImagesFromUrlsWithHttpMessagesAsync(configuration.project.Id,
                                                                                                                   new ImageUrlCreateBatch(batch));

                if (createImagesResult.Response.IsSuccessStatusCode)
                {
                    if (!createImagesResult.Body.IsBatchSuccessful)
                    {
                        //Maybe it's actually OK or we submitted duplicates (OKDuplicate Status)
                        var notOKImages = createImagesResult.Body.Images.Where(im => (im.Status != "OKDuplicate" && im.Status != "OK" &&
                                                                                      im.Status != "ErrorTagLimitExceed"));          // Custom Vision may decline an image with too many regions, but reports it as too many tags
                        if (notOKImages != null && notOKImages.Count() > 0)
                        {
                            var message = await createImagesResult.Response.Content.ReadAsStringAsync();

                            throw new Exception($"Failed to create a trainig image batch (batch is not successful). Result:\n {message}");
                        }
                        else
                        {
                            var tooManyTags = createImagesResult.Body.Images.Where(im => (im.Status == "ErrorTagLimitExceed"));
                            if (tooManyTags != null)
                            {
                                imagesIgnored += tooManyTags.Count();
                            }
                        }
                    }
                }
                else
                {
                    var message = createImagesResult.Response.Content.ReadAsStringAsync();
                    throw new Exception($"Failed to create a trainig image batch ({createImagesResult.Response.ReasonPhrase}).");
                }
            }

            return(imagesIgnored);
        }