Auto-Tinder wurde erstellt, um eine API mit Tensorflow und Python3 zu trainieren, die Ihre Interessen lernt und automatisch den Zunder-Wischspiel für Sie spielt.

In diesem Dokument werde ich die folgenden Schritte erläutern, die für die Erstellung von Auto-Tinder erforderlich waren:
Auto Tinder ist ein Konzeptprojekt, das nur für unterhaltsame und pädagogische Zwecke erstellt wurde. Es wird niemals missbraucht, um jemandem zu schaden oder die Plattform zu spam. Die automatischen Skripte sollten nicht mit Ihrem Zunder-Profil verwendet werden, da sie sicherlich gegen Tindersbedingungen verstoßen.
Ich habe diese Software hauptsächlich aus zwei Gründen geschrieben:
Der erste Schritt besteht darin, herauszufinden, wie die Tinder -App mit Tinders Backend Server kommuniziert. Da Tinder eine Webversion seines Portals anbietet, ist dies so einfach wie bei Tinder.com zu gehen, Chrome Devtools zu öffnen und das Netzwerkprotokoll kurz zu betrachten.
Der im obige Bild angezeigte Inhalt stammt aus einer Anfrage zu https://api.gotinder.com/v2/recs/core, die beim Laden der Tinder.com -Zielseite erstellt wird. Tinder hat eindeutig eine interne API, mit der sie zwischen Front- und Backend kommunizieren.
Bei der Analyse des Inhalts von /recs /core wird klar, dass dieser API -Endpunkt eine Liste von Benutzerprofilen von Personen in der Nähe zurückgibt.
Die Daten umfassen (unter vielen anderen Feldern) die folgenden Daten:
{
"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" : []
}
}
]
}
}
Ein paar Dinge sind hier sehr interessant (beachten Sie, dass ich alle Daten geändert habe, um nicht gegen die Privatsphäre der Person zu verstoßen) :
Bei der Analyse der Inhaltsheader finden wir schnell unsere privaten API-Schlüssel: X-Auth-Token .
Wenn wir dieses Token kopieren und zum Postman gehen, können wir bestätigen, dass wir tatsächlich frei mit der Tinder -API mit der richtigen URL und unserem Auth -Token kommunizieren können.
Wenn ich ein bisschen durch Tinders WebApp klicke, entdecke ich schnell alle relevanten API -Endpunkte:
| Typ | URL | Beschreibung |
|---|---|---|
| ERHALTEN | /v2/recs/core | Gibt eine Liste von Personen in der Nähe zurück |
| ERHALTEN | /v2/Profil? Include = Account%2Cuser | Gibt alle Informationen zu Ihrem eigenen Profil zurück |
| ERHALTEN | /v2/Matches | Gibt eine Liste aller Personen zurück, die mit Ihnen übereinstimmen |
| ERHALTEN | /wie/{user_id} | Mag die Person mit dem gegebenen user_id |
| ERHALTEN | /pass/{user_id} | Übergibt die Person mit dem gegebenen user_id |
Kommen wir also in den Code. Wir werden die Python -Anforderungsbibliothek verwenden, um mit der API zu kommunizieren und eine API -Wrapper -Klasse um sie zu schreiben.
In ähnlicher Weise schreiben wir eine Klassenklasse mit kleiner Person, die die API -Antwort von Tinder, die eine Person darstellt, die Tinder -API darstellt.
Beginnen wir mit der Personklasse. Es empfängt API-Daten, ein Tinder-API-Objekt und speichert alle relevanten Daten in Instanzvariablen. Es muss einige grundlegende Funktionen wie "Like" oder "Abneigung" anbieten, die die Tinder-API anfordern, die es uns ermöglicht, "slow_person.like ()" bequem zu verwenden, um ein Profil zu mögen, das wir interessant finden.
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 )Unsere API -Wrapper ist nicht viel mehr als eine ausgefallene Art, die Tinder -API mit einer Klasse aufzurufen:
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" ]))Wir können jetzt die API verwenden, um Menschen in der Nähe zu finden und sich ihr Profil anzusehen oder sogar alle von ihnen. Ersetzen Sie Ihr API-Token durch das X-Auth-Token, das Sie früher in der Chrome Dev-Konsole gefunden haben.
if __name__ == "__main__" :
token = "YOUR-API-TOKEN"
api = tinderAPI ( token )
while True :
persons = api . nearby_persons ()
for person in persons :
print ( person )
# person.like() Als nächstes möchten wir automatisch einige Bilder von Personen in der Nähe herunterladen, die wir für die Schulung unserer KI verwenden können. Mit 'Einige' meine ich wie 1500-2500 Bilder.
Lassen Sie uns zunächst unsere Personklasse mit einer Funktion erweitern, mit der wir Bilder herunterladen können.
# 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 )Beachten Sie, dass ich hier und da einige zufällige Schlafe hinzugefügt habe, nur weil wir wahrscheinlich blockiert werden, wenn wir den Tinder CDN spammen und viele Bilder in nur wenigen Sekunden herunterladen.
Wir schreiben alle Profil -IDs der Menschen in eine Datei namens "Profiles.txt". Durch das erste Scannen des Dokuments, ob eine bestimmte Person bereits da ist, können wir Personen, denen wir bereits begegnet sind, überspringen, und wir stellen sicher, dass wir Menschen nicht mehrmals klassifizieren (Sie werden später sehen, warum dies ein Risiko ist).
Wir können jetzt einfach über nahe gelegene Personen wechseln und ihre Bilder in einen "nicht klassifizierten" Ordner herunterladen.
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 )Wir können dieses Skript jetzt einfach starten und es ein paar Stunden lang ausführen lassen, um ein paar Hundret -Profilbilder von Personen in der Nähe zu erhalten. Wenn Sie ein Tinder Pro -Benutzer sind, aktualisieren Sie Ihren Standort ab und zu, um neue Personen zu erhalten.
Nachdem wir eine Reihe von Bildern haben, mit denen wir arbeiten können, lassen Sie uns einen wirklich einfachen und hässlichen Klassifizierer aufbauen.
Es soll einfach alle Bilder in unserem "nicht klassifizierten" Ordner überschreiten und das Bild in einem GUI -Fenster öffnen. Indem wir mit der rechten Maustaste auf eine Person klicken, können wir die Person als "Abneigung" markieren, während ein linkes Klick die Person als "Like" markiert. Dies wird später im Dateinamen dargestellt: 4Tz3kjldfj3482.jpg wird in 1_4TZ3KJLDFJ3482.JPG umbenannt, wenn wir das Bild als "Gefällt mir" oder 0_4TZ3KJLDFJ3482.JPG ansonsten markieren. Das Etikett wie/Abneigung wird zu Beginn des Filenmae als 1/0 codiert.
Verwenden wir Tkinter, um diese GUI schnell zu schreiben:
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 ()Wir laden alle nicht klassifizierten Bilder in die Liste "Nicht klassifiziert_images", öffnen ein Tkinter -Fenster, packen das erste Bild ein, indem Sie Next_img () aufrufen und das Bild so ändern, dass sie auf den Bildschirm passen. Anschließend registrieren wir zwei Klicks, links und die rechte Maustasten und rufen die Funktionen positiv/negativ auf, die die Bilder gemäß ihrem Etikett umgeben und das nächste Bild anzeigen.
Hässlich, aber effektiv.
Für den nächsten Schritt müssen wir unsere Bilddaten in ein Format bringen, mit dem wir eine Klassifizierung durchführen können. Es gibt einige Schwierigkeiten, die wir angesichts unseres Datensatzes berücksichtigen müssen.
Wir bekämpfen diese Herausforderungen durch:

Der erste Teil ist so einfach wie das Öffnen von Kissen, um unser Bild zu öffnen und es in Graustufen umzuwandeln. Für den zweiten Teil verwenden wir die TensorFlow -Objekterkennungs -API mit der Mobilenet -Netzwerkarchitektur, die auf dem Coco -Datensatz vorgebracht ist, das auch ein Etikett für "Person" enthält.
Unser Skript für die Erkennung von Personen enthält vier Teile:
Sie finden die .bp -Datei für das TensorFlow Mobilenet Coco -Diagramm in meinem Github -Repository. Öffnen wir es als Tensorflow -Diagramm:
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_graphWir verwenden Kissen zur Bildmanipulation. Da TensorFlow rohe Numpy -Arrays benötigt, um mit den Daten zu arbeiten, schreiben wir eine kleine Funktion, die Kissenbilder in Numpy -Arrays umwandelt:
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 )Die nächste Funktion nimmt ein Bild und ein Tensorflow -Diagramm auf, führt eine Tensorflow -Sitzung mit es aus und gibt alle Informationen über die erkannten Klassen (Objekttypen), Begrenzungsboxen und Bewertungen zurück (Gewissheit, dass das Objekt korrekt erkannt wurde).
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_dictDer letzte Schritt besteht darin, eine Funktion zu schreiben, die einen Bildpfad übernimmt, sie mit Kissen öffnet, die Objekterkennungs -API -Schnittstelle aufruft und das Bild gemäß den erfassten Personen begrenzt.
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 NoneAls letzter Schritt schreiben wir ein Skript, das alle Bilder im Ordner "nicht klassifiziert" überschreitet, überprüft, ob sie im Namen ein codiertes Etikett im Namen des Namens in dem Ordner "Klassifiziert" kopiert, wobei die zuvor entwickelten Vorverarbeitungsschritte angewendet werden:
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" )Wenn wir dieses Skript ausführen, werden alle beschrifteten Bilder verarbeitet und in entsprechende Unterordner im "Klassifizierten" Verzeichnis verarbeitet.
Für den Umschulungsteil verwenden wir nur TensorFlows Retrain.py -Skript mit dem Inceptionv3 -Modell.
Rufen Sie das Skript in Ihrem Projekt Root Directory mit den folgenden Parametern an:
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.001Das Lernen dauert ungefähr 15 Minuten bei einem GTX 1080 TI, mit einer endgültigen Genauigkeit von etwa 80% für meinen beschrifteten Datensatz, dies hängt jedoch stark von der Qualität Ihrer Eingabedaten und Ihrer Beschriftung ab.
Das Ergebnis des Trainingsprozesses ist ein umfasertes Inceptionv3 -Modell in der Datei "TF/Training_Output/retailliert_graph.pb". Wir müssen jetzt eine Klassifikatorklasse schreiben, die die neuen Gewichte im Tensorflow -Diagramm effizient verwendet, um eine Klassifizierungsvorhersage vorzunehmen.
Schreiben wir eine Klassifikatorklasse, die das Diagramm als Sitzung öffnet und eine "Klassifizierung" -Methode mit einer Bilddatei anbietet, die ein Diktat mit Sicherheitswerten zurückgibt, die unseren Labels "positiv" und "negativ" entsprechen.
Die Klasse nimmt sowohl den Pfad zum Diagramm als auch den Pfad zur Etikettendatei ein, die beide in unserem Ordner "TF/Training_Output/" sitzen. Wir entwickeln Helferfunktionen zum Konvertieren einer Bilddatei in einen Tensor, den wir in unseren Diagramm einspeisen können, eine Helferfunktion zum Laden des Diagramms und der Beschriftungen und eine wichtige kleine Funktion, um unser Diagramm zu schließen, nachdem wir sie mit dieser mit dieser erledigt sind.
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 Nachdem wir unseren Klassifikator vorhanden haben, erweitern wir die "Person" -Klasse von früher und erweitern sie mit einer Funktion "predict_likeliness", die eine Klassifikatorinstanz verwendet, um zu überprüfen, ob eine bestimmte Person gemocht werden sollte oder nicht.
# 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.4Jetzt müssen wir alle Puzzleteile zusammenbringen.
Lassen Sie uns zunächst die Tinder -API mit unserem API -Token initialisieren. Anschließend öffnen wir unseren TensorFlow -Diagramm der Klassifizierung als Tensorflow -Sitzung mit unserem umkassierten Diagramm und den Etiketten. Dann holen wir Personen in der Nähe und machen eine Wahrscheinlichkeit Vorhersage.
Als kleiner Bonus habe ich einen Wahrscheinlichkeitsmultiplikator von 1,2 hinzugefügt, wenn die Person auf Tinder an die gleiche Universität geht wie ich, damit ich eher mit lokalen Studenten übereinstimme.
Für alle Menschen, die eine vorhergesagte Wahrscheinlichkeit von 0,8 haben, nenne ich ein Like, für alle anderen eine Abneigung.
Ich habe das Skript für die nächsten 2 Stunden nach dem Start für das automatische Spiel entwickelt.
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 ()Das war's! Wir können jetzt unser Drehbuch so lange laufen lassen, wie wir es mögen und Tinder spielen, ohne unseren Daumen zu missbrauchen!
Wenn Sie Fragen oder Fehlern haben, können Sie zu meinem Github -Repository beisteuern.
MIT -Lizenz
Copyright (C) 2018 Joel Barmettler
Die Erlaubnis wird hiermit kostenlos an eine Person erteilt, die eine Kopie dieser Software und zugehörigen Dokumentationsdateien ("Software") erhält, um die Software ohne Einschränkung zu behandeln, einschließlich ohne Einschränkung der Rechte zu verwenden, zu kopieren, zu modifizieren, zu verschmelzen, verschmelzen , veröffentlichen, vertreiben, unterlizenzieren und/oder Kopien der Software verkaufen und Personen, denen die Software dazu bereitgestellt wird, unter den folgenden Bedingungen ermöglicht:
Die oben genannte Copyright -Mitteilung und diese Erlaubnisbekanntmachung müssen in alle Kopien oder wesentlichen Teile der Software enthalten sein.
Die Software wird "wie es ist" ohne Garantie jeglicher Art, ausdrücklich oder stillschweigend bereitgestellt, einschließlich, aber nicht beschränkt auf die Gewährleistung der Handelsfähigkeit, die Eignung für einen bestimmten Zweck und die Nichtverletzung. In keinem Fall haftet die Autoren oder Urheberrechtsinhaber für Ansprüche, Schäden oder andere Haftungen, sei es in einer Vertragsklage, unerlaubter Handlung oder anderweitig, aus oder im Zusammenhang mit der Software oder anderen Geschäften in der SOFTWARE.
Hire uns: Software Entwickler in Zürich!