बैच तंत्रिकाकरण को गहरे तंत्रिका जाल में पर्याप्त प्रदर्शन सुधार के साथ श्रेय दिया गया है। इंटरनेट पर बहुत सारी सामग्री यह बताती है कि इसे सक्रियण-दर-सक्रियण के आधार पर कैसे लागू किया जाए। मैंने पहले से ही मैट्रिक्स बीजगणित का उपयोग करके बैकप्रॉप लागू किया है, और यह देखते हुए कि मैं उच्च-स्तरीय भाषाओं में काम कर रहा हूं (जबकि Rcpp
घनी मैट्रिक्स गुणन के लिए (और अंततः GPU के) पर भरोसा करते हुए ), सब कुछ बाहर निकाल देना और for
-loops का सहारा लेना शायद उनके कोड को धीमा कर देगा बहुत बड़ा दर्द होने के अलावा।
बैच सामान्यीकरण फ़ंक्शन जहां है
- पी है से पहले ही सक्रिय हो जाता है, वें नोड
- बीटा और स्केलर पैरामीटर हैं
- σ एक्स पी एक्स पी और माध्य और SD का । (ध्यान दें कि विचरण के वर्गमूल के साथ-साथ एक ठगना कारक का आमतौर पर उपयोग किया जाता है - मान लें कि कॉम्पैक्ट के लिए गैर-एस्टेरो तत्व हैं)
मैट्रिक्स के रूप में, एक पूरी परत के लिए बैच सामान्यीकरण जहां
- है
- एक कॉलम वेक्टर है
- और अब प्रति-परत सामान्यीकरण मापदंडों के पंक्ति -vectors हैंपी
- और हैं मैट्रिक्स, जहां प्रत्येक स्तंभ एक है -vector columnwise अर्थ है और मानक विचलन की एन × पी एन
- क्रोनकर उत्पाद है और एलिमेंटवाइज (हैडमार्ड) उत्पाद है
एक बहुत ही सरल एक-परत तंत्रिका जाल जिसमें कोई बैच सामान्यीकरण नहीं है और एक निरंतर परिणाम है
कहाँ पे
- है
- पी 2 × 1 है
- सक्रियण फ़ंक्शन है
यदि नुकसान , तो ग्रेडिएंट्स ∂ आर
कहाँ पे
बैच के सामान्यीकरण के तहत, नेट या मुझे नहीं पता कि और क्रोनकर उत्पादों के डेरिवेटिव की गणना कैसे की जाती है। क्रोनकर उत्पादों के विषय पर, साहित्य को काफी रहस्यमय तरीके से प्राप्त होता है। y = एक ( ( गामा ⊗ 1 एन ) ⊙ ( एक्स Γ 1 - μ एक्स Γ 1
क्या मैट्रिक्स फ्रेमवर्क के भीतर , , और की गणना करने का एक व्यावहारिक तरीका है ? नोड-दर-नोड संगणना का सहारा लिए बिना, एक सरल अभिव्यक्ति?∂ आर / ∂ बीटा ∂ आर / ∂ गामा 1
अपडेट 1:
मुझे पता चला है कि - की तरह है। यह है: कुछ आर कोड दर्शाता है कि यह करने के लिए लूपिंग के बराबर है। पहले नकली डेटा सेट करें:1 टी एन (
set.seed(1)
library(dplyr)
library(foreach)
#numbers of obs, variables, and hidden layers
N <- 10
p1 <- 7
p2 <- 4
a <- function (v) {
v[v < 0] <- 0
v
}
ap <- function (v) {
v[v < 0] <- 0
v[v >= 0] <- 1
v
}
# parameters
G1 <- matrix(rnorm(p1*p2), nrow = p1)
G2 <- rnorm(p2)
gamma <- 1:p2+1
beta <- (1:p2+1)*-1
# error
u <- rnorm(10)
# matrix batch norm function
b <- function(x, bet = beta, gam = gamma){
xs <- scale(x)
gk <- t(matrix(gam)) %x% matrix(rep(1, N))
bk <- t(matrix(bet)) %x% matrix(rep(1, N))
gk*xs+bk
}
# activation-wise batch norm function
bi <- function(x, i){
xs <- scale(x)
gk <- t(matrix(gamma[i]))
bk <- t(matrix(beta[i]))
suppressWarnings(gk*xs[,i]+bk)
}
X <- round(runif(N*p1, -5, 5)) %>% matrix(nrow = N)
# the neural net
y <- a(b(X %*% G1)) %*% G2 + u
फिर डेरिवेटिव की गणना करें:
# drdbeta -- the matrix way
drdb <- matrix(rep(1, N*1), nrow = 1) %*% (-2*u %*% t(G2) * ap(b(X%*%G1)))
drdb
[,1] [,2] [,3] [,4]
[1,] -0.4460901 0.3899186 1.26758 -0.09589582
# the looping way
foreach(i = 1:4, .combine = c) %do%{
sum(-2*u*matrix(ap(bi(X[,i, drop = FALSE]%*%G1[i,], i)))*G2[i])
}
[1] -0.44609015 0.38991862 1.26758024 -0.09589582
उनका मिलान होता है। लेकिन मैं अभी भी उलझन में हूं, क्योंकि मैं वास्तव में नहीं जानता कि यह क्यों काम करता है। @Mark L. स्टोन द्वारा संदर्भित MatCalc नोट का कहना है कि का व्युत्पन्न होना चाहिए
# playing with the kroneker derivative rule
A <- t(matrix(beta))
B <- matrix(rep(1, N))
diag(rep(1, ncol(A) *ncol(B))) %*% diag(rep(1, ncol(A))) %x% (B) %x% diag(nrow(A))
[,1] [,2] [,3] [,4]
[1,] 1 0 0 0
[2,] 1 0 0 0
snip
[13,] 0 1 0 0
[14,] 0 1 0 0
snip
[28,] 0 0 1 0
[29,] 0 0 1 0
[snip
[39,] 0 0 0 1
[40,] 0 0 0 1
यह कंफर्टेबल नहीं है। स्पष्ट रूप से मैं उन क्रोनकर व्युत्पन्न नियमों को नहीं समझ रहा हूँ। उन लोगों के साथ मदद करना बहुत अच्छा होगा। मैं अभी भी पूरी तरह से अन्य डेरिवेटिव पर अटक कर रहा हूँ के लिए और - उन कड़ी मेहनत कर रहे हैं क्योंकि वे की तरह additively में प्रवेश नहीं करते करता है।
अपडेट २
पाठ्यपुस्तकें पढ़ना, मुझे पूरा यकीन है कि और को ऑपरेटर के उपयोग की आवश्यकता होगी । लेकिन मैं स्पष्ट रूप से व्युत्पत्तियों का पालन करने में असमर्थ हूं क्योंकि उन्हें कोड में अनुवाद करने में सक्षम होना चाहिए। उदाहरण के लिए, के व्युत्पन्न ले जा शामिल हो रहा है के संबंध में , जहां (जिसे हम इस समय के लिए एक स्थिर मैट्रिक्स के रूप में सकते हैं)। vec()
मेरी वृत्ति केवल यह कहने के लिए है कि "उत्तर " है, लेकिन यह स्पष्ट रूप से काम नहीं करता है क्योंकि अनुरूप नहीं है ।
मुझे पता है कि
और इस से , कि
अपडेट ३
यहां प्रगति हो रही है। मैं इस विचार के साथ कल रात 2 बजे उठा। मैथ नींद के लिए अच्छा नहीं है।
कुछ चीनी के बाद यहाँ :
श्रृंखला नियम के अंत में आने के बाद आपके पास यहां क्या है: यह लूपिंग तरीका करने से शुरू करें - और कॉलम को सब्स्क्रिप्ट करेंगे और एक कंफर्टेबल आइडेंटिटी मैट्रिक्स है:
और, वास्तव में यह है:
stub <- (-2*u %*% t(G2) * ap(b(X%*%G1)))
w <- t(matrix(gamma)) %x% matrix(rep(1, N)) * (apply(X%*%G1, 2, sd) %>% t %x% matrix(rep(1, N)))
drdG1 <- t(X) %*% (stub*w)
loop_drdG1 <- drdG1*NA
for (i in 1:7){
for (j in 1:4){
loop_drdG1[i,j] <- t(X[,i]) %*% diag(w[,j]) %*% (stub[,j])
}
}
> loop_drdG1
[,1] [,2] [,3] [,4]
[1,] -61.531877 122.66157 360.08132 -51.666215
[2,] 7.047767 -14.04947 -41.24316 5.917769
[3,] 124.157678 -247.50384 -726.56422 104.250961
[4,] 44.151682 -88.01478 -258.37333 37.072659
[5,] 22.478082 -44.80924 -131.54056 18.874078
[6,] 22.098857 -44.05327 -129.32135 18.555655
[7,] 79.617345 -158.71430 -465.91653 66.851965
> drdG1
[,1] [,2] [,3] [,4]
[1,] -61.531877 122.66157 360.08132 -51.666215
[2,] 7.047767 -14.04947 -41.24316 5.917769
[3,] 124.157678 -247.50384 -726.56422 104.250961
[4,] 44.151682 -88.01478 -258.37333 37.072659
[5,] 22.478082 -44.80924 -131.54056 18.874078
[6,] 22.098857 -44.05327 -129.32135 18.555655
[7,] 79.617345 -158.71430 -465.91653 66.851965
अद्यतन ४
यहाँ, मुझे लगता है, । प्रथम
पहले की तरह ही, चेन नियम आपको लूपिंग आपको जो पहले की तरह मूल रूप से स्टब को पहले से गुणा कर रहा है। इसलिए यह इसके बराबर होना चाहिए:
यह मेल खाता है:
drdg <- t(scale(X %*% G1)) %*% (stub * t(matrix(gamma)) %x% matrix(rep(1, N)))
loop_drdg <- foreach(i = 1:4, .combine = c) %do% {
t(scale(X %*% G1)[,i]) %*% (stub[,i, drop = F] * gamma[i])
}
> drdg
[,1] [,2] [,3] [,4]
[1,] 0.8580574 -1.125017 -4.876398 0.4611406
[2,] -4.5463304 5.960787 25.837103 -2.4433071
[3,] 2.0706860 -2.714919 -11.767849 1.1128364
[4,] -8.5641868 11.228681 48.670853 -4.6025996
> loop_drdg
[1] 0.8580574 5.9607870 -11.7678486 -4.6025996
पहले पर विकर्ण दूसरे पर वेक्टर के समान है। लेकिन वास्तव में चूंकि व्युत्पन्न एक मैट्रिक्स के संबंध में है - एक निश्चित संरचना के साथ एक के बावजूद, आउटपुट समान संरचना के साथ एक समान मैट्रिक्स होना चाहिए। क्या मुझे मैट्रिक्स एप्रोच का विकर्ण लेना चाहिए और बस इसे होना चाहिए ? मुझे यकीन नहीं है।
ऐसा लगता है कि मैंने अपने प्रश्न का उत्तर दिया है लेकिन मैं अनिश्चित हूं कि क्या मैं सही हूं। इस बिंदु पर मैं एक उत्तर को स्वीकार करूंगा कि कठोरता से साबित होता है (या नापसंद करता है) कि मैंने एक साथ हैक किया है।
while(not_answered){
print("Bueller?")
Sys.sleep(1)
}
Rcpp
इसे कुशलतापूर्वक लागू करने के लिए पर्याप्त सीखना उपयोगी है।