Satu lapis
Untuk menginisialisasi bobot satu lapisan, gunakan fungsi dari torch.nn.init
. Contohnya:
conv1 = torch.nn.Conv2d(...)
torch.nn.init.xavier_uniform(conv1.weight)
Alternatifnya, Anda dapat memodifikasi parameter dengan menulis ke conv1.weight.data
(yaitu a torch.Tensor
). Contoh:
conv1.weight.data.fill_(0.01)
Hal yang sama berlaku untuk bias:
conv1.bias.data.fill_(0.01)
nn.Sequential
atau adat nn.Module
Teruskan fungsi inisialisasi ke torch.nn.Module.apply
. Ini akan menginisialisasi bobot di seluruh nn.Module
secara rekursif.
apply ( fn ): Berlaku fn
secara rekursif untuk setiap submodul (seperti yang dikembalikan oleh .children()
) serta diri sendiri. Penggunaan umum termasuk menginisialisasi parameter model (lihat juga torch-nn-init).
Contoh:
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)
reset_parameters
metode dalam kode sumber dari banyak modul. Haruskah saya mengganti metode inisialisasi bobot?Kami membandingkan mode inisialisasi bobot yang berbeda menggunakan arsitektur neural-network (NN) yang sama.
Semua Nol atau Satu
Jika Anda mengikuti prinsip pisau cukur Occam , Anda mungkin berpikir bahwa mengatur semua bobot ke 0 atau 1 akan menjadi solusi terbaik. Ini bukan kasusnya.
Dengan setiap bobot yang sama, semua neuron di setiap lapisan menghasilkan keluaran yang sama. Hal ini membuat sulit untuk memutuskan bobot mana yang akan disesuaikan.
# 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
Inisialisasi Seragam
Sebuah distribusi seragam memiliki probabilitas yang sama memetik angka dari satu set nomor.
Mari kita lihat seberapa baik jaringan neural berlatih menggunakan inisialisasi bobot seragam, di mana
low=0.0
danhigh=1.0
.Di bawah ini, kita akan melihat cara lain (selain kode kelas Net) untuk menginisialisasi bobot jaringan. Untuk menentukan bobot di luar definisi model, kita dapat:
# 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
Aturan umum untuk mengatur bobot
Aturan umum untuk menyetel bobot di jaringan neural adalah menyetelnya mendekati nol tanpa menjadi terlalu kecil.
# 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)
di bawah ini kami membandingkan kinerja NN, bobot yang diinisialisasi dengan distribusi seragam [-0.5,0.5) versus bobot yang diinisialisasi menggunakan aturan umum
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)
distribusi normal untuk menginisialisasi bobot
## 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)
di bawah ini kami menunjukkan kinerja dari dua NN, satu diinisialisasi menggunakan distribusi seragam dan yang lainnya menggunakan distribusi normal
Validation Accuracy 85.775% -- Uniform Rule [-y, y) 84.717% -- Normal Distribution Training Loss 0.329 -- Uniform Rule [-y, y) 0.443 -- Normal Distribution
sumber
Untuk menginisialisasi lapisan, Anda biasanya tidak perlu melakukan apa pun.
PyTorch akan melakukannya untuk Anda. Jika Anda memikirkannya, ini memiliki banyak arti. Mengapa kita harus menginisialisasi lapisan, ketika PyTorch dapat melakukannya mengikuti tren terbaru.
Periksa misalnya lapisan Linear .
Dalam
__init__
metode ini akan memanggil fungsi init Kaiming He .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)
Yang serupa untuk jenis lapisan lainnya. Untuk
conv2d
misalnya memeriksa di sini .Untuk diperhatikan: Keuntungan dari inisialisasi yang tepat adalah kecepatan latihan yang lebih cepat. Jika masalah Anda memerlukan inisialisasi khusus, Anda dapat melakukannya setelah kata sandi.
sumber
xavier_uniform
inisialisasi untuk bobot (dengan bias yang diinisialisasi ke 0), daripada menggunakan inisialisasi default, akurasi validasi saya setelah 30 epochs RMSprop meningkat dari 82% menjadi 86%. Saya juga mendapatkan akurasi validasi 86% saat menggunakan model VGG16 bawaan Pytorch (tidak dilatih sebelumnya), jadi saya rasa saya menerapkannya dengan benar. (Saya menggunakan kecepatan pemelajaran 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)
sumber
Maaf terlambat, saya harap jawaban saya akan membantu.
Untuk menginisialisasi bobot dengan
normal distribution
menggunakan:torch.nn.init.normal_(tensor, mean=0, std=1)
Atau menggunakan file
constant distribution
tulisan:Atau menggunakan file
uniform distribution
:torch.nn.init.uniform_(tensor, a=0, b=1) # a: lower_bound, b: upper_bound
Anda dapat memeriksa metode lain untuk menginisialisasi tensor di sini
sumber
Jika Anda menginginkan fleksibilitas ekstra, Anda juga dapat mengatur bobot secara manual .
Katakanlah Anda memiliki masukan dari semuanya:
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.]])
Dan Anda ingin membuat lapisan padat tanpa bias (sehingga kami dapat memvisualisasikannya):
d = nn.Linear(8, 8, bias=False)
Atur semua bobot menjadi 0,5 (atau yang lainnya):
d.weight.data = torch.full((8, 8), 0.5) print(d.weight.data)
Bobot:
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]])
Semua bobot Anda sekarang 0,5. Kirimkan data melalui:
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>)
Ingatlah bahwa setiap neuron menerima 8 masukan, yang semuanya memiliki bobot 0,5 dan nilai 1 (dan tidak ada bias), jadi jumlahnya masing-masing menjadi 4.
sumber
Iterasi parameter
Jika Anda tidak dapat menggunakan
apply
misalnya jika model tidak diimplementasikanSequential
secara langsung:Sama untuk semua
# 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.)
Tergantung bentuknya
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)
Anda dapat mencoba
torch.nn.init.constant_(x, len(x.shape))
untuk memeriksa apakah mereka diinisialisasi dengan benar:init_funcs = { "default": lambda x: torch.nn.init.constant_(x, len(x.shape)) }
sumber
Jika Anda melihat peringatan penghentian (@ Fábio Perez) ...
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)
sumber
Karena reputasi saya sejauh ini belum cukup, saya tidak bisa menambahkan komentar di bawah
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)
Tapi saya ingin menunjukkan bahwa sebenarnya kita tahu beberapa asumsi dalam makalah Kaiming He , Menggali Lebih Dalam ke Rectifier: Melampaui Kinerja Tingkat Manusia pada Klasifikasi ImageNet , tidak tepat, meskipun tampaknya metode inisialisasi yang sengaja dirancang membuat hit dalam praktiknya. .
Misalnya, dalam sub-bagian Kasus Propagasi Mundur , mereka mengasumsikan bahwa $ w_l $ dan $ \ delta y_l $ tidak bergantung satu sama lain. Tapi seperti yang kita semua tahu, ambil peta skor $ \ delta y ^ L_i $ sebagai contoh, seringkali $ y_i-softmax (y ^ L_i) = y_i-softmax (w ^ L_ix ^ L_i) $ jika kita menggunakan tipikal tujuan fungsi kerugian entropi silang.
Jadi saya pikir alasan mendasar sebenarnya mengapa Inisialisasi Dia bekerja dengan baik masih belum terurai. Karena semua orang telah menyaksikan kekuatannya dalam meningkatkan pelatihan pembelajaran yang mendalam.
sumber