समस्या
मल्टी-हेड अटेंशन Transformer को एक साथ कई चीज़ों पर ध्यान देने देता है। इनपुट X (n टोकन × d कॉलम) और d × d वज़न मैट्रिक्स के साथ:
- Q = X × w_q, K = X × w_k, V = X × w_v
- d कॉलम को
num_headsहेड में बाँटें, हर हेड में d_k = d / num_heads लगातार कॉलम (हेड h कॉलम h×d_k से (h+1)×d_k - 1 तक उपयोग करता है)। - हर हेड के लिए उसके कॉलम पर स्केल्ड डॉट-प्रोडक्ट अटेंशन चलाएँ: टोकन i के लिए उस हेड के कॉलम पर score_j = (Q_i · K_j) / √d_k, सभी n टोकन j पर softmax, और आउटपुट = Σ weight_j × V_j (उस हेड के कॉलम)।
- हेड के आउटपुट को उनके कॉलम में वापस रखें (कॉन्कैटिनेशन) और w_o से गुणा करें।
multi_head_attention(x, w_q, w_k, w_v, w_o, num_heads) लागू करें।
इनपुट
x: n × d इनपुट मैट्रिक्स।
w_q, w_k, w_v, w_o: d × d वज़न मैट्रिक्स।
num_heads: हेड की संख्या (d इससे विभाज्य है)।
आउटपुट
n × d आउटपुट मैट्रिक्स लौटाएँ।
सीमाएँ
1 ≤ n ≤ 30, 1 ≤ d ≤ 32, 1 ≤ num_heads ≤ d और d, num_heads से विभाज्य है
-5 ≤ हर मान ≤ 5
उदाहरण
इनपुट:
x = [
[1.0, 0.0],
[0.0, 1.0]
]
w_k = [
[1.0, 0.0],
[0.0, 1.0]
]
w_o = [
[1.0, 0.0],
[0.0, 1.0]
]
w_q = [
[0.0, 0.0],
[0.0, 0.0]
]
w_v = [
[1.0, 0.0],
[0.0, 1.0]
]
num_heads = 1
अपेक्षित आउटपुट:
expected = [
[0.5, 0.5],
[0.5, 0.5]
]
इनपुट:
std::vector<std::vector<double>> x = {
{1.0, 0.0},
{0.0, 1.0}
};
std::vector<std::vector<double>> w_k = {
{1.0, 0.0},
{0.0, 1.0}
};
std::vector<std::vector<double>> w_o = {
{1.0, 0.0},
{0.0, 1.0}
};
std::vector<std::vector<double>> w_q = {
{0.0, 0.0},
{0.0, 0.0}
};
std::vector<std::vector<double>> w_v = {
{1.0, 0.0},
{0.0, 1.0}
};
long long num_heads = 1;
अपेक्षित आउटपुट:
std::vector<std::vector<double>> expected = {
{0.5, 0.5},
{0.5, 0.5}
};
इनपुट:
double[][] x = new double[][] {
new double[] {1.0, 0.0},
new double[] {0.0, 1.0}
};
double[][] w_k = new double[][] {
new double[] {1.0, 0.0},
new double[] {0.0, 1.0}
};
double[][] w_o = new double[][] {
new double[] {1.0, 0.0},
new double[] {0.0, 1.0}
};
double[][] w_q = new double[][] {
new double[] {0.0, 0.0},
new double[] {0.0, 0.0}
};
double[][] w_v = new double[][] {
new double[] {1.0, 0.0},
new double[] {0.0, 1.0}
};
long num_heads = 1;
अपेक्षित आउटपुट:
double[][] expected = new double[][] {
new double[] {0.5, 0.5},
new double[] {0.5, 0.5}
};
व्याख्या
w_q पूरी तरह शून्य है, इसलिए सभी स्कोर 0 हैं और हर टोकन वैल्यू पंक्तियों का औसत लेता है: V = X, इसलिए दोनों पंक्तियाँ [0.5, 0.5] बन जाती हैं।
इनपुट:
x = [
[2.0, 4.0]
]
w_k = [
[1.0, 0.0],
[0.0, 1.0]
]
w_o = [
[0.0, 1.0],
[1.0, 0.0]
]
w_q = [
[1.0, 0.0],
[0.0, 1.0]
]
w_v = [
[1.0, 0.0],
[0.0, 1.0]
]
num_heads = 2
अपेक्षित आउटपुट:
expected = [
[4.0, 2.0]
]
इनपुट:
std::vector<std::vector<double>> x = {
{2.0, 4.0}
};
std::vector<std::vector<double>> w_k = {
{1.0, 0.0},
{0.0, 1.0}
};
std::vector<std::vector<double>> w_o = {
{0.0, 1.0},
{1.0, 0.0}
};
std::vector<std::vector<double>> w_q = {
{1.0, 0.0},
{0.0, 1.0}
};
std::vector<std::vector<double>> w_v = {
{1.0, 0.0},
{0.0, 1.0}
};
long long num_heads = 2;
अपेक्षित आउटपुट:
std::vector<std::vector<double>> expected = {
{4.0, 2.0}
};
इनपुट:
double[][] x = new double[][] {
new double[] {2.0, 4.0}
};
double[][] w_k = new double[][] {
new double[] {1.0, 0.0},
new double[] {0.0, 1.0}
};
double[][] w_o = new double[][] {
new double[] {0.0, 1.0},
new double[] {1.0, 0.0}
};
double[][] w_q = new double[][] {
new double[] {1.0, 0.0},
new double[] {0.0, 1.0}
};
double[][] w_v = new double[][] {
new double[] {1.0, 0.0},
new double[] {0.0, 1.0}
};
long num_heads = 2;
अपेक्षित आउटपुट:
double[][] expected = new double[][] {
new double[] {4.0, 2.0}
};
व्याख्या
केवल एक टोकन होने पर हर हेड सिर्फ़ ख़ुद पर ध्यान देता है, इसलिए जोड़ा गया आउटपुट V = [2, 4] है। w_o दोनों कॉलम की अदला-बदली करता है: [4, 2]।
कैसे हल करें
पहले खुद कोशिश करें, फिर एक-एक करके संकेत खोलें।
संकेत 1
पहले input को queries, keys, और values में project करें, फिर feature dimension को equal head-sized chunks में split करें.
संकेत 2
हर head के अंदर वही attention procedure independently run करें, scaling के लिए smaller head dimension use करके.
संकेत 3
Final output projection से पहले head outputs को उनके original column order में concatenate करें, और matrix dimensions को carefully aligned रखें.
अपेक्षित जटिलता
समय O(n^2 * d + n * d^2), अतिरिक्त स्थान O(n * d)
संदर्भ
यह चुनौती CodeUtility के लिए अनुकूलित की गई है। ऊपर दिए गए स्टेटमेंट और सीमाओं का पालन करें।