@@ -46,40 +46,40 @@ public static void Example()
46
46
mlContext . Data . LoadFromEnumerable ( images ) ) ;
47
47
48
48
shuffledFullImagesDataset = mlContext . Transforms . Conversion
49
- . MapValueToKey ( "Label" )
49
+ . MapValueToKey ( "Label" )
50
+ . Append ( mlContext . Transforms . LoadImages ( "Image" ,
51
+ fullImagesetFolderPath , false , "ImagePath" ) )
50
52
. Fit ( shuffledFullImagesDataset )
51
53
. Transform ( shuffledFullImagesDataset ) ;
52
54
53
- // Split the data 90:10 into train and test sets, train and evaluate.
55
+ // Split the data 90:10 into train and test sets, train and
56
+ // evaluate.
54
57
TrainTestData trainTestData = mlContext . Data . TrainTestSplit (
55
58
shuffledFullImagesDataset , testFraction : 0.1 , seed : 1 ) ;
56
59
57
60
IDataView trainDataset = trainTestData . TrainSet ;
58
61
IDataView testDataset = trainTestData . TestSet ;
59
62
60
- var validationSet = mlContext . Transforms . LoadImages ( "Image" , fullImagesetFolderPath , false , "ImagePath" ) // false indicates we want the image as a VBuffer<byte>
61
- . Fit ( testDataset )
62
- . Transform ( testDataset ) ;
63
-
64
- var pipeline = mlContext . Transforms . LoadImages ( "Image" , fullImagesetFolderPath , false , "ImagePath" ) // false indicates we want the image as a VBuffer<byte>
65
- . Append ( mlContext . Model . ImageClassification (
63
+ var pipeline = mlContext . Model . ImageClassification (
66
64
"Image" , "Label" ,
67
65
// Just by changing/selecting InceptionV3 here instead of
68
- // ResnetV2101 you can try a different architecture/pre-trained
69
- // model.
66
+ // ResnetV2101 you can try a different architecture/
67
+ // pre-trained model.
70
68
arch : ImageClassificationEstimator . Architecture . ResnetV2101 ,
71
69
epoch : 50 ,
72
70
batchSize : 10 ,
73
71
learningRate : 0.01f ,
74
72
metricsCallback : ( metrics ) => Console . WriteLine ( metrics ) ,
75
- validationSet : validationSet ,
73
+ validationSet : testDataset ,
76
74
disableEarlyStopping : true )
77
- . Append ( mlContext . Transforms . Conversion . MapKeyToValue ( outputColumnName : "PredictedLabel" , inputColumnName : "PredictedLabel" ) ) ) ;
75
+ . Append ( mlContext . Transforms . Conversion . MapKeyToValue (
76
+ outputColumnName : "PredictedLabel" ,
77
+ inputColumnName : "PredictedLabel" ) ) ;
78
78
79
79
80
- Console . WriteLine ( "*** Training the image classification model with " +
81
- "DNN Transfer Learning on top of the selected pre-trained " +
82
- "model/architecture ***" ) ;
80
+ Console . WriteLine ( "*** Training the image classification model " +
81
+ "with DNN Transfer Learning on top of the selected " +
82
+ "pre-trained model/architecture ***" ) ;
83
83
84
84
// Measuring training time
85
85
var watch = System . Diagnostics . Stopwatch . StartNew ( ) ;
@@ -104,6 +104,7 @@ public static void Example()
104
104
105
105
watch = System . Diagnostics . Stopwatch . StartNew ( ) ;
106
106
107
+ // Predict image class using an in-memory image.
107
108
TrySinglePrediction ( fullImagesetFolderPath , mlContext , loadedModel ) ;
108
109
109
110
watch . Stop ( ) ;
@@ -126,21 +127,19 @@ private static void TrySinglePrediction(string imagesForPredictions,
126
127
{
127
128
// Create prediction function to try one prediction
128
129
var predictionEngine = mlContext . Model
129
- . CreatePredictionEngine < ImageData , ImagePrediction > ( trainedModel ) ;
130
+ . CreatePredictionEngine < InMemoryImageData , ImagePrediction > ( trainedModel ) ;
130
131
131
- IEnumerable < ImageData > testImages = LoadImagesFromDirectory (
132
+ IEnumerable < InMemoryImageData > testImages = LoadInMemoryImagesFromDirectory (
132
133
imagesForPredictions , false ) ;
133
134
134
- ImageData imageToPredict = new ImageData
135
+ InMemoryImageData imageToPredict = new InMemoryImageData
135
136
{
136
- ImagePath = testImages . First ( ) . ImagePath
137
+ Image = testImages . First ( ) . Image
137
138
} ;
138
139
139
140
var prediction = predictionEngine . Predict ( imageToPredict ) ;
140
141
141
- Console . WriteLine ( $ "ImageFile : " +
142
- $ "[{ Path . GetFileName ( imageToPredict . ImagePath ) } ], " +
143
- $ "Scores : [{ string . Join ( "," , prediction . Score ) } ], " +
142
+ Console . WriteLine ( $ "Scores : [{ string . Join ( "," , prediction . Score ) } ], " +
144
143
$ "Predicted Label : { prediction . PredictedLabel } ") ;
145
144
}
146
145
@@ -201,6 +200,41 @@ public static IEnumerable<ImageData> LoadImagesFromDirectory(string folder,
201
200
}
202
201
}
203
202
203
+ public static IEnumerable < InMemoryImageData >
204
+ LoadInMemoryImagesFromDirectory ( string folder ,
205
+ bool useFolderNameAsLabel = true )
206
+ {
207
+ var files = Directory . GetFiles ( folder , "*" ,
208
+ searchOption : SearchOption . AllDirectories ) ;
209
+ foreach ( var file in files )
210
+ {
211
+ if ( Path . GetExtension ( file ) != ".jpg" )
212
+ continue ;
213
+
214
+ var label = Path . GetFileName ( file ) ;
215
+ if ( useFolderNameAsLabel )
216
+ label = Directory . GetParent ( file ) . Name ;
217
+ else
218
+ {
219
+ for ( int index = 0 ; index < label . Length ; index ++ )
220
+ {
221
+ if ( ! char . IsLetter ( label [ index ] ) )
222
+ {
223
+ label = label . Substring ( 0 , index ) ;
224
+ break ;
225
+ }
226
+ }
227
+ }
228
+
229
+ yield return new InMemoryImageData ( )
230
+ {
231
+ Image = File . ReadAllBytes ( file ) ,
232
+ Label = label
233
+ } ;
234
+
235
+ }
236
+ }
237
+
204
238
public static string DownloadImageSet ( string imagesDownloadFolder )
205
239
{
206
240
// get a set of images to teach the network about the new classes
@@ -285,6 +319,15 @@ public static string GetAbsolutePath(string relativePath)
285
319
return fullPath ;
286
320
}
287
321
322
+ public class InMemoryImageData
323
+ {
324
+ [ LoadColumn ( 0 ) ]
325
+ public byte [ ] Image ;
326
+
327
+ [ LoadColumn ( 1 ) ]
328
+ public string Label ;
329
+ }
330
+
288
331
public class ImageData
289
332
{
290
333
[ LoadColumn ( 0 ) ]
0 commit comments