2017-12-09 23 views
1

ためPyTorchにバイアスを使用して、基本的な機能を近似することは非常に容易である:Rを使用して、基本的な関数近似

library(nnet) 
x <- sort(10*runif(50)) 
y <- sin(x) 
nn <- nnet(x, y, size=4, maxit=10000, linout=TRUE, abstol=1.0e-8, reltol = 1.0e-9, Wts = seq(0, 1, by=1/12)) 
plot(x, y) 
x1 <- seq(0, 10, by=0.1) 
lines(x1, predict(nn, data.frame(x=x1)), col="green") 
predict(nn , data.frame(x=pi/2)) 

単なる4個のニューロンの1つの隠れ層を有する単純なニューラルネットワークは正弦を近似するのに十分です。 (stackoverflow質問による)

しかし、私はPyTorchで同じものを得ることはできません。

実際、Rで作成されたニューラルネットワークには、入力、4つの隠れ、出力だけでなく、2つの「バイアス」ニューロンも含まれています。上記連結

Link to image: schema of the network built with R

プロットは、以下によって得られる:PyTorchと同じにしようと

library(devtools) 
library(scales) 
library(reshape) 
source_url('https://gist.github.com/fawda123/7471137/raw/cd6e6a0b0bdb4e065c597e52165e5ac887f5fe95/nnet_plot_update.r') 
plot.nnet(nn$wts,struct=nn$n, pos.col='#007700',neg.col='#FF7777') ### this plots the graph 
plot.nnet(nn$wts,struct=nn$n, pos.col='#007700',neg.col='#FF7777', wts.only=1) ### this prints the weights 

は異なるネットワークを生成する:バイアスニューロンが失われています。

以下は、以前にRで行われたことをPyTorchで行う試みです。結果は満足できません。関数は近似されません。最も顕著な違いは、バイアスニューロンが存在しないことです。 「バイアス」ニューロンまたは他の行方不明の詳細を挿入いずれかを介して、所定の関数(ここでは正弦)にネットワークを近似する方法

import torch 
from torch.autograd import Variable 

import random 
import math 

N, D_in, H, D_out = 1000, 1, 4, 1 

l_x = [] 
l_y = [] 

for a in range(1000): 
    r = random.random()*10 
    l_x.append([r]) 
    l_y.append([math.sin(r)]) 


tx = torch.cuda.FloatTensor(l_x) 
ty = torch.cuda.FloatTensor(l_y) 

x = Variable(tx, requires_grad=False) 
y = Variable(ty, requires_grad=False) 

w1 = Variable(torch.randn(D_in, H).type(torch.cuda.FloatTensor), requires_grad=True) 
w2 = Variable(torch.randn(H, D_out).type(torch.cuda.FloatTensor), requires_grad=True) 

learning_rate = 1e-5 
for t in range(1000): 
    y_pred = x.mm(w1).clamp(min=0).mm(w2) 

    loss = (y_pred - y).pow(2).sum() 
    if t<10 or t%100==1: print(t, loss.data[0]) 

    loss.backward() 

    w1.data -= learning_rate * w1.grad.data 
    w2.data -= learning_rate * w2.grad.data 

    w1.grad.data.zero_() 
    w2.grad.data.zero_() 


t = [ [math.pi] ] 
print(str(t) +" -> "+ str((Variable(torch.cuda.FloatTensor(t))).mm(w1).clamp(min=0).mm(w2).data)) 
t = [ [math.pi/2] ] 
print(str(t) +" -> "+ str((Variable(torch.cuda.FloatTensor(t))).mm(w1).clamp(min=0).mm(w2).data)) 

さらに、「R」が「バイアス」を挿入する理由を理解することが困難です。私はバイアスが "回帰モデルの傍受"に似ているという情報を見つけました - 私はまだそれが明らかでないことがわかります。どんな情報もありがとうございます。


EDIT:結果を得る

例えば、次のように "より完全な" フレームワーク( "車輪を改革しない")を使用することであるけれども:

残念なことに
import torch 
from torch.autograd import Variable 
import torch.nn.functional as F 

import math 

N, D_in, H, D_out = 1000, 1, 4, 1 

l_x = [] 
l_y = [] 

for a in range(1000): 
    t = (a/1000.0)*10 
    l_x.append([t]) 
    l_y.append([math.sin(t)]) 

x = Variable(torch.FloatTensor(l_x)) 
y = Variable(torch.FloatTensor(l_y)) 


class Net(torch.nn.Module): 
    def __init__(self, n_feature, n_hidden, n_output): 
     super(Net, self).__init__() 
     self.to_hidden = torch.nn.Linear(n_feature, n_hidden) 
     self.to_output = torch.nn.Linear(n_hidden, n_output) 

    def forward(self, x): 
     x = self.to_hidden(x) 
     x = F.tanh(x)   # activation function 
     x = self.to_output(x) 
     return x 


net = Net(n_feature = D_in, n_hidden = H, n_output = D_out) 

learning_rate = 0.01 
optimizer = torch.optim.Adam(net.parameters() , lr=learning_rate) 

for t in range(1000): 
    y_pred = net(x) 

    loss = (y_pred - y).pow(2).sum() 
    if t<10 or t%100==1: print(t, loss.data[0]) 

    loss.backward() 
    optimizer.step() 
    optimizer.zero_grad() 


t = [ [math.pi] ] 
print(str(t) +" -> "+ str(net(Variable(torch.FloatTensor(t))))) 
t = [ [math.pi/2] ] 
print(str(t) +" -> "+ str(net(Variable(torch.FloatTensor(t))))) 

、このながらコードは正常に動作し、元の "低レベル"コードを期待通りに動作させる問題を解決しません(例えばバイアスを導入するなど)。

class LinearWithInputBias(nn.Linear): 
    def __init__(self, in_features, out_features, out_bias=True, in_bias=True): 
     nn.Linear.__init__(self, in_features, out_features, out_bias) 
     if in_bias: 
      in_bias = torch.zeros(1, out_features) 
      # in_bias.normal_() # if you want it to be randomly initialized 
      self._out_bias = nn.Parameter(in_bias) 

    def forward(self, x): 
     out = nn.Linear.forward(self, x) 
     try: 
      out = out + self._out_bias 
     except AttributeError: 
      pass 
     return out 

は、しかし、あなたのコードでは、追加のバグがあります: -

+1

バイアス用語を追加していないので、 'nn.Linear() '' nn.Module'によって提供されるいくつかの非線形起動関数を使用し、あなたのモードを最適化するために '' torch.optim''を使用しますl?あなたが望むことを簡単にする方法があれば、ホイールを再発明しないでください。 – jdhao

+0

@jdhao、理由は教訓でした:私は最初に "なぜこれはうまくいかないのですか"という混乱がありました。私は偏りがなく、偏見を実装するのが難しいと思っていました。 ライブラリを使用する前に、プロセスの仕組みを理解するためです。 – mdp

答えて

0

@ jdhaoさんのコメントフォローアップは、これはあなたが望むものを正確に計算し、超シンプルなPyTorchモデルで、私が見ることができるものからつまり、grad.data.zero_()を呼び出して、グラディエント情報を削除する前に、torch.optim.SGD(mod.parameters())のようなオプティマイザを呼び出さないでください。

+0

私は、torch.nn.Linearに既にバイアスが実装されていることは確かではありません - 重量以外の余分なパラメータ - 十分なはずです...あなたが追加した余分なバイアス( "in_bias")の役割を理解していません計算は – mdp

+0

最初のバイアス項は実際の機能を追加しないので、技術的には決して必要ありません(変換を使用して追加のバイアスを変換し、それを第2のバイアスに追加し、等価線形近似器の最初のバイアスを削除することができます)。しかし、私は元の質問を理解して、1つのPytorchモジュールでいくつかのバイアス用語をどうやって調べるかを調べました。 – cleros

関連する問題