স্পার্স টেন্সর নিয়ে কাজ করা

TensorFlow.org এ দেখুন Google Colab-এ চালান GitHub এ দেখুন নোটবুক ডাউনলোড করুন

অনেক শূন্য মান ধারণ করে এমন টেনসরগুলির সাথে কাজ করার সময়, সেগুলিকে স্থান- এবং সময়-দক্ষ পদ্ধতিতে সংরক্ষণ করা গুরুত্বপূর্ণ। স্পার্স টেনসরগুলি অনেক শূন্য মান ধারণ করে এমন টেনসরগুলির দক্ষ স্টোরেজ এবং প্রক্রিয়াকরণ সক্ষম করে। স্পার্স টেনসরগুলি এনএলপি অ্যাপ্লিকেশনগুলিতে ডেটা প্রাক-প্রক্রিয়াকরণের অংশ হিসাবে টিএফ-আইডিএফের মতো এনকোডিং স্কিমগুলিতে এবং কম্পিউটার ভিশন অ্যাপ্লিকেশনগুলিতে প্রচুর ডার্ক পিক্সেল সহ ইমেজ প্রাক-প্রসেসিংয়ের জন্য ব্যাপকভাবে ব্যবহৃত হয়।

টেনসরফ্লোতে স্পারস টেনসর

tf.SparseTensor অবজেক্টের মাধ্যমে স্পার্স টেনসর উপস্থাপন করে। বর্তমানে, TensorFlow-এ স্পার্স টেনসরগুলি স্থানাঙ্ক তালিকা (COO) ফর্ম্যাট ব্যবহার করে এনকোড করা হয়েছে। এই এনকোডিং বিন্যাসটি হাইপার-স্পার্স ম্যাট্রিক্স যেমন এমবেডিংয়ের জন্য অপ্টিমাইজ করা হয়েছে।

স্পার্স টেনসরের জন্য COO এনকোডিং এর মধ্যে রয়েছে:

  • values : আকৃতি [N] সহ একটি 1D টেনসর যেখানে সমস্ত অশূন্য মান রয়েছে।
  • indices : আকৃতি [N, rank] সহ একটি 2D টেনসর, যেখানে অশূন্য মানগুলির সূচক রয়েছে।
  • dense_shape : আকৃতি [rank] সহ একটি 1D টেনসর, টেনসরের আকৃতি নির্দিষ্ট করে।

একটি tf.SparseTensor এর প্রসঙ্গে একটি অশূন্য মান হল একটি মান যা স্পষ্টভাবে এনকোড করা হয় না। একটি COO স্পার্স ম্যাট্রিক্সের values স্পষ্টভাবে শূন্য মানগুলি অন্তর্ভুক্ত করা সম্ভব, তবে এই "স্পষ্ট শূন্য" সাধারণত একটি স্পার্স টেনসরে অশূন্য মান উল্লেখ করার সময় অন্তর্ভুক্ত করা হয় না।

একটি tf.SparseTensor তৈরি করা হচ্ছে

সরাসরি তাদের values , indices , এবং dense_shape নির্দিষ্ট করে স্পার্স টেনসর তৈরি করুন।

import tensorflow as tf
st1 = tf.SparseTensor(indices=[[0, 3], [2, 4]],
                      values=[10, 20],
                      dense_shape=[3, 10])

যখন আপনি একটি স্পার্স টেনসর প্রিন্ট করতে print() ফাংশন ব্যবহার করেন, তখন এটি তিনটি উপাদান টেনসরের বিষয়বস্তু দেখায়:

print(st1)
SparseTensor(indices=tf.Tensor(
[[0 3]
 [2 4]], shape=(2, 2), dtype=int64), values=tf.Tensor([10 20], shape=(2,), dtype=int32), dense_shape=tf.Tensor([ 3 10], shape=(2,), dtype=int64))

একটি স্পার্স টেনসরের বিষয়বস্তু বোঝা সহজ হয় যদি অশূন্য values তাদের সংশ্লিষ্ট indices সাথে সারিবদ্ধ করা হয়। প্রিটি-প্রিন্ট করার জন্য একটি সহায়ক ফাংশন সংজ্ঞায়িত করুন স্পার্স টেনসর যাতে প্রতিটি অশূন্য মান তার নিজস্ব লাইনে দেখানো হয়।

def pprint_sparse_tensor(st):
  s = "<SparseTensor shape=%s \n values={" % (st.dense_shape.numpy().tolist(),)
  for (index, value) in zip(st.indices, st.values):
    s += f"\n  %s: %s" % (index.numpy().tolist(), value.numpy().tolist())
  return s + "}>"
print(pprint_sparse_tensor(st1))
<SparseTensor shape=[3, 10] 
 values={
  [0, 3]: 10
  [2, 4]: 20}>

এছাড়াও আপনি tf.sparse.from_dense ব্যবহার করে ঘন টেনসর থেকে স্পারস টেনসর তৈরি করতে পারেন এবং tf.sparse.from_dense ব্যবহার করে তাদের আবার ঘন tf.sparse.to_dense রূপান্তর করতে পারেন।

st2 = tf.sparse.from_dense([[1, 0, 0, 8], [0, 0, 0, 0], [0, 0, 3, 0]])
print(pprint_sparse_tensor(st2))
<SparseTensor shape=[3, 4] 
 values={
  [0, 0]: 1
  [0, 3]: 8
  [2, 2]: 3}>
st3 = tf.sparse.to_dense(st2)
print(st3)
tf.Tensor(
[[1 0 0 8]
 [0 0 0 0]
 [0 0 3 0]], shape=(3, 4), dtype=int32)

স্পার্স টেনসর ম্যানিপুলেট করা

স্পার্স টেনসর ম্যানিপুলেট করতে tf.sparse প্যাকেজের ইউটিলিটিগুলি ব্যবহার করুন। tf.math.add মতো অপ্স যা আপনি ঘন টেনসরের গাণিতিক ম্যানিপুলেশনের জন্য ব্যবহার করতে পারেন স্পারস টেনসরের সাথে কাজ করে না।

tf.sparse.add ব্যবহার করে একই আকৃতির স্পার্স টেনসর যোগ করুন।

st_a = tf.SparseTensor(indices=[[0, 2], [3, 4]],
                       values=[31, 2], 
                       dense_shape=[4, 10])

st_b = tf.SparseTensor(indices=[[0, 2], [7, 0]],
                       values=[56, 38],
                       dense_shape=[4, 10])

st_sum = tf.sparse.add(st_a, st_b)

print(pprint_sparse_tensor(st_sum))
<SparseTensor shape=[4, 10] 
 values={
  [0, 2]: 87
  [3, 4]: 2
  [7, 0]: 38}>

tf.sparse.sparse_dense_matmul ব্যবহার করুন ঘন ম্যাট্রিক্স সহ স্পার্স tf.sparse.sparse_dense_matmul গুণ করতে।

st_c = tf.SparseTensor(indices=([0, 1], [1, 0], [1, 1]),
                       values=[13, 15, 17],
                       dense_shape=(2,2))

mb = tf.constant([[4], [6]])
product = tf.sparse.sparse_dense_matmul(st_c, mb)

print(product)
tf.Tensor(
[[ 78]
 [162]], shape=(2, 1), dtype=int32)

tf.sparse.concat ব্যবহার করে sparse tensors একসাথে রাখুন এবং tf.sparse.concat ব্যবহার করে তাদের আলাদা tf.sparse.slice

sparse_pattern_A = tf.SparseTensor(indices = [[2,4], [3,3], [3,4], [4,3], [4,4], [5,4]],
                         values = [1,1,1,1,1,1],
                         dense_shape = [8,5])
sparse_pattern_B = tf.SparseTensor(indices = [[0,2], [1,1], [1,3], [2,0], [2,4], [2,5], [3,5], 
                                              [4,5], [5,0], [5,4], [5,5], [6,1], [6,3], [7,2]],
                         values = [1,1,1,1,1,1,1,1,1,1,1,1,1,1],
                         dense_shape = [8,6])
sparse_pattern_C = tf.SparseTensor(indices = [[3,0], [4,0]],
                         values = [1,1],
                         dense_shape = [8,6])

sparse_patterns_list = [sparse_pattern_A, sparse_pattern_B, sparse_pattern_C]
sparse_pattern = tf.sparse.concat(axis=1, sp_inputs=sparse_patterns_list)
print(tf.sparse.to_dense(sparse_pattern))
tf.Tensor(
[[0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0]
 [0 0 0 0 1 1 0 0 0 1 1 0 0 0 0 0 0]
 [0 0 0 1 1 0 0 0 0 0 1 1 0 0 0 0 0]
 [0 0 0 1 1 0 0 0 0 0 1 1 0 0 0 0 0]
 [0 0 0 0 1 1 0 0 0 1 1 0 0 0 0 0 0]
 [0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0]], shape=(8, 17), dtype=int32)
sparse_slice_A = tf.sparse.slice(sparse_pattern_A, start = [0,0], size = [8,5])
sparse_slice_B = tf.sparse.slice(sparse_pattern_B, start = [0,5], size = [8,6])
sparse_slice_C = tf.sparse.slice(sparse_pattern_C, start = [0,10], size = [8,6])
print(tf.sparse.to_dense(sparse_slice_A))
print(tf.sparse.to_dense(sparse_slice_B))
print(tf.sparse.to_dense(sparse_slice_C))
tf.Tensor(
[[0 0 0 0 0]
 [0 0 0 0 0]
 [0 0 0 0 1]
 [0 0 0 1 1]
 [0 0 0 1 1]
 [0 0 0 0 1]
 [0 0 0 0 0]
 [0 0 0 0 0]], shape=(8, 5), dtype=int32)
tf.Tensor(
[[0]
 [0]
 [1]
 [1]
 [1]
 [1]
 [0]
 [0]], shape=(8, 1), dtype=int32)
tf.Tensor([], shape=(8, 0), dtype=int32)

আপনি যদি TensorFlow 2.4 বা তার বেশি ব্যবহার করেন, তাহলে sparse tensors-এ nonzero values ​​এ elementwise ক্রিয়াকলাপের জন্য tf.sparse.map_values ব্যবহার করুন।

st2_plus_5 = tf.sparse.map_values(tf.add, st2, 5)
print(tf.sparse.to_dense(st2_plus_5))
tf.Tensor(
[[ 6  0  0 13]
 [ 0  0  0  0]
 [ 0  0  8  0]], shape=(3, 4), dtype=int32)

মনে রাখবেন যে শুধুমাত্র অশূন্য মানগুলি সংশোধন করা হয়েছে - শূন্য মানগুলি শূন্য থাকবে।

সমানভাবে, আপনি TensorFlow এর আগের সংস্করণগুলির জন্য নীচের নকশা প্যাটার্ন অনুসরণ করতে পারেন:

st2_plus_5 = tf.SparseTensor(
    st2.indices,
    st2.values + 5,
    st2.dense_shape)
print(tf.sparse.to_dense(st2_plus_5))
tf.Tensor(
[[ 6  0  0 13]
 [ 0  0  0  0]
 [ 0  0  8  0]], shape=(3, 4), dtype=int32)

অন্যান্য TensorFlow API-এর সাথে tf.SparseTensor ব্যবহার করা

স্পার্স টেনসরগুলি এই টেনসরফ্লো APIগুলির সাথে স্বচ্ছভাবে কাজ করে:

উপরের কয়েকটি API-এর উদাহরণ নিচে দেখানো হয়েছে।

tf.keras

tf.keras API-এর একটি উপসেট ব্যয়বহুল কাস্টিং বা রূপান্তর অপস ছাড়াই স্পার্স টেনসর সমর্থন করে। কেরাস এপিআই আপনাকে কেরাস মডেলে ইনপুট হিসাবে স্পার্স টেনসর পাস করতে দেয়। tf.keras.Input বা tf.keras.layers.InputLayer কল করার সময় sparse=True সেট করুন। আপনি কেরাস স্তরগুলির মধ্যে স্পার্স টেনসরগুলি পাস করতে পারেন এবং কেরাস মডেলগুলিকে আউটপুট হিসাবে ফেরত দিতে পারেন। আপনি যদি আপনার মডেলে tf.keras.layers.Dense লেয়ারে স্পারস টেনসর ব্যবহার করেন, তাহলে তারা ঘন টেনসর আউটপুট করবে।

নীচের উদাহরণটি আপনাকে দেখায় কিভাবে একটি কেরাস মডেলে একটি ইনপুট হিসাবে একটি স্পার্স টেনসর পাস করতে হয় যদি আপনি কেবলমাত্র স্পার্স ইনপুট সমর্থন করে এমন স্তরগুলি ব্যবহার করেন।

x = tf.keras.Input(shape=(4,), sparse=True)
y = tf.keras.layers.Dense(4)(x)
model = tf.keras.Model(x, y)

sparse_data = tf.SparseTensor(
    indices = [(0,0),(0,1),(0,2),
               (4,3),(5,0),(5,1)],
    values = [1,1,1,1,1,1],
    dense_shape = (6,4)
)

model(sparse_data)

model.predict(sparse_data)
array([[-1.3111044 , -1.7598825 ,  0.07225233, -0.44544357],
       [ 0.        ,  0.        ,  0.        ,  0.        ],
       [ 0.        ,  0.        ,  0.        ,  0.        ],
       [ 0.        ,  0.        ,  0.        ,  0.        ],
       [ 0.8517609 , -0.16835624,  0.7307872 , -0.14531797],
       [-0.8916302 , -0.9417639 ,  0.24563438, -0.9029659 ]],
      dtype=float32)

tf.data

tf.data API আপনাকে সহজ, পুনরায় ব্যবহারযোগ্য টুকরা থেকে জটিল ইনপুট পাইপলাইন তৈরি করতে সক্ষম করে। এর মূল ডেটা স্ট্রাকচার হল tf.data.Dataset , যা উপাদানগুলির একটি ক্রম প্রতিনিধিত্ব করে যেখানে প্রতিটি উপাদান এক বা একাধিক উপাদান নিয়ে গঠিত।

স্পার্স টেনসর দিয়ে ডেটাসেট তৈরি করা

tf.Tensor s বা NumPy অ্যারে যেমন tf.data.Dataset.from_tensor_slices থেকে তৈরি করতে ব্যবহৃত একই পদ্ধতি ব্যবহার করে স্পার্স টেনসর থেকে ডেটাসেট তৈরি করুন। এই অপটি ডেটার স্পার্সিটি (বা স্পার্স প্রকৃতি) সংরক্ষণ করে।

dataset = tf.data.Dataset.from_tensor_slices(sparse_data)
for element in dataset: 
  print(pprint_sparse_tensor(element))
<SparseTensor shape=[4] 
 values={
  [0]: 1
  [1]: 1
  [2]: 1}>
<SparseTensor shape=[4] 
 values={}>
<SparseTensor shape=[4] 
 values={}>
<SparseTensor shape=[4] 
 values={}>
<SparseTensor shape=[4] 
 values={
  [3]: 1}>
<SparseTensor shape=[4] 
 values={
  [0]: 1
  [1]: 1}>

স্পার্স টেনসর সহ ডেটাসেট ব্যাচিং এবং আনব্যাচিং

আপনি যথাক্রমে Dataset.batch এবং Dataset.unbatch পদ্ধতি ব্যবহার করে ব্যাচ (একটি উপাদানের মধ্যে পরপর উপাদানগুলিকে একত্রিত করুন) এবং স্পার্স টেনসরগুলির সাথে ডেটাসেটগুলি আনব্যাচ করতে পারেন।

batched_dataset = dataset.batch(2)
for element in batched_dataset:
  print (pprint_sparse_tensor(element))
<SparseTensor shape=[2, 4] 
 values={
  [0, 0]: 1
  [0, 1]: 1
  [0, 2]: 1}>
<SparseTensor shape=[2, 4] 
 values={}>
<SparseTensor shape=[2, 4] 
 values={
  [0, 3]: 1
  [1, 0]: 1
  [1, 1]: 1}>
unbatched_dataset = batched_dataset.unbatch()
for element in unbatched_dataset:
  print (pprint_sparse_tensor(element))
<SparseTensor shape=[4] 
 values={
  [0]: 1
  [1]: 1
  [2]: 1}>
<SparseTensor shape=[4] 
 values={}>
<SparseTensor shape=[4] 
 values={}>
<SparseTensor shape=[4] 
 values={}>
<SparseTensor shape=[4] 
 values={
  [3]: 1}>
<SparseTensor shape=[4] 
 values={
  [0]: 1
  [1]: 1}>

এছাড়াও আপনি tf.data.experimental.dense_to_sparse_batch ব্যবহার করতে পারেন বিভিন্ন আকারের ডেটাসেট উপাদানগুলিকে স্পার্স tf.data.experimental.dense_to_sparse_batch ব্যাচ করতে।

স্পার্স টেনসর সহ ডেটাসেটগুলিকে রূপান্তর করা

Dataset.map ব্যবহার করে ডেটাসেটে স্পার্স টেনসর রূপান্তর করুন এবং তৈরি করুন।

transform_dataset = dataset.map(lambda x: x*2)
for i in transform_dataset:
  print(pprint_sparse_tensor(i))
<SparseTensor shape=[4] 
 values={
  [0]: 2
  [1]: 2
  [2]: 2}>
<SparseTensor shape=[4] 
 values={}>
<SparseTensor shape=[4] 
 values={}>
<SparseTensor shape=[4] 
 values={}>
<SparseTensor shape=[4] 
 values={
  [3]: 2}>
<SparseTensor shape=[4] 
 values={
  [0]: 2
  [1]: 2}>

tf.train.উদাহরণ

tf.train.Example হল TensorFlow ডেটার জন্য একটি আদর্শ প্রোটোবাফ এনকোডিং। tf.train.Example সাথে স্পার্স টেনসর ব্যবহার করার সময়, আপনি করতে পারেন:

  • tf.SparseTensor ব্যবহার করে একটি tf.io.VarLenFeature এ পরিবর্তনশীল-দৈর্ঘ্যের ডেটা পড়ুন। যাইহোক, আপনার পরিবর্তে tf.io.RaggedFeature ব্যবহার করা উচিত।

  • tf.SparseTensor ব্যবহার করে একটি tf.io.SparseFeature এ নির্বিচারে স্পার্স ডেটা পড়ুন, যা indices , values এবং dense_shape সংরক্ষণ করতে তিনটি পৃথক বৈশিষ্ট্য কী ব্যবহার করে।

tf.function

tf.function ডেকোরেটর Python ফাংশনগুলির জন্য TensorFlow গ্রাফগুলি প্রি-কম্পিউট করে, যা আপনার টেনসরফ্লো কোডের কার্যকারিতাকে উল্লেখযোগ্যভাবে উন্নত করতে পারে। স্পার্স tf.function এবং কংক্রিট ফাংশন উভয়ের সাথে স্বচ্ছভাবে কাজ করে।

@tf.function
def f(x,y):
  return tf.sparse.sparse_dense_matmul(x,y)

a = tf.SparseTensor(indices=[[0, 3], [2, 4]],
                    values=[15, 25],
                    dense_shape=[3, 10])

b = tf.sparse.to_dense(tf.sparse.transpose(a))

c = f(a,b)

print(c)
tf.Tensor(
[[225   0   0]
 [  0   0   0]
 [  0   0 625]], shape=(3, 3), dtype=int32)

শূন্য মান থেকে অনুপস্থিত মানগুলিকে আলাদা করা

tf.SparseTensor এর বেশিরভাগ অপারেশন অনুপস্থিত মান এবং সুস্পষ্ট শূন্য মানগুলিকে অভিন্নভাবে বিবেচনা করে। এটি ডিজাইন অনুসারে — একটি tf.SparseTensor একটি ঘন টেনসরের মতো কাজ করে বলে মনে করা হয়।

যাইহোক, এমন কয়েকটি ক্ষেত্রে রয়েছে যেখানে এটি অনুপস্থিত মান থেকে শূন্য মানগুলিকে আলাদা করতে কার্যকর হতে পারে। বিশেষ করে, এটি আপনার প্রশিক্ষণ ডেটাতে অনুপস্থিত/অজানা ডেটা এনকোড করার একটি উপায়ের অনুমতি দেয়। উদাহরণ স্বরূপ, একটি ব্যবহারের ক্ষেত্রে বিবেচনা করুন যেখানে আপনার স্কোরগুলির একটি টেনসর রয়েছে (যাতে -Inf থেকে +Inf পর্যন্ত যেকোনো ফ্লোটিং পয়েন্ট মান থাকতে পারে), কিছু অনুপস্থিত স্কোর সহ। আপনি একটি স্পার্স টেনসর ব্যবহার করে এই টেনসরটিকে এনকোড করতে পারেন যেখানে স্পষ্ট শূন্যগুলি শূন্য স্কোর হিসাবে পরিচিত কিন্তু অন্তর্নিহিত শূন্য মানগুলি আসলে অনুপস্থিত ডেটা উপস্থাপন করে এবং শূন্য নয়।

উল্লেখ্য যে tf.sparse.reduce_max মতো কিছু অপ্স অনুপস্থিত মানগুলিকে শূন্য হিসাবে বিবেচনা করে না। উদাহরণস্বরূপ, যখন আপনি নীচের কোড ব্লক চালান, তখন প্রত্যাশিত আউটপুট 0 হয়। যাইহোক, এই ব্যতিক্রমের কারণে, আউটপুট হল -3

print(tf.sparse.reduce_max(tf.sparse.from_dense([-5, 0, -3])))
tf.Tensor(-3, shape=(), dtype=int32)

বিপরীতে, যখন আপনি একটি ঘন tf.math.reduce_max প্রয়োগ করেন, আউটপুটটি প্রত্যাশিত হিসাবে 0 হয়।

print(tf.math.reduce_max([-5, 0, -3]))
tf.Tensor(0, shape=(), dtype=int32)

আরও পড়া এবং সম্পদ