Skip to content

Commit 5a933b4

Browse files
authored
Merge pull request #1592 from Noplz/smooth_l1_layer
Smooth l1 layer for SSD
2 parents 24b00ac + b3313f2 commit 5a933b4

File tree

5 files changed

+150
-0
lines changed

5 files changed

+150
-0
lines changed

paddle/gserver/layers/CostLayer.cpp

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,59 @@ void SumOfSquaresCostLayer::backwardImp(Matrix& output,
192192
outputG.sumOfSquaresBp(output, *label.value);
193193
}
194194

195+
//
196+
// class SmoothL1CostLayer
197+
//
198+
199+
REGISTER_LAYER(smooth_l1, SmoothL1CostLayer);
200+
201+
bool SmoothL1CostLayer::init(const LayerMap& layerMap,
202+
const ParameterMap& parameterMap) {
203+
return CostLayer::init(layerMap, parameterMap);
204+
}
205+
206+
void SmoothL1CostLayer::forwardImp(Matrix& output,
207+
Argument& label,
208+
Matrix& target) {
209+
MatrixPtr targetCpu, outputCpu, labelCpu;
210+
if (useGpu_) {
211+
targetCpu =
212+
Matrix::create(target.getHeight(), target.getWidth(), false, false);
213+
outputCpu =
214+
Matrix::create(output.getHeight(), output.getWidth(), false, false);
215+
labelCpu = Matrix::create(
216+
label.value->getHeight(), label.value->getWidth(), false, false);
217+
targetCpu->copyFrom(target);
218+
outputCpu->copyFrom(output);
219+
labelCpu->copyFrom(*label.value);
220+
targetCpu->smoothL1(*outputCpu, *(labelCpu));
221+
target.copyFrom(*targetCpu);
222+
} else {
223+
target.smoothL1(output, *label.value);
224+
}
225+
}
226+
227+
void SmoothL1CostLayer::backwardImp(Matrix& output,
228+
Argument& label,
229+
Matrix& outputG) {
230+
MatrixPtr outputGCpu, outputCpu, labelCpu;
231+
if (useGpu_) {
232+
outputGCpu =
233+
Matrix::create(outputG.getHeight(), outputG.getWidth(), false, false);
234+
outputCpu =
235+
Matrix::create(output.getHeight(), output.getWidth(), false, false);
236+
labelCpu = Matrix::create(
237+
label.value->getHeight(), label.value->getWidth(), false, false);
238+
outputGCpu->copyFrom(outputG);
239+
outputCpu->copyFrom(output);
240+
labelCpu->copyFrom(*label.value);
241+
outputGCpu->smoothL1Bp(*outputCpu, *labelCpu);
242+
outputG.copyFrom(*outputGCpu);
243+
} else {
244+
outputG.smoothL1Bp(output, *label.value);
245+
}
246+
}
247+
195248
//
196249
// class RankingCost
197250
//

paddle/gserver/layers/CostLayer.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,29 @@ class SumOfSquaresCostLayer : public CostLayer {
159159
Matrix& outputGrad) override;
160160
};
161161

162+
/**
163+
* This cost layer compute smooth L1 loss for real-valued regression
164+
* tasks.
165+
* \f[
166+
* L =
167+
* (output - label)^2 * 0.5 / -1 < (output - label) < 1 /
168+
* (output - label) - 0.5 / otherwise /
169+
* \f]
170+
*/
171+
class SmoothL1CostLayer : public CostLayer {
172+
public:
173+
explicit SmoothL1CostLayer(const LayerConfig& config) : CostLayer(config) {}
174+
175+
bool init(const LayerMap& layerMap,
176+
const ParameterMap& parameterMap) override;
177+
178+
void forwardImp(Matrix& output, Argument& label, Matrix& cost) override;
179+
180+
void backwardImp(Matrix& outputValue,
181+
Argument& label,
182+
Matrix& outputGrad) override;
183+
};
184+
162185
/**
163186
* A cost layer for learning to rank (LTR) task. This layer contains at leat
164187
* three inputs.

paddle/gserver/tests/test_LayerGrad.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1602,6 +1602,20 @@ TEST(Layer, PadLayer) {
16021602
}
16031603
}
16041604

1605+
TEST(Layer, smooth_l1) {
1606+
TestConfig config;
1607+
config.layerConfig.set_type("smooth_l1");
1608+
1609+
config.inputDefs.push_back({INPUT_DATA, "layer_0", 1, 0});
1610+
config.inputDefs.push_back({INPUT_DATA_TARGET, "layer_1", 1, 0});
1611+
config.layerConfig.add_inputs();
1612+
config.layerConfig.add_inputs();
1613+
1614+
for (auto useGpu : {false, true}) {
1615+
testLayerGrad(config, "smooth_l1", 100, false, useGpu, false, 2.0);
1616+
}
1617+
}
1618+
16051619
int main(int argc, char** argv) {
16061620
testing::InitGoogleTest(&argc, argv);
16071621
initMain(argc, argv);

paddle/math/Matrix.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3590,6 +3590,55 @@ void CpuMatrix::sumOfSquaresBp(Matrix& output, Matrix& label) {
35903590
}
35913591
}
35923592

3593+
void CpuMatrix::smoothL1(Matrix& output, Matrix& label) {
3594+
CHECK(output.useGpu_ == false && label.useGpu_ == false)
3595+
<< "Matrix type are not equal";
3596+
3597+
size_t numSamples = getHeight();
3598+
size_t dim = output.getWidth();
3599+
CHECK_EQ(label.getHeight(), numSamples);
3600+
CHECK_EQ(output.getHeight(), numSamples);
3601+
CHECK_EQ(label.getWidth(), dim);
3602+
CHECK_EQ(getWidth(), (size_t)1);
3603+
real* out = output.getData();
3604+
real* cost = getData();
3605+
real* lbl = label.getData();
3606+
3607+
for (size_t i = 0; i < numSamples; ++i, out += dim, cost += dim, lbl += dim) {
3608+
for (size_t j = 0; j < dim; ++j) {
3609+
cost[j] = std::fabs(out[j] - lbl[j]);
3610+
if (cost[j] < 1.0)
3611+
cost[j] = 0.5 * cost[j] * cost[j];
3612+
else
3613+
cost[j] = cost[j] - 0.5;
3614+
}
3615+
}
3616+
}
3617+
3618+
void CpuMatrix::smoothL1Bp(Matrix& output, Matrix& label) {
3619+
CHECK(output.useGpu_ == false && label.useGpu_ == false)
3620+
<< "Matrix type are not equal";
3621+
3622+
size_t numSamples = getHeight();
3623+
size_t dim = output.getWidth();
3624+
CHECK_EQ(label.getHeight(), numSamples);
3625+
CHECK_EQ(output.getHeight(), numSamples);
3626+
CHECK_EQ(label.getWidth(), dim);
3627+
CHECK_EQ(getWidth(), (size_t)1);
3628+
real* out = output.getData();
3629+
real* cost = getData();
3630+
real* lbl = label.getData();
3631+
3632+
// f'(x) = x if |x| < 1
3633+
// = sign(x) otherwise
3634+
for (size_t i = 0; i < numSamples; ++i, out += dim, cost += dim, lbl += dim) {
3635+
for (size_t j = 0; j < dim; ++j) {
3636+
cost[j] = out[j] - lbl[j];
3637+
if (std::fabs(cost[j]) >= 1) cost[j] = (0 < cost[j]) - (cost[j] < 0);
3638+
}
3639+
}
3640+
}
3641+
35933642
void CpuMatrix::tanh(Matrix& output) {
35943643
CHECK(isContiguous());
35953644
CHECK(output.isContiguous());

paddle/math/Matrix.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -783,6 +783,14 @@ class Matrix : public BaseMatrix {
783783
LOG(FATAL) << "Not implemented";
784784
}
785785

786+
virtual void smoothL1(Matrix& output, Matrix& label) {
787+
LOG(FATAL) << "Not implemented";
788+
}
789+
790+
virtual void smoothL1Bp(Matrix& outputV, Matrix& label) {
791+
LOG(FATAL) << "Not implemented";
792+
}
793+
786794
virtual void tanh(Matrix& output) { LOG(FATAL) << "Not implemented"; }
787795

788796
virtual void tanhDerivative(Matrix& output) {
@@ -1720,6 +1728,9 @@ class CpuMatrix : public Matrix {
17201728
/// gradient of sumOfSquares.
17211729
void sumOfSquaresBp(Matrix& outputV, Matrix& label);
17221730

1731+
void smoothL1(Matrix& output, Matrix& label);
1732+
void smoothL1Bp(Matrix& output, Matrix& label);
1733+
17231734
void tanh(Matrix& output);
17241735
void tanhDerivative(Matrix& output);
17251736

0 commit comments

Comments
 (0)