Загрузить набор данных из файла HDF5 в C#
Я пытаюсь загрузить набор данных из файла HDF5 в C# (.NET Framework) таким образом, чтобы у меня было содержимое в массиве, например float[,]
, Я нашел библиотеку HDF.PInvoke, но мне очень трудно понять, как ее использовать.
Обновить
Из скорого ответа мне удалось заставить его работать. Вот мой рабочий фрагмент:
using System;
using System.Runtime.InteropServices;
using HDF.PInvoke;
namespace MyNamespace
{
class Program
{
static void Main()
{
string datasetPath = "/dense1/dense1/kernel:0";
long fileId = H5F.open(@"\path\to\weights.h5", H5F.ACC_RDONLY);
long dataSetId = H5D.open(fileId, datasetPath);
long typeId = H5D.get_type(dataSetId);
// read array (shape may be inferred w/ H5S.get_simple_extent_ndims)
float[,] arr = new float[162, 128];
GCHandle gch = GCHandle.Alloc(arr, GCHandleType.Pinned);
try
{
H5D.read(dataSetId, typeId, H5S.ALL, H5S.ALL, H5P.DEFAULT,
gch.AddrOfPinnedObject());
}
finally
{
gch.Free();
}
// show one entry
Console.WriteLine(arr[13, 87].ToString());
// Keep the console window open in debug mode.
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
}
Оригинальная первая попытка:
Что мне удалось пока что:
using System;
using System.IO;
using System.Runtime.InteropServices;
using HDF.PInvoke;
namespace MyNamespace
{
class Program
{
static void Main()
{
string datasetPath = "/dense1/dense1/bias:0";
long fileId = H5F.open(@"\path\to\weights.h5", H5F.ACC_RDONLY);
long dataSetId = H5D.open(fileId, datasetPath);
long typeId = H5D.get_type(dataSetId);
long spaceId = H5D.get_space(dataSetId);
// not sure about this
TextWriter tw = Console.Out;
GCHandle gch = GCHandle.Alloc(tw);
// I was hoping that this would write to the Console, but the
// program crashes outside the scope of the c# debugger.
H5D.read(
dataSetId,
typeId,
H5S.ALL,
H5S.ALL,
H5P.DEFAULT,
GCHandle.ToIntPtr(gch)
);
// Keep the console window open in debug mode.
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
}
Подпись для H5F.read()
является:
Type Name Description
--------------------------------------------------------------
long dset_id Identifier of the dataset read from.
long mem_type_id Identifier of the memory datatype.
long mem_space_id Identifier of the memory dataspace.
long file_space_id Identifier of the dataset's dataspace in the file.
long plist_id Identifier of a transfer property list for this I/O operation.
IntPtr buf Buffer to receive data read from file.
Вопрос
Может ли кто-нибудь помочь мне заполнить пробелы здесь?
2 ответа
Вам нужно создать массив (обычный 1D, а не 2D) правильного размера и типа. Затем напишите что-то вроде этого:
int width = 1920, height = 1080;
float[] data = new float[ width * height ];
var gch = GCHandle.Alloc( data, GCHandleType.Pinned );
try
{
H5D.read( /* skipped */, gch.AddrOfPinnedObject() );
}
finally
{
gch.Free();
}
Это будет читать набор данных в data
массив, вы можете скопировать отдельные строки в другой, 2D массив, если вам это нужно.
Прочитайте документацию API, как получить измерения (HDF5 поддерживает набор данных произвольных измерений) и размер набора данных (для 2D-набора данных размер составляет 2 целых числа), т.е. как узнать необходимый размер буфера (для 2D-набора данных это width * height
).
Что касается типа элементов, вы должны знать это заранее, например, float
Это хорошо.
В качестве альтернативы, возможно, вы захотите взглянуть на HDFql, поскольку он смягчает детали HDF5 низкого уровня. Ваше (опубликованное выше) решение может быть переписано / упрощено с использованием HDFql следующим образом:
using System;
using System.Runtime.InteropServices;
using AS.HDFql; // use HDFql namespace (make sure it can be found by the C# compiler)
namespace MyNamespace
{
class Program
{
static void Main()
{
// dims
int h = 162;
int w = 128;
// read array
float[] arrFlat = new float[h * w];
HDFql.Execute("SELECT FROM \\path\\to\\weights.h5 \"/dense1/dense1/kernel:0\" INTO MEMORY " + HDFql.VariableTransientRegister(arrFlat));
// reshape
float[,] arr = new float[h, w]; // row-major
for (int i = 0; i < h; i++)
{
for (int j = 0; j < w; j++)
{
arr[i, j] = arrFlat[i * w + j];
}
}
// show one entry
Console.WriteLine(arr[13, 87].ToString());
Console.WriteLine(arrFlat[13 * w + 87].ToString());
// Keep the console window open in debug mode.
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
}
Дополнительные примеры того, как читать наборы данных с использованием HDFql, можно найти в кратком руководстве и справочном руководстве.