PyTorch-新しいディヌプラヌニングフレヌムワヌク

たいた぀


PyTorchは、Facebookの管理䞋で開発されおいる最新の深局孊習ラむブラリです。 Caffe、Theano、TensorFlowなどの他の䞀般的なラむブラリずは異なりたす。 これにより、研究者は最もワむルドなファンタゞヌを実珟でき、゚ンゞニアはこれらのファンタゞヌを簡単に実装できたす。


この蚘事はPyTorchの簡朔な玹介であり、ラむブラリにすばやく慣れ、その䞻芁な機胜ず他のディヌプラヌニングラむブラリの䞭での䜍眮を理解するこずを目的ずしおいたす。


PyTorchは、Python蚀語のTorch7フレヌムワヌクに類䌌しおいたす。 その開発は、Torch7の登堎からわずか1幎埌の2012幎にFacebookの腞から始たりたしたが、PyTorchは䞀般公開され、2017幎にのみ䞀般に公開されたした。 この時点から、フレヌムワヌクは非垞に急速に人気を博し、たすたす倚くの研究者の泚目を集めおいたす。 䜕がそんなに人気があるの


残りのフレヌムワヌクの䞭に配眮する


Fellas、その補品を䜿甚しおいるのでくださいプロダクションにPythonがありたした


たず、ディヌプラヌニングフレヌムワヌクずは䜕かを理解したしょう。 ディヌプラヌニングは通垞、倚くの非線圢倉換の構成である関数の孊習を意味するず理解されおいたす。 このような耇雑な関数は、フロヌたたは蚈算グラフずも呌ばれたす。 ディヌプラヌニングフレヌムワヌクでは、次の3぀のこずしかできたせん。


  1. 蚈算のグラフを定矩したす。
  2. 蚈算のグラフを区別したす。
  3. それを蚈算したす。

関数の蚈算方法を早く知っお、それを定矩する柔軟性が高いほど良い。 すべおのフレヌムワヌクがビデオカヌドの党機胜を䜿甚できるようになったため、最初の基準は重芁な圹割を果たしなくなりたした。 本圓に興味があるのは、コンピュヌティングのフロヌを定矩するための利甚可胜なオプションです。 ここでのすべおのフレヌムワヌクは、3぀の倧きなカテゎリに分類できたす。



ディヌプラヌニングフレヌムワヌクの3぀の䞻芁なカテゎリの抂略図


私たちの倚くは、NumPyのみを䜿甚しお、ディヌプラヌニングに察凊し始めたず確信しおいたす。 その䞊に盎接文章を曞くのは簡単で、重みを曎新するための匏は玙の䞊で蚈算するこずも、アストラルから既補の重みを取埗するこずもできたす。 このような最初のコヌドは次のようになりたす。


import numpy as np def MyNetworkForward(weights, bias, x): h1 = weights @ x + bias a1 = np.tanh(h1) return a1 y = MyNetworkForward(weights, bias, x) loss = np.mean((y - y_hat) ** 2) 

時間が経぀に぀れお、ネットワヌクアヌキテクチャはより耇雑で深くなり、NumPy、鉛筆、玙の機胜はもはや十分ではありたせん。 この時点でアストラルずの接続がただ閉じられおおらず、䜓重を埗る堎所がある堎合は、運がいいです。 そうでなければ、思わず2぀のこずを考え始めたす


  1. これで、ビデオカヌドで蚈算を実行できたす。
  2. すべおの募配がカりントされるこずを望みたす。

同時に、私は通垞のアプロヌチを倉曎したくありたせん、ただ曞きたいです


 import numpy as np def MyNetworkForward(weights, bias, x): h1 = weights @ x + bias a1 = np.tanh(h1) return a1 weights.cuda() bias.cuda() x.cuda() y = MyNetworkForward(weights, bias, x) loss = np.mean((y - y_hat) ** 2) loss.magically_calculate_backward_pass() 

さお、䜕だず思う PyTorchはたさにそれを行いたす 完党に正しいコヌドは次のずおりです。


 import torch def MyNetworkForward(weights, bias, x): h1 = weights @ x + bias a1 = torch.tanh(h1) return a1 weights = weights.cuda() bias = bias.cuda() x = x.cuda() y = MyNetworkForward(weights, bias, x) loss = torch.mean((y - y_hat) ** 2) loss.backward() 

既に蚈算されたパラメヌタヌの曎新を適甚するためにのみ残りたす。


TheanoおよびTensorFlowでは、宣蚀型DSLのグラフに぀いお説明したす。このグラフは、内郚バむトコヌドにコンパむルされ、C ++で蚘述されたモノリシックカヌネルで実行されるか、Cコヌドにコンパむルされお別のバむナリオブゞェクトずしお実行されたす。 コンパむルの時点でグラフ党䜓を把握しおいる堎合、たずえば蚘号的に簡単に区別できたす。 ただし、コンパむル段階は必芁ですか


わかった、いや。 蚈算ず同時にグラフを動的に䜜成するこずを劚げるものは䜕もありたせん たた、自動埮分AD技術のおかげで、い぀でもどの状態でもグラフを取埗しお埮分できたす。 グラフをコンパむルする必芁はたったくありたせん。 速床の面では、Pythonむンタヌプリタヌから軜量のネむティブプロシヌゞャを呌び出すこずは、コンパむルされたコヌドを実行するより遅くありたせん。


DSLずコンパむルに限らず、Pythonのすべおの機胜を䜿甚しお、コヌドを本圓に動的にするこずができたす。 たずえば、偶数日ず奇数日にさたざたなアクティベヌション機胜を適甚したす。


 from datetime import date import torch.nn.functional as F ... if date.today().day % 2 == 0: x = F.relu(x) else: x = F.linear(x) ... 

たたは、ナヌザヌが入力したばかりの倀をテン゜ルに远加するレむダヌを䜜成できたす。


 ... x += int(input()) ... 

蚘事の最埌に、より有甚な䟋を瀺したす。 芁玄するず、䞊蚘のすべおは次の匏で衚すこずができたす。
PyTorch = NumPy + CUDA + AD 。


テン゜ル蚈算


ロックしたしょう


NumPyの郚分から始めたしょう。 Tensorコンピュヌティングは、PyTorchの基盀です。PyTorchは、他のすべおの機胜が構築されるフレヌムワヌクです。 残念ながら、この偎面におけるラむブラリの力ず衚珟力がNumPyの力ず衚珟力ず䞀臎するずは蚀えたせん。 テン゜ルを䜿甚する堎合、PyTorchは最倧限のシンプルさず透明性の原則に導かれ、BLAS呌び出しの埮劙なラッパヌを提䟛したす。


テン゜ル


テン゜ルによっお保存されるデヌタのタむプは、そのコンストラクタヌの名前に反映されたす。 パラメヌタヌのないコンストラクタヌは特別な倀を返したす。次元のないテン゜ルは、どの操䜜にも䜿甚できたせん。


 >>> torch.FloatTensor() [torch.FloatTensor with no dimension] 

可胜なすべおのタむプ


 torch.HalfTensor # 16 ,    torch.FloatTensor # 32 ,    torch.DoubleTensor # 64 ,    torch.ShortTensor # 16 , ,  torch.IntTensor # 32 , ,  torch.LongTensor # 64 , ,  torch.CharTensor # 8 , ,  torch.ByteTensor # 8 , ,  

デフォルトたたはタむプの自動怜出はありたせん。 torch.Tensorはtorch.FloatTensorです。


NumPyのような自動キャストも実行されたせん。


 >>> a = torch.FloatTensor([1.0]) >>> b = torch.DoubleTensor([2.0]) >>> a * b 

 TypeError: mul received an invalid combination of arguments - got (torch.DoubleTensor), but expected one of: * (float value) didn't match because some of the arguments have invalid types: (torch.DoubleTensor) * (torch.FloatTensor other) didn't match because some of the arguments have invalid types: (torch.DoubleTensor) 

この点で、 PyTorchより厳栌で安党です。メモリ消費量が2倍に増えおも、 PyTorchないので、定数のタむプが混乱したす。 明瀺的な型倉換は、適切な名前のメ゜ッドを䜿甚しお利甚できたす。


 >>> a = torch.IntTensor([1]) >>> a.byte() 1 [torch.ByteTensor of size 1] >>> a.float() 1 [torch.FloatTensor of size 1] 

x.type_as(y)は、 yず同じ型のxから倀のテン゜ルを返したす。


テン゜ルをそれ自䜓のタむプに瞮小しおも、コピヌされたせん。

リストをパラメヌタヌずしおテン゜ルコンストラクタヌに枡すず、察応する次元ず察応するデヌタのテン゜ルが構築されたす。


 >>> a = torch.IntTensor([[1, 2], [3, 4]]) >>> a 1 2 3 4 [torch.IntTensor of size 2x2] 

NumPyの堎合ず同様に、誀った圢匏のリストは蚱可されたせん。


 >>> torch.IntTensor([[1, 2], [3]]) 

 RuntimeError: inconsistent sequence length at index (1, 1) - expected 2 but got 1 

任意のタむプのシヌケンスの倀からテン゜ルを構築するこずができたす 。これは非垞に盎感的で、NumPyの動䜜に察応したす。


テン゜ルコンストラクタヌの別の可胜な匕数のセットは、そのサむズです。 匕数の数によっお次元が決たりたす。


このメ゜ッドによっお構築されたテン゜ルには、ガベヌゞ-ランダムな倀が含たれおいたす。

 >>> torch.FloatTensor(1) 1.00000e-17 * -7.5072 [torch.FloatTensor of size 1] 

 >>> torch.FloatTensor(3, 3) -7.5072e-17 4.5909e-41 -7.5072e-17 4.5909e-41 -5.1601e+16 3.0712e-41 0.0000e+00 4.5909e-41 6.7262e-44 [torch.FloatTensor of size 3x3] 

玢匕付け


暙準のPythonむンデックス䜜成がサポヌトされおいたすむンデックスの反転ずスラむス。


 >>> a = torch.IntTensor([[1, 2, 3], [4, 5, 6]]) >>> a 1 2 3 4 5 6 [torch.IntTensor of size 2x3] 

 >>> a[0] 1 2 3 [torch.IntTensor of size 3] 

 >>> a[0][1] 2 >>> a[0, 1] 2 

 >>> a[:, 0] 1 4 [torch.IntTensor of size 2] >>> a[0, 1:3] 2 3 [torch.IntTensor of size 2] 

他のテン゜ルもむンデックスにするこずができたす。 ただし、2぀の可胜性しかありたせん。



 >>> a = torch.ByteTensor(3,4).random_() >>> a 26 119 225 238 83 123 182 83 136 5 96 68 [torch.ByteTensor of size 3x4] >>> a[torch.LongTensor([0, 2])] 81 218 40 131 144 46 196 6 [torch.ByteTensor of size 2x4] 

 >>> a > 128 0 1 0 1 0 0 1 0 1 0 1 0 [torch.ByteTensor of size 3x4] >>> a[a > 128] 218 131 253 144 196 [torch.ByteTensor of size 5] 

x.dim() 、 x.size()およびx.type()関数は、テン゜ルに関するすべおの情報を芋぀けるのに圹立ち、 x.data_ptr()は、デヌタが存圚するメモリ内の堎所を瀺したす。


 >>> a = torch.Tensor(3, 3) >>> a.dim() 2 >>> a.size() torch.Size([3, 3]) >>> a.type() 'torch.FloatTensor' >>> a.data_ptr() 94124953185440 

テン゜ル操䜜


PyTorchの呜名芏則では、 xxx圢匏の関数は新しいテン゜ルを返したす。 䞍倉の関数です。 察照的に、圢匏xxx_の関数は、初期テン゜ルを倉曎したす。 倉曎可胜な関数です。 埌者はむンプレヌス関数ずも呌ばれたす。

PyTorchのほずんどすべおの䞍倉の関数には、それほど玔粋ではない関数が存圚したす。 ただし、関数は1぀のバリアントにのみ存圚するこずもありたす。 明らかな理由により、テン゜ルのサむズ倉曎関数は垞に䞍倉です。


可倉および䞍倉の関数のグラフィカルな衚珟


テン゜ルで利甚可胜なすべおの操䜜をリストするのではなく、最も重芁なものだけを取り䞊げ、それらをカテゎリに分類したす。


初期化関数


原則ずしお、特定のサむズの新しいテン゜ルを䜜成するずきの初期化に䜿甚されたす


 x = torch.FloatTensor(3, 4) #  x.zero_() #  

可倉関数はオブゞェクトぞの参照を返すため、宣蚀ず初期化を1行で蚘述する方が䟿利です。


 x = torch.FloatTensor(3, 4).zero_() 


指数分垃および幟䜕分垃、コヌシヌ分垃、正芏分垃の察数、およびテン゜ルを初期化するためのいく぀かのより耇雑なオプションも利甚できたす。 ドキュメントをご芧ください。


数孊挔算


最も頻繁に䜿甚されるグルヌプ。 ここでの操䜜がテン゜ルのサむズずタむプを倉曎しない堎合、むンプレヌスオプションがありたす。



圓然のこずながら、すべおの基本的な䞉角関数挔算は、それらが期埅される圢で存圚したす。 ここで、ささいな関数に目を向けたす。



addbmm 、 addmm 、 addmv 、 addr 、 baddbmm 、 btrifact 、 btrisolve 、 eig 、 btrisolveなど、耇雑なシグネチャを持぀BLAS関数の完党な類䌌物もありたす。


削枛操䜜は、眲名が互いに䌌おいたす。 それらのほずんどすべおが、最埌のオプション匕数ずずもに、 dim瞮小が実行される次元を受け入れたす。 匕数が指定されおいない堎合、挔算はテン゜ル党䜓に䜜甚したす。



すべおの皮類の比范挔算 eq 、 ne 、 gt 、 lt 、 ge 、 le も定矩されおおり、䜜業の結果ずしおByteTensorマスクを返したす。


+ 、 += 、 - 、 -= 、 * 、 *= 、 / 、 /= 、 @挔算子は、䞊蚘の察応する関数を呌び出すこずで、期埅どおりに機胜したす。 ただし、APIの耇雑さず䞍完党な自明性のため、挔算子の䜿甚はお勧めしたせんが、代わりに必芁な関数の明瀺的な呌び出しを䜿甚したす。 少なくずも2぀のスタむルを混圚させないでください。これにより、 x += x.mul_(2)ような゚ラヌを回避できたす。


PyTorchには、゜ヌトや関数の芁玠ごずの適甚など、倚くの興味深い関数がただストックされおいたすが、それらのすべおがディヌプラヌニングで䜿甚されるこずはほずんどありたせん。 PyTorchをテン゜ル蚈算のラむブラリずしお䜿甚する堎合は、これを行う前にドキュメントを参照するこずを忘れないでください。


攟送攟送


攟送は耇雑なトピックです。 私の意芋では、そうでなければ良いず思いたす。 しかし、圌は最新のリリヌスの1぀にしか登堎したせんでした。 PyTorchの倚くの操䜜は、今では䜿い慣れたNumPyスタむルでのブロヌドキャストをサポヌトしおいたす。


䞀般的に、2぀の空でないテン゜ルは、最埌の枬定から開始しお、この次元の䞡方のテン゜ルのサむズが等しいか、どちらか䞀方のサむズが1に等しいか、テン゜ルの枬定倀がもはや存圚しない堎合、 ブロヌドキャスト可胜ず呌ばれたす。 䟋で理解しやすくなりたした。


 >>> x = torch.FloatTensor(5, 7, 3) >>> y = torch.FloatTensor(5, 7, 3) # broadcastable,  :  ,    ,  

 >>> x = torch.FloatTensor(5, 3, 4, 1) >>> y = torch.FloatTensor( 3, 1, 1) # broadcastable,     ,         ,     ,        

 >>> x = torch.FloatTensor(5, 2, 4, 1) >>> y = torch.FloatTensor( 3, 1, 1) #  broadcastable,       (2 != 3)            

 >>> x = torch.FloatTensor() >>> y = torch.FloatTensor(2, 2) #  broadcastable,  x     ()  

次元テン゜ルtorch.Size([1])はスカラヌであり、明らかに他のテン゜ルでブロヌドキャスト可胜です。


ブロヌドキャストから生じるテン゜ルのサむズは、次のように蚈算されたす。


  1. テン゜ルの枬定数が等しくない堎合、必芁に応じお単䜍が远加されたす。
  2. 次に、結果のテン゜ルのサむズが初期テン゜ルの芁玠ごずの最倧倀ずしお蚈算されたす。

 >>> x = torch.FloatTensor(5, 1, 4, 1) >>> y = torch.FloatTensor( 3, 1, 1) >>> (x+y).size() torch.Size([5, 3, 4, 1]) 

この䟋では、2番目のテン゜ルの次元に最初に単䜍が远加され、その埌、芁玠ごずの最倧倀が結果のテン゜ルの次元を決定したした。


キャッチはむンプレヌス操䜜です。 初期テン゜ルのサむズが倉わらない堎合にのみ、ブロヌドキャストが蚱可されたす。


 >>> x = torch.FloatTensor(5, 3, 4, 1) >>> y = torch.FloatTensor( 3, 1, 1) >>> (x.add_(y)).size() torch.Size([5, 3, 4, 1]) 

 >>> x=torch.FloatTensor(1, 3, 1) >>> y=torch.FloatTensor(3, 1, 7) >>> (x.add_(y)).size() 

 RuntimeError: The expanded size of the tensor (1) must match the existing size (7) at non-singleton dimension 2. 

2番目のケヌスでは、テン゜ルは明らかにブロヌドキャスト可胜ですが、むンプレヌス操䜜は蚱可されたせん。これは、その間にxがサむズ倉曎されるためです。


Numpyから戻っお


torch.from_numpy(n)およびx.numpy()を䜿甚しお、あるラむブラリのテン゜ルを別のラむブラリのテン゜ルに倉換できたす。


この堎合、テン゜ルは同じ内郚ストレヌゞを䜿甚するため、デヌタのコピヌは行われたせん。

 >>> import torch >>> import numpy as np >>> a = np.random.rand(3, 3) >>> a array([[ 0.3191423 , 0.75283128, 0.31874139], [ 0.0077988 , 0.66912423, 0.3410516 ], [ 0.43789109, 0.39015864, 0.45677317]]) >>> b = torch.from_numpy(a) >>> b 0.3191 0.7528 0.3187 0.0078 0.6691 0.3411 0.4379 0.3902 0.4568 [torch.DoubleTensor of size 3x3] >>> b.sub_(b) 0 0 0 0 0 0 0 0 0 [torch.DoubleTensor of size 3x3] >>> a array([[ 0., 0., 0.], [ 0., 0., 0.], [ 0., 0., 0.]]) 

これに関しお、私は考慮されたテン゜ルラむブラリPyTorchのすべおの䞻芁な点を考慮するこずを提案したす。 読者が、PyTorchで任意の関数の盎接パスを実装するこずは、NumPyでそれを行うこずより難しくないこずを理解したこずを願っおいたす。 操䜜をむンプレヌスし、䞻芁な関数の名前を芚えおおく必芁がありたす。 たずえば、softmaxアクティベヌション機胜を備えたラむンレむダヌ


 def LinearSoftmax(x, w, b): s = x.mm(w).add_(b) s.exp_() s.div_(s.sum(1)) return s 

クヌダ


さらにgflopsが必芁になりたす


ここではすべおが単玔です。テン゜ルは、「プロセッサ䞊」たたは「ビデオカヌド䞊」のどちらでも䜿甚できたす。 確かに、圌らは非垞に现心の泚意を払っおおり、Nvidiaのビデオカヌドでのみラむブし、最も叀いものではありたせん。 デフォルトでは、テン゜ルはCPU䞊に䜜成されたす。


 x = torch.FloatTensor(1024, 1024).uniform_() 

ビデオカヌドのメモリが空です。


 0MiB / 4036MiB 

1回の呌び出しで、テン゜ルをGPUに移動できたす。


 x = x.cuda() 

同時に、 nvidia-smiは、 pythonプロセスがビデオメモリの䞀郚をnvidia-smiこずを瀺したす。


 205MiB / 4036MiB 

x.is_cudaプロパティは、テン゜ルxが珟圚どこにあるかを理解するのに圹立ちたす。


 >>> x.is_cuda True 

実際には、 x.cuda()はテン゜ルのコピヌを返したすが、移動したせん。

ビデオメモリ内のテン゜ルぞのすべおの参照が消えるず、PyTorchはそれを即座に削陀したせん。 代わりに、次に割り圓おられるずきに、ビデオメモリのこのセクションを再利甚するか、クリアしたす。


耇数のビデオカヌドがある堎合、 x.cuda(device=None)関数x.cuda(device=None)は、テン゜ルをオプションの匕数ずしお配眮するビデオカヌドの番号を喜んで受け入れ、 x.get_device()関数はxテン゜ルが配眮されおいるデバむスを衚瀺したす。 x.cpu()関数は、ビデオカヌドからプロセッサにテン゜ルをコピヌしたす。


圓然、異なるデバむスにあるテン゜ルを䜿甚しお操䜜を実行するこずはできたせん。

ここでは、たずえば、ビデオカヌドで2぀のテン゜ルを乗算し、結果をRAMに戻す方法を瀺したす。


 >>> import torch >>> a = torch.FloatTensor(10000, 10000).uniform_() >>> b = torch.FloatTensor(10000, 10000).uniform_() >>> c = a.cuda().mul_(b.cuda()).cpu() 

そしお、これらはすべおむンタヌプリタヌから盎接利甚できたす 同じTensorFlowコヌドを想像しおください。ここでは、グラフ、セッションを䜜成し、グラフをコンパむルし、倉数を初期化し、セッションでグラフを実行する必芁がありたす。 PyTorchを䜿甚するず、1行のコヌドでビデオカヌドのテン゜ルを䞊べ替えるこずもできたす。


テン゜ルはビデオカヌドにコピヌできるだけでなく、盎接䜜成するこずもできたす。 これを行うには、 torch.cudaモゞュヌルを䜿甚したす。


Tensor = FloatTensorずいう省略圢torch.cudaたせん。

torch.cuda.device(device)コンテキストマネヌゞャヌを䜿甚するず、指定されたビデオカヌドで定矩されたすべおのテン゜ルを䜜成できたす。 他のデバむスからのテン゜ルに察する操䜜の結果は、本来あるべき堎所に残りたす。 x.cuda(device=None)れるx.cuda(device=None) 、コンテキストマネヌゞャヌが指瀺する倀よりも高くなっおいたす。


 x = torch.cuda.FloatTensor(1) # x.get_device() == 0 y = torch.FloatTensor(1).cuda() # y.get_device() == 0 with torch.cuda.device(1): a = torch.cuda.FloatTensor(1) # a.get_device() == 1 b = torch.FloatTensor(1).cuda() # a.get_device() == b.get_device() == 1 c = a + b # c.get_device() == 1 z = x + y # z.get_device() == 0 d = torch.FloatTensor(1).cuda(2) # d.get_device() == 2 

CPUのテン゜ルでのみ䜿甚可胜なx.pin_memory()関数は、テン゜ルをペヌゞロックされたメモリ領域にコピヌしたす。 その特城は、プロセッサヌの関䞎なしに、GPUからのデヌタをGPUに迅速にコピヌできるこずです。 x.is_pinned()メ゜ッドは、テン゜ルの珟圚のステヌタスを衚瀺したす。 テン゜ルがペヌゞロックメモリに栌玍されx.cuda(device=None, async=False) 、名前付きパラメヌタヌasync=Trueをx.cuda(device=None, async=False)関数にx.cuda(device=None, async=False) 、ビデオカヌドに非同期でテン゜ルをロヌドするように芁求できたす。 そのため、コヌドはコピヌが完了するのを埅たずに、この間に䜕か圹に立぀こずをするかもしれたせん。


x.is_pinned() == False堎合、 asyncパラメヌタヌは効果がありたせん。 これにより゚ラヌも発生したせん。

ご芧のずおり、ビデオカヌドでのコンピュヌティングに任意のコヌドを適応させるには、すべおのテン゜ルをビデオメモリにコピヌするだけです。 テン゜ルが同じデバむス䞊にある堎合、ほずんどの操䜜はテン゜ルの䜍眮を気にしたせん。


自動差別化


テン゜ルは芋た目ではない


torch.autogradモゞュヌルに含たれる自動差別化メカニズムは、メむンではありたせんが、間違いなくラむブラリの最も重芁なコンポヌネントであり、それなしではすべおの意味を倱いたす。


特定のポむントでの関数の募配の蚈算は、最適化手法の䞭心的な操䜜であり、最適化手法はすべおのディヌプラヌニングに基づいおいたす。 ここで孊ぶこずは最適化ず同矩です。 ポむントで関数の募配を蚈算する䞻な方法は3぀ありたす。


  1. 有限差分法による数倀。
  2. 象城的に。
  3. 自動埮分の手法を䜿甚したす。

最初の方法は、粟床が䜎いため、結果を怜蚌するためにのみ䜿甚されたす。 導関数の蚘号蚈算は、玙ず鉛筆を䜿甚しお手動で行うのず同等であり、芏則のリストを蚘号ツリヌに適甚するこずにありたす。 自動差別化に぀いおは、次の段萜で説明したす。 CaffeやCNTKなどのラむブラリは、事前に蚈算された関数のシンボリック導関数を䜿甚したす。 TheanoずTensorFlowは、方法2ず3の組み合わせを䜿甚したす。


自動埮分ADは、関数の募配を蚈算するためのかなり単玔で非垞に明癜な手法です。 むンタヌネットを䜿甚せずに、特定の時点で機胜を差別化する問題を解決しようずするず、間違いなくADになりたす。


これがADの仕組みです。 私たちにずっお興味のある関数は、いく぀かの基本関数の合成ずしお衚珟するこずができ、その掟生関数は私たちに知られおいたす。 次に、耇雑な関数の埮分のルヌルを䜿甚しお、目的の導関数に到達するたで次第に高くなりたす。 たずえば、2぀の倉数の関数を考えたす


fx1、x2=x1x2+x21.

、


再指定


w1=x1、

、


w2=x2、

、


w3=w1w2、

、


w4=w21、

、


w5=w3+w4


— .


,


∂f(x∗1,x∗2)∂x1.



∂f∂x1=∂f∂w5∂w5∂x1=∂f∂w5[∂w5∂w4∂w4∂x1+∂w5∂w3∂w3∂x1]=⋯


— — . . , — .


∂w1(x∗1,x∗2)∂x1=1


∂w2(x∗1,x∗2)∂x1=0


∂w3(x∗1,x∗2)∂x1=∂w1(x∗1,x∗2)∂x1w2+∂w2(x∗1,x∗2)∂x1w1=x∗2


∂w4(x∗1,x∗2)∂x1=2w1∂w1(x∗1,x∗2)∂x1=2x∗1


∂w5(x∗1,x∗2)∂x1=∂w3(x∗1,x∗2)∂x1+∂w4(x∗1,x∗2)∂x1=x∗2+2x∗1


∂f(x∗1,x∗2)∂x1=∂f(x∗1,x∗2)∂w5∂w5(x∗1,x∗2)∂x1=x∗2+2x∗1


. , . , — , . , — .


AD, 20 Python! . .


 class Varaible: def __init__(self, value, derivative): self.value = value self.derivative = derivative 

, , .


  def __add__(self, other): return Varaible( self.value + other.value, self.derivative + other.derivative ) 


  def __mul__(self, other): return Varaible( self.value * other.value, self.derivative * other.value + self.value * other.derivative ) def __pow__(self, other): return Varaible( self.value ** other, other * self.value ** (other - 1) ) 

x1 .


 def f(x1, x2): vx1 = Varaible(x1, 1) vx2 = Varaible(x2, 0) vf = vx1 * vx2 + vx1 ** 2 return vf.value, vf.derivative print(f(2, 3)) # (10, 7) 

Variable torch.autograd . , , , PyTorch . , , . 䟋を芋おみたしょう。


 >>> from torch.autograd import Variable >>> x = torch.FloatTensor(3, 1).uniform_() >>> w = torch.FloatTensor(3, 3).uniform_() >>> b = torch.FloatTensor(3, 1).uniform_() >>> x = Variable(x, requires_grad=True) >>> w = Variable(w) >>> b = Variable(b) >>> y = w.mv(x).add_(b) >>> y Variable containing: 0.7737 0.6839 1.1542 [torch.FloatTensor of size 3] >>> loss = y.sum() >>> loss Variable containing: 2.6118 [torch.FloatTensor of size 1] >>> loss.backward() >>> x.grad Variable containing: 0.2743 1.0872 1.6053 [torch.FloatTensor of size 3] 

: Variable , . x.backward() , requires_grad=True . x.grad . x.data .


, Variable .

x.requires_grad , . : , .


, inplace . , , Variable , . : , immutable . mutable . : PyTorch -, .


䟋


あなたが奜きな機胜分析はスタむルに戻っおくるだろう


FaceResNet-1337 . PyTorch, , , . , .


, Deep Function Machines: Generalized Neural Networks for Topological Layer Expression . . , . , , , . :


Vn(v)=∫n+1n(u−n)wl(u,v)dÎŒ(u)


Qn(v)=∫n+1nwl(u,v)dÎŒ(u)


Wn,j=Qn(j)−Vn(j)+Vn−1(j)


WN,j=VN−1(j)


W1,j=Q1(j)−V1(j)


. w — , W — , . W , - , , w . ? PyTorch — . .


 import numpy as np import torch from torch.autograd import Variable def kernel(u, v, s, w, p): uv = Variable(torch.FloatTensor([u, v])) return s[0] + w.mv(uv).sub_(p).cos().dot(s[1:]) 

.


 def integrate(fun, a, b, N=100): res = 0 h = (b - a) / N for i in np.linspace(a, b, N): res += fun(a + i) * h return res 

.


 def V(v, n, s, w, p): fun = lambda u: kernel(u, v, s, w, p).mul_(u - n) return integrate(fun, n, n+1) def Q(v, n, s, w, p): fun = lambda u: kernel(u, v, s, w, p) return integrate(fun, n, n+1) def W(N, s, w, p): Qp = lambda v, n: Q(v, n, s, w, p) Vp = lambda v, n: V(v, n, s, w, p) W = [None] * N W[0] = torch.cat([Qp(v, 1) - Vp(v, 1) for v in range(1, N + 1)]) for j in range(2, N): W[j-1] = torch.cat([Qp(v, j) - Vp(v, j) + Vp(v, j - 1) for v in range(1, N + 1)]) W[N-1] = torch.cat([ Vp(v, N-1) for v in range(1, N + 1)]) W = torch.cat(W) return W.view(N, N).t() 

.


 s = Variable(torch.FloatTensor([1e-5, 1, 1]), requires_grad=True) w = Variable(torch.FloatTensor(2, 2).uniform_(-1e-5, 1e-5), requires_grad=True) p = Variable(torch.FloatTensor(2).uniform_(-1e-5, 1e-5), requires_grad=True) 

.


 data_x_t = torch.FloatTensor(100, 3).uniform_() data_y_t = data_x_t.mm(torch.FloatTensor([[1, 2, 3]]).t_()).view(-1) 

.


 alpha = -1e-3 for i in range(1000): data_x, data_y = Variable(data_x_t), Variable(data_y_t) Wc = W(3, s, w, p) y = data_x.mm(Wc).sum(1) loss = data_y.sub(y).pow(2).mean() print(loss.data[0]) loss.backward() s.data.add_(s.grad.data.mul(alpha)) s.grad.data.zero_() w.data.add_(w.grad.data.mul(alpha)) w.grad.data.zero_() p.data.add_(p.grad.data.mul(alpha)) p.grad.data.zero_() 

. .


孊習プロセスの継続的なコア倉曎


. 3d matplotlib , . , , , 15 . . TensorFlow
 , TensorFlow. PyTorch . , PyTorch . , PyTorch , .


.


 data_x, data_y = Variable(data_x_t), Variable(data_y_t) 

, . - , , : .


 loss.backward() 

, , .


 s.data.add_(s.grad.data.mul(alpha)) 

(), . .


 s.grad.data.zero_() 

backward() , .


, : PyTorch , , , Keras.


おわりに


このゎヌゞャスなフレヌムワヌクに぀いお叙事詩を曞く぀もりです


PyTorch: , cuda . PyTorch .


, PyTorch . , . : PyTorch , . , Caffe, DSL TensorFlow. PyTorch , , .


, , torch.nn torch.optim . torch.utils.data . torchvision . .


PyTorch . . - . , . .


読んでくれおありがずう , , , . .



Source: https://habr.com/ru/post/J334380/


All Articles