พื้นฐาน NLP เชิงปฏิบัติ: ตัวแยกประเภทภาษาที่ใช้งานออนไลน์ใน 3 ขั้นตอน
Tl; dr: ฉันใช้เวลาพูดคุย TED 5,000 ครั้งเพื่อสร้างตัวแยกประเภทภาษาโปรตุเกสด้วย scikit-learn จากนั้นฉันก็ปรับแต่ง Flask และ Vue.js เพื่อ "แชร์กับคุณ"
Clique aqui para o artigo em português
ใช่ ฉันเป็นสมาชิกของกลุ่มคนที่ตัดสินใจก้าวเข้าสู่กลุ่ม Data Science เมื่อเร็วๆ นี้ เรียนรู้ตามที่คุณไปผู้คนกล่าว เสนอปัญหาและหาทางแก้ไขพวกเขากล่าว อย่ากลัวที่จะทำลายสิ่งของระหว่างทางพวกเขากล่าว ฉันก็พยายามมากเหมือนกัน ในฐานะนักแปลภาษาโปแลนด์-โปรตุเกสในชีวิตก่อน ฉันมีปัญหาในโลกแห่งความเป็นจริงขึ้นมาทันที:
คุณเห็นไหมว่าโปรตุเกสเป็นภาษาที่แบ่งออกเป็นมหาสมุทรแอตแลนติก ประเทศบราซิลและโลกเก่า (ประเทศในแอฟริกาและเอเชียที่พูดโปรตุเกส + โปรตุเกส) มีความแตกต่างกันในเรื่องคำศัพท์ ไวยากรณ์ และการออกเสียง
ในขณะเดียวกัน ตลาดการแปลภาษาโปรตุเกสอิสระในโปแลนด์ค่อนข้างแคบ ฉันไม่มีความหรูหราที่จะเชี่ยวชาญและยึดติดกับพันธุ์ใดพันธุ์หนึ่งเท่านั้น เมื่อฉันสวมหมวกทั้งสองข้าง บางครั้งในสัปดาห์ทำงานเดียวกัน ฉันจึงต้องระมัดระวังในการรักษาความสม่ำเสมอในการแปลที่กำหนดเป็นสองเท่า นั่นเป็นเหตุผลว่าทำไมแนวคิดแรกๆ ของฉันสำหรับโครงการ NLP คือตัวแยกประเภทภาษาโปรตุเกส
ไม่ใช่การวิจัยที่ก้าวล้ำที่ปูทางใหม่ใน NLP หรือ AI แรงจูงใจของฉันที่นี่คล้ายกับใน "บทความขนาดกลางเกี่ยวกับ Tweetbot" ก่อนหน้าของฉัน — แสดงให้เห็นว่าขั้นตอนแรกในการประมวลผลภาษาธรรมชาติใน Python นั้นตรงไปตรงมาเพียงใด ในฐานะบุคคลที่มีพื้นฐานด้านเทคนิคเพียงเล็กน้อย ฉันพยายามนำเสนอเป็นภาษาอังกฤษธรรมดาที่สุด
บทความนี้แบ่งออกเป็นสามส่วนหลัก:
- การเตรียมแหล่งข้อมูล (Scrapy);
- ฝึกอบรมโมเดล (scikit-learn);
- การปรับใช้ API ด้วยโมเดล (Flask+Vue.js)
กำลังเตรียมแหล่งข้อมูล
ฉันต้องใช้ข้อมูลอะไรบ้าง จะรวบรวมข้อมูลได้ที่ไหน และอย่างไร? ในกรณีนี้ ฉันเลือก TED.com เป็นแหล่งข้อมูลของฉัน เป็นฐานข้อมูลขนาดใหญ่พอสมควรของการบรรยายที่ถอดความได้อย่างสะดวก สิ่งที่สำคัญอย่างยิ่งในกรณีนี้คือ ทีมแปลของ TED จะคอยแบ่งแยกภาษาโปรตุเกสทั้งสองอย่างเข้มงวด (ซึ่งไม่ใช่ในกรณีของวิกิพีเดีย เป็นต้น)
TED เคยดูแลรักษา API อย่างเป็นทางการ แต่เลิกผลิตไปในปี 2016 ดังนั้นฉันจึงตั้งค่า "Scrapy Spider" เพื่อดึงข้อมูล ส่วนใหญ่เป็นแบบสำเร็จรูปตาม "บทช่วยสอนแบบ Scrapy" สไปเดอร์วนดูรายการการบรรยายของ TED ในภาษาที่ระบุ และติดตามลิงก์ไปยังการบรรยายแต่ละรายการ:
def parse_front(self, response): talk_links = response.css(“a.ga-link::attr(href)”) links_to_follow = talk_links.extract() for url in links_to_follow: url = url.replace(‘?language’, ‘/transcript?language’) yield response.follow(url=url, callback=self.parse_pages)
จากนั้น วิธีแยกวิเคราะห์ที่สองจะขูดชื่อและข้อความของการบรรยายแต่ละรายการและเพิ่มลงในพจนานุกรม:
def parse_pages(self, response): title = response.xpath(‘//head/title/text()’).extract_first() title = title.strip() title = title.split(‘:’)[0] talk = response.xpath( ‘//div[@class=”Grid__cell flx-s:1 p-r:4"]/p/text()’).extract() for line in talk: line = line.strip() line = line.replace(‘\n’,’ ‘) line = line.replace(‘\t’,’ ‘) talk = ‘ ‘.join(talk) talk = talk.replace(‘\n’,’ ‘) ted_dict[title] = talk
เมื่อเสร็จแล้ว พจนานุกรมจะถูกเทลงในไฟล์ CSV สิ่งที่ฉันต้องทำคือกำหนด xpaths ที่เหมาะสม ฉันยังตั้งค่าดีเลย์ครึ่งนาทีระหว่างการดาวน์โหลดแต่ละครั้ง (หากไม่มี ฉันเข้าใช้งานเซิร์ฟเวอร์บ่อยเกินไปและมันบล็อกคำถามของฉัน):
class TedSpiderPt(scrapy.Spider): name = “ted_spider_pt” download_delay = 0.5
การเตรียมข้อมูลที่เหลือและกระบวนการฝึกอบรมสามารถรวมอยู่ในสมุดบันทึก Jupyter ที่นี่ ด้านล่างนี้ ฉันอ่านผ่านๆ และเน้นช่วงเวลาสำคัญๆ
ฉันคัดลอกการพูดคุย TED ประมาณ 2,500 รายการสำหรับภาษาโปรตุเกสแต่ละเวอร์ชัน ประมาณ 12-18,000 อักขระต่อการพูดคุยแต่ละครั้ง หลังจากทำความสะอาดการจัดรูปแบบแล้ว ฉันติดป้ายกำกับการถอดเสียงเป็น "0" สำหรับ PT-PT (โปรตุเกสแบบยุโรป) และ "1" สำหรับ PT-BR จากนั้นจึงปรับให้เหมาะสมและแปลงด้วย CountVectorizer ของ scikit-learn
หากบทความนี้เป็นการแนะนำคุณเกี่ยวกับการประมวลผลภาษาธรรมชาติ: CountVectorizer แปลงชุดเอกสารข้อความเป็นจำนวนคำ ข้อมูลข้อความในรูปแบบตัวเลขนี้ช่วยเพิ่มความสามารถในการประมวลผลได้อย่างมาก
ก่อนอื่น ฉันแบ่งการบรรยายออกเป็นชุดการฝึกอบรมและการทดสอบในสัดส่วน 2:1 โมเดลจะเรียนรู้จากข้อมูลการฝึกเท่านั้น ส่วนทดสอบใช้ตรวจสอบประสิทธิภาพก่อนปล่อยออกสู่โลก
จากนั้นฉันก็จัด Vectorizer เข้ากับข้อมูลการฝึกอบรม — ในภาษาอังกฤษธรรมดา มันจะกำหนดหมายเลขที่ไม่ซ้ำกันสำหรับแต่ละคำที่พบ เพื่อสร้างคำศัพท์ เพื่อกำจัดค่าผิดปกติที่รุนแรง ฉันตั้งค่าพารามิเตอร์ min_df เป็น 2 — คำที่เกิดขึ้นเพียงครั้งเดียวจะไม่นำมาพิจารณา จากนั้นฉันก็เปลี่ยนชุดการฝึก เช่น นับจำนวนคำแต่ละคำจากคำศัพท์ หลังจาก CountVectorizing แต่ละคำ 59,061 คำจะถูกนับในการพูดคุย 3,555 คำที่ประกอบเป็นชุดการฝึกอบรม
ดูด้านล่างสำหรับภาพประกอบ:
คำว่า "eu" ("ฉัน" ในภาษาโปรตุเกส) ได้รับการจัดทำดัชนีเป็น "23892" ในคำศัพท์ ในการนับจำนวนคำสำหรับดัชนีนี้ เราจะเห็นการบรรยายรายการหนึ่งที่มีจำนวน "eu" สูงกว่ามาก เราสามารถย้อนกลับไปดูการถอดเสียงพูดคุยได้ และ... แท้จริงแล้ว ประสบการณ์ส่วนตัวมีบทบาทสำคัญใน "TED talk" ของ Chiki Sarkar
นอกเหนือจากการทำเวคเตอร์และการนับแล้ว ฉันงดเว้นการประมวลผลล่วงหน้าอื่นๆ ฉันไม่ควบคุมคำนั้น เนื่องจากฉันต้องการรักษาความแตกต่างทางไวยากรณ์ (เช่น ความแตกต่างในการผันคำกริยา) ระหว่างภาษาทั้งสองเวอร์ชัน เพื่อยกตัวอย่าง: การลด "[a] fazer" และ "fazendo" ลงไปที่ก้านจะทำให้ความแตกต่าง PT/BR ที่ฉันต้องการจับไม่ชัดเจน
การฝึกอบรมโมเดล
จากนั้น ฉันฝึกตัวแยกประเภท Multinomial Naive Bayes ในชุดการฝึก แม้ว่าแนวทางนี้จะค่อนข้างพื้นฐาน แต่ก็ทำงานได้ดีอย่างน่าประหลาดใจในแอปพลิเคชัน NLP เช่นนี้
คำอธิบายภาษาอังกฤษธรรมดาบางประการอีกครั้ง: ตัวแยกประเภท NaiveBayes โดยทั่วไปจะเปรียบเทียบความถี่ของคำที่กำหนดในชุด BR และ PT และกำหนดว่าคำนั้นแนะนำข้อความ "บราซิล" หรือ "โปรตุเกส" มากกว่ากัน ขณะทำนาย คำทั้งหมดในข้อความจะถูกชั่งน้ำหนักและเราจะได้ความน่าจะเป็นขั้นสุดท้าย
หลังจากฝึกฝนตัวแยกประเภทแล้ว ฉันจะเปลี่ยนชุดการทดสอบโดยใช้เวกเตอร์ไลเซอร์แบบเดิม มีคำศัพท์ชุดฝึกอบรมอยู่แล้ว และจะนับเฉพาะคำที่ปรากฏในนั้นเท่านั้น
จากนั้นชุดการทดสอบแบบเวกเตอร์จะถูกจำแนกประเภทโดยใช้ MultinomialNaiveBayes ในกรณีนี้ ฉันได้ปรับแต่งชุดทดสอบเล็กน้อย — ฉันต้องการทดสอบความสามารถในการจัดประเภทข้อความสั้น ดังนั้นฉันจึงแบ่งการบรรยายของชุดการทดสอบออกเป็นกลุ่มย่อยๆ ละ 200–760 อักขระ เพื่อการเปรียบเทียบ ย่อหน้าที่คุณกำลังอ่านอยู่ตอนนี้มีอักขระ 370 ตัว ผลลัพธ์?
ฉันได้รับความแม่นยำ 86.55% สำหรับข้อความสั้น โดยมีสัดส่วนที่เกือบเท่ากันของตัวอย่าง PT-PT และ PT-BR ที่จัดประเภทอย่างไม่ถูกต้อง คะแนนดีพอมั้ย? ฉันไม่ใช่ผู้ตัดสินที่เป็นกลางที่สุดที่นี่ แต่ฉันว่ามันก็ค่อนข้างดี เรามาดูตัวอย่างวลีที่จัดประเภทผิดเพื่อช่วยเราประเมินโมเดลกัน
แม้ว่าคุณจะไม่คุ้นเคยกับภาษาโปรตุเกสทั้งสองรูปแบบ ลองจินตนาการถึงประโยคบางประโยคที่แต่งขึ้นในลักษณะที่ไม่ทำให้ฟังดูเป็นภาษาอังกฤษแบบอเมริกันหรือแบบอังกฤษ นั่นเป็นปัญหาของวลีที่จัดประเภทไม่ถูกต้องหลายวลีที่นี่ ไม่ว่าในกรณีใด ฉันจะเจาะลึกถึงวิธีปรับปรุงโมเดลในส่วนต่อๆ ไปของบทความนี้ สำหรับตอนนี้ มาแบ่งปันให้โลกได้รับรู้กันเถอะ!
การปรับใช้ API กับโมเดล
หากฉันต้องการใช้โมเดลของฉันนอก Jupyter Notebook ฉันต้องการวิธีส่งออกข้อมูลดังกล่าว สำหรับงานนี้ ฉันใช้ ไลบรารีการทำให้ซีเรียลไลซ์ joblib ซึ่งให้วิธีแก้ปัญหาแบบเบา ๆ
ข้อความใหม่ทุกข้อความที่ส่งไปที่โมเดลจะต้องได้รับการแปลงโดย vectorizer แล้วจึงจัดประเภท ดังนั้นฉันจึงสรุป vectorizer และ classifier ให้เป็น "ไปป์ไลน์" ของ scikit ถ้าอย่างนั้นก็เป็นเพียงเรื่องของการถ่ายโอนข้อมูลลงในไฟล์ joblib:
pipeline = Pipeline([('vectorizer',vectorizer), 'classifier',nb_classifier)]) dump(pipeline, 'ptclassifier.joblib', protocol = 2)
“Lightweight” เป็นคำที่ใช้กับ Flask ซึ่งเป็นเฟรมเวิร์กแอปพลิเคชันเว็บแบบลีนที่ฉันใช้ในการปรับใช้ API รหัสเต็มสำหรับแอป Flask ของฉันคือ "ใน repo GitHub" โดยพื้นฐานแล้วมันจะโหลดโมเดล joblibbed และรับฟังคำขอ GET ด้วยอาร์กิวเมนต์เดียว: สตริงของข้อมูลข้อความ เมื่อได้รับแล้ว จะส่งสตริงผ่านไปป์ไลน์และส่งกลับทั้งป้ายกำกับที่คาดการณ์และค่าความเชื่อมั่นของการคาดคะเนนั้น
ฉันยังใช้แพ็คเกจ flask-cors เพื่ออนุญาตคำขอจากแหล่งอื่น ในกรณีของเรา แอปส่วนหน้าที่ฉันจะแนะนำในอีกสักครู่ซึ่งโฮสต์ไว้ที่อื่น จะต้องมีสิทธิ์เข้าถึง Flask API นี้ คุณสามารถอ่านเพิ่มเติมเกี่ยวกับ CORS ที่นี่
ฉันโฮสต์แอป Flask ของฉันบน PythonAnywhere ซึ่งเป็นบริการที่ฉันอธิบายโดยละเอียดเพิ่มเติมอีกเล็กน้อยใน บทความ tweetbot หากคุณเริ่มต้นด้วยสคริปต์ Python ที่โฮสต์ออนไลน์ ฉันขอแนะนำ PyA ด้วยความเต็มใจ — ทีมสนับสนุนให้ความช่วยเหลือเสมอกับปัญหาของผู้เริ่มต้น
วิธีที่ทรมานของฉันไปสู่ส่วนหน้า ML
เอ่อ ส่วนหน้า.. ต้นตอและสาเหตุของความหงุดหงิดครั้งใหญ่ของฉัน ฉันเชื่อว่าขั้นตอนสุดท้าย การตั้งค่าหน้าที่ง่ายที่สุดด้วยกล่องข้อความและปุ่ม "ส่ง" จะค่อนข้างง่าย ฉันมั่นใจมากจนฉันตกอยู่ในวงจรอุบาทว์
ก่อนอื่น ฉันได้รับคำแนะนำว่าฉันควรใช้ Vue.js แต่เริ่มต้นด้วยหนังสือเกี่ยวกับ JavaScript เอง เช่น EloquentJS อ่า.. อย่าเข้าใจฉันผิด ฉันชอบ EJS ซึ่งเป็นเวอร์ชันออนไลน์ที่มีแซนด์บ็อกซ์สำหรับแบบฝึกหัด ซึ่งสามารถเข้าถึงได้มาก แต่หลังจากผ่านไปหนึ่งสัปดาห์กับหลักสูตรนี้ ฉันก็ตระหนักว่าเป้าหมายของฉันในขณะนี้คือการต่อส่วนหน้าพื้นฐานและกลับไปสร้างโมเดลอีกครั้ง ฉันยังคงรู้สึกไม่คล่องในภาษา Python เพียงพอที่จะเริ่มภาษาใหม่
จากนั้นฉันก็ค้นหา “เทมเพลตส่วนหน้าของ Machine Learning อย่างง่าย” และคำหลักที่คล้ายกันซึ่งมีผลลัพธ์ที่หลากหลาย กับดักที่ฉันตกเข้าไป? ความอดทนของฉันสำหรับโซลูชันที่ใช้งานได้เพียงเล็กน้อยนั้นกินเวลาน้อยกว่าเวลาที่ฉันต้องทำความเข้าใจและปรับใช้เทมเพลต
ในที่สุด ฉันพบอันที่ทำงานเร็วพอสำหรับฟิวส์สั้นของฉัน — นำเสนอโดย James Salvatore ในบล็อก Uptake Tech ฉันนำเทมเพลตของเขามาปรับแต่งเล็กน้อยตามจุดประสงค์ของฉัน เพื่อความง่าย ฉันจึงตัดแถบเครื่องมือออก เพิ่มรูปภาพที่ใช้เป็นส่วนหัว และเก็บกล่องข้อความไว้เพียงกล่องเดียว ฉันโฮสต์แอปเวอร์ชันที่ใช้งานจริงบน AlwaysData ซึ่งเป็นบริการอื่นที่ฉันสามารถแนะนำได้
ดูผลลัพธ์สุดท้าย ที่นี่ หากคุณยังไม่ได้ดำเนินการ
เล่นสนุกแม้ว่าคุณจะไม่รู้จักภาษาโปรตุเกสก็ตาม ฉันจะมีความสุขมากถ้าคุณทำลายบางสิ่งที่นั่นและบอกฉันเกี่ยวกับมัน! นอกจากนี้ การวิพากษ์วิจารณ์อย่างสร้างสรรค์ต่อ "โค้ดในพื้นที่เก็บข้อมูล" จะทำให้คุณได้รับความกตัญญูชั่วนิรันดร์
อะไรต่อไป?
บทความนี้จะมีส่วนที่ 2 ในอนาคตอันใกล้นี้ ฉันต้องการ:
- เพิ่มฟีเจอร์ที่แสดงให้ผู้ใช้แอปส่วนหน้าของฉันเห็นว่าคำแต่ละคำมีอิทธิพลต่อการทำนายอย่างไร
- ขูดแหล่งข้อความอื่นๆ (ข่าว บล็อก คำบรรยายภาพยนตร์) ตรวจสอบประสิทธิภาพของโมเดล
- สำรวจข้อผิดพลาดของตัวแยกประเภทและพยายามค้นหารูปแบบ
- ลองใช้แนวทาง LSTM ในการแก้ปัญหาและเปรียบเทียบผลลัพธ์
- และสุดท้ายแต่ไม่ท้ายสุด หวังว่าฉันจะได้รับคำติชมจากผู้อ่านของฉันที่ควรค่าแก่การแบ่งปัน!
โบนัส (สำหรับผู้พูดภาษาโปรตุเกส)!
ฉันสะดุดกับสองตัวอย่างของผู้คนที่แก้ไขปัญหาคล้ายกันกับภาษาโปรตุเกส:
- Estudo sobre Identificação Automática de Sotaques Regionais Brasileiros โดย Nathalia Alves Rocha (pdf)
- Criando um detetor de sotaques com Machine Learning in PHP by Rodrigo Cardoso
ขอขอบคุณ Piotr Migdał สำหรับคำแนะนำเกี่ยวกับเรื่องนี้และโครงการอื่นๆ และขอขอบคุณ Kamil Herba และ Piotr Kaznowski สำหรับข้อมูลเชิงลึก ทั้งในบทความและเว็บแอป