ãã£ãŒãã©ãŒãã³ã°å®è·µå ¥é ïœ Kerasã©ã€ãã©ãªã§ç»åèªèãã¯ããããïŒ
ãã£ãŒãã©ãŒãã³ã°ïŒæ·±å±€åŠç¿ïŒã«èå³ãããã©ããªããªãæéããªããŠããšããæ¹ã®ããã«ãã³ãŒããåãããªãããããã£ãšè©ŠããŠæè§Šãã€ããã§ããããããã«ã解説ããŸãã
ã¯ãããŸããŠãå®®æ¬åªäžãšç³ããŸãã
æè¿ãªã«ããšè©±é¡ã®å€ããã£ãŒãã©ãŒãã³ã°ïŒæ·±å±€åŠç¿ãdeep learningïŒããšã³ãžãã¢Hubã®èªè ã®æ¹ã§ããèå³ãã人ã¯å€ãã®ã§ã¯ãªãã§ããããã
ãããããã£ãŒãã©ãŒãã³ã°ã«ã€ããŠåšãã®ãšã³ãžãã¢ã«èããŠã¿ããšã
ããªããé£ãããã
ããªããªãæéããªããŠãã©ãããå§ããã°è¯ãããåãããªãã
ãäžå詊ããŠã¿ããã ãã©ãåå¿è
åããã¥ãŒããªã¢ã«ïŒMNISTãªã©ïŒãåãããŠæ«æãã¡ãã£ããã ããã
ãšãã声ãèãããŠããŸãã
ããã§ïŒ ãã®èšäºã§ã¯ãããããæ¹ã察象ã«ããã£ãŒãã©ãŒãã³ã°ãããã£ãšè©ŠããŠæè§Šãã€ããã§ãããããããã³ãŒããåãããªãã解説ããããšæããŸãïŒãã®ããæ°åŒãªã©ã®å³å¯ãªè§£èª¬ã¯çãããŠããã ããŸãïŒã
æåŸãŸã§è©ŠããŠããã ãããšãèªåã§çšæããããŒã¿ã»ããã§ç»åèªèãã§ããããã«ãªã£ãŠããã¯ãïŒ ã§ãã
- ã¯ããã« â ç§ããã£ãŒãã©ãŒãã³ã°ã§éçºãããé¡èªèãã·ã¹ãã
- ãã£ãŒãã©ãŒãã³ã°ãšã¯äœãïŒ
- ãã£ãŒãã©ãŒãã³ã°ã®æŽå²
- ãã£ãŒãã©ãŒãã³ã°ã䜿ãããåé
- ãã£ãŒãã©ãŒãã³ã°ã©ã€ãã©ãªãKerasããåãããŠã¿ãã
-
1. AWSã§ãã£ãŒãã©ãŒãã³ã°çšã®ã€ã³ã¹ã¿ã³ã¹ãçšæãã
- AWSã®ã¢ã«ãŠã³ããäœæããŠã³ã³ãœãŒã«ã«ãµã€ã³ã€ã³
- å ¬åŒã®ãã£ãŒãã©ãŒãã³ã°çšAMIã§ã€ã³ã¹ã¿ã³ã¹ãéžæ
- ãšãã£ã¿ã䜿çšããã»ãã¥ãªãã£ã«ãŒã«ã®è¿œå
- ã€ã³ã¹ã¿ã³ã¹ã®èµ·åãšæ¥ç¶
- Pythonã®åäœç¢ºèª
- Kerasã®ã¢ããããŒã
- Jupyter Notebookã®èšå®ãšèµ·å
- 2. Kerasã§MNISTã®ææžãæ°åãèªèãããŠã¿ãã
- 3. Inception v3ã¢ãã«ãçšããç»åèªè
- ãŸãšããšåèæç®
ã¯ããã« â ç§ããã£ãŒãã©ãŒãã³ã°ã§éçºãããé¡èªèãã·ã¹ãã
æåã«å°ãã ãèªå·±ç޹ä»ããããŠãã ãããç§ã¯ãæ°åã§ããžã¿ã«ã«ã¡ã©ãªã©ãäœã£ãŠããäŒç€Ÿã«å ¥ç€Ÿããç ç©¶éçºéšéã§ç»ååŠçãæ©æ¢°åŠç¿ã®ã¢ã«ãŽãªãºã éçºãè¡ã£ãŠããŸããã
5幎åã»ã©å€ããåŸã«è»¢è·ããçŸåšã¯PARTYãšããäŒç€Ÿã§ãªãµãŒããšã³ãžãã¢ãšããŠåããŠããŸããPARTYã¯ãææ°ãã¯ãããžãŒãšã¹ããŒãªãŒããŒãªã³ã°ãèåããæªæ¥ã®äœéšããã¶ã€ã³ããäŒç€Ÿããã¹ããŒã¬ã³ã«ãããŸããŸãªãããžã§ã¯ãã«åãçµãã§ããŸãã
ãããªç§ãå ¥ç€ŸããŠäœã£ãã®ããDeeplooksãšãããµãŒãã¹ã§ããããã¯ãé¡åçãã¢ããããŒããããšããã®é¡ã®ãçŸãããã5ç¹æºç¹ã§ç¹æ°ä»ãããŠããããšãããã®ã§ãïŒãžã§ãŒã¯ãšããŠæ¥œããã§ããã ãããšå¹žãã§ãïŒã
æ°äžæã®ç»åã«å¯ŸããŠäººéãç¹æ°ä»ãããããŒã¿ãããã£ãŒãã©ãŒãã³ã°ãçšããŠåŠç¿ããçµæãã5ç¹ã®é¡ããšã2ç¹ã®é¡ãã®éããã³ã³ãã¥ãŒã¿ãèªèããŠãç¹æ°ä»ãã§ããããã«ãªããŸããã
çŸåšã¯ããã®ã·ã¹ãã ãé¡ä»¥å€ã«ãå¿çšãããæ°ããèªèã·ã¹ãã ãéçºäžã§ãã
ãã£ãŒãã©ãŒãã³ã°ãšã¯äœãïŒ
æåã«ããã£ãŒãã©ãŒãã³ã°ãšã¯ã©ããªãã®ããç°¡åã«èª¬æããŠãããããšæããŸããåãã£ãŠããæ¹ã¯ãå ã®ããã£ãŒãã©ãŒãã³ã°ã©ã€ãã©ãªãKerasããåãããŠã¿ããããŸã§èªã¿é£ã°ããŠããã ããŠãåé¡ãããŸããã
AIïŒäººå·¥ç¥èœïŒã»æ©æ¢°åŠç¿ã»ãã£ãŒãã©ãŒãã³ã°ïŒæ·±å±€åŠç¿ïŒã®éã
ãã¥ãŒã¹ãªã©ã§ã人工ç¥èœãããæ·±å±€åŠç¿ããšãã£ãèšèãèãæ©äŒãå¢ããŠããŸããããããããã¡ããŸãã«èªãããããšãå€ããããããæå³ãããã®ã®éããåããã«ãããšæããæ¹ããããããããŸããã
ããããã®èšèã®éãã«ã€ããŠã¯ãããããã©ãçºå±ããŠãããã解説ããNVIDIA瀟ã®ããã°èšäºãåèã«ãªããŸãã
ç°¡åã«èª¬æãããšã以äžã®ããã«ãªããŸãã
- AIïŒäººå·¥ç¥èœãartificial intelligenceïŒ
- ããŸããŸãªã¿ã¹ã¯ã«å¯ŸããŠã人éãšåç以äžã®èªè粟床ãæã¡ãèããããšã®ã§ããæ©æ¢°
- æ©æ¢°åŠç¿
- ããŒã¿ãè§£æããŠãç¹åŸŽãæœåºããããŒã¿éã®é¢ä¿ãåŠç¿ããããã®çµæãããæ°ããããŒã¿ã«å¯ŸããŠäºæž¬ãè¡ããæ±ºå®æšãSVMãªã©ããŸããŸãªææ³ããã
- ãã£ãŒãã©ãŒãã³ã°
- æ©æ¢°åŠç¿ã®ææ³ã®äžã€ããã¥ãŒã©ã«ãããã¯ãŒã¯ãå€å±€ã«æ¥ç¶ããããŸããŸãªå·¥å€«ã倧éã®ããŒã¿ãé«éã«èšç®ãå®è¡ã§ããGPUã«ãã£ãŠãèªèæ§èœãåäžãã
æè¿ã¯ã人éã®èªèã»åé¡èœåãã¯ããã«è¶ ãããã£ãŒãã©ãŒãã³ã°ææ³ãåºãŠããŸãããMicrosoftãGoogleã®ã¢ã«ãŽãªãºã ã«ããç»åèªèããæšå¹Žå²ç¢ã§äžçãããã¯ã©ã¹ã®æ£å£«ã«åã£ãAlphaGoãªã©ã¯æåãªãšããã§ãã
ãããããããã®ã¢ã«ãŽãªãºã ã¯ããããã®ã¿ã¹ã¯ã«æé©åãããŠããŠãä»ã®ã¿ã¹ã¯ãè§£ãããšã¯ã§ããªããããçã®äººå·¥ç¥èœãå®çŸãããšã¯èšããŸããããã ãä»ãŸã§ã«ãªã人工ç¥èœã®å®çŸã«è¿ã¥ããŠãããšãããã§ãããã
ãã£ãŒãã©ãŒãã³ã°ã«ã¯é«æ©èœãªGPUãäžå¯æ¬
æ©æ¢°åŠç¿ãšãã£ãŒãã©ãŒãã³ã°ã§å€§ããç°ãªãç¹ã¯ãéçºã«å¿ èŠãªç°å¢ã§ãããã£ãŒãã©ãŒãã³ã°ã§ã¯ãåŠç¿ã®éã«GPUãçšããŠãŽãªãŽãªãšèšç®ããããšãäžå¯æ¬ ã«ãªã£ãŠããããã髿©èœãªGPUãåããç°å¢ãæºåã§ãããã©ãããããã¯ã«ãªããŸãã
ããŸããŸãªãã£ãŒãã©ãŒãã³ã°ã®ã©ã€ãã©ãªã察å¿ããŠããã®ã¯ãNVIDIA瀟ã®GPUã§ããå¿ èŠãªã¹ããã¯ã¯ããããã¿ã¹ã¯ã«å¿ããŠæ±ºãŸãã®ã§ãããç»åèªèã§ããã°ããçšåºŠã®é«ã¹ããã¯ãªGPUãèŠæ±ãããŸããæ¬çš¿å·çæç¹ã§ã®æäœã©ã€ã³ã¯GeForce GTX 1060ã§ãGeForce GTX 1080 TiãTITAN Xãããã°å®å¿ã§ãã
æè¿ã§ã¯ãGPUãå©çšã§ããã¯ã©ãŠãã³ã³ãã¥ãŒãã£ã³ã°ç°å¢ããAmazonãGoogleãMicrosoftããããã€ã³ã¿ãŒããããªã©ã§æäŸãããŠãããããããªã詊ãããããªã£ãŠããŸããæ¬çš¿ã§ããAmazonã®ã¯ã©ãŠãç°å¢ãå©çšããŠããã£ãŒãã©ãŒãã³ã°ã詊ããŠã¿ãŸãã
ãã£ãŒãã©ãŒãã³ã°ãšãã®ä»ã®æ©æ¢°åŠç¿ææ³ã®äœ¿ãåãããç°å¢èŠå 以å€ã§ç·åŒãããããšã¯é£ããã§ããããã¿ã¹ã¯ã«ãã£ãŠã¯ãä»ãŸã§ã®ææ³ã®æ¹è¯ã§ãææ°ã®ãã£ãŒãã©ãŒãã³ã°ææ³ãè¶ ããããšããããŸãã
人éãç°¡åããã«æããã¿ã¹ã¯ã§ãæ©æ¢°ã«ã¯é£ããã£ãããéã«äººéã¯é£ãããšæããããšãæå€ã𿩿¢°ã¯ç°¡åã«ã§ãããããã®ã§ãç¥èãçµéšãè±å¯ãªæ©æ¢°åŠç¿ãšã³ãžãã¢ã«èãã®ãäžçªã ã£ããããŸãâŠâŠã
ãã£ãŒãã©ãŒãã³ã°ã®æŽå²
ãã£ãŒãã©ãŒãã³ã°ã¯ãã©ã®ããã«çºå±ããã®ã§ããããïŒ
ãã¥ãŒã©ã«ãããã¯ãŒã¯ãšAIããŒã
ãã£ãŒãã©ãŒãã³ã°ã®å ã«ãªã£ãã®ã¯ãã¥ãŒã©ã«ãããã¯ãŒã¯ïŒneural networkïŒã§ããããã®ããã«å ã®å ã®å ãšãªã£ãã¢ã«ãŽãªãºã ã§ãã圢åŒãã¥ãŒãã³ïŒformal neuronïŒã¯ã1943幎ã«çºè¡šãããŸãããäžçæåã®ã³ã³ãã¥ãŒã¿ãšããããENIACãéçºãããã®ã1946幎ã人工ç¥èœãšããèšèãçãŸããã®ã¯1956幎ãšèšãããŠããŸããããããªãé·ãæŽå²ããããŸãã
ãã®åŸã1960幎代ã«ãããŠç¬¬äžæ¬¡AIããŒã ãèµ·ããŸããããããåœæã®æè¡ã§ã¯ç°¡åãªåé¡ããè§£ããªãããšãåããã1970幎代ã¯AIã«ãšã£ãŠå¬ã®æä»£ã蚪ããŸãã
1980幎代ã«å ¥ããšãããŸããŸãªç¥èãããšã«æé©ãªçããå°ããšãã¹ããŒãã·ã¹ãã ãææ¡ããããªã©ãåã³AIã»æ©æ¢°åŠç¿ããŒã ïŒç¬¬äºæ¬¡AIããŒã ïŒãèµ·ããŸãããã¥ãŒã©ã«ãããã¯ãŒã¯ã«è€æ°ã®å±€ãéããã°ãããŸããŸãªè¡šçŸãå¯èœã«ãªããé£ããåé¡ãè§£ããããã«ãªãããšãåãã£ãã®ããã®æä»£ã§ãã
äŸãã°ããã£ãŒãã©ãŒãã³ã°ã®ã©ã€ãã©ãªã®äžã€ã§ããTensorFlowã®ãµã€ãã«ãããã¡ãã®ãã¢ã詊ããŠããã ãããšã宿ã§ãããããããŸãããFEATURESãx1ãšx2ã«ããŠé ãå±€ïŒHIDDEN LAYERïŒã1å±€ã«ãããšåçŽãªåé¡ããã§ããŸãããã
å±€ãè€æ°éããããšã«ãã£ãŠãè€éãªååžãããŠããŠãæ£ããåé¡ã§ããããã«ãªããŸãã
ãŸãããã®ãããªå€å±€ãã¥ãŒã©ã«ãããã¯ãŒã¯ãæ¯èŒçç°¡åã«æé©åã§ããã¢ã«ãŽãªãºã ãææ¡ãããŸããã
ãããããªããªãäžæããããªãã®ãæ©æ¢°åŠç¿ã§ãããã¥ãŒã©ã«ãããã¯ãŒã¯ã®å±€ãæ·±ãããŠããã°ãããé£ããåé¡ãè§£ããããã«ãªãïŒ ãšæããããåŠç¿ãäžæããããããªããªã粟床ãäžããããšãã§ããªããšããåé¡ã«ã¶ã¡åœãããŸãã
æ©æ¢°åŠç¿ã®åéãã1990幎代ã«ã¯åã³å¬ã®æä»£ã蚪ããŠããŸããŸãã
2000幎代ã«ç»åèªèã§ãã¬ã€ã¯
ãã®åŸãã€ã³ã¿ãŒãããã®çºéã§å€§éã®ããŒã¿ãéãããããªããã³ã³ãã¥ãŒã¿ã®åŠçé床ãå€§å¹ ã«åäžãæ©æ¢°åŠç¿ãã瀟äŒã§åŸã ã«äœ¿ãããããã«ãªã£ãŠããŸãããäžçªèº«è¿ãªäŸã§ã¯ãããžã«ã¡ã®é¡æ€åºãªã©ã§ãããã®æµããçŸåšãŸã§ç¶ããŠããããã£ãŒãã©ãŒãã³ã°ã®ç»å Žã«ãã£ãŠãã€ãŠãªãã»ã©ã®ããŒã ïŒç¬¬äžæ¬¡AIããŒã ïŒã«ãªã£ãŠããŸãã
æå€ãããããŸãããããã¥ãŒã©ã«ãããã¯ãŒã¯ã¯ãæè¿ãŸã§ã»ãšãã©æ³šç®ãããŠããŸããã§ãããããã©ããããè«æäžã«ããã¥ãŒã©ã«ãããã¯ãŒã¯ããšããèšèãå¢ããã»ã©æ¡æçãäœããšãŸã§èšãããŠããŸãããããããé颚ã®äžã§ãå°éã«ç ç©¶ãç¶ãããã2006幎ã«ã¯åŸã®æåã«ã€ãªãã£ã倧ããªãã¬ã€ã¯ã¹ã«ãŒããããŸããã
åŸæ¥ã¯ã圢ãè²ãªã©ç©äœã衚çŸããç¹åŸŽãç»åããã©ãæœåºãããã人éããããã詊ããŠããã®ããŒã¿ãããŸãåå²ããããã®ã¢ã«ãŽãªãºã ã調æŽããŠé©å¿ãããšããããšããäžè¬çãªè§£æ±ºæ³ã§ããããããããã£ãŒãã©ãŒãã³ã°ã®ç»å Žã«ãã£ãŠãç¹åŸŽæœåºããåé¡ãŸã§æ©æ¢°ãèªåçã«èšç®ããŠãããããã«ãªããŸããã
ãã¥ãŒã©ã«ãããã¯ãŒã¯ã倧ããæ³šç®ããããã£ããã«ãªã£ãã®ã¯ã2012幎ã«éå¬ããããILSVRC2012ããšããäžè¬ç»åèªèã®ã³ã³ããã£ã·ã§ã³ã§ãããã1,000çš®é¡ã®ç©äœïŒãã¢ãããã«ã¡ã·ã¢ã³ãéé¶ãªã©ïŒãåã£ã120äžæã®ç»åãçšæãããç»åèªèçãç«¶ããŸãããããã£ãŒãã©ãŒãã³ã°ãä»ã®ææ³ãå§åããŠãã³ããã®1äœãç²åŸããŸããã
ãã®å¹Žã«ã¯ãã©ãã«ä»ãããŠããªã倧éã®YouTubeåç»ãGoogleããã£ãŒãã©ãŒãã³ã°ã§åŠç¿ããããšãããç«ã人éã®é¡ã«åå¿ãããã¥ãŒãã³ãã§ãããšããããšã倧ããªè©±é¡ã«ãªããŸããã
åœæãç§ã¯ãŸã åã®äŒç€Ÿã«ããŠãååãšããªãã ããã°ãæè¡ãåºãŠãããããšå匷äŒãå§ããã®ã§ãããè«æãèªãã§ããŸã£ããèããããšã®ãªãçè«ãåºãŠããŠãçè§£ããã®ã«ãšãŠãèŠåŽããŸãããä»ã§ã¯åããããã解説ãããæžç±ãªã©ãããŸããŸãªææãåºãŠããŠè¯ãæä»£ã«ãªã£ããªãŒãšæããŸãã
ãã£ãŒãã©ãŒãã³ã°ã®ã©ã€ãã©ãªãå å®ããŠããŸãããæåã¯ãäžèšã®ã³ã³ãã§1äœãç²åŸããç ç©¶è ãå ¬éãããŽãªãŽãªã®C++ã§æžãããcuda-convnetãšåŒã°ãããã®ããããããªãã£ãã®ã§ãããä»ã§ã¯TensorFlowãChainerããã®èšäºã§è§£èª¬ããKerasãªã©ã䜿ãããããã¬ãŒã ã¯ãŒã¯ãåºãŠããŠããŸãã
ãã£ãŒãã©ãŒãã³ã°ã䜿ãããåé
çŸåšããã£ãŒãã©ãŒãã³ã°ãå®ç€ŸäŒã§æ°å€ã䜿ãããŠããåéã¯ãé³å£°èªèãç»åèªèã§ããç ç©¶åéã§ã¯ããã1幎ãããã§ç»åçæã匷ååŠç¿ããã«ãã¢ãŒãã«åŠç¿ã®åéã§å€§ããªææãåºãŠããŠããŸãã
äŸãããã€ãèŠãŠãããŸãããã
é³å£°èªèãç»åèªè
- é³å£°èªè
- ã¹ããŒããã©ã³ã®é³å£°å ¥åãªã©ã§å©çšãããŠããŸãã
- ç»åèªè
- ãã©ãã¢ã«ãã ã®å顿©èœããèºã®ã¬ã³ãã²ã³ç»åããã¬ã³ã®é åãèŠã€ãããåç»ãã倧éã®äººã®ããŒãºãèªèããŠãããïŒäžèšåç
§ïŒãªã©ããããŸãã
Realtime Multi-Person 2D Pose Estimation using Part Affinity Fields
ç»åçæ
æå®ããç»åãããŒã¿ããçæããŸããäžã®äŸã§ã¯ãã©ããªé³¥ããæç« ã§å ¥åãããšãããã«è¿ãé³¥ã®ç»åãçæããŠãããŸãã
ãã«ãã¢ãŒãã«åŠç¿
ãã£ãŒãã©ãŒãã³ã°ã¯ãç°ãªãã¢ãŒãéã®å¯Ÿå¿ãå¿ èŠãªåé¡ïŒç»åãšèšèªãé³å£°ãšç»åãªã©ïŒã«åŒ·ã¿ããããŸããäŸãã°ãæ¬¡ã®æè¡ã§ã¯ãç¡é³å£°ã®åç»ããåã£ãŠãããã®ãè§£æããŠãé³ãçæãããŠããŸãã
ãã£ãŒãã©ãŒãã³ã°ã©ã€ãã©ãªãKerasããåãããŠã¿ãã
ç°¡åãªèª¬æã¯ãããŸã§ãšããŠãå®éã«æãåãããªããããã£ãŒãã©ãŒãã³ã°ãåŠãã§ãããããšæããŸãã
æ¬çš¿ã§ã¯ãPythonã§å®è£ ãããŠããKerasãšããã©ã€ãã©ãªã䜿ãã以äžã®æµãã§è§£èª¬ããŠãããŸãã
Kerasãšã¯ïŒ TensorFlowãšã®é¢ä¿
ãã£ãŒãã©ãŒãã³ã°ã®æåãªã©ã€ãã©ãªãšããŠãå ã»ã©ããååãåºãŠããŸãããGoogleãéçºããŠããTensorFlowããããŸããKerasã¯ããã®TensorFlowãšãã«ããã®ã¢ã³ããªãªãŒã«å€§åŠãéçºããŠããTheanoãè£ã§èªã¿èŸŒãã§ããŠã2ã€ã®ã©ã€ãã©ãªãåãæ¿ããŠäœ¿ãããšãã§ããŸãã
æ¥æ¬ã§ã¯æè¿ãã£ãšç¥å床ãäžãã£ãŠããããªãšããå°è±¡ã§ãããæµ·å€ã§ã¯ããªã䜿ãããŠããŸããKerasã®äœè ã§ããFrançois CholletïŒãã©ã³ãœã¯ã»ã·ã§ã¬ïŒã«ãããšãGitHubã§éèšããããã¥ã©ãªãã£ã§TensorFlowã1äœãKerasã¯3äœã ããã§ãïŒ2äœã®Caffeã¯åæã«åºãŠããã©ã€ãã©ãªã§ãæåã§ã¯ããã®ã§ãã䜿ãã«ããã§ãâŠâŠïŒã
å æ¥ïŒ2017幎2æïŒãTensorFlowã1.0ã«ããŒãžã§ã³ã¢ããããéã«ã¯ãTensorFlowããKerasãèªã¿èŸŒããããã«ãªããšããçºè¡šããããä»åŸã¯å ¬åŒã«TensorFlowã«ãµããŒããããŸãã
çšãããã©ã³ã¹ã§äººæ°ãåºãKerasã®ç¹åŸŽ
Kerasã®ãããªã©ã€ãã©ãªããªãçãŸããå€ãã®äººã«äœ¿ãããããã«ãªã£ãã®ã§ããããïŒ
TensorFlowãTheanoãã现ããããšãã§ããåé¢ãèšè¿°ãç ©éã«ãªã£ãŠããŸããã¬ãã¬ãã®ç ç©¶è ã§ããã°ãã®æ¹ãè¯ãã®ã§ãããå人ã§è©Šãã«ã¯ãªãŒããŒã¹ããã¯ãšããå Žåãå€ãã®ã§ãã
ãã®ãããTensorFlowã«ã¯ã©ãããŒãäœçš®é¡ãååšããã®ã§ãããéã«ãã©ãã¯ããã¯ã¹åãããããŠãããããããšãã§ããªãã£ããããããšããããŸãã
ãã®äžã§ãKerasã¯çšãããã©ã³ã¹ã§äœ¿ãããšãã§ããããã人æ°ãåºãŸããã
ä»ã«ããæ¥æ¬èªã®ããã¥ã¡ã³ãããã£ããã話é¡ã«ãªã£ãå€ãã®ã¢ã«ãŽãªãºã ãKerasã§å®è£ ãããŠå ¬éãããŠãããããããšããããããã§ããçç±ã§ãã
ãã ãäžã€ã ãæ³šæç¹ããããŸããKerasã¯å æ¥ïŒ2017幎3æïŒã2.0ã«ã¢ããããŒãããã®ã§ãããTensorFlowã®å ¬åŒãµããŒããå ¥ã£ãããšããããå€§å¹ ãªå€æŽããããŸãããããã€ãã®é¢æ°ã廿¢ãããããååãå€ãã£ãããããããç¹ã«ããŒãžã§ã³1以åã®ã³ãŒãã䜿ãå Žåã«ã¯ãã¯ãŒãã³ã°ããšã©ãŒãåºãå¯èœæ§ããããŸãã
1. AWSã§ãã£ãŒãã©ãŒãã³ã°çšã®ã€ã³ã¹ã¿ã³ã¹ãçšæãã
ãã£ãŒãã©ãŒãã³ã°ã®åŠç¿ïŒtrainingïŒã«ã¯ãGPUãæ¬ ãããŸããã
æ§èœæ¯ã«ããããŸãããCPUã ãã§åŠç¿ããããšãããšãæ°åããæ°ååã®æéããããããšããããŸããGPUãå©çšããŠã5æ¥ã»ã©ãããåŠçãå®è¡ããããšãããªããCPUã®ã¿ã§ã¯æ°ã¶æãè²»ãããŠããŸãããšã«ãªããããéçŸå®çã§ãã
ãããã£ãŠãGPUãæèŒããPCãçšæããããAmazon Web ServicesïŒAWSïŒãGoogle Cloud PlatformïŒGCPïŒãšãã£ãã¯ã©ãŠãã³ã³ãã¥ãŒãã£ã³ã°ç°å¢ãå©çšããŠãæŒç®ããå¿ èŠããããŸãã
ä»åã¯ãAmazon EC2ã§GPUã³ã³ãã¥ãŒãã£ã³ã°ã¢ããªã±ãŒã·ã§ã³çšã«çšæãããP2ã€ã³ã¹ã¿ã³ã¹ãçšããŠããã·ã³ã¹ããã¯ãæ°ã«ããæè»œã«è©ŠããããšæããŸãã
ãã®èšäºã®å 容ã詊ãããã«ãP2ã€ã³ã¹ã¿ã³ã¹ã䜿ããš3æéã»ã©ããããŸããåŸé課éå¶ãšãªã£ãŠããã1æéããã0.90ãã«ã§ãïŒæ¬çš¿å·çæç¹ïŒããã ãã䜿çšåŸã«ã€ã³ã¹ã¿ã³ã¹ããåé€ãããã®ãå¿ããªãã§ãã ããã
ãŸããJupyter Notebooksãšãããšãã£ã¿ã䜿ã£ãŠããã°ã©ã ããŠãããŸããJupyter Notebooksã䜿ãããšã«ãã£ãŠãèªåã®PCã®ãã©ãŠã¶äžã§ã€ã³ã¿ã©ã¯ãã£ãã«ã³ãŒããæžãããšãã§ããŸãã詳现ã¯åŸã»ã©èª¬æããŸãã
AWSã®ã¢ã«ãŠã³ããäœæããŠã³ã³ãœãŒã«ã«ãµã€ã³ã€ã³
AWSã®ã¢ã«ãŠã³ããæã£ãŠããªãæ¹ã¯ãaws.amazon.comã§ã¢ã«ãŠã³ããäœããŸãã
ã³ã³ãœãŒã«ã«ãµã€ã³ã€ã³ããéã«ããªãŒãžã§ã³ã¯ãç±³åœæ±éšïŒããŒãžãã¢åéšïŒããéžæããŸããã¢ãžã¢ãã·ãã£ãã¯ïŒæ±äº¬ïŒãªãŒãžã§ã³ãéžã¶ãšãP2ã€ã³ã¹ã¿ã³ã¹ã䜿ããªããªã£ãŠããŸãã®ã§æ³šæããŠãã ããã
å ¬åŒã®ãã£ãŒãã©ãŒãã³ã°çšAMIã§ã€ã³ã¹ã¿ã³ã¹ãéžæ
ãã€ã³ã¹ã¿ã³ã¹ã®äœæããã¿ã³ãã¯ãªãã¯ããŸãã
AmazonãæäŸããããã£ãŒãã©ãŒãã³ã°çšã®AMIïŒAmazon Machine ImageïŒã䜿ããŸããGPUçšãœãããŠã§ã¢ãšåçš®ã®ãã£ãŒãã©ãŒãã³ã°ã©ã€ãã©ãªãã€ã³ã¹ããŒã«ãããŠãããããç ©éãªäœæ¥ãçç¥ã§ããŸãã
EC2ã€ã³ã¹ã¿ã³ã¹ã®èµ·åãŠã£ã¶ãŒãã®ã¹ããã1ãAmazonãã·ã³ã€ã¡ãŒãžïŒAMIïŒãã§ãAWS Marketplaceãã®ã¿ããã¯ãªãã¯ããæ€çŽ¢çªã«ãdeep learning amiããšå ¥åããŸãã
ãDeep Learning AMI Ubuntu VersionããèŠã€ããŠãéžæããã¯ãªãã¯ããŸãã
ã¹ããã2ãã€ã³ã¹ã¿ã³ã¹ã¿ã€ãã®éžæãã§ã¯ãGPUã³ã³ãã¥ãŒãã£ã³ã°ã®p2.xlargeã€ã³ã¹ã¿ã³ã¹ãéžæããŸãïŒæ¬çš¿å·çæç¹ã§ãNVIDIA Tesla K80ãšããGPUãäžã€ã1æéããã0.90ãã«ã§äœ¿ãããšãã§ããŸãïŒã
å³äžã®ãæ¬¡ã®æé ããã¯ãªãã¯ããã¹ããã6ã®ãã»ãã¥ãªãã£ã°ã«ãŒãã®èšå®ããŸã§ãã®ãŸãŸé²ã¿ãŸãã
ãšãã£ã¿ã䜿çšããã»ãã¥ãªãã£ã«ãŒã«ã®è¿œå
ãã»ãã¥ãªãã£ã°ã«ãŒãã®èšå®ãã§ã¯ãèªåã®PCãã©ãŠã¶ããJupyter Notebookã䜿ããããæ¬¡ã®ã«ãŒã«ã远å ããŸãã
| é ç® | å 容 |
|---|---|
| ã¿ã€ã | ã«ã¹ã¿ã TCPã«ãŒã« |
| ããŒãç¯å² | 8080 |
| éä¿¡å | ã«ã¹ã¿ã 0.0.0.0/0 |
ãã«ãŒã«ã®è¿œå ããã¯ãªãã¯ããŠããã®å 容ãå ¥åããŸãã
以éã®èšå®ã§Jupyter Notebookã«ãã¹ã¯ãŒããç»é²ããŠç¡é¢ä¿ãªäººããã®ã¢ã¯ã»ã¹ãå¶éããŸãããããæ©å¯ããŒã¿ãåãæ±ãå Žåã¯ãéä¿¡å ãšããŠç¹å®ã®IPã¢ãã¬ã¹ããã®ã¢ã¯ã»ã¹ã®ã¿ãåãå ¥ãããšè¯ãã§ãããã
ã確èªãšäœæããã¯ãªãã¯ããŸãã
次ã®ç»é¢ã§ãäœæããã¯ãªãã¯ãããšã次ã®ãããªãããã¢ããã衚瀺ãããŸããããã§æ°ããïŒãŸãã¯æ¢åã®ïŒããŒãã¢ãèšå®ããŠãã€ã³ã¹ã¿ã³ã¹ã®äœæããã¯ãªãã¯ããŸãã
ããã§èšå®ããããŒãã¢ã䜿ã£ãŠãã€ã³ã¹ã¿ã³ã¹ã«SSHçµç±ã§ãã°ã€ã³ãã以éã®èšå®ãè¡ããŸãã
ã€ã³ã¹ã¿ã³ã¹ã®èµ·åãšæ¥ç¶
次ã®ãããªç»é¢ãåºãããã€ã³ã¹ã¿ã³ã¹ã®èµ·åãå§ãŸããŸãã
ãã€ã³ã¹ã¿ã³ã¹ã®è¡šç€ºããæŒããšãçŸåšèµ·åäžã®ã€ã³ã¹ã¿ã³ã¹ã®äžèЧã衚瀺ãããŸãã
å ã»ã©èµ·åããã€ã³ã¹ã¿ã³ã¹ããã§ãã¯ãããæ¥ç¶ããã¯ãªãã¯ãããšãã®ãããªãããã¢ãããåºãŸãã
PCã§ã¿ãŒããã«ãèµ·åããäŸã«åŸã£ãŠã³ãã³ããå ¥åããŸãã
$ ssh -i "[䜿çšããããŒãã¡ã€ã«ã®å Žæãšåå].pem" ubuntu@[ãããªãã¯DNSã®ãã¡ã€ã³]
Pythonã®åäœç¢ºèª
Deep Learning AMI Ubuntu Versionã«ã¯ãAnacondaãšããPythonã®ãã£ã¹ããªãã¥ãŒã·ã§ã³ãã€ã³ã¹ããŒã«ãããŠããŸãã
ãã¹ãéã£ãŠããªãã®ã§ããã¹ãéããŠãããŸãã
$ export PATH=/home/ubuntu/src/anaconda3/bin:$PATH
ãã¹ãéããŠPythonãå®è¡ãããšã以äžã®ããã«è¡šç€ºãããŸãã
$ python Python 3.5.2 |Anaconda 4.2.0 (64-bit)| (default, Jul 2 2016, 17:53:06)
Kerasã®ã¢ããããŒã
ããã§äœ¿çšããŠããAMIã¯ãAmazonã宿çã«ã¢ããããŒãããŠããŸãããã¿ã€ãã³ã°ã«ãã£ãŠææ°çãã€ã³ã¹ããŒã«ãããŠããªãããšããããŸãïŒæ¬çš¿å·çæã«ãææ°ã®ããŒãžã§ã³2.0ãã€ã³ã¹ããŒã«ãããŠããŸããã§ããïŒã
ãã®ãããªãšãã¯ãæåã§ã¢ããããŒãããŠãããŸãã
$ sudo chown -R ubuntu src/anaconda3 $ conda install --channel https://conda.anaconda.org/conda-forge keras
Jupyter Notebookã®èšå®ãšèµ·å
Jupyter Notebookã䜿ãåã«ããŸãèšå®ãè¡ããŸãã
ã³ã³ãã£ã°ãã¡ã€ã«ãäœãã
$ jupyter notebook --generate-config
Jupyterã«ãã°ã€ã³ããéã®ãã¹ã¯ãŒããèšå®ããŸãã
$ python -c "import IPython; print(IPython.lib.passwd())"
Enter passwordãšVerify passwordãšåºãã®ã§ã奜ããªãã¹ã¯ãŒããå
¥åããŸãããããšãsha1ããå§ãŸãæååã衚瀺ãããŸããããã¯åŸã»ã©äœ¿ããŸãã®ã§ãsha1ãå«ããŠã³ããŒããŠãããŸãããã
次ã«ãviïŒãããã¯å¥œããªããã¹ããšãã£ã¿ïŒã§ãå ã»ã©äœæããã³ã³ãã£ã°ãã¡ã€ã«ãä¿®æ£ããŸãã
$ vi ~/.jupyter/jupyter_notebook_config.py
ãã¡ã€ã«ãéããé©åœãªãšããã«ä»¥äžãå ¥åããä¿åããŸãã
c = get_config() c.NotebookApp.ip = '*' c.NotebookApp.open_browser = False c.NotebookApp.port = 8080 c.NotebookApp.password = 'sha1:hogehoge123abc123' #å ã»ã©ã³ããŒããsha1ããå§ãŸãæåå
Jupyterã®èšå®ãå®äºãããã以äžã®ã³ãã³ããå ¥åããŠNotebookãèµ·åããŸãã
$ jupyter notebook
ããã§èµ·åããNotebookã«ãèªåã®PCã®Webãã©ãŠã¶ããã¢ã¯ã»ã¹ããŸãããã©ãŠã¶ã®ã¢ãã¬ã¹ããŒã«ãã€ã³ã¹ã¿ã³ã¹ã®IPã¢ãã¬ã¹ãŸãã¯ãã¡ã€ã³:8080ããšå ¥åããŸããã€ã³ã¹ã¿ã³ã¹ã®ãããªãã¯IPïŒãããªãã¯DNSïŒã¯ãAWSã®ã³ã³ãœãŒã«ã§ç¢ºèªã§ããŸãã
衚瀺ãããWebããŒãžã«ãå ã»ã©èšå®ããJupyterã®ãã¹ã¯ãŒããå ¥åãããšããã°ã€ã³ã§ããŸãã
å³äžã®ãNewããã¯ãªãã¯ãããšãããŸããŸãªãã¡ã€ã«ããã©ã«ããäœãããšãã§ããŸãã
ã€ã³ã¹ã¿ã³ã¹ã®çµäº
ã€ã³ã¹ã¿ã³ã¹ã®çµäºæ¹æ³ã説æããŠãããŸãããã¢ã¯ã·ã§ã³ãããã€ã¡ãŒãžâã€ã¡ãŒãžã®äœæãéžæãããšããã®AMIãä¿åããããšãã§ããæ¬¡åã䜿ãããšãã§ããŸãã
AMIãä¿åããããã¢ã¯ã·ã§ã³ããã€ã³ã¹ã¿ã³ã¹ã®ç¶æ âåé€ãéžæããã€ã³ã¹ã¿ã³ã¹ããåé€ãããŠçµäºã§ãããåé€ããããªããšæéããã£ãšè«æ±ããç¶ããã®ã§ãå¿ ãã¡ãããšåé€ã§ããã確èªããŸãããã
2. Kerasã§MNISTã®ææžãæ°åãèªèãããŠã¿ãã
Kerasã§ã¯ããã£ãŒãã©ãŒãã³ã°ã®ã¢ãŒããã¯ãã£ã衚çŸããã¢ãã«ã®æžãæ¹ãšããŠãSequentialã¢ãã«ãšãããè€éãªã¢ãŒããã¯ãã£ã®ããã«functional APIãå©çšããã¢ãã«ã®2çš®é¡ããããŸãã
ã³ãŒããåããåã«ããããããç°¡åã«èŠãŠã¿ãŸãããã
Kerasã®Sequentialã¢ãã«
ãŸããSequentialã¢ãã«ã§ããäœããã£ãŠãããã¯æ¬¡ç« ã§è§£èª¬ããŸãããå ¥å784次å ãé ãå±€ã2ã€ãåºåã«10ã¯ã©ã¹åé¡ãããã¢ãŒããã¯ãã£ã§ãã
from keras.models import Sequential from keras.layers import Dense, Activation import numpy as np #ãããŒããŒã¿ data = np.random.random((1000, 784)) labels = np.random.randint(10, size=(1000, 1)) labels = to_categorical(labels, 10)#ã©ãã«ã®å€æ model = Sequential() model.add(Dense(64, activation='relu', input_dim=784)) model.add(Dense(64, activation='relu') model.add(Dense(10, activation='softmax')) #ã¢ãã«ã®ã³ã³ãã€ã« model.compile(optimizer='rmsprop', loss='categorical_crossentropy', metrics=['accuracy']) #åŠç¿ãè¡ã model.fit(data, labels)
addã䜿ã£ãŠãå®çŸ©ããå±€ãäžã€ãã€å ããŠãããŸãã
functional APIã䜿ã£ãã¢ãã«ã®æžãæ¹
åãã¢ãã«ãfunctional APIã䜿ã£ãŠæžããšã以äžã®ããã«ãªããŸããæåãšæåŸã¯åãã§ãäžã»ã©ã«ããã¢ãŒããã¯ãã£ãå®çŸ©ãããšããã ãéã£ãŠããŸãã
from keras.layers import Input, Dense from keras.models import Model import numpy as np #ãããŒããŒã¿ data = np.random.random((1000, 784)) labels = np.random.randint(10, size=(1000, 1)) labels = to_categorical(labels, 10)#ã©ãã«ã®å€æ inputs = Input(shape=(784,)) x = Dense(64, activation='relu')(inputs) x = Dense(64, activation='relu')(x) predictions = Dense(10, activation='softmax')(x) #Modelãå®çŸ©ããŠå ¥åãšåºåãæ¥ç¶ããŸã model = Model(inputs=inputs, outputs=predictions) model.compile(optimizer='rmsprop', loss='categorical_crossentropy', metrics=['accuracy']) model.fit(data, labels)
ãããããSequentialã¢ãã«ã¯å±€ãç©ã¿äžããŠããã€ã¡ãŒãžã§ãfunctional APIã¯å±€ã®åºåãããŒãã®ããã«ã€ãªããŠããã€ã¡ãŒãžã§ããããã
MNISTããŒã¿ãèªã¿èŸŒã
ããã§ã¯ãããããå®éã«ã³ãŒããåãããŠãããŸãããããŸããMNISTããŒã¿ãèªã¿èŸŒã¿ãŸãã
- MNISTããŒã¿
- ã¢ã¡ãªã«åœç«æšæºæè¡ç ç©¶æïŒNISTïŒãçšæããææžãæ°åã®ç»åããŒã¿ããŒã¹ã§ãæ©æ¢°åŠç¿ã®åéã§ç»åèªèã®å ¥éçšãµã³ãã«ãšããŠå©çšãããŠããã
åç¯ã®ãJupyter Notebookã®èšå®ãšèµ·åãã§è§£èª¬ããããã«ãJupyter Notebookãèµ·åããŠãã©ãŠã¶ããã¢ã¯ã»ã¹ããŸãã
é©åœãªãã©ã«ããäœãããNewããã¯ãªãã¯ããŠãPython 3ããéžæãããšãNotebookçšã®.ipynbãã¡ã€ã«ãäœãããŸãã
以äžã®ã³ãŒããã»ã«ã«ã³ããããŠãRunãã¿ã³ãã¯ãªãã¯ããããShiftïŒEnterãå ¥åããŠãã ããã
%matplotlib inline import keras from keras.datasets import mnist import matplotlib.pyplot as plt #Kerasã®é¢æ°ã§ããŒã¿ã®èªã¿èŸŒã¿ãããŒã¿ãã·ã£ããã«ããŠåŠç¿ããŒã¿ãšèšç·ŽããŒã¿ã«åå²ããŠããã (x_train, y_train), (x_test, y_test) = mnist.load_data() #MNISTããŒã¿ã®è¡šç€º fig = plt.figure(figsize=(9, 9)) fig.subplots_adjust(left=0, right=1, bottom=0, top=0.5, hspace=0.05, wspace=0.05) for i in range(81): ax = fig.add_subplot(9, 9, i + 1, xticks=[], yticks=[]) ax.imshow(x_train[i].reshape((28, 28)), cmap='gray')
ã³ãŒãã®å®è¡äžã¯ãã»ã«ã®å®è¡çªå·ãã*ãã«ãªã£ãŠããã®ã§ãåŠçãçµãããŸã§åŸ ã¡ãŸãã
ã³ãŒããå®è¡ããããšMNISTããŒã¿ã衚瀺ãããŸãã0ãã9ãŸã§ã®ææžãæ°åãç»åã«ãªã£ãŠããŸãã
ãã®ããã«Jupyter Notebookã§ã¯ãåŠçã®éäžãªã©ã§ç°¡åã«ç»åã衚瀺ã§ããã®ã§ããªã¢ãŒãã§åŠçãè¡ãéã«ã䟿å©ã§ãïŒmatplotlibãšããã©ã€ãã©ãªã䜿ã£ãŠãç»åãã°ã©ãã衚瀺ããããšãã§ããŸãïŒã
ã©ã®ç»åãã©ã®æ°åããèªèããããã°ã©ã
ããã䜿ã£ãŠãã©ã®ç»åãã©ã®æ°åããèªèããããã°ã©ã ãæžããŠãããŸãã
ãŸããæ©æ¢°ãèšç®ãããã圢ã«ãããŒã¿ã倿ããŸãããïŒããã¿ã³ãã¯ãªãã¯ãã衚瀺ãããã»ã«ã«ä»¥äžãã³ããããŠãå®è¡ããŠãã ããã
num_classes = 10 x_train = x_train.reshape(60000, 784) x_test = x_test.reshape(10000, 784) x_train = x_train.astype('float32') x_test = x_test.astype('float32') x_train /= 255 x_test /= 255 y_train = y_train.astype('int32') y_test = y_test.astype('int32') y_train = keras.utils.np_utils.to_categorical(y_train, num_classes) y_test = keras.utils.np_utils.to_categorical(y_test, num_classes) print(x_train.shape[0], 'train samples') print(x_test.shape[0], 'test samples')
reshapeã¯ã28Ã28ç»çŽ ã®ç»åã784Ã1ã®ããŒã¿ã«å€æããŠããŸãã
to_categoricalãšããåŠçã¯ãy_trainã«å
¥ã£ãŠãã1ã4ã2ã6ãªã©ã®æ°åã®ã©ãã«ããæ¬¡ã®ããã«å€æããŠããŸãïŒone-hotãšèšããŸãïŒã
0â[1,0,0,0,0,0,0,0,0,0] 1â[0,1,0,0,0,0,0,0,0,0] 2â[0,0,1,0,0,0,0,0,0,0] 3â[0,0,0,1,0,0,0,0,0,0] âŠ
次ã«ããããã¢ãã«ãå®çŸ©ããŸããSequentialã¢ãã«ã䜿ããŸãã
from keras.models import Sequential from keras.layers import Dense, Dropout, Activation from keras.optimizers import RMSprop model = Sequential() model.add(Dense(512, activation='relu', input_shape=(784,))) model.add(Dropout(0.2)) model.add(Dense(512, activation='relu')) model.add(Dropout(0.2)) model.add(Dense(10, activation='softmax')) model.compile(loss='categorical_crossentropy', optimizer=RMSprop(), metrics=['accuracy'])
addã¡ãœããã§è¿œå ããŠããDenseã¯ãå
šçµåå±€ã§ããæ¬¡ã®ãããªåŒæ°ãåã£ãŠããŸãã
| åŒæ° | 説æ |
|---|---|
512 |
ãã¥ãŒãã³ã®æ° |
activation |
掻æ§å颿°ã®æå® |
input_shape |
æåã®å±€ã§ã¯å ¥åã®åœ¢ãæå®ããªããã°ãããªãããã以éã®å±€ã§ã¯äžèŠ |
Dropoutã¯ãã£ãŒãã©ãŒãã³ã°ã®éåŠç¿ãé²ãããã«è¡ããŸããDropoutã¯ãå
šçµåã®å±€ãšã®ã€ãªãããã©ã³ãã ã«åæããŠãããããšã§ãéåŠç¿ãé²ããŸãã0.2ãšããæ°åã¯ããã®åæããå²åã瀺ããŠããŸãã
- éåŠç¿
- åŠç¿çšã®ããŒã¿ã«å¯ŸããŠé©åãéããŠããŸãããã®ä»ã®ããŒã¿ãå ¥ã£ãŠãããšãã«ããŸãèªèã§ããªããªãããšããç·Žç¿åé¡ãäžåäžå¥äžžæèšããŠãã¹ãã«æãã ããå°ãéã£ãåŸåã®åé¡ãåºãããã ãã§ããŸãè§£ããªãã£ãããšãã«è¿ãã
compileã¡ãœããã§ã¯ãåŠç¿ã®éã®èšå®ãè¡ããŸãã
| åŒæ° | 説æ |
|---|---|
loss |
æå€±é¢æ° |
optimizer |
æé©åææ³ |
metrics |
è©äŸ¡ææš |
batch_size = 128 epochs = 20 history = model.fit(x_train, y_train, batch_size=batch_size, epochs=epochs, verbose=1, validation_data=(x_test, y_test))
fitã¡ãœããã§ãåŠç¿ãè¡ããŸããepochsã®æ°ã ãã«ãŒãããŸãã
| åŒæ° | 説æ |
|---|---|
batch_size |
åŠç¿ããŒã¿ããèšå®ãããµã€ãºããšã«ããŒã¿ãåãåºããèšç®ãè¡ã |
epochs |
ã¢ãã«ãåŠç¿ãããšããã¯æ°ïŒåŠç¿ããŒã¿å šäœãäœåç¹°ãè¿ãåŠç¿ããããïŒãæå®ããïŒããŒãžã§ã³2.0ã§ååã倿ŽãããïŒ |
verbose |
0ïŒæšæºåºåã«ãã°ãåºåããªãã1ïŒãã°ãããã°ã¬ã¹ããŒã§æšæºåºåã2ïŒãšããã¯ããšã«1è¡ã®ãã°ãåºå |
æ»ãå€ãhistoryã§åããŠããŸãããã®äžã«ã¯ãããŸã§ã®åŠç¿ã®çµéãå
¥ã£ãŠããã®ã§ãmatplotlibã§è¡šç€ºããŠã¿ãŸãããã
#æ£çç plt.plot(history.history['acc']) plt.plot(history.history['val_acc']) plt.title('model accuracy') plt.ylabel('accuracy') plt.xlabel('epoch') plt.legend(['train', 'test'], loc='upper left') plt.show() #loss plt.plot(history.history['loss']) plt.plot(history.history['val_loss']) plt.title('model loss') plt.ylabel('loss') plt.xlabel('epoch') plt.legend(['train', 'test'], loc='upper left') plt.show()
20ãšããã¯ãããã§ãtestã®æ£ççãäžãããã£ãŠããã®ãåãããŸãïŒlossã«ã€ããŠãã§ããããããã®å€ã¯æ¯å埮åŠã«éããŸããåŠç¿ã®éã«ãã£ãŒãã©ãŒãã³ã°ãä¹±æ°ã䜿ã£ãŠããŸããŸãªåŠçãããŠããããã§ãïŒã
åŠç¿ã®å±¥æŽãä¿åããæ©èœããããããçšæãããŠããã®ããKerasã®äŸ¿å©ãªãšããã§ãã
ããã§è©Šããã¢ãã«ã¯ãå®ã¯æé©ãªã¢ãã«ã§ã¯ãããŸãããå®éã®äœæ¥ã§ã¯åçš®ãã©ã¡ãŒã¿ãæäœããŠãtestããŒã¿ã®æ£ççãæãäžããçµã¿åãããæ¢ããŠããããšã«ãªããŸãã
CNNã䜿ã£ãŠç»åãèªèãã
å ã»ã©ã¯ãç»åã®ç»çŽ å€ãããã®ãŸãŸç¹åŸŽéãšããŠäœ¿ããŸããããã®ãã2次å ã®ããŒã¿ã1次å ã«å€æããã®ã§ããããã倿ããŠããŸããšãäžäžå·Šå³ã®ç»çŽ å€å士ã®é¢ä¿æ§ã¯èæ ®ãããªããªããŸãã
ãã£ãŒãã©ãŒãã³ã°ã§ç»åèªèããå Žåã«ã¯ãäžè¬çã«CNNïŒConvolutional Neural Networkãç³ã¿èŸŒã¿ãã¥ãŒã©ã«ãããã¯ãŒã¯ïŒã䜿ããŸããããã«ãã空éçãªç¹åŸŽãæããããšãã§ããŸãã
æ°ãããã¡ã€ã«ãéããŠã以äžãã³ããããŠãã ããã
import keras from keras.datasets import mnist from keras.models import Sequential from keras.layers import Dense, Dropout, Flatten from keras.layers import Conv2D, MaxPooling2D from keras import backend as K batch_size = 128 num_classes = 10 epochs = 12 img_rows, img_cols = 28, 28 (x_train, y_train), (x_test, y_test) = mnist.load_data() #Kerasã®ããã¯ãšã³ãã§åãTensorFlowãšTheanoã§ã¯å ¥åãã£ã³ãã«ã®é çªãéãã®ã§å ŽååãããŠæžããŠããŸã if K.image_data_format() == 'channels_first': x_train = x_train.reshape(x_train.shape[0], 1, img_rows, img_cols) x_test = x_test.reshape(x_test.shape[0], 1, img_rows, img_cols) input_shape = (1, img_rows, img_cols) else: x_train = x_train.reshape(x_train.shape[0], img_rows, img_cols, 1) x_test = x_test.reshape(x_test.shape[0], img_rows, img_cols, 1) input_shape = (img_rows, img_cols, 1) x_train = x_train.astype('float32') x_test = x_test.astype('float32') x_train /= 255 x_test /= 255 print('x_train shape:', x_train.shape) print(x_train.shape[0], 'train samples') print(x_test.shape[0], 'test samples') y_train = y_train.astype('int32') y_test = y_test.astype('int32') y_train = keras.utils.np_utils.to_categorical(y_train, num_classes) y_test = keras.utils.np_utils.to_categorical(y_test, num_classes) model = Sequential() model.add(Conv2D(32, kernel_size=(3, 3), activation='relu', input_shape=input_shape)) model.add(Conv2D(64, (3, 3), activation='relu')) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Dropout(0.25)) model.add(Flatten()) model.add(Dense(128, activation='relu')) model.add(Dropout(0.5)) model.add(Dense(num_classes, activation='softmax')) model.compile(loss=keras.losses.categorical_crossentropy, optimizer=keras.optimizers.Adadelta(), metrics=['accuracy']) model.fit(x_train, y_train, batch_size=batch_size, epochs=epochs, verbose=1, validation_data=(x_test, y_test))
addã¡ãœããã§å®çŸ©ããŠãããã©ã¡ãŒã¿ããå
ã»ã©ãšãŸã£ããéãã®ããããããšæããŸãã
Conv2Dã¡ãœããã§ã¯ãkernel_sizeã§æå®ããç¯å²ã®ç»åãèŠãŠãç³ã¿èŸŒã¿ãè¡ã£ãŠããŸããç»åã«ãããç³ã¿èŸŒã¿èšç®ã¯ãç°¡åã«ãããšãã£ã«ã¿ãŒåŠçã§ãïŒãã®ãã£ã«ã¿ãŒã¯ãã«ãŒãã«ãšãåŒã°ããŸãïŒã
ç³ã¿èŸŒã¿èšç®ã¯å³ã®ããã«ãå ¥åããŒã¿ã«å¯ŸããŠãã£ã«ã¿ãŒãäžå®ã®ééã§ããããŠèšç®ããŠãããŸãïŒå³ã®è©³çްã¯ãã¡ãïŒã
ãŸããMaxPooling2Dã¡ãœããã§ã¯ãpool_sizeã®ç¯å²ãèŠãŠããã®äžã§æã倧ããªå€ã次ã®å±€ã«æž¡ããŸããããã«ãããææžãã®ç·ãå€å°ãããŠããŠããåããããªç¹åŸŽãåãåºãããšãã§ããŸãã
Flattenã¯ã2次å
ïŒ2DïŒã®ç¹åŸŽã1次å
ã«åŒãå»¶ã°ãæäœã§ãã
ãããå®è¡ãããšããã¹ãããŒã¿ã§ã®æ£ççã99.25%ãšããçµæã«ãªããŸãããå ã»ã©ã®CNNã䜿ããªã詊è¡ã§ã¯98.40%ã ã£ãã®ã§ã粟床ãåäžããŸããã
3. Inception v3ã¢ãã«ãçšããç»åèªè
次ã¯ãããæ¬æ Œçã«ç»åèªèã®åé¡ãæ±ã£ãŠã¿ãããšæããŸãã
ããŒã¿ã®ååŠçã«ã€ããŠ
åŠç¿ãå§ããåã«ãèªè粟床ãäžããããã®ååŠçã«ã€ããŠèª¬æããŸãã
ãã£ãŒãã©ãŒãã³ã°ã§ã¯ãåãåŠç¿ããŒã¿ãäœåãç¹°ãè¿ãå ¥åããããšã§åŠç¿ãè¡ããŸãããåãç»åãå ¥åãç¶ãããšãéåŠç¿ãèµ·ããããšããããŸãããã¥ãŒã©ã«ãããã¯ãŒã¯ãç»åã®ç¹åŸŽãæ£ç¢ºã«èŠããŠããŸãããã«èµ·ããçŸè±¡ã§ãã
ãããé²ããããç»åãäžäžå·Šå³ã«ããããããå転ãããããããªã©ããŠãããŒã¿ã埮åŠã«å€ããªããå ¥åããå®éã«çšæããããŒã¿ããã倿§ãªããŒã¿ãå ¥åããããŒã¿æ¡åŒµãè¡ããŸãã
Kerasã«ã¯ãããŒã¿æ¡åŒµã®ããã®äŸ¿å©ãªã¡ãœãããçšæãããŠããŸãã
keras.preprocessing.image.ImageDataGenerator(featurewise_center=False, samplewise_center=False, featurewise_std_normalization=False, samplewise_std_normalization=False, zca_whitening=False, rotation_range=0., width_shift_range=0., height_shift_range=0., shear_range=0., zoom_range=0., channel_shift_range=0., fill_mode='nearest', cval=0., horizontal_flip=False, vertical_flip=False, rescale=None, dim_ordering=K.image_dim_ordering())
ImageDataGeneratorã¡ãœããã䜿ããšãããŸããŸãªããŒã¿æ¡åŒµãããããã®ãã©ã¡ãŒã¿ãå€ããã ãã§è¡ãããšãã§ããŸãïŒããããšåŒæ°ãå€ãã®ã§ãããããã¥ã¡ã³ãã«åŒæ°ã®èª¬æããããŸãïŒã
ãŸããããŒã¿ã®æšæºåã®åŠçãè¡ãããšãã§ããŸãã
ImageDataGeneratorã®åŸã«flowã¡ãœããã䜿ããšãååŠçããç»åãä¿åããããšãã§ããŸããæåã¯æ°æã®ç»åã§è©ŠããŠã¿ãŠã確èªããªããã¬ã³ãžã調æŽããã®ãè¯ãã§ãããã
åŠç¿ããéã®äŸ¿å©ãªæ©èœ
å®éšã§äœåã詊è¡é¯èª€ããäžã§äŸ¿å©ãªæ©èœã«ã€ããŠãã玹ä»ããŠãããŸãã
ãã£ãŒãã©ãŒãã³ã°ã®åŠç¿ã«ã¯ãæ°æéïœæ°æ¥ãããã®ãäžè¬çã§ãããã®åŠç¿ã®éäžã§ãã¢ãã«ã®å éšç¶æ ãçµ±èšæ å ±ã衚瀺ã§ããæ©èœãçšæãããŠããŸãã
åŠç¿ããéã®fitãfit_generatorã¡ãœããã«ã¯ãcallbacksãšããåŒæ°ããããããã«é¢æ°ãæžã蟌ãã§ãããšããããããèšå®ããæ©èœãåŒã³åºãããšãã§ããŸãã
颿°ã®äžäŸãšããŠã次ã®ãããªãã®ããããŸãã
| 颿° | 説æ |
|---|---|
ModelCheckpoint |
åçš®ã¿ã€ãã³ã°ïŒæ¯ãšããã¯çµäºæããä»ãŸã§ã§lossãäžçªå°ããã£ããšããã¯çµäºæãªã©ïŒã«ãåŠç¿ããã¢ãã«ãä¿åã§ãããä¿åããååãããã®ãšããã¯æ°ããlossã®å€ã«ããããšãã§ãã |
EarlyStopping |
lossãæ£ççãå€åããªããªã£ããšããã§ãåŠç¿ãæã¡åãããšãã§ãã |
LearningRateScheduler |
åŠç¿çã®ã¹ã±ãžã¥ãŒãªã³ã°ãã§ãã |
CSVLogger |
åãšããã¯ã®çµæãCSVãã¡ã€ã«ã«ä¿åãã |
åŠç¿æžã¿ã¢ãã«ã®èªã¿èŸŒã¿
Kerasã«ã¯ãããã€ãã®åŠç¿æžã¿ã®ã¢ãã«ãçšæãããŠããŠãç°¡åã«èªã¿èŸŒãããšãã§ããŸãã
- VGG16
- VGG19
- ResNet50
- Inception v3
- CRNN for music tagging
æåŸã®äžã€ã¯é³æ¥œã®ã¿ã°ä»ããè¡ãã¢ãã«ã§ããããã以å€ã¯ç»åèªèã§ãã䜿ãããŠããã¢ãŒããã¯ãã£ã§ã120äžæ1,000ã¯ã©ã¹ïŒimagenetãšåŒã°ããç»åèªèã§äœ¿ãããããŒã¿ã»ããïŒã®ç»åèªèãè¡ã£ãã¢ãã«ã§ãã
ãã®ã¢ãã«ãèªã¿èŸŒãããšã§ãèªåã§æ°é±éãããŠåŠç¿ãè¡ããªããŠãã1,000ã¯ã©ã¹ã®ç»åèªèãåããããšãã§ããŸãã
ãããå®éã«ã¯ãèªåã§çšæããããŒã¿ã»ããã«å¯ŸããŠç»åãèªèããããå Žåãå€ããšæããŸãããã®ãšãããã®ç»åã®ã仲éããäžèšã®1,000ã¯ã©ã¹ã«å ¥ã£ãŠãããããªç»åã®å ŽåïŒ1,000ã¯ã©ã¹ãããã®ã§ãããŠãã®ãã®ãå«ãŸãããšæããŸãïŒãã¢ãã«ãååŠç¿ããããšã§ãå°ãªãç»åã§ãèªè粟床ãé«ãããããšãã§ããŸãã
ãããããåŠç¿æžã¿ã®ã¢ãã«ã䜿ã£ãŠä»ã®åŠç¿ãè¡ãããšããfine tuningïŒè»¢ç§»åŠç¿ïŒãšèšããŸãã
ä»åã¯ãInception v3ããšåŒã°ããïŒååããã£ãããïŒã¢ãã«ã䜿ããŸãããã®ã¢ãã«ãå³ã«ãããã®ããã¡ããå³ã®åè§ãåå±€ã衚ããŠããŸãã
âŠâŠã¯ãããªããšãªãåãããšããããšãããã£ãŠããã ããã°ãè¯ãããšæããŸãã
ãã®ã¢ãŒããã¯ãã£ã§1,000ã¯ã©ã¹åé¡ãè¡ã£ããšãããäºæž¬ããããã5ã®äžã«æ£ããçãããªãã£ãé »åºŠïŒããã5ãšã©ãŒçãäœãã»ã©è¯ãïŒã¯3.46ïŒ ã ã£ãããã§ããã¡ãªã¿ã«äººéïŒç ç©¶è ïŒããã£ãå Žåã¯ã5.1%ã ã£ãããã§ããInception v3ãã°ãã§ããã
ã¡ãªã¿ã«ãVGGãã§ã®fine tuningã«é¢ããŠã¯ãä»ã®ããã°ãªã©ã§è§£èª¬ãããŠããŸãããInception v3ã«é¢ããŠã¯ãfine tuningã®èšäºãããŸããªãã£ãã®ã§ãåèã«ãªããšæããŸãïŒãã ããKerasã®ããŒãžã§ã³ã¯ãããã1.0ãš1.2ïŒã
- Kerasã§åŠã¶è»¢ç§»åŠç¿ - Elix Tech Blog
- VGG16ã®Fine-tuningã«ããç¬ç«èªè (1) - 人工ç¥èœã«é¢ããæåµé²
fine tuningã䜿ã£ãç»åèªè
ããã§äœ¿ãç»åããŒã¿ã¯ãå ã»ã©ã®ããã°ãåèã«ãKaggleã§äœ¿ãããŠããç¬ç«ç»åã«ããŸãã
Kaggleã®ããŒãžã«ç§»åããDataã¿ããã¯ãªãã¯ããŠãtrain.zipããã¡ã€ã«ãããŠã³ããŒãããŸãããã®éã«ãkaggleã«ã¢ã«ãŠã³ããç»é²ããå¿ èŠããããŸããããã§ã¯ãåŠç¿ããŒã¿ã«ãç¬ã¯ã©ã¹1,000æãç«ã¯ã©ã¹1,000æãæ€èšŒçšã«ãããã400æãã€ã䜿ããŸãã
ããŒã¿ãçšæã§ããããã¹ã¯ãªãããæžããŠãããŸãã
from keras.applications.inception_v3 import InceptionV3 from keras.applications.inception_v3 import preprocess_input from keras.models import Sequential, Model from keras.layers import Dense, Dropout, Activation, Flatten from keras.layers import Convolution2D, MaxPooling2D, ZeroPadding2D, GlobalAveragePooling2D, AveragePooling2D from keras.preprocessing.image import ImageDataGenerator from keras.callbacks import ModelCheckpoint, CSVLogger, LearningRateScheduler, ReduceLROnPlateau from keras.optimizers import SGD from keras.regularizers import l2 import matplotlib.image as mpimg from scipy.misc import imresize import numpy as np import keras.backend as K import math K.clear_session() img_size=299 #èšç·ŽããŒã¿æ¡åŒµ train_datagen = ImageDataGenerator( featurewise_center=False, samplewise_center=False, featurewise_std_normalization=False, samplewise_std_normalization=False, rotation_range=10, width_shift_range=0.2, height_shift_range=0.2, horizontal_flip=True, vertical_flip=False, zoom_range=[.8, 1], channel_shift_range=30, fill_mode='reflect') test_datagen = ImageDataGenerator() #ç»åã®èªã¿èŸŒã¿ def load_images(root,nb_img): all_imgs = [] all_classes = [] for i in range(nb_img): img_name = "%s/dog.%d.jpg" % (root, i + 1) img_arr = mpimg.imread(img_name) resize_img_ar = imresize(img_arr, (img_size, img_size)) all_imgs.append(resize_img_ar) all_classes.append(0) for i in range(nb_img): img_name = "%s/cat.%d.jpg" % (root, i + 1) img_arr = mpimg.imread(img_name) resize_img_ar = imresize(img_arr, (img_size, img_size)) all_imgs.append(resize_img_ar) all_classes.append(1) return np.array(all_imgs), np.array(all_classes) X_train, y_train = load_images('./train', 1000) X_test, y_test = load_images('./train', 400) train_generator = train_datagen.flow(X_train, y_train, batch_size=64, seed = 13) test_generator = test_datagen.flow(X_test, y_test, batch_size=64, seed = 13) #Inception v3ã¢ãã«ã®èªã¿èŸŒã¿ãæçµå±€ã¯èªã¿èŸŒãŸãªã base_model = InceptionV3(weights='imagenet', include_top=False) #æçµå±€ã®èšå® x = base_model.output x = GlobalAveragePooling2D()(x) predictions = Dense(1, kernel_initializer="glorot_uniform", activation="sigmoid", kernel_regularizer=l2(.0005))(x) model = Model(inputs=base_model.input, outputs=predictions) #base_modelã¯weightsãæŽæ°ããªã for layer in base_model.layers: layer.trainable = False opt = SGD(lr=.01, momentum=.9) model.compile(optimizer=opt, loss='binary_crossentropy', metrics=['accuracy']) checkpointer = ModelCheckpoint(filepath='model.{epoch:02d}-{val_loss:.2f}.hdf5', verbose=1, save_best_only=True) csv_logger = CSVLogger('model.log') reduce_lr = ReduceLROnPlateau(monitor='val_loss', factor=0.2, patience=5, min_lr=0.001) history = model.fit_generator(train_generator, steps_per_epoch=2000, epochs=10, validation_data=test_generator, validation_steps=800, verbose=1, callbacks=[reduce_lr, csv_logger, checkpointer])
åã®ç« ã§è§£èª¬ããäŸ¿å©æ©èœã䜿ã£ãŠæžããŠããŸãã
ç»åèªèã®å®è¡çµæãšç²ŸåºŠã®ç¢ºèª
ãããå®è¡ããŠã¿ããšãããã1ãšããã¯ã§ãæ€èšŒããŒã¿ã§ã®ç²ŸåºŠã0.99ã§ãããæ¬åœã¯ãšããã¯ãå¢ããããšã«ã ãã ãlossãäžããã粟床ãäžãã£ãŠãããšããããèŠããããã£ãã®ã§ãããæãã®ã»ãInception v3ã匷åãããŸããâŠâŠã
æåã«10ãšããã¯æå®ããŸããããæéãããã£ãŠããŸãã®ã§ãã¢ãã«ãä¿åãããŠããã®ã確èªãããäžæããŸãã
åŠç¿ããã¢ãã«ã¯ãmodel.ââââ.hdf5ããšããååã§ä¿åãããŠãããšæããŸãã®ã§ããããèªã¿èŸŒãã§ç²ŸåºŠã確ãããŠã¿ãããšæããŸãã
from keras.models import load_model import matplotlib.pyplot as plt model = load_model(filepath='./model.00-0.03.hdf5') def predict_img(img_name): img_arr = mpimg.imread(img_name) fig, ax = plt.subplots() ax.imshow(img_arr) plt.show() resize_img = imresize(img_arr, (img_size, img_size)) x=resize_img x = np.expand_dims(x, axis=0) y_pred = model.predict(x) if y_pred <0.5: print (y_pred[0][0], 'dog') else: print (y_pred[0][0], 'cat')
åŠç¿ã«äœ¿ã£ãŠããªãç»åãèªã¿èŸŒãã§ã¿ãŸãã
predict_img('./train/dog.3112.jpg')
predict_img('./train/cat.3011.jpg')
äœæã詊ããŸããããå šéšæ£è§£ã§ãããæãã¹ãInception v3âŠâŠïŒïŒ
ããã«fine tuningãã
ããŠããã®ã¢ãã«ããããã«fine tuningãããå ŽåãäŸãã°ãç¬ç«ããŒã¿ã䜿ã£ãŠåŠç¿ããåŸã«ã10åçš®ã®ã©ãã«ãã€ããããŒã¿ã50æãã€ãåèš500æãããªãå Žåã«åçš®ãåé¡ããã¿ã¹ã¯ããªã©ãæ³å®ãããã§ããããã
ä»åã®äŸã§ã¯æçµå±€ããæŽæ°ããŠããªãã®ã§ãããŸã广ã¯ãªããšæããŸããã䌌ããããªã·ãã¥ãšãŒã·ã§ã³ã§åŠç¿ãè¡ã£ãããšããããŸããããããŠåŸ®åŠã«ããããŸããâŠâŠããã£ããã§ãã®ã§å ±æããŸãã
æåã®åŠç¿ã§ãå
ã»ã©ã®äŸã§ã¯modelãä¿åããŠããŸããããModelCheckpointã®åŒæ°ã§weightsã ããä¿åããããã«ããŸãã
checkpointer = ModelCheckpoint(filepath='model.{epoch:02d}-{val_loss:.2f}.hdf5', verbose=1, save_best_only=True, save_weights_only=True)
fine tuningãããŸãã
#imagenetã®modelã¯èªã¿èŸŒããweightsã¯èªã¿èŸŒãŸãªã base_model = InceptionV3(weights=None, include_top=False) x = base_model.output x = GlobalAveragePooling2D()(x) predictions = Dense(10, init='glorot_uniform', W_regularizer=l2(.0005), activation='softmax', name= '10dogcat')(x)#nameã§å±€ã«ïŒãã£ããšã¯éãïŒååãã€ãã model = Model(input=base_model.input, output=predictions) #å ã»ã©åŠç¿ããweightsãèªã¿èŸŒãããå±€ã®ååãéããšããã¯èªã¿èŸŒãŸãªã model.load_weights("./weight.19-0.70.hdf5", by_name=True)
Kerasã§ã¯åå±€ã«ååãã€ããããšãã§ããã®ã§ããããã®ååãä¿åããweightsã®å±€ãšéãå Žåã«ã¯ãby_nameãTrueã«ããããšã«ãã£ãŠãweightsãèªã¿èŸŒãŸãªãããã«ããããšãã§ããŸãã
以äžã§åŠç¿ã¯çµäºã§ããæåŸã«ã€ã³ã¹ã¿ã³ã¹ãä¿åãåé€ããŠãã ããã
ãŸãšããšåèæç®
ä»åã®èšäºã¯ãããŸã§ãšãªããŸããããªãé§ãè¶³ã§Kerasã䜿ã£ãŠã¿ãŸãããããªããšãªããã£ãŒãã©ãŒãã³ã°ãšãããã®ãã©ããããã®ãã€ã¡ãŒãžããŠããã ããã§ããããã
èšäºã§è§£èª¬ããã®ã¯ããã®ãããé床ã§é²æ©ããŠããæè¡ã®äžéšã§ãããããŸãããããã®èšäºããã£ããã«ãã£ãŒãã©ãŒãã³ã°ãæ©æ¢°åŠç¿ã«èå³ãæã£ãŠããã ããã°å¹žãã§ãã
æåŸã«åèã«ãªããããªæ¬ãWebããŒãžã玹ä»ããŸãã
ãŒãããäœãDeep Learning âPythonã§åŠã¶ãã£ãŒãã©ãŒãã³ã°ã®çè«ãšå®è£
ããããªæ¹ãããããªãšããã§æšèŠããŠããŸããåããããããçŽ æŽãããã§ãã
Bengioå çã®ããããã¬ã·ã
å®éã«ãã£ãŒãã©ãŒãã³ã°ã䜿ã£ãŠåŠç¿ãé²ããããšããŠãã1åã§ããŸãããå¯èœæ§ã¯äœãã§ããããã§ããŸããŸãªãã©ã¡ãŒã¿ã調æŽããããã©ãã«åå ãããã®ããæ¢ãå¿ èŠããããŸããåå ãæ¢ãã³ãã«ã€ããŠãç ç©¶è ããŸãšãããã®ïŒã®æ¥æ¬èªèš³ïŒã§ãã
å·çè ãããã£ãŒã«
å®®æ¬åªäžïŒã¿ãããšã»ãããã¡ïŒ @miyamotty
ç·šéïŒèäºåæ¥ïŒZINEïŒ




