рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдЖрд╕рд╛рди рд╣реЛрдЧрд╛, рд▓реЗрдХрд┐рди рдХрдИ рд▓реЛрдЧреЛрдВ рдХреЛ рдпрд╣ рдЧрдгрдирд╛ рдХрд░рдиреЗ рдореЗрдВ рд╕рд┐рд░рджрд░реНрдж рд╕реЗ рдкреАрдбрд╝рд┐рдд рд╣реЛрдиреЗ рдореЗрдВ рдорджрдж рдорд┐рд▓ рд╕рдХрддреА рд╣реИ рдХрд┐ рдЙрдиреНрд╣реЗрдВ рдХрд┐рддрдиреЗ рдкреИрдбрд┐рдВрдЧ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред
cc @ezyang @gchanan @zou3519 @albanD @mruberry
рдРрд╕рд╛ рдХрд░рдиреЗ рд▓рд╛рдпрдХ рд▓рдЧрддрд╛ рд╣реИред рдЖрдк рдХрд┐рд╕ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХрд╛ рдкреНрд░рд╕реНрддрд╛рд╡ рдХрд░ рд░рд╣реЗ рд╣реИрдВ? 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
рдЙрдард╛рдирд╛ рдЪрд╛рд╣рд┐рдПред
рдореБрдЭреЗ рдкрддрд╛ рд╣реИ, рдпрд╣ рд╕рдмрд╕реЗ рд╕рд╛рдл рд╕рдорд╛рдзрд╛рди рдирд╣реАрдВ рд╣реИ, рд▓реЗрдХрд┐рди рдмрд╛рдзрд╛ рдореБрдЭреЗ рдХрд╛рдлреА рдЙрдЪрд┐рдд рд▓рдЧрддреА рд╣реИ:
stride > 1
рд▓рд┐рдП рдЯреЗрдВрд╕рд░рдлрд╝реНрд▓реЛ рдореЗрдВ рд╕рдЪ рдирд╣реАрдВ рд╣реИ рдФрд░ рдпрд╣ "рд╕рдорд╛рди" рд╢рдмреНрдж рдХрд╛ рдЙрдкрдпреЛрдЧ рдереЛрдбрд╝рд╛ рднреНрд░рд╛рдордХ рдЖрдИрдПрдордУ рдмрдирд╛рддрд╛ рд╣реИ;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 рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд╕реЗ рдореЗрд▓ рдЦрд╛рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдкрд░реАрдХреНрд╖рдг рд╕рдВрдкреВрд░реНрдг рдирд╣реАрдВ рдерд╛
@ рд╕реМрдорд┐рде рдХреБрдЫ рддреНрд╡рд░рд┐рдд рдкреНрд░рд╢реНрди:
functional.conv2d
рдорд╛рдзреНрдпрдо рд╕реЗ рд▓рд╛рдЧреВ рдирд╣реАрдВ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП? рдЖрдкрдХреЗ рджреНрд╡рд╛рд░рд╛ рд▓рд┐рдЦрд╛ рдЧрдпрд╛ рдбрд┐рдЬрд╝рд╛рдЗрди рдпрд╣ рджрд░реНрд╢рд╛рддрд╛ рд╣реИ рдХрд┐ рдРрд╕рд╛ рдирд╣реАрдВ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред padding
= "рд╕рдорд╛рди" рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдРрд╕рд╛ рдХреБрдЫ рднреА рдирд╣реАрдВ рд╣реИ рдЬреЛ рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рдкрд░рддреЛрдВ рдХреЗ рд▓рд┐рдП рд╡рд┐рд╢рд┐рд╖реНрдЯ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред (рд╕рдВрдкрд╛рджрд┐рдд рдХрд░реЗрдВ: рдПрдирд╡реАрдПрдо, рдЙрд╕ F.conv2d
impl рдХрд╛ рдПрд╣рд╕рд╛рд╕ рдирд╣реАрдВ рд╣реБрдЖ рдЬрд┐рд╕реЗ рдореИрдВ рджреЗрдЦ рд░рд╣рд╛ рдерд╛ рдорд╛рддреНрд░рд╛рдмрджреНрдз рдерд╛)ред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 рдиреЗ рдПрдХ рдорд╕реМрджрд╛ рдкреАрдЖрд░ рдЬреЛрдбрд╝рд╛ рд╣реИ рдЬрд┐рд╕рдХрд╛ рдЖрдк рдЕрдиреБрд╕рд░рдг рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред
рд╕рдмрд╕реЗ рдЙрдкрдпреЛрдЧреА рдЯрд┐рдкреНрдкрдгреА
рдХреНрдпрд╛ рдирд┐рдХрдЯ рднрд╡рд┐рд╖реНрдп рдореЗрдВ рдкрд╛рдЗрдЯреЛрд░рдЪ рдореЗрдВ рдЗрд╕реА рддрд░рд╣ рдХреЗ рдПрдкреАрдЖрдИ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреА рдХреЛрдИ рдпреЛрдЬрдирд╛ рд╣реИ? рдЯреЗрдВрд╕рд░рдлрд╝реНрд▓реЛ / рдХреЗрд░рд╕ рдкреГрд╖реНрдарднреВрдорд┐ рд╕реЗ рдЖрдиреЗ рд╡рд╛рд▓реЗ рд▓реЛрдЧ рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ рдЗрд╕рдХреА рд╕рд░рд╛рд╣рдирд╛ рдХрд░реЗрдВрдЧреЗред