| using System.Collections.Generic; |
| using System.Diagnostics; |
| using Unity.InferenceEngine; |
| using Unity.MLAgents.Actuators; |
| using Unity.MLAgents.Inference; |
| using Unity.MLAgents.Policies; |
| using Unity.MLAgents.Sensors; |
| using UnityEngine; |
|
|
| #if MLA_UNITY_ANALYTICS_MODULE && ENABLE_CLOUD_SERVICES_ANALYTICS |
| using UnityEngine.Analytics; |
| #endif |
|
|
|
|
| #if UNITY_EDITOR |
| using UnityEditor; |
| #if MLA_UNITY_ANALYTICS_MODULE |
| using UnityEditor.Analytics; |
| #endif // MLA_UNITY_ANALYTICS_MODULE |
| #endif // UNITY_EDITOR |
|
|
|
|
| namespace Unity.MLAgents.Analytics |
| { |
| internal class InferenceAnalytics |
| { |
|
|
|
|
| #if UNITY_EDITOR && MLA_UNITY_ANALYTICS_MODULE && ENABLE_CLOUD_SERVICES_ANALYTICS |
| |
| |
| |
| private static HashSet<ModelAsset> s_SentModels; |
| #endif |
|
|
| static bool EnableAnalytics() |
| { |
| #if UNITY_EDITOR && MLA_UNITY_ANALYTICS_MODULE && ENABLE_CLOUD_SERVICES_ANALYTICS |
|
|
| if (s_SentModels == null) |
| { |
| s_SentModels = new HashSet<ModelAsset>(); |
| } |
|
|
| return true; |
|
|
| #else // no editor, no analytics |
| return false; |
| #endif |
| } |
|
|
| public static bool IsAnalyticsEnabled() |
| { |
| #if UNITY_EDITOR |
| return EditorAnalytics.enabled; |
| #else |
| return false; |
| #endif |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| [Conditional("MLA_UNITY_ANALYTICS_MODULE")] |
| public static void InferenceModelSet( |
| ModelAsset nnModel, |
| string behaviorName, |
| InferenceDevice inferenceDevice, |
| IList<ISensor> sensors, |
| ActionSpec actionSpec, |
| IList<IActuator> actuators |
| ) |
| { |
| #if UNITY_EDITOR && MLA_UNITY_ANALYTICS_MODULE && ENABLE_CLOUD_SERVICES_ANALYTICS |
| |
| |
| if (!IsAnalyticsEnabled()) |
| return; |
|
|
| if (!EnableAnalytics()) |
| return; |
|
|
| var added = s_SentModels.Add(nnModel); |
|
|
| if (!added) |
| { |
| |
| return; |
| } |
|
|
| var data = GetEventForModel(nnModel, behaviorName, inferenceDevice, sensors, actionSpec, actuators); |
| |
| |
| if (AnalyticsUtils.s_SendEditorAnalytics) |
| { |
| EditorAnalytics.SendAnalytic(data); |
| } |
| #endif |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| internal static InferenceEvent GetEventForModel( |
| ModelAsset nnModel, |
| string behaviorName, |
| InferenceDevice inferenceDevice, |
| IList<ISensor> sensors, |
| ActionSpec actionSpec, |
| IList<IActuator> actuators |
| ) |
| { |
| var sentisModel = ModelLoader.Load(nnModel); |
| using var sentisModelInfo = new SentisModelInfo(sentisModel); |
| var inferenceEvent = new InferenceEvent(); |
|
|
| |
| inferenceEvent.BehaviorName = AnalyticsUtils.Hash(AnalyticsConstants.k_VendorKey, behaviorName); |
|
|
| inferenceEvent.SentisModelVersion = sentisModelInfo.Version; |
| inferenceEvent.SentisModelProducer = sentisModel.ProducerName; |
| inferenceEvent.MemorySize = sentisModelInfo.MemorySize; |
| inferenceEvent.InferenceDevice = (int)inferenceDevice; |
|
|
| |
| if (sentisModel.ProducerName == "Script") |
| { |
| |
| inferenceEvent.SentisModelSource = "NN"; |
| inferenceEvent.SentisModelProducer = "tensorflow_to_barracuda.py"; |
| } |
|
|
| #if UNITY_EDITOR |
| var sentisPackageInfo = UnityEditor.PackageManager.PackageInfo.FindForAssembly(typeof(Tensor).Assembly); |
| inferenceEvent.SentisPackageVersion = sentisPackageInfo.version; |
| #else |
| inferenceEvent.SentisPackageVersion = null; |
| #endif |
|
|
| inferenceEvent.ActionSpec = EventActionSpec.FromActionSpec(actionSpec); |
| inferenceEvent.ObservationSpecs = new List<EventObservationSpec>(sensors.Count); |
| foreach (var sensor in sensors) |
| { |
| inferenceEvent.ObservationSpecs.Add(EventObservationSpec.FromSensor(sensor)); |
| } |
|
|
| inferenceEvent.ActuatorInfos = new List<EventActuatorInfo>(actuators.Count); |
| foreach (var actuator in actuators) |
| { |
| inferenceEvent.ActuatorInfos.Add(EventActuatorInfo.FromActuator(actuator)); |
| } |
|
|
| inferenceEvent.TotalWeightSizeBytes = GetModelWeightSize(sentisModel); |
| inferenceEvent.ModelHash = GetModelHash(sentisModel); |
| return inferenceEvent; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| static long GetModelWeightSize(Model sentisModel) |
| { |
| long totalWeightsSizeInBytes = 0; |
| for (var c = 0; c < sentisModel.constants.Count; c++) |
| { |
| totalWeightsSizeInBytes += sentisModel.constants[c].lengthBytes; |
| } |
| return totalWeightsSizeInBytes; |
| } |
|
|
| |
| |
| |
| struct MLAgentsHash128 |
| { |
| private Hash128 m_Hash; |
|
|
| public void Append(float[] values, int count) |
| { |
| if (values == null) |
| { |
| return; |
| } |
|
|
| |
| |
| #if UNITY_2020_1_OR_NEWER |
| m_Hash.Append(values, 0, count); |
| #else |
| for (var i = 0; i < count; i++) |
| { |
| var tempHash = new Hash128(); |
| HashUtilities.ComputeHash128(ref values[i], ref tempHash); |
| HashUtilities.AppendHash(ref tempHash, ref m_Hash); |
| } |
| #endif |
| } |
|
|
| public void Append(string value) |
| { |
| var tempHash = Hash128.Compute(value); |
| HashUtilities.AppendHash(ref tempHash, ref m_Hash); |
| } |
|
|
| public override string ToString() |
| { |
| return m_Hash.ToString(); |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| static string GetModelHash(Model sentisModel) |
| { |
| var hash = new MLAgentsHash128(); |
|
|
| foreach (var constant in sentisModel.constants) |
| { |
| hash.Append(constant.ToString()); |
| } |
|
|
| return hash.ToString(); |
| } |
| } |
| } |
|
|