व्यक्तिगत रूप से सभी को कैसे याद रखें, या बड़े डेटाबेस में चेहरे की प्रभावी खोज करें

मेरे बारे में


नमस्कार, हेब्र! मेरा नाम पावेल है, मैं IoT उपकरणों के उत्पादन में लगी एक कंपनी में तकनीकी निदेशक के रूप में काम करता हूं। हम अपने पेटेंट सेंसर नेटवर्क प्रोटोकॉल पर स्मार्ट होम कंट्रोलर से स्मार्ट मीटरिंग उपकरणों तक - बहुत सी चीजों का उत्पादन करते हैं।


वे आईटी कंपनी के सामान्य निदेशक के रूप में भी कार्य करते हैं। अतीत में, विश्व कप प्रोग्रामिंग के एसीएम ICPC सेमीफाइनलिस्ट।


प्रेरणा


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


एंबेडिंग एक पूर्वनिर्धारित आयाम के साथ एक निरंतर वेक्टर में वर्गीकृत विशेषताओं के असतत वेक्टर से एक मानचित्रण है।

तो यह सब कहां से शुरू हुआ


- , , , / , . , , , , . "" 87%, , , . , 3 . . 2-3 . — … , , - "" ( ) 6 . .



, , : ( ) , , , , , , . 10 200 , . , 50 . 10.


, +- , .


, , , dlib, . C++, BLAS, Python CPU. .


, dlib , 0.6, . 128.


, . , , , , , . , , k , k , , - -. , -, -.


.



. dlib .


def get_img_vector(img):
    dets = detector(img, 1)
    for k, d in enumerate(dets):
        shape = sp(img, d)
        return facerec.compute_face_descriptor(img, shape)
    return None

def prepare_database():
    database = {}

    for file in glob.glob("_images/*"):
        identity = os.path.splitext(os.path.basename(file))[0]
        img = cv2.imread(file, 1)

        database[identity] = get_img_vector(img)

    return database

def who_is_it(img, shape, database):
    face_descriptor1 = facerec.compute_face_descriptor(img, shape)

    min_dist = 100
    identity = None

    for (name, db_enc) in database.items():
        dist = distance.euclidean(db_enc, face_descriptor1)

        if dist < min_dist:
            min_dist = dist
            identity = name

    print(min_dist)
    if min_dist > 0.57:
        return None
    else:
        return str(identity)

if __name__ == "__main__":
    global sp
    sp = dlib.shape_predictor('weights/shape_predictor_face_landmarks.dat')
    global facerec
    facerec = dlib.face_recognition_model_v1('weights/dlib_face_recognition_resnet_model_v1.dat')
    global detector
    detector = dlib.get_frontal_face_detector()

    database = prepare_database()
    webcam_face_recognizer(database)

webcam_face_recognizer ( cv2- ) . who_is_it, . , , , , !


, 1 . (N*k), N — , k — . , , . , , - . .



, ?


— , , . — . , , , L2 .



scores = np.linalg.norm(face_descriptor1 - np.asarray(database.items()), axis=1)
min_el_ind = scores.argmax()

, , , .


, , nmslib. HNSW k . , . :


import nmslib

index = nmslib.init(method='hnsw', space='l2', data_type=nmslib.DataType.DENSE_VECTOR)

for idx, emb in enumerate(database.items()):
    index.addDataPoint(idx, emb)

index_params = {
    'indexThreadQty': 5,
    'skip_optimized_index': 0,
    'post': 3,
    'delaunay_type': 2,
    'M': 100,
    'efConstruction': 2000
}

index.createIndex(index_params, print_progress=True)
index.saveIndex('./db/database.bin')

HNSW .


"" . ?



, 4 . dlib , .


छवि


, . , , . .


postgresql


- , , (, . ) .


:


import postgresql

def setup_db():
    db = postgresql.open('pq://user:pass@localhost:5434/db')
    db.execute("create extension if not exists cube;")
    db.execute("drop table if exists vectors")
    db.execute("create table vectors (id serial, file varchar, vec_low cube, vec_high cube);")
    db.execute("create index vectors_vec_idx on vectors (vec_low, vec_high);")

:


query = "INSERT INTO vectors (file, vec_low, vec_high) VALUES ('{}', CUBE(array[{}]), CUBE(array[{}]))".format(
            file_name,
            ','.join(str(s) for s in encodings[0][0:64]),
            ','.join(str(s) for s in encodings[0][64:128]),
        )
db.execute(query)

:


import time
import postgresql
import random

db = postgresql.open('pq://user:pass@localhost:5434/db')

for i in range(100):
    t = time.time()
    encodings = [random.random() for i in range(128)]

    threshold = 0.6
    query = "SELECT file FROM vectors WHERE sqrt(power(CUBE(array[{}]) <-> vec_low, 2) + power(CUBE(array[{}]) <-> vec_high, 2)) <= {} ".format(
        ','.join(str(s) for s in encodings[0:64]),
        ','.join(str(s) for s in encodings[64:128]),
        threshold,
    ) + \
            "ORDER BY sqrt(power(CUBE(array[{}]) <-> vec_low, 2) + power(CUBE(array[{}]) <-> vec_high, 2)) ASC LIMIT 1".format(
                ','.join(str(s) for s in encodings[0:64]),
                ','.join(str(s) for s in encodings[64:128]),
            )
    print(db.query(query))
    print('inset time', time.time() - t, 'ind', i)

10^5 (4- i5, 2,33 GHz) 0.034 .
? +- ( ). , , … , .


K-d


- , , " ", . , .


, , , .


K-d — k- . , ( , . .), .


, :


.


(N) , , , (N). , !


"" , NDA.


. , .



15 . , . . .


— . , , :)


k-tree , ( ), , ( -), 4-6 . .



, . — 1,5 , , , , , , . , , .


, , , . , mail cloud. , .


यदि इस समस्या को हल करने के लिए अन्य विकल्प हैं, तो मैं ख़ुशी से टिप्पणियों में उनके बारे में पढ़ूंगा।


और इस कल्पित का नैतिक यह है - भीड़ भी गिर गई शेरखुले स्रोत के समाधान समय के अनुसार परीक्षण किए गए। एल्गोरिदम, पृष्ठन सीखें :)


All Articles