Add option to mark worst features

This commit is contained in:
Filip Gralinski 2020-01-30 23:04:36 +01:00
parent 15946b89db
commit 8761965e8e
5 changed files with 152 additions and 20 deletions

View File

@ -108,6 +108,8 @@ library
, singletons , singletons
, ordered-containers , ordered-containers
, random , random
, rainbow
, hpqtypes
default-language: Haskell2010 default-language: Haskell2010
executable geval executable geval

View File

@ -195,7 +195,7 @@ getExpectedDirectory spec = fromMaybe outDirectory $ gesExpectedDirectory spec
-- | Special command, not just running the regular evaluation. -- | Special command, not just running the regular evaluation.
-- See OptionsParser.hs for more information. -- See OptionsParser.hs for more information.
data GEvalSpecialCommand = Init data GEvalSpecialCommand = Init
| LineByLine | WorstFeatures | LineByLine | LineByLineWithWorstFeatures | WorstFeatures
| Diff FilePath | MostWorseningFeatures FilePath | Diff FilePath | MostWorseningFeatures FilePath
| PrintVersion | JustTokenize | Submit | PrintVersion | JustTokenize | Submit
| Validate | ListMetrics | Validate | ListMetrics
@ -209,7 +209,8 @@ data GEvalOptions = GEvalOptions
geoFilter :: Maybe String, geoFilter :: Maybe String,
geoSpec :: GEvalSpecification, geoSpec :: GEvalSpecification,
geoBlackBoxDebugginsOptions :: BlackBoxDebuggingOptions, geoBlackBoxDebugginsOptions :: BlackBoxDebuggingOptions,
geoGraphFile :: Maybe FilePath } geoGraphFile :: Maybe FilePath,
geoMarkWorstFeatures :: Bool }
defaultGEvalSpecification = GEvalSpecification { defaultGEvalSpecification = GEvalSpecification {

View File

@ -19,6 +19,7 @@ module GEval.FeatureExtractor
FeatureNamespace(..), FeatureNamespace(..),
References(..), References(..),
ReferencesData(..), ReferencesData(..),
toTextualContent,
filterExistentialFactors) filterExistentialFactors)
where where
@ -223,3 +224,21 @@ filterExistentialFactors :: [PeggedFactor] -> [PeggedExistentialFactor]
filterExistentialFactors factors = catMaybes $ Prelude.map toExistential factors filterExistentialFactors factors = catMaybes $ Prelude.map toExistential factors
where toExistential (PeggedFactor namespace (SimpleExistentialFactor factor)) = Just $ PeggedExistentialFactor namespace factor where toExistential (PeggedFactor namespace (SimpleExistentialFactor factor)) = Just $ PeggedExistentialFactor namespace factor
toExistential _ = Nothing toExistential _ = Nothing
class WithTextualContent a where
toTextualContent :: a -> Maybe Text
instance WithTextualContent PeggedFactor where
toTextualContent (PeggedFactor _ factor) = toTextualContent factor
instance WithTextualContent SimpleFactor where
toTextualContent (SimpleExistentialFactor eFactor) = toTextualContent eFactor
toTextualContent (NumericalFactor _ _) = Nothing
instance WithTextualContent ExistentialFactor where
toTextualContent (SimpleAtomicFactor aFactor) = toTextualContent aFactor
toTextualContent (BigramFactor _ _) = Nothing
instance WithTextualContent AtomicFactor where
toTextualContent (TextFactor t) = Just t
toTextualContent (ShapeFactor _) = Nothing

View File

@ -9,6 +9,7 @@
module GEval.LineByLine module GEval.LineByLine
(runLineByLine, (runLineByLine,
runLineByLineWithWorstFeatures,
runWorstFeatures, runWorstFeatures,
runLineByLineGeneralized, runLineByLineGeneralized,
runDiff, runDiff,
@ -26,6 +27,8 @@ import GEval.Common
import GEval.EvaluationScheme import GEval.EvaluationScheme
import Text.Tokenizer import Text.Tokenizer
import System.IO
import Data.Conduit.AutoDecompress (doNothing) import Data.Conduit.AutoDecompress (doNothing)
import Data.Conduit import Data.Conduit
@ -35,12 +38,12 @@ import qualified Data.Conduit.Text as CT
import Data.Text import Data.Text
import Data.Text.Encoding import Data.Text.Encoding
import Data.Conduit.Rank import Data.Conduit.Rank
import Data.Maybe (fromMaybe) import Data.Maybe (fromMaybe, catMaybes)
import Data.Either (rights) import Data.Either (rights)
import qualified Data.Vector as V import qualified Data.Vector as V
import Data.List (sortBy, sortOn, sort, concat, maximumBy) import Data.List (sortBy, sortOn, sort, concat, maximumBy, intersperse)
import Control.Monad.IO.Class import Control.Monad.IO.Class
import Control.Monad.Trans.Resource import Control.Monad.Trans.Resource
@ -48,6 +51,7 @@ import Data.Conduit.Lift
import Control.Monad.State.Strict import Control.Monad.State.Strict
import Data.Monoid ((<>)) import Data.Monoid ((<>))
import Data.Monoid.Utils (mintercalate)
import GEval.FeatureExtractor import GEval.FeatureExtractor
import GEval.BlackBoxDebugging import GEval.BlackBoxDebugging
@ -71,6 +75,8 @@ import qualified Data.HashMap.Strict as H
import qualified Data.Map.Strict as M import qualified Data.Map.Strict as M
import qualified Data.Set as S import qualified Data.Set as S
import Rainbow (Chunk, (&), magenta, cyan, fore, bold, yellow, brightYellow, red, brightRed, chunk, chunksToByteStrings, byteStringMakerFromEnvironment, byteStringMakerFromHandle, ByteString)
data LineRecord = LineRecord Text Text Text Word32 MetricValue data LineRecord = LineRecord Text Text Text Word32 MetricValue
deriving (Eq, Show) deriving (Eq, Show)
@ -99,7 +105,103 @@ runLineByLine ordering featureFilter spec bbdo = runLineByLineGeneralized orderi
formatScore :: MetricValue -> Text formatScore :: MetricValue -> Text
formatScore = Data.Text.pack . printf "%f" formatScore = Data.Text.pack . printf "%f"
runFeatureFilter :: (Monad m, FeatureSource s) => Maybe String -> GEvalSpecification -> BlackBoxDebuggingOptions -> Maybe References -> ConduitT s s m () data LineSpan = UnmarkedSpan Text | MarkedSpan Double Text
deriving (Eq, Show)
runLineByLineWithWorstFeatures :: ResultOrdering -> Maybe String -> GEvalSpecification -> BlackBoxDebuggingOptions -> IO ()
runLineByLineWithWorstFeatures ordering featureFilter spec bbdo = do
maker <- byteStringMakerFromEnvironment
let consum = CL.map (recordToBytes maker) .| CC.unlinesAscii .| CC.stdout
runLineByLineWithWorstFeaturesGeneralized ordering featureFilter spec bbdo consum
recordToBytes :: (Chunk Text -> [ByteString] -> [ByteString]) -> SpanLineRecord -> ByteString
recordToBytes maker (SpanLineRecord inSpans expSpans outSpans score) =
mintercalate "\t" [lineToBytes maker inSpans,
lineToBytes maker expSpans,
lineToBytes maker outSpans,
encodeUtf8 $ formatScore score]
where formatScore :: MetricValue -> Text
formatScore = Data.Text.pack . printf "%f"
lineToBytes :: (Chunk Text -> [ByteString] -> [ByteString]) -> [LineSpan] -> ByteString
lineToBytes maker spans =
mconcat
$ chunksToByteStrings maker
$ Data.List.intersperse (chunk " ")
$ Prelude.map spanToRainbowChunk $ spans
spanToRainbowChunk :: LineSpan -> Chunk Text
spanToRainbowChunk (UnmarkedSpan t) = chunk t
spanToRainbowChunk (MarkedSpan p t) = markedChunk p c
where c = chunk t
markedChunk :: Double -> Chunk Text -> Chunk Text
markedChunk pValue c
| pValue < 0.000000000000001 = bold c & fore brightRed
| pValue < 0.000000000001 = c & fore red
| pValue < 0.000001 = c & fore magenta
| pValue < 0.001 = bold c
| otherwise = c
markBadFeatures :: (M.Map PeggedFactor Double) -> (Maybe Tokenizer) -> BlackBoxDebuggingOptions -> Text -> Text -> [LineSpan]
markBadFeatures worstFeaturesMap mTokenizer bbdo field line =
catMaybes
$ Prelude.map (featureToLineSpan worstFeaturesMap)
$ extractFactors mTokenizer bbdo Nothing field line
markBadFeaturesInTabbed :: (M.Map PeggedFactor Double) -> (Maybe Tokenizer) -> BlackBoxDebuggingOptions -> Text -> Text -> [LineSpan]
markBadFeaturesInTabbed worstFeaturesMap mTokenizer bbdo field line =
catMaybes
$ Prelude.map (featureToLineSpan worstFeaturesMap)
$ extractFactorsFromTabbed mTokenizer bbdo Nothing field line
doMarking worstFeaturesMap mTokenizer bbdo (LineRecord inpLine expLine outLine _ score) =
SpanLineRecord (markBadFeaturesInTabbed worstFeaturesMap mTokenizer bbdo "in" inpLine)
(markBadFeatures worstFeaturesMap mTokenizer bbdo "exp" expLine)
(markBadFeatures worstFeaturesMap mTokenizer bbdo "out" outLine)
score
featureToLineSpan :: (M.Map PeggedFactor Double) -> PeggedFactor -> Maybe LineSpan
featureToLineSpan worstFeaturesMap pf = featureToLineSpan' (M.lookup pf worstFeaturesMap) pf
where featureToLineSpan' Nothing pf = UnmarkedSpan <$> toTextualContent pf
featureToLineSpan' (Just pValue) pf = MarkedSpan pValue <$> toTextualContent pf
data SpanLineRecord = SpanLineRecord [LineSpan] [LineSpan] [LineSpan] MetricValue
deriving (Eq, Show)
runLineByLineWithWorstFeaturesGeneralized :: ResultOrdering
-> Maybe String
-> GEvalSpecification
-> BlackBoxDebuggingOptions
-> ConduitT SpanLineRecord Void (ResourceT IO) r
-> IO r
runLineByLineWithWorstFeaturesGeneralized ordering featureFilter spec bbdo consum = do
hPutStrLn stderr "Looking for worst features..."
worstFeatures <- runLineByLineGeneralized ordering' spec (\mReferences -> worstFeaturesPipeline False spec bbdo mReferences (CL.take 100))
let worstFeaturesMap = M.fromList
$ catMaybes
$ Prelude.map featureToFactor
$ Prelude.map (\(FeatureWithPValue feature pValue _ _) -> (feature, pValue)) worstFeatures
runLineByLineGeneralized ordering spec (consum' worstFeaturesMap)
where consum' worstFeaturesMap = (\mReferences -> (runFeatureFilter featureFilter spec bbdo mReferences
.| CL.map (doMarking worstFeaturesMap mTokenizer bbdo)
.| consum))
ordering' = forceSomeOrdering ordering
mTokenizer = gesTokenizer spec
featureToFactor :: (Feature, Double) -> Maybe (PeggedFactor, Double)
featureToFactor ((UnaryFeature (PeggedExistentialFactor namespace (SimpleAtomicFactor factor))), p) =
Just (PeggedFactor namespace (SimpleExistentialFactor (SimpleAtomicFactor factor)), p)
featureToFactor _ = Nothing
runFeatureFilter :: (Monad m, FeatureSource s) => Maybe String
-> GEvalSpecification
-> BlackBoxDebuggingOptions
-> Maybe References
-> ConduitT s s m ()
runFeatureFilter Nothing _ _ _ = doNothing runFeatureFilter Nothing _ _ _ = doNothing
runFeatureFilter (Just feature) spec bbdo mReferences = CC.map (\l -> (fakeRank, l)) runFeatureFilter (Just feature) spec bbdo mReferences = CC.map (\l -> (fakeRank, l))
.| featureExtractor mTokenizer bbdo mReferences .| featureExtractor mTokenizer bbdo mReferences
@ -121,8 +223,8 @@ worstFeaturesPipeline :: Bool
-> GEvalSpecification -> GEvalSpecification
-> BlackBoxDebuggingOptions -> BlackBoxDebuggingOptions
-> Maybe References -> Maybe References
-> ConduitT FeatureWithPValue Void (ResourceT IO) () -> ConduitT FeatureWithPValue Void (ResourceT IO) a
-> ConduitT LineRecord Void (ResourceT IO) () -> ConduitT LineRecord Void (ResourceT IO) a
worstFeaturesPipeline reversed spec bbdo mReferences consum = rank (lessByMetric reversed $ gesMainMetric spec) worstFeaturesPipeline reversed spec bbdo mReferences consum = rank (lessByMetric reversed $ gesMainMetric spec)
.| evalStateC 0 (extractFeaturesAndPValues spec bbdo mReferences) .| evalStateC 0 (extractFeaturesAndPValues spec bbdo mReferences)
.| CC.filter (\(FeatureWithPValue _ p _ _) -> not $ isNaN p) -- NaN values would poison sorting .| CC.filter (\(FeatureWithPValue _ p _ _) -> not $ isNaN p) -- NaN values would poison sorting

View File

@ -121,6 +121,10 @@ optionsParser = GEvalOptions
( long "plot-graph" ( long "plot-graph"
<> metavar "FILE-PATH" <> metavar "FILE-PATH"
<> help "Plot an extra graph, applicable only for Probabilistic-MultiLabel/Soft-F-score (LOESS function for calibration)")) <> help "Plot an extra graph, applicable only for Probabilistic-MultiLabel/Soft-F-score (LOESS function for calibration)"))
<*> switch
( long "mark-worst-features"
<> help "Mark worst features when in the line-by-line mode")
precisionArgParser :: Parser Int precisionArgParser :: Parser Int
precisionArgParser = option auto precisionArgParser = option auto
@ -322,6 +326,7 @@ runGEval'' opts = runGEval''' (geoSpecialCommand opts)
(geoSpec opts) (geoSpec opts)
(geoBlackBoxDebugginsOptions opts) (geoBlackBoxDebugginsOptions opts)
(geoGraphFile opts) (geoGraphFile opts)
(geoMarkWorstFeatures opts)
runGEval''' :: Maybe GEvalSpecialCommand runGEval''' :: Maybe GEvalSpecialCommand
-> ResultOrdering -> ResultOrdering
@ -329,8 +334,9 @@ runGEval''' :: Maybe GEvalSpecialCommand
-> GEvalSpecification -> GEvalSpecification
-> BlackBoxDebuggingOptions -> BlackBoxDebuggingOptions
-> Maybe FilePath -> Maybe FilePath
-> Bool
-> IO (Maybe [(SourceSpec, [MetricResult])]) -> IO (Maybe [(SourceSpec, [MetricResult])])
runGEval''' Nothing _ _ spec _ mGraphFile = do runGEval''' Nothing _ _ spec _ mGraphFile _ = do
vals' <- geval spec vals' <- geval spec
let vals = map (\(s, val) -> (s, map getMetricValue val)) vals' let vals = map (\(s, val) -> (s, map getMetricValue val)) vals'
case mGraphFile of case mGraphFile of
@ -339,37 +345,39 @@ runGEval''' Nothing _ _ spec _ mGraphFile = do
mapM_ (\(ix, d) -> (plotGraph (getGraphFilename ix graphFile) d)) $ zip [0..] graphsData mapM_ (\(ix, d) -> (plotGraph (getGraphFilename ix graphFile) d)) $ zip [0..] graphsData
Nothing -> return () Nothing -> return ()
return $ Just vals return $ Just vals
runGEval''' (Just Init) _ _ spec _ _ = do runGEval''' (Just Init) _ _ spec _ _ _ = do
initChallenge spec initChallenge spec
return Nothing return Nothing
runGEval''' (Just PrintVersion) _ _ _ _ _ = do runGEval''' (Just PrintVersion) _ _ _ _ _ _ = do
putStrLn ("geval " ++ showVersion version) putStrLn ("geval " ++ showVersion version)
return Nothing return Nothing
runGEval''' (Just LineByLine) ordering featureFilter spec bbdo _ = do runGEval''' (Just LineByLine) ordering featureFilter spec bbdo _ markWorstFeatures = do
runLineByLine ordering featureFilter spec bbdo if markWorstFeatures
then runLineByLineWithWorstFeatures ordering featureFilter spec bbdo
else runLineByLine ordering featureFilter spec bbdo
return Nothing return Nothing
runGEval''' (Just WorstFeatures) ordering _ spec bbdo _ = do runGEval''' (Just WorstFeatures) ordering _ spec bbdo _ _ = do
runWorstFeatures ordering spec bbdo runWorstFeatures ordering spec bbdo
return Nothing return Nothing
runGEval''' (Just (Diff otherOut)) ordering featureFilter spec bbdo _ = do runGEval''' (Just (Diff otherOut)) ordering featureFilter spec bbdo _ _ = do
runDiff ordering featureFilter otherOut spec bbdo runDiff ordering featureFilter otherOut spec bbdo
return Nothing return Nothing
runGEval''' (Just (MostWorseningFeatures otherOut)) ordering _ spec bbdo _ = do runGEval''' (Just (MostWorseningFeatures otherOut)) ordering _ spec bbdo _ _ = do
runMostWorseningFeatures ordering otherOut spec bbdo runMostWorseningFeatures ordering otherOut spec bbdo
return Nothing return Nothing
runGEval''' (Just JustTokenize) _ _ spec _ _ = do runGEval''' (Just JustTokenize) _ _ spec _ _ _ = do
justTokenize (gesTokenizer spec) justTokenize (gesTokenizer spec)
return Nothing return Nothing
runGEval''' (Just Submit) _ _ spec _ _ = do runGEval''' (Just Submit) _ _ spec _ _ _ = do
submit (gesGonitoHost spec) (gesToken spec) (gesGonitoGitAnnexRemote spec) submit (gesGonitoHost spec) (gesToken spec) (gesGonitoGitAnnexRemote spec)
return Nothing return Nothing
runGEval''' (Just Validate) _ _ spec _ _ = do runGEval''' (Just Validate) _ _ spec _ _ _ = do
validateChallenge spec validateChallenge spec
return Nothing return Nothing
runGEval''' (Just ListMetrics) _ _ _ _ _ = do runGEval''' (Just ListMetrics) _ _ _ _ _ _ = do
listMetrics listMetrics
return Nothing return Nothing
runGEval''' (Just OracleItemBased) _ _ spec _ _ = do runGEval''' (Just OracleItemBased) _ _ spec _ _ _ = do
runOracleItemBased spec runOracleItemBased spec
return Nothing return Nothing