विरल टेंसर के साथ काम करना

TensorFlow.org पर देखें Google Colab में चलाएं गिटहब पर देखें नोटबुक डाउनलोड करें

बहुत सारे शून्य मान वाले टेंसर के साथ काम करते समय, उन्हें एक स्थान- और समय-कुशल तरीके से संग्रहीत करना महत्वपूर्ण है। विरल टेंसर कुशल भंडारण और टेंसर के प्रसंस्करण को सक्षम करते हैं जिसमें बहुत अधिक शून्य मान होते हैं। एनएलपी अनुप्रयोगों में डेटा प्री-प्रोसेसिंग के हिस्से के रूप में टीएफ-आईडीएफ जैसी एन्कोडिंग योजनाओं में विरल टेंसर का व्यापक रूप से उपयोग किया जाता है और कंप्यूटर विज़न अनुप्रयोगों में बहुत सारे डार्क पिक्सल के साथ प्री-प्रोसेसिंग छवियों के लिए।

TensorFlow में विरल टेंसर

TensorFlow tf.SparseTensor ऑब्जेक्ट के माध्यम से विरल टेंसर का प्रतिनिधित्व करता है। वर्तमान में, TensorFlow में विरल टेंसर समन्वय सूची (COO) प्रारूप का उपयोग करके एन्कोड किए गए हैं। यह एन्कोडिंग प्रारूप एम्बेडिंग जैसे हाइपर-स्पैस मैट्रिसेस के लिए अनुकूलित है।

विरल टेंसर के लिए सीओओ एन्कोडिंग में निम्न शामिल हैं:

  • values : आकार के साथ एक 1D टेंसर [N] जिसमें सभी गैर-शून्य मान होते हैं।
  • indices : आकार के साथ एक 2D टेंसर [N, rank] , जिसमें गैर-शून्य मानों के सूचकांक होते हैं।
  • dense_shape : आकार के साथ एक 1D टेंसर [rank] , टेंसर के आकार को निर्दिष्ट करता है।

tf.SparseTensor के संदर्भ में एक गैर-शून्य मान एक ऐसा मान है जो स्पष्ट रूप से एन्कोड नहीं किया गया है। सीओओ विरल मैट्रिक्स के values में शून्य मानों को स्पष्ट रूप से शामिल करना संभव है, लेकिन इन "स्पष्ट शून्य" को आम तौर पर शामिल नहीं किया जाता है जब एक विरल टेंसर में गैर-शून्य मानों का जिक्र होता है।

एक tf.SparseTensor Creating बनाना

विरल टेंसरों का निर्माण सीधे उनके 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 का उपयोग करें।

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 का उपयोग करके विरल टेंसरों को एक साथ रखें और 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 या इसके बाद के संस्करण का उपयोग कर रहे हैं, तो 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 का उपयोग करना

विरल टेंसर इन TensorFlow API के साथ पारदर्शी रूप से काम करते हैं:

उपरोक्त कुछ एपीआई के उदाहरण नीचे दिखाए गए हैं।

tf.keras

tf.keras API का एक सबसेट महंगी कास्टिंग या रूपांतरण ऑप्स के बिना विरल टेंसर का समर्थन करता है। Keras API आपको Keras मॉडल के इनपुट के रूप में विरल टेंसर पास करने देता है। tf.keras.Input या tf.keras.layers.InputLayer को कॉल करते समय sparse 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 का उपयोग अलग-अलग आकार के डेटासेट तत्वों को विरल टेंसर में बैचने के लिए भी कर सकते हैं।

विरल टेंसर के साथ डेटासेट बदलना

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}>
प्लेसहोल्डर33

tf.ट्रेन।उदाहरण

tf.train.Example TensorFlow डेटा के लिए एक मानक प्रोटोबफ़ एन्कोडिंग है। tf.train.Example के साथ विरल टेंसर का उपयोग करते समय, आप यह कर सकते हैं:

  • चर-लंबाई वाले डेटा को tf.SparseTensor का उपयोग करके tf.io.VarLenFeature में पढ़ें। हालांकि, आपको इसके बजाय tf.io.RaggedFeature का उपयोग करने पर विचार करना चाहिए।

  • tf.io.SparseFeature tf.SparseTensor मनमाने ढंग से विरल डेटा पढ़ें, जो indices , values और dense_shape को संग्रहीत करने के लिए तीन अलग-अलग सुविधा कुंजियों का उपयोग करता है।

tf.function

tf.function डेकोरेटर पायथन फ़ंक्शन के लिए TensorFlow ग्राफ़ की पूर्व-गणना करता है, जो आपके 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)
34 एल10एन-प्लेसहोल्डर
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)

आगे पढ़ने और संसाधन