Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use BrightnessContrast as implementation of Brightness and Contrast ops #2981

Merged
merged 9 commits into from
Jun 11, 2021

Conversation

banasraf
Copy link
Collaborator

@banasraf banasraf commented May 21, 2021

Signed-off-by: Rafal Banas.Rafal97@gmail.com

Why we need this PR?

Brightness and Contrast operators are now implemented as ColorTwist which less performant than BrightnessContrast.

What happened in this PR?

  • What solution was applied:
    Brightness and Contrast are now implemented as BrightnessContrast with limited args.
  • Affected modules and functionalities:
    Brightness and Contrast were moved from color_twist to brightness_contrast.
  • Key points relevant for the review:
    brightness_contrast.cc/h
  • Validation and testing:
    I added new python tests for BrightnessContrast.
  • Documentation (including examples):
    Changes in operators documentation.

JIRA TASK: DALI-2104

Signed-off-by: Rafal <Banas.Rafal97@gmail.com>
@banasraf
Copy link
Collaborator Author

!build

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [2396121]: BUILD STARTED

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [2396121]: BUILD FAILED

Signed-off-by: Rafal <Banas.Rafal97@gmail.com>
@banasraf
Copy link
Collaborator Author

!build

@banasraf banasraf changed the title [WiP] Use BrightnessContrast as implementation of Brightness and Contrast ops Use BrightnessContrast as implementation of Brightness and Contrast ops May 24, 2021
@dali-automaton
Copy link
Collaborator

CI MESSAGE: [2402733]: BUILD STARTED

if (this->spec_.ArgumentDefined("brightness_shift")) {
this->GetPerSampleArgument(brightness_shift_, "brightness_shift", ws, curr_batch_size);
} else {
brightness_shift_ = std::vector<float>(curr_batch_size, 0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't it just get a default value from schema? Why we need this here?

Copy link
Collaborator Author

@banasraf banasraf May 24, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because getting an arg that is not present in the schema (e.g. it's Contrast op and we fetch for brightness) results in exception.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we have one constant that defines this default value here and in the schema?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Copy link
Contributor

@mzient mzient Jun 8, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tend to disagree. The code with 0 and 1 is easier to understand.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would agree that it doesn't make much sense to name those constants, but in this case it connects the default values in the schema with the ones here, so I think it useful.

for device in ['cpu', 'gpu']:
pipe1 = bricon_ref_pipe(ri1, 0.4, device, batch_size=batch_size)
pipe2 = bricon_pipe(ri2, 0.4, device, batch_size=batch_size)
yield compare_pipelines, pipe1, pipe2, batch_size, n_iters
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Newline.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@JanuszL JanuszL self-assigned this May 24, 2021
Signed-off-by: Rafal <Banas.Rafal97@gmail.com>
@banasraf
Copy link
Collaborator Author

!build

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [2405630]: BUILD STARTED

@jantonguirao jantonguirao self-assigned this May 25, 2021
@dali-automaton
Copy link
Collaborator

CI MESSAGE: [2405630]: BUILD PASSED

If not set, the input type is used.)code", DALI_NO_TYPE);

DALI_SCHEMA(Contrast)
.DocStr(R"code(Changes the color contrast of the image.)code")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

color contrast -> color (?)

Also, I'd keep the formula here, for completeness

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
.DocStr(R"code(Changes the color contrast of the image.)code")
.DocStr(R"code(Adjusts the contrast of the image.)code")

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


This operator can also change the type of data.)code")
DALI_SCHEMA(Brightness)
.DocStr(R"code(Changes the brightness of the image.)code")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess we should keep the full explanation with the formula, adjusted for this case.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

this->GetPerSampleArgument(brightness_, "brightness", ws, curr_batch_size);
this->GetPerSampleArgument(brightness_shift_, "brightness_shift", ws, curr_batch_size);
this->GetPerSampleArgument(contrast_, "contrast", ws, curr_batch_size);
if (this->spec_.ArgumentDefined("brightness")) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

perhaps out of scope, but consider using the ArgValue utility. The code is much simpler to write this way.

fn.random.uniform(range=[0.4, 0.6], seed=123)


@pipeline_def(num_threads=12, device_id=0, seed=1234)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's quite a high number of threads. Maybe 4?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

dali/test/python/test_operator_brightness_contrast.py Outdated Show resolved Hide resolved
dali/test/python/test_operator_brightness_contrast.py Outdated Show resolved Hide resolved
ri2 = RandomDataIterator(batch_size, shape=(512, 256, 3), dtype=np.float32)
for device in ['cpu', 'gpu']:
pipe1 = bri_and_con_pipe(ri1, 0.4, device, batch_size=batch_size)
pipe2 = bricon_pipe(ri2, 0.4, device, batch_size=batch_size)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you put that 0.4 in a variable so that it is easier to understand what it is?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

dali/test/python/test_operator_brightness_contrast.py Outdated Show resolved Hide resolved
Comment on lines 31 to 33
return fn.random.uniform(range=[0.5, 2.0], seed=123), \
fn.random.uniform(range=[0.5, 2.0], seed=123), \
fn.random.uniform(range=[0.4, 0.6], seed=123)
Copy link
Contributor

@mzient mzient May 26, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return fn.random.uniform(range=[0.5, 2.0], seed=123), \
fn.random.uniform(range=[0.5, 2.0], seed=123), \
fn.random.uniform(range=[0.4, 0.6], seed=123)
return fn.random.uniform(range=[0.0, 5.0], seed=123), \
fn.random.uniform(range=[0.0, 5.0], seed=123), \
fn.random.uniform(range=[-1,0, 1.0], seed=123)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done



def bricon_ref(input, brightness, brightness_shift, contrast, contrast_center):
return brightness_shift + brightness * (contrast_center + contrast * (input - contrast_center))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is the output's dynamic range?

Suggested change
return brightness_shift + brightness * (contrast_center + contrast * (input - contrast_center))
return brightness_shift * output_range + brightness * (contrast_center + contrast * (input - contrast_center))

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extended tests to check different input/output types

Comment on lines 78 to 79
ri1 = RandomDataIterator(batch_size, shape=(512, 256, 3), dtype=np.float32)
ri2 = RandomDataIterator(batch_size, shape=(512, 256, 3), dtype=np.float32)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The operator's output depends on the type (type's dynamic range is used) - please include this fact in the test.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extended tests to check different input/output types

Signed-off-by: Rafal <Banas.Rafal97@gmail.com>
@@ -84,16 +86,32 @@ class BrightnessContrastOp : public Operator<Backend> {
// out = (brightness_shift * brightness_range +
// brightness * (contrast_center - contrast * contrast_center)) +
// brightness * contrast * in
float norm_brightness = (brightness * brightness_contrast::FullRange<OutputType>()) /
Copy link
Collaborator Author

@banasraf banasraf Jun 8, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the bugfix. It adds normalization to the output range.

Signed-off-by: Rafal <Banas.Rafal97@gmail.com>
Comment on lines 28 to 30
.DocStr(R"code(Adjusts the brightness of the images based on the following formula::
out = brightness_shift * output_range + brightness * in
Where output_range is 1 for float outputs or the maximum positive value for integral types.
Copy link
Contributor

@JanuszL JanuszL Jun 8, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
.DocStr(R"code(Adjusts the brightness of the images based on the following formula::
out = brightness_shift * output_range + brightness * in
Where output_range is 1 for float outputs or the maximum positive value for integral types.
.DocStr(R"code(Adjusts the brightness of the images based on the following formula::
out = brightness_shift * output_range + brightness * in
Where output_range is 1 for float outputs or the maximum positive value for integral types.

You need an empty line between formula and the comment

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Comment on lines 49 to 51
.DocStr(R"code(Adjusts the contrast of the images based on the following formula::
out = grey + contrast * (in - grey)
Where:
Copy link
Contributor

@JanuszL JanuszL Jun 8, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
.DocStr(R"code(Adjusts the contrast of the images based on the following formula::
out = grey + contrast * (in - grey)
Where:
.DocStr(R"code(Adjusts the contrast of the images based on the following formula::
out = grey + contrast * (in - grey)
Where:

Similar

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

clipped = np.round(clipped)
return clipped.astype(out_dtype)

def dali_to_np_type(dtype):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe you can use dali_type_to_np ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Copy link
Contributor

@JanuszL JanuszL left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please adjust Copyright notices as well.

- The output_range is 1 for float outputs or the maximum positive value for integral types.
- Grey denotes the value of 0.5 for ``float``, 128 for ``uint8``, and 16384 for ``int16``, and so on.
DALI_SCHEMA(Brightness)
.DocStr(R"code(Adjusts the brightness of the images based on the following formula::
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This won't work well with the operators table, the first sentence should be short to fit into the table:

Suggested change
.DocStr(R"code(Adjusts the brightness of the images based on the following formula::
.DocStr(R"code(Adjusts the brightness of images.
The brightness is adjusted based on the following formula::

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

If not set, the input type is used.)code", DALI_NO_TYPE);

DALI_SCHEMA(Contrast)
.DocStr(R"code(Adjusts the contrast of the images based on the following formula::
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
.DocStr(R"code(Adjusts the contrast of the images based on the following formula::
.DocStr(R"code(Adjusts the contrast of images.
The contrast is adjusted based on the following formula::

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Where:

- The output_range is 1 for float outputs or the maximum positive value for integral types.
- Grey denotes the value of 0.5 for ``float``, 128 for ``uint8``, and 16384 for ``int16``, and so on.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: rename grey to "midrange", "halfrange" or similar.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, there is an argument contrast_center that is used is this value, so I renamed gray to contrast_center. It has its own description so I removed this information from here.

DALI_SCHEMA(BrightnessContrast)
.AddParent("Brightness")
.AddParent("Contrast")
.DocStr(R"code(Adjusts the brightness and contrast of the images based on the following
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
.DocStr(R"code(Adjusts the brightness and contrast of the images based on the following
.DocStr(R"code(Adjusts the brightness and contrast the images.
The brightness and contrast is adjusted based on the following

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

}

void AcquireArguments(const workspace_t<Backend> &ws) {
auto curr_batch_size = ws.GetInputBatchSize(0);
if (this->spec_.ArgumentDefined("brightness")) {
this->GetPerSampleArgument(brightness_, "brightness", ws, curr_batch_size);
} else {
brightness_ = std::vector<float>(curr_batch_size, 1.f);
brightness_ = std::vector<float>(curr_batch_size, kDefaultBrightness);
Copy link
Contributor

@mzient mzient Jun 8, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 and 0 are not considered magic numbers - and it's much easier to understand the code when you see a default argument of multiplication or addition without having to look up the remote definition.

}

if (this->spec_.ArgumentDefined("brightness_shift")) {
this->GetPerSampleArgument(brightness_shift_, "brightness_shift", ws, curr_batch_size);
} else {
brightness_shift_ = std::vector<float>(curr_batch_size, 0);
brightness_shift_ = std::vector<float>(curr_batch_size, kDefaultBrightnessShift);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Likewise.

}

if (this->spec_.ArgumentDefined("contrast")) {
this->GetPerSampleArgument(contrast_, "contrast", ws, curr_batch_size);
} else {
contrast_ = std::vector<float>(curr_batch_size, 1.f);
contrast_ = std::vector<float>(curr_batch_size, kDefaultContrast);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...and again.

Comment on lines +49 to +51
const float kDefaultBrightness = 1.f;
const float kDefaultBrightnessShift = 0;
const float kDefaultContrast = 1.f;
Copy link
Contributor

@mzient mzient Jun 8, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't. It's much easier to understand the purpose of having a multiplier of 1 or an addend of 0 than to look for definition somewhere. This also may create a misconception that these values are somehow arbitrarily chosen, when in fact they are mathematically fixed.

Signed-off-by: Rafal <Banas.Rafal97@gmail.com>
Comment on lines 77 to 78
inp = fn.brightness(inp, brightness=brightness, brightness_shift=brightness_shift, dtype=dtype)
return inp
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
inp = fn.brightness(inp, brightness=brightness, brightness_shift=brightness_shift, dtype=dtype)
return inp
out = fn.brightness(inp, brightness=brightness, brightness_shift=brightness_shift, dtype=dtype)
return out

And similar in other functions.
Just a suggestion.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to directly returning

Signed-off-by: Rafal <Banas.Rafal97@gmail.com>
@banasraf
Copy link
Collaborator Author

banasraf commented Jun 9, 2021

!build

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [2455714]: BUILD STARTED

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [2455714]: BUILD FAILED

Signed-off-by: Rafal <Banas.Rafal97@gmail.com>
@banasraf
Copy link
Collaborator Author

banasraf commented Jun 9, 2021

!build

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [2455858]: BUILD STARTED

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [2455858]: BUILD FAILED

Signed-off-by: Rafal <Banas.Rafal97@gmail.com>
@banasraf
Copy link
Collaborator Author

!build

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [2461351]: BUILD STARTED

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [2461351]: BUILD PASSED

@banasraf banasraf merged commit 2293d33 into NVIDIA:main Jun 11, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants