//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ // // Copyright (c) 2001 Microsoft Corporation. All rights reserved. // // Module: // volcano/dll/brknet.c // // Description: // Functions to implement the functionality of the break Neural net that // modifies the lattice structure to correct segmentation errors. // // Author: // ahmadab 11/05/01 // //$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ #include "common.h" #include "volcanop.h" #include "lattice.h" #include "runnet.h" #include "brknet.h" #include "segm.h" #include "nnet.h" // the size and structure representing the Breaking net used in Free mode // if the is not available for a particular configuration, s_iBrkNetSize will be zero static int s_iBrkNetSize = 0; static LOCAL_NET s_BrkNet; // validates the header of the brknet BOOL CheckBrkNetHeader (void *pData) { NNET_HEADER *pHeader = (NNET_HEADER *)pData; // wrong magic number ASSERT (pHeader->dwFileType == BRKNET_FILE_TYPE); if (pHeader->dwFileType != BRKNET_FILE_TYPE) { return FALSE; } // check version ASSERT(pHeader->iFileVer >= BRKNET_OLD_FILE_VERSION); ASSERT(pHeader->iMinCodeVer <= BRKNET_CUR_FILE_VERSION); ASSERT ( !memcmp ( pHeader->adwSignature, g_locRunInfo.adwSignature, sizeof (pHeader->adwSignature) ) ); ASSERT (pHeader->cSpace == 1); if ( pHeader->iFileVer >= BRKNET_OLD_FILE_VERSION && pHeader->iMinCodeVer <= BRKNET_CUR_FILE_VERSION && !memcmp ( pHeader->adwSignature, g_locRunInfo.adwSignature, sizeof (pHeader->adwSignature) ) && pHeader->cSpace == 1 ) { return TRUE; } else { return FALSE; } } // does the necessary preparations for a net to be used later static LOCAL_NET *PrepareBrkNet(BYTE *pData, int *piNetSize, LOCAL_NET *pNet) { NNET_SPACE_HEADER *pSpaceHeader; if (!pData) { return FALSE; } // check the header info if (!CheckBrkNetHeader (pData)) { return NULL; } // point to the one and only space that we have pSpaceHeader = (NNET_SPACE_HEADER *)(pData + sizeof (NNET_HEADER)); // point to the actual data pData = pData + pSpaceHeader->iDataOffset; // restore the connections if (!(pNet = restoreLocalConnectNet(pData, 0, pNet)) ) { return NULL; } // compute the run time memory requirements of the net (*piNetSize) = getRunTimeNetMemoryRequirements(pData); if ((*piNetSize) <= 0) { return NULL; } return pNet; } // load the brk net from resources BOOL LoadBrkNetFromFile(wchar_t *pwszRecogDir, LOAD_INFO *pLoadInfo) { BYTE *pData; wchar_t awszFileName[MAX_PATH]; // init the size to zero, in case we fail s_iBrkNetSize = 0; swprintf (awszFileName, L"%s\\brknet.bin", pwszRecogDir); // memory map the file pData = DoOpenFile (pLoadInfo, awszFileName); if (!pData) { return FALSE; } // prepare Brk net if (!PrepareBrkNet(pData, &s_iBrkNetSize, &s_BrkNet)) { return FALSE; } return TRUE; } // load the brk net from resources BOOL LoadBrkNetFromResource (HINSTANCE hInst, int nResID, int nType) { BYTE *pData; LOAD_INFO LoadInfo; // init the size to zero, in case we fail s_iBrkNetSize = 0; pData = DoLoadResource (&LoadInfo, hInst, nResID, nType); if (!pData) { return FALSE; } // prepare the net if (!PrepareBrkNet(pData, &s_iBrkNetSize, &s_BrkNet)) { return FALSE; } return TRUE; } // update the lattice by running the BRK-NET on all the possible break points. // Currently only one segmentation survives which is the one suggested by the BRK-NET // returns the number of charcaters in the updated lattice on success, -1 upon failure int UpdateLattice (LATTICE *pLat) { int iPos, iStrk, cStrk, iWinner, cOut, cBrk; BOOL *pIsBreak = NULL; BRKPT *pBrk = NULL; RREAL *pNetMem = NULL, *pNetOut; int iRet = -1, iBrk; // if the net has not been successfully loaded, we'll fail if (s_iBrkNetSize <= 0) { goto exit; } // alloc memory for the Net's running buffer pNetMem = (RREAL *) ExternAlloc (s_iBrkNetSize * sizeof (*pNetMem)); if (!pNetMem) { goto exit; } // create the break pts structure cStrk = pLat->nStrokes; pBrk = CreateBrkPtList (pLat); // if we have succeeded, lets process these break points if (pBrk) { // allocate a boolean struct to mark ON break points pIsBreak = (BOOL *) ExternAlloc (cStrk * sizeof (*pIsBreak)); if (!pIsBreak) { goto exit; } // for all break points for (iStrk = 0, cBrk = 0; iStrk < cStrk; iStrk++) { int iFeat, cFeat, aFeat[MAX_BRK_NET_FEAT]; // featurize for this break point cFeat = FeaturizeBrkPt (pLat, pBrk + iStrk, aFeat); ASSERT (cFeat <= MAX_BRK_NET_FEAT); // prepare the nets input for (iFeat = 0; iFeat < cFeat; iFeat++) { pNetMem[iFeat] = aFeat[iFeat]; } // run the net pNetOut = runLocalConnectNet (&s_BrkNet, pNetMem, &iWinner, &cOut); ASSERT (cOut == 2); // this is considered a hard break point if the net's output is higher than the threshold pIsBreak[iStrk] = pNetOut[1] >= (BREAKING_THRESHOLD); // mark it a as a breakpoint if (pIsBreak[iStrk]) { cBrk++; } // copy the score in the lattice pLat->pAltList[iStrk].iBrkNetScore = pNetOut[1]; } ASSERT (cBrk <= cStrk); // make sure there is a break point always at the end, if (!pIsBreak[cStrk - 1]) { pIsBreak[cStrk - 1] = TRUE; cBrk++; } // clear out all the existing alternate lists at every stroke for (iStrk = 0; iStrk < cStrk; iStrk++) { ClearAltList (pLat->pAltList + iStrk); } // change the lattice to reflect the new segmentation for (iBrk = iStrk = 0; iBrk < cBrk; iBrk++) { iPos = iStrk; // find the next break point while (!pIsBreak[iStrk] && iStrk < cStrk) { iStrk++; } // build the alt list at the the ending stroke with the // current stroke being the starting one //BuildStrokeCountRecogAlts(pLat, iStrk, iStrk - iPos + 1); if (!ProcessLatticeRange (pLat, iPos, iStrk)) { goto exit; } UpdateSegmentations (pLat, iPos, iStrk); iStrk++; } // Mark the best path through the lattice //iRet = FindFullPath (pLat); FixupBackPointers (pLat); } exit: // free the local buffers if had been allocated if (pBrk) { FreeBreaks (cStrk, pBrk); } if (pIsBreak) { ExternFree (pIsBreak); } if (pNetMem) { ExternFree (pNetMem); } return iRet; } void BrkNetUnloadfile (LOAD_INFO *pLoadInfo) { if (s_iBrkNetSize != 0) { DoCloseFile (pLoadInfo); } }