npy2flt のソースコード

#!
# coding: utf-8
# Copyright (C) 2017 TOPS SYSTEMS
### @file npy2flt.py
### @brief Numpy format binary array to FLT format converter
###
### Numpyフォーマットのバイナリ配列を読み取り、FLT形式にして出力する
###
### Contact: izumida@topscom.co.jp
###
### @author: M.Izumida
### @date: April 19, 2017
###
# Original: fltFormatter.py v01r01
# Written for Python 2.7 (NOT FOR 3.x)
#=======================================================================
# インポート宣言
from __future__ import division
import sys
import re
import argparse
import os
import numpy as np
from datetime import datetime
#=======================================================================
# バージョン文字列
versionSTR = "npy2flt.py v01r01 Tops Systems (pgm by mpi)"
#=======================================================================
# 共通サブルーチン
#-------------------------------------------------------------------
def errPrint(mes):
    """errPrint.

    エラー出力へのメッセージ表示
    後の始末はその後で別に書くこと
    """
    sys.stderr.write(mes)
    sys.stderr.write('\n')

#-------------------------------------------------------------------
def stdExceptionHandler(mes):
    """standard Exception Handler.

    エラーメッセージを送出し、デバッグのための情報を出力する
    """
    errPrint("Exception Captured: " + str(mes))
    errPrint("0:" + str(sys.exc_info()[0]))
    errPrint("1:" + str(sys.exc_info()[1]))
    errPrint("2:" + str(sys.exc_info()[2]))

#-------------------------------------------------------------------
def tryIntParse(st, dval, radix=10):
    """try Parse string to Integer

    文字列stをパースして整数化できれば値を返す、できなければデフォルト値dvalを返す
    """
    try:
        work = int(st, radix)
    except:
        return dval
    return work

#=======================================================================
# 解析オプション クラス
class Options:
    """Options Class.

    グローバルオプションを保持するクラス
    """
    pass

#=======================================================================
# Numpyファイルリーダクラス
[ドキュメント]class NumpyFileReader: """NumpyFile Reader Class. Numpy形式のバイナリファイルを読みとってNumpy ndarrayとして確保する。 読み取り時にshapeを報告する。 取り出し時には、FltFileWriterで出力できるようにshapeを加工したndarrayに変形する """ #-------------------------------------------------------------------- # 静的(クラス)変数 static_const_modeDic = dict() static_const_modeDic['none'] = 0 static_const_modeDic['NHWC'] = 1 static_const_modeDic['NCHW'] = 2 static_const_modeDic['HWI_'] = 3 static_const_modeDic['HW_O'] = 4 #-------------------------------------------------------------------- # 静的(クラス)メソッド @staticmethod
[ドキュメント] def getModeNumber(modeName): """get Mode Number. モード文字列からモード番号を返す。 """ if modeName in NumpyFileReader.static_const_modeDic: return NumpyFileReader.static_const_modeDic[modeName] else: return 0
#-------------------------------------------------------------------- def __init__(self, inputFnam, bt): """Numpy File Reader Constructor コンストラクタ """ self.iFname = inputFnam #<<! 入力.npyファイル名 self.nArray = None #<<! 確保した配列 self.prmBatch = bt #<<! 抽出するバッチ番号 # debug self.debug = False self.verbose = False #--------------------------------------------------------------------
[ドキュメント] def read(self): """Read method .npyファイルを読み込むメソッド。読み込み成功すれば真を返す。 """ try: self.nArray = np.load(self.iFname) if self.verbose: print "Shape : ", self.nArray.shape print "dType : ", self.nArray.dtype except: stdExceptionHandler("Error: in file reading = " + self.iFname) return False return True
#--------------------------------------------------------------------
[ドキュメント] def getArray(self, mode): """Get Array method 読み込み済のndarrayをmodeに従って変形したndarrayに変換して返す。 'NHWC' = 1 ... 特定のN=prmBatch について、HWをWHに変換W*H->X, C->Y 'NCHW' = 2 ... 特定のN=prmBatch について、HWをWHに変換W*H->X, C->Y 'HWI\_' = 3 ... _=0固定、HWをWHに変換W*H->X, C->Y 'HW_O' = 4 ... _=0固定、HWをWHに変換W*H->X, C->Y 変換不能な場合は Noneを返す。 """ if mode == 1: return self.getNHWC() elif mode == 2: return self.getNCHW() elif mode == 3: return self.getHWI_() elif mode == 4: return self.getHW_O() else: return None
#--------------------------------------------------------------------
[ドキュメント] def getNHWC(self): """Get NHWC Array 'NHWC' = 1 ... 特定のN=prmBatch について、HWをWHに変換W*H->X, C->Y """ sh = self.nArray.shape if len(sh) != 4: print "ERROR: NOT A NHWC format.", sh return None wTEMP = sh[2] wALIGN = ((wTEMP + 15) // 16) * 16 wFILL = wTEMP % 16 iX = sh[1] * wALIGN iY = sh[3] if self.verbose: print "NHWC" print "iX=", iX, "W(ORG)=", sh[2], "W(ALIGN)=", wALIGN, "H=", sh[1], "iY=", iY oArray = np.zeros((iX, iY), dtype=self.nArray.dtype) for cY in range(0, sh[3]): for hX in range(0, sh[1]): for wX in range(0, wALIGN): if wX < sh[2]: temp = self.nArray[self.prmBatch, hX, wX, cY] else: temp = 0 oArray[hX * wALIGN + wX, cY]=temp return oArray
#--------------------------------------------------------------------
[ドキュメント] def getNCHW(self): """Get NCHW Array 'NCHW' = 2 ... 特定のN=prmBatch について、HWをWHに変換W*H->X, C->Y """ sh = self.nArray.shape if len(sh) != 4: print "ERROR: NOT A NHWC format.", sh return None wTEMP = sh[3] wALIGN = ((wTEMP + 15) // 16) * 16 wFILL = wTEMP % 16 iX = sh[2] * wALIGN iY = sh[1] if self.verbose: print "NHWC" print "iX=", iX, "W(ORG)=", sh[3], "W(ALIGN)=", wALIGN, "H=", sh[2], "iY=", iY oArray = np.zeros((iX, iY), dtype=self.nArray.dtype) for cY in range(0, sh[1]): for hX in range(0, sh[2]): for wX in range(0, wALIGN): if wX < sh[3]: temp = self.nArray[self.prmBatch, cY, hX, wX] else: temp = 0 oArray[hX * wALIGN + wX, cY]=temp return oArray
#--------------------------------------------------------------------
[ドキュメント] def getHWI_(self): """Get HWI\_ Array 'HWI\_' = 3 ... _=0固定、HWをWHに変換W*H->X, C->Y """ sh = self.nArray.shape if len(sh) != 4: print "ERROR: NOT A HW_O format.", sh return None iX = sh[0] * sh[1] iY = sh[2] if self.verbose: print "HW_O" print "iX=", iX, "W=", sh[1], "H=", sh[0], "iY=", iY oArray = np.zeros((iX, iY), dtype=self.nArray.dtype) for cY in range(0, sh[2]): for hX in range(0, sh[0]): for wX in range(0, sh[1]): oArray[hX * sh[1] + wX, cY]=self.nArray[hX, wX, cY, 0] return oArray
#--------------------------------------------------------------------
[ドキュメント] def getHW_O(self): """Get HW_O Array 'HW_O' = 4 ... _=0固定、HWをWHに変換W*H->X, C->Y """ sh = self.nArray.shape if len(sh) != 4: print "ERROR: NOT A HW_O format.", sh return None iX = sh[0] * sh[1] iY = sh[3] if self.verbose: print "HW_O" print "iX=", iX, "W=", sh[1], "H=", sh[0], "iY=", iY oArray = np.zeros((iX, iY), dtype=self.nArray.dtype) for cY in range(0, sh[3]): for hX in range(0, sh[0]): for wX in range(0, sh[1]): oArray[hX * sh[1] + wX, cY]=self.nArray[hX, wX, 0, cY] return oArray
#======================================================================= # FLTファイルライタクラス
[ドキュメント]class FltFileWriter: """FltFile Writer Class. Numpy 配列をFLT形式ファイルとして出力する。 モードにより整形用の「フィルタ」を適用する。 """ #-------------------------------------------------------------------- # 静的(クラス)変数 static_const_modeDic = dict() static_const_modeDic['none'] = 0 static_const_modeDic['ip8'] = 1 #-------------------------------------------------------------------- # 静的(クラス)メソッド @staticmethod
[ドキュメント] def getModeNumber(modeName): """get Mode Number. モード文字列からモード番号を返す。 """ if modeName in FltFileWriter.static_const_modeDic: return FltFileWriter.static_const_modeDic[modeName] else: return 0
#-------------------------------------------------------------------- def __init__(self, nary, aName, md, padX): """FLT File Writer Constructor コンストラクタ """ # 入力配列 self.IN_nArray = nary #<<! 入力Numpy配列 self.IN_arrayName = aName #<<! 入力FLT配列名 self.IN_iX = 0 #<<! 入力Numpy配列のXサイズ self.IN_iY = 0 #<<! 入力Numpy配列のYサイズ if isinstance(self.IN_nArray, np.ndarray): self.IN_iX, self.IN_iY = self.IN_nArray.shape # 出力配列 self.nArray = None #<<! 出力するNumpy配列 self.arrayName = None #<<! 出力FLT配列名 self.iX = 0 #<<! 出力Numpy配列のXサイズ self.iY = 0 #<<! 出力Numpy配列のYサイズ self.fX = 0 #<<! 出力FLT配列のXサイズ self.fY = 0 #<<! 出力FLT配列のYサイズ # mode self.mode = md #<<! モードフラグ self.paddingX = padX #<<! 出力fX方向のパディングサイズ # debug self.debug = False self.verbose = False #--------------------------------------------------------------------
[ドキュメント] def formatArray(self): """format Array 入力Numpy配列の形とモードから出力Numpy配列を準備し、 モードに応じた方法でデータを変形しながら転送する。 成功すれば真、そうでなければ偽。 """ if self.mode == FltFileWriter.static_const_modeDic['none']: self.arrayName = self.IN_arrayName return self.makeSTRAIGHT() elif self.mode == FltFileWriter.static_const_modeDic['ip8']: self.arrayName = self.IN_arrayName + "_ip8" return self.makeIP8() else: return False
#--------------------------------------------------------------------
[ドキュメント] def makeIP8(self): """format IP8(inner product x 8 mode) 内積計算8並列モードとなるように入力Numpy配列の行8行を1行とした出力Numpy配列を準備する。 横幅8倍、縦幅8分の1 入力Numpy配列の行8行縦1列を横8要素として出力Numpy配列にコピー (行が8行以下の場合は要素0フィルして8要素とする) 成功すれば真、そうでなければ偽。 """ if self.IN_nArray is None: return False self.iX = self.IN_iX * 8 self.iY = (self.IN_iY + 7) / 8 if (self.iX > 0) and (self.iY > 0): if self.verbose: print "NEW ARRAY, x:{0} y:{1}".format(self.iX, self.iY) self.nArray = np.zeros((self.iX, self.iY), dtype=np.float) else: return False tempDat = np.zeros(8, dtype=np.float) for oLine in range(0, self.iY): #出力側行番号で舐める for iCol in range(0, self.IN_iX): #入力側列番号で舐める self.nArray[iCol * 8 + 0, oLine] = float(self.IN_nArray[iCol, oLine * 8 + 0]) if (oLine * 8 + 0) < self.IN_iY else 0.0 self.nArray[iCol * 8 + 1, oLine] = float(self.IN_nArray[iCol, oLine * 8 + 1]) if (oLine * 8 + 1) < self.IN_iY else 0.0 self.nArray[iCol * 8 + 2, oLine] = float(self.IN_nArray[iCol, oLine * 8 + 2]) if (oLine * 8 + 2) < self.IN_iY else 0.0 self.nArray[iCol * 8 + 3, oLine] = float(self.IN_nArray[iCol, oLine * 8 + 3]) if (oLine * 8 + 3) < self.IN_iY else 0.0 self.nArray[iCol * 8 + 4, oLine] = float(self.IN_nArray[iCol, oLine * 8 + 4]) if (oLine * 8 + 4) < self.IN_iY else 0.0 self.nArray[iCol * 8 + 5, oLine] = float(self.IN_nArray[iCol, oLine * 8 + 5]) if (oLine * 8 + 5) < self.IN_iY else 0.0 self.nArray[iCol * 8 + 6, oLine] = float(self.IN_nArray[iCol, oLine * 8 + 6]) if (oLine * 8 + 6) < self.IN_iY else 0.0 self.nArray[iCol * 8 + 7, oLine] = float(self.IN_nArray[iCol, oLine * 8 + 7]) if (oLine * 8 + 7) < self.IN_iY else 0.0 return True
#--------------------------------------------------------------------
[ドキュメント] def makeSTRAIGHT(self): """format STRAIGHT そのままのX, Yサイズで出力Numpy配列を準備する。 """ if self.IN_nArray is None: return False self.iX = self.IN_iX self.iY = self.IN_iY if (self.iX > 0) and (self.iY > 0): if self.verbose: print "NEW ARRAY, x:{0} y:{1}".format(self.iX, self.iY) self.nArray = np.zeros((self.iX, self.iY), dtype=np.float) else: return False for oLine in range(0, self.iY): #出力側行番号で舐める for iCol in range(0, self.iX): #入力側列番号で舐める self.nArray[iCol, oLine] = float(self.IN_nArray[iCol, oLine]) return True
#--------------------------------------------------------------------
[ドキュメント] def writeFLT(self, fname): """write FLT file 出力Numpy配列をFLTファイルへ出力。 出力X方向がpaddingXの倍数でなければpaddingXの倍数になるまで0で埋める。 Numpy配列とFLTファイル上のxが異なることがある。 書き込み成功すれば真 """ segLen = (self.iX + (self.paddingX - 1)) // self.paddingX self.fX = segLen * self.paddingX self.fY = self.iY if self.debug: print self.iX, self.fX, self.paddingX try: with open(fname, 'w') as f: f.write('@{0}<FLOAT>[{1}, {2}] '.format(self.arrayName, self.fX, self.fY) + '{\n' ) lfNum = 0 #行送り用カウンタ for ay in range(0, self.iY): for ax in range(0, self.fX): if ax < self.iX: f.write(str(self.nArray[ax][ay])+", ") else: f.write("0, ") lfNum += 1 if lfNum == 16: #FLTファイルは16要素毎に改行を入れる。 f.write('\n') lfNum = 0 if lfNum != 0: f.write('\n') f.write('} ' + 'nREC={0}, CONV_ERR_CODE=0, CONV_ERR_COUNT=0\n'.format(self.fX*self.fY)) except: stdExceptionHandler("ERROR: Unexpected Error in the writing dump file. ?=" + fname) return False return True
#======================================================================= # メインプログラム def main(): """main. メインプログラム """ #----------------------------------------------------------------------- # コマンドラインオプション処理 # parser = argparse.ArgumentParser(description='npy2flt, NPY to FLT format converter.') parser.add_argument('--NPY', nargs=1, help='NPY format binary data file name.') parser.add_argument('--NPFMT', nargs=1, help='NPY array Format, (NHWC, ...).') parser.add_argument('--FOUT', nargs=1, help='Output FLT file name.') parser.add_argument('--FARRAY', nargs=1, help='Output FLT Array name.') parser.add_argument('--FMT', nargs=1, help='Formatting mode, (ip8, ...).') parser.add_argument('--PADX', nargs=1, help='X PADDING SIZE (default=32).') parser.add_argument('--BATCH', nargs=1, help='Extract # of NPY BATCH.') parser.add_argument('-d', dest='debug', help='Debug mode, print debug information.', action='store_true', default=False) parser.add_argument('-v', dest='verbose', help='Verbose mode.', action='store_true', default=False) parser.add_argument('-V', dest='VERSION', help='Show Version, then exit', action='store_true', default=False) args = parser.parse_args() #----------------------------------------------------------------------- # Version 表示 # print versionSTR if args.VERSION: sys.exit(0) #----------------------------------------------------------------------- # ファイル名処理 # if args.NPY is None: errPrint('ERROR: NO .NPY file!') sys.exit(1) else: npyFname = args.NPY[0] if not os.path.isfile(npyFname): errPrint('ERROR: NPY file, NOT EXIST. ?=' + npyFname) sys.exit(1) if args.FOUT is None: print "WARNING: NO OUTPUT mode." foutFname = None else: foutFname = args.FOUT[0] if args.FARRAY is None: farrayName = "fromNumpyArray" else: farrayName = args.FARRAY[0] #----------------------------------------------------------------------- # パラメータ処理 if args.NPFMT is None: npMode = 0 else: npMode = NumpyFileReader.getModeNumber(args.NPFMT[0]) if npMode == 0: errPrint('WARNING: Unknown Numpy array Format.') if args.FMT is None: fmtMode = 0 else: fmtMode = FltFileWriter.getModeNumber(args.FMT[0]) if fmtMode == 0: errPrint('WARNING: FLT output is a Straight.') if args.BATCH is None: prmBatch = 0 else: prmBatch = tryIntParse(args.BATCH[0], 0) if args.PADX is None: paddingX = 32 else: paddingX = tryIntParse(args.PADX[0], 32) #----------------------------------------------------------------------- # 実処理 # print "-"*50 #元ファイルを読み込み npyOBJ = NumpyFileReader(npyFname, prmBatch) npyOBJ.debug = args.debug npyOBJ.verbose = args.verbose if not npyOBJ.read(): sys.exit(1) # 変換出力 if foutFname is not None: fout = FltFileWriter(npyOBJ.getArray(npMode), farrayName, fmtMode, paddingX) fout.debug = args.debug fout.verbose = args.verbose if fout.formatArray(): if not fout.writeFLT(foutFname): errPrint("ERROR: Writing FLT file. ?=" + foutFname) sys.exit(1) else: errPrint("ERROR: Formatting FLT file. ?mode=" + str(fmtMode)) sys.exit(1) today = datetime.today() print today.strftime("FINISH: %Y/%m/%d %H:%M:%S") #----------------------------------------------------------------------- # 正常終了 # sys.exit(0) #======================================================================= # メインプログラムの起動 if __name__ == "__main__": main()