تم إنشاء التلقائي التلقائي لتدريب واجهة برمجة تطبيقات باستخدام TensorFlow و Python3 التي تتعلم اهتماماتك وتلعب تلقائيًا لعبة الضرب من أجلك.

في هذا المستند ، سأشرح الخطوات التالية التي كانت ضرورية لإنشاء التربية التلقائية:
Auto Tinder هو مشروع مفهوم تم إنشاؤه بحتة لأغراض متعة وتعليمية. لن يتم إساءة معاملتها أبدًا لإلحاق الأذى بأي شخص أو البريد العشوائي للمنصة. لا ينبغي استخدام البرامج النصية للعبث التلقائي مع ملف تعريف Tinder الخاص بك لأنها تنتهك بالتأكيد شروط خدمة Tinders.
لقد كتبت هذه البرنامج بشكل رئيسي من سببين:
الخطوة الأولى هي معرفة كيفية تواصل تطبيق Tinder مع خادم Backend Tinders. نظرًا لأن Tinder يوفر إصدار ويب من بوابةها ، فهذا أمر سهل مثل الذهاب إلى Tinder.com ، وفتح Chrome DevTools وإلقاء نظرة سريعة على بروتوكول الشبكة.
كان المحتوى الموضح في الصورة أعلاه من طلب إلى https://api.gotinder.com/v2/recs/core الذي يتم صنعه عند تحميل صفحة Tinder.com المقصودة. من الواضح أن Tinder لديه نوع من واجهة برمجة التطبيقات الداخلية التي يستخدمونها للتواصل بين الواجهة الأمامية والخلفية.
من خلال تحليل محتوى /recs /core ، يصبح من الواضح أن نقطة نهاية API هذه تُرجع قائمة ملفات تعريف المستخدمين للأشخاص القريبين.
تتضمن البيانات (من بين العديد من الحقول الأخرى) ، البيانات التالية:
{
"meta" : {
"status" : 200
},
"data" : {
"results" : [
{
"type" : " user " ,
"user" : {
"_id" : " 4adfwe547s8df64df " ,
"bio" : " 19y. " ,
"birth_date" : " 1997-17-06T18:21:44.654Z " ,
"name" : " Anna " ,
"photos" : [
{
"id" : " 879sdfert-lskdföj-8asdf879-987sdflkj " ,
"crop_info" : {
"user" : {
"width_pct" : 1 ,
"x_offset_pct" : 0 ,
"height_pct" : 0.8 ,
"y_offset_pct" : 0.08975463
},
"algo" : {
"width_pct" : 0.45674357 ,
"x_offset_pct" : 0.984341657 ,
"height_pct" : 0.234165403 ,
"y_offset_pct" : 0.78902343
},
"processed_by_bullseye" : true ,
"user_customized" : false
},
"url" : " https://images-ssl.gotinder.com/4adfwe547s8df64df/original_879sdfert-lskdföj-8asdf879-987sdflkj.jpeg " ,
"processedFiles" : [
{
"url" : " https://images-ssl.gotinder.com/4adfwe547s8df64df/640x800_879sdfert-lskdföj-8asdf879-987sdflkj.jpg " ,
"height" : 800 ,
"width" : 640
},
{
"url" : " https://images-ssl.gotinder.com/4adfwe547s8df64df/320x400_879sdfert-lskdföj-8asdf879-987sdflkj.jpg " ,
"height" : 400 ,
"width" : 320
},
{
"url" : " https://images-ssl.gotinder.com/4adfwe547s8df64df/172x216_879sdfert-lskdföj-8asdf879-987sdflkj.jpg " ,
"height" : 216 ,
"width" : 172
},
{
"url" : " https://images-ssl.gotinder.com/4adfwe547s8df64df/84x106_879sdfert-lskdföj-8asdf879-987sdflkj.jpg " ,
"height" : 106 ,
"width" : 84
}
],
"last_update_time" : " 2019-10-03T16:18:30.532Z " ,
"fileName" : " 879sdfert-lskdföj-8asdf879-987sdflkj.webp " ,
"extension" : " jpg,webp " ,
"webp_qf" : [
75
]
}
],
"gender" : 1 ,
"jobs" : [],
"schools" : [],
"show_gender_on_profile" : false
},
"facebook" : {
"common_connections" : [],
"connection_count" : 0 ,
"common_interests" : []
},
"spotify" : {
"spotify_connected" : false
},
"distance_mi" : 1 ,
"content_hash" : " slkadjfiuwejsdfuzkejhrsdbfskdzufiuerwer " ,
"s_number" : 9876540657341 ,
"teaser" : {
"string" : " "
},
"teasers" : [],
"snap" : {
"snaps" : []
}
}
]
}
}
بعض الأشياء مثيرة للاهتمام للغاية هنا (لاحظ أنني غيرت جميع البيانات لعدم انتهاك خصوصية هؤلاء الأشخاص) :
من خلال تحليل رؤوس المحتوى ، نجد بسرعة مفاتيح واجهة برمجة التطبيقات الخاصة الخاصة بنا: X-Auth-Token .
من خلال نسخ هذا الرمز المميز والانتقال إلى ساعي البريد ، يمكننا التحقق من أنه يمكننا بالفعل التواصل بحرية مع واجهة برمجة تطبيقات Tinder مع عنوان URL المناسب ورمز مصادقنا.
مع النقر قليلاً من خلال Tinders WebApp ، اكتشفت بسرعة جميع نقاط نهاية واجهة برمجة التطبيقات ذات الصلة:
| يكتب | عنوان URL | وصف |
|---|---|---|
| يحصل | /v2/recs/core | يعيد قائمة الأشخاص القريبة |
| يحصل | /v2/ملف تعريف؟ | إرجاع جميع المعلومات حول ملف التعريف الخاص بك |
| يحصل | /V2/المباريات | إرجاع قائمة بجميع الأشخاص الذين يتطابقون معك |
| يحصل | /like/{user_id} | يحب الشخص مع user_id المعطى |
| يحصل | /pass/{user_id} | يمرر الشخص مع user_id المعطى |
لذلك دعونا ندخل في الكود. سوف نستخدم مكتبة طلبات Python للتواصل مع API وكتابة فئة Wrapper API حولها للراحة.
وبالمثل ، نكتب فئة شخص صغير يأخذ استجابة واجهة برمجة التطبيقات من Tinder تمثل شخص ما ويقدم بعض الواجهات الأساسية إلى واجهة برمجة تطبيقات Tinder.
لنبدأ بفصل الشخص. يجب أن تتلقى بيانات API ، وكائن Tinder-API وحفظ جميع البيانات ذات الصلة في متغيرات مثيل. يجب أن تقدم أيضًا بعض الميزات الأساسية مثل "Like" أو "Conke" التي تقدم طلبًا إلى Tinder-API ، والتي تتيح لنا استخدام "some_person.ke ()" من أجل أن نجد ملفًا تعريفًا مثيرًا للاهتمام.
import datetime
from geopy . geocoders import Nominatim
TINDER_URL = "https://api.gotinder.com"
geolocator = Nominatim ( user_agent = "auto-tinder" )
PROF_FILE = "./images/unclassified/profiles.txt"
class Person ( object ):
def __init__ ( self , data , api ):
self . _api = api
self . id = data [ "_id" ]
self . name = data . get ( "name" , "Unknown" )
self . bio = data . get ( "bio" , "" )
self . distance = data . get ( "distance_mi" , 0 ) / 1.60934
self . birth_date = datetime . datetime . strptime ( data [ "birth_date" ], '%Y-%m-%dT%H:%M:%S.%fZ' ) if data . get (
"birth_date" , False ) else None
self . gender = [ "Male" , "Female" , "Unknown" ][ data . get ( "gender" , 2 )]
self . images = list ( map ( lambda photo : photo [ "url" ], data . get ( "photos" , [])))
self . jobs = list (
map ( lambda job : { "title" : job . get ( "title" , {}). get ( "name" ), "company" : job . get ( "company" , {}). get ( "name" )}, data . get ( "jobs" , [])))
self . schools = list ( map ( lambda school : school [ "name" ], data . get ( "schools" , [])))
if data . get ( "pos" , False ):
self . location = geolocator . reverse ( f' { data [ "pos" ][ "lat" ] } , { data [ "pos" ][ "lon" ] } ' )
def __repr__ ( self ):
return f" { self . id } - { self . name } ( { self . birth_date . strftime ( '%d.%m.%Y' ) } )"
def like ( self ):
return self . _api . like ( self . id )
def dislike ( self ):
return self . _api . dislike ( self . id )غلاف API الخاص بنا ليس أكثر من مجرد طريقة خيالية لاستدعاء واجهة برمجة تطبيقات Tinder باستخدام فصل:
import requests
TINDER_URL = "https://api.gotinder.com"
class tinderAPI ():
def __init__ ( self , token ):
self . _token = token
def profile ( self ):
data = requests . get ( TINDER_URL + "/v2/profile?include=account%2Cuser" , headers = { "X-Auth-Token" : self . _token }). json ()
return Profile ( data [ "data" ], self )
def matches ( self , limit = 10 ):
data = requests . get ( TINDER_URL + f"/v2/matches?count= { limit } " , headers = { "X-Auth-Token" : self . _token }). json ()
return list ( map ( lambda match : Person ( match [ "person" ], self ), data [ "data" ][ "matches" ]))
def like ( self , user_id ):
data = requests . get ( TINDER_URL + f"/like/ { user_id } " , headers = { "X-Auth-Token" : self . _token }). json ()
return {
"is_match" : data [ "match" ],
"liked_remaining" : data [ "likes_remaining" ]
}
def dislike ( self , user_id ):
requests . get ( TINDER_URL + f"/pass/ { user_id } " , headers = { "X-Auth-Token" : self . _token }). json ()
return True
def nearby_persons ( self ):
data = requests . get ( TINDER_URL + "/v2/recs/core" , headers = { "X-Auth-Token" : self . _token }). json ()
return list ( map ( lambda user : Person ( user [ "user" ], self ), data [ "data" ][ "results" ]))يمكننا الآن استخدام API للعثور على أشخاص في مكان قريب وإلقاء نظرة على ملفهم الشخصي ، أو حتى مثلهم جميعًا. استبدل api-token مع X-auth-token التي وجدت في وحدة التحكم في Chrome Dev في وقت سابق.
if __name__ == "__main__" :
token = "YOUR-API-TOKEN"
api = tinderAPI ( token )
while True :
persons = api . nearby_persons ()
for person in persons :
print ( person )
# person.like() بعد ذلك ، نريد تنزيل بعض صور الأشخاص القريبة تلقائيًا والتي يمكننا استخدامها لتدريب الذكاء الاصطناعي لدينا. مع "البعض" ، أعني مثل 1500-2500 صور.
أولاً ، دعنا نوسع فئة شخصنا بوظيفة تسمح لنا بتنزيل الصور.
# At the top of auto_tinder.py
PROF_FILE = "./images/unclassified/profiles.txt"
# inside the Person-class
def download_images ( self , folder = "." , sleep_max_for = 0 ):
with open ( PROF_FILE , "r" ) as f :
lines = f . readlines ()
if self . id in lines :
return
with open ( PROF_FILE , "a" ) as f :
f . write ( self . id + " r n " )
index = - 1
for image_url in self . images :
index += 1
req = requests . get ( image_url , stream = True )
if req . status_code == 200 :
with open ( f" { folder } / { self . id } _ { self . name } _ { index } .jpeg" , "wb" ) as f :
f . write ( req . content )
sleep ( random () * sleep_max_for )لاحظ أنني أضفت بعض النوم العشوائي هنا وهناك ، لمجرد أننا سنحظر على الأرجح إذا تم إرسال بريد إلكتروني إلى Tinder CDN وقم بتنزيل العديد من الصور في بضع ثوانٍ فقط.
نكتب جميع معرفات ملف تعريف Peoples في ملف يسمى "Perfile.txt". من خلال مسح المستند أولاً ما إذا كان هناك شخص معين موجود بالفعل هناك ، يمكننا تخطي الأشخاص الذين واجهناهم بالفعل ، ونتضمن عدم تصنيف الأشخاص عدة مرات (سترى لاحقًا سبب وجود خطر).
يمكننا الآن فقط حلقة على الأشخاص القريبين وتنزيل صورهم في مجلد "غير مصنف".
if __name__ == "__main__" :
token = "YOUR-API-TOKEN"
api = tinderAPI ( token )
while True :
persons = api . nearby_persons ()
for person in persons :
person . download_images ( folder = "./images/unclassified" , sleep_max_for = random () * 3 )
sleep ( random () * 10 )
sleep ( random () * 10 )يمكننا الآن ببساطة بدء هذا البرنامج النصي والسماح له بالركض لبضع ساعات للحصول على عدد قليل من صور ملف تعريف Hundret للأشخاص القريبين. إذا كنت من مستخدمي Tinder Pro ، فقم بتحديث موقعك الآن وبعد ذلك للحصول على أشخاص جدد.
الآن بعد أن أصبح لدينا مجموعة من الصور للعمل معها ، دعنا نبني مصنفًا بسيطًا وقبيحًا حقًا.
يجب أن تحلق فقط على جميع الصور في مجلدنا "غير المصنف" وفتح الصورة في نافذة واجهة المستخدم الرسومية. من خلال النقر بزر الماوس الأيمن على شخص ما ، يمكننا وضع علامة على الشخص على أنه "يكره" ، في حين أن النقر اليسرى يصادف الشخص على أنه "مثل". سيتم تمثيل هذا في اسم الملف لاحقًا: سيتم إعادة تسمية 4TZ3KJLDFJ3482.JPG إلى 1_4TZ3KJLDFJ3482.JPG إذا وضعنا علامة على الصورة على أنها "مثل" ، أو 0_4TZ3KJLDFJ3482.JPG على خلاف ذلك. يتم تشفير الملصق مثل/كره كأبعاد في بداية filenmae.
دعنا نستخدم tkinter لكتابة هذا واجهة المستخدم الرسومية بسرعة:
from os import listdir , rename
from os . path import isfile , join
import tkinter as tk
from PIL import ImageTk , Image
IMAGE_FOLDER = "./images/unclassified"
images = [ f for f in listdir ( IMAGE_FOLDER ) if isfile ( join ( IMAGE_FOLDER , f ))]
unclassified_images = filter ( lambda image : not ( image . startswith ( "0_" ) or image . startswith ( "1_" )), images )
current = None
def next_img ():
global current , unclassified_images
try :
current = next ( unclassified_images )
except StopIteration :
root . quit ()
print ( current )
pil_img = Image . open ( IMAGE_FOLDER + "/" + current )
width , height = pil_img . size
max_height = 1000
if height > max_height :
resize_factor = max_height / height
pil_img = pil_img . resize (( int ( width * resize_factor ), int ( height * resize_factor )), resample = Image . LANCZOS )
img_tk = ImageTk . PhotoImage ( pil_img )
img_label . img = img_tk
img_label . config ( image = img_label . img )
def positive ( arg ):
global current
rename ( IMAGE_FOLDER + "/" + current , IMAGE_FOLDER + "/1_" + current )
next_img ()
def negative ( arg ):
global current
rename ( IMAGE_FOLDER + "/" + current , IMAGE_FOLDER + "/0_" + current )
next_img ()
if __name__ == "__main__" :
root = tk . Tk ()
img_label = tk . Label ( root )
img_label . pack ()
img_label . bind ( "<Button-1>" , positive )
img_label . bind ( "<Button-3>" , negative )
btn = tk . Button ( root , text = 'Next image' , command = next_img )
next_img () # load first image
root . mainloop ()نقوم بتحميل جميع الصور غير المصنفة في قائمة "unclassified_images" ، ونفتح نافذة tkinter ، وحزم الصورة الأولى فيها عن طريق الاتصال بـ next_img () وتغيير حجم الصورة لتناسب الشاشة. بعد ذلك ، نقوم بتسجيل نقرتين ، أزرار الماوس اليمنى واليسرى ، ونقوم بالاتصال بالوظائف الإيجابية/السلبية التي تقوم بإعادة تسمية الصور وفقًا لتسميةها وإظهار الصورة التالية.
قبيحة ولكنها فعالة.
بالنسبة للخطوة التالية ، نحتاج إلى إحضار بيانات الصور الخاصة بنا إلى تنسيق يسمح لنا بالقيام بتصنيف. هناك بعض الصعوبات التي يتعين علينا التفكير فيها بالنظر إلى مجموعة البيانات الخاصة بنا.
نحن نحارب هذه التحديات من خلال:

الجزء الأول سهل مثل استخدام الوسادة لفتح صورتنا وتحويلها إلى Greyscale. بالنسبة للجزء الثاني ، نستخدم واجهة برمجة تطبيقات TensorFlow للكائنات مع بنية شبكة Mobilenet ، التي تم تجهيزها على مجموعة بيانات Coco التي تحتوي أيضًا على ملصق لـ "الشخص".
يحتوي البرنامج النصي للكشف عن الشخص على أربعة أجزاء:
يمكنك العثور على ملف .bp لرسم البياني Coco TensorFlow Mobilenet في مستودع GitHub الخاص بي. دعنا نفتحه كرسوم بيانية Tensorflow:
import tensorflow as tf
def open_graph ():
detection_graph = tf . Graph ()
with detection_graph . as_default ():
od_graph_def = tf . GraphDef ()
with tf . gfile . GFile ( 'ssd_mobilenet_v1_coco_2017_11_17/frozen_inference_graph.pb' , 'rb' ) as fid :
serialized_graph = fid . read ()
od_graph_def . ParseFromString ( serialized_graph )
tf . import_graph_def ( od_graph_def , name = '' )
return detection_graphنستخدم وسادة لمعالجة الصور. نظرًا لأن TensorFlow يحتاج إلى صفائف numpy الخام للعمل مع البيانات ، فلنكتب وظيفة صغيرة تقوم بتحويل صور الوسادة إلى صفائف numpy:
import numpy as np
def load_image_into_numpy_array ( image ):
( im_width , im_height ) = image . size
return np . array ( image . getdata ()). reshape (
( im_height , im_width , 3 )). astype ( np . uint8 )تأخذ الوظيفة التالية صورة ورسم بياني TensorFlow ، وتشغيل جلسة TensorFlow باستخدامها وإرجاع جميع المعلومات حول الفئات التي تم اكتشافها (أنواع الكائنات) ، مربعات محددة وعشرات (اليقين تم اكتشاف الكائن بشكل صحيح).
import numpy as np
from object_detection . utils import ops as utils_ops
import tensorflow as tf
def run_inference_for_single_image ( image , sess ):
ops = tf . get_default_graph (). get_operations ()
all_tensor_names = { output . name for op in ops for output in op . outputs }
tensor_dict = {}
for key in [
'num_detections' , 'detection_boxes' , 'detection_scores' ,
'detection_classes' , 'detection_masks'
]:
tensor_name = key + ':0'
if tensor_name in all_tensor_names :
tensor_dict [ key ] = tf . get_default_graph (). get_tensor_by_name (
tensor_name )
if 'detection_masks' in tensor_dict :
# The following processing is only for single image
detection_boxes = tf . squeeze ( tensor_dict [ 'detection_boxes' ], [ 0 ])
detection_masks = tf . squeeze ( tensor_dict [ 'detection_masks' ], [ 0 ])
# Reframe is required to translate mask from box coordinates to image coordinates and fit the image size.
real_num_detection = tf . cast ( tensor_dict [ 'num_detections' ][ 0 ], tf . int32 )
detection_boxes = tf . slice ( detection_boxes , [ 0 , 0 ], [ real_num_detection , - 1 ])
detection_masks = tf . slice ( detection_masks , [ 0 , 0 , 0 ], [ real_num_detection , - 1 , - 1 ])
detection_masks_reframed = utils_ops . reframe_box_masks_to_image_masks (
detection_masks , detection_boxes , image . shape [ 1 ], image . shape [ 2 ])
detection_masks_reframed = tf . cast (
tf . greater ( detection_masks_reframed , 0.5 ), tf . uint8 )
# Follow the convention by adding back the batch dimension
tensor_dict [ 'detection_masks' ] = tf . expand_dims (
detection_masks_reframed , 0 )
image_tensor = tf . get_default_graph (). get_tensor_by_name ( 'image_tensor:0' )
# Run inference
output_dict = sess . run ( tensor_dict ,
feed_dict = { image_tensor : image })
# all outputs are float32 numpy arrays, so convert types as appropriate
output_dict [ 'num_detections' ] = int ( output_dict [ 'num_detections' ][ 0 ])
output_dict [ 'detection_classes' ] = output_dict [
'detection_classes' ][ 0 ]. astype ( np . int64 )
output_dict [ 'detection_boxes' ] = output_dict [ 'detection_boxes' ][ 0 ]
output_dict [ 'detection_scores' ] = output_dict [ 'detection_scores' ][ 0 ]
if 'detection_masks' in output_dict :
output_dict [ 'detection_masks' ] = output_dict [ 'detection_masks' ][ 0 ]
return output_dictالخطوة الأخيرة هي كتابة وظيفة تأخذ مسار الصورة ، ويفتحها باستخدام الوسادة ، وتستدعي واجهة API للكشف عن الكائن ومحاصيل الصورة وفقًا لمربع محيط الأشخاص المكتشفون.
import numpy as np
from PIL import Image
PERSON_CLASS = 1
SCORE_THRESHOLD = 0.5
def get_person ( image_path , sess ):
img = Image . open ( image_path )
image_np = load_image_into_numpy_array ( img )
image_np_expanded = np . expand_dims ( image_np , axis = 0 )
output_dict = run_inference_for_single_image ( image_np_expanded , sess )
persons_coordinates = []
for i in range ( len ( output_dict [ "detection_boxes" ])):
score = output_dict [ "detection_scores" ][ i ]
classtype = output_dict [ "detection_classes" ][ i ]
if score > SCORE_THRESHOLD and classtype == PERSON_CLASS :
persons_coordinates . append ( output_dict [ "detection_boxes" ][ i ])
w , h = img . size
for person_coordinate in persons_coordinates :
cropped_img = img . crop ((
int ( w * person_coordinate [ 1 ]),
int ( h * person_coordinate [ 0 ]),
int ( w * person_coordinate [ 3 ]),
int ( h * person_coordinate [ 2 ]),
))
return cropped_img
return Noneكخطوة أخيرة ، نكتب برنامج نصي يحلق على جميع الصور في المجلد "غير المصنف" ، والتحقق مما إذا كان لديهم تسمية مشفرة بالاسم ينسخ الصورة في المجلد "المصنف" وفقًا لتطبيق خطوات المعالجة المسبقة التي تم تطويرها مسبقًا:
import os
import person_detector
import tensorflow as tf
IMAGE_FOLDER = "./images/unclassified"
POS_FOLDER = "./images/classified/positive"
NEG_FOLDER = "./images/classified/negative"
if __name__ == "__main__" :
detection_graph = person_detector . open_graph ()
images = [ f for f in os . listdir ( IMAGE_FOLDER ) if os . path . isfile ( os . path . join ( IMAGE_FOLDER , f ))]
positive_images = filter ( lambda image : ( image . startswith ( "1_" )), images )
negative_images = filter ( lambda image : ( image . startswith ( "0_" )), images )
with detection_graph . as_default ():
with tf . Session () as sess :
for pos in positive_images :
old_filename = IMAGE_FOLDER + "/" + pos
new_filename = POS_FOLDER + "/" + pos [: - 5 ] + ".jpg"
if not os . path . isfile ( new_filename ):
img = person_detector . get_person ( old_filename , sess )
if not img :
continue
img = img . convert ( 'L' )
img . save ( new_filename , "jpeg" )
for neg in negative_images :
old_filename = IMAGE_FOLDER + "/" + neg
new_filename = NEG_FOLDER + "/" + neg [: - 5 ] + ".jpg"
if not os . path . isfile ( new_filename ):
img = person_detector . get_person ( old_filename , sess )
if not img :
continue
img = img . convert ( 'L' )
img . save ( new_filename , "jpeg" )عندما نقوم بتشغيل هذا البرنامج النصي ، تتم معالجة جميع الصور المسمى ونقلها إلى المجلدات الفرعية المقابلة في الدليل "المصنف".
بالنسبة لجزء التدريب ، سنستخدم فقط TensorFlows Retrain.py البرنامج النصي مع نموذج InceptionV3.
اتصل بالبرنامج النصي في دليل جذر المشروع الخاص بك مع المعلمات التالية:
python retrain.py --bottleneck_dir=tf/training_data/bottlenecks --model_dir=tf/training_data/inception --summaries_dir=tf/training_data/summaries/basic --output_graph=tf/training_output/retrained_graph.pb --output_labels=tf/training_output/retrained_labels.txt --image_dir=./images/classified --how_many_training_steps=50000 --testing_percentage=20 --learning_rate=0.001يستغرق التعلم حوالي 15 دقيقة على GTX 1080 TI ، بدقة نهائية تبلغ حوالي 80 ٪ لمجموعة البيانات المسمى ، ولكن هذا يعتمد بشكل كبير على جودة بيانات الإدخال الخاصة بك ووضع العلامات الخاصة بك.
نتيجة عملية التدريب هي نموذج inceptionv3 مدرب في ملف "TF/Training_output/Retrained_graph.pb". يجب علينا الآن كتابة فئة مصنف تستخدم بكفاءة الأوزان الجديدة في الرسم البياني لـ TensorFlow لإجراء تنبؤ بالتصنيف.
دعنا نكتب فئة المصنف التي تفتح الرسم البياني كجلسة ويقدم طريقة "تصنيف" مع ملف صورة يعيد التقليل بقيم اليقين التي تتطابق مع ملصقاتنا "إيجابية" و "سلبية".
يأخذ الفصل كإدخال المسار إلى الرسم البياني وكذلك المسار إلى ملف التسمية ، وكلاهما يجلس في مجلد "TF/Training_output/". نقوم بتطوير وظائف المساعدة لتحويل ملف صورة إلى موتر يمكننا إطعامه في الرسم البياني لدينا ، ودالة مساعد لتحميل الرسم البياني والعلامات ووظيفة صغيرة مهمة لإغلاق الرسم البياني الخاص بنا بعد الانتهاء من استخدامه.
import numpy as np
import tensorflow as tf
class Classifier ():
def __init__ ( self , graph , labels ):
self . _graph = self . load_graph ( graph )
self . _labels = self . load_labels ( labels )
self . _input_operation = self . _graph . get_operation_by_name ( "import/Placeholder" )
self . _output_operation = self . _graph . get_operation_by_name ( "import/final_result" )
self . _session = tf . Session ( graph = self . _graph )
def classify ( self , file_name ):
t = self . read_tensor_from_image_file ( file_name )
# Open up a new tensorflow session and run it on the input
results = self . _session . run ( self . _output_operation . outputs [ 0 ], { self . _input_operation . outputs [ 0 ]: t })
results = np . squeeze ( results )
# Sort the output predictions by prediction accuracy
top_k = results . argsort ()[ - 5 :][:: - 1 ]
result = {}
for i in top_k :
result [ self . _labels [ i ]] = results [ i ]
# Return sorted result tuples
return result
def close ( self ):
self . _session . close ()
@ staticmethod
def load_graph ( model_file ):
graph = tf . Graph ()
graph_def = tf . GraphDef ()
with open ( model_file , "rb" ) as f :
graph_def . ParseFromString ( f . read ())
with graph . as_default ():
tf . import_graph_def ( graph_def )
return graph
@ staticmethod
def load_labels ( label_file ):
label = []
proto_as_ascii_lines = tf . gfile . GFile ( label_file ). readlines ()
for l in proto_as_ascii_lines :
label . append ( l . rstrip ())
return label
@ staticmethod
def read_tensor_from_image_file ( file_name ,
input_height = 299 ,
input_width = 299 ,
input_mean = 0 ,
input_std = 255 ):
input_name = "file_reader"
file_reader = tf . read_file ( file_name , input_name )
image_reader = tf . image . decode_jpeg (
file_reader , channels = 3 , name = "jpeg_reader" )
float_caster = tf . cast ( image_reader , tf . float32 )
dims_expander = tf . expand_dims ( float_caster , 0 )
resized = tf . image . resize_bilinear ( dims_expander , [ input_height , input_width ])
normalized = tf . divide ( tf . subtract ( resized , [ input_mean ]), [ input_std ])
sess = tf . Session ()
result = sess . run ( normalized )
return result الآن وبعد أن أصبح لدينا مصنفنا في مكانه ، دعنا نوسع فئة "الشخص" من وقت سابق وتوسيعها مع وظيفة "predict_likeliness" التي تستخدم مثيل المصنف للتحقق مما إذا كان ينبغي أن يكون الشخص المعطى محبوبًا أم لا.
# In the Person class
def predict_likeliness ( self , classifier , sess ):
ratings = []
for image in self . images :
req = requests . get ( image , stream = True )
tmp_filename = f"./images/tmp/run.jpg"
if req . status_code == 200 :
with open ( tmp_filename , "wb" ) as f :
f . write ( req . content )
img = person_detector . get_person ( tmp_filename , sess )
if img :
img = img . convert ( 'L' )
img . save ( tmp_filename , "jpeg" )
certainty = classifier . classify ( tmp_filename )
pos = certainty [ "positive" ]
ratings . append ( pos )
ratings . sort ( reverse = True )
ratings = ratings [: 5 ]
if len ( ratings ) == 0 :
return 0.001
return ratings [ 0 ] * 0.6 + sum ( ratings [ 1 :]) / len ( ratings [ 1 :]) * 0.4الآن علينا أن نجمع كل قطع الألغاز معًا.
أولاً ، دعنا نهيئة واجهة برمجة تطبيقات Tinder مع رمز API الخاص بنا. بعد ذلك ، نفتح الرسم البياني لـ TensorFlow تصنيفنا كجلسة TensorFlow باستخدام الرسم البياني والتسميات المدربين. ثم ، نجلب الأشخاص القريبين ونجعل التنبؤ بالاحتمال.
كمكافأة صغيرة ، أضفت محترفين من 1.2 إذا ذهب الشخص الموجود في Tinder إلى نفس الجامعة كما أفعل ، بحيث يكون من المرجح أن أتطابق مع الطلاب المحليين.
بالنسبة لجميع الأشخاص الذين لديهم درجة احترافية متوقعة قدرها 0.8 ، أسميها ، لجميع غيرها من الكراهية.
لقد طورت البرنامج النصي للعب تلقائيًا لمدة ساعتين التاليتين بعد بدء تشغيله.
from likeliness_classifier import Classifier
import person_detector
import tensorflow as tf
from time import time
if __name__ == "__main__" :
token = "YOUR-API-TOKEN"
api = tinderAPI ( token )
detection_graph = person_detector . open_graph ()
with detection_graph . as_default ():
with tf . Session () as sess :
classifier = Classifier ( graph = "./tf/training_output/retrained_graph.pb" ,
labels = "./tf/training_output/retrained_labels.txt" )
end_time = time () + 60 * 60 * 2
while time () < end_time :
try :
persons = api . nearby_persons ()
pos_schools = [ "Universität Zürich" , "University of Zurich" , "UZH" ]
for person in persons :
score = person . predict_likeliness ( classifier , sess )
for school in pos_schools :
if school in person . schools :
print ()
score *= 1.2
print ( "-------------------------" )
print ( "ID: " , person . id )
print ( "Name: " , person . name )
print ( "Schools: " , person . schools )
print ( "Images: " , person . images )
print ( score )
if score > 0.8 :
res = person . like ()
print ( "LIKE" )
else :
res = person . dislike ()
print ( "DISLIKE" )
except Exception :
pass
classifier . close ()هذا كل شيء! يمكننا الآن أن ندع البرنامج النصي الخاص بنا يركض طالما نحب ونلعب Tinder دون إساءة استخدام إبهامنا!
إذا كانت لديك أسئلة أو عثرت على الأخطاء ، فلا تتردد في المساهمة في مستودع github الخاص بي.
رخصة معهد ماساتشوستس للتكنولوجيا
حقوق الطبع والنشر (C) 2018 جويل بارميتلر
يتم منح الإذن بموجب هذا ، مجانًا ، لأي شخص يحصل على نسخة من هذا البرنامج وملفات الوثائق المرتبطة ("البرنامج") ، للتعامل في البرنامج دون تقييد ، بما في ذلك على سبيل المثال لا الحصر حقوق استخدام ، نسخ ، تعديل ، دمج أو نشر نسخ وتوزيعها و/أو بيعها و/أو بيع نسخ من البرامج ، والسماح للأشخاص الذين يتم تقديم البرنامج لهم للقيام بذلك ، مع مراعاة الشروط التالية:
يجب إدراج إشعار حقوق الطبع والنشر أعلاه وإشعار الإذن هذا في جميع النسخ أو الأجزاء الكبيرة من البرنامج.
يتم توفير البرنامج "كما هو" ، دون أي ضمان من أي نوع ، صريح أو ضمني ، بما في ذلك على سبيل المثال لا الحصر ضمانات القابلية للتسويق واللياقة لغرض معين وعدم الانفجار. لا يجوز بأي حال من الأحوال أن يتحمل المؤلفون أو حاملي حقوق الطبع والنشر مسؤولية أي مطالبة أو أضرار أو مسؤولية أخرى ، سواء في إجراء عقد أو أضرار أو غير ذلك ، ناشئة عن البرامج أو خارجها أو الاستخدام أو غيرها برمجة.
استئجار الولايات المتحدة: البرمجيات entwickler في Zürich!