機械学習ゴルフ:乗算


68

このコミュニティに異なる種類のゴルフチャレンジを提案したいと思います。

(人工)ニューラルネットワークは、与えられた(通常は未知の)関数を近似するように設計およびトレーニングできる非常に一般的な機械学習モデルです。彼らは多くの場合、ニューラルネットワーク上のプライマーのために...私たちは、音声認識、画像分類の特定の種類、自律走行システムでは、さまざまなタスクのようにアルゴリズム的解決する方法がわからない、非常に複雑な問題を解決するために使用しているこの素晴らしいを考えますウィキペディアの記事

これが一連の機械学習のゴルフチャレンジになりたいと願う最初のものであるため、できるだけシンプルなものにしたいと思います。

選択した言語とフレームワークで、与えられた)がと間(を含む)のすべての整数積を計算するニューラルネットワークを設計およびトレーニングします。(x1,x2)x1x2x1,x21010

パフォーマンス目標

資格を得るために、モデルはこれらのエントリの正しい結果からを超えて逸脱することはできません。0.5

ルール

あなたのモデル

  • 「従来の」ニューラルネットワークである必要があります(ノードの値は、前のレイヤーのノードの一部の重み付き線形結合と、それに続く活性化関数として計算されます)、
  • 次の標準アクティベーション関数のみを使用できます。
    1. linear(x)=x
    2. softmax(x)i=exijexj
    3. seluα,β(x)={βx, if x>0αβ(ex1), otherwise
    4. softplus(x)=ln(ex+1)
    5. leaky-reluα(x)={x, if x<0αx, otherwise
    6. tanh(x)
    7. sigmoid(x)=exex+1
    8. hard-sigmoid(x)={0, if x<2.51, if x>2.50.2x+0.5, otherwise
    9. ex
  • 取らなければならない、整数のいずれかのタプル/ベクトル/リストとして/ ...またはその入力としてのみ浮かびます(x1,x2)
  • 答えを整数、浮動小数点数(またはこの答えを含む適切なコンテナ、例えばベクトルやリスト)として返します。

答えには、モデルの訓練された重みを含む、結果を確認するために必要なすべてのコードを含める(またはリンクする)必要があります。

得点

重み(バイアスの重みを含む)の数が最も少ないニューラルネットワークが優先されます。

楽しい!


9
サイトへようこそ!この課題は、ニューラルネットワークのより堅牢な定義から大きな利益を得ることができると思います。ここにはいくつかのことがあります1)NNの知識をまだ暗示していない言語でそれを述べることは非常に良いでしょう2)外部ソースにリンクするのではなく、投稿にアクティベーション関数をリストするべきです(外部リンクは変更または非表示にできます)。
ウィートウィザード

4
ウェイトを再利用/畳み込み層を使用できますか?(ボーナスを削除することをお勧めします。チャレンジに何も追加せず、主な目標から気を散らすだけです。)重みは実際のものであるか、複雑になる可能性がありますか?
flawr

4
あなたの言葉遣いは、レイヤー3からのノードがレイヤー1からの入力を使用できないことを意味します。レイヤー2のノードにf(x) = x入力を転送するだけのことは重みがかかりますか?
グリムミー

4
右側の列にはサンドボックスへのリンクが必要です。サンドボックスは、質問がメインサイトに投稿される前にこの種の問題を修正するために明示的に作成されたものです。また、ネットワークの哲学は、質問を修正してから再開する方が、質問が修正された後に意味をなさないか、質問に加えることができる変更を厳しく制限する回答を得るよりも良いということです。
ピーターテイラー

7
どういたしまして。これらの種類の問題は、他の人が同じ種類の間違いをするのを見た長年の経験によって検出されます。いくつかのあいまいさがサンドボックスをすり抜けますが、さらに多くのものがそこにあります。私の最初のコメントに示されているように、 2か月前のニューラルネットの質問とまったく同じ問題があったため、これは間違いなくキャッチされたでしょう。
ピーターテイラー

回答:


37

21 13 11 9ウェイト

これは、1次元の実数の場合、多項式恒等式に帰着する双線形形式の偏光恒等式に基づいています。

xy=(x+y)2(xy)24

したがって、線形変換を使用してy1計算するだけで、次の前処理ステップの絶対値になります。次に、「ハード」部分は、以下で説明する平方を計算し、その後、差とスケーリングを計算するだけです再び線形操作です。[x+y, x-y]y3y1

平方を計算するには、約以内のすべての整数に対して正確でなければならない指数級数を使用します。このシリーズの形式はs{0,1,2,,20}0.5

approx_square(x)=i=02wiexp(0.0001ix)

ここで、重みW2()に最適化したところです。この近似全体も、指数関数的活性化が間に挟まれた2つの線形変換のみで構成されています。このアプローチにより、最大偏差は約となります。=(wi)i0.02

function p = net(x)
% 9 weights
one = 1; 
mone =-1;
zero = 0;
fourth = 0.25;
W1 = [1e-4, 2e-4];
W2  = [-199400468.100687;99700353.6313757];
b2 = 99700114.4299316;
leaky_relu = @(a,x)max(a*x,x); 


% Linear
y0 = [one, one; one, mone] * x;

% Linear + ReLU
y1 = mone * y0;
y2 = [leaky_relu(zero, y0), leaky_relu(zero, y1)];

% Linear
y3 = y2 * [one; one];

% Linear + exp
y4 = exp(y3 * W1); 

% Linear + Bias
y5 =  y4 * W2 + b2;

% Linear
y6 = [one, mone]*y5;
p = y6 * fourth;

end

オンラインでお試しください!


TIOリンクのフッターにあるチェックコードは、のアプリケーションを見逃していますabs。とにかくすべてが順調です。
クリスチャンジーバーズ

@ChristianSieversありがとう、TIOリンクを更新しました!
flawr

私は好奇心からNNの専門家ではありませんが、体重のカウントはどのように行われますか?y0ニーズ4、y1ニーズ2、y3ニーズ2、y4ニーズ1、y5ニーズ1、y6ニーズ2。それは12です。
マーガレットブルーム

3
@MargaretBloomはい、これは確かに少し珍しいですが、OPはコメントで、同じ重みを複数回使用しても、重みを再利用でき、一度だけカウントする必要があると述べました。したがって、使用しているすべての重みは、関数の最初の部分で定義されています。
フレア

31

7つの重み

eps = 1e-6
c = 1 / (2 * eps * eps)

def f(A, B):
	e_s = exp(eps * A + eps * B)  # 2 weights, exp activation
	e_d = exp(eps * A - eps * B)  # 2 weights, exp activation
	return c * e_s + (-c) * e_d + (-1 / eps) * B  # 3 weights, linear activation

オンラインでお試しください!

テイラー展開基づいて、小さなに対して次の近似等式を使用します。ϵex1+x+x22

ABeϵA+ϵBeϵAϵB2ϵ2Bϵ

ピッキング十分に小さくすることは必要な誤差範囲内たちを取得します。およびはコード内の定数の重みであることに注意してください。ϵepsc


1
これが「従来のニューラルネットワーク」(ルール#1)としてカウントされるかどうかはわかりませんが、1つに再フォーマットできることは明らかなので、問題はありません。いい解決策!
ステファンメスケン

1
C = -B(1つの重み)を定義[e_s, e_d] = conv([A,B,C], [eps, eps])し、1つの重みを節約するために(2つの重み)を持つことができます:)(ところで:非常に賢いアプローチ!)
flawr

(私はを追加するのを忘れていましたexp
flawr

4
ウェイトを再利用することで、さらに低くすることもできます。同じウェイトを何度も数える必要はありません。
flawr

2
@flawrこれは素晴らしいトリックですが、コメントでの畳み込みと重みの再利用の許容範囲がこれを非常に異なる課題にしているので、この答えをそのままにしておきます。
xnor

22

33 31ウェイト

# Activation functions
sub hard { $_[0] < -2.5 ? 0 : $_[0] > 2.5 ? 1 : 0.2 * $_[0] + 0.5 }
sub linear { $_[0] }

# Layer 0
sub inputA() { $a }
sub inputB() { $b }

# Layer 1
sub a15() { hard(5*inputA) }

# Layer 2
sub a8()  { hard(-5*inputA + 75*a15 - 37.5) }

# Layer 3
sub aa()  { linear(-5*inputA + 75*a15 - 40*a8) }

# Layer 4
sub a4()  { hard(aa - 17.5) }

# Layer 5
sub a2()  { hard(aa - 20*a4 - 7.5) }

# Layer 6
sub a1()  { linear(0.2*aa - 4*a4 - 2*a2) }

# Layer 7
sub b15() { hard(0.25*inputB - 5*a15) }
sub b8()  { hard(0.25*inputB - 5*a8) }
sub b4()  { hard(0.25*inputB - 5*a4) }
sub b2()  { hard(0.25*inputB - 5*a2) }
sub b1()  { hard(0.25*inputB - 5*a1) }

# Layer 8
sub output() { linear(-300*b15 + 160*b8 + 80*b4 + 40*b2 + 20*b1 - 10*inputA) }

# Test
for $a (-10..10) {
        for $b (-10..10) {
                die if abs($a * $b - output) >= 0.5;
        }
}

print "All OK";

オンラインでお試しください!

これは(sorta)バイナリで長い乗算を行うため、正確な結果を返します。0.5エラーウィンドウを利用して、これをさらにゴルフにかけることができるはずですが、どうすればよいかわかりません。

レイヤー1〜6は、最初の入力を5つの「ビット」に分解します。ゴルフの理由から、実際のバイナリは使用しません。最上位の「ビット」の重みは16ではなく-15であり、入力が0の場合、すべての「ビット」は0.5です(IDが保持されるため、依然として問題ありませんinputA = -15*a15 + 8*a8 + 4*a4 + 2*a2 + 1*a1)。


1
誰かがハードコードされたANN化された乗算アルゴリズムを思い付くと期待していました。しかし、私はそれが最初の応答だとは思わなかった。よくやった!(MNISTデータセットまたは他のより弾力性のあるML問題でこのような何かを引き出すことができるかどうかも楽しみです:D。)
Stefan Mesken

14

43の重み

これまでに投稿された2つのソリューションは非常に巧妙ですが、それらのアプローチは機械学習のより伝統的なタスク(OCRなど)では機能しない可能性があります。したがって、私は他の人々がそれを改善して機械学習の世界に吸い込まれることを願って、このタスクに「汎用」(巧妙なトリックなし)ソリューションを提出したいと思います:

私のモデルは、TensorFlow 2.0に組み込まれた2つの隠されたレイヤーを持つ非常に単純なニューラルネットワークです(ただし、他のフレームワークも同様に機能します)。

model = tf.keras.models.Sequential([
tf.keras.layers.Dense(6, activation='tanh', input_shape=(2,)),
tf.keras.layers.Dense(3, activation='tanh'),
tf.keras.layers.Dense(1, activation='linear')
])

ご覧のとおり、すべてのレイヤーは密集しており(これは最適ではありません)、アクティベーション関数はtanhです(このタスクでは実際に問題ないかもしれません)。ただし、このタスクの性質上、線形活性化機能があります。

43の重みがあります。

  • (2+1)6=18
  • (6+1)3=21
  • (3+1)1=4

1010

次に、私はそれらを微調整しました-整数乗算タスクのいずれかの最大偏差を最適化します。残念ながら、私のノートには最終的に行った細かいチューニングは表示されませんが、非常に小さなものでした。441個のバッチサイズで、これらの441個のトレーニングサンプルの100エポック付近。

これらは私が最終的に得た重みです:

[<tf.Variable 'dense/kernel:0' shape=(2, 6) dtype=float32, numpy=
 array([[ 0.10697944,  0.05394982,  0.05479664, -0.04538541,  0.05369904,
         -0.0728976 ],
        [ 0.10571832,  0.05576797, -0.04670485, -0.04466859, -0.05855528,
         -0.07390639]], dtype=float32)>,
 <tf.Variable 'dense/bias:0' shape=(6,) dtype=float32, numpy=
 array([-3.4242163, -0.8875816, -1.7694025, -1.9409281,  1.7825342,
         1.1364107], dtype=float32)>,
 <tf.Variable 'dense_1/kernel:0' shape=(6, 3) dtype=float32, numpy=
 array([[-3.0665843 ,  0.64912266,  3.7107112 ],
        [ 0.4914808 ,  2.1569328 ,  0.65417236],
        [ 3.461693  ,  1.2072319 , -4.181983  ],
        [-2.8746269 , -4.9959164 ,  4.505049  ],
        [-2.920127  , -0.0665407 ,  4.1409926 ],
        [ 1.3777553 , -3.3750365 , -0.10507642]], dtype=float32)>,
 <tf.Variable 'dense_1/bias:0' shape=(3,) dtype=float32, numpy=array([-1.376577  ,  2.8885336 ,  0.19852689], dtype=float32)>,
 <tf.Variable 'dense_2/kernel:0' shape=(3, 1) dtype=float32, numpy=
 array([[-78.7569  ],
        [-23.602606],
        [ 84.29587 ]], dtype=float32)>,
 <tf.Variable 'dense_2/bias:0' shape=(1,) dtype=float32, numpy=array([8.521169], dtype=float32)>]

0.44350433910=90.443504

私のモデルはここで見つけることができ、オンラインで試すこともできます!Google Colab環境で。


6

2つの重み

他の答えに触発されて、偏光アイデンティティを別の方法で近似しました。すべての小さな、ϵ>0

xyeϵx+ϵy+eϵxϵyeϵxϵyeϵx+ϵy4ϵ2.

このチャレンジにはで十分です。ϵ=0.01

この近似の明らかなニューラルネット実装は、重みを取ります。これらの4つのウェイトは因数分解することにより、3つのまでゴルフできます。。上記のコメントで述べたように、マシン精度の重みを持つすべてのニューラルネットは、2つの異なる重みのみを持つ(巨大な)ニューラルネットにゴルフすることができます。この手順を適用して、次のMATLABコードを記述しました。{±ϵ,±(4ϵ2)1}{±ϵ,(4ϵ3)1}±(4ϵ2)1=±ϵ(4ϵ3)1

function z=approxmultgolfed(x,y)

w1 = 0.1;   % first weight
w2 = -w1;   % second weight

k  = 250000;
v1 = w1*ones(k,1);
v2 = w2*ones(k,1);

L1 = w1*eye(2);
L2 = [ w1 w1; w2 w2; w1 w2; w2 w1 ];
L3 = [ v1 v1 v2 v2 ];
L4 = v1';

z = L4 * L3 * exp( L2 * L1 * [ x; y ] );

言うまでもなく、このニューラルネットは1,250,010個の重みで構成されており、そのすべてがます。{±0.1}

たった1つの重さで逃げる方法(!)

重みがにあるニューラルネットを、重みが1つだけの大きいニューラルネット、つまりシミュレートできることがます。実際、乗算は次のように実装できます。{±0.1}0.10.1

0.1x=wwx,

ここで、はエントリの列ベクトルで、すべて等しくなります。重みの半分が正のニューラルネットの場合、この変換は倍のニューラルネットを生成します。w100.110.5

この手順の明白な一般化は、重みがニューラルネットを単一の重み大きなニューラルネットに変換します。上記の私のコメントの手順と組み合わせると、したがって、機械精度の重みを持つすべてのニューラルネットを単一重みのニューラルネットに変換できると考えられます。{±10k}10k

(おそらく、将来のニューラルネットゴルフの課題で再利用されたウェイトのスコアを変更する必要があります。)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.