diff --git a/Project/Assets/ML-Agents/Examples/Hallway/Prefabs/HallwayArea.prefab b/Project/Assets/ML-Agents/Examples/Hallway/Prefabs/HallwayArea.prefab index 6b3eabbba8..0ab6583542 100644 --- a/Project/Assets/ML-Agents/Examples/Hallway/Prefabs/HallwayArea.prefab +++ b/Project/Assets/ML-Agents/Examples/Hallway/Prefabs/HallwayArea.prefab @@ -55,6 +55,7 @@ MeshRenderer: m_MotionVectors: 1 m_LightProbeUsage: 1 m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 m_RenderingLayerMask: 1 m_RendererPriority: 0 m_Materials: @@ -66,6 +67,7 @@ MeshRenderer: m_ProbeAnchor: {fileID: 0} m_LightProbeVolumeOverride: {fileID: 0} m_ScaleInLightmap: 1 + m_ReceiveGI: 1 m_PreserveUVs: 0 m_IgnoreNormalsForChartDetection: 0 m_ImportantGI: 0 @@ -180,6 +182,7 @@ MeshRenderer: m_MotionVectors: 1 m_LightProbeUsage: 1 m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 m_RenderingLayerMask: 1 m_RendererPriority: 0 m_Materials: @@ -191,6 +194,7 @@ MeshRenderer: m_ProbeAnchor: {fileID: 0} m_LightProbeVolumeOverride: {fileID: 0} m_ScaleInLightmap: 1 + m_ReceiveGI: 1 m_PreserveUVs: 0 m_IgnoreNormalsForChartDetection: 0 m_ImportantGI: 0 @@ -271,6 +275,7 @@ MeshRenderer: m_MotionVectors: 1 m_LightProbeUsage: 1 m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 m_RenderingLayerMask: 1 m_RendererPriority: 0 m_Materials: @@ -282,6 +287,7 @@ MeshRenderer: m_ProbeAnchor: {fileID: 0} m_LightProbeVolumeOverride: {fileID: 0} m_ScaleInLightmap: 1 + m_ReceiveGI: 1 m_PreserveUVs: 0 m_IgnoreNormalsForChartDetection: 0 m_ImportantGI: 0 @@ -362,6 +368,7 @@ MeshRenderer: m_MotionVectors: 1 m_LightProbeUsage: 1 m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 m_RenderingLayerMask: 1 m_RendererPriority: 0 m_Materials: @@ -373,6 +380,7 @@ MeshRenderer: m_ProbeAnchor: {fileID: 0} m_LightProbeVolumeOverride: {fileID: 0} m_ScaleInLightmap: 1 + m_ReceiveGI: 1 m_PreserveUVs: 0 m_IgnoreNormalsForChartDetection: 0 m_ImportantGI: 0 @@ -452,6 +460,7 @@ MeshRenderer: m_MotionVectors: 1 m_LightProbeUsage: 1 m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 m_RenderingLayerMask: 1 m_RendererPriority: 0 m_Materials: @@ -463,6 +472,7 @@ MeshRenderer: m_ProbeAnchor: {fileID: 0} m_LightProbeVolumeOverride: {fileID: 0} m_ScaleInLightmap: 1 + m_ReceiveGI: 1 m_PreserveUVs: 1 m_IgnoreNormalsForChartDetection: 0 m_ImportantGI: 0 @@ -529,6 +539,7 @@ MeshRenderer: m_MotionVectors: 1 m_LightProbeUsage: 1 m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 m_RenderingLayerMask: 1 m_RendererPriority: 0 m_Materials: @@ -540,6 +551,7 @@ MeshRenderer: m_ProbeAnchor: {fileID: 0} m_LightProbeVolumeOverride: {fileID: 0} m_ScaleInLightmap: 1 + m_ReceiveGI: 1 m_PreserveUVs: 1 m_IgnoreNormalsForChartDetection: 0 m_ImportantGI: 0 @@ -606,6 +618,7 @@ MeshRenderer: m_MotionVectors: 1 m_LightProbeUsage: 1 m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 m_RenderingLayerMask: 1 m_RendererPriority: 0 m_Materials: @@ -617,6 +630,7 @@ MeshRenderer: m_ProbeAnchor: {fileID: 0} m_LightProbeVolumeOverride: {fileID: 0} m_ScaleInLightmap: 1 + m_ReceiveGI: 1 m_PreserveUVs: 0 m_IgnoreNormalsForChartDetection: 0 m_ImportantGI: 0 @@ -698,6 +712,7 @@ MeshRenderer: m_MotionVectors: 1 m_LightProbeUsage: 1 m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 m_RenderingLayerMask: 1 m_RendererPriority: 0 m_Materials: @@ -709,6 +724,7 @@ MeshRenderer: m_ProbeAnchor: {fileID: 0} m_LightProbeVolumeOverride: {fileID: 0} m_ScaleInLightmap: 1 + m_ReceiveGI: 1 m_PreserveUVs: 1 m_IgnoreNormalsForChartDetection: 0 m_ImportantGI: 0 @@ -775,6 +791,7 @@ MeshRenderer: m_MotionVectors: 1 m_LightProbeUsage: 1 m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 m_RenderingLayerMask: 1 m_RendererPriority: 0 m_Materials: @@ -786,6 +803,7 @@ MeshRenderer: m_ProbeAnchor: {fileID: 0} m_LightProbeVolumeOverride: {fileID: 0} m_ScaleInLightmap: 1 + m_ReceiveGI: 1 m_PreserveUVs: 1 m_IgnoreNormalsForChartDetection: 0 m_ImportantGI: 0 @@ -852,6 +870,7 @@ MeshRenderer: m_MotionVectors: 1 m_LightProbeUsage: 1 m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 m_RenderingLayerMask: 1 m_RendererPriority: 0 m_Materials: @@ -863,6 +882,7 @@ MeshRenderer: m_ProbeAnchor: {fileID: 0} m_LightProbeVolumeOverride: {fileID: 0} m_ScaleInLightmap: 1 + m_ReceiveGI: 1 m_PreserveUVs: 0 m_IgnoreNormalsForChartDetection: 0 m_ImportantGI: 0 @@ -929,6 +949,7 @@ MeshRenderer: m_MotionVectors: 1 m_LightProbeUsage: 1 m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 m_RenderingLayerMask: 1 m_RendererPriority: 0 m_Materials: @@ -940,6 +961,7 @@ MeshRenderer: m_ProbeAnchor: {fileID: 0} m_LightProbeVolumeOverride: {fileID: 0} m_ScaleInLightmap: 1 + m_ReceiveGI: 1 m_PreserveUVs: 0 m_IgnoreNormalsForChartDetection: 0 m_ImportantGI: 0 @@ -1006,6 +1028,7 @@ MeshRenderer: m_MotionVectors: 1 m_LightProbeUsage: 1 m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 m_RenderingLayerMask: 1 m_RendererPriority: 0 m_Materials: @@ -1017,6 +1040,7 @@ MeshRenderer: m_ProbeAnchor: {fileID: 0} m_LightProbeVolumeOverride: {fileID: 0} m_ScaleInLightmap: 1 + m_ReceiveGI: 1 m_PreserveUVs: 1 m_IgnoreNormalsForChartDetection: 0 m_ImportantGI: 0 @@ -1072,9 +1096,10 @@ Camera: m_ClearFlags: 2 m_BackGroundColor: {r: 0.5043253, g: 0.5998091, b: 0.64705884, a: 0} m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 m_SensorSize: {x: 36, y: 24} m_LensShift: {x: 0, y: 0} - m_GateFitMode: 2 m_FocalLength: 50 m_NormalizedViewPortRect: serializedVersion: 2 @@ -1171,6 +1196,7 @@ MeshRenderer: m_MotionVectors: 1 m_LightProbeUsage: 1 m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 m_RenderingLayerMask: 1 m_RendererPriority: 0 m_Materials: @@ -1182,6 +1208,7 @@ MeshRenderer: m_ProbeAnchor: {fileID: 0} m_LightProbeVolumeOverride: {fileID: 0} m_ScaleInLightmap: 1 + m_ReceiveGI: 1 m_PreserveUVs: 1 m_IgnoreNormalsForChartDetection: 0 m_ImportantGI: 0 @@ -1250,6 +1277,7 @@ MeshRenderer: m_MotionVectors: 1 m_LightProbeUsage: 1 m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 m_RenderingLayerMask: 1 m_RendererPriority: 0 m_Materials: @@ -1261,6 +1289,7 @@ MeshRenderer: m_ProbeAnchor: {fileID: 0} m_LightProbeVolumeOverride: {fileID: 0} m_ScaleInLightmap: 1 + m_ReceiveGI: 1 m_PreserveUVs: 0 m_IgnoreNormalsForChartDetection: 0 m_ImportantGI: 0 @@ -1342,6 +1371,7 @@ MeshRenderer: m_MotionVectors: 1 m_LightProbeUsage: 1 m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 m_RenderingLayerMask: 1 m_RendererPriority: 0 m_Materials: @@ -1353,6 +1383,7 @@ MeshRenderer: m_ProbeAnchor: {fileID: 0} m_LightProbeVolumeOverride: {fileID: 0} m_ScaleInLightmap: 1 + m_ReceiveGI: 1 m_PreserveUVs: 0 m_IgnoreNormalsForChartDetection: 0 m_ImportantGI: 0 @@ -1447,6 +1478,7 @@ MeshRenderer: m_MotionVectors: 1 m_LightProbeUsage: 1 m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 m_RenderingLayerMask: 1 m_RendererPriority: 0 m_Materials: @@ -1458,6 +1490,7 @@ MeshRenderer: m_ProbeAnchor: {fileID: 0} m_LightProbeVolumeOverride: {fileID: 0} m_ScaleInLightmap: 1 + m_ReceiveGI: 1 m_PreserveUVs: 1 m_IgnoreNormalsForChartDetection: 0 m_ImportantGI: 0 @@ -1560,7 +1593,7 @@ MonoBehaviour: VectorActionDescriptions: [] VectorActionSpaceType: 0 hasUpgradedBrainParametersWithActionSpec: 1 - m_Model: {fileID: 11400000, guid: 317f4f8da7e4846b3aae0969781824a2, type: 3} + m_Model: {fileID: 5022602860645237092, guid: 5e4f7c94351f346859ff7e00810f5d34, type: 3} m_InferenceDevice: 2 m_BehaviorType: 0 m_BehaviorName: Hallway @@ -1704,6 +1737,7 @@ MeshRenderer: m_MotionVectors: 1 m_LightProbeUsage: 1 m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 m_RenderingLayerMask: 1 m_RendererPriority: 0 m_Materials: @@ -1715,6 +1749,7 @@ MeshRenderer: m_ProbeAnchor: {fileID: 0} m_LightProbeVolumeOverride: {fileID: 0} m_ScaleInLightmap: 1 + m_ReceiveGI: 1 m_PreserveUVs: 0 m_IgnoreNormalsForChartDetection: 0 m_ImportantGI: 0 @@ -1783,9 +1818,10 @@ Camera: m_ClearFlags: 2 m_BackGroundColor: {r: 0.46666667, g: 0.5647059, b: 0.60784316, a: 1} m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 m_SensorSize: {x: 36, y: 24} m_LensShift: {x: 0, y: 0} - m_GateFitMode: 2 m_FocalLength: 50 m_NormalizedViewPortRect: serializedVersion: 2 @@ -1867,6 +1903,7 @@ MeshRenderer: m_MotionVectors: 1 m_LightProbeUsage: 1 m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 m_RenderingLayerMask: 1 m_RendererPriority: 0 m_Materials: @@ -1878,6 +1915,7 @@ MeshRenderer: m_ProbeAnchor: {fileID: 0} m_LightProbeVolumeOverride: {fileID: 0} m_ScaleInLightmap: 1 + m_ReceiveGI: 1 m_PreserveUVs: 0 m_IgnoreNormalsForChartDetection: 0 m_ImportantGI: 0 @@ -1900,7 +1938,7 @@ GameObject: m_Component: - component: {fileID: 4726744827719472} m_Layer: 0 - m_Name: SymbolFinderArea + m_Name: HallwayArea m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 @@ -1986,6 +2024,7 @@ MeshRenderer: m_MotionVectors: 1 m_LightProbeUsage: 1 m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 m_RenderingLayerMask: 1 m_RendererPriority: 0 m_Materials: @@ -1997,6 +2036,7 @@ MeshRenderer: m_ProbeAnchor: {fileID: 0} m_LightProbeVolumeOverride: {fileID: 0} m_ScaleInLightmap: 1 + m_ReceiveGI: 1 m_PreserveUVs: 1 m_IgnoreNormalsForChartDetection: 0 m_ImportantGI: 0 @@ -2078,6 +2118,7 @@ MeshRenderer: m_MotionVectors: 1 m_LightProbeUsage: 1 m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 m_RenderingLayerMask: 1 m_RendererPriority: 0 m_Materials: @@ -2089,6 +2130,7 @@ MeshRenderer: m_ProbeAnchor: {fileID: 0} m_LightProbeVolumeOverride: {fileID: 0} m_ScaleInLightmap: 1 + m_ReceiveGI: 1 m_PreserveUVs: 1 m_IgnoreNormalsForChartDetection: 0 m_ImportantGI: 0 diff --git a/Project/Assets/ML-Agents/Examples/Hallway/TFModels/Hallway.nn b/Project/Assets/ML-Agents/Examples/Hallway/TFModels/Hallway.nn deleted file mode 100644 index 41326dfc3b..0000000000 Binary files a/Project/Assets/ML-Agents/Examples/Hallway/TFModels/Hallway.nn and /dev/null differ diff --git a/Project/Assets/ML-Agents/Examples/Hallway/TFModels/Hallway.nn.meta b/Project/Assets/ML-Agents/Examples/Hallway/TFModels/Hallway.nn.meta deleted file mode 100644 index ca1b541769..0000000000 --- a/Project/Assets/ML-Agents/Examples/Hallway/TFModels/Hallway.nn.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 317f4f8da7e4846b3aae0969781824a2 -ScriptedImporter: - fileIDToRecycleName: - 11400000: main obj - 11400002: model data - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: - script: {fileID: 11500000, guid: 19ed1486aa27d4903b34839f37b8f69f, type: 3} diff --git a/Project/Assets/ML-Agents/Examples/Hallway/TFModels/Hallway.onnx b/Project/Assets/ML-Agents/Examples/Hallway/TFModels/Hallway.onnx new file mode 100644 index 0000000000..bde0dfbeac Binary files /dev/null and b/Project/Assets/ML-Agents/Examples/Hallway/TFModels/Hallway.onnx differ diff --git a/Project/Assets/ML-Agents/Examples/Hallway/TFModels/Hallway.onnx.meta b/Project/Assets/ML-Agents/Examples/Hallway/TFModels/Hallway.onnx.meta new file mode 100644 index 0000000000..b9630279de --- /dev/null +++ b/Project/Assets/ML-Agents/Examples/Hallway/TFModels/Hallway.onnx.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 5e4f7c94351f346859ff7e00810f5d34 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: 683b6cb6d0a474744822c888b46772c9, type: 3} + optimizeModel: 1 + forceArbitraryBatchSize: 1 + treatErrorsAsWarnings: 0 + importMode: 1 diff --git a/com.unity.ml-agents/CHANGELOG.md b/com.unity.ml-agents/CHANGELOG.md index f2f8956dfb..8cfa57955a 100755 --- a/com.unity.ml-agents/CHANGELOG.md +++ b/com.unity.ml-agents/CHANGELOG.md @@ -33,6 +33,7 @@ different sizes using the same model. For a summary of the interface changes, pl - `GridSensor` has been refactored and moved to main package, with changes to both sensor interfaces and behaviors. Exsisting GridSensor created by extension package will not work in newer version. Previously trained models will need to be retrained. Please see the Migration Guide for more details. (#5256) +- Models trained with 1.x versions of ML-Agents will no longer work at inference if they were trained using recurrent neural networks (#5254) ### Minor Changes #### com.unity.ml-agents / com.unity.ml-agents.extensions (C#) diff --git a/com.unity.ml-agents/Runtime/Inference/ApplierImpl.cs b/com.unity.ml-agents/Runtime/Inference/ApplierImpl.cs index 581ef102a2..e80ccd9fdd 100644 --- a/com.unity.ml-agents/Runtime/Inference/ApplierImpl.cs +++ b/com.unity.ml-agents/Runtime/Inference/ApplierImpl.cs @@ -204,48 +204,4 @@ public void Apply(TensorProxy tensorProxy, IList actionIds, Dictionary> m_Memories; - - public BarracudaMemoryOutputApplier( - int memoriesCount, - int memoryIndex, - Dictionary> memories) - { - m_MemoriesCount = memoriesCount; - m_MemoryIndex = memoryIndex; - m_Memories = memories; - } - - public void Apply(TensorProxy tensorProxy, IList actionIds, Dictionary lastActions) - { - var agentIndex = 0; - var memorySize = (int)tensorProxy.shape[tensorProxy.shape.Length - 1]; - - for (var i = 0; i < actionIds.Count; i++) - { - var agentId = actionIds[i]; - List memory; - if (!m_Memories.TryGetValue(agentId, out memory) - || memory.Count < memorySize * m_MemoriesCount) - { - memory = new List(); - memory.AddRange(Enumerable.Repeat(0f, memorySize * m_MemoriesCount)); - } - - for (var j = 0; j < memorySize; j++) - { - memory[memorySize * m_MemoryIndex + j] = tensorProxy.data[agentIndex, j]; - } - - m_Memories[agentId] = memory; - agentIndex++; - } - } - } } diff --git a/com.unity.ml-agents/Runtime/Inference/BarracudaModelExtensions.cs b/com.unity.ml-agents/Runtime/Inference/BarracudaModelExtensions.cs index fc2e3a0168..d4355589c3 100644 --- a/com.unity.ml-agents/Runtime/Inference/BarracudaModelExtensions.cs +++ b/com.unity.ml-agents/Runtime/Inference/BarracudaModelExtensions.cs @@ -77,21 +77,6 @@ public static IReadOnlyList GetInputTensors(this Model model) }); } - var modelVersion = model.GetVersion(); - if (modelVersion < (int)BarracudaModelParamLoader.ModelApiVersion.MLAgents2_0) - { - foreach (var mem in model.memories) - { - tensors.Add(new TensorProxy - { - name = mem.input, - valueType = TensorProxy.TensorType.FloatingPoint, - data = null, - shape = TensorUtils.TensorShapeFromBarracuda(mem.shape) - }); - } - } - tensors.Sort((el1, el2) => string.Compare(el1.name, el2.name, StringComparison.InvariantCulture)); return tensors; @@ -150,17 +135,7 @@ public static string[] GetOutputNames(this Model model) var memory = (int)model.GetTensorByName(TensorNames.MemorySize)[0]; if (memory > 0) { - if (modelVersion < (int)BarracudaModelParamLoader.ModelApiVersion.MLAgents2_0) - { - foreach (var mem in model.memories) - { - names.Add(mem.output); - } - } - else - { - names.Add(TensorNames.RecurrentOutput); - } + names.Add(TensorNames.RecurrentOutput); } names.Sort(StringComparer.InvariantCulture); diff --git a/com.unity.ml-agents/Runtime/Inference/BarracudaModelParamLoader.cs b/com.unity.ml-agents/Runtime/Inference/BarracudaModelParamLoader.cs index 383e674675..21917b303d 100644 --- a/com.unity.ml-agents/Runtime/Inference/BarracudaModelParamLoader.cs +++ b/com.unity.ml-agents/Runtime/Inference/BarracudaModelParamLoader.cs @@ -61,6 +61,53 @@ public static FailedCheck Error(string message) } } + /// + /// Checks that a model has the appropriate version. + /// + /// + /// The Barracuda engine model for loading static parameters + /// + /// A FailedCheck containing the error message if the version of the model does not mach, else null + public static FailedCheck CheckModelVersion(Model model) + { + var modelApiVersion = model.GetVersion(); + if (modelApiVersion < (int)ModelApiVersion.MinSupportedVersion) + { + return FailedCheck.Error( + "Model was trained with a older version of the trainer than is supported. " + + "Either retrain with an newer trainer, or use an older version of com.unity.ml-agents.\n" + + $"Model version: {modelApiVersion} Minimum supported version: {(int)ModelApiVersion.MinSupportedVersion}" + ); + } + + if (modelApiVersion > (int)ModelApiVersion.MaxSupportedVersion) + { + return FailedCheck.Error( + "Model was trained with a newer version of the trainer than is supported. " + + "Either retrain with an older trainer, or update to a newer version of com.unity.ml-agents.\n" + + $"Model version: {modelApiVersion} Maximum supported version: {(int)ModelApiVersion.MaxSupportedVersion}" + ); + } + + var memorySize = (int)model.GetTensorByName(TensorNames.MemorySize)[0]; + + if (modelApiVersion == (int)ModelApiVersion.MLAgents1_0 && memorySize > 0) + { + // This block is to make sure that models that are trained with MLAgents version 1.x and have + // an LSTM (i.e. use the barracuda _c and _h inputs and outputs) will not work with MLAgents version + // 2.x. This is because Barracuda version 2.x will eventually drop support for the _c and _h inputs + // and only ML-Agents 2.x models will be compatible. + return FailedCheck.Error( + "Models from com.unity.ml-agents 1.x that use recurrent neural networks are not supported in newer versions. " + + "Either retrain with an newer trainer, or use an older version of com.unity.ml-agents.\n" + ); + } + return null; + + } + + + /// /// Factory for the ModelParamLoader : Creates a ModelParamLoader and runs the checks /// on it. @@ -108,14 +155,10 @@ public static IEnumerable CheckModel( } var modelApiVersion = model.GetVersion(); - if (modelApiVersion < (int)ModelApiVersion.MinSupportedVersion || modelApiVersion > (int)ModelApiVersion.MaxSupportedVersion) + var versionCheck = CheckModelVersion(model); + if (versionCheck != null) { - failedModelChecks.Add( - FailedCheck.Warning($"Version of the trainer the model was trained with ({modelApiVersion}) " + - $"is not compatible with the current range of supported versions: " + - $"({(int)ModelApiVersion.MinSupportedVersion} to {(int)ModelApiVersion.MaxSupportedVersion}).") - ); - return failedModelChecks; + failedModelChecks.Add(versionCheck); } var memorySize = (int)model.GetTensorByName(TensorNames.MemorySize)[0]; @@ -304,17 +347,7 @@ ISensor[] sensors if (memory > 0) { var modelVersion = model.GetVersion(); - var netHasMemories = false; - if (modelVersion < (int)BarracudaModelParamLoader.ModelApiVersion.MLAgents2_0) - { - netHasMemories = tensorsNames.Any(x => x.EndsWith("_h")) && - tensorsNames.Any(x => x.EndsWith("_c")); - } - else - { - netHasMemories = tensorsNames.Any(x => x == TensorNames.RecurrentInPlaceholder); - } - if (!netHasMemories) + if (!tensorsNames.Any(x => x == TensorNames.RecurrentInPlaceholder)) { failedModelChecks.Add( FailedCheck.Warning("The model does not contain a Recurrent Input Node but has memory_size.") @@ -353,21 +386,8 @@ static IEnumerable CheckOutputTensorPresence(Model model, int memor // If there is no Recurrent Output but the model is Recurrent. if (memory > 0) { - - var netHasMemories = false; - var modelVersion = model.GetVersion(); - if (modelVersion < (int)BarracudaModelParamLoader.ModelApiVersion.MLAgents2_0) - { - var memOutputs = model.memories.Select(x => x.output).ToList(); - netHasMemories = memOutputs.Any(x => x.EndsWith("_h")) && - memOutputs.Any(x => x.EndsWith("_c")); - } - else - { - var allOutputs = model.GetOutputNames().ToList(); - netHasMemories = allOutputs.Any(x => x == TensorNames.RecurrentOutput); - } - if (!netHasMemories) + var allOutputs = model.GetOutputNames().ToList(); + if (!allOutputs.Any(x => x == TensorNames.RecurrentOutput)) { failedModelChecks.Add( FailedCheck.Warning("The model does not contain a Recurrent Output Node but has memory_size.") diff --git a/com.unity.ml-agents/Runtime/Inference/GeneratorImpl.cs b/com.unity.ml-agents/Runtime/Inference/GeneratorImpl.cs index 2d290538b3..f54212dcc7 100644 --- a/com.unity.ml-agents/Runtime/Inference/GeneratorImpl.cs +++ b/com.unity.ml-agents/Runtime/Inference/GeneratorImpl.cs @@ -131,63 +131,6 @@ public void Generate( } } - internal class BarracudaRecurrentInputGenerator : TensorGenerator.IGenerator - { - int m_MemoriesCount; - readonly int m_MemoryIndex; - readonly ITensorAllocator m_Allocator; - - Dictionary> m_Memories; - - public BarracudaRecurrentInputGenerator( - int memoryIndex, - ITensorAllocator allocator, - Dictionary> memories) - { - m_MemoryIndex = memoryIndex; - m_Allocator = allocator; - m_Memories = memories; - } - - public void Generate(TensorProxy tensorProxy, int batchSize, IList infos) - { - TensorUtils.ResizeTensor(tensorProxy, batchSize, m_Allocator); - - var memorySize = (int)tensorProxy.shape[tensorProxy.shape.Length - 1]; - var agentIndex = 0; - for (var infoIndex = 0; infoIndex < infos.Count; infoIndex++) - { - var infoSensorPair = infos[infoIndex]; - var info = infoSensorPair.agentInfo; - var offset = memorySize * m_MemoryIndex; - List memory; - if (info.done) - { - m_Memories.Remove(info.episodeId); - } - if (!m_Memories.TryGetValue(info.episodeId, out memory)) - { - for (var j = 0; j < memorySize; j++) - { - tensorProxy.data[agentIndex, j] = 0; - } - agentIndex++; - continue; - } - for (var j = 0; j < memorySize; j++) - { - if (j >= memory.Count) - { - break; - } - - tensorProxy.data[agentIndex, j] = memory[j + offset]; - } - agentIndex++; - } - } - } - /// /// Generates the Tensor corresponding to the Previous Action input : Will be a two /// dimensional integer array of dimension [batchSize x actionSize]. diff --git a/com.unity.ml-agents/Runtime/Inference/ModelRunner.cs b/com.unity.ml-agents/Runtime/Inference/ModelRunner.cs index 054ac2ac4e..6672a0ea37 100644 --- a/com.unity.ml-agents/Runtime/Inference/ModelRunner.cs +++ b/com.unity.ml-agents/Runtime/Inference/ModelRunner.cs @@ -71,6 +71,18 @@ public ModelRunner( D.logEnabled = m_Verbose; barracudaModel = ModelLoader.Load(model); + + var failedCheck = BarracudaModelParamLoader.CheckModelVersion( + barracudaModel + ); + if (failedCheck != null) + { + if (failedCheck.CheckType == BarracudaModelParamLoader.FailedCheck.CheckTypeEnum.Error) + { + throw new UnityAgentsException(failedCheck.Message); + } + } + WorkerFactory.Type executionDevice; switch (inferenceDevice) { diff --git a/com.unity.ml-agents/Runtime/Inference/TensorApplier.cs b/com.unity.ml-agents/Runtime/Inference/TensorApplier.cs index b9487bbc70..d311010aae 100644 --- a/com.unity.ml-agents/Runtime/Inference/TensorApplier.cs +++ b/com.unity.ml-agents/Runtime/Inference/TensorApplier.cs @@ -81,15 +81,6 @@ public TensorApplier( } } m_Dict[TensorNames.RecurrentOutput] = new MemoryOutputApplier(memories); - - if (modelVersion < (int)BarracudaModelParamLoader.ModelApiVersion.MLAgents2_0) - { - for (var i = 0; i < model?.memories.Count; i++) - { - m_Dict[model.memories[i].output] = - new BarracudaMemoryOutputApplier(model.memories.Count, i, memories); - } - } } /// diff --git a/com.unity.ml-agents/Runtime/Inference/TensorGenerator.cs b/com.unity.ml-agents/Runtime/Inference/TensorGenerator.cs index 5eb8706013..feb521ebd8 100644 --- a/com.unity.ml-agents/Runtime/Inference/TensorGenerator.cs +++ b/com.unity.ml-agents/Runtime/Inference/TensorGenerator.cs @@ -67,15 +67,6 @@ public TensorGenerator( m_Dict[TensorNames.RecurrentInPlaceholder] = new RecurrentInputGenerator(allocator, memories); - if (m_ApiVersion < (int)BarracudaModelParamLoader.ModelApiVersion.MLAgents2_0) - { - for (var i = 0; i < model.memories.Count; i++) - { - m_Dict[model.memories[i].input] = - new BarracudaRecurrentInputGenerator(i, allocator, memories); - } - } - m_Dict[TensorNames.PreviousActionPlaceholder] = new PreviousActionInputGenerator(allocator); m_Dict[TensorNames.ActionMaskPlaceholder] = diff --git a/com.unity.ml-agents/Tests/Editor/Inference/ModelRunnerTest.cs b/com.unity.ml-agents/Tests/Editor/Inference/ModelRunnerTest.cs index 1c65793ecd..0e81c4f8ad 100644 --- a/com.unity.ml-agents/Tests/Editor/Inference/ModelRunnerTest.cs +++ b/com.unity.ml-agents/Tests/Editor/Inference/ModelRunnerTest.cs @@ -12,12 +12,15 @@ namespace Unity.MLAgents.Tests [TestFixture] public class ModelRunnerTest { + const string k_hybrid_ONNX_recurr_v2 = "Packages/com.unity.ml-agents/Tests/Editor/TestModels/hybrid0vis8vec_2c_2_3d_v2_0.onnx"; + const string k_continuousONNXPath = "Packages/com.unity.ml-agents/Tests/Editor/TestModels/continuous2vis8vec2action_v1_0.onnx"; - const string k_discreteONNXPath = "Packages/com.unity.ml-agents/Tests/Editor/TestModels/discrete1vis0vec_2_3action_recurr_v1_0.onnx"; + const string k_discreteONNXPath = "Packages/com.unity.ml-agents/Tests/Editor/TestModels/discrete1vis0vec_2_3action_obsolete_recurr_v1_0.onnx"; const string k_hybridONNXPath = "Packages/com.unity.ml-agents/Tests/Editor/TestModels/hybrid0vis53vec_3c_2daction_v1_0.onnx"; const string k_continuousNNPath = "Packages/com.unity.ml-agents/Tests/Editor/TestModels/continuous2vis8vec2action_deprecated_v1_0.nn"; const string k_discreteNNPath = "Packages/com.unity.ml-agents/Tests/Editor/TestModels/discrete1vis0vec_2_3action_recurr_deprecated_v1_0.nn"; + NNModel hybridONNXModelV2; NNModel continuousONNXModel; NNModel discreteONNXModel; NNModel hybridONNXModel; @@ -45,6 +48,8 @@ ActionSpec GetHybrid0vis53vec_3c_2dActionSpec() [SetUp] public void SetUp() { + hybridONNXModelV2 = (NNModel)AssetDatabase.LoadAssetAtPath(k_hybrid_ONNX_recurr_v2, typeof(NNModel)); + continuousONNXModel = (NNModel)AssetDatabase.LoadAssetAtPath(k_continuousONNXPath, typeof(NNModel)); discreteONNXModel = (NNModel)AssetDatabase.LoadAssetAtPath(k_discreteONNXPath, typeof(NNModel)); hybridONNXModel = (NNModel)AssetDatabase.LoadAssetAtPath(k_hybridONNXPath, typeof(NNModel)); @@ -65,6 +70,7 @@ public void TestModelExist() Assert.IsNotNull(hybridONNXModel); Assert.IsNotNull(continuousNNModel); Assert.IsNotNull(discreteNNModel); + Assert.IsNotNull(hybridONNXModelV2); } [Test] @@ -73,13 +79,25 @@ public void TestCreation() var inferenceDevice = InferenceDevice.Burst; var modelRunner = new ModelRunner(continuousONNXModel, GetContinuous2vis8vec2actionActionSpec(), inferenceDevice); modelRunner.Dispose(); - modelRunner = new ModelRunner(discreteONNXModel, GetDiscrete1vis0vec_2_3action_recurrModelActionSpec(), inferenceDevice); - modelRunner.Dispose(); + Assert.Throws(() => + { + // Cannot load a model trained with 1.x that has an LSTM + modelRunner = new ModelRunner(discreteONNXModel, GetDiscrete1vis0vec_2_3action_recurrModelActionSpec(), inferenceDevice); + modelRunner.Dispose(); + }); modelRunner = new ModelRunner(hybridONNXModel, GetHybrid0vis53vec_3c_2dActionSpec(), inferenceDevice); modelRunner.Dispose(); modelRunner = new ModelRunner(continuousNNModel, GetContinuous2vis8vec2actionActionSpec(), inferenceDevice); modelRunner.Dispose(); - modelRunner = new ModelRunner(discreteNNModel, GetDiscrete1vis0vec_2_3action_recurrModelActionSpec(), inferenceDevice); + + Assert.Throws(() => + { + // Cannot load a model trained with 1.x that has an LSTM + modelRunner = new ModelRunner(discreteNNModel, GetDiscrete1vis0vec_2_3action_recurrModelActionSpec(), inferenceDevice); + modelRunner.Dispose(); + }); + // This one was trained with 2.0 so it should not raise an error: + modelRunner = new ModelRunner(hybridONNXModelV2, new ActionSpec(2, new[] { 2, 3 }), inferenceDevice); modelRunner.Dispose(); } @@ -96,14 +114,21 @@ public void TestHasModel() [Test] public void TestRunModel() { - var actionSpec = GetDiscrete1vis0vec_2_3action_recurrModelActionSpec(); - var modelRunner = new ModelRunner(discreteONNXModel, actionSpec, InferenceDevice.Burst); + var actionSpec = GetContinuous2vis8vec2actionActionSpec(); + var modelRunner = new ModelRunner(continuousONNXModel, actionSpec, InferenceDevice.Burst); + var sensor_8 = new Sensors.VectorSensor(8, "VectorSensor8"); var info1 = new AgentInfo(); info1.episodeId = 1; - modelRunner.PutObservations(info1, new[] { sensor_21_20_3.CreateSensors()[0] }.ToList()); + modelRunner.PutObservations(info1, new[] { + sensor_8, + sensor_21_20_3.CreateSensors()[0], + sensor_20_22_3.CreateSensors()[0] }.ToList()); var info2 = new AgentInfo(); info2.episodeId = 2; - modelRunner.PutObservations(info2, new[] { sensor_21_20_3.CreateSensors()[0] }.ToList()); + modelRunner.PutObservations(info2, new[] { + sensor_8, + sensor_21_20_3.CreateSensors()[0], + sensor_20_22_3.CreateSensors()[0] }.ToList()); modelRunner.DecideBatch(); diff --git a/com.unity.ml-agents/Tests/Editor/Inference/ParameterLoaderTest.cs b/com.unity.ml-agents/Tests/Editor/Inference/ParameterLoaderTest.cs index f6c8f3124f..ae9d52d74b 100644 --- a/com.unity.ml-agents/Tests/Editor/Inference/ParameterLoaderTest.cs +++ b/com.unity.ml-agents/Tests/Editor/Inference/ParameterLoaderTest.cs @@ -79,10 +79,12 @@ public BuiltInSensorType GetBuiltInSensorType() public class ParameterLoaderTest { const string k_discrete_ONNX_v2 = "Packages/com.unity.ml-agents/Tests/Editor/TestModels/discrete_rank2_vector_v2_0.onnx"; + const string k_hybrid_ONNX_recurr_v2 = "Packages/com.unity.ml-agents/Tests/Editor/TestModels/hybrid0vis8vec_2c_2_3d_v2_0.onnx"; + // ONNX model with continuous/discrete action output (support hybrid action) const string k_continuousONNXPath = "Packages/com.unity.ml-agents/Tests/Editor/TestModels/continuous2vis8vec2action_v1_0.onnx"; - const string k_discreteONNXPath = "Packages/com.unity.ml-agents/Tests/Editor/TestModels/discrete1vis0vec_2_3action_recurr_v1_0.onnx"; + const string k_discreteONNXPath = "Packages/com.unity.ml-agents/Tests/Editor/TestModels/discrete1vis0vec_2_3action_obsolete_recurr_v1_0.onnx"; const string k_hybridONNXPath = "Packages/com.unity.ml-agents/Tests/Editor/TestModels/hybrid0vis53vec_3c_2daction_v1_0.onnx"; // NN model with single action output (deprecated, does not support hybrid action). // Same BrainParameters settings as the corresponding ONNX model. @@ -90,6 +92,7 @@ public class ParameterLoaderTest const string k_discreteNNPath = "Packages/com.unity.ml-agents/Tests/Editor/TestModels/discrete1vis0vec_2_3action_recurr_deprecated_v1_0.nn"; NNModel rank2ONNXModel; + NNModel hybridRecurrV2Model; NNModel continuousONNXModel; NNModel discreteONNXModel; NNModel hybridONNXModel; @@ -137,6 +140,15 @@ BrainParameters GetRank2BrainParameters() return validBrainParameters; } + BrainParameters GetRecurrHybridBrainParameters() + { + var validBrainParameters = new BrainParameters(); + validBrainParameters.VectorObservationSize = 8; + validBrainParameters.NumStackedVectorObservations = 1; + validBrainParameters.ActionSpec = new ActionSpec(2, new int[] { 2, 3 }); + return validBrainParameters; + } + [SetUp] public void SetUp() { @@ -146,6 +158,7 @@ public void SetUp() continuousNNModel = (NNModel)AssetDatabase.LoadAssetAtPath(k_continuousNNPath, typeof(NNModel)); discreteNNModel = (NNModel)AssetDatabase.LoadAssetAtPath(k_discreteNNPath, typeof(NNModel)); rank2ONNXModel = (NNModel)AssetDatabase.LoadAssetAtPath(k_discrete_ONNX_v2, typeof(NNModel)); + hybridRecurrV2Model = (NNModel)AssetDatabase.LoadAssetAtPath(k_hybrid_ONNX_recurr_v2, typeof(NNModel)); var go = new GameObject("SensorA"); sensor_21_20_3 = go.AddComponent(); sensor_21_20_3.Sensor = new Test3DSensor("SensorA", 21, 20, 3); @@ -165,6 +178,7 @@ public void TestModelExist() Assert.IsNotNull(continuousNNModel); Assert.IsNotNull(discreteNNModel); Assert.IsNotNull(rank2ONNXModel); + Assert.IsNotNull(hybridRecurrV2Model); } [TestCase(true)] @@ -308,7 +322,40 @@ public void TestCheckModelValidDiscrete(bool useDeprecatedNNModel) model, validBrainParameters, new ISensor[] { sensor_21_20_3.CreateSensors()[0] }, new ActuatorComponent[0] ); - Assert.AreEqual(0, errors.Count()); // There should not be any errors + foreach (var e in errors) + { + Debug.Log(e.Message); + } + Assert.Greater(errors.Count(), 0); // There should be an error since LSTM v1.x is not supported + } + + [Test] + public void TestCheckModelValidRecurrent() + { + var model = ModelLoader.Load(hybridRecurrV2Model); + var num_errors = 0; // A model trained with v2 should not raise errors + var validBrainParameters = GetRecurrHybridBrainParameters(); + + var errors = BarracudaModelParamLoader.CheckModel( + model, validBrainParameters, + new ISensor[] { sensor_8 }, new ActuatorComponent[0] + ); + Assert.AreEqual(num_errors, errors.Count()); // There should not be any errors + + var invalidBrainParameters = GetRecurrHybridBrainParameters(); + invalidBrainParameters.ActionSpec = new ActionSpec(1, new int[] { 2, 3 }); + errors = BarracudaModelParamLoader.CheckModel( + model, invalidBrainParameters, + new ISensor[] { sensor_8 }, new ActuatorComponent[0] + ); + Assert.AreEqual(1, errors.Count()); // 1 continuous action instead of 2 + + invalidBrainParameters.ActionSpec = new ActionSpec(2, new int[] { 3, 2 }); + errors = BarracudaModelParamLoader.CheckModel( + model, invalidBrainParameters, + new ISensor[] { sensor_8 }, new ActuatorComponent[0] + ); + Assert.AreEqual(1, errors.Count()); // Discrete action branches flipped } [Test] diff --git a/com.unity.ml-agents/Tests/Editor/TestModels/discrete1vis0vec_2_3action_obsolete_recurr_v1_0.onnx b/com.unity.ml-agents/Tests/Editor/TestModels/discrete1vis0vec_2_3action_obsolete_recurr_v1_0.onnx new file mode 100644 index 0000000000..e7e6c0cce4 Binary files /dev/null and b/com.unity.ml-agents/Tests/Editor/TestModels/discrete1vis0vec_2_3action_obsolete_recurr_v1_0.onnx differ diff --git a/com.unity.ml-agents/Tests/Editor/TestModels/discrete1vis0vec_2_3action_obsolete_recurr_v1_0.onnx.meta b/com.unity.ml-agents/Tests/Editor/TestModels/discrete1vis0vec_2_3action_obsolete_recurr_v1_0.onnx.meta new file mode 100644 index 0000000000..92c9212a72 --- /dev/null +++ b/com.unity.ml-agents/Tests/Editor/TestModels/discrete1vis0vec_2_3action_obsolete_recurr_v1_0.onnx.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 9ecb2a56b0c6b42f7ad2b40ab97c5515 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: 683b6cb6d0a474744822c888b46772c9, type: 3} + optimizeModel: 1 + forceArbitraryBatchSize: 1 + treatErrorsAsWarnings: 0 + importMode: 1 diff --git a/com.unity.ml-agents/Tests/Editor/TestModels/discrete1vis0vec_2_3action_recurr_v1_0.onnx b/com.unity.ml-agents/Tests/Editor/TestModels/discrete1vis0vec_2_3action_v1_0.onnx similarity index 100% rename from com.unity.ml-agents/Tests/Editor/TestModels/discrete1vis0vec_2_3action_recurr_v1_0.onnx rename to com.unity.ml-agents/Tests/Editor/TestModels/discrete1vis0vec_2_3action_v1_0.onnx diff --git a/com.unity.ml-agents/Tests/Editor/TestModels/discrete1vis0vec_2_3action_recurr_v1_0.onnx.meta b/com.unity.ml-agents/Tests/Editor/TestModels/discrete1vis0vec_2_3action_v1_0.onnx.meta similarity index 89% rename from com.unity.ml-agents/Tests/Editor/TestModels/discrete1vis0vec_2_3action_recurr_v1_0.onnx.meta rename to com.unity.ml-agents/Tests/Editor/TestModels/discrete1vis0vec_2_3action_v1_0.onnx.meta index c57773013f..2bceceabac 100644 --- a/com.unity.ml-agents/Tests/Editor/TestModels/discrete1vis0vec_2_3action_recurr_v1_0.onnx.meta +++ b/com.unity.ml-agents/Tests/Editor/TestModels/discrete1vis0vec_2_3action_v1_0.onnx.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 9383297608d1d4530807d7109ee19d85 +guid: 68991653e04394f95b15a222253c0729 ScriptedImporter: fileIDToRecycleName: 11400000: main obj diff --git a/com.unity.ml-agents/Tests/Editor/TestModels/hybrid0vis8vec_2c_2_3d_v2_0.onnx b/com.unity.ml-agents/Tests/Editor/TestModels/hybrid0vis8vec_2c_2_3d_v2_0.onnx new file mode 100644 index 0000000000..cd2a356f1c Binary files /dev/null and b/com.unity.ml-agents/Tests/Editor/TestModels/hybrid0vis8vec_2c_2_3d_v2_0.onnx differ diff --git a/com.unity.ml-agents/Tests/Editor/TestModels/hybrid0vis8vec_2c_2_3d_v2_0.onnx.meta b/com.unity.ml-agents/Tests/Editor/TestModels/hybrid0vis8vec_2c_2_3d_v2_0.onnx.meta new file mode 100644 index 0000000000..5abc7e6432 --- /dev/null +++ b/com.unity.ml-agents/Tests/Editor/TestModels/hybrid0vis8vec_2c_2_3d_v2_0.onnx.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 2f6b2ae61d96a4555b60892a0ad924bb +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: 683b6cb6d0a474744822c888b46772c9, type: 3} + optimizeModel: 1 + forceArbitraryBatchSize: 1 + treatErrorsAsWarnings: 0 + importMode: 1 diff --git a/docs/Migrating.md b/docs/Migrating.md index eb41c7078b..8867a7787d 100644 --- a/docs/Migrating.md +++ b/docs/Migrating.md @@ -134,6 +134,13 @@ Sensors with non-normalized data cannot use PNG compression type. * The sensor will not further encode the data recieved from `GetObjectData()` anymore. The values recieved from `GetObjectData()` will be the observation sent to the trainer. +### LSTM models from previous releases no longer supported +The way the Unity Inference Engine processes LSTM (recurrent neural networks) has changed. As a result, models +trained with previous versions of ML-Agents will not be usable at inference if they were trained with a `memory` +setting in the `.yaml` config file. +If you want to use a model that has a recurrent neural network in this release of ML-Agents, you need to train +the model using the python trainer from this release. + ## Migrating to Release 13 ### Implementing IHeuristic in your IActuator implementations