Repository: hplt-project/OpusTrainer (language: python)

Issue:
Add nonsense to forced decoding filter
Extend the PlaceholderTagModifier to generate examples that teach the model to force-decode to some random string, so the model learns to force-decode to unexpected input (and copy it as-is)
Add noise filter
placeholder for until i get around to implement it.

In order to simulate  random noise on the source and target side, and encourage our byte_fallback vocabulary to pick it up, we should just corrupt the input with random strings on the source and the target. We can use the alignment information in order to give it a believable corresponding location.


Discussion / hints:

Fix patch:
diff --git a/src/opustrainer/modifiers/placeholders.py b/src/opustrainer/modifiers/placeholders.py
index 25af09c..5950415 100644
--- a/src/opustrainer/modifiers/placeholders.py
+++ b/src/opustrainer/modifiers/placeholders.py
@@ -1,6 +1,6 @@
 import random
 from operator import itemgetter
-from typing import Set, List, Tuple, Optional, Protocol
+from typing import Set, List, Tuple, Optional, Protocol, TypeVar, Iterable
 from warnings import warn
 
 from sacremoses import MosesDetokenizer
@@ -8,6 +8,165 @@
 from opustrainer.modifiers import Modifier
 
 
+T = TypeVar('T')
+
+def random_weighted_choice(options:Iterable[Tuple[T,float]]) -> T:
+    choice = random.random()
+    cumsum = 0
+    for option, prob in options:
+        cumsum += prob
+        if choice < cumsum:
+            return option
+    raise RuntimeError('random_weighted_choice called with cumulative sum smaller than 1.0')
+
+
+
+def get_random_unicode_string(min_length: int=1, max_length: int=4, max_words: int=3) -> str:
+    """Gets a random unicode string of words, of up to max_words, where each word is of length
+    min_length-max_length. Only one character set per invocation.
+    Maybe should do special rules for emoji and CJK? Emoji wouldn't appear with spaces in between normally
+    and CJK would normally be of maximum length of 3 per word."""
+
+    length: int = random.randint(min_length, max_length)
+
+    # Update this to include code point ranges to be sampled
+    # https://jrgraphix.net/r/Unicode/
+    # https://en.wikipedia.org/wiki/Unicode_block
+    include_ranges = [
+        (0x0020, 0x007F), # Basic Latin
+        (0x00A0, 0x00FF), # Latin-1 Supplement
+       # (0x0100, 0x017F), # Latin Extended-A
+       # (0x0180, 0x024F), # Latin Extended-B
+       # (0x0250, 0x02AF), # IPA Extensions
+       # (0x02B0, 0x02FF), # Spacing Modifier Letters
+       # (0x0300, 0x036F), # Combining Diacritical Marks
+        (0x0370, 0x03FF), # Greek and Coptic
+        (0x0400, 0x04FF), # Cyrillic
+       # (0x0500, 0x052F), # Cyrillic Supplementary
+        (0x0530, 0x058F), # Armenian
+        (0x0590, 0x05FF), # Hebrew
+        (0x0600, 0x06FF), # Arabic
+       # (0x0700, 0x074F), # Syriac
+       # (0x0780, 0x07BF), # Thaana
+        (0x0900, 0x097F), # Devanagari
+        (0x0980, 0x09FF), # Bengali
+       # (0x0A00, 0x0A7F), # Gurmukhi
+        (0x0A80, 0x0AFF), # Gujarati
+       # (0x0B00, 0x0B7F), # Oriya
+       # (0x0B80, 0x0BFF), # Tamil
+       # (0x0C00, 0x0C7F), # Telugu
+       # (0x0C80, 0x0CFF), # Kannada
+       # (0x0D00, 0x0D7F), # Malayalam
+       # (0x0D80, 0x0DFF), # Sinhala
+        (0x0E00, 0x0E7F), # Thai
+       # (0x0E80, 0x0EFF), # Lao
+       # (0x0F00, 0x0FFF), # Tibetan
+        (0x1000, 0x109F), # Myanmar
+        (0x10A0, 0x10FF), # Georgian
+       # (0x1100, 0x11FF), # Hangul Jamo
+       # (0x1200, 0x137F), # Ethiopic
+       # (0x13A0, 0x13FF), # Cherokee
+       # (0x1400, 0x167F), # Unified Canadian Aboriginal Syllabics
+       # (0x1680, 0x169F), # Ogham
+       # (0x16A0, 0x16FF), # Runic
+       # (0x1700, 0x171F), # Tagalog
+       # (0x1720, 0x173F), # Hanunoo
+       # (0x1740, 0x175F), # Buhid
+       # (0x1760, 0x177F), # Tagbanwa
+        (0x1780, 0x17FF), # Khmer
+       # (0x1800, 0x18AF), # Mongolian
+       # (0x1900, 0x194F), # Limbu
+       # (0x1950, 0x197F), # Tai Le
+       # (0x19E0, 0x19FF), # Khmer Symbols
+       # (0x1D00, 0x1D7F), # Phonetic Extensions
+       # (0x1E00, 0x1EFF), # Latin Extended Additional
+       # (0x1F00, 0x1FFF), # Greek Extended
+       # (0x2000, 0x206F), # General Punctuation
+       # (0x2070, 0x209F), # Superscripts and Subscripts
+       # (0x20A0, 0x20CF), # Currency Symbols
+       # (0x20D0, 0x20FF), # Combining Diacritical Marks for Symbols
+       # (0x2100, 0x214F), # Letterlike Symbols
+       # (0x2150, 0x218F), # Number Forms
+       # (0x2190, 0x21FF), # Arrows
+       # (0x2200, 0x22FF), # Mathematical Operators
+       # (0x2300, 0x23FF), # Miscellaneous Technical
+       # (0x2400, 0x243F), # Control Pictures
+       # (0x2440, 0x245F), # Optical Character Recognition
+       # (0x2460, 0x24FF), # Enclosed Alphanumerics
+       # (0x2500, 0x257F), # Box Drawing
+       # (0x2580, 0x259F), # Block Elements
+       # (0x25A0, 0x25FF), # Geometric Shapes
+       # (0x2600, 0x26FF), # Miscellaneous Symbols
+       # (0x2700, 0x27BF), # Dingbats
+       # (0x27C0, 0x27EF), # Miscellaneous Mathematical Symbols-A
+       # (0x27F0, 0x27FF), # Supplemental Arrows-A
+       # (0x2800, 0x28FF), # Braille Patterns
+       # (0x2900, 0x297F), # Supplemental Arrows-B
+       # (0x2980, 0x29FF), # Miscellaneous Mathematical Symbols-B
+       # (0x2A00, 0x2AFF), # Supplemental Mathematical Operators
+       # (0x2B00, 0x2BFF), # Miscellaneous Symbols and Arrows
+       # (0x2E80, 0x2EFF), # CJK Radicals Supplement
+       # (0x2F00, 0x2FDF), # Kangxi Radicals
+       # (0x2FF0, 0x2FFF), # Ideographic Description Characters
+       # (0x3000, 0x303F), # CJK Symbols and Punctuation
+        (0x3040, 0x309F), # Hiragana
+        (0x30A0, 0x30FF), # Katakana
+       # (0x3100, 0x312F), # Bopomofo
+       # (0x3130, 0x318F), # Hangul Compatibility Jamo
+       # (0x3190, 0x319F), # Kanbun
+       # (0x31A0, 0x31BF), # Bopomofo Extended
+       # (0x31F0, 0x31FF), # Katakana Phonetic Extensions
+       # (0x3200, 0x32FF), # Enclosed CJK Letters and Months
+       # (0x3300, 0x33FF), # CJK Compatibility
+       # (0x3400, 0x4DBF), # CJK Unified Ideographs Extension A
+       # (0x4DC0, 0x4DFF), # Yijing Hexagram Symbols
+        (0x4E00, 0x9FFF), # CJK Unified Ideographs
+       # (0xA000, 0xA48F), # Yi Syllables
+       # (0xA490, 0xA4CF), # Yi Radicals
+        (0xAC00, 0xD7AF), # Hangul Syllables
+       # (0xD800, 0xDB7F), # High Surrogates
+       # (0xDB80, 0xDBFF), # High Private Use Surrogates
+       # (0xDC00, 0xDFFF), # Low Surrogates
+       # (0xE000, 0xF8FF), # Private Use Area
+       # (0xF900, 0xFAFF), # CJK Compatibility Ideographs
+       # (0xFB00, 0xFB4F), # Alphabetic Presentation Forms
+       # (0xFB50, 0xFDFF), # Arabic Presentation Forms-A
+       # (0xFE00, 0xFE0F), # Variation Selectors
+       # (0xFE20, 0xFE2F), # Combining Half Marks
+       # (0xFE30, 0xFE4F), # CJK Compatibility Forms
+       # (0xFE50, 0xFE6F), # Small Form Variants
+       # (0xFE70, 0xFEFF), # Arabic Presentation Forms-B
+       # (0xFF00, 0xFFEF), # Halfwidth and Fullwidth Forms
+       # (0xFFF0, 0xFFFF), # Specials
+       # (0x10000, 0x1007F), # Linear B Syllabary
+       # (0x10080, 0x100FF), # Linear B Ideograms
+       # (0x10100, 0x1013F), # Aegean Numbers
+       # (0x10300, 0x1032F), # Old Italic
+       # (0x10330, 0x1034F), # Gothic
+       # (0x10380, 0x1039F), # Ugaritic
+       # (0x10400, 0x1044F), # Deseret
+       # (0x10450, 0x1047F), # Shavian
+       # (0x10480, 0x104AF), # Osmanya
+       # (0x10800, 0x1083F), # Cypriot Syllabary
+       # (0x1D000, 0x1D0FF), # Byzantine Musical Symbols
+       # (0x1D100, 0x1D1FF), # Musical Symbols
+       # (0x1D300, 0x1D35F), # Tai Xuan Jing Symbols
+       # (0x1D400, 0x1D7FF), # Mathematical Alphanumeric Symbols
+        (0x1F600, 0x1F64F),  # Emoji
+       # (0x20000, 0x2A6DF), # CJK Unified Ideographs Extension B
+       # (0x2F800, 0x2FA1F), # CJK Compatibility Ideographs Supplement
+       # (0xE0000, 0xE007F), # Tags
+    ]
+    # Select a character set
+    alphabet = random.choice(include_ranges)
+    
+    # Generate a random string of 1 - 3 words
+    return ' '.join(
+        ''.join(chr(random.randrange(*alphabet)) for _ in range(length))
+        for _ in range(random.randint(1, max_words))
+    )
+
+
 def tuplify(pair: str) -> Tuple[int, int]:
     """Parses "x-y" description of an aligned token pair into `(x,y)` tuple of ints."""
     s, t = pair.split('-')
@@ -83,17 +242,20 @@ class PlaceholderTagModifier(Modifier):
          custom_detok_src: 'zh'
          custom_detok_trg: null
          template: " <tag{n}> {token} </tag{n}>"
+         augment: 0.0 # 0% chance to just insert a random string on both sides
+         replace: 0.0 # 0% change to use tags to force translate to a random string
         ```
     """
 
     num_tags: int
     template: str
     src_detokenizer: Detokenizer
-    trg_detokenizer: Optional[Detokenizer]
+    trg_detokenizer: Detokenizer
+    modes: List[Tuple[str,float]]
 
     def __init__(self, probability: float=0.0, num_tags: int=6,
         custom_detok_src: Optional[str]=None, custom_detok_trg: Optional[str]=None,
-        template: str=" <tag{n}> {token} </tag{n}>"):
+        template: str=" <tag{n}> {token} </tag{n}>", augment: float=0, replace:float=0):
         super().__init__(probability)
 
         self.num_tags = num_tags
@@ -107,8 +269,20 @@ def __init__(self, probability: float=0.0, num_tags: int=6,
         if custom_detok_trg:
             self.trg_detokenizer = MosesDetokenizer(lang=custom_detok_trg)
         else:
-            self.trg_detokenizer = None
+            self.trg_detokenizer = SpaceDetokenizer()
+
+        self.modes = []
+
+        if augment + replace > 1.0:
+            raise ValueError('sum of augment and replace probability should not exceed 1.0')
+
+        if augment > 0:
+            self.modes.append(('augment', augment))
+
+        if replace > 0:
+            self.modes.append(('replace', replace))
 
+        self.modes.append(('tag', 1.0)) # Weight doesn't matter as long as cumsum => 1.0, it's last on the list anyway
 
     def __call__(self, line:str) -> str:
         """Applies tag to words in a line based on alignment info, and then removes the alignment info from the line.
@@ -116,6 +290,7 @@ def __call__(self, line:str) -> str:
            eg "I like cake" would become "I like <tag0> gusta </tag0> cake. By default the detokenizer used is the trivial
            detokenizer, but we can instead have separate detokenizers on src and trg."
         """
+
         src, trg, alignment = line.strip().split('\t')
         source = src.split(' ')
         target = trg.split(' ')
@@ -135,24 +310,40 @@ def __call__(self, line:str) -> str:
             # Skip words that are the same on 
             if source[candidates[i][0]] == target[candidates[i][1]]:
                 continue
-            
+
             # Skip words whose turn it isn't yet.
             if random.random() >= self.probability:
                 continue
+            
+            # Select mode (skip random_weighted_choices*() when 'tag' is the only mode)
+            mode = random_weighted_choice(self.modes) if len(self.modes) > 1 else 'tag'
 
-            # We run out of tags so no point of trying to tag anything else
-            if not tags:
-                break
-
-            tag_id = tags.pop()
-            source[candidates[i][0]] = source[candidates[i][0]] + self.template.format(n=tag_id, token=target[candidates[i][1]])
+            # If we'd need a tag but we ran out of them, skip.
+            if (mode == "tag" or mode == "replace") and not tags:
+                continue
 
-        source_detok: str = self.src_detokenizer.detokenize(source)
-        if self.trg_detokenizer is not None:
-            trg = self.trg_detokenizer.detokenize(target)
+            if mode == "tag":
+                # Hint the expected output to the trainer by specifying it in the input as a tag
+                source[candidates[i][0]] += self.template.format(n=tags.pop(), token=target[candidates[i][1]])
+            elif mode == "replace":
+                # Same as above, but instead of the expected target word, we replace it on both
+                # sides with a random string. This encourages the model to really ignore the source
+                # and produce the target that we desire.
+                augment = get_random_unicode_string()
+                source[candidates[i][0]] += self.template.format(n=tags.pop(), token=augment)
+                target[candidates[i][1]] = augment
+            elif mode == "augment":
+                # Augment mode adds random noise both on the source and the target without any
+                # tagging encouraging the model to copy crap from one side to the other.
+                augment = get_random_unicode_string()
+                source[candidates[i][0]] = source[candidates[i][0]] + " " + augment
+                target[candidates[i][1]] = target[candidates[i][1]] + " " + augment
+
+        source_detok = self.src_detokenizer.detokenize(source)
+        target_detok = self.trg_detokenizer.detokenize(target)
 
         # Return the sentence, source tagged a la Dinu et al, target as it is and no alignment info
-        return  source_detok + "\t" + trg
+        return  source_detok + "\t" + target_detok
 
     def validate(self, context:List[Modifier]) -> None:
         """Current limitation of the tags modifier is that any other modifier might modify the


Test patch:
diff --git a/contrib/test-data/clean.enzh.ref.06.4.none b/contrib/test-data/clean.enzh.ref.06.4.none
index 154ca30..d72e5a7 100644
--- a/contrib/test-data/clean.enzh.ref.06.4.none
+++ b/contrib/test-data/clean.enzh.ref.06.4.none
@@ -1,10 +1,10 @@
 429 Transport <tag2> 运输 </tag2> Squadron <tag0> 中队 </tag0> (429 Bison Squadron) - Flying the CC-177 <tag1> 177 </tag1>	429 运输 中队 ( 429 野牛) , 使用 CC - 177
 The conference concluded that the manifestations of <tag3> / </tag3> SIRS include, but <tag1> 但 </tag1> are not <tag2> 不 </tag2> limited <tag0> 限于 </tag0> to the first four described above under adult SIRS criteria.	SIR S 标准 成立 于 1992年 , 是 美国 胸科 医师 学会 / 重症 监护 医学 协商会 共同 会议 的 一部分 。 会议 得出 结论 , SIR S 的 表现 包括 但 不 限于 上述 成人 SIR S 的 前 四 项 判定 标准 。
-On 1 March, Australia <tag3> 澳大利亚 </tag3> reported the first death from COVID-19: <tag1> 公主号 </tag1> a 78-year-old Perth <tag0> Gairdner </tag0> man, who was one of the passengers from the Diamond Princess, and who <tag2> 他 </tag2> had been evacuated and was being treated in Western Australia.	同日 , 一个 曾 为 钻石 公主号 邮轮 乘客 的 78 岁 男性 老人 宣布 死亡 , 为 澳大利亚 首例 因 感染 COVID - 19 死亡 的 病例 。 他 曾 在 西 澳大利亚州 Sir Charles Gairdner Hospital 治疗 。
-On 30 January, <tag0> 1月 </tag0> the WHO declared a Public <tag1> - </tag1> Health <tag2> COVID </tag2> Emergency of International Concern and on January 31, the Trump administration declared a public health emergency, and placed travel restrictions on entry for travellers from China. <tag3> 。 </tag3>	2020年 1月 20日 , 华盛顿州 确诊 首例 COVID - 19 患者 。 1月 29日 , 成立 白宫 冠状 病毒 工作组 。 1月 31日 , 特朗 普政府 宣布 进入 公共 卫生 紧急 状态 。
-Community health, even population health, is not encouraged as health sectors in <tag0> 在 </tag0> developing countries <tag1> 国家 </tag1> are not <tag2> 未 </tag2> able to link the national authorities with <tag3> 与 </tag3> the local government and community action.	其他 问题 涉及 医疗 服务 的 取得 , 以及 费用 。 世界 上 绝大部分 的 国家 地区 没有 足够 的 健康 保险 。 在 低 收入 国家 , 不 到 总 医疗 保健 支出 的 40% 的 经费 由 公家 / 政府 支付 。 社区 卫生 , 甚至 全民 卫生 都 未 受到 鼓励 , 因为 发展中国家 的 卫生 部门 无法 将 他们 的 国家 主管 部门 , 与 地方政府 , 以及 社区 行动 联系 起来 。
-Generally, the treatment for <tag2> 的 </tag2> SIRS is directed towards the underlying problem or inciting cause (i.e. adequate fluid replacement <tag0> 替代 </tag0> for hypovolemia, IVF/NPO for pancreatitis, epinephrine/steroids/diphenhydramine for anaphylaxis).Selenium, glutamine, and eicosapentaenoic acid have <tag3> 已经 </tag3> shown effectiveness in improving <tag1> 改善 </tag1> symptoms in clinical trials.	一般来说 , SIR S 的 治疗 针对 潜在 的 问题 或 诱发 原因 (例 如 , 使用 足够 的 液体 替代 血 容量 不足 , 对 胰腺 炎患者 应用 IV F / NPO , 肾上腺素 / 类固醇 / 苯海 拉明 用于 过敏 反应 ) 。 硒 , 谷氨 酰胺 和 二十 碳 五烯酸 已经 显示 出 在 临床 试验 中 改善 症状 的 有效性 。 其他 的 抗氧化剂 , 如 维生素E 可能 是 有 帮助 的 。
+On 1 March, Australia <tag3> 澳大利亚 </tag3> reported <tag2> 病例 </tag2> the first death from COVID-19: <tag0> 公主号 </tag0> a 78-year-old Perth man, who was one of the passengers from the Diamond Princess, and who <tag1> 他 </tag1> had been evacuated and was being treated in Western Australia.	同日 , 一个 曾 为 钻石 公主号 邮轮 乘客 的 78 岁 男性 老人 宣布 死亡 , 为 澳大利亚 首例 因 感染 COVID - 19 死亡 的 病例 。 他 曾 在 西 澳大利亚州 Sir Charles Gairdner Hospital 治疗 。
+On 30 January, the WHO declared a <tag1> 华盛顿州 </tag1> Public Health Emergency of International Concern and on January 31, the Trump administration declared a public health emergency, and <tag0> , </tag0> placed travel restrictions on entry <tag3> 进入 </tag3> for travellers from China. <tag2> 。 </tag2>	2020年 1月 20日 , 华盛顿州 确诊 首例 COVID - 19 患者 。 1月 29日 , 成立 白宫 冠状 病毒 工作组 。 1月 31日 , 特朗 普政府 宣布 进入 公共 卫生 紧急 状态 。
+Community <tag2> 社区 </tag2> health, even population health, is not encouraged <tag1> 鼓励 </tag1> as health sectors in developing countries are not able to link the national authorities with <tag3> 与 </tag3> the local government and community action. <tag0> 行动 </tag0>	其他 问题 涉及 医疗 服务 的 取得 , 以及 费用 。 世界 上 绝大部分 的 国家 地区 没有 足够 的 健康 保险 。 在 低 收入 国家 , 不 到 总 医疗 保健 支出 的 40% 的 经费 由 公家 / 政府 支付 。 社区 卫生 , 甚至 全民 卫生 都 未 受到 鼓励 , 因为 发展中国家 的 卫生 部门 无法 将 他们 的 国家 主管 部门 , 与 地方政府 , 以及 社区 行动 联系 起来 。
+Generally, the treatment for <tag1> 的 </tag1> SIRS is directed towards the underlying problem or inciting cause (i.e. adequate fluid <tag2> 液体 </tag2> replacement <tag0> 替代 </tag0> for hypovolemia, IVF/NPO for pancreatitis, epinephrine/steroids/diphenhydramine for anaphylaxis).Selenium, glutamine, and <tag3> 和 </tag3> eicosapentaenoic acid have shown effectiveness in improving symptoms in clinical trials.	一般来说 , SIR S 的 治疗 针对 潜在 的 问题 或 诱发 原因 (例 如 , 使用 足够 的 液体 替代 血 容量 不足 , 对 胰腺 炎患者 应用 IV F / NPO , 肾上腺素 / 类固醇 / 苯海 拉明 用于 过敏 反应 ) 。 硒 , 谷氨 酰胺 和 二十 碳 五烯酸 已经 显示 出 在 临床 试验 中 改善 症状 的 有效性 。 其他 的 抗氧化剂 , 如 维生素E 可能 是 有 帮助 的 。
 Food Poisoning and Food Hygiene.	微生物 检验 与 食品 安全 控制 .
-Together at Home <tag3> 在家 </tag3> (also known as One World: Together at Home) was a virtual concert series organised <tag0> 组织 </tag0> by Global Citizen <tag1> 公民 </tag1> and curated by singer Lady Gaga, in support <tag2> 支持 </tag2> of the World Health Organization.	同一个 世界 : 共同 在家 ( 英语 : One World : Together at Home) , 是 于 2020年 4月 18日 举行 的 虚拟 系列 演唱会 , 推广 在 2019 冠状 病毒 病 疫情 期间 保持 社交 距离 等 防疫 理念 , 由 全球 公民 和 歌手 嘎嘎 小姐 共同 组织 发起 , 以 支持 世界 卫生 组织 。
-On 20 September 2019, the <tag1> 了 </tag1> Australian <tag3> 澳大利亚 </tag3> Olympic Committee announced the first set of sailors selected for Tokyo 2020, <tag2> 2020年 </tag2> namely Rio 2016 silver medalists and defending world 470 champions Mathew Belcher and William Ryan and world's <tag0> 成为 </tag0> current top-ranked Laser sailor Matthew Wearn.	2019年 9月 20日 , 澳大利亚 奥林匹克 委员会 公布 了 第一 批 入选 奥运 阵容 的 帆船 选手 名单 , 名单 中 包括 2016年 里约 奥运 银牌 得主 Mathew Belcher 和 William Ryan 。 2020年 2月 27日 , 第二 批 入选 奥运 阵容 的 帆船 选手 名单 正式 公布 。 2020年 3月 19日 , Mara Stransky 确认 获得 代表 澳大利亚 参加 女子 辐射型 的 资格 , 成为 第三 批 入选 的 帆船 选手 。
-Transfusion-related <tag1> 相关 </tag1> acute <tag2> 急性 </tag2> lung injury <tag0> 损伤 </tag0> (TRALI) is a serious blood transfusion complication characterized by the acute onset of non-cardiogenic pulmonary edema following transfusion of blood products. <tag3> 。 </tag3>	输血 相关 急性 肺 损伤 (Transfusion related acute lung injury ; TRALI) 是 一 种 会 引发 急性 肺水肿 的 严重 输血併 发症 。
+Together at Home (also known as One World: Together at Home) was a virtual concert <tag2> 演唱会 </tag2> series organised <tag0> 组织 </tag0> by Global Citizen <tag3> 公民 </tag3> and curated by singer Lady Gaga, in support of the World <tag1> 世界 </tag1> Health Organization.	同一个 世界 : 共同 在家 ( 英语 : One World : Together at Home) , 是 于 2020年 4月 18日 举行 的 虚拟 系列 演唱会 , 推广 在 2019 冠状 病毒 病 疫情 期间 保持 社交 距离 等 防疫 理念 , 由 全球 公民 和 歌手 嘎嘎 小姐 共同 组织 发起 , 以 支持 世界 卫生 组织 。
+On 20 September 2019, the Australian <tag0> 澳大利亚 </tag0> Olympic Committee announced the first set of sailors selected for Tokyo 2020, namely Rio 2016 silver <tag3> 银牌 </tag3> medalists and defending world 470 champions Mathew Belcher <tag1> Mara </tag1> and William Ryan and world's <tag2> 成为 </tag2> current top-ranked Laser sailor Matthew Wearn.	2019年 9月 20日 , 澳大利亚 奥林匹克 委员会 公布 了 第一 批 入选 奥运 阵容 的 帆船 选手 名单 , 名单 中 包括 2016年 里约 奥运 银牌 得主 Mathew Belcher 和 William Ryan 。 2020年 2月 27日 , 第二 批 入选 奥运 阵容 的 帆船 选手 名单 正式 公布 。 2020年 3月 19日 , Mara Stransky 确认 获得 代表 澳大利亚 参加 女子 辐射型 的 资格 , 成为 第三 批 入选 的 帆船 选手 。
+Transfusion-related acute <tag3> 急性 </tag3> lung injury (TRALI) is a serious <tag2> 严重 </tag2> blood transfusion complication <tag1> TRALI) </tag1> characterized by the acute onset <tag0> 引发 </tag0> of non-cardiogenic pulmonary edema following transfusion of blood products.	输血 相关 急性 肺 损伤 (Transfusion related acute lung injury ; TRALI) 是 一 种 会 引发 急性 肺水肿 的 严重 输血併 发症 。
diff --git a/contrib/test-data/clean.enzh.ref.06.4.trg b/contrib/test-data/clean.enzh.ref.06.4.trg
index bbea76d..56b10bc 100644
--- a/contrib/test-data/clean.enzh.ref.06.4.trg
+++ b/contrib/test-data/clean.enzh.ref.06.4.trg
@@ -1,10 +1,10 @@
 429 Transport <tag2> 运输 </tag2> Squadron <tag0> 中队 </tag0> (429 Bison Squadron) - Flying the CC-177 <tag1> 177 </tag1>	429 运输中队 (429 野牛), 使用 CC - 177
 The conference concluded that the manifestations of <tag3> / </tag3> SIRS include, but <tag1> 但 </tag1> are not <tag2> 不 </tag2> limited <tag0> 限于 </tag0> to the first four described above under adult SIRS criteria.	SIR S 标准成立于 1992年, 是美国胸科医师学会 / 重症监护医学协商会共同会议的一部分。会议得出结论, SIR S 的表现包括但不限于上述成人 SIR S 的前四项判定标准。
-On 1 March, Australia <tag3> 澳大利亚 </tag3> reported the first death from COVID-19: <tag1> 公主号 </tag1> a 78-year-old Perth <tag0> Gairdner </tag0> man, who was one of the passengers from the Diamond Princess, and who <tag2> 他 </tag2> had been evacuated and was being treated in Western Australia.	同日, 一个曾为钻石公主号邮轮乘客的 78 岁男性老人宣布死亡, 为澳大利亚首例因感染 COVID - 19 死亡的病例。他曾在西澳大利亚州 Sir Charles Gairdner Hospital 治疗。
-On 30 January, <tag0> 1月 </tag0> the WHO declared a Public <tag1> - </tag1> Health <tag2> COVID </tag2> Emergency of International Concern and on January 31, the Trump administration declared a public health emergency, and placed travel restrictions on entry for travellers from China. <tag3> 。 </tag3>	2020年 1月 20日, 华盛顿州确诊首例 COVID - 19 患者。 1月 29日, 成立白宫冠状病毒工作组。 1月 31日, 特朗普政府宣布进入公共卫生紧急状态。
-Community health, even population health, is not encouraged as health sectors in <tag0> 在 </tag0> developing countries <tag1> 国家 </tag1> are not <tag2> 未 </tag2> able to link the national authorities with <tag3> 与 </tag3> the local government and community action.	其他问题涉及医疗服务的取得, 以及费用。世界上绝大部分的国家地区没有足够的健康保险。在低收入国家, 不到总医疗保健支出的 40% 的经费由公家 / 政府支付。社区卫生, 甚至全民卫生都未受到鼓励, 因为发展中国家的卫生部门无法将他们的国家主管部门, 与地方政府, 以及社区行动联系起来。
-Generally, the treatment for <tag2> 的 </tag2> SIRS is directed towards the underlying problem or inciting cause (i.e. adequate fluid replacement <tag0> 替代 </tag0> for hypovolemia, IVF/NPO for pancreatitis, epinephrine/steroids/diphenhydramine for anaphylaxis).Selenium, glutamine, and eicosapentaenoic acid have <tag3> 已经 </tag3> shown effectiveness in improving <tag1> 改善 </tag1> symptoms in clinical trials.	一般来说, SIR S 的治疗针对潜在的问题或诱发原因 (例如, 使用足够的液体替代血容量不足, 对胰腺炎患者应用 IV F / NPO, 肾上腺素 / 类固醇 / 苯海拉明用于过敏反应) 。硒, 谷氨酰胺和二十碳五烯酸已经显示出在临床试验中改善症状的有效性。其他的抗氧化剂, 如维生素E 可能是有帮助的。
+On 1 March, Australia <tag3> 澳大利亚 </tag3> reported <tag2> 病例 </tag2> the first death from COVID-19: <tag0> 公主号 </tag0> a 78-year-old Perth man, who was one of the passengers from the Diamond Princess, and who <tag1> 他 </tag1> had been evacuated and was being treated in Western Australia.	同日, 一个曾为钻石公主号邮轮乘客的 78 岁男性老人宣布死亡, 为澳大利亚首例因感染 COVID - 19 死亡的病例。他曾在西澳大利亚州 Sir Charles Gairdner Hospital 治疗。
+On 30 January, the WHO declared a <tag1> 华盛顿州 </tag1> Public Health Emergency of International Concern and on January 31, the Trump administration declared a public health emergency, and <tag0> , </tag0> placed travel restrictions on entry <tag3> 进入 </tag3> for travellers from China. <tag2> 。 </tag2>	2020年 1月 20日, 华盛顿州确诊首例 COVID - 19 患者。 1月 29日, 成立白宫冠状病毒工作组。 1月 31日, 特朗普政府宣布进入公共卫生紧急状态。
+Community <tag2> 社区 </tag2> health, even population health, is not encouraged <tag1> 鼓励 </tag1> as health sectors in developing countries are not able to link the national authorities with <tag3> 与 </tag3> the local government and community action. <tag0> 行动 </tag0>	其他问题涉及医疗服务的取得, 以及费用。世界上绝大部分的国家地区没有足够的健康保险。在低收入国家, 不到总医疗保健支出的 40% 的经费由公家 / 政府支付。社区卫生, 甚至全民卫生都未受到鼓励, 因为发展中国家的卫生部门无法将他们的国家主管部门, 与地方政府, 以及社区行动联系起来。
+Generally, the treatment for <tag1> 的 </tag1> SIRS is directed towards the underlying problem or inciting cause (i.e. adequate fluid <tag2> 液体 </tag2> replacement <tag0> 替代 </tag0> for hypovolemia, IVF/NPO for pancreatitis, epinephrine/steroids/diphenhydramine for anaphylaxis).Selenium, glutamine, and <tag3> 和 </tag3> eicosapentaenoic acid have shown effectiveness in improving symptoms in clinical trials.	一般来说, SIR S 的治疗针对潜在的问题或诱发原因 (例如, 使用足够的液体替代血容量不足, 对胰腺炎患者应用 IV F / NPO, 肾上腺素 / 类固醇 / 苯海拉明用于过敏反应) 。硒, 谷氨酰胺和二十碳五烯酸已经显示出在临床试验中改善症状的有效性。其他的抗氧化剂, 如维生素E 可能是有帮助的。
 Food Poisoning and Food Hygiene.	微生物检验与食品安全控制.
-Together at Home <tag3> 在家 </tag3> (also known as One World: Together at Home) was a virtual concert series organised <tag0> 组织 </tag0> by Global Citizen <tag1> 公民 </tag1> and curated by singer Lady Gaga, in support <tag2> 支持 </tag2> of the World Health Organization.	同一个世界: 共同在家 (英语: One World: Together at Home), 是于 2020年 4月 18日举行的虚拟系列演唱会, 推广在 2019 冠状病毒病疫情期间保持社交距离等防疫理念, 由全球公民和歌手嘎嘎小姐共同组织发起, 以支持世界卫生组织。
-On 20 September 2019, the <tag1> 了 </tag1> Australian <tag3> 澳大利亚 </tag3> Olympic Committee announced the first set of sailors selected for Tokyo 2020, <tag2> 2020年 </tag2> namely Rio 2016 silver medalists and defending world 470 champions Mathew Belcher and William Ryan and world's <tag0> 成为 </tag0> current top-ranked Laser sailor Matthew Wearn.	2019年 9月 20日, 澳大利亚奥林匹克委员会公布了第一批入选奥运阵容的帆船选手名单, 名单中包括 2016年里约奥运银牌得主 Mathew Belcher 和 William Ryan 。 2020年 2月 27日, 第二批入选奥运阵容的帆船选手名单正式公布。 2020年 3月 19日, Mara Stransky 确认获得代表澳大利亚参加女子辐射型的资格, 成为第三批入选的帆船选手。
-Transfusion-related <tag1> 相关 </tag1> acute <tag2> 急性 </tag2> lung injury <tag0> 损伤 </tag0> (TRALI) is a serious blood transfusion complication characterized by the acute onset of non-cardiogenic pulmonary edema following transfusion of blood products. <tag3> 。 </tag3>	输血相关急性肺损伤 (Transfusion related acute lung injury; TRALI) 是一种会引发急性肺水肿的严重输血併发症。
+Together at Home (also known as One World: Together at Home) was a virtual concert <tag2> 演唱会 </tag2> series organised <tag0> 组织 </tag0> by Global Citizen <tag3> 公民 </tag3> and curated by singer Lady Gaga, in support of the World <tag1> 世界 </tag1> Health Organization.	同一个世界: 共同在家 (英语: One World: Together at Home), 是于 2020年 4月 18日举行的虚拟系列演唱会, 推广在 2019 冠状病毒病疫情期间保持社交距离等防疫理念, 由全球公民和歌手嘎嘎小姐共同组织发起, 以支持世界卫生组织。
+On 20 September 2019, the Australian <tag0> 澳大利亚 </tag0> Olympic Committee announced the first set of sailors selected for Tokyo 2020, namely Rio 2016 silver <tag3> 银牌 </tag3> medalists and defending world 470 champions Mathew Belcher <tag1> Mara </tag1> and William Ryan and world's <tag2> 成为 </tag2> current top-ranked Laser sailor Matthew Wearn.	2019年 9月 20日, 澳大利亚奥林匹克委员会公布了第一批入选奥运阵容的帆船选手名单, 名单中包括 2016年里约奥运银牌得主 Mathew Belcher 和 William Ryan 。 2020年 2月 27日, 第二批入选奥运阵容的帆船选手名单正式公布。 2020年 3月 19日, Mara Stransky 确认获得代表澳大利亚参加女子辐射型的资格, 成为第三批入选的帆船选手。
+Transfusion-related acute <tag3> 急性 </tag3> lung injury (TRALI) is a serious <tag2> 严重 </tag2> blood transfusion complication <tag1> TRALI) </tag1> characterized by the acute onset <tag0> 引发 </tag0> of non-cardiogenic pulmonary edema following transfusion of blood products.	输血相关急性肺损伤 (Transfusion related acute lung injury; TRALI) 是一种会引发急性肺水肿的严重输血併发症。
diff --git a/contrib/test-data/clean.zhen.ref.06.4.04.04.src b/contrib/test-data/clean.zhen.ref.06.4.04.04.src
new file mode 100644
index 0000000..390271c
--- /dev/null
+++ b/contrib/test-data/clean.zhen.ref.06.4.04.04.src
@@ -0,0 +1,10 @@
+429 运输中队 <tag2> Squadron </tag2> (429 野牛), 使用 CC - 177 <tag1> バズガマィパプロ゠ヹベヂ </tag1>	429 Transport Squadron (429 Bison Squadron) - Flying the バズガマ ィパプロ ゠ヹベヂ
+SIR S 标准成立 ૬ ૽ ૎ 于 1992年, 是饤剫譸洒膿茈搥糽美国胸科医师学会 / 重症监护医学协商会共同会议的一部分。会议得出结论, あふょを SIR S 的表现包括 <tag2> ڹ؇ڇظ ۃٰ۰پ </tag2> 但不 <tag0> ѕӥҸ ӹҶҀ ӯӷѬ </tag0> 限于 ֑֭ ײ֩ ו׾ 上述成人 <tag3> adult </tag3> SIR S 的前四 <tag1> ϲ΋Ι ϵϔώ </tag1> 项判定标准。	The ૬ ૽ ૎ conference concluded that the manifestations of SIRS ڹ؇ڇظ ۃٰ۰پ but are 饤剫譸洒 膿茈搥糽 ѕӥҸ ӹҶҀ ӯӷѬ limited ֑֭ ײ֩ ו׾ to あふ ょを the first ϲ΋Ι ϵϔώ described above under adult SIRS criteria.
+同日, 一个 <tag1> ぃそゑざゆりしかゆ </tag1> 曾为钻石 ૙઩િ ઼઎ઃ 公主号 ঠ৳ 邮轮乘客的 78 岁男性老人宣布死亡, 为澳大利亚 <tag2> Australia </tag2> 首例因感染 COVID - 19 死亡的病例。他 ঢ 曾在 😙🙀😴 😾😭😵 😬😀🙄 西澳大利亚州 Sir Charles Gairdner <tag0> કઔઠ </tag0> Hospital 治疗。	On 1 March, Australia reported the first death from COVID-19: ঠ৳ ぃそゑ ざゆり しかゆ 78-year-old કઔઠ man, who was one of the passengers from the Diamond ૙઩િ ઼઎ઃ Princess, and who ঢ had been evacuated and was being treated in 😙🙀😴 😾😭😵 😬😀🙄 Western Australia.
+2020年 1月 <tag1> January, </tag1> 20日, 华盛顿州确诊首例 COVID ઔઙ૭઩ - 19 患者。 1月 29日 ´Ù úà öÖ, 成立 ॓ःलॖ ॉ०ऩ॔ ॐशइफ़ 白宫冠状病毒工作组。 1月 31日 ჌, <tag0> 😿😍😱😥 </tag0> 特朗普政府宣布 <tag3> declared </tag3> 进入퇌公共卫生 <tag2> health </tag2> 紧急状态。	On 30 January, the WHO declared a Public Health ઔઙ૭઩ Emergency of International Concern and on ´Ù úà öÖ January 31, ჌ the Trump administration declared a ॓ःलॖ ॉ०ऩ॔ ॐशइफ़ public health emergency, 😿😍😱😥 placed travel restrictions on entry 퇌 for travellers from China.
+其他问题涉及医疗服务的取得, 以及费用。世界上绝大部分的国家地区没有足够的健康保险。在低收入国家, 不到总医疗保健支出的 40% 的经费由公家 / 政府支付。社区卫生, 甚至 ۉ 全民卫生都未 ႐ႈဝ ၵ၆ရ 受到鼓励, 因为发展中国家的卫生部门无法 <tag0> ิ </tag0> 将他们的国家 <tag3> national </tag3> 主管部门, य़६ 与地方政府, 以及 <tag1> 츲쬂츔묄뀮꺕녫뒃 </tag1> 社区 <tag2> ၗဝ၊ ြႚၽ </tag2> 行动联系起来。	Community health, even ۉ population health, is not encouraged as health sectors in developing countries are not ႐ႈဝ ၵ၆ရ ิ to link the national authorities with the य़६ local government 츲쬂츔묄 뀮꺕녫뒃 ၗဝ၊ ြႚၽ action.
+一般来说, SIR S 的治疗コガムドォメ针对潜在 Ⴢღ 的问题或 ¡Åü 诱发原因 (例如, 使用足够的液体 ऌॅॎ ॊ१ौ 替代 ီႊဵ၎ ဲဿၜန 血容量不足, 对胰腺炎患者应用 IV F / NPO, 肾上腺素 / 类固醇 / 苯海拉明用于 <tag1> ญ๚ แ๪ </tag1> 过敏反应) 。硒, 谷氨酰胺和 <tag0> and </tag0> 二十碳 <tag3> 😫 😝 😱 </tag3> 五烯酸已经 <tag2> Ⴈ჈წ </tag2> 显示出在临床试验中改善症状的有效性。其他的抗氧化剂, 如维生素E 可能是有帮助的。	Generally, the treatment コガム ドォメ for SIRS is directed towards the underlying Ⴢღ problem or ¡Åü inciting cause (i.e. adequate fluid ऌॅॎ ॊ१ौ replacement ီႊဵ၎ ဲဿၜန ญ๚ แ๪ hypovolemia, IVF/NPO for pancreatitis, epinephrine/steroids/diphenhydramine 😫 😝 😱 anaphylaxis).Selenium, glutamine, and eicosapentaenoic acid Ⴈ჈წ shown effectiveness in improving symptoms in clinical trials.
+微生物检验与食品安全控制.	Food Poisoning and Food Hygiene.
+同一个世界: 共同在家 <tag3> Home </tag3> (英语: One World: Together at Home), 是于 2020年 4月 18日举行的虚拟系列演唱会 ৗ৻, 推广在 2019 冠状病毒病 დႶხ ႫႽპ ႠႶუ 疫情期间保持社交距离等防疫理念, 由全球公民和 <tag1> 칯줃겲앓솬뛺 </tag1> 歌手 <tag0> 꺚춌뇉뱔퐸뉷 </tag0> 嘎嘎小姐共同组织 😇😭🙊😑 发起, 以 <tag2> ϳϐΝΗ </tag2> 支持ヒ・ヱ世界 ऴफेॎ ॴढ़ॵ॓ णॼ॒ज 卫生 ײ׵֪ ֶַר ֶ׼ז 组织。	Together at Home (also known დႶხ ႫႽპ ႠႶუ as One World: Together at Home) was a virtual concert ৗ৻ series organised 😇😭🙊😑 by Global Citizen 칯줃겲 앓솬뛺 curated by 꺚춌 뇉뱔 퐸뉷 Lady Gaga, ϳϐΝΗ support ヒ ・ ヱ of the World ऴफेॎ ॴढ़ॵ॓ णॼ॒ज Health ײ׵֪ ֶַר ֶ׼ז Organization.
+2019年 ႶႩ ჭႡ 9月 ႊၦၖ႒ ၾလၠၡ 20日, 澳大利亚 Оґҿ 奥林匹克 Ϗο ϟϰ ϋϷ 委员会 <tag2> ןץד ֩־ד </tag2> 公布떻즒벙쬂뛛짥첩껧了第一批入选奥运阵容 ჯცჽჹ ႨჟႿჱ 的帆船选手名单, 名单中包括 2016年 <tag0> 2016 </tag0> 里约わませ奥运银牌褕髨逪得主 Mathew Belcher 和 William Ryan 。 2020年 😹😕🙅 😭😾😵 2月 27日, 第二批入选奥运阵容的帆船选手名单正式公布。 2020年 3月 19日, Mara <tag1> ычпѠ ҿҏЁӵ а҇ѰҔ </tag1> Stransky 确认获得代表澳大利亚参加女子辐射型的资格, 成为 ΁ϡ͵Κ ϱΙ·ϖ 第三批入选的 <tag3> খত </tag3> 帆船选手。	On 20 September ႊၦၖ႒ ၾလၠၡ 2019, ႶႩ ჭႡ the Australian Оґҿ Olympic Ϗο ϟϰ ϋϷ ןץד ֩־ד announced 떻즒벙쬂 뛛짥첩껧 the first set of sailors selected for Tokyo 2020, 😹😕🙅 😭😾😵 namely Rio わませ 2016 silver 褕髨逪 medalists ჯცჽჹ ႨჟႿჱ and defending world 470 champions Mathew ычпѠ ҿҏЁӵ а҇ѰҔ and William Ryan and world's ΁ϡ͵Κ ϱΙ·ϖ current top-ranked খত sailor Matthew Wearn.
+输血相关 <tag3> დႶ ოჁ ხ჊ </tag3> 急性肺损伤 (Transfusion related acute lung injury; TRALI) উ৙৪ 是一种会引发急性 <tag0> 😒🙍😡😺 🙃😔😑😑 😸😮😧😳 </tag0> 肺水肿的严重 <tag2> ף ׮ </tag2> 输血併发症。 <tag1> SH W? B8 </tag1>	დႶ ოჁ ხ჊ acute lung injury (TRALI) is a ף ׮ blood transfusion complication উ৙৪ characterized by the 😒🙍😡😺 🙃😔😑😑 😸😮😧😳 onset of non-cardiogenic pulmonary edema following transfusion of blood SH W? B8
diff --git a/contrib/test-data/clean.zhen.ref.06.4.src b/contrib/test-data/clean.zhen.ref.06.4.src
index c837ee8..55ef0d4 100644
--- a/contrib/test-data/clean.zhen.ref.06.4.src
+++ b/contrib/test-data/clean.zhen.ref.06.4.src
@@ -1,10 +1,10 @@
 429 运输 <tag2> Transport </tag2> 中队 <tag0> Squadron </tag0> (429 野牛), 使用 CC - 177 <tag1> CC-177 </tag1>	429 Transport Squadron (429 Bison Squadron) - Flying the CC-177
 SIR S 标准成立 <tag2> The </tag2> 于 1992年, 是美国胸科医师学会 / <tag1> of </tag1> 重症监护医学协商会共同会议的一部分。会议得出结论, SIR S 的表现包括 <tag3> include, </tag3> 但不 <tag0> not </tag0> 限于上述成人 SIR S 的前四项判定标准。	The conference concluded that the manifestations of SIRS include, but are not limited to the first four described above under adult SIRS criteria.
-同日, 一个 <tag0> a </tag0> 曾为钻石公主号邮轮乘客的 78 岁男性 <tag3> man, </tag3> 老人宣布死亡, 为澳大利亚 <tag1> Australia </tag1> 首例因感染 COVID - 19 死亡的病例。他曾在 <tag2> in </tag2> 西澳大利亚州 Sir Charles Gairdner Hospital 治疗。	On 1 March, Australia reported the first death from COVID-19: a 78-year-old Perth man, who was one of the passengers from the Diamond Princess, and who had been evacuated and was being treated in Western Australia.
-2020年 1月 <tag2> January, </tag2> 20日, 华盛顿州确诊首例 COVID - 19 患者。 1月 29日, 成立 <tag0> a </tag0> 白宫冠状病毒工作组。 1月 31日 <tag1> 31, </tag1>, 特朗普政府宣布进入 <tag3> entry </tag3> 公共卫生紧急状态。	On 30 January, the WHO declared a Public Health Emergency of International Concern and on January 31, the Trump administration declared a public health emergency, and placed travel restrictions on entry for travellers from China.
-其他问题涉及医疗服务的取得, 以及费用。世界上绝大部分的国家地区没有足够的健康保险。在低收入国家, 不到总医疗保健支出的 40% 的经费由公家 / 政府支付 <tag0> to </tag0> 。社区卫生, 甚至全民卫生都未受到鼓励 <tag1> encouraged </tag1>, 因为发展中国家 <tag3> developing </tag3> 的卫生部门无法将他们的国家主管部门, 与地方政府, 以及社区 <tag2> community </tag2> 行动联系起来。	Community health, even population health, is not encouraged as health sectors in developing countries are not able to link the national authorities with the local government and community action.
-一般来说, SIR S 的治疗针对潜在的问题 <tag3> problem </tag3> 或诱发原因 (例如, 使用足够的液体 <tag1> fluid </tag1> 替代 <tag0> replacement </tag0> 血容量不足, 对胰腺炎患者应用 IV F / NPO, 肾上腺素 / 类固醇 / 苯海拉明用于过敏反应) 。硒, 谷氨酰胺和二十碳五烯酸已经 <tag2> have </tag2> 显示出在临床试验中改善症状的有效性。其他的抗氧化剂, 如维生素E 可能是有帮助的。	Generally, the treatment for SIRS is directed towards the underlying problem or inciting cause (i.e. adequate fluid replacement for hypovolemia, IVF/NPO for pancreatitis, epinephrine/steroids/diphenhydramine for anaphylaxis).Selenium, glutamine, and eicosapentaenoic acid have shown effectiveness in improving symptoms in clinical trials.
+同日, 一个曾为钻石公主号 <tag2> COVID-19: </tag2> 邮轮乘客的 78 岁男性 <tag3> man, </tag3> 老人宣布死亡, 为澳大利亚 <tag0> Australia </tag0> 首例因感染 COVID - 19 死亡的病例。他曾在 <tag1> in </tag1> 西澳大利亚州 Sir Charles Gairdner Hospital 治疗。	On 1 March, Australia reported the first death from COVID-19: a 78-year-old Perth man, who was one of the passengers from the Diamond Princess, and who had been evacuated and was being treated in Western Australia.
+2020年 <tag0> 30 </tag0> 1月 20日, 华盛顿州确诊首例 COVID - 19 患者。 1月 29日 <tag3> on </tag3>, 成立白宫冠状病毒工作组。 1月 31日, 特朗普政府宣布进入 <tag2> entry </tag2> 公共卫生 <tag1> health </tag1> 紧急状态。	On 30 January, the WHO declared a Public Health Emergency of International Concern and on January 31, the Trump administration declared a public health emergency, and placed travel restrictions on entry for travellers from China.
+其他问题涉及医疗服务的取得, 以及 <tag2> as </tag2> 费用。世界上绝大部分的国家地区没有足够的健康保险。在低收入国家, 不到总医疗保健支出的 40% 的经费由公家 / 政府支付。社区卫生, 甚至全民卫生都未受到鼓励, 因为发展中国家 <tag3> developing </tag3> 的卫生部门无法 <tag1> able </tag1> 将他们的国家 <tag0> national </tag0> 主管部门, 与地方政府, 以及社区行动联系起来。	Community health, even population health, is not encouraged as health sectors in developing countries are not able to link the national authorities with the local government and community action.
+一般来说, SIR S 的治疗针对潜在的问题或诱发原因 <tag2> cause </tag2> (例如, 使用足够的液体替代 <tag0> replacement </tag0> 血容量不足, 对胰腺炎患者应用 IV F / NPO, 肾上腺素 / 类固醇 / 苯海拉明用于过敏反应) 。硒, 谷氨酰胺和二十碳五烯酸已经 <tag1> have </tag1> 显示出在临床试验中改善症状 <tag3> symptoms </tag3> 的有效性。其他的抗氧化剂, 如维生素E 可能是有帮助的。	Generally, the treatment for SIRS is directed towards the underlying problem or inciting cause (i.e. adequate fluid replacement for hypovolemia, IVF/NPO for pancreatitis, epinephrine/steroids/diphenhydramine for anaphylaxis).Selenium, glutamine, and eicosapentaenoic acid have shown effectiveness in improving symptoms in clinical trials.
 微生物检验与食品安全控制.	Food Poisoning and Food Hygiene.
-同一个世界: 共同在家 <tag0> Home </tag0> (英语: One World: Together at Home), 是于 2020年 4月 18日举行的虚拟 <tag3> virtual </tag3> 系列演唱会 <tag2> concert </tag2>, 推广在 2019 冠状病毒病疫情期间保持社交距离等防疫理念, 由全球公民和 <tag1> and </tag1> 歌手嘎嘎小姐共同组织发起, 以支持世界卫生组织。	Together at Home (also known as One World: Together at Home) was a virtual concert series organised by Global Citizen and curated by singer Lady Gaga, in support of the World Health Organization.
-2019年 9月 20日, 澳大利亚 <tag1> Australian </tag1> 奥林匹克委员会公布了第一批入选奥运阵容的帆船选手名单, 名单中包括 2016年 <tag3> 2016 </tag3> 里约奥运银牌得主 Mathew Belcher 和 <tag0> and </tag0> William Ryan 。 2020年 2月 27日, 第二批入选奥运阵容的帆船选手名单正式公布。 2020年 3月 19日, Mara <tag2> Belcher </tag2> Stransky 确认获得代表澳大利亚参加女子辐射型的资格, 成为第三批入选的帆船选手。	On 20 September 2019, the Australian Olympic Committee announced the first set of sailors selected for Tokyo 2020, namely Rio 2016 silver medalists and defending world 470 champions Mathew Belcher and William Ryan and world's current top-ranked Laser sailor Matthew Wearn.
-输血相关急性 <tag2> acute </tag2> 肺损伤 (Transfusion related acute lung injury; TRALI) <tag1> complication </tag1> 是一种会引发 <tag3> onset </tag3> 急性肺水肿的严重 <tag0> serious </tag0> 输血併发症。	Transfusion-related acute lung injury (TRALI) is a serious blood transfusion complication characterized by the acute onset of non-cardiogenic pulmonary edema following transfusion of blood products.
+同一个世界: 共同 <tag2> Together </tag2> 在家 <tag0> Home </tag0> (英语: One World: Together at Home), 是于 2020年 4月 18日举行的虚拟系列演唱会, 推广在 2019 冠状病毒病 <tag1> known </tag1> 疫情期间保持社交距离等防疫理念, 由全球公民和 <tag3> and </tag3> 歌手嘎嘎小姐共同组织发起, 以支持世界卫生组织。	Together at Home (also known as One World: Together at Home) was a virtual concert series organised by Global Citizen and curated by singer Lady Gaga, in support of the World Health Organization.
+2019年 9月 20日, 澳大利亚奥林匹克委员会公布了第一批入选奥运阵容的帆船选手名单, 名单中包括 2016年 <tag0> 2016 </tag0> 里约 <tag3> Rio </tag3> 奥运银牌得主 Mathew Belcher 和 <tag2> and </tag2> William Ryan 。 2020年 2月 27日, 第二批入选奥运阵容的帆船选手名单正式公布。 2020年 3月 19日, Mara Stransky 确认获得代表澳大利亚参加女子辐射型的资格, 成为第三批入选的 <tag1> Laser </tag1> 帆船选手。	On 20 September 2019, the Australian Olympic Committee announced the first set of sailors selected for Tokyo 2020, namely Rio 2016 silver medalists and defending world 470 champions Mathew Belcher and William Ryan and world's current top-ranked Laser sailor Matthew Wearn.
+输血相关 <tag2> Transfusion-related </tag2> 急性 <tag3> acute </tag3> 肺损伤 <tag1> injury </tag1> (Transfusion related acute lung injury; TRALI) 是一种会引发急性肺水肿的严重输血併发症。 <tag0> products. </tag0>	Transfusion-related acute lung injury (TRALI) is a serious blood transfusion complication characterized by the acute onset of non-cardiogenic pulmonary edema following transfusion of blood products.
diff --git a/contrib/test_enzh_config.yml b/contrib/test_enzh_config.yml
index 77684c7..ea0019c 100644
--- a/contrib/test_enzh_config.yml
+++ b/contrib/test_enzh_config.yml
@@ -17,9 +17,14 @@ modifiers:
     num_tags: 6
     custom_detok_src: null # Null value for the src detokenizer
     custom_detok_trg: zh
-    # template: " <tag{n}> {token} </tag{n}>" # This is the default way of inserting tags.
+    template: " <tag{n}> {token} </tag{n}>" # This is the default way of inserting tags.
     # We STRONGLY DISCOURAGE the modification of this line and in fact it shouldn't be included in the config
     # unless you really know what you are doing.
+    # Testing the parsing those values. The 0 means that whenever this modifier takes effect (probability 0.1)
+    # Out of those times, there's `augment` fraction of chance of adding untagged noise to both sides instead of tags
+    # and `replace` fraction of chance of adding placeholder tags, but replace the expected target with noise.
+    augment: 0
+    replace: 0
 
 seed: 1111
 trainer: cat
diff --git a/contrib/test_enzh_noise_config.yml b/contrib/test_enzh_noise_config.yml
new file mode 100644
index 0000000..80d334e
--- /dev/null
+++ b/contrib/test_enzh_noise_config.yml
@@ -0,0 +1,26 @@
+# Datasets are already TSV files
+datasets:
+  clean: test-data/clean.enzh.10
+
+stages:
+  - start
+
+start:
+  - clean  1
+  - until clean 1
+
+modifiers:
+  - UpperCase: 0.2
+  - TitleCase: 0.2
+  - Tags: 0.1
+    num_tags: 6
+    custom_detok_src: null # Null value for the src detokenizer
+    custom_detok_trg: zh
+    augment: 0.4 # 0.4 out of the time tags is triggered, instead augment the source and the target with random noise
+    replace: 0.4 # =====//=====, instead replace the target token with random noise, and use that random noise to tag a corresponding source word
+    # template: " <tag{n}> {token} </tag{n}>" # This is the default way of inserting tags.
+    # We STRONGLY DISCOURAGE the modification of this line and in fact it shouldn't be included in the config
+    # unless you really know what you are doing.
+
+seed: 1111
+trainer: cat
diff --git a/tests/test_placholders.py b/tests/test_placeholders.py
similarity index 59%
rename from tests/test_placholders.py
rename to tests/test_placeholders.py
index 5e40a71..325bd0f 100644
--- a/tests/test_placholders.py
+++ b/tests/test_placeholders.py
@@ -8,6 +8,24 @@
 
 
 class TestTagger(unittest.TestCase):
+  def test_tagger_tagging(self):
+    random.seed(1)
+    tagger = PlaceholderTagModifier(probability=1)
+    output = tagger('Hello world\tHallo Welt\t0-0 1-1')
+    self.assertEqual(output, 'Hello <tag4> Hallo </tag4> world <tag1> Welt </tag1>\tHallo Welt')
+
+  def test_tagger_augment(self):
+    random.seed(1)
+    tagger = PlaceholderTagModifier(probability=1, augment=1)
+    output = tagger('Hello world\tHallo Welt\t0-0 1-1')
+    self.assertEqual(output, '''Hello ゜ そ world ټ؇ۤە	Hallo ゜ そ Welt ټ؇ۤە''')
+
+  def test_tagger_replace(self):
+    random.seed(1)
+    tagger = PlaceholderTagModifier(probability=.5, replace=1)
+    output = tagger('Hello world\tHallo Welt\t0-0 1-1')
+    self.assertEqual(output, '''Hello <tag4> ゜ そ </tag4> world <tag1> ټ؇ۤە </tag1>	゜ そ ټ؇ۤە''')
+
   def test_tagger_zh_src(self):
     '''Tests the tagger with zh on the source side'''
     random.seed(1)
@@ -41,6 +59,18 @@ def test_tagger_no_zh(self):
           ref = reference.readline()[:-1]
           self.assertEqual(test, ref)
 
+  def test_tagger_zh_src_augment_replace(self):
+    '''Tests the tagger with zh on the source side'''
+    random.seed(1)
+    tagger = PlaceholderTagModifier(probability=0.6, num_tags=4, custom_detok_src='zh', custom_detok_trg=None,
+          template=" <tag{n}> {token} </tag{n}>", augment=0.4, replace=0.4)
+    with open('contrib/test-data/clean.zhen.10', 'r', encoding='utf-8') as myinput, \
+         open('contrib/test-data/clean.zhen.ref.06.4.04.04.src', 'r', encoding='utf-8') as reference:
+        for line in myinput:
+          test = tagger(line)
+          ref = reference.readline()[:-1]
+          self.assertEqual(test, ref)
+
   def test_warn_if_tag_modifier_is_not_last(self):
     with self.assertWarnsRegex(UserWarning, r'Tags modifier should to be the last modifier to be applied'):
       loader = CurriculumLoader()