ãã®èšäºã§ã¯ãèªè ã«èå¥ã®ã¿ã¹ã¯ã玹ä»ããŸããåºæ¬çãªå®çŸ©ããããã®åéã®æè¿ã®èšäºã®1ã€ãå®è£ ããããšã§ãã çµæã¯ãåçã§åã人ãæ€çŽ¢ã§ããã¢ããªã±ãŒã·ã§ã³ã§ãããæãéèŠãªã®ã¯ããã®ä»çµã¿ãç解ããããšã§ãã
Bourneã®èå¥ïŒBourneã ãã§ãªãïŒ
èå¥åé¡ã¯åé¡åé¡ã«äŒŒãŠãããæŽå²çã«ãã®åé¡ããçããŸããããªããžã§ã¯ãã®ã¯ã©ã¹ã決å®ãã代ããã«ããªããžã§ã¯ãã«å¿ èŠãªããããã£ããããã©ããã決å®ããããšãå¿ èŠã«ãªããŸããã èå¥åé¡ã§ã¯ããã¬ãŒãã³ã°ã»ããã¯ãªããžã§ã¯ãã®ã»ããã§ã ãããããã«ããããã£ããããŸã ïŒ ãã©ããã ããã«ããã¹ãŠã®ãªããžã§ã¯ãã¯åãã¯ã©ã¹ã«å±ããæå®ãããããããã£ãæããªããªããžã§ã¯ãã®ä»£è¡šçãªéžæãè¡ãããšã¯äžå¯èœã§ã ã
ããšãã°ããµã«ã®é¡ãã人ã®é¡ãåé¢ããå Žåãããã¯åé¡ã¿ã¹ã¯ã§ãã2ã€ã®ã¯ã©ã¹ãããããªããžã§ã¯ãããšã«ã¯ã©ã¹ãæå®ããŠãäž¡æ¹ã®ã¯ã©ã¹ã®ä»£è¡šçãªãµã³ãã«ãäœæã§ããŸãã é¡ç»åãã©ã®äººç©ã«å±ãããã決å®ããå¿ èŠãããããããã®äººç©ãæéã®åºå®ã»ããã§ããå Žåããããåé¡ã¿ã¹ã¯ã§ãã
ä»ãããªãã圌ã®é¡ã®åçãã人ã決å®ããã¢ããªã±ãŒã·ã§ã³ãéçºããŠãããããŒã¿ããŒã¹ã«èšæ¶ãããŠããå€ãã®äººã ã絶ããå€åããŠããããšãæ³åããŠãã ãããåœç¶ã䜿çšäžãã¢ããªã±ãŒã·ã§ã³ã¯ãã¬ãŒãã³ã°ã»ããã«ããªã人ãèŠãã§ããã-å®éã®ã¿ã¹ã¯çŸä»£äžçã¯èª°ãé©ããªãã§ãããã ãã ããåé¡ã®åé¡ã§ã¯ãªããªããŸããã 解決æ¹æ³ã¯ïŒ
人ãèªèã§ããããã«ããã«ã¯ãå°ãªããšãäžåºŠã¯äŒãå¿ èŠããããŸãã ããæ£ç¢ºã«ã¯ãå°ãªããšã圌ã®åçã1ææã£ãŠããããç¹å®ã®ç»åã®åœ¢ã§ãããèŠããŠããã ãã®åŸã圌ãããããŸã§ç¥ãããŠããªãæ°ããåçãèŠããããããããã¹ãŠã®èšæ¶ãããç»åãšæ¯èŒããçããåºãããšãã§ããŸãïŒç§ãã¡ã¯ãã§ã«ãã®äººãèŠãŠã圌ãŸãã¯ç§ãã¡ãäŒã£ãããšããªããã®äººãèå¥ã§ãã圌ã ããèŠããããšãã§ããŸãã ãããã£ãŠãäžèšã®åé¡ã¯æ¬¡ã®ããã«ãªããŸãã2æã®åçãæ〠ãããã1人ã«é¢ä¿ãããã©ãããå€æããŸãã èšãæããã°ã圌ãã¯äžäººã«å±ãããšããç¹æ§ãæã£ãŠããŸããïŒ
èå¥åé¡ã®å®çŸ©ã¯æ¬¡ã®ãšããã§ãããã¬ãŒãã³ã°ãµã³ãã«ã«ããïŒäŸã§ã¯ãé¡ã®å€ãã®ã㢠ïŒãã«ãèå¥å ããªããžã§ã¯ãã«å¿ é å±æ§ããããã©ãããå€æã§ããŸãã ããããé¢æ£æ§ã¯éå±ã§ãããµã€ã³ã®é倧床ãç¥ãããšã¯ã¯ããã«èå³æ·±ãã§ã 確çã«çãããªããžã§ã¯ã ã
ãã®äŸã®æåŸã®åé¡ã¯ã arxiv.org ã Python ãããã³Kerasã®å©ããæ±ããããšã§ãããå°ã圢åŒçãã€è±éçã«è§£æ±ºããŸãã é¡åç-ããã®è¡å ã 2人ã®å Žåã1人ã«å±ãã確çãç¥ãããã§ãã 確çã¯0ã1ã®å®æ°ã§ãããããã£ãŠãé¢æ°ãæ¢ããŠããŸãã ã ã€ãŒãã¯æ¢ã«2017幎ã§ãããããæ©æ¢°åŠç¿æ³ã䜿çšããŠæ€çŽ¢ããŸãã ãã ãããã¬ãŒãã³ã°ã»ããã«ã¯ãå®çŸ©ããã®ãã¢ã¯å€ããããŸããããåé¡ã¿ã¹ã¯ã®å Žåãšåãããã«ãã©ãã«ãæã€ããŸããŸãªäººã®é¡ã®åçããããããããŸãã ãããã®ã»ããã¯åçã§ããã2çªç®ã®ã»ããã¯æäœãç°¡åã§ãã
ããŒã³ã¹ãã¬ãã·ãŒ
æ©æ¢°åŠç¿ã®åé¡ã解決ããäžã§æãéèŠãªããšã¯äœã§ããïŒ çããæ¢ãèœåããããšæããŸããïŒ ããããäž»ãªããšã¯ãã®çããæ€èšŒããèœåã§ãã æ©èœ ééããä¹±æ°ãè¿ã ã¯åé¡ã«å¯Ÿããå®å šã«æ£ãã解決çã§ãããå®éã«ã¯åœ¹ã«ç«ããªãã ãç®ã§èŠããæ¹æ³ã«é Œããã«èª¿ã¹ãæ¹æ³ã¯ïŒ åé¡åé¡ã§ã¯ãæ€èšŒã»ããã®æ£ç¢ºããã€ãŸãæ£ããåé¡ãããäŸã®å²åãèŠãããšãã§ããŸãã èå¥ã®åé¡ã«ã€ããŠã¯ããã®ãããªã¡ããªãã¯ã¯é©çšãããŸããã ã§ã¯ãåé¡è§£æ±ºã®é©æ§ã客芳çã«è©äŸ¡ããã«ã¯ã©ãããã°ããã®ã§ããããïŒ
ã¿ãŒã²ããè©Šè¡ãšåœè è©Šè¡ã®æŠå¿µã玹ä»ããŸãããã æåã«ãªããžã§ã¯ããåŒã³åºããŸã ãã®ããã«ç¥ãããŠãã ãã€ãŸã ãªããžã§ã¯ãã«ã¯ã確ç1ã®å¿ é ããããã£ããããŸãïŒãã®åé¡ã§ã¯ã1çµã®é¢ 1人ã«å±ããïŒã2人ç®ã¯ãããããªããžã§ã¯ã ãã®ãã㪠ã ãããã£ãŠãæã ã¯ã»ãããèæ ®ããŸã ãã㊠æ€èšŒã»ããã«ãªããŸãïŒ ã æ©æ¢°åŠç¿ã¿ã¹ã¯ã«é¢ããŠã¯ã圌ã®éžæã®èæ ®äºé ã¯çµ¶å¯Ÿã«æšæºã§ã-ããã¯ä»£è¡šçãªãã®ã§ãªããã°ãªããŸããã å¿ èŠãªãã¹ãŠã®å¯å€æ§ãåæ ããååãªãµã€ãºã§ããã ããšãã°ãé¡èªèã·ã¹ãã ã«ããŸããŸãªç §ææ¡ä»¶ã§ã®äœæ¥ãå«ãŸããå Žåããããã®æ¡ä»¶ã¯æ€èšŒã»ããã§ïŒãã¡ãããã¬ãŒãã³ã°ã»ããã§ãïŒæ瀺ããå¿ èŠããããŸãã
æ§ç¯ãããé¢æ°ãåããŸã ãããŠãã«ã -ç³è«çµæ ãã¹ãŠã®ã¿ãŒã²ããè©Šè¡ã«å¯ŸããŠã ééããå®æ°ã®ã»ãããååŸããŸã ãŸãã¯ã¹ã³ã¢ ã ãããã®å€ã¯ã圌ãããããã ãŸãããšãããããããè¯å®çãªçããæåŸ ããŠããªãå Žåã«ãç§ãã¡ã®ãœãªã¥ãŒã·ã§ã³ãã©ãã ãããŸãæ©èœãããã®å°ºåºŠã§ãã ããã« -代衚ãšã¿ãªããããµã³ãã«ã ãã®çµéšçå¯åºŠ-ãã¹ãã°ã©ã ãæ§ç¯ããŸãããã
圌女ã¯æ¢ããŸã ïŒ
åæããŠããã®ãããªèå¥åã«ã¯ã»ãšãã©æå³ããããŸãã-ååã®å Žåã¯çããæšæž¬ããååã¯ééã£ãŠããŸãã
ãã®ãããªååžã¯ãã§ã«ç§ãã¡ã«é©ããŠããŸãïŒ
ã¿ãŒã²ããã®è©Šã¿ã®å Žåããã®ãããªé¢æ°ã¯ããã§ãªããããæ£ç¢ºã§ããããšããã確å®ã«ããŸãã
ããããè©æ¬ºåž«ãé åžããã«ã¿ãŒã²ããã®é åžãèæ ®ããããšã¯ç¡æå³ã§ãã ãããã«å¯ŸããŠåãæäœãå®è¡ããŸãïŒååžå¯åºŠãæ§ç¯ããŸã åãã°ã©ãã«è¡šç€ºããŸãã åæ§ã®ç»åãåŸãããŸãã
è©æ¬ºçãªè©Šã¿ã®å Žåãã»ãšãã©ã®å Žåãç§ãã¡ã®æ©èœã¯æ£ããçãã«åŸããŠããããšãæããã«ãªããŸãã ãããããããã¯ãŸã èŠèŠçãªèŠ³å¯ã«ãããã 客芳çãªè©äŸ¡ãäžãããã®ã§ã¯ãããŸããã
ã·ã¹ãã ãå ¥åã§ç»åã®ãã¢ãåãåããšä»®å®ããŸãã 圌女ã¯åœŒãã®ããã«ãããæšçã®è©Šã¿ã§ããå¯èœæ§ãèšç®ã§ããŸãã ãããã圌女ã«ã¯æ確ãªçããå¿ èŠã§ããããã¯åã人ç©ã§ãããã©ããã圌ãç§å¯ã®ãªããžã§ã¯ãã«å ¥ãããã©ããã§ãã ãããå€ãèšå®ããŸããã ãã㊠ãåŠå®ã§çããŸãããã以å€ã®å Žåã¯è¯å®ã§çããŸãã ãã ãã·ã¹ãã ã¯èª°ãèªèããã ããã®åŸãä»»æã®2人ãåããšèŠãªãããŸãã ã°ã©ãã¯ãååžãåé¢å¯èœã§ã¯ãªããéžæã§ããªãããšã瀺ããŠããŸã äž¡æ¹ã®ã±ãŒã¹ã§å®ç§ãªããã©ãŒãã³ã¹ãéæããããã«ã ããšãã°ãäžèšã®äŸã§èšå®ããå Žåãã©ããªããŸãã ïŒ
ã¿ãŒã²ããã®è©Šè¡äžã«ã·ã¹ãã ããã¹ãããã±ãŒã¹ã¯ããã€ãããŸããïŒ æ°ããããïŒ -äžæ£ãªè©Šè¡ãšããŠèª€ã£ãŠåé¡ãããã¿ãŒã²ããè©Šè¡ã®æ°ã åŸè ã«ã€ããŠãåæ§ã§ãã 次ã«ãååãä»ããŠã絶察ã§ã¯ãªãçžå¯Ÿçãªååã«ããŸãã
- FRR ïŒFalse Rejection RateïŒ-誀ã£ãŠæåŠãããã¿ãŒã²ããè©Šè¡ã®å²åã
- FAR ïŒFalse Acceptance RateïŒ-äžé©åã«åä¿¡ãããè©æ¬ºã®è©Šã¿ã®å²åã
äžæ©èžã¿åºããŸããã ãããŠãããã«å¯ŸããŠFRRãšFARã®å€ãèšç®ããŸã ééããã®ãã€ã³ã ãããŠãããã1ã€ã®ãã£ãŒãã«è¡šç€ºããŸãïŒ
ããã§ãéžæãããè·é¢ã«ã€ããŠã ã¿ãŒã²ããã®è©Šè¡ã®ã©ã®å²åãæåŠãããã©ã®çšåºŠã®è©æ¬ºã®è©Šè¡ãåãå ¥ããããããèšãããšãã§ããŸãã ãããŠãã®éã«ãããªãã¯éžã¶ããšãã§ããŸã ã¿ã¹ã¯ã«åºã¥ããŠã äŸãã°ãèŠç¥ãã¬äººãéããªãããšãéèŠã§ããä¿è·ããããªããžã§ã¯ãã§ã®æ€èšŒã«ã¯ãæãããªçç±ã§ããããå¿ èŠã§ã å¯èœãªéãäœãFARãæäŸããŸãã ã³ã³ãã¥ãŒã¿ãŒãããªããèªèãããã¯ãããæã¿ãããªãã ããéåžžã¢ããŒããåãå Žåã¯ãäœFRRãšååã«é«ãFARã§åæ¢ã§ããŸããã³ã³ãã¥ãŒã¿ãŒã圌ã«ããªãã®ååãåŒãã§èª°ãã«æšæ¶ããŠãæªãããšã¯èµ·ãããŸããã
ã°ã©ãã®äº€ç¹ã«æ³šæããŠãã ããã ãã®äžã®å€ã¯EER ïŒEqual Error RateïŒãšåŒã°ããŸãã
éžæããå Žå ã FARãšFRRã®å€ã¯çããã§ãã EERã¯ãç§ãã¡ãè¡ã£ãéåžžã«å®¢èŠ³çãªåºæºã§ãã ããã«ãããèå¥ã®åè³ªå šäœãè©äŸ¡ã§ããŸããããã¯ãæ€èšŒã»ããã®å¹³å誀差ã§ãã åºå®FRRã§FARãèŠãããšãã§ãããã®éãå¯èœã§ãããã»ãšãã©ã®å Žåãã¡ããªãã¯ãšããŠäœ¿çšãããã®ã¯EERã§ãã
äžèšã®äŸã§ã¯ã EER = 0.067ã§ãã ããã¯ããã¹ãŠã®æšçã®è©Šã¿ã®å¹³å6.7ïŒ ãæåŠããããã¹ãŠã®åœè ã®è©Šã¿ã®6.7ïŒ ãåãå ¥ããããããšãæå³ããŸãã
ãã1ã€ã®éèŠãªæŠå¿µã¯DETæ²ç·ã§ãã察æ°ã¹ã±ãŒã«ã§ã®FRRã®FRRãžã®äŸåæ§ã§ãã ãã®åœ¢åŒã«ãã£ãŠãã·ã¹ãã å šäœã®å質ãå€æãã1ã€ã®åºæºã®å€ãäžå®ã®ç§ã§ååŸã§ããããšãè©äŸ¡ããæãéèŠãªããšã«ã¯ãã·ã¹ãã ãæ¯èŒããã®ãç°¡åã§ãã
ããã§ã®ERRã¯ã DETæ²ç·ãšçŽç·ã®äº€å·®ç¹ã§ãã ã
Pythonã§ã®çŽ æŽãªå®è£ ïŒ FARãšFRRã次ã®ç¹ã§ã®ã¿å€åãããšèãããšãããæé©ãªå ŽåããããŸã ïŒïŒ
import numpy as np def calc_metrics(targets_scores, imposter_scores): min_score = np.minimum(np.min(targets_scores), np.min(imposter_scores)) max_score = np.maximum(np.max(targets_scores), np.max(imposter_scores)) n_tars = len(targets_scores) n_imps = len(imposter_scores) N = 100 fars = np.zeros((N,)) frrs = np.zeros((N,)) dists = np.zeros((N,)) mink = float('inf') eer = 0 for i, dist in enumerate(np.linspace(min_score, max_score, N)): far = len(np.where(imposter_scores > dist)[0]) / n_imps frr = len(np.where(targets_scores < dist)[0]) / n_tars fars[i] = far frrs[i] = frr dists[i] = dist k = np.abs(far - frr) if k < mink: mink = k eer = (far + frr) / 2 return eer, fars, frrs, dists
ã³ã³ãããŒã«ãèŠã€ããŸããïŒä»ãã©ããªæ©èœã§ã éžæããŠããŸããããæ€èšŒã»ããã§FAR ã FRR ã ERRãèšç®ããèŠèŠçãªã°ã©ããäœæã§ããŸãã
éèŠïŒèå¥ã®åé¡ã§ã¯ãäžèšã®æ€èšŒã»ãããšåŒã°ãããã®ãéçºã»ãã ïŒéçºã»ãããdevsetïŒãšåŒã³ãŸãã å°æ¥ããã®è¡šèšæ³ãé å®ããŸãã
éèŠïŒå®è»žã®éé㯠ã»ã°ã¡ã³ãã«è¡šç€ºã§ããŸã ãé¢æ°ã®å€ããŒããã1ã®ç¯å²ã«ããããšã¯çµ¶å¯Ÿã«å¿ èŠã§ã¯ãããŸããã åäžã®ã»ã°ã¡ã³ãã«è¡šç€ºããªããŠããçµæã«åœ±é¿ãäžããããšãªãå€ã®ç¯å²ãèæ ®ããããšãã§ããŸãã
ããŒã¹æºå
å€ãã®é¡èªèããŒã¿ã»ããããããŸãã äžéšã¯ææã§ãäžéšã¯ãªã¯ãšã¹ãã«å¿ããŠå©çšã§ããŸãã ç §æã«å€§ããªã°ãã€ãããããã®ãããã°ãé¡ã®äœçœ®ã«ãããã®ããããŸãã ããã€ãã¯å®éšå®€ã§æ®åœ±ããããã®ã§ãä»ã¯èªç¶ã®çæ¯å°ã§æ®åœ±ãããåçããç·šéããããã®ã§ãã ããŒã¿èŠä»¶ãæ確ã«å®åŒåãããšãé©åãªããŒã¿ã»ãããç°¡åã«éžæããããè€æ°ã®ããŒã¿ã»ããããçµã¿ç«ãŠããã§ããŸãã ç§ã«ãšã£ãŠããã®æè²ã¿ã¹ã¯ã®ãã¬ãŒã ã¯ãŒã¯å ã§ã®èŠä»¶ã¯æ¬¡ã®ãšããã§ãããããŒã¿ã»ããã¯ããŠã³ããŒãã®ããã«ç°¡åã«ã¢ã¯ã»ã¹ã§ããããŸãå€ãã®ããŒã¿ãå«ãŸããé¡ã®äœçœ®ã«å€åæ§ãå«ãå¿ èŠããããŸãã ç§ã1ã€ã«çµåãã3ã€ã®ããŒã¿ã»ããã¯ãèŠä»¶ãæºãããŸããã
- ã«ã«ããã¯ã®é¡
- FEI FaceããŒã¿ããŒã¹
- ãžã§ãŒãžã¢å·¥ç§å€§åŠã®é¡ããŒã¿ããŒã¹ ã
ãããã¯ãã¹ãŠå€ããªã£ãŠãããé«å質ã®ææ°ã®é¡èªèã·ã¹ãã ãæ§ç¯ããããšã¯ã§ããŸãããããã¬ãŒãã³ã°ã«ã¯çæ³çã§ãã
ãã®ããã«ããŠåŸãããããŒã¿ããŒã¹ã¯ã277人ã®è¢«éšè ãšã4000æã®ç»åã§ããã1人ãããå¹³å14æã®ç»åã§ããã éçºã»ããã®å¯Ÿè±¡ã®5ã10ïŒ ãåããæ®ãã¯ãã¬ãŒãã³ã°ã«äœ¿çšããŸãã ãã¬ãŒãã³ã°äžãã·ã¹ãã ã¯2çªç®ã®ã»ããã®ãµã³ãã«ã®ã¿ã衚瀺ããå¿ èŠããããæåã«ããããã§ãã¯ããŸãïŒ EERãèæ ®ïŒã
ããŒã¿ãå ±æããããã®ã³ãŒãã¯ãã¡ãããå ¥æã§ããŸã ã äžèšã®ã¢ã³ããã¯ãããããŒã¿ã»ãããžã®ãã¹ã瀺ãããšã®ã¿ãå¿ èŠã§ãã
ããã§ãããŒã¿ãååŠçããå¿ èŠããããŸãã ãŸããé¡ããã€ã©ã€ãããŸãã ããã¯èªåã§ã¯è¡ããŸããããdlibã©ã€ãã©ãªã䜿çšããŸãã
import dlib import numpy as np from skimage import io image = io.imread(image_path) detector = dlib.get_frontal_face_detector() face_rects = list(detector(image, 1)) face_rect = face_rects[0]
ã芧ã®ãšããããã®ã©ã€ãã©ãªã䜿çšãããšãæ°è¡ã®ã³ãŒãã§é¡ãå²ãåè§åœ¢ãååŸã§ããŸãã ãŸããdlibæ€åºåšã¯ã OpenCVãšã¯ç°ãªã ãéåžžã«ããŸãæ©èœããŸããããŒã¿ããŒã¹å šäœããããã12人ã®å人ããã圌ã¯æ€åºã§ãããåäžã®èª€æ€åºãäœæããŸããã§ããã
ç§ãã¡ã®ä»äºã®æ£åŒãªå£°æã¯ããã¹ãŠã®äººãåããµã€ãºã§ãªããã°ãªããªãããšãæå³ããŸãã ãã®èŠä»¶ãæºãããåæã«ãã¹ãŠã®é¡ãæããŠãããŒãã€ã³ãïŒç®ã錻ãåïŒãåžžã«ç»åäžã®åãå Žæã«ããããã«ããŸãã éžæãããã¬ãŒãã³ã°æ¹æ³ã«é¢ä¿ãªãããã®ãããªæ段ãç§ãã¡ãå©ãã確ãã«å€§ããªå®³ãäžããªãããšã¯æããã§ãã ã¢ã«ãŽãªãºã ã¯ç°¡åã§ãïŒ
- åäœæ£æ¹åœ¢ã«ã¯ãããŒãã€ã³ãã®å éšçãªäœçœ®ããããŸãã
- éžæããç»åãµã€ãºãç¥ã£ãŠãåçŽãªã¹ã±ãŒãªã³ã°ã«ãã£ãŠç»åäžã®ãããã®ãã€ã³ãã®åº§æšãèšç®ããŸãã
- 次ã®äººã®ããŒãã€ã³ããéžæããŸãã
- 2çªç®ã®ãã€ã³ãã»ãããæåã®ãã€ã³ãã»ããã«ãããã³ã°ããã¢ãã£ã³å€æãäœæããŸãã
- ã¢ãã£ã³å€æãç»åã«é©çšããŠåãåããŸãã
dlibã®äŸïŒface_template.npyã ãã¡ãããããŠã³ããŒãïŒã§ããŒãã€ã³ãã®åç §äœçœ®ãèŠã€ããŸãã
face_template = np.load(face_template_path)
é¡ç»åäžã®ããŒãã€ã³ããæ€çŽ¢ããã«ã¯ãäŸïŒshape_predictor_68_face_landmarks.datã ãã¡ãããããŠã³ããŒãïŒã§èŠã€ããããšãã§ããæ¢ã«èšç·Žãããã¢ãã«ã䜿çšããŠãdlibãå床䜿çšããŸãã
predictor = dlib.shape_predictor(dlib_predictor_path) points = predictor(image, face_rect) landmarks = np.array(list(map(lambda p: [px, py], points.parts())))
ã¢ãã£ã³å€æã¯ã3ã€ã®ãã€ã³ãã«ãã£ãŠäžæã«å®çŸ©ãããŸãã
INNER_EYES_AND_BOTTOM_LIP = [39, 42, 57]
ããã -ç§ãã¡ã翻蚳ãããåºçºç¹ ã 次ã«ãè¡åã§è¡šãããã¢ãã£ã³å€æ é¢ä¿ããèŠã€ããããšãã§ããŸã
ãããèŠã€ããïŒ
proper_landmarks = 227 * face_template[INNER_EYES_AND_BOTTOM_LIP] current_landmarks = landmarks[INNER_EYES_AND_BOTTOM_LIP] A = np.hstack([current_landmarks, np.ones((3, 1))]).astype(np.float64) B = np.hstack([proper_landmarks, np.ones((3, 1))]).astype(np.float64) T = np.linalg.solve(A, B).T
ãããŠãscipy-imageã©ã€ãã©ãªã䜿çšããŠç»åã«é©çšããŸãã
import skimage.transform as tr wrapped = tr.warp( image, tr.AffineTransform(T).inverse, output_shape=(227, 227), order=3, mode='constant', cval=0, clip=True, preserve_range=True ) wrapped /= 255.0
䟿å©ãªAPIã«ã©ãããããå®å šãªååŠçã³ãŒãã¯ã preprocessing.pyãã¡ã€ã«ã«ãããŸãã
ããŒã¿æºåã®æåŸã®ã³ãŒãã¯æ£èŠåã§ãããã¬ãŒãã³ã°ããŒã¹ã«åŸã£ãŠå¹³åãšæšæºåå·®ãèšç®ãããããã®åç»åãæ£èŠåããŸãã éçºã»ããã«ã€ããŠå¿ããªãã§ãã ããã ãã¡ãã®ã³ãŒããã芧ãã ãã ã
åéãåå²ãæŽåãããã³æ£èŠåãããããŒã¿ã¯ã ããããããŠã³ããŒãã§ããŸã ã
ããŒã³ã¢ã«ãã£ã¡ã€ã¿ã
ããŒã¿ãèŠã€ããæºåãããã®ã§ããã¹ãæ¹æ³ãæŽçããŸããã æŠãã®ååãçµãã£ããæ®ã£ãŠããæãç°¡åãªããšã¯èŠã€ããããšã§ã è¯ãEERã§åé¡ã解決ããŸãã EER = 10ïŒ ããã®ãããªãã¬ãŒãã³ã°ã¿ã¹ã¯ã«éåžžã«é©ããŠãããšããã«å€æããŸãããã å®éããã®ãããªã·ã¹ãã ã¯ã2ã€ã®åçã§åäžã®é¡ãæ€çŽ¢ãããªã©ã®åçŽãªã¢ããªã±ãŒã·ã§ã³ã§ã䜿çšã§ããŸãã
ã³ã€ã³
æªãæ©èœã®ãŸãã«ãã®äŸããæ€çŽ¢ãå§ããŸããã ã éçºã»ããããã®åçã®ãã¢ããšã«ãã©ã³ãã ãªå€ãååŸãããããã«DETæ²ç·ãäœæããŠEERãèŠã€ããŸãã
EER = 49.5ïŒ ã®å Žåããã®ãããªèå¥åã¯ãå決å®ã§æããã³ã€ã³ãããåªããŠããŸããã ãã¡ãããããã¯ã°ã©ãããªããŠãç解ã§ããŸãããç§ãã¡ã®ç®æšã¯ãèå¥åé¡ã解決ããæ¹æ³ãåŠç¿ããæããã«æªãå€æã§ãã£ãŠãã決å®ã客芳çã«è©äŸ¡ã§ããããã«ããããšã§ãã ããã«ãããã·ã¥ãããã®ããããŸãã
è·é¢
ããã®2ã€ã®ãã¯ãã«ã®æ©èœã¯äœã§ãã å®æ°ãè¿ãããšãæåã«æãæµ®ãã³ãŸããïŒ ã»ãšãã©ã®äººããã®è³ªåã«çãããšç¢ºä¿¡ããŠããŸããè·é¢ã§ãã 確ãã« ã¡ããªãã¯ç©ºéã§ããããã¯ãä»»æã®2ã€ã®èŠçŽ ãæå³ããŸã ãã㊠è·é¢ã¯ãããã決å®ãããŸã ããŸããŸãªæ¹æ³ã§å ¥åã§ããŸãã ããããè·é¢ã¯ãŒããããã©ã¹ã®ç¡éãŸã§å€åããããããã€ãã¹ã§èæ ®ããå¿ èŠããããæ¡çšãã圢åŒåã§ã¯ããã®éãåæ§ã§ãã
ããšãã°ãäœåŒŠè·é¢ãèããŸãã
ãããŠãéçºã»ããã§åãæäœããã¹ãŠè¡ããŸãã
dev_x = np.load('data/dev_x.npy') protocol = np.load('data/dev_protocol.npy') dev_x = dev_x.mean(axis=3).reshape(dev_x.shape[0], -1) dev_x /= np.linalg.norm(dev_x, axis=1)[:, np.newaxis] scores = dev_x @ dev_x.T tsc, isc = scores[protocol], scores[np.logical_not(protocol)] eer, fars, frrs, dists = calc_metrics(tsc, isc)
ãã®ãããªDETæ²ç·ãåŸãããŸãã
EERã¯16ïŒ æžå°ãã34.18ïŒ ã«ãªããŸããã ããè¯ããããŸã é©çšãããªãã ãã¡ããããã¬ãŒãã³ã°ã»ãããšæ©æ¢°åŠç¿ã¡ãœããã䜿çšããã«ãé¢æ°ã®ã¿ãéžæããããã§ãã ãã ããè·é¢ã®æŠå¿µã¯å ç¢ã§ãããã®ãŸãŸã«ããŠãæ©èœã玹ä»ããŸãããã 圢ã§
ã©ã㧠-ã³ãµã€ã³è·é¢ãããã³ embedderãšåŒã¶é¢æ°ãšããã®äœæ¥ã®çµæãå®å®ãã - åã蟌㿠ã 圌女ã¯ããã¬ãŒãã³ã°ã»ããããåŸãããäºåŸã®çµéšãèæ ®ããŠãå¥ã®ïŒå¿ ãããå°ãããšã¯éããªãïŒæ¬¡å ã®ããã€ãã®ã¹ããŒã¹ã«ç»åããåã蟌ã¿ããŸãã
CNN
ããŠãããªããšç§ã¯ã¿ã¹ã¯ãããã«åçŽåããŸããã è¯ãæ©èœãèŠã€ããã ãã§ã ãã·ã¹ãã ã®ä»ã®ãã¹ãŠã®éšåã¯ãã§ã«é 眮ãããŠããŸãã èã¿ã«åã¡ãŸããã-çŸæç¹ã§ã¯ãCNNïŒConvolutional Neural NetworksïŒãããåªããç»åãåŠçã§ããã¢ãã«ã¯ååšããªãããšãããã£ãŠããŸãã 次ã®ããã«ãããã»ã©è€éã§ã¯ãªãã¢ãŒããã¯ãã£ã®ç³ã¿èŸŒã¿ãããã¯ãŒã¯ãæ§ç¯ããŸãããã
ã±ã©ã¹ã®ã¢ãã«
from keras.layers import Flatten, Dense, Dropout from keras.layers.convolutional import Convolution2D, MaxPooling2D from keras.layers.advanced_activations import PReLU from keras.models import Sequential model = Sequential() model.add(Convolution2D(96, 11, 11, subsample=(4, 4), input_shape=(dim, dim, 3), init='glorot_uniform', border_mode='same')) model.add(PReLU()) model.add(MaxPooling2D((3, 3), strides=(2, 2))) model.add(Convolution2D(256, 5, 5, subsample=(1, 1), init='glorot_uniform', border_mode='same')) model.add(PReLU()) model.add(MaxPooling2D((3, 3), strides=(2, 2))) model.add(Convolution2D(384, 3, 3, subsample=(1, 1), init='glorot_uniform', border_mode='same')) model.add(PReLU()) model.add(Convolution2D(384, 3, 3, subsample=(1, 1), init='glorot_uniform', border_mode='same')) model.add(PReLU()) model.add(Convolution2D(256, 3, 3, subsample=(1, 1), init='glorot_uniform', border_mode='same')) model.add(PReLU()) model.add(MaxPooling2D((3, 3), strides=(2, 2))) model.add(Flatten()) model.add(Dropout(0.5)) model.add(Dense(2048, init='glorot_uniform')) model.add(PReLU()) model.add(Dropout(0.5)) model.add(Dense(256, init='glorot_uniform')) model.add(PReLU()) model.add(Dense(n_classes, init='glorot_uniform', activation='softmax')) model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
ãããŠããã¬ãŒãã³ã°ã»ããã®å€å žçãªåé¡ã®åé¡ã解決ããããšã圌女ã«æããŸãã250人ã®è¢«éšè ã®ã©ããé¡åçãææããŠããããå€æããŸãã äžèšã®ã³ãŒãã«å ããŠã誰ããã±ã©ã§ãã®ãããªç°¡åãªã¿ã¹ã¯ã解決ã§ããŸãããŸãã5ã6è¡ç®ãå¿ èŠã§ãã ãã®èšäºã§èª¬æãããã¬ãŒãã³ã°ããŒã¹ã«ã¯ã æ¡åŒµãé©çšããããšãäžå¯æ¬ ã§ããããããªããšãããŒã¿ãååãªçµæãåŸãããšãã§ããŸããã
ããªãã¯ãåé¡ã¿ã¹ã¯ããããšäœã®é¢ä¿ãããã®ãââããããŠãã®è§£æ±ºçã¯ã©ã®ããã«ç§ãã¡ãå©ããã®ã§ããããïŒ æ£ããããïŒ ä»¥äžã§èª¬æããã¢ã¯ã·ã§ã³ãç解ããããã«ã¯ãéåžžã«éèŠãªä»®å®ãç«ãŠãå¿ èŠããããŸã ïŒ ãããã¯ãŒã¯ãéããéåã®åé¡åé¡ãããŸã解決ããããšãåŠç¿ããå Žåã次å 256ã®æåŸãã2çªç®ã®ã¬ã€ã€ãŒã«ã察象ããã¬ãŒãã³ã°ã»ããã«å«ãŸããŠããªããŠããé¡ç»åã«é¢ãããã¹ãŠã®éèŠãªæ å ±ãéäžããŸãã
èšç·Žããããããã¯ãŒã¯ã®æåŸã®å±€ããäœæ¬¡å ã®ç¹åŸŽãæœåºãããã®ææ³ã¯åºãæ®åããŠããã ããã«ããã¯ãšåŒã°ããŠããŸãã ã¡ãªã¿ã«ãkerasã®ããã«ããã¯ãåŠçããããã®ã³ãŒãã¯ãã¡ãã«ãããŸã ã
ãããã¯ãŒã¯ã¯ãã¬ãŒãã³ã°ããã256次å ã®å±æ§ãéçºã»ããããæœåºãããŸããã DETæ²ç·ãèŠãŠã¿ãŸãããã
ä»®å®ã¯çå®ã§ããããšãå€æãã EERãããã«13ïŒ æžå°ããçµæã¯21.6ïŒ ã«éããŸããã ã³ã€ã³ãæããããã2åè¯ãã ããã¯ããã«è¯ãã§ããïŒ ãã¡ããããã倧ããããå€æ§ãªããŒã¹ãæ§ç¯ããããæ·±ãCNNãæ§ç¯ããããŸããŸãªæ£ååææ³ãé©çšã§ããŸã...ããããé«å質ã®æŠå¿µçã¢ãããŒããæ€èšããŠããŸãã ãããŠãéã¯ãã€ã§ãå¢ããããšãã§ããŸãã è¢ã«ã¯ãŸã ãã1ã€ã®åãæããããŸãããããŒãã«ã«çœ®ãåã«å°ãæ°ãæ£ãããªããã°ãªããŸããã
ããŒã³ãšããªã¥ãŒã·ã§ã³
çµæãæ¹åããéµã¯ãæé©åã®å®çŸã«ãããŸã ãã¬ãŒãã³ã°ã»ããã®æ å ±ã ãã§ãªããæ©èœã«é¢ããæ å ±ã䜿çšã§ããŸãã ã 確ãã«ãä¿®æ£ããŸããã ãããŠç§ãã¡ã¯èšç·ŽããŸã åã蟌ã¿ã䜿çšããŠã¹ã³ã¢ãååŸããæ¹æ³ã«é¢ããå éšçãªç¥èã«åºã¥ããŠããŸãã FaceNetã® Googleã®äººã ã«ãã£ãŠããã®ãããªã¢ãããŒããåããŠææ¡ãããŸããïŒé¡èªèãšã¯ã©ã¹ã¿ãªã³ã°ã®ããã®çµ±åãããåã蟌㿠ã
圌ããææ¡ããã¢ãããŒãã¯TDE ïŒTriplet Distance EmbeddingïŒãšåŒã°ãã以äžããæ§æãããŠããŸããã ãœãŒã¹ã¹ããŒã¹ããã®ãããã¯ãŒã¯ã®ãã㪠åã蟌ã¿ã¹ããŒã¹ãž äžéåé¡åé¡ã解決ããå¿ èŠãªããä¿®æ£ããŸã ãŠãŒã¯ãªããè·é¢ãšããŠã æ倱é¢æ°ã§èæ ®ã«å ¥ããŸãã ã©ããã£ãŠïŒ ããã¯éåžžã«çŽæçã§ãã1ã€ã®è¢«éšè ã®ãã¯ãã«ããã¿ãŒã²ãã空éã«ã§ããã ãè¿ã¥ããä»ã®è¢«éšè ã®ãã¯ãã«ããé ãããããã«ããŸãã
ããªãã«ã䜿çšããŠãã®ãããªãããã¯ãŒã¯ãæããããšãææ¡ãããŸããã ã©ã㧠ïŒã¢ã³ã«ãŒïŒããã³ ïŒããžãã£ãïŒ1ã€ã®ãšã³ãã£ãã£ã«å±ããã〠ïŒè² ïŒå¥ã«ã 3ã€ã®ãã¯ãã«ãã¹ãŠã«ã€ããŠã åã蟌ã¿ãæ§ç¯ããŸã ã ãã㊠ã äºåã«ãã©ã¡ãŒã¿ãŒãå°ããŸã ã é¢ä¿ã次ã®å Žåãããªãã«ã¯è¯ããšä»®å®ããŸãã
ã€ãŸããç¹å®ã®ã¢ã³ã«ãŒã«ã€ããŠãããžãã£ããšãã¬ãã£ããååšãããšãªã¢éã«ã®ã£ãããããããšãæå³ããŸã ã ãã®æ¯çããã¬ãŒãã³ã°ã»ããããã®ãã¹ãŠã®ããªãã«ã«ã€ããŠæãç«ã€å ŽåãããŒã¿ãçæ³çã«åå²ããŸããã ãããŠããã®äžçåŒã«éåããŠããããªãã«ã§ã®ã¿ãããã¯ãŒã¯ããã¬ãŒãã³ã°ããããšã¯çã«ããªã£ãŠããŸãã äžçåŒã«åºã¥ããŠããããã¯ãŒã¯ã®æ倱é¢æ°ãæ§ç¯ã§ããŸã ïŒ
ãã®ã¢ãããŒãã䜿çšããŠãèè ã¯WildãšYouTube Faces DB ããŒã¿ã»ããã®Labeled Facesã®ãšã©ãŒã30ïŒ åæžããŸãããããã¯ééããªãéåžžã«ã¯ãŒã«ã§ãã ãã ãããã®ã¢ãããŒãã«ã¯åé¡ããããŸãã
- å€ãã®ããŒã¿ãå¿ èŠã§ãã
- é ãåŠç¿
- ãªãã·ã§ã³ãã©ã¡ãŒã¿ éžææ¹æ³ã¯æ確ã§ã¯ãããŸããã
- å€ãã®å ŽåïŒäž»ã«å°éã®ããŒã¿ã§ïŒã softmax + bottleneckãããåäœãæªããªããŸãã
ããã«ãã·ãŒã³TPE ïŒTriplet確ççåã蟌ã¿ïŒããããŸããããã¯ãé¡æ€èšŒãšã¯ã©ã¹ã¿ãªã³ã°ã®ããã®ããªãã¬ãã確ççåã蟌ã¿ã§èª¬æãããŠããŸãã
è¿œå ã®ãã©ã¡ãŒã¿ãŒãå ¥åããçç± ãã€ããåçŽãªäžå¹³çãèŠæ±ã§ããã®ã§ããããïŒ ããã«ãããŸãïŒ
ããã¯ãªãªãžãã«ãããç°¡åã§è§£éããããã§ããç§ãã¡ã«æãè¿ãè² ã®äŸã¯ãç§ãã¡ããæãé ãæ£ã®äŸãããé ãã«ããããšãæã¿ãŸããããããã®éã«ã®ã£ããããã£ãŠã¯ãªããŸããã è·é¢ãé¢ããŠããããã¯ãŒã¯ã®æŽæ°ãåæ¢ããªããšããäºå®ã®ãã åã蟌ã¿ã®ã°ã«ãŒãã¯ç©ºéçã«ééã空ããããšãã§ããŸã ããã«è¯ãã
ããªãã¬ãããæå®ãããäžçåŒãæºãã確çãèšç®ã§ããŸãã
ã§å²ã£ã ïŒ
確çã®å¯Ÿæ°ãæ倧åãããããæ倱é¢æ°ã¯æ¬¡ã®ããã«ãªããŸãã
ãããŠæ©èœãšã㊠èè ã¯ã巚倧ãªCNNã§ã¯ãªããåçŽãªãããªãã¯ã¹ã®äœ¿çšãææ¡ããŠããŸãã æ¢ã«åãåã£ãããã«ããã¯ã®å åã«ã€ããŠåœŒå¥³ã«æããŸãã èè ãéæããçµæã¯æ¬¡ã®ãšããã§ãã
ã芧ã®ãšããããã®ã¢ãããŒãã¯å ã®ã¢ãããŒããããããŸãæ©èœããå€ãã®å©ç¹ããããŸãã
- å¿ èŠãªããŒã¿ãå°ãªãã
- éåžžã«éãåŠç¿ããŸãã
- æ·±ãããã¢ãŒããã¯ãã£ã¯å¿ èŠãããŸããã
- æ¢åã®ãã¬ãŒãã³ã°æžã¿ã¢ãŒããã¯ãã£ã®äžã§äœ¿çšã§ããŸãã
ãã®ã¢ãããŒãã䜿çšããŠããŸãã ãã®ããã«å¿ èŠãªã³ãŒãã¯20è¡ã ãã§ãã
def triplet_loss(y_true, y_pred): return -K.mean(K.log(K.sigmoid(y_pred))) def triplet_merge(inputs): a, p, n = inputs return K.sum(a * (p - n), axis=1) def triplet_merge_shape(input_shapes): return (input_shapes[0][0], 1) a = Input(shape=(n_in,)) p = Input(shape=(n_in,)) n = Input(shape=(n_in,)) base_model = Sequential() base_model.add(Dense(n_out, input_dim=n_in, bias=False, weights=[W_pca], activation='linear')) base_model.add(Lambda(lambda x: K.l2_normalize(x, axis=1))) a_emb = base_model(a) p_emb = base_model(p) n_emb = base_model(n) e = merge([a_emb, p_emb, n_emb], mode=triplet_merge, output_shape=triplet_merge_shape) model = Model(input=[a, p, n], output=e) predict = Model(input=a, output=a_emb) model.compile(loss=triplet_loss, optimizer='rmsprop')
ãããžã§ã¯ãã§TPEã䜿çšãããå Žåã¯ãããªãã¬ããã䜿çšãããã¬ãŒãã³ã°ã®æãéèŠãªåé¡ïŒãã®éžæã®åé¡ïŒãåãäžããªãã£ããããå ã®äœåãèªãã®ãé¢åã§ã¯ãããŸããã å°ããªã¿ã¹ã¯ã§ã¯ãã©ã³ãã éžæã§ååã§ãããããã¯ã«ãŒã«ãšããããã¯äŸå€ã§ãã
ããã«ããã¯ã«ã€ããŠTPEããã¬ãŒãã³ã°ããä»æ¥ã®æåŸã®DETæ²ç·ãèŠãŠã¿ãŸãããã
12ïŒ ã®EERã¯ãç§ãã¡ãæãã§ãããã®ã«éåžžã«è¿ããã®ã§ãã ããã¯ãCNNã䜿çšããããã2åãã©ã³ãã éžæããã5ååªããŠããŸãã ãã¡ãããããæ·±ãã¢ãŒããã¯ãã£ãšãã倧ããªããŒã¹ã䜿çšããŠçµæãæ¹åã§ããŸããããã®ãããªçµæã¯ååãç解ããã®ã«ååã§ãã
èæ ®ãããŠãããã¹ãŠã®ã¡ãœããã®DET-æ²ç·ã®æ¯èŒïŒ
WebããŒã¹ã®ã€ã³ã¿ãŒãã§ãŒã¹ã§ããããšQtã¢ããªã±ãŒã·ã§ã³ã§ããããšãããããçš®é¡ã®ãšã³ãžãã¢ãªã³ã°ãšã·ã¹ãã ãžã®ã€ã³ã¿ãŒãã§ãŒã¹ãåºå®ããåçã§åäžã®é¡ãæ€çŽ¢ããããã®ããã°ã©ã ãçšæãããŠããŸãã
ãã®ã¢ããªã¯GitHubã§å ¥æã§ããŸã ã
èªãã§ãããŠããããšãïŒ åæ§ã«ããããã£ãŒã«ã賌èªããã³ã¡ã³ããæ®ããè»ãäžæã«æããŠãã ããã è¿œå ã¯å€§æè¿ã§ãã