From 5a48c1cb7f0e13ec9828a9bf7845e684ee0a8d27 Mon Sep 17 00:00:00 2001 From: yhliang <429259365@qq.com> Date: Wed, 26 Apr 2023 16:39:22 +0800 Subject: [PATCH 001/120] update m2met docs --- docs/m2met2/Organizers.md | 2 +- .../m2met2/_build/doctrees/Organizers.doctree | Bin 10632 -> 10556 bytes .../m2met2/_build/doctrees/environment.pickle | Bin 25894 -> 25894 bytes docs/m2met2/_build/html/Organizers.html | 2 +- .../_build/html/_sources/Organizers.md.txt | 2 +- docs/m2met2/_build/html/searchindex.js | 2 +- .../_build/doctrees/environment.pickle | Bin 25266 -> 25266 bytes docs/m2met2_cn/_build/doctrees/简介.doctree | Bin 13572 -> 13574 bytes .../_build/html/_sources/简介.md.txt | 2 +- docs/m2met2_cn/_build/html/searchindex.js | 2 +- docs/m2met2_cn/_build/html/简介.html | 2 +- docs/m2met2_cn/简介.md | 2 +- 12 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/m2met2/Organizers.md b/docs/m2met2/Organizers.md index e16c803af..f5a9da2ba 100644 --- a/docs/m2met2/Organizers.md +++ b/docs/m2met2/Organizers.md @@ -1,5 +1,5 @@ # Organizers -***Lei Xie, Professor, Northwestern Polytechnical University, China*** +***Lei Xie, Professor, AISHELL foundation, China*** Email: [lxie@nwpu.edu.cn](mailto:lxie@nwpu.edu.cn) diff --git a/docs/m2met2/_build/doctrees/Organizers.doctree b/docs/m2met2/_build/doctrees/Organizers.doctree index 0f571a3b7b6877df4fcfb03aed01e9af94771a06..7ecfbdf5a0ffa64a181a3dc1ef9d88bbf24a53a8 100644 GIT binary patch delta 143 zcmeAO-V?;qz%tcvBg;HSF=H()EuYj(g^0{l9fg3R{It~K;{2k?dt_85zh@K|*2N;{ pBdajkhsg+soH7n^na!Nc)0BBErev_kPRS7KVKTGWyjtxp696iWF6#gQ delta 290 zcmdlJ)Dg_mz%sRVBg;HSTQ@B&EuYj(g^0{l9fg3R{It~K;`|~V1;6~Fl8o}y;*!*& zJcWS#oXV2a(7epD)S}|dlFG?v7}fP1NYg&KTu^ng36n}aiTaSN)lqQH o$jnQelEEH3B}1%-JcB0d3yE$%#?-6KV+k{e$;@(dyxLtR0M_nlSO5S3 diff --git a/docs/m2met2/_build/doctrees/environment.pickle b/docs/m2met2/_build/doctrees/environment.pickle index ea9c740c17419d54ae9b20aa3cfc75fcdbc9dff3..4e86ccaa153e7e65487388a77fd2388dd0fef420 100644 GIT binary patch delta 1357 zcmY*YU2Icj81A=$V`DPAK{qBCTuVEww&TZ9sOUD3b?peKSqE&hoR*XJe3sL$r^hXe zKQ{(ea^f1_!-aR^#WZN5a4?p(Trr&7N1a`qN@oWcSMniOm9<+gpP(OzG|L(7hS1xwqC9`OO$<_H2d6?p8;U z-^U`_GtwC$DJuR^NsuAp@xm?7rarA9XN@ z@d9BTS6`Zgzx+{)!02rhhY}YHRYD zgrdK%x6?)A(_POJxD#|4_jflUup9sG88Sh#Ghu>|sjav+hoiUkNZdTHxzY2reDQHfZU)4gLFMrp^#F?{^vBho4>#KlOFOhUm}m zMc4&RgR`V$%nzznyHK&n8ZK9aaIF|ap_oIJSP&&*4)uvVMN2StvWJvl=45yPg(}js zHT=)xvK8rM1v_8CvDZT<{by{Ch z(G(XHF)hhrEGH^zI$y48SgBfquTHhrZm`&$Q`-YLZ&9mFk4vJtMC{Z}D-~vLowai; z)lyD@SJ<-GEU1}K(!TJqUY+Ib<-B<;F0pm&#&Qlm5FGC2GUJtXt5%jB<0vO#MhF}T vuVerGF*GO8h-i+W=|vMqlR`6$<`9|~nkbsLz#m^;+m?DhwautYY^nMmTo2JB delta 1347 zcmY*YUrbY181DfQK_)9@z=|Z;b}iajz%c|nH^pg7!DuwVL>S!Go8Eh5x0Q0IW0`wd zuw8Dn*>`!^<4nYjnQi9k3+_*%2@jYkPz9Hm#iu1(vMgEL9v1iKeCM_|>C5;1e&3&S zzw^82n_D7tOXQo&F8JEz*;pnkr^Iux;@Z|!d1Nv!DDt#8nbNiL0|{kHh)wBQ*)erO zOc|B#($WuCN^G{!{vYi>U-`(nPS-3pLptcH#nNB>Mwcz7HNHn5TI}K%*XX*%vVR|@ z4=e_CO*Ch*+1uw;t?HDR6xoDIOcql*XkLFg&TvU@fpu>aeD8g+BFn#w5vR`y|9G3~ zv;2E3qS@tlgt(Y$jjEC=L&WEAE<~m!naW~-CgZyHe7@?8EGRJVYjjoT1E&*8Jdjja zi6bA0Nun|>sR_vW-X$v#X?aT4;EnCQWYx%Qf0dABL?unxLf_rag7Zm8~Y!cB%R1l-Wj_7=$PZs?CV zV6N>B{KsNi`}GmLKfS~b=K9mm5ux_Y@{Iv6v-twW~?^mi*vl?J#L4nzGO4>a^H!lQvsP+sd|DxHMi2R+8!$a9;4 z1QSfEakx4dhI>H|IEKC@Ib(T9E!lG&JOpG z94rh+22ivtohj!JkV}}Q=_2-V5z~s;#Uhq1Fyq9@XN1o+s`I&+!~e+~&cz(g#T?GX z9L~jD4la!L`|&y%-j(4^Y2K6OEg9aC;SFh;GyWYNDQT}_znpCb#m1~wof5``)Z~~j z8I$-!pV8^&q6!B*@zz$c@Rodd6}}vIR#aQ;-uO#hIAB(*m^jBbN{s8QzCK@J<~CWY z#8S0|6!?X$yUl{~>C{9Zax{dkFBJ0TvAC9OQO#o;3OP70)OqU)j8|5kRjFCaC$JZi zupo5p4Q*l%ehkeB8VOAVjfiFt&6{XWpgD@>IGQM$!_XRCE88YDOD>}_wzcGc>RZim diff --git a/docs/m2met2/_build/html/Organizers.html b/docs/m2met2/_build/html/Organizers.html index 0a8811e78..6daffe26e 100644 --- a/docs/m2met2/_build/html/Organizers.html +++ b/docs/m2met2/_build/html/Organizers.html @@ -124,7 +124,7 @@

Organizers

-

Lei Xie, Professor, Northwestern Polytechnical University, China

+

Lei Xie, Professor, AISHELL foundation, China

Email: lxie@nwpu.edu.cn

lxie

Kong Aik Lee, Senior Scientist at Institute for Infocomm Research, A*Star, Singapore

diff --git a/docs/m2met2/_build/html/_sources/Organizers.md.txt b/docs/m2met2/_build/html/_sources/Organizers.md.txt index e16c803af..f5a9da2ba 100644 --- a/docs/m2met2/_build/html/_sources/Organizers.md.txt +++ b/docs/m2met2/_build/html/_sources/Organizers.md.txt @@ -1,5 +1,5 @@ # Organizers -***Lei Xie, Professor, Northwestern Polytechnical University, China*** +***Lei Xie, Professor, AISHELL foundation, China*** Email: [lxie@nwpu.edu.cn](mailto:lxie@nwpu.edu.cn) diff --git a/docs/m2met2/_build/html/searchindex.js b/docs/m2met2/_build/html/searchindex.js index 54443a001..ec81fa7b2 100644 --- a/docs/m2met2/_build/html/searchindex.js +++ b/docs/m2met2/_build/html/searchindex.js @@ -1 +1 @@ -Search.setIndex({"docnames": ["Baseline", "Contact", "Dataset", "Introduction", "Organizers", "Rules", "Track_setting_and_evaluation", "index"], "filenames": ["Baseline.md", "Contact.md", "Dataset.md", "Introduction.md", "Organizers.md", "Rules.md", "Track_setting_and_evaluation.md", "index.rst"], "titles": ["Baseline", "Contact", "Datasets", "Introduction", "Organizers", "Rules", "Track & Evaluation", "ASRU 2023 MULTI-CHANNEL MULTI-PARTY MEETING TRANSCRIPTION CHALLENGE 2.0 (M2MeT2.0)"], "terms": {"we": [0, 2, 3, 7], "releas": [0, 2, 3, 6], "an": [0, 2, 3, 6], "e2": 0, "sa": 0, "asr": [0, 3, 7], "cite": 0, "kanda21b_interspeech": 0, "conduct": [0, 2], "funasr": 0, "time": [0, 6], "accord": [0, 3], "timelin": [0, 2], "The": [0, 2, 3, 5, 6], "model": [0, 2, 3, 5, 6], "architectur": 0, "i": [0, 2, 3, 5], "shown": [0, 2], "figur": [0, 6], "3": [0, 2, 3], "speakerencod": 0, "initi": 0, "pre": [0, 6], "train": [0, 3, 5, 7], "speaker": [0, 2, 3, 7], "verif": 0, "from": [0, 2, 3, 5, 6], "modelscop": [0, 6], "thi": [0, 3, 5, 6], "also": [0, 2, 6], "us": [0, 2, 5, 6], "extract": 0, "embed": 0, "profil": 0, "todo": 0, "fill": 0, "readm": 0, "md": 0, "system": [0, 3, 5, 6, 7], "ar": [0, 2, 3, 5, 6, 7], "tabl": [0, 2], "adopt": 0, "oracl": [0, 6], "dure": [0, 2, 6], "howev": [0, 3, 6], "due": [0, 3], "lack": 0, "label": [0, 5, 6], "evalu": [0, 2, 3, 7], "provid": [0, 2, 6, 7], "addit": [0, 6], "spectral": 0, "cluster": 0, "meanwhil": 0, "eval": [0, 2, 5, 6], "test": [0, 2, 3, 5, 6], "set": [0, 2, 3, 5, 6], "show": 0, "impact": 0, "accuraci": [0, 6], "If": [1, 5, 6], "you": 1, "have": [1, 3], "ani": [1, 5, 6], "question": 1, "about": 1, "m2met2": [1, 3], "0": [1, 2, 3], "challeng": [1, 3, 5, 6], "pleas": 1, "u": [1, 2], "email": [1, 3, 4], "m2met": [1, 3, 6, 7], "alimeet": [1, 6], "gmail": 1, "com": [1, 4], "wechat": 1, "group": [1, 2], "In": [2, 3, 5], "fix": [2, 3, 7], "condit": [2, 3, 7], "restrict": 2, "three": [2, 3, 6], "publicli": [2, 6], "avail": [2, 6], "corpora": 2, "name": 2, "aishel": [2, 4, 6], "4": [2, 6], "cn": [2, 4, 6], "celeb": [2, 6], "To": [2, 3, 7], "perform": [2, 3], "new": [2, 3, 6], "call": 2, "2023": [2, 3, 5, 6], "score": [2, 6], "rank": [2, 3, 6], "describ": 2, "contain": [2, 6], "118": 2, "75": 2, "hour": [2, 3, 6], "speech": [2, 3, 6, 7], "total": [2, 6], "divid": [2, 6], "104": 2, "10": [2, 3, 6], "specif": [2, 6], "212": 2, "8": [2, 3], "20": 2, "session": [2, 3, 6, 7], "respect": 2, "each": [2, 3, 6], "consist": [2, 6], "15": [2, 3], "30": 2, "minut": 2, "discuss": 2, "particip": [2, 5, 6], "number": [2, 3, 6], "456": 2, "25": 2, "60": 2, "balanc": 2, "gender": 2, "coverag": 2, "collect": 2, "13": [2, 3], "meet": [2, 3, 6], "venu": 2, "which": [2, 3, 6], "categor": 2, "type": 2, "small": 2, "medium": 2, "larg": [2, 3], "room": [2, 3], "size": 2, "rang": 2, "m": 2, "2": [2, 6], "55": 2, "differ": [2, 3, 6], "give": 2, "varieti": 2, "acoust": [2, 3, 6], "properti": 2, "layout": 2, "paramet": [2, 5], "togeth": 2, "wall": 2, "materi": 2, "cover": 2, "cement": 2, "glass": 2, "etc": 2, "other": 2, "furnish": 2, "includ": [2, 3, 5, 6], "sofa": 2, "tv": 2, "blackboard": 2, "fan": 2, "air": 2, "condition": 2, "plant": 2, "record": [2, 6], "sit": 2, "around": 2, "microphon": [2, 3], "arrai": [2, 3], "place": 2, "natur": 2, "convers": 2, "distanc": 2, "5": 2, "all": [2, 3, 5, 6], "nativ": 2, "chines": 2, "speak": [2, 3], "mandarin": [2, 3], "without": 2, "strong": 2, "accent": 2, "variou": [2, 3], "kind": 2, "indoor": 2, "nois": [2, 3, 5], "limit": [2, 3, 5], "click": 2, "keyboard": 2, "door": 2, "open": [2, 3, 7], "close": 2, "bubbl": 2, "made": [2, 3], "For": 2, "both": [2, 6], "requir": [2, 3, 6], "remain": [2, 3], "same": [2, 5], "posit": 2, "There": 2, "overlap": [2, 3], "between": [2, 6], "exampl": 2, "fig": 2, "1": 2, "within": [2, 3], "one": [2, 5], "ensur": 2, "ratio": 2, "select": [2, 3, 5, 6], "topic": 2, "medic": 2, "treatment": 2, "educ": 2, "busi": 2, "organ": [2, 3, 5, 6, 7], "manag": 2, "industri": [2, 3], "product": 2, "daili": 2, "routin": 2, "averag": 2, "42": 2, "27": 2, "34": 2, "76": 2, "more": 2, "A": [2, 4], "distribut": 2, "were": 2, "ident": [2, 6], "compris": [2, 3, 7], "therebi": 2, "share": 2, "similar": 2, "configur": 2, "field": [2, 3, 6], "signal": [2, 3], "headset": 2, "onli": [2, 5, 6], "": [2, 6], "own": 2, "transcrib": [2, 3, 6], "It": [2, 6], "worth": [2, 6], "note": [2, 6], "far": [2, 3], "audio": [2, 3, 6], "synchron": 2, "common": 2, "transcript": [2, 3, 5, 6], "prepar": 2, "textgrid": 2, "format": 2, "inform": [2, 3], "durat": 2, "id": 2, "segment": [2, 6], "timestamp": [2, 6], "mention": 2, "abov": 2, "can": [2, 3, 5, 6], "download": 2, "openslr": 2, "via": 2, "follow": [2, 5], "link": 2, "particularli": 2, "baselin": [2, 3, 7], "conveni": 2, "script": 2, "automat": [3, 7], "recognit": [3, 7], "diariz": 3, "signific": 3, "stride": 3, "recent": 3, "year": 3, "result": 3, "surg": 3, "technologi": 3, "applic": 3, "across": 3, "domain": 3, "present": 3, "uniqu": [3, 6], "complex": [3, 5], "divers": 3, "style": 3, "variabl": 3, "confer": 3, "environment": 3, "reverber": [3, 5], "over": 3, "sever": 3, "been": 3, "advanc": [3, 7], "develop": [3, 6], "rich": 3, "comput": [3, 5], "hear": 3, "multisourc": 3, "environ": 3, "chime": 3, "latest": 3, "iter": 3, "ha": 3, "particular": 3, "focu": 3, "distant": 3, "gener": 3, "topologi": 3, "scenario": 3, "while": 3, "progress": 3, "english": 3, "languag": [3, 5], "barrier": 3, "achiev": 3, "compar": 3, "non": 3, "multimod": 3, "base": 3, "process": [3, 6], "misp": 3, "multi": [3, 6], "channel": 3, "parti": [3, 6], "instrument": 3, "seek": 3, "address": 3, "problem": 3, "visual": 3, "everydai": 3, "home": 3, "focus": 3, "tackl": 3, "issu": 3, "offlin": 3, "icassp2022": 3, "two": [3, 5, 7], "main": 3, "task": [3, 6, 7], "former": 3, "involv": [3, 6], "identifi": 3, "who": 3, "spoke": 3, "when": 3, "latter": 3, "aim": 3, "multipl": [3, 6], "simultan": 3, "pose": [3, 6], "technic": 3, "difficulti": 3, "interfer": 3, "build": [3, 6, 7], "success": [3, 7], "previou": 3, "excit": 3, "propos": [3, 7], "asru2023": [3, 7], "special": [3, 5, 7], "origin": [3, 5], "metric": [3, 7], "wa": [3, 6], "independ": 3, "meant": 3, "could": 3, "determin": 3, "correspond": [3, 5], "further": 3, "current": [3, 7], "talker": [3, 7], "toward": 3, "practic": 3, "attribut": [3, 7], "sub": [3, 5, 7], "track": [3, 5, 7], "what": 3, "facilit": [3, 7], "reproduc": [3, 7], "research": [3, 4, 7], "offer": 3, "comprehens": [3, 7], "overview": [3, 7], "dataset": [3, 5, 6, 7], "rule": [3, 7], "furthermor": 3, "carefulli": 3, "curat": 3, "approxim": [3, 6], "design": 3, "enabl": 3, "valid": 3, "state": [3, 6, 7], "art": [3, 7], "area": 3, "april": 3, "29": 3, "registr": 3, "mai": 3, "deadlin": 3, "date": 3, "join": 3, "june": 3, "9": 3, "data": [3, 5, 6], "leaderboard": 3, "final": [3, 5, 6], "submiss": 3, "19": 3, "juli": 3, "paper": [3, 6], "decemb": 3, "12": 3, "16": 3, "asru": 3, "workshop": 3, "interest": 3, "whether": 3, "academia": 3, "must": [3, 5, 6], "regist": 3, "complet": 3, "googl": 3, "form": 3, "below": 3, "work": 3, "dai": 3, "send": 3, "invit": 3, "elig": [3, 5], "team": 3, "qualifi": 3, "adher": [3, 5], "publish": 3, "page": 3, "prior": 3, "submit": 3, "descript": [3, 6], "document": 3, "detail": [3, 6], "approach": [3, 5], "method": 3, "top": 3, "proceed": 3, "lei": 4, "xie": 4, "professor": 4, "northwestern": 4, "polytechn": 4, "univers": 4, "china": 4, "lxie": 4, "nwpu": 4, "edu": 4, "kong": 4, "aik": 4, "lee": 4, "senior": 4, "scientist": 4, "institut": 4, "infocomm": 4, "star": 4, "singapor": 4, "kongaik": 4, "ieee": 4, "org": 4, "zhiji": 4, "yan": 4, "princip": 4, "engin": 4, "alibaba": 4, "yzj": 4, "inc": 4, "shiliang": 4, "zhang": 4, "sly": 4, "zsl": 4, "yanmin": 4, "qian": 4, "shanghai": 4, "jiao": 4, "tong": 4, "yanminqian": 4, "sjtu": 4, "zhuo": 4, "chen": 4, "appli": 4, "microsoft": 4, "usa": 4, "zhuc": 4, "jian": 4, "wu": 4, "wujian": 4, "hui": 4, "bu": 4, "ceo": 4, "foundat": 4, "buhui": 4, "aishelldata": 4, "should": 5, "augment": 5, "allow": [5, 6], "ad": 5, "speed": 5, "perturb": 5, "tone": 5, "chang": 5, "permit": 5, "purpos": 5, "instead": [5, 6], "util": [5, 6], "tune": 5, "violat": 5, "strictli": [5, 6], "prohibit": [5, 6], "fine": 5, "cpcer": [5, 6], "lower": 5, "judg": 5, "superior": 5, "forc": 5, "align": 5, "obtain": [5, 6], "frame": 5, "level": 5, "classif": 5, "basi": 5, "shallow": 5, "fusion": 5, "end": 5, "e": [5, 6], "g": 5, "la": 5, "rnnt": 5, "transform": [5, 6], "come": 5, "right": 5, "interpret": 5, "belong": 5, "case": 5, "circumst": 5, "coordin": 5, "assign": 6, "illustr": 6, "aishell4": 6, "constrain": 6, "sourc": 6, "addition": 6, "corpu": 6, "soon": 6, "simpl": 6, "voic": 6, "activ": 6, "detect": 6, "vad": 6, "concaten": 6, "minimum": 6, "permut": 6, "charact": 6, "error": 6, "rate": 6, "calcul": 6, "step": 6, "firstli": 6, "refer": 6, "hypothesi": 6, "chronolog": 6, "order": 6, "secondli": 6, "cer": 6, "repeat": 6, "possibl": 6, "lowest": 6, "tthe": 6, "insert": 6, "Ins": 6, "substitut": 6, "delet": 6, "del": 6, "output": 6, "text": 6, "frac": 6, "mathcal": 6, "n_": 6, "100": 6, "where": 6, "usag": 6, "third": 6, "hug": 6, "face": 6, "list": 6, "clearli": 6, "privat": 6, "manual": 6, "simul": 6, "thei": 6, "mandatori": 6, "clear": 6, "scheme": 6, "delight": 7, "introduct": 7, "contact": 7}, "objects": {}, "objtypes": {}, "objnames": {}, "titleterms": {"baselin": 0, "overview": [0, 2], "quick": 0, "start": 0, "result": 0, "contact": 1, "dataset": 2, "train": [2, 6], "data": 2, "detail": 2, "alimeet": 2, "corpu": 2, "get": 2, "introduct": 3, "call": 3, "particip": 3, "timelin": 3, "aoe": 3, "time": 3, "guidelin": 3, "organ": 4, "rule": 5, "track": 6, "evalu": 6, "speaker": 6, "attribut": 6, "asr": 6, "metric": 6, "sub": 6, "arrang": 6, "i": 6, "fix": 6, "condit": 6, "ii": 6, "open": 6, "asru": 7, "2023": 7, "multi": 7, "channel": 7, "parti": 7, "meet": 7, "transcript": 7, "challeng": 7, "2": 7, "0": 7, "m2met2": 7, "content": 7}, "envversion": {"sphinx.domains.c": 2, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 8, "sphinx.domains.index": 1, "sphinx.domains.javascript": 2, "sphinx.domains.math": 2, "sphinx.domains.python": 3, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx": 57}, "alltitles": {"Baseline": [[0, "baseline"]], "Overview": [[0, "overview"]], "Quick start": [[0, "quick-start"]], "Baseline results": [[0, "baseline-results"]], "Contact": [[1, "contact"]], "Datasets": [[2, "datasets"]], "Overview of training data": [[2, "overview-of-training-data"]], "Detail of AliMeeting corpus": [[2, "detail-of-alimeeting-corpus"]], "Get the data": [[2, "get-the-data"]], "Introduction": [[3, "introduction"]], "Call for participation": [[3, "call-for-participation"]], "Timeline(AOE Time)": [[3, "timeline-aoe-time"]], "Guidelines": [[3, "guidelines"]], "Organizers": [[4, "organizers"]], "Rules": [[5, "rules"]], "Track & Evaluation": [[6, "track-evaluation"]], "Speaker-Attributed ASR": [[6, "speaker-attributed-asr"]], "Evaluation metric": [[6, "evaluation-metric"]], "Sub-track arrangement": [[6, "sub-track-arrangement"]], "Sub-track I (Fixed Training Condition):": [[6, "sub-track-i-fixed-training-condition"]], "Sub-track II (Open Training Condition):": [[6, "sub-track-ii-open-training-condition"]], "ASRU 2023 MULTI-CHANNEL MULTI-PARTY MEETING TRANSCRIPTION CHALLENGE 2.0 (M2MeT2.0)": [[7, "asru-2023-multi-channel-multi-party-meeting-transcription-challenge-2-0-m2met2-0"]], "Contents:": [[7, null]]}, "indexentries": {}}) \ No newline at end of file +Search.setIndex({"docnames": ["Baseline", "Contact", "Dataset", "Introduction", "Organizers", "Rules", "Track_setting_and_evaluation", "index"], "filenames": ["Baseline.md", "Contact.md", "Dataset.md", "Introduction.md", "Organizers.md", "Rules.md", "Track_setting_and_evaluation.md", "index.rst"], "titles": ["Baseline", "Contact", "Datasets", "Introduction", "Organizers", "Rules", "Track & Evaluation", "ASRU 2023 MULTI-CHANNEL MULTI-PARTY MEETING TRANSCRIPTION CHALLENGE 2.0 (M2MeT2.0)"], "terms": {"we": [0, 2, 3, 7], "releas": [0, 2, 3, 6], "an": [0, 2, 3, 6], "e2": 0, "sa": 0, "asr": [0, 3, 7], "cite": 0, "kanda21b_interspeech": 0, "conduct": [0, 2], "funasr": 0, "time": [0, 6], "accord": [0, 3], "timelin": [0, 2], "The": [0, 2, 3, 5, 6], "model": [0, 2, 3, 5, 6], "architectur": 0, "i": [0, 2, 3, 5], "shown": [0, 2], "figur": [0, 6], "3": [0, 2, 3], "speakerencod": 0, "initi": 0, "pre": [0, 6], "train": [0, 3, 5, 7], "speaker": [0, 2, 3, 7], "verif": 0, "from": [0, 2, 3, 5, 6], "modelscop": [0, 6], "thi": [0, 3, 5, 6], "also": [0, 2, 6], "us": [0, 2, 5, 6], "extract": 0, "embed": 0, "profil": 0, "todo": 0, "fill": 0, "readm": 0, "md": 0, "system": [0, 3, 5, 6, 7], "ar": [0, 2, 3, 5, 6, 7], "tabl": [0, 2], "adopt": 0, "oracl": [0, 6], "dure": [0, 2, 6], "howev": [0, 3, 6], "due": [0, 3], "lack": 0, "label": [0, 5, 6], "evalu": [0, 2, 3, 7], "provid": [0, 2, 6, 7], "addit": [0, 6], "spectral": 0, "cluster": 0, "meanwhil": 0, "eval": [0, 2, 5, 6], "test": [0, 2, 3, 5, 6], "set": [0, 2, 3, 5, 6], "show": 0, "impact": 0, "accuraci": [0, 6], "If": [1, 5, 6], "you": 1, "have": [1, 3], "ani": [1, 5, 6], "question": 1, "about": 1, "m2met2": [1, 3], "0": [1, 2, 3], "challeng": [1, 3, 5, 6], "pleas": 1, "u": [1, 2], "email": [1, 3, 4], "m2met": [1, 3, 6, 7], "alimeet": [1, 6], "gmail": 1, "com": [1, 4], "wechat": 1, "group": [1, 2], "In": [2, 3, 5], "fix": [2, 3, 7], "condit": [2, 3, 7], "restrict": 2, "three": [2, 3, 6], "publicli": [2, 6], "avail": [2, 6], "corpora": 2, "name": 2, "aishel": [2, 4, 6], "4": [2, 6], "cn": [2, 4, 6], "celeb": [2, 6], "To": [2, 3, 7], "perform": [2, 3], "new": [2, 3, 6], "call": 2, "2023": [2, 3, 5, 6], "score": [2, 6], "rank": [2, 3, 6], "describ": 2, "contain": [2, 6], "118": 2, "75": 2, "hour": [2, 3, 6], "speech": [2, 3, 6, 7], "total": [2, 6], "divid": [2, 6], "104": 2, "10": [2, 3, 6], "specif": [2, 6], "212": 2, "8": [2, 3], "20": 2, "session": [2, 3, 6, 7], "respect": 2, "each": [2, 3, 6], "consist": [2, 6], "15": [2, 3], "30": 2, "minut": 2, "discuss": 2, "particip": [2, 5, 6], "number": [2, 3, 6], "456": 2, "25": 2, "60": 2, "balanc": 2, "gender": 2, "coverag": 2, "collect": 2, "13": [2, 3], "meet": [2, 3, 6], "venu": 2, "which": [2, 3, 6], "categor": 2, "type": 2, "small": 2, "medium": 2, "larg": [2, 3], "room": [2, 3], "size": 2, "rang": 2, "m": 2, "2": [2, 6], "55": 2, "differ": [2, 3, 6], "give": 2, "varieti": 2, "acoust": [2, 3, 6], "properti": 2, "layout": 2, "paramet": [2, 5], "togeth": 2, "wall": 2, "materi": 2, "cover": 2, "cement": 2, "glass": 2, "etc": 2, "other": 2, "furnish": 2, "includ": [2, 3, 5, 6], "sofa": 2, "tv": 2, "blackboard": 2, "fan": 2, "air": 2, "condition": 2, "plant": 2, "record": [2, 6], "sit": 2, "around": 2, "microphon": [2, 3], "arrai": [2, 3], "place": 2, "natur": 2, "convers": 2, "distanc": 2, "5": 2, "all": [2, 3, 5, 6], "nativ": 2, "chines": 2, "speak": [2, 3], "mandarin": [2, 3], "without": 2, "strong": 2, "accent": 2, "variou": [2, 3], "kind": 2, "indoor": 2, "nois": [2, 3, 5], "limit": [2, 3, 5], "click": 2, "keyboard": 2, "door": 2, "open": [2, 3, 7], "close": 2, "bubbl": 2, "made": [2, 3], "For": 2, "both": [2, 6], "requir": [2, 3, 6], "remain": [2, 3], "same": [2, 5], "posit": 2, "There": 2, "overlap": [2, 3], "between": [2, 6], "exampl": 2, "fig": 2, "1": 2, "within": [2, 3], "one": [2, 5], "ensur": 2, "ratio": 2, "select": [2, 3, 5, 6], "topic": 2, "medic": 2, "treatment": 2, "educ": 2, "busi": 2, "organ": [2, 3, 5, 6, 7], "manag": 2, "industri": [2, 3], "product": 2, "daili": 2, "routin": 2, "averag": 2, "42": 2, "27": 2, "34": 2, "76": 2, "more": 2, "A": [2, 4], "distribut": 2, "were": 2, "ident": [2, 6], "compris": [2, 3, 7], "therebi": 2, "share": 2, "similar": 2, "configur": 2, "field": [2, 3, 6], "signal": [2, 3], "headset": 2, "onli": [2, 5, 6], "": [2, 6], "own": 2, "transcrib": [2, 3, 6], "It": [2, 6], "worth": [2, 6], "note": [2, 6], "far": [2, 3], "audio": [2, 3, 6], "synchron": 2, "common": 2, "transcript": [2, 3, 5, 6], "prepar": 2, "textgrid": 2, "format": 2, "inform": [2, 3], "durat": 2, "id": 2, "segment": [2, 6], "timestamp": [2, 6], "mention": 2, "abov": 2, "can": [2, 3, 5, 6], "download": 2, "openslr": 2, "via": 2, "follow": [2, 5], "link": 2, "particularli": 2, "baselin": [2, 3, 7], "conveni": 2, "script": 2, "automat": [3, 7], "recognit": [3, 7], "diariz": 3, "signific": 3, "stride": 3, "recent": 3, "year": 3, "result": 3, "surg": 3, "technologi": 3, "applic": 3, "across": 3, "domain": 3, "present": 3, "uniqu": [3, 6], "complex": [3, 5], "divers": 3, "style": 3, "variabl": 3, "confer": 3, "environment": 3, "reverber": [3, 5], "over": 3, "sever": 3, "been": 3, "advanc": [3, 7], "develop": [3, 6], "rich": 3, "comput": [3, 5], "hear": 3, "multisourc": 3, "environ": 3, "chime": 3, "latest": 3, "iter": 3, "ha": 3, "particular": 3, "focu": 3, "distant": 3, "gener": 3, "topologi": 3, "scenario": 3, "while": 3, "progress": 3, "english": 3, "languag": [3, 5], "barrier": 3, "achiev": 3, "compar": 3, "non": 3, "multimod": 3, "base": 3, "process": [3, 6], "misp": 3, "multi": [3, 6], "channel": 3, "parti": [3, 6], "instrument": 3, "seek": 3, "address": 3, "problem": 3, "visual": 3, "everydai": 3, "home": 3, "focus": 3, "tackl": 3, "issu": 3, "offlin": 3, "icassp2022": 3, "two": [3, 5, 7], "main": 3, "task": [3, 6, 7], "former": 3, "involv": [3, 6], "identifi": 3, "who": 3, "spoke": 3, "when": 3, "latter": 3, "aim": 3, "multipl": [3, 6], "simultan": 3, "pose": [3, 6], "technic": 3, "difficulti": 3, "interfer": 3, "build": [3, 6, 7], "success": [3, 7], "previou": 3, "excit": 3, "propos": [3, 7], "asru2023": [3, 7], "special": [3, 5, 7], "origin": [3, 5], "metric": [3, 7], "wa": [3, 6], "independ": 3, "meant": 3, "could": 3, "determin": 3, "correspond": [3, 5], "further": 3, "current": [3, 7], "talker": [3, 7], "toward": 3, "practic": 3, "attribut": [3, 7], "sub": [3, 5, 7], "track": [3, 5, 7], "what": 3, "facilit": [3, 7], "reproduc": [3, 7], "research": [3, 4, 7], "offer": 3, "comprehens": [3, 7], "overview": [3, 7], "dataset": [3, 5, 6, 7], "rule": [3, 7], "furthermor": 3, "carefulli": 3, "curat": 3, "approxim": [3, 6], "design": 3, "enabl": 3, "valid": 3, "state": [3, 6, 7], "art": [3, 7], "area": 3, "april": 3, "29": 3, "registr": 3, "mai": 3, "deadlin": 3, "date": 3, "join": 3, "june": 3, "9": 3, "data": [3, 5, 6], "leaderboard": 3, "final": [3, 5, 6], "submiss": 3, "19": 3, "juli": 3, "paper": [3, 6], "decemb": 3, "12": 3, "16": 3, "asru": 3, "workshop": 3, "interest": 3, "whether": 3, "academia": 3, "must": [3, 5, 6], "regist": 3, "complet": 3, "googl": 3, "form": 3, "below": 3, "work": 3, "dai": 3, "send": 3, "invit": 3, "elig": [3, 5], "team": 3, "qualifi": 3, "adher": [3, 5], "publish": 3, "page": 3, "prior": 3, "submit": 3, "descript": [3, 6], "document": 3, "detail": [3, 6], "approach": [3, 5], "method": 3, "top": 3, "proceed": 3, "lei": 4, "xie": 4, "professor": 4, "foundat": 4, "china": 4, "lxie": 4, "nwpu": 4, "edu": 4, "kong": 4, "aik": 4, "lee": 4, "senior": 4, "scientist": 4, "institut": 4, "infocomm": 4, "star": 4, "singapor": 4, "kongaik": 4, "ieee": 4, "org": 4, "zhiji": 4, "yan": 4, "princip": 4, "engin": 4, "alibaba": 4, "yzj": 4, "inc": 4, "shiliang": 4, "zhang": 4, "sly": 4, "zsl": 4, "yanmin": 4, "qian": 4, "shanghai": 4, "jiao": 4, "tong": 4, "univers": 4, "yanminqian": 4, "sjtu": 4, "zhuo": 4, "chen": 4, "appli": 4, "microsoft": 4, "usa": 4, "zhuc": 4, "jian": 4, "wu": 4, "wujian": 4, "hui": 4, "bu": 4, "ceo": 4, "buhui": 4, "aishelldata": 4, "should": 5, "augment": 5, "allow": [5, 6], "ad": 5, "speed": 5, "perturb": 5, "tone": 5, "chang": 5, "permit": 5, "purpos": 5, "instead": [5, 6], "util": [5, 6], "tune": 5, "violat": 5, "strictli": [5, 6], "prohibit": [5, 6], "fine": 5, "cpcer": [5, 6], "lower": 5, "judg": 5, "superior": 5, "forc": 5, "align": 5, "obtain": [5, 6], "frame": 5, "level": 5, "classif": 5, "basi": 5, "shallow": 5, "fusion": 5, "end": 5, "e": [5, 6], "g": 5, "la": 5, "rnnt": 5, "transform": [5, 6], "come": 5, "right": 5, "interpret": 5, "belong": 5, "case": 5, "circumst": 5, "coordin": 5, "assign": 6, "illustr": 6, "aishell4": 6, "constrain": 6, "sourc": 6, "addition": 6, "corpu": 6, "soon": 6, "simpl": 6, "voic": 6, "activ": 6, "detect": 6, "vad": 6, "concaten": 6, "minimum": 6, "permut": 6, "charact": 6, "error": 6, "rate": 6, "calcul": 6, "step": 6, "firstli": 6, "refer": 6, "hypothesi": 6, "chronolog": 6, "order": 6, "secondli": 6, "cer": 6, "repeat": 6, "possibl": 6, "lowest": 6, "tthe": 6, "insert": 6, "Ins": 6, "substitut": 6, "delet": 6, "del": 6, "output": 6, "text": 6, "frac": 6, "mathcal": 6, "n_": 6, "100": 6, "where": 6, "usag": 6, "third": 6, "hug": 6, "face": 6, "list": 6, "clearli": 6, "privat": 6, "manual": 6, "simul": 6, "thei": 6, "mandatori": 6, "clear": 6, "scheme": 6, "delight": 7, "introduct": 7, "contact": 7}, "objects": {}, "objtypes": {}, "objnames": {}, "titleterms": {"baselin": 0, "overview": [0, 2], "quick": 0, "start": 0, "result": 0, "contact": 1, "dataset": 2, "train": [2, 6], "data": 2, "detail": 2, "alimeet": 2, "corpu": 2, "get": 2, "introduct": 3, "call": 3, "particip": 3, "timelin": 3, "aoe": 3, "time": 3, "guidelin": 3, "organ": 4, "rule": 5, "track": 6, "evalu": 6, "speaker": 6, "attribut": 6, "asr": 6, "metric": 6, "sub": 6, "arrang": 6, "i": 6, "fix": 6, "condit": 6, "ii": 6, "open": 6, "asru": 7, "2023": 7, "multi": 7, "channel": 7, "parti": 7, "meet": 7, "transcript": 7, "challeng": 7, "2": 7, "0": 7, "m2met2": 7, "content": 7}, "envversion": {"sphinx.domains.c": 2, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 8, "sphinx.domains.index": 1, "sphinx.domains.javascript": 2, "sphinx.domains.math": 2, "sphinx.domains.python": 3, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx": 57}, "alltitles": {"Baseline": [[0, "baseline"]], "Overview": [[0, "overview"]], "Quick start": [[0, "quick-start"]], "Baseline results": [[0, "baseline-results"]], "Contact": [[1, "contact"]], "Datasets": [[2, "datasets"]], "Overview of training data": [[2, "overview-of-training-data"]], "Detail of AliMeeting corpus": [[2, "detail-of-alimeeting-corpus"]], "Get the data": [[2, "get-the-data"]], "Introduction": [[3, "introduction"]], "Call for participation": [[3, "call-for-participation"]], "Timeline(AOE Time)": [[3, "timeline-aoe-time"]], "Guidelines": [[3, "guidelines"]], "Organizers": [[4, "organizers"]], "Rules": [[5, "rules"]], "Track & Evaluation": [[6, "track-evaluation"]], "Speaker-Attributed ASR": [[6, "speaker-attributed-asr"]], "Evaluation metric": [[6, "evaluation-metric"]], "Sub-track arrangement": [[6, "sub-track-arrangement"]], "Sub-track I (Fixed Training Condition):": [[6, "sub-track-i-fixed-training-condition"]], "Sub-track II (Open Training Condition):": [[6, "sub-track-ii-open-training-condition"]], "ASRU 2023 MULTI-CHANNEL MULTI-PARTY MEETING TRANSCRIPTION CHALLENGE 2.0 (M2MeT2.0)": [[7, "asru-2023-multi-channel-multi-party-meeting-transcription-challenge-2-0-m2met2-0"]], "Contents:": [[7, null]]}, "indexentries": {}}) \ No newline at end of file diff --git a/docs/m2met2_cn/_build/doctrees/environment.pickle b/docs/m2met2_cn/_build/doctrees/environment.pickle index fb92f83a040224afdf7aae847237bdc3d0a0a996..91ebda67a97f008d62b1b445b3559013f56dcac6 100644 GIT binary patch delta 1548 zcmY*ZZ%k8H6!$`rKS2e{5QteOZGZ|C1{-p7j?p(Wd zZh3YRZsh0XrmoFiSh*=L&s~wl^k?VgH8#6C{q@S+CH7r@V&YgZVat}r`lmbh-TnEk z6LcZQUesKpk7DeX-VypZ#(o`tL6>6ew{D3(iLsYzi7sxkAIvlqW9y5R0WsYn3=6zu zPrqC6$zUufCJW##s7=P(F3Cj@EXYe0bKOIBr{F6Cdyo34q};}R;`WI7jBikHwl>OQ zX2kGbfV%A-Jsoz+;*N;zl-J|b4|}*JBVri|#|TcSEiBPRbI-Wk)GdT_qmhH7ibZhB z5)HxSLJwK^s3=4p!BWw4@)+*wf-qXV9j@)IAy44x-os=Obj62Bh`nE&Nk|YTOV**M zOas?T+h9nqfw7uhP^v!&%UqZAZO~D!f#kAwo@^`o5dJ9Dz`tdkB*a-hd{FK`iDRKt zi5zew^mEkkfha=_M?t?u4aYzqqJ|@&KcR-tPuEbxr>7fS3y3Pex8En9m5XSQS>7}d zNNdr;mlbm)$UK!D32@F_1=gecdBIuGRAmCIMa#ab$|hXNgpB$mD7UKFMs;1(ki$;y zkC7x$9aFP=2bu}^4PM@?4eE?qmhet4;mT%yLoJWs26m&aC#+=DI|zJl3g0d1v*0g- z38tI0tl!A*o^IOA{j9;P7}%>r?NLt-JKM-l+-RwS;pTl%-DHD>RxQjl&GUynZ(f9{ z3N838^N>-45m!K}%LJ=Y4f>XOn19>LpIQUsttNO-t=QS`twn?r9Wz>aa}TPsfi|ky z7e|Z)t{%{_UB^lkD?8EV3M)Sz|C?0cuq;HGltrbCi3^+&7dRm9!|8B=qv0Y1st$t+ z)8JKQA&hjqaU6+652}CQVvL(mx|mR!m{5ASsI)MlWK1Xt6EwsoyBrC8Z(nxrG2;g+iRwPPPZ)H2 z1lwuB7Z~&_i#IOQbpG}6%~cMR#Ec<9@Vh-u+i9pXY8UkHCyT`I43=5US)XhcY zhh@h3Qeq3vU9ZKt(*C#8+_@vpnH>FlaL>*-PwI#p{_IhcB}lWq&QWLEJr=GbtuNpT zxcNVV{}FgvP9zN%OcJ;G?Y>hshkIZk(oz6B?o8p!*Nb357(i%6XhSd{^dqz*m=KO2 fbR!(%AoYpKjzPF*dzh?s?Qv;b`RtS4yoCP%*nA=S delta 1600 zcmZWpZA?>V6!wK8LU2-x_%X6f+5nYN7-lex6DT011+0jQL%0@tp?!rGY@0dU!psPx z;WCQn&g|od*?#DcZN_=G9|N+lD9N&jC?$*AuO)owpScgR{n+O@w;!(ApL5Rhp7Y%I zyzg_*d;KQ6ev@5uQFZTfR~J$Ki}6t~AIo>jigO->$OO4_iYzWSba^}|<3 zX8B?qjZPKu+i^7Z!^iwi9E}@4;CJI_;^8qqA4iks%X}e@rs~RgIF8`8Z2>96DGrFZ zzo*+R`edldD`bn{%{!1vyG_akFrSw*ENyr9J9-x^BRU(!>7Nh$5OjdinEa{>P-7e8HqyjZAZYzfAn`Wf0v^l+)D6}~Ul!|?v?P-LotUyJk*GPOd#Ne`*T$B`@)zl3A~ zYyK%d0n504uEc+m6yp=gXhPMh4?LsNFDwiMWhU0qli@D>lg(j zjo;htlV6q#_>y9K+RVUiGr&isvusK6>}^Ye^(HSin*|MJ7MO1~D4&#NGx)J38%pdt zWxc#I0(iYnIa#3sqjFLXM(%!4Js#y8E?pQ3L@OpuP-&_U*jn6`P zg8-E^2AFP`gSlsDtpXle9q>)L7VI@T@Z09_V$WMWc(FU-t40eB0Zl& zfkvAxaIwLl{L);&Fi`teO6)B$utRzOa7_%PD4HX9_*mJAR@Wo&?a@D2DamGIs%AEg zDi}Ia3mr*?InoIoiG(f;nl`hBXzCwd@+g52uhOW4!XwC>fNB%a!31PUK-L&i zR@?rJwAUf4?V+Rp2_3bEj@m;}fj+-FQlm28jK3vLxcb46l=;6m0827rCD7iP zGpvmwYBVIJJ(_f^%udK{ijOX)wj`v||MQSwa%(~|btw8&U}jrFCT-9Szjf+x;?spE z&>DrD;Yc6pT>)3XjgJsM9Z1^|rP1Vtq|JVZ@3i1__w+S+pu delta 40 qcmZq6YRO`0V43=JBa06Yi#8(z!{%OI9Y*d9_Sh*IVi8b*N_7DD77GRd diff --git a/docs/m2met2_cn/_build/html/_sources/简介.md.txt b/docs/m2met2_cn/_build/html/_sources/简介.md.txt index 52df97d6b..f43dbabec 100644 --- a/docs/m2met2_cn/_build/html/_sources/简介.md.txt +++ b/docs/m2met2_cn/_build/html/_sources/简介.md.txt @@ -4,7 +4,7 @@ 为了推动会议场景语音识别的发展,已经有很多相关的挑战赛,如 Rich Transcription evaluation 和 CHIME(Computational Hearing in Multisource Environments) 挑战赛。最新的CHIME挑战赛关注于远距离自动语音识别和开发能在各种不同拓扑结构的阵列和应用场景中通用的系统。然而不同语言之间的差异限制了非英语会议转录的进展。MISP(Multimodal Information Based Speech Processing)和M2MeT(Multi-Channel Multi-Party Meeting Transcription)挑战赛为推动普通话会议场景语音识别做出了贡献。MISP挑战赛侧重于用视听多模态的方法解决日常家庭环境中的远距离多麦克风信号处理问题,而M2MeT挑战则侧重于解决离线会议室中会议转录的语音重叠问题。 -ASSP2022 M2MeT挑战的侧重点是会议场景,它包括两个赛道:说话人日记和多说话人自动语音识别。前者涉及识别“谁在什么时候说了话”,而后者旨在同时识别来自多个说话人的语音,语音重叠和各种噪声带来了巨大的技术困难。 +IASSP2022 M2MeT挑战的侧重点是会议场景,它包括两个赛道:说话人日记和多说话人自动语音识别。前者涉及识别“谁在什么时候说了话”,而后者旨在同时识别来自多个说话人的语音,语音重叠和各种噪声带来了巨大的技术困难。 在上一届M2MET成功举办的基础上,我们将在ASRU2023上继续举办M2MET2.0挑战赛。在上一届M2MET挑战赛中,评估指标是说话人无关的,我们只能得到识别文本,而不能确定相应的说话人。 为了解决这一局限性并将现在的多说话人语音识别系统推向实用化,M2MET2.0挑战赛将在说话人相关的人物上评估,并且同时设立限定数据与不限定数据两个子赛道。通过将语音归属于特定的说话人,这项任务旨在提高多说话人ASR系统在真实世界环境中的准确性和适用性。 diff --git a/docs/m2met2_cn/_build/html/searchindex.js b/docs/m2met2_cn/_build/html/searchindex.js index c9fe167cc..c2af3e243 100644 --- a/docs/m2met2_cn/_build/html/searchindex.js +++ b/docs/m2met2_cn/_build/html/searchindex.js @@ -1 +1 @@ -Search.setIndex({"docnames": ["index", "\u57fa\u7ebf", "\u6570\u636e\u96c6", "\u7b80\u4ecb", "\u7ec4\u59d4\u4f1a", "\u8054\u7cfb\u65b9\u5f0f", "\u89c4\u5219", "\u8d5b\u9053\u8bbe\u7f6e\u4e0e\u8bc4\u4f30"], "filenames": ["index.rst", "\u57fa\u7ebf.md", "\u6570\u636e\u96c6.md", "\u7b80\u4ecb.md", "\u7ec4\u59d4\u4f1a.md", "\u8054\u7cfb\u65b9\u5f0f.md", "\u89c4\u5219.md", "\u8d5b\u9053\u8bbe\u7f6e\u4e0e\u8bc4\u4f30.md"], "titles": ["ASRU 2023 \u591a\u901a\u9053\u591a\u65b9\u4f1a\u8bae\u8f6c\u5f55\u6311\u6218 2.0", "\u57fa\u7ebf", "\u6570\u636e\u96c6", "\u7b80\u4ecb", "\u7ec4\u59d4\u4f1a", "\u8054\u7cfb\u65b9\u5f0f", "\u7ade\u8d5b\u89c4\u5219", "\u8d5b\u9053\u8bbe\u7f6e\u4e0e\u8bc4\u4f30"], "terms": {"m2met": [0, 3, 5, 7], "asru2023": [0, 3], "m2met2": [0, 3, 5, 7], "funasr": 1, "sa": 1, "asr": [1, 3, 7], "speakerencod": 1, "modelscop": [1, 7], "todo": 1, "fill": 1, "with": 1, "the": 1, "readm": 1, "md": 1, "of": 1, "baselin": [1, 2], "aishel": [2, 7], "cn": [2, 4, 7], "celeb": [2, 7], "test": [2, 6, 7], "2023": [2, 3, 6, 7], "118": 2, "75": 2, "104": 2, "train": 2, "eval": [2, 6], "10": [2, 3, 7], "212": 2, "15": [2, 3], "30": 2, "456": 2, "25": 2, "13": [2, 3], "55": 2, "42": 2, "27": 2, "34": 2, "76": 2, "20": 2, "textgrid": 2, "id": 2, "openslr": 2, "automat": 3, "speech": 3, "recognit": 3, "speaker": 3, "diariz": 3, "rich": 3, "transcript": 3, "evalu": 3, "chime": 3, "comput": 3, "hear": 3, "in": 3, "multisourc": 3, "environ": 3, "misp": 3, "multimod": 3, "inform": 3, "base": 3, "process": 3, "multi": 3, "channel": 3, "parti": 3, "meet": 3, "assp2022": 3, "29": 3, "19": 3, "12": 3, "asru": 3, "workshop": 3, "challeng": 3, "session": 3, "lxie": 4, "nwpu": 4, "edu": 4, "kong": 4, "aik": 4, "lee": 4, "star": 4, "kongaik": 4, "ieee": 4, "org": 4, "zhiji": 4, "yzj": 4, "alibaba": 4, "inc": 4, "com": [4, 5], "sli": 4, "zsl": 4, "yanminqian": 4, "sjtu": 4, "zhuc": 4, "microsoft": 4, "wujian": 4, "ceo": 4, "buhui": 4, "aishelldata": 4, "alimeet": [5, 7], "gmail": 5, "cpcer": [6, 7], "las": 6, "rnnt": 6, "transform": 6, "aishell4": 7, "vad": 7, "cer": 7, "ins": 7, "sub": 7, "del": 7, "text": 7, "frac": 7, "mathcal": 7, "n_": 7, "total": 7, "time": 7, "100": 7, "hug": 7, "face": 7}, "objects": {}, "objtypes": {}, "objnames": {}, "titleterms": {"asru": 0, "2023": 0, "alimeet": 2, "aoe": 3}, "envversion": {"sphinx.domains.c": 2, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 8, "sphinx.domains.index": 1, "sphinx.domains.javascript": 2, "sphinx.domains.math": 2, "sphinx.domains.python": 3, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx": 57}, "alltitles": {"ASRU 2023 \u591a\u901a\u9053\u591a\u65b9\u4f1a\u8bae\u8f6c\u5f55\u6311\u6218 2.0": [[0, "asru-2023-2-0"]], "\u76ee\u5f55:": [[0, null]], "\u57fa\u7ebf": [[1, "id1"]], "\u57fa\u7ebf\u6982\u8ff0": [[1, "id2"]], "\u5feb\u901f\u5f00\u59cb": [[1, "id3"]], "\u57fa\u7ebf\u7ed3\u679c": [[1, "id4"]], "\u6570\u636e\u96c6": [[2, "id1"]], "\u6570\u636e\u96c6\u6982\u8ff0": [[2, "id2"]], "Alimeeting\u6570\u636e\u96c6\u4ecb\u7ecd": [[2, "alimeeting"]], "\u83b7\u53d6\u6570\u636e": [[2, "id3"]], "\u7b80\u4ecb": [[3, "id1"]], "\u7ade\u8d5b\u4ecb\u7ecd": [[3, "id2"]], "\u65f6\u95f4\u5b89\u6392(AOE\u65f6\u95f4)": [[3, "aoe"]], "\u7ade\u8d5b\u62a5\u540d": [[3, "id3"]], "\u7ec4\u59d4\u4f1a": [[4, "id1"]], "\u8054\u7cfb\u65b9\u5f0f": [[5, "id1"]], "\u7ade\u8d5b\u89c4\u5219": [[6, "id1"]], "\u8d5b\u9053\u8bbe\u7f6e\u4e0e\u8bc4\u4f30": [[7, "id1"]], "\u8bf4\u8bdd\u4eba\u76f8\u5173\u7684\u8bed\u97f3\u8bc6\u522b": [[7, "id2"]], "\u8bc4\u4f30\u65b9\u6cd5": [[7, "id3"]], "\u5b50\u8d5b\u9053\u8bbe\u7f6e": [[7, "id4"]], "\u5b50\u8d5b\u9053\u4e00 (\u9650\u5b9a\u8bad\u7ec3\u6570\u636e):": [[7, "id5"]], "\u5b50\u8d5b\u9053\u4e8c (\u5f00\u653e\u8bad\u7ec3\u6570\u636e):": [[7, "id6"]]}, "indexentries": {}}) \ No newline at end of file +Search.setIndex({"docnames": ["index", "\u57fa\u7ebf", "\u6570\u636e\u96c6", "\u7b80\u4ecb", "\u7ec4\u59d4\u4f1a", "\u8054\u7cfb\u65b9\u5f0f", "\u89c4\u5219", "\u8d5b\u9053\u8bbe\u7f6e\u4e0e\u8bc4\u4f30"], "filenames": ["index.rst", "\u57fa\u7ebf.md", "\u6570\u636e\u96c6.md", "\u7b80\u4ecb.md", "\u7ec4\u59d4\u4f1a.md", "\u8054\u7cfb\u65b9\u5f0f.md", "\u89c4\u5219.md", "\u8d5b\u9053\u8bbe\u7f6e\u4e0e\u8bc4\u4f30.md"], "titles": ["ASRU 2023 \u591a\u901a\u9053\u591a\u65b9\u4f1a\u8bae\u8f6c\u5f55\u6311\u6218 2.0", "\u57fa\u7ebf", "\u6570\u636e\u96c6", "\u7b80\u4ecb", "\u7ec4\u59d4\u4f1a", "\u8054\u7cfb\u65b9\u5f0f", "\u7ade\u8d5b\u89c4\u5219", "\u8d5b\u9053\u8bbe\u7f6e\u4e0e\u8bc4\u4f30"], "terms": {"m2met": [0, 3, 5, 7], "asru2023": [0, 3], "m2met2": [0, 3, 5, 7], "funasr": 1, "sa": 1, "asr": [1, 3, 7], "speakerencod": 1, "modelscop": [1, 7], "todo": 1, "fill": 1, "with": 1, "the": 1, "readm": 1, "md": 1, "of": 1, "baselin": [1, 2], "aishel": [2, 7], "cn": [2, 4, 7], "celeb": [2, 7], "test": [2, 6, 7], "2023": [2, 3, 6, 7], "118": 2, "75": 2, "104": 2, "train": 2, "eval": [2, 6], "10": [2, 3, 7], "212": 2, "15": [2, 3], "30": 2, "456": 2, "25": 2, "13": [2, 3], "55": 2, "42": 2, "27": 2, "34": 2, "76": 2, "20": 2, "textgrid": 2, "id": 2, "openslr": 2, "automat": 3, "speech": 3, "recognit": 3, "speaker": 3, "diariz": 3, "rich": 3, "transcript": 3, "evalu": 3, "chime": 3, "comput": 3, "hear": 3, "in": 3, "multisourc": 3, "environ": 3, "misp": 3, "multimod": 3, "inform": 3, "base": 3, "process": 3, "multi": 3, "channel": 3, "parti": 3, "meet": 3, "iassp2022": 3, "29": 3, "19": 3, "12": 3, "asru": 3, "workshop": 3, "challeng": 3, "session": 3, "lxie": 4, "nwpu": 4, "edu": 4, "kong": 4, "aik": 4, "lee": 4, "star": 4, "kongaik": 4, "ieee": 4, "org": 4, "zhiji": 4, "yzj": 4, "alibaba": 4, "inc": 4, "com": [4, 5], "sli": 4, "zsl": 4, "yanminqian": 4, "sjtu": 4, "zhuc": 4, "microsoft": 4, "wujian": 4, "ceo": 4, "buhui": 4, "aishelldata": 4, "alimeet": [5, 7], "gmail": 5, "cpcer": [6, 7], "las": 6, "rnnt": 6, "transform": 6, "aishell4": 7, "vad": 7, "cer": 7, "ins": 7, "sub": 7, "del": 7, "text": 7, "frac": 7, "mathcal": 7, "n_": 7, "total": 7, "time": 7, "100": 7, "hug": 7, "face": 7}, "objects": {}, "objtypes": {}, "objnames": {}, "titleterms": {"asru": 0, "2023": 0, "alimeet": 2, "aoe": 3}, "envversion": {"sphinx.domains.c": 2, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 8, "sphinx.domains.index": 1, "sphinx.domains.javascript": 2, "sphinx.domains.math": 2, "sphinx.domains.python": 3, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx": 57}, "alltitles": {"ASRU 2023 \u591a\u901a\u9053\u591a\u65b9\u4f1a\u8bae\u8f6c\u5f55\u6311\u6218 2.0": [[0, "asru-2023-2-0"]], "\u76ee\u5f55:": [[0, null]], "\u57fa\u7ebf": [[1, "id1"]], "\u57fa\u7ebf\u6982\u8ff0": [[1, "id2"]], "\u5feb\u901f\u5f00\u59cb": [[1, "id3"]], "\u57fa\u7ebf\u7ed3\u679c": [[1, "id4"]], "\u6570\u636e\u96c6": [[2, "id1"]], "\u6570\u636e\u96c6\u6982\u8ff0": [[2, "id2"]], "Alimeeting\u6570\u636e\u96c6\u4ecb\u7ecd": [[2, "alimeeting"]], "\u83b7\u53d6\u6570\u636e": [[2, "id3"]], "\u7b80\u4ecb": [[3, "id1"]], "\u7ade\u8d5b\u4ecb\u7ecd": [[3, "id2"]], "\u65f6\u95f4\u5b89\u6392(AOE\u65f6\u95f4)": [[3, "aoe"]], "\u7ade\u8d5b\u62a5\u540d": [[3, "id3"]], "\u7ec4\u59d4\u4f1a": [[4, "id1"]], "\u8054\u7cfb\u65b9\u5f0f": [[5, "id1"]], "\u7ade\u8d5b\u89c4\u5219": [[6, "id1"]], "\u8d5b\u9053\u8bbe\u7f6e\u4e0e\u8bc4\u4f30": [[7, "id1"]], "\u8bf4\u8bdd\u4eba\u76f8\u5173\u7684\u8bed\u97f3\u8bc6\u522b": [[7, "id2"]], "\u8bc4\u4f30\u65b9\u6cd5": [[7, "id3"]], "\u5b50\u8d5b\u9053\u8bbe\u7f6e": [[7, "id4"]], "\u5b50\u8d5b\u9053\u4e00 (\u9650\u5b9a\u8bad\u7ec3\u6570\u636e):": [[7, "id5"]], "\u5b50\u8d5b\u9053\u4e8c (\u5f00\u653e\u8bad\u7ec3\u6570\u636e):": [[7, "id6"]]}, "indexentries": {}}) \ No newline at end of file diff --git a/docs/m2met2_cn/_build/html/简介.html b/docs/m2met2_cn/_build/html/简介.html index f1da18e63..b53850647 100644 --- a/docs/m2met2_cn/_build/html/简介.html +++ b/docs/m2met2_cn/_build/html/简介.html @@ -130,7 +130,7 @@

竞赛介绍

语音识别(Automatic Speech Recognition)、说话人日志(Speaker Diarization)等语音处理技术的最新发展激发了众多智能语音的广泛应用。然而会议场景由于其复杂的声学条件和不同的讲话风格,包括重叠的讲话、不同数量的发言者、大会议室的远场信号以及环境噪声和混响,仍然属于一项极具挑战性的任务。

为了推动会议场景语音识别的发展,已经有很多相关的挑战赛,如 Rich Transcription evaluation 和 CHIME(Computational Hearing in Multisource Environments) 挑战赛。最新的CHIME挑战赛关注于远距离自动语音识别和开发能在各种不同拓扑结构的阵列和应用场景中通用的系统。然而不同语言之间的差异限制了非英语会议转录的进展。MISP(Multimodal Information Based Speech Processing)和M2MeT(Multi-Channel Multi-Party Meeting Transcription)挑战赛为推动普通话会议场景语音识别做出了贡献。MISP挑战赛侧重于用视听多模态的方法解决日常家庭环境中的远距离多麦克风信号处理问题,而M2MeT挑战则侧重于解决离线会议室中会议转录的语音重叠问题。

-

ASSP2022 M2MeT挑战的侧重点是会议场景,它包括两个赛道:说话人日记和多说话人自动语音识别。前者涉及识别“谁在什么时候说了话”,而后者旨在同时识别来自多个说话人的语音,语音重叠和各种噪声带来了巨大的技术困难。

+

IASSP2022 M2MeT挑战的侧重点是会议场景,它包括两个赛道:说话人日记和多说话人自动语音识别。前者涉及识别“谁在什么时候说了话”,而后者旨在同时识别来自多个说话人的语音,语音重叠和各种噪声带来了巨大的技术困难。

在上一届M2MET成功举办的基础上,我们将在ASRU2023上继续举办M2MET2.0挑战赛。在上一届M2MET挑战赛中,评估指标是说话人无关的,我们只能得到识别文本,而不能确定相应的说话人。 为了解决这一局限性并将现在的多说话人语音识别系统推向实用化,M2MET2.0挑战赛将在说话人相关的人物上评估,并且同时设立限定数据与不限定数据两个子赛道。通过将语音归属于特定的说话人,这项任务旨在提高多说话人ASR系统在真实世界环境中的准确性和适用性。 我们对数据集、规则、基线系统和评估方法进行了详细介绍,以进一步促进多说话人语音识别领域研究的发展。此外,我们将根据时间表发布一个全新的测试集,包括大约10小时的音频。

diff --git a/docs/m2met2_cn/简介.md b/docs/m2met2_cn/简介.md index 52df97d6b..f43dbabec 100644 --- a/docs/m2met2_cn/简介.md +++ b/docs/m2met2_cn/简介.md @@ -4,7 +4,7 @@ 为了推动会议场景语音识别的发展,已经有很多相关的挑战赛,如 Rich Transcription evaluation 和 CHIME(Computational Hearing in Multisource Environments) 挑战赛。最新的CHIME挑战赛关注于远距离自动语音识别和开发能在各种不同拓扑结构的阵列和应用场景中通用的系统。然而不同语言之间的差异限制了非英语会议转录的进展。MISP(Multimodal Information Based Speech Processing)和M2MeT(Multi-Channel Multi-Party Meeting Transcription)挑战赛为推动普通话会议场景语音识别做出了贡献。MISP挑战赛侧重于用视听多模态的方法解决日常家庭环境中的远距离多麦克风信号处理问题,而M2MeT挑战则侧重于解决离线会议室中会议转录的语音重叠问题。 -ASSP2022 M2MeT挑战的侧重点是会议场景,它包括两个赛道:说话人日记和多说话人自动语音识别。前者涉及识别“谁在什么时候说了话”,而后者旨在同时识别来自多个说话人的语音,语音重叠和各种噪声带来了巨大的技术困难。 +IASSP2022 M2MeT挑战的侧重点是会议场景,它包括两个赛道:说话人日记和多说话人自动语音识别。前者涉及识别“谁在什么时候说了话”,而后者旨在同时识别来自多个说话人的语音,语音重叠和各种噪声带来了巨大的技术困难。 在上一届M2MET成功举办的基础上,我们将在ASRU2023上继续举办M2MET2.0挑战赛。在上一届M2MET挑战赛中,评估指标是说话人无关的,我们只能得到识别文本,而不能确定相应的说话人。 为了解决这一局限性并将现在的多说话人语音识别系统推向实用化,M2MET2.0挑战赛将在说话人相关的人物上评估,并且同时设立限定数据与不限定数据两个子赛道。通过将语音归属于特定的说话人,这项任务旨在提高多说话人ASR系统在真实世界环境中的准确性和适用性。 From aa910b9860d420877d73f36c71302995587b0a49 Mon Sep 17 00:00:00 2001 From: "shixian.shi" Date: Thu, 27 Apr 2023 12:03:31 +0800 Subject: [PATCH 002/120] update adavanced clas, including model and dataset --- funasr/datasets/large_datasets/dataset.py | 40 +- .../large_datasets/utils/hotword_utils.py | 32 ++ .../datasets/large_datasets/utils/padding.py | 43 ++ .../datasets/large_datasets/utils/tokenize.py | 7 +- .../models/e2e_asr_contextual_paraformer.py | 408 ++++++++++++++++++ funasr/tasks/asr.py | 2 + 6 files changed, 528 insertions(+), 4 deletions(-) create mode 100644 funasr/datasets/large_datasets/utils/hotword_utils.py create mode 100644 funasr/models/e2e_asr_contextual_paraformer.py diff --git a/funasr/datasets/large_datasets/dataset.py b/funasr/datasets/large_datasets/dataset.py index b0e1b8f31..500257cf7 100644 --- a/funasr/datasets/large_datasets/dataset.py +++ b/funasr/datasets/large_datasets/dataset.py @@ -28,7 +28,7 @@ def read_lists(list_file): class AudioDataset(IterableDataset): - def __init__(self, scp_lists, data_names, data_types, frontend_conf=None, shuffle=True, mode="train"): + def __init__(self, scp_lists, data_names, data_types, frontend_conf=None, shuffle=True, mode="train", pre_hwlist=None, pre_prob=0.0): self.scp_lists = scp_lists self.data_names = data_names self.data_types = data_types @@ -40,6 +40,8 @@ class AudioDataset(IterableDataset): self.world_size = 1 self.worker_id = 0 self.num_workers = 1 + self.pre_hwlist = pre_hwlist + self.pre_prob = pre_prob def set_epoch(self, epoch): self.epoch = epoch @@ -131,6 +133,13 @@ class AudioDataset(IterableDataset): sample_dict["sampling_rate"] = sampling_rate if data_name == "speech": sample_dict["key"] = key + elif data_type == "text_hotword": + text = item + segs = text.strip().split() + sample_dict[data_name] = segs[1:] + if "key" not in sample_dict: + sample_dict["key"] = segs[0] + sample_dict['hw_tag'] = 1 else: text = item segs = text.strip().split() @@ -167,14 +176,39 @@ def Dataset(data_list_file, shuffle = conf.get('shuffle', True) data_names = conf.get("data_names", "speech,text") data_types = conf.get("data_types", "kaldi_ark,text") - dataset = AudioDataset(scp_lists, data_names, data_types, frontend_conf=frontend_conf, shuffle=shuffle, mode=mode) + + pre_hwfile = conf.get("pre_hwlist", None) + pre_prob = conf.get("pre_prob", 0) + + hw_config = {"sample_rate": conf.get("sample_rate", 0.6), + "double_rate": conf.get("double_rate", 0.1), + "hotword_min_length": conf.get("hotword_min_length", 2), + "hotword_max_length": conf.get("hotword_max_length", 8)} + + + if pre_hwfile is not None: + pre_hwlist = [] + with open(pre_hwfile, 'r') as fin: + for line in fin.readlines(): + pre_hwlist.append(line.strip()) + else: + pre_hwlist = None + # logging.warning("Previous hwlist: {}".format(pre_hwlist)) + dataset = AudioDataset(scp_lists, + data_names, + data_types, + frontend_conf=frontend_conf, + shuffle=shuffle, + mode=mode, + pre_hwlist=pre_hwlist, + pre_prob=pre_prob) filter_conf = conf.get('filter_conf', {}) filter_fn = partial(filter, **filter_conf) dataset = FilterIterDataPipe(dataset, fn=filter_fn) if "text" in data_names: - vocab = {'vocab': dict, 'seg_dict': seg_dict, 'punc_dict': punc_dict, 'bpe_tokenizer': bpe_tokenizer} + vocab = {'vocab': dict, 'seg_dict': seg_dict, 'punc_dict': punc_dict, 'bpe_tokenizer': bpe_tokenizer, 'hw_config': hw_config} tokenize_fn = partial(tokenize, **vocab) dataset = MapperIterDataPipe(dataset, fn=tokenize_fn) diff --git a/funasr/datasets/large_datasets/utils/hotword_utils.py b/funasr/datasets/large_datasets/utils/hotword_utils.py new file mode 100644 index 000000000..fccfea696 --- /dev/null +++ b/funasr/datasets/large_datasets/utils/hotword_utils.py @@ -0,0 +1,32 @@ +import random + +def sample_hotword(length, + hotword_min_length, + hotword_max_length, + sample_rate, + double_rate, + pre_prob, + pre_index=None): + if length < hotword_min_length: + return [-1] + if random.random() < sample_rate: + if pre_prob > 0 and random.random() < pre_prob and pre_index is not None: + return pre_index + if length == hotword_min_length: + return [0, length-1] + elif random.random() < double_rate and length > hotword_max_length + hotword_min_length + 2: + # sample two hotwords in a sentence + _max_hw_length = min(hotword_max_length, length // 2) + # first hotword + start1 = random.randint(0, length // 3) + end1 = random.randint(start1 + hotword_min_length - 1, start1 + _max_hw_length - 1) + # second hotword + start2 = random.randint(end1 + 1, length - hotword_min_length) + end2 = random.randint(min(length-1, start2+hotword_min_length-1), min(length-1, start2+hotword_max_length-1)) + return [start1, end1, start2, end2] + else: # single hotword + start = random.randint(0, length - hotword_min_length) + end = random.randint(min(length-1, start+hotword_min_length-1), min(length-1, start+hotword_max_length-1)) + return [start, end] + else: + return [-1] \ No newline at end of file diff --git a/funasr/datasets/large_datasets/utils/padding.py b/funasr/datasets/large_datasets/utils/padding.py index e0feac62e..fdca63d7b 100644 --- a/funasr/datasets/large_datasets/utils/padding.py +++ b/funasr/datasets/large_datasets/utils/padding.py @@ -31,4 +31,47 @@ def padding(data, float_pad_value=0.0, int_pad_value=-1): batch[data_name] = tensor_pad batch[data_name + "_lengths"] = tensor_lengths + # DHA, EAHC NOT INCLUDED + if "hotword_indxs" in batch: + # if hotword indxs in batch + # use it to slice hotwords out + hotword_list = [] + hotword_lengths = [] + text = batch['text'] + text_lengths = batch['text_lengths'] + hotword_indxs = batch['hotword_indxs'] + num_hw = sum([int(i) for i in batch['hotword_indxs_lengths'] if i != 1]) // 2 + B, t1 = text.shape + t1 += 1 # TODO: as parameter which is same as predictor_bias + ideal_attn = torch.zeros(B, t1, num_hw+1) + nth_hw = 0 + for b, (hotword_indx, one_text, length) in enumerate(zip(hotword_indxs, text, text_lengths)): + ideal_attn[b][:,-1] = 1 + if hotword_indx[0] != -1: + start, end = int(hotword_indx[0]), int(hotword_indx[1]) + hotword = one_text[start: end+1] + hotword_list.append(hotword) + hotword_lengths.append(end-start+1) + ideal_attn[b][start:end+1, nth_hw] = 1 + ideal_attn[b][start:end+1, -1] = 0 + nth_hw += 1 + if len(hotword_indx) == 4 and hotword_indx[2] != -1: + # the second hotword if exist + start, end = int(hotword_indx[2]), int(hotword_indx[3]) + hotword_list.append(one_text[start: end+1]) + hotword_lengths.append(end-start+1) + ideal_attn[b][start:end+1, nth_hw-1] = 1 + ideal_attn[b][start:end+1, -1] = 0 + nth_hw += 1 + hotword_list.append(torch.tensor([1])) + hotword_lengths.append(1) + hotword_pad = pad_sequence(hotword_list, + batch_first=True, + padding_value=0) + batch["hotword_pad"] = hotword_pad + batch["hotword_lengths"] = torch.tensor(hotword_lengths, dtype=torch.int32) + batch['ideal_attn'] = ideal_attn + del batch['hotword_indxs'] + del batch['hotword_indxs_lengths'] + return keys, batch diff --git a/funasr/datasets/large_datasets/utils/tokenize.py b/funasr/datasets/large_datasets/utils/tokenize.py index 0d2fd84ee..09ece76d1 100644 --- a/funasr/datasets/large_datasets/utils/tokenize.py +++ b/funasr/datasets/large_datasets/utils/tokenize.py @@ -1,6 +1,7 @@ #!/usr/bin/env python import re import numpy as np +from funasr.datasets.large_datasets.utils.hotword_utils import sample_hotword def forward_segment(text, seg_dict): word_list = [] @@ -38,7 +39,8 @@ def tokenize(data, vocab=None, seg_dict=None, punc_dict=None, - bpe_tokenizer=None): + bpe_tokenizer=None, + hw_config=None): assert "text" in data assert isinstance(vocab, dict) text = data["text"] @@ -53,6 +55,9 @@ def tokenize(data, text = seg_tokenize(text, seg_dict) length = len(text) + if 'hw_tag' in data: + hotword_indxs = sample_hotword(length, **hw_config) + data[hotword_indxs] = hotword_indxs for i in range(length): x = text[i] if i == length-1 and "punc" in data and x.startswith("vad:"): diff --git a/funasr/models/e2e_asr_contextual_paraformer.py b/funasr/models/e2e_asr_contextual_paraformer.py new file mode 100644 index 000000000..cafb65314 --- /dev/null +++ b/funasr/models/e2e_asr_contextual_paraformer.py @@ -0,0 +1,408 @@ +from json import decoder +import logging +from contextlib import contextmanager +from distutils.version import LooseVersion +from typing import Dict +from typing import List +from typing import Optional +from typing import Tuple +from typing import Union +import random +from unicodedata import bidirectional +import numpy as np + +import torch +from typeguard import check_argument_types + +from funasr.layers.abs_normalize import AbsNormalize +from funasr.losses.label_smoothing_loss import ( + LabelSmoothingLoss, # noqa: H301 +) +from funasr.models.ctc import CTC +from funasr.models.decoder.abs_decoder import AbsDecoder +from funasr.models.e2e_asr_common import ErrorCalculator +from funasr.models.encoder.abs_encoder import AbsEncoder +from funasr.models.frontend.abs_frontend import AbsFrontend +from funasr.models.postencoder.abs_postencoder import AbsPostEncoder +from funasr.models.predictor.cif import mae_loss +from funasr.models.preencoder.abs_preencoder import AbsPreEncoder +from funasr.models.specaug.abs_specaug import AbsSpecAug +from funasr.modules.add_sos_eos import add_sos_eos +from funasr.modules.nets_utils import make_pad_mask, pad_list +from funasr.modules.nets_utils import th_accuracy +from funasr.torch_utils.device_funcs import force_gatherable +from funasr.train.abs_espnet_model import AbsESPnetModel +from funasr.models.predictor.cif import CifPredictorV3 +from funasr.modules.streaming_utils import utils as myutils +from funasr.models.e2e_asr_paraformer import Paraformer +from funasr.modules.layer_norm import LayerNorm + + +if LooseVersion(torch.__version__) >= LooseVersion("1.6.0"): + from torch.cuda.amp import autocast +else: + # Nothing to do if torch<1.6.0 + @contextmanager + def autocast(enabled=True): + yield + + +class AdvancedContextualParaformer(Paraformer): + def __init__( + self, + vocab_size: int, + token_list: Union[Tuple[str, ...], List[str]], + frontend: Optional[AbsFrontend], + specaug: Optional[AbsSpecAug], + normalize: Optional[AbsNormalize], + preencoder: Optional[AbsPreEncoder], + encoder: AbsEncoder, + postencoder: Optional[AbsPostEncoder], + decoder: AbsDecoder, + ctc: CTC, + ctc_weight: float = 0.5, + interctc_weight: float = 0.0, + ignore_id: int = -1, + blank_id: int = 0, + sos: int = 1, + eos: int = 2, + lsm_weight: float = 0.0, + length_normalized_loss: bool = False, + report_cer: bool = True, + report_wer: bool = True, + sym_space: str = "", + sym_blank: str = "", + extract_feats_in_collect_stats: bool = True, + predictor = None, + predictor_weight: float = 0.0, + predictor_bias: int = 0, + sampling_ratio: float = 0.2, + target_buffer_length: int = -1, + inner_dim: int = 256, + bias_encoder_type: str = 'lstm', + use_decoder_embedding: bool = True, + crit_attn_weight: float = 0.0, + crit_attn_smooth: float = 0.0, + bias_encoder_dropout_rate: float = 0.0, + ): + assert check_argument_types() + assert 0.0 <= ctc_weight <= 1.0, ctc_weight + assert 0.0 <= interctc_weight < 1.0, interctc_weight + + super().__init__( + vocab_size=vocab_size, + token_list=token_list, + frontend=frontend, + specaug=specaug, + normalize=normalize, + preencoder=preencoder, + encoder=encoder, + postencoder=postencoder, + decoder=decoder, + ctc=ctc, + ctc_weight=ctc_weight, + interctc_weight=interctc_weight, + ignore_id=ignore_id, + blank_id=blank_id, + sos=sos, + eos=eos, + lsm_weight=lsm_weight, + length_normalized_loss=length_normalized_loss, + report_cer=report_cer, + report_wer=report_wer, + sym_space=sym_space, + sym_blank=sym_blank, + extract_feats_in_collect_stats=extract_feats_in_collect_stats, + predictor=predictor, + predictor_weight=predictor_weight, + predictor_bias=predictor_bias, + sampling_ratio=sampling_ratio, + ) + + if bias_encoder_type == 'lstm': + logging.warning("enable bias encoder sampling and contextual training") + self.bias_encoder = torch.nn.LSTM(inner_dim, inner_dim, 1, batch_first=True, dropout=bias_encoder_dropout_rate) + self.bias_embed = torch.nn.Embedding(vocab_size, inner_dim) + elif bias_encoder_type == 'mean': + logging.warning("enable bias encoder sampling and contextual training") + self.bias_embed = torch.nn.Embedding(vocab_size, inner_dim) + else: + logging.error("Unsupport bias encoder type: {}".format(bias_encoder_type)) + + self.target_buffer_length = target_buffer_length + if self.target_buffer_length > 0: + self.hotword_buffer = None + self.length_record = [] + self.current_buffer_length = 0 + self.use_decoder_embedding = use_decoder_embedding + self.crit_attn_weight = crit_attn_weight + if self.crit_attn_weight > 0: + self.attn_loss = torch.nn.L1Loss() + self.crit_attn_smooth = crit_attn_smooth + + def forward( + self, + speech: torch.Tensor, + speech_lengths: torch.Tensor, + text: torch.Tensor, + text_lengths: torch.Tensor, + hotword_pad: torch.Tensor, + hotword_lengths: torch.Tensor, + ideal_attn: torch.Tensor, + ) -> Tuple[torch.Tensor, Dict[str, torch.Tensor], torch.Tensor]: + """Frontend + Encoder + Decoder + Calc loss + + Args: + speech: (Batch, Length, ...) + speech_lengths: (Batch, ) + text: (Batch, Length) + text_lengths: (Batch,) + """ + assert text_lengths.dim() == 1, text_lengths.shape + # Check that batch_size is unified + assert ( + speech.shape[0] + == speech_lengths.shape[0] + == text.shape[0] + == text_lengths.shape[0] + ), (speech.shape, speech_lengths.shape, text.shape, text_lengths.shape) + batch_size = speech.shape[0] + self.step_cur += 1 + # for data-parallel + text = text[:, : text_lengths.max()] + speech = speech[:, :speech_lengths.max()] + + # 1. Encoder + encoder_out, encoder_out_lens = self.encode(speech, speech_lengths) + intermediate_outs = None + if isinstance(encoder_out, tuple): + intermediate_outs = encoder_out[1] + encoder_out = encoder_out[0] + + loss_att, acc_att, cer_att, wer_att = None, None, None, None + loss_ctc, cer_ctc = None, None + loss_pre = None + loss_ideal = None + + stats = dict() + + # 1. CTC branch + if self.ctc_weight != 0.0: + loss_ctc, cer_ctc = self._calc_ctc_loss( + encoder_out, encoder_out_lens, text, text_lengths + ) + + # Collect CTC branch stats + stats["loss_ctc"] = loss_ctc.detach() if loss_ctc is not None else None + stats["cer_ctc"] = cer_ctc + + # Intermediate CTC (optional) + loss_interctc = 0.0 + if self.interctc_weight != 0.0 and intermediate_outs is not None: + for layer_idx, intermediate_out in intermediate_outs: + # we assume intermediate_out has the same length & padding + # as those of encoder_out + loss_ic, cer_ic = self._calc_ctc_loss( + intermediate_out, encoder_out_lens, text, text_lengths + ) + loss_interctc = loss_interctc + loss_ic + + # Collect Intermedaite CTC stats + stats["loss_interctc_layer{}".format(layer_idx)] = ( + loss_ic.detach() if loss_ic is not None else None + ) + stats["cer_interctc_layer{}".format(layer_idx)] = cer_ic + + loss_interctc = loss_interctc / len(intermediate_outs) + + # calculate whole encoder loss + loss_ctc = (1 - self.interctc_weight) * loss_ctc + self.interctc_weight * loss_interctc + + # 2b. Attention decoder branch + if self.ctc_weight != 1.0: + loss_att, acc_att, cer_att, wer_att, loss_pre, loss_ideal = self._calc_att_clas_loss( + encoder_out, encoder_out_lens, text, text_lengths, hotword_pad, hotword_lengths, ideal_attn + ) + + # 3. CTC-Att loss definition + if self.ctc_weight == 0.0: + loss = loss_att + loss_pre * self.predictor_weight + elif self.ctc_weight == 1.0: + loss = loss_ctc + else: + loss = self.ctc_weight * loss_ctc + (1 - self.ctc_weight) * loss_att + loss_pre * self.predictor_weight + + if loss_ideal is not None: + loss = loss + loss_ideal * self.crit_attn_weight + stats["loss_ideal"] = loss_ideal.detach().cpu() + + # Collect Attn branch stats + stats["loss_att"] = loss_att.detach() if loss_att is not None else None + stats["acc"] = acc_att + stats["cer"] = cer_att + stats["wer"] = wer_att + stats["loss_pre"] = loss_pre.detach().cpu() if loss_pre is not None else None + + stats["loss"] = torch.clone(loss.detach()) + # force_gatherable: to-device and to-tensor if scalar for DataParallel + loss, stats, weight = force_gatherable((loss, stats, batch_size), loss.device) + return loss, stats, weight + + def _calc_att_clas_loss( + self, + encoder_out: torch.Tensor, + encoder_out_lens: torch.Tensor, + ys_pad: torch.Tensor, + ys_pad_lens: torch.Tensor, + hotword_pad: torch.Tensor, + hotword_lengths: torch.Tensor, + ideal_attn: torch.Tensor, + ): + encoder_out_mask = (~make_pad_mask(encoder_out_lens, maxlen=encoder_out.size(1))[:, None, :]).to( + encoder_out.device) + if self.predictor_bias == 1: + _, ys_pad = add_sos_eos(ys_pad, self.sos, self.eos, self.ignore_id) + ys_pad_lens = ys_pad_lens + self.predictor_bias + pre_acoustic_embeds, pre_token_length, _, _ = self.predictor(encoder_out, ys_pad, encoder_out_mask, + ignore_id=self.ignore_id) + + # -1. bias encoder + if self.use_decoder_embedding: + hw_embed = self.decoder.embed(hotword_pad) + else: + hw_embed = self.bias_embed(hotword_pad) + hw_embed, (_, _) = self.bias_encoder(hw_embed) + _ind = np.arange(0, hotword_pad.shape[0]).tolist() + selected = hw_embed[_ind, [i-1 for i in hotword_lengths.detach().cpu().tolist()]] + contextual_info = selected.squeeze(0).repeat(ys_pad.shape[0], 1, 1).to(ys_pad.device) + + # 0. sampler + decoder_out_1st = None + if self.sampling_ratio > 0.0: + if self.step_cur < 2: + logging.info("enable sampler in paraformer, sampling_ratio: {}".format(self.sampling_ratio)) + sematic_embeds, decoder_out_1st = self.sampler(encoder_out, encoder_out_lens, ys_pad, ys_pad_lens, + pre_acoustic_embeds, contextual_info) + else: + if self.step_cur < 2: + logging.info("disable sampler in paraformer, sampling_ratio: {}".format(self.sampling_ratio)) + sematic_embeds = pre_acoustic_embeds + + # 1. Forward decoder + decoder_outs = self.decoder( + encoder_out, encoder_out_lens, sematic_embeds, ys_pad_lens, contextual_info=contextual_info, ret_attn=(ideal_attn is not None) + ) + decoder_out, _, attn = decoder_outs[0], decoder_outs[1], decoder_outs[2] + if self.crit_attn_weight > 0 and attn.shape[-1] > 1: + ideal_attn = ideal_attn + self.crit_attn_smooth / (self.crit_attn_smooth + 1.0) + attn_non_blank = attn[:,:,:,:-1] + ideal_attn_non_blank = ideal_attn[:,:,:-1] + loss_ideal = self.attn_loss(attn_non_blank.max(1)[0], ideal_attn_non_blank.to(attn.device)) + else: + loss_ideal = None + + if decoder_out_1st is None: + decoder_out_1st = decoder_out + # 2. Compute attention loss + loss_att = self.criterion_att(decoder_out, ys_pad) + acc_att = th_accuracy( + decoder_out_1st.view(-1, self.vocab_size), + ys_pad, + ignore_label=self.ignore_id, + ) + loss_pre = self.criterion_pre(ys_pad_lens.type_as(pre_token_length), pre_token_length) + + # Compute cer/wer using attention-decoder + if self.training or self.error_calculator is None: + cer_att, wer_att = None, None + else: + ys_hat = decoder_out_1st.argmax(dim=-1) + cer_att, wer_att = self.error_calculator(ys_hat.cpu(), ys_pad.cpu()) + + return loss_att, acc_att, cer_att, wer_att, loss_pre, loss_ideal + + def sampler(self, encoder_out, encoder_out_lens, ys_pad, ys_pad_lens, pre_acoustic_embeds, contextual_info): + + tgt_mask = (~make_pad_mask(ys_pad_lens, maxlen=ys_pad_lens.max())[:, :, None]).to(ys_pad.device) + ys_pad = ys_pad * tgt_mask[:, :, 0] + if self.share_embedding: + ys_pad_embed = self.decoder.output_layer.weight[ys_pad] + else: + ys_pad_embed = self.decoder.embed(ys_pad) + with torch.no_grad(): + decoder_outs = self.decoder( + encoder_out, encoder_out_lens, pre_acoustic_embeds, ys_pad_lens, contextual_info=contextual_info + ) + decoder_out, _ = decoder_outs[0], decoder_outs[1] + pred_tokens = decoder_out.argmax(-1) + nonpad_positions = ys_pad.ne(self.ignore_id) + seq_lens = (nonpad_positions).sum(1) + same_num = ((pred_tokens == ys_pad) & nonpad_positions).sum(1) + input_mask = torch.ones_like(nonpad_positions) + bsz, seq_len = ys_pad.size() + for li in range(bsz): + target_num = (((seq_lens[li] - same_num[li].sum()).float()) * self.sampling_ratio).long() + if target_num > 0: + input_mask[li].scatter_(dim=0, index=torch.randperm(seq_lens[li])[:target_num].to(pre_acoustic_embeds.device), value=0) + input_mask = input_mask.eq(1) + input_mask = input_mask.masked_fill(~nonpad_positions, False) + input_mask_expand_dim = input_mask.unsqueeze(2).to(pre_acoustic_embeds.device) + + sematic_embeds = pre_acoustic_embeds.masked_fill(~input_mask_expand_dim, 0) + ys_pad_embed.masked_fill( + input_mask_expand_dim, 0) + return sematic_embeds * tgt_mask, decoder_out * tgt_mask + + def cal_decoder_with_predictor_with_hwlist_advanced(self, encoder_out, encoder_out_lens, sematic_embeds, ys_pad_lens, hw_list=None): + if hw_list is None: + hw_list = [torch.Tensor([1]).long().to(encoder_out.device)] # empty hotword list + hw_list_pad = pad_list(hw_list, 0) + if self.use_decoder_embedding: + hw_embed = self.decoder.embed(hw_list_pad) + else: + hw_embed = self.bias_embed(hw_list_pad) + hw_embed, (h_n, _) = self.bias_encoder(hw_embed) + else: + # hw_list = hw_list[1:] + [hw_list[0]] # reorder + hw_lengths = [len(i) for i in hw_list] + hw_list_pad = pad_list([torch.Tensor(i).long() for i in hw_list], 0).to(encoder_out.device) + if self.use_decoder_embedding: + hw_embed = self.decoder.embed(hw_list_pad) + else: + hw_embed = self.bias_embed(hw_list_pad) + hw_embed = torch.nn.utils.rnn.pack_padded_sequence(hw_embed, hw_lengths, batch_first=True, + enforce_sorted=False) + _, (h_n, _) = self.bias_encoder(hw_embed) + # hw_embed, _ = torch.nn.utils.rnn.pad_packed_sequence(hw_embed, batch_first=True) + if h_n.shape[1] > 2000: # large hotword list + _h_n = self.pick_hwlist_group(h_n.squeeze(0), encoder_out, encoder_out_lens, sematic_embeds, ys_pad_lens) + if _h_n is not None: + h_n = _h_n + hw_embed = h_n.repeat(encoder_out.shape[0], 1, 1) + # import pdb; pdb.set_trace() + + decoder_outs = self.decoder( + encoder_out, encoder_out_lens, sematic_embeds, ys_pad_lens, contextual_info=hw_embed + ) + decoder_out = decoder_outs[0] + decoder_out = torch.log_softmax(decoder_out, dim=-1) + return decoder_out, ys_pad_lens + + def pick_hwlist_group(self, hw_embed, encoder_out, encoder_out_lens, sematic_embeds, ys_pad_lens): + max_attn_score = 0.0 + # max_attn_index = 0 + argmax_g = None + non_blank = hw_embed[-1] + hw_embed_groups = hw_embed[:-1].split(2000) + for i, g in enumerate(hw_embed_groups): + g = torch.cat([g, non_blank.unsqueeze(0)], dim=0) + _ = self.decoder( + encoder_out, encoder_out_lens, sematic_embeds, ys_pad_lens, contextual_info=g.unsqueeze(0) + ) + attn = self.decoder.bias_decoder.src_attn.attn[0] + _max_attn_score = attn.max(0)[0][:,:-1].max() + if _max_attn_score > max_attn_score: + max_attn_score = _max_attn_score + # max_attn_index = i + argmax_g = g + # import pdb; pdb.set_trace() + return argmax_g \ No newline at end of file diff --git a/funasr/tasks/asr.py b/funasr/tasks/asr.py index d52c9c383..9e33c1151 100644 --- a/funasr/tasks/asr.py +++ b/funasr/tasks/asr.py @@ -42,6 +42,7 @@ from funasr.models.decoder.rnnt_decoder import RNNTDecoder from funasr.models.joint_net.joint_network import JointNetwork from funasr.models.e2e_asr import ESPnetASRModel from funasr.models.e2e_asr_paraformer import Paraformer, ParaformerOnline, ParaformerBert, BiCifParaformer, ContextualParaformer +from funasr.models.e2e_asr_contextual_paraformer import AdvancedContextualParaformer from funasr.models.e2e_tp import TimestampPredictor from funasr.models.e2e_asr_mfcca import MFCCA from funasr.models.e2e_uni_asr import UniASR @@ -128,6 +129,7 @@ model_choices = ClassChoices( paraformer_bert=ParaformerBert, bicif_paraformer=BiCifParaformer, contextual_paraformer=ContextualParaformer, + acontextual_paraformer=AdvancedContextualParaformer, mfcca=MFCCA, timestamp_prediction=TimestampPredictor, ), From 7bf5a94a124819c84b80307e0ab8f71027360313 Mon Sep 17 00:00:00 2001 From: "shixian.shi" Date: Thu, 27 Apr 2023 12:06:51 +0800 Subject: [PATCH 003/120] fix --- funasr/datasets/large_datasets/dataset.py | 12 ++++-------- funasr/tasks/asr.py | 1 - 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/funasr/datasets/large_datasets/dataset.py b/funasr/datasets/large_datasets/dataset.py index 500257cf7..db770f596 100644 --- a/funasr/datasets/large_datasets/dataset.py +++ b/funasr/datasets/large_datasets/dataset.py @@ -28,7 +28,7 @@ def read_lists(list_file): class AudioDataset(IterableDataset): - def __init__(self, scp_lists, data_names, data_types, frontend_conf=None, shuffle=True, mode="train", pre_hwlist=None, pre_prob=0.0): + def __init__(self, scp_lists, data_names, data_types, frontend_conf=None, shuffle=True, mode="train"): self.scp_lists = scp_lists self.data_names = data_names self.data_types = data_types @@ -40,8 +40,6 @@ class AudioDataset(IterableDataset): self.world_size = 1 self.worker_id = 0 self.num_workers = 1 - self.pre_hwlist = pre_hwlist - self.pre_prob = pre_prob def set_epoch(self, epoch): self.epoch = epoch @@ -178,14 +176,13 @@ def Dataset(data_list_file, data_types = conf.get("data_types", "kaldi_ark,text") pre_hwfile = conf.get("pre_hwlist", None) - pre_prob = conf.get("pre_prob", 0) + pre_prob = conf.get("pre_prob", 0) # unused yet hw_config = {"sample_rate": conf.get("sample_rate", 0.6), "double_rate": conf.get("double_rate", 0.1), "hotword_min_length": conf.get("hotword_min_length", 2), "hotword_max_length": conf.get("hotword_max_length", 8)} - if pre_hwfile is not None: pre_hwlist = [] with open(pre_hwfile, 'r') as fin: @@ -193,15 +190,14 @@ def Dataset(data_list_file, pre_hwlist.append(line.strip()) else: pre_hwlist = None - # logging.warning("Previous hwlist: {}".format(pre_hwlist)) + dataset = AudioDataset(scp_lists, data_names, data_types, frontend_conf=frontend_conf, shuffle=shuffle, mode=mode, - pre_hwlist=pre_hwlist, - pre_prob=pre_prob) + ) filter_conf = conf.get('filter_conf', {}) filter_fn = partial(filter, **filter_conf) diff --git a/funasr/tasks/asr.py b/funasr/tasks/asr.py index 9e33c1151..d8d524605 100644 --- a/funasr/tasks/asr.py +++ b/funasr/tasks/asr.py @@ -1649,7 +1649,6 @@ class ASRTransducerTask(AbsTask): normalize = None # 4. Encoder - if getattr(args, "encoder", None) is not None: encoder_class = encoder_choices.get_class(args.encoder) encoder = encoder_class(input_size, **args.encoder_conf) From 3c0a9fb7c1bd642f3370d406fca81ff50ae9bc82 Mon Sep 17 00:00:00 2001 From: "shixian.shi" Date: Thu, 27 Apr 2023 12:10:41 +0800 Subject: [PATCH 004/120] fix name --- funasr/models/e2e_asr_contextual_paraformer.py | 14 +------------- funasr/tasks/asr.py | 4 ++-- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/funasr/models/e2e_asr_contextual_paraformer.py b/funasr/models/e2e_asr_contextual_paraformer.py index cafb65314..e1dfe6cf0 100644 --- a/funasr/models/e2e_asr_contextual_paraformer.py +++ b/funasr/models/e2e_asr_contextual_paraformer.py @@ -1,4 +1,3 @@ -from json import decoder import logging from contextlib import contextmanager from distutils.version import LooseVersion @@ -7,35 +6,24 @@ from typing import List from typing import Optional from typing import Tuple from typing import Union -import random -from unicodedata import bidirectional import numpy as np import torch from typeguard import check_argument_types from funasr.layers.abs_normalize import AbsNormalize -from funasr.losses.label_smoothing_loss import ( - LabelSmoothingLoss, # noqa: H301 -) from funasr.models.ctc import CTC from funasr.models.decoder.abs_decoder import AbsDecoder -from funasr.models.e2e_asr_common import ErrorCalculator from funasr.models.encoder.abs_encoder import AbsEncoder from funasr.models.frontend.abs_frontend import AbsFrontend from funasr.models.postencoder.abs_postencoder import AbsPostEncoder -from funasr.models.predictor.cif import mae_loss from funasr.models.preencoder.abs_preencoder import AbsPreEncoder from funasr.models.specaug.abs_specaug import AbsSpecAug from funasr.modules.add_sos_eos import add_sos_eos from funasr.modules.nets_utils import make_pad_mask, pad_list from funasr.modules.nets_utils import th_accuracy from funasr.torch_utils.device_funcs import force_gatherable -from funasr.train.abs_espnet_model import AbsESPnetModel -from funasr.models.predictor.cif import CifPredictorV3 -from funasr.modules.streaming_utils import utils as myutils from funasr.models.e2e_asr_paraformer import Paraformer -from funasr.modules.layer_norm import LayerNorm if LooseVersion(torch.__version__) >= LooseVersion("1.6.0"): @@ -47,7 +35,7 @@ else: yield -class AdvancedContextualParaformer(Paraformer): +class NeatContextualParaformer(Paraformer): def __init__( self, vocab_size: int, diff --git a/funasr/tasks/asr.py b/funasr/tasks/asr.py index d8d524605..4d1009220 100644 --- a/funasr/tasks/asr.py +++ b/funasr/tasks/asr.py @@ -42,7 +42,7 @@ from funasr.models.decoder.rnnt_decoder import RNNTDecoder from funasr.models.joint_net.joint_network import JointNetwork from funasr.models.e2e_asr import ESPnetASRModel from funasr.models.e2e_asr_paraformer import Paraformer, ParaformerOnline, ParaformerBert, BiCifParaformer, ContextualParaformer -from funasr.models.e2e_asr_contextual_paraformer import AdvancedContextualParaformer +from funasr.models.e2e_asr_contextual_paraformer import NeatContextualParaformer from funasr.models.e2e_tp import TimestampPredictor from funasr.models.e2e_asr_mfcca import MFCCA from funasr.models.e2e_uni_asr import UniASR @@ -129,7 +129,7 @@ model_choices = ClassChoices( paraformer_bert=ParaformerBert, bicif_paraformer=BiCifParaformer, contextual_paraformer=ContextualParaformer, - acontextual_paraformer=AdvancedContextualParaformer, + neatcontextual_paraformer=NeatContextualParaformer, mfcca=MFCCA, timestamp_prediction=TimestampPredictor, ), From 32d2b3ec153e53176da710ebcc0aba5669effd8a Mon Sep 17 00:00:00 2001 From: yhliang <429259365@qq.com> Date: Thu, 27 Apr 2023 17:45:00 +0800 Subject: [PATCH 005/120] update m2met2 docs --- docs/m2met2/Contact.md | 2 +- docs/m2met2/Introduction.md | 2 +- docs/m2met2/_build/doctrees/Contact.doctree | Bin 4389 -> 4629 bytes .../_build/doctrees/Introduction.doctree | Bin 15878 -> 15882 bytes .../m2met2/_build/doctrees/environment.pickle | Bin 25894 -> 25957 bytes docs/m2met2/_build/html/Contact.html | 5 ++++- docs/m2met2/_build/html/Introduction.html | 2 +- docs/m2met2/_build/html/_images/qrcode.png | Bin 0 -> 144841 bytes .../_build/html/_sources/Contact.md.txt | 2 +- .../_build/html/_sources/Introduction.md.txt | 2 +- docs/m2met2/images/qrcode.png | Bin 0 -> 144841 bytes .../_build/doctrees/environment.pickle | Bin 25266 -> 25329 bytes docs/m2met2_cn/_build/doctrees/简介.doctree | Bin 13574 -> 13586 bytes .../_build/doctrees/联系方式.doctree | Bin 4479 -> 4719 bytes docs/m2met2_cn/_build/html/_images/qrcode.png | Bin 0 -> 144841 bytes .../_build/html/_sources/简介.md.txt | 2 +- .../_build/html/_sources/联系方式.md.txt | 2 +- docs/m2met2_cn/_build/html/简介.html | 2 +- docs/m2met2_cn/_build/html/联系方式.html | 5 ++++- docs/m2met2_cn/images/qrcode.png | Bin 0 -> 144841 bytes docs/m2met2_cn/简介.md | 2 +- docs/m2met2_cn/联系方式.md | 2 +- 22 files changed, 18 insertions(+), 12 deletions(-) create mode 100644 docs/m2met2/_build/html/_images/qrcode.png create mode 100644 docs/m2met2/images/qrcode.png create mode 100644 docs/m2met2_cn/_build/html/_images/qrcode.png create mode 100644 docs/m2met2_cn/images/qrcode.png diff --git a/docs/m2met2/Contact.md b/docs/m2met2/Contact.md index 3097ad791..d0811c650 100644 --- a/docs/m2met2/Contact.md +++ b/docs/m2met2/Contact.md @@ -5,5 +5,5 @@ If you have any questions about M2MET2.0 challenge, please contact us by | Wechat group | |:------------------------------------------:| - +| | diff --git a/docs/m2met2/Introduction.md b/docs/m2met2/Introduction.md index eac9eb6b5..99a426f2a 100644 --- a/docs/m2met2/Introduction.md +++ b/docs/m2met2/Introduction.md @@ -25,4 +25,4 @@ Interested participants, whether from academia or industry, must register for th [M2MET2.0 Registration](https://docs.google.com/forms/d/e/1FAIpQLSf77T9vAl7Ym-u5g8gXu18SBofoWRaFShBo26Ym0-HDxHW9PQ/viewform?usp=sf_link) -Within three working days, the challenge organizer will send email invitations to eligible teams to participate in the challenge. All qualified teams are required to adhere to the challenge rules, which will be published on the challenge page. Prior to the ranking release time, each participant must submit a system description document detailing their approach and methods. The organizer will select the top three submissions to be included in the ASRU2023 Proceedings. +Within three working days, the challenge organizer will send email invitations to eligible teams to participate in the challenge. All qualified teams are required to adhere to the challenge rules, which will be published on the challenge page. Prior to the ranking release time, each participant must submit a system description document detailing their approach and methods. The organizer will select the top ranking submissions to be included in the ASRU2023 Proceedings. diff --git a/docs/m2met2/_build/doctrees/Contact.doctree b/docs/m2met2/_build/doctrees/Contact.doctree index e3f579ff55b635d8ca2fc176b01c4e90495acd11..877cb686874aefdbe7c701e4f8c298a9dd326db3 100644 GIT binary patch delta 378 zcmZ3gG*yMQfn_R}&_>n?Y&sd7J**{3`6-oCCQs39oKibQBZD=AErUIFO2$Mq{mHkrBU3dKdqwn~|~iRr1u`h`Ww`6;P-1$pU83gww8B^kC##s&sT`gT*m#sDn< zE1dk8Mca)PtYAtHGf)MPEG^2M(j$mr&XgXm-o7eFtGRkD}09AT3f<=1Ro%8cb5|c}&v`;B6 HP0|AZqI!LP delta 346 zcmbQLvQ&w+fn}P zZn{EoQL?R4W^Q77YO#KKYH~(miC#fox{^Y9W=ctht&*{Ufs(!*P_eGA9oLi$_Sh*I zVx$-#g=RwQ6p$-2q%%$zPd>;hZPLS*mS2>cSTd!DC8H!aXG#xeMQ)B&aY15o>XaUi zf}+&o)S|M~DWw_O87DJjGjuZKyg4@C;3#Hd8fFAV43=VBg+PT#+#dG7|vy6FG|eI&df`nY-MaYd4eH3n($^T<1<_Ui2oK1 delta 55 zcmeCGX{%vrV43=RBg+PT#_OAB8O~*7Ey*ZKO`U9KY{`+q9y=vNECN}4vz_r7E&yi` B6-xjB diff --git a/docs/m2met2/_build/doctrees/environment.pickle b/docs/m2met2/_build/doctrees/environment.pickle index 4e86ccaa153e7e65487388a77fd2388dd0fef420..a71853ab4f53fdce1ef6a5e827388ee609e29e00 100644 GIT binary patch literal 25957 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

Wechat group

+ +

_images/qrcode.png

+ + -
diff --git a/docs/m2met2/_build/html/Introduction.html b/docs/m2met2/_build/html/Introduction.html index 2ddafe22c..c89e665fa 100644 --- a/docs/m2met2/_build/html/Introduction.html +++ b/docs/m2met2/_build/html/Introduction.html @@ -150,7 +150,7 @@

Guidelines

Interested participants, whether from academia or industry, must register for the challenge by completing the Google form below. The deadline for registration is May 15, 2023.

M2MET2.0 Registration

-

Within three working days, the challenge organizer will send email invitations to eligible teams to participate in the challenge. All qualified teams are required to adhere to the challenge rules, which will be published on the challenge page. Prior to the ranking release time, each participant must submit a system description document detailing their approach and methods. The organizer will select the top three submissions to be included in the ASRU2023 Proceedings.

+

Within three working days, the challenge organizer will send email invitations to eligible teams to participate in the challenge. All qualified teams are required to adhere to the challenge rules, which will be published on the challenge page. Prior to the ranking release time, each participant must submit a system description document detailing their approach and methods. The organizer will select the top ranking submissions to be included in the ASRU2023 Proceedings.

diff --git a/docs/m2met2/_build/html/_images/qrcode.png b/docs/m2met2/_build/html/_images/qrcode.png new file mode 100644 index 0000000000000000000000000000000000000000..68984beac9295fa662dbbf2d933bd8b7ad08405c GIT binary patch literal 144841 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

s#yDGd;bm#*lRi;V{W!{zx=hc? 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 XuJ2w+HtG8_(N5{C>Y21t#<%|$+at?n literal 0 HcmV?d00001 diff --git a/docs/m2met2_cn/_build/doctrees/environment.pickle b/docs/m2met2_cn/_build/doctrees/environment.pickle index 91ebda67a97f008d62b1b445b3559013f56dcac6..bb82bcbbea5613c25d1cd0203d83566102a4b537 100644 GIT binary patch literal 25329 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 literal 25266 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 a;ktOG#qp%u@#qQyurGKSen%-Tjr~7P`LB}z diff --git a/docs/m2met2_cn/_build/doctrees/简介.doctree b/docs/m2met2_cn/_build/doctrees/简介.doctree index bcc005b07ecf1be0bb887d1223aad1034437924f..26017348ba916f88346a21a59b0daaff48cdfe9d 100644 GIT binary patch delta 86 zcmZq6nv})bz%rHHbR+9ebw-!X|J5ZJMV|FddOD%^X=m@#j_J>5wY;1$|H+=o`C2j@ T8SJrBGQ=YADBGN`HJu9p&KoMd delta 67 zcmbP~)t1HDz%uo>$wtWp@q|Eo(d^1W>6eAd14X=m?~9i2}nOxD&^#xAqDT5CEN E04L%g(*OVf diff --git a/docs/m2met2_cn/_build/doctrees/联系方式.doctree b/docs/m2met2_cn/_build/doctrees/联系方式.doctree index df477c8d5ccb82c810ca819c48d49f8def02d585..e7e78891122c27ca8f576a7f87d2ffb38cc841d5 100644 GIT binary patch delta 380 zcmeyb^j?Lvfn{on&_>p4Y&sd7J**{3`6-oCCQs39oKibQBZD=AErUIFO2$Mq{oAZdGufR@nehNvYywbhFNnpsd-6%P{>@$-`Am%Zn|E>jVrI;p ztj8}g`7ECtWA@}XKr&}CH@^~NEl|_~D3Z=^%9u5IF24k0&E#$T8k$)gj0_A}tU#i; zhchoRH?^d)0PGg9L}zh^V(k>L^yJ_CUl?sCe-J29%;Etm_htkO_wc-Eobr70?q}0> PKHbwlrF}|qX_6iQ3_pY? delta 375 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

s#yDGd;bm#*lRi;V{W!{zx=hc? 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 XuJ2w+HtG8_(N5{C>Y21t#<%|$+at?n literal 0 HcmV?d00001 diff --git a/docs/m2met2_cn/_build/html/_sources/简介.md.txt b/docs/m2met2_cn/_build/html/_sources/简介.md.txt index f43dbabec..5afb6a099 100644 --- a/docs/m2met2_cn/_build/html/_sources/简介.md.txt +++ b/docs/m2met2_cn/_build/html/_sources/简介.md.txt @@ -29,4 +29,4 @@ IASSP2022 M2MeT挑战的侧重点是会议场景,它包括两个赛道:说 [M2MET2.0报名](https://docs.google.com/forms/d/e/1FAIpQLSf77T9vAl7Ym-u5g8gXu18SBofoWRaFShBo26Ym0-HDxHW9PQ/viewform?usp=sf_link) -主办方将在3个工作日内通过电子邮件通知符合条件的参赛团队,团队必须遵守将在挑战网站上发布的挑战规则。在排名发布之前,每个参赛者必须提交一份系统描述文件,详细说明使用的方法和模型。主办方将选择前三名纳入ASRU2023论文集。 \ No newline at end of file +主办方将在3个工作日内通过电子邮件通知符合条件的参赛团队,团队必须遵守将在挑战网站上发布的挑战规则。在排名发布之前,每个参赛者必须提交一份系统描述文件,详细说明使用的方法和模型。主办方将排名前列的队伍纳入ASRU2023论文集。 \ No newline at end of file diff --git a/docs/m2met2_cn/_build/html/_sources/联系方式.md.txt b/docs/m2met2_cn/_build/html/_sources/联系方式.md.txt index 5c65ca01d..de43593fc 100644 --- a/docs/m2met2_cn/_build/html/_sources/联系方式.md.txt +++ b/docs/m2met2_cn/_build/html/_sources/联系方式.md.txt @@ -5,5 +5,5 @@ | M2MET2.0竞赛官方微信群 | |:------------------------------------------:| - +| | diff --git a/docs/m2met2_cn/_build/html/简介.html b/docs/m2met2_cn/_build/html/简介.html index b53850647..1aa4f2989 100644 --- a/docs/m2met2_cn/_build/html/简介.html +++ b/docs/m2met2_cn/_build/html/简介.html @@ -153,7 +153,7 @@

竞赛报名

来自学术界和工业界的有意向参赛者均应在2023年5月15日及之前填写下方的谷歌表单:

M2MET2.0报名

-

主办方将在3个工作日内通过电子邮件通知符合条件的参赛团队,团队必须遵守将在挑战网站上发布的挑战规则。在排名发布之前,每个参赛者必须提交一份系统描述文件,详细说明使用的方法和模型。主办方将选择前三名纳入ASRU2023论文集。

+

主办方将在3个工作日内通过电子邮件通知符合条件的参赛团队,团队必须遵守将在挑战网站上发布的挑战规则。在排名发布之前,每个参赛者必须提交一份系统描述文件,详细说明使用的方法和模型。主办方将排名前列的队伍纳入ASRU2023论文集。

diff --git a/docs/m2met2_cn/_build/html/联系方式.html b/docs/m2met2_cn/_build/html/联系方式.html index 249e5dd69..03e494b9c 100644 --- a/docs/m2met2_cn/_build/html/联系方式.html +++ b/docs/m2met2_cn/_build/html/联系方式.html @@ -130,8 +130,11 @@

M2MET2.0竞赛官方微信群

+ +

_images/qrcode.png

+ + - diff --git a/docs/m2met2_cn/images/qrcode.png b/docs/m2met2_cn/images/qrcode.png new file mode 100644 index 0000000000000000000000000000000000000000..68984beac9295fa662dbbf2d933bd8b7ad08405c GIT binary patch literal 144841 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
  • previous |
  • - + @@ -55,7 +55,7 @@
    + index.html" class="text-logo">MULTI-PARTY MEETING TRANSCRIPTION CHALLENGE 2.0
    + index.html" class="text-logo">MULTI-PARTY MEETING TRANSCRIPTION CHALLENGE 2.0
    + index.html" class="text-logo">MULTI-PARTY MEETING TRANSCRIPTION CHALLENGE 2.0
    + index.html" class="text-logo">MULTI-PARTY MEETING TRANSCRIPTION CHALLENGE 2.0
    + index.html" class="text-logo">MULTI-PARTY MEETING TRANSCRIPTION CHALLENGE 2.0
    + index.html" class="text-logo">MULTI-PARTY MEETING TRANSCRIPTION CHALLENGE 2.0
    + index.html" class="text-logo">MULTI-PARTY MEETING TRANSCRIPTION CHALLENGE 2.0
    + index.html" class="text-logo">MULTI-PARTY MEETING TRANSCRIPTION CHALLENGE 2.0
    + #" class="text-logo">MULTI-PARTY MEETING TRANSCRIPTION CHALLENGE 2.0
    + index.html" class="text-logo">MULTI-PARTY MEETING TRANSCRIPTION CHALLENGE 2.0 @@ -47,7 +47,7 @@
    + index.html" class="text-logo">多通道多方会议转录挑战2.0
    + #" class="text-logo">多通道多方会议转录挑战2.0
    + index.html" class="text-logo">多通道多方会议转录挑战2.0 @@ -56,7 +56,7 @@
    + index.html" class="text-logo">多通道多方会议转录挑战2.0
    + index.html" class="text-logo">多通道多方会议转录挑战2.0
    + index.html" class="text-logo">多通道多方会议转录挑战2.0
    + index.html" class="text-logo">多通道多方会议转录挑战2.0
    + index.html" class="text-logo">多通道多方会议转录挑战2.0
    + index.html" class="text-logo">多通道多方会议转录挑战2.0
    + index.html" class="text-logo">多通道多方会议转录挑战2.0

    s#yDGd;bm#*lRi;V{W!{zx=hc? z%EN7EWtAFF$!E7>U|=Y#Fh9EUW`EKVUf!pTG1tx?wL}_m84en6Pav-*XKV+6T_c{PR`NDR*bnW7n*oXaFH2zYIH4$F-(z+wi#BRv*_gl>ICouxT_kwu57f=d$&T|h{P zIeplxR|ib;c7suuXEPcgLjgD{U0M??QqM7mV>O0KNczTkIQy?Unl|1)t)v;}q_$k} z{LB@L&S#)RsgLd<)=J7<<@zX%+{@`NXnSMOf9}qw)%HtFGFMbmM489cG>T>ZmYmX?Qx^rQPI-U zqF)13@{-0psMBvV+D5bX{is<5!7yr2&n=xm)EC$yWb$ z{8!#!F}o{ukun4=5CE_DAj;E%x_`G4vTvnsg z|6<3sd2(0MP`@tZ>s2}h-({#YM@k;#yYRpo972Q>s^VCjlPi$e@LrTG=-K9|G>*%c zLD^J=%64o+=ZdOOa!cCzyJi3s5JIadN|Hz!1c-P_#$NZ!5n(CvT;)BFcTUNJE=tq3 znk?iRezLvMwf~BHT5$KSEcUaJ&HgK9vi*E-{qIjs zdG)PtiYk&L$a{`joywc6{*XDhp7h6ZvmPeVR$EiuD{&~PKue$&5OU7*xTbfw6pC)}b9f_2Qz)bHD>*4Ij zh~A$kC1LqiR#wU@E8}_`VDTLs9ld>%;D)wLBmL{;n_=XjDK0L4c<#w6??*f-tVwYSFWsxIi0AwEm94}iz zgCJ6@Vx6OAWe3w}nNr&Cy@*}5yz*y8I>%>u{cak@o?dK2)glHtp1 zmK1@dAD)?q@|#pJbA1+=b?i?!*fvGUGOH*l-9$p&=&Hgblx>!$1mu}^>sCgyJlqxm z*2|72kh7U)B~|ASA3prtU-$o^p}hD*s7To{3K8cN^z`;JGBdYnT}f)Xrlj<$bd;8f z=Nj!8Hlz9-;ys23^26vArWw99|%;|M_|IC^=#$bul% z-#KB=y62wC^=gDgzaAr%L5jV3T5!~MYxR5kAAMy8?qp&T+igX)aZ9pj zPY<+NI;x9;2;@q~Y5aKHS|l|8W;NaX76ZsY`O0dLNk-Hvc*;yIw^a%m3(h%Qax%3@oWJ(JDL#sQEYSctSd6#Jo-=1?RP?wP`b2;GF8bm2_vQt z7k$T*+26nQFbrDNxx?WPXoz}fnb{5u&t^3WN}jEGaXZw%5$vXl_#gKn9*M^A zB@5Uorb+N#;(?Ba_k09nj=o60bh8R7dy1PseL6)Xu6-6jIq|CKh*jpEgBvaqNmsmx zvDExOGtD&>$SZ_rE*1ubGOPJ`)24C!SvPh+fn7+hn(nbqQlS6t(sj$$-0G|s#3*?&UOgah+m_38vV)3w0-+t(Vvx- zJ^*GSI9!oQ4EJ{Er_eb-@UB36S`(k4q zg=ydCX)39}iO%fs4+yA(_LcbtF>8w_!+nqe3p>2mvNPX{>?Ew9rgqq|1>StIY!!*r zz7?(n=?KUCE|tznMAOm+W#i}fOlova6uUNC{2Tnr(;wfXmP6Yqwv<1eN9(ktP}wHY zOxL!R6is~F_Oq|(?@!C$ivqHo{{6@kR+3S%E!F>uxy64=PCpyp)7PW@4*0}vCNp8u zyAuctNYS3V=;BF7djF5VZ>J`+xpXdeP@mi8o~8#_G2=8?(pQ=lP(B*A*feEZ<8(gE zZWURF^Hx19H~e}t@;j(V?zVqyyK1Wf%`$V9~cMA8;JsA#x-3VF$P6MD<%+_(rE6*bHI&J$QwJ3L{P z)mSK+uOkgH`(FzS3B6iDFy=jA_#}l8N5tqsImk@}oxBq+L%38vfYlh+03529fMw)o zGtsVoyF)@k;*VNb$emWw()#|0j-AgWNHg8|Mb9ESqkP#VY{Bz74=*@|lkYtk*o#ni zY_>_4Iimxhk$TA>hTsw`!$iUY0@g|M?8>rar`@)V>4_x)ZWXx|$xz^WP`6!?=HcM* z2$695xzFXVYM>9_mgdH}P4eXA*A)QSl5|bsm+}G&C>aY?Y3J$M7mFjDM$YN6SwN#rX&iPdZCn{ctoW z`yL_Z* zehlsm$k?v|WgM%Wm)S81{3a5dz*e>-Lx>T>_U)f|-N13l=?_4)fktX(8`4ecG?I#Z zG^t-h_+G4=gm-ZsY+dV1d}D`zyyy`o@qO$Tn8e0n*Y!Bf=Wrso*G4Nu3}G8j1UewI zMsV;(ing+eD&0Q+8#$%`@lBySVK~B*3YRJjT>;C3c(1ZH?!#aB4pCy;cj&;2*b|jC za};AM$;;~rNA{-JQH=^GKD1^F4U0YHO`o_l-E(CE09W(Im?mr1gbFW;Or1oSxg4QVX%`5IF zGHXDS((PB!mM0SMB<)vz_0$Ix3WY~U7sXEij%p3#6UK=q3_J4Uk*H8p+8vc^N8SU9 z6s?7@Wx*^H`oyfIE@Tmrk>U5(`*s%H{&hy?(6bC0ERg%i?>8f)Psg7>DK|N~@BNCF z`I*lkVh{ZKweNM)w{MRLxQJ;I?$-9k33%fv=p4=6ItNB{GElI*tQI)pM`217CQ)AJ zAp`hKd>Uw8qa9Jg!l-Tcbte(5OJ@{7Z+j1RX5ZOQ#IXKoi?E6#83&~kzML2z|D7ij zzVDEr)9Hp4XO_e;%EQ>`#z(fny^_As)kaJ|qoLvx0fT#J&GF1Fe>6 z_9n6&>4Gtm?wHxUf3N=m!>_aGCbY7oTmtg@* zJ(NlSj$gBC`;&s|^2#~;FrjeAHP3j8aZ_T5zIhfx<^RnR%f&7gA_RTaY0)<@$d;rs z7S@ydCBRN7qllc?5O}6pwZQeO5{L5L+H;H;`!XoL|RYLor#S z#1yP3#v~MwNQ5af_H3ux-8q@~Idt~ZJrAeuMakHe>5p@BvQhtuH^+v66iZqU@`deo z`bkBzdE#^xc|W-(>}R1=!%rO&iGYkF2iT;4@O2tZwD(*0@{PVfmrs{%KNxs_-Zn0S zO!uGgbn7pdfh$!sD*ic@j?wgFD!%U`pZF0p|L1O>ydFQML0pO4n>M5jDbcZ#!e<3gya?RzP;Dh0@~S75cO3dJF2Gx%TZ)qu?D+?H zkhPOYNBFfK>I0U*To9j?CHxeH+&vCNxFag6ahC$jR2qf4@%EkISB|vjqzx@V;uH|H z4)s60{N|WU-4xt5Wu7bqzgyWQwPvQE!`}fW=7#$e)AkEcS5+vH_)w$}uIMcXO|a`s zGubwKd3wGBXu};KB`K*>H-#LUVa*`WQZ83y!whTAKizdubPh?BkAq=ug*`b95TS!V;Atm#AVxEbuk_ouYp4dW7p6WH zwA1|&{fmxgfFosEZ%_4IoCB_0X5u5b2M2@)(HM@S@|-9$ut5`_Vm( z>UHjsa7->*TW#Z5MIkFdyp|`8I7*)%Y#PJ!duJ9PYX@KUtkNpjZR#aJrbEEC)V`B$ZlIvYxitMr{SlEl@Fea|JHT7? z86Dq4!~)^rYLwuSm6RyZYmAn8N<<_+W~BLy0J_Z=5R|r5_;bH`_Uu`F=E+`xTXhF) zv7*$Dp($8ib@O$En_(eTO@E3*IK= z2W=Q8H=$$lpBOVz&nNwCQd2!rcH_R^e$g8<@*yq1Bhh68lI$aTQtLU5=JuoJiAMS z;qGyI93jM(Ayo$X1qEEh>bFaOb~!&&v%wL2sw_SaM*vlv)dR;6uJUPR140MqlSt|& zi-mqfSNv_H7@$DC+%#R}V2X6THEGX_kkvL^T4=mhvBFqGG=S@uY-%v^gbY#G{Z z3*?&#Ovh6;3zuz3-McP)y?OkS+=XbFM4^4Zz^73oD5!(3=-<{1G2-sw*U2wKV0J*% z6(`$p@oI?Z!CM{3$tE`E2EKZgjBr-%?gX&LRG? zNL9iI4rzJt1n~}rQ8|S7irI|xJ>SGKZUc$B*wz8=w7qbP0f>(mM)EKm_)X~=q|vV@ z?#hvD43n%L)=94I-{fNa#&#BdzI^F&XAV%{)0|C28j1^<5atrB;L@ogs8lVx=Ey{+n>TODjA6YF6alcgs+zuH zbwT7)T4sldI#HT58`3bIh^&_3q@t7{vRKic9XZw?`!eB>$8fBoVa0P+T{X3#W?|{| zF)mUdIjJwovv$)!LYM!ze*#*v(HE_{=3^%n*Fx*s*vJ&|a&=~>r7HiWE0yHDwDOhj z+>EAI^W$7}%ll2nQ5k>yPuTVs*;LJ8a4=@--ot?9)1&r#^eQ?g?7x|AU84Qx0FZ#6 z4*1x)h8`ggwbj#|l)p_U-gVyS8LPagj_D8Gf5N}!O=3%*sL12K_*|baD`7U}rKr~xX;C#<*mW|;qpK1oMDFMoPq=c;zAWX zSS^JjC7fX?Y+||wt`U(T%MW^g1Q5XtboldH<33P1Z2mA1QunyJy7KVx`2r1`)?rj` zMgV0Be#@9E*a+Sk!|>3@T8zRNL&Q*ijBqiIV->0?9uQ)9uWEvZLBJXcqWpfYAT{ru z;B@ig|3%lA$Hm<4e-GXEHOdwuai=1oLMlrlS=#qKg%(k2+9#AH;udWvC6a01w67G} zOZzev+V|bG&GWu;&iS3+^Ln2CIrquTH1nPBbzPs&d;2VTDQtANv+?55p}!zvkr!m) zNbu8*ULQb%Puimm-659r{gTMBwx`S?M3Osqj$;c80W-1KlutDXeSvCerv(+e zw)nuVG=z^|0DuhnL6xB7fdfj4)A;A&AHa*`%44x(nBb1|i$76rG$Nx>rCzz`B=}8-pSe4mGN;L1egR-LY$Cj zVR$@zsG+UB88z;+rU8oPJEJ1^3&xZ~{$7{a(U6_nx^=@Nr2zb0eo@10{e5LH@^dh? z+R&Yx_7&3Gh3?~#a5&2o2leyk9O0xRiV%&O&LSRCTr-W&2%PkRcY483+AQ;OcWrFQ zo1XL1ME0i%4@vPf>fW0}KThRYubuf$mA-U<^;Y&7>=ZXVI%Xk=?(`I6#Q49y&nJbj zx@p`HSJ8inHj8Nu9R;_Bt23Rip)4o0vT>r{6s^!Dq z@QOHKJmgj1>^jca*hCx_L=V|ou&SyfdAE;QBNf!4vr2}|?l zl^sl6A?!vw^ahGDO3+(k2f`Jz7h~&n{j{Tu|5ZEADrh-3TsVd<5MT-U3EKC{dEwlW zqZ}LngjN}2a1t6&QEuo1-r)QY2$YhL2mmKx-abA!NOB8y2d1HI1`N!b+>aV%rN4Cx z^iH>XqP}<&1QKTry{S*2~# z%`U|}YgijR9z0<8X5ncb9a3PV!}|7$iuwQ(BkW=Vz(|FLra5>YkTmYumpG>Q{D6m5 z-)t-3%o}-q=*Ef4sX)jgzzQfGoWLG%75=VARc*0zpx0HncI_l(Y`cGa-H)7( z;9pHk$<#7J!^x&V6Jwb-jBn?R<^)Xc0zM5m3eZ-TrvTI`gqeI*-Y{B{mm*inj@_Jv z4lK_KbrPT)o(}_a9Z3Iy%Ox=c+PT?Jh`iz>LN&N&c_XJ#BSxwB1E^RBxzZ8pnKO&U zueZ2DdpR?vR-JHFsho-8F|zZ~6d=ogDkp#us0fm`paHj{bVq+x_tT*U^o_NcY32PsaA~TNJNs2#7rkEehaCMm^YhL<=T$o&vOxs(>=kRU^^->% z$y43ghGX=jVamwxFmH64mv|3o&Cp-dXT4sC@87Q&+lX)5_qi7ERP^(xkqi1d3q}Oq zf#3$pB+FzWr@@bmo?D zNPy5|W!S{LAeH0@Lho(pAV)_HKVv59((G_U-Vm<{`WAlo35UUcDx+r=rKKCl>G>(x z<%`pnY*PS`9)`7({xWC9pF?NKqICr=O;5&uQGNRY@vM>ob7VIyuL@JRLp^Ye=U-aN z7i1(i<2>a7dRH>umxQujmwrTkmYX6!QE&tc1wV<=sr%5&r{iVsV>x8;0udO?^M&`D|a0^@&aAB zofw-d#7W1#&!0a(49FkO6CPYL2S{-3#P0lg_MOQg$zz|t&g*OMXobqLHM97R9rpPU zU;|Jox1e+^OGlMb0ZGKShK83^rR=+?fGZxX{TnYK&Jg!cANjABXv3yNfJ!`-3w7aD zG|vaEew~4?uLauxh3CZ)8~&ZUcA46K$*W2HKte^xu#)+Cz)RJ)yHQ1qn&_iyOY@F{_t;X>$ z+nqWn8KW?1d;92zJy~9TZ7KbxJydD|3lfCysBKav=Bb~Rl?}#A4WcJB)2Ha?UpW{D zkIcFa8@@upvXQ;D^%oi`5p^(RT1XvGVvImR5C9F(;*W*60LX#?k^$tFy-En1r$+|> zNRg4DA$IR({e66aQosq6uK`Z6MF(-pn#)tBePBR{p9buW>=%ODw;!*hKJxWl4;81+ z4`$vqDg>{F(0+Kd&!WFn$6uCigNIi6pqSAkKx1;F)N-^;oW;%){W`>>q`(Bw8BTbV zmy*s$uwvE}^%0PtYB`H_>adH>2?9zfTMH!d zVex;q5oNbbNV&nl0oP4k8@_jL5TdY?LcOl8?(>En7`Mzi(v=0zV8VAxwcjw%mZS1B z{}_%M{~)@UJnN2*4kBvWSu2E%<}Lh0e1R;KFYj?6)fEkZ=Y^Ktqhl8jgg=YfpB7I; z>&t_N^UP2qrr@$j7=`Fm!2M2OOiD+^*cE_2;b_h=nZ<|xj#lHXT|YtKuvIKbO2dw= zhzcJZ5NcOM7{2~%M4Ud5XHEr4YyFisj5a;As2IWx6PGu%$*=55xl^UI*^`j+#?%b} z!yd&m_yecVXpbUcVQJ>T(9jU^8Rm`9putIib^ls}jxidYcduP0zwLCPCXP1a1C^oO z*gQKsKa8C)6LUYC?j8P*kErA!6~ETbLH`93rKo*B3Mz6|g|mEKz7+7=0cH}Nl+lm_ zN*z*l?8}5PN;yPkMNV77TUZn=hsbz-t*NQ`VFSAzhTiPUgv8D^vDBOBT+sFY zovaP@=Qs4QKgQrB=I7&EO(5>8dHa|J1kMGTJO}+kl-r386wt4eQy56Dxn}4i4sxPe z%4y5CM_}rC6e{bq_d*YiTVRhax}GD@Kk4jaY>^tFP;PIaxaLEeeWxl?OYQm^V*iRo zWu^WZntUS1nd{_>^!LS}>rww)`a(obc^b(%ugbU3z5M+6Oy|?FHE4cjq}n_rF8wz@ z)(hzt8T4&7!#53H8zy0Ba3tbu;i!!RN~th}bf~zm&PZ2X$IiZ;-vu9Y-4J3O^c^yE z2c01t+gSMZYs`HjUemwEV+cT}7X@g6&5^I75W6Te6hqEu%I?S|~ z>+0eZN+uCXo(I#i9493}dONR_e{&??o2;q3T>iLD$~jq^sQzajqDb*9$1!pp|;_Gs(QpaC{n?KaMSO z(g{#B$rh%?gQ(Z27*@H=%|f-vn}@fiR52VS2*C}0JJk;u!j~fpyMhNxNI)P27}fp9 zGx%i}s&~#(>?NJpzTfmw!CGm^S-^1ee6dFF8Pr@_+62tNIVUSEQ zG5Xg z^hT?xr>BofQlsV#fE_dX*K?1xEn2jzKPPa4{r`H}=Ahv_Y-=Z6pR#qk|JSQ+4!T|c zO(Odz`;*cDv+OAfrA7TuCs^|8Rz2ADnDq=S(l00G6f)P_A8~K?OJ4M7v%F9`7zq0hu zp~vWryKVOxr%j+@1-5YJkEn%m>?h8qFHrn%WUq6AS^PfX1bAE!^>8~@`tw$o-v)C^ zHE!g&@n@neE9qRR(uI3BEVHLRG5l07nD9EIClb5(Gij{Z&DABbNKM_S(8D0A5mi-_ zby^_T&~=>3o9L-2<)Ol00xMHW*zdWe3f$`XoTLwFZ>i=$fz}P7Z(r@5hGo)=_K~c$ zak#4QI}8w)%)?sbzr~@Jx$i-=HTM$PC@pedHsoKKM-jv;AsqlEhT$WP8A~)hUFaPX zHxW!jjZ1B|8Mciwh^Kg;H&rw_=uxo!)z6WX63k!EKuzJY-?muJqV+aW?Kr9? z7Y$M?WVgBhv-<3bE5Ucm#N8OJXW8F=*yeGZpv{R2e zEOFbq_?8<-#kTEZ)3eDjS>`73*1H_N>WW>YO5>kgv&u}zHS+JptT<823#eY6&K!m5 z3!D2pzk!-)Zj?7)U0eXDf^L3pNUoy1dB}pmSThKli7jP(1kRue(7hZZ#Or2-)`m{Y ze+42J2Z}|4r>Ex%fZ!D^19*rGYGaWX(elCb(F7H@4A|vIVKapqhIh&y-Uf@hxKqN- zkU=@|ekyt;>HGpWCT9a@m1yaK0m26&*us0}C{!%i&!hbYDnG1cPEM{Pe@&eF7-~X} zhO38dQG|rzXkHw>W$oIK35B5B%Mo4Ha$Xvk-5CG^ibdv;{7dY$}TKYKR0};8gVP;S)VfQ4QewSUT&dYO0H~Cf_iC1UX zn+hq}JgCSpBmL6ou2WvTu>kd#L}$=gF6})%;daju)bckJO8Yfj5S>(%lXF}c`@$Cl zck>lK;Szh?v+FzxdLtZQaYW3XGVDBwVRo2qseuzPc^Cy1=Yf{_=l%8_zrk3|Zq}GA zjC&+dkX0ZMeZ4phxWUqaDL@}7*Op&4GWtZ6<{B<|I}ta#Dm<7=Ir%rF`|lX=Y(?2$ z3rUGF6JaD)ZBVrCa_S8l1OS_DV{}N?s}>!xdkqUSOq1Ksqt35GM`z4Ll7Lm4_|4Aj zKq=bZgaNfEZ3DdYPr8)z?zL4xdkQjG4&aom|k@a z4c0Y6S|0@w7gO10f6*<|>G$v7i+daqk^;K*SCoaNWodg!fI!47tb~O&YbM)JwBLbg zerb5A^>zP=au8D)=`Ugt=w^hCb#3(opmJdZ&Z`)$=jM(sT*WQf1&pbO8n5zLiUWH+_qMkA5d@?Nt z@2qr*xU3f+fXOsxRn>LK_goy#8tqcbdlJ>=?dKO}w6iU1$rHu3c-3XxY1qsA z$C<3XQn(c{A&{lTj($2|rx(jY@xXw!mDT9%$FP8VOue6!V?#OLa8W8VUD=tp-|ssY z8EwM~zMi0K=||P)m-P~ik}RCCp=y>pOvR2*QYbsOTma#!zFO{R%o_hih407a=^Au* z1SDyW>-F?~sqbN9q(Hv8QGjumMVGW zWY5@RfkoLB8pGafn%^C!s!}B>$7Jt4W1|SEH%KhX-hVZNaifjmceaP^s9dJiF*8le zEX|rl6uvGj6-xH)E6)12@qA@X?v}Ziu#~FS8o_TEJ^AVXg06cuV444fT&anlfNa7D%{!X#*K0b%gQkJ z!$*!-b%3iH3#4{cxQok4S0~HT?X-;WZ~;=?sLue= z;Ku@_PN9(hCmhRHVnl)hY19mJNCT&$iw z*c+DZ^ugFWxoOrND?tTF)QD!?_$kvmMkWo3SVHuf4Yu$S6H@Ez7V$)!0s-`z`U%9_ z#^e66_H4>x%~+CC!yJEI+o%SjN?V8+TgSe5a(xjQ2lef39P;LkI`GhxVKip!j0wnX zZg}e89IQnpYs`e+k}s0;`fO72YIkA&=g%?d;H`_(NWteLg`~J} z0v7PSjLODYi44ntXCNB5<25*hYf4i`Rw`g zBAU%5B~jT21|csA!G0EEkF>q{&3zg0+za|5$;R*$oNdpIH+$Op{96lvIj5bd);*Z$ zAOT-J6J-7Rw$|bIV6dU&KpJ~Hub^O&e%8ork`r@yVe{bvxWxcq@VAGngv;QY&YjxI z$$1LUxwN!Q&-$A-g}}*4deW6loa4%grYd)sXskPDvx4yaHXv?VKE*IF3=Uq;bHb`n z)_F%cB?NSD&6+irrqmerm+9$KX}7y^&^-mYELgZ91TK=ibY#PL?^cqrYsQy(4hB|_ zv4^HKe;Vy_7?CV}FwFDFHN&NQgm03g2OqwnMP(Tt#=*rE?kDuvUQK=m6zsa+C5JCE zfJ(Gf2_x$BCiJ3tPFTg?7z|yXCl4Qn0Ef^60ax=g0??ed5NA8!`=*ky^e0ssz(*6&2S&?k^kL1SsGv zFuAzb1c6F`&^OOX!Ltd-C3G3}S6<=^BY@(H*~ga|V_o0xL4PYBHVf1}{<0FxuH~Yz zX^o;`SrQ%K?=Op+Fv>8ESX8UdOFb-Hujh0eLM7q)P%Q6J+-S?9i#LQ|%#2*D&Y3g! zbGX!iqy&(%EN>cV!C$MYRK`aDf|V0D%E$tX5inRHz*(BERHF(ZRZ`w2_ni1*5@gv@ zydEPg&XeFKLt;b~{ylVD3E4jC14ftbKHsC|Ln5csMJd<$KRYj_1T6+2b=R9;sLHw!hkw%FBS2&W-i;LvUMBHN!?Z(~za9rTKB)h?r*>;l;T)MjuUmPQtD zFv7LR%xGJW#DG_?YVm!$)kG_QSW^?{=;&A&2W(7ROo^AL9p<+50bqNVp!V}f+_Gg$ z9Z8R7k_xct6{#f<`=n^cNW$-OIAuIw!o%Hq(?LZ6^Lk`LiB`0pjrmL9~e zgkyt$yotdGBzY8e&cG+5Vo?EI!kUOnM?bEXi3=Rp3t@`?%a>egnJA3orm;7tg^3;lFLce?KC6xQ;6Y`ZW?(lw=Dj#%j4NtWl9R&<7X9_t;+`o`rOHocQ0=-^ zEuy$2cTim2y?AA7v+|S~zRDJkziDs2lz3GyaJ)e^eah0k(VnPF4XsRiYyU>N$GF^q z;RmId+Gc6XpLr>Ji!5ltW9cIA`zVy9cTqg7TS~hUye}b8OtVJJ{oNLIZ)MHsMUg!( zPxSOfCtvKGM{zweSDu_okc=r$&D?!m-*9V!?ke)=>W0@J#uEFb{#AxhRHb{^xaOY9 zwl=co6H9&Aq0C|GlQ))l`-;C8Q3Rjw%sRH9?}~(FLX_pw$W`YOqE@ktzV#gM>070S zBFRq-B~OgJ&-8rGgpjfH@>EH6$;ef!6Ul>xBf)oJF? zw4|YEqGYGH{(`cFvwSjJre`v=Y%*KAXR`f7&y6y?Z$bO1c-up<^AQh)w^HPa`zd3% zK%lYj&h6VoTASOwic9p-S>L_IO|t+Z)~GgAV4Ly7B1vhuh}P@M4DLJYq{O78_c;2O zgl|C<1iGn?Ys7amJT}Ius@HcERt2H4KtP`l#ZhG-OI1ci!ico4XfxZdHKPiGWw}OT z0J&c9HeK(4H9nk9YZu(M&Gq)3J1Gs+&azu5V0K5$LL>Q}J_8G^Ta~B^IxdoS*w_bV zPmT}_sw~WrQmAr)MaiLby`Xv!zZ4+%j1Cl5KTFzKX}ujCr=gu`DZ%~Zg~ZbACf#q? zM88#6`=rePv>Xi#54eX#u29ABLn)^So-l>T5}y-Yb%Z1(ESr)o_&Gm64mA0Gp8b=9 z*gN3d&F#_4bn=(=daF)D)}Nq+gpQrFoGlvUsMwc?^+(C#Usk_y<3@A5FONi&BJhQ; z)`XR+zd5UvUxofwJqwa;;^wrQfnZhcMlT*iutQ_0tZD&ye)A?g>R{$+8JRfLZ~TvS zurBL>DqUiNWxP?GhF$d`spbc=d=PD-jv9xQLHmK?U$G2lOiBDP>I^^yA-Hx2A3Wt@ug=O1Il;?+U2kTR?mt?S)J+HZ7I zoFjn!dJ&70`=uY$n)XyUBu{a$xcsS*3Rpv5xO1mwe-9Z|r`nk1#R}+U9wpuR;3Osc zwBhm^zkh|1sUL6xqxkPr54Y*ukE?h5_f$4Y`!C!hm4K}BY$3XSi%(wQG7D)jKV$T? z7jG&;c7vy`L=k`Nyk-=YBURq0{j`N>z3r*RZ zn+wAHq$x})JQcBvzeJF5Ss!C?r(Co>wfOIyI~9n2y#X(3S&1^Pt`t7Yi!jrAFj0_L zUBCX%j1wwjlG(7ScwJlVP|@61huoB1Q$RhB5acK}ALP;7?uD-D^OM7%uE3a@F8HquiL_n!>C!BblbEW0nXAr_n z2BcyNO)=4!UWI~RX2gq^ghi6_d)EXfMerXJsyJoe0YbZ{D_mflo_)CjRqzw>9#r;7 z=o8UY9KszNZQ48BY)+!H8#Tnl#4@-VK*q)5HLW`!Dlb5V=f1}gf{<|FS=1TW+jP_| z@;8X1CZSpY@X3gU$=d{#>yHu)f(e8zVMz~pc+Co?t|ZVPSThD&ZqeTr{nQ*t4 zM_l`wY(HYspNZQ)0BX;kxYE~Bm+>wCC_w_la|!23W%XvP3jd4@3F-`T4l^)5)QxV> z1?V|qfTDjGTXV|-fZQsyLo?IUqr;|g(w}7>Z3r&+^7vw%G?~82($X^HXlX$Bh@`Ib zn2L^S-?FVdhWOBHKlTFcQPk1nO*E>(KwKSBh-Gb>v3c-C4B(!ko632;^(B^5dOEtw zm`sezrEi_WRoZBJitmaQD^vnXX(zsOpyS(rmGM8P zusB71WurCa*bXm{Jqrx{3WOxSH8U#HHACBrWo0$j?QH)Tktbo9c&S^|?1G>L&D)n( zcGryK&aQ#SiLt-zmr;D!aPsJ8&*N8TE7B6)x6&P8fGNNLo#r_(VExEeO3Kb{+D|l~(OLE}jgt@X>!A zpmUf(IvbnM;t|z9|LWt^=K3LK284<*j`G3z{f8;l6#V0(ldV^sU9WyqTj{s7L5f1z za0m4OMfIaFc>4n`N8PGgv|bm4 zpoCHFH}~IfT#M83W?e_=>v%*a+#tY#2F88F7-u<7>?Qjtbq1}&(s0zJ*jd}>a5u!Y z1{Y%PRvac>T<^f-$Ztr~b{~^~l?RxxRSgmD>&}AJrnfiY+{V8EHij|db($^i=vpii z_bM?JtP*-GjIvdQ+^}`4%wn~qnj_453cFfLJTVcj+In>LN0Rd!fkUQoZ0=~Wwzgs7 z(4uRO<9J!xBX0D_8FXJ`BHR4=wXomX)Ir}RiukGiX|w2zeB^xCFrgx-CU6D`qk_8a zV_BP69yxiY2qO(vPglu*bTE@%=-)Lfnu&cdgA?x^CD z9Y?|PcfKEEc+CuJSk6oO?~8$Nfs+;vOR=U8kVZ*ZudLQ{tHcXn^(F`P(14NdHT&Hx z4G@My&mo#K&l?dw`y49emkwA-jA=c%%(R!pCLyA*l215`!J*ePwr!KsevRzOG zNzf6D0y^d6`S@`tuCG8lc3nA8A?WRau~rbyFd-8p0ofm;E$C2`l5q+=Kc~V07s;bm zzQn}V8bCG@KXjHm7A;z&F$-hdJM38s!g|V6g}x&twX-IW7mXsu^lKdYQRUzh3-YG1 zF?_&YmWzb=YC$kVvcVI+xL(1~wDlyGzQ%sC7w)G5{lLq#34Gz-F>d6%RvFJe+N{$g zL^ew^vU(wb$GbQe?L13b>`px5RJn8144@o=uEZMMXT~5j&ST$EDMBvl)97f+r=#4I zA})gX&Hbn!#)k3d2fgn9ocd&uACHTRyMhCoSJtci9xedtwKG1n$ z%^P=QvvD1g_n}~8uStiNga2`>{7&ElW_9@5&!I{?VFs661-d(qo`%}mGLTaW@1`J;V`Vc%0U0}oG{Di zLE4u>bnji{l-ZO96d*E9ppmF+e45HG&jKL1f*j;^;NFN9PO#$S5hxKZ zfj3N@h9t=k$R2eTHZQ*FSdq(6dFTTXZ`+!NcD|>r%1MchJ(dQIiG#fe)j26C=`xBg z!IDDvZe7ovVxks9o0j z62e|ku{%~4LPzc`u7!Ko7Tl(%kMcFBb3w~JPGg~pSfj~81p3b?oha?Ywm&{E2_Bml zWY>Z`-)*M4F{{~eS={z=ZQUAm`yoU|8R_-0T!0B>peyn zbj6v%xAnLBJXaZB*|^T5u89V}t+?a$i+koxS@akej%|yavVx z+~>nf%lD{&8BF=okDVtj{n@j%YK-!71s~_ZmU$EDBZGr{WKBaxVKO%Uo8 zJ|&0L)YSSd#<3TjFoS~C$B{weXRcUK_$1dD*>Np7_8iU2cQiT=?vFBpy?JFPw7q!i zGaQq0rqTJyA}!0IZ=|ECv9Yt6HH%-u+<~E6RaY`W`x1TDrXolbE>4s@4^HQmC2Dmt z(S_qnZhiV@ai0B$T%@IeA?-r$jRKfjw{UB^Kzt?oijaaJI|)0cKbkEEBe3&{0_Y(S22!DL|X?#4f1Um z@AV)~iM(l?lV1tsNz9skjEsiP*@D_y8ph8NL^Oopz!iYRmbdSzgY`oOI?J6rpGL;o zX6v;(B6pL>S!^|Gjm_YreE>8VGjX0)KxQyn@0&0~1d|`|&d{`BTpr@g&0?qIDDnie z`SYW?aspN0+)s>^ttOR1nbk8iWNpHk>@l*t@m;*Zj1Utxp*2Uz>suCCqbqDGGhnOIu_0(0}0Eyhx%U%v(s6A6K|i-%>dA8jBcZ%S(F(mA9RN11|o z2NG~aMRyKJ>KyDxoTgP#8jd84yUH~zz1(vlj$L*Ri;np7pa>G90 zcd-E5H3%`REmnciPTL-OdUDoJKwvM5pt2}?P}N6*6LSvY0Y)lxWd&_2GM0={0{L`pbz0VCYZVFi|@nz-HF(gyTe=)akS2 zhHp%Ka6bc*bO$B`F4r#u3?9=Rg&d7UNm+MbSF6Pzci)rtfy_+-F^yx#mo`?VmJ*Mx z&m0pcawlDI>LJe}TPF)RZ7-_g)M>1meCG)Z9z*nEYpP*5cI->6Nj3xHLqZ6H$AYiJ zc~R6|6J46ok7SHGO!;xIdJRh#-GWTRabSYQ(ou0ij$`iRH9ESEIJ5-T6B%%h5cEoY z2A?Q=Q`*J@CX2%(6S2kJa6b8^@Cz~p#)i}XeyS%)LTNIbu+b#PLqKT)Z^^^Gj$nxT zE!DR3s1i^K;=7(reI-n@2Z;Iq7JIWWs-?Ez2>(9Lncj18Nbfo+iS&A8rryW5Eoo(LoDnXm-+VS@ z-Ct@euR!v5>{8Rnv7SD)o`3V`>U?G{w@iz#x4DwjT>3wMzCPPw5uYTvTZ1E*cn83o z_4^VeunTu@yJyi2~p8I(cMP=n}gS1$Scc3aQQw9^I6(RVr*== zV-!$Ona+oTK*^rfhZlEn3n=AZFbmzAR-gXWSWVoA2@18I{^Fi#^?_A5=~enp)!fUC z9i0i-St_1rv^#Ymv|nhC#*I?(r?mHpcAjh$_s@VMJ4srJ7eEqNRO2E^QaK(Q0R}vp$CZ|bp{g( zzQqGr-;2kT2cwqVz$) zkI-{IZTpm)+lfn4X=cfX)5zZxUlPPDml85@4KmP4E*v4@c(-uwk6<%Y!nWx)fj84L zifWLrT8IupT`SFY4+57qH8q14C_^BYTTMwp!5eHj{Qc3o_HCSW-HcR0Zg%$LFr%pz z0jLVZ@##L%tZbiDcYCrqOkoFclMmJduLvTuXFaA0u|-(f+OE^pGdns}h}%iADb>cf z4ieFFTx`w}Y^|a=XA6cQ-wQ?R=z0fQ3h-d)l>^J2a9mzN$AxzeycGf&u3~~A5?X5C zDoVkB^S39#%FO+!UTA7MMLC;{)4U$(Du!ub$`tTAZZ%RsMCVj#N9f$;|QSb<9*h7{qhR4Ga_ zt9i_?8o@VZ55FzJ285;bvnhAPywaSQWq;df{#y&M-~HY_f%avah;=l-(h|8rg9NnnBF9x*Nz1_ z-e(b8q=l{4okAlWfp5|yv9GTWj6b;D8bv_Jb9#>2dv0!DNqMU+<{uXuYar(%$j%@` zGIukyAKh0c&>1eNdrb|gQvL89{fL|T{W}KhZ%MQi+&oy^I9cFs2=_gI@#1BmEv*Fv zYgU~CO&ft-NZbCTn7&9Ac&%j9MGF@agY?&7Qn#yR;)7$7^GTtXB&3=;P~r`{S&eZb z9LM?2JI>>2O|eFcM#jfgiyV;0htkc1>*l^W!e-nT77jsSVFe!|SglF7N0D$){m4%Q zl@}nP`VadI1wUP>C|H`|I!>{!RZ4IQWCKx5pgk-no#@w)U`!_hp^C_ zKx)*Z?zs6r0rL=x3U5iz6xg@qOoN|oAw+3mYG#2RUz^%c>KH_1HwI%k$iq!vqFA8o zG9WTnaRGmkY7WK(Mxxe|BS(&GN_Vt3Ak!zb|5ntKL|TSA2tp>AOp3RBwIRPZR@MmgkPqxBHjgUzDGJS9}06*4B#oSC*mUuxkYyMz0sp$&HeMwhqL?^(5MO??wm` zy93{chE|~9NXEMzdhYH0j{YP+Y|FAlBa3sWWq-8A+T&n3H?;qn+#8eLjYb&M72-&i z76c}ZOcci%mOJ;UK-)yO|J_->!yqxy$HynsbSulFxLzSBTT#TWTu zfJN0aG@=HCY!EoBO4R|GK6S`|{n&4B51k%)a{Es>$^j% zYf@Q3D~hn8lHl=G5sXw(qe$~iUS8jq9s3$@N^mO}{lOic% zF~dGV`%uhUHo}fmHjviukJj%+kh22%^<+_JPNd5g#&jrr)f($ywc z{7H~Vq+Xa7)PkY8kmuo71_^<-N)Z_*t zH$sXP7J?ZR)l@AmE-nlryw#tAV-(f-6LA2WvhYFCCoey$x37hp6yI{F?N+2fd7}k( zuR`=&3Vj@}RpH1$X`sS{Ca-h08O$~G%gOP80+mT=JoX4-l?!ozStX(Q3T7O)L5Tpm zM@p6XMNyXF@JQGcI%(=hgsKoYya|e3DqS;?p9ebCsu7g*O0pn<7;^YqR=05fymvXEF(CTF`USS^o!R@kZ zkR9wbSWo&mXxc?IU*7k7_;49=G2ROjfxjyBjd@PkLF&L8x=+vmuaSa|6co8;dKgH6 zq>kOywl{BH!uH3ht0xC>tT~zi?U8Y)edcNlvg^(PMCLdrbEimTA+}ja3D#lUW_qR% zf&oimsO0o*!ocz^kfGSkAgt7?_$7Lqc+iCz<}h^-c+jvJY&!tUl!$Q@OX~QdlZVNs zHE67dil`PK)NKhOn8)I<7R*5;Ycm0~eltBSEggeok|^T#;VDD` z`5cCz-6l}ml#=%2T3OB|kn1g)1Hh9_U~P(Xf`3?T7Gt2x^}8P7+*=l(l%&?{Ncc;{ zni?}nD8>!iY3T?^zXc%;zO(bMeXG_O{ob}RTaIYU#=2F!c)xYN3qd98aQWS-6z3^X z7(h2gf=;{$7yZHCX>e!A6PzI(m;^&y_6-3wF!T@A^(2b1wGLIea=@*F0a$H_v@|md z@758MBPk`2G^BPc*h4!$U?(FjEl-YVU`waQOJ;x+8^7)a0UlW?Ffj2;9V`3|Cv-R%%MULEuxiP3Y>iNpkW$;?c^Y%Sz~<>lob%-i{Uk;fh= z>1=wCh_j)<&CC%E3YeZMoaU8%1GRwH`}gmAso)~s5%+sLxoH6do|qJ<09$ik*d&1k z3}=Dv)tiVG$*ZA4%!Z=Z*h+7nASc;;=6?PcRWa0zI9QGu*qYzrR^k7s1-om`YclE? zRsN-e@S$Cu#GvnGRZ`X@#=AcGMu=hBZ8Sz?B*hP%BJ{%-Q53+fAt@OMVdXo&*ZYl^ zBCGdhWvSOL?7*QH0_e5K#+O|vb-@}AzezY;2{xBT5HJ8W%L2qWOVfK`2>`%<(XI~( z&=o{2P{M_RMuzqLUi0t*8v{0Zqp|I zgmGYl8tzLule=r6;<#cV=j-jAhtl(_h%GkKn$)!YC@tH%QG|(;IK%2D&ThOleWDpI zBmgoru^()x#;}g1RO`T>VO&RYFQB`-(S{N@ET>|g>tb}w+ZLDVTpy9dl&cSgckkT` zFF|6u=BIa@a(!`GXkIj_8ka{q%juJQWxaGWQ8&_uu?271^MTpQw0)Ak3V1LefBPEj zM>?V?!Blj;c;UZ3YEW1*)wc~`tI~%pX;=}sgp##*^F4F!K>+8$}7 z{dC(TK~x%<7WwnXk2mxI=EeJTopG2i!5CBYmlD!_b?7i7klFC^Mbago^xnJ-hPAb| zO5(lS{`;T!B9|Ye%f91i5wbg01!&^5PNVtmRrb9YkHzzl{-4Y<) z=jYHy0ax(<`0dJw>>E+`-+lypP?`m4$Bi>A*!Uaq<_=l(0^9b7GzoA#@ABS|pp%m;_7@dKc9LkA8 z-xxHOvr6A(EXavzaHuNYw2@*l8&}?V;_(E@%h0GjNOQ)Q9fmIO zRP7EMax>Crz#ESSlA^Lv1IO_sX4Sl-Z>9Jx0aJ1mATCib$$EXhAC`TOSGKpv|3DlG zH9}*OQ7*_XjAtOeWyK1gm`?2P@g!vFMjcKx^sm)e3=pWdX%1lj+3Gks`av)Y_fym~ z*ai{xBO@OjC$8n$pOhvR#yE2mlU*+lTwYm|{>O#{-*GiK_bANX^cytBK$tf_(zo-B z1Bi&hmK>Z2kgN{Muax#aFpF;0A8*2}VopHd5fjwz;6&O{PH6Wy;|n4l{+|A&V-T8E zV}wzjO-D~pAu|6$unt`&yZ#1qjHO^)hgj=%Yu4n7Se6Eezn@!(IPWMM|7^srBA>o2 z{nw@(vH8FDXYojJiv9)gLRV2Bc=VBk4^ZVocej4P%u)el7eIlGDuPVRxs&xX#l8Yx z`W4KejeCvk3tyy~hWi1BS%jc0zK=>h;4DM2;cT+_37Y~OfWp7iVA++2Yp2`^ai)6! z|Cc!no>5ljK-c=Iv&K!F7MSmkrtYySTA3D?p7Y(fIZkJ(`; z6$x7~)r4%wpk!{KSuppV>kr?Kvp{Y7>{keDDf&%Jb<2Aaz==DG3& zcWqfkDLRAurpD7jR}y2a$bN&CM4f=RQ<9)l1L`l>s>e! zmO;&gOGw|8hPE+d8rsX`cnm?)2f>~@8TjHwfz9_;-zVHIzi+|$y%-P1_h&WHgo2g? zXEYg8`2Hd-%JJeHVRm8g%aLgj@uXTz^XYJIOt)9^#VQS>NASuzj0r%D$v@E7x5vD0 z2M>?(1o3*;v>~lJJK+#5QRbFlg)?UIM62WD)`$vUx@fVMxuz+7o2=r~k78mz44T=yF^2<*nbk9kVoZE8XEYqJ?G_Q^ReI2v_|m-M ziYd!TIJDYr+ZIp;<45~SE2dUa^!xwp?pJ0?Hlpi_(f(i01P>h9e3*!reF`g*q~r#q zD6T2cZMd$F=)=zLpAble<~Z9*V{-g**UTcyJ}S{x-A-(>rU*W(9$AT&O?|Ii^Q>S7 z3-V_Idh5oFQhD)ztIzfbsLu6|^ITuQv!waBw0Tv-@%0>Re)cj*oK&k^po%+HxpoXF z;b~wSjeTTHFuExk>J)IZ@BeH+d9xHbbkd{}Dajfs z5m!d8$eh>e8;FyXhWUQsC^|lv5-!Rhkyxey8XTcc!Fr@XaLp>QDv+fri7dn{js+6? zxVYB4vz#yX8Qi8jPAC9@(zMWt1FGx%env?nFkZgQxQf^ zL-9mZGO{dYDGi{XPU=Cx6C0)jV0yvw<|>Ag>X|L_r8_0p@uC>SDh;vw)(ag{7@%6-U)8b%G&xtC(ZYu zoR=F*^Eb`H979^FKh}0A>H@!7Ppa2g9jHF%C`~|oj*}2kJo*S>($)aTL+mV+fY7-C z@4A-Y$tw%AQx>#sT(k2mvxC?s@}>c@pYOhW9Nj3##28NGHyG~6A?vKOqbdGtp zkn-e}aZ&h|;s&Hp{yB}m2H@=h0FkSxNfU7P!Abc&Rco6os8zh7CvdkM+q!iteAm)I z*)^%lAe|S)&4(X$VvNGAa2209!Lm7%$FXB|(H#g6&__MQ5h91deZhbNt~Tw&qt6rF z1w~yVe*@ZB1kU_`1wafj@jvd-j;%_Ie+bxcW7G3vh~-I%MRd&yN?;%czgoeOc%yFb@D zE}_P%GR7uT2ZA(Z1aztil##jlvyigP>6D1z(jC*hdTx>0^^Dis?o);Mx5WOqI{B&j z#897W3bIK?#RB*!nty08z0o`TNAl~^n(LlBxfR^7L({_q$U|Rk$UZqfI6Q1f&=Gt9 z#fI1DCOI|qDqldiOV0!m40!)06ENq8k`80E_WaFYm(Y>SG+`v9O&w&)RZO7hi@Byi zfzSgH{bJf`w19GZpLf!Le8bkFJ1LQ3N*w`-C0h9#;Md4+IlU)46})vhl8aOf+f&bI z4p@4KM~^~v`}`mlSP*;T@1+U)-RS~LMnqwP1}H_Q)b~WW`eRZ_D9E$;v@iFo6BxAT zZZoSWu7`=#&$DIA;AyHOOm!Bd;yzO1|orEuOibYB>YzV+)BQ`h$mc6VVpp{XdM{`g}Rgv``>X z2CTrH0|N;z9nBRZK2Z5ZEM}u@Cj>sPtfBPV-(jFLtD8gwU{d?FNsPx3TNJkB&4<0x zW^p#S*NC0M4l|K%ZENe(20H3XMlZ^+)eIJV0{xRn+)0v61YVV5)_UtS0|t`2K^s|F z_FvPA&wBAjMDYQv{JAv=J9y!+sgDGb;@>*CK)%?~?+C2%5)*>L8y#S~bcERg2_;LN zK_#{nX0e^GKW~UCpTF9e?4_ut3?Dt^m0d84d9A4Zt9pCu;_qQ!IxDT*lFY8~)Uyei zUm0*ZGBsKd?R7#sDC9L6`Ws+cCrNA`P1nL`-@fLo<}29e1Ce#E#XB=l9m&PMQEvca zzZN3(x$*50=plb$nv4}KXY!JXiC0EOMhtBL4beepJbCs@4nV?jeDB`9x!oQW8III~ z;$o51tS)dLo=~v+6a!cSe9zY(jq#@!$b^PzL^)iA;lqOo>A^FAWP(}HpOD?4JRQnY zvLP(=ogp0oZl#UIIDq|KkoEU{Q9UJarVSZRB;)s#BKN<9=ale&u)P9d(xkEp$^%_& z2Z;3C4h=32g9Wda-OJ7G$bf@=Q|;BJd6dN{v$n2kg``jFVi|&T8;r6 zaW4Ut&y`-$)>gZ_O-D!PTfWTn)IEZoq4dvtax*z4g)_NVdOD;n} zl5OaQbZ7ztG2W6e;$F0J=>EcRbCb*)zP*m%)@u<+kl26iffX>VcEtZ58b_j;KGMVE zrm;ekukAzdRdg&4xo4BeYf=yti~bbyO9Hp;`4^7%sOn=-<=m*60q1>*3H9taB0l(t zr<)j*2+^E;?XPY`hwRl&=QB?^3 z;G2g=Bp;+IafO@@v=QOEW_wgatZQfjz(F-_{1X*cP)1(jKL<(1WzjC5B2^Led zP#1lPMG08V&yp;-?RJf=Z&r0ZZNSZw71=^8Y$_z_!GS61JbC?cAy9do%%OjBL#{RY ziE|@)5Bq~4^e{xHYTAn!jBp!Y8#0kc70hveCdn6oAFOj28gYraU=M5B*fquY+((b`fVE zRF^I~8?<0g$Cj0X zK`}+fw5z64MaGAh7XGJ4%0AnAY)OJE!XwuB7tXFxTd8jQ@BWH%EH(#Pn+HX0pVvff zj_I9cqxgyArlGhR-ud(R2RpS7>(~9eLBhPcg=#BZck=K4+egs(FuEc6L+S&6m@7(9 zZA-zt80npDpS|7*-Fr8|y>wB}mZ0CLOph%wC|)F4o!+adBtFh;Sl^NQY1uhG!KWjY z&uMaAyw65_KvP=jeKgJJPtcyw6cQ&6#vo}w5wmq*8!k&<8f^uqNivOWsP1GQHsO)A zZPBNSVn>Zk(|SY7>7sAnWN-9J96d_HV~m;TWCTne+=mj&8zFlBl{IkvMQPf#JZ0hN zHmGPUM0D^&l5Z1!4W*_rX+id*>y9F0A}_^$uXg>n7Jv!T#UBj-zX>{l+Btz&%Bich zG23h6paazGi7IeH))dKh$W%j?#+IXY@;(C<@0QiXp{;uf5oO^pINKiu(90|?=Mv6`LJ z?{A)^D_4eMk-n%b#nrF^%+l4oZ+(A%zcOBzj;01=;nU5VH$QqzgA}z10YHFm5ZJy( zO(6_|4_OF7b7wOE9hHF~x&QTdIx6?LoWqVtcEf8sgyOG`>meLQLd9 z`pDxL<8=f%NpP8Q2pQ4w;w5uyzvbnf>gg}w>l@f$1b%8qH};$0VQFcwZ6QFZG{*4- zl5yvGWDC4VpbTGU^pGScETktA#NcSoBJK@ELMYB*#dy>X?&Km1prqTxmTb+rc1YbF zM-I%4WvN{5hGu4R1mnVtz(@D*Lw)lNjRa%@$NU-8+acgR6d`i-h)_k)4f+yK2!4sb z1M_PYE+qtdUXy;Ad8EfGsbW6J=!|7*YC($HZ9=Z__?Q7l{WF6xou1(Og8a}RO3dYhZAIS-?Tmbp*3>&6AIS4i zLD^tyhT-Qls8x~V%!jCsR}wi6#uc0d!u$>yM~2}R{nC1e2hnNGg^Ll%(8i;?Z}ioR zkbz=`jLk{*`5U0C){51^7f0-yd1WC#@L+xC;ePk7B65q$BhbOxAjc+lA%%loK}?9kx8&~fjc@GYx1kZ4lUqqTjPe1& zc=4my_N+I59`RCY%%W8{K@yDz6MriP8mYoz2uIse6%)MDHr(O>z?j0h&06qGjbHNuCH;uQd0e3COoca}9*xJlqO7@)0;7VQGJNo*EkU(*$PNC2* z`ts#o+D8~~K=D4@3!k@1RNBQX5@i(wrmSliUz7L9~Vg$1UcXwa53M6zPAQRI*9VHe`YZd6rB?WJ@awCkdTlqZe1TQuQy|>yS{z>st*U4F|>~5PLC2?{tsL49gp??|Bqiy zO=+u$R5BA~B~ejP6tc=Fd(SdMr%opc36YSJjBKJyR!cU?yzI{zBFu zZXMQMkMQ$^K@}e|Cf*lkPM>DcfEN1G%TL5+(QT6K^h^nb3T^o{8s_m7+f8nhc8-oj zq_`y;m#NyJ@W2+?H1Nq@T6p2mSpa-_ps&jHP*hw6z1#OE5VES`pPi2afga{If+{rz zpz_cRPO`BlqdM)6HRsX`V7B8-Sm2NYUnRWvO)@?YG%YOn;F|V#ZhjzM`=a{}J)76B ze+HkejE$wm%9Tfqe82leW?eBE=RHg|EdUL9U`-D2?YMDSaLt=DZseQ*_2(*BQE*XQ z4Pd0oqR>{S#{ou8uzMo6Y-~5S*HY7{9Yy8TdqIy2HYUvHT2;Yc<{Oqkt&I9PU5#j` z_TKrH;Cb6nVVGy3^+3bEU=X&G@^PX0SZy${C?$uTbL&1w$uux(pAnqVYi^W-4DbzY zUqukIL*hHg#t04nt0Cp|gQ1L1I#Yi-ls|M~z4Pv!PsjfHXTfb^6LW+6*Rb-xN-=tw zW2z(GQpvf|iWuX}P&bG$BRN-fu);W3IMj1f2-*mkT>X*RA7}h^tAS~|3lr_|mHe$w zB-tJzdLs;4aocqLdzxq{x661QA)f?OJ^3WU|M!y+7LFE+jwB?xJ0DT0)XyNJnt`9S z#oeHDFQy8M&z=Rw5$NN<8I@e*{R^izp6KGf9-rZO-A2lvgXsmtK_OhBpI0 z0KYR2oBj8!SbUAq{LuI0ZX&3$5HEh#>YA&vVQM|)ZPwR{MK?@at*aJ&=8ljIaI_eF zy{Y0_v3Lw<>+*FwlbqDp$|7Iy*!zrQ5k+SQGc)Cg8a#&;%F*3iN^i#G zO)^-AdO;gGjg@7?H2&v8+T~+I(3damtqgB;D}-7l(31(VLSttq5U2GaveJTxYaC25 zy(B<8(l8CA_yTwtL)ZUWye!_VCc3r!-d$hcm?N$uc0&4~)195bskS#k56!{Bwonmf zq?-_4lWKnJ$1o}Go1EwI`z9cmEvB}2==H^8EM{N|=D6KFzIUAfu?Yzb@k-ZUcI+uu zeU7HHv$MQMj_9aLpF)ow`06^^0`|HM{roD?f5$|1!j(s(W>NvJ8=U5(a2UN2GM@IF z^q_$eKuSv_{0RRPJj=4QhDb1)fcRLAz~rK9AQ#e$CL@j`E^pgiy4Thuajvk! z&@VO#X=EBc_`N>h2s9#q_`SxMSVZg4cf#b3*mMSQz=K<}0PnsSQ7@zSkV+vb5}Wm% z1%+AH=*-4^6ht%zG3aEdJH5nuYRk55-(MYd>QhQ>rIX|4EUYP0CTM6XGBJ7b=*_n|ck~WSW3Ai7 zO_EJXzc`}g;KVqJMNfZ;{l zoWF-VzW~ADALx(<8z#obtHxV`moPC0lp1A(quJwxU)`?q8FZ6(y$AcS{fgI0HxQ$N zeR$ZR$Gh!Fjh89=@5xD84?L1jKsxiPWmrxQJfn&X2AaG$oQ$+e`qjgw9Z!A`pU`hq z5{tZHuVRxC_Ickh2uG9JpjvQ!(rSbx{eimT)0at?a=vnabx&mPu2X>4NjgUchbgEk zByUVk4v)iAya%P875%8nr_e#-7lM%e3(mN`k+(-h;DC#@ejIR|{x`M7YnR`O?&#tM zpp6dmZpj?o7>_mj(GT2Sq<4a2hrhm1{YTd4xKTBYiMZuw4)0dxcWF00ar`*Can+yA zSO*c-cT4iQUme@bwevOL))9m)>f>&EXKZ3&L!A+hYZr1|jElkpk_TE=K~}$$Bje*v zF6_t@7706>v2(Ym=tH=^$%2$#{c8g68W9nfbacoR-?vWJibu62hVmo=a{B~YLe0N!;oas9OXmP70=vu!K4QAZCcKH&e$iwx0Zz(li zQVBTTx$^a*x{F~!lQVXSzLmf`K&cu9=KVt9rA(TdVpq-E+T%c;*gIAKp{$z1@kdg1 zHtE`c!k|6p0eG3vy>qoOrahLhH}G!`4Hrbg5fpulfyhc{vdE_g%U5Djf z0$vL3xt96437HzPY?zf2_u-J^OL+{`Q-hz?zCm`yB1^znl*kR^4 zD&T66+mE;pWt3EW0PF?6q1Cv6E|^VPti~(V5ZvkDYm^W5)MkYctm2-c74zO7+UCAC z-n1$0N_2Mu>N_cpMV9)AfGL=tbFb+I>_ZlcVqSnGqzHO&=)OJE(<=_#0+bu`&d8V1 zcx9%NQtC;5$sk;5$<-@Xuv8NNhI2I077rmR`^ZQcwoxgZOOs z;ZUW)9l>e@gtNY86Q51I@4LFYjgu4gQu|--?H|YSARJV>Coz&xEkOmOHLO^(hPcI* z|Lpb}Dc$GPcm;PWqq&-OKF0B44niPl9?`*gX)>`%vd@BLVU>mWR=u}U-|Yc8(a=?H zN`;`}oq8eahZqfweL55qDcA8GH`_{4B$!aAc>XqB-nG>hWhcV~uq8jQ(2B)m;`Xtm zAI7`Fmotn}%eqqN;;YjR9hhXlJSIWqG0itQjVxq_?_~AA1~y$Z1;ky&p~C}%c*6`@ zhCQj%_cY5`F@z@-1eMij@{{yu06HP{Cy}TL&;3LkNZHr$%6tGm9Nt~bA#5O*eILO{ z8F|}%E?`IqIFhY{7?k=|J!x73fz#JO@~{x!(d4DMG;qo-wEp2=4rSHV=Tv90{W2*# z!|sf$pqa#=bRKyGCe^O9UFLDfT$59mv@hxArC*ap#czlS$^B8$iFf6O0a>mQu-4HCK ze^mRvAex-PrUxllCX?kePE89;wg}`^gMS|vgIKa-Z^<{Jl_JYv3`uI5qr)JGU>Bh7=**#)##^eDqE}Shd|~UAfTQ$uVr1 z?fYaKW@cv-u=HYfzn%p~$|KNVl)xM&hug(G7h!FIEm`5chb(NJt8)~w^5S%U{|-Rl zT9xVW6X?`Lkwt|W2VX3zC9tJA-(4Ijliu)ZJOk*L9J1zNcy3?9)~Fuwy(biT*nbjd!EZ*|794q&1a5l}19FxX}+=|a>A?RWL7C>Nr8Z7&~_{`Wn9r#9`Xa#JsrM2x6_V9e_^Hv=h_ z9HNTLLWRy@_Z^21&SL0`jh3>!&!%U1^&jAtp~(zIAZ^Bx1G2w5dj7^{riV^H1F{&w zkr49q48OI3Zw=^3vX~B3dKB0B2kv;Hk53^?9)bV}A{>S2!^7vG*UM@bI{%bH92TXZ z_AJu5w$@&fED169xliJSR7EqIG?9plikYjg3W&QJ%2M(Kuv@|JS4XfVFnKc%V9L() zt~W`&Hg|PL9&kKx7L-!qLz$V36V_;f@ zLS{g{R&=@jE4Hl2kgcim2JpUra5-Yy`uL7 zVZied^39w!%1`yr1dL!7?|A)V%ibSUOUYt1uj++ZdJ7PmZg7TMVrv3 zDM}gJe0&b2rbQxr?v{$www}AxJ*{ni+ z8yOi<%_XEk=G#%5aYS6Q>q+>E)C4s2jI?6SW_TZb`>;;t)lOD#AD?I}rfSik=ys8I zib)5o^s{j2)rgH6iC@(59A7T=mYflGtNmNwkr)DCby9;r9}<9I`+>_8vNn>FBl+(a z(+!pZj#lgqF=hZDizPlhUxu?D_TlKqhmqLesR14o%B>2FgXKb}aiikF#a1?ZFs+3^ zBw_}1HHWyhOinZK`&;+>|<|we*a|=sTfKE=M_z}_AOZjB0Sdy4*T*cS9zHxE; zfR2COHHI#P_e}*FD$<^14E*U#L&jKXXuS>rQowK+a$=`GFGi7Apj$QQ@JftCRKWWt zXO81{{$(t)&X@a%SrQCF)d%QfZt}&-m@|kW#MK<&FF}Qcg_Rwk%Hr`7+)!yc;Wi1+ ziO;x<3=<3uW&mxYMPqP0UC4E^uIVMVttgw>lhZ(*;V9g(wGy@s>R^!6BRS zwCg$(W&d8RQNJuzM>l98F4-t?^&5+GA)$icRlk&Jk{Jdcz#u7(jT=9}mp$1vU$6Sj z)$i{kqYjyGI2d-;;%ZP=g~`Ei1RhSj5yu0n)=`RR+D~x#rP3j}(bka8*Bkzgwqv0VzOj6xG|bt*yn)1)S8WbgCve1JpKzrT#xtX_HtZ6pnb@e2B%1VW zQzIigrHJVnF?>Q3vG8PKFtlJcFoQ>Bv!&FHhR#mP+k;0k>kDW4n94fC@+XTfp>8JA z&_5|w;Sp+itdAxoMqs_MYta%x#j|IF^M)Y5O*R(*R^Vout+K`POdX~}G(}Yf23;%+B3XQlL{;H~eDrhp+l@|rJl#->;rBUoJf+O(Y zlZEr8(23U#&DtFF){M)L_&8g{*q6YZrN5!wXKkzc03^Bj8E)0 zq~1j=p;RBZTbTCX%@Lz>HXYqLj_Vwv#81f#lj9hh)jJI(31n*o!o9rQysqsm-ZYII zc}Y$9KyN>2vIcxB$>i8TN9K}kcW!dRKuAn5tG-@x+N0rN=fTAk88)IKv$;6;xyM(b zcMeH`WhEtcF6_KJk6u3w6NA;lpGp9slkX0(r-e9wF$!-yMq8qlimSi+(0+J;sf0~e zpE16K(&L08_rtf2ovA`^?a=A+?)Gg`TQJqeLggWq$1HTO=s1|((RfUj#H$Jxz=33>1-CpJ1-yr<e?mrN>)oaF{w3b^H zKVIlHyG81qhL&~Bf7>s43zY%o$vbmXO4q9+Ly=>P>>;C4PWaG`H61BvTvNk78#}I# z`t=k`!1S9e9!S$dWTo(Tzk{`uG8S~@D&bfkpFt6e#t|C{_Ja}`yHVfpY~9}@1DB8T zh>^TEWz@zg@!^ZMGG-e;t^MznT>eR$g9QMBji+ZzU;=Rm#*)!z#$hVTgd7{UMw5 zKWMw42QrQ^fcfcEx**zh9S$g z!hVNo#iMt?^5|*(HJ1`#)g(~L>?md$S|3Ux-(#fo0P_{1m-L%V~2aik8OQ%ffJ zO%7@MUuvItjE0!E-H9T&p7leH7&x`lsCQ*S`|k5);fkIEw=)i28i!xB1L*q(pocqO z@0{T$-)G=aO1?;W43t+M=bB@Q;f{qaO}%j5=HFZZhY~|9fvKwy|BM6rSY<~m8UIMt z1#I_^+5onl;Q-qKWUr7kE z&J-S5qF$g^!C6muh{PHiC8uuJJl3DQapJ0Kb$kkDGnq+yc#J zD}w~29VB$eeF?)@`~>pOV@GLcdJpiJ|4!+bO{A^5i(d3z?i|#AB>>kgD&f#4`=$OY zAxmksEPAz^RL{~VnZg+HDgY2g7EyS^NAA?)Zt-grqK*YxtiJhF%liB|P6{%jI#~zn)&3Cmx&D4hZvs8(Hl?j&}E9X)@5EgEVf5L-z-D=WaZhn?QOK*W_TMUZ2c3A(Y#%$Q07^dCJW! zf0jZ?S=cPz*ipq6a4xP^1)!LcJ9yXM(AW{l1}cn3tk*%-HDLwYIMAFD9<`f3%TgpD zJ_R8fb1GL*sZo9dwaDNZb`G_m$o9R>Qmw{oODt8HlfVAoABH*d$SuUEe#C-t64Ler zurnK`aYO?SJ%bHHEVgP*Y^cptW81djyq$hqrHQl)cg4n4k~}nD7IrpKq(%JZ}&?AX{mJ*4NB=n{e%|kbDNu-X#n}tiE|WWeG6zR36U*X>zPPdaBzspH0e106^aRzG09?qX8q_?E}r+nNKyw zyRri~)Jebz8!M4B4DV@qq4MqQ?8FwUe5Au=Y6#HLGt}Cicn?a>B0Ot=XAZEg3Ep>Z zXIA*Lmt68b52(zvb3DS&-bAp}A}|9|I5>p$bWktRT>O3Z?aCh?i|rFi0g| zuv_{LB`Urmgt#!{wTsYL_b==wYzbu*c5+4{VM#$pjVJUuI5_Uqd3i?Kx{m=G(;eAy z0GRUfTkmWNg+FCTvp1U^3MBi`eO!0O^P5J8V9N32NtymJRM;T&x7Mwt51%~QKLxKD z*U}-W2+1Gwz>ZGA?B;V%!Uzgu3_$^DR!$d{UR1MT2@%sscbsuE6$vXbJJct!P7>%= zi9vc3!#Ps9Kdo{5lg2Z6wva$$ciKa8&GIGa8|vHR7TvfNxRI4Y%>;j&MD*6&wOM-X zG9Dh4Jc1L10f8}_C7nB9JYGG0f4p~Mn150VTHws6G>6A&5URq>mHjx@fW`5)&*5f@ z9AlBA!!Pd+Xu&)er?DU%M4Shf<6zkFUA(js<6GxIE=G+ssBE;e)-1mjvognFIvER$ zL9{@tq=Tx`(J&y~rvF!gssr3)X%zsV-ey&%Xr;gB_Ja8z+(GuG%-~$vY$<-g2~=I; z#L+wfpvV}@ne%yb=sT!-LKu0=7FsN!V$kZeF?Gnd=z-U8)@{vGE=+mnPouHOkujT^ zoJ=Q9Um8+)-JlL}XvA`!H`i;vz+kKwq(*V)7UBqplQNlxMjb~(xMM#cD59)Hfk*nX zxI!i;R?WKU&A!47P}2-Gqj#_ZChXG?YKZ1QfQQFBcNU_s2kO=8DH@%8;>TFDK%Jq1 zySB;gBs(21wQBEM%7Y9|{@-9>?X7aCI(`FcCTfrYm|tp1jG;l0r;_j&?;hY z-KR%_5Y>{z*4JRUTalksYUD65{HkaWqadmhHI$gYC%HXx`0*+)j;j6G`Un$K;48A06UjpNH`iI!Ug)L&Yn8;?ebC8(R#%*#S2tlS zOfr39qP{@MC7a&tpum2I1k2($mrRqV1hA8ty;5c5)|*`Wes&|@9hU%dV3CJ2@C&{L zrfMYyHw~YIkJ!_GIVSNUr_8DQfA%`9-crMyhQ(zCNG?4O*pvsh83J4GHCOK9ibfwm z9O3G0{wXK4orRTGaFo~%3KcC%w3EmAJ5n;kP3alcXpX^SlLz7L1(pQ0I4RT%A0Jay z4SYEk<@k{CNxd2PZqCLkJb8DUrT8ownXXYsNB!CPkAi?0gD-uEmE#HE2XS~G>zlEt z5UsZ;EK$$i@!y3PrSoK~E7LY9jW6ggZUHzyiB)VJB3nrZfx_g6_i3=$#8(9@R?u}G z0*j7hIN)i#0MZ3*tjFQMp93)Qf4-aK1jI2lIARi9es|gI$e-mJ9K0y&2aBJLtmTrJOz|jNI`L2`hYHk4e-e5=x#zLk@XeE{A84_l{A4; zjMW2?RasSS0>hsfnhtLg+KbcvIj|(@+Cp)&&u`7?kJz2tG3mYa07`k|_!F-ceJ^_a zeHvt_iVUe2qsWP%*21=CUkW!SDrLL?xbDHTTBNnWNUDl4o={w0K|(;MtssP^r?QI( z33u?Yl>!9%`Op5gn+QK!jBIRp$&1QtjQ+wA?%1=w&_q_?>+F(2N#MW4T~(Ir;IL_mJ!r6$3it0 zBVleiLM89EyU_*j)P?Tezu%usXK!?zJYY<~S7UnsBq(z{ypk4CtWS#J=DSSPs_FdC zW^|G-(2)A~?VH;s<} zD%N*3Q`i`v&%+6f8gvGevlAUDQ~{`=y#Z5sX}6dpZ!bCXbkmawBESR|tLi@rm*dir zjHhHv4NXg~D_1mjf~J#>Te5J>`;m_~k%M);D)8Al8@?M(yfS`^C_Nv6`VcMCHzR4Z zcgC3cvP$Q1&A>K3bx0rLb!>8vhJ&luox@!ZmqcE)*!~CK{M`bN2rBn)%swXQN-yNi zk#H$dg$sCNY53(fCnMOd;v$TP)x9wP_%xXK5_>)Z2-GwqmB5JDY~~egLc?@rW5d^w zTwAw%z54XkIUk5~VY?|pDsicctwylN>e-%()r|p8?Tk_s;Yj{@j98M-rS?n`ERtI{ z1$%U`_SAB7D35R7T0+_1iPKr&(4pYzTNW_dfc0mxXd(1lgcB3FZtYs*g&`R0Sa?Zq zbuPe|U~yF~1Z{p1x>{<>PH3Wty}uUGCmkdm`xLqh%_LZBt3$V!o2?vYh-}dZ23aV1 z6{|M!z)u-`l0jr0`qYQ6(&T?D7$?3rRf95Qj=i%0;Jj8tVlM@jlJ+QutG>f&KV~4V z>OG5BI#tM=I9^uKbc2(zMe(C^{u;dmY*QOZL38Eu&wEhXI~QY}{|z^@wH$V>wfGiE z6W}1qVo}vPiB=H;!GFf)@M@tobm&LRQ=Xsn9HWWi>C>HhbHLuOqNOSt*tcg-z`M)% zH`vMf)N^x@f-;eT*#!cyBrOJ5i3*KR3gP_)+Ou5xl9#M4l(O{+DdrNNWdO}5T^n|oMV9R5v-pYiYetyO!Xnkk9qQ@z4eRFzm;U- zG1z%bIU&CdO}E4n(y~+6XE_JdC*5a1Qo@_{dI$c!DcOYht>s>?}#V7J?1n6tZL(Pysz`Cb(9=y7I| z|Ic6j%rp2+RykhU#;%WI_Mo|C?G339<4m1Lu!iYe497MdCH#&Br zx1{8>Lh2QvLUBlNZXxRT0%+6<(R2VsRWN=?aPi;;9NEZPy!Lgd z?ebg47T#&l&ZzDDrPn44?=*5d?(q|UP1CD)_5k=cz&RXEx?3(O z0P@Y1%RUSICCtXmWVaa)VI0awbco2&B8NfT<%MTcM`GA#@=Rz2ocecy^=9A>h&Z*(@iAjt4e$HVf6{ z%v_(M`N`+&JGhVee;af2Wk0{P+Fc%;lX#fcNmgm13jWzQ6OaU*zT7B4^*!ixYI-BA z(RHJ@8Qi~d!-g(ZQ|Ui|$e$rK%u{*ETfhMU@Um~N#G`G;^DnfTWvP1q5sLMD5^CrC zPG-rr8#}0YBVn%=&T2@Y=K0x<`MJg>cC^3;?%{q|f@XONo_} zyG)V>Y>x8r`49tNV^4U($jQQ#P9&oKm*Njal!}j^{=p zwP5OHvr<+%j?KevzvA1*-CbNh{j#8!|AX9&py#bf5vVI&T7>~YWR(NAii`p&5GYT3S~4~P-c^+_QV8itNxfTH?QRVI|H=6Oz;Qo zdT|vkgY+|uRyOuzwYRrh0Wubw!~-c3sl4woVM|Tpowgbwud-$fSj?nCKm2Y-Sqs+M z4O5gb&hJYMwY0Qik5sSuDAbM{V~j`6UBkf>ze~dm3dY{vWydZPu67?@ru~wsdlKmF z*u~1z%YP#DL(wAli^slG1l=x}N77UBBwC--Rd7Qpc}&u5YNu^5;Oc0Oy6t8cyq?ptpocHk2@S$m|N(HK<*hfZyK<~2XpU^>l`OqT;k4qh-%C!4ShMu7zA+gW$9JTd&OJY7x(Icg5M@-iU=AT<+#!l)J<#m4{ zuR6bw=Ck9sHizzn@|6s*I(|$hu*LM^D z&{eBftL1L%?7~AA4}`@+{KE?>oMI^yf2j8;)u(4qf^B%dzUr2H+1l>?Ac^s9xT(Oc`k~1OI_A^2R{b1a&f>*I(SA%S1ut-(E#8O4X?*wyq}3qYC3`Z*5La+ zJ#sFKRN&?Zm#Ww}xqvB0L+x;$oOWn$35J~&zLbxAGHi;@=Yo@Zvc3eqQH9C`WpR*kYypP~DMpd%W%&;a9wQaP_if%+Jx$ z=Mewd3vuk+sf>Z-Rl5*MhrGPJeLwMD0)sKV-OH8D$CaM^ni~30k!9&&$VUhf2-}%+ zc#xSBm!-UeFpvCSxR1u5IXi64)CHg;l#3Z+pL90UjYhs*JZ=7Nzbw z@z3dtbG;M20Ltu4k!;6XtY3_M z69J%%7dfymr)U6NF}TTjfU9gAOu%Vq;jJ>DIvpg6#4_BrwgtU{Mxm!it~Qqe3N_$j zL$QU77B4Tan(M?P7L~wy1ov~Jwbc4_boCjivi!AQt7BfgNC#2uUIU1DAd{%$Ai@_j zHIBC9=Z`Nu58^QqRv2 zK}{3p92%CpO>luJ!iX#1awlBOh9tozziv0cIYaPI>93#D}1%kBkXz_sh7Y^QWD#{_ckKNPaVQSn%D#@&0$-egu5I) ziT5LeXfk@B1FS%Uv-`2_mzb5guA{L^#1KqpxEAh9R{$5N$9`CJ==9|^GMr0X{Dn_) z2bE6EV|_mp>J1Lyk1}MpLbznf3ZXT+@$DsKe^yp>J{Gyz!6SNkyZX#lT6x+;z;GV-4K3Y zTy(<19$V*{@vnu=zlGK(h=u6&FsC}>ySvvX|9*1{6>>&it+up`+b95=Qeka3TuUf{1$x0)FOt+07i@cu1Gd`Wkq?Op7nG`X z+?X*{h+K({93j>&z*!1WPOhbUk+ZRneG zMoF?eSv(=5=`sl5Jyjf%4j+G>TVW^ZHFsoU6jYKR^Hw|u*_Yof9wJVi*Z?- z%*6@ZETb}bG|FWa91O37d=<%eZ6H*g^}uF93)JzPQMBS2u2JK#>8&a}vM8ypz#Q-3x(B239DOJmZSE^XsdKB+S;0OtPN@C<`n!EfY3cpLE`W|Bs31#ukJ`v-sU;2f4uD-y8 zK}k7YX+K!Os9!&p)!->=*?sW+yqbF}#cbumH2WZF|G5`0j!=3cnp-&ZWGH{Mn3!^N zI=tf}nQla=xlezfGf{3>{@HG2_&C)FtQdFMM0swXEWlnSYJdvz6=x?-u>*zx?+HW)Nxs~M~#615mO z$JJ0#sG+vCv1>{8UHTNj<=|H{ps|UxL4%bXvykotMnC@QLO#15DY4)ttHPOvI*M{f z1PAn4B9!2~C6=Yg+OZAF(h?X%m)%z;16xCG@{VK8G6;JUAi)73fQr8aA zQFnB@(Kab*FKm`mU?BTgDMa`r>ipNT@Uz^foNpTegy?e14?g_Y&ULV;V->zhAN#U- znvk;Su0Zc{x?ucA%rH}?wDTLG=W#>&iQM#2w4N0vnO%&24>F%38l@Ht%&*(UfsJY8 zF&uE#V$-qF8jx5U`^eF?onm$2LvZm53JRg0wFlC&KYN!N|G2g z6}^?>c4suNCBX$yLWF<*?e9QrFv-x|I!3;l zmpC<@9+(CzgulTl2e5pZ=-s~27NGLls74EbCXl+4WiBR(UXxCMF)mftVv$!?=QswzSJ@)fl38`Dr3S^kL zruvR_G2jGp&1tJ~BBqEy{mfv9J@zz$kWIy!H_(AoEYW^nXq~;d%a6;JPH>kC97Qq9 zHL$*a_wEDHAu?|o@7}$8vt_OhdXvZ=`=Ee;r%suR4y}~orb+ zGn4&O1SedV*e&0yFSPX7TL~vMi^BGtQTO{HuO+jJfhWFO(1WdCdW^wMDTy9iH)Mef z@0LOkt|%01?@znp&hdX0`to0ZB>bm6o)+)9V$>i4@6wcSE z7ZmZ^wsx;pR_`#2Y;b0QM6Jr4Fo$v$230ff2InNotAbnJ2bmm{=?o@H34>G!*%Pk{ z43|B<2E|hUe=Q6gR_1VM_4d>!C0|o*Y>S*;75sc$?4JGLlRD4#tRpsAtxh?wTAe7B zS13;R(_1%hHsSQz z#K?t9j6)+~fW{UCow4X3rq1cjoduA_2$;754>vCBfNQeqQ9(gLHA0AMrD6Y_i9^lQ z>Ao(aDFPd$(FoK`VNbHpnE~;G(nK4^ip|Lj9FoTUV0IBNa#2f>uqJHS%Oar;U5A4a zrfc9?ySlo9|AVNF*crkupG6;yBxiK z_sOQ@T`LwdV0;J&*?Nv#cw&rLL(F0r`=9>+Q^5J!U4me(?6%cC0-(^m#1}A z@>ITF*%fHRJ!hw)Q=Q4m4uk=IJqYzCiE~G8dD9MOi1lM|tC}kBV1Ev3xI^nncbE3K zeUJeO3k!>Rp)cGs#%R$zG>_^GHri?b=Kj-w1o=oE(~ZUTBT3*A3G$Sjb^kMPEP$Bg zaPRCpQV+=9=#!(!I_~~bk5_Yf<>rO0*BaeAN}oA(Bt(Xupm(1vXK1>&UT*DWn_}j4 z2E~rDzY9x_I>fkRFYIKCu7k)eG2N{~w)jfeAT@ck!#j*bdRvIse}Y9y0@0y$XJfV_ z+_Z4w04Ud}3j!Ui$Z=kt5}QP??_&ZhipodAAGWo9y#S3$=XP;Ch)*E|4WEIu>fOU? zi~TGpLnKwY43)8zdmesv1fb9)cC9`W#9g?NN=N+LH=R9IA&@(Q#J15o7m}1SRgG!H z2Osv|RC`c^tVXcJ5!9Rm#p!h^qE0`fg{^#uD8Z;Mx+m&aiv8A&8&4oAMJ2C*4TE|e zNICd-h{|%AMF}Vi7f&^t#r>)UF1~GmT1UGfKo@n@K!#UgyIWU=UZbVFquLHa1|+1(=(|2JqhMs&)|WAWgUD z0CrEN0D`*oCeS4qmw|UR0ggK|J;O#IT6h?YN|YjMi8cn~9W@g#r{Vm}=zRl^*Wm6D z4g1g(c+w`^K?>mfc z;HS$@%F7#*SPhKqLhQ8&2(15+`k#4hvXRS{5d$;KNmy{UWT&f+C!(FP1tr(?5v4!R^|8d zB5CtkqI@|vZP$0h4GXV7(*VWqy*SU10=+tS;YZ}(x^s}J?$$x*t``hsh@4zX!vQ6R zGpbq21sq*z0DQ!fW}$S&=Ns+~CE}s~`&HBx2^?BK*D4M@9qZSnGaC7_3jb1<5(*6| zPUg>&=gYBf{NCeXrJjja(T?7)oS3z!m3avzG!05l(*1as3{?U~BC*hnzMD5m3gA@U z#`XM{vXiij_(_P`*iY4D6B~qC2p_~q8mvRIJ7B#9X=(uh`zOI|ka#W?@e+ND4qY$i z^m=T!OoNaT-&KZaC9w1&c*7ygBTg|7QxOBF#6Y{U;9<~0>UC{902v550WH6j6=4M9E715VaSN|m(@qAe) zA6c0|u$!Ihi=azncf3;&Tx@z;Q85}GXx{rLP{33Xsj>0mo=VW=VUk=rBm&C!FKowA zx}vU++%@wfbSL0*)^kWVP(&NGsS@F)-uT`3zKLk?WfeaD>jE8y&niH_tmo!1kHDZQ z&&&@^qZ&34)^j8>7=rh7Gfz;LkQrepi^tIl zW`$qtp?1?u;6Zc(=Zh2AjQCaxD0CZit5mveu*1T3gt1=@BAtQu{M-`*OQ=i8@^|5n zog$a2NzO%AY{q1}vLSXIG7zp@Yy-2E!pT|BO~X@gmj zEO3`9G5(Oyd#0@*9Ep@iU3hesn|R-t6<}YniH$Ad`FM`VlY-SiukaDV3&Sf-YNF&= z)&r?l!HU{y?g^?Awn;3N;#N%u%A<@*uA$l}Dk)_xJUf_`rJ#EKo{QgD&B(~ezu6SI z8LOb+y0^a((>quk8hHg$Sf@ONG^6kL*a)_V(K5&2ef|u~pi&D{CznswpezvMC+388 zPgf3{y#~<^Ce=Hz{lBLy1{bSou#W3&QvC36+9@3(v~{P6AzgV(T%8-3zI_tOlwmc3 zfuZa1qbh97f$N{G$v*h036Dt*cbG*((zXQw(O9qd{rjfCaMqI=%d`OMdSa~ylI7`z zd@hnU6Fx(79-mC0XtI};DXD6!r<9w`)8=3t3UjzKi zgwjDbJ=+Uh8391^tz*y#MQd5-?1YJx^r-lHaKE0OWzq!mvrO9Z@Oq@Gr=68r4Xx+e zg*?o{BhwPY%nhTLupAZXB@SP_GDamVmSQj_f=4RI>&O!atvkNSQQWcbY#-uybV=}b z*a!yEkXJ)M{lROsm`0Zjwz15_8%)PfAj+^T@S2|soJs-I8a4ngf^({KSk|apwLx$B z{@Ufv$z(ifVJQu1fIdlNc_i7(5FcR!28lh1DWKCb;|#Le*oW(tyuEu%gYH1~Ui298 z+Kc%CPC6H0HD`r`&nL?R=xzme|GA#{ESnS8J{83oA-fApj()v{%Lj-dCwtR&b7J^> zc*&1@F3R77yRheIEq{DA_N&-UDKBX z;tW*KaF_>?@Y^{_z2JZVSzPJ#c5seJ!)(`oF7oih?*+lu{@)6tWb%lERp1D~jr6%f zn$?!sZ58*3`!Tw{zyX@$?9?^4sb9PkBSP7c-rum?4;)}8YNL@9WFP$ntbiK2Fw)e< z>+if{fG7l!w$SEK)hK@Vg{g{-8-|CFQjHO&ww#y$k7&eO1ktQQ>Q1`rwf|Fe+QaY0 zpu)C0LWM#kpa+I5Rgr~oq=Z4TzUuT~4&upU?0I?*u9USQJ4(JQ)blIM0$T0EFMaZ` z(O&1gXT{B)ihI@0$|EVq=`E?vW5>e(E0YPzHH_(HPu$uYGG=#5lBVMFbFyK?|DT4} z`dLT-Ur;%NZvSeo@;RG>GfTQ*_jb~fxaQO$-h5#wzM=SPX3@shP-u07PYf}0Ia%o} zsbV`XBoz8TKj?q|((c!ToNvIMf2yaqKZ|}#>`E);2bq;Aov~xKJ9|q6rM!ojO_}3E zL(ed#{yi*H#G%*aVd`TmVgL8fpZ6MUb9UKOKgIOJSyf@3!s#0UpWTI?Ij>OleZ{%> z<{@59pB16poObey*1zE4k*6M7GuEDL7P(nPiPL%BP_C^Ia%+>`_m3Vp*|G(O7e2&|9 z?l|`6=jBy=Qci?hiwe#~Y6~XSCaX&fVI2?v)fo)Z(?GoA@S3>0NlMNR_kN*|o-d`3 zDl@cRCY$=bKPC!|YvTxnGrS7Ne;zFf0nS(SZiPUx(O-T{aYFz}E1j~4N z)@I{mCu%7vf_NciOS4|aQcvcehw-jTivzk3P*}Q9VM(B|ulFWfK*#mDxgt@XQ@olT z1lvLl-}lN1bD1SFNHs~MN7)Dpxgjp!`HD9=IqAR@S2Lsxef<#1lQ;}dSYwd&HtFdT zL3TPiM4s`s($c#m);$C!GRv?JP^-9e`*u1}&n+xg0{0*{vi@ZeFf6`u)Q50>;<;6h z*Neyl_=#macD*6J_hH?Rm2&mNC>Ub+O`LDwKKGXJR(j zo@qlphSNLE;wT7fsPpDOosSr5f=F{OYSU>2g=e_xMb}Z`1wG4%_;o4xur) ziUTox^x{unT`&;@JQcYB>>&Oy=}{^Wz?aV9em6}AVP%FGohWZ&eS|U`|LDHA_fs&< zY1I&8f5&3NXA<`;aq7ZW0*`*dpq!kI_~d6$zG%&`S2sbbdwNW2_6YHA!1YwK0zWKa zAV}fqAQtae!R)~=E!_@ZlmMK!NhXfHW%8H?vl6@%UHYtXbuM`Dt>KJ&*Y&T~^Tw?Y zqL`x={;);-u70_Qm8`tKA&q_ySJ}wRlE6KXW_ifrp1!9O8WQOx1NRtfcYxIfRy}uK zwgx`lAs9Ov_!`r^6aonYV~dPQVm;h*6fqHq)u&(RK-LXbkmkbJH(VtJ=&_JW^ilv; zr3RjGZ-_msF$w12OT?%S_7g8cdgM5Ch z>@y@9MXGxVu_Pig(wHP+)MAb>mhqB~s?QV6z*>n25HhbvTpyD-jDg@DhaX;y9l*JY zy9y&Eqc#>RCjwoo!MDqtnN75Pp4OONKBHrJcaH+$Z@@0==AbjQ?a|P1^7TP$cNQvF zlEF%B$Dm?))jSV$giupDE~io)9*H}eFQFL5gDcWiREY!>bWxl2rh#Y~n zH>HBAu|;UjRyf>=Isw%SG#-Wk`I_)ag+LN0Y(#$lOk#L90}#oW*jA_E9phcF;lmQf zWmwe)&|T;DTzuvgsf-fHPl+i?P9H285to7oCIh^(l`D@|Vo-&<}0Yu>FQN0ktrqm?qqK5|~ zukAkRyO3h)0r1YmYv$*j_O@jQ1O%8VGq?Ib9vKyc^{N&F9&IT>g2obGWlAPnbyrvlWac${;8YVa2KgiL zFxjc85wmZNeB!^d$%%;jG}JxdoO~sVJ+j$V4Gp)N82opx5ticNp=2$K3F*1d}xf|^}qW)XntiQWsu{E zIHjEpSC7K#-LR4WIsU_s;~h>Cp7_a9SL^|r$o}%|*Bd@^WA}%jU}Vr%q7RrqKke_^ zKHT|Dm*dy738@LU{zYut{5jyZr>wIsze4X*?@+1+2~X4uJFMk*E|=(f(tmNhlm3&?|}oKUmku+((t_8u7bzJ;8)VXA(f17f1V+8GR}9D<0Y$V<;*lg|E%Qr^BN)B7Z~y(b-D}M+ zkoT!GaMJQ8Wk09G(DCIsh!mo;^Jpp*&}!6!_NXrHPC`S~8PA_TSDF`6*pQE~yjB{N zD&$Ce=_aWSten~c(r7sNRiS?QD*ePK!qn7sXgpO$JYL!)_v-iPmmW?4|G0=3LvDU^ zzcHoc??pFCF@3SF=WU1Mq+s4SQ4Zp_-eid;D+48cRcdNI7{NK8h@~ka#G$bw<_hVg zVFBAUN`P8|NfpJh!5Dhrc zrp&-S>DZ){jbL4S8DF4L0YmFdyyj&iz?+O=$?P*pz+E(MqwOzR`>LZ-CC2eJ*r@5a zSf2{P`wuA*iZ=`tdCN)QXg>U+bw>l?ge~$w z0N_zv>co6IboN$r9%>V zde6Z&<>||8cFr$WUj2!cIP0hDY8WzQyHAenmG+v`N!N9%l-k|xky2{W0ctvrsAzp( z-tL1_O+Sw`_LM!mr=zQDEYpt+oc4C7Nz)Z>M;j>;tH^7*@JB*I=RZ){ zK5_tFa_b+^PBrdP5V1zJBrZ%)daX#6!2%e$Cik%drcX~#*CJHiL>Ng3mJ6kqTqLxb z?FI$#nfSv)?~j5M^MFvdi2MQU~ zi@?Pbq=*@KVlBKyrfY`yaH37H82ee)+=L}gC?;DoQILZbh#`DY-j{CnnvSh39%B)l zU$9Ry$9U{>9~_+I-LNdx_5>p%yxrJn0S_Q>J%wwtU(DfYiULo|K)3_WU2w%pdu$6081`Wm21iF7l{6;N zt-pNJB#;V@@MjQq2P6jTJJy&z(t zSLxCPln5B2Q?bz$r3fM_D!mJcp(sv4sVat0gMgujC?T{Ea>j#e?QebOeCNmhy*Jmo zt~FI4$@@O%ZS+f3-fyCtH;Hd3y6CWU!ZgARM49+le;iOD zV8$>m-1Npl#5ETds)p*A<0K#&(hUTX_%ws z#HV?QemVhNXsAUU|FH;@ozD%!c#@_^X5(GP52zsJ>NzGswo^l#_4ejWwx$F14~lP#7UF1^UlKgdNENg>u5W!F~NgR1@BUW`_E}|dg9w1+oZ|bkE4Qon7PbY?v*KA_51H; zCDyQ%sgS@8ypKgDH@eacVa%3FYag~=;6=-AKupA6<#}dqRD;U^Q@9Fn`}iguR@!N0 zp6ck2eNO}vzLmd0O+4#pY4EiNMcsGo%I!si`&smReht(u?H~9$mBn|Ij176k%6C1y zawq0(Kd5SL5_5sQ)REoxOgQJw-7_wfZ;}VSTB;bTJJy#m3d~kG#0Vy92VOd!Qy^eV z_)*c+%9EJP{rbb8}BDvrpMCW#tzP;MHgJ1Ty)KYue3Jm%&uK)<$9KgTuga@5YDV5 zS+)5rYsDvq_{^~|CHlJ^HOG1LjsD-?L%F=1JuF;a^w!-o>RZdbNh6>C{USgou2aXx ztiR7c7OgO{VXEsF)~AVT(Q-ZDkiQ}Kp5STmkX_Q{65XK(B`*IAayZFC@)ul43{DY1 zlem$-K*#JWGLC?+oDS%|}lo7Bt-Cs&CXIXRyp z&%ij)cX13@RpD767scAG0(uyZCfKNl!lwyekA74iYQRsyj zi>ArCl}K5w*tvP2cD~>e12U4x`Djm{jW0Ua-HJ%7&4t==HSi7cLSVWCGDO{#rG)kf zZ}}_AYA`8)G0}EMpoKwL@%f665WsONUCZCCH4n5^OkWlnNK)7^OI;5;f-^x<@@Tx) zADO3o?%U-bb>NcQKv9@(5OGrvhy{$p?sMkPpHJ)%%!ynk@8ZwBA)u7rZOI2YYq!T% zq@3rUXz)$5!DDhdQTE6@Z2i6ascy|~SOeSlz|M^sl`$A&(y4@LL#&{~#3j4hO+3pNTcCo%9!j)*SK+LHdgs`Hd4>RFJu-_E}jj`)U z8a0?X8EVO(G7g~w7G&kqF;ykJpR&s~>DUpROasao|2}Ows2I9qsKnDRK^PAEoD*e) zkb@*Vy=f4W<>WLJb$=jq&jkj8(YH>vlkxlf#T!puBZ)Oc^YGy_Sa5%P7>6zjz78My zz>xm#>EDM_Ncb2}gpW{v6a}m--OeL8<4Z+K?oO;!_xtxs^|kMaL+bd~jvfDzWbvPt zu1E~7E-rsy)r%{(1~zVWW?;1knz;1m-Y5dC1SU-t*x?c~3_b0iZQ$NC%J5U_tb(a7 zE>AG&HN@tzB3BOLeVoTb8MH{g??vUgTplkNbC4(YlrUcyyP zJet95MYxV@X*~cjW=0tUyT#hTv3MuL-yNunPPRP2I0h|U$H>Lb*4Ah}V)6tE z@v0P*ZBdS*saq!J$$3)F$hq^_Nf)0)mStmTrmn|@@PYVi^wy!^G{^Kvo`c4|9NFki zq!{+E<(t1;Xe(Qq?7KAowFqQGYf%$sK=Enyd0yG6X;|d9bNR0Ge^R;dB}vBxn~@+1 z7UJJmujX`%!F?{YQz)XEW#|GlRB{J#;)%eYKt`>rl+mLhRbOKUV5|Z|#O7pTf2^1L z>Y>TFbzm3_Mq^X!aK|l4ftcKgtis5>6PH9RS9@syCYLZS{(QuE1+#~J*gp`Ii3?!>o99PWvqsML3%V56dtkcK{%}i( zaD14MKp^Q=Uiw>=q`cuW-9k6w4J~Q`D?UhKG5TU4en6hFED{e48U-PNTkXlNOcDwc2;+7UsEohvuVc{?VpBxr0+=B# zzcZ7ZEispA9)Ds$1G&b8iQ{kMhg^g+0E(NInIQ8u{JY{UOupA3PNvdD-KGthQ)exC z17nnHOjbP*qE~}?_=Pg)YkWm zFe}mnMRKDUrCM88S4pHATp&_uHhyVn3|v@qBqVIW-&v@mj8(oGYb@v6@cKuOf($iy2 zuN`5s=8uio`xam?!qXPzQc%O5p`0%D_J-`y4w@sT%kcv1sH{;~YUtEo z^z{4!h|h<$zGXQB`zy$r_072hz!hyFG`h`&1;@tRtj}13aTmR-Stb^+!|wW)LtGQ^ zyw|Rr+e}3ev|b>|+o;oILFOR5+>;JeEGxv;_xa;1Yn~&u>pPytAOgPFK0oR_h2Y*1 zWxYdC$vu?R4?x$aomI}WK5;nTRG;@e{R}TVz=Co><>qeW|pbpUcmsKP=!R2m}QGKZ8Qu{7txCq+|gt$g;glK zO?BcDQUm__TCoC1&9AR--^Qy;@`v&Nyz>!C@FUncSr61x&>Mdagj?wMH@v5jSPwW{ z|18;eQw4Zyfjw?3*)V;r8oGRlKQPeQSehE^SW{vIYBh|r>B=E>k^H1Nl%nXS%()YKN>Q|G8UN-1G{zG<2a?a4+xI{Pk~#LGvTZuf-7){f*8V+ z@ENK3*gMB-LwVQb8$vO5eiFFW-h^vKmCN6t2C7hH;Z%t!4c^=qE-ZZs{jSz zUL>^4_nUIuHq69&+Y0QO{@in0dMdSvuxD|n%}UUT-y^IVWwZohdBv#tlV==aP~A<)8Vo9TVi{ zzU}B&-IKX4YWS6W-}J4kfT6x2H3fiL_68k_K_~5RyYHHFI%uP<0A^R)pz)?$zS2Q6 z|Lx5AgJa(>vy0Wp&$ud*ggFVA^4d4bbV}VfG;~Cq-8YCohaz z@kvgCLK&D1h?gL;w-#R3@r-&*+Q0w$iGb0khj=s=BmdFYUSao!^#=TdZ6EkW9WNWG z0b?I0$O>~dB`b$mJ%`p9HrIeBcydV!+>v_ zem-WZMww(hf+3ORFoqkh9Kv{m@Yg4xk@(Bt5z`eRyqApAWBEURU`WegWWZH%ZwU7A z`nI&r{yhz3q6|QjPlU-##1s7!C+?UxVakfa>i#&M3cb!kJ`N$#s@)@VkB=7$U~ruQ zWa$GUY-oE4L7oVaA%u*nb@L$$F`u%6GV74J%+x&p$&WvS5^)wo@Y`H8GU}igJ3l_; zT#ZI}Vf}tA34w3uH5MDIi%BF&YXn?GLW>MRx*EF`WH1AI*EzQAE%f&HviyTdTLwRV%- zlZ)^j3~F0k&E^CTWmJ(U>O+_g$XFs_lQ?Tg`B5Q=72Ab00CI zK@!IIW97*~f{7|&0*K`m@k|Ho#5oHvYCK^f+Qc9Y{+Z=fH8#{LQ3oGvb4Fs36V{{> zL!^XSvX1MOORLOSK>N>R%xS+u(C=H&x>ShUcnV}0D>d|%n>4^0mM88146th*z^Ie> zpOc?ae=nXMl^rOkz@iV&LX~TLt&FVX3z3OCG?>oB`|d;;lunvAbf7;i;`i^zX^Tcx zmEZwO|4rDl`<}>EWCN&eT$nC^`VeeY_2o+kNLaUraruJ+0|VcWci;0sXF2X`SX)JX_SIrV%7+Mkj>GP1V~tEv}BB zH~9oKS(ZfO*g(a+BMaA4G-@p4vv;8KNyA!NsT0x)o0f*+@kB5mq}nQE>`RvKdWMTjYOCb8tv zZO_J$->FXq)J8OT>P5fz-PvdI)%p8}yXid`is->UDyI(y{>^#nv!hWj7%fg&spt^) zqYglU1?oiI6;vD*;7z-l1rsilqxj|tTH0G=u#~4KH6q+p0S-kqqkivhEC~n(GuNw$ zL?(<*HHL9dGXOZdwZq)m+&%pVF?u#07BZ7?E38GBR4T*DNYB#p`|{<6>j*m!=DiIx zIe=Bl9(~U?65v@LAo;jBzpRU3x>%G8Z?l^G7_FW6+k>gBQ(S~j;z?w#QVHS@w+|-XA-8#-L)E1fmp~;{@ zpMEQz_+yv%?VkB0#R=mP2S8|Rc%H^Ty%ow5>LG8HOB}$J(FY4U$DTNKk|mOQG|IOd z_H!tg_u+=GLQsrih%grdNqFOOul}}YaN9$Pm{X6||E5#JE3>))U*Bk;ALrUZNH8Dp zpNqztNF;j6UXb!E439oUu3Lk`J~V!ymORGRk~4K(i6JobH)Og8B z#9To6ouIEZaAAP6ASKaR%C5Z`&CfA$<&tO&tIyd0aqC3fe!)fORfS-cLskboh5u%F z7IZdtiW0#ORcYb)H5&B@6Rj2VL?T(m2i%&pecD8qVO^i1c3tlts*$0j$p`x|T*eaM zZ*L};WulC;#!tu6Or}s=ej&b6N4{+5eOQujG;P}#;Sf_9Il7vRX5n3}vgiHu&EF<# zs(DHlUyXdZg?>bai#dx3ZRH!P*6ve?RydCz-0sD3c%fKMz6y2w&JO zj#yvzB& zb1EVY(|D+ltn8PB6#ttGfKDcq>;jLySn&Jr35e4~6Dfn4Dm9sGeANT(;1dmPkkmK= z>j?Y|C)uaEx*lfw`k>0^v^fG&vK+=}EFF;rRAcd|oBlXQ8LP782`5&EOlisX@!R}^ zK~g$sU(uh+>*tf0Mu<6(5lNLEg3$;E=347ZO>!^ZCD@s?7;2uM?B~}%qeD*is6t=S zoC$7xA=u;#?ct=5hFWfViUj47RMC%N)ys)~aN-1>{EVu!;y5^gWHr6>%Qo~i9f%1! z_1__tfMFB=x@Uje3UrD{?bf6X|C&$p@-4t_jJ3c;^a*kOG$NJkST8)DPWD&;vyVI9 z`6V5E=COy~V4=MyRw3Lz<2Pt#PQ&MisfgQ3q*|n4U;v^%iL+xlUZ~*eZ*1#kCd72j zU!M!{?jB&`S`Ne^3h5Tay+eqsCmmQAo%%*4?}P~*x*-$!C}xc#TogegvE1GbA_68H z87P80bipVg41%6^Klu>>%k)=L9y(6HbZIw6BI@!m%C-7gwH=@PIc~?M@g$1^jl_vG zW8AB9Rbc<%H*}y71!8gW;tAYgl44acF1lC_bx#}+hVvNe!!PeKu$2S! zQ`wD_nYS0q9aj&Ld4j=WM`N%I*|^%XsV7M4V-~TPK}){aLUfIC#(+xD3P|`$(#C3Jk@(b={hD1H$nBij~*RnPi18KHSMm zx!p|#1@XS+6aShMRLVlt=tBbk8plpmqB-Fb*&wHU@`~3Zb!IQ^6(HqLb&ySx zl_W+2!%Vw%FJZBWax)SH)<3J~VEqfGOLI+7bB`DaO<jr`Kq>_3_Dn1eR;L#;j~*@QYXt+2DKipO2n0<;iVssqz;%cpAf&HCyGfT_MtP++6IPrs zH(!ILCx$#H3U(foVH1Q8xPTKtjDvlFYR z*w61&bA}Ph$vBnk`z75x)!1jBx94VX^5=i-7+guoU5W?j2D}e6aR5FumOn1Uk4$)fjWGE^_$4K$@tP5=x(cNTg7D`Vzk5Y)HI8ofHfb6OI@-Vg?0Thu(c z>eac?iIndSNKWx#Z#YO^r;|1c$`yr@zL<0|D}V#w zH;STVecYKSS9 z9VSPqb%ZrZdf{wHG?oF-o1OqFpO-c<{&mV~L}1q*hB_Rg?A@MOSf$f+j*nzRN?rCrt{hG5==(|!WymnuX)I0a(&HKzF6RSB)kz<_{7I?E}uu1(mnWldrE8#Bqg4fFJ zHn>+CN=eL_y<*25X+((`%`_}k+5+8@cA_yTC}cBbvjCLCL&+Wr7!fxEQOz&M*4rnq zc;Gsr*PoW+Y>BqRip+XhHDrPEMG;T|q(ZoS5iwV@AoHfLuLWxP_AW6#*EJU298~;k z%*jv3%V2n^#!yX7djz*t{wqKx4!IK#0u z;1e{pD2JiAhWO)gSmiAXtPujy@y{#}%hzHa*DOF$dJyoSu0yD?g|j7gDiKTen$3(N zG~X3~FQN3#c%Huqp03!Z`mE-7Wm;*l^kR_dr=>)OgpAv%J1m|%_cBX?GG~VGq;H>I zZk|Ju8S0R;AO*ow_>WlKoh$%qu~62KrIH%r0F}+8lm*_k6e#uMJ)r)c1-(*l$v3S8 z9a%yLLVhA&mszg}11cKkrV_|c!N_niRNYz60Sde%vpBl>>Z7=_#2j4e$UOO?V^}&E zBy}4sYXsz(DKs8i1(z^X-&kFMq~-K;;$=v7$%5`prbqDfII!8 z;!esUGhX7%S+l-BqJp;gnZcmE29b8hwnrOoCpzh^NR3pHog;(g-rA(b1_t88#H#Pu z_z@sB)*g=*4?l3mcB2nf7(4x)P36cs458srSUuUs?&6>itT&W`t@E3d019(EaiH9aYiQ|#t9HDIl{aIL)4?wLr>4*H{IrYb z_h{;;l92g654SoCRJ{ciSII>9*ARBnXJMpL9-m^cbokz+|JJl_nVZ+-QKc;LIQXvG z&c}m4ZTffrVmncmH?N%a=_;F-+Zj3a(~PJU=Nfi{UA3Izjl`PzJNqp~r9)H^!Sc6_=*l-G?W zAJLe^#fvaf^I=v;)OqZ{;?xW-@vD!=baxFzN)Pat=Q~b-VzNlbl)HNcgv_-A7**zE zkoDvU77wzpoALljEYy6cA;4{3SLKdrKUtnTPTwQir(^Y`jfL_iuQm(6(DsW|1{aav z&4vi7aM!i9D<7c;LYW6)X}Dv7szlOscw(Z2jE@hEoHA#{VK|UAaB)~e{PQNHy3KlX z<@dYg*`P1vF`V^K?uHks?%HK=mX1#6ANV9DR^OMp1rNLXgoi`2E097-RFi3B$BE^* zAc$No4zA-`V*i~%ZKCPQ^DrSM0-jPe5RjnYl4jcgu(d$CDlG0LPC>K{YY+?yrl-KS z^3{%Hn&h^#b0Jp0%Ymrl-F9by|H<#zRw?7mpziu?IWmp@RELP?0D{f!OyKSy8s6g| z2fhXA{!MV8ukSq$kQ_b4&xL%H9p-3cGi`eytH8r)gUlAnLFMu>7;>)7*n=3#!BnR_ zm<+LHBEWxAMfgY_6$uADc&Fa!Wjn28o$TNRRo&#q#g(+gGYj+=Mlqkd`$#?^yZ*JiZ{ctUa>CS%J(sVPGs0G zjG2Xm0tc_45B2r+Jq0OFsLHW9BT_aq#h9@^!9I@c-a)e0fscxI4_!-3E9+}M_6&M> zc^M}0;FN~(OlBCyIoowr8CppOO!LMv0i204lJXZJG?%6~JrLuXn#-fKI+wir18~#h z14BPX=<@C%*dX|^rPaPoJTf$7`2fUQAM<=PYx-?~$`|k@Y5gZdFgMc;>BD;>JYU~h zc)^?-zjbPlH@(D1DQ(Zz6>Gb_Ri}KI;%VAX`AhTJIkT1a*#P7-Ic`gA#@s?^N7z4lI#p5qpLV8il^o882wbpQUzRBu#< zV9zn{t6`0;n~O_x1$K2*I5dGRpVAeEk~=olg${_GbzqxmBV;DFKh47_cSNMw(~PCrsC0}sfbd~;fHRqsJoIRo7?79=FujhB&x(kM z&^O`c`uh1Ts2)U-9s7uiE&yRlI&;tqXXaQfpjPHEh@0fo9pL5?%$seTwcM_~5!Hf* z{v+pL4-xUCKJATaG@k!J^9~HZ;zsf-0iLOAqhD$%EHdWqO-70XN>%?z*QN=c%$Y?1s7zX(MG$&~(wg8}Eumd2$}b`qwM!!tqnBudtn zkz55=vB3LnJn6G2A8K&{&aBNnF;!&=jlDEa{5bON;+yyf*R7<-T5|KVW}+XP{%Ow4 z{r^poV%|SrdhMVoZ@xla_ti1KOQWbXMHsSP_W!YWW&fFe51a2}-M{*}sJnsa%2Mg$ ziN_@N>MB1~o?ip~Vc2-<^0k|V^OQRlvF^0@_ z+d)4%f)(H|xF{QMLBWv2M;o!NKEU6f=xnfy_q4W`J=r2ew6IjK%*s;A>VSWK=uF$O zMOL~KiSCzP67bY>)F^ciSrH*O0ubeiKk`l}SRLKd|JX~2KbtpK*hRqG;xh(6t6y&Z z{WFqU99TU%#acm924Hi4x@Uh97W>Bl%BR=8z;pHzX|_4DwWTE%D`0Q)T|l8gaN1s5 zNgn29@H%JWVx5O;f`+KO93;`^$-Lx&*4qzY*M*sVenLJ*9H+=8b2cc#;~HT& zSNiYWw{Kx_GH%Fu%;xpSfJKok{1gK}fJ&8?L}KL1!E^`x^`+q;eCB6i7r^rYURZxo zqBaGHo=bTIVf{2RSNO;ugthGVaB9fr8KH0^K!$EF!TwLo>EH|j2K63!q5$)y@501z zXR-$$E}ujdYc)Kc46wdj{U}M{C;>`?;n0>LBLq*a3*KtF>@NqDFep<;8E|@qauQ3b zqy$5qSF3nrA2%G^_S$b)x9&6aPOsV;Nj+aZ<+9REf-<~5Vk57qFD9Tkv%U+D=$W2iB>Tx66Nsmjuuo?iz5@;g# zcFFi0d0s#$Nbm^x1p_qg`MZdxfeg* z$HYJhgo?S;G4P~q(Eh&|#i56^4Sd`30U8O_eW)9i##P|T5!g+b1-G!%1EBAKUSQoY z3`{r`ed8Z)*X4`QY`@3&Ij5T_F!WFf3Ok|$U)kd(M2KLYvA28Dn+O!w=g!)hSmt`a zYq`wrv2{6vsb9REdeA?h+S!&2c6{Dfh3Zn5bX70wmZPQ{cgPtw^hOH8301doTZ{Kz~sS4Ghm*j4DnLJ+|Mw;R+k3M3%^(d`^oo_BI8U2&?#zBmzO0PQvC~`xt+VkdgBrf5H8nC(uWo138;K)SMn;CYF;FPt z{H&jk;A_Tw2_!H5xFUlp>~LF4%hNE} z7o8!Uj7$>|1Ls4wmH|%0hdw|JM#EsHm828SH%5rfC4lB@io8B}qnB_CGzJls-B>OU zP9AZ7VAa6suCxyoi#7UkqhW|dO8UV6w1B_FZE}JXaW4MF0-|AC86G>!VW^p0IIw}J z9giz`vAW&vNM)9=GBp}T`1(LLshcBjo+^9&`gJ;5ESsHE9kfx>CFf&OnT8s8dJ+vV z7Li&ek07QmG*}M4^R2WM{W{YwA2rayMC@HBm}QFXAQv7*YnHh)MM+j-C8YC+$_{R5 zv%+EIPF|ZM$OD;YFV#9Z6Rc zS4RxP;3@eO%>7ck*#Hg0VTkv>3HZ-#bY5q+ll3Pg>%DIx>Q^0%T~TX3!9)Dfd)!A0 z6`VPkLd{zENVSz1pdSYD{d5`srF=MK0OTiIa)&_#jRU#PIn`!o6WTmm)U~&{WMG3P zGChjmIbvMh3n9X#Djxr{Vw) z>9gi463_{F?J^bd(poTKYbF3wCvy62?$P^y?g5XXu)CWJr-<8*_*91=e=W2p&1`q& zRSa;Xauq)}N!|th+J~tK0A`U`YOgbjw&y_9Hf0f-@_S8NaAOIJbRoZX`@nAg<{dl2 z`oI7~p+PnXl69p-ep+?gribir!nt#Ptkgwz`k`0H3>2DEEUd0;;awb10iKQ>9S#*Z z=cnPb($fxnmT;urUwW|B3d4Afv`7Q=6;D8LO>jh27Kf2lq5UMv29?d{q4K!dTDVKU zQO3CE@NAU05UIFEWUbFG6~MFLfl{z%XcB2hyA=P=qCC zvJj6)TMv@Lc=k*~Rd|jWrRW&`3EM`qKrl_7S+x-QOZe33UZlx_XkG)~;KwyoU}iu? zHkQJq_yH+EqzNwBEHZt4KCVUn(0;N=vSAd`~a&mS*^wZ zTWgV^Fmiu@#~=*=>81c0Qf58+SsAdu?2aGB_T}aEUoEfDm%p8_afs zwkngLnlYAbTXm3G1IoF2O${gr5A4mpF=erP4h5OUe~@rccfmCK215k0*Ppn2dLjg@ zI6KmA;FG%#^youS-R4vP<>2?D#wiXp)d1KVBWgv!2bQyy2>NA;~eBMzNMb~J67^x&CMr+I|y-Co=p74 ze_O{ha3Zu~j;{p9Sj~`*hmP_zs7n34*S8=>!5#5qBO8QA1PC8yWvENv5;p-PZMW<}fnXi6!4PDg0&Av#_to!tM8tBego}^2@dwoh zx_Fmttd;vh+ta!bw{zuGP+-5ew}(Qaxnai+J#DYd;oe zpuK(g*h!bGLZiuwG9;WCP`HT2Z2Um=tDKy>7!&@hgPi+cMaf}FRY*l3czzNm=iJiP z(^H1&+*_hZ_lQF8w@t7P=;fOa;z~jogoJ-V_o6>fTt@0ULcmM=rhFBaH%2H&F9MSX z;n2Pb9dQ{X=zqR+$I%(*2#PT0o=KL+VQy@OisE)AsT0U%v*{@*?-7plp~`zzlni7p zeH6+AJp|!beV83DV2d$ta$^$TXR;&}#w~;*77RI_Ehg+um;Qt z4C@F7)WZP9K@b6!P8RXLcPD#Eeqc`>rWY}UAmTV59Vo~$r6D5*4NwfAR(xKQj3B*8 z?T-u4(V)e9NE-967&u1=&(5yQl|KDq77G1!hF$h9pd^vCapsJk@N9!EMQ72|!wdkI z>^X*F`EMWn1fu)|%n(CI=&JUifXEtR;OcA~^B7-)2l4`;8aorWPIOTrBH~bu+G73t zOW-Y&1yM+x0JLLJvg$du!W0CQo%xu_4nfboB0S{%6`+c*U0ScdVegpZWklrL80cGq zQvd7g@>RFb43riDy{Kde{(#SqAv?&PAH2O0GjGE}wG5?I&5JRs><0=qo4m`28MGFd z@U@kgTc0Hxy0_y7$eQfu;o&oq%qT|+gqt*=z7JUNh7FI%UFjISf;IXA{Ef8=m+83M?*TZDT@$Z-urIAVGf-msp_yDqI^(3 zKeX`h4h~=hnHerIYu3wBHT72)x)+f(w70oL4DY)*vmSbXV(KUFoDvvn&;TnB{0QzE z(9iF!t^6sT&nkfO9|DK@W!(#mDM)#m_hi+C?|*q3_fX!fnp^DSk^UN`dUqr3U3&J+ zd0k1ce7?OnE=cMY@hS=NhtLxk^!F017Cn9=FC!UKcB4TLAcOi24v8|7OP78O1{R$q zLo$aBK3ei601`iF1iU9~B=r%F_0SnV- zPz>!!a~JX8twq-HsXnf*Zb6KV;sG4E>5t(Of`?~rMC=hh_K_zZ8BnJT@N_CvE+;$k zeZj|)O)e%xn2+gzzs!gQUddoLOY=rvsR@oECtL{Q}Z^S=L(nL(z9Xo1dD*3WAA2_3XXW43Uz-|8L0;g9u8{zQ* z$3wHnv=OHNWqo$V#Pe)X7MTdzV5-`XX>4p<3%ZyOlXa9^W2IVq5z<=_cG@d;?cA9L z@NQbS5XAYgd-vv3iHFgzDI@mk#FMH9whDLeKJn~9v1e5x1{_=loJScNsYM!Je-z?s`1+ z5WRh_pC)hd2od1u9Bh(6wsyEGT=}gW^(5u;6^L)nocApFq=a0*LNugAl5@|v9&grU zsBZ$<8`gWWDmM~mheK*({%ksh;zcTu*w3E1B~zW7oX5yFS32y!#J0O|_NRXi zpPKA6>6M0gw5@@XY**2htJ@BAtNs1dsqXQSd#it|d!292^VBtH{3_e^^kNh1j>1F! z;8c2L)zS*Vtev_2xu%y>)%%7k_+@1Z{M}8JgKJh$6m2hF)Ke4l)uO6gE%i)q$ET$s z?^`sbdzCgjJv9%KWQcZsaXTZf;}uI#yjC_-Qhx&(FnLT!7xN}hUW6yUyVP{7&q=cA zQJ;buUty=CID4$R>FCgKMwBR#lfF4rT~gF>$gQr)y{o(Xw1-CyhpYDUmZsF`sM1(b z(+68RUFa<4UW-y2%&FAh+Rc>p1R~$QT|f zR&yFFsOl{1+?|+|#6RLB;I%?$puz1dm zeS{UqN!Qla-sLrrIPA7>AKBGzn?rIvSzTRP@0?vAq>7!6*VEe+qK*uCv{DbR=WsZv zZ!aAe)|V=Ji>>%oYND$8^HMpbg58&}kVVVLDA)hcno_PuC7^}|HDU5 zYF;fjCL^XX*F$08mgc23I$ByUIjm8)C}D$>T4e5slDMr&&yy|gj~c6bmaZBlH!vt3 zYs%IdQxms~b7xj=&QKF(sQK<(5s+9sR$J+<2x{H~t+7FG-k^-iVAGI))8S3sgF=gf ze)WR;nThY3Z;C!kicYelglN*{+B-Ouy%vKxR0ONlM}s2g16!8(iMmq8;-9m|44X!D zP7Q+|`;Y3_&p<;@E?#jo%0q3eU?ia+{XCo2cQ49sHY9=xOSfP|TRo+*K$IZ3}bbdd-lLF+kjY_ zGia~gflaMXVjRj$trufX*b?2 zla#D{ZHzmcYvTNcr>mp0O-U&HhGv8` zC9~Ki9(aitB_$=fy!x&|v)3#q7nhT0{`5;@ytpr3ym*MwoL4x3vOI9}m&bE&-=!3letCFLu zTNO8lN;^9Hn+^w?eyr0LU|skKw`q*4A!)J8&CPA3WpP1RT0-2r=1;8rf$bNl)D0po z);L!2L~Nc_!wvksct}#bmeVxWN*@gzsi5X(boQB!dw>15kH_&cK##?{=#92K!-Wy0CuZ z1|8u*c0p3XkZ-|gt z7ArVqNQ$bRMImrxxaSg4RCG|(EIDRYQlRg_RUJqR?35h6N>BauW=|a-8OF4i#*sGt z=*bq{5dVsaR@2J++B+uIA0oN3anij=I+0c8%9 zo|EZY{TxmW zn~IpGnWJ^I*5yqfgg-+=LJW4<96fq8sN}e&rs1R28Bd?Ci5oQ?eQ&B4zFPfMPgT^| z`BTH>GKQEahn6lB>WaHeIU*dA{1IkKkg|0Z*+d2^QJn{ z==)Ii;21|?#gL}BQ;m}=Mv>m`C}!ARy43K+kNZ>XJxHaqWW*cjeH(TbxJ!BunXv;3 z0GY+myzo!*0saK!w*ZvrMPkBee~f_`UAfGAf`!eTwJTMO7XDT&O9f4 zwt+^Tx017v2YARs{L@v%*#rwDGaR-pE6*7XEf}@R7?q$8y?a<%oU-UA`Kij`9DE=S zH?v6tkoKO6sM?_!`Aluw7E?xC+{TRD;DwvEMpAXIPG~g+GP`%!s4{}wy=|pzC>q*X zz4c9F1B!X~C|j}1kMiMU&${s93o%ipCgGE}vD))pgh?Tl%+m90$M?qzdWYF!of2oG z-`49I%0@|7)QWAg3!L3w@4hU$b&itd4&8a9>g4YqIIf-0Au?!7vaH%?I9*Cjd(fW7 zJYy;Mo3wjY1n->_eQbc=zL;_cso6oc{@U>xuaeSIL5f&Vz~;V7l~vX~r0>G`P6 zU|?fLRMS*tI@adalDmO5!RXYQ8&zk0U(GCQs@bV^j+G}S zCa6rkBgrt{(^x)Z0GDJ3Z!o2CtbtM^Ic@6Y9e8hfuT{(s;78QsGr>oKNl&2b1H=pZ}6h+f5$Ba&$dTKiI+%(-NKOsRqYPig% zEXvE%lXO-3o5iG#AS=!}TvO}imG2x>1#z04z@<^V z=PQ+qsXJDTWSR=Mms(+nEy$^)Rg8MHdW4lL^K$Q{es@l8Z%!F4Nr_EO{nR($rGMzq zjj^_-(TI?2I<{pn>+9{uM&mSTMW&Fr>H{2`+`BbI3-M`&T zkwn3H-eV=Y`Q|wej*dy>nuV!3qxkCN@mT1%Wt=5e2bxpnU3=GD0}gi&p8Pay1uvHR z>3l;h8m$yx8viR;8LafE1bfT^^_zZRH`<*5OrUx`$aC+buBxdV>#4M+^*UuME2^qK z((*=XtZry{m^q4Jhy^IjC`mwlSlxDRM|!WA6bd0)iYw+6=MR@VTaSkqsP~U-;_-*g zqr{`_vcd2rQs1PepfFz040OO!g|`CH znp8wG%ly~h_dgh&rZy6-maa7hZTb-=g$)@z`*pdX|3Wuhj#A;-6|+=h?Go&t4a7 zs;768_I<77M}z#dGb$-oK`ehdQnwF(7isF^7{|mVEu^pKGw^UodM5 zRd_D7*x%2u1NC!hr%?`-_XrC3I7C6m-RV7R?%td-WlBG=KS#Ai=qa8&`D6H!YH2b0 zI`S>oc&8jH%F6tpihjbN@_GlJNZs1M#=y|9bZF^}$rJm8BH@6Mo}pnC0_1byANU1; zjqCwqPYrOe>EZAtYG(H~s#4BKzle#^K6&zw6qbEX8H#T*{7#-3VAQ zdEx})9M=Ou{dWT|NyYG24W#3Off#u>2=#X~Q16oFbCxm+Dk@39hmRVhED#I~I0;>> zcZJ}S9{GZ-fux!*E4=mI{55=ip*_CEhWp-r>6Ae=}~pYb!YM=d->(SCkE$mj!q4{=PHv_=WT5V`F2_su%MHh1->t z6RuyM;<5YDvw}m>C;bBgx&R%z?o!CUt8x5z7x3&&va(EI1i`KmupiR&E-*z)0-o1j z6~)VE_?)^faXjWUE(4mT_TsYlxY)$d4TY~@a4@EE^SoOf0O!#vGC_2}cwy+2(N*`6 z(Mbcl3Mcd!Vz5;OcOrBaG5PtbrHenI1jm~rD*=}+U3wB3dDEs%S;J?uHFvB~bnd9H zt2;Gi(wC9)EUE2^is31^ZFhGmD+{m&5JS5|aMSgy_SN6Ej9F50o72j_xZA+M;7dnG zEN5%b*T%*qxQ{(7aX1K|VIbsVe0;nkZB*oBXLporbt<(84h>Df97irNbLrbNC%g;P zQUbBY*Dc>HDK_>K^7RF5u*cPjPftI!a^*_fY*QSqH*YRW#XWnrA3hHaU*w&Gf1hej8#gkuveswUCjq{>Uw`eL8P3YlQ>S>B0|MsYBH4L(=)+&T8qKakuiTPZ zU8F*jm2ASFIRek^Teq6$_({P&e-nq--rk;lp8q=SY4e~^0P?@%$j`)~G8@%1>#AjI8}}UiayM&Uz@^Tf z9-JrL3Jz*cfEh7J{*8HFx;XzE4Zm5Wg^`Dk$<)SUfakl~^?+1kPWnRpY93>d`NsO_+V6JsOym7kt4V8xC+of2L}hQ^ZAO06bJbWq7@7nIfFuSw}2VnuY8AQ zcvdI+)M5QqD^`%t0Tl0kcWJ5xV#&dS2N%q_L6z;t0_9~(mVEm0BULKy(+EuX?yn9@5fhdcH>r0A{{y53 zO|OmPbUCc(s$C<78#wAc$FU=pCyb3FGX?7w%;>~D3VH@8Aps*Fjyu$`h$F7MBI9vQ zh9XKir>N9ytXE3J=}CD0d>t>zi~xSnyH<1Yk;#b+EWVdD^`AxtHG3P|r9k^DweG_Q z;$86vj!U3-f3&rg@-qLfs}iaohJT{t(ft0k1;sWaZqUZTL8hI(v2#f<2XFKUF}{$! zF-h6c*7l>r$K%C5%qjoo0=(bR`}*}RRL0L52H-@{CO#DXIZZ2151Hwh;ag*Uefg`t z+@8;=jqHo9v-#r4<1r|B3+euJM7|~=dr<0#bDp3&L~SZ)O>NtyBk>CBMaeNShj1mA ztz5~3Bi*Txgydu$^Z_`tc$R|)mVIF|*Wvm7`O{_gtXZ+oo>}U8QJG)Ac0eXGy}x=5u-oQ^%(bE?%^#><{$^upwN(am87H zJ(%RlN@i5H!-61GDk*AG&ZV|f#)k$9aUd={%&B3){&ziI8tpiF3~*lXrm99qb2+!m z0C&QKDB7?7*>d$)>FGh)Gd>>FdEG;7b+7#O7m>m)76SE*O;7*gux{Htdh|l`wXH8k zz;w6v`O^f^xpu3bo?fh`ci+9~bfwpuA*tQaaQO znC1LCFpc6h=_6GkC4qi^Va6$HK%Mk^bsof}FISV1iWmwJk^yA?$*zu$)br8vrcFK% z#p01}rB6STeni+>HTYe>eqF;qt-Sry9WWv9M_n~SmT|T{)(cim#_=F%AMTvU(X{dO ztaJETvA({QY_GT8aSqc{oCrGyhhxNr&a+kW)_zx~ll4bu8jae`2Ks0#Jta-=7#`BT zi@RUDwIBb|1R0*Tfq@-KHq`T3XKGu2_Iz}yWh`{Z;}c<~ku~>4Z0v{8-i9Sxs=t1X z&CfRhjcL>7%{q91IVEAh05Jz84>_I?;{tDEkx1mxec`@z>&|B_0?!Lrm2;#!su}RC z2G7RY`XFYS2p~EjURCqI@CGB?W*zQkjXAvAf+wo{k3DhUNAz!sN0%iH8m29-P&<>- zdaNiPsKI%7%@KEI1ATqM3Kw8>$*UQgIb(*_>C+jqfssi*tLIJ&leLSCjBGnl(awLM zG>8=W`r&b#z0cpojy^XpyH;=#4cA^D$JXDNVVqad(QCQy6_K*xY?V*Y4qz(x&8~bl z59>X6#30Idb*R~I`}XYvW*qvGy({cCv*hfkJDN1P`3DZH`5hX=E$yyIF>M-#ibxkB zPDU_oiqFj4j*GTo_Q_lHazg`y^I+?%3)#L4qmPYx(~Bw(Z$`p7j9ghMw;D}h(TQ$)fgQvU@k<| zvHLFYTsUjWb|_}#KSbaW$GpC*@*Rqvj46{4+&zDMyYfun;XcrEQJCjCHoob+m2(>`Lp>N`L^efj88t8D6-?rNPfG!NVwR?~^-7 zJ@X9a`@MOL5RP!vmRJ|0WojCwwGl1y7Sns@Wy>CH+Nc^;nR}(|>vn|&Gi)6lHGt;Y zN>)yrx>Y;YHD~8+pS{)z>bP3Zd*3rq-zc`aHR+{&Jnv@n|Frkr?_9U>+fBt?Dy6Jj zo2(*agtSB?nHiZO<6~1sXrM?#S&?pKBr91NAG!%;Zy6tMgvjVaHhIpg=Qy6@`3s(3 zo^Qu}+((N(@Aq|Guh;oH&-3-Vx>o6B=jU4=wsJ=#iF1~d<2ocL*cHA#L)Q`Z^PAZ! zaUzD^5=g$oI1zeRuCxG-5maUuWi{D0_jnWm@NIf}-4Dl|J9gMEEOz{u)-xQZq$9uO z$eh_9YOqGB6uxzJZ5H&Ek#`33U~{}TP!vc4i=a_Az9UE4@SSm_rtj_?c6sR|(DN6) zGmc|0Bzf+gb#jj~^fWjJ8bP)Ic7#kWY`cHv7g(dX?q}daE}59bB4KJU+yi++CbOZ4 z0o{zNr1Bm-6$UWRs7>rqXwo98_-e?R`6)D^!I-G-7YzSKa6RY&~ZzU3#Edsx^M zh}a$N#-r&nlD4?YpbBJxto;19fJaw;m|i2WSoaAgoJZ)AehSfm%`R?k07>o9_tZk5 zsYPlgiTaz{dI=^!(4I$!)`P0xGNW%zSN;ngFV$z)VYk0}^;4JqxpNgcM;NoUU@)tZ z)cgnAmY7W9rcE|S);6@aw?~)UYG}B0_B9$lyPxenzx3{Qc=qBqd@9W4KA?oRQ0dN6 z6HfN6yJ6g77be@h!S}#{Ccy4_RFrefKMrHBH!JIaie1E` zmi2uBAp`p(NKXj~B*{Z4)NrnF@!z$nBUq!S zDAhqSrLj?+I$0^e?zvJnA)upOd706CrV?54?2)0rxo!D0{G6}=2K=c2hyy9Vk=@Z; zrX$RzDaN67{rYUq-#@ffE?(pnl-kK0FpW5H*MtGDP#w6iW8lf;L5|?(yBe{)4|X-G z9lHA4C!f>8tbD<%OYPjgZO($l75(i^qU!prMknhm>$k1Q@yo;ERg<$7SZPu|FD!U~J>=WE@jE=FsD$$|q~la_ zFX}ILF5ufl+e>1#ozU83+xyUU@z~i<{CDPMobBA90T*dvMS=vYfksgY0ZRb^0S*q1 z5QsEZefg>PCffgVkYw>^N`orr;-ZNn+$vz}PFB`06SK+qZ0V(&PRFX9`gk0H%`v)= z6+j(1u@(Cbdfn472_b%d^@|rDLBE?{K+~Td{+z5G5YIRIjpnAN*LWRdtXSK_jt)J< zx?@8Q#87&XQ#v&*?RoNk>cU8}mFGHC8?c})`Up)pA9>;P(eSjS?@dbzMJV=_m15g_ z1PPK~{Z8!-4GTjLi3Xp3Hd=V&jD-;|Z_A1*h=l^bXR=U{onc%%xI`OpO3KXCKs;gW zH_I&@9Zhi;Y%kx1XH?SLy*8Tv%so&T$L6m&vU75ZK1!uhZ(hv)j}q2U*4$73mVKMs zM>SqQhEj0*esEvK;&>bwk*FylE?Ez;M8jR4Cy}E9>Mw8W$=}7~SADq1zK~v?ASWO$ zF3uRroZKsafTaPxvF-k;w&qq1t*zS1RUHg>PCB!lzHlKpS~W2+Fi=xn-BeY5w!ckPot)k%SbU#mP}v$QUUekxY2WLEL)S--%bAW}z? zQiqFKbPmsR;d$XvBiYKCAc#S6vzFj(luPe%F$a+9@85qY5GRMGI;$5}P~K5R}W*;55+a zqzBbPM=iILVz?E&QHb5KzHmX{hV%J!Arvk8y72hq&96Xbx0=uF>oc7)wR72^BB4#I ze780kMH4>sKC9)yeKfXfsKuH-)XyEePV62d+}=p3j)?poW5%ABS=ns;s3f8 z(AbB*d=)BpU@&W40>uU@z}EfY6P)+W%*@t~jv|S%OpxmlC`EXE!{RC{&%cm#+&6Te zzn_wlRS~puGhs|!oQ;yzIkfwoQK7;08}iY4$nDI`&-;hb-<^dM0cr^gLH;|n7m|Bq z>VCw$j;SkOfLi|WSiRTFCEG$mSP)2lpi&%k9vK@W6GIQi8x~6#zTH`XeuB6{N4?9J z6)(4c{JyYj0wRzwue_KZTcg&S{?c2iIe`~dR3c8EO_<*g1AW%;com)YPpTxE%+U*$ zn{*R!|Aa!Wh1IeGuhGz3k+f_?ma+QBn!WO%4iUtbyo<5SOhCEX+BxxIO>kn`Xs~|5 zxwE%s`-lokD*8Vd-mE-TM|mM&Se=fUKwC*?j-WZt6lp1l+1@@#afg4U=J@yN(X zM|05z28N@DV|Uu4bl7x^jLyws2@(lfMo0yEs-9~2&MpFD#IJ~0wa+Ox#&f?&W8_nq z+rt1Huc`b7j3CQdoQ2d;d2mm^)Qj4z)mC1Ly>0~>3@)5&8|LO+8t<=gVPgLCm(w>; zF6)-w^77Bno?G^wT7)C#0^AiC57YSb=g$QF@0-gXzruF~`C=(+go;XBPA(0vU`iU3 zqf+4SLG1W4>|*WZWq@q~Zmve^T1Nh;%hI>XsEj`=OHQJdot^53Cx0F?PL^K$=%ubZ z<_q=LnCa?9V$|D{o;$SF`0~LHydfGWp~0)xIIBv@+igd8a`c3#qv@~NX5W>wLNt%w z;ZFf;ll0~ugfcz2$ilnSxqQ8sOgG%DOXVnKg0#EPI;BK2x-S$`wQBc+R;l3Dg=CxP`2ApAG#{^M}$Js z{5;YF?L}tiy{t-aT^3BhvhsSV#*h7-X1a0RnnCq+SpN9*Wd!*7$t9;GQxOgkT&W8Z z7dWYr4JYPqdC9$m<79hGI^8gjHh#0o`J);hXeM*FkrGntdCsLWAD=`FtPRQOyMZoF z)E8ojzK7&&U%Y%N!8G>b-YCJOJcuK)b-P zmcRC2`JP2TF5J|$uKiRUO>V_^`L@HVMODP)lFiri4}Zkr19{8O$M*yjQ|H*RiWCr5 zfOeT>SM*k1NpRbko1f)=WLbCp$ip-HER+>BG@iQuDX+n!BJuHPc6WO(jy+3eW&7dk z^Xv8QY?nJl8Br9ps+H7KdQMQoU7F0hWSDWU0qKC{0*dS%Ewn4_;@$fCZ|hBQ}YnMNpG(kSST`i8K)lyw(+oyq_}we$cVM`dVd&9 zhcSShl;21yD5|k6FMiTY*EItME!z1{f%oU#%qaTF=Mjv)abt2tp$A!fe|I9zek<&n!CDEFzFBbj(_6hmni$9 z$Yaqc*hPk7^Y9hrjEpP9#^x@YrkR6MZ*jfl5kox+g#s2>c|KS1fT^lXzl-#Ar9gVb zeV0Q!8bNfhG6%FE;Iy>|OpSq;hLZty8rA;EKHb6(bn!oDYWnI`e$VHOjih4Y*%Qe-fTUI7#aDS@ETih(J+CT9IG zs#a?$*d!t9Yp|L0acOBhN_2fl|NmhZAvj>@qCSa19ODQQ$6HSA+Qd*}oLW@mt*@PV z2*01lD)l@2-tL^Ieyn=iG=Xnh9X!Dm(_1=9jvT; zd>b8pFn*oKXCl6L6fnenRIgtdk;ucg>1}SVPEb(LVEz#5c4=e|vgp#%)~bU$gUYJ+ zTst0S+{LKPKMO8`kxF+fbz`^>ykOQgZA3jD%Y=j>6|k00n+;yof#Zu93{Je^ z+qXD8{n5joHZ1@pjSi2|f%qM47wAurN17DMSd9IlcD@4Et80%F&&hURO`x1izkhOb z+oJ#D-5E5DFoyE>sQ#JRw~>+Tnd0*x8p+N??g9?h*3lvAkdSgM8OVh90I-AT8>YVx zJ_o^x{obtp1|_$kEoH7xPfN2?etLjH{CH|7W1^y(Mn^|;{Ld-O+Pv;-XlXI`m&03= zSbH0w;Si3Xb!hP1(6glM((fVg5kYzgb!wf&)+Ix%AYyIA*j~m759sKW3wP zxRqdMqD;l^B8S-@^1SQ!UKjo2>VEQa{=PGw{L?Fb$!>-WUvsGANxjfqxux7yYt}=XsjJF&CkXwJes~b{Yl#)~qYt4{4A%2u z7ofAj3hEL%=ymMv(`C3HNp;1>$Dg&!)dy^041EFQ*V5VwKH$%cJQQ>81dogj%S*ig zd6%`ltlVdpWk+r06mvi+BW|#q>TWjribp)>2*ne^A-zanLxqO12EQGKz%@fvZ+?bR^B7ao|JX?@k7xV80jw*Aj>b3WFA2F8tHB zjh@f>_uMNpwW?50WH}*qwMg$Ybf3JioVb);c`pIy!=Xzx8~siVUa$a1-x|xi_(Y`Q zJb$_1Kxf%pVFE|3CWM5HHLgo@^b6@9MUEf0vATB4(Tj*LICw;nfxnmFA%w)iA(^H) zYh;nf!Ev;%7$R8WCLyS=Vq#(kAfzMYLyNdyOn#MMie z8p85L^c(8yAJ=!99{;2xm|}QWVus_hj)Y@zkG&gJ5CkD07mhDcnaMjUxPB2!;$Glx z03MQ1uThhL6nE|FINfEqp}~(}3L%6S@dES2k(rn0mwr5}qd%jkpUVk6z2vncZyhH+ zB`t=ISd$rW0ZGX;<8r0;_?)vawh^WDu0|4jx_*A$m?6^@kYVWgmLgg`V}BXp{bqQq zu3b|zH;+d^sn%{pLwzAb$Z;!gZ#k2e=PHe^RXHX7^fv_s`XSXOY~{j!(5-~^y$k)*$c%ULc4kN^^a_)$SkBxFCNT+%g42) z2ry!B2Vl}+ocY=KX)VqNG3!rEYn;fApP((f{a#(*SHM~50vt>#M_@71+W@`TV&FC6 z3r4|<7Jr4_iu;OEaM~61b~jxIAM>|S&LJIyY;4b(c}a{q&`8rZRxu8<4xSG_F(fV0 z5GtS(!joC`4a~5`SvVXodpra;9qn3#ZhU*z$Jki6ZmphLlES2a_bKRV@mN#vLnE*m zcnpN<ff!bSL}T` z(zxmTKZ_XJ8XO#)gv(!&BuXYH-(wC?0tgLq=g^W|kddx=!D$C8swqdX0(d#0fYhjr z!a`eZU#ej`VT|d=3zKlq=+mb#N`Pj4h8Ld*D}_bZIrtxNVqmY)Lcs`|iN)A>abaN! z;0Tub3e`gkFT>r3797Kf{0M$<1nquo`KEWZkqzCKi)dRw59rSfzS#Uu2`V7k=^=49 zLY#1&9???z!8Z-ex!o=Tu7y19f-LS$P$DgiTy}MiieOXo1hWU*Z=;QJOhv{;<;iUC zUt=qN@7{!JS3|>-@S&~D0j_X9XX^KZ(`WIIMMz7+W+xRKXg4CJVBCOE_Ms03ho^u2 z`i@yGI-Z^dV4Q?>enHl1ZfhfIJ`5t4W3*&`i!=M3;`5XT9q6pJHoVF_Dg4aR8TClJ zIK1k1j;B?HJEAhSR}GA@7GytoMc3`Au9?DnIVL;wN!wOtLgC!GOzjy7|FA`R*Zaw3 zj@|iaU-)L;>H)13{|KSbsX`Ba)B_U|(!g!%Sdm7w>QGMI2BfK)cNuwk?w$O1yo-BA z*Y8QK%QG=&eg+5yK~@Q{4!xq0U?`3TNIY4!m2r!TgRS|3hmtJ^Xci>_#qU3f&Ne)o5WGC0KQc4)Cc>lh>p}{2WI3;ECP0SP*+AIRMP(4bQyrkJw zxB`amv-Ow0a$${zvxsDokk*P6433RrKmFKPI6}D8HQ{`514XCfcUnQYq_Y6PdG(h) z7_s-1C#I_^Qwv7W1Pbc|`?1H6S! z8Y53W|6t|SH`Qw}cu2+*Bn7s#p0Xc{m zNrr(EU|PVg4s{nSS6R@9@>Bg^+r(@Yl+e&g7)cOE*55e^hM@4Goy}#4s0cmPhsP6D zU%ZzQBe(;+rN_$hY)$M_SmVvo!vX$~eZDoXG1AeoWLO7D0|k?HxrtrWB_pGBNIoO* zz@i>&10mMZ(ZP=dMbf!39aSE!UVQcpV0v+_SUesapuMKH_PNk*eXHTG zU*sz!b4z;PdC3`dggqM^w1Dl%#?@7eD6Tl_8qD)BB7pBqWB-ZnoCJz%5VTc^6_jL@ zbTyFwy3BTcYf}L+3NK3My0^(T#P`M`Xn^`WNTD3|o2#HzGi^QhkSjyXP%0FV zVNix!4z3``mJs^1PoBJGcyn5dkeHC@!I|QBPBt#eoj8#WbH#I7CagqhB#)u4g{1K( z%4h%OA@|8N<3iov#@Pn>Ef?UcA*Op!{13KEqIHZUQBu+&zc=^v*fTuT=83O50DB9O zN+q{~jCZKO3d8?2*n@YTA(R|B=Osr{wMBXoTExG}NLhm`TUc0dnV&RA;3R%V_`;CZ zl=aV{ zc+VH1hXv<8Qlgx`OVRAubu+%Az(6Kafa7QrJp>7r42L5g7QkA{*)qkP>y0+)RExBi z%V+~8P6hx5N|2YXu5P8$B+*t5zgI~1qt9weY=Mb^T_6PoO7#!HDTPxnQ(aAwXj2UG z4brk~T=g@sf{+gn3Qiz&gb3Hk^CLi^nfFQCj~2unlt;gM19n5RCn6&)JH94mrqw}` z3zRY`j_2DI2T*@JkB-(vJqw3F2sevbmocZj9l;97t+3aeoGQ=9<*jDs_MpF_jbZ`V z0xZL;Zxnf26+K2#Pf1!#qIcLzBsS&6*FD_(yWpzmYS0($E)%H+r~icjgcZl*8RBCh zP4NS~p3bzjq@s)fRCH(y`fvsR1Nz4Yy zoNWB@h3Qen>pzB*oax17i}YBD9U+b#oW*dBNSfvCeERp zxa8nA-0W9iqas8lAa#`Wy03pBA@2sOYZMh3DIy>SPJ|qR5FQm0YJknRhgpw|jy9vv z!V7^XG8Pz`xcx{uic%5$+n=`0zXnwC2?lRC!G{Gl3Q2)j5>q}^7)kbr->=H?rkAI^ z_kS^RYfoy=MmE}f=9n{NXWLji8=FqeDrZPlV8h8srJ2hP(l18F$F-51<16rU*uU;# zIci+r2Kf7fh!HXes$JAc7y;&lg z%CG5C(O8GrN6II(Iha!zXXd>uW`CoQ!{Sa{#${r6@Am*2QmnqyP)I>F)kHP8gP}ZN zi6Njg7GlTeF}J9x4M+>N9(ExJ(*Rg4g_hSSloqUbjj=Jf51-{WpH!G8$ZeZoMFHPI zD6yY7LVvp2Zj(8h-%hn7Xu}wWmXU*O!p*I%BWQ+bK{g@*7ut}};lpne6M56Am%%NO zj+wyKOKBWvC|}i}`vKSxm@E9L?2iu-HXbcCwLOn2%zlFoRGR3t zd+GDh`y^sf&4)vhFKXkAjZyHEvM?foKn}?D7dbj@*Zl5FA$zEQim`~IC9>(MWkf# zycB`gA_;99&GHKhgkDt8Z{6O@a{rp6V}ne1N_9e!20Td4axrstM)}!8sl+vX*ASi_ zC?t#mw?1*Qvn#Rf+#0L^ue423T08$@!?k9a?lFTj2iyo@!qS423Y0Y^`gm9p1rJt( z7}EJ!?tlK@+NVqcjDNgMrs#cysj8@bO=Z_A!mn?HuZXs99XM+liJ)K-!Y=n_v^>Born#f4Cwzroky#w)*N9BV% zs0AU}mp4!bjG$`?bG@@ad^iLI3ETIP*ftY6_%58y_gF1YVN`WQy}n=+fCgr(d z;5X@Jw_0B8M}9z9d6p%2#vH{a7+7QrLVY4Zi_W-+{+gYQYRmmUf`=Xqa~__ah+8#L zKj+3@`6CsQYLsikI7rOy?lhE@I2hM(ion>Bcy~^2a+|2otOxaYHxrk=z;;85+p7Xw zbT8KmSoT6<4!?8Q(yk=??6$ zyD1=YG79_4@AClBhpa(K+mdzq4rIso-V@c;)e*fVZnbs7$B##;N!=f!-#E&!9YagR z1NK6Cc!T0`EKd(2I=lmz8gSxhT`t;s!Awez&HCKDNnKc6Bo!C1BksphxK(;;>Mq|y_Vj+nwfF?TjquuO6H8q)m$+8j zTVNQdwJGN`Jj~!;j%lri_w1s_MeuNihUv&)ncdAdWVkcUO+<3#y$WHI%V9l<%%K{oyDRfI>6CV%RrO(cW8#UK-2__nrCnrTWUaT^$QWN{oZdLWO1|+OOqF|1(1)H}8Wve|(d?QpY}i;u;#lX-ge2VSPwRC+B1-=7;WD75?xTO-yhEqH zebqWUf8g}E*{|pXzrhKV z8h9=qjca6lkt0#v=iF303CA26f?)qc?pVj1uCTY8Bp1NPGt`nNM6q*~dWKQ|BELE1 z8CWQ)f2Z2yJdv&Bc0z$(); zgRTkg?0hnjfGhy2znwa>;^e@9T+FYuD2hX=l?9*NL{t3Fl*2}rJzZ(N9|#;zkiDznU6D#TYT z{v}ma@V+a~8H^}x*wBoy*L$wfaa`paH=VHv91xD803cuE@WeVcyc~uN8xZ9XI<4JJ zl~OP;L(|9Sg!1dvt7bO&V_qzN7(0{BWBmC4uS4#C9{PWJXUWe0f7dX)xYCia_D{R= z$=|Ja4A{PqpGQ0;173xBNk6l(Dw&V|F`67nUnyLFvuc&I6Z!w(H}e1L|M`Od>n$0) XuJ2w+HtG8_(N5{C>Y21t#<%|$+at?n literal 0 HcmV?d00001 diff --git a/docs/m2met2_cn/简介.md b/docs/m2met2_cn/简介.md index f43dbabec..5afb6a099 100644 --- a/docs/m2met2_cn/简介.md +++ b/docs/m2met2_cn/简介.md @@ -29,4 +29,4 @@ IASSP2022 M2MeT挑战的侧重点是会议场景,它包括两个赛道:说 [M2MET2.0报名](https://docs.google.com/forms/d/e/1FAIpQLSf77T9vAl7Ym-u5g8gXu18SBofoWRaFShBo26Ym0-HDxHW9PQ/viewform?usp=sf_link) -主办方将在3个工作日内通过电子邮件通知符合条件的参赛团队,团队必须遵守将在挑战网站上发布的挑战规则。在排名发布之前,每个参赛者必须提交一份系统描述文件,详细说明使用的方法和模型。主办方将选择前三名纳入ASRU2023论文集。 \ No newline at end of file +主办方将在3个工作日内通过电子邮件通知符合条件的参赛团队,团队必须遵守将在挑战网站上发布的挑战规则。在排名发布之前,每个参赛者必须提交一份系统描述文件,详细说明使用的方法和模型。主办方将排名前列的队伍纳入ASRU2023论文集。 \ No newline at end of file diff --git a/docs/m2met2_cn/联系方式.md b/docs/m2met2_cn/联系方式.md index 5c65ca01d..de43593fc 100644 --- a/docs/m2met2_cn/联系方式.md +++ b/docs/m2met2_cn/联系方式.md @@ -5,5 +5,5 @@ | M2MET2.0竞赛官方微信群 | |:------------------------------------------:| - +| | From c91430542e219463b12530145cc338d26ef7c358 Mon Sep 17 00:00:00 2001 From: "shixian.shi" Date: Thu, 4 May 2023 16:15:26 +0800 Subject: [PATCH 006/120] update --- .../finetune.py | 36 +++++++++++++++++++ .../infer_aishell1_subtest_demo.py | 5 +++ funasr/bin/asr_inference_paraformer.py | 3 +- .../models/e2e_asr_contextual_paraformer.py | 6 ++-- 4 files changed, 45 insertions(+), 5 deletions(-) create mode 100644 egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/finetune.py diff --git a/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/finetune.py b/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/finetune.py new file mode 100644 index 000000000..796cf3715 --- /dev/null +++ b/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/finetune.py @@ -0,0 +1,36 @@ +import os + +from modelscope.metainfo import Trainers +from modelscope.trainers import build_trainer + +from funasr.datasets.ms_dataset import MsDataset +from funasr.utils.modelscope_param import modelscope_args + + +def modelscope_finetune(params): + if not os.path.exists(params.output_dir): + os.makedirs(params.output_dir, exist_ok=True) + # dataset split ["train", "validation"] + ds_dict = MsDataset.load(params.data_path) + kwargs = dict( + model=params.model, + data_dir=ds_dict, + dataset_type=params.dataset_type, + work_dir=params.output_dir, + batch_bins=params.batch_bins, + max_epoch=params.max_epoch, + lr=params.lr) + trainer = build_trainer(Trainers.speech_asr_trainer, default_args=kwargs) + trainer.train() + + +if __name__ == '__main__': + params = modelscope_args(model="damo/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404", data_path="./data") + params.output_dir = "./checkpoint" # m模型保存路径 + params.data_path = "./example_data/" # 数据路径 + params.dataset_type = "small" # 小数据量设置small,若数据量大于1000小时,请使用large + params.batch_bins = 2000 # batch size,如果dataset_type="small",batch_bins单位为fbank特征帧数,如果dataset_type="large",batch_bins单位为毫秒, + params.max_epoch = 50 # 最大训练轮数 + params.lr = 0.00005 # 设置学习率 + + modelscope_finetune(params) diff --git a/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/infer_aishell1_subtest_demo.py b/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/infer_aishell1_subtest_demo.py index 18897b1a1..c3e18b43e 100644 --- a/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/infer_aishell1_subtest_demo.py +++ b/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/infer_aishell1_subtest_demo.py @@ -1,3 +1,4 @@ +from itertools import count import os import tempfile import codecs @@ -19,11 +20,15 @@ if __name__ == '__main__': os.makedirs(work_dir) wav_file_path = os.path.join(work_dir, "wav.scp") + counter = 0 with codecs.open(wav_file_path, 'w') as fin: for line in ds_dict: + counter += 1 wav = line["Audio:FILE"] idx = wav.split("/")[-1].split(".")[0] fin.writelines(idx + " " + wav + "\n") + if counter == 50: + break audio_in = wav_file_path inference_pipeline = pipeline( diff --git a/funasr/bin/asr_inference_paraformer.py b/funasr/bin/asr_inference_paraformer.py index 5546c92ae..5335860f4 100644 --- a/funasr/bin/asr_inference_paraformer.py +++ b/funasr/bin/asr_inference_paraformer.py @@ -41,6 +41,7 @@ from funasr.utils.types import str_or_none from funasr.utils import asr_utils, wav_utils, postprocess_utils from funasr.models.frontend.wav_frontend import WavFrontend from funasr.models.e2e_asr_paraformer import BiCifParaformer, ContextualParaformer +from funasr.models.e2e_asr_contextual_paraformer import NeatContextualParaformer from funasr.export.models.e2e_asr_paraformer import Paraformer as Paraformer_export from funasr.utils.timestamp_tools import ts_prediction_lfr6_standard from funasr.bin.tp_inference import SpeechText2Timestamp @@ -236,7 +237,7 @@ class Speech2Text: pre_token_length = pre_token_length.round().long() if torch.max(pre_token_length) < 1: return [] - if not isinstance(self.asr_model, ContextualParaformer): + if not isinstance(self.asr_model, ContextualParaformer) and not isinstance(self.asr_model, NeatContextualParaformer): if self.hotword_list: logging.warning("Hotword is given but asr model is not a ContextualParaformer.") decoder_outs = self.asr_model.cal_decoder_with_predictor(enc, enc_len, pre_acoustic_embeds, pre_token_length) diff --git a/funasr/models/e2e_asr_contextual_paraformer.py b/funasr/models/e2e_asr_contextual_paraformer.py index e1dfe6cf0..93027ec2a 100644 --- a/funasr/models/e2e_asr_contextual_paraformer.py +++ b/funasr/models/e2e_asr_contextual_paraformer.py @@ -68,7 +68,7 @@ class NeatContextualParaformer(Paraformer): target_buffer_length: int = -1, inner_dim: int = 256, bias_encoder_type: str = 'lstm', - use_decoder_embedding: bool = True, + use_decoder_embedding: bool = False, crit_attn_weight: float = 0.0, crit_attn_smooth: float = 0.0, bias_encoder_dropout_rate: float = 0.0, @@ -340,7 +340,7 @@ class NeatContextualParaformer(Paraformer): input_mask_expand_dim, 0) return sematic_embeds * tgt_mask, decoder_out * tgt_mask - def cal_decoder_with_predictor_with_hwlist_advanced(self, encoder_out, encoder_out_lens, sematic_embeds, ys_pad_lens, hw_list=None): + def cal_decoder_with_predictor(self, encoder_out, encoder_out_lens, sematic_embeds, ys_pad_lens, hw_list=None): if hw_list is None: hw_list = [torch.Tensor([1]).long().to(encoder_out.device)] # empty hotword list hw_list_pad = pad_list(hw_list, 0) @@ -350,7 +350,6 @@ class NeatContextualParaformer(Paraformer): hw_embed = self.bias_embed(hw_list_pad) hw_embed, (h_n, _) = self.bias_encoder(hw_embed) else: - # hw_list = hw_list[1:] + [hw_list[0]] # reorder hw_lengths = [len(i) for i in hw_list] hw_list_pad = pad_list([torch.Tensor(i).long() for i in hw_list], 0).to(encoder_out.device) if self.use_decoder_embedding: @@ -366,7 +365,6 @@ class NeatContextualParaformer(Paraformer): if _h_n is not None: h_n = _h_n hw_embed = h_n.repeat(encoder_out.shape[0], 1, 1) - # import pdb; pdb.set_trace() decoder_outs = self.decoder( encoder_out, encoder_out_lens, sematic_embeds, ys_pad_lens, contextual_info=hw_embed From 297fafd674715bcd849557616bd22b6791460f31 Mon Sep 17 00:00:00 2001 From: "haoneng.lhn" Date: Thu, 4 May 2023 16:40:34 +0800 Subject: [PATCH 007/120] update streaming paraformer text process --- funasr/bin/asr_inference_paraformer_streaming.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/funasr/bin/asr_inference_paraformer_streaming.py b/funasr/bin/asr_inference_paraformer_streaming.py index bf5590c9b..341abe670 100644 --- a/funasr/bin/asr_inference_paraformer_streaming.py +++ b/funasr/bin/asr_inference_paraformer_streaming.py @@ -239,7 +239,7 @@ class Speech2Text: feats_len = torch.tensor([feats_chunk2.shape[1]]) results_chunk2 = self.infer(feats_chunk2, feats_len, cache) - return ["".join(results_chunk1 + results_chunk2)] + return [" ".join(results_chunk1 + results_chunk2)] results = self.infer(feats, feats_len, cache) @@ -299,12 +299,13 @@ class Speech2Text: # Change integer-ids to tokens token = self.converter.ids2tokens(token_int) + token = " ".join(token) - if self.tokenizer is not None: - text = self.tokenizer.tokens2text(token) - else: - text = None - results.append(text) + #if self.tokenizer is not None: + # text = self.tokenizer.tokens2text(token) + #else: + # text = None + results.append(token) # assert check_return_type(results) return results From 00275d207832564a24c2e1d5b1ec1a0fce70b7ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BB=B4=E7=9F=B3?= Date: Thu, 4 May 2023 16:44:56 +0800 Subject: [PATCH 008/120] update --- .../finetune.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/finetune.py b/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/finetune.py index 796cf3715..676c943af 100644 --- a/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/finetune.py +++ b/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/finetune.py @@ -3,6 +3,7 @@ import os from modelscope.metainfo import Trainers from modelscope.trainers import build_trainer +import funasr from funasr.datasets.ms_dataset import MsDataset from funasr.utils.modelscope_param import modelscope_args @@ -28,7 +29,7 @@ if __name__ == '__main__': params = modelscope_args(model="damo/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404", data_path="./data") params.output_dir = "./checkpoint" # m模型保存路径 params.data_path = "./example_data/" # 数据路径 - params.dataset_type = "small" # 小数据量设置small,若数据量大于1000小时,请使用large + params.dataset_type = "large" # 小数据量设置small,若数据量大于1000小时,请使用large params.batch_bins = 2000 # batch size,如果dataset_type="small",batch_bins单位为fbank特征帧数,如果dataset_type="large",batch_bins单位为毫秒, params.max_epoch = 50 # 最大训练轮数 params.lr = 0.00005 # 设置学习率 From 4bbc661aa58798dbb9df7b7b548704bc5c619590 Mon Sep 17 00:00:00 2001 From: "shixian.shi" Date: Thu, 4 May 2023 17:24:15 +0800 Subject: [PATCH 009/120] update --- funasr/datasets/large_datasets/dataset.py | 3 ++- funasr/datasets/large_datasets/utils/tokenize.py | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/funasr/datasets/large_datasets/dataset.py b/funasr/datasets/large_datasets/dataset.py index db770f596..53994cbd2 100644 --- a/funasr/datasets/large_datasets/dataset.py +++ b/funasr/datasets/large_datasets/dataset.py @@ -181,7 +181,8 @@ def Dataset(data_list_file, hw_config = {"sample_rate": conf.get("sample_rate", 0.6), "double_rate": conf.get("double_rate", 0.1), "hotword_min_length": conf.get("hotword_min_length", 2), - "hotword_max_length": conf.get("hotword_max_length", 8)} + "hotword_max_length": conf.get("hotword_max_length", 8), + "pre_prob": conf.get("pre_prob", 0.0)} if pre_hwfile is not None: pre_hwlist = [] diff --git a/funasr/datasets/large_datasets/utils/tokenize.py b/funasr/datasets/large_datasets/utils/tokenize.py index 09ece76d1..f8833b1a1 100644 --- a/funasr/datasets/large_datasets/utils/tokenize.py +++ b/funasr/datasets/large_datasets/utils/tokenize.py @@ -58,6 +58,7 @@ def tokenize(data, if 'hw_tag' in data: hotword_indxs = sample_hotword(length, **hw_config) data[hotword_indxs] = hotword_indxs + del data['hw_tag'] for i in range(length): x = text[i] if i == length-1 and "punc" in data and x.startswith("vad:"): From ca4aac692b9d1ab2b923adc7952b868b306b37d2 Mon Sep 17 00:00:00 2001 From: "shixian.shi" Date: Thu, 4 May 2023 19:02:47 +0800 Subject: [PATCH 010/120] update --- funasr/bin/build_trainer.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/funasr/bin/build_trainer.py b/funasr/bin/build_trainer.py index 94f72627e..5c30fdb6f 100644 --- a/funasr/bin/build_trainer.py +++ b/funasr/bin/build_trainer.py @@ -83,7 +83,8 @@ def build_trainer(modelscope_dict, finetune_configs = yaml.safe_load(f) # set data_types if dataset_type == "large": - finetune_configs["dataset_conf"]["data_types"] = "sound,text" + if 'data_types' not in finetune_configs['dataset_conf']: + finetune_configs["dataset_conf"]["data_types"] = "sound,text" finetune_configs = update_dct(configs, finetune_configs) for key, value in finetune_configs.items(): if hasattr(args, key): From 472c0f9265c6a313b342341b3e0ca930c55206c7 Mon Sep 17 00:00:00 2001 From: "shixian.shi" Date: Thu, 4 May 2023 19:06:30 +0800 Subject: [PATCH 011/120] update --- funasr/datasets/large_datasets/dataset.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/funasr/datasets/large_datasets/dataset.py b/funasr/datasets/large_datasets/dataset.py index 53994cbd2..8c224d87d 100644 --- a/funasr/datasets/large_datasets/dataset.py +++ b/funasr/datasets/large_datasets/dataset.py @@ -101,7 +101,7 @@ class AudioDataset(IterableDataset): if data_type == "kaldi_ark": ark_reader = ReadHelper('ark:{}'.format(data_file)) reader_list.append(ark_reader) - elif data_type == "text" or data_type == "sound": + elif data_type == "text" or data_type == "sound" or data_type == 'text_hotword': text_reader = open(data_file, "r") reader_list.append(text_reader) elif data_type == "none": From 1187f5937e6d86df4107fadcbc9f9340039e231a Mon Sep 17 00:00:00 2001 From: "shixian.shi" Date: Thu, 4 May 2023 19:10:28 +0800 Subject: [PATCH 012/120] update --- funasr/datasets/large_datasets/utils/tokenize.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/funasr/datasets/large_datasets/utils/tokenize.py b/funasr/datasets/large_datasets/utils/tokenize.py index f8833b1a1..f0f0c66d9 100644 --- a/funasr/datasets/large_datasets/utils/tokenize.py +++ b/funasr/datasets/large_datasets/utils/tokenize.py @@ -57,7 +57,7 @@ def tokenize(data, length = len(text) if 'hw_tag' in data: hotword_indxs = sample_hotword(length, **hw_config) - data[hotword_indxs] = hotword_indxs + data['hotword_indxs'] = hotword_indxs del data['hw_tag'] for i in range(length): x = text[i] From 23b327cadae391f3aaf1886a7a2ff505a9e6c3b3 Mon Sep 17 00:00:00 2001 From: "shixian.shi" Date: Thu, 4 May 2023 19:17:08 +0800 Subject: [PATCH 013/120] update --- funasr/datasets/large_datasets/utils/padding.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/funasr/datasets/large_datasets/utils/padding.py b/funasr/datasets/large_datasets/utils/padding.py index fdca63d7b..b31748280 100644 --- a/funasr/datasets/large_datasets/utils/padding.py +++ b/funasr/datasets/large_datasets/utils/padding.py @@ -13,7 +13,7 @@ def padding(data, float_pad_value=0.0, int_pad_value=-1): batch = {} data_names = data[0].keys() for data_name in data_names: - if data_name == "key" or data_name =="sampling_rate": + if data_name == "key" or data_name == "sampling_rate" or data_name == 'hotword_indxs': continue else: if data[0][data_name].dtype.kind == "i": From 8cac1c97d92a0cbfaf9862930404ede92150beeb Mon Sep 17 00:00:00 2001 From: "shixian.shi" Date: Thu, 4 May 2023 19:22:56 +0800 Subject: [PATCH 014/120] update --- funasr/datasets/large_datasets/utils/padding.py | 1 + 1 file changed, 1 insertion(+) diff --git a/funasr/datasets/large_datasets/utils/padding.py b/funasr/datasets/large_datasets/utils/padding.py index b31748280..7c6660825 100644 --- a/funasr/datasets/large_datasets/utils/padding.py +++ b/funasr/datasets/large_datasets/utils/padding.py @@ -14,6 +14,7 @@ def padding(data, float_pad_value=0.0, int_pad_value=-1): data_names = data[0].keys() for data_name in data_names: if data_name == "key" or data_name == "sampling_rate" or data_name == 'hotword_indxs': + batch[data_name] = data[0][data_name] continue else: if data[0][data_name].dtype.kind == "i": From 1988fe85f6d4e2d2f809e705e13d69d0b57bd0fc Mon Sep 17 00:00:00 2001 From: "shixian.shi" Date: Thu, 4 May 2023 19:27:00 +0800 Subject: [PATCH 015/120] update --- funasr/datasets/large_datasets/utils/padding.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/funasr/datasets/large_datasets/utils/padding.py b/funasr/datasets/large_datasets/utils/padding.py index 7c6660825..20ba7a38f 100644 --- a/funasr/datasets/large_datasets/utils/padding.py +++ b/funasr/datasets/large_datasets/utils/padding.py @@ -13,16 +13,16 @@ def padding(data, float_pad_value=0.0, int_pad_value=-1): batch = {} data_names = data[0].keys() for data_name in data_names: - if data_name == "key" or data_name == "sampling_rate" or data_name == 'hotword_indxs': - batch[data_name] = data[0][data_name] + if data_name == "key" or data_name == "sampling_rate": continue else: - if data[0][data_name].dtype.kind == "i": - pad_value = int_pad_value - tensor_type = torch.int64 - else: - pad_value = float_pad_value - tensor_type = torch.float32 + if data_name != 'hotword_indxs': + if data[0][data_name].dtype.kind == "i": + pad_value = int_pad_value + tensor_type = torch.int64 + else: + pad_value = float_pad_value + tensor_type = torch.float32 tensor_list = [torch.tensor(np.copy(d[data_name]), dtype=tensor_type) for d in data] tensor_lengths = torch.tensor([len(d[data_name]) for d in data], dtype=torch.int32) From c238436e07e844dff455a21b707111590518b220 Mon Sep 17 00:00:00 2001 From: "shixian.shi" Date: Thu, 4 May 2023 19:31:19 +0800 Subject: [PATCH 016/120] update --- funasr/models/e2e_asr_contextual_paraformer.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/funasr/models/e2e_asr_contextual_paraformer.py b/funasr/models/e2e_asr_contextual_paraformer.py index 93027ec2a..493b34545 100644 --- a/funasr/models/e2e_asr_contextual_paraformer.py +++ b/funasr/models/e2e_asr_contextual_paraformer.py @@ -278,9 +278,10 @@ class NeatContextualParaformer(Paraformer): # 1. Forward decoder decoder_outs = self.decoder( - encoder_out, encoder_out_lens, sematic_embeds, ys_pad_lens, contextual_info=contextual_info, ret_attn=(ideal_attn is not None) + encoder_out, encoder_out_lens, sematic_embeds, ys_pad_lens, contextual_info=contextual_info ) decoder_out, _, attn = decoder_outs[0], decoder_outs[1], decoder_outs[2] + if self.crit_attn_weight > 0 and attn.shape[-1] > 1: ideal_attn = ideal_attn + self.crit_attn_smooth / (self.crit_attn_smooth + 1.0) attn_non_blank = attn[:,:,:,:-1] From a6889a31700bf3d610712c7fb5edecd06f78f0bf Mon Sep 17 00:00:00 2001 From: "shixian.shi" Date: Thu, 4 May 2023 19:33:50 +0800 Subject: [PATCH 017/120] update --- funasr/models/e2e_asr_contextual_paraformer.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/funasr/models/e2e_asr_contextual_paraformer.py b/funasr/models/e2e_asr_contextual_paraformer.py index 493b34545..aced11edd 100644 --- a/funasr/models/e2e_asr_contextual_paraformer.py +++ b/funasr/models/e2e_asr_contextual_paraformer.py @@ -280,8 +280,8 @@ class NeatContextualParaformer(Paraformer): decoder_outs = self.decoder( encoder_out, encoder_out_lens, sematic_embeds, ys_pad_lens, contextual_info=contextual_info ) - decoder_out, _, attn = decoder_outs[0], decoder_outs[1], decoder_outs[2] - + decoder_out, _ = decoder_outs[0], decoder_outs[1] + ''' if self.crit_attn_weight > 0 and attn.shape[-1] > 1: ideal_attn = ideal_attn + self.crit_attn_smooth / (self.crit_attn_smooth + 1.0) attn_non_blank = attn[:,:,:,:-1] @@ -289,7 +289,9 @@ class NeatContextualParaformer(Paraformer): loss_ideal = self.attn_loss(attn_non_blank.max(1)[0], ideal_attn_non_blank.to(attn.device)) else: loss_ideal = None - + ''' + loss_ideal = None + if decoder_out_1st is None: decoder_out_1st = decoder_out # 2. Compute attention loss From bc57005507aad83ed7c092e3a3ea8e994451d105 Mon Sep 17 00:00:00 2001 From: "shixian.shi" Date: Thu, 4 May 2023 19:36:23 +0800 Subject: [PATCH 018/120] update --- funasr/bin/build_trainer.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/funasr/bin/build_trainer.py b/funasr/bin/build_trainer.py index 5c30fdb6f..df921fabd 100644 --- a/funasr/bin/build_trainer.py +++ b/funasr/bin/build_trainer.py @@ -132,7 +132,8 @@ def build_trainer(modelscope_dict, if args.dataset_type == "small": args.batch_bins = batch_bins elif args.dataset_type == "large": - args.dataset_conf["batch_conf"]["batch_size"] = batch_bins + # args.dataset_conf["batch_conf"]["batch_size"] = batch_bins + pass else: raise ValueError(f"Not supported dataset_type={args.dataset_type}") if args.normalize in ["null", "none", "None"]: From 6482fb94a5f84f98967d3274792772b0a0ab87a2 Mon Sep 17 00:00:00 2001 From: "shixian.shi" Date: Thu, 4 May 2023 19:41:53 +0800 Subject: [PATCH 019/120] update --- funasr/bin/build_trainer.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/funasr/bin/build_trainer.py b/funasr/bin/build_trainer.py index df921fabd..cfe65a180 100644 --- a/funasr/bin/build_trainer.py +++ b/funasr/bin/build_trainer.py @@ -131,9 +131,8 @@ def build_trainer(modelscope_dict, if batch_bins is not None: if args.dataset_type == "small": args.batch_bins = batch_bins - elif args.dataset_type == "large": - # args.dataset_conf["batch_conf"]["batch_size"] = batch_bins - pass + elif args.dataset_type == "large" and "batch_size" not in args.dataset_conf["batch_conf"]: + args.dataset_conf["batch_conf"]["batch_size"] = batch_bins else: raise ValueError(f"Not supported dataset_type={args.dataset_type}") if args.normalize in ["null", "none", "None"]: From 86f5e64b9ade696c83d78dfae9f46228d678b00e Mon Sep 17 00:00:00 2001 From: "shixian.shi" Date: Thu, 4 May 2023 19:43:45 +0800 Subject: [PATCH 020/120] update --- funasr/bin/build_trainer.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/funasr/bin/build_trainer.py b/funasr/bin/build_trainer.py index cfe65a180..6bd5bd715 100644 --- a/funasr/bin/build_trainer.py +++ b/funasr/bin/build_trainer.py @@ -131,8 +131,9 @@ def build_trainer(modelscope_dict, if batch_bins is not None: if args.dataset_type == "small": args.batch_bins = batch_bins - elif args.dataset_type == "large" and "batch_size" not in args.dataset_conf["batch_conf"]: - args.dataset_conf["batch_conf"]["batch_size"] = batch_bins + elif args.dataset_type == "large": + if "batch_size" not in args.dataset_conf["batch_conf"]: + args.dataset_conf["batch_conf"]["batch_size"] = batch_bins else: raise ValueError(f"Not supported dataset_type={args.dataset_type}") if args.normalize in ["null", "none", "None"]: From 8d169f9cd98f4b2a4917e0ced2638856e3410277 Mon Sep 17 00:00:00 2001 From: "shixian.shi" Date: Thu, 4 May 2023 19:46:12 +0800 Subject: [PATCH 021/120] update --- funasr/torch_utils/load_pretrained_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/funasr/torch_utils/load_pretrained_model.py b/funasr/torch_utils/load_pretrained_model.py index e9b18cd0d..b54f7771f 100644 --- a/funasr/torch_utils/load_pretrained_model.py +++ b/funasr/torch_utils/load_pretrained_model.py @@ -120,6 +120,6 @@ def load_pretrained_model( if ignore_init_mismatch: src_state = filter_state_dict(dst_state, src_state) - logging.info("Loaded src_state keys: {}".format(src_state.keys())) + # logging.info("Loaded src_state keys: {}".format(src_state.keys())) dst_state.update(src_state) obj.load_state_dict(dst_state) From 7987a7b6fade65a7fd2a70b661c3818862a21965 Mon Sep 17 00:00:00 2001 From: "haoneng.lhn" Date: Fri, 5 May 2023 11:36:26 +0800 Subject: [PATCH 022/120] update streaming paraformer text process --- .../bin/asr_inference_paraformer_streaming.py | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/funasr/bin/asr_inference_paraformer_streaming.py b/funasr/bin/asr_inference_paraformer_streaming.py index 341abe670..be0d752a1 100644 --- a/funasr/bin/asr_inference_paraformer_streaming.py +++ b/funasr/bin/asr_inference_paraformer_streaming.py @@ -301,10 +301,6 @@ class Speech2Text: token = self.converter.ids2tokens(token_int) token = " ".join(token) - #if self.tokenizer is not None: - # text = self.tokenizer.tokens2text(token) - #else: - # text = None results.append(token) # assert check_return_type(results) @@ -556,8 +552,8 @@ def inference_modelscope( input_lens = torch.tensor([stride_size]) asr_result = speech2text(cache, raw_inputs[:, sample_offset: sample_offset + stride_size], input_lens) if len(asr_result) != 0: - final_result += asr_result[0] - item = {'key': "utt", 'value': [final_result]} + final_result += " ".join(asr_result) + " " + item = {'key': "utt", 'value': [final_result.strip()]} else: input_lens = torch.tensor([raw_inputs.shape[1]]) cache["encoder"]["is_final"] = is_final @@ -751,12 +747,3 @@ def main(cmd=None): if __name__ == "__main__": main() - # from modelscope.pipelines import pipeline - # from modelscope.utils.constant import Tasks - # - # inference_16k_pipline = pipeline( - # task=Tasks.auto_speech_recognition, - # model='damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch') - # - # rec_result = inference_16k_pipline(audio_in='https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_example_zh.wav') - # print(rec_result) From 19a2b9f38ec82d37011aa086cf6cee0e516dd747 Mon Sep 17 00:00:00 2001 From: "haoneng.lhn" Date: Fri, 5 May 2023 11:44:14 +0800 Subject: [PATCH 023/120] update streaming paraformer text process --- .../infer.py | 2 +- .../infer.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online/infer.py b/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online/infer.py index 4fd4cdf9c..808084fd5 100644 --- a/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online/infer.py +++ b/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online/infer.py @@ -34,6 +34,6 @@ for sample_offset in range(0, speech_length, min(stride_size, speech_length - sa rec_result = inference_pipeline(audio_in=speech[sample_offset: sample_offset + stride_size], param_dict=param_dict) if len(rec_result) != 0: - final_result += rec_result['text'][0] + final_result += " ".join(rec_result['text']) + " " print(rec_result) print(final_result) diff --git a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-common-vocab8404-online/infer.py b/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-common-vocab8404-online/infer.py index 0066c7b6f..0ecf1ab39 100644 --- a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-common-vocab8404-online/infer.py +++ b/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-common-vocab8404-online/infer.py @@ -34,6 +34,6 @@ for sample_offset in range(0, speech_length, min(stride_size, speech_length - sa rec_result = inference_pipeline(audio_in=speech[sample_offset: sample_offset + stride_size], param_dict=param_dict) if len(rec_result) != 0: - final_result += rec_result['text'][0] + final_result += " ".join(rec_result['text']) + " " print(rec_result) -print(final_result) +print(final_result.strip()) From 7558409170e10b0169b63a07e5d068eb61f543f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BB=B4=E7=9F=B3?= Date: Fri, 5 May 2023 11:48:26 +0800 Subject: [PATCH 024/120] update contextual finetune --- .../README.md | 2 +- .../infer.sh | 106 +++++++++++++++++- 2 files changed, 106 insertions(+), 2 deletions(-) mode change 120000 => 100644 egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/infer.sh diff --git a/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/README.md b/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/README.md index 92088a21d..bb55ab52e 120000 --- a/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/README.md +++ b/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/README.md @@ -1 +1 @@ -../TEMPLATE/README.md \ No newline at end of file +../../TEMPLATE/README.md \ No newline at end of file diff --git a/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/infer.sh b/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/infer.sh deleted file mode 120000 index 0b3b38b6f..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/infer.sh +++ /dev/null @@ -1 +0,0 @@ -../TEMPLATE/infer.sh \ No newline at end of file diff --git a/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/infer.sh b/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/infer.sh new file mode 100644 index 000000000..632562670 --- /dev/null +++ b/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/infer.sh @@ -0,0 +1,105 @@ +#!/usr/bin/env bash + +set -e +set -u +set -o pipefail + +stage=1 +stop_stage=2 +model="damo/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404" +data_dir="./data/test" +output_dir="./results" +batch_size=64 +gpu_inference=true # whether to perform gpu decoding +gpuid_list="0,1" # set gpus, e.g., gpuid_list="0,1" +njob=10 # the number of jobs for CPU decoding, if gpu_inference=false, use CPU decoding, please set njob +checkpoint_dir= +checkpoint_name="valid.cer_ctc.ave.pb" +hotword_txt=None + +. utils/parse_options.sh || exit 1; + +if ${gpu_inference} == "true"; then + nj=$(echo $gpuid_list | awk -F "," '{print NF}') +else + nj=$njob + batch_size=1 + gpuid_list="" + for JOB in $(seq ${nj}); do + gpuid_list=$gpuid_list"-1," + done +fi + +mkdir -p $output_dir/split +split_scps="" +for JOB in $(seq ${nj}); do + split_scps="$split_scps $output_dir/split/wav.$JOB.scp" +done +perl utils/split_scp.pl ${data_dir}/wav.scp ${split_scps} + +if [ -n "${checkpoint_dir}" ]; then + python utils/prepare_checkpoint.py ${model} ${checkpoint_dir} ${checkpoint_name} + model=${checkpoint_dir}/${model} +fi + +if [ $stage -le 1 ] && [ $stop_stage -ge 1 ];then + echo "Decoding ..." + gpuid_list_array=(${gpuid_list//,/ }) + for JOB in $(seq ${nj}); do + { + id=$((JOB-1)) + gpuid=${gpuid_list_array[$id]} + mkdir -p ${output_dir}/output.$JOB + python infer.py \ + --model ${model} \ + --audio_in ${output_dir}/split/wav.$JOB.scp \ + --output_dir ${output_dir}/output.$JOB \ + --batch_size ${batch_size} \ + --hotword_txt ${hotword_txt} \ + --gpuid ${gpuid} + }& + done + wait + + mkdir -p ${output_dir}/1best_recog + for f in token score text; do + if [ -f "${output_dir}/output.1/1best_recog/${f}" ]; then + for i in $(seq "${nj}"); do + cat "${output_dir}/output.${i}/1best_recog/${f}" + done | sort -k1 >"${output_dir}/1best_recog/${f}" + fi + done +fi + +if [ $stage -le 2 ] && [ $stop_stage -ge 2 ];then + echo "Computing WER ..." + cp ${output_dir}/1best_recog/text ${output_dir}/1best_recog/text.proc + cp ${data_dir}/text ${output_dir}/1best_recog/text.ref + python utils/compute_wer.py ${output_dir}/1best_recog/text.ref ${output_dir}/1best_recog/text.proc ${output_dir}/1best_recog/text.cer + tail -n 3 ${output_dir}/1best_recog/text.cer +fi + +if [ $stage -le 3 ] && [ $stop_stage -ge 3 ];then + echo "SpeechIO TIOBE textnorm" + echo "$0 --> Normalizing REF text ..." + ./utils/textnorm_zh.py \ + --has_key --to_upper \ + ${data_dir}/text \ + ${output_dir}/1best_recog/ref.txt + + echo "$0 --> Normalizing HYP text ..." + ./utils/textnorm_zh.py \ + --has_key --to_upper \ + ${output_dir}/1best_recog/text.proc \ + ${output_dir}/1best_recog/rec.txt + grep -v $'\t$' ${output_dir}/1best_recog/rec.txt > ${output_dir}/1best_recog/rec_non_empty.txt + + echo "$0 --> computing WER/CER and alignment ..." + ./utils/error_rate_zh \ + --tokenizer char \ + --ref ${output_dir}/1best_recog/ref.txt \ + --hyp ${output_dir}/1best_recog/rec_non_empty.txt \ + ${output_dir}/1best_recog/DETAILS.txt | tee ${output_dir}/1best_recog/RESULTS.txt + rm -rf ${output_dir}/1best_recog/rec.txt ${output_dir}/1best_recog/rec_non_empty.txt +fi + From e1d535e697279e3e80f15888141ebf3ec0b9179c Mon Sep 17 00:00:00 2001 From: "shixian.shi" Date: Fri, 5 May 2023 11:53:39 +0800 Subject: [PATCH 025/120] update neat contextual paraformer --- .../models/e2e_asr_contextual_paraformer.py | 27 +------------------ 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/funasr/models/e2e_asr_contextual_paraformer.py b/funasr/models/e2e_asr_contextual_paraformer.py index aced11edd..dc820dbbb 100644 --- a/funasr/models/e2e_asr_contextual_paraformer.py +++ b/funasr/models/e2e_asr_contextual_paraformer.py @@ -291,7 +291,7 @@ class NeatContextualParaformer(Paraformer): loss_ideal = None ''' loss_ideal = None - + if decoder_out_1st is None: decoder_out_1st = decoder_out # 2. Compute attention loss @@ -362,11 +362,6 @@ class NeatContextualParaformer(Paraformer): hw_embed = torch.nn.utils.rnn.pack_padded_sequence(hw_embed, hw_lengths, batch_first=True, enforce_sorted=False) _, (h_n, _) = self.bias_encoder(hw_embed) - # hw_embed, _ = torch.nn.utils.rnn.pad_packed_sequence(hw_embed, batch_first=True) - if h_n.shape[1] > 2000: # large hotword list - _h_n = self.pick_hwlist_group(h_n.squeeze(0), encoder_out, encoder_out_lens, sematic_embeds, ys_pad_lens) - if _h_n is not None: - h_n = _h_n hw_embed = h_n.repeat(encoder_out.shape[0], 1, 1) decoder_outs = self.decoder( @@ -375,23 +370,3 @@ class NeatContextualParaformer(Paraformer): decoder_out = decoder_outs[0] decoder_out = torch.log_softmax(decoder_out, dim=-1) return decoder_out, ys_pad_lens - - def pick_hwlist_group(self, hw_embed, encoder_out, encoder_out_lens, sematic_embeds, ys_pad_lens): - max_attn_score = 0.0 - # max_attn_index = 0 - argmax_g = None - non_blank = hw_embed[-1] - hw_embed_groups = hw_embed[:-1].split(2000) - for i, g in enumerate(hw_embed_groups): - g = torch.cat([g, non_blank.unsqueeze(0)], dim=0) - _ = self.decoder( - encoder_out, encoder_out_lens, sematic_embeds, ys_pad_lens, contextual_info=g.unsqueeze(0) - ) - attn = self.decoder.bias_decoder.src_attn.attn[0] - _max_attn_score = attn.max(0)[0][:,:-1].max() - if _max_attn_score > max_attn_score: - max_attn_score = _max_attn_score - # max_attn_index = i - argmax_g = g - # import pdb; pdb.set_trace() - return argmax_g \ No newline at end of file From e6d8d9d6d3948969c7ba2489ab06114c45b2a7ec Mon Sep 17 00:00:00 2001 From: zhuzizyf <42790740+zhuzizyf@users.noreply.github.com> Date: Fri, 5 May 2023 12:48:27 +0800 Subject: [PATCH 026/120] Update e2e-vad.h Removing unused code. --- funasr/runtime/onnxruntime/src/e2e-vad.h | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/funasr/runtime/onnxruntime/src/e2e-vad.h b/funasr/runtime/onnxruntime/src/e2e-vad.h index 02bae6296..0e0b50feb 100644 --- a/funasr/runtime/onnxruntime/src/e2e-vad.h +++ b/funasr/runtime/onnxruntime/src/e2e-vad.h @@ -492,7 +492,7 @@ private: if (cur_seg.end_ms != start_frm * vad_opts.frame_in_ms) { std::cout << "warning\n"; } - int out_pos = (int) cur_seg.buffer.size(); + int data_to_pop; if (end_point_is_sent_end) { data_to_pop = expected_sample_number; @@ -505,14 +505,7 @@ private: expected_sample_number = data_buf_size; } cur_seg.doa = 0; - for (int sample_cpy_out = 0; sample_cpy_out < data_to_pop; sample_cpy_out++) { - cur_seg.buffer.push_back(data_buf.back()); - out_pos++; - } - for (int sample_cpy_out = data_to_pop; sample_cpy_out < expected_sample_number; sample_cpy_out++) { - cur_seg.buffer.push_back(data_buf.back()); - out_pos++; - } + if (cur_seg.end_ms != start_frm * vad_opts.frame_in_ms) { std::cout << "Something wrong with the VAD algorithm\n"; } From 14a3da36432a89be094757677e6e7dc093fdf359 Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Mon, 27 Mar 2023 17:23:34 +0800 Subject: [PATCH 027/120] Update postprocess_utils.py add Burmese characters --- funasr/utils/postprocess_utils.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/funasr/utils/postprocess_utils.py b/funasr/utils/postprocess_utils.py index b607e1da0..e3d8d6b47 100644 --- a/funasr/utils/postprocess_utils.py +++ b/funasr/utils/postprocess_utils.py @@ -51,6 +51,26 @@ def isAllAlpha(word: Union[List[Any], str]): return True +def isMy(word: Union[List[Any], str]): + my_char = ['စေ', 'ကို', 'ဖြစ်', 'ဌ', 'ေါ', 'ရင်း', 'w', 'ပုံ', 'ပတ်', 'လာ', 'စီး', 'ဘက်', 'က်', 'ုံ', 'ဏာ', 'ဖော်', 'အတွင်း', 'r', '၀', 'တို', 'ပြန်', 'ီး', 'h', 'ဖြ', 'က္ခ', 'မ္', 'အထိ', 'ဆွ', 'ပေး', 'တူ', '၈', 'မ်း', 'ဠ', 'ထို', 'စွ', 'ထားသည်', 'အခြေ', 'စာ', 'တို့သည်', 'အက', 'ရဲ့', 'ွ', 'င', 'o', 'ုတ်', 'လွ', 'ပင်', 'နိုင်ငံ', 'ပါတယ်', 'ကား', 'အဖွဲ့', 'အခြား', 'ယ့်', 'ပို', 'ည်း', 'ယာ', 'ဆုံး', '၄', 'ကြောင်း', 'တပ်', 'အနေ', 'ဣ', '၏', 'ိုး', 'ချုပ်', 'နေ', 'စ', 'ဟ', 'လွှ', 'အဆ', '၌', 'ဣ', 'နိုင်', 'တည်', 'တွ', 'အချိန်', 'ပဲ', 'ဝင်', 'ဒီ', 'သူ', 'l', 'ဏ', 'ဲ့', 'အထ', 'ပည', 'စိတ်', 'ကြသည်', 'ဩ', 's', 't', 'သေ', 'လျ', 'ိုက်', 'များသည်', 'ငါ', 'ို', 'ထဲ', 'လာ', 'ဝန်', 'ဓ', 'ခဲ့', 'စွာ', 'မ', 'နှင့်', '၎', 'အစိုး', 'ရာ', '၉', 'တယ်', '၎င်း', '၅', 'ပညာ', 'ကြီး', 'သို့မဟုတ်', '၍', 'ို', 'မူ', 'f', 'ခု', 'ိမ', 'c', 'ုပ်', 'l', 'အမ', 'နောက်', 'သော', 'ုန်း', 'ှ', 'ကြ', 'တ', 'ဌာ', 'p', 'ပေါ်', 'h', 'ပင်', 'ဲ', 'ဒီ', 'ဈ', 'လက္ခ', 'r', 'ပြ', 'ဒေ', 'မှ', 'ရှ', 'လျှ', 'လေ့', 'ရောဂါ', 'ော်', 'လည်', 'ဖွဲ့', 'မ်', 'သိ', 'ထုတ်', 'ရိ', 'အား', 'ာ', 'လ', 'ုပ', 'ကျော်', 'အေ', 'g', 'နာ', 'ရီ', 'ရာ', 'v', 'သော', 'လူ', 'တာ', 'ီး', 'j', 'ကာ', 'ရွာ', 'မျက်နှ', 'ယ', 'q', 'ပ်', 'ဌ', 'ဒ', 'ဝ', 'အခြ', 'd', 'ဍ', 'လှ', 'သည်', 'မြန်မာ', 'ယ်', 'ဖ', 'ဦ', 'ါ', 'ဲ့', 'ပျ', 'ရ', 'မိ', 'ပြီး', 'ကို', 'လည်း', 'ဇ', 'မြ', 'နွေး', 'ဘ', 'အသုံးပြု', 'ော', 'ချ', 'မွ', 'လဲ', 'န့်', 'ဂ', 'ည်', 'ကန်', 'က', 'ဗ', 'ေး', 'လု', 'တီ', 'မြို့', 'ိတ်', 'ဘ', 'အရေး', 'ုပ်', 'p', 'ဖ', 'င်', 'သွား', 'တိုင်း', '၃', 'ဿ', 'စေ', 'ဖြတ်', 'ဖွ', 'k', 'သူ', 'တစ်', 'ြ', 'စက်', 'ကြီး', 'ပြည်နယ်', 'ဝါ', 'ဘူး', 'ထ', 'ငြ', 'တော်', 'ကျ', 'ကိ', 'ဈ', 'i', 'အဲ', 'o', 'ေ', 'b', 'င်္', 'ဒါ', 'ညီ', 'w', 'ငွ', 'သ', 'မှတ်', 'ြ', 'ခြား', 'ကြောင့်', 'နာ', 'မှာ', 'f', 'ပွ', 'ကျွန်ုပ်', '၁၀', 'ခေါ', 'ယ်', '၊', 'ှ', 'အဓ', 'နိုင်', 'သက်', 'ပေး', 'a', 'ကျွန်', 'd', 'ထွ', 't', 'n', 'ဠ', 'အရာ', 'ခွ', 'ထ', 'ိုင်', 'ည့်', 'ိမ်', 'သည်', 'တွေ', 'အချ', 'ကား', 'ဗ', 'သုံး', 'အ', 'သူများ', 'ိုက်', 'အမျိုး', '၇', 'စား', 'ဪ', 'တဲ့', 'များ', 's', 'ေ', 'ယ', 'အဓိ', 'နိုင်သည်', 'ဎ', '္', 'ခ', 'စည်း', '၂', 'န်', 'ရ', 'ခရ', 'နည်း', 'အကြ', 'န်', 'တိ', 'န', 'ပြော', 'မှတ်', 'ောင်း', 'န်း', 'ရေး', 'ဆို', 'ူး', 'ရောက်', 'ထို့', 'ည်', 'ပြန်', 'ဒေ', 'စစ်', 'ဟာ', 'ဏ', 'ပြင်', 'ဆိုင်ရာ', 'z', 'ခုနှစ်', 'နဲ့', 'သ', 'စ္', 'ော', 'c', 'လုပ်', 'မျိုး', 'ကေ', 'ဘာ', 'များ', 'ိတ်', 'စား', 'တို', 'ယား', 'တာ', 'q', 'k', 'ဎ', 'င်း', 'စ်', 'အားလုံး', 'အခ', 'အ', 'အသ', 'ချက်', 'ဆက်', 'ည်း', 'ို့', 'လုပ်', 'ပွဲ', 'ကု', 'စပ်', 'အန', 'ပိုင်း', 'm', 'ဖို့', 'ဃ', 'ု', 'တင်', 'ပ္', 'ပြင်', 'း', 'နယ်', 'm', 'ား', 'အနေ', 'အတွက်', 'င့်', 'ရှိ', 'ခြ', '၄', 'v', 'မဟ', 'က်', 'လေး', 'တိုက်', 'ံ', 'သမ', 'ိုင်', '၏', 'j', 'ကြား', 'ကောင်း', 'ဦး', 'တစ်ခု', 'ထုတ်', 'ကု', 'u', 'မည်', 'ရွ', 'မင်း', 'ပ', 'စ်', 'ဆိုင်', 'ဆက်', 'တွင်', 'မြို့နယ်', 'စု', 'ဟ', 'တစ်ဦး', 'လက်', 'ုတ်', 'သူတို့', '်', 'သာ', 'ဩ', 'မာ', 'ယူ', 'ဤ', '့', 'မန', 'ရောဂ', 'သွ', 'ဝင်', 'အတ', 'ရက်', 'မျက်', 'ထား', '၁', 'တ်', 'တို့', 'ဤ', 'နေ့', 'ရင်', '…', 'ထား', 'ဧ', 'ပါး', 'မာ', 'သား', 'ဆောင်', 'မှု', 'ဂ', 'င', 'အား', 'ဇ', 'ောက်', 'သိ', 'ူ', 'စ', '်', 'အတွ', 'e', 'ဉ', 'ဆို', 'ည', 'သည့်', 'က', 'ဖြစ်', 'တရား', 'ရေ', 'ရပ်', 'ပါ', 'ကူး', 'ကမ္', 'သား', 'ကျ', 'မျိုး', 'ခဲ့', 'ောင်', 'ျ', 'ို့', 'ချ', 'အစိုးရ', 'သတ', 'ပြု', 'ကျွ', 'အရ', 'ိုလ', 'ပြီး', 'လုံး', 'လို', 'z', 'ောက်', 'ဥ', 'တမ်း', 'တရ', 'ကျွန်ုပ်တို့', 'နှစ်', 'ိန်', 'ခံ', 'ကာ', 'ဥပ', 'အသုံး', 'တော်', 'ူး', 'ဘာ', 'ပါ', 'ိပ်', 'ား', 'တ', 'နွ', '္တ', 'ဝ', 'လို့', 'ေ့', 'န္', 'e', 'ေ့', 'စီး', 'y', 'ပြား', 'ပိုး', 'အရ', 'အဖြစ်', 'g', 'ဓာ', 'ပြ', 'တစ်', 'မှ', 'ဖွဲ့', '၍', 'ခြင်း', 'ုံး', 'ဆင်', 'ွန်', 'အလ', 'တော့', 'မို', 'လ', 'စာ', 'ဿ', 'အမြ', 'တင်', 'အကျ', 'ဲ', 'ူ', 'အုပ်', 'y', 'u', 'ဒါ', 'ရော', 'ပို', 'လိုအ', 'a', 'ိ', 'ဆ', '့', 'x', 'လို', '့်', 'ပြည်', 'ယူ', 'ဃ', 'ဆေး', 'ခံ', 'မွ', 'ဘဲ', 'ုံး', 'ော်', 'လိုက်', 'နေ', 'မျ', 'နိုင်င', 'ံ့', 'မှာ', 'နည်း', 'ရန်', 'လက္ခဏာ', 'ဥ', 'င့်', 'ပညာ', 'ပ်', 'အားဖြင့်', 'နှစ်', 'ဆွေး', 'ဖြစ်သည်', 'ဒ', 'ီ', 'နစ်', 'ကျင်', 'ဋ', 'အများ', 'ဉ', 'မ်း', 'န့်', 'ကွ', 'သို့', 'b', '၀', 'ခု', 'ပုံ', 'တော', 'အာ', 'ဖြင့်', 'ဧ', 'သွား', 'အခါ', 'မ', 'င်း', 'ာ', 'ဆ', 'i', 'ဓ', '၆', 'ကြော', 'ရိ', 'သြ', 'တွေ့', '၌', 'ထိ', 'က္', 'အစ', 'ကြ', 'ရွ', 'ု', 'ေး', 'ွ', 'န်း', 'း', 'ပ', 'ဋ', 'ဆာ', 'အောင်', 'မြို့', 'စိတ်', 'ျ', 'ပြင်ဆင်', 'ါ', 'မဟုတ်', 'ပြု', 'ကိုယ်', 'ရှိ', 'ည', 'ဆောင်', 'ဆွေးနွေး', 'င်', 'n', 'တ်', 'ိုင်း', 'စီ', 'လူ', 'ဍ', 'ဟု', 'ည့်', 'သို့', '္', '႓', 'ိုး', 'န', 'ရေ', 'မယ်', 'ခဲ့သည်', 'ုံ', 'ောင်း', 'ောင်', 'ဦး', 'ထိ', 'တို့', 'ိမ့်', 'x', 'နိုင်ငံ', '၊', 'အပြ', 'ံ', 'ထု', 'ရေး', 'စစ်', 'ီ', 'မှု', 'ရှင်', 'ဦ', 'ရှိသည်', 'ပေါ', 'ဂျ', 'အစား', 'မြန်', 'ခ', 'သာ', 'နှ', 'ပထ', 'ိ', 'သင်', '့်'] + + word_lists = [] + for i in word: + cur = i.replace(' ', '') + cur = cur.replace('', '') + cur = cur.replace('', '') + word_lists.append(cur) + + if len(word_lists) == 0: + return False + + for ch in word_lists: + if ch.isalpha() is False and ch in my_char: + return True + elif ch.isalpha() is True and isChinese(ch) is True: + return False + + return True # def abbr_dispose(words: List[Any]) -> List[Any]: def abbr_dispose(words: List[Any], time_stamp: List[List] = None) -> List[Any]: @@ -224,6 +244,17 @@ def sentence_postprocess(words: List[Any], time_stamp: List[List] = None): end = time_stamp[i][1] ts_lists.append([begin, end]) begin = end + elif isMy(ch): + word_item += ch + word_lists.append(word_item) + word_lists.append(' ') + word_item = '' + alpha_blank = True + if time_stamp is not None: + ts_flag = True + end = time_stamp[i][1] + ts_lists.append([begin, end]) + begin = end else: word_lists.append(ch) From 3fe6147415a65313fdc856c94fb92a5eb65a63da Mon Sep 17 00:00:00 2001 From: "chong.zhang" Date: Mon, 27 Mar 2023 17:42:35 +0800 Subject: [PATCH 028/120] update --- funasr/utils/postprocess_utils.py | 31 ------------------------------- 1 file changed, 31 deletions(-) diff --git a/funasr/utils/postprocess_utils.py b/funasr/utils/postprocess_utils.py index e3d8d6b47..b607e1da0 100644 --- a/funasr/utils/postprocess_utils.py +++ b/funasr/utils/postprocess_utils.py @@ -51,26 +51,6 @@ def isAllAlpha(word: Union[List[Any], str]): return True -def isMy(word: Union[List[Any], str]): - my_char = ['စေ', 'ကို', 'ဖြစ်', 'ဌ', 'ေါ', 'ရင်း', 'w', 'ပုံ', 'ပတ်', 'လာ', 'စီး', 'ဘက်', 'က်', 'ုံ', 'ဏာ', 'ဖော်', 'အတွင်း', 'r', '၀', 'တို', 'ပြန်', 'ီး', 'h', 'ဖြ', 'က္ခ', 'မ္', 'အထိ', 'ဆွ', 'ပေး', 'တူ', '၈', 'မ်း', 'ဠ', 'ထို', 'စွ', 'ထားသည်', 'အခြေ', 'စာ', 'တို့သည်', 'အက', 'ရဲ့', 'ွ', 'င', 'o', 'ုတ်', 'လွ', 'ပင်', 'နိုင်ငံ', 'ပါတယ်', 'ကား', 'အဖွဲ့', 'အခြား', 'ယ့်', 'ပို', 'ည်း', 'ယာ', 'ဆုံး', '၄', 'ကြောင်း', 'တပ်', 'အနေ', 'ဣ', '၏', 'ိုး', 'ချုပ်', 'နေ', 'စ', 'ဟ', 'လွှ', 'အဆ', '၌', 'ဣ', 'နိုင်', 'တည်', 'တွ', 'အချိန်', 'ပဲ', 'ဝင်', 'ဒီ', 'သူ', 'l', 'ဏ', 'ဲ့', 'အထ', 'ပည', 'စိတ်', 'ကြသည်', 'ဩ', 's', 't', 'သေ', 'လျ', 'ိုက်', 'များသည်', 'ငါ', 'ို', 'ထဲ', 'လာ', 'ဝန်', 'ဓ', 'ခဲ့', 'စွာ', 'မ', 'နှင့်', '၎', 'အစိုး', 'ရာ', '၉', 'တယ်', '၎င်း', '၅', 'ပညာ', 'ကြီး', 'သို့မဟုတ်', '၍', 'ို', 'မူ', 'f', 'ခု', 'ိမ', 'c', 'ုပ်', 'l', 'အမ', 'နောက်', 'သော', 'ုန်း', 'ှ', 'ကြ', 'တ', 'ဌာ', 'p', 'ပေါ်', 'h', 'ပင်', 'ဲ', 'ဒီ', 'ဈ', 'လက္ခ', 'r', 'ပြ', 'ဒေ', 'မှ', 'ရှ', 'လျှ', 'လေ့', 'ရောဂါ', 'ော်', 'လည်', 'ဖွဲ့', 'မ်', 'သိ', 'ထုတ်', 'ရိ', 'အား', 'ာ', 'လ', 'ုပ', 'ကျော်', 'အေ', 'g', 'နာ', 'ရီ', 'ရာ', 'v', 'သော', 'လူ', 'တာ', 'ီး', 'j', 'ကာ', 'ရွာ', 'မျက်နှ', 'ယ', 'q', 'ပ်', 'ဌ', 'ဒ', 'ဝ', 'အခြ', 'd', 'ဍ', 'လှ', 'သည်', 'မြန်မာ', 'ယ်', 'ဖ', 'ဦ', 'ါ', 'ဲ့', 'ပျ', 'ရ', 'မိ', 'ပြီး', 'ကို', 'လည်း', 'ဇ', 'မြ', 'နွေး', 'ဘ', 'အသုံးပြု', 'ော', 'ချ', 'မွ', 'လဲ', 'န့်', 'ဂ', 'ည်', 'ကန်', 'က', 'ဗ', 'ေး', 'လု', 'တီ', 'မြို့', 'ိတ်', 'ဘ', 'အရေး', 'ုပ်', 'p', 'ဖ', 'င်', 'သွား', 'တိုင်း', '၃', 'ဿ', 'စေ', 'ဖြတ်', 'ဖွ', 'k', 'သူ', 'တစ်', 'ြ', 'စက်', 'ကြီး', 'ပြည်နယ်', 'ဝါ', 'ဘူး', 'ထ', 'ငြ', 'တော်', 'ကျ', 'ကိ', 'ဈ', 'i', 'အဲ', 'o', 'ေ', 'b', 'င်္', 'ဒါ', 'ညီ', 'w', 'ငွ', 'သ', 'မှတ်', 'ြ', 'ခြား', 'ကြောင့်', 'နာ', 'မှာ', 'f', 'ပွ', 'ကျွန်ုပ်', '၁၀', 'ခေါ', 'ယ်', '၊', 'ှ', 'အဓ', 'နိုင်', 'သက်', 'ပေး', 'a', 'ကျွန်', 'd', 'ထွ', 't', 'n', 'ဠ', 'အရာ', 'ခွ', 'ထ', 'ိုင်', 'ည့်', 'ိမ်', 'သည်', 'တွေ', 'အချ', 'ကား', 'ဗ', 'သုံး', 'အ', 'သူများ', 'ိုက်', 'အမျိုး', '၇', 'စား', 'ဪ', 'တဲ့', 'များ', 's', 'ေ', 'ယ', 'အဓိ', 'နိုင်သည်', 'ဎ', '္', 'ခ', 'စည်း', '၂', 'န်', 'ရ', 'ခရ', 'နည်း', 'အကြ', 'န်', 'တိ', 'န', 'ပြော', 'မှတ်', 'ောင်း', 'န်း', 'ရေး', 'ဆို', 'ူး', 'ရောက်', 'ထို့', 'ည်', 'ပြန်', 'ဒေ', 'စစ်', 'ဟာ', 'ဏ', 'ပြင်', 'ဆိုင်ရာ', 'z', 'ခုနှစ်', 'နဲ့', 'သ', 'စ္', 'ော', 'c', 'လုပ်', 'မျိုး', 'ကေ', 'ဘာ', 'များ', 'ိတ်', 'စား', 'တို', 'ယား', 'တာ', 'q', 'k', 'ဎ', 'င်း', 'စ်', 'အားလုံး', 'အခ', 'အ', 'အသ', 'ချက်', 'ဆက်', 'ည်း', 'ို့', 'လုပ်', 'ပွဲ', 'ကု', 'စပ်', 'အန', 'ပိုင်း', 'm', 'ဖို့', 'ဃ', 'ု', 'တင်', 'ပ္', 'ပြင်', 'း', 'နယ်', 'm', 'ား', 'အနေ', 'အတွက်', 'င့်', 'ရှိ', 'ခြ', '၄', 'v', 'မဟ', 'က်', 'လေး', 'တိုက်', 'ံ', 'သမ', 'ိုင်', '၏', 'j', 'ကြား', 'ကောင်း', 'ဦး', 'တစ်ခု', 'ထုတ်', 'ကု', 'u', 'မည်', 'ရွ', 'မင်း', 'ပ', 'စ်', 'ဆိုင်', 'ဆက်', 'တွင်', 'မြို့နယ်', 'စု', 'ဟ', 'တစ်ဦး', 'လက်', 'ုတ်', 'သူတို့', '်', 'သာ', 'ဩ', 'မာ', 'ယူ', 'ဤ', '့', 'မန', 'ရောဂ', 'သွ', 'ဝင်', 'အတ', 'ရက်', 'မျက်', 'ထား', '၁', 'တ်', 'တို့', 'ဤ', 'နေ့', 'ရင်', '…', 'ထား', 'ဧ', 'ပါး', 'မာ', 'သား', 'ဆောင်', 'မှု', 'ဂ', 'င', 'အား', 'ဇ', 'ောက်', 'သိ', 'ူ', 'စ', '်', 'အတွ', 'e', 'ဉ', 'ဆို', 'ည', 'သည့်', 'က', 'ဖြစ်', 'တရား', 'ရေ', 'ရပ်', 'ပါ', 'ကူး', 'ကမ္', 'သား', 'ကျ', 'မျိုး', 'ခဲ့', 'ောင်', 'ျ', 'ို့', 'ချ', 'အစိုးရ', 'သတ', 'ပြု', 'ကျွ', 'အရ', 'ိုလ', 'ပြီး', 'လုံး', 'လို', 'z', 'ောက်', 'ဥ', 'တမ်း', 'တရ', 'ကျွန်ုပ်တို့', 'နှစ်', 'ိန်', 'ခံ', 'ကာ', 'ဥပ', 'အသုံး', 'တော်', 'ူး', 'ဘာ', 'ပါ', 'ိပ်', 'ား', 'တ', 'နွ', '္တ', 'ဝ', 'လို့', 'ေ့', 'န္', 'e', 'ေ့', 'စီး', 'y', 'ပြား', 'ပိုး', 'အရ', 'အဖြစ်', 'g', 'ဓာ', 'ပြ', 'တစ်', 'မှ', 'ဖွဲ့', '၍', 'ခြင်း', 'ုံး', 'ဆင်', 'ွန်', 'အလ', 'တော့', 'မို', 'လ', 'စာ', 'ဿ', 'အမြ', 'တင်', 'အကျ', 'ဲ', 'ူ', 'အုပ်', 'y', 'u', 'ဒါ', 'ရော', 'ပို', 'လိုအ', 'a', 'ိ', 'ဆ', '့', 'x', 'လို', '့်', 'ပြည်', 'ယူ', 'ဃ', 'ဆေး', 'ခံ', 'မွ', 'ဘဲ', 'ုံး', 'ော်', 'လိုက်', 'နေ', 'မျ', 'နိုင်င', 'ံ့', 'မှာ', 'နည်း', 'ရန်', 'လက္ခဏာ', 'ဥ', 'င့်', 'ပညာ', 'ပ်', 'အားဖြင့်', 'နှစ်', 'ဆွေး', 'ဖြစ်သည်', 'ဒ', 'ီ', 'နစ်', 'ကျင်', 'ဋ', 'အများ', 'ဉ', 'မ်း', 'န့်', 'ကွ', 'သို့', 'b', '၀', 'ခု', 'ပုံ', 'တော', 'အာ', 'ဖြင့်', 'ဧ', 'သွား', 'အခါ', 'မ', 'င်း', 'ာ', 'ဆ', 'i', 'ဓ', '၆', 'ကြော', 'ရိ', 'သြ', 'တွေ့', '၌', 'ထိ', 'က္', 'အစ', 'ကြ', 'ရွ', 'ု', 'ေး', 'ွ', 'န်း', 'း', 'ပ', 'ဋ', 'ဆာ', 'အောင်', 'မြို့', 'စိတ်', 'ျ', 'ပြင်ဆင်', 'ါ', 'မဟုတ်', 'ပြု', 'ကိုယ်', 'ရှိ', 'ည', 'ဆောင်', 'ဆွေးနွေး', 'င်', 'n', 'တ်', 'ိုင်း', 'စီ', 'လူ', 'ဍ', 'ဟု', 'ည့်', 'သို့', '္', '႓', 'ိုး', 'န', 'ရေ', 'မယ်', 'ခဲ့သည်', 'ုံ', 'ောင်း', 'ောင်', 'ဦး', 'ထိ', 'တို့', 'ိမ့်', 'x', 'နိုင်ငံ', '၊', 'အပြ', 'ံ', 'ထု', 'ရေး', 'စစ်', 'ီ', 'မှု', 'ရှင်', 'ဦ', 'ရှိသည်', 'ပေါ', 'ဂျ', 'အစား', 'မြန်', 'ခ', 'သာ', 'နှ', 'ပထ', 'ိ', 'သင်', '့်'] - - word_lists = [] - for i in word: - cur = i.replace(' ', '') - cur = cur.replace('', '') - cur = cur.replace('', '') - word_lists.append(cur) - - if len(word_lists) == 0: - return False - - for ch in word_lists: - if ch.isalpha() is False and ch in my_char: - return True - elif ch.isalpha() is True and isChinese(ch) is True: - return False - - return True # def abbr_dispose(words: List[Any]) -> List[Any]: def abbr_dispose(words: List[Any], time_stamp: List[List] = None) -> List[Any]: @@ -244,17 +224,6 @@ def sentence_postprocess(words: List[Any], time_stamp: List[List] = None): end = time_stamp[i][1] ts_lists.append([begin, end]) begin = end - elif isMy(ch): - word_item += ch - word_lists.append(word_item) - word_lists.append(' ') - word_item = '' - alpha_blank = True - if time_stamp is not None: - ts_flag = True - end = time_stamp[i][1] - ts_lists.append([begin, end]) - begin = end else: word_lists.append(ch) From 5d7ccbfc012905b0fd067da337321b06f66ee3bc Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Mon, 27 Mar 2023 17:23:34 +0800 Subject: [PATCH 029/120] Update postprocess_utils.py add Burmese characters --- funasr/utils/postprocess_utils.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/funasr/utils/postprocess_utils.py b/funasr/utils/postprocess_utils.py index b607e1da0..e3d8d6b47 100644 --- a/funasr/utils/postprocess_utils.py +++ b/funasr/utils/postprocess_utils.py @@ -51,6 +51,26 @@ def isAllAlpha(word: Union[List[Any], str]): return True +def isMy(word: Union[List[Any], str]): + my_char = ['စေ', 'ကို', 'ဖြစ်', 'ဌ', 'ေါ', 'ရင်း', 'w', 'ပုံ', 'ပတ်', 'လာ', 'စီး', 'ဘက်', 'က်', 'ုံ', 'ဏာ', 'ဖော်', 'အတွင်း', 'r', '၀', 'တို', 'ပြန်', 'ီး', 'h', 'ဖြ', 'က္ခ', 'မ္', 'အထိ', 'ဆွ', 'ပေး', 'တူ', '၈', 'မ်း', 'ဠ', 'ထို', 'စွ', 'ထားသည်', 'အခြေ', 'စာ', 'တို့သည်', 'အက', 'ရဲ့', 'ွ', 'င', 'o', 'ုတ်', 'လွ', 'ပင်', 'နိုင်ငံ', 'ပါတယ်', 'ကား', 'အဖွဲ့', 'အခြား', 'ယ့်', 'ပို', 'ည်း', 'ယာ', 'ဆုံး', '၄', 'ကြောင်း', 'တပ်', 'အနေ', 'ဣ', '၏', 'ိုး', 'ချုပ်', 'နေ', 'စ', 'ဟ', 'လွှ', 'အဆ', '၌', 'ဣ', 'နိုင်', 'တည်', 'တွ', 'အချိန်', 'ပဲ', 'ဝင်', 'ဒီ', 'သူ', 'l', 'ဏ', 'ဲ့', 'အထ', 'ပည', 'စိတ်', 'ကြသည်', 'ဩ', 's', 't', 'သေ', 'လျ', 'ိုက်', 'များသည်', 'ငါ', 'ို', 'ထဲ', 'လာ', 'ဝန်', 'ဓ', 'ခဲ့', 'စွာ', 'မ', 'နှင့်', '၎', 'အစိုး', 'ရာ', '၉', 'တယ်', '၎င်း', '၅', 'ပညာ', 'ကြီး', 'သို့မဟုတ်', '၍', 'ို', 'မူ', 'f', 'ခု', 'ိမ', 'c', 'ုပ်', 'l', 'အမ', 'နောက်', 'သော', 'ုန်း', 'ှ', 'ကြ', 'တ', 'ဌာ', 'p', 'ပေါ်', 'h', 'ပင်', 'ဲ', 'ဒီ', 'ဈ', 'လက္ခ', 'r', 'ပြ', 'ဒေ', 'မှ', 'ရှ', 'လျှ', 'လေ့', 'ရောဂါ', 'ော်', 'လည်', 'ဖွဲ့', 'မ်', 'သိ', 'ထုတ်', 'ရိ', 'အား', 'ာ', 'လ', 'ုပ', 'ကျော်', 'အေ', 'g', 'နာ', 'ရီ', 'ရာ', 'v', 'သော', 'လူ', 'တာ', 'ီး', 'j', 'ကာ', 'ရွာ', 'မျက်နှ', 'ယ', 'q', 'ပ်', 'ဌ', 'ဒ', 'ဝ', 'အခြ', 'd', 'ဍ', 'လှ', 'သည်', 'မြန်မာ', 'ယ်', 'ဖ', 'ဦ', 'ါ', 'ဲ့', 'ပျ', 'ရ', 'မိ', 'ပြီး', 'ကို', 'လည်း', 'ဇ', 'မြ', 'နွေး', 'ဘ', 'အသုံးပြု', 'ော', 'ချ', 'မွ', 'လဲ', 'န့်', 'ဂ', 'ည်', 'ကန်', 'က', 'ဗ', 'ေး', 'လု', 'တီ', 'မြို့', 'ိတ်', 'ဘ', 'အရေး', 'ုပ်', 'p', 'ဖ', 'င်', 'သွား', 'တိုင်း', '၃', 'ဿ', 'စေ', 'ဖြတ်', 'ဖွ', 'k', 'သူ', 'တစ်', 'ြ', 'စက်', 'ကြီး', 'ပြည်နယ်', 'ဝါ', 'ဘူး', 'ထ', 'ငြ', 'တော်', 'ကျ', 'ကိ', 'ဈ', 'i', 'အဲ', 'o', 'ေ', 'b', 'င်္', 'ဒါ', 'ညီ', 'w', 'ငွ', 'သ', 'မှတ်', 'ြ', 'ခြား', 'ကြောင့်', 'နာ', 'မှာ', 'f', 'ပွ', 'ကျွန်ုပ်', '၁၀', 'ခေါ', 'ယ်', '၊', 'ှ', 'အဓ', 'နိုင်', 'သက်', 'ပေး', 'a', 'ကျွန်', 'd', 'ထွ', 't', 'n', 'ဠ', 'အရာ', 'ခွ', 'ထ', 'ိုင်', 'ည့်', 'ိမ်', 'သည်', 'တွေ', 'အချ', 'ကား', 'ဗ', 'သုံး', 'အ', 'သူများ', 'ိုက်', 'အမျိုး', '၇', 'စား', 'ဪ', 'တဲ့', 'များ', 's', 'ေ', 'ယ', 'အဓိ', 'နိုင်သည်', 'ဎ', '္', 'ခ', 'စည်း', '၂', 'န်', 'ရ', 'ခရ', 'နည်း', 'အကြ', 'န်', 'တိ', 'န', 'ပြော', 'မှတ်', 'ောင်း', 'န်း', 'ရေး', 'ဆို', 'ူး', 'ရောက်', 'ထို့', 'ည်', 'ပြန်', 'ဒေ', 'စစ်', 'ဟာ', 'ဏ', 'ပြင်', 'ဆိုင်ရာ', 'z', 'ခုနှစ်', 'နဲ့', 'သ', 'စ္', 'ော', 'c', 'လုပ်', 'မျိုး', 'ကေ', 'ဘာ', 'များ', 'ိတ်', 'စား', 'တို', 'ယား', 'တာ', 'q', 'k', 'ဎ', 'င်း', 'စ်', 'အားလုံး', 'အခ', 'အ', 'အသ', 'ချက်', 'ဆက်', 'ည်း', 'ို့', 'လုပ်', 'ပွဲ', 'ကု', 'စပ်', 'အန', 'ပိုင်း', 'm', 'ဖို့', 'ဃ', 'ု', 'တင်', 'ပ္', 'ပြင်', 'း', 'နယ်', 'm', 'ား', 'အနေ', 'အတွက်', 'င့်', 'ရှိ', 'ခြ', '၄', 'v', 'မဟ', 'က်', 'လေး', 'တိုက်', 'ံ', 'သမ', 'ိုင်', '၏', 'j', 'ကြား', 'ကောင်း', 'ဦး', 'တစ်ခု', 'ထုတ်', 'ကု', 'u', 'မည်', 'ရွ', 'မင်း', 'ပ', 'စ်', 'ဆိုင်', 'ဆက်', 'တွင်', 'မြို့နယ်', 'စု', 'ဟ', 'တစ်ဦး', 'လက်', 'ုတ်', 'သူတို့', '်', 'သာ', 'ဩ', 'မာ', 'ယူ', 'ဤ', '့', 'မန', 'ရောဂ', 'သွ', 'ဝင်', 'အတ', 'ရက်', 'မျက်', 'ထား', '၁', 'တ်', 'တို့', 'ဤ', 'နေ့', 'ရင်', '…', 'ထား', 'ဧ', 'ပါး', 'မာ', 'သား', 'ဆောင်', 'မှု', 'ဂ', 'င', 'အား', 'ဇ', 'ောက်', 'သိ', 'ူ', 'စ', '်', 'အတွ', 'e', 'ဉ', 'ဆို', 'ည', 'သည့်', 'က', 'ဖြစ်', 'တရား', 'ရေ', 'ရပ်', 'ပါ', 'ကူး', 'ကမ္', 'သား', 'ကျ', 'မျိုး', 'ခဲ့', 'ောင်', 'ျ', 'ို့', 'ချ', 'အစိုးရ', 'သတ', 'ပြု', 'ကျွ', 'အရ', 'ိုလ', 'ပြီး', 'လုံး', 'လို', 'z', 'ောက်', 'ဥ', 'တမ်း', 'တရ', 'ကျွန်ုပ်တို့', 'နှစ်', 'ိန်', 'ခံ', 'ကာ', 'ဥပ', 'အသုံး', 'တော်', 'ူး', 'ဘာ', 'ပါ', 'ိပ်', 'ား', 'တ', 'နွ', '္တ', 'ဝ', 'လို့', 'ေ့', 'န္', 'e', 'ေ့', 'စီး', 'y', 'ပြား', 'ပိုး', 'အရ', 'အဖြစ်', 'g', 'ဓာ', 'ပြ', 'တစ်', 'မှ', 'ဖွဲ့', '၍', 'ခြင်း', 'ုံး', 'ဆင်', 'ွန်', 'အလ', 'တော့', 'မို', 'လ', 'စာ', 'ဿ', 'အမြ', 'တင်', 'အကျ', 'ဲ', 'ူ', 'အုပ်', 'y', 'u', 'ဒါ', 'ရော', 'ပို', 'လိုအ', 'a', 'ိ', 'ဆ', '့', 'x', 'လို', '့်', 'ပြည်', 'ယူ', 'ဃ', 'ဆေး', 'ခံ', 'မွ', 'ဘဲ', 'ုံး', 'ော်', 'လိုက်', 'နေ', 'မျ', 'နိုင်င', 'ံ့', 'မှာ', 'နည်း', 'ရန်', 'လက္ခဏာ', 'ဥ', 'င့်', 'ပညာ', 'ပ်', 'အားဖြင့်', 'နှစ်', 'ဆွေး', 'ဖြစ်သည်', 'ဒ', 'ီ', 'နစ်', 'ကျင်', 'ဋ', 'အများ', 'ဉ', 'မ်း', 'န့်', 'ကွ', 'သို့', 'b', '၀', 'ခု', 'ပုံ', 'တော', 'အာ', 'ဖြင့်', 'ဧ', 'သွား', 'အခါ', 'မ', 'င်း', 'ာ', 'ဆ', 'i', 'ဓ', '၆', 'ကြော', 'ရိ', 'သြ', 'တွေ့', '၌', 'ထိ', 'က္', 'အစ', 'ကြ', 'ရွ', 'ု', 'ေး', 'ွ', 'န်း', 'း', 'ပ', 'ဋ', 'ဆာ', 'အောင်', 'မြို့', 'စိတ်', 'ျ', 'ပြင်ဆင်', 'ါ', 'မဟုတ်', 'ပြု', 'ကိုယ်', 'ရှိ', 'ည', 'ဆောင်', 'ဆွေးနွေး', 'င်', 'n', 'တ်', 'ိုင်း', 'စီ', 'လူ', 'ဍ', 'ဟု', 'ည့်', 'သို့', '္', '႓', 'ိုး', 'န', 'ရေ', 'မယ်', 'ခဲ့သည်', 'ုံ', 'ောင်း', 'ောင်', 'ဦး', 'ထိ', 'တို့', 'ိမ့်', 'x', 'နိုင်ငံ', '၊', 'အပြ', 'ံ', 'ထု', 'ရေး', 'စစ်', 'ီ', 'မှု', 'ရှင်', 'ဦ', 'ရှိသည်', 'ပေါ', 'ဂျ', 'အစား', 'မြန်', 'ခ', 'သာ', 'နှ', 'ပထ', 'ိ', 'သင်', '့်'] + + word_lists = [] + for i in word: + cur = i.replace(' ', '') + cur = cur.replace('', '') + cur = cur.replace('', '') + word_lists.append(cur) + + if len(word_lists) == 0: + return False + + for ch in word_lists: + if ch.isalpha() is False and ch in my_char: + return True + elif ch.isalpha() is True and isChinese(ch) is True: + return False + + return True # def abbr_dispose(words: List[Any]) -> List[Any]: def abbr_dispose(words: List[Any], time_stamp: List[List] = None) -> List[Any]: @@ -224,6 +244,17 @@ def sentence_postprocess(words: List[Any], time_stamp: List[List] = None): end = time_stamp[i][1] ts_lists.append([begin, end]) begin = end + elif isMy(ch): + word_item += ch + word_lists.append(word_item) + word_lists.append(' ') + word_item = '' + alpha_blank = True + if time_stamp is not None: + ts_flag = True + end = time_stamp[i][1] + ts_lists.append([begin, end]) + begin = end else: word_lists.append(ch) From 09de0c653ebec3b802de807f9705802adcc46896 Mon Sep 17 00:00:00 2001 From: "chong.zhang" Date: Mon, 27 Mar 2023 17:42:35 +0800 Subject: [PATCH 030/120] update --- funasr/utils/postprocess_utils.py | 31 ------------------------------- 1 file changed, 31 deletions(-) diff --git a/funasr/utils/postprocess_utils.py b/funasr/utils/postprocess_utils.py index e3d8d6b47..b607e1da0 100644 --- a/funasr/utils/postprocess_utils.py +++ b/funasr/utils/postprocess_utils.py @@ -51,26 +51,6 @@ def isAllAlpha(word: Union[List[Any], str]): return True -def isMy(word: Union[List[Any], str]): - my_char = ['စေ', 'ကို', 'ဖြစ်', 'ဌ', 'ေါ', 'ရင်း', 'w', 'ပုံ', 'ပတ်', 'လာ', 'စီး', 'ဘက်', 'က်', 'ုံ', 'ဏာ', 'ဖော်', 'အတွင်း', 'r', '၀', 'တို', 'ပြန်', 'ီး', 'h', 'ဖြ', 'က္ခ', 'မ္', 'အထိ', 'ဆွ', 'ပေး', 'တူ', '၈', 'မ်း', 'ဠ', 'ထို', 'စွ', 'ထားသည်', 'အခြေ', 'စာ', 'တို့သည်', 'အက', 'ရဲ့', 'ွ', 'င', 'o', 'ုတ်', 'လွ', 'ပင်', 'နိုင်ငံ', 'ပါတယ်', 'ကား', 'အဖွဲ့', 'အခြား', 'ယ့်', 'ပို', 'ည်း', 'ယာ', 'ဆုံး', '၄', 'ကြောင်း', 'တပ်', 'အနေ', 'ဣ', '၏', 'ိုး', 'ချုပ်', 'နေ', 'စ', 'ဟ', 'လွှ', 'အဆ', '၌', 'ဣ', 'နိုင်', 'တည်', 'တွ', 'အချိန်', 'ပဲ', 'ဝင်', 'ဒီ', 'သူ', 'l', 'ဏ', 'ဲ့', 'အထ', 'ပည', 'စိတ်', 'ကြသည်', 'ဩ', 's', 't', 'သေ', 'လျ', 'ိုက်', 'များသည်', 'ငါ', 'ို', 'ထဲ', 'လာ', 'ဝန်', 'ဓ', 'ခဲ့', 'စွာ', 'မ', 'နှင့်', '၎', 'အစိုး', 'ရာ', '၉', 'တယ်', '၎င်း', '၅', 'ပညာ', 'ကြီး', 'သို့မဟုတ်', '၍', 'ို', 'မူ', 'f', 'ခု', 'ိမ', 'c', 'ုပ်', 'l', 'အမ', 'နောက်', 'သော', 'ုန်း', 'ှ', 'ကြ', 'တ', 'ဌာ', 'p', 'ပေါ်', 'h', 'ပင်', 'ဲ', 'ဒီ', 'ဈ', 'လက္ခ', 'r', 'ပြ', 'ဒေ', 'မှ', 'ရှ', 'လျှ', 'လေ့', 'ရောဂါ', 'ော်', 'လည်', 'ဖွဲ့', 'မ်', 'သိ', 'ထုတ်', 'ရိ', 'အား', 'ာ', 'လ', 'ုပ', 'ကျော်', 'အေ', 'g', 'နာ', 'ရီ', 'ရာ', 'v', 'သော', 'လူ', 'တာ', 'ီး', 'j', 'ကာ', 'ရွာ', 'မျက်နှ', 'ယ', 'q', 'ပ်', 'ဌ', 'ဒ', 'ဝ', 'အခြ', 'd', 'ဍ', 'လှ', 'သည်', 'မြန်မာ', 'ယ်', 'ဖ', 'ဦ', 'ါ', 'ဲ့', 'ပျ', 'ရ', 'မိ', 'ပြီး', 'ကို', 'လည်း', 'ဇ', 'မြ', 'နွေး', 'ဘ', 'အသုံးပြု', 'ော', 'ချ', 'မွ', 'လဲ', 'န့်', 'ဂ', 'ည်', 'ကန်', 'က', 'ဗ', 'ေး', 'လု', 'တီ', 'မြို့', 'ိတ်', 'ဘ', 'အရေး', 'ုပ်', 'p', 'ဖ', 'င်', 'သွား', 'တိုင်း', '၃', 'ဿ', 'စေ', 'ဖြတ်', 'ဖွ', 'k', 'သူ', 'တစ်', 'ြ', 'စက်', 'ကြီး', 'ပြည်နယ်', 'ဝါ', 'ဘူး', 'ထ', 'ငြ', 'တော်', 'ကျ', 'ကိ', 'ဈ', 'i', 'အဲ', 'o', 'ေ', 'b', 'င်္', 'ဒါ', 'ညီ', 'w', 'ငွ', 'သ', 'မှတ်', 'ြ', 'ခြား', 'ကြောင့်', 'နာ', 'မှာ', 'f', 'ပွ', 'ကျွန်ုပ်', '၁၀', 'ခေါ', 'ယ်', '၊', 'ှ', 'အဓ', 'နိုင်', 'သက်', 'ပေး', 'a', 'ကျွန်', 'd', 'ထွ', 't', 'n', 'ဠ', 'အရာ', 'ခွ', 'ထ', 'ိုင်', 'ည့်', 'ိမ်', 'သည်', 'တွေ', 'အချ', 'ကား', 'ဗ', 'သုံး', 'အ', 'သူများ', 'ိုက်', 'အမျိုး', '၇', 'စား', 'ဪ', 'တဲ့', 'များ', 's', 'ေ', 'ယ', 'အဓိ', 'နိုင်သည်', 'ဎ', '္', 'ခ', 'စည်း', '၂', 'န်', 'ရ', 'ခရ', 'နည်း', 'အကြ', 'န်', 'တိ', 'န', 'ပြော', 'မှတ်', 'ောင်း', 'န်း', 'ရေး', 'ဆို', 'ူး', 'ရောက်', 'ထို့', 'ည်', 'ပြန်', 'ဒေ', 'စစ်', 'ဟာ', 'ဏ', 'ပြင်', 'ဆိုင်ရာ', 'z', 'ခုနှစ်', 'နဲ့', 'သ', 'စ္', 'ော', 'c', 'လုပ်', 'မျိုး', 'ကေ', 'ဘာ', 'များ', 'ိတ်', 'စား', 'တို', 'ယား', 'တာ', 'q', 'k', 'ဎ', 'င်း', 'စ်', 'အားလုံး', 'အခ', 'အ', 'အသ', 'ချက်', 'ဆက်', 'ည်း', 'ို့', 'လုပ်', 'ပွဲ', 'ကု', 'စပ်', 'အန', 'ပိုင်း', 'm', 'ဖို့', 'ဃ', 'ု', 'တင်', 'ပ္', 'ပြင်', 'း', 'နယ်', 'm', 'ား', 'အနေ', 'အတွက်', 'င့်', 'ရှိ', 'ခြ', '၄', 'v', 'မဟ', 'က်', 'လေး', 'တိုက်', 'ံ', 'သမ', 'ိုင်', '၏', 'j', 'ကြား', 'ကောင်း', 'ဦး', 'တစ်ခု', 'ထုတ်', 'ကု', 'u', 'မည်', 'ရွ', 'မင်း', 'ပ', 'စ်', 'ဆိုင်', 'ဆက်', 'တွင်', 'မြို့နယ်', 'စု', 'ဟ', 'တစ်ဦး', 'လက်', 'ုတ်', 'သူတို့', '်', 'သာ', 'ဩ', 'မာ', 'ယူ', 'ဤ', '့', 'မန', 'ရောဂ', 'သွ', 'ဝင်', 'အတ', 'ရက်', 'မျက်', 'ထား', '၁', 'တ်', 'တို့', 'ဤ', 'နေ့', 'ရင်', '…', 'ထား', 'ဧ', 'ပါး', 'မာ', 'သား', 'ဆောင်', 'မှု', 'ဂ', 'င', 'အား', 'ဇ', 'ောက်', 'သိ', 'ူ', 'စ', '်', 'အတွ', 'e', 'ဉ', 'ဆို', 'ည', 'သည့်', 'က', 'ဖြစ်', 'တရား', 'ရေ', 'ရပ်', 'ပါ', 'ကူး', 'ကမ္', 'သား', 'ကျ', 'မျိုး', 'ခဲ့', 'ောင်', 'ျ', 'ို့', 'ချ', 'အစိုးရ', 'သတ', 'ပြု', 'ကျွ', 'အရ', 'ိုလ', 'ပြီး', 'လုံး', 'လို', 'z', 'ောက်', 'ဥ', 'တမ်း', 'တရ', 'ကျွန်ုပ်တို့', 'နှစ်', 'ိန်', 'ခံ', 'ကာ', 'ဥပ', 'အသုံး', 'တော်', 'ူး', 'ဘာ', 'ပါ', 'ိပ်', 'ား', 'တ', 'နွ', '္တ', 'ဝ', 'လို့', 'ေ့', 'န္', 'e', 'ေ့', 'စီး', 'y', 'ပြား', 'ပိုး', 'အရ', 'အဖြစ်', 'g', 'ဓာ', 'ပြ', 'တစ်', 'မှ', 'ဖွဲ့', '၍', 'ခြင်း', 'ုံး', 'ဆင်', 'ွန်', 'အလ', 'တော့', 'မို', 'လ', 'စာ', 'ဿ', 'အမြ', 'တင်', 'အကျ', 'ဲ', 'ူ', 'အုပ်', 'y', 'u', 'ဒါ', 'ရော', 'ပို', 'လိုအ', 'a', 'ိ', 'ဆ', '့', 'x', 'လို', '့်', 'ပြည်', 'ယူ', 'ဃ', 'ဆေး', 'ခံ', 'မွ', 'ဘဲ', 'ုံး', 'ော်', 'လိုက်', 'နေ', 'မျ', 'နိုင်င', 'ံ့', 'မှာ', 'နည်း', 'ရန်', 'လက္ခဏာ', 'ဥ', 'င့်', 'ပညာ', 'ပ်', 'အားဖြင့်', 'နှစ်', 'ဆွေး', 'ဖြစ်သည်', 'ဒ', 'ီ', 'နစ်', 'ကျင်', 'ဋ', 'အများ', 'ဉ', 'မ်း', 'န့်', 'ကွ', 'သို့', 'b', '၀', 'ခု', 'ပုံ', 'တော', 'အာ', 'ဖြင့်', 'ဧ', 'သွား', 'အခါ', 'မ', 'င်း', 'ာ', 'ဆ', 'i', 'ဓ', '၆', 'ကြော', 'ရိ', 'သြ', 'တွေ့', '၌', 'ထိ', 'က္', 'အစ', 'ကြ', 'ရွ', 'ု', 'ေး', 'ွ', 'န်း', 'း', 'ပ', 'ဋ', 'ဆာ', 'အောင်', 'မြို့', 'စိတ်', 'ျ', 'ပြင်ဆင်', 'ါ', 'မဟုတ်', 'ပြု', 'ကိုယ်', 'ရှိ', 'ည', 'ဆောင်', 'ဆွေးနွေး', 'င်', 'n', 'တ်', 'ိုင်း', 'စီ', 'လူ', 'ဍ', 'ဟု', 'ည့်', 'သို့', '္', '႓', 'ိုး', 'န', 'ရေ', 'မယ်', 'ခဲ့သည်', 'ုံ', 'ောင်း', 'ောင်', 'ဦး', 'ထိ', 'တို့', 'ိမ့်', 'x', 'နိုင်ငံ', '၊', 'အပြ', 'ံ', 'ထု', 'ရေး', 'စစ်', 'ီ', 'မှု', 'ရှင်', 'ဦ', 'ရှိသည်', 'ပေါ', 'ဂျ', 'အစား', 'မြန်', 'ခ', 'သာ', 'နှ', 'ပထ', 'ိ', 'သင်', '့်'] - - word_lists = [] - for i in word: - cur = i.replace(' ', '') - cur = cur.replace('', '') - cur = cur.replace('', '') - word_lists.append(cur) - - if len(word_lists) == 0: - return False - - for ch in word_lists: - if ch.isalpha() is False and ch in my_char: - return True - elif ch.isalpha() is True and isChinese(ch) is True: - return False - - return True # def abbr_dispose(words: List[Any]) -> List[Any]: def abbr_dispose(words: List[Any], time_stamp: List[List] = None) -> List[Any]: @@ -244,17 +224,6 @@ def sentence_postprocess(words: List[Any], time_stamp: List[List] = None): end = time_stamp[i][1] ts_lists.append([begin, end]) begin = end - elif isMy(ch): - word_item += ch - word_lists.append(word_item) - word_lists.append(' ') - word_item = '' - alpha_blank = True - if time_stamp is not None: - ts_flag = True - end = time_stamp[i][1] - ts_lists.append([begin, end]) - begin = end else: word_lists.append(ch) From 6be52a387938e40961194dfb79d079ab24137b32 Mon Sep 17 00:00:00 2001 From: "chong.zhang" Date: Wed, 12 Apr 2023 17:37:57 +0800 Subject: [PATCH 031/120] update --- funasr/utils/postprocess_utils.py | 245 ------------------------------ 1 file changed, 245 deletions(-) delete mode 100644 funasr/utils/postprocess_utils.py diff --git a/funasr/utils/postprocess_utils.py b/funasr/utils/postprocess_utils.py deleted file mode 100644 index b607e1da0..000000000 --- a/funasr/utils/postprocess_utils.py +++ /dev/null @@ -1,245 +0,0 @@ -# Copyright (c) Alibaba, Inc. and its affiliates. - -import string -import logging -from typing import Any, List, Union - - -def isChinese(ch: str): - if '\u4e00' <= ch <= '\u9fff' or '\u0030' <= ch <= '\u0039' or ch == '@': - return True - return False - - -def isAllChinese(word: Union[List[Any], str]): - word_lists = [] - for i in word: - cur = i.replace(' ', '') - cur = cur.replace('', '') - cur = cur.replace('', '') - cur = cur.replace('', '') - cur = cur.replace('', '') - word_lists.append(cur) - - if len(word_lists) == 0: - return False - - for ch in word_lists: - if isChinese(ch) is False: - return False - return True - - -def isAllAlpha(word: Union[List[Any], str]): - word_lists = [] - for i in word: - cur = i.replace(' ', '') - cur = cur.replace('', '') - cur = cur.replace('', '') - cur = cur.replace('', '') - cur = cur.replace('', '') - word_lists.append(cur) - - if len(word_lists) == 0: - return False - - for ch in word_lists: - if ch.isalpha() is False and ch != "'": - return False - elif ch.isalpha() is True and isChinese(ch) is True: - return False - - return True - - -# def abbr_dispose(words: List[Any]) -> List[Any]: -def abbr_dispose(words: List[Any], time_stamp: List[List] = None) -> List[Any]: - words_size = len(words) - word_lists = [] - abbr_begin = [] - abbr_end = [] - last_num = -1 - ts_lists = [] - ts_nums = [] - ts_index = 0 - for num in range(words_size): - if num <= last_num: - continue - - if len(words[num]) == 1 and words[num].encode('utf-8').isalpha(): - if num + 1 < words_size and words[ - num + 1] == ' ' and num + 2 < words_size and len( - words[num + - 2]) == 1 and words[num + - 2].encode('utf-8').isalpha(): - # found the begin of abbr - abbr_begin.append(num) - num += 2 - abbr_end.append(num) - # to find the end of abbr - while True: - num += 1 - if num < words_size and words[num] == ' ': - num += 1 - if num < words_size and len( - words[num]) == 1 and words[num].encode( - 'utf-8').isalpha(): - abbr_end.pop() - abbr_end.append(num) - last_num = num - else: - break - else: - break - - for num in range(words_size): - if words[num] == ' ': - ts_nums.append(ts_index) - else: - ts_nums.append(ts_index) - ts_index += 1 - last_num = -1 - for num in range(words_size): - if num <= last_num: - continue - - if num in abbr_begin: - if time_stamp is not None: - begin = time_stamp[ts_nums[num]][0] - abbr_word = words[num].upper() - num += 1 - while num < words_size: - if num in abbr_end: - abbr_word += words[num].upper() - last_num = num - break - else: - if words[num].encode('utf-8').isalpha(): - abbr_word += words[num].upper() - num += 1 - word_lists.append(abbr_word) - if time_stamp is not None: - end = time_stamp[ts_nums[num]][1] - ts_lists.append([begin, end]) - else: - word_lists.append(words[num]) - if time_stamp is not None and words[num] != ' ': - begin = time_stamp[ts_nums[num]][0] - end = time_stamp[ts_nums[num]][1] - ts_lists.append([begin, end]) - begin = end - - if time_stamp is not None: - return word_lists, ts_lists - else: - return word_lists - - -def sentence_postprocess(words: List[Any], time_stamp: List[List] = None): - middle_lists = [] - word_lists = [] - word_item = '' - ts_lists = [] - - # wash words lists - for i in words: - word = '' - if isinstance(i, str): - word = i - else: - word = i.decode('utf-8') - - if word in ['', '', '', '']: - continue - else: - middle_lists.append(word) - - # all chinese characters - if isAllChinese(middle_lists): - for i, ch in enumerate(middle_lists): - word_lists.append(ch.replace(' ', '')) - if time_stamp is not None: - ts_lists = time_stamp - - # all alpha characters - elif isAllAlpha(middle_lists): - ts_flag = True - for i, ch in enumerate(middle_lists): - if ts_flag and time_stamp is not None: - begin = time_stamp[i][0] - end = time_stamp[i][1] - word = '' - if '@@' in ch: - word = ch.replace('@@', '') - word_item += word - if time_stamp is not None: - ts_flag = False - end = time_stamp[i][1] - else: - word_item += ch - word_lists.append(word_item) - word_lists.append(' ') - word_item = '' - if time_stamp is not None: - ts_flag = True - end = time_stamp[i][1] - ts_lists.append([begin, end]) - begin = end - - # mix characters - else: - alpha_blank = False - ts_flag = True - begin = -1 - end = -1 - for i, ch in enumerate(middle_lists): - if ts_flag and time_stamp is not None: - begin = time_stamp[i][0] - end = time_stamp[i][1] - word = '' - if isAllChinese(ch): - if alpha_blank is True: - word_lists.pop() - word_lists.append(ch) - alpha_blank = False - if time_stamp is not None: - ts_flag = True - ts_lists.append([begin, end]) - begin = end - elif '@@' in ch: - word = ch.replace('@@', '') - word_item += word - alpha_blank = False - if time_stamp is not None: - ts_flag = False - end = time_stamp[i][1] - elif isAllAlpha(ch): - word_item += ch - word_lists.append(word_item) - word_lists.append(' ') - word_item = '' - alpha_blank = True - if time_stamp is not None: - ts_flag = True - end = time_stamp[i][1] - ts_lists.append([begin, end]) - begin = end - else: - word_lists.append(ch) - - if time_stamp is not None: - word_lists, ts_lists = abbr_dispose(word_lists, ts_lists) - real_word_lists = [] - for ch in word_lists: - if ch != ' ': - real_word_lists.append(ch) - sentence = ' '.join(real_word_lists).strip() - return sentence, ts_lists, real_word_lists - else: - word_lists = abbr_dispose(word_lists) - real_word_lists = [] - for ch in word_lists: - if ch != ' ': - real_word_lists.append(ch) - sentence = ''.join(word_lists).strip() - return sentence, real_word_lists From 8e202636ac9d0621f26645c58e19bf1416ffa077 Mon Sep 17 00:00:00 2001 From: "chong.zhang" Date: Wed, 12 Apr 2023 17:40:08 +0800 Subject: [PATCH 032/120] udpate --- funasr/utils/postprocess_utils.py | 245 ++++++++++++++++++++++++++++++ 1 file changed, 245 insertions(+) create mode 100644 funasr/utils/postprocess_utils.py diff --git a/funasr/utils/postprocess_utils.py b/funasr/utils/postprocess_utils.py new file mode 100644 index 000000000..b607e1da0 --- /dev/null +++ b/funasr/utils/postprocess_utils.py @@ -0,0 +1,245 @@ +# Copyright (c) Alibaba, Inc. and its affiliates. + +import string +import logging +from typing import Any, List, Union + + +def isChinese(ch: str): + if '\u4e00' <= ch <= '\u9fff' or '\u0030' <= ch <= '\u0039' or ch == '@': + return True + return False + + +def isAllChinese(word: Union[List[Any], str]): + word_lists = [] + for i in word: + cur = i.replace(' ', '') + cur = cur.replace('', '') + cur = cur.replace('', '') + cur = cur.replace('', '') + cur = cur.replace('', '') + word_lists.append(cur) + + if len(word_lists) == 0: + return False + + for ch in word_lists: + if isChinese(ch) is False: + return False + return True + + +def isAllAlpha(word: Union[List[Any], str]): + word_lists = [] + for i in word: + cur = i.replace(' ', '') + cur = cur.replace('', '') + cur = cur.replace('', '') + cur = cur.replace('', '') + cur = cur.replace('', '') + word_lists.append(cur) + + if len(word_lists) == 0: + return False + + for ch in word_lists: + if ch.isalpha() is False and ch != "'": + return False + elif ch.isalpha() is True and isChinese(ch) is True: + return False + + return True + + +# def abbr_dispose(words: List[Any]) -> List[Any]: +def abbr_dispose(words: List[Any], time_stamp: List[List] = None) -> List[Any]: + words_size = len(words) + word_lists = [] + abbr_begin = [] + abbr_end = [] + last_num = -1 + ts_lists = [] + ts_nums = [] + ts_index = 0 + for num in range(words_size): + if num <= last_num: + continue + + if len(words[num]) == 1 and words[num].encode('utf-8').isalpha(): + if num + 1 < words_size and words[ + num + 1] == ' ' and num + 2 < words_size and len( + words[num + + 2]) == 1 and words[num + + 2].encode('utf-8').isalpha(): + # found the begin of abbr + abbr_begin.append(num) + num += 2 + abbr_end.append(num) + # to find the end of abbr + while True: + num += 1 + if num < words_size and words[num] == ' ': + num += 1 + if num < words_size and len( + words[num]) == 1 and words[num].encode( + 'utf-8').isalpha(): + abbr_end.pop() + abbr_end.append(num) + last_num = num + else: + break + else: + break + + for num in range(words_size): + if words[num] == ' ': + ts_nums.append(ts_index) + else: + ts_nums.append(ts_index) + ts_index += 1 + last_num = -1 + for num in range(words_size): + if num <= last_num: + continue + + if num in abbr_begin: + if time_stamp is not None: + begin = time_stamp[ts_nums[num]][0] + abbr_word = words[num].upper() + num += 1 + while num < words_size: + if num in abbr_end: + abbr_word += words[num].upper() + last_num = num + break + else: + if words[num].encode('utf-8').isalpha(): + abbr_word += words[num].upper() + num += 1 + word_lists.append(abbr_word) + if time_stamp is not None: + end = time_stamp[ts_nums[num]][1] + ts_lists.append([begin, end]) + else: + word_lists.append(words[num]) + if time_stamp is not None and words[num] != ' ': + begin = time_stamp[ts_nums[num]][0] + end = time_stamp[ts_nums[num]][1] + ts_lists.append([begin, end]) + begin = end + + if time_stamp is not None: + return word_lists, ts_lists + else: + return word_lists + + +def sentence_postprocess(words: List[Any], time_stamp: List[List] = None): + middle_lists = [] + word_lists = [] + word_item = '' + ts_lists = [] + + # wash words lists + for i in words: + word = '' + if isinstance(i, str): + word = i + else: + word = i.decode('utf-8') + + if word in ['', '', '', '']: + continue + else: + middle_lists.append(word) + + # all chinese characters + if isAllChinese(middle_lists): + for i, ch in enumerate(middle_lists): + word_lists.append(ch.replace(' ', '')) + if time_stamp is not None: + ts_lists = time_stamp + + # all alpha characters + elif isAllAlpha(middle_lists): + ts_flag = True + for i, ch in enumerate(middle_lists): + if ts_flag and time_stamp is not None: + begin = time_stamp[i][0] + end = time_stamp[i][1] + word = '' + if '@@' in ch: + word = ch.replace('@@', '') + word_item += word + if time_stamp is not None: + ts_flag = False + end = time_stamp[i][1] + else: + word_item += ch + word_lists.append(word_item) + word_lists.append(' ') + word_item = '' + if time_stamp is not None: + ts_flag = True + end = time_stamp[i][1] + ts_lists.append([begin, end]) + begin = end + + # mix characters + else: + alpha_blank = False + ts_flag = True + begin = -1 + end = -1 + for i, ch in enumerate(middle_lists): + if ts_flag and time_stamp is not None: + begin = time_stamp[i][0] + end = time_stamp[i][1] + word = '' + if isAllChinese(ch): + if alpha_blank is True: + word_lists.pop() + word_lists.append(ch) + alpha_blank = False + if time_stamp is not None: + ts_flag = True + ts_lists.append([begin, end]) + begin = end + elif '@@' in ch: + word = ch.replace('@@', '') + word_item += word + alpha_blank = False + if time_stamp is not None: + ts_flag = False + end = time_stamp[i][1] + elif isAllAlpha(ch): + word_item += ch + word_lists.append(word_item) + word_lists.append(' ') + word_item = '' + alpha_blank = True + if time_stamp is not None: + ts_flag = True + end = time_stamp[i][1] + ts_lists.append([begin, end]) + begin = end + else: + word_lists.append(ch) + + if time_stamp is not None: + word_lists, ts_lists = abbr_dispose(word_lists, ts_lists) + real_word_lists = [] + for ch in word_lists: + if ch != ' ': + real_word_lists.append(ch) + sentence = ' '.join(real_word_lists).strip() + return sentence, ts_lists, real_word_lists + else: + word_lists = abbr_dispose(word_lists) + real_word_lists = [] + for ch in word_lists: + if ch != ' ': + real_word_lists.append(ch) + sentence = ''.join(word_lists).strip() + return sentence, real_word_lists From fc95f1b35e3bc65c070a96a673f7099d5f255d38 Mon Sep 17 00:00:00 2001 From: "chong.zhang" Date: Fri, 5 May 2023 13:31:45 +0800 Subject: [PATCH 033/120] update docs/modelscope_models.md --- docs/modelscope_models.md | 43 ++++++++++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/docs/modelscope_models.md b/docs/modelscope_models.md index 5f94a09e4..e7c754c8a 100644 --- a/docs/modelscope_models.md +++ b/docs/modelscope_models.md @@ -25,13 +25,27 @@ Here we provided several pretrained models on different datasets. The details of #### UniASR Models -| Model Name | Language | Training Data | Vocab Size | Parameter | Offline/Online | Notes | -|:--------------------------------------------------------------------------------------------------------------------------------------:|:--------:|:--------------------------------:|:----------:|:---------:|:--------------:|:--------------------------------------------------------------------------------------------------------------------------------| -| [UniASR](https://modelscope.cn/models/damo/speech_UniASR_asr_2pass-zh-cn-16k-common-vocab8358-tensorflow1-online/summary) | CN & EN | Alibaba Speech Data (60000hours) | 8358 | 100M | Online | UniASR streaming offline unifying models | -| [UniASR-large](https://modelscope.cn/models/damo/speech_UniASR-large_asr_2pass-zh-cn-16k-common-vocab8358-tensorflow1-offline/summary) | CN & EN | Alibaba Speech Data (60000hours) | 8358 | 220M | Offline | UniASR streaming offline unifying models | -| [UniASR Burmese](https://modelscope.cn/models/damo/speech_UniASR_asr_2pass-my-16k-common-vocab696-pytorch/summary) | Burmese | Alibaba Speech Data (? hours) | 696 | 95M | Online | UniASR streaming offline unifying models | -| [UniASR Hebrew](https://modelscope.cn/models/damo/speech_UniASR_asr_2pass-he-16k-common-vocab1085-pytorch/summary) | Hebrew | Alibaba Speech Data (? hours) | 1085 | 95M | Online | UniASR streaming offline unifying models | -| [UniASR Urdu](https://modelscope.cn/models/damo/speech_UniASR_asr_2pass-ur-16k-common-vocab877-pytorch/summary) | Urdu | Alibaba Speech Data (? hours) | 877 | 95M | Online | UniASR streaming offline unifying models | +| Model Name | Language | Training Data | Vocab Size | Parameter | Offline/Online | Notes | +|:-------------------------------------------------------------------------------------------------------------------------------------------------:|:---------------:|:---------------------------------:|:----------:|:---------:|:--------------:|:--------------------------------------------------------------------------------------------------------------------------------| +| [UniASR](https://modelscope.cn/models/damo/speech_UniASR_asr_2pass-zh-cn-16k-common-vocab8358-tensorflow1-online/summary) | CN & EN | Alibaba Speech Data (60000 hours) | 8358 | 100M | Online | UniASR streaming offline unifying models | +| [UniASR-large](https://modelscope.cn/models/damo/speech_UniASR-large_asr_2pass-zh-cn-16k-common-vocab8358-tensorflow1-offline/summary) | CN & EN | Alibaba Speech Data (60000 hours) | 8358 | 220M | Offline | UniASR streaming offline unifying models | +| [UniASR English](https://modelscope.cn/models/damo/speech_UniASR_asr_2pass-en-16k-common-vocab1080-tensorflow1-online/summary) | EN | Alibaba Speech Data (10000 hours) | 1080 | 95M | Online | UniASR streaming online unifying models | +| [UniASR Russian](https://modelscope.cn/models/damo/speech_UniASR_asr_2pass-ru-16k-common-vocab1664-tensorflow1-online/summary) | RU | Alibaba Speech Data (5000 hours) | 1664 | 95M | Online | UniASR streaming online unifying models | +| [UniASR Japanese](https://modelscope.cn/models/damo/speech_UniASR_asr_2pass-ja-16k-common-vocab93-tensorflow1-online/summary) | JA | Alibaba Speech Data (5000 hours) | 5977 | 95M | Online | UniASR streaming offline unifying models | +| [UniASR Korean](https://modelscope.cn/models/damo/speech_UniASR_asr_2pass-ko-16k-common-vocab6400-tensorflow1-online/summary) | KO | Alibaba Speech Data (2000 hours) | 6400 | 95M | Online | UniASR streaming online unifying models | +| [UniASR Cantonese (CHS)](https://modelscope.cn/models/damo/speech_UniASR_asr_2pass-cantonese-CHS-16k-common-vocab1468-tensorflow1-online/summary) | Cantonese (CHS) | Alibaba Speech Data (5000 hours) | 1468 | 95M | Online | UniASR streaming online unifying models | +| [UniASR Indonesian](https://modelscope.cn/models/damo/speech_UniASR_asr_2pass-id-16k-common-vocab1067-tensorflow1-online/summary) | ID | Alibaba Speech Data (1000 hours) | 1067 | 95M | Online | UniASR streaming offline unifying models | +| [UniASR Vietnamese](https://modelscope.cn/models/damo/speech_UniASR_asr_2pass-vi-16k-common-vocab1001-pytorch-online/summary) | VI | Alibaba Speech Data (1000 hours) | 1001 | 95M | Online | UniASR streaming offline unifying models | +| [UniASR Spanish](https://modelscope.cn/models/damo/speech_UniASR_asr_2pass-es-16k-common-vocab3445-tensorflow1-online/summary) | ES | Alibaba Speech Data (1000 hours) | 3445 | 95M | Online | UniASR streaming online unifying models | +| [UniASR Portuguese](https://modelscope.cn/models/damo/speech_UniASR_asr_2pass-pt-16k-common-vocab1617-tensorflow1-online/summary) | PT | Alibaba Speech Data (1000 hours) | 1617 | 95M | Online | UniASR streaming offline unifying models | +| [UniASR French](https://modelscope.cn/models/damo/speech_UniASR_asr_2pass-fr-16k-common-vocab3472-tensorflow1-online/summary) | FR | Alibaba Speech Data (1000 hours) | 3472 | 95M | Online | UniASR streaming online unifying models | +| [UniASR German](https://modelscope.cn/models/damo/speech_UniASR_asr_2pass-de-16k-common-vocab3690-tensorflow1-online/summary) | GE | Alibaba Speech Data (1000 hours) | 3690 | 95M | Online | UniASR streaming online unifying models | +| [UniASR Persian](https://modelscope.cn/models/damo/speech_UniASR_asr_2pass-fa-16k-common-vocab1257-pytorch-online/summary) | FA | Alibaba Speech Data (1000 hours) | 1257 | 95M | Online | UniASR streaming offline unifying models | +| [UniASR Burmese](https://modelscope.cn/models/damo/speech_UniASR_asr_2pass-my-16k-common-vocab696-pytorch/summary) | MY | Alibaba Speech Data (1000 hours) | 696 | 95M | Online | UniASR streaming offline unifying models | +| [UniASR Hebrew](https://modelscope.cn/models/damo/speech_UniASR_asr_2pass-he-16k-common-vocab1085-pytorch/summary) | HE | Alibaba Speech Data (1000 hours) | 1085 | 95M | Online | UniASR streaming offline unifying models | +| [UniASR Urdu](https://modelscope.cn/models/damo/speech_UniASR_asr_2pass-ur-16k-common-vocab877-pytorch/summary) | UR | Alibaba Speech Data (1000 hours) | 877 | 95M | Online | UniASR streaming offline unifying models | + + #### Conformer Models @@ -92,3 +106,18 @@ Here we provided several pretrained models on different datasets. The details of | Model Name | Language | Training Data | Parameters | Notes | |:--------------------------------------------------------------------------------------------------:|:--------------:|:-------------------:|:----------:|:------| | [TP-Aligner](https://modelscope.cn/models/damo/speech_timestamp_prediction-v1-16k-offline/summary) | CN | Alibaba Speech Data (50000hours) | 37.8M | Timestamp prediction, Mandarin, middle size | + +### Inverse Text Normalization (ITN) Models +| Model Name | Language | Parameters | Notes | +|:----------------------------------------------------------------------------------------------------------------:|:--------:|:----------:|:------| +| [English](https://modelscope.cn/models/damo/speech_inverse_text_processing_fun-text-processing-itn-en/summary) | EN | 1.54M | ITN, ASR post processing | +| [Russian](https://modelscope.cn/models/damo/speech_inverse_text_processing_fun-text-processing-itn-ru/summary) | RU | 1.28M | ITN, ASR post processing | +| [Japanese](https://modelscope.cn/models/damo/speech_inverse_text_processing_fun-text-processing-itn-ja/summary) | JA | 6.8M | ITN, ASR post processing | +| [Korean](https://modelscope.cn/models/damo/speech_inverse_text_processing_fun-text-processing-itn-ko/summary) | KO | 1.28M | InverASR post processing | +| [Indonesian](https://modelscope.cn/models/damo/speech_inverse_text_processing_fun-text-processing-itn-id/summary) | ID | 2.06M | ITN, ASR post processing | +| [Vietnamese](https://modelscope.cn/models/damo/speech_inverse_text_processing_fun-text-processing-itn-vi/summary) | VI | 0.92M | ITN, ASR post processing | +| [Tagalog](https://modelscope.cn/models/damo/speech_inverse_text_processing_fun-text-processing-itn-tl/summary) | TL | 1.28M | ITN, ASR post processing | +| [Spanish](https://modelscope.cn/models/damo/speech_inverse_text_processing_fun-text-processing-itn-es/summary) | ES | 1.28M | ITN, ASR post processing | +| [Portuguese](https://modelscope.cn/models/damo/speech_inverse_text_processing_fun-text-processing-itn-pt/summary) | PT | 1.28M | ITN, ASR post processing | +| [French](https://modelscope.cn/models/damo/speech_inverse_text_processing_fun-text-processing-itn-fr/summary) | FR | 1.28M | InverASR post processing | +| [German](https://modelscope.cn/models/damo/speech_inverse_text_processing_fun-text-processing-itn-de/summary)| GE | 1.28M | ITN, ASR post processing | From 3c4898fe1695f8aaa4fadc495e4aaf5ca54d85e9 Mon Sep 17 00:00:00 2001 From: zhifu gao Date: Fri, 5 May 2023 13:43:14 +0800 Subject: [PATCH 034/120] Update modelscope_models.md --- docs/modelscope_models.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/modelscope_models.md b/docs/modelscope_models.md index e7c754c8a..bdaeb82f2 100644 --- a/docs/modelscope_models.md +++ b/docs/modelscope_models.md @@ -108,6 +108,7 @@ Here we provided several pretrained models on different datasets. The details of | [TP-Aligner](https://modelscope.cn/models/damo/speech_timestamp_prediction-v1-16k-offline/summary) | CN | Alibaba Speech Data (50000hours) | 37.8M | Timestamp prediction, Mandarin, middle size | ### Inverse Text Normalization (ITN) Models + | Model Name | Language | Parameters | Notes | |:----------------------------------------------------------------------------------------------------------------:|:--------:|:----------:|:------| | [English](https://modelscope.cn/models/damo/speech_inverse_text_processing_fun-text-processing-itn-en/summary) | EN | 1.54M | ITN, ASR post processing | From 651a94577326242e68933fba1f9f9bd0e6cab63c Mon Sep 17 00:00:00 2001 From: "shixian.shi" Date: Fri, 5 May 2023 14:09:41 +0800 Subject: [PATCH 035/120] update batch_bins configuration --- funasr/bin/build_trainer.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/funasr/bin/build_trainer.py b/funasr/bin/build_trainer.py index 6bd5bd715..5c30fdb6f 100644 --- a/funasr/bin/build_trainer.py +++ b/funasr/bin/build_trainer.py @@ -132,8 +132,7 @@ def build_trainer(modelscope_dict, if args.dataset_type == "small": args.batch_bins = batch_bins elif args.dataset_type == "large": - if "batch_size" not in args.dataset_conf["batch_conf"]: - args.dataset_conf["batch_conf"]["batch_size"] = batch_bins + args.dataset_conf["batch_conf"]["batch_size"] = batch_bins else: raise ValueError(f"Not supported dataset_type={args.dataset_type}") if args.normalize in ["null", "none", "None"]: From b0b8aba7c079b3af4265e0b25849a847bf9266bf Mon Sep 17 00:00:00 2001 From: nichongjia-2007 <57480507+nichongjia-2007@users.noreply.github.com> Date: Fri, 5 May 2023 14:38:54 +0800 Subject: [PATCH 036/120] Update modelscope_models.md update the conformer --- docs/modelscope_models.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/modelscope_models.md b/docs/modelscope_models.md index bdaeb82f2..97ba33323 100644 --- a/docs/modelscope_models.md +++ b/docs/modelscope_models.md @@ -53,6 +53,7 @@ Here we provided several pretrained models on different datasets. The details of |:----------------------------------------------------------------------------------------------------------------------:|:--------:|:---------------------:|:----------:|:---------:|:--------------:|:--------------------------------------------------------------------------------------------------------------------------------| | [Conformer](https://modelscope.cn/models/damo/speech_conformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/summary) | CN | AISHELL (178hours) | 4234 | 44M | Offline | Duration of input wav <= 20s | | [Conformer](https://www.modelscope.cn/models/damo/speech_conformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch/summary) | CN | AISHELL-2 (1000hours) | 5212 | 44M | Offline | Duration of input wav <= 20s | +| [Conformer](https://modelscope.cn/models/damo/speech_conformer_asr-en-16k-vocab4199-pytorch/summary) | EN | Alibaba Speech Data (10000hours) | 4199 | 220M | Offline | Duration of input wav <= 20s | #### RNN-T Models From 86e72b594ac6e00345b2f52fd0e44e32fa68ee9c Mon Sep 17 00:00:00 2001 From: "chong.zhang" Date: Fri, 5 May 2023 14:46:29 +0800 Subject: [PATCH 037/120] docs/modelscope_models.md --- docs/modelscope_models.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/modelscope_models.md b/docs/modelscope_models.md index bdaeb82f2..96f2ce6cb 100644 --- a/docs/modelscope_models.md +++ b/docs/modelscope_models.md @@ -109,16 +109,16 @@ Here we provided several pretrained models on different datasets. The details of ### Inverse Text Normalization (ITN) Models -| Model Name | Language | Parameters | Notes | -|:----------------------------------------------------------------------------------------------------------------:|:--------:|:----------:|:------| -| [English](https://modelscope.cn/models/damo/speech_inverse_text_processing_fun-text-processing-itn-en/summary) | EN | 1.54M | ITN, ASR post processing | -| [Russian](https://modelscope.cn/models/damo/speech_inverse_text_processing_fun-text-processing-itn-ru/summary) | RU | 1.28M | ITN, ASR post processing | -| [Japanese](https://modelscope.cn/models/damo/speech_inverse_text_processing_fun-text-processing-itn-ja/summary) | JA | 6.8M | ITN, ASR post processing | -| [Korean](https://modelscope.cn/models/damo/speech_inverse_text_processing_fun-text-processing-itn-ko/summary) | KO | 1.28M | InverASR post processing | -| [Indonesian](https://modelscope.cn/models/damo/speech_inverse_text_processing_fun-text-processing-itn-id/summary) | ID | 2.06M | ITN, ASR post processing | -| [Vietnamese](https://modelscope.cn/models/damo/speech_inverse_text_processing_fun-text-processing-itn-vi/summary) | VI | 0.92M | ITN, ASR post processing | -| [Tagalog](https://modelscope.cn/models/damo/speech_inverse_text_processing_fun-text-processing-itn-tl/summary) | TL | 1.28M | ITN, ASR post processing | -| [Spanish](https://modelscope.cn/models/damo/speech_inverse_text_processing_fun-text-processing-itn-es/summary) | ES | 1.28M | ITN, ASR post processing | -| [Portuguese](https://modelscope.cn/models/damo/speech_inverse_text_processing_fun-text-processing-itn-pt/summary) | PT | 1.28M | ITN, ASR post processing | -| [French](https://modelscope.cn/models/damo/speech_inverse_text_processing_fun-text-processing-itn-fr/summary) | FR | 1.28M | InverASR post processing | -| [German](https://modelscope.cn/models/damo/speech_inverse_text_processing_fun-text-processing-itn-de/summary)| GE | 1.28M | ITN, ASR post processing | +| Model Name | Language | Parameters | Notes | +|:----------------------------------------------------------------------------------------------------------------:|:--------:|:----------:|:-------------------------| +| [English](https://modelscope.cn/models/damo/speech_inverse_text_processing_fun-text-processing-itn-en/summary) | EN | 1.54M | ITN, ASR post-processing | +| [Russian](https://modelscope.cn/models/damo/speech_inverse_text_processing_fun-text-processing-itn-ru/summary) | RU | 17.79M | ITN, ASR post-processing | +| [Japanese](https://modelscope.cn/models/damo/speech_inverse_text_processing_fun-text-processing-itn-ja/summary) | JA | 6.8M | ITN, ASR post-processing | +| [Korean](https://modelscope.cn/models/damo/speech_inverse_text_processing_fun-text-processing-itn-ko/summary) | KO | 1.28M | ITN, ASR post-processing | +| [Indonesian](https://modelscope.cn/models/damo/speech_inverse_text_processing_fun-text-processing-itn-id/summary) | ID | 2.06M | ITN, ASR post-processing | +| [Vietnamese](https://modelscope.cn/models/damo/speech_inverse_text_processing_fun-text-processing-itn-vi/summary) | VI | 0.92M | ITN, ASR post-processing | +| [Tagalog](https://modelscope.cn/models/damo/speech_inverse_text_processing_fun-text-processing-itn-tl/summary) | TL | 0.65M | ITN, ASR post-processing | +| [Spanish](https://modelscope.cn/models/damo/speech_inverse_text_processing_fun-text-processing-itn-es/summary) | ES | 1.32M | ITN, ASR post-processing | +| [Portuguese](https://modelscope.cn/models/damo/speech_inverse_text_processing_fun-text-processing-itn-pt/summary) | PT | 1.28M | ITN, ASR post-processing | +| [French](https://modelscope.cn/models/damo/speech_inverse_text_processing_fun-text-processing-itn-fr/summary) | FR | 4.39M | ITN, ASR post-processing | +| [German](https://modelscope.cn/models/damo/speech_inverse_text_processing_fun-text-processing-itn-de/summary)| GE | 3.95M | ITN, ASR post-processing | From 8cbcb7e0d4a2776baa509e3b09ea5258917389d8 Mon Sep 17 00:00:00 2001 From: zhifu gao Date: Fri, 5 May 2023 14:59:50 +0800 Subject: [PATCH 038/120] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 414eb9b89..4128d875f 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ | [**Highlights**](#highlights) | [**Installation**](#installation) | [**Docs**](https://alibaba-damo-academy.github.io/FunASR/en/index.html) -| [**Tutorial**](https://github.com/alibaba-damo-academy/FunASR/wiki#funasr%E7%94%A8%E6%88%B7%E6%89%8B%E5%86%8C) +| [**Tutorial_CN**](https://github.com/alibaba-damo-academy/FunASR/wiki#funasr%E7%94%A8%E6%88%B7%E6%89%8B%E5%86%8C) | [**Papers**](https://github.com/alibaba-damo-academy/FunASR#citations) | [**Runtime**](https://github.com/alibaba-damo-academy/FunASR/tree/main/funasr/runtime) | [**Model Zoo**](https://github.com/alibaba-damo-academy/FunASR/blob/main/docs/modelscope_models.md) From 77af9dfe37def0cc3e88c112b4bcf195092cc1c9 Mon Sep 17 00:00:00 2001 From: zhifu gao Date: Fri, 5 May 2023 15:03:27 +0800 Subject: [PATCH 039/120] v0.4.5 --- funasr/version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/funasr/version.txt b/funasr/version.txt index 6f2743d65..0bfccb080 100644 --- a/funasr/version.txt +++ b/funasr/version.txt @@ -1 +1 @@ -0.4.4 +0.4.5 From fa7297855d2cde0cf5aeacc0991ae8025333942c Mon Sep 17 00:00:00 2001 From: "shixian.shi" Date: Fri, 5 May 2023 15:31:06 +0800 Subject: [PATCH 040/120] update contextual finetune --- .../finetune.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/finetune.py b/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/finetune.py index 676c943af..e4d6682b0 100644 --- a/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/finetune.py +++ b/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/finetune.py @@ -3,7 +3,6 @@ import os from modelscope.metainfo import Trainers from modelscope.trainers import build_trainer -import funasr from funasr.datasets.ms_dataset import MsDataset from funasr.utils.modelscope_param import modelscope_args @@ -27,11 +26,11 @@ def modelscope_finetune(params): if __name__ == '__main__': params = modelscope_args(model="damo/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404", data_path="./data") - params.output_dir = "./checkpoint" # m模型保存路径 + params.output_dir = "./checkpoint" # 模型保存路径 params.data_path = "./example_data/" # 数据路径 - params.dataset_type = "large" # 小数据量设置small,若数据量大于1000小时,请使用large - params.batch_bins = 2000 # batch size,如果dataset_type="small",batch_bins单位为fbank特征帧数,如果dataset_type="large",batch_bins单位为毫秒, - params.max_epoch = 50 # 最大训练轮数 + params.dataset_type = "large" # finetune contextual paraformer模型只能使用large dataset + params.batch_bins = 200000 # batch size,如果dataset_type="small",batch_bins单位为fbank特征帧数,如果dataset_type="large",batch_bins单位为毫秒, + params.max_epoch = 20 # 最大训练轮数 params.lr = 0.00005 # 设置学习率 - - modelscope_finetune(params) + + modelscope_finetune(params) \ No newline at end of file From 41c18ea11bec7bb68ba5eff81f7428df1b7b9c6a Mon Sep 17 00:00:00 2001 From: "chong.zhang" Date: Fri, 5 May 2023 15:33:47 +0800 Subject: [PATCH 041/120] add docs/modelscope_pipeline/itn_pipeline.md --- docs/modelscope_pipeline/itn_pipeline.md | 70 ++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 docs/modelscope_pipeline/itn_pipeline.md diff --git a/docs/modelscope_pipeline/itn_pipeline.md b/docs/modelscope_pipeline/itn_pipeline.md new file mode 100644 index 000000000..7f27f26fd --- /dev/null +++ b/docs/modelscope_pipeline/itn_pipeline.md @@ -0,0 +1,70 @@ +# Inverse Text Normalization (ITN) + +> **Note**: +> The modelscope pipeline supports all the models in [model zoo](https://modelscope.cn/models?page=1&tasks=inverse-text-processing&type=audio) to inference. Here we take the model of the Japanese ITN model as example to demonstrate the usage. + +## Inference + +### Quick start +#### [Japanese ITN model](https://modelscope.cn/models/damo/speech_inverse_text_processing_fun-text-processing-itn-ja/summary) +```python +from modelscope.pipelines import pipeline +from modelscope.utils.constant import Tasks + +itn_inference_pipline = pipeline( + task=Tasks.inverse_text_processing, + model='damo/speech_inverse_text_processing_fun-text-processing-itn-ja', + model_revision=None) + +itn_result = itn_inference_pipline(text_in='百二十三') +print(itn_result) +``` +- read text data directly. +```python +rec_result = inference_pipeline(text_in='一九九九年に誕生した同商品にちなみ、約三十年前、二十四歳の頃の幸四郎の写真を公開。') +``` +- text stored via url,example:https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_text/ja_itn_example.txt +```python +rec_result = inference_pipeline(text_in='https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_text/ja_itn_example.txt') +``` + +Full code of demo, please ref to [demo](https://github.com/alibaba-damo-academy/FunASR/tree/main/fun_text_processing/inverse_text_normalization) + +#### Modify Your Own ITN Model +The rule-based ITN code is open-sourced in [FunTextProcessing](https://github.com/alibaba-damo-academy/FunASR/tree/main/fun_text_processing), users can modify by their own grammar rules. After modify the rules, the users can export their own ITN models in local directory. + +##### Export ITN Model +Use the code in FunASR to export ITN model. An example to export ITN model to local folder is shown as below. +```shell +cd fun_text_processing/inverse_text_normalization/ +python export_models.py --language ja --export_dir ./itn_models/ +``` + +##### Evaluate ITN Model +Users can evaluate their own ITN model in local directory. Here is an example: +```shell +python fun_text_processing/inverse_text_normalization/inverse_normalize.py --input_file ja_itn_example.txt --cache_dir ./itn_models/ --output_file output.txt --language=ja +``` + +### API-reference +#### Define pipeline +- `task`: `Tasks.inverse_text_processing` +- `model`: model name in [model zoo](https://modelscope.cn/models?page=1&tasks=inverse-text-processing&type=audio), or model path in local disk +- `output_dir`: `None` (Default), the output path of results if set +- `model_revision`: `None` (Default), setting the model version + +#### Infer pipeline +- `text_in`: the input to decode, which could be: + - text bytes, `e.g.`: "一九九九年に誕生した同商品にちなみ、約三十年前、二十四歳の頃の幸四郎の写真を公開。" + - text file, `e.g.`: https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_text/ja_itn_example.txt + In this case of `text file` input, `output_dir` must be set to save the output results + + +## Finetune with pipeline + +### Quick start + +### Finetune with your data + +## Inference with your finetuned model + From 653fffdf29fc77ea9203d0cffdcc760f55a61dd5 Mon Sep 17 00:00:00 2001 From: "shixian.shi" Date: Fri, 5 May 2023 16:14:20 +0800 Subject: [PATCH 042/120] update lr and bias_grad_times --- .../finetune.py | 2 +- funasr/tasks/abs_task.py | 6 ++++++ funasr/train/trainer.py | 15 +++++++++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/finetune.py b/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/finetune.py index e4d6682b0..34c7cf949 100644 --- a/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/finetune.py +++ b/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/finetune.py @@ -31,6 +31,6 @@ if __name__ == '__main__': params.dataset_type = "large" # finetune contextual paraformer模型只能使用large dataset params.batch_bins = 200000 # batch size,如果dataset_type="small",batch_bins单位为fbank特征帧数,如果dataset_type="large",batch_bins单位为毫秒, params.max_epoch = 20 # 最大训练轮数 - params.lr = 0.00005 # 设置学习率 + params.lr = 0.0002 # 设置学习率 modelscope_finetune(params) \ No newline at end of file diff --git a/funasr/tasks/abs_task.py b/funasr/tasks/abs_task.py index 3d2004c2d..31057f93d 100644 --- a/funasr/tasks/abs_task.py +++ b/funasr/tasks/abs_task.py @@ -548,6 +548,12 @@ class AbsTask(ABC): default=1, help="The number of gradient accumulation", ) + group.add_argument( + "--bias_grad_times", + type=float, + default=1.0, + help="To scale the gradient of contextual related params", + ) group.add_argument( "--no_forward_run", type=str2bool, diff --git a/funasr/train/trainer.py b/funasr/train/trainer.py index 7c187e999..405268a28 100644 --- a/funasr/train/trainer.py +++ b/funasr/train/trainer.py @@ -3,6 +3,7 @@ """Trainer module.""" import argparse +from audioop import bias from contextlib import contextmanager import dataclasses from dataclasses import is_dataclass @@ -95,6 +96,7 @@ class TrainerOptions: use_pai: bool oss_bucket: Union[oss2.Bucket, None] batch_interval: int + bias_grad_times: float class Trainer: """Trainer having a optimizer. @@ -546,8 +548,11 @@ class Trainer: no_forward_run = options.no_forward_run ngpu = options.ngpu use_wandb = options.use_wandb + bias_grad_times = options.bias_grad_times distributed = distributed_option.distributed + if bias_grad_times != 1.0: + logging.warning("Using bias_grad_times: {} for gradient scaling".format(bias_grad_times)) if log_interval is None: try: log_interval = max(len(iterator) // 20, 10) @@ -690,6 +695,16 @@ class Trainer: scale_factor=0.55, ) + # for contextual training + if bias_grad_times != 1.0: + # contextual related parameter names + cr_pnames = ["bias_encoder", "bias_embed", "decoder.bias_decoder", "decoder.bias_output"] + for name, param in model.named_parameters(): + for cr_pname in cr_pnames: + if cr_pname in name: + param.grad *= bias_grad_times + continue + # compute the gradient norm to check if it is normal or not grad_norm = torch.nn.utils.clip_grad_norm_( model.parameters(), From f72d19508c82a13369f9031bc1e3d7f238119250 Mon Sep 17 00:00:00 2001 From: "shixian.shi" Date: Fri, 5 May 2023 16:24:03 +0800 Subject: [PATCH 043/120] update model_revision --- .../finetune.py | 1 + 1 file changed, 1 insertion(+) diff --git a/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/finetune.py b/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/finetune.py index 34c7cf949..9d08923f8 100644 --- a/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/finetune.py +++ b/egs_modelscope/asr/paraformer/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/finetune.py @@ -14,6 +14,7 @@ def modelscope_finetune(params): ds_dict = MsDataset.load(params.data_path) kwargs = dict( model=params.model, + model_revision="v1.0.2", data_dir=ds_dict, dataset_type=params.dataset_type, work_dir=params.output_dir, From 52aa3c36665f551c9dc70f73c7023aa699c5b720 Mon Sep 17 00:00:00 2001 From: "shixian.shi" Date: Fri, 5 May 2023 16:25:52 +0800 Subject: [PATCH 044/120] bug fix --- funasr/train/trainer.py | 1 - 1 file changed, 1 deletion(-) diff --git a/funasr/train/trainer.py b/funasr/train/trainer.py index 405268a28..a40f031a5 100644 --- a/funasr/train/trainer.py +++ b/funasr/train/trainer.py @@ -3,7 +3,6 @@ """Trainer module.""" import argparse -from audioop import bias from contextlib import contextmanager import dataclasses from dataclasses import is_dataclass From 04c74dabf5944935258fc74fe5d5a685496c77c7 Mon Sep 17 00:00:00 2001 From: "chong.zhang" Date: Fri, 5 May 2023 16:29:05 +0800 Subject: [PATCH 045/120] add itn_pipeline.md --- docs/modelscope_pipeline/itn_pipeline.md | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/docs/modelscope_pipeline/itn_pipeline.md b/docs/modelscope_pipeline/itn_pipeline.md index 7f27f26fd..15380f3aa 100644 --- a/docs/modelscope_pipeline/itn_pipeline.md +++ b/docs/modelscope_pipeline/itn_pipeline.md @@ -30,17 +30,17 @@ rec_result = inference_pipeline(text_in='https://isv-data.oss-cn-hangzhou.aliyun Full code of demo, please ref to [demo](https://github.com/alibaba-damo-academy/FunASR/tree/main/fun_text_processing/inverse_text_normalization) -#### Modify Your Own ITN Model +### Modify Your Own ITN Model The rule-based ITN code is open-sourced in [FunTextProcessing](https://github.com/alibaba-damo-academy/FunASR/tree/main/fun_text_processing), users can modify by their own grammar rules. After modify the rules, the users can export their own ITN models in local directory. -##### Export ITN Model +### Export ITN Model Use the code in FunASR to export ITN model. An example to export ITN model to local folder is shown as below. ```shell cd fun_text_processing/inverse_text_normalization/ python export_models.py --language ja --export_dir ./itn_models/ ``` -##### Evaluate ITN Model +### Evaluate ITN Model Users can evaluate their own ITN model in local directory. Here is an example: ```shell python fun_text_processing/inverse_text_normalization/inverse_normalize.py --input_file ja_itn_example.txt --cache_dir ./itn_models/ --output_file output.txt --language=ja @@ -58,13 +58,4 @@ python fun_text_processing/inverse_text_normalization/inverse_normalize.py --inp - text bytes, `e.g.`: "一九九九年に誕生した同商品にちなみ、約三十年前、二十四歳の頃の幸四郎の写真を公開。" - text file, `e.g.`: https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_text/ja_itn_example.txt In this case of `text file` input, `output_dir` must be set to save the output results - - -## Finetune with pipeline - -### Quick start - -### Finetune with your data - -## Inference with your finetuned model - + \ No newline at end of file From 9723253549110c6a210001f4c7ec3912a37b874c Mon Sep 17 00:00:00 2001 From: "chong.zhang" Date: Fri, 5 May 2023 16:35:21 +0800 Subject: [PATCH 046/120] add itn_pipeline.md --- docs/modelscope_pipeline/itn_pipeline.md | 35 ++++++++++++------------ 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/docs/modelscope_pipeline/itn_pipeline.md b/docs/modelscope_pipeline/itn_pipeline.md index 15380f3aa..4d3f6b33d 100644 --- a/docs/modelscope_pipeline/itn_pipeline.md +++ b/docs/modelscope_pipeline/itn_pipeline.md @@ -18,10 +18,12 @@ itn_inference_pipline = pipeline( itn_result = itn_inference_pipline(text_in='百二十三') print(itn_result) +# 123 ``` - read text data directly. ```python rec_result = inference_pipeline(text_in='一九九九年に誕生した同商品にちなみ、約三十年前、二十四歳の頃の幸四郎の写真を公開。') +# 1999年に誕生した同商品にちなみ、約30年前、24歳の頃の幸四郎の写真を公開。 ``` - text stored via url,example:https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_text/ja_itn_example.txt ```python @@ -30,22 +32,6 @@ rec_result = inference_pipeline(text_in='https://isv-data.oss-cn-hangzhou.aliyun Full code of demo, please ref to [demo](https://github.com/alibaba-damo-academy/FunASR/tree/main/fun_text_processing/inverse_text_normalization) -### Modify Your Own ITN Model -The rule-based ITN code is open-sourced in [FunTextProcessing](https://github.com/alibaba-damo-academy/FunASR/tree/main/fun_text_processing), users can modify by their own grammar rules. After modify the rules, the users can export their own ITN models in local directory. - -### Export ITN Model -Use the code in FunASR to export ITN model. An example to export ITN model to local folder is shown as below. -```shell -cd fun_text_processing/inverse_text_normalization/ -python export_models.py --language ja --export_dir ./itn_models/ -``` - -### Evaluate ITN Model -Users can evaluate their own ITN model in local directory. Here is an example: -```shell -python fun_text_processing/inverse_text_normalization/inverse_normalize.py --input_file ja_itn_example.txt --cache_dir ./itn_models/ --output_file output.txt --language=ja -``` - ### API-reference #### Define pipeline - `task`: `Tasks.inverse_text_processing` @@ -58,4 +44,19 @@ python fun_text_processing/inverse_text_normalization/inverse_normalize.py --inp - text bytes, `e.g.`: "一九九九年に誕生した同商品にちなみ、約三十年前、二十四歳の頃の幸四郎の写真を公開。" - text file, `e.g.`: https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_text/ja_itn_example.txt In this case of `text file` input, `output_dir` must be set to save the output results - \ No newline at end of file + +## Modify Your Own ITN Model +The rule-based ITN code is open-sourced in [FunTextProcessing](https://github.com/alibaba-damo-academy/FunASR/tree/main/fun_text_processing), users can modify by their own grammar rules for different languages. Let's take Japanese as an example, users can add their own whitelist in fun_text_processing/inverse_text_normalization/ja/data/whitelist.tsv. After modify the rules, the users can export their own ITN models in local directory. + +### Export ITN Model +Use the code in FunASR to export ITN model. An example to export ITN model to local folder is shown as below. +```shell +cd fun_text_processing/inverse_text_normalization/ +python export_models.py --language ja --export_dir ./itn_models/ +``` + +### Evaluate ITN Model +Users can evaluate their own ITN model in local directory. Here is an example: +```shell +python fun_text_processing/inverse_text_normalization/inverse_normalize.py --input_file ja_itn_example.txt --cache_dir ./itn_models/ --output_file output.txt --language=ja +``` \ No newline at end of file From 8b3b594303fda83dba30770cb061334707460b04 Mon Sep 17 00:00:00 2001 From: "chong.zhang" Date: Fri, 5 May 2023 16:43:06 +0800 Subject: [PATCH 047/120] update itn_pipeline.md --- docs/modelscope_pipeline/itn_pipeline.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/modelscope_pipeline/itn_pipeline.md b/docs/modelscope_pipeline/itn_pipeline.md index 4d3f6b33d..23368425c 100644 --- a/docs/modelscope_pipeline/itn_pipeline.md +++ b/docs/modelscope_pipeline/itn_pipeline.md @@ -46,17 +46,18 @@ Full code of demo, please ref to [demo](https://github.com/alibaba-damo-academy/ In this case of `text file` input, `output_dir` must be set to save the output results ## Modify Your Own ITN Model -The rule-based ITN code is open-sourced in [FunTextProcessing](https://github.com/alibaba-damo-academy/FunASR/tree/main/fun_text_processing), users can modify by their own grammar rules for different languages. Let's take Japanese as an example, users can add their own whitelist in fun_text_processing/inverse_text_normalization/ja/data/whitelist.tsv. After modify the rules, the users can export their own ITN models in local directory. +The rule-based ITN code is open-sourced in [FunTextProcessing](https://github.com/alibaba-damo-academy/FunASR/tree/main/fun_text_processing), users can modify by their own grammar rules for different languages. Let's take Japanese as an example, users can add their own whitelist in ```FunASR/fun_text_processing/inverse_text_normalization/ja/data/whitelist.tsv```. After modified the grammar rules, the users can export and evaluate their own ITN models in local directory. ### Export ITN Model -Use the code in FunASR to export ITN model. An example to export ITN model to local folder is shown as below. +Export ITN model via ```FunASR/fun_text_processing/inverse_text_normalization/export_models.py```. An example to export ITN model to local folder is shown as below. ```shell -cd fun_text_processing/inverse_text_normalization/ +cd FunASR/fun_text_processing/inverse_text_normalization/ python export_models.py --language ja --export_dir ./itn_models/ ``` ### Evaluate ITN Model -Users can evaluate their own ITN model in local directory. Here is an example: +Users can evaluate their own ITN model in local directory via ```FunASR/fun_text_processing/inverse_text_normalization/inverse_normalize.py```. Here is an example: ```shell -python fun_text_processing/inverse_text_normalization/inverse_normalize.py --input_file ja_itn_example.txt --cache_dir ./itn_models/ --output_file output.txt --language=ja +cd FunASR/fun_text_processing/inverse_text_normalization/ +python inverse_normalize.py --input_file ja_itn_example.txt --cache_dir ./itn_models/ --output_file output.txt --language=ja ``` \ No newline at end of file From 5f7f2ae41dac5264d33c88e6c0a7286b9542fa2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=98=89=E6=B8=8A?= Date: Fri, 5 May 2023 16:44:53 +0800 Subject: [PATCH 048/120] update repo --- docs/README.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 docs/README.md diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 000000000..91de3c6ff --- /dev/null +++ b/docs/README.md @@ -0,0 +1,19 @@ +# FunASR document generation + +## Generate HTML +For convenience, we provide users with the ability to generate local HTML manually. + +First, you should install the following packages, which is required for building HTML: +```sh +conda activate funasr +pip install requests sphinx nbsphinx sphinx_markdown_tables sphinx_rtd_theme recommonmark +``` + +Then you can generate HTML manually. + +```sh +cd FunASR/docs +make html +``` + +The generated files are all contained in the "FunASR/docs/_build" directory. You can access the FunASR documentation by simply opening the "html/index.html" file in your browser from this directory.~~ \ No newline at end of file From 4935dd9e437fecf2dbc5de890616964110546cc6 Mon Sep 17 00:00:00 2001 From: zhifu gao Date: Fri, 5 May 2023 16:58:59 +0800 Subject: [PATCH 049/120] Update index.rst --- docs/index.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/index.rst b/docs/index.rst index b8fcacdeb..890768e4f 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -44,6 +44,7 @@ Overview ./modelscope_pipeline/tp_pipeline.md ./modelscope_pipeline/sv_pipeline.md ./modelscope_pipeline/sd_pipeline.md + ./modelscope_pipeline/itn_pipeline.md .. toctree:: :maxdepth: 1 From 5f602de8b6bae6120443dfd787ac9b36f5565a4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=B8=E9=9B=81?= Date: Fri, 5 May 2023 17:32:00 +0800 Subject: [PATCH 050/120] docs --- docs/README.md | 4 ++-- docs/index.rst | 16 ++++++++-------- docs/{ => installation}/docker.md | 0 docs/{ => installation}/installation.md | 0 docs/{ => model_zoo}/huggingface_models.md | 0 docs/{ => model_zoo}/modelscope_models.md | 0 docs/{ => reference}/FQA.md | 0 docs/{ => reference}/application.md | 0 docs/{ => reference}/build_task.md | 0 docs/{ => reference}/papers.md | 0 10 files changed, 10 insertions(+), 10 deletions(-) rename docs/{ => installation}/docker.md (100%) rename docs/{ => installation}/installation.md (100%) rename docs/{ => model_zoo}/huggingface_models.md (100%) rename docs/{ => model_zoo}/modelscope_models.md (100%) rename docs/{ => reference}/FQA.md (100%) rename docs/{ => reference}/application.md (100%) rename docs/{ => reference}/build_task.md (100%) rename docs/{ => reference}/papers.md (100%) diff --git a/docs/README.md b/docs/README.md index 91de3c6ff..4e16b046f 100644 --- a/docs/README.md +++ b/docs/README.md @@ -12,8 +12,8 @@ pip install requests sphinx nbsphinx sphinx_markdown_tables sphinx_rtd_theme rec Then you can generate HTML manually. ```sh -cd FunASR/docs +cd docs make html ``` -The generated files are all contained in the "FunASR/docs/_build" directory. You can access the FunASR documentation by simply opening the "html/index.html" file in your browser from this directory.~~ \ No newline at end of file +The generated files are all contained in the "FunASR/docs/_build" directory. You can access the FunASR documentation by simply opening the "html/index.html" file in your browser from this directory. \ No newline at end of file diff --git a/docs/index.rst b/docs/index.rst index 890768e4f..c2656bded 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -17,8 +17,8 @@ Overview :maxdepth: 1 :caption: Installation - ./installation.md - ./docker.md + ./installation/installation.md + ./installation/docker.md .. toctree:: :maxdepth: 1 @@ -57,8 +57,8 @@ Overview :maxdepth: 1 :caption: Model Zoo - ./modelscope_models.md - ./huggingface_models.md + ./model_zoo/modelscope_models.md + ./model_zoo/huggingface_models.md .. toctree:: :maxdepth: 1 @@ -86,25 +86,25 @@ Overview :maxdepth: 1 :caption: Funasr Library - ./build_task.md + ./reference/build_task.md .. toctree:: :maxdepth: 1 :caption: Papers - ./papers.md + ./reference/papers.md .. toctree:: :maxdepth: 1 :caption: Application - ./application.md + ./reference/application.md .. toctree:: :maxdepth: 1 :caption: FQA - ./FQA.md + ./reference/FQA.md Indices and tables diff --git a/docs/docker.md b/docs/installation/docker.md similarity index 100% rename from docs/docker.md rename to docs/installation/docker.md diff --git a/docs/installation.md b/docs/installation/installation.md similarity index 100% rename from docs/installation.md rename to docs/installation/installation.md diff --git a/docs/huggingface_models.md b/docs/model_zoo/huggingface_models.md similarity index 100% rename from docs/huggingface_models.md rename to docs/model_zoo/huggingface_models.md diff --git a/docs/modelscope_models.md b/docs/model_zoo/modelscope_models.md similarity index 100% rename from docs/modelscope_models.md rename to docs/model_zoo/modelscope_models.md diff --git a/docs/FQA.md b/docs/reference/FQA.md similarity index 100% rename from docs/FQA.md rename to docs/reference/FQA.md diff --git a/docs/application.md b/docs/reference/application.md similarity index 100% rename from docs/application.md rename to docs/reference/application.md diff --git a/docs/build_task.md b/docs/reference/build_task.md similarity index 100% rename from docs/build_task.md rename to docs/reference/build_task.md diff --git a/docs/papers.md b/docs/reference/papers.md similarity index 100% rename from docs/papers.md rename to docs/reference/papers.md From 20619400eb3587afd7a975fb57b1a79a5c1e89fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=B8=E9=9B=81?= Date: Fri, 5 May 2023 17:50:28 +0800 Subject: [PATCH 051/120] vad bug --- .gitignore | 3 ++- funasr/bin/vad_inference.py | 2 -- funasr/bin/vad_inference_online.py | 1 - 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 33b8c3979..c4b031f5b 100644 --- a/.gitignore +++ b/.gitignore @@ -16,4 +16,5 @@ MaaS-lib .egg* dist build -funasr.egg-info \ No newline at end of file +funasr.egg-info +docs/_build \ No newline at end of file diff --git a/funasr/bin/vad_inference.py b/funasr/bin/vad_inference.py index 387b6228a..f9dc39770 100644 --- a/funasr/bin/vad_inference.py +++ b/funasr/bin/vad_inference.py @@ -352,7 +352,6 @@ def inference_modelscope( item = {'key': keys[i], 'value': results[i]} vad_results.append(item) if writer is not None: - results[i] = json.loads(results[i]) ibest_writer["text"][keys[i]] = "{}".format(results[i]) return vad_results @@ -466,7 +465,6 @@ def inference_modelscope_online( item = {'key': keys[i], 'value': results[i]} vad_results.append(item) if writer is not None: - results[i] = json.loads(results[i]) ibest_writer["text"][keys[i]] = "{}".format(results[i]) return vad_results diff --git a/funasr/bin/vad_inference_online.py b/funasr/bin/vad_inference_online.py index 4d026207d..e1dbcf256 100644 --- a/funasr/bin/vad_inference_online.py +++ b/funasr/bin/vad_inference_online.py @@ -243,7 +243,6 @@ def inference_modelscope( item = {'key': keys[i], 'value': results[i]} vad_results.append(item) if writer is not None: - results[i] = json.loads(results[i]) ibest_writer["text"][keys[i]] = "{}".format(results[i]) return vad_results From 1fadb21eb61dc0e4df987eaf0f9c59bdacec6ca4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=B8=E9=9B=81?= Date: Fri, 5 May 2023 18:49:33 +0800 Subject: [PATCH 052/120] docs --- docs/modelscope_pipeline/quick_start.md | 2 +- egs_modelscope/asr/TEMPLATE/README.md | 6 +++--- egs_modelscope/punctuation/TEMPLATE/README.md | 6 +++--- egs_modelscope/speaker_diarization/TEMPLATE/README.md | 4 ++-- egs_modelscope/speaker_verification/TEMPLATE/README.md | 4 ++-- egs_modelscope/tp/TEMPLATE/README.md | 4 ++-- egs_modelscope/vad/TEMPLATE/README.md | 6 +++--- 7 files changed, 16 insertions(+), 16 deletions(-) diff --git a/docs/modelscope_pipeline/quick_start.md b/docs/modelscope_pipeline/quick_start.md index 436fb1d86..7e35e9159 100644 --- a/docs/modelscope_pipeline/quick_start.md +++ b/docs/modelscope_pipeline/quick_start.md @@ -1,7 +1,7 @@ # Quick Start > **Note**: -> The modelscope pipeline supports all the models in [model zoo](https://alibaba-damo-academy.github.io/FunASR/en/modelscope_models.html#pretrained-models-on-modelscope) to inference and finetine. Here we take typic model as example to demonstrate the usage. +> The modelscope pipeline supports all the models in [model zoo](https://alibaba-damo-academy.github.io/FunASR/en/model_zoo/modelscope_models.html#pretrained-models-on-modelscope) to inference and finetine. Here we take typic model as example to demonstrate the usage. ## Inference with pipeline diff --git a/egs_modelscope/asr/TEMPLATE/README.md b/egs_modelscope/asr/TEMPLATE/README.md index 30ae8c990..06daf26a5 100644 --- a/egs_modelscope/asr/TEMPLATE/README.md +++ b/egs_modelscope/asr/TEMPLATE/README.md @@ -1,7 +1,7 @@ # Speech Recognition > **Note**: -> The modelscope pipeline supports all the models in [model zoo](https://alibaba-damo-academy.github.io/FunASR/en/modelscope_models.html#pretrained-models-on-modelscope) to inference and finetine. Here we take the typic models as examples to demonstrate the usage. +> The modelscope pipeline supports all the models in [model zoo](https://alibaba-damo-academy.github.io/FunASR/en/model_zoo/modelscope_models.html#pretrained-models-on-modelscope) to inference and finetine. Here we take the typic models as examples to demonstrate the usage. ## Inference @@ -79,7 +79,7 @@ print(rec_result) ### API-reference #### Define pipeline - `task`: `Tasks.auto_speech_recognition` -- `model`: model name in [model zoo](https://alibaba-damo-academy.github.io/FunASR/en/modelscope_models.html#pretrained-models-on-modelscope), or model path in local disk +- `model`: model name in [model zoo](https://alibaba-damo-academy.github.io/FunASR/en/model_zoo/modelscope_models.html#pretrained-models-on-modelscope), or model path in local disk - `ngpu`: `1` (Default), decoding on GPU. If ngpu=0, decoding on CPU - `ncpu`: `1` (Default), sets the number of threads used for intraop parallelism on CPU - `output_dir`: `None` (Default), the output path of results if set @@ -103,7 +103,7 @@ print(rec_result) FunASR also offer recipes [egs_modelscope/asr/TEMPLATE/infer.sh](https://github.com/alibaba-damo-academy/FunASR/blob/main/egs_modelscope/asr/TEMPLATE/infer.sh) to decode with multi-thread CPUs, or multi GPUs. #### Settings of `infer.sh` -- `model`: model name in [model zoo](https://alibaba-damo-academy.github.io/FunASR/en/modelscope_models.html#pretrained-models-on-modelscope), or model path in local disk +- `model`: model name in [model zoo](https://alibaba-damo-academy.github.io/FunASR/en/model_zoo/modelscope_models.html#pretrained-models-on-modelscope), or model path in local disk - `data_dir`: the dataset dir needs to include `wav.scp`. If `${data_dir}/text` is also exists, CER will be computed - `output_dir`: output dir of the recognition results - `batch_size`: `64` (Default), batch size of inference on gpu diff --git a/egs_modelscope/punctuation/TEMPLATE/README.md b/egs_modelscope/punctuation/TEMPLATE/README.md index dfbe04480..08814ea44 100644 --- a/egs_modelscope/punctuation/TEMPLATE/README.md +++ b/egs_modelscope/punctuation/TEMPLATE/README.md @@ -1,7 +1,7 @@ # Punctuation Restoration > **Note**: -> The modelscope pipeline supports all the models in [model zoo](https://alibaba-damo-academy.github.io/FunASR/en/modelscope_models.html#pretrained-models-on-modelscope) to inference and finetune. Here we take the model of the punctuation model of CT-Transformer as example to demonstrate the usage. +> The modelscope pipeline supports all the models in [model zoo](https://alibaba-damo-academy.github.io/FunASR/en/model_zoo/modelscope_models.html#pretrained-models-on-modelscope) to inference and finetune. Here we take the model of the punctuation model of CT-Transformer as example to demonstrate the usage. ## Inference @@ -55,7 +55,7 @@ Full code of demo, please ref to [demo](https://github.com/alibaba-damo-academy/ ### API-reference #### Define pipeline - `task`: `Tasks.punctuation` -- `model`: model name in [model zoo](https://alibaba-damo-academy.github.io/FunASR/en/modelscope_models.html#pretrained-models-on-modelscope), or model path in local disk +- `model`: model name in [model zoo](https://alibaba-damo-academy.github.io/FunASR/en/model_zoo/modelscope_models.html#pretrained-models-on-modelscope), or model path in local disk - `ngpu`: `1` (Default), decoding on GPU. If ngpu=0, decoding on CPU - `output_dir`: `None` (Default), the output path of results if set - `model_revision`: `None` (Default), setting the model version @@ -71,7 +71,7 @@ Full code of demo, please ref to [demo](https://github.com/alibaba-damo-academy/ FunASR also offer recipes [egs_modelscope/punctuation/TEMPLATE/infer.sh](https://github.com/alibaba-damo-academy/FunASR/blob/main/egs_modelscope/punctuation/TEMPLATE/infer.sh) to decode with multi-thread CPUs, or multi GPUs. It is an offline recipe and only support offline model. #### Settings of `infer.sh` -- `model`: model name in [model zoo](https://alibaba-damo-academy.github.io/FunASR/en/modelscope_models.html#pretrained-models-on-modelscope), or model path in local disk +- `model`: model name in [model zoo](https://alibaba-damo-academy.github.io/FunASR/en/model_zoo/modelscope_models.html#pretrained-models-on-modelscope), or model path in local disk - `data_dir`: the dataset dir needs to include `punc.txt` - `output_dir`: output dir of the recognition results - `gpu_inference`: `true` (Default), whether to perform gpu decoding, set false for CPU inference diff --git a/egs_modelscope/speaker_diarization/TEMPLATE/README.md b/egs_modelscope/speaker_diarization/TEMPLATE/README.md index 99c9b593c..ba179ed58 100644 --- a/egs_modelscope/speaker_diarization/TEMPLATE/README.md +++ b/egs_modelscope/speaker_diarization/TEMPLATE/README.md @@ -2,7 +2,7 @@ > **Note**: > The modelscope pipeline supports all the models in -[model zoo](https://alibaba-damo-academy.github.io/FunASR/en/modelscope_models.html#pretrained-models-on-modelscope) +[model zoo](https://alibaba-damo-academy.github.io/FunASR/en/model_zoo/modelscope_models.html#pretrained-models-on-modelscope) to inference and finetine. Here we take the model of xvector_sv as example to demonstrate the usage. ## Inference with pipeline @@ -40,7 +40,7 @@ print(results) ### API-reference #### Define pipeline - `task`: `Tasks.speaker_diarization` -- `model`: model name in [model zoo](https://alibaba-damo-academy.github.io/FunASR/en/modelscope_models.html#pretrained-models-on-modelscope), or model path in local disk +- `model`: model name in [model zoo](https://alibaba-damo-academy.github.io/FunASR/en/model_zoo/modelscope_models.html#pretrained-models-on-modelscope), or model path in local disk - `ngpu`: `1` (Default), decoding on GPU. If ngpu=0, decoding on CPU - `output_dir`: `None` (Default), the output path of results if set - `batch_size`: `1` (Default), batch size when decoding diff --git a/egs_modelscope/speaker_verification/TEMPLATE/README.md b/egs_modelscope/speaker_verification/TEMPLATE/README.md index f7b64ce4b..d6736e378 100644 --- a/egs_modelscope/speaker_verification/TEMPLATE/README.md +++ b/egs_modelscope/speaker_verification/TEMPLATE/README.md @@ -2,7 +2,7 @@ > **Note**: > The modelscope pipeline supports all the models in -[model zoo](https://alibaba-damo-academy.github.io/FunASR/en/modelscope_models.html#pretrained-models-on-modelscope) +[model zoo](https://alibaba-damo-academy.github.io/FunASR/en/model_zoo/modelscope_models.html#pretrained-models-on-modelscope) to inference and finetine. Here we take the model of xvector_sv as example to demonstrate the usage. ## Inference with pipeline @@ -50,7 +50,7 @@ Full code of demo, please ref to [infer.py](https://github.com/alibaba-damo-acad ### API-reference #### Define pipeline - `task`: `Tasks.speaker_verification` -- `model`: model name in [model zoo](https://alibaba-damo-academy.github.io/FunASR/en/modelscope_models.html#pretrained-models-on-modelscope), or model path in local disk +- `model`: model name in [model zoo](https://alibaba-damo-academy.github.io/FunASR/en/model_zoo/modelscope_models.html#pretrained-models-on-modelscope), or model path in local disk - `ngpu`: `1` (Default), decoding on GPU. If ngpu=0, decoding on CPU - `output_dir`: `None` (Default), the output path of results if set - `batch_size`: `1` (Default), batch size when decoding diff --git a/egs_modelscope/tp/TEMPLATE/README.md b/egs_modelscope/tp/TEMPLATE/README.md index 62c35d80a..7cc85088a 100644 --- a/egs_modelscope/tp/TEMPLATE/README.md +++ b/egs_modelscope/tp/TEMPLATE/README.md @@ -26,7 +26,7 @@ Timestamp pipeline can also be used after ASR pipeline to compose complete ASR f ### API-reference #### Define pipeline - `task`: `Tasks.speech_timestamp` -- `model`: model name in [model zoo](https://alibaba-damo-academy.github.io/FunASR/en/modelscope_models.html#pretrained-models-on-modelscope), or model path in local disk +- `model`: model name in [model zoo](https://alibaba-damo-academy.github.io/FunASR/en/model_zoo/modelscope_models.html#pretrained-models-on-modelscope), or model path in local disk - `ngpu`: `1` (Default), decoding on GPU. If ngpu=0, decoding on CPU - `ncpu`: `1` (Default), sets the number of threads used for intraop parallelism on CPU - `output_dir`: `None` (Default), the output path of results if set @@ -62,7 +62,7 @@ Timestamp pipeline can also be used after ASR pipeline to compose complete ASR f FunASR also offer recipes [egs_modelscope/tp/TEMPLATE/infer.sh](https://github.com/alibaba-damo-academy/FunASR/blob/main/egs_modelscope/tp/TEMPLATE/infer.sh) to decode with multi-thread CPUs, or multi GPUs. #### Settings of `infer.sh` -- `model`: model name in [model zoo](https://alibaba-damo-academy.github.io/FunASR/en/modelscope_models.html#pretrained-models-on-modelscope), or model path in local disk +- `model`: model name in [model zoo](https://alibaba-damo-academy.github.io/FunASR/en/model_zoo/modelscope_models.html#pretrained-models-on-modelscope), or model path in local disk - `data_dir`: the dataset dir **must** include `wav.scp` and `text.txt` - `output_dir`: output dir of the recognition results - `batch_size`: `64` (Default), batch size of inference on gpu diff --git a/egs_modelscope/vad/TEMPLATE/README.md b/egs_modelscope/vad/TEMPLATE/README.md index 503b9bf8e..4c6f8c282 100644 --- a/egs_modelscope/vad/TEMPLATE/README.md +++ b/egs_modelscope/vad/TEMPLATE/README.md @@ -1,7 +1,7 @@ # Voice Activity Detection > **Note**: -> The modelscope pipeline supports all the models in [model zoo](https://alibaba-damo-academy.github.io/FunASR/en/modelscope_models.html#pretrained-models-on-modelscope) to inference and finetune. Here we take the model of FSMN-VAD as example to demonstrate the usage. +> The modelscope pipeline supports all the models in [model zoo](https://alibaba-damo-academy.github.io/FunASR/en/model_zoo/modelscope_models.html#pretrained-models-on-modelscope) to inference and finetune. Here we take the model of FSMN-VAD as example to demonstrate the usage. ## Inference @@ -46,7 +46,7 @@ Full code of demo, please ref to [demo](https://github.com/alibaba-damo-academy/ ### API-reference #### Define pipeline - `task`: `Tasks.voice_activity_detection` -- `model`: model name in [model zoo](https://alibaba-damo-academy.github.io/FunASR/en/modelscope_models.html#pretrained-models-on-modelscope), or model path in local disk +- `model`: model name in [model zoo](https://alibaba-damo-academy.github.io/FunASR/en/model_zoo/modelscope_models.html#pretrained-models-on-modelscope), or model path in local disk - `ngpu`: `1` (Default), decoding on GPU. If ngpu=0, decoding on CPU - `ncpu`: `1` (Default), sets the number of threads used for intraop parallelism on CPU - `output_dir`: `None` (Default), the output path of results if set @@ -70,7 +70,7 @@ Full code of demo, please ref to [demo](https://github.com/alibaba-damo-academy/ FunASR also offer recipes [egs_modelscope/vad/TEMPLATE/infer.sh](https://github.com/alibaba-damo-academy/FunASR/blob/main/egs_modelscope/vad/TEMPLATE/infer.sh) to decode with multi-thread CPUs, or multi GPUs. #### Settings of `infer.sh` -- `model`: model name in [model zoo](https://alibaba-damo-academy.github.io/FunASR/en/modelscope_models.html#pretrained-models-on-modelscope), or model path in local disk +- `model`: model name in [model zoo](https://alibaba-damo-academy.github.io/FunASR/en/model_zoo/modelscope_models.html#pretrained-models-on-modelscope), or model path in local disk - `data_dir`: the dataset dir needs to include `wav.scp` - `output_dir`: output dir of the recognition results - `batch_size`: `64` (Default), batch size of inference on gpu From 63cb171bc5f734180195e2428ef4b3a0da93dc43 Mon Sep 17 00:00:00 2001 From: Yabin Li Date: Fri, 5 May 2023 19:12:31 +0800 Subject: [PATCH 053/120] Update audio.cpp --- funasr/runtime/onnxruntime/src/audio.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/funasr/runtime/onnxruntime/src/audio.cpp b/funasr/runtime/onnxruntime/src/audio.cpp index 8f46a4f63..e6bfd2848 100644 --- a/funasr/runtime/onnxruntime/src/audio.cpp +++ b/funasr/runtime/onnxruntime/src/audio.cpp @@ -238,6 +238,15 @@ bool Audio::LoadWav(const char *filename, int32_t* sampling_rate) return false; } + if (!header.Validate()) { + return false; + } + + header.SeekToDataChunk(is); + if (!is) { + return false; + } + *sampling_rate = header.sample_rate; // header.subchunk2_size contains the number of bytes in the data. // As we assume each sample contains two bytes, so it is divided by 2 here @@ -519,4 +528,4 @@ void Audio::Split(Model* recog_obj) frame_queue.push(frame); frame = NULL; } -} \ No newline at end of file +} From 56a8d4b41f470a22bc54ad08c5513cdff45b6b00 Mon Sep 17 00:00:00 2001 From: zhifu gao Date: Fri, 5 May 2023 21:39:22 +0800 Subject: [PATCH 054/120] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4128d875f..9013968ac 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ | [**Tutorial_CN**](https://github.com/alibaba-damo-academy/FunASR/wiki#funasr%E7%94%A8%E6%88%B7%E6%89%8B%E5%86%8C) | [**Papers**](https://github.com/alibaba-damo-academy/FunASR#citations) | [**Runtime**](https://github.com/alibaba-damo-academy/FunASR/tree/main/funasr/runtime) -| [**Model Zoo**](https://github.com/alibaba-damo-academy/FunASR/blob/main/docs/modelscope_models.md) +| [**Model Zoo**](https://github.com/alibaba-damo-academy/FunASR/blob/main/docs/model_zoo/modelscope_models.md) | [**Contact**](#contact) | [**M2MET2.0 Challenge**](https://github.com/alibaba-damo-academy/FunASR#multi-channel-multi-party-meeting-transcription-20-m2met20-challenge) @@ -28,7 +28,7 @@ For the release notes, please ref to [news](https://github.com/alibaba-damo-acad ## Highlights - FunASR supports speech recognition(ASR), Multi-talker ASR, Voice Activity Detection(VAD), Punctuation Restoration, Language Models, Speaker Verification and Speaker diarization. -- We have released large number of academic and industrial pretrained models on [ModelScope](https://www.modelscope.cn/models?page=1&tasks=auto-speech-recognition), ref to [Model Zoo](https://alibaba-damo-academy.github.io/FunASR/en/modelscope_models.html) +- We have released large number of academic and industrial pretrained models on [ModelScope](https://www.modelscope.cn/models?page=1&tasks=auto-speech-recognition), ref to [Model Zoo](https://github.com/alibaba-damo-academy/FunASR/blob/main/docs/model_zoo/modelscope_models.md) - The pretrained model [Paraformer-large](https://www.modelscope.cn/models/damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/summary) obtains the best performance on many tasks in [SpeechIO leaderboard](https://github.com/SpeechColab/Leaderboard) - FunASR supplies a easy-to-use pipeline to finetune pretrained models from [ModelScope](https://www.modelscope.cn/models?page=1&tasks=auto-speech-recognition) - Compared to [Espnet](https://github.com/espnet/espnet) framework, the training speed of large-scale datasets in FunASR is much faster owning to the optimized dataloader. From 698ba630a0b77c8a38b71ae799e4122ab5387213 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=B8=E9=9B=81?= Date: Sat, 6 May 2023 10:13:15 +0800 Subject: [PATCH 055/120] docs --- docs/model_zoo/modelscope_models.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/model_zoo/modelscope_models.md b/docs/model_zoo/modelscope_models.md index 04742dd0d..1b7f47583 100644 --- a/docs/model_zoo/modelscope_models.md +++ b/docs/model_zoo/modelscope_models.md @@ -15,7 +15,8 @@ Here we provided several pretrained models on different datasets. The details of | [Paraformer-large-long](https://www.modelscope.cn/models/damo/speech_paraformer-large-vad-punc_asr_nat-zh-cn-16k-common-vocab8404-pytorch/summary) | CN & EN | Alibaba Speech Data (60000hours) | 8404 | 220M | Offline | Which ould deal with arbitrary length input wav | | [Paraformer-large-contextual](https://www.modelscope.cn/models/damo/speech_paraformer-large-contextual_asr_nat-zh-cn-16k-common-vocab8404/summary) | CN & EN | Alibaba Speech Data (60000hours) | 8404 | 220M | Offline | Which supports the hotword customization based on the incentive enhancement, and improves the recall and precision of hotwords. | | [Paraformer](https://modelscope.cn/models/damo/speech_paraformer_asr_nat-zh-cn-16k-common-vocab8358-tensorflow1/summary) | CN & EN | Alibaba Speech Data (50000hours) | 8358 | 68M | Offline | Duration of input wav <= 20s | -| [Paraformer-online](https://www.modelscope.cn/models/damo/speech_paraformer_asr_nat-zh-cn-16k-common-vocab8404-online/summary) | CN & EN | Alibaba Speech Data (50000hours) | 8404 | 68M | Online | Which could deal with streaming input | +| [Paraformer-online](https://www.modelscope.cn/models/damo/speech_paraformer_asr_nat-zh-cn-16k-common-vocab8404-online/summary) | CN & EN | Alibaba Speech Data (50000hours) | 8404 | 68M | Online | Which could deal with streaming input | +| [Paraformer-large-online](https://www.modelscope.cn/models/damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online/summary) | CN & EN | Alibaba Speech Data (60000hours) | 8404 | 220M | Online | Which could deal with streaming input | | [Paraformer-tiny](https://www.modelscope.cn/models/damo/speech_paraformer-tiny-commandword_asr_nat-zh-cn-16k-vocab544-pytorch/summary) | CN | Alibaba Speech Data (200hours) | 544 | 5.2M | Offline | Lightweight Paraformer model which supports Mandarin command words recognition | | [Paraformer-aishell](https://www.modelscope.cn/models/damo/speech_paraformer_asr_nat-aishell1-pytorch/summary) | CN | AISHELL (178hours) | 4234 | 43M | Offline | | | [ParaformerBert-aishell](https://modelscope.cn/models/damo/speech_paraformerbert_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/summary) | CN | AISHELL (178hours) | 4234 | 43M | Offline | | @@ -38,12 +39,12 @@ Here we provided several pretrained models on different datasets. The details of | [UniASR Vietnamese](https://modelscope.cn/models/damo/speech_UniASR_asr_2pass-vi-16k-common-vocab1001-pytorch-online/summary) | VI | Alibaba Speech Data (1000 hours) | 1001 | 95M | Online | UniASR streaming offline unifying models | | [UniASR Spanish](https://modelscope.cn/models/damo/speech_UniASR_asr_2pass-es-16k-common-vocab3445-tensorflow1-online/summary) | ES | Alibaba Speech Data (1000 hours) | 3445 | 95M | Online | UniASR streaming online unifying models | | [UniASR Portuguese](https://modelscope.cn/models/damo/speech_UniASR_asr_2pass-pt-16k-common-vocab1617-tensorflow1-online/summary) | PT | Alibaba Speech Data (1000 hours) | 1617 | 95M | Online | UniASR streaming offline unifying models | -| [UniASR French](https://modelscope.cn/models/damo/speech_UniASR_asr_2pass-fr-16k-common-vocab3472-tensorflow1-online/summary) | FR | Alibaba Speech Data (1000 hours) | 3472 | 95M | Online | UniASR streaming online unifying models | -| [UniASR German](https://modelscope.cn/models/damo/speech_UniASR_asr_2pass-de-16k-common-vocab3690-tensorflow1-online/summary) | GE | Alibaba Speech Data (1000 hours) | 3690 | 95M | Online | UniASR streaming online unifying models | +| [UniASR French](https://modelscope.cn/models/damo/speech_UniASR_asr_2pass-fr-16k-common-vocab3472-tensorflow1-online/summary) | FR | Alibaba Speech Data (1000 hours) | 3472 | 95M | Online | UniASR streaming online unifying models | +| [UniASR German](https://modelscope.cn/models/damo/speech_UniASR_asr_2pass-de-16k-common-vocab3690-tensorflow1-online/summary) | GE | Alibaba Speech Data (1000 hours) | 3690 | 95M | Online | UniASR streaming online unifying models | | [UniASR Persian](https://modelscope.cn/models/damo/speech_UniASR_asr_2pass-fa-16k-common-vocab1257-pytorch-online/summary) | FA | Alibaba Speech Data (1000 hours) | 1257 | 95M | Online | UniASR streaming offline unifying models | | [UniASR Burmese](https://modelscope.cn/models/damo/speech_UniASR_asr_2pass-my-16k-common-vocab696-pytorch/summary) | MY | Alibaba Speech Data (1000 hours) | 696 | 95M | Online | UniASR streaming offline unifying models | | [UniASR Hebrew](https://modelscope.cn/models/damo/speech_UniASR_asr_2pass-he-16k-common-vocab1085-pytorch/summary) | HE | Alibaba Speech Data (1000 hours) | 1085 | 95M | Online | UniASR streaming offline unifying models | -| [UniASR Urdu](https://modelscope.cn/models/damo/speech_UniASR_asr_2pass-ur-16k-common-vocab877-pytorch/summary) | UR | Alibaba Speech Data (1000 hours) | 877 | 95M | Online | UniASR streaming offline unifying models | +| [UniASR Urdu](https://modelscope.cn/models/damo/speech_UniASR_asr_2pass-ur-16k-common-vocab877-pytorch/summary) | UR | Alibaba Speech Data (1000 hours) | 877 | 95M | Online | UniASR streaming offline unifying models | From 6361a1a68cbdcba59817c576409cf6da6b97a2b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=B8=E9=9B=81?= Date: Sat, 6 May 2023 14:26:43 +0800 Subject: [PATCH 056/120] docs --- egs_modelscope/asr/TEMPLATE/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/egs_modelscope/asr/TEMPLATE/README.md b/egs_modelscope/asr/TEMPLATE/README.md index 06daf26a5..7ff04eb00 100644 --- a/egs_modelscope/asr/TEMPLATE/README.md +++ b/egs_modelscope/asr/TEMPLATE/README.md @@ -44,7 +44,7 @@ print(rec_result) Full code of demo, please ref to [demo](https://github.com/alibaba-damo-academy/FunASR/discussions/241) #### [UniASR Model](https://www.modelscope.cn/models/damo/speech_UniASR_asr_2pass-zh-cn-8k-common-vocab3445-pytorch-online/summary) -There are three decoding mode for UniASR model(`fast`、`normal`、`offline`), for more model detailes, please refer to [docs](https://www.modelscope.cn/models/damo/speech_UniASR_asr_2pass-zh-cn-8k-common-vocab3445-pytorch-online/summary) +There are three decoding mode for UniASR model(`fast`、`normal`、`offline`), for more model details, please refer to [docs](https://www.modelscope.cn/models/damo/speech_UniASR_asr_2pass-zh-cn-8k-common-vocab3445-pytorch-online/summary) ```python decoding_model = "fast" # "fast"、"normal"、"offline" inference_pipeline = pipeline( @@ -61,7 +61,7 @@ Full code of demo, please ref to [demo](https://github.com/alibaba-damo-academy/ Undo #### [MFCCA Model](https://www.modelscope.cn/models/NPU-ASLP/speech_mfcca_asr-zh-cn-16k-alimeeting-vocab4950/summary) -For more model detailes, please refer to [docs](https://www.modelscope.cn/models/NPU-ASLP/speech_mfcca_asr-zh-cn-16k-alimeeting-vocab4950/summary) +For more model details, please refer to [docs](https://www.modelscope.cn/models/NPU-ASLP/speech_mfcca_asr-zh-cn-16k-alimeeting-vocab4950/summary) ```python from modelscope.pipelines import pipeline from modelscope.utils.constant import Tasks From 0ccf05b850299a9f76af1fb416e7454374ba15f3 Mon Sep 17 00:00:00 2001 From: root Date: Sat, 6 May 2023 08:48:41 +0000 Subject: [PATCH 057/120] fix bug for python websocket --- funasr/runtime/python/websocket/ws_client.py | 2 +- .../python/websocket/ws_server_online.py | 31 +++---------------- 2 files changed, 6 insertions(+), 27 deletions(-) diff --git a/funasr/runtime/python/websocket/ws_client.py b/funasr/runtime/python/websocket/ws_client.py index 8bbf1032d..a3b49a9b5 100644 --- a/funasr/runtime/python/websocket/ws_client.py +++ b/funasr/runtime/python/websocket/ws_client.py @@ -143,7 +143,7 @@ async def message(): meg = json.loads(meg) # print(meg, end = '') # print("\r") - text = meg["text"][0] + text = meg["text"] text_print += text text_print = text_print[-55:] os.system('clear') diff --git a/funasr/runtime/python/websocket/ws_server_online.py b/funasr/runtime/python/websocket/ws_server_online.py index 7ef0e2125..ea9ba6dd5 100644 --- a/funasr/runtime/python/websocket/ws_server_online.py +++ b/funasr/runtime/python/websocket/ws_server_online.py @@ -41,8 +41,6 @@ async def ws_serve(websocket, path): websocket_users.add(websocket) websocket.param_dict_asr_online = {"cache": dict()} websocket.speek_online = Queue() - ss_online = threading.Thread(target=asr_online, args=(websocket,)) - ss_online.start() try: async for message in websocket: @@ -56,18 +54,8 @@ async def ws_serve(websocket, path): websocket.param_dict_asr_online["chunk_size"] = message["chunk_size"] - - frames_online.append(audio) - - if len(frames_online) % message["chunk_interval"] == 0 or not is_speaking: - - audio_in = b"".join(frames_online) - websocket.speek_online.put(audio_in) - frames_online = [] + await async_asr_online(websocket,audio) - if not websocket.send_msg.empty(): - await websocket.send(websocket.send_msg.get()) - websocket.send_msg.task_done() except websockets.ConnectionClosed: @@ -78,29 +66,20 @@ async def ws_serve(websocket, path): except Exception as e: print("Exception:", e) - - -def asr_online(websocket): # ASR推理 - global websocket_users - while websocket in websocket_users: - if not websocket.speek_online.empty(): - audio_in = websocket.speek_online.get() - websocket.speek_online.task_done() +async def async_asr_online(websocket,audio_in): # ASR推理 if len(audio_in) > 0: - # print(len(audio_in)) audio_in = load_bytes(audio_in) rec_result = inference_pipeline_asr_online(audio_in=audio_in, param_dict=websocket.param_dict_asr_online) if websocket.param_dict_asr_online["is_final"]: websocket.param_dict_asr_online["cache"] = dict() - if "text" in rec_result: if rec_result["text"] != "sil" and rec_result["text"] != "waiting_for_more_voice": print(rec_result["text"]) message = json.dumps({"mode": "online", "text": rec_result["text"]}) - websocket.send_msg.put(message) - - time.sleep(0.005) + await websocket.send(message) + + start_server = websockets.serve(ws_serve, args.host, args.port, subprotocols=["binary"], ping_interval=None) From 0a5f4d0f4a90032e0be55461d4451886e12eb12b Mon Sep 17 00:00:00 2001 From: zhifu gao Date: Sat, 6 May 2023 17:39:31 +0800 Subject: [PATCH 058/120] Update README.md --- README.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/README.md b/README.md index 9013968ac..64d6d894a 100644 --- a/README.md +++ b/README.md @@ -60,12 +60,8 @@ pip install -U modelscope # pip install -U modelscope -f https://modelscope.oss-cn-beijing.aliyuncs.com/releases/repo.html -i https://mirror.sjtu.edu.cn/pypi/web/simple ``` -For more details, please ref to [installation](https://alibaba-damo-academy.github.io/FunASR/en/installation.html) +For more details, please ref to [installation](https://alibaba-damo-academy.github.io/FunASR/en/installation/installation.html) -[//]: # () -[//]: # (## Usage) - -[//]: # (For users who are new to FunASR and ModelScope, please refer to FunASR Docs([CN](https://alibaba-damo-academy.github.io/FunASR/cn/index.html) / [EN](https://alibaba-damo-academy.github.io/FunASR/en/index.html))) ## Contact From af346ddd4d4486d8d1d1b1622be563a0f790487f Mon Sep 17 00:00:00 2001 From: root Date: Sat, 6 May 2023 10:55:32 +0000 Subject: [PATCH 059/120] add multiple process test for python websocket client --- funasr/runtime/python/websocket/ws_client.py | 45 +++++++++++++++----- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/funasr/runtime/python/websocket/ws_client.py b/funasr/runtime/python/websocket/ws_client.py index a3b49a9b5..55507a791 100644 --- a/funasr/runtime/python/websocket/ws_client.py +++ b/funasr/runtime/python/websocket/ws_client.py @@ -6,7 +6,8 @@ import asyncio # import threading import argparse import json - +import traceback +from multiprocessing import Process parser = argparse.ArgumentParser() parser.add_argument("--host", type=str, @@ -31,6 +32,11 @@ parser.add_argument("--audio_in", default=None, help="audio_in") +parser.add_argument("--test_thread_num", + type=int, + default=1, + help="test_thread_num") + args = parser.parse_args() args.chunk_size = [int(x) for x in args.chunk_size.split(",")] @@ -129,12 +135,14 @@ async def ws_send(): await websocket.send(data) # 通过ws对象发送数据 except Exception as e: print('Exception occurred:', e) + traceback.print_exc() + exit(0) await asyncio.sleep(0.005) await asyncio.sleep(0.005) -async def message(): +async def message(id): global websocket text_print = "" while True: @@ -146,11 +154,12 @@ async def message(): text = meg["text"] text_print += text text_print = text_print[-55:] - os.system('clear') - print("\r"+text_print) + #os.system('clear') + print("\r"+str(id)+":"+text_print) except Exception as e: print("Exception:", e) - + traceback.print_exc() + exit(0) async def print_messge(): global websocket @@ -161,9 +170,10 @@ async def print_messge(): print(meg) except Exception as e: print("Exception:", e) + traceback.print_exc() + exit(0) - -async def ws_client(): +async def ws_client(id): global websocket # 定义一个全局变量ws,用于保存websocket连接对象 # uri = "ws://11.167.134.197:8899" uri = "ws://{}:{}".format(args.host, args.port) @@ -174,9 +184,24 @@ async def ws_client(): else: task = asyncio.create_task(record_microphone()) # 创建一个后台任务录音 task2 = asyncio.create_task(ws_send()) # 创建一个后台任务发送 - task3 = asyncio.create_task(message()) # 创建一个后台接收消息的任务 + task3 = asyncio.create_task(message(id)) # 创建一个后台接收消息的任务 await asyncio.gather(task, task2, task3) +def one_thread(id): + asyncio.get_event_loop().run_until_complete(ws_client(id)) # 启动协程 + asyncio.get_event_loop().run_forever() + + +if __name__ == '__main__': + process_list = [] + for i in range(args.test_thread_num): + p = Process(target=one_thread,args=(i,)) #实例化进程对象 + p.start() + process_list.append(p) + + for i in process_list: + p.join() + + print('结束测试') + -asyncio.get_event_loop().run_until_complete(ws_client()) # 启动协程 -asyncio.get_event_loop().run_forever() From eb6c31aeddfa1840b9de2aebec652c5ea8795948 Mon Sep 17 00:00:00 2001 From: zhaomingwork Date: Sat, 6 May 2023 13:53:28 +0000 Subject: [PATCH 060/120] fix problem about chunk_interval --- funasr/runtime/python/websocket/ws_client.py | 3 +-- funasr/runtime/python/websocket/ws_server_online.py | 9 +++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/funasr/runtime/python/websocket/ws_client.py b/funasr/runtime/python/websocket/ws_client.py index 55507a791..c62dd8706 100644 --- a/funasr/runtime/python/websocket/ws_client.py +++ b/funasr/runtime/python/websocket/ws_client.py @@ -151,8 +151,7 @@ async def message(id): meg = json.loads(meg) # print(meg, end = '') # print("\r") - text = meg["text"] - text_print += text + text_print += " {}".format(meg["text"][0]) text_print = text_print[-55:] #os.system('clear') print("\r"+str(id)+":"+text_print) diff --git a/funasr/runtime/python/websocket/ws_server_online.py b/funasr/runtime/python/websocket/ws_server_online.py index ea9ba6dd5..a395d73fd 100644 --- a/funasr/runtime/python/websocket/ws_server_online.py +++ b/funasr/runtime/python/websocket/ws_server_online.py @@ -54,7 +54,11 @@ async def ws_serve(websocket, path): websocket.param_dict_asr_online["chunk_size"] = message["chunk_size"] - await async_asr_online(websocket,audio) + frames_online.append(audio) + if len(frames_online) % message["chunk_interval"] == 0 or not is_speaking: + audio_in = b"".join(frames_online) + await async_asr_online(websocket,audio_in) + frames_online = [] @@ -75,7 +79,8 @@ async def async_asr_online(websocket,audio_in): # ASR推理 websocket.param_dict_asr_online["cache"] = dict() if "text" in rec_result: if rec_result["text"] != "sil" and rec_result["text"] != "waiting_for_more_voice": - print(rec_result["text"]) + if len(rec_result["text"])>0: + rec_result["text"][0]=rec_result["text"][0].replace(" ","") message = json.dumps({"mode": "online", "text": rec_result["text"]}) await websocket.send(message) From 8e238cfc854c1e41cc3a8a6cc29b0defee55b22f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=B8=E9=9B=81?= Date: Sat, 6 May 2023 22:19:26 +0800 Subject: [PATCH 061/120] websocket --- funasr/runtime/python/websocket/ws_server_online.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/funasr/runtime/python/websocket/ws_server_online.py b/funasr/runtime/python/websocket/ws_server_online.py index a395d73fd..4e6c38e52 100644 --- a/funasr/runtime/python/websocket/ws_server_online.py +++ b/funasr/runtime/python/websocket/ws_server_online.py @@ -80,7 +80,7 @@ async def async_asr_online(websocket,audio_in): # ASR推理 if "text" in rec_result: if rec_result["text"] != "sil" and rec_result["text"] != "waiting_for_more_voice": if len(rec_result["text"])>0: - rec_result["text"][0]=rec_result["text"][0].replace(" ","") + rec_result["text"][0]=rec_result["text"][0] #.replace(" ","") message = json.dumps({"mode": "online", "text": rec_result["text"]}) await websocket.send(message) From 4f498e8d82ae5e7e977326a24f897c4b9fdc46bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=B8=E9=9B=81?= Date: Sat, 6 May 2023 22:24:50 +0800 Subject: [PATCH 062/120] websocket --- funasr/runtime/python/websocket/README.md | 4 ++-- funasr/runtime/python/websocket/ws_client.py | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/funasr/runtime/python/websocket/README.md b/funasr/runtime/python/websocket/README.md index ee7dca0a9..fd48f3609 100644 --- a/funasr/runtime/python/websocket/README.md +++ b/funasr/runtime/python/websocket/README.md @@ -54,12 +54,12 @@ pip install -r requirements_client.txt #### Recording from mircrophone ```shell # --chunk_size, "5,10,5"=600ms, "8,8,4"=480ms -python ws_client.py --host "127.0.0.1" --port 10095 --chunk_size "5,10,5" +python ws_client.py --host "127.0.0.1" --port 10095 --chunk_size "5,10,5" --words_max_print 100 ``` #### Loadding from wav.scp(kaldi style) ```shell # --chunk_size, "5,10,5"=600ms, "8,8,4"=480ms -python ws_client.py --host "127.0.0.1" --port 10095 --chunk_size "5,10,5" --audio_in "./data/wav.scp" +python ws_client.py --host "127.0.0.1" --port 10095 --chunk_size "5,10,5" --audio_in "./data/wav.scp" --words_max_print 100 ``` ## Acknowledge diff --git a/funasr/runtime/python/websocket/ws_client.py b/funasr/runtime/python/websocket/ws_client.py index c62dd8706..d32ce0a5a 100644 --- a/funasr/runtime/python/websocket/ws_client.py +++ b/funasr/runtime/python/websocket/ws_client.py @@ -36,6 +36,10 @@ parser.add_argument("--test_thread_num", type=int, default=1, help="test_thread_num") +parser.add_argument("--words_max_print", + type=int, + default=100, + help="chunk") args = parser.parse_args() args.chunk_size = [int(x) for x in args.chunk_size.split(",")] @@ -152,7 +156,7 @@ async def message(id): # print(meg, end = '') # print("\r") text_print += " {}".format(meg["text"][0]) - text_print = text_print[-55:] + text_print = text_print[-args.words_max_print:] #os.system('clear') print("\r"+str(id)+":"+text_print) except Exception as e: From c04d30bf09daf015f30b071b4198798c0af10682 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=B8=E9=9B=81?= Date: Sat, 6 May 2023 22:43:13 +0800 Subject: [PATCH 063/120] websocket readme --- funasr/runtime/python/websocket/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/funasr/runtime/python/websocket/README.md b/funasr/runtime/python/websocket/README.md index fd48f3609..b0ef20610 100644 --- a/funasr/runtime/python/websocket/README.md +++ b/funasr/runtime/python/websocket/README.md @@ -64,4 +64,5 @@ python ws_client.py --host "127.0.0.1" --port 10095 --chunk_size "5,10,5" --audi ## Acknowledge 1. This project is maintained by [FunASR community](https://github.com/alibaba-damo-academy/FunASR). -2. We acknowledge [cgisky1980](https://github.com/cgisky1980/FunASR) for contributing the websocket service. +2. We acknowledge [zhaoming](https://github.com/zhaomingwork/FunASR/tree/fix_bug_for_python_websocket) for contributing the websocket service. +3. We acknowledge [cgisky1980](https://github.com/cgisky1980/FunASR) for contributing the websocket service of offline model. From 296ec00997d4ad4715286c8dad9cc2226d064b71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=B8=E9=9B=81?= Date: Sun, 7 May 2023 23:02:56 +0800 Subject: [PATCH 064/120] websocket offline --- funasr/runtime/python/websocket/README.md | 32 ++-- funasr/runtime/python/websocket/parse_args.py | 7 +- funasr/runtime/python/websocket/ws_client.py | 45 +++--- .../python/websocket/ws_server_offline.py | 147 ++++++++++++++++++ .../python/websocket/ws_server_online.py | 11 +- 5 files changed, 203 insertions(+), 39 deletions(-) create mode 100644 funasr/runtime/python/websocket/ws_server_offline.py diff --git a/funasr/runtime/python/websocket/README.md b/funasr/runtime/python/websocket/README.md index b0ef20610..76405eaf5 100644 --- a/funasr/runtime/python/websocket/README.md +++ b/funasr/runtime/python/websocket/README.md @@ -22,15 +22,13 @@ pip install -r requirements_server.txt ### Start server #### ASR offline server +```shell +python ws_server_offline.py --port 10095 --asr_model "damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch" +``` -[//]: # (```shell) - -[//]: # (python ws_server_online.py --host "0.0.0.0" --port 10095 --asr_model "damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch") - -[//]: # (```) #### ASR streaming server ```shell -python ws_server_online.py --host "0.0.0.0" --port 10095 --asr_model_online "damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online" +python ws_server_online.py --port 10095 --asr_model_online "damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online" ``` #### ASR offline/online 2pass server @@ -51,17 +49,31 @@ pip install -r requirements_client.txt ``` ### Start client -#### Recording from mircrophone +#### ASR offline client +##### Recording from mircrophone +```shell +# --chunk_interval, "10": 600/10=60ms, "5"=600/5=120ms, "20": 600/12=30ms +python ws_client.py --host "0.0.0.0" --port 10095 --chunk_interval 10 --words_max_print 100 +``` +##### Loadding from wav.scp(kaldi style) +```shell +# --chunk_interval, "10": 600/10=60ms, "5"=600/5=120ms, "20": 600/12=30ms +python ws_client.py --host "0.0.0.0" --port 10095 --chunk_interval 10 --words_max_print 100 --audio_in "./data/wav.scp" --send_without_sleep +``` +#### ASR streaming client +##### Recording from mircrophone ```shell # --chunk_size, "5,10,5"=600ms, "8,8,4"=480ms -python ws_client.py --host "127.0.0.1" --port 10095 --chunk_size "5,10,5" --words_max_print 100 +python ws_client.py --host "0.0.0.0" --port 10095 --chunk_size "5,10,5" --words_max_print 100 ``` -#### Loadding from wav.scp(kaldi style) +##### Loadding from wav.scp(kaldi style) ```shell # --chunk_size, "5,10,5"=600ms, "8,8,4"=480ms -python ws_client.py --host "127.0.0.1" --port 10095 --chunk_size "5,10,5" --audio_in "./data/wav.scp" --words_max_print 100 +python ws_client.py --host "0.0.0.0" --port 10095 --chunk_size "5,10,5" --audio_in "./data/wav.scp" --words_max_print 100 ``` +#### ASR offline/online 2pass client + ## Acknowledge 1. This project is maintained by [FunASR community](https://github.com/alibaba-damo-academy/FunASR). 2. We acknowledge [zhaoming](https://github.com/zhaomingwork/FunASR/tree/fix_bug_for_python_websocket) for contributing the websocket service. diff --git a/funasr/runtime/python/websocket/parse_args.py b/funasr/runtime/python/websocket/parse_args.py index 2528a7624..d170be857 100644 --- a/funasr/runtime/python/websocket/parse_args.py +++ b/funasr/runtime/python/websocket/parse_args.py @@ -31,5 +31,10 @@ parser.add_argument("--ngpu", type=int, default=1, help="0 for cpu, 1 for gpu") +parser.add_argument("--ncpu", + type=int, + default=1, + help="cpu cores") -args = parser.parse_args() \ No newline at end of file +args = parser.parse_args() +print(args) \ No newline at end of file diff --git a/funasr/runtime/python/websocket/ws_client.py b/funasr/runtime/python/websocket/ws_client.py index d32ce0a5a..d8bbb6596 100644 --- a/funasr/runtime/python/websocket/ws_client.py +++ b/funasr/runtime/python/websocket/ws_client.py @@ -31,7 +31,10 @@ parser.add_argument("--audio_in", type=str, default=None, help="audio_in") - +parser.add_argument("--send_without_sleep", + action="store_true", + default=False, + help="if audio_in is set, send_without_sleep") parser.add_argument("--test_thread_num", type=int, default=1, @@ -43,12 +46,11 @@ parser.add_argument("--words_max_print", args = parser.parse_args() args.chunk_size = [int(x) for x in args.chunk_size.split(",")] - +print(args) # voices = asyncio.Queue() from queue import Queue voices = Queue() -# 其他函数可以通过调用send(data)来发送数据,例如: async def record_microphone(): is_finished = False import pyaudio @@ -75,11 +77,9 @@ async def record_microphone(): message = json.dumps({"chunk_size": args.chunk_size, "chunk_interval": args.chunk_interval, "audio": data, "is_speaking": is_speaking, "is_finished": is_finished}) voices.put(message) - #print(voices.qsize()) await asyncio.sleep(0.005) -# 其他函数可以通过调用send(data)来发送数据,例如: async def record_from_scp(): import wave global voices @@ -95,15 +95,11 @@ async def record_from_scp(): # bytes_f = open(wav_path, "rb") # bytes_data = bytes_f.read() with wave.open(wav_path, "rb") as wav_file: - # 获取音频参数 params = wav_file.getparams() - # 获取头信息的长度 # header_length = wav_file.getheaders()[0][1] - # 读取音频帧数据,跳过头信息 # wav_file.setpos(header_length) frames = wav_file.readframes(wav_file.getnframes()) - # 将音频帧数据转换为字节类型的数据 audio_bytes = bytes(frames) # stride = int(args.chunk_size/1000*16000*2) stride = int(60*args.chunk_size[1]/args.chunk_interval/1000*16000*2) @@ -120,8 +116,8 @@ async def record_from_scp(): voices.put(message) # print("data_chunk: ", len(data_chunk)) # print(voices.qsize()) - - await asyncio.sleep(60*args.chunk_size[1]/args.chunk_interval/1000) + sleep_duration = 0.001 if args.send_without_sleep else 60*args.chunk_size[1]/args.chunk_interval/1000 + await asyncio.sleep(sleep_duration) is_finished = True message = json.dumps({"is_finished": is_finished}) @@ -136,7 +132,7 @@ async def ws_send(): data = voices.get() voices.task_done() try: - await websocket.send(data) # 通过ws对象发送数据 + await websocket.send(data) except Exception as e: print('Exception occurred:', e) traceback.print_exc() @@ -155,9 +151,14 @@ async def message(id): meg = json.loads(meg) # print(meg, end = '') # print("\r") - text_print += " {}".format(meg["text"][0]) + # print(meg) + text = meg["text"][0] + if meg["mode"] == "online": + text_print += " {}".format(text) + else: + text_print += "{}".format(text) text_print = text_print[-args.words_max_print:] - #os.system('clear') + os.system('clear') print("\r"+str(id)+":"+text_print) except Exception as e: print("Exception:", e) @@ -177,17 +178,15 @@ async def print_messge(): exit(0) async def ws_client(id): - global websocket # 定义一个全局变量ws,用于保存websocket连接对象 - # uri = "ws://11.167.134.197:8899" + global websocket uri = "ws://{}:{}".format(args.host, args.port) - #ws = await websockets.connect(uri, subprotocols=["binary"]) # 创建一个长连接 async for websocket in websockets.connect(uri, subprotocols=["binary"], ping_interval=None): if args.audio_in is not None: - task = asyncio.create_task(record_from_scp()) # 创建一个后台任务录音 + task = asyncio.create_task(record_from_scp()) else: - task = asyncio.create_task(record_microphone()) # 创建一个后台任务录音 - task2 = asyncio.create_task(ws_send()) # 创建一个后台任务发送 - task3 = asyncio.create_task(message(id)) # 创建一个后台接收消息的任务 + task = asyncio.create_task(record_microphone()) + task2 = asyncio.create_task(ws_send()) + task3 = asyncio.create_task(message(id)) await asyncio.gather(task, task2, task3) def one_thread(id): @@ -198,13 +197,13 @@ def one_thread(id): if __name__ == '__main__': process_list = [] for i in range(args.test_thread_num): - p = Process(target=one_thread,args=(i,)) #实例化进程对象 + p = Process(target=one_thread,args=(i,)) p.start() process_list.append(p) for i in process_list: p.join() - print('结束测试') + print('end') diff --git a/funasr/runtime/python/websocket/ws_server_offline.py b/funasr/runtime/python/websocket/ws_server_offline.py new file mode 100644 index 000000000..787391871 --- /dev/null +++ b/funasr/runtime/python/websocket/ws_server_offline.py @@ -0,0 +1,147 @@ +import asyncio +import json +import websockets +import time +import logging +import tracemalloc +import numpy as np + +from parse_args import args +from modelscope.pipelines import pipeline +from modelscope.utils.constant import Tasks +from modelscope.utils.logger import get_logger +from funasr.runtime.python.onnxruntime.funasr_onnx.utils.frontend import load_bytes + +tracemalloc.start() + +logger = get_logger(log_level=logging.CRITICAL) +logger.setLevel(logging.CRITICAL) + + +websocket_users = set() + +print("model loading") +# asr +inference_pipeline_asr = pipeline( + task=Tasks.auto_speech_recognition, + model=args.asr_model, + ngpu=args.ngpu, + ncpu=args.ncpu, + model_revision=None) + + +# vad +inference_pipeline_vad = pipeline( + task=Tasks.voice_activity_detection, + model=args.vad_model, + model_revision=None, + output_dir=None, + batch_size=1, + mode='online', + ngpu=args.ngpu, + ncpu=args.ncpu, +) + +if args.punc_model != "": + inference_pipeline_punc = pipeline( + task=Tasks.punctuation, + model=args.punc_model, + model_revision=None, + ngpu=args.ngpu, + ncpu=args.ncpu, + ) +else: + inference_pipeline_punc = None + +print("model loaded") + +async def ws_serve(websocket, path): + frames = [] + frames_asr = [] + global websocket_users + websocket_users.add(websocket) + websocket.param_dict_asr = {} + websocket.param_dict_vad = {'in_cache': dict(), "is_final": False} + websocket.param_dict_punc = {'cache': list()} + websocket.vad_pre_idx = 0 + speech_start = False + + try: + async for message in websocket: + message = json.loads(message) + is_finished = message["is_finished"] + if not is_finished: + audio = bytes(message['audio'], 'ISO-8859-1') + frames.append(audio) + duration_ms = len(audio)//32 + websocket.vad_pre_idx += duration_ms + + is_speaking = message["is_speaking"] + websocket.param_dict_vad["is_final"] = not is_speaking + if speech_start: + frames_asr.append(audio) + speech_start_i, speech_end_i = await async_vad(websocket, audio) + if speech_start_i: + speech_start = True + beg_bias = (websocket.vad_pre_idx-speech_start_i)//duration_ms + frames_pre = frames[-beg_bias:] + frames_asr = [] + frames_asr.extend(frames_pre) + if speech_end_i or not is_speaking: + audio_in = b"".join(frames_asr) + await async_asr(websocket, audio_in) + frames_asr = [] + speech_start = False + if not is_speaking: + websocket.vad_pre_idx = 0 + frames = [] + else: + frames = frames[-10:] + + + except websockets.ConnectionClosed: + print("ConnectionClosed...", websocket_users) + websocket_users.remove(websocket) + except websockets.InvalidState: + print("InvalidState...") + except Exception as e: + print("Exception:", e) + + +async def async_vad(websocket, audio_in): + + segments_result = inference_pipeline_vad(audio_in=audio_in, param_dict=websocket.param_dict_vad) + + speech_start = False + speech_end = False + + if len(segments_result) == 0 or len(segments_result["text"]) > 1: + return speech_start, speech_end + if segments_result["text"][0][0] != -1: + speech_start = segments_result["text"][0][0] + if segments_result["text"][0][1] != -1: + speech_end = True + return speech_start, speech_end + + +async def async_asr(websocket, audio_in): + if len(audio_in) > 0: + # print(len(audio_in)) + audio_in = load_bytes(audio_in) + + rec_result = inference_pipeline_asr(audio_in=audio_in, + param_dict=websocket.param_dict_asr) + # print(rec_result) + if inference_pipeline_punc is not None and 'text' in rec_result and len(rec_result["text"])>0: + rec_result = inference_pipeline_punc(text_in=rec_result['text'], + param_dict=websocket.param_dict_punc) + # print(rec_result) + message = json.dumps({"mode": "offline", "text": [rec_result["text"]]}) + await websocket.send(message) + + + + +start_server = websockets.serve(ws_serve, args.host, args.port, subprotocols=["binary"], ping_interval=None) +asyncio.get_event_loop().run_until_complete(start_server) +asyncio.get_event_loop().run_forever() \ No newline at end of file diff --git a/funasr/runtime/python/websocket/ws_server_online.py b/funasr/runtime/python/websocket/ws_server_online.py index 4e6c38e52..6ea8f397a 100644 --- a/funasr/runtime/python/websocket/ws_server_online.py +++ b/funasr/runtime/python/websocket/ws_server_online.py @@ -12,7 +12,7 @@ from parse_args import args from modelscope.pipelines import pipeline from modelscope.utils.constant import Tasks from modelscope.utils.logger import get_logger -from funasr_onnx.utils.frontend import load_bytes +from funasr.runtime.python.onnxruntime.funasr_onnx.utils.frontend import load_bytes tracemalloc.start() @@ -28,6 +28,8 @@ print("model loading") inference_pipeline_asr_online = pipeline( task=Tasks.auto_speech_recognition, model=args.asr_model_online, + ngpu=args.ngpu, + ncpu=args.ncpu, model_revision='v1.0.4') print("model loaded") @@ -63,14 +65,14 @@ async def ws_serve(websocket, path): except websockets.ConnectionClosed: - print("ConnectionClosed...", websocket_users) # 链接断开 + print("ConnectionClosed...", websocket_users) websocket_users.remove(websocket) except websockets.InvalidState: - print("InvalidState...") # 无效状态 + print("InvalidState...") except Exception as e: print("Exception:", e) -async def async_asr_online(websocket,audio_in): # ASR推理 +async def async_asr_online(websocket,audio_in): if len(audio_in) > 0: audio_in = load_bytes(audio_in) rec_result = inference_pipeline_asr_online(audio_in=audio_in, @@ -84,7 +86,6 @@ async def async_asr_online(websocket,audio_in): # ASR推理 message = json.dumps({"mode": "online", "text": rec_result["text"]}) await websocket.send(message) - start_server = websockets.serve(ws_serve, args.host, args.port, subprotocols=["binary"], ping_interval=None) From a6b790bffc56b27932c9a9e985bb71c437372822 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=B8=E9=9B=81?= Date: Mon, 8 May 2023 00:11:30 +0800 Subject: [PATCH 065/120] websocket offline --- funasr/runtime/python/websocket/README.md | 4 ++-- funasr/runtime/python/websocket/ws_client.py | 23 ++++++++++++++++--- .../python/websocket/ws_server_offline.py | 6 +++-- .../python/websocket/ws_server_online.py | 8 +++---- 4 files changed, 30 insertions(+), 11 deletions(-) diff --git a/funasr/runtime/python/websocket/README.md b/funasr/runtime/python/websocket/README.md index 76405eaf5..473c37a2c 100644 --- a/funasr/runtime/python/websocket/README.md +++ b/funasr/runtime/python/websocket/README.md @@ -58,7 +58,7 @@ python ws_client.py --host "0.0.0.0" --port 10095 --chunk_interval 10 --words_ma ##### Loadding from wav.scp(kaldi style) ```shell # --chunk_interval, "10": 600/10=60ms, "5"=600/5=120ms, "20": 600/12=30ms -python ws_client.py --host "0.0.0.0" --port 10095 --chunk_interval 10 --words_max_print 100 --audio_in "./data/wav.scp" --send_without_sleep +python ws_client.py --host "0.0.0.0" --port 10095 --chunk_interval 10 --words_max_print 100 --audio_in "./data/wav.scp" --send_without_sleep --output_dir "./results" ``` #### ASR streaming client ##### Recording from mircrophone @@ -69,7 +69,7 @@ python ws_client.py --host "0.0.0.0" --port 10095 --chunk_size "5,10,5" --words_ ##### Loadding from wav.scp(kaldi style) ```shell # --chunk_size, "5,10,5"=600ms, "8,8,4"=480ms -python ws_client.py --host "0.0.0.0" --port 10095 --chunk_size "5,10,5" --audio_in "./data/wav.scp" --words_max_print 100 +python ws_client.py --host "0.0.0.0" --port 10095 --chunk_size "5,10,5" --audio_in "./data/wav.scp" --words_max_print 100 --output_dir "./results" ``` #### ASR offline/online 2pass client diff --git a/funasr/runtime/python/websocket/ws_client.py b/funasr/runtime/python/websocket/ws_client.py index d8bbb6596..bbc49b104 100644 --- a/funasr/runtime/python/websocket/ws_client.py +++ b/funasr/runtime/python/websocket/ws_client.py @@ -7,7 +7,9 @@ import asyncio import argparse import json import traceback -from multiprocessing import Process +from multiprocessing import Process +from funasr.fileio.datadir_writer import DatadirWriter + parser = argparse.ArgumentParser() parser.add_argument("--host", type=str, @@ -43,6 +45,10 @@ parser.add_argument("--words_max_print", type=int, default=100, help="chunk") +parser.add_argument("--output_dir", + type=str, + default=None, + help="output_dir") args = parser.parse_args() args.chunk_size = [int(x) for x in args.chunk_size.split(",")] @@ -51,6 +57,11 @@ print(args) from queue import Queue voices = Queue() +ibest_writer = None +if args.output_dir is not None: + writer = DatadirWriter(args.output_dir) + ibest_writer = writer[f"1best_recog"] + async def record_microphone(): is_finished = False import pyaudio @@ -91,7 +102,9 @@ async def record_from_scp(): wavs = [args.audio_in] for wav in wavs: wav_splits = wav.strip().split() + wav_name = wav_splits[0] if len(wav_splits) > 1 else "demo" wav_path = wav_splits[1] if len(wav_splits) > 1 else wav_splits[0] + # bytes_f = open(wav_path, "rb") # bytes_data = bytes_f.read() with wave.open(wav_path, "rb") as wav_file: @@ -112,7 +125,7 @@ async def record_from_scp(): beg = i*stride data = audio_bytes[beg:beg+stride] data = data.decode('ISO-8859-1') - message = json.dumps({"chunk_size": args.chunk_size, "chunk_interval": args.chunk_interval, "is_speaking": is_speaking, "audio": data, "is_finished": is_finished}) + message = json.dumps({"chunk_size": args.chunk_size, "chunk_interval": args.chunk_interval, "is_speaking": is_speaking, "audio": data, "is_finished": is_finished, "wav_name": wav_name}) voices.put(message) # print("data_chunk: ", len(data_chunk)) # print(voices.qsize()) @@ -152,14 +165,18 @@ async def message(id): # print(meg, end = '') # print("\r") # print(meg) + wav_name = meg.get("wav_name", "demo") + print(wav_name) text = meg["text"][0] + if ibest_writer is not None: + ibest_writer["text"][wav_name] = text if meg["mode"] == "online": text_print += " {}".format(text) else: text_print += "{}".format(text) text_print = text_print[-args.words_max_print:] os.system('clear') - print("\r"+str(id)+":"+text_print) + print("\rpid"+str(id)+": "+text_print) except Exception as e: print("Exception:", e) traceback.print_exc() diff --git a/funasr/runtime/python/websocket/ws_server_offline.py b/funasr/runtime/python/websocket/ws_server_offline.py index 787391871..c60ea6f16 100644 --- a/funasr/runtime/python/websocket/ws_server_offline.py +++ b/funasr/runtime/python/websocket/ws_server_offline.py @@ -78,6 +78,7 @@ async def ws_serve(websocket, path): is_speaking = message["is_speaking"] websocket.param_dict_vad["is_final"] = not is_speaking + websocket.wav_name = message.get("wav_name", "demo") if speech_start: frames_asr.append(audio) speech_start_i, speech_end_i = await async_vad(websocket, audio) @@ -136,8 +137,9 @@ async def async_asr(websocket, audio_in): rec_result = inference_pipeline_punc(text_in=rec_result['text'], param_dict=websocket.param_dict_punc) # print(rec_result) - message = json.dumps({"mode": "offline", "text": [rec_result["text"]]}) - await websocket.send(message) + message = json.dumps({"mode": "offline", "text": [rec_result["text"]], "wav_name": websocket.wav_name}) + await websocket.send(message) + diff --git a/funasr/runtime/python/websocket/ws_server_online.py b/funasr/runtime/python/websocket/ws_server_online.py index 6ea8f397a..b1cd4eaea 100644 --- a/funasr/runtime/python/websocket/ws_server_online.py +++ b/funasr/runtime/python/websocket/ws_server_online.py @@ -53,7 +53,7 @@ async def ws_serve(websocket, path): is_speaking = message["is_speaking"] websocket.param_dict_asr_online["is_final"] = not is_speaking - + websocket.wav_name = message.get("wav_name", "demo") websocket.param_dict_asr_online["chunk_size"] = message["chunk_size"] frames_online.append(audio) @@ -81,9 +81,9 @@ async def async_asr_online(websocket,audio_in): websocket.param_dict_asr_online["cache"] = dict() if "text" in rec_result: if rec_result["text"] != "sil" and rec_result["text"] != "waiting_for_more_voice": - if len(rec_result["text"])>0: - rec_result["text"][0]=rec_result["text"][0] #.replace(" ","") - message = json.dumps({"mode": "online", "text": rec_result["text"]}) + # if len(rec_result["text"])>0: + # rec_result["text"][0]=rec_result["text"][0] #.replace(" ","") + message = json.dumps({"mode": "online", "text": rec_result["text"], "wav_name": websocket.wav_name}) await websocket.send(message) From 63f1496cbb9d1cf5893a77489a9c8e5ef589ccf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=B8=E9=9B=81?= Date: Mon, 8 May 2023 00:13:17 +0800 Subject: [PATCH 066/120] v0.4.6 --- funasr/version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/funasr/version.txt b/funasr/version.txt index 0bfccb080..ef52a6480 100644 --- a/funasr/version.txt +++ b/funasr/version.txt @@ -1 +1 @@ -0.4.5 +0.4.6 From 5d165695e651a814a1d44d2beaedf4348eecc039 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=B8=E9=9B=81?= Date: Mon, 8 May 2023 00:36:14 +0800 Subject: [PATCH 067/120] vad begin point bias --- funasr/runtime/python/onnxruntime/setup.py | 2 +- funasr/runtime/python/websocket/tmp/1best_recog/text | 12 ++++++++++++ funasr/runtime/python/websocket/ws_server_offline.py | 2 +- 3 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 funasr/runtime/python/websocket/tmp/1best_recog/text diff --git a/funasr/runtime/python/onnxruntime/setup.py b/funasr/runtime/python/onnxruntime/setup.py index 06603f003..3fafd5339 100644 --- a/funasr/runtime/python/onnxruntime/setup.py +++ b/funasr/runtime/python/onnxruntime/setup.py @@ -13,7 +13,7 @@ def get_readme(): MODULE_NAME = 'funasr_onnx' -VERSION_NUM = '0.0.6' +VERSION_NUM = '0.0.7' setuptools.setup( name=MODULE_NAME, diff --git a/funasr/runtime/python/websocket/tmp/1best_recog/text b/funasr/runtime/python/websocket/tmp/1best_recog/text new file mode 100644 index 000000000..ff2ab648c --- /dev/null +++ b/funasr/runtime/python/websocket/tmp/1best_recog/text @@ -0,0 +1,12 @@ +wav1 欢 迎 大 +wav1 家 来 +wav1 体 验 达 +wav1 摩 院 推 +wav1 出 的 +wav1 语 音 识 +wav1 别 模 +wav1 型 +wav2 欢 迎 大 +wav2 家 来 +wav2 体 验 达 +wav2 摩 院 推 diff --git a/funasr/runtime/python/websocket/ws_server_offline.py b/funasr/runtime/python/websocket/ws_server_offline.py index c60ea6f16..c2366d085 100644 --- a/funasr/runtime/python/websocket/ws_server_offline.py +++ b/funasr/runtime/python/websocket/ws_server_offline.py @@ -97,7 +97,7 @@ async def ws_serve(websocket, path): websocket.vad_pre_idx = 0 frames = [] else: - frames = frames[-10:] + frames = frames[-20:] except websockets.ConnectionClosed: From 24f2aa224a49bee0de0a59504abce232e5f2683e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=B8=E9=9B=81?= Date: Mon, 8 May 2023 00:41:21 +0800 Subject: [PATCH 068/120] vad begin point bias --- .../runtime/python/websocket/tmp/1best_recog/text | 14 ++------------ .../runtime/python/websocket/ws_server_offline.py | 1 + 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/funasr/runtime/python/websocket/tmp/1best_recog/text b/funasr/runtime/python/websocket/tmp/1best_recog/text index ff2ab648c..05a67e614 100644 --- a/funasr/runtime/python/websocket/tmp/1best_recog/text +++ b/funasr/runtime/python/websocket/tmp/1best_recog/text @@ -1,12 +1,2 @@ -wav1 欢 迎 大 -wav1 家 来 -wav1 体 验 达 -wav1 摩 院 推 -wav1 出 的 -wav1 语 音 识 -wav1 别 模 -wav1 型 -wav2 欢 迎 大 -wav2 家 来 -wav2 体 验 达 -wav2 摩 院 推 +wav1 欢迎大家来体验达摩院推出的语音识别模型 +wav2 。欢迎大家来体验达摩院推出的语音识别模型 diff --git a/funasr/runtime/python/websocket/ws_server_offline.py b/funasr/runtime/python/websocket/ws_server_offline.py index c2366d085..c415703e4 100644 --- a/funasr/runtime/python/websocket/ws_server_offline.py +++ b/funasr/runtime/python/websocket/ws_server_offline.py @@ -96,6 +96,7 @@ async def ws_serve(websocket, path): if not is_speaking: websocket.vad_pre_idx = 0 frames = [] + websocket.param_dict_vad = {'in_cache': dict()} else: frames = frames[-20:] From 4d3210044e22fc06140b435f79ed04c8302f832a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=B8=E9=9B=81?= Date: Mon, 8 May 2023 09:56:34 +0800 Subject: [PATCH 069/120] vad begin point bias --- funasr/runtime/python/websocket/tmp/1best_recog/text | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 funasr/runtime/python/websocket/tmp/1best_recog/text diff --git a/funasr/runtime/python/websocket/tmp/1best_recog/text b/funasr/runtime/python/websocket/tmp/1best_recog/text deleted file mode 100644 index 05a67e614..000000000 --- a/funasr/runtime/python/websocket/tmp/1best_recog/text +++ /dev/null @@ -1,2 +0,0 @@ -wav1 欢迎大家来体验达摩院推出的语音识别模型 -wav2 。欢迎大家来体验达摩院推出的语音识别模型 From 1f2a51be9890dc3325c953a927aac41189cd317b Mon Sep 17 00:00:00 2001 From: "haoneng.lhn" Date: Mon, 8 May 2023 10:28:30 +0800 Subject: [PATCH 070/120] update streaming paraformer text process --- .../infer.py | 2 +- .../infer.py | 2 +- funasr/bin/asr_inference_paraformer_streaming.py | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online/infer.py b/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online/infer.py index 808084fd5..b56645413 100644 --- a/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online/infer.py +++ b/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online/infer.py @@ -34,6 +34,6 @@ for sample_offset in range(0, speech_length, min(stride_size, speech_length - sa rec_result = inference_pipeline(audio_in=speech[sample_offset: sample_offset + stride_size], param_dict=param_dict) if len(rec_result) != 0: - final_result += " ".join(rec_result['text']) + " " + final_result += rec_result['text'] + " " print(rec_result) print(final_result) diff --git a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-common-vocab8404-online/infer.py b/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-common-vocab8404-online/infer.py index 0ecf1ab39..6672bbf78 100644 --- a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-common-vocab8404-online/infer.py +++ b/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-common-vocab8404-online/infer.py @@ -34,6 +34,6 @@ for sample_offset in range(0, speech_length, min(stride_size, speech_length - sa rec_result = inference_pipeline(audio_in=speech[sample_offset: sample_offset + stride_size], param_dict=param_dict) if len(rec_result) != 0: - final_result += " ".join(rec_result['text']) + " " + final_result += rec_result['text'] + " " print(rec_result) print(final_result.strip()) diff --git a/funasr/bin/asr_inference_paraformer_streaming.py b/funasr/bin/asr_inference_paraformer_streaming.py index be0d752a1..4f04d02e3 100644 --- a/funasr/bin/asr_inference_paraformer_streaming.py +++ b/funasr/bin/asr_inference_paraformer_streaming.py @@ -553,12 +553,12 @@ def inference_modelscope( asr_result = speech2text(cache, raw_inputs[:, sample_offset: sample_offset + stride_size], input_lens) if len(asr_result) != 0: final_result += " ".join(asr_result) + " " - item = {'key': "utt", 'value': [final_result.strip()]} + item = {'key': "utt", 'value': final_result.strip()} else: input_lens = torch.tensor([raw_inputs.shape[1]]) cache["encoder"]["is_final"] = is_final asr_result = speech2text(cache, raw_inputs, input_lens) - item = {'key': "utt", 'value': asr_result} + item = {'key': "utt", 'value': " ".join(asr_result)} asr_result_list.append(item) if is_final: From 36cc1768c4b9583a673afa041928a679717c1d0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=B8=E9=9B=81?= Date: Mon, 8 May 2023 10:36:58 +0800 Subject: [PATCH 071/120] recipe --- .../README.md | 1 - .../infer.py | 1 - .../infer.sh | 1 - 3 files changed, 3 deletions(-) delete mode 120000 egs_modelscope/punctuation/punc_ct-transformer_zh-cn-common-vadrealtime-vocab272727/README.md delete mode 120000 egs_modelscope/punctuation/punc_ct-transformer_zh-cn-common-vadrealtime-vocab272727/infer.py delete mode 120000 egs_modelscope/punctuation/punc_ct-transformer_zh-cn-common-vadrealtime-vocab272727/infer.sh diff --git a/egs_modelscope/punctuation/punc_ct-transformer_zh-cn-common-vadrealtime-vocab272727/README.md b/egs_modelscope/punctuation/punc_ct-transformer_zh-cn-common-vadrealtime-vocab272727/README.md deleted file mode 120000 index bb55ab52e..000000000 --- a/egs_modelscope/punctuation/punc_ct-transformer_zh-cn-common-vadrealtime-vocab272727/README.md +++ /dev/null @@ -1 +0,0 @@ -../../TEMPLATE/README.md \ No newline at end of file diff --git a/egs_modelscope/punctuation/punc_ct-transformer_zh-cn-common-vadrealtime-vocab272727/infer.py b/egs_modelscope/punctuation/punc_ct-transformer_zh-cn-common-vadrealtime-vocab272727/infer.py deleted file mode 120000 index 128fc31c2..000000000 --- a/egs_modelscope/punctuation/punc_ct-transformer_zh-cn-common-vadrealtime-vocab272727/infer.py +++ /dev/null @@ -1 +0,0 @@ -../../TEMPLATE/infer.py \ No newline at end of file diff --git a/egs_modelscope/punctuation/punc_ct-transformer_zh-cn-common-vadrealtime-vocab272727/infer.sh b/egs_modelscope/punctuation/punc_ct-transformer_zh-cn-common-vadrealtime-vocab272727/infer.sh deleted file mode 120000 index 5e59f1841..000000000 --- a/egs_modelscope/punctuation/punc_ct-transformer_zh-cn-common-vadrealtime-vocab272727/infer.sh +++ /dev/null @@ -1 +0,0 @@ -../../TEMPLATE/infer.sh \ No newline at end of file From 11f0ed89afb2ec16e022cef0ce50d11c534fe028 Mon Sep 17 00:00:00 2001 From: lyblsgo Date: Mon, 8 May 2023 10:56:18 +0800 Subject: [PATCH 072/120] fix wavhead reader; modify punc input to int32; add vad/punc/offline-stream apis; modify option parser --- funasr/runtime/onnxruntime/include/audio.h | 7 +- .../runtime/onnxruntime/include/com-define.h | 35 +++- .../onnxruntime/include/libfunasrapi.h | 26 ++- funasr/runtime/onnxruntime/include/model.h | 5 +- .../onnxruntime/include/offline-stream.h | 28 +++ .../runtime/onnxruntime/include/punc-model.h | 18 ++ .../runtime/onnxruntime/include/vad-model.h | 27 +++ funasr/runtime/onnxruntime/src/CMakeLists.txt | 4 + funasr/runtime/onnxruntime/src/audio.cpp | 28 ++- funasr/runtime/onnxruntime/src/commonfunc.h | 6 + .../onnxruntime/src/ct-transformer.cpp | 9 +- .../runtime/onnxruntime/src/ct-transformer.h | 4 +- funasr/runtime/onnxruntime/src/fsmn-vad.cpp | 7 +- funasr/runtime/onnxruntime/src/fsmn-vad.h | 6 +- .../src/funasr-onnx-offline-punc.cpp | 98 ++++++++++ .../src/funasr-onnx-offline-rtf.cpp | 32 +--- .../src/funasr-onnx-offline-vad.cpp | 143 ++++++++++++++ .../onnxruntime/src/funasr-onnx-offline.cpp | 56 +++--- .../runtime/onnxruntime/src/libfunasrapi.cpp | 175 +++++++++++++++--- funasr/runtime/onnxruntime/src/model.cpp | 14 +- .../onnxruntime/src/offline-stream.cpp | 61 ++++++ funasr/runtime/onnxruntime/src/paraformer.cpp | 76 +------- funasr/runtime/onnxruntime/src/paraformer.h | 16 +- funasr/runtime/onnxruntime/src/precomp.h | 7 +- funasr/runtime/onnxruntime/src/punc-model.cpp | 19 ++ funasr/runtime/onnxruntime/src/tokenizer.cpp | 4 + funasr/runtime/onnxruntime/src/tokenizer.h | 1 + funasr/runtime/onnxruntime/src/vad-model.cpp | 21 +++ 28 files changed, 723 insertions(+), 210 deletions(-) create mode 100644 funasr/runtime/onnxruntime/include/offline-stream.h create mode 100644 funasr/runtime/onnxruntime/include/punc-model.h create mode 100644 funasr/runtime/onnxruntime/include/vad-model.h create mode 100644 funasr/runtime/onnxruntime/src/funasr-onnx-offline-punc.cpp create mode 100644 funasr/runtime/onnxruntime/src/funasr-onnx-offline-vad.cpp create mode 100644 funasr/runtime/onnxruntime/src/offline-stream.cpp create mode 100644 funasr/runtime/onnxruntime/src/punc-model.cpp create mode 100644 funasr/runtime/onnxruntime/src/vad-model.cpp diff --git a/funasr/runtime/onnxruntime/include/audio.h b/funasr/runtime/onnxruntime/include/audio.h index ab9f420a2..a61a68fe9 100644 --- a/funasr/runtime/onnxruntime/include/audio.h +++ b/funasr/runtime/onnxruntime/include/audio.h @@ -1,10 +1,10 @@ - #ifndef AUDIO_H #define AUDIO_H #include #include -#include "model.h" +#include "vad-model.h" +#include "offline-stream.h" #ifndef WAV_HEADER_SIZE #define WAV_HEADER_SIZE 44 @@ -54,7 +54,8 @@ class Audio { int FetchChunck(float *&dout, int len); int Fetch(float *&dout, int &len, int &flag); void Padding(); - void Split(Model* recog_obj); + void Split(OfflineStream* offline_streamj); + void Split(VadModel* vad_obj, vector>& vad_segments); float GetTimeLen(); int GetQueueSize() { return (int)frame_queue.size(); } }; diff --git a/funasr/runtime/onnxruntime/include/com-define.h b/funasr/runtime/onnxruntime/include/com-define.h index 9b7b212b7..ad3bd35d3 100644 --- a/funasr/runtime/onnxruntime/include/com-define.h +++ b/funasr/runtime/onnxruntime/include/com-define.h @@ -12,20 +12,37 @@ #define MODEL_SAMPLE_RATE 16000 #endif -// model path -#define VAD_MODEL_PATH "vad-model" -#define VAD_CMVN_PATH "vad-cmvn" -#define VAD_CONFIG_PATH "vad-config" -#define AM_MODEL_PATH "am-model" -#define AM_CMVN_PATH "am-cmvn" -#define AM_CONFIG_PATH "am-config" -#define PUNC_MODEL_PATH "punc-model" -#define PUNC_CONFIG_PATH "punc-config" +// parser option +#define MODEL_DIR "model-dir" +#define VAD_DIR "vad-dir" +#define PUNC_DIR "punc-dir" +#define QUANTIZE "quantize" +#define VAD_QUANT "vad-quant" +#define PUNC_QUANT "punc-quant" + #define WAV_PATH "wav-path" #define WAV_SCP "wav-scp" +#define TXT_PATH "txt-path" #define THREAD_NUM "thread-num" #define PORT_ID "port-id" +// #define VAD_MODEL_PATH "vad-model" +// #define VAD_CMVN_PATH "vad-cmvn" +// #define VAD_CONFIG_PATH "vad-config" +// #define AM_MODEL_PATH "am-model" +// #define AM_CMVN_PATH "am-cmvn" +// #define AM_CONFIG_PATH "am-config" +// #define PUNC_MODEL_PATH "punc-model" +// #define PUNC_CONFIG_PATH "punc-config" + +#define MODEL_NAME "model.onnx" +#define QUANT_MODEL_NAME "model_quant.onnx" +#define VAD_CMVN_NAME "vad.mvn" +#define VAD_CONFIG_NAME "vad.yaml" +#define AM_CMVN_NAME "am.mvn" +#define AM_CONFIG_NAME "config.yaml" +#define PUNC_CONFIG_NAME "punc.yaml" + // vad #ifndef VAD_SILENCE_DURATION #define VAD_SILENCE_DURATION 800 diff --git a/funasr/runtime/onnxruntime/include/libfunasrapi.h b/funasr/runtime/onnxruntime/include/libfunasrapi.h index f65efccfc..152db6183 100644 --- a/funasr/runtime/onnxruntime/include/libfunasrapi.h +++ b/funasr/runtime/onnxruntime/include/libfunasrapi.h @@ -1,5 +1,6 @@ #pragma once #include +#include #ifdef WIN32 #ifdef _FUNASR_API_EXPORT @@ -47,8 +48,8 @@ typedef enum { typedef void (* QM_CALLBACK)(int cur_step, int n_total); // n_total: total steps; cur_step: Current Step. -// // ASR -_FUNASRAPI FUNASR_HANDLE FunASRInit(std::map& model_path, int thread_num); +// ASR +_FUNASRAPI FUNASR_HANDLE FunASRInit(std::map& model_path, int thread_num); _FUNASRAPI FUNASR_RESULT FunASRRecogBuffer(FUNASR_HANDLE handle, const char* sz_buf, int n_len, FUNASR_MODE mode, QM_CALLBACK fn_callback); _FUNASRAPI FUNASR_RESULT FunASRRecogPCMBuffer(FUNASR_HANDLE handle, const char* sz_buf, int n_len, int sampling_rate, FUNASR_MODE mode, QM_CALLBACK fn_callback); @@ -62,12 +63,23 @@ _FUNASRAPI void FunASRUninit(FUNASR_HANDLE handle); _FUNASRAPI const float FunASRGetRetSnippetTime(FUNASR_RESULT result); // VAD -_FUNASRAPI FUNASR_HANDLE FunVadInit(std::map& model_path, int thread_num); +_FUNASRAPI FUNASR_HANDLE FunVadInit(std::map& model_path, int thread_num); -_FUNASRAPI FUNASR_RESULT FunASRVadBuffer(FUNASR_HANDLE handle, const char* sz_buf, int n_len, FUNASR_MODE mode, QM_CALLBACK fn_callback); -_FUNASRAPI FUNASR_RESULT FunASRVadPCMBuffer(FUNASR_HANDLE handle, const char* sz_buf, int n_len, int sampling_rate, FUNASR_MODE mode, QM_CALLBACK fn_callback); -_FUNASRAPI FUNASR_RESULT FunASRVadPCMFile(FUNASR_HANDLE handle, const char* sz_filename, int sampling_rate, FUNASR_MODE mode, QM_CALLBACK fn_callback); -_FUNASRAPI FUNASR_RESULT FunASRVadFile(FUNASR_HANDLE handle, const char* sz_wavfile, FUNASR_MODE mode, QM_CALLBACK fn_callback); +_FUNASRAPI FUNASR_RESULT FunVadWavFile(FUNASR_HANDLE handle, const char* sz_wavfile, FUNASR_MODE mode, QM_CALLBACK fn_callback); +_FUNASRAPI std::vector>* FunVadGetResult(FUNASR_RESULT result,int n_index); +_FUNASRAPI void FunVadFreeResult(FUNASR_RESULT result); +_FUNASRAPI void FunVadUninit(FUNASR_HANDLE handle); +_FUNASRAPI const float FunVadGetRetSnippetTime(FUNASR_RESULT result); + +// PUNC +_FUNASRAPI FUNASR_HANDLE FunPuncInit(std::map& model_path, int thread_num); +_FUNASRAPI const std::string FunPuncInfer(FUNASR_HANDLE handle, const char* sz_sentence, FUNASR_MODE mode, QM_CALLBACK fn_callback); +_FUNASRAPI void FunPuncUninit(FUNASR_HANDLE handle); + +//OfflineStream +_FUNASRAPI FUNASR_HANDLE FunOfflineInit(std::map& model_path, int thread_num); +_FUNASRAPI FUNASR_RESULT FunOfflineStream(FUNASR_HANDLE handle, const char* sz_wavfile, FUNASR_MODE mode, QM_CALLBACK fn_callback); +_FUNASRAPI void FunOfflineUninit(FUNASR_HANDLE handle); #ifdef __cplusplus diff --git a/funasr/runtime/onnxruntime/include/model.h b/funasr/runtime/onnxruntime/include/model.h index 4b4b582ff..786fd28d1 100644 --- a/funasr/runtime/onnxruntime/include/model.h +++ b/funasr/runtime/onnxruntime/include/model.h @@ -9,13 +9,10 @@ class Model { public: virtual ~Model(){}; virtual void Reset() = 0; + virtual void InitAsr(const std::string &am_model, const std::string &am_cmvn, const std::string &am_config, int thread_num)=0; virtual std::string ForwardChunk(float *din, int len, int flag) = 0; virtual std::string Forward(float *din, int len, int flag) = 0; virtual std::string Rescoring() = 0; - virtual std::vector> VadSeg(std::vector& pcm_data)=0; - virtual std::string AddPunc(const char* sz_input)=0; - virtual bool UseVad() =0; - virtual bool UsePunc() =0; }; Model *CreateModel(std::map& model_path,int thread_num=1); diff --git a/funasr/runtime/onnxruntime/include/offline-stream.h b/funasr/runtime/onnxruntime/include/offline-stream.h new file mode 100644 index 000000000..caa4ea62b --- /dev/null +++ b/funasr/runtime/onnxruntime/include/offline-stream.h @@ -0,0 +1,28 @@ +#ifndef OFFLINE_STREAM_H +#define OFFLINE_STREAM_H + +#include +#include +#include +#include "model.h" +#include "punc-model.h" +#include "vad-model.h" + +class OfflineStream { + public: + OfflineStream(std::map& model_path, int thread_num); + ~OfflineStream(){}; + + std::unique_ptr vad_handle; + std::unique_ptr asr_handle; + std::unique_ptr punc_handle; + bool UseVad(){return use_vad;}; + bool UsePunc(){return use_punc;}; + + private: + bool use_vad=false; + bool use_punc=false; +}; + +OfflineStream *CreateOfflineStream(std::map& model_path, int thread_num=1); +#endif diff --git a/funasr/runtime/onnxruntime/include/punc-model.h b/funasr/runtime/onnxruntime/include/punc-model.h new file mode 100644 index 000000000..0bb353abe --- /dev/null +++ b/funasr/runtime/onnxruntime/include/punc-model.h @@ -0,0 +1,18 @@ + +#ifndef PUNC_MODEL_H +#define PUNC_MODEL_H + +#include +#include +#include + +class PuncModel { + public: + virtual ~PuncModel(){}; + virtual void InitPunc(const std::string &punc_model, const std::string &punc_config, int thread_num)=0; + virtual std::vector Infer(std::vector input_data)=0; + virtual std::string AddPunc(const char* sz_input)=0; +}; + +PuncModel *CreatePuncModel(std::map& model_path, int thread_num); +#endif diff --git a/funasr/runtime/onnxruntime/include/vad-model.h b/funasr/runtime/onnxruntime/include/vad-model.h new file mode 100644 index 000000000..646a1e954 --- /dev/null +++ b/funasr/runtime/onnxruntime/include/vad-model.h @@ -0,0 +1,27 @@ + +#ifndef VAD_MODEL_H +#define VAD_MODEL_H + +#include +#include +#include + +class VadModel { + public: + virtual ~VadModel(){}; + virtual void InitVad(const std::string &vad_model, const std::string &vad_cmvn, const std::string &vad_config, int thread_num)=0; + virtual std::vector> Infer(const std::vector &waves)=0; + virtual void ReadModel(const char* vad_model)=0; + virtual void LoadConfigFromYaml(const char* filename)=0; + virtual void FbankKaldi(float sample_rate, std::vector> &vad_feats, + const std::vector &waves)=0; + virtual std::vector> &LfrCmvn(std::vector> &vad_feats)=0; + virtual void Forward( + const std::vector> &chunk_feats, + std::vector> *out_prob)=0; + virtual void LoadCmvn(const char *filename)=0; + virtual void InitCache()=0; +}; + +VadModel *CreateVadModel(std::map& model_path, int thread_num); +#endif diff --git a/funasr/runtime/onnxruntime/src/CMakeLists.txt b/funasr/runtime/onnxruntime/src/CMakeLists.txt index 28a67b4be..341a16a7a 100644 --- a/funasr/runtime/onnxruntime/src/CMakeLists.txt +++ b/funasr/runtime/onnxruntime/src/CMakeLists.txt @@ -26,7 +26,11 @@ include_directories(${CMAKE_SOURCE_DIR}/include) target_link_libraries(funasr PUBLIC onnxruntime ${EXTRA_LIBS}) add_executable(funasr-onnx-offline "funasr-onnx-offline.cpp") +add_executable(funasr-onnx-offline-vad "funasr-onnx-offline-vad.cpp") +add_executable(funasr-onnx-offline-punc "funasr-onnx-offline-punc.cpp") add_executable(funasr-onnx-offline-rtf "funasr-onnx-offline-rtf.cpp") target_link_libraries(funasr-onnx-offline PUBLIC funasr) +target_link_libraries(funasr-onnx-offline-vad PUBLIC funasr) +target_link_libraries(funasr-onnx-offline-punc PUBLIC funasr) target_link_libraries(funasr-onnx-offline-rtf PUBLIC funasr) diff --git a/funasr/runtime/onnxruntime/src/audio.cpp b/funasr/runtime/onnxruntime/src/audio.cpp index d104500d1..6113614ed 100644 --- a/funasr/runtime/onnxruntime/src/audio.cpp +++ b/funasr/runtime/onnxruntime/src/audio.cpp @@ -237,6 +237,15 @@ bool Audio::LoadWav(const char *filename, int32_t* sampling_rate) LOG(ERROR) << "Failed to read " << filename; return false; } + + if (!header.Validate()) { + return false; + } + + header.SeekToDataChunk(is); + if (!is) { + return false; + } *sampling_rate = header.sample_rate; // header.subchunk2_size contains the number of bytes in the data. @@ -494,7 +503,7 @@ void Audio::Padding() delete frame; } -void Audio::Split(Model* recog_obj) +void Audio::Split(OfflineStream* offline_stream) { AudioFrame *frame; @@ -505,7 +514,7 @@ void Audio::Split(Model* recog_obj) frame = NULL; std::vector pcm_data(speech_data, speech_data+sp_len); - vector> vad_segments = recog_obj->VadSeg(pcm_data); + vector> vad_segments = (offline_stream->vad_handle)->Infer(pcm_data); int seg_sample = MODEL_SAMPLE_RATE/1000; for(vector segment:vad_segments) { @@ -518,3 +527,18 @@ void Audio::Split(Model* recog_obj) frame = NULL; } } + + +void Audio::Split(VadModel* vad_obj, vector>& vad_segments) +{ + AudioFrame *frame; + + frame = frame_queue.front(); + frame_queue.pop(); + int sp_len = frame->GetLen(); + delete frame; + frame = NULL; + + std::vector pcm_data(speech_data, speech_data+sp_len); + vad_segments = vad_obj->Infer(pcm_data); +} \ No newline at end of file diff --git a/funasr/runtime/onnxruntime/src/commonfunc.h b/funasr/runtime/onnxruntime/src/commonfunc.h index fbbda74e9..d5298c31c 100644 --- a/funasr/runtime/onnxruntime/src/commonfunc.h +++ b/funasr/runtime/onnxruntime/src/commonfunc.h @@ -6,6 +6,12 @@ typedef struct float snippet_time; }FUNASR_RECOG_RESULT; +typedef struct +{ + std::vector>* segments; + float snippet_time; +}FUNASR_VAD_RESULT; + #ifdef _WIN32 #include diff --git a/funasr/runtime/onnxruntime/src/ct-transformer.cpp b/funasr/runtime/onnxruntime/src/ct-transformer.cpp index ecde636ab..91e795c45 100644 --- a/funasr/runtime/onnxruntime/src/ct-transformer.cpp +++ b/funasr/runtime/onnxruntime/src/ct-transformer.cpp @@ -54,7 +54,7 @@ string CTTransformer::AddPunc(const char* sz_input) int nTotalBatch = ceil((float)InputData.size() / TOKEN_LEN); int nCurBatch = -1; int nSentEnd = -1, nLastCommaIndex = -1; - vector RemainIDs; // + vector RemainIDs; // vector RemainStr; // vector NewPunctuation; // vector NewString; // @@ -64,7 +64,7 @@ string CTTransformer::AddPunc(const char* sz_input) for (size_t i = 0; i < InputData.size(); i += TOKEN_LEN) { nDiff = (i + TOKEN_LEN) < InputData.size() ? (0) : (i + TOKEN_LEN - InputData.size()); - vector InputIDs(InputData.begin() + i, InputData.begin() + i + TOKEN_LEN - nDiff); + vector InputIDs(InputData.begin() + i, InputData.begin() + i + TOKEN_LEN - nDiff); vector InputStr(strOut.begin() + i, strOut.begin() + i + TOKEN_LEN - nDiff); InputIDs.insert(InputIDs.begin(), RemainIDs.begin(), RemainIDs.end()); // RemainIDs+InputIDs; InputStr.insert(InputStr.begin(), RemainStr.begin(), RemainStr.end()); // RemainStr+InputStr; @@ -141,12 +141,13 @@ string CTTransformer::AddPunc(const char* sz_input) return strResult; } -vector CTTransformer::Infer(vector input_data) +vector CTTransformer::Infer(vector input_data) { Ort::MemoryInfo m_memoryInfo = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault); vector punction; std::array input_shape_{ 1, (int64_t)input_data.size()}; - Ort::Value onnx_input = Ort::Value::CreateTensor(m_memoryInfo, + Ort::Value onnx_input = Ort::Value::CreateTensor( + m_memoryInfo, input_data.data(), input_data.size(), input_shape_.data(), diff --git a/funasr/runtime/onnxruntime/src/ct-transformer.h b/funasr/runtime/onnxruntime/src/ct-transformer.h index d965bb33a..cff4f4747 100644 --- a/funasr/runtime/onnxruntime/src/ct-transformer.h +++ b/funasr/runtime/onnxruntime/src/ct-transformer.h @@ -5,7 +5,7 @@ #pragma once -class CTTransformer { +class CTTransformer : public PuncModel { /** * Author: Speech Lab of DAMO Academy, Alibaba Group * CT-Transformer: Controllable time-delay transformer for real-time punctuation prediction and disfluency detection @@ -27,6 +27,6 @@ public: CTTransformer(); void InitPunc(const std::string &punc_model, const std::string &punc_config, int thread_num); ~CTTransformer(); - vector Infer(vector input_data); + vector Infer(vector input_data); string AddPunc(const char* sz_input); }; diff --git a/funasr/runtime/onnxruntime/src/fsmn-vad.cpp b/funasr/runtime/onnxruntime/src/fsmn-vad.cpp index fbb682b69..b1b0e639c 100644 --- a/funasr/runtime/onnxruntime/src/fsmn-vad.cpp +++ b/funasr/runtime/onnxruntime/src/fsmn-vad.cpp @@ -6,8 +6,8 @@ #include #include "precomp.h" -void FsmnVad::InitVad(const std::string &vad_model, const std::string &vad_cmvn, const std::string &vad_config) { - session_options_.SetIntraOpNumThreads(1); +void FsmnVad::InitVad(const std::string &vad_model, const std::string &vad_cmvn, const std::string &vad_config, int thread_num) { + session_options_.SetIntraOpNumThreads(thread_num); session_options_.SetGraphOptimizationLevel(ORT_ENABLE_ALL); session_options_.DisableCpuMemArena(); @@ -296,5 +296,8 @@ void FsmnVad::Reset(){ void FsmnVad::Test() { } +FsmnVad::~FsmnVad() { +} + FsmnVad::FsmnVad():env_(ORT_LOGGING_LEVEL_ERROR, ""),session_options_{} { } diff --git a/funasr/runtime/onnxruntime/src/fsmn-vad.h b/funasr/runtime/onnxruntime/src/fsmn-vad.h index 1d5f68c56..cf03ce91a 100644 --- a/funasr/runtime/onnxruntime/src/fsmn-vad.h +++ b/funasr/runtime/onnxruntime/src/fsmn-vad.h @@ -8,7 +8,7 @@ #include "precomp.h" -class FsmnVad { +class FsmnVad : public VadModel { /** * Author: Speech Lab of DAMO Academy, Alibaba Group * Deep-FSMN for Large Vocabulary Continuous Speech Recognition @@ -17,9 +17,9 @@ class FsmnVad { public: FsmnVad(); + ~FsmnVad(); void Test(); - void InitVad(const std::string &vad_model, const std::string &vad_cmvn, const std::string &vad_config); - + void InitVad(const std::string &vad_model, const std::string &vad_cmvn, const std::string &vad_config, int thread_num); std::vector> Infer(const std::vector &waves); void Reset(); diff --git a/funasr/runtime/onnxruntime/src/funasr-onnx-offline-punc.cpp b/funasr/runtime/onnxruntime/src/funasr-onnx-offline-punc.cpp new file mode 100644 index 000000000..e8f221f6f --- /dev/null +++ b/funasr/runtime/onnxruntime/src/funasr-onnx-offline-punc.cpp @@ -0,0 +1,98 @@ +/** + * Copyright FunASR (https://github.com/alibaba-damo-academy/FunASR). All Rights Reserved. + * MIT License (https://opensource.org/licenses/MIT) +*/ + +#ifndef _WIN32 +#include +#else +#include +#endif + +#include +#include +#include +#include +#include +#include "libfunasrapi.h" +#include "tclap/CmdLine.h" +#include "com-define.h" + +using namespace std; + +void GetValue(TCLAP::ValueArg& value_arg, string key, std::map& model_path) +{ + if (value_arg.isSet()){ + model_path.insert({key, value_arg.getValue()}); + LOG(INFO)<< key << " : " << value_arg.getValue(); + } +} + +int main(int argc, char *argv[]) +{ + google::InitGoogleLogging(argv[0]); + FLAGS_logtostderr = true; + + TCLAP::CmdLine cmd("funasr-onnx-offline-punc", ' ', "1.0"); + TCLAP::ValueArg model_dir("", MODEL_DIR, "the punc model path, which contains model.onnx, punc.yaml", true, "", "string"); + TCLAP::ValueArg quantize("", QUANTIZE, "false (Default), load the model of model.onnx in model_dir. If set true, load the model of model_quant.onnx in model_dir", false, "false", "string"); + TCLAP::ValueArg txt_path("", TXT_PATH, "txt file path, one sentence per line", false, "", "string"); + + cmd.add(model_dir); + cmd.add(quantize); + cmd.add(txt_path); + cmd.parse(argc, argv); + + std::map model_path; + GetValue(model_dir, MODEL_DIR, model_path); + GetValue(quantize, QUANTIZE, model_path); + GetValue(txt_path, TXT_PATH, model_path); + + struct timeval start, end; + gettimeofday(&start, NULL); + int thread_num = 1; + FUNASR_HANDLE punc_hanlde=FunPuncInit(model_path, thread_num); + + if (!punc_hanlde) + { + LOG(ERROR) << "FunASR init failed"; + exit(-1); + } + + gettimeofday(&end, NULL); + long seconds = (end.tv_sec - start.tv_sec); + long modle_init_micros = ((seconds * 1000000) + end.tv_usec) - (start.tv_usec); + LOG(INFO) << "Model initialization takes " << (double)modle_init_micros / 1000000 << " s"; + + // read txt_path + vector txt_list; + + if(model_path.find(TXT_PATH)!=model_path.end()){ + ifstream in(model_path.at(TXT_PATH)); + if (!in.is_open()) { + LOG(ERROR) << "Failed to open file: " << model_path.at(TXT_PATH) ; + return 0; + } + string line; + while(getline(in, line)) + { + txt_list.emplace_back(line); + } + in.close(); + } + + long taking_micros = 0; + for(auto& txt_str : txt_list){ + gettimeofday(&start, NULL); + string result=FunPuncInfer(punc_hanlde, txt_str.c_str(), RASR_NONE, NULL); + gettimeofday(&end, NULL); + seconds = (end.tv_sec - start.tv_sec); + taking_micros += ((seconds * 1000000) + end.tv_usec) - (start.tv_usec); + LOG(INFO)<<"Results: "< vad_model("", VAD_MODEL_PATH, "vad model path", false, "", "string"); - TCLAP::ValueArg vad_cmvn("", VAD_CMVN_PATH, "vad cmvn path", false, "", "string"); - TCLAP::ValueArg vad_config("", VAD_CONFIG_PATH, "vad config path", false, "", "string"); - - TCLAP::ValueArg am_model("", AM_MODEL_PATH, "am model path", false, "", "string"); - TCLAP::ValueArg am_cmvn("", AM_CMVN_PATH, "am cmvn path", false, "", "string"); - TCLAP::ValueArg am_config("", AM_CONFIG_PATH, "am config path", false, "", "string"); - - TCLAP::ValueArg punc_model("", PUNC_MODEL_PATH, "punc model path", false, "", "string"); - TCLAP::ValueArg punc_config("", PUNC_CONFIG_PATH, "punc config path", false, "", "string"); + TCLAP::ValueArg model_dir("", MODEL_DIR, "the model path, which contains model.onnx, config.yaml, am.mvn", true, "", "string"); + TCLAP::ValueArg quantize("", QUANTIZE, "false (Default), load the model of model.onnx in model_dir. If set true, load the model of model_quant.onnx in model_dir", false, "false", "string"); TCLAP::ValueArg wav_scp("", WAV_SCP, "wave scp path", true, "", "string"); TCLAP::ValueArg thread_num("", THREAD_NUM, "multi-thread num for rtf", true, 0, "int32_t"); - cmd.add(vad_model); - cmd.add(vad_cmvn); - cmd.add(vad_config); - cmd.add(am_model); - cmd.add(am_cmvn); - cmd.add(am_config); - cmd.add(punc_model); - cmd.add(punc_config); + cmd.add(model_dir); + cmd.add(quantize); cmd.add(wav_scp); cmd.add(thread_num); cmd.parse(argc, argv); std::map model_path; - GetValue(vad_model, VAD_MODEL_PATH, model_path); - GetValue(vad_cmvn, VAD_CMVN_PATH, model_path); - GetValue(vad_config, VAD_CONFIG_PATH, model_path); - GetValue(am_model, AM_MODEL_PATH, model_path); - GetValue(am_cmvn, AM_CMVN_PATH, model_path); - GetValue(am_config, AM_CONFIG_PATH, model_path); - GetValue(punc_model, PUNC_MODEL_PATH, model_path); - GetValue(punc_config, PUNC_CONFIG_PATH, model_path); + GetValue(model_dir, MODEL_DIR, model_path); + GetValue(quantize, QUANTIZE, model_path); GetValue(wav_scp, WAV_SCP, model_path); struct timeval start, end; diff --git a/funasr/runtime/onnxruntime/src/funasr-onnx-offline-vad.cpp b/funasr/runtime/onnxruntime/src/funasr-onnx-offline-vad.cpp new file mode 100644 index 000000000..278753484 --- /dev/null +++ b/funasr/runtime/onnxruntime/src/funasr-onnx-offline-vad.cpp @@ -0,0 +1,143 @@ +/** + * Copyright FunASR (https://github.com/alibaba-damo-academy/FunASR). All Rights Reserved. + * MIT License (https://opensource.org/licenses/MIT) +*/ + +#ifndef _WIN32 +#include +#else +#include +#endif + +#include +#include +#include +#include +#include +#include +#include "libfunasrapi.h" +#include "tclap/CmdLine.h" +#include "com-define.h" + +using namespace std; + +void GetValue(TCLAP::ValueArg& value_arg, string key, std::map& model_path) +{ + if (value_arg.isSet()){ + model_path.insert({key, value_arg.getValue()}); + LOG(INFO)<< key << " : " << value_arg.getValue(); + } +} + +void print_segs(vector>* vec) { + string seg_out="["; + for (int i = 0; i < vec->size(); i++) { + vector inner_vec = (*vec)[i]; + seg_out += "["; + for (int j = 0; j < inner_vec.size(); j++) { + seg_out += to_string(inner_vec[j]); + if (j != inner_vec.size() - 1) { + seg_out += ","; + } + } + seg_out += "]"; + if (i != vec->size() - 1) { + seg_out += ","; + } + } + seg_out += "]"; + LOG(INFO)< model_dir("", MODEL_DIR, "the vad model path, which contains model.onnx, vad.yaml, vad.mvn", true, "", "string"); + TCLAP::ValueArg quantize("", QUANTIZE, "false (Default), load the model of model.onnx in model_dir. If set true, load the model of model_quant.onnx in model_dir", false, "false", "string"); + + TCLAP::ValueArg wav_path("", WAV_PATH, "wave file path", false, "", "string"); + TCLAP::ValueArg wav_scp("", WAV_SCP, "wave scp path", false, "", "string"); + + cmd.add(model_dir); + cmd.add(quantize); + cmd.add(wav_path); + cmd.add(wav_scp); + cmd.parse(argc, argv); + + std::map model_path; + GetValue(model_dir, MODEL_DIR, model_path); + GetValue(quantize, QUANTIZE, model_path); + GetValue(wav_path, WAV_PATH, model_path); + GetValue(wav_scp, WAV_SCP, model_path); + + struct timeval start, end; + gettimeofday(&start, NULL); + int thread_num = 1; + FUNASR_HANDLE vad_hanlde=FunVadInit(model_path, thread_num); + + if (!vad_hanlde) + { + LOG(ERROR) << "FunVad init failed"; + exit(-1); + } + + gettimeofday(&end, NULL); + long seconds = (end.tv_sec - start.tv_sec); + long modle_init_micros = ((seconds * 1000000) + end.tv_usec) - (start.tv_usec); + LOG(INFO) << "Model initialization takes " << (double)modle_init_micros / 1000000 << " s"; + + // read wav_path and wav_scp + vector wav_list; + + if(model_path.find(WAV_PATH)!=model_path.end()){ + wav_list.emplace_back(model_path.at(WAV_PATH)); + } + if(model_path.find(WAV_SCP)!=model_path.end()){ + ifstream in(model_path.at(WAV_SCP)); + if (!in.is_open()) { + LOG(ERROR) << "Failed to open file: " << model_path.at(WAV_SCP) ; + return 0; + } + string line; + while(getline(in, line)) + { + istringstream iss(line); + string column1, column2; + iss >> column1 >> column2; + wav_list.emplace_back(column2); + } + in.close(); + } + + float snippet_time = 0.0f; + long taking_micros = 0; + for(auto& wav_file : wav_list){ + gettimeofday(&start, NULL); + FUNASR_RESULT result=FunVadWavFile(vad_hanlde, wav_file.c_str(), RASR_NONE, NULL); + gettimeofday(&end, NULL); + seconds = (end.tv_sec - start.tv_sec); + taking_micros += ((seconds * 1000000) + end.tv_usec) - (start.tv_usec); + + if (result) + { + vector>* vad_segments = FunVadGetResult(result, 0); + print_segs(vad_segments); + snippet_time += FunVadGetRetSnippetTime(result); + FunVadFreeResult(result); + } + else + { + LOG(ERROR) << ("No return data!\n"); + } + } + + LOG(INFO) << "Audio length: " << (double)snippet_time << " s"; + LOG(INFO) << "Model inference takes: " << (double)taking_micros / 1000000 <<" s"; + LOG(INFO) << "Model inference RTF: " << (double)taking_micros/ (snippet_time*1000000); + FunVadUninit(vad_hanlde); + return 0; +} + diff --git a/funasr/runtime/onnxruntime/src/funasr-onnx-offline.cpp b/funasr/runtime/onnxruntime/src/funasr-onnx-offline.cpp index 2d61bbb30..af6d0e3ce 100644 --- a/funasr/runtime/onnxruntime/src/funasr-onnx-offline.cpp +++ b/funasr/runtime/onnxruntime/src/funasr-onnx-offline.cpp @@ -28,55 +28,46 @@ void GetValue(TCLAP::ValueArg& value_arg, string key, std::map vad_model("", VAD_MODEL_PATH, "vad model path", false, "", "string"); - TCLAP::ValueArg vad_cmvn("", VAD_CMVN_PATH, "vad cmvn path", false, "", "string"); - TCLAP::ValueArg vad_config("", VAD_CONFIG_PATH, "vad config path", false, "", "string"); - - TCLAP::ValueArg am_model("", AM_MODEL_PATH, "am model path", true, "", "string"); - TCLAP::ValueArg am_cmvn("", AM_CMVN_PATH, "am cmvn path", true, "", "string"); - TCLAP::ValueArg am_config("", AM_CONFIG_PATH, "am config path", true, "", "string"); - - TCLAP::ValueArg punc_model("", PUNC_MODEL_PATH, "punc model path", false, "", "string"); - TCLAP::ValueArg punc_config("", PUNC_CONFIG_PATH, "punc config path", false, "", "string"); + TCLAP::ValueArg model_dir("", MODEL_DIR, "the model path, which contains model.onnx, config.yaml, am.mvn", true, "", "string"); + TCLAP::ValueArg quantize("", QUANTIZE, "false (Default), load the model of model.onnx in model_dir. If set true, load the model of model_quant.onnx in model_dir", false, "false", "string"); + TCLAP::ValueArg vad_dir("", VAD_DIR, "the vad model path, which contains model.onnx, vad.yaml, vad.mvn", false, "", "string"); + TCLAP::ValueArg vad_quant("", VAD_QUANT, "false (Default), load the model of model.onnx in vad_dir. If set true, load the model of model_quant.onnx in vad_dir", false, "false", "string"); + TCLAP::ValueArg punc_dir("", PUNC_DIR, "the punc model path, which contains model.onnx, punc.yaml", false, "", "string"); + TCLAP::ValueArg punc_quant("", PUNC_QUANT, "false (Default), load the model of model.onnx in punc_dir. If set true, load the model of model_quant.onnx in punc_dir", false, "false", "string"); TCLAP::ValueArg wav_path("", WAV_PATH, "wave file path", false, "", "string"); TCLAP::ValueArg wav_scp("", WAV_SCP, "wave scp path", false, "", "string"); - cmd.add(vad_model); - cmd.add(vad_cmvn); - cmd.add(vad_config); - cmd.add(am_model); - cmd.add(am_cmvn); - cmd.add(am_config); - cmd.add(punc_model); - cmd.add(punc_config); + cmd.add(model_dir); + cmd.add(quantize); + cmd.add(vad_dir); + cmd.add(vad_quant); + cmd.add(punc_dir); + cmd.add(punc_quant); cmd.add(wav_path); cmd.add(wav_scp); cmd.parse(argc, argv); std::map model_path; - GetValue(vad_model, VAD_MODEL_PATH, model_path); - GetValue(vad_cmvn, VAD_CMVN_PATH, model_path); - GetValue(vad_config, VAD_CONFIG_PATH, model_path); - GetValue(am_model, AM_MODEL_PATH, model_path); - GetValue(am_cmvn, AM_CMVN_PATH, model_path); - GetValue(am_config, AM_CONFIG_PATH, model_path); - GetValue(punc_model, PUNC_MODEL_PATH, model_path); - GetValue(punc_config, PUNC_CONFIG_PATH, model_path); + GetValue(model_dir, MODEL_DIR, model_path); + GetValue(quantize, QUANTIZE, model_path); + GetValue(vad_dir, VAD_DIR, model_path); + GetValue(vad_quant, VAD_QUANT, model_path); + GetValue(punc_dir, PUNC_DIR, model_path); + GetValue(punc_quant, PUNC_QUANT, model_path); GetValue(wav_path, WAV_PATH, model_path); GetValue(wav_scp, WAV_SCP, model_path); - struct timeval start, end; gettimeofday(&start, NULL); int thread_num = 1; - FUNASR_HANDLE asr_hanlde=FunASRInit(model_path, thread_num); + FUNASR_HANDLE asr_hanlde=FunOfflineInit(model_path, thread_num); if (!asr_hanlde) { @@ -116,7 +107,7 @@ int main(int argc, char *argv[]) long taking_micros = 0; for(auto& wav_file : wav_list){ gettimeofday(&start, NULL); - FUNASR_RESULT result=FunASRRecogFile(asr_hanlde, wav_file.c_str(), RASR_NONE, NULL); + FUNASR_RESULT result=FunOfflineStream(asr_hanlde, wav_file.c_str(), RASR_NONE, NULL); gettimeofday(&end, NULL); seconds = (end.tv_sec - start.tv_sec); taking_micros += ((seconds * 1000000) + end.tv_usec) - (start.tv_usec); @@ -124,8 +115,7 @@ int main(int argc, char *argv[]) if (result) { string msg = FunASRGetResult(result, 0); - setbuf(stdout, NULL); - printf("Result: %s \n", msg.c_str()); + LOG(INFO)<<"Result: "<& model_path, int thread_num) { Model* mm = CreateModel(model_path, thread_num); @@ -13,10 +13,23 @@ extern "C" { _FUNASRAPI FUNASR_HANDLE FunVadInit(std::map& model_path, int thread_num) { - Model* mm = CreateModel(model_path, thread_num); + VadModel* mm = CreateVadModel(model_path, thread_num); return mm; } + _FUNASRAPI FUNASR_HANDLE FunPuncInit(std::map& model_path, int thread_num) + { + PuncModel* mm = CreatePuncModel(model_path, thread_num); + return mm; + } + + _FUNASRAPI FUNASR_HANDLE FunOfflineInit(std::map& model_path, int thread_num) + { + OfflineStream* mm = CreateOfflineStream(model_path, thread_num); + return mm; + } + + // APIs for ASR Infer _FUNASRAPI FUNASR_RESULT FunASRRecogBuffer(FUNASR_HANDLE handle, const char* sz_buf, int n_len, FUNASR_MODE mode, QM_CALLBACK fn_callback) { Model* recog_obj = (Model*)handle; @@ -27,9 +40,6 @@ extern "C" { Audio audio(1); if (!audio.LoadWav(sz_buf, n_len, &sampling_rate)) return nullptr; - if(recog_obj->UseVad()){ - audio.Split(recog_obj); - } float* buff; int len; @@ -45,10 +55,6 @@ extern "C" { if (fn_callback) fn_callback(n_step, n_total); } - if(recog_obj->UsePunc()){ - string punc_res = recog_obj->AddPunc((p_result->msg).c_str()); - p_result->msg = punc_res; - } return p_result; } @@ -62,9 +68,6 @@ extern "C" { Audio audio(1); if (!audio.LoadPcmwav(sz_buf, n_len, &sampling_rate)) return nullptr; - if(recog_obj->UseVad()){ - audio.Split(recog_obj); - } float* buff; int len; @@ -80,10 +83,6 @@ extern "C" { if (fn_callback) fn_callback(n_step, n_total); } - if(recog_obj->UsePunc()){ - string punc_res = recog_obj->AddPunc((p_result->msg).c_str()); - p_result->msg = punc_res; - } return p_result; } @@ -97,9 +96,6 @@ extern "C" { Audio audio(1); if (!audio.LoadPcmwav(sz_filename, &sampling_rate)) return nullptr; - if(recog_obj->UseVad()){ - audio.Split(recog_obj); - } float* buff; int len; @@ -115,10 +111,6 @@ extern "C" { if (fn_callback) fn_callback(n_step, n_total); } - if(recog_obj->UsePunc()){ - string punc_res = recog_obj->AddPunc((p_result->msg).c_str()); - p_result->msg = punc_res; - } return p_result; } @@ -133,9 +125,6 @@ extern "C" { Audio audio(1); if(!audio.LoadWav(sz_wavfile, &sampling_rate)) return nullptr; - if(recog_obj->UseVad()){ - audio.Split(recog_obj); - } float* buff; int len; @@ -151,8 +140,74 @@ extern "C" { if (fn_callback) fn_callback(n_step, n_total); } - if(recog_obj->UsePunc()){ - string punc_res = recog_obj->AddPunc((p_result->msg).c_str()); + + return p_result; + } + + // APIs for VAD Infer + _FUNASRAPI FUNASR_RESULT FunVadWavFile(FUNASR_HANDLE handle, const char* sz_wavfile, FUNASR_MODE mode, QM_CALLBACK fn_callback) + { + VadModel* vad_obj = (VadModel*)handle; + if (!vad_obj) + return nullptr; + + int32_t sampling_rate = -1; + Audio audio(1); + if(!audio.LoadWav(sz_wavfile, &sampling_rate)) + return nullptr; + + FUNASR_VAD_RESULT* p_result = new FUNASR_VAD_RESULT; + p_result->snippet_time = audio.GetTimeLen(); + + vector> vad_segments; + audio.Split(vad_obj, vad_segments); + p_result->segments = new vector>(vad_segments); + + return p_result; + } + + // APIs for PUNC Infer + _FUNASRAPI const std::string FunPuncInfer(FUNASR_HANDLE handle, const char* sz_sentence, FUNASR_MODE mode, QM_CALLBACK fn_callback) + { + PuncModel* punc_obj = (PuncModel*)handle; + if (!punc_obj) + return nullptr; + + string punc_res = punc_obj->AddPunc(sz_sentence); + return punc_res; + } + + // APIs for Offline-stream Infer + _FUNASRAPI FUNASR_RESULT FunOfflineStream(FUNASR_HANDLE handle, const char* sz_wavfile, FUNASR_MODE mode, QM_CALLBACK fn_callback) + { + OfflineStream* offline_stream = (OfflineStream*)handle; + if (!offline_stream) + return nullptr; + + int32_t sampling_rate = -1; + Audio audio(1); + if(!audio.LoadWav(sz_wavfile, &sampling_rate)) + return nullptr; + if(offline_stream->UseVad()){ + audio.Split(offline_stream); + } + + float* buff; + int len; + int flag = 0; + int n_step = 0; + int n_total = audio.GetQueueSize(); + FUNASR_RECOG_RESULT* p_result = new FUNASR_RECOG_RESULT; + p_result->snippet_time = audio.GetTimeLen(); + while (audio.Fetch(buff, len, flag) > 0) { + string msg = (offline_stream->asr_handle)->Forward(buff, len, flag); + p_result->msg+= msg; + n_step++; + if (fn_callback) + fn_callback(n_step, n_total); + } + if(offline_stream->UsePunc()){ + string punc_res = (offline_stream->punc_handle)->AddPunc((p_result->msg).c_str()); p_result->msg = punc_res; } @@ -167,7 +222,7 @@ extern "C" { return 1; } - + // APIs for GetRetSnippetTime _FUNASRAPI const float FunASRGetRetSnippetTime(FUNASR_RESULT result) { if (!result) @@ -176,6 +231,15 @@ extern "C" { return ((FUNASR_RECOG_RESULT*)result)->snippet_time; } + _FUNASRAPI const float FunVadGetRetSnippetTime(FUNASR_RESULT result) + { + if (!result) + return 0.0f; + + return ((FUNASR_VAD_RESULT*)result)->snippet_time; + } + + // APIs for GetResult _FUNASRAPI const char* FunASRGetResult(FUNASR_RESULT result,int n_index) { FUNASR_RECOG_RESULT * p_result = (FUNASR_RECOG_RESULT*)result; @@ -185,6 +249,16 @@ extern "C" { return p_result->msg.c_str(); } + _FUNASRAPI vector>* FunVadGetResult(FUNASR_RESULT result,int n_index) + { + FUNASR_VAD_RESULT * p_result = (FUNASR_VAD_RESULT*)result; + if(!p_result) + return nullptr; + + return p_result->segments; + } + + // APIs for FreeResult _FUNASRAPI void FunASRFreeResult(FUNASR_RESULT result) { if (result) @@ -193,6 +267,19 @@ extern "C" { } } + _FUNASRAPI void FunVadFreeResult(FUNASR_RESULT result) + { + FUNASR_VAD_RESULT * p_result = (FUNASR_VAD_RESULT*)result; + if (p_result) + { + if(p_result->segments){ + delete p_result->segments; + } + delete p_result; + } + } + + // APIs for Uninit _FUNASRAPI void FunASRUninit(FUNASR_HANDLE handle) { Model* recog_obj = (Model*)handle; @@ -203,6 +290,36 @@ extern "C" { delete recog_obj; } + _FUNASRAPI void FunVadUninit(FUNASR_HANDLE handle) + { + VadModel* recog_obj = (VadModel*)handle; + + if (!recog_obj) + return; + + delete recog_obj; + } + + _FUNASRAPI void FunPuncUninit(FUNASR_HANDLE handle) + { + PuncModel* punc_obj = (PuncModel*)handle; + + if (!punc_obj) + return; + + delete punc_obj; + } + + _FUNASRAPI void FunOfflineUninit(FUNASR_HANDLE handle) + { + OfflineStream* offline_stream = (OfflineStream*)handle; + + if (!offline_stream) + return; + + delete offline_stream; + } + #ifdef __cplusplus } diff --git a/funasr/runtime/onnxruntime/src/model.cpp b/funasr/runtime/onnxruntime/src/model.cpp index 52ce7ba7c..65ea172f0 100644 --- a/funasr/runtime/onnxruntime/src/model.cpp +++ b/funasr/runtime/onnxruntime/src/model.cpp @@ -2,7 +2,19 @@ Model *CreateModel(std::map& model_path, int thread_num) { + string am_model_path; + string am_cmvn_path; + string am_config_path; + + am_model_path = PathAppend(model_path.at(MODEL_DIR), MODEL_NAME); + if(model_path.find(QUANTIZE) != model_path.end() && model_path.at(QUANTIZE) == "true"){ + am_model_path = PathAppend(model_path.at(MODEL_DIR), QUANT_MODEL_NAME); + } + am_cmvn_path = PathAppend(model_path.at(MODEL_DIR), AM_CMVN_NAME); + am_config_path = PathAppend(model_path.at(MODEL_DIR), AM_CONFIG_NAME); + Model *mm; - mm = new paraformer::Paraformer(model_path, thread_num); + mm = new paraformer::Paraformer(); + mm->InitAsr(am_model_path, am_cmvn_path, am_config_path, thread_num); return mm; } diff --git a/funasr/runtime/onnxruntime/src/offline-stream.cpp b/funasr/runtime/onnxruntime/src/offline-stream.cpp new file mode 100644 index 000000000..00c131844 --- /dev/null +++ b/funasr/runtime/onnxruntime/src/offline-stream.cpp @@ -0,0 +1,61 @@ +#include "precomp.h" + +OfflineStream::OfflineStream(std::map& model_path, int thread_num) +{ + // VAD model + if(model_path.find(VAD_DIR) != model_path.end()){ + use_vad = true; + string vad_model_path; + string vad_cmvn_path; + string vad_config_path; + + vad_model_path = PathAppend(model_path.at(VAD_DIR), MODEL_NAME); + if(model_path.find(VAD_QUANT) != model_path.end() && model_path.at(VAD_QUANT) == "true"){ + vad_model_path = PathAppend(model_path.at(VAD_DIR), QUANT_MODEL_NAME); + } + vad_cmvn_path = PathAppend(model_path.at(VAD_DIR), VAD_CMVN_NAME); + vad_config_path = PathAppend(model_path.at(VAD_DIR), VAD_CONFIG_NAME); + vad_handle = make_unique(); + vad_handle->InitVad(vad_model_path, vad_cmvn_path, vad_config_path, thread_num); + } + + // AM model + if(model_path.find(MODEL_DIR) != model_path.end()){ + string am_model_path; + string am_cmvn_path; + string am_config_path; + + am_model_path = PathAppend(model_path.at(MODEL_DIR), MODEL_NAME); + if(model_path.find(QUANTIZE) != model_path.end() && model_path.at(QUANTIZE) == "true"){ + am_model_path = PathAppend(model_path.at(MODEL_DIR), QUANT_MODEL_NAME); + } + am_cmvn_path = PathAppend(model_path.at(MODEL_DIR), AM_CMVN_NAME); + am_config_path = PathAppend(model_path.at(MODEL_DIR), AM_CONFIG_NAME); + + asr_handle = make_unique(); + asr_handle->InitAsr(am_model_path, am_cmvn_path, am_config_path, thread_num); + } + + // PUNC model + if(model_path.find(PUNC_DIR) != model_path.end()){ + use_punc = true; + string punc_model_path; + string punc_config_path; + + punc_model_path = PathAppend(model_path.at(PUNC_DIR), MODEL_NAME); + if(model_path.find(PUNC_QUANT) != model_path.end() && model_path.at(PUNC_QUANT) == "true"){ + punc_model_path = PathAppend(model_path.at(PUNC_DIR), QUANT_MODEL_NAME); + } + punc_config_path = PathAppend(model_path.at(PUNC_DIR), PUNC_CONFIG_NAME); + + punc_handle = make_unique(); + punc_handle->InitPunc(punc_model_path, punc_config_path, thread_num); + } +} + +OfflineStream *CreateOfflineStream(std::map& model_path, int thread_num) +{ + OfflineStream *mm; + mm = new OfflineStream(model_path, thread_num); + return mm; +} diff --git a/funasr/runtime/onnxruntime/src/paraformer.cpp b/funasr/runtime/onnxruntime/src/paraformer.cpp index 136d22808..244a706db 100644 --- a/funasr/runtime/onnxruntime/src/paraformer.cpp +++ b/funasr/runtime/onnxruntime/src/paraformer.cpp @@ -8,65 +8,11 @@ using namespace std; using namespace paraformer; -Paraformer::Paraformer(std::map& model_path,int thread_num) +Paraformer::Paraformer() :env_(ORT_LOGGING_LEVEL_ERROR, "paraformer"),session_options{}{ - - // VAD model - if(model_path.find(VAD_MODEL_PATH) != model_path.end()){ - use_vad = true; - string vad_model_path; - string vad_cmvn_path; - string vad_config_path; - - try{ - vad_model_path = model_path.at(VAD_MODEL_PATH); - vad_cmvn_path = model_path.at(VAD_CMVN_PATH); - vad_config_path = model_path.at(VAD_CONFIG_PATH); - }catch(const out_of_range& e){ - LOG(ERROR) << "Error when read "<< VAD_CMVN_PATH << " or " << VAD_CONFIG_PATH <<" :" << e.what(); - exit(0); - } - vad_handle = make_unique(); - vad_handle->InitVad(vad_model_path, vad_cmvn_path, vad_config_path); - } - - // AM model - if(model_path.find(AM_MODEL_PATH) != model_path.end()){ - string am_model_path; - string am_cmvn_path; - string am_config_path; - - try{ - am_model_path = model_path.at(AM_MODEL_PATH); - am_cmvn_path = model_path.at(AM_CMVN_PATH); - am_config_path = model_path.at(AM_CONFIG_PATH); - }catch(const out_of_range& e){ - LOG(ERROR) << "Error when read "<< AM_CONFIG_PATH << " or " << AM_CMVN_PATH <<" :" << e.what(); - exit(0); - } - InitAM(am_model_path, am_cmvn_path, am_config_path, thread_num); - } - - // PUNC model - if(model_path.find(PUNC_MODEL_PATH) != model_path.end()){ - use_punc = true; - string punc_model_path; - string punc_config_path; - - try{ - punc_model_path = model_path.at(PUNC_MODEL_PATH); - punc_config_path = model_path.at(PUNC_CONFIG_PATH); - }catch(const out_of_range& e){ - LOG(ERROR) << "Error when read "<< PUNC_CONFIG_PATH <<" :" << e.what(); - exit(0); - } - - punc_handle = make_unique(); - punc_handle->InitPunc(punc_model_path, punc_config_path, thread_num); - } } -void Paraformer::InitAM(const std::string &am_model, const std::string &am_cmvn, const std::string &am_config, int thread_num){ +void Paraformer::InitAsr(const std::string &am_model, const std::string &am_cmvn, const std::string &am_config, int thread_num){ // knf options fbank_opts.frame_opts.dither = 0; fbank_opts.mel_opts.num_bins = 80; @@ -120,14 +66,6 @@ void Paraformer::Reset() { } -vector> Paraformer::VadSeg(std::vector& pcm_data){ - return vad_handle->Infer(pcm_data); -} - -string Paraformer::AddPunc(const char* sz_input){ - return punc_handle->AddPunc(sz_input); -} - vector Paraformer::FbankKaldi(float sample_rate, const float* waves, int len) { knf::OnlineFbank fbank_(fbank_opts); fbank_.AcceptWaveform(sample_rate, waves, len); @@ -282,7 +220,7 @@ string Paraformer::Forward(float* din, int len, int flag) } catch (std::exception const &e) { - printf(e.what()); + LOG(ERROR)< fbank_; knf::FbankOptions fbank_opts; - std::unique_ptr vad_handle; - std::unique_ptr punc_handle; - Vocab* vocab; vector means_list; vector vars_list; @@ -36,7 +31,6 @@ namespace paraformer { void LoadCmvn(const char *filename); vector ApplyLfr(const vector &in); void ApplyCmvn(vector *v); - string GreedySearch( float* in, int n_len, int64_t token_nums); std::shared_ptr m_session; @@ -46,22 +40,16 @@ namespace paraformer { vector m_strInputNames, m_strOutputNames; vector m_szInputNames; vector m_szOutputNames; - bool use_vad=false; - bool use_punc=false; public: - Paraformer(std::map& model_path, int thread_num=0); + Paraformer(); ~Paraformer(); - void InitAM(const std::string &am_model, const std::string &am_cmvn, const std::string &am_config, int thread_num); + void InitAsr(const std::string &am_model, const std::string &am_cmvn, const std::string &am_config, int thread_num); void Reset(); vector FbankKaldi(float sample_rate, const float* waves, int len); string ForwardChunk(float* din, int len, int flag); string Forward(float* din, int len, int flag); string Rescoring(); - std::vector> VadSeg(std::vector& pcm_data); - string AddPunc(const char* sz_input); - bool UseVad(){return use_vad;}; - bool UsePunc(){return use_punc;}; }; } // namespace paraformer diff --git a/funasr/runtime/onnxruntime/src/precomp.h b/funasr/runtime/onnxruntime/src/precomp.h index 68e0fe840..0d3199ee7 100644 --- a/funasr/runtime/onnxruntime/src/precomp.h +++ b/funasr/runtime/onnxruntime/src/precomp.h @@ -30,6 +30,10 @@ using namespace std; #include "com-define.h" #include "commonfunc.h" #include "predefine-coe.h" +#include "model.h" +#include "vad-model.h" +#include "punc-model.h" +#include "offline-stream.h" #include "tokenizer.h" #include "ct-transformer.h" #include "fsmn-vad.h" @@ -39,9 +43,8 @@ using namespace std; #include "tensor.h" #include "util.h" #include "resample.h" -#include "model.h" -#include "vad-model.h" #include "paraformer.h" +#include "offline-stream.h" #include "libfunasrapi.h" using namespace paraformer; diff --git a/funasr/runtime/onnxruntime/src/punc-model.cpp b/funasr/runtime/onnxruntime/src/punc-model.cpp new file mode 100644 index 000000000..1e619ab9d --- /dev/null +++ b/funasr/runtime/onnxruntime/src/punc-model.cpp @@ -0,0 +1,19 @@ +#include "precomp.h" + +PuncModel *CreatePuncModel(std::map& model_path, int thread_num) +{ + PuncModel *mm; + mm = new CTTransformer(); + + string punc_model_path; + string punc_config_path; + + punc_model_path = PathAppend(model_path.at(MODEL_DIR), MODEL_NAME); + if(model_path.find(QUANTIZE) != model_path.end() && model_path.at(QUANTIZE) == "true"){ + punc_model_path = PathAppend(model_path.at(MODEL_DIR), QUANT_MODEL_NAME); + } + punc_config_path = PathAppend(model_path.at(MODEL_DIR), PUNC_CONFIG_NAME); + + mm->InitPunc(punc_model_path, punc_config_path, thread_num); + return mm; +} diff --git a/funasr/runtime/onnxruntime/src/tokenizer.cpp b/funasr/runtime/onnxruntime/src/tokenizer.cpp index 5f29b46f0..5aff058b3 100644 --- a/funasr/runtime/onnxruntime/src/tokenizer.cpp +++ b/funasr/runtime/onnxruntime/src/tokenizer.cpp @@ -14,6 +14,10 @@ CTokenizer::CTokenizer():m_ready(false) { } +CTokenizer::~CTokenizer() +{ +} + void CTokenizer::ReadYaml(const YAML::Node& node) { if (node.IsMap()) diff --git a/funasr/runtime/onnxruntime/src/tokenizer.h b/funasr/runtime/onnxruntime/src/tokenizer.h index 4ff1809cf..4ddd359e5 100644 --- a/funasr/runtime/onnxruntime/src/tokenizer.h +++ b/funasr/runtime/onnxruntime/src/tokenizer.h @@ -17,6 +17,7 @@ public: CTokenizer(const char* sz_yamlfile); CTokenizer(); + ~CTokenizer(); bool OpenYaml(const char* sz_yamlfile); void ReadYaml(const YAML::Node& node); vector Id2String(vector input); diff --git a/funasr/runtime/onnxruntime/src/vad-model.cpp b/funasr/runtime/onnxruntime/src/vad-model.cpp new file mode 100644 index 000000000..0a0ec84eb --- /dev/null +++ b/funasr/runtime/onnxruntime/src/vad-model.cpp @@ -0,0 +1,21 @@ +#include "precomp.h" + +VadModel *CreateVadModel(std::map& model_path, int thread_num) +{ + VadModel *mm; + mm = new FsmnVad(); + + string vad_model_path; + string vad_cmvn_path; + string vad_config_path; + + vad_model_path = PathAppend(model_path.at(MODEL_DIR), MODEL_NAME); + if(model_path.find(QUANTIZE) != model_path.end() && model_path.at(QUANTIZE) == "true"){ + vad_model_path = PathAppend(model_path.at(MODEL_DIR), QUANT_MODEL_NAME); + } + vad_cmvn_path = PathAppend(model_path.at(MODEL_DIR), VAD_CMVN_NAME); + vad_config_path = PathAppend(model_path.at(MODEL_DIR), VAD_CONFIG_NAME); + + mm->InitVad(vad_model_path, vad_cmvn_path, vad_config_path, thread_num); + return mm; +} From 2978c59a95c3c71df8e26385294877917160f2c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=B8=E9=9B=81?= Date: Mon, 8 May 2023 11:25:38 +0800 Subject: [PATCH 073/120] websocket python --- funasr/runtime/python/websocket/ws_client.py | 2 +- funasr/runtime/python/websocket/ws_server_offline.py | 4 ++-- funasr/version.txt | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/funasr/runtime/python/websocket/ws_client.py b/funasr/runtime/python/websocket/ws_client.py index bbc49b104..9de31a444 100644 --- a/funasr/runtime/python/websocket/ws_client.py +++ b/funasr/runtime/python/websocket/ws_client.py @@ -167,7 +167,7 @@ async def message(id): # print(meg) wav_name = meg.get("wav_name", "demo") print(wav_name) - text = meg["text"][0] + text = meg["text"] if ibest_writer is not None: ibest_writer["text"][wav_name] = text if meg["mode"] == "online": diff --git a/funasr/runtime/python/websocket/ws_server_offline.py b/funasr/runtime/python/websocket/ws_server_offline.py index c415703e4..15578f641 100644 --- a/funasr/runtime/python/websocket/ws_server_offline.py +++ b/funasr/runtime/python/websocket/ws_server_offline.py @@ -138,10 +138,10 @@ async def async_asr(websocket, audio_in): rec_result = inference_pipeline_punc(text_in=rec_result['text'], param_dict=websocket.param_dict_punc) # print(rec_result) - message = json.dumps({"mode": "offline", "text": [rec_result["text"]], "wav_name": websocket.wav_name}) + message = json.dumps({"mode": "offline", "text": rec_result["text"], "wav_name": websocket.wav_name}) await websocket.send(message) - + diff --git a/funasr/version.txt b/funasr/version.txt index ef52a6480..f90568270 100644 --- a/funasr/version.txt +++ b/funasr/version.txt @@ -1 +1 @@ -0.4.6 +0.4.7 From 76e3e8445a72ece8dd3eb30a129ec141c2746e8a Mon Sep 17 00:00:00 2001 From: lyblsgo Date: Mon, 8 May 2023 11:28:45 +0800 Subject: [PATCH 074/120] update readme --- funasr/runtime/onnxruntime/readme.md | 97 ++++++++++++++----- .../onnxruntime/src/funasr-onnx-offline.cpp | 2 +- 2 files changed, 73 insertions(+), 26 deletions(-) diff --git a/funasr/runtime/onnxruntime/readme.md b/funasr/runtime/onnxruntime/readme.md index 95840e530..ab032bf67 100644 --- a/funasr/runtime/onnxruntime/readme.md +++ b/funasr/runtime/onnxruntime/readme.md @@ -40,41 +40,88 @@ make ``` ## Run the demo +### funasr-onnx-offline ```shell ./funasr-onnx-offline [--wav-scp ] [--wav-path ] - [--punc-config ] [--punc-model ] - --am-config --am-cmvn - --am-model [--vad-config ] - [--vad-cmvn ] [--vad-model ] [--] - [--version] [-h] + [--punc-quant ] [--punc-dir ] + [--vad-quant ] [--vad-dir ] + [--quantize ] --model-dir + [--] [--version] [-h] Where: + --model-dir + (required) the asr model path, which contains model.onnx, config.yaml, am.mvn + --quantize + false (Default), load the model of model.onnx in model_dir. If set true, load the model of model_quant.onnx in model_dir + + --vad-dir + the vad model path, which contains model.onnx, vad.yaml, vad.mvn + --vad-quant + false (Default), load the model of model.onnx in vad_dir. If set true, load the model of model_quant.onnx in vad_dir + + --punc-dir + the punc model path, which contains model.onnx, punc.yaml + --punc-quant + false (Default), load the model of model.onnx in punc_dir. If set true, load the model of model_quant.onnx in punc_dir + + --wav-scp + wave scp path + --wav-path + wave file path + + Required: --model-dir + If use vad, please add: --vad-dir + If use punc, please add: --punc-dir + +For example: +./funasr-onnx-offline \ + --model-dir ./asrmodel/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch \ + --quantize true \ + --vad-dir ./asrmodel/speech_fsmn_vad_zh-cn-16k-common-pytorch \ + --punc-dir ./asrmodel/punc_ct-transformer_zh-cn-common-vocab272727-pytorch \ + --wav-path ./vad_example.wav +``` + +### funasr-onnx-offline-vad +```shell +./funasr-onnx-offline-vad [--wav-scp ] [--wav-path ] + [--quantize ] --model-dir + [--] [--version] [-h] +Where: + --model-dir + (required) the vad model path, which contains model.onnx, vad.yaml, vad.mvn + --quantize + false (Default), load the model of model.onnx in model_dir. If set true, load the model of model_quant.onnx in model_dir --wav-scp wave scp path --wav-path wave file path - --punc-config - punc config path - --punc-model - punc model path + Required: --model-dir - --am-config - (required) am config path - --am-cmvn - (required) am cmvn path - --am-model - (required) am model path +For example: +./funasr-onnx-offline-vad \ + --model-dir ./asrmodel/speech_fsmn_vad_zh-cn-16k-common-pytorch \ + --wav-path ./vad_example.wav +``` - --vad-config - vad config path - --vad-cmvn - vad cmvn path - --vad-model - vad model path - - Required: --am-config --am-cmvn --am-model - If use vad, please add: [--vad-config ] [--vad-cmvn ] [--vad-model ] - If use punc, please add: [--punc-config ] [--punc-model ] +### funasr-onnx-offline-punc +```shell +./funasr-onnx-offline-punc [--txt-path ] [--quantize ] + --model-dir [--] [--version] [-h] +Where: + --model-dir + (required) the punc model path, which contains model.onnx, punc.yaml + --quantize + false (Default), load the model of model.onnx in model_dir. If set true, load the model of model_quant.onnx in model_dir + --txt-path + txt file path, one sentence per line + + Required: --model-dir + +For example: +./funasr-onnx-offline-punc \ + --model-dir ./asrmodel/punc_ct-transformer_zh-cn-common-vocab272727-pytorch \ + --txt-path ./punc_example.txt ``` ## Acknowledge diff --git a/funasr/runtime/onnxruntime/src/funasr-onnx-offline.cpp b/funasr/runtime/onnxruntime/src/funasr-onnx-offline.cpp index af6d0e3ce..51758a733 100644 --- a/funasr/runtime/onnxruntime/src/funasr-onnx-offline.cpp +++ b/funasr/runtime/onnxruntime/src/funasr-onnx-offline.cpp @@ -34,7 +34,7 @@ int main(int argc, char** argv) FLAGS_logtostderr = true; TCLAP::CmdLine cmd("funasr-onnx-offline", ' ', "1.0"); - TCLAP::ValueArg model_dir("", MODEL_DIR, "the model path, which contains model.onnx, config.yaml, am.mvn", true, "", "string"); + TCLAP::ValueArg model_dir("", MODEL_DIR, "the asr model path, which contains model.onnx, config.yaml, am.mvn", true, "", "string"); TCLAP::ValueArg quantize("", QUANTIZE, "false (Default), load the model of model.onnx in model_dir. If set true, load the model of model_quant.onnx in model_dir", false, "false", "string"); TCLAP::ValueArg vad_dir("", VAD_DIR, "the vad model path, which contains model.onnx, vad.yaml, vad.mvn", false, "", "string"); TCLAP::ValueArg vad_quant("", VAD_QUANT, "false (Default), load the model of model.onnx in vad_dir. If set true, load the model of model_quant.onnx in vad_dir", false, "false", "string"); From 3d7c0c5d2d1e097ae17dc4275c75050574d1f217 Mon Sep 17 00:00:00 2001 From: "mengzhe.cmz" Date: Mon, 8 May 2023 12:44:50 +0800 Subject: [PATCH 075/120] fix vad realtime space bug --- funasr/bin/punctuation_infer_vadrealtime.py | 2 +- funasr/runtime/python/onnxruntime/funasr_onnx/punc_bin.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/funasr/bin/punctuation_infer_vadrealtime.py b/funasr/bin/punctuation_infer_vadrealtime.py index b2db1bf17..01d242006 100644 --- a/funasr/bin/punctuation_infer_vadrealtime.py +++ b/funasr/bin/punctuation_infer_vadrealtime.py @@ -70,7 +70,7 @@ class Text2Punc: else: precache = "" cache = [] - data = {"text": precache + text} + data = {"text": precache + " " + text} result = self.preprocessor(data=data, uid="12938712838719") split_text = self.preprocessor.pop_split_text_data(result) mini_sentences = split_to_mini_sentence(split_text, split_size) diff --git a/funasr/runtime/python/onnxruntime/funasr_onnx/punc_bin.py b/funasr/runtime/python/onnxruntime/funasr_onnx/punc_bin.py index aeb91e7d7..b1a6c255b 100644 --- a/funasr/runtime/python/onnxruntime/funasr_onnx/punc_bin.py +++ b/funasr/runtime/python/onnxruntime/funasr_onnx/punc_bin.py @@ -148,7 +148,7 @@ class CT_Transformer_VadRealtime(CT_Transformer): else: precache = "" cache = [] - full_text = precache + text + full_text = precache + " " + text split_text = code_mix_split_words(full_text) split_text_id = self.converter.tokens2ids(split_text) mini_sentences = split_to_mini_sentence(split_text, split_size) From cc91b8fb60c31fbcf4b8479eead42ad0a16d35bb Mon Sep 17 00:00:00 2001 From: lyblsgo Date: Mon, 8 May 2023 14:18:41 +0800 Subject: [PATCH 076/120] modify copyright --- funasr/runtime/onnxruntime/src/e2e-vad.h | 1 - 1 file changed, 1 deletion(-) diff --git a/funasr/runtime/onnxruntime/src/e2e-vad.h b/funasr/runtime/onnxruntime/src/e2e-vad.h index 0e0b50feb..d881a322e 100644 --- a/funasr/runtime/onnxruntime/src/e2e-vad.h +++ b/funasr/runtime/onnxruntime/src/e2e-vad.h @@ -1,7 +1,6 @@ /** * Copyright FunASR (https://github.com/alibaba-damo-academy/FunASR). All Rights Reserved. * MIT License (https://opensource.org/licenses/MIT) - * Collaborators: zhuzizyf(China Telecom Shanghai) */ #include From 46357e96f4359c4b552b8e08136e9239da586d32 Mon Sep 17 00:00:00 2001 From: lyblsgo Date: Mon, 8 May 2023 14:33:23 +0800 Subject: [PATCH 077/120] update onnxruntime readme --- funasr/runtime/onnxruntime/readme.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/funasr/runtime/onnxruntime/readme.md b/funasr/runtime/onnxruntime/readme.md index f3dc3b60d..5b42c3048 100644 --- a/funasr/runtime/onnxruntime/readme.md +++ b/funasr/runtime/onnxruntime/readme.md @@ -124,6 +124,28 @@ For example: --model-dir ./asrmodel/punc_ct-transformer_zh-cn-common-vocab272727-pytorch \ --txt-path ./punc_example.txt ``` +### funasr-onnx-offline-rtf +```shell +./funasr-onnx-offline-rtf --thread-num --wav-scp + [--quantize ] --model-dir + [--] [--version] [-h] +Where: + --thread-num + (required) multi-thread num for rtf + --model-dir + (required) the model path, which contains model.onnx, config.yaml, am.mvn + --quantize + false (Default), load the model of model.onnx in model_dir. If set true, load the model of model_quant.onnx in model_dir + --wav-scp + (required) wave scp path + +For example: +./funasr-onnx-offline-rtf \ + --model-dir ./asrmodel/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch \ + --quantize true \ + --wav-scp ./aishell1_test.scp \ + --thread-num 32 +``` ## Acknowledge 1. This project is maintained by [FunASR community](https://github.com/alibaba-damo-academy/FunASR). From 59f920f17c781be3a9b31d2b82dbda28c9b0c362 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=B8=E9=9B=81?= Date: Mon, 8 May 2023 16:14:25 +0800 Subject: [PATCH 078/120] websocket python offline/online 2pass demo --- funasr/bin/punctuation_infer_vadrealtime.py | 2 +- funasr/runtime/python/websocket/README.md | 21 +- funasr/runtime/python/websocket/ws_client.py | 37 +++- .../python/websocket/ws_server_2pass.py | 182 ++++++++++++++++++ .../python/websocket/ws_server_online.py | 14 +- 5 files changed, 231 insertions(+), 25 deletions(-) create mode 100644 funasr/runtime/python/websocket/ws_server_2pass.py diff --git a/funasr/bin/punctuation_infer_vadrealtime.py b/funasr/bin/punctuation_infer_vadrealtime.py index 01d242006..0dc01f531 100644 --- a/funasr/bin/punctuation_infer_vadrealtime.py +++ b/funasr/bin/punctuation_infer_vadrealtime.py @@ -61,7 +61,7 @@ class Text2Punc: text_name="text", non_linguistic_symbols=train_args.non_linguistic_symbols, ) - print("start decoding!!!") + @torch.no_grad() def __call__(self, text: Union[list, str], cache: list, split_size=20): diff --git a/funasr/runtime/python/websocket/README.md b/funasr/runtime/python/websocket/README.md index 473c37a2c..8f6c883c4 100644 --- a/funasr/runtime/python/websocket/README.md +++ b/funasr/runtime/python/websocket/README.md @@ -33,11 +33,9 @@ python ws_server_online.py --port 10095 --asr_model_online "damo/speech_paraform #### ASR offline/online 2pass server -[//]: # (```shell) - -[//]: # (python ws_server_online.py --host "0.0.0.0" --port 10095 --asr_model "damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch") - -[//]: # (```) +```shell +python ws_server_2pass.py --port 10095 --asr_model "damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch" --asr_model_online "damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online" +``` ## For the client @@ -49,6 +47,7 @@ pip install -r requirements_client.txt ``` ### Start client + #### ASR offline client ##### Recording from mircrophone ```shell @@ -60,6 +59,7 @@ python ws_client.py --host "0.0.0.0" --port 10095 --chunk_interval 10 --words_ma # --chunk_interval, "10": 600/10=60ms, "5"=600/5=120ms, "20": 600/12=30ms python ws_client.py --host "0.0.0.0" --port 10095 --chunk_interval 10 --words_max_print 100 --audio_in "./data/wav.scp" --send_without_sleep --output_dir "./results" ``` + #### ASR streaming client ##### Recording from mircrophone ```shell @@ -73,7 +73,16 @@ python ws_client.py --host "0.0.0.0" --port 10095 --chunk_size "5,10,5" --audio_ ``` #### ASR offline/online 2pass client - +##### Recording from mircrophone +```shell +# --chunk_size, "5,10,5"=600ms, "8,8,4"=480ms +python ws_client.py --host "0.0.0.0" --port 10095 --chunk_size "8,8,4" --words_max_print 10000 +``` +##### Loadding from wav.scp(kaldi style) +```shell +# --chunk_size, "5,10,5"=600ms, "8,8,4"=480ms +python ws_client.py --host "0.0.0.0" --port 10095 --chunk_size "8,8,4" --audio_in "./data/wav.scp" --words_max_print 10000 --output_dir "./results" +``` ## Acknowledge 1. This project is maintained by [FunASR community](https://github.com/alibaba-damo-academy/FunASR). 2. We acknowledge [zhaoming](https://github.com/zhaomingwork/FunASR/tree/fix_bug_for_python_websocket) for contributing the websocket service. diff --git a/funasr/runtime/python/websocket/ws_client.py b/funasr/runtime/python/websocket/ws_client.py index 9de31a444..5ced6888b 100644 --- a/funasr/runtime/python/websocket/ws_client.py +++ b/funasr/runtime/python/websocket/ws_client.py @@ -10,6 +10,10 @@ import traceback from multiprocessing import Process from funasr.fileio.datadir_writer import DatadirWriter +import logging + +logging.basicConfig(level=logging.ERROR) + parser = argparse.ArgumentParser() parser.add_argument("--host", type=str, @@ -158,25 +162,40 @@ async def ws_send(): async def message(id): global websocket text_print = "" + text_print_2pass_online = "" + text_print_2pass_offline = "" while True: try: meg = await websocket.recv() meg = json.loads(meg) - # print(meg, end = '') - # print("\r") - # print(meg) wav_name = meg.get("wav_name", "demo") - print(wav_name) + # print(wav_name) text = meg["text"] if ibest_writer is not None: ibest_writer["text"][wav_name] = text + if meg["mode"] == "online": text_print += " {}".format(text) - else: + text_print = text_print[-args.words_max_print:] + os.system('clear') + print("\rpid"+str(id)+": "+text_print) + elif meg["mode"] == "online": text_print += "{}".format(text) - text_print = text_print[-args.words_max_print:] - os.system('clear') - print("\rpid"+str(id)+": "+text_print) + text_print = text_print[-args.words_max_print:] + os.system('clear') + print("\rpid"+str(id)+": "+text_print) + else: + if meg["mode"] == "2pass-online": + text_print_2pass_online += " {}".format(text) + text_print = text_print_2pass_offline + text_print_2pass_online + else: + text_print_2pass_online = " " + text_print = text_print_2pass_offline + "{}".format(text) + text_print_2pass_offline += "{}".format(text) + text_print = text_print[-args.words_max_print:] + os.system('clear') + print("\rpid" + str(id) + ": " + text_print) + except Exception as e: print("Exception:", e) traceback.print_exc() @@ -207,7 +226,7 @@ async def ws_client(id): await asyncio.gather(task, task2, task3) def one_thread(id): - asyncio.get_event_loop().run_until_complete(ws_client(id)) # 启动协程 + asyncio.get_event_loop().run_until_complete(ws_client(id)) asyncio.get_event_loop().run_forever() diff --git a/funasr/runtime/python/websocket/ws_server_2pass.py b/funasr/runtime/python/websocket/ws_server_2pass.py new file mode 100644 index 000000000..ced67ffa5 --- /dev/null +++ b/funasr/runtime/python/websocket/ws_server_2pass.py @@ -0,0 +1,182 @@ +import asyncio +import json +import websockets +import time +import logging +import tracemalloc +import numpy as np + +from parse_args import args +from modelscope.pipelines import pipeline +from modelscope.utils.constant import Tasks +from modelscope.utils.logger import get_logger +from funasr.runtime.python.onnxruntime.funasr_onnx.utils.frontend import load_bytes + +tracemalloc.start() + +logger = get_logger(log_level=logging.CRITICAL) +logger.setLevel(logging.CRITICAL) + + +websocket_users = set() + +print("model loading") +# asr +inference_pipeline_asr = pipeline( + task=Tasks.auto_speech_recognition, + model=args.asr_model, + ngpu=args.ngpu, + ncpu=args.ncpu, + model_revision=None) + + +# vad +inference_pipeline_vad = pipeline( + task=Tasks.voice_activity_detection, + model=args.vad_model, + model_revision=None, + output_dir=None, + batch_size=1, + mode='online', + ngpu=args.ngpu, + ncpu=args.ncpu, +) + +if args.punc_model != "": + inference_pipeline_punc = pipeline( + task=Tasks.punctuation, + model=args.punc_model, + model_revision=None, + ngpu=args.ngpu, + ncpu=args.ncpu, + ) +else: + inference_pipeline_punc = None + +inference_pipeline_asr_online = pipeline( + task=Tasks.auto_speech_recognition, + model=args.asr_model_online, + ngpu=args.ngpu, + ncpu=args.ncpu, + model_revision='v1.0.4') + +print("model loaded") + +async def ws_serve(websocket, path): + frames = [] + frames_asr = [] + frames_asr_online = [] + global websocket_users + websocket_users.add(websocket) + websocket.param_dict_asr = {} + websocket.param_dict_asr_online = {"cache": dict()} + websocket.param_dict_vad = {'in_cache': dict(), "is_final": False} + websocket.param_dict_punc = {'cache': list()} + websocket.vad_pre_idx = 0 + speech_start = False + + try: + async for message in websocket: + message = json.loads(message) + is_finished = message["is_finished"] + if not is_finished: + audio = bytes(message['audio'], 'ISO-8859-1') + frames.append(audio) + duration_ms = len(audio)//32 + websocket.vad_pre_idx += duration_ms + + is_speaking = message["is_speaking"] + websocket.param_dict_vad["is_final"] = not is_speaking + websocket.param_dict_asr_online["is_final"] = not is_speaking + websocket.param_dict_asr_online["chunk_size"] = message["chunk_size"] + websocket.wav_name = message.get("wav_name", "demo") + # asr online + frames_asr_online.append(audio) + if len(frames_asr_online) % message["chunk_interval"] == 0: + audio_in = b"".join(frames_asr_online) + await async_asr_online(websocket, audio_in) + frames_asr_online = [] + if speech_start: + frames_asr.append(audio) + # vad online + speech_start_i, speech_end_i = await async_vad(websocket, audio) + if speech_start_i: + speech_start = True + beg_bias = (websocket.vad_pre_idx-speech_start_i)//duration_ms + frames_pre = frames[-beg_bias:] + frames_asr = [] + frames_asr.extend(frames_pre) + # asr punc offline + if speech_end_i or not is_speaking: + audio_in = b"".join(frames_asr) + await async_asr(websocket, audio_in) + frames_asr = [] + speech_start = False + frames_asr_online = [] + websocket.param_dict_asr_online = {"cache": dict()} + if not is_speaking: + websocket.vad_pre_idx = 0 + frames = [] + websocket.param_dict_vad = {'in_cache': dict()} + else: + frames = frames[-20:] + + + except websockets.ConnectionClosed: + print("ConnectionClosed...", websocket_users) + websocket_users.remove(websocket) + except websockets.InvalidState: + print("InvalidState...") + except Exception as e: + print("Exception:", e) + + +async def async_vad(websocket, audio_in): + + segments_result = inference_pipeline_vad(audio_in=audio_in, param_dict=websocket.param_dict_vad) + + speech_start = False + speech_end = False + + if len(segments_result) == 0 or len(segments_result["text"]) > 1: + return speech_start, speech_end + if segments_result["text"][0][0] != -1: + speech_start = segments_result["text"][0][0] + if segments_result["text"][0][1] != -1: + speech_end = True + return speech_start, speech_end + + +async def async_asr(websocket, audio_in): + if len(audio_in) > 0: + # print(len(audio_in)) + audio_in = load_bytes(audio_in) + + rec_result = inference_pipeline_asr(audio_in=audio_in, + param_dict=websocket.param_dict_asr) + # print(rec_result) + if inference_pipeline_punc is not None and 'text' in rec_result and len(rec_result["text"])>0: + rec_result = inference_pipeline_punc(text_in=rec_result['text'], + param_dict=websocket.param_dict_punc) + # print("offline", rec_result) + message = json.dumps({"mode": "2pass-offline", "text": rec_result["text"], "wav_name": websocket.wav_name}) + await websocket.send(message) + + +async def async_asr_online(websocket, audio_in): + if len(audio_in) > 0: + audio_in = load_bytes(audio_in) + rec_result = inference_pipeline_asr_online(audio_in=audio_in, + param_dict=websocket.param_dict_asr_online) + if websocket.param_dict_asr_online["is_final"]: + websocket.param_dict_asr_online["cache"] = dict() + if "text" in rec_result: + if rec_result["text"] != "sil" and rec_result["text"] != "waiting_for_more_voice": + # print("online", rec_result) + message = json.dumps({"mode": "2pass-online", "text": rec_result["text"], "wav_name": websocket.wav_name}) + await websocket.send(message) + + +start_server = websockets.serve(ws_serve, args.host, args.port, subprotocols=["binary"], ping_interval=None) +asyncio.get_event_loop().run_until_complete(start_server) +asyncio.get_event_loop().run_forever() \ No newline at end of file diff --git a/funasr/runtime/python/websocket/ws_server_online.py b/funasr/runtime/python/websocket/ws_server_online.py index b1cd4eaea..3c0fb160d 100644 --- a/funasr/runtime/python/websocket/ws_server_online.py +++ b/funasr/runtime/python/websocket/ws_server_online.py @@ -37,12 +37,10 @@ print("model loaded") async def ws_serve(websocket, path): - frames_online = [] + frames_asr_online = [] global websocket_users - websocket.send_msg = Queue() websocket_users.add(websocket) websocket.param_dict_asr_online = {"cache": dict()} - websocket.speek_online = Queue() try: async for message in websocket: @@ -56,11 +54,11 @@ async def ws_serve(websocket, path): websocket.wav_name = message.get("wav_name", "demo") websocket.param_dict_asr_online["chunk_size"] = message["chunk_size"] - frames_online.append(audio) - if len(frames_online) % message["chunk_interval"] == 0 or not is_speaking: - audio_in = b"".join(frames_online) + frames_asr_online.append(audio) + if len(frames_asr_online) % message["chunk_interval"] == 0 or not is_speaking: + audio_in = b"".join(frames_asr_online) await async_asr_online(websocket,audio_in) - frames_online = [] + frames_asr_online = [] @@ -81,8 +79,6 @@ async def async_asr_online(websocket,audio_in): websocket.param_dict_asr_online["cache"] = dict() if "text" in rec_result: if rec_result["text"] != "sil" and rec_result["text"] != "waiting_for_more_voice": - # if len(rec_result["text"])>0: - # rec_result["text"][0]=rec_result["text"][0] #.replace(" ","") message = json.dumps({"mode": "online", "text": rec_result["text"], "wav_name": websocket.wav_name}) await websocket.send(message) From 589b115a1fa36233d99d20f8b05e93f5348947cd Mon Sep 17 00:00:00 2001 From: "haoneng.lhn" Date: Mon, 8 May 2023 16:19:27 +0800 Subject: [PATCH 079/120] add paraformer online UnitTest --- tests/test_asr_inference_pipeline.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/test_asr_inference_pipeline.py b/tests/test_asr_inference_pipeline.py index 2f2f11d58..9098ea62d 100644 --- a/tests/test_asr_inference_pipeline.py +++ b/tests/test_asr_inference_pipeline.py @@ -112,6 +112,22 @@ class TestParaformerInferencePipelines(unittest.TestCase): audio_in='https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_example_zh.wav') logger.info("asr inference result: {0}".format(rec_result)) + def test_paraformer_large_online_common(self): + inference_pipeline = pipeline( + task=Tasks.auto_speech_recognition, + model='damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online') + rec_result = inference_pipeline( + audio_in='https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_example_zh.wav') + logger.info("asr inference result: {0}".format(rec_result)) + + def test_paraformer_online_common(self): + inference_pipeline = pipeline( + task=Tasks.auto_speech_recognition, + model='damo/speech_paraformer_asr_nat-zh-cn-16k-common-vocab8404-online') + rec_result = inference_pipeline( + audio_in='https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/test_audio/asr_example_zh.wav') + logger.info("asr inference result: {0}".format(rec_result)) + def test_paraformer_tiny_commandword(self): inference_pipeline = pipeline( task=Tasks.auto_speech_recognition, From 3cb44db96a1ae7985631759b593fee9efade7029 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=B8=E9=9B=81?= Date: Mon, 8 May 2023 16:25:46 +0800 Subject: [PATCH 080/120] websocket python offline/online 2pass demo --- funasr/runtime/python/websocket/README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/funasr/runtime/python/websocket/README.md b/funasr/runtime/python/websocket/README.md index 8f6c883c4..e73dbd50b 100644 --- a/funasr/runtime/python/websocket/README.md +++ b/funasr/runtime/python/websocket/README.md @@ -48,6 +48,18 @@ pip install -r requirements_client.txt ### Start client +```shell +python ws_client.py \ +--host [ip_address] \ +--port [port id] \ +--chunk_size ["5,10,5"=600ms, "8,8,4"=480ms] \ +--chunk_interval [duration of send chunk_size/chunk_interval] \ +--words_max_print [max number of words to print] \ +--audio_in [if set, loadding from wav.scp, else recording from mircrophone] \ +--output_dir [if set, write the results to output_dir] \ +--send_without_sleep [only set for offline] +``` + #### ASR offline client ##### Recording from mircrophone ```shell From 7283592ce10e1433e10944e83a95e7b3d93fec48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=B8=E9=9B=81?= Date: Mon, 8 May 2023 17:09:04 +0800 Subject: [PATCH 081/120] websocket python offline/online 2pass demo --- funasr/runtime/python/websocket/README.md | 28 ++++++++++++++++++++++- funasr/version.txt | 2 +- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/funasr/runtime/python/websocket/README.md b/funasr/runtime/python/websocket/README.md index e73dbd50b..4764232b5 100644 --- a/funasr/runtime/python/websocket/README.md +++ b/funasr/runtime/python/websocket/README.md @@ -23,16 +23,42 @@ pip install -r requirements_server.txt ### Start server #### ASR offline server ```shell +python ws_server_offline.py \ +--port [port id] \ +--asr_model [asr model_name] \ +--punc_model [punc model_name] \ +--ngpu [0 or 1] \ +--ncpu [1 or 4] +``` +`e.g.` +```shell python ws_server_offline.py --port 10095 --asr_model "damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch" ``` #### ASR streaming server ```shell +python ws_server_online.py \ +--port [port id] \ +--asr_model_online [asr model_name] \ +--ngpu [0 or 1] \ +--ncpu [1 or 4] +``` +`e.g.` +```shell python ws_server_online.py --port 10095 --asr_model_online "damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online" ``` #### ASR offline/online 2pass server - +```shell +python ws_server_2pass.py \ +--port [port id] \ +--asr_model [asr model_name] \ +--asr_model_online [asr model_name] \ +--punc_model [punc model_name] \ +--ngpu [0 or 1] \ +--ncpu [1 or 4] +``` +`e.g.` ```shell python ws_server_2pass.py --port 10095 --asr_model "damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch" --asr_model_online "damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online" ``` diff --git a/funasr/version.txt b/funasr/version.txt index f90568270..cb498ab2c 100644 --- a/funasr/version.txt +++ b/funasr/version.txt @@ -1 +1 @@ -0.4.7 +0.4.8 From f5825f1f4f228e459455e7b739bf3b7e2aac3395 Mon Sep 17 00:00:00 2001 From: "mengzhe.cmz" Date: Mon, 8 May 2023 18:54:30 +0800 Subject: [PATCH 082/120] onnx runtime model int32 --- funasr/runtime/python/onnxruntime/funasr_onnx/punc_bin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/funasr/runtime/python/onnxruntime/funasr_onnx/punc_bin.py b/funasr/runtime/python/onnxruntime/funasr_onnx/punc_bin.py index b1a6c255b..6fd01e404 100644 --- a/funasr/runtime/python/onnxruntime/funasr_onnx/punc_bin.py +++ b/funasr/runtime/python/onnxruntime/funasr_onnx/punc_bin.py @@ -64,7 +64,7 @@ class CT_Transformer(): mini_sentence = mini_sentences[mini_sentence_i] mini_sentence_id = mini_sentences_id[mini_sentence_i] mini_sentence = cache_sent + mini_sentence - mini_sentence_id = np.array(cache_sent_id + mini_sentence_id, dtype='int64') + mini_sentence_id = np.array(cache_sent_id + mini_sentence_id, dtype='int32') data = { "text": mini_sentence_id[None,:], "text_lengths": np.array([len(mini_sentence_id)], dtype='int32'), @@ -166,7 +166,7 @@ class CT_Transformer_VadRealtime(CT_Transformer): mini_sentence = mini_sentences[mini_sentence_i] mini_sentence_id = mini_sentences_id[mini_sentence_i] mini_sentence = cache_sent + mini_sentence - mini_sentence_id = np.concatenate((cache_sent_id, mini_sentence_id), axis=0) + mini_sentence_id = np.concatenate((cache_sent_id, mini_sentence_id), axis=0,dtype='int32') text_length = len(mini_sentence_id) data = { "input": mini_sentence_id[None,:], From fd1aa6b079240ab528e63fd0cfb6685f90f60f8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=B8=E9=9B=81?= Date: Mon, 8 May 2023 19:02:30 +0800 Subject: [PATCH 083/120] funasr_onnx 0.0.8 --- funasr/runtime/python/onnxruntime/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/funasr/runtime/python/onnxruntime/setup.py b/funasr/runtime/python/onnxruntime/setup.py index 3fafd5339..0b249dd90 100644 --- a/funasr/runtime/python/onnxruntime/setup.py +++ b/funasr/runtime/python/onnxruntime/setup.py @@ -13,7 +13,7 @@ def get_readme(): MODULE_NAME = 'funasr_onnx' -VERSION_NUM = '0.0.7' +VERSION_NUM = '0.0.8' setuptools.setup( name=MODULE_NAME, From 2a475a112f4d765609939089fcaf0bca8f34e1e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=B8=E9=9B=81?= Date: Mon, 8 May 2023 19:11:40 +0800 Subject: [PATCH 084/120] docs --- docs/academic_recipe/lm_recipe.md | 128 +-------------------------- docs/academic_recipe/punc_recipe.md | 129 +--------------------------- docs/academic_recipe/sd_recipe.md | 129 +--------------------------- docs/academic_recipe/sv_recipe.md | 129 +--------------------------- docs/academic_recipe/vad_recipe.md | 129 +--------------------------- 5 files changed, 5 insertions(+), 639 deletions(-) diff --git a/docs/academic_recipe/lm_recipe.md b/docs/academic_recipe/lm_recipe.md index f82a6fee4..730e27c42 100644 --- a/docs/academic_recipe/lm_recipe.md +++ b/docs/academic_recipe/lm_recipe.md @@ -1,129 +1,3 @@ # Speech Recognition -Here we take "Training a paraformer model from scratch using the AISHELL-1 dataset" as an example to introduce how to use FunASR. According to this example, users can similarly employ other datasets (such as AISHELL-2 dataset, etc.) to train other models (such as conformer, transformer, etc.). - -## Overall Introduction -We provide a recipe `egs/aishell/paraformer/run.sh` for training a paraformer model on AISHELL-1 dataset. This recipe consists of five stages, supporting training on multiple GPUs and decoding by CPU or GPU. Before introducing each stage in detail, we first explain several parameters which should be set by users. -- `CUDA_VISIBLE_DEVICES`: visible gpu list -- `gpu_num`: the number of GPUs used for training -- `gpu_inference`: whether to use GPUs for decoding -- `njob`: for CPU decoding, indicating the total number of CPU jobs; for GPU decoding, indicating the number of jobs on each GPU -- `data_aishell`: the raw path of AISHELL-1 dataset -- `feats_dir`: the path for saving processed data -- `nj`: the number of jobs for data preparation -- `speed_perturb`: the range of speech perturbed -- `exp_dir`: the path for saving experimental results -- `tag`: the suffix of experimental result directory - -## Stage 0: Data preparation -This stage processes raw AISHELL-1 dataset `$data_aishell` and generates the corresponding `wav.scp` and `text` in `$feats_dir/data/xxx`. `xxx` means `train/dev/test`. Here we assume users have already downloaded AISHELL-1 dataset. If not, users can download data [here](https://www.openslr.org/33/) and set the path for `$data_aishell`. The examples of `wav.scp` and `text` are as follows: -* `wav.scp` -``` -BAC009S0002W0122 /nfs/ASR_DATA/AISHELL-1/data_aishell/wav/train/S0002/BAC009S0002W0122.wav -BAC009S0002W0123 /nfs/ASR_DATA/AISHELL-1/data_aishell/wav/train/S0002/BAC009S0002W0123.wav -BAC009S0002W0124 /nfs/ASR_DATA/AISHELL-1/data_aishell/wav/train/S0002/BAC009S0002W0124.wav -... -``` -* `text` -``` -BAC009S0002W0122 而 对 楼 市 成 交 抑 制 作 用 最 大 的 限 购 -BAC009S0002W0123 也 成 为 地 方 政 府 的 眼 中 钉 -BAC009S0002W0124 自 六 月 底 呼 和 浩 特 市 率 先 宣 布 取 消 限 购 后 -... -``` -These two files both have two columns, while the first column is wav ids and the second column is the corresponding wav paths/label tokens. - -## Stage 1: Feature Generation -This stage extracts FBank features from `wav.scp` and apply speed perturbation as data augmentation according to `speed_perturb`. Users can set `nj` to control the number of jobs for feature generation. The generated features are saved in `$feats_dir/dump/xxx/ark` and the corresponding `feats.scp` files are saved as `$feats_dir/dump/xxx/feats.scp`. An example of `feats.scp` can be seen as follows: -* `feats.scp` -``` -... -BAC009S0002W0122_sp0.9 /nfs/funasr_data/aishell-1/dump/fbank/train/ark/feats.16.ark:592751055 -... -``` -Note that samples in this file have already been shuffled randomly. This file contains two columns. The first column is wav ids while the second column is kaldi-ark feature paths. Besides, `speech_shape` and `text_shape` are also generated in this stage, denoting the speech feature shape and text length of each sample. The examples are shown as follows: -* `speech_shape` -``` -... -BAC009S0002W0122_sp0.9 665,80 -... -``` -* `text_shape` -``` -... -BAC009S0002W0122_sp0.9 15 -... -``` -These two files have two columns. The first column is wav ids and the second column is the corresponding speech feature shape and text length. - -## Stage 2: Dictionary Preparation -This stage processes the dictionary, which is used as a mapping between label characters and integer indices during ASR training. The processed dictionary file is saved as `$feats_dir/data/$lang_toekn_list/$token_type/tokens.txt`. An example of `tokens.txt` is as follows: -* `tokens.txt` -``` - - - -一 -丁 -... -龚 -龟 - -``` -* ``: indicates the blank token for CTC -* ``: indicates the start-of-sentence token -* ``: indicates the end-of-sentence token -* ``: indicates the out-of-vocabulary token - -## Stage 3: Training -This stage achieves the training of the specified model. To start training, users should manually set `exp_dir`, `CUDA_VISIBLE_DEVICES` and `gpu_num`, which have already been explained above. By default, the best `$keep_nbest_models` checkpoints on validation dataset will be averaged to generate a better model and adopted for decoding. - -* DDP Training - -We support the DistributedDataParallel (DDP) training and the detail can be found [here](https://pytorch.org/tutorials/intermediate/ddp_tutorial.html). To enable DDP training, please set `gpu_num` greater than 1. For example, if you set `CUDA_VISIBLE_DEVICES=0,1,5,6,7` and `gpu_num=3`, then the gpus with ids 0, 1 and 5 will be used for training. - -* DataLoader - -We support an optional iterable-style DataLoader based on [Pytorch Iterable-style DataPipes](https://pytorch.org/data/beta/torchdata.datapipes.iter.html) for large dataset and users can set `dataset_type=large` to enable it. - -* Configuration - -The parameters of the training, including model, optimization, dataset, etc., can be set by a YAML file in `conf` directory. Also, users can directly set the parameters in `run.sh` recipe. Please avoid to set the same parameters in both the YAML file and the recipe. - -* Training Steps - -We support two parameters to specify the training steps, namely `max_epoch` and `max_update`. `max_epoch` indicates the total training epochs while `max_update` indicates the total training steps. If these two parameters are specified at the same time, once the training reaches any one of these two parameters, the training will be stopped. - -* Tensorboard - -Users can use tensorboard to observe the loss, learning rate, etc. Please run the following command: -``` -tensorboard --logdir ${exp_dir}/exp/${model_dir}/tensorboard/train -``` - -## Stage 4: Decoding -This stage generates the recognition results and calculates the `CER` to verify the performance of the trained model. - -* Mode Selection - -As we support paraformer, uniasr, conformer and other models in FunASR, a `mode` parameter should be specified as `asr/paraformer/uniasr` according to the trained model. - -* Configuration - -We support CTC decoding, attention decoding and hybrid CTC-attention decoding in FunASR, which can be specified by `ctc_weight` in a YAML file in `conf` directory. Specifically, `ctc_weight=1.0` indicates CTC decoding, `ctc_weight=0.0` indicates attention decoding, `0.0 - - -一 -丁 -... -龚 -龟 - -``` -* ``: indicates the blank token for CTC -* ``: indicates the start-of-sentence token -* ``: indicates the end-of-sentence token -* ``: indicates the out-of-vocabulary token - -## Stage 3: Training -This stage achieves the training of the specified model. To start training, users should manually set `exp_dir`, `CUDA_VISIBLE_DEVICES` and `gpu_num`, which have already been explained above. By default, the best `$keep_nbest_models` checkpoints on validation dataset will be averaged to generate a better model and adopted for decoding. - -* DDP Training - -We support the DistributedDataParallel (DDP) training and the detail can be found [here](https://pytorch.org/tutorials/intermediate/ddp_tutorial.html). To enable DDP training, please set `gpu_num` greater than 1. For example, if you set `CUDA_VISIBLE_DEVICES=0,1,5,6,7` and `gpu_num=3`, then the gpus with ids 0, 1 and 5 will be used for training. - -* DataLoader - -We support an optional iterable-style DataLoader based on [Pytorch Iterable-style DataPipes](https://pytorch.org/data/beta/torchdata.datapipes.iter.html) for large dataset and users can set `dataset_type=large` to enable it. - -* Configuration - -The parameters of the training, including model, optimization, dataset, etc., can be set by a YAML file in `conf` directory. Also, users can directly set the parameters in `run.sh` recipe. Please avoid to set the same parameters in both the YAML file and the recipe. - -* Training Steps - -We support two parameters to specify the training steps, namely `max_epoch` and `max_update`. `max_epoch` indicates the total training epochs while `max_update` indicates the total training steps. If these two parameters are specified at the same time, once the training reaches any one of these two parameters, the training will be stopped. - -* Tensorboard - -Users can use tensorboard to observe the loss, learning rate, etc. Please run the following command: -``` -tensorboard --logdir ${exp_dir}/exp/${model_dir}/tensorboard/train -``` - -## Stage 4: Decoding -This stage generates the recognition results and calculates the `CER` to verify the performance of the trained model. - -* Mode Selection - -As we support paraformer, uniasr, conformer and other models in FunASR, a `mode` parameter should be specified as `asr/paraformer/uniasr` according to the trained model. - -* Configuration - -We support CTC decoding, attention decoding and hybrid CTC-attention decoding in FunASR, which can be specified by `ctc_weight` in a YAML file in `conf` directory. Specifically, `ctc_weight=1.0` indicates CTC decoding, `ctc_weight=0.0` indicates attention decoding, `0.0 - - -一 -丁 -... -龚 -龟 - -``` -* ``: indicates the blank token for CTC -* ``: indicates the start-of-sentence token -* ``: indicates the end-of-sentence token -* ``: indicates the out-of-vocabulary token - -## Stage 3: Training -This stage achieves the training of the specified model. To start training, users should manually set `exp_dir`, `CUDA_VISIBLE_DEVICES` and `gpu_num`, which have already been explained above. By default, the best `$keep_nbest_models` checkpoints on validation dataset will be averaged to generate a better model and adopted for decoding. - -* DDP Training - -We support the DistributedDataParallel (DDP) training and the detail can be found [here](https://pytorch.org/tutorials/intermediate/ddp_tutorial.html). To enable DDP training, please set `gpu_num` greater than 1. For example, if you set `CUDA_VISIBLE_DEVICES=0,1,5,6,7` and `gpu_num=3`, then the gpus with ids 0, 1 and 5 will be used for training. - -* DataLoader - -We support an optional iterable-style DataLoader based on [Pytorch Iterable-style DataPipes](https://pytorch.org/data/beta/torchdata.datapipes.iter.html) for large dataset and users can set `dataset_type=large` to enable it. - -* Configuration - -The parameters of the training, including model, optimization, dataset, etc., can be set by a YAML file in `conf` directory. Also, users can directly set the parameters in `run.sh` recipe. Please avoid to set the same parameters in both the YAML file and the recipe. - -* Training Steps - -We support two parameters to specify the training steps, namely `max_epoch` and `max_update`. `max_epoch` indicates the total training epochs while `max_update` indicates the total training steps. If these two parameters are specified at the same time, once the training reaches any one of these two parameters, the training will be stopped. - -* Tensorboard - -Users can use tensorboard to observe the loss, learning rate, etc. Please run the following command: -``` -tensorboard --logdir ${exp_dir}/exp/${model_dir}/tensorboard/train -``` - -## Stage 4: Decoding -This stage generates the recognition results and calculates the `CER` to verify the performance of the trained model. - -* Mode Selection - -As we support paraformer, uniasr, conformer and other models in FunASR, a `mode` parameter should be specified as `asr/paraformer/uniasr` according to the trained model. - -* Configuration - -We support CTC decoding, attention decoding and hybrid CTC-attention decoding in FunASR, which can be specified by `ctc_weight` in a YAML file in `conf` directory. Specifically, `ctc_weight=1.0` indicates CTC decoding, `ctc_weight=0.0` indicates attention decoding, `0.0 - - -一 -丁 -... -龚 -龟 - -``` -* ``: indicates the blank token for CTC -* ``: indicates the start-of-sentence token -* ``: indicates the end-of-sentence token -* ``: indicates the out-of-vocabulary token - -## Stage 3: Training -This stage achieves the training of the specified model. To start training, users should manually set `exp_dir`, `CUDA_VISIBLE_DEVICES` and `gpu_num`, which have already been explained above. By default, the best `$keep_nbest_models` checkpoints on validation dataset will be averaged to generate a better model and adopted for decoding. - -* DDP Training - -We support the DistributedDataParallel (DDP) training and the detail can be found [here](https://pytorch.org/tutorials/intermediate/ddp_tutorial.html). To enable DDP training, please set `gpu_num` greater than 1. For example, if you set `CUDA_VISIBLE_DEVICES=0,1,5,6,7` and `gpu_num=3`, then the gpus with ids 0, 1 and 5 will be used for training. - -* DataLoader - -We support an optional iterable-style DataLoader based on [Pytorch Iterable-style DataPipes](https://pytorch.org/data/beta/torchdata.datapipes.iter.html) for large dataset and users can set `dataset_type=large` to enable it. - -* Configuration - -The parameters of the training, including model, optimization, dataset, etc., can be set by a YAML file in `conf` directory. Also, users can directly set the parameters in `run.sh` recipe. Please avoid to set the same parameters in both the YAML file and the recipe. - -* Training Steps - -We support two parameters to specify the training steps, namely `max_epoch` and `max_update`. `max_epoch` indicates the total training epochs while `max_update` indicates the total training steps. If these two parameters are specified at the same time, once the training reaches any one of these two parameters, the training will be stopped. - -* Tensorboard - -Users can use tensorboard to observe the loss, learning rate, etc. Please run the following command: -``` -tensorboard --logdir ${exp_dir}/exp/${model_dir}/tensorboard/train -``` - -## Stage 4: Decoding -This stage generates the recognition results and calculates the `CER` to verify the performance of the trained model. - -* Mode Selection - -As we support paraformer, uniasr, conformer and other models in FunASR, a `mode` parameter should be specified as `asr/paraformer/uniasr` according to the trained model. - -* Configuration - -We support CTC decoding, attention decoding and hybrid CTC-attention decoding in FunASR, which can be specified by `ctc_weight` in a YAML file in `conf` directory. Specifically, `ctc_weight=1.0` indicates CTC decoding, `ctc_weight=0.0` indicates attention decoding, `0.0 - - -一 -丁 -... -龚 -龟 - -``` -* ``: indicates the blank token for CTC -* ``: indicates the start-of-sentence token -* ``: indicates the end-of-sentence token -* ``: indicates the out-of-vocabulary token - -## Stage 3: Training -This stage achieves the training of the specified model. To start training, users should manually set `exp_dir`, `CUDA_VISIBLE_DEVICES` and `gpu_num`, which have already been explained above. By default, the best `$keep_nbest_models` checkpoints on validation dataset will be averaged to generate a better model and adopted for decoding. - -* DDP Training - -We support the DistributedDataParallel (DDP) training and the detail can be found [here](https://pytorch.org/tutorials/intermediate/ddp_tutorial.html). To enable DDP training, please set `gpu_num` greater than 1. For example, if you set `CUDA_VISIBLE_DEVICES=0,1,5,6,7` and `gpu_num=3`, then the gpus with ids 0, 1 and 5 will be used for training. - -* DataLoader - -We support an optional iterable-style DataLoader based on [Pytorch Iterable-style DataPipes](https://pytorch.org/data/beta/torchdata.datapipes.iter.html) for large dataset and users can set `dataset_type=large` to enable it. - -* Configuration - -The parameters of the training, including model, optimization, dataset, etc., can be set by a YAML file in `conf` directory. Also, users can directly set the parameters in `run.sh` recipe. Please avoid to set the same parameters in both the YAML file and the recipe. - -* Training Steps - -We support two parameters to specify the training steps, namely `max_epoch` and `max_update`. `max_epoch` indicates the total training epochs while `max_update` indicates the total training steps. If these two parameters are specified at the same time, once the training reaches any one of these two parameters, the training will be stopped. - -* Tensorboard - -Users can use tensorboard to observe the loss, learning rate, etc. Please run the following command: -``` -tensorboard --logdir ${exp_dir}/exp/${model_dir}/tensorboard/train -``` - -## Stage 4: Decoding -This stage generates the recognition results and calculates the `CER` to verify the performance of the trained model. - -* Mode Selection - -As we support paraformer, uniasr, conformer and other models in FunASR, a `mode` parameter should be specified as `asr/paraformer/uniasr` according to the trained model. - -* Configuration - -We support CTC decoding, attention decoding and hybrid CTC-attention decoding in FunASR, which can be specified by `ctc_weight` in a YAML file in `conf` directory. Specifically, `ctc_weight=1.0` indicates CTC decoding, `ctc_weight=0.0` indicates attention decoding, `0.0 Date: Mon, 8 May 2023 19:12:29 +0800 Subject: [PATCH 085/120] rename api names --- .../include/{libfunasrapi.h => funasrruntime.h} | 12 ++++++------ .../onnxruntime/src/funasr-onnx-offline-punc.cpp | 2 +- .../onnxruntime/src/funasr-onnx-offline-rtf.cpp | 2 +- .../onnxruntime/src/funasr-onnx-offline-vad.cpp | 14 +++++++------- .../onnxruntime/src/funasr-onnx-offline.cpp | 2 +- .../src/{libfunasrapi.cpp => funasrruntime.cpp} | 12 ++++++------ funasr/runtime/onnxruntime/src/precomp.h | 2 +- .../onnxruntime/src/{resample.cc => resample.cpp} | 0 8 files changed, 23 insertions(+), 23 deletions(-) rename funasr/runtime/onnxruntime/include/{libfunasrapi.h => funasrruntime.h} (83%) rename funasr/runtime/onnxruntime/src/{libfunasrapi.cpp => funasrruntime.cpp} (93%) rename funasr/runtime/onnxruntime/src/{resample.cc => resample.cpp} (100%) diff --git a/funasr/runtime/onnxruntime/include/libfunasrapi.h b/funasr/runtime/onnxruntime/include/funasrruntime.h similarity index 83% rename from funasr/runtime/onnxruntime/include/libfunasrapi.h rename to funasr/runtime/onnxruntime/include/funasrruntime.h index 152db6183..065fa299f 100644 --- a/funasr/runtime/onnxruntime/include/libfunasrapi.h +++ b/funasr/runtime/onnxruntime/include/funasrruntime.h @@ -63,13 +63,13 @@ _FUNASRAPI void FunASRUninit(FUNASR_HANDLE handle); _FUNASRAPI const float FunASRGetRetSnippetTime(FUNASR_RESULT result); // VAD -_FUNASRAPI FUNASR_HANDLE FunVadInit(std::map& model_path, int thread_num); +_FUNASRAPI FUNASR_HANDLE FsmnVadInit(std::map& model_path, int thread_num); -_FUNASRAPI FUNASR_RESULT FunVadWavFile(FUNASR_HANDLE handle, const char* sz_wavfile, FUNASR_MODE mode, QM_CALLBACK fn_callback); -_FUNASRAPI std::vector>* FunVadGetResult(FUNASR_RESULT result,int n_index); -_FUNASRAPI void FunVadFreeResult(FUNASR_RESULT result); -_FUNASRAPI void FunVadUninit(FUNASR_HANDLE handle); -_FUNASRAPI const float FunVadGetRetSnippetTime(FUNASR_RESULT result); +_FUNASRAPI FUNASR_RESULT FsmnVadWavFile(FUNASR_HANDLE handle, const char* sz_wavfile, FUNASR_MODE mode, QM_CALLBACK fn_callback); +_FUNASRAPI std::vector>* FsmnVadGetResult(FUNASR_RESULT result,int n_index); +_FUNASRAPI void FsmnVadFreeResult(FUNASR_RESULT result); +_FUNASRAPI void FsmnVadUninit(FUNASR_HANDLE handle); +_FUNASRAPI const float FsmnVadGetRetSnippetTime(FUNASR_RESULT result); // PUNC _FUNASRAPI FUNASR_HANDLE FunPuncInit(std::map& model_path, int thread_num); diff --git a/funasr/runtime/onnxruntime/src/funasr-onnx-offline-punc.cpp b/funasr/runtime/onnxruntime/src/funasr-onnx-offline-punc.cpp index e8f221f6f..4354ad474 100644 --- a/funasr/runtime/onnxruntime/src/funasr-onnx-offline-punc.cpp +++ b/funasr/runtime/onnxruntime/src/funasr-onnx-offline-punc.cpp @@ -14,7 +14,7 @@ #include #include #include -#include "libfunasrapi.h" +#include "funasrruntime.h" #include "tclap/CmdLine.h" #include "com-define.h" diff --git a/funasr/runtime/onnxruntime/src/funasr-onnx-offline-rtf.cpp b/funasr/runtime/onnxruntime/src/funasr-onnx-offline-rtf.cpp index e2f8ee5a7..76624e768 100644 --- a/funasr/runtime/onnxruntime/src/funasr-onnx-offline-rtf.cpp +++ b/funasr/runtime/onnxruntime/src/funasr-onnx-offline-rtf.cpp @@ -10,7 +10,7 @@ #endif #include -#include "libfunasrapi.h" +#include "funasrruntime.h" #include "tclap/CmdLine.h" #include "com-define.h" diff --git a/funasr/runtime/onnxruntime/src/funasr-onnx-offline-vad.cpp b/funasr/runtime/onnxruntime/src/funasr-onnx-offline-vad.cpp index 278753484..37513ae2a 100644 --- a/funasr/runtime/onnxruntime/src/funasr-onnx-offline-vad.cpp +++ b/funasr/runtime/onnxruntime/src/funasr-onnx-offline-vad.cpp @@ -15,7 +15,7 @@ #include #include #include -#include "libfunasrapi.h" +#include "funasrruntime.h" #include "tclap/CmdLine.h" #include "com-define.h" @@ -76,7 +76,7 @@ int main(int argc, char *argv[]) struct timeval start, end; gettimeofday(&start, NULL); int thread_num = 1; - FUNASR_HANDLE vad_hanlde=FunVadInit(model_path, thread_num); + FUNASR_HANDLE vad_hanlde=FsmnVadInit(model_path, thread_num); if (!vad_hanlde) { @@ -116,17 +116,17 @@ int main(int argc, char *argv[]) long taking_micros = 0; for(auto& wav_file : wav_list){ gettimeofday(&start, NULL); - FUNASR_RESULT result=FunVadWavFile(vad_hanlde, wav_file.c_str(), RASR_NONE, NULL); + FUNASR_RESULT result=FsmnVadWavFile(vad_hanlde, wav_file.c_str(), RASR_NONE, NULL); gettimeofday(&end, NULL); seconds = (end.tv_sec - start.tv_sec); taking_micros += ((seconds * 1000000) + end.tv_usec) - (start.tv_usec); if (result) { - vector>* vad_segments = FunVadGetResult(result, 0); + vector>* vad_segments = FsmnVadGetResult(result, 0); print_segs(vad_segments); - snippet_time += FunVadGetRetSnippetTime(result); - FunVadFreeResult(result); + snippet_time += FsmnVadGetRetSnippetTime(result); + FsmnVadFreeResult(result); } else { @@ -137,7 +137,7 @@ int main(int argc, char *argv[]) LOG(INFO) << "Audio length: " << (double)snippet_time << " s"; LOG(INFO) << "Model inference takes: " << (double)taking_micros / 1000000 <<" s"; LOG(INFO) << "Model inference RTF: " << (double)taking_micros/ (snippet_time*1000000); - FunVadUninit(vad_hanlde); + FsmnVadUninit(vad_hanlde); return 0; } diff --git a/funasr/runtime/onnxruntime/src/funasr-onnx-offline.cpp b/funasr/runtime/onnxruntime/src/funasr-onnx-offline.cpp index 51758a733..3b8ef51f4 100644 --- a/funasr/runtime/onnxruntime/src/funasr-onnx-offline.cpp +++ b/funasr/runtime/onnxruntime/src/funasr-onnx-offline.cpp @@ -14,7 +14,7 @@ #include #include #include -#include "libfunasrapi.h" +#include "funasrruntime.h" #include "tclap/CmdLine.h" #include "com-define.h" diff --git a/funasr/runtime/onnxruntime/src/libfunasrapi.cpp b/funasr/runtime/onnxruntime/src/funasrruntime.cpp similarity index 93% rename from funasr/runtime/onnxruntime/src/libfunasrapi.cpp rename to funasr/runtime/onnxruntime/src/funasrruntime.cpp index 439e8da85..ab826bee6 100644 --- a/funasr/runtime/onnxruntime/src/libfunasrapi.cpp +++ b/funasr/runtime/onnxruntime/src/funasrruntime.cpp @@ -11,7 +11,7 @@ extern "C" { return mm; } - _FUNASRAPI FUNASR_HANDLE FunVadInit(std::map& model_path, int thread_num) + _FUNASRAPI FUNASR_HANDLE FsmnVadInit(std::map& model_path, int thread_num) { VadModel* mm = CreateVadModel(model_path, thread_num); return mm; @@ -145,7 +145,7 @@ extern "C" { } // APIs for VAD Infer - _FUNASRAPI FUNASR_RESULT FunVadWavFile(FUNASR_HANDLE handle, const char* sz_wavfile, FUNASR_MODE mode, QM_CALLBACK fn_callback) + _FUNASRAPI FUNASR_RESULT FsmnVadWavFile(FUNASR_HANDLE handle, const char* sz_wavfile, FUNASR_MODE mode, QM_CALLBACK fn_callback) { VadModel* vad_obj = (VadModel*)handle; if (!vad_obj) @@ -231,7 +231,7 @@ extern "C" { return ((FUNASR_RECOG_RESULT*)result)->snippet_time; } - _FUNASRAPI const float FunVadGetRetSnippetTime(FUNASR_RESULT result) + _FUNASRAPI const float FsmnVadGetRetSnippetTime(FUNASR_RESULT result) { if (!result) return 0.0f; @@ -249,7 +249,7 @@ extern "C" { return p_result->msg.c_str(); } - _FUNASRAPI vector>* FunVadGetResult(FUNASR_RESULT result,int n_index) + _FUNASRAPI vector>* FsmnVadGetResult(FUNASR_RESULT result,int n_index) { FUNASR_VAD_RESULT * p_result = (FUNASR_VAD_RESULT*)result; if(!p_result) @@ -267,7 +267,7 @@ extern "C" { } } - _FUNASRAPI void FunVadFreeResult(FUNASR_RESULT result) + _FUNASRAPI void FsmnVadFreeResult(FUNASR_RESULT result) { FUNASR_VAD_RESULT * p_result = (FUNASR_VAD_RESULT*)result; if (p_result) @@ -290,7 +290,7 @@ extern "C" { delete recog_obj; } - _FUNASRAPI void FunVadUninit(FUNASR_HANDLE handle) + _FUNASRAPI void FsmnVadUninit(FUNASR_HANDLE handle) { VadModel* recog_obj = (VadModel*)handle; diff --git a/funasr/runtime/onnxruntime/src/precomp.h b/funasr/runtime/onnxruntime/src/precomp.h index 0d3199ee7..9a8b17d69 100644 --- a/funasr/runtime/onnxruntime/src/precomp.h +++ b/funasr/runtime/onnxruntime/src/precomp.h @@ -45,6 +45,6 @@ using namespace std; #include "resample.h" #include "paraformer.h" #include "offline-stream.h" -#include "libfunasrapi.h" +#include "funasrruntime.h" using namespace paraformer; diff --git a/funasr/runtime/onnxruntime/src/resample.cc b/funasr/runtime/onnxruntime/src/resample.cpp similarity index 100% rename from funasr/runtime/onnxruntime/src/resample.cc rename to funasr/runtime/onnxruntime/src/resample.cpp From 760d1cd6d2e8e449c471a1514bcbf790f65a7899 Mon Sep 17 00:00:00 2001 From: lyblsgo Date: Mon, 8 May 2023 19:47:01 +0800 Subject: [PATCH 086/120] fix paraformer-server for new apis --- funasr/runtime/grpc/Readme.md | 49 ++++++++---------- funasr/runtime/grpc/paraformer-server.cc | 50 ++++++++----------- funasr/runtime/grpc/paraformer-server.h | 2 +- .../onnxruntime/include/funasrruntime.h | 3 +- .../onnxruntime/src/funasr-onnx-offline.cpp | 2 +- .../runtime/onnxruntime/src/funasrruntime.cpp | 37 +++++++++++++- 6 files changed, 82 insertions(+), 61 deletions(-) diff --git a/funasr/runtime/grpc/Readme.md b/funasr/runtime/grpc/Readme.md index 44994412b..71bb03594 100644 --- a/funasr/runtime/grpc/Readme.md +++ b/funasr/runtime/grpc/Readme.md @@ -37,39 +37,32 @@ source ~/.bashrc ### Start grpc paraformer server ``` -./cmake/build/paraformer-server --port-id [--punc-config - ] [--punc-model ] - --am-config --am-cmvn - --am-model [--vad-config - ] [--vad-cmvn ] - [--vad-model ] [--] [--version] - [-h] + +./cmake/build/paraformer-server --port-id [--punc-quant ] + [--punc-dir ] [--vad-quant ] + [--vad-dir ] [--quantize ] + --model-dir [--] [--version] [-h] Where: --port-id (required) port id + --model-dir + (required) the asr model path, which contains model.onnx, config.yaml, am.mvn + --quantize + false (Default), load the model of model.onnx in model_dir. If set true, load the model of model_quant.onnx in model_dir - --am-config - (required) am config path - --am-cmvn - (required) am cmvn path - --am-model - (required) am model path + --vad-dir + the vad model path, which contains model.onnx, vad.yaml, vad.mvn + --vad-quant + false (Default), load the model of model.onnx in vad_dir. If set true, load the model of model_quant.onnx in vad_dir - --punc-config - punc config path - --punc-model - punc model path - - --vad-config - vad config path - --vad-cmvn - vad cmvn path - --vad-model - vad model path - - Required: --port-id --am-config --am-cmvn --am-model - If use vad, please add: [--vad-config ] [--vad-cmvn ] [--vad-model ] - If use punc, please add: [--punc-config ] [--punc-model ] + --punc-dir + the punc model path, which contains model.onnx, punc.yaml + --punc-quant + false (Default), load the model of model.onnx in punc_dir. If set true, load the model of model_quant.onnx in punc_dir + + Required: --port-id --model-dir + If use vad, please add: --vad-dir + If use punc, please add: --punc-dir ``` ## For the client diff --git a/funasr/runtime/grpc/paraformer-server.cc b/funasr/runtime/grpc/paraformer-server.cc index 31333c9eb..3bc011aea 100644 --- a/funasr/runtime/grpc/paraformer-server.cc +++ b/funasr/runtime/grpc/paraformer-server.cc @@ -31,7 +31,7 @@ using paraformer::Response; using paraformer::ASR; ASRServicer::ASRServicer(std::map& model_path) { - AsrHanlde=FunASRInit(model_path, 1); + AsrHanlde=FunOfflineInit(model_path, 1); std::cout << "ASRServicer init" << std::endl; init_flag = 0; } @@ -137,7 +137,7 @@ grpc::Status ASRServicer::Recognize( stream->Write(res); } else { - FUNASR_RESULT Result= FunASRRecogPCMBuffer(AsrHanlde, tmp_data.c_str(), data_len_int, 16000, RASR_NONE, NULL); + FUNASR_RESULT Result= FunOfflineRecogPCMBuffer(AsrHanlde, tmp_data.c_str(), data_len_int, 16000, RASR_NONE, NULL); std::string asr_result = ((FUNASR_RECOG_RESULT*)Result)->msg; auto end_time = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); @@ -204,38 +204,30 @@ int main(int argc, char* argv[]) { FLAGS_logtostderr = true; TCLAP::CmdLine cmd("paraformer-server", ' ', "1.0"); - TCLAP::ValueArg vad_model("", VAD_MODEL_PATH, "vad model path", false, "", "string"); - TCLAP::ValueArg vad_cmvn("", VAD_CMVN_PATH, "vad cmvn path", false, "", "string"); - TCLAP::ValueArg vad_config("", VAD_CONFIG_PATH, "vad config path", false, "", "string"); + TCLAP::ValueArg model_dir("", MODEL_DIR, "the asr model path, which contains model.onnx, config.yaml, am.mvn", true, "", "string"); + TCLAP::ValueArg quantize("", QUANTIZE, "false (Default), load the model of model.onnx in model_dir. If set true, load the model of model_quant.onnx in model_dir", false, "false", "string"); + TCLAP::ValueArg vad_dir("", VAD_DIR, "the vad model path, which contains model.onnx, vad.yaml, vad.mvn", false, "", "string"); + TCLAP::ValueArg vad_quant("", VAD_QUANT, "false (Default), load the model of model.onnx in vad_dir. If set true, load the model of model_quant.onnx in vad_dir", false, "false", "string"); + TCLAP::ValueArg punc_dir("", PUNC_DIR, "the punc model path, which contains model.onnx, punc.yaml", false, "", "string"); + TCLAP::ValueArg punc_quant("", PUNC_QUANT, "false (Default), load the model of model.onnx in punc_dir. If set true, load the model of model_quant.onnx in punc_dir", false, "false", "string"); + TCLAP::ValueArg port_id("", PORT_ID, "port id", true, "", "string"); - TCLAP::ValueArg am_model("", AM_MODEL_PATH, "am model path", true, "", "string"); - TCLAP::ValueArg am_cmvn("", AM_CMVN_PATH, "am cmvn path", true, "", "string"); - TCLAP::ValueArg am_config("", AM_CONFIG_PATH, "am config path", true, "", "string"); - - TCLAP::ValueArg punc_model("", PUNC_MODEL_PATH, "punc model path", false, "", "string"); - TCLAP::ValueArg punc_config("", PUNC_CONFIG_PATH, "punc config path", false, "", "string"); - TCLAP::ValueArg port_id("", PORT_ID, "port id", true, "", "string"); - - cmd.add(vad_model); - cmd.add(vad_cmvn); - cmd.add(vad_config); - cmd.add(am_model); - cmd.add(am_cmvn); - cmd.add(am_config); - cmd.add(punc_model); - cmd.add(punc_config); + cmd.add(model_dir); + cmd.add(quantize); + cmd.add(vad_dir); + cmd.add(vad_quant); + cmd.add(punc_dir); + cmd.add(punc_quant); cmd.add(port_id); cmd.parse(argc, argv); std::map model_path; - GetValue(vad_model, VAD_MODEL_PATH, model_path); - GetValue(vad_cmvn, VAD_CMVN_PATH, model_path); - GetValue(vad_config, VAD_CONFIG_PATH, model_path); - GetValue(am_model, AM_MODEL_PATH, model_path); - GetValue(am_cmvn, AM_CMVN_PATH, model_path); - GetValue(am_config, AM_CONFIG_PATH, model_path); - GetValue(punc_model, PUNC_MODEL_PATH, model_path); - GetValue(punc_config, PUNC_CONFIG_PATH, model_path); + GetValue(model_dir, MODEL_DIR, model_path); + GetValue(quantize, QUANTIZE, model_path); + GetValue(vad_dir, VAD_DIR, model_path); + GetValue(vad_quant, VAD_QUANT, model_path); + GetValue(punc_dir, PUNC_DIR, model_path); + GetValue(punc_quant, PUNC_QUANT, model_path); GetValue(port_id, PORT_ID, model_path); RunServer(model_path); diff --git a/funasr/runtime/grpc/paraformer-server.h b/funasr/runtime/grpc/paraformer-server.h index 108e3b688..760ea2a83 100644 --- a/funasr/runtime/grpc/paraformer-server.h +++ b/funasr/runtime/grpc/paraformer-server.h @@ -15,7 +15,7 @@ #include #include "paraformer.grpc.pb.h" -#include "libfunasrapi.h" +#include "funasrruntime.h" using grpc::Server; diff --git a/funasr/runtime/onnxruntime/include/funasrruntime.h b/funasr/runtime/onnxruntime/include/funasrruntime.h index 065fa299f..7d290aa3e 100644 --- a/funasr/runtime/onnxruntime/include/funasrruntime.h +++ b/funasr/runtime/onnxruntime/include/funasrruntime.h @@ -78,7 +78,8 @@ _FUNASRAPI void FunPuncUninit(FUNASR_HANDLE handle); //OfflineStream _FUNASRAPI FUNASR_HANDLE FunOfflineInit(std::map& model_path, int thread_num); -_FUNASRAPI FUNASR_RESULT FunOfflineStream(FUNASR_HANDLE handle, const char* sz_wavfile, FUNASR_MODE mode, QM_CALLBACK fn_callback); +_FUNASRAPI FUNASR_RESULT FunOfflineRecogFile(FUNASR_HANDLE handle, const char* sz_wavfile, FUNASR_MODE mode, QM_CALLBACK fn_callback); +_FUNASRAPI FUNASR_RESULT FunOfflineRecogPCMBuffer(FUNASR_HANDLE handle, const char* sz_buf, int n_len, int sampling_rate, FUNASR_MODE mode, QM_CALLBACK fn_callback); _FUNASRAPI void FunOfflineUninit(FUNASR_HANDLE handle); #ifdef __cplusplus diff --git a/funasr/runtime/onnxruntime/src/funasr-onnx-offline.cpp b/funasr/runtime/onnxruntime/src/funasr-onnx-offline.cpp index 3b8ef51f4..343039d7c 100644 --- a/funasr/runtime/onnxruntime/src/funasr-onnx-offline.cpp +++ b/funasr/runtime/onnxruntime/src/funasr-onnx-offline.cpp @@ -107,7 +107,7 @@ int main(int argc, char** argv) long taking_micros = 0; for(auto& wav_file : wav_list){ gettimeofday(&start, NULL); - FUNASR_RESULT result=FunOfflineStream(asr_hanlde, wav_file.c_str(), RASR_NONE, NULL); + FUNASR_RESULT result=FunOfflineRecogFile(asr_hanlde, wav_file.c_str(), RASR_NONE, NULL); gettimeofday(&end, NULL); seconds = (end.tv_sec - start.tv_sec); taking_micros += ((seconds * 1000000) + end.tv_usec) - (start.tv_usec); diff --git a/funasr/runtime/onnxruntime/src/funasrruntime.cpp b/funasr/runtime/onnxruntime/src/funasrruntime.cpp index ab826bee6..ee6143edf 100644 --- a/funasr/runtime/onnxruntime/src/funasrruntime.cpp +++ b/funasr/runtime/onnxruntime/src/funasrruntime.cpp @@ -178,7 +178,7 @@ extern "C" { } // APIs for Offline-stream Infer - _FUNASRAPI FUNASR_RESULT FunOfflineStream(FUNASR_HANDLE handle, const char* sz_wavfile, FUNASR_MODE mode, QM_CALLBACK fn_callback) + _FUNASRAPI FUNASR_RESULT FunOfflineRecogFile(FUNASR_HANDLE handle, const char* sz_wavfile, FUNASR_MODE mode, QM_CALLBACK fn_callback) { OfflineStream* offline_stream = (OfflineStream*)handle; if (!offline_stream) @@ -214,6 +214,41 @@ extern "C" { return p_result; } + _FUNASRAPI FUNASR_RESULT FunOfflineRecogPCMBuffer(FUNASR_HANDLE handle, const char* sz_buf, int n_len, int sampling_rate, FUNASR_MODE mode, QM_CALLBACK fn_callback) + { + OfflineStream* offline_stream = (OfflineStream*)handle; + if (!offline_stream) + return nullptr; + + Audio audio(1); + if (!audio.LoadPcmwav(sz_buf, n_len, &sampling_rate)) + return nullptr; + if(offline_stream->UseVad()){ + audio.Split(offline_stream); + } + + float* buff; + int len; + int flag = 0; + FUNASR_RECOG_RESULT* p_result = new FUNASR_RECOG_RESULT; + p_result->snippet_time = audio.GetTimeLen(); + int n_step = 0; + int n_total = audio.GetQueueSize(); + while (audio.Fetch(buff, len, flag) > 0) { + string msg = (offline_stream->asr_handle)->Forward(buff, len, flag); + p_result->msg += msg; + n_step++; + if (fn_callback) + fn_callback(n_step, n_total); + } + if(offline_stream->UsePunc()){ + string punc_res = (offline_stream->punc_handle)->AddPunc((p_result->msg).c_str()); + p_result->msg = punc_res; + } + + return p_result; + } + _FUNASRAPI const int FunASRGetRetNumber(FUNASR_RESULT result) { if (!result) From 090fe9fad0b3e74f56be55b604e2c0731aac4708 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=B8=E9=9B=81?= Date: Mon, 8 May 2023 20:05:03 +0800 Subject: [PATCH 087/120] fix --- funasr/runtime/python/websocket/ws_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/funasr/runtime/python/websocket/ws_client.py b/funasr/runtime/python/websocket/ws_client.py index 5ced6888b..a4a6d9f54 100644 --- a/funasr/runtime/python/websocket/ws_client.py +++ b/funasr/runtime/python/websocket/ws_client.py @@ -189,7 +189,7 @@ async def message(id): text_print_2pass_online += " {}".format(text) text_print = text_print_2pass_offline + text_print_2pass_online else: - text_print_2pass_online = " " + text_print_2pass_online = "" text_print = text_print_2pass_offline + "{}".format(text) text_print_2pass_offline += "{}".format(text) text_print = text_print[-args.words_max_print:] From 0983550a2253a5628aabdc998ebff44dcf1906fc Mon Sep 17 00:00:00 2001 From: lyblsgo Date: Mon, 8 May 2023 20:31:39 +0800 Subject: [PATCH 088/120] add funasr namespace --- funasr/runtime/onnxruntime/include/audio.h | 2 + .../runtime/onnxruntime/include/com-define.h | 7 +- .../runtime/onnxruntime/include/glog/export.h | 42 + .../onnxruntime/include/glog/log_severity.h | 98 + .../onnxruntime/include/glog/logging.h | 1842 +++++++++++++++++ .../onnxruntime/include/glog/logging.h.in | 1842 +++++++++++++++++ .../onnxruntime/include/glog/platform.h | 60 + .../onnxruntime/include/glog/raw_logging.h | 179 ++ .../onnxruntime/include/glog/raw_logging.h.in | 179 ++ .../onnxruntime/include/glog/stl_logging.h | 177 ++ .../onnxruntime/include/glog/stl_logging.h.in | 177 ++ .../onnxruntime/include/glog/vlog_is_on.h | 120 ++ .../onnxruntime/include/glog/vlog_is_on.h.in | 120 ++ funasr/runtime/onnxruntime/include/model.h | 3 +- .../onnxruntime/include/offline-stream.h | 2 + .../runtime/onnxruntime/include/punc-model.h | 2 + .../runtime/onnxruntime/include/vad-model.h | 2 + 17 files changed, 4849 insertions(+), 5 deletions(-) create mode 100644 funasr/runtime/onnxruntime/include/glog/export.h create mode 100644 funasr/runtime/onnxruntime/include/glog/log_severity.h create mode 100644 funasr/runtime/onnxruntime/include/glog/logging.h create mode 100644 funasr/runtime/onnxruntime/include/glog/logging.h.in create mode 100644 funasr/runtime/onnxruntime/include/glog/platform.h create mode 100644 funasr/runtime/onnxruntime/include/glog/raw_logging.h create mode 100644 funasr/runtime/onnxruntime/include/glog/raw_logging.h.in create mode 100644 funasr/runtime/onnxruntime/include/glog/stl_logging.h create mode 100644 funasr/runtime/onnxruntime/include/glog/stl_logging.h.in create mode 100644 funasr/runtime/onnxruntime/include/glog/vlog_is_on.h create mode 100644 funasr/runtime/onnxruntime/include/glog/vlog_is_on.h.in diff --git a/funasr/runtime/onnxruntime/include/audio.h b/funasr/runtime/onnxruntime/include/audio.h index a61a68fe9..1eabd3e7b 100644 --- a/funasr/runtime/onnxruntime/include/audio.h +++ b/funasr/runtime/onnxruntime/include/audio.h @@ -11,6 +11,7 @@ #endif using namespace std; +namespace funasr { class AudioFrame { private: @@ -60,4 +61,5 @@ class Audio { int GetQueueSize() { return (int)frame_queue.size(); } }; +} // namespace funasr #endif diff --git a/funasr/runtime/onnxruntime/include/com-define.h b/funasr/runtime/onnxruntime/include/com-define.h index ad3bd35d3..7a6345bbf 100644 --- a/funasr/runtime/onnxruntime/include/com-define.h +++ b/funasr/runtime/onnxruntime/include/com-define.h @@ -1,7 +1,6 @@ +#pragma once -#ifndef COMDEFINE_H -#define COMDEFINE_H - +namespace funasr { #define S_BEGIN 0 #define S_MIDDLE 1 #define S_END 2 @@ -77,4 +76,4 @@ #define DUN_INDEX 5 #define CACHE_POP_TRIGGER_LIMIT 200 -#endif +} // namespace funasr diff --git a/funasr/runtime/onnxruntime/include/glog/export.h b/funasr/runtime/onnxruntime/include/glog/export.h new file mode 100644 index 000000000..1ad80af5b --- /dev/null +++ b/funasr/runtime/onnxruntime/include/glog/export.h @@ -0,0 +1,42 @@ + +#ifndef GLOG_EXPORT_H +#define GLOG_EXPORT_H + +#ifdef GLOG_STATIC_DEFINE +# define GLOG_EXPORT +# define GLOG_NO_EXPORT +#else +# ifndef GLOG_EXPORT +# ifdef GOOGLE_GLOG_IS_A_DLL + /* We are building this library */ +# define GLOG_EXPORT +# else + /* We are using this library */ +# define GLOG_EXPORT +# endif +# endif + +# ifndef GLOG_NO_EXPORT +# define GLOG_NO_EXPORT +# endif +#endif + +#ifndef GLOG_DEPRECATED +# define GLOG_DEPRECATED __attribute__ ((__deprecated__)) +#endif + +#ifndef GLOG_DEPRECATED_EXPORT +# define GLOG_DEPRECATED_EXPORT GLOG_EXPORT GLOG_DEPRECATED +#endif + +#ifndef GLOG_DEPRECATED_NO_EXPORT +# define GLOG_DEPRECATED_NO_EXPORT GLOG_NO_EXPORT GLOG_DEPRECATED +#endif + +#if 0 /* DEFINE_NO_DEPRECATED */ +# ifndef GLOG_NO_DEPRECATED +# define GLOG_NO_DEPRECATED +# endif +#endif + +#endif /* GLOG_EXPORT_H */ diff --git a/funasr/runtime/onnxruntime/include/glog/log_severity.h b/funasr/runtime/onnxruntime/include/glog/log_severity.h new file mode 100644 index 000000000..d52989d72 --- /dev/null +++ b/funasr/runtime/onnxruntime/include/glog/log_severity.h @@ -0,0 +1,98 @@ +// Copyright (c) 2023, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef BASE_LOG_SEVERITY_H__ +#define BASE_LOG_SEVERITY_H__ + +// The recommended semantics of the log levels are as follows: +// +// INFO: +// Use for state changes or other major events, or to aid debugging. +// WARNING: +// Use for undesired but relatively expected events, which may indicate a +// problem +// ERROR: +// Use for undesired and unexpected events that the program can recover from. +// All ERRORs should be actionable - it should be appropriate to file a bug +// whenever an ERROR occurs in production. +// FATAL: +// Use for undesired and unexpected events that the program cannot recover +// from. + +// Variables of type LogSeverity are widely taken to lie in the range +// [0, NUM_SEVERITIES-1]. Be careful to preserve this assumption if +// you ever need to change their values or add a new severity. +using LogSeverity = int; + +const int GLOG_INFO = 0, GLOG_WARNING = 1, GLOG_ERROR = 2, GLOG_FATAL = 3, + NUM_SEVERITIES = 4; +#ifndef GLOG_NO_ABBREVIATED_SEVERITIES +# ifdef ERROR +# error ERROR macro is defined. Define GLOG_NO_ABBREVIATED_SEVERITIES before including logging.h. See the document for detail. +# endif +const int INFO = GLOG_INFO, WARNING = GLOG_WARNING, + ERROR = GLOG_ERROR, FATAL = GLOG_FATAL; +#endif + +// DFATAL is FATAL in debug mode, ERROR in normal mode +#ifdef NDEBUG +#define DFATAL_LEVEL ERROR +#else +#define DFATAL_LEVEL FATAL +#endif + +extern GLOG_EXPORT const char* const LogSeverityNames[NUM_SEVERITIES]; + +// NDEBUG usage helpers related to (RAW_)DCHECK: +// +// DEBUG_MODE is for small !NDEBUG uses like +// if (DEBUG_MODE) foo.CheckThatFoo(); +// instead of substantially more verbose +// #ifndef NDEBUG +// foo.CheckThatFoo(); +// #endif +// +// IF_DEBUG_MODE is for small !NDEBUG uses like +// IF_DEBUG_MODE( string error; ) +// DCHECK(Foo(&error)) << error; +// instead of substantially more verbose +// #ifndef NDEBUG +// string error; +// DCHECK(Foo(&error)) << error; +// #endif +// +#ifdef NDEBUG +enum { DEBUG_MODE = 0 }; +#define IF_DEBUG_MODE(x) +#else +enum { DEBUG_MODE = 1 }; +#define IF_DEBUG_MODE(x) x +#endif + +#endif // BASE_LOG_SEVERITY_H__ diff --git a/funasr/runtime/onnxruntime/include/glog/logging.h b/funasr/runtime/onnxruntime/include/glog/logging.h new file mode 100644 index 000000000..6f6685a44 --- /dev/null +++ b/funasr/runtime/onnxruntime/include/glog/logging.h @@ -0,0 +1,1842 @@ +// Copyright (c) 2023, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: Ray Sidney +// +// This file contains #include information about logging-related stuff. +// Pretty much everybody needs to #include this file so that they can +// log various happenings. +// +#ifndef GLOG_LOGGING_H +#define GLOG_LOGGING_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if 1 +# include +#endif +#include + +#if defined(_MSC_VER) +#define GLOG_MSVC_PUSH_DISABLE_WARNING(n) __pragma(warning(push)) \ + __pragma(warning(disable:n)) +#define GLOG_MSVC_POP_WARNING() __pragma(warning(pop)) +#else +#define GLOG_MSVC_PUSH_DISABLE_WARNING(n) +#define GLOG_MSVC_POP_WARNING() +#endif + +#include + +#if 1 +#include +#endif + +// We care a lot about number of bits things take up. Unfortunately, +// systems define their bit-specific ints in a lot of different ways. +// We use our own way, and have a typedef to get there. +// Note: these commands below may look like "#if 1" or "#if 0", but +// that's because they were constructed that way at ./configure time. +// Look at logging.h.in to see how they're calculated (based on your config). +#include // the normal place uint16_t is defined +#if 1 +#include // the normal place u_int16_t is defined +#endif + +#if 0 +#include +#endif + +#include + +namespace google { + + typedef std::int32_t int32; +typedef std::uint32_t uint32; +typedef std::int64_t int64; +typedef std::uint64_t uint64; + +#if !(1) +typedef ptrdiff_t ssize_t; +#endif + +#if !(1) +typedef int mode_t; +#endif + +typedef double WallTime; + +struct GLOG_EXPORT LogMessageTime { + LogMessageTime(); + LogMessageTime(std::tm t); + LogMessageTime(std::time_t timestamp, WallTime now); + + const time_t& timestamp() const { return timestamp_; } + const int& sec() const { return time_struct_.tm_sec; } + const int32_t& usec() const { return usecs_; } + const int&(min)() const { return time_struct_.tm_min; } + const int& hour() const { return time_struct_.tm_hour; } + const int& day() const { return time_struct_.tm_mday; } + const int& month() const { return time_struct_.tm_mon; } + const int& year() const { return time_struct_.tm_year; } + const int& dayOfWeek() const { return time_struct_.tm_wday; } + const int& dayInYear() const { return time_struct_.tm_yday; } + const int& dst() const { return time_struct_.tm_isdst; } + const long int& gmtoff() const { return gmtoffset_; } + const std::tm& tm() const { return time_struct_; } + + private: + void init(const std::tm& t, std::time_t timestamp, WallTime now); + std::tm time_struct_; // Time of creation of LogMessage + time_t timestamp_; // Time of creation of LogMessage in seconds + int32_t usecs_; // Time of creation of LogMessage - microseconds part + long int gmtoffset_; + + void CalcGmtOffset(); +}; + +struct LogMessageInfo { + explicit LogMessageInfo(const char* const severity_, + const char* const filename_, + const int& line_number_, + const int& thread_id_, + const LogMessageTime& time_): + severity(severity_), filename(filename_), line_number(line_number_), + thread_id(thread_id_), time(time_) + {} + + const char* const severity; + const char* const filename; + const int &line_number; + const int &thread_id; + const LogMessageTime& time; +}; + +typedef void(*CustomPrefixCallback)(std::ostream& s, const LogMessageInfo& l, void* data); + +} + + +// The global value of GOOGLE_STRIP_LOG. All the messages logged to +// LOG(XXX) with severity less than GOOGLE_STRIP_LOG will not be displayed. +// If it can be determined at compile time that the message will not be +// printed, the statement will be compiled out. +// +// Example: to strip out all INFO and WARNING messages, use the value +// of 2 below. To make an exception for WARNING messages from a single +// file, add "#define GOOGLE_STRIP_LOG 1" to that file _before_ including +// base/logging.h +#ifndef GOOGLE_STRIP_LOG +#define GOOGLE_STRIP_LOG 0 +#endif + +// GCC can be told that a certain branch is not likely to be taken (for +// instance, a CHECK failure), and use that information in static analysis. +// Giving it this information can help it optimize for the common case in +// the absence of better information (ie. -fprofile-arcs). +// +#ifndef GOOGLE_PREDICT_BRANCH_NOT_TAKEN +#if 1 +#define GOOGLE_PREDICT_BRANCH_NOT_TAKEN(x) (__builtin_expect(x, 0)) +#else +#define GOOGLE_PREDICT_BRANCH_NOT_TAKEN(x) x +#endif +#endif + +#ifndef GOOGLE_PREDICT_FALSE +#if 1 +#define GOOGLE_PREDICT_FALSE(x) (__builtin_expect(x, 0)) +#else +#define GOOGLE_PREDICT_FALSE(x) x +#endif +#endif + +#ifndef GOOGLE_PREDICT_TRUE +#if 1 +#define GOOGLE_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1)) +#else +#define GOOGLE_PREDICT_TRUE(x) x +#endif +#endif + + +// Make a bunch of macros for logging. The way to log things is to stream +// things to LOG(). E.g., +// +// LOG(INFO) << "Found " << num_cookies << " cookies"; +// +// You can capture log messages in a string, rather than reporting them +// immediately: +// +// vector errors; +// LOG_STRING(ERROR, &errors) << "Couldn't parse cookie #" << cookie_num; +// +// This pushes back the new error onto 'errors'; if given a NULL pointer, +// it reports the error via LOG(ERROR). +// +// You can also do conditional logging: +// +// LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies"; +// +// You can also do occasional logging (log every n'th occurrence of an +// event): +// +// LOG_EVERY_N(INFO, 10) << "Got the " << google::COUNTER << "th cookie"; +// +// The above will cause log messages to be output on the 1st, 11th, 21st, ... +// times it is executed. Note that the special google::COUNTER value is used +// to identify which repetition is happening. +// +// You can also do occasional conditional logging (log every n'th +// occurrence of an event, when condition is satisfied): +// +// LOG_IF_EVERY_N(INFO, (size > 1024), 10) << "Got the " << google::COUNTER +// << "th big cookie"; +// +// You can log messages the first N times your code executes a line. E.g. +// +// LOG_FIRST_N(INFO, 20) << "Got the " << google::COUNTER << "th cookie"; +// +// Outputs log messages for the first 20 times it is executed. +// +// Analogous SYSLOG, SYSLOG_IF, and SYSLOG_EVERY_N macros are available. +// These log to syslog as well as to the normal logs. If you use these at +// all, you need to be aware that syslog can drastically reduce performance, +// especially if it is configured for remote logging! Don't use these +// unless you fully understand this and have a concrete need to use them. +// Even then, try to minimize your use of them. +// +// There are also "debug mode" logging macros like the ones above: +// +// DLOG(INFO) << "Found cookies"; +// +// DLOG_IF(INFO, num_cookies > 10) << "Got lots of cookies"; +// +// DLOG_EVERY_N(INFO, 10) << "Got the " << google::COUNTER << "th cookie"; +// +// All "debug mode" logging is compiled away to nothing for non-debug mode +// compiles. +// +// We also have +// +// LOG_ASSERT(assertion); +// DLOG_ASSERT(assertion); +// +// which is syntactic sugar for {,D}LOG_IF(FATAL, assert fails) << assertion; +// +// There are "verbose level" logging macros. They look like +// +// VLOG(1) << "I'm printed when you run the program with --v=1 or more"; +// VLOG(2) << "I'm printed when you run the program with --v=2 or more"; +// +// These always log at the INFO log level (when they log at all). +// The verbose logging can also be turned on module-by-module. For instance, +// --vmodule=mapreduce=2,file=1,gfs*=3 --v=0 +// will cause: +// a. VLOG(2) and lower messages to be printed from mapreduce.{h,cc} +// b. VLOG(1) and lower messages to be printed from file.{h,cc} +// c. VLOG(3) and lower messages to be printed from files prefixed with "gfs" +// d. VLOG(0) and lower messages to be printed from elsewhere +// +// The wildcarding functionality shown by (c) supports both '*' (match +// 0 or more characters) and '?' (match any single character) wildcards. +// +// There's also VLOG_IS_ON(n) "verbose level" condition macro. To be used as +// +// if (VLOG_IS_ON(2)) { +// // do some logging preparation and logging +// // that can't be accomplished with just VLOG(2) << ...; +// } +// +// There are also VLOG_IF, VLOG_EVERY_N and VLOG_IF_EVERY_N "verbose level" +// condition macros for sample cases, when some extra computation and +// preparation for logs is not needed. +// VLOG_IF(1, (size > 1024)) +// << "I'm printed when size is more than 1024 and when you run the " +// "program with --v=1 or more"; +// VLOG_EVERY_N(1, 10) +// << "I'm printed every 10th occurrence, and when you run the program " +// "with --v=1 or more. Present occurence is " << google::COUNTER; +// VLOG_IF_EVERY_N(1, (size > 1024), 10) +// << "I'm printed on every 10th occurence of case when size is more " +// " than 1024, when you run the program with --v=1 or more. "; +// "Present occurence is " << google::COUNTER; +// +// The supported severity levels for macros that allow you to specify one +// are (in increasing order of severity) INFO, WARNING, ERROR, and FATAL. +// Note that messages of a given severity are logged not only in the +// logfile for that severity, but also in all logfiles of lower severity. +// E.g., a message of severity FATAL will be logged to the logfiles of +// severity FATAL, ERROR, WARNING, and INFO. +// +// There is also the special severity of DFATAL, which logs FATAL in +// debug mode, ERROR in normal mode. +// +// Very important: logging a message at the FATAL severity level causes +// the program to terminate (after the message is logged). +// +// Unless otherwise specified, logs will be written to the filename +// "...log..", followed +// by the date, time, and pid (you can't prevent the date, time, and pid +// from being in the filename). +// +// The logging code takes two flags: +// --v=# set the verbose level +// --logtostderr log all the messages to stderr instead of to logfiles + +// LOG LINE PREFIX FORMAT +// +// Log lines have this form: +// +// Lyyyymmdd hh:mm:ss.uuuuuu threadid file:line] msg... +// +// where the fields are defined as follows: +// +// L A single character, representing the log level +// (eg 'I' for INFO) +// yyyy The year +// mm The month (zero padded; ie May is '05') +// dd The day (zero padded) +// hh:mm:ss.uuuuuu Time in hours, minutes and fractional seconds +// threadid The space-padded thread ID as returned by GetTID() +// (this matches the PID on Linux) +// file The file name +// line The line number +// msg The user-supplied message +// +// Example: +// +// I1103 11:57:31.739339 24395 google.cc:2341] Command line: ./some_prog +// I1103 11:57:31.739403 24395 google.cc:2342] Process id 24395 +// +// NOTE: although the microseconds are useful for comparing events on +// a single machine, clocks on different machines may not be well +// synchronized. Hence, use caution when comparing the low bits of +// timestamps from different machines. + +#pragma push_macro("DECLARE_VARIABLE") +#pragma push_macro("DECLARE_bool") +#pragma push_macro("DECLARE_string") +#pragma push_macro("DECLARE_int32") +#pragma push_macro("DECLARE_uint32") + +#ifdef DECLARE_VARIABLE +#undef DECLARE_VARIABLE +#endif + +#ifdef DECLARE_bool +#undef DECLARE_bool +#endif + +#ifdef DECLARE_string +#undef DECLARE_string +#endif + +#ifdef DECLARE_int32 +#undef DECLARE_int32 +#endif + +#ifdef DECLARE_uint32 +#undef DECLARE_uint32 +#endif + +#ifndef DECLARE_VARIABLE +#define DECLARE_VARIABLE(type, shorttype, name, tn) \ + namespace fL##shorttype { \ + extern GLOG_EXPORT type FLAGS_##name; \ + } \ + using fL##shorttype::FLAGS_##name + +// bool specialization +#define DECLARE_bool(name) \ + DECLARE_VARIABLE(bool, B, name, bool) + +// int32 specialization +#define DECLARE_int32(name) \ + DECLARE_VARIABLE(google::int32, I, name, int32) + +#if !defined(DECLARE_uint32) +// uint32 specialization +#define DECLARE_uint32(name) \ + DECLARE_VARIABLE(google::uint32, U, name, uint32) +#endif // !defined(DECLARE_uint32) && !(0) + +// Special case for string, because we have to specify the namespace +// std::string, which doesn't play nicely with our FLAG__namespace hackery. +#define DECLARE_string(name) \ + namespace fLS { \ + extern GLOG_EXPORT std::string& FLAGS_##name; \ + } \ + using fLS::FLAGS_##name +#endif + +// Set whether appending a timestamp to the log file name +DECLARE_bool(timestamp_in_logfile_name); + +// Set whether log messages go to stdout instead of logfiles +DECLARE_bool(logtostdout); + +// Set color messages logged to stdout (if supported by terminal). +DECLARE_bool(colorlogtostdout); + +// Set whether log messages go to stderr instead of logfiles +DECLARE_bool(logtostderr); + +// Set whether log messages go to stderr in addition to logfiles. +DECLARE_bool(alsologtostderr); + +// Set color messages logged to stderr (if supported by terminal). +DECLARE_bool(colorlogtostderr); + +// Log messages at a level >= this flag are automatically sent to +// stderr in addition to log files. +DECLARE_int32(stderrthreshold); + +// Set whether the log file header should be written upon creating a file. +DECLARE_bool(log_file_header); + +// Set whether the log prefix should be prepended to each line of output. +DECLARE_bool(log_prefix); + +// Set whether the year should be included in the log prefix. +DECLARE_bool(log_year_in_prefix); + +// Log messages at a level <= this flag are buffered. +// Log messages at a higher level are flushed immediately. +DECLARE_int32(logbuflevel); + +// Sets the maximum number of seconds which logs may be buffered for. +DECLARE_int32(logbufsecs); + +// Log suppression level: messages logged at a lower level than this +// are suppressed. +DECLARE_int32(minloglevel); + +// If specified, logfiles are written into this directory instead of the +// default logging directory. +DECLARE_string(log_dir); + +// Set the log file mode. +DECLARE_int32(logfile_mode); + +// Sets the path of the directory into which to put additional links +// to the log files. +DECLARE_string(log_link); + +DECLARE_int32(v); // in vlog_is_on.cc + +DECLARE_string(vmodule); // also in vlog_is_on.cc + +// Sets the maximum log file size (in MB). +DECLARE_uint32(max_log_size); + +// Sets whether to avoid logging to the disk if the disk is full. +DECLARE_bool(stop_logging_if_full_disk); + +// Use UTC time for logging +DECLARE_bool(log_utc_time); + +// Log messages below the GOOGLE_STRIP_LOG level will be compiled away for +// security reasons. See LOG(severtiy) below. + +// A few definitions of macros that don't generate much code. Since +// LOG(INFO) and its ilk are used all over our code, it's +// better to have compact code for these operations. + +#if GOOGLE_STRIP_LOG == 0 +#define COMPACT_GOOGLE_LOG_INFO google::LogMessage( \ + __FILE__, __LINE__) +#define LOG_TO_STRING_INFO(message) google::LogMessage( \ + __FILE__, __LINE__, google::GLOG_INFO, message) +#else +#define COMPACT_GOOGLE_LOG_INFO google::NullStream() +#define LOG_TO_STRING_INFO(message) google::NullStream() +#endif + +#if GOOGLE_STRIP_LOG <= 1 +#define COMPACT_GOOGLE_LOG_WARNING google::LogMessage( \ + __FILE__, __LINE__, google::GLOG_WARNING) +#define LOG_TO_STRING_WARNING(message) google::LogMessage( \ + __FILE__, __LINE__, google::GLOG_WARNING, message) +#else +#define COMPACT_GOOGLE_LOG_WARNING google::NullStream() +#define LOG_TO_STRING_WARNING(message) google::NullStream() +#endif + +#if GOOGLE_STRIP_LOG <= 2 +#define COMPACT_GOOGLE_LOG_ERROR google::LogMessage( \ + __FILE__, __LINE__, google::GLOG_ERROR) +#define LOG_TO_STRING_ERROR(message) google::LogMessage( \ + __FILE__, __LINE__, google::GLOG_ERROR, message) +#else +#define COMPACT_GOOGLE_LOG_ERROR google::NullStream() +#define LOG_TO_STRING_ERROR(message) google::NullStream() +#endif + +#if GOOGLE_STRIP_LOG <= 3 +#define COMPACT_GOOGLE_LOG_FATAL google::LogMessageFatal( \ + __FILE__, __LINE__) +#define LOG_TO_STRING_FATAL(message) google::LogMessage( \ + __FILE__, __LINE__, google::GLOG_FATAL, message) +#else +#define COMPACT_GOOGLE_LOG_FATAL google::NullStreamFatal() +#define LOG_TO_STRING_FATAL(message) google::NullStreamFatal() +#endif + +#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON) +#define DCHECK_IS_ON() 0 +#else +#define DCHECK_IS_ON() 1 +#endif + +// For DFATAL, we want to use LogMessage (as opposed to +// LogMessageFatal), to be consistent with the original behavior. +#if !DCHECK_IS_ON() +#define COMPACT_GOOGLE_LOG_DFATAL COMPACT_GOOGLE_LOG_ERROR +#elif GOOGLE_STRIP_LOG <= 3 +#define COMPACT_GOOGLE_LOG_DFATAL google::LogMessage( \ + __FILE__, __LINE__, google::GLOG_FATAL) +#else +#define COMPACT_GOOGLE_LOG_DFATAL google::NullStreamFatal() +#endif + +#define GOOGLE_LOG_INFO(counter) google::LogMessage(__FILE__, __LINE__, google::GLOG_INFO, counter, &google::LogMessage::SendToLog) +#define SYSLOG_INFO(counter) \ + google::LogMessage(__FILE__, __LINE__, google::GLOG_INFO, counter, \ + &google::LogMessage::SendToSyslogAndLog) +#define GOOGLE_LOG_WARNING(counter) \ + google::LogMessage(__FILE__, __LINE__, google::GLOG_WARNING, counter, \ + &google::LogMessage::SendToLog) +#define SYSLOG_WARNING(counter) \ + google::LogMessage(__FILE__, __LINE__, google::GLOG_WARNING, counter, \ + &google::LogMessage::SendToSyslogAndLog) +#define GOOGLE_LOG_ERROR(counter) \ + google::LogMessage(__FILE__, __LINE__, google::GLOG_ERROR, counter, \ + &google::LogMessage::SendToLog) +#define SYSLOG_ERROR(counter) \ + google::LogMessage(__FILE__, __LINE__, google::GLOG_ERROR, counter, \ + &google::LogMessage::SendToSyslogAndLog) +#define GOOGLE_LOG_FATAL(counter) \ + google::LogMessage(__FILE__, __LINE__, google::GLOG_FATAL, counter, \ + &google::LogMessage::SendToLog) +#define SYSLOG_FATAL(counter) \ + google::LogMessage(__FILE__, __LINE__, google::GLOG_FATAL, counter, \ + &google::LogMessage::SendToSyslogAndLog) +#define GOOGLE_LOG_DFATAL(counter) \ + google::LogMessage(__FILE__, __LINE__, google::DFATAL_LEVEL, counter, \ + &google::LogMessage::SendToLog) +#define SYSLOG_DFATAL(counter) \ + google::LogMessage(__FILE__, __LINE__, google::DFATAL_LEVEL, counter, \ + &google::LogMessage::SendToSyslogAndLog) + +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) || defined(__CYGWIN32__) +// A very useful logging macro to log windows errors: +#define LOG_SYSRESULT(result) \ + if (FAILED(HRESULT_FROM_WIN32(result))) { \ + LPSTR message = NULL; \ + LPSTR msg = reinterpret_cast(&message); \ + DWORD message_length = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | \ + FORMAT_MESSAGE_FROM_SYSTEM | \ + FORMAT_MESSAGE_IGNORE_INSERTS, \ + 0, result, 0, msg, 100, NULL); \ + if (message_length > 0) { \ + google::LogMessage(__FILE__, __LINE__, google::GLOG_ERROR, 0, \ + &google::LogMessage::SendToLog).stream() \ + << reinterpret_cast(message); \ + LocalFree(message); \ + } \ + } +#endif + +// We use the preprocessor's merging operator, "##", so that, e.g., +// LOG(INFO) becomes the token GOOGLE_LOG_INFO. There's some funny +// subtle difference between ostream member streaming functions (e.g., +// ostream::operator<<(int) and ostream non-member streaming functions +// (e.g., ::operator<<(ostream&, string&): it turns out that it's +// impossible to stream something like a string directly to an unnamed +// ostream. We employ a neat hack by calling the stream() member +// function of LogMessage which seems to avoid the problem. +#define LOG(severity) COMPACT_GOOGLE_LOG_ ## severity.stream() +#define SYSLOG(severity) SYSLOG_ ## severity(0).stream() + +namespace google { + +// They need the definitions of integer types. +#include +#include + +// Initialize google's logging library. You will see the program name +// specified by argv0 in log outputs. +GLOG_EXPORT void InitGoogleLogging(const char* argv0); + +GLOG_EXPORT void InitGoogleLogging(const char* argv0, + CustomPrefixCallback prefix_callback, + void* prefix_callback_data = NULL); + +// Check if google's logging library has been initialized. +GLOG_EXPORT bool IsGoogleLoggingInitialized(); + +// Shutdown google's logging library. +GLOG_EXPORT void ShutdownGoogleLogging(); + +#if defined(__GNUC__) +typedef void (*logging_fail_func_t)() __attribute__((noreturn)); +#else +typedef void (*logging_fail_func_t)(); +#endif + +// Install a function which will be called after LOG(FATAL). +GLOG_EXPORT void InstallFailureFunction(logging_fail_func_t fail_func); + +// Enable/Disable old log cleaner. +GLOG_EXPORT void EnableLogCleaner(unsigned int overdue_days); +GLOG_EXPORT void DisableLogCleaner(); +GLOG_EXPORT void SetApplicationFingerprint(const std::string& fingerprint); + +class LogSink; // defined below + +// If a non-NULL sink pointer is given, we push this message to that sink. +// For LOG_TO_SINK we then do normal LOG(severity) logging as well. +// This is useful for capturing messages and passing/storing them +// somewhere more specific than the global log of the process. +// Argument types: +// LogSink* sink; +// LogSeverity severity; +// The cast is to disambiguate NULL arguments. +#define LOG_TO_SINK(sink, severity) \ + google::LogMessage( \ + __FILE__, __LINE__, \ + google::GLOG_ ## severity, \ + static_cast(sink), true).stream() +#define LOG_TO_SINK_BUT_NOT_TO_LOGFILE(sink, severity) \ + google::LogMessage( \ + __FILE__, __LINE__, \ + google::GLOG_ ## severity, \ + static_cast(sink), false).stream() + +// If a non-NULL string pointer is given, we write this message to that string. +// We then do normal LOG(severity) logging as well. +// This is useful for capturing messages and storing them somewhere more +// specific than the global log of the process. +// Argument types: +// string* message; +// LogSeverity severity; +// The cast is to disambiguate NULL arguments. +// NOTE: LOG(severity) expands to LogMessage().stream() for the specified +// severity. +#define LOG_TO_STRING(severity, message) \ + LOG_TO_STRING_##severity(static_cast(message)).stream() + +// If a non-NULL pointer is given, we push the message onto the end +// of a vector of strings; otherwise, we report it with LOG(severity). +// This is handy for capturing messages and perhaps passing them back +// to the caller, rather than reporting them immediately. +// Argument types: +// LogSeverity severity; +// vector *outvec; +// The cast is to disambiguate NULL arguments. +#define LOG_STRING(severity, outvec) \ + LOG_TO_STRING_##severity(static_cast*>(outvec)).stream() + +#define LOG_IF(severity, condition) \ + static_cast(0), \ + !(condition) ? (void) 0 : google::LogMessageVoidify() & LOG(severity) +#define SYSLOG_IF(severity, condition) \ + static_cast(0), \ + !(condition) ? (void) 0 : google::LogMessageVoidify() & SYSLOG(severity) + +#define LOG_ASSERT(condition) \ + LOG_IF(FATAL, !(condition)) << "Assert failed: " #condition +#define SYSLOG_ASSERT(condition) \ + SYSLOG_IF(FATAL, !(condition)) << "Assert failed: " #condition + +// CHECK dies with a fatal error if condition is not true. It is *not* +// controlled by DCHECK_IS_ON(), so the check will be executed regardless of +// compilation mode. Therefore, it is safe to do things like: +// CHECK(fp->Write(x) == 4) +#define CHECK(condition) \ + LOG_IF(FATAL, GOOGLE_PREDICT_BRANCH_NOT_TAKEN(!(condition))) \ + << "Check failed: " #condition " " + +// A container for a string pointer which can be evaluated to a bool - +// true iff the pointer is NULL. +struct CheckOpString { + CheckOpString(std::string* str) : str_(str) { } + // No destructor: if str_ is non-NULL, we're about to LOG(FATAL), + // so there's no point in cleaning up str_. + operator bool() const { + return GOOGLE_PREDICT_BRANCH_NOT_TAKEN(str_ != NULL); + } + std::string* str_; +}; + +// Function is overloaded for integral types to allow static const +// integrals declared in classes and not defined to be used as arguments to +// CHECK* macros. It's not encouraged though. +template +inline const T& GetReferenceableValue(const T& t) { return t; } +inline char GetReferenceableValue(char t) { return t; } +inline unsigned char GetReferenceableValue(unsigned char t) { return t; } +inline signed char GetReferenceableValue(signed char t) { return t; } +inline short GetReferenceableValue(short t) { return t; } +inline unsigned short GetReferenceableValue(unsigned short t) { return t; } +inline int GetReferenceableValue(int t) { return t; } +inline unsigned int GetReferenceableValue(unsigned int t) { return t; } +inline long GetReferenceableValue(long t) { return t; } +inline unsigned long GetReferenceableValue(unsigned long t) { return t; } +inline long long GetReferenceableValue(long long t) { return t; } +inline unsigned long long GetReferenceableValue(unsigned long long t) { + return t; +} + +// This is a dummy class to define the following operator. +struct DummyClassToDefineOperator {}; + +} + +// Define global operator<< to declare using ::operator<<. +// This declaration will allow use to use CHECK macros for user +// defined classes which have operator<< (e.g., stl_logging.h). +inline std::ostream& operator<<( + std::ostream& out, const google::DummyClassToDefineOperator&) { + return out; +} + +namespace google { + +// This formats a value for a failing CHECK_XX statement. Ordinarily, +// it uses the definition for operator<<, with a few special cases below. +template +inline void MakeCheckOpValueString(std::ostream* os, const T& v) { + (*os) << v; +} + +// Overrides for char types provide readable values for unprintable +// characters. +template <> GLOG_EXPORT +void MakeCheckOpValueString(std::ostream* os, const char& v); +template <> GLOG_EXPORT +void MakeCheckOpValueString(std::ostream* os, const signed char& v); +template <> GLOG_EXPORT +void MakeCheckOpValueString(std::ostream* os, const unsigned char& v); + +// Provide printable value for nullptr_t +template <> +GLOG_EXPORT void MakeCheckOpValueString(std::ostream* os, + const std::nullptr_t& v); + +// Build the error message string. Specify no inlining for code size. +template +std::string* MakeCheckOpString(const T1& v1, const T2& v2, const char* exprtext) + __attribute__((noinline)); + +namespace base { +namespace internal { + +// If "s" is less than base_logging::INFO, returns base_logging::INFO. +// If "s" is greater than base_logging::FATAL, returns +// base_logging::ERROR. Otherwise, returns "s". +LogSeverity NormalizeSeverity(LogSeverity s); + +} // namespace internal + +// A helper class for formatting "expr (V1 vs. V2)" in a CHECK_XX +// statement. See MakeCheckOpString for sample usage. Other +// approaches were considered: use of a template method (e.g., +// base::BuildCheckOpString(exprtext, base::Print, &v1, +// base::Print, &v2), however this approach has complications +// related to volatile arguments and function-pointer arguments). +class GLOG_EXPORT CheckOpMessageBuilder { + public: + // Inserts "exprtext" and " (" to the stream. + explicit CheckOpMessageBuilder(const char *exprtext); + // Deletes "stream_". + ~CheckOpMessageBuilder(); + // For inserting the first variable. + std::ostream* ForVar1() { return stream_; } + // For inserting the second variable (adds an intermediate " vs. "). + std::ostream* ForVar2(); + // Get the result (inserts the closing ")"). + std::string* NewString(); + + private: + std::ostringstream *stream_; +}; + +} // namespace base + +template +std::string* MakeCheckOpString(const T1& v1, const T2& v2, const char* exprtext) { + base::CheckOpMessageBuilder comb(exprtext); + MakeCheckOpValueString(comb.ForVar1(), v1); + MakeCheckOpValueString(comb.ForVar2(), v2); + return comb.NewString(); +} + +// Helper functions for CHECK_OP macro. +// The (int, int) specialization works around the issue that the compiler +// will not instantiate the template version of the function on values of +// unnamed enum type - see comment below. +#define DEFINE_CHECK_OP_IMPL(name, op) \ + template \ + inline std::string* name##Impl(const T1& v1, const T2& v2, \ + const char* exprtext) { \ + if (GOOGLE_PREDICT_TRUE(v1 op v2)) return NULL; \ + else return MakeCheckOpString(v1, v2, exprtext); \ + } \ + inline std::string* name##Impl(int v1, int v2, const char* exprtext) { \ + return name##Impl(v1, v2, exprtext); \ + } + +// We use the full name Check_EQ, Check_NE, etc. in case the file including +// base/logging.h provides its own #defines for the simpler names EQ, NE, etc. +// This happens if, for example, those are used as token names in a +// yacc grammar. +DEFINE_CHECK_OP_IMPL(Check_EQ, ==) // Compilation error with CHECK_EQ(NULL, x)? +DEFINE_CHECK_OP_IMPL(Check_NE, !=) // Use CHECK(x == NULL) instead. +DEFINE_CHECK_OP_IMPL(Check_LE, <=) +DEFINE_CHECK_OP_IMPL(Check_LT, < ) +DEFINE_CHECK_OP_IMPL(Check_GE, >=) +DEFINE_CHECK_OP_IMPL(Check_GT, > ) +#undef DEFINE_CHECK_OP_IMPL + +// Helper macro for binary operators. +// Don't use this macro directly in your code, use CHECK_EQ et al below. + +#if defined(STATIC_ANALYSIS) +// Only for static analysis tool to know that it is equivalent to assert +#define CHECK_OP_LOG(name, op, val1, val2, log) CHECK((val1) op (val2)) +#elif DCHECK_IS_ON() +// In debug mode, avoid constructing CheckOpStrings if possible, +// to reduce the overhead of CHECK statments by 2x. +// Real DCHECK-heavy tests have seen 1.5x speedups. + +// The meaning of "string" might be different between now and +// when this macro gets invoked (e.g., if someone is experimenting +// with other string implementations that get defined after this +// file is included). Save the current meaning now and use it +// in the macro. +typedef std::string _Check_string; +#define CHECK_OP_LOG(name, op, val1, val2, log) \ + while (google::_Check_string* _result = \ + google::Check##name##Impl( \ + google::GetReferenceableValue(val1), \ + google::GetReferenceableValue(val2), \ + #val1 " " #op " " #val2)) \ + log(__FILE__, __LINE__, \ + google::CheckOpString(_result)).stream() +#else +// In optimized mode, use CheckOpString to hint to compiler that +// the while condition is unlikely. +#define CHECK_OP_LOG(name, op, val1, val2, log) \ + while (google::CheckOpString _result = \ + google::Check##name##Impl( \ + google::GetReferenceableValue(val1), \ + google::GetReferenceableValue(val2), \ + #val1 " " #op " " #val2)) \ + log(__FILE__, __LINE__, _result).stream() +#endif // STATIC_ANALYSIS, DCHECK_IS_ON() + +#if GOOGLE_STRIP_LOG <= 3 +#define CHECK_OP(name, op, val1, val2) \ + CHECK_OP_LOG(name, op, val1, val2, google::LogMessageFatal) +#else +#define CHECK_OP(name, op, val1, val2) \ + CHECK_OP_LOG(name, op, val1, val2, google::NullStreamFatal) +#endif // STRIP_LOG <= 3 + +// Equality/Inequality checks - compare two values, and log a FATAL message +// including the two values when the result is not as expected. The values +// must have operator<<(ostream, ...) defined. +// +// You may append to the error message like so: +// CHECK_NE(1, 2) << ": The world must be ending!"; +// +// We are very careful to ensure that each argument is evaluated exactly +// once, and that anything which is legal to pass as a function argument is +// legal here. In particular, the arguments may be temporary expressions +// which will end up being destroyed at the end of the apparent statement, +// for example: +// CHECK_EQ(string("abc")[1], 'b'); +// +// WARNING: These don't compile correctly if one of the arguments is a pointer +// and the other is NULL. To work around this, simply static_cast NULL to the +// type of the desired pointer. + +#define CHECK_EQ(val1, val2) CHECK_OP(_EQ, ==, val1, val2) +#define CHECK_NE(val1, val2) CHECK_OP(_NE, !=, val1, val2) +#define CHECK_LE(val1, val2) CHECK_OP(_LE, <=, val1, val2) +#define CHECK_LT(val1, val2) CHECK_OP(_LT, < , val1, val2) +#define CHECK_GE(val1, val2) CHECK_OP(_GE, >=, val1, val2) +#define CHECK_GT(val1, val2) CHECK_OP(_GT, > , val1, val2) + +// Check that the input is non NULL. This very useful in constructor +// initializer lists. + +#define CHECK_NOTNULL(val) \ + google::CheckNotNull(__FILE__, __LINE__, "'" #val "' Must be non NULL", (val)) + +// Helper functions for string comparisons. +// To avoid bloat, the definitions are in logging.cc. +#define DECLARE_CHECK_STROP_IMPL(func, expected) \ + GLOG_EXPORT std::string* Check##func##expected##Impl( \ + const char* s1, const char* s2, const char* names); +DECLARE_CHECK_STROP_IMPL(strcmp, true) +DECLARE_CHECK_STROP_IMPL(strcmp, false) +DECLARE_CHECK_STROP_IMPL(strcasecmp, true) +DECLARE_CHECK_STROP_IMPL(strcasecmp, false) +#undef DECLARE_CHECK_STROP_IMPL + +// Helper macro for string comparisons. +// Don't use this macro directly in your code, use CHECK_STREQ et al below. +#define CHECK_STROP(func, op, expected, s1, s2) \ + while (google::CheckOpString _result = \ + google::Check##func##expected##Impl((s1), (s2), \ + #s1 " " #op " " #s2)) \ + LOG(FATAL) << *_result.str_ + + +// String (char*) equality/inequality checks. +// CASE versions are case-insensitive. +// +// Note that "s1" and "s2" may be temporary strings which are destroyed +// by the compiler at the end of the current "full expression" +// (e.g. CHECK_STREQ(Foo().c_str(), Bar().c_str())). + +#define CHECK_STREQ(s1, s2) CHECK_STROP(strcmp, ==, true, s1, s2) +#define CHECK_STRNE(s1, s2) CHECK_STROP(strcmp, !=, false, s1, s2) +#define CHECK_STRCASEEQ(s1, s2) CHECK_STROP(strcasecmp, ==, true, s1, s2) +#define CHECK_STRCASENE(s1, s2) CHECK_STROP(strcasecmp, !=, false, s1, s2) + +#define CHECK_INDEX(I,A) CHECK(I < (sizeof(A)/sizeof(A[0]))) +#define CHECK_BOUND(B,A) CHECK(B <= (sizeof(A)/sizeof(A[0]))) + +#define CHECK_DOUBLE_EQ(val1, val2) \ + do { \ + CHECK_LE((val1), (val2)+0.000000000000001L); \ + CHECK_GE((val1), (val2)-0.000000000000001L); \ + } while (0) + +#define CHECK_NEAR(val1, val2, margin) \ + do { \ + CHECK_LE((val1), (val2)+(margin)); \ + CHECK_GE((val1), (val2)-(margin)); \ + } while (0) + +// perror()..googly style! +// +// PLOG() and PLOG_IF() and PCHECK() behave exactly like their LOG* and +// CHECK equivalents with the addition that they postpend a description +// of the current state of errno to their output lines. + +#define PLOG(severity) GOOGLE_PLOG(severity, 0).stream() + +#define GOOGLE_PLOG(severity, counter) \ + google::ErrnoLogMessage( \ + __FILE__, __LINE__, google::GLOG_ ## severity, counter, \ + &google::LogMessage::SendToLog) + +#define PLOG_IF(severity, condition) \ + static_cast(0), \ + !(condition) ? (void) 0 : google::LogMessageVoidify() & PLOG(severity) + +// A CHECK() macro that postpends errno if the condition is false. E.g. +// +// if (poll(fds, nfds, timeout) == -1) { PCHECK(errno == EINTR); ... } +#define PCHECK(condition) \ + PLOG_IF(FATAL, GOOGLE_PREDICT_BRANCH_NOT_TAKEN(!(condition))) \ + << "Check failed: " #condition " " + +// A CHECK() macro that lets you assert the success of a function that +// returns -1 and sets errno in case of an error. E.g. +// +// CHECK_ERR(mkdir(path, 0700)); +// +// or +// +// int fd = open(filename, flags); CHECK_ERR(fd) << ": open " << filename; +#define CHECK_ERR(invocation) \ +PLOG_IF(FATAL, GOOGLE_PREDICT_BRANCH_NOT_TAKEN((invocation) == -1)) \ + << #invocation + +// Use macro expansion to create, for each use of LOG_EVERY_N(), static +// variables with the __LINE__ expansion as part of the variable name. +#define LOG_EVERY_N_VARNAME(base, line) LOG_EVERY_N_VARNAME_CONCAT(base, line) +#define LOG_EVERY_N_VARNAME_CONCAT(base, line) base ## line + +#define LOG_OCCURRENCES LOG_EVERY_N_VARNAME(occurrences_, __LINE__) +#define LOG_OCCURRENCES_MOD_N LOG_EVERY_N_VARNAME(occurrences_mod_n_, __LINE__) + +#define LOG_TIME_PERIOD LOG_EVERY_N_VARNAME(timePeriod_, __LINE__) +#define LOG_PREVIOUS_TIME_RAW LOG_EVERY_N_VARNAME(previousTimeRaw_, __LINE__) +#define LOG_TIME_DELTA LOG_EVERY_N_VARNAME(deltaTime_, __LINE__) +#define LOG_CURRENT_TIME LOG_EVERY_N_VARNAME(currentTime_, __LINE__) +#define LOG_PREVIOUS_TIME LOG_EVERY_N_VARNAME(previousTime_, __LINE__) + +#if defined(__has_feature) +# if __has_feature(thread_sanitizer) +# define GLOG_SANITIZE_THREAD 1 +# endif +#endif + +#if !defined(GLOG_SANITIZE_THREAD) && defined(__SANITIZE_THREAD__) && __SANITIZE_THREAD__ +# define GLOG_SANITIZE_THREAD 1 +#endif + +#if defined(GLOG_SANITIZE_THREAD) +#define GLOG_IFDEF_THREAD_SANITIZER(X) X +#else +#define GLOG_IFDEF_THREAD_SANITIZER(X) +#endif + +#if defined(GLOG_SANITIZE_THREAD) +} // namespace google + +// We need to identify the static variables as "benign" races +// to avoid noisy reports from TSAN. +extern "C" void AnnotateBenignRaceSized( + const char *file, + int line, + const volatile void *mem, + size_t size, + const char *description); + +namespace google { +#endif + +#define SOME_KIND_OF_LOG_EVERY_T(severity, seconds) \ + constexpr std::chrono::nanoseconds LOG_TIME_PERIOD = \ + std::chrono::duration_cast( \ + std::chrono::duration(seconds)); \ + static std::atomic LOG_PREVIOUS_TIME_RAW; \ + GLOG_IFDEF_THREAD_SANITIZER( \ + AnnotateBenignRaceSized(__FILE__, __LINE__, &LOG_TIME_PERIOD, \ + sizeof(@ac_google_namespace @ ::int64), "")); \ + GLOG_IFDEF_THREAD_SANITIZER( \ + AnnotateBenignRaceSized(__FILE__, __LINE__, &LOG_PREVIOUS_TIME_RAW, \ + sizeof(@ac_google_namespace @ ::int64), "")); \ + const auto LOG_CURRENT_TIME = \ + std::chrono::duration_cast( \ + std::chrono::steady_clock::now().time_since_epoch()); \ + const auto LOG_PREVIOUS_TIME = \ + LOG_PREVIOUS_TIME_RAW.load(std::memory_order_relaxed); \ + const auto LOG_TIME_DELTA = \ + LOG_CURRENT_TIME - std::chrono::nanoseconds(LOG_PREVIOUS_TIME); \ + if (LOG_TIME_DELTA > LOG_TIME_PERIOD) \ + LOG_PREVIOUS_TIME_RAW.store( \ + std::chrono::duration_cast(LOG_CURRENT_TIME) \ + .count(), \ + std::memory_order_relaxed); \ + if (LOG_TIME_DELTA > LOG_TIME_PERIOD) \ + google ::LogMessage( \ + __FILE__, __LINE__, google ::GLOG_##severity) \ + .stream() + +#define SOME_KIND_OF_LOG_EVERY_N(severity, n, what_to_do) \ + static std::atomic LOG_OCCURRENCES(0), LOG_OCCURRENCES_MOD_N(0); \ + GLOG_IFDEF_THREAD_SANITIZER(AnnotateBenignRaceSized(__FILE__, __LINE__, &LOG_OCCURRENCES, sizeof(int), "")); \ + GLOG_IFDEF_THREAD_SANITIZER(AnnotateBenignRaceSized(__FILE__, __LINE__, &LOG_OCCURRENCES_MOD_N, sizeof(int), "")); \ + ++LOG_OCCURRENCES; \ + if (++LOG_OCCURRENCES_MOD_N > n) LOG_OCCURRENCES_MOD_N -= n; \ + if (LOG_OCCURRENCES_MOD_N == 1) \ + google::LogMessage( \ + __FILE__, __LINE__, google::GLOG_ ## severity, LOG_OCCURRENCES, \ + &what_to_do).stream() + +#define SOME_KIND_OF_LOG_IF_EVERY_N(severity, condition, n, what_to_do) \ + static std::atomic LOG_OCCURRENCES(0), LOG_OCCURRENCES_MOD_N(0); \ + GLOG_IFDEF_THREAD_SANITIZER(AnnotateBenignRaceSized(__FILE__, __LINE__, &LOG_OCCURRENCES, sizeof(int), "")); \ + GLOG_IFDEF_THREAD_SANITIZER(AnnotateBenignRaceSized(__FILE__, __LINE__, &LOG_OCCURRENCES_MOD_N, sizeof(int), "")); \ + ++LOG_OCCURRENCES; \ + if ((condition) && \ + ((LOG_OCCURRENCES_MOD_N=(LOG_OCCURRENCES_MOD_N + 1) % n) == (1 % n))) \ + google::LogMessage( \ + __FILE__, __LINE__, google::GLOG_ ## severity, LOG_OCCURRENCES, \ + &what_to_do).stream() + +#define SOME_KIND_OF_PLOG_EVERY_N(severity, n, what_to_do) \ + static std::atomic LOG_OCCURRENCES(0), LOG_OCCURRENCES_MOD_N(0); \ + GLOG_IFDEF_THREAD_SANITIZER(AnnotateBenignRaceSized(__FILE__, __LINE__, &LOG_OCCURRENCES, sizeof(int), "")); \ + GLOG_IFDEF_THREAD_SANITIZER(AnnotateBenignRaceSized(__FILE__, __LINE__, &LOG_OCCURRENCES_MOD_N, sizeof(int), "")); \ + ++LOG_OCCURRENCES; \ + if (++LOG_OCCURRENCES_MOD_N > n) LOG_OCCURRENCES_MOD_N -= n; \ + if (LOG_OCCURRENCES_MOD_N == 1) \ + google::ErrnoLogMessage( \ + __FILE__, __LINE__, google::GLOG_ ## severity, LOG_OCCURRENCES, \ + &what_to_do).stream() + +#define SOME_KIND_OF_LOG_FIRST_N(severity, n, what_to_do) \ + static std::atomic LOG_OCCURRENCES(0); \ + GLOG_IFDEF_THREAD_SANITIZER(AnnotateBenignRaceSized(__FILE__, __LINE__, &LOG_OCCURRENCES, sizeof(int), "")); \ + if (LOG_OCCURRENCES <= n) \ + ++LOG_OCCURRENCES; \ + if (LOG_OCCURRENCES <= n) \ + google::LogMessage( \ + __FILE__, __LINE__, google::GLOG_ ## severity, LOG_OCCURRENCES, \ + &what_to_do).stream() + +namespace glog_internal_namespace_ { +template +struct CompileAssert { +}; +struct CrashReason; + +// Returns true if FailureSignalHandler is installed. +// Needs to be exported since it's used by the signalhandler_unittest. +GLOG_EXPORT bool IsFailureSignalHandlerInstalled(); +} // namespace glog_internal_namespace_ + +#define LOG_EVERY_N(severity, n) \ + SOME_KIND_OF_LOG_EVERY_N(severity, (n), google::LogMessage::SendToLog) + +#define LOG_EVERY_T(severity, T) SOME_KIND_OF_LOG_EVERY_T(severity, (T)) + +#define SYSLOG_EVERY_N(severity, n) \ + SOME_KIND_OF_LOG_EVERY_N(severity, (n), google::LogMessage::SendToSyslogAndLog) + +#define PLOG_EVERY_N(severity, n) \ + SOME_KIND_OF_PLOG_EVERY_N(severity, (n), google::LogMessage::SendToLog) + +#define LOG_FIRST_N(severity, n) \ + SOME_KIND_OF_LOG_FIRST_N(severity, (n), google::LogMessage::SendToLog) + +#define LOG_IF_EVERY_N(severity, condition, n) \ + SOME_KIND_OF_LOG_IF_EVERY_N(severity, (condition), (n), google::LogMessage::SendToLog) + +// We want the special COUNTER value available for LOG_EVERY_X()'ed messages +enum PRIVATE_Counter {COUNTER}; + +#ifdef GLOG_NO_ABBREVIATED_SEVERITIES +// wingdi.h defines ERROR to be 0. When we call LOG(ERROR), it gets +// substituted with 0, and it expands to COMPACT_GOOGLE_LOG_0. To allow us +// to keep using this syntax, we define this macro to do the same thing +// as COMPACT_GOOGLE_LOG_ERROR. +#define COMPACT_GOOGLE_LOG_0 COMPACT_GOOGLE_LOG_ERROR +#define SYSLOG_0 SYSLOG_ERROR +#define LOG_TO_STRING_0 LOG_TO_STRING_ERROR +// Needed for LOG_IS_ON(ERROR). +const LogSeverity GLOG_0 = GLOG_ERROR; +#else +// Users may include windows.h after logging.h without +// GLOG_NO_ABBREVIATED_SEVERITIES nor WIN32_LEAN_AND_MEAN. +// For this case, we cannot detect if ERROR is defined before users +// actually use ERROR. Let's make an undefined symbol to warn users. +# define GLOG_ERROR_MSG ERROR_macro_is_defined_Define_GLOG_NO_ABBREVIATED_SEVERITIES_before_including_logging_h_See_the_document_for_detail +# define COMPACT_GOOGLE_LOG_0 GLOG_ERROR_MSG +# define SYSLOG_0 GLOG_ERROR_MSG +# define LOG_TO_STRING_0 GLOG_ERROR_MSG +# define GLOG_0 GLOG_ERROR_MSG +#endif + +// Plus some debug-logging macros that get compiled to nothing for production + +#if DCHECK_IS_ON() + +#define DLOG(severity) LOG(severity) +#define DVLOG(verboselevel) VLOG(verboselevel) +#define DLOG_IF(severity, condition) LOG_IF(severity, condition) +#define DLOG_EVERY_N(severity, n) LOG_EVERY_N(severity, n) +#define DLOG_IF_EVERY_N(severity, condition, n) \ + LOG_IF_EVERY_N(severity, condition, n) +#define DLOG_ASSERT(condition) LOG_ASSERT(condition) + +// debug-only checking. executed if DCHECK_IS_ON(). +#define DCHECK(condition) CHECK(condition) +#define DCHECK_EQ(val1, val2) CHECK_EQ(val1, val2) +#define DCHECK_NE(val1, val2) CHECK_NE(val1, val2) +#define DCHECK_LE(val1, val2) CHECK_LE(val1, val2) +#define DCHECK_LT(val1, val2) CHECK_LT(val1, val2) +#define DCHECK_GE(val1, val2) CHECK_GE(val1, val2) +#define DCHECK_GT(val1, val2) CHECK_GT(val1, val2) +#define DCHECK_NOTNULL(val) CHECK_NOTNULL(val) +#define DCHECK_STREQ(str1, str2) CHECK_STREQ(str1, str2) +#define DCHECK_STRCASEEQ(str1, str2) CHECK_STRCASEEQ(str1, str2) +#define DCHECK_STRNE(str1, str2) CHECK_STRNE(str1, str2) +#define DCHECK_STRCASENE(str1, str2) CHECK_STRCASENE(str1, str2) + +#else // !DCHECK_IS_ON() + +#define DLOG(severity) \ + static_cast(0), \ + true ? (void) 0 : google::LogMessageVoidify() & LOG(severity) + +#define DVLOG(verboselevel) \ + static_cast(0), \ + (true || !VLOG_IS_ON(verboselevel)) ? \ + (void) 0 : google::LogMessageVoidify() & LOG(INFO) + +#define DLOG_IF(severity, condition) \ + static_cast(0), \ + (true || !(condition)) ? (void) 0 : google::LogMessageVoidify() & LOG(severity) + +#define DLOG_EVERY_N(severity, n) \ + static_cast(0), \ + true ? (void) 0 : google::LogMessageVoidify() & LOG(severity) + +#define DLOG_IF_EVERY_N(severity, condition, n) \ + static_cast(0), \ + (true || !(condition))? (void) 0 : google::LogMessageVoidify() & LOG(severity) + +#define DLOG_ASSERT(condition) \ + static_cast(0), \ + true ? (void) 0 : LOG_ASSERT(condition) + +// MSVC warning C4127: conditional expression is constant +#define DCHECK(condition) \ + GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ + while (false) \ + GLOG_MSVC_POP_WARNING() CHECK(condition) + +#define DCHECK_EQ(val1, val2) \ + GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ + while (false) \ + GLOG_MSVC_POP_WARNING() CHECK_EQ(val1, val2) + +#define DCHECK_NE(val1, val2) \ + GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ + while (false) \ + GLOG_MSVC_POP_WARNING() CHECK_NE(val1, val2) + +#define DCHECK_LE(val1, val2) \ + GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ + while (false) \ + GLOG_MSVC_POP_WARNING() CHECK_LE(val1, val2) + +#define DCHECK_LT(val1, val2) \ + GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ + while (false) \ + GLOG_MSVC_POP_WARNING() CHECK_LT(val1, val2) + +#define DCHECK_GE(val1, val2) \ + GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ + while (false) \ + GLOG_MSVC_POP_WARNING() CHECK_GE(val1, val2) + +#define DCHECK_GT(val1, val2) \ + GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ + while (false) \ + GLOG_MSVC_POP_WARNING() CHECK_GT(val1, val2) + +// You may see warnings in release mode if you don't use the return +// value of DCHECK_NOTNULL. Please just use DCHECK for such cases. +#define DCHECK_NOTNULL(val) (val) + +#define DCHECK_STREQ(str1, str2) \ + GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ + while (false) \ + GLOG_MSVC_POP_WARNING() CHECK_STREQ(str1, str2) + +#define DCHECK_STRCASEEQ(str1, str2) \ + GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ + while (false) \ + GLOG_MSVC_POP_WARNING() CHECK_STRCASEEQ(str1, str2) + +#define DCHECK_STRNE(str1, str2) \ + GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ + while (false) \ + GLOG_MSVC_POP_WARNING() CHECK_STRNE(str1, str2) + +#define DCHECK_STRCASENE(str1, str2) \ + GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ + while (false) \ + GLOG_MSVC_POP_WARNING() CHECK_STRCASENE(str1, str2) + +#endif // DCHECK_IS_ON() + +// Log only in verbose mode. + +#define VLOG(verboselevel) LOG_IF(INFO, VLOG_IS_ON(verboselevel)) + +#define VLOG_IF(verboselevel, condition) \ + LOG_IF(INFO, (condition) && VLOG_IS_ON(verboselevel)) + +#define VLOG_EVERY_N(verboselevel, n) \ + LOG_IF_EVERY_N(INFO, VLOG_IS_ON(verboselevel), n) + +#define VLOG_IF_EVERY_N(verboselevel, condition, n) \ + LOG_IF_EVERY_N(INFO, (condition) && VLOG_IS_ON(verboselevel), n) + +namespace base_logging { + +// LogMessage::LogStream is a std::ostream backed by this streambuf. +// This class ignores overflow and leaves two bytes at the end of the +// buffer to allow for a '\n' and '\0'. +class GLOG_EXPORT LogStreamBuf : public std::streambuf { + public: + // REQUIREMENTS: "len" must be >= 2 to account for the '\n' and '\0'. + LogStreamBuf(char *buf, int len) { + setp(buf, buf + len - 2); + } + + // This effectively ignores overflow. + int_type overflow(int_type ch) { + return ch; + } + + // Legacy public ostrstream method. + size_t pcount() const { return static_cast(pptr() - pbase()); } + char* pbase() const { return std::streambuf::pbase(); } +}; + +} // namespace base_logging + +// +// This class more or less represents a particular log message. You +// create an instance of LogMessage and then stream stuff to it. +// When you finish streaming to it, ~LogMessage is called and the +// full message gets streamed to the appropriate destination. +// +// You shouldn't actually use LogMessage's constructor to log things, +// though. You should use the LOG() macro (and variants thereof) +// above. +class GLOG_EXPORT LogMessage { +public: + enum { + // Passing kNoLogPrefix for the line number disables the + // log-message prefix. Useful for using the LogMessage + // infrastructure as a printing utility. See also the --log_prefix + // flag for controlling the log-message prefix on an + // application-wide basis. + kNoLogPrefix = -1 + }; + + // LogStream inherit from non-DLL-exported class (std::ostrstream) + // and VC++ produces a warning for this situation. + // However, MSDN says "C4275 can be ignored in Microsoft Visual C++ + // 2005 if you are deriving from a type in the Standard C++ Library" + // http://msdn.microsoft.com/en-us/library/3tdb471s(VS.80).aspx + // Let's just ignore the warning. +GLOG_MSVC_PUSH_DISABLE_WARNING(4275) + class GLOG_EXPORT LogStream : public std::ostream { +GLOG_MSVC_POP_WARNING() + public: + LogStream(char *buf, int len, int64 ctr) + : std::ostream(NULL), + streambuf_(buf, len), + ctr_(ctr), + self_(this) { + rdbuf(&streambuf_); + } + + int64 ctr() const { return ctr_; } + void set_ctr(int64 ctr) { ctr_ = ctr; } + LogStream* self() const { return self_; } + + // Legacy std::streambuf methods. + size_t pcount() const { return streambuf_.pcount(); } + char* pbase() const { return streambuf_.pbase(); } + char* str() const { return pbase(); } + + private: + LogStream(const LogStream&); + LogStream& operator=(const LogStream&); + base_logging::LogStreamBuf streambuf_; + int64 ctr_; // Counter hack (for the LOG_EVERY_X() macro) + LogStream *self_; // Consistency check hack + }; + +public: + // icc 8 requires this typedef to avoid an internal compiler error. + typedef void (LogMessage::*SendMethod)(); + + LogMessage(const char* file, int line, LogSeverity severity, int64 ctr, + SendMethod send_method); + + // Two special constructors that generate reduced amounts of code at + // LOG call sites for common cases. + + // Used for LOG(INFO): Implied are: + // severity = INFO, ctr = 0, send_method = &LogMessage::SendToLog. + // + // Using this constructor instead of the more complex constructor above + // saves 19 bytes per call site. + LogMessage(const char* file, int line); + + // Used for LOG(severity) where severity != INFO. Implied + // are: ctr = 0, send_method = &LogMessage::SendToLog + // + // Using this constructor instead of the more complex constructor above + // saves 17 bytes per call site. + LogMessage(const char* file, int line, LogSeverity severity); + + // Constructor to log this message to a specified sink (if not NULL). + // Implied are: ctr = 0, send_method = &LogMessage::SendToSinkAndLog if + // also_send_to_log is true, send_method = &LogMessage::SendToSink otherwise. + LogMessage(const char* file, int line, LogSeverity severity, LogSink* sink, + bool also_send_to_log); + + // Constructor where we also give a vector pointer + // for storing the messages (if the pointer is not NULL). + // Implied are: ctr = 0, send_method = &LogMessage::SaveOrSendToLog. + LogMessage(const char* file, int line, LogSeverity severity, + std::vector* outvec); + + // Constructor where we also give a string pointer for storing the + // message (if the pointer is not NULL). Implied are: ctr = 0, + // send_method = &LogMessage::WriteToStringAndLog. + LogMessage(const char* file, int line, LogSeverity severity, + std::string* message); + + // A special constructor used for check failures + LogMessage(const char* file, int line, const CheckOpString& result); + + ~LogMessage(); + + // Flush a buffered message to the sink set in the constructor. Always + // called by the destructor, it may also be called from elsewhere if + // needed. Only the first call is actioned; any later ones are ignored. + void Flush(); + + // An arbitrary limit on the length of a single log message. This + // is so that streaming can be done more efficiently. + static const size_t kMaxLogMessageLen; + + // Theses should not be called directly outside of logging.*, + // only passed as SendMethod arguments to other LogMessage methods: + void SendToLog(); // Actually dispatch to the logs + void SendToSyslogAndLog(); // Actually dispatch to syslog and the logs + + // Call abort() or similar to perform LOG(FATAL) crash. + [[noreturn]] static void Fail(); + + std::ostream& stream(); + + int preserved_errno() const; + + // Must be called without the log_mutex held. (L < log_mutex) + static int64 num_messages(int severity); + + const LogMessageTime& getLogMessageTime() const; + + struct LogMessageData; + +private: + // Fully internal SendMethod cases: + void SendToSinkAndLog(); // Send to sink if provided and dispatch to the logs + void SendToSink(); // Send to sink if provided, do nothing otherwise. + + // Write to string if provided and dispatch to the logs. + void WriteToStringAndLog(); + + void SaveOrSendToLog(); // Save to stringvec if provided, else to logs + + void Init(const char* file, int line, LogSeverity severity, + void (LogMessage::*send_method)()); + + // Used to fill in crash information during LOG(FATAL) failures. + void RecordCrashReason(glog_internal_namespace_::CrashReason* reason); + + // Counts of messages sent at each priority: + static int64 num_messages_[NUM_SEVERITIES]; // under log_mutex + + // We keep the data in a separate struct so that each instance of + // LogMessage uses less stack space. + LogMessageData* allocated_; + LogMessageData* data_; + LogMessageTime logmsgtime_; + + friend class LogDestination; + + LogMessage(const LogMessage&); + void operator=(const LogMessage&); +}; + +// This class happens to be thread-hostile because all instances share +// a single data buffer, but since it can only be created just before +// the process dies, we don't worry so much. +class GLOG_EXPORT LogMessageFatal : public LogMessage { + public: + LogMessageFatal(const char* file, int line); + LogMessageFatal(const char* file, int line, const CheckOpString& result); + [[noreturn]] ~LogMessageFatal(); +}; + +// A non-macro interface to the log facility; (useful +// when the logging level is not a compile-time constant). +inline void LogAtLevel(int const severity, std::string const &msg) { + LogMessage(__FILE__, __LINE__, severity).stream() << msg; +} + +// A macro alternative of LogAtLevel. New code may want to use this +// version since there are two advantages: 1. this version outputs the +// file name and the line number where this macro is put like other +// LOG macros, 2. this macro can be used as C++ stream. +#define LOG_AT_LEVEL(severity) google::LogMessage(__FILE__, __LINE__, severity).stream() + +// Helper for CHECK_NOTNULL(). +// +// In C++11, all cases can be handled by a single function. Since the value +// category of the argument is preserved (also for rvalue references), +// member initializer lists like the one below will compile correctly: +// +// Foo() +// : x_(CHECK_NOTNULL(MethodReturningUniquePtr())) {} +template +T CheckNotNull(const char* file, int line, const char* names, T&& t) { + if (t == nullptr) { + LogMessageFatal(file, line, new std::string(names)); + } + return std::forward(t); +} + +// Allow folks to put a counter in the LOG_EVERY_X()'ed messages. This +// only works if ostream is a LogStream. If the ostream is not a +// LogStream you'll get an assert saying as much at runtime. +GLOG_EXPORT std::ostream& operator<<(std::ostream &os, + const PRIVATE_Counter&); + + +// Derived class for PLOG*() above. +class GLOG_EXPORT ErrnoLogMessage : public LogMessage { + public: + ErrnoLogMessage(const char* file, int line, LogSeverity severity, int64 ctr, + void (LogMessage::*send_method)()); + + // Postpends ": strerror(errno) [errno]". + ~ErrnoLogMessage(); + + private: + ErrnoLogMessage(const ErrnoLogMessage&); + void operator=(const ErrnoLogMessage&); +}; + + +// This class is used to explicitly ignore values in the conditional +// logging macros. This avoids compiler warnings like "value computed +// is not used" and "statement has no effect". + +class GLOG_EXPORT LogMessageVoidify { + public: + LogMessageVoidify() { } + // This has to be an operator with a precedence lower than << but + // higher than ?: + void operator&(std::ostream&) { } +}; + + +// Flushes all log files that contains messages that are at least of +// the specified severity level. Thread-safe. +GLOG_EXPORT void FlushLogFiles(LogSeverity min_severity); + +// Flushes all log files that contains messages that are at least of +// the specified severity level. Thread-hostile because it ignores +// locking -- used for catastrophic failures. +GLOG_EXPORT void FlushLogFilesUnsafe(LogSeverity min_severity); + +// +// Set the destination to which a particular severity level of log +// messages is sent. If base_filename is "", it means "don't log this +// severity". Thread-safe. +// +GLOG_EXPORT void SetLogDestination(LogSeverity severity, + const char* base_filename); + +// +// Set the basename of the symlink to the latest log file at a given +// severity. If symlink_basename is empty, do not make a symlink. If +// you don't call this function, the symlink basename is the +// invocation name of the program. Thread-safe. +// +GLOG_EXPORT void SetLogSymlink(LogSeverity severity, + const char* symlink_basename); + +// +// Used to send logs to some other kind of destination +// Users should subclass LogSink and override send to do whatever they want. +// Implementations must be thread-safe because a shared instance will +// be called from whichever thread ran the LOG(XXX) line. +class GLOG_EXPORT LogSink { + public: + virtual ~LogSink(); + + // Sink's logging logic (message_len is such as to exclude '\n' at the end). + // This method can't use LOG() or CHECK() as logging system mutex(s) are held + // during this call. + virtual void send(LogSeverity severity, const char* full_filename, + const char* base_filename, int line, + const LogMessageTime& logmsgtime, const char* message, + size_t message_len); + // Provide an overload for compatibility purposes + GLOG_DEPRECATED + virtual void send(LogSeverity severity, const char* full_filename, + const char* base_filename, int line, const std::tm* t, + const char* message, size_t message_len); + + // Redefine this to implement waiting for + // the sink's logging logic to complete. + // It will be called after each send() returns, + // but before that LogMessage exits or crashes. + // By default this function does nothing. + // Using this function one can implement complex logic for send() + // that itself involves logging; and do all this w/o causing deadlocks and + // inconsistent rearrangement of log messages. + // E.g. if a LogSink has thread-specific actions, the send() method + // can simply add the message to a queue and wake up another thread that + // handles real logging while itself making some LOG() calls; + // WaitTillSent() can be implemented to wait for that logic to complete. + // See our unittest for an example. + virtual void WaitTillSent(); + + // Returns the normal text output of the log message. + // Can be useful to implement send(). + static std::string ToString(LogSeverity severity, const char* file, int line, + const LogMessageTime &logmsgtime, + const char* message, size_t message_len); +}; + +// Add or remove a LogSink as a consumer of logging data. Thread-safe. +GLOG_EXPORT void AddLogSink(LogSink *destination); +GLOG_EXPORT void RemoveLogSink(LogSink *destination); + +// +// Specify an "extension" added to the filename specified via +// SetLogDestination. This applies to all severity levels. It's +// often used to append the port we're listening on to the logfile +// name. Thread-safe. +// +GLOG_EXPORT void SetLogFilenameExtension( + const char* filename_extension); + +// +// Make it so that all log messages of at least a particular severity +// are logged to stderr (in addition to logging to the usual log +// file(s)). Thread-safe. +// +GLOG_EXPORT void SetStderrLogging(LogSeverity min_severity); + +// +// Make it so that all log messages go only to stderr. Thread-safe. +// +GLOG_EXPORT void LogToStderr(); + +// +// Make it so that all log messages of at least a particular severity are +// logged via email to a list of addresses (in addition to logging to the +// usual log file(s)). The list of addresses is just a string containing +// the email addresses to send to (separated by spaces, say). Thread-safe. +// +GLOG_EXPORT void SetEmailLogging(LogSeverity min_severity, + const char* addresses); + +// A simple function that sends email. dest is a commma-separated +// list of addressess. Thread-safe. +GLOG_EXPORT bool SendEmail(const char* dest, const char* subject, + const char* body); + +GLOG_EXPORT const std::vector& GetLoggingDirectories(); + +// For tests only: Clear the internal [cached] list of logging directories to +// force a refresh the next time GetLoggingDirectories is called. +// Thread-hostile. +void TestOnly_ClearLoggingDirectoriesList(); + +// Returns a set of existing temporary directories, which will be a +// subset of the directories returned by GetLoggingDirectories(). +// Thread-safe. +GLOG_EXPORT void GetExistingTempDirectories( + std::vector* list); + +// Print any fatal message again -- useful to call from signal handler +// so that the last thing in the output is the fatal message. +// Thread-hostile, but a race is unlikely. +GLOG_EXPORT void ReprintFatalMessage(); + +// Truncate a log file that may be the append-only output of multiple +// processes and hence can't simply be renamed/reopened (typically a +// stdout/stderr). If the file "path" is > "limit" bytes, copy the +// last "keep" bytes to offset 0 and truncate the rest. Since we could +// be racing with other writers, this approach has the potential to +// lose very small amounts of data. For security, only follow symlinks +// if the path is /proc/self/fd/* +GLOG_EXPORT void TruncateLogFile(const char* path, uint64 limit, uint64 keep); + +// Truncate stdout and stderr if they are over the value specified by +// --max_log_size; keep the final 1MB. This function has the same +// race condition as TruncateLogFile. +GLOG_EXPORT void TruncateStdoutStderr(); + +// Return the string representation of the provided LogSeverity level. +// Thread-safe. +GLOG_EXPORT const char* GetLogSeverityName(LogSeverity severity); + +// --------------------------------------------------------------------- +// Implementation details that are not useful to most clients +// --------------------------------------------------------------------- + +// A Logger is the interface used by logging modules to emit entries +// to a log. A typical implementation will dump formatted data to a +// sequence of files. We also provide interfaces that will forward +// the data to another thread so that the invoker never blocks. +// Implementations should be thread-safe since the logging system +// will write to them from multiple threads. + +namespace base { + +class GLOG_EXPORT Logger { + public: + virtual ~Logger(); + + // Writes "message[0,message_len-1]" corresponding to an event that + // occurred at "timestamp". If "force_flush" is true, the log file + // is flushed immediately. + // + // The input message has already been formatted as deemed + // appropriate by the higher level logging facility. For example, + // textual log messages already contain timestamps, and the + // file:linenumber header. + virtual void Write(bool force_flush, + time_t timestamp, + const char* message, + size_t message_len) = 0; + + // Flush any buffered messages + virtual void Flush() = 0; + + // Get the current LOG file size. + // The returned value is approximate since some + // logged data may not have been flushed to disk yet. + virtual uint32 LogSize() = 0; +}; + +// Get the logger for the specified severity level. The logger +// remains the property of the logging module and should not be +// deleted by the caller. Thread-safe. +extern GLOG_EXPORT Logger* GetLogger(LogSeverity level); + +// Set the logger for the specified severity level. The logger +// becomes the property of the logging module and should not +// be deleted by the caller. Thread-safe. +extern GLOG_EXPORT void SetLogger(LogSeverity level, Logger* logger); + +} + +// glibc has traditionally implemented two incompatible versions of +// strerror_r(). There is a poorly defined convention for picking the +// version that we want, but it is not clear whether it even works with +// all versions of glibc. +// So, instead, we provide this wrapper that automatically detects the +// version that is in use, and then implements POSIX semantics. +// N.B. In addition to what POSIX says, we also guarantee that "buf" will +// be set to an empty string, if this function failed. This means, in most +// cases, you do not need to check the error code and you can directly +// use the value of "buf". It will never have an undefined value. +// DEPRECATED: Use StrError(int) instead. +GLOG_EXPORT int posix_strerror_r(int err, char *buf, size_t len); + +// A thread-safe replacement for strerror(). Returns a string describing the +// given POSIX error code. +GLOG_EXPORT std::string StrError(int err); + +// A class for which we define operator<<, which does nothing. +class GLOG_EXPORT NullStream : public LogMessage::LogStream { + public: + // Initialize the LogStream so the messages can be written somewhere + // (they'll never be actually displayed). This will be needed if a + // NullStream& is implicitly converted to LogStream&, in which case + // the overloaded NullStream::operator<< will not be invoked. + NullStream() : LogMessage::LogStream(message_buffer_, 1, 0) { } + NullStream(const char* /*file*/, int /*line*/, + const CheckOpString& /*result*/) : + LogMessage::LogStream(message_buffer_, 1, 0) { } + NullStream &stream() { return *this; } + private: + // A very short buffer for messages (which we discard anyway). This + // will be needed if NullStream& converted to LogStream& (e.g. as a + // result of a conditional expression). + char message_buffer_[2]; +}; + +// Do nothing. This operator is inline, allowing the message to be +// compiled away. The message will not be compiled away if we do +// something like (flag ? LOG(INFO) : LOG(ERROR)) << message; when +// SKIP_LOG=WARNING. In those cases, NullStream will be implicitly +// converted to LogStream and the message will be computed and then +// quietly discarded. +template +inline NullStream& operator<<(NullStream &str, const T &) { return str; } + +// Similar to NullStream, but aborts the program (without stack +// trace), like LogMessageFatal. +class GLOG_EXPORT NullStreamFatal : public NullStream { + public: + NullStreamFatal() { } + NullStreamFatal(const char* file, int line, const CheckOpString& result) : + NullStream(file, line, result) { } +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4722) +#endif // _MSC_VER + [[noreturn]] ~NullStreamFatal() throw() { _exit(EXIT_FAILURE); } +#if defined(_MSC_VER) +#pragma warning(pop) +#endif // _MSC_VER +}; + +// Install a signal handler that will dump signal information and a stack +// trace when the program crashes on certain signals. We'll install the +// signal handler for the following signals. +// +// SIGSEGV, SIGILL, SIGFPE, SIGABRT, SIGBUS, and SIGTERM. +// +// By default, the signal handler will write the failure dump to the +// standard error. You can customize the destination by installing your +// own writer function by InstallFailureWriter() below. +// +// Note on threading: +// +// The function should be called before threads are created, if you want +// to use the failure signal handler for all threads. The stack trace +// will be shown only for the thread that receives the signal. In other +// words, stack traces of other threads won't be shown. +GLOG_EXPORT void InstallFailureSignalHandler(); + +// Installs a function that is used for writing the failure dump. "data" +// is the pointer to the beginning of a message to be written, and "size" +// is the size of the message. You should not expect the data is +// terminated with '\0'. +GLOG_EXPORT void InstallFailureWriter( + void (*writer)(const char* data, size_t size)); + +} + +#pragma pop_macro("DECLARE_VARIABLE") +#pragma pop_macro("DECLARE_bool") +#pragma pop_macro("DECLARE_string") +#pragma pop_macro("DECLARE_int32") +#pragma pop_macro("DECLARE_uint32") + +#endif // GLOG_LOGGING_H diff --git a/funasr/runtime/onnxruntime/include/glog/logging.h.in b/funasr/runtime/onnxruntime/include/glog/logging.h.in new file mode 100644 index 000000000..e8e6c41b8 --- /dev/null +++ b/funasr/runtime/onnxruntime/include/glog/logging.h.in @@ -0,0 +1,1842 @@ +// Copyright (c) 2023, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: Ray Sidney +// +// This file contains #include information about logging-related stuff. +// Pretty much everybody needs to #include this file so that they can +// log various happenings. +// +#ifndef GLOG_LOGGING_H +#define GLOG_LOGGING_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if @ac_cv_have_unistd_h@ +# include +#endif +#include + +#if defined(_MSC_VER) +#define GLOG_MSVC_PUSH_DISABLE_WARNING(n) __pragma(warning(push)) \ + __pragma(warning(disable:n)) +#define GLOG_MSVC_POP_WARNING() __pragma(warning(pop)) +#else +#define GLOG_MSVC_PUSH_DISABLE_WARNING(n) +#define GLOG_MSVC_POP_WARNING() +#endif + +#include + +#if @ac_cv_have_glog_export@ +#include +#endif + +// We care a lot about number of bits things take up. Unfortunately, +// systems define their bit-specific ints in a lot of different ways. +// We use our own way, and have a typedef to get there. +// Note: these commands below may look like "#if 1" or "#if 0", but +// that's because they were constructed that way at ./configure time. +// Look at logging.h.in to see how they're calculated (based on your config). +#include // the normal place uint16_t is defined +#if @ac_cv_have_systypes_h@ +#include // the normal place u_int16_t is defined +#endif + +#if @ac_cv_have_libgflags@ +#include +#endif + +#include + +@ac_google_start_namespace@ + + typedef std::int32_t int32; +typedef std::uint32_t uint32; +typedef std::int64_t int64; +typedef std::uint64_t uint64; + +#if !(@ac_cv_have_ssize_t@) +typedef ptrdiff_t ssize_t; +#endif + +#if !(@ac_cv_have_mode_t@) +typedef int mode_t; +#endif + +typedef double WallTime; + +struct GLOG_EXPORT LogMessageTime { + LogMessageTime(); + LogMessageTime(std::tm t); + LogMessageTime(std::time_t timestamp, WallTime now); + + const time_t& timestamp() const { return timestamp_; } + const int& sec() const { return time_struct_.tm_sec; } + const int32_t& usec() const { return usecs_; } + const int&(min)() const { return time_struct_.tm_min; } + const int& hour() const { return time_struct_.tm_hour; } + const int& day() const { return time_struct_.tm_mday; } + const int& month() const { return time_struct_.tm_mon; } + const int& year() const { return time_struct_.tm_year; } + const int& dayOfWeek() const { return time_struct_.tm_wday; } + const int& dayInYear() const { return time_struct_.tm_yday; } + const int& dst() const { return time_struct_.tm_isdst; } + const long int& gmtoff() const { return gmtoffset_; } + const std::tm& tm() const { return time_struct_; } + + private: + void init(const std::tm& t, std::time_t timestamp, WallTime now); + std::tm time_struct_; // Time of creation of LogMessage + time_t timestamp_; // Time of creation of LogMessage in seconds + int32_t usecs_; // Time of creation of LogMessage - microseconds part + long int gmtoffset_; + + void CalcGmtOffset(); +}; + +struct LogMessageInfo { + explicit LogMessageInfo(const char* const severity_, + const char* const filename_, + const int& line_number_, + const int& thread_id_, + const LogMessageTime& time_): + severity(severity_), filename(filename_), line_number(line_number_), + thread_id(thread_id_), time(time_) + {} + + const char* const severity; + const char* const filename; + const int &line_number; + const int &thread_id; + const LogMessageTime& time; +}; + +typedef void(*CustomPrefixCallback)(std::ostream& s, const LogMessageInfo& l, void* data); + +@ac_google_end_namespace@ + + +// The global value of GOOGLE_STRIP_LOG. All the messages logged to +// LOG(XXX) with severity less than GOOGLE_STRIP_LOG will not be displayed. +// If it can be determined at compile time that the message will not be +// printed, the statement will be compiled out. +// +// Example: to strip out all INFO and WARNING messages, use the value +// of 2 below. To make an exception for WARNING messages from a single +// file, add "#define GOOGLE_STRIP_LOG 1" to that file _before_ including +// base/logging.h +#ifndef GOOGLE_STRIP_LOG +#define GOOGLE_STRIP_LOG 0 +#endif + +// GCC can be told that a certain branch is not likely to be taken (for +// instance, a CHECK failure), and use that information in static analysis. +// Giving it this information can help it optimize for the common case in +// the absence of better information (ie. -fprofile-arcs). +// +#ifndef GOOGLE_PREDICT_BRANCH_NOT_TAKEN +#if @ac_cv_have___builtin_expect@ +#define GOOGLE_PREDICT_BRANCH_NOT_TAKEN(x) (__builtin_expect(x, 0)) +#else +#define GOOGLE_PREDICT_BRANCH_NOT_TAKEN(x) x +#endif +#endif + +#ifndef GOOGLE_PREDICT_FALSE +#if @ac_cv_have___builtin_expect@ +#define GOOGLE_PREDICT_FALSE(x) (__builtin_expect(x, 0)) +#else +#define GOOGLE_PREDICT_FALSE(x) x +#endif +#endif + +#ifndef GOOGLE_PREDICT_TRUE +#if @ac_cv_have___builtin_expect@ +#define GOOGLE_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1)) +#else +#define GOOGLE_PREDICT_TRUE(x) x +#endif +#endif + + +// Make a bunch of macros for logging. The way to log things is to stream +// things to LOG(). E.g., +// +// LOG(INFO) << "Found " << num_cookies << " cookies"; +// +// You can capture log messages in a string, rather than reporting them +// immediately: +// +// vector errors; +// LOG_STRING(ERROR, &errors) << "Couldn't parse cookie #" << cookie_num; +// +// This pushes back the new error onto 'errors'; if given a NULL pointer, +// it reports the error via LOG(ERROR). +// +// You can also do conditional logging: +// +// LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies"; +// +// You can also do occasional logging (log every n'th occurrence of an +// event): +// +// LOG_EVERY_N(INFO, 10) << "Got the " << google::COUNTER << "th cookie"; +// +// The above will cause log messages to be output on the 1st, 11th, 21st, ... +// times it is executed. Note that the special google::COUNTER value is used +// to identify which repetition is happening. +// +// You can also do occasional conditional logging (log every n'th +// occurrence of an event, when condition is satisfied): +// +// LOG_IF_EVERY_N(INFO, (size > 1024), 10) << "Got the " << google::COUNTER +// << "th big cookie"; +// +// You can log messages the first N times your code executes a line. E.g. +// +// LOG_FIRST_N(INFO, 20) << "Got the " << google::COUNTER << "th cookie"; +// +// Outputs log messages for the first 20 times it is executed. +// +// Analogous SYSLOG, SYSLOG_IF, and SYSLOG_EVERY_N macros are available. +// These log to syslog as well as to the normal logs. If you use these at +// all, you need to be aware that syslog can drastically reduce performance, +// especially if it is configured for remote logging! Don't use these +// unless you fully understand this and have a concrete need to use them. +// Even then, try to minimize your use of them. +// +// There are also "debug mode" logging macros like the ones above: +// +// DLOG(INFO) << "Found cookies"; +// +// DLOG_IF(INFO, num_cookies > 10) << "Got lots of cookies"; +// +// DLOG_EVERY_N(INFO, 10) << "Got the " << google::COUNTER << "th cookie"; +// +// All "debug mode" logging is compiled away to nothing for non-debug mode +// compiles. +// +// We also have +// +// LOG_ASSERT(assertion); +// DLOG_ASSERT(assertion); +// +// which is syntactic sugar for {,D}LOG_IF(FATAL, assert fails) << assertion; +// +// There are "verbose level" logging macros. They look like +// +// VLOG(1) << "I'm printed when you run the program with --v=1 or more"; +// VLOG(2) << "I'm printed when you run the program with --v=2 or more"; +// +// These always log at the INFO log level (when they log at all). +// The verbose logging can also be turned on module-by-module. For instance, +// --vmodule=mapreduce=2,file=1,gfs*=3 --v=0 +// will cause: +// a. VLOG(2) and lower messages to be printed from mapreduce.{h,cc} +// b. VLOG(1) and lower messages to be printed from file.{h,cc} +// c. VLOG(3) and lower messages to be printed from files prefixed with "gfs" +// d. VLOG(0) and lower messages to be printed from elsewhere +// +// The wildcarding functionality shown by (c) supports both '*' (match +// 0 or more characters) and '?' (match any single character) wildcards. +// +// There's also VLOG_IS_ON(n) "verbose level" condition macro. To be used as +// +// if (VLOG_IS_ON(2)) { +// // do some logging preparation and logging +// // that can't be accomplished with just VLOG(2) << ...; +// } +// +// There are also VLOG_IF, VLOG_EVERY_N and VLOG_IF_EVERY_N "verbose level" +// condition macros for sample cases, when some extra computation and +// preparation for logs is not needed. +// VLOG_IF(1, (size > 1024)) +// << "I'm printed when size is more than 1024 and when you run the " +// "program with --v=1 or more"; +// VLOG_EVERY_N(1, 10) +// << "I'm printed every 10th occurrence, and when you run the program " +// "with --v=1 or more. Present occurence is " << google::COUNTER; +// VLOG_IF_EVERY_N(1, (size > 1024), 10) +// << "I'm printed on every 10th occurence of case when size is more " +// " than 1024, when you run the program with --v=1 or more. "; +// "Present occurence is " << google::COUNTER; +// +// The supported severity levels for macros that allow you to specify one +// are (in increasing order of severity) INFO, WARNING, ERROR, and FATAL. +// Note that messages of a given severity are logged not only in the +// logfile for that severity, but also in all logfiles of lower severity. +// E.g., a message of severity FATAL will be logged to the logfiles of +// severity FATAL, ERROR, WARNING, and INFO. +// +// There is also the special severity of DFATAL, which logs FATAL in +// debug mode, ERROR in normal mode. +// +// Very important: logging a message at the FATAL severity level causes +// the program to terminate (after the message is logged). +// +// Unless otherwise specified, logs will be written to the filename +// "...log..", followed +// by the date, time, and pid (you can't prevent the date, time, and pid +// from being in the filename). +// +// The logging code takes two flags: +// --v=# set the verbose level +// --logtostderr log all the messages to stderr instead of to logfiles + +// LOG LINE PREFIX FORMAT +// +// Log lines have this form: +// +// Lyyyymmdd hh:mm:ss.uuuuuu threadid file:line] msg... +// +// where the fields are defined as follows: +// +// L A single character, representing the log level +// (eg 'I' for INFO) +// yyyy The year +// mm The month (zero padded; ie May is '05') +// dd The day (zero padded) +// hh:mm:ss.uuuuuu Time in hours, minutes and fractional seconds +// threadid The space-padded thread ID as returned by GetTID() +// (this matches the PID on Linux) +// file The file name +// line The line number +// msg The user-supplied message +// +// Example: +// +// I1103 11:57:31.739339 24395 google.cc:2341] Command line: ./some_prog +// I1103 11:57:31.739403 24395 google.cc:2342] Process id 24395 +// +// NOTE: although the microseconds are useful for comparing events on +// a single machine, clocks on different machines may not be well +// synchronized. Hence, use caution when comparing the low bits of +// timestamps from different machines. + +#pragma push_macro("DECLARE_VARIABLE") +#pragma push_macro("DECLARE_bool") +#pragma push_macro("DECLARE_string") +#pragma push_macro("DECLARE_int32") +#pragma push_macro("DECLARE_uint32") + +#ifdef DECLARE_VARIABLE +#undef DECLARE_VARIABLE +#endif + +#ifdef DECLARE_bool +#undef DECLARE_bool +#endif + +#ifdef DECLARE_string +#undef DECLARE_string +#endif + +#ifdef DECLARE_int32 +#undef DECLARE_int32 +#endif + +#ifdef DECLARE_uint32 +#undef DECLARE_uint32 +#endif + +#ifndef DECLARE_VARIABLE +#define DECLARE_VARIABLE(type, shorttype, name, tn) \ + namespace fL##shorttype { \ + extern GLOG_EXPORT type FLAGS_##name; \ + } \ + using fL##shorttype::FLAGS_##name + +// bool specialization +#define DECLARE_bool(name) \ + DECLARE_VARIABLE(bool, B, name, bool) + +// int32 specialization +#define DECLARE_int32(name) \ + DECLARE_VARIABLE(@ac_google_namespace@::int32, I, name, int32) + +#if !defined(DECLARE_uint32) +// uint32 specialization +#define DECLARE_uint32(name) \ + DECLARE_VARIABLE(@ac_google_namespace@::uint32, U, name, uint32) +#endif // !defined(DECLARE_uint32) && !(@ac_cv_have_libgflags@) + +// Special case for string, because we have to specify the namespace +// std::string, which doesn't play nicely with our FLAG__namespace hackery. +#define DECLARE_string(name) \ + namespace fLS { \ + extern GLOG_EXPORT std::string& FLAGS_##name; \ + } \ + using fLS::FLAGS_##name +#endif + +// Set whether appending a timestamp to the log file name +DECLARE_bool(timestamp_in_logfile_name); + +// Set whether log messages go to stdout instead of logfiles +DECLARE_bool(logtostdout); + +// Set color messages logged to stdout (if supported by terminal). +DECLARE_bool(colorlogtostdout); + +// Set whether log messages go to stderr instead of logfiles +DECLARE_bool(logtostderr); + +// Set whether log messages go to stderr in addition to logfiles. +DECLARE_bool(alsologtostderr); + +// Set color messages logged to stderr (if supported by terminal). +DECLARE_bool(colorlogtostderr); + +// Log messages at a level >= this flag are automatically sent to +// stderr in addition to log files. +DECLARE_int32(stderrthreshold); + +// Set whether the log file header should be written upon creating a file. +DECLARE_bool(log_file_header); + +// Set whether the log prefix should be prepended to each line of output. +DECLARE_bool(log_prefix); + +// Set whether the year should be included in the log prefix. +DECLARE_bool(log_year_in_prefix); + +// Log messages at a level <= this flag are buffered. +// Log messages at a higher level are flushed immediately. +DECLARE_int32(logbuflevel); + +// Sets the maximum number of seconds which logs may be buffered for. +DECLARE_int32(logbufsecs); + +// Log suppression level: messages logged at a lower level than this +// are suppressed. +DECLARE_int32(minloglevel); + +// If specified, logfiles are written into this directory instead of the +// default logging directory. +DECLARE_string(log_dir); + +// Set the log file mode. +DECLARE_int32(logfile_mode); + +// Sets the path of the directory into which to put additional links +// to the log files. +DECLARE_string(log_link); + +DECLARE_int32(v); // in vlog_is_on.cc + +DECLARE_string(vmodule); // also in vlog_is_on.cc + +// Sets the maximum log file size (in MB). +DECLARE_uint32(max_log_size); + +// Sets whether to avoid logging to the disk if the disk is full. +DECLARE_bool(stop_logging_if_full_disk); + +// Use UTC time for logging +DECLARE_bool(log_utc_time); + +// Log messages below the GOOGLE_STRIP_LOG level will be compiled away for +// security reasons. See LOG(severtiy) below. + +// A few definitions of macros that don't generate much code. Since +// LOG(INFO) and its ilk are used all over our code, it's +// better to have compact code for these operations. + +#if GOOGLE_STRIP_LOG == 0 +#define COMPACT_GOOGLE_LOG_INFO @ac_google_namespace@::LogMessage( \ + __FILE__, __LINE__) +#define LOG_TO_STRING_INFO(message) @ac_google_namespace@::LogMessage( \ + __FILE__, __LINE__, @ac_google_namespace@::GLOG_INFO, message) +#else +#define COMPACT_GOOGLE_LOG_INFO @ac_google_namespace@::NullStream() +#define LOG_TO_STRING_INFO(message) @ac_google_namespace@::NullStream() +#endif + +#if GOOGLE_STRIP_LOG <= 1 +#define COMPACT_GOOGLE_LOG_WARNING @ac_google_namespace@::LogMessage( \ + __FILE__, __LINE__, @ac_google_namespace@::GLOG_WARNING) +#define LOG_TO_STRING_WARNING(message) @ac_google_namespace@::LogMessage( \ + __FILE__, __LINE__, @ac_google_namespace@::GLOG_WARNING, message) +#else +#define COMPACT_GOOGLE_LOG_WARNING @ac_google_namespace@::NullStream() +#define LOG_TO_STRING_WARNING(message) @ac_google_namespace@::NullStream() +#endif + +#if GOOGLE_STRIP_LOG <= 2 +#define COMPACT_GOOGLE_LOG_ERROR @ac_google_namespace@::LogMessage( \ + __FILE__, __LINE__, @ac_google_namespace@::GLOG_ERROR) +#define LOG_TO_STRING_ERROR(message) @ac_google_namespace@::LogMessage( \ + __FILE__, __LINE__, @ac_google_namespace@::GLOG_ERROR, message) +#else +#define COMPACT_GOOGLE_LOG_ERROR @ac_google_namespace@::NullStream() +#define LOG_TO_STRING_ERROR(message) @ac_google_namespace@::NullStream() +#endif + +#if GOOGLE_STRIP_LOG <= 3 +#define COMPACT_GOOGLE_LOG_FATAL @ac_google_namespace@::LogMessageFatal( \ + __FILE__, __LINE__) +#define LOG_TO_STRING_FATAL(message) @ac_google_namespace@::LogMessage( \ + __FILE__, __LINE__, @ac_google_namespace@::GLOG_FATAL, message) +#else +#define COMPACT_GOOGLE_LOG_FATAL @ac_google_namespace@::NullStreamFatal() +#define LOG_TO_STRING_FATAL(message) @ac_google_namespace@::NullStreamFatal() +#endif + +#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON) +#define DCHECK_IS_ON() 0 +#else +#define DCHECK_IS_ON() 1 +#endif + +// For DFATAL, we want to use LogMessage (as opposed to +// LogMessageFatal), to be consistent with the original behavior. +#if !DCHECK_IS_ON() +#define COMPACT_GOOGLE_LOG_DFATAL COMPACT_GOOGLE_LOG_ERROR +#elif GOOGLE_STRIP_LOG <= 3 +#define COMPACT_GOOGLE_LOG_DFATAL @ac_google_namespace@::LogMessage( \ + __FILE__, __LINE__, @ac_google_namespace@::GLOG_FATAL) +#else +#define COMPACT_GOOGLE_LOG_DFATAL @ac_google_namespace@::NullStreamFatal() +#endif + +#define GOOGLE_LOG_INFO(counter) @ac_google_namespace@::LogMessage(__FILE__, __LINE__, @ac_google_namespace@::GLOG_INFO, counter, &@ac_google_namespace@::LogMessage::SendToLog) +#define SYSLOG_INFO(counter) \ + @ac_google_namespace@::LogMessage(__FILE__, __LINE__, @ac_google_namespace@::GLOG_INFO, counter, \ + &@ac_google_namespace@::LogMessage::SendToSyslogAndLog) +#define GOOGLE_LOG_WARNING(counter) \ + @ac_google_namespace@::LogMessage(__FILE__, __LINE__, @ac_google_namespace@::GLOG_WARNING, counter, \ + &@ac_google_namespace@::LogMessage::SendToLog) +#define SYSLOG_WARNING(counter) \ + @ac_google_namespace@::LogMessage(__FILE__, __LINE__, @ac_google_namespace@::GLOG_WARNING, counter, \ + &@ac_google_namespace@::LogMessage::SendToSyslogAndLog) +#define GOOGLE_LOG_ERROR(counter) \ + @ac_google_namespace@::LogMessage(__FILE__, __LINE__, @ac_google_namespace@::GLOG_ERROR, counter, \ + &@ac_google_namespace@::LogMessage::SendToLog) +#define SYSLOG_ERROR(counter) \ + @ac_google_namespace@::LogMessage(__FILE__, __LINE__, @ac_google_namespace@::GLOG_ERROR, counter, \ + &@ac_google_namespace@::LogMessage::SendToSyslogAndLog) +#define GOOGLE_LOG_FATAL(counter) \ + @ac_google_namespace@::LogMessage(__FILE__, __LINE__, @ac_google_namespace@::GLOG_FATAL, counter, \ + &@ac_google_namespace@::LogMessage::SendToLog) +#define SYSLOG_FATAL(counter) \ + @ac_google_namespace@::LogMessage(__FILE__, __LINE__, @ac_google_namespace@::GLOG_FATAL, counter, \ + &@ac_google_namespace@::LogMessage::SendToSyslogAndLog) +#define GOOGLE_LOG_DFATAL(counter) \ + @ac_google_namespace@::LogMessage(__FILE__, __LINE__, @ac_google_namespace@::DFATAL_LEVEL, counter, \ + &@ac_google_namespace@::LogMessage::SendToLog) +#define SYSLOG_DFATAL(counter) \ + @ac_google_namespace@::LogMessage(__FILE__, __LINE__, @ac_google_namespace@::DFATAL_LEVEL, counter, \ + &@ac_google_namespace@::LogMessage::SendToSyslogAndLog) + +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) || defined(__CYGWIN32__) +// A very useful logging macro to log windows errors: +#define LOG_SYSRESULT(result) \ + if (FAILED(HRESULT_FROM_WIN32(result))) { \ + LPSTR message = NULL; \ + LPSTR msg = reinterpret_cast(&message); \ + DWORD message_length = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | \ + FORMAT_MESSAGE_FROM_SYSTEM | \ + FORMAT_MESSAGE_IGNORE_INSERTS, \ + 0, result, 0, msg, 100, NULL); \ + if (message_length > 0) { \ + @ac_google_namespace@::LogMessage(__FILE__, __LINE__, @ac_google_namespace@::GLOG_ERROR, 0, \ + &@ac_google_namespace@::LogMessage::SendToLog).stream() \ + << reinterpret_cast(message); \ + LocalFree(message); \ + } \ + } +#endif + +// We use the preprocessor's merging operator, "##", so that, e.g., +// LOG(INFO) becomes the token GOOGLE_LOG_INFO. There's some funny +// subtle difference between ostream member streaming functions (e.g., +// ostream::operator<<(int) and ostream non-member streaming functions +// (e.g., ::operator<<(ostream&, string&): it turns out that it's +// impossible to stream something like a string directly to an unnamed +// ostream. We employ a neat hack by calling the stream() member +// function of LogMessage which seems to avoid the problem. +#define LOG(severity) COMPACT_GOOGLE_LOG_ ## severity.stream() +#define SYSLOG(severity) SYSLOG_ ## severity(0).stream() + +@ac_google_start_namespace@ + +// They need the definitions of integer types. +#include +#include + +// Initialize google's logging library. You will see the program name +// specified by argv0 in log outputs. +GLOG_EXPORT void InitGoogleLogging(const char* argv0); + +GLOG_EXPORT void InitGoogleLogging(const char* argv0, + CustomPrefixCallback prefix_callback, + void* prefix_callback_data = NULL); + +// Check if google's logging library has been initialized. +GLOG_EXPORT bool IsGoogleLoggingInitialized(); + +// Shutdown google's logging library. +GLOG_EXPORT void ShutdownGoogleLogging(); + +#if defined(__GNUC__) +typedef void (*logging_fail_func_t)() __attribute__((noreturn)); +#else +typedef void (*logging_fail_func_t)(); +#endif + +// Install a function which will be called after LOG(FATAL). +GLOG_EXPORT void InstallFailureFunction(logging_fail_func_t fail_func); + +// Enable/Disable old log cleaner. +GLOG_EXPORT void EnableLogCleaner(unsigned int overdue_days); +GLOG_EXPORT void DisableLogCleaner(); +GLOG_EXPORT void SetApplicationFingerprint(const std::string& fingerprint); + +class LogSink; // defined below + +// If a non-NULL sink pointer is given, we push this message to that sink. +// For LOG_TO_SINK we then do normal LOG(severity) logging as well. +// This is useful for capturing messages and passing/storing them +// somewhere more specific than the global log of the process. +// Argument types: +// LogSink* sink; +// LogSeverity severity; +// The cast is to disambiguate NULL arguments. +#define LOG_TO_SINK(sink, severity) \ + @ac_google_namespace@::LogMessage( \ + __FILE__, __LINE__, \ + @ac_google_namespace@::GLOG_ ## severity, \ + static_cast<@ac_google_namespace@::LogSink*>(sink), true).stream() +#define LOG_TO_SINK_BUT_NOT_TO_LOGFILE(sink, severity) \ + @ac_google_namespace@::LogMessage( \ + __FILE__, __LINE__, \ + @ac_google_namespace@::GLOG_ ## severity, \ + static_cast<@ac_google_namespace@::LogSink*>(sink), false).stream() + +// If a non-NULL string pointer is given, we write this message to that string. +// We then do normal LOG(severity) logging as well. +// This is useful for capturing messages and storing them somewhere more +// specific than the global log of the process. +// Argument types: +// string* message; +// LogSeverity severity; +// The cast is to disambiguate NULL arguments. +// NOTE: LOG(severity) expands to LogMessage().stream() for the specified +// severity. +#define LOG_TO_STRING(severity, message) \ + LOG_TO_STRING_##severity(static_cast(message)).stream() + +// If a non-NULL pointer is given, we push the message onto the end +// of a vector of strings; otherwise, we report it with LOG(severity). +// This is handy for capturing messages and perhaps passing them back +// to the caller, rather than reporting them immediately. +// Argument types: +// LogSeverity severity; +// vector *outvec; +// The cast is to disambiguate NULL arguments. +#define LOG_STRING(severity, outvec) \ + LOG_TO_STRING_##severity(static_cast*>(outvec)).stream() + +#define LOG_IF(severity, condition) \ + static_cast(0), \ + !(condition) ? (void) 0 : @ac_google_namespace@::LogMessageVoidify() & LOG(severity) +#define SYSLOG_IF(severity, condition) \ + static_cast(0), \ + !(condition) ? (void) 0 : @ac_google_namespace@::LogMessageVoidify() & SYSLOG(severity) + +#define LOG_ASSERT(condition) \ + LOG_IF(FATAL, !(condition)) << "Assert failed: " #condition +#define SYSLOG_ASSERT(condition) \ + SYSLOG_IF(FATAL, !(condition)) << "Assert failed: " #condition + +// CHECK dies with a fatal error if condition is not true. It is *not* +// controlled by DCHECK_IS_ON(), so the check will be executed regardless of +// compilation mode. Therefore, it is safe to do things like: +// CHECK(fp->Write(x) == 4) +#define CHECK(condition) \ + LOG_IF(FATAL, GOOGLE_PREDICT_BRANCH_NOT_TAKEN(!(condition))) \ + << "Check failed: " #condition " " + +// A container for a string pointer which can be evaluated to a bool - +// true iff the pointer is NULL. +struct CheckOpString { + CheckOpString(std::string* str) : str_(str) { } + // No destructor: if str_ is non-NULL, we're about to LOG(FATAL), + // so there's no point in cleaning up str_. + operator bool() const { + return GOOGLE_PREDICT_BRANCH_NOT_TAKEN(str_ != NULL); + } + std::string* str_; +}; + +// Function is overloaded for integral types to allow static const +// integrals declared in classes and not defined to be used as arguments to +// CHECK* macros. It's not encouraged though. +template +inline const T& GetReferenceableValue(const T& t) { return t; } +inline char GetReferenceableValue(char t) { return t; } +inline unsigned char GetReferenceableValue(unsigned char t) { return t; } +inline signed char GetReferenceableValue(signed char t) { return t; } +inline short GetReferenceableValue(short t) { return t; } +inline unsigned short GetReferenceableValue(unsigned short t) { return t; } +inline int GetReferenceableValue(int t) { return t; } +inline unsigned int GetReferenceableValue(unsigned int t) { return t; } +inline long GetReferenceableValue(long t) { return t; } +inline unsigned long GetReferenceableValue(unsigned long t) { return t; } +inline long long GetReferenceableValue(long long t) { return t; } +inline unsigned long long GetReferenceableValue(unsigned long long t) { + return t; +} + +// This is a dummy class to define the following operator. +struct DummyClassToDefineOperator {}; + +@ac_google_end_namespace@ + +// Define global operator<< to declare using ::operator<<. +// This declaration will allow use to use CHECK macros for user +// defined classes which have operator<< (e.g., stl_logging.h). +inline std::ostream& operator<<( + std::ostream& out, const google::DummyClassToDefineOperator&) { + return out; +} + +@ac_google_start_namespace@ + +// This formats a value for a failing CHECK_XX statement. Ordinarily, +// it uses the definition for operator<<, with a few special cases below. +template +inline void MakeCheckOpValueString(std::ostream* os, const T& v) { + (*os) << v; +} + +// Overrides for char types provide readable values for unprintable +// characters. +template <> GLOG_EXPORT +void MakeCheckOpValueString(std::ostream* os, const char& v); +template <> GLOG_EXPORT +void MakeCheckOpValueString(std::ostream* os, const signed char& v); +template <> GLOG_EXPORT +void MakeCheckOpValueString(std::ostream* os, const unsigned char& v); + +// Provide printable value for nullptr_t +template <> +GLOG_EXPORT void MakeCheckOpValueString(std::ostream* os, + const std::nullptr_t& v); + +// Build the error message string. Specify no inlining for code size. +template +std::string* MakeCheckOpString(const T1& v1, const T2& v2, const char* exprtext) + @ac_cv___attribute___noinline@; + +namespace base { +namespace internal { + +// If "s" is less than base_logging::INFO, returns base_logging::INFO. +// If "s" is greater than base_logging::FATAL, returns +// base_logging::ERROR. Otherwise, returns "s". +LogSeverity NormalizeSeverity(LogSeverity s); + +} // namespace internal + +// A helper class for formatting "expr (V1 vs. V2)" in a CHECK_XX +// statement. See MakeCheckOpString for sample usage. Other +// approaches were considered: use of a template method (e.g., +// base::BuildCheckOpString(exprtext, base::Print, &v1, +// base::Print, &v2), however this approach has complications +// related to volatile arguments and function-pointer arguments). +class GLOG_EXPORT CheckOpMessageBuilder { + public: + // Inserts "exprtext" and " (" to the stream. + explicit CheckOpMessageBuilder(const char *exprtext); + // Deletes "stream_". + ~CheckOpMessageBuilder(); + // For inserting the first variable. + std::ostream* ForVar1() { return stream_; } + // For inserting the second variable (adds an intermediate " vs. "). + std::ostream* ForVar2(); + // Get the result (inserts the closing ")"). + std::string* NewString(); + + private: + std::ostringstream *stream_; +}; + +} // namespace base + +template +std::string* MakeCheckOpString(const T1& v1, const T2& v2, const char* exprtext) { + base::CheckOpMessageBuilder comb(exprtext); + MakeCheckOpValueString(comb.ForVar1(), v1); + MakeCheckOpValueString(comb.ForVar2(), v2); + return comb.NewString(); +} + +// Helper functions for CHECK_OP macro. +// The (int, int) specialization works around the issue that the compiler +// will not instantiate the template version of the function on values of +// unnamed enum type - see comment below. +#define DEFINE_CHECK_OP_IMPL(name, op) \ + template \ + inline std::string* name##Impl(const T1& v1, const T2& v2, \ + const char* exprtext) { \ + if (GOOGLE_PREDICT_TRUE(v1 op v2)) return NULL; \ + else return MakeCheckOpString(v1, v2, exprtext); \ + } \ + inline std::string* name##Impl(int v1, int v2, const char* exprtext) { \ + return name##Impl(v1, v2, exprtext); \ + } + +// We use the full name Check_EQ, Check_NE, etc. in case the file including +// base/logging.h provides its own #defines for the simpler names EQ, NE, etc. +// This happens if, for example, those are used as token names in a +// yacc grammar. +DEFINE_CHECK_OP_IMPL(Check_EQ, ==) // Compilation error with CHECK_EQ(NULL, x)? +DEFINE_CHECK_OP_IMPL(Check_NE, !=) // Use CHECK(x == NULL) instead. +DEFINE_CHECK_OP_IMPL(Check_LE, <=) +DEFINE_CHECK_OP_IMPL(Check_LT, < ) +DEFINE_CHECK_OP_IMPL(Check_GE, >=) +DEFINE_CHECK_OP_IMPL(Check_GT, > ) +#undef DEFINE_CHECK_OP_IMPL + +// Helper macro for binary operators. +// Don't use this macro directly in your code, use CHECK_EQ et al below. + +#if defined(STATIC_ANALYSIS) +// Only for static analysis tool to know that it is equivalent to assert +#define CHECK_OP_LOG(name, op, val1, val2, log) CHECK((val1) op (val2)) +#elif DCHECK_IS_ON() +// In debug mode, avoid constructing CheckOpStrings if possible, +// to reduce the overhead of CHECK statments by 2x. +// Real DCHECK-heavy tests have seen 1.5x speedups. + +// The meaning of "string" might be different between now and +// when this macro gets invoked (e.g., if someone is experimenting +// with other string implementations that get defined after this +// file is included). Save the current meaning now and use it +// in the macro. +typedef std::string _Check_string; +#define CHECK_OP_LOG(name, op, val1, val2, log) \ + while (@ac_google_namespace@::_Check_string* _result = \ + @ac_google_namespace@::Check##name##Impl( \ + @ac_google_namespace@::GetReferenceableValue(val1), \ + @ac_google_namespace@::GetReferenceableValue(val2), \ + #val1 " " #op " " #val2)) \ + log(__FILE__, __LINE__, \ + @ac_google_namespace@::CheckOpString(_result)).stream() +#else +// In optimized mode, use CheckOpString to hint to compiler that +// the while condition is unlikely. +#define CHECK_OP_LOG(name, op, val1, val2, log) \ + while (@ac_google_namespace@::CheckOpString _result = \ + @ac_google_namespace@::Check##name##Impl( \ + @ac_google_namespace@::GetReferenceableValue(val1), \ + @ac_google_namespace@::GetReferenceableValue(val2), \ + #val1 " " #op " " #val2)) \ + log(__FILE__, __LINE__, _result).stream() +#endif // STATIC_ANALYSIS, DCHECK_IS_ON() + +#if GOOGLE_STRIP_LOG <= 3 +#define CHECK_OP(name, op, val1, val2) \ + CHECK_OP_LOG(name, op, val1, val2, @ac_google_namespace@::LogMessageFatal) +#else +#define CHECK_OP(name, op, val1, val2) \ + CHECK_OP_LOG(name, op, val1, val2, @ac_google_namespace@::NullStreamFatal) +#endif // STRIP_LOG <= 3 + +// Equality/Inequality checks - compare two values, and log a FATAL message +// including the two values when the result is not as expected. The values +// must have operator<<(ostream, ...) defined. +// +// You may append to the error message like so: +// CHECK_NE(1, 2) << ": The world must be ending!"; +// +// We are very careful to ensure that each argument is evaluated exactly +// once, and that anything which is legal to pass as a function argument is +// legal here. In particular, the arguments may be temporary expressions +// which will end up being destroyed at the end of the apparent statement, +// for example: +// CHECK_EQ(string("abc")[1], 'b'); +// +// WARNING: These don't compile correctly if one of the arguments is a pointer +// and the other is NULL. To work around this, simply static_cast NULL to the +// type of the desired pointer. + +#define CHECK_EQ(val1, val2) CHECK_OP(_EQ, ==, val1, val2) +#define CHECK_NE(val1, val2) CHECK_OP(_NE, !=, val1, val2) +#define CHECK_LE(val1, val2) CHECK_OP(_LE, <=, val1, val2) +#define CHECK_LT(val1, val2) CHECK_OP(_LT, < , val1, val2) +#define CHECK_GE(val1, val2) CHECK_OP(_GE, >=, val1, val2) +#define CHECK_GT(val1, val2) CHECK_OP(_GT, > , val1, val2) + +// Check that the input is non NULL. This very useful in constructor +// initializer lists. + +#define CHECK_NOTNULL(val) \ + @ac_google_namespace@::CheckNotNull(__FILE__, __LINE__, "'" #val "' Must be non NULL", (val)) + +// Helper functions for string comparisons. +// To avoid bloat, the definitions are in logging.cc. +#define DECLARE_CHECK_STROP_IMPL(func, expected) \ + GLOG_EXPORT std::string* Check##func##expected##Impl( \ + const char* s1, const char* s2, const char* names); +DECLARE_CHECK_STROP_IMPL(strcmp, true) +DECLARE_CHECK_STROP_IMPL(strcmp, false) +DECLARE_CHECK_STROP_IMPL(strcasecmp, true) +DECLARE_CHECK_STROP_IMPL(strcasecmp, false) +#undef DECLARE_CHECK_STROP_IMPL + +// Helper macro for string comparisons. +// Don't use this macro directly in your code, use CHECK_STREQ et al below. +#define CHECK_STROP(func, op, expected, s1, s2) \ + while (@ac_google_namespace@::CheckOpString _result = \ + @ac_google_namespace@::Check##func##expected##Impl((s1), (s2), \ + #s1 " " #op " " #s2)) \ + LOG(FATAL) << *_result.str_ + + +// String (char*) equality/inequality checks. +// CASE versions are case-insensitive. +// +// Note that "s1" and "s2" may be temporary strings which are destroyed +// by the compiler at the end of the current "full expression" +// (e.g. CHECK_STREQ(Foo().c_str(), Bar().c_str())). + +#define CHECK_STREQ(s1, s2) CHECK_STROP(strcmp, ==, true, s1, s2) +#define CHECK_STRNE(s1, s2) CHECK_STROP(strcmp, !=, false, s1, s2) +#define CHECK_STRCASEEQ(s1, s2) CHECK_STROP(strcasecmp, ==, true, s1, s2) +#define CHECK_STRCASENE(s1, s2) CHECK_STROP(strcasecmp, !=, false, s1, s2) + +#define CHECK_INDEX(I,A) CHECK(I < (sizeof(A)/sizeof(A[0]))) +#define CHECK_BOUND(B,A) CHECK(B <= (sizeof(A)/sizeof(A[0]))) + +#define CHECK_DOUBLE_EQ(val1, val2) \ + do { \ + CHECK_LE((val1), (val2)+0.000000000000001L); \ + CHECK_GE((val1), (val2)-0.000000000000001L); \ + } while (0) + +#define CHECK_NEAR(val1, val2, margin) \ + do { \ + CHECK_LE((val1), (val2)+(margin)); \ + CHECK_GE((val1), (val2)-(margin)); \ + } while (0) + +// perror()..googly style! +// +// PLOG() and PLOG_IF() and PCHECK() behave exactly like their LOG* and +// CHECK equivalents with the addition that they postpend a description +// of the current state of errno to their output lines. + +#define PLOG(severity) GOOGLE_PLOG(severity, 0).stream() + +#define GOOGLE_PLOG(severity, counter) \ + @ac_google_namespace@::ErrnoLogMessage( \ + __FILE__, __LINE__, @ac_google_namespace@::GLOG_ ## severity, counter, \ + &@ac_google_namespace@::LogMessage::SendToLog) + +#define PLOG_IF(severity, condition) \ + static_cast(0), \ + !(condition) ? (void) 0 : @ac_google_namespace@::LogMessageVoidify() & PLOG(severity) + +// A CHECK() macro that postpends errno if the condition is false. E.g. +// +// if (poll(fds, nfds, timeout) == -1) { PCHECK(errno == EINTR); ... } +#define PCHECK(condition) \ + PLOG_IF(FATAL, GOOGLE_PREDICT_BRANCH_NOT_TAKEN(!(condition))) \ + << "Check failed: " #condition " " + +// A CHECK() macro that lets you assert the success of a function that +// returns -1 and sets errno in case of an error. E.g. +// +// CHECK_ERR(mkdir(path, 0700)); +// +// or +// +// int fd = open(filename, flags); CHECK_ERR(fd) << ": open " << filename; +#define CHECK_ERR(invocation) \ +PLOG_IF(FATAL, GOOGLE_PREDICT_BRANCH_NOT_TAKEN((invocation) == -1)) \ + << #invocation + +// Use macro expansion to create, for each use of LOG_EVERY_N(), static +// variables with the __LINE__ expansion as part of the variable name. +#define LOG_EVERY_N_VARNAME(base, line) LOG_EVERY_N_VARNAME_CONCAT(base, line) +#define LOG_EVERY_N_VARNAME_CONCAT(base, line) base ## line + +#define LOG_OCCURRENCES LOG_EVERY_N_VARNAME(occurrences_, __LINE__) +#define LOG_OCCURRENCES_MOD_N LOG_EVERY_N_VARNAME(occurrences_mod_n_, __LINE__) + +#define LOG_TIME_PERIOD LOG_EVERY_N_VARNAME(timePeriod_, __LINE__) +#define LOG_PREVIOUS_TIME_RAW LOG_EVERY_N_VARNAME(previousTimeRaw_, __LINE__) +#define LOG_TIME_DELTA LOG_EVERY_N_VARNAME(deltaTime_, __LINE__) +#define LOG_CURRENT_TIME LOG_EVERY_N_VARNAME(currentTime_, __LINE__) +#define LOG_PREVIOUS_TIME LOG_EVERY_N_VARNAME(previousTime_, __LINE__) + +#if defined(__has_feature) +# if __has_feature(thread_sanitizer) +# define GLOG_SANITIZE_THREAD 1 +# endif +#endif + +#if !defined(GLOG_SANITIZE_THREAD) && defined(__SANITIZE_THREAD__) && __SANITIZE_THREAD__ +# define GLOG_SANITIZE_THREAD 1 +#endif + +#if defined(GLOG_SANITIZE_THREAD) +#define GLOG_IFDEF_THREAD_SANITIZER(X) X +#else +#define GLOG_IFDEF_THREAD_SANITIZER(X) +#endif + +#if defined(GLOG_SANITIZE_THREAD) +} // namespace google + +// We need to identify the static variables as "benign" races +// to avoid noisy reports from TSAN. +extern "C" void AnnotateBenignRaceSized( + const char *file, + int line, + const volatile void *mem, + size_t size, + const char *description); + +namespace google { +#endif + +#define SOME_KIND_OF_LOG_EVERY_T(severity, seconds) \ + constexpr std::chrono::nanoseconds LOG_TIME_PERIOD = \ + std::chrono::duration_cast( \ + std::chrono::duration(seconds)); \ + static std::atomic<@ac_google_namespace@ ::int64> LOG_PREVIOUS_TIME_RAW; \ + GLOG_IFDEF_THREAD_SANITIZER( \ + AnnotateBenignRaceSized(__FILE__, __LINE__, &LOG_TIME_PERIOD, \ + sizeof(@ac_google_namespace @ ::int64), "")); \ + GLOG_IFDEF_THREAD_SANITIZER( \ + AnnotateBenignRaceSized(__FILE__, __LINE__, &LOG_PREVIOUS_TIME_RAW, \ + sizeof(@ac_google_namespace @ ::int64), "")); \ + const auto LOG_CURRENT_TIME = \ + std::chrono::duration_cast( \ + std::chrono::steady_clock::now().time_since_epoch()); \ + const auto LOG_PREVIOUS_TIME = \ + LOG_PREVIOUS_TIME_RAW.load(std::memory_order_relaxed); \ + const auto LOG_TIME_DELTA = \ + LOG_CURRENT_TIME - std::chrono::nanoseconds(LOG_PREVIOUS_TIME); \ + if (LOG_TIME_DELTA > LOG_TIME_PERIOD) \ + LOG_PREVIOUS_TIME_RAW.store( \ + std::chrono::duration_cast(LOG_CURRENT_TIME) \ + .count(), \ + std::memory_order_relaxed); \ + if (LOG_TIME_DELTA > LOG_TIME_PERIOD) \ + @ac_google_namespace@ ::LogMessage( \ + __FILE__, __LINE__, @ac_google_namespace@ ::GLOG_##severity) \ + .stream() + +#define SOME_KIND_OF_LOG_EVERY_N(severity, n, what_to_do) \ + static std::atomic LOG_OCCURRENCES(0), LOG_OCCURRENCES_MOD_N(0); \ + GLOG_IFDEF_THREAD_SANITIZER(AnnotateBenignRaceSized(__FILE__, __LINE__, &LOG_OCCURRENCES, sizeof(int), "")); \ + GLOG_IFDEF_THREAD_SANITIZER(AnnotateBenignRaceSized(__FILE__, __LINE__, &LOG_OCCURRENCES_MOD_N, sizeof(int), "")); \ + ++LOG_OCCURRENCES; \ + if (++LOG_OCCURRENCES_MOD_N > n) LOG_OCCURRENCES_MOD_N -= n; \ + if (LOG_OCCURRENCES_MOD_N == 1) \ + @ac_google_namespace@::LogMessage( \ + __FILE__, __LINE__, @ac_google_namespace@::GLOG_ ## severity, LOG_OCCURRENCES, \ + &what_to_do).stream() + +#define SOME_KIND_OF_LOG_IF_EVERY_N(severity, condition, n, what_to_do) \ + static std::atomic LOG_OCCURRENCES(0), LOG_OCCURRENCES_MOD_N(0); \ + GLOG_IFDEF_THREAD_SANITIZER(AnnotateBenignRaceSized(__FILE__, __LINE__, &LOG_OCCURRENCES, sizeof(int), "")); \ + GLOG_IFDEF_THREAD_SANITIZER(AnnotateBenignRaceSized(__FILE__, __LINE__, &LOG_OCCURRENCES_MOD_N, sizeof(int), "")); \ + ++LOG_OCCURRENCES; \ + if ((condition) && \ + ((LOG_OCCURRENCES_MOD_N=(LOG_OCCURRENCES_MOD_N + 1) % n) == (1 % n))) \ + @ac_google_namespace@::LogMessage( \ + __FILE__, __LINE__, @ac_google_namespace@::GLOG_ ## severity, LOG_OCCURRENCES, \ + &what_to_do).stream() + +#define SOME_KIND_OF_PLOG_EVERY_N(severity, n, what_to_do) \ + static std::atomic LOG_OCCURRENCES(0), LOG_OCCURRENCES_MOD_N(0); \ + GLOG_IFDEF_THREAD_SANITIZER(AnnotateBenignRaceSized(__FILE__, __LINE__, &LOG_OCCURRENCES, sizeof(int), "")); \ + GLOG_IFDEF_THREAD_SANITIZER(AnnotateBenignRaceSized(__FILE__, __LINE__, &LOG_OCCURRENCES_MOD_N, sizeof(int), "")); \ + ++LOG_OCCURRENCES; \ + if (++LOG_OCCURRENCES_MOD_N > n) LOG_OCCURRENCES_MOD_N -= n; \ + if (LOG_OCCURRENCES_MOD_N == 1) \ + @ac_google_namespace@::ErrnoLogMessage( \ + __FILE__, __LINE__, @ac_google_namespace@::GLOG_ ## severity, LOG_OCCURRENCES, \ + &what_to_do).stream() + +#define SOME_KIND_OF_LOG_FIRST_N(severity, n, what_to_do) \ + static std::atomic LOG_OCCURRENCES(0); \ + GLOG_IFDEF_THREAD_SANITIZER(AnnotateBenignRaceSized(__FILE__, __LINE__, &LOG_OCCURRENCES, sizeof(int), "")); \ + if (LOG_OCCURRENCES <= n) \ + ++LOG_OCCURRENCES; \ + if (LOG_OCCURRENCES <= n) \ + @ac_google_namespace@::LogMessage( \ + __FILE__, __LINE__, @ac_google_namespace@::GLOG_ ## severity, LOG_OCCURRENCES, \ + &what_to_do).stream() + +namespace glog_internal_namespace_ { +template +struct CompileAssert { +}; +struct CrashReason; + +// Returns true if FailureSignalHandler is installed. +// Needs to be exported since it's used by the signalhandler_unittest. +GLOG_EXPORT bool IsFailureSignalHandlerInstalled(); +} // namespace glog_internal_namespace_ + +#define LOG_EVERY_N(severity, n) \ + SOME_KIND_OF_LOG_EVERY_N(severity, (n), @ac_google_namespace@::LogMessage::SendToLog) + +#define LOG_EVERY_T(severity, T) SOME_KIND_OF_LOG_EVERY_T(severity, (T)) + +#define SYSLOG_EVERY_N(severity, n) \ + SOME_KIND_OF_LOG_EVERY_N(severity, (n), @ac_google_namespace@::LogMessage::SendToSyslogAndLog) + +#define PLOG_EVERY_N(severity, n) \ + SOME_KIND_OF_PLOG_EVERY_N(severity, (n), @ac_google_namespace@::LogMessage::SendToLog) + +#define LOG_FIRST_N(severity, n) \ + SOME_KIND_OF_LOG_FIRST_N(severity, (n), @ac_google_namespace@::LogMessage::SendToLog) + +#define LOG_IF_EVERY_N(severity, condition, n) \ + SOME_KIND_OF_LOG_IF_EVERY_N(severity, (condition), (n), @ac_google_namespace@::LogMessage::SendToLog) + +// We want the special COUNTER value available for LOG_EVERY_X()'ed messages +enum PRIVATE_Counter {COUNTER}; + +#ifdef GLOG_NO_ABBREVIATED_SEVERITIES +// wingdi.h defines ERROR to be 0. When we call LOG(ERROR), it gets +// substituted with 0, and it expands to COMPACT_GOOGLE_LOG_0. To allow us +// to keep using this syntax, we define this macro to do the same thing +// as COMPACT_GOOGLE_LOG_ERROR. +#define COMPACT_GOOGLE_LOG_0 COMPACT_GOOGLE_LOG_ERROR +#define SYSLOG_0 SYSLOG_ERROR +#define LOG_TO_STRING_0 LOG_TO_STRING_ERROR +// Needed for LOG_IS_ON(ERROR). +const LogSeverity GLOG_0 = GLOG_ERROR; +#else +// Users may include windows.h after logging.h without +// GLOG_NO_ABBREVIATED_SEVERITIES nor WIN32_LEAN_AND_MEAN. +// For this case, we cannot detect if ERROR is defined before users +// actually use ERROR. Let's make an undefined symbol to warn users. +# define GLOG_ERROR_MSG ERROR_macro_is_defined_Define_GLOG_NO_ABBREVIATED_SEVERITIES_before_including_logging_h_See_the_document_for_detail +# define COMPACT_GOOGLE_LOG_0 GLOG_ERROR_MSG +# define SYSLOG_0 GLOG_ERROR_MSG +# define LOG_TO_STRING_0 GLOG_ERROR_MSG +# define GLOG_0 GLOG_ERROR_MSG +#endif + +// Plus some debug-logging macros that get compiled to nothing for production + +#if DCHECK_IS_ON() + +#define DLOG(severity) LOG(severity) +#define DVLOG(verboselevel) VLOG(verboselevel) +#define DLOG_IF(severity, condition) LOG_IF(severity, condition) +#define DLOG_EVERY_N(severity, n) LOG_EVERY_N(severity, n) +#define DLOG_IF_EVERY_N(severity, condition, n) \ + LOG_IF_EVERY_N(severity, condition, n) +#define DLOG_ASSERT(condition) LOG_ASSERT(condition) + +// debug-only checking. executed if DCHECK_IS_ON(). +#define DCHECK(condition) CHECK(condition) +#define DCHECK_EQ(val1, val2) CHECK_EQ(val1, val2) +#define DCHECK_NE(val1, val2) CHECK_NE(val1, val2) +#define DCHECK_LE(val1, val2) CHECK_LE(val1, val2) +#define DCHECK_LT(val1, val2) CHECK_LT(val1, val2) +#define DCHECK_GE(val1, val2) CHECK_GE(val1, val2) +#define DCHECK_GT(val1, val2) CHECK_GT(val1, val2) +#define DCHECK_NOTNULL(val) CHECK_NOTNULL(val) +#define DCHECK_STREQ(str1, str2) CHECK_STREQ(str1, str2) +#define DCHECK_STRCASEEQ(str1, str2) CHECK_STRCASEEQ(str1, str2) +#define DCHECK_STRNE(str1, str2) CHECK_STRNE(str1, str2) +#define DCHECK_STRCASENE(str1, str2) CHECK_STRCASENE(str1, str2) + +#else // !DCHECK_IS_ON() + +#define DLOG(severity) \ + static_cast(0), \ + true ? (void) 0 : @ac_google_namespace@::LogMessageVoidify() & LOG(severity) + +#define DVLOG(verboselevel) \ + static_cast(0), \ + (true || !VLOG_IS_ON(verboselevel)) ? \ + (void) 0 : @ac_google_namespace@::LogMessageVoidify() & LOG(INFO) + +#define DLOG_IF(severity, condition) \ + static_cast(0), \ + (true || !(condition)) ? (void) 0 : @ac_google_namespace@::LogMessageVoidify() & LOG(severity) + +#define DLOG_EVERY_N(severity, n) \ + static_cast(0), \ + true ? (void) 0 : @ac_google_namespace@::LogMessageVoidify() & LOG(severity) + +#define DLOG_IF_EVERY_N(severity, condition, n) \ + static_cast(0), \ + (true || !(condition))? (void) 0 : @ac_google_namespace@::LogMessageVoidify() & LOG(severity) + +#define DLOG_ASSERT(condition) \ + static_cast(0), \ + true ? (void) 0 : LOG_ASSERT(condition) + +// MSVC warning C4127: conditional expression is constant +#define DCHECK(condition) \ + GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ + while (false) \ + GLOG_MSVC_POP_WARNING() CHECK(condition) + +#define DCHECK_EQ(val1, val2) \ + GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ + while (false) \ + GLOG_MSVC_POP_WARNING() CHECK_EQ(val1, val2) + +#define DCHECK_NE(val1, val2) \ + GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ + while (false) \ + GLOG_MSVC_POP_WARNING() CHECK_NE(val1, val2) + +#define DCHECK_LE(val1, val2) \ + GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ + while (false) \ + GLOG_MSVC_POP_WARNING() CHECK_LE(val1, val2) + +#define DCHECK_LT(val1, val2) \ + GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ + while (false) \ + GLOG_MSVC_POP_WARNING() CHECK_LT(val1, val2) + +#define DCHECK_GE(val1, val2) \ + GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ + while (false) \ + GLOG_MSVC_POP_WARNING() CHECK_GE(val1, val2) + +#define DCHECK_GT(val1, val2) \ + GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ + while (false) \ + GLOG_MSVC_POP_WARNING() CHECK_GT(val1, val2) + +// You may see warnings in release mode if you don't use the return +// value of DCHECK_NOTNULL. Please just use DCHECK for such cases. +#define DCHECK_NOTNULL(val) (val) + +#define DCHECK_STREQ(str1, str2) \ + GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ + while (false) \ + GLOG_MSVC_POP_WARNING() CHECK_STREQ(str1, str2) + +#define DCHECK_STRCASEEQ(str1, str2) \ + GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ + while (false) \ + GLOG_MSVC_POP_WARNING() CHECK_STRCASEEQ(str1, str2) + +#define DCHECK_STRNE(str1, str2) \ + GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ + while (false) \ + GLOG_MSVC_POP_WARNING() CHECK_STRNE(str1, str2) + +#define DCHECK_STRCASENE(str1, str2) \ + GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ + while (false) \ + GLOG_MSVC_POP_WARNING() CHECK_STRCASENE(str1, str2) + +#endif // DCHECK_IS_ON() + +// Log only in verbose mode. + +#define VLOG(verboselevel) LOG_IF(INFO, VLOG_IS_ON(verboselevel)) + +#define VLOG_IF(verboselevel, condition) \ + LOG_IF(INFO, (condition) && VLOG_IS_ON(verboselevel)) + +#define VLOG_EVERY_N(verboselevel, n) \ + LOG_IF_EVERY_N(INFO, VLOG_IS_ON(verboselevel), n) + +#define VLOG_IF_EVERY_N(verboselevel, condition, n) \ + LOG_IF_EVERY_N(INFO, (condition) && VLOG_IS_ON(verboselevel), n) + +namespace base_logging { + +// LogMessage::LogStream is a std::ostream backed by this streambuf. +// This class ignores overflow and leaves two bytes at the end of the +// buffer to allow for a '\n' and '\0'. +class GLOG_EXPORT LogStreamBuf : public std::streambuf { + public: + // REQUIREMENTS: "len" must be >= 2 to account for the '\n' and '\0'. + LogStreamBuf(char *buf, int len) { + setp(buf, buf + len - 2); + } + + // This effectively ignores overflow. + int_type overflow(int_type ch) { + return ch; + } + + // Legacy public ostrstream method. + size_t pcount() const { return static_cast(pptr() - pbase()); } + char* pbase() const { return std::streambuf::pbase(); } +}; + +} // namespace base_logging + +// +// This class more or less represents a particular log message. You +// create an instance of LogMessage and then stream stuff to it. +// When you finish streaming to it, ~LogMessage is called and the +// full message gets streamed to the appropriate destination. +// +// You shouldn't actually use LogMessage's constructor to log things, +// though. You should use the LOG() macro (and variants thereof) +// above. +class GLOG_EXPORT LogMessage { +public: + enum { + // Passing kNoLogPrefix for the line number disables the + // log-message prefix. Useful for using the LogMessage + // infrastructure as a printing utility. See also the --log_prefix + // flag for controlling the log-message prefix on an + // application-wide basis. + kNoLogPrefix = -1 + }; + + // LogStream inherit from non-DLL-exported class (std::ostrstream) + // and VC++ produces a warning for this situation. + // However, MSDN says "C4275 can be ignored in Microsoft Visual C++ + // 2005 if you are deriving from a type in the Standard C++ Library" + // http://msdn.microsoft.com/en-us/library/3tdb471s(VS.80).aspx + // Let's just ignore the warning. +GLOG_MSVC_PUSH_DISABLE_WARNING(4275) + class GLOG_EXPORT LogStream : public std::ostream { +GLOG_MSVC_POP_WARNING() + public: + LogStream(char *buf, int len, int64 ctr) + : std::ostream(NULL), + streambuf_(buf, len), + ctr_(ctr), + self_(this) { + rdbuf(&streambuf_); + } + + int64 ctr() const { return ctr_; } + void set_ctr(int64 ctr) { ctr_ = ctr; } + LogStream* self() const { return self_; } + + // Legacy std::streambuf methods. + size_t pcount() const { return streambuf_.pcount(); } + char* pbase() const { return streambuf_.pbase(); } + char* str() const { return pbase(); } + + private: + LogStream(const LogStream&); + LogStream& operator=(const LogStream&); + base_logging::LogStreamBuf streambuf_; + int64 ctr_; // Counter hack (for the LOG_EVERY_X() macro) + LogStream *self_; // Consistency check hack + }; + +public: + // icc 8 requires this typedef to avoid an internal compiler error. + typedef void (LogMessage::*SendMethod)(); + + LogMessage(const char* file, int line, LogSeverity severity, int64 ctr, + SendMethod send_method); + + // Two special constructors that generate reduced amounts of code at + // LOG call sites for common cases. + + // Used for LOG(INFO): Implied are: + // severity = INFO, ctr = 0, send_method = &LogMessage::SendToLog. + // + // Using this constructor instead of the more complex constructor above + // saves 19 bytes per call site. + LogMessage(const char* file, int line); + + // Used for LOG(severity) where severity != INFO. Implied + // are: ctr = 0, send_method = &LogMessage::SendToLog + // + // Using this constructor instead of the more complex constructor above + // saves 17 bytes per call site. + LogMessage(const char* file, int line, LogSeverity severity); + + // Constructor to log this message to a specified sink (if not NULL). + // Implied are: ctr = 0, send_method = &LogMessage::SendToSinkAndLog if + // also_send_to_log is true, send_method = &LogMessage::SendToSink otherwise. + LogMessage(const char* file, int line, LogSeverity severity, LogSink* sink, + bool also_send_to_log); + + // Constructor where we also give a vector pointer + // for storing the messages (if the pointer is not NULL). + // Implied are: ctr = 0, send_method = &LogMessage::SaveOrSendToLog. + LogMessage(const char* file, int line, LogSeverity severity, + std::vector* outvec); + + // Constructor where we also give a string pointer for storing the + // message (if the pointer is not NULL). Implied are: ctr = 0, + // send_method = &LogMessage::WriteToStringAndLog. + LogMessage(const char* file, int line, LogSeverity severity, + std::string* message); + + // A special constructor used for check failures + LogMessage(const char* file, int line, const CheckOpString& result); + + ~LogMessage(); + + // Flush a buffered message to the sink set in the constructor. Always + // called by the destructor, it may also be called from elsewhere if + // needed. Only the first call is actioned; any later ones are ignored. + void Flush(); + + // An arbitrary limit on the length of a single log message. This + // is so that streaming can be done more efficiently. + static const size_t kMaxLogMessageLen; + + // Theses should not be called directly outside of logging.*, + // only passed as SendMethod arguments to other LogMessage methods: + void SendToLog(); // Actually dispatch to the logs + void SendToSyslogAndLog(); // Actually dispatch to syslog and the logs + + // Call abort() or similar to perform LOG(FATAL) crash. + [[noreturn]] static void Fail(); + + std::ostream& stream(); + + int preserved_errno() const; + + // Must be called without the log_mutex held. (L < log_mutex) + static int64 num_messages(int severity); + + const LogMessageTime& getLogMessageTime() const; + + struct LogMessageData; + +private: + // Fully internal SendMethod cases: + void SendToSinkAndLog(); // Send to sink if provided and dispatch to the logs + void SendToSink(); // Send to sink if provided, do nothing otherwise. + + // Write to string if provided and dispatch to the logs. + void WriteToStringAndLog(); + + void SaveOrSendToLog(); // Save to stringvec if provided, else to logs + + void Init(const char* file, int line, LogSeverity severity, + void (LogMessage::*send_method)()); + + // Used to fill in crash information during LOG(FATAL) failures. + void RecordCrashReason(glog_internal_namespace_::CrashReason* reason); + + // Counts of messages sent at each priority: + static int64 num_messages_[NUM_SEVERITIES]; // under log_mutex + + // We keep the data in a separate struct so that each instance of + // LogMessage uses less stack space. + LogMessageData* allocated_; + LogMessageData* data_; + LogMessageTime logmsgtime_; + + friend class LogDestination; + + LogMessage(const LogMessage&); + void operator=(const LogMessage&); +}; + +// This class happens to be thread-hostile because all instances share +// a single data buffer, but since it can only be created just before +// the process dies, we don't worry so much. +class GLOG_EXPORT LogMessageFatal : public LogMessage { + public: + LogMessageFatal(const char* file, int line); + LogMessageFatal(const char* file, int line, const CheckOpString& result); + [[noreturn]] ~LogMessageFatal(); +}; + +// A non-macro interface to the log facility; (useful +// when the logging level is not a compile-time constant). +inline void LogAtLevel(int const severity, std::string const &msg) { + LogMessage(__FILE__, __LINE__, severity).stream() << msg; +} + +// A macro alternative of LogAtLevel. New code may want to use this +// version since there are two advantages: 1. this version outputs the +// file name and the line number where this macro is put like other +// LOG macros, 2. this macro can be used as C++ stream. +#define LOG_AT_LEVEL(severity) @ac_google_namespace@::LogMessage(__FILE__, __LINE__, severity).stream() + +// Helper for CHECK_NOTNULL(). +// +// In C++11, all cases can be handled by a single function. Since the value +// category of the argument is preserved (also for rvalue references), +// member initializer lists like the one below will compile correctly: +// +// Foo() +// : x_(CHECK_NOTNULL(MethodReturningUniquePtr())) {} +template +T CheckNotNull(const char* file, int line, const char* names, T&& t) { + if (t == nullptr) { + LogMessageFatal(file, line, new std::string(names)); + } + return std::forward(t); +} + +// Allow folks to put a counter in the LOG_EVERY_X()'ed messages. This +// only works if ostream is a LogStream. If the ostream is not a +// LogStream you'll get an assert saying as much at runtime. +GLOG_EXPORT std::ostream& operator<<(std::ostream &os, + const PRIVATE_Counter&); + + +// Derived class for PLOG*() above. +class GLOG_EXPORT ErrnoLogMessage : public LogMessage { + public: + ErrnoLogMessage(const char* file, int line, LogSeverity severity, int64 ctr, + void (LogMessage::*send_method)()); + + // Postpends ": strerror(errno) [errno]". + ~ErrnoLogMessage(); + + private: + ErrnoLogMessage(const ErrnoLogMessage&); + void operator=(const ErrnoLogMessage&); +}; + + +// This class is used to explicitly ignore values in the conditional +// logging macros. This avoids compiler warnings like "value computed +// is not used" and "statement has no effect". + +class GLOG_EXPORT LogMessageVoidify { + public: + LogMessageVoidify() { } + // This has to be an operator with a precedence lower than << but + // higher than ?: + void operator&(std::ostream&) { } +}; + + +// Flushes all log files that contains messages that are at least of +// the specified severity level. Thread-safe. +GLOG_EXPORT void FlushLogFiles(LogSeverity min_severity); + +// Flushes all log files that contains messages that are at least of +// the specified severity level. Thread-hostile because it ignores +// locking -- used for catastrophic failures. +GLOG_EXPORT void FlushLogFilesUnsafe(LogSeverity min_severity); + +// +// Set the destination to which a particular severity level of log +// messages is sent. If base_filename is "", it means "don't log this +// severity". Thread-safe. +// +GLOG_EXPORT void SetLogDestination(LogSeverity severity, + const char* base_filename); + +// +// Set the basename of the symlink to the latest log file at a given +// severity. If symlink_basename is empty, do not make a symlink. If +// you don't call this function, the symlink basename is the +// invocation name of the program. Thread-safe. +// +GLOG_EXPORT void SetLogSymlink(LogSeverity severity, + const char* symlink_basename); + +// +// Used to send logs to some other kind of destination +// Users should subclass LogSink and override send to do whatever they want. +// Implementations must be thread-safe because a shared instance will +// be called from whichever thread ran the LOG(XXX) line. +class GLOG_EXPORT LogSink { + public: + virtual ~LogSink(); + + // Sink's logging logic (message_len is such as to exclude '\n' at the end). + // This method can't use LOG() or CHECK() as logging system mutex(s) are held + // during this call. + virtual void send(LogSeverity severity, const char* full_filename, + const char* base_filename, int line, + const LogMessageTime& logmsgtime, const char* message, + size_t message_len); + // Provide an overload for compatibility purposes + GLOG_DEPRECATED + virtual void send(LogSeverity severity, const char* full_filename, + const char* base_filename, int line, const std::tm* t, + const char* message, size_t message_len); + + // Redefine this to implement waiting for + // the sink's logging logic to complete. + // It will be called after each send() returns, + // but before that LogMessage exits or crashes. + // By default this function does nothing. + // Using this function one can implement complex logic for send() + // that itself involves logging; and do all this w/o causing deadlocks and + // inconsistent rearrangement of log messages. + // E.g. if a LogSink has thread-specific actions, the send() method + // can simply add the message to a queue and wake up another thread that + // handles real logging while itself making some LOG() calls; + // WaitTillSent() can be implemented to wait for that logic to complete. + // See our unittest for an example. + virtual void WaitTillSent(); + + // Returns the normal text output of the log message. + // Can be useful to implement send(). + static std::string ToString(LogSeverity severity, const char* file, int line, + const LogMessageTime &logmsgtime, + const char* message, size_t message_len); +}; + +// Add or remove a LogSink as a consumer of logging data. Thread-safe. +GLOG_EXPORT void AddLogSink(LogSink *destination); +GLOG_EXPORT void RemoveLogSink(LogSink *destination); + +// +// Specify an "extension" added to the filename specified via +// SetLogDestination. This applies to all severity levels. It's +// often used to append the port we're listening on to the logfile +// name. Thread-safe. +// +GLOG_EXPORT void SetLogFilenameExtension( + const char* filename_extension); + +// +// Make it so that all log messages of at least a particular severity +// are logged to stderr (in addition to logging to the usual log +// file(s)). Thread-safe. +// +GLOG_EXPORT void SetStderrLogging(LogSeverity min_severity); + +// +// Make it so that all log messages go only to stderr. Thread-safe. +// +GLOG_EXPORT void LogToStderr(); + +// +// Make it so that all log messages of at least a particular severity are +// logged via email to a list of addresses (in addition to logging to the +// usual log file(s)). The list of addresses is just a string containing +// the email addresses to send to (separated by spaces, say). Thread-safe. +// +GLOG_EXPORT void SetEmailLogging(LogSeverity min_severity, + const char* addresses); + +// A simple function that sends email. dest is a commma-separated +// list of addressess. Thread-safe. +GLOG_EXPORT bool SendEmail(const char* dest, const char* subject, + const char* body); + +GLOG_EXPORT const std::vector& GetLoggingDirectories(); + +// For tests only: Clear the internal [cached] list of logging directories to +// force a refresh the next time GetLoggingDirectories is called. +// Thread-hostile. +void TestOnly_ClearLoggingDirectoriesList(); + +// Returns a set of existing temporary directories, which will be a +// subset of the directories returned by GetLoggingDirectories(). +// Thread-safe. +GLOG_EXPORT void GetExistingTempDirectories( + std::vector* list); + +// Print any fatal message again -- useful to call from signal handler +// so that the last thing in the output is the fatal message. +// Thread-hostile, but a race is unlikely. +GLOG_EXPORT void ReprintFatalMessage(); + +// Truncate a log file that may be the append-only output of multiple +// processes and hence can't simply be renamed/reopened (typically a +// stdout/stderr). If the file "path" is > "limit" bytes, copy the +// last "keep" bytes to offset 0 and truncate the rest. Since we could +// be racing with other writers, this approach has the potential to +// lose very small amounts of data. For security, only follow symlinks +// if the path is /proc/self/fd/* +GLOG_EXPORT void TruncateLogFile(const char* path, uint64 limit, uint64 keep); + +// Truncate stdout and stderr if they are over the value specified by +// --max_log_size; keep the final 1MB. This function has the same +// race condition as TruncateLogFile. +GLOG_EXPORT void TruncateStdoutStderr(); + +// Return the string representation of the provided LogSeverity level. +// Thread-safe. +GLOG_EXPORT const char* GetLogSeverityName(LogSeverity severity); + +// --------------------------------------------------------------------- +// Implementation details that are not useful to most clients +// --------------------------------------------------------------------- + +// A Logger is the interface used by logging modules to emit entries +// to a log. A typical implementation will dump formatted data to a +// sequence of files. We also provide interfaces that will forward +// the data to another thread so that the invoker never blocks. +// Implementations should be thread-safe since the logging system +// will write to them from multiple threads. + +namespace base { + +class GLOG_EXPORT Logger { + public: + virtual ~Logger(); + + // Writes "message[0,message_len-1]" corresponding to an event that + // occurred at "timestamp". If "force_flush" is true, the log file + // is flushed immediately. + // + // The input message has already been formatted as deemed + // appropriate by the higher level logging facility. For example, + // textual log messages already contain timestamps, and the + // file:linenumber header. + virtual void Write(bool force_flush, + time_t timestamp, + const char* message, + size_t message_len) = 0; + + // Flush any buffered messages + virtual void Flush() = 0; + + // Get the current LOG file size. + // The returned value is approximate since some + // logged data may not have been flushed to disk yet. + virtual uint32 LogSize() = 0; +}; + +// Get the logger for the specified severity level. The logger +// remains the property of the logging module and should not be +// deleted by the caller. Thread-safe. +extern GLOG_EXPORT Logger* GetLogger(LogSeverity level); + +// Set the logger for the specified severity level. The logger +// becomes the property of the logging module and should not +// be deleted by the caller. Thread-safe. +extern GLOG_EXPORT void SetLogger(LogSeverity level, Logger* logger); + +} + +// glibc has traditionally implemented two incompatible versions of +// strerror_r(). There is a poorly defined convention for picking the +// version that we want, but it is not clear whether it even works with +// all versions of glibc. +// So, instead, we provide this wrapper that automatically detects the +// version that is in use, and then implements POSIX semantics. +// N.B. In addition to what POSIX says, we also guarantee that "buf" will +// be set to an empty string, if this function failed. This means, in most +// cases, you do not need to check the error code and you can directly +// use the value of "buf". It will never have an undefined value. +// DEPRECATED: Use StrError(int) instead. +GLOG_EXPORT int posix_strerror_r(int err, char *buf, size_t len); + +// A thread-safe replacement for strerror(). Returns a string describing the +// given POSIX error code. +GLOG_EXPORT std::string StrError(int err); + +// A class for which we define operator<<, which does nothing. +class GLOG_EXPORT NullStream : public LogMessage::LogStream { + public: + // Initialize the LogStream so the messages can be written somewhere + // (they'll never be actually displayed). This will be needed if a + // NullStream& is implicitly converted to LogStream&, in which case + // the overloaded NullStream::operator<< will not be invoked. + NullStream() : LogMessage::LogStream(message_buffer_, 1, 0) { } + NullStream(const char* /*file*/, int /*line*/, + const CheckOpString& /*result*/) : + LogMessage::LogStream(message_buffer_, 1, 0) { } + NullStream &stream() { return *this; } + private: + // A very short buffer for messages (which we discard anyway). This + // will be needed if NullStream& converted to LogStream& (e.g. as a + // result of a conditional expression). + char message_buffer_[2]; +}; + +// Do nothing. This operator is inline, allowing the message to be +// compiled away. The message will not be compiled away if we do +// something like (flag ? LOG(INFO) : LOG(ERROR)) << message; when +// SKIP_LOG=WARNING. In those cases, NullStream will be implicitly +// converted to LogStream and the message will be computed and then +// quietly discarded. +template +inline NullStream& operator<<(NullStream &str, const T &) { return str; } + +// Similar to NullStream, but aborts the program (without stack +// trace), like LogMessageFatal. +class GLOG_EXPORT NullStreamFatal : public NullStream { + public: + NullStreamFatal() { } + NullStreamFatal(const char* file, int line, const CheckOpString& result) : + NullStream(file, line, result) { } +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4722) +#endif // _MSC_VER + [[noreturn]] ~NullStreamFatal() throw() { _exit(EXIT_FAILURE); } +#if defined(_MSC_VER) +#pragma warning(pop) +#endif // _MSC_VER +}; + +// Install a signal handler that will dump signal information and a stack +// trace when the program crashes on certain signals. We'll install the +// signal handler for the following signals. +// +// SIGSEGV, SIGILL, SIGFPE, SIGABRT, SIGBUS, and SIGTERM. +// +// By default, the signal handler will write the failure dump to the +// standard error. You can customize the destination by installing your +// own writer function by InstallFailureWriter() below. +// +// Note on threading: +// +// The function should be called before threads are created, if you want +// to use the failure signal handler for all threads. The stack trace +// will be shown only for the thread that receives the signal. In other +// words, stack traces of other threads won't be shown. +GLOG_EXPORT void InstallFailureSignalHandler(); + +// Installs a function that is used for writing the failure dump. "data" +// is the pointer to the beginning of a message to be written, and "size" +// is the size of the message. You should not expect the data is +// terminated with '\0'. +GLOG_EXPORT void InstallFailureWriter( + void (*writer)(const char* data, size_t size)); + +@ac_google_end_namespace@ + +#pragma pop_macro("DECLARE_VARIABLE") +#pragma pop_macro("DECLARE_bool") +#pragma pop_macro("DECLARE_string") +#pragma pop_macro("DECLARE_int32") +#pragma pop_macro("DECLARE_uint32") + +#endif // GLOG_LOGGING_H diff --git a/funasr/runtime/onnxruntime/include/glog/platform.h b/funasr/runtime/onnxruntime/include/glog/platform.h new file mode 100644 index 000000000..7893c45d1 --- /dev/null +++ b/funasr/runtime/onnxruntime/include/glog/platform.h @@ -0,0 +1,60 @@ +// Copyright (c) 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: Shinichiro Hamaji +// +// Detect supported platforms. + +#ifndef GLOG_PLATFORM_H +#define GLOG_PLATFORM_H + +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) +#define GLOG_OS_WINDOWS +#elif defined(__CYGWIN__) || defined(__CYGWIN32__) +#define GLOG_OS_CYGWIN +#elif defined(linux) || defined(__linux) || defined(__linux__) +#ifndef GLOG_OS_LINUX +#define GLOG_OS_LINUX +#endif +#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) +#define GLOG_OS_MACOSX +#elif defined(__FreeBSD__) +#define GLOG_OS_FREEBSD +#elif defined(__NetBSD__) +#define GLOG_OS_NETBSD +#elif defined(__OpenBSD__) +#define GLOG_OS_OPENBSD +#elif defined(__EMSCRIPTEN__) +#define GLOG_OS_EMSCRIPTEN +#else +// TODO(hamaji): Add other platforms. +#error Platform not supported by glog. Please consider to contribute platform information by submitting a pull request on Github. +#endif + +#endif // GLOG_PLATFORM_H diff --git a/funasr/runtime/onnxruntime/include/glog/raw_logging.h b/funasr/runtime/onnxruntime/include/glog/raw_logging.h new file mode 100644 index 000000000..eda5fb456 --- /dev/null +++ b/funasr/runtime/onnxruntime/include/glog/raw_logging.h @@ -0,0 +1,179 @@ +// Copyright (c) 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: Maxim Lifantsev +// +// Thread-safe logging routines that do not allocate any memory or +// acquire any locks, and can therefore be used by low-level memory +// allocation and synchronization code. + +#ifndef GLOG_RAW_LOGGING_H +#define GLOG_RAW_LOGGING_H + +#include + +namespace google { + +#include +#include +#include + +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wvariadic-macros" +#endif + +// This is similar to LOG(severity) << format... and VLOG(level) << format.., +// but +// * it is to be used ONLY by low-level modules that can't use normal LOG() +// * it is desiged to be a low-level logger that does not allocate any +// memory and does not need any locks, hence: +// * it logs straight and ONLY to STDERR w/o buffering +// * it uses an explicit format and arguments list +// * it will silently chop off really long message strings +// Usage example: +// RAW_LOG(ERROR, "Failed foo with %i: %s", status, error); +// RAW_VLOG(3, "status is %i", status); +// These will print an almost standard log lines like this to stderr only: +// E20200821 211317 file.cc:123] RAW: Failed foo with 22: bad_file +// I20200821 211317 file.cc:142] RAW: status is 20 +#define RAW_LOG(severity, ...) \ + do { \ + switch (google::GLOG_ ## severity) { \ + case 0: \ + RAW_LOG_INFO(__VA_ARGS__); \ + break; \ + case 1: \ + RAW_LOG_WARNING(__VA_ARGS__); \ + break; \ + case 2: \ + RAW_LOG_ERROR(__VA_ARGS__); \ + break; \ + case 3: \ + RAW_LOG_FATAL(__VA_ARGS__); \ + break; \ + default: \ + break; \ + } \ + } while (0) + +// The following STRIP_LOG testing is performed in the header file so that it's +// possible to completely compile out the logging code and the log messages. +#if !defined(STRIP_LOG) || STRIP_LOG == 0 +#define RAW_VLOG(verboselevel, ...) \ + do { \ + if (VLOG_IS_ON(verboselevel)) { \ + RAW_LOG_INFO(__VA_ARGS__); \ + } \ + } while (0) +#else +#define RAW_VLOG(verboselevel, ...) RawLogStub__(0, __VA_ARGS__) +#endif // STRIP_LOG == 0 + +#if !defined(STRIP_LOG) || STRIP_LOG == 0 +#define RAW_LOG_INFO(...) google::RawLog__(google::GLOG_INFO, \ + __FILE__, __LINE__, __VA_ARGS__) +#else +#define RAW_LOG_INFO(...) google::RawLogStub__(0, __VA_ARGS__) +#endif // STRIP_LOG == 0 + +#if !defined(STRIP_LOG) || STRIP_LOG <= 1 +#define RAW_LOG_WARNING(...) google::RawLog__(google::GLOG_WARNING, \ + __FILE__, __LINE__, __VA_ARGS__) +#else +#define RAW_LOG_WARNING(...) google::RawLogStub__(0, __VA_ARGS__) +#endif // STRIP_LOG <= 1 + +#if !defined(STRIP_LOG) || STRIP_LOG <= 2 +#define RAW_LOG_ERROR(...) google::RawLog__(google::GLOG_ERROR, \ + __FILE__, __LINE__, __VA_ARGS__) +#else +#define RAW_LOG_ERROR(...) google::RawLogStub__(0, __VA_ARGS__) +#endif // STRIP_LOG <= 2 + +#if !defined(STRIP_LOG) || STRIP_LOG <= 3 +#define RAW_LOG_FATAL(...) google::RawLog__(google::GLOG_FATAL, \ + __FILE__, __LINE__, __VA_ARGS__) +#else +#define RAW_LOG_FATAL(...) \ + do { \ + google::RawLogStub__(0, __VA_ARGS__); \ + exit(EXIT_FAILURE); \ + } while (0) +#endif // STRIP_LOG <= 3 + +// Similar to CHECK(condition) << message, +// but for low-level modules: we use only RAW_LOG that does not allocate memory. +// We do not want to provide args list here to encourage this usage: +// if (!cond) RAW_LOG(FATAL, "foo ...", hard_to_compute_args); +// so that the args are not computed when not needed. +#define RAW_CHECK(condition, message) \ + do { \ + if (!(condition)) { \ + RAW_LOG(FATAL, "Check %s failed: %s", #condition, message); \ + } \ + } while (0) + +// Debug versions of RAW_LOG and RAW_CHECK +#ifndef NDEBUG + +#define RAW_DLOG(severity, ...) RAW_LOG(severity, __VA_ARGS__) +#define RAW_DCHECK(condition, message) RAW_CHECK(condition, message) + +#else // NDEBUG + +#define RAW_DLOG(severity, ...) \ + while (false) \ + RAW_LOG(severity, __VA_ARGS__) +#define RAW_DCHECK(condition, message) \ + while (false) \ + RAW_CHECK(condition, message) + +#endif // NDEBUG + +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + +// Stub log function used to work around for unused variable warnings when +// building with STRIP_LOG > 0. +static inline void RawLogStub__(int /* ignored */, ...) { +} + +// Helper function to implement RAW_LOG and RAW_VLOG +// Logs format... at "severity" level, reporting it +// as called from file:line. +// This does not allocate memory or acquire locks. +GLOG_EXPORT void RawLog__(LogSeverity severity, const char* file, int line, + const char* format, ...) + __attribute__((__format__(__printf__, 4, 5))); + +} + +#endif // GLOG_RAW_LOGGING_H diff --git a/funasr/runtime/onnxruntime/include/glog/raw_logging.h.in b/funasr/runtime/onnxruntime/include/glog/raw_logging.h.in new file mode 100644 index 000000000..66fec91e5 --- /dev/null +++ b/funasr/runtime/onnxruntime/include/glog/raw_logging.h.in @@ -0,0 +1,179 @@ +// Copyright (c) 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: Maxim Lifantsev +// +// Thread-safe logging routines that do not allocate any memory or +// acquire any locks, and can therefore be used by low-level memory +// allocation and synchronization code. + +#ifndef GLOG_RAW_LOGGING_H +#define GLOG_RAW_LOGGING_H + +#include + +@ac_google_start_namespace@ + +#include +#include +#include + +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wvariadic-macros" +#endif + +// This is similar to LOG(severity) << format... and VLOG(level) << format.., +// but +// * it is to be used ONLY by low-level modules that can't use normal LOG() +// * it is desiged to be a low-level logger that does not allocate any +// memory and does not need any locks, hence: +// * it logs straight and ONLY to STDERR w/o buffering +// * it uses an explicit format and arguments list +// * it will silently chop off really long message strings +// Usage example: +// RAW_LOG(ERROR, "Failed foo with %i: %s", status, error); +// RAW_VLOG(3, "status is %i", status); +// These will print an almost standard log lines like this to stderr only: +// E20200821 211317 file.cc:123] RAW: Failed foo with 22: bad_file +// I20200821 211317 file.cc:142] RAW: status is 20 +#define RAW_LOG(severity, ...) \ + do { \ + switch (@ac_google_namespace@::GLOG_ ## severity) { \ + case 0: \ + RAW_LOG_INFO(__VA_ARGS__); \ + break; \ + case 1: \ + RAW_LOG_WARNING(__VA_ARGS__); \ + break; \ + case 2: \ + RAW_LOG_ERROR(__VA_ARGS__); \ + break; \ + case 3: \ + RAW_LOG_FATAL(__VA_ARGS__); \ + break; \ + default: \ + break; \ + } \ + } while (0) + +// The following STRIP_LOG testing is performed in the header file so that it's +// possible to completely compile out the logging code and the log messages. +#if !defined(STRIP_LOG) || STRIP_LOG == 0 +#define RAW_VLOG(verboselevel, ...) \ + do { \ + if (VLOG_IS_ON(verboselevel)) { \ + RAW_LOG_INFO(__VA_ARGS__); \ + } \ + } while (0) +#else +#define RAW_VLOG(verboselevel, ...) RawLogStub__(0, __VA_ARGS__) +#endif // STRIP_LOG == 0 + +#if !defined(STRIP_LOG) || STRIP_LOG == 0 +#define RAW_LOG_INFO(...) @ac_google_namespace@::RawLog__(@ac_google_namespace@::GLOG_INFO, \ + __FILE__, __LINE__, __VA_ARGS__) +#else +#define RAW_LOG_INFO(...) @ac_google_namespace@::RawLogStub__(0, __VA_ARGS__) +#endif // STRIP_LOG == 0 + +#if !defined(STRIP_LOG) || STRIP_LOG <= 1 +#define RAW_LOG_WARNING(...) @ac_google_namespace@::RawLog__(@ac_google_namespace@::GLOG_WARNING, \ + __FILE__, __LINE__, __VA_ARGS__) +#else +#define RAW_LOG_WARNING(...) @ac_google_namespace@::RawLogStub__(0, __VA_ARGS__) +#endif // STRIP_LOG <= 1 + +#if !defined(STRIP_LOG) || STRIP_LOG <= 2 +#define RAW_LOG_ERROR(...) @ac_google_namespace@::RawLog__(@ac_google_namespace@::GLOG_ERROR, \ + __FILE__, __LINE__, __VA_ARGS__) +#else +#define RAW_LOG_ERROR(...) @ac_google_namespace@::RawLogStub__(0, __VA_ARGS__) +#endif // STRIP_LOG <= 2 + +#if !defined(STRIP_LOG) || STRIP_LOG <= 3 +#define RAW_LOG_FATAL(...) @ac_google_namespace@::RawLog__(@ac_google_namespace@::GLOG_FATAL, \ + __FILE__, __LINE__, __VA_ARGS__) +#else +#define RAW_LOG_FATAL(...) \ + do { \ + @ac_google_namespace@::RawLogStub__(0, __VA_ARGS__); \ + exit(EXIT_FAILURE); \ + } while (0) +#endif // STRIP_LOG <= 3 + +// Similar to CHECK(condition) << message, +// but for low-level modules: we use only RAW_LOG that does not allocate memory. +// We do not want to provide args list here to encourage this usage: +// if (!cond) RAW_LOG(FATAL, "foo ...", hard_to_compute_args); +// so that the args are not computed when not needed. +#define RAW_CHECK(condition, message) \ + do { \ + if (!(condition)) { \ + RAW_LOG(FATAL, "Check %s failed: %s", #condition, message); \ + } \ + } while (0) + +// Debug versions of RAW_LOG and RAW_CHECK +#ifndef NDEBUG + +#define RAW_DLOG(severity, ...) RAW_LOG(severity, __VA_ARGS__) +#define RAW_DCHECK(condition, message) RAW_CHECK(condition, message) + +#else // NDEBUG + +#define RAW_DLOG(severity, ...) \ + while (false) \ + RAW_LOG(severity, __VA_ARGS__) +#define RAW_DCHECK(condition, message) \ + while (false) \ + RAW_CHECK(condition, message) + +#endif // NDEBUG + +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + +// Stub log function used to work around for unused variable warnings when +// building with STRIP_LOG > 0. +static inline void RawLogStub__(int /* ignored */, ...) { +} + +// Helper function to implement RAW_LOG and RAW_VLOG +// Logs format... at "severity" level, reporting it +// as called from file:line. +// This does not allocate memory or acquire locks. +GLOG_EXPORT void RawLog__(LogSeverity severity, const char* file, int line, + const char* format, ...) + @ac_cv___attribute___printf_4_5@; + +@ac_google_end_namespace@ + +#endif // GLOG_RAW_LOGGING_H diff --git a/funasr/runtime/onnxruntime/include/glog/stl_logging.h b/funasr/runtime/onnxruntime/include/glog/stl_logging.h new file mode 100644 index 000000000..96304e553 --- /dev/null +++ b/funasr/runtime/onnxruntime/include/glog/stl_logging.h @@ -0,0 +1,177 @@ +// Copyright (c) 2003, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Stream output operators for STL containers; to be used for logging *only*. +// Inclusion of this file lets you do: +// +// list x; +// LOG(INFO) << "data: " << x; +// vector v1, v2; +// CHECK_EQ(v1, v2); +// +// If you want to use this header file with hash maps or slist, you +// need to define macros before including this file: +// +// - GLOG_STL_LOGGING_FOR_UNORDERED - and +// - GLOG_STL_LOGGING_FOR_TR1_UNORDERED - +// - GLOG_STL_LOGGING_FOR_EXT_HASH - +// - GLOG_STL_LOGGING_FOR_EXT_SLIST - +// + +#ifndef UTIL_GTL_STL_LOGGING_INL_H_ +#define UTIL_GTL_STL_LOGGING_INL_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Forward declare these two, and define them after all the container streams +// operators so that we can recurse from pair -> container -> container -> pair +// properly. +template +std::ostream& operator<<(std::ostream& out, const std::pair& p); + +namespace google { + +template +void PrintSequence(std::ostream& out, Iter begin, Iter end); + +} +#define OUTPUT_TWO_ARG_CONTAINER(Sequence) \ +template \ +inline std::ostream& operator<<(std::ostream& out, \ + const Sequence& seq) { \ + google::PrintSequence(out, seq.begin(), seq.end()); \ + return out; \ +} + + OUTPUT_TWO_ARG_CONTAINER(std::vector) OUTPUT_TWO_ARG_CONTAINER(std::deque) + OUTPUT_TWO_ARG_CONTAINER(std::list) + +#undef OUTPUT_TWO_ARG_CONTAINER + +#define OUTPUT_THREE_ARG_CONTAINER(Sequence) \ +template \ +inline std::ostream& operator<<(std::ostream& out, \ + const Sequence& seq) { \ + google::PrintSequence(out, seq.begin(), seq.end()); \ + return out; \ +} + + OUTPUT_THREE_ARG_CONTAINER(std::set) OUTPUT_THREE_ARG_CONTAINER( + std::multiset) + +#undef OUTPUT_THREE_ARG_CONTAINER + +#define OUTPUT_FOUR_ARG_CONTAINER(Sequence) \ +template \ +inline std::ostream& operator<<(std::ostream& out, \ + const Sequence& seq) { \ + google::PrintSequence(out, seq.begin(), seq.end()); \ + return out; \ +} + + OUTPUT_FOUR_ARG_CONTAINER(std::map) OUTPUT_FOUR_ARG_CONTAINER( + std::multimap) OUTPUT_FOUR_ARG_CONTAINER(std::unordered_set) + OUTPUT_FOUR_ARG_CONTAINER(std::unordered_multiset) + +#undef OUTPUT_FOUR_ARG_CONTAINER + +#define OUTPUT_FIVE_ARG_CONTAINER(Sequence) \ +template \ +inline std::ostream& operator<<(std::ostream& out, \ + const Sequence& seq) { \ + google::PrintSequence(out, seq.begin(), seq.end()); \ + return out; \ +} + +#if defined(GLOG_STL_LOGGING_FOR_UNORDERED) && __cplusplus >= 201103L + OUTPUT_FIVE_ARG_CONTAINER(std::unordered_map) + OUTPUT_FIVE_ARG_CONTAINER(std::unordered_multimap) +#endif + +#undef OUTPUT_FIVE_ARG_CONTAINER + + template + inline std::ostream& operator<<( + std::ostream& out, + const std::pair& p) { + out << '(' << p.first << ", " << p.second << ')'; + return out; +} + +namespace google { + +template +inline void PrintSequence(std::ostream& out, Iter begin, Iter end) { + // Output at most 100 elements -- appropriate if used for logging. + for (int i = 0; begin != end && i < 100; ++i, ++begin) { + if (i > 0) out << ' '; + out << *begin; + } + if (begin != end) { + out << " ..."; + } +} + +} + +// Note that this is technically undefined behavior! We are adding things into +// the std namespace for a reason though -- we are providing new operations on +// types which are themselves defined with this namespace. Without this, these +// operator overloads cannot be found via ADL. If these definitions are not +// found via ADL, they must be #included before they're used, which requires +// this header to be included before apparently independent other headers. +// +// For example, base/logging.h defines various template functions to implement +// CHECK_EQ(x, y) and stream x and y into the log in the event the check fails. +// It does so via the function template MakeCheckOpValueString: +// template +// void MakeCheckOpValueString(strstream* ss, const T& v) { +// (*ss) << v; +// } +// Because 'glog/logging.h' is included before 'glog/stl_logging.h', +// subsequent CHECK_EQ(v1, v2) for vector<...> typed variable v1 and v2 can only +// find these operator definitions via ADL. +// +// Even this solution has problems -- it may pull unintended operators into the +// namespace as well, allowing them to also be found via ADL, and creating code +// that only works with a particular order of includes. Long term, we need to +// move all of the *definitions* into namespace std, bet we need to ensure no +// one references them first. This lets us take that step. We cannot define them +// in both because that would create ambiguous overloads when both are found. +namespace std { using ::operator<<; } + +#endif // UTIL_GTL_STL_LOGGING_INL_H_ diff --git a/funasr/runtime/onnxruntime/include/glog/stl_logging.h.in b/funasr/runtime/onnxruntime/include/glog/stl_logging.h.in new file mode 100644 index 000000000..49eec0397 --- /dev/null +++ b/funasr/runtime/onnxruntime/include/glog/stl_logging.h.in @@ -0,0 +1,177 @@ +// Copyright (c) 2003, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Stream output operators for STL containers; to be used for logging *only*. +// Inclusion of this file lets you do: +// +// list x; +// LOG(INFO) << "data: " << x; +// vector v1, v2; +// CHECK_EQ(v1, v2); +// +// If you want to use this header file with hash maps or slist, you +// need to define macros before including this file: +// +// - GLOG_STL_LOGGING_FOR_UNORDERED - and +// - GLOG_STL_LOGGING_FOR_TR1_UNORDERED - +// - GLOG_STL_LOGGING_FOR_EXT_HASH - +// - GLOG_STL_LOGGING_FOR_EXT_SLIST - +// + +#ifndef UTIL_GTL_STL_LOGGING_INL_H_ +#define UTIL_GTL_STL_LOGGING_INL_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Forward declare these two, and define them after all the container streams +// operators so that we can recurse from pair -> container -> container -> pair +// properly. +template +std::ostream& operator<<(std::ostream& out, const std::pair& p); + +@ac_google_start_namespace@ + +template +void PrintSequence(std::ostream& out, Iter begin, Iter end); + +@ac_google_end_namespace@ +#define OUTPUT_TWO_ARG_CONTAINER(Sequence) \ +template \ +inline std::ostream& operator<<(std::ostream& out, \ + const Sequence& seq) { \ + @ac_google_namespace@::PrintSequence(out, seq.begin(), seq.end()); \ + return out; \ +} + + OUTPUT_TWO_ARG_CONTAINER(std::vector) OUTPUT_TWO_ARG_CONTAINER(std::deque) + OUTPUT_TWO_ARG_CONTAINER(std::list) + +#undef OUTPUT_TWO_ARG_CONTAINER + +#define OUTPUT_THREE_ARG_CONTAINER(Sequence) \ +template \ +inline std::ostream& operator<<(std::ostream& out, \ + const Sequence& seq) { \ + @ac_google_namespace@::PrintSequence(out, seq.begin(), seq.end()); \ + return out; \ +} + + OUTPUT_THREE_ARG_CONTAINER(std::set) OUTPUT_THREE_ARG_CONTAINER( + std::multiset) + +#undef OUTPUT_THREE_ARG_CONTAINER + +#define OUTPUT_FOUR_ARG_CONTAINER(Sequence) \ +template \ +inline std::ostream& operator<<(std::ostream& out, \ + const Sequence& seq) { \ + @ac_google_namespace@::PrintSequence(out, seq.begin(), seq.end()); \ + return out; \ +} + + OUTPUT_FOUR_ARG_CONTAINER(std::map) OUTPUT_FOUR_ARG_CONTAINER( + std::multimap) OUTPUT_FOUR_ARG_CONTAINER(std::unordered_set) + OUTPUT_FOUR_ARG_CONTAINER(std::unordered_multiset) + +#undef OUTPUT_FOUR_ARG_CONTAINER + +#define OUTPUT_FIVE_ARG_CONTAINER(Sequence) \ +template \ +inline std::ostream& operator<<(std::ostream& out, \ + const Sequence& seq) { \ + @ac_google_namespace@::PrintSequence(out, seq.begin(), seq.end()); \ + return out; \ +} + +#if defined(GLOG_STL_LOGGING_FOR_UNORDERED) && __cplusplus >= 201103L + OUTPUT_FIVE_ARG_CONTAINER(std::unordered_map) + OUTPUT_FIVE_ARG_CONTAINER(std::unordered_multimap) +#endif + +#undef OUTPUT_FIVE_ARG_CONTAINER + + template + inline std::ostream& operator<<( + std::ostream& out, + const std::pair& p) { + out << '(' << p.first << ", " << p.second << ')'; + return out; +} + +@ac_google_start_namespace@ + +template +inline void PrintSequence(std::ostream& out, Iter begin, Iter end) { + // Output at most 100 elements -- appropriate if used for logging. + for (int i = 0; begin != end && i < 100; ++i, ++begin) { + if (i > 0) out << ' '; + out << *begin; + } + if (begin != end) { + out << " ..."; + } +} + +@ac_google_end_namespace@ + +// Note that this is technically undefined behavior! We are adding things into +// the std namespace for a reason though -- we are providing new operations on +// types which are themselves defined with this namespace. Without this, these +// operator overloads cannot be found via ADL. If these definitions are not +// found via ADL, they must be #included before they're used, which requires +// this header to be included before apparently independent other headers. +// +// For example, base/logging.h defines various template functions to implement +// CHECK_EQ(x, y) and stream x and y into the log in the event the check fails. +// It does so via the function template MakeCheckOpValueString: +// template +// void MakeCheckOpValueString(strstream* ss, const T& v) { +// (*ss) << v; +// } +// Because 'glog/logging.h' is included before 'glog/stl_logging.h', +// subsequent CHECK_EQ(v1, v2) for vector<...> typed variable v1 and v2 can only +// find these operator definitions via ADL. +// +// Even this solution has problems -- it may pull unintended operators into the +// namespace as well, allowing them to also be found via ADL, and creating code +// that only works with a particular order of includes. Long term, we need to +// move all of the *definitions* into namespace std, bet we need to ensure no +// one references them first. This lets us take that step. We cannot define them +// in both because that would create ambiguous overloads when both are found. +namespace std { using ::operator<<; } + +#endif // UTIL_GTL_STL_LOGGING_INL_H_ diff --git a/funasr/runtime/onnxruntime/include/glog/vlog_is_on.h b/funasr/runtime/onnxruntime/include/glog/vlog_is_on.h new file mode 100644 index 000000000..44c204857 --- /dev/null +++ b/funasr/runtime/onnxruntime/include/glog/vlog_is_on.h @@ -0,0 +1,120 @@ +// Copyright (c) 2023, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: Ray Sidney and many others +// +// Defines the VLOG_IS_ON macro that controls the variable-verbosity +// conditional logging. +// +// It's used by VLOG and VLOG_IF in logging.h +// and by RAW_VLOG in raw_logging.h to trigger the logging. +// +// It can also be used directly e.g. like this: +// if (VLOG_IS_ON(2)) { +// // do some logging preparation and logging +// // that can't be accomplished e.g. via just VLOG(2) << ...; +// } +// +// The truth value that VLOG_IS_ON(level) returns is determined by +// the three verbosity level flags: +// --v= Gives the default maximal active V-logging level; +// 0 is the default. +// Normally positive values are used for V-logging levels. +// --vmodule= Gives the per-module maximal V-logging levels to override +// the value given by --v. +// E.g. "my_module=2,foo*=3" would change the logging level +// for all code in source files "my_module.*" and "foo*.*" +// ("-inl" suffixes are also disregarded for this matching). +// +// SetVLOGLevel helper function is provided to do limited dynamic control over +// V-logging by overriding the per-module settings given via --vmodule flag. +// +// CAVEAT: --vmodule functionality is not available in non gcc compilers. +// + +#ifndef BASE_VLOG_IS_ON_H_ +#define BASE_VLOG_IS_ON_H_ + +#include + +#include + +#if defined(__GNUC__) +// We emit an anonymous static int* variable at every VLOG_IS_ON(n) site. +// (Normally) the first time every VLOG_IS_ON(n) site is hit, +// we determine what variable will dynamically control logging at this site: +// it's either FLAGS_v or an appropriate internal variable +// matching the current source file that represents results of +// parsing of --vmodule flag and/or SetVLOGLevel calls. +#define VLOG_IS_ON(verboselevel) \ + __extension__ \ + ({ static google::SiteFlag vlocal__ = {NULL, NULL, 0, NULL}; \ + google::int32 verbose_level__ = (verboselevel); \ + (vlocal__.level == NULL ? google::InitVLOG3__(&vlocal__, &FLAGS_v, \ + __FILE__, verbose_level__) : *vlocal__.level >= verbose_level__); \ + }) +#else +// GNU extensions not available, so we do not support --vmodule. +// Dynamic value of FLAGS_v always controls the logging level. +#define VLOG_IS_ON(verboselevel) (FLAGS_v >= (verboselevel)) +#endif + +// Set VLOG(_IS_ON) level for module_pattern to log_level. +// This lets us dynamically control what is normally set by the --vmodule flag. +// Returns the level that previously applied to module_pattern. +// NOTE: To change the log level for VLOG(_IS_ON) sites +// that have already executed after/during InitGoogleLogging, +// one needs to supply the exact --vmodule pattern that applied to them. +// (If no --vmodule pattern applied to them +// the value of FLAGS_v will continue to control them.) +extern GLOG_EXPORT int SetVLOGLevel(const char* module_pattern, int log_level); + +// Various declarations needed for VLOG_IS_ON above: ========================= + +struct SiteFlag { + google::int32* level; + const char* base_name; + std::size_t base_len; + SiteFlag* next; +}; + +// Helper routine which determines the logging info for a particalur VLOG site. +// site_flag is the address of the site-local pointer to the controlling +// verbosity level +// site_default is the default to use for *site_flag +// fname is the current source file name +// verbose_level is the argument to VLOG_IS_ON +// We will return the return value for VLOG_IS_ON +// and if possible set *site_flag appropriately. +extern GLOG_EXPORT bool InitVLOG3__( + google::SiteFlag* site_flag, + google::int32* site_default, const char* fname, + google::int32 verbose_level); + +#endif // BASE_VLOG_IS_ON_H_ diff --git a/funasr/runtime/onnxruntime/include/glog/vlog_is_on.h.in b/funasr/runtime/onnxruntime/include/glog/vlog_is_on.h.in new file mode 100644 index 000000000..ed37e0d35 --- /dev/null +++ b/funasr/runtime/onnxruntime/include/glog/vlog_is_on.h.in @@ -0,0 +1,120 @@ +// Copyright (c) 2023, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: Ray Sidney and many others +// +// Defines the VLOG_IS_ON macro that controls the variable-verbosity +// conditional logging. +// +// It's used by VLOG and VLOG_IF in logging.h +// and by RAW_VLOG in raw_logging.h to trigger the logging. +// +// It can also be used directly e.g. like this: +// if (VLOG_IS_ON(2)) { +// // do some logging preparation and logging +// // that can't be accomplished e.g. via just VLOG(2) << ...; +// } +// +// The truth value that VLOG_IS_ON(level) returns is determined by +// the three verbosity level flags: +// --v= Gives the default maximal active V-logging level; +// 0 is the default. +// Normally positive values are used for V-logging levels. +// --vmodule= Gives the per-module maximal V-logging levels to override +// the value given by --v. +// E.g. "my_module=2,foo*=3" would change the logging level +// for all code in source files "my_module.*" and "foo*.*" +// ("-inl" suffixes are also disregarded for this matching). +// +// SetVLOGLevel helper function is provided to do limited dynamic control over +// V-logging by overriding the per-module settings given via --vmodule flag. +// +// CAVEAT: --vmodule functionality is not available in non gcc compilers. +// + +#ifndef BASE_VLOG_IS_ON_H_ +#define BASE_VLOG_IS_ON_H_ + +#include + +#include + +#if defined(__GNUC__) +// We emit an anonymous static int* variable at every VLOG_IS_ON(n) site. +// (Normally) the first time every VLOG_IS_ON(n) site is hit, +// we determine what variable will dynamically control logging at this site: +// it's either FLAGS_v or an appropriate internal variable +// matching the current source file that represents results of +// parsing of --vmodule flag and/or SetVLOGLevel calls. +#define VLOG_IS_ON(verboselevel) \ + __extension__ \ + ({ static @ac_google_namespace@::SiteFlag vlocal__ = {NULL, NULL, 0, NULL}; \ + @ac_google_namespace@::int32 verbose_level__ = (verboselevel); \ + (vlocal__.level == NULL ? @ac_google_namespace@::InitVLOG3__(&vlocal__, &FLAGS_v, \ + __FILE__, verbose_level__) : *vlocal__.level >= verbose_level__); \ + }) +#else +// GNU extensions not available, so we do not support --vmodule. +// Dynamic value of FLAGS_v always controls the logging level. +#define VLOG_IS_ON(verboselevel) (FLAGS_v >= (verboselevel)) +#endif + +// Set VLOG(_IS_ON) level for module_pattern to log_level. +// This lets us dynamically control what is normally set by the --vmodule flag. +// Returns the level that previously applied to module_pattern. +// NOTE: To change the log level for VLOG(_IS_ON) sites +// that have already executed after/during InitGoogleLogging, +// one needs to supply the exact --vmodule pattern that applied to them. +// (If no --vmodule pattern applied to them +// the value of FLAGS_v will continue to control them.) +extern GLOG_EXPORT int SetVLOGLevel(const char* module_pattern, int log_level); + +// Various declarations needed for VLOG_IS_ON above: ========================= + +struct SiteFlag { + @ac_google_namespace@::int32* level; + const char* base_name; + std::size_t base_len; + SiteFlag* next; +}; + +// Helper routine which determines the logging info for a particalur VLOG site. +// site_flag is the address of the site-local pointer to the controlling +// verbosity level +// site_default is the default to use for *site_flag +// fname is the current source file name +// verbose_level is the argument to VLOG_IS_ON +// We will return the return value for VLOG_IS_ON +// and if possible set *site_flag appropriately. +extern GLOG_EXPORT bool InitVLOG3__( + @ac_google_namespace@::SiteFlag* site_flag, + @ac_google_namespace@::int32* site_default, const char* fname, + @ac_google_namespace@::int32 verbose_level); + +#endif // BASE_VLOG_IS_ON_H_ diff --git a/funasr/runtime/onnxruntime/include/model.h b/funasr/runtime/onnxruntime/include/model.h index 786fd28d1..44bd02230 100644 --- a/funasr/runtime/onnxruntime/include/model.h +++ b/funasr/runtime/onnxruntime/include/model.h @@ -4,7 +4,7 @@ #include #include - +namespace funasr { class Model { public: virtual ~Model(){}; @@ -16,4 +16,5 @@ class Model { }; Model *CreateModel(std::map& model_path,int thread_num=1); +} // namespace funasr #endif diff --git a/funasr/runtime/onnxruntime/include/offline-stream.h b/funasr/runtime/onnxruntime/include/offline-stream.h index caa4ea62b..a9ce88eaf 100644 --- a/funasr/runtime/onnxruntime/include/offline-stream.h +++ b/funasr/runtime/onnxruntime/include/offline-stream.h @@ -8,6 +8,7 @@ #include "punc-model.h" #include "vad-model.h" +namespace funasr { class OfflineStream { public: OfflineStream(std::map& model_path, int thread_num); @@ -25,4 +26,5 @@ class OfflineStream { }; OfflineStream *CreateOfflineStream(std::map& model_path, int thread_num=1); +} // namespace funasr #endif diff --git a/funasr/runtime/onnxruntime/include/punc-model.h b/funasr/runtime/onnxruntime/include/punc-model.h index 0bb353abe..da7ff6086 100644 --- a/funasr/runtime/onnxruntime/include/punc-model.h +++ b/funasr/runtime/onnxruntime/include/punc-model.h @@ -6,6 +6,7 @@ #include #include +namespace funasr { class PuncModel { public: virtual ~PuncModel(){}; @@ -15,4 +16,5 @@ class PuncModel { }; PuncModel *CreatePuncModel(std::map& model_path, int thread_num); +} // namespace funasr #endif diff --git a/funasr/runtime/onnxruntime/include/vad-model.h b/funasr/runtime/onnxruntime/include/vad-model.h index 646a1e954..2a8d6e4d6 100644 --- a/funasr/runtime/onnxruntime/include/vad-model.h +++ b/funasr/runtime/onnxruntime/include/vad-model.h @@ -6,6 +6,7 @@ #include #include +namespace funasr { class VadModel { public: virtual ~VadModel(){}; @@ -24,4 +25,5 @@ class VadModel { }; VadModel *CreateVadModel(std::map& model_path, int thread_num); +} // namespace funasr #endif From e619b649384385c3f9fe10c068734a783c56bb94 Mon Sep 17 00:00:00 2001 From: lyblsgo Date: Mon, 8 May 2023 20:32:37 +0800 Subject: [PATCH 089/120] rm include/glog --- .../runtime/onnxruntime/include/glog/export.h | 42 - .../onnxruntime/include/glog/log_severity.h | 98 - .../onnxruntime/include/glog/logging.h | 1842 ----------------- .../onnxruntime/include/glog/logging.h.in | 1842 ----------------- .../onnxruntime/include/glog/platform.h | 60 - .../onnxruntime/include/glog/raw_logging.h | 179 -- .../onnxruntime/include/glog/raw_logging.h.in | 179 -- .../onnxruntime/include/glog/stl_logging.h | 177 -- .../onnxruntime/include/glog/stl_logging.h.in | 177 -- .../onnxruntime/include/glog/vlog_is_on.h | 120 -- .../onnxruntime/include/glog/vlog_is_on.h.in | 120 -- 11 files changed, 4836 deletions(-) delete mode 100644 funasr/runtime/onnxruntime/include/glog/export.h delete mode 100644 funasr/runtime/onnxruntime/include/glog/log_severity.h delete mode 100644 funasr/runtime/onnxruntime/include/glog/logging.h delete mode 100644 funasr/runtime/onnxruntime/include/glog/logging.h.in delete mode 100644 funasr/runtime/onnxruntime/include/glog/platform.h delete mode 100644 funasr/runtime/onnxruntime/include/glog/raw_logging.h delete mode 100644 funasr/runtime/onnxruntime/include/glog/raw_logging.h.in delete mode 100644 funasr/runtime/onnxruntime/include/glog/stl_logging.h delete mode 100644 funasr/runtime/onnxruntime/include/glog/stl_logging.h.in delete mode 100644 funasr/runtime/onnxruntime/include/glog/vlog_is_on.h delete mode 100644 funasr/runtime/onnxruntime/include/glog/vlog_is_on.h.in diff --git a/funasr/runtime/onnxruntime/include/glog/export.h b/funasr/runtime/onnxruntime/include/glog/export.h deleted file mode 100644 index 1ad80af5b..000000000 --- a/funasr/runtime/onnxruntime/include/glog/export.h +++ /dev/null @@ -1,42 +0,0 @@ - -#ifndef GLOG_EXPORT_H -#define GLOG_EXPORT_H - -#ifdef GLOG_STATIC_DEFINE -# define GLOG_EXPORT -# define GLOG_NO_EXPORT -#else -# ifndef GLOG_EXPORT -# ifdef GOOGLE_GLOG_IS_A_DLL - /* We are building this library */ -# define GLOG_EXPORT -# else - /* We are using this library */ -# define GLOG_EXPORT -# endif -# endif - -# ifndef GLOG_NO_EXPORT -# define GLOG_NO_EXPORT -# endif -#endif - -#ifndef GLOG_DEPRECATED -# define GLOG_DEPRECATED __attribute__ ((__deprecated__)) -#endif - -#ifndef GLOG_DEPRECATED_EXPORT -# define GLOG_DEPRECATED_EXPORT GLOG_EXPORT GLOG_DEPRECATED -#endif - -#ifndef GLOG_DEPRECATED_NO_EXPORT -# define GLOG_DEPRECATED_NO_EXPORT GLOG_NO_EXPORT GLOG_DEPRECATED -#endif - -#if 0 /* DEFINE_NO_DEPRECATED */ -# ifndef GLOG_NO_DEPRECATED -# define GLOG_NO_DEPRECATED -# endif -#endif - -#endif /* GLOG_EXPORT_H */ diff --git a/funasr/runtime/onnxruntime/include/glog/log_severity.h b/funasr/runtime/onnxruntime/include/glog/log_severity.h deleted file mode 100644 index d52989d72..000000000 --- a/funasr/runtime/onnxruntime/include/glog/log_severity.h +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright (c) 2023, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef BASE_LOG_SEVERITY_H__ -#define BASE_LOG_SEVERITY_H__ - -// The recommended semantics of the log levels are as follows: -// -// INFO: -// Use for state changes or other major events, or to aid debugging. -// WARNING: -// Use for undesired but relatively expected events, which may indicate a -// problem -// ERROR: -// Use for undesired and unexpected events that the program can recover from. -// All ERRORs should be actionable - it should be appropriate to file a bug -// whenever an ERROR occurs in production. -// FATAL: -// Use for undesired and unexpected events that the program cannot recover -// from. - -// Variables of type LogSeverity are widely taken to lie in the range -// [0, NUM_SEVERITIES-1]. Be careful to preserve this assumption if -// you ever need to change their values or add a new severity. -using LogSeverity = int; - -const int GLOG_INFO = 0, GLOG_WARNING = 1, GLOG_ERROR = 2, GLOG_FATAL = 3, - NUM_SEVERITIES = 4; -#ifndef GLOG_NO_ABBREVIATED_SEVERITIES -# ifdef ERROR -# error ERROR macro is defined. Define GLOG_NO_ABBREVIATED_SEVERITIES before including logging.h. See the document for detail. -# endif -const int INFO = GLOG_INFO, WARNING = GLOG_WARNING, - ERROR = GLOG_ERROR, FATAL = GLOG_FATAL; -#endif - -// DFATAL is FATAL in debug mode, ERROR in normal mode -#ifdef NDEBUG -#define DFATAL_LEVEL ERROR -#else -#define DFATAL_LEVEL FATAL -#endif - -extern GLOG_EXPORT const char* const LogSeverityNames[NUM_SEVERITIES]; - -// NDEBUG usage helpers related to (RAW_)DCHECK: -// -// DEBUG_MODE is for small !NDEBUG uses like -// if (DEBUG_MODE) foo.CheckThatFoo(); -// instead of substantially more verbose -// #ifndef NDEBUG -// foo.CheckThatFoo(); -// #endif -// -// IF_DEBUG_MODE is for small !NDEBUG uses like -// IF_DEBUG_MODE( string error; ) -// DCHECK(Foo(&error)) << error; -// instead of substantially more verbose -// #ifndef NDEBUG -// string error; -// DCHECK(Foo(&error)) << error; -// #endif -// -#ifdef NDEBUG -enum { DEBUG_MODE = 0 }; -#define IF_DEBUG_MODE(x) -#else -enum { DEBUG_MODE = 1 }; -#define IF_DEBUG_MODE(x) x -#endif - -#endif // BASE_LOG_SEVERITY_H__ diff --git a/funasr/runtime/onnxruntime/include/glog/logging.h b/funasr/runtime/onnxruntime/include/glog/logging.h deleted file mode 100644 index 6f6685a44..000000000 --- a/funasr/runtime/onnxruntime/include/glog/logging.h +++ /dev/null @@ -1,1842 +0,0 @@ -// Copyright (c) 2023, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Author: Ray Sidney -// -// This file contains #include information about logging-related stuff. -// Pretty much everybody needs to #include this file so that they can -// log various happenings. -// -#ifndef GLOG_LOGGING_H -#define GLOG_LOGGING_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if 1 -# include -#endif -#include - -#if defined(_MSC_VER) -#define GLOG_MSVC_PUSH_DISABLE_WARNING(n) __pragma(warning(push)) \ - __pragma(warning(disable:n)) -#define GLOG_MSVC_POP_WARNING() __pragma(warning(pop)) -#else -#define GLOG_MSVC_PUSH_DISABLE_WARNING(n) -#define GLOG_MSVC_POP_WARNING() -#endif - -#include - -#if 1 -#include -#endif - -// We care a lot about number of bits things take up. Unfortunately, -// systems define their bit-specific ints in a lot of different ways. -// We use our own way, and have a typedef to get there. -// Note: these commands below may look like "#if 1" or "#if 0", but -// that's because they were constructed that way at ./configure time. -// Look at logging.h.in to see how they're calculated (based on your config). -#include // the normal place uint16_t is defined -#if 1 -#include // the normal place u_int16_t is defined -#endif - -#if 0 -#include -#endif - -#include - -namespace google { - - typedef std::int32_t int32; -typedef std::uint32_t uint32; -typedef std::int64_t int64; -typedef std::uint64_t uint64; - -#if !(1) -typedef ptrdiff_t ssize_t; -#endif - -#if !(1) -typedef int mode_t; -#endif - -typedef double WallTime; - -struct GLOG_EXPORT LogMessageTime { - LogMessageTime(); - LogMessageTime(std::tm t); - LogMessageTime(std::time_t timestamp, WallTime now); - - const time_t& timestamp() const { return timestamp_; } - const int& sec() const { return time_struct_.tm_sec; } - const int32_t& usec() const { return usecs_; } - const int&(min)() const { return time_struct_.tm_min; } - const int& hour() const { return time_struct_.tm_hour; } - const int& day() const { return time_struct_.tm_mday; } - const int& month() const { return time_struct_.tm_mon; } - const int& year() const { return time_struct_.tm_year; } - const int& dayOfWeek() const { return time_struct_.tm_wday; } - const int& dayInYear() const { return time_struct_.tm_yday; } - const int& dst() const { return time_struct_.tm_isdst; } - const long int& gmtoff() const { return gmtoffset_; } - const std::tm& tm() const { return time_struct_; } - - private: - void init(const std::tm& t, std::time_t timestamp, WallTime now); - std::tm time_struct_; // Time of creation of LogMessage - time_t timestamp_; // Time of creation of LogMessage in seconds - int32_t usecs_; // Time of creation of LogMessage - microseconds part - long int gmtoffset_; - - void CalcGmtOffset(); -}; - -struct LogMessageInfo { - explicit LogMessageInfo(const char* const severity_, - const char* const filename_, - const int& line_number_, - const int& thread_id_, - const LogMessageTime& time_): - severity(severity_), filename(filename_), line_number(line_number_), - thread_id(thread_id_), time(time_) - {} - - const char* const severity; - const char* const filename; - const int &line_number; - const int &thread_id; - const LogMessageTime& time; -}; - -typedef void(*CustomPrefixCallback)(std::ostream& s, const LogMessageInfo& l, void* data); - -} - - -// The global value of GOOGLE_STRIP_LOG. All the messages logged to -// LOG(XXX) with severity less than GOOGLE_STRIP_LOG will not be displayed. -// If it can be determined at compile time that the message will not be -// printed, the statement will be compiled out. -// -// Example: to strip out all INFO and WARNING messages, use the value -// of 2 below. To make an exception for WARNING messages from a single -// file, add "#define GOOGLE_STRIP_LOG 1" to that file _before_ including -// base/logging.h -#ifndef GOOGLE_STRIP_LOG -#define GOOGLE_STRIP_LOG 0 -#endif - -// GCC can be told that a certain branch is not likely to be taken (for -// instance, a CHECK failure), and use that information in static analysis. -// Giving it this information can help it optimize for the common case in -// the absence of better information (ie. -fprofile-arcs). -// -#ifndef GOOGLE_PREDICT_BRANCH_NOT_TAKEN -#if 1 -#define GOOGLE_PREDICT_BRANCH_NOT_TAKEN(x) (__builtin_expect(x, 0)) -#else -#define GOOGLE_PREDICT_BRANCH_NOT_TAKEN(x) x -#endif -#endif - -#ifndef GOOGLE_PREDICT_FALSE -#if 1 -#define GOOGLE_PREDICT_FALSE(x) (__builtin_expect(x, 0)) -#else -#define GOOGLE_PREDICT_FALSE(x) x -#endif -#endif - -#ifndef GOOGLE_PREDICT_TRUE -#if 1 -#define GOOGLE_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1)) -#else -#define GOOGLE_PREDICT_TRUE(x) x -#endif -#endif - - -// Make a bunch of macros for logging. The way to log things is to stream -// things to LOG(). E.g., -// -// LOG(INFO) << "Found " << num_cookies << " cookies"; -// -// You can capture log messages in a string, rather than reporting them -// immediately: -// -// vector errors; -// LOG_STRING(ERROR, &errors) << "Couldn't parse cookie #" << cookie_num; -// -// This pushes back the new error onto 'errors'; if given a NULL pointer, -// it reports the error via LOG(ERROR). -// -// You can also do conditional logging: -// -// LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies"; -// -// You can also do occasional logging (log every n'th occurrence of an -// event): -// -// LOG_EVERY_N(INFO, 10) << "Got the " << google::COUNTER << "th cookie"; -// -// The above will cause log messages to be output on the 1st, 11th, 21st, ... -// times it is executed. Note that the special google::COUNTER value is used -// to identify which repetition is happening. -// -// You can also do occasional conditional logging (log every n'th -// occurrence of an event, when condition is satisfied): -// -// LOG_IF_EVERY_N(INFO, (size > 1024), 10) << "Got the " << google::COUNTER -// << "th big cookie"; -// -// You can log messages the first N times your code executes a line. E.g. -// -// LOG_FIRST_N(INFO, 20) << "Got the " << google::COUNTER << "th cookie"; -// -// Outputs log messages for the first 20 times it is executed. -// -// Analogous SYSLOG, SYSLOG_IF, and SYSLOG_EVERY_N macros are available. -// These log to syslog as well as to the normal logs. If you use these at -// all, you need to be aware that syslog can drastically reduce performance, -// especially if it is configured for remote logging! Don't use these -// unless you fully understand this and have a concrete need to use them. -// Even then, try to minimize your use of them. -// -// There are also "debug mode" logging macros like the ones above: -// -// DLOG(INFO) << "Found cookies"; -// -// DLOG_IF(INFO, num_cookies > 10) << "Got lots of cookies"; -// -// DLOG_EVERY_N(INFO, 10) << "Got the " << google::COUNTER << "th cookie"; -// -// All "debug mode" logging is compiled away to nothing for non-debug mode -// compiles. -// -// We also have -// -// LOG_ASSERT(assertion); -// DLOG_ASSERT(assertion); -// -// which is syntactic sugar for {,D}LOG_IF(FATAL, assert fails) << assertion; -// -// There are "verbose level" logging macros. They look like -// -// VLOG(1) << "I'm printed when you run the program with --v=1 or more"; -// VLOG(2) << "I'm printed when you run the program with --v=2 or more"; -// -// These always log at the INFO log level (when they log at all). -// The verbose logging can also be turned on module-by-module. For instance, -// --vmodule=mapreduce=2,file=1,gfs*=3 --v=0 -// will cause: -// a. VLOG(2) and lower messages to be printed from mapreduce.{h,cc} -// b. VLOG(1) and lower messages to be printed from file.{h,cc} -// c. VLOG(3) and lower messages to be printed from files prefixed with "gfs" -// d. VLOG(0) and lower messages to be printed from elsewhere -// -// The wildcarding functionality shown by (c) supports both '*' (match -// 0 or more characters) and '?' (match any single character) wildcards. -// -// There's also VLOG_IS_ON(n) "verbose level" condition macro. To be used as -// -// if (VLOG_IS_ON(2)) { -// // do some logging preparation and logging -// // that can't be accomplished with just VLOG(2) << ...; -// } -// -// There are also VLOG_IF, VLOG_EVERY_N and VLOG_IF_EVERY_N "verbose level" -// condition macros for sample cases, when some extra computation and -// preparation for logs is not needed. -// VLOG_IF(1, (size > 1024)) -// << "I'm printed when size is more than 1024 and when you run the " -// "program with --v=1 or more"; -// VLOG_EVERY_N(1, 10) -// << "I'm printed every 10th occurrence, and when you run the program " -// "with --v=1 or more. Present occurence is " << google::COUNTER; -// VLOG_IF_EVERY_N(1, (size > 1024), 10) -// << "I'm printed on every 10th occurence of case when size is more " -// " than 1024, when you run the program with --v=1 or more. "; -// "Present occurence is " << google::COUNTER; -// -// The supported severity levels for macros that allow you to specify one -// are (in increasing order of severity) INFO, WARNING, ERROR, and FATAL. -// Note that messages of a given severity are logged not only in the -// logfile for that severity, but also in all logfiles of lower severity. -// E.g., a message of severity FATAL will be logged to the logfiles of -// severity FATAL, ERROR, WARNING, and INFO. -// -// There is also the special severity of DFATAL, which logs FATAL in -// debug mode, ERROR in normal mode. -// -// Very important: logging a message at the FATAL severity level causes -// the program to terminate (after the message is logged). -// -// Unless otherwise specified, logs will be written to the filename -// "...log..", followed -// by the date, time, and pid (you can't prevent the date, time, and pid -// from being in the filename). -// -// The logging code takes two flags: -// --v=# set the verbose level -// --logtostderr log all the messages to stderr instead of to logfiles - -// LOG LINE PREFIX FORMAT -// -// Log lines have this form: -// -// Lyyyymmdd hh:mm:ss.uuuuuu threadid file:line] msg... -// -// where the fields are defined as follows: -// -// L A single character, representing the log level -// (eg 'I' for INFO) -// yyyy The year -// mm The month (zero padded; ie May is '05') -// dd The day (zero padded) -// hh:mm:ss.uuuuuu Time in hours, minutes and fractional seconds -// threadid The space-padded thread ID as returned by GetTID() -// (this matches the PID on Linux) -// file The file name -// line The line number -// msg The user-supplied message -// -// Example: -// -// I1103 11:57:31.739339 24395 google.cc:2341] Command line: ./some_prog -// I1103 11:57:31.739403 24395 google.cc:2342] Process id 24395 -// -// NOTE: although the microseconds are useful for comparing events on -// a single machine, clocks on different machines may not be well -// synchronized. Hence, use caution when comparing the low bits of -// timestamps from different machines. - -#pragma push_macro("DECLARE_VARIABLE") -#pragma push_macro("DECLARE_bool") -#pragma push_macro("DECLARE_string") -#pragma push_macro("DECLARE_int32") -#pragma push_macro("DECLARE_uint32") - -#ifdef DECLARE_VARIABLE -#undef DECLARE_VARIABLE -#endif - -#ifdef DECLARE_bool -#undef DECLARE_bool -#endif - -#ifdef DECLARE_string -#undef DECLARE_string -#endif - -#ifdef DECLARE_int32 -#undef DECLARE_int32 -#endif - -#ifdef DECLARE_uint32 -#undef DECLARE_uint32 -#endif - -#ifndef DECLARE_VARIABLE -#define DECLARE_VARIABLE(type, shorttype, name, tn) \ - namespace fL##shorttype { \ - extern GLOG_EXPORT type FLAGS_##name; \ - } \ - using fL##shorttype::FLAGS_##name - -// bool specialization -#define DECLARE_bool(name) \ - DECLARE_VARIABLE(bool, B, name, bool) - -// int32 specialization -#define DECLARE_int32(name) \ - DECLARE_VARIABLE(google::int32, I, name, int32) - -#if !defined(DECLARE_uint32) -// uint32 specialization -#define DECLARE_uint32(name) \ - DECLARE_VARIABLE(google::uint32, U, name, uint32) -#endif // !defined(DECLARE_uint32) && !(0) - -// Special case for string, because we have to specify the namespace -// std::string, which doesn't play nicely with our FLAG__namespace hackery. -#define DECLARE_string(name) \ - namespace fLS { \ - extern GLOG_EXPORT std::string& FLAGS_##name; \ - } \ - using fLS::FLAGS_##name -#endif - -// Set whether appending a timestamp to the log file name -DECLARE_bool(timestamp_in_logfile_name); - -// Set whether log messages go to stdout instead of logfiles -DECLARE_bool(logtostdout); - -// Set color messages logged to stdout (if supported by terminal). -DECLARE_bool(colorlogtostdout); - -// Set whether log messages go to stderr instead of logfiles -DECLARE_bool(logtostderr); - -// Set whether log messages go to stderr in addition to logfiles. -DECLARE_bool(alsologtostderr); - -// Set color messages logged to stderr (if supported by terminal). -DECLARE_bool(colorlogtostderr); - -// Log messages at a level >= this flag are automatically sent to -// stderr in addition to log files. -DECLARE_int32(stderrthreshold); - -// Set whether the log file header should be written upon creating a file. -DECLARE_bool(log_file_header); - -// Set whether the log prefix should be prepended to each line of output. -DECLARE_bool(log_prefix); - -// Set whether the year should be included in the log prefix. -DECLARE_bool(log_year_in_prefix); - -// Log messages at a level <= this flag are buffered. -// Log messages at a higher level are flushed immediately. -DECLARE_int32(logbuflevel); - -// Sets the maximum number of seconds which logs may be buffered for. -DECLARE_int32(logbufsecs); - -// Log suppression level: messages logged at a lower level than this -// are suppressed. -DECLARE_int32(minloglevel); - -// If specified, logfiles are written into this directory instead of the -// default logging directory. -DECLARE_string(log_dir); - -// Set the log file mode. -DECLARE_int32(logfile_mode); - -// Sets the path of the directory into which to put additional links -// to the log files. -DECLARE_string(log_link); - -DECLARE_int32(v); // in vlog_is_on.cc - -DECLARE_string(vmodule); // also in vlog_is_on.cc - -// Sets the maximum log file size (in MB). -DECLARE_uint32(max_log_size); - -// Sets whether to avoid logging to the disk if the disk is full. -DECLARE_bool(stop_logging_if_full_disk); - -// Use UTC time for logging -DECLARE_bool(log_utc_time); - -// Log messages below the GOOGLE_STRIP_LOG level will be compiled away for -// security reasons. See LOG(severtiy) below. - -// A few definitions of macros that don't generate much code. Since -// LOG(INFO) and its ilk are used all over our code, it's -// better to have compact code for these operations. - -#if GOOGLE_STRIP_LOG == 0 -#define COMPACT_GOOGLE_LOG_INFO google::LogMessage( \ - __FILE__, __LINE__) -#define LOG_TO_STRING_INFO(message) google::LogMessage( \ - __FILE__, __LINE__, google::GLOG_INFO, message) -#else -#define COMPACT_GOOGLE_LOG_INFO google::NullStream() -#define LOG_TO_STRING_INFO(message) google::NullStream() -#endif - -#if GOOGLE_STRIP_LOG <= 1 -#define COMPACT_GOOGLE_LOG_WARNING google::LogMessage( \ - __FILE__, __LINE__, google::GLOG_WARNING) -#define LOG_TO_STRING_WARNING(message) google::LogMessage( \ - __FILE__, __LINE__, google::GLOG_WARNING, message) -#else -#define COMPACT_GOOGLE_LOG_WARNING google::NullStream() -#define LOG_TO_STRING_WARNING(message) google::NullStream() -#endif - -#if GOOGLE_STRIP_LOG <= 2 -#define COMPACT_GOOGLE_LOG_ERROR google::LogMessage( \ - __FILE__, __LINE__, google::GLOG_ERROR) -#define LOG_TO_STRING_ERROR(message) google::LogMessage( \ - __FILE__, __LINE__, google::GLOG_ERROR, message) -#else -#define COMPACT_GOOGLE_LOG_ERROR google::NullStream() -#define LOG_TO_STRING_ERROR(message) google::NullStream() -#endif - -#if GOOGLE_STRIP_LOG <= 3 -#define COMPACT_GOOGLE_LOG_FATAL google::LogMessageFatal( \ - __FILE__, __LINE__) -#define LOG_TO_STRING_FATAL(message) google::LogMessage( \ - __FILE__, __LINE__, google::GLOG_FATAL, message) -#else -#define COMPACT_GOOGLE_LOG_FATAL google::NullStreamFatal() -#define LOG_TO_STRING_FATAL(message) google::NullStreamFatal() -#endif - -#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON) -#define DCHECK_IS_ON() 0 -#else -#define DCHECK_IS_ON() 1 -#endif - -// For DFATAL, we want to use LogMessage (as opposed to -// LogMessageFatal), to be consistent with the original behavior. -#if !DCHECK_IS_ON() -#define COMPACT_GOOGLE_LOG_DFATAL COMPACT_GOOGLE_LOG_ERROR -#elif GOOGLE_STRIP_LOG <= 3 -#define COMPACT_GOOGLE_LOG_DFATAL google::LogMessage( \ - __FILE__, __LINE__, google::GLOG_FATAL) -#else -#define COMPACT_GOOGLE_LOG_DFATAL google::NullStreamFatal() -#endif - -#define GOOGLE_LOG_INFO(counter) google::LogMessage(__FILE__, __LINE__, google::GLOG_INFO, counter, &google::LogMessage::SendToLog) -#define SYSLOG_INFO(counter) \ - google::LogMessage(__FILE__, __LINE__, google::GLOG_INFO, counter, \ - &google::LogMessage::SendToSyslogAndLog) -#define GOOGLE_LOG_WARNING(counter) \ - google::LogMessage(__FILE__, __LINE__, google::GLOG_WARNING, counter, \ - &google::LogMessage::SendToLog) -#define SYSLOG_WARNING(counter) \ - google::LogMessage(__FILE__, __LINE__, google::GLOG_WARNING, counter, \ - &google::LogMessage::SendToSyslogAndLog) -#define GOOGLE_LOG_ERROR(counter) \ - google::LogMessage(__FILE__, __LINE__, google::GLOG_ERROR, counter, \ - &google::LogMessage::SendToLog) -#define SYSLOG_ERROR(counter) \ - google::LogMessage(__FILE__, __LINE__, google::GLOG_ERROR, counter, \ - &google::LogMessage::SendToSyslogAndLog) -#define GOOGLE_LOG_FATAL(counter) \ - google::LogMessage(__FILE__, __LINE__, google::GLOG_FATAL, counter, \ - &google::LogMessage::SendToLog) -#define SYSLOG_FATAL(counter) \ - google::LogMessage(__FILE__, __LINE__, google::GLOG_FATAL, counter, \ - &google::LogMessage::SendToSyslogAndLog) -#define GOOGLE_LOG_DFATAL(counter) \ - google::LogMessage(__FILE__, __LINE__, google::DFATAL_LEVEL, counter, \ - &google::LogMessage::SendToLog) -#define SYSLOG_DFATAL(counter) \ - google::LogMessage(__FILE__, __LINE__, google::DFATAL_LEVEL, counter, \ - &google::LogMessage::SendToSyslogAndLog) - -#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) || defined(__CYGWIN32__) -// A very useful logging macro to log windows errors: -#define LOG_SYSRESULT(result) \ - if (FAILED(HRESULT_FROM_WIN32(result))) { \ - LPSTR message = NULL; \ - LPSTR msg = reinterpret_cast(&message); \ - DWORD message_length = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | \ - FORMAT_MESSAGE_FROM_SYSTEM | \ - FORMAT_MESSAGE_IGNORE_INSERTS, \ - 0, result, 0, msg, 100, NULL); \ - if (message_length > 0) { \ - google::LogMessage(__FILE__, __LINE__, google::GLOG_ERROR, 0, \ - &google::LogMessage::SendToLog).stream() \ - << reinterpret_cast(message); \ - LocalFree(message); \ - } \ - } -#endif - -// We use the preprocessor's merging operator, "##", so that, e.g., -// LOG(INFO) becomes the token GOOGLE_LOG_INFO. There's some funny -// subtle difference between ostream member streaming functions (e.g., -// ostream::operator<<(int) and ostream non-member streaming functions -// (e.g., ::operator<<(ostream&, string&): it turns out that it's -// impossible to stream something like a string directly to an unnamed -// ostream. We employ a neat hack by calling the stream() member -// function of LogMessage which seems to avoid the problem. -#define LOG(severity) COMPACT_GOOGLE_LOG_ ## severity.stream() -#define SYSLOG(severity) SYSLOG_ ## severity(0).stream() - -namespace google { - -// They need the definitions of integer types. -#include -#include - -// Initialize google's logging library. You will see the program name -// specified by argv0 in log outputs. -GLOG_EXPORT void InitGoogleLogging(const char* argv0); - -GLOG_EXPORT void InitGoogleLogging(const char* argv0, - CustomPrefixCallback prefix_callback, - void* prefix_callback_data = NULL); - -// Check if google's logging library has been initialized. -GLOG_EXPORT bool IsGoogleLoggingInitialized(); - -// Shutdown google's logging library. -GLOG_EXPORT void ShutdownGoogleLogging(); - -#if defined(__GNUC__) -typedef void (*logging_fail_func_t)() __attribute__((noreturn)); -#else -typedef void (*logging_fail_func_t)(); -#endif - -// Install a function which will be called after LOG(FATAL). -GLOG_EXPORT void InstallFailureFunction(logging_fail_func_t fail_func); - -// Enable/Disable old log cleaner. -GLOG_EXPORT void EnableLogCleaner(unsigned int overdue_days); -GLOG_EXPORT void DisableLogCleaner(); -GLOG_EXPORT void SetApplicationFingerprint(const std::string& fingerprint); - -class LogSink; // defined below - -// If a non-NULL sink pointer is given, we push this message to that sink. -// For LOG_TO_SINK we then do normal LOG(severity) logging as well. -// This is useful for capturing messages and passing/storing them -// somewhere more specific than the global log of the process. -// Argument types: -// LogSink* sink; -// LogSeverity severity; -// The cast is to disambiguate NULL arguments. -#define LOG_TO_SINK(sink, severity) \ - google::LogMessage( \ - __FILE__, __LINE__, \ - google::GLOG_ ## severity, \ - static_cast(sink), true).stream() -#define LOG_TO_SINK_BUT_NOT_TO_LOGFILE(sink, severity) \ - google::LogMessage( \ - __FILE__, __LINE__, \ - google::GLOG_ ## severity, \ - static_cast(sink), false).stream() - -// If a non-NULL string pointer is given, we write this message to that string. -// We then do normal LOG(severity) logging as well. -// This is useful for capturing messages and storing them somewhere more -// specific than the global log of the process. -// Argument types: -// string* message; -// LogSeverity severity; -// The cast is to disambiguate NULL arguments. -// NOTE: LOG(severity) expands to LogMessage().stream() for the specified -// severity. -#define LOG_TO_STRING(severity, message) \ - LOG_TO_STRING_##severity(static_cast(message)).stream() - -// If a non-NULL pointer is given, we push the message onto the end -// of a vector of strings; otherwise, we report it with LOG(severity). -// This is handy for capturing messages and perhaps passing them back -// to the caller, rather than reporting them immediately. -// Argument types: -// LogSeverity severity; -// vector *outvec; -// The cast is to disambiguate NULL arguments. -#define LOG_STRING(severity, outvec) \ - LOG_TO_STRING_##severity(static_cast*>(outvec)).stream() - -#define LOG_IF(severity, condition) \ - static_cast(0), \ - !(condition) ? (void) 0 : google::LogMessageVoidify() & LOG(severity) -#define SYSLOG_IF(severity, condition) \ - static_cast(0), \ - !(condition) ? (void) 0 : google::LogMessageVoidify() & SYSLOG(severity) - -#define LOG_ASSERT(condition) \ - LOG_IF(FATAL, !(condition)) << "Assert failed: " #condition -#define SYSLOG_ASSERT(condition) \ - SYSLOG_IF(FATAL, !(condition)) << "Assert failed: " #condition - -// CHECK dies with a fatal error if condition is not true. It is *not* -// controlled by DCHECK_IS_ON(), so the check will be executed regardless of -// compilation mode. Therefore, it is safe to do things like: -// CHECK(fp->Write(x) == 4) -#define CHECK(condition) \ - LOG_IF(FATAL, GOOGLE_PREDICT_BRANCH_NOT_TAKEN(!(condition))) \ - << "Check failed: " #condition " " - -// A container for a string pointer which can be evaluated to a bool - -// true iff the pointer is NULL. -struct CheckOpString { - CheckOpString(std::string* str) : str_(str) { } - // No destructor: if str_ is non-NULL, we're about to LOG(FATAL), - // so there's no point in cleaning up str_. - operator bool() const { - return GOOGLE_PREDICT_BRANCH_NOT_TAKEN(str_ != NULL); - } - std::string* str_; -}; - -// Function is overloaded for integral types to allow static const -// integrals declared in classes and not defined to be used as arguments to -// CHECK* macros. It's not encouraged though. -template -inline const T& GetReferenceableValue(const T& t) { return t; } -inline char GetReferenceableValue(char t) { return t; } -inline unsigned char GetReferenceableValue(unsigned char t) { return t; } -inline signed char GetReferenceableValue(signed char t) { return t; } -inline short GetReferenceableValue(short t) { return t; } -inline unsigned short GetReferenceableValue(unsigned short t) { return t; } -inline int GetReferenceableValue(int t) { return t; } -inline unsigned int GetReferenceableValue(unsigned int t) { return t; } -inline long GetReferenceableValue(long t) { return t; } -inline unsigned long GetReferenceableValue(unsigned long t) { return t; } -inline long long GetReferenceableValue(long long t) { return t; } -inline unsigned long long GetReferenceableValue(unsigned long long t) { - return t; -} - -// This is a dummy class to define the following operator. -struct DummyClassToDefineOperator {}; - -} - -// Define global operator<< to declare using ::operator<<. -// This declaration will allow use to use CHECK macros for user -// defined classes which have operator<< (e.g., stl_logging.h). -inline std::ostream& operator<<( - std::ostream& out, const google::DummyClassToDefineOperator&) { - return out; -} - -namespace google { - -// This formats a value for a failing CHECK_XX statement. Ordinarily, -// it uses the definition for operator<<, with a few special cases below. -template -inline void MakeCheckOpValueString(std::ostream* os, const T& v) { - (*os) << v; -} - -// Overrides for char types provide readable values for unprintable -// characters. -template <> GLOG_EXPORT -void MakeCheckOpValueString(std::ostream* os, const char& v); -template <> GLOG_EXPORT -void MakeCheckOpValueString(std::ostream* os, const signed char& v); -template <> GLOG_EXPORT -void MakeCheckOpValueString(std::ostream* os, const unsigned char& v); - -// Provide printable value for nullptr_t -template <> -GLOG_EXPORT void MakeCheckOpValueString(std::ostream* os, - const std::nullptr_t& v); - -// Build the error message string. Specify no inlining for code size. -template -std::string* MakeCheckOpString(const T1& v1, const T2& v2, const char* exprtext) - __attribute__((noinline)); - -namespace base { -namespace internal { - -// If "s" is less than base_logging::INFO, returns base_logging::INFO. -// If "s" is greater than base_logging::FATAL, returns -// base_logging::ERROR. Otherwise, returns "s". -LogSeverity NormalizeSeverity(LogSeverity s); - -} // namespace internal - -// A helper class for formatting "expr (V1 vs. V2)" in a CHECK_XX -// statement. See MakeCheckOpString for sample usage. Other -// approaches were considered: use of a template method (e.g., -// base::BuildCheckOpString(exprtext, base::Print, &v1, -// base::Print, &v2), however this approach has complications -// related to volatile arguments and function-pointer arguments). -class GLOG_EXPORT CheckOpMessageBuilder { - public: - // Inserts "exprtext" and " (" to the stream. - explicit CheckOpMessageBuilder(const char *exprtext); - // Deletes "stream_". - ~CheckOpMessageBuilder(); - // For inserting the first variable. - std::ostream* ForVar1() { return stream_; } - // For inserting the second variable (adds an intermediate " vs. "). - std::ostream* ForVar2(); - // Get the result (inserts the closing ")"). - std::string* NewString(); - - private: - std::ostringstream *stream_; -}; - -} // namespace base - -template -std::string* MakeCheckOpString(const T1& v1, const T2& v2, const char* exprtext) { - base::CheckOpMessageBuilder comb(exprtext); - MakeCheckOpValueString(comb.ForVar1(), v1); - MakeCheckOpValueString(comb.ForVar2(), v2); - return comb.NewString(); -} - -// Helper functions for CHECK_OP macro. -// The (int, int) specialization works around the issue that the compiler -// will not instantiate the template version of the function on values of -// unnamed enum type - see comment below. -#define DEFINE_CHECK_OP_IMPL(name, op) \ - template \ - inline std::string* name##Impl(const T1& v1, const T2& v2, \ - const char* exprtext) { \ - if (GOOGLE_PREDICT_TRUE(v1 op v2)) return NULL; \ - else return MakeCheckOpString(v1, v2, exprtext); \ - } \ - inline std::string* name##Impl(int v1, int v2, const char* exprtext) { \ - return name##Impl(v1, v2, exprtext); \ - } - -// We use the full name Check_EQ, Check_NE, etc. in case the file including -// base/logging.h provides its own #defines for the simpler names EQ, NE, etc. -// This happens if, for example, those are used as token names in a -// yacc grammar. -DEFINE_CHECK_OP_IMPL(Check_EQ, ==) // Compilation error with CHECK_EQ(NULL, x)? -DEFINE_CHECK_OP_IMPL(Check_NE, !=) // Use CHECK(x == NULL) instead. -DEFINE_CHECK_OP_IMPL(Check_LE, <=) -DEFINE_CHECK_OP_IMPL(Check_LT, < ) -DEFINE_CHECK_OP_IMPL(Check_GE, >=) -DEFINE_CHECK_OP_IMPL(Check_GT, > ) -#undef DEFINE_CHECK_OP_IMPL - -// Helper macro for binary operators. -// Don't use this macro directly in your code, use CHECK_EQ et al below. - -#if defined(STATIC_ANALYSIS) -// Only for static analysis tool to know that it is equivalent to assert -#define CHECK_OP_LOG(name, op, val1, val2, log) CHECK((val1) op (val2)) -#elif DCHECK_IS_ON() -// In debug mode, avoid constructing CheckOpStrings if possible, -// to reduce the overhead of CHECK statments by 2x. -// Real DCHECK-heavy tests have seen 1.5x speedups. - -// The meaning of "string" might be different between now and -// when this macro gets invoked (e.g., if someone is experimenting -// with other string implementations that get defined after this -// file is included). Save the current meaning now and use it -// in the macro. -typedef std::string _Check_string; -#define CHECK_OP_LOG(name, op, val1, val2, log) \ - while (google::_Check_string* _result = \ - google::Check##name##Impl( \ - google::GetReferenceableValue(val1), \ - google::GetReferenceableValue(val2), \ - #val1 " " #op " " #val2)) \ - log(__FILE__, __LINE__, \ - google::CheckOpString(_result)).stream() -#else -// In optimized mode, use CheckOpString to hint to compiler that -// the while condition is unlikely. -#define CHECK_OP_LOG(name, op, val1, val2, log) \ - while (google::CheckOpString _result = \ - google::Check##name##Impl( \ - google::GetReferenceableValue(val1), \ - google::GetReferenceableValue(val2), \ - #val1 " " #op " " #val2)) \ - log(__FILE__, __LINE__, _result).stream() -#endif // STATIC_ANALYSIS, DCHECK_IS_ON() - -#if GOOGLE_STRIP_LOG <= 3 -#define CHECK_OP(name, op, val1, val2) \ - CHECK_OP_LOG(name, op, val1, val2, google::LogMessageFatal) -#else -#define CHECK_OP(name, op, val1, val2) \ - CHECK_OP_LOG(name, op, val1, val2, google::NullStreamFatal) -#endif // STRIP_LOG <= 3 - -// Equality/Inequality checks - compare two values, and log a FATAL message -// including the two values when the result is not as expected. The values -// must have operator<<(ostream, ...) defined. -// -// You may append to the error message like so: -// CHECK_NE(1, 2) << ": The world must be ending!"; -// -// We are very careful to ensure that each argument is evaluated exactly -// once, and that anything which is legal to pass as a function argument is -// legal here. In particular, the arguments may be temporary expressions -// which will end up being destroyed at the end of the apparent statement, -// for example: -// CHECK_EQ(string("abc")[1], 'b'); -// -// WARNING: These don't compile correctly if one of the arguments is a pointer -// and the other is NULL. To work around this, simply static_cast NULL to the -// type of the desired pointer. - -#define CHECK_EQ(val1, val2) CHECK_OP(_EQ, ==, val1, val2) -#define CHECK_NE(val1, val2) CHECK_OP(_NE, !=, val1, val2) -#define CHECK_LE(val1, val2) CHECK_OP(_LE, <=, val1, val2) -#define CHECK_LT(val1, val2) CHECK_OP(_LT, < , val1, val2) -#define CHECK_GE(val1, val2) CHECK_OP(_GE, >=, val1, val2) -#define CHECK_GT(val1, val2) CHECK_OP(_GT, > , val1, val2) - -// Check that the input is non NULL. This very useful in constructor -// initializer lists. - -#define CHECK_NOTNULL(val) \ - google::CheckNotNull(__FILE__, __LINE__, "'" #val "' Must be non NULL", (val)) - -// Helper functions for string comparisons. -// To avoid bloat, the definitions are in logging.cc. -#define DECLARE_CHECK_STROP_IMPL(func, expected) \ - GLOG_EXPORT std::string* Check##func##expected##Impl( \ - const char* s1, const char* s2, const char* names); -DECLARE_CHECK_STROP_IMPL(strcmp, true) -DECLARE_CHECK_STROP_IMPL(strcmp, false) -DECLARE_CHECK_STROP_IMPL(strcasecmp, true) -DECLARE_CHECK_STROP_IMPL(strcasecmp, false) -#undef DECLARE_CHECK_STROP_IMPL - -// Helper macro for string comparisons. -// Don't use this macro directly in your code, use CHECK_STREQ et al below. -#define CHECK_STROP(func, op, expected, s1, s2) \ - while (google::CheckOpString _result = \ - google::Check##func##expected##Impl((s1), (s2), \ - #s1 " " #op " " #s2)) \ - LOG(FATAL) << *_result.str_ - - -// String (char*) equality/inequality checks. -// CASE versions are case-insensitive. -// -// Note that "s1" and "s2" may be temporary strings which are destroyed -// by the compiler at the end of the current "full expression" -// (e.g. CHECK_STREQ(Foo().c_str(), Bar().c_str())). - -#define CHECK_STREQ(s1, s2) CHECK_STROP(strcmp, ==, true, s1, s2) -#define CHECK_STRNE(s1, s2) CHECK_STROP(strcmp, !=, false, s1, s2) -#define CHECK_STRCASEEQ(s1, s2) CHECK_STROP(strcasecmp, ==, true, s1, s2) -#define CHECK_STRCASENE(s1, s2) CHECK_STROP(strcasecmp, !=, false, s1, s2) - -#define CHECK_INDEX(I,A) CHECK(I < (sizeof(A)/sizeof(A[0]))) -#define CHECK_BOUND(B,A) CHECK(B <= (sizeof(A)/sizeof(A[0]))) - -#define CHECK_DOUBLE_EQ(val1, val2) \ - do { \ - CHECK_LE((val1), (val2)+0.000000000000001L); \ - CHECK_GE((val1), (val2)-0.000000000000001L); \ - } while (0) - -#define CHECK_NEAR(val1, val2, margin) \ - do { \ - CHECK_LE((val1), (val2)+(margin)); \ - CHECK_GE((val1), (val2)-(margin)); \ - } while (0) - -// perror()..googly style! -// -// PLOG() and PLOG_IF() and PCHECK() behave exactly like their LOG* and -// CHECK equivalents with the addition that they postpend a description -// of the current state of errno to their output lines. - -#define PLOG(severity) GOOGLE_PLOG(severity, 0).stream() - -#define GOOGLE_PLOG(severity, counter) \ - google::ErrnoLogMessage( \ - __FILE__, __LINE__, google::GLOG_ ## severity, counter, \ - &google::LogMessage::SendToLog) - -#define PLOG_IF(severity, condition) \ - static_cast(0), \ - !(condition) ? (void) 0 : google::LogMessageVoidify() & PLOG(severity) - -// A CHECK() macro that postpends errno if the condition is false. E.g. -// -// if (poll(fds, nfds, timeout) == -1) { PCHECK(errno == EINTR); ... } -#define PCHECK(condition) \ - PLOG_IF(FATAL, GOOGLE_PREDICT_BRANCH_NOT_TAKEN(!(condition))) \ - << "Check failed: " #condition " " - -// A CHECK() macro that lets you assert the success of a function that -// returns -1 and sets errno in case of an error. E.g. -// -// CHECK_ERR(mkdir(path, 0700)); -// -// or -// -// int fd = open(filename, flags); CHECK_ERR(fd) << ": open " << filename; -#define CHECK_ERR(invocation) \ -PLOG_IF(FATAL, GOOGLE_PREDICT_BRANCH_NOT_TAKEN((invocation) == -1)) \ - << #invocation - -// Use macro expansion to create, for each use of LOG_EVERY_N(), static -// variables with the __LINE__ expansion as part of the variable name. -#define LOG_EVERY_N_VARNAME(base, line) LOG_EVERY_N_VARNAME_CONCAT(base, line) -#define LOG_EVERY_N_VARNAME_CONCAT(base, line) base ## line - -#define LOG_OCCURRENCES LOG_EVERY_N_VARNAME(occurrences_, __LINE__) -#define LOG_OCCURRENCES_MOD_N LOG_EVERY_N_VARNAME(occurrences_mod_n_, __LINE__) - -#define LOG_TIME_PERIOD LOG_EVERY_N_VARNAME(timePeriod_, __LINE__) -#define LOG_PREVIOUS_TIME_RAW LOG_EVERY_N_VARNAME(previousTimeRaw_, __LINE__) -#define LOG_TIME_DELTA LOG_EVERY_N_VARNAME(deltaTime_, __LINE__) -#define LOG_CURRENT_TIME LOG_EVERY_N_VARNAME(currentTime_, __LINE__) -#define LOG_PREVIOUS_TIME LOG_EVERY_N_VARNAME(previousTime_, __LINE__) - -#if defined(__has_feature) -# if __has_feature(thread_sanitizer) -# define GLOG_SANITIZE_THREAD 1 -# endif -#endif - -#if !defined(GLOG_SANITIZE_THREAD) && defined(__SANITIZE_THREAD__) && __SANITIZE_THREAD__ -# define GLOG_SANITIZE_THREAD 1 -#endif - -#if defined(GLOG_SANITIZE_THREAD) -#define GLOG_IFDEF_THREAD_SANITIZER(X) X -#else -#define GLOG_IFDEF_THREAD_SANITIZER(X) -#endif - -#if defined(GLOG_SANITIZE_THREAD) -} // namespace google - -// We need to identify the static variables as "benign" races -// to avoid noisy reports from TSAN. -extern "C" void AnnotateBenignRaceSized( - const char *file, - int line, - const volatile void *mem, - size_t size, - const char *description); - -namespace google { -#endif - -#define SOME_KIND_OF_LOG_EVERY_T(severity, seconds) \ - constexpr std::chrono::nanoseconds LOG_TIME_PERIOD = \ - std::chrono::duration_cast( \ - std::chrono::duration(seconds)); \ - static std::atomic LOG_PREVIOUS_TIME_RAW; \ - GLOG_IFDEF_THREAD_SANITIZER( \ - AnnotateBenignRaceSized(__FILE__, __LINE__, &LOG_TIME_PERIOD, \ - sizeof(@ac_google_namespace @ ::int64), "")); \ - GLOG_IFDEF_THREAD_SANITIZER( \ - AnnotateBenignRaceSized(__FILE__, __LINE__, &LOG_PREVIOUS_TIME_RAW, \ - sizeof(@ac_google_namespace @ ::int64), "")); \ - const auto LOG_CURRENT_TIME = \ - std::chrono::duration_cast( \ - std::chrono::steady_clock::now().time_since_epoch()); \ - const auto LOG_PREVIOUS_TIME = \ - LOG_PREVIOUS_TIME_RAW.load(std::memory_order_relaxed); \ - const auto LOG_TIME_DELTA = \ - LOG_CURRENT_TIME - std::chrono::nanoseconds(LOG_PREVIOUS_TIME); \ - if (LOG_TIME_DELTA > LOG_TIME_PERIOD) \ - LOG_PREVIOUS_TIME_RAW.store( \ - std::chrono::duration_cast(LOG_CURRENT_TIME) \ - .count(), \ - std::memory_order_relaxed); \ - if (LOG_TIME_DELTA > LOG_TIME_PERIOD) \ - google ::LogMessage( \ - __FILE__, __LINE__, google ::GLOG_##severity) \ - .stream() - -#define SOME_KIND_OF_LOG_EVERY_N(severity, n, what_to_do) \ - static std::atomic LOG_OCCURRENCES(0), LOG_OCCURRENCES_MOD_N(0); \ - GLOG_IFDEF_THREAD_SANITIZER(AnnotateBenignRaceSized(__FILE__, __LINE__, &LOG_OCCURRENCES, sizeof(int), "")); \ - GLOG_IFDEF_THREAD_SANITIZER(AnnotateBenignRaceSized(__FILE__, __LINE__, &LOG_OCCURRENCES_MOD_N, sizeof(int), "")); \ - ++LOG_OCCURRENCES; \ - if (++LOG_OCCURRENCES_MOD_N > n) LOG_OCCURRENCES_MOD_N -= n; \ - if (LOG_OCCURRENCES_MOD_N == 1) \ - google::LogMessage( \ - __FILE__, __LINE__, google::GLOG_ ## severity, LOG_OCCURRENCES, \ - &what_to_do).stream() - -#define SOME_KIND_OF_LOG_IF_EVERY_N(severity, condition, n, what_to_do) \ - static std::atomic LOG_OCCURRENCES(0), LOG_OCCURRENCES_MOD_N(0); \ - GLOG_IFDEF_THREAD_SANITIZER(AnnotateBenignRaceSized(__FILE__, __LINE__, &LOG_OCCURRENCES, sizeof(int), "")); \ - GLOG_IFDEF_THREAD_SANITIZER(AnnotateBenignRaceSized(__FILE__, __LINE__, &LOG_OCCURRENCES_MOD_N, sizeof(int), "")); \ - ++LOG_OCCURRENCES; \ - if ((condition) && \ - ((LOG_OCCURRENCES_MOD_N=(LOG_OCCURRENCES_MOD_N + 1) % n) == (1 % n))) \ - google::LogMessage( \ - __FILE__, __LINE__, google::GLOG_ ## severity, LOG_OCCURRENCES, \ - &what_to_do).stream() - -#define SOME_KIND_OF_PLOG_EVERY_N(severity, n, what_to_do) \ - static std::atomic LOG_OCCURRENCES(0), LOG_OCCURRENCES_MOD_N(0); \ - GLOG_IFDEF_THREAD_SANITIZER(AnnotateBenignRaceSized(__FILE__, __LINE__, &LOG_OCCURRENCES, sizeof(int), "")); \ - GLOG_IFDEF_THREAD_SANITIZER(AnnotateBenignRaceSized(__FILE__, __LINE__, &LOG_OCCURRENCES_MOD_N, sizeof(int), "")); \ - ++LOG_OCCURRENCES; \ - if (++LOG_OCCURRENCES_MOD_N > n) LOG_OCCURRENCES_MOD_N -= n; \ - if (LOG_OCCURRENCES_MOD_N == 1) \ - google::ErrnoLogMessage( \ - __FILE__, __LINE__, google::GLOG_ ## severity, LOG_OCCURRENCES, \ - &what_to_do).stream() - -#define SOME_KIND_OF_LOG_FIRST_N(severity, n, what_to_do) \ - static std::atomic LOG_OCCURRENCES(0); \ - GLOG_IFDEF_THREAD_SANITIZER(AnnotateBenignRaceSized(__FILE__, __LINE__, &LOG_OCCURRENCES, sizeof(int), "")); \ - if (LOG_OCCURRENCES <= n) \ - ++LOG_OCCURRENCES; \ - if (LOG_OCCURRENCES <= n) \ - google::LogMessage( \ - __FILE__, __LINE__, google::GLOG_ ## severity, LOG_OCCURRENCES, \ - &what_to_do).stream() - -namespace glog_internal_namespace_ { -template -struct CompileAssert { -}; -struct CrashReason; - -// Returns true if FailureSignalHandler is installed. -// Needs to be exported since it's used by the signalhandler_unittest. -GLOG_EXPORT bool IsFailureSignalHandlerInstalled(); -} // namespace glog_internal_namespace_ - -#define LOG_EVERY_N(severity, n) \ - SOME_KIND_OF_LOG_EVERY_N(severity, (n), google::LogMessage::SendToLog) - -#define LOG_EVERY_T(severity, T) SOME_KIND_OF_LOG_EVERY_T(severity, (T)) - -#define SYSLOG_EVERY_N(severity, n) \ - SOME_KIND_OF_LOG_EVERY_N(severity, (n), google::LogMessage::SendToSyslogAndLog) - -#define PLOG_EVERY_N(severity, n) \ - SOME_KIND_OF_PLOG_EVERY_N(severity, (n), google::LogMessage::SendToLog) - -#define LOG_FIRST_N(severity, n) \ - SOME_KIND_OF_LOG_FIRST_N(severity, (n), google::LogMessage::SendToLog) - -#define LOG_IF_EVERY_N(severity, condition, n) \ - SOME_KIND_OF_LOG_IF_EVERY_N(severity, (condition), (n), google::LogMessage::SendToLog) - -// We want the special COUNTER value available for LOG_EVERY_X()'ed messages -enum PRIVATE_Counter {COUNTER}; - -#ifdef GLOG_NO_ABBREVIATED_SEVERITIES -// wingdi.h defines ERROR to be 0. When we call LOG(ERROR), it gets -// substituted with 0, and it expands to COMPACT_GOOGLE_LOG_0. To allow us -// to keep using this syntax, we define this macro to do the same thing -// as COMPACT_GOOGLE_LOG_ERROR. -#define COMPACT_GOOGLE_LOG_0 COMPACT_GOOGLE_LOG_ERROR -#define SYSLOG_0 SYSLOG_ERROR -#define LOG_TO_STRING_0 LOG_TO_STRING_ERROR -// Needed for LOG_IS_ON(ERROR). -const LogSeverity GLOG_0 = GLOG_ERROR; -#else -// Users may include windows.h after logging.h without -// GLOG_NO_ABBREVIATED_SEVERITIES nor WIN32_LEAN_AND_MEAN. -// For this case, we cannot detect if ERROR is defined before users -// actually use ERROR. Let's make an undefined symbol to warn users. -# define GLOG_ERROR_MSG ERROR_macro_is_defined_Define_GLOG_NO_ABBREVIATED_SEVERITIES_before_including_logging_h_See_the_document_for_detail -# define COMPACT_GOOGLE_LOG_0 GLOG_ERROR_MSG -# define SYSLOG_0 GLOG_ERROR_MSG -# define LOG_TO_STRING_0 GLOG_ERROR_MSG -# define GLOG_0 GLOG_ERROR_MSG -#endif - -// Plus some debug-logging macros that get compiled to nothing for production - -#if DCHECK_IS_ON() - -#define DLOG(severity) LOG(severity) -#define DVLOG(verboselevel) VLOG(verboselevel) -#define DLOG_IF(severity, condition) LOG_IF(severity, condition) -#define DLOG_EVERY_N(severity, n) LOG_EVERY_N(severity, n) -#define DLOG_IF_EVERY_N(severity, condition, n) \ - LOG_IF_EVERY_N(severity, condition, n) -#define DLOG_ASSERT(condition) LOG_ASSERT(condition) - -// debug-only checking. executed if DCHECK_IS_ON(). -#define DCHECK(condition) CHECK(condition) -#define DCHECK_EQ(val1, val2) CHECK_EQ(val1, val2) -#define DCHECK_NE(val1, val2) CHECK_NE(val1, val2) -#define DCHECK_LE(val1, val2) CHECK_LE(val1, val2) -#define DCHECK_LT(val1, val2) CHECK_LT(val1, val2) -#define DCHECK_GE(val1, val2) CHECK_GE(val1, val2) -#define DCHECK_GT(val1, val2) CHECK_GT(val1, val2) -#define DCHECK_NOTNULL(val) CHECK_NOTNULL(val) -#define DCHECK_STREQ(str1, str2) CHECK_STREQ(str1, str2) -#define DCHECK_STRCASEEQ(str1, str2) CHECK_STRCASEEQ(str1, str2) -#define DCHECK_STRNE(str1, str2) CHECK_STRNE(str1, str2) -#define DCHECK_STRCASENE(str1, str2) CHECK_STRCASENE(str1, str2) - -#else // !DCHECK_IS_ON() - -#define DLOG(severity) \ - static_cast(0), \ - true ? (void) 0 : google::LogMessageVoidify() & LOG(severity) - -#define DVLOG(verboselevel) \ - static_cast(0), \ - (true || !VLOG_IS_ON(verboselevel)) ? \ - (void) 0 : google::LogMessageVoidify() & LOG(INFO) - -#define DLOG_IF(severity, condition) \ - static_cast(0), \ - (true || !(condition)) ? (void) 0 : google::LogMessageVoidify() & LOG(severity) - -#define DLOG_EVERY_N(severity, n) \ - static_cast(0), \ - true ? (void) 0 : google::LogMessageVoidify() & LOG(severity) - -#define DLOG_IF_EVERY_N(severity, condition, n) \ - static_cast(0), \ - (true || !(condition))? (void) 0 : google::LogMessageVoidify() & LOG(severity) - -#define DLOG_ASSERT(condition) \ - static_cast(0), \ - true ? (void) 0 : LOG_ASSERT(condition) - -// MSVC warning C4127: conditional expression is constant -#define DCHECK(condition) \ - GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ - while (false) \ - GLOG_MSVC_POP_WARNING() CHECK(condition) - -#define DCHECK_EQ(val1, val2) \ - GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ - while (false) \ - GLOG_MSVC_POP_WARNING() CHECK_EQ(val1, val2) - -#define DCHECK_NE(val1, val2) \ - GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ - while (false) \ - GLOG_MSVC_POP_WARNING() CHECK_NE(val1, val2) - -#define DCHECK_LE(val1, val2) \ - GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ - while (false) \ - GLOG_MSVC_POP_WARNING() CHECK_LE(val1, val2) - -#define DCHECK_LT(val1, val2) \ - GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ - while (false) \ - GLOG_MSVC_POP_WARNING() CHECK_LT(val1, val2) - -#define DCHECK_GE(val1, val2) \ - GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ - while (false) \ - GLOG_MSVC_POP_WARNING() CHECK_GE(val1, val2) - -#define DCHECK_GT(val1, val2) \ - GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ - while (false) \ - GLOG_MSVC_POP_WARNING() CHECK_GT(val1, val2) - -// You may see warnings in release mode if you don't use the return -// value of DCHECK_NOTNULL. Please just use DCHECK for such cases. -#define DCHECK_NOTNULL(val) (val) - -#define DCHECK_STREQ(str1, str2) \ - GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ - while (false) \ - GLOG_MSVC_POP_WARNING() CHECK_STREQ(str1, str2) - -#define DCHECK_STRCASEEQ(str1, str2) \ - GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ - while (false) \ - GLOG_MSVC_POP_WARNING() CHECK_STRCASEEQ(str1, str2) - -#define DCHECK_STRNE(str1, str2) \ - GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ - while (false) \ - GLOG_MSVC_POP_WARNING() CHECK_STRNE(str1, str2) - -#define DCHECK_STRCASENE(str1, str2) \ - GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ - while (false) \ - GLOG_MSVC_POP_WARNING() CHECK_STRCASENE(str1, str2) - -#endif // DCHECK_IS_ON() - -// Log only in verbose mode. - -#define VLOG(verboselevel) LOG_IF(INFO, VLOG_IS_ON(verboselevel)) - -#define VLOG_IF(verboselevel, condition) \ - LOG_IF(INFO, (condition) && VLOG_IS_ON(verboselevel)) - -#define VLOG_EVERY_N(verboselevel, n) \ - LOG_IF_EVERY_N(INFO, VLOG_IS_ON(verboselevel), n) - -#define VLOG_IF_EVERY_N(verboselevel, condition, n) \ - LOG_IF_EVERY_N(INFO, (condition) && VLOG_IS_ON(verboselevel), n) - -namespace base_logging { - -// LogMessage::LogStream is a std::ostream backed by this streambuf. -// This class ignores overflow and leaves two bytes at the end of the -// buffer to allow for a '\n' and '\0'. -class GLOG_EXPORT LogStreamBuf : public std::streambuf { - public: - // REQUIREMENTS: "len" must be >= 2 to account for the '\n' and '\0'. - LogStreamBuf(char *buf, int len) { - setp(buf, buf + len - 2); - } - - // This effectively ignores overflow. - int_type overflow(int_type ch) { - return ch; - } - - // Legacy public ostrstream method. - size_t pcount() const { return static_cast(pptr() - pbase()); } - char* pbase() const { return std::streambuf::pbase(); } -}; - -} // namespace base_logging - -// -// This class more or less represents a particular log message. You -// create an instance of LogMessage and then stream stuff to it. -// When you finish streaming to it, ~LogMessage is called and the -// full message gets streamed to the appropriate destination. -// -// You shouldn't actually use LogMessage's constructor to log things, -// though. You should use the LOG() macro (and variants thereof) -// above. -class GLOG_EXPORT LogMessage { -public: - enum { - // Passing kNoLogPrefix for the line number disables the - // log-message prefix. Useful for using the LogMessage - // infrastructure as a printing utility. See also the --log_prefix - // flag for controlling the log-message prefix on an - // application-wide basis. - kNoLogPrefix = -1 - }; - - // LogStream inherit from non-DLL-exported class (std::ostrstream) - // and VC++ produces a warning for this situation. - // However, MSDN says "C4275 can be ignored in Microsoft Visual C++ - // 2005 if you are deriving from a type in the Standard C++ Library" - // http://msdn.microsoft.com/en-us/library/3tdb471s(VS.80).aspx - // Let's just ignore the warning. -GLOG_MSVC_PUSH_DISABLE_WARNING(4275) - class GLOG_EXPORT LogStream : public std::ostream { -GLOG_MSVC_POP_WARNING() - public: - LogStream(char *buf, int len, int64 ctr) - : std::ostream(NULL), - streambuf_(buf, len), - ctr_(ctr), - self_(this) { - rdbuf(&streambuf_); - } - - int64 ctr() const { return ctr_; } - void set_ctr(int64 ctr) { ctr_ = ctr; } - LogStream* self() const { return self_; } - - // Legacy std::streambuf methods. - size_t pcount() const { return streambuf_.pcount(); } - char* pbase() const { return streambuf_.pbase(); } - char* str() const { return pbase(); } - - private: - LogStream(const LogStream&); - LogStream& operator=(const LogStream&); - base_logging::LogStreamBuf streambuf_; - int64 ctr_; // Counter hack (for the LOG_EVERY_X() macro) - LogStream *self_; // Consistency check hack - }; - -public: - // icc 8 requires this typedef to avoid an internal compiler error. - typedef void (LogMessage::*SendMethod)(); - - LogMessage(const char* file, int line, LogSeverity severity, int64 ctr, - SendMethod send_method); - - // Two special constructors that generate reduced amounts of code at - // LOG call sites for common cases. - - // Used for LOG(INFO): Implied are: - // severity = INFO, ctr = 0, send_method = &LogMessage::SendToLog. - // - // Using this constructor instead of the more complex constructor above - // saves 19 bytes per call site. - LogMessage(const char* file, int line); - - // Used for LOG(severity) where severity != INFO. Implied - // are: ctr = 0, send_method = &LogMessage::SendToLog - // - // Using this constructor instead of the more complex constructor above - // saves 17 bytes per call site. - LogMessage(const char* file, int line, LogSeverity severity); - - // Constructor to log this message to a specified sink (if not NULL). - // Implied are: ctr = 0, send_method = &LogMessage::SendToSinkAndLog if - // also_send_to_log is true, send_method = &LogMessage::SendToSink otherwise. - LogMessage(const char* file, int line, LogSeverity severity, LogSink* sink, - bool also_send_to_log); - - // Constructor where we also give a vector pointer - // for storing the messages (if the pointer is not NULL). - // Implied are: ctr = 0, send_method = &LogMessage::SaveOrSendToLog. - LogMessage(const char* file, int line, LogSeverity severity, - std::vector* outvec); - - // Constructor where we also give a string pointer for storing the - // message (if the pointer is not NULL). Implied are: ctr = 0, - // send_method = &LogMessage::WriteToStringAndLog. - LogMessage(const char* file, int line, LogSeverity severity, - std::string* message); - - // A special constructor used for check failures - LogMessage(const char* file, int line, const CheckOpString& result); - - ~LogMessage(); - - // Flush a buffered message to the sink set in the constructor. Always - // called by the destructor, it may also be called from elsewhere if - // needed. Only the first call is actioned; any later ones are ignored. - void Flush(); - - // An arbitrary limit on the length of a single log message. This - // is so that streaming can be done more efficiently. - static const size_t kMaxLogMessageLen; - - // Theses should not be called directly outside of logging.*, - // only passed as SendMethod arguments to other LogMessage methods: - void SendToLog(); // Actually dispatch to the logs - void SendToSyslogAndLog(); // Actually dispatch to syslog and the logs - - // Call abort() or similar to perform LOG(FATAL) crash. - [[noreturn]] static void Fail(); - - std::ostream& stream(); - - int preserved_errno() const; - - // Must be called without the log_mutex held. (L < log_mutex) - static int64 num_messages(int severity); - - const LogMessageTime& getLogMessageTime() const; - - struct LogMessageData; - -private: - // Fully internal SendMethod cases: - void SendToSinkAndLog(); // Send to sink if provided and dispatch to the logs - void SendToSink(); // Send to sink if provided, do nothing otherwise. - - // Write to string if provided and dispatch to the logs. - void WriteToStringAndLog(); - - void SaveOrSendToLog(); // Save to stringvec if provided, else to logs - - void Init(const char* file, int line, LogSeverity severity, - void (LogMessage::*send_method)()); - - // Used to fill in crash information during LOG(FATAL) failures. - void RecordCrashReason(glog_internal_namespace_::CrashReason* reason); - - // Counts of messages sent at each priority: - static int64 num_messages_[NUM_SEVERITIES]; // under log_mutex - - // We keep the data in a separate struct so that each instance of - // LogMessage uses less stack space. - LogMessageData* allocated_; - LogMessageData* data_; - LogMessageTime logmsgtime_; - - friend class LogDestination; - - LogMessage(const LogMessage&); - void operator=(const LogMessage&); -}; - -// This class happens to be thread-hostile because all instances share -// a single data buffer, but since it can only be created just before -// the process dies, we don't worry so much. -class GLOG_EXPORT LogMessageFatal : public LogMessage { - public: - LogMessageFatal(const char* file, int line); - LogMessageFatal(const char* file, int line, const CheckOpString& result); - [[noreturn]] ~LogMessageFatal(); -}; - -// A non-macro interface to the log facility; (useful -// when the logging level is not a compile-time constant). -inline void LogAtLevel(int const severity, std::string const &msg) { - LogMessage(__FILE__, __LINE__, severity).stream() << msg; -} - -// A macro alternative of LogAtLevel. New code may want to use this -// version since there are two advantages: 1. this version outputs the -// file name and the line number where this macro is put like other -// LOG macros, 2. this macro can be used as C++ stream. -#define LOG_AT_LEVEL(severity) google::LogMessage(__FILE__, __LINE__, severity).stream() - -// Helper for CHECK_NOTNULL(). -// -// In C++11, all cases can be handled by a single function. Since the value -// category of the argument is preserved (also for rvalue references), -// member initializer lists like the one below will compile correctly: -// -// Foo() -// : x_(CHECK_NOTNULL(MethodReturningUniquePtr())) {} -template -T CheckNotNull(const char* file, int line, const char* names, T&& t) { - if (t == nullptr) { - LogMessageFatal(file, line, new std::string(names)); - } - return std::forward(t); -} - -// Allow folks to put a counter in the LOG_EVERY_X()'ed messages. This -// only works if ostream is a LogStream. If the ostream is not a -// LogStream you'll get an assert saying as much at runtime. -GLOG_EXPORT std::ostream& operator<<(std::ostream &os, - const PRIVATE_Counter&); - - -// Derived class for PLOG*() above. -class GLOG_EXPORT ErrnoLogMessage : public LogMessage { - public: - ErrnoLogMessage(const char* file, int line, LogSeverity severity, int64 ctr, - void (LogMessage::*send_method)()); - - // Postpends ": strerror(errno) [errno]". - ~ErrnoLogMessage(); - - private: - ErrnoLogMessage(const ErrnoLogMessage&); - void operator=(const ErrnoLogMessage&); -}; - - -// This class is used to explicitly ignore values in the conditional -// logging macros. This avoids compiler warnings like "value computed -// is not used" and "statement has no effect". - -class GLOG_EXPORT LogMessageVoidify { - public: - LogMessageVoidify() { } - // This has to be an operator with a precedence lower than << but - // higher than ?: - void operator&(std::ostream&) { } -}; - - -// Flushes all log files that contains messages that are at least of -// the specified severity level. Thread-safe. -GLOG_EXPORT void FlushLogFiles(LogSeverity min_severity); - -// Flushes all log files that contains messages that are at least of -// the specified severity level. Thread-hostile because it ignores -// locking -- used for catastrophic failures. -GLOG_EXPORT void FlushLogFilesUnsafe(LogSeverity min_severity); - -// -// Set the destination to which a particular severity level of log -// messages is sent. If base_filename is "", it means "don't log this -// severity". Thread-safe. -// -GLOG_EXPORT void SetLogDestination(LogSeverity severity, - const char* base_filename); - -// -// Set the basename of the symlink to the latest log file at a given -// severity. If symlink_basename is empty, do not make a symlink. If -// you don't call this function, the symlink basename is the -// invocation name of the program. Thread-safe. -// -GLOG_EXPORT void SetLogSymlink(LogSeverity severity, - const char* symlink_basename); - -// -// Used to send logs to some other kind of destination -// Users should subclass LogSink and override send to do whatever they want. -// Implementations must be thread-safe because a shared instance will -// be called from whichever thread ran the LOG(XXX) line. -class GLOG_EXPORT LogSink { - public: - virtual ~LogSink(); - - // Sink's logging logic (message_len is such as to exclude '\n' at the end). - // This method can't use LOG() or CHECK() as logging system mutex(s) are held - // during this call. - virtual void send(LogSeverity severity, const char* full_filename, - const char* base_filename, int line, - const LogMessageTime& logmsgtime, const char* message, - size_t message_len); - // Provide an overload for compatibility purposes - GLOG_DEPRECATED - virtual void send(LogSeverity severity, const char* full_filename, - const char* base_filename, int line, const std::tm* t, - const char* message, size_t message_len); - - // Redefine this to implement waiting for - // the sink's logging logic to complete. - // It will be called after each send() returns, - // but before that LogMessage exits or crashes. - // By default this function does nothing. - // Using this function one can implement complex logic for send() - // that itself involves logging; and do all this w/o causing deadlocks and - // inconsistent rearrangement of log messages. - // E.g. if a LogSink has thread-specific actions, the send() method - // can simply add the message to a queue and wake up another thread that - // handles real logging while itself making some LOG() calls; - // WaitTillSent() can be implemented to wait for that logic to complete. - // See our unittest for an example. - virtual void WaitTillSent(); - - // Returns the normal text output of the log message. - // Can be useful to implement send(). - static std::string ToString(LogSeverity severity, const char* file, int line, - const LogMessageTime &logmsgtime, - const char* message, size_t message_len); -}; - -// Add or remove a LogSink as a consumer of logging data. Thread-safe. -GLOG_EXPORT void AddLogSink(LogSink *destination); -GLOG_EXPORT void RemoveLogSink(LogSink *destination); - -// -// Specify an "extension" added to the filename specified via -// SetLogDestination. This applies to all severity levels. It's -// often used to append the port we're listening on to the logfile -// name. Thread-safe. -// -GLOG_EXPORT void SetLogFilenameExtension( - const char* filename_extension); - -// -// Make it so that all log messages of at least a particular severity -// are logged to stderr (in addition to logging to the usual log -// file(s)). Thread-safe. -// -GLOG_EXPORT void SetStderrLogging(LogSeverity min_severity); - -// -// Make it so that all log messages go only to stderr. Thread-safe. -// -GLOG_EXPORT void LogToStderr(); - -// -// Make it so that all log messages of at least a particular severity are -// logged via email to a list of addresses (in addition to logging to the -// usual log file(s)). The list of addresses is just a string containing -// the email addresses to send to (separated by spaces, say). Thread-safe. -// -GLOG_EXPORT void SetEmailLogging(LogSeverity min_severity, - const char* addresses); - -// A simple function that sends email. dest is a commma-separated -// list of addressess. Thread-safe. -GLOG_EXPORT bool SendEmail(const char* dest, const char* subject, - const char* body); - -GLOG_EXPORT const std::vector& GetLoggingDirectories(); - -// For tests only: Clear the internal [cached] list of logging directories to -// force a refresh the next time GetLoggingDirectories is called. -// Thread-hostile. -void TestOnly_ClearLoggingDirectoriesList(); - -// Returns a set of existing temporary directories, which will be a -// subset of the directories returned by GetLoggingDirectories(). -// Thread-safe. -GLOG_EXPORT void GetExistingTempDirectories( - std::vector* list); - -// Print any fatal message again -- useful to call from signal handler -// so that the last thing in the output is the fatal message. -// Thread-hostile, but a race is unlikely. -GLOG_EXPORT void ReprintFatalMessage(); - -// Truncate a log file that may be the append-only output of multiple -// processes and hence can't simply be renamed/reopened (typically a -// stdout/stderr). If the file "path" is > "limit" bytes, copy the -// last "keep" bytes to offset 0 and truncate the rest. Since we could -// be racing with other writers, this approach has the potential to -// lose very small amounts of data. For security, only follow symlinks -// if the path is /proc/self/fd/* -GLOG_EXPORT void TruncateLogFile(const char* path, uint64 limit, uint64 keep); - -// Truncate stdout and stderr if they are over the value specified by -// --max_log_size; keep the final 1MB. This function has the same -// race condition as TruncateLogFile. -GLOG_EXPORT void TruncateStdoutStderr(); - -// Return the string representation of the provided LogSeverity level. -// Thread-safe. -GLOG_EXPORT const char* GetLogSeverityName(LogSeverity severity); - -// --------------------------------------------------------------------- -// Implementation details that are not useful to most clients -// --------------------------------------------------------------------- - -// A Logger is the interface used by logging modules to emit entries -// to a log. A typical implementation will dump formatted data to a -// sequence of files. We also provide interfaces that will forward -// the data to another thread so that the invoker never blocks. -// Implementations should be thread-safe since the logging system -// will write to them from multiple threads. - -namespace base { - -class GLOG_EXPORT Logger { - public: - virtual ~Logger(); - - // Writes "message[0,message_len-1]" corresponding to an event that - // occurred at "timestamp". If "force_flush" is true, the log file - // is flushed immediately. - // - // The input message has already been formatted as deemed - // appropriate by the higher level logging facility. For example, - // textual log messages already contain timestamps, and the - // file:linenumber header. - virtual void Write(bool force_flush, - time_t timestamp, - const char* message, - size_t message_len) = 0; - - // Flush any buffered messages - virtual void Flush() = 0; - - // Get the current LOG file size. - // The returned value is approximate since some - // logged data may not have been flushed to disk yet. - virtual uint32 LogSize() = 0; -}; - -// Get the logger for the specified severity level. The logger -// remains the property of the logging module and should not be -// deleted by the caller. Thread-safe. -extern GLOG_EXPORT Logger* GetLogger(LogSeverity level); - -// Set the logger for the specified severity level. The logger -// becomes the property of the logging module and should not -// be deleted by the caller. Thread-safe. -extern GLOG_EXPORT void SetLogger(LogSeverity level, Logger* logger); - -} - -// glibc has traditionally implemented two incompatible versions of -// strerror_r(). There is a poorly defined convention for picking the -// version that we want, but it is not clear whether it even works with -// all versions of glibc. -// So, instead, we provide this wrapper that automatically detects the -// version that is in use, and then implements POSIX semantics. -// N.B. In addition to what POSIX says, we also guarantee that "buf" will -// be set to an empty string, if this function failed. This means, in most -// cases, you do not need to check the error code and you can directly -// use the value of "buf". It will never have an undefined value. -// DEPRECATED: Use StrError(int) instead. -GLOG_EXPORT int posix_strerror_r(int err, char *buf, size_t len); - -// A thread-safe replacement for strerror(). Returns a string describing the -// given POSIX error code. -GLOG_EXPORT std::string StrError(int err); - -// A class for which we define operator<<, which does nothing. -class GLOG_EXPORT NullStream : public LogMessage::LogStream { - public: - // Initialize the LogStream so the messages can be written somewhere - // (they'll never be actually displayed). This will be needed if a - // NullStream& is implicitly converted to LogStream&, in which case - // the overloaded NullStream::operator<< will not be invoked. - NullStream() : LogMessage::LogStream(message_buffer_, 1, 0) { } - NullStream(const char* /*file*/, int /*line*/, - const CheckOpString& /*result*/) : - LogMessage::LogStream(message_buffer_, 1, 0) { } - NullStream &stream() { return *this; } - private: - // A very short buffer for messages (which we discard anyway). This - // will be needed if NullStream& converted to LogStream& (e.g. as a - // result of a conditional expression). - char message_buffer_[2]; -}; - -// Do nothing. This operator is inline, allowing the message to be -// compiled away. The message will not be compiled away if we do -// something like (flag ? LOG(INFO) : LOG(ERROR)) << message; when -// SKIP_LOG=WARNING. In those cases, NullStream will be implicitly -// converted to LogStream and the message will be computed and then -// quietly discarded. -template -inline NullStream& operator<<(NullStream &str, const T &) { return str; } - -// Similar to NullStream, but aborts the program (without stack -// trace), like LogMessageFatal. -class GLOG_EXPORT NullStreamFatal : public NullStream { - public: - NullStreamFatal() { } - NullStreamFatal(const char* file, int line, const CheckOpString& result) : - NullStream(file, line, result) { } -#if defined(_MSC_VER) -#pragma warning(push) -#pragma warning(disable : 4722) -#endif // _MSC_VER - [[noreturn]] ~NullStreamFatal() throw() { _exit(EXIT_FAILURE); } -#if defined(_MSC_VER) -#pragma warning(pop) -#endif // _MSC_VER -}; - -// Install a signal handler that will dump signal information and a stack -// trace when the program crashes on certain signals. We'll install the -// signal handler for the following signals. -// -// SIGSEGV, SIGILL, SIGFPE, SIGABRT, SIGBUS, and SIGTERM. -// -// By default, the signal handler will write the failure dump to the -// standard error. You can customize the destination by installing your -// own writer function by InstallFailureWriter() below. -// -// Note on threading: -// -// The function should be called before threads are created, if you want -// to use the failure signal handler for all threads. The stack trace -// will be shown only for the thread that receives the signal. In other -// words, stack traces of other threads won't be shown. -GLOG_EXPORT void InstallFailureSignalHandler(); - -// Installs a function that is used for writing the failure dump. "data" -// is the pointer to the beginning of a message to be written, and "size" -// is the size of the message. You should not expect the data is -// terminated with '\0'. -GLOG_EXPORT void InstallFailureWriter( - void (*writer)(const char* data, size_t size)); - -} - -#pragma pop_macro("DECLARE_VARIABLE") -#pragma pop_macro("DECLARE_bool") -#pragma pop_macro("DECLARE_string") -#pragma pop_macro("DECLARE_int32") -#pragma pop_macro("DECLARE_uint32") - -#endif // GLOG_LOGGING_H diff --git a/funasr/runtime/onnxruntime/include/glog/logging.h.in b/funasr/runtime/onnxruntime/include/glog/logging.h.in deleted file mode 100644 index e8e6c41b8..000000000 --- a/funasr/runtime/onnxruntime/include/glog/logging.h.in +++ /dev/null @@ -1,1842 +0,0 @@ -// Copyright (c) 2023, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Author: Ray Sidney -// -// This file contains #include information about logging-related stuff. -// Pretty much everybody needs to #include this file so that they can -// log various happenings. -// -#ifndef GLOG_LOGGING_H -#define GLOG_LOGGING_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if @ac_cv_have_unistd_h@ -# include -#endif -#include - -#if defined(_MSC_VER) -#define GLOG_MSVC_PUSH_DISABLE_WARNING(n) __pragma(warning(push)) \ - __pragma(warning(disable:n)) -#define GLOG_MSVC_POP_WARNING() __pragma(warning(pop)) -#else -#define GLOG_MSVC_PUSH_DISABLE_WARNING(n) -#define GLOG_MSVC_POP_WARNING() -#endif - -#include - -#if @ac_cv_have_glog_export@ -#include -#endif - -// We care a lot about number of bits things take up. Unfortunately, -// systems define their bit-specific ints in a lot of different ways. -// We use our own way, and have a typedef to get there. -// Note: these commands below may look like "#if 1" or "#if 0", but -// that's because they were constructed that way at ./configure time. -// Look at logging.h.in to see how they're calculated (based on your config). -#include // the normal place uint16_t is defined -#if @ac_cv_have_systypes_h@ -#include // the normal place u_int16_t is defined -#endif - -#if @ac_cv_have_libgflags@ -#include -#endif - -#include - -@ac_google_start_namespace@ - - typedef std::int32_t int32; -typedef std::uint32_t uint32; -typedef std::int64_t int64; -typedef std::uint64_t uint64; - -#if !(@ac_cv_have_ssize_t@) -typedef ptrdiff_t ssize_t; -#endif - -#if !(@ac_cv_have_mode_t@) -typedef int mode_t; -#endif - -typedef double WallTime; - -struct GLOG_EXPORT LogMessageTime { - LogMessageTime(); - LogMessageTime(std::tm t); - LogMessageTime(std::time_t timestamp, WallTime now); - - const time_t& timestamp() const { return timestamp_; } - const int& sec() const { return time_struct_.tm_sec; } - const int32_t& usec() const { return usecs_; } - const int&(min)() const { return time_struct_.tm_min; } - const int& hour() const { return time_struct_.tm_hour; } - const int& day() const { return time_struct_.tm_mday; } - const int& month() const { return time_struct_.tm_mon; } - const int& year() const { return time_struct_.tm_year; } - const int& dayOfWeek() const { return time_struct_.tm_wday; } - const int& dayInYear() const { return time_struct_.tm_yday; } - const int& dst() const { return time_struct_.tm_isdst; } - const long int& gmtoff() const { return gmtoffset_; } - const std::tm& tm() const { return time_struct_; } - - private: - void init(const std::tm& t, std::time_t timestamp, WallTime now); - std::tm time_struct_; // Time of creation of LogMessage - time_t timestamp_; // Time of creation of LogMessage in seconds - int32_t usecs_; // Time of creation of LogMessage - microseconds part - long int gmtoffset_; - - void CalcGmtOffset(); -}; - -struct LogMessageInfo { - explicit LogMessageInfo(const char* const severity_, - const char* const filename_, - const int& line_number_, - const int& thread_id_, - const LogMessageTime& time_): - severity(severity_), filename(filename_), line_number(line_number_), - thread_id(thread_id_), time(time_) - {} - - const char* const severity; - const char* const filename; - const int &line_number; - const int &thread_id; - const LogMessageTime& time; -}; - -typedef void(*CustomPrefixCallback)(std::ostream& s, const LogMessageInfo& l, void* data); - -@ac_google_end_namespace@ - - -// The global value of GOOGLE_STRIP_LOG. All the messages logged to -// LOG(XXX) with severity less than GOOGLE_STRIP_LOG will not be displayed. -// If it can be determined at compile time that the message will not be -// printed, the statement will be compiled out. -// -// Example: to strip out all INFO and WARNING messages, use the value -// of 2 below. To make an exception for WARNING messages from a single -// file, add "#define GOOGLE_STRIP_LOG 1" to that file _before_ including -// base/logging.h -#ifndef GOOGLE_STRIP_LOG -#define GOOGLE_STRIP_LOG 0 -#endif - -// GCC can be told that a certain branch is not likely to be taken (for -// instance, a CHECK failure), and use that information in static analysis. -// Giving it this information can help it optimize for the common case in -// the absence of better information (ie. -fprofile-arcs). -// -#ifndef GOOGLE_PREDICT_BRANCH_NOT_TAKEN -#if @ac_cv_have___builtin_expect@ -#define GOOGLE_PREDICT_BRANCH_NOT_TAKEN(x) (__builtin_expect(x, 0)) -#else -#define GOOGLE_PREDICT_BRANCH_NOT_TAKEN(x) x -#endif -#endif - -#ifndef GOOGLE_PREDICT_FALSE -#if @ac_cv_have___builtin_expect@ -#define GOOGLE_PREDICT_FALSE(x) (__builtin_expect(x, 0)) -#else -#define GOOGLE_PREDICT_FALSE(x) x -#endif -#endif - -#ifndef GOOGLE_PREDICT_TRUE -#if @ac_cv_have___builtin_expect@ -#define GOOGLE_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1)) -#else -#define GOOGLE_PREDICT_TRUE(x) x -#endif -#endif - - -// Make a bunch of macros for logging. The way to log things is to stream -// things to LOG(). E.g., -// -// LOG(INFO) << "Found " << num_cookies << " cookies"; -// -// You can capture log messages in a string, rather than reporting them -// immediately: -// -// vector errors; -// LOG_STRING(ERROR, &errors) << "Couldn't parse cookie #" << cookie_num; -// -// This pushes back the new error onto 'errors'; if given a NULL pointer, -// it reports the error via LOG(ERROR). -// -// You can also do conditional logging: -// -// LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies"; -// -// You can also do occasional logging (log every n'th occurrence of an -// event): -// -// LOG_EVERY_N(INFO, 10) << "Got the " << google::COUNTER << "th cookie"; -// -// The above will cause log messages to be output on the 1st, 11th, 21st, ... -// times it is executed. Note that the special google::COUNTER value is used -// to identify which repetition is happening. -// -// You can also do occasional conditional logging (log every n'th -// occurrence of an event, when condition is satisfied): -// -// LOG_IF_EVERY_N(INFO, (size > 1024), 10) << "Got the " << google::COUNTER -// << "th big cookie"; -// -// You can log messages the first N times your code executes a line. E.g. -// -// LOG_FIRST_N(INFO, 20) << "Got the " << google::COUNTER << "th cookie"; -// -// Outputs log messages for the first 20 times it is executed. -// -// Analogous SYSLOG, SYSLOG_IF, and SYSLOG_EVERY_N macros are available. -// These log to syslog as well as to the normal logs. If you use these at -// all, you need to be aware that syslog can drastically reduce performance, -// especially if it is configured for remote logging! Don't use these -// unless you fully understand this and have a concrete need to use them. -// Even then, try to minimize your use of them. -// -// There are also "debug mode" logging macros like the ones above: -// -// DLOG(INFO) << "Found cookies"; -// -// DLOG_IF(INFO, num_cookies > 10) << "Got lots of cookies"; -// -// DLOG_EVERY_N(INFO, 10) << "Got the " << google::COUNTER << "th cookie"; -// -// All "debug mode" logging is compiled away to nothing for non-debug mode -// compiles. -// -// We also have -// -// LOG_ASSERT(assertion); -// DLOG_ASSERT(assertion); -// -// which is syntactic sugar for {,D}LOG_IF(FATAL, assert fails) << assertion; -// -// There are "verbose level" logging macros. They look like -// -// VLOG(1) << "I'm printed when you run the program with --v=1 or more"; -// VLOG(2) << "I'm printed when you run the program with --v=2 or more"; -// -// These always log at the INFO log level (when they log at all). -// The verbose logging can also be turned on module-by-module. For instance, -// --vmodule=mapreduce=2,file=1,gfs*=3 --v=0 -// will cause: -// a. VLOG(2) and lower messages to be printed from mapreduce.{h,cc} -// b. VLOG(1) and lower messages to be printed from file.{h,cc} -// c. VLOG(3) and lower messages to be printed from files prefixed with "gfs" -// d. VLOG(0) and lower messages to be printed from elsewhere -// -// The wildcarding functionality shown by (c) supports both '*' (match -// 0 or more characters) and '?' (match any single character) wildcards. -// -// There's also VLOG_IS_ON(n) "verbose level" condition macro. To be used as -// -// if (VLOG_IS_ON(2)) { -// // do some logging preparation and logging -// // that can't be accomplished with just VLOG(2) << ...; -// } -// -// There are also VLOG_IF, VLOG_EVERY_N and VLOG_IF_EVERY_N "verbose level" -// condition macros for sample cases, when some extra computation and -// preparation for logs is not needed. -// VLOG_IF(1, (size > 1024)) -// << "I'm printed when size is more than 1024 and when you run the " -// "program with --v=1 or more"; -// VLOG_EVERY_N(1, 10) -// << "I'm printed every 10th occurrence, and when you run the program " -// "with --v=1 or more. Present occurence is " << google::COUNTER; -// VLOG_IF_EVERY_N(1, (size > 1024), 10) -// << "I'm printed on every 10th occurence of case when size is more " -// " than 1024, when you run the program with --v=1 or more. "; -// "Present occurence is " << google::COUNTER; -// -// The supported severity levels for macros that allow you to specify one -// are (in increasing order of severity) INFO, WARNING, ERROR, and FATAL. -// Note that messages of a given severity are logged not only in the -// logfile for that severity, but also in all logfiles of lower severity. -// E.g., a message of severity FATAL will be logged to the logfiles of -// severity FATAL, ERROR, WARNING, and INFO. -// -// There is also the special severity of DFATAL, which logs FATAL in -// debug mode, ERROR in normal mode. -// -// Very important: logging a message at the FATAL severity level causes -// the program to terminate (after the message is logged). -// -// Unless otherwise specified, logs will be written to the filename -// "...log..", followed -// by the date, time, and pid (you can't prevent the date, time, and pid -// from being in the filename). -// -// The logging code takes two flags: -// --v=# set the verbose level -// --logtostderr log all the messages to stderr instead of to logfiles - -// LOG LINE PREFIX FORMAT -// -// Log lines have this form: -// -// Lyyyymmdd hh:mm:ss.uuuuuu threadid file:line] msg... -// -// where the fields are defined as follows: -// -// L A single character, representing the log level -// (eg 'I' for INFO) -// yyyy The year -// mm The month (zero padded; ie May is '05') -// dd The day (zero padded) -// hh:mm:ss.uuuuuu Time in hours, minutes and fractional seconds -// threadid The space-padded thread ID as returned by GetTID() -// (this matches the PID on Linux) -// file The file name -// line The line number -// msg The user-supplied message -// -// Example: -// -// I1103 11:57:31.739339 24395 google.cc:2341] Command line: ./some_prog -// I1103 11:57:31.739403 24395 google.cc:2342] Process id 24395 -// -// NOTE: although the microseconds are useful for comparing events on -// a single machine, clocks on different machines may not be well -// synchronized. Hence, use caution when comparing the low bits of -// timestamps from different machines. - -#pragma push_macro("DECLARE_VARIABLE") -#pragma push_macro("DECLARE_bool") -#pragma push_macro("DECLARE_string") -#pragma push_macro("DECLARE_int32") -#pragma push_macro("DECLARE_uint32") - -#ifdef DECLARE_VARIABLE -#undef DECLARE_VARIABLE -#endif - -#ifdef DECLARE_bool -#undef DECLARE_bool -#endif - -#ifdef DECLARE_string -#undef DECLARE_string -#endif - -#ifdef DECLARE_int32 -#undef DECLARE_int32 -#endif - -#ifdef DECLARE_uint32 -#undef DECLARE_uint32 -#endif - -#ifndef DECLARE_VARIABLE -#define DECLARE_VARIABLE(type, shorttype, name, tn) \ - namespace fL##shorttype { \ - extern GLOG_EXPORT type FLAGS_##name; \ - } \ - using fL##shorttype::FLAGS_##name - -// bool specialization -#define DECLARE_bool(name) \ - DECLARE_VARIABLE(bool, B, name, bool) - -// int32 specialization -#define DECLARE_int32(name) \ - DECLARE_VARIABLE(@ac_google_namespace@::int32, I, name, int32) - -#if !defined(DECLARE_uint32) -// uint32 specialization -#define DECLARE_uint32(name) \ - DECLARE_VARIABLE(@ac_google_namespace@::uint32, U, name, uint32) -#endif // !defined(DECLARE_uint32) && !(@ac_cv_have_libgflags@) - -// Special case for string, because we have to specify the namespace -// std::string, which doesn't play nicely with our FLAG__namespace hackery. -#define DECLARE_string(name) \ - namespace fLS { \ - extern GLOG_EXPORT std::string& FLAGS_##name; \ - } \ - using fLS::FLAGS_##name -#endif - -// Set whether appending a timestamp to the log file name -DECLARE_bool(timestamp_in_logfile_name); - -// Set whether log messages go to stdout instead of logfiles -DECLARE_bool(logtostdout); - -// Set color messages logged to stdout (if supported by terminal). -DECLARE_bool(colorlogtostdout); - -// Set whether log messages go to stderr instead of logfiles -DECLARE_bool(logtostderr); - -// Set whether log messages go to stderr in addition to logfiles. -DECLARE_bool(alsologtostderr); - -// Set color messages logged to stderr (if supported by terminal). -DECLARE_bool(colorlogtostderr); - -// Log messages at a level >= this flag are automatically sent to -// stderr in addition to log files. -DECLARE_int32(stderrthreshold); - -// Set whether the log file header should be written upon creating a file. -DECLARE_bool(log_file_header); - -// Set whether the log prefix should be prepended to each line of output. -DECLARE_bool(log_prefix); - -// Set whether the year should be included in the log prefix. -DECLARE_bool(log_year_in_prefix); - -// Log messages at a level <= this flag are buffered. -// Log messages at a higher level are flushed immediately. -DECLARE_int32(logbuflevel); - -// Sets the maximum number of seconds which logs may be buffered for. -DECLARE_int32(logbufsecs); - -// Log suppression level: messages logged at a lower level than this -// are suppressed. -DECLARE_int32(minloglevel); - -// If specified, logfiles are written into this directory instead of the -// default logging directory. -DECLARE_string(log_dir); - -// Set the log file mode. -DECLARE_int32(logfile_mode); - -// Sets the path of the directory into which to put additional links -// to the log files. -DECLARE_string(log_link); - -DECLARE_int32(v); // in vlog_is_on.cc - -DECLARE_string(vmodule); // also in vlog_is_on.cc - -// Sets the maximum log file size (in MB). -DECLARE_uint32(max_log_size); - -// Sets whether to avoid logging to the disk if the disk is full. -DECLARE_bool(stop_logging_if_full_disk); - -// Use UTC time for logging -DECLARE_bool(log_utc_time); - -// Log messages below the GOOGLE_STRIP_LOG level will be compiled away for -// security reasons. See LOG(severtiy) below. - -// A few definitions of macros that don't generate much code. Since -// LOG(INFO) and its ilk are used all over our code, it's -// better to have compact code for these operations. - -#if GOOGLE_STRIP_LOG == 0 -#define COMPACT_GOOGLE_LOG_INFO @ac_google_namespace@::LogMessage( \ - __FILE__, __LINE__) -#define LOG_TO_STRING_INFO(message) @ac_google_namespace@::LogMessage( \ - __FILE__, __LINE__, @ac_google_namespace@::GLOG_INFO, message) -#else -#define COMPACT_GOOGLE_LOG_INFO @ac_google_namespace@::NullStream() -#define LOG_TO_STRING_INFO(message) @ac_google_namespace@::NullStream() -#endif - -#if GOOGLE_STRIP_LOG <= 1 -#define COMPACT_GOOGLE_LOG_WARNING @ac_google_namespace@::LogMessage( \ - __FILE__, __LINE__, @ac_google_namespace@::GLOG_WARNING) -#define LOG_TO_STRING_WARNING(message) @ac_google_namespace@::LogMessage( \ - __FILE__, __LINE__, @ac_google_namespace@::GLOG_WARNING, message) -#else -#define COMPACT_GOOGLE_LOG_WARNING @ac_google_namespace@::NullStream() -#define LOG_TO_STRING_WARNING(message) @ac_google_namespace@::NullStream() -#endif - -#if GOOGLE_STRIP_LOG <= 2 -#define COMPACT_GOOGLE_LOG_ERROR @ac_google_namespace@::LogMessage( \ - __FILE__, __LINE__, @ac_google_namespace@::GLOG_ERROR) -#define LOG_TO_STRING_ERROR(message) @ac_google_namespace@::LogMessage( \ - __FILE__, __LINE__, @ac_google_namespace@::GLOG_ERROR, message) -#else -#define COMPACT_GOOGLE_LOG_ERROR @ac_google_namespace@::NullStream() -#define LOG_TO_STRING_ERROR(message) @ac_google_namespace@::NullStream() -#endif - -#if GOOGLE_STRIP_LOG <= 3 -#define COMPACT_GOOGLE_LOG_FATAL @ac_google_namespace@::LogMessageFatal( \ - __FILE__, __LINE__) -#define LOG_TO_STRING_FATAL(message) @ac_google_namespace@::LogMessage( \ - __FILE__, __LINE__, @ac_google_namespace@::GLOG_FATAL, message) -#else -#define COMPACT_GOOGLE_LOG_FATAL @ac_google_namespace@::NullStreamFatal() -#define LOG_TO_STRING_FATAL(message) @ac_google_namespace@::NullStreamFatal() -#endif - -#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON) -#define DCHECK_IS_ON() 0 -#else -#define DCHECK_IS_ON() 1 -#endif - -// For DFATAL, we want to use LogMessage (as opposed to -// LogMessageFatal), to be consistent with the original behavior. -#if !DCHECK_IS_ON() -#define COMPACT_GOOGLE_LOG_DFATAL COMPACT_GOOGLE_LOG_ERROR -#elif GOOGLE_STRIP_LOG <= 3 -#define COMPACT_GOOGLE_LOG_DFATAL @ac_google_namespace@::LogMessage( \ - __FILE__, __LINE__, @ac_google_namespace@::GLOG_FATAL) -#else -#define COMPACT_GOOGLE_LOG_DFATAL @ac_google_namespace@::NullStreamFatal() -#endif - -#define GOOGLE_LOG_INFO(counter) @ac_google_namespace@::LogMessage(__FILE__, __LINE__, @ac_google_namespace@::GLOG_INFO, counter, &@ac_google_namespace@::LogMessage::SendToLog) -#define SYSLOG_INFO(counter) \ - @ac_google_namespace@::LogMessage(__FILE__, __LINE__, @ac_google_namespace@::GLOG_INFO, counter, \ - &@ac_google_namespace@::LogMessage::SendToSyslogAndLog) -#define GOOGLE_LOG_WARNING(counter) \ - @ac_google_namespace@::LogMessage(__FILE__, __LINE__, @ac_google_namespace@::GLOG_WARNING, counter, \ - &@ac_google_namespace@::LogMessage::SendToLog) -#define SYSLOG_WARNING(counter) \ - @ac_google_namespace@::LogMessage(__FILE__, __LINE__, @ac_google_namespace@::GLOG_WARNING, counter, \ - &@ac_google_namespace@::LogMessage::SendToSyslogAndLog) -#define GOOGLE_LOG_ERROR(counter) \ - @ac_google_namespace@::LogMessage(__FILE__, __LINE__, @ac_google_namespace@::GLOG_ERROR, counter, \ - &@ac_google_namespace@::LogMessage::SendToLog) -#define SYSLOG_ERROR(counter) \ - @ac_google_namespace@::LogMessage(__FILE__, __LINE__, @ac_google_namespace@::GLOG_ERROR, counter, \ - &@ac_google_namespace@::LogMessage::SendToSyslogAndLog) -#define GOOGLE_LOG_FATAL(counter) \ - @ac_google_namespace@::LogMessage(__FILE__, __LINE__, @ac_google_namespace@::GLOG_FATAL, counter, \ - &@ac_google_namespace@::LogMessage::SendToLog) -#define SYSLOG_FATAL(counter) \ - @ac_google_namespace@::LogMessage(__FILE__, __LINE__, @ac_google_namespace@::GLOG_FATAL, counter, \ - &@ac_google_namespace@::LogMessage::SendToSyslogAndLog) -#define GOOGLE_LOG_DFATAL(counter) \ - @ac_google_namespace@::LogMessage(__FILE__, __LINE__, @ac_google_namespace@::DFATAL_LEVEL, counter, \ - &@ac_google_namespace@::LogMessage::SendToLog) -#define SYSLOG_DFATAL(counter) \ - @ac_google_namespace@::LogMessage(__FILE__, __LINE__, @ac_google_namespace@::DFATAL_LEVEL, counter, \ - &@ac_google_namespace@::LogMessage::SendToSyslogAndLog) - -#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) || defined(__CYGWIN32__) -// A very useful logging macro to log windows errors: -#define LOG_SYSRESULT(result) \ - if (FAILED(HRESULT_FROM_WIN32(result))) { \ - LPSTR message = NULL; \ - LPSTR msg = reinterpret_cast(&message); \ - DWORD message_length = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | \ - FORMAT_MESSAGE_FROM_SYSTEM | \ - FORMAT_MESSAGE_IGNORE_INSERTS, \ - 0, result, 0, msg, 100, NULL); \ - if (message_length > 0) { \ - @ac_google_namespace@::LogMessage(__FILE__, __LINE__, @ac_google_namespace@::GLOG_ERROR, 0, \ - &@ac_google_namespace@::LogMessage::SendToLog).stream() \ - << reinterpret_cast(message); \ - LocalFree(message); \ - } \ - } -#endif - -// We use the preprocessor's merging operator, "##", so that, e.g., -// LOG(INFO) becomes the token GOOGLE_LOG_INFO. There's some funny -// subtle difference between ostream member streaming functions (e.g., -// ostream::operator<<(int) and ostream non-member streaming functions -// (e.g., ::operator<<(ostream&, string&): it turns out that it's -// impossible to stream something like a string directly to an unnamed -// ostream. We employ a neat hack by calling the stream() member -// function of LogMessage which seems to avoid the problem. -#define LOG(severity) COMPACT_GOOGLE_LOG_ ## severity.stream() -#define SYSLOG(severity) SYSLOG_ ## severity(0).stream() - -@ac_google_start_namespace@ - -// They need the definitions of integer types. -#include -#include - -// Initialize google's logging library. You will see the program name -// specified by argv0 in log outputs. -GLOG_EXPORT void InitGoogleLogging(const char* argv0); - -GLOG_EXPORT void InitGoogleLogging(const char* argv0, - CustomPrefixCallback prefix_callback, - void* prefix_callback_data = NULL); - -// Check if google's logging library has been initialized. -GLOG_EXPORT bool IsGoogleLoggingInitialized(); - -// Shutdown google's logging library. -GLOG_EXPORT void ShutdownGoogleLogging(); - -#if defined(__GNUC__) -typedef void (*logging_fail_func_t)() __attribute__((noreturn)); -#else -typedef void (*logging_fail_func_t)(); -#endif - -// Install a function which will be called after LOG(FATAL). -GLOG_EXPORT void InstallFailureFunction(logging_fail_func_t fail_func); - -// Enable/Disable old log cleaner. -GLOG_EXPORT void EnableLogCleaner(unsigned int overdue_days); -GLOG_EXPORT void DisableLogCleaner(); -GLOG_EXPORT void SetApplicationFingerprint(const std::string& fingerprint); - -class LogSink; // defined below - -// If a non-NULL sink pointer is given, we push this message to that sink. -// For LOG_TO_SINK we then do normal LOG(severity) logging as well. -// This is useful for capturing messages and passing/storing them -// somewhere more specific than the global log of the process. -// Argument types: -// LogSink* sink; -// LogSeverity severity; -// The cast is to disambiguate NULL arguments. -#define LOG_TO_SINK(sink, severity) \ - @ac_google_namespace@::LogMessage( \ - __FILE__, __LINE__, \ - @ac_google_namespace@::GLOG_ ## severity, \ - static_cast<@ac_google_namespace@::LogSink*>(sink), true).stream() -#define LOG_TO_SINK_BUT_NOT_TO_LOGFILE(sink, severity) \ - @ac_google_namespace@::LogMessage( \ - __FILE__, __LINE__, \ - @ac_google_namespace@::GLOG_ ## severity, \ - static_cast<@ac_google_namespace@::LogSink*>(sink), false).stream() - -// If a non-NULL string pointer is given, we write this message to that string. -// We then do normal LOG(severity) logging as well. -// This is useful for capturing messages and storing them somewhere more -// specific than the global log of the process. -// Argument types: -// string* message; -// LogSeverity severity; -// The cast is to disambiguate NULL arguments. -// NOTE: LOG(severity) expands to LogMessage().stream() for the specified -// severity. -#define LOG_TO_STRING(severity, message) \ - LOG_TO_STRING_##severity(static_cast(message)).stream() - -// If a non-NULL pointer is given, we push the message onto the end -// of a vector of strings; otherwise, we report it with LOG(severity). -// This is handy for capturing messages and perhaps passing them back -// to the caller, rather than reporting them immediately. -// Argument types: -// LogSeverity severity; -// vector *outvec; -// The cast is to disambiguate NULL arguments. -#define LOG_STRING(severity, outvec) \ - LOG_TO_STRING_##severity(static_cast*>(outvec)).stream() - -#define LOG_IF(severity, condition) \ - static_cast(0), \ - !(condition) ? (void) 0 : @ac_google_namespace@::LogMessageVoidify() & LOG(severity) -#define SYSLOG_IF(severity, condition) \ - static_cast(0), \ - !(condition) ? (void) 0 : @ac_google_namespace@::LogMessageVoidify() & SYSLOG(severity) - -#define LOG_ASSERT(condition) \ - LOG_IF(FATAL, !(condition)) << "Assert failed: " #condition -#define SYSLOG_ASSERT(condition) \ - SYSLOG_IF(FATAL, !(condition)) << "Assert failed: " #condition - -// CHECK dies with a fatal error if condition is not true. It is *not* -// controlled by DCHECK_IS_ON(), so the check will be executed regardless of -// compilation mode. Therefore, it is safe to do things like: -// CHECK(fp->Write(x) == 4) -#define CHECK(condition) \ - LOG_IF(FATAL, GOOGLE_PREDICT_BRANCH_NOT_TAKEN(!(condition))) \ - << "Check failed: " #condition " " - -// A container for a string pointer which can be evaluated to a bool - -// true iff the pointer is NULL. -struct CheckOpString { - CheckOpString(std::string* str) : str_(str) { } - // No destructor: if str_ is non-NULL, we're about to LOG(FATAL), - // so there's no point in cleaning up str_. - operator bool() const { - return GOOGLE_PREDICT_BRANCH_NOT_TAKEN(str_ != NULL); - } - std::string* str_; -}; - -// Function is overloaded for integral types to allow static const -// integrals declared in classes and not defined to be used as arguments to -// CHECK* macros. It's not encouraged though. -template -inline const T& GetReferenceableValue(const T& t) { return t; } -inline char GetReferenceableValue(char t) { return t; } -inline unsigned char GetReferenceableValue(unsigned char t) { return t; } -inline signed char GetReferenceableValue(signed char t) { return t; } -inline short GetReferenceableValue(short t) { return t; } -inline unsigned short GetReferenceableValue(unsigned short t) { return t; } -inline int GetReferenceableValue(int t) { return t; } -inline unsigned int GetReferenceableValue(unsigned int t) { return t; } -inline long GetReferenceableValue(long t) { return t; } -inline unsigned long GetReferenceableValue(unsigned long t) { return t; } -inline long long GetReferenceableValue(long long t) { return t; } -inline unsigned long long GetReferenceableValue(unsigned long long t) { - return t; -} - -// This is a dummy class to define the following operator. -struct DummyClassToDefineOperator {}; - -@ac_google_end_namespace@ - -// Define global operator<< to declare using ::operator<<. -// This declaration will allow use to use CHECK macros for user -// defined classes which have operator<< (e.g., stl_logging.h). -inline std::ostream& operator<<( - std::ostream& out, const google::DummyClassToDefineOperator&) { - return out; -} - -@ac_google_start_namespace@ - -// This formats a value for a failing CHECK_XX statement. Ordinarily, -// it uses the definition for operator<<, with a few special cases below. -template -inline void MakeCheckOpValueString(std::ostream* os, const T& v) { - (*os) << v; -} - -// Overrides for char types provide readable values for unprintable -// characters. -template <> GLOG_EXPORT -void MakeCheckOpValueString(std::ostream* os, const char& v); -template <> GLOG_EXPORT -void MakeCheckOpValueString(std::ostream* os, const signed char& v); -template <> GLOG_EXPORT -void MakeCheckOpValueString(std::ostream* os, const unsigned char& v); - -// Provide printable value for nullptr_t -template <> -GLOG_EXPORT void MakeCheckOpValueString(std::ostream* os, - const std::nullptr_t& v); - -// Build the error message string. Specify no inlining for code size. -template -std::string* MakeCheckOpString(const T1& v1, const T2& v2, const char* exprtext) - @ac_cv___attribute___noinline@; - -namespace base { -namespace internal { - -// If "s" is less than base_logging::INFO, returns base_logging::INFO. -// If "s" is greater than base_logging::FATAL, returns -// base_logging::ERROR. Otherwise, returns "s". -LogSeverity NormalizeSeverity(LogSeverity s); - -} // namespace internal - -// A helper class for formatting "expr (V1 vs. V2)" in a CHECK_XX -// statement. See MakeCheckOpString for sample usage. Other -// approaches were considered: use of a template method (e.g., -// base::BuildCheckOpString(exprtext, base::Print, &v1, -// base::Print, &v2), however this approach has complications -// related to volatile arguments and function-pointer arguments). -class GLOG_EXPORT CheckOpMessageBuilder { - public: - // Inserts "exprtext" and " (" to the stream. - explicit CheckOpMessageBuilder(const char *exprtext); - // Deletes "stream_". - ~CheckOpMessageBuilder(); - // For inserting the first variable. - std::ostream* ForVar1() { return stream_; } - // For inserting the second variable (adds an intermediate " vs. "). - std::ostream* ForVar2(); - // Get the result (inserts the closing ")"). - std::string* NewString(); - - private: - std::ostringstream *stream_; -}; - -} // namespace base - -template -std::string* MakeCheckOpString(const T1& v1, const T2& v2, const char* exprtext) { - base::CheckOpMessageBuilder comb(exprtext); - MakeCheckOpValueString(comb.ForVar1(), v1); - MakeCheckOpValueString(comb.ForVar2(), v2); - return comb.NewString(); -} - -// Helper functions for CHECK_OP macro. -// The (int, int) specialization works around the issue that the compiler -// will not instantiate the template version of the function on values of -// unnamed enum type - see comment below. -#define DEFINE_CHECK_OP_IMPL(name, op) \ - template \ - inline std::string* name##Impl(const T1& v1, const T2& v2, \ - const char* exprtext) { \ - if (GOOGLE_PREDICT_TRUE(v1 op v2)) return NULL; \ - else return MakeCheckOpString(v1, v2, exprtext); \ - } \ - inline std::string* name##Impl(int v1, int v2, const char* exprtext) { \ - return name##Impl(v1, v2, exprtext); \ - } - -// We use the full name Check_EQ, Check_NE, etc. in case the file including -// base/logging.h provides its own #defines for the simpler names EQ, NE, etc. -// This happens if, for example, those are used as token names in a -// yacc grammar. -DEFINE_CHECK_OP_IMPL(Check_EQ, ==) // Compilation error with CHECK_EQ(NULL, x)? -DEFINE_CHECK_OP_IMPL(Check_NE, !=) // Use CHECK(x == NULL) instead. -DEFINE_CHECK_OP_IMPL(Check_LE, <=) -DEFINE_CHECK_OP_IMPL(Check_LT, < ) -DEFINE_CHECK_OP_IMPL(Check_GE, >=) -DEFINE_CHECK_OP_IMPL(Check_GT, > ) -#undef DEFINE_CHECK_OP_IMPL - -// Helper macro for binary operators. -// Don't use this macro directly in your code, use CHECK_EQ et al below. - -#if defined(STATIC_ANALYSIS) -// Only for static analysis tool to know that it is equivalent to assert -#define CHECK_OP_LOG(name, op, val1, val2, log) CHECK((val1) op (val2)) -#elif DCHECK_IS_ON() -// In debug mode, avoid constructing CheckOpStrings if possible, -// to reduce the overhead of CHECK statments by 2x. -// Real DCHECK-heavy tests have seen 1.5x speedups. - -// The meaning of "string" might be different between now and -// when this macro gets invoked (e.g., if someone is experimenting -// with other string implementations that get defined after this -// file is included). Save the current meaning now and use it -// in the macro. -typedef std::string _Check_string; -#define CHECK_OP_LOG(name, op, val1, val2, log) \ - while (@ac_google_namespace@::_Check_string* _result = \ - @ac_google_namespace@::Check##name##Impl( \ - @ac_google_namespace@::GetReferenceableValue(val1), \ - @ac_google_namespace@::GetReferenceableValue(val2), \ - #val1 " " #op " " #val2)) \ - log(__FILE__, __LINE__, \ - @ac_google_namespace@::CheckOpString(_result)).stream() -#else -// In optimized mode, use CheckOpString to hint to compiler that -// the while condition is unlikely. -#define CHECK_OP_LOG(name, op, val1, val2, log) \ - while (@ac_google_namespace@::CheckOpString _result = \ - @ac_google_namespace@::Check##name##Impl( \ - @ac_google_namespace@::GetReferenceableValue(val1), \ - @ac_google_namespace@::GetReferenceableValue(val2), \ - #val1 " " #op " " #val2)) \ - log(__FILE__, __LINE__, _result).stream() -#endif // STATIC_ANALYSIS, DCHECK_IS_ON() - -#if GOOGLE_STRIP_LOG <= 3 -#define CHECK_OP(name, op, val1, val2) \ - CHECK_OP_LOG(name, op, val1, val2, @ac_google_namespace@::LogMessageFatal) -#else -#define CHECK_OP(name, op, val1, val2) \ - CHECK_OP_LOG(name, op, val1, val2, @ac_google_namespace@::NullStreamFatal) -#endif // STRIP_LOG <= 3 - -// Equality/Inequality checks - compare two values, and log a FATAL message -// including the two values when the result is not as expected. The values -// must have operator<<(ostream, ...) defined. -// -// You may append to the error message like so: -// CHECK_NE(1, 2) << ": The world must be ending!"; -// -// We are very careful to ensure that each argument is evaluated exactly -// once, and that anything which is legal to pass as a function argument is -// legal here. In particular, the arguments may be temporary expressions -// which will end up being destroyed at the end of the apparent statement, -// for example: -// CHECK_EQ(string("abc")[1], 'b'); -// -// WARNING: These don't compile correctly if one of the arguments is a pointer -// and the other is NULL. To work around this, simply static_cast NULL to the -// type of the desired pointer. - -#define CHECK_EQ(val1, val2) CHECK_OP(_EQ, ==, val1, val2) -#define CHECK_NE(val1, val2) CHECK_OP(_NE, !=, val1, val2) -#define CHECK_LE(val1, val2) CHECK_OP(_LE, <=, val1, val2) -#define CHECK_LT(val1, val2) CHECK_OP(_LT, < , val1, val2) -#define CHECK_GE(val1, val2) CHECK_OP(_GE, >=, val1, val2) -#define CHECK_GT(val1, val2) CHECK_OP(_GT, > , val1, val2) - -// Check that the input is non NULL. This very useful in constructor -// initializer lists. - -#define CHECK_NOTNULL(val) \ - @ac_google_namespace@::CheckNotNull(__FILE__, __LINE__, "'" #val "' Must be non NULL", (val)) - -// Helper functions for string comparisons. -// To avoid bloat, the definitions are in logging.cc. -#define DECLARE_CHECK_STROP_IMPL(func, expected) \ - GLOG_EXPORT std::string* Check##func##expected##Impl( \ - const char* s1, const char* s2, const char* names); -DECLARE_CHECK_STROP_IMPL(strcmp, true) -DECLARE_CHECK_STROP_IMPL(strcmp, false) -DECLARE_CHECK_STROP_IMPL(strcasecmp, true) -DECLARE_CHECK_STROP_IMPL(strcasecmp, false) -#undef DECLARE_CHECK_STROP_IMPL - -// Helper macro for string comparisons. -// Don't use this macro directly in your code, use CHECK_STREQ et al below. -#define CHECK_STROP(func, op, expected, s1, s2) \ - while (@ac_google_namespace@::CheckOpString _result = \ - @ac_google_namespace@::Check##func##expected##Impl((s1), (s2), \ - #s1 " " #op " " #s2)) \ - LOG(FATAL) << *_result.str_ - - -// String (char*) equality/inequality checks. -// CASE versions are case-insensitive. -// -// Note that "s1" and "s2" may be temporary strings which are destroyed -// by the compiler at the end of the current "full expression" -// (e.g. CHECK_STREQ(Foo().c_str(), Bar().c_str())). - -#define CHECK_STREQ(s1, s2) CHECK_STROP(strcmp, ==, true, s1, s2) -#define CHECK_STRNE(s1, s2) CHECK_STROP(strcmp, !=, false, s1, s2) -#define CHECK_STRCASEEQ(s1, s2) CHECK_STROP(strcasecmp, ==, true, s1, s2) -#define CHECK_STRCASENE(s1, s2) CHECK_STROP(strcasecmp, !=, false, s1, s2) - -#define CHECK_INDEX(I,A) CHECK(I < (sizeof(A)/sizeof(A[0]))) -#define CHECK_BOUND(B,A) CHECK(B <= (sizeof(A)/sizeof(A[0]))) - -#define CHECK_DOUBLE_EQ(val1, val2) \ - do { \ - CHECK_LE((val1), (val2)+0.000000000000001L); \ - CHECK_GE((val1), (val2)-0.000000000000001L); \ - } while (0) - -#define CHECK_NEAR(val1, val2, margin) \ - do { \ - CHECK_LE((val1), (val2)+(margin)); \ - CHECK_GE((val1), (val2)-(margin)); \ - } while (0) - -// perror()..googly style! -// -// PLOG() and PLOG_IF() and PCHECK() behave exactly like their LOG* and -// CHECK equivalents with the addition that they postpend a description -// of the current state of errno to their output lines. - -#define PLOG(severity) GOOGLE_PLOG(severity, 0).stream() - -#define GOOGLE_PLOG(severity, counter) \ - @ac_google_namespace@::ErrnoLogMessage( \ - __FILE__, __LINE__, @ac_google_namespace@::GLOG_ ## severity, counter, \ - &@ac_google_namespace@::LogMessage::SendToLog) - -#define PLOG_IF(severity, condition) \ - static_cast(0), \ - !(condition) ? (void) 0 : @ac_google_namespace@::LogMessageVoidify() & PLOG(severity) - -// A CHECK() macro that postpends errno if the condition is false. E.g. -// -// if (poll(fds, nfds, timeout) == -1) { PCHECK(errno == EINTR); ... } -#define PCHECK(condition) \ - PLOG_IF(FATAL, GOOGLE_PREDICT_BRANCH_NOT_TAKEN(!(condition))) \ - << "Check failed: " #condition " " - -// A CHECK() macro that lets you assert the success of a function that -// returns -1 and sets errno in case of an error. E.g. -// -// CHECK_ERR(mkdir(path, 0700)); -// -// or -// -// int fd = open(filename, flags); CHECK_ERR(fd) << ": open " << filename; -#define CHECK_ERR(invocation) \ -PLOG_IF(FATAL, GOOGLE_PREDICT_BRANCH_NOT_TAKEN((invocation) == -1)) \ - << #invocation - -// Use macro expansion to create, for each use of LOG_EVERY_N(), static -// variables with the __LINE__ expansion as part of the variable name. -#define LOG_EVERY_N_VARNAME(base, line) LOG_EVERY_N_VARNAME_CONCAT(base, line) -#define LOG_EVERY_N_VARNAME_CONCAT(base, line) base ## line - -#define LOG_OCCURRENCES LOG_EVERY_N_VARNAME(occurrences_, __LINE__) -#define LOG_OCCURRENCES_MOD_N LOG_EVERY_N_VARNAME(occurrences_mod_n_, __LINE__) - -#define LOG_TIME_PERIOD LOG_EVERY_N_VARNAME(timePeriod_, __LINE__) -#define LOG_PREVIOUS_TIME_RAW LOG_EVERY_N_VARNAME(previousTimeRaw_, __LINE__) -#define LOG_TIME_DELTA LOG_EVERY_N_VARNAME(deltaTime_, __LINE__) -#define LOG_CURRENT_TIME LOG_EVERY_N_VARNAME(currentTime_, __LINE__) -#define LOG_PREVIOUS_TIME LOG_EVERY_N_VARNAME(previousTime_, __LINE__) - -#if defined(__has_feature) -# if __has_feature(thread_sanitizer) -# define GLOG_SANITIZE_THREAD 1 -# endif -#endif - -#if !defined(GLOG_SANITIZE_THREAD) && defined(__SANITIZE_THREAD__) && __SANITIZE_THREAD__ -# define GLOG_SANITIZE_THREAD 1 -#endif - -#if defined(GLOG_SANITIZE_THREAD) -#define GLOG_IFDEF_THREAD_SANITIZER(X) X -#else -#define GLOG_IFDEF_THREAD_SANITIZER(X) -#endif - -#if defined(GLOG_SANITIZE_THREAD) -} // namespace google - -// We need to identify the static variables as "benign" races -// to avoid noisy reports from TSAN. -extern "C" void AnnotateBenignRaceSized( - const char *file, - int line, - const volatile void *mem, - size_t size, - const char *description); - -namespace google { -#endif - -#define SOME_KIND_OF_LOG_EVERY_T(severity, seconds) \ - constexpr std::chrono::nanoseconds LOG_TIME_PERIOD = \ - std::chrono::duration_cast( \ - std::chrono::duration(seconds)); \ - static std::atomic<@ac_google_namespace@ ::int64> LOG_PREVIOUS_TIME_RAW; \ - GLOG_IFDEF_THREAD_SANITIZER( \ - AnnotateBenignRaceSized(__FILE__, __LINE__, &LOG_TIME_PERIOD, \ - sizeof(@ac_google_namespace @ ::int64), "")); \ - GLOG_IFDEF_THREAD_SANITIZER( \ - AnnotateBenignRaceSized(__FILE__, __LINE__, &LOG_PREVIOUS_TIME_RAW, \ - sizeof(@ac_google_namespace @ ::int64), "")); \ - const auto LOG_CURRENT_TIME = \ - std::chrono::duration_cast( \ - std::chrono::steady_clock::now().time_since_epoch()); \ - const auto LOG_PREVIOUS_TIME = \ - LOG_PREVIOUS_TIME_RAW.load(std::memory_order_relaxed); \ - const auto LOG_TIME_DELTA = \ - LOG_CURRENT_TIME - std::chrono::nanoseconds(LOG_PREVIOUS_TIME); \ - if (LOG_TIME_DELTA > LOG_TIME_PERIOD) \ - LOG_PREVIOUS_TIME_RAW.store( \ - std::chrono::duration_cast(LOG_CURRENT_TIME) \ - .count(), \ - std::memory_order_relaxed); \ - if (LOG_TIME_DELTA > LOG_TIME_PERIOD) \ - @ac_google_namespace@ ::LogMessage( \ - __FILE__, __LINE__, @ac_google_namespace@ ::GLOG_##severity) \ - .stream() - -#define SOME_KIND_OF_LOG_EVERY_N(severity, n, what_to_do) \ - static std::atomic LOG_OCCURRENCES(0), LOG_OCCURRENCES_MOD_N(0); \ - GLOG_IFDEF_THREAD_SANITIZER(AnnotateBenignRaceSized(__FILE__, __LINE__, &LOG_OCCURRENCES, sizeof(int), "")); \ - GLOG_IFDEF_THREAD_SANITIZER(AnnotateBenignRaceSized(__FILE__, __LINE__, &LOG_OCCURRENCES_MOD_N, sizeof(int), "")); \ - ++LOG_OCCURRENCES; \ - if (++LOG_OCCURRENCES_MOD_N > n) LOG_OCCURRENCES_MOD_N -= n; \ - if (LOG_OCCURRENCES_MOD_N == 1) \ - @ac_google_namespace@::LogMessage( \ - __FILE__, __LINE__, @ac_google_namespace@::GLOG_ ## severity, LOG_OCCURRENCES, \ - &what_to_do).stream() - -#define SOME_KIND_OF_LOG_IF_EVERY_N(severity, condition, n, what_to_do) \ - static std::atomic LOG_OCCURRENCES(0), LOG_OCCURRENCES_MOD_N(0); \ - GLOG_IFDEF_THREAD_SANITIZER(AnnotateBenignRaceSized(__FILE__, __LINE__, &LOG_OCCURRENCES, sizeof(int), "")); \ - GLOG_IFDEF_THREAD_SANITIZER(AnnotateBenignRaceSized(__FILE__, __LINE__, &LOG_OCCURRENCES_MOD_N, sizeof(int), "")); \ - ++LOG_OCCURRENCES; \ - if ((condition) && \ - ((LOG_OCCURRENCES_MOD_N=(LOG_OCCURRENCES_MOD_N + 1) % n) == (1 % n))) \ - @ac_google_namespace@::LogMessage( \ - __FILE__, __LINE__, @ac_google_namespace@::GLOG_ ## severity, LOG_OCCURRENCES, \ - &what_to_do).stream() - -#define SOME_KIND_OF_PLOG_EVERY_N(severity, n, what_to_do) \ - static std::atomic LOG_OCCURRENCES(0), LOG_OCCURRENCES_MOD_N(0); \ - GLOG_IFDEF_THREAD_SANITIZER(AnnotateBenignRaceSized(__FILE__, __LINE__, &LOG_OCCURRENCES, sizeof(int), "")); \ - GLOG_IFDEF_THREAD_SANITIZER(AnnotateBenignRaceSized(__FILE__, __LINE__, &LOG_OCCURRENCES_MOD_N, sizeof(int), "")); \ - ++LOG_OCCURRENCES; \ - if (++LOG_OCCURRENCES_MOD_N > n) LOG_OCCURRENCES_MOD_N -= n; \ - if (LOG_OCCURRENCES_MOD_N == 1) \ - @ac_google_namespace@::ErrnoLogMessage( \ - __FILE__, __LINE__, @ac_google_namespace@::GLOG_ ## severity, LOG_OCCURRENCES, \ - &what_to_do).stream() - -#define SOME_KIND_OF_LOG_FIRST_N(severity, n, what_to_do) \ - static std::atomic LOG_OCCURRENCES(0); \ - GLOG_IFDEF_THREAD_SANITIZER(AnnotateBenignRaceSized(__FILE__, __LINE__, &LOG_OCCURRENCES, sizeof(int), "")); \ - if (LOG_OCCURRENCES <= n) \ - ++LOG_OCCURRENCES; \ - if (LOG_OCCURRENCES <= n) \ - @ac_google_namespace@::LogMessage( \ - __FILE__, __LINE__, @ac_google_namespace@::GLOG_ ## severity, LOG_OCCURRENCES, \ - &what_to_do).stream() - -namespace glog_internal_namespace_ { -template -struct CompileAssert { -}; -struct CrashReason; - -// Returns true if FailureSignalHandler is installed. -// Needs to be exported since it's used by the signalhandler_unittest. -GLOG_EXPORT bool IsFailureSignalHandlerInstalled(); -} // namespace glog_internal_namespace_ - -#define LOG_EVERY_N(severity, n) \ - SOME_KIND_OF_LOG_EVERY_N(severity, (n), @ac_google_namespace@::LogMessage::SendToLog) - -#define LOG_EVERY_T(severity, T) SOME_KIND_OF_LOG_EVERY_T(severity, (T)) - -#define SYSLOG_EVERY_N(severity, n) \ - SOME_KIND_OF_LOG_EVERY_N(severity, (n), @ac_google_namespace@::LogMessage::SendToSyslogAndLog) - -#define PLOG_EVERY_N(severity, n) \ - SOME_KIND_OF_PLOG_EVERY_N(severity, (n), @ac_google_namespace@::LogMessage::SendToLog) - -#define LOG_FIRST_N(severity, n) \ - SOME_KIND_OF_LOG_FIRST_N(severity, (n), @ac_google_namespace@::LogMessage::SendToLog) - -#define LOG_IF_EVERY_N(severity, condition, n) \ - SOME_KIND_OF_LOG_IF_EVERY_N(severity, (condition), (n), @ac_google_namespace@::LogMessage::SendToLog) - -// We want the special COUNTER value available for LOG_EVERY_X()'ed messages -enum PRIVATE_Counter {COUNTER}; - -#ifdef GLOG_NO_ABBREVIATED_SEVERITIES -// wingdi.h defines ERROR to be 0. When we call LOG(ERROR), it gets -// substituted with 0, and it expands to COMPACT_GOOGLE_LOG_0. To allow us -// to keep using this syntax, we define this macro to do the same thing -// as COMPACT_GOOGLE_LOG_ERROR. -#define COMPACT_GOOGLE_LOG_0 COMPACT_GOOGLE_LOG_ERROR -#define SYSLOG_0 SYSLOG_ERROR -#define LOG_TO_STRING_0 LOG_TO_STRING_ERROR -// Needed for LOG_IS_ON(ERROR). -const LogSeverity GLOG_0 = GLOG_ERROR; -#else -// Users may include windows.h after logging.h without -// GLOG_NO_ABBREVIATED_SEVERITIES nor WIN32_LEAN_AND_MEAN. -// For this case, we cannot detect if ERROR is defined before users -// actually use ERROR. Let's make an undefined symbol to warn users. -# define GLOG_ERROR_MSG ERROR_macro_is_defined_Define_GLOG_NO_ABBREVIATED_SEVERITIES_before_including_logging_h_See_the_document_for_detail -# define COMPACT_GOOGLE_LOG_0 GLOG_ERROR_MSG -# define SYSLOG_0 GLOG_ERROR_MSG -# define LOG_TO_STRING_0 GLOG_ERROR_MSG -# define GLOG_0 GLOG_ERROR_MSG -#endif - -// Plus some debug-logging macros that get compiled to nothing for production - -#if DCHECK_IS_ON() - -#define DLOG(severity) LOG(severity) -#define DVLOG(verboselevel) VLOG(verboselevel) -#define DLOG_IF(severity, condition) LOG_IF(severity, condition) -#define DLOG_EVERY_N(severity, n) LOG_EVERY_N(severity, n) -#define DLOG_IF_EVERY_N(severity, condition, n) \ - LOG_IF_EVERY_N(severity, condition, n) -#define DLOG_ASSERT(condition) LOG_ASSERT(condition) - -// debug-only checking. executed if DCHECK_IS_ON(). -#define DCHECK(condition) CHECK(condition) -#define DCHECK_EQ(val1, val2) CHECK_EQ(val1, val2) -#define DCHECK_NE(val1, val2) CHECK_NE(val1, val2) -#define DCHECK_LE(val1, val2) CHECK_LE(val1, val2) -#define DCHECK_LT(val1, val2) CHECK_LT(val1, val2) -#define DCHECK_GE(val1, val2) CHECK_GE(val1, val2) -#define DCHECK_GT(val1, val2) CHECK_GT(val1, val2) -#define DCHECK_NOTNULL(val) CHECK_NOTNULL(val) -#define DCHECK_STREQ(str1, str2) CHECK_STREQ(str1, str2) -#define DCHECK_STRCASEEQ(str1, str2) CHECK_STRCASEEQ(str1, str2) -#define DCHECK_STRNE(str1, str2) CHECK_STRNE(str1, str2) -#define DCHECK_STRCASENE(str1, str2) CHECK_STRCASENE(str1, str2) - -#else // !DCHECK_IS_ON() - -#define DLOG(severity) \ - static_cast(0), \ - true ? (void) 0 : @ac_google_namespace@::LogMessageVoidify() & LOG(severity) - -#define DVLOG(verboselevel) \ - static_cast(0), \ - (true || !VLOG_IS_ON(verboselevel)) ? \ - (void) 0 : @ac_google_namespace@::LogMessageVoidify() & LOG(INFO) - -#define DLOG_IF(severity, condition) \ - static_cast(0), \ - (true || !(condition)) ? (void) 0 : @ac_google_namespace@::LogMessageVoidify() & LOG(severity) - -#define DLOG_EVERY_N(severity, n) \ - static_cast(0), \ - true ? (void) 0 : @ac_google_namespace@::LogMessageVoidify() & LOG(severity) - -#define DLOG_IF_EVERY_N(severity, condition, n) \ - static_cast(0), \ - (true || !(condition))? (void) 0 : @ac_google_namespace@::LogMessageVoidify() & LOG(severity) - -#define DLOG_ASSERT(condition) \ - static_cast(0), \ - true ? (void) 0 : LOG_ASSERT(condition) - -// MSVC warning C4127: conditional expression is constant -#define DCHECK(condition) \ - GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ - while (false) \ - GLOG_MSVC_POP_WARNING() CHECK(condition) - -#define DCHECK_EQ(val1, val2) \ - GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ - while (false) \ - GLOG_MSVC_POP_WARNING() CHECK_EQ(val1, val2) - -#define DCHECK_NE(val1, val2) \ - GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ - while (false) \ - GLOG_MSVC_POP_WARNING() CHECK_NE(val1, val2) - -#define DCHECK_LE(val1, val2) \ - GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ - while (false) \ - GLOG_MSVC_POP_WARNING() CHECK_LE(val1, val2) - -#define DCHECK_LT(val1, val2) \ - GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ - while (false) \ - GLOG_MSVC_POP_WARNING() CHECK_LT(val1, val2) - -#define DCHECK_GE(val1, val2) \ - GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ - while (false) \ - GLOG_MSVC_POP_WARNING() CHECK_GE(val1, val2) - -#define DCHECK_GT(val1, val2) \ - GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ - while (false) \ - GLOG_MSVC_POP_WARNING() CHECK_GT(val1, val2) - -// You may see warnings in release mode if you don't use the return -// value of DCHECK_NOTNULL. Please just use DCHECK for such cases. -#define DCHECK_NOTNULL(val) (val) - -#define DCHECK_STREQ(str1, str2) \ - GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ - while (false) \ - GLOG_MSVC_POP_WARNING() CHECK_STREQ(str1, str2) - -#define DCHECK_STRCASEEQ(str1, str2) \ - GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ - while (false) \ - GLOG_MSVC_POP_WARNING() CHECK_STRCASEEQ(str1, str2) - -#define DCHECK_STRNE(str1, str2) \ - GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ - while (false) \ - GLOG_MSVC_POP_WARNING() CHECK_STRNE(str1, str2) - -#define DCHECK_STRCASENE(str1, str2) \ - GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ - while (false) \ - GLOG_MSVC_POP_WARNING() CHECK_STRCASENE(str1, str2) - -#endif // DCHECK_IS_ON() - -// Log only in verbose mode. - -#define VLOG(verboselevel) LOG_IF(INFO, VLOG_IS_ON(verboselevel)) - -#define VLOG_IF(verboselevel, condition) \ - LOG_IF(INFO, (condition) && VLOG_IS_ON(verboselevel)) - -#define VLOG_EVERY_N(verboselevel, n) \ - LOG_IF_EVERY_N(INFO, VLOG_IS_ON(verboselevel), n) - -#define VLOG_IF_EVERY_N(verboselevel, condition, n) \ - LOG_IF_EVERY_N(INFO, (condition) && VLOG_IS_ON(verboselevel), n) - -namespace base_logging { - -// LogMessage::LogStream is a std::ostream backed by this streambuf. -// This class ignores overflow and leaves two bytes at the end of the -// buffer to allow for a '\n' and '\0'. -class GLOG_EXPORT LogStreamBuf : public std::streambuf { - public: - // REQUIREMENTS: "len" must be >= 2 to account for the '\n' and '\0'. - LogStreamBuf(char *buf, int len) { - setp(buf, buf + len - 2); - } - - // This effectively ignores overflow. - int_type overflow(int_type ch) { - return ch; - } - - // Legacy public ostrstream method. - size_t pcount() const { return static_cast(pptr() - pbase()); } - char* pbase() const { return std::streambuf::pbase(); } -}; - -} // namespace base_logging - -// -// This class more or less represents a particular log message. You -// create an instance of LogMessage and then stream stuff to it. -// When you finish streaming to it, ~LogMessage is called and the -// full message gets streamed to the appropriate destination. -// -// You shouldn't actually use LogMessage's constructor to log things, -// though. You should use the LOG() macro (and variants thereof) -// above. -class GLOG_EXPORT LogMessage { -public: - enum { - // Passing kNoLogPrefix for the line number disables the - // log-message prefix. Useful for using the LogMessage - // infrastructure as a printing utility. See also the --log_prefix - // flag for controlling the log-message prefix on an - // application-wide basis. - kNoLogPrefix = -1 - }; - - // LogStream inherit from non-DLL-exported class (std::ostrstream) - // and VC++ produces a warning for this situation. - // However, MSDN says "C4275 can be ignored in Microsoft Visual C++ - // 2005 if you are deriving from a type in the Standard C++ Library" - // http://msdn.microsoft.com/en-us/library/3tdb471s(VS.80).aspx - // Let's just ignore the warning. -GLOG_MSVC_PUSH_DISABLE_WARNING(4275) - class GLOG_EXPORT LogStream : public std::ostream { -GLOG_MSVC_POP_WARNING() - public: - LogStream(char *buf, int len, int64 ctr) - : std::ostream(NULL), - streambuf_(buf, len), - ctr_(ctr), - self_(this) { - rdbuf(&streambuf_); - } - - int64 ctr() const { return ctr_; } - void set_ctr(int64 ctr) { ctr_ = ctr; } - LogStream* self() const { return self_; } - - // Legacy std::streambuf methods. - size_t pcount() const { return streambuf_.pcount(); } - char* pbase() const { return streambuf_.pbase(); } - char* str() const { return pbase(); } - - private: - LogStream(const LogStream&); - LogStream& operator=(const LogStream&); - base_logging::LogStreamBuf streambuf_; - int64 ctr_; // Counter hack (for the LOG_EVERY_X() macro) - LogStream *self_; // Consistency check hack - }; - -public: - // icc 8 requires this typedef to avoid an internal compiler error. - typedef void (LogMessage::*SendMethod)(); - - LogMessage(const char* file, int line, LogSeverity severity, int64 ctr, - SendMethod send_method); - - // Two special constructors that generate reduced amounts of code at - // LOG call sites for common cases. - - // Used for LOG(INFO): Implied are: - // severity = INFO, ctr = 0, send_method = &LogMessage::SendToLog. - // - // Using this constructor instead of the more complex constructor above - // saves 19 bytes per call site. - LogMessage(const char* file, int line); - - // Used for LOG(severity) where severity != INFO. Implied - // are: ctr = 0, send_method = &LogMessage::SendToLog - // - // Using this constructor instead of the more complex constructor above - // saves 17 bytes per call site. - LogMessage(const char* file, int line, LogSeverity severity); - - // Constructor to log this message to a specified sink (if not NULL). - // Implied are: ctr = 0, send_method = &LogMessage::SendToSinkAndLog if - // also_send_to_log is true, send_method = &LogMessage::SendToSink otherwise. - LogMessage(const char* file, int line, LogSeverity severity, LogSink* sink, - bool also_send_to_log); - - // Constructor where we also give a vector pointer - // for storing the messages (if the pointer is not NULL). - // Implied are: ctr = 0, send_method = &LogMessage::SaveOrSendToLog. - LogMessage(const char* file, int line, LogSeverity severity, - std::vector* outvec); - - // Constructor where we also give a string pointer for storing the - // message (if the pointer is not NULL). Implied are: ctr = 0, - // send_method = &LogMessage::WriteToStringAndLog. - LogMessage(const char* file, int line, LogSeverity severity, - std::string* message); - - // A special constructor used for check failures - LogMessage(const char* file, int line, const CheckOpString& result); - - ~LogMessage(); - - // Flush a buffered message to the sink set in the constructor. Always - // called by the destructor, it may also be called from elsewhere if - // needed. Only the first call is actioned; any later ones are ignored. - void Flush(); - - // An arbitrary limit on the length of a single log message. This - // is so that streaming can be done more efficiently. - static const size_t kMaxLogMessageLen; - - // Theses should not be called directly outside of logging.*, - // only passed as SendMethod arguments to other LogMessage methods: - void SendToLog(); // Actually dispatch to the logs - void SendToSyslogAndLog(); // Actually dispatch to syslog and the logs - - // Call abort() or similar to perform LOG(FATAL) crash. - [[noreturn]] static void Fail(); - - std::ostream& stream(); - - int preserved_errno() const; - - // Must be called without the log_mutex held. (L < log_mutex) - static int64 num_messages(int severity); - - const LogMessageTime& getLogMessageTime() const; - - struct LogMessageData; - -private: - // Fully internal SendMethod cases: - void SendToSinkAndLog(); // Send to sink if provided and dispatch to the logs - void SendToSink(); // Send to sink if provided, do nothing otherwise. - - // Write to string if provided and dispatch to the logs. - void WriteToStringAndLog(); - - void SaveOrSendToLog(); // Save to stringvec if provided, else to logs - - void Init(const char* file, int line, LogSeverity severity, - void (LogMessage::*send_method)()); - - // Used to fill in crash information during LOG(FATAL) failures. - void RecordCrashReason(glog_internal_namespace_::CrashReason* reason); - - // Counts of messages sent at each priority: - static int64 num_messages_[NUM_SEVERITIES]; // under log_mutex - - // We keep the data in a separate struct so that each instance of - // LogMessage uses less stack space. - LogMessageData* allocated_; - LogMessageData* data_; - LogMessageTime logmsgtime_; - - friend class LogDestination; - - LogMessage(const LogMessage&); - void operator=(const LogMessage&); -}; - -// This class happens to be thread-hostile because all instances share -// a single data buffer, but since it can only be created just before -// the process dies, we don't worry so much. -class GLOG_EXPORT LogMessageFatal : public LogMessage { - public: - LogMessageFatal(const char* file, int line); - LogMessageFatal(const char* file, int line, const CheckOpString& result); - [[noreturn]] ~LogMessageFatal(); -}; - -// A non-macro interface to the log facility; (useful -// when the logging level is not a compile-time constant). -inline void LogAtLevel(int const severity, std::string const &msg) { - LogMessage(__FILE__, __LINE__, severity).stream() << msg; -} - -// A macro alternative of LogAtLevel. New code may want to use this -// version since there are two advantages: 1. this version outputs the -// file name and the line number where this macro is put like other -// LOG macros, 2. this macro can be used as C++ stream. -#define LOG_AT_LEVEL(severity) @ac_google_namespace@::LogMessage(__FILE__, __LINE__, severity).stream() - -// Helper for CHECK_NOTNULL(). -// -// In C++11, all cases can be handled by a single function. Since the value -// category of the argument is preserved (also for rvalue references), -// member initializer lists like the one below will compile correctly: -// -// Foo() -// : x_(CHECK_NOTNULL(MethodReturningUniquePtr())) {} -template -T CheckNotNull(const char* file, int line, const char* names, T&& t) { - if (t == nullptr) { - LogMessageFatal(file, line, new std::string(names)); - } - return std::forward(t); -} - -// Allow folks to put a counter in the LOG_EVERY_X()'ed messages. This -// only works if ostream is a LogStream. If the ostream is not a -// LogStream you'll get an assert saying as much at runtime. -GLOG_EXPORT std::ostream& operator<<(std::ostream &os, - const PRIVATE_Counter&); - - -// Derived class for PLOG*() above. -class GLOG_EXPORT ErrnoLogMessage : public LogMessage { - public: - ErrnoLogMessage(const char* file, int line, LogSeverity severity, int64 ctr, - void (LogMessage::*send_method)()); - - // Postpends ": strerror(errno) [errno]". - ~ErrnoLogMessage(); - - private: - ErrnoLogMessage(const ErrnoLogMessage&); - void operator=(const ErrnoLogMessage&); -}; - - -// This class is used to explicitly ignore values in the conditional -// logging macros. This avoids compiler warnings like "value computed -// is not used" and "statement has no effect". - -class GLOG_EXPORT LogMessageVoidify { - public: - LogMessageVoidify() { } - // This has to be an operator with a precedence lower than << but - // higher than ?: - void operator&(std::ostream&) { } -}; - - -// Flushes all log files that contains messages that are at least of -// the specified severity level. Thread-safe. -GLOG_EXPORT void FlushLogFiles(LogSeverity min_severity); - -// Flushes all log files that contains messages that are at least of -// the specified severity level. Thread-hostile because it ignores -// locking -- used for catastrophic failures. -GLOG_EXPORT void FlushLogFilesUnsafe(LogSeverity min_severity); - -// -// Set the destination to which a particular severity level of log -// messages is sent. If base_filename is "", it means "don't log this -// severity". Thread-safe. -// -GLOG_EXPORT void SetLogDestination(LogSeverity severity, - const char* base_filename); - -// -// Set the basename of the symlink to the latest log file at a given -// severity. If symlink_basename is empty, do not make a symlink. If -// you don't call this function, the symlink basename is the -// invocation name of the program. Thread-safe. -// -GLOG_EXPORT void SetLogSymlink(LogSeverity severity, - const char* symlink_basename); - -// -// Used to send logs to some other kind of destination -// Users should subclass LogSink and override send to do whatever they want. -// Implementations must be thread-safe because a shared instance will -// be called from whichever thread ran the LOG(XXX) line. -class GLOG_EXPORT LogSink { - public: - virtual ~LogSink(); - - // Sink's logging logic (message_len is such as to exclude '\n' at the end). - // This method can't use LOG() or CHECK() as logging system mutex(s) are held - // during this call. - virtual void send(LogSeverity severity, const char* full_filename, - const char* base_filename, int line, - const LogMessageTime& logmsgtime, const char* message, - size_t message_len); - // Provide an overload for compatibility purposes - GLOG_DEPRECATED - virtual void send(LogSeverity severity, const char* full_filename, - const char* base_filename, int line, const std::tm* t, - const char* message, size_t message_len); - - // Redefine this to implement waiting for - // the sink's logging logic to complete. - // It will be called after each send() returns, - // but before that LogMessage exits or crashes. - // By default this function does nothing. - // Using this function one can implement complex logic for send() - // that itself involves logging; and do all this w/o causing deadlocks and - // inconsistent rearrangement of log messages. - // E.g. if a LogSink has thread-specific actions, the send() method - // can simply add the message to a queue and wake up another thread that - // handles real logging while itself making some LOG() calls; - // WaitTillSent() can be implemented to wait for that logic to complete. - // See our unittest for an example. - virtual void WaitTillSent(); - - // Returns the normal text output of the log message. - // Can be useful to implement send(). - static std::string ToString(LogSeverity severity, const char* file, int line, - const LogMessageTime &logmsgtime, - const char* message, size_t message_len); -}; - -// Add or remove a LogSink as a consumer of logging data. Thread-safe. -GLOG_EXPORT void AddLogSink(LogSink *destination); -GLOG_EXPORT void RemoveLogSink(LogSink *destination); - -// -// Specify an "extension" added to the filename specified via -// SetLogDestination. This applies to all severity levels. It's -// often used to append the port we're listening on to the logfile -// name. Thread-safe. -// -GLOG_EXPORT void SetLogFilenameExtension( - const char* filename_extension); - -// -// Make it so that all log messages of at least a particular severity -// are logged to stderr (in addition to logging to the usual log -// file(s)). Thread-safe. -// -GLOG_EXPORT void SetStderrLogging(LogSeverity min_severity); - -// -// Make it so that all log messages go only to stderr. Thread-safe. -// -GLOG_EXPORT void LogToStderr(); - -// -// Make it so that all log messages of at least a particular severity are -// logged via email to a list of addresses (in addition to logging to the -// usual log file(s)). The list of addresses is just a string containing -// the email addresses to send to (separated by spaces, say). Thread-safe. -// -GLOG_EXPORT void SetEmailLogging(LogSeverity min_severity, - const char* addresses); - -// A simple function that sends email. dest is a commma-separated -// list of addressess. Thread-safe. -GLOG_EXPORT bool SendEmail(const char* dest, const char* subject, - const char* body); - -GLOG_EXPORT const std::vector& GetLoggingDirectories(); - -// For tests only: Clear the internal [cached] list of logging directories to -// force a refresh the next time GetLoggingDirectories is called. -// Thread-hostile. -void TestOnly_ClearLoggingDirectoriesList(); - -// Returns a set of existing temporary directories, which will be a -// subset of the directories returned by GetLoggingDirectories(). -// Thread-safe. -GLOG_EXPORT void GetExistingTempDirectories( - std::vector* list); - -// Print any fatal message again -- useful to call from signal handler -// so that the last thing in the output is the fatal message. -// Thread-hostile, but a race is unlikely. -GLOG_EXPORT void ReprintFatalMessage(); - -// Truncate a log file that may be the append-only output of multiple -// processes and hence can't simply be renamed/reopened (typically a -// stdout/stderr). If the file "path" is > "limit" bytes, copy the -// last "keep" bytes to offset 0 and truncate the rest. Since we could -// be racing with other writers, this approach has the potential to -// lose very small amounts of data. For security, only follow symlinks -// if the path is /proc/self/fd/* -GLOG_EXPORT void TruncateLogFile(const char* path, uint64 limit, uint64 keep); - -// Truncate stdout and stderr if they are over the value specified by -// --max_log_size; keep the final 1MB. This function has the same -// race condition as TruncateLogFile. -GLOG_EXPORT void TruncateStdoutStderr(); - -// Return the string representation of the provided LogSeverity level. -// Thread-safe. -GLOG_EXPORT const char* GetLogSeverityName(LogSeverity severity); - -// --------------------------------------------------------------------- -// Implementation details that are not useful to most clients -// --------------------------------------------------------------------- - -// A Logger is the interface used by logging modules to emit entries -// to a log. A typical implementation will dump formatted data to a -// sequence of files. We also provide interfaces that will forward -// the data to another thread so that the invoker never blocks. -// Implementations should be thread-safe since the logging system -// will write to them from multiple threads. - -namespace base { - -class GLOG_EXPORT Logger { - public: - virtual ~Logger(); - - // Writes "message[0,message_len-1]" corresponding to an event that - // occurred at "timestamp". If "force_flush" is true, the log file - // is flushed immediately. - // - // The input message has already been formatted as deemed - // appropriate by the higher level logging facility. For example, - // textual log messages already contain timestamps, and the - // file:linenumber header. - virtual void Write(bool force_flush, - time_t timestamp, - const char* message, - size_t message_len) = 0; - - // Flush any buffered messages - virtual void Flush() = 0; - - // Get the current LOG file size. - // The returned value is approximate since some - // logged data may not have been flushed to disk yet. - virtual uint32 LogSize() = 0; -}; - -// Get the logger for the specified severity level. The logger -// remains the property of the logging module and should not be -// deleted by the caller. Thread-safe. -extern GLOG_EXPORT Logger* GetLogger(LogSeverity level); - -// Set the logger for the specified severity level. The logger -// becomes the property of the logging module and should not -// be deleted by the caller. Thread-safe. -extern GLOG_EXPORT void SetLogger(LogSeverity level, Logger* logger); - -} - -// glibc has traditionally implemented two incompatible versions of -// strerror_r(). There is a poorly defined convention for picking the -// version that we want, but it is not clear whether it even works with -// all versions of glibc. -// So, instead, we provide this wrapper that automatically detects the -// version that is in use, and then implements POSIX semantics. -// N.B. In addition to what POSIX says, we also guarantee that "buf" will -// be set to an empty string, if this function failed. This means, in most -// cases, you do not need to check the error code and you can directly -// use the value of "buf". It will never have an undefined value. -// DEPRECATED: Use StrError(int) instead. -GLOG_EXPORT int posix_strerror_r(int err, char *buf, size_t len); - -// A thread-safe replacement for strerror(). Returns a string describing the -// given POSIX error code. -GLOG_EXPORT std::string StrError(int err); - -// A class for which we define operator<<, which does nothing. -class GLOG_EXPORT NullStream : public LogMessage::LogStream { - public: - // Initialize the LogStream so the messages can be written somewhere - // (they'll never be actually displayed). This will be needed if a - // NullStream& is implicitly converted to LogStream&, in which case - // the overloaded NullStream::operator<< will not be invoked. - NullStream() : LogMessage::LogStream(message_buffer_, 1, 0) { } - NullStream(const char* /*file*/, int /*line*/, - const CheckOpString& /*result*/) : - LogMessage::LogStream(message_buffer_, 1, 0) { } - NullStream &stream() { return *this; } - private: - // A very short buffer for messages (which we discard anyway). This - // will be needed if NullStream& converted to LogStream& (e.g. as a - // result of a conditional expression). - char message_buffer_[2]; -}; - -// Do nothing. This operator is inline, allowing the message to be -// compiled away. The message will not be compiled away if we do -// something like (flag ? LOG(INFO) : LOG(ERROR)) << message; when -// SKIP_LOG=WARNING. In those cases, NullStream will be implicitly -// converted to LogStream and the message will be computed and then -// quietly discarded. -template -inline NullStream& operator<<(NullStream &str, const T &) { return str; } - -// Similar to NullStream, but aborts the program (without stack -// trace), like LogMessageFatal. -class GLOG_EXPORT NullStreamFatal : public NullStream { - public: - NullStreamFatal() { } - NullStreamFatal(const char* file, int line, const CheckOpString& result) : - NullStream(file, line, result) { } -#if defined(_MSC_VER) -#pragma warning(push) -#pragma warning(disable : 4722) -#endif // _MSC_VER - [[noreturn]] ~NullStreamFatal() throw() { _exit(EXIT_FAILURE); } -#if defined(_MSC_VER) -#pragma warning(pop) -#endif // _MSC_VER -}; - -// Install a signal handler that will dump signal information and a stack -// trace when the program crashes on certain signals. We'll install the -// signal handler for the following signals. -// -// SIGSEGV, SIGILL, SIGFPE, SIGABRT, SIGBUS, and SIGTERM. -// -// By default, the signal handler will write the failure dump to the -// standard error. You can customize the destination by installing your -// own writer function by InstallFailureWriter() below. -// -// Note on threading: -// -// The function should be called before threads are created, if you want -// to use the failure signal handler for all threads. The stack trace -// will be shown only for the thread that receives the signal. In other -// words, stack traces of other threads won't be shown. -GLOG_EXPORT void InstallFailureSignalHandler(); - -// Installs a function that is used for writing the failure dump. "data" -// is the pointer to the beginning of a message to be written, and "size" -// is the size of the message. You should not expect the data is -// terminated with '\0'. -GLOG_EXPORT void InstallFailureWriter( - void (*writer)(const char* data, size_t size)); - -@ac_google_end_namespace@ - -#pragma pop_macro("DECLARE_VARIABLE") -#pragma pop_macro("DECLARE_bool") -#pragma pop_macro("DECLARE_string") -#pragma pop_macro("DECLARE_int32") -#pragma pop_macro("DECLARE_uint32") - -#endif // GLOG_LOGGING_H diff --git a/funasr/runtime/onnxruntime/include/glog/platform.h b/funasr/runtime/onnxruntime/include/glog/platform.h deleted file mode 100644 index 7893c45d1..000000000 --- a/funasr/runtime/onnxruntime/include/glog/platform.h +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) 2008, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Author: Shinichiro Hamaji -// -// Detect supported platforms. - -#ifndef GLOG_PLATFORM_H -#define GLOG_PLATFORM_H - -#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) -#define GLOG_OS_WINDOWS -#elif defined(__CYGWIN__) || defined(__CYGWIN32__) -#define GLOG_OS_CYGWIN -#elif defined(linux) || defined(__linux) || defined(__linux__) -#ifndef GLOG_OS_LINUX -#define GLOG_OS_LINUX -#endif -#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) -#define GLOG_OS_MACOSX -#elif defined(__FreeBSD__) -#define GLOG_OS_FREEBSD -#elif defined(__NetBSD__) -#define GLOG_OS_NETBSD -#elif defined(__OpenBSD__) -#define GLOG_OS_OPENBSD -#elif defined(__EMSCRIPTEN__) -#define GLOG_OS_EMSCRIPTEN -#else -// TODO(hamaji): Add other platforms. -#error Platform not supported by glog. Please consider to contribute platform information by submitting a pull request on Github. -#endif - -#endif // GLOG_PLATFORM_H diff --git a/funasr/runtime/onnxruntime/include/glog/raw_logging.h b/funasr/runtime/onnxruntime/include/glog/raw_logging.h deleted file mode 100644 index eda5fb456..000000000 --- a/funasr/runtime/onnxruntime/include/glog/raw_logging.h +++ /dev/null @@ -1,179 +0,0 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Author: Maxim Lifantsev -// -// Thread-safe logging routines that do not allocate any memory or -// acquire any locks, and can therefore be used by low-level memory -// allocation and synchronization code. - -#ifndef GLOG_RAW_LOGGING_H -#define GLOG_RAW_LOGGING_H - -#include - -namespace google { - -#include -#include -#include - -#if defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wvariadic-macros" -#endif - -// This is similar to LOG(severity) << format... and VLOG(level) << format.., -// but -// * it is to be used ONLY by low-level modules that can't use normal LOG() -// * it is desiged to be a low-level logger that does not allocate any -// memory and does not need any locks, hence: -// * it logs straight and ONLY to STDERR w/o buffering -// * it uses an explicit format and arguments list -// * it will silently chop off really long message strings -// Usage example: -// RAW_LOG(ERROR, "Failed foo with %i: %s", status, error); -// RAW_VLOG(3, "status is %i", status); -// These will print an almost standard log lines like this to stderr only: -// E20200821 211317 file.cc:123] RAW: Failed foo with 22: bad_file -// I20200821 211317 file.cc:142] RAW: status is 20 -#define RAW_LOG(severity, ...) \ - do { \ - switch (google::GLOG_ ## severity) { \ - case 0: \ - RAW_LOG_INFO(__VA_ARGS__); \ - break; \ - case 1: \ - RAW_LOG_WARNING(__VA_ARGS__); \ - break; \ - case 2: \ - RAW_LOG_ERROR(__VA_ARGS__); \ - break; \ - case 3: \ - RAW_LOG_FATAL(__VA_ARGS__); \ - break; \ - default: \ - break; \ - } \ - } while (0) - -// The following STRIP_LOG testing is performed in the header file so that it's -// possible to completely compile out the logging code and the log messages. -#if !defined(STRIP_LOG) || STRIP_LOG == 0 -#define RAW_VLOG(verboselevel, ...) \ - do { \ - if (VLOG_IS_ON(verboselevel)) { \ - RAW_LOG_INFO(__VA_ARGS__); \ - } \ - } while (0) -#else -#define RAW_VLOG(verboselevel, ...) RawLogStub__(0, __VA_ARGS__) -#endif // STRIP_LOG == 0 - -#if !defined(STRIP_LOG) || STRIP_LOG == 0 -#define RAW_LOG_INFO(...) google::RawLog__(google::GLOG_INFO, \ - __FILE__, __LINE__, __VA_ARGS__) -#else -#define RAW_LOG_INFO(...) google::RawLogStub__(0, __VA_ARGS__) -#endif // STRIP_LOG == 0 - -#if !defined(STRIP_LOG) || STRIP_LOG <= 1 -#define RAW_LOG_WARNING(...) google::RawLog__(google::GLOG_WARNING, \ - __FILE__, __LINE__, __VA_ARGS__) -#else -#define RAW_LOG_WARNING(...) google::RawLogStub__(0, __VA_ARGS__) -#endif // STRIP_LOG <= 1 - -#if !defined(STRIP_LOG) || STRIP_LOG <= 2 -#define RAW_LOG_ERROR(...) google::RawLog__(google::GLOG_ERROR, \ - __FILE__, __LINE__, __VA_ARGS__) -#else -#define RAW_LOG_ERROR(...) google::RawLogStub__(0, __VA_ARGS__) -#endif // STRIP_LOG <= 2 - -#if !defined(STRIP_LOG) || STRIP_LOG <= 3 -#define RAW_LOG_FATAL(...) google::RawLog__(google::GLOG_FATAL, \ - __FILE__, __LINE__, __VA_ARGS__) -#else -#define RAW_LOG_FATAL(...) \ - do { \ - google::RawLogStub__(0, __VA_ARGS__); \ - exit(EXIT_FAILURE); \ - } while (0) -#endif // STRIP_LOG <= 3 - -// Similar to CHECK(condition) << message, -// but for low-level modules: we use only RAW_LOG that does not allocate memory. -// We do not want to provide args list here to encourage this usage: -// if (!cond) RAW_LOG(FATAL, "foo ...", hard_to_compute_args); -// so that the args are not computed when not needed. -#define RAW_CHECK(condition, message) \ - do { \ - if (!(condition)) { \ - RAW_LOG(FATAL, "Check %s failed: %s", #condition, message); \ - } \ - } while (0) - -// Debug versions of RAW_LOG and RAW_CHECK -#ifndef NDEBUG - -#define RAW_DLOG(severity, ...) RAW_LOG(severity, __VA_ARGS__) -#define RAW_DCHECK(condition, message) RAW_CHECK(condition, message) - -#else // NDEBUG - -#define RAW_DLOG(severity, ...) \ - while (false) \ - RAW_LOG(severity, __VA_ARGS__) -#define RAW_DCHECK(condition, message) \ - while (false) \ - RAW_CHECK(condition, message) - -#endif // NDEBUG - -#if defined(__GNUC__) -#pragma GCC diagnostic pop -#endif - -// Stub log function used to work around for unused variable warnings when -// building with STRIP_LOG > 0. -static inline void RawLogStub__(int /* ignored */, ...) { -} - -// Helper function to implement RAW_LOG and RAW_VLOG -// Logs format... at "severity" level, reporting it -// as called from file:line. -// This does not allocate memory or acquire locks. -GLOG_EXPORT void RawLog__(LogSeverity severity, const char* file, int line, - const char* format, ...) - __attribute__((__format__(__printf__, 4, 5))); - -} - -#endif // GLOG_RAW_LOGGING_H diff --git a/funasr/runtime/onnxruntime/include/glog/raw_logging.h.in b/funasr/runtime/onnxruntime/include/glog/raw_logging.h.in deleted file mode 100644 index 66fec91e5..000000000 --- a/funasr/runtime/onnxruntime/include/glog/raw_logging.h.in +++ /dev/null @@ -1,179 +0,0 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Author: Maxim Lifantsev -// -// Thread-safe logging routines that do not allocate any memory or -// acquire any locks, and can therefore be used by low-level memory -// allocation and synchronization code. - -#ifndef GLOG_RAW_LOGGING_H -#define GLOG_RAW_LOGGING_H - -#include - -@ac_google_start_namespace@ - -#include -#include -#include - -#if defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wvariadic-macros" -#endif - -// This is similar to LOG(severity) << format... and VLOG(level) << format.., -// but -// * it is to be used ONLY by low-level modules that can't use normal LOG() -// * it is desiged to be a low-level logger that does not allocate any -// memory and does not need any locks, hence: -// * it logs straight and ONLY to STDERR w/o buffering -// * it uses an explicit format and arguments list -// * it will silently chop off really long message strings -// Usage example: -// RAW_LOG(ERROR, "Failed foo with %i: %s", status, error); -// RAW_VLOG(3, "status is %i", status); -// These will print an almost standard log lines like this to stderr only: -// E20200821 211317 file.cc:123] RAW: Failed foo with 22: bad_file -// I20200821 211317 file.cc:142] RAW: status is 20 -#define RAW_LOG(severity, ...) \ - do { \ - switch (@ac_google_namespace@::GLOG_ ## severity) { \ - case 0: \ - RAW_LOG_INFO(__VA_ARGS__); \ - break; \ - case 1: \ - RAW_LOG_WARNING(__VA_ARGS__); \ - break; \ - case 2: \ - RAW_LOG_ERROR(__VA_ARGS__); \ - break; \ - case 3: \ - RAW_LOG_FATAL(__VA_ARGS__); \ - break; \ - default: \ - break; \ - } \ - } while (0) - -// The following STRIP_LOG testing is performed in the header file so that it's -// possible to completely compile out the logging code and the log messages. -#if !defined(STRIP_LOG) || STRIP_LOG == 0 -#define RAW_VLOG(verboselevel, ...) \ - do { \ - if (VLOG_IS_ON(verboselevel)) { \ - RAW_LOG_INFO(__VA_ARGS__); \ - } \ - } while (0) -#else -#define RAW_VLOG(verboselevel, ...) RawLogStub__(0, __VA_ARGS__) -#endif // STRIP_LOG == 0 - -#if !defined(STRIP_LOG) || STRIP_LOG == 0 -#define RAW_LOG_INFO(...) @ac_google_namespace@::RawLog__(@ac_google_namespace@::GLOG_INFO, \ - __FILE__, __LINE__, __VA_ARGS__) -#else -#define RAW_LOG_INFO(...) @ac_google_namespace@::RawLogStub__(0, __VA_ARGS__) -#endif // STRIP_LOG == 0 - -#if !defined(STRIP_LOG) || STRIP_LOG <= 1 -#define RAW_LOG_WARNING(...) @ac_google_namespace@::RawLog__(@ac_google_namespace@::GLOG_WARNING, \ - __FILE__, __LINE__, __VA_ARGS__) -#else -#define RAW_LOG_WARNING(...) @ac_google_namespace@::RawLogStub__(0, __VA_ARGS__) -#endif // STRIP_LOG <= 1 - -#if !defined(STRIP_LOG) || STRIP_LOG <= 2 -#define RAW_LOG_ERROR(...) @ac_google_namespace@::RawLog__(@ac_google_namespace@::GLOG_ERROR, \ - __FILE__, __LINE__, __VA_ARGS__) -#else -#define RAW_LOG_ERROR(...) @ac_google_namespace@::RawLogStub__(0, __VA_ARGS__) -#endif // STRIP_LOG <= 2 - -#if !defined(STRIP_LOG) || STRIP_LOG <= 3 -#define RAW_LOG_FATAL(...) @ac_google_namespace@::RawLog__(@ac_google_namespace@::GLOG_FATAL, \ - __FILE__, __LINE__, __VA_ARGS__) -#else -#define RAW_LOG_FATAL(...) \ - do { \ - @ac_google_namespace@::RawLogStub__(0, __VA_ARGS__); \ - exit(EXIT_FAILURE); \ - } while (0) -#endif // STRIP_LOG <= 3 - -// Similar to CHECK(condition) << message, -// but for low-level modules: we use only RAW_LOG that does not allocate memory. -// We do not want to provide args list here to encourage this usage: -// if (!cond) RAW_LOG(FATAL, "foo ...", hard_to_compute_args); -// so that the args are not computed when not needed. -#define RAW_CHECK(condition, message) \ - do { \ - if (!(condition)) { \ - RAW_LOG(FATAL, "Check %s failed: %s", #condition, message); \ - } \ - } while (0) - -// Debug versions of RAW_LOG and RAW_CHECK -#ifndef NDEBUG - -#define RAW_DLOG(severity, ...) RAW_LOG(severity, __VA_ARGS__) -#define RAW_DCHECK(condition, message) RAW_CHECK(condition, message) - -#else // NDEBUG - -#define RAW_DLOG(severity, ...) \ - while (false) \ - RAW_LOG(severity, __VA_ARGS__) -#define RAW_DCHECK(condition, message) \ - while (false) \ - RAW_CHECK(condition, message) - -#endif // NDEBUG - -#if defined(__GNUC__) -#pragma GCC diagnostic pop -#endif - -// Stub log function used to work around for unused variable warnings when -// building with STRIP_LOG > 0. -static inline void RawLogStub__(int /* ignored */, ...) { -} - -// Helper function to implement RAW_LOG and RAW_VLOG -// Logs format... at "severity" level, reporting it -// as called from file:line. -// This does not allocate memory or acquire locks. -GLOG_EXPORT void RawLog__(LogSeverity severity, const char* file, int line, - const char* format, ...) - @ac_cv___attribute___printf_4_5@; - -@ac_google_end_namespace@ - -#endif // GLOG_RAW_LOGGING_H diff --git a/funasr/runtime/onnxruntime/include/glog/stl_logging.h b/funasr/runtime/onnxruntime/include/glog/stl_logging.h deleted file mode 100644 index 96304e553..000000000 --- a/funasr/runtime/onnxruntime/include/glog/stl_logging.h +++ /dev/null @@ -1,177 +0,0 @@ -// Copyright (c) 2003, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Stream output operators for STL containers; to be used for logging *only*. -// Inclusion of this file lets you do: -// -// list x; -// LOG(INFO) << "data: " << x; -// vector v1, v2; -// CHECK_EQ(v1, v2); -// -// If you want to use this header file with hash maps or slist, you -// need to define macros before including this file: -// -// - GLOG_STL_LOGGING_FOR_UNORDERED - and -// - GLOG_STL_LOGGING_FOR_TR1_UNORDERED - -// - GLOG_STL_LOGGING_FOR_EXT_HASH - -// - GLOG_STL_LOGGING_FOR_EXT_SLIST - -// - -#ifndef UTIL_GTL_STL_LOGGING_INL_H_ -#define UTIL_GTL_STL_LOGGING_INL_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// Forward declare these two, and define them after all the container streams -// operators so that we can recurse from pair -> container -> container -> pair -// properly. -template -std::ostream& operator<<(std::ostream& out, const std::pair& p); - -namespace google { - -template -void PrintSequence(std::ostream& out, Iter begin, Iter end); - -} -#define OUTPUT_TWO_ARG_CONTAINER(Sequence) \ -template \ -inline std::ostream& operator<<(std::ostream& out, \ - const Sequence& seq) { \ - google::PrintSequence(out, seq.begin(), seq.end()); \ - return out; \ -} - - OUTPUT_TWO_ARG_CONTAINER(std::vector) OUTPUT_TWO_ARG_CONTAINER(std::deque) - OUTPUT_TWO_ARG_CONTAINER(std::list) - -#undef OUTPUT_TWO_ARG_CONTAINER - -#define OUTPUT_THREE_ARG_CONTAINER(Sequence) \ -template \ -inline std::ostream& operator<<(std::ostream& out, \ - const Sequence& seq) { \ - google::PrintSequence(out, seq.begin(), seq.end()); \ - return out; \ -} - - OUTPUT_THREE_ARG_CONTAINER(std::set) OUTPUT_THREE_ARG_CONTAINER( - std::multiset) - -#undef OUTPUT_THREE_ARG_CONTAINER - -#define OUTPUT_FOUR_ARG_CONTAINER(Sequence) \ -template \ -inline std::ostream& operator<<(std::ostream& out, \ - const Sequence& seq) { \ - google::PrintSequence(out, seq.begin(), seq.end()); \ - return out; \ -} - - OUTPUT_FOUR_ARG_CONTAINER(std::map) OUTPUT_FOUR_ARG_CONTAINER( - std::multimap) OUTPUT_FOUR_ARG_CONTAINER(std::unordered_set) - OUTPUT_FOUR_ARG_CONTAINER(std::unordered_multiset) - -#undef OUTPUT_FOUR_ARG_CONTAINER - -#define OUTPUT_FIVE_ARG_CONTAINER(Sequence) \ -template \ -inline std::ostream& operator<<(std::ostream& out, \ - const Sequence& seq) { \ - google::PrintSequence(out, seq.begin(), seq.end()); \ - return out; \ -} - -#if defined(GLOG_STL_LOGGING_FOR_UNORDERED) && __cplusplus >= 201103L - OUTPUT_FIVE_ARG_CONTAINER(std::unordered_map) - OUTPUT_FIVE_ARG_CONTAINER(std::unordered_multimap) -#endif - -#undef OUTPUT_FIVE_ARG_CONTAINER - - template - inline std::ostream& operator<<( - std::ostream& out, - const std::pair& p) { - out << '(' << p.first << ", " << p.second << ')'; - return out; -} - -namespace google { - -template -inline void PrintSequence(std::ostream& out, Iter begin, Iter end) { - // Output at most 100 elements -- appropriate if used for logging. - for (int i = 0; begin != end && i < 100; ++i, ++begin) { - if (i > 0) out << ' '; - out << *begin; - } - if (begin != end) { - out << " ..."; - } -} - -} - -// Note that this is technically undefined behavior! We are adding things into -// the std namespace for a reason though -- we are providing new operations on -// types which are themselves defined with this namespace. Without this, these -// operator overloads cannot be found via ADL. If these definitions are not -// found via ADL, they must be #included before they're used, which requires -// this header to be included before apparently independent other headers. -// -// For example, base/logging.h defines various template functions to implement -// CHECK_EQ(x, y) and stream x and y into the log in the event the check fails. -// It does so via the function template MakeCheckOpValueString: -// template -// void MakeCheckOpValueString(strstream* ss, const T& v) { -// (*ss) << v; -// } -// Because 'glog/logging.h' is included before 'glog/stl_logging.h', -// subsequent CHECK_EQ(v1, v2) for vector<...> typed variable v1 and v2 can only -// find these operator definitions via ADL. -// -// Even this solution has problems -- it may pull unintended operators into the -// namespace as well, allowing them to also be found via ADL, and creating code -// that only works with a particular order of includes. Long term, we need to -// move all of the *definitions* into namespace std, bet we need to ensure no -// one references them first. This lets us take that step. We cannot define them -// in both because that would create ambiguous overloads when both are found. -namespace std { using ::operator<<; } - -#endif // UTIL_GTL_STL_LOGGING_INL_H_ diff --git a/funasr/runtime/onnxruntime/include/glog/stl_logging.h.in b/funasr/runtime/onnxruntime/include/glog/stl_logging.h.in deleted file mode 100644 index 49eec0397..000000000 --- a/funasr/runtime/onnxruntime/include/glog/stl_logging.h.in +++ /dev/null @@ -1,177 +0,0 @@ -// Copyright (c) 2003, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Stream output operators for STL containers; to be used for logging *only*. -// Inclusion of this file lets you do: -// -// list x; -// LOG(INFO) << "data: " << x; -// vector v1, v2; -// CHECK_EQ(v1, v2); -// -// If you want to use this header file with hash maps or slist, you -// need to define macros before including this file: -// -// - GLOG_STL_LOGGING_FOR_UNORDERED - and -// - GLOG_STL_LOGGING_FOR_TR1_UNORDERED - -// - GLOG_STL_LOGGING_FOR_EXT_HASH - -// - GLOG_STL_LOGGING_FOR_EXT_SLIST - -// - -#ifndef UTIL_GTL_STL_LOGGING_INL_H_ -#define UTIL_GTL_STL_LOGGING_INL_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// Forward declare these two, and define them after all the container streams -// operators so that we can recurse from pair -> container -> container -> pair -// properly. -template -std::ostream& operator<<(std::ostream& out, const std::pair& p); - -@ac_google_start_namespace@ - -template -void PrintSequence(std::ostream& out, Iter begin, Iter end); - -@ac_google_end_namespace@ -#define OUTPUT_TWO_ARG_CONTAINER(Sequence) \ -template \ -inline std::ostream& operator<<(std::ostream& out, \ - const Sequence& seq) { \ - @ac_google_namespace@::PrintSequence(out, seq.begin(), seq.end()); \ - return out; \ -} - - OUTPUT_TWO_ARG_CONTAINER(std::vector) OUTPUT_TWO_ARG_CONTAINER(std::deque) - OUTPUT_TWO_ARG_CONTAINER(std::list) - -#undef OUTPUT_TWO_ARG_CONTAINER - -#define OUTPUT_THREE_ARG_CONTAINER(Sequence) \ -template \ -inline std::ostream& operator<<(std::ostream& out, \ - const Sequence& seq) { \ - @ac_google_namespace@::PrintSequence(out, seq.begin(), seq.end()); \ - return out; \ -} - - OUTPUT_THREE_ARG_CONTAINER(std::set) OUTPUT_THREE_ARG_CONTAINER( - std::multiset) - -#undef OUTPUT_THREE_ARG_CONTAINER - -#define OUTPUT_FOUR_ARG_CONTAINER(Sequence) \ -template \ -inline std::ostream& operator<<(std::ostream& out, \ - const Sequence& seq) { \ - @ac_google_namespace@::PrintSequence(out, seq.begin(), seq.end()); \ - return out; \ -} - - OUTPUT_FOUR_ARG_CONTAINER(std::map) OUTPUT_FOUR_ARG_CONTAINER( - std::multimap) OUTPUT_FOUR_ARG_CONTAINER(std::unordered_set) - OUTPUT_FOUR_ARG_CONTAINER(std::unordered_multiset) - -#undef OUTPUT_FOUR_ARG_CONTAINER - -#define OUTPUT_FIVE_ARG_CONTAINER(Sequence) \ -template \ -inline std::ostream& operator<<(std::ostream& out, \ - const Sequence& seq) { \ - @ac_google_namespace@::PrintSequence(out, seq.begin(), seq.end()); \ - return out; \ -} - -#if defined(GLOG_STL_LOGGING_FOR_UNORDERED) && __cplusplus >= 201103L - OUTPUT_FIVE_ARG_CONTAINER(std::unordered_map) - OUTPUT_FIVE_ARG_CONTAINER(std::unordered_multimap) -#endif - -#undef OUTPUT_FIVE_ARG_CONTAINER - - template - inline std::ostream& operator<<( - std::ostream& out, - const std::pair& p) { - out << '(' << p.first << ", " << p.second << ')'; - return out; -} - -@ac_google_start_namespace@ - -template -inline void PrintSequence(std::ostream& out, Iter begin, Iter end) { - // Output at most 100 elements -- appropriate if used for logging. - for (int i = 0; begin != end && i < 100; ++i, ++begin) { - if (i > 0) out << ' '; - out << *begin; - } - if (begin != end) { - out << " ..."; - } -} - -@ac_google_end_namespace@ - -// Note that this is technically undefined behavior! We are adding things into -// the std namespace for a reason though -- we are providing new operations on -// types which are themselves defined with this namespace. Without this, these -// operator overloads cannot be found via ADL. If these definitions are not -// found via ADL, they must be #included before they're used, which requires -// this header to be included before apparently independent other headers. -// -// For example, base/logging.h defines various template functions to implement -// CHECK_EQ(x, y) and stream x and y into the log in the event the check fails. -// It does so via the function template MakeCheckOpValueString: -// template -// void MakeCheckOpValueString(strstream* ss, const T& v) { -// (*ss) << v; -// } -// Because 'glog/logging.h' is included before 'glog/stl_logging.h', -// subsequent CHECK_EQ(v1, v2) for vector<...> typed variable v1 and v2 can only -// find these operator definitions via ADL. -// -// Even this solution has problems -- it may pull unintended operators into the -// namespace as well, allowing them to also be found via ADL, and creating code -// that only works with a particular order of includes. Long term, we need to -// move all of the *definitions* into namespace std, bet we need to ensure no -// one references them first. This lets us take that step. We cannot define them -// in both because that would create ambiguous overloads when both are found. -namespace std { using ::operator<<; } - -#endif // UTIL_GTL_STL_LOGGING_INL_H_ diff --git a/funasr/runtime/onnxruntime/include/glog/vlog_is_on.h b/funasr/runtime/onnxruntime/include/glog/vlog_is_on.h deleted file mode 100644 index 44c204857..000000000 --- a/funasr/runtime/onnxruntime/include/glog/vlog_is_on.h +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright (c) 2023, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Author: Ray Sidney and many others -// -// Defines the VLOG_IS_ON macro that controls the variable-verbosity -// conditional logging. -// -// It's used by VLOG and VLOG_IF in logging.h -// and by RAW_VLOG in raw_logging.h to trigger the logging. -// -// It can also be used directly e.g. like this: -// if (VLOG_IS_ON(2)) { -// // do some logging preparation and logging -// // that can't be accomplished e.g. via just VLOG(2) << ...; -// } -// -// The truth value that VLOG_IS_ON(level) returns is determined by -// the three verbosity level flags: -// --v= Gives the default maximal active V-logging level; -// 0 is the default. -// Normally positive values are used for V-logging levels. -// --vmodule= Gives the per-module maximal V-logging levels to override -// the value given by --v. -// E.g. "my_module=2,foo*=3" would change the logging level -// for all code in source files "my_module.*" and "foo*.*" -// ("-inl" suffixes are also disregarded for this matching). -// -// SetVLOGLevel helper function is provided to do limited dynamic control over -// V-logging by overriding the per-module settings given via --vmodule flag. -// -// CAVEAT: --vmodule functionality is not available in non gcc compilers. -// - -#ifndef BASE_VLOG_IS_ON_H_ -#define BASE_VLOG_IS_ON_H_ - -#include - -#include - -#if defined(__GNUC__) -// We emit an anonymous static int* variable at every VLOG_IS_ON(n) site. -// (Normally) the first time every VLOG_IS_ON(n) site is hit, -// we determine what variable will dynamically control logging at this site: -// it's either FLAGS_v or an appropriate internal variable -// matching the current source file that represents results of -// parsing of --vmodule flag and/or SetVLOGLevel calls. -#define VLOG_IS_ON(verboselevel) \ - __extension__ \ - ({ static google::SiteFlag vlocal__ = {NULL, NULL, 0, NULL}; \ - google::int32 verbose_level__ = (verboselevel); \ - (vlocal__.level == NULL ? google::InitVLOG3__(&vlocal__, &FLAGS_v, \ - __FILE__, verbose_level__) : *vlocal__.level >= verbose_level__); \ - }) -#else -// GNU extensions not available, so we do not support --vmodule. -// Dynamic value of FLAGS_v always controls the logging level. -#define VLOG_IS_ON(verboselevel) (FLAGS_v >= (verboselevel)) -#endif - -// Set VLOG(_IS_ON) level for module_pattern to log_level. -// This lets us dynamically control what is normally set by the --vmodule flag. -// Returns the level that previously applied to module_pattern. -// NOTE: To change the log level for VLOG(_IS_ON) sites -// that have already executed after/during InitGoogleLogging, -// one needs to supply the exact --vmodule pattern that applied to them. -// (If no --vmodule pattern applied to them -// the value of FLAGS_v will continue to control them.) -extern GLOG_EXPORT int SetVLOGLevel(const char* module_pattern, int log_level); - -// Various declarations needed for VLOG_IS_ON above: ========================= - -struct SiteFlag { - google::int32* level; - const char* base_name; - std::size_t base_len; - SiteFlag* next; -}; - -// Helper routine which determines the logging info for a particalur VLOG site. -// site_flag is the address of the site-local pointer to the controlling -// verbosity level -// site_default is the default to use for *site_flag -// fname is the current source file name -// verbose_level is the argument to VLOG_IS_ON -// We will return the return value for VLOG_IS_ON -// and if possible set *site_flag appropriately. -extern GLOG_EXPORT bool InitVLOG3__( - google::SiteFlag* site_flag, - google::int32* site_default, const char* fname, - google::int32 verbose_level); - -#endif // BASE_VLOG_IS_ON_H_ diff --git a/funasr/runtime/onnxruntime/include/glog/vlog_is_on.h.in b/funasr/runtime/onnxruntime/include/glog/vlog_is_on.h.in deleted file mode 100644 index ed37e0d35..000000000 --- a/funasr/runtime/onnxruntime/include/glog/vlog_is_on.h.in +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright (c) 2023, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Author: Ray Sidney and many others -// -// Defines the VLOG_IS_ON macro that controls the variable-verbosity -// conditional logging. -// -// It's used by VLOG and VLOG_IF in logging.h -// and by RAW_VLOG in raw_logging.h to trigger the logging. -// -// It can also be used directly e.g. like this: -// if (VLOG_IS_ON(2)) { -// // do some logging preparation and logging -// // that can't be accomplished e.g. via just VLOG(2) << ...; -// } -// -// The truth value that VLOG_IS_ON(level) returns is determined by -// the three verbosity level flags: -// --v= Gives the default maximal active V-logging level; -// 0 is the default. -// Normally positive values are used for V-logging levels. -// --vmodule= Gives the per-module maximal V-logging levels to override -// the value given by --v. -// E.g. "my_module=2,foo*=3" would change the logging level -// for all code in source files "my_module.*" and "foo*.*" -// ("-inl" suffixes are also disregarded for this matching). -// -// SetVLOGLevel helper function is provided to do limited dynamic control over -// V-logging by overriding the per-module settings given via --vmodule flag. -// -// CAVEAT: --vmodule functionality is not available in non gcc compilers. -// - -#ifndef BASE_VLOG_IS_ON_H_ -#define BASE_VLOG_IS_ON_H_ - -#include - -#include - -#if defined(__GNUC__) -// We emit an anonymous static int* variable at every VLOG_IS_ON(n) site. -// (Normally) the first time every VLOG_IS_ON(n) site is hit, -// we determine what variable will dynamically control logging at this site: -// it's either FLAGS_v or an appropriate internal variable -// matching the current source file that represents results of -// parsing of --vmodule flag and/or SetVLOGLevel calls. -#define VLOG_IS_ON(verboselevel) \ - __extension__ \ - ({ static @ac_google_namespace@::SiteFlag vlocal__ = {NULL, NULL, 0, NULL}; \ - @ac_google_namespace@::int32 verbose_level__ = (verboselevel); \ - (vlocal__.level == NULL ? @ac_google_namespace@::InitVLOG3__(&vlocal__, &FLAGS_v, \ - __FILE__, verbose_level__) : *vlocal__.level >= verbose_level__); \ - }) -#else -// GNU extensions not available, so we do not support --vmodule. -// Dynamic value of FLAGS_v always controls the logging level. -#define VLOG_IS_ON(verboselevel) (FLAGS_v >= (verboselevel)) -#endif - -// Set VLOG(_IS_ON) level for module_pattern to log_level. -// This lets us dynamically control what is normally set by the --vmodule flag. -// Returns the level that previously applied to module_pattern. -// NOTE: To change the log level for VLOG(_IS_ON) sites -// that have already executed after/during InitGoogleLogging, -// one needs to supply the exact --vmodule pattern that applied to them. -// (If no --vmodule pattern applied to them -// the value of FLAGS_v will continue to control them.) -extern GLOG_EXPORT int SetVLOGLevel(const char* module_pattern, int log_level); - -// Various declarations needed for VLOG_IS_ON above: ========================= - -struct SiteFlag { - @ac_google_namespace@::int32* level; - const char* base_name; - std::size_t base_len; - SiteFlag* next; -}; - -// Helper routine which determines the logging info for a particalur VLOG site. -// site_flag is the address of the site-local pointer to the controlling -// verbosity level -// site_default is the default to use for *site_flag -// fname is the current source file name -// verbose_level is the argument to VLOG_IS_ON -// We will return the return value for VLOG_IS_ON -// and if possible set *site_flag appropriately. -extern GLOG_EXPORT bool InitVLOG3__( - @ac_google_namespace@::SiteFlag* site_flag, - @ac_google_namespace@::int32* site_default, const char* fname, - @ac_google_namespace@::int32 verbose_level); - -#endif // BASE_VLOG_IS_ON_H_ From 1799f356dff6bcc790d702bb15dc2eed07722ec9 Mon Sep 17 00:00:00 2001 From: lyblsgo Date: Mon, 8 May 2023 20:33:46 +0800 Subject: [PATCH 090/120] add funasr namespace --- funasr/runtime/onnxruntime/src/alignedmem.cpp | 3 + funasr/runtime/onnxruntime/src/alignedmem.h | 2 + funasr/runtime/onnxruntime/src/audio.cpp | 5 +- funasr/runtime/onnxruntime/src/commonfunc.h | 3 + .../onnxruntime/src/ct-transformer.cpp | 2 + .../runtime/onnxruntime/src/ct-transformer.h | 2 + funasr/runtime/onnxruntime/src/e2e-vad.h | 7 +- funasr/runtime/onnxruntime/src/fsmn-vad.cpp | 3 + funasr/runtime/onnxruntime/src/fsmn-vad.h | 3 +- .../runtime/onnxruntime/src/funasrruntime.cpp | 72 +++++++++---------- funasr/runtime/onnxruntime/src/model.cpp | 5 +- .../onnxruntime/src/offline-stream.cpp | 3 + .../onnxruntime/src/online-feature.cpp | 3 + .../runtime/onnxruntime/src/online-feature.h | 6 +- funasr/runtime/onnxruntime/src/paraformer.cpp | 4 +- funasr/runtime/onnxruntime/src/paraformer.h | 8 +-- funasr/runtime/onnxruntime/src/precomp.h | 2 - .../runtime/onnxruntime/src/predefine-coe.h | 3 + funasr/runtime/onnxruntime/src/punc-model.cpp | 3 + funasr/runtime/onnxruntime/src/resample.cpp | 2 + funasr/runtime/onnxruntime/src/resample.h | 5 +- funasr/runtime/onnxruntime/src/tensor.h | 4 ++ funasr/runtime/onnxruntime/src/tokenizer.cpp | 3 + funasr/runtime/onnxruntime/src/tokenizer.h | 3 + funasr/runtime/onnxruntime/src/util.cpp | 3 + funasr/runtime/onnxruntime/src/util.h | 4 +- funasr/runtime/onnxruntime/src/vad-model.cpp | 3 + funasr/runtime/onnxruntime/src/vocab.cpp | 3 + funasr/runtime/onnxruntime/src/vocab.h | 2 + 29 files changed, 114 insertions(+), 57 deletions(-) diff --git a/funasr/runtime/onnxruntime/src/alignedmem.cpp b/funasr/runtime/onnxruntime/src/alignedmem.cpp index d3e4b8202..9c7d323df 100644 --- a/funasr/runtime/onnxruntime/src/alignedmem.cpp +++ b/funasr/runtime/onnxruntime/src/alignedmem.cpp @@ -1,4 +1,6 @@ #include "precomp.h" + +namespace funasr { void *AlignedMalloc(size_t alignment, size_t required_bytes) { void *p1; // original block @@ -16,3 +18,4 @@ void AlignedFree(void *p) { free(((void **)p)[-1]); } +} // namespace funasr \ No newline at end of file diff --git a/funasr/runtime/onnxruntime/src/alignedmem.h b/funasr/runtime/onnxruntime/src/alignedmem.h index e2b640a97..e4b9a7892 100644 --- a/funasr/runtime/onnxruntime/src/alignedmem.h +++ b/funasr/runtime/onnxruntime/src/alignedmem.h @@ -2,7 +2,9 @@ #ifndef ALIGNEDMEM_H #define ALIGNEDMEM_H +namespace funasr { extern void *AlignedMalloc(size_t alignment, size_t required_bytes); extern void AlignedFree(void *p); +} // namespace funasr #endif diff --git a/funasr/runtime/onnxruntime/src/audio.cpp b/funasr/runtime/onnxruntime/src/audio.cpp index 2ecd3e63c..6d63d6757 100644 --- a/funasr/runtime/onnxruntime/src/audio.cpp +++ b/funasr/runtime/onnxruntime/src/audio.cpp @@ -11,6 +11,7 @@ using namespace std; +namespace funasr { // see http://soundfile.sapp.org/doc/WaveFormat/ // Note: We assume little endian here struct WaveHeader { @@ -552,4 +553,6 @@ void Audio::Split(VadModel* vad_obj, vector>& vad_segments) std::vector pcm_data(speech_data, speech_data+sp_len); vad_segments = vad_obj->Infer(pcm_data); -} \ No newline at end of file +} + +} // namespace funasr \ No newline at end of file diff --git a/funasr/runtime/onnxruntime/src/commonfunc.h b/funasr/runtime/onnxruntime/src/commonfunc.h index d5298c31c..d0882c6a9 100644 --- a/funasr/runtime/onnxruntime/src/commonfunc.h +++ b/funasr/runtime/onnxruntime/src/commonfunc.h @@ -1,5 +1,7 @@ #pragma once #include + +namespace funasr { typedef struct { std::string msg; @@ -58,3 +60,4 @@ template inline static size_t Argmax(ForwardIterator first, ForwardIterator last) { return std::distance(first, std::max_element(first, last)); } +} // namespace funasr diff --git a/funasr/runtime/onnxruntime/src/ct-transformer.cpp b/funasr/runtime/onnxruntime/src/ct-transformer.cpp index 91e795c45..38a5a70a9 100644 --- a/funasr/runtime/onnxruntime/src/ct-transformer.cpp +++ b/funasr/runtime/onnxruntime/src/ct-transformer.cpp @@ -5,6 +5,7 @@ #include "precomp.h" +namespace funasr { CTTransformer::CTTransformer() :env_(ORT_LOGGING_LEVEL_ERROR, ""),session_options{} { @@ -186,3 +187,4 @@ vector CTTransformer::Infer(vector input_data) return punction; } +} // namespace funasr \ No newline at end of file diff --git a/funasr/runtime/onnxruntime/src/ct-transformer.h b/funasr/runtime/onnxruntime/src/ct-transformer.h index cff4f4747..49ed1b7bf 100644 --- a/funasr/runtime/onnxruntime/src/ct-transformer.h +++ b/funasr/runtime/onnxruntime/src/ct-transformer.h @@ -5,6 +5,7 @@ #pragma once +namespace funasr { class CTTransformer : public PuncModel { /** * Author: Speech Lab of DAMO Academy, Alibaba Group @@ -30,3 +31,4 @@ public: vector Infer(vector input_data); string AddPunc(const char* sz_input); }; +} // namespace funasr \ No newline at end of file diff --git a/funasr/runtime/onnxruntime/src/e2e-vad.h b/funasr/runtime/onnxruntime/src/e2e-vad.h index d881a322e..e9a8293ef 100644 --- a/funasr/runtime/onnxruntime/src/e2e-vad.h +++ b/funasr/runtime/onnxruntime/src/e2e-vad.h @@ -3,6 +3,8 @@ * MIT License (https://opensource.org/licenses/MIT) */ +#pragma once + #include #include #include @@ -13,7 +15,7 @@ #include #include - +namespace funasr { enum class VadStateMachine { kVadInStateStartPointNotDetected = 1, kVadInStateInSpeechSegment = 2, @@ -779,5 +781,4 @@ private: }; - - +} // namespace funasr diff --git a/funasr/runtime/onnxruntime/src/fsmn-vad.cpp b/funasr/runtime/onnxruntime/src/fsmn-vad.cpp index b1b0e639c..0a646f0ca 100644 --- a/funasr/runtime/onnxruntime/src/fsmn-vad.cpp +++ b/funasr/runtime/onnxruntime/src/fsmn-vad.cpp @@ -6,6 +6,7 @@ #include #include "precomp.h" +namespace funasr { void FsmnVad::InitVad(const std::string &vad_model, const std::string &vad_cmvn, const std::string &vad_config, int thread_num) { session_options_.SetIntraOpNumThreads(thread_num); session_options_.SetGraphOptimizationLevel(ORT_ENABLE_ALL); @@ -301,3 +302,5 @@ FsmnVad::~FsmnVad() { FsmnVad::FsmnVad():env_(ORT_LOGGING_LEVEL_ERROR, ""),session_options_{} { } + +} // namespace funasr diff --git a/funasr/runtime/onnxruntime/src/fsmn-vad.h b/funasr/runtime/onnxruntime/src/fsmn-vad.h index cf03ce91a..7a6707c4d 100644 --- a/funasr/runtime/onnxruntime/src/fsmn-vad.h +++ b/funasr/runtime/onnxruntime/src/fsmn-vad.h @@ -8,6 +8,7 @@ #include "precomp.h" +namespace funasr { class FsmnVad : public VadModel { /** * Author: Speech Lab of DAMO Academy, Alibaba Group @@ -63,5 +64,5 @@ private: int lfr_n = VAD_LFR_N; }; - +} // namespace funasr #endif //VAD_SERVER_FSMNVAD_H diff --git a/funasr/runtime/onnxruntime/src/funasrruntime.cpp b/funasr/runtime/onnxruntime/src/funasrruntime.cpp index ee6143edf..b8508fd3d 100644 --- a/funasr/runtime/onnxruntime/src/funasrruntime.cpp +++ b/funasr/runtime/onnxruntime/src/funasrruntime.cpp @@ -7,44 +7,44 @@ extern "C" { // APIs for Init _FUNASRAPI FUNASR_HANDLE FunASRInit(std::map& model_path, int thread_num) { - Model* mm = CreateModel(model_path, thread_num); + funasr::Model* mm = funasr::CreateModel(model_path, thread_num); return mm; } _FUNASRAPI FUNASR_HANDLE FsmnVadInit(std::map& model_path, int thread_num) { - VadModel* mm = CreateVadModel(model_path, thread_num); + funasr::VadModel* mm = funasr::CreateVadModel(model_path, thread_num); return mm; } _FUNASRAPI FUNASR_HANDLE FunPuncInit(std::map& model_path, int thread_num) { - PuncModel* mm = CreatePuncModel(model_path, thread_num); + funasr::PuncModel* mm = funasr::CreatePuncModel(model_path, thread_num); return mm; } _FUNASRAPI FUNASR_HANDLE FunOfflineInit(std::map& model_path, int thread_num) { - OfflineStream* mm = CreateOfflineStream(model_path, thread_num); + funasr::OfflineStream* mm = funasr::CreateOfflineStream(model_path, thread_num); return mm; } // APIs for ASR Infer _FUNASRAPI FUNASR_RESULT FunASRRecogBuffer(FUNASR_HANDLE handle, const char* sz_buf, int n_len, FUNASR_MODE mode, QM_CALLBACK fn_callback) { - Model* recog_obj = (Model*)handle; + funasr::Model* recog_obj = (funasr::Model*)handle; if (!recog_obj) return nullptr; int32_t sampling_rate = -1; - Audio audio(1); + funasr::Audio audio(1); if (!audio.LoadWav(sz_buf, n_len, &sampling_rate)) return nullptr; float* buff; int len; int flag=0; - FUNASR_RECOG_RESULT* p_result = new FUNASR_RECOG_RESULT; + funasr::FUNASR_RECOG_RESULT* p_result = new funasr::FUNASR_RECOG_RESULT; p_result->snippet_time = audio.GetTimeLen(); int n_step = 0; int n_total = audio.GetQueueSize(); @@ -61,18 +61,18 @@ extern "C" { _FUNASRAPI FUNASR_RESULT FunASRRecogPCMBuffer(FUNASR_HANDLE handle, const char* sz_buf, int n_len, int sampling_rate, FUNASR_MODE mode, QM_CALLBACK fn_callback) { - Model* recog_obj = (Model*)handle; + funasr::Model* recog_obj = (funasr::Model*)handle; if (!recog_obj) return nullptr; - Audio audio(1); + funasr::Audio audio(1); if (!audio.LoadPcmwav(sz_buf, n_len, &sampling_rate)) return nullptr; float* buff; int len; int flag = 0; - FUNASR_RECOG_RESULT* p_result = new FUNASR_RECOG_RESULT; + funasr::FUNASR_RECOG_RESULT* p_result = new funasr::FUNASR_RECOG_RESULT; p_result->snippet_time = audio.GetTimeLen(); int n_step = 0; int n_total = audio.GetQueueSize(); @@ -89,18 +89,18 @@ extern "C" { _FUNASRAPI FUNASR_RESULT FunASRRecogPCMFile(FUNASR_HANDLE handle, const char* sz_filename, int sampling_rate, FUNASR_MODE mode, QM_CALLBACK fn_callback) { - Model* recog_obj = (Model*)handle; + funasr::Model* recog_obj = (funasr::Model*)handle; if (!recog_obj) return nullptr; - Audio audio(1); + funasr::Audio audio(1); if (!audio.LoadPcmwav(sz_filename, &sampling_rate)) return nullptr; float* buff; int len; int flag = 0; - FUNASR_RECOG_RESULT* p_result = new FUNASR_RECOG_RESULT; + funasr::FUNASR_RECOG_RESULT* p_result = new funasr::FUNASR_RECOG_RESULT; p_result->snippet_time = audio.GetTimeLen(); int n_step = 0; int n_total = audio.GetQueueSize(); @@ -117,12 +117,12 @@ extern "C" { _FUNASRAPI FUNASR_RESULT FunASRRecogFile(FUNASR_HANDLE handle, const char* sz_wavfile, FUNASR_MODE mode, QM_CALLBACK fn_callback) { - Model* recog_obj = (Model*)handle; + funasr::Model* recog_obj = (funasr::Model*)handle; if (!recog_obj) return nullptr; int32_t sampling_rate = -1; - Audio audio(1); + funasr::Audio audio(1); if(!audio.LoadWav(sz_wavfile, &sampling_rate)) return nullptr; @@ -131,7 +131,7 @@ extern "C" { int flag = 0; int n_step = 0; int n_total = audio.GetQueueSize(); - FUNASR_RECOG_RESULT* p_result = new FUNASR_RECOG_RESULT; + funasr::FUNASR_RECOG_RESULT* p_result = new funasr::FUNASR_RECOG_RESULT; p_result->snippet_time = audio.GetTimeLen(); while (audio.Fetch(buff, len, flag) > 0) { string msg = recog_obj->Forward(buff, len, flag); @@ -147,16 +147,16 @@ extern "C" { // APIs for VAD Infer _FUNASRAPI FUNASR_RESULT FsmnVadWavFile(FUNASR_HANDLE handle, const char* sz_wavfile, FUNASR_MODE mode, QM_CALLBACK fn_callback) { - VadModel* vad_obj = (VadModel*)handle; + funasr::VadModel* vad_obj = (funasr::VadModel*)handle; if (!vad_obj) return nullptr; int32_t sampling_rate = -1; - Audio audio(1); + funasr::Audio audio(1); if(!audio.LoadWav(sz_wavfile, &sampling_rate)) return nullptr; - FUNASR_VAD_RESULT* p_result = new FUNASR_VAD_RESULT; + funasr::FUNASR_VAD_RESULT* p_result = new funasr::FUNASR_VAD_RESULT; p_result->snippet_time = audio.GetTimeLen(); vector> vad_segments; @@ -169,7 +169,7 @@ extern "C" { // APIs for PUNC Infer _FUNASRAPI const std::string FunPuncInfer(FUNASR_HANDLE handle, const char* sz_sentence, FUNASR_MODE mode, QM_CALLBACK fn_callback) { - PuncModel* punc_obj = (PuncModel*)handle; + funasr::PuncModel* punc_obj = (funasr::PuncModel*)handle; if (!punc_obj) return nullptr; @@ -180,12 +180,12 @@ extern "C" { // APIs for Offline-stream Infer _FUNASRAPI FUNASR_RESULT FunOfflineRecogFile(FUNASR_HANDLE handle, const char* sz_wavfile, FUNASR_MODE mode, QM_CALLBACK fn_callback) { - OfflineStream* offline_stream = (OfflineStream*)handle; + funasr::OfflineStream* offline_stream = (funasr::OfflineStream*)handle; if (!offline_stream) return nullptr; int32_t sampling_rate = -1; - Audio audio(1); + funasr::Audio audio(1); if(!audio.LoadWav(sz_wavfile, &sampling_rate)) return nullptr; if(offline_stream->UseVad()){ @@ -197,7 +197,7 @@ extern "C" { int flag = 0; int n_step = 0; int n_total = audio.GetQueueSize(); - FUNASR_RECOG_RESULT* p_result = new FUNASR_RECOG_RESULT; + funasr::FUNASR_RECOG_RESULT* p_result = new funasr::FUNASR_RECOG_RESULT; p_result->snippet_time = audio.GetTimeLen(); while (audio.Fetch(buff, len, flag) > 0) { string msg = (offline_stream->asr_handle)->Forward(buff, len, flag); @@ -216,11 +216,11 @@ extern "C" { _FUNASRAPI FUNASR_RESULT FunOfflineRecogPCMBuffer(FUNASR_HANDLE handle, const char* sz_buf, int n_len, int sampling_rate, FUNASR_MODE mode, QM_CALLBACK fn_callback) { - OfflineStream* offline_stream = (OfflineStream*)handle; + funasr::OfflineStream* offline_stream = (funasr::OfflineStream*)handle; if (!offline_stream) return nullptr; - Audio audio(1); + funasr::Audio audio(1); if (!audio.LoadPcmwav(sz_buf, n_len, &sampling_rate)) return nullptr; if(offline_stream->UseVad()){ @@ -230,7 +230,7 @@ extern "C" { float* buff; int len; int flag = 0; - FUNASR_RECOG_RESULT* p_result = new FUNASR_RECOG_RESULT; + funasr::FUNASR_RECOG_RESULT* p_result = new funasr::FUNASR_RECOG_RESULT; p_result->snippet_time = audio.GetTimeLen(); int n_step = 0; int n_total = audio.GetQueueSize(); @@ -263,7 +263,7 @@ extern "C" { if (!result) return 0.0f; - return ((FUNASR_RECOG_RESULT*)result)->snippet_time; + return ((funasr::FUNASR_RECOG_RESULT*)result)->snippet_time; } _FUNASRAPI const float FsmnVadGetRetSnippetTime(FUNASR_RESULT result) @@ -271,13 +271,13 @@ extern "C" { if (!result) return 0.0f; - return ((FUNASR_VAD_RESULT*)result)->snippet_time; + return ((funasr::FUNASR_VAD_RESULT*)result)->snippet_time; } // APIs for GetResult _FUNASRAPI const char* FunASRGetResult(FUNASR_RESULT result,int n_index) { - FUNASR_RECOG_RESULT * p_result = (FUNASR_RECOG_RESULT*)result; + funasr::FUNASR_RECOG_RESULT * p_result = (funasr::FUNASR_RECOG_RESULT*)result; if(!p_result) return nullptr; @@ -286,7 +286,7 @@ extern "C" { _FUNASRAPI vector>* FsmnVadGetResult(FUNASR_RESULT result,int n_index) { - FUNASR_VAD_RESULT * p_result = (FUNASR_VAD_RESULT*)result; + funasr::FUNASR_VAD_RESULT * p_result = (funasr::FUNASR_VAD_RESULT*)result; if(!p_result) return nullptr; @@ -298,13 +298,13 @@ extern "C" { { if (result) { - delete (FUNASR_RECOG_RESULT*)result; + delete (funasr::FUNASR_RECOG_RESULT*)result; } } _FUNASRAPI void FsmnVadFreeResult(FUNASR_RESULT result) { - FUNASR_VAD_RESULT * p_result = (FUNASR_VAD_RESULT*)result; + funasr::FUNASR_VAD_RESULT * p_result = (funasr::FUNASR_VAD_RESULT*)result; if (p_result) { if(p_result->segments){ @@ -317,7 +317,7 @@ extern "C" { // APIs for Uninit _FUNASRAPI void FunASRUninit(FUNASR_HANDLE handle) { - Model* recog_obj = (Model*)handle; + funasr::Model* recog_obj = (funasr::Model*)handle; if (!recog_obj) return; @@ -327,7 +327,7 @@ extern "C" { _FUNASRAPI void FsmnVadUninit(FUNASR_HANDLE handle) { - VadModel* recog_obj = (VadModel*)handle; + funasr::VadModel* recog_obj = (funasr::VadModel*)handle; if (!recog_obj) return; @@ -337,7 +337,7 @@ extern "C" { _FUNASRAPI void FunPuncUninit(FUNASR_HANDLE handle) { - PuncModel* punc_obj = (PuncModel*)handle; + funasr::PuncModel* punc_obj = (funasr::PuncModel*)handle; if (!punc_obj) return; @@ -347,7 +347,7 @@ extern "C" { _FUNASRAPI void FunOfflineUninit(FUNASR_HANDLE handle) { - OfflineStream* offline_stream = (OfflineStream*)handle; + funasr::OfflineStream* offline_stream = (funasr::OfflineStream*)handle; if (!offline_stream) return; diff --git a/funasr/runtime/onnxruntime/src/model.cpp b/funasr/runtime/onnxruntime/src/model.cpp index 65ea172f0..6badde667 100644 --- a/funasr/runtime/onnxruntime/src/model.cpp +++ b/funasr/runtime/onnxruntime/src/model.cpp @@ -1,5 +1,6 @@ #include "precomp.h" +namespace funasr { Model *CreateModel(std::map& model_path, int thread_num) { string am_model_path; @@ -14,7 +15,9 @@ Model *CreateModel(std::map& model_path, int thread_nu am_config_path = PathAppend(model_path.at(MODEL_DIR), AM_CONFIG_NAME); Model *mm; - mm = new paraformer::Paraformer(); + mm = new Paraformer(); mm->InitAsr(am_model_path, am_cmvn_path, am_config_path, thread_num); return mm; } + +} // namespace funasr \ No newline at end of file diff --git a/funasr/runtime/onnxruntime/src/offline-stream.cpp b/funasr/runtime/onnxruntime/src/offline-stream.cpp index 00c131844..817012981 100644 --- a/funasr/runtime/onnxruntime/src/offline-stream.cpp +++ b/funasr/runtime/onnxruntime/src/offline-stream.cpp @@ -1,5 +1,6 @@ #include "precomp.h" +namespace funasr { OfflineStream::OfflineStream(std::map& model_path, int thread_num) { // VAD model @@ -59,3 +60,5 @@ OfflineStream *CreateOfflineStream(std::map& model_pat mm = new OfflineStream(model_path, thread_num); return mm; } + +} // namespace funasr \ No newline at end of file diff --git a/funasr/runtime/onnxruntime/src/online-feature.cpp b/funasr/runtime/onnxruntime/src/online-feature.cpp index 3f57e0b9d..c5caf0ae6 100644 --- a/funasr/runtime/onnxruntime/src/online-feature.cpp +++ b/funasr/runtime/onnxruntime/src/online-feature.cpp @@ -6,6 +6,7 @@ #include "online-feature.h" #include +namespace funasr { OnlineFeature::OnlineFeature(int sample_rate, knf::FbankOptions fbank_opts, int lfr_m, int lfr_n, std::vector> cmvns) : sample_rate_(sample_rate), @@ -131,3 +132,5 @@ void OnlineFeature::OnlineFbank(vector> &vad_feats, } } + +} // namespace funasr \ No newline at end of file diff --git a/funasr/runtime/onnxruntime/src/online-feature.h b/funasr/runtime/onnxruntime/src/online-feature.h index decaaf4e7..7347056de 100644 --- a/funasr/runtime/onnxruntime/src/online-feature.h +++ b/funasr/runtime/onnxruntime/src/online-feature.h @@ -2,12 +2,12 @@ * Copyright FunASR (https://github.com/alibaba-damo-academy/FunASR). All Rights Reserved. * MIT License (https://opensource.org/licenses/MIT) */ - +#pragma once #include #include "precomp.h" using namespace std; - +namespace funasr { class OnlineFeature { public: @@ -53,3 +53,5 @@ private: bool input_finished_ = false; }; + +} // namespace funasr diff --git a/funasr/runtime/onnxruntime/src/paraformer.cpp b/funasr/runtime/onnxruntime/src/paraformer.cpp index 244a706db..74366a0fa 100644 --- a/funasr/runtime/onnxruntime/src/paraformer.cpp +++ b/funasr/runtime/onnxruntime/src/paraformer.cpp @@ -6,7 +6,8 @@ #include "precomp.h" using namespace std; -using namespace paraformer; + +namespace funasr { Paraformer::Paraformer() :env_(ORT_LOGGING_LEVEL_ERROR, "paraformer"),session_options{}{ @@ -238,3 +239,4 @@ string Paraformer::Rescoring() LOG(ERROR)<<"Not Imp!!!!!!"; return ""; } +} // namespace funasr diff --git a/funasr/runtime/onnxruntime/src/paraformer.h b/funasr/runtime/onnxruntime/src/paraformer.h index 3aa7057e5..533c16fdc 100644 --- a/funasr/runtime/onnxruntime/src/paraformer.h +++ b/funasr/runtime/onnxruntime/src/paraformer.h @@ -4,12 +4,9 @@ */ #pragma once -#ifndef PARAFORMER_MODELIMP_H -#define PARAFORMER_MODELIMP_H - #include "precomp.h" -namespace paraformer { +namespace funasr { class Paraformer : public Model { /** @@ -52,5 +49,4 @@ namespace paraformer { string Rescoring(); }; -} // namespace paraformer -#endif +} // namespace funasr diff --git a/funasr/runtime/onnxruntime/src/precomp.h b/funasr/runtime/onnxruntime/src/precomp.h index 9a8b17d69..e607dbff1 100644 --- a/funasr/runtime/onnxruntime/src/precomp.h +++ b/funasr/runtime/onnxruntime/src/precomp.h @@ -46,5 +46,3 @@ using namespace std; #include "paraformer.h" #include "offline-stream.h" #include "funasrruntime.h" - -using namespace paraformer; diff --git a/funasr/runtime/onnxruntime/src/predefine-coe.h b/funasr/runtime/onnxruntime/src/predefine-coe.h index 93012d857..17c263f7b 100644 --- a/funasr/runtime/onnxruntime/src/predefine-coe.h +++ b/funasr/runtime/onnxruntime/src/predefine-coe.h @@ -3,6 +3,7 @@ #include +namespace funasr { const int32_t melcoe_hex[] = { 0x3f01050c, 0x3e0afb11, 0x3f5d413c, 0x3f547fd0, 0x3e2e00c1, 0x3f132970, @@ -590,3 +591,5 @@ const int pos_enc_div_term_hex[] = { 0x39164323, 0x3910f3c6, 0x390bd472, 0x3906e374, 0x39021f2b, 0x38fb0c03, 0x38f22ce3, 0x38e99e04, 0x38e15c92, 0x38d965ce}; #endif + +} // namespace funasr \ No newline at end of file diff --git a/funasr/runtime/onnxruntime/src/punc-model.cpp b/funasr/runtime/onnxruntime/src/punc-model.cpp index 1e619ab9d..52ba0df90 100644 --- a/funasr/runtime/onnxruntime/src/punc-model.cpp +++ b/funasr/runtime/onnxruntime/src/punc-model.cpp @@ -1,5 +1,6 @@ #include "precomp.h" +namespace funasr { PuncModel *CreatePuncModel(std::map& model_path, int thread_num) { PuncModel *mm; @@ -17,3 +18,5 @@ PuncModel *CreatePuncModel(std::map& model_path, int t mm->InitPunc(punc_model_path, punc_config_path, thread_num); return mm; } + +} // namespace funasr diff --git a/funasr/runtime/onnxruntime/src/resample.cpp b/funasr/runtime/onnxruntime/src/resample.cpp index 0238752c3..9c74dc886 100644 --- a/funasr/runtime/onnxruntime/src/resample.cpp +++ b/funasr/runtime/onnxruntime/src/resample.cpp @@ -31,6 +31,7 @@ #include #include +namespace funasr { #ifndef M_2PI #define M_2PI 6.283185307179586476925286766559005 #endif @@ -303,3 +304,4 @@ void LinearResample::SetRemainder(const float *input, int32_t input_dim) { } } } +} // namespace funasr \ No newline at end of file diff --git a/funasr/runtime/onnxruntime/src/resample.h b/funasr/runtime/onnxruntime/src/resample.h index b9a283ab8..5cfc97196 100644 --- a/funasr/runtime/onnxruntime/src/resample.h +++ b/funasr/runtime/onnxruntime/src/resample.h @@ -21,11 +21,11 @@ */ // this file is copied and modified from // kaldi/src/feat/resample.h - +#pragma once #include #include - +namespace funasr { /* We require that the input and output sampling rate be specified as integers, as this is an easy way to specify that their ratio be rational. @@ -135,3 +135,4 @@ class LinearResample { std::vector input_remainder_; ///< A small trailing part of the ///< previously seen input signal. }; +} // namespace funasr diff --git a/funasr/runtime/onnxruntime/src/tensor.h b/funasr/runtime/onnxruntime/src/tensor.h index 3b7a63352..a2a7bc366 100644 --- a/funasr/runtime/onnxruntime/src/tensor.h +++ b/funasr/runtime/onnxruntime/src/tensor.h @@ -5,6 +5,8 @@ using namespace std; +namespace funasr { + template class Tensor { private: void alloc_buff(); @@ -152,4 +154,6 @@ template void Tensor::dump(const char *mode) fwrite(buff, 1, buff_size * sizeof(T), fp); fclose(fp); } + +} // namespace funasr #endif diff --git a/funasr/runtime/onnxruntime/src/tokenizer.cpp b/funasr/runtime/onnxruntime/src/tokenizer.cpp index 5aff058b3..a8f630108 100644 --- a/funasr/runtime/onnxruntime/src/tokenizer.cpp +++ b/funasr/runtime/onnxruntime/src/tokenizer.cpp @@ -5,6 +5,7 @@ #include "precomp.h" +namespace funasr { CTokenizer::CTokenizer(const char* sz_yamlfile):m_ready(false) { OpenYaml(sz_yamlfile); @@ -220,3 +221,5 @@ void CTokenizer::StrSplit(const string& str, const char split, vector& r } id_out= String2Ids(str_out); } + +} // namespace funasr \ No newline at end of file diff --git a/funasr/runtime/onnxruntime/src/tokenizer.h b/funasr/runtime/onnxruntime/src/tokenizer.h index 4ddd359e5..419791bf5 100644 --- a/funasr/runtime/onnxruntime/src/tokenizer.h +++ b/funasr/runtime/onnxruntime/src/tokenizer.h @@ -6,6 +6,7 @@ #pragma once #include +namespace funasr { class CTokenizer { private: @@ -31,3 +32,5 @@ public: void Tokenize(const char* str_info, vector& str_out, vector& id_out); }; + +} // namespace funasr diff --git a/funasr/runtime/onnxruntime/src/util.cpp b/funasr/runtime/onnxruntime/src/util.cpp index c5c27af7d..d29c5c0f9 100644 --- a/funasr/runtime/onnxruntime/src/util.cpp +++ b/funasr/runtime/onnxruntime/src/util.cpp @@ -1,6 +1,7 @@ #include "precomp.h" +namespace funasr { float *LoadParams(const char *filename) { @@ -178,3 +179,5 @@ void Glu(Tensor *din, Tensor *dout) } } } + +} // namespace funasr \ No newline at end of file diff --git a/funasr/runtime/onnxruntime/src/util.h b/funasr/runtime/onnxruntime/src/util.h index 6327f7b4b..95ef4586a 100644 --- a/funasr/runtime/onnxruntime/src/util.h +++ b/funasr/runtime/onnxruntime/src/util.h @@ -1,10 +1,9 @@ - - #ifndef UTIL_H #define UTIL_H using namespace std; +namespace funasr { extern float *LoadParams(const char *filename); extern void SaveDataFile(const char *filename, void *data, uint32_t len); @@ -27,4 +26,5 @@ extern void Glu(Tensor *din, Tensor *dout); string PathAppend(const string &p1, const string &p2); +} // namespace funasr #endif diff --git a/funasr/runtime/onnxruntime/src/vad-model.cpp b/funasr/runtime/onnxruntime/src/vad-model.cpp index 0a0ec84eb..764db00c9 100644 --- a/funasr/runtime/onnxruntime/src/vad-model.cpp +++ b/funasr/runtime/onnxruntime/src/vad-model.cpp @@ -1,5 +1,6 @@ #include "precomp.h" +namespace funasr { VadModel *CreateVadModel(std::map& model_path, int thread_num) { VadModel *mm; @@ -19,3 +20,5 @@ VadModel *CreateVadModel(std::map& model_path, int thr mm->InitVad(vad_model_path, vad_cmvn_path, vad_config_path, thread_num); return mm; } + +} // namespace funasr \ No newline at end of file diff --git a/funasr/runtime/onnxruntime/src/vocab.cpp b/funasr/runtime/onnxruntime/src/vocab.cpp index 53233b341..65af8b6f5 100644 --- a/funasr/runtime/onnxruntime/src/vocab.cpp +++ b/funasr/runtime/onnxruntime/src/vocab.cpp @@ -10,6 +10,7 @@ using namespace std; +namespace funasr { Vocab::Vocab(const char *filename) { ifstream in(filename); @@ -151,3 +152,5 @@ int Vocab::Size() { return vocab.size(); } + +} // namespace funasr \ No newline at end of file diff --git a/funasr/runtime/onnxruntime/src/vocab.h b/funasr/runtime/onnxruntime/src/vocab.h index a3fdf654a..6c4e52354 100644 --- a/funasr/runtime/onnxruntime/src/vocab.h +++ b/funasr/runtime/onnxruntime/src/vocab.h @@ -7,6 +7,7 @@ #include using namespace std; +namespace funasr { class Vocab { private: vector vocab; @@ -22,4 +23,5 @@ class Vocab { string Vector2StringV2(vector in); }; +} // namespace funasr #endif From c197b3aa85ef7de4fdcfc1f706ab95205fdb8617 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=B8=E9=9B=81?= Date: Mon, 8 May 2023 22:06:44 +0800 Subject: [PATCH 091/120] fix vad cpu infer.sh batch=1 --- egs_modelscope/vad/TEMPLATE/infer.sh | 2 +- funasr/bin/vad_inference.py | 11 ++++------- funasr/bin/vad_inference_online.py | 4 +--- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/egs_modelscope/vad/TEMPLATE/infer.sh b/egs_modelscope/vad/TEMPLATE/infer.sh index 7dc03871f..0651c98f8 100644 --- a/egs_modelscope/vad/TEMPLATE/infer.sh +++ b/egs_modelscope/vad/TEMPLATE/infer.sh @@ -9,7 +9,7 @@ stop_stage=2 model="damo/speech_fsmn_vad_zh-cn-16k-common" data_dir="./data/test" output_dir="./results" -batch_size=64 +batch_size=1 gpu_inference=true # whether to perform gpu decoding gpuid_list="0,1" # set gpus, e.g., gpuid_list="0,1" njob=64 # the number of jobs for CPU decoding, if gpu_inference=false, use CPU decoding, please set njob diff --git a/funasr/bin/vad_inference.py b/funasr/bin/vad_inference.py index f9dc39770..5fbd8449a 100644 --- a/funasr/bin/vad_inference.py +++ b/funasr/bin/vad_inference.py @@ -274,8 +274,7 @@ def inference_modelscope( assert check_argument_types() if batch_size > 1: raise NotImplementedError("batch decoding is not implemented") - if ngpu > 1: - raise NotImplementedError("only single GPU decoding is supported") + logging.basicConfig( level=log_level, @@ -286,7 +285,7 @@ def inference_modelscope( device = "cuda" else: device = "cpu" - + batch_size = 1 # 1. Set random-seed set_all_random_seed(seed) @@ -376,10 +375,7 @@ def inference_modelscope_online( **kwargs, ): assert check_argument_types() - if batch_size > 1: - raise NotImplementedError("batch decoding is not implemented") - if ngpu > 1: - raise NotImplementedError("only single GPU decoding is supported") + logging.basicConfig( level=log_level, @@ -390,6 +386,7 @@ def inference_modelscope_online( device = "cuda" else: device = "cpu" + batch_size = 1 # 1. Set random-seed set_all_random_seed(seed) diff --git a/funasr/bin/vad_inference_online.py b/funasr/bin/vad_inference_online.py index e1dbcf256..a3633093e 100644 --- a/funasr/bin/vad_inference_online.py +++ b/funasr/bin/vad_inference_online.py @@ -156,8 +156,6 @@ def inference_modelscope( if batch_size > 1: raise NotImplementedError("batch decoding is not implemented") - if ngpu > 1: - raise NotImplementedError("only single GPU decoding is supported") logging.basicConfig( level=log_level, @@ -168,7 +166,7 @@ def inference_modelscope( device = "cuda" else: device = "cpu" - + batch_size = 1 # 1. Set random-seed set_all_random_seed(seed) From 5edc1b77321380e4710e28c5dea2be3812d39418 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=B8=E9=9B=81?= Date: Mon, 8 May 2023 22:36:07 +0800 Subject: [PATCH 092/120] websocket docs --- .../python/grpc/proto/paraformer.proto | 14 -------- funasr/runtime/python/websocket/README.md | 33 ++++++++++--------- 2 files changed, 18 insertions(+), 29 deletions(-) diff --git a/funasr/runtime/python/grpc/proto/paraformer.proto b/funasr/runtime/python/grpc/proto/paraformer.proto index b221ee2fa..6c336a8f0 100644 --- a/funasr/runtime/python/grpc/proto/paraformer.proto +++ b/funasr/runtime/python/grpc/proto/paraformer.proto @@ -1,19 +1,5 @@ -// Copyright (c) 2021 Ximalaya Speech Team (Xiang Lyu) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. syntax = "proto3"; -option java_package = "ex.grpc"; option objc_class_prefix = "paraformer"; package paraformer; diff --git a/funasr/runtime/python/websocket/README.md b/funasr/runtime/python/websocket/README.md index 4764232b5..d77bd62d0 100644 --- a/funasr/runtime/python/websocket/README.md +++ b/funasr/runtime/python/websocket/README.md @@ -1,6 +1,6 @@ # Service with websocket-python -This is a demo using funasr pipeline with websocket python-api. +This is a demo using funasr pipeline with websocket python-api. It supports the offline, online, offline/online-2pass unifying speech recognition. ## For the Server @@ -22,6 +22,7 @@ pip install -r requirements_server.txt ### Start server #### ASR offline server +##### API-reference ```shell python ws_server_offline.py \ --port [port id] \ @@ -30,12 +31,13 @@ python ws_server_offline.py \ --ngpu [0 or 1] \ --ncpu [1 or 4] ``` -`e.g.` +##### Usage examples ```shell python ws_server_offline.py --port 10095 --asr_model "damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch" ``` #### ASR streaming server +##### API-reference ```shell python ws_server_online.py \ --port [port id] \ @@ -43,12 +45,13 @@ python ws_server_online.py \ --ngpu [0 or 1] \ --ncpu [1 or 4] ``` -`e.g.` +##### Usage examples ```shell python ws_server_online.py --port 10095 --asr_model_online "damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online" ``` #### ASR offline/online 2pass server +##### API-reference ```shell python ws_server_2pass.py \ --port [port id] \ @@ -58,7 +61,7 @@ python ws_server_2pass.py \ --ngpu [0 or 1] \ --ncpu [1 or 4] ``` -`e.g.` +##### Usage examples ```shell python ws_server_2pass.py --port 10095 --asr_model "damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch" --asr_model_online "damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online" ``` @@ -73,7 +76,7 @@ pip install -r requirements_client.txt ``` ### Start client - +#### API-reference ```shell python ws_client.py \ --host [ip_address] \ @@ -85,38 +88,38 @@ python ws_client.py \ --output_dir [if set, write the results to output_dir] \ --send_without_sleep [only set for offline] ``` - -#### ASR offline client -##### Recording from mircrophone +#### Usage examples +##### ASR offline client +###### Recording from mircrophone ```shell # --chunk_interval, "10": 600/10=60ms, "5"=600/5=120ms, "20": 600/12=30ms python ws_client.py --host "0.0.0.0" --port 10095 --chunk_interval 10 --words_max_print 100 ``` -##### Loadding from wav.scp(kaldi style) +###### Loadding from wav.scp(kaldi style) ```shell # --chunk_interval, "10": 600/10=60ms, "5"=600/5=120ms, "20": 600/12=30ms python ws_client.py --host "0.0.0.0" --port 10095 --chunk_interval 10 --words_max_print 100 --audio_in "./data/wav.scp" --send_without_sleep --output_dir "./results" ``` -#### ASR streaming client -##### Recording from mircrophone +##### ASR streaming client +###### Recording from mircrophone ```shell # --chunk_size, "5,10,5"=600ms, "8,8,4"=480ms python ws_client.py --host "0.0.0.0" --port 10095 --chunk_size "5,10,5" --words_max_print 100 ``` -##### Loadding from wav.scp(kaldi style) +###### Loadding from wav.scp(kaldi style) ```shell # --chunk_size, "5,10,5"=600ms, "8,8,4"=480ms python ws_client.py --host "0.0.0.0" --port 10095 --chunk_size "5,10,5" --audio_in "./data/wav.scp" --words_max_print 100 --output_dir "./results" ``` -#### ASR offline/online 2pass client -##### Recording from mircrophone +##### ASR offline/online 2pass client +###### Recording from mircrophone ```shell # --chunk_size, "5,10,5"=600ms, "8,8,4"=480ms python ws_client.py --host "0.0.0.0" --port 10095 --chunk_size "8,8,4" --words_max_print 10000 ``` -##### Loadding from wav.scp(kaldi style) +###### Loadding from wav.scp(kaldi style) ```shell # --chunk_size, "5,10,5"=600ms, "8,8,4"=480ms python ws_client.py --host "0.0.0.0" --port 10095 --chunk_size "8,8,4" --audio_in "./data/wav.scp" --words_max_print 10000 --output_dir "./results" From 80cc830eba3600ba23c57f4f7691abd23dd6b298 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=B8=E9=9B=81?= Date: Mon, 8 May 2023 22:40:34 +0800 Subject: [PATCH 093/120] websocket docs --- funasr/runtime/python/websocket/README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/funasr/runtime/python/websocket/README.md b/funasr/runtime/python/websocket/README.md index d77bd62d0..7ca573013 100644 --- a/funasr/runtime/python/websocket/README.md +++ b/funasr/runtime/python/websocket/README.md @@ -90,36 +90,36 @@ python ws_client.py \ ``` #### Usage examples ##### ASR offline client -###### Recording from mircrophone +Recording from mircrophone ```shell # --chunk_interval, "10": 600/10=60ms, "5"=600/5=120ms, "20": 600/12=30ms python ws_client.py --host "0.0.0.0" --port 10095 --chunk_interval 10 --words_max_print 100 ``` -###### Loadding from wav.scp(kaldi style) +Loadding from wav.scp(kaldi style) ```shell # --chunk_interval, "10": 600/10=60ms, "5"=600/5=120ms, "20": 600/12=30ms python ws_client.py --host "0.0.0.0" --port 10095 --chunk_interval 10 --words_max_print 100 --audio_in "./data/wav.scp" --send_without_sleep --output_dir "./results" ``` ##### ASR streaming client -###### Recording from mircrophone +Recording from mircrophone ```shell # --chunk_size, "5,10,5"=600ms, "8,8,4"=480ms python ws_client.py --host "0.0.0.0" --port 10095 --chunk_size "5,10,5" --words_max_print 100 ``` -###### Loadding from wav.scp(kaldi style) +Loadding from wav.scp(kaldi style) ```shell # --chunk_size, "5,10,5"=600ms, "8,8,4"=480ms python ws_client.py --host "0.0.0.0" --port 10095 --chunk_size "5,10,5" --audio_in "./data/wav.scp" --words_max_print 100 --output_dir "./results" ``` ##### ASR offline/online 2pass client -###### Recording from mircrophone +Recording from mircrophone ```shell # --chunk_size, "5,10,5"=600ms, "8,8,4"=480ms python ws_client.py --host "0.0.0.0" --port 10095 --chunk_size "8,8,4" --words_max_print 10000 ``` -###### Loadding from wav.scp(kaldi style) +Loadding from wav.scp(kaldi style) ```shell # --chunk_size, "5,10,5"=600ms, "8,8,4"=480ms python ws_client.py --host "0.0.0.0" --port 10095 --chunk_size "8,8,4" --audio_in "./data/wav.scp" --words_max_print 10000 --output_dir "./results" From 77045e7bb78d4b8a82f96130f9d84e356a32d5c5 Mon Sep 17 00:00:00 2001 From: aky15 Date: Tue, 9 May 2023 11:16:07 +0800 Subject: [PATCH 094/120] rnnt bug fix --- funasr/bin/asr_inference_rnnt.py | 19 +++++------- funasr/models/decoder/rnnt_decoder.py | 12 ++++++++ funasr/models/e2e_asr_transducer.py | 8 ++--- funasr/models/encoder/conformer_encoder.py | 4 +-- funasr/modules/nets_utils.py | 35 ++++++++++++++++++---- funasr/modules/repeat.py | 4 +-- funasr/tasks/asr.py | 2 +- 7 files changed, 59 insertions(+), 25 deletions(-) diff --git a/funasr/bin/asr_inference_rnnt.py b/funasr/bin/asr_inference_rnnt.py index d96464360..bd36907f7 100644 --- a/funasr/bin/asr_inference_rnnt.py +++ b/funasr/bin/asr_inference_rnnt.py @@ -188,18 +188,15 @@ class Speech2Text: self.frontend = frontend self.window_size = self.chunk_size + self.right_context - self._ctx = self.asr_model.encoder.get_encoder_input_size( - self.window_size - ) + if self.streaming: + self._ctx = self.asr_model.encoder.get_encoder_input_size( + self.window_size + ) - #self.last_chunk_length = ( - # self.asr_model.encoder.embed.min_frame_length + self.right_context + 1 - #) * self.hop_length - - self.last_chunk_length = ( - self.asr_model.encoder.embed.min_frame_length + self.right_context + 1 - ) - self.reset_inference_cache() + self.last_chunk_length = ( + self.asr_model.encoder.embed.min_frame_length + self.right_context + 1 + ) + self.reset_inference_cache() def reset_inference_cache(self) -> None: """Reset Speech2Text parameters.""" diff --git a/funasr/models/decoder/rnnt_decoder.py b/funasr/models/decoder/rnnt_decoder.py index 5401ab20c..a0fe9eadc 100644 --- a/funasr/models/decoder/rnnt_decoder.py +++ b/funasr/models/decoder/rnnt_decoder.py @@ -33,6 +33,7 @@ class RNNTDecoder(torch.nn.Module): dropout_rate: float = 0.0, embed_dropout_rate: float = 0.0, embed_pad: int = 0, + use_embed_mask: bool = False, ) -> None: """Construct a RNNDecoder object.""" super().__init__() @@ -66,6 +67,15 @@ class RNNTDecoder(torch.nn.Module): self.device = next(self.parameters()).device self.score_cache = {} + + self.use_embed_mask = use_embed_mask + if self.use_embed_mask: + self._embed_mask = SpecAug( + time_mask_width_range=3, + num_time_mask=4, + apply_freq_mask=False, + apply_time_warp=False + ) def forward( self, @@ -88,6 +98,8 @@ class RNNTDecoder(torch.nn.Module): states = self.init_state(labels.size(0)) dec_embed = self.dropout_embed(self.embed(labels)) + if self.use_embed_mask and self.training: + dec_embed = self._embed_mask(dec_embed, label_lens)[0] dec_out, states = self.rnn_forward(dec_embed, states) return dec_out diff --git a/funasr/models/e2e_asr_transducer.py b/funasr/models/e2e_asr_transducer.py index f8ba0f0c6..a5aaa6c52 100644 --- a/funasr/models/e2e_asr_transducer.py +++ b/funasr/models/e2e_asr_transducer.py @@ -12,7 +12,7 @@ from funasr.models.frontend.abs_frontend import AbsFrontend from funasr.models.specaug.abs_specaug import AbsSpecAug from funasr.models.decoder.rnnt_decoder import RNNTDecoder from funasr.models.decoder.abs_decoder import AbsDecoder as AbsAttDecoder -from funasr.models.encoder.conformer_encoder import ConformerChunkEncoder as Encoder +from funasr.models.encoder.abs_encoder import AbsEncoder from funasr.models.joint_net.joint_network import JointNetwork from funasr.modules.nets_utils import get_transducer_task_io from funasr.layers.abs_normalize import AbsNormalize @@ -62,7 +62,7 @@ class TransducerModel(AbsESPnetModel): frontend: Optional[AbsFrontend], specaug: Optional[AbsSpecAug], normalize: Optional[AbsNormalize], - encoder: Encoder, + encoder: AbsEncoder, decoder: RNNTDecoder, joint_network: JointNetwork, att_decoder: Optional[AbsAttDecoder] = None, @@ -286,7 +286,7 @@ class TransducerModel(AbsESPnetModel): feats, feats_lengths = self.normalize(feats, feats_lengths) # 4. Forward encoder - encoder_out, encoder_out_lens = self.encoder(feats, feats_lengths) + encoder_out, encoder_out_lens, _ = self.encoder(feats, feats_lengths) assert encoder_out.size(0) == speech.size(0), ( encoder_out.size(), @@ -515,7 +515,7 @@ class UnifiedTransducerModel(AbsESPnetModel): frontend: Optional[AbsFrontend], specaug: Optional[AbsSpecAug], normalize: Optional[AbsNormalize], - encoder: Encoder, + encoder: AbsEncoder, decoder: RNNTDecoder, joint_network: JointNetwork, att_decoder: Optional[AbsAttDecoder] = None, diff --git a/funasr/models/encoder/conformer_encoder.py b/funasr/models/encoder/conformer_encoder.py index 9777ceed6..434f2a480 100644 --- a/funasr/models/encoder/conformer_encoder.py +++ b/funasr/models/encoder/conformer_encoder.py @@ -307,7 +307,7 @@ class ChunkEncoderLayer(torch.nn.Module): feed_forward: torch.nn.Module, feed_forward_macaron: torch.nn.Module, conv_mod: torch.nn.Module, - norm_class: torch.nn.Module = torch.nn.LayerNorm, + norm_class: torch.nn.Module = LayerNorm, norm_args: Dict = {}, dropout_rate: float = 0.0, ) -> None: @@ -1145,7 +1145,7 @@ class ConformerChunkEncoder(AbsEncoder): x = x[:,::self.time_reduction_factor,:] olens = torch.floor_divide(olens-1, self.time_reduction_factor) + 1 - return x, olens + return x, olens, None def simu_chunk_forward( self, diff --git a/funasr/modules/nets_utils.py b/funasr/modules/nets_utils.py index 10df124f8..397a5c428 100644 --- a/funasr/modules/nets_utils.py +++ b/funasr/modules/nets_utils.py @@ -485,14 +485,39 @@ def rename_state_dict( new_k = k.replace(old_prefix, new_prefix) state_dict[new_k] = v - class Swish(torch.nn.Module): - """Construct an Swish object.""" + """Swish activation definition. - def forward(self, x): - """Return Swich activation function.""" - return x * torch.sigmoid(x) + Swish(x) = (beta * x) * sigmoid(x) + where beta = 1 defines standard Swish activation. + References: + https://arxiv.org/abs/2108.12943 / https://arxiv.org/abs/1710.05941v1. + E-swish variant: https://arxiv.org/abs/1801.07145. + + Args: + beta: Beta parameter for E-Swish. + (beta >= 1. If beta < 1, use standard Swish). + use_builtin: Whether to use PyTorch function if available. + + """ + + def __init__(self, beta: float = 1.0, use_builtin: bool = False) -> None: + super().__init__() + + self.beta = beta + + if beta > 1: + self.swish = lambda x: (self.beta * x) * torch.sigmoid(x) + else: + if use_builtin: + self.swish = torch.nn.SiLU() + else: + self.swish = lambda x: x * torch.sigmoid(x) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + """Forward computation.""" + return self.swish(x) def get_activation(act): """Return activation function.""" diff --git a/funasr/modules/repeat.py b/funasr/modules/repeat.py index 2b2dac8f3..ff1e182af 100644 --- a/funasr/modules/repeat.py +++ b/funasr/modules/repeat.py @@ -7,7 +7,7 @@ """Repeat the same layer definition.""" from typing import Dict, List, Optional - +from funasr.modules.layer_norm import LayerNorm import torch @@ -48,7 +48,7 @@ class MultiBlocks(torch.nn.Module): self, block_list: List[torch.nn.Module], output_size: int, - norm_class: torch.nn.Module = torch.nn.LayerNorm, + norm_class: torch.nn.Module = LayerNorm, ) -> None: """Construct a MultiBlocks object.""" super().__init__() diff --git a/funasr/tasks/asr.py b/funasr/tasks/asr.py index 87db05c67..a64b9e7e4 100644 --- a/funasr/tasks/asr.py +++ b/funasr/tasks/asr.py @@ -1682,7 +1682,7 @@ class ASRTransducerTask(AbsTask): # 7. Build model - if encoder.unified_model_training: + if hasattr(encoder, 'unified_model_training') and encoder.unified_model_training: model = UnifiedTransducerModel( vocab_size=vocab_size, token_list=token_list, From f2500eca9390e0369884c7ae87a0107c4841d01d Mon Sep 17 00:00:00 2001 From: lyblsgo Date: Tue, 9 May 2023 13:39:51 +0800 Subject: [PATCH 095/120] rename punc functions --- funasr/runtime/onnxruntime/include/funasrruntime.h | 6 +++--- funasr/runtime/onnxruntime/src/funasr-onnx-offline-punc.cpp | 6 +++--- funasr/runtime/onnxruntime/src/funasrruntime.cpp | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/funasr/runtime/onnxruntime/include/funasrruntime.h b/funasr/runtime/onnxruntime/include/funasrruntime.h index 7d290aa3e..75be80e5c 100644 --- a/funasr/runtime/onnxruntime/include/funasrruntime.h +++ b/funasr/runtime/onnxruntime/include/funasrruntime.h @@ -72,9 +72,9 @@ _FUNASRAPI void FsmnVadUninit(FUNASR_HANDLE handle); _FUNASRAPI const float FsmnVadGetRetSnippetTime(FUNASR_RESULT result); // PUNC -_FUNASRAPI FUNASR_HANDLE FunPuncInit(std::map& model_path, int thread_num); -_FUNASRAPI const std::string FunPuncInfer(FUNASR_HANDLE handle, const char* sz_sentence, FUNASR_MODE mode, QM_CALLBACK fn_callback); -_FUNASRAPI void FunPuncUninit(FUNASR_HANDLE handle); +_FUNASRAPI FUNASR_HANDLE CTTransformerInit(std::map& model_path, int thread_num); +_FUNASRAPI const std::string CTTransformerInfer(FUNASR_HANDLE handle, const char* sz_sentence, FUNASR_MODE mode, QM_CALLBACK fn_callback); +_FUNASRAPI void CTTransformerUninit(FUNASR_HANDLE handle); //OfflineStream _FUNASRAPI FUNASR_HANDLE FunOfflineInit(std::map& model_path, int thread_num); diff --git a/funasr/runtime/onnxruntime/src/funasr-onnx-offline-punc.cpp b/funasr/runtime/onnxruntime/src/funasr-onnx-offline-punc.cpp index 4354ad474..a8ee9a970 100644 --- a/funasr/runtime/onnxruntime/src/funasr-onnx-offline-punc.cpp +++ b/funasr/runtime/onnxruntime/src/funasr-onnx-offline-punc.cpp @@ -51,7 +51,7 @@ int main(int argc, char *argv[]) struct timeval start, end; gettimeofday(&start, NULL); int thread_num = 1; - FUNASR_HANDLE punc_hanlde=FunPuncInit(model_path, thread_num); + FUNASR_HANDLE punc_hanlde=CTTransformerInit(model_path, thread_num); if (!punc_hanlde) { @@ -84,7 +84,7 @@ int main(int argc, char *argv[]) long taking_micros = 0; for(auto& txt_str : txt_list){ gettimeofday(&start, NULL); - string result=FunPuncInfer(punc_hanlde, txt_str.c_str(), RASR_NONE, NULL); + string result=CTTransformerInfer(punc_hanlde, txt_str.c_str(), RASR_NONE, NULL); gettimeofday(&end, NULL); seconds = (end.tv_sec - start.tv_sec); taking_micros += ((seconds * 1000000) + end.tv_usec) - (start.tv_usec); @@ -92,7 +92,7 @@ int main(int argc, char *argv[]) } LOG(INFO) << "Model inference takes: " << (double)taking_micros / 1000000 <<" s"; - FunPuncUninit(punc_hanlde); + CTTransformerUninit(punc_hanlde); return 0; } diff --git a/funasr/runtime/onnxruntime/src/funasrruntime.cpp b/funasr/runtime/onnxruntime/src/funasrruntime.cpp index b8508fd3d..893ba70d7 100644 --- a/funasr/runtime/onnxruntime/src/funasrruntime.cpp +++ b/funasr/runtime/onnxruntime/src/funasrruntime.cpp @@ -17,7 +17,7 @@ extern "C" { return mm; } - _FUNASRAPI FUNASR_HANDLE FunPuncInit(std::map& model_path, int thread_num) + _FUNASRAPI FUNASR_HANDLE CTTransformerInit(std::map& model_path, int thread_num) { funasr::PuncModel* mm = funasr::CreatePuncModel(model_path, thread_num); return mm; @@ -167,7 +167,7 @@ extern "C" { } // APIs for PUNC Infer - _FUNASRAPI const std::string FunPuncInfer(FUNASR_HANDLE handle, const char* sz_sentence, FUNASR_MODE mode, QM_CALLBACK fn_callback) + _FUNASRAPI const std::string CTTransformerInfer(FUNASR_HANDLE handle, const char* sz_sentence, FUNASR_MODE mode, QM_CALLBACK fn_callback) { funasr::PuncModel* punc_obj = (funasr::PuncModel*)handle; if (!punc_obj) @@ -335,7 +335,7 @@ extern "C" { delete recog_obj; } - _FUNASRAPI void FunPuncUninit(FUNASR_HANDLE handle) + _FUNASRAPI void CTTransformerUninit(FUNASR_HANDLE handle) { funasr::PuncModel* punc_obj = (funasr::PuncModel*)handle; From c533410c922e742020d7acf9f3776eb3a890d402 Mon Sep 17 00:00:00 2001 From: zhaomingwork Date: Tue, 9 May 2023 10:21:21 +0000 Subject: [PATCH 096/120] modified for new asr api --- funasr/runtime/websocket/readme.md | 59 +++++------- funasr/runtime/websocket/websocketclient.cpp | 2 +- funasr/runtime/websocket/websocketmain.cpp | 98 +++++++++----------- funasr/runtime/websocket/websocketsrv.cpp | 4 +- funasr/runtime/websocket/websocketsrv.h | 2 +- 5 files changed, 74 insertions(+), 91 deletions(-) diff --git a/funasr/runtime/websocket/readme.md b/funasr/runtime/websocket/readme.md index 6ff3e505c..078184e0a 100644 --- a/funasr/runtime/websocket/readme.md +++ b/funasr/runtime/websocket/readme.md @@ -43,48 +43,39 @@ make ```shell cd bin -websocketmain [--model_thread_num ] [--decoder_thread_num - ] [--io_thread_num ] [--port ] - [--listen_ip ] [--wav-scp ] - [--wav-path ] [--punc-config ] - [--punc-model ] --am-config - --am-cmvn --am-model - [--vad-config ] [--vad-cmvn ] - [--vad-model ] [--] [--version] [-h] +./websocketmain [--model_thread_num ] [--decoder_thread_num ] + [--io_thread_num ] [--port ] [--listen_ip + ] [--punc-quant ] [--punc-dir ] + [--vad-quant ] [--vad-dir ] [--quantize + ] --model-dir [--] [--version] [-h] Where: - --wav-scp - wave scp path - --wav-path - wave file path + --model-dir + (required) the asr model path, which contains model.onnx, config.yaml, am.mvn + --quantize + false (Default), load the model of model.onnx in model_dir. If set true, load the model of model_quant.onnx in model_dir - --punc-config - punc config path - --punc-model - punc model path + --vad-dir + the vad model path, which contains model.onnx, vad.yaml, vad.mvn + --vad-quant + false (Default), load the model of model.onnx in vad_dir. If set true, load the model of model_quant.onnx in vad_dir - --am-config - (required) am config path - --am-cmvn - (required) am cmvn path - --am-model - (required) am model path + --punc-dir + the punc model path, which contains model.onnx, punc.yaml + --punc-quant + false (Default), load the model of model.onnx in punc_dir. If set true, load the model of model_quant.onnx in punc_dir - --vad-config - vad config path - --vad-cmvn - vad cmvn path - --vad-model - vad model path --decoder_thread_num - number of threads for decoder + number of threads for decoder, default:8 --io_thread_num - number of threads for network io + number of threads for network io, default:8 + --port + listen port, default:8889 - Required: --am-config --am-cmvn --am-model - If use vad, please add: [--vad-config ] [--vad-cmvn ] [--vad-model ] - If use punc, please add: [--punc-config ] [--punc-model ] + Required: --model-dir + If use vad, please add: --vad-dir + If use punc, please add: --punc-dir example: - websocketmain --am-config /FunASR/funasr/runtime/onnxruntime/export/damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/config.yaml --am-model /FunASR/funasr/runtime/onnxruntime/export/damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/model.onnx --am-cmvn /FunASR/funasr/runtime/onnxruntime/export/damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/am.mvn + websocketmain --model-dir /FunASR/funasr/runtime/onnxruntime/export/damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch ``` ## Run websocket client test diff --git a/funasr/runtime/websocket/websocketclient.cpp b/funasr/runtime/websocket/websocketclient.cpp index 9ef1d5e5e..3ab4e99e9 100644 --- a/funasr/runtime/websocket/websocketclient.cpp +++ b/funasr/runtime/websocket/websocketclient.cpp @@ -120,7 +120,7 @@ class websocket_client { uint64_t count = 0; std::stringstream val; - Audio audio(1); + funasr::Audio audio(1); int32_t sampling_rate = 16000; if (!audio.LoadPcmwav(wav_path.c_str(), &sampling_rate)) { diff --git a/funasr/runtime/websocket/websocketmain.cpp b/funasr/runtime/websocket/websocketmain.cpp index 24e4269d4..4614b5126 100644 --- a/funasr/runtime/websocket/websocketmain.cpp +++ b/funasr/runtime/websocket/websocketmain.cpp @@ -5,14 +5,11 @@ /* 2022-2023 by zhaomingwork */ // io server -// Usage:websocketmain [--model_thread_num ] [--decoder_thread_num -// ] [--io_thread_num ] [--port ] -// [--listen_ip ] [--wav-scp ] -// [--wav-path ] [--punc-config ] -// [--punc-model ] --am-config -// --am-cmvn --am-model -// [--vad-config ] [--vad-cmvn ] -// [--vad-model ] [--] [--version] [-h] +// Usage:websocketmain [--model_thread_num ] [--decoder_thread_num ] +// [--io_thread_num ] [--port ] [--listen_ip +// ] [--punc-quant ] [--punc-dir ] +// [--vad-quant ] [--vad-dir ] [--quantize +// ] --model-dir [--] [--version] [-h] #include "websocketsrv.h" using namespace std; @@ -29,29 +26,33 @@ int main(int argc, char* argv[]) { FLAGS_logtostderr = true; TCLAP::CmdLine cmd("websocketmain", ' ', "1.0"); - TCLAP::ValueArg vad_model("", VAD_MODEL_PATH, "vad model path", - false, "", "string"); - TCLAP::ValueArg vad_cmvn("", VAD_CMVN_PATH, "vad cmvn path", - false, "", "string"); - TCLAP::ValueArg vad_config( - "", VAD_CONFIG_PATH, "vad config path", false, "", "string"); - - TCLAP::ValueArg am_model("", AM_MODEL_PATH, "am model path", - true, "", "string"); - TCLAP::ValueArg am_cmvn("", AM_CMVN_PATH, "am cmvn path", true, - "", "string"); - TCLAP::ValueArg am_config("", AM_CONFIG_PATH, "am config path", - true, "", "string"); - - TCLAP::ValueArg punc_model( - "", PUNC_MODEL_PATH, "punc model path", false, "", "string"); - TCLAP::ValueArg punc_config( - "", PUNC_CONFIG_PATH, "punc config path", false, "", "string"); - - TCLAP::ValueArg wav_path("", WAV_PATH, "wave file path", false, - "", "string"); - TCLAP::ValueArg wav_scp("", WAV_SCP, "wave scp path", false, - "", "string"); + TCLAP::ValueArg model_dir( + "", MODEL_DIR, + "the asr model path, which contains model.onnx, config.yaml, am.mvn", + true, "", "string"); + TCLAP::ValueArg quantize( + "", QUANTIZE, + "false (Default), load the model of model.onnx in model_dir. If set " + "true, load the model of model_quant.onnx in model_dir", + false, "false", "string"); + TCLAP::ValueArg vad_dir( + "", VAD_DIR, + "the vad model path, which contains model.onnx, vad.yaml, vad.mvn", + false, "", "string"); + TCLAP::ValueArg vad_quant( + "", VAD_QUANT, + "false (Default), load the model of model.onnx in vad_dir. If set " + "true, load the model of model_quant.onnx in vad_dir", + false, "false", "string"); + TCLAP::ValueArg punc_dir( + "", PUNC_DIR, + "the punc model path, which contains model.onnx, punc.yaml", false, "", + "string"); + TCLAP::ValueArg punc_quant( + "", PUNC_QUANT, + "false (Default), load the model of model.onnx in punc_dir. If set " + "true, load the model of model_quant.onnx in punc_dir", + false, "false", "string"); TCLAP::ValueArg listen_ip("", "listen_ip", "listen_ip", false, "0.0.0.0", "string"); @@ -63,16 +64,13 @@ int main(int argc, char* argv[]) { TCLAP::ValueArg model_thread_num("", "model_thread_num", "model_thread_num", false, 1, "int"); - cmd.add(vad_model); - cmd.add(vad_cmvn); - cmd.add(vad_config); - cmd.add(am_model); - cmd.add(am_cmvn); - cmd.add(am_config); - cmd.add(punc_model); - cmd.add(punc_config); - cmd.add(wav_path); - cmd.add(wav_scp); + cmd.add(model_dir); + cmd.add(quantize); + cmd.add(vad_dir); + cmd.add(vad_quant); + cmd.add(punc_dir); + cmd.add(punc_quant); + cmd.add(listen_ip); cmd.add(port); cmd.add(io_thread_num); @@ -81,17 +79,12 @@ int main(int argc, char* argv[]) { cmd.parse(argc, argv); std::map model_path; - GetValue(vad_model, VAD_MODEL_PATH, model_path); - GetValue(vad_cmvn, VAD_CMVN_PATH, model_path); - GetValue(vad_config, VAD_CONFIG_PATH, model_path); - GetValue(am_model, AM_MODEL_PATH, model_path); - GetValue(am_cmvn, AM_CMVN_PATH, model_path); - GetValue(am_config, AM_CONFIG_PATH, model_path); - GetValue(punc_model, PUNC_MODEL_PATH, model_path); - GetValue(punc_config, PUNC_CONFIG_PATH, model_path); - GetValue(wav_path, WAV_PATH, model_path); - GetValue(wav_scp, WAV_SCP, model_path); - + GetValue(model_dir, MODEL_DIR, model_path); + GetValue(quantize, QUANTIZE, model_path); + GetValue(vad_dir, VAD_DIR, model_path); + GetValue(vad_quant, VAD_QUANT, model_path); + GetValue(punc_dir, PUNC_DIR, model_path); + GetValue(punc_quant, PUNC_QUANT, model_path); std::string s_listen_ip = listen_ip.getValue(); int s_port = port.getValue(); @@ -100,7 +93,6 @@ int main(int argc, char* argv[]) { int s_model_thread_num = model_thread_num.getValue(); - asio::io_context io_decoder; // context for decoding std::vector decoder_threads; diff --git a/funasr/runtime/websocket/websocketsrv.cpp b/funasr/runtime/websocket/websocketsrv.cpp index 7e54210cb..9e566677b 100644 --- a/funasr/runtime/websocket/websocketsrv.cpp +++ b/funasr/runtime/websocket/websocketsrv.cpp @@ -25,7 +25,7 @@ void WebSocketServer::do_decoder(const std::vector& buffer, if (!buffer.empty()) { // fout.write(buffer.data(), buffer.size()); // feed data to asr engine - FUNASR_RESULT Result = FunASRRecogPCMBuffer( + FUNASR_RESULT Result = FunOfflineRecogPCMBuffer( asr_hanlde, buffer.data(), buffer.size(), 16000, RASR_NONE, NULL); std::string asr_result = @@ -149,7 +149,7 @@ void WebSocketServer::initAsr(std::map& model_path, try { // init model with api - asr_hanlde = FunASRInit(model_path, thread_num); + asr_hanlde = FunOfflineInit(model_path, thread_num); std::cout << "model ready" << std::endl; } catch (const std::exception& e) { diff --git a/funasr/runtime/websocket/websocketsrv.h b/funasr/runtime/websocket/websocketsrv.h index 2d0c7bda3..e484724ba 100644 --- a/funasr/runtime/websocket/websocketsrv.h +++ b/funasr/runtime/websocket/websocketsrv.h @@ -30,7 +30,7 @@ #include "asio.hpp" #include "com-define.h" -#include "libfunasrapi.h" +#include "funasrruntime.h" #include "nlohmann/json.hpp" #include "tclap/CmdLine.h" typedef websocketpp::server server; From af6d02693975c224b19e4feadab63533a93c57a5 Mon Sep 17 00:00:00 2001 From: Yabin Li Date: Tue, 9 May 2023 19:16:48 +0800 Subject: [PATCH 097/120] Update CMakeLists.txt --- funasr/runtime/websocket/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/funasr/runtime/websocket/CMakeLists.txt b/funasr/runtime/websocket/CMakeLists.txt index 07d96d902..e89537b8f 100644 --- a/funasr/runtime/websocket/CMakeLists.txt +++ b/funasr/runtime/websocket/CMakeLists.txt @@ -8,7 +8,7 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) option(ENABLE_WEBSOCKET "Whether to build websocket server" ON) if(ENABLE_WEBSOCKET) - cmake_policy(SET CMP0135 NEW) + # cmake_policy(SET CMP0135 NEW) include(FetchContent) FetchContent_Declare(websocketpp From 2502160fcdfaaaab35c6691484d7dda04bb5720d Mon Sep 17 00:00:00 2001 From: "shixian.shi" Date: Tue, 9 May 2023 21:02:22 +0800 Subject: [PATCH 098/120] update sentence timestamp for ClipVedio --- funasr/utils/timestamp_tools.py | 38 +++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/funasr/utils/timestamp_tools.py b/funasr/utils/timestamp_tools.py index 87cc49eee..489d317d5 100644 --- a/funasr/utils/timestamp_tools.py +++ b/funasr/utils/timestamp_tools.py @@ -94,19 +94,33 @@ def time_stamp_sentence(punc_id_list, time_stamp_postprocessed, text_postprocess res.append({ 'text': text_postprocessed.split(), "start": time_stamp_postprocessed[0][0], - "end": time_stamp_postprocessed[-1][1] + "end": time_stamp_postprocessed[-1][1], + 'text_seg': text_postprocessed.split(), + "ts_list": time_stamp_postprocessed, }) return res if len(punc_id_list) != len(time_stamp_postprocessed): print(" warning length mistach!!!!!!") - sentence_text = '' + sentence_text = "" + sentence_text_seg = "" + ts_list = [] sentence_start = time_stamp_postprocessed[0][0] sentence_end = time_stamp_postprocessed[0][1] texts = text_postprocessed.split() punc_stamp_text_list = list(zip_longest(punc_id_list, time_stamp_postprocessed, texts, fillvalue=None)) for punc_stamp_text in punc_stamp_text_list: punc_id, time_stamp, text = punc_stamp_text - sentence_text += text if text is not None else '' + # sentence_text += text if text is not None else '' + if text is not None: + if 'a' <= text[0] <= 'z' or 'A' <= text[0] <= 'Z': + sentence_text += ' ' + text + elif len(sentence_text) and ('a' <= sentence_text[-1] <= 'z' or 'A' <= sentence_text[-1] <= 'Z'): + sentence_text += ' ' + text + else: + sentence_text += text + sentence_text_seg += text + ' ' + ts_list.append(time_stamp) + punc_id = int(punc_id) if punc_id is not None else 1 sentence_end = time_stamp[1] if time_stamp is not None else sentence_end @@ -115,27 +129,39 @@ def time_stamp_sentence(punc_id_list, time_stamp_postprocessed, text_postprocess res.append({ 'text': sentence_text, "start": sentence_start, - "end": sentence_end + "end": sentence_end, + "text_seg": sentence_text_seg, + "ts_list": ts_list }) sentence_text = '' + sentence_text_seg = '' + ts_list = [] sentence_start = sentence_end elif punc_id == 3: sentence_text += '.' res.append({ 'text': sentence_text, "start": sentence_start, - "end": sentence_end + "end": sentence_end, + "text_seg": sentence_text_seg, + "ts_list": ts_list }) sentence_text = '' + sentence_text_seg = '' + ts_list = [] sentence_start = sentence_end elif punc_id == 4: sentence_text += '?' res.append({ 'text': sentence_text, "start": sentence_start, - "end": sentence_end + "end": sentence_end, + "text_seg": sentence_text_seg, + "ts_list": ts_list }) sentence_text = '' + sentence_text_seg = '' + ts_list = [] sentence_start = sentence_end return res From 0bb1196656d1f730cbe75ba36f4105cadd120008 Mon Sep 17 00:00:00 2001 From: zhuzizyf <42790740+zhuzizyf@users.noreply.github.com> Date: Tue, 9 May 2023 22:23:06 +0800 Subject: [PATCH 099/120] Update e2e-vad.h Fixed the memory out-of-bounds issue caused by unsigned numbers. --- funasr/runtime/onnxruntime/src/e2e-vad.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/funasr/runtime/onnxruntime/src/e2e-vad.h b/funasr/runtime/onnxruntime/src/e2e-vad.h index e9a8293ef..d89a88950 100644 --- a/funasr/runtime/onnxruntime/src/e2e-vad.h +++ b/funasr/runtime/onnxruntime/src/e2e-vad.h @@ -442,7 +442,7 @@ private: } else { data_buf_all_size += waveform.size(); } - for (int offset = 0; offset < waveform.size() - frame_sample_length + 1; offset += frame_shift_length) { + for (int offset = 0; offset + frame_sample_length -1 < waveform.size(); offset += frame_shift_length) { float sum = 0.0; for (int i = 0; i < frame_sample_length; i++) { sum += waveform[offset + i] * waveform[offset + i]; From b15db52e4e67da8a133a67e8ffa415386de48b40 Mon Sep 17 00:00:00 2001 From: zhuyunfeng <10596244@qq.com> Date: Tue, 9 May 2023 23:03:15 +0800 Subject: [PATCH 100/120] Add contributor --- funasr/runtime/onnxruntime/src/e2e-vad.h | 1 + funasr/runtime/onnxruntime/src/online-feature.cpp | 1 + funasr/runtime/onnxruntime/src/online-feature.h | 1 + 3 files changed, 3 insertions(+) diff --git a/funasr/runtime/onnxruntime/src/e2e-vad.h b/funasr/runtime/onnxruntime/src/e2e-vad.h index d89a88950..5ece1f8ca 100644 --- a/funasr/runtime/onnxruntime/src/e2e-vad.h +++ b/funasr/runtime/onnxruntime/src/e2e-vad.h @@ -1,6 +1,7 @@ /** * Copyright FunASR (https://github.com/alibaba-damo-academy/FunASR). All Rights Reserved. * MIT License (https://opensource.org/licenses/MIT) + * Contributed by zhuzizyf(China Telecom). */ #pragma once diff --git a/funasr/runtime/onnxruntime/src/online-feature.cpp b/funasr/runtime/onnxruntime/src/online-feature.cpp index c5caf0ae6..a21589cf3 100644 --- a/funasr/runtime/onnxruntime/src/online-feature.cpp +++ b/funasr/runtime/onnxruntime/src/online-feature.cpp @@ -1,6 +1,7 @@ /** * Copyright FunASR (https://github.com/alibaba-damo-academy/FunASR). All Rights Reserved. * MIT License (https://opensource.org/licenses/MIT) + * Contributed by zhuzizyf(China Telecom). */ #include "online-feature.h" diff --git a/funasr/runtime/onnxruntime/src/online-feature.h b/funasr/runtime/onnxruntime/src/online-feature.h index 7347056de..16e6e4bea 100644 --- a/funasr/runtime/onnxruntime/src/online-feature.h +++ b/funasr/runtime/onnxruntime/src/online-feature.h @@ -1,6 +1,7 @@ /** * Copyright FunASR (https://github.com/alibaba-damo-academy/FunASR). All Rights Reserved. * MIT License (https://opensource.org/licenses/MIT) + * Contributed by zhuzizyf(China Telecom). */ #pragma once #include From 633d68f35457dd245026a3f6ad5a6cc06fd89996 Mon Sep 17 00:00:00 2001 From: "shixian.shi" Date: Wed, 10 May 2023 11:32:36 +0800 Subject: [PATCH 101/120] update timestamp_tools --- funasr/utils/timestamp_tools.py | 31 +++---------------------------- 1 file changed, 3 insertions(+), 28 deletions(-) diff --git a/funasr/utils/timestamp_tools.py b/funasr/utils/timestamp_tools.py index 489d317d5..4e7a8a942 100644 --- a/funasr/utils/timestamp_tools.py +++ b/funasr/utils/timestamp_tools.py @@ -80,6 +80,7 @@ def ts_prediction_lfr6_standard(us_alphas, def time_stamp_sentence(punc_id_list, time_stamp_postprocessed, text_postprocessed): + punc_list = [',', '。', '?', '、'] res = [] if text_postprocessed is None: return res @@ -124,34 +125,8 @@ def time_stamp_sentence(punc_id_list, time_stamp_postprocessed, text_postprocess punc_id = int(punc_id) if punc_id is not None else 1 sentence_end = time_stamp[1] if time_stamp is not None else sentence_end - if punc_id == 2: - sentence_text += ',' - res.append({ - 'text': sentence_text, - "start": sentence_start, - "end": sentence_end, - "text_seg": sentence_text_seg, - "ts_list": ts_list - }) - sentence_text = '' - sentence_text_seg = '' - ts_list = [] - sentence_start = sentence_end - elif punc_id == 3: - sentence_text += '.' - res.append({ - 'text': sentence_text, - "start": sentence_start, - "end": sentence_end, - "text_seg": sentence_text_seg, - "ts_list": ts_list - }) - sentence_text = '' - sentence_text_seg = '' - ts_list = [] - sentence_start = sentence_end - elif punc_id == 4: - sentence_text += '?' + if punc_id > 1: + sentence_text += punc_list[punc_id - 2] res.append({ 'text': sentence_text, "start": sentence_start, From a85cfe4a31e99858cb4b7d41edfd75e808dba45a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=B8=E9=9B=81?= Date: Wed, 10 May 2023 15:23:08 +0800 Subject: [PATCH 102/120] vad docs --- egs_modelscope/vad/TEMPLATE/README.md | 4 ++-- egs_modelscope/vad/TEMPLATE/infer.py | 4 ++-- egs_modelscope/vad/speech_fsmn_vad_zh-cn-16k-common/README.md | 2 +- egs_modelscope/vad/speech_fsmn_vad_zh-cn-16k-common/demo.py | 2 +- egs_modelscope/vad/speech_fsmn_vad_zh-cn-16k-common/infer.py | 2 +- egs_modelscope/vad/speech_fsmn_vad_zh-cn-16k-common/infer.sh | 2 +- egs_modelscope/vad/speech_fsmn_vad_zh-cn-8k-common/README.md | 2 +- egs_modelscope/vad/speech_fsmn_vad_zh-cn-8k-common/demo.py | 2 +- .../vad/speech_fsmn_vad_zh-cn-8k-common/demo_online.py | 2 +- egs_modelscope/vad/speech_fsmn_vad_zh-cn-8k-common/infer.py | 2 +- egs_modelscope/vad/speech_fsmn_vad_zh-cn-8k-common/infer.sh | 2 +- k2/__init__.py | 0 12 files changed, 13 insertions(+), 13 deletions(-) create mode 100644 k2/__init__.py diff --git a/egs_modelscope/vad/TEMPLATE/README.md b/egs_modelscope/vad/TEMPLATE/README.md index 4c6f8c282..945f9fa60 100644 --- a/egs_modelscope/vad/TEMPLATE/README.md +++ b/egs_modelscope/vad/TEMPLATE/README.md @@ -83,7 +83,7 @@ FunASR also offer recipes [egs_modelscope/vad/TEMPLATE/infer.sh](https://github. #### Decode with multi GPUs: ```shell bash infer.sh \ - --model "damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch" \ + --model "damo/speech_fsmn_vad_zh-cn-16k-common-pytorch" \ --data_dir "./data/test" \ --output_dir "./results" \ --batch_size 1 \ @@ -93,7 +93,7 @@ FunASR also offer recipes [egs_modelscope/vad/TEMPLATE/infer.sh](https://github. #### Decode with multi-thread CPUs: ```shell bash infer.sh \ - --model "damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch" \ + --model "damo/speech_fsmn_vad_zh-cn-16k-common-pytorch" \ --data_dir "./data/test" \ --output_dir "./results" \ --gpu_inference false \ diff --git a/egs_modelscope/vad/TEMPLATE/infer.py b/egs_modelscope/vad/TEMPLATE/infer.py index 3d9ee5520..f49ab4b79 100644 --- a/egs_modelscope/vad/TEMPLATE/infer.py +++ b/egs_modelscope/vad/TEMPLATE/infer.py @@ -16,10 +16,10 @@ def modelscope_infer(args): if __name__ == "__main__": parser = argparse.ArgumentParser() - parser.add_argument('--model', type=str, default="damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch") + parser.add_argument('--model', type=str, default="damo/speech_fsmn_vad_zh-cn-16k-common-pytorch") parser.add_argument('--audio_in', type=str, default="./data/test/wav.scp") parser.add_argument('--output_dir', type=str, default="./results/") - parser.add_argument('--batch_size', type=int, default=64) + parser.add_argument('--batch_size', type=int, default=1) parser.add_argument('--gpuid', type=str, default="0") args = parser.parse_args() modelscope_infer(args) \ No newline at end of file diff --git a/egs_modelscope/vad/speech_fsmn_vad_zh-cn-16k-common/README.md b/egs_modelscope/vad/speech_fsmn_vad_zh-cn-16k-common/README.md index bb55ab52e..92088a21d 120000 --- a/egs_modelscope/vad/speech_fsmn_vad_zh-cn-16k-common/README.md +++ b/egs_modelscope/vad/speech_fsmn_vad_zh-cn-16k-common/README.md @@ -1 +1 @@ -../../TEMPLATE/README.md \ No newline at end of file +../TEMPLATE/README.md \ No newline at end of file diff --git a/egs_modelscope/vad/speech_fsmn_vad_zh-cn-16k-common/demo.py b/egs_modelscope/vad/speech_fsmn_vad_zh-cn-16k-common/demo.py index bbc16c5b6..eded5edca 100644 --- a/egs_modelscope/vad/speech_fsmn_vad_zh-cn-16k-common/demo.py +++ b/egs_modelscope/vad/speech_fsmn_vad_zh-cn-16k-common/demo.py @@ -7,7 +7,7 @@ if __name__ == '__main__': inference_pipeline = pipeline( task=Tasks.voice_activity_detection, model="damo/speech_fsmn_vad_zh-cn-16k-common-pytorch", - model_revision='v1.2.0', + model_revision=None, output_dir=output_dir, batch_size=1, ) diff --git a/egs_modelscope/vad/speech_fsmn_vad_zh-cn-16k-common/infer.py b/egs_modelscope/vad/speech_fsmn_vad_zh-cn-16k-common/infer.py index 128fc31c2..f05fbbb8b 120000 --- a/egs_modelscope/vad/speech_fsmn_vad_zh-cn-16k-common/infer.py +++ b/egs_modelscope/vad/speech_fsmn_vad_zh-cn-16k-common/infer.py @@ -1 +1 @@ -../../TEMPLATE/infer.py \ No newline at end of file +../TEMPLATE/infer.py \ No newline at end of file diff --git a/egs_modelscope/vad/speech_fsmn_vad_zh-cn-16k-common/infer.sh b/egs_modelscope/vad/speech_fsmn_vad_zh-cn-16k-common/infer.sh index 5e59f1841..0b3b38b6f 120000 --- a/egs_modelscope/vad/speech_fsmn_vad_zh-cn-16k-common/infer.sh +++ b/egs_modelscope/vad/speech_fsmn_vad_zh-cn-16k-common/infer.sh @@ -1 +1 @@ -../../TEMPLATE/infer.sh \ No newline at end of file +../TEMPLATE/infer.sh \ No newline at end of file diff --git a/egs_modelscope/vad/speech_fsmn_vad_zh-cn-8k-common/README.md b/egs_modelscope/vad/speech_fsmn_vad_zh-cn-8k-common/README.md index bb55ab52e..92088a21d 120000 --- a/egs_modelscope/vad/speech_fsmn_vad_zh-cn-8k-common/README.md +++ b/egs_modelscope/vad/speech_fsmn_vad_zh-cn-8k-common/README.md @@ -1 +1 @@ -../../TEMPLATE/README.md \ No newline at end of file +../TEMPLATE/README.md \ No newline at end of file diff --git a/egs_modelscope/vad/speech_fsmn_vad_zh-cn-8k-common/demo.py b/egs_modelscope/vad/speech_fsmn_vad_zh-cn-8k-common/demo.py index 84863d082..33be5059a 100644 --- a/egs_modelscope/vad/speech_fsmn_vad_zh-cn-8k-common/demo.py +++ b/egs_modelscope/vad/speech_fsmn_vad_zh-cn-8k-common/demo.py @@ -7,7 +7,7 @@ if __name__ == '__main__': inference_pipeline = pipeline( task=Tasks.voice_activity_detection, model="damo/speech_fsmn_vad_zh-cn-8k-common", - model_revision='v1.2.0', + model_revision=None, output_dir=output_dir, batch_size=1, ) diff --git a/egs_modelscope/vad/speech_fsmn_vad_zh-cn-8k-common/demo_online.py b/egs_modelscope/vad/speech_fsmn_vad_zh-cn-8k-common/demo_online.py index 5b67da74a..ec5c50281 100644 --- a/egs_modelscope/vad/speech_fsmn_vad_zh-cn-8k-common/demo_online.py +++ b/egs_modelscope/vad/speech_fsmn_vad_zh-cn-8k-common/demo_online.py @@ -11,7 +11,7 @@ if __name__ == '__main__': inference_pipeline = pipeline( task=Tasks.voice_activity_detection, model="damo/speech_fsmn_vad_zh-cn-8k-common", - model_revision='v1.2.0', + model_revision=None, output_dir=output_dir, batch_size=1, mode='online', diff --git a/egs_modelscope/vad/speech_fsmn_vad_zh-cn-8k-common/infer.py b/egs_modelscope/vad/speech_fsmn_vad_zh-cn-8k-common/infer.py index 128fc31c2..f05fbbb8b 120000 --- a/egs_modelscope/vad/speech_fsmn_vad_zh-cn-8k-common/infer.py +++ b/egs_modelscope/vad/speech_fsmn_vad_zh-cn-8k-common/infer.py @@ -1 +1 @@ -../../TEMPLATE/infer.py \ No newline at end of file +../TEMPLATE/infer.py \ No newline at end of file diff --git a/egs_modelscope/vad/speech_fsmn_vad_zh-cn-8k-common/infer.sh b/egs_modelscope/vad/speech_fsmn_vad_zh-cn-8k-common/infer.sh index 5e59f1841..0b3b38b6f 120000 --- a/egs_modelscope/vad/speech_fsmn_vad_zh-cn-8k-common/infer.sh +++ b/egs_modelscope/vad/speech_fsmn_vad_zh-cn-8k-common/infer.sh @@ -1 +1 @@ -../../TEMPLATE/infer.sh \ No newline at end of file +../TEMPLATE/infer.sh \ No newline at end of file diff --git a/k2/__init__.py b/k2/__init__.py new file mode 100644 index 000000000..e69de29bb From f1b7c6e039f200b41a5d77e0eb1258b84a059fac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=B8=E9=9B=81?= Date: Wed, 10 May 2023 15:23:34 +0800 Subject: [PATCH 103/120] vad docs --- k2/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 k2/__init__.py diff --git a/k2/__init__.py b/k2/__init__.py deleted file mode 100644 index e69de29bb..000000000 From 42b7bbb92027b3bbba729a70ec8f2c4071618728 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=B8=E9=9B=81?= Date: Wed, 10 May 2023 15:27:59 +0800 Subject: [PATCH 104/120] vad docs --- egs_modelscope/vad/TEMPLATE/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/egs_modelscope/vad/TEMPLATE/README.md b/egs_modelscope/vad/TEMPLATE/README.md index 945f9fa60..0ad9fb34c 100644 --- a/egs_modelscope/vad/TEMPLATE/README.md +++ b/egs_modelscope/vad/TEMPLATE/README.md @@ -97,7 +97,7 @@ FunASR also offer recipes [egs_modelscope/vad/TEMPLATE/infer.sh](https://github. --data_dir "./data/test" \ --output_dir "./results" \ --gpu_inference false \ - --njob 1 + --njob 64 ``` ## Finetune with pipeline From 5bbdcb2e2c88e6fa828566dfb4182613a65f6911 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=B8=E9=9B=81?= Date: Wed, 10 May 2023 15:42:24 +0800 Subject: [PATCH 105/120] online demo --- .../{infer.py => demo.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online/{infer.py => demo.py} (100%) diff --git a/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online/infer.py b/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online/demo.py similarity index 100% rename from egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online/infer.py rename to egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online/demo.py From 6d9644d98a1e21db28dae771c1f122de368179c0 Mon Sep 17 00:00:00 2001 From: "haoneng.lhn" Date: Wed, 10 May 2023 16:50:00 +0800 Subject: [PATCH 106/120] update infer recipe --- .../README.md | 2 +- .../infer.sh | 104 +++++++++++++++++- .../README.md | 2 +- .../infer.py | 2 +- .../infer.sh | 104 +++++++++++++++++- .../README.md | 2 +- .../infer.py | 2 +- .../infer.sh | 104 +++++++++++++++++- 8 files changed, 314 insertions(+), 8 deletions(-) mode change 120000 => 100644 egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/infer.sh mode change 120000 => 100644 egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/infer.sh mode change 120000 => 100644 egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch/infer.sh diff --git a/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/README.md b/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/README.md index 92088a21d..bb55ab52e 120000 --- a/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/README.md +++ b/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/README.md @@ -1 +1 @@ -../TEMPLATE/README.md \ No newline at end of file +../../TEMPLATE/README.md \ No newline at end of file diff --git a/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/infer.sh b/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/infer.sh deleted file mode 120000 index 0b3b38b6f..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/infer.sh +++ /dev/null @@ -1 +0,0 @@ -../TEMPLATE/infer.sh \ No newline at end of file diff --git a/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/infer.sh b/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/infer.sh new file mode 100644 index 000000000..ef49d7a60 --- /dev/null +++ b/egs_modelscope/asr/paraformer/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/infer.sh @@ -0,0 +1,103 @@ +#!/usr/bin/env bash + +set -e +set -u +set -o pipefail + +stage=1 +stop_stage=2 +model="damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch" +data_dir="./data/test" +output_dir="./results" +batch_size=64 +gpu_inference=true # whether to perform gpu decoding +gpuid_list="0,1" # set gpus, e.g., gpuid_list="0,1" +njob=64 # the number of jobs for CPU decoding, if gpu_inference=false, use CPU decoding, please set njob +checkpoint_dir= +checkpoint_name="valid.cer_ctc.ave.pb" + +. utils/parse_options.sh || exit 1; + +if ${gpu_inference} == "true"; then + nj=$(echo $gpuid_list | awk -F "," '{print NF}') +else + nj=$njob + batch_size=1 + gpuid_list="" + for JOB in $(seq ${nj}); do + gpuid_list=$gpuid_list"-1," + done +fi + +mkdir -p $output_dir/split +split_scps="" +for JOB in $(seq ${nj}); do + split_scps="$split_scps $output_dir/split/wav.$JOB.scp" +done +perl utils/split_scp.pl ${data_dir}/wav.scp ${split_scps} + +if [ -n "${checkpoint_dir}" ]; then + python utils/prepare_checkpoint.py ${model} ${checkpoint_dir} ${checkpoint_name} + model=${checkpoint_dir}/${model} +fi + +if [ $stage -le 1 ] && [ $stop_stage -ge 1 ];then + echo "Decoding ..." + gpuid_list_array=(${gpuid_list//,/ }) + for JOB in $(seq ${nj}); do + { + id=$((JOB-1)) + gpuid=${gpuid_list_array[$id]} + mkdir -p ${output_dir}/output.$JOB + python infer.py \ + --model ${model} \ + --audio_in ${output_dir}/split/wav.$JOB.scp \ + --output_dir ${output_dir}/output.$JOB \ + --batch_size ${batch_size} \ + --gpuid ${gpuid} + }& + done + wait + + mkdir -p ${output_dir}/1best_recog + for f in token score text; do + if [ -f "${output_dir}/output.1/1best_recog/${f}" ]; then + for i in $(seq "${nj}"); do + cat "${output_dir}/output.${i}/1best_recog/${f}" + done | sort -k1 >"${output_dir}/1best_recog/${f}" + fi + done +fi + +if [ $stage -le 2 ] && [ $stop_stage -ge 2 ];then + echo "Computing WER ..." + cp ${output_dir}/1best_recog/text ${output_dir}/1best_recog/text.proc + cp ${data_dir}/text ${output_dir}/1best_recog/text.ref + python utils/compute_wer.py ${output_dir}/1best_recog/text.ref ${output_dir}/1best_recog/text.proc ${output_dir}/1best_recog/text.cer + tail -n 3 ${output_dir}/1best_recog/text.cer +fi + +if [ $stage -le 3 ] && [ $stop_stage -ge 3 ];then + echo "SpeechIO TIOBE textnorm" + echo "$0 --> Normalizing REF text ..." + ./utils/textnorm_zh.py \ + --has_key --to_upper \ + ${data_dir}/text \ + ${output_dir}/1best_recog/ref.txt + + echo "$0 --> Normalizing HYP text ..." + ./utils/textnorm_zh.py \ + --has_key --to_upper \ + ${output_dir}/1best_recog/text.proc \ + ${output_dir}/1best_recog/rec.txt + grep -v $'\t$' ${output_dir}/1best_recog/rec.txt > ${output_dir}/1best_recog/rec_non_empty.txt + + echo "$0 --> computing WER/CER and alignment ..." + ./utils/error_rate_zh \ + --tokenizer char \ + --ref ${output_dir}/1best_recog/ref.txt \ + --hyp ${output_dir}/1best_recog/rec_non_empty.txt \ + ${output_dir}/1best_recog/DETAILS.txt | tee ${output_dir}/1best_recog/RESULTS.txt + rm -rf ${output_dir}/1best_recog/rec.txt ${output_dir}/1best_recog/rec_non_empty.txt +fi + diff --git a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/README.md b/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/README.md index 92088a21d..bb55ab52e 120000 --- a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/README.md +++ b/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/README.md @@ -1 +1 @@ -../TEMPLATE/README.md \ No newline at end of file +../../TEMPLATE/README.md \ No newline at end of file diff --git a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/infer.py b/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/infer.py index f05fbbb8b..128fc31c2 120000 --- a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/infer.py +++ b/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/infer.py @@ -1 +1 @@ -../TEMPLATE/infer.py \ No newline at end of file +../../TEMPLATE/infer.py \ No newline at end of file diff --git a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/infer.sh b/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/infer.sh deleted file mode 120000 index 0b3b38b6f..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/infer.sh +++ /dev/null @@ -1 +0,0 @@ -../TEMPLATE/infer.sh \ No newline at end of file diff --git a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/infer.sh b/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/infer.sh new file mode 100644 index 000000000..207bbdf04 --- /dev/null +++ b/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch/infer.sh @@ -0,0 +1,103 @@ +#!/usr/bin/env bash + +set -e +set -u +set -o pipefail + +stage=1 +stop_stage=2 +model="damo/speech_paraformer_asr_nat-zh-cn-16k-aishell1-vocab4234-pytorch" +data_dir="./data/test" +output_dir="./results" +batch_size=64 +gpu_inference=true # whether to perform gpu decoding +gpuid_list="0,1" # set gpus, e.g., gpuid_list="0,1" +njob=64 # the number of jobs for CPU decoding, if gpu_inference=false, use CPU decoding, please set njob +checkpoint_dir= +checkpoint_name="valid.cer_ctc.ave.pb" + +. utils/parse_options.sh || exit 1; + +if ${gpu_inference} == "true"; then + nj=$(echo $gpuid_list | awk -F "," '{print NF}') +else + nj=$njob + batch_size=1 + gpuid_list="" + for JOB in $(seq ${nj}); do + gpuid_list=$gpuid_list"-1," + done +fi + +mkdir -p $output_dir/split +split_scps="" +for JOB in $(seq ${nj}); do + split_scps="$split_scps $output_dir/split/wav.$JOB.scp" +done +perl utils/split_scp.pl ${data_dir}/wav.scp ${split_scps} + +if [ -n "${checkpoint_dir}" ]; then + python utils/prepare_checkpoint.py ${model} ${checkpoint_dir} ${checkpoint_name} + model=${checkpoint_dir}/${model} +fi + +if [ $stage -le 1 ] && [ $stop_stage -ge 1 ];then + echo "Decoding ..." + gpuid_list_array=(${gpuid_list//,/ }) + for JOB in $(seq ${nj}); do + { + id=$((JOB-1)) + gpuid=${gpuid_list_array[$id]} + mkdir -p ${output_dir}/output.$JOB + python infer.py \ + --model ${model} \ + --audio_in ${output_dir}/split/wav.$JOB.scp \ + --output_dir ${output_dir}/output.$JOB \ + --batch_size ${batch_size} \ + --gpuid ${gpuid} + }& + done + wait + + mkdir -p ${output_dir}/1best_recog + for f in token score text; do + if [ -f "${output_dir}/output.1/1best_recog/${f}" ]; then + for i in $(seq "${nj}"); do + cat "${output_dir}/output.${i}/1best_recog/${f}" + done | sort -k1 >"${output_dir}/1best_recog/${f}" + fi + done +fi + +if [ $stage -le 2 ] && [ $stop_stage -ge 2 ];then + echo "Computing WER ..." + cp ${output_dir}/1best_recog/text ${output_dir}/1best_recog/text.proc + cp ${data_dir}/text ${output_dir}/1best_recog/text.ref + python utils/compute_wer.py ${output_dir}/1best_recog/text.ref ${output_dir}/1best_recog/text.proc ${output_dir}/1best_recog/text.cer + tail -n 3 ${output_dir}/1best_recog/text.cer +fi + +if [ $stage -le 3 ] && [ $stop_stage -ge 3 ];then + echo "SpeechIO TIOBE textnorm" + echo "$0 --> Normalizing REF text ..." + ./utils/textnorm_zh.py \ + --has_key --to_upper \ + ${data_dir}/text \ + ${output_dir}/1best_recog/ref.txt + + echo "$0 --> Normalizing HYP text ..." + ./utils/textnorm_zh.py \ + --has_key --to_upper \ + ${output_dir}/1best_recog/text.proc \ + ${output_dir}/1best_recog/rec.txt + grep -v $'\t$' ${output_dir}/1best_recog/rec.txt > ${output_dir}/1best_recog/rec_non_empty.txt + + echo "$0 --> computing WER/CER and alignment ..." + ./utils/error_rate_zh \ + --tokenizer char \ + --ref ${output_dir}/1best_recog/ref.txt \ + --hyp ${output_dir}/1best_recog/rec_non_empty.txt \ + ${output_dir}/1best_recog/DETAILS.txt | tee ${output_dir}/1best_recog/RESULTS.txt + rm -rf ${output_dir}/1best_recog/rec.txt ${output_dir}/1best_recog/rec_non_empty.txt +fi + diff --git a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch/README.md b/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch/README.md index 92088a21d..bb55ab52e 120000 --- a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch/README.md +++ b/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch/README.md @@ -1 +1 @@ -../TEMPLATE/README.md \ No newline at end of file +../../TEMPLATE/README.md \ No newline at end of file diff --git a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch/infer.py b/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch/infer.py index f05fbbb8b..128fc31c2 120000 --- a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch/infer.py +++ b/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch/infer.py @@ -1 +1 @@ -../TEMPLATE/infer.py \ No newline at end of file +../../TEMPLATE/infer.py \ No newline at end of file diff --git a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch/infer.sh b/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch/infer.sh deleted file mode 120000 index 0b3b38b6f..000000000 --- a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch/infer.sh +++ /dev/null @@ -1 +0,0 @@ -../TEMPLATE/infer.sh \ No newline at end of file diff --git a/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch/infer.sh b/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch/infer.sh new file mode 100644 index 000000000..4b59bc102 --- /dev/null +++ b/egs_modelscope/asr/paraformer/speech_paraformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch/infer.sh @@ -0,0 +1,103 @@ +#!/usr/bin/env bash + +set -e +set -u +set -o pipefail + +stage=1 +stop_stage=2 +model="damo/speech_paraformer_asr_nat-zh-cn-16k-aishell2-vocab5212-pytorch" +data_dir="./data/test" +output_dir="./results" +batch_size=64 +gpu_inference=true # whether to perform gpu decoding +gpuid_list="0,1" # set gpus, e.g., gpuid_list="0,1" +njob=64 # the number of jobs for CPU decoding, if gpu_inference=false, use CPU decoding, please set njob +checkpoint_dir= +checkpoint_name="valid.cer_ctc.ave.pb" + +. utils/parse_options.sh || exit 1; + +if ${gpu_inference} == "true"; then + nj=$(echo $gpuid_list | awk -F "," '{print NF}') +else + nj=$njob + batch_size=1 + gpuid_list="" + for JOB in $(seq ${nj}); do + gpuid_list=$gpuid_list"-1," + done +fi + +mkdir -p $output_dir/split +split_scps="" +for JOB in $(seq ${nj}); do + split_scps="$split_scps $output_dir/split/wav.$JOB.scp" +done +perl utils/split_scp.pl ${data_dir}/wav.scp ${split_scps} + +if [ -n "${checkpoint_dir}" ]; then + python utils/prepare_checkpoint.py ${model} ${checkpoint_dir} ${checkpoint_name} + model=${checkpoint_dir}/${model} +fi + +if [ $stage -le 1 ] && [ $stop_stage -ge 1 ];then + echo "Decoding ..." + gpuid_list_array=(${gpuid_list//,/ }) + for JOB in $(seq ${nj}); do + { + id=$((JOB-1)) + gpuid=${gpuid_list_array[$id]} + mkdir -p ${output_dir}/output.$JOB + python infer.py \ + --model ${model} \ + --audio_in ${output_dir}/split/wav.$JOB.scp \ + --output_dir ${output_dir}/output.$JOB \ + --batch_size ${batch_size} \ + --gpuid ${gpuid} + }& + done + wait + + mkdir -p ${output_dir}/1best_recog + for f in token score text; do + if [ -f "${output_dir}/output.1/1best_recog/${f}" ]; then + for i in $(seq "${nj}"); do + cat "${output_dir}/output.${i}/1best_recog/${f}" + done | sort -k1 >"${output_dir}/1best_recog/${f}" + fi + done +fi + +if [ $stage -le 2 ] && [ $stop_stage -ge 2 ];then + echo "Computing WER ..." + cp ${output_dir}/1best_recog/text ${output_dir}/1best_recog/text.proc + cp ${data_dir}/text ${output_dir}/1best_recog/text.ref + python utils/compute_wer.py ${output_dir}/1best_recog/text.ref ${output_dir}/1best_recog/text.proc ${output_dir}/1best_recog/text.cer + tail -n 3 ${output_dir}/1best_recog/text.cer +fi + +if [ $stage -le 3 ] && [ $stop_stage -ge 3 ];then + echo "SpeechIO TIOBE textnorm" + echo "$0 --> Normalizing REF text ..." + ./utils/textnorm_zh.py \ + --has_key --to_upper \ + ${data_dir}/text \ + ${output_dir}/1best_recog/ref.txt + + echo "$0 --> Normalizing HYP text ..." + ./utils/textnorm_zh.py \ + --has_key --to_upper \ + ${output_dir}/1best_recog/text.proc \ + ${output_dir}/1best_recog/rec.txt + grep -v $'\t$' ${output_dir}/1best_recog/rec.txt > ${output_dir}/1best_recog/rec_non_empty.txt + + echo "$0 --> computing WER/CER and alignment ..." + ./utils/error_rate_zh \ + --tokenizer char \ + --ref ${output_dir}/1best_recog/ref.txt \ + --hyp ${output_dir}/1best_recog/rec_non_empty.txt \ + ${output_dir}/1best_recog/DETAILS.txt | tee ${output_dir}/1best_recog/RESULTS.txt + rm -rf ${output_dir}/1best_recog/rec.txt ${output_dir}/1best_recog/rec_non_empty.txt +fi + From eea2a7689f18ce7ef3b0ab8bd3657f4f6f5cf8e0 Mon Sep 17 00:00:00 2001 From: lyblsgo Date: Wed, 10 May 2023 16:52:46 +0800 Subject: [PATCH 107/120] fix paraformer-server for new apis --- funasr/runtime/grpc/paraformer-server.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/funasr/runtime/grpc/paraformer-server.cc b/funasr/runtime/grpc/paraformer-server.cc index 3bc011aea..734dadc6a 100644 --- a/funasr/runtime/grpc/paraformer-server.cc +++ b/funasr/runtime/grpc/paraformer-server.cc @@ -137,7 +137,7 @@ grpc::Status ASRServicer::Recognize( stream->Write(res); } else { - FUNASR_RESULT Result= FunOfflineRecogPCMBuffer(AsrHanlde, tmp_data.c_str(), data_len_int, 16000, RASR_NONE, NULL); + FUNASR_RESULT Result= FunOfflineInferBuffer(AsrHanlde, tmp_data.c_str(), data_len_int, RASR_NONE, NULL, 16000); std::string asr_result = ((FUNASR_RECOG_RESULT*)Result)->msg; auto end_time = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); From 9eaa9de61afdeb384825a2d6f9bcc2122c9a0804 Mon Sep 17 00:00:00 2001 From: lyblsgo Date: Wed, 10 May 2023 16:53:16 +0800 Subject: [PATCH 108/120] fix websocketsrv.cpp for new apis --- funasr/runtime/websocket/websocketsrv.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/funasr/runtime/websocket/websocketsrv.cpp b/funasr/runtime/websocket/websocketsrv.cpp index 9e566677b..1a6adbff2 100644 --- a/funasr/runtime/websocket/websocketsrv.cpp +++ b/funasr/runtime/websocket/websocketsrv.cpp @@ -25,8 +25,8 @@ void WebSocketServer::do_decoder(const std::vector& buffer, if (!buffer.empty()) { // fout.write(buffer.data(), buffer.size()); // feed data to asr engine - FUNASR_RESULT Result = FunOfflineRecogPCMBuffer( - asr_hanlde, buffer.data(), buffer.size(), 16000, RASR_NONE, NULL); + FUNASR_RESULT Result = FunOfflineInferBuffer( + asr_hanlde, buffer.data(), buffer.size(), RASR_NONE, NULL, 16000); std::string asr_result = ((FUNASR_RECOG_RESULT*)Result)->msg; // get decode result From 02ff2230adf4a84bd0332d784d4f64f17cb4112c Mon Sep 17 00:00:00 2001 From: lyblsgo Date: Wed, 10 May 2023 16:54:21 +0800 Subject: [PATCH 109/120] modify funasr apis --- .../onnxruntime/include/funasrruntime.h | 28 ++- .../runtime/onnxruntime/src/funasrruntime.cpp | 201 ++++++++---------- 2 files changed, 113 insertions(+), 116 deletions(-) diff --git a/funasr/runtime/onnxruntime/include/funasrruntime.h b/funasr/runtime/onnxruntime/include/funasrruntime.h index 75be80e5c..5cfdb47d3 100644 --- a/funasr/runtime/onnxruntime/include/funasrruntime.h +++ b/funasr/runtime/onnxruntime/include/funasrruntime.h @@ -46,15 +46,20 @@ typedef enum { FUNASR_MODEL_PARAFORMER = 3, }FUNASR_MODEL_TYPE; +typedef enum +{ + FSMN_VAD_OFFLINE=0, + FSMN_VAD_ONLINE = 1, +}FSMN_VAD_MODE; + typedef void (* QM_CALLBACK)(int cur_step, int n_total); // n_total: total steps; cur_step: Current Step. // ASR _FUNASRAPI FUNASR_HANDLE FunASRInit(std::map& model_path, int thread_num); - -_FUNASRAPI FUNASR_RESULT FunASRRecogBuffer(FUNASR_HANDLE handle, const char* sz_buf, int n_len, FUNASR_MODE mode, QM_CALLBACK fn_callback); -_FUNASRAPI FUNASR_RESULT FunASRRecogPCMBuffer(FUNASR_HANDLE handle, const char* sz_buf, int n_len, int sampling_rate, FUNASR_MODE mode, QM_CALLBACK fn_callback); -_FUNASRAPI FUNASR_RESULT FunASRRecogPCMFile(FUNASR_HANDLE handle, const char* sz_filename, int sampling_rate, FUNASR_MODE mode, QM_CALLBACK fn_callback); -_FUNASRAPI FUNASR_RESULT FunASRRecogFile(FUNASR_HANDLE handle, const char* sz_wavfile, FUNASR_MODE mode, QM_CALLBACK fn_callback); +// buffer +_FUNASRAPI FUNASR_RESULT FunASRInferBuffer(FUNASR_HANDLE handle, const char* sz_buf, int n_len, FUNASR_MODE mode, QM_CALLBACK fn_callback, int sampling_rate=16000); +// file, support wav & pcm +_FUNASRAPI FUNASR_RESULT FunASRInfer(FUNASR_HANDLE handle, const char* sz_filename, FUNASR_MODE mode, QM_CALLBACK fn_callback, int sampling_rate=16000); _FUNASRAPI const char* FunASRGetResult(FUNASR_RESULT result,int n_index); _FUNASRAPI const int FunASRGetRetNumber(FUNASR_RESULT result); @@ -63,9 +68,12 @@ _FUNASRAPI void FunASRUninit(FUNASR_HANDLE handle); _FUNASRAPI const float FunASRGetRetSnippetTime(FUNASR_RESULT result); // VAD -_FUNASRAPI FUNASR_HANDLE FsmnVadInit(std::map& model_path, int thread_num); +_FUNASRAPI FUNASR_HANDLE FsmnVadInit(std::map& model_path, int thread_num, FSMN_VAD_MODE mode=FSMN_VAD_OFFLINE); +// buffer +_FUNASRAPI FUNASR_RESULT FsmnVadInferBuffer(FUNASR_HANDLE handle, const char* sz_buf, int n_len, FSMN_VAD_MODE mode, QM_CALLBACK fn_callback, int sampling_rate=16000); +// file, support wav & pcm +_FUNASRAPI FUNASR_RESULT FsmnVadInfer(FUNASR_HANDLE handle, const char* sz_filename, FSMN_VAD_MODE mode, QM_CALLBACK fn_callback, int sampling_rate=16000); -_FUNASRAPI FUNASR_RESULT FsmnVadWavFile(FUNASR_HANDLE handle, const char* sz_wavfile, FUNASR_MODE mode, QM_CALLBACK fn_callback); _FUNASRAPI std::vector>* FsmnVadGetResult(FUNASR_RESULT result,int n_index); _FUNASRAPI void FsmnVadFreeResult(FUNASR_RESULT result); _FUNASRAPI void FsmnVadUninit(FUNASR_HANDLE handle); @@ -78,8 +86,10 @@ _FUNASRAPI void CTTransformerUninit(FUNASR_HANDLE handle); //OfflineStream _FUNASRAPI FUNASR_HANDLE FunOfflineInit(std::map& model_path, int thread_num); -_FUNASRAPI FUNASR_RESULT FunOfflineRecogFile(FUNASR_HANDLE handle, const char* sz_wavfile, FUNASR_MODE mode, QM_CALLBACK fn_callback); -_FUNASRAPI FUNASR_RESULT FunOfflineRecogPCMBuffer(FUNASR_HANDLE handle, const char* sz_buf, int n_len, int sampling_rate, FUNASR_MODE mode, QM_CALLBACK fn_callback); +// buffer +_FUNASRAPI FUNASR_RESULT FunOfflineInferBuffer(FUNASR_HANDLE handle, const char* sz_buf, int n_len, FUNASR_MODE mode, QM_CALLBACK fn_callback, int sampling_rate=16000); +// file, support wav & pcm +_FUNASRAPI FUNASR_RESULT FunOfflineInfer(FUNASR_HANDLE handle, const char* sz_filename, FUNASR_MODE mode, QM_CALLBACK fn_callback, int sampling_rate=16000); _FUNASRAPI void FunOfflineUninit(FUNASR_HANDLE handle); #ifdef __cplusplus diff --git a/funasr/runtime/onnxruntime/src/funasrruntime.cpp b/funasr/runtime/onnxruntime/src/funasrruntime.cpp index 893ba70d7..adef5049e 100644 --- a/funasr/runtime/onnxruntime/src/funasrruntime.cpp +++ b/funasr/runtime/onnxruntime/src/funasrruntime.cpp @@ -11,9 +11,9 @@ extern "C" { return mm; } - _FUNASRAPI FUNASR_HANDLE FsmnVadInit(std::map& model_path, int thread_num) + _FUNASRAPI FUNASR_HANDLE FsmnVadInit(std::map& model_path, int thread_num, FSMN_VAD_MODE mode) { - funasr::VadModel* mm = funasr::CreateVadModel(model_path, thread_num); + funasr::VadModel* mm = funasr::CreateVadModel(model_path, thread_num, mode); return mm; } @@ -30,36 +30,7 @@ extern "C" { } // APIs for ASR Infer - _FUNASRAPI FUNASR_RESULT FunASRRecogBuffer(FUNASR_HANDLE handle, const char* sz_buf, int n_len, FUNASR_MODE mode, QM_CALLBACK fn_callback) - { - funasr::Model* recog_obj = (funasr::Model*)handle; - if (!recog_obj) - return nullptr; - - int32_t sampling_rate = -1; - funasr::Audio audio(1); - if (!audio.LoadWav(sz_buf, n_len, &sampling_rate)) - return nullptr; - - float* buff; - int len; - int flag=0; - funasr::FUNASR_RECOG_RESULT* p_result = new funasr::FUNASR_RECOG_RESULT; - p_result->snippet_time = audio.GetTimeLen(); - int n_step = 0; - int n_total = audio.GetQueueSize(); - while (audio.Fetch(buff, len, flag) > 0) { - string msg = recog_obj->Forward(buff, len, flag); - p_result->msg += msg; - n_step++; - if (fn_callback) - fn_callback(n_step, n_total); - } - - return p_result; - } - - _FUNASRAPI FUNASR_RESULT FunASRRecogPCMBuffer(FUNASR_HANDLE handle, const char* sz_buf, int n_len, int sampling_rate, FUNASR_MODE mode, QM_CALLBACK fn_callback) + _FUNASRAPI FUNASR_RESULT FunASRInferBuffer(FUNASR_HANDLE handle, const char* sz_buf, int n_len, FUNASR_MODE mode, QM_CALLBACK fn_callback, int sampling_rate) { funasr::Model* recog_obj = (funasr::Model*)handle; if (!recog_obj) @@ -87,23 +58,32 @@ extern "C" { return p_result; } - _FUNASRAPI FUNASR_RESULT FunASRRecogPCMFile(FUNASR_HANDLE handle, const char* sz_filename, int sampling_rate, FUNASR_MODE mode, QM_CALLBACK fn_callback) + _FUNASRAPI FUNASR_RESULT FunASRInfer(FUNASR_HANDLE handle, const char* sz_filename, FUNASR_MODE mode, QM_CALLBACK fn_callback, int sampling_rate) { funasr::Model* recog_obj = (funasr::Model*)handle; if (!recog_obj) return nullptr; funasr::Audio audio(1); - if (!audio.LoadPcmwav(sz_filename, &sampling_rate)) - return nullptr; + if(funasr::is_target_file(sz_filename, "wav")){ + int32_t sampling_rate_ = -1; + if(!audio.LoadWav(sz_filename, &sampling_rate_)) + return nullptr; + }else if(funasr::is_target_file(sz_filename, "pcm")){ + if (!audio.LoadPcmwav(sz_filename, &sampling_rate)) + return nullptr; + }else{ + LOG(ERROR)<<"Wrong wav extension"; + exit(-1); + } float* buff; int len; int flag = 0; - funasr::FUNASR_RECOG_RESULT* p_result = new funasr::FUNASR_RECOG_RESULT; - p_result->snippet_time = audio.GetTimeLen(); int n_step = 0; int n_total = audio.GetQueueSize(); + funasr::FUNASR_RECOG_RESULT* p_result = new funasr::FUNASR_RECOG_RESULT; + p_result->snippet_time = audio.GetTimeLen(); while (audio.Fetch(buff, len, flag) > 0) { string msg = recog_obj->Forward(buff, len, flag); p_result->msg += msg; @@ -115,45 +95,15 @@ extern "C" { return p_result; } - _FUNASRAPI FUNASR_RESULT FunASRRecogFile(FUNASR_HANDLE handle, const char* sz_wavfile, FUNASR_MODE mode, QM_CALLBACK fn_callback) - { - funasr::Model* recog_obj = (funasr::Model*)handle; - if (!recog_obj) - return nullptr; - - int32_t sampling_rate = -1; - funasr::Audio audio(1); - if(!audio.LoadWav(sz_wavfile, &sampling_rate)) - return nullptr; - - float* buff; - int len; - int flag = 0; - int n_step = 0; - int n_total = audio.GetQueueSize(); - funasr::FUNASR_RECOG_RESULT* p_result = new funasr::FUNASR_RECOG_RESULT; - p_result->snippet_time = audio.GetTimeLen(); - while (audio.Fetch(buff, len, flag) > 0) { - string msg = recog_obj->Forward(buff, len, flag); - p_result->msg+= msg; - n_step++; - if (fn_callback) - fn_callback(n_step, n_total); - } - - return p_result; - } - // APIs for VAD Infer - _FUNASRAPI FUNASR_RESULT FsmnVadWavFile(FUNASR_HANDLE handle, const char* sz_wavfile, FUNASR_MODE mode, QM_CALLBACK fn_callback) + _FUNASRAPI FUNASR_RESULT FsmnVadInferBuffer(FUNASR_HANDLE handle, const char* sz_buf, int n_len, FSMN_VAD_MODE mode, QM_CALLBACK fn_callback, int sampling_rate) { funasr::VadModel* vad_obj = (funasr::VadModel*)handle; if (!vad_obj) return nullptr; - - int32_t sampling_rate = -1; + funasr::Audio audio(1); - if(!audio.LoadWav(sz_wavfile, &sampling_rate)) + if (!audio.LoadPcmwav(sz_buf, n_len, &sampling_rate)) return nullptr; funasr::FUNASR_VAD_RESULT* p_result = new funasr::FUNASR_VAD_RESULT; @@ -166,6 +116,35 @@ extern "C" { return p_result; } + _FUNASRAPI FUNASR_RESULT FsmnVadInfer(FUNASR_HANDLE handle, const char* sz_filename, FSMN_VAD_MODE mode, QM_CALLBACK fn_callback, int sampling_rate) + { + funasr::VadModel* vad_obj = (funasr::VadModel*)handle; + if (!vad_obj) + return nullptr; + + funasr::Audio audio(1); + if(funasr::is_target_file(sz_filename, "wav")){ + int32_t sampling_rate_ = -1; + if(!audio.LoadWav(sz_filename, &sampling_rate_)) + return nullptr; + }else if(funasr::is_target_file(sz_filename, "pcm")){ + if (!audio.LoadPcmwav(sz_filename, &sampling_rate)) + return nullptr; + }else{ + LOG(ERROR)<<"Wrong wav extension"; + exit(-1); + } + + funasr::FUNASR_VAD_RESULT* p_result = new funasr::FUNASR_VAD_RESULT; + p_result->snippet_time = audio.GetTimeLen(); + + vector> vad_segments; + audio.Split(vad_obj, vad_segments); + p_result->segments = new vector>(vad_segments); + + return p_result; + } + // APIs for PUNC Infer _FUNASRAPI const std::string CTTransformerInfer(FUNASR_HANDLE handle, const char* sz_sentence, FUNASR_MODE mode, QM_CALLBACK fn_callback) { @@ -178,43 +157,7 @@ extern "C" { } // APIs for Offline-stream Infer - _FUNASRAPI FUNASR_RESULT FunOfflineRecogFile(FUNASR_HANDLE handle, const char* sz_wavfile, FUNASR_MODE mode, QM_CALLBACK fn_callback) - { - funasr::OfflineStream* offline_stream = (funasr::OfflineStream*)handle; - if (!offline_stream) - return nullptr; - - int32_t sampling_rate = -1; - funasr::Audio audio(1); - if(!audio.LoadWav(sz_wavfile, &sampling_rate)) - return nullptr; - if(offline_stream->UseVad()){ - audio.Split(offline_stream); - } - - float* buff; - int len; - int flag = 0; - int n_step = 0; - int n_total = audio.GetQueueSize(); - funasr::FUNASR_RECOG_RESULT* p_result = new funasr::FUNASR_RECOG_RESULT; - p_result->snippet_time = audio.GetTimeLen(); - while (audio.Fetch(buff, len, flag) > 0) { - string msg = (offline_stream->asr_handle)->Forward(buff, len, flag); - p_result->msg+= msg; - n_step++; - if (fn_callback) - fn_callback(n_step, n_total); - } - if(offline_stream->UsePunc()){ - string punc_res = (offline_stream->punc_handle)->AddPunc((p_result->msg).c_str()); - p_result->msg = punc_res; - } - - return p_result; - } - - _FUNASRAPI FUNASR_RESULT FunOfflineRecogPCMBuffer(FUNASR_HANDLE handle, const char* sz_buf, int n_len, int sampling_rate, FUNASR_MODE mode, QM_CALLBACK fn_callback) + _FUNASRAPI FUNASR_RESULT FunOfflineInferBuffer(FUNASR_HANDLE handle, const char* sz_buf, int n_len, FUNASR_MODE mode, QM_CALLBACK fn_callback, int sampling_rate) { funasr::OfflineStream* offline_stream = (funasr::OfflineStream*)handle; if (!offline_stream) @@ -249,6 +192,50 @@ extern "C" { return p_result; } + _FUNASRAPI FUNASR_RESULT FunOfflineInfer(FUNASR_HANDLE handle, const char* sz_filename, FUNASR_MODE mode, QM_CALLBACK fn_callback, int sampling_rate) + { + funasr::OfflineStream* offline_stream = (funasr::OfflineStream*)handle; + if (!offline_stream) + return nullptr; + + funasr::Audio audio(1); + if(funasr::is_target_file(sz_filename, "wav")){ + int32_t sampling_rate_ = -1; + if(!audio.LoadWav(sz_filename, &sampling_rate_)) + return nullptr; + }else if(funasr::is_target_file(sz_filename, "pcm")){ + if (!audio.LoadPcmwav(sz_filename, &sampling_rate)) + return nullptr; + }else{ + LOG(ERROR)<<"Wrong wav extension"; + exit(-1); + } + if(offline_stream->UseVad()){ + audio.Split(offline_stream); + } + + float* buff; + int len; + int flag = 0; + int n_step = 0; + int n_total = audio.GetQueueSize(); + funasr::FUNASR_RECOG_RESULT* p_result = new funasr::FUNASR_RECOG_RESULT; + p_result->snippet_time = audio.GetTimeLen(); + while (audio.Fetch(buff, len, flag) > 0) { + string msg = (offline_stream->asr_handle)->Forward(buff, len, flag); + p_result->msg+= msg; + n_step++; + if (fn_callback) + fn_callback(n_step, n_total); + } + if(offline_stream->UsePunc()){ + string punc_res = (offline_stream->punc_handle)->AddPunc((p_result->msg).c_str()); + p_result->msg = punc_res; + } + + return p_result; + } + _FUNASRAPI const int FunASRGetRetNumber(FUNASR_RESULT result) { if (!result) From 1a6334f9dc0eee12c3c6fc9df4dc396e36df0647 Mon Sep 17 00:00:00 2001 From: yhliang <429259365@qq.com> Date: Wed, 10 May 2023 16:54:45 +0800 Subject: [PATCH 110/120] update m2met docs --- README.md | 2 +- docs/m2met2/Baseline.md | 24 +++++++++++-- docs/m2met2/Introduction.md | 6 ++-- docs/m2met2/_build/doctrees/Baseline.doctree | Bin 6269 -> 10742 bytes .../_build/doctrees/Introduction.doctree | Bin 15882 -> 16483 bytes .../m2met2/_build/doctrees/environment.pickle | Bin 25957 -> 26555 bytes docs/m2met2/_build/html/.buildinfo | 2 +- docs/m2met2/_build/html/Baseline.html | 32 ++++++++++++++---- docs/m2met2/_build/html/Contact.html | 8 ++--- docs/m2met2/_build/html/Dataset.html | 8 ++--- docs/m2met2/_build/html/Introduction.html | 14 ++++---- docs/m2met2/_build/html/Organizers.html | 8 ++--- docs/m2met2/_build/html/Rules.html | 8 ++--- .../html/Track_setting_and_evaluation.html | 8 ++--- docs/m2met2/_build/html/_images/qrcode.png | Bin 144841 -> 187682 bytes .../_build/html/_sources/Baseline.md.txt | 24 +++++++++++-- .../_build/html/_sources/Introduction.md.txt | 6 ++-- docs/m2met2/_build/html/genindex.html | 8 ++--- docs/m2met2/_build/html/index.html | 8 ++--- docs/m2met2/_build/html/objects.inv | 2 +- docs/m2met2/_build/html/search.html | 8 ++--- docs/m2met2/_build/html/searchindex.js | 2 +- docs/m2met2/conf.py | 2 +- docs/m2met2/images/qrcode.png | Bin 144841 -> 187682 bytes .../_build/doctrees/environment.pickle | Bin 25329 -> 25501 bytes docs/m2met2_cn/_build/doctrees/基线.doctree | Bin 6474 -> 10367 bytes docs/m2met2_cn/_build/doctrees/简介.doctree | Bin 13586 -> 14440 bytes docs/m2met2_cn/_build/html/.buildinfo | 2 +- docs/m2met2_cn/_build/html/_images/qrcode.png | Bin 144841 -> 187682 bytes .../_build/html/_sources/基线.md.txt | 23 +++++++++++-- .../_build/html/_sources/简介.md.txt | 19 ++++++----- docs/m2met2_cn/_build/html/genindex.html | 8 ++--- docs/m2met2_cn/_build/html/index.html | 8 ++--- docs/m2met2_cn/_build/html/objects.inv | Bin 509 -> 539 bytes docs/m2met2_cn/_build/html/search.html | 8 ++--- docs/m2met2_cn/_build/html/searchindex.js | 2 +- docs/m2met2_cn/_build/html/基线.html | 30 +++++++++++++--- docs/m2met2_cn/_build/html/数据集.html | 8 ++--- docs/m2met2_cn/_build/html/简介.html | 26 +++++++------- docs/m2met2_cn/_build/html/组委会.html | 8 ++--- docs/m2met2_cn/_build/html/联系方式.html | 8 ++--- docs/m2met2_cn/_build/html/规则.html | 8 ++--- .../m2met2_cn/_build/html/赛道设置与评估.html | 8 ++--- docs/m2met2_cn/conf.py | 2 +- docs/m2met2_cn/images/qrcode.png | Bin 144841 -> 187682 bytes docs/m2met2_cn/基线.md | 23 +++++++++++-- docs/m2met2_cn/简介.md | 19 ++++++----- 47 files changed, 255 insertions(+), 135 deletions(-) diff --git a/README.md b/README.md index 64d6d894a..f0cbfa87f 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ ## What's new: ### Multi-Channel Multi-Party Meeting Transcription 2.0 (M2MET2.0) Challenge -We are pleased to announce that the M2MeT2.0 challenge will be held in the near future. The baseline system is conducted on FunASR and is provided as a receipe of AliMeeting corpus. For more details you can see the guidence of M2MET2.0 ([CN](https://alibaba-damo-academy.github.io/FunASR/m2met2_cn/index.html)/[EN](https://alibaba-damo-academy.github.io/FunASR/m2met2/index.html)). +We are pleased to announce that the M2MeT2.0 challenge has been accepted by the ASRU2023 challenge special session. The registration is now open. The baseline system is conducted on FunASR and is provided as a receipe of AliMeeting corpus. For more details you can see the guidence of M2MET2.0 ([CN](https://alibaba-damo-academy.github.io/FunASR/m2met2_cn/index.html)/[EN](https://alibaba-damo-academy.github.io/FunASR/m2met2/index.html)). ### Release notes For the release notes, please ref to [news](https://github.com/alibaba-damo-academy/FunASR/releases) diff --git a/docs/m2met2/Baseline.md b/docs/m2met2/Baseline.md index 6f9609bde..a7820863f 100644 --- a/docs/m2met2/Baseline.md +++ b/docs/m2met2/Baseline.md @@ -1,11 +1,31 @@ # Baseline ## Overview -We will release an E2E SA-ASR~\cite{kanda21b_interspeech} baseline conducted on [FunASR](https://github.com/alibaba-damo-academy/FunASR) at the time according to the timeline. The model architecture is shown in Figure 3. The SpeakerEncoder is initialized with a pre-trained speaker verification model from ModelScope. This speaker verification model is also be used to extract the speaker embedding in the speaker profile. +We will release an E2E SA-ASR baseline conducted on [FunASR](https://github.com/alibaba-damo-academy/FunASR) at the time according to the timeline. The model architecture is shown in Figure 3. The SpeakerEncoder is initialized with a pre-trained speaker verification model from ModelScope. This speaker verification model is also be used to extract the speaker embedding in the speaker profile. ![model archietecture](images/sa_asr_arch.png) ## Quick start -#TODO: fill with the README.md of the baseline +To run the baseline, first you need to install FunASR and ModelScope. ([installation](https://alibaba-damo-academy.github.io/FunASR/en/installation.html)) +There are two startup scripts, `run.sh` for training and evaluating on the old eval and test sets, and `run_m2met_2023_infer.sh` for inference on the new test set of the Multi-Channel Multi-Party Meeting Transcription 2.0 ([M2MET2.0](https://alibaba-damo-academy.github.io/FunASR/m2met2/index.html)) Challenge. +Before running `run.sh`, you must manually download and unpack the [AliMeeting](http://www.openslr.org/119/) corpus and place it in the `./dataset` directory: +```shell +dataset +|—— Eval_Ali_far +|—— Eval_Ali_near +|—— Test_Ali_far +|—— Test_Ali_near +|—— Train_Ali_far +|—— Train_Ali_near +Before running `run_m2met_2023_infer.sh`, you need to place the new test set `Test_2023_Ali_far` (to be released after the challenge starts) in the `./dataset` directory, which contains only raw audios. Then put the given `wav.scp`, `wav_raw.scp`, `segments`, `utt2spk` and `spk2utt` in the `./data/Test_2023_Ali_far` directory. +```shell +data/Test_2023_Ali_far +|—— wav.scp +|—— wav_raw.scp +|—— segments +|—— utt2spk +|—— spk2utt +``` +For more details you can see [here](https://github.com/alibaba-damo-academy/FunASR/blob/main/egs/alimeeting/sa-asr/README.md) ## Baseline results The results of the baseline system are shown in Table 3. The speaker profile adopts the oracle speaker embedding during training. However, due to the lack of oracle speaker label during evaluation, the speaker profile provided by an additional spectral clustering is used. Meanwhile, the results of using the oracle speaker profile on Eval and Test Set are also provided to show the impact of speaker profile accuracy. diff --git a/docs/m2met2/Introduction.md b/docs/m2met2/Introduction.md index 99a426f2a..a00122a47 100644 --- a/docs/m2met2/Introduction.md +++ b/docs/m2met2/Introduction.md @@ -13,15 +13,15 @@ Building on the success of the previous M2MeT challenge, we are excited to propo - $ May~8, 2023: $ Baseline release. - $ May~15, 2023: $ Registration deadline, the due date for participants to join the Challenge. - $ June~9, 2023: $ Test data release and leaderboard open. -- $ June~13, 2023: $ Final submission deadline. +- $ June~13, 2023: $ Final submission deadline and leaderboar close. - $ June~19, 2023: $ Evaluation result and ranking release. - $ July~3, 2023: $ Deadline for paper submission. - $ July~10, 2023: $ Deadline for final paper submission. -- $ December~12\ to\ 16, 2023: $ ASRU Workshop and challenge session +- $ December~12\ to\ 16, 2023: $ ASRU Workshop and challenge Session ## Guidelines -Interested participants, whether from academia or industry, must register for the challenge by completing the Google form below. The deadline for registration is May 15, 2023. +Interested participants, whether from academia or industry, must register for the challenge by completing the Google form below. The deadline for registration is May 22, 2023. Participants are also welcome to join the [wechat group](https://alibaba-damo-academy.github.io/FunASR/m2met2/Contact.html) of M2MET2.0 and keep up to date with the latest updates about the challenge. [M2MET2.0 Registration](https://docs.google.com/forms/d/e/1FAIpQLSf77T9vAl7Ym-u5g8gXu18SBofoWRaFShBo26Ym0-HDxHW9PQ/viewform?usp=sf_link) diff --git a/docs/m2met2/_build/doctrees/Baseline.doctree b/docs/m2met2/_build/doctrees/Baseline.doctree index 9fc7c50bc88215e9cb639dc6b29bd9deb676a116..b2577644c72e0b0b77edb5dc4fde8da57df41554 100644 GIT binary patch literal 10742 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 SzVqtfe{U^L32? delta 534 zcmews{MUfBfn{ou#70&zCdOrxWtbFX>SB^JOH!+|6Z29MjSQ3GGxJJPi;4?UQsZ%o8W2a<@k*aO-L_vwkZv~|$^Gb0ra!eMJ+RK!&b@D?& zwaNdaI5@d7WHWR!q%$^c7Lv|qX397WmH{f|(>RdF_;p%8dKPr5V~8 z85wfkyif%fGh{NDCkyh(fNbD|iEf&_Lq3&}YqOj}H4~Ez&54Pc&NHUzR; zr!-Ch8Y-O?#W-0&U3~I7H94jT#>wZ@WSJrvC%;uwWXb|bn1cj8)lHbf87J4Pi!)_1 zPM)Ez;gs<;<5Na!MpMSRjMW)$GG3PUaONfErj}F|q!t5>)yVkTnbF#rv92@YO=oF_ zB1q&@1`klZE>L|}#!H}|H8m0#*)o23GiH36JXKRcCS#*Fd&cS>?!eN_6 z!nrrXXbg}YG8=;rU_eEFPk+CsR=bxH6SGz7F)PX z5QWu-Y1K=EgwlF5BS}bC6{MhK1=Y+XDszgpJ7QI(#8O1nlrC7tSpKS1lWUmD(u8SH zRHh}7(3&2H<}H|$bLX$gV#-rEgK-^Nbr-gRD26RQ#>3Wm)TF%Rra4c=w5V6$jC36v zRV>#kBakxK| zTNC!Pb~4UBiQVn7|FOz*%C^V}ZJ$diG8HBRB(aU5rEn6te^_~T2VQQ;=<&0qqbatO zd?jch&VbE`lOXMC6SSBce->}=-K5sPNlo%Ibo>}wi*`BBq^|)m$*-Suob(qzcJg?-CJ!3Ul_%`=y>!{9AzXT#tJ6^TpRXP?q%pZB9F-Yb}((5AkwSp5p nqk`R4-ZKR>#MtQd$PG8>)e3xD?7nEJ6|AcUZrTrRi+}K6AUZi} delta 415 zcmaFdz}Qv8+Q2gPzwJg=TV+Pw$C16pBleax;sIGxPHlQc@FB zax(KaJE|nGG8Ru>qfhwip^gv9y3dt7{TmgHU+X+Ib#t{{CL>1(P>(lbmfz$z_K|YlAdVQ=@E$Jr(#(`pU0NbL*v%7OQGq*dl zoCkSFSwajX5-;e)jJ19yLF^cTVHh!j7*Jv)28Ykasz2lL~2LbNxbahwvR8?11S6BD__RdfJ<jf(_PH@$W!l3R1NmGqJ zpL(_Gi9*pE&BGsWzS5jhJM2cIxuE*1VI_$ir|Lyb_1@Wfkj$>SHO~%~X0L_Oa@?>h z&g{uFn7epk7FFZf`jNVm9GSJsgqez{b=*|laa3U>hi@AR8dbtz(OYV&Aw7EY+L;9t4`r5 zxK7<^I;y7;g}ze(eP++TaOTqK>GN|JE`6wU_QZ)xrx#9@E?t;gxOnWs>GPLPpIay$ z`@r0pGba{KohTidd8(=UDq&+a@|Ik*zHsEJBTqkBy4Y}>id#Bkm!B-n)x5G@wo9j? zFl{_rn!9-By!?K$v=By#d(DXxCkjgE!`fV4@bz2a zO{-p*^=t=K^d2mw_L5UNAB7bsj=f;%4m+M?(m8=$2F2EswG!6Cz*=;Iiqlj*RcEp0 z#h?JBr&hD0x}CUqaFcq?^6D4`h`gK8xsF}MP%JyB;HBc`e3zPFK-#F3ZS`7M9^!xD-w&c-I-K(^SK;V@DOY9IlvxrCM0FYe`s<0w-1@ zjE+Sq8|ax9k;e?2#s7GAF%9fEnuSQrHdevZ;OUw7%!13#G-lN@$P~|RB%rpYq=>6K zsYc}u5_+T>(0lVzFJOwgUbX53%^Rs2 zb{c8fs>HFi=+!XQz=UB&-clqK^$V4T;xLUWm}u$ZqPNmi1Joa87!O4aoQtYX2fWsETjDyNHWb9v`d|%RRaJl8CUs`P3P2}&LDgB&sCua%E_YXWRPG7)vMR#Om>=#l}(G10BCOt!&7qsYrakG6xX*aejYKgnJ-tlOSp(!*$7hs1_S5JJyI z&LU<2v?pv4ENXL2Ml#4KMB~S%aJaF$MCLoj3}5BfVsRRGVRdR`c{0w5DkcJGvXA9; zaz(&hxo>wL7qJ{MO4TaEo*Im;5^`d%y7$Tc+j$jHC%)VR45u}LXjT=N#m%LL4b`%@CqOR4A$+SLF(2@Bg|33&>MJ3!>cT>HrKe) zuzt3@rGN~_Wof&+wHSf&q9SV zW)5bWX+6f}&J_^RXgWRA0n-8#+t8*zsl^r)jJLRIiUz2t0_lp9*t}(b3P;GoyTcna z*kaH$xspOGGfIya$}F2F4ixc~<4{#h?%hSWw!>sfr&OQOB&>?Md>i(tmwiJxG@uh4 zO;8{Dk(IlX3ciO$IxU!d*N(jyM!klCyI~E6B9px#wnk-WOwnFX6udR zDd<$@JYz6=_|(x}?JV!4a#3MiLz~*4yFaH^<9V4?m_`ii7nqk|V!HdJ{s5P0zYTVR zE6U&vb(-$76pMvL?{J`8_^773w!E25fe~ReBa9o)OOSYr9yzr=X|NoSVJvnYSJ=08 z|3?aYxmD^_ng*x#c<{Il+UWhFt4ESXNvtpxrlq2Nyu&`W02xq(2iM1jgGr*JPb$QZY| z7J1}JkZFOf?T5qbT}NfRCLOx(aVJ?by6-G0xNt01>bZiP-_EL}RD$|U z$z-sZ*6LS#jTl8@CHE4s`1viisgH+G?liOvEB`?*S+uWupqDOm=iKMzy^p!a<;OGb zd!@d()zICMZCqRd>=D#(G%Q&&z_zo4MBTX4?o6>73_Dm526hcdpzxuh1U$i5#EuZV zJ*<%+b39amkx$TY;9x>RmLV&<^@`N!GQA?0Ah(-VNRiWsw68!u?Z~|kvvmNWFApg9nKfDV$#}?-l77&(PBz~R zIFn*j5M!@fih$8%gwSMsmX{CHq>+*fXFSYZ>|yHHljRb87Ins+st37lj$Xw+wQ-J?&>I`O+_!Hem7y*6E;v7xdi8oNAL z<`=Cg(`49mr4=*z3tcZxVYTz(;ie~7+%6EI~83oeuOGrHkC3&5D4;;G($|= zBXChSDt~%?xmf{e>3|fbeNW-ne`Wig!Z3&;mn!R!ra*trT3pWJ9qlb(YfQtFPyk|@wuk-yeDre z;UGj%>^hX$nYo2iFU%o`_5L$wj@G=HFj_Kg1}W&Wg2}Q(rcw1as&K+lqFtyF0UHa$ zKApRwX6jgVcnD-f$!gtk$nNn-jnS;QaBYFpIr7vDA?qO2_Mih`-EdS>80!QJY4#rb z<<+%WlRRt zaCs}sR<>M|76(Xi3dA_0MbT}m#GwvoU4);!2xQOu7|t<~YfsaY``(|IN6r-lixP{X zoV0E+1RN_?kuU<5f!w+PO1!!QOJ!JGfKcR}@XhaPYh(hcHw3aT?@2>)f~c;S9y6kR zFs~O;+_mP_;ZT?noH`nPi&sX1v=0+O`%h5FnCws7{$y{er|#5yCCVPO=eK9`ZixEN zrCCesLsVL~m*IEF^q>G3euZ!rbd?DTd)FNCDNMlEc!*d!h_}x`D^ZAWPZqHv=SV~s6%s>y=ywRH>UrYV zr(b>BJ3gvS*AQ0;oNGiFfOn<=0zzWeCKyI;cIIDY@dp|iqt;=O7Qai@uPfMFK!7R1 z9*MT4BNfZ5TG$NW)fl>i9C6)oiju?C*$6gTp}h?(GM1fHOtUHrf$D+Rzl2~tUWk8% zix_)346!HBL#{xLELb0HZFm7Wr>d7?LSok zMj9?-32r74H4^~K67BC9*nR}-y@rKIZD3Q#-YR1w1JU8wHE;Bo>~vUU;?>?wsU zs#dbvFu_*+?t38qn5#~$0T(H#>R4=3-AR;3^<_vnnlq6-8l3RT7W~tgu;j+=&cRjZ zD#h~1l~cQ%U>XxNtF|w%rblKXNNW2#^J>F+HCg0l2nziymm#$XHPde6I|`a{i}=-a z-py#<4UlmJbEA$Tr%r+9R`}k$twd^#`B=+P?9Z#zy#W4VRJX`+gT>1USDBY6)x4)Lx6A#N+c@c~FlPLTsSLR$WiG(rKF7PV|%&~_u#aE*KkR;)w3 zO}(^OZzPkQ{G_Fv`7*5{jNz_c3p>6aP(@qp~v|VFAG5TyiL} zQ%dV^WNPfKar#b&!X+O^3I4xsuH^KC!{1Ag%cmx=%9Q(oKYOC!p zi7Qt0-$;0wP z!}k^7)ezeS6s0Dw%8-5IGzxipVTp;Y@Y0FAv8Ui=9icD`EE462e9Y7+K7ULH&)`7W zniefW&uc4WNC2VClr$}?AqlT=N&+nD{B||bQX)PV^oZ)l0vB7G;QwBvTS&@M<}vr2 z*NHhM?Z@qP`)KD_^+FBFR_!M+CHl`rOLpL0XU6p$qZm8c*MpZLxFc{c6Ar^8Eyi+a zKVKp?W`kM{o<;zlO)^{mp5t}`y@d9=E?`F(bn1N`&rIu^Y1u8)BplU4)l+MxLYXZ4 z))%_it;a@lLIl{m9_Z=lJYXhQE5n9Vtohz7u~w@Ra>?vIH6`8l(vK14Z#Jc8HebbgS}EL8)!Ein`WTzn%YxA ztz~Q=LKj+CRL~YRcy~h$Hn59LhK5}sg#fceFHs!N2ni_qHH*v^s##d(EU3X~u~KOJ zxM_=2B^zso3Kr!vo|7yx0!ZX6DK5f9?OHGmdqGPC+I>|Gqk*W<6-s0wqR~PYdZ@K@ z%q(vqgNqUeUc+V*vXJ1HAv%PpfSP0r>>)NEk#0lqjvR_AUVoyvQ)?1KXkp~;aBr@u zA+sR~?qQS4T~>qKz%u*6sp=&Ig|RZD{C|e)d}{8k$sat@_|q=```J^pve$nrdy2pN z75|^Ir?l@Q{`az{tKWA0A7)S2-gwjhLH4xrH^1=zF?+iH%@3psDIFABL+qZiFWi%A zK<9WM+(y|$vb&54j)}U1=Gq(0-)$nJh(}7wVUmR?o{eo-JM4WUp=+i=X(kV800{@p zZg4C{5R-v7`PHcTn67mtA_{3By(s|=3K9tPtyj^IE5g55x76WKz3r*7&25mlPdWl+(rC;TVW!=r!yi#g{)6l=ADqPy5(c zJ?9$fr~E4yZ>*0zkxG~%&4ONPm#mQHzo~k}F(I3nrYvND`%i)%(20mGi0Q(sX1`Tt&|YuG z{&QS&%0G(l`4NAPzP14qNo0;`3IK~aT*HEqg0=1<`d|6 z3#i&}2ul$z)3U@Zf%kw!lL#x;`&#~|vBlLOXJF^8;p)I~jztmXxte!YHWNy^HL%kj z%QU=uJ<#3j3e?~!Cn*7LhLg4s?d;Jmq1p~mjdWCzYJ*vazOOKaM z#BKw*o2#~+tTXB)+k6?K?bNoLQPBZwQ!B6)k|FihQIR6M=xf+$x`CmYx|22GIWd0ZNO~Umhe51ji z%h#9X>nrm0RsKr-zreTYm(=bS{pK3C*zw;2$=!5Jnrn-WTh}$k&cAz?os)*xqVwXC ztl0JU@3L#sBwKW?muAxE{8yF@fJh409Euti4LKZB%q1} z$c2RyXY|u;pK2*hojr2axrFmAhxJsJ$?~hadxcc>`It9eaLFO+_Ms{R;njLJM zeG*k(JoqFzym0V|n`{nzA}TK!d>UJdtkU8-MfB4^IYs7yB=%%lZJmN(Mb<~DKNd1y z>YG%XQX_f^jRmIGmSZMw2)fQ*itL8FNn;sIU$!dTtQza8^{Q0p|LD#;)fwcY)7cor z6mO_*^qodtlUGL2#e4*ZwW#}&)@l!<2kGk}{7O4fjQcVayBUQ)jIWKf@{~WZ3B=#O z8Q_u4075n6l(tCib7*sCn)WuSruq&U{~7KSTZNo{&!X46q~9~0q8LX*;o`d)#XTo< z%UY?Z?(!lZlcq}?*QS7gTF z`^Joehi(<0Y-7jcozgNF_(PqdxbN&}4VD(^f9Af?f9Oz41h|&OH(*dZDdM)WQ-7gxdy@xj0$Y`6KU$}eP{z<1O@@esTVb8rbP8)5j6dCZH`^JFrL+!gfZM6S( zr-aMp`dgi%xbL(t?oSnI{vY>^<^zWc+huLU{za#h%8C86PEo8Ub_XUTw?d-IIzW++ z;^j_XL|Y-=Ft}qY)ae>&v%QDMy6=s9Pj9o833>#5-K7tIpi>k%-}ZHiLi3GxTOJtS zHrTj1bB|a?FR~TOPIpSIe8QjX6h+RmW1XVVEaR=JJ7!tO@rbRqy{_FO2GVP7#lWOf z(&Y@i!YCf3+qX$ZLD2$!`hL+6Zr>)E4sF)(jk~Aq%}!C|ljHY=J@?w}+aM#ONdIr# zH~NnsYR?*JBmJA5(k&P3uXl>#wn^Wy0@);srAYrD-8cGA9@;qTri}-0bxOdT2R~pG z4^XxITAm+tx-@mtTXCu-q(X6$UkOR_lB|9BeJ#7Czq)Uhw1MLr7gLOMW^k0R()BawJ3_+W(kKrc{O7ShYP4#rkeZV*iu=zdO ze8x-e!llzrNB|#{{Df6P-bq4Mu2w{y{1`&F|zS z!1?W*0f;9G^y7cb~j$FmvME4|6>qObzhVx zbEJ}`3$r}-a0O+sG*?DW8|I>Ue%`^=zj)ro2kP+y$FGpBjZ0(bm;>glK8T5P_Fu-( z7jS$jzTgz=tf@Y$kTkA_aQSx_9Lv+labC1XF4-lEm}k7oDTy z*2CtS-1B((Iu5MjVh?>o`CNpvN(=svxap7ilWF1q1i#n(f59hm%74mVNb{kra{Zp} ziWz>Ub7_P$AJBr5Xz)eZ1o)!)fG?U4_@eoMFPabdBDIaY_*8Y_jy1yYGjs;Y?~z-L zbGq*2!=Qy4L%46%!nH-rPiafNuW{#V-1iOc`UdyB#vQM5zc;wswUjyLel17p_u^hv z!^s_Vm^6n8dw0-LQWUBIob_D_vpdSoxV!b)X{yqT%WCE1tA7x9aR$NsaR7a_gc`H3 ztTC5T|;x61D)IQ!L1&l3&^q*n0YT`U!JYQ-V8y#3fIxsApoLDDr5veu3Uu*h@ z@wEP}QA}gi1I80|q5FBQ$x?x{B)C3=ryow9$T>n#PbX3HEgEX{B(9F6EM)xAgDc17 zOefNXr~DC26VikvjyI8cz3%uXIvj1OF=3Jwi|05|Yh2f&*>qF&7tV14xJLtNj@?wF zZAUdxWp_)J2~x4^k9wlkBf1t%&zrafIXg%R*uEB6Z+5T~pod#P{e?4`06x?L?76Pb zdIGY)1=4pVI~WSs!4}wH%i&Le_qKrh3nxzjJkSa(93};@q=BS!ZmOZy^Pu23G3$dQ z1HVNd0e!qkALr@AqK{?zaOvYLeU$0r3VmFpj}Os@gO8gq2-TW6e*Os*sG;My;Fykq zld#0%@Tzg#r%U%Q>Ax|7^W7eFis~b^Y-vjf3y2Fa=vXBkQUX-|AP5TRR!Ak6HXwB$ z2d8JGa7L~cA3j@!qDL`2N2+Sfgc@nP9|RgIyA=cnzS{m^2I%5G>b}h_xsTn%aVve< zi@poQ|3gqyjnf%xnBV2%B_L`5m-iH}{_sD8x(ohi`SWx9`FZ+GTRy{@c#@L;FZyZz{R^f@OLfR|5V4ADJ$IDq2#V#zOBRmDj}QL@R|-ay20ff zP~|OGa`=Bm2!>Huyo8mtb@r_-oXvB*q^&!{_W6~s!c0k2I&P`nII1#|hhH%g6sm^7lDFJaBf9nGyZ1=} zWX&B2Z#Yrp)lk*#mO2nSNy^Q4Rud##)?MO*@Jm^k-^0y>+YZSc2S2 zT&Ll*9M#v1Lf@%^KE2YLmKvyr&9%r|c9D4bvq(z6Bi$D(x_Wr1FZn<4l+8|v1@3GWd~JsDsCbfu7_EoPVL3rxXDLrhjmC~0RozOsY7&;~Va2W|VO0{G zSdB3{mXNHW=i4M118WZdm|LS%#c0lOEd8!vMMP08}bAr~L zRE;{#v|?4`*jn=H7(rmdC?ju65{mkTOe1laMpcZTbZN<3ZK)xu4+DprqJ}O;H79av zr#uWL4AjeL+y2>z1ZX_MfQZs+k^)YgXsLa(jap0fH|%Jo7Tye6sTv8=1_r;i6q2N| zQtFEZJA~wlyp`SDXWed_pp0J?E@oQi!Zd?n!T2N4)CY7)JR&3Qlh`Ehc$#29FoK#G~C7*g%V{B^~rbK zvITxbh+vtr%*()rMpM(zMPZoSo_)^1Za)W_-`0pr%MM1?YGT>-dU(@Xf=*nslE@BX zj7w(ay6V$;sHID|SI8!B4VR3mdj)nDiQyZa`wgBnYAB zB4-IB0NN8K28Ob=E-e{m6r%BClQ`O3TPCXL}j8e5KFq6>Li;_OF;y6v~rX2-fO4gW(IBhmDNaGxGO;&h?5F^}jnjW;QVGSo?02PuZnNZ{&KoeL?bsKeSK8-d(Lpxf795H28 zPZNWMN8xY)PXq*FSEjYNNYXeiX%Jvz=x+l8z;MG3nxt;6G{P7a4E=$ZG`;G|T5Fv% zjp}d9TMo!@T$8c~+mpe_WeB+j_KIRMjGNMW3c3kzR?TU`jxFpJ`Y*Z{rQ$KNc@{EM zFmf=`Oz8nDf}A?eTS20 zu*INhay^AuW|W>Rq**o(94O-Jr=Y5s+y{$rZHLK}&Zq&SNmv#2_%`fOKf8QzXh0|U zkDxyEBP(|&6@0G|>9k<-T|4$-81*_D?uK<3icI!K*cw%!F)FTq zwPU-V(nT+E4sAbw;r@b3P3CD$n{-nvS&1q&RU>O+A7~_UV5+vS|M-FIT8mt6l?TVGhRrW*OUrJ&>mrA`_3n|PN zX?K-8-j>#wlC+Fmj!Dw3i=51;Ye8gu&5(wjw)PBgf75+jY809ozpE{i5>h}bYBAp@ zNQG>a47Xd4<1A|on+Xbks#rfXhWLyb+YfTP8n#ZiZhAEuM|-4{^oI2&Mlj%RAh6N`CQdp*|zqc$oq?B&cEQ zEpgjnUfD;XYTU9rTg(RA3W9}!T?Z2ATxbaaPcarz<-{Bh(-cSuH&tL{mYWWIJn(Y` zoIR-LdPbdSr+kV$Uz(&uPBYTxn%v5d>WZWv1w^`%gWP~T-D0|^p0E9lE-0>UQFgd- znmNt7muR6{msSga{6I^58q*!AiDgs()FA_$=4RySnbW*~Hi7?JBnUMHBPNh(3HgbI z2GMXdWi`j8K~&i$fY6s4l)J5(EJvh0jYZ{yhCo+h=)g?v1Xy`y_GCoV^ z!!&88?`qfswcscp!tiN;dJqa&ytMo@Ur<+NLmJUc^O7?r) zq|Z%AG&| zc-@-~qh(WOnBpF*7%aL1%|0S zPtr*5ar(5R7wli=Ffn{W;9|PObQ>xRX%M@6{ufDYa1q@M2{sj!83Q#@1*k)2Z7qbn zR3X1?fprOJH29R&6)T(MNQvX5>jYxFy`r>rWa0n;6eWT-UIen|b&Tei$akg@#dROe z(=>ms>=jsdk!Xta;4Oqn)>)<~zFT+1a+}De@xvyd5WHY1r0@%Snnq!m z24RZxfd6YqnR@VI;FQowr&Mr_OW{%}3w)1U@Zze2;9&r&$N4CqG?i>IsK*VgbBq|s z)PegrvaiGVi=|vMviLcp=6V2Y8j)}bNe>WMdoX(2#_O6 zk|5BptB)%wW|Azj+xEXLN|) z!X>o55{3wD_mMHJlbsl#_`Da8d#Cy-(1FM+rspFPOtzpd5I#W2Byl4QPm4o~u<+cZ z(W;INq6^lIM?iB&Lje$*ZXRCr}JVKnYYkKrL3D;X>a?;>B%o|P9 zYgV$>G!aAH_d^hWj6qb|#KB+sU+Ghq<5_pN!h(L9^X{W1iFdR8hBMFc@ zFsre-6bnHWFPL+^H1XP%zjbK`GVAYOk9RA;KJ>S*<5>N!q_39RV zWd>ZRTH|RtTQbZ^Dh>vdwqw%qB3u@8jG5yG7Qr=d*@JJa;YSMaT8LmV#VE{U~3DdK@ZIjCODzOY&a{vXB)x@<1V{KvjadJBcwpyBqr1GE^Z`k`B7 z_3cFriNTA}vK@H0m~nb3QT0ComBAEJ4_u94rQvlY9F4`62g{+gS_uWH1DCOw2YL*j zLmZcl8r#plCn;3R7Veat09n%7NGooI2I07FsvcUiRoa|zWOJg61z4;dCPaY4n}MDV z;sR!N)nwSPX=b563t^gMHVcI7=q6mgeZ!XEH1Cnv1SPIg`k_tf;-|D0_I1=xtLrGR zxmj^iqvT$}(^`0Est#%wf`Z)OutaaMPhhew9g#XLiedfNXd>*R=-1p3r8df;7C5td z8Bq1W!%-u=9|YbR?*oBDN+S-@90$u^aH45}6H6wb@47lvMXnXB2|*WHaItCC5j?%4 zhMQQJB_MAQAS8btw7p{ukvfrv&^Ht3=D)Cn_@gETKmTyY&s3D{Ty zrw5@6Oj*@5n^h07-iUM?fwhQv`r%*w(*JJu^`k>g|J&KukFQl z^r?^f|C)XM`{W<^-^#vz_TD-F8`;+{&TOO#tMnB3K`fXS)ZH^`NH5zX7DO9DWWf;Q z8UuJAjkT9rf7rq%5pF3dhiMj~crLbK?XaAQJvy^Z+BtAc14uYXPk>`F0!R$p;I2{e z37zYDL=@6M>L~#Y3K9s^t>=`GE5d(Rmux^nX?$Q;LqnG*YEb!cou$6&IkSG#K`B$; z&D6*KI3yO*Dyf@#I^U=+dMmEa{??_l7!{_WQjBm-=_Kgr;Fg<)f^AHvu7ts|wA9pj z%k_M2$Z~6gxk7C`sI#MoD{vN;mZT35486ai*7Eo7+q1{-!-Gh#Mi8N<`JY|CX|Kg_ zE3hF4#+-ZnbCdK_{-OFW znsj6ux}IXmzKqE#CaDX3?cZwXw+UJjC~}XRddngfuwsK-Bx3WU7N3&I_X4&84Ui{N z4O6U~Q>PBd^kd=oF<+B6CbLFpwgWY<%+%)ql#QqmM@o*~;Nk84As#-5X`*6X^IdP<7N0mf}68 zWQj`x?{SH(5LV27wfvW{WYQ#OVE@a*)$vmtnIX*cb?<_Vo{}yN>=d&v!@JiFJ-8`B z4WD(A65yseX&cclJl-Qz+Xt$Vjw(`Z*eiMf;6i)CCJzB^nZ}w=y$t=0U3pNwRS(lI zavngw?Lcb!Nt7v}OsTyL(2Y}gkaUq9I%RrqEexp%lUUAD)#O#3ac2JF=@NZB+(P+5 zUb`m*p!0Owry4v<>-qwNh_(~uwFRP(a>|LK24NkIa|MbNKieFy4(U9VODF030?Gps zJ6yn~-;4{^f#X|(gT@M3i5v$MGh5(tx!}nG;kcw05s`!T{6mZ`I48x1{C&3G&4i zY)#EbExLW5$I(aVI$CN#<=0TXxb=AJ$1afkgW_y(sVGmX`Vt%QHw+K|MW9YAtVsP0 zyvx3G|0TS-&-yL=pq-z>Pp(F#b^d3N=zkFpw9NlA{E~2e7QZO)Ir;g#{QQOde1U&b z|1a@t>LsPNptN`ar<>T{eN-;vJfB8LH^%5}hk3U3mKZ)pO-1pPFA>Jbhk& zU7Ejq_5Gy_r%zu!w|KU6_454Ul_xKsyL9#3#l;eGo!B=z zk+))~+m28xj1#+^y1eUyI14Kjh3W6mlDjd0DKNN`iTP@`^X3Eq`!lV>R9F~ zbcWhGbn35nPvQUT7DYZV{#TfEx1F??jqVkh@z6bE#seo_E=wm6 zXGeRmv`GJ_?iu|@PP9dEI|zQdTWaMR=80}mY$kXY4ngiyh@R^LMc#@ZbUTo>dEz+H z{WDM7$DBTLm&A!Ww3CUt-7WWX0lLK~?xTs?ZdIT-BtLtvXs8aK*k&Q4V{m?E_q6?V zw*K1MLsyzg*|uM?b~8UMv?wsy=U~FJkhypq=WQd>6UJ}Sbw=&6t9@{ zT`Q1ncCi%c|Gj%g|LGH3@4D&W!MD35V9tYYGK%}CTHcuN4?0(xIpeK5wGy^M@g~0# z_O{Dr?S~(0TP^+7J)`wQ1zLM$+}z^S@;!(7-ti97|IhA8|KHuB$i@G^gnM^e^Avdm zCSAl<=bd?UyzlP#u^l#5weiR+)Ab>*h(|}zqFs8shq^_vnMYkrbn>~94AL%8t}NH1{;@_diAJIe6<74#LpvTAYaOmdGRdaP7 zww2m)U6&ewxx>YNN&FZN5z!TL@$ZK+4vu6V^+fbDNQ<}+S$y(yh`!UphR*`JUS@@_U{ zJaEL|Aov4;x?gXQ@O_OxLv zn(rqZ+~$h!1AMF`i7{>k=UH%5c6N4>`q8I9GkAa19G?W3ilBr}VU~}WFFJ-tDXH3r zTOEif{@2k?|KC6h{~LH~r-T1(>V*Ft?#cl7`C@dDj$4nKn@=yH^9>wW#WffD(&_mK zXO$NH?{U%Z^OI@e{{Zjn{txlQp7I~@54QQxu5#T^chxjM)49|_8V@Kzn`rPuy9w|^ z;{iW39`Hls0Y5Yz@Iz`F`{Gm8gFCwj!%t8dB)?BCs?F)TpAUl;a*W^#O$&GGFh8X% z)xOS^uXEjZxavDx^Ey|&&h_5mYS&ZdnERz1slOk$Y8p=Nqr;>*OxU}Rj*=o#4dJZs za+qB^ZQ9+d&rVa8e%wDQCtv*|z>6~o<{Ec>Z-bh!Fs(874CBb~>KaVqjDHll)fkRp z7cL@p0P%m04$@u3ffHe4tU7Rx?;cKYXu*FC$}rr2ExkR6#|toX6&%p$H#gSeBw2H< zoPFV#!Et1p*;G~yU*JoEOWR|AV*z`wzNXJFBXK*FLs$4}y3!@wDuvs0I@>#2z}VJE z|4~M(rY`Ya;-$8>(SbE=2Zn`{6YIn+BDJRX^DX}&d~NPElBun_!T6#obUn|vSSoOq z1b1`r@WaUyIY$WU=}pvpmxUTXgR2N>7c%a#zkW*2bYi>kj6Z~7LYk1oaRWQAHyz(Z zg~M$*rp#u=;yF&_8r8XIG;OHC!Z}U=Cp3`8*oGSKII4*(<84`{NX2eG>WN%aIu{Mk z4P0!S9q0t?XdA3QJ9i1tu{O|P;Q%Ip(`~@MTl%CYAcxx^1J|=7pMV`{gAKQx{RH@6 z8+fpA%oM;w?ZCo$Qve^(K+-uIYNY)K6+fH#|P>0EIpR#agH7hdR(N3 zO^>JP;nSl=kMnqJz#!D>;`sUVNKhlEaJ?-Z11DjL#o<+xxJ{LABhr610Oz|s=oB?T zYT4435Ec*@V9>EjI-~@s{OJZH&@F>XE^WZpeH@&gmBd-OEqe4q4T>Jg@Ej?tF%xR6 z<9-lmsO(k{9Qf+^8wj9_`=I+e_w{aR1IMlOl`Hx#5dV)sO*KhptYLmvikE<>A>52p zy!yj`33(U&7C%41&ri}bm0p^|^^0n9%ga5~q__@z)Z1L?;r}@>z$>GBV~clr;7=8F z{`G|klUBI5L&@E-d|QYA1wuBp9~AD zO&0IWFjsD - Baseline — m2met2 documentation + Baseline — MULTI-PARTY MEETING TRANSCRIPTION CHALLENGE 2.0 @@ -44,7 +44,7 @@

    s#yDGd;bm#*lRi;V{W!{zx=hc? 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 XuJ2w+HtG8_(N5{C>Y21t#<%|$+at?n literal 0 HcmV?d00001 diff --git a/docs/m2met2/_build/html/_sources/Contact.md.txt b/docs/m2met2/_build/html/_sources/Contact.md.txt index 3097ad791..d0811c650 100644 --- a/docs/m2met2/_build/html/_sources/Contact.md.txt +++ b/docs/m2met2/_build/html/_sources/Contact.md.txt @@ -5,5 +5,5 @@ If you have any questions about M2MET2.0 challenge, please contact us by | Wechat group | |:------------------------------------------:| - +| | diff --git a/docs/m2met2/_build/html/_sources/Introduction.md.txt b/docs/m2met2/_build/html/_sources/Introduction.md.txt index eac9eb6b5..99a426f2a 100644 --- a/docs/m2met2/_build/html/_sources/Introduction.md.txt +++ b/docs/m2met2/_build/html/_sources/Introduction.md.txt @@ -25,4 +25,4 @@ Interested participants, whether from academia or industry, must register for th [M2MET2.0 Registration](https://docs.google.com/forms/d/e/1FAIpQLSf77T9vAl7Ym-u5g8gXu18SBofoWRaFShBo26Ym0-HDxHW9PQ/viewform?usp=sf_link) -Within three working days, the challenge organizer will send email invitations to eligible teams to participate in the challenge. All qualified teams are required to adhere to the challenge rules, which will be published on the challenge page. Prior to the ranking release time, each participant must submit a system description document detailing their approach and methods. The organizer will select the top three submissions to be included in the ASRU2023 Proceedings. +Within three working days, the challenge organizer will send email invitations to eligible teams to participate in the challenge. All qualified teams are required to adhere to the challenge rules, which will be published on the challenge page. Prior to the ranking release time, each participant must submit a system description document detailing their approach and methods. The organizer will select the top ranking submissions to be included in the ASRU2023 Proceedings. diff --git a/docs/m2met2/images/qrcode.png b/docs/m2met2/images/qrcode.png new file mode 100644 index 0000000000000000000000000000000000000000..68984beac9295fa662dbbf2d933bd8b7ad08405c GIT binary patch literal 144841 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