Một mạng lưới thần kinh có thể nhận ra các số nguyên tố?


26

Lý lịch

Nhận biết tính nguyên thủy có vẻ như không phù hợp với mạng lưới thần kinh (nhân tạo). Tuy nhiên, định lý gần đúng phổ quát nói rằng các mạng nơ ron có thể xấp xỉ bất kỳ hàm liên tục nào, do đó, đặc biệt có thể biểu diễn bất kỳ hàm nào được hỗ trợ chính xác mà một mong muốn. Vì vậy, hãy cố gắng nhận ra tất cả các số nguyên tố trong số một triệu số đầu tiên.

Chính xác hơn, vì đây là một trang web lập trình, chúng ta hãy lên tới 2 ^ 20 = 1.048.576. Số lượng các số nguyên tố dưới ngưỡng này là 82.025 hoặc khoảng 8%.

Thử thách

Làm thế nào nhỏ của một mạng thần kinh mà bạn có thể tìm thấy phân loại chính xác tất cả các số nguyên 20 bit là số nguyên tố hoặc không phải là số nguyên tố?

Đối với mục đích của thử thách này, kích thước của mạng nơ ron là tổng số trọng lượng và độ lệch cần thiết để thể hiện nó.

Chi tiết

Mục tiêu là để giảm thiểu kích thước của một mạng thần kinh duy nhất, rõ ràng.

Đầu vào vào mạng của bạn sẽ là một vectơ có độ dài 20 chứa các bit riêng lẻ của một số nguyên, được biểu thị bằng 0 và 1 hoặc thay thế bằng -1 và + 1s. Thứ tự của những thứ này có thể là bit đầu tiên có ý nghĩa nhất hoặc ít nhất có ý nghĩa nhất.

Đầu ra của mạng của bạn phải là một số duy nhất, sao cho trên một số điểm cắt, đầu vào được nhận là số nguyên tố và dưới cùng mức cắt, đầu vào được nhận là không phải là số nguyên tố. Ví dụ: dương có thể có nghĩa là số nguyên tố (và âm không phải là số nguyên tố) hoặc lớn hơn 0,5 có thể có nghĩa là số nguyên tố (và nhỏ hơn 0,5 không phải là số nguyên tố).

Mạng phải chính xác 100% trên tất cả 2 ^ 20 = 1.048.576 đầu vào có thể. Như đã đề cập ở trên, lưu ý rằng có 82.025 số nguyên tố trong phạm vi này. (Theo sau, luôn luôn xuất ra "không phải là số nguyên tố" sẽ chính xác 92%.)

Về mặt thuật ngữ mạng thần kinh tiêu chuẩn, điều này có thể sẽ được gọi là quá mức . Nói cách khác, mục tiêu của bạn là hoàn toàn phù hợp với các số nguyên tố. Những từ khác người ta có thể sử dụng là "tập huấn luyện" và "tập kiểm tra" là như nhau.

Thử thách này không xem xét số lượng tham số "có thể huấn luyện" hoặc "có thể học được". Thật vậy, mạng của bạn có thể chứa các trọng số được mã hóa cứng và ví dụ dưới đây hoàn toàn được mã hóa cứng. Thay vào đó, tất cả các trọng số và độ lệch được coi là tham số và được tính.

Độ dài của mã cần thiết để đào tạo hoặc tạo mạng lưới thần kinh của bạn không liên quan đến điểm số của bạn, nhưng việc đăng mã có liên quan chắc chắn được đánh giá cao.

Đường cơ sở

Là một điều cơ bản, có thể "ghi nhớ" tất cả 82.025 số nguyên tố với 1.804.551 tổng trọng số và độ lệch.

Lưu ý rằng mã này bao gồm nhiều thứ: ví dụ hoạt động, mã kiểm tra hoạt động, định nghĩa làm việc của mạng thần kinh sử dụng thư viện mạng thần kinh đã biết, mạng thần kinh "được mã hóa cứng" (hoặc ít nhất là không được "đào tạo"), và một phép đo điểm số làm việc.

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."

Mạng lưới thần kinh là gì?

Đối với mục đích của thách thức này, chúng ta có thể viết ra một định nghĩa hẹp nhưng chính xác về một mạng lưới thần kinh (nhân tạo). Đối với một số cách đọc bên ngoài, tôi đề xuất Wikipedia trên mạng nơ ron nhân tạo , mạng nơ ron phản hồi , mạng lưới tri giác đa lớpchức năng kích hoạt .

Một mạng lưới thần kinh feedforward là một tập hợp các lớp tế bào thần kinh. Số lượng tế bào thần kinh trên mỗi lớp khác nhau, với 20 tế bào thần kinh ở lớp đầu vào, một số tế bào thần kinh ở một hoặc nhiều lớp ẩn và 1 nơ ron ở lớp đầu ra. (Phải có ít nhất một lớp ẩn vì các số nguyên tố và số nguyên tố không được phân tách tuyến tính theo mẫu bit của chúng.) Trong ví dụ cơ bản ở trên, kích thước của các lớp là [20, 82025, 1].

Các giá trị của các nơ ron đầu vào được xác định bởi đầu vào. Như đã mô tả ở trên, đây sẽ là 0 và 1 tương ứng với các bit của một số trong khoảng từ 0 đến 2 ^ 20 hoặc -1 và 1 tương tự.

Các giá trị của các nơ-ron của mỗi lớp sau, bao gồm cả lớp đầu ra, được xác định từ lớp trước. Đầu tiên, một hàm tuyến tính được áp dụng, theo kiểu kết nối đầy đủ hoặc dày đặc . Một phương pháp biểu diễn một hàm như vậy là sử dụng ma trận trọng số . Ví dụ, các chuyển đổi giữa hai lớp đầu tiên của đường cơ sở có thể được biểu diễn bằng ma trận 82025 x 20. Số lượng trọng số là số lượng mục nhập trong ma trận này, ví dụ 1640500. Sau đó, mỗi mục nhập có một thuật ngữ thiên vị (riêng biệt) được thêm vào. Điều này có thể được biểu thị bằng một vectơ, ví dụ ma trận 82025 x 1 trong trường hợp của chúng tôi. Số lượng thành kiến ​​là số lượng mục nhập, ví dụ 82025. (Lưu ý rằng các trọng số và độ lệch cùng nhau mô tả một hàm tuyến tính affine .)

Một trọng số hoặc sai lệch được tính ngay cả khi nó bằng không. Đối với mục đích của định nghĩa hẹp này, các thành kiến ​​được tính là trọng số ngay cả khi tất cả đều bằng không. Lưu ý rằng trong ví dụ cơ bản, chỉ có hai trọng số riêng biệt (+1 và -1) được sử dụng (và chỉ thiên vị khác biệt hơn một chút); Tuy nhiên, kích thước là hơn một triệu, vì sự lặp lại không giúp ích gì cho điểm số dưới bất kỳ hình thức nào.

Cuối cùng, một hàm phi tuyến được gọi là hàm kích hoạt được áp dụng entry-khôn ngoan cho kết quả của hàm tuyến tính affine này. Đối với mục đích của định nghĩa hẹp này, các hàm kích hoạt được phép là ReLU , tanhsigmoid . Toàn bộ lớp phải sử dụng cùng chức năng kích hoạt.

Trong ví dụ cơ bản, số lượng trọng số là 20 * 82025 + 82025 * 1 = 1722525 và số lượng sai lệch là 82025 + 1 = 82026, với tổng số điểm là 1722525 + 82026 = 1804551. Nếu có một ví dụ tượng trưng, ​​nếu có thay vào đó một lớp và kích thước lớp thay vào đó là [20, a, b, 1], thì số lượng trọng số sẽ là 20 * a + a * b + b * 1 và số lượng sai lệch sẽ là a + b + 1.

Định nghĩa về mạng nơ-ron này được hỗ trợ tốt bởi nhiều khung, bao gồm Keras , scikit-learnTensorflow . Máy ảnh được sử dụng trong ví dụ cơ bản ở trên, với mã cơ bản như sau:

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)

Nếu các ma trận trọng số và thiên vị là các mảng numpy , thì numpy.size sẽ trực tiếp cho bạn biết số lượng mục nhập.

Có các loại mạng thần kinh khác?

Nếu bạn muốn có một định nghĩa chính xác, duy nhất về mạng thần kinh và ghi điểm cho các mục đích của thử thách này, thì vui lòng sử dụng định nghĩa trong phần trước. Nếu bạn nghĩ rằng "bất kỳ chức năng" nào nhìn đúng cách là một mạng thần kinh không có tham số , thì vui lòng sử dụng định nghĩa trong phần trước.

Nếu bạn là người có tinh thần tự do hơn, thì tôi khuyến khích bạn khám phá thêm. Có lẽ câu trả lời của bạn sẽ không được tính vào thử thách hẹp , nhưng có lẽ bạn sẽ có nhiều niềm vui hơn. Một số ý tưởng khác mà bạn có thể thử bao gồm các chức năng kích hoạt kỳ lạ hơn, mạng thần kinh tái phát (đọc từng bit một), mạng thần kinh tích chập, kiến ​​trúc kỳ lạ hơn, softmax và LSTM (!). Bạn có thể sử dụng bất kỳ chức năng kích hoạt tiêu chuẩn và bất kỳ kiến ​​trúc tiêu chuẩn. Một định nghĩa tự do về các tính năng mạng thần kinh "tiêu chuẩn" có thể bao gồm mọi thứ được đăng trên arxiv trước khi đăng câu hỏi này.


Những loại trọng lượng này là gì? Thông thường mọi người sử dụng phao chúng ta có thể sử dụng các loại số khác? ví dụ các loại có độ chính xác ít hơn, nhiều hơn hoặc không giới hạn.
Thuật sĩ lúa mì

@ SriotchilismO'Z cổ: Đối với mục đích của định nghĩa hẹp, tôi nghĩ rằng nên hạn chế nổi và nhân đôi (các số thực dấu phẩy động chính xác và đơn chính xác của IEEE) cho tất cả các trọng số và giá trị trung gian. (Mặc dù lưu ý rằng một số triển khai có thể sử dụng lượng chính xác khác - ví dụ 80 bit - trong quá trình đánh giá.)
A. Rex

Tôi thích câu hỏi này nhưng tôi thất vọng vì không tìm thấy một mạng lưới thần kinh nhỏ hơn nhiều với thời gian đào tạo đủ.
Anush

Câu trả lời:


13

Phân chia thử nghiệm: tổng số 59407, 6243 lớp, tổng số 16478 tế bào thần kinh

Đưa ra như một chương trình Python tạo và xác nhận mạng. Xem các ý kiến ​​trong trial_divisionđể giải thích về cách thức hoạt động. Quá trình xác nhận khá chậm (như trong, thời gian chạy tính bằng giờ): Tôi khuyên bạn nên sử dụng PyPy hoặc Cython.

αtối đa(0,α)

Ngưỡng là 1: mọi thứ ở trên là số nguyên tố, mọi thứ bên dưới là hỗn hợp hoặc bằng 0 và đầu vào duy nhất cung cấp đầu ra là 1 là 1.

#!/usr/bin/python3

import math


def primes_to(n):
    ps = []
    for i in range(2, n):
        is_composite = False
        for p in ps:
            if i % p == 0:
                is_composite = True
                break
            if p * p > i:
                break
        if not is_composite:
            ps.append(i)
    return ps


def eval_net(net, inputs):
    for layer in net:
        inputs.append(1)
        n = len(inputs)
        inputs = [max(0, sum(inputs[i] * neuron[i] for i in range(n))) for neuron in layer]
    return inputs


def cost(net):
    return sum(len(layer) * len(layer[0]) for layer in net)


def trial_division(num_bits):
    # Overview: we convert the bits to a single number x and perform trial division.
    # x is also our "is prime" flag: whenever we prove that x is composite, we clear it to 0
    # At the end x will be non-zero only if it's a unit or a prime, and greater than 1 only if it's a prime.
    # We calculate x % p as
    #     rem = x - (x >= (p << a) ? 1 : 0) * (p << a)
    #     rem -= (rem >= (p << (a-1)) ? 1) : 0) * (p << (a-1))
    #     ...
    #     rem -= (rem >= p ? 1 : 0) * p
    #
    # If x % p == 0 and x > p then x is a composite multiple of p and we want to set it to 0

    N = 1 << num_bits
    primes = primes_to(1 + int(2.0 ** (num_bits / 2)))

    # As a micro-optimisation we exploit 2 == -1 (mod 3) to skip a number of shifts for p=3.
    # We need to bias by a multiple of 3 which is at least num_bits // 2 so that we don't get a negative intermediate value.
    bias3 = num_bits // 2
    bias3 += (3 - (bias3 % 3)) % 3

    # inputs: [bit0, ..., bit19]
    yield [[1 << i for i in range(num_bits)] + [0],
           [-1] + [0] * (num_bits - 1) + [1],
           [0] * 2 + [-1] * (num_bits - 2) + [1],
           [(-1) ** i for i in range(num_bits)] + [bias3]]

    for p in primes[1:]:
        # As a keyhole optimisation we overlap the cases slightly.
        if p == 3:
            # [x, x_is_even, x_lt_4, x_reduced_mod_3]
            max_shift = int(math.log((bias3 + (num_bits + 1) // 2) // p, 2))
            yield [[1, 0, 0, 0, 0], [0, 1, -1, 0, 0], [0, 0, 0, 1, 0], [0, 0, 0, -1, p << max_shift]]
            yield [[1, -N, 0, 0, 0], [0, 0, 1, 0, 0], [0, 0, 0, -1, 1]]
            yield [[1, 0, 0, 0], [0, 1, -p << max_shift, 0]]
        else:
            # [x, x % old_p]
            max_shift = int(num_bits - math.log(p, 2))
            yield [[1, 0, 0], [1, -N, -p_old], [-1, 0, p << max_shift]]
            yield [[1, -N, 0, 0], [0, 0, -1, 1]]
            yield [[1, 0, 0], [1, -p << max_shift, 0]]

        for shift in range(max_shift - 1, -1, -1):
            # [x, rem]
            yield [[1, 0, 0], [0, 1, 0], [0, -1, p << shift]]
            yield [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, -1, 1]]
            yield [[1, 0, 0, 0], [0, 1, -p << shift, 0]]
        # [x, x % p]
        p_old = p

    yield [[1, 0, 0], [1, -N, -p]]
    yield [[1, -N, 0]]


def validate_primality_tester(primality_tester, threshold):
    num_bits = len(primality_tester[0][0]) - 1
    primes = set(primes_to(1 << num_bits))
    errors = 0
    for i in range(1 << num_bits):
        expected = i in primes
        observed = eval_net(primality_tester, [(i >> shift) & 1 for shift in range(num_bits)])[-1] > threshold
        if expected != observed:
            errors += 1
            print("Failed test case", i)
        if (i & 0xff) == 0:
            print("Progress", i)

    if errors > 0:
        raise Exception("Failed " + str(errors) + " test case(s)")


if __name__ == "__main__":
    n = 20

    trial_div = list(trial_division(n))
    print("Cost", cost(trial_div))
    validate_primality_tester(trial_div, 1)

Như một bên, tái

định lý gần đúng phổ quát nói rằng các mạng thần kinh có thể xấp xỉ bất kỳ hàm liên tục nào

tối đa(0,1-Σmộttôi)tối đa(0,1+Σ(mộttôi-1))nhưng chỉ hoạt động chính xác nếu đầu vào của nó được đảm bảo là 0 hoặc 1 và có thể xuất các số nguyên lớn hơn. Nhiều cổng khác có thể có trong một lớp, nhưng bản thân NOR đã hoàn thành Turing nên không cần phải đi sâu vào chi tiết.


Ngoài ra, tôi bắt đầu làm bài kiểm tra Euler trước khi tôi thử phân chia thử nghiệm, vì tôi nghĩ nó sẽ hiệu quả hơn, nhưng nâng một số (7 là ứng cử viên tốt nhất) lên sức mạnh của (x- (x mod 2) ) sẽ yêu cầu 38 phép nhân theo sau là mod giảm x và mạng tốt nhất tôi tìm thấy để nhân số 20 bit có giá 1135, vì vậy nó sẽ không cạnh tranh.
Peter Taylor

7

Điểm 984314, 82027 lớp, tổng cộng 246076 tế bào thần kinh

Chúng ta có thể giữ mọi thứ hoàn toàn trong các số nguyên nếu chúng ta sử dụng chức năng kích hoạt ReLU, giúp đơn giản hóa việc phân tích.

xx= =một

  1. địa lýmột= =(x-một)+lemột= =(-x+một)+
  2. phương trìnhmột= =(-địa lýmột-lemột+1)+phương trìnhmột1x= =một0

x

địa lý2= =(x-2)+le2= =(-x+2)+

tích lũy2= =(-địa lý2-le2+1)+địa lý3= =(địa lý2-(3-2))+le3= =(-địa lý2+(3-2))+

tích lũy3= =(221tích lũy2-địa lý3-le3+1)+địa lý5= =(địa lý3-(5-3))+le5= =(-địa lý3+(5-3))+

tích lũy5= =(221tích lũy3-địa lý5-le5+1)+địa lý7= =(địa lý5-(7-5))+le7= =(-địa lý5+(7-5))+

...

tích lũy1048571= =(221tích lũy1048559-địa lý1048571-le1048571+1)+địa lý1048573= =(địa lý1048571-(1048573-1048571))+le1048573= =(-địa lý1048571+(1048573-1048571))+

tích lũy1048573= =(221tích lũy1048571-địa lý1048573-le1048573+1)+

+

Điểm là (82026 - 3) * 12 + 21 + 4 + 9 + 4.


Mát mẻ. Theo tôi hiểu, điều này cũng "ghi nhớ" các số nguyên tố, nhưng nó kiểm tra sự bằng nhau "tuần tự" chứ không phải là "song song". (Ngoài ra, nó giống như một chuyển vị của đường cơ sở.) Bước đầu tiên là ngay lập tức di chuyển ra khỏi mẫu bit và chỉ làm việc với chính số nguyên thực tế. Kết quả là, không có hình phạt nào gấp 20 lần trong kiểm tra bình đẳng. Cảm ơn bạn đã gửi
A. Rex

Siêu ký tự cộng là gì?
frageum

1
x+= =tối đa(0,x)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.