شعار زيفيرنت

نموذج محول الضبط الدقيق للتعرف على الفاتورة

التاريخ:

نموذج محول الضبط الدقيق للتعرف على الفاتورة

يقدم المؤلف دليلًا تفصيليًا من التعليق التوضيحي إلى التدريب.


By وليد عمو، مؤسس UBIAI

الشكل
التعرف على الفاتورة

المُقدّمة

 
بناء على تعليمي الأخير على كيفية إضافة تعليقات توضيحية إلى ملفات PDF والصور الممسوحة لتطبيقات البرمجة اللغوية العصبية، سنحاول تحسين ملفات Microsoft التي تم إصدارها مؤخرًا نموذج تخطيط LM في مجموعة بيانات مخصصة مشروحة تتضمن فواتير فرنسية وإنجليزية. بينما ركزت البرامج التعليمية السابقة على استخدام المحتوى المتاح للجمهور مجموعة بيانات FUNSD لضبط النموذج ، سنعرض هنا العملية بأكملها بدءًا من التعليق التوضيحي والمعالجة المسبقة إلى التدريب والاستدلال.

نموذج LM

 
يعتمد نموذج LayoutLM على بنية BERT ولكن مع نوعين إضافيين من عمليات دمج المدخلات. الأول هو تضمين موضع ثنائي الأبعاد يشير إلى الموضع النسبي للرمز المميز داخل المستند ، والثاني عبارة عن دمج صورة للصور المميزة الممسوحة ضوئيًا داخل المستند. حقق هذا النموذج أحدث النتائج في العديد من المهام النهائية ، بما في ذلك فهم النموذج (من 2 إلى 70.72) ، وفهم الإيصالات (من 79.27 إلى 94.02) ، وتصنيف صورة المستند (من 95.24 إلى 93.07). لمزيد من المعلومات ، راجع المقال الأصلي.

لحسن الحظ ، كان النموذج مفتوح المصدر ومتاحًا في مكتبة huggingface. شكرا مايكروسوفت!

في هذا البرنامج التعليمي ، سنقوم باستنساخ النموذج مباشرة من مكتبة huggingface و ضبطه على مجموعة البيانات الخاصة بنا. لكن أولاً ، نحتاج إلى إنشاء بيانات التدريب.

شرح الفاتورة

 
باستخدام أداة التعليقات التوضيحية النصية UBIAI، لقد قمت بتعليق حوالي 50 فاتورة شخصية. أنا مهتم باستخراج مفاتيح وقيم الكيانات ؛ على سبيل المثال في النص التالي "التاريخ: 06/12/2021" سنعلق "التاريخ" كـ DATE_ID و "06/12/2021" كـ DATE. سيساعدنا استخراج كل من المفاتيح والقيم على ربط القيم العددية بسماتها. إليك جميع الكيانات التي تم شرحها:

DATE_ID, DATE, INVOICE_ID, INVOICE_NUMBER,SELLER_ID, SELLER, MONTANT_HT_ID, MONTANT_HT, TVA_ID, TVA, TTC_ID, TTC

فيما يلي بعض تعريفات الكيانات:

MONTANT_HT: السعر الإجمالي قبل الضريبة
TTC: السعر الإجمالي شامل الضريبة
TVA: قيمة الضريبة

فيما يلي مثال على فاتورة مشروحة باستخدام يوبياي:

الشكل
شرح الفاتورة في UBIAI

 

بعد التعليق التوضيحي ، نقوم بتصدير ملفات القطار والاختبار من UBIAI مباشرة بالتنسيق الصحيح دون أي خطوة ما قبل المعالجة. سيتضمن التصدير ثلاثة ملفات لكل مجموعة بيانات تدريب واختبار وملف نصي واحد يحتوي على جميع الملصقات المسماة labels.txt:

Train / Test.txt 2018 O Sous-total O en O EUR O 3,20،0 O € O TVA S-TVA_ID (0,00٪) O 3,20،XNUMX € S-TVA Total B-TTC_ID en I-TTC_ID EUR E-TTC_ID XNUMX ، XNUMX S-TTC € O Services O soumis O au O mécanisme O d'autol Liquidation O - O


Train / Test_box.txt (يحتوي على مربع محيط لكل رمز مميز):

912 الخدمات 457 سوميس 920 الاتحاد الأفريقي 466 الميكانيزم 80 تصفية تلقائية 486 - 133


Train / Test_image.txt (يحتوي على المربع المحيط وحجم المستند والاسم):

€ 912 425 920 image434.jpg TVA 1653 2339 1 image500.jpg (441٪) 526 449 1653 image2339.jpg 1،0 € 529 441 557 image451.jpg المجموع 1653 2339 1 0,00 image882.jpg ar 441 920 451 image1653.jpg EUR 2339 1 500 image457.jpg 531،466 1653 2339 image1.jpg € 534 459 549 image466.jpg الخدمات 1653 2339 1 553 image457.jpg soumis 578 466 1653 image2339.jpg الاتحاد الأوروبي 1 3,20 882 image457.jpg mécanisme 911 467 1653 image2339.jpg d'autol Liquidation 1 912 457 image920.jpg - 466 1653 2339 image1.jpg


التسميات.txt:

B-DATE_ID B-INVOICE_ID B-INVOICE_NUMBER B-MONTANT_HT B-MONTANT_HT_ID B-SELLER B-TTC B-DATE B-TTC_ID B-TVA B-TVA_ID E-DATE_ID E-DATE E-INVOICE_ONTID E-INVOICE_NUMBER MONTANT_HT_ID E-SELLER E-TTC E-TTC_ID E-TVA E-TVA_ID I-DATE_ID I-DATE I-SELLER I-INVOICE_ID I-MONTANT_HT_ID I-TTC I-TTC_ID I-TVA_ID O S-DATE_ID S-DATE S-INVOICE S-INVOICE_NUMBER S-MONTANT_HT_ID S-MONTANT_HT S-SELLER S-TTC S-TTC_ID S-TVA S-TVA_ID


نموذج LM:

 
هنا ، نستخدم google colab مع GPU لضبط النموذج. الكود أدناه يعتمد على ورق تخطيط أصلي LM و هذا البرنامج التعليمي 

أولاً ، قم بتثبيت حزمة layoutLM ...

! rm -r unilm! git clone -b remove_torch_save https://github.com/NielsRogge/unilm.git! القرص المضغوط unilm / layoutlm! نقطة تثبيت unilm / layoutlm


... بالإضافة إلى حزمة المحولات التي سيتم تنزيل النموذج منها:

! محولات rm -r! استنساخ بوابة https://github.com/huggingface/transformers.git! محولات الأقراص المدمجة! تثبيت النقطة. / المحولات


بعد ذلك ، قم بإنشاء قائمة تحتوي على التسميات الفريدة من labels.txt:

من torch.nn استيراد CrossEntropyLoss def get_labels (المسار): مفتوح (المسار ، "r") مثل f: labels = f.read (). splitlines () إذا لم يكن "O" في الملصقات: labels = ["O"] + تسميات إرجاع تسميات = get_labels ("./ labels.txt") num_labels = len (ملصقات) label_map = {i: تسمية لـ i ، تسمية في تعداد (ملصقات)} pad_token_label_id = CrossEntropyLoss (). ignore_index


بعد ذلك ، أنشئ مجموعة بيانات pytorch ومحمل بيانات:

من المحولات استيراد LayoutLMTokenizer من layoutlm.data.funsd استيراد FunsdDataset و InputFeatures من torch.utils.data استيراد DataLoader و RandomSampler و SequentialSampler args = {'local_rank': -1، 'overwrite_cache': True، 'data_dir': '/ content data '،' model_name_or_path ':' microsoft / layoutlm-base-uncased '،' max_seq_length ': 512،' model_type ':' layoutlm '،} # class لتحويل مفاتيح dict إلى سمات فئة AttrDict (ict): def __init __ (self، * args، ** kwargs): super (AttrDict، self) .__ init __ (* args، ** kwargs) self .__ict__ = self args = AttrDict (args) tokenizer = LayoutLMTokenizer.from_pretrained ("microsoft / layoutlm- base-uncased ") # قام مؤلفو LayoutLM بالفعل بتعريف FunsdDataset محدد ، لذلك سنستخدم هذا هنا train_dataset = FunsdDataset (args ، tokenizer ، labels ، pad_token_label_id ، mode =" train ") train_sampler = RandomSampler (train_dataset) (train_dataset ، sampler = train_sampler ، batch_size = 2) Eval_dataset = FunsdDataset (args ، tokenizer ، labels، pad_token_label_id، mode = "test") Eval_sampler = SequentialSampler (EVAL_dataset) Eval_dataloader = DataLoader (Eval_dataset، sampler = Eval_sampler، batch_size = 2) الدفعة = التالية (iter (train_dataloader to)) [0] input_ids .decode (input_ids)


تحميل النموذج من huggingface. سيتم ضبط هذا على مجموعة البيانات.

من المحولات استيراد LayoutLMForTokenClassification import torch device = torch.device ("cuda" if torch.cuda.is_available () else "cpu") model = LayoutLMForTokenClassification.from_pretrained ("microsoft / layoutlm-base-uncased"، num_labels = num_labels) model. ل الجهاز)


أخيرًا ، ابدأ التدريب:

تستورد محولات rom AdamW من tqdm import tqdm optimizer = AdamW (model.parameters ()، lr = 5e-5) global_step = 0 num_train_epochs = 50 t_total = len (train_dataloader) * num_train_epochs # إجمالي عدد خطوات التدريب # إدخال النموذج في التدريب الوضع model.train () للحقبة في النطاق (num_train_epochs): للدفعة في tqdm (train_dataloader، desc = "Training"): input_ids = الدُفعة [0] .to (الجهاز) bbox = الدُفعة [4]. إلى (الجهاز) الاهتمام_mask = الدفعة [1]. إلى (الجهاز) token_type_ids = الدفعة [2]. إلى (الجهاز) الملصقات = الدفعة [3]. إلى (الجهاز) # مخرجات تمرير التوجيه = النموذج (المدخلات = المدخلات ، bbox = bbox ، الانتباه_ماسك = الاهتمام_mask، token_type_ids = token_type_ids، labels = labels) loss = outputs.loss # خسارة طباعة كل 100 خطوة إذا global_step٪ 100 == 0: print (f "الخسارة بعد {global_step} الخطوات: {loss.item ()}") # تمرير للخلف للحصول على التدرجات loss.backward () #print ("التدرجات على رأس التصنيف:") #print (model.classifier.weight.grad [6،:]. sum ()) # update optimizer.step () محسن .zero_grad () global_step + =1


يجب أن تكون قادرًا على رؤية تقدم التدريب والخسارة يتم تحديثها.

الشكل
تدريب تخطيط LM قيد التقدم

 

بعد التدريب ، قم بتقييم أداء النموذج بالوظيفة التالية:

mport numpy كـ np من استيراد seqeval.metrics (تصنيف_تقرير ، f1_score ، دقة_تقييم ، استدعاء_تسجيل ،) EVAL_loss = 0.0 nb_eval_steps = 0 preds = لا شيء out_label_ids = لا شيء # وضع نموذج في نموذج وضع التقييم. = "تقييم"): مع torch.no_grad (): input_ids = الدفعة [0]. to (الجهاز) bbox = الدفعة [4]. to (الجهاز) الانتباه_mask = الدفعة [1]. to (الجهاز) token_type_ids = الدُفعة [ 2] .to (device) labels = الدفعة [3] .to (device) # forward pass output = model (input_ids = input_ids ، bbox = bbox ، calling_mask = calling_mask ، token_type_ids = token_type_ids ، labels = labels) # احصل على الخسارة و logits tmp_eval_loss = outputs.loss logits = outputs.logits EVAL_loss + = tmp_eval_loss.item () nb_eval_steps + = 1 # احسب التنبؤات إذا كانت المفترسات بلا: preds = logits.detach (). cpu (). numpy () out_label_ids = labels .detach (). cpu (). numpy () else: preds = np.append (preds، logits.detach (). cpu (). numpy ()، axis = 0) out_label_ids = np.append (out_label_ids، labels. افصل (). cpu (). n umpy ()، axis = 0) # حساب متوسط ​​خسارة التقييم Eval_loss = Eval_loss / nb_eval_steps preds = np.argmax (preds، axis = 2) out_label_list = [[] لـ _ في النطاق (out_label_ids.shape [0])] preds_list = [[] لـ _ في النطاق (out_label_ids.shape [0])] لـ i في النطاق (out_label_ids.shape [0]): لـ j في النطاق (out_label_ids.shape [1]): if out_label_ids [i، j]! = pad_token_label_id: out_label_list [i] .append (label_map [out_label_ids [i] [j]]) preds_list [i] .append (label_map [preds [i] [j]]) النتائج = {"loss": Eval_loss، "دقة ": quality_score (out_label_list، preds_list)،" استدعاء ": rec_score (out_label_list، preds_list)،" f1 ": f1_score (out_label_list، preds_list)،}


مع 50 مستندًا فقط ، نحصل على الدرجات التالية:

الشكل
درجة التقييم بعد التدريب

 

مع المزيد من التعليقات التوضيحية ، من المفترض أن نحصل بالتأكيد على درجات أعلى.

أخيرًا ، احفظ النموذج للتنبؤ المستقبلي:

PATH = '. / drive / MyDrive / train_layoutlm / layoutlm_UBIAI.pt' torch.save (model.state_dict () ، PATH)


الإستنباط:

 
الآن يأتي الجزء الممتع ، دعنا نحمّل فاتورة ، و OCR عليها ، واستخرج الكيانات ذات الصلة. في هذا الاختبار ، نستخدم فاتورة لم تكن موجودة في مجموعة بيانات التدريب أو الاختبار. لتحليل النص من الفاتورة ، نستخدم حزمة Tesseract مفتوحة المصدر. لنقم بتثبيت الحزمة:

! sudo apt install tesseract-ocr! pip install pytesseract


قبل تشغيل التنبؤات ، نحتاج إلى تحليل النص من الصورة ومعالجة الرموز المميزة والمربعات المحيطة مسبقًا إلى ميزات. للقيام بذلك ، قمت بإنشاء ملف python للعملية التمهيدية LayoutLM_preprocess.py هذا سيجعل من السهل معالجة الصورة مسبقًا:

mport sys sys.path.insert (1، './drive/MyDrive/UBIAI_layoutlm') من layoutlm_preprocess import * image_path = '.


بعد ذلك ، قم بتحميل النموذج واحصل على تنبؤات الكلمات مع المربعات المحيطة بها:

model_path = '. / drive / MyDrive / training_layoutlm / layoutlm_UBIAI.pt' model = model_load (model_path، num_labels) word_level_prediction، final_boxes = convert_to_features (صورة ، كلمات ، مربعات ، ملفات فعلية ، نموذج)


أخيرًا ، اعرض الصورة مع الكيانات المتوقعة والمربعات المحيطة:

draw = ImageDraw.Draw (image) font = ImageFont.load_default () def iob_to_label (التسمية): if label! = 'O': إرجاع التسمية [2:] else: return "" label2color = {'data_id': 'green' ، 'date': 'green'، 'invoice_id': 'blue'، 'invoice_number': 'blue'، 'montant_ht_id': 'black'، 'montant_ht': 'black'، 'seller_id': 'red'، ' البائع ':' red '،' ttc_id ':' grey '،' ttc ':' gray '،' ':' violet '،' tva_id ':' orange '،' tva ':' orange '} للتنبؤ، box في zip (word_level_prediction، final_boxes): Forecasted_label = iob_to_label (label_map [توقع]). Lower () draw.rectangle (box، outline = label2color [Forecasted_label]) draw.text ((box [0] + 10، box [1] - 10) ، نص = علامة_تنبؤة ، ملء = تسمية 2 لون [علامة_تتوقع] ، خط = خط) صورة


ها أنت ذا:

الشكل
استخراج كيان الفاتورة باستخدام LayoutLM

 

كان النموذج قادرًا على استخراج البائع ورقم الفاتورة والتاريخ و TTC بشكل صحيح ولكنه ارتكب خطأً من خلال تعيين ملصق TTC إلى عنصر تم شراؤه. كانت النتائج مبهرة وواعدة جدًا نظرًا لقلة عدد المستندات المشروحة (50 فقط)! مع المزيد من الفواتير المشروحة ، سنتمكن من الوصول إلى درجات F أعلى وتوقعات أكثر دقة. 

الخلاصة:

 
بشكل عام ، النتائج من نموذج LayoutLM واعدة للغاية وتوضح فائدة المحولات في تحليل النص شبه المنظم. يمكن ضبط النموذج بدقة على أي مستندات شبه مهيكلة أخرى مثل رخص القيادة والعقود والمستندات الحكومية والمستندات المالية وما إلى ذلك.

إذا كان لديك أي سؤال ، فلا تتردد في طرحه أدناه أو إرسال بريد إلكتروني إلينا على admin@ubiai.tools.

إذا أعجبك هذا المقال ، يرجى التصفيق والإعجاب والمشاركة! 

 
السيرة الذاتية: وليد عمو هو مؤسس UBIAI ، أداة شرح لتطبيقات البرمجة اللغوية العصبية ، وحاصل على درجة الدكتوراه في الفيزياء.

هذا الموضوع ذو علاقة بـ:

كوينسمارت. Beste Bitcoin-Börse في أوروبا
المصدر: https://www.kdnuggets.com/2021/06/fine-tuning-transformer-model-invoice-recognition.html

بقعة_صورة

أحدث المعلومات الاستخباراتية

بقعة_صورة

الدردشة معنا

أهلاً! كيف يمكنني مساعدك؟