рдЯреНрд░рд╛рдВрд╕рдлрд░ рд▓рд░реНрдирд┐рдВрдЧ: рдЕрдкрдиреЗ рдбреЗрдЯрд╛ рдкрд░ рдПрдХ рддрдВрддреНрд░рд┐рдХрд╛ рдиреЗрдЯрд╡рд░реНрдХ рдХреЛ рдЬрд▓реНрджреА рд╕реЗ рдХреИрд╕реЗ рдкреНрд░рд╢рд┐рдХреНрд╖рд┐рдд рдХрд░реЗрдВ

рдорд╢реАрди рд▓рд░реНрдирд┐рдВрдЧ рдЕрдзрд┐рдХ рд╕реБрд▓рдн рд╣реЛ рд░рд╣реА рд╣реИ, рдЗрд╕ рддрдХрдиреАрдХ рдХреЛ "рдСрдл-рдж-рд╢реЗрд▓реНрдл рдШрдЯрдХреЛрдВ" рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЕрдзрд┐рдХ рдЕрд╡рд╕рд░ рд╣реИрдВред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рд╕реНрдерд╛рдирд╛рдВрддрд░рдг рд▓рд░реНрдирд┐рдВрдЧ рдЖрдкрдХреЛ рдПрдХ рд╕рдорд╕реНрдпрд╛ рдХреЛ рд╣рд▓ рдХрд░рдиреЗ рдореЗрдВ рдкреНрд░рд╛рдкреНрдд рдЕрдиреБрднрд╡ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ, рджреВрд╕рд░реА рд╕рдорд╕реНрдпрд╛ред рддрдВрддреНрд░рд┐рдХрд╛ рдиреЗрдЯрд╡рд░реНрдХ рдХреЛ рдкрд╣рд▓реЗ рдмрдбрд╝реА рдорд╛рддреНрд░рд╛ рдореЗрдВ рдбреЗрдЯрд╛, рдлрд┐рд░ рд▓рдХреНрд╖реНрдп рд╕реЗрдЯ рдкрд░ рдкреНрд░рд╢рд┐рдХреНрд╖рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред

рдЦрд╛рджреНрдп рдорд╛рдиреНрдпрддрд╛

рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ рдореИрдВ рдЖрдкрдХреЛ рдмрддрд╛рдКрдВрдЧрд╛ рдХрд┐ рднреЛрдЬрди рдХреЗ рд╕рд╛рде рдЫрд╡рд┐рдпреЛрдВ рдХреА рдорд╛рдиреНрдпрддрд╛ рдХреЗ рдЙрджрд╛рд╣рд░рдг рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╕реНрдерд╛рдирд╛рдВрддрд░рдг рдЕрдзрд┐рдЧрдо рд╡рд┐рдзрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХреИрд╕реЗ рдХрд░реЗрдВред рдореИрдВ рдбреЗрд╡рд▓рдкрд░ рдХрд╛рд░реНрдпрд╢рд╛рд▓рд╛ рдХреЗ рд▓рд┐рдП рдорд╢реАрди рд▓рд░реНрдирд┐рдВрдЧ рдФрд░ рдиреНрдпреВрд░рд▓ рдиреЗрдЯрд╡рд░реНрдХ рдкрд░ рдЕрдиреНрдп рдорд╢реАрди рд▓рд░реНрдирд┐рдВрдЧ рдЯреВрд▓реНрд╕ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдмрд╛рдд рдХрд░реВрдВрдЧрд╛ред

рдпрджрд┐ рд╣рдореЗрдВ рдЫрд╡рд┐ рдкрд╣рдЪрд╛рди рдХреЗ рдХрд╛рд░реНрдп рдХрд╛ рд╕рд╛рдордирд╛ рдХрд░рдирд╛ рдкрдбрд╝рддрд╛ рд╣реИ, рддреЛ рдЖрдк рддреИрдпрд╛рд░ рд╕реЗрд╡рд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рд╣рд╛рд▓рд╛рдВрдХрд┐, рдпрджрд┐ рдЖрдкрдХреЛ рдЕрдкрдиреЗ рд╕реНрд╡рдпрдВ рдХреЗ рдбреЗрдЯрд╛ рд╕реЗрдЯ рдкрд░ рдореЙрдбрд▓ рдХреЛ рдкреНрд░рд╢рд┐рдХреНрд╖рд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рддреЛ рдЖрдкрдХреЛ рдЗрд╕реЗ рд╕реНрд╡рдпрдВ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред

рдЫрд╡рд┐ рд╡рд░реНрдЧреАрдХрд░рдг рдХреЗ рд░реВрдк рдореЗрдВ рдРрд╕реЗ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдХрд╛рд░реНрдпреЛрдВ рдХреЗ рд▓рд┐рдП, рдЖрдк рддреИрдпрд╛рд░ рдЖрд░реНрдХрд┐рдЯреЗрдХреНрдЪрд░ (рдПрд▓реЗрдХреНрд╕рдиреЗрдЯ, рд╡реАрдЬреАрдЬреА, рдЗрдВрд╕реЗрдкреНрд╢рди, рд░реЗрд╕рдиреЗрдЯ, рдЖрджрд┐) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рдЕрдкрдиреЗ рдбреЗрдЯрд╛ рдкрд░ рддрдВрддреНрд░рд┐рдХрд╛ рдиреЗрдЯрд╡рд░реНрдХ рдХреЛ рдкреНрд░рд╢рд┐рдХреНрд╖рд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдЗрд╕ рддрд░рд╣ рдХреЗ рдиреЗрдЯрд╡рд░реНрдХ рдХрд╛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд╡рд┐рднрд┐рдиреНрди рд░реВрдкрд░реЗрдЦрд╛рдУрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдореМрдЬреВрдж рд╣реИ, рдЗрд╕рд▓рд┐рдП рдЗрд╕ рд╕реНрддрд░ рдкрд░ рдЖрдк рдЗрд╕рдХреЗ рд╕рдВрдЪрд╛рд▓рди рдХреЗ рд╕рд┐рджреНрдзрд╛рдВрдд рдореЗрдВ рдЧрд╣рд░рд╛рдИ рд╕реЗ рдмрд┐рдирд╛, рдПрдХ рдмреНрд▓реИрдХ рдмреЙрдХреНрд╕ рдХреЗ рд░реВрдк рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред

рд╣рд╛рд▓рд╛рдВрдХрд┐, рдЧрд╣рди рддрдВрддреНрд░рд┐рдХрд╛ рдиреЗрдЯрд╡рд░реНрдХ рд╕реАрдЦрдиреЗ рдХреА рдЕрднрд┐рд╕рд░рдг рдХреЗ рд▓рд┐рдП рдмрдбрд╝реА рдорд╛рддреНрд░рд╛ рдореЗрдВ рдбреЗрдЯрд╛ рдХреА рдорд╛рдВрдЧ рдХрд░ рд░рд╣реЗ рд╣реИрдВред рдФрд░ рдЕрдХреНрд╕рд░ рд╣рдорд╛рд░реЗ рд╡рд┐рд╢реЗрд╖ рдХрд╛рд░реНрдп рдореЗрдВ рддрдВрддреНрд░рд┐рдХрд╛ рдиреЗрдЯрд╡рд░реНрдХ рдХреА рд╕рднреА рдкрд░рддреЛрдВ рдХреЛ рдареАрдХ рд╕реЗ рдкреНрд░рд╢рд┐рдХреНрд╖рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд░реНрдпрд╛рдкреНрдд рдбреЗрдЯрд╛ рдирд╣реАрдВ рд╣реЛрддрд╛ рд╣реИред рд╕реНрдерд╛рдирд╛рдВрддрд░рдг рд▓рд░реНрдирд┐рдВрдЧ рдЗрд╕ рд╕рдорд╕реНрдпрд╛ рдХреЛ рд╣рд▓ рдХрд░рддрд╛ рд╣реИред

рдЫрд╡рд┐ рд╡рд░реНрдЧреАрдХрд░рдг рдХреЗ рд▓рд┐рдП рд╕реНрдерд╛рдирд╛рдВрддрд░рдг рд╕реАрдЦрдирд╛


рд╡рд░реНрдЧреАрдХрд░рдг рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧ рдХрд┐рдП рдЬрд╛рдиреЗ рд╡рд╛рд▓реЗ рддрдВрддреНрд░рд┐рдХрд╛ рдиреЗрдЯрд╡рд░реНрдХ рдореЗрдВ рдЖрдорддреМрд░ рдкрд░ рдЕрдВрддрд┐рдо рдкрд░рдд рдореЗрдВ N рдЖрдЙрдЯрдкреБрдЯ рдиреНрдпреВрд░реЙрдиреНрд╕ рд╣реЛрддреЗ рд╣реИрдВ, рдЬрд╣рд╛рдВ N рдХрдХреНрд╖рд╛рдУрдВ рдХреА рд╕рдВрдЦреНрдпрд╛ рд╣реЛрддреА рд╣реИред рдЗрд╕ рддрд░рд╣ рдХреЗ рдПрдХ рдЖрдЙрдЯрдкреБрдЯ рд╡реЗрдХреНрдЯрд░ рдХреЛ рдПрдХ рд╡рд░реНрдЧ рд╕реЗ рд╕рдВрдмрдВрдзрд┐рдд рд╕рдВрднрд╛рд╡рдирд╛рдУрдВ рдХреА рдПрдХ рд╕реЗрдЯ рдХреЗ рд░реВрдк рдореЗрдВ рдорд╛рдирд╛ рдЬрд╛рддрд╛ рд╣реИред рднреЛрдЬрди рдЫрд╡рд┐рдпреЛрдВ рдХреЛ рдкрд╣рдЪрд╛рдирдиреЗ рдХреЗ рд╣рдорд╛рд░реЗ рдХрд╛рд░реНрдп рдореЗрдВ, рдХрдХреНрд╖рд╛рдУрдВ рдХреА рд╕рдВрдЦреНрдпрд╛ рдореВрд▓ рдбреЗрдЯрд╛рд╕реЗрдЯ рд╕реЗ рднрд┐рдиреНрди рд╣реЛ рд╕рдХрддреА рд╣реИред рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ, рд╣рдореЗрдВ рдЗрд╕ рдЕрдВрддрд┐рдо рдкрд░рдд рдХреЛ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдмрд╛рд╣рд░ рдлреЗрдВрдХрдирд╛ рд╣реЛрдЧрд╛ рдФрд░ рдПрдХ рдирдИ рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рдбрд╛рд▓рдирд╛ рд╣реЛрдЧрд╛, рдЬрд┐рд╕рдореЗрдВ рдЖрдЙрдЯрдкреБрдЯ рдиреНрдпреВрд░реЙрдиреНрд╕ рдХреА рд╕рд╣реА рд╕рдВрдЦреНрдпрд╛ рд╣реЛрдЧреА

рд╕реАрдЦрдиреЗ рдХрд╛ рд╕реНрдерд╛рдирд╛рдВрддрд░рдг

рдЕрдХреНрд╕рд░ рд╡рд░реНрдЧреАрдХрд░рдг рдиреЗрдЯрд╡рд░реНрдХ рдХреЗ рдЕрдВрдд рдореЗрдВ, рдПрдХ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдЬреБрдбрд╝реА рдкрд░рдд рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдЪреВрдВрдХрд┐ рд╣рдордиреЗ рдЗрд╕ рдкрд░рдд рдХреЛ рдмрджрд▓ рджрд┐рдпрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдЗрд╕рдХреЗ рд▓рд┐рдП рдкреВрд░реНрд╡ рдкреНрд░рд╢рд┐рдХреНрд╖рд┐рдд рднрд╛рд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдХрд╛рдо рдирд╣реАрдВ рдХрд░реЗрдЧрд╛ред рдпрд╛рджреГрдЪреНрдЫрд┐рдХ рдореВрд▓реНрдпреЛрдВ рдХреЗ рд╕рд╛рде рдЕрдкрдиреЗ рд╡рдЬрди рдХреЛ рд╢реБрд░реВ рдХрд░рддреЗ рд╣реБрдП, рдЖрдкрдХреЛ рдЙрд╕реЗ рдЦрд░реЛрдВрдЪ рд╕реЗ рдкреНрд░рд╢рд┐рдХреНрд╖рд┐рдд рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред рд╣рдо рдкреВрд░реНрд╡-рдкреНрд░рд╢рд┐рдХреНрд╖рд┐рдд рд╕реНрдиреИрдкрд╢реЙрдЯ рд╕реЗ рдЕрдиреНрдп рд╕рднреА рдкрд░рддреЛрдВ рдХреЗ рд▓рд┐рдП рднрд╛рд░ рд▓реЛрдб рдХрд░рддреЗ рд╣реИрдВред

рдореЙрдбрд▓ рдХреЛ рдЖрдЧреЗ рдХреЗ рдкреНрд░рд╢рд┐рдХреНрд╖рдг рдХреЗ рд▓рд┐рдП рд╡рд┐рднрд┐рдиреНрди рд░рдгрдиреАрддрд┐рдпрд╛рдБ рд╣реИрдВред рд╣рдо рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗ: рд╣рдо рдкреВрд░реЗ рдиреЗрдЯрд╡рд░реНрдХ рдХреЛ рдЕрдВрдд рд╕реЗ рдЕрдВрдд ( рдПрдВрдб-рдЯреВ-рдПрдВрдб ) рддрдХ рдкреНрд░рд╢рд┐рдХреНрд╖рд┐рдд рдХрд░реЗрдВрдЧреЗ, рдФрд░ рд╣рдо рдкреВрд░реНрд╡-рдкреНрд░рд╢рд┐рдХреНрд╖рд┐рдд рднрд╛рд░ рдХреЛ рдареАрдХ рдирд╣реАрдВ рдХрд░реЗрдВрдЧреЗ рддрд╛рдХрд┐ рдЙрдиреНрд╣реЗрдВ рдереЛрдбрд╝рд╛ рд╕рдорд╛рдпреЛрдЬрд┐рдд рдХрд░рдиреЗ рдФрд░ рд╣рдорд╛рд░реЗ рдбреЗрдЯрд╛ рдХреЛ рд╕рдорд╛рдпреЛрдЬрд┐рдд рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рдорд┐рд▓ рд╕рдХреЗред рдЗрд╕ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЛ рдлрд╛рдЗрди-рдЯреНрдпреВрдирд┐рдВрдЧ рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ ред

рд╕рдВрд░рдЪрдирд╛рддреНрдордХ рдШрдЯрдХ


рд╕рдорд╕реНрдпрд╛ рдХреЛ рд╣рд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдШрдЯрдХреЛрдВ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ:

  1. рддрдВрддреНрд░рд┐рдХрд╛ рдиреЗрдЯрд╡рд░реНрдХ рдореЙрдбрд▓ рдХрд╛ рд╡рд┐рд╡рд░рдг
  2. рд▓рд░реНрдирд┐рдВрдЧ рдкрд╛рдЗрдк рд▓рд╛рдЗрди
  3. рд╣рд╕реНрддрдХреНрд╖реЗрдк рдкрд╛рдЗрдкрд▓рд╛рдЗрди
  4. рдЗрд╕ рдореЙрдбрд▓ рдХреЗ рд▓рд┐рдП рдкрд╣рд▓реЗ рд╕реЗ рдкреНрд░рд╢рд┐рдХреНрд╖рд┐рдд рд╡рдЬрди
  5. рдкреНрд░рд╢рд┐рдХреНрд╖рдг рдФрд░ рд╕рддреНрдпрд╛рдкрди рдХреЗ рд▓рд┐рдП рдбреЗрдЯрд╛

рдЕрд╡рдпрд╡

рд╣рдорд╛рд░реЗ рдЙрджрд╛рд╣рд░рдг рдореЗрдВ, рдореИрдВ рдЕрдкрдиреЗ рд╕реНрд╡рдпрдВ рдХреЗ рднрдВрдбрд╛рд░ рд╕реЗ рдШрдЯрдХреЛрдВ (1), (2) рдФрд░ (3) рдХреЛ рд▓реЗ рдЬрд╛рдКрдВрдЧрд╛ , рдЬрд┐рд╕рдореЗрдВ рд╕рдмрд╕реЗ рд╣рд▓реНрдХрд╛ рдХреЛрдб рд╣реЛрддрд╛ рд╣реИ - рдЖрдк рдЪрд╛рд╣реЗрдВ рддреЛ рдЖрд╕рд╛рдиреА рд╕реЗ рдЗрд╕рдХрд╛ рдкрддрд╛ рд▓рдЧрд╛ рд╕рдХрддреЗ рд╣реИрдВред рд╣рдорд╛рд░рд╛ рдЙрджрд╛рд╣рд░рдг рд▓реЛрдХрдкреНрд░рд┐рдп TensorFlow рдврд╛рдВрдЪреЗ рдкрд░ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред рдЪрдпрдирд┐рдд рдврд╛рдВрдЪреЗ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреБрдХреНрдд рдкреВрд░реНрд╡ рдкреНрд░рд╢рд┐рдХреНрд╖рд┐рдд рднрд╛рд░ (4) рдкрд╛рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ рдпрджрд┐ рд╡реЗ рд╢рд╛рд╕реНрддреНрд░реАрдп рд╡рд╛рд╕реНрддреБрд╢рд┐рд▓реНрдк рдореЗрдВ рд╕реЗ рдПрдХ рдХреЗ рдЕрдиреБрд░реВрдк рд╣реЛрдВред рдкреНрд░рджрд░реНрд╢рди рдХреЗ рд▓рд┐рдП рдПрдХ рдбреЗрдЯрд╛рд╕реЗрдЯ (5) рдХреЗ рд░реВрдк рдореЗрдВ рдореИрдВ рдлрд╝реВрдб -резреж рд▓реЗ рд▓реВрдВрдЧрд╛ред

рдЖрджрд░реНрд╢


рдПрдХ рдореЙрдбрд▓ рдХреЗ рд░реВрдк рдореЗрдВ, рд╣рдо рдХреНрд▓рд╛рд╕рд┐рдХ рд╡реАрдЬреАрдЬреА рдиреНрдпреВрд░рд▓ рдиреЗрдЯрд╡рд░реНрдХ (рдЕрдзрд┐рдХ рд╕рдЯреАрдХ, рд╡реАрдЬреАрдЬреА 19 ) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВред рдХреБрдЫ рдиреБрдХрд╕рд╛рди рдХреЗ рдмрд╛рд╡рдЬреВрдж, рдпрд╣ рдореЙрдбрд▓ рдХрд╛рдлреА рдЙрдЪреНрдЪ рдЧреБрдгрд╡рддреНрддрд╛ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рддрд╛ рд╣реИред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд░рдирд╛ рдЖрд╕рд╛рди рд╣реИред TensorFlow рд╕реНрд▓рд┐рдо рдкрд░, рдореЙрдбрд▓ рд╡рд┐рд╡рд░рдг рдХрд╛рдлреА рдХреЙрдореНрдкреИрдХреНрдЯ рджрд┐рдЦрддрд╛ рд╣реИ:

 import tensorflow as tf import tensorflow.contrib.slim as slim def vgg_19(inputs, num_classes, is_training, scope='vgg_19', weight_decay=0.0005): with slim.arg_scope([slim.conv2d], activation_fn=tf.nn.relu, weights_regularizer=slim.l2_regularizer(weight_decay), biases_initializer=tf.zeros_initializer(), padding='SAME'): with tf.variable_scope(scope, 'vgg_19', [inputs]): net = slim.repeat(inputs, 2, slim.conv2d, 64, [3, 3], scope='conv1') net = slim.max_pool2d(net, [2, 2], scope='pool1') net = slim.repeat(net, 2, slim.conv2d, 128, [3, 3], scope='conv2') net = slim.max_pool2d(net, [2, 2], scope='pool2') net = slim.repeat(net, 4, slim.conv2d, 256, [3, 3], scope='conv3') net = slim.max_pool2d(net, [2, 2], scope='pool3') net = slim.repeat(net, 4, slim.conv2d, 512, [3, 3], scope='conv4') net = slim.max_pool2d(net, [2, 2], scope='pool4') net = slim.repeat(net, 4, slim.conv2d, 512, [3, 3], scope='conv5') net = slim.max_pool2d(net, [2, 2], scope='pool5') # Use conv2d instead of fully_connected layers net = slim.conv2d(net, 4096, [7, 7], padding='VALID', scope='fc6') net = slim.dropout(net, 0.5, is_training=is_training, scope='drop6') net = slim.conv2d(net, 4096, [1, 1], scope='fc7') net = slim.dropout(net, 0.5, is_training=is_training, scope='drop7') net = slim.conv2d(net, num_classes, [1, 1], scope='fc8', activation_fn=None) net = tf.squeeze(net, [1, 2], name='fc8/squeezed') return net 

рдЗрдореЗрдЬрдиреЗрдЯ рдкрд░ рдкреНрд░рд╢рд┐рдХреНрд╖рд┐рдд рд╡реАрдЬреАрдЬреА 19 рдХреЗ рд▓рд┐рдП рд╡реЗрдЯ рдФрд░ рдЯреЗрдиреНрд╕рд░рдлреНрд▓реЛ рдХреЗ рд╕рд╛рде рд╕рдВрдЧрдд, рдкреНрд░реА-рдкреНрд░рд╢рд┐рдХреНрд╖рд┐рдд рдореЙрдбрд▓ рд╕реЗрдХреНрд╢рди рд╕реЗ рдЧрд┐рдЯрд╣рдм рдкрд░ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рд╕реЗ рдбрд╛рдЙрдирд▓реЛрдб рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред

 mkdir data && cd data wget http://download.tensorflow.org/models/vgg_19_2016_08_28.tar.gz tar -xzf vgg_19_2016_08_28.tar.gz 

рдбрд╛рдЯрд╛рд╕реЗрдЯ


рдкреНрд░рд╢рд┐рдХреНрд╖рдг рдФрд░ рд╕рддреНрдпрд╛рдкрди рдирдореВрдиреЗ рдХреЗ рд░реВрдк рдореЗрдВ, рд╣рдо рд╕рд╛рд░реНрд╡рдЬрдирд┐рдХ рдЦрд╛рджреНрдп -резрежрез рдбреЗрдЯрд╛рд╕реЗрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗ, рдЬрд┐рд╕рдореЗрдВ резреж рд╣рдЬрд╛рд░ рд╕реЗ рдЕрдзрд┐рдХ рдЦрд╛рджреНрдп рдЪрд┐рддреНрд░ рд╣реИрдВ, рдЬреЛ резрежрез рд╢реНрд░реЗрдгрд┐рдпреЛрдВ рдореЗрдВ рд╡рд┐рднрд╛рдЬрд┐рдд рд╣реИрдВред

рдЦрд╛рджреНрдп -резрежрез рдбреЗрдЯрд╛рд╕реЗрдЯ

рдбреЗрдЯрд╛рд╕реЗрдЯ рдбрд╛рдЙрдирд▓реЛрдб рдФрд░ рдЕрдирдкреИрдХ рдХрд░реЗрдВ:

 cd data wget http://data.vision.ee.ethz.ch/cvl/food-101.tar.gz tar -xzf food-101.tar.gz 

рд╣рдорд╛рд░реЗ рдкреНрд░рд╢рд┐рдХреНрд╖рдг рдореЗрдВ рдбреЗрдЯрд╛ рдкрд╛рдЗрдкрд▓рд╛рдЗрди рдЗрд╕ рддрд░рд╣ рд╕реЗ рдбрд┐рдЬрд╝рд╛рдЗрди рдХреА рдЧрдИ рд╣реИ рдХрд┐ рдбреЗрдЯрд╛рд╕реЗрдЯ рд╕реЗ рд╣рдореЗрдВ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдХреЛ рдкрд╛рд░реНрд╕ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ:

  1. рд╡рд░реНрдЧреЛрдВ рдХреА рд╕реВрдЪреА (рд╢реНрд░реЗрдгрд┐рдпрд╛рдВ)
  2. рдЯреНрдпреВрдЯреЛрд░рд┐рдпрд▓: рдЪрд┐рддреНрд░реЛрдВ рдХреЗ рд▓рд┐рдП рд░рд╛рд╕реНрддреЛрдВ рдХреА рд╕реВрдЪреА рдФрд░ рд╕рд╣реА рдЙрддреНрддрд░реЛрдВ рдХреА рд╕реВрдЪреА
  3. рд╕рддреНрдпрд╛рдкрди рд╕реЗрдЯ: рдЪрд┐рддреНрд░реЛрдВ рдХреЗ рд▓рд┐рдП рд░рд╛рд╕реНрддреЛрдВ рдХреА рд╕реВрдЪреА рдФрд░ рд╕рд╣реА рдЙрддреНрддрд░реЛрдВ рдХреА рд╕реВрдЪреА

рдпрджрд┐ рдЖрдкрдХрд╛ рдбреЗрдЯрд╛рд╕реЗрдЯ, рддреЛ рдЯреНрд░реЗрди рдФрд░ рд╕рддреНрдпрд╛рдкрди рдХреЗ рд▓рд┐рдП рдЖрдкрдХреЛ рд╕реЗрдЯ рдХреЛ рд╕реНрд╡рдпрдВ рддреЛрдбрд╝рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдлрд╝реВрдб -резреж рдореЗрдВ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдРрд╕рд╛ рд╡рд┐рднрд╛рдЬрди рд╣реИ, рдФрд░ рдпрд╣ рдЬрд╛рдирдХрд╛рд░реА meta рдбрд╛рдпрд░реЗрдХреНрдЯрд░реА рдореЗрдВ рд╕рдВрдЧреНрд░рд╣реАрдд рд╣реИред

 DATASET_ROOT = 'data/food-101/' train_data, val_data, classes = data.food101(DATASET_ROOT) num_classes = len(classes) 

рдбреЗрдЯрд╛ рдкреНрд░реЛрд╕реЗрд╕рд┐рдВрдЧ рдХреЗ рд▓рд┐рдП рдЬрд╝рд┐рдореНрдореЗрджрд╛рд░ рд╕рднреА рд╕рд╣рд╛рдпрдХ рдлрд╝рдВрдХреНрд╢рдВрд╕ рдХреЛ рдПрдХ рдЕрд▓рдЧ data.py рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рд▓реЗ рдЬрд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ:

data.py
 from os.path import join as opj import tensorflow as tf def parse_ds_subset(img_root, list_fpath, classes): ''' Parse a meta file with image paths and labels -> img_root: path to the root of image folders -> list_fpath: path to the file with the list (eg train.txt) -> classes: list of class names <- (list_of_img_paths, integer_labels) ''' fpaths = [] labels = [] with open(list_fpath, 'r') as f: for line in f: class_name, image_id = line.strip().split('/') fpaths.append(opj(img_root, class_name, image_id+'.jpg')) labels.append(classes.index(class_name)) return fpaths, labels def food101(dataset_root): ''' Get lists of train and validation examples for Food-101 dataset -> dataset_root: root of the Food-101 dataset <- ((train_fpaths, train_labels), (val_fpaths, val_labels), classes) ''' img_root = opj(dataset_root, 'images') train_list_fpath = opj(dataset_root, 'meta', 'train.txt') test_list_fpath = opj(dataset_root, 'meta', 'test.txt') classes_list_fpath = opj(dataset_root, 'meta', 'classes.txt') with open(classes_list_fpath, 'r') as f: classes = [line.strip() for line in f] train_data = parse_ds_subset(img_root, train_list_fpath, classes) val_data = parse_ds_subset(img_root, test_list_fpath, classes) return train_data, val_data, classes def imread_and_crop(fpath, inp_size, margin=0, random_crop=False): ''' Construct TF graph for image preparation: Read the file, crop and resize -> fpath: path to the JPEG image file (TF node) -> inp_size: size of the network input (eg 224) -> margin: cropping margin -> random_crop: perform random crop or central crop <- prepared image (TF node) ''' data = tf.read_file(fpath) img = tf.image.decode_jpeg(data, channels=3) img = tf.image.convert_image_dtype(img, dtype=tf.float32) shape = tf.shape(img) crop_size = tf.minimum(shape[0], shape[1]) - 2 * margin if random_crop: img = tf.random_crop(img, (crop_size, crop_size, 3)) else: # central crop ho = (shape[0] - crop_size) // 2 wo = (shape[0] - crop_size) // 2 img = img[ho:ho+crop_size, wo:wo+crop_size, :] img = tf.image.resize_images(img, (inp_size, inp_size), method=tf.image.ResizeMethod.AREA) return img def train_dataset(data, batch_size, epochs, inp_size, margin): ''' Prepare training data pipeline -> data: (list_of_img_paths, integer_labels) -> batch_size: training batch size -> epochs: number of training epochs -> inp_size: size of the network input (eg 224) -> margin: cropping margin <- (dataset, number_of_train_iterations) ''' num_examples = len(data[0]) iters = (epochs * num_examples) // batch_size def fpath_to_image(fpath, label): img = imread_and_crop(fpath, inp_size, margin, random_crop=True) return img, label dataset = tf.data.Dataset.from_tensor_slices(data) dataset = dataset.shuffle(buffer_size=num_examples) dataset = dataset.map(fpath_to_image) dataset = dataset.repeat(epochs) dataset = dataset.batch(batch_size, drop_remainder=True) return dataset, iters def val_dataset(data, batch_size, inp_size): ''' Prepare validation data pipeline -> data: (list_of_img_paths, integer_labels) -> batch_size: validation batch size -> inp_size: size of the network input (eg 224) <- (dataset, number_of_val_iterations) ''' num_examples = len(data[0]) iters = num_examples // batch_size def fpath_to_image(fpath, label): img = imread_and_crop(fpath, inp_size, 0, random_crop=False) return img, label dataset = tf.data.Dataset.from_tensor_slices(data) dataset = dataset.map(fpath_to_image) dataset = dataset.batch(batch_size, drop_remainder=True) return dataset, iters 


рдореЙрдбрд▓ рдкреНрд░рд╢рд┐рдХреНрд╖рдг


рдореЙрдбрд▓ рдкреНрд░рд╢рд┐рдХреНрд╖рдг рдХреЛрдб рдореЗрдВ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдЪрд░рдг рд╣реЛрддреЗ рд╣реИрдВ:

  1. рдмрд┐рд▓реНрдбрд┐рдВрдЧ рдЯреНрд░реЗрди / рд╕рддреНрдпрд╛рдкрди рдбреЗрдЯрд╛ рдкрд╛рдЗрдкрд▓рд╛рдЗрди
  2. рдмрд┐рд▓реНрдбрд┐рдВрдЧ рдЯреНрд░реЗрди / рд╕рддреНрдпрд╛рдкрди рдЧреНрд░рд╛рдл (рдиреЗрдЯрд╡рд░реНрдХ)
  3. рдЯреНрд░реЗрди рдЧреНрд░рд╛рдл рдкрд░ рдиреБрдХрд╕рд╛рди рдХреЗ рд╡рд░реНрдЧреАрдХрд░рдг рд╕рдорд╛рд░реЛрд╣ ( рдХреНрд░реЙрд╕ рдПрдиреНрдЯреНрд░рд╛рдкреА рд▓реЙрд╕ ) рдХреЛ рд╕рдВрд▓рдЧреНрди рдХрд░рдирд╛
  4. рдкреНрд░рд╢рд┐рдХреНрд╖рдг рдХреЗ рджреМрд░рд╛рди рд╕рддреНрдпрд╛рдкрди рдирдореВрдиреЗ рдкрд░ рднрд╡рд┐рд╖реНрдпрд╡рд╛рдгрд┐рдпреЛрдВ рдХреА рд╕рдЯреАрдХрддрд╛ рдХреА рдЧрдгрдирд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рдХреЛрдб
  5. рд╕реНрдиреИрдкрд╢реЙрдЯ рд╕реЗ рдкреВрд░реНрд╡ рдкреНрд░рд╢рд┐рдХреНрд╖рд┐рдд рддрд░рд╛рдЬреВ рд▓реЛрдб рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рддрд░реНрдХ
  6. рдкреНрд░рд╢рд┐рдХреНрд╖рдг рдХреЗ рд▓рд┐рдП рд╡рд┐рднрд┐рдиреНрди рд╕рдВрд░рдЪрдирд╛рдУрдВ рдХрд╛ рдирд┐рд░реНрдорд╛рдг
  7. рд╕реНрд╡рдпрдВ рд╕реАрдЦрдиреЗ рдХрд╛ рдЪрдХреНрд░ (рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ рдЕрдиреБрдХреВрд▓рди)

рдЧреНрд░рд╛рдл рдХреА рдЕрдВрддрд┐рдо рдкрд░рдд рдХреЛ рдЖрд╡рд╢реНрдпрдХ рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рдиреНрдпреВрд░реЙрдиреНрд╕ рдХреЗ рд╕рд╛рде рдмрдирд╛рдпрд╛ рдЧрдпрд╛ рд╣реИ рдФрд░ рдЗрд╕реЗ рдкреВрд░реНрд╡-рдкреНрд░рд╢рд┐рдХреНрд╖рд┐рдд рд╕реНрдиреИрдкрд╢реЙрдЯ рд╕реЗ рд▓реЛрдб рдХрд┐рдП рдЧрдП рдорд╛рдкрджрдВрдбреЛрдВ рдХреА рд╕реВрдЪреА рд╕реЗ рдмрд╛рд╣рд░ рд░рдЦрд╛ рдЧрдпрд╛ рд╣реИред

рдореЙрдбрд▓ рдкреНрд░рд╢рд┐рдХреНрд╖рдг рдХреЛрдб
 import numpy as np import tensorflow as tf import tensorflow.contrib.slim as slim tf.logging.set_verbosity(tf.logging.INFO) import model import data ########################################################### ### Settings ########################################################### INPUT_SIZE = 224 RANDOM_CROP_MARGIN = 10 TRAIN_EPOCHS = 20 TRAIN_BATCH_SIZE = 64 VAL_BATCH_SIZE = 128 LR_START = 0.001 LR_END = LR_START / 1e4 MOMENTUM = 0.9 VGG_PRETRAINED_CKPT = 'data/vgg_19.ckpt' CHECKPOINT_DIR = 'checkpoints/vgg19_food' LOG_LOSS_EVERY = 10 CALC_ACC_EVERY = 500 ########################################################### ### Build training and validation data pipelines ########################################################### train_ds, train_iters = data.train_dataset(train_data, TRAIN_BATCH_SIZE, TRAIN_EPOCHS, INPUT_SIZE, RANDOM_CROP_MARGIN) train_ds_iterator = train_ds.make_one_shot_iterator() train_x, train_y = train_ds_iterator.get_next() val_ds, val_iters = data.val_dataset(val_data, VAL_BATCH_SIZE, INPUT_SIZE) val_ds_iterator = val_ds.make_initializable_iterator() val_x, val_y = val_ds_iterator.get_next() ########################################################### ### Construct training and validation graphs ########################################################### with tf.variable_scope('', reuse=tf.AUTO_REUSE): train_logits = model.vgg_19(train_x, num_classes, is_training=True) val_logits = model.vgg_19(val_x, num_classes, is_training=False) ########################################################### ### Construct training loss ########################################################### loss = tf.losses.sparse_softmax_cross_entropy( labels=train_y, logits=train_logits) tf.summary.scalar('loss', loss) ########################################################### ### Construct validation accuracy ### and related functions ########################################################### def calc_accuracy(sess, val_logits, val_y, val_iters): acc_total = 0.0 acc_denom = 0 for i in range(val_iters): logits, y = sess.run((val_logits, val_y)) y_pred = np.argmax(logits, axis=1) correct = np.count_nonzero(y == y_pred) acc_denom += y_pred.shape[0] acc_total += float(correct) tf.logging.info('Validating batch [{} / {}] correct = {}'.format( i, val_iters, correct)) acc_total /= acc_denom return acc_total def accuracy_summary(sess, acc_value, iteration): acc_summary = tf.Summary() acc_summary.value.add(tag="accuracy", simple_value=acc_value) sess._hooks[1]._summary_writer.add_summary(acc_summary, iteration) ########################################################### ### Define set of VGG variables to restore ### Create the Restorer ### Define init callback (used by monitored session) ########################################################### vars_to_restore = tf.contrib.framework.get_variables_to_restore( exclude=['vgg_19/fc8']) vgg_restorer = tf.train.Saver(vars_to_restore) def init_fn(scaffold, sess): vgg_restorer.restore(sess, VGG_PRETRAINED_CKPT) ########################################################### ### Create various training structures ########################################################### global_step = tf.train.get_or_create_global_step() lr = tf.train.polynomial_decay(LR_START, global_step, train_iters, LR_END) tf.summary.scalar('learning_rate', lr) optimizer = tf.train.MomentumOptimizer(learning_rate=lr, momentum=MOMENTUM) training_op = slim.learning.create_train_op( loss, optimizer, global_step=global_step) scaffold = tf.train.Scaffold(init_fn=init_fn) ########################################################### ### Create monitored session ### Run training loop ########################################################### with tf.train.MonitoredTrainingSession(checkpoint_dir=CHECKPOINT_DIR, save_checkpoint_secs=600, save_summaries_steps=30, scaffold=scaffold) as sess: start_iter = sess.run(global_step) for iteration in range(start_iter, train_iters): # Gradient Descent loss_value = sess.run(training_op) # Loss logging if iteration % LOG_LOSS_EVERY == 0: tf.logging.info('[{} / {}] Loss = {}'.format( iteration, train_iters, loss_value)) # Accuracy logging if iteration % CALC_ACC_EVERY == 0: sess.run(val_ds_iterator.initializer) acc_value = calc_accuracy(sess, val_logits, val_y, val_iters) accuracy_summary(sess, acc_value, iteration) tf.logging.info('[{} / {}] Validation accuracy = {}'.format( iteration, train_iters, acc_value)) 


рдкреНрд░рд╢рд┐рдХреНрд╖рдг рд╢реБрд░реВ рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж, рдЖрдк TensorBoard рдЙрдкрдпреЛрдЧрд┐рддрд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЗрд╕рдХреА рдкреНрд░рдЧрддрд┐ рдХреЛ рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ, рдЬреЛ TensorFlow рдХреЗ рд╕рд╛рде рдмрдВрдбрд▓ рдореЗрдВ рдЖрддрд╛ рд╣реИ рдФрд░ рд╡рд┐рднрд┐рдиреНрди рдореИрдЯреНрд░рд┐рдХреНрд╕ рдФрд░ рдЕрдиреНрдп рдорд╛рдкрджрдВрдбреЛрдВ рдХреА рдХрд▓реНрдкрдирд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд╛рд░реНрдп рдХрд░рддрд╛ рд╣реИред

 tensorboard --logdir checkpoints/ 

TensorBoard рдореЗрдВ рдкреНрд░рд╢рд┐рдХреНрд╖рдг рдХреЗ рдЕрдВрдд рдореЗрдВ, рд╣рдо рдПрдХ рд▓рдЧрднрдЧ рд╕рд╣реА рддрд╕реНрд╡реАрд░ рджреЗрдЦрддреЗ рд╣реИрдВ: рдЯреНрд░реЗрди рдХреА рдХрдореА рдореЗрдВ рдХрдореА рдФрд░ рд╡реИрдзрддрд╛ рд╕рдЯреАрдХрддрд╛ рдореЗрдВ рд╡реГрджреНрдзрд┐

TensorBoard рдиреБрдХрд╕рд╛рди рдФрд░ рд╕рдЯреАрдХрддрд╛

рдирддреАрдЬрддрди, рд╣рдореЗрдВ checkpoints/vgg19_food рдореЗрдВ рд╕рд╣реЗрдЬреЗ рдЧрдП рд╕реНрдиреИрдкрд╢реЙрдЯ checkpoints/vgg19_food , рдЬрд┐рд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рд╣рдо рдЕрдкрдиреЗ рдореЙрдбрд▓ ( checkpoints/vgg19_food рдХреЗ рдкрд░реАрдХреНрд╖рдг рдХреЗ рджреМрд░рд╛рди рдХрд░реЗрдВрдЧреЗред

рдореЙрдбрд▓ рдкрд░реАрдХреНрд╖рдг


рдЕрдм рд╣рдорд╛рд░реЗ рдореЙрдбрд▓ рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд░реЗрдВред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП:

  1. рд╣рдо рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рдЕрдиреБрдорд╛рди рдХреЗ рд▓рд┐рдП рдбрд┐рдЬрд╝рд╛рдЗрди рдХрд┐рдпрд╛ рдЧрдпрд╛ рдПрдХ рдирдпрд╛ рдЧреНрд░рд╛рдл is_training=False ( is_training=False )
  2. рдПрдХ рд╕реНрдиреИрдкрд╢реЙрдЯ рд╕реЗ рднрд╛рд░ рдкреНрд░рд╢рд┐рдХреНрд╖рд┐рдд рднрд╛рд░
  3. рдбрд╛рдЙрдирд▓реЛрдб рдХрд░реЗрдВ рдФрд░ рдЗрдирдкреБрдЯ рдкрд░реАрдХреНрд╖рдг рдЫрд╡рд┐ рдХреЛ рдкреНрд░реАрдкреНрд░реЛрд╕реЗрд╕ рдХрд░реЗрдВред
  4. рдЪрд▓реЛ рддрдВрддреНрд░рд┐рдХрд╛ рдиреЗрдЯрд╡рд░реНрдХ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдЫрд╡рд┐ рдХреЛ рдбреНрд░рд╛рдЗрд╡ рдХрд░реЗрдВ рдФрд░ рднрд╡рд┐рд╖реНрдпрд╡рд╛рдгреА рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВ

inference.py
 import sys import numpy as np import imageio from skimage.transform import resize import tensorflow as tf import model ########################################################### ### Settings ########################################################### CLASSES_FPATH = 'data/food-101/meta/labels.txt' INP_SIZE = 224 # Input will be cropped and resized CHECKPOINT_DIR = 'checkpoints/vgg19_food' IMG_FPATH = 'data/food-101/images/bruschetta/3564471.jpg' ########################################################### ### Get all class names ########################################################### with open(CLASSES_FPATH, 'r') as f: classes = [line.strip() for line in f] num_classes = len(classes) ########################################################### ### Construct inference graph ########################################################### x = tf.placeholder(tf.float32, (1, INP_SIZE, INP_SIZE, 3), name='inputs') logits = model.vgg_19(x, num_classes, is_training=False) ########################################################### ### Create TF session and restore from a snapshot ########################################################### sess = tf.Session() snapshot_fpath = tf.train.latest_checkpoint(CHECKPOINT_DIR) restorer = tf.train.Saver() restorer.restore(sess, snapshot_fpath) ########################################################### ### Load and prepare input image ########################################################### def crop_and_resize(img, input_size): crop_size = min(img.shape[0], img.shape[1]) ho = (img.shape[0] - crop_size) // 2 wo = (img.shape[0] - crop_size) // 2 img = img[ho:ho+crop_size, wo:wo+crop_size, :] img = resize(img, (input_size, input_size), order=3, mode='reflect', anti_aliasing=True, preserve_range=True) return img img = imageio.imread(IMG_FPATH) img = img.astype(np.float32) img = crop_and_resize(img, INP_SIZE) img = img[None, ...] ########################################################### ### Run inference ########################################################### out = sess.run(logits, feed_dict={x:img}) pred_class = classes[np.argmax(out)] print('Input: {}'.format(IMG_FPATH)) print('Prediction: {}'.format(pred_class)) 


рдЕрдиреБрдорд╛рди

рдкреБрд╕реНрддрдХрд╛рд▓рдпреЛрдВ рдХреЗ рд╕рднреА рдЖрд╡рд╢реНрдпрдХ рд╕рдВрд╕реНрдХрд░рдгреЛрдВ рдХреЗ рд╕рд╛рде рдбреЙрдХ рдХрдВрдЯреЗрдирд░ рдмрдирд╛рдиреЗ рдФрд░ рдЪрд▓рд╛рдиреЗ рдХреЗ рд▓рд┐рдП рд╕рдВрд╕рд╛рдзрдиреЛрдВ рд╕рд╣рд┐рдд рд╕рднреА рдХреЛрдб, рдЗрд╕ рднрдВрдбрд╛рд░ рдореЗрдВ рд╣реИ - рд▓реЗрдЦ рдкрдврд╝рдиреЗ рдХреЗ рд╕рдордп, рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдХреЗ рдХреЛрдб рдореЗрдВ рдЕрдкрдбреЗрдЯ рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВред

рдХрд╛рд░реНрдпрд╢рд╛рд▓рд╛ рдореЗрдВ "рдорд╢реАрди рд▓рд░реНрдирд┐рдВрдЧ рдФрд░ рдбреЗрд╡рд▓рдкрд░реНрд╕ рдХреЗ рд▓рд┐рдП рддрдВрддреНрд░рд┐рдХрд╛ рдиреЗрдЯрд╡рд░реНрдХ" рдореИрдВ рдорд╢реАрди рд╕реАрдЦрдиреЗ рдХреЗ рдЕрдиреНрдп рдХрд╛рд░реНрдпреЛрдВ рдХрд╛ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд░реЗрдЧрд╛, рдФрд░ рдЫрд╛рддреНрд░ рдЧрд╣рди рд╕рддреНрд░ рдХреЗ рдЕрдВрдд рддрдХ рдЕрдкрдиреА рдкрд░рд┐рдпреЛрдЬрдирд╛рдУрдВ рдХреЛ рдкреНрд░рд╕реНрддреБрдд рдХрд░реЗрдВрдЧреЗред

Source: https://habr.com/ru/post/hi428255/


All Articles