From 37c45c3d6bf4f1c6f152f22575b33edb3aac1aa6 Mon Sep 17 00:00:00 2001 From: Marcus Turewicz <24448509+marcusturewicz@users.noreply.github.com> Date: Sat, 8 Aug 2020 06:36:36 +1000 Subject: [PATCH] C# ResNet50 v2 sample/tutorial (#4722) C# ResNet50 v2 sample Update samples README --- .../LabelMap.cs | 1006 +++++++++++++++++ ...oft.ML.OnnxRuntime.ResNet50v2Sample.csproj | 14 + .../Prediction.cs | 8 + .../Program.cs | 80 ++ .../README.md | 169 +++ .../dog.jpeg | Bin 0 -> 6888 bytes samples/README.md | 1 + 7 files changed, 1278 insertions(+) create mode 100644 csharp/sample/Microsoft.ML.OnnxRuntime.ResNet50v2Sample/LabelMap.cs create mode 100644 csharp/sample/Microsoft.ML.OnnxRuntime.ResNet50v2Sample/Microsoft.ML.OnnxRuntime.ResNet50v2Sample.csproj create mode 100644 csharp/sample/Microsoft.ML.OnnxRuntime.ResNet50v2Sample/Prediction.cs create mode 100644 csharp/sample/Microsoft.ML.OnnxRuntime.ResNet50v2Sample/Program.cs create mode 100644 csharp/sample/Microsoft.ML.OnnxRuntime.ResNet50v2Sample/README.md create mode 100644 csharp/sample/Microsoft.ML.OnnxRuntime.ResNet50v2Sample/dog.jpeg diff --git a/csharp/sample/Microsoft.ML.OnnxRuntime.ResNet50v2Sample/LabelMap.cs b/csharp/sample/Microsoft.ML.OnnxRuntime.ResNet50v2Sample/LabelMap.cs new file mode 100644 index 0000000000..90cb514c6f --- /dev/null +++ b/csharp/sample/Microsoft.ML.OnnxRuntime.ResNet50v2Sample/LabelMap.cs @@ -0,0 +1,1006 @@ +namespace Microsoft.ML.OnnxRuntime.ResNet50v2Sample +{ + public class LabelMap + { + public static readonly string[] Labels = new[] {"tench", + "goldfish", + "great white shark", + "tiger shark", + "hammerhead shark", + "electric ray", + "stingray", + "cock", + "hen", + "ostrich", + "brambling", + "goldfinch", + "house finch", + "junco", + "indigo bunting", + "American robin", + "bulbul", + "jay", + "magpie", + "chickadee", + "American dipper", + "kite", + "bald eagle", + "vulture", + "great grey owl", + "fire salamander", + "smooth newt", + "newt", + "spotted salamander", + "axolotl", + "American bullfrog", + "tree frog", + "tailed frog", + "loggerhead sea turtle", + "leatherback sea turtle", + "mud turtle", + "terrapin", + "box turtle", + "banded gecko", + "green iguana", + "Carolina anole", + "desert grassland whiptail lizard", + "agama", + "frilled-necked lizard", + "alligator lizard", + "Gila monster", + "European green lizard", + "chameleon", + "Komodo dragon", + "Nile crocodile", + "American alligator", + "triceratops", + "worm snake", + "ring-necked snake", + "eastern hog-nosed snake", + "smooth green snake", + "kingsnake", + "garter snake", + "water snake", + "vine snake", + "night snake", + "boa constrictor", + "African rock python", + "Indian cobra", + "green mamba", + "sea snake", + "Saharan horned viper", + "eastern diamondback rattlesnake", + "sidewinder", + "trilobite", + "harvestman", + "scorpion", + "yellow garden spider", + "barn spider", + "European garden spider", + "southern black widow", + "tarantula", + "wolf spider", + "tick", + "centipede", + "black grouse", + "ptarmigan", + "ruffed grouse", + "prairie grouse", + "peacock", + "quail", + "partridge", + "grey parrot", + "macaw", + "sulphur-crested cockatoo", + "lorikeet", + "coucal", + "bee eater", + "hornbill", + "hummingbird", + "jacamar", + "toucan", + "duck", + "red-breasted merganser", + "goose", + "black swan", + "tusker", + "echidna", + "platypus", + "wallaby", + "koala", + "wombat", + "jellyfish", + "sea anemone", + "brain coral", + "flatworm", + "nematode", + "conch", + "snail", + "slug", + "sea slug", + "chiton", + "chambered nautilus", + "Dungeness crab", + "rock crab", + "fiddler crab", + "red king crab", + "American lobster", + "spiny lobster", + "crayfish", + "hermit crab", + "isopod", + "white stork", + "black stork", + "spoonbill", + "flamingo", + "little blue heron", + "great egret", + "bittern", + "crane (bird)", + "limpkin", + "common gallinule", + "American coot", + "bustard", + "ruddy turnstone", + "dunlin", + "common redshank", + "dowitcher", + "oystercatcher", + "pelican", + "king penguin", + "albatross", + "grey whale", + "killer whale", + "dugong", + "sea lion", + "Chihuahua", + "Japanese Chin", + "Maltese", + "Pekingese", + "Shih Tzu", + "King Charles Spaniel", + "Papillon", + "toy terrier", + "Rhodesian Ridgeback", + "Afghan Hound", + "Basset Hound", + "Beagle", + "Bloodhound", + "Bluetick Coonhound", + "Black and Tan Coonhound", + "Treeing Walker Coonhound", + "English foxhound", + "Redbone Coonhound", + "borzoi", + "Irish Wolfhound", + "Italian Greyhound", + "Whippet", + "Ibizan Hound", + "Norwegian Elkhound", + "Otterhound", + "Saluki", + "Scottish Deerhound", + "Weimaraner", + "Staffordshire Bull Terrier", + "American Staffordshire Terrier", + "Bedlington Terrier", + "Border Terrier", + "Kerry Blue Terrier", + "Irish Terrier", + "Norfolk Terrier", + "Norwich Terrier", + "Yorkshire Terrier", + "Wire Fox Terrier", + "Lakeland Terrier", + "Sealyham Terrier", + "Airedale Terrier", + "Cairn Terrier", + "Australian Terrier", + "Dandie Dinmont Terrier", + "Boston Terrier", + "Miniature Schnauzer", + "Giant Schnauzer", + "Standard Schnauzer", + "Scottish Terrier", + "Tibetan Terrier", + "Australian Silky Terrier", + "Soft-coated Wheaten Terrier", + "West Highland White Terrier", + "Lhasa Apso", + "Flat-Coated Retriever", + "Curly-coated Retriever", + "Golden Retriever", + "Labrador Retriever", + "Chesapeake Bay Retriever", + "German Shorthaired Pointer", + "Vizsla", + "English Setter", + "Irish Setter", + "Gordon Setter", + "Brittany", + "Clumber Spaniel", + "English Springer Spaniel", + "Welsh Springer Spaniel", + "Cocker Spaniels", + "Sussex Spaniel", + "Irish Water Spaniel", + "Kuvasz", + "Schipperke", + "Groenendael", + "Malinois", + "Briard", + "Australian Kelpie", + "Komondor", + "Old English Sheepdog", + "Shetland Sheepdog", + "collie", + "Border Collie", + "Bouvier des Flandres", + "Rottweiler", + "German Shepherd Dog", + "Dobermann", + "Miniature Pinscher", + "Greater Swiss Mountain Dog", + "Bernese Mountain Dog", + "Appenzeller Sennenhund", + "Entlebucher Sennenhund", + "Boxer", + "Bullmastiff", + "Tibetan Mastiff", + "French Bulldog", + "Great Dane", + "St. Bernard", + "husky", + "Alaskan Malamute", + "Siberian Husky", + "Dalmatian", + "Affenpinscher", + "Basenji", + "pug", + "Leonberger", + "Newfoundland", + "Pyrenean Mountain Dog", + "Samoyed", + "Pomeranian", + "Chow Chow", + "Keeshond", + "Griffon Bruxellois", + "Pembroke Welsh Corgi", + "Cardigan Welsh Corgi", + "Toy Poodle", + "Miniature Poodle", + "Standard Poodle", + "Mexican hairless dog", + "grey wolf", + "Alaskan tundra wolf", + "red wolf", + "coyote", + "dingo", + "dhole", + "African wild dog", + "hyena", + "red fox", + "kit fox", + "Arctic fox", + "grey fox", + "tabby cat", + "tiger cat", + "Persian cat", + "Siamese cat", + "Egyptian Mau", + "cougar", + "lynx", + "leopard", + "snow leopard", + "jaguar", + "lion", + "tiger", + "cheetah", + "brown bear", + "American black bear", + "polar bear", + "sloth bear", + "mongoose", + "meerkat", + "tiger beetle", + "ladybug", + "ground beetle", + "longhorn beetle", + "leaf beetle", + "dung beetle", + "rhinoceros beetle", + "weevil", + "fly", + "bee", + "ant", + "grasshopper", + "cricket", + "stick insect", + "cockroach", + "mantis", + "cicada", + "leafhopper", + "lacewing", + "dragonfly", + "damselfly", + "red admiral", + "ringlet", + "monarch butterfly", + "small white", + "sulphur butterfly", + "gossamer-winged butterfly", + "starfish", + "sea urchin", + "sea cucumber", + "cottontail rabbit", + "hare", + "Angora rabbit", + "hamster", + "porcupine", + "fox squirrel", + "marmot", + "beaver", + "guinea pig", + "common sorrel", + "zebra", + "pig", + "wild boar", + "warthog", + "hippopotamus", + "ox", + "water buffalo", + "bison", + "ram", + "bighorn sheep", + "Alpine ibex", + "hartebeest", + "impala", + "gazelle", + "dromedary", + "llama", + "weasel", + "mink", + "European polecat", + "black-footed ferret", + "otter", + "skunk", + "badger", + "armadillo", + "three-toed sloth", + "orangutan", + "gorilla", + "chimpanzee", + "gibbon", + "siamang", + "guenon", + "patas monkey", + "baboon", + "macaque", + "langur", + "black-and-white colobus", + "proboscis monkey", + "marmoset", + "white-headed capuchin", + "howler monkey", + "titi", + "Geoffroy's spider monkey", + "common squirrel monkey", + "ring-tailed lemur", + "indri", + "Asian elephant", + "African bush elephant", + "red panda", + "giant panda", + "snoek", + "eel", + "coho salmon", + "rock beauty", + "clownfish", + "sturgeon", + "garfish", + "lionfish", + "pufferfish", + "abacus", + "abaya", + "academic gown", + "accordion", + "acoustic guitar", + "aircraft carrier", + "airliner", + "airship", + "altar", + "ambulance", + "amphibious vehicle", + "analog clock", + "apiary", + "apron", + "waste container", + "assault rifle", + "backpack", + "bakery", + "balance beam", + "balloon", + "ballpoint pen", + "Band-Aid", + "banjo", + "baluster", + "barbell", + "barber chair", + "barbershop", + "barn", + "barometer", + "barrel", + "wheelbarrow", + "baseball", + "basketball", + "bassinet", + "bassoon", + "swimming cap", + "bath towel", + "bathtub", + "station wagon", + "lighthouse", + "beaker", + "military cap", + "beer bottle", + "beer glass", + "bell-cot", + "bib", + "tandem bicycle", + "bikini", + "ring binder", + "binoculars", + "birdhouse", + "boathouse", + "bobsleigh", + "bolo tie", + "poke bonnet", + "bookcase", + "bookstore", + "bottle cap", + "bow", + "bow tie", + "brass", + "bra", + "breakwater", + "breastplate", + "broom", + "bucket", + "buckle", + "bulletproof vest", + "high-speed train", + "butcher shop", + "taxicab", + "cauldron", + "candle", + "cannon", + "canoe", + "can opener", + "cardigan", + "car mirror", + "carousel", + "tool kit", + "carton", + "car wheel", + "automated teller machine", + "cassette", + "cassette player", + "castle", + "catamaran", + "CD player", + "cello", + "mobile phone", + "chain", + "chain-link fence", + "chain mail", + "chainsaw", + "chest", + "chiffonier", + "chime", + "china cabinet", + "Christmas stocking", + "church", + "movie theater", + "cleaver", + "cliff dwelling", + "cloak", + "clogs", + "cocktail shaker", + "coffee mug", + "coffeemaker", + "coil", + "combination lock", + "computer keyboard", + "confectionery store", + "container ship", + "convertible", + "corkscrew", + "cornet", + "cowboy boot", + "cowboy hat", + "cradle", + "crane (machine)", + "crash helmet", + "crate", + "infant bed", + "Crock Pot", + "croquet ball", + "crutch", + "cuirass", + "dam", + "desk", + "desktop computer", + "rotary dial telephone", + "diaper", + "digital clock", + "digital watch", + "dining table", + "dishcloth", + "dishwasher", + "disc brake", + "dock", + "dog sled", + "dome", + "doormat", + "drilling rig", + "drum", + "drumstick", + "dumbbell", + "Dutch oven", + "electric fan", + "electric guitar", + "electric locomotive", + "entertainment center", + "envelope", + "espresso machine", + "face powder", + "feather boa", + "filing cabinet", + "fireboat", + "fire engine", + "fire screen sheet", + "flagpole", + "flute", + "folding chair", + "football helmet", + "forklift", + "fountain", + "fountain pen", + "four-poster bed", + "freight car", + "French horn", + "frying pan", + "fur coat", + "garbage truck", + "gas mask", + "gas pump", + "goblet", + "go-kart", + "golf ball", + "golf cart", + "gondola", + "gong", + "gown", + "grand piano", + "greenhouse", + "grille", + "grocery store", + "guillotine", + "barrette", + "hair spray", + "half-track", + "hammer", + "hamper", + "hair dryer", + "hand-held computer", + "handkerchief", + "hard disk drive", + "harmonica", + "harp", + "harvester", + "hatchet", + "holster", + "home theater", + "honeycomb", + "hook", + "hoop skirt", + "horizontal bar", + "horse-drawn vehicle", + "hourglass", + "iPod", + "clothes iron", + "jack-o'-lantern", + "jeans", + "jeep", + "T-shirt", + "jigsaw puzzle", + "pulled rickshaw", + "joystick", + "kimono", + "knee pad", + "knot", + "lab coat", + "ladle", + "lampshade", + "laptop computer", + "lawn mower", + "lens cap", + "paper knife", + "library", + "lifeboat", + "lighter", + "limousine", + "ocean liner", + "lipstick", + "slip-on shoe", + "lotion", + "speaker", + "loupe", + "sawmill", + "magnetic compass", + "mail bag", + "mailbox", + "tights", + "tank suit", + "manhole cover", + "maraca", + "marimba", + "mask", + "match", + "maypole", + "maze", + "measuring cup", + "medicine chest", + "megalith", + "microphone", + "microwave oven", + "military uniform", + "milk can", + "minibus", + "miniskirt", + "minivan", + "missile", + "mitten", + "mixing bowl", + "mobile home", + "Model T", + "modem", + "monastery", + "monitor", + "moped", + "mortar", + "square academic cap", + "mosque", + "mosquito net", + "scooter", + "mountain bike", + "tent", + "computer mouse", + "mousetrap", + "moving van", + "muzzle", + "nail", + "neck brace", + "necklace", + "nipple", + "notebook computer", + "obelisk", + "oboe", + "ocarina", + "odometer", + "oil filter", + "organ", + "oscilloscope", + "overskirt", + "bullock cart", + "oxygen mask", + "packet", + "paddle", + "paddle wheel", + "padlock", + "paintbrush", + "pajamas", + "palace", + "pan flute", + "paper towel", + "parachute", + "parallel bars", + "park bench", + "parking meter", + "passenger car", + "patio", + "payphone", + "pedestal", + "pencil case", + "pencil sharpener", + "perfume", + "Petri dish", + "photocopier", + "plectrum", + "Pickelhaube", + "picket fence", + "pickup truck", + "pier", + "piggy bank", + "pill bottle", + "pillow", + "ping-pong ball", + "pinwheel", + "pirate ship", + "pitcher", + "hand plane", + "planetarium", + "plastic bag", + "plate rack", + "plow", + "plunger", + "Polaroid camera", + "pole", + "police van", + "poncho", + "billiard table", + "soda bottle", + "pot", + "potter's wheel", + "power drill", + "prayer rug", + "printer", + "prison", + "projectile", + "projector", + "hockey puck", + "punching bag", + "purse", + "quill", + "quilt", + "race car", + "racket", + "radiator", + "radio", + "radio telescope", + "rain barrel", + "recreational vehicle", + "reel", + "reflex camera", + "refrigerator", + "remote control", + "restaurant", + "revolver", + "rifle", + "rocking chair", + "rotisserie", + "eraser", + "rugby ball", + "ruler", + "running shoe", + "safe", + "safety pin", + "salt shaker", + "sandal", + "sarong", + "saxophone", + "scabbard", + "weighing scale", + "school bus", + "schooner", + "scoreboard", + "CRT screen", + "screw", + "screwdriver", + "seat belt", + "sewing machine", + "shield", + "shoe store", + "shoji", + "shopping basket", + "shopping cart", + "shovel", + "shower cap", + "shower curtain", + "ski", + "ski mask", + "sleeping bag", + "slide rule", + "sliding door", + "slot machine", + "snorkel", + "snowmobile", + "snowplow", + "soap dispenser", + "soccer ball", + "sock", + "solar thermal collector", + "sombrero", + "soup bowl", + "space bar", + "space heater", + "space shuttle", + "spatula", + "motorboat", + "spider web", + "spindle", + "sports car", + "spotlight", + "stage", + "steam locomotive", + "through arch bridge", + "steel drum", + "stethoscope", + "scarf", + "stone wall", + "stopwatch", + "stove", + "strainer", + "tram", + "stretcher", + "couch", + "stupa", + "submarine", + "suit", + "sundial", + "sunglass", + "sunglasses", + "sunscreen", + "suspension bridge", + "mop", + "sweatshirt", + "swimsuit", + "swing", + "switch", + "syringe", + "table lamp", + "tank", + "tape player", + "teapot", + "teddy bear", + "television", + "tennis ball", + "thatched roof", + "front curtain", + "thimble", + "threshing machine", + "throne", + "tile roof", + "toaster", + "tobacco shop", + "toilet seat", + "torch", + "totem pole", + "tow truck", + "toy store", + "tractor", + "semi-trailer truck", + "tray", + "trench coat", + "tricycle", + "trimaran", + "tripod", + "triumphal arch", + "trolleybus", + "trombone", + "tub", + "turnstile", + "typewriter keyboard", + "umbrella", + "unicycle", + "upright piano", + "vacuum cleaner", + "vase", + "vault", + "velvet", + "vending machine", + "vestment", + "viaduct", + "violin", + "volleyball", + "waffle iron", + "wall clock", + "wallet", + "wardrobe", + "military aircraft", + "sink", + "washing machine", + "water bottle", + "water jug", + "water tower", + "whiskey jug", + "whistle", + "wig", + "window screen", + "window shade", + "Windsor tie", + "wine bottle", + "wing", + "wok", + "wooden spoon", + "wool", + "split-rail fence", + "shipwreck", + "yawl", + "yurt", + "website", + "comic book", + "crossword", + "traffic sign", + "traffic light", + "dust jacket", + "menu", + "plate", + "guacamole", + "consomme", + "hot pot", + "trifle", + "ice cream", + "ice pop", + "baguette", + "bagel", + "pretzel", + "cheeseburger", + "hot dog", + "mashed potato", + "cabbage", + "broccoli", + "cauliflower", + "zucchini", + "spaghetti squash", + "acorn squash", + "butternut squash", + "cucumber", + "artichoke", + "bell pepper", + "cardoon", + "mushroom", + "Granny Smith", + "strawberry", + "orange", + "lemon", + "fig", + "pineapple", + "banana", + "jackfruit", + "custard apple", + "pomegranate", + "hay", + "carbonara", + "chocolate syrup", + "dough", + "meatloaf", + "pizza", + "pot pie", + "burrito", + "red wine", + "espresso", + "cup", + "eggnog", + "alp", + "bubble", + "cliff", + "coral reef", + "geyser", + "lakeshore", + "promontory", + "shoal", + "seashore", + "valley", + "volcano", + "baseball player", + "bridegroom", + "scuba diver", + "rapeseed", + "daisy", + "yellow lady's slipper", + "corn", + "acorn", + "rose hip", + "horse chestnut seed", + "coral fungus", + "agaric", + "gyromitra", + "stinkhorn mushroom", + "earth star", + "hen-of-the-woods", + "bolete", + "ear", + "toilet paper"}; + } +} \ No newline at end of file diff --git a/csharp/sample/Microsoft.ML.OnnxRuntime.ResNet50v2Sample/Microsoft.ML.OnnxRuntime.ResNet50v2Sample.csproj b/csharp/sample/Microsoft.ML.OnnxRuntime.ResNet50v2Sample/Microsoft.ML.OnnxRuntime.ResNet50v2Sample.csproj new file mode 100644 index 0000000000..504c667860 --- /dev/null +++ b/csharp/sample/Microsoft.ML.OnnxRuntime.ResNet50v2Sample/Microsoft.ML.OnnxRuntime.ResNet50v2Sample.csproj @@ -0,0 +1,14 @@ + + + + Exe + netcoreapp3.1 + 8.0 + + + + + + + + diff --git a/csharp/sample/Microsoft.ML.OnnxRuntime.ResNet50v2Sample/Prediction.cs b/csharp/sample/Microsoft.ML.OnnxRuntime.ResNet50v2Sample/Prediction.cs new file mode 100644 index 0000000000..1a08f67fcd --- /dev/null +++ b/csharp/sample/Microsoft.ML.OnnxRuntime.ResNet50v2Sample/Prediction.cs @@ -0,0 +1,8 @@ +namespace Microsoft.ML.OnnxRuntime.ResNet50v2Sample +{ + internal class Prediction + { + public string Label { get; set; } + public float Confidence { get; set; } + } +} \ No newline at end of file diff --git a/csharp/sample/Microsoft.ML.OnnxRuntime.ResNet50v2Sample/Program.cs b/csharp/sample/Microsoft.ML.OnnxRuntime.ResNet50v2Sample/Program.cs new file mode 100644 index 0000000000..65afa6186c --- /dev/null +++ b/csharp/sample/Microsoft.ML.OnnxRuntime.ResNet50v2Sample/Program.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Microsoft.ML.OnnxRuntime.Tensors; +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.Formats; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; + +namespace Microsoft.ML.OnnxRuntime.ResNet50v2Sample +{ + class Program + { + public static void Main(string[] args) + { + // Read paths + string modelFilePath = args[0]; + string imageFilePath = args[1]; + + // Read image + using Image image = Image.Load(imageFilePath, out IImageFormat format); + + // Resize image + using Stream imageStream = new MemoryStream(); + image.Mutate(x => + { + x.Resize(new ResizeOptions + { + Size = new Size(224, 224), + Mode = ResizeMode.Crop + }); + }); + image.Save(imageStream, format); + + // Preprocess image + Tensor input = new DenseTensor(new[] { 1, 3, 224, 224 }); + var mean = new[] { 0.485f, 0.456f, 0.406f }; + var stddev = new[] { 0.229f, 0.224f, 0.225f }; + for (int y = 0; y < image.Height; y++) + { + Span pixelSpan = image.GetPixelRowSpan(y); + for (int x = 0; x < image.Width; x++) + { + input[0, 0, y, x] = ((pixelSpan[x].R / 255f) - mean[0]) / stddev[0]; + input[0, 1, y, x] = ((pixelSpan[x].G / 255f) - mean[1]) / stddev[1]; + input[0, 2, y, x] = ((pixelSpan[x].B / 255f) - mean[2]) / stddev[2]; + } + } + + // Setup inputs + var inputs = new List + { + NamedOnnxValue.CreateFromTensor("data", input) + }; + + // Run inference + using var session = new InferenceSession(modelFilePath); + using IDisposableReadOnlyCollection results = session.Run(inputs); + + // Postprocess to get softmax vector + IEnumerable output = results.First().AsEnumerable(); + float sum = output.Sum(x => (float)Math.Exp(x)); + IEnumerable softmax = output.Select(x => (float)Math.Exp(x) / sum); + + // Extract top 10 predicted classes + IEnumerable top10 = softmax.Select((x, i) => new Prediction { Label = LabelMap.Labels[i], Confidence = x }) + .OrderByDescending(x => x.Confidence) + .Take(10); + + // Print results to console + Console.WriteLine("Top 10 predictions for ResNet50 v2..."); + Console.WriteLine("--------------------------------------------------------------"); + foreach (var t in top10) + { + Console.WriteLine($"Label: {t.Label}, Confidence: {t.Confidence}"); + } + } + } +} diff --git a/csharp/sample/Microsoft.ML.OnnxRuntime.ResNet50v2Sample/README.md b/csharp/sample/Microsoft.ML.OnnxRuntime.ResNet50v2Sample/README.md new file mode 100644 index 0000000000..7e72547624 --- /dev/null +++ b/csharp/sample/Microsoft.ML.OnnxRuntime.ResNet50v2Sample/README.md @@ -0,0 +1,169 @@ +# C# Sample: ResNet50 v2 + +The sample walks through how to run a pretrained ResNet50 v2 ONNX model using the Onnx Runtime C# API. + +The source code for this sample is available [here](Program.cs). + +## Prerequisites + +To run this sample, you'll need the following things: + +1. Install [.NET Core 3.1](https://dotnet.microsoft.com/download/dotnet-core/3.1) or higher for you OS (Mac, Windows or Linux). +2. Download the [ResNet50 v2](https://github.com/onnx/models/blob/master/vision/classification/resnet/model/resnet50-v2-7.onnx) ONNX model to your local system. +3. Download [this picture of a dog](dog.jpeg) to test the model. You can also use any image you like. + +## Getting Started + +Now we have everything set up, we can start adding code to run the model on the image. We'll do this in the main method of the program for simplicity. + +### Read paths + +Firstly, let's read the path to the model and path to the image we want to test in through program arguments: + +```cs +string modelFilePath = args[0]; +string imageFilePath = args[1]; +``` + +### Read image + +Next, we will read the image in using the cross-platform image library [ImageSharp](https://www.nuget.org/packages/SixLabors.ImageSharp): + +```cs +using Image image = Image.Load(imageFilePath, out IImageFormat format); +``` + +Note, we're specifically reading the `Rgb24` type so we can efficiently preprocess the image in a later step. + +### Resize image + +Next, we will resize the image to the appropriate size that the model is expecting; 224 pixels by 224 pixels: + +```cs +using Stream imageStream = new MemoryStream(); +image.Mutate(x => +{ + x.Resize(new ResizeOptions + { + Size = new Size(224, 224), + Mode = ResizeMode.Crop + }); +}); +image.Save(imageStream, format); +``` + +Note, we're doing a centered crop resize to preserve aspect ratio. + +### Preprocess image + +Next, we will preprocess the image according to the [requirements of the model](https://github.com/onnx/models/tree/master/vision/classification/resnet#preprocessing): + +```cs +Tensor input = new DenseTensor(new[] { 1, 3, 224, 224 }); +var mean = new[] { 0.485f, 0.456f, 0.406f }; +var stddev = new[] { 0.229f, 0.224f, 0.225f }; +for (int y = 0; y < image.Height; y++) +{ + Span pixelSpan = image.GetPixelRowSpan(y); + for (int x = 0; x < image.Width; x++) + { + input[0, 0, y, x] = ((pixelSpan[x].R / 255f) - mean[0]) / stddev[0]; + input[0, 1, y, x] = ((pixelSpan[x].G / 255f) - mean[1]) / stddev[1]; + input[0, 2, y, x] = ((pixelSpan[x].B / 255f) - mean[2]) / stddev[2]; + } +} +``` + +Here, we're creating a Tensor of the required size `(batch-size, channels, height, width)`, accessing the pixel values, preprocessing them and finally assigning them to the tensor at the appropriate indicies. + +### Setup inputs + +Next, we will create the inputs to the model: + +```cs +var inputs = new List +{ + NamedOnnxValue.CreateFromTensor("data", input) +}; +``` + +To check the input node names for an ONNX model, you can use [Netron](https://github.com/lutzroeder/netron) to visualise the model and see input/output names. In this case, this model has `data` as the input node name. + +### Run inference + +Next, we will create an inference session and run the input through it: + +```cs +using var session = new InferenceSession(modelFilePath); +using IDisposableReadOnlyCollection results = session.Run(inputs); +``` + +### Postprocess output + +Next, we will need to postprocess the output to get the softmax vector, as this is not handled by the model itself: + +```cs +IEnumerable output = results.First().AsEnumerable(); +float sum = output.Sum(x => (float)Math.Exp(x)); +IEnumerable softmax = output.Select(x => (float)Math.Exp(x) / sum); +``` + +Other models may apply a Softmax node before the output, in which case you won't need this step. Again, you can use Netron to see the model outputs. + +### Extract top 10 + +Next, we will extract the top 10 class predictions: + +```cs +IEnumerable top10 = softmax.Select((x, i) => new Prediction { Label = LabelMap.Labels[i], Confidence = x }) + .OrderByDescending(x => x.Confidence) + .Take(10); +``` + +### Print results + +Next, we will print the top 10 results to the console: + +```cs +Console.WriteLine("Top 10 predictions for ResNet50 v2..."); +Console.WriteLine("--------------------------------------------------------------"); +foreach (var t in top10) +{ + Console.WriteLine($"Label: {t.Label}, Confidence: {t.Confidence}"); +} +``` + +## Running the program + +Now the program is created, we can run it will the following command: + +``` +dotnet run [path-to-model] [path-to-image] +``` + +e.g. + +``` +dotnet run ~/Downloads/resnet50-v2-7.onnx ~/Downloads/dog.jpeg +``` + +Running this on the following image: + +![](dog.jpeg) + +We get the following output: + +``` +Top 10 predictions for ResNet50 v2... +-------------------------------------------------------------- +Label: Golden Retriever, Confidence: 0.9212826 +Label: Kuvasz, Confidence: 0.026514154 +Label: Clumber Spaniel, Confidence: 0.012455719 +Label: Labrador Retriever, Confidence: 0.004103844 +Label: Saluki, Confidence: 0.0033182495 +Label: Flat-Coated Retriever, Confidence: 0.0032045357 +Label: English Setter, Confidence: 0.002513516 +Label: Brittany, Confidence: 0.0023459378 +Label: Cocker Spaniels, Confidence: 0.0019343802 +Label: Sussex Spaniel, Confidence: 0.0019247672 +``` diff --git a/csharp/sample/Microsoft.ML.OnnxRuntime.ResNet50v2Sample/dog.jpeg b/csharp/sample/Microsoft.ML.OnnxRuntime.ResNet50v2Sample/dog.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..8c4f1ce11a1563196d84ec27dcd797b4b1257453 GIT binary patch literal 6888 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 m0D1;lHCM_n+%Ms3xsOOtRmzm9_+-G!a