Files

164 lines
6.5 KiB
Python

# Copyright (c) 2006 Carnegie Mellon University
#
# You may copy and modify this freely under the same terms as
# Sphinx-III
"""Read/write Sphinx-III Gaussian parameter.
This module reads and writes the mean and variance parameter files
used by SphinxTrain, Sphinx-III, and PocketSphinx.
"""
__author__ = "David Huggins-Daines <dhdaines@gmail.com>"
__version__ = "$Revision$"
from struct import unpack, pack
from numpy import reshape, shape, frombuffer
from .s3file import S3File, S3File_write
def open(filename, mode="rb", attr={"version": 1.0}):
if mode in ("r", "rb"):
return S3GauFile(filename)
elif mode in ("w", "wb"):
return S3GauFile_write(filename, attr=attr)
else:
raise Exception("mode must be 'r', 'rb', 'w', or 'wb'")
def open_full(filename, mode="rb", attr={"version": 1.0}):
if mode in ("r", "rb"):
return S3FullGauFile(filename)
elif mode in ("w", "wb"):
return S3FullGauFile_write(filename, attr=attr)
else:
raise Exception("mode must be 'r', 'rb', 'w', or 'wb'")
class S3GauFile(S3File):
"Read Sphinx-III format Gaussian parameter files"
def __init__(self, filename, mode="rb"):
super().__init__(filename=filename, mode=mode)
self._load()
def readgauheader(self):
if self.fileattr["version"] != "1.0":
raise Exception("Version mismatch: must be 1.0 but is "
+ self.fileattr["version"])
self.fh.seek(self.data_start, 0)
self.n_mgau = unpack(self.swap + "I", self.fh.read(4))[0]
self.n_feat = unpack(self.swap + "I", self.fh.read(4))[0]
self.density = unpack(self.swap + "I", self.fh.read(4))[0]
self.veclen = unpack(self.swap + "I" * self.n_feat,
self.fh.read(4 * self.n_feat))
self.blk = sum(self.veclen)
self._nfloats = unpack(self.swap + "I", self.fh.read(4))[0]
def _load(self):
self.readgauheader()
if self._nfloats != self.n_mgau * self.density * self.blk:
raise Exception(("Number of data points %d doesn't match "
+ "total %d = %d*%d*%d")
%
(self._nfloats,
self.n_mgau * self.density * self.blk,
self.n_mgau, self.density, self.blk))
# First load everything into a really big Numeric array.
spam = self.fh.read(self._nfloats * 4)
data = frombuffer(spam, 'f').copy()
if self.otherend:
data = data.byteswap()
# The on-disk layout is bogus so we have to slice and dice it.
# Since feature streams are not the same dimensionality, we use
# a two-dimensional outer list of Numeric array slices
params = []
r = 0
for i in range(0, self.n_mgau):
mgau = []
params.append(mgau)
for j in range(0, self.n_feat):
rnext = r + self.density * self.veclen[j];
gmm = reshape(data[r:rnext], (self.density, self.veclen[j]))
mgau.append(gmm)
r = rnext
self._params = params
class S3FullGauFile(S3GauFile):
"Read Sphinx-III format Gaussian full covariance matrix files"
def _load(self):
self.readgauheader()
if self._nfloats != self.n_mgau * self.density * self.blk * self.blk:
raise Exception(("Number of data points %d doesn't match "
+ "total %d = %d*%d*%d*%d")
%
(self._nfloats,
self.n_mgau * self.density * self.blk * self.blk,
self.n_mgau, self.density, self.blk, self.blk))
# First load everything into a really big Numeric array.
# This is inefficient, but in the absence of fromfile()...
spam = self.fh.read(self._nfloats * 4)
data = frombuffer(spam, 'f').copy()
if self.otherend:
data = data.byteswap()
# The on-disk layout is bogus so we have to slice and dice it.
# Since feature streams are not the same dimensionality, we use
# a two-dimensional outer list of Numeric array slices
params = []
r = 0
for i in range(0, self.n_mgau):
mgau = []
params.append(mgau)
for j in range(0, self.n_feat):
rnext = r + self.density * self.veclen[j] * self.veclen[j];
gmm = reshape(data[r:rnext], (self.density,
self.veclen[j],
self.veclen[j]))
mgau.append(gmm)
r = rnext
self._params = params
class S3GauFile_write(S3File_write):
"Write Sphinx-III format Gaussian parameter files"
def writeall(self, stuff):
# Single-stream files are easy
n_mgau = len(stuff)
n_feat = len(stuff[0])
n_density = len(stuff[0][0])
if n_feat == 1:
veclen = len(stuff[0][0][0])
# Write the header
self.fh.seek(self.data_start, 0)
self.fh.write(pack("=IIIII",
n_mgau, n_feat, n_density, veclen,
n_mgau * n_feat * n_density * veclen))
allgau = reshape(stuff, (n_mgau*n_feat*n_density*veclen,))
self.fh.write(pack("=" + str(len(allgau)) + "f", *allgau))
else:
veclen = [len(x[0]) for x in stuff[0]]
# Write the header
self.fh.seek(self.data_start, 0)
self.fh.write(pack("=III", n_mgau, n_feat, n_density))
self.fh.write(pack(("=%dI" % len(veclen)), *veclen))
self.fh.write(pack("=I", n_mgau * n_density * sum(veclen)))
for m in stuff:
for f in m:
f.ravel().astype('f').tofile(self.fh)
class S3FullGauFile_write(S3GauFile_write):
"Write Sphinx-III format Gaussian full covariance matrix files"
def writeall(self, stuff):
# This will break for multi-stream files
n_mgau, n_feat, density, veclen, veclen2 = shape(stuff)
if n_feat != 1:
raise Exception("Multi-stream files not supported")
# Write the header
self.fh.seek(self.data_start, 0)
self.fh.write(pack("=IIIII",
n_mgau, n_feat, density, veclen,
n_mgau * n_feat * density * veclen * veclen2))
allgau = reshape(stuff, (n_mgau*n_feat*density*veclen*veclen2,))
self.fh.write(pack("=" + str(len(allgau)) + "f", *allgau))