การแก้สมการคณิตศาสตร์พื้นฐานโดยใช้ RNN [พร้อมตัวอย่างการเข้ารหัส]
เผยแพร่แล้ว: 2020-12-07ถ้าชีวิตให้ RNN แก่คุณ ให้สร้างเครื่องคิดเลข
Recurrent Neural Network เป็นหนึ่งในโครงข่ายประสาทเทียมแบบคลาสสิก โดยที่การเชื่อมต่อระหว่างโหนดจะสร้างกราฟกำกับตามลำดับ RNN มีชื่อเสียงในด้านแอปพลิเคชัน เช่น การรู้จำคำพูด การรู้จำลายมือ ฯลฯ เนื่องจากหน่วยความจำสถานะภายในสำหรับการประมวลผลลำดับความยาวแปรผัน
RNNs แบ่งออกเป็นสองประเภทเพิ่มเติม อันแรกคือแรงกระตุ้นที่จำกัดซึ่งโครงข่ายประสาทเทียมอยู่ในรูปแบบของกราฟ acyclic แบบกำกับซึ่งโหนดหนึ่งสามารถเชื่อมต่อกับโหนดอย่างน้อยหนึ่งโหนดที่อยู่ข้างหน้าโดยไม่มีวงจรที่มองเห็นได้ในเครือข่าย อีกประการหนึ่งคือแรงกระตุ้นที่ไม่สิ้นสุดซึ่งโครงข่ายประสาทเทียมอยู่ในรูปแบบของกราฟวัฏจักรโดยตรงซึ่งไม่สามารถคลี่ออกเป็นโครงข่ายประสาทเทียมแบบฟีดฟอร์เวิร์ด
สารบัญ
เราจะทำอะไร?
มาสร้างแบบจำลองที่ทำนายผลลัพธ์ของนิพจน์เลขคณิตกัน ตัวอย่างเช่น หากฉันป้อนค่า '11+88' โมเดลควรคาดเดาคำถัดไปในลำดับเป็น '99' อินพุตและเอาต์พุตเป็นลำดับของอักขระเนื่องจาก RNN เกี่ยวข้องกับข้อมูลตามลำดับ
ตอนนี้การออกแบบสถาปัตยกรรมของโมเดลดูเหมือนเป็นงานง่ายเมื่อเทียบกับการรวบรวมชุดข้อมูล การสร้างข้อมูลหรือการรวบรวมชุดข้อมูลเป็นงานที่ต้องใช้กำลังมาก เนื่องจากโมเดล AI ที่หิวกระหายข้อมูลต้องการข้อมูลในปริมาณที่พอเหมาะเพื่อความถูกต้องที่ยอมรับได้
ดังนั้นโมเดลนี้สามารถนำไปใช้ได้ใน 6 ขั้นตอนพื้นฐาน:

- กำลังสร้างข้อมูล
- การสร้างแบบจำลอง
- Vectorizing และ De-vectorising ข้อมูล
- การสร้างชุดข้อมูล
- ฝึกโมเดล
- การทดสอบโมเดล
ก่อนที่เราจะลงลึกถึงการนำโมเดลไปใช้งาน เรามานำเข้าไลบรารีที่จำเป็นทั้งหมดก่อน
| นำเข้า numpy เป็น np นำเข้า เทนเซอร์โฟลว์ เป็น tf จาก tensorflow.keras.models นำเข้า Sequential จาก tensorflow.keras.layers นำเข้า หนาแน่น, ออกกลางคัน, SimpleRNN, RepeatVector, TimeDistributed จาก tensorflow.keras.callbacks นำเข้า EarlyStopping, LambdaCallback จาก termcolor นำเข้า สี |
1. การสร้างข้อมูล
มากำหนดสตริงอักขระที่มีอักขระทั้งหมดที่เราต้องการสำหรับการเขียนสมการเลขคณิตพื้นฐาน ดังนั้น สตริงจึงประกอบด้วยอักขระทั้งหมดตั้งแต่ 0-9 และตัวดำเนินการเลขคณิตทั้งหมด เช่น /, *, +, -, .(ทศนิยม)
เราไม่สามารถป้อนข้อมูลตัวเลขลงในแบบจำลองของเราได้โดยตรง เราต้องส่งข้อมูลในรูปแบบของเทนเซอร์ การแปลงสตริงในข้อมูลเป็นเวคเตอร์ที่เข้ารหัสแบบร้อนครั้งเดียวจะทำให้เรามีประสิทธิภาพของโมเดลที่เหมาะสมที่สุด vector ที่เข้ารหัสแบบ hot เดียวคืออาร์เรย์ที่มีความยาวเท่ากับความยาวของสตริง char ของเรา โดยเวกเตอร์ one-hot vector นั้นจะมีค่าเพียงตัวเดียวที่ดัชนีของอักขระตามลำดับที่ปรากฏในแต่ละสตริง
ตัวอย่างเช่น สมมติว่าสตริงอักขระของเราคือ '0123456789' และหากเราต้องการเข้ารหัสสตริงเช่น '12' เวกเตอร์แบบร้อนครั้งเดียวจะเป็น [ [0,1,0,0,0,0,0,0 ,0,0], [0,0,1,0,0,0,0,0,0,0,0] ]. ในการทำเช่นนั้น เราจำเป็นต้องสร้างพจนานุกรมสองชุดโดยมีดัชนีหนึ่งเป็นคีย์และอักขระเป็นค่า และอีกชุดหนึ่งกลับกัน
| char_string = ' 0123456789/*+- ' num_chars = เลน (char_string) character_to_index = dict ((c, i) สำหรับ i, c ใน การ แจกแจง (char_string)) index_to_character = dict ((i, c) สำหรับ i, c ใน การ แจกแจง (char_string)) |
ตอนนี้ มาเขียนฟังก์ชันที่ส่งกลับสมการเลขคณิตสุ่มพร้อมกับผลลัพธ์ของสมการนั้น
| def ดิวิชั่น (n, d): คืนค่า n / d ถ้า d != 0 อื่น 0 def datagen (): random1 = np.random.randint(ต่ำ = 0 สูง = 100 ) random2 = np.random.randint(ต่ำ = 0 สูง = 100 ) op = np.random.randint(ต่ำ = 0 สูง = 4 ) ถ้า op == 1 : arith = str (random1) + ' + ' + str (random2) res = str ( สุ่ม1 + สุ่ม2) เอลฟ์ op == 1 : arith = str (random1) + ' – ' + str (random2) res = str ( สุ่ม1 – สุ่ม2) เอลฟ์ op == 2 : arith = str (สุ่ม1) + ' * ' + str (สุ่ม2) res = str ( สุ่ม1 * สุ่ม2) อื่นๆ : arith = str (random1) + ' / ' + str (random2) res = str ( รอบ (ดิวิชั่น(สุ่ม1,สุ่ม2), 2 )) คืนค่า arith, res |
อ่านเพิ่มเติม: แนวคิดโครงการโครงข่ายประสาทเทียมที่น่าสนใจ
2. การสร้างแบบจำลอง
โมเดลจะมีตัวเข้ารหัสและตัวถอดรหัส ตัวเข้ารหัสเป็นโมเดล RNN ธรรมดาที่มีรูปร่างอินพุตเป็น (None,num_chars) และ 128 หน่วยที่ซ่อนอยู่ เหตุผลที่เราเลือกหน่วยที่ซ่อนอยู่เป็น 32,64,128 เป็นต้น เป็นเพราะประสิทธิภาพที่ดีขึ้นของ CPU หรือ GPU ที่มีหน่วยที่ซ่อนอยู่เป็นพลังของ 2.
ตัวเข้ารหัสของเราจะเป็นเครือข่ายที่เชื่อมต่ออย่างสมบูรณ์ และเอาต์พุตของสิ่งเหล่านี้จะถูกป้อนกลับเข้าสู่เครือข่าย นั่นคือวิธีการทำงานของ RNN เลเยอร์ RNN ใช้การเปิดใช้งาน 'tanh' โดยค่าเริ่มต้น เราจะไม่เปลี่ยนแปลงเพราะว่าเหมาะสมที่สุดกับตัวเข้ารหัส ผลลัพธ์ของเลเยอร์นี้จะเป็นเวกเตอร์เดียว และเพื่อให้ได้เวกเตอร์เดียวของผลลัพธ์ทั้งหมด เราจะใช้เลเยอร์ RepeatVector() ด้วยจำนวนครั้งที่ต้องการเป็นพารามิเตอร์
ตอนนี้เวกเตอร์เอาท์พุตจะมีสาระสำคัญของอินพุตที่กำหนด และเวกเตอร์นี้จะถูกป้อนเข้าไปในตัวถอดรหัส
ตัวถอดรหัสประกอบด้วยเลเยอร์ RNN อย่างง่าย และสิ่งนี้จะสร้างลำดับเอาต์พุต เนื่องจากเราต้องการเลเยอร์ RNN เพื่อส่งคืนลำดับที่คาดการณ์ไว้ เราจะตั้งค่าสถานะ 'return_sequences' เป็น True ด้วยการกำหนด 'return_sequences' เป็น True เลเยอร์ RNN จะส่งคืนลำดับที่คาดการณ์ไว้สำหรับแต่ละขั้นตอนเวลา (หลายต่อหลาย RNN)
เอาต์พุตของเลเยอร์ RNN นี้จะถูกป้อนลงในเลเยอร์หนาแน่นด้วยจำนวนหน่วยที่ซ่อนอยู่ 'num_chars' และเราจะใช้การเปิดใช้งาน softmax เนื่องจากเราต้องการความน่าจะเป็นของอักขระแต่ละตัว ก่อนที่เราจะปรับใช้เลเยอร์ Dense เราจำเป็นต้องย่อเลเยอร์นี้ให้เป็นเลเยอร์ TimeDistributed เนื่องจากเราจำเป็นต้องปรับใช้เลเยอร์ Dense สำหรับผลลัพธ์ของแต่ละขั้นตอน
| hidden_units = 128 max_time_steps = 5 #เรากำลังฮาร์ดโค้ดเอาต์พุตให้มีอักขระ 5 ตัว รุ่น def (): รุ่น = ลำดับ () model.add(SimpleRNN(hidden_units, input_shape = ( None , num_chars))) model.add(RepeatVector(max_time_steps)) model.add(SimpleRNN(hidden_units, return_sequences = True )) model.add (TimeDistributed (หนาแน่น (num_chars, การเปิดใช้งาน = ' softmax ' ))) รูปแบบ การคืน สินค้า รุ่น = รุ่น () model.summary() model.compile(loss = ' categorical_crossentropy ' , เครื่องมือเพิ่มประสิทธิภาพ = ' adam ' , metrics = [ ' ความแม่นยำ ' ]) |

สถาปัตยกรรมของโมเดลจะเป็นตามที่แสดงด้านบน
ต้องอ่าน: บทช่วยสอนเกี่ยวกับโครงข่ายประสาทเทียม
3. Vectorizing และ De-vectorizing ข้อมูล
มากำหนดฟังก์ชันสำหรับ vectorizing และ de-vectorizing ข้อมูลกัน
นี่คือฟังก์ชันสำหรับการแปลงเวกเตอร์นิพจน์เลขคณิตและผลลัพธ์ร่วมกัน
| def vectorize (arith, res): x = np.zeros((max_time_steps, num_chars)) y = np.zeros((max_time_steps, num_chars)) ![]() x_remaining = max_time_steps – เลน (arith) y_remaining = max_time_steps – len (ความละเอียด) สำหรับ ฉัน c ใน การ แจกแจง (arith): x[x_remaining + i, character_to_index[c]] = 1 สำหรับ ฉัน อยู่ใน ช่วง (x_remaining): x[i, character_to_index[ ' 0 ' ]] = 1 สำหรับ ฉัน c ใน การ แจกแจง (res): y[y_remaining + i, character_to_index[c]] = 1 สำหรับ ฉัน อยู่ใน ช่วง (y_remaining): y[i, character_to_index[ ' 0 ' ]] = 1 ผลตอบแทน x, y |
ในทำนองเดียวกัน นี่คือฟังก์ชันสำหรับการดีเวคเตอร์ของสตริง เนื่องจากผลลัพธ์ที่เราได้รับเป็นเวกเตอร์ของความน่าจะเป็น เราจะใช้ np.argmax() ในการเลือกอักขระที่มีความน่าจะเป็นสูงสุด ตอนนี้พจนานุกรม index_to_character ถูกใช้เพื่อติดตามอักขระที่ดัชนีนั้น
| def devectorize (อินพุต): res = [index_to_character[np.argmax(vec)] สำหรับ i, vec ใน การ แจกแจง ( อินพุต )] ส่งคืน ' ' .join(res) |
ตอนนี้ข้อจำกัดที่เรามีกับฟังก์ชัน 'devectorize' คือ มันจะใส่เลขศูนย์ต่ออักขระต่อท้าย ตัวอย่างเช่น หากเวกเตอร์อินพุตคือ ('1-20', '-19') เอาต์พุตที่ยกเลิกการเวกเตอร์จะเป็น ('01-20', '00-19') เราจำเป็นต้องดูแลศูนย์เสริมเหล่านี้ มาเขียนฟังก์ชันสำหรับลอกสตริงกัน
| def ปอก (อินพุต): ธง = เท็จ เอาท์พุท = ' ' สำหรับ c ใน อินพุต : ถ้า ไม่ ตั้งค่าสถานะ และ c == ' 0 ' : ดำเนินต่อ ถ้า c == ' + ' หรือ c == ' – ' หรือ c == ' * ' หรือ c == ' / ' หรือ c == ' _ ' : ธง = เท็จ อื่นๆ : ธง = True เอาต์พุต += c ผลตอบแทน การส่งออก |
4. การสร้างชุดข้อมูล
ตอนนี้เรากำหนดฟังก์ชันสำหรับสร้างข้อมูลเสร็จแล้ว ลองใช้ฟังก์ชันนั้นและสร้างชุดข้อมูลที่มีคู่ (นิพจน์ทางคณิตศาสตร์, ผลลัพธ์) จำนวนมาก
| def create_dataset (num_equations): x_train = np.zeros ((num_equations, max_time_steps, num_chars)) y_train = np.zeros ((num_equations, max_time_steps, num_chars)) สำหรับ ฉัน อยู่ใน ช่วง (num_equations): e, l = datagen() x, y = vectorize (e, l) x_train[i] = x y_train[i] = y กลับ x_train, y_train |
5. การฝึกโมเดล
มาสร้างชุดข้อมูลจำนวน 50,000 ตัวอย่างซึ่งเป็นตัวเลขที่เหมาะสมในการฝึกโมเดลความหิวของข้อมูล เราจะใช้ข้อมูลนี้ 25% สำหรับการตรวจสอบ นอกจากนี้ เรามาสร้างการโทรกลับสำหรับการขัดจังหวะการฝึกอัจฉริยะกัน หากความแม่นยำยังคงไม่เปลี่ยนแปลงเป็นเวลา 8 ยุค สามารถทำได้โดยการตั้งค่าพารามิเตอร์ความอดทนเป็น 8

| x_train, y_train = create_dataset( 50000 ) simple_logger = LambdaCallback ( on_epoch_end = lambda e, l: พิมพ์ ( ' {:.2f} ' .format(l[ ' val_accuracy ' ]), end = ' _ ' ) ) early_stopping = EarlyStopping(จอภาพ = ' val_loss ' ความอดทน = 8 ) model.fit(x_train, y_train, epochs = 100 , validation_split = 0.25 , verbose = 0 , โทรกลับ = [simple_logger, early_stopping]) |
6. การทดสอบโมเดล
ตอนนี้ มาทดสอบโมเดลของเราด้วยการสร้างชุดข้อมูลขนาด 30
| x_test, y_test = create_dataset(num_equations = 20 ) preds = model.predict(x_test) full_seq_acc = 0 สำหรับ ฉัน pred ใน การ แจกแจง (preds): pred_str = การปอก (devectorize(pred)) y_test_str = การปอก (devectorize(y_test[i])) x_test_str = การปอก (devectorize(x_test[i])) col = ' green ' ถ้า pred_str == y_test_str อื่น ' red ' full_seq_acc += 1 / len (preds) * int (pred_str == y_test_str) outstring = ' อินพุต: {}, เอาต์พุต: {}, การคาดการณ์: {} ' .format(x_test_str, y_test_str, pred_str) พิมพ์ (สี(outstring, col)) พิมพ์ ( ' \n ความถูกต้องของลำดับแบบเต็ม: {:.3f} % ' .format ( 100 * full_seq_acc)) |
ผลลัพธ์จะเป็นดังนี้

เราเห็นว่าความแม่นยำนั้นค่อนข้างแย่ อย่างไรก็ตาม เราสามารถเพิ่มประสิทธิภาพได้ด้วยการปรับแต่งไฮเปอร์พารามิเตอร์สองสามตัว เช่น จำนวนหน่วยที่ซ่อนอยู่ การแยกการตรวจสอบ จำนวนยุค ฯลฯ
บทสรุป
เราเข้าใจเวิร์กโฟลว์พื้นฐานของ RNN แล้ว เข้าใจว่า RNN เหมาะสมที่สุดสำหรับข้อมูลตามลำดับ สร้างชุดข้อมูลของสมการเลขคณิตสุ่ม พัฒนาแบบจำลองตามลำดับสำหรับการทำนายผลลัพธ์ของนิพจน์เลขคณิตพื้นฐาน ฝึกโมเดลนั้นด้วยชุดข้อมูลซึ่ง เราได้สร้าง และสุดท้ายได้ทดสอบโมเดลนั้นด้วยชุดข้อมูลเล็กๆ ที่โมเดลไม่เคยเห็นมาก่อน
หากคุณสนใจที่จะเรียนรู้เพิ่มเติมเกี่ยวกับ RNN แมชชีนเลิร์นนิง โปรดดูที่ IIIT-B & upGrad's PG Diploma in Machine Learning & AI ซึ่งออกแบบมาสำหรับมืออาชีพที่ทำงานและมีการฝึกอบรมอย่างเข้มงวดมากกว่า 450 ชั่วโมง กรณีศึกษาและการมอบหมายมากกว่า 30 รายการ สถานะศิษย์เก่า IIIT-B โครงการหลัก 5 โครงการและความช่วยเหลือด้านงานกับบริษัทชั้นนำ
โครงข่ายประสาทเทียมชนิดต่างๆ ในการเรียนรู้ของเครื่องมีอะไรบ้าง
ในการเรียนรู้ของเครื่อง โครงข่ายประสาทเทียมนั้นเป็นแบบจำลองทางคอมพิวเตอร์ที่ออกแบบมาให้คล้ายกับสมองของมนุษย์ มีเครือข่ายประสาทเทียมหลายประเภทที่แมชชีนเลิร์นนิงใช้โดยอิงจากการคำนวณทางคณิตศาสตร์ที่จำเป็นต้องได้รับ โครงข่ายประสาทเทียมเหล่านี้เป็นชุดย่อยของเทคนิคการเรียนรู้ของเครื่องต่างๆ ที่เรียนรู้จากข้อมูลในรูปแบบต่างๆ โครงข่ายประสาทเทียมที่ใช้กันอย่างแพร่หลายบางประเภท ได้แก่ – โครงข่ายประสาทแบบเกิดซ้ำ – หน่วยความจำระยะสั้นระยะยาว, โครงข่ายประสาทเทียมแบบฟีดฟอร์เวิร์ด – เซลล์ประสาทเทียม, โครงข่ายประสาทฟังก์ชันพื้นฐานแนวรัศมี, โครงข่ายประสาทที่จัดระเบียบตัวเองของ Kohonen, โครงข่ายประสาทแบบโค้ง และโครงข่ายประสาทแบบแยกส่วน ท่ามกลางคนอื่น ๆ.
ข้อดีของโครงข่ายประสาทเทียมแบบกำเริบคืออะไร?
โครงข่ายประสาทเทียมที่เกิดซ้ำเป็นหนึ่งในเครือข่ายประสาทเทียมที่ใช้บ่อยที่สุดในการเรียนรู้เชิงลึกและการเรียนรู้ของเครื่อง ในโมเดลโครงข่ายประสาทเทียมประเภทนี้ ผลลัพธ์ที่ได้จากขั้นตอนก่อนหน้าจะถูกป้อนเป็นอินพุตไปยังขั้นตอนถัดไป โครงข่ายประสาทเทียมที่เกิดซ้ำมีข้อดีหลายประการ เช่น สามารถเก็บข้อมูลทุกบิตตลอดเวลา รวมถึงอินพุตก่อนหน้า ซึ่งทำให้เหมาะสำหรับการทำนายอนุกรมเวลา ประเภทนี้เป็นตัวอย่างที่ดีที่สุดของหน่วยความจำสั้นยาว นอกจากนี้ โครงข่ายประสาทเทียมแบบเกิดซ้ำยังให้พื้นที่ใกล้เคียงของพิกเซลที่สร้างสรรค์โดยใช้เลเยอร์แบบ Convolutional
โครงข่ายประสาทเทียมถูกนำมาใช้ในการใช้งานจริงอย่างไร?
โครงข่ายประสาทเทียมเป็นส่วนสำคัญของการเรียนรู้เชิงลึก ซึ่งเป็นสาขาที่เชี่ยวชาญเป็นพิเศษของการเรียนรู้ด้วยเครื่องและปัญญาประดิษฐ์ โครงข่ายประสาทเทียมถูกใช้ในอุตสาหกรรมต่างๆ เพื่อบรรลุวัตถุประสงค์ที่สำคัญต่างๆ แอปพลิเคชั่นที่น่าสนใจที่สุดในโลกแห่งความเป็นจริงของโครงข่ายประสาทเทียม ได้แก่ การพยากรณ์ตลาดหุ้น การจดจำใบหน้า การนำร่องอัตโนมัติที่มีประสิทธิภาพสูง และการวินิจฉัยข้อผิดพลาดในอุตสาหกรรมการบินและอวกาศ การวิเคราะห์การโจมตีด้วยอาวุธและตำแหน่งวัตถุในภาคการป้องกัน การประมวลผลภาพ การค้นพบยาและการตรวจหาโรคในภาคการดูแลสุขภาพ การตรวจสอบลายเซ็น การวิเคราะห์ลายมือ การพยากรณ์อากาศ และการพยากรณ์แนวโน้มโซเชียลมีเดีย เป็นต้น

