การแก้สมการคณิตศาสตร์พื้นฐานโดยใช้ RNN [พร้อมตัวอย่างการเข้ารหัส]

เผยแพร่แล้ว: 2020-12-07

ถ้าชีวิตให้ RNN แก่คุณ ให้สร้างเครื่องคิดเลข

Recurrent Neural Network เป็นหนึ่งในโครงข่ายประสาทเทียมแบบคลาสสิก โดยที่การเชื่อมต่อระหว่างโหนดจะสร้างกราฟกำกับตามลำดับ RNN มีชื่อเสียงในด้านแอปพลิเคชัน เช่น การรู้จำคำพูด การรู้จำลายมือ ฯลฯ เนื่องจากหน่วยความจำสถานะภายในสำหรับการประมวลผลลำดับความยาวแปรผัน

RNNs แบ่งออกเป็นสองประเภทเพิ่มเติม อันแรกคือแรงกระตุ้นที่จำกัดซึ่งโครงข่ายประสาทเทียมอยู่ในรูปแบบของกราฟ acyclic แบบกำกับซึ่งโหนดหนึ่งสามารถเชื่อมต่อกับโหนดอย่างน้อยหนึ่งโหนดที่อยู่ข้างหน้าโดยไม่มีวงจรที่มองเห็นได้ในเครือข่าย อีกประการหนึ่งคือแรงกระตุ้นที่ไม่สิ้นสุดซึ่งโครงข่ายประสาทเทียมอยู่ในรูปแบบของกราฟวัฏจักรโดยตรงซึ่งไม่สามารถคลี่ออกเป็นโครงข่ายประสาทเทียมแบบฟีดฟอร์เวิร์ด

สารบัญ

เราจะทำอะไร?

มาสร้างแบบจำลองที่ทำนายผลลัพธ์ของนิพจน์เลขคณิตกัน ตัวอย่างเช่น หากฉันป้อนค่า '11+88' โมเดลควรคาดเดาคำถัดไปในลำดับเป็น '99' อินพุตและเอาต์พุตเป็นลำดับของอักขระเนื่องจาก RNN เกี่ยวข้องกับข้อมูลตามลำดับ

ตอนนี้การออกแบบสถาปัตยกรรมของโมเดลดูเหมือนเป็นงานง่ายเมื่อเทียบกับการรวบรวมชุดข้อมูล การสร้างข้อมูลหรือการรวบรวมชุดข้อมูลเป็นงานที่ต้องใช้กำลังมาก เนื่องจากโมเดล AI ที่หิวกระหายข้อมูลต้องการข้อมูลในปริมาณที่พอเหมาะเพื่อความถูกต้องที่ยอมรับได้

ดังนั้นโมเดลนี้สามารถนำไปใช้ได้ใน 6 ขั้นตอนพื้นฐาน:

  1. กำลังสร้างข้อมูล
  2. การสร้างแบบจำลอง
  3. Vectorizing และ De-vectorising ข้อมูล
  4. การสร้างชุดข้อมูล
  5. ฝึกโมเดล
  6. การทดสอบโมเดล

ก่อนที่เราจะลงลึกถึงการนำโมเดลไปใช้งาน เรามานำเข้าไลบรารีที่จำเป็นทั้งหมดก่อน

นำเข้า 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

โครงข่ายประสาทเทียมถูกนำมาใช้ในการใช้งานจริงอย่างไร?

โครงข่ายประสาทเทียมเป็นส่วนสำคัญของการเรียนรู้เชิงลึก ซึ่งเป็นสาขาที่เชี่ยวชาญเป็นพิเศษของการเรียนรู้ด้วยเครื่องและปัญญาประดิษฐ์ โครงข่ายประสาทเทียมถูกใช้ในอุตสาหกรรมต่างๆ เพื่อบรรลุวัตถุประสงค์ที่สำคัญต่างๆ แอปพลิเคชั่นที่น่าสนใจที่สุดในโลกแห่งความเป็นจริงของโครงข่ายประสาทเทียม ได้แก่ การพยากรณ์ตลาดหุ้น การจดจำใบหน้า การนำร่องอัตโนมัติที่มีประสิทธิภาพสูง และการวินิจฉัยข้อผิดพลาดในอุตสาหกรรมการบินและอวกาศ การวิเคราะห์การโจมตีด้วยอาวุธและตำแหน่งวัตถุในภาคการป้องกัน การประมวลผลภาพ การค้นพบยาและการตรวจหาโรคในภาคการดูแลสุขภาพ การตรวจสอบลายเซ็น การวิเคราะห์ลายมือ การพยากรณ์อากาศ และการพยากรณ์แนวโน้มโซเชียลมีเดีย เป็นต้น