क्या एक तंत्रिका नेटवर्क अपराधों को पहचान सकता है?


26

पृष्ठभूमि

(कृत्रिम) तंत्रिका नेटवर्क के लिए एक गरीब फिट की तरह प्रतीत होता है। हालांकि, सार्वभौमिक सन्निकटन प्रमेय में कहा गया है कि तंत्रिका नेटवर्क किसी भी निरंतर फ़ंक्शन को अनुमानित कर सकते हैं, इसलिए विशेष रूप से किसी भी अंतिम रूप से समर्थित फ़ंक्शन एक इच्छाओं का प्रतिनिधित्व करना संभव होना चाहिए। तो आइए पहले मिलियन संख्याओं के बीच के सभी अपराधों को पहचानने का प्रयास करें।

अधिक सटीक रूप से, क्योंकि यह एक प्रोग्रामिंग वेबसाइट है, चलो 2 ^ 20 = 1,048,576 तक चलते हैं। इस सीमा से नीचे के अपराधों की संख्या 82,025 या लगभग 8% है।

चुनौती

तंत्रिका नेटवर्क कितना छोटा है, आप यह जान सकते हैं कि सभी 20-बिट पूर्णांक को सही रूप से प्रधान या नहीं के रूप में वर्गीकृत करता है?

इस चुनौती के प्रयोजनों के लिए, एक तंत्रिका नेटवर्क का आकार कुल वजन और इसे प्रदर्शित करने के लिए आवश्यक गैसों की संख्या है।

विवरण

लक्ष्य एकल, स्पष्ट तंत्रिका नेटवर्क के आकार को कम करना है ।

आपके नेटवर्क पर इनपुट लंबाई का एक वेक्टर होगा जिसमें पूर्णांक के व्यक्तिगत बिट्स होते हैं, जिन्हें 0s और 1s के साथ या वैकल्पिक रूप से -1 s और + 1s के साथ दर्शाया जाता है। इनका आदेश सबसे महत्वपूर्ण-बिट पहले या कम से कम महत्वपूर्ण-बिट पहले हो सकता है।

आपके नेटवर्क का आउटपुट एक सिंगल नंबर होना चाहिए, जैसे कि कुछ कटऑफ के ऊपर इनपुट को प्राइम के रूप में पहचाना जाता है और उसी कटऑफ के नीचे इनपुट को प्राइम के रूप में मान्यता दी जाती है। उदाहरण के लिए, सकारात्मक का अर्थ प्रधान हो सकता है (और नकारात्मक अभाज्य नहीं), या वैकल्पिक रूप से 0.5 से अधिक अभिप्राय अभिप्राय प्रधान हो सकता है (और 0.5 से कम अभाज्य नहीं)।

सभी 2 ^ 20 = 1,048,576 संभावित इनपुट पर नेटवर्क 100% सटीक होना चाहिए। जैसा कि ऊपर उल्लेख किया गया है, ध्यान दें कि इस रेंज में 82,025 प्राइम हैं। (यह निम्नानुसार है कि हमेशा आउटपुट "प्राइम" 92% सटीक होगा।)

मानक तंत्रिका नेटवर्क शब्दावली के संदर्भ में, इसे संभवतः ओवरफिटिंग कहा जाएगा । दूसरे शब्दों में, आपका लक्ष्य पूरी तरह से अपराधों को खत्म करना है। अन्य शब्द जो उपयोग कर सकते हैं वे हैं "प्रशिक्षण सेट" और "परीक्षण सेट" समान हैं।

यह चुनौती "ट्रेन करने योग्य" या "सीखने योग्य" मापदंडों की संख्या पर विचार नहीं करती है। दरअसल, आपके नेटवर्क में हार्ड-कोडेड वेट होने की संभावना है, और नीचे दिया गया उदाहरण पूरी तरह से हार्ड-कोडेड है। इसके बजाय, सभी वजन और गैसों को पैरामीटर माना जाता है और गिना जाता है।

आपके तंत्रिका नेटवर्क को प्रशिक्षित करने या उत्पन्न करने के लिए आवश्यक कोड की लंबाई आपके स्कोर के लिए प्रासंगिक नहीं है, लेकिन संबंधित कोड को पोस्ट करना निश्चित रूप से सराहनीय है।

बेसलाइन

एक बेसलाइन के रूप में, कुल वजन और गैसों के साथ 1,804,551 के साथ सभी 82,025 primes को "याद" करना संभव है ।

ध्यान दें कि इस कोड का अनुसरण करता है जिसमें कई चीजें शामिल हैं: एक कार्य उदाहरण, कार्य परीक्षण कोड, एक ज्ञात तंत्रिका नेटवर्क लाइब्रेरी का उपयोग करके तंत्रिका नेटवर्क की एक कार्यशील परिभाषा, एक "हार्ड-कोडेड" (या कम से कम, "प्रशिक्षित" नहीं) तंत्रिका नेटवर्क, और स्कोर का एक कार्य माप।

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 न्यूरॉन। (कम से कम एक छिपी हुई परत होनी चाहिए क्योंकि प्राइम्स और न-प्राइम्स अपने बिट पैटर्न के अनुसार रैखिक रूप से अलग नहीं होते हैं।) ऊपर के बेसलाइन उदाहरण में, परतों के आकार [20, 82025, 1] ​​हैं।

इनपुट न्यूरॉन्स के मूल्य इनपुट द्वारा निर्धारित किए जाते हैं। जैसा कि ऊपर वर्णित है, यह 0 या 2 ^ 20, या -1 और + 1 s के बीच की संख्या के बिट्स के अनुरूप 0s और 1s होगा।

प्रत्येक निम्न परत के न्यूरॉन्स के मान, आउटपुट परत सहित, पहले से परत से निर्धारित होते हैं। पहले एक रेखीय फ़ंक्शन लागू किया जाता है, एक पूरी तरह से जुड़ा हुआ या घने फैशन में। इस तरह के फ़ंक्शन का प्रतिनिधित्व करने का एक तरीका एक वेट मैट्रिक्स का उपयोग कर रहा है । उदाहरण के लिए, बेसलाइन की पहली दो परतों के बीच के संक्रमण को 82025 x 20 मैट्रिक्स के साथ दर्शाया जा सकता है। वेट की संख्या इस मैट्रिक्स में प्रविष्टियों की संख्या है, उदाहरण 1640500। तब प्रत्येक प्रविष्टि में एक (अलग) पूर्वाग्रह शब्द जोड़ा गया है। यह एक वेक्टर द्वारा दर्शाया जा सकता है, उदाहरण के लिए हमारे मामले में एक 82025 x 1 मैट्रिक्स। बॉयोसेस की संख्या प्रविष्टियों की संख्या है, उदाहरण के लिए 82025। (ध्यान दें कि वज़न और बायसेप्स एक साथ मिलन समारोह का वर्णन करते हैं ।)

वजन या पूर्वाग्रह की गणना शून्य होने पर भी की जाती है। इस संकीर्ण परिभाषा के प्रयोजनों के लिए, पक्षपात वजन के रूप में गिना जाता है, भले ही वे सभी शून्य हों। ध्यान दें कि बेसलाइन उदाहरण में, केवल दो अलग-अलग वजन (+1 और -1) का उपयोग किया जाता है (और केवल थोड़ा अलग पक्षपात); फिर भी, आकार एक मिलियन से अधिक है, क्योंकि पुनरावृत्ति किसी भी तरह से स्कोर के साथ मदद नहीं करता है।

अंत में, एक nonlinear फ़ंक्शन जिसे सक्रियण फ़ंक्शन कहा जाता है, इस चक्करदार रैखिक फ़ंक्शन के परिणाम के लिए प्रविष्टि-वार लागू किया जाता है। इस संकीर्ण परिभाषा के प्रयोजनों के लिए अनुमति दी सक्रियण कार्य हैं Relu , tanh , और अवग्रह । संपूर्ण परत को समान सक्रियण फ़ंक्शन का उपयोग करना चाहिए।

आधारभूत उदाहरण में, वेट की संख्या 20 * 82025 + 82025 * 1 = 1722525 है और पूर्वाग्रह की संख्या 82025 + 1 = 82026 है, कुल स्कोर के लिए 1722525 + 82026 = 1804551 है। यदि कोई प्रतीकात्मक उदाहरण हैं, तो एक और परत और परत का आकार इसके बजाय था [20, ए, बी, 1], फिर वज़न की संख्या 20 * a + a * b + b * 1 होगी और पूर्वाग्रह की संख्या + b + 1 होगी।

तंत्रिका नेटवर्क की यह परिभाषा सहित कई व्यवस्थाएं, द्वारा अच्छी तरह से समर्थित है Keras , scikit सीखने , और 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.size सीधे आपको प्रविष्टियों की संख्‍या बताएगा।

क्या अन्य प्रकार के तंत्रिका नेटवर्क हैं?

यदि आप तंत्रिका नेटवर्क की एकल, सटीक परिभाषा चाहते हैं और इस चुनौती के प्रयोजनों के लिए स्कोर करते हैं, तो कृपया पिछले अनुभाग में परिभाषा का उपयोग करें। अगर आपको लगता है कि "कोई भी फ़ंक्शन" सही तरीके से देखा गया है, तो यह एक तंत्रिका नेटवर्क है जिसमें कोई पैरामीटर नहीं है , तो , तो कृपया पिछले अनुभाग में परिभाषा का उपयोग करें।

यदि आप अधिक स्वतंत्र आत्मा हैं, तो मैं आपको आगे का पता लगाने के लिए प्रोत्साहित करता हूं। शायद आपका जवाब संकीर्ण चुनौती की ओर नहीं गिना जाएगा , लेकिन शायद आपको अधिक मज़ा आएगा। कुछ अन्य विचार जो आप आज़मा सकते हैं, उनमें अधिक विदेशी सक्रियण कार्य, आवर्तक तंत्रिका नेटवर्क (एक समय में एक बिट पढ़ना), दृढ़ तंत्रिका नेटवर्क, अधिक विदेशी आर्किटेक्चर, सॉफ्टमैक्स और एलएसटीएम (!) शामिल हैं। आप किसी भी मानक सक्रियण फ़ंक्शन और किसी भी मानक वास्तुकला का उपयोग कर सकते हैं। "मानक" तंत्रिका नेटवर्क सुविधाओं की उदार परिभाषा में इस प्रश्न के पोस्टिंग से पहले arxiv पर पोस्ट की गई कुछ भी शामिल हो सकती है।


ये वज़न किस प्रकार के हैं? आमतौर पर लोग झांकियों का उपयोग करते हैं क्या हम अन्य संख्यात्मक प्रकारों का उपयोग कर सकते हैं? उदाहरण के लिए कम, अधिक या असीमित परिशुद्धता के प्रकार।
गेहूं जादूगर

@ SriotchilismO'Zaic: संकीर्ण परिभाषा के प्रयोजनों के लिए, मुझे लगता है कि यह सभी वजन और मध्यवर्ती मूल्यों के लिए फ्लोट और डबल (IEEE सिंगल- और डबल-सटीक फ़्लोटिंग पॉइंट वास्तविक संख्या) को प्रतिबंधित करने के लिए समझ में आता है। (हालांकि ध्यान दें कि कुछ कार्यान्वयन अन्य मात्राओं का सटीक उपयोग कर सकते हैं - जैसे कि 80-बिट - मूल्यांकन के दौरान।)
ए। रेक्स

मैं इस सवाल से प्यार करता हूं लेकिन निराश हूं कि पर्याप्त प्रशिक्षण समय के साथ खोजने के लिए बहुत छोटा तंत्रिका नेटवर्क नहीं है।
अनुष

जवाबों:


13

परीक्षण विभाजन: कुल 59407, 6243 परतें, 16478 न्यूरॉन्स

एक पायथन कार्यक्रम के रूप में दिया जाता है जो नेट उत्पन्न करता है और मान्य करता है। trial_divisionयह कैसे काम करता है, इसकी व्याख्या के लिए टिप्पणियों को देखें । सत्यापन काफी धीमा है (जैसे, समय को घंटों में मापा जाता है): मैं PyPy या Cython का उपयोग करने की सलाह देता हूं।

αmax(0,α) सक्रियण समारोह के रूप में ) का उपयोग करती हैं।

दहलीज 1: कुछ भी है जो कि प्रधान है, नीचे कुछ भी समग्र या शून्य है, और एकमात्र इनपुट जो 1 का आउटपुट देता है वह 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)

एक तरफ के रूप में, फिर से

सार्वभौमिक सन्निकटन प्रमेय बताता है कि तंत्रिका नेटवर्क किसी भी निरंतर कार्य को अनुमानित कर सकते हैं

max(0,1ai)max(0,1+(ai1))लेकिन केवल तभी सही ढंग से काम करता है जब इसके इनपुट की गारंटी 0 या 1 हो, और इससे बड़े पूर्णांक का उत्पादन हो सकता है। एक परत में विभिन्न अन्य द्वार संभव हैं, लेकिन NOR अपने आप में ट्यूरिंग-पूर्ण है इसलिए विस्तार में जाने की आवश्यकता नहीं है।


एक और बात के रूप में, मैंने ट्रायल डिवीजन की कोशिश करने से पहले एक यूलर टेस्ट पर काम शुरू कर दिया, क्योंकि मुझे लगा कि यह अधिक कुशल होगा, लेकिन (x- मॉड 2) की शक्ति के लिए एक संख्या (7 सबसे अच्छा उम्मीदवार) था ) को 38 गुणा की आवश्यकता होगी, इसके बाद मॉड x में कमी आएगी, और सबसे अच्छा नेटवर्क जो मुझे 20-बिट संख्या को गुणा करने के लिए मिला है, उसकी लागत 1135 है, इसलिए यह प्रतिस्पर्धी नहीं होगा।
पीटर टेलर

7

कुल मिलाकर 984314, 82027 परतें, 246076 न्यूरॉन्स

यदि हम सक्रियण फ़ंक्शन ReLU का उपयोग करते हैं, तो हम पूरी तरह से पूर्णांक में चीजें रख सकते हैं, जो विश्लेषण को सरल बनाता है।

xx=a

  1. gea=(xa)+lea=(x+a)+
  2. eqa=(gealea+1)+eqa1एक्स=0

एक्स

जीई2=(एक्स-2)+le2=(-एक्स+2)+

accum2=(-जीई2-le2+1)+जीई3=(जीई2-(3-2))+le3=(-जीई2+(3-2))+ । लागत (2 + 1) * 3 = 9।

accum3=(221accum2-जीई3-le3+1)+, जीई5=(जीई3-(5-3))+, le5=(-जीई3+(5-3))+। लागत (3 + 1) * 3 = 12।

परत 5: आउटपुट accum5=(221accum3-जीई5-le5+1)+, ge7=(ge5(75))+, le7=(ge5+(75))+. Cost (3 + 1) * 3 = 12.

...

Layer 82026: outputs accum1048571=(221accum1048559ge1048571le1048571+1)+, ge1048573=(ge1048571(10485731048571))+, le1048573=(ge1048571+(10485731048571))+. Cost (3 + 1) * 3 = 12.

Layer 82027: outputs accum1048573=(221accum1048571ge1048573le1048573+1)+. Cost (3 + 1) * 1 = 4.

The threshold is 0. If working with doubles, overflow to + is quite possible, but that seems to be perfectly in accordance with the rules.

Score is (82026 - 3) * 12 + 21 + 4 + 9 + 4.


Cool. As I understand, this also "memorizes" the primes, but it tests for equality "sequentially" rather than in "parallel". (Alternatively, it's like a transpose of the baseline.) The first step is to immediately move away from the bit pattern and just work with the actual integer itself. As a result, there isn't a 20-fold penalty in the equality check. Thanks for your submission
A. Rex

What is superscript plus?
feersum

1
@feersum, that's notation from the Wikipedia page on ReLU linked in the question. x+=max(0,x)
Peter Taylor
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.