1-  // <SnippetAddUsings> 
1+ // <SnippetAddUsings> 
22using  System ; 
33using  System . Collections . Generic ; 
44using  System . IO ; 
55using  System . Linq ; 
6- using  Microsoft . Data . DataView ; 
76using  Microsoft . ML ; 
8- using  Microsoft . ML . Core . Data ; 
97using  Microsoft . ML . Data ; 
10- using  Microsoft . ML . ImageAnalytics ; 
8+ using  Microsoft . ML . Data . IO ; 
119using  Microsoft . ML . Trainers ; 
10+ using  Microsoft . ML . Transforms . Image ; 
1211// </SnippetAddUsings> 
1312
1413namespace  TransferLearningTF 
@@ -26,27 +25,26 @@ class Program
2625        static readonly  string  _inputImageClassifierZip  =  Path . Combine ( _assetsPath ,  "inputs-predict" ,  "imageClassifier.zip" ) ; 
2726        static readonly  string  _outputImageClassifierZip  =  Path . Combine ( _assetsPath ,  "outputs" ,  "imageClassifier.zip" ) ; 
2827        private  static string  LabelTokey  =  nameof ( LabelTokey ) ; 
29-         private  static string  ImageReal  =  nameof ( ImageReal ) ; 
3028        private  static string  PredictedLabelValue  =  nameof ( PredictedLabelValue ) ; 
3129        // </SnippetDeclareGlobalVariables> 
3230
3331        static void  Main ( string [ ]  args ) 
3432        { 
3533            // Create MLContext to be shared across the model creation workflow objects  
3634            // <SnippetCreateMLContext> 
37-             MLContext  mlContext  =  new  MLContext ( seed : 1 ) ; 
35+             MLContext  mlContext  =  new  MLContext ( seed :   1 ) ; 
3836            // </SnippetCreateMLContext> 
3937
4038            // <SnippetCallReuseAndTuneInceptionModel> 
41-             ReuseAndTuneInceptionModel ( mlContext ,  _trainTagsTsv ,  _trainImagesFolder ,  _inceptionPb ,  _outputImageClassifierZip ) ; 
39+             var   model   =   ReuseAndTuneInceptionModel ( mlContext ,  _trainTagsTsv ,  _trainImagesFolder ,  _inceptionPb ,  _outputImageClassifierZip ) ; 
4240            // </SnippetCallReuseAndTuneInceptionModel> 
4341
4442            // <SnippetCallClassifyImages> 
45-             ClassifyImages ( mlContext ,  _predictImageListTsv ,  _predictImagesFolder ,  _outputImageClassifierZip ) ; 
43+             ClassifyImages ( mlContext ,  _predictImageListTsv ,  _predictImagesFolder ,  _outputImageClassifierZip ,   model ) ; 
4644            // </SnippetCallClassifyImages> 
4745
4846            // <SnippetCallClassifySingleImage> 
49-             ClassifySingleImage ( mlContext ,  _predictSingleImage ,  _outputImageClassifierZip ) ; 
47+             ClassifySingleImage ( mlContext ,  _predictSingleImage ,  _outputImageClassifierZip ,   model ) ; 
5048            // </SnippetCallClassifySingleImage> 
5149        } 
5250
@@ -62,32 +60,34 @@ private struct InceptionSettings
6260        // </SnippetInceptionSettings> 
6361
6462        // Build and train model 
65-         public  static void  ReuseAndTuneInceptionModel ( MLContext  mlContext ,  string  dataLocation ,  string  imagesFolder ,  string  inputModelLocation ,  string  outputModelLocation ) 
63+         public  static ITransformer  ReuseAndTuneInceptionModel ( MLContext  mlContext ,  string  dataLocation ,  string  imagesFolder ,  string  inputModelLocation ,  string  outputModelLocation ) 
6664        { 
6765
6866            // <SnippetLoadData> 
69-             var  data  =  mlContext . Data . ReadFromTextFile < ImageData > ( path :  dataLocation ,  hasHeader :  false ) ; 
67+             var  data  =  mlContext . Data . LoadFromTextFile < ImageData > ( path :  dataLocation ,  hasHeader :  false ) ; 
7068            // </SnippetLoadData> 
7169
7270            // <SnippetMapValueToKey1> 
73-             var  estimator  =  mlContext . Transforms . Conversion . MapValueToKey ( outputColumnName :  LabelTokey ,  inputColumnName :  DefaultColumnNames . Label ) 
71+             var  estimator  =  mlContext . Transforms . Conversion . MapValueToKey ( outputColumnName :  LabelTokey ,  inputColumnName :  " Label" ) 
7472                            // </SnippetMapValueToKey1> 
7573                            // The image transforms transform the images into the model's expected format. 
7674                            // <SnippetImageTransforms> 
77-                             . Append ( mlContext . Transforms . LoadImages ( _trainImagesFolder ,   ( ImageReal ,   nameof ( ImageData . ImagePath ) ) ) ) 
78-                             . Append ( mlContext . Transforms . Resize ( outputColumnName :  ImageReal ,  imageWidth :  InceptionSettings . ImageWidth ,  imageHeight :  InceptionSettings . ImageHeight ,  inputColumnName :  ImageReal ) ) 
79-                             . Append ( mlContext . Transforms . ExtractPixels ( new   ImagePixelExtractorTransformer . ColumnInfo ( name :  "input" ,  inputColumnName :   ImageReal ,   interleave :   InceptionSettings . ChannelsLast ,  offset :  InceptionSettings . Mean ) ) ) 
75+                             . Append ( mlContext . Transforms . LoadImages ( outputColumnName :   "input" ,   imageFolder :   _trainImagesFolder ,   inputColumnName :   nameof ( ImageData . ImagePath ) ) ) 
76+                             . Append ( mlContext . Transforms . ResizeImages ( outputColumnName :  "input" ,  imageWidth :  InceptionSettings . ImageWidth ,  imageHeight :  InceptionSettings . ImageHeight ,  inputColumnName :  "input" ) ) 
77+                             . Append ( mlContext . Transforms . ExtractPixels ( outputColumnName :  "input" ,  interleavePixelColors :   InceptionSettings . ChannelsLast ,  offsetImage :  InceptionSettings . Mean ) ) 
8078                            // </SnippetImageTransforms> 
8179                            // The ScoreTensorFlowModel transform scores the TensorFlow model and allows communication  
8280                            // <SnippetScoreTensorFlowModel> 
83-                             . Append ( mlContext . Transforms . ScoreTensorFlowModel ( modelLocation :  inputModelLocation ,  outputColumnNames :  new [ ]  {  "softmax2_pre_activation"  } ,  inputColumnNames :  new [ ]  {  "input"  } ) ) 
81+                             . Append ( mlContext . Model . LoadTensorFlowModel ( inputModelLocation ) . 
82+                                 ScoreTensorFlowModel ( outputColumnNames :  new [ ]  {  "softmax2_pre_activation"  } ,  inputColumnNames :  new [ ]  {  "input"  } ,  addBatchDimensionInput :  true ) ) 
8483                            // </SnippetScoreTensorFlowModel> 
8584                            // <SnippetAddTrainer>  
86-                             . Append ( mlContext . MulticlassClassification . Trainers . LogisticRegression ( labelColumn :  LabelTokey ,  featureColumn :  "softmax2_pre_activation" ) ) 
85+                             . Append ( mlContext . MulticlassClassification . Trainers . LbfgsMaximumEntropy ( labelColumnName :  LabelTokey ,  featureColumnName :  "softmax2_pre_activation" ) ) 
8786                            // </SnippetAddTrainer> 
8887                            // <SnippetMapValueToKey2> 
89-                             . Append ( mlContext . Transforms . Conversion . MapKeyToValue ( ( PredictedLabelValue ,  DefaultColumnNames . PredictedLabel ) ) ) ; 
90-                             // </SnippetMapValueToKey2> 
88+                             . Append ( mlContext . Transforms . Conversion . MapKeyToValue ( PredictedLabelValue ,  "PredictedLabel" ) ) 
89+                             . AppendCacheCheckpoint ( mlContext ) ; 
90+             // </SnippetMapValueToKey2> 
9191
9292            // Train the model 
9393            Console . WriteLine ( "=============== Training classification model ===============" ) ; 
@@ -105,92 +105,67 @@ public static void ReuseAndTuneInceptionModel(MLContext mlContext, string dataLo
105105            // Create enumerables for both the ImageData and ImagePrediction DataViews  
106106            // for displaying results 
107107            // <SnippetEnumerateDataViews> 
108-             var  imageData  =  mlContext . CreateEnumerable < ImageData > ( data ,  false ,  true ) ; 
109-             var  imagePredictionData  =  mlContext . CreateEnumerable < ImagePrediction > ( predictions ,  false ,  true ) ; 
108+             var  imageData  =  mlContext . Data . CreateEnumerable < ImageData > ( data ,  false ,  true ) ; 
109+             var  imagePredictionData  =  mlContext . Data . CreateEnumerable < ImagePrediction > ( predictions ,  false ,  true ) ; 
110110            // </SnippetEnumerateDataViews> 
111111
112-             // Read the tags.tsv file and add the filepath to the image file name  
113-             // before loading into ImageData  
114-             // <SnippetCallPairAndDisplayResults1> 
115-             PairAndDisplayResults ( imageData ,  imagePredictionData ) ; 
116-             // </SnippetCallPairAndDisplayResults1> 
112+             // <SnippetCallDisplayResults1> 
113+             DisplayResults ( imagePredictionData ) ; 
114+             // </SnippetCallDisplayResults1> 
117115
118116            // Get some performance metrics on the model using training data 
119117            Console . WriteLine ( "=============== Classification metrics ===============" ) ; 
120118
121119            // <SnippetEvaluate>            
122-             var  regressionContext  =  new   MulticlassClassificationCatalog ( mlContext ) ; 
123-             var  metrics  =  regressionContext . Evaluate ( predictions ,  label :  LabelTokey ,  predictedLabel :   DefaultColumnNames . PredictedLabel ) ; 
120+             var  multiclassContext  =  mlContext . MulticlassClassification ; 
121+             var  metrics  =  multiclassContext . Evaluate ( predictions ,  labelColumnName :  LabelTokey ,  predictedLabelColumnName :   " PredictedLabel" ) ; 
124122            // </SnippetEvaluate> 
125123
126124            //<SnippetDisplayMetrics> 
127125            Console . WriteLine ( $ "LogLoss is: { metrics . LogLoss } ") ; 
128126            Console . WriteLine ( $ "PerClassLogLoss is: { String . Join ( " , " ,  metrics . PerClassLogLoss . Select ( c =>  c . ToString ( ) ) ) } ") ; 
129127            //</SnippetDisplayMetrics> 
130128
131-             // Save the model to assets/outputs 
132-             Console . WriteLine ( "=============== Save model to local file ===============" ) ; 
133- 
134-             // <SnippetSaveModel> 
135-             using  ( var  fileStream  =  new  FileStream ( outputModelLocation ,  FileMode . Create ) ) 
136-                 mlContext . Model . Save ( model ,  fileStream ) ; 
137-             // </SnippetSaveModel> 
138- 
139-             Console . WriteLine ( $ "Model saved: { outputModelLocation } ") ; 
129+             // <SnippetReturnModel> 
130+             return  model ; 
131+             // </SnippetReturnModel> 
140132        } 
141133
142-         public  static void  ClassifyImages ( MLContext  mlContext ,  string  dataLocation ,  string  imagesFolder ,  string  outputModelLocation ) 
134+         public  static void  ClassifyImages ( MLContext  mlContext ,  string  dataLocation ,  string  imagesFolder ,  string  outputModelLocation ,   ITransformer   model ) 
143135        { 
144-             Console . WriteLine ( $ "=============== Loading model ===============") ; 
145-             Console . WriteLine ( $ "Model loaded: { outputModelLocation } ") ; 
146-             // Load the model 
147-             // <SnippetLoadModel> 
148-             ITransformer  loadedModel ; 
149-             using  ( var  fileStream  =  new  FileStream ( outputModelLocation ,  FileMode . Open ) ) 
150-                 loadedModel  =  mlContext . Model . Load ( fileStream ) ; 
151-             // </SnippetLoadModel> 
152136
153137            // Read the image_list.tsv file and add the filepath to the image file name  
154138            // before loading into ImageData  
155139            // <SnippetReadFromTSV>  
156140            var  imageData  =  ReadFromTsv ( dataLocation ,  imagesFolder ) ; 
157-             var  imageDataView  =  mlContext . Data . ReadFromEnumerable < ImageData > ( imageData ) ; 
141+             var  imageDataView  =  mlContext . Data . LoadFromEnumerable < ImageData > ( imageData ) ; 
158142            // </SnippetReadFromTSV>   
159-              
143+ 
160144            // <SnippetPredict>   
161-             var  predictions  =  loadedModel . Transform ( imageDataView ) ; 
162-             var  imagePredictionData  =  mlContext . CreateEnumerable < ImagePrediction > ( predictions ,  false , true ) ; 
145+             var  predictions  =  model . Transform ( imageDataView ) ; 
146+             var  imagePredictionData  =  mlContext . Data . CreateEnumerable < ImagePrediction > ( predictions ,  false ,   true ) ; 
163147            // </SnippetPredict>  
164148
165149            Console . WriteLine ( "=============== Making classifications ===============" ) ; 
166-             // <SnippetCallPairAndDisplayResults2> 
167-             PairAndDisplayResults ( imageData ,  imagePredictionData ) ; 
168-             // </SnippetCallPairAndDisplayResults2>  
169150
151+             // <SnippetCallDisplayResults2> 
152+             DisplayResults ( imagePredictionData ) ; 
153+             // </SnippetCallDisplayResults2>  
170154        } 
171155
172-         public  static void  ClassifySingleImage ( MLContext  mlContext ,  string  imagePath ,  string  outputModelLocation ) 
156+         public  static void  ClassifySingleImage ( MLContext  mlContext ,  string  imagePath ,  string  outputModelLocation ,   ITransformer   model ) 
173157        { 
174-             Console . WriteLine ( $ "=============== Loading model ===============") ; 
175-             Console . WriteLine ( $ "Model loaded: { outputModelLocation } ") ; 
176-             // Load the model 
177-             // <SnippetLoadModel2> 
178-             ITransformer  loadedModel ; 
179-             using  ( var  fileStream  =  new  FileStream ( outputModelLocation ,  FileMode . Open ) ) 
180-                 loadedModel  =  mlContext . Model . Load ( fileStream ) ; 
181-             // </SnippetLoadModel2> 
182- 
183158            // load the fully qualified image file name into ImageData  
184159            // <SnippetLoadImageData>  
185160            var  imageData  =  new  ImageData ( ) 
186161            { 
187162                ImagePath  =  imagePath 
188-             } ;   
163+             } ; 
189164            // </SnippetLoadImageData>   
190165
191166            // <SnippetPredictSingle>   
192-             // Make prediction function (input = ImageNetData , output = ImageNetPrediction ) 
193-             var  predictor  =  loadedModel . CreatePredictionEngine < ImageData ,  ImagePrediction > ( mlContext ) ; 
167+             // Make prediction function (input = ImageData , output = ImagePrediction ) 
168+             var  predictor  =  mlContext . Model . CreatePredictionEngine < ImageData ,  ImagePrediction > ( model ) ; 
194169            var  prediction  =  predictor . Predict ( imageData ) ; 
195170            // </SnippetPredictSingle>  
196171
@@ -201,17 +176,12 @@ public static void ClassifySingleImage(MLContext mlContext, string imagePath, st
201176
202177        } 
203178
204-         private  static void  PairAndDisplayResults ( IEnumerable < ImageData >   imageNetData ,   IEnumerable < ImagePrediction >  imageNetPredictionData ) 
179+         private  static void  DisplayResults ( IEnumerable < ImagePrediction >  imagePredictionData ) 
205180        { 
206-             // Builds pairs of (image, prediction) to sync up for display 
207-             // <SnippetBuildImagePredictionPairs> 
208-             IEnumerable < ( ImageData  image ,  ImagePrediction  prediction ) >  imagesAndPredictions  =  imageNetData . Zip ( imageNetPredictionData ,  ( image ,  prediction )  =>  ( image ,  prediction ) ) ; 
209-             // </SnippetBuildImagePredictionPairs> 
210- 
211181            // <SnippetDisplayPredictions> 
212-             foreach  ( ( ImageData   image ,   ImagePrediction  prediction )   item   in  imagesAndPredictions ) 
182+             foreach  ( ImagePrediction  prediction   in  imagePredictionData ) 
213183            { 
214-                 Console . WriteLine ( $ "Image: { Path . GetFileName ( item . image . ImagePath ) }  predicted as: { item . prediction . PredictedLabelValue }  with score: { item . prediction . Score . Max ( ) }  ") ; 
184+                 Console . WriteLine ( $ "Image: { Path . GetFileName ( prediction . ImagePath ) }  predicted as: { prediction . PredictedLabelValue }  with score: { prediction . Score . Max ( ) }  ") ; 
215185            } 
216186            // </SnippetDisplayPredictions> 
217187        } 
0 commit comments