Pytorch: [рдлрд╝реАрдЪрд░ рдЕрдиреБрд░реЛрдз] рдХрдирд╡рд▓реНрд╢рди рдСрдкрд░реЗрд╢рдВрд╕ рдХреЗ рд▓рд┐рдП "рд╕рдорд╛рди" рдкреИрдбрд┐рдВрдЧ рд▓рд╛рдЧреВ рдХрд░реЗрдВ?

рдХреЛ рдирд┐рд░реНрдорд┐рдд 25 рдирд╡ре░ 2017  ┬╖  59рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ  ┬╖  рд╕реНрд░реЛрдд: pytorch/pytorch

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

cc @ezyang @gchanan @zou3519 @albanD @mruberry

enhancement high priority convolution nn triaged

рд╕рдмрд╕реЗ рдЙрдкрдпреЛрдЧреА рдЯрд┐рдкреНрдкрдгреА

рдХреНрдпрд╛ рдирд┐рдХрдЯ рднрд╡рд┐рд╖реНрдп рдореЗрдВ рдкрд╛рдЗрдЯреЛрд░рдЪ рдореЗрдВ рдЗрд╕реА рддрд░рд╣ рдХреЗ рдПрдкреАрдЖрдИ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреА рдХреЛрдИ рдпреЛрдЬрдирд╛ рд╣реИ? рдЯреЗрдВрд╕рд░рдлрд╝реНрд▓реЛ / рдХреЗрд░рд╕ рдкреГрд╖реНрдарднреВрдорд┐ рд╕реЗ рдЖрдиреЗ рд╡рд╛рд▓реЗ рд▓реЛрдЧ рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ рдЗрд╕рдХреА рд╕рд░рд╛рд╣рдирд╛ рдХрд░реЗрдВрдЧреЗред

рд╕рднреА 59 рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

рдРрд╕рд╛ рдХрд░рдиреЗ рд▓рд╛рдпрдХ рд▓рдЧрддрд╛ рд╣реИред рдЖрдк рдХрд┐рд╕ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХрд╛ рдкреНрд░рд╕реНрддрд╛рд╡ рдХрд░ рд░рд╣реЗ рд╣реИрдВ? nn.Conv2d(..., padding="same") ?

рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рдпрджрд┐ рдЖрдк TensorFlow рдХреЗ рд╕рдорд╛рди рд╡реНрдпрд╡рд╣рд╛рд░ рдХреА рддрд▓рд╛рд╢ рдХрд░ рд░рд╣реЗ рд╣реИрдВ, рддреЛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдЙрддрдирд╛ рд╕реАрдзрд╛ рдирд╣реАрдВ рд╣реЛрдЧрд╛, рдХреНрдпреЛрдВрдХрд┐ рдЬреЛрдбрд╝рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд┐рдХреНрд╕реЗрд▓ рдХреА рд╕рдВрдЦреНрдпрд╛ рдЗрдирдкреБрдЯ рдЖрдХрд╛рд░ рдкрд░ рдирд┐рд░реНрднрд░ рдХрд░рддреА рд╣реИред рд╕рдВрджрд░реНрдн рдХреЗ рд▓рд┐рдП рджреЗрдЦреЗрдВ https://github.com/caffe2/caffe2/blob/master/caffe2/proto/caffe2_legacy.proto

рдореБрджреНрджреЗ рдФрд░ рд╕рдВрджрд░реНрдн рдХреЛ рдЗрдВрдЧрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рджред
@fmassa рджреНрд╡рд╛рд░рд╛ рдмрддрд╛рдИ рдЧрдИ рд╕рдорд╕реНрдпрд╛ рдХреЛ рд╣рд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдореИрдВ рджреЛ рдЗрдВрдЯрд░рдлреЗрд╕ рдкреНрд░рд╕реНрддрд╛рд╡рд┐рдд рдХрд░рддрд╛ рд╣реВрдВред
рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рдЬреИрд╕рд╛ рдХрд┐ @soutmith рдиреЗ рдЙрд▓реНрд▓реЗрдЦ рдХрд┐рдпрд╛ рд╣реИ, рдкрд╣рд▓рд╛ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ nn.Conv*d(..., padding="same") рдЬреИрд╕рд╛ рд╣реЛрдЧрд╛, рдЬреЛ рдкреНрд░рддреНрдпреЗрдХ forward() рдХреЙрд▓ рдкрд░ рдкреИрдбрд┐рдВрдЧ рдХреА рдЧрдгрдирд╛ рдХрд░реЗрдЧрд╛ред
рд╣рд╛рд▓рд╛рдБрдХрд┐, рдпрд╣ рдПрдХ рдЕрдХреНрд╖рдо рддрд░реАрдХрд╛ рд╣реЛрдЧрд╛ рдЬрдм рдкреНрд░рд╛рд░рдВрднрд┐рдХ рдЪрд░рдг рдореЗрдВ рдЗрдирдкреБрдЯ рдЖрдХрд╛рд░ рдЬреНрдЮрд╛рдд рд╣реЛред рдЗрд╕рд▓рд┐рдП, рдореИрдВ nn.CalcPadConv*d(<almost same parameters as Conv*d>) рдЬреИрд╕реЗ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХрд╛ рд╕реБрдЭрд╛рд╡ рджреЗрддрд╛ рд╣реВрдВред рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ, рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЖрд░рдВрднреАрдХрд░рдг рдореЗрдВ рдЬреНрдЮрд╛рдд рдЪреМрдбрд╝рд╛рдИ рдФрд░ рдКрдВрдЪрд╛рдИ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдкреИрдбрд┐рдВрдЧ рдХреА рдЧрдгрдирд╛ рдХрд░ рд╕рдХрддрд╛ рд╣реИ, рдФрд░ рдЖрдЙрдЯрдкреБрдЯ (рдкреИрдбрд┐рдВрдЧ рдХрд╛ рдЖрдХрд╛рд░) рдХреЛ nn.Conv2d(...) рдХреЗ рдкреИрдбрд┐рдВрдЧ рдкреИрд░рд╛рдореАрдЯрд░ рдореЗрдВ рдкрд╛рд╕ рдХрд░ рд╕рдХрддрд╛ рд╣реИред
рдореБрдЭреЗ рдпрдХреАрди рдирд╣реАрдВ рд╣реИ рдХрд┐ рджреВрд╕рд░рд╛ рдкреНрд░рд╕реНрддрд╛рд╡ рд╕рдордпрдкреВрд░реНрд╡ рдЕрдиреБрдХреВрд▓рди рд╣реЛ рд╕рдХрддрд╛ рд╣реИред
рдЖрдк рдЗрди рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдХреИрд╕реЗ рд╕реЛрдЪрддреЗ рд╣реИрдВ? рдХреНрдпрд╛ рдмреЗрд╣рддрд░ рдирд╛рдо рдХрд╛ рдХреЛрдИ рд╡рд┐рдЪрд╛рд░ рд╣реИ?

рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдЕрдХреНрд╖рдорддрд╛ рдХрд╛ рд╕рдмрд╕реЗ рдмрдбрд╝рд╛ рд╕реНрд░реЛрдд рдЗрд╕ рддрдереНрдп рд╕реЗ рдЖрдПрдЧрд╛ рдХрд┐ рд╣рдореЗрдВ рд╣рд░ рджреВрд╕рд░реЗ рдХрдирд╡рд▓реНрд╢рди рд╕реЗ рдкрд╣рд▓реЗ рдПрдХ F.pad рдкрд░рдд рдЬреЛрдбрд╝рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреА рдЬрд┐рд╕рдХреЗ рд▓рд┐рдП padding=same рдХреЗрд╕ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ (рдХреНрдпреЛрдВрдХрд┐ рдкреИрдбрд┐рдВрдЧ рдХреА рдорд╛рддреНрд░рд╛ рд╕рдорд╛рди рдирд╣реАрдВ рд╣реЛ рд╕рдХрддреА рд╣реИ) рдмрд╛рдИрдВ рдФрд░ рджрд╛рдИрдВ рдУрд░), рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП рджреЗрдЦреЗрдВ рдХрд┐ cudnn рдорд╛рдорд▓реЗ рдореЗрдВ TensorFlow рдХреЛ рдЗрд╕реЗ рдХреИрд╕реЗ рд╕рдВрднрд╛рд▓рдирд╛ рд╣реИ ред рддреЛ рдЗрд╕рдХрд╛ рдорддрд▓рдм рд╣реИ рдХрд┐ nn.CalcPadConv*d рд╕рд╛рдорд╛рдиреНрдп рд░реВрдк рд╕реЗ nn.Conv*d(..., padding="same") рдЬрд┐рддрдирд╛ рдорд╣рдВрдЧрд╛ рд╣реЛрдЧрд╛ред

рдЗрд╕реЗ рдФрд░ рдЕрдзрд┐рдХ рдХреБрд╢рд▓ рдмрдирд╛рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ рдпрджрд┐ рд╣рдо рдХрдирд╡рд▓реНрд╢рди рдХреЗ рдкреНрд░рддреНрдпреЗрдХ рдкрдХреНрд╖ рдХреЗ рд▓рд┐рдП рдЕрд▓рдЧ-рдЕрд▓рдЧ рдкреИрдбрд┐рдВрдЧ рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рддреЗ рд╣реИрдВ (рдЬреИрд╕реЗ Caffe2, рддреЛ рдмрд╛рдПрдБ, рджрд╛рдПрдБ, рдКрдкрд░, рдиреАрдЪреЗ), рд▓реЗрдХрд┐рди cudnn рдЕрднреА рднреА рдЗрд╕рдХрд╛ рд╕рдорд░реНрдерди рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рд╣рдореЗрдВ рдЙрди рдорд╛рдорд▓реЛрдВ рдореЗрдВ рдЕрддрд┐рд░рд┐рдХреНрдд рдкреИрдбрд┐рдВрдЧ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреАред .

рд╕рд╛рде рд╣реА, рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдЕрдЧрд░ рд╣рдо padding="same" рдХреЛ nn.Conv*d рдЬреЛрдбрд╝рддреЗ рд╣реИрдВ, рддреЛ рд╣рдореЗрдВ рд╢рд╛рдпрдж nn.*Pool*d рд▓рд┐рдП рднреА рдРрд╕рд╛ рд╣реА рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП, рд╣реИ рдирд╛?

рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдЬреЛ рдореБрдЭреЗ рдереЛрдбрд╝рд╛ рдкрд░реЗрд╢рд╛рди рдХрд░рддрд╛ рд╣реИ рд╡рд╣ рдпрд╣ рд╣реИ рдХрд┐ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ padding=same рдХреЗ рд╡реНрдпрд╡рд╣рд╛рд░ рдХреЛ TF рдХреЗ рдмрд░рд╛рдмрд░ рд╣реЛрдиреЗ рдХреА рдЙрдореНрдореАрдж рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рд╡реЗ рдкреНрд░рджрд░реНрд╢рди рдореЗрдВ рдЧрд┐рд░рд╛рд╡рдЯ рдХреА рдЙрдореНрдореАрдж рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред

рддреБрдо рдХреНрдпрд╛ рд╕реЛрдЪрддреЗ рд╣реЛ?

рдпрд╣ рдЕрдХреНрд╖рдо рдХреНрдпреЛрдВ рд╣реЛрдЧрд╛? рдХреНрдпрд╛ рд╣рдо рд╣рд░ рдЖрдЧреЗ рдХреЗ рдХрджрдо рдкрд░ рдкреИрдбрд┐рдВрдЧ рдХреА рдЧрдгрдирд╛ рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗ? рд▓рд╛рдЧрдд рдХрдо рд╣реЛрдиреА рдЪрд╛рд╣рд┐рдП, рдЗрд╕рд▓рд┐рдП рдЗрд╕реЗ рдЕрдиреБрдХреВрд▓рд┐рдд рдХрд░рдиреЗ рдХреА рдХреЛрдИ рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИред рд╣реЛ рд╕рдХрддрд╛ рд╣реИ рдХрд┐ рдореИрдВ рд╢рдмреНрджрд╛рд░реНрде рдХреЛ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдирд╣реАрдВ рд╕рдордЭрддрд╛, рд▓реЗрдХрд┐рди рдореИрдВ рдпрд╣ рдирд╣реАрдВ рджреЗрдЦ рд╕рдХрддрд╛ рдХрд┐ F.pad рдЖрд╡рд╢реНрдпрдХрддрд╛ рдХреНрдпреЛрдВ рд╣реЛрдЧреАред

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

@fmassa, рдореИрдВ рдХреНрдпрд╛ рдЗрд░рд╛рджрд╛ "рдирд┐рд░рдВрддрд░" рдореЗрдВ рдЧрджреНрджреА рдЖрдХрд╛рд░ рдХреА рдЧрдгрдирд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдерд╛ __init__() рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ nn.CalcPadConv*d() ред рдЬреИрд╕рд╛ рдХрд┐ рдЖрдкрдиреЗ рдХрд╣рд╛, рдпрд╣ рддрд░реАрдХрд╛ рдХреЗрд╡рд▓ рддрднреА рдХрд╛рдо рдирд╣реАрдВ рдХрд░реЗрдЧрд╛ рдЬрдм рдкрд░рд┐рдХрд▓рд┐рдд рдкреИрдбрд┐рдВрдЧ рд╡рд┐рд╖рдо рд╣реЛред рдЗрд╕рд▓рд┐рдП, F.pad рдкрд░рдд рдХреЛ рдЬреЛрдбрд╝рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдпрд╛ рд╡рд┐рд╖рдо рдкреИрдбрд┐рдВрдЧ рдХреЗ рд▓рд┐рдП F.conv*d рдХреЗ рд╕рдорд░реНрдерди рд╕реЗ рдорджрдж рдорд┐рд▓рдиреА рдЪрд╛рд╣рд┐рдПред

рд╕рдВрдкрд╛рджрд┐рдд рдХрд░реЗрдВ: рдлрд┐рд░ рдореИрдВрдиреЗ рдЬреЛ рд╕реБрдЭрд╛рд╡ рджрд┐рдпрд╛ рд╡рд╣ рдПрдХ рд╕рдорд╛рд░реЛрд╣ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП рдФрд░ рдХрд╣реЗрдВ, рдЯреЙрд░реНрдЪ.рдПрдирдПрди.рдпреВрдЯрд┐рд▓реНрд╕ рдпрд╛ рдЯреЙрд░реНрдЪ.рдпреВрдЯрд┐рд▓реНрд╕ рдореЗрдВ рд░рдЦрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред

рдирддреАрдЬрддрди, рдореИрдВ рдЬреЛ рд╕реБрдЭрд╛рд╡ рджреЗрддрд╛ рд╣реВрдВ рд╡рд╣ рдПрдХ рд╕рд╛рдзрд╛рд░рдг рдЙрдкрдпреЛрдЧрд┐рддрд╛ рдлрд╝рдВрдХреНрд╢рди рд╣реИ, рдЬреИрд╕реЗ (рдЫрджреНрдо рдХреЛрдб):

def calc_pad_conv1d(width, padding='same', check_symmetric=True, ... <params that conv1d has>):
    shape = <calculate padding>

    assert not check_symmetric or <shape is symmetric>, \
        'Calculated padding shape is asymmetric, which is not supported by conv1d. ' \ 
        'If you just want to get the value, consider using check_symmetric=False.'

    return shape


width = 100  # for example
padding = calc_pad_conv1d(width, ...)
m = nn.Conv1d(..., padding=padding)

рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЗ рдкрдХреНрд╖ рдореЗрдВ F.pad рд╕рд╛рде рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред

@ qbx2 рд╢рд╛рдпрдж рдореИрдВ рдЖрдкрдХреЗ рдкреНрд░рд╕реНрддрд╛рд╡ рдХреЛ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдирд╣реАрдВ рд╕рдордЭрддрд╛, рд▓реЗрдХрд┐рди рдЕрдЧрд░ рд╣рдо TensorFlow рд╡реНрдпрд╡рд╣рд╛рд░ рдХреЛ рджреЛрд╣рд░рд╛рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ рддреЛ рдореБрдЭреЗ рдирд╣реАрдВ рд▓рдЧрддрд╛ рдХрд┐ рдпрд╣ рдкрд░реНрдпрд╛рдкреНрдд рд╣реИред

рдпрд╣рд╛рдВ рдПрдХ рд╕реНрдирд┐рдкреЗрдЯ рд╣реИ рдЬреЛ рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ TensorFlow SAME рдкреИрдбрд┐рдВрдЧ рдХреА рдирдХрд▓ рдХрд░рддрд╛ рд╣реИ (рдореИрдВ рдЗрд╕реЗ рдХрд╛рд░реНрдпрд╛рддреНрдордХ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдореЗрдВ рд▓рд┐рдЦ рд░рд╣рд╛ рд╣реВрдВ, рддрд╛рдХрд┐ nn.Conv2d рдмрд╕ F.conv2d_same_padding рдореЗрдВ рдХреЙрд▓ рдХрд░ рд╕рдХреЗ):

def conv2d_same_padding(input, weight, bias=None, stride=1, dilation=1, groups=1):
  input_rows = input.size(2)
  filter_rows = weight.size(2)
  effective_filter_size_rows = (filter_rows - 1) * dilation[0] + 1
  out_rows = (input_rows + stride[0] - 1) // stride[0]
  padding_needed =
          max(0, (out_rows - 1) * stride[0] + effective_filter_size_rows -
                  input_rows)
  padding_rows = max(0, (out_rows - 1) * stride[0] +
                        (filter_rows - 1) * dilation[0] + 1 - input_rows)
  rows_odd = (padding_rows % 2 != 0)
  # same for padding_cols

  if rows_odd or cols_odd:
    input = F.pad(input, [0, int(cols_odd), 0, int(rows_odd)])

  return F.conv2d(input, weight, bias, stride,
                  padding=(padding_rows // 2, padding_cols // 2),
                  dilation=dilation, groups=groups)

рдЗрд╕реЗ рдЬреНрдпрд╛рджрд╛рддрд░ TensorFlow рдХреЛрдб рд╕реЗ рдпрд╣рд╛рдБ рдФрд░ рдпрд╣рд╛рдБ рдХреЙрдкреА-рдкреЗрд╕реНрдЯ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ред

рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ, рд╡рд╣рд╛рдВ рдмрд╣реБрдд рд╕реА рдЫрд┐рдкреА рд╣реБрдИ рдЪреАрдЬреЗрдВ рдЪрд▓ рд░рд╣реА рд╣реИрдВ, рдФрд░ рдЗрд╕рд▓рд┐рдП рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ padding='same' рдЬреЛрдбрд╝рдиреЗ рдХреЗ рд▓рд╛рдпрдХ рдирд╣реАрдВ рд╣реЛ рд╕рдХрддрд╛ рд╣реИред рдФрд░ рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ TensorFlow рдореЗрдВ SAME рд╡реНрдпрд╡рд╣рд╛рд░ рдХреА рдирдХрд▓ рдирд╣реАрдВ рдХрд░рдирд╛ рднреА рдЖрджрд░реНрд╢ рдирд╣реАрдВ рд╣реИред

рд╡рд┐рдЪрд╛рд░?

@fmassa рд╣рд╛рдБ, рддреБрдо рд╕рд╣реА рд╣реЛред рдкреНрд░рддреНрдпреЗрдХ forward() рдкрд░ рдкреИрдбрд┐рдВрдЧ рдХреА рдЧрдгрдирд╛ рдХрд░рдирд╛ рдЕрдХреНрд╖рдо рд╣реЛ рд╕рдХрддрд╛ рд╣реИред

рд╣рд╛рд▓рд╛рдВрдХрд┐, рдореЗрд░рд╛ рдкреНрд░рд╕реНрддрд╛рд╡ рдкреНрд░рддреНрдпреЗрдХ forward() рдХреЙрд▓ рдкрд░ рдкреИрдбрд┐рдВрдЧ рдХреА рдЧрдгрдирд╛ рдХрд░рдиреЗ рдХрд╛ рдирд╣реАрдВ рд╣реИред рдПрдХ рд╢реЛрдзрдХрд░реНрддрд╛ (рдбреЗрд╡рд▓рдкрд░) рд░рдирдЯрд╛рдЗрдо рд╕реЗ рдкрд╣рд▓реЗ рдЫрд╡рд┐рдпреЛрдВ рдХреЗ рдЖрдХрд╛рд░ nn.Conv2d рдЙрдореНрдореАрдж рдХрд░ рд╕рдХрддрд╛ рд╣реИред рдФрд░ рдЕрдЧрд░ рд╡рд╣ 'рд╕рдорд╛рди' рдкреИрдбрд┐рдВрдЧ рдЪрд╛рд╣рддрд╛ рд╣реИ, рддреЛ рд╡рд╣ 'рд╕рдорд╛рди' рдХреА рдирдХрд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рдкреИрдбрд┐рдВрдЧ рдХреА рдЧрдгрдирд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддрд╛ рд╣реИред

рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдорд╛рди рд▓реЗрдВ рдХрд┐ рдХрд┐рд╕реА рд╢реЛрдзрдХрд░реНрддрд╛ рдХреЗ рдкрд╛рд╕ 200x200, 300x300, 400x400 рд╡рд╛рд▓реА рдЫрд╡рд┐рдпрд╛рдВ рд╣реИрдВред рдлрд┐рд░ рд╡рд╣ рдЗрдирд┐рд╢рд┐рдпрд▓рд╛рдЗрдЬрд╝реЗрд╢рди рдЪрд░рдг рдореЗрдВ рддреАрди рдорд╛рдорд▓реЛрдВ рдХреЗ рд▓рд┐рдП рдкреИрдбрд┐рдВрдЧ рдХреА рдЧрдгрдирд╛ рдХрд░ рд╕рдХрддрд╛ рд╣реИ рдФрд░ рд╕рдВрдмрдВрдзрд┐рдд рдкреИрдбрд┐рдВрдЧ рдХреЗ рд╕рд╛рде рдЫрд╡рд┐рдпреЛрдВ рдХреЛ F.pad() рдкрд░ рдкрд╛рд╕ рдХрд░ рд╕рдХрддрд╛ рд╣реИред рдпрд╛ рд╡рд╣ forward() рдХреЙрд▓ рд╕реЗ рдкрд╣рд▓реЗ nn.Conv2d рдХреЗ рдкреИрдбрд┐рдВрдЧ рдлрд╝реАрд▓реНрдб рдХреЛ рдмрджрд▓ рджреЗрддрд╛ рд╣реИред рдЗрд╕рдХрд╛ рд╕рдВрджрд░реНрдн рд▓реЗрдВ:

>>> import torch
>>> import torch.nn as nn
>>> from torch.autograd import Variable
>>> m = nn.Conv2d(1,1,1)
>>> m(Variable(torch.randn(1,1,2,2))).shape
torch.Size([1, 1, 2, 2])
>>> m.padding = (1, 1)
>>> m(Variable(torch.randn(1,1,2,2))).shape
torch.Size([1, 1, 4, 4])

рд╣рд╛рдВ, рдореИрдВ рд╕рд┐рд░реНрдл рдкрд╛рдЗрдЯреЛрд░рдЪ рдХреЛрд░ рдореЗрдВ "рдкреИрдбрд┐рдВрдЧ рдХреИрд▓рдХреБрд▓реЗрдЯрд┐рдВрдЧ рдпреВрдЯрд┐рд▓рд┐рдЯреА рдлрдВрдХреНрд╢рди" рдЬреЛрдбрд╝рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВред

рдЬрдм рд╢реЛрдзрдХрд░реНрддрд╛ рдкреНрд░рддреНрдпреЗрдХ рдЗрдирдкреБрдЯ рдЫрд╡рд┐ рдЖрдХрд╛рд░ рдкрд░ рдирд┐рд░реНрднрд░ рдкреИрдбрд┐рдВрдЧ рдЪрд╛рд╣рддрд╛ рд╣реИ, рддреЛ рд╡рд╣ рдЫрд╡рд┐ рдХреЛ nn.Conv2d рдкрд╛рд╕ рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдлрд╝рдВрдХреНрд╢рди рдХреЛ F.pad() рд╕рд╛рде рдЬреЛрдбрд╝ рд╕рдХрддрд╛ рд╣реИред рдореИрдВ рдХреЛрдб рд▓реЗрдЦрдХ рдХреЛ рдпрд╣ рддрдп рдХрд░рдиреЗ рджреЗрдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ рдХрд┐ рдкреНрд░рддреНрдпреЗрдХ forward() рдХреЙрд▓ рдкрд░ рдЗрдирдкреБрдЯ рдкреИрдб рдХрд░рдирд╛ рд╣реИ рдпрд╛ рдирд╣реАрдВред

рдХреНрдпрд╛ рдирд┐рдХрдЯ рднрд╡рд┐рд╖реНрдп рдореЗрдВ рдкрд╛рдЗрдЯреЛрд░рдЪ рдореЗрдВ рдЗрд╕реА рддрд░рд╣ рдХреЗ рдПрдкреАрдЖрдИ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреА рдХреЛрдИ рдпреЛрдЬрдирд╛ рд╣реИ? рдЯреЗрдВрд╕рд░рдлрд╝реНрд▓реЛ / рдХреЗрд░рд╕ рдкреГрд╖реНрдарднреВрдорд┐ рд╕реЗ рдЖрдиреЗ рд╡рд╛рд▓реЗ рд▓реЛрдЧ рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ рдЗрд╕рдХреА рд╕рд░рд╛рд╣рдирд╛ рдХрд░реЗрдВрдЧреЗред

рддреЛ, рдПрдХ рдмреБрдирд┐рдпрд╛рджреА рдкреИрдбрд┐рдВрдЧ рдЧрдгрдирд╛ рд░рдгрдиреАрддрд┐ (рдЬреЛ TensorFlow рдХреЗ рд╕рдорд╛рди рдкрд░рд┐рдгрд╛рдо рдирд╣реАрдВ рджреЗрддреА рд╣реИ, рд▓реЗрдХрд┐рди рдЖрдХрд╛рд░ рд╕рдорд╛рди рд╣реИрдВ) рд╣реИ

def _get_padding(padding_type, kernel_size):
    assert padding_type in ['SAME', 'VALID']
    if padding_type == 'SAME':
        return tuple((k - 1) // 2 for k in kernel_size))
    return tuple(0 for _ in kernel_size)

рдХреНрдпрд╛ рдЖрдкрдХреЗ рдорди рдореЗрдВ @im9uri рдпрд╣реА рд╣реИ ?

рдпрд╣ рд╡рд╣реА рд╣реИ рдЬреЛ рдореЗрд░реЗ рдорди рдореЗрдВ рдерд╛, рд▓реЗрдХрд┐рди рдЬреИрд╕рд╛ рдХрд┐ рдЖрдкрдиреЗ рдкрд╣рд▓реЗ рдЙрд▓реНрд▓реЗрдЦ рдХрд┐рдпрд╛ рд╣реИ рдХрд┐ рдЧрдгрдирд╛ рдкреНрд░рдЧрддрд┐ рдФрд░ рдлреИрд▓рд╛рд╡ рдХреЗ рд╕рд╛рде рдЬрдЯрд┐рд▓ рд╣реЛ рдЬрд╛рддреА рд╣реИред

рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛ ConvTranspose2d рдЬреИрд╕реЗ рдЕрдиреНрдп рдХрдирд╡рд▓реНрд╢рди рдСрдкрд░реЗрд╢рдВрд╕ рдореЗрдВ рдЗрд╕ рддрд░рд╣ рдХреЗ рдПрдкреАрдЖрдИ рдХрд╛ рд╣реЛрдирд╛ рдмрд╣реБрдд рдЕрдЪреНрдЫрд╛ рд╣реЛрдЧрд╛ред

рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ "рд╕реНрд▓рд╛рдЗрдбрд┐рдВрдЧ-рд╡рд┐рдВрдбреЛ рдСрдкрд░реЗрдЯрд░реЛрдВ" рдХреЛ рд╕рднреА рдЕрд╕рдордорд┐рдд рдкреИрдбрд┐рдВрдЧ рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдПред

"рд╕рдорд╛рди" рддрд░реНрдХ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ ...
@soumith рдХреНрдпрд╛ рдЖрдк рдмрддрд╛ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рдЗрдирдкреБрдЯ рдЖрдХрд╛рд░ рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдкреИрдбрд┐рдВрдЧ рдХреНрдпреЛрдВ рдЦрд░рд╛рдм рд╣реИ, рдХреГрдкрдпрд╛?
рдпрджрд┐ рдпрд╣ рдПрдХ рд╕рдорд╕реНрдпрд╛ рд╣реИ, рд╡реИрд╕реЗ рднреА, "рд╕рдорд╛рди" рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╕рдордп stride == 1 рдЖрд╡рд╢реНрдпрдХрддрд╛ рдХреЗ рд▓рд┐рдП рдПрдХ рд╡реНрдпрд╛рд╡рд╣рд╛рд░рд┐рдХ рд╕рдорд╛рдзрд╛рди рд╣реЛ рд╕рдХрддрд╛ рд╣реИред stride == 1 , рдкреИрдбрд┐рдВрдЧ рдЗрдирдкреБрдЯ рдЖрдХрд╛рд░ рдкрд░ рдирд┐рд░реНрднрд░ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ рдФрд░ рдЗрд╕рдХреА рдЧрдгрдирд╛ рдПрдХ рдмрд╛рд░ рдХреА рдЬрд╛ рд╕рдХрддреА рд╣реИред рдпрджрд┐ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ padding='same' рд╕рд╛рде stride > 1 рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░рддрд╛ рд╣реИ рддреЛ рдХрдВрд╕реНрдЯреНрд░рдХреНрдЯрд░ рдХреЛ ValueError рдЙрдард╛рдирд╛ рдЪрд╛рд╣рд┐рдПред

рдореБрдЭреЗ рдкрддрд╛ рд╣реИ, рдпрд╣ рд╕рдмрд╕реЗ рд╕рд╛рдл рд╕рдорд╛рдзрд╛рди рдирд╣реАрдВ рд╣реИ, рд▓реЗрдХрд┐рди рдмрд╛рдзрд╛ рдореБрдЭреЗ рдХрд╛рдлреА рдЙрдЪрд┐рдд рд▓рдЧрддреА рд╣реИ:

  1. "рд╕рдорд╛рди" рд▓реЗрдмрд▓ рдХрд╛ рдореВрд▓ рд╢рдмреНрджрд╛рд░реНрде рдмрд┐рдирд╛ рд╕реНрдЯреНрд░рд╛рдЗрдб рдХрдирд╡рд▓реНрд╢рди рдХреЗ рд▓рд┐рдП рдкреЗрд╢ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ рдФрд░ рдерд╛: рдЖрдЙрдЯрдкреБрдЯ рдореЗрдВ рдЗрдирдкреБрдЯ рдХрд╛ _same_ рдЖрдХрд╛рд░ рд╣реИ; рдмреЗрд╢рдХ, рдпрд╣ stride > 1 рд▓рд┐рдП рдЯреЗрдВрд╕рд░рдлрд╝реНрд▓реЛ рдореЗрдВ рд╕рдЪ рдирд╣реАрдВ рд╣реИ рдФрд░ рдпрд╣ "рд╕рдорд╛рди" рд╢рдмреНрдж рдХрд╛ рдЙрдкрдпреЛрдЧ рдереЛрдбрд╝рд╛ рднреНрд░рд╛рдордХ рдЖрдИрдПрдордУ рдмрдирд╛рддрд╛ рд╣реИ;
  2. рдпрд╣ 99% рдорд╛рдорд▓реЛрдВ рдХреЛ рдХрд╡рд░ рдХрд░реЗрдЧрд╛ рдЬреЛ рдХреЛрдИ "рд╕рдорд╛рди" рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реИ; рдореИрдВ рдореБрд╢реНрдХрд┐рд▓ рд╕реЗ рдРрд╕реЗ рдорд╛рдорд▓реЗ рдХреА рдХрд▓реНрдкрдирд╛ рдХрд░ рд╕рдХрддрд╛ рд╣реВрдВ рдЬрдм рдХрд┐рд╕реА рдХреЛ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ stride > 1 рд▓рд┐рдП рдЯреЗрдВрд╕рд░рдлреНрд▓реЛ рдХреЗ рд╡реНрдпрд╡рд╣рд╛рд░ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ, рдЬрдмрдХрд┐ рдЕрдЧрд░ рд╣рдо рдЗрд╕рдХреЗ рдореВрд▓ рдЕрд░реНрде рдХреЛ "рд╕рдорд╛рди" рджреЗрддреЗ рд╣реИрдВ, рддреЛ рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ рдЗрд╕рдХрд╛ рдХреЛрдИ рдорддрд▓рдм рдирд╣реАрдВ рд╣реИ рдПрдХ рдХрдареЛрд░ рджреГрдврд╝ рд╕рдВрдХрд▓реНрдк рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдпрджрд┐ рдЖрдк рдЪрд╛рд╣рддреЗ рд╣реИрдВ рдХрд┐ рдЖрдЙрдЯрдкреБрдЯ рдореЗрдВ рдЗрдирдкреБрдЯ рдХрд╛ рдЖрдХрд╛рд░ рд╕рдорд╛рди рд╣реЛред

conv2d рдкреНрд░рд▓реЗрдЦрди рдЖрдЙрдЯрдкреБрдЯ рдЖрдХрд╛рд░ рдХреЗ рд▓рд┐рдП рд╕реНрдкрд╖реНрдЯ рд╕реВрддреНрд░ рджреЗрддрд╛ рд╣реИред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП Hin рдХреЗ рд╕рд╛рде Hout рдкреИрдбрд┐рдВрдЧ рдХреЗ рд▓рд┐рдП рд╣рд▓ рдХрд░ рд╕рдХрддрд╛ рд╣реИ:

def _get_padding(size, kernel_size, stride, dilation):
    padding = ((size - 1) * (stride - 1) + dilation * (kernel_size - 1)) //2
    return padding

рдЪреВрдБрдХрд┐ рд╕рдорд╛рди рдкреИрдбрд┐рдВрдЧ рдХрд╛ рдЕрд░реНрде рд╣реИ рдкреИрдбрд┐рдВрдЧ = (рдХрд░реНрдиреЗрд▓_рд╕рд╛рдЗрдЬрд╝ - рд╕реНрдЯреНрд░рд╛рдЗрдб)//2, рдХреНрдпрд╛ рд╣реЛрдЧрд╛ рдпрджрд┐ рдкреИрдбрд┐рдВрдЧ = "рд╕рдорд╛рди" рдХреЛ рдЗрд╕ рддрд░рд╣ рдкреЗрд╢ рдХрд┐рдпрд╛ рдЬрд╛рдП рдХрд┐ рдЬрдм рд▓рд┐рдЦрд╛ рдЬрд╛рдП, рддреЛ рдпрд╣ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рдХрд░реНрдиреЗрд▓ рдЖрдХрд╛рд░ рдФрд░ рд╕реНрдЯреНрд░рд╛рдЗрдб рдХреЛ рдкрдврд╝рддрд╛ рд╣реИ (рдЬреИрд╕рд╛ рдХрд┐ nn.Conv2d рдореЗрдВ рднреА рдЙрд▓реНрд▓реЗрдЦ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ) рдФрд░ рдкреИрдбрд┐рдВрдЧ рд▓рд╛рдЧреВ рдХрд░рддрд╛ рд╣реИ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рддрджрдиреБрд╕рд╛рд░

рд╕рдВрджрд░реНрдн рдХреЗ рд▓рд┐рдП same рдкреИрдбрд┐рдВрдЧ рдХреЗ рд╕рд╛рде рдпрд╣рд╛рдВ рдПрдХ рдмрд╣реБрдд рд╣реА рд╕рд░рд▓ Conv2d рдкрд░рдд рд╣реИред рдпрд╣ рдХреЗрд╡рд▓ рд╡рд░реНрдЧрд╛рдХрд╛рд░ рдЧреБрдард▓реА рдФрд░ рд╕реНрдЯреНрд░рд╛рдЗрдб = 1, рдлреИрд▓рд╛рд╡ = 1, рд╕рдореВрд╣ = 1 рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рддрд╛ рд╣реИред

class Conv2dSame(torch.nn.Module):
    def __init__(self, in_channels, out_channels, kernel_size, bias=True, padding_layer=torch.nn.ReflectionPad2d):
        super().__init__()
        ka = kernel_size // 2
        kb = ka - 1 if kernel_size % 2 == 0 else ka
        self.net = torch.nn.Sequential(
            padding_layer((ka,kb,ka,kb)),
            torch.nn.Conv2d(in_channels, out_channels, kernel_size, bias=bias)
        )
    def forward(self, x):
        return self.net(x)

c = Conv2dSame(1,3,5)
print(c(torch.rand((16,1,10,10))).shape)

# torch.Size([16, 3, 10, 10])

рдпрджрд┐ рдпрд╣ рдЕрднреА рднреА PyTorch рдореЗрдВ рдЬреЛрдбрд╝реЗ рдЬрд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдореВрд▓реНрдпрд╛рдВрдХрди рдХрд┐рдпрд╛ рдЬрд╛ рд░рд╣рд╛ рд╣реИ, рддреЛ рдЬрдЯрд┐рд▓рддрд╛ / рдЕрдХреНрд╖рдорддрд╛ рдмрдирд╛рдо рдбреЗрд╡рд▓рдкрд░реНрд╕ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧ рдореЗрдВ рдЖрд╕рд╛рдиреА рдХреЗ рдмреАрдЪ рдЯреНрд░реЗрдбрдСрдлрд╝ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ:

1.0 рдмреНрд▓реЙрдЧ рдкреЛрд╕реНрдЯ рдХреА

PyTorch рдХрд╛ рдХреЗрдВрджреНрд░реАрдп рд▓рдХреНрд╖реНрдп рдЕрдиреБрд╕рдВрдзрд╛рди рдФрд░ рд╣реИрдХ рдХрд░рдиреЗ рдХреА рдХреНрд╖рдорддрд╛ рдХреЗ рд▓рд┐рдП рдПрдХ рдорд╣рд╛рди рдордВрдЪ рдкреНрд░рджрд╛рди рдХрд░рдирд╛ рд╣реИред рдЗрд╕рд▓рд┐рдП, рдЬрдм рд╣рдо рдЗрди рд╕рднреА [рдЙрддреНрдкрд╛рджрди-рдЙрдкрдпреЛрдЧ] рдЕрдиреБрдХреВрд▓рдиреЛрдВ рдХреЛ рдЬреЛрдбрд╝рддреЗ рд╣реИрдВ, рддреЛ рд╣рдо рдПрдХ рдХрдард┐рди рдбрд┐рдЬрд╝рд╛рдЗрди рдмрд╛рдзрд╛ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░ рд░рд╣реЗ рд╣реИрдВ рддрд╛рдХрд┐ рдЗрдиреНрд╣реЗрдВ рдЙрдкрдпреЛрдЧрд┐рддрд╛ рдХреЗ рд╡рд┐рд░реБрджреНрдз рдХрднреА рднреА рд╡реНрдпрд╛рдкрд╛рд░ рди рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХреЗред

рдЕрдирдЬрд╛рдиреЗ рдореЗрдВ, рдореИрдВ рдХреЗрд░рд╕ рдХреЗ рд╕рд╛рде-рд╕рд╛рде рдореВрд▓ tf.layers / рдЕрдиреБрдорд╛рдирдХ рдПрдкреАрдЖрдИ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдкреГрд╖реНрдарднреВрдорд┐ рд╕реЗ рдЖрдпрд╛ рд╣реВрдВред рд╕рднреА рдХреЗ рдкрд╛рд╕ same рдкреИрдбрд┐рдВрдЧ рдХрд╛ рд╕рдорд░реНрдерди рд╣реИред рдореИрдВ рд╡рд░реНрддрдорд╛рди рдореЗрдВ рдПрдХ рдХрдиреНрд╡рдиреЗрдЯ рдХреЛ рдлрд┐рд░ рд╕реЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рд┐рдд рдХрд░ рд░рд╣рд╛ рд╣реВрдВ рдЬрд┐рд╕реЗ рдореИрдВрдиреЗ рдореВрд▓ рд░реВрдк рд╕реЗ рдЯреАрдПрдл рдореЗрдВ рдкрд╛рдпрдЯреЙрд░реНрдЪ рдХреЗ рд╕рд╛рде рд▓рд┐рдЦрд╛ рдерд╛, рдФрд░ рддрдереНрдп рдпрд╣ рд╣реИ рдХрд┐ рдореБрдЭреЗ рд╢реВрдиреНрдп-рдкреИрдбрд┐рдВрдЧ рдХреЗ рд▓рд┐рдП рдЕрдВрдХрдЧрдгрд┐рдд рдореЗрдВ рдирд┐рд░реНрдорд╛рдг рдХрд░рдирд╛ рдкрдбрд╝рд╛ рд╣реИ, рдореБрдЭреЗ рд▓рдЧрднрдЧ рдЖрдзреЗ рджрд┐рди рдХрд╛ рд╕рдордп рд▓рдЧрд╛ рд╣реИред

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

рдореИрдВ рдЗрд╕ рд╕реБрд╡рд┐рдзрд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реВрдВрдЧрд╛

рдпрд╣ рдореЗрд░реЗ рд▓рд┐рдП рдХреЛрдИ рдорд╛рдпрдиреЗ рдирд╣реАрдВ рд░рдЦрддрд╛ рд╣реИ рдХрд┐ padding=SAME рдХрд╛ рд╡реИрдХрд▓реНрдкрд┐рдХ рдПрдкреАрдЖрдИ рдХреНрдпреЛрдВ рдирд╣реАрдВ рдкреЗрд╢ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ? рдЕрдЧрд░ рдХреЛрдИ рдкреИрдбрд┐рдВрдЧ рдХрд╛ рдЕрддрд┐рд░рд┐рдХреНрдд рдЦрд░реНрдЪ рдЙрдард╛рдиреЗ рдХреЛ рддреИрдпрд╛рд░ рд╣реИ рддреЛ рдЙрдиреНрд╣реЗрдВ рдРрд╕рд╛ рдХрд░рдиреЗ рджреЗрдВред рдХрдИ рд╢реЛрдзрдХрд░реНрддрд╛рдУрдВ рдХреЗ рд▓рд┐рдП, рддреНрд╡рд░рд┐рдд рдкреНрд░реЛрдЯреЛрдЯрд╛рдЗрдк рдПрдХ рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред

рд╣рд╛рдВ, рдЕрдЧрд░ рдХреЛрдИ рдХреГрдкрдпрд╛ рдЗрд╕реЗ рдЬреЛрдбрд╝ рдФрд░ рд╕реНрд╡реАрдХреГрдд рдХрд░ рд╕рдХрддрд╛ рд╣реИ, рддреЛ рдпрд╣ рдмрд╣реБрдд рдЕрдЪреНрдЫрд╛ рд╣реЛрдЧрд╛ред

рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ рдЗрд╕реЗ рдЬреЛрдбрд╝реЗрдВ, рдХреЙрдирд░ рдЗрд╕реЗ рдЪрд╛рд╣рддрд╛ рд╣реИред

рдХреНрдпрд╛ pytorch рдЕрдм рдЗрд╕рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рддрд╛ рд╣реИ? рдХреНрдпрд╛ рдпрд╣ рд╡реАрдЬреАрдЬреА рдореЗрдВ рдкрд╣рд▓реЗ рдХреА рддрд░рд╣ рд╣реА рдСрдкрд░реЗрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддрд╛ рд╣реИ, рдкреИрдбрд┐рдВрдЧ = (рдХрд░реНрдиреЗрд▓_рд╕рд╛рдЗрдЬ -1)/2 рд╕реЗрдЯ рдХрд░реЗрдВ?
рд╡реАрдЬреАрдЬреА рдиреЗрдЯрд╡рд░реНрдХ рдкрд╣рд▓реЗ рд╕рдореВрд╣ рдореЗрдВ рдЖрдЙрдЯрдкреБрдЯ рдХрд╛ рдЖрдХрд╛рд░ рдирд╣реАрдВ рдмрджрд▓ рд╕рдХрддрд╛ рд╣реИред рдлрд┐рд░ рдЖрдк рдлреАрдЪрд░рдореИрдк рдХрд╛ рдЖрдХрд╛рд░ рдмрджрд▓рдиреЗ рдХреЗ рд▓рд┐рдП рд╕реНрдЯреНрд░рд╛рдЗрдб рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдХреНрдпрд╛ рдпрд╣ рдареАрдХ рд▓рдЧрддрд╛ рд╣реИ?

рдбреАрдкрдлреЗрдХ рд╕реЗ рд╕рдорд╛рди conv2d рдХреЛ рдХреЙрд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдпрд╣рд╛рдВ рдПрдХ рдЙрджрд╛рд╣рд░рдг рджрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ:

# modify con2d function to use same padding
# code referd to <strong i="6">@famssa</strong> in 'https://github.com/pytorch/pytorch/issues/3867'
# and tensorflow source code

import torch.utils.data
from torch.nn import functional as F

import math
import torch
from torch.nn.parameter import Parameter
from torch.nn.functional import pad
from torch.nn.modules import Module
from torch.nn.modules.utils import _single, _pair, _triple


class _ConvNd(Module):

    def __init__(self, in_channels, out_channels, kernel_size, stride,
                 padding, dilation, transposed, output_padding, groups, bias):
        super(_ConvNd, self).__init__()
        if in_channels % groups != 0:
            raise ValueError('in_channels must be divisible by groups')
        if out_channels % groups != 0:
            raise ValueError('out_channels must be divisible by groups')
        self.in_channels = in_channels
        self.out_channels = out_channels
        self.kernel_size = kernel_size
        self.stride = stride
        self.padding = padding
        self.dilation = dilation
        self.transposed = transposed
        self.output_padding = output_padding
        self.groups = groups
        if transposed:
            self.weight = Parameter(torch.Tensor(
                in_channels, out_channels // groups, *kernel_size))
        else:
            self.weight = Parameter(torch.Tensor(
                out_channels, in_channels // groups, *kernel_size))
        if bias:
            self.bias = Parameter(torch.Tensor(out_channels))
        else:
            self.register_parameter('bias', None)
        self.reset_parameters()

    def reset_parameters(self):
        n = self.in_channels
        for k in self.kernel_size:
            n *= k
        stdv = 1. / math.sqrt(n)
        self.weight.data.uniform_(-stdv, stdv)
        if self.bias is not None:
            self.bias.data.uniform_(-stdv, stdv)

    def __repr__(self):
        s = ('{name}({in_channels}, {out_channels}, kernel_size={kernel_size}'
             ', stride={stride}')
        if self.padding != (0,) * len(self.padding):
            s += ', padding={padding}'
        if self.dilation != (1,) * len(self.dilation):
            s += ', dilation={dilation}'
        if self.output_padding != (0,) * len(self.output_padding):
            s += ', output_padding={output_padding}'
        if self.groups != 1:
            s += ', groups={groups}'
        if self.bias is None:
            s += ', bias=False'
        s += ')'
        return s.format(name=self.__class__.__name__, **self.__dict__)


class Conv2d(_ConvNd):

    def __init__(self, in_channels, out_channels, kernel_size, stride=1,
                 padding=0, dilation=1, groups=1, bias=True):
        kernel_size = _pair(kernel_size)
        stride = _pair(stride)
        padding = _pair(padding)
        dilation = _pair(dilation)
        super(Conv2d, self).__init__(
            in_channels, out_channels, kernel_size, stride, padding, dilation,
            False, _pair(0), groups, bias)

    def forward(self, input):
        return conv2d_same_padding(input, self.weight, self.bias, self.stride,
                        self.padding, self.dilation, self.groups)


# custom con2d, because pytorch don't have "padding='same'" option.
def conv2d_same_padding(input, weight, bias=None, stride=1, padding=1, dilation=1, groups=1):

    input_rows = input.size(2)
    filter_rows = weight.size(2)
    effective_filter_size_rows = (filter_rows - 1) * dilation[0] + 1
    out_rows = (input_rows + stride[0] - 1) // stride[0]
    padding_needed = max(0, (out_rows - 1) * stride[0] + effective_filter_size_rows -
                  input_rows)
    padding_rows = max(0, (out_rows - 1) * stride[0] +
                        (filter_rows - 1) * dilation[0] + 1 - input_rows)
    rows_odd = (padding_rows % 2 != 0)
    padding_cols = max(0, (out_rows - 1) * stride[0] +
                        (filter_rows - 1) * dilation[0] + 1 - input_rows)
    cols_odd = (padding_rows % 2 != 0)

    if rows_odd or cols_odd:
        input = pad(input, [0, int(cols_odd), 0, int(rows_odd)])

    return F.conv2d(input, weight, bias, stride,
                  padding=(padding_rows // 2, padding_cols // 2),
                  dilation=dilation, groups=groups)

рдмрд╕ рдпрд╣ рдХрд╣рдиреЗ рдХреЗ рд▓рд┐рдП рдЫреЛрдбрд╝ рд░рд╣рд╛ рд╣реВрдВ рдХрд┐ рдореИрдВ рднреА рдЗрд╕рдХреА рдмрд╣реБрдд рд╕рд░рд╛рд╣рдирд╛ рдХрд░рддрд╛ рд╣реВрдВред рд╡рд░реНрддрдорд╛рди рдореЗрдВ рдЯреЗрдВрд╕рд░рдлрд╝реНрд▓реЛ рд╕реЗ рдПрдХ рд╕рд╛рдзрд╛рд░рдг рдореЙрдбрд▓ рдХреЛ рдкреЛрд░реНрдЯ рдХрд░ рд░рд╣рд╛ рд╣реИ рдФрд░ рдЧрдгрдирд╛рдУрдВ рдХреЛ рд╕рдордЭрдиреЗ рдореЗрдВ рдореБрдЭреЗ рдмрд╣реБрдд рд▓рдВрдмрд╛ рд╕рдордп рд▓рдЧ рд░рд╣рд╛ рд╣реИ ...

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

рдореИрдВ рдЗрд╕рдХреЗ рд▓рд┐рдП рдПрдХ рдкреНрд░рд╕реНрддрд╛рд╡ рд▓рд┐рдЦреВрдВрдЧрд╛ рдФрд░ рд╣рдо рдЗрд╕реЗ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐рд╕реА рдХреЛ рдвреВрдВрдв рд╕рдХрддреЗ рд╣реИрдВред
рдореИрдВ рдЗрд╕реЗ v1.1 рдореАрд▓ рдХреЗ рдкрддреНрдерд░ рдХреЗ рдЦрд┐рд▓рд╛рдл рд░рдЦ рд░рд╣рд╛ рд╣реВрдВред

рдзрдиреНрдпрд╡рд╛рдж, рдЖрдк рдХрдорд╛рд▓ рд╣реИрдВ! рдореИрдВрдиреЗ рдкреИрдбрд┐рдВрдЧ рддрд░реНрдХ рдХреЛ 4-рдЯреБрдкрд▓ рд╕реНрд╡реАрдХрд╛рд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЕрд▓рдЧ рдлреАрдЪрд░ рдЕрдиреБрд░реЛрдз рднреА рджрд╛рдпрд░ рдХрд┐рдпрд╛ред рдпрд╣ рдЕрд╕рдордорд┐рдд рдХреЗ рд╕рд╛рде-рд╕рд╛рде рд╕рдордорд┐рдд рдкреИрдбрд┐рдВрдЧ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрдЧрд╛ рдЬреЛ рдХрд┐ рдЖрдзреЗ рд░рд╛рд╕реНрддреЗ рддрдХ рдкрд╣реБрдВрдЪрдиреЗ рдХреЗ рд▓рд┐рдП рдХрдо рд▓рд╛рдЧрдд рд╡рд╛рд▓рд╛ рдорд╛рд░реНрдЧ рднреА рд╣реИред

@soumith рдкрд╛рдЗрдЯреЛрд░рдЪ рдореЗрдВ рдПрдХ рдкреИрдбрд┐рдВрдЧ рдореЛрдб SAME рд╣реЛрдирд╛ рдЕрдЪреНрдЫрд╛ рд╣реЛрдЧрд╛ред

@soumith рдПрдХ рд╕рдВрдХрд▓рди рдкреНрд░рдХрд╛рд░ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдХреИрд╕реЗ?

model=torch.compile(model,input_shape=(3,224,224))

рдореИрдВрдиреЗ рдЙрд╕реА рдкреИрдбрд┐рдВрдЧ рдХреЗ рд╕рд╛рде рдПрдХ Conv2D рдмрдирд╛рдпрд╛, рдЬреЛ рдЗрд╕ рдкрд░ рдЖрдзрд╛рд░рд┐рдд рд╣реИ рдХрд┐ TensorFlow рдЙрдирдХрд╛ рдХреИрд╕реЗ рдХрд░рддрд╛ рд╣реИред рдпрд╣ рд╡рд╛рд╕реНрддрд╡рд┐рдХ рд╕рдордп рдореЗрдВ рдЗрд╕рдХреА рдЧрдгрдирд╛ рдХрд░рддрд╛ рд╣реИ, рд╣рд╛рд▓рд╛рдВрдХрд┐, рдпрджрд┐ рдЖрдк рдЗрд╕реЗ рдкреВрд░реНрд╡-рдЧрдгрдирд╛ рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ рддреЛ рдмрд╕ рдкреИрдбрд┐рдВрдЧ рдХреЛ init() рдкрд░ рд▓реЗ рдЬрд╛рдПрдВ рдФрд░ рдЗрдирдкреБрдЯ рдЖрдХрд╛рд░ рдкреИрд░рд╛рдореАрдЯрд░ рд░рдЦреЗрдВред

import torch as tr
import math

class Conv2dSame(tr.nn.Module):

    def __init__(self, in_channels, out_channels, kernel_size, stride=1, dilation=1):
        super(Conv2dSame, self).__init__()
        self.F = kernel_size
        self.S = stride
        self.D = dilation
        self.layer = tr.nn.Conv2d(in_channels, out_channels, kernel_size, stride, dilation=dilation)

    def forward(self, x_in):
        N, C, H, W = x_in.shape
        H2 = math.ceil(H / self.S)
        W2 = math.ceil(W / self.S)
        Pr = (H2 - 1) * self.S + (self.F - 1) * self.D + 1 - H
        Pc = (W2 - 1) * self.S + (self.F - 1) * self.D + 1 - W
        x_pad = tr.nn.ZeroPad2d((Pr//2, Pr - Pr//2, Pc//2, Pc - Pc//2))(x_in)
        x_out = self.layer(x_pad)
        return x_out

Ex1:
рдЗрдирдкреБрдЯ рдЖрдХрд╛рд░: (1, 3, 96, 96)
рдлрд┐рд▓реНрдЯрд░: 64
рдЖрдХрд╛рд░: 9x9

Conv2dSame(3, 64, 9)

рдЧрджреНрджреЗрджрд╛рд░ рдЖрдХрд╛рд░: (1, 3, 104, 104)
рдЖрдЙрдЯрдкреБрдЯ рдЖрдХрд╛рд░: (1, 64, 96, 96)

Ex2:
рдкрд╣рд▓реЗ рдЬреИрд╕рд╛ рд╣реА, рд▓реЗрдХрд┐рди рд╕реНрдЯреНрд░рд╛рдЗрдб рдХреЗ рд╕рд╛рде=2

Conv2dSame(3, 64, 9, 2)

рдЧрджреНрджреЗрджрд╛рд░ рдЖрдХрд╛рд░ = (1, 3, 103, 103)
рдЖрдЙрдЯрдкреБрдЯ рдЖрдХрд╛рд░ = (1, 64, 48, 48)

@jpatts рдореЗрд░рд╛ рдорд╛рдирдирд╛ тАЛтАЛтАЛтАЛрд╣реИ рдХрд┐ рдЖрдкрдХреА рдЖрдЙрдЯрдкреБрдЯ рдЖрдХрд╛рд░ рдЧрдгрдирд╛ рдЧрд▓рдд рд╣реИ, рдпрд╣ рдЫрдд (рдЗрдирдкреБрдЯ_рдбрд┐рдореЗрдВрд╢рди/рд╕реНрдЯреНрд░рд╛рдЗрдб) рд╣реЛрдиреА рдЪрд╛рд╣рд┐рдПред рдкрд╛рдпрдерди рдореЗрдВ рдЗрдВрдЯреАрдЬрд░ рдбрд┐рд╡реАрдЬрди рдлрд░реНрд╢ рдбрд┐рд╡реАрдЬрди рд╣реИ - рдЖрдкрдХреЗ рдХреЛрдб рдХрд╛ рдЯреЗрдВрд╕рд░рдлреНрд▓реЛ рд╕реЗ рдЕрд▓рдЧ рдкрд░рд┐рдгрд╛рдо рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП h=w=28, stride=3, kernel_size=1 ред

рдпрд╣рд╛рдБ рдПрдХ рдкреНрд░рдХрд╛рд░ рд╣реИ рдЬреЛ рдкрд╣рд▓реЗ рд╕реЗ рдЧрдгрдирд╛ рдХрд░рддрд╛ рд╣реИ:

def pad_same(in_dim, ks, stride, dilation=1):
    """
    Refernces:
          https://github.com/tensorflow/tensorflow/blob/master/tensorflow/core/framework/common_shape_fns.h
          https://github.com/tensorflow/tensorflow/blob/master/tensorflow/core/framework/common_shape_fns.cc#L21
    """
    assert stride > 0
    assert dilation >= 1
    effective_ks = (ks - 1) * dilation + 1
    out_dim = (in_dim + stride - 1) // stride
    p = max(0, (out_dim - 1) * stride + effective_ks - in_dim)

    padding_before = p // 2
    padding_after = p - padding_before
    return padding_before, padding_after

рдпрджрд┐ рдЗрдирдкреБрдЯ рдЖрдпрд╛рдо рдЬреНрдЮрд╛рдд рд╣реИ рдФрд░ рдлреНрд▓рд╛рдИ рдкрд░ рдЧрдгрдирд╛ рдирд╣реАрдВ рдХреА рдЧрдИ рд╣реИ, рддреЛ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ рдЬреИрд╕реЗ:

# Pass this to nn.Sequential
def conv2d_samepad(in_dim, in_ch, out_ch, ks, stride, dilation=1, bias=True):
    pad_before, pad_after = pad_same(in_dim, ks, stride, dilation)
    if pad_before == pad_after:
        return [nn.Conv2d(in_ch, out_ch, ks, stride, pad_after, dilation, bias=bias)]
    else:
        return [nn.ZeroPad2d((pad_before, pad_after, pad_before, pad_after)),
                nn.Conv2d(in_ch, out_ch, ks, stride, 0, dilation, bias=bias)]

рд╣рд╛рд▓рд╛рдВрдХрд┐, рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ рдЗрдирдкреБрдЯ рдЖрдпрд╛рдо (рдпрд╣ рдореБрдЦреНрдп рдореБрджреНрджрд╛ рд╣реИ) рдХреЗ рд▓рд┐рдП рдХреБрдЫ рдмреБрдХ-рдХреАрдкрд┐рдВрдЧ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдпрджрд┐ рдЖрдк рдЙрдкрд░реЛрдХреНрдд рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ рддреЛ рдЖрдк рдЙрдкрдпреЛрдЧреА рдкрд╛ рд╕рдХрддреЗ рд╣реИрдВ:

def conv_outdim(in_dim, padding, ks, stride, dilation):
    if isinstance(padding, int) or isinstance(padding, tuple):
        return conv_outdim_general(in_dim, padding, ks, stride, dilation)
    elif isinstance(padding, str):
        assert padding in ['same', 'valid']
        if padding == 'same':
            return conv_outdim_samepad(in_dim, stride)
        else:
            return conv_outdim_general(in_dim, 0, ks, stride, dilation)
    else:
        raise TypeError('Padding can be int/tuple or str=same/valid')


def conv_outdim_general(in_dim, padding, ks, stride, dilation=1):
    # See https://arxiv.org/pdf/1603.07285.pdf, eq (15)
    return ((in_dim + 2 * padding - ks - (ks - 1) * (dilation - 1)) // stride) + 1


def conv_outdim_samepad(in_dim, stride):
    return (in_dim + stride - 1) // stride

@mirceamironenco рдпрд╣ рдЗрдВрдЧрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж, рдореИрдВрдиреЗ рдЗрд╕реЗ рддреНрд╡рд░рд┐рдд рдФрд░ рдЧрдВрджрд╛ рдмрдирд╛ рджрд┐рдпрд╛ рдФрд░ рдХрднреА рдЪреЗрдХ рдирд╣реАрдВ рдХрд┐рдпрд╛ред рдЗрд╕рдХреЗ рдмрдЬрд╛рдп рдЫрдд рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЕрдкрдбреЗрдЯ рдХрд┐рдпрд╛ рдЧрдпрд╛

@harritaylor рд╕рд╣рдордд рд╣реИрдВ, рдпрд╣ рд╕реБрд╡рд┐рдзрд╛ рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ рдХреЗрд░рд╕/рдЯреАрдПрдл рдореЙрдбрд▓ рдХреЛ PyTorch рдореЗрдВ рдкреЛрд░реНрдЯ рдХрд░рдирд╛ рдЖрд╕рд╛рди рдмрдирд╛ рджреЗрдЧреАред рд╣рд░ рдмрд╛рд░ рдПрдХ рд╕рдордп рдореЗрдВ, рдореИрдВ рдЕрднреА рднреА рдЕрдкрдиреА рд╕рдорд╛рди-рдЧрджреНрджреЗрджрд╛рд░ рдкрд░рддреЛрдВ рдХреЗ рдирд┐рд░реНрдорд╛рдг рдХреЗ рд▓рд┐рдП рдкреИрдбрд┐рдВрдЧ рдЖрдХрд╛рд░ рдХреА "рдореИрдиреБрдЕрд▓" рдЧрдгрдирд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реВрдВред

@kylemcdonald

рд╕рдВрджрд░реНрдн рдХреЗ рд▓рд┐рдП same рдкреИрдбрд┐рдВрдЧ рдХреЗ рд╕рд╛рде рдпрд╣рд╛рдВ рдПрдХ рдмрд╣реБрдд рд╣реА рд╕рд░рд▓ Conv2d рдкрд░рдд рд╣реИред рдпрд╣ рдХреЗрд╡рд▓ рд╡рд░реНрдЧрд╛рдХрд╛рд░ рдЧреБрдард▓реА рдФрд░ рд╕реНрдЯреНрд░рд╛рдЗрдб = 1, рдлреИрд▓рд╛рд╡ = 1, рд╕рдореВрд╣ = 1 рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рддрд╛ рд╣реИред

class Conv2dSame(torch.nn.Module):
    def __init__(self, in_channels, out_channels, kernel_size, bias=True, padding_layer=torch.nn.ReflectionPad2d):
        super().__init__()
        ka = kernel_size // 2
        kb = ka - 1 if kernel_size % 2 == 0 else ka
        self.net = torch.nn.Sequential(
            padding_layer((ka,kb,ka,kb)),
            torch.nn.Conv2d(in_channels, out_channels, kernel_size, bias=bias)
        )
    def forward(self, x):
        return self.net(x)

c = Conv2dSame(1,3,5)
print(c(torch.rand((16,1,10,10))).shape)

# torch.Size([16, 3, 10, 10])

рдХреНрдпрд╛ рдпрд╣ kb = ka - 1 if kernel_size % 2 else ka рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП рдпрд╛ рдирд╣реАрдВ?

рдХреНрдпрд╛ рдпрд╣ рд░реВрдкрд╛рдВрддрд░рдг1d рдкрд░ рднреА рд▓рд╛рдЧреВ рд╣реЛрдЧрд╛?

рд╣реЛ рд╕рдХрддрд╛ рд╣реИ рдХрд┐ рдХрдХреНрд╖рд╛ ConvND рдореЗрдВ рдирдИ рдкреИрдбрд┐рдВрдЧ рд╡рд┐рдзрд┐ рдЬреЛрдбрд╝рдирд╛ рдПрдХ рд╕реБрдВрджрд░ рд╡рд┐рдХрд▓реНрдк рд╣реЛрдЧрд╛, рдФрд░ рд╡рд┐рдзрд┐ рдХреЛ рдУрд╡рд░рд▓реЛрдб рдХрд░рдХреЗ, рдкреИрдбрд┐рдВрдЧ рд╢реЗрдбреНрдпреВрд▓ рдХреЛ рдЖрд╕рд╛рдиреА рд╕реЗ рдмрдврд╝рд╛рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред

рдореИрдВ рд╢рд╛рдпрдж рдЗрд╕реЗ рд▓реЗ рд╕рдХрддрд╛ рд╣реВрдВ рдпрджрд┐ @soumith рдиреЗ рдХрднреА рд╡рд╣ рдкреНрд░рд╕реНрддрд╛рд╡ рд▓рд┐рдЦрд╛ рд╣реЛ рдпрд╛ рдпрджрд┐ рдХреЛрдИ рд╕рдВрдХреНрд╖реЗрдк рдореЗрдВ рдмрддрд╛рддрд╛ рд╣реИ рдХрд┐ рдХреНрдпрд╛ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдКрдкрд░ рдмрд╣реБрдд рдЪрд░реНрдЪрд╛ рд╣реЛ рдЪреБрдХреА рд╣реИ рдФрд░ рдореБрдЭреЗ рдирд╣реАрдВ рдкрддрд╛ рдХрд┐ рд╣рдордиреЗ рдХреНрдпрд╛ рддрдп рдХрд┐рдпрд╛ рд╣реИред рдХреНрдпрд╛ рд╣рдо рдЗрдирдкреБрдЯ рдбреЗрдЯрд╛ рдкрд░ рдирд┐рд░реНрднрд░ рдкреИрдбрд┐рдВрдЧ рдХреА рдЧрдгрдирд╛ рдХрд░ рд░рд╣реЗ рд╣реИрдВ рдпрд╛ рдирд╣реАрдВ, рдХреНрдпрд╛ рд╣рдореЗрдВ рдкреВрд▓ рдХреЗ рд▓рд┐рдП рднреА padding="same" рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдЖрджрд┐?

рдореИрдВ рдХрд╛рд░рдг рдкреИрдбрд┐рдВрдЧ рднреА рдЬреЛрдбрд╝рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВред рдФрд░ рдХреГрдкрдпрд╛ рдЗрд╕реЗ рднреА conv1d рдореЗрдВ рдЬреЛрдбрд╝реЗрдВред
рдореИрдВрдиреЗ рдХреБрдЫ рдмрд┐рдВрджреБ рдкрд░ рдЯрд┐рдкреНрдкрдгрд┐рдпреЛрдВ рдХрд╛ рдкрд╛рд▓рди рдХрд░рдирд╛ рдмрдВрдж рдХрд░ рджрд┐рдпрд╛ рд▓реЗрдХрд┐рди рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рд╕реБрд╡рд┐рдзрд╛ рдХреЗрд░рд╕ рдореЗрдВ рдмрд╣реБрдд рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рдХреА рдЬрд╛рддреА рд╣реИред рдЖрдкрдХреЛ рдЗрд╕рдХрд╛ рдареАрдХ рд╕реЗ рдкрд╛рд▓рди рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдПред

@Chillee рдпрд╣рд╛рдБ рддреБрдо рдЬрд╛рдУ:

рджрд╛рдпрд░рд╛

рд╣рдореЗрдВ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдкрд░рддреЛрдВ рдореЗрдВ рдкреИрдбрд┐рдВрдЧ рдЬреЛрдбрд╝рдиреА рдЪрд╛рд╣рд┐рдП:

  • рд░реВрдкрд╛*рдбреА
  • рдореИрдХреНрд╕рдкреВрд▓*рдбреА
  • рдФрд╕рдд рдкреВрд▓*рдбреА

рдкрд╣рд▓реЗ рдкреАрдЖрд░ рдХреЗ рд▓рд┐рдП, рдЗрд╕реЗ рд╕рд░рд▓ рд░рдЦреЗрдВ рдФрд░ рдХреЗрд╡рд▓ рд░реВрдкрд╛рдВрддрд░рдг*d рд╕реЗ рдЪрд┐рдкрдХреЗ рд░рд╣реЗрдВред

рдЬрдЯрд┐рд▓рддрд╛ рдФрд░ рдбрд╛рдЙрдирд╕рд╛рдЗрдбреНрд╕

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

рдЕрдиреНрдп рд╡реНрдпрд╛рд╡рд╣рд╛рд░рд┐рдХ рдкрд╣рд▓реВ рдпрд╣ рд╣реИ рдХрд┐ рдпрд╣ рдЧрддрд┐рд╢реАрд▓ рд░реВрдк рд╕реЗ рдЧрдгрдирд╛ рдХреА рдЧрдИ padding рдЕрдм рд╣рдореЗрд╢рд╛ рд╕рдордорд┐рдд рдирд╣реАрдВ рд╣реЛрддреА рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдХрд░реНрдиреЗрд▓ рдХреЗ рдЖрдХрд╛рд░/рд╕реНрдЯреНрд░рд╛рдЗрдб, рдлреИрд▓рд╛рд╡ рдХрд╛рд░рдХ рдФрд░ рдЗрдирдкреБрдЯ рдЖрдХрд╛рд░ рдХреЗ рдЖрдзрд╛рд░ рдкрд░, рдкреИрдбрд┐рдВрдЧ рдХреЛ рдЕрд╕рдордорд┐рдд рд╣реЛрдирд╛ рдкрдбрд╝ рд╕рдХрддрд╛ рд╣реИ (рдЕрд░реНрдерд╛рдд рднрд┐рдиреНрди рдмрд╛рдИрдВ рдУрд░ рдмрдирд╛рдо рджрд╛рдИрдВ рдУрд░ рдкреИрдбрд┐рдВрдЧ рд░рд╛рд╢рд┐)ред рдЗрд╕рдХрд╛ рдорддрд▓рдм рдпрд╣ рд╣реЛрдЧрд╛ рдХрд┐ рдЖрдк рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП CuDNN рдХрд░реНрдиреЗрд▓ рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗред

рдбрд┐рдЬрд╝рд╛рдЗрди

рд╡рд░реНрддрдорд╛рди рдореЗрдВ, Conv2d рдХреЗ рд╣рд╕реНрддрд╛рдХреНрд╖рд░ рд╣реИрдВ:

torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True, padding_mode='zeros')

рдпрд╣рд╛рдВ, рд╣рдо padding рдХреЛ int рдпрд╛ tuple ints (рдпрд╛рдиреА рдКрдВрдЪрд╛рдИ/рдЪреМрдбрд╝рд╛рдИ рдХреЗ рдкреНрд░рддреНрдпреЗрдХ рдЖрдпрд╛рдо рдХреЗ рд▓рд┐рдП) рд╣реЛрдиреЗ рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рддреЗ рд╣реИрдВред
рд╣рдо рдХреЗ рд▓рд┐рдП рдПрдХ рдЕрддрд┐рд░рд┐рдХреНрдд рдЕрдзрд┐рднрд╛рд░ рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП padding рдХрд┐ рдПрдХ рд╕реНрдЯреНрд░рд┐рдВрдЧ рд▓реЗ рдЬрд╛рдПрдЧрд╛, рд╕рд╛рде рдореВрд▓реНрдп same ред

same рдкреИрдбрд┐рдВрдЧ рдХреЛ input рдХреЛ рдХрдирд╡рд▓реНрд╢рди рдХреЛ рджреЗрдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдЗрд╕ рддрд░рд╣ рд╕реЗ рдкреИрдб рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП рдХрд┐ output рдЖрдХрд╛рд░ input рдЖрдХрд╛рд░ рдХреЗ рд╕рдорд╛рди рд╣реЛред

рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд╡рд┐рд╡рд░рдг

рдЬрдм 'same' рдХреЛ padding , рддреЛ рд╣рдореЗрдВ рдкреНрд░рддреНрдпреЗрдХ рдЖрдпрд╛рдо рдореЗрдВ рдЖрд╡рд╢реНрдпрдХ рдмрд╛рдПрдБ рдФрд░ рджрд╛рдПрдБ рдкреИрдбрд┐рдВрдЧ рдХреА рдорд╛рддреНрд░рд╛ рдХреА рдЧрдгрдирд╛ рдХрд░рдиреА рд╣реЛрддреА рд╣реИред

рдЖрд╡рд╢реНрдпрдХ рдПрд▓ (рдмрд╛рдПрдВ) рдФрд░ рдЖрд░ (рджрд╛рдПрдВ) рдкреИрдбрд┐рдВрдЧ рдХреА рдЧрдгрдирд╛ рдХреЗ рдмрд╛рдж рд╡рд┐рдЪрд╛рд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рджреЛ рдорд╛рдорд▓реЗ рд╣реИрдВ:

  • рдПрд▓ == рдЖрд░: рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ рдпрд╣ рд╕рдордорд┐рдд рдкреИрдбрд┐рдВрдЧ рд╣реИред рдХреЛрдИ рднреА F.conv2d рдХреЛ padding рдорд╛рди рдХреЗ рд╕рд╛рде L рдмрд░рд╛рдмрд░ рдХреЙрд▓ рдХрд░ рд╕рдХрддрд╛ рд╣реИ
  • рдПрд▓! = рдЖрд░: рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ, рдкреИрдбрд┐рдВрдЧ рдЕрд╕рдордорд┐рдд рд╣реИ, рдФрд░ рдЗрд╕рдХреЗ рдорд╣рддреНрд╡рдкреВрд░реНрдг рдкреНрд░рджрд░реНрд╢рди рдФрд░ рд╕реНрдореГрддрд┐ рдкреНрд░рднрд╛рд╡ рд╣реИрдВред рд╣рдо рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдХрд░рддреЗ рд╣реИрдВ:

    • рд╣рдо input_padded = F.pad(input, ...) рдХреЙрд▓ рдХрд░рддреЗ рд╣реИрдВ рдФрд░ input_padded рдХреЛ F.conv2d рднреЗрдЬрддреЗ рд╣реИрдВред

    • рд╣рдо рдкреНрд░рджрд░реНрд╢рди рдирд┐рд╣рд┐рддрд╛рд░реНрде рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЗрд╕ рдорд╛рдорд▓реЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдЪреЗрддрд╛рд╡рдиреА рдлреЗрдВрдХрддреЗ рд╣реИрдВ (рдХрдо рд╕реЗ рдХрдо рдкреНрд░рд╛рд░рдВрднрд┐рдХ рд░рд┐рд▓реАрдЬ рдХреЗ рд▓рд┐рдП, рдФрд░ рдпрджрд┐ рдЪреЗрддрд╛рд╡рдиреА рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рддреЛ рд╣рдо рдлрд┐рд░ рд╕реЗ рдЬрд╛ рд╕рдХрддреЗ рд╣реИрдВ)ред

    • рдореБрдЭреЗ рдлреЙрд░реНрдореВрд▓реЗрд╢рди рдХрд╛ рд╡рд┐рд╡рд░рдг рдпрд╛рдж рдирд╣реАрдВ рд╣реИ рдФрд░ рд╣рдо рдЗрд╕ рдорд╛рдорд▓реЗ рдХреЛ рдХрд╣рд╛рдВ рджрд░реНрдЬ рдХрд░рддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдЕрдЧрд░ рдореБрдЭреЗ рдпрд╛рдж рд╣реИ, рддреЛ рдпрд╣ рдПрдХ рд╕рдорд╛рди рдЖрдХрд╛рд░ рдХреЗ рдХрд░реНрдиреЗрд▓ рдХреЗ рд░реВрдк рдореЗрдВ рд╕рд░рд▓ рд╣реЛ рд╕рдХрддрд╛ рд╣реИред рдпрджрд┐ рдРрд╕рд╛ рд╣реИ, рддреЛ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреА рдУрд░ рд╕реЗ рдЪреЗрддрд╛рд╡рдиреА рдХреЛ рдЖрд╕рд╛рдиреА рд╕реЗ рдареАрдХ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред

рдХрд╣рдиреЗ рдХреА рдЬрд░реВрд░рдд рдирд╣реАрдВ рд╣реИ рдХрд┐ рдЬреЗрдЖрдИрдЯреА рдкрде рдкрд░ рднреА рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЗрд╕рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд░рдирд╛ рд╣реЛрдЧрд╛

@рдЪрд┐рд▓реА рд╕рдВрджрд░реНрдн рдХреЗ рд▓рд┐рдП, https://github.com/mlperf/inference/blob/master/others/edge/object_detection/ssd_mobilenet/pytorch/utils.py#L40 рд╕реЗ рдкреНрд░реЗрд░рдгрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдпрд╣рд╛рдВ рдПрдХ рд╕рдВрднрд╛рд╡рд┐рдд рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд╣реИред

рдпрд╣ рдкрд░реАрдХреНрд╖рдг рдХрд┐рдП рдЧрдП рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдХреЗ рд▓рд┐рдП TF рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд╕реЗ рдореЗрд▓ рдЦрд╛рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдкрд░реАрдХреНрд╖рдг рд╕рдВрдкреВрд░реНрдг рдирд╣реАрдВ рдерд╛

@ рд╕реМрдорд┐рде рдХреБрдЫ рддреНрд╡рд░рд┐рдд рдкреНрд░рд╢реНрди:

  1. рдХреНрдпрд╛ рдХреЛрдИ рдХрд╛рд░рдг рд╣реИ рдХрд┐ рд╣рдореЗрдВ рдЗрд╕реЗ functional.conv2d рдорд╛рдзреНрдпрдо рд╕реЗ рд▓рд╛рдЧреВ рдирд╣реАрдВ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП? рдЖрдкрдХреЗ рджреНрд╡рд╛рд░рд╛ рд▓рд┐рдЦрд╛ рдЧрдпрд╛ рдбрд┐рдЬрд╝рд╛рдЗрди рдпрд╣ рджрд░реНрд╢рд╛рддрд╛ рд╣реИ рдХрд┐ рдРрд╕рд╛ рдирд╣реАрдВ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред padding = "рд╕рдорд╛рди" рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдРрд╕рд╛ рдХреБрдЫ рднреА рдирд╣реАрдВ рд╣реИ рдЬреЛ рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рдкрд░рддреЛрдВ рдХреЗ рд▓рд┐рдП рд╡рд┐рд╢рд┐рд╖реНрдЯ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред (рд╕рдВрдкрд╛рджрд┐рдд рдХрд░реЗрдВ: рдПрдирд╡реАрдПрдо, рдЙрд╕ F.conv2d impl рдХрд╛ рдПрд╣рд╕рд╛рд╕ рдирд╣реАрдВ рд╣реБрдЖ рдЬрд┐рд╕реЗ рдореИрдВ рджреЗрдЦ рд░рд╣рд╛ рдерд╛ рдорд╛рддреНрд░рд╛рдмрджреНрдз рдерд╛)ред
  2. рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ Tensorflow рдХрд╛ valid рдкреИрдбрд┐рдВрдЧ рдореЛрдб рд╣рдорд╛рд░реЗ padding=0 , рд╣реИ рдирд╛?

рд╕рд╛рде рд╣реА, рдРрд╕рд╛ рдирд╣реАрдВ рд▓рдЧрддрд╛ рдХрд┐ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЗ рд▓рд┐рдП рдЕрд╕рдордорд┐рдд рдкреИрдбрд┐рдВрдЧ рд╕реЗ рдирд┐рдкрдЯрдиреЗ рдХреЗ рд▓рд┐рдП рдХреЛрдИ рдЖрд╕рд╛рди рд╕рдорд╛рдзрд╛рди рд╣реЛрдЧрд╛ред рд╣реЛрдиреЗ рд╡рд╛рд▓реА рдкреИрдбрд┐рдВрдЧ рдХреА рдорд╛рддреНрд░рд╛ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рдиреЗ рдХрд╛ рдкреВрд░рд╛ рдирд┐рдпрдо рд╣реИ
(ceil(x/stride) -1)*stride + (filter-1)*dilation + 1 - x рдПрдХ рдЖрдпрд╛рдо рдХреЗ рд╕рд╛рдеред рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ, рд╣рдореЗрдВ рдЕрд╕рдордорд┐рдд рдкреИрдбрд┐рдВрдЧ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреА рдЬрдм рдпрд╣ 2 рдХрд╛ рдЧреБрдгрдЬ рди рд╣реЛред рдЖрдкрдХреА рдЖрд╢рд╛ рдХреЗ рдкреНрд░рддрд┐ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд░реВрдк рдореЗрдВ рдХрд┐ рдпрд╣ рдХреЗрд╡рд▓ рд╕рдо рдЖрдХрд╛рд░ рдХреЗ рдлрд┐рд▓реНрдЯрд░ рдХреЗ рд╕рд╛рде рд╣реЛрддрд╛ рд╣реИ, input = 10, stride=3, filter=3, dilation=1 ред рдЬрд┐рди рд╕реНрдерд┐рддрд┐рдпреЛрдВ рдореЗрдВ рдРрд╕рд╛ рд╣реЛ рд╕рдХрддрд╛ рд╣реИ, рдЙрдиреНрд╣реЗрдВ рд╣рд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдореБрдЭреЗ рдХреЛрдИ рд╕рд░рд▓ рдирд┐рдпрдо рдирд╣реАрдВ рджрд┐рдЦрддрд╛ред

рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рд╣рдо рдЙрд╕ рд╕реНрдерд┐рддрд┐ рдХреЛ рдЫреЛрдбрд╝рдХрд░ рдкреИрдбрд┐рдВрдЧ рдХреЛ рд╕реНрдерд┐рд░ рд░реВрдк рд╕реЗ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рдирд╣реАрдВ рд╣реЛрдВрдЧреЗ рдЬрдм stride=1 , рддрдм ceil(x/stride) = x , рдФрд░ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ (filter-1)*dilation рдмрд░рд╛рдмрд░ рдкреИрдбрд┐рдВрдЧ рд╣реЛред

@ рдЪрд┐рд▓реА рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ (1), рдХреЛрдИ рдХрд╛рд░рдг рдирд╣реАрдВ, рдореИрдВрдиреЗ рдкреНрд░рднрд╛рд╡реЛрдВ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдирд╣реАрдВ рд╕реЛрдЪрд╛ рдерд╛ - рдкреВрд░реНрдг рдпрд╛ рдЕрдиреНрдпрдерд╛ред

(2) рд╣рд╛рдБред

рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рд╣рдо рд╕реНрдерд┐рд░ рд░реВрдк рд╕реЗ рдкреИрдбрд┐рдВрдЧ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рдирд╣реАрдВ рд╣реЛрдВрдЧреЗ, рд╕рд┐рд╡рд╛рдп рдЙрд╕ рд╕реНрдерд┐рддрд┐ рдХреЛ рдЫреЛрдбрд╝рдХрд░ рдЬрдм рд╕реНрдЯреНрд░рд╛рдЗрдб = 1, рддрдм рдЫрдд (x / рд╕реНрдЯреНрд░рд╛рдЗрдб) = x, рдФрд░ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдкреИрдбрд┐рдВрдЧ (рдлрд╝рд┐рд▓реНрдЯрд░ -1) * рдлреИрд▓рд╛рд╡ рдХреЗ рдмрд░рд╛рдмрд░ рд╣реИ

рд╣рд╛рдВ, рд▓реЗрдХрд┐рди рд╕реНрдЯреНрд░рд╛рдЗрдб = 1 рд╕рд╛рдорд╛рдиреНрдп-рдкрд░реНрдпрд╛рдкреНрдд рд╣реИ рдФрд░ рд╕реНрдЯреИрдЯрд┐рдХ рдкреИрдбрд┐рдВрдЧ рдХреЗ рд▓рд╛рдн рдЗрддрдиреЗ рдЕрдЪреНрдЫреЗ рд╣реИрдВ рдХрд┐ рд╣рдореЗрдВ рдЗрд╕реЗ рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рд╕рдВрднрд╛рд▓рдирд╛ рдЪрд╛рд╣рд┐рдПред

рдЕрд╕рдордорд┐рдд рдкреИрдбрд┐рдВрдЧ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ, рдУрд╣ рд╡реЗрд▓ .....

рдпрд╣ рдореЗрд░реЗ рд▓рд┐рдП рдХреЛрдИ рдорд╛рдпрдиреЗ рдирд╣реАрдВ рд░рдЦрддрд╛ рд╣реИ рдХрд┐ padding=SAME рдХрд╛ рд╡реИрдХрд▓реНрдкрд┐рдХ рдПрдкреАрдЖрдИ рдХреНрдпреЛрдВ рдирд╣реАрдВ рдкреЗрд╢ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ? рдЕрдЧрд░ рдХреЛрдИ рдкреИрдбрд┐рдВрдЧ рдХрд╛ рдЕрддрд┐рд░рд┐рдХреНрдд рдЦрд░реНрдЪ рдЙрдард╛рдиреЗ рдХреЛ рддреИрдпрд╛рд░ рд╣реИ рддреЛ рдЙрдиреНрд╣реЗрдВ рдРрд╕рд╛ рдХрд░рдиреЗ рджреЗрдВред рдХрдИ рд╢реЛрдзрдХрд░реНрддрд╛рдУрдВ рдХреЗ рд▓рд┐рдП, рддреНрд╡рд░рд┐рдд рдкреНрд░реЛрдЯреЛрдЯрд╛рдЗрдк рдПрдХ рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред

рд╣рд╛рдВ,

рдпрд╣ рдореЗрд░реЗ рд▓рд┐рдП рдХреЛрдИ рдорд╛рдпрдиреЗ рдирд╣реАрдВ рд░рдЦрддрд╛ рд╣реИ рдХрд┐ padding=SAME рдХрд╛ рд╡реИрдХрд▓реНрдкрд┐рдХ рдПрдкреАрдЖрдИ рдХреНрдпреЛрдВ рдирд╣реАрдВ рдкреЗрд╢ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ? рдЕрдЧрд░ рдХреЛрдИ рдкреИрдбрд┐рдВрдЧ рдХрд╛ рдЕрддрд┐рд░рд┐рдХреНрдд рдЦрд░реНрдЪ рдЙрдард╛рдиреЗ рдХреЛ рддреИрдпрд╛рд░ рд╣реИ рддреЛ рдЙрдиреНрд╣реЗрдВ рдРрд╕рд╛ рдХрд░рдиреЗ рджреЗрдВред рдХрдИ рд╢реЛрдзрдХрд░реНрддрд╛рдУрдВ рдХреЗ рд▓рд┐рдП, рддреНрд╡рд░рд┐рдд рдкреНрд░реЛрдЯреЛрдЯрд╛рдЗрдк рдПрдХ рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред

рдЗрд╕ рдмрд╛рдд рд╕реЗ рд╕рд╣рдордд! рдореИрдВ рдЗрд╕ рд╕рд╛рд▓рд╛ "рдкреИрдбрд┐рдВрдЧ" рдореЗрдВ 4 рдШрдВрдЯреЗ рддрдХ рдлрдВрд╕ рдЧрдпрд╛ред

рдХреНрдпрд╛ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдЗрд╕ рд╕рдорд╕реНрдпрд╛ рдХреЗ рд╕рдорд╛рдзрд╛рди рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдХреЛрдИ рдЕрдкрдбреЗрдЯ рд╣реИ?

рд╡рд╛рд╣ рдФрд░ рдпрд╣рд╛рдБ рдореИрдВрдиреЗ рд╕реЛрдЪрд╛ рдерд╛ рдХрд┐ рдкрд╛рдЗрдЯреЛрд░рдЪ рдХреЗрд░рд╕/рдЯреЗрдиреНрд╕рд░рдлрд╝реНрд▓реЛ 2.0 рдХреА рддреБрд▓рдирд╛ рдореЗрдВ рдЖрд╕рд╛рди рд╣реЛрдЧрд╛ ...

@zwep рдЖрд░рдВрдн рдХрд░рдиреЗ рдореЗрдВ рдереЛрдбрд╝рд╛ рдФрд░ рдкреНрд░рдпрд╛рд╕ рд╣реИред рдЖрдкрдХреЛ рдЕрдкрдирд╛ рдЯреНрд░рд╛рдЗрдирд┐рдВрдЧ рд▓реВрдк рд▓рд┐рдЦрдирд╛ рд╣реЛрдЧрд╛ рдЬреЛ рдХрд╖реНрдЯрдкреНрд░рдж рд╣реЛ рд╕рдХрддрд╛ рд╣реИ рдФрд░ рдЖрдкрдХреЛ рдкрд░рддреЛрдВ рдХреЛ рдЕрдзрд┐рдХ рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рд▓рд┐рдЦрдирд╛ рд╣реЛрдЧрд╛ред рдПрдХ рдмрд╛рд░ рдЬрдм рдЖрдк рдпрд╣ рдХрд░ рд▓реЗрддреЗ рд╣реИрдВ (рдПрдХ рдмрд╛рд░) рддреЛ рдЖрдк рдЗрд╕рд╕реЗ рдЖрдЧреЗ рд╡рд╛рд╕реНрддрд╡рд┐рдХ рд╕реБрдзрд╛рд░ рдкрд░ рдмрд╣реБрдд рдЖрдЧреЗ рдмрдврд╝ рд╕рдХрддреЗ рд╣реИрдВред

рдореЗрд░реЗ рдЕрдВрдЧреВрдареЗ рдХрд╛ рдирд┐рдпрдо рдХреЗрд░рд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рд╣реИ рдпрджрд┐ рдпрд╣ рдРрд╕рд╛ рдХреБрдЫ рд╣реИ рдЬрд┐рд╕реЗ рдЖрдкрдиреЗ рджрд╕ рд▓рд╛рдЦ рдмрд╛рд░/рд╕реБрдкрд░ рдорд╛рдирдХ рдХрд┐рдпрд╛ рд╣реИред
рдХрд┐рд╕реА рднреА рд╕рдордп рдЕрдиреБрд╕рдВрдзрд╛рди рдФрд░ рд╡рд┐рдХрд╛рд╕ рд╢рд╛рдорд┐рд▓ рд╣реЛрдиреЗ рдкрд░ pytorch рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВред

рдпрд╣рд╛рдБ рдЧрджреНрджреЗрджрд╛рд░ 1d рд░реВрдкрд╛рдВрддрд░рдг рдХреЗ рд▓рд┐рдП рдореЗрд░рд╛ рдХреЛрдб рд╣реИ

рдорд╢рд╛рд▓ рдЖрдпрд╛рдд рдХрд░реЗрдВ
рдорд╢рд╛рд▓ рдЖрдпрд╛рдд nn . рд╕реЗ
np . рдХреЗ рд░реВрдк рдореЗрдВ numpy рдЖрдпрд╛рдд рдХрд░реЗрдВ
рдорд╢рд╛рд▓ рдЖрдпрд╛рдд рдХрд░реЗрдВред рдПрдл рдХреЗ рд░реВрдк рдореЗрдВ рдХрд╛рд░реНрдпрд╛рддреНрдордХ

class Conv1dSamePad(nn.Module):
    def __init__(self, in_channels, out_channels, filter_len, stride=1, **kwargs):
        super(Conv1dSamePad, self).__init__()
        self.filter_len = filter_len
        self.conv = nn.Conv1d(in_channels, out_channels, filter_len, padding=(self.filter_len // 2), stride=stride,
                              **kwargs)
        nn.init.xavier_uniform_(self.conv.weight)
        # nn.init.constant_(self.conv.bias, 1 / out_channels)

    def forward(self, x):
        if self.filter_len % 2 == 1:
            return self.conv(x)
        else:
            return self.conv(x)[:, :, :-1]


class Conv1dCausalPad(nn.Module):
    def __init__(self, in_channels, out_channels, filter_len, **kwargs):
        super(Conv1dCausalPad, self).__init__()
        self.filter_len = filter_len
        self.conv = nn.Conv1d(in_channels, out_channels, filter_len, **kwargs)
        nn.init.xavier_uniform_(self.conv.weight)

    def forward(self, x):
        padding = (self.filter_len - 1, 0)
        return self.conv(F.pad(x, padding))


class Conv1dPad(nn.Module):
    def __init__(self, in_channels, out_channels, filter_len, padding="same", groups=1):
        super(Conv1dPad, self).__init__()
        if padding not in ["same", "causal"]:
            raise Exception("invalid padding type %s" % padding)
        self.conv = Conv1dCausalPad(in_channels, out_channels, filter_len, groups=groups) \
            if padding == "causal" else Conv1dSamePad(in_channels, out_channels, filter_len, groups=groups)

    def forward(self, x):
        return self.conv(x)

@danFromTelAviv рд╡рд╣ рдЖрджрдореА, рдХреЛрдб рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рджред рдЙрд╕ рдкрд╛рдЗрдЯреЛрд░реЗрдХ рджрд░реНрд╢рди рдХреЛ рдзреНрдпрд╛рди рдореЗрдВ рд░рдЦреЗрдВрдЧреЗ!

рдпрд╣ 2020 рд╣реИред рдЕрднреА рднреА рдкрд╛рдЗрдЯреЛрд░рдЪ рдореЗрдВ padding='same' рд╣реИ?

рдХрд┐рд╕реА рднреА рдХрд░реНрдиреЗрд▓ рдЖрдХрд╛рд░, рд╕реНрдЯреНрд░рд╛рдЗрдб рдФрд░ рдлреИрд▓рд╛рд╡ (рдпрд╣рд╛рдВ рддрдХ тАЛтАЛрдХрд┐ рдХрд░реНрдиреЗрд▓ рдЖрдХрд╛рд░ рднреА рдХрд╛рдо рдХрд░рддреЗ рд╣реИрдВ) рдХреЗ рд▓рд┐рдП рд╕рдорд╛рди рдкреИрдбрд┐рдВрдЧ рдХрд╛рдо рдХрд░рдиреЗ рдХрд╛ рдпрд╣ рдПрдХ рддрд░реАрдХрд╛ рд╣реИред

class Conv1dSame(nn.Module):
    def __init__(self, in_channels, out_channels, kernel_size, stride=1, dilation=1):
        super().__init__()
        self.cut_last_element = (kernel_size % 2 == 0 and stride == 1 and dilation % 2 == 1)
        self.padding = math.ceil((1 - stride + dilation * (kernel_size-1))/2)
        self.conv = nn.Conv1d(in_channels, out_channels, kernel_size, padding=self.padding, stride=stride, dilation=dilation)

    def forward(self, x):
        if self.cut_last_element:
            return self.conv(x)[:, :, :-1]
        else:
            return self.conv(x)

рдореИрдВ nn.Conv2d рднреА "рд╡рд╣реА рдкреИрдбрд┐рдВрдЧ" рд╕реБрд╡рд┐рдзрд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВред

рдмреАрдЯреАрдбрдмреНрд▓реВ, рдКрдкрд░ рдЪрд░реНрдЪрд╛ рдХреА рдЧрдИ рдкреВрд░реНрдг/рдХреНрд░рдордмрджреНрдзрддрд╛ рдЪрд┐рдВрддрд╛рдУрдВ рдХреЗ рдЕрддрд┐рд░рд┐рдХреНрдд, рдЯреАрдПрдл рдореЗрдВ рдЖрдХрд╛рд░-рдирд┐рд░реНрднрд░ "рд╕рдорд╛рди" рдкреИрдбрд┐рдВрдЧ рдореЛрдб рдПрдХ рдЕрдЪреНрдЫрд╛ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдХреНрдпреЛрдВ рдирд╣реАрдВ рд╣реИ, рдЗрд╕ рдкрд░ рд╢реБрджреНрдзрддрд╛/рд╕рдЯреАрдХрддрд╛ рдХрд╛рд░рдг рд╣реИрдВред рдореИрдВрдиреЗ https://github.com/tensorflow/tensorflow/issues/18213 рдореЗрдВ рдЪрд░реНрдЪрд╛ рдХреА рд╣реИ рдФрд░ рджрд┐рдЦрд╛рдпрд╛ рд╣реИ рдХрд┐ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдХрдИ Google рдХрд╛ рдЕрдкрдирд╛ рдХреЛрдб рдЖрдХрд╛рд░-рд╕реНрд╡рддрдВрддреНрд░ "рд╕рдорд╛рди" рдкреИрдбрд┐рдВрдЧ рдореЛрдб рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИред

рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдЗрд╕ рдореБрджреНрджреЗ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЕрднреА рдХреЛрдИ рдХрд╛рдо рдирд╣реАрдВ рдЪрд▓ рд░рд╣рд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдЕрдЧрд░ рдРрд╕рд╛ рд╣реИ, рддреЛ рдореБрдЭреЗ рдЙрдореНрдореАрдж рд╣реИ рдХрд┐ рдпрд╣ рдПрдХ рдЖрдХрд╛рд░-рд╕реНрд╡рддрдВрддреНрд░ рд╕рдорд╛рдзрд╛рди рд╣реИред

рдирдорд╕реНрддреЗ, @ppwwyyxx Yuxin, рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рджред
рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ @ McHughes288 рд╕реЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдЕрдЪреНрдЫрд╛ рд╣реИ, рдФрд░ рдореБрдЭреЗ рдЙрдирдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЖрдкрдХреА рд░рд╛рдп рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЖрд╢реНрдЪрд░реНрдп рд╣реИред

рдпрд╣рд╛рдБ Conv1D рд╕рдорд╛рди рдкреИрдбрд┐рдВрдЧ рдХреЗ рд▓рд┐рдП рдореЗрд░рд╛ рд╕рдорд╛рдзрд╛рди рд╣реИ (рдХреЗрд╡рд▓ рддрднреА рд╕рд╣реА рдврдВрдЧ рд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ рдЬрдм dilation==1 & groups==1 , рдФрд░ рдЕрдзрд┐рдХ рдЬрдЯрд┐рд▓ рдЬрдм рдЖрдк рдлреИрд▓рд╛рд╡ рдФрд░ рд╕рдореВрд╣реЛрдВ рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░рддреЗ рд╣реИрдВ):

import torch.nn.functional as F
from torch import nn

class Conv1dSamePadding(nn.Conv1d):
    """Represents the "Same" padding functionality from Tensorflow.
    NOTE: Only work correctly when dilation == 1, groups == 1 !!!
    """
    def forward(self, input):
        size, kernel, stride = input.size(-1), self.weight.size(
            2), self.stride[0]
        padding = kernel - stride - size % stride
        while padding < 0:
            padding += stride
        if padding != 0:
            # pad left by padding // 2, pad right by padding - padding // 2
            # in Tensorflow, one more padding value(default: 0) is on the right when needed
            input = F.pad(input, (padding // 2, padding - padding // 2))
        return F.conv1d(input=input,
                        weight=self.weight,
                        bias=self.bias,
                        stride=stride,
                        dilation=1,
                        groups=1)

@Chillie рдХреНрдпрд╛ рдЖрдк рдЗрд╕ рд╕реБрд╡рд┐рдзрд╛ рдкрд░ рдХрд╛рдо рдХрд░рдирд╛ рдЬрд╛рд░реА рд░рдЦрдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ? рдореИрдВ рдЕрднреА рдХреЗ рд▓рд┐рдП рдЖрдкрдХреЛ рдЕрдирдЕрд╕рд╛рдЗрди рдХрд░рдиреЗ рдЬрд╛ рд░рд╣рд╛ рд╣реВрдВ рддрд╛рдХрд┐ рд╣рдо рдЗрд╕ рдореБрджреНрджреЗ рдХреА рдкреНрд░рдЧрддрд┐ рдХреЛ рдмреЗрд╣рддрд░ рдврдВрдЧ рд╕реЗ рдЯреНрд░реИрдХ рдХрд░ рд╕рдХреЗрдВ, рдХреГрдкрдпрд╛ рдмреЗрдЭрд┐рдЭрдХ рдлрд┐рд░ рд╕реЗ рдЕрд╕рд╛рдЗрди рдХрд░реЗрдВ рдпрджрд┐ рдЖрдк рдЕрднреА рднреА рдЗрд╕ рдкрд░ рдХрд╛рдо рдХрд░ рд░рд╣реЗ рд╣реИрдВред

@wizcheu рдХреЗ рдХреЛрдб рдХреЛ рдкрдврд╝рдиреЗ рдХреЗ рдмрд╛рдж, рдореИрдВ рдкреИрдбрд┐рдВрдЧ = 'рд╕рдорд╛рди' рдХреЗ рд╕рд╛рде conv1d рдХрд╛ рдПрдХ рдФрд░ рд╕рдВрд╕реНрдХрд░рдг рдмрдирд╛ рджреЗрддрд╛ рд╣реВрдВ

class Conv1dPaddingSame(nn.Module):
    '''pytorch version of padding=='same'
    ============== ATTENTION ================
    Only work when dilation == 1, groups == 1
    =========================================
    '''
    def __init__(self, in_channels, out_channels, kernel_size, stride):
        super(Conv1dPaddingSame, self).__init__()
        self.kernel_size = kernel_size
        self.stride = stride
        self.weight = nn.Parameter(torch.rand((out_channels, 
                                                 in_channels, kernel_size)))
        # nn.Conv1d default set bias=Trueя╝Мso create this param
        self.bias = nn.Parameter(torch.rand(out_channels))

    def forward(self, x):
        batch_size, num_channels, length = x.shape
        if length % self.stride == 0:
            out_length = length // self.stride
        else:
            out_length = length // self.stride + 1

        pad = math.ceil((out_length * self.stride + 
                         self.kernel_size - length - self.stride) / 2)
        out = F.conv1d(input=x, 
                       weight = self.weight,
                       stride = self.stride, 
                       bias = self.bias,
                       padding=pad)
        return out

рдХреНрдпрд╛ рдЗрд╕ рдкрд░ рдХреЛрдИ рдЕрдкрдбреЗрдЯ рд╣реИ?

рдХреЛрдИ рдЕрдкрдбреЗрдЯреНрд╕??

@ рдкреАрдЯрд░рдмреЗрд▓ 10 рдиреЗ рдПрдХ рдорд╕реМрджрд╛ рдкреАрдЖрд░ рдЬреЛрдбрд╝рд╛ рд╣реИ рдЬрд┐рд╕рдХрд╛ рдЖрдк рдЕрдиреБрд╕рд░рдг рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред

рдХреНрдпрд╛ рдпрд╣ рдкреГрд╖реНрда рдЙрдкрдпреЛрдЧреА рдерд╛?
0 / 5 - 0 рд░реЗрдЯрд┐рдВрдЧреНрд╕

рд╕рдВрдмрдВрдзрд┐рдд рдореБрджреНрджреЛрдВ

soumith picture soumith  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

rajarshd picture rajarshd  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

eliabruni picture eliabruni  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

ikostrikov picture ikostrikov  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

keskarnitish picture keskarnitish  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ