Tf.nn.conv2d টেনসরফ্লোতে কী করে?


135

আমি tf.nn.conv2d এখানে প্রায় টেনস্রোফ্লো এর ডক্স তাকিয়ে ছিল । তবে এটি কী করে বা এটি অর্জন করার চেষ্টা করছে তা আমি বুঝতে পারি না। এটি ডক্সে বলে,

# 1: আকারটি সহ ফিল্টারটিকে 2-ডি ম্যাট্রিক্সে ফ্ল্যাট করে

[filter_height * filter_width * in_channels, output_channels]

এখন কি করে? সেই উপাদান-ভিত্তিক গুণ বা কেবল সরল ম্যাট্রিক্সের গুণ? ডক্সে উল্লিখিত অন্য দুটি বিষয়ও আমি বুঝতে পারি না। আমি সেগুলি নীচে লিখেছি:

# 2: আকারের ভার্চুয়াল টেনসর গঠনের জন্য ইনপুট টেনসর থেকে চিত্র প্যাচগুলি বের করে

[batch, out_height, out_width, filter_height * filter_width * in_channels]

# 3: প্রতিটি প্যাচের জন্য ফিল্টার ম্যাট্রিক্স এবং চিত্র প্যাচ ভেক্টরকে ডান গুণ করে।

এটি সত্যিই সহায়ক হবে যদি কেউ উদাহরণ দিতে পারে, একটি টুকরো কোড (অত্যন্ত সহায়ক) হতে পারে এবং সেখানে কী চলছে এবং কেন অপারেশনটি এরকম হচ্ছে তা ব্যাখ্যা করে।

আমি একটি ছোট অংশ কোডিং করার চেষ্টা করেছি এবং অপারেশনটির আকারটি মুদ্রণ করেছি। তবুও বুঝতে পারি না।

আমি এরকম কিছু চেষ্টা করেছি:

op = tf.shape(tf.nn.conv2d(tf.random_normal([1,10,10,10]), 
              tf.random_normal([2,10,10,10]), 
              strides=[1, 2, 2, 1], padding='SAME'))

with tf.Session() as sess:
    result = sess.run(op)
    print(result)

আমি বিট এবং কনভোলশনাল নিউরাল নেটওয়ার্কগুলির টুকরোগুলি বুঝতে পারি। আমি তাদের এখানে অধ্যয়ন করেছি । তবে টেনসরফ্লোতে বাস্তবায়ন আমার প্রত্যাশা নয়। সুতরাং এটি প্রশ্ন উত্থাপন।

সম্পাদনা : সুতরাং, আমি অনেক সহজ কোড প্রয়োগ করেছি। তবে কী হচ্ছে তা আমি বুঝতে পারি না। আমি বোঝাতে চাইছি ফলাফলগুলি এরকম কেমন। এটি অত্যন্ত সহায়ক হবে যদি কেউ আমাকে বলতে পারে কোন প্রক্রিয়াটি এই আউটপুটটি দেয়।

input = tf.Variable(tf.random_normal([1,2,2,1]))
filter = tf.Variable(tf.random_normal([1,1,1,1]))

op = tf.nn.conv2d(input, filter, strides=[1, 1, 1, 1], padding='SAME')
init = tf.initialize_all_variables()
with tf.Session() as sess:
    sess.run(init)

    print("input")
    print(input.eval())
    print("filter")
    print(filter.eval())
    print("result")
    result = sess.run(op)
    print(result)

আউটপুট

input
[[[[ 1.60314465]
   [-0.55022103]]

  [[ 0.00595062]
   [-0.69889867]]]]
filter
[[[[-0.59594476]]]]
result
[[[[-0.95538563]
   [ 0.32790133]]

  [[-0.00354624]
   [ 0.41650501]]]]

আসলে জিপিইউ-তে চুডন ডিফল্টরূপে সক্ষম হয় tf.nn.conv2d(), সুতরাং আমরা যখন জিপিইউ সমর্থন সহ টিএফ ব্যবহার করি তখন প্রশ্নে পদ্ধতিটি মোটেই ব্যবহৃত হয় না, যতক্ষণ না use_cudnn_on_gpu=Falseস্পষ্টভাবে নির্দিষ্ট না করা হয়।
gkcn

উত্তর:


59

2 ডি কনভোলিউশনটি একইভাবে গণনা করা হয় যে 1D কনভোলিউশন গণনা করা যায় : আপনি আপনার কার্নেলটিকে ইনপুটটির উপরে স্লাইড করেন, উপাদান-ভিত্তিক গুণগুলি গণনা করুন এবং সেগুলি যোগ করুন। তবে আপনার কার্নেল / ইনপুটটি অ্যারে হওয়ার পরিবর্তে এখানে ম্যাট্রিক রয়েছে।


সর্বাধিক প্রাথমিক উদাহরণে কোনও প্যাডিং এবং স্ট্রাইড = 1 নেই। আসুন আপনার inputএবং ধরে নেওয়া যাক kernel: এখানে চিত্র বর্ণনা লিখুন

আপনি যখন আপনার কার্নেল ব্যবহার করবেন আপনি নিম্নলিখিত আউটপুট পাবেন: এখানে চিত্র বর্ণনা লিখুনযা নিম্নলিখিত উপায়ে গণনা করা হয়:

  • 14 = 4 * 1 + 3 * 0 + 1 * 1 + 2 * 2 + 1 * 1 + 0 * 0 + 1 * 0 + 2 * 0 + 4 * 1
  • 6 = 3 * 1 + 1 * 0 + 0 * 1 + 1 * 2 + 0 * 1 + 1 * 0 + 2 * 0 + 4 * 0 + 1 * 1
  • 6 = 2 * 1 + 1 * 0 + 0 * 1 + 1 * 2 + 2 * 1 + 4 * 0 + 3 * 0 + 1 * 0 + 0 * 1
  • 12 = 1 * 1 + 0 * 0 + 1 * 1 + 2 * 2 + 4 * 1 + 1 * 0 + 1 * 0 + 0 * 0 + 2 * 1

টিএফ এর কনফ 2 ডি ফাংশন ব্যাচগুলিতে কনভোলিউশন গণনা করে এবং কিছুটা আলাদা ফর্ম্যাট ব্যবহার করে। একটি ইনপুট [batch, in_height, in_width, in_channels]জন্য এটি কার্নেলের জন্য এটি [filter_height, filter_width, in_channels, out_channels]। সুতরাং আমাদের সঠিক বিন্যাসে ডেটা সরবরাহ করতে হবে:

import tensorflow as tf
k = tf.constant([
    [1, 0, 1],
    [2, 1, 0],
    [0, 0, 1]
], dtype=tf.float32, name='k')
i = tf.constant([
    [4, 3, 1, 0],
    [2, 1, 0, 1],
    [1, 2, 4, 1],
    [3, 1, 0, 2]
], dtype=tf.float32, name='i')
kernel = tf.reshape(k, [3, 3, 1, 1], name='kernel')
image  = tf.reshape(i, [1, 4, 4, 1], name='image')

পরে সমঝোতার সাথে গণনা করা হয়:

res = tf.squeeze(tf.nn.conv2d(image, kernel, [1, 1, 1, 1], "VALID"))
# VALID means no padding
with tf.Session() as sess:
   print sess.run(res)

এবং আমরা হাত দ্বারা গণনা করা একটি সমতুল্য হবে।


প্যাডিং / স্ট্রাইড সহ উদাহরণগুলির জন্য , এখানে একবার দেখুন


দুর্দান্ত উদাহরণ, তবে কিছু লিঙ্ক ভাঙা।
সিলগন

1
@ সিলগন দুঃখজনকভাবে এটি হ'ল কারণ এসও সিদ্ধান্ত নিয়েছিলেন যে তারা যে ডকুমেন্টেশন বৈশিষ্ট্যটি প্রথমে তৈরি করেছিলেন এবং বিজ্ঞাপন দিয়েছিলেন তা সমর্থন করবেন না।
সালভাদোর ডালি

161

ঠিক আছে আমি মনে করি এটি সমস্ত ব্যাখ্যা করার সহজ উপায় সম্পর্কে।


আপনার উদাহরণটি 1 চ্যানেল সহ 1 চিত্র, আকার 2x2। আকার 1x1 এবং 1 চ্যানেল সহ আপনার 1 টি ফিল্টার রয়েছে (আকার উচ্চতা x প্রস্থ x চ্যানেল x ফিল্টারগুলির সংখ্যা)।

এই সাধারণ ক্ষেত্রে ফলাফল 2x2, 1 চ্যানেল চিত্র (আকার 1x2x2x1, চিত্র সংখ্যা x উচ্চতা এক্স প্রস্থ xx চ্যানেল) চিত্রের প্রতিটি পিক্সেল দ্বারা ফিল্টার মান গুণনের ফলাফল।


এখন আরও চ্যানেল চেষ্টা করুন:

input = tf.Variable(tf.random_normal([1,3,3,5]))
filter = tf.Variable(tf.random_normal([1,1,5,1]))

op = tf.nn.conv2d(input, filter, strides=[1, 1, 1, 1], padding='VALID')

এখানে 3x3 চিত্র এবং 1x1 ফিল্টারটিতে প্রতিটি 5 টি চ্যানেল রয়েছে। ফলাফলের চিত্রটি 3 চ্যানেল (আকার 1x3x3x1) সহ 3x3 হবে, যেখানে প্রতিটি পিক্সেলের মান ইনপুট চিত্রের সাথে সম্পর্কিত পিক্সেলের সাথে ফিল্টারের চ্যানেলগুলিতে ডট পণ্য।


এখন একটি 3x3 ফিল্টার সহ

input = tf.Variable(tf.random_normal([1,3,3,5]))
filter = tf.Variable(tf.random_normal([3,3,5,1]))

op = tf.nn.conv2d(input, filter, strides=[1, 1, 1, 1], padding='VALID')

এখানে আমরা 1 চ্যানেল (আকার 1x1x1x1) সহ একটি 1x1 চিত্র পেয়েছি। মান 9, 5-এলিমেন্ট ডট পণ্যগুলির যোগফল। তবে আপনি এটিকে একটি 45-উপাদান ডট পণ্য বলতে পারেন।


এখন একটি বড় চিত্র সঙ্গে

input = tf.Variable(tf.random_normal([1,5,5,5]))
filter = tf.Variable(tf.random_normal([3,3,5,1]))

op = tf.nn.conv2d(input, filter, strides=[1, 1, 1, 1], padding='VALID')

আউটপুটটি 3x3 1-চ্যানেল চিত্র (আকার 1x3x3x1)। এই মানগুলির প্রতিটি 9, 5-এলিমেন্ট ডট পণ্যগুলির যোগফল।

প্রতিটি আউটপুট ফিল্টারকে ইনপুট চিত্রের 9 টি কেন্দ্রের পিক্সেলের একটিতে কেন্দ্র করে তৈরি করা হয়, যাতে ফিল্টারটি কোনওরই বাইরে না যায়। xনিচে গুলি প্রতিটি আউটপুট পিক্সেলের জন্য ফিল্টার কেন্দ্র প্রতিনিধিত্ব করে।

.....
.xxx.
.xxx.
.xxx.
.....

এখন "একই" প্যাডিং সহ:

input = tf.Variable(tf.random_normal([1,5,5,5]))
filter = tf.Variable(tf.random_normal([3,3,5,1]))

op = tf.nn.conv2d(input, filter, strides=[1, 1, 1, 1], padding='SAME')

এটি একটি 5x5 আউটপুট চিত্র দেয় (আকার 1x5x5x1)। এটি চিত্রের প্রতিটি অবস্থানে ফিল্টারকে কেন্দ্র করে করা হয়।

যে কোনও 5-এলিমেন্ট ডট পণ্য যেখানে ফিল্টারটি চিত্রের প্রান্তের বাইরে চলে যায় শূন্যের মান পায়।

সুতরাং কোণগুলি 4, 5-এলিমেন্ট ডট পণ্যগুলির যোগফল।


এখন একাধিক ফিল্টার সহ।

input = tf.Variable(tf.random_normal([1,5,5,5]))
filter = tf.Variable(tf.random_normal([3,3,5,7]))

op = tf.nn.conv2d(input, filter, strides=[1, 1, 1, 1], padding='SAME')

এটি এখনও একটি 5x5 আউটপুট চিত্র দেয় তবে channels টি চ্যানেল (আকার 1x5x5x7)। যেখানে প্রতিটি চ্যানেল সেটের একটি ফিল্টার দ্বারা উত্পাদিত হয়।


এখন ২,২ পদক্ষেপ সহ:

input = tf.Variable(tf.random_normal([1,5,5,5]))
filter = tf.Variable(tf.random_normal([3,3,5,7]))

op = tf.nn.conv2d(input, filter, strides=[1, 2, 2, 1], padding='SAME')

এখন ফলাফলটিতে এখনও 7 টি চ্যানেল রয়েছে তবে এটি কেবল 3x3 (আকার 1x3x3x7)।

এটি কারণ চিত্রটির প্রতিটি বিন্দুতে ফিল্টারগুলি কেন্দ্র করে না রেখে, ফিল্টারগুলি চিত্রের প্রতিটি পয়েন্টে কেন্দ্রিক হয়, প্রস্থের ২ (পদক্ষেপ) গ্রহণ করে থাকে xbelow নীচের অংশে প্রতিটি আউটপুট পিক্সেলের জন্য ফিল্টার কেন্দ্র উপস্থাপন করে ইনপুট চিত্র।

x.x.x
.....
x.x.x
.....
x.x.x

এবং অবশ্যই ইনপুটটির প্রথম মাত্রাটি হ'ল চিত্রগুলির সংখ্যা যাতে আপনি এটি 10 ​​টি চিত্রের ব্যাচের উপর প্রয়োগ করতে পারেন, উদাহরণস্বরূপ:

input = tf.Variable(tf.random_normal([10,5,5,5]))
filter = tf.Variable(tf.random_normal([3,3,5,7]))

op = tf.nn.conv2d(input, filter, strides=[1, 2, 2, 1], padding='SAME')

ফলাফল হিসাবে 10 টি চিত্রের স্ট্যাক প্রদান করে এটি প্রতিটি ইমেজের জন্য স্বাধীনভাবে একই ক্রিয়াকলাপ সম্পাদন করে (আকার 10x3x3x7)


@ জিজুনলস্ট নং, ডক্সে বলা হয়েছে যে প্রথম এবং শেষ উপাদানটি ১ হতে হবেMust have strides[0] = strides[3] = 1. For the most common case of the same horizontal and vertices strides, strides = [1, stride, stride, 1].
অ্যালেন

এটি কি টোপলিটজ ম্যাট্রিক্স ভিত্তিক বাস্তবায়ন?
gkcn

এটি সম্পর্কে: "এটি এখনও একটি 5x5 আউটপুট চিত্র দেয় তবে channels টি চ্যানেল (আকার 1x5x5x7) রয়েছে Where যেখানে প্রতিটি চ্যানেল সেটের একটি ফিল্টার দ্বারা উত্পাদিত হয়" "7 টি চ্যানেল কোথা থেকে এসেছে তা বুঝতে আমার এখনও অসুবিধা হচ্ছে? "সেটে ফিল্টারগুলি" বলতে কী বোঝ? ধন্যবাদ।
ডেরেক

@ এমডাউস্ট হাই, আপনার দ্বিতীয় উদাহরণটি সম্পর্কে যেখানে the 3x3 image and the 1x1 filter each have 5 channelsআমি জানতে পারি ফলাফলটি ম্যানুয়ালি গণনা করা ডট পণ্য থেকে আলাদা।
টিজিএন ইয়াং

1
@ ডেরেক আমারও একই প্রশ্ন, "আউটপুট_চ্যানেল" "ফিল্টার সংখ্যা" এর মতো কি ??? যদি তা হয় তবে কেন তাদের টেনসরফ্লো ডক্সে "আউটপুট_চ্যানেল" নাম দেওয়া হয়েছে?
ওয়েই

11

কেবলমাত্র অন্য উত্তরগুলিতে যোগ করার জন্য আপনাকে প্যারামিটারগুলির মধ্যে চিন্তা করা উচিত

filter = tf.Variable(tf.random_normal([3,3,5,7]))

প্রতিটি ফিল্টারে চ্যানেলের সংখ্যার সাথে সম্পর্কিত '5'। প্রতিটি ফিল্টার একটি 3 ডি কিউব হয়, যার গভীরতা 5 হয় filter আপনার ফিল্টার গভীরতা অবশ্যই আপনার ইনপুট চিত্রের গভীরতার সাথে সঙ্গতিপূর্ণ। 7, শেষ প্যারামিটারটি ব্যাচের ফিল্টারগুলির সংখ্যা হিসাবে বিবেচনা করা উচিত। এটি 4 ডি হওয়ার কথা ভুলে যাবেন না এবং পরিবর্তে কল্পনা করুন যে আপনার কাছে 7 টি ফিল্টার বা একটি ব্যাচ রয়েছে। আপনি যা করেন তা হল মাত্রা (3,3,5) সহ 7 টি ফিল্টার কিউব।

ফুরিয়ার ডোমেনে ভিজ্যুয়ালাইজ করা অনেক সহজ, যেহেতু কনভলিউশনটি পয়েন্ট-ওয়াইজ গুণে পরিণত হয়। মাত্রাগুলির একটি ইনপুট চিত্রের জন্য (100,100,3) আপনি ফিল্টার মাত্রাগুলি পুনরায় লিখতে পারেন

filter = tf.Variable(tf.random_normal([100,100,3,7]))

Output টি আউটপুট বৈশিষ্ট্য মানচিত্রের মধ্যে একটি পেতে, আমরা কেবল চিত্র ঘনক দিয়ে ফিল্টার কিউবের বিন্দু-ভিত্তিক গুণটি সম্পাদন করি, তারপরে আমরা চ্যানেলগুলি / গভীরতার মাত্রা জুড়ে ফলাফলগুলি সংশ্লেষ করি (এটি এখানে 3), একটি 2 ডি সংক্রমণের ফলে (100,100) বৈশিষ্ট্যের মানচিত্র। প্রতিটি ফিল্টার কিউব দিয়ে এটি করুন এবং আপনি 7 2D বৈশিষ্ট্যের মানচিত্র পাবেন।


8

আমি কনফি 2 ডি প্রয়োগ করার চেষ্টা করেছি (আমার পড়াশুনার জন্য)। ঠিক আছে, আমি লিখেছি:

def conv(ix, w):
   # filter shape: [filter_height, filter_width, in_channels, out_channels]
   # flatten filters
   filter_height = int(w.shape[0])
   filter_width = int(w.shape[1])
   in_channels = int(w.shape[2])
   out_channels = int(w.shape[3])
   ix_height = int(ix.shape[1])
   ix_width = int(ix.shape[2])
   ix_channels = int(ix.shape[3])
   filter_shape = [filter_height, filter_width, in_channels, out_channels]
   flat_w = tf.reshape(w, [filter_height * filter_width * in_channels, out_channels])
   patches = tf.extract_image_patches(
       ix,
       ksizes=[1, filter_height, filter_width, 1],
       strides=[1, 1, 1, 1],
       rates=[1, 1, 1, 1],
       padding='SAME'
   )
   patches_reshaped = tf.reshape(patches, [-1, ix_height, ix_width, filter_height * filter_width * ix_channels])
   feature_maps = []
   for i in range(out_channels):
       feature_map = tf.reduce_sum(tf.multiply(flat_w[:, i], patches_reshaped), axis=3, keep_dims=True)
       feature_maps.append(feature_map)
   features = tf.concat(feature_maps, axis=3)
   return features

আশা করি আমি এটি সঠিকভাবে করেছি। এমএনআইএসটিতে চেক করা হয়েছে, খুব ঘনিষ্ঠ ফলাফল ছিল (তবে এই বাস্তবায়নটি ধীর)। আমি আশা করি এটা আপনাকে সাহায্য করবে।


0

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


সুতরাং মেমোরিতে, কনভলশনটি আসলে ম্যাট্রিক্সের গুণ হিসাবে সম্পাদিত হচ্ছে যা ব্যাখ্যা করে যে বৃহত্তর চিত্রগুলি কেন অগত্যা বৃহত্তর গণনার সময় চালিত হয় না তবে এর পরিবর্তে OOM (মেমরির বাইরে) ত্রুটিতে চলে যাওয়ার সম্ভাবনা বেশি। আপনি কি আমাকে ব্যাখ্যা করতে পারেন যে 2 ডি কনভ্যুশনের তুলনায় 3 ডি কনভোলশনটি আরও মেমরি অদক্ষ / দক্ষ? উদাহরণস্বরূপ [বি, এইচ, ডাব্লু, ডি, সি] এ [বি * সি, এইচ, ডাব্লু, ডি] তে 2 ডি কনভ্যালের তুলনায় থ্রিডি রূপান্তর করা। অবশ্যই, তারা গণনা একই খরচ?
সোমফিজিকস স্টুডেন্ট
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.