{"action":"created","issue":{"url":"https://api.github.com/repos/dotnet/machinelearning/issues/179","repository_url":"https://api.github.com/repos/dotnet/machinelearning","labels_url":"https://api.github.com/repos/dotnet/machinelearning/issues/179/labels{/name}","comments_url":"https://api.github.com/repos/dotnet/machinelearning/issues/179/comments","events_url":"https://api.github.com/repos/dotnet/machinelearning/issues/179/events","html_url":"https://github.com/dotnet/machinelearning/issues/179","id":323864804,"number":179,"title":"Speed of Random Forest predictions","user":{"login":"mjmckp","id":7776787,"avatar_url":"https://avatars0.githubusercontent.com/u/7776787?v=4","gravatar_id":"","url":"https://api.github.com/users/mjmckp","html_url":"https://github.com/mjmckp","followers_url":"https://api.github.com/users/mjmckp/followers","following_url":"https://api.github.com/users/mjmckp/following{/other_user}","gists_url":"https://api.github.com/users/mjmckp/gists{/gist_id}","starred_url":"https://api.github.com/users/mjmckp/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mjmckp/subscriptions","organizations_url":"https://api.github.com/users/mjmckp/orgs","repos_url":"https://api.github.com/users/mjmckp/repos","events_url":"https://api.github.com/users/mjmckp/events{/privacy}","received_events_url":"https://api.github.com/users/mjmckp/received_events","type":"User","site_admin":false},"labels":[{"id":921787126,"url":"https://api.github.com/repos/dotnet/machinelearning/labels/question","name":"question","color":"d876e3","default":true}],"state":"open","locked":false,"assignee":{"login":"glebuk","id":25063330,"avatar_url":"https://avatars3.githubusercontent.com/u/25063330?v=4","gravatar_id":"","url":"https://api.github.com/users/glebuk","html_url":"https://github.com/glebuk","followers_url":"https://api.github.com/users/glebuk/followers","following_url":"https://api.github.com/users/glebuk/following{/other_user}","gists_url":"https://api.github.com/users/glebuk/gists{/gist_id}","starred_url":"https://api.github.com/users/glebuk/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/glebuk/subscriptions","organizations_url":"https://api.github.com/users/glebuk/orgs","repos_url":"https://api.github.com/users/glebuk/repos","events_url":"https://api.github.com/users/glebuk/events{/privacy}","received_events_url":"https://api.github.com/users/glebuk/received_events","type":"User","site_admin":false},"assignees":[{"login":"glebuk","id":25063330,"avatar_url":"https://avatars3.githubusercontent.com/u/25063330?v=4","gravatar_id":"","url":"https://api.github.com/users/glebuk","html_url":"https://github.com/glebuk","followers_url":"https://api.github.com/users/glebuk/followers","following_url":"https://api.github.com/users/glebuk/following{/other_user}","gists_url":"https://api.github.com/users/glebuk/gists{/gist_id}","starred_url":"https://api.github.com/users/glebuk/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/glebuk/subscriptions","organizations_url":"https://api.github.com/users/glebuk/orgs","repos_url":"https://api.github.com/users/glebuk/repos","events_url":"https://api.github.com/users/glebuk/events{/privacy}","received_events_url":"https://api.github.com/users/glebuk/received_events","type":"User","site_admin":false}],"milestone":{"url":"https://api.github.com/repos/dotnet/machinelearning/milestones/1","html_url":"https://github.com/dotnet/machinelearning/milestone/1","labels_url":"https://api.github.com/repos/dotnet/machinelearning/milestones/1/labels","id":3331667,"number":1,"title":"0518","description":"","creator":{"login":"shauheen","id":3270738,"avatar_url":"https://avatars3.githubusercontent.com/u/3270738?v=4","gravatar_id":"","url":"https://api.github.com/users/shauheen","html_url":"https://github.com/shauheen","followers_url":"https://api.github.com/users/shauheen/followers","following_url":"https://api.github.com/users/shauheen/following{/other_user}","gists_url":"https://api.github.com/users/shauheen/gists{/gist_id}","starred_url":"https://api.github.com/users/shauheen/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/shauheen/subscriptions","organizations_url":"https://api.github.com/users/shauheen/orgs","repos_url":"https://api.github.com/users/shauheen/repos","events_url":"https://api.github.com/users/shauheen/events{/privacy}","received_events_url":"https://api.github.com/users/shauheen/received_events","type":"User","site_admin":false},"open_issues":32,"closed_issues":17,"state":"open","created_at":"2018-05-08T22:47:08Z","updated_at":"2018-05-18T22:07:51Z","due_on":"2018-06-01T07:00:00Z","closed_at":null},"comments":6,"created_at":"2018-05-17T04:02:33Z","updated_at":"2018-05-20T22:40:55Z","closed_at":null,"author_association":"NONE","body":"I trained a `FastForestBinaryClassifier` on a toy model with two features and zero input transformations, and found that calling the `Predict` method on the resulting model takes about 5ms for a single input on a high spec machine.  This seems quite slow, shouldn't it take less than 1ms?\r\n\r\nI notice that the `FastTreePredictionWrapper` type is able to write itself out as code:\r\n\r\nhttps://github.com/dotnet/machinelearning/blob/ae1ecefce576baed2419bd61f5782489d94d1821/src/Microsoft.ML.FastTree/FastTree.cs#L2942\r\n\r\nWould it be possible to write out the calibrated model as C# code, which should presumably be faster to run?  This would have the additional benefit of being able to be included as a static model which can be deployed without any `ML.Net` dependencies...\r\n"},"comment":{"url":"https://api.github.com/repos/dotnet/machinelearning/issues/comments/390518410","html_url":"https://github.com/dotnet/machinelearning/issues/179#issuecomment-390518410","issue_url":"https://api.github.com/repos/dotnet/machinelearning/issues/179","id":390518410,"user":{"login":"mjmckp","id":7776787,"avatar_url":"https://avatars0.githubusercontent.com/u/7776787?v=4","gravatar_id":"","url":"https://api.github.com/users/mjmckp","html_url":"https://github.com/mjmckp","followers_url":"https://api.github.com/users/mjmckp/followers","following_url":"https://api.github.com/users/mjmckp/following{/other_user}","gists_url":"https://api.github.com/users/mjmckp/gists{/gist_id}","starred_url":"https://api.github.com/users/mjmckp/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mjmckp/subscriptions","organizations_url":"https://api.github.com/users/mjmckp/orgs","repos_url":"https://api.github.com/users/mjmckp/repos","events_url":"https://api.github.com/users/mjmckp/events{/privacy}","received_events_url":"https://api.github.com/users/mjmckp/received_events","type":"User","site_admin":false},"created_at":"2018-05-20T22:40:55Z","updated_at":"2018-05-20T22:40:55Z","author_association":"NONE","body":"Thanks @glebuk, I think that is what I am doing, see below.   The output of the program when run is:\r\n```\r\nNot adding a normalizer.\r\nMaking per-feature arrays\r\nChanging data from row-wise to column-wise\r\nProcessed 100 instances\r\nBinning and forming Feature objects\r\nReserved memory for tree learner: 31824 bytes\r\nStarting to train ...\r\nWarning: 5 of the boosting iterations failed to grow a tree. This is commonly because the minimum documents in leaf hyperparameter was set too high for this dataset.\r\nTraining calibrator.\r\nCalling inputEnumerator.Retarget\r\nFacadeEnumerator: Retarget\r\nCalling outputEnumerator.MoveNext\r\nFacadeEnumerator: GetEnumerator\r\nFacadeEnumerator: MoveNext\r\nFacadeEnumerator: Current\r\nFacadeEnumerator: MoveNext\r\nFacadeEnumerator: Moved past the end!\r\n```\r\n\r\nSelf-contained repro:\r\n```\r\nusing System;\r\nusing System.Collections;\r\nusing System.Collections.Generic;\r\nusing Microsoft.ML;\r\nusing Microsoft.ML.Data;\r\nusing Microsoft.ML.Runtime.Api;\r\nusing Microsoft.ML.Trainers;\r\n\r\nnamespace Axon.Research.ML.Net.Cs\r\n{\r\n    class Program\r\n    {\r\n        public sealed class FacadeEnumerator<T> : IEnumerator<T>\r\n        {\r\n            private IEnumerator<T> _target;\r\n\r\n            public FacadeEnumerator()\r\n            {\r\n            }\r\n\r\n            public void Retarget(IEnumerator<T> target)\r\n            {\r\n                Console.WriteLine(\"FacadeEnumerator: Retarget\");\r\n                _target = target;\r\n            }\r\n\r\n            public T Current\r\n            {\r\n                get\r\n                {\r\n                    Console.WriteLine(\"FacadeEnumerator: Current\");\r\n                    if (_target == null)\r\n                        return default(T);\r\n                    return _target.Current;\r\n                }\r\n            }\r\n\r\n            object IEnumerator.Current\r\n            {\r\n                get\r\n                {\r\n                    return Current;\r\n                }\r\n            }\r\n\r\n            public void Dispose()\r\n            {\r\n            }\r\n\r\n            public bool MoveNext()\r\n            {\r\n                Console.WriteLine(\"FacadeEnumerator: MoveNext\");\r\n                var hasNext = _target.MoveNext();\r\n                if (!hasNext)\r\n                {\r\n                    Console.WriteLine(\"FacadeEnumerator: Moved past the end!\");\r\n                    throw (new Exception(\"Moved past the end!\"));\r\n                }\r\n                return hasNext;\r\n            }\r\n\r\n            public void Reset()\r\n            {\r\n                throw (new Exception(\"Reset is not expected to be used when scoring.\"));\r\n            }\r\n        }\r\n\r\n        public sealed class FacadeEnumerable<T> : IEnumerable<T>\r\n        {\r\n            private readonly FacadeEnumerator<T> _enumerator;\r\n\r\n            public FacadeEnumerable()\r\n            {\r\n                _enumerator = new FacadeEnumerator<T>();\r\n            }\r\n\r\n            public FacadeEnumerator<T> GetEnumerator()\r\n            {\r\n                return _enumerator;\r\n            }\r\n\r\n            IEnumerator<T> IEnumerable<T>.GetEnumerator()\r\n            {\r\n                Console.WriteLine(\"FacadeEnumerator: GetEnumerator\");\r\n                return _enumerator;\r\n            }\r\n\r\n            IEnumerator IEnumerable.GetEnumerator()\r\n            {\r\n                return _enumerator;\r\n            }\r\n        }\r\n        public class Data\r\n        {\r\n            [ColumnName(\"Features\")]\r\n            [VectorType(2)]\r\n            public float[] Features;\r\n\r\n            [ColumnName(\"Label\")]\r\n            public float Label;\r\n        }\r\n\r\n        public class Prediction\r\n        {\r\n            [ColumnName(\"PredictedLabel\")]\r\n            public bool PredictedLabel;\r\n        }\r\n\r\n        static PredictionModel<Data,Prediction> Train(IEnumerable<Data> data)\r\n        {\r\n            var pipeline = new LearningPipeline();\r\n            pipeline.Add(CollectionDataSource.Create(data));\r\n            pipeline.Add(new FastForestBinaryClassifier());\r\n            var model = pipeline.Train<Data, Prediction>();\r\n            return model;\r\n        }\r\n\r\n        static void Main(string[] args)\r\n        {\r\n            var data = new Data[100];\r\n            var rand = new Random();\r\n            for (var i = 0; i < data.Length; i++)\r\n            {\r\n                data[i] = new Data();\r\n                data[i].Features = new float[] { (float)rand.NextDouble(), (float)rand.NextDouble() };\r\n                data[i].Label = rand.Next(2) == 0 ? 0.0f : 1.0f;\r\n            }\r\n\r\n            var model = Train(data);\r\n\r\n            var facade = new FacadeEnumerable<Data>();\r\n            var inputEnumerator = facade.GetEnumerator();\r\n            var outputEnumerator = model.Predict(facade).GetEnumerator();\r\n\r\n            // simulate evaluation of single input\r\n            var input = new List<Data>(1);\r\n            input.Add(new Data());\r\n\r\n            for (var i=0; i<10; i++)\r\n            {\r\n                input[0].Features = new float[] { (float)rand.NextDouble(), (float)rand.NextDouble() };\r\n                Console.WriteLine(\"Calling inputEnumerator.Retarget\");\r\n                inputEnumerator.Retarget(input.GetEnumerator());\r\n                Console.WriteLine(\"Calling outputEnumerator.MoveNext\");\r\n                if (!outputEnumerator.MoveNext())\r\n                    throw (new Exception(\"Failed to MoveNext on output enumerator\"));\r\n                Console.WriteLine(\"{0} {1}\", i, outputEnumerator.Current.PredictedLabel);\r\n            }\r\n        }\r\n    }\r\n}\r\n```\r\n"}}
{"actor":{"display_login":"mjmckp"}}