MyCaffe  1.12.2.41
Deep learning software for Windows C# programmers.
HDF5.cs
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Runtime.InteropServices;
5using System.Text;
6using System.Threading.Tasks;
7using HDF5DotNet;
8using MyCaffe.basecode;
9using MyCaffe.common;
10
11namespace MyCaffe.layers.hdf5
12{
17 public interface IHDF5Load<T>
18 {
25 void CopyTrainedLayersFromHDF5(Net<T> net, Log log, string strFile);
26 }
27
32 public class HDF5<T> : IDisposable, IHDF5Load<T>
33 {
34 Log m_log;
35 CudaDnn<T> m_cuda;
36 H5FileId m_file;
37 string m_strFile;
38
45 public HDF5(CudaDnn<T> cuda, Log log, string strFile)
46 {
47 m_strFile = strFile;
48 m_cuda = cuda;
49 m_log = log;
50
51 m_file = H5F.open(strFile, H5F.OpenMode.ACC_RDONLY);
52 if (m_file == null)
53 m_log.FAIL("Failed opening HDF5 file: '" + strFile + "'!");
54 }
55
59 public HDF5()
60 {
61 }
62
63 private int get_num_links(H5GroupId hG)
64 {
65 H5GInfo info = H5G.getInfo(hG);
66 return (int)info.nLinks;
67 }
68
69 private string get_name_by_idx(H5GroupId hg, int i)
70 {
71 return H5L.getNameByIndex(hg, ".", H5IndexType.NAME, H5IterationOrder.NATIVE, i);
72 }
73
74 private Tuple<H5DataSetId, int> load_nd_datasetEx(Blob<T> blob, string strDatasetName, bool bReshape, int nMinDim = 1, int nMaxDim = int.MaxValue, H5GroupId id = null, bool bAllowSingleItems = false)
75 {
76 H5DataSetId ds = null;
77 int nSingleItemSize = 0;
78
79 try
80 {
81 if (id != null)
82 ds = H5D.open(id, strDatasetName);
83 else
84 ds = H5D.open(m_file, strDatasetName);
85
86 if (ds == null)
87 m_log.FAIL("Failed to find the dataset '" + strDatasetName + "'!");
88
89 // Verify that the number of dimensions are in the accepted range.
90 H5DataSpaceId dsSpace = H5D.getSpace(ds);
91 if (dsSpace == null)
92 m_log.FAIL("Failed to get the dataset space!");
93
94 int nDims = H5S.getSimpleExtentNDims(dsSpace);
95 m_log.CHECK_GE(nDims, nMinDim, "The dataset dim is out of range!");
96 m_log.CHECK_LE(nDims, nMaxDim, "The dataset dim is out of range!");
97
98 long[] rgDims = H5S.getSimpleExtentDims(dsSpace);
99
100 // Verify that the data format is what we expect: float or double
101 H5DataTypeId dsType = H5D.getType(ds);
102 if (dsType == null)
103 m_log.FAIL("Failed to get the dataset type!");
104
105 H5T.H5TClass dataClass = H5T.getClass(dsType);
106 switch (dataClass)
107 {
108 case H5T.H5TClass.FLOAT:
109 m_log.WriteLine("Datatype class: H5T_FLOAT");
110 break;
111
112 case H5T.H5TClass.INTEGER:
113 m_log.WriteLine("Datatype class: H5T_INTEGER");
114 break;
115
116 default:
117 m_log.FAIL("Unsupported datatype class: " + dataClass.ToString());
118 break;
119 }
120
121 List<int> rgBlobDims = new List<int>();
122 for (int i = 0; i < nDims; i++)
123 {
124 rgBlobDims.Add((int)rgDims[i]);
125 }
126
127 if (bReshape)
128 {
129 blob.Reshape(rgBlobDims);
130 }
131 else
132 {
133 if (!Utility.Compare<int>(rgBlobDims, blob.shape()))
134 {
135 if (!bAllowSingleItems || (rgBlobDims.Count == 1 && rgBlobDims[0] != 1))
136 {
137 string strSrcShape = Utility.ToString<int>(rgBlobDims);
138 m_log.FAIL("Cannot load blob from hdf5; shape mismatch. Source shape = " + strSrcShape + ", target shape = " + blob.shape_string);
139 }
140
141 if (rgBlobDims.Count == 1)
142 nSingleItemSize = rgBlobDims[0];
143 }
144 }
145 }
146 catch (Exception excpt)
147 {
148 if (ds != null)
149 {
150 H5D.close(ds);
151 ds = null;
152 }
153
154 throw excpt;
155 }
156
157 return new Tuple<H5DataSetId, int>(ds, nSingleItemSize);
158 }
159
170 public void load_nd_dataset(Blob<T> blob, string strDatasetName, bool bReshape = false, int nMinDim = 1, int nMaxDim = int.MaxValue, H5GroupId id = null, bool bAllowSingleItems = false)
171 {
172 H5DataSetId ds = null;
173 int nSingleItemSize = 0;
174
175 try
176 {
177 Tuple<H5DataSetId, int> ds1 = load_nd_datasetEx(blob, strDatasetName, bReshape, nMinDim, nMaxDim, id, bAllowSingleItems);
178 ds = ds1.Item1;
179 nSingleItemSize = ds1.Item2;
180
181 H5DataTypeId dsType = H5D.getType(ds);
182 int nSize = H5T.getSize(dsType);
183
184 if (nSize == sizeof(double))
185 {
186 double[] rgBuffer = new double[blob.count()];
187 H5Array<double> rgData = new H5Array<double>(rgBuffer);
188
189 H5D.read<double>(ds, dsType, rgData);
190
191 if (!bAllowSingleItems || nSingleItemSize == 0)
192 blob.mutable_cpu_data = Utility.ConvertVec<T>(rgBuffer);
193 else
194 blob.SetData(rgBuffer[0]);
195 }
196 else if (nSize == sizeof(float))
197 {
198 float[] rgBuffer = new float[blob.count()];
199 H5Array<float> rgData = new H5Array<float>(rgBuffer);
200
201 H5D.read<float>(ds, dsType, rgData);
202
203 if (!bAllowSingleItems || nSingleItemSize == 0)
204 blob.mutable_cpu_data = Utility.ConvertVec<T>(rgBuffer);
205 else
206 blob.SetData(rgBuffer[0]);
207 }
208 else if (nSize == sizeof(byte))
209 {
210 byte[] rgBuffer = new byte[blob.count()];
211 H5Array<byte> rgData = new H5Array<byte>(rgBuffer);
212
213 H5D.read<byte>(ds, dsType, rgData);
214
215 float[] rgf = rgBuffer.Select(p1 => (float)p1).ToArray();
216 blob.mutable_cpu_data = Utility.ConvertVec<T>(rgf);
217 }
218 else
219 m_log.FAIL("The dataset size of '" + nSize.ToString() + "' is not supported!");
220 }
221 catch (Exception excpt)
222 {
223 m_log.FAIL(excpt.Message);
224 }
225 finally
226 {
227 if (ds != null)
228 H5D.close(ds);
229 }
230 }
231
238 public void CopyTrainedLayersFromHDF5(Net<T> net, Log log, string strFile)
239 {
240 m_log = log;
241
242 if (m_file == null)
243 {
244 m_file = H5F.open(strFile, H5F.OpenMode.ACC_RDONLY);
245 if (m_file == null)
246 m_log.FAIL("Failed opening HDF5 weights file: '" + strFile + "'!");
247 }
248
249 H5GroupId hData = null;
250 H5GroupId hLayer = null;
251
252 try
253 {
254 hData = H5G.open(m_file, "data");
255 if (hData == null || hData.Id <= 0)
256 m_log.FAIL("Failed to open the 'data' data stream within the HDF5 weights file: '" + strFile + "'!");
257
258 int nNumLayers = get_num_links(hData);
259
260 for (int i = 0; i < nNumLayers; i++)
261 {
262 string strSrcLayerName = get_name_by_idx(hData, i);
263
264 if (net.layer_index_by_name(strSrcLayerName) < 0)
265 {
266 m_log.WriteLine("Ignoring source layer '" + strSrcLayerName + "'.");
267 continue;
268 }
269
270 int nTargetLayerId = net.layer_index_by_name(strSrcLayerName);
271 m_log.WriteLine("Copying source layer '" + strSrcLayerName + "'.");
272
273 BlobCollection<T> targetBlobs = net.layers[nTargetLayerId].blobs;
274
275 hLayer = H5G.open(hData, strSrcLayerName);
276 if (hLayer == null || hLayer.Id <= 0)
277 m_log.FAIL("Failed to open '" + strSrcLayerName + "' layer in data stream within the HDF5 weights file: '" + strFile + "'!");
278
279 // Check that source layer doesnt have more params than target layer.
280 int nNumSourceParams = get_num_links(hLayer);
281 m_log.CHECK_LE(nNumSourceParams, targetBlobs.Count, "Incompatible number of blobs for layer '" + strSrcLayerName + "'!");
282
283 for (int j = 0; j < nNumSourceParams; j++)
284 {
285 string strDatasetName = j.ToString();
286
287 if (!H5L.Exists(hLayer, strDatasetName))
288 {
289 // Target param doesnt exist in source weights...
290 int nTargetNetParamId = net.param_names_index[strDatasetName];
291 if (net.param_owners.Contains(nTargetNetParamId))
292 {
293 // ...but its weight-shared in target, thats fine.
294 continue;
295 }
296 else
297 {
298 m_log.FAIL("Incompatible number of blobs for layer '" + strSrcLayerName + "'!");
299 }
300 }
301
302 load_nd_dataset(targetBlobs[j], strDatasetName, false, 1, int.MaxValue, hLayer, true);
303 }
304
305 H5G.close(hLayer);
306 hLayer = null;
307 }
308
309 H5G.close(hData);
310 hData = null;
311 }
312 finally
313 {
314 if (hLayer != null)
315 H5G.close(hLayer);
316
317 if (hData != null)
318 H5G.close(hData);
319 }
320 }
321
325 public void Dispose()
326 {
327 if (m_file != null)
328 {
329 H5F.close(m_file);
330 m_file = null;
331 }
332 }
333 }
334}
The Log class provides general output in text form.
Definition: Log.cs:13
void FAIL(string str)
Causes a failure which throws an exception with the desciptive text.
Definition: Log.cs:394
The Utility class provides general utility funtions.
Definition: Utility.cs:35
static double[] ConvertVec(float[] rgf)
Convert an array of float to an array of generics.
Definition: Utility.cs:550
The BlobCollection contains a list of Blobs.
int Count
Returns the number of items in the collection.
The Blob is the main holder of data that moves through the Layers of the Net.
Definition: Blob.cs:25
void SetData(T[] rgData, int nCount=-1, bool bSetCount=true)
Sets a number of items within the Blob's data.
Definition: Blob.cs:1922
string shape_string
Returns a string describing the Blob's shape.
Definition: Blob.cs:657
T[] mutable_cpu_data
Get data from the GPU and bring it over to the host, or Set data from the Host and send it over to th...
Definition: Blob.cs:1461
void Reshape(int nNum, int nChannels, int nHeight, int nWidth, bool? bUseHalfSize=null)
DEPRECIATED; use
Definition: Blob.cs:442
List< int > shape()
Returns an array where each element contains the shape of an axis of the Blob.
Definition: Blob.cs:684
int count()
Returns the total number of items in the Blob.
Definition: Blob.cs:739
The CudaDnn object is the main interface to the Low-Level Cuda C++ DLL.
Definition: CudaDnn.cs:969
Connects Layer's together into a direct acrylic graph (DAG) specified by a NetParameter
Definition: Net.cs:23
List< Layer< T > > layers
Returns the layers.
Definition: Net.cs:2003
int layer_index_by_name(string strLayer)
Returns a Layer's index given its name.
Definition: Net.cs:2315
DictionaryEx< string, int > param_names_index
Returns the dictionary look for parameter names to their indexes.
Definition: Net.cs:2141
List< int > param_owners
Returns the list of parameter owner indexes.
Definition: Net.cs:2149
The HDF5 object provides HDF5 dataset support to the HDF5DataLayer.
Definition: HDF5.cs:33
void Dispose()
Release all resources uses.
Definition: HDF5.cs:325
void CopyTrainedLayersFromHDF5(Net< T > net, Log log, string strFile)
Copy the weights from an HDF5 file into a Net.
Definition: HDF5.cs:238
HDF5()
The constructor used when loading weights into a Net.
Definition: HDF5.cs:59
HDF5(CudaDnn< T > cuda, Log log, string strFile)
The constructor.
Definition: HDF5.cs:45
void load_nd_dataset(Blob< T > blob, string strDatasetName, bool bReshape=false, int nMinDim=1, int nMaxDim=int.MaxValue, H5GroupId id=null, bool bAllowSingleItems=false)
Creates a new dataset from an HDF5 data file.
Definition: HDF5.cs:170
The HDF5Load interface is used to load weights into objects like a Net.
Definition: HDF5.cs:18
void CopyTrainedLayersFromHDF5(Net< T > net, Log log, string strFile)
Copy the weights from an HDF5 file into a Net.
The MyCaffe.basecode contains all generic types used throughout MyCaffe.
Definition: Annotation.cs:12
The MyCaffe.common namespace contains common MyCaffe classes.
Definition: BatchInput.cs:8
The MyCaffe.layers.hdf5 namespace contains all HDF5 related layers.
Definition: LayerFactory.cs:15
The MyCaffe namespace contains the main body of MyCaffe code that closesly tracks the C++ Caffe open-...
Definition: Annotation.cs:12