Deep Learning – 06 – Neural Networks

Neural Networks

சென்ற எடுத்துக்காட்டில் உள்ளீட்டு அடுக்கில் உள்ள ஒரு நியூரானையும், வெளியீட்டு அடுக்கில் உள்ள ஒரு நியூரானையும் இணைத்து கணிப்பு எவ்வாறு நடக்கிறது என்று பார்த்தோம். இப்போது உள்ளீட்டு அடுக்கில் பல நியூரான்களை அமைத்து அவற்றை வெளியீட்டு அடுக்கில் உள்ள ஒரு நியூரானுடன் இணைத்து கணிப்பினை எவ்வாறு நிகழ்த்துவது என்று பார்க்கலாம். முதலில் இதன் தத்துவார்தங்களை சாதாரண பைதான் நிரல் கொண்டு எழுதிப் புரிந்து கொள்வோம். பின்னர் அதற்கு இணையான டென்சார் நிரலை எவ்வாறு பயன்படுத்துவது என்று பார்க்கலாம்.

Python code

நியூரல் நெட்‌வொர்கில் உள்ள பல்வேறு நியூரான்கள் மாதிரித் தரவுகளுடன் அவற்றுக்கே உரிய பல்வேறு அளவுருக்களை இணைத்து இணைத்து கணிப்புகளை நிகழ்த்துகிறது. முதலில் அளவுருக்ககளின் (parameters – weights, bias) மதிப்புகளை சுழியம் என வைத்து கணிப்புகளை நிகழ்த்திப் பார்க்கும். இந்நிலையில் குறைந்த அளவு கணிப்புகளே சரியாகவும், நிறைய கணிப்புகள் தவறாகவும் அமையும் பட்சத்தில் அளவுருக்களின் மதிப்புகளை மாற்றி மாற்றி சரியாகக் கணிக்க முயல்கிறது. கடைசியாக ஓரளவுக்கு கணிப்புகள் அனைத்தும் சரியாக அமைந்துவிடும் பட்சத்தில், தனது கற்றலை நிறுத்திக் கொள்கிறது. இத்தகைய கடைசி நிலையில் நாம் பயன்படுத்தியுள்ள அளவுருக்களின் மதிப்பையே எதிர்காலத்தில் வரப்போகின்ற தரவுகளை கணிப்பதற்கு நாம் பயன்படுத்திக் கொள்ளலாம்.

அனைத்து மாதிரித் தரவுகளின் உள்ளீடுகளை வைத்துக் கொண்டு அதன் வெளியீடுகளை சரியாகக் கணிப்பதற்கு, சுழியத்தில் ஆரம்பித்து, கடைசி நிலையை அடையும் வரை அளவுருக்களின் மதிப்பை மாற்றி மாற்றி கணிக்கும் முறையே “முன்னோக்கிப் பரவுதல்” / Forward propagation என்று அழைக்கப்படுகிறது. அளவுருக்களின் மதிப்பை ஒருசில காரணிகளின் அடிப்படையில் மாற்றும் முறைக்கு பின்னோக்கிப் பரவுதல் / Back propagation என்று பெயர்.
இவ்வாறாக முன்னோக்கிப் பின்னோக்கிப் பரவுதல் மூலம் நியூரல் நெட்‌வொர்க்கானது தனது கற்றலை நிகழ்த்துகிறது.

கீழ்க்கண்ட எடுத்துக்காட்டில் உள்ளீட்டுத் தரவு ஒரு 2d array-வைக் கொண்டுள்ளது. அவற்றில் 4 rows மற்றும் ஒவ்வொரு row-விலும் 2 columns உள்ளன. அதாவது 2 features-ஆல் விளக்கப்படும் 4 மாதிரித் தரவுகளைக் கொண்டுள்ளது. இந்த 2 features-ம் உள்ளீட்டு அடுக்கில் அமையும் 2 நியூரான்களாக அமையும். இதற்கான வெளியீடு 0 மற்றும் 1-ஆக உள்ளது. எனவே இது logistic regression-க்கான எடுத்துக்காட்டு என்பதால், இதற்கான வெளியீட்டு layer-ல் sigmoid activation fn பயன்படுத்தப்பட்டுள்ளது.


from sklearn import datasets
import numpy as np
X_data = np.array([[0.4,0.3],[0.6,0.8],[0.7,0.5],[0.9,0.2]])
Y_data = np.array([[1],[1],[1],[0]])
X = X_data.T
Y = Y_data.T
W = np.zeros((X.shape[0], 1))
b = 0
num_samples = float(X.shape[1])
for i in range(1000):
Z = np.dot(W.T,X) + b
pred_y = 1/(1 + np.exp(-Z))
if(i%100 == 0):
print("cost after %d epoch:"%i)
print (-1/num_samples *np.sum(Y*np.log(pred_y) + (1-Y)*(np.log(1-pred_y))))
dW = (np.dot(X,(pred_y-Y).T))/num_samples
db = np.sum(pred_y-Y)/num_samples
W = W – (0.1 * dW)
b = b – (0.1 * db)
print (W,b)

நிரலுக்கான விளக்கம் & வெளியீடு:

cost after 0 epoch: 0.6931471805599453
cost after 100 epoch: 0.5020586179991661
cost after 200 epoch: 0.4448439151612328
cost after 300 epoch: 0.3979115275585397
cost after 400 epoch: 0.3590456846967788
cost after 500 epoch: 0.32654805177827606
cost after 600 epoch: 0.2990946818904699
cost after 700 epoch: 0.2756668906115973
cost after 800 epoch: 0.25548229634006936
cost after 900 epoch: 0.2379373586492477
[[-3.43906374] [ 4.4016814 ]] 1.6577403314904984

மாதிரித் தரவுகள் (Sample data):

மேற்கண்ட உதாரணத்தில் உள்ளீடாக 4 மாதிரித் தரவுகளும் (X_data), அதற்கான வெளியீடாக 4 மாதிரித் தரவுகளும் (Y_data) பயிற்சிக்கு அளிக்கப்பட்டுள்ளன. இதன் வெளியீடானது 0 & 1 என இருப்பதால், இது logistic regression-க்கானது என நாம் தெரிந்து கொள்ளலாம். உள்ளீட்டுக்கான தரவானது 4 rows & 2 columns கொண்ட 2d array ஆக உள்ளது. அதாவது 4 sample data-க்கான 2 features கொடுக்கப்பட்டுள்ளது.
X_data = np.array([[0.4,0.3],[0.6,0.8],[0.7,0.5],[0.9,0.2]])
Y_data = np.array([[1],[1],[1],[0]])

உள்ளீட்டு அடுக்கு (Input Layer):

நியூரல் நெட்‌வொர்க்-ஐப் பொருத்த வரையில் முதல் அடுக்கில் உள்ளீட்டுத் தரவுகளுக்கான features அமைந்திருக்கும். இந்த features-ன் எண்ணிக்கையில் அமைந்த weights & bias அணி உருவாக்கப்பட்டு கணக்கீடுகள் நிகழும். எனவே உள்ளீட்டுத் தரவுகளை transpose செய்து features*sample_records என்று அமையுமாறு மாற்றிக் கொள்ள வேண்டும் (2,4). அவ்வாறே வெளியீட்டுத் தரவுகளைக் கொண்ட அணியின் shape-ம் (4,) என இருக்கும். இதையும் transpose செய்து (1,4)என மாற்றிக் கொள்ள வேண்டும். இவ்வாறே X, Yஉருவாக்கப்படுகிறது.
X = X_data.T
Y = Y_data.T

அளவுருக்களின் துவக்கநிலை மதிப்புகள் (Initializing weights & bias):

இப்போது X.shape[0] என்பது 2 features-ஐயும், X.shape[1] என்பது பயிற்சிக்கு அளிக்கப்பட்டுள்ள 4 மாதிரித் தரவுகளையும் குறிக்கிறது. weights-ஐ 0 என initialize செய்வதற்கு np.zeros() பயன்படுகிறது. இந்த அலகு மாதிரித் தரவுகளில் உள்ள features-ன் எண்ணிக்கைக்கு இணையாக இருக்க வேண்டும் என்பதற்காக X.shape[0] என கொடுக்கப்பட்டு பூஜ்ஜிய அணி உருவாக்கப்பட்டுள்ளது. bias-க்கு துவக்க மதிப்பாக பூஜ்ஜியம் அளிக்கப்படுகிறது.
W = np.zeros((X.shape[0], 1))
b = 0

சகாப்தங்கள் (Epochs):

X.shape[1] என்பது பயிற்சிக்கு அளிக்கப்பட்டுள்ள 4 மாதிரித் தரவுகளைக் குறிக்குமாதலால் இதை வைத்து num_samples எனும் variable உருவாக்கப்படுகிறது. இது cost கண்டுபிடிக்கப் பயன்படுகிறது. அதாவது மொத்தத் தரவுகளில் எவ்வளவு தரவுகளுக்கு கணிப்புகள் தவறாக நிகழ்ந்துள்ளது என்பதைக் கணக்கிடப் பயன்படுகிறது. முதலில் பூஜ்ஜியம் என வரையறுக்கப்பட்ட அளவுருக்களை இணைத்து கணிப்புகளை நிகழ்த்தி cost கண்டுபிடிக்கிறது. இந்த cost அதிகமாக இருக்கும் பட்சத்தில் (அதாவது அதிக அளவு கணிப்புகள் தவறாக நிகழ்ந்திருந்தால்) கொடுக்கப்பட்ட அளவுருக்களை மாற்றி மீண்டும் கணித்து அதற்கான cost கண்டுபிடிக்கிறது. இவ்வாறே for loop மூலம் 1000 சுற்றுகள் செல்கின்றன. ஒவ்வொரு சுற்றும் 1 epoch / சகாப்தம் என்றழைக்கப்படுகிறது. ஒவ்வொரு epoch-லும் முன்னோக்கிப் பரவி தரவுகள் அனைத்தையும் கணிக்கும் முறையும், கணிக்கப்பட்ட தரவுகளுக்கான இழப்பைக் கணக்கிடும் முறையும் , இழப்பு அதிகமாக இருக்கும் பட்சத்தில் பின்னோக்கிப் பரவுதல் முறைப்படி அளவுருக்களை மாற்றும் நிகழ்வும் தொடர்ச்சியாக நடைபெறுகின்றன.

முன்னோக்கிப் பரவுதல் (Forward Propagation):

ஒரு நியூரான் input features-ல் உள்ள மதிப்புகளுடன் weights மற்றும் bias-ஐச் சேர்த்து தனது கணக்கீடுகளைத் தொடங்கும் என ஏற்கெனவே பார்த்தோம். இங்கும் np.dot() மூலம் உள்ளீட்டுத் தரவுடன் சுழியம் எனும் துவக்க மதிப்பைப் பெற்ற weights மற்றும் bias-ஐ இணைத்து Z -ஐக் கணக்கிடுகிறது. இந்த Z என்பது ஒரு நியூரான் கணக்கிட்ட linear முறையில் அமைந்த கணிப்புகள் ஆகும். இதனை logistic regression-க்கு ஏற்ற முறையில் அமைக்க, Z மதிப்பான து sigmoid activation function-க்குள் செலுத்தப்பட்டு 0 / 1 என கணிக்கப்படுகிறது. இதே போன்று ஒவ்வொரு முறையும், மாற்றப்பட்ட அளவுருக்களை இணைத்து கணிப்புகளை நிகழ்த்தும் முறையே forward propagation என்று அழைக்கப்படுகிறது.
Z = np.dot(W.T,X) + b
pred_y = 1/(1 + np.exp(-Z))

இழப்பைக் கணக்கிடுதல் (Finding cost):

சுழியம் என அளவுருக்கள் (parameters = weights/bias) இருக்கும் போது, ஒரு நியூரான் கணிக்கின்ற விஷயம் தவறாக அமைவதற்கான வாய்ப்பு எந்த அளவுக்கு உள்ளது என்பதைக் கணக்கிட்டு வெளிப்படுத்துவதற்கான நிரல் பின்வருமாறு. இதே போன்று ஒவ்வொரு சுற்றிலும் அளவுருக்கள் மாற்றப்பட்டு, கணிப்புகள் நிகழ்த்தப்பட்டு இந்த cost கணக்கிடப்படுகிறது. மொத்தம் 1000 சுற்றுகள் என்பதால் ஒவ்வொரு முறையும் இம்மதிப்புகள் print செய்யப்படுவதைத் தவிர்க்க, சுற்றுகளின் எண்ணிக்கை 100-ன் மடங்காக இருக்கும்போது மட்டுமே இதனை print செய்க எனக்கூற if-ஐப் பயன்படுத்தியுள்ளோம். இதனால் மொத்தம் 10 முறை மட்டுமே cost வெளியிடப்படுகிறது.
if(i%100 == 0):
print(“cost after %d epoch:”%i)
print (-1/num_samples *np.sum(Y*np.log(pred_y) + (1-Y)*(np.log(1-pred_y))))

பின்னோக்கிப் பரவுதல் (Backward Propagation):

ஏற்கெனவே உள்ள அளவுருக்களின் அடிப்படையில் இம்மதிப்பு பின்வரும் வாய்ப்பாடு மூலம் கணக்கிடப்படுகிறது. இம்முறையில் அளவுருக்களுக்கான delta / derivativeஎனும் மிகச் சிறிய மதிப்பு கணக்கிடப்படுகிறது. derivative என்றால் பெறுதி (மூலத்தினின்று பெறுகின்ற மதிப்பு) அல்லது வழித்தோன்றல் என்று பொருள் கொள்ளலாம். Gradient descent எனும் பகுதியில் இம்மதிப்பு எவ்வாறு கணக்கிடப்படுகிறது என்பதைக் கண்டோம். அதாவது உண்மையான மதிப்புக்கும், கணிக்கப்பட்ட மதிப்புக்குமிடையே சாய்வான ஒரு கோடு வரையப்படுகிறது. இச்சாய்வுக் கோட்டின் மதிப்பே derivativeஎன்றழைக்கப்படுகிறது. இதைக் கணக்கிடுவதற்கான வாய்ப்பாடு பின்வருமாறு.
dW = (np.dot(X,(pred_y-Y).T))/num_samples
db = np.sum(pred_y-Y)/num_samples

அளவுருக்களை மேம்படுத்துதல் (updating parameters):

நாம் கொடுத்துள்ள learning rate-ஆல் back propagation மூலம் நாம் கண்டறிந்த பெறுதி மதிப்புகளைப் பெருக்கி, ஏற்கெனவே உள்ள அளவுருக்களின் மதிப்பிலிருந்து கழித்து புதிய அளவுருக்களை நாம் உருவாக்கலாம். learning rate என்பது எந்த அளவுக்கு சிறியதாக நாம் அடுத்த அடியை எடுத்து வைக்க வேண்டும் என்பதைக் குறிக்கும் (இங்கு 0.1 எனக் கொண்டுள்ளோம்).
W = W – (0.1 * dW)
b = b – (0.1 * db)

சரியான அளவுருக்களைக் கண்டுபிடித்தல்(Finding right parameters):

கடைசியாக கடைசி சுற்றில் பயன்படுத்தப்பட்ட அளவுருக்களின் மதிப்பு வெளிப்படுத்தப்படுகிறது. இதையே எதிர்காலத்தில் வரப்போகும் தரவுகளைக் கணிப்பதற்குப் பயன்படுத்திக் கொள்ளலாம்.
weights = [[-3.44] [ 4.40]]
bias = 1.66

TensorFlow code

மேற்கண்ட அதே விஷயத்தை TensorFlow மூலம் வைத்து எழுதியுள்ள நிரல் பின்வருமாறு. இதுவும் மேற்கண்ட அதே வெளியீட்டை வெளியிடும். இதில் பயன்படுத்தியுள்ள functions-ன் தெளிவான விளக்கங்களை shallow neural network எனும் பகுதியில் காணலாம்.


import tensorflow as tf
X_data = tf.constant([[0.4,0.3],[0.6,0.8],[0.7,0.5],[0.9,0.2]],name="input_value")
Y_data = tf.constant([[1.0],[1.0],[1.0],[0.0]],name="output_value")
X = tf.transpose(X_data)
Y = tf.transpose(Y_data)
W = tf.Variable(initial_value=tf.zeros([1,X.shape[0]], dtype=tf.float32),name="weight")
b = tf.Variable(initial_value=tf.zeros([1,1], dtype=tf.float32))
Z = tf.matmul(W,X) + b
cost = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=Z,labels=Y))
GD = tf.train.GradientDescentOptimizer(0.1).minimize(cost)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
for i in range(1000):
c = sess.run([GD, cost])[1]
if i % 100 == 0:
print ("cost after %d epoch:"%i)
print(c)
print (sess.run(W),sess.run(b))

%d bloggers like this: