मुख्य कंटेंट तक स्किप करें

न्यूरल नेटवर्क आर्किटेक्चर विस्तृत व्याख्या

यह लेख KataGo न्यूरल नेटवर्क के पूर्ण आर्किटेक्चर की गहन व्याख्या करता है, इनपुट फीचर एनकोडिंग से लेकर मल्टी-हेड आउटपुट डिज़ाइन तक।

KataGo एकल न्यूरल नेटवर्क और मल्टी-हेड आउटपुट का डिज़ाइन अपनाता है: मुख्य आधार के रूप में रेसिडुअल टावर (20 से 60 रेसिडुअल ब्लॉक तथा ग्लोबल पूलिंग लेयर) इनपुट फीचर प्लेन से फीचर निकालता है, और फिर Policy (चाल की प्रायिकता), Value (जीत दर), Score (अंकों का अंतर) तथा Ownership (क्षेत्र का स्वामित्व) इन चार आउटपुट हेड में विभाजित होता है।


आर्किटेक्चर अवलोकन

KataGo एकल न्यूरल नेटवर्क, मल्टी-हेड आउटपुट डिज़ाइन का उपयोग करता है:


इनपुट फीचर एनकोडिंग

फीचर प्लेन अवलोकन

KataGo 22 फीचर प्लेन (19×19×22) का उपयोग करता है, प्रत्येक प्लेन एक 19×19 मैट्रिक्स है:

प्लेनसामग्रीविवरण
0अपने पत्थर1 = अपना पत्थर है, 0 = नहीं
1प्रतिद्वंद्वी के पत्थर1 = प्रतिद्वंद्वी का पत्थर है, 0 = नहीं
2खाली बिंदु1 = खाली, 0 = पत्थर है
3-10इतिहास स्थितिपिछली 8 चालों के बोर्ड परिवर्तन
11को निषिद्ध बिंदु1 = यहाँ को है, 0 = खेल सकते हैं
12-17लिबर्टी एनकोडिंग1-लिबर्टी, 2-लिबर्टी, 3-लिबर्टी... समूह
18-21नियम एनकोडिंगचीनी/जापानी नियम, कोमी आदि

इतिहास स्थिति स्टैकिंग

न्यूरल नेटवर्क को स्थिति के गतिशील परिवर्तनों को समझने देने के लिए, KataGo पिछली 8 चालों की बोर्ड स्थिति स्टैक करता है:

# इतिहास स्थिति एनकोडिंग (अवधारणा)
def encode_history(game_history, current_player):
features = []

for t in range(8): # पिछली 8 चालें
if t < len(game_history):
board = game_history[-(t+1)]
# उस समय बिंदु पर अपने/प्रतिद्वंद्वी के पत्थर एनकोड करें
features.append(encode_board(board, current_player))
else:
# इतिहास अपर्याप्त, शून्य भरें
features.append(np.zeros((19, 19)))

return np.stack(features, axis=0)

नियम एनकोडिंग

KataGo कई नियमों का समर्थन करता है, फीचर प्लेन के माध्यम से न्यूरल नेटवर्क को सूचित करता है:

# नियम एनकोडिंग (अवधारणा)
def encode_rules(rules, komi):
rule_features = np.zeros((4, 19, 19))

# नियम प्रकार (one-hot)
if rules == "chinese":
rule_features[0] = 1.0
elif rules == "japanese":
rule_features[1] = 1.0

# कोमी नॉर्मलाइज़ेशन
normalized_komi = komi / 15.0 # [-1, 1] में नॉर्मलाइज़ करें
rule_features[2] = normalized_komi

# वर्तमान खिलाड़ी
rule_features[3] = 1.0 if current_player == BLACK else 0.0

return rule_features

मुख्य नेटवर्क: रेसिड्यूअल टावर

रेसिड्यूअल ब्लॉक संरचना

KataGo Pre-activation ResNet संरचना का उपयोग करता है:

कोड उदाहरण

class ResidualBlock(nn.Module):
def __init__(self, channels):
super().__init__()
self.bn1 = nn.BatchNorm2d(channels)
self.conv1 = nn.Conv2d(channels, channels, 3, padding=1)
self.bn2 = nn.BatchNorm2d(channels)
self.conv2 = nn.Conv2d(channels, channels, 3, padding=1)

def forward(self, x):
residual = x

out = self.bn1(x)
out = F.relu(out)
out = self.conv1(out)

out = self.bn2(out)
out = F.relu(out)
out = self.conv2(out)

return out + residual # रेसिड्यूअल कनेक्शन

ग्लोबल पूलिंग लेयर

KataGo की प्रमुख नवाचारों में से एक: रेसिड्यूअल ब्लॉक में ग्लोबल पूलिंग जोड़ना, नेटवर्क को वैश्विक जानकारी देखने देता है:

class GlobalPoolingBlock(nn.Module):
def __init__(self, channels):
super().__init__()
self.conv = nn.Conv2d(channels, channels, 3, padding=1)
self.fc = nn.Linear(channels, channels)

def forward(self, x):
# लोकल पाथ
local = self.conv(x)

# ग्लोबल पाथ
global_pool = x.mean(dim=[2, 3]) # ग्लोबल एवरेज पूलिंग
global_fc = self.fc(global_pool)
global_broadcast = global_fc.unsqueeze(2).unsqueeze(3)
global_broadcast = global_broadcast.expand(-1, -1, 19, 19)

# मर्ज करें
return local + global_broadcast

ग्लोबल पूलिंग क्यों आवश्यक है?

पारंपरिक कन्वोल्यूशन केवल लोकल (3×3 रिसेप्टिव फील्ड) देखता है, कई लेयर स्टैक करने के बाद भी, वैश्विक जानकारी की धारणा सीमित रहती है। ग्लोबल पूलिंग नेटवर्क को सीधे "देखने" देता है:

  • पूरे बोर्ड पर पत्थरों का अंतर
  • वैश्विक प्रभाव वितरण
  • समग्र स्थिति आकलन

आउटपुट हेड डिज़ाइन

Policy Head (रणनीति हेड)

प्रत्येक स्थिति की चाल प्रायिकता आउटपुट करता है:

class PolicyHead(nn.Module):
def __init__(self, in_channels):
super().__init__()
self.conv = nn.Conv2d(in_channels, 2, 1) # 1×1 कन्वोल्यूशन
self.bn = nn.BatchNorm2d(2)
self.fc = nn.Linear(2 * 19 * 19, 362) # 361 + pass

def forward(self, x):
out = F.relu(self.bn(self.conv(x)))
out = out.view(out.size(0), -1)
out = self.fc(out)
return F.softmax(out, dim=1) # प्रायिकता वितरण

आउटपुट प्रारूप: 362-आयामी वेक्टर

  • इंडेक्स 0-360: बोर्ड पर 361 स्थानों की चाल प्रायिकता
  • इंडेक्स 361: पास की प्रायिकता

Value Head (मूल्य हेड)

वर्तमान स्थिति की जीत दर आउटपुट करता है:

class ValueHead(nn.Module):
def __init__(self, in_channels):
super().__init__()
self.conv = nn.Conv2d(in_channels, 1, 1)
self.bn = nn.BatchNorm2d(1)
self.fc1 = nn.Linear(19 * 19, 256)
self.fc2 = nn.Linear(256, 1)

def forward(self, x):
out = F.relu(self.bn(self.conv(x)))
out = out.view(out.size(0), -1)
out = F.relu(self.fc1(out))
out = torch.tanh(self.fc2(out)) # -1 से +1 आउटपुट
return out

आउटपुट प्रारूप: एकल मान [-1, +1]

  • +1: अपनी निश्चित जीत
  • -1: प्रतिद्वंद्वी की निश्चित जीत
  • 0: समान स्थिति

Score Head (अंक हेड)

KataGo विशेष, अंतिम अंक अंतर का पूर्वानुमान:

class ScoreHead(nn.Module):
def __init__(self, in_channels):
super().__init__()
self.conv = nn.Conv2d(in_channels, 1, 1)
self.bn = nn.BatchNorm2d(1)
self.fc1 = nn.Linear(19 * 19, 256)
self.fc2 = nn.Linear(256, 1)

def forward(self, x):
out = F.relu(self.bn(self.conv(x)))
out = out.view(out.size(0), -1)
out = F.relu(self.fc1(out))
out = self.fc2(out) # अप्रतिबंधित आउटपुट
return out

आउटपुट प्रारूप: एकल मान (अंक)

  • धनात्मक संख्या: अपनी बढ़त
  • ऋणात्मक संख्या: प्रतिद्वंद्वी की बढ़त

Ownership Head (स्वामित्व हेड)

प्रत्येक बिंदु के अंतिम स्वामित्व का पूर्वानुमान:

class OwnershipHead(nn.Module):
def __init__(self, in_channels):
super().__init__()
self.conv1 = nn.Conv2d(in_channels, 32, 1)
self.bn = nn.BatchNorm2d(32)
self.conv2 = nn.Conv2d(32, 1, 1)

def forward(self, x):
out = F.relu(self.bn(self.conv1(x)))
out = torch.tanh(self.conv2(out)) # प्रत्येक बिंदु -1 से +1
return out.view(out.size(0), -1) # 361 में फ्लैटन करें

आउटपुट प्रारूप: 361-आयामी वेक्टर, प्रत्येक मान [-1, +1] में

  • +1: यह बिंदु अपने क्षेत्र का है
  • -1: यह बिंदु प्रतिद्वंद्वी के क्षेत्र का है
  • 0: तटस्थ या विवादित क्षेत्र

AlphaZero से अंतर

पहलूAlphaZeroKataGo
आउटपुट हेड2 (Policy + Value)4 (+ Score + Ownership)
ग्लोबल पूलिंगनहींहाँ
इनपुट फीचर्स17 प्लेन22 प्लेन (नियम एनकोडिंग सहित)
रेसिड्यूअल ब्लॉकमानक ResNetPre-activation + ग्लोबल पूलिंग
मल्टी-रूल समर्थननहींहाँ (फीचर एनकोडिंग के माध्यम से)

मॉडल स्केल

KataGo विभिन्न स्केल के मॉडल प्रदान करता है:

मॉडलरेसिड्यूअल ब्लॉकचैनलपैरामीटरउपयोग परिदृश्य
b10c12810128~5MCPU, त्वरित परीक्षण
b18c38418384~75Mसामान्य GPU
b40c25640256~95Mउच्च-स्तरीय GPU
b60c32060320~200Mटॉप-टियर GPU

नामकरण नियम: b{रेसिड्यूअल ब्लॉक संख्या}c{चैनल संख्या}


पूर्ण नेटवर्क कार्यान्वयन

class KataGoNetwork(nn.Module):
def __init__(self, num_blocks=18, channels=384):
super().__init__()

# प्रारंभिक कन्वोल्यूशन
self.initial_conv = nn.Conv2d(22, channels, 3, padding=1)
self.initial_bn = nn.BatchNorm2d(channels)

# रेसिड्यूअल टावर
self.residual_blocks = nn.ModuleList([
ResidualBlock(channels) for _ in range(num_blocks)
])

# ग्लोबल पूलिंग ब्लॉक (हर कुछ रेसिड्यूअल ब्लॉक के बाद एक डालें)
self.global_pooling_blocks = nn.ModuleList([
GlobalPoolingBlock(channels) for _ in range(num_blocks // 6)
])

# आउटपुट हेड
self.policy_head = PolicyHead(channels)
self.value_head = ValueHead(channels)
self.score_head = ScoreHead(channels)
self.ownership_head = OwnershipHead(channels)

def forward(self, x):
# प्रारंभिक कन्वोल्यूशन
out = F.relu(self.initial_bn(self.initial_conv(x)))

# रेसिड्यूअल टावर
gp_idx = 0
for i, block in enumerate(self.residual_blocks):
out = block(out)

# हर 6 रेसिड्यूअल ब्लॉक के बाद ग्लोबल पूलिंग डालें
if (i + 1) % 6 == 0 and gp_idx < len(self.global_pooling_blocks):
out = self.global_pooling_blocks[gp_idx](out)
gp_idx += 1

# आउटपुट हेड
policy = self.policy_head(out)
value = self.value_head(out)
score = self.score_head(out)
ownership = self.ownership_head(out)

return {
'policy': policy,
'value': value,
'score': score,
'ownership': ownership
}

आगे पढ़ें