packages feed

concraft 0.5.0 → 0.6.0

raw patch · 6 files changed

+234/−329 lines, 6 filesdep +Chartdep +cmdargsdep +colourdep −crf-chain2-genericdep ~crf-chain1-constraineddep ~sgdnew-component:exe:concraft-analyse-modelPVP ok

version bump matches the API change (PVP)

Dependencies added: Chart, cmdargs, colour, crf-chain2-tiers, data-accessor, logfloat

Dependencies removed: crf-chain2-generic

Dependency ranges changed: crf-chain1-constrained, sgd

API changes (from Hackage documentation)

- NLP.Concraft.Disamb: data CRF a b
+ NLP.Concraft.Disamb: onDiskT :: TrainConf -> Bool
+ NLP.Concraft.Disamb: pruneT :: TrainConf -> Maybe Double
+ NLP.Concraft.Guess: onDiskT :: TrainConf -> Bool
- NLP.Concraft: train :: (Word w, FromJSON w, ToJSON w) => Tagset -> Analyse w Tag -> Int -> TrainConf -> TrainConf -> [SentO w Tag] -> Maybe [SentO w Tag] -> IO Concraft
+ NLP.Concraft: train :: (Word w, FromJSON w, ToJSON w) => Tagset -> Analyse w Tag -> Int -> TrainConf -> TrainConf -> [SentO w Tag] -> [SentO w Tag] -> IO Concraft
- NLP.Concraft.Disamb: TrainConf :: [Tier] -> SchemaConf -> SgdArgs -> TrainConf
+ NLP.Concraft.Disamb: TrainConf :: [Tier] -> SchemaConf -> SgdArgs -> Bool -> Maybe Double -> TrainConf
- NLP.Concraft.Disamb: train :: Word w => TrainConf -> [Sent w Tag] -> Maybe [Sent w Tag] -> IO Disamb
+ NLP.Concraft.Disamb: train :: Word w => TrainConf -> IO [Sent w Tag] -> IO [Sent w Tag] -> IO Disamb
- NLP.Concraft.Guess: TrainConf :: SchemaConf -> SgdArgs -> TrainConf
+ NLP.Concraft.Guess: TrainConf :: SchemaConf -> SgdArgs -> Bool -> TrainConf
- NLP.Concraft.Guess: train :: (Word w, Ord t) => TrainConf -> [Sent w t] -> Maybe [Sent w t] -> IO (Guesser t)
+ NLP.Concraft.Guess: train :: (Word w, Ord t) => TrainConf -> IO [Sent w t] -> IO [Sent w t] -> IO (Guesser t)

Files

concraft.cabal view
@@ -1,5 +1,5 @@ name:               concraft-version:            0.5.0+version:            0.6.0 synopsis:           Morphological disambiguation based on constrained CRFs description:     A morphological disambiguation library based on@@ -15,6 +15,10 @@ homepage:           http://zil.ipipan.waw.pl/Concraft build-type:         Simple +Flag buildAnaTool+    Description: Build model analysis tool+    Default:     False+ library     hs-source-dirs: src @@ -28,11 +32,11 @@       , text-binary >= 0.1 && < 0.2       , vector       , vector-binary-      , crf-chain1-constrained >= 0.1.2 && < 0.2+      , crf-chain1-constrained >= 0.2 && < 0.3       , monad-ox >= 0.3 && < 0.4-      , sgd >= 0.2.2 && < 0.3+      , sgd >= 0.3 && < 0.4       , tagset-positional >= 0.3 && < 0.4-      , crf-chain2-generic >= 0.3 && < 0.4+      , crf-chain2-tiers >= 0.1 && < 0.2       , monad-codec >= 0.2 && < 0.3       , data-lens       , transformers@@ -50,8 +54,7 @@       , NLP.Concraft.Disamb      other-modules:-        NLP.Concraft.Disamb.Tiered-      , NLP.Concraft.Disamb.Positional+        NLP.Concraft.Disamb.Positional       , NLP.Concraft.Morphosyntax.Align       , NLP.Concraft.Format.Temp @@ -61,3 +64,17 @@ source-repository head     type: git     location: https://github.com/kawu/concraft.git++executable concraft-analyse-model+    if flag(buildAnaTool)+        build-depends:+            cmdargs >= 0.10 && < 0.11+          , logfloat+          , Chart+          , data-accessor+          , colour+    else+        buildable: False+    hs-source-dirs: src, tools+    main-is: concraft-analyse-model.hs+    ghc-options: -Wall
src/NLP/Concraft.hs view
@@ -20,7 +20,6 @@ import           Data.Binary (Binary, put, get) import qualified Data.Binary as Binary import           Data.Aeson-import           Data.Maybe (fromJust) import qualified System.IO.Temp as Temp import qualified Data.ByteString.Lazy as BL import qualified Codec.Compression.GZip as GZip@@ -105,27 +104,27 @@     -> G.TrainConf      -- ^ Guessing model training configuration     -> D.TrainConf      -- ^ Disambiguation model training configuration     -> [SentO w P.Tag]  -- ^ Training data-    -> Maybe [SentO w P.Tag]  -- ^ Maybe evaluation data+    -> [SentO w P.Tag]  -- ^ Evaluation data     -> IO Concraft train tagset ana guessNum guessConf disambConf train0 eval0 = do+    Temp.withTempDirectory "." ".tmp" $ \tmpDir -> do+    let temp = withTemp tagset tmpDir+     putStrLn "\n===== Reanalysis ====="     trainR <- reAnaPar tagset ana train0-    evalR  <- case eval0 of-            Just ev -> Just <$> reAnaPar tagset ana ev-            Nothing -> return Nothing-    withTemp tagset "train" trainR $ \trainR'IO -> do-    withTemp' tagset "eval" evalR  $ \evalR'IO  -> do+    evalR  <- reAnaPar tagset ana eval0+    temp "train-reana" trainR $ \trainR'IO -> do+    temp "eval-reana"  evalR  $ \evalR'IO  -> do      putStrLn "\n===== Train guessing model ====="-    guesser <- do-        tr <- trainR'IO-        ev <- evalR'IO-        G.train guessConf tr ev-    trainG <-       map (G.guessSent guessNum guesser)  <$> trainR'IO-    evalG  <- fmap (map (G.guessSent guessNum guesser)) <$> evalR'IO+    guesser <- G.train guessConf trainR'IO evalR'IO+    trainG  <- map (G.guessSent guessNum guesser) <$> trainR'IO+    evalG   <- map (G.guessSent guessNum guesser) <$> evalR'IO+    temp "train-guessed" trainG $ \trainG'IO -> do+    temp "eval-guessed"  evalG  $ \evalG'IO  -> do      putStrLn "\n===== Train disambiguation model ====="-    disamb <- D.train disambConf trainG evalG+    disamb <- D.train disambConf trainG'IO evalG'IO     return $ Concraft tagset guessNum guesser disamb  @@ -140,31 +139,16 @@ withTemp     :: (FromJSON w, ToJSON w)     => P.Tagset+    -> FilePath                     -- ^ Directory to create the file in     -> String                       -- ^ Template for `Temp.withTempFile`     -> [Sent w P.Tag]               -- ^ Input dataset     -> (IO [Sent w P.Tag] -> IO a)  -- ^ Handler     -> IO a-withTemp tagset tmpl xs handler =-    withTemp' tagset tmpl (Just xs) (handler . fmap fromJust)----- | Similar to `withTemp` but on a `Maybe` dataset.------ Store dataset on a disk and run a handler on a list which is read--- lazily from the disk.  A temporary file will be automatically--- deleted after the handler is done.-withTemp'-    :: (FromJSON w, ToJSON w)-    => P.Tagset-    -> String-    -> Maybe [Sent w P.Tag]-    -> (IO (Maybe [Sent w P.Tag]) -> IO a)-    -> IO a-withTemp' tagset tmpl (Just xs) handler =-  Temp.withTempFile "." tmpl $ \tmpPath tmpHandle -> do+withTemp _      _   _    [] handler = handler (return [])+withTemp tagset dir tmpl xs handler =+  Temp.withTempFile dir tmpl $ \tmpPath tmpHandle -> do     hClose tmpHandle     let txtSent = mapSent $ P.showTag tagset         tagSent = mapSent $ P.parseTag tagset     writePar tmpPath $ map txtSent xs-    handler (Just . map tagSent <$> readPar tmpPath)-withTemp' _ _ Nothing handler = handler (return Nothing)+    handler (map tagSent <$> readPar tmpPath)
src/NLP/Concraft/Disamb.hs view
@@ -1,10 +1,10 @@ {-# LANGUAGE RecordWildCards #-} + module NLP.Concraft.Disamb ( -- * Model   Disamb (..)-, Tier.CRF ()   -- * Tiers , P.Tier (..)@@ -20,6 +20,7 @@ , train ) where + import Control.Applicative ((<$>), (<*>)) import Data.Maybe (fromJust) import Data.List (find)@@ -29,18 +30,18 @@ import qualified Data.Vector as V  import qualified Control.Monad.Ox as Ox-import qualified Data.CRF.Chain2.Generic.External as CRF+import qualified Data.CRF.Chain2.Tiers as CRF  import NLP.Concraft.Schema hiding (schematize) import qualified NLP.Concraft.Morphosyntax as X -import qualified NLP.Concraft.Disamb.Tiered as Tier import qualified NLP.Concraft.Disamb.Positional as P import qualified Data.Tagset.Positional as T import qualified Numeric.SGD as SGD + -- | Schematize the input sentence with according to 'schema' rules.-schematize :: Schema w t a -> X.Sent w t -> CRF.Sent Ob t+schematize :: Schema w [t] a -> X.Sent w [t] -> CRF.Sent Ob t schematize schema sent =     [ CRF.mkWord (obs i) (lbs i)     | i <- [0 .. n - 1] ]@@ -51,27 +52,31 @@     lbs i = X.interpsSet w         where w = v V.! i + -- | A disambiguation model. data Disamb = Disamb     { tiers         :: [P.Tier]     , schemaConf    :: SchemaConf-    , crf           :: Tier.CRF Ob P.Atom }+    , crf           :: CRF.CRF Ob P.Atom } + instance Binary Disamb where     put Disamb{..} = put tiers >> put schemaConf >> put crf     get = Disamb <$> get <*> get <*> get + -- | Unsplit the complex tag (assuming, that it is one -- of the interpretations of the word). unSplit :: Eq t => (r -> t) -> X.Seg w r -> t -> r unSplit split' word x = fromJust $ find ((==x) . split') (X.interps word) + -- | Perform context-sensitive disambiguation. disamb :: X.Word w => Disamb -> X.Sent w T.Tag -> [T.Tag] disamb Disamb{..} sent     = map (uncurry embed)     . zip sent-    . Tier.tag crf+    . CRF.tag crf     . schematize schema     . X.mapSent split     $ sent@@ -80,6 +85,7 @@     split   = P.split tiers     embed   = unSplit split + -- | Insert disambiguation results into the sentence. include :: (X.Sent w T.Tag -> [T.Tag]) -> X.Sent w T.Tag -> X.Sent w T.Tag include f sent =@@ -91,42 +97,69 @@         [ (y, if x == y then 1 else 0)         | y <- X.interps word ] + -- | Combine `disamb` with `include`.  disambSent :: X.Word w => Disamb -> X.Sent w T.Tag -> X.Sent w T.Tag disambSent = include . disamb + -- | Training configuration. data TrainConf = TrainConf     { tiersT        :: [P.Tier]     , schemaConfT   :: SchemaConf-    , sgdArgsT      :: SGD.SgdArgs }+    , sgdArgsT      :: SGD.SgdArgs+    , onDiskT       :: Bool+    , pruneT        :: Maybe Double } + -- | Train disamb model. train     :: X.Word w-    => TrainConf                        -- ^ Training configuration-    -> [X.Sent w T.Tag]                 -- ^ Training data-    -> Maybe [X.Sent w T.Tag]           -- ^ Maybe evaluation data-    -> IO Disamb                        -- ^ Resultant model-train TrainConf{..} trainData evalData'Maybe = do-    crf <- Tier.train-        (length tiersT)-        sgdArgsT-        (retSchemed schema split trainData)-        (retSchemed schema split <$> evalData'Maybe)-    return $ Disamb tiersT schemaConfT crf+    => TrainConf                -- ^ Training configuration+    -> IO [X.Sent w T.Tag]      -- ^ Training data+    -> IO [X.Sent w T.Tag]      -- ^ Evaluation data+    -> IO Disamb                -- ^ Resultant model+train TrainConf{..} trainData evalData = do++    -- Train first model+    crf <- CRF.train (length tiersT) CRF.selectHidden sgdArgsT onDiskT+        (schemed schema split <$> trainData)+        (schemed schema split <$> evalData)+    putStr "\nNumber of features: " >> print (CRF.size crf)++    -- Re-train model if prune parameter is Just+    reCrf <- case pruneT of+        Just th -> do +            putStrLn "\n===== Prune and retrain disambiguation model ====="+            crf' <- CRF.reTrain (CRF.prune th crf)+                (gainMul 0.5 sgdArgsT) onDiskT+                (schemed schema split <$> trainData)+                (schemed schema split <$> evalData)+            putStr "\nNumber of features: " >> print (CRF.size crf')+            return crf'+        Nothing -> return crf++    -- Final disamb model+    return $ Disamb tiersT schemaConfT reCrf+   where-    retSchemed sc sp = return . schemed sc sp +     schema = fromConf schemaConfT     split  = P.split tiersT +    -- Muliply gain0 parameter by the given number.+    gainMul x sgdArgs =+        let gain0' = SGD.gain0 sgdArgs * x+        in  sgdArgs { SGD.gain0 = gain0' }++ -- | Schematized data from the plain file.-schemed :: Ord t => Schema w t a -> (T.Tag -> t)+schemed :: Ord t => Schema w [t] a -> (T.Tag -> [t])         -> [X.Sent w T.Tag] -> [CRF.SentL Ob t] schemed schema split =     map onSent   where     onSent sent =         let xs  = map (X.mapSeg split) sent-            mkDist = CRF.mkDist . M.toList . X.unWMap . X.tags-        in  zip (schematize schema xs) (map mkDist xs)+            mkProb = CRF.mkProb . M.toList . X.unWMap . X.tags+        in  zip (schematize schema xs) (map mkProb xs)
− src/NLP/Concraft/Disamb/Tiered.hs
@@ -1,258 +0,0 @@-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE BangPatterns #-}--module NLP.Concraft.Disamb.Tiered-( Ob (..)-, Lb (..)-, Feat (..)-, CRF (..)-, train-, tag-) where--import Control.Applicative ((<$>), (<*>))-import Control.Comonad.Trans.Store (store)-import Control.Monad (guard)-import Data.Ix (Ix, inRange, range)-import Data.Maybe (catMaybes, fromJust)-import Data.List (zip4, foldl1')-import Data.Lens.Common (Lens(..))-import Data.Binary (Binary, get, put, Put, Get)-import Data.Vector.Binary ()-import qualified Data.Map as M-import qualified Data.Vector as V-import qualified Data.Array.Unboxed as A--import Data.CRF.Chain2.Generic.Codec-    ( Codec(..), mkCodec, encodeDataL-    , encodeSent, decodeLabels, unJust )-import Data.CRF.Chain2.Generic.Model-    ( FeatGen(..), Model, selectHidden-    , core, withCore )-import Data.CRF.Chain2.Generic.Internal (FeatIx(..))-import qualified Data.CRF.Chain2.Generic.Inference as I-import qualified Data.CRF.Chain2.Generic.External as E-import qualified Data.CRF.Chain2.Generic.Train as Train-import qualified Data.CRF.Chain2.Generic.FeatMap as F-import qualified Control.Monad.Codec as C-import qualified Numeric.SGD as SGD---- | Observation.-newtype Ob = Ob { unOb :: Int } deriving (Show, Eq, Ord, Ix, Binary)---- | Sublabel.-newtype Lb = Lb { unLb :: Int } deriving (Show, Eq, Ord, Ix, Binary)---- | Feature.-data Feat-    = TFeat3-        { x1    :: {-# UNPACK #-} !Lb-        , x2    :: {-# UNPACK #-} !Lb-        , x3    :: {-# UNPACK #-} !Lb-        , ln    :: {-# UNPACK #-} !Int }-    | TFeat2-        { x1    :: {-# UNPACK #-} !Lb-        , x2    :: {-# UNPACK #-} !Lb-        , ln    :: {-# UNPACK #-} !Int }-    | TFeat1-        { x1    :: {-# UNPACK #-} !Lb-        , ln    :: {-# UNPACK #-} !Int }-    | OFeat-        { ob    :: {-# UNPACK #-} !Ob-        , x1    :: {-# UNPACK #-} !Lb-        , ln    :: {-# UNPACK #-} !Int }-    deriving (Show, Eq, Ord)--instance Binary Feat where-    put (OFeat o x k)       = putI 0 >> put o >> put x >> put k-    put (TFeat3 x y z k)    = putI 1 >> put x >> put y >> put z >> put k-    put (TFeat2 x y k)      = putI 2 >> put x >> put y >> put k-    put (TFeat1 x k)        = putI 3 >> put x >> put k-    get = getI >>= \i -> case i of-        0   -> OFeat  <$> get <*> get <*> get-        1   -> TFeat3 <$> get <*> get <*> get <*> get-        2   -> TFeat2 <$> get <*> get <*> get-        3   -> TFeat1 <$> get <*> get-        _   -> error "get feature: unknown code"--putI :: Int -> Put-putI = put-{-# INLINE putI #-}--getI :: Get Int-getI = get-{-# INLINE getI #-}---- | Feature generation for complex [Lb] label type.-featGen :: FeatGen Ob [Lb] Feat-featGen = FeatGen-    { obFeats   = obFeats'-    , trFeats1  = trFeats1'-    , trFeats2  = trFeats2'-    , trFeats3  = trFeats3' }-  where-    obFeats' ob' xs =-        [ OFeat ob' x k-        | (x, k) <- zip xs [0..] ]-    trFeats1' xs =-        [ TFeat1 x k-        | (x, k) <- zip xs [0..] ]-    trFeats2' xs1 xs2 =-        [ TFeat2 x1' x2' k-        | (x1', x2', k) <--          zip3 xs1 xs2 [0..] ]-    trFeats3' xs1 xs2 xs3 =-        [ TFeat3 x1' x2' x3' k-        | (x1', x2', x3', k) <--          zip4 xs1 xs2 xs3 [0..] ]---- | Codec internal data.  The first component is used to--- encode observations of type a, the second one is used to--- encode labels of type [b].-type CodecData a b =-    ( C.AtomCodec a-    , V.Vector (C.AtomCodec (Maybe b)) )--obLens :: Lens (a, b) a-obLens = Lens $ \(a, b) -> store (\a' -> (a', b)) a--lbLens :: Int -> Lens (a, V.Vector b) b-lbLens k = Lens $ \(a, b) -> store-    (\x -> (a, b V.// [(k, x)]))-    (b V.! k)---- | Codec dependes on the number of layers. -codec :: (Ord a, Ord b) => Int -> Codec a [b] (CodecData a b) Ob [Lb]-codec n = Codec-    { empty =-        let x = C.execCodec C.empty (C.encode C.idLens Nothing)-        in  (C.empty, V.replicate n x)-    , encodeObU = fmap Ob . C.encode' obLens-    , encodeObN = fmap (fmap Ob) . C.maybeEncode obLens-    , encodeLbU = \ xs -> sequence-        [ Lb <$> C.encode (lbLens k) (Just x)-        | (x, k) <- zip xs [0..] ]-    , encodeLbN = \ xs ->-        let encode lens x = C.maybeEncode lens (Just x) >>= \mx -> case mx of-                Just x' -> return x'-                Nothing -> fromJust <$> C.maybeEncode lens Nothing-        in  sequence-                [ Lb <$> encode (lbLens k) x-                | (x, k) <- zip xs [0..] ]-    , decodeLbC = \ xs -> sequence <$> sequence-        [ C.decode (lbLens k) (unLb x)-        | (x, k) <- zip xs [0..] ]-    , hasLabel = \ cdcData xs -> and-        [ M.member-            (Just x)-            (C.to $ snd cdcData V.! k)-        | (x, k) <- zip xs [0..] ] }---- | Dummy feature index.-dummy :: FeatIx-dummy = FeatIx (-1)-{-# INLINE dummy #-}---- | Transition map restricted to a particular tagging layer.-type TransMap = A.UArray (Lb, Lb, Lb) FeatIx---- | CRF feature map.-data FeatMap a = FeatMap-    { transMaps	:: V.Vector TransMap-    , otherMap 	:: M.Map Feat FeatIx }--instance Binary (FeatMap Feat) where-    put FeatMap{..} = put transMaps >> put otherMap-    get = FeatMap <$> get <*> get--instance F.FeatMap FeatMap Feat where-    featIndex (TFeat3 x y z k) (FeatMap v _) = do-        m  <- v V.!? k-        ix <- m !? (x, y, z)-        guard (ix /= dummy)-        return ix-    featIndex x (FeatMap _ m) = M.lookup x m-    mkFeatMap xs = FeatMap-        ( V.fromList-            [ mkArray . catMaybes $-                map (getTFeat3 k) xs-            | k <- [0 .. maxLayerNum xs] ] )-        (M.fromList (filter (isOther . fst) xs))-      where-        maxLayerNum = maximum . map (ln.fst)-        getTFeat3 i (TFeat3 x y z j, v)-            | i == j                = Just ((x, y, z), v)-            | otherwise             = Nothing-        getTFeat3 _ _               = Nothing-        isOther (TFeat3 _ _ _ _)    = False-        isOther _                   = True-        mkArray ys =-            let p = foldl1' updateMin (map fst ys)-                q = foldl1' updateMax (map fst ys)-                updateMin (!x, !y, !z) (x', y', z') =-                    (min x x', min y y', min z z')-                updateMax (!x, !y, !z) (x', y', z') =-                    (max x x', max y y', max z z')-                zeroed pq = A.array pq [(k, dummy) | k <- range pq]-            in  zeroed (p, q) A.// ys--(!?) :: (Ix i, A.IArray a b) => a i b -> i -> Maybe b-m !? x = if inRange (A.bounds m) x-    then Just (m A.! x)-    else Nothing-{-# INLINE (!?) #-}---- | CRF model data.-data CRF a b = CRF-    { numOfLayers   :: Int-    , codecData     :: CodecData a b-    , model         :: Model FeatMap Ob [Lb] Feat }--instance (Ord a, Ord b, Binary a, Binary b) => Binary (CRF a b) where-    put CRF{..} = put numOfLayers >> put codecData >> put (core model)-    get = CRF <$> get <*> get <*> do-        _core <- get-        return $ withCore _core featGen---- | Codec specification given the number of layers.-codecSpec-    :: (Ord a, Ord b) => Int-    -> Train.CodecSpec a [b] (CodecData a b) Ob [Lb]-codecSpec n = Train.CodecSpec-    { Train.mkCodec = mkCodec (codec n)-    , Train.encode  = encodeDataL (codec n) }---- | Train the CRF using the stochastic gradient descent method.--- Use the provided feature selection function to determine model--- features.-train-    :: (Ord o, Ord t)-    => Int                          -- ^ Number of tagging layers-    -> SGD.SgdArgs                  -- ^ Args for SGD-    -> IO [E.SentL o [t]]           -- ^ Training data 'IO' action-    -> Maybe (IO [E.SentL o [t]])   -- ^ Maybe evalation data-    -> IO (CRF o t)                 -- ^ Resulting model-train n sgdArgs trainIO evalIO'Maybe = do-    (_codecData, _model) <- Train.train-        sgdArgs-        (codecSpec n)-        featGen-        selectHidden-        trainIO-        evalIO'Maybe-    return $ CRF n _codecData _model---- | Find the most probable label sequence.-tag :: (Ord o, Ord t) => CRF o t -> E.Sent o [t] -> [[t]]-tag CRF{..} sent-    = onWords . decodeLabels cdc codecData-    . I.tag model . encodeSent cdc codecData-    $ sent-  where-    cdc = codec numOfLayers-    onWords xs =-        [ unJust cdc codecData word x-        | (word, x) <- zip sent xs ]
src/NLP/Concraft/Guess.hs view
@@ -84,26 +84,27 @@ -- | Training configuration. data TrainConf = TrainConf     { schemaConfT   :: SchemaConf-    , sgdArgsT      :: SGD.SgdArgs }+    , sgdArgsT      :: SGD.SgdArgs+    -- | Store SGD dataset on disk.+    , onDiskT       :: Bool }  -- | Train guesser. train     :: (X.Word w, Ord t)     => TrainConf            -- ^ Training configuration-    -> [X.Sent w t]         -- ^ Training data-    -> Maybe [X.Sent w t]   -- ^ Maybe evaluation data+    -> IO [X.Sent w t]      -- ^ Training data+    -> IO [X.Sent w t]      -- ^ Evaluation data     -> IO (Guesser t)-train TrainConf{..} trainData evalData'Maybe = do+train TrainConf{..} trainData evalData = do     let schema = fromConf schemaConfT-    crf <- CRF.train sgdArgsT-        (retSchemed schema trainData)-        (retSchemed schema <$> evalData'Maybe)+    crf <- CRF.train sgdArgsT onDiskT+        (schemed schema <$> trainData)+        (schemed schema <$> evalData)         (const CRF.presentFeats)     return $ Guesser schemaConfT crf   where-    retSchemed schema = return . schemed schema --- | Schematized data from the plain file.+-- | Schematized dataset. schemed :: (X.Word w, Ord t) => Schema w t a         -> [X.Sent w t] -> [CRF.SentL Ob t] schemed schema =
+ tools/concraft-analyse-model.hs view
@@ -0,0 +1,128 @@+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE RecordWildCards #-}++import           Control.Applicative ((<$>))+import           Control.Arrow (second)+import           Control.Monad (void)+import           System.Console.CmdArgs+import           Data.List (foldl')+import qualified Data.Map as M+import qualified Data.Number.LogFloat as L++import           Data.Colour.Names+import           Data.Colour+import           Data.Accessor+import           Graphics.Rendering.Chart++import qualified Data.CRF.Chain2.Tiers.Model as CRF+import qualified Data.CRF.Chain2.Tiers.Feature as CRF+import qualified Data.CRF.Chain2.Tiers as CRF++import qualified NLP.Concraft as C+import qualified NLP.Concraft.Disamb as D+++---------------------------------------+-- Histogram+---------------------------------------+++-- | Round double value.+roundTo :: Int -> Double -> Double+roundTo n x = (fromInteger $ round $ x * (10^n)) / (10.0^^n)+++-- | Make a histogram with a given precision.+hist :: Ord a => [a] -> M.Map a Int+hist =+    let update m x = M.insertWith' (+) x 1 m+    in  foldl' update M.empty+++---------------------------------------+-- Rendering+---------------------------------------+++drawModel :: Int -> CRF.Model -> FilePath -> IO ()+drawModel rnParam model filePath = do++    void $ renderableToPNGFile (toRenderable layout) 640 480 filePath++  where++    -- Feature map with values in log domain+    featMap = L.logFromLogFloat <$> CRF.toMap model++    -- Values assigned to observation features+    obVals = [x | (ft, x) <- M.assocs featMap, isOFeat ft]++    -- Values assigned to transition features+    trVals = [x | (ft, x) <- M.assocs featMap, not (isOFeat ft)]++    -- Is it an observation feature?+    isOFeat (CRF.OFeat _ _ _) = True+    isOFeat _                 = False++    -- Make log-domain histogram+    mkHist = map (second intLog) . M.toList . hist . map (roundTo rnParam)++    obChart =+          plot_lines_style .> line_color ^= opaque blue+        $ plot_lines_values ^= [mkHist obVals]+        $ plot_lines_title ^= "Observation features"+        $ defaultPlotLines++    trChart =+          plot_lines_style .> line_color ^= opaque green+        $ plot_lines_values ^= [mkHist trVals]+        $ plot_lines_title ^= "Transition features"+        $ defaultPlotLines++    layout =+          layout1_left_axis ^: laxis_override ^= axisGridHide+        $ layout1_right_axis ^: laxis_override ^= axisGridHide+        $ layout1_bottom_axis ^: laxis_override ^= axisGridHide+        $ layout1_plots ^= [Left (toPlot obChart), Right (toPlot trChart)]+        $ layout1_grid_last ^= False+        $ defaultLayout1+++-- | Int logarithm.+intLog :: Int -> Double+intLog = (log :: Double -> Double) . fromIntegral+++---------------------------------------+-- Command line options+---------------------------------------+++data AnaModel = AnaModel+    { inModel   :: FilePath+    , outFile   :: FilePath+    , rnParam   :: Int }+    deriving (Data, Typeable, Show)+++anaModel :: AnaModel+anaModel = AnaModel+    { inModel = def &= argPos 0 &= typ "MODEL-FILE"+    , outFile = def &= argPos 1 &= typ "OUTPUT-FILE"+    , rnParam = 1 &= help "Rounding parameter" }+++---------------------------------------+-- Main+---------------------------------------+++main :: IO ()+main = exec =<< cmdArgs anaModel+++exec :: AnaModel -> IO ()+exec AnaModel{..} = do+    model <- CRF.model . D.crf . C.disamb <$> C.loadModel inModel+    drawModel rnParam model outFile