fundo
Reconhecer a primalidade parece um ajuste inadequado para redes neurais (artificiais). Entretanto, o teorema da aproximação universal afirma que as redes neurais podem se aproximar de qualquer função contínua, portanto, em particular, deve ser possível representar qualquer função com suporte finito que se deseja. Então, vamos tentar reconhecer todos os números primos entre o primeiro milhão de números.
Mais precisamente, como este é um site de programação, vamos subir para 2 ^ 20 = 1.048.576. O número de primos abaixo deste limite é 82.025 ou aproximadamente 8%.
Desafio
Qual o tamanho de uma rede neural que classifica corretamente todos os números inteiros de 20 bits como primos ou não primos?
Para os propósitos deste desafio, o tamanho de uma rede neural é o número total de pesos e desvios necessários para representá-la.
Detalhes
O objetivo é minimizar o tamanho de uma única rede neural explícita.
A entrada para sua rede será um vetor de comprimento 20 contendo os bits individuais de um número inteiro, representados com 0s e 1s ou alternativamente com -1s e + 1s. A ordem destes pode ser o primeiro com o bit mais significativo ou o primeiro com o menos significativo.
A saída da sua rede deve ser um número único, de modo que, acima de algum ponto de corte, a entrada seja reconhecida como primária e abaixo do mesmo ponto de corte, a entrada seja reconhecida como não primária. Por exemplo, positivo pode significar primo (e negativo, não primo) ou, alternativamente, maior que 0,5 pode significar primo (e menor que 0,5, não primo).
A rede deve ser 100% precisa em todas as 2 ^ 20 = 1.048.576 entradas possíveis. Como mencionado acima, observe que existem 82.025 números primos nesse intervalo. (Daqui resulta que sempre a saída "not prime" seria 92% precisa.)
Em termos de terminologia de rede neural padrão, isso provavelmente seria chamado de ajuste excessivo . Em outras palavras, seu objetivo é super-ajustar perfeitamente os números primos. Outras palavras que se pode usar são que o "conjunto de treinamento" e o "conjunto de teste" são os mesmos.
Esse desafio não considera o número de parâmetros "treináveis" ou "aprendíveis". De fato, é provável que sua rede contenha pesos codificados e o exemplo abaixo é totalmente codificado. Em vez disso, todos os pesos e desvios são considerados parâmetros e são contados.
O comprimento do código necessário para treinar ou gerar sua rede neural não é relevante para sua pontuação, mas a publicação do código relevante é certamente apreciada.
Linha de base
Como linha de base, é possível "memorizar" todos os 82.025 primos com 1.804.551 pesos totais e desvios.
Observe que este código a seguir inclui muitas coisas: um exemplo de trabalho, código de teste de trabalho, uma definição funcional de rede neural usando uma biblioteca de rede neural conhecida, uma rede neural "codificada" (ou pelo menos não treinada), e uma medida de trabalho de pontuação.
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."
O que é uma rede neural?
Para os propósitos deste desafio, podemos escrever uma definição estreita, mas precisa, de uma rede neural (artificial). Para algumas leituras externas, sugiro Wikipedia sobre rede neural artificial , rede neural feedforward , perceptron multicamada e função de ativação .
Uma rede neural feedforward é uma coleção de camadas de neurônios. O número de neurônios por camada varia, com 20 neurônios na camada de entrada, algum número de neurônios em uma ou mais camadas ocultas e 1 neurônio na camada de saída. (Deve haver pelo menos uma camada oculta porque os números primos e não primos não são linearmente separáveis de acordo com seus padrões de bits.) No exemplo da linha de base acima, os tamanhos das camadas são [20, 82025, 1].
Os valores dos neurônios de entrada são determinados pela entrada. Como descrito acima, serão 0s e 1s correspondentes aos bits de um número entre 0 e 2 ^ 20 ou -1s e + 1s da mesma forma.
Os valores dos neurônios de cada camada seguinte, incluindo a camada de saída, são determinados previamente a partir da camada. Primeiro, uma função linear é aplicada, de maneira totalmente conectada ou densa . Um método para representar essa função é usar uma matriz de pesos . Por exemplo, as transições entre as duas primeiras camadas da linha de base podem ser representadas com uma matriz 82025 x 20. O número de pesos é o número de entradas nessa matriz, por exemplo, 1640500. Em seguida, cada entrada possui um termo de viés (separado) adicionado. Isso pode ser representado por um vetor, por exemplo, uma matriz 82025 x 1 em nosso caso. O número de desvios é o número de entradas, por exemplo, 82025. (Observe que os pesos e desvios juntos descrevem uma função linear afim .)
Um peso ou viés é contado, mesmo que seja zero. Para os fins desta definição restrita, os vieses contam como pesos, mesmo que sejam todos zero. Observe que no exemplo da linha de base, apenas dois pesos distintos (+1 e -1) são usados (e apenas vieses ligeiramente mais distintos); no entanto, o tamanho é superior a um milhão, porque a repetição não ajuda na pontuação de forma alguma.
Finalmente, uma função não linear denominada função de ativação é aplicada de entrada no resultado dessa função linear afim. Para os fins desta definição restrita, as funções de ativação permitidas são ReLU , tanh e sigmoid . A camada inteira deve usar a mesma função de ativação.
No exemplo da linha de base, o número de pesos é 20 * 82025 + 82025 * 1 = 1722525 e o número de desvios é 82025 + 1 = 82026, para uma pontuação total de 1722525 + 82026 = 1804551. Como exemplo simbólico, se houver mais uma camada e os tamanhos das camadas eram [20, a, b, 1], então o número de pesos seria 20 * a + a * b + b * 1 e o número de vieses seria a + b + 1.
Essa definição de rede neural é bem suportada por muitas estruturas, incluindo Keras , scikit-learn e Tensorflow . Keras é usado no exemplo da linha de base acima, com o código essencialmente da seguinte maneira:
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)
Se as matrizes de ponderação e polarização forem matrizes numpy , o numpy.size informará diretamente o número de entradas.
Existem outros tipos de redes neurais?
Se você deseja uma definição única e precisa de rede neural e pontuação para os propósitos deste desafio, use a definição na seção anterior. Se você acha que "qualquer função" vista da maneira correta é uma rede neural sem parâmetros , use a definição na seção anterior.
Se você é um espírito mais livre, encorajo você a explorar mais. Talvez sua resposta não conte para o desafio estreito , mas talvez você se divirta mais. Algumas outras idéias que você pode tentar incluem funções de ativação mais exóticas, redes neurais recorrentes (lendo um bit de cada vez), redes neurais convolucionais, arquiteturas mais exóticas, softmax e LSTMs (!). Você pode usar qualquer função de ativação padrão e qualquer arquitetura padrão. Uma definição liberal de recursos de rede neural "padrão" pode incluir qualquer coisa postada no arxiv antes da publicação desta pergunta.