blob: 2ce28b3a75e6bf325f531627a0c31eb8b40c3998 [file] [log] [blame]
#ifndef MSHADOW_TENSOR_IO_H
#define MSHADOW_TENSOR_IO_H
/*!
* \file tensor_io.h
* \brief definitions of I/O functions for mshadow tensor
* \author Tianqi Chen
*/
#include <cstdio>
#include "tensor.h"
namespace mshadow{
namespace utils{
/*!
* \brief interface of stream I/O, used to serialize data,
* it is not restricted to only this interface in SaveBinary/LoadBinary
* mshadow accept all class that implements Read and Write
*/
class IStream{
public:
/*!
* \brief read data from stream
* \param ptr pointer to memory buffer
* \param size size of block
* \return usually is the size of data readed
*/
virtual size_t Read( void *ptr, size_t size ) = 0;
/*!
* \brief write data to stream
* \param ptr pointer to memory buffer
* \param size size of block
*/
virtual void Write( const void *ptr, size_t size ) = 0;
/*! \brief virtual destructor */
virtual ~IStream( void ){}
};
};
/*!
* \brief CPU/GPU: save a tensor by binary format, for GPU version, a temp Tensor<cpu,dim> storage will be allocated
* \param fo output binary stream
* \param src source data file
* \tparam dim dimension of tensor
* \tparam TStream type of stream, need to support Read, Write, one example is utils::IStream.
*/
template<int dim,typename TStream>
inline void SaveBinary( TStream &fo, const Tensor<cpu,dim> &src );
/*! \brief refer to comment of cpu ver \sa SaveBinary */
template<int dim,typename TStream>
inline void SaveBinary( TStream &fo, const Tensor<gpu,dim> &src );
/*!
* \brief CPU/GPU: load a tensor by binary format, for GPU version, a temp Tensor<cpu,dim> storage will be allocated
* if pre_alloc is true , then space in dst is preallocated, and must have same shape of the tensor loaded
* if pre_alloc is false, then dst originally does not have space allocated, LoadBinary will allocate space for dst
* \param fi output binary stream
* \param dst destination file
* \param pre_alloc whether space is pre-allocated, if false, space allocation will happen
* \tparam dim dimension of tensor
* \tparam TStream type of stream, need to support Read, Write, one example is utils::IStream.
*/
template<int dim,typename TStream>
inline void LoadBinary( TStream &fi, Tensor<cpu,dim> &dst, bool pre_alloc );
/*! \brief refer to comment of cpu ver \sa LoadBinary */
template<int dim,typename TStream>
inline void LoadBinary( TStream &fi, Tensor<gpu,dim> &dst, bool pre_alloc );
namespace utils{
/*! \brief implementation of file i/o stream */
class FileStream: public IStream{
public:
/*! \brief constructor */
FileStream( FILE *fp ):fp_(fp){}
virtual size_t Read( void *ptr, size_t size ){
return fread( ptr, size, 1, fp_ );
}
virtual void Write( const void *ptr, size_t size ){
fwrite( ptr, size, 1, fp_ );
}
/*! \brief close file */
inline void Close( void ){
fclose( fp_ );
}
private:
FILE *fp_;
};
};
};
namespace mshadow{
// implementations
template<int dim, typename TStream>
inline void SaveBinary( TStream &fo, const Tensor<cpu,dim> &src_ ){
fo.Write( src_.shape.shape_, sizeof(index_t) * dim );
Tensor<cpu,2> src = src_.FlatTo2D();
for( index_t i = 0; i < src.shape[1]; ++ i ){
fo.Write( src[i].dptr, sizeof(real_t)*src.shape[0] );
}
}
template<int dim, typename TStream>
inline void SaveBinary( TStream &fo, const Tensor<gpu,dim> &src ){
// copy to CPU, then save
Tensor<cpu,dim> tmp( src.shape );
AllocSpace( tmp );
Copy( tmp, src );
SaveBinary( fo, tmp );
FreeSpace( tmp );
}
template<int dim, typename TStream>
inline void LoadBinary( TStream &fi, Tensor<cpu,dim> &dst_, bool pre_alloc ){
Shape<dim> shape;
utils::Assert( fi.Read( shape.shape_, sizeof(index_t) * dim ) != 0, "mshadow::LoadBinary" );
if( pre_alloc ){
utils::Assert( shape == dst_.shape );
}else{
dst_.shape = shape; AllocSpace( dst_ );
}
Tensor<cpu,2> dst = dst_.FlatTo2D();
if( dst.shape[0] == 0 ) return;
for( index_t i = 0; i < dst.shape[1]; ++ i ){
utils::Assert( fi.Read( dst[i].dptr, sizeof(real_t)*dst.shape[0] ) != 0, "mshadow::LoadBinary" );
}
}
template<int dim, typename TStream>
inline void LoadBinary( TStream &fi, Tensor<gpu,dim> &dst, bool pre_alloc ){
Tensor<cpu,dim> tmp;
LoadBinary( fi, tmp, false );
if( pre_alloc ){
utils::Assert( tmp.shape == dst.shape );
}else{
dst.shape = tmp.shape; AllocSpace( dst );
}
Copy( dst, tmp );
FreeSpace( tmp );
}
};
#endif // TENSOR_IO_H