Auto-Tinder는 귀하의 관심사를 배우고 틴더 스 와이프 게임을 자동으로 재생하는 Tensorflow 및 Python3을 사용하여 API를 훈련시키기 위해 만들어졌습니다.

이 문서에서는 자동 텐더를 만드는 데 필요한 다음 단계를 설명하겠습니다.
Auto Tinder는 재미 있고 교육적인 목적을 위해 순수하게 만든 컨셉 프로젝트입니다. 누군가에게 해를 끼치거나 플랫폼을 스팸으로써 학대받지 않아야합니다. 자동 틴더 스크립트는 Tinders 서비스 약관을 반드시 위반하므로 Tinder 프로파일과 함께 사용해서는 안됩니다.
나는 주로 두 가지 이유 중에서이 소프트웨어를 작성했습니다.
첫 번째 단계는 Tinder 앱이 Tinders 백엔드 서버와 통신하는 방법을 찾는 것입니다. Tinder는 포털의 웹 버전을 제공하기 때문에 Tinder.com으로 이동하여 Chrome Devtools를 열고 네트워크 프로토콜을 빠르게 살펴보십시오.
위의 그림에 표시된 내용은 Tinder.com 방문 페이지가로드 될 때 만들어지는 https://api.gotinder.com/v2/recs/core에 대한 요청에서입니다. 분명히, Tinder는 전면과 백엔드간에 통신하는 데 사용하는 일종의 내부 API를 가지고 있습니다.
/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" : []
}
}
]
}
}
여기에서 몇 가지가 매우 흥미 롭습니다 (이 개인 정보를 위반하지 않도록 모든 데이터를 변경했다는 점에 유의하십시오) .
컨텐츠 헤더를 분석하면 개인 API 키 ( X-Auth-Token) 를 빠르게 찾을 수 있습니다.
이 토큰을 복사하고 우체부에게 넘어 가면 올바른 URL과 인증 토큰으로 틴더 API와 자유롭게 의사 소통 할 수 있음을 확인할 수 있습니다.
Tinders WebApp을 통해 약간 클릭하면 모든 관련 API 엔드 포인트를 빠르게 발견합니다.
| 유형 | URL | 설명 |
|---|---|---|
| 얻다 | /v2/recs/core | 근처의 사람들 목록을 반환합니다 |
| 얻다 | /v2/프로필? 포함 = 계정%2Cuser | 자신의 프로필에 대한 모든 정보를 반환합니다 |
| 얻다 | /v2/일치 | 당신과 일치하는 모든 사람들의 목록을 반환합니다. |
| 얻다 | /좋아요/{user_id} | 주어진 user_id를 가진 사람을 좋아합니다 |
| 얻다 | /pass/{user_id} | 주어진 user_id로 사람을 통과시킵니다 |
그래서 코드에 들어가자. Python Requests 라이브러리를 사용하여 API와 통신하고 편의를 위해 API 래퍼 클래스를 작성합니다.
마찬가지로, 우리는 사람을 나타내는 틴더의 API 응답을 취하는 작은 사람 클래스를 작성하고 틴더 API에 몇 가지 기본 인터페이스를 제공합니다.
사람 수업부터 시작하겠습니다. Tinder-API 객체 인 API 데이터를 수신하고 모든 관련 데이터를 인스턴스 변수에 저장해야합니다. 또한 Tinder-API에 요청하는 "Like"또는 "Disike"와 같은 몇 가지 기본 기능을 제공해야합니다.이를 통해 프로필을 좋아하기 위해 "some_person.like ()"를 편리하게 사용할 수 있습니다.
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 래퍼는 클래스를 사용하여 틴더 API를 호출하는 멋진 방법 이상이 아닙니다.
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를 사용하여 근처의 사람들을 찾아서 프로필을 살펴 보거나 심지어 모든 것을 살펴볼 수 있습니다. 이전에 Chrome Dev 콘솔에서 찾은 X-Auth-Token으로 -API-Token을 교체하십시오.
if __name__ == "__main__" :
token = "YOUR-API-TOKEN"
api = tinderAPI ( token )
while True :
persons = api . nearby_persons ()
for person in persons :
print ( person )
# person.like() 다음으로, 우리는 AI를 훈련시키는 데 사용할 수있는 근처의 사람들의 일부 이미지를 자동으로 다운로드하려고합니다. '일부'는 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을 스팸하고 몇 초만에 많은 사진을 다운로드하면 차단 될 가능성이 있기 때문에 여기 저기 임의의 수면을 추가했습니다.
우리는 모든 사람들 프로필 ID를 "profiles.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 사용자 인 경우 지금 위치를 업데이트 한 다음 새로운 사람을 얻으십시오.
이제 작업 할 이미지가 있으므로 정말 간단하고 추악한 분류기를 만들어 봅시다.
"분류되지 않은"폴더의 모든 이미지를 반복하고 GUI 창에서 이미지를 열어야합니다. 사람을 마우스 오른쪽 버튼으로 클릭하면 사람을 "싫어하는"것으로 표시 할 수 있으며 왼쪽 클릭은 사람을 "좋아요"로 표시합니다. 이것은 나중에 파일 이름 으로 표시 됩니다 . Like Like/Like는 Filenmae의 시작 부분에서 1/0으로 인코딩됩니다.
Tkinter를 사용 하여이 GUI를 빠르게 작성합시다.
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으로 변환하는 것만 큼 쉽습니다. 두 번째 부분의 경우 "사람"에 대한 레이블이 포함 된 Coco 데이터 세트에서 사전에 사전에 사전 된 Mobilenet Network Architecture와 함께 Tensorflow 객체 감지 API를 사용합니다.
개인 탐지를위한 스크립트에는 네 가지 부분이 있습니다.
내 GitHub 저장소에서 Tensorflow Mobilenet Coco 그래프의 .BP 파일을 찾을 수 있습니다. 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 Array로 변환하는 작은 기능을 작성해 봅시다.
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 그래프를 사용하고,이를 사용하여 텐서 플로우 세션을 실행하고 감지 된 클래스 (객체 유형), 경계 상자 및 점수 (객체가 올바르게 감지되었음을 확실하게)에 대한 모든 정보를 반환합니다.
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" )이 스크립트를 실행할 때 라벨이 붙은 이미지가 처리되고 "분류 된"디렉토리의 해당 하위 폴더로 이동합니다.
재교육 부품의 경우 inceptionv3 모델과 함께 Tensorflows Reack.py 스크립트 만 사용합니다.
다음 매개 변수로 프로젝트 루트 디렉토리의 스크립트를 호출하십시오.
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학습은 GTX 1080 Ti에서 약 15 분이 걸리며 레이블이 붙은 데이터 세트의 최종 정확도는 약 80%이지만 입력 데이터의 품질과 레이블링에 크게 달려 있습니다.
교육 프로세스의 결과는 "tf/training_output/retrained_graph.pb"파일의 재교육 inceptionv3 모델입니다. 이제 분류 예측을 위해 텐서 플로 그래프의 새로운 가중치를 효율적으로 사용하는 분류기 클래스를 작성해야합니다.
그래프를 세션으로 열고 "positive"및 "negative"와 일치하는 확실성 값이있는 dict를 반환하는 이미지 파일로 "분류"메소드를 제공하는 분류기 클래스를 작성해 봅시다.
클래스는 "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 이제 우리는 분류기를 확보 했으므로 "Person"클래스를 이전에서 확장하고 분류기 인스턴스를 사용하여 주어진 사람을 좋아하는지 여부를 확인하는 "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이제 우리는 모든 퍼즐 조각을 모아야합니다.
먼저 API 토큰으로 Tinder API를 초기화합시다. 그런 다음 재교집 된 그래프 및 레이블을 사용하여 분류 인 Tensorflow 그래프를 텐서 플로 세션으로 열립니다. 그런 다음 우리는 근처에있는 사람들을 데려와 가능성을 예측합니다.
약간의 보너스로, 나는 틴더에있는 사람이 나와 같은 대학에 가면 현지 학생들과 일치 할 가능성이 더 높으면 1.2의 가능성을 1.2로 추가했습니다.
예측 된 우수성 점수가 0.8 인 모든 사람들의 경우, 나는 다른 모든 것을 싫어한다고 부릅니다.
시작 후 2 시간 동안 스크립트를 자동 플레이하기 위해 스크립트를 개발했습니다.
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 ()그게 다야! 우리는 이제 우리가 좋아하는 한 스크립트를 실행하고 엄지 손가락을 남용하지 않고 틴더를 연주 할 수 있습니다!
궁금한 점이 있거나 버그를 찾은 경우 내 Github 저장소에 자유롭게 기여하십시오.
MIT 라이센스
저작권 (C) 2018 Joel Barmettler
이에 따라이 소프트웨어 및 관련 문서 파일 ( "소프트웨어")의 사본을 얻는 사람에게 허가는 제한없이 소프트웨어를 처리 할 수있는 사람에게 무료로 제공됩니다. , 소프트웨어의 사본을 게시, 배포, 서브 리센스 및/또는 판매하고, 소프트웨어가 제공하도록하는 사람을 다음과 같은 조건에 따라 할 수 있도록합니다.
위의 저작권 통지 및이 권한 통지는 소프트웨어의 모든 사본 또는 실질적인 부분에 포함되어야합니다.
이 소프트웨어는 상업성, 특정 목적에 대한 적합성 및 비 침해에 대한 보증을 포함하여 명시 적 또는 묵시적 보증없이 "그대로"제공됩니다. 어떠한 경우에도 저자 또는 저작권 보유자는 계약, 불법 행위 또는 기타, 소프트웨어 또는 사용 또는 기타 거래와 관련하여 계약, 불법 행위 또는 기타의 행동에 관계없이 청구, 손해 또는 기타 책임에 대해 책임을지지 않아야합니다. 소프트웨어.
우리를 고용하십시오 : 취리히의 소프트웨어 Entwickler!