バックグラウンド
素数性の認識は、(人工)ニューラルネットワークにはあまり適していないと思われます。ただし、普遍近似定理では、ニューラルネットワークは任意の連続関数を近似できるため、特に、希望する有限サポート関数を表すことができるはずです。それで、最初の100万の数の中のすべての素数を認識してみましょう。
より正確には、これはプログラミングWebサイトであるため、2 ^ 20 = 1,048,576まで進みましょう。このしきい値を下回る素数の数は82,025または約8%です。
チャレンジ
すべての20ビット整数を素数または素数として正しく分類できるニューラルネットワークはどれくらい小さいでしょうか?
この課題のために、ニューラルネットワークのサイズは、それを表現するために必要な重みとバイアスの総数です。
詳細
目標は、単一の明示的なニューラルネットワークのサイズを最小化することです。
ネットワークへの入力は、整数の個々のビットを含む長さ20のベクトルになり、0と1で表されるか、-1と+1で表されます。これらの順序は、最上位ビットが先か、最下位ビットが先です。
ネットワークの出力は単一の数値である必要があります。これにより、カットオフ値を超えると入力が素数として認識され、同じカットオフ値を下回ると入力が素数でないと認識されます。たとえば、正は素数を意味し(負ではなく負)、あるいは0.5より大きい場合は素数を意味します(そして0.5未満は素数ではありません)。
ネットワークは、すべての2 ^ 20 = 1,048,576の入力で100%正確でなければなりません。上記のように、この範囲には82,025個の素数があることに注意してください。(常に「素数ではない」を出力すると、92%正確になります。)
標準的なニューラルネットワークの用語では、これはおそらくオーバーフィッティングと呼ばれます。言い換えれば、あなたの目標は素数を完全に過剰適合させることです。他の言葉としては、「トレーニングセット」と「テストセット」が同じであることです。
この課題では、「トレーニング可能な」または「学習可能な」パラメータの数は考慮されていません。実際、ネットワークにはハードコーディングされた重みが含まれている可能性が高く、以下の例は完全にハードコーディングされています。代わりに、すべての重みとバイアスがパラメーターと見なされ、カウントされます。
ニューラルネットワークをトレーニングまたは生成するために必要なコードの長さはスコアに関係ありませんが、関連するコードを投稿することは確かにありがたいです。
ベースライン
ベースラインとして、82,025個のすべての素数を1,804,551個の合計重みとバイアスで「記憶」することができます。
以下のこのコードには、実例、テストコード、既知のニューラルネットワークライブラリを使用したニューラルネットワークの動作定義、「ハードコード」(または少なくとも「トレーニングされていない」)ニューラルネットワーク、スコアの実際の測定。
import numpy as np
bits = 20
from keras.models import Sequential
from keras.layers import Dense
from sympy import isprime
# Hardcode some weights
weights = []
biases = []
for n in xrange(1<<bits):
if not isprime(n):
continue
bit_list = [(n / (1 << i))%2 for i in xrange(bits)]
weight = [2*bit - 1 for bit in bit_list]
bias = - (sum(bit_list) - 1)
weights.append(weight)
biases .append(bias)
nprimes = len(biases)
weights1 = np.transpose(np.array(weights))
biases1 = np.array(biases )
weights2 = np.full( (nprimes,1), 1 )
biases2 = np.array( [0] )
model = Sequential()
model.add(Dense(units=nprimes, activation='relu', input_dim=bits, weights=[weights1, biases1]))
model.add(Dense(units=1, activation='relu', weights=[weights2, biases2]))
print "Total weights and biases: {}".format( np.size(weights1) + np.size(weights2) + np.size(biases1) + np.size(biases2) )
# Evaluate performance
x = []
y = []
for n in xrange(1<<bits):
row = [(n / (1 << i))%2 for i in xrange(bits)]
x.append( row )
col = 0
if isprime(n):
col = 1
y.append( col )
x = np.array(x)
y = np.array(y)
model.compile(loss='binary_crossentropy', optimizer='sgd', metrics=['accuracy'])
loss, accuracy = model.evaluate(x, y, batch_size=256)
if accuracy == 1.0:
print "Perfect fit."
else:
print "Made at least one mistake."
ニューラルネットワークとは何ですか?
この課題のために、(人工)ニューラルネットワークの狭いが正確な定義を書き留めることができます。一部の外部リーディングについては、ウィキペディアの人工ニューラルネットワーク、フィードフォワードニューラルネットワーク、多層パーセプトロン、および活性化機能をお勧めします。
フィードフォワードニューラルネットワークはの集まりである層ニューロンの。層ごとのニューロンの数は異なります。入力層に20個のニューロン、1つ以上の隠れ層にいくつかのニューロン、出力層に1個のニューロンがあります。(素数と素数はビットパターンに従って線形に分離できないため、少なくとも1つの隠れ層が必要です。)上記のベースラインの例では、層のサイズは[20、82025、1]です。
入力ニューロンの値は、入力によって決まります。上記のように、これは0と2 ^ 20の間の数のビットに対応する0と1、または同様に-1と+1のいずれかです。
出力層を含む次の各層のニューロンの値は、層から事前に決定されます。最初に、線形関数が完全に接続された形式または高密度形式で適用されます。このような関数を表す1つの方法は、重み行列を使用することです。たとえば、ベースラインの最初の2つのレイヤー間の遷移は、82025 x 20マトリックスで表すことができます。重みの数は、このマトリックス内のエントリの数、たとえば1640500です。各エントリには、(別個の)バイアス項が追加されます。これは、ベクトル(例では82025 x 1行列)で表すことができます。バイアスの数は、エントリの数です(例:82025)(重みとバイアスはともにアフィン線形関数を表すことに注意してください)。
重みまたはバイアスは、ゼロであってもカウントされます。この狭い定義の目的のために、バイアスはすべてがゼロであっても重みとしてカウントされます。ベースラインの例では、2つの異なる重み(+1と-1)のみが使用されていることに注意してください(わずかに異なるバイアスのみ)。それでも、サイズが100万を超えるのは、繰り返しがスコアに役立たないためです。
最後に、活性化関数と呼ばれる非線形関数が、このアフィン線形関数の結果にエントリ単位で適用されます。この狭い定義のために、許可されるアクティベーション関数はReLU、tanh、およびsigmoidです。レイヤー全体で同じアクティベーション機能を使用する必要があります。
ベースラインの例では、重みの数は20 * 82025 + 82025 * 1 = 1722525であり、バイアスの数は82025 + 1 = 82026であり、合計スコアは1722525 + 82026 = 1804551です。象徴的な例として、もう1つのレイヤーとレイヤーサイズが代わりに[20、a、b、1]であった場合、重みの数は20 * a + a * b + b * 1になり、バイアスの数はa + b + 1になります。
ニューラルネットワークのこの定義は、Keras、scikit-learn、およびTensorflowを含む多くのフレームワークによって十分にサポートされています。Kerasは上記のベースラインの例で使用されており、コードは基本的に次のとおりです。
from keras.models import Sequential
model = Sequential()
from keras.layers import Dense
model.add(Dense(units=82025, activation='relu', input_dim=20, weights=[weights1, biases1]))
model.add(Dense(units=1, activation='relu', weights=[weights2, biases2]))
score = numpy.size(weights1) + numpy.size(biases1) + numpy.size(weights2) + numpy.size(biases2)
重み行列とバイアス行列がnumpy配列の場合、numpy.sizeはエントリの数を直接通知します。
他の種類のニューラルネットワークはありますか?
この課題のためにニューラルネットワークとスコアの単一の正確な定義が必要な場合は、前のセクションの定義を使用してください。正しい方法で見た「任意の関数」がパラメーターのないニューラルネットワークであると思われる場合は、前のセクションの定義を使用してください。
あなたがより自由な精神であれば、私はあなたがさらに探検することをお勧めします。おそらくあなたの答えは狭い挑戦にカウントされないでしょうが、多分あなたはもっと楽しくなるでしょう。他のアイデアとしては、よりエキゾチックな活性化関数、リカレントニューラルネットワーク(一度に1ビットずつ読み取る)、畳み込みニューラルネットワーク、よりエキゾチックなアーキテクチャ、ソフトマックス、LSTM(!)などがあります。標準のアクティベーション機能と標準のアーキテクチャを使用できます。「標準の」ニューラルネットワーク機能の自由な定義には、この質問を投稿する前にarxivに投稿されたものが含まれます。