CSharp:无法读取大型 .npy 文件。例外是 "NumSharp.dll Arithmetic operation resulted in an overflow."
CSharp: Failed to read LARGE .npy file. Exception is "NumSharp.dll Arithmetic operation resulted in an overflow."
我正在尝试在 CSharp 中读取一个大的 .npy 文件。
为此,我正在尝试使用 NumSharp nuget。
该文件是 7GB 锯齿状浮点数组 (float[][])。它有大约 100 万个向量,每个向量都是 960 维。
注:
更具体地说,我使用的数据是来自以下 link Approximate Nearest Neighbors Large datasets.
的 GIST
以下是我用来加载数据的方法,但失败并出现异常:
private static void ReadNpyVectorsFromFile(string pathPrefix, out List<float[]> candidates)
{
var npyFilename = @$"{pathPrefix}.npy";
var v = np.load(npyFilename);//NDArray
candidates = v
.astype(np.float32)
.ToJaggedArray<float>()
.OfType<float[]>()
.Select(a =>
{
return a.OfType<float>().ToArray();
})
.ToList();
}
例外情况是:
Exception thrown: 'System.OverflowException' in NumSharp.dll An
unhandled exception of type 'System.OverflowException' occurred in
NumSharp.dll Arithmetic operation resulted in an overflow.
我该如何解决这个问题?
更新
如果文件太大,NumSharp 包会有限制。
阅读下面的 comments/answers 以获得更多解释。
我添加了一个答案和解决方法的建议
但是,
一个好的替代方法是将数据保存为 .npz(参考:numpy.savez()),然后以下包可以完成这项工作:
https://github.com/matajoh/libnpy
代码示例:
NPZInputStream npz = new NPZInputStream(npyFilename);
var keys = npz.Keys();
//var header = npz.Peek(keys[0]);
var t = npz.ReadFloat32(keys[0]);
Debug.Assert(t.DataType == DataType.FLOAT32);
问题是 NumSharp 数据结构是一个沉重的 RAM 消耗者,似乎 CSharp GC 不知道 NumSharp 正在分配什么,所以它很快达到 RAM 限制。
所以,
为了克服这个问题,我拆分了输入的 npy 文件,这样每个部分都不会消耗超过 C# 中允许的最大内存分配 (2147483591)。在我的例子中,我分成了 5 个不同的文件(每个 200k 个向量)。
python 拆分大 .npy 文件的部分:
infile = r'C:\temp\input\GIST.1m.npy'
data = np.load(infile)
# create 5 files
incr = int(data.shape[0] / 5)
# the +1 is to handle any leftovers
r = range(0, int(size/incr + 1))
for i in r:
print(i)
start = i * incr
stop = min(start + incr, size)
if(start >= len(data)):
break
np.save(infile.replace('.npy', f'.{i}.npy'), data[start:stop])
现在 CSharp 中的代码如下所示:
private static void ReadNpyVectorsFromFile(string pathPrefix, out List<float[]> candidates)
{
candidates = new List<float[]>();
// TODO:
// For now I am assuming there are 10 files maximum...
// this can be improved by scanning the input folder and
// collecting all the relevant files.
foreach (var i in Enumerable.Range(-1, 10))
{
var npyFilename = @$"{pathPrefix}.{i}.npy";
Console.WriteLine(npyFilename);
if (!File.Exists(npyFilename))
continue;
var v = np.load(npyFilename); //NDArray
var tempList = v
.astype(np.float32)
.ToJaggedArray<float>()
.OfType<float[]>()
.Select(a => { return a.OfType<float>().ToArray(); })
.ToList();
candidates.AddRange(tempList);
}
}
我看到您已经找到了解决方法。以防万一您现在想知道问题的原因,这是因为 .NET 中 Array
class 的限制。
定义了np.load(string path)
方法here,后者又调用了np.load(Stream stream)
.
int bytes;
Type type;
int[] shape;
if (!parseReader(reader, out bytes, out type, out shape))
throw new FormatException();
Array array = Arrays.Create(type, shape.Aggregate((dims, dim) => dims * dim));
var result = new NDArray(readValueMatrix(reader, array, bytes, type, shape));
return result.reshape(shape);
这里,bytes
是你日期类型的大小。因为您使用的是float
,所以这个值为4
。而shape
是向量的个数和向量的形状。
接下来,让我们看看readValueMatrix
method.
int total = 1;
for (int i = 0; i < shape.Length; i++)
total *= shape[i];
var buffer = new byte[bytes * total];
// omitted
NumSharp 正在尝试创建大小等于 bytes * total
的一维 byte
数组。这里,bytes
是 4,total
是向量数乘以所有维度的大小。
但是,在 .NET 中,byte
数组的任何给定维度中的最大索引为 0X7FFFFFC7
,即 2147483591
,如文档所述 here。我还没有下载你的数据,但我猜它足够大 bytes * total > 2147483591
.
请注意,如果您想使用 NumSharp 将数据写回 npy 文件,那么您将在 writeValueMatrix
method.
中遇到同样的问题
我正在尝试在 CSharp 中读取一个大的 .npy 文件。 为此,我正在尝试使用 NumSharp nuget。
该文件是 7GB 锯齿状浮点数组 (float[][])。它有大约 100 万个向量,每个向量都是 960 维。
注: 更具体地说,我使用的数据是来自以下 link Approximate Nearest Neighbors Large datasets.
的 GIST以下是我用来加载数据的方法,但失败并出现异常:
private static void ReadNpyVectorsFromFile(string pathPrefix, out List<float[]> candidates)
{
var npyFilename = @$"{pathPrefix}.npy";
var v = np.load(npyFilename);//NDArray
candidates = v
.astype(np.float32)
.ToJaggedArray<float>()
.OfType<float[]>()
.Select(a =>
{
return a.OfType<float>().ToArray();
})
.ToList();
}
例外情况是:
Exception thrown: 'System.OverflowException' in NumSharp.dll An unhandled exception of type 'System.OverflowException' occurred in NumSharp.dll Arithmetic operation resulted in an overflow.
我该如何解决这个问题?
更新
如果文件太大,NumSharp 包会有限制。 阅读下面的 comments/answers 以获得更多解释。 我添加了一个答案和解决方法的建议
但是, 一个好的替代方法是将数据保存为 .npz(参考:numpy.savez()),然后以下包可以完成这项工作:
https://github.com/matajoh/libnpy
代码示例:
NPZInputStream npz = new NPZInputStream(npyFilename);
var keys = npz.Keys();
//var header = npz.Peek(keys[0]);
var t = npz.ReadFloat32(keys[0]);
Debug.Assert(t.DataType == DataType.FLOAT32);
问题是 NumSharp 数据结构是一个沉重的 RAM 消耗者,似乎 CSharp GC 不知道 NumSharp 正在分配什么,所以它很快达到 RAM 限制。
所以, 为了克服这个问题,我拆分了输入的 npy 文件,这样每个部分都不会消耗超过 C# 中允许的最大内存分配 (2147483591)。在我的例子中,我分成了 5 个不同的文件(每个 200k 个向量)。
python 拆分大 .npy 文件的部分:
infile = r'C:\temp\input\GIST.1m.npy'
data = np.load(infile)
# create 5 files
incr = int(data.shape[0] / 5)
# the +1 is to handle any leftovers
r = range(0, int(size/incr + 1))
for i in r:
print(i)
start = i * incr
stop = min(start + incr, size)
if(start >= len(data)):
break
np.save(infile.replace('.npy', f'.{i}.npy'), data[start:stop])
现在 CSharp 中的代码如下所示:
private static void ReadNpyVectorsFromFile(string pathPrefix, out List<float[]> candidates)
{
candidates = new List<float[]>();
// TODO:
// For now I am assuming there are 10 files maximum...
// this can be improved by scanning the input folder and
// collecting all the relevant files.
foreach (var i in Enumerable.Range(-1, 10))
{
var npyFilename = @$"{pathPrefix}.{i}.npy";
Console.WriteLine(npyFilename);
if (!File.Exists(npyFilename))
continue;
var v = np.load(npyFilename); //NDArray
var tempList = v
.astype(np.float32)
.ToJaggedArray<float>()
.OfType<float[]>()
.Select(a => { return a.OfType<float>().ToArray(); })
.ToList();
candidates.AddRange(tempList);
}
}
我看到您已经找到了解决方法。以防万一您现在想知道问题的原因,这是因为 .NET 中 Array
class 的限制。
定义了np.load(string path)
方法here,后者又调用了np.load(Stream stream)
.
int bytes;
Type type;
int[] shape;
if (!parseReader(reader, out bytes, out type, out shape))
throw new FormatException();
Array array = Arrays.Create(type, shape.Aggregate((dims, dim) => dims * dim));
var result = new NDArray(readValueMatrix(reader, array, bytes, type, shape));
return result.reshape(shape);
这里,bytes
是你日期类型的大小。因为您使用的是float
,所以这个值为4
。而shape
是向量的个数和向量的形状。
接下来,让我们看看readValueMatrix
method.
int total = 1;
for (int i = 0; i < shape.Length; i++)
total *= shape[i];
var buffer = new byte[bytes * total];
// omitted
NumSharp 正在尝试创建大小等于 bytes * total
的一维 byte
数组。这里,bytes
是 4,total
是向量数乘以所有维度的大小。
但是,在 .NET 中,byte
数组的任何给定维度中的最大索引为 0X7FFFFFC7
,即 2147483591
,如文档所述 here。我还没有下载你的数据,但我猜它足够大 bytes * total > 2147483591
.
请注意,如果您想使用 NumSharp 将数据写回 npy 文件,那么您将在 writeValueMatrix
method.