From 7360f91a6867191c33fd7a07f6dfec5595e740b3 Mon Sep 17 00:00:00 2001
From: dayo <dayo05@daum.net>
Date: Sun, 28 Nov 2021 12:33:52 +0900
Subject: [PATCH 01/38] Add pytorch style dataloader

---
 src/TorchSharp/Data/DataLoader.cs | 96 +++++++++++++++++++++++++++++++
 src/TorchSharp/Data/Dataset.cs    | 14 +++++
 2 files changed, 110 insertions(+)
 create mode 100644 src/TorchSharp/Data/DataLoader.cs
 create mode 100644 src/TorchSharp/Data/Dataset.cs

diff --git a/src/TorchSharp/Data/DataLoader.cs b/src/TorchSharp/Data/DataLoader.cs
new file mode 100644
index 000000000..d774e7110
--- /dev/null
+++ b/src/TorchSharp/Data/DataLoader.cs
@@ -0,0 +1,96 @@
+using System;
+using System.Linq;
+using System.Collections;
+using System.Collections.Generic;
+
+using static TorchSharp.torch;
+
+namespace TorchSharp.Data
+{
+    public class DataLoader: IEnumerable<(Tensor, Tensor)>
+    {
+        private Dataset dataset;
+        private int batchSize;
+        private bool shuffle;
+        private Device device;
+
+        public DataLoader(Dataset dataset, int batchSize, bool shuffle = false, Device device = null)
+        {
+            this.dataset = dataset;
+            this.batchSize = batchSize;
+            this.shuffle = shuffle;
+            this.device = device ?? CPU;
+        }
+        public IEnumerator<(Tensor, Tensor)> GetEnumerator()
+        {
+            return new DataLoaderEnumerator(dataset, batchSize, shuffle, device);
+        }
+
+        IEnumerator IEnumerable.GetEnumerator()
+        {
+            return GetEnumerator();
+        }
+
+        public long Count => (dataset.Count() - 1) / batchSize + 1;
+
+        private class DataLoaderEnumerator : IEnumerator<(Tensor, Tensor)>
+        {
+            private Dataset dataset;
+            private IEnumerator<object> load;
+            private int batchSize;
+            private Device device;
+            public DataLoaderEnumerator(Dataset dataset, int batchSize, bool shuffle, Device device)
+            {
+                this.dataset = dataset;
+                this.batchSize = batchSize;
+                this.device = device;
+
+                if (shuffle)
+                {
+                    var r = new Random();
+                    load = dataset.GetDataEnumerable()
+                        .Select(x => new {Number = r.Next(), Item = x})
+                        .OrderBy(x => x.Number)
+                        .Select(x => x.Item)
+                        .GetEnumerator();
+                }
+                else load = dataset.GetDataEnumerable().GetEnumerator();
+            }
+
+            private Tensor dataTensor;
+            private Tensor labelTensor;
+            private (Tensor, Tensor) tmp;
+
+            public bool MoveNext()
+            {
+                if (!load.MoveNext()) return false;
+                (dataTensor, labelTensor) = dataset.GetTensor(load.Current);
+                dataTensor.unsqueeze_(0);
+                for (var i = 1; i < batchSize; i++)
+                {
+                    if (!load.MoveNext())
+                        break;
+                    tmp = dataset.GetTensor(load.Current);
+                    dataTensor = cat(new List<Tensor> {dataTensor, tmp.Item1.unsqueeze(0)}, 0);
+                    labelTensor = cat(new List<Tensor> {labelTensor, tmp.Item2}, 0);
+                }
+                return true;
+            }
+
+            public void Reset()
+            {
+                load.Reset();
+            }
+
+            public (Tensor, Tensor) Current => (dataTensor.to(device), labelTensor.to(device));
+
+            object IEnumerator.Current => Current;
+
+            public void Dispose()
+            {
+                load.Dispose();
+                dataset.Dispose();
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/TorchSharp/Data/Dataset.cs b/src/TorchSharp/Data/Dataset.cs
new file mode 100644
index 000000000..6b23dc4f6
--- /dev/null
+++ b/src/TorchSharp/Data/Dataset.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+
+using static TorchSharp.torch;
+
+namespace TorchSharp.Data
+{
+    public interface Dataset: IDisposable
+    {
+        public long Count();
+        public (Tensor, Tensor) GetTensor(object index);
+        public IEnumerable<object> GetDataEnumerable();
+    }
+}
\ No newline at end of file

From 3de29c35d1770afadea61a6958cbbbf4162f5d7b Mon Sep 17 00:00:00 2001
From: dayo <dayo05@daum.net>
Date: Tue, 30 Nov 2021 22:21:06 +0900
Subject: [PATCH 02/38] Remove GetDataEnumerable from interface

---
 src/TorchSharp/Data/Dataset.cs | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/src/TorchSharp/Data/Dataset.cs b/src/TorchSharp/Data/Dataset.cs
index 6b23dc4f6..733261a02 100644
--- a/src/TorchSharp/Data/Dataset.cs
+++ b/src/TorchSharp/Data/Dataset.cs
@@ -8,7 +8,6 @@ namespace TorchSharp.Data
     public interface Dataset: IDisposable
     {
         public long Count();
-        public (Tensor, Tensor) GetTensor(object index);
-        public IEnumerable<object> GetDataEnumerable();
+        public (Tensor, Tensor) GetTensor(int index);
     }
 }
\ No newline at end of file

From 857f9e6862e7ddf22ff006a0b60aeeacc44a3990 Mon Sep 17 00:00:00 2001
From: dayo <dayo05@daum.net>
Date: Tue, 30 Nov 2021 23:16:14 +0900
Subject: [PATCH 03/38] Resolve review except get random value

---
 src/TorchSharp/Data/DataLoader.cs | 36 ++++++++++++++-----------------
 src/TorchSharp/Data/Dataset.cs    |  2 +-
 2 files changed, 17 insertions(+), 21 deletions(-)

diff --git a/src/TorchSharp/Data/DataLoader.cs b/src/TorchSharp/Data/DataLoader.cs
index d774e7110..b67b08b0e 100644
--- a/src/TorchSharp/Data/DataLoader.cs
+++ b/src/TorchSharp/Data/DataLoader.cs
@@ -31,46 +31,43 @@ IEnumerator IEnumerable.GetEnumerator()
             return GetEnumerator();
         }
 
-        public long Count => (dataset.Count() - 1) / batchSize + 1;
+        public long Count => (dataset.Count - 1) / batchSize + 1;
 
         private class DataLoaderEnumerator : IEnumerator<(Tensor, Tensor)>
         {
             private Dataset dataset;
-            private IEnumerator<object> load;
             private int batchSize;
             private Device device;
+            private bool shuffle;
             public DataLoaderEnumerator(Dataset dataset, int batchSize, bool shuffle, Device device)
             {
                 this.dataset = dataset;
                 this.batchSize = batchSize;
                 this.device = device;
-
-                if (shuffle)
-                {
-                    var r = new Random();
-                    load = dataset.GetDataEnumerable()
-                        .Select(x => new {Number = r.Next(), Item = x})
-                        .OrderBy(x => x.Number)
-                        .Select(x => x.Item)
-                        .GetEnumerator();
-                }
-                else load = dataset.GetDataEnumerable().GetEnumerator();
+                this.shuffle = shuffle;
             }
 
             private Tensor dataTensor;
             private Tensor labelTensor;
-            private (Tensor, Tensor) tmp;
 
+            private bool isFinished()
+            {
+                throw new NotImplementedException();
+            }
+            private int getRandomValue()
+            {
+                throw new NotImplementedException();
+            }
             public bool MoveNext()
             {
-                if (!load.MoveNext()) return false;
-                (dataTensor, labelTensor) = dataset.GetTensor(load.Current);
+                if (isFinished()) return false;
+                (dataTensor, labelTensor) = dataset.GetTensor(getRandomValue());
                 dataTensor.unsqueeze_(0);
                 for (var i = 1; i < batchSize; i++)
                 {
-                    if (!load.MoveNext())
+                    if (isFinished())
                         break;
-                    tmp = dataset.GetTensor(load.Current);
+                    var tmp = dataset.GetTensor(getRandomValue());
                     dataTensor = cat(new List<Tensor> {dataTensor, tmp.Item1.unsqueeze(0)}, 0);
                     labelTensor = cat(new List<Tensor> {labelTensor, tmp.Item2}, 0);
                 }
@@ -79,7 +76,7 @@ public bool MoveNext()
 
             public void Reset()
             {
-                load.Reset();
+
             }
 
             public (Tensor, Tensor) Current => (dataTensor.to(device), labelTensor.to(device));
@@ -88,7 +85,6 @@ public void Reset()
 
             public void Dispose()
             {
-                load.Dispose();
                 dataset.Dispose();
             }
         }
diff --git a/src/TorchSharp/Data/Dataset.cs b/src/TorchSharp/Data/Dataset.cs
index 733261a02..f4b9a1161 100644
--- a/src/TorchSharp/Data/Dataset.cs
+++ b/src/TorchSharp/Data/Dataset.cs
@@ -7,7 +7,7 @@ namespace TorchSharp.Data
 {
     public interface Dataset: IDisposable
     {
-        public long Count();
+        public long Count { get; }
         public (Tensor, Tensor) GetTensor(int index);
     }
 }
\ No newline at end of file

From 954fa8c5510309d48bbf6658a58af45c6661eaed Mon Sep 17 00:00:00 2001
From: dayo <dayo05@daum.net>
Date: Tue, 30 Nov 2021 23:39:17 +0900
Subject: [PATCH 04/38] Rename method and create reset method

---
 src/TorchSharp/Data/DataLoader.cs | 21 ++++++++++++---------
 1 file changed, 12 insertions(+), 9 deletions(-)

diff --git a/src/TorchSharp/Data/DataLoader.cs b/src/TorchSharp/Data/DataLoader.cs
index b67b08b0e..76c6ac379 100644
--- a/src/TorchSharp/Data/DataLoader.cs
+++ b/src/TorchSharp/Data/DataLoader.cs
@@ -45,6 +45,7 @@ public DataLoaderEnumerator(Dataset dataset, int batchSize, bool shuffle, Device
                 this.batchSize = batchSize;
                 this.device = device;
                 this.shuffle = shuffle;
+                reset();
             }
 
             private Tensor dataTensor;
@@ -54,30 +55,32 @@ private bool isFinished()
             {
                 throw new NotImplementedException();
             }
-            private int getRandomValue()
+            private int getNextValue()
+            {
+                throw new NotImplementedException();
+            }
+
+            private void reset()
             {
                 throw new NotImplementedException();
             }
             public bool MoveNext()
             {
                 if (isFinished()) return false;
-                (dataTensor, labelTensor) = dataset.GetTensor(getRandomValue());
+                (dataTensor, labelTensor) = dataset.GetTensor(getNextValue());
                 dataTensor.unsqueeze_(0);
                 for (var i = 1; i < batchSize; i++)
                 {
                     if (isFinished())
                         break;
-                    var tmp = dataset.GetTensor(getRandomValue());
-                    dataTensor = cat(new List<Tensor> {dataTensor, tmp.Item1.unsqueeze(0)}, 0);
-                    labelTensor = cat(new List<Tensor> {labelTensor, tmp.Item2}, 0);
+                    var (data, label) = dataset.GetTensor(getNextValue());
+                    dataTensor = cat(new List<Tensor> {dataTensor, data.unsqueeze(0)}, 0);
+                    labelTensor = cat(new List<Tensor> {labelTensor, label}, 0);
                 }
                 return true;
             }
 
-            public void Reset()
-            {
-
-            }
+            public void Reset() => reset();
 
             public (Tensor, Tensor) Current => (dataTensor.to(device), labelTensor.to(device));
 

From 63568f9fd21a62b9808940d0888ff4c6bcc5656b Mon Sep 17 00:00:00 2001
From: dayo <dayo05@daum.net>
Date: Wed, 1 Dec 2021 00:06:24 +0900
Subject: [PATCH 05/38] Add copyright string

---
 src/TorchSharp/Data/DataLoader.cs | 15 +++++++--------
 src/TorchSharp/Data/Dataset.cs    |  1 +
 2 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/src/TorchSharp/Data/DataLoader.cs b/src/TorchSharp/Data/DataLoader.cs
index 76c6ac379..d95cd6f01 100644
--- a/src/TorchSharp/Data/DataLoader.cs
+++ b/src/TorchSharp/Data/DataLoader.cs
@@ -1,3 +1,4 @@
+// Copyright (c) .NET Foundation and Contributors.  All Rights Reserved.  See LICENSE in the project root for license information.
 using System;
 using System.Linq;
 using System.Collections;
@@ -21,15 +22,10 @@ public DataLoader(Dataset dataset, int batchSize, bool shuffle = false, Device d
             this.shuffle = shuffle;
             this.device = device ?? CPU;
         }
-        public IEnumerator<(Tensor, Tensor)> GetEnumerator()
-        {
-            return new DataLoaderEnumerator(dataset, batchSize, shuffle, device);
-        }
 
-        IEnumerator IEnumerable.GetEnumerator()
-        {
-            return GetEnumerator();
-        }
+        public IEnumerator<(Tensor, Tensor)> GetEnumerator() => new DataLoaderEnumerator(dataset, batchSize, shuffle, device);
+
+        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
 
         public long Count => (dataset.Count - 1) / batchSize + 1;
 
@@ -39,6 +35,7 @@ private class DataLoaderEnumerator : IEnumerator<(Tensor, Tensor)>
             private int batchSize;
             private Device device;
             private bool shuffle;
+
             public DataLoaderEnumerator(Dataset dataset, int batchSize, bool shuffle, Device device)
             {
                 this.dataset = dataset;
@@ -55,6 +52,7 @@ private bool isFinished()
             {
                 throw new NotImplementedException();
             }
+
             private int getNextValue()
             {
                 throw new NotImplementedException();
@@ -64,6 +62,7 @@ private void reset()
             {
                 throw new NotImplementedException();
             }
+
             public bool MoveNext()
             {
                 if (isFinished()) return false;
diff --git a/src/TorchSharp/Data/Dataset.cs b/src/TorchSharp/Data/Dataset.cs
index f4b9a1161..6240f0ab0 100644
--- a/src/TorchSharp/Data/Dataset.cs
+++ b/src/TorchSharp/Data/Dataset.cs
@@ -1,3 +1,4 @@
+// Copyright (c) .NET Foundation and Contributors.  All Rights Reserved.  See LICENSE in the project root for license information.
 using System;
 using System.Collections.Generic;
 

From d8d249f1298812f9fdb614c71eabf2407056aada Mon Sep 17 00:00:00 2001
From: dayo <dayo05@daum.net>
Date: Wed, 1 Dec 2021 00:54:05 +0900
Subject: [PATCH 06/38] Use new shuffle algorithm

---
 src/TorchSharp/Data/DataLoader.cs       | 13 ++--
 src/TorchSharp/Data/Dataset.cs          |  2 +-
 src/TorchSharp/Data/ShuffleGenerator.cs | 89 +++++++++++++++++++++++++
 3 files changed, 94 insertions(+), 10 deletions(-)
 create mode 100644 src/TorchSharp/Data/ShuffleGenerator.cs

diff --git a/src/TorchSharp/Data/DataLoader.cs b/src/TorchSharp/Data/DataLoader.cs
index d95cd6f01..bb96e8267 100644
--- a/src/TorchSharp/Data/DataLoader.cs
+++ b/src/TorchSharp/Data/DataLoader.cs
@@ -35,6 +35,7 @@ private class DataLoaderEnumerator : IEnumerator<(Tensor, Tensor)>
             private int batchSize;
             private Device device;
             private bool shuffle;
+            private ShuffleGenerator shuffleGenerator;
 
             public DataLoaderEnumerator(Dataset dataset, int batchSize, bool shuffle, Device device)
             {
@@ -48,19 +49,13 @@ public DataLoaderEnumerator(Dataset dataset, int batchSize, bool shuffle, Device
             private Tensor dataTensor;
             private Tensor labelTensor;
 
-            private bool isFinished()
-            {
-                throw new NotImplementedException();
-            }
+            private bool isFinished() => !shuffleGenerator.hasNext();
 
-            private int getNextValue()
-            {
-                throw new NotImplementedException();
-            }
+            private int getNextValue() => shuffleGenerator.next();
 
             private void reset()
             {
-                throw new NotImplementedException();
+                shuffleGenerator = new ShuffleGenerator(dataset.Count);
             }
 
             public bool MoveNext()
diff --git a/src/TorchSharp/Data/Dataset.cs b/src/TorchSharp/Data/Dataset.cs
index 6240f0ab0..911d3e87d 100644
--- a/src/TorchSharp/Data/Dataset.cs
+++ b/src/TorchSharp/Data/Dataset.cs
@@ -8,7 +8,7 @@ namespace TorchSharp.Data
 {
     public interface Dataset: IDisposable
     {
-        public long Count { get; }
+        public int Count { get; }
         public (Tensor, Tensor) GetTensor(int index);
     }
 }
\ No newline at end of file
diff --git a/src/TorchSharp/Data/ShuffleGenerator.cs b/src/TorchSharp/Data/ShuffleGenerator.cs
new file mode 100644
index 000000000..2a553770a
--- /dev/null
+++ b/src/TorchSharp/Data/ShuffleGenerator.cs
@@ -0,0 +1,89 @@
+using System;
+
+namespace TorchSharp.Data
+{
+    public class ShuffleGenerator
+    {
+        int maxrange;
+        int prime;
+        int index;
+        int offset;
+        int runningvalue;
+
+        public ShuffleGenerator(int size)
+        {
+            var min = size / 2;
+            maxrange = size;
+            prime = selectCoPrimeResev(min, size);
+            offset = new Random().Next(size);
+            index = 0;
+            runningvalue = offset;
+        }
+
+        private int getCurrentValue()
+        {
+            return (int) (((long) index * prime + offset) % (maxrange));
+        }
+
+        public bool hasNext()
+        {
+            return index < maxrange;
+        }
+
+        public int next()
+        {
+            runningvalue += prime;
+            if (runningvalue >= maxrange) runningvalue -= maxrange;
+            index++;
+            return runningvalue;
+        }
+
+        private const int MAX_COUNT = int.MaxValue;
+
+        static int selectCoPrimeResev(int min, int target)
+        {
+            var count = 0;
+            var selected = 0;
+            var rand = new Random();
+            for (var val = min; val < target; ++val) {
+                if (coprime(val, target)) {
+                    count += 1;
+                    if ((count == 1) || (rand.Next(count) < 1)) {
+                        selected = val;
+                    }
+                }
+
+                if (count == MAX_COUNT) return val;
+            }
+
+            return selected;
+        }
+
+        static bool coprime(int u, int v) => gcd(u, v) == 1;
+
+        static int gcd(int u, int v)
+        {
+            int shift;
+            if (u == 0) return v;
+            if (v == 0) return u;
+            for (shift = 0; ((u | v) & 1) == 0; ++shift) {
+                u >>= 1;
+                v >>= 1;
+            }
+
+            while ((u & 1) == 0)
+                u >>= 1;
+
+            do {
+                while ((v & 1) == 0)
+                    v >>= 1;
+                if (u > v)
+                    (v, u) = (u, v);
+
+                v -= u;
+            } while (v != 0);
+
+            return u << shift;
+        }
+    }
+}
\ No newline at end of file

From ab2eb092f36c85e7def260a727f91ad32784168c Mon Sep 17 00:00:00 2001
From: dayo <dayo05@daum.net>
Date: Wed, 1 Dec 2021 01:54:36 +0900
Subject: [PATCH 07/38] Add summery

---
 src/TorchSharp/Data/DataLoader.cs | 9 +++++++--
 src/TorchSharp/Data/Dataset.cs    | 1 -
 2 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/src/TorchSharp/Data/DataLoader.cs b/src/TorchSharp/Data/DataLoader.cs
index bb96e8267..8e3fa45f9 100644
--- a/src/TorchSharp/Data/DataLoader.cs
+++ b/src/TorchSharp/Data/DataLoader.cs
@@ -1,6 +1,4 @@
 // Copyright (c) .NET Foundation and Contributors.  All Rights Reserved.  See LICENSE in the project root for license information.
-using System;
-using System.Linq;
 using System.Collections;
 using System.Collections.Generic;
 
@@ -15,6 +13,13 @@ public class DataLoader: IEnumerable<(Tensor, Tensor)>
         private bool shuffle;
         private Device device;
 
+        /// <summary>
+        /// Create pytorch style dataloader
+        /// </summary>
+        /// <param name="dataset"></param>
+        /// <param name="batchSize"></param>
+        /// <param name="shuffle"></param>
+        /// <param name="device"></param>
         public DataLoader(Dataset dataset, int batchSize, bool shuffle = false, Device device = null)
         {
             this.dataset = dataset;
diff --git a/src/TorchSharp/Data/Dataset.cs b/src/TorchSharp/Data/Dataset.cs
index 911d3e87d..13d9975bb 100644
--- a/src/TorchSharp/Data/Dataset.cs
+++ b/src/TorchSharp/Data/Dataset.cs
@@ -1,6 +1,5 @@
 // Copyright (c) .NET Foundation and Contributors.  All Rights Reserved.  See LICENSE in the project root for license information.
 using System;
-using System.Collections.Generic;
 
 using static TorchSharp.torch;
 

From ca4934030628214a7a5752ce93e1653b33be2e52 Mon Sep 17 00:00:00 2001
From: dayo <dayo05@daum.net>
Date: Wed, 1 Dec 2021 02:06:41 +0900
Subject: [PATCH 08/38] Make able to create non-shuffle dataloader

---
 src/TorchSharp/Data/DataLoader.cs | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/src/TorchSharp/Data/DataLoader.cs b/src/TorchSharp/Data/DataLoader.cs
index 8e3fa45f9..74d1cf693 100644
--- a/src/TorchSharp/Data/DataLoader.cs
+++ b/src/TorchSharp/Data/DataLoader.cs
@@ -41,6 +41,7 @@ private class DataLoaderEnumerator : IEnumerator<(Tensor, Tensor)>
             private Device device;
             private bool shuffle;
             private ShuffleGenerator shuffleGenerator;
+            private int currentVal = 0;
 
             public DataLoaderEnumerator(Dataset dataset, int batchSize, bool shuffle, Device device)
             {
@@ -56,11 +57,12 @@ public DataLoaderEnumerator(Dataset dataset, int batchSize, bool shuffle, Device
 
             private bool isFinished() => !shuffleGenerator.hasNext();
 
-            private int getNextValue() => shuffleGenerator.next();
+            private int getNextValue() => shuffle ? shuffleGenerator.next() : currentVal++;
 
             private void reset()
             {
                 shuffleGenerator = new ShuffleGenerator(dataset.Count);
+                currentVal = 0;
             }
 
             public bool MoveNext()

From 2cc2300b86036b255c2ff93f4846c54d8ed9248b Mon Sep 17 00:00:00 2001
From: dayo <dayo05@daum.net>
Date: Wed, 1 Dec 2021 02:07:54 +0900
Subject: [PATCH 09/38] Make able to create non-shuffle dataset

---
 src/TorchSharp/Data/DataLoader.cs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/TorchSharp/Data/DataLoader.cs b/src/TorchSharp/Data/DataLoader.cs
index 74d1cf693..e830622c8 100644
--- a/src/TorchSharp/Data/DataLoader.cs
+++ b/src/TorchSharp/Data/DataLoader.cs
@@ -55,7 +55,7 @@ public DataLoaderEnumerator(Dataset dataset, int batchSize, bool shuffle, Device
             private Tensor dataTensor;
             private Tensor labelTensor;
 
-            private bool isFinished() => !shuffleGenerator.hasNext();
+            private bool isFinished() => shuffle ? !shuffleGenerator.hasNext() : currentVal >= dataset.Count;
 
             private int getNextValue() => shuffle ? shuffleGenerator.next() : currentVal++;
 

From 4cff460f59d7a888c33920cab7f3216bcc5cf556 Mon Sep 17 00:00:00 2001
From: dayo <dayo05@daum.net>
Date: Wed, 1 Dec 2021 02:26:20 +0900
Subject: [PATCH 10/38] Change tensor tuple to dictionary

---
 src/TorchSharp/Data/DataLoader.cs | 24 ++++++++++++------------
 src/TorchSharp/Data/Dataset.cs    |  4 ++--
 2 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/src/TorchSharp/Data/DataLoader.cs b/src/TorchSharp/Data/DataLoader.cs
index e830622c8..6952af5cc 100644
--- a/src/TorchSharp/Data/DataLoader.cs
+++ b/src/TorchSharp/Data/DataLoader.cs
@@ -6,7 +6,7 @@
 
 namespace TorchSharp.Data
 {
-    public class DataLoader: IEnumerable<(Tensor, Tensor)>
+    public class DataLoader: IEnumerable<Dictionary<string, Tensor>>
     {
         private Dataset dataset;
         private int batchSize;
@@ -28,13 +28,13 @@ public DataLoader(Dataset dataset, int batchSize, bool shuffle = false, Device d
             this.device = device ?? CPU;
         }
 
-        public IEnumerator<(Tensor, Tensor)> GetEnumerator() => new DataLoaderEnumerator(dataset, batchSize, shuffle, device);
+        public IEnumerator<Dictionary<string, Tensor>> GetEnumerator() => new DataLoaderEnumerator(dataset, batchSize, shuffle, device);
 
         IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
 
         public long Count => (dataset.Count - 1) / batchSize + 1;
 
-        private class DataLoaderEnumerator : IEnumerator<(Tensor, Tensor)>
+        private class DataLoaderEnumerator : IEnumerator<Dictionary<string, Tensor>>
         {
             private Dataset dataset;
             private int batchSize;
@@ -52,9 +52,6 @@ public DataLoaderEnumerator(Dataset dataset, int batchSize, bool shuffle, Device
                 reset();
             }
 
-            private Tensor dataTensor;
-            private Tensor labelTensor;
-
             private bool isFinished() => shuffle ? !shuffleGenerator.hasNext() : currentVal >= dataset.Count;
 
             private int getNextValue() => shuffle ? shuffleGenerator.next() : currentVal++;
@@ -68,22 +65,25 @@ private void reset()
             public bool MoveNext()
             {
                 if (isFinished()) return false;
-                (dataTensor, labelTensor) = dataset.GetTensor(getNextValue());
-                dataTensor.unsqueeze_(0);
+                Current = dataset.GetTensor(getNextValue());
+                var currentKeys = Current.Keys;
+                foreach (var x in currentKeys)
+                    Current[x].unsqueeze_(0);
+                Dictionary<string, Tensor> dic;
                 for (var i = 1; i < batchSize; i++)
                 {
                     if (isFinished())
                         break;
-                    var (data, label) = dataset.GetTensor(getNextValue());
-                    dataTensor = cat(new List<Tensor> {dataTensor, data.unsqueeze(0)}, 0);
-                    labelTensor = cat(new List<Tensor> {labelTensor, label}, 0);
+                    dic = dataset.GetTensor(getNextValue());
+                    foreach (var x in currentKeys)
+                        Current[x] = cat(new List<Tensor>() {dic[x].unsqueeze(0), Current[x]}, 0);
                 }
                 return true;
             }
 
             public void Reset() => reset();
 
-            public (Tensor, Tensor) Current => (dataTensor.to(device), labelTensor.to(device));
+            public Dictionary<string, Tensor> Current { get; private set; }
 
             object IEnumerator.Current => Current;
 
diff --git a/src/TorchSharp/Data/Dataset.cs b/src/TorchSharp/Data/Dataset.cs
index 13d9975bb..77b48685e 100644
--- a/src/TorchSharp/Data/Dataset.cs
+++ b/src/TorchSharp/Data/Dataset.cs
@@ -1,6 +1,6 @@
 // Copyright (c) .NET Foundation and Contributors.  All Rights Reserved.  See LICENSE in the project root for license information.
 using System;
-
+using System.Collections.Generic;
 using static TorchSharp.torch;
 
 namespace TorchSharp.Data
@@ -8,6 +8,6 @@ namespace TorchSharp.Data
     public interface Dataset: IDisposable
     {
         public int Count { get; }
-        public (Tensor, Tensor) GetTensor(int index);
+        public Dictionary<string, Tensor> GetTensor(int index);
     }
 }
\ No newline at end of file

From 17a902217feb737a496c2c15413a4d57852ab9be Mon Sep 17 00:00:00 2001
From: dayo <dayo05@daum.net>
Date: Wed, 1 Dec 2021 03:02:59 +0900
Subject: [PATCH 11/38] Replace files and make dataset abstract class

---
 src/TorchSharp/Data/DataLoader.cs             |  96 ----------------
 src/TorchSharp/Data/Dataset.cs                |  13 ---
 src/TorchSharp/DataLoader.cs                  | 107 ++++++++++++++++++
 src/TorchSharp/Dataset.cs                     |  26 +++++
 .../{Data => Utils}/ShuffleGenerator.cs       |   2 +-
 5 files changed, 134 insertions(+), 110 deletions(-)
 delete mode 100644 src/TorchSharp/Data/DataLoader.cs
 delete mode 100644 src/TorchSharp/Data/Dataset.cs
 create mode 100644 src/TorchSharp/DataLoader.cs
 create mode 100644 src/TorchSharp/Dataset.cs
 rename src/TorchSharp/{Data => Utils}/ShuffleGenerator.cs (98%)

diff --git a/src/TorchSharp/Data/DataLoader.cs b/src/TorchSharp/Data/DataLoader.cs
deleted file mode 100644
index 6952af5cc..000000000
--- a/src/TorchSharp/Data/DataLoader.cs
+++ /dev/null
@@ -1,96 +0,0 @@
-// Copyright (c) .NET Foundation and Contributors.  All Rights Reserved.  See LICENSE in the project root for license information.
-using System.Collections;
-using System.Collections.Generic;
-
-using static TorchSharp.torch;
-
-namespace TorchSharp.Data
-{
-    public class DataLoader: IEnumerable<Dictionary<string, Tensor>>
-    {
-        private Dataset dataset;
-        private int batchSize;
-        private bool shuffle;
-        private Device device;
-
-        /// <summary>
-        /// Create pytorch style dataloader
-        /// </summary>
-        /// <param name="dataset"></param>
-        /// <param name="batchSize"></param>
-        /// <param name="shuffle"></param>
-        /// <param name="device"></param>
-        public DataLoader(Dataset dataset, int batchSize, bool shuffle = false, Device device = null)
-        {
-            this.dataset = dataset;
-            this.batchSize = batchSize;
-            this.shuffle = shuffle;
-            this.device = device ?? CPU;
-        }
-
-        public IEnumerator<Dictionary<string, Tensor>> GetEnumerator() => new DataLoaderEnumerator(dataset, batchSize, shuffle, device);
-
-        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
-
-        public long Count => (dataset.Count - 1) / batchSize + 1;
-
-        private class DataLoaderEnumerator : IEnumerator<Dictionary<string, Tensor>>
-        {
-            private Dataset dataset;
-            private int batchSize;
-            private Device device;
-            private bool shuffle;
-            private ShuffleGenerator shuffleGenerator;
-            private int currentVal = 0;
-
-            public DataLoaderEnumerator(Dataset dataset, int batchSize, bool shuffle, Device device)
-            {
-                this.dataset = dataset;
-                this.batchSize = batchSize;
-                this.device = device;
-                this.shuffle = shuffle;
-                reset();
-            }
-
-            private bool isFinished() => shuffle ? !shuffleGenerator.hasNext() : currentVal >= dataset.Count;
-
-            private int getNextValue() => shuffle ? shuffleGenerator.next() : currentVal++;
-
-            private void reset()
-            {
-                shuffleGenerator = new ShuffleGenerator(dataset.Count);
-                currentVal = 0;
-            }
-
-            public bool MoveNext()
-            {
-                if (isFinished()) return false;
-                Current = dataset.GetTensor(getNextValue());
-                var currentKeys = Current.Keys;
-                foreach (var x in currentKeys)
-                    Current[x].unsqueeze_(0);
-                Dictionary<string, Tensor> dic;
-                for (var i = 1; i < batchSize; i++)
-                {
-                    if (isFinished())
-                        break;
-                    dic = dataset.GetTensor(getNextValue());
-                    foreach (var x in currentKeys)
-                        Current[x] = cat(new List<Tensor>() {dic[x].unsqueeze(0), Current[x]}, 0);
-                }
-                return true;
-            }
-
-            public void Reset() => reset();
-
-            public Dictionary<string, Tensor> Current { get; private set; }
-
-            object IEnumerator.Current => Current;
-
-            public void Dispose()
-            {
-                dataset.Dispose();
-            }
-        }
-    }
-}
\ No newline at end of file
diff --git a/src/TorchSharp/Data/Dataset.cs b/src/TorchSharp/Data/Dataset.cs
deleted file mode 100644
index 77b48685e..000000000
--- a/src/TorchSharp/Data/Dataset.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright (c) .NET Foundation and Contributors.  All Rights Reserved.  See LICENSE in the project root for license information.
-using System;
-using System.Collections.Generic;
-using static TorchSharp.torch;
-
-namespace TorchSharp.Data
-{
-    public interface Dataset: IDisposable
-    {
-        public int Count { get; }
-        public Dictionary<string, Tensor> GetTensor(int index);
-    }
-}
\ No newline at end of file
diff --git a/src/TorchSharp/DataLoader.cs b/src/TorchSharp/DataLoader.cs
new file mode 100644
index 000000000..1c594f6b5
--- /dev/null
+++ b/src/TorchSharp/DataLoader.cs
@@ -0,0 +1,107 @@
+// Copyright (c) .NET Foundation and Contributors.  All Rights Reserved.  See LICENSE in the project root for license information.
+using System.Collections;
+using System.Collections.Generic;
+
+using TorchSharp.Utils;
+
+namespace TorchSharp
+{
+    public static partial class torch
+    {
+        public static partial class utils
+        {
+            public static partial class data
+            {
+                public class DataLoader : IEnumerable<Dictionary<string, Tensor>>
+                {
+                    private Dataset dataset;
+                    private int batchSize;
+                    private bool shuffle;
+                    private Device device;
+
+                    /// <summary>
+                    /// Create pytorch style dataloader
+                    /// </summary>
+                    /// <param name="dataset"></param>
+                    /// <param name="batchSize"></param>
+                    /// <param name="shuffle"></param>
+                    /// <param name="device"></param>
+                    public DataLoader(Dataset dataset, int batchSize, bool shuffle = false, Device device = null)
+                    {
+                        this.dataset = dataset;
+                        this.batchSize = batchSize;
+                        this.shuffle = shuffle;
+                        this.device = device ?? CPU;
+                    }
+
+                    public IEnumerator<Dictionary<string, Tensor>> GetEnumerator() =>
+                        new DataLoaderEnumerator(dataset, batchSize, shuffle, device);
+
+                    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
+
+                    public long Count => (dataset.Count - 1) / batchSize + 1;
+
+                    private class DataLoaderEnumerator : IEnumerator<Dictionary<string, Tensor>>
+                    {
+                        private Dataset dataset;
+                        private int batchSize;
+                        private Device device;
+                        private bool shuffle;
+                        private ShuffleGenerator shuffleGenerator;
+                        private int currentVal = 0;
+
+                        public DataLoaderEnumerator(Dataset dataset, int batchSize, bool shuffle, Device device)
+                        {
+                            this.dataset = dataset;
+                            this.batchSize = batchSize;
+                            this.device = device;
+                            this.shuffle = shuffle;
+                            reset();
+                        }
+
+                        private bool isFinished() =>
+                            shuffle ? !shuffleGenerator.hasNext() : currentVal >= dataset.Count;
+
+                        private int getNextValue() => shuffle ? shuffleGenerator.next() : currentVal++;
+
+                        private void reset()
+                        {
+                            shuffleGenerator = new ShuffleGenerator(dataset.Count);
+                            currentVal = 0;
+                        }
+
+                        public bool MoveNext()
+                        {
+                            if (isFinished()) return false;
+                            Current = dataset.GetTensor(getNextValue());
+                            var currentKeys = Current.Keys;
+                            foreach (var x in currentKeys)
+                                Current[x].unsqueeze_(0);
+                            Dictionary<string, Tensor> dic;
+                            for (var i = 1; i < batchSize; i++) {
+                                if (isFinished())
+                                    break;
+                                dic = dataset.GetTensor(getNextValue());
+                                foreach (var x in currentKeys)
+                                    Current[x] = cat(new List<Tensor>() {dic[x].unsqueeze(0), Current[x]}, 0);
+                            }
+
+                            return true;
+                        }
+
+                        public void Reset() => reset();
+
+                        public Dictionary<string, Tensor> Current { get; private set; }
+
+                        object IEnumerator.Current => Current;
+
+                        public void Dispose()
+                        {
+                            dataset.Dispose();
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/TorchSharp/Dataset.cs b/src/TorchSharp/Dataset.cs
new file mode 100644
index 000000000..70613f17b
--- /dev/null
+++ b/src/TorchSharp/Dataset.cs
@@ -0,0 +1,26 @@
+// Copyright (c) .NET Foundation and Contributors.  All Rights Reserved.  See LICENSE in the project root for license information.
+using System;
+using System.Collections.Generic;
+
+namespace TorchSharp
+{
+    public static partial class torch
+    {
+        public static partial class utils
+        {
+            public static partial class data
+            {
+                public abstract class Dataset : IDisposable
+                {
+                    public virtual void Dispose()
+                    {
+                    }
+
+                    public int Count { get; }
+
+                    public abstract Dictionary<string, Tensor> GetTensor(int index);
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/TorchSharp/Data/ShuffleGenerator.cs b/src/TorchSharp/Utils/ShuffleGenerator.cs
similarity index 98%
rename from src/TorchSharp/Data/ShuffleGenerator.cs
rename to src/TorchSharp/Utils/ShuffleGenerator.cs
index 2a553770a..8f0394373 100644
--- a/src/TorchSharp/Data/ShuffleGenerator.cs
+++ b/src/TorchSharp/Utils/ShuffleGenerator.cs
@@ -1,6 +1,6 @@
 using System;
 
-namespace TorchSharp.Data
+namespace TorchSharp.Utils
 {
     public class ShuffleGenerator
     {

From ab6bd3e67e434130b19a41779b94665a2f2dae24 Mon Sep 17 00:00:00 2001
From: dayo <dayo05@daum.net>
Date: Wed, 1 Dec 2021 13:09:03 +0900
Subject: [PATCH 12/38] Make dataloader disposable

---
 src/TorchSharp/DataLoader.cs | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/src/TorchSharp/DataLoader.cs b/src/TorchSharp/DataLoader.cs
index 1c594f6b5..b6d32b0cd 100644
--- a/src/TorchSharp/DataLoader.cs
+++ b/src/TorchSharp/DataLoader.cs
@@ -1,4 +1,6 @@
 // Copyright (c) .NET Foundation and Contributors.  All Rights Reserved.  See LICENSE in the project root for license information.
+
+using System;
 using System.Collections;
 using System.Collections.Generic;
 
@@ -12,7 +14,7 @@ public static partial class utils
         {
             public static partial class data
             {
-                public class DataLoader : IEnumerable<Dictionary<string, Tensor>>
+                public class DataLoader : IEnumerable<Dictionary<string, Tensor>>, IDisposable
                 {
                     private Dataset dataset;
                     private int batchSize;
@@ -100,6 +102,11 @@ public void Dispose()
                             dataset.Dispose();
                         }
                     }
+
+                    public void Dispose()
+                    {
+                        dataset.Dispose();
+                    }
                 }
             }
         }

From 9631ed6acf4d89ba5076e7e63374de4fd538a0a5 Mon Sep 17 00:00:00 2001
From: dayo <dayo05@daum.net>
Date: Wed, 1 Dec 2021 13:09:24 +0900
Subject: [PATCH 13/38] Make count priority abstract

---
 src/TorchSharp/Dataset.cs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/TorchSharp/Dataset.cs b/src/TorchSharp/Dataset.cs
index 70613f17b..fa01f75dc 100644
--- a/src/TorchSharp/Dataset.cs
+++ b/src/TorchSharp/Dataset.cs
@@ -16,7 +16,7 @@ public virtual void Dispose()
                     {
                     }
 
-                    public int Count { get; }
+                    public abstract int Count { get; }
 
                     public abstract Dictionary<string, Tensor> GetTensor(int index);
                 }

From 43dfcc169fd3828a068801567850d9dc9afe48d7 Mon Sep 17 00:00:00 2001
From: dayo <dayo05@daum.net>
Date: Wed, 1 Dec 2021 13:20:11 +0900
Subject: [PATCH 14/38] Make dataloader to stack data as end of tensor

---
 src/TorchSharp/DataLoader.cs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/TorchSharp/DataLoader.cs b/src/TorchSharp/DataLoader.cs
index b6d32b0cd..28f149713 100644
--- a/src/TorchSharp/DataLoader.cs
+++ b/src/TorchSharp/DataLoader.cs
@@ -85,7 +85,7 @@ public bool MoveNext()
                                     break;
                                 dic = dataset.GetTensor(getNextValue());
                                 foreach (var x in currentKeys)
-                                    Current[x] = cat(new List<Tensor>() {dic[x].unsqueeze(0), Current[x]}, 0);
+                                    Current[x] = cat(new List<Tensor>() {Current[x], dic[x].unsqueeze(0)}, 0);
                             }
 
                             return true;

From 225b9f854ae7fead1e366246a8e711fe113e68a8 Mon Sep 17 00:00:00 2001
From: dayo <dayo05@daum.net>
Date: Wed, 1 Dec 2021 13:20:39 +0900
Subject: [PATCH 15/38] Create simple test for dataset and dataloader

---
 test/TorchSharpTest/TestDataLoader.cs | 44 +++++++++++++++++++++++++++
 1 file changed, 44 insertions(+)
 create mode 100644 test/TorchSharpTest/TestDataLoader.cs

diff --git a/test/TorchSharpTest/TestDataLoader.cs b/test/TorchSharpTest/TestDataLoader.cs
new file mode 100644
index 000000000..a09023456
--- /dev/null
+++ b/test/TorchSharpTest/TestDataLoader.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Collections.Generic;
+using Xunit;
+
+namespace TorchSharp
+{
+    public class TestDataLoader
+    {
+        private class TestDataset : torch.utils.data.Dataset
+        {
+            public override int Count { get; } = 10;
+            public override Dictionary<string, torch.Tensor> GetTensor(int index)
+            {
+                return new() {{"data", torch.tensor(1)}, {"label", torch.tensor(13)}, {"index", torch.tensor(index)}};
+            }
+        }
+
+        [Fact]
+        public void DatasetTest()
+        {
+            using var dataset = new TestDataset();
+            var d = dataset.GetTensor(0);
+            Assert.True(d.ContainsKey("data"));
+            Assert.True(d.ContainsKey("index"));
+            Assert.True(d.ContainsKey("label"));
+
+            Assert.Equal(d["data"], torch.tensor(1));
+            Assert.Equal(d["label"], torch.tensor(13));
+            Assert.Equal(d["index"], torch.tensor(0));
+        }
+
+        [Fact]
+        public void DataLoaderTest()
+        {
+            using var dataset = new TestDataset();
+            using var dataloader = new torch.utils.data.DataLoader(dataset, 2, false, torch.CPU);
+            var iterator = dataloader.GetEnumerator();
+            iterator.MoveNext();
+            Assert.Equal(iterator.Current["data"], torch.tensor(rawArray: new[]{1, 1}, dimensions: new[]{2L}));
+            Assert.Equal(iterator.Current["label"], torch.tensor(rawArray: new[]{13, 13}, dimensions: new[]{2L}));
+            Assert.Equal(iterator.Current["index"], torch.tensor(rawArray: new[]{0, 1}, dimensions: new[]{2L}));
+        }
+    }
+}
\ No newline at end of file

From 6e336ca34b29d2be15ad188720e3d8330f0c4bb8 Mon Sep 17 00:00:00 2001
From: dayo <dayo05@daum.net>
Date: Thu, 2 Dec 2021 00:16:25 +0900
Subject: [PATCH 16/38] Make dispose enumerator

---
 test/TorchSharpTest/TestDataLoader.cs | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/test/TorchSharpTest/TestDataLoader.cs b/test/TorchSharpTest/TestDataLoader.cs
index a09023456..c632536ae 100644
--- a/test/TorchSharpTest/TestDataLoader.cs
+++ b/test/TorchSharpTest/TestDataLoader.cs
@@ -2,6 +2,7 @@
 using System.Collections.Generic;
 using Xunit;
 
+
 namespace TorchSharp
 {
     public class TestDataLoader
@@ -39,6 +40,7 @@ public void DataLoaderTest()
             Assert.Equal(iterator.Current["data"], torch.tensor(rawArray: new[]{1, 1}, dimensions: new[]{2L}));
             Assert.Equal(iterator.Current["label"], torch.tensor(rawArray: new[]{13, 13}, dimensions: new[]{2L}));
             Assert.Equal(iterator.Current["index"], torch.tensor(rawArray: new[]{0, 1}, dimensions: new[]{2L}));
+            iterator.Dispose();
         }
     }
 }
\ No newline at end of file

From 5b5d9d51de1998d841d585f966d071bf4ec1f327 Mon Sep 17 00:00:00 2001
From: dayo <dayo05@daum.net>
Date: Fri, 3 Dec 2021 16:02:22 +0900
Subject: [PATCH 17/38] Rename methods and add copyright notice

---
 src/TorchSharp/DataLoader.cs             |  4 ++--
 src/TorchSharp/Utils/ShuffleGenerator.cs | 24 +++++++++++-------------
 test/TorchSharpTest/TestDataLoader.cs    |  2 ++
 3 files changed, 15 insertions(+), 15 deletions(-)

diff --git a/src/TorchSharp/DataLoader.cs b/src/TorchSharp/DataLoader.cs
index 28f149713..789271175 100644
--- a/src/TorchSharp/DataLoader.cs
+++ b/src/TorchSharp/DataLoader.cs
@@ -62,9 +62,9 @@ public DataLoaderEnumerator(Dataset dataset, int batchSize, bool shuffle, Device
                         }
 
                         private bool isFinished() =>
-                            shuffle ? !shuffleGenerator.hasNext() : currentVal >= dataset.Count;
+                            shuffle ? !shuffleGenerator.HasNext() : currentVal >= dataset.Count;
 
-                        private int getNextValue() => shuffle ? shuffleGenerator.next() : currentVal++;
+                        private int getNextValue() => shuffle ? shuffleGenerator.Next() : currentVal++;
 
                         private void reset()
                         {
diff --git a/src/TorchSharp/Utils/ShuffleGenerator.cs b/src/TorchSharp/Utils/ShuffleGenerator.cs
index 8f0394373..0a89b622d 100644
--- a/src/TorchSharp/Utils/ShuffleGenerator.cs
+++ b/src/TorchSharp/Utils/ShuffleGenerator.cs
@@ -1,8 +1,11 @@
+// Copyright (c) .NET Foundation and Contributors.  All Rights Reserved.  See LICENSE in the project root for license information.
+
+//Algorithm from https://github.com/lemire/Code-used-on-Daniel-Lemire-s-blog/blob/master/2017/09/18_2/VisitInDisorder.java
 using System;
 
 namespace TorchSharp.Utils
 {
-    public class ShuffleGenerator
+    class ShuffleGenerator
     {
         int maxrange;
         int prime;
@@ -14,23 +17,18 @@ public ShuffleGenerator(int size)
         {
             var min = size / 2;
             maxrange = size;
-            prime = selectCoPrimeResev(min, size);
+            prime = SelectCoPrimeResev(min, size);
             offset = new Random().Next(size);
             index = 0;
             runningvalue = offset;
         }
 
-        private int getCurrentValue()
-        {
-            return (int) (((long) index * prime + offset) % (maxrange));
-        }
-
-        public bool hasNext()
+        public bool HasNext()
         {
             return index < maxrange;
         }
 
-        public int next()
+        public int Next()
         {
             runningvalue += prime;
             if (runningvalue >= maxrange) runningvalue -= maxrange;
@@ -40,13 +38,13 @@ public int next()
 
         private const int MAX_COUNT = int.MaxValue;
 
-        static int selectCoPrimeResev(int min, int target)
+        static int SelectCoPrimeResev(int min, int target)
         {
             var count = 0;
             var selected = 0;
             var rand = new Random();
             for (var val = min; val < target; ++val) {
-                if (coprime(val, target)) {
+                if (Coprime(val, target)) {
                     count += 1;
                     if ((count == 1) || (rand.Next(count) < 1)) {
                         selected = val;
@@ -59,9 +57,9 @@ static int selectCoPrimeResev(int min, int target)
             return selected;
         }
 
-        static bool coprime(int u, int v) => gcd(u, v) == 1;
+        static bool Coprime(int u, int v) => Gcd(u, v) == 1;
 
-        static int gcd(int u, int v)
+        static int Gcd(int u, int v)
         {
             int shift;
             if (u == 0) return v;
diff --git a/test/TorchSharpTest/TestDataLoader.cs b/test/TorchSharpTest/TestDataLoader.cs
index c632536ae..ba52ba222 100644
--- a/test/TorchSharpTest/TestDataLoader.cs
+++ b/test/TorchSharpTest/TestDataLoader.cs
@@ -1,3 +1,5 @@
+// Copyright (c) .NET Foundation and Contributors.  All Rights Reserved.  See LICENSE in the project root for license information.
+
 using System;
 using System.Collections.Generic;
 using Xunit;

From 49d7afdbc866176ab3c2fc58f699de5ad6a02cd9 Mon Sep 17 00:00:00 2001
From: dayo <dayo05@daum.net>
Date: Fri, 3 Dec 2021 16:05:41 +0900
Subject: [PATCH 18/38] Rename reset to Reset

---
 src/TorchSharp/DataLoader.cs | 14 ++++++--------
 1 file changed, 6 insertions(+), 8 deletions(-)

diff --git a/src/TorchSharp/DataLoader.cs b/src/TorchSharp/DataLoader.cs
index 789271175..95d4566a6 100644
--- a/src/TorchSharp/DataLoader.cs
+++ b/src/TorchSharp/DataLoader.cs
@@ -58,7 +58,7 @@ public DataLoaderEnumerator(Dataset dataset, int batchSize, bool shuffle, Device
                             this.batchSize = batchSize;
                             this.device = device;
                             this.shuffle = shuffle;
-                            reset();
+                            Reset();
                         }
 
                         private bool isFinished() =>
@@ -66,12 +66,6 @@ private bool isFinished() =>
 
                         private int getNextValue() => shuffle ? shuffleGenerator.Next() : currentVal++;
 
-                        private void reset()
-                        {
-                            shuffleGenerator = new ShuffleGenerator(dataset.Count);
-                            currentVal = 0;
-                        }
-
                         public bool MoveNext()
                         {
                             if (isFinished()) return false;
@@ -91,7 +85,11 @@ public bool MoveNext()
                             return true;
                         }
 
-                        public void Reset() => reset();
+                        public void Reset()
+                        {
+                            shuffleGenerator = new ShuffleGenerator(dataset.Count);
+                            currentVal = 0;
+                        }
 
                         public Dictionary<string, Tensor> Current { get; private set; }
 

From b250fe0e34a3a91c844685e4030596d823a69383 Mon Sep 17 00:00:00 2001
From: dayo <dayo05@daum.net>
Date: Fri, 3 Dec 2021 16:06:05 +0900
Subject: [PATCH 19/38] Make Count of dataset to long type

---
 src/TorchSharp/Dataset.cs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/TorchSharp/Dataset.cs b/src/TorchSharp/Dataset.cs
index fa01f75dc..134ad22d5 100644
--- a/src/TorchSharp/Dataset.cs
+++ b/src/TorchSharp/Dataset.cs
@@ -16,7 +16,7 @@ public virtual void Dispose()
                     {
                     }
 
-                    public abstract int Count { get; }
+                    public abstract long Count { get; }
 
                     public abstract Dictionary<string, Tensor> GetTensor(int index);
                 }

From 703cb01d593e156bf29996e2646fc495b42bd787 Mon Sep 17 00:00:00 2001
From: dayo <dayo05@daum.net>
Date: Fri, 3 Dec 2021 16:13:53 +0900
Subject: [PATCH 20/38] Make type of Count to long

---
 test/TorchSharpTest/TestDataLoader.cs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test/TorchSharpTest/TestDataLoader.cs b/test/TorchSharpTest/TestDataLoader.cs
index ba52ba222..d301e1c3c 100644
--- a/test/TorchSharpTest/TestDataLoader.cs
+++ b/test/TorchSharpTest/TestDataLoader.cs
@@ -11,7 +11,7 @@ public class TestDataLoader
     {
         private class TestDataset : torch.utils.data.Dataset
         {
-            public override int Count { get; } = 10;
+            public override long Count { get; } = 10;
             public override Dictionary<string, torch.Tensor> GetTensor(int index)
             {
                 return new() {{"data", torch.tensor(1)}, {"label", torch.tensor(13)}, {"index", torch.tensor(index)}};

From 65f06cfe974112d7125565deed84ed7953022713 Mon Sep 17 00:00:00 2001
From: dayo <dayo05@daum.net>
Date: Fri, 3 Dec 2021 16:19:34 +0900
Subject: [PATCH 21/38] Make Count to long

---
 src/TorchSharp/DataLoader.cs             |  2 +-
 src/TorchSharp/Dataset.cs                |  2 +-
 src/TorchSharp/Utils/ShuffleGenerator.cs | 47 +++++++++++++++---------
 3 files changed, 32 insertions(+), 19 deletions(-)

diff --git a/src/TorchSharp/DataLoader.cs b/src/TorchSharp/DataLoader.cs
index 95d4566a6..74d846816 100644
--- a/src/TorchSharp/DataLoader.cs
+++ b/src/TorchSharp/DataLoader.cs
@@ -64,7 +64,7 @@ public DataLoaderEnumerator(Dataset dataset, int batchSize, bool shuffle, Device
                         private bool isFinished() =>
                             shuffle ? !shuffleGenerator.HasNext() : currentVal >= dataset.Count;
 
-                        private int getNextValue() => shuffle ? shuffleGenerator.Next() : currentVal++;
+                        private long getNextValue() => shuffle ? shuffleGenerator.Next() : currentVal++;
 
                         public bool MoveNext()
                         {
diff --git a/src/TorchSharp/Dataset.cs b/src/TorchSharp/Dataset.cs
index 134ad22d5..e372d40de 100644
--- a/src/TorchSharp/Dataset.cs
+++ b/src/TorchSharp/Dataset.cs
@@ -18,7 +18,7 @@ public virtual void Dispose()
 
                     public abstract long Count { get; }
 
-                    public abstract Dictionary<string, Tensor> GetTensor(int index);
+                    public abstract Dictionary<string, Tensor> GetTensor(long index);
                 }
             }
         }
diff --git a/src/TorchSharp/Utils/ShuffleGenerator.cs b/src/TorchSharp/Utils/ShuffleGenerator.cs
index 0a89b622d..20bdbf430 100644
--- a/src/TorchSharp/Utils/ShuffleGenerator.cs
+++ b/src/TorchSharp/Utils/ShuffleGenerator.cs
@@ -7,18 +7,19 @@ namespace TorchSharp.Utils
 {
     class ShuffleGenerator
     {
-        int maxrange;
-        int prime;
-        int index;
-        int offset;
-        int runningvalue;
-
-        public ShuffleGenerator(int size)
+        long maxrange;
+        long prime;
+        long index;
+        long offset;
+        long runningvalue;
+        private Random rand;
+        public ShuffleGenerator(long size)
         {
+            rand = new Random();
             var min = size / 2;
             maxrange = size;
             prime = SelectCoPrimeResev(min, size);
-            offset = new Random().Next(size);
+            offset = NextLong(rand, size);
             index = 0;
             runningvalue = offset;
         }
@@ -28,7 +29,7 @@ public bool HasNext()
             return index < maxrange;
         }
 
-        public int Next()
+        public long Next()
         {
             runningvalue += prime;
             if (runningvalue >= maxrange) runningvalue -= maxrange;
@@ -36,17 +37,16 @@ public int Next()
             return runningvalue;
         }
 
-        private const int MAX_COUNT = int.MaxValue;
+        private const long MAX_COUNT = long.MaxValue;
 
-        static int SelectCoPrimeResev(int min, int target)
+        long SelectCoPrimeResev(long min, long target)
         {
-            var count = 0;
-            var selected = 0;
-            var rand = new Random();
+            var count = 0L;
+            var selected = 0L;
             for (var val = min; val < target; ++val) {
                 if (Coprime(val, target)) {
                     count += 1;
-                    if ((count == 1) || (rand.Next(count) < 1)) {
+                    if ((count == 1) || (NextLong(rand, count) < 1)) {
                         selected = val;
                     }
                 }
@@ -57,9 +57,9 @@ static int SelectCoPrimeResev(int min, int target)
             return selected;
         }
 
-        static bool Coprime(int u, int v) => Gcd(u, v) == 1;
+        static bool Coprime(long u, long v) => Gcd(u, v) == 1;
 
-        static int Gcd(int u, int v)
+        static long Gcd(long u, long v)
         {
             int shift;
             if (u == 0) return v;
@@ -83,5 +83,18 @@ static int Gcd(int u, int v)
 
             return u << shift;
         }
+
+        private static long NextLong(Random r, long l)
+        {
+            var bytebuffer = new byte[8];
+            r.NextBytes(bytebuffer);
+            var t = 0L;
+            foreach (var b in bytebuffer) {
+                t <<= 8;
+                t += b;
+            }
+
+            return t % l;
+        }
     }
 }
\ No newline at end of file

From 5f1707f9a9a2c1a8f2ac1d7c7e0ec0b461112165 Mon Sep 17 00:00:00 2001
From: dayo <dayo05@daum.net>
Date: Fri, 3 Dec 2021 16:21:59 +0900
Subject: [PATCH 22/38] Rename methods

---
 src/TorchSharp/DataLoader.cs          | 12 ++++++------
 test/TorchSharpTest/TestDataLoader.cs |  2 +-
 2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/src/TorchSharp/DataLoader.cs b/src/TorchSharp/DataLoader.cs
index 74d846816..34417555d 100644
--- a/src/TorchSharp/DataLoader.cs
+++ b/src/TorchSharp/DataLoader.cs
@@ -61,23 +61,23 @@ public DataLoaderEnumerator(Dataset dataset, int batchSize, bool shuffle, Device
                             Reset();
                         }
 
-                        private bool isFinished() =>
+                        private bool IsFinished() =>
                             shuffle ? !shuffleGenerator.HasNext() : currentVal >= dataset.Count;
 
-                        private long getNextValue() => shuffle ? shuffleGenerator.Next() : currentVal++;
+                        private long GetNextValue() => shuffle ? shuffleGenerator.Next() : currentVal++;
 
                         public bool MoveNext()
                         {
-                            if (isFinished()) return false;
-                            Current = dataset.GetTensor(getNextValue());
+                            if (IsFinished()) return false;
+                            Current = dataset.GetTensor(GetNextValue());
                             var currentKeys = Current.Keys;
                             foreach (var x in currentKeys)
                                 Current[x].unsqueeze_(0);
                             Dictionary<string, Tensor> dic;
                             for (var i = 1; i < batchSize; i++) {
-                                if (isFinished())
+                                if (IsFinished())
                                     break;
-                                dic = dataset.GetTensor(getNextValue());
+                                dic = dataset.GetTensor(GetNextValue());
                                 foreach (var x in currentKeys)
                                     Current[x] = cat(new List<Tensor>() {Current[x], dic[x].unsqueeze(0)}, 0);
                             }
diff --git a/test/TorchSharpTest/TestDataLoader.cs b/test/TorchSharpTest/TestDataLoader.cs
index d301e1c3c..7c6c9c8fe 100644
--- a/test/TorchSharpTest/TestDataLoader.cs
+++ b/test/TorchSharpTest/TestDataLoader.cs
@@ -12,7 +12,7 @@ public class TestDataLoader
         private class TestDataset : torch.utils.data.Dataset
         {
             public override long Count { get; } = 10;
-            public override Dictionary<string, torch.Tensor> GetTensor(int index)
+            public override Dictionary<string, torch.Tensor> GetTensor(long index)
             {
                 return new() {{"data", torch.tensor(1)}, {"label", torch.tensor(13)}, {"index", torch.tensor(index)}};
             }

From 3bda582187e718ce3551b490acab42db65a3d12f Mon Sep 17 00:00:00 2001
From: dayo <dayo05@daum.net>
Date: Fri, 3 Dec 2021 16:26:17 +0900
Subject: [PATCH 23/38] Make move tensor automatically to device

---
 src/TorchSharp/DataLoader.cs | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/TorchSharp/DataLoader.cs b/src/TorchSharp/DataLoader.cs
index 34417555d..45ab1c94a 100644
--- a/src/TorchSharp/DataLoader.cs
+++ b/src/TorchSharp/DataLoader.cs
@@ -82,6 +82,8 @@ public bool MoveNext()
                                     Current[x] = cat(new List<Tensor>() {Current[x], dic[x].unsqueeze(0)}, 0);
                             }
 
+                            foreach (var x in currentKeys)
+                                Current[x].to(device);
                             return true;
                         }
 

From 22d0556e5c9419f9fc939fbedb75d1e8c0e1f9b8 Mon Sep 17 00:00:00 2001
From: dayo <dayo05@daum.net>
Date: Fri, 3 Dec 2021 16:30:44 +0900
Subject: [PATCH 24/38] Make able to use custom seed

---
 src/TorchSharp/DataLoader.cs             | 14 +++++++++-----
 src/TorchSharp/Utils/ShuffleGenerator.cs |  4 ++--
 2 files changed, 11 insertions(+), 7 deletions(-)

diff --git a/src/TorchSharp/DataLoader.cs b/src/TorchSharp/DataLoader.cs
index 45ab1c94a..9be5647c1 100644
--- a/src/TorchSharp/DataLoader.cs
+++ b/src/TorchSharp/DataLoader.cs
@@ -20,6 +20,7 @@ public class DataLoader : IEnumerable<Dictionary<string, Tensor>>, IDisposable
                     private int batchSize;
                     private bool shuffle;
                     private Device device;
+                    private int? seed;
 
                     /// <summary>
                     /// Create pytorch style dataloader
@@ -28,16 +29,18 @@ public class DataLoader : IEnumerable<Dictionary<string, Tensor>>, IDisposable
                     /// <param name="batchSize"></param>
                     /// <param name="shuffle"></param>
                     /// <param name="device"></param>
-                    public DataLoader(Dataset dataset, int batchSize, bool shuffle = false, Device device = null)
+                    /// <param name="seed"></param>
+                    public DataLoader(Dataset dataset, int batchSize, bool shuffle = false, Device device = null, int? seed = null)
                     {
                         this.dataset = dataset;
                         this.batchSize = batchSize;
                         this.shuffle = shuffle;
                         this.device = device ?? CPU;
+                        this.seed = seed;
                     }
 
                     public IEnumerator<Dictionary<string, Tensor>> GetEnumerator() =>
-                        new DataLoaderEnumerator(dataset, batchSize, shuffle, device);
+                        new DataLoaderEnumerator(dataset, batchSize, shuffle, device, seed);
 
                     IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
 
@@ -51,13 +54,14 @@ private class DataLoaderEnumerator : IEnumerator<Dictionary<string, Tensor>>
                         private bool shuffle;
                         private ShuffleGenerator shuffleGenerator;
                         private int currentVal = 0;
-
-                        public DataLoaderEnumerator(Dataset dataset, int batchSize, bool shuffle, Device device)
+                        private int? seed;
+                        public DataLoaderEnumerator(Dataset dataset, int batchSize, bool shuffle, Device device, int? seed)
                         {
                             this.dataset = dataset;
                             this.batchSize = batchSize;
                             this.device = device;
                             this.shuffle = shuffle;
+                            this.seed = seed;
                             Reset();
                         }
 
@@ -89,7 +93,7 @@ public bool MoveNext()
 
                         public void Reset()
                         {
-                            shuffleGenerator = new ShuffleGenerator(dataset.Count);
+                            shuffleGenerator = seed is null ? new ShuffleGenerator(dataset.Count) : new ShuffleGenerator(dataset.Count, seed);
                             currentVal = 0;
                         }
 
diff --git a/src/TorchSharp/Utils/ShuffleGenerator.cs b/src/TorchSharp/Utils/ShuffleGenerator.cs
index 20bdbf430..a0f443920 100644
--- a/src/TorchSharp/Utils/ShuffleGenerator.cs
+++ b/src/TorchSharp/Utils/ShuffleGenerator.cs
@@ -13,9 +13,9 @@ class ShuffleGenerator
         long offset;
         long runningvalue;
         private Random rand;
-        public ShuffleGenerator(long size)
+        public ShuffleGenerator(long size, int? seed = null)
         {
-            rand = new Random();
+            rand = seed is null ? new Random() : new Random(seed.Value);
             var min = size / 2;
             maxrange = size;
             prime = SelectCoPrimeResev(min, size);

From eb53d61a5f59ce5cc1a516faf789b58225a75db3 Mon Sep 17 00:00:00 2001
From: dayo <dayo05@daum.net>
Date: Fri, 3 Dec 2021 16:39:09 +0900
Subject: [PATCH 25/38] Edit test for long

---
 test/TorchSharpTest/TestDataLoader.cs | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/test/TorchSharpTest/TestDataLoader.cs b/test/TorchSharpTest/TestDataLoader.cs
index 7c6c9c8fe..26dcd160d 100644
--- a/test/TorchSharpTest/TestDataLoader.cs
+++ b/test/TorchSharpTest/TestDataLoader.cs
@@ -29,7 +29,7 @@ public void DatasetTest()
 
             Assert.Equal(d["data"], torch.tensor(1));
             Assert.Equal(d["label"], torch.tensor(13));
-            Assert.Equal(d["index"], torch.tensor(0));
+            Assert.Equal(d["index"], torch.tensor(0L));
         }
 
         [Fact]
@@ -39,9 +39,9 @@ public void DataLoaderTest()
             using var dataloader = new torch.utils.data.DataLoader(dataset, 2, false, torch.CPU);
             var iterator = dataloader.GetEnumerator();
             iterator.MoveNext();
-            Assert.Equal(iterator.Current["data"], torch.tensor(rawArray: new[]{1, 1}, dimensions: new[]{2L}));
-            Assert.Equal(iterator.Current["label"], torch.tensor(rawArray: new[]{13, 13}, dimensions: new[]{2L}));
-            Assert.Equal(iterator.Current["index"], torch.tensor(rawArray: new[]{0, 1}, dimensions: new[]{2L}));
+            Assert.Equal(iterator.Current["data"], torch.tensor(rawArray: new[]{1L, 1L}, dimensions: new[]{2L}, dtype: torch.ScalarType.Int32));
+            Assert.Equal(iterator.Current["label"], torch.tensor(rawArray: new[]{13L, 13L}, dimensions: new[]{2L}, dtype: torch.ScalarType.Int32));
+            Assert.Equal(iterator.Current["index"], torch.tensor(rawArray: new[]{0L, 1L}, dimensions: new[]{2L}, dtype: torch.ScalarType.Int64));
             iterator.Dispose();
         }
     }

From 921bb3dfcb04b8c9ed83558b73d363f5acd2f5ed Mon Sep 17 00:00:00 2001
From: dayo <dayo05@daum.net>
Date: Fri, 3 Dec 2021 16:41:58 +0900
Subject: [PATCH 26/38] Create test for custom seed

---
 test/TorchSharpTest/TestDataLoader.cs | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/test/TorchSharpTest/TestDataLoader.cs b/test/TorchSharpTest/TestDataLoader.cs
index 26dcd160d..ab38d65f4 100644
--- a/test/TorchSharpTest/TestDataLoader.cs
+++ b/test/TorchSharpTest/TestDataLoader.cs
@@ -44,5 +44,18 @@ public void DataLoaderTest()
             Assert.Equal(iterator.Current["index"], torch.tensor(rawArray: new[]{0L, 1L}, dimensions: new[]{2L}, dtype: torch.ScalarType.Int64));
             iterator.Dispose();
         }
+
+        [Fact]
+        public void CustomSeedTest()
+        {
+            using var dataset = new TestDataset();
+            using var dataloader = new torch.utils.data.DataLoader(dataset, 2, true, seed: 1);
+            using var dataloader2 = new torch.utils.data.DataLoader(dataset, 2, true, seed: 1);
+            var iterator = dataloader.GetEnumerator();
+            var iterator2 = dataloader2.GetEnumerator();
+            iterator.MoveNext();
+            iterator2.MoveNext();
+            Assert.Equal(iterator.Current, iterator2.Current);
+        }
     }
 }
\ No newline at end of file

From 168f87c53c1e7613befab3ad45e4ba1828c06506 Mon Sep 17 00:00:00 2001
From: dayo <dayo05@daum.net>
Date: Sat, 4 Dec 2021 08:07:57 +0900
Subject: [PATCH 27/38] Make dataloader tensor dispose on MoveNext or Reset

---
 src/TorchSharp/DataLoader.cs          | 11 ++++++++++-
 test/TorchSharpTest/TestDataLoader.cs | 14 +++++++++++++-
 2 files changed, 23 insertions(+), 2 deletions(-)

diff --git a/src/TorchSharp/DataLoader.cs b/src/TorchSharp/DataLoader.cs
index 9be5647c1..e834b5544 100644
--- a/src/TorchSharp/DataLoader.cs
+++ b/src/TorchSharp/DataLoader.cs
@@ -3,7 +3,6 @@
 using System;
 using System.Collections;
 using System.Collections.Generic;
-
 using TorchSharp.Utils;
 
 namespace TorchSharp
@@ -72,6 +71,7 @@ private bool IsFinished() =>
 
                         public bool MoveNext()
                         {
+                            DisposeCurrent();
                             if (IsFinished()) return false;
                             Current = dataset.GetTensor(GetNextValue());
                             var currentKeys = Current.Keys;
@@ -93,6 +93,7 @@ public bool MoveNext()
 
                         public void Reset()
                         {
+                            DisposeCurrent();
                             shuffleGenerator = seed is null ? new ShuffleGenerator(dataset.Count) : new ShuffleGenerator(dataset.Count, seed);
                             currentVal = 0;
                         }
@@ -103,8 +104,16 @@ public void Reset()
 
                         public void Dispose()
                         {
+                            DisposeCurrent();
                             dataset.Dispose();
                         }
+
+                        private void DisposeCurrent()
+                        {
+                            if (Current is null) return;
+                            foreach(var x in Current.Values)
+                                x.Dispose();
+                        }
                     }
 
                     public void Dispose()
diff --git a/test/TorchSharpTest/TestDataLoader.cs b/test/TorchSharpTest/TestDataLoader.cs
index ab38d65f4..1ece75b90 100644
--- a/test/TorchSharpTest/TestDataLoader.cs
+++ b/test/TorchSharpTest/TestDataLoader.cs
@@ -33,7 +33,7 @@ public void DatasetTest()
         }
 
         [Fact]
-        public void DataLoaderTest()
+        public void DataLoaderTest1()
         {
             using var dataset = new TestDataset();
             using var dataloader = new torch.utils.data.DataLoader(dataset, 2, false, torch.CPU);
@@ -45,6 +45,18 @@ public void DataLoaderTest()
             iterator.Dispose();
         }
 
+        [Fact]
+        public void DataLoaderTest2()
+        {
+            using var dataset = new TestDataset();
+            using var dataloader = new torch.utils.data.DataLoader(dataset, 2, false, torch.CPU);
+            long idx = 0;
+            foreach (var x in dataloader) {
+                Assert.Equal(x["data"], torch.tensor(new[]{1, 1}, new[]{2L}));
+                Assert.Equal(x["index"], torch.tensor(new[]{idx++, idx++}, new[]{2L}));
+            }
+        }
+
         [Fact]
         public void CustomSeedTest()
         {

From 4db9b645a2ff956febc75c7d64cd665bebff9118 Mon Sep 17 00:00:00 2001
From: dayo <dayo05@daum.net>
Date: Sat, 4 Dec 2021 08:37:47 +0900
Subject: [PATCH 28/38] Change GCD algorithm

---
 src/TorchSharp/Utils/ShuffleGenerator.cs | 26 +++++-------------------
 1 file changed, 5 insertions(+), 21 deletions(-)

diff --git a/src/TorchSharp/Utils/ShuffleGenerator.cs b/src/TorchSharp/Utils/ShuffleGenerator.cs
index a0f443920..1fbc3509f 100644
--- a/src/TorchSharp/Utils/ShuffleGenerator.cs
+++ b/src/TorchSharp/Utils/ShuffleGenerator.cs
@@ -59,29 +59,13 @@ long SelectCoPrimeResev(long min, long target)
 
         static bool Coprime(long u, long v) => Gcd(u, v) == 1;
 
-        static long Gcd(long u, long v)
+        private static long Gcd(long a, long b)
         {
-            int shift;
-            if (u == 0) return v;
-            if (v == 0) return u;
-            for (shift = 0; ((u | v) & 1) == 0; ++shift) {
-                u >>= 1;
-                v >>= 1;
-            }
-
-            while ((u & 1) == 0)
-                u >>= 1;
-
-            do {
-                while ((v & 1) == 0)
-                    v >>= 1;
-                if (u > v)
-                    (v, u) = (u, v);
-
-                v -= u;
-            } while (v != 0);
+            while (a != 0 && b != 0)
+                if (a > b) a %= b;
+                else b %= a;
 
-            return u << shift;
+            return a | b;
         }
 
         private static long NextLong(Random r, long l)

From eab28ebf29c44c76fcef38a354c27056820858a5 Mon Sep 17 00:00:00 2001
From: dayo <dayo05@daum.net>
Date: Sat, 25 Dec 2021 20:07:22 +0900
Subject: [PATCH 29/38] Added document comments

---
 src/TorchSharp/DataLoader.cs | 29 +++++++++++++++++++++++------
 src/TorchSharp/Dataset.cs    |  8 ++++++++
 2 files changed, 31 insertions(+), 6 deletions(-)

diff --git a/src/TorchSharp/DataLoader.cs b/src/TorchSharp/DataLoader.cs
index e834b5544..ce0ba511e 100644
--- a/src/TorchSharp/DataLoader.cs
+++ b/src/TorchSharp/DataLoader.cs
@@ -22,13 +22,13 @@ public class DataLoader : IEnumerable<Dictionary<string, Tensor>>, IDisposable
                     private int? seed;
 
                     /// <summary>
-                    /// Create pytorch style dataloader
+                    /// Pytorch style dataloader
                     /// </summary>
-                    /// <param name="dataset"></param>
-                    /// <param name="batchSize"></param>
-                    /// <param name="shuffle"></param>
-                    /// <param name="device"></param>
-                    /// <param name="seed"></param>
+                    /// <param name="dataset">Dataset for create batch</param>
+                    /// <param name="batchSize">Size of batch</param>
+                    /// <param name="shuffle">true if shuffle dataset, false for not</param>
+                    /// <param name="device">device for output tensor</param>
+                    /// <param name="seed">Seed for generating shuffle</param>
                     public DataLoader(Dataset dataset, int batchSize, bool shuffle = false, Device device = null, int? seed = null)
                     {
                         this.dataset = dataset;
@@ -38,11 +38,18 @@ public DataLoader(Dataset dataset, int batchSize, bool shuffle = false, Device d
                         this.seed = seed;
                     }
 
+                    /// <summary>
+                    /// Generate enumerator
+                    /// </summary>
+                    /// <returns>Enumerator for batch</returns>
                     public IEnumerator<Dictionary<string, Tensor>> GetEnumerator() =>
                         new DataLoaderEnumerator(dataset, batchSize, shuffle, device, seed);
 
                     IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
 
+                    /// <summary>
+                    /// Size of batch
+                    /// </summary>
                     public long Count => (dataset.Count - 1) / batchSize + 1;
 
                     private class DataLoaderEnumerator : IEnumerator<Dictionary<string, Tensor>>
@@ -69,6 +76,10 @@ private bool IsFinished() =>
 
                         private long GetNextValue() => shuffle ? shuffleGenerator.Next() : currentVal++;
 
+                        /// <summary>
+                        /// Get next batch
+                        /// </summary>
+                        /// <returns>true if batch created, false if batch has finished</returns>
                         public bool MoveNext()
                         {
                             DisposeCurrent();
@@ -91,6 +102,9 @@ public bool MoveNext()
                             return true;
                         }
 
+                        /// <summary>
+                        /// Reset enumerator
+                        /// </summary>
                         public void Reset()
                         {
                             DisposeCurrent();
@@ -98,6 +112,9 @@ public void Reset()
                             currentVal = 0;
                         }
 
+                        /// <summary>
+                        /// Current tensor
+                        /// </summary>
                         public Dictionary<string, Tensor> Current { get; private set; }
 
                         object IEnumerator.Current => Current;
diff --git a/src/TorchSharp/Dataset.cs b/src/TorchSharp/Dataset.cs
index e372d40de..c95a6fe3d 100644
--- a/src/TorchSharp/Dataset.cs
+++ b/src/TorchSharp/Dataset.cs
@@ -16,8 +16,16 @@ public virtual void Dispose()
                     {
                     }
 
+                    /// <summary>
+                    /// Size of dataset
+                    /// </summary>
                     public abstract long Count { get; }
 
+                    /// <summary>
+                    /// Get tensor via index
+                    /// </summary>
+                    /// <param name="index">Index for tensor</param>
+                    /// <returns>Tensor for index</returns>
                     public abstract Dictionary<string, Tensor> GetTensor(long index);
                 }
             }

From 0deaddbd66c1e514b0a158b43979035de65ab9e8 Mon Sep 17 00:00:00 2001
From: dayo <dayo05@daum.net>
Date: Sat, 25 Dec 2021 22:17:57 +0900
Subject: [PATCH 30/38] Add document comment for classes

---
 src/TorchSharp/DataLoader.cs | 3 +++
 src/TorchSharp/Dataset.cs    | 3 +++
 2 files changed, 6 insertions(+)

diff --git a/src/TorchSharp/DataLoader.cs b/src/TorchSharp/DataLoader.cs
index ce0ba511e..69e340ff3 100644
--- a/src/TorchSharp/DataLoader.cs
+++ b/src/TorchSharp/DataLoader.cs
@@ -13,6 +13,9 @@ public static partial class utils
         {
             public static partial class data
             {
+                /// <summary>
+                /// This class makes easier to create batch. Data set must implement Dataset interface
+                /// </summary>
                 public class DataLoader : IEnumerable<Dictionary<string, Tensor>>, IDisposable
                 {
                     private Dataset dataset;
diff --git a/src/TorchSharp/Dataset.cs b/src/TorchSharp/Dataset.cs
index c95a6fe3d..c7ab0a49b 100644
--- a/src/TorchSharp/Dataset.cs
+++ b/src/TorchSharp/Dataset.cs
@@ -10,6 +10,9 @@ public static partial class utils
         {
             public static partial class data
             {
+                /// <summary>
+                /// Interface for Dataloader
+                /// </summary>
                 public abstract class Dataset : IDisposable
                 {
                     public virtual void Dispose()

From e9c20a40c8c20c61679da8a617be0dbe3962a624 Mon Sep 17 00:00:00 2001
From: dayo <dayo05@daum.net>
Date: Sat, 25 Dec 2021 22:34:18 +0900
Subject: [PATCH 31/38] Make catenate every tensor once

---
 src/TorchSharp/DataLoader.cs | 21 ++++++++-------------
 1 file changed, 8 insertions(+), 13 deletions(-)

diff --git a/src/TorchSharp/DataLoader.cs b/src/TorchSharp/DataLoader.cs
index 69e340ff3..ae68d9ff3 100644
--- a/src/TorchSharp/DataLoader.cs
+++ b/src/TorchSharp/DataLoader.cs
@@ -3,6 +3,7 @@
 using System;
 using System.Collections;
 using System.Collections.Generic;
+using System.Linq;
 using TorchSharp.Utils;
 
 namespace TorchSharp
@@ -87,21 +88,15 @@ public bool MoveNext()
                         {
                             DisposeCurrent();
                             if (IsFinished()) return false;
-                            Current = dataset.GetTensor(GetNextValue());
-                            var currentKeys = Current.Keys;
-                            foreach (var x in currentKeys)
-                                Current[x].unsqueeze_(0);
-                            Dictionary<string, Tensor> dic;
-                            for (var i = 1; i < batchSize; i++) {
-                                if (IsFinished())
-                                    break;
-                                dic = dataset.GetTensor(GetNextValue());
-                                foreach (var x in currentKeys)
-                                    Current[x] = cat(new List<Tensor>() {Current[x], dic[x].unsqueeze(0)}, 0);
+                            List<Dictionary<string, Tensor>> dic = new();
+                            for (var i = 0; i < batchSize; i++) {
+                                if (IsFinished()) break;
+                                dic.Add(dataset.GetTensor(GetNextValue()));
                             }
 
-                            foreach (var x in currentKeys)
-                                Current[x].to(device);
+                            Current = new();
+                            foreach (var x in dic[0].Keys)
+                                Current[x] = cat(dic.Select(k => k[x].unsqueeze(0)).ToArray(), 0).to(device);
                             return true;
                         }
 

From cc5dfe0b16442dece906d81f45a8a824ed309fed Mon Sep 17 00:00:00 2001
From: dayo <dayo05@daum.net>
Date: Sat, 25 Dec 2021 23:28:01 +0900
Subject: [PATCH 32/38] Update doc comment

---
 global.json               | 8 ++++----
 src/TorchSharp/Dataset.cs | 2 +-
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/global.json b/global.json
index 058794f5d..3a5517d73 100644
--- a/global.json
+++ b/global.json
@@ -1,7 +1,7 @@
 {
   "sdk": {
-    "version": "5.0.402",
-    "allowPrerelease": true,
-    "rollForward": "minor"
+    "version": "5.0.0",
+    "rollForward": "minor",
+    "allowPrerelease": true
   }
-}
+}
\ No newline at end of file
diff --git a/src/TorchSharp/Dataset.cs b/src/TorchSharp/Dataset.cs
index c7ab0a49b..85eca42af 100644
--- a/src/TorchSharp/Dataset.cs
+++ b/src/TorchSharp/Dataset.cs
@@ -28,7 +28,7 @@ public virtual void Dispose()
                     /// Get tensor via index
                     /// </summary>
                     /// <param name="index">Index for tensor</param>
-                    /// <returns>Tensor for index</returns>
+                    /// <returns>Tensor for index. You should return dictionary for catenate random amount of tensors.</returns>
                     public abstract Dictionary<string, Tensor> GetTensor(long index);
                 }
             }

From dfff08a06458c7893b61d89f1673b0791d86a984 Mon Sep 17 00:00:00 2001
From: dayo <dayo05@daum.net>
Date: Fri, 7 Jan 2022 05:59:51 +0900
Subject: [PATCH 33/38] Make able to set custom shuffler

---
 src/TorchSharp/DataLoader.cs             |  62 ++++++++----
 src/TorchSharp/Utils/FastShuffler.cs     | 124 +++++++++++++++++++++++
 src/TorchSharp/Utils/ShuffleGenerator.cs |  84 ---------------
 test/TorchSharpTest/TestDataLoader.cs    |   4 +-
 4 files changed, 169 insertions(+), 105 deletions(-)
 create mode 100644 src/TorchSharp/Utils/FastShuffler.cs
 delete mode 100644 src/TorchSharp/Utils/ShuffleGenerator.cs

diff --git a/src/TorchSharp/DataLoader.cs b/src/TorchSharp/DataLoader.cs
index ae68d9ff3..9b0d869c6 100644
--- a/src/TorchSharp/DataLoader.cs
+++ b/src/TorchSharp/DataLoader.cs
@@ -23,7 +23,23 @@ public class DataLoader : IEnumerable<Dictionary<string, Tensor>>, IDisposable
                     private int batchSize;
                     private bool shuffle;
                     private Device device;
-                    private int? seed;
+                    private IEnumerable<long> shuffler;
+
+                    /// <summary>
+                    /// Pytorch style dataloader
+                    /// </summary>
+                    /// <param name="dataset">Dataset for create batch</param>
+                    /// <param name="batchSize">Size of batch</param>
+                    /// <param name="device">device for output tensor</param>
+                    /// <param name="shuffler">Shuffler for dataloader</param>
+                    public DataLoader(Dataset dataset, int batchSize, IEnumerable<long> shuffler, Device device = null)
+                    {
+                        this.dataset = dataset;
+                        this.batchSize = batchSize;
+                        this.shuffle = true;
+                        this.device = device ?? CPU;
+                        this.shuffler = shuffler;
+                    }
 
                     /// <summary>
                     /// Pytorch style dataloader
@@ -39,7 +55,7 @@ public DataLoader(Dataset dataset, int batchSize, bool shuffle = false, Device d
                         this.batchSize = batchSize;
                         this.shuffle = shuffle;
                         this.device = device ?? CPU;
-                        this.seed = seed;
+                        this.shuffler = seed is null ? new FastShuffler(dataset.Count) : new FastShuffler(dataset.Count, seed);
                     }
 
                     /// <summary>
@@ -47,7 +63,7 @@ public DataLoader(Dataset dataset, int batchSize, bool shuffle = false, Device d
                     /// </summary>
                     /// <returns>Enumerator for batch</returns>
                     public IEnumerator<Dictionary<string, Tensor>> GetEnumerator() =>
-                        new DataLoaderEnumerator(dataset, batchSize, shuffle, device, seed);
+                        new DataLoaderEnumerator(dataset, batchSize, shuffle, device, shuffler);
 
                     IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
 
@@ -62,23 +78,30 @@ private class DataLoaderEnumerator : IEnumerator<Dictionary<string, Tensor>>
                         private int batchSize;
                         private Device device;
                         private bool shuffle;
-                        private ShuffleGenerator shuffleGenerator;
-                        private int currentVal = 0;
-                        private int? seed;
-                        public DataLoaderEnumerator(Dataset dataset, int batchSize, bool shuffle, Device device, int? seed)
+                        private IEnumerable<long> shuffleEnumerable;
+                        private IEnumerator<long> shuffler;
+                        private long currentVal = 0;
+                        public DataLoaderEnumerator(Dataset dataset, int batchSize, bool shuffle, Device device, IEnumerable<long> shuffleEnumerable)
                         {
                             this.dataset = dataset;
                             this.batchSize = batchSize;
                             this.device = device;
                             this.shuffle = shuffle;
-                            this.seed = seed;
+                            this.shuffleEnumerable = shuffleEnumerable;
                             Reset();
                         }
-
-                        private bool IsFinished() =>
-                            shuffle ? !shuffleGenerator.HasNext() : currentVal >= dataset.Count;
-
-                        private long GetNextValue() => shuffle ? shuffleGenerator.Next() : currentVal++;
+                        private bool MoveNextValue()
+                        {
+                            if (shuffle) {
+                                if (shuffler.MoveNext()) return false;
+                                currentVal = shuffler.Current;
+                                return true;
+                            }
+                            else {
+                                currentVal++;
+                                return currentVal < dataset.Count;
+                            }
+                        }
 
                         /// <summary>
                         /// Get next batch
@@ -87,11 +110,12 @@ private bool IsFinished() =>
                         public bool MoveNext()
                         {
                             DisposeCurrent();
-                            if (IsFinished()) return false;
+                            if (!MoveNextValue()) return false;
                             List<Dictionary<string, Tensor>> dic = new();
-                            for (var i = 0; i < batchSize; i++) {
-                                if (IsFinished()) break;
-                                dic.Add(dataset.GetTensor(GetNextValue()));
+                            dic.Add(dataset.GetTensor(currentVal));
+                            for (var i = 1; i < batchSize; i++) {
+                                if (!MoveNextValue()) break;
+                                dic.Add(dataset.GetTensor(currentVal));
                             }
 
                             Current = new();
@@ -106,8 +130,8 @@ public bool MoveNext()
                         public void Reset()
                         {
                             DisposeCurrent();
-                            shuffleGenerator = seed is null ? new ShuffleGenerator(dataset.Count) : new ShuffleGenerator(dataset.Count, seed);
-                            currentVal = 0;
+                            if(shuffle) shuffler = shuffleEnumerable.GetEnumerator();
+                            currentVal = -1;
                         }
 
                         /// <summary>
diff --git a/src/TorchSharp/Utils/FastShuffler.cs b/src/TorchSharp/Utils/FastShuffler.cs
new file mode 100644
index 000000000..7b2b7d7b2
--- /dev/null
+++ b/src/TorchSharp/Utils/FastShuffler.cs
@@ -0,0 +1,124 @@
+// Copyright (c) .NET Foundation and Contributors.  All Rights Reserved.  See LICENSE in the project root for license information.
+
+//Algorithm from https://github.com/lemire/Code-used-on-Daniel-Lemire-s-blog/blob/master/2017/09/18_2/VisitInDisorder.java
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace TorchSharp.Utils
+{
+    class FastShuffler : IEnumerable<long>
+    {
+        private long size;
+        private int? seed;
+
+        public FastShuffler(long size, int? seed = null)
+        {
+            this.size = size;
+            this.seed = seed;
+        }
+
+        private class ShuffleEnumerator : IEnumerator<long>
+        {
+            long maxrange;
+            long prime;
+            long index;
+            long offset;
+            long runningvalue;
+            private Random rand;
+            private int? seed;
+            private long size;
+
+            public ShuffleEnumerator(long size, int? seed = null)
+            {
+                this.seed = seed;
+                this.size = size;
+                Reset();
+            }
+
+            private const long MAX_COUNT = long.MaxValue;
+
+            long SelectCoPrimeResev(long min, long target)
+            {
+                var count = 0L;
+                var selected = 0L;
+                for (var val = min; val < target; ++val) {
+                    if (Coprime(val, target)) {
+                        count += 1;
+                        if ((count == 1) || (NextLong(rand, count) < 1)) {
+                            selected = val;
+                        }
+                    }
+
+                    if (count == MAX_COUNT) return val;
+                }
+
+                return selected;
+            }
+
+            static bool Coprime(long u, long v) => Gcd(u, v) == 1;
+
+            private static long Gcd(long a, long b)
+            {
+                while (a != 0 && b != 0)
+                    if (a > b) a %= b;
+                    else b %= a;
+
+                return a | b;
+            }
+
+            private static long NextLong(Random r, long l)
+            {
+                var bytebuffer = new byte[8];
+                r.NextBytes(bytebuffer);
+                var t = 0L;
+                foreach (var b in bytebuffer) {
+                    t <<= 8;
+                    t += b;
+                }
+
+                return t % l;
+            }
+
+            public bool MoveNext()
+            {
+
+                if (index >= maxrange) return false;
+                runningvalue += prime;
+                if (runningvalue >= maxrange) runningvalue -= maxrange;
+                index++;
+                return true;
+            }
+
+            public void Reset()
+            {
+                rand = seed is null ? new Random() : new Random(seed.Value);
+                var min = size / 2;
+                maxrange = size;
+                prime = SelectCoPrimeResev(min, size);
+                offset = NextLong(rand, size);
+                index = 0;
+                runningvalue = offset;
+            }
+
+            object IEnumerator.Current => Current;
+
+            public long Current => runningvalue;
+
+            public void Dispose()
+            {
+
+            }
+        }
+
+        public IEnumerator<long> GetEnumerator()
+        {
+            return new ShuffleEnumerator(size, seed);
+        }
+
+        IEnumerator IEnumerable.GetEnumerator()
+        {
+            return GetEnumerator();
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/TorchSharp/Utils/ShuffleGenerator.cs b/src/TorchSharp/Utils/ShuffleGenerator.cs
deleted file mode 100644
index 1fbc3509f..000000000
--- a/src/TorchSharp/Utils/ShuffleGenerator.cs
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright (c) .NET Foundation and Contributors.  All Rights Reserved.  See LICENSE in the project root for license information.
-
-//Algorithm from https://github.com/lemire/Code-used-on-Daniel-Lemire-s-blog/blob/master/2017/09/18_2/VisitInDisorder.java
-using System;
-
-namespace TorchSharp.Utils
-{
-    class ShuffleGenerator
-    {
-        long maxrange;
-        long prime;
-        long index;
-        long offset;
-        long runningvalue;
-        private Random rand;
-        public ShuffleGenerator(long size, int? seed = null)
-        {
-            rand = seed is null ? new Random() : new Random(seed.Value);
-            var min = size / 2;
-            maxrange = size;
-            prime = SelectCoPrimeResev(min, size);
-            offset = NextLong(rand, size);
-            index = 0;
-            runningvalue = offset;
-        }
-
-        public bool HasNext()
-        {
-            return index < maxrange;
-        }
-
-        public long Next()
-        {
-            runningvalue += prime;
-            if (runningvalue >= maxrange) runningvalue -= maxrange;
-            index++;
-            return runningvalue;
-        }
-
-        private const long MAX_COUNT = long.MaxValue;
-
-        long SelectCoPrimeResev(long min, long target)
-        {
-            var count = 0L;
-            var selected = 0L;
-            for (var val = min; val < target; ++val) {
-                if (Coprime(val, target)) {
-                    count += 1;
-                    if ((count == 1) || (NextLong(rand, count) < 1)) {
-                        selected = val;
-                    }
-                }
-
-                if (count == MAX_COUNT) return val;
-            }
-
-            return selected;
-        }
-
-        static bool Coprime(long u, long v) => Gcd(u, v) == 1;
-
-        private static long Gcd(long a, long b)
-        {
-            while (a != 0 && b != 0)
-                if (a > b) a %= b;
-                else b %= a;
-
-            return a | b;
-        }
-
-        private static long NextLong(Random r, long l)
-        {
-            var bytebuffer = new byte[8];
-            r.NextBytes(bytebuffer);
-            var t = 0L;
-            foreach (var b in bytebuffer) {
-                t <<= 8;
-                t += b;
-            }
-
-            return t % l;
-        }
-    }
-}
\ No newline at end of file
diff --git a/test/TorchSharpTest/TestDataLoader.cs b/test/TorchSharpTest/TestDataLoader.cs
index 1ece75b90..7054f4f12 100644
--- a/test/TorchSharpTest/TestDataLoader.cs
+++ b/test/TorchSharpTest/TestDataLoader.cs
@@ -38,10 +38,10 @@ public void DataLoaderTest1()
             using var dataset = new TestDataset();
             using var dataloader = new torch.utils.data.DataLoader(dataset, 2, false, torch.CPU);
             var iterator = dataloader.GetEnumerator();
-            iterator.MoveNext();
+            Assert.True(iterator.MoveNext());
             Assert.Equal(iterator.Current["data"], torch.tensor(rawArray: new[]{1L, 1L}, dimensions: new[]{2L}, dtype: torch.ScalarType.Int32));
             Assert.Equal(iterator.Current["label"], torch.tensor(rawArray: new[]{13L, 13L}, dimensions: new[]{2L}, dtype: torch.ScalarType.Int32));
-            Assert.Equal(iterator.Current["index"], torch.tensor(rawArray: new[]{0L, 1L}, dimensions: new[]{2L}, dtype: torch.ScalarType.Int64));
+            Assert.Equal(iterator.Current["index"].ToString(true), torch.tensor(rawArray: new[]{0L, 1L}, dimensions: new[]{2L}, dtype: torch.ScalarType.Int64).ToString(true));
             iterator.Dispose();
         }
 

From 9dffab6d601a2ce30d0d1d97fa84e4f5282bf0fb Mon Sep 17 00:00:00 2001
From: dayo <dayo05@daum.net>
Date: Sat, 8 Jan 2022 12:01:24 +0900
Subject: [PATCH 34/38] Fix mistake on creating custom shuffler

---
 src/TorchSharp/DataLoader.cs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/TorchSharp/DataLoader.cs b/src/TorchSharp/DataLoader.cs
index 9b0d869c6..7ec93617a 100644
--- a/src/TorchSharp/DataLoader.cs
+++ b/src/TorchSharp/DataLoader.cs
@@ -93,7 +93,7 @@ public DataLoaderEnumerator(Dataset dataset, int batchSize, bool shuffle, Device
                         private bool MoveNextValue()
                         {
                             if (shuffle) {
-                                if (shuffler.MoveNext()) return false;
+                                if (!shuffler.MoveNext()) return false;
                                 currentVal = shuffler.Current;
                                 return true;
                             }

From 991c37762e93b732046f2c840a6e67fac821cf10 Mon Sep 17 00:00:00 2001
From: dayo <dayo05@daum.net>
Date: Sat, 8 Jan 2022 12:16:48 +0900
Subject: [PATCH 35/38] Add fisher yates shuffler and make that as default

---
 src/TorchSharp/DataLoader.cs                |  2 +-
 src/TorchSharp/Utils/FisherYatesShuffler.cs | 89 +++++++++++++++++++++
 2 files changed, 90 insertions(+), 1 deletion(-)
 create mode 100644 src/TorchSharp/Utils/FisherYatesShuffler.cs

diff --git a/src/TorchSharp/DataLoader.cs b/src/TorchSharp/DataLoader.cs
index 7ec93617a..3a482dda3 100644
--- a/src/TorchSharp/DataLoader.cs
+++ b/src/TorchSharp/DataLoader.cs
@@ -55,7 +55,7 @@ public DataLoader(Dataset dataset, int batchSize, bool shuffle = false, Device d
                         this.batchSize = batchSize;
                         this.shuffle = shuffle;
                         this.device = device ?? CPU;
-                        this.shuffler = seed is null ? new FastShuffler(dataset.Count) : new FastShuffler(dataset.Count, seed);
+                        this.shuffler = seed is null ? new FisherYatesShuffler(dataset.Count) : new FisherYatesShuffler(dataset.Count, seed);
                     }
 
                     /// <summary>
diff --git a/src/TorchSharp/Utils/FisherYatesShuffler.cs b/src/TorchSharp/Utils/FisherYatesShuffler.cs
new file mode 100644
index 000000000..b69eb9983
--- /dev/null
+++ b/src/TorchSharp/Utils/FisherYatesShuffler.cs
@@ -0,0 +1,89 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace TorchSharp.Utils
+{
+    public class FisherYatesShuffler : IEnumerable<long>
+    {
+        private long size;
+        private int? seed;
+
+        public FisherYatesShuffler(long size, int? seed = null)
+        {
+            this.size = size;
+            this.seed = seed;
+        }
+
+        public IEnumerator<long> GetEnumerator()
+            => seed == null
+                ? new FisherYatesShufflerEnumerable(size)
+                : new FisherYatesShufflerEnumerable(size, seed.Value);
+
+        IEnumerator IEnumerable.GetEnumerator()
+        {
+            return GetEnumerator();
+        }
+
+        private class FisherYatesShufflerEnumerable : IEnumerator<long>
+        {
+            public FisherYatesShufflerEnumerable(long size)
+            {
+                this.size = size;
+                this.seed = null;
+                Reset();
+            }
+
+            public FisherYatesShufflerEnumerable(long size, int seed)
+            {
+                this.size = size;
+                this.seed = seed;
+                Reset();
+            }
+
+            private int? seed;
+            private long size;
+            private Dictionary<long, long> indexs = new();
+            private Random r;
+            private long current = -1;
+
+            public bool MoveNext()
+            {
+                current++;
+                return current < size;
+            }
+
+            public void Reset()
+            {
+                r = seed == null ? new Random() : new Random(seed.Value);
+                current = -1;
+                indexs.Clear();
+                for (var i = 0L; i < size; i++) {
+                    var rndidx = GetRandomLong();
+                    if (rndidx == i)
+                        indexs[i] = i;
+                    else {
+                        indexs[i] = indexs[rndidx];
+                        indexs[rndidx] = i;
+                    }
+                }
+            }
+
+            public long Current => indexs[current];
+
+            object IEnumerator.Current => Current;
+
+            public void Dispose()
+            {
+                /* Ignore */
+            }
+
+            private long GetRandomLong()
+            {
+                unchecked {
+                    return ((long) r.Next() << 32) + (uint) r.Next();
+                }
+            }
+        }
+    }
+}
\ No newline at end of file

From 2efce390f6de5b5e36ebb86dc15359f236e5f312 Mon Sep 17 00:00:00 2001
From: dayo <dayo05@daum.net>
Date: Sat, 8 Jan 2022 04:00:53 +0900
Subject: [PATCH 36/38] Fix mistake on shuffler

---
 src/TorchSharp/Utils/FisherYatesShuffler.cs | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/TorchSharp/Utils/FisherYatesShuffler.cs b/src/TorchSharp/Utils/FisherYatesShuffler.cs
index b69eb9983..4134ccc68 100644
--- a/src/TorchSharp/Utils/FisherYatesShuffler.cs
+++ b/src/TorchSharp/Utils/FisherYatesShuffler.cs
@@ -59,7 +59,7 @@ public void Reset()
                 current = -1;
                 indexs.Clear();
                 for (var i = 0L; i < size; i++) {
-                    var rndidx = GetRandomLong();
+                    var rndidx = GetRandomLong(i);
                     if (rndidx == i)
                         indexs[i] = i;
                     else {
@@ -78,10 +78,10 @@ public void Dispose()
                 /* Ignore */
             }
 
-            private long GetRandomLong()
+            private long GetRandomLong(long l)
             {
                 unchecked {
-                    return ((long) r.Next() << 32) + (uint) r.Next();
+                    return (((long) r.Next() << 32) + (uint) r.Next()) % (l + 1);
                 }
             }
         }

From 00e16ad68b553d5708510ecf538aa85c67055a5c Mon Sep 17 00:00:00 2001
From: dayo05 <77111795+dayo05@users.noreply.github.com>
Date: Tue, 11 Jan 2022 03:19:24 +0900
Subject: [PATCH 37/38] Make dispose dataset once

In previous code, dataset is able to dispose twice
---
 src/TorchSharp/DataLoader.cs | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/src/TorchSharp/DataLoader.cs b/src/TorchSharp/DataLoader.cs
index 3a482dda3..8ed439c74 100644
--- a/src/TorchSharp/DataLoader.cs
+++ b/src/TorchSharp/DataLoader.cs
@@ -144,7 +144,6 @@ public void Reset()
                         public void Dispose()
                         {
                             DisposeCurrent();
-                            dataset.Dispose();
                         }
 
                         private void DisposeCurrent()
@@ -163,4 +162,4 @@ public void Dispose()
             }
         }
     }
-}
\ No newline at end of file
+}

From 9291dc4b5d787806b9c4fb4a6b18df08294785dd Mon Sep 17 00:00:00 2001
From: dayo05 <77111795+dayo05@users.noreply.github.com>
Date: Thu, 13 Jan 2022 02:24:04 +0900
Subject: [PATCH 38/38] Undo changes on global.json

---
 global.json | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/global.json b/global.json
index 3a5517d73..6a0767248 100644
--- a/global.json
+++ b/global.json
@@ -1,7 +1,7 @@
 {
-  "sdk": {
-    "version": "5.0.0",
-    "rollForward": "minor",
-    "allowPrerelease": true
+  "sdk": {    
+    "version": "5.0.402",
+    "allowPrerelease": true,
+    "rollForward": "minor"
   }
-}
\ No newline at end of file
+}
