-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Added categorical value support for PredictedLabel for the Image Classification Transfer Learning example. Addresses Issue #4169 #4228
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
8d07401
d80e23d
7b239b0
33e71ae
2b1ab69
7254a7e
1a43cc7
d39f98b
8cf2b7c
c4182fb
d490383
01c77c9
380d8bf
2af03ca
2c05ba8
6356665
ed928c6
f7f8253
bd42f0a
f851791
643fb58
b6cfeda
cca4fb8
1c4c5dc
2301a96
26e2ae1
94c0423
109879b
6ff4c64
15c4654
0573ef3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -64,6 +64,7 @@ public sealed class ImageClassificationTransformer : RowToRowTransformerBase | |
| private Graph Graph => _session.graph; | ||
| private readonly string[] _inputs; | ||
| private readonly string[] _outputs; | ||
| private readonly string[] _keyValueAnnotations; | ||
| private readonly string _labelColumnName; | ||
| private readonly string _finalModelPrefix; | ||
| private readonly Architecture _arch; | ||
|
|
@@ -109,7 +110,7 @@ private static ImageClassificationTransformer Create(IHostEnvironment env, Model | |
|
|
||
| GetModelInfo(env, ctx, out string[] inputs, out string[] outputs, out bool addBatchDimensionInput, | ||
| out string labelColumn, out string checkpointName, out Architecture arch, out string scoreColumnName, | ||
| out string predictedColumnName, out float learningRate, out int classCount, out string predictionTensorName, out string softMaxTensorName, | ||
| out string predictedColumnName, out float learningRate, out int classCount, out string[] keyValueAnnotations, out string predictionTensorName, out string softMaxTensorName, | ||
| out string jpegDataTensorName, out string resizeTensorName); | ||
|
|
||
| byte[] modelBytes = null; | ||
|
|
@@ -118,7 +119,7 @@ private static ImageClassificationTransformer Create(IHostEnvironment env, Model | |
|
|
||
| return new ImageClassificationTransformer(env, DnnUtils.LoadTFSession(env, modelBytes), outputs, inputs, | ||
| null, addBatchDimensionInput, 1, labelColumn, checkpointName, arch, | ||
| scoreColumnName, predictedColumnName, learningRate, null, classCount, true, predictionTensorName, | ||
| scoreColumnName, predictedColumnName, learningRate, null, classCount, keyValueAnnotations, true, predictionTensorName, | ||
| softMaxTensorName, jpegDataTensorName, resizeTensorName); | ||
|
|
||
| } | ||
|
|
@@ -617,7 +618,7 @@ private static IRowMapper Create(IHostEnvironment env, ModelLoadContext ctx, Dat | |
| private static void GetModelInfo(IHostEnvironment env, ModelLoadContext ctx, out string[] inputs, | ||
| out string[] outputs, out bool addBatchDimensionInput, | ||
| out string labelColumn, out string checkpointName, out Architecture arch, | ||
| out string scoreColumnName, out string predictedColumnName, out float learningRate, out int classCount, out string predictionTensorName, out string softMaxTensorName, | ||
| out string scoreColumnName, out string predictedColumnName, out float learningRate, out int classCount, out string[] keyValueAnnotations, out string predictionTensorName, out string softMaxTensorName, | ||
| out string jpegDataTensorName, out string resizeTensorName) | ||
| { | ||
| addBatchDimensionInput = ctx.Reader.ReadBoolByte(); | ||
|
|
@@ -641,6 +642,12 @@ private static void GetModelInfo(IHostEnvironment env, ModelLoadContext ctx, out | |
| predictedColumnName = ctx.Reader.ReadString(); | ||
| learningRate = ctx.Reader.ReadFloat(); | ||
| classCount = ctx.Reader.ReadInt32(); | ||
|
|
||
| env.CheckDecode(classCount > 0); | ||
| keyValueAnnotations = new string[classCount]; | ||
| for (int j = 0; j < keyValueAnnotations.Length; j++) | ||
| keyValueAnnotations[j] = ctx.LoadNonEmptyString(); | ||
|
|
||
| predictionTensorName = ctx.Reader.ReadString(); | ||
| softMaxTensorName = ctx.Reader.ReadString(); | ||
| jpegDataTensorName = ctx.Reader.ReadString(); | ||
|
|
@@ -650,7 +657,7 @@ private static void GetModelInfo(IHostEnvironment env, ModelLoadContext ctx, out | |
| internal ImageClassificationTransformer(IHostEnvironment env, Session session, string[] outputColumnNames, | ||
| string[] inputColumnNames, string modelLocation, | ||
| bool? addBatchDimensionInput, int batchSize, string labelColumnName, string finalModelPrefix, Architecture arch, | ||
| string scoreColumnName, string predictedLabelColumnName, float learningRate, DataViewSchema inputSchema, int? classCount = null, bool loadModel = false, | ||
| string scoreColumnName, string predictedLabelColumnName, float learningRate, DataViewSchema inputSchema, int? classCount = null, string[] keyValueAnnotations = null, bool loadModel = false, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The transformer can be created in one of two ways: Either by calling There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Notice that it is possible that the label column does not contain key values annotations, which means that the PredictedLabel column will not have them either. You have to account for that at serialization/deserialization time (for example, by serialiazing the number of key value strings, and only then serializing the strings them selves). In reply to: 327481050 [](ancestors = 327481050) |
||
| string predictionTensorName = null, string softMaxTensorName = null, string jpegDataTensorName = null, string resizeTensorName = null) | ||
| : base(Contracts.CheckRef(env, nameof(env)).Register(nameof(ImageClassificationTransformer))) | ||
|
|
||
|
|
@@ -664,6 +671,7 @@ internal ImageClassificationTransformer(IHostEnvironment env, Session session, s | |
| _addBatchDimensionInput = addBatchDimensionInput ?? arch == Architecture.ResnetV2101; | ||
| _inputs = inputColumnNames; | ||
| _outputs = outputColumnNames; | ||
| _keyValueAnnotations = keyValueAnnotations; | ||
| _labelColumnName = labelColumnName; | ||
| _finalModelPrefix = finalModelPrefix; | ||
| _arch = arch; | ||
|
|
@@ -684,6 +692,9 @@ internal ImageClassificationTransformer(IHostEnvironment env, Session session, s | |
| throw Host.ExceptSchemaMismatch(nameof(inputSchema), "label", (string)labelColumn.Name, "Key", (string)labelType.ToString()); | ||
|
|
||
| _classCount = labelCount == 1 ? 2 : (int)labelCount; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Why?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To account for binary classification case where in the train set all you have seen is just one class :-). In reply to: 327483161 [](ancestors = 327483161) |
||
|
|
||
| //Temporary string array for key values, will replace soon | ||
| _keyValueAnnotations = new string[] { "sunflowers", "roses", "dandelion", "daisy", "tulips"}; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
It seems that the |
||
| } | ||
| else | ||
| _classCount = classCount.Value; | ||
|
|
@@ -749,6 +760,10 @@ private protected override void SaveModel(ModelSaveContext ctx) | |
| ctx.Writer.Write(_predictedLabelColumnName); | ||
| ctx.Writer.Write(_learningRate); | ||
| ctx.Writer.Write(_classCount); | ||
|
|
||
| foreach (var keyValueAnnotation in _keyValueAnnotations) | ||
| ctx.SaveNonEmptyString(keyValueAnnotation); | ||
|
|
||
| ctx.Writer.Write(_predictionTensorName); | ||
| ctx.Writer.Write(_softmaxTensorName); | ||
| ctx.Writer.Write(_jpegDataTensorName); | ||
|
|
@@ -877,8 +892,8 @@ private protected override Func<int, bool> GetDependenciesCore(Func<int, bool> a | |
| protected override DataViewSchema.DetachedColumn[] GetOutputColumnsCore() | ||
| { | ||
| var info = new DataViewSchema.DetachedColumn[_parent._outputs.Length]; | ||
| info[0] = new DataViewSchema.DetachedColumn(_parent._outputs[0], new VectorDataViewType(NumberDataViewType.Single, _parent._classCount), null); | ||
| info[1] = new DataViewSchema.DetachedColumn(_parent._outputs[1], NumberDataViewType.UInt32, null); | ||
| info[0] = new DataViewSchema.DetachedColumn(_parent._scoreColumnName, new VectorDataViewType(NumberDataViewType.Single, _parent._classCount), null); | ||
| info[1] = new DataViewSchema.DetachedColumn(_parent._predictedLabelColumnName, new KeyDataViewType(typeof(uint), _parent._classCount), ((DataViewSchema.Column)InputSchema.GetColumnOrNull(_parent._labelColumnName)).Annotations); | ||
| return info; | ||
| } | ||
| } | ||
|
|
@@ -1038,6 +1053,12 @@ internal sealed class Options : TransformInputBase | |
| [Argument(ArgumentType.Multiple | ArgumentType.Required, HelpText = "The name of the outputs", ShortName = "outputs", SortOrder = 2)] | ||
| public string[] OutputColumns; | ||
|
|
||
| /// <summary> | ||
| /// The names of the requested key value annotations. | ||
| /// </summary> | ||
| [Argument(ArgumentType.Multiple | ArgumentType.Required, HelpText = "The name of the key value annotations", ShortName = "annotations", SortOrder = 3)] | ||
| public string[] KeyValueAnnotations; | ||
|
mstfbl marked this conversation as resolved.
Outdated
|
||
|
|
||
| /// <summary> | ||
| /// The name of the label column in <see cref="IDataView"/> that will be mapped to label node in TensorFlow model. | ||
| /// </summary> | ||
|
|
@@ -1166,7 +1187,7 @@ internal ImageClassificationEstimator(IHostEnvironment env, Options options, Dnn | |
| _options = options; | ||
| _dnnModel = dnnModel; | ||
| _tfInputTypes = new[] { TF_DataType.TF_STRING }; | ||
| _outputTypes = new[] { new VectorDataViewType(NumberDataViewType.Single), NumberDataViewType.UInt32.GetItemType() }; | ||
| _outputTypes = new DataViewType[] { new VectorDataViewType(NumberDataViewType.Single), new KeyDataViewType(typeof(uint), 5) }; | ||
|
mstfbl marked this conversation as resolved.
Outdated
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a good catch, thank you! Quick question, the Image Classification example ResnetV2101TransferLearningTrainTestSplit.cs runs perfectly well when I don't further define _outputTypes, i,e, delete line 69. Does this also mean than the estimator isn't using this field? #Resolved
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually, I've found that the DataViewType field is needed for the pipeline in ResnetV2101TransferLearningTrainTestSplit.cs to fit properly. #Resolved There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you elaborate? The only place In reply to: 326329163 [](ancestors = 326329163)
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It was giving a different error when I removed _outputTypes, but as I now see that was not the bottleneck problem I was having while implementing this KeyType solution. #Resolved There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The field In reply to: 326229209 [](ancestors = 326229209)
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I missed this, thank you for the catch! #Resolved |
||
| } | ||
|
|
||
| private static Options CreateArguments(DnnModel tensorFlowModel, string[] outputColumnNames, string[] inputColumnName, bool addBatchDimensionInput) | ||
|
|
@@ -1196,12 +1217,16 @@ public SchemaShape GetOutputSchema(SchemaShape inputSchema) | |
| if (col.ItemType != expectedType) | ||
| throw _host.ExceptSchemaMismatch(nameof(inputSchema), "input", input, expectedType.ToString(), col.ItemType.ToString()); | ||
| } | ||
| for (var i = 0; i < _options.OutputColumns.Length; i++) | ||
| { | ||
| resultDic[_options.OutputColumns[i]] = new SchemaShape.Column(_options.OutputColumns[i], | ||
| _outputTypes[i].IsKnownSizeVector() ? SchemaShape.Column.VectorKind.Vector | ||
| : SchemaShape.Column.VectorKind.VariableVector, _outputTypes[i].GetItemType(), false); | ||
| } | ||
|
|
||
| resultDic[_options.OutputColumns[0]] = new SchemaShape.Column(_options.OutputColumns[0], | ||
| SchemaShape.Column.VectorKind.Vector, _outputTypes[0].GetItemType(), false); | ||
|
|
||
| var metadata = new List<SchemaShape.Column>(); | ||
| metadata.Add(new SchemaShape.Column(AnnotationUtils.Kinds.KeyValues, SchemaShape.Column.VectorKind.Vector, TextDataViewType.Instance, false, inputSchema[1].Annotations)); | ||
|
mstfbl marked this conversation as resolved.
Outdated
|
||
|
|
||
| resultDic[_options.OutputColumns[1]] = new SchemaShape.Column(_options.OutputColumns[1], | ||
| SchemaShape.Column.VectorKind.Scalar, NumberDataViewType.UInt32, true, new SchemaShape(metadata.ToArray())); | ||
|
|
||
| return new SchemaShape(resultDic.Values); | ||
| } | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.