PyTorch में एक नेटवर्क में वज़न और पूर्वाग्रह (उदाहरण के लिए, वह या ज़ेवियर इनिशियलाइज़ेशन) के साथ कैसे आरंभ करें?
PyTorch में एक नेटवर्क में वज़न और पूर्वाग्रह (उदाहरण के लिए, वह या ज़ेवियर इनिशियलाइज़ेशन) के साथ कैसे आरंभ करें?
जवाबों:
किसी एक परत के भार को आरंभ करने के लिए, एक फ़ंक्शन का उपयोग करें torch.nn.init
। उदाहरण के लिए:
conv1 = torch.nn.Conv2d(...)
torch.nn.init.xavier_uniform(conv1.weight)
वैकल्पिक रूप से, आप conv1.weight.data
(जो एक है torch.Tensor
) को लिखकर मापदंडों को संशोधित कर सकते हैं । उदाहरण:
conv1.weight.data.fill_(0.01)
एक ही पक्षपात के लिए लागू होता है:
conv1.bias.data.fill_(0.01)
nn.Sequential
या प्रथा nn.Module
एक इनिशियलाइज़ेशन फंक्शन पास करें torch.nn.Module.apply
। यह पूरी तरह से nn.Module
पुनरावर्ती में भार को आरंभ करेगा ।
लागू ( fn ): लागू होता है
fn
हर submodule को रिकर्सिवली (के रूप में द्वारा लौटाए गए.children()
स्वयं के रूप में) के रूप में अच्छी तरह से। विशिष्ट उपयोग में एक मॉडल के मापदंडों को शुरू करना शामिल है (देखें टॉर्च-एनएन-इनिट भी)।
उदाहरण:
def init_weights(m):
if type(m) == nn.Linear:
torch.nn.init.xavier_uniform(m.weight)
m.bias.data.fill_(0.01)
net = nn.Sequential(nn.Linear(2, 2), nn.Linear(2, 2))
net.apply(init_weights)
यदि आप ओकाम के रेजर के सिद्धांत का पालन करते हैं , तो आप सोच सकते हैं कि सभी भार को 0 या 1 पर सेट करना सबसे अच्छा समाधान होगा। यह मामला नहीं है।
प्रत्येक भार के साथ, प्रत्येक परत पर सभी न्यूरॉन्स समान उत्पादन कर रहे हैं। इससे यह तय करना कठिन हो जाता है कि कौन सा वजन समायोजित करना है।
# initialize two NN's with 0 and 1 constant weights
model_0 = Net(constant_weight=0)
model_1 = Net(constant_weight=1)
Validation Accuracy
9.625% -- All Zeros
10.050% -- All Ones
Training Loss
2.304 -- All Zeros
1552.281 -- All Ones
एक समान वितरण में संख्याओं के समूह से किसी भी संख्या को चुनने की समान संभावना होती है।
आइए देखें कि एक समान वजन के आरंभीकरण का उपयोग करके तंत्रिका नेटवर्क कितनी अच्छी तरह से ट्रेन करता है, कहां low=0.0
और high=1.0
।
नीचे, हम नेटवर्क के भार को आरंभीकृत करने के लिए (नेट क्लास कोड के अलावा) एक और तरीका देखेंगे। मॉडल परिभाषा के बाहर वजन को परिभाषित करने के लिए, हम कर सकते हैं:
- एक फ़ंक्शन को परिभाषित करें जो नेटवर्क लेयर के प्रकार द्वारा वज़न असाइन करता है, फिर
- उन वज़न को एक प्रारंभिक मॉडल का उपयोग करके
model.apply(fn)
लागू करें, जो प्रत्येक मॉडल परत पर एक फ़ंक्शन लागू करता है।
# takes in a module and applies the specified weight initialization
def weights_init_uniform(m):
classname = m.__class__.__name__
# for every Linear layer in a model..
if classname.find('Linear') != -1:
# apply a uniform distribution to the weights and a bias=0
m.weight.data.uniform_(0.0, 1.0)
m.bias.data.fill_(0)
model_uniform = Net()
model_uniform.apply(weights_init_uniform)
Validation Accuracy
36.667% -- Uniform Weights
Training Loss
3.208 -- Uniform Weights
एक तंत्रिका नेटवर्क में वजन सेट करने के लिए सामान्य नियम उन्हें बहुत छोटा होने के बिना शून्य के करीब होने के लिए सेट करना है।
अच्छा अभ्यास [-y, y] जहां
y=1/sqrt(n)
(n किसी दिए गए न्यूरॉन को इनपुट की संख्या है) की सीमा में अपना वजन शुरू करना है ।
# takes in a module and applies the specified weight initialization
def weights_init_uniform_rule(m):
classname = m.__class__.__name__
# for every Linear layer in a model..
if classname.find('Linear') != -1:
# get the number of the inputs
n = m.in_features
y = 1.0/np.sqrt(n)
m.weight.data.uniform_(-y, y)
m.bias.data.fill_(0)
# create a new model with these weights
model_rule = Net()
model_rule.apply(weights_init_uniform_rule)
नीचे हम एनएन के प्रदर्शन की तुलना करते हैं, एक समान वितरण के साथ आरंभिक वजन [-0.5,0.5) बनाम जिसका वजन प्रारंभिक नियम नियम का उपयोग करके शुरू किया गया है
Validation Accuracy
75.817% -- Centered Weights [-0.5, 0.5)
85.208% -- General Rule [-y, y)
Training Loss
0.705 -- Centered Weights [-0.5, 0.5)
0.469 -- General Rule [-y, y)
सामान्य वितरण में 0 का मतलब और मानक विचलन होना चाहिए
y=1/sqrt(n)
, जहां n एनएन में इनपुट की संख्या है
## takes in a module and applies the specified weight initialization
def weights_init_normal(m):
'''Takes in a module and initializes all linear layers with weight
values taken from a normal distribution.'''
classname = m.__class__.__name__
# for every Linear layer in a model
if classname.find('Linear') != -1:
y = m.in_features
# m.weight.data shoud be taken from a normal distribution
m.weight.data.normal_(0.0,1/np.sqrt(y))
# m.bias.data should be 0
m.bias.data.fill_(0)
नीचे हम समान-वितरण का उपयोग करके दो एनएन एक के प्रदर्शन को दिखाते हैं और दूसरा सामान्य-वितरण का उपयोग करते हुए
Validation Accuracy
85.775% -- Uniform Rule [-y, y)
84.717% -- Normal Distribution
Training Loss
0.329 -- Uniform Rule [-y, y)
0.443 -- Normal Distribution
PyTorch इसे आपके लिए करेगा। यदि आप सोचते हैं, तो इसका बहुत अर्थ है। हमें लेयर को इनिशियलाइज़ क्यों करना चाहिए, जब PyTorch लेटेस्ट ट्रेंड को फॉलो कर सकता है।
उदाहरण के लिए रेखीय परत की जाँच करें ।
में __init__
विधि यह फोन करेगा Kaiming वह init समारोह।
def reset_parameters(self):
init.kaiming_uniform_(self.weight, a=math.sqrt(3))
if self.bias is not None:
fan_in, _ = init._calculate_fan_in_and_fan_out(self.weight)
bound = 1 / math.sqrt(fan_in)
init.uniform_(self.bias, -bound, bound)
अन्य परतों के प्रकारों के लिए भी ऐसा ही है। उदाहरण conv2d
के लिए यहाँ जाँच करें ।
ध्यान दें: उचित आरंभ का लाभ तेज प्रशिक्षण गति है। यदि आपकी समस्या विशेष आरंभ के योग्य है, तो आप इसे बाद में कर सकते हैं।
xavier_uniform
डिफ़ॉल्ट आरंभीकरण का उपयोग करने के बजाय वेट के लिए आरंभीकरण पर स्विच किया जा रहा है (0 के साथ शुरुआती गैसों के बजाय), मेरी सत्यापन सटीकता 30 के बाद। आरएमएसप्रॉप की अवधि 82% से बढ़कर 86% हो गई। Pytorch के अंतर्निहित VGG16 मॉडल (पूर्व-प्रशिक्षित नहीं) का उपयोग करते समय मुझे 86% सत्यापन सटीकता भी मिली, इसलिए मुझे लगता है कि मैंने इसे सही तरीके से लागू किया। (मैंने 0.00001 की सीखने की दर का इस्तेमाल किया।)
import torch.nn as nn
# a simple network
rand_net = nn.Sequential(nn.Linear(in_features, h_size),
nn.BatchNorm1d(h_size),
nn.ReLU(),
nn.Linear(h_size, h_size),
nn.BatchNorm1d(h_size),
nn.ReLU(),
nn.Linear(h_size, 1),
nn.ReLU())
# initialization function, first checks the module type,
# then applies the desired changes to the weights
def init_normal(m):
if type(m) == nn.Linear:
nn.init.uniform_(m.weight)
# use the modules apply function to recursively apply the initialization
rand_net.apply(init_normal)
इतनी देर होने के लिए क्षमा करें, मुझे आशा है कि मेरा उत्तर मदद करेगा।
एक normal distribution
उपयोग के साथ वजन को आरंभ करने के लिए:
torch.nn.init.normal_(tensor, mean=0, std=1)
या constant distribution
लिखने का उपयोग करने के लिए :
torch.nn.init.constant_(tensor, value)
या एक का उपयोग करने के लिए uniform distribution
:
torch.nn.init.uniform_(tensor, a=0, b=1) # a: lower_bound, b: upper_bound
आप यहाँ दसियों को इनिशियलाइज़ करने के लिए अन्य तरीकों की जाँच कर सकते हैं
यदि आप कुछ अतिरिक्त लचीलापन चाहते हैं, तो आप मैन्युअल रूप से वजन भी निर्धारित कर सकते हैं ।
कहो कि आपके पास सभी का इनपुट है:
import torch
import torch.nn as nn
input = torch.ones((8, 8))
print(input)
tensor([[1., 1., 1., 1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1., 1., 1., 1.]])
और आप बिना किसी पूर्वाग्रह के साथ घनी परत बनाना चाहते हैं (ताकि हम कल्पना कर सकें):
d = nn.Linear(8, 8, bias=False)
सभी वज़न को 0.5 पर सेट करें (या कुछ और):
d.weight.data = torch.full((8, 8), 0.5)
print(d.weight.data)
वजन:
Out[14]:
tensor([[0.5000, 0.5000, 0.5000, 0.5000, 0.5000, 0.5000, 0.5000, 0.5000],
[0.5000, 0.5000, 0.5000, 0.5000, 0.5000, 0.5000, 0.5000, 0.5000],
[0.5000, 0.5000, 0.5000, 0.5000, 0.5000, 0.5000, 0.5000, 0.5000],
[0.5000, 0.5000, 0.5000, 0.5000, 0.5000, 0.5000, 0.5000, 0.5000],
[0.5000, 0.5000, 0.5000, 0.5000, 0.5000, 0.5000, 0.5000, 0.5000],
[0.5000, 0.5000, 0.5000, 0.5000, 0.5000, 0.5000, 0.5000, 0.5000],
[0.5000, 0.5000, 0.5000, 0.5000, 0.5000, 0.5000, 0.5000, 0.5000],
[0.5000, 0.5000, 0.5000, 0.5000, 0.5000, 0.5000, 0.5000, 0.5000]])
आपके सभी वजन अब 0.5 हैं। डेटा पास करें:
d(input)
Out[13]:
tensor([[4., 4., 4., 4., 4., 4., 4., 4.],
[4., 4., 4., 4., 4., 4., 4., 4.],
[4., 4., 4., 4., 4., 4., 4., 4.],
[4., 4., 4., 4., 4., 4., 4., 4.],
[4., 4., 4., 4., 4., 4., 4., 4.],
[4., 4., 4., 4., 4., 4., 4., 4.],
[4., 4., 4., 4., 4., 4., 4., 4.],
[4., 4., 4., 4., 4., 4., 4., 4.]], grad_fn=<MmBackward>)
याद रखें कि प्रत्येक न्यूरॉन को 8 इनपुट प्राप्त होते हैं, जिनमें से सभी का वजन 0.5 और 1 (और कोई पूर्वाग्रह) का मूल्य नहीं होता है, इसलिए यह प्रत्येक के लिए 4 तक बैठता है।
यदि आप apply
उदाहरण के लिए उपयोग नहीं कर सकते हैं यदि मॉडल Sequential
सीधे लागू नहीं होता है:
# see UNet at https://github.com/milesial/Pytorch-UNet/tree/master/unet
def init_all(model, init_func, *params, **kwargs):
for p in model.parameters():
init_func(p, *params, **kwargs)
model = UNet(3, 10)
init_all(model, torch.nn.init.normal_, mean=0., std=1)
# or
init_all(model, torch.nn.init.constant_, 1.)
def init_all(model, init_funcs):
for p in model.parameters():
init_func = init_funcs.get(len(p.shape), init_funcs["default"])
init_func(p)
model = UNet(3, 10)
init_funcs = {
1: lambda x: torch.nn.init.normal_(x, mean=0., std=1.), # can be bias
2: lambda x: torch.nn.init.xavier_normal_(x, gain=1.), # can be weight
3: lambda x: torch.nn.init.xavier_uniform_(x, gain=1.), # can be conv1D filter
4: lambda x: torch.nn.init.xavier_uniform_(x, gain=1.), # can be conv2D filter
"default": lambda x: torch.nn.init.constant(x, 1.), # everything else
}
init_all(model, init_funcs)
आप यह torch.nn.init.constant_(x, len(x.shape))
जाँचने की कोशिश कर सकते हैं कि वे उचित रूप से आरंभिक हैं:
init_funcs = {
"default": lambda x: torch.nn.init.constant_(x, len(x.shape))
}
यदि आप एक चेतावनी चेतावनी (@ Fábio पेरेस) देखें ...
def init_weights(m):
if type(m) == nn.Linear:
torch.nn.init.xavier_uniform_(m.weight)
m.bias.data.fill_(0.01)
net = nn.Sequential(nn.Linear(2, 2), nn.Linear(2, 2))
net.apply(init_weights)
Cuz मुझे अब तक पर्याप्त प्रतिष्ठा नहीं मिली है, मैं एक टिप्पणी नहीं जोड़ सकता
इस सवाल का जवाब द्वारा पोस्ट की गई prosti में 13:16 पर जून 26 '19 ।
def reset_parameters(self):
init.kaiming_uniform_(self.weight, a=math.sqrt(3))
if self.bias is not None:
fan_in, _ = init._calculate_fan_in_and_fan_out(self.weight)
bound = 1 / math.sqrt(fan_in)
init.uniform_(self.bias, -bound, bound)
लेकिन मैं कहना चाहता हूं कि वास्तव में हम कैमिंग ही के पेपर में कुछ धारणाएं जानते हैं , डेलिंग डीप इन रेक्टिफायर्स: इमेजिनेशन क्लासिफिकेशन पर मानव-स्तरीय प्रदर्शन को दरकिनार करना , उचित नहीं है, हालांकि यह ऐसा लगता है कि जानबूझकर डिजाइन किया गया प्रैक्टिस मेथड प्रचलन में है। ।
उदाहरण के लिए, पिछड़े प्रसार मामले के अंतर्गत , वे मानते हैं कि $ w_l $ और $ \ डेल्टा y_l $ एक-दूसरे से स्वतंत्र हैं। लेकिन जैसा कि हम सभी जानते हैं, एक उदाहरण के रूप में स्कोर मैप $ \ डेल्टा y ^ L_i $ लेते हैं, यह अक्सर $ y_i-softmax (y ^ L_i) = y_i-softmax (w ^ L_ix-L_i) $ होता है यदि हम एक ठेठ का उपयोग करते हैं क्रॉस एन्ट्रापी लॉस फ़ंक्शन का उद्देश्य।
इसलिए मुझे लगता है कि असली अंतर्निहित कारण यह है कि प्रारंभ में काम करता है अच्छी तरह से खुला रहता है। Cuz सभी ने गहन शिक्षण प्रशिक्षण को बढ़ावा देने के लिए अपनी शक्ति देखी है।
reset_parameters
कई मॉड्यूल के स्रोत कोड में एक विधि मिली । क्या मुझे वजन आरंभीकरण के लिए विधि को ओवरराइड करना चाहिए?