FastText: рдХреЛрдб рдиреБрд╕реНрдЦрд╛

рд╢реБрдн рджрд┐рди, рджреЛрд╕реНрддреЛрдВ! рдореИрдВ рдЖрдкрдХреЗ рд▓рд┐рдП рдореВрд▓ рд▓реЗрдЦ рдХрд╛ рдПрдХ рд╢реМрдХрд┐рдпрд╛ рдЕрдиреБрд╡рд╛рдж рдкреНрд░рд╕реНрддреБрдд рдХрд░рддрд╛ рд╣реВрдВ: рдлрд╛рд╕реНрдЯрдЯреЗрдХреНрд╕реНрдЯ: рдорд╛рд░рд┐рдпрд╛ рдореЗрд╕реНрдЯреНрд░реЗ рджреНрд╡рд╛рд░рд╛ рдХреЛрдб рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдХрджрдо ред

рдПрдХ рдЫреЛрдЯреА рд╕реА рдЪреЗрддрд╛рд╡рдиреА: рдЙрдкрд▓рдмреНрдз рдХрд░рд╛рдИ рдЧрдИ рдХреБрдЫ рдЬрд╛рдирдХрд╛рд░реА рд▓реЗрдЦрдХ рдХреЗ рд╕рдордп рдФрд░ рдпрд╛рджреГрдЪреНрдЫрд┐рдХ рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЗ рдкрд╛рд░рд┐рдд рд╣реЛрдиреЗ рдХреЗ рдХрд╛рд░рдг рдкреВрд░реА рддрд░рд╣ рд╕реЗ рд╕рдЪ рдирд╣реАрдВ рд╣реЛ рд╕рдХрддреА рд╣реИред рдХрд┐рд╕реА рднреА рдорд╛рдорд▓реЗ рдореЗрдВ, рдХреЛрдИ рднреА рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рд╡рд╛рдВрдЫрдиреАрдп рд╣реЛрдЧреА!

рдЖрдкрдиреЗ рдЧреНрд░рдВрдереЛрдВ рдХреЗ рдЕрдкрдиреЗ рд╢рд░реАрд░ рдХреЛ рд╡реЗрдХреНрдЯрд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП FastText рдЬреИрд╕реЗ рдЙрдкрдХрд░рдг рдХрд╛ рд╕рд╛рдордирд╛ рдХрд┐рдпрд╛ рд╣реЛрдЧрд╛, рд▓реЗрдХрд┐рди рдХреНрдпрд╛ рдЖрдк рдЬрд╛рдирддреЗ рд╣реИрдВ рдХрд┐ FastText рдЖрдкрдХреЗ рд╡рд░реНрдЧреАрдХрд░рдг рд╕реЗ рднреА рдирд┐рдкрдЯ рд╕рдХрддрд╛ рд╣реИ? рдпрд╛ рд╢рд╛рдпрдж рд╡реЗ рдЬрд╛рдирддреЗ рдереЗ, рд▓реЗрдХрд┐рди рдХреНрдпрд╛ рд╡рд╣ рдЬрд╛рдирддрд╛ рд╣реИ рдХрд┐ рд╡рд╣ рдЗрд╕реЗ рдХреИрд╕реЗ рдХрд░рддрд╛ рд╣реИ? рдЪрд▓реЛ рдЗрд╕реЗ рдЕрдВрджрд░ рд╕реЗ рджреЗрдЦреЗрдВ ... рдореЗрд░рд╛ рдорддрд▓рдм рд╣реИ, рд╕реНрдХреНрд░реАрди рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗред

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

рдЖрдзрд┐рдХрд╛рд░рд┐рдХ рдкреНрд░рд▓реЗрдЦрди (рд╕реНрдкрд╖реНрдЯреАрдХрд░рдг рдХреЗ рд▓рд┐рдП рдмрд╣реБрдд рд╣реА рджреБрд░реНрд▓рдн) рдХреЛ рдкрдврд╝рддреЗ рд╣реБрдП, рдореБрдЭреЗ рдПрд╣рд╕рд╛рд╕ рд╣реБрдЖ рдХрд┐ рдЗрд╕рдореЗрдВ рдПрд▓реНрдЧреЛрд░рд┐рджрдо рдХрд╛ рдПрдХ рдмрдбрд╝рд╛ рд╣рд┐рд╕реНрд╕рд╛ рд╢рд╛рдорд┐рд▓ рд╣реИ рдЬреЛ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдкрд╛рд░рджрд░реНрд╢реА рдирд╣реАрдВ рд╣реЛ рд╕рдХрддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдпрд╣ рд╕реНрд╡рддрдВрддреНрд░ рд░реВрдк рд╕реЗ рдпрд╣ рдкрддрд╛ рд▓рдЧрд╛рдиреЗ рдХрд╛ рдирд┐рд░реНрдгрдп рд▓рд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ рдХрд┐ рдпрд╣ рдХреИрд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ рдФрд░ рдпрд╣ рдХреНрдпрд╛ рдЦрд╛рддрд╛ рд╣реИред рдореИрдВрдиреЗ рд░рдЪрдирд╛рдХрд╛рд░реЛрдВ рдХреЗ рдореБрдЦреНрдп рд▓реЗрдЦ рдФрд░ рдПрдирдПрд▓рдкреА рдореЗрдВ рд╕реНрдЯреИрдирдлреЛрд░реНрдб рдбреАрдк рд▓рд░реНрдирд┐рдВрдЧ рдХреЛрд░реНрд╕ рдкрд░ рдПрдХ рддреНрд╡рд░рд┐рдд рдирдЬрд╝рд░ рдбрд╛рд▓рдХрд░ рдкрдврд╝рдирд╛ рд╢реБрд░реВ рдХрд┐рдпрд╛ред рдЗрд╕ рд╕рд╛рд░реА рдЦреБрд╢реА рдХреА рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдореЗрдВ, рдореИрдВрдиреЗ рдХреЗрд╡рд▓ рдкреНрд░рд╢реНрди рдмрдврд╝рд╛рдПред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП: рдХрд┐ рд╕реНрдЯреИрдирдлреЛрд░реНрдб рдХреЗ рд╡реНрдпрд╛рдЦреНрдпрд╛рди рдХреЗ рджреМрд░рд╛рди рдФрд░ рд▓реЗрдЦ рдХреЗ рдПрдХ рд╣рд┐рд╕реНрд╕реЗ рдореЗрдВ рд╡реЗ рдПрди-рдЧреНрд░рд╛рдо рдХреЗ рдЙрдкрдпреЛрдЧ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдмрд╛рдд рдХрд░рддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рд╡реЗ рдЕрдкрдиреЗ рдЖрд╡реЗрджрди рдореЗрдВ рдХреЛрдИ рд╡рд┐рд╢реЗрд╖рддрд╛рдПрдВ рдирд╣реАрдВ рдХрд╣рддреЗ рд╣реИрдВред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдХрдорд╛рдВрдб рд▓рд╛рдЗрди рдореЗрдВ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдорд╛рдкрджрдВрдбреЛрдВ рдореЗрдВ рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд рдмрд╛рд▓реНрдЯреА рд╣реА рд╢рд╛рдорд┐рд▓ рд╣реИ рдЬрд┐рд╕ рдкрд░ рдХреЗрд╡рд▓ "рдХрдВрдЯреЗрдирд░ (рдмрд╛рд▓реНрдЯреА) рдХреА рд╕рдВрдЦреНрдпрд╛" рдЬреИрд╕реА рдзреНрд╡рдирд┐ рд╣реЛрддреА рд╣реИред рдЗрди рдПрди-рдЧреНрд░рд╛рдореЛрдВ рдХреА рдЧрдгрдирд╛ рдХреИрд╕реЗ рдХреА рдЬрд╛рддреА рд╣реИ? рдмрд╛рд▓реНрдЯреА? рдпрд╣ рд╕реНрдкрд╖реНрдЯ рдирд╣реАрдВ рд╣реИ ... рдПрдХ рд╡рд┐рдХрд▓реНрдк рд╢реЗрд╖ рд╣реИ, рдХреЛрдб рджреЗрдЦреЗрдВGitHub ред

рд╕рднреА рдЕрдЪреНрдЫреЗ рдХреЛ рджреЗрдЦрдиреЗ рдХреЗ рдмрд╛рдж, рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдкрддрд╛ рдЪрд▓рд╛


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

рдореЙрдбрд▓ рдкрд░рд┐рдЪрдп


рдЫрд╡рд┐

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

рдЫрд╡рд┐

рдЬрд╣рд╛рдВ:

  • x_n n-gram рдореЗрдВ рдПрдХ рд╢рдмреНрдж рдХрд╛ рдкреНрд░рддрд┐рдирд┐рдзрд┐рддреНрд╡ рд╣реИред
  • рдФрд░ рдпрд╣ рдПрдХ рд▓реБрдХ_рдЕрдк рдореИрдЯреНрд░рд┐рдХреНрд╕ рд╣реИ рдЬреЛ рдХрд┐рд╕реА рд╢рдмреНрдж рдХреЗ рдПрдореНрдмреЗрдбрд┐рдВрдЧ рдХреЛ рдирд┐рдХрд╛рд▓рддрд╛ рд╣реИред
  • рдпрд╣ рдЖрдЙрдЯрдкреБрдЯ рдХрд╛ рдПрдХ рд░реИрдЦрд┐рдХ рдкрд░рд┐рд╡рд░реНрддрди рд╣реИред
  • f рд╕реАрдзреЗ рд╕реЙрдлреНрдЯрдореИрдХреНрд╕ рдлрд╝рдВрдХреНрд╢рди рдХреЛ рд╕реНрд╡рдпрдВ рдХрд░рддрд╛ рд╣реИред

рд╕рд╛рдорд╛рдиреНрдп рддреМрд░ рдкрд░ рд╕рдм рдХреБрдЫ рдЗрддрдирд╛ рдмреБрд░рд╛ рдирд╣реАрдВ рд╣реИ, рд▓реЗрдХрд┐рди рдлрд┐рд░ рднреА рдЖрдЗрдП рдХреЛрдб рдкрд░ рдПрдХ рдирдЬрд╝рд░ рдбрд╛рд▓рддреЗ рд╣реИрдВ:

рдПрдХ рд╡рд┐рдЪрд╛рд░ рдЕрдиреБрд╡рд╛рдж рдХреЗ рд░реВрдк рдореЗрдВ рдХреЛрдб


рд╕реНрд░реЛрдд рдбреЗрдЯрд╛ рдХреЗ рд╕рд╛рде рдлрд╝рд╛рдЗрд▓ рдЬрд┐рд╕реЗ рд╣рдо рдЕрдкрдиреЗ рдХреНрд▓рд╛рд╕рд┐рдлрд╝рд╛рдпрд░ рдХреЗ рд▓рд┐рдП рдЖрд╡реЗрджрди рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдЙрд╕реЗ рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдлрд╝реЙрд░реНрдо рдХрд╛ рдкрд╛рд▓рди рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП: __label__0 (рдкрд╛рда)ред

рдЙрджрд╛рд╣рд░рдг рдХреЗ рд░реВрдк рдореЗрдВ:
__label__cat рдпрд╣ рдЪреЛрд░реА рдмрд┐рд▓реНрд▓рд┐рдпреЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╣реИред
__label__dog рдпрд╣ рдкрд╛рда рдХреБрддреНрддреЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╣реИред

рд╕реНрд░реЛрдд рдлрд╝рд╛рдЗрд▓ рдХрд╛ рдЙрдкрдпреЛрдЧ рдЯреНрд░реЗрди рдлрд╝рдВрдХреНрд╢рди рдХреЗ рддрд░реНрдХ рдХреЗ рд░реВрдк рдореЗрдВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ ред рдЯреНрд░реЗрди рдлрд╝рдВрдХреНрд╢рди рдкреНрд░рд╛рд░рдВрдн рдФрд░ рдмрд╛рдж рдореЗрдВ рдбрд┐рдХреНрдЯреНрд░реА_ рд╡реЗрд░рд┐рдПрдмрд▓ рдХреЗ рднрд░рдиреЗ рд╕реЗ рд╢реБрд░реВ рд╣реЛрддрд╛ рд╣реИ ред

void FastText::train(const Args args) {
  args_ = std::make_shared<Args>(args);
  dict_ = std::make_shared<Dictionary>(args_);
  if (args_->input == "-") {
    // manage expectations
    throw std::invalid_argument("Cannot use stdin for training!");
  }
  std::ifstream ifs(args_->input);
  if (!ifs.is_open()) {
    throw std::invalid_argument(
        args_->input + " cannot be opened for training!");
  }
  dict_->readFromFile(ifs);

рдбрд┐рдХреНрд╢рдирд░реА_ рдбрд┐рдХреНрд╢рдирд░реА рдХреНрд▓рд╛рд╕ рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг рд╣реИред


Dictionary::Dictionary(std::shared_ptr<Args> args) : args_(args),
  word2int_(MAX_VOCAB_SIZE, -1), size_(0), nwords_(0), nlabels_(0),
  ntokens_(0), pruneidx_size_(-1) {}

рд╕реНрд░реЛрдд рдлрд╝рд╛рдЗрд▓ рдХреЗ рд╡рд╛рдХреНрдпреЛрдВ рдХреЛ рдкрдврд╝рдиреЗ рдФрд░ рдкрд╛рд░реНрд╕ рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж, рд╣рдо рджреЛ рд╡реИрдХреНрдЯрд░ рднрд░рддреЗ рд╣реИрдВ:

  • рд╢рдмреНрдж_ рдЬрд┐рд╕рдореЗрдВ рдкрд╛рда рд╕реЗ рдирд┐рдХрд╛рд▓реЗ рдЧрдП рдЕрджреНрд╡рд┐рддреАрдп рд╢рдмреНрдж рд╣реИрдВ
  • word2int_ рдореЗрдВ рдЕрдкрдиреА рд╕реНрдерд┐рддрд┐ рдХреЗ рдЕрдиреБрд╕рд╛рд░ рдкреНрд░рддреНрдпреЗрдХ рд╢рдмреНрдж рдХреЗ рд▓рд┐рдП рд╣реИрд╢ рдпреБрдХреНрдд words_ рд╡реЗрдХреНрдЯрд░ ред рдпрд╣ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдмрд╣реБрдд рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдореИрдЯреНрд░рд┐рдХреНрд╕ рдП рдХреЗ рдПрдореНрдмреЗрдбрд┐рдВрдЧ рдХреЗ рд▓рд┐рдП рдЦреЛрдЬ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛

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

struct entry {
  std::string word;
  int64_t count;
  entry_type type;
  std::vector<int32_t> subwords;
};

рд╢рдмреНрдж рдпрд╛ рдЯреИрдЧ рдХреЛ рд╢рдмреНрдж 2int_ рдЪрд░ рдореЗрдВ рдЬреЛрдбрд╝рдХрд░ , рдЯрдХрд░рд╛рд╡ рдХреЛ рдЗрд╕ рддрд░рд╣ рд╕реЗ рд╣рд▓ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдХрд┐ рд╣рдо рдХрднреА рднреА рджреЛ рдЕрд▓рдЧ-рдЕрд▓рдЧ рд╢рдмреНрджреЛрдВ рдХреЛ рд╕рдВрджрд░реНрднрд┐рдд рдирд╣реАрдВ рдХрд░рддреЗ рд╣реИрдВ рдЬрд┐рдирдореЗрдВ рдПрдХ рд╣реА рд╕реВрдЪрдХрд╛рдВрдХ рд╣реЛрддрд╛ рд╣реИред рд╡рд╣рд╛рдБ рдмрд╕ рдХреЛрдИ рдирд╣реАрдВ рд╣реЛрдЧрд╛

int32_t Dictionary::find(const std::string& w, uint32_t h) const {
  int32_t word2intsize = word2int_.size();
  int32_t id = h % word2intsize;
  while (word2int_[id] != -1 && words_[word2int_[id]].word != w) {
    id = (id + 1) % word2intsize;
  }
  return id;
}

int32_t Dictionary::find(const std::string& w) const {
  return find(w, hash(w));
}

void Dictionary::add(const std::string& w) {
  int32_t h = find(w);
  ntokens_++;
  if (word2int_[h] == -1) {
    entry e;
    e.word = w;
    e.count = 1;
    e.type = getType(w);
    words_.push_back(e);
    word2int_[h] = size_++;
  } else {
    words_[word2int_[h]].count++;
  }
}

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


void Dictionary::readFromFile(std::istream& in) {
  std::string word;
  int64_t minThreshold = 1;
  while (readWord(in, word)) {
    add(word);
    if (ntokens_ % 1000000 == 0 && args_->verbose > 1) {
      std::cerr << "\rRead " << ntokens_  / 1000000 << "M words" << std::flush;
    }
    if (size_ > 0.75 * MAX_VOCAB_SIZE) {
      minThreshold++;
      threshold(minThreshold, minThreshold);
    }
  }
  threshold(args_->minCount, args_->minCountLabel);
  initTableDiscard();
  initNgrams();

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

рд╕рд╛рдорд╛рдиреНрдп рддреМрд░ рдкрд░, рдкрд╛рда рдХреЗ рдкреНрд░рддреНрдпреЗрдХ рд╢рдмреНрдж рдХреЗ рд▓рд┐рдП, рдЖрдк рд╕рдм - рдкрд╛рд╕рд╡рд░реНрдб ... рдПрди-рдЧреНрд░рд╛рдо рд╡рд░реНрдг рдкреНрд░рджрд╛рди рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ ред
рдПрдВрдмреЗрдбрд┐рдВрдЧ рдореИрдЯреНрд░рд┐рдХреНрд╕ A рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рддрд╛ рд╣реИ:

  • рдкрд╛рда рдХреЗ рд▓рд┐рдП рдЙрдкрд▓рдмреНрдз рд╢рдмреНрджрдХреЛрд╢ рд╕реЗ рдкреНрд░рддреНрдпреЗрдХ рд╢рдмреНрдж рдХреЗ рд▓рд┐рдП рдкреНрд░рд╛рд░рдВрднрд┐рдХ nwords_ рд▓рд╛рдЗрдиреЗрдВ рдЬрд┐рдирдореЗрдВ рдПрдореНрдмреЗрдбрд┐рдВрдЧ рд╣реИред
  • рдкреНрд░рддреНрдпреЗрдХ рдПрди-рдЧреНрд░рд╛рдо рдХреЗ рдкрд╛рддреНрд░реЛрдВ рдХреЗ рд▓рд┐рдП рдПрдореНрдмреЗрдбрд┐рдВрдЧ рд╡рд╛рд▓реА рд▓рд╛рдЗрдиреЛрдВ рдХреА рдмрд╛рд▓реНрдЯреА рдХрд╛ рдкрд╛рд▓рди рдХрд░реЗрдВ


void Dictionary::initNgrams() {
  for (size_t i = 0; i < size_; i++) {
    std::string word = BOW + words_[i].word + EOW;
    words_[i].subwords.clear();
    words_[i].subwords.push_back(i);
    if (words_[i].word != EOS) {
      computeSubwords(word, words_[i].subwords);
    }
  }
}

void Dictionary::computeSubwords(const std::string& word,
                               std::vector<int32_t>& ngrams) const {
  for (size_t i = 0; i < word.size(); i++) {
    std::string ngram;
    if ((word[i] & 0xC0) == 0x80) continue;
    for (size_t j = i, n = 1; j < word.size() && n <= args_->maxn; n++) {
      ngram.push_back(word[j++]);
      while (j < word.size() && (word[j] & 0xC0) == 0x80) {
        ngram.push_back(word[j++]);
      }
      if (n >= args_->minn && !(n == 1 && (i == 0 || j == word.size()))) {
        int32_t h = hash(ngram) % args_->bucket;
        pushHash(ngrams, h);
      }
    }
  }
}

void Dictionary::pushHash(std::vector<int32_t>& hashes, int32_t id) const {
  if (pruneidx_size_ == 0 || id < 0) return;
  if (pruneidx_size_ > 0) {
    if (pruneidx_.count(id)) {
      id = pruneidx_.at(id);
    } else {
      return;
    }
  }
  hashes.push_back(nwords_ + id);
}

рдЗрд╕рд▓рд┐рдП рд╣рдордиреЗ рд░рд╣рд╕реНрдпрдордп рдПрди-рдЧреНрд░рд╛рдо рдкрд╛рддреНрд░реЛрдВ рдХрд╛ рдЕрдиреБрдорд╛рди рд▓рдЧрд╛рдпрд╛ред рдЕрдм рд╢рдмреНрджреЛрдВ рдХреЗ рдПрди-рдЧреНрд░рд╛рдо рд╕реЗ рдирд┐рдкрдЯрддреЗ рд╣реИрдВред рдЯреНрд░реЗрди

рдлрд╝рдВрдХреНрд╢рди рдкрд░ рд▓реМрдЯрддреЗ рд╣реБрдП , рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдирд┐рд░реНрджреЗрд╢реЛрдВ рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ:

  if (args_->pretrainedVectors.size() != 0) {
    loadVectors(args_->pretrainedVectors);
  } else {
    input_ = std::make_shared<Matrix>(dict_->nwords()+args_->bucket, args_->dim);
    input_->uniform(1.0 / args_->dim);
  }

  if (args_->model == model_name::sup) {
    output_ = std::make_shared<Matrix>(dict_->nlabels(), args_->dim);
  } else {
    output_ = std::make_shared<Matrix>(dict_->nwords(), args_->dim);
  }
  output_->zero();
  startThreads();

рдпрд╣ рд╡рд╣ рдЬрдЧрд╣ рд╣реИ рдЬрд╣рд╛рдВ рдПрдореНрдмреЗрдбрд┐рдВрдЧ рдореИрдЯреНрд░рд┐рдХреНрд╕ рдП рдХреЛ рдЗрдирд┐рд╢рд┐рдпрд▓рд╛рдЗрдЬрд╝ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред рдпрд╣ рдЗрдВрдЧрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП рдХрд┐ рдЕрдЧрд░ pretrainedVectors рдЗрд╕ рдлрд╝рдВрдХреНрд╢рди рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдпрд╣ рдЪрд░ рдкреВрд░реНрдг рдорд╛рдирд╛ рдЬрд╛рддрд╛ рд╣реИред рдпрджрд┐ рдРрд╕рд╛ рдирд╣реАрдВ рд╣реЛрддрд╛ рд╣реИ, рддреЛ рдореИрдЯреНрд░рд┐рдХреНрд╕ рдХреЛ рдпрд╛рджреГрдЪреНрдЫрд┐рдХ рд╕рдВрдЦреНрдпрд╛ -1 / рдордВрдж рдФрд░ 1 / рдордВрдж рдХреЗ рд╕рд╛рде рдкреНрд░рд╛рд░рдВрдн рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ , рдЬрд╣рд╛рдВ рдордВрдж рд╣рдорд╛рд░реЗ рдПрдореНрдмреЗрдбрд┐рдВрдЧ рдХрд╛ рдЖрдХрд╛рд░ рд╣реИред рдореИрдЯреНрд░рд┐рдХреНрд╕ рдП рдХрд╛ рдЖрдпрд╛рдо ( n_words_ + рдмрд╛рд▓реНрдЯреА ; рдордВрдж ), рдЕрд░реНрдерд╛рдд рд╣рдо рдкреНрд░рддреНрдпреЗрдХ рд╢рдмреНрдж рдХреЗ рд▓рд┐рдП рдпреЗ рд╕рднреА рдПрдореНрдмреЗрдбрд┐рдВрдЧ рд╕реЗрдЯ рдХрд░рдиреЗ рдЬрд╛ рд░рд╣реЗ рд╣реИрдВред рдЗрд╕ рдЪрд░рдг рдореЗрдВ рдЖрдЙрдЯрдкреБрдЯ рдХреЛ рдЗрдирд┐рд╢рд┐рдпрд▓рд╛рдЗрдЬрд╝ рднреА рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред

рдирддреАрдЬрддрди, рд╣рдореЗрдВ рд╡рд╣ рд╣рд┐рд╕реНрд╕рд╛ рдорд┐рд▓рддрд╛ рд╣реИ рдЬрд╣рд╛рдВ рд╣рдо рдЕрдкрдиреЗ рдореЙрдбрд▓ рдХрд╛ рдкреНрд░рд╢рд┐рдХреНрд╖рдг рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВред


void FastText::trainThread(int32_t threadId) {
  std::ifstream ifs(args_->input);
  utils::seek(ifs, threadId * utils::size(ifs) / args_->thread);

  Model model(input_, output_, args_, threadId);
  if (args_->model == model_name::sup) {
    model.setTargetCounts(dict_->getCounts(entry_type::label));
  } else {
    model.setTargetCounts(dict_->getCounts(entry_type::word));
  }

  const int64_t ntokens = dict_->ntokens();
  int64_t localTokenCount = 0;
  std::vector<int32_t> line, labels;
  while (tokenCount_ < args_->epoch * ntokens) {
    real progress = real(tokenCount_) / (args_->epoch * ntokens);
    real lr = args_->lr * (1.0 - progress);
    if (args_->model == model_name::sup) {
      localTokenCount += dict_->getLine(ifs, line, labels);
      supervised(model, lr, line, labels);
    } else if (args_->model == model_name::cbow) {
      localTokenCount += dict_->getLine(ifs, line, model.rng);
      cbow(model, lr, line);
    } else if (args_->model == model_name::sg) {
      localTokenCount += dict_->getLine(ifs, line, model.rng);
      skipgram(model, lr, line);
    }
    if (localTokenCount > args_->lrUpdateRate) {
      tokenCount_ += localTokenCount;
      localTokenCount = 0;
      if (threadId == 0 && args_->verbose > 1)
        loss_ = model.getLoss();
    }
  }
  if (threadId == 0)
    loss_ = model.getLoss();
  ifs.close();
}

рдХреЛрдб рдХреЗ рдЗрд╕ рднрд╛рдЧ рдореЗрдВ рджреЛ рдореБрдЦреНрдп рдмрд┐рдВрджреБ рд╣реИрдВред рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, getLine рдлрд╝рдВрдХреНрд╢рди рдбрд┐рдХреНрдЯреЗрдб_ рд╡реЗрд░рд┐рдПрдмрд▓ рдХреЛ рдХреЙрд▓ рдХрд░рддрд╛ рд╣реИ ред рджреВрд╕рд░рд╛, рдкрд░реНрдпрд╡реЗрдХреНрд╖рд┐рдд рдлрд╝рдВрдХреНрд╢рди рдХрд╣рд▓рд╛рддрд╛ рд╣реИ ред

int32_t Dictionary::getLine(std::istream& in,
                            std::vector<int32_t>& words,
                            std::vector<int32_t>& labels) const {
  std::vector<int32_t> word_hashes;
  std::string token;
  int32_t ntokens = 0;

  reset(in);
  words.clear();
  labels.clear();
  while (readWord(in, token)) {
    uint32_t h = hash(token);
    int32_t wid = getId(token, h);
    entry_type type = wid < 0 ? getType(token) : getType(wid);

    ntokens++;
    if (type == entry_type::word) {
      addSubwords(words, token, wid);
      word_hashes.push_back(h);
    } else if (type == entry_type::label && wid >= 0) {
      labels.push_back(wid - nwords_);
    }<source lang="cpp">
    if (token == EOS) break;
  }
  addWordNgrams(words, word_hashes, args_->wordNgrams);
  return ntokens;
}

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

рдЙрдирдХреЗ рд▓рд┐рдП рдмрдирд╛рдП рдЧрдП рд╡реИрдХреНрдЯрд░ рд╕реЗ рд╕реАрдзреЗ рдкрд╛рда (рдХреЙрд░реНрдкрд╕ рд╕реЗ рд╡рд╛рдХреНрдп) рдХреЛ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдкрдврд╝рдиреЗ рдФрд░ рдЬреЛрдбрд╝рдиреЗ рдХреЗ рдмрд╛рдж, рд╣рдореЗрдВ рдПрди-рдЧреНрд░рд╛рдо рдХреЛ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рдХреЛрдб рдХрд╛ рдПрдХ рд╣рд┐рд╕реНрд╕рд╛ рдорд┐рд▓рддрд╛ рд╣реИред рдпрд╣ addWordNgrams рдлрд╝рдВрдХреНрд╢рди рд╣реИ ред

void Dictionary::addWordNgrams(std::vector<int32_t>& line,
                               const std::vector<int32_t>& hashes,
                               int32_t n) const {
  for (int32_t i = 0; i < hashes.size(); i++) {
    uint64_t h = hashes[i];
    for (int32_t j = i + 1; j < hashes.size() && j < i + n; j++) {
      h = h * 116049371 + hashes[j];
      pushHash(line, h % args_->bucket);
    }
  }
}

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

h=hтИЧ116049371+hashes[j]

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

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

рд╡рд╛рдХреНрдп рдкрдврд╝рдиреЗ рдХреЗ рдмрд╛рдж, рдкрд░реНрдпрд╡реЗрдХреНрд╖рд┐рдд рдлрд╝рдВрдХреНрд╢рди рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ ред рдпрджрд┐ рдСрдлрд╝рд░ рдореЗрдВ рдХрдИ рдЯреИрдЧ рд╣реИрдВ, рддреЛ рд╣рдо рдмреЗрддрд░рддреАрдм рдврдВрдЧ рд╕реЗ рдЙрдирдореЗрдВ рд╕реЗ рдПрдХ рдХрд╛ рдЪрдпрди рдХрд░рддреЗ рд╣реИрдВред


void FastText::supervised(
    Model& model,
    real lr,
    const std::vector<int32_t>& line,
    const std::vector<int32_t>& labels) {
  if (labels.size() == 0 || line.size() == 0) return;
  std::uniform_int_distribution<> uniform(0, labels.size() - 1);
  int32_t i = uniform(model.rng);
  model.update(line, labels[i], lr);
}

рдФрд░ рдЕрдВрдд рдореЗрдВ, рдореЙрдбрд▓ рдЕрдкрдбреЗрдЯ рдлрд╝рдВрдХреНрд╢рдиред

void Model::computeHidden(const std::vector<int32_t>& input, Vector& hidden) const {
  assert(hidden.size() == hsz_);
  hidden.zero();
  for (auto it = input.cbegin(); it != input.cend(); ++it) {
    if(quant_) {
      hidden.addRow(*qwi_, *it);
    } else {
      hidden.addRow(*wi_, *it);
    }
  }
  hidden.mul(1.0 / input.size());
}

void Model::update(const std::vector<int32_t>& input, int32_t target, real lr) {
  assert(target >= 0);
  assert(target < osz_);
  if (input.size() == 0) return;
  computeHidden(input, hidden_);
  if (args_->loss == loss_name::ns) {
    loss_ += negativeSampling(target, lr);
  } else if (args_->loss == loss_name::hs) {
    loss_ += hierarchicalSoftmax(target, lr);
  } else {
    loss_ += softmax(target, lr);
  }
  nexamples_ += 1;

  if (args_->model == model_name::sup) {
    grad_.mul(1.0 / input.size());
  }
  for (auto it = input.cbegin(); it != input.cend(); ++it) {
    wi_->addRow(grad_, *it, 1.0);
  }
}

рдкрд░реНрдпрд╡реЗрдХреНрд╖рд┐рдд рдлрд╝рдВрдХреНрд╢рди рд╕реЗ рдЧреБрдЬрд░рдиреЗ рд╡рд╛рд▓реЗ рдЗрдирдкреБрдЯ рдЪрд░ рдореЗрдВ рд╡рд╛рдХреНрдп рдХреЗ рдЙрдирдХреЗ рд╕рднреА рдШрдЯрдХреЛрдВ (рд╢рдмреНрджреЛрдВ, рд╢рдмреНрджреЛрдВ рдХреЗ рдПрди-рдЧреНрд░рд╛рдо рдФрд░ рдкреНрд░рддреАрдХреЛрдВ) рдХреЗ рд╕реВрдЪрдХрд╛рдВрдХреЛрдВ рдХреА рдПрдХ рд╕реВрдЪреА рд╣реЛрддреА рд╣реИред рд▓рдХреНрд╖реНрдп рдПрдХ рд╡рд░реНрдЧ рдХреЛ рдЖрдЙрдЯрдкреБрдЯ рдкрд░ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рдирд╛ рд╣реИред рдХрдореНрдкреНрдпреВрдЯреЗрдб рдлрд╝рдВрдХреНрд╢рди рдЗрдирдкреБрдЯ рдХреЗ рдкреНрд░рддреНрдпреЗрдХ рдШрдЯрдХ рдХреЗ рд▓рд┐рдП wi_ рдореИрдЯреНрд░рд┐рдХреНрд╕ рдореЗрдВ рдЙрдиреНрд╣реЗрдВ рдЦреЛрдЬрдХрд░ рдФрд░ рдФрд╕рдд ( addRow рдХреЛ рдЙрдирдХреЗ рдЖрдХрд╛рд░ рд╕реЗ рд╡рд┐рднрд╛рдЬрд┐рдд рдФрд░ рд╡рд┐рднрд╛рдЬрд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ) рдХреЗ рд▓рд┐рдП рд╕рднреА рдПрдореНрдмреЗрдбрд┐рдВрдЧ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рддрд╛ рд╣реИ ред Hide_ рд╡реЗрдХреНрдЯрд░ рдХреЛ рд╕рдВрд╢реЛрдзрд┐рдд рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж , рдЙрдиреНрд╣реЗрдВ рд╕реЙрдлреНрдЯрдореИрдХреНрд╕ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рд╕рдХреНрд░рд┐рдпрдг рдХреЗ рд▓рд┐рдП рднреЗрдЬреЗрдВ рдФрд░ рдПрдХ рд▓реЗрдмрд▓ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░реЗрдВред

рдХреЛрдб рдХрд╛ рдпрд╣ рдЦрдВрдб рд╕реЙрдлреНрдЯрдореИрдХреНрд╕ рд╕рдХреНрд░рд┐рдпрдг рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рджрд┐рдЦрд╛рддрд╛ рд╣реИ ред рд▓реЙрдЧ-рд▓реЙрд╕ рдХреА рдЧрдгрдирд╛ рднреА рдХреА рдЬрд╛рддреА рд╣реИ ред

void Model::computeOutputSoftmax(Vector& hidden, Vector& output) const {
  if (quant_ && args_->qout) {
    output.mul(*qwo_, hidden);
  } else {
    output.mul(*wo_, hidden);
  }
  real max = output[0], z = 0.0;
  for (int32_t i = 0; i < osz_; i++) {
    max = std::max(output[i], max);
  }
  for (int32_t i = 0; i < osz_; i++) {
    output[i] = exp(output[i] - max);
    z += output[i];
  }
  for (int32_t i = 0; i < osz_; i++) {
    output[i] /= z;
  }
}

void Model::computeOutputSoftmax() {
  computeOutputSoftmax(hidden_, output_);
}

real Model::softmax(int32_t target, real lr) {
  grad_.zero();
  computeOutputSoftmax();
  for (int32_t i = 0; i < osz_; i++) {
    real label = (i == target) ? 1.0 : 0.0;
    real alpha = lr * (label - output_[i]);
    grad_.addRow(*wo_, i, alpha);
    wo_->addRow(hidden_, i, alpha);
  }
  return -log(output_[target]);
}

рдЗрд╕ рдкрджреНрдзрддрд┐ рдХреЗ рдЙрдкрдпреЛрдЧ рд╕реЗ, рд╣рдореЗрдВ рд╢рдмреНрджреЛрдВ рдФрд░ рд╡рд░реНрдгреЛрдВ рдХреЗ рдПрди-рдЧреНрд░рд╛рдо рдХреЗ рдЖрдХрд╛рд░ рдореЗрдВ рд╡реГрджреНрдзрд┐ рдирд╣реАрдВ рдорд┐рд▓реЗрдЧреАред рд╡рд┐рдХрд╛рд╕ рдкрд╣рд▓реЗ рд╕реЗ рдЙрдкрд▓рдмреНрдз рдмрд╛рд▓реНрдЯрд┐рдпреЛрдВ рдХреА рд╕рдВрдЦреНрдпрд╛ рд╕реЗ рд╕реАрдорд┐рдд рд╣реИ ред

рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ, FastText N-gr рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рд╣рдо рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд╡рд┐рдХрд▓реНрдкреЛрдВ рдХреА рд╕рд▓рд╛рд╣ рджреЗрддреЗ рд╣реИрдВ:

  • рд╣рд┐рд░рди = 2,000,000; рд╢рдмреНрджрдЧреНрд░рд╛рдо> 1 рдпрд╛ рдЕрдзрд┐рдХрддрдо> 0
  • рдордВрдж = резрежреж
  • n_output = 2
  • n_words = 500000

рдХреБрд▓ рдорд┐рд▓рд╛рдХрд░, рд╣рдореЗрдВ рдкреНрд░рд╢рд┐рдХреНрд╖рдг рдХреЗ рд▓рд┐рдП рдХрд╛рдлреА рдмрдбрд╝реА рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рдкреИрд░рд╛рдореАрдЯрд░ рдорд┐рд▓рддреЗ рд╣реИрдВ

(5000000+2000000)тИЧ100+(2тИЧ100)=250,000,000


рдмрд╣реБрдд рдЕрдзрд┐рдХ, рдпрд╣ рдирд╣реАрдВ рд╣реИ?) рдЬреИрд╕рд╛ рдХрд┐ рд╣рдо рдЗрд╕ рддрд░рд╣ рдХреЗ рдПрдХ рд╕рд░рд▓ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рднреА рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ, рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдХрд╛рдлреА рдмрдбрд╝реА рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рдкреИрд░рд╛рдореАрдЯрд░ рд╣реИрдВ, рдЬреЛ рдХрд┐ рдЧрд╣рди рд╢рд┐рдХреНрд╖рдг рд╡рд┐рдзрд┐рдпреЛрдВ рдХреА рдмрд╣реБрдд рд╡рд┐рд╢рд┐рд╖реНрдЯ рд╣реИред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдХреНрд░рдо рджрд┐рдЦрд╛рдиреЗ рдХреЗ рд▓рд┐рдП 2_000_000 рдХреЗ рд▓рд┐рдП рд▓реА рдЧрдИ N-gr рдХреА рд╕рдВрдЦреНрдпрд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рд╕рд╛рдорд╛рдиреНрдп рддреМрд░ рдкрд░, рдХреБрдЫ рд╣рд╛рдЗрдкрд░рдкрд░рдореЗрдЯрд░реНрд╕, рдЬреИрд╕реЗ рдмрд╛рд▓реНрдЯреА рдпрд╛ рд╕реИрдВрдкрд▓рд┐рдВрдЧ рдереНрд░реЗрд╢реЛрд▓реНрдб рдХреЛ рдЯреНрдпреВрди рдХрд░рдХреЗ рдореЙрдбрд▓ рдХреА рдЬрдЯрд┐рд▓рддрд╛ рдХреЛ рдХрдо рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред

рдХреБрдЫ рд▓рд┐рдВрдХ рдЙрдкрдпреЛрдЧреА рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВ:
research.fb.com/fasttext
arxiv.org/pdf/1607.01759.pdf рдФрд░ arxiv.org/pdf/1607.04606v1.pdf
www.youtube.com/watch?v=isPiE-DBagM&index=5&list=PLU40WLOO894/zp94 (47:39 рд╕реЗ)

All Articles