মেশিন লার্নিং সিস্টেম গুলোতে ডেটা স্ট্র্যাকচার হিসেবে টেনসর ব্যবহার করা হয়। টেনসর সম্পর্কে এর আগে আরেকটি লেখা লিখেছি, সেখানে টেনসর সম্পর্কে বিস্তারিত জানা যাবে। এই লেখাতে আমরা টেনসফ্লোতে কিভাবে টেনসর ব্যবহার করব, কিভাবে টেনসরের বিভিন্ন অপারেশন করব, তা দেখব।
সবার আগে জানা যাক কিভাবে টেনসরফ্লো ইম্পোর্ট করা যায়। যদিও ইতিমধ্যে সবাই জানি, এরপরও দেখিঃ
# import tensorflow import tensorflow as tf print(tf.__version__)
উপরে টেনসরফ্লো ইম্পোর্টের পাশাপাশি টেনসরফ্লো এর কোন ভার্সন ব্যবহার করছি, তা আউটপুট দিবে।
টেনসর হচ্ছে অ্যারের মত ডেটা টাইপ। অন্য সব ডেটা টাইপের মত আমরা কনস্টেন্ট(অপরিবর্তনশীল) অথবা ভ্যারিয়েবল(পরিবর্তনশীল) টেনসর তৈরি করতে পারি। কনস্টেন্ট টেনসর তৈরি করার জন্য tf.constant ব্যবহার করা হয়।
স্কেলার বা 0 র্যাঙ্ক টেনসর
কোন টেনসরে যদি শুধু মাত্র একটা নাম্বার স্টোর করা হয়, তাহলে তাকে বলে স্কেলার বা 0 র্যাঙ্ক টেনসর বা স্কেলার টেনসর।
scalar = tf.constant(5) scalar
স্কেলার টেনসরের ডাইমেনশন আমরা এভাবে দেখতে পারিঃ
scalar.ndim
যা আউটটপুট দিবেঃ 0
ভেক্টর বা 1 র্যাঙ্ক টেনসর
একের অধিক নাম্বারের লিস্টকে বলে ভেক্টর বা 1 র্যাঙ্ক টেনসরঃ
vector = tf.constant([1, 3, 5, 7]) vector
উপরের ভেক্টরের যদি ডাইমেনশন দেখতে চাই, তাহলে এভাবে দেখতে পারিঃ
vector.ndim
যা আউটটপুট দিবেঃ 1
ম্যাট্রিক্স বা 2 র্যাঙ্ক টেনসর
একের অধিক ভেক্টরের অ্যারে হচ্ছে ম্যাট্রিক্স বা 2 র্যাঙ্ক টেনসর।
matrix = tf.constant([[1, 2], [3, 4], [5, 6]]) matrix
যদি ডাইমেনশন দেখি, তাহলে দেখবঃ
matrix.ndim
যা আউটটপুট দিবেঃ 2
3D টেনসর
একের অধিক 2D টেনসরের অ্যারে হচ্ছে 3D টেনসর।
rank_3_tensor = tf.constant([[[1,2,3], [4,5,6]], [[7,8,9], [10,11,12]], [[13,14,15], [16,17,18]]]) rank_3_tensor
যদি উপরের টেনসরের ডাইমেশন বা র্যাংক দেখতে চাইঃ
tensor.ndim
দেখব 3
আরেকটু সহজ ভাবে যদি যদি বুঝতে চাই, তাহলে বলতে পারি উপরে 3 টি 2D টেনসর রয়েছে।
টেনসর থেকে নামপাই অ্যারে
আমরা চাইলে টেনসরকে নামপাই অ্যারেতে কনভার্ট করতে পারি এভাবেঃ
np.array(tensor)
অথবাঃ
tensor.numpy()
আবার একই ভাবে আমরা চাইলে নামপাইকে টেনসরে কনভার্ট করতে পারিঃ
import numpy as np numpy_a = np.arange(1, 25, dtype=np.int32) numpy_a t_n = tf.constant(numpy_a, shape=(3, 8)) t_n
এভাবেও কোন লিস্টকে টেনসরে কনভার্ট করতে পারিঃ
tf.convert_to_tensor([1,2,3])
টেনসরে ম্যাথ
একটা টেনসরের সাথে স্কেলারের যোগ, বিয়োগ, গুন, ভাগ ইত্যাদি করতে পারিঃ
tensor = tf.constant([[1, 2], [3, 4]]) print(tensor + 10) print(tensor - 100) print(tensor * 10) print(tensor / 10)
এখানে যে যোগ, বিয়োগ, গুন, ভাগ হবে, তা হবে ইলিম্যান্ট ওয়াইজ। মানে যদি ১০ যোগ করি, তাহলে উপরের টেনসরের প্রতিটা আইটেমের সাথেই ১০ যোগ হবে।
একের অধিক টেনসর অন্য সব সংখ্যার মত যোগ বিয়োগ করতে পারিঃ
a = tf.constant([[1, 2], [3, 4]]) b = tf.constant([[1, 1], [1, 1]]) print(tf.add(a, b), "\n") print(tf.multiply(a, b), "\n") print(tf.matmul(a, b), "\n") print(a + b, "\n") # element-wise addition print(a * b, "\n") # element-wise multiplication print(a @ b, "\n") # matrix multiplication উপরের উদাহরণেও ইলিম্যান্টওয়াইজ যোগ, বিয়োগ, গুণ ভাগ হবে। এর মানে হচ্ছে প্রথম টেনসরের প্রথম আইটেমর সাথে দ্বিতীয় টেনসরের প্রথম আইটেম যোগ হবে... এভাবে বাকি সব অপারেশন।
লিস্টের মত অন্যান্য অপারেশনও করতে পারিঃ
c = tf.constant([[4.0, 5.0], [10.0, 1.0]]) # Find the largest value print(tf.reduce_max(c)) # Find the index of the largest value print(tf.math.argmax(c)) # Compute the softmax print(tf.nn.softmax(c))
টেনসরের শেইপঃ
- স্কেলারের কোন শেইপ হয় না।
- ভেক্টরের ক্ষেত্রে শেইপ হচ্ছে ঐ ভেক্টরের লেন্থ বা কত গুলো আইটেম রয়েছে, তা।
- র্যাঙ্ক ২ এর একটা টেনসরের শেইপ হবে দুইটা সংখ্যা। যেমন x,y। যেমনঃ
matrix = tf.constant([[1, 2], [3, 4]]) matrix.shape
যা আউটপুট দিবেঃ TensorShape([2, 2])
এর মানে হচ্ছে উপরের টেনসরের শেইপ হচ্ছে [2,2]
আবার
matrix_2 = tf.constant([[1,2],[3,4], [5,6] ]) matrix_2.shape
যা আউটপুট দিবেঃ TensorShape([3, 2])
এর মানে হচ্ছে উপরের টেনসরের শেইপ হচ্ছে (2,3)
আবার এই শেইপ থেকে আমরা একটা টেনসরে কত গুলো আইটেম রয়েছে, তা বের করে ফেলতে পারি। শেইপ গুলোকে গুন করলেই হয়ে গেলো।
র্যাঙ্ক 3 এর একটা টেনসরের শেইপ হবে এমনঃ x, y , z। যেমনঃ
rank_3_tensor = tf.constant([[[1,2,3], [4,5,6]], [[7,8,9], [10,11,12]], [[13,14,15], [16,17,18]]]) rank_3_tensor.shape
উপরের টেনসরের শেইপ হচ্ছেঃ 3, 2, 3
আরেকটু ক্লিয়াক করে যদি বলি, তাহলে উপরের টেনসরে ৩টি 2*3 সাইজের অ্যারে রয়েছে। যদি আরেকটা আইটেম এড করে শেইপ দেখিঃ
rank_3_tensor = tf.constant([ [[1,2,3], [4,5,6]], [[7,8,9], [10,11,12]], [[13,14,15], [16,17,18]], [[19,20,21], [22,23,24]] ]) rank_3_tensor.shape
আমরা পাবো TensorShape([4, 2, 3])
টেনসররের র্যাঙ্ক এভাবে চিন্তা করতে পারেনঃ যে কোন সংখ্যা হচ্ছে স্কেলার। যার কোন শেইপ নেই। বিক্ষিপ্ত ভাবে ছড়িয়ে ছিটিয়ে রয়েছে। এখন এই সংখ্যা গুলোকে যদি একটা বক্সের ভেতর রাখেন, তাহলে পাবো হচ্ছে 1 র্যাঙ্কের টেনসর বা ভেক্টর। এক বা একাধিক ভেক্টর বা 1 র্যাঙ্কের টেনসর যদি আরেকটা বড় বাক্সে ঢুকাই, তাহলে পাবো র্যাঙ্ক 2 বা ম্যাটিক্স। আবার এক বা এর অধিক ম্যাট্রিক্স যদি আরো বড় একটা বাক্সে ঢুকাই, তাহলে পাবো র্যাঙ্ক ৩ টেনসর।
টেনসর ইন্ডেক্সিং
টেনসর ইন্ডেক্সিং অনেকটা লিস্ট ইন্ডেক্সিং এর মতইঃ
টেনসরের ইন্ডেক্সিংও ০ থেকে শুরু হয়।
rank_1_tensor = tf.constant([1, 3, 5, 7, 9, 11, 13]) print(rank_1_tensor.numpy()) print("First:", rank_1_tensor[0].numpy()) print("Second:", rank_1_tensor[1].numpy()) print("Last:", rank_1_tensor[-1].numpy())
র্যাঙ্ক ২ এর টেনসর ইন্ডেক্সিংঃ
rank_2_tensor = tf.constant([ [1, 2 , 3], [4, 5, 6], [7, 8, 9] ]) print(rank_2_tensor[0, 2].numpy())
উপরের কোড দেখে বলতে পারেন [0, 2] মানে উপরের টেনসরের কোন আইটেমটি? ঠিকই ধরেছেন। 3।
টেনসরের শেইপ পরিবর্তন
রি-শেইপকে ভাবতে পারেন রিএরেঞ্জের মত করে। একটা বক্সের ভেতর আমরা চাইলে যে কোন ভাবেই এর আইটেম গুলো রাখতে পারি। যেমন আমাদের বক্সে ৬টা আইটেম রয়েছে। আগে ছিল প্রতিটা সারিতে ২ টা করে আইটেম। আমরা চাইলে প্রতি সারিতে একটা করে বা তিনটা করে বা ৬টা করে রাখতে পারি। যেমনঃ
matrix = tf.constant([[1, 3], [5, 7], [9, 11]]) matrix.shape
যা আউটপুট দিবেঃ TensorShape([3, 2])
এখন আমরা এটাকে (2,3) শেইপে পরিবর্তন করতে পারি এভাবেঃ
reshaped_matrix = tf.reshape(matrix, [2, 3])
reshaped_matrix
যা আউটপুট দিবেঃ
<tf.Tensor: shape=(2, 3), dtype=int32, numpy= array([[ 1, 3, 5], [ 7, 9, 11]], dtype=int32)>
এইক্ষেত্রে খেয়াল রাখতে হবে আমরা যেভাবেই এরেঞ্জ করতে চাইনা কেনো, যেন শেইপের গুণ সংখ্যা টোটাল আইটেমের সমান হয়। যদি না হয়, তাহলে রিশেইপ করা যাবে না। যেমন আমরা
উপরের টেনসরকে (2,2) শেইপে পরিবর্তন করতে পারব না। চাইলে (6, 1) শেইপে পরিবর্তন করতে পারবঃ
reshaped_matrix = tf.reshape(matrix, [6, 1]) reshaped_matrix
যা আউটপুট দিবেঃ
<tf.Tensor: shape=(6, 1), dtype=int32, numpy= array([[ 1], [ 3], [ 5], [ 7], [ 9], [11]], dtype=int32)>
টেনসরের ডেটা টাইপ
এতক্ষণ টেনসর তৈরির সময় অটোম্যাটিক ডেটাটাইপ এসাইন হয়েছে। আর তা হয়তো int32 বা float64 এমন। আমরা চাইলে স্পেসিফিক ভাবে বলে দিতে পারি কোন ডেটা টাইপের টেনসর তৈরি করবঃ
the_f64_tensor = tf.constant([2.2, 3.3, 4.4], dtype=tf.float64) the_f16_tensor = tf.cast(the_f64_tensor, dtype=tf.float16) # Now, cast to an uint8 and lose the decimal precision the_u8_tensor = tf.cast(the_f16_tensor, dtype=tf.uint8) print(the_u8_tensor)